Support access keeps the monitor and moves the data path under it
The /support-access monitor now follows the generated-hook architecture used by firms and staff. The table remains the useDataTable owner; the browser generated hook reads from a validated BFF and the server page only performs the initial prefetch.
What changed
The monitor read no longer imports src/lib/actions/support-access.ts. The page prefetches useAdminListActiveGrants through supportAccessGateway, dehydrates the result, and lets the hydrated client table refetch through the generated hook.
src/app/(admin)/support-access/page.tsx uses adminListActiveGrantsQueryOptions, supportAccessGateway.listActive, and <HydrationBoundary>. The deleted server-action list path is no longer part of the monitor.
SupportAccessTable builds the active-grants request from table.getState(). Search and firm/staff filters update shallow URL state; they do not force an RSC navigation. The expiring quick filter stays client-side because the backend exposes no such parameter.
GrantRowActions calls useAdminRevokeGrant and invalidates the active-grants collection after mutateAsync resolves. There is no onMutate and no optimistic row removal.
BFF boundary
The new /api/internal/support_grants/active route validates generated query params, delegates to supportAccessGateway.listActiveWithResponseHeaders, and forwards x-pramaan-* diagnostics headers with the shared internal helpers.
Revoke uses the existing generated-client mapping to /api/internal/firms/[firmId]/grants/[grantId], which validates generated path/body schemas and delegates to firmDetailGateway.revokeGrantWithResponseHeaders. The gateway calls src/lib/gateway.ts and parses upstream JSON with assertContract, so the pramaan-docs ADR-104 trace bridge remains the only observability path.
Story #1485 chrome is consumed on the monitor: SegmentedFilter powers the expiring quick filter and StatusBadge renders the active-grant support-access state. The shared revoke dialog was not modified.
Verification proof
Focused tests cover the Bug-1638 bar: search updates shallow URL state and the generated useAdminListActiveGrants params are rebuilt from table.getState(). The test asserts options.shallow === true.
Revoke coverage asserts useAdminRevokeGrant().mutateAsync receives the firm, grant, and reason, then active-grants invalidation happens only after the mutation call. BFF tests cover generated schema validation, x-pramaan-* forwarding, GatewayError envelopes, and generated browser-client routing.
Local verification for this story is pnpm lint, pnpm exec tsc --noEmit, pnpm test, NEXT_PUBLIC_ENV=local pnpm build, pnpm build-storybook, and git diff --check.