# Release Evidence Remediation 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:** Build one immutable release bundle and fail promotion unless every artifact, provider report, schema, and digest proves it describes those exact bytes. **Architecture:** Executable Zod contracts validate artifacts at every writer boundary. One fail-closed tracked-file inventory feeds security and provenance. CI creates the candidate once, scans that candidate, then promotes it without rebuilding. **Tech Stack:** TypeScript 7, Node.js 24, Zod 4, Vite 8, Gitea Actions, Vitest 4. ## Global Constraints - Repository code validates but never fabricates external vulnerability or signed provenance evidence. - Missing evidence, unreadable required roots, tool crashes, signals, timeouts, and digest mismatch fail closed. - V2 release identity is its exact contract package set and recomputed set digest; no scalar version is synthesized. - Promotion consumes the same archived `dist` and `distSha256` produced by `immutable_build`. - All production changes start with a failing fixture or unit test. --- ### Task 1: One V1/V2 runtime coherence verifier **Files:** - Create: `scripts/lib/release-runtime-coherence.ts` - Modify: `scripts/verify-release.ts` - Modify: `scripts/drill-runbook.ts` - Modify: `src/contracts/release-tokens.ts` - Modify: `tests/unit/release-coherence.test.ts` - Modify: `tests/unit/release-artifacts.test.ts` - [ ] Add a shared matrix covering V1 scalar success/mismatch and V2 package add/remove/version/digest tampering. Assert verifier and rollback drill return identical verdicts. - [ ] Run `corepack pnpm exec vitest run tests/unit/release-coherence.test.ts tests/unit/release-artifacts.test.ts` and confirm RED because the drill compares only scalar release tokens. - [ ] Implement async `verifyReleaseRuntimeCoherence({ release, runtime, contractPackages })`; V1 delegates to legacy scalar policy, V2 checks exact sorted package tuples then recomputes `contractSet.setDigest`. - [ ] Remove V2 synthetic `0`/legacy scalar projection from `release-tokens.ts`; call the shared verifier from both scripts. - [ ] Re-run the focused tests and commit with `git commit -m "fix: unify release runtime coherence verification"`. ### Task 2: Validated artifact writers and generated JSON schemas **Files:** - Create: `scripts/lib/validated-json-artifact.ts` - Create: `scripts/generate-artifact-schemas.ts` - Modify: `scripts/contracts/release-artifacts.ts` - Modify: `scripts/generate-build-manifest.ts` - Modify: `scripts/generate-supply-chain.ts` - Modify: `scripts/collect-web-vitals-evidence.ts` - Modify: `scripts/test-performance.ts` - Modify: `scripts/verify-release.ts` - Modify: `scripts/drill-runbook.ts` - Modify: `schemas/artifacts/build-manifest.schema.json` - Modify: `schemas/artifacts/dependency-inventory.schema.json` - Modify: `schemas/artifacts/registry-snapshot.schema.json` - Modify: `schemas/artifacts/supply-chain-verification.schema.json` - Create: `tests/unit/validated-json-artifact.test.ts` - Modify: `tests/unit/release-artifacts.test.ts` - Modify: `tests/unit/json-schema.test.ts` - [ ] Add tests proving invalid values do not touch the destination, a valid write is atomic, and `generate-artifact-schemas.ts --check` reports checked-in drift. - [ ] Run focused tests and confirm RED because writers call `writeFile` directly and schemas are hand-maintained. - [ ] Implement `writeValidatedJsonArtifact({ path, schema, value })`: parse first, write a sibling temporary file, rename atomically, and clean only its explicit temp file on failure. - [ ] Route every listed writer through the helper. Generate draft-2020-12 schemas deterministically with `additionalProperties: false` and stable final newline. - [ ] Add `generate:artifact-schemas` and `check:artifact-schemas` scripts; run generation then check mode. - [ ] Run `corepack pnpm exec vitest run tests/unit/validated-json-artifact.test.ts tests/unit/release-artifacts.test.ts tests/unit/json-schema.test.ts` and commit with `git commit -m "refactor: validate generated evidence artifacts"`. ### Task 3: Manifest outputs and fail-closed repository inventory **Files:** - Create: `scripts/lib/repository-file-inventory.ts` - Create: `scripts/lib/build-manifest-outputs.ts` - Modify: `scripts/generate-supply-chain.ts` - Modify: `scripts/security-scan.ts` - Modify: `scripts/verify-release.ts` - Modify: `config/security/secret-scan-policy.json` - Modify: `tests/unit/supply-chain.test.ts` - Create: `tests/unit/repository-file-inventory.test.ts` - Modify: `tests/unit/release-artifacts.test.ts` - [ ] Add fixtures for missing required root, optional `ENOENT`, unreadable file, untracked omission, path traversal, module-inventory tamper, and hash mismatch. - [ ] Run focused tests and confirm current discovery skips read failures and verification accepts a stale `moduleInventoryHash`. - [ ] Build inventory from `git ls-files -z` plus explicitly generated inputs; normalize and confine every path under repository root. Only configured optional roots may ignore exact `ENOENT`. - [ ] Make provenance and secret scan consume the same inventory. Add `index.html`, Vite configs, all TS configs, `.nvmrc`, package/lock files, scripts, schemas, configs, and `.gitea/workflows/quality-gates.yml` to mandatory policy coverage. - [ ] Implement `verifyBuildManifestOutputs` to confine declared output paths, read module inventory bytes, and compare raw SHA-256 to `moduleInventoryHash`. - [ ] Re-run focused tests and commit with `git commit -m "fix: fail closed on release input discovery"`. ### Task 4: Immutable candidate, provider evidence, and promotion **Files:** - Modify: `package.json` - Modify: `scripts/generate-supply-chain.ts` - Modify: `scripts/verify-supply-chain-artifacts.ts` - Modify: `scripts/verify-supply-chain-promotion.ts` - Modify: `scripts/check-supply-chain-provider-fixtures.ts` - Modify: `tests/unit/supply-chain.test.ts` - Modify: `.gitea/workflows/quality-gates.yml` - [ ] Add fixtures for absent provider evidence, valid matching digest, wrong digest, and post-attestation byte change. Assert only the valid immutable fixture passes promotion. - [ ] Run `corepack pnpm exec vitest run tests/unit/supply-chain.test.ts && corepack pnpm check:supply-chain:provider-fixtures` and confirm RED for promotion wiring. - [ ] Split scripts into `build:release-candidate`, `verify:local-evidence`, `verify:provider-evidence`, and `verify:promotion`; remove any build command from promotion. - [ ] `immutable_build` archives `dist`, build manifest, module inventory, and local evidence together and publishes `distSha256`. Provider jobs download that archive and emit reports bound to the digest. - [ ] Promotion downloads the same archive plus provider reports, exports `VULNERABILITY_REPORT_PATH` and `PROVENANCE_ATTESTATION_PATH`, verifies all schemas/signatures/digests, and uploads/deploys the unchanged bundle. - [ ] Verify missing external evidence remains `FAIL_UNVERIFIED`; do not add a repository-generated passing provider fixture to production flow. - [ ] Re-run fixtures and the workflow contract check, then commit with `git commit -m "fix: promote immutable verified release bundles"`. ### Task 5: Release/evidence verification - [ ] Run `corepack pnpm check:artifact-schemas`. - [ ] Run `corepack pnpm exec vitest run tests/unit/release-artifacts.test.ts tests/unit/release-coherence.test.ts tests/unit/validated-json-artifact.test.ts tests/unit/repository-file-inventory.test.ts tests/unit/supply-chain.test.ts tests/unit/json-schema.test.ts`. - [ ] Run `corepack pnpm check:supply-chain:fixtures` and `corepack pnpm check:supply-chain:provider-fixtures`. - [ ] Run the candidate build and local release verification with deterministic local environment values. - [ ] Confirm promotion fails specifically with `FAIL_UNVERIFIED` when real external evidence paths are absent. - [ ] Run `corepack pnpm check:types`, `corepack pnpm lint`, and `git diff --check`.