Residuals from the review of PR #2208 (Review queue refresh, Refs #2194) that are below the merge-blocking bar or beyond its scope. Triaged once at the two-round ceiling; none of these reopens that PR.
Source: Codex round 2 on head 844c1ad5a (2026-08-29T07:40Z), threads on frontend/taskdeck-web/src/composables/useReviewProposals.ts.
1. Re-authorise a deep-linked proposal before restoring it (Codex P1 → MEDIUM here)
The unscoped list endpoint filters an inaccessible proposal out and returns 200, not 403, so the deep-link pin restores the previously loaded object on ID match alone. Result: a proposal the user can no longer access stays on screen with its operations, provenance and action controls until navigation; any action is rejected server-side with 403. No new data reaches the client (the object was loaded while access was valid), so this is stale state, not a leak — but it is exactly the false-state class the PR targets. Fix direction: re-fetch the pinned proposal (getProposal(id)) when it is absent from the list response and drop the pin on 403/404, or treat absence-from-list as revocation for the pin.
2. Restart polling after permission recovery (Codex P2)
After a 403, clearing the scope calls loadProposals() which clears queueAccessRevoked, but nothing restarts the interval — the recovered queue is a point-in-time read until the route is left and re-entered. Fix direction: startQueueRefresh() on a successful load when queueAccessRevoked was set.
3. Mark the queue stale when refreshes fail (Codex P2)
Repeated poll failures only log, leaving "Nothing waiting. Good." on screen with no degraded indicator — the same false negative the PR removes for the happy path. Fix direction: a queueStaleSince flag set after N consecutive failures, cleared on success, rendered in the eyebrow/live region in both skins.
Fixed in the PR's final round (recorded here for the trail)
saveRevision() did not replace the proposals array, so a poll started just before it passed both stale-response guards and restored the pre-revision summary/operations/latestRevisionId — fixed on the PR (same class as the round-1 HIGH).
- A late 403 from a superseded scope entered the catch without the load-generation check the success path has, so it could clear a freshly loaded queue for another board and stop polling — fixed on the PR.
Related: #2194 (parent), #2205 (apply-rate split), #2202.
Residuals from the review of PR #2208 (Review queue refresh, Refs #2194) that are below the merge-blocking bar or beyond its scope. Triaged once at the two-round ceiling; none of these reopens that PR.
Source: Codex round 2 on head
844c1ad5a(2026-08-29T07:40Z), threads onfrontend/taskdeck-web/src/composables/useReviewProposals.ts.1. Re-authorise a deep-linked proposal before restoring it (Codex P1 → MEDIUM here)
The unscoped list endpoint filters an inaccessible proposal out and returns 200, not 403, so the deep-link pin restores the previously loaded object on ID match alone. Result: a proposal the user can no longer access stays on screen with its operations, provenance and action controls until navigation; any action is rejected server-side with 403. No new data reaches the client (the object was loaded while access was valid), so this is stale state, not a leak — but it is exactly the false-state class the PR targets. Fix direction: re-fetch the pinned proposal (
getProposal(id)) when it is absent from the list response and drop the pin on 403/404, or treat absence-from-list as revocation for the pin.2. Restart polling after permission recovery (Codex P2)
After a 403, clearing the scope calls
loadProposals()which clearsqueueAccessRevoked, but nothing restarts the interval — the recovered queue is a point-in-time read until the route is left and re-entered. Fix direction:startQueueRefresh()on a successful load whenqueueAccessRevokedwas set.3. Mark the queue stale when refreshes fail (Codex P2)
Repeated poll failures only log, leaving "Nothing waiting. Good." on screen with no degraded indicator — the same false negative the PR removes for the happy path. Fix direction: a
queueStaleSinceflag set after N consecutive failures, cleared on success, rendered in the eyebrow/live region in both skins.Fixed in the PR's final round (recorded here for the trail)
saveRevision()did not replace theproposalsarray, so a poll started just before it passed both stale-response guards and restored the pre-revision summary/operations/latestRevisionId— fixed on the PR (same class as the round-1 HIGH).Related: #2194 (parent), #2205 (apply-rate split), #2202.