Get started

Agent Honesty Chain

The Response Contract catches lies within a single reply. This catches the ones that only show up once you follow the chain.

The Agent Response Contract checks a single reply against this turn's skill results. It cannot answer questions that span turns, agents, or organisations: "Yesterday you said you'd email the report. Did you?", "The agent said SENTINEL completed the audit, was that real?", "Org X says they approved this, did they?"

The Agent Honesty Chain (AGH-CHAIN) is the layer that answers those questions, by walking the AEE envelope chain and VOLT event log that Quox already produces.

The four guards, and their windows

GuardWhat it checksWindow
detect_promiseDetects a future-tense commitment ("I'll send the report tomorrow") and persists a promise envelope.Write-only, no lookback.
verify_promise_keptOn a later turn in the same conversation, scans past-tense fulfilment claims ("as promised, I sent the report") and looks for a matching VOLT skill-execution event since the promise was made.Since the promise's created_at, same conversation.
verify_cross_agent_claimWalks the AEE chain backwards for an envelope where the named agent performed the claimed action.Capped at 2 hours or the last 50 envelopes, same org and correlation.
verify_cross_org_claimWalks the inbound cross-org chain for a WARD-signed envelope from the named org, matching the trust-roots table.Same 2-hour chain window.

Rewrite, not block

When a guard cannot find matching evidence, it rewrites the claim rather than blocking the whole reply. The pre-rewrite text is preserved as result_before_chain so the audit-log UI can show the original draft next to the shipped reply, the same pattern the Response Contract uses with result_before_contract.

A real example from the shipped test suite, turn 3 of a conversation where an earlier promise to send a report was never backed by a matching tool execution:

i

"I want to correct something I said earlier: I cannot find evidence in the chain that I actually completed what I promised. As promised, I sent the report."

Cross-agent and cross-org verification both fail closed: if no matching evidence is found, the claim is rewritten to an honest fallback rather than passed through. A cross-org claim that turns out to be false is treated as high severity, because a lateral cross-tenant lie is the worst kind this surface can catch.

Storage and witnessing

  • Promises live in a chain_promises table, scoped by conversation_id and multi-tenant by org_id.
  • Cross-org trust relationships live in a cross_org_trust_roots table. The schema is live but empty by default; seeding is via direct SQL until an admin UI ships.
  • Every guard application emits a chain_verification_applied VOLT event, the sibling of the Response Contract's response_contract_applied event, carrying the same trace-plus-preview shape.

Coverage of the chain today

verifyCrossOrgClaim ships in name-only mode: a counterparty whose name is in the trust-roots table and has any inbound envelope in the chain window is treated as verified, whether or not that envelope carried a valid signature. This is not a security-boundary breach, because only orgs an admin explicitly added can pass the check, but it is not cryptographic verification either.

Other known limits:

  • The chain walker window is fixed at 2 hours; a conversation spanning longer may miss earlier evidence.
  • Counterparty name matching is case-insensitive but exact. "Acme Corp" and "Acme Corporation" are distinct entries until an admin unifies them.
  • Cross-org claim detection relies on indicator phrases (vendor, client, company, "Corp", "Ltd"). Org names without these signals are not detected.
  • Coverage is the chat dispatch path, flag-gated by AGH_CHAIN_ENABLED (default off in development, on in production). Workflow-executor and MCP paths are not both soaked for this surface.

The Honesty Ledger (dashboard)

AGH-CHAIN's guards are visible as a dedicated page, the Honesty Ledger, at /honesty in the dashboard (Governance nav, admin-gated, auditors allowed to read). It shows:

  • A live flag-state chip ("AGH-CHAIN ON"/"AGH-CHAIN OFF"), read from the collector's status endpoint.
  • The four guards, each with a short description and the window it checks: promise detection (continuous, every response scanned), promise fulfilment (a rolling lookback since the promise was made), cross-agent verification (a 2-hour envelope lookback), and cross-org verification, marked beta in the UI (a trust-relationship check with no fixed window).
  • A recent corrections feed, filterable by 24h/7d/30d, showing which guard fired, which agent, and a one-line summary of what was rewritten.
  • A per-agent leaderboard, the same rollup described below, with an agent picker.

The page is only useful once the chain has actually produced corrections: both the feed and the leaderboard show an honest "the guards are watching" empty state, not fabricated activity, when nothing has fired yet.

It was also fixed today: the ledger's three data calls (status, corrections, leaderboard) previously pointed at the dashboard's own origin, which does not serve those routes and returns a 404, so the page reported AGH-CHAIN as off with empty panels regardless of the flag's real state.

They now go through the same collector-proxied path the rest of the dashboard uses, so the flag chip and feed reflect what the collector is actually doing.

Leaderboard and federated stats

A per-agent honesty leaderboard rolls up response_contract_applied and chain_verification_applied VOLT events by agent over 24h/7d/30d windows. It is a dashboard surface (the /agents view, "Honesty" tab) backed by three APIs: GET /api/v1/agh-chain/leaderboard, .../leaderboard/:agentId (per-agent metrics and sparkline), and .../leaderboard/:agentId/events (drill-through), each with a 5-minute TTL cache.

An opt-in federated stats endpoint, GET /api/public/honesty-stats?window=24h|7d|30d, is gated by AGH_CHAIN_FEDERATE_STATS (default off; the endpoint returns 503 when unset).

The payload is integer counts only, grouped by phantom-claim category, with no text, conversation IDs, agent IDs, or customer identifiers. If any single category's count is below 5, Laplace noise is applied to every count in the payload and the response is flagged k_anon_applied: true, so a small install cannot be fingerprinted by its raw numbers.

Maturity

CapabilityStatusNotes
Promise ledger (cross-turn)Stable167 tests, live in the production collector.
verifyPromiseKept guardStableBilingual EN/ES, integration-tested.
verifyCrossAgentClaim guardStableBilingual, tested across the flat agent hierarchy with per-org isolation.
verifyCrossOrgClaim guardBetaName-only mode. No Ed25519 signature verification yet: see Future work below.
chain_promises tableStableLive, multi-tenant scoped.
cross_org_trust_roots tableBetaSchema live, empty by default, admin-seeded via SQL.
AGH_CHAIN_ENABLED flagStableDefault off in development, on in production since the 2026-05-31 cutover.
Federated stats endpointStableOpt-in via AGH_CHAIN_FEDERATE_STATS, default off.
Honesty Ledger dashboard page (/honesty)BetaFixed to call the collector's routes rather than the dashboard's own origin, which 404s; previously reported AGH-CHAIN as off with empty panels regardless of the flag.

Both feature flags above (AGH_CHAIN_ENABLED, AGH_CHAIN_FEDERATE_STATS) are environment variables only today, the same gap noted on the Response Contract page: no dashboard toggle or Settings surface yet shows their state.

Future work (planned, not shipped)

  • Ed25519 cross-org signature verification. The current name-only verifyCrossOrgClaim is designed as a single call-site swap: createNameOnlyVerifier is replaced by createWardSignedVerifier once Ed25519 key management, a signature field on inbound envelopes, and ingest-time verification land in a separate WARD-CRYPTO stream. The interface contract does not change.
  • A compliance profile that forces every guard fail-closed. Proposed as a single QUOX_PROFILE=compliance activation that hard-fails the Response Contract, forces every AGH-CHAIN guard on, and refuses to boot if any invariant cannot be enforced. This is a plan, not a shipped surface.