Skip to content

feat(release): wire per-package release-please with npm publish and changelogs - #39

Merged
90sRehem merged 11 commits into
mainfrom
sq/squad-npm-release-changelogs
Aug 14, 2026
Merged

90sRehem merged 11 commits into
mainfrom
sq/squad-npm-release-changelogs

Conversation

@90sRehem

@90sRehem 90sRehem commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor

Intent

Revision round 2 of PR #39 (runecraftai/squad): commander review feedback on the npm-publishing/changelog PR, applied on the existing branch sq/squad-npm-release-changelogs (PR stays the same, no new branch/PR). (1) The packages//CHANGELOG.md files must NEVER mention vendor transitions - the initial 0.1.0 entries in fob, pr-review, sq-browser, sq-gh, sq-quota, sq-report, and sq-tasks that carried vendor history were rewritten in product-feature language (what the package does for the user: features, fixes, ergonomics), keeping the real dates, issue links, and commit links and the release-please format; the drill changelog already had no vendor wording; scan all 8 changelogs for any other vendor wording and clean it too. (2) The sq-tasks hero (packages/sq-tasks/assets/readme/hero.svg) was redesigned clean and product-focused: the 'order of battle' label and the diamond target/map-marker over it are removed, the military star-in-ring unit patch is replaced with a completed-task checkbox product mark, the message is a backlog that stays human-editable while agents edit it (byte-exact round-trip, TOON output), no military jargon and no target icons, SVG stays accessible (title/desc, alt text) and consistent with how packages/sq-tasks/README.md embeds it. (3) Re-validate via drill on the same PR; the PR description publish-name decision text was checked and the only adjustment needed was rewording 'fob installs via the vendored go build' to 'fob installs via a source build' - the publish-name decision itself (bare sq- npm names, @runecraft/pr-review scoped, drill/fob not published to npm) is unchanged. Acceptance: no vendor wording in any packages/*/CHANGELOG.md; hero has no order-of-battle or target/diamond marker; PR #39 updated on the same branch with drill re-validation green on the new head; bin/sq-lint.sh and bin/sq-doc-audience-check.sh pass.

What Changed

  • Added a root .github/workflows/release.yml running one release-please stream per package (drill, fob, pr-review, sq-browser, sq-gh, sq-quota, sq-report, sq-tasks): merged release PRs create GitHub releases/tags and publish the JS packages to npm via NPM_TOKEN (gated on releases_created == 'true' and OIDC provenance); Go binaries (drill, fob) get releases/tags only.
  • Added initial 0.1.0 CHANGELOG.md files for all 8 packages written in product-feature language, registered them as public-product in docs/documentation-audiences.json, and re-keyed each package's release-please-config.json / .release-please-manifest.json to package-relative paths with a pinned bootstrap-sha.
  • Updated package CI and guards (ci.yml, drill-required.yml, guard-generated-files.yml plus their exclusion tests and sq-tasks/scripts/guard-generated-files.sh) to exclude the package-relative release-please outputs; switched sq-browser, sq-gh, and sq-quota builds from prepublishOnly to prepack, added the repository field to pr-review's package.json and rewrote its RELEASING.md for the monorepo pipeline; redesigned packages/sq-tasks/assets/readme/hero.svg with a completed-task checkbox mark and "source of truth" wording, removing the order-of-battle label, map-marker/diamond target, and star-in-ring patch while keeping accessible title/desc.

Risk Assessment

✅ Low: All prior error/warning findings (F5 publish gating, F1 bootstrap-sha, F2 re-keying) are verified fixed and durable; remaining items are informational only, and the change is well-bounded release wiring with internally consistent configs, workflows, and tests.

Testing

Exercised the full intent end-to-end on the new head bf2d1e2: scanned all 8 changelogs (0 vendor mentions, format/date/link integrity vs real history), diffed and pixel-verified the redesigned sq-tasks hero (checkbox mark, no order-of-battle/target iconography, accessible title/desc matching README alt), ran both acceptance scripts (sq-lint exit 0, doc-audience ok 179 surfaces), and ran the targeted release-pipeline suites (drill/fob Go, pr-review bun, sq-report node, sq-* vitest incl. release-ci-exclusions, guard-generated-files, and the round-trip/TOON suites backing the hero's claims) — all green after fixing a missing-deps environment gap with bun install; PR #39 was confirmed open on the correct branch with the reworded 'source build' text, though its GitHub head (0b6dea7) still predates the two newest local commits, whose push/re-validation belongs to the outer executor's later phases. Overall result: pass, no product defects found.

  • Evidence: Rendered sq-tasks hero.svg (redesigned: checkbox product mark, no order-of-battle/diamond, accessible title/desc) (local file: /tmp/drill-evidence/01KZZVWSBEN4263T1S780TDNQ4/sq-tasks-hero.png)
Evidence: Vendor wording scan across all 8 packages/*/CHANGELOG.md (0 matches)

Source: Vendor wording scan across all 8 packages/*/CHANGELOG.md (0 matches) (local file: /tmp/drill-evidence/01KZZVWSBEN4263T1S780TDNQ4/changelog-vendor-scan.txt)

grep -rniE "vendor|vendored" packages/*/CHANGELOG.md -> 0 matches (8 files scanned: drill, fob, pr-review, sq-browser, sq-gh, sq-quota, sq-report, sq-tasks)
Evidence: Acceptance scripts
bin/sq-lint.sh -> exit 0 ("no changed lint targets", pinned ShellCheck 0.11.0)
bin/sq-doc-audience-check.sh -> "ok surfaces=179 local_links=248" exit 0
- Outcome: ⚠️ 1 info across 1 run (5m10s)

Pipeline

Updates from git push drill

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 2 infos
  • ⚠️ packages/pr-review/release-please-config.json:3 - First release-please run will regenerate vendor-wording changelog entries, defeating the intent's durable 'CHANGELOG.md files must NEVER mention vendor transitions' requirement. Concrete path: merging this PR pushes conventional commits touching all 8 package dirs to main, triggering .github/workflows/release.yml. No tags exist yet, so needsBootstrap=true; the configured bootstrap-sha b9b62811 (pr-review, line 3) and 9f5dc949 (sq-quota, line 3) are not in this repo's history (repo starts at squashed import 7a63db7), and the other 6 packages set no bootstrap-sha at all. The commit walk never hits the sha, so commitsAfterSha(commits, '') returns the full history and the first release PR changelogs will include 'feat: vendor M6 toolchain packages and rename tasks-axi to sq-tasks (feat: vendor M6 toolchain packages and rename tasks-axi to sq-tasks #2)' (774b6bf, touches all 6 npm packages), 'feat: rebrand vendored tool names to sq-* across packages (feat: rebrand vendored tool names to sq-* across packages #14)' (39bb7bb), and 'chore: reset workspace packages to clean 0.1.0 baseline and unvendor pr-review (chore: reset workspace packages to clean 0.1.0 baseline and unvendor pr-review #16)' (fd4f9b9, touches all 8) - the exact vendor wording the head commit removed by hand. Recommended earliest supported boundary: point each package's bootstrap-sha at a commit that exists in this repo and postdates the vendor-wording commits (e.g. the release-wiring commit 7171571 or branch base 01d7ad2) so generated changelogs truncate before those subjects. Note sq-quota CONTRIBUTING.md explicitly documents keeping the inherited out-of-history bootstrap-sha, so this challenges documented author intent.
  • ⚠️ packages/sq-browser/test/release-ci-exclusions.test.ts:34 - Release-output drift guard is now vacuous: this branch re-keyed the release-please configs from '.' to 'packages/<name>', but sq-browser, sq-gh, sq-quota, and sq-tasks release-ci-exclusions.test.ts still read config.packages?.["."] (line 34), which no longer exists, so they silently pass via the ?? {} fallback while asserting root-relative paths (CHANGELOG.md, package.json, .release-please-manifest.json) that no longer match where the pipeline writes (packages/<name>/...). sq-report's test was only half-updated: the key is now packages/sq-report (line 18) but it still derives unprefixed paths. The updated AGENTS.md files for these packages claim the test 'derives that set from release-please-config.json and fails if a workflow drifts' - that guarantee is broken. (The package-local workflows these tests validate are only executed by GitHub at the repo root, so no runtime impact today; drill/fob were fully re-keyed in both workflows and tests, making the sq-* treatment inconsistent.)
  • ℹ️ .github/workflows/release.yml:37 - cancel-in-progress: true on the release concurrency group can abort a run after release-please has created the GitHub release/tag but before the npm publish step completes (e.g. a second push to main). The next run sees the tag already present, releases_created is false, and the publish step is skipped, leaving a released version never published; recovery is a manual npm publish. Consider cancel-in-progress: false (queue) or a publish-time guard that checks whether the version is already on npm.
  • ℹ️ packages/pr-review/release-please-config.json:7 - package-name is still 'pi-pr-review' (the upstream component name). The npm name is @runecraft/pr-review (package.json) and tags are bare v<version> (include-component-in-tag: false), but the component flows into release PR titles via pull-request-title-pattern (release${component} ${version}) and release metadata, so release PRs will read 'release pi-pr-review 0.1.1'. Cosmetic naming inconsistency with the publish-name decision; consider 'pr-review' or dropping the override.

🔧 Fix: Fix bootstrap-sha and re-key sq-* release exclusion guards
2 issues (1 error, 1 info) still open:

  • 🚨 .github/workflows/release.yml:49 - The publish-side steps are gated with bare if: ${{ steps.release.outputs.releases_created }} (lines 49, 51, 55, 60). googleapis/release-please-action@v4 always sets this output to the string 'true'/'false' (never unset: core.setOutput(&#39;releases_created&#39;, releases.length &gt; 0) in src/index.ts of v4.0.0/v4.1.1), and GitHub coerces any non-empty string - including the string 'false' - to true in an if: conditional (documented falsy set is false, 0, -0, &#34;&#34;, &#39;&#39;, null; empirically confirmed by release-please-action issues #912/#965, fix: evaluate output of release-please correctly supabase/supabase-py#1259, fix(ci): gate release-please publish on releases_created == 'true' TightknitAI/slack-hono#35). So on EVERY push to main the step runs: on the first push (release-please only opens bootstrap release PRs; no release is cut, output is 'false') it executes npm publish for all 6 npm packages, publishing the manifest version 0.1.0 to npm before any release PR if NPM_TOKEN exists (bypassing the release-PR process the workflow comments describe), and every subsequent ordinary push fails the job with 'You cannot publish over the previously published versions' (or E401 when NPM_TOKEN is absent). Since release.yml has no pull_request trigger it will not be exercised by this PR's CI. Fix: use if: ${{ steps.release.outputs.releases_created == &#39;true&#39; }} on all four steps.
  • ℹ️ packages/sq-browser/AGENTS.md:28 - The 'so release PRs create zero runs' claims added/kept in this branch's AGENTS.md files (sq-browser:28, sq-gh:26, sq-quota:63, sq-tasks:89, drill) describe package-local .github/workflows/*.yml, but GitHub Actions only executes workflows under the repo-root .github/workflows - nested ones are inert. The root .github/workflows/ci.yml has no paths-ignore and no bot-author exclusion, so release-please PRs (authored by github-actions[bot]) will trigger the full root suite (lint + all test lanes + go/node builds) on every release PR, and the extensive package-local exclusion machinery has no runtime effect. Cost/accuracy gap only, not a correctness blocker; the drill-required root job does skip bot-authored PRs.

🔧 Fix: Gate release publish steps on releases_created == 'true
2 infos still open:

  • ℹ️ packages/sq-tasks/assets/readme/hero.svg:5 - The redesigned hero's accessibility desc reads 'A backlog.md document shows queued and done tasks with checkboxes, headed source of truth; ...' — 'checkboxes, headed source of truth' is broken copy, most likely a typo for 'the source of truth' (or 'the headed source of truth'). Introduced by 0b6dea7. The intent requires the SVG to stay accessible (title/desc/alt); the desc exists but is grammatically garbled. Trivial follow-up copy fix; not a blocker.
  • ℹ️ .github/workflows/release.yml:68 - On the first drill release, this workflow creates an empty draft GitHub release + tag (drill's config sets draft: true and force-tag-creation: true) and skips the publish step ('No npm package for drill'), but nothing attaches binaries: the signing/build pipeline that drill's AGENTS.md:235 calls 'Mechanics live in packages/drill/.github/workflows/release.yml' is a nested workflow that GitHub Actions never executes, so it cannot upload assets. The draft will stay empty (and force-tag-creation keeps consuming versions on later bumps) until an operator uploads assets manually. The workflow header comment discloses the draft intent, and the inertness pre-dates this branch, so this is a documented gap rather than a regression — flagging for awareness.
⚠️ **Test** - 1 info
  • ℹ️ .github/workflows/release.yml:1 - PR feat(release): wire per-package release-please with npm publish and changelogs #39 on GitHub currently points at head 0b6dea7 (CI all green there); the local target head bf2d1e2 carries two additional commits (09059c3 bootstrap-sha fix, bf2d1e2 releases_created=='true' gating) that are not yet pushed, so PR re-validation on the new head happens in the outer executor's push/CI phases. All local tests of bf2d1e2 pass; PR description already contains the required 'fob installs via a source build' wording and no 'vendored go build' text.
  • grep -rniE &#34;vendor|vendored&#34; packages/*/CHANGELOG.md -> 0 matches across all 8 changelogs; regression proven: 7171571 carried 'vendored fob'/'vendor M6 toolchain'/'unvendor' wording, 0b6dea7 rewrote in product language
  • git diff 01d7ad2..bf2d1e2 -- packages/sq-tasks/assets/readme/hero.svg -> star-in-ring unit patch -> completed-task checkbox, 'order of battle'+diamond map-marker -> 'source of truth'; grep for order of battle/target/diamond/map-marker/unit/insignia/star/battle -> clean
  • rsvg-convert -w 1200 packages/sq-tasks/assets/readme/hero.svg -> 1200x380 PNG with 1608 colors and rendered checkbox mark (evidence artifact)
  • bin/sq-lint.sh -> exit 0 (no changed canonical-set shell targets; the one changed .sh, packages/sq-tasks/scripts/guard-generated-files.sh, is outside the canonical set by design)
  • bin/sq-doc-audience-check.sh -> 'ok surfaces=179 local_links=248' exit 0
  • go test ./... in packages/drill -> ok, incl. new TestReleaseWorkflowBuildStartsOnlyWhenReleaseIsCreated (bf2d1e2 releases_created=='true' gating) and TestReleasePleaseConfigCreatesDrafts/ForcesTagCreation
  • go test . -run Release -v in packages/fob -> 2 PASS (TestPullRequestWorkflowsExcludeReleasePleaseOutputs, TestExpectedReleaseOutputsIncludesConfiguredExtraFiles)
  • bun test tests/release-version.test.ts in packages/pr-review -> 6 pass (package's declared runner is bun, not node); node scripts/verify-release-version.mjs -> 'Verified root release version 0.1.0'
  • node --test test/package-json.test.js test/release-ci-exclusions.test.js in packages/sq-report after bun install (missing node_modules was an env gap, not a code failure) -> 16 pass
  • vitest test/release-ci-exclusions.test.ts -> sq-browser 6/6, sq-gh 4/4, sq-quota 3/3; sq-tasks 4/4 + test/workflows/guard-generated-files.test.ts 6/6
  • vitest test/backends/markdown.test.ts test/format.test.ts in packages/sq-tasks -> 78 pass (byte-exact render(parse(src))===src round-trip and TOON output the hero advertises)
  • gh pr view 39 --repo runecraftai/squad -> PR OPEN on sq/squad-npm-release-changelogs, description contains 'fob installs via a source build' and no 'vendored go build', publish-name decision unchanged, head 0b6dea7 with all checks SUCCESS; mergeable
  • git cat-file -e for all 13 commit SHAs cited in changelogs -> all present in real history
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@90sRehem 90sRehem changed the title feat: add npm publishing and changelog generation for squad packages feat(release): wire per-package release-please with npm publish and changelogs Aug 14, 2026
@90sRehem
90sRehem merged commit 58232bc into main Aug 14, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant