Skip to content

confirm_gate leaves the handler call outside _refusal_reaches_the_caller #371

Closed

Description

@Cyrax321

What happens

confirm_gate closes its _refusal_reaches_the_caller() block before invoking the handler, so a domain refusal raised inside continuum_confirm would reach the client as the opaque Error executing tool continuum_confirm instead of its own message.

The difference

guard calls the handler inside the context manager:

with _refusal_reaches_the_caller():
    auth.verify(caller, token_from(ctx))
    policy.require(caller, fn.__name__)
    return fn(*args, **kwargs)

confirm_gate does not:

with _refusal_reaches_the_caller():
    confirm_auth.verify(token_from(ctx))
    policy.require(caller, fn.__name__)
return fn(*args, **kwargs)

continuum_confirm calls ctx.storage.append_event(run_id, ...), which raises RunNotFound for an unknown run. Under guard that becomes a ToolError carrying no such run: '<id>'. Here it stays a bare domain exception, which is the case _refusal_reaches_the_caller documents as needing conversion: "a run that does not exist. Each answer is only useful if the caller is told which one it was."

Severity

Latent. Not reproducible in the default configuration, because confirmation refuses every caller before the body runs when CONTINUUM_MCP_CONFIRM_TOKEN is unset. It becomes reachable as soon as an operator opts in, which is exactly when a confirm call against a mistyped run id is likely.

Found by inspection while auditing the MCP surface, not by observation. Flagging it rather than filing it as reproduced.

Suggested fix

Move return fn(*args, **kwargs) inside the with block, matching guard. The authenticate-before-authorize ordering that the surrounding comment protects is unaffected.

A test asserting that both decorators convert a domain exception raised by the handler body would keep the two from drifting again.

Activity

  1. added
    bugSomething isn't working
    mcpMCP server and mutating-tool surface
    on Aug 25, 2026
  2. zynx-real commented on Aug 25, 2026

    @zynx-real
    Contributor

    Hi! I’d like to work on this issue if it’s available.

  3. added a commit that references this issue on Aug 25, 2026
    129c9c4
  4. Cyrax321 commented on Aug 25, 2026

    @Cyrax321
    OwnerAuthor

    Reopened and assigned to @zynx-real, who claimed this at 09:40 UTC and opened #377 at 09:54. I merged a duplicate fix in #379 at 11:14 without checking, which was my error; #381 has reverted it so #377 is the live fix. Details and the one remaining changelog conflict are in #377.

  5. added a commit that references this issue on Aug 25, 2026
    29b7832
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workinggood first issueGood for newcomersmcpMCP server and mutating-tool surface

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions