Story-1697 pramaan-admin type-layer convergence closer

The converged admin type layer now has a regression guard

This closer verifies the end state from Stories 1693-1696 and adds a CI-enforced static check so backend wire contracts stay imported from @/gen/types, view-models stay feature-owned, and src/types remains limited to cross-cutting table UI types.

Converged state evidence

grep -rn 'from "@/types"' src returned zero rows. The command exits 1 for no matches, which is the expected clean result.

ls src/types prints only data-table.ts.

rg 'export\s+(interface|type)\s+(ActivityFeed(Item|Response)|FirmListRequest|SeatAdjustRequest|PlanChangeRequest|SubscriptionActionResponse|ReassignCSM(Request|Response))\b' src/types returned zero rows.

The generated replacements are present under src/gen/types: ActivityFeedItem, ActivityFeedResponse, AdminListFirms for the old firm-list request shape, SeatAdjustRequest, PlanChangeRequest, SubscriptionActionResponse, ReassignCSMRequest, and ReassignCSMResponse.

Guardrail behavior

scripts/frontend-drift-checks.mjs now has a hard-error type-convergence pass in addition to its existing warning-only drift checks. It parses TypeScript source and fails when:

The CI wiring stays in the existing path: pnpm run check:frontend-drift is still invoked by .github/workflows/ci.yml. The step label was updated from "warnings only" because convergence violations now exit non-zero.

Regression proof

A temporary negative control added this import to src/app/(admin)/firms/firm-list-request.ts:

import type { FirmListResponse } from "@/types";

pnpm run check:frontend-drift failed with exit code 1 and the actionable message:

::error file=src/app/(admin)/firms/firm-list-request.ts,line=12,col=39::Forbidden @/types import. Story-1697 type-layer convergence: import API contracts directly from @/gen/types/*, keep view-models feature-local, and reserve @/types for data-table only.

The temporary import was removed before committing. The clean tree then passed the same guardrail with Type-layer convergence guardrail passed.

Verification proof

  • pnpm lint passed with zero errors and the existing three React Compiler/TanStack warnings.
  • pnpm exec tsc --noEmit passed.
  • pnpm test passed: 91 files, 579 tests.
  • NEXT_PUBLIC_ENV=local pnpm build passed.
  • pnpm build-storybook passed; Storybook emitted its existing package/chunk-size warnings and completed successfully.
  • pnpm run check:frontend-drift passed clean for the type-convergence guardrail on the restored tree.
  • git diff --check passed after the walkthrough was added.

Scope boundaries

No type moves, deletions, codegen, generated contract edits, OpenAPI snapshot edits, pramaan-functions changes, pramaan-app changes, i18n work, or src/types/data-table.ts content changes were made.

pramaan-docs ADR-124: instrumentation-exempt. The new executable code is a local/CI tooling checker only. It does not add a product route, handler, workflow boundary, external call, background job, or user-visible state change.