Files
stack/scratchpads/ri-1-002-publish-gate-negative-controls.md
T
2026-08-18 05:57:06 +00:00

3.1 KiB
Raw Blame History

RI-1-002 — Publish-gate negative controls (SDLC-D-034 second half)

  • Task: RI-1-002 (docs/release-integrity workstream, PRD item RI-N1), issue ref #1275
  • Branch: test/ri-050-publish-gate-negative (base origin/next @ d8e0aec9 = PR #1277, RI-1-001)
  • Budget: worker estimate ~45K tokens; keep scoped to the two test files + scratchpad.

Objective

Checked-in negative-control tests that PROVE the publish gate fails when it must:

  1. Broken mandatory check blocks every publish step (structural DAG proof from .woodpecker/publish.yml).
  2. Bypass shapes fail the checker: missing edge, hidden effect (non-publish name), detached verify, always-pass verify (failure: ignore / success override), conditional verify (when).
  3. Exact-commit identity: no HEAD-moving step between verify and publish effects; legitimate re-checkout requires verify to re-run after it.
  4. verify-release.mjs composition control: a SUBSET stage list fails the composition check.

Plan

  • NEW scripts/publish-gate-structure.test.mjs — self-contained structural checker (assertPublishGateBlocksOnVerify) + positive control on the real pipeline + one negative-control test per bypass shape (S1S6, documented in file header) + positive control for the legitimate re-checkout shape.
  • EXTEND scripts/verify-release.test.mjs — refactor the stage-mirror test body into assertStagesMirrorCi(stages, ci); add negative control dropping each stage one at a time (subset must throw).

Conventions confirmed

  • Root test:checkout = node --test scripts/*.test.mjs → new file auto-joins pnpm test.
  • Test-enumeration guard population is *test*.sh under packages/mosaic/framework/tools/ only → unaffected.
  • Root eslint covers only **/*.{ts,tsx} → .mjs files need Prettier style only (printWidth 100, singleQuote, semi, trailingComma all).
  • Do NOT touch docs/TASKS.md, docs/release-integrity/TASKS.md, docs/scratchpads/.

Progress log

  • Base verified: publish.yml verify step + verify-release.mjs present; HEAD contains origin/next.
  • Wrote scripts/publish-gate-structure.test.mjs
  • Extended scripts/verify-release.test.mjs (mirror fn + subset negative control)
  • Gates: node --test scripts (31 tests pass), prettier clean on touched files, pnpm typecheck PASS, pnpm lint PASS, pnpm format:check PASS
  • Committed ff585b88 + pushed, PR #1305 → next (no conflicts). Stopped before merge per task instruction.

Evidence

  • node --test scripts/verify-release.test.mjs scripts/publish-gate-structure.test.mjs → 31 tests, 0 fail.
  • Mutation sanity: temporarily removing the verify edge from build-gateway in publish.yml → structure test goes red (verified manually during dev, then reverted).
  • Gates run from repo root on this worktree; results in Progress log.

Risks / notes

  • Effect detection (isPublishCommand) is deliberately over-broad (any npm/pnpm/yarn command mentioning publish, any kaniko/docker-push/--destination) — fail-closed: a false positive forces justification, a false negative is the actual hazard.
  • git fetch flagged as HEAD-moving even though fetch alone doesn't move HEAD — fail-closed on the classic fetch && reset pair.