Repository navigation
fix(release): judge the major-boundary template stamps on the version-pr lane, and stop prerelease cuts re-dating the last GA - #22095
Conversation
…e release index sync-release-index-currency stamped today's date into a current-series field that already named the newest GA, so every pre-mode cut (18.0.0-next.N, and X.Y.Z-rc.N on the RC lane) moved the v17 entry's release date to the cut's day. The gate judges the version only, and the date belongs to the version commit that moves the field; a same-version field is now left alone. Battery B's pinned re-date case is inverted and Control H pins the prerelease cut. Claude-Session: https://claude.ai/code/session_01VF48aw8RPG6wzDnMgp6rtw Co-authored-by: Claude <noreply@anthropic.com>
…or boundary instead of refusing them Validate the post-version tree refused all four major-boundary paths for want of a gate. The blank template's three stamped files are now judged by gates the repo already runs (create-objectstack's suite, which renders the template and ratchets its stamps against the scaffolder's new major, and check:template-manifests). protocol-version.ts gets its lockstep test (one file, 5 s) and the two artifacts derived from PROTOCOL_MAJOR (check:spec-changes, check:upgrade-guide), and stays refused: moving the protocol major makes the handshake refuse the example apps' engines.protocol, which no gate on this lane boots. The refusal is collected, so one boundary run names every verdict. Claude-Session: https://claude.ai/code/session_01VF48aw8RPG6wzDnMgp6rtw Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF48aw8RPG6wzDnMgp6rtw Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VF48aw8RPG6wzDnMgp6rtw Co-authored-by: Claude <noreply@anthropic.com>
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 37654789143 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
Part of #22085. This PR carries the half of the card that holds on measurement. The half it does not carry needs a decision first (see "What still stops the refresh").
Clause-②: no
What this changes
sync-release-index-currencyno longer re-dates the newest GA on a prerelease cut.rewriteStatusFieldre-stamped today's date into acurrent series:field that already named the newest GA. The gate it serves (indexCurrencyFindings) judges the version only. The date it holds is the release date of the version the run moves the field TO, so a run that moves nothing (everynextorrccut) is not that version's version commit. A same-version field is now left alone. Battery B's case that pinned the re-date is inverted, and a new battery,Control H: a prerelease cut never re-dates the newest GA(7 cases), pins thenextcut, therccut, a positive control (a stale entry on the same later day still gets the version and that day), andsyncIndexend to end on a temp checkout (no write, bytes identical). The roster floor goes from 7 to 8.release.ymlversion-pr›Validate the post-version treevalidates the blank template's three major-boundary paths instead of refusing them. It reuses gates the repo already runs, with no build:pnpm --filter create-objectstack test: the template rendered by the scaffolder's own copy and identity rewrite, from a template packed the way npm ships it, plus the ratchets intemplate-consistency.test.tsthat judge all three stamps against create-objectstack's NEW major;pnpm --filter @objectstack/spec check:template-manifests.protocol-version.tsgets its gates too:protocol-version.test.tsas ONE file (5 s). It does not need the whole spec suite, which is what the step's comment used to claim;check:spec-changesandcheck:upgrade-guide, the two artifacts derived fromPROTOCOL_MAJOR.It stays refused, for the measured reason below. The refusal is now collected instead of exiting first, so a boundary run reports every gate's verdict together. Every pnpm filter carries
--fail-if-no-match, because a filter that matches nothing exits 0 having run nothing (measured: 0 without it, 1 with it).Pin: the boundary train, replayed (throwaway tree, never committed)
Tree: this branch at
3079e4aef0plus PR #22084's.changeset/pre.jsonand.changeset/22080-v18-line-opens.md, carried by one local commit that was never pushed. The steps were extracted from this branch'srelease.ymlwith a YAML parser and run verbatim withRUNNER_TEMP/GITHUB_OUTPUT/GITHUB_STEP_SUMMARYset.Render the post-version tree(the full rootversionscript)fixedmembers at18.0.0-next.0,pre.jsonunchanged (mode: pre,tag: next).PROTOCOL_VERSION 17.0.0 → 18.0.0. Template stamps at^18.0.0/'^18'. 9 docs pins moved to18.0.0-next.0. Release index: "already names the newest GA … nothing rewritten"(current series: 17.7.0, released 2026-10-06);git diff HEAD -- content/docs/releases/index.mdxempty. Before this PR, the same replay wrotereleased 2026-10-07(reproduced on PR #22084's head52f7a509c6)Validate the post-version treecheck:release-notes, plus the create-objectstack suite,check:template-manifestsand the lockstep test. 3 gates red:check:release-notes,check:spec-changes,check:upgrade-guide. 1 unvalidated:protocol-version.tsRestore the pre-version treeControl on an ordinary train. This branch without the two opening files is the 17.8.0 refresh #21988 gets today.
Renderexits 0 (194 paths, and the release index stamps17.8.0, released 2026-10-07, version and date together).Validateexits 0 with all 14 gates green, holding 44 s.Restoreexits 0.Negative control for the template gate. On the boundary tree,
specVersionin the blank manifest was set back to^17.0.0.template-consistency.test.tsthen exits 1 with 2 failed, and the file was restored by hash (0956082cfd8eboth sides).Baseline.
main's own step, replayed on PR #22084's head, exits 1 at the old blanket refusal and names all 4 paths. This reproduces the measurement the card rests on.Why
protocol-version.tsis still refused (measured, not guessed)Moving the protocol major at version time does more than move a constant:
check:spec-changesexits 1 ("spec-changes.json is stale") andcheck:upgrade-guideexits 1. Both pass on the pre-version tree (control). Regenerating them in the throwaway changespackages/spec/spec-changes.jsonby 6342 lines, and adds a 1024-lineProtocol 17 → 18section todocs/protocol-upgrade-guide.md. The version pass regenerates neither. Both gates run in the requiredTypeScript Type Checkjob, so a version PR let through as things stand would turnmainred on its next ordinary PR.assertProtocolCompatruns on the app load seam (packages/runtime/src/app-plugin.ts:421). Probed with the post-version constant,checkProtocolCompatgives^17→incompatible(OS_PROTOCOL_INCOMPATIBLE) and^18→ok. On the pre-version tree it is the reverse.examples/app-crm,app-showcaseandapp-todo, plus the two packages inapp-multi-package, declareengines: { protocol: '^17' }. No gate this lane can afford boots them.So the refusal stays, as Done-when 1's last clause provides ("The refusal stays for any major-only path still unvalidated"), with its message rewritten to say exactly this.
What still stops #21988 refreshing into 18.0.0-next.0
These are three decisions, set out with options and a recommendation in the card's
os-dev-report. None of them is made here:How the protocol major moves at the opening. Either the version pass regenerates the two artifacts and restamps in-repo
engines.protocol(the version chain grows), or an ordinary PR with CI moves the protocol major ahead of the version PR (the lockstep test's definition changes).check:release-notesis red at the boundary (it is already in this step). It counts## 18.0.0-next.0as "shipped a 18.x release" and asks forcontent/docs/releases/v18.mdxplus itsmeta.jsonentry. That content is release-owned, and this PR does not write it.Docs image pins during the
nextline. These were measured and not edited (Done-when 4). On the first prerelease,sync-docs-image-tagsmoves 9 pins from17.7.0to18.0.0-next.0:docker/README.md: 3 image tags and 1 build-arg;content/docs/deployment/self-hosting.mdx: 3 image tags and 1 npm pin;content/docs/upgrading.mdx: 1 image tag.Meanwhile
npm viewgiveslatest: 17.7.0(andrc: 17.0.0-rc.6, nonextyet) for@objectstack/cli,@objectstack/specandcreate-objectstack. The ghcrlatesttag does not move for a prerelease (docker-publish.yml:83).Verification
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackata4cbcfdb16): 50 commands, all exit 0, exit codes written to disk before any pipe.--ran:50 derived, 50 run, 0 NOT-MEASURED, 0 UNRUN. The batterypnpm check:pm-dispatch-gatespassed 1976 cases in 997.8 s.node scripts/sync-release-index-currency.mjs --self-test: exit 0, 42 cases.ablation-replace.mjs, the pre-fix logic (const rewritten = …; return rewritten === field ? null : rewritten;) was put back in place of the fix. The self-test exits 1 with exactly 5 failures: battery B's inverted case and 4 of Control H's 7. H's three controls stay green, as they should. The file was restored with blob equal to HEAD andgit diff HEADempty. A first, cruder ablation that only deleted the guard line also reddened B and C. That mutation was too strong, so the faithful one above is the reading.Acceptance notes (noted, not fixed here)
Create or update the "chore: version packages" PRinrelease.ymlstill sayspnpm run versionis FOUR rewriters. It is five (sync-release-index-currency.mjsjoined).cut-rc.ymlsays "On an RC cut this rewriter writes NOTHING". That was false for the date before this PR (an rc cut on a later day re-dated the entry) and is true after it.cut-rc.ymlis not edited, by the card.release.yml's step comment said the lockstep test was "reachable only through the whole @objectstack/spec suite". That is corrected in place, because it is the step this card owns.Changeset: none. The diff touches
.github/workflows/release.ymlandscripts/sync-release-index-currency.mjs, and neither is in any package'sfiles[].Commits carry this repository's model-free trailer pair (AGENTS.md).
Generated by Claude Code