Files
tech-log-frontend/docs/superpowers/plans/2026-08-02-v8-coverage-counter-contract.md
T

177 lines
8.9 KiB
Markdown

# V8 Coverage Counter Contract Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Publish risk-coverage artifact schema version 3 and continuously verify the installed Vitest/V8 producer's counter-bearing/counterless row semantics in an isolated child run.
**Architecture:** A real CLI contract test owns the serialized artifact assertion. A standalone producer checker copies fixed source templates into one OS-temp root, creates its child config and report there, validates an exact JSON summary, bounds child diagnostics, and removes the owned root in `finally`. `test:coverage` invokes the checker before repository coverage, which also carries it into CI and sample removal.
**Tech Stack:** TypeScript 7, Node.js 24 child processes and filesystem APIs, Vitest 4, V8 coverage.
## Global Constraints
- Policy schema remains version 2; serialized risk-coverage artifact schema becomes version 3.
- Child root, config, and reports directory are all below one owned OS temporary directory.
- Main Vitest must not discover the child `.fixture.ts` file.
- Child exit, summary absence, malformed/missing/additional rows, counterless nonzero drift, and runtime all-zero drift fail closed.
- Child stdout/stderr included in diagnostics is bounded.
- Cleanup uses `finally` and targets only the exact owned temporary root.
- Source edits use `apply_patch`; behavior changes follow RED-GREEN TDD.
---
### Task 1: Version the real serialized artifact
**Files:**
- Modify: `tests/unit/risk-coverage.test.ts`
- Modify: `scripts/check-risk-coverage.ts`
**Interfaces:**
- Consumes: the real `check-risk-coverage.ts` CLI, current policy structure, and an exact temporary coverage summary.
- Produces: serialized artifact schema version 3 with `counterBearingTotal`, `instrumentedCounterBearingTotal`, `counterlessTotal`, and `counterlessModules` only.
- [x] **Step 1: Add the actual CLI serialization contract test.**
Create a temporary repository with the 19 current policy paths, write each as `export const covered = true`, set the cloned policy baseline to 19, write one full counter row per module, run the CLI with `process.execPath`, and assert:
```ts
expect(artifact).toMatchObject({
schemaVersion: 3,
counterBearingTotal: 19,
instrumentedCounterBearingTotal: 19,
counterlessTotal: 0,
counterlessModules: [],
});
expect(artifact).not.toHaveProperty("executableTotal");
expect(artifact).not.toHaveProperty("instrumentedExecutableTotal");
expect(artifact).not.toHaveProperty("nonExecutableTotal");
expect(artifact).not.toHaveProperty("nonExecutableModules");
```
- [x] **Step 2: Run the single test and verify RED.**
Run: `./node_modules/.bin/vitest run tests/unit/risk-coverage.test.ts -t "publishes artifact schema version 3" --reporter=dot`
Expected: FAIL because the actual artifact contains `schemaVersion: 2`.
- [x] **Step 3: Change only the serialized envelope to version 3.**
Change `schemaVersion: 2` to `schemaVersion: 3` in the value passed to `writeRiskCoverageArtifactAtomic`; do not change policy parsing.
- [x] **Step 4: Re-run the single test and verify GREEN.**
Run the Step 2 command and expect one passing test.
### Task 2: Lock actual Vitest/V8 counter semantics
**Files:**
- Create: `tests/fixtures/v8-coverage-counter-semantics/counter-semantics.fixture.ts`
- Create: `tests/fixtures/v8-coverage-counter-semantics/src/runtime.ts`
- Create: `tests/fixtures/v8-coverage-counter-semantics/src/import-type-empty.ts`
- Create: `tests/fixtures/v8-coverage-counter-semantics/src/import-empty.ts`
- Create: `tests/fixtures/v8-coverage-counter-semantics/src/import-side-effect.ts`
- Create: `tests/fixtures/v8-coverage-counter-semantics/src/import-value.ts`
- Create: `tests/fixtures/v8-coverage-counter-semantics/src/reexport-named.ts`
- Create: `tests/fixtures/v8-coverage-counter-semantics/src/reexport-star.ts`
- Create: `tests/fixtures/v8-coverage-counter-semantics/src/type-only.ts`
- Create: `tests/unit/v8-coverage-counter-semantics.test.ts`
- Create: `scripts/lib/v8-coverage-counter-semantics.ts`
- Create: `scripts/check-v8-coverage-counter-semantics.ts`
- Modify: `vitest.config.ts`
**Interfaces:**
- Produces: `assertV8CoverageCounterSemantics(summary, fixtureRoot)` and `checkV8CoverageCounterSemantics(options?)`.
- Consumes: fixed fixture templates, owned temp paths, a shell-free Vitest child result, and `coverage-summary.json`.
- [x] **Step 1: Add fixture templates and failing checker tests.**
The fixture test imports the seven counterless modules and observes the direct/named/star runtime values. The unit tests use literal summaries to require exact rows and mutate them for missing row, extra row, counterless nonzero, and runtime all-zero failures. Runner tests inject child exit and successful-without-summary results and require bounded diagnostics plus removal of the owned root.
- [x] **Step 2: Run the new unit file and verify RED.**
Run: `./node_modules/.bin/vitest run tests/unit/v8-coverage-counter-semantics.test.ts --reporter=dot`
Expected: FAIL because `scripts/lib/v8-coverage-counter-semantics.ts` does not exist.
- [x] **Step 3: Implement exact summary validation and owned child execution.**
The default runner executes:
```ts
execFile(process.execPath, [
path.join(repositoryRoot, "node_modules/vitest/vitest.mjs"),
"run",
"--config",
configPath,
"--coverage",
"--reporter=dot",
"--no-color",
], { cwd: ownedRoot, timeout: 30_000, maxBuffer: 256 * 1024 });
```
The generated config has `root`, `include`, `coverage.reportsDirectory`, and `coverage.include` paths inside the owned root. Always remove the root in `finally`.
- [x] **Step 4: Add a behavioral main-discovery assertion.**
Run main `vitest list` filtered to the fixture directory with `--filesOnly --passWithNoTests`; require empty stdout. Add an explicit fixture-directory exclude in `vitest.config.ts`.
- [x] **Step 5: Run the new unit file and standalone checker for GREEN.**
Run:
```sh
./node_modules/.bin/vitest run tests/unit/v8-coverage-counter-semantics.test.ts --reporter=dot
node scripts/check-v8-coverage-counter-semantics.ts
```
Expected checker output: `V8 coverage counter semantics: PASS (1 counter-bearing, 7 counterless)`.
### Task 3: Wire coverage/CI and refresh documentation
**Files:**
- Modify: `package.json`
- Modify: `docs/testing/frontend-platform-testing-strategy.md`
- Modify: `.superpowers/sdd/2026-08-01-quality-architecture-remediation/task-1-report.md`
- Modify: `.superpowers/sdd/2026-08-01-quality-architecture-remediation/progress.md`
**Interfaces:**
- Consumes: `check:v8-coverage-counter-semantics` and existing FE-GATE-005 `test:coverage` step.
- Produces: package/CI/sample-removal execution and current 19-module/80-threshold documentation.
- [x] **Step 1: Add the package checker and prepend it to `test:coverage`.**
```json
"check:v8-coverage-counter-semantics": "node scripts/check-v8-coverage-counter-semantics.ts",
"test:coverage": "corepack pnpm check:v8-coverage-counter-semantics && vitest run ..."
```
- [x] **Step 2: Synchronize documentation.**
Replace stale `12개 high-risk module` and `52개 scoped threshold` with `19개` and `80개`; document artifact schema 3 and policy schema 2 separately.
- [x] **Step 3: Run full relevant verification.**
```sh
./node_modules/.bin/vitest run tests/unit/risk-coverage.test.ts tests/unit/risk-coverage-files.test.ts tests/unit/v8-coverage-counter-semantics.test.ts tests/unit/bounded-body-reader.test.ts --reporter=dot
./node_modules/.bin/tsc --noEmit -p tsconfig.node.json
./node_modules/.bin/tsc --noEmit -p tsconfig.test.json
./node_modules/.bin/eslint scripts/check-risk-coverage.ts scripts/check-v8-coverage-counter-semantics.ts scripts/lib/v8-coverage-counter-semantics.ts tests/unit/risk-coverage.test.ts tests/unit/v8-coverage-counter-semantics.test.ts vitest.config.ts --max-warnings=0
corepack pnpm check:v8-coverage-counter-semantics
node scripts/check-risk-coverage.ts
corepack pnpm test:sample-removal
git diff --check
```
- [x] **Step 4: Commit the verified closeout.**
```sh
git add package.json vitest.config.ts scripts/check-risk-coverage.ts scripts/check-v8-coverage-counter-semantics.ts scripts/lib/v8-coverage-counter-semantics.ts tests/fixtures/v8-coverage-counter-semantics tests/unit/risk-coverage.test.ts tests/unit/v8-coverage-counter-semantics.test.ts docs/testing/frontend-platform-testing-strategy.md docs/superpowers/plans/2026-08-02-v8-coverage-counter-contract.md
git commit -m "test: lock V8 coverage counter semantics"
```
## Self-review
- Spec coverage: artifact versioning, actual producer rows, discovery isolation, every fail-closed path, bounded diagnostics, cleanup, coverage/CI linkage, sample-removal preservation, and documentation counts are assigned.
- Placeholder scan: no deferred implementation remains.
- Type consistency: parser and runner names match in tests, script, and plan.