Summary
frontend/taskdeck-web/src/store/agentStore.ts writes profile, run-list and run-detail responses into one shared slot per surface without request-generation or session-lifetime ownership.
This is a source-traced finding on main 307c3b8b50bec1cb0bfaea3e570a942bcb1d4451. Implementation must begin with failing real Pinia regressions.
Reachable races
A → B → A request identity reuse
AgentRunsView clears the run list and starts a new request when agentId changes. If an older request for agent A remains pending while the user visits B and then A again, the old A response can settle after the newer A response and overwrite it. Run detail has the same shape across {agentId, runId} navigation.
Clear/unmount is not an invalidation boundary
clearRuns() and clearRunDetail() clear visible state but do not retire an in-flight request or its finally. A late success can repopulate a route that was deliberately cleared; a late failure can install an error and toast after navigation; the old finally can clear loading owned by a newer request.
Session replacement
The store has no session watcher or reset epoch. A request begun under account A can settle after logout/login, including login as the same user ID, and populate the replacement account’s agent surfaces or emit stale error UI.
Profiles also accept every response, so overlapping profile reads are last-settlement-wins rather than latest-request-wins.
Expected contract
- Give profiles, run-list and run-detail independent request-owner lanes.
- A newer read retires only the previous owner in the same lane.
clearRuns() and clearRunDetail() synchronously invalidate their lane before clearing state.
- Identity/auth/demo replacement advances a store epoch and clears every agent surface, error and loading owner.
- Late stale success/failure/finally cannot patch state, emit a toast or clear a newer owner’s loading flag.
- The original transport promise still resolves or rejects to its caller; the client must not pretend an already-sent server request was cancelled.
- Legitimate independent profile/list/detail reads remain concurrent.
- Preserve demo-mode no-network behavior.
Acceptance
- Deferred Pinia regression for A-old → B → A-new run-list responses with A-old settling last.
- Equivalent run-detail identity-reuse regression.
clearRuns() and clearRunDetail() followed by late success and late failure, including no stale toast/error.
- Reverse-settling profile reads.
- Old
finally cannot clear loading for a newer same-lane request.
- Logout/login as the same user ID while each representative lane is pending.
- Independent lanes remain concurrent and their loading indicators remain truthful.
- Existing agent-store and demo tests remain green.
- Frontend lint, typecheck, build, full Vitest and exact-head hosted CI pass.
Boundaries
This is client-state ownership, not a demonstrated server authorization bypass. It does not add request cancellation, alter the agent API, or redesign the routes.
Audit provenance
Found during the 2026-09-21 async state-ownership pass after #3327/#3328. Searches found no open issue or PR owning agentStore.ts request/session lifetime.
Summary
frontend/taskdeck-web/src/store/agentStore.tswrites profile, run-list and run-detail responses into one shared slot per surface without request-generation or session-lifetime ownership.This is a source-traced finding on
main307c3b8b50bec1cb0bfaea3e570a942bcb1d4451. Implementation must begin with failing real Pinia regressions.Reachable races
A → B → A request identity reuse
AgentRunsViewclears the run list and starts a new request whenagentIdchanges. If an older request for agent A remains pending while the user visits B and then A again, the old A response can settle after the newer A response and overwrite it. Run detail has the same shape across{agentId, runId}navigation.Clear/unmount is not an invalidation boundary
clearRuns()andclearRunDetail()clear visible state but do not retire an in-flight request or itsfinally. A late success can repopulate a route that was deliberately cleared; a late failure can install an error and toast after navigation; the oldfinallycan clear loading owned by a newer request.Session replacement
The store has no session watcher or reset epoch. A request begun under account A can settle after logout/login, including login as the same user ID, and populate the replacement account’s agent surfaces or emit stale error UI.
Profiles also accept every response, so overlapping profile reads are last-settlement-wins rather than latest-request-wins.
Expected contract
clearRuns()andclearRunDetail()synchronously invalidate their lane before clearing state.Acceptance
clearRuns()andclearRunDetail()followed by late success and late failure, including no stale toast/error.finallycannot clear loading for a newer same-lane request.Boundaries
This is client-state ownership, not a demonstrated server authorization bypass. It does not add request cancellation, alter the agent API, or redesign the routes.
Audit provenance
Found during the 2026-09-21 async state-ownership pass after #3327/#3328. Searches found no open issue or PR owning
agentStore.tsrequest/session lifetime.