* fix(queries): close React Query key/fetch-arg drift cache collisions
Several query hooks fetched with an identifier that was absent from their
queryKey, so distinct fetch args shared one cache entry. Thread the missing
args into the key factories and update all callsites/invalidations.
- organization: useOrganization always fetched the ACTIVE org via
getFullOrganization() while caching under detail(orgId). Pass orgId through
to the better-auth call (query.organizationId); active-org behavior unchanged.
- logs: logKeys.detail now keys on (workspaceId, logId) to prevent cross-
workspace collision; updated useLogDetail, useLogByExecutionId, prefetchLogDetail,
useCancelExecution optimistic path, and external callsites.
- inbox: inboxKeys.taskList now includes cursor/limit (pagination args were sent
but omitted from the key); keepPreviousData pagination UX preserved.
- a2a: narrow create/update byWorkflows() invalidation to byWorkflow(ws, wf)
since their responses reliably carry both ids; delete/publish stay broad.
Not bugs (verified, left unchanged):
- kb/connectors update/delete invalidate knowledgeKeys.detail(kbId), which is a
prefix of connectorKeys.all(kbId) — connector list/detail are invalidated
transitively by React Query prefix matching.
Harness: add a key-fetch-arg-drift check to check-react-query-patterns.ts that
flags a camelCase identifier the queryFn forwards into the fetch but is absent
from the queryKey (excludes the requestJson contract arg, PascalCase/SCREAMING
constants, and signal/pageParam machinery). Document the rule in sim-queries.md.
tables.useTable annotated rq-lint-allow (tableId globally unique; workspaceId is
only an authz scope).
* fix(stores): whitelist durable fields in persist partialize
chat/terminal/panel persist configs leaked actions and transient state
into localStorage. Replace the chat full-state spread with an explicit
durable whitelist, and add partialize to terminal and panel (which had
none) so isResizing and _hasHydrated are no longer persisted. Panel keeps
activeTab + panelWidth because the layout.tsx blocking script reads them
from panel-state to set data-panel-active-tab before hydration (SSR
tab-flash prevention).
Harden sim-stores doctrine: persist MUST use an explicit partialize
whitelist; never persist transient flags or _hasHydrated.
* fix(state): model component useState as single source of truth
- edit-knowledge-base-modal: reset fields on closed→open via prevOpenRef
render idiom instead of mirroring props into state through useEffect
(a prop change while open no longer clobbers in-progress edits)
- use-verification: collapse contradictory isLoading/isVerified/isInvalidOtp
booleans into a single status enum + errorMessage; consumer derives flags
- contact-form / demo-request-modal: derive busy/success from the mutation
object; delete duplicated submitSuccess local state
- sim-hooks.md: add state-shape rule (no props-into-state, status enum,
derive mutation state)
* fix(verify): clear lingering message on complete OTP (restore parity)
* docs(state): convert inline reset comment to TSDoc
* docs(state): tighten harness rules for accuracy (queryFn forwards, partialize whitelist, mutation-flag caveat)
* fix(verify): block auto-verify while a resend is in flight (restore parity)
* fix(logs): key cancel optimistic detail by route workspaceId (not the log row)