PR #2208 makes an open Review page poll its queue, so a poll can now replace the active proposal's row while a reviewer is working on it. Three consequences were raised by Codex after that PR's two-round review ceiling (2026-08-29T10:13Z, threads on useReviewProposals.ts:633); triaged once and tracked here rather than fix-cycled. None reaches the merge-blocking bar on its own because every path still ends in the shipped two-step trust model — Approve is explicit and Apply is a separate explicit step with an Idempotency-Key (ADR-0003 / GP-06) — but together they describe one class: the active proposal changes under a live reviewer's hands.
A. Preserve decision focus when a poll removes or settles the active proposal (Codex P1 → MEDIUM here)
When another session settles or removes the active Paper proposal, canRefreshQueue still allows the replacement (no action or dialog is active), activeProposal falls through to the next pending row, the keyed ReviewMain is re-created (focus drops out of the decision control), and the window-level keymap stays enabled for the newly selected proposal. A review shortcut pressed next acts on a proposal the user never chose. Fix direction: when the active proposal disappears from a poll, do not auto-activate the next row — clear the selection, announce it in the live region ("This proposal was decided elsewhere"), and move focus to a safe target; or defer the replacement while focus is inside the decision surface.
B. Invalidate an open diff when the polled latestRevisionId changes (Codex P1 → MEDIUM here)
Both skins key their cached live diff on the proposal ID only (Paper also clears it on a local save). If another reviewer saves a revision, the poll brings in the new effective operations but the preview beside them was computed for the previous revision, while Approve pins and Apply executes the server's latest. Fix direction: key the diff watchers on latestRevisionId as well and clear/reload the diff when it changes.
C. Reload revision state when a poll changes the latest revision (Codex P2)
useProposalRevisions watches only activeProposal.id, so after a poll replaces the row revisionCount stays stale and editablePayload keeps preferring the cached earlier latestRevision; opening Edit and saving can create a newer revision from obsolete operations, overwriting a collaborator's edit. (The overwrite itself pre-dates polling — before #2208 the whole row was stale — but the row/revision inconsistency is new.) Fix direction: watch latestRevisionId too, or resync revision state whenever the active row is replaced.
Related: #2194 (parent), #2214 (other #2208 residuals), #2205, ADR-0003, GP-06.
PR #2208 makes an open Review page poll its queue, so a poll can now replace the active proposal's row while a reviewer is working on it. Three consequences were raised by Codex after that PR's two-round review ceiling (2026-08-29T10:13Z, threads on
useReviewProposals.ts:633); triaged once and tracked here rather than fix-cycled. None reaches the merge-blocking bar on its own because every path still ends in the shipped two-step trust model — Approve is explicit and Apply is a separate explicit step with an Idempotency-Key (ADR-0003 / GP-06) — but together they describe one class: the active proposal changes under a live reviewer's hands.A. Preserve decision focus when a poll removes or settles the active proposal (Codex P1 → MEDIUM here)
When another session settles or removes the active Paper proposal,
canRefreshQueuestill allows the replacement (no action or dialog is active),activeProposalfalls through to the next pending row, the keyedReviewMainis re-created (focus drops out of the decision control), and the window-level keymap stays enabled for the newly selected proposal. A review shortcut pressed next acts on a proposal the user never chose. Fix direction: when the active proposal disappears from a poll, do not auto-activate the next row — clear the selection, announce it in the live region ("This proposal was decided elsewhere"), and move focus to a safe target; or defer the replacement while focus is inside the decision surface.B. Invalidate an open diff when the polled
latestRevisionIdchanges (Codex P1 → MEDIUM here)Both skins key their cached live diff on the proposal ID only (Paper also clears it on a local save). If another reviewer saves a revision, the poll brings in the new effective operations but the preview beside them was computed for the previous revision, while Approve pins and Apply executes the server's latest. Fix direction: key the diff watchers on
latestRevisionIdas well and clear/reload the diff when it changes.C. Reload revision state when a poll changes the latest revision (Codex P2)
useProposalRevisionswatches onlyactiveProposal.id, so after a poll replaces the rowrevisionCountstays stale andeditablePayloadkeeps preferring the cached earlierlatestRevision; opening Edit and saving can create a newer revision from obsolete operations, overwriting a collaborator's edit. (The overwrite itself pre-dates polling — before #2208 the whole row was stale — but the row/revision inconsistency is new.) Fix direction: watchlatestRevisionIdtoo, or resync revision state whenever the active row is replaced.Related: #2194 (parent), #2214 (other #2208 residuals), #2205, ADR-0003, GP-06.