wait step. Tokens are opaque capabilities; do not expose them in logs.
List pending waitpoints
A database failure is
500.
Who may decide
Every completing route goes through one resolve door (B14, #2388, PR #2394) that derives the decider from the request’s auth, never from the body:- a session or CLI-token principal is a person — the inbox, the routine
page,
crewship routine waitpoints approve|reject; - the holder of the token on the external route is external (recorded
as
external-callback); - an agent’s internal token is an agent, and the door refuses it:
403 {"error": …, "reason": "waitpoint_decider_not_allowed"}. The waitpoint is untouched and the attempt is written to the audit log aswaitpoint.decision_refused(crewship audit --action waitpoint.decision_refused). A request with no principal at all is refused the same way. In practice an agent never reaches the authenticated route — internal tokens are401there — but the door checks the kind regardless, so a future agent-facing route cannot quietly become a way for a peer agent to say “go”.
Approve or deny from the inbox
approved means false on this authenticated
route. comment is optional and is stored as the decision payload. This is an
update/MANAGER+ operation. A successful response is
{"ok":true,"approved":true|false} and resumes the parked run for either
decision. Missing tokens are 400; malformed JSON is 400; an
expired/already-decided token is 409; an unauthenticated caller is 401,
a role below MANAGER 403, and an agent or principal-less caller 403 with
reason: waitpoint_decider_not_allowed (see above); an unavailable waitpoint
store is 503; and completion failures are 500.
Complete from an external service
approved defaults to true (unlike the authenticated approve
route). payload accepts any JSON and is stored for the resumed step. It
returns {"ok":true,"approved":true|false}; an empty token is 400, an
already-decided or expired token is 409, malformed JSON is 400, an
unavailable or non-completing waitpoint store is 503, and other completion
failures are 500.