Skip to content

[Frontend][Inbox] Session-epoch follow-ups: list snapshot path, dropped-read reporting, peekDetail wording, spec mock hygiene #2640

Description

@Chris0Jeky

Follow-up to PR #2631 (#2571), from the read-only verification pass on its round-2 fixes. None blocks that merge; all are post-logout-only edges of the new session epoch, tracked here for one small follow-up PR.

1. MEDIUM: the map clear inverts the summary-side guard the same way it inverted the detail guard, and the epoch does not cover the list path. applyBackgroundListSnapshot (captureStore.ts ~184-193) keeps a locally newer row only when latestSummaryGenerationById.get(id) ?? 0 exceeds the snapshot's observed generation; after resetForLogout() clears that map the read is 0, so an older in-flight background list snapshot wins. Scenario: a batch triage poll is active; a detail read moves an item to a terminal status via upsertSummary (generation N above the in-flight snapshot's observed generation); the user logs out; between the shell watcher's resetForLogout() and the Inbox unmount's cancelBatchTriagePolling(), the pre-logout list response lands with isCurrent() still true and items regresses the row. The window is sub-millisecond, the route is already leaving, and the next Inbox mount replaces items through the scope-replacement seam, so it is not user-visible today; but the pre-existing spec at captureStore.spec.ts ~2763-2796 asserts the regressed behaviour as intended ("nothing stale-high is left to pin the row"), so the two halves of one guard now carry opposite post-logout contracts. Fix: the list snapshot path captures the session epoch like the detail path and drops a snapshot issued before the reset; retarget that spec.

2. LOW: onRefreshed fires for reads the epoch dropped (captureStore.ts ~651), so refreshedDetailIds in the batch poll can claim an id was reconciled while detailById still holds pre-batch state; post-logout only.

3. LOW: fetchDetail's drop is unreported to callers (three drop paths, no boolean, unlike fetchItems); selectItemById returns true with an empty detail and the Legacy panel shows "Unable to load capture detail." for a read that succeeded; the new path is post-logout only, the other two are pre-existing.

4. LOW: the docstring says every detail read captures the epoch, but peekDetail writes detailById through cacheDetail with no epoch and no generation compare (its only guard is the hash re-check); cacheSummary: false keeps it out of items. Qualify the wording or add the capture.

5. LOW: captureStore.spec.ts ~2560 installs a persistent mockImplementation returning never-resolving promises; the suite's only reset is vi.clearAllMocks(), so a test added below it that triggers an unconfigured detail read hangs instead of receiving undefined. Replace with per-test mockReturnValueOnce or restore the implementation in that test's teardown.

Refs #2571, PR #2631, PR #2567.

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

    Priority VMeta-tracking, archival consistency, historical context.bugSomething isn't workingfrontendPrimary implementation impact in Vue/TypeScript UI and client runtime.tech-debtDebt cleanup or deferred engineering quality work with limited product-surface change.

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions