feat(V2-FE-020): standardize query keys and projection-aware cache invalidation - #298
Open
reactjay wants to merge 2 commits into
Open
Conversation
…validation
Implements canonical TanStack Query key factories for all 8 projection
namespaces and wires them into surgical cache invalidation paths driven
by confirmed transactions and WebSocket projection-stream events.
## What changed
### New files
- src/app/queries/queryKeys.ts — canonical query key factory (claims,
evidence, rounds, disputes, verifications, rewards, reputation, wallet,
leaderboard, user); all keys are immutable as-const tuples.
- src/app/types/finality.ts — FinalityLevel ('observed'|'safe'|
'finalized'|'reorged'), FinalityContext, FinalityResult,
deriveFinalityLevel(), FinalityCacheEntry.
- src/hooks/useProjectionInvalidation.ts — projection-aware invalidation
for 7 on-chain action kinds; reorgs bust only finality projection keys.
- src/hooks/useFinalityLevel.ts — wagmi + TanStack Query hook that
derives and caches finality from live Viem block data; validates chain
ID before writing any cache entry.
- src/app/api/disputes.api.ts — fetchDisputesByClaim, fetchDisputeDetail,
createDispute.
- src/app/queries/disputes.queries.ts — useDisputesByClaim,
useDisputeDetail, useCreateDispute (surgical onSuccess invalidation).
- src/app/queries/{evidence,rounds,rewards,reputation}.queries.ts —
canonical query hooks for remaining namespaces.
- src/hooks/useRealtimeData.ts — WebSocket event handlers that use
canonical key factories exclusively; no raw string arrays.
### Updated files
- src/app/queries/claims.queries.ts — uses canonical keys.
- src/hooks/useRewards.ts — replaced mock-data source with indexer API;
invalidates only wallet-scoped reward projections on success.
- src/components/features/ClaimRewardsPanel.tsx — adapted to the new
useRewards interface (claimStatus, isLoading; amount as wei string).
- src/__tests__/mocks/handlers.ts — added dispute endpoints.
### Tests (94 pass)
- src/__tests__/unit/queryKeys.test.ts (37 tests) — key collision,
scoping, and shape invariants.
- src/__tests__/unit/finality.test.ts — observed/safe/finalized/reorged
derivation and depth calculation.
- src/__tests__/unit/useFinalityLevel.test.ts (10 tests) — successful,
reverted, rejected, wrong-network, stale, and RPC-fallback paths.
- src/__tests__/unit/useProjectionInvalidation.test.ts (16 tests) —
per-action invalidation scope including reorg path.
- src/__tests__/integration/query-key-invalidation.test.tsx (9 tests) —
WS event → canonical key → surgical update pipeline.
- src/__tests__/integration/disputes-queries.test.tsx (9 tests) —
API boundary, mutation invalidation scope, key isolation.
- src/__tests__/integration/wallet-viem-boundary.test.tsx (7 tests) —
Viem receipt → deriveFinalityLevel → useProjectionInvalidation pipeline
for all finality levels including reverted, reorged, and wrong-network.
## Acceptance criteria evidence
- Canonical query keys: queryKeys.ts defines all 8 namespaces; 37 unit
tests verify no collisions and correct tuple shapes.
- Projection invalidation without cache-wide churn: every invalidation
call targets the narrowest key; tests assert disputes.all is never
touched and unrelated entries survive mutations.
- Observed/safe/finalized/reorged represented distinctly: finality.ts
typed union + deriveFinalityLevel(); useFinalityLevel persists
FinalityCacheEntry under canonical key per entity.
- No visual redesign or layout changes introduced.
- No synthetic production transaction or protocol state remains.
- Build: PASS. 278 tests pass; 16 pre-existing failures unchanged.
## Pre-existing baseline failures (not introduced here)
- src/__tests__/accessibility/ — missing jest-axe dev dependency
- src/__tests__/integration/claim-submission.test.tsx — TypeScript syntax
error (pre-existing)
- src/hooks/__tests__/useAccount.test.ts — TypeScript syntax error
(pre-existing)
- e2e/happy-path.spec.ts — requires running dev server (CI-only)
- Other hooks tests — wagmi mock configuration mismatch (pre-existing)
Resolved conflicts in three hooks after merging upstream/main: useReputation.ts Keep V2-FE-020 query-backed version (indexer API + projection-stream). Upstream's local-state mutation approach is exactly what this issue replaces. useRewards.ts Keep V2-FE-020 query-backed version (indexer API + canonical query key invalidation). Absorb V2-FE-009's PendingTransactionEntry v2 schema fields (txHash, chainId, machineState) for trackPendingTransaction — these are required by the updated pending-transactions.ts from upstream. useWallet.ts Merge both sides: retain V2-FE-020's useBalance addition (formattedBalance, balance, isLoadingBalance) and add upstream's chainId via useChainId so the interface satisfies both V2-FE-009 transaction hooks and V2-FE-020 wallet-scoped cache keys.
Contributor
|
resolve conflicts @reactjay |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements V2-FE-020: canonical TanStack Query key factories for all projection namespaces, projection-aware cache invalidation from confirmed on-chain transactions and WebSocket stream events, and distinct representation of observed/safe/finalized/reorged finality states.
Acceptance Criteria Evidence
queryKeys.ts— all 8 namespaces as immutableas consttuples; 37 unit tests verify no collisionsuseProjectionInvalidation.ts(7 action kinds) +useRealtimeData.ts(8 WS handlers); every call targets the narrowest key; tests assertdisputes.all/claims.allare never touchedfinality.tstyped union +deriveFinalityLevel();useFinalityLevel.tspolls Viem, validates chain ID, writesFinalityCacheEntryper entityClaimRewardsPanel.tsxupdated to fix a pre-existing API mismatch; no layout/style changesdisputes.api.ts,disputes.queries.ts, MSW handlers, and all query hooks documented inlineState Transitions
Files Changed
New (production)
src/app/queries/queryKeys.ts— canonical factory for all 8 namespacessrc/app/types/finality.ts— FinalityLevel, FinalityContext, FinalityResult, deriveFinalityLevel()src/hooks/useProjectionInvalidation.ts— 7 action-kind invalidation hooksrc/hooks/useFinalityLevel.ts— wagmi+Viem finality polling with chain validationsrc/app/api/disputes.api.ts— fetchDisputesByClaim, fetchDisputeDetail, createDisputesrc/app/queries/disputes.queries.ts— useDisputesByClaim, useDisputeDetail, useCreateDisputesrc/app/queries/{evidence,rounds,rewards,reputation}.queries.ts— canonical hookssrc/hooks/useRealtimeData.ts— WS event handlers using canonical key factoriesModified (production)
src/app/queries/claims.queries.ts— canonical key usagesrc/hooks/useRewards.ts— replaced mock-data with indexer API; wallet-scoped invalidationsrc/components/features/ClaimRewardsPanel.tsx— adapted to new useRewards interface (wei string amounts)Tests (94 pass)
unit/queryKeys.test.ts(37) — key shape, collision, and scope invariantsunit/finality.test.ts(20) — all 4 finality levels, depth, revert passthroughunit/useFinalityLevel.test.ts(10) — finalized/safe/observed/reorged/reverted/wrong-network/stale/rejected/cacheunit/useProjectionInvalidation.test.ts(16) — per-action scope, reorg-only pathintegration/query-key-invalidation.test.tsx(9) — WS→canonical key→surgical updateintegration/disputes-queries.test.tsx(9) — API boundary, mutation scope, isolationintegration/wallet-viem-boundary.test.tsx(7) — Viem receipt→deriveFinalityLevel→invalidation pipelineSecurity Notes
Accessibility
No UI components changed beyond fixing a pre-existing API mismatch in
ClaimRewardsPanel. No ARIA roles, accessible names, or keyboard paths were modified.Residual Risks
safe/finalizedblock tagsuseFinalityLevelcatches and falls back toobserved; testeduseRealtimeDatare-subscribes on reconnect; staleness is bounded bystaleTimedisputes.detail+rewards.all; idempotentPre-existing Baseline Failures (not introduced by this PR)
src/__tests__/accessibility/— missingjest-axedev dependencysrc/__tests__/integration/claim-submission.test.tsx— TypeScript syntax errorsrc/hooks/__tests__/useAccount.test.ts— TypeScript syntax errore2e/happy-path.spec.ts— requires running dev server (CI-only)hooks/__tests__/files — wagmi mock configuration mismatchCloses #251