diff --git a/COMMANDS.md b/COMMANDS.md index 9b767c3..41bd71a 100644 --- a/COMMANDS.md +++ b/COMMANDS.md @@ -4,6 +4,8 @@ This document mirrors `src/index.ts` command registration and is the canonical C Trust boundary: live receipt > committed receipt > memory summary. Memory is advisory only; `8099/deploy` via git-proxy is the guarded deploy route, and `8098/deploy-webhook` is legacy/stale for fable-agent deploy trust. +Agent-run traces follow system-card discipline: `fable.agent_run.trace.v1` records budget, environment, safety posture, receipts, latency, and `deployAttempted: false`; capability evidence is not deploy authority. + Last sync: 2026-06-14. ## Quick examples diff --git a/src/fable5/eval-trace.test.ts b/src/fable5/eval-trace.test.ts index c69caa3..a490d32 100644 --- a/src/fable5/eval-trace.test.ts +++ b/src/fable5/eval-trace.test.ts @@ -43,6 +43,9 @@ describe("eval trace receipt", () => { receiptsWritten: ["fable.agent_run.trace.v1"], tokensIn: 100, tokensOut: 20, + budget: { tokens: 500, wallClockMs: 10_000, toolCalls: 8 }, + environment: { internet: false, repoAccess: true, deployAuthority: "gated" }, + safetyPosture: { cyber: "read-only", securityScan: "passed", approval: "required" }, decision: "ok", }); @@ -52,6 +55,22 @@ describe("eval trace receipt", () => { schema: "fable.agent_run.trace.v1", runId: "run-1", latencyMs: 2500, + budget: { tokens: 500, wallClockMs: 10000, toolCalls: 8 }, + environment: { internet: false, repoAccess: true, secretsAccess: false, deployAuthority: "gated" }, + safetyPosture: { cyber: "read-only", securityScan: "passed", approval: "required" }, + deployAttempted: false, + }); + }); + + it("defaults agent run traces to no internet, no secrets, and no deploy authority", () => { + expect(createAgentRunTraceReceipt({ + runId: "run-2", + task: "inspect", + startedAt: new Date("2026-06-29T00:00:00.000Z"), + endedAt: new Date("2026-06-29T00:00:00.001Z"), + })).toMatchObject({ + environment: { internet: false, repoAccess: true, secretsAccess: false, deployAuthority: "none" }, + safetyPosture: { cyber: "not-run", securityScan: "not-run", approval: "not-required" }, deployAttempted: false, }); }); diff --git a/src/fable5/eval-trace.ts b/src/fable5/eval-trace.ts index 26726ed..1400f95 100644 --- a/src/fable5/eval-trace.ts +++ b/src/fable5/eval-trace.ts @@ -15,6 +15,25 @@ export interface EvalTraceReceipt { createdAt: string; } +export interface AgentRunTraceBudget { + tokens?: number; + wallClockMs?: number; + toolCalls?: number; +} + +export interface AgentRunTraceEnvironment { + internet: boolean; + repoAccess: boolean; + secretsAccess: false; + deployAuthority: "none" | "gated"; +} + +export interface AgentRunTraceSafetyPosture { + cyber: "not-run" | "read-only" | "approved-active"; + securityScan?: "not-run" | "passed" | "failed"; + approval?: "not-required" | "required" | "granted"; +} + export interface AgentRunTraceReceipt { schema: "fable.agent_run.trace.v1"; runId: string; @@ -27,6 +46,9 @@ export interface AgentRunTraceReceipt { tokensIn?: number; tokensOut?: number; latencyMs: number; + budget: AgentRunTraceBudget; + environment: AgentRunTraceEnvironment; + safetyPosture: AgentRunTraceSafetyPosture; decision: "ok" | "needs-human" | "blocked" | "failed"; reasons: string[]; deployAttempted: false; @@ -42,6 +64,9 @@ export interface AgentRunTraceOptions { receiptsWritten?: string[]; tokensIn?: number; tokensOut?: number; + budget?: Partial; + environment?: Partial; + safetyPosture?: Partial; decision?: AgentRunTraceReceipt["decision"]; reasons?: string[]; } @@ -109,6 +134,22 @@ export function createAgentRunTraceReceipt(opts: AgentRunTraceOptions): AgentRun tokensIn: opts.tokensIn, tokensOut: opts.tokensOut, latencyMs, + budget: { + tokens: opts.budget?.tokens, + wallClockMs: opts.budget?.wallClockMs, + toolCalls: opts.budget?.toolCalls, + }, + environment: { + internet: opts.environment?.internet ?? false, + repoAccess: opts.environment?.repoAccess ?? true, + secretsAccess: false, + deployAuthority: opts.environment?.deployAuthority ?? "none", + }, + safetyPosture: { + cyber: opts.safetyPosture?.cyber ?? "not-run", + securityScan: opts.safetyPosture?.securityScan ?? "not-run", + approval: opts.safetyPosture?.approval ?? "not-required", + }, decision: opts.decision ?? "ok", reasons: opts.reasons ?? [], deployAttempted: false, diff --git a/src/fable5/index.ts b/src/fable5/index.ts index f9ceb00..ce1df0a 100644 --- a/src/fable5/index.ts +++ b/src/fable5/index.ts @@ -76,7 +76,7 @@ export { checkReceiptHealth } from "./receipt-consumer.js"; export type { ReceiptHealth } from "./receipt-consumer.js"; export { createAgentRunTraceReceipt, createDuelEvalReceipt, createEvalTraceReceipt, gradeSetRecovery, gradeVerifiableReward, tallyDuelReceipts, writeAgentRunTraceReceipt, writeDuelEvalReceipt, writeEvalTraceReceipt } from "./eval-trace.js"; -export type { AgentRunTraceOptions, AgentRunTraceReceipt, DuelEvalReceipt, DuelTally, EvalTraceCommand, EvalTraceReceipt, SetGradeReceipt, VerifiableRewardReceipt } from "./eval-trace.js"; +export type { AgentRunTraceBudget, AgentRunTraceEnvironment, AgentRunTraceOptions, AgentRunTraceReceipt, AgentRunTraceSafetyPosture, DuelEvalReceipt, DuelTally, EvalTraceCommand, EvalTraceReceipt, SetGradeReceipt, VerifiableRewardReceipt } from "./eval-trace.js"; export { loadBenchHarnesses, runAgentBench, writeAgentBenchReceipt } from "./agent-bench.js"; export type { AgentBenchOptions, AgentBenchReceipt, BenchContenderId, BenchContenderResult, BenchHarnessConfig, BenchmarkHygiene } from "./agent-bench.js";