mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 22:14:25 +01:00
docs(ship-policy, troubleshooting, harness): train land refusals, resume and required checks; stamped bisect; three-way manifest merges
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
d414d9db24
commit
fa62ea3555
3 files changed
+48
-18
No files matched your search
@@ -129,8 +129,9 @@ A lane (one crew thread, one branch) does this, in order. Every command is
|
||||
harness-generic; only the thread and the PR tool are Capy.
|
||||
|
||||
1. **Branch from the default branch, build, test with focused checks.** Write
|
||||
the CHANGELOG entry under `## [Unreleased]`; leave VERSION at main's value.
|
||||
Never pre-pick a version.
|
||||
the CHANGELOG entry under `## [Unreleased]` (under `changelog_fragments`, a
|
||||
fragment in the policy's fragment directory instead); leave VERSION at
|
||||
main's value. Never pre-pick a version.
|
||||
2. **Push the final head.** Everything below binds to the pushed head; a later
|
||||
push invalidates the receipt, the pregate record and the review binding.
|
||||
3. **Open the PR** with the host's PR tool (Capy: `tools.pr.create`, never
|
||||
@@ -182,6 +183,11 @@ reference:
|
||||
<sha>`, or `--merge` where the repository keeps merge commits), and
|
||||
verifies again. A stamp commit that holds anything beyond the stamp files
|
||||
fails `verify --train`, freezes the queue and costs a backstop gate.
|
||||
Under `changelog_fragments` there is no slot call and no lane stamp: the
|
||||
controller runs `gstack-ship-queue train land --train <nonce> --pr 41` per
|
||||
slot, which pushes the stamped prefix the gate covered, waits for checks,
|
||||
merges and confirms main
|
||||
([ship-policy.md#train-land](ship-policy.md#train-land)).
|
||||
4. `train prune` when every slot has merged.
|
||||
|
||||
**Who merges.** One controller, never the lane. Both crews that ran this
|
||||
@@ -317,7 +323,7 @@ closed) holds the longer history behind these numbers; from here on
|
||||
| Running a workflow | the SKILL.md files, `GSTACK_SESSION_KIND=unattended`, `GSTACK_RESULT:` lines | the `GSTACK_LAUNCH` assignments, `GSTACK_CAPY=1` and the `capy-asks` block, no enforced hooks (safety skills are advisory) |
|
||||
| Approvals | `gstack-approvals`, `gstack-owner-brief render --captain`, the `## Approvals` table | the Captain relay (`needs_you`), the Captain drive `approvals/` mirror |
|
||||
| Pull requests | `/ship`, the ship receipt, `gstack-pr-shots` | `tools.pr.create` (callbacks), `tools.pr.uploadAsset` (before/after images) |
|
||||
| Merging | `gstack-ship-queue` (ready, train build, verdict, verify), `gstack-restamp`, `gh pr merge --match-head-commit` | the controller is a Captain thread; slot calls are thread messages |
|
||||
| Merging | `gstack-ship-queue` (ready, train build, verdict, verify; train land and land under `changelog_fragments`), `gstack-restamp`, `gh pr merge --match-head-commit` | the controller is a Captain thread; slot calls are thread messages |
|
||||
| Flaky pass | the rerun rule, `flake-records-a*` and `flake-ledger-*` artifacts, `test:health` | the daily automation and the ledger in the Captain's Drive |
|
||||
| Release | `release-cut`, `weekly-release.yml`, the `stable` channel | nothing |
|
||||
| Scorecard | `gstack-factory-scorecard`, `/retro` Step 7.5 | nothing (the CSV can be kept in the Captain's Drive) |
|
||||
|
||||
+17
-8
@@ -392,12 +392,18 @@ Slots merge with `train land --train <nonce> --pr <n>`, never a slot call:
|
||||
only that verified chain. main's tree must equal S_(i-1)'s exactly (slot 1:
|
||||
the train base), and the PR's head its pin, with its /ship receipt. main
|
||||
equal to an earlier prefix refuses and names the slot to land first; main
|
||||
equal to a later prefix confirms the slot (a rerun).
|
||||
equal to a later prefix confirms the slot (a rerun). A base that cannot be
|
||||
fetched refuses (`QUEUE_PROOF_MISSING`), a fork head refuses
|
||||
(`QUEUE_TRAIN_UNTRUSTED`), and a PR whose base is no longer the train's
|
||||
base refuses (`QUEUE_NOT_READY`), here and again before the merge.
|
||||
2. It commits S_i's tree with parents [pin, main], adds the
|
||||
`evals-no-debounce` label (a tool-made head gets no later push, so the
|
||||
10-minute quiet window protects nothing), and pushes under
|
||||
`--force-with-lease=<branch>:<pin>`; a foreign push is never overwritten
|
||||
(`QUEUE_TRAIN_MOVED`).
|
||||
(`QUEUE_TRAIN_MOVED`). The stamp commit is deterministic and journaled
|
||||
(`land-<n>.json` beside the train record) before the push, so a rerun
|
||||
adopts its own stamp head instead of reading it as a move. A push that
|
||||
fails while the branch still reads the pin is `QUEUE_NOT_READY`; rerun.
|
||||
3. It waits for the PR's checks on that commit (`--no-wait` prints the
|
||||
command). Required checks run live at the slot until GSTA-156's exact-tree
|
||||
reuse is on main. Every name in `changelog_fragments.required_checks` must
|
||||
@@ -548,9 +554,10 @@ records does not stand; see [the ship receipt](#ship-receipt)),
|
||||
`QUEUE_TRAIN_CONFLICT: train <id> stopped at #<pr> (conflicts: <files>) after
|
||||
merging #<a>,#<b>; nothing dispatched, no branch pushed; fix: …` line names
|
||||
the build without that PR) and `QUEUE_TRAIN_FREE_RED` (free tests red,
|
||||
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
|
||||
missing, cancelled or on another SHA). In a merge, the version file takes the
|
||||
prefix's side, a manifest or npm lockfile conflict merges three-way with the
|
||||
prefix's version (so a pin's dependency edit survives), and the CHANGELOG
|
||||
merges by section, since the stamp at merge rewrites them; 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, except the stacked child whose parent
|
||||
was released since their merge base, which `mergeChangelogs` carries (see *A
|
||||
@@ -585,7 +592,8 @@ gstack-ship-queue train rebuild --train <nonce>
|
||||
```
|
||||
|
||||
The bisect dispatches the red cases (`cases`) on every prefix T0..Tk
|
||||
(`prefix_shas`), one trial each, after checking every prefix is an ancestor
|
||||
(`prefix_shas`; for a [stamped train](#train-land), T0 and S_1..S_k, the
|
||||
chain its gate ran), one trial each, after checking every prefix is an ancestor
|
||||
of `train/<nonce>` (`QUEUE_TRAIN_PREFIX_INVALID`). It reserves every
|
||||
case×prefix trial (unknown costs at `trial_reservation_usd`) and launches only
|
||||
the prefixes that fit the cap (`QUEUE_TRAIN_BISECT_CAPPED`; completed prefixes
|
||||
@@ -1200,7 +1208,7 @@ writes only stamps.
|
||||
|
||||
The command also gets `GSTACK_RESTAMP_BASE_SHA`, the release predecessor: the
|
||||
base branch commit the version is allocated after (origin/<base> for a per-PR
|
||||
restamp and for `land`). A repo counter that must be predecessor + 1 (a
|
||||
restamp and for `land`, S_(i-1) for a [stamped train](#train-land)'s S_i). A repo counter that must be predecessor + 1 (a
|
||||
SAVE_VERSION, a rules number) reads its old value from that commit
|
||||
(`git show "$GSTACK_RESTAMP_BASE_SHA:<file>"`), never from the branch, so two PRs
|
||||
cut from one base never both claim the same number. Regenerated goldens go in
|
||||
@@ -1262,7 +1270,8 @@ valid fragment (a legacy `[Unreleased]`-only entry passes during migration;
|
||||
a `[bot]` author, such as Dependabot, needs none). Other manifest edits, a
|
||||
dependency or a script, pass. A head made by the merge step, a commit whose
|
||||
parents are [pin, base], must carry the base's version plus the effective
|
||||
bump of the fragments its pin adds. Under a train policy `gstack-ship-queue
|
||||
bump of the fragments its pin adds; a stacked pin's parent fragment whose
|
||||
text the base already released is skipped, not counted again. Under a train policy `gstack-ship-queue
|
||||
ready` applies the same rule itself; without one, `ready` requires the head's
|
||||
checks green, Version Gate included.
|
||||
|
||||
|
||||
+22
-7
@@ -4104,12 +4104,18 @@ HEAD is not the PR's pushed head (read through `gh pr view`), CI at that
|
||||
exact head is not green (failed, pending or unreadable), or the pregate result
|
||||
is missing, failed or recorded on another tree (`PREGATE_STALE`). Under
|
||||
`--dispatch-ci` it is also a dispatched workflow run that concluded red (a red
|
||||
run clears no pregate lane) or a `gh workflow run` that failed.
|
||||
run clears no pregate lane) or a `gh workflow run` that failed. `train land`
|
||||
uses it while a slot cannot merge yet: checks on the stamp commit are not
|
||||
green, a name in `changelog_fragments.required_checks` is missing or not green
|
||||
there, the PR's base is no longer the train's base, the stamp push failed while
|
||||
the branch still read the pin, `gh pr merge` refused, or the merge is not yet
|
||||
visible on main.
|
||||
|
||||
**Fix.** Commit and push, wait for CI on that head, rerun
|
||||
`gstack-pregate run --allow-repo-commands` when the tree changed, then rerun
|
||||
`gstack-ship-queue ready --pr <n>`. The block it prints before refusing shows
|
||||
which line is not yet true.
|
||||
which line is not yet true. For `train land`, do what `NEXT:` says, then rerun
|
||||
the same `train land` command; it adopts its own journaled stamp commit.
|
||||
|
||||
<a id="queue-proof-missing"></a>
|
||||
### `QUEUE_PROOF_MISSING`
|
||||
@@ -4125,8 +4131,10 @@ train still building, running or merging, `train watch` on an unknown record,
|
||||
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
|
||||
state), `train land` when the base or the train branch cannot be fetched or
|
||||
the record's T0 and S_1..S_k are not the gated head's first-parent chain
|
||||
(each S_i's second parent slot i's pin), and `ready --screen` when the
|
||||
scratch merge branch cannot be pushed. Nothing was written unless the `QUEUE_STAMP_REFUSED:` line says
|
||||
`committed=yes`.
|
||||
|
||||
**Fix.** Supply the named input (fetch the gated head, pass the current base
|
||||
@@ -4165,7 +4173,9 @@ predecessor PR moved after the gate.
|
||||
**Meaning.** The ship policy sets `full_e2e: true`, and no passing full-gate
|
||||
result is bound to the tree being stamped or verified: no recorded gate-ahead
|
||||
attempt for that gated head, no `--gate-exit 0 --gate-log <file>` from a run
|
||||
on it, or the recorded run exited non-zero.
|
||||
on it, or the recorded run exited non-zero. The train commands use it too: a
|
||||
PR that is not in the train, a train without a green gate, `verify --train` on
|
||||
a stamped train and `train land` on a plain one (each names the other).
|
||||
|
||||
**Fix.** Run the gate the policy's `gate_command` names in the gate-ahead
|
||||
worktree and bind it with `gstack-ship-queue gate-ahead --record`, or pass the
|
||||
@@ -4203,7 +4213,7 @@ a `train` block with `min_gstack_version` on the base branch first
|
||||
**Meaning.** A pinned PR's head repository is not the base repository. The
|
||||
train branch and its dispatches run with repository secrets, so fork work
|
||||
never rides a train. `ready --dispatch-ci` refuses a fork head for the same
|
||||
reason and dispatches nothing.
|
||||
reason and dispatches nothing, and `train land` refuses one and pushes nothing.
|
||||
|
||||
**Fix.** Run the printed `train build --prs <list without it>`; the fork PR
|
||||
stays on the trusted-branch path.
|
||||
@@ -4287,7 +4297,8 @@ and report it.
|
||||
**Meaning.** A PR's head is no longer the SHA the train pinned (at build, or
|
||||
past its pin beyond stamps at verify), so the train would not test what
|
||||
merges. At verify after earlier slots merged, the queue also freezes
|
||||
(`QUEUE_TRAIN_FROZEN`).
|
||||
(`QUEUE_TRAIN_FROZEN`). At `train land` it is a PR head or branch that moved
|
||||
off the pin (or off land's own stamp commit); land never overwrites it.
|
||||
|
||||
**Fix.** Ask the lane for a fresh READY on the new head, then build the train
|
||||
with the new pin (`train build --prs <n>@<new sha>,…`).
|
||||
@@ -4440,6 +4451,10 @@ 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)).
|
||||
For a stamped train, `train land` compares exact trees: main must be S_(i-1)
|
||||
before the merge, must not move during the slot's checks, and must be S_i
|
||||
after it ([stamped trains](ship-policy.md#train-land)); main equal to an
|
||||
earlier prefix refuses without freezing and names the slot to land first.
|
||||
|
||||
**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
|
||||
|
||||
Reference in new issue
Block a user