Skip to content

ci: move the Squad CLI activation pin when the release publishes - #1858

Merged
bradygaster merged 1 commit into
devfrom
squad/1825-release-time-pin-bump
Aug 24, 2026
Merged

ci: move the Squad CLI activation pin when the release publishes#1858
bradygaster merged 1 commit into
devfrom
squad/1825-release-time-pin-bump

Conversation

@bradygaster

Copy link
Copy Markdown
Owner

Completes #1825. PR #1855 shipped the daily backstop that detects a stale
activation pin; this is the half that prevents one.

What was still broken

workflows/shared/squad.md decides which Squad CLI a brand-new repository installs
during activation. Nothing about publishing touched it, so every release silently
made it stale. It once ran 8 days behind and was caught only because someone
happened to cold-start a throwaway repo (PR #1818).

The issue asked for both halves, and said why:

(1) alone reintroduces the failure whenever someone releases manually; (2) alone
leaves a red build with no fix path.

What this adds

A bump-activation-pin job in squad-npm-publish.yml, gated on publish-cli. It
moves the pin to the version that same run made installable and opens a pull request
against dev.

A third copy nobody was guarding

docs/src/content/docs/guide/gh-aw.md states the same default. Neither the drift
guard's npm comparison nor the existing tests ever looked at it, so it could sit
stale indefinitely while every other guard reported green. It is now bumped with the
other two and asserted equal on every pull request.

Why the rewrite is a script, not a run: block

Its patterns contain backticks (the docs table) and pipes (the YAML || fallback),
both hostile to shell quoting — that is the SC2016 problem #1855 had to suppress. As
a file it is also executable by the test suite, which is what makes the guard
non-decorative:

squad-cli-pin.test.ts runs the real bumper against the version already pinned.
That is an identity rewrite, so it touches nothing, but it proves all three patterns
still match. A pattern that quietly stopped matching would turn the release-time bump
into a no-op — the same silent decay this issue is about.

Fails closed

Situation Behaviour
A pin site is missing Named error, non-zero exit
A pin site is duplicated Named error, non-zero exit
Version is a prerelease Refuses to pin
dist-tags.latest disagrees with the published version Refuses to pin
Pin is already correct True no-op, writes nothing

It never reads packages/squad-cli/package.json — that holds the next unreleased
version and is exactly the E404 PR #1818 had to fix by hand. A test asserts this.

Verification

  • test/squad-cli-pin.test.ts: 10 passed (was 6)
  • npx eslint clean; actionlint clean with shellcheck on PATH
  • Bumper exercised directly: all three sites rewritten, idempotent on re-run,
    prerelease and empty input rejected
  • Mutation-verified — each of these turns the suite red:
    • reshaping the activation pin so patterns cannot match (4 tests fail)
    • drifting the docs copy to a different version (2 tests fail)
    • retargeting the pull request at main instead of dev (1 test fails)

Note for reviewers

The pull request this job opens will arrive without CI — GitHub does not fire
pull_request workflows for pull requests opened with GITHUB_TOKEN. That is
confirmed behaviour observed during E2E fixture work today, not a guess. The rewrite
is therefore verified inside the job that produces it, and the generated body says so.

The pin in `workflows/shared/squad.md` decides which Squad CLI a brand-new
repository installs during activation. Nothing about publishing touched it, so
every release silently made it stale -- it once ran 8 days behind and was caught
only because someone happened to cold-start a throwaway repo (PR #1818).

PR #1855 added the daily backstop that *detects* that state. This adds the half
that prevents it: after `publish-cli` succeeds, the pin moves to the version that
same run made installable, and the change arrives as a pull request against `dev`.

Both halves are load-bearing. Detection alone leaves a red build with no fix path;
prevention alone re-breaks the moment someone publishes out-of-band.

Three things worth knowing:

- The version is confirmed against two independent sources before anything is
  rewritten -- the version this run published, and npm's `dist-tags.latest`. The
  bumper never reads `packages/squad-cli/package.json`, which holds the next
  *unreleased* version and is exactly the E404 that PR #1818 fixed by hand.

- There was a third copy of the pin nobody was guarding, in
  `docs/src/content/docs/guide/gh-aw.md`. Neither the drift guard nor the existing
  tests looked at it, so it could sit stale while everything reported green. It is
  now bumped with the other two and asserted equal on every pull request.

- The rewrite is a script rather than an inline `run:` block. Its patterns contain
  backticks and pipes that are hostile to shell quoting -- the SC2016 problem
  PR #1855 had to suppress -- and as a file it can be executed by the test suite.

That last point is what makes this guard non-decorative: `squad-cli-pin.test.ts`
runs the real bumper against the version already pinned. That is an identity
rewrite, so it touches nothing, but it proves all three patterns still match. A
pattern that quietly stops matching would turn the bump into a no-op, which is the
same silent decay this issue was filed about.

Verified by mutation: reshaping the pin, drifting the docs copy, and retargeting
the pull request at `main` each turn the suite red, and the bumper fails closed
with a named error when a site goes missing or is duplicated.

Closes #1825
Copilot AI lite review requested due to automatic review settings August 24, 2026 19:53
@github-actions

Copy link
Copy Markdown
Contributor

🔒 Security Review

🔒 Security review: 1 error(s), 2 info.

Severity Category Finding Location
🔴 error unsafe-git Unsafe git operation: git add -A — this can stage unintended files or force-push shared branches. .github/workflows/squad-npm-publish.yml:488
ℹ️ info workflow-permissions Workflow grants write permission — verify this is the minimum required scope. .github/workflows/squad-npm-publish.yml:412
ℹ️ info workflow-permissions Workflow grants write permission — verify this is the minimum required scope. .github/workflows/squad-npm-publish.yml:413

Automated security review — informational only.

@github-actions

github-actions Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

🛫 PR Readiness Check

ℹ️ This comment updates on each push. Last checked: commit 3e0a611

PR Scope: 🔧 Infrastructure

⚠️ 2 item(s) to address before review

Status Check Details
Single commit 1 commit — clean history
Not in draft Ready for review
Branch up to date Up to date with dev
Copilot review No Copilot review yet — it may still be processing
Changeset present No source files changed — changeset not required
Scope clean No .squad/ or docs/proposals/ files
No merge conflicts No merge conflicts
Copilot threads resolved 3 unresolved Copilot thread(s) — fix and resolve before merging
CI passing All checks passing

Files Changed (3 files, +377 −0)

File +/−
.github/workflows/squad-npm-publish.yml +114 −0
scripts/bump-activation-pin.mjs +176 −0
test/squad-cli-pin.test.ts +87 −0

Total: +377 −0


This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.

@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Architectural Review

⚠️ Architectural review: 1 info.

Severity Category Finding Files
ℹ️ info template-sync Template files changed in .github/workflows/ but not in other template locations. If these templates should stay in sync, consider updating the others too. Changed: .github/workflows/, Unchanged: templates/, .squad-templates/, packages/squad-cli/templates/

Automated architectural review — informational only.

@github-actions

Copy link
Copy Markdown
Contributor

🟡 Impact Analysis — PR #1858

Risk tier: 🟡 MEDIUM

📊 Summary

Metric Count
Files changed 3
Files added 1
Files modified 2
Files deleted 0
Modules touched 3

🎯 Risk Factors

  • 3 files changed (≤5 → LOW)
  • 3 modules touched (2-4 → MEDIUM)

📦 Modules Affected

ci-workflows (1 file)
  • .github/workflows/squad-npm-publish.yml
scripts (1 file)
  • scripts/bump-activation-pin.mjs
tests (1 file)
  • test/squad-cli-pin.test.ts

This report is generated automatically for every PR. See #733 for details.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

There are release-automation correctness/reliability issues (PR body generation can emit malformed Markdown, and the new workflow job should pin Node via setup-node) plus a test that relies on cross-test ordering assumptions.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR completes the “prevention” half of #1825 by wiring a release-time activation-pin bump into the npm publish workflow, ensuring workflows/shared/squad.md (and the docs copy) are updated automatically when a new Squad CLI release is published.

Changes:

  • Add bump-activation-pin job to .github/workflows/squad-npm-publish.yml that opens a PR against dev after a successful CLI publish.
  • Introduce scripts/bump-activation-pin.mjs to rewrite all pin sites and fail closed when patterns drift.
  • Expand test/squad-cli-pin.test.ts to cover docs consistency, publish-workflow wiring, and to exercise the bumper script.
File summaries
File Description
test/squad-cli-pin.test.ts Adds assertions for docs pin consistency, publish-workflow wiring, and executes the bumper script to prove patterns still match.
scripts/bump-activation-pin.mjs New script to rewrite activation pin sites and generate a PR body, failing closed if rewrite targets can’t be located uniquely.
.github/workflows/squad-npm-publish.yml Adds a post-publish job that verifies npm dist-tags.latest, rewrites pins on dev, and opens a PR with the changes.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +100 to +107
const previous = matches[0][0];
const after = before.replace(pattern, (_full, head, tail) => `${head}${target}${tail}`);

if (after !== before) {
applied.push({ file, label, previous: previous.trim() });
dirty.add(file);
}
sources.set(file, after);
Comment on lines +414 to +423
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 #v7
with:
# The pin lives on the default branch, but releases are cut from `main`.
# Bumping a `main` checkout would edit a file `dev` never sees, and the next
# merge would quietly restore the stale value.
ref: dev
fetch-depth: 0

- name: Confirm the version is published and current
Comment on lines +191 to +202
it('can still find every place it has to rewrite', () => {
const pin = effectivePin(readPinFile());

// Runs the real bumper against the version already pinned. That is an identity
// rewrite, so it touches nothing — but it exercises all three patterns for real,
// which is the only way to prove they still match. A pattern that quietly stops
// matching turns the release-time bump into a no-op, and the whole failure mode
// #1825 describes is a guard that decays without saying anything.
const env = { ...process.env, TARGET_VERSION: pin as string };
delete env.GITHUB_OUTPUT;
delete env.PR_BODY_FILE;

@bradygaster
bradygaster merged commit 5a361b3 into dev Aug 24, 2026
18 checks passed
@bradygaster
bradygaster deleted the squad/1825-release-time-pin-bump branch September 9, 2026 19:44
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.

2 participants