mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 22:14:25 +01:00
v1.91.282.0 fix(ship-queue): one CHANGELOG rule before and after the merge, base keys stay in slot stamps, a stacked child carries past its released parent (#3518)
* Ship-queue train tooling: one CHANGELOG rule, base keys stay, stacked-child carry (GSTA-129) Four train-24 (GSTA-96) defects in one change. verify --train applies the same CHANGELOG rule before and after the merge: main's CHANGELOG plus the PR's own lines (its authored diff plus what mergeChangelogs writes for it). A head the pre-merge verify accepted no longer freezes the queue after its squash merge, and a freeze record lists a slot GitHub reports MERGED as merged. restamp's stamp_paths stage leaves a *_KEY_VERSION line the base introduced after the fork point alone, base merge committed or staged, and says so. mergeChangelogs with a base carries a stacked child's edits to its released parent entry as "Correction to the <version> entry below" bullets under the child's own Gate integrity section instead of returning null; the slot one-liner prints each carried correction. #3453's two 1.91.276.0 corrections are restored that way here. The digest-freshness defect is already closed by #3451 (regeneratedAtBase); docs/ship-policy.md now says how an unstamped generator change ships. Docs: ship-policy § Run a merge train, captain.md § Merge trains and the slot-call template carry the stamp-files and stacked-child rules. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * Review fixes: carried union from slot 2, GitHub-merged slot-1 freeze, no-own-entry refusal, fail-closed base diff (GSTA-129) Pre-landing review pass 1 (six specialists and the Red Team, all INFORMATIONAL): - mergeStep unions the carried child from slot 2 on, so a stacked child behind another slot never repeats its released parent's text under a second [Unreleased] (Red Team, lib/ship-queue-train.ts). - stopped() freezes the queue when any slot is MERGED on GitHub, so a slot-1 squash that fails the post-merge check no longer answers "nothing merged" (Red Team, lib/ship-queue-train-verify.ts). - ownEntryAboveMain refuses a CHANGELOG equal to main's: no entry of the PR's own (state-machines, lib/changelog-check.ts). - branchAddedLines refuses when the base diff cannot run instead of reading it as "nothing added" (Red Team, lib/restamp.ts). - slot-call.md and docs/captain.md name the stamp files as the ones the slot call names, STAMP_FILES plus a *_KEY_VERSION file the PR introduced, matching docs/ship-policy.md (maintainability). Also: the coverage tests Step 7 added (post-merge parent check, carry shapes), and two dependency-map rows (test/helpers/free-fixtures-data.ts for the merge-train-3453 fixtures, scripts/test-pr-profile.ts for captain/templates/**) so the paid-gate selector and the FREE_FIXTURES inventory accept the new files. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * Review pass 2: an unreadable GitHub state at a failed slot refuses, never "nothing merged" (GSTA-129) stopped() read prState's 'unreadable' as "not merged": with nothing in t.merged, a slot-1 squash already on main while gh pr view failed answered "nothing of the train merged, so the queue is not frozen". It now refuses with QUEUE_PROOF_MISSING ("whether #<n> merged on GitHub could not be read, so whether the queue must freeze is unknown") and asks for the verify to be rerun; no freeze, no backstop. Raised independently by five pass-2 reviewers. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * Docs audit: troubleshooting codes and ship-policy sections match the shipped train rules (GSTA-129) The /document-release audit (edit mode) corrected two docs the PR had not reached: docs/troubleshooting.md's QUEUE_TRAIN_TREE_MISMATCH, QUEUE_PROOF_MISSING, QUEUE_TRAIN_FROZEN and POLICY_SOURCE_UNAVAILABLE entries, and docs/ship-policy.md's train build conflict rule (the carried stacked child is the exception), the verify freeze paragraph (slot-1 GitHub-MERGED freeze, unreadable-state refusal) and the restamp stamp_paths stage (base-added lines stay; an unrunnable base diff refuses). Five mid-sentence colons in the PR's own paragraphs are rewritten for the prose lint, and the CHANGELOG Docs bullet names docs/troubleshooting.md. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * HARNESS_VERSION: scripts/test-pr-profile.ts row recorded non-behavioral at version 6 (GSTA-129) The remote free tier's only red was the HARNESS_VERSION guard: scripts/test-pr-profile.ts is a pinned shared-harness file and gained the captain/templates/** FREE_ONLY_PR_FILES row. Recorded with bump-harness-version.ts --non-behavioral: no paid case reads the crew templates, so no selection, input or verdict changes and no pass-rate series resets. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: type the saved fixture PR row for the test-code ratchet (GSTA-129) CI's typecheck:test ratchet refused one new TS2698 (spread of a loosely typed fixture row) in the slot-1 freeze test; the row is read as any, as the neighbouring state writes already do. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * ship-queue verify: build the freeze record from the one GitHub read that decided to freeze freezeQueue took a second prState read per unverified slot and filed anything but an exact MERGED under unmerged, so a slot that read MERGED at stopped() and was unreadable a moment later was recorded as unmerged (the record half of train 24's #3453 misfile). stopped() now reads each unverified slot once and passes those states in; a MERGED slot stays merged, and a slot unreadable beside a merged one is kept out of unmerged and named in the reason. The fixture's gh shim gains a per-PR vanish count so a test can change GitHub's answer between two reads. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * ship-queue verify: say what happens to a slot unreadable beside a merged one The freeze reason, docs and CHANGELOG said the slot was kept out of unmerged 'until read', but nothing reads it again: the NEXT after the repair is built from unmerged alone. Say so (the operator seats it in a train by hand once gh answers) and pin the record shape with a test. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * v1.91.282.0 stamp Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
392f50d47b
commit
9ccb5233f3
21 files changed
+1080
-73
No files matched your search
@@ -207,6 +207,21 @@ files. In practice slot 1 needs the same merge whenever the base moved after the
|
||||
taken. A stamp commit with one extra byte freezes the queue for every
|
||||
lane behind it.
|
||||
|
||||
The slot stamp is the base merge, `mergeChangelogs`, and the stamp files the slot call
|
||||
names (`STAMP_FILES` in CREW.md; gstack's are `CHANGELOG.md`, `VERSION`, `package.json` and
|
||||
`agents-digest/gstack-AGENTS.md`, plus the file carrying a `*_KEY_VERSION` the PR
|
||||
introduced, which the restamp moves on the PR's own line, when the call names it), never a
|
||||
fifth: a file the restamp lists that the call did not name is not a stamp, so the lane
|
||||
leaves it out and says so in its READY. The restamp itself never
|
||||
moves a line the base added since the pin's fork point, base merge committed or staged. A
|
||||
pin stacked on a PR that squash-merged earlier conflicts beyond the CHANGELOG where the
|
||||
parent's squash touched the pin's lines, so the lane takes its pin's bytes for those files
|
||||
(`verify` checks the tree against T<i>, which already carries the parent), and
|
||||
`mergeChangelogs` carries the pin's edits to the parent's now-released entry as Gate
|
||||
integrity corrections in the pin's own entry. The post-merge `verify` judges the CHANGELOG
|
||||
by the same rule the pre-merge one did, so an accepted head never freezes the queue after
|
||||
its merge ([ship-policy.md](ship-policy.md#run-a-merge-train)).
|
||||
|
||||
Options the controller writes into CREW.md rather than inheriting: squash versus merge
|
||||
commits; lane stamps versus controller stamps; gate-ahead (slot i+1 gates on slot i's
|
||||
head while i merges); the severe race (several severe lanes told at once that the next
|
||||
|
||||
+76
-12
@@ -486,7 +486,9 @@ missing, cancelled or on another SHA). In a merge, version files take the
|
||||
prefix's side and the CHANGELOG merges by section, since the stamp at merge
|
||||
rewrites both; a PR whose CHANGELOG drops or renames a released heading (or
|
||||
carries a released entry's text in a section of its own) is a CHANGELOG
|
||||
conflict, never merged with the damage. READY receipts and train records are
|
||||
conflict, never merged with the damage, except the stacked child whose parent
|
||||
was released since their merge base, which `mergeChangelogs` carries (see *A
|
||||
stacked child whose parent merged earlier*, below). READY receipts and train records are
|
||||
keyed on origin's GitHub owner/repo, so lanes whose origin uses another URL
|
||||
form (git.capy.ai, ssh, a token URL) share the coordinator's queue.
|
||||
|
||||
@@ -539,7 +541,7 @@ EVAL_POLICY records it. Bisect results never turn a train green.
|
||||
```bash
|
||||
git fetch origin main
|
||||
git merge --no-ff --no-commit origin/main # expect a CHANGELOG.md conflict only
|
||||
bun --no-env-file --config=/dev/null -e "import { mergeChangelogs } from './lib/changelog-check'; import { spawnSync } from 'node:child_process'; import { writeFileSync } from 'node:fs'; const s = (n) => spawnSync('git', ['show', ':' + n + ':CHANGELOG.md'], { encoding: 'utf8', maxBuffer: 1 << 26, timeout: 30000 }).stdout; const m = mergeChangelogs(s(2), s(3), s(1)); if (!m) { console.error('CHANGELOG needs a hand merge'); process.exit(1); } writeFileSync('CHANGELOG.md', m);"
|
||||
bun --no-env-file --config=/dev/null -e "import { mergeChangelogsWithNotes } from './lib/changelog-check'; import { spawnSync } from 'node:child_process'; import { writeFileSync } from 'node:fs'; const s = (n) => spawnSync('git', ['show', ':' + n + ':CHANGELOG.md'], { encoding: 'utf8', maxBuffer: 1 << 26, timeout: 30000 }).stdout; const m = mergeChangelogsWithNotes(s(2), s(3), s(1)); for (const n of m.notes) console.error('CHANGELOG: carried as a Gate integrity correction: ' + n); if (!m.text) { console.error('CHANGELOG needs a hand merge'); process.exit(1); } writeFileSync('CHANGELOG.md', m.text);"
|
||||
git add CHANGELOG.md && git commit --no-edit
|
||||
gstack-restamp --next --base main --pr 42 --expect-base <main sha> --expect-order <order> --allow-repo-commands
|
||||
git add CHANGELOG.md VERSION package.json <release outputs> && git commit -m "v<X> stamp" && git push
|
||||
@@ -547,6 +549,47 @@ git add CHANGELOG.md VERSION package.json <release outputs> && git commit -m "v<
|
||||
|
||||
A conflict in any file other than CHANGELOG.md means the merge isn't the train's prefix. Stop and report it. When the helper says the CHANGELOG needs a hand merge, take main's CHANGELOG unchanged and put your own entry above it. `verify` accepts the resulting head because it contains main and its tree equals T<i> modulo stamps, with its CHANGELOG judged as main's plus lines your pin added, however the conflict was resolved; the `head:` line says "T<i> with main merged in".
|
||||
|
||||
**The stamp commit is the base merge plus the stamp files, never a fifth.** The
|
||||
restamp writes the version files, the CHANGELOG, the `release_outputs` and the
|
||||
`stamp_paths` lines the branch itself added (gstack: `CHANGELOG.md`, `VERSION`,
|
||||
`package.json`, `agents-digest/gstack-AGENTS.md`, and a `*_KEY_VERSION` the PR
|
||||
introduced). A line the base added since the pin's fork point is the base's,
|
||||
whether the base merge is committed or still staged (`stage stamp_paths` says
|
||||
"N line(s) the base added since the fork point are the base's"; train 24,
|
||||
2026-10-27, moved main's `DOCS_CAPS_KEY_VERSION` in both slots before this
|
||||
rule). A file the restamp lists that the slot call did not name is not a stamp:
|
||||
leave it out and report it. The tree receipt refuses such a move after the fact
|
||||
only while the moved version is older than the base's at the build, so the
|
||||
restamp, not the receipt, is what keeps the base's key in place.
|
||||
|
||||
**A stacked child whose parent merged earlier.** When the pin was stacked on a
|
||||
PR that squash-merged in an earlier slot or train, the base merge conflicts
|
||||
beyond the CHANGELOG wherever the parent's squash and the pin touched the same
|
||||
lines. Take the pin's bytes for those files: `verify` checks the tree against
|
||||
T<i>, the train's own merge of that pin, so the parent's content is already in
|
||||
the prefix. The CHANGELOG is `mergeChangelogs`' job and needs no hand merge for
|
||||
this shape: the pin's `[Unreleased]` still holds the parent's entry (as forked,
|
||||
maybe edited) while main carries it under a released heading the merge base
|
||||
lacks, so the parent's lines leave the child's section and each edit the child
|
||||
made to them becomes a `- Correction to the <version> entry below: "<old>"
|
||||
should read "<new>".` bullet under the child's own `### Gate integrity` (the
|
||||
one-liner prints each carried correction). The released entry stays main's byte
|
||||
for byte, and `verify` accepts those bullets as the pin's own lines because
|
||||
the tool writes them. A pin that does not carry base can still be refused here
|
||||
(`ours's Unreleased section holds released <version> text`): that is the
|
||||
GSTA-67 shape, a released heading dropped by hand, and stays a hand merge.
|
||||
|
||||
**A generator change on an unstamped head.** A release output such as
|
||||
`agents-digest/gstack-AGENTS.md` is stamped at the slot, and an unstamped PR
|
||||
changes it the ordinary way, which is to edit the generator, regenerate at the
|
||||
branch's own `VERSION` (its merge base's), and commit both. CI's Version Gate
|
||||
regenerates the output at that VERSION and reads a byte-identical result as
|
||||
unstamped ([what /ship reads](#ship), since 1.91.237.0); the freshness test
|
||||
compares against the checkout's VERSION, so it passes before and after the
|
||||
slot's restamp regenerates the file at the new version. Never revert a
|
||||
regenerated output to the base's bytes to get past the gate (#3434 did, on a
|
||||
gate older than that rule, and shipped a stale digest line until its merge).
|
||||
|
||||
**5. Coordinator: verify, merge, verify again.** For each slot in order:
|
||||
|
||||
```bash
|
||||
@@ -558,15 +601,36 @@ gstack-ship-queue verify --pr 41 --train <nonce> # VERIFY_TRAIN: #41 merged; m
|
||||
Before a merge, main's tree must equal the prefix before the PR modulo stamps
|
||||
and the PR must be at its pin (stamps aside) or contain main and be T<i>
|
||||
modulo stamps (its pin with main merged in; its CHANGELOG must be main's with
|
||||
only lines from the pin's own CHANGELOG diff above it); after it, main's tree
|
||||
must equal the prefix after it. Anything else is `QUEUE_TRAIN_TREE_MISMATCH`
|
||||
(or `QUEUE_TRAIN_MOVED`). When nothing of the train has merged, that is a plain
|
||||
refusal: build a new train on current main. When earlier slots already
|
||||
merged, main holds a prefix no gate covered on its own, so verify freezes the
|
||||
queue: the freeze goes to local state and the notes ref first, then the full
|
||||
gate is dispatched on main's SHA at once (the backstop), and the
|
||||
`QUEUE_TRAIN_FROZEN:` line lists the merged PRs, main's tree and the backstop
|
||||
run. While frozen, ordinary trains and other trains' merges are refused
|
||||
only lines from the pin's own CHANGELOG diff, or lines `mergeChangelogs`
|
||||
writes for that pin against main, above it); after it, main's tree must equal
|
||||
the prefix after it modulo stamps, or differ from it in the CHANGELOG alone
|
||||
while being its own first parent's CHANGELOG (the main the pre-merge verify
|
||||
saw, itself the prefix before modulo stamps) plus the PR's own entry under the
|
||||
same rule. One CHANGELOG rule applies before and after, so a head the pre-merge
|
||||
verify accepted confirms after its squash merge with the same CHANGELOG, and a
|
||||
stacked child whose one `[Unreleased]` became two released sections is not a
|
||||
mismatch (train 24, 2026-10-27, froze on exactly that). Anything else is
|
||||
`QUEUE_TRAIN_TREE_MISMATCH` (or `QUEUE_TRAIN_MOVED`). When nothing of the train
|
||||
has merged, that is a plain refusal, and a new train is built on current main. When
|
||||
earlier slots already merged, main holds a prefix no gate covered on its own,
|
||||
so verify freezes the queue. The freeze goes to local state and the notes ref
|
||||
first, then the full gate is dispatched on main's SHA at once (the backstop),
|
||||
and the `QUEUE_TRAIN_FROZEN:` line lists the merged PRs, main's tree and the
|
||||
backstop run. A slot GitHub reports MERGED counts as merged in that record,
|
||||
verified tree or not, so the rebuild after the repair never seats it again
|
||||
(the reason says "merged on GitHub without a verified tree"); a first slot
|
||||
whose squash GitHub reports MERGED but whose tree fails the post-merge check
|
||||
freezes the same way, since main already holds the unverified squash. The
|
||||
record comes from the one GitHub read that decided to freeze, never a second
|
||||
one: a slot that read MERGED stays merged even when GitHub stops answering
|
||||
before the record is written, and a slot unreadable beside a merged one is
|
||||
left out of `unmerged` and named in the reason; nothing reads it again, so
|
||||
the `NEXT:` after the repair omits it and the operator seats it in a train by
|
||||
hand once `gh pr view` answers. When
|
||||
whether a slot merged on GitHub cannot be read, verify refuses
|
||||
(`QUEUE_PROOF_MISSING`, "whether #<n> merged on GitHub could not be read")
|
||||
and asks to be rerun once `gh pr view` answers; an unreadable state is never
|
||||
"nothing merged". While frozen, ordinary trains and other trains' merges are refused
|
||||
(`QUEUE_TRAIN_FROZEN`). Admit one repair PR at its exact head:
|
||||
|
||||
```bash
|
||||
@@ -884,7 +948,7 @@ Stages, each journaled in `.gstack/tmp/restamp-journal.json`:
|
||||
1. **version**: `gstack-version-bump write --version <X>` in the staging worktree (VERSION, the manifest, npm lockfiles); skipped when `restamp_command` owns the version.
|
||||
2. **release_tool**: the policy command, under the contract below.
|
||||
3. **changelog**: the PR's `[Unreleased]` or old-version section moves to the top under `<X>`, above its predecessor's entry. A duplicate heading the PR introduces (`CHANGELOG_DUPLICATE_HEADING`: the headings are counted against the base's CHANGELOG at `origin/<base>` and at the fork point, so a version the base already heads twice passes as long as the PR adds no further copy) and a top entry that is not `<X>` (`CHANGELOG_TOP_MISMATCH`) are errors; the section being re-headed itself may exist only once.
|
||||
4. **stamp_paths**: exact `(was X)`, `since: X` and `vX` rewrites, plus every `stamp_patterns` template, within `stamp_paths` and `stamp_files`. A quote around X in the first two forms is part of the form and is kept as written: `since: 'X'`, `since: "X"`, `(was 'X')` and `(was "X")` move like the bare ones (the shape of a quoted source row such as gbrain's `{ since: '0.60.468.0', … }`), an opened quote must close right after X (`since: '1.2.3-beta'` and `since: '1.2.3"` are not the form, in the writer and in the tree receipt alike), and `vX` already accepts a quote before the `v`. Which X moves is decided by provenance. The branch's own tentative stamp (its VERSION when it moved past base) and `--was <X>`, when given, are each rewritten on every line of every stamp file. Beyond that, only lines the branch itself added are read, by their position in the file (`git diff --unified=0` from the fork point), so a base line with the same text, or a CRLF checkout whose diff is LF-normalized, is told apart: a stamp-form mention there of a version newer than the version at the branch's fork point is a tentative stamp and moves (this is what finds a quoted row after a lost slot and a merge of the base, since the base's release is newer than the fork point), and when the branch has no stamp of its own because its VERSION equals the base's and its fork point is the base itself (a branch rebased onto the base after it reached X, or one never stamped) a mention of the base version on a line it added is its stale stamp and moves too, while the same version on a line the base already carries is the base's release and stays. The stage detail names both counts per file (`VERSION equals base X, so X moved only on lines this branch added and stayed on the base's own lines (<file>: N moved, M kept)`), so the stamp commit shows which lines moved and why. The rule reads line ownership, not meaning: a branch-added line inside `stamp_paths` that means the base's own release in a stamp form (`Requires vX or later` written on a branch forked at X) moves with it, which the `--dry-run` diff and the per-file counts show before anything is written; write such a reference outside a stamp form, or keep that file out of `stamp_paths`. `--was X` is the opposite tool: it rewrites X everywhere, the base's own lines included, and re-heads the CHANGELOG section `## [X]`. Only the repo's own version width counts, so a 3-digit dependency pin in a 4-digit repo is never a candidate.
|
||||
4. **stamp_paths**: exact `(was X)`, `since: X` and `vX` rewrites, plus every `stamp_patterns` template, within `stamp_paths` and `stamp_files`. A quote around X in the first two forms is part of the form and is kept as written: `since: 'X'`, `since: "X"`, `(was 'X')` and `(was "X")` move like the bare ones (the shape of a quoted source row such as gbrain's `{ since: '0.60.468.0', … }`), an opened quote must close right after X (`since: '1.2.3-beta'` and `since: '1.2.3"` are not the form, in the writer and in the tree receipt alike), and `vX` already accepts a quote before the `v`. Which X moves is decided by provenance. The branch's own tentative stamp (its VERSION when it moved past base) and `--was <X>`, when given, are each rewritten on every line of every stamp file. Beyond that, only lines the branch itself added are read, by their position in the file (`git diff --unified=0` from the fork point), so a base line with the same text, or a CRLF checkout whose diff is LF-normalized, is told apart: a stamp-form mention there of a version newer than the version at the branch's fork point is a tentative stamp and moves (this is what finds a quoted row after a lost slot and a merge of the base, since the base's release is newer than the fork point), and when the branch has no stamp of its own because its VERSION equals the base's and its fork point is the base itself (a branch rebased onto the base after it reached X, or one never stamped) a mention of the base version on a line it added is its stale stamp and moves too, while the same version on a line the base already carries is the base's release and stays. The stage detail names both counts per file (`VERSION equals base X, so X moved only on lines this branch added and stayed on the base's own lines (<file>: N moved, M kept)`), so the stamp commit shows which lines moved and why. A line the base added since the fork point is the base's even when that diff shows it (a merge of the base on the branch, committed or still staged, brings every line the base added since the fork into the diff from the fork point, main's own release keys included): it is left out, the detail says `N line(s) the base added since the fork point are the base's, not this branch's, and stay (<file>: N)`, and a base diff git cannot run refuses the stage (`POLICY_SOURCE_UNAVAILABLE`, `cannot diff <since>..<base> for the stamp_paths stage`) rather than reading as an empty set that would move the base's lines again. The rule reads line ownership, not meaning: a branch-added line inside `stamp_paths` that means the base's own release in a stamp form (`Requires vX or later` written on a branch forked at X) moves with it, which the `--dry-run` diff and the per-file counts show before anything is written; write such a reference outside a stamp form, or keep that file out of `stamp_paths`. `--was X` is the opposite tool: it rewrites X everywhere, the base's own lines included, and re-heads the CHANGELOG section `## [X]`. Only the repo's own version width counts, so a 3-digit dependency pin in a 4-digit repo is never a candidate.
|
||||
5. **mirror**: tier 2; declared and validated, reported as not run.
|
||||
6. **apply**: every changed file is written to the branch only after all stages validated, each against the fingerprinted preimage; a file edited meanwhile is `RESTAMP_CONFLICT` and the applied writes roll back (rollback refuses to overwrite a file whose bytes differ from the recorded postimage).
|
||||
|
||||
|
||||
+30
-6
@@ -2653,7 +2653,11 @@ from the working directory (a bare `bun gstack-pregate`), since a branch could
|
||||
then pick the user policy: run `gstack-pregate` directly or as
|
||||
`bun --no-env-file`. `gstack-ship-queue ready` under a train policy fetches
|
||||
`origin/<base>` first and refuses with this code, quoting git's error, when
|
||||
that fetch fails.
|
||||
that fetch fails. `gstack-restamp`'s `stamp_paths` stage refuses with it when
|
||||
the diff that tells the base's added lines from the branch's own cannot run
|
||||
(`cannot diff <since>..<base> for the stamp_paths stage (<git's first stderr
|
||||
line>); nothing written`), since an empty diff would read as "the base added
|
||||
nothing" and move the base's lines again.
|
||||
|
||||
**Fix.** `git fetch origin <base> --depth=1`, then rerun. To run against the
|
||||
branch's own file deliberately, pass `--policy-from head --allow-repo-commands`;
|
||||
@@ -4089,7 +4093,10 @@ gate-ahead merge could not be recomputed with `git merge-tree`. The train
|
||||
commands use it too: `train forget` on a record that does not exist or on a
|
||||
train still building, running or merging, `train watch` on an unknown record,
|
||||
`verify --pr <n> --screen` on a run with no verdict to read (an INCOMPLETE or
|
||||
unreadable run), and `ready --screen` when the scratch merge branch cannot be
|
||||
unreadable run), `verify --pr <n> --train <nonce>` when main's tree mismatches
|
||||
and whether a slot merged on GitHub cannot be read (so whether the queue must
|
||||
freeze is unknown; it never answers "nothing merged" from an unreadable
|
||||
state), and `ready --screen` when the scratch merge branch cannot be
|
||||
pushed. Nothing was written unless the `QUEUE_STAMP_REFUSED:` line says
|
||||
`committed=yes`.
|
||||
|
||||
@@ -4327,17 +4334,34 @@ the repair merges (a changed train).
|
||||
|
||||
**Meaning.** Main's tree is neither the train's prefix before this PR nor the
|
||||
one after it, modulo stamps, so the merge would not publish what the gate
|
||||
tested.
|
||||
tested. After a merge, a main that differs from the prefix after the PR in
|
||||
the CHANGELOG alone, while being its own first parent's CHANGELOG plus the
|
||||
PR's own entry (the rule the pre-merge verify applied to the head), is not a
|
||||
mismatch ([one CHANGELOG rule, before and after](ship-policy.md#run-a-merge-train)).
|
||||
|
||||
**Fix.** Stop merging. If earlier PRs of the train merged, the queue is now
|
||||
frozen (`QUEUE_TRAIN_FROZEN`); otherwise build a new train on current main.
|
||||
**Fix.** Stop merging. If a PR of the train merged (verified, or reported
|
||||
MERGED by GitHub without a verified tree, slot 1's own squash included), the
|
||||
queue is now frozen (`QUEUE_TRAIN_FROZEN`); otherwise build a new train on
|
||||
current main. When whether a slot merged on GitHub cannot be read, verify
|
||||
refuses with `QUEUE_PROOF_MISSING` instead of either answer; rerun it once
|
||||
`gh pr view` answers.
|
||||
|
||||
<a id="queue-train-frozen"></a>
|
||||
### `QUEUE_TRAIN_FROZEN`
|
||||
|
||||
**Meaning.** A train stopped partway through publication, so main holds a
|
||||
prefix no gate covered on its own. The `QUEUE_TRAIN_FROZEN:` line lists the
|
||||
merged PRs, main's tree and the backstop run dispatched on main's SHA. The
|
||||
merged PRs (a slot GitHub reports MERGED counts as merged, verified tree or
|
||||
not, and the reason then says `merged on GitHub without a verified tree`, so
|
||||
the repair's rebuild never seats it again), main's tree and the backstop run
|
||||
dispatched on main's SHA. The record is built from the one GitHub read that
|
||||
decided to freeze: a slot that read MERGED stays merged even when `gh pr view`
|
||||
stops answering a moment later, and a slot whose state could not be read when
|
||||
another slot had merged is left out of `unmerged` and named in the reason
|
||||
(`#<n> unreadable on GitHub, left out of unmerged; seat it in a train by hand
|
||||
once gh pr view answers`), so the rebuild after the repair never seats a PR
|
||||
that may already be in; nothing reads that slot again, so the `NEXT:` after
|
||||
the repair omits it and the operator seats it by hand. The
|
||||
freeze lives in local state and on `refs/notes/gstack-trains`. Ordinary
|
||||
trains and other trains' merges are refused until a repair lands.
|
||||
|
||||
|
||||
Reference in new issue
Block a user