Skip to content

Commit e9e84af

Browse files
committed
docs(state): tighten harness rules for accuracy (queryFn forwards, partialize whitelist, mutation-flag caveat)
1 parent daea86d commit e9e84af

3 files changed

Lines changed: 3 additions & 3 deletions

File tree

.claude/rules/sim-hooks.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,4 @@ if (prevOpenRef.current !== open) {
6363

6464
Model mutually-exclusive flags as ONE `status` enum, not several contradictory booleans. `isLoading`/`isVerified`/`isInvalidOtp` describing one machine collapse to `status: 'idle' | 'verifying' | 'verified' | 'error'` (+ `errorMessage`); derive any boolean a consumer still needs (`status === 'error'`).
6565

66-
Derive busy/success from the mutation object — never duplicate `mutation.isPending`/`mutation.isSuccess` into local `useState`. Read them directly (`mutation.isSuccess`) and reset with `mutation.reset()`.
66+
Derive busy/success from the mutation object — never duplicate `mutation.isPending`/`mutation.isSuccess` into local `useState`. Read them directly (`mutation.isSuccess`) and reset with `mutation.reset()`. A distinct phase the mutation doesn't cover — e.g. a pre-submit captcha/Turnstile gate that runs before `mutate()` — is not a duplicate; keep that flag.

.claude/rules/sim-queries.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const entityKeys = {
2525

2626
Never use inline query keys — always use the factory.
2727

28-
**Every identifier the `queryFn` uses MUST appear in the `queryKey`.** If the fetch is scoped by `workspaceId`, `cursor`, `limit`, an org id, etc., those values must be part of the key — otherwise distinct fetch args share one cache entry (a cross-tenant / per-param cache collision). The lone exception is a globally-unique id used as the key while a second fetch arg is only an authz scope that cannot collide; annotate those with `// rq-lint-allow: <reason>`. Enforced by the `key-fetch-arg-drift` check in `scripts/check-react-query-patterns.ts`.
28+
**Every identifier the `queryFn` forwards into the fetch MUST appear in the `queryKey`.** (Query-machinery identifiers — `signal`, `pageParam` — are exempt; they aren't fetch-scoping args.) If the fetch is scoped by `workspaceId`, `cursor`, `limit`, an org id, etc., those values must be part of the key — otherwise distinct fetch args share one cache entry (a cross-tenant / per-param cache collision). The lone exception is a globally-unique id used as the key while a second fetch arg is only an authz scope that cannot collide; annotate those with `// rq-lint-allow: <reason>`. Enforced by the `key-fetch-arg-drift` check in `scripts/check-react-query-patterns.ts`.
2929

3030
## File Structure
3131

.claude/rules/sim-stores.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export const useFeatureStore = create<FeatureState>()(
5757

5858
1. Use `devtools` middleware (named stores)
5959
2. Use `persist` only when data should survive reload
60-
3. `persist` MUST use `partialize` with an explicit whitelist of the durable fields. NEVER persist transient flags (`isResizing`, drag/hover state) or `_hasHydrated`, and never spread the whole state (`{ ...state }`) — it leaks actions and transient state into storage
60+
3. `persist` MUST use `partialize` with an explicit whitelist of the durable fields. Exclude transient flags (`isResizing`, drag/hover state) and `_hasHydrated` from the whitelist, and never spread the whole state (`{ ...state }`) — it leaks actions and transient state into storage
6161
4. `_hasHydrated` pattern for persisted stores needing hydration tracking
6262
5. Immutable updates only
6363
6. `set((state) => ...)` when depending on previous state

0 commit comments

Comments
 (0)