A machine answers an outbound wait through its own route
A remote system cannot use the route a human uses; it has no session and so cannot present the token that route requires. It gets a route built for its threat model, and an authority that buys it nothing else.
The rule
- A machine caller resolves an outbound wait by posting
{"value": …}(the same key the human resolution route takes) to a dedicated callback route addressed by the interrupt's unguessable identifier. - The human route requires a session-bound request token that a machine cannot obtain; the callback route does not require one, and must therefore admit only authentication schemes a cookie-authenticated browser cannot present, so there is no session to ride and nothing for such a token to protect.
- Authorisation is a dedicated authority to resolve interrupts by callback: it is not satisfied by, and does not grant, the authority to resolve interrupts as a human.
- The route is scoped by interrupt type, not by direction: only an external-call interrupt (the one shape a remote system was invited to answer) is resolvable here, and any other is refused
409. - Every human prompt shape is stamped outward exactly as an external call is, so a direction-only guard would hand the callback credential a person's approval prompt and resume the run as though someone had answered; a direction check is kept behind the type check as defence in depth.
- An unknown identifier answers
404; an interrupt that is not pending, or has expired, answers409, so a replayed callback never resolves twice. - A request omitting
valueis refused400before the interrupt is looked up, so a malformed request reveals nothing about which identifiers exist.
What it means
A remote system has no session to ride, so the human route's request token is not something it can ever present; it gets a callback route built for what it actually is, addressed by the interrupt's own unguessable identifier instead of a session. Reaching that route does not make a caller a human: resolving by callback is a distinct authority that grants nothing else, in particular not the authority to answer as a person would.
The bite is in the guard order, not just its existence. The route is scoped
by interrupt type first — only the one shape a remote system was invited
to answer is resolvable here — and the direction check sits behind it. Every
human prompt is stamped outward exactly as an external call is, so checking
direction alone would let the callback credential answer a person's approval
prompt. And the missing-value check runs before the interrupt is even
looked up: a malformed request gets refused without learning whether the
identifier it named exists at all.
Example
POST /api/flowdrop/interrupts/{interrupt_id}/callback
{"value": {"ok": true}}POST /api/flowdrop/interrupts/{interrupt_id}/callback
{}POST /api/flowdrop/interrupts/{interrupt_id}/callback
{"value": true}The second request is refused for what it is missing, before anything is
looked up; only a well-formed request against an unknown identifier reaches
404.