Skip to content

Follow SEP-2624: drop chain naming, use confirmations for "ask" - #32

Merged
murthy-g merged 5 commits into
mainfrom
sep-confirmation
Oct 20, 2026
Merged

murthy-g merged 5 commits into
mainfrom
sep-confirmation

Conversation

@murthy-g

Copy link
Copy Markdown
Contributor

Two changes to follow the current SEP-2624 draft.

Rename (#24). ChainOutcome is now PhaseOutcome, and the "chain" wording is gone from the invoker and the gateway, since the SEP no longer has a chain concept. No behaviour change.

Confirmations for "ask" (#30). This follows the proposal in modelcontextprotocol/experimental-ext-interceptors#45.

  • adtl.policy returns "ask" as valid: false, severity: "error" with confirmation: { id, reason, callHash, expiresAt, token }. An invoker that doesn't implement confirmations still blocks the call. info["adtl/decision"] is still set.
  • callHash now covers the call binding { event, phase, target, payload } (new callBindingHash() in @adtl/labels). The token is an HMAC over the id, that hash, the session and the expiry.
  • adtl.policy accepts a confirmation from context.confirmations only for the same call, in the same session, before it expires, and only once. A confirmation never turns a "block" into an allow.
  • The gateway sets context.target to the upstream server on every interceptor invocation. After a human approves, it re-invokes the validators with context.confirmations, and forwards the call only if they all allow it and it still hashes to the approved value.
  • The confirmation token stays inside the gateway; it is not included in the error results the agent sees.

Note: callHash values in audit logs differ from 0.4.0. The Claude Code hooks path still uses the old callHash(server, tool, args), since it doesn't go through the interceptors.

Tests: 188 pass, typecheck clean. New tests cover single use, a different call, another session, a forged token, expiry, a block not being overridden, the second check in the gateway, and the token never reaching the agent.

Closes #24
Closes #30

adtl.policy returns a confirmation request (id, reason, callHash,
expiresAt, HMAC token) with valid: false, so invokers without
confirmation support still block. callHash now covers the call binding
{ event, phase, target, payload }. The gateway sets context.target and,
after a human approves, re-invokes the validators with
context.confirmations and forwards only if they all allow the call and
it still hashes to the approved value. info["adtl/decision"] is still set.

Closes #30
@murthy-g
murthy-g merged commit 5f057f4 into main Oct 20, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use the confirmation field from the SEP-2624 proposal in adtl.policy Rename internal "chain" naming after SEP-2624 dropped the chain concept

1 participant