{"slug": "control-before-proof-after-an-accountability-primitive-for-ai-agents", "title": "Control before, proof after: an accountability primitive for AI agents", "summary": "A developer proposes an accountability primitive for AI agents that combines authorization and audit into a single object. The system issues a policy-scoped capability that synchronously denies out-of-policy actions before they occur, then asynchronously records a tamper-evident proof of the decision. The approach decouples the fast verdict from durable settlement via a transactional outbox, preventing drift between policy and audit log.", "body_md": "There's a pattern I kept seeing. A team gives an agent real capability, like moving money, shipping a change, or resolving a ticket that touches a customer's account. For a while it's great. Then the agent does one thing nobody can explain or defend after the fact, and the entire program snaps back to a human clicking approve on everything.\n\nThe blocker was almost never the model. It was that there was no clean way to do two things at once. You couldn't bound what the agent was allowed to do before it acted, and you couldn't prove what it did after, in a form that survives contact with an auditor, a regulator, or a customer dispute.\n\nYou can assemble that from parts today. Use a policy engine to authorize, and an audit log to record. The problem is they're two systems, and two systems drift. Six months later, when someone is actually asking \"was this action allowed, and can you prove it,\" the policy engine and the log disagree about what the policy even was at the time. Now you're reconstructing intent from two sources that were never the same object.\n\nThat's the gap. Not authorization by itself, and not observability by itself. The thing that authorizes an action and the thing that proves it should be the same object, bound to the exact policy version in force when the decision was made.\n\nTwo verbs, one primitive.\n\n**Control before.** You mint a capability, which is a policy scoped to one agent: a spend cap, a counterparty allowlist, an expiry, whatever the action needs. Every consequential action the agent takes gets checked against the committed policy state and returns an allow or deny in the request path. An over-budget or out-of-policy action is refused before it happens, not flagged after. Refused is the operative word. The enforcement point commits no state change for a denied action, no matter how the agent reasons, how it's prompted, or whether it's been compromised. You've turned unbounded irreversible harm into bounded irreversible harm.\n\n**Prove after.** The decision's full context is hashed (salted per tenant), signed, and anchored append-only, bound to the exact policy version it was judged under. Later, anyone holding the context can recompute the hash and check it against the anchored record. Change one field and the recomputation won't match, so you can prove the record wasn't edited after the fact. The object that allowed the action is the object that proves it. They can't drift, because they're one thing.\n\nThe part I'm most happy with is that the verdict and the durable proof are decoupled, and neither one becomes a lie.\n\nThe naive version blocks the agent while the record settles. That fails the workload almost immediately. A few concurrent actions and you're either serializing everything or answering the API before the record is durable. That second case is the \"authorized, but we're not sure it was recorded\" state, which is worse than useless in an audit.\n\nSo the verdict is synchronous and the record is asynchronous, through a transactional outbox.\n\nThe agent gets its allow or deny synchronously, off committed state. Sub-second, with no settlement in the hot path. The policy check reads state you can read too.\n\nThe tamper-evident record is persisted before the API answers, then settles asynchronously. It's retried until it lands, and alerted on if it can't. The agent never blocks on settlement, and there's no window where you've authorized something you failed to durably record.\n\nGetting that split right is most of the actual engineering. Exactly-once recording means a retry can't double-write a decision. Single-writer-per-capability means a stale read can't double-spend a budget by racing two actions through at once. Those two properties are what let you decouple the fast path from the durable path without opening a hole.\n\nThis is the load-bearing claim, so it should be the one you can check hardest.\n\nThe record is a salted hash of the decision context, signed, anchored append-only. You hold the context. You recompute the hash. You check it against the anchor. Nothing in that loop requires trusting our server to still exist or to still be honest, which is the whole point, because the dispute you care about is often with the company holding the log.\n\nTwo design choices fall out of that.\n\nPost-quantum signatures, using ML-DSA (FIPS 204). These records are meant to be checkable years out. The scheme is standardized and cheap to adopt, so it's low-cost insurance rather than a headline.\n\nPer-record crypto-shred. The on-chain record is a salted hash, and the salt lives off-chain, per tenant. Destroy the salt and the hash can never be recomputed and the context never recovered. The ledger stays immutable, but the erasure is real and provable. That's how an immutable record and a right-to-erasure coexist instead of contradicting.\n\nAnd because the claim is \"verifiable, don't trust us,\" the client SDKs are open source, in TypeScript, Python, and Go, so you can read exactly what gets hashed and signed on your behalf. If the code that computes the thing you're supposed to independently verify were closed, the claim would be hollow.\n\nThe anchor lives on a post-quantum L1 we built. I know how that reads.\n\nThe honest version: I needed PQ signatures and clean per-record crypto-shred as first-class properties, plus a record that doesn't depend on my company surviving to remain checkable. Existing chains didn't give me those from genesis, and I didn't want per-record public gas costs or a token in the developer's face. You don't touch any of it. No token, no wallet, no gas. You call a REST API or an SDK. Whether that justifies a new L1 is the fair debate, and I'd rather have it in the open than pretend the substrate isn't there.\n\nStraight answer: sometimes you shouldn't.\n\nIf an append-only Merkle log is enough, like Certificate Transparency, Trillian, or Rekor, and you don't need the record verifiable without trusting your own server, and you don't need per-record erasure, then use that. It's simpler.\n\nIf your authorization and your audit trail genuinely can't drift, because you already bind every decision to the exact policy version and can prove it, you may not need this primitive at all.\n\nYou'd reach for this when the same object has to authorize before and prove after, when the proof has to hold up against the company that produced it, and when \"immutable\" and \"erasable\" both have to be true. That's a narrow, real set of situations, like regulated actions, money movement, and anything where a decision might be litigated. It's exactly where bolting a policy engine to an audit log leaves you exposed six months later.\n\nThere's a live demo, no signup. Give an agent a budget, watch it get allowed twice and then blocked when it goes over, see the decision recorded, verify the record is intact, then tamper with a field and watch the check catch it. About thirty seconds in the browser.\n\nIt's a managed beta, and I'll say the early parts plainly. Today we custody the agent's signing key, KMS-sealed, and we never hold your principal key. We also run the validators. Non-custodial issuance and third-party validation are the direction, not the current state. The control and proof loop, the SDKs, the PQ signing, and the crypto-shred are real now.\n\nThe feedback I most want is where this is wrong, where it's redundant with something you already trust, and where you'd never put a third party in the path.", "url": "https://wpnews.pro/news/control-before-proof-after-an-accountability-primitive-for-ai-agents", "canonical_source": "https://dev.to/4quarters/control-before-proof-after-an-accountability-primitive-for-ai-agents-11nl", "published_at": "2026-07-09 18:30:25+00:00", "updated_at": "2026-07-09 19:05:42.764146+00:00", "lang": "en", "topics": ["ai-agents", "ai-safety", "ai-ethics", "ai-infrastructure", "developer-tools"], "entities": [], "alternates": {"html": "https://wpnews.pro/news/control-before-proof-after-an-accountability-primitive-for-ai-agents", "markdown": "https://wpnews.pro/news/control-before-proof-after-an-accountability-primitive-for-ai-agents.md", "text": "https://wpnews.pro/news/control-before-proof-after-an-accountability-primitive-for-ai-agents.txt", "jsonld": "https://wpnews.pro/news/control-before-proof-after-an-accountability-primitive-for-ai-agents.jsonld"}}