Repository navigation
Commit 2a4254a
fix(release): the release-integrity backfill builds from the version commit's tree, not github.sha (#21008)
Closes #20982
Clause-②: no (release wiring; no published package's accept set or
public surface moves, per the question in `scripts/pm/clause2-line.mjs`)
## What this changes
`release.yml`'s `release-integrity` job repairs an already-published
release by backfilling its GitHub Releases and its ADR-0087 D4 asset
(`spec-changes.json`). Before this PR, those backfill steps ran in the
job's checkout. That checkout is `github.sha`, the head of whichever
push is being audited. Since PR #20625, the publish job builds the
**version commit** instead. As a result:
- A landing after the version commit that touched `packages/spec/src`
made a repaired D4 asset describe a tree npm did not ship.
- The Releases backfill pointed `target_commitish` and the CHANGELOG
permalink at that landing.
After this PR, every backfill step builds from the version commit's
tree, as the publish job does. Per triage `5922583890` and the claim
`5922727017`:
- **Audit step.** It already makes a worktree of the version commit
(`git worktree add --detach`, from the object database, for the
whole-group probe). It now passes that worktree to the backfill steps as
a new step output, `version-tree`. Nothing else in the audit moves. The
checkout is not swapped, the audit still reads `github.sha`, and its
tripwire still reads the workspace.
- **`Install dependencies (the version commit's tree)`.** `pnpm install
--frozen-lockfile` runs in that worktree, against the version commit's
lockfile. The `github.sha` checkout is no longer installed, because
nothing reads it after the audit.
- **Releases backfill.** The version commit's own
`scripts/release-github-releases.mjs` runs in its own tree, so every
package and every `CHANGELOG.md` is read from there. `GITHUB_SHA` is set
to the version commit for that one process. The script uses that value
as `target_commitish` and as the ref of the CHANGELOG permalink. GitHub
ignores `target_commitish` when the tag already exists. But a publish
that died before its tag push leaves no tag, and the Release then
creates the tag at `target_commitish`.
- **D4 backfill.** `release-spec-changes.sh --prepare` and `--attach`
run in the worktree, with that commit's generator, exactly as the
publish job's own D4 step does. So the asset a repair attaches is the
manifest the publish built.
- **Each of the three steps refuses a tree that is not at the version
commit.** It compares `git -C "$VERSION_TREE" rev-parse HEAD` with
`version-commit`. Without this check, an empty `version-tree` would
silently leave the step in the checkout, which is the defect.
- **The lane header** used to say the job "Reads github.sha ONLY". It
now says the job reads `github.sha` and the version commit it selects,
and that every backfill builds from that commit's tree.
`scripts/release-spec-changes.sh` is unchanged. It needs no tree
argument, because the version commit's own copy runs in the version
commit's tree.
## Pin
The pin is battery 13 of `node scripts/release-verify-npm.mjs
--self-test`, which `lint.yml` already runs as "Post-publish npm
verification self-test". Battery 12, next to it, pins *when* the audit
backfills; battery 13 pins *which tree* the backfill builds from. The
self-test now has 93 cases across 13 batteries (82 across 12 before),
and the roster floor is 13.
- **Fixture.** A throwaway repository: base (1.0.0), then the version
commit (1.1.0), then **a landing that moved `packages/spec/src`**. The
release scripts are committed into the fixture together with their
imports. A symlink would not work: Node would resolve
`release-github-releases.mjs` to this repository and read this
repository's workspace.
- **What runs.** Five steps, each from its own text in `release.yml`.
Each step's `env:` is read from the YAML too, and every expression in it
is either resolved or refused. The five steps are:
- the audit, with `github.sha` set to the landing;
- the three backfill steps;
- the publish job's own D4 step, in a worktree at the version commit
(what its `ref:` checks out).
- **Stubs.**
- `npm`: `view`, `versions`, and a real `pack`.
- `gh`: records each upload.
- `pnpm`: records each install. It also stands in for the generator: it
finds the workspace above its cwd, as pnpm does, and writes a manifest
that is a pure function of that workspace's `packages/spec/src`.
- A Releases API on 127.0.0.1 that records every POST.
- **The 11 cases.**
- Fixture control: the D4 step run in the landing's tree builds a
different manifest from the publish's.
- The audit requests the Releases backfill and names a `version-tree`
that is at the version commit.
- Install runs in that tree only.
- Both Releases are POSTed with `target_commitish` equal to the version
commit.
- The truncated spec body links `CHANGELOG.md` at the version commit.
- The generator runs in that tree, and the upload is made from it.
- **The attached `spec-changes.json` is byte-identical to the publish
job's manifest.**
- Every backfill step refuses an empty `version-tree`, with nothing
installed, created or attached.
- Every backfill step refuses a `version-tree` at the landing, with
nothing installed, created or attached.
- Every step's env resolved.
- The five steps are read out of `release.yml` itself.
### Ablations
Each leg starts from the committed fix and goes through `node
scripts/ablation-replace.mjs`. The anchor had to hit, and the blob
changed on disk. The tool wrapped the self-test, under a trap. Every
restore was proven by the file's blob matching HEAD's and by an empty
`git diff HEAD`.
| Mutation in `release.yml` | Result |
|---|---|
| D4 step: drop `cd "$VERSION_TREE"` before `--prepare`, so it runs in
the checkout again | **2 of 93 red.** The generator ran in the checkout,
and the attached manifest (145 bytes) is not the publish job's (138
bytes); it equals the landing-tree build |
| Releases step: drop the `GITHUB_SHA="$VERSION_COMMIT"` override | **2
of 93 red.** Both Releases were POSTed at the landing, and the permalink
names the landing |
| Delete the tree guard from all three steps (`--expect 3`) | **2 of 93
red.** The two refusal cases fail: install ran in the checkout, then in
the landing's tree |
| Audit: drop the `version-tree` output line | **6 of 93 red.** Every
backfill step refuses, so the lane fails closed |
The first attempt at the first leg was a no-op: the replacement text was
already in the file. `ablation-replace` refused it before anything ran,
and the leg was re-run with a distinct marker.
## Gates
- `node scripts/release-verify-npm.mjs --self-test` exits 0 on
`68e56d7e65` (93 cases, 13 batteries).
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` over this diff (2 paths) derives 50
commands. All 50 exit 0 on `68e56d7e65`; `dispatch-gates --ran`: 50
derived, 50 run, 0 NOT-MEASURED, 0 UNRUN; `check:pm-dispatch-gates` 1976
cases pass (dev report `5923103867`).
- No changeset: a workflow and a root `scripts/` file publish nothing,
so `skip-changeset` applies.
## Acceptance notes
- **Not changed here: the publish job's own `Create GitHub Releases`
step.** It runs `release-github-releases.mjs` with Actions'
`GITHUB_SHA`, so its truncated bodies link `CHANGELOG.md` at the head of
the queuing push. On a repair dispatch, that head can be well past the
version commit. Its CHANGELOGs are still read from the version commit's
checkout. Its tags already exist by then, because `release-publish.sh`
pushes them before `published=true`, so `target_commitish` is unused.
The linked file at the later head still carries the entry. This is
outside this card's surface (the backfill). Carrier: none.
- The new install step's pnpm is materialised from `github.sha`'s
`packageManager` pin, by `setup-pnpm`. Corepack then runs whatever the
version commit's `package.json` pins. If the two differ, the version
commit's pnpm is downloaded once. That is the same pnpm the publish job
uses, and the Corepack cache is not involved, because it is saved inside
`setup-pnpm` before this step runs.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent f257223 commit 2a4254a
2 files changed
Lines changed: 600 additions & 15 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
740 | 740 | | |
741 | 741 | | |
742 | 742 | | |
743 | | - | |
| 743 | + | |
| 744 | + | |
| 745 | + | |
744 | 746 | | |
745 | 747 | | |
746 | 748 | | |
| |||
999 | 1001 | | |
1000 | 1002 | | |
1001 | 1003 | | |
| 1004 | + | |
| 1005 | + | |
| 1006 | + | |
1002 | 1007 | | |
1003 | 1008 | | |
1004 | 1009 | | |
| |||
1049 | 1054 | | |
1050 | 1055 | | |
1051 | 1056 | | |
| 1057 | + | |
| 1058 | + | |
| 1059 | + | |
| 1060 | + | |
| 1061 | + | |
| 1062 | + | |
| 1063 | + | |
| 1064 | + | |
| 1065 | + | |
| 1066 | + | |
| 1067 | + | |
| 1068 | + | |
| 1069 | + | |
| 1070 | + | |
| 1071 | + | |
| 1072 | + | |
| 1073 | + | |
| 1074 | + | |
| 1075 | + | |
| 1076 | + | |
| 1077 | + | |
| 1078 | + | |
1052 | 1079 | | |
1053 | 1080 | | |
1054 | 1081 | | |
1055 | 1082 | | |
1056 | | - | |
| 1083 | + | |
1057 | 1084 | | |
1058 | | - | |
| 1085 | + | |
| 1086 | + | |
| 1087 | + | |
| 1088 | + | |
| 1089 | + | |
| 1090 | + | |
| 1091 | + | |
| 1092 | + | |
| 1093 | + | |
| 1094 | + | |
1059 | 1095 | | |
1060 | 1096 | | |
1061 | 1097 | | |
| |||
1066 | 1102 | | |
1067 | 1103 | | |
1068 | 1104 | | |
1069 | | - | |
| 1105 | + | |
| 1106 | + | |
| 1107 | + | |
| 1108 | + | |
| 1109 | + | |
| 1110 | + | |
| 1111 | + | |
| 1112 | + | |
| 1113 | + | |
| 1114 | + | |
| 1115 | + | |
| 1116 | + | |
| 1117 | + | |
| 1118 | + | |
| 1119 | + | |
| 1120 | + | |
| 1121 | + | |
1070 | 1122 | | |
1071 | 1123 | | |
1072 | 1124 | | |
1073 | 1125 | | |
1074 | 1126 | | |
1075 | 1127 | | |
1076 | | - | |
1077 | | - | |
1078 | | - | |
1079 | | - | |
| 1128 | + | |
| 1129 | + | |
| 1130 | + | |
| 1131 | + | |
| 1132 | + | |
1080 | 1133 | | |
1081 | 1134 | | |
1082 | 1135 | | |
1083 | 1136 | | |
| 1137 | + | |
| 1138 | + | |
1084 | 1139 | | |
| 1140 | + | |
| 1141 | + | |
| 1142 | + | |
| 1143 | + | |
| 1144 | + | |
1085 | 1145 | | |
1086 | 1146 | | |
1087 | 1147 | | |
| |||
0 commit comments