Tracked residuals from the fresh-context review of PR #2484 (#2044, retained Inbox rows after same-scope refresh failures). The HIGH (mount load not treated as a scope replacement) was fixed in that PR; these were classified non-blocking.
MEDIUM — isScopeReplacement is cleared on a resolution the store discarded. useInboxOrchestrator.ts (~363-373 at head 1900e90) treats "the fetchItems promise resolved and my request id is still latest" as "the new scope's rows are in the store". The store has a second guard the orchestrator does not mirror: captureStore.ts (~151, 167) drops a list response when observedListWriteGeneration !== latestListWriteGeneration. Scenario: switch board A to B; while the replacement fetch is in flight, submit a capture from the nib (dispatchCapture is not gated on loadingList); recordCaptureWrite bumps the write generation and unshifts the new summary onto board A's list; the replacement fetch resolves, the store discards it, but the orchestrator's guards pass and it clears isScopeReplacement, so board A's rows show under board B's label. The follow-up loadInbox() normally corrects it; if that follow-up fails the wrong-label state persists. Fix direction: fetchItems should report whether it applied the response (or expose the generation) so the orchestrator only clears the flag on an applied response.
MEDIUM — header eyebrow counts ignore scope replacement. PaperInboxView.vue (~98, 484-494): useInboxCounts(items) is unconditional, so while isScopeReplacement is true the eyebrow still renders pending/total from the retained old-scope rows next to the new scope's disclosure label. Pre-existing, but it makes "retained rows stay hidden during a replacement" true only of the table.
LOW — no visible in-flight affordance during a same-scope refresh with retained rows (PaperTriageTable.vue ~539, 555): only aria-busy changes; rows stay actionable against possibly stale data.
Coordination: this seam (useInboxOrchestrator.ts generations, captureStore.ts pollers) is also touched by #2455 / #2457 / #2458 / #2464. isScopeReplacement is a third piece of state only loadInboxInternal clears — whoever picks those up should know.
Tracked residuals from the fresh-context review of PR #2484 (#2044, retained Inbox rows after same-scope refresh failures). The HIGH (mount load not treated as a scope replacement) was fixed in that PR; these were classified non-blocking.
MEDIUM —
isScopeReplacementis cleared on a resolution the store discarded.useInboxOrchestrator.ts(~363-373 at head 1900e90) treats "thefetchItemspromise resolved and my request id is still latest" as "the new scope's rows are in the store". The store has a second guard the orchestrator does not mirror:captureStore.ts(~151, 167) drops a list response whenobservedListWriteGeneration !== latestListWriteGeneration. Scenario: switch board A to B; while the replacement fetch is in flight, submit a capture from the nib (dispatchCaptureis not gated onloadingList);recordCaptureWritebumps the write generation and unshifts the new summary onto board A's list; the replacement fetch resolves, the store discards it, but the orchestrator's guards pass and it clearsisScopeReplacement, so board A's rows show under board B's label. The follow-uploadInbox()normally corrects it; if that follow-up fails the wrong-label state persists. Fix direction:fetchItemsshould report whether it applied the response (or expose the generation) so the orchestrator only clears the flag on an applied response.MEDIUM — header eyebrow counts ignore scope replacement.
PaperInboxView.vue(~98, 484-494):useInboxCounts(items)is unconditional, so whileisScopeReplacementis true the eyebrow still renders pending/total from the retained old-scope rows next to the new scope's disclosure label. Pre-existing, but it makes "retained rows stay hidden during a replacement" true only of the table.LOW — no visible in-flight affordance during a same-scope refresh with retained rows (
PaperTriageTable.vue~539, 555): onlyaria-busychanges; rows stay actionable against possibly stale data.Coordination: this seam (
useInboxOrchestrator.tsgenerations,captureStore.tspollers) is also touched by #2455 / #2457 / #2458 / #2464.isScopeReplacementis a third piece of state onlyloadInboxInternalclears — whoever picks those up should know.