Skip to content

Activity history reads lack latest-query and credential ownership #3344

Description

@Chris0Jeky

Summary

frontend/taskdeck-web/src/store/auditStore.ts writes board, entity, and user history into one shared entries surface, but every asynchronous request commits its response, error, toast, loading transition, and finally unconditionally.

This is a source-traced finding on main 307c3b8b50bec1cb0bfaea3e570a942bcb1d4451. useActivityQuery can start a new history request after route or selector changes while the prior request remains in flight, making the race reachable through ordinary Activity navigation.

Confirmed ownership gaps

  1. Cross-query stale overwrite: an old board request can resolve after a newer entity or user request and replace the current result list.
  2. Stale failure UI: an older rejected request can set error and emit a toast after a newer request succeeded.
  3. Loading last-settler race: an older request's finally can clear loading while the current query is still pending.
  4. Credential replacement: logout, login as another user, same-user token rotation, or demo-session replacement does not clear audit entries or invalidate requests that began with the previous credentials. AppShell resets board, capture, and workspace state on logout, but not the audit store.

The original request promise should still settle to its caller. This issue concerns client-state truthfulness and does not claim request cancellation or a server authorization bypass.

Expected contract

  • The shared history surface has exactly one current request owner, regardless of whether the query is board, entity, or user history.
  • Starting a newer query retires the previous owner's permission to write entries, errors, toasts, loading, or final state.
  • Identity, token, authentication, or demo-session replacement synchronously clears audit state and advances a credential epoch.
  • A stale success or failure still settles its original promise but cannot alter the replacement lifetime.
  • Limit clamping, preserved entries on a current failure, demo behavior, API contracts, and route behavior remain unchanged.
  • Consolidate the three duplicated request bodies behind one bounded internal helper if that can be done without changing the public store API.

Acceptance

  • Real Pinia/Vitest deferred regressions for board-old → entity-new reverse settlement and cross-kind latest-query ownership.
  • Older failure after newer success rejects its caller but leaves current entries/error/toasts untouched.
  • Older finally cannot clear the current query's loading state.
  • Same-user token rotation clears the surface synchronously and suppresses late success and late failure UI.
  • Existing audit store and Activity view/composable tests remain green.
  • Frontend lint, typecheck, production build, full Vitest on Ubuntu and Windows, and complete exact-head hosted CI pass.

Audit provenance

Found while continuing the 2026-09-21 asynchronous state-ownership pass after integration, permissions, agent, and notification stores. Searches for an open issue naming auditStore.ts found no existing owner.

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.testingTest coverage, harnesses, regression prevention, and verification pipeline work.

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions