Server-backed list side params now mirror URLs without nuqs
Firms scope and support-access before/expiringWithin now live in React state and use shallow window.history.replaceState URL mirroring. TanStack Table and server-side pagination remain unchanged.
What changed
src/components/firms/firm-table.tsx removed its direct useQueryState("scope") call. The route parses initial scope on the server and passes it into the client tree, then scope tab changes reset the table page, clear the status filter, rebuild the generated firms request, and mirror ?scope=archived into the URL.
src/components/support-access/support-access-table.tsx removed direct nuqs state for before and expiringWithin. Cursor buttons and expiring filters now update local state first, mirror only their own query params, and keep generated active-grant request params unchanged.
Initial state comes from the server-parsed URL, not a client URL reader. Active scope omits the query param; archived scope writes scope=archived.
before starts from initialRequest.before. Older/newer buttons write or clear the cursor with replaceState and continue refetching through the generated hook.
expiringWithin starts from the server-parsed filter and stays a client-side view filter. It is not sent to the backend request.
Scope guardrails
This story deliberately does not touch src/hooks/use-data-table.ts, src/lib/parsers.ts, staff, matter types, filing types, generated contracts, OpenAPI, backend code, customer app code, or i18n.
The NuqsAdapter, BrowserNuqsAdapter, NuqsTestingAdapter wrappers, and the nuqs package remain until Story #1676. @tanstack/react-table and useReactTable remain the list engine by the Spike #1670 pinned decision.
Observability: client-side state plumbing only; instrumentation-exempt under pramaan-docs ADR-124.
Verification proof
Firm tests now cover archived-scope deep-link hydration, scope tab change URL mirroring through replaceState, no router navigation, and unchanged generated request params.
Support-access tests now cover initial before/expiringWithin hydration, cursor URL mirroring, expiring URL mirroring, no pushState navigation, and no expiringWithin drift into backend request params.
Required local verification: pnpm lint, pnpm exec tsc --noEmit, pnpm test, NEXT_PUBLIC_ENV=local pnpm build, pnpm build-storybook, and git diff --check.