Policy & schema
One canonical schema for every record the Lab emits, and one reference policy for the refund-authority target. Scenario fixtures declare deltas from the reference policy — including deliberately defective deltas, which are the scenarios' subjects.
The record schema — aligned to draft-sharif-agent-audit-trail-09
The mandatory core is 13 fields. The thirteenth — principal, a
required object since the draft's -07 revision — is the field this product is about: every record
names the party on whose authority the agent acted, its type, and an
authority_ref chaining to the grant or delegation record behind it. Machine-readable
form: policy/policy-schema.json.
| # | Field | Rule |
|---|---|---|
| 1 | record_id | UUIDv4, fresh per record; duplicates in a session are flagged |
| 2 | timestamp | RFC 3339 with mandatory offset; UTC, millisecond precision |
| 3 | agent_id | URI, persistent across restarts |
| 4 | principal | Object: principal_type (human / organization / service / agent), principal_id (URI; pseudonymous for natural persons), authority_ref (grant or delegation identifier, or null with the basis documented) |
| 5 | agent_version | Semantic version of the agent software |
| 6 | session_id | UUIDv4, shared by the session's records |
| 7 | action_type | tool_call · tool_response · decision · delegation · escalation · error · lifecycle |
| 8 | action_detail | Action-type-specific object |
| 9 | outcome | success · failure · timeout · denied · escalated |
| 10 | trust_level | L0–L4 |
| 11 | parent_record_id | Null only for the genesis record |
| 12 | prev_hash | SHA-256 of the previous record's canonical JSON (RFC 8785 JCS), lowercase hex; null only for genesis |
| 13 | record_phase | pre_execution · post_execution · concurrent |
The draft is an individual Internet-Draft (R. Sharif, 26 Oct 2026, expires 29 Apr 2027): work in progress, not an IETF standard. This profile pins revision -09 and was last verified against the Datatracker text on 2026-10-28.
Lab profile — draft-optional fields the Lab makes mandatory
| Field | Lab rule |
|---|---|
signature + signer_kid | Required on Lab records. ES256 over the record's canonical JSON excluding its signature envelope (signature, signer_kid, sig_alg) and any detached batch field; signer_kid is the RFC 7638 JWK thumbprint of the signing key. |
cost_estimate | Required on every cost-bearing record — the hook the cost module writes into. |
deny_reasons | Required when the outcome is denied. Draft codes verbatim; Lab codes carry the THRESWARDA_ prefix. |
nonce | Required on all Lab records. The replay evidence. |
sequence_number | Required on all Lab records, gap-free from 0 — the sequence-continuity completeness evidence. |
content_fingerprint, input_hash, output_hash | Required where content exists; exports carry hashes, never raw inputs or outputs. |
human_override | Required when a human intervenes — approvals, denials, overrides. |
external_timestamp | Not adopted. An external timestamp anchor is an attestation-shaped claim; this product promises hash/sign integrity only. |
Behavioural rules the schema encodes
Pre-execution recording. Consequential actions are recorded before execution, and the record's outcome is the enforcement decision — denied or escalated — not an execution result. A preflight product that recorded after the fact would fail its own rubric.
Record reproducibility only. Deterministic scenarios claim that their records reproduce. No Lab material claims decision reproducibility for hosted or closed models.
Size discipline. A record should not exceed 64 KB serialised; validators reject records over 256 KB.
How conformance is enforced. The workbench validates every record against this published schema itself at verification time: the schema document is loaded as data and executed by the workbench's validator — it is the single source of truth, not a hand-copied subset of its clauses — and the formats it declares (date-time, UUID, URI) are asserted, not merely annotated. If the schema ever used a construct the validator does not implement, loading would fail outright rather than let a clause pass unenforced.
What verification proves — and what it does not. Records are signed with a per-session key generated in the user's own browser, and exported packets embed that session's public key, so any holder can verify a packet from the packet alone. Verification proves the packet was not altered after export; it does not by itself prove who created the session.
The reference refund-authority policy
Machine-readable form: policy/refund-authority-policy.json — the same object the workbench enforces. Its parameters are the product's reference configuration, stated here as configuration, not as findings:
| Parameter | Reference value |
|---|---|
| Acting agent's tools | refund.issue · refund.status · invoice.read · writeoff.issue |
| Delegated subagent's scope | invoice.read · refund.status (no money movement) |
| Per-action limit | $250 per refund; $2,500 per write-off |
| Approval threshold | Approval required above $100; high-value approval above $1,000 |
| Loop-cost ceiling | $25, enforced |
| Cumulative refund cap | $2,000, enforced |
| Step ceiling | 40 steps, enforced |
| Wall-clock ceiling | 30 minutes of declared step durations, enforced |
| Enforcement switches | Nonce checking, authority-chain enforcement, approval enforcement, grant-expiry enforcement — all on |
Deny-reason codes used by the gate include the draft's registry codes
(CAPABILITY_NOT_GRANTED, REPLAY_DETECTED) and Lab-prefixed codes
(THRESWARDA_GRANT_EXPIRED, THRESWARDA_PER_ACTION_LIMIT,
THRESWARDA_APPROVAL_DENIED, THRESWARDA_CUMULATIVE_CAP,
THRESWARDA_CEILING_HALT).
OTel gen_ai.* alignment
The GenAI semantic conventions are at Development stability and live in the
open-telemetry/semantic-conventions-genai repository (pinned at this build,
2026-10-28). All gen_ai.* names are kept in a single mapping module in the product,
so a rename is a one-file change. Two rules matter most: input mapping dual-accepts the deprecated
gen_ai.system while emitted telemetry uses gen_ai.provider.name only;
and OTel carries tokens, not dollars — every dollar figure in this product comes from the cost
module's stated rate card (rate-card-2026-10-28-v1:
input $0.004 / 1K tokens, output $0.016 / 1K tokens, $0.002 per API call, $0.005 per tool call,
rounded per step, half-up to cents), never from a telemetry attribute rendered as money.