Skip to content

[Frontend][Review] Degraded-queue follow-ups: decision rail sticky is inert, recovery sentence retired by explicit loads #2638

Description

@Chris0Jeky

Follow-up to PR #2630 (#2214 degraded-queue disclosure), from the read-only verification pass on its round-2 fixes. Neither item blocks that merge; both are tracked here for the smallest follow-up PR.

1. The decision rail's sticky positioning is scoped to a container that never scrolls, so the "rail below the pinned warning" handshake is inert and its comments assert a browser fact that appears false. ReviewDecisionRail renders inside ReviewMain.vue's .paper-review-main, which is overflow: auto with auto height (ReviewMain.vue ~397-401). overflow: auto makes that element the rail's nearest scrollport even though it never overflows (the surrounding .paper-review-deep__main-col is the element that scrolls), so .paper-review-decision { position: sticky; top: var(--paper-review-sticky-offset, 0) } stays at its flow position. Consequences: the round-1 review premise that the rail covered the pinned warning, and the round-2 remedy (a ResizeObserver in PaperReviewView.vue ~1206-1237 writing --paper-review-sticky-offset on the main column, consumed by ReviewDecisionRail.vue ~305-311), target a rail that does not pin; the comments at PaperReviewView.vue ~1195-1200 and ~3027-3032 and ReviewDecisionRail.vue ~305-311 describe a two-sticky band that does not exist; the spec at PaperReviewView.spec.ts ~3392-3394 frames the property as true but unreachable. The pinned warning itself is a direct child of the scrolling column and does stick. This is a CSS reading, not a browser observation; confirm first in a real browser (DevTools shows the sticky badge and its scroll container), then either make the rail's sticky real (its intended scroller is the main column; check why .paper-review-main carries overflow: auto before changing it) or remove the offset machinery and rewrite the comments to say the rail is in flow.

2. The recovery sentence is retired on any successful load, so an explicit load within a poll interval of a recovery can blank the live region before it is announced. useReviewProposals.ts ~651-667 retires queueRefreshRecovered on the next recordQueueRefreshSuccess where queueRefreshStale is already false; explicit loads take the same path (loadProposalsWithOutcome ~588), and they are common right after a recovery: post-decision reloads in useReviewActions.ts (~563, ~591), the batch composables, the board-filter watcher, dismissSettledElsewhereNotice, the pre-decision refresh barrier. Scenario: the poll recovers and sets the text; the reviewer's already-clicked Approve completes ~150 ms later and its reload empties the region; a polite live region whose text is reverted within a few hundred milliseconds may never be spoken. Fix: retire only on a background poll success (not on explicit loads), or track a recovered-at tick and retire on the next poll after it; add the poll-recovery-then-explicit-load spec.

3. Coverage note. The ResizeObserver seam (PaperReviewView.vue ~1206-1237 and the unmount disconnect) has no spec beyond the presence of the custom property; if item 1 keeps it, cover the watch, the observe call and the disconnect.

Refs #2214, PR #2630, PR #2388.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfrontendPrimary implementation impact in Vue/TypeScript UI and client runtime.uxDiscoverability, accessibility, interaction model, and user workflow quality.

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions