You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
suggested-binding-loop (b): unknown ?status on /security/suggested-bindings returns 200 empty instead of 400 (live REST route skips validation) #7678
GET /api/v1/security/suggested-bindings?status=garbage → 200 empty (same for ?status=PENDING) — which reads as "there are no suggestions", the failure mode the clause forbids. Expected 400 for an unknown status value.
Root cause
Located by the run. The live route is packages/rest/src/rest-server.tsregisterSecurityEndpoints, which forwards req.query.status through with no validation (rest-server.ts ~L9219: status: req.query?.status ? String(req.query.status) : undefined). The isSuggestionStatus 400 guard exists only on the parallel runtime dispatcher domain, whose own comment describes precisely this observed behaviour. The fix landed on the dispatcher path only — a dispatcher-vs-REST divergence in the opposite direction from the earlier /meta cases (where routes were on the dispatcher but never mounted on REST). Confirmed present on origin/main.
This strengthens the case for the route-ledger↔live-mount parity gate #7526, and argues that gate should cover behaviour divergence, not just mount presence.
Reproduction
Stock boot; as admin GET /api/v1/security/suggested-bindings?status=garbage.
Observe 200 with an empty list instead of 400.
Suggested fix
Apply the isSuggestionStatus validation (the same guard already on the dispatcher) on the live registerSecurityEndpoints REST route, returning 400 for an unknown ?status value.
File surface: packages/rest/src/rest-server.ts — the registerSecurityEndpoints / suggested-bindings region (~:9219) only + tests. Stop on breach; explain in the report.
Container & model: M, mode:cloud, model: claude-opus-5.
The guard already exists on the runtime dispatcher domain, and its own comment describes exactly the behaviour observed here. So this is a convergence fix: the live REST route calls the same predicate, it does not grow a second copy of the status vocabulary. A re-implemented check would be the fourth instance this lane has closed today of one rule in two implementations (#7616, #7652, #7602, #7749) — ⛔ do not add a fifth.
If the guard is not currently importable from where the REST route sits, say so and propose the smallest shared home rather than duplicating it; ⛔ do not copy the status list.
Pin the consequence — and note the failure mode is a silent one
?status=garbage returning 200 with an empty list is worse than an error: it reads as "there are no suggestions", which is a plausible, actionable-looking answer. That is the specific thing to pin.
?status=garbage → 400, with the error codeandstatus asserted per ADR-0112 (⛔ not merely "it did not return 200").
?status=PENDING (the card names it — wrong case for the vocabulary) → 400 as well, unless measurement shows the vocabulary genuinely accepts it. If it does accept it, say so; that changes the card.
Negative, load-bearing: every valid status still returns its list, and no?status at all still returns the unfiltered list. A fix that 400s everything would satisfy the positives and break the route.
Reverse-verify: with the guard removed, the 400 cases go red and the negatives stay green.
Worth noting, ⛔ not in scope
The card argues this strengthens the case for the route-ledger↔live-mount parity gate (#7526) covering behaviour divergence, not just mount presence — and it is right, because this divergence points the opposite way from the earlier /meta cases (mounted on the dispatcher, absent from REST). ⛔ Do not build or extend that gate here. If your measurement turns up other REST routes whose dispatcher twin validates and they do not, list them in out_of_scope_findings as their own finding issues (search first) — that list is the useful input to #7526, and it is worth more than fixing them one at a time.
Premise-first: verify on current origin/main that the REST route still forwards status unvalidated and the dispatcher still guards it — find by text, not line number (several PRs landed in this file today). Already fixed ⇒ premise_still_valid: false, no PR.
Activity
hotlong commentedon Aug 12, 2026
Claim: PM loop round 8 —
domain:cliseat.session_01B3Kurx8qufrDzNjk4rag7V(accounthotlong)claude/issue-7678-suggested-bindings-status-validationdomain:clipackages/rest/src/rest-server.ts— theregisterSecurityEndpoints/ suggested-bindings region (~:9219) only + tests. Stop on breach; explain in the report.mode:cloud,model: claude-opus-5.rest-server.tsis free — A bearer-authenticated admin metadata write is stampedactor: 'system'—req.user/req.userIdare unset on the/metaPUT path #7749/PR fix(rest): attribute a bearer-authenticated metadata write to its caller (#7749) #7940 (resolveMetaWriteActor+ the five/metawrite sites) merged at ~07:5xZ, as did REST: the UNIQUE_VIOLATION 409 message is hard-coded English and carries no field — and it is less informative than the bulk path's own message for the same constraint #7821/fix(rest): name the conflicting field in the UNIQUE_VIOLATION 409 body (#7821) #7930 (mapDataError) and finding:/meta/_draftsserves DRAFT object schemas unmasked — the one ADR-0106 outlet left uncovered #6599/fix(meta): gate_draftsoutlets as authoring surfaces (ADR-0106 D5(4), #6599) #7907 (_drafts). This card's region is disjoint from all of them regardless.裁决:复用既有的
isSuggestionStatus,⛔ 不重写一份The guard already exists on the runtime dispatcher domain, and its own comment describes exactly the behaviour observed here. So this is a convergence fix: the live REST route calls the same predicate, it does not grow a second copy of the status vocabulary. A re-implemented check would be the fourth instance this lane has closed today of one rule in two implementations (#7616, #7652, #7602, #7749) — ⛔ do not add a fifth.
If the guard is not currently importable from where the REST route sits, say so and propose the smallest shared home rather than duplicating it; ⛔ do not copy the status list.
Pin the consequence — and note the failure mode is a silent one
?status=garbagereturning 200 with an empty list is worse than an error: it reads as "there are no suggestions", which is a plausible, actionable-looking answer. That is the specific thing to pin.?status=garbage→ 400, with the errorcodeandstatusasserted per ADR-0112 (⛔ not merely "it did not return 200").?status=PENDING(the card names it — wrong case for the vocabulary) → 400 as well, unless measurement shows the vocabulary genuinely accepts it. If it does accept it, say so; that changes the card.?statusat all still returns the unfiltered list. A fix that 400s everything would satisfy the positives and break the route.Worth noting, ⛔ not in scope
The card argues this strengthens the case for the route-ledger↔live-mount parity gate (#7526) covering behaviour divergence, not just mount presence — and it is right, because this divergence points the opposite way from the earlier
/metacases (mounted on the dispatcher, absent from REST). ⛔ Do not build or extend that gate here. If your measurement turns up other REST routes whose dispatcher twin validates and they do not, list them inout_of_scope_findingsas their ownfindingissues (search first) — that list is the useful input to #7526, and it is worth more than fixing them one at a time.Premise-first: verify on current
origin/mainthat the REST route still forwardsstatusunvalidated and the dispatcher still guards it — find by text, not line number (several PRs landed in this file today). Already fixed ⇒premise_still_valid: false, no PR.Generated by Claude Code
hotlong commentedon Aug 12, 2026
Dev claim (picking up the PM dispatch above).
session_01Xc86SFVAgZHc52YF9iLxCcclaude/issue-7678-suggested-bindings-status-validationStarting with premise verification on
origin/main(find by text, not line number), then the convergence fix reusing the existingisSuggestionStatus.Generated by Claude Code
Generated by Claude Code
fix(rest): refuse an unknown ?status on /security/suggested-bindings (o…