# Test Coverage Snapshot — 2026-05-08

> Audience: vendor implementation team and operator pre-handover reviewers.
> Goal: document the test surface and coverage at the moment of handover so a
> vendor can see what is actually exercised by the test suite, without
> re-running the suite to find out.
> Priority: **High** — reuses the same source of truth as
> [`docs/foundation/sbom-current.json`](sbom-current.json) (governance evidence).

---

## 1. How the snapshot was produced

```bash
npm run test:coverage -- --coverage.reporter=json-summary
```

Vitest 4.1 with the v8 coverage provider. Configuration lives in
[`vitest.config.ts`](../../vitest.config.ts) and limits the coverage scope to
the modules that carry product-critical business logic:

- `lib/entitlement/**`
- `lib/provisioning/**`
- `lib/owner-audit/**`
- `lib/tenant/**`
- `lib/demo/**`

Other modules (App-Router pages, React components, repository client code)
are intentionally excluded from coverage measurement — they are validated by
the typecheck and portability gates instead.

## 2. Test surface

- **Test files:** 13
- **Tests:** 240 (all passing)
- **Test runtime:** ~1.5 seconds total
- **Test entry-points:** [`__tests__/`](../../__tests__/) — Vitest only picks
  up files matching `__tests__/**/*.test.ts`.

Headline subjects covered:

- Entitlement engine (4-layer plan/override/role/kill-switch model)
- Provisioning pipeline (Supabase project creation, schema migration, key
  rotation)
- Owner-audit middleware (`requireOwnerRole`, the audit hooks)
- Tenant context guards (`requireActiveTenant`, status state machine)
- Demo seeder (every module's `*-seed.ts` reaches 100 % coverage so demo
  resets cannot regress unnoticed)

## 3. Coverage totals

| Metric     | Coverage |
|-----------|---------:|
| Statements | 79.17 % |
| Branches   | 64.73 % |
| Functions  | 81.31 % |
| Lines      | 83.67 % |

Branch coverage is lower than line coverage because several defensive
`if (error)` paths are not exercised in tests — the underlying calls return
typed errors that the application code is required to handle but the tests
do not always force.

## 4. Per-cluster line coverage

| Cluster              | Lines      |
|----------------------|-----------:|
| `lib/demo/seeds/**`  | 100.00 %   |
| `lib/demo/seeder.ts` | 95.21 %    |
| `lib/tenant/status`  | 90.00 %    |
| `lib/entitlement/engine.ts` | 87.93 % |
| `lib/provisioning/runner.ts` | 87.50 % |
| `lib/owner-audit/middleware.ts` | 85.71 % |
| `lib/provisioning/steps.ts` | 67.85 % |

## 5. Files reported as 0 % (intentional)

Four files report 0 % coverage in the Vitest v8 report. They are not
test gaps — they are non-runnable in the Node test environment:

- `lib/demo/demo-service.ts` — re-exports for the App Router; never
  evaluated under Node test.
- `lib/entitlement/client-hook.ts` — `'use client'` React hook; cannot
  load in a Node environment.
- `lib/provisioning/dispatcher.ts` — top-level barrel that loads steps
  lazily through `await import()`; the lazy chains are exercised by the
  steps tests but the barrel itself is not.
- `lib/tenant/layout-guard.ts` — Next.js Server Component helper that
  reads `headers()`; only evaluated inside a Next.js request scope.

These files appear in the coverage report because the v8 provider lists
every file in the configured `include` paths, even when no test imports
them. The vendor should treat these as "covered by integration smoke
testing in a running Next.js process" rather than re-write Node tests.

## 6. Where the lowest-line coverage really sits

After excluding the four 0 % files above, the lowest real coverage is
`lib/provisioning/steps.ts` at 67.85 % lines. Uncovered ranges:

- The Supabase Management API HTTP client paths that handle 5xx retries.
  Tested manually against the live API during the BMW pilot, hard to fake
  in a unit test without a contract recorder.
- The fallback paths in `runMigration` for `legacy_v0` schema variants.
  Used only on databases provisioned before the v001 migration shipped.

The vendor can extend this when a contract recording becomes available
on the Azure side.

## 7. How to refresh

Re-run the snapshot any time the test surface meaningfully changes:

```bash
npm run test:coverage -- --coverage.reporter=json-summary
```

The v8 provider produces:

- `coverage/coverage-summary.json` — machine-readable totals (committed
  alongside this document).
- `coverage/coverage-final.json` — full per-file detail (gitignored — too
  large).
- `coverage/index.html` — interactive HTML report (gitignored).

After regeneration, replace [`coverage-summary-2026-05-08.json`](coverage-summary-2026-05-08.json)
and update the date and totals in this document.

## 8. Pointers

- [`vitest.config.ts`](../../vitest.config.ts) — coverage `include` list.
- [`__tests__/`](../../__tests__/) — test files.
- [`TESTING.md`](../../TESTING.md) — how to write new tests, how the
  validation gates relate to each other.
- [`docs/foundation/sbom-current.json`](sbom-current.json) — production
  dependency graph (refreshed on the same day as this snapshot, commit
  `dfff123`).
