# V8 Coverage Counter Contract Design ## Goal Version the serialized risk-coverage artifact independently from its policy and lock the repository's counter-bearing/counterless classifier to the output of the installed Vitest/V8 producer. ## Artifact contract `config/testing/risk-coverage.json` remains policy schema version 2. `scripts/check-risk-coverage.ts` changes only its serialized output envelope to schema version 3 because the artifact fields were renamed from executable/non-executable terminology to `counterBearingTotal`, `instrumentedCounterBearingTotal`, `counterlessTotal`, and `counterlessModules`. The contract test runs the real CLI against an owned temporary repository. It reuses the current policy, materializes its 19 policy-sensitive source paths as counter-bearing modules, writes an exact consistent coverage summary, and reads the published JSON artifact. It requires output schema version 3, the exact counter-bearing fields, and absence of every legacy executable/non-executable field. ## Producer microfixture Repository fixtures under `tests/fixtures/v8-coverage-counter-semantics/` contain only source and a child test template. The child test file uses a `.fixture.ts` suffix and the main Vitest discovery exclusion is verified behaviorally so it cannot recursively join the repository suite. At runtime, `scripts/check-v8-coverage-counter-semantics.ts` creates one owned directory below the operating-system temporary directory. It copies the fixed fixture into that directory and writes the child Vitest config there. The child process uses that directory as its root and writes its JSON summary below that same directory; it never writes repository coverage or artifact paths. The fixture contains these exact source rows: - `runtime.ts`: a runtime declaration/initializer; at least one standard counter total must be positive. - `import-type-empty.ts`: `import type {}` only. - `import-empty.ts`: `import {}` only. - `import-side-effect.ts`: a bare side-effect import only. - `import-value.ts`: a value import only. - `reexport-named.ts`: a named value re-export only. - `reexport-star.ts`: a star value re-export only. - `type-only.ts`: type declarations only. Every row except `runtime.ts` must contain exact `0/0/0/100` lines, statements, functions, and branches counters. The checker rejects a missing summary, missing or additional row, malformed counter, counterless nonzero drift, or runtime all-zero drift. ## Process and failure handling The child Vitest process is launched without a shell or network. Exit failure is converted to a bounded diagnostic containing truncated stdout/stderr. File or JSON failures identify the missing or invalid summary without exposing unbounded child output. An outer `finally` removes only the exact owned temporary root for success and every failure path. Pure summary validation is exported from a focused library and covered with literal mutation fixtures. Runner tests inject child exit or successful-without-summary behavior and assert cleanup. The real standalone checker executes in `test:coverage` before the repository coverage run, so FE-GATE-005 and sample removal both consume it through the existing package script contract. ## Documentation and evidence The testing strategy is synchronized to the current 19 high-risk modules and 80 thresholds, documents output schema version 3, and retains policy schema version 2. Final evidence includes the focused unit/contract tests, node/test TypeScript, changed-file lint, standalone producer checker, root risk checker, sample removal, and diff validation. ## Self-review - No placeholder or deferred choice remains. - Policy schema 2 and artifact schema 3 are explicitly separate. - All child-owned paths are below one temporary root and cleanup has one owner. - Main discovery, subprocess failure, missing summary, exact rows, zero/nonzero drift, and bounded diagnostics have explicit verification paths.