Your agent asked for approval. Where did the answer go? An engineer's blog post argues that AI agent protocols like MCP and A2A fail to record human judgment in approval workflows, citing a paper by Kang and Diponegoro that scores five protocols against governance dimensions. The post proposes a solution: signing decision records and chaining them by content hash, optionally anchored in an external transparency log like IETF's SCITT, to create tamper-evident audit trails. An agent drafts a refund decision. A reviewer reads it, changes the amount, adds a line about the customer's contract, and approves. The refund goes out. Everyone moves on. Six months later somebody asks who approved that refund, and why the amount changed. The agent's draft is in a trace. The final amount is in the payments system. The reviewer's reasoning was a sentence in a chat thread that has since scrolled away, and the fact that a human changed the number at all is not recorded anywhere as a distinct event. The trace shows a call. The database shows a result. Nobody can show the decision. This is not an unusual failure. It is what happens by default, because the plumbing we have built for AI agents moves work around without recording the judgment applied to it. The Model Context Protocol connects an agent to tools. A2A lets agents discover one another and exchange messages. Both do their jobs well, and neither is trying to do this one. A paper by Kang and Diponegoro makes the point precisely. They take five agent interoperability protocols, including MCP and A2A, and score them against six governance dimensions drawn from organisational theory: membership, deliberation, voting, dissent preservation, human escalation, and audit or replay. Their conclusion is that these protocols coordinate tasks but cannot express a governed community. You cannot state in MCP who is allowed to approve something, how a dissent is preserved, or when a human must be brought in. Governance, they argue, is a missing architectural layer above these protocols rather than a feature inside them. That matches what we kept running into. We build AI systems for regulated industries, where a client cannot simply assert that a human was in the loop. They have to produce the evidence, sometimes years later, to somebody who is paid to be sceptical. "The logs show a call was made" is not evidence that a person exercised judgment. The temptation is to log an approval as a boolean and move on. Approved: true. This is where most implementations start, and it is worth being clear about what it throws away. An approval and an edit are different events. If a reviewer changed the draft before approving it, then the thing that went out is not the thing the agent produced, and the difference is the most interesting part of the record. It is where the human judgment actually lives. So the record needs the agent's output as an artefact, and the human's intervention as an override that carries the diff, the reviewer's rationale, and a flag for whether the edit refined the agent's intent or replaced it. Refining and substituting are different signals: one says the agent was roughly right, the other says it was wrong. Aggregate a few hundred of those and you have an honest measure of where the agent is failing, which is a byproduct of the audit trail rather than a separate analytics project. Rejections and escalations matter too, and for the same reason. A record that only preserves the decisions that went through preserves the successes and discards the disagreements, which is precisely backwards from an accountability point of view. A decision record that the system producing it can quietly edit is not evidence. It is a claim. The fix is old and well understood: sign each record, and chain it by content hash so each entry commits to the one before it. Change any entry after the fact and every subsequent link breaks. A verifier can then re-walk the chain and say whether it is intact, without trusting the system that produced it. For the strongest form, that chain can be anchored in an external transparency log. This is what the IETF's SCITT work is for, and it means a relying party can check a decision happened without asking either party involved. We have an optional profile for it, and we have been discussing the details on the SCITT mailing list, where several implementers pointed out things we had wrong. More on that in a moment, because it is the most useful part of this post. CHAP is our attempt at this layer. It is an open protocol, Apache-2.0, and it rides on MCP and A2A as transport rather than competing with them. The Python coordinator has no runtime dependencies, so the fastest way to see what a decision record looks like is to run one of the worked scenarios straight from a clone, with nothing installed: git clone https://github.com/BrightbeamAI/chap cd chap/scenarios/02-marketing-copy python3 scenario.py That scenario runs a small marketing workflow with one drafter and one editor. It prints the chain, verifies it, tampers with a copy to show the verification failing at the exact entry, reconstructs a single edit with its diff and rationale, and reports which kind of override the editor kept making. The whole thing is deterministic, so you get the same output every time and can read the script to see exactly what produced it. If you would rather wire it into something, the coordinator and the framework bridges are published: pip install chap-coordinator pip install chap-langgraph or chap-pydantic-ai, chap-llama-index, chap-ag2, chap-google-adk npm install @brightbeamai/chap-coordinator npx -y @brightbeamai/chap-coordinator-mcp expose CHAP as MCP tools This is the part worth reading if you are building anything similar, because these were not obvious to us and most of them came from other people. Adapters must not infer decisions. Our first bridges tried to be helpful. If a framework's human-input hook returned an empty string, that looked like assent, so the bridge recorded an approval. It also joined the reviewer as a human participant regardless of what identity the caller supplied. Both are unforgivable in a record whose entire purpose is attributing a decision to a person. An adapter that guesses is manufacturing evidence. Now an explicit decision is required, unknown identity schemes are rejected rather than assumed to be human, and a bot cannot be recorded as a human approver. An override must diff against the artefact under review. Ours originally took the "before" value from the caller. That let a reviewer record an override against a document that was never actually reviewed, which makes the diff a fiction while leaving the rationale and the signature perfectly valid. The base now always comes from the coordinator's own record of what was sent for review. Reading a log should not change it. For a while, calling the audit read method appended an entry to the audit chain, which meant inspecting the log altered it, and so did verifying it. Obvious in hindsight, invisible in practice until somebody looked. Two implementations will disagree about bytes. We have a TypeScript coordinator and a Python one, and they hash records identically, except that Python sorts object keys by code point and the JSON canonicalisation standard sorts by UTF-16 code unit. For any key outside the basic multilingual plane the two produce different canonical bytes, and therefore different hashes for the same object, which quietly breaks cross-implementation verification. If you have two implementations of anything hash-based, test them against each other with awkward input. Integrity checks cannot see a record that was never written. This one came from another implementer on the SCITT list, who has operated a public transparency log and found four cases of it. Chaining and signing prove that the records you hold are intact. They say nothing about a record that failed to be created, and a chain of signed links reads identically whether an approval never happened or happened and was lost. For a human oversight trail that distinction is the whole ballgame. The fix is ordering rather than cleverness: admit the record first, and make the decision's success conditional on it. CHAP is at 0.2.10, with two reference implementations that answer the same conformance suite identically, eleven composable profiles, bridges for the five common agent frameworks, and a first external integration from a team building an execution authority layer, which is currently experimental. The recent releases have been almost entirely security and audit hardening driven by outside review, which is the argument for doing this in the open. Every item in the section above was either found by somebody else or found by us because somebody else asked a sharp question. If you are building agents that take consequential actions, the questions worth asking are the same whether or not you use any of this. Can you produce the record of a single human decision without disclosing the others? Does your override bind to the exact artefact it overrode? Can you tell the difference between no approval and a lost approval? If you want to pull at any of it, the spec, the scenarios, and the conformance harness are at github.com/BrightbeamAI/chap https://github.com/BrightbeamAI/chap , and issues are genuinely welcome, including the ones that tell us we have this wrong.