46 lines
3.1 KiB
Markdown
46 lines
3.1 KiB
Markdown
# 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 (S1–S6, 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
|
||
|
||
- [x] Base verified: publish.yml `verify` step + verify-release.mjs present; HEAD contains origin/next.
|
||
- [x] Wrote scripts/publish-gate-structure.test.mjs
|
||
- [x] Extended scripts/verify-release.test.mjs (mirror fn + subset negative control)
|
||
- [x] Gates: node --test scripts (31 tests pass), prettier clean on touched files, pnpm typecheck PASS, pnpm lint PASS, pnpm format:check PASS
|
||
- [x] Committed + pushed, PR opened to next. Stop before merge (per task).
|
||
|
||
## 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.
|