The attention feature has been dead since it merged: the gate never allowlisted /api/agent/events #133
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/agent-status"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Every session attention report has been rejected with
401 {"error":"locked"}since #125 merged.AGENT_CALLBACKSinhooks.server.tsnamed three routes; there are four on disk.Reproduced from inside a live session, against the running instance:
Because the gate rejects it, the route's own bridge-IP check never runs either.
Why nobody noticed
Three independent silences line up:
nexus-report.shends its curl with>/dev/null 2>&1 || trueand always exits 0. It has to — a non-zero exit on aStophook wedges the turn, and stdout onSessionStartis injected into the agent's context.hooks.server.tswas unlogged, and Nexus's own stdout has no UI surface (/api/workers/[id]/logsserves worker containers).attention ?? 'running'renders a never-reported session exactly like a healthy pre-feature one. Deliberate, pinned by a parity suite — and precisely what made a dead pipe invisible.#123 replaced the
/api/agent/prefix with this named allowlist and merged 48 minutes before #125 added the route. Different files, no textual conflict, both merged clean.git merge-base --is-ancestor 7b6e5bc 647e70a→ true, so the route was born 401'd on main.Worth noting:
AgentAuthScopeinagent/authorize.tshas read "The four callback routes" — listing'agent events'— since #125. The contradiction sat on disk, greppable, tied to nothing.The fix
One allowlist entry. The rest is guards, since the same seam produced this twice in one week.
+server.jscounts. Matching.tsalone left a route invisible to the guard while SvelteKit still served it.GATED_AGENT_ROUTES, which asserts it 401s. Without a declaration site the failure readsexpected 401 to be 200and pushes the next author toward granting passthrough — the wrong fix in a security test./api/agent/URL inworker/**/*.shis driven through the gate. All four producers hand-write their URL and swallow the response.routeIdis under/api/agent/. Structurally unreachable except by this bug — a path with no route gets a nullrouteIdand 404s, an allowlisted one returns at step 1 — so it costs no false positives and fires on the first hook after a bad merge.Verification
Every guard was proven to fail by breaking what it protects:
+server.js/api/agent/jsroute/api/agent//api/agent(was/api/agent/.)GATED/api/agent/quota/api/agent/renamed-awayexpected 1 to be >= 4End to end over real HTTP against a migrated database:
{}→ 400, bad state → 400, unknown session → 403. All three were 401 before.Typecheck 4941 files / 0 errors. Suite 1508 passed.
Reviewed by four specialist agents (security/code, tests, silent-failure, comments); 12 findings, all applied or declined in the thread.
Not in this PR
SessionStartmust produce anidlewithin seconds of every launch; probe-healthy plusattention_state IS NULLpast that is a broken pipe. It catches the rest of the class (plugin not loading,NEXUS_URLunset, a matcher renamed by a claude-code bump, a 403 from authorize). It needs a launch-timestamp column —convergeSessionscallsclearAttentionagainst acreated_athours old — so it is past "smallest" and belongs on its own.worker/notify-preview.sh:58-59builds its JSON withprintfand raw$LABELinterpolation, whilenotify-artifact.sh:24-25correctly usesjq -n --arg. A label containing"or\produces invalid JSON and a 400. Visible rather than silent, and unrelated to this branch.This does not reach the UI until the
agent-nexusimage is rebuilt and redeployed.