Skip to content

ci: fail when unreleased changesets accumulate#1481

Merged
bradygaster merged 1 commit into
bradygaster:devfrom
omercangumus:omercangumus/1273-changeset-drift-gate
Jul 19, 2026
Merged

ci: fail when unreleased changesets accumulate#1481
bradygaster merged 1 commit into
bradygaster:devfrom
omercangumus:omercangumus/1273-changeset-drift-gate

Conversation

@omercangumus

Copy link
Copy Markdown
Contributor

What

Adds a changeset-drift gate to Squad CI: scripts/check-changeset-drift.mjs counts pending .changeset/ fragments and the age of the oldest one, and trips when count > 25 or age > 30 days. Warn-only on PRs, hard fail on pushes to dev.

Why

Part of #1273 — the CI-gate half only. The issue documented 104 pending fragments with the root CHANGELOG a full minor version behind, and nothing in CI noticing. Consolidating the backlog itself is a maintainer call (asked on the issue: one-off changeset version PR vs inside the release workflow) — this gate doesn't wait on that answer.

Threshold rationale in one sentence: loose enough that normal development between releases never trips it (25 fragments / 30 days is several release cycles of headroom), tight enough that a stalled release flow gets caught within a month instead of a version later.

How

  • scripts/check-changeset-drift.mjs — zero-dep ESM, same shape as the other scripts/*.mjs checks. Fragments = .changeset/*.md minus README.md (config.json is JSON, filtered by extension). Age comes from git log --diff-filter=A on each fragment; untracked/unresolvable files count as age 0 so a PR adding its own changeset can't trip the age check. Threshold logic is a pure exported function.
  • New changeset-drift job in squad-ci.yml: --mode=fail on push (dev), --mode=warn on pull_request — the PR author isn't the one who can fix release cadence, so red PRs would just be noise. vars.SQUAD_CHANGESET_DRIFT_CHECK != 'false' is the off switch, matching the escape-hatch convention of the other gates in this file. Actions pinned to full-length SHAs with trailing version comments (same refs already used elsewhere in the file). fetch-depth: 0 because fragment age needs history.
  • One-paragraph note in CONTRIBUTING.md's existing Release Workflow section.
  • Deliberately NOT added to the shipped workflow templates (.squad-templates/workflows/) — this is release hygiene for this repo's changeset flow, not something consumer repos need.

Heads up: the gate trips today by design — current tree has 64 pending fragments, oldest 36 days. PRs (including this one) only get a warning annotation, but the first dev push after merge will show a red Changeset Drift check until the #1273 consolidation lands or the repo var turns it off. That's the alarm working; flagging it so nobody is surprised.

Testing

  • test/scripts/check-changeset-drift.test.ts (8 tests, same import style as test/scripts/parse-diff.test.ts): threshold boundaries (at-threshold passes, +1 trips), both-reasons case, custom thresholds, zero fragments, and listFragments filtering (README.md and config.json excluded, missing dir → empty).
  • Dry-run against the real tree: warn mode prints the 64/36-day drift and exits 0; --mode=fail exits 1.
  • squad-ci.yml still parses (js-yaml), npm run lint (tsc) passes after build, npx eslint on the new files — 0 errors.
  • CONTRIBUTING.md is CRLF-committed; the added lines keep CRLF per the line-ending rule, so git diff --check flags CR on them — expected for that file, git diff -w vs git diff shows no whitespace-only hunks.

⚠️ Quick Check

  • No changeset — .github/workflows/, scripts/, test/, and CONTRIBUTING.md are not governed source/template paths per the changelog gate's own path regex

PR Readiness Checklist

Branch & Commit

  • Branch created from dev
  • Branch is up to date with dev
  • Verified diff contains only intended changes (4 files, +214)
  • PR is not in draft mode
  • Commit history is clean (single commit)

Build & Test

  • npm run build passes
  • npx vitest run test/scripts/check-changeset-drift.test.ts test/ci/changelog-gate.test.ts — 26 passed
  • npm run lint passes (type check clean)
  • npm run lint:eslint — 0 errors on changed files

Changeset

  • N/A — infrastructure only

Docs

  • CONTRIBUTING.md Release Workflow section updated

Exports

  • N/A

Breaking Changes

None at merge time. The first dev push after merge will fail the new check until the fragment backlog is consolidated — see the heads-up above.

Waivers

None.

The .changeset flow only works if a release consumes the fragments at
some cadence — bradygaster#1273 documented 104 pending fragments with the root
CHANGELOG a full minor behind, and nothing in CI noticing. This adds a
smoke alarm: scripts/check-changeset-drift.mjs counts pending fragments
and the age of the oldest one (via the commit that added it), and trips
when count > 25 or age > 30 days. Warn-only on PRs since the PR author
isn't the one who can fix release cadence; hard fail on dev pushes.
SQUAD_CHANGESET_DRIFT_CHECK repo var is the off switch, matching the
other gates in squad-ci.yml.

Thresholds are deliberately loose — the current tree (64 fragments,
oldest 36 days) already trips both, which is the alarm working, not a
false positive. Consolidating the backlog itself is a maintainer call
tracked on the issue.

Part of bradygaster#1273

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

🟡 Impact Analysis — PR #1481

Risk tier: 🟡 MEDIUM

📊 Summary

Metric Count
Files changed 4
Files added 2
Files modified 2
Files deleted 0
Modules touched 4

🎯 Risk Factors

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

📦 Modules Affected

ci-workflows (1 file)
  • .github/workflows/squad-ci.yml
root (1 file)
  • CONTRIBUTING.md
scripts (1 file)
  • scripts/check-changeset-drift.mjs
tests (1 file)
  • test/scripts/check-changeset-drift.test.ts

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

@github-actions

Copy link
Copy Markdown
Contributor

🛫 PR Readiness Check

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

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 No Copilot review threads
CI passing 8 check(s) still running

Files Changed (4 files, +214 −0)

File +/−
.github/workflows/squad-ci.yml +19 −0
CONTRIBUTING.md +2 −0
scripts/check-changeset-drift.mjs +113 −0
test/scripts/check-changeset-drift.test.ts +80 −0

Total: +214 −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.

@bradygaster
bradygaster merged commit 84a5553 into bradygaster:dev Jul 19, 2026
15 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.

2 participants