Every agent decision now names an accountable human — signed, recorded, and chain-committed

2026-09-15

securitygovernancetrust-envelopeaudit-chainagent-lifecycle

LOCKSTEP TRACEABILITY MATRIX --- api_endpoints: [ "POST /v1/agent/bootstrap (owner_id)", "POST /v1/agent/profiles (owner validation)", "PATCH /v1/agent/profiles/{agentId} (owner validation)", "GET /v1/governance/lineage/{request_id} (principal block)", "GET /v1/governance/artifacts/{request_id} (accountability block)", ] sdk_methods_updated: ["agentProfiles.bootstrap() owner_id", "agent_profiles.bootstrap(owner_id=) sync + async"] mcp_tools_updated: ["br_bootstrap_agent (owner_id)"] ---

What We Built

The agent profile store has carried an owner_id since the ARM work, and both agent auth paths already hoisted it onto the request context. Nothing downstream ever read it. The signed trust envelope, the hash-chained audit row, and the governance artifact all said _which agent_ acted and none of them said _which human_ is answerable for it. An auditor holding an artifact could not answer the first question a Hush-educated buyer now asks: "who owns this agent?"

This change binds the owner into every evidence surface through one resolver, resolveRequestAccountability(c), so the surfaces can never disagree:

  • Trust envelopebr_principal.owner_id + owner_source, signed with the rest.
  • Audit rowcompletion_audit.principal_owner_id on every allow, deny, error,

cache-hit and guardian-denial write (migration v69, non-hashed like grant_context).

  • Lineage decisiondecision.accountability inside the bound lineage row, covered

by lineage_digestprovenanceDigest → the chain. A post-hoc edit of the owner is chain-detectable. This is the copy the artifact prefers.

  • Governance artifact — a signed accountability block with an explicit

evidence: committed | recorded flag, and a new EU AI Act Art. 14 control.

Two opt-in knobs make it a policy, not just a record. owner_id on bootstrap defaults to the _user_ behind the bootstrapping key (never the key id — a credential is not a person). BR_AGENT_OWNER_REQUIRED=1 refuses to create an ownerless agent (400) and refuses agent-authenticated requests from an ownerless profile (403 owner_required with a recovery hint), leaving only the self-service paths an agent needs to get fixed.

Why It Matters

Identity vendors are teaching buyers that agent governance means "every agent has an accountable owner." They can prove it in a directory. BrainstormRouter proves it on the decision itself: the owner is signed into the grant the request ran under, and chain-committed next to the model, the policy verdict and the cost. That is evidence a directory cannot produce, and it is the exact artifact an EU AI Act Art. 14 review asks for.

How It Works

// One resolver, every surface.
const a = resolveRequestAccountability(c);
// agent caller  → { agent_id, owner_id: profile.ownerId, owner_source: "agent_profile" }
// api-key caller → { agent_id: null, owner_id: apiKey.userId, owner_source: "api_key_user" }
// unknown        → { agent_id, owner_id: null, owner_source: null }   // never guessed

The router receives it as lineageAccountability and stamps it into the decision payload; the completions handler passes principalOwnerId to every chained audit write; synthesizeEnvelope signs it. On read, assembleLineageWhy exposes a principal block and deriveAccountability picks the committed copy first, the recorded column second, and omits the key when neither exists so pre-binding artifacts keep their exact signed bytes.

The chain payload versions (v1/v2) are untouched. The owner rides the lineage digest, which v2 already commits, so no verify-side dispatch changed and no published test vector moved.

The Numbers

SurfaceBeforeAfter
Envelope names an ownerneveralways (or honest null)
Audit rows with owner0every write site (20)
Artifact accountabilityabsentcommitted / recorded, signed
Framework controls per plain completion1 (SOC2 CC7.2)2 (+ EU AI Act Art.14 when owned)
Bootstrap owner defaultnone (ownerless)bootstrapping key's user

Competitive Edge

Hush, Astrix and the NHI vendors bind an owner to an identity in their directory. BrainstormRouter binds the owner to the _decision_: the signed grant, the chained audit row and the artifact the auditor holds. No gateway that sits beside the model call can produce that; no directory that sits beside the agent can either.

Lockstep Checklist

  • [x] API Routes: bootstrap owner_id; profile create/patch owner validation; lineage principal; artifact accountability.
  • [x] TS SDK: AgentBootstrapParams.owner_id (packages/sdk-ts/src/types.ts).
  • [x] Python SDK: bootstrap(owner_id=) sync + async (packages/sdk-py/.../agent_profiles.py).
  • [x] MCP Schemas: br_bootstrap_agent accepts owner_id; agents.json regenerated.
  • [x] Docs: docs/api-reference/agents.mdx, docs/api-reference/governance.mdx.
  • [x] Migration: v69 completion_audit.principal_owner_id (idempotent, additive).
  • [ ] Master Record: capability record entry for owner binding — follow-up.
  • [ ] Production verification: deploy, bootstrap an owned agent, fetch its artifact and confirm accountability.evidence === "committed".