Fitness Tests
Vitest architecture tests that enforce structural invariants -- authorizedProcedure in routers and MCP tool registration.
Architecture fitness tests are Vitest tests that enforce structural invariants which cannot be expressed as ESLint rules or dependency-cruiser patterns. They scan source files at test time and assert that conventions are followed. They run in CI alongside unit tests.
authorizedProcedure Enforcement
File: packages/api/src/__tests__/arch.test.ts
This test scans all router files in packages/api/src/routers/ and asserts that every router uses authorizedProcedure. It detects use of lower-privilege procedures (publicProcedure, protectedProcedure, tenantProcedure) and fails with a specific message explaining why the violation matters and how to resolve it.
What It Checks
For each .ts file in the routers directory (excluding test files):
- The file contains the string
authorizedProcedure - The file does NOT use
publicProcedure.(with dot -- indicating a procedure chain) - The file does NOT use
protectedProcedure. - The file does NOT use
tenantProcedure.
The Allowlist
An explicit allowlist permits exceptions. Each entry requires a mandatory justification:
| File | Justification |
|---|---|
pat.ts | PAT management is user-level, not org-scoped -- uses protectedProcedure |
index.ts | Barrel re-export file, no procedure definitions |
ai-logs-helpers.ts | Pure helper functions, no procedure definitions |
The allowlist is deliberately small. Adding entries is a red flag in architecture review -- the /arch-review skill specifically checks whether the allowlist has been expanded without legitimate justification.
Failure Messages
The test produces different messages depending on which lower-privilege procedure was used:
publicProcedure: "feature routers must use authorizedProcedure. If this endpoint is intentionally public, add it to AUTHORIZED_PROCEDURE_ALLOWLIST with a justification."protectedProcedure: "feature routers must use authorizedProcedure. If this endpoint is intentionally user-scoped (not org-scoped), add it to AUTHORIZED_PROCEDURE_ALLOWLIST with a justification."tenantProcedure: "feature routers must use authorizedProcedure (which extends tenantProcedure with CASL authorization). If this endpoint intentionally skips CASL, add it to AUTHORIZED_PROCEDURE_ALLOWLIST with a justification."
Why Not a Custom ESLint Rule
A custom ESLint rule would require maintaining an ESLint plugin for a single assertion. The Vitest approach is simpler, more readable, and runs in CI alongside other tests. It scans the file system directly rather than operating within ESLint's per-file visitor pattern.
MCP Tool Registration
File: packages/mcp/src/__tests__/arch.test.ts
A parallel fitness test verifies that all MCP tool files in packages/mcp/src/tools/ are imported and registered in server.ts. This prevents tools from being created but not wired into the server.
Similar to the router test, it has an allowlist (TOOLS_DIR_ALLOWLIST) for helper files that are not tool registrations.
What AI Agents Get Wrong
AI agents writing routers take the shortest path to working functionality. Common patterns the fitness test catches:
- Using
publicProcedurefor a new endpoint -- works, but skips all three layers of tenant isolation - Using
tenantProcedurewithout CASL -- gets RLS context but skips authorization checks - Adding to the allowlist with a weak justification -- "CASL not needed yet" or "will add authorization later"
- Creating a router file that doesn't import
authorizedProcedureat all -- the test checks for the string's presence
Running the Tests
# Run all tests (includes fitness tests)
pnpm test
# Run only architecture tests
pnpm --filter @repo/api test -- --grep "arch"
Related Pages
- Identity & Access -- Tenant Isolation Enforcement -- how
authorizedProcedurefits into the broader tenant isolation system - Identity & Access -- Review Rules -- arch review checklist rules for authorization
- Review and Audits -- the
/arch-reviewskill checks allowlist integrity as part of Section 2.1
Complexity and Naming
ESLint complexity limits, hand-picked sonarjs rules, and naming convention enforcement -- the editor-time layer of architecture enforcement.
Hotspot Analysis
Git churn x ESLint complexity cross-reference script that identifies the most dangerous files -- high change frequency AND high complexity.