Repository navigation
Commit 8a925b3
fix(release): judge the major-boundary template stamps on the version-pr lane, and stop prerelease cuts re-dating the last GA (#22095)
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
1. **`sync-release-index-currency` no longer re-dates the newest GA on a
prerelease cut.** `rewriteStatusField` re-stamped today's date into a
`current 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 (every `next` or `rc` cut) 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 the `next` cut, the `rc` cut, a positive control (a stale entry on
the same later day still gets the version and that day), and `syncIndex`
end to end on a temp checkout (no write, bytes identical). The roster
floor goes from 7 to 8.
2. **`release.yml` `version-pr` › `Validate the post-version tree`
validates 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 in `template-consistency.test.ts`
that judge all three stamps against create-objectstack's NEW major;
- `pnpm --filter @objectstack/spec check:template-manifests`.
`protocol-version.ts` gets its gates too:
- `protocol-version.test.ts` as ONE file (5 s). It does not need the
whole spec suite, which is what the step's comment used to claim;
- `check:spec-changes` and `check:upgrade-guide`, the two artifacts
derived from `PROTOCOL_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 `3079e4aef0` plus PR #22084's `.changeset/pre.json`
and `.changeset/22080-v18-line-opens.md`, carried by one local commit
that was never pushed. The steps were extracted from this branch's
`release.yml` with a YAML parser and run verbatim with `RUNNER_TEMP` /
`GITHUB_OUTPUT` / `GITHUB_STEP_SUMMARY` set.
| step | exit | reading |
|---|---|---|
| `Render the post-version tree` (the full root `version` script) | 0 |
69 of 69 `fixed` members at `18.0.0-next.0`, `pre.json` unchanged
(`mode: pre`, `tag: next`). `PROTOCOL_VERSION 17.0.0 → 18.0.0`. Template
stamps at `^18.0.0` / `'^18'`. 9 docs pins moved to `18.0.0-next.0`.
Release index: "already names the newest GA … nothing rewritten" |
| release index v17 entry | unchanged | `(current series: 17.7.0,
released 2026-10-06)`; `git diff HEAD --
content/docs/releases/index.mdx` empty. Before this PR, the same replay
wrote `released 2026-10-07` (reproduced on PR #22084's head
`52f7a509c6`) |
| shape assertion | pass | 235 paths moved, 0 outside the reviewed
surface. It was 236 before this PR; the difference is the release index
|
| `Validate the post-version tree` | **1** | 11 gates green: the 9
existing content gates except `check:release-notes`, plus the
create-objectstack suite, `check:template-manifests` and the lockstep
test. 3 gates red: `check:release-notes`, `check:spec-changes`,
`check:upgrade-guide`. 1 unvalidated: `protocol-version.ts` |
| `Restore the pre-version tree` | 0 | 37 pending changesets, tree clean
|
**Control on an ordinary train.** This branch without the two opening
files is the 17.8.0 refresh #21988 gets today. `Render` exits 0 (194
paths, and the release index stamps `17.8.0, released 2026-10-07`,
version and date together). `Validate` exits **0** with all 14 gates
green, holding 44 s. `Restore` exits 0.
**Negative control for the template gate.** On the boundary tree,
`specVersion` in the blank manifest was set back to `^17.0.0`.
`template-consistency.test.ts` then exits 1 with 2 failed, and the file
was restored by hash (`0956082cfd8e` both 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.ts` is still refused (measured, not guessed)
Moving the protocol major at version time does more than move a
constant:
- **Two derived artifacts go stale.** On the boundary tree,
`check:spec-changes` exits 1 ("spec-changes.json is stale") and
`check:upgrade-guide` exits 1. Both pass on the pre-version tree
(control). Regenerating them in the throwaway changes
`packages/spec/spec-changes.json` by 6342 lines, and adds a 1024-line
`Protocol 17 → 18` section to `docs/protocol-upgrade-guide.md`. The
version pass regenerates neither. Both gates run in the required
`TypeScript Type Check` job, so a version PR let through as things stand
would turn `main` red on its next ordinary PR.
- **The handshake refuses this repository's own example apps.**
`assertProtocolCompat` runs on the app load seam
(`packages/runtime/src/app-plugin.ts:421`). Probed with the post-version
constant, `checkProtocolCompat` gives `^17` → `incompatible`
(`OS_PROTOCOL_INCOMPATIBLE`) and `^18` → `ok`. On the pre-version tree
it is the reverse. `examples/app-crm`, `app-showcase` and `app-todo`,
plus the two packages in `app-multi-package`, declare `engines: {
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:
1. **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).
2. **`check:release-notes` is red at the boundary** (it is already in
this step). It counts `## 18.0.0-next.0` as "shipped a 18.x release" and
asks for `content/docs/releases/v18.mdx` plus its `meta.json` entry.
That content is release-owned, and this PR does not write it.
3. **Docs image pins during the `next` line.** These were measured and
not edited (Done-when 4). On the first prerelease,
`sync-docs-image-tags` moves 9 pins from `17.7.0` to `18.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 view` gives `latest: 17.7.0` (and `rc: 17.0.0-rc.6`, no
`next` yet) for `@objectstack/cli`, `@objectstack/spec` and
`create-objectstack`. The ghcr `latest` tag does not move for a
prerelease (`docker-publish.yml:83`).
## Verification
- Derived gates (`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` at `a4cbcfdb16`): 50 commands, all exit 0,
exit codes written to disk before any pipe. `--ran`: `50 derived, 50
run, 0 NOT-MEASURED, 0 UNRUN`. The battery `pnpm
check:pm-dispatch-gates` passed 1976 cases in 997.8 s.
- `node scripts/sync-release-index-currency.mjs --self-test`: exit 0, 42
cases.
- **Ablation, committed first.** With `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 and `git diff HEAD` empty. 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.
- Not run locally: the whole spec suite (the step no longer needs it),
and the repo-wide lint farm, which belongs to CI.
## Acceptance notes (noted, not fixed here)
- The comment above `Create or update the "chore: version packages" PR`
in `release.yml` still says `pnpm run version` is FOUR rewriters. It is
five (`sync-release-index-currency.mjs` joined).
- `cut-rc.yml` says "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.yml` is 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.yml` and
`scripts/sync-release-index-currency.mjs`, and neither is in any
package's `files[]`.
Commits carry this repository's model-free trailer pair (AGENTS.md).
---
_Generated by [Claude
Code](https://claude.ai/code/session_01VF48aw8RPG6wzDnMgp6rtw)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 172be37 commit 8a925b3
2 files changed
Lines changed: 162 additions & 33 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
368 | 368 | | |
369 | 369 | | |
370 | 370 | | |
371 | | - | |
372 | | - | |
373 | | - | |
374 | | - | |
375 | | - | |
376 | | - | |
377 | | - | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
378 | 383 | | |
379 | 384 | | |
380 | | - | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
381 | 388 | | |
382 | 389 | | |
383 | 390 | | |
| |||
417 | 424 | | |
418 | 425 | | |
419 | 426 | | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
| 447 | + | |
| 448 | + | |
| 449 | + | |
| 450 | + | |
| 451 | + | |
| 452 | + | |
420 | 453 | | |
421 | 454 | | |
422 | 455 | | |
| |||
595 | 628 | | |
596 | 629 | | |
597 | 630 | | |
598 | | - | |
599 | | - | |
600 | | - | |
601 | | - | |
602 | | - | |
603 | | - | |
604 | | - | |
605 | | - | |
606 | | - | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
607 | 650 | | |
608 | | - | |
609 | | - | |
610 | | - | |
611 | | - | |
612 | | - | |
613 | | - | |
| 651 | + | |
614 | 652 | | |
615 | 653 | | |
616 | 654 | | |
| |||
634 | 672 | | |
635 | 673 | | |
636 | 674 | | |
637 | | - | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
638 | 684 | | |
639 | 685 | | |
| 686 | + | |
640 | 687 | | |
| 688 | + | |
641 | 689 | | |
642 | 690 | | |
643 | 691 | | |
644 | 692 | | |
645 | 693 | | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
646 | 700 | | |
647 | 701 | | |
648 | 702 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
108 | 108 | | |
109 | 109 | | |
110 | 110 | | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
111 | 115 | | |
112 | 116 | | |
113 | 117 | | |
114 | 118 | | |
115 | 119 | | |
116 | | - | |
| 120 | + | |
| 121 | + | |
117 | 122 | | |
118 | 123 | | |
119 | 124 | | |
| |||
175 | 180 | | |
176 | 181 | | |
177 | 182 | | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
178 | 189 | | |
179 | 190 | | |
180 | 191 | | |
| |||
199 | 210 | | |
200 | 211 | | |
201 | 212 | | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
202 | 222 | | |
203 | 223 | | |
204 | 224 | | |
| |||
207 | 227 | | |
208 | 228 | | |
209 | 229 | | |
210 | | - | |
211 | | - | |
| 230 | + | |
| 231 | + | |
212 | 232 | | |
213 | 233 | | |
214 | 234 | | |
| |||
445 | 465 | | |
446 | 466 | | |
447 | 467 | | |
| 468 | + | |
448 | 469 | | |
449 | 470 | | |
450 | 471 | | |
451 | 472 | | |
452 | | - | |
| 473 | + | |
453 | 474 | | |
454 | 475 | | |
455 | 476 | | |
| |||
549 | 570 | | |
550 | 571 | | |
551 | 572 | | |
552 | | - | |
553 | | - | |
554 | | - | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
555 | 576 | | |
556 | 577 | | |
557 | 578 | | |
| |||
645 | 666 | | |
646 | 667 | | |
647 | 668 | | |
| 669 | + | |
| 670 | + | |
| 671 | + | |
| 672 | + | |
| 673 | + | |
| 674 | + | |
| 675 | + | |
| 676 | + | |
| 677 | + | |
| 678 | + | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
| 683 | + | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
| 700 | + | |
| 701 | + | |
| 702 | + | |
| 703 | + | |
| 704 | + | |
| 705 | + | |
| 706 | + | |
| 707 | + | |
| 708 | + | |
| 709 | + | |
| 710 | + | |
| 711 | + | |
| 712 | + | |
| 713 | + | |
| 714 | + | |
| 715 | + | |
| 716 | + | |
| 717 | + | |
| 718 | + | |
| 719 | + | |
| 720 | + | |
| 721 | + | |
648 | 722 | | |
649 | 723 | | |
650 | 724 | | |
| |||
695 | 769 | | |
696 | 770 | | |
697 | 771 | | |
698 | | - | |
699 | | - | |
| 772 | + | |
| 773 | + | |
| 774 | + | |
700 | 775 | | |
701 | 776 | | |
702 | 777 | | |
| |||
0 commit comments