Finding
.github/workflows/publish.yml carries five inline shell gates that stand between a v* tag and npm publish --provenance:
verify-tag → tag must equal package.json version
verify-tag → tag commit must be reachable from origin/main
verify-tag → CHANGELOG.md must have a nonempty ## <ver> section (awk extraction)
release → the same awk extraction feeds release-notes.md (test -s)
release → gh release create --verify-tag ..., skipped when the release already exists
None of them is exercised by .github/tests/*.test.cjs, which CI runs on every PR ("Workflow regression tests" step in ci.yml). auto-release.yml (auto-release.test.cjs) and the ci.yml changelog-guard (#173) already have this kind of suite; publish is the one release-path workflow that can only be observed by cutting a real tag. A regression in the awk heading match (e.g. ## 0.12.01 colliding with ## 0.12.0), the --is-ancestor negation, or the idempotency check would only surface on the next release.
Verified at a3e94c6: node --test .github/tests/*.test.cjs → 2 files, publish.yml not referenced.
Recommendation
Add .github/tests/publish.test.cjs mirroring the existing suites: extract the five run: | blocks from publish.yml and run each under bash against throwaway fixtures (temp package.json/CHANGELOG.md, a bare origin + clone for the ancestry gate, a stubbed gh recording its argv). No workflow edit is needed — the existing node --test .github/tests/*.test.cjs glob picks the file up.
Priority
- Impact: medium (release-path gates; a silent regression ships or blocks a release)
- Effort: low
Filed by quality agent (ACMM L4/L6 — full mode)
🐝 Hive Agent: quality | Instance: hosted-available-oke-11-placeholder-r05x | SHA: a3e94c6
— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88
Finding
.github/workflows/publish.ymlcarries five inline shell gates that stand between av*tag andnpm publish --provenance:verify-tag→ tag must equalpackage.jsonversionverify-tag→ tag commit must be reachable fromorigin/mainverify-tag→CHANGELOG.mdmust have a nonempty## <ver>section (awk extraction)release→ the same awk extraction feedsrelease-notes.md(test -s)release→gh release create --verify-tag ..., skipped when the release already existsNone of them is exercised by
.github/tests/*.test.cjs, which CI runs on every PR ("Workflow regression tests" step inci.yml).auto-release.yml(auto-release.test.cjs) and theci.ymlchangelog-guard (#173) already have this kind of suite; publish is the one release-path workflow that can only be observed by cutting a real tag. A regression in the awk heading match (e.g.## 0.12.01colliding with## 0.12.0), the--is-ancestornegation, or the idempotency check would only surface on the next release.Verified at
a3e94c6:node --test .github/tests/*.test.cjs→ 2 files, publish.yml not referenced.Recommendation
Add
.github/tests/publish.test.cjsmirroring the existing suites: extract the fiverun: |blocks frompublish.ymland run each under bash against throwaway fixtures (temppackage.json/CHANGELOG.md, a bareorigin+ clone for the ancestry gate, a stubbedghrecording its argv). No workflow edit is needed — the existingnode --test .github/tests/*.test.cjsglob picks the file up.publish.test.cjscovering all five scripts plus jobneeds:wiringPriority
Filed by quality agent (ACMM L4/L6 — full mode)
🐝 Hive Agent:
quality| Instance:hosted-available-oke-11-placeholder-r05x| SHA:a3e94c6— hive: agent=quality backend=copilot model=claude-fable-5.1 copilot=1.0.88