Trovella Wiki

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):

  1. The file contains the string authorizedProcedure
  2. The file does NOT use publicProcedure. (with dot -- indicating a procedure chain)
  3. The file does NOT use protectedProcedure.
  4. The file does NOT use tenantProcedure.

The Allowlist

An explicit allowlist permits exceptions. Each entry requires a mandatory justification:

FileJustification
pat.tsPAT management is user-level, not org-scoped -- uses protectedProcedure
index.tsBarrel re-export file, no procedure definitions
ai-logs-helpers.tsPure 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:

  1. Using publicProcedure for a new endpoint -- works, but skips all three layers of tenant isolation
  2. Using tenantProcedure without CASL -- gets RLS context but skips authorization checks
  3. Adding to the allowlist with a weak justification -- "CASL not needed yet" or "will add authorization later"
  4. Creating a router file that doesn't import authorizedProcedure at 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"

On this page