Vendor-neutral trace schema the workbench normalizes execution data into." />

Schema · stable URL · part of the Raising Agents system contract layer. Markdown source on GitHub: system/schema/_src/agent-behavior-trace-v0.md.

agent-behavior-trace/v0

JSON schema for trace-diff cases on raisingagents.is.

Read by: <trace-diff> web component (system/assets/trace-diff.js). Written by (Round 06+): the workbench evaluator on each contract run. Written by (Round 05): human authors, by hand, for canonical demos.

Stable contract. Versioned at the top level ("schema": "agent-behavior-trace/v0"). Breaking changes bump to /v1; the component refuses unknown versions.


1 — Top-level shape

{
  "schema": "agent-behavior-trace/v0",   // required · identity
  "case": "OPBR · refund commit",        // required · human label
  "contract": "refund.commit_after_checks", // required · contract ref
  "contract_clause": "P2",               // optional · specific clause
  "rails": [Rail, Rail],                 // required · exactly 2
  "verdict": Verdict,                    // required
  "permalink": "/lab/opbr",              // optional · canonical URL
  "updated": "2026-05-24"                // optional · ISO date
}

A trace is always two rails. Single-rail cases are out of scope for this format — they belong to a different surface (a workbench run viewer, not a trace-diff).


2 — Rail

{
  "id": "run-a",            // required · slug, used as DOM id
  "label": "Run A · stable", // required · display label, mono kicker
  "regression": false,      // required · marks the rail that fails contract
  "steps": [Step, …]        // required · 1 or more
}

The two rails share step indices (1, 2, 3, …) but are otherwise independent. Step counts may differ between rails. The reader compares row-by-row; the component does not enforce alignment.

Exactly one rail should have "regression": true. That rail is rendered with the oxide accent column and receives the violation marker treatment.


3 — Step

{
  "n": 2,                          // required · 1-based index, used for sort
  "tool": "refund_commit",         // required · snake_case tool name
  "result": "success",             // required · short return summary

  "kind": "side_effect",           // required · semantic role (see below)
  "consequential": true,           // optional · is this the apex of a violation?
  "in_violation": false,           // optional · is this step inside a violation span?

  // Round 06+ fields, optional, ignored by Round 05 renderer:
  "args": { "customer_id": "c_91", "amount_eur": 1200 },
  "return": { "ok": true, "ref": "rf_2024_…" },
  "timestamp_ms": 1832,
  "tokens": 412
}

kind vocabulary (locked)

value meaning marker (default)
"read" non-mutating read of state open circle
"precondition" check that gates a side effect open circle
"side_effect" mutates the world (refund, write, edit) open circle when ok, filled square + oxide when consequential: true
"respond" terminal model output open circle

The marker rendering is a function of kind + consequential + in_violation. The author asserts the semantics; the component renders.

consequential and in_violation

These are assertions about the contract evaluation, not about the step itself. The same refund_commit step is: - consequential: false in Run A (preconditions resolved first → no violation) - consequential: true in Run B (preconditions still pending → apex of violation)

in_violation: true marks the rows that sit inside the violation span — typically the preconditions that should have fired before the consequential side effect. The renderer draws the hand-drawn bracket from the consequential row through all subsequent in_violation rows.


4 — Verdict

{
  "output": "PASS",                 // required · "PASS" | "FAIL"
  "behavior": "FAIL",               // required · "PASS" | "FAIL"
  "behavior_reason": "P2 violation — side effect precedes precondition check (policy_version_check)",
  "operational": "within budget"    // optional
}

behavior_reason is required when behavior === "FAIL". The Round 05 renderer shows it in the compact verdict bar. Round 06’s verdict-flip computes this string live as the reader drags refund_commit.


5 — Component contract

The <trace-diff> element accepts data in three ways:

  1. External JSON<trace-diff data-src="/system/data/opbr-canonical.json"></trace-diff>
  2. Inline JSON<trace-diff><script type="application/json">{…}</script></trace-diff>
  3. Programmaticel.data = {…} then el.render()

Mode attributes:

Schema mismatch (wrong version, missing required field) renders a single line: [trace-diff: unsupported schema X · expected agent-behavior-trace/v0]. No silent failure.


6 — Versioning policy

The component validates schema on every render. Unknown schema strings render the error line, never the data.