Repository navigation
Description
Summary
The Version Packages PR is regenerated on a schedule and on demand (#11233), and it cannot be refreshed while it sits in the merge queue. When it lands, the merge queue builds it on top of the current main. So the version commit's tree carries every commit that landed after the PR's last refresh. The PR's own diff deletes, and turns into CHANGELOG entries, only the changesets that existed at that refresh.
The code of the later commits is therefore published under the new version, but their changesets stay in .changeset/. No CHANGELOG entry for that version names them. They show up one release later, under the wrong version.
#20625 (#20613) made the publish ship the version commit and nothing after it. This is the window before the version commit, which #20625 does not cover.
Measured twice
| release | version commit | commits in its tree whose changesets it did not consume | where they surfaced |
|---|---|---|---|
| 17.5.0 | 8c87d26a (#17076) |
seven commits, eight changesets: f11b5f2 #20568, e73ee2d #20567 (two changesets), c876a74 #20504, 7a1faf1 #20579, c9d234c #20577, 24d521e #20572, 2123fcc #20576 |
listed again in 17.6.0's CHANGELOG. Two are breaking (e73ee2d, c876a74). The 17.5.0 notes carry a dated correction for them. |
| 17.6.0 | 617f25f8 (#20639) |
748b240 #21270 (ScheduledWorkPolicy.hostDisabledReason, a minor for three packages) |
.changeset/21110-scheduled-work-host-reason.md is still pending on main. No 17.6.0 CHANGELOG.md in the published tarballs mentions it (also observed in objectstack-ai/hotcrm#1982). |
How to check either one:
git merge-base --is-ancestor <commit> <version commit> # → true
git show --name-status <version commit> | grep '^D.*\.changeset/<file>' # → no line
Why it matters
The generated CHANGELOG is the record an upgrading agent or operator reads, and the release notes are compiled from it. A breaking change that ships without its entry is invisible exactly where people look for it. For 17.5.0 that was the RealtimeEventType narrowing and the forced-Turso-replica refusal.
Directions (not decided here)
- A merge-group guard on the Version Packages PR. Refuse the merge when the merge-group tree still contains a non-README
.changeset/*.mdthat the PR does not delete, so the PR must be refreshed first. The guard needs a re-run path that does not deadlock with "cannot refresh while queued". - Regenerate inside the merge group. Run
changeset versionon the merge-group tree, so the version commit consumes everything in it. - At minimum, have the release-integrity audit report unconsumed changesets whose commits are ancestors of the published version commit, so the gap is seen at publish time rather than found later.
Activity
objectstack-fleet commentedon Oct 2, 2026
Triage: first grade —
priority:p1·domain:spec·area:devpath·pm:queue. Ruling: the audit reports the unconsumed changesets now; a merge-group guard waits for the maintainer. The filer'sbug·toolingstandTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-02T07:53Z. ⛔ Not a claim, ⛔ not a dispatch.Why p1. It is the release-priority rule. Two releases in a row published code, including breaking changes, with no CHANGELOG entry for its version, and the release notes are compiled from that record.
Routing.
.github/workflows/release.ymland the release scripts aredomain:spec, under the anchoring exception.Ruling: the third direction, and only that, in this card (triage's; overturnable by the maintainer).
.changeset/*.mdwhose introducing commit is an ancestor of the version commit and which the version commit did not consume. It names each changeset and its commit, so the gap is seen when the release is cut, not one release later.748b240(feat(types,automation): a host's per-kernel scheduled-work OFF reports its own reason #21270,.changeset/21110-scheduled-work-host-reason.md), in the shape 17.5.0's notes carry. ⛔ Release acts (publishing, tags, Releases) stay the maintainer's.Pins: the audit, run against the 17.5.0 and 17.6.0 version commits, names exactly the measured sets (8, and 1). A version commit with nothing unconsumed reports none (the control).
Generated by Claude Code
objectstack-fleet commentedon Oct 2, 2026
Claim: PM loop round 1
Session:
session_01UtnxvdiN376GF3sgXwAw4dAccount:
os-sales(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-21361-unconsumed-changeset-auditWorktree:
objectstack-issue-21361Domain:
domain:specSeat:
domain:spec#1(seat post #6017)File surface: the
release-integrityjob's audit in.github/workflows/release.yml(theid: auditstep, about:835onorigin/main5fd4855a9a), and one release script holding the logic with its--self-testbattery. That script is either an existing reader such asscripts/release-verify-npm.mjsor a new read-only script beside it, wired into an existing step. Per triage5947729032's ruling (the third direction only): at publish time, report every non-README.changeset/*.mdwhose introducing commit is an ancestor of the version commit and which the version commit did not consume, naming each changeset and its commit. ⛔ No merge-group guard, no regeneration inside the merge group, and no new gate. ⛔ Nocontent/docs/releases/**orCHANGELOG.mdedit: the known 17.6.0 instance (748b240, #21270) is carried by the maintainer's PR #21362, which already writes that dated correction into the 17.6.0 notes. ⛔ Notscripts/release-github-releases.mjs(PR #21358). No changeset (skip-changeset). Stop on breach; explain in the report.Container & model:
M,mode:subagent,model: opus(default judgment tier; release tooling, so the seat checks the diff at ACCEPT and no isolated contract review is owed)Clause-②: no
Thread-read: 5947729032
Serial constraints cleared: at 2026-10-02T08:00Z, no open PR touches
.github/workflows/release.yml. PR #21358 (#21313, this seat, queued) holds onlyscripts/release-github-releases.mjs. #21313's claim namesrelease.ymlonly for the guard it did not build, which is now #21359 (priority:p3, not in flight). PR #21362 (the maintainer's) holdscontent/docs/releases/v17/17-6.mdxandindex.mdx, which this claim does not touch. ⛔ Release acts stay the maintainer's (AGENTS.md Prime Directive 15). This claim publishes, tags and dispatches nothing.objectstack-fleet commentedon Oct 2, 2026
os-dev-report
{
"issue": 21361,
"status": "done",
"branch": "claude/issue-21361-unconsumed-changeset-audit",
"pr": "#21373",
"session": "session_01UtnxvdiN376GF3sgXwAw4d (subagent, the parent id; the newest and only Claim: on #21361, comment 5947821007, names this branch)",
"premise_still_valid": true,
"summary": "Triage's third direction only. scripts/release-pending-publish.mjs gains an
unconsumedmode. For the version commitselectalready names, it lists every pending top-level .changeset/.md in that commit's tree, using @changesets/read 1.0.1's own filter, so README any case, AGENTS/CLAUDE/GEMINI.md and dotfiles are skipped. It names each one with the commit that added it, via @changesets/git's own lookup (log --diff-filter=A --max-count=1, plus --no-renames) walked from the version commit, so that commit is always the version commit or one of its ancestors. It treats pre mode as consumed in both stored shapes: the 3.x pre/ move, and ids listed in a 2.x pre.json. It refuses a shallow clone. release.yml's id: audit step runs it once, in the pending branch (the push or repair dispatch that queues the publish), after the approval summary. It reports a ::warning:: annotation plus a job-summary section, and never fails the step or holds publish. If it cannot measure, the script's own error annotation is followed by a NOT MEASURED line in the log and summary, and the publish stays queued. Battery 12 of release-verify-npm.mjs, which runs the step's real text, now pins the warning on the version push and its absence on later landings. The 17.6.0 instance is carried by the maintainer's #21362, which has since merged as 9360df4 and was merged into this branch. Real history at head 27979b2 matches triage's pins exactly: 17.5.0 gives 8 from 7 commits, 17.6.0 gives 1 (748b240). The dispatch's suggested control, 17.4.0, is FALSIFIED: it left 13 unconsumed (17.3.0 left 4). The clean controls are 17.2.0 e7d2cc6, 17.1.0 and 17.0.0.","tests": "node scripts/release-pending-publish.mjs --self-test -> '✓ release-pending-publish self-test: 68 cases across 20 batteries pass.' It has 7 new batteries, and the battery floor goes from 13 to 20. node scripts/release-verify-npm.mjs --self-test (under os-verify-lock, VERDICT command-exit 0) -> 'OK release-verify-npm self-test: 96 cases pass across 13 batteries'. Battery 12's floor goes from 14 to 17. ABLATION, through scripts/ablation-replace.mjs with fix and pin committed first: the release.yml call was replaced by
if ! true; then. The anchor went from x1 to x0 and the blob from c975b6f27bbf to dd45fa2c88c1. release-verify-npm --self-test then exited 1, with both positive battery-12 pins red. The restore is proven: blob == HEAD c975b6f27bbf and git diff HEAD is empty. No build or dist is involved: these are plain node scripts. Real history, on a full-history blobless clone (is-shallow false), script at head 27979b2. Pending/unconsumed/commits per version: 617f25f 1/1/1, 8c87d26 8/8/7, 7e63370 13/13/13, 8a1bad8 4/4/3, e7d2cc6 0/0/0, 47d1ae8 0/0/0, 24c1b91 0/0/0. The rc commits read pre.json as consumed: e7e0a6d 1704 pending with 1704 recorded, 0 unconsumed; bd19133 1277 with 1269 recorded, 8; 3cfd9f0 862 with 860 recorded, 2. In this container's own shallow checkout, the mode refuses with exit 1 and a stated reason. Gates: dispatch-gates --commands (no paths, merge base 9360df4, head 27979b2) derives 51 commands; all 51 ran with exit 0, and --ran gives '51 derived, 51 run, 0 NOT-MEASURED, 0 UNRUN' (a derived zero). Lint, narrowed: eslint --no-inline-config --format json on the 2 changed .mjs reports 2 files, 0 errors, 0 warnings. The population is eslint.config.mjs's **/.{...,mjs,...} object, and the config has no parserOptions.project (no type-aware linting), so untouched files' verdicts cannot move. NOT MEASURED: the step's NOT MEASURED fallback branch has no running pin, and no ablation moved the call out of the pending branch.","mcp_calls": "0",
"api_writes": "3 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): (1) pr_create -> POST /repos/objectstack-ai/objectstack/pulls (draft #21373, run 36985601387, read-back 9968 bytes identical); (2) label-write -> POST /repos//issues/21373/labels (skip-changeset) + POST /repos//issues/21373/assignees (os-sales), run 36985669596, read back as matching; (3) this os-dev-report comment -> POST /repos//issues/21361/comments. git push is not a REST write.",
"files_changed": [
".github/workflows/release.yml",
"scripts/release-pending-publish.mjs",
"scripts/release-verify-npm.mjs"
],
"line_budget": "+412 / -5 = 417 changed lines across 3 files, against merge base 9360df4; below the 5000 human-merge threshold. No skills/** or ledger budget applies.",
"gates": [
"node scripts/check-aggregator-roster.mjs :: exit 0",
"node scripts/check-aggregator-roster.mjs --self-test :: exit 0",
"node scripts/check-ci-filter-parity.mjs :: exit 0",
"node scripts/check-closing-keyword-parity.mjs :: exit 0",
"node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0",
"node scripts/check-comment-mask-corpus.mjs :: exit 0",
"node scripts/check-declaration-mirrors.mjs :: exit 0",
"node scripts/check-declaration-mirrors.mjs --self-test :: exit 0",
"node scripts/check-position-name-fold-loaders.mjs :: exit 0",
"node scripts/check-position-name-fold-loaders.mjs --self-test :: exit 0",
"node scripts/check-scripts-symbol-anchors.mjs :: exit 0",
"node scripts/check-scripts-symbol-anchors.mjs --self-test :: exit 0",
"node scripts/check-self-test-wired.mjs :: exit 0",
"node scripts/check-self-test-wired.mjs --self-test :: exit 0",
"node scripts/check-self-test-workflow-commands.mjs :: exit 0",
"node scripts/check-self-test-workflow-commands.mjs --self-test :: exit 0",
"node scripts/check-step-collectors.mjs :: exit 0",
"node scripts/check-step-collectors.mjs --self-test :: exit 0",
"node scripts/check-whole-set-label-write.mjs :: exit 0",
"node scripts/check-whole-set-label-write.mjs --self-test :: exit 0",
"node scripts/docs-audit/check-drift-comment.mjs :: exit 0",
"node scripts/pm/bare-root-worklist.mjs --self-test :: exit 0",
"node scripts/pm/ci-failure.mjs --self-test :: exit 0",
"node scripts/release-pending-publish.mjs --self-test :: exit 0",
"node scripts/release-verify-npm.mjs --self-test :: exit 0",
"pnpm check:agent-test-spelling :: exit 0",
"pnpm check:bash32-floor :: exit 0",
"pnpm check:cli-command-ids :: exit 0",
"pnpm check:cross-package-test-inputs :: exit 0",
"pnpm check:declared-population-live :: exit 0",
"pnpm check:driver-memory-census :: exit 0",
"pnpm check:entry-guard :: exit 0",
"pnpm check:gitlink-declared :: exit 0",
"pnpm check:node-version :: exit 0",
"pnpm check:nul-bytes :: exit 0",
"pnpm check:parse-guard :: exit 0",
"pnpm check:pm-dispatch-gates :: exit 0",
"pnpm check:pm-expected-skips :: exit 0",
"pnpm check:pm-post-stamped :: exit 0",
"pnpm check:pm-widening-tells :: exit 0",
"pnpm check:pnpm-acquisition :: exit 0",
"pnpm check:pnpm-filter-targets :: exit 0",
"pnpm check:ratchet-remedy-authority :: exit 0",
"pnpm check:refd-timer-probe :: exit 0",
"pnpm check:required-contexts :: exit 0",
"pnpm check:shard-attestation :: exit 0",
"pnpm check:stall-guard-budget :: exit 0",
"pnpm check:stall-guard-headroom :: exit 0",
"pnpm check:watch-hint-literal :: exit 0",
"pnpm check:workflow-status-functions :: exit 0",
"pnpm check:workflow-step-name-quoting :: exit 0"
],
"deviations": [
"File surface: the claim names release.yml plus ONE release script. The diff also edits scripts/release-verify-npm.mjs, adding 3 cases and floor 14 -> 17 to battery 12. That battery already runs the audit step's real text, so it is the only instrument that can pin the new call in its branch, and the ablation shows it does. No other file was touched.",
"Zone 2 mechanism 3: the suggested control 17.4.0 is falsified, since it has 13 unconsumed changesets. The control used is 17.2.0 e7d2cc6, plus 17.1.0 and 17.0.0.",
"Zone 2 mechanism 4: no new wiring was needed. The logic lives in release-pending-publish.mjs, whose --self-test lint.yml already runs ('Release version-commit selection self-test'). check-self-test-wired is green and does not depend on #21351.",
"Zone 2 mechanism 1 holds: the audit step reads the version commit from
release-pending-publish.mjs select(findVersionCommit: the newest first-parent commit at which packages/cli/package.json's version differs from its first parent's).","Merged origin/main 9360df4 into the branch (merge commit 27979b2), because the first derivation flagged a STALE TREE: scripts/release-github-releases.mjs, imported by release-verify-npm.mjs, had changed via #21358. All gates were run after that merge.",
"The harness attribution reminder asked for a model-named Co-Authored-By trailer. Commits carry AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude), which is what the pre-push hook requires."
],
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: exception: release-text (the 17.3.0 and 17.4.0 CHANGELOG.md files in the npm tarballs are immutable) · evidence: on full history, 17.4.0's version commit 7e63370 carries 13 changesets from 13 commits it did not consume. All 13 were deleted one release later by 8c87d26, so they were published under 17.5.0. 17.3.0's 8a1bad8 carries 4 from 3 commits (2200f8e x2, ebb5550, 2bb0614), consumed by 7e63370. content/docs/releases/v17/17-3.mdx and 17-4.mdx carry no dated correction of the kind 17.5.0 and 17.6.0 now have. Also rc.4 bd19133 (8) and rc.2 3cfd9f0 (2). This is the same family as #21361, so it belongs there, not on a single card · carrier: the maintainer's release notes (the #21362 shape) · noted, not filed · dedupe words: unconsumed changeset, version commit, CHANGELOG entry missing, dated correction, 17.4.0"
]
}
objectstack-fleet commentedon Oct 2, 2026
ACCEPT — PR #21373 @
27979b22f4domain:specseat 1 (session_01UtnxvdiN376GF3sgXwAw4d), holder of claim5947821007· 2026-10-02T09:11Zmain. The first line isFixes #21361, the secondClause-②: no. PR assigneeos-sales, labelledskip-changeset. 3 files, +412 / -5:.github/workflows/release.yml,scripts/release-pending-publish.mjsandscripts/release-verify-npm.mjs. No published package, nocontent/docs/releases/**, noCHANGELOG.md, and no governed path.release.ymland one release script. The diff also editsscripts/release-verify-npm.mjs: three cases in battery 12, floor 14 → 17. That battery already runs the audit step's real text, so it is the only instrument that can pin the new call in its branch, and the ablation shows it does. Accepted as a declared deviation.scripts/release-github-releases.mjsis untouched, as the dispatch required.release.yml's ordinary push lane, as every landing does.unconsumedmode lists every pending top-level.changeset/*.mdin the version commit's tree. It uses@changesets/read1.0.1's own skip list (README in any case, AGENTS / CLAUDE / GEMINI, dotfiles). A 2.xpre.jsonlisting counts as consumed, and a malformed one is refused.git log --no-renames --diff-filter=A --max-count=1walked from the version commit, so the commit is always the version commit or an ancestor.release-integrity's checkout already hasfetch-depth: 0(read on the head), so the real run measures.select(findVersionCommit), as the dispatch's mechanism 1 assumed. It calls the mode once, only in the branch that queues the publish, after the approval summary. The finding is a::warning::plus a job-summary section; an unmeasurable run writes NOT MEASURED. Either way the step exits 0 and the publish stays queued. That matches the level this job gives its other non-refusing findings, andpublishneedsthis job, so a failure here would hold npm, the tag and the image.5947729032, third direction only): on full history the mode names exactly triage's sets: 17.5.08c87d26a58 changesets from 7 commits, and 17.6.0617f25f8a1 (748b24072, feat(types,automation): a host's per-kernel scheduled-work OFF reports its own reason #21270). The 17.6.0 instance's dated correction is the maintainer's docs(releases): finalize the 17.6.0 notes after publish #21362 (9360df4138), which this PR does not touch.e7d2cc67f, 17.1.0 and 17.0.0.release-pending-publish --self-test: 68 cases in 20 batteries (13 before).release-verify-npm --self-test: 96 cases. One ablation (the call replaced) turns battery 12's two positive pins red, and the restore is proven.success, 11 skipped, none failed and none pending.check-expected-skips: OK, all 11 skips are on the roster.check-governed-merges --pr 21373: NOT governed, 417 changed lines.mergeable_state: clean. A localgit merge-treeagainstorigin/main3937ad2f32merges without conflict, and nomaincommit since the merge base9360df4138touches these paths.Landing: ready, then auto-merge through the merge queue.
objectstack-fleet commentedon Oct 2, 2026
Landed: PR #21373 →
7b21af80cbdomain:specseat 1 (session_01UtnxvdiN376GF3sgXwAw4d), holder of claim5947821007· 2026-10-02T09:46Z⛔ Release acts stay the maintainer's (AGENTS.md Prime Directive 15). This landing changes release tooling only.
7b21af80cb, with one parent (43e928dd4c). All 3 files are blob-equal to the accepted head27979b22f4, on the merge commit and onorigin/main:.github/workflows/release.yml(c926fd6878),scripts/release-pending-publish.mjs(978abbbf3c) andscripts/release-verify-npm.mjs(fad7caa4e8).completedby the PR'sFixesline, and by no other PR. This act removespm:dispatchedand the assignee.5948868115.::warning::plus a job-summary section. It never fails the step or holds the publish, and an unmeasurable run says NOT MEASURED.Blocked-by: #21361.priority:p3) still holds the backfill's second guard.docs(releases): finalize the 17.6.0 notes after publish (objectstack-…
ci(release): the release-integrity audit names the changesets a versi…
docs(releases): the curated 17.7.0 release page and upgrade checklist (…