Goal: PDEV-610 — Stale-Data Banner Cross-User Signal
Lifecycle: Completed
Linear issues
Section titled “Linear issues”- PDEV-610 — Stale-data banner does not appear for the second user — cross-user staleness
- PDEV-596 (parent)
A user with an items detail panel open does not see the “stale data” banner when a different user edits the same item. The banner only fires for the user who initiated the change, leaving concurrent observers free to act on stale state and hit If-Match conflicts on the next bulk action. This sub-project, part of the wider acceptance-test-failures effort, picks a cross-user staleness mechanism, wires it in, and adds the regression coverage that PDEV-596 §4.1 surfaced.
Tickets
Section titled “Tickets”- Linear — PDEV-610: Stale-data banner does not appear for the second user — cross-user staleness regression. Parent: PDEV-596 §4.1.
- Related (refactor cascade that introduced the banner): PDEV-548, PDEV-549, PDEV-559, PDEV-597.
- Related (adjacent staleness gap, different surface): PDEV-588 — tenant switch shows old item instance on low Wi-Fi.
Repositories
Section titled “Repositories”| Repository | Role | Planned Changes |
|---|---|---|
arda-frontend-app | Primary surface; owns banner, useFreshRead, ItemCardsContext | Add cross-user invalidation trigger (mechanism TBD: BroadcastChannel for same-browser, server push, or active polling) wired into useFreshRead / ItemCardsProvider. Add E2E or integration coverage. |
operations | Backend; may need to publish item-change events if mechanism is server push | Only if the chosen mechanism is server push (e.g., SSE/WebSocket fan-out, ETag-revision endpoint). Otherwise no backend change. |
documentation | Project artifacts | This goal, an investigation note, a short decision log entry for the mechanism choice, and acceptance criteria sign-off. |
Context
Section titled “Context”Investigation (/arda-frontend-app/src/app/items/ItemCardsContext.tsx) shows:
useFreshReadsnapshots therIdset of cards at mount and only flipsisStale=truewhen its own revalidation discoversrIdchanges. A second user’s mutation never triggers this hook in another tab/session.ItemCardsProviderowns an in-memoryMap<entityId, {cards, fetchedAt, inFlightPromise}>mounted at the root layout (post-PDEV-597). The cache TTL is wall-clock per browser; nothing in the codebase pushes invalidation events from one user to another.- No BroadcastChannel, SSE, WebSocket, polling, or server-push signal currently exists. The banner therefore works as designed for the local writer (their own refresh sees new
rIds) but the cross-user case has no transport at all.
This makes the bug less a “regression” and more a previously-invisible gap that the refactor’s banner now exposes. The mechanism choice is the core decision of the sub-project.
In Scope
Section titled “In Scope”- Decide and document the cross-user staleness transport (BroadcastChannel for same-browser/session, polling on items detail panel, or server push). Record the decision in the inline Decision Log section of
design.md. - Implement the chosen transport with minimal surface area; integrate it with
useFreshRead/ItemCardsProviderso the existing banner renders without further plumbing. - Add automated coverage: E2E test for two concurrent sessions if feasible, otherwise a unit/integration test that simulates the cross-user event and asserts the banner appears.
- Update PDEV-596 §4.1 acceptance evidence.
Out of Scope
Section titled “Out of Scope”- Fixing PDEV-588 (tenant switch staleness) — adjacent surface; the mechanism here may inform that fix but is not required to land it.
- Bulk-action
If-Matchconflict UX beyond what the banner provides (separate ticket if needed). - Full real-time collaboration / live cursors / multi-user editing — out of project scope; the goal is notification, not co-editing.
Constraints
Section titled “Constraints”- The transport must not add a hard dependency on a backend push channel if the same-browser case (BroadcastChannel) covers the majority of reported incidents — pick the smallest mechanism that meets the acceptance criteria.
- No change to the existing
If-Match/rIdrevision model on the backend in this sub-project. - Must not regress the local-writer banner behavior already shipped in v6.0.2.
- Frontend changes follow the
react-best-practicesandclean-componentsskills; backend changes (if any) followkotlin-coding.
Success Criteria
Section titled “Success Criteria”- With two browser sessions (or two tabs in the same browser, depending on transport choice) signed in to the same tenant and the same item open, an edit by session A causes session B to see the stale-data banner within an agreed-on latency budget (target: ≤ 5 s for polling, ≤ 1 s for BroadcastChannel / push).
- Automated regression coverage exists for the cross-user case and runs in CI.
- PDEV-610 acceptance criteria 1–3 satisfied; ticket moved to Done and PDEV-596 §4.1 re-verified.
- Decision log records the chosen mechanism with rationale and rejected alternatives.
Reference Documents
Section titled “Reference Documents”- PDEV-596 manual regression plan — source of the §4.1 failure.
/arda-frontend-app/src/app/items/ItemCardsContext.tsx—useFreshRead,ItemCardsProvider, the host for any invalidation hook./arda-frontend-app/src/components/common/StaleDataBanner.tsx— banner component (no change expected).react-best-practices,clean-components,unit-tests-frontendskills.
Copyright: (c) Arda Systems 2025-2026, All rights reserved
Copyright: © Arda Systems 2025-2026, All rights reserved