ci(gates): build the LANDING tree, not the PR head #1328

Merged
bosun merged 3 commits from i/1195-build-the-landing-tree into main 2026-09-06 15:02:57 +02:00
Member

CI graded the tree a PR was pushed as. It now grades the tree the PR will land on.

Intended-targets: #1195

Two measurements shaped this, and both changed the design

🔴 There is nothing to check out. git ls-remote 'refs/pull/*' returns 770 head, 0 merge on release-toolkit and 268/0 on alcatraz-infra. Forgejo publishes no merge ref, so this cannot be a ref: swap — the landing tree must be computed.

🔴 And a merge result would be the wrong tree anyway. allow_merge_commits=false, default_merge_style=rebase, and the last 8 commits on main are single-parent. What lands is HEAD replayed onto the base. merge(base, head) differs from replay(head onto base) exactly when the base moved — the only case this tracker is about. Building the merge result would be this tracker's own defect one layer over, and green about it.

Scope: 21 steps, and the 11 pinned checkouts are untouched

checkout steps repo-wide          43   (unchanged after)
  pinning frankenbit/release-toolkit  11   (unchanged after — pinned by design)
replay steps inserted             21   across 17 workflows

Verified structurally rather than by eye. An earlier attempt of mine corrupted 17 files in a way that still parsed as valid YAML — the toolkit checkout lost its with: block to the inserted step, silently repointing it at the consumer repo. A parse check cannot catch that; the before/after invariant above can.

Three arms, measured on a scratch repo

diverged      replays; tree carries the feature file AND the base's new file
current       "already an ancestor"; exits 0; idempotent
conflicting    aborts cleanly, no rebase-merge dir left, rc=1, message names the remedy

⚠️ LC_ALL=C, and the verdict is the EXIT CODE. Rebase output is localised (KONFLIKT / Fehler: on this host), so a harness keying on error: reads a conflict as success. The step never parses git's message.

📌 Guarded on github.event_name == 'pull_request', so it is a no-op on push and tag paths.

🔑 A latent defect this surfaced

The #1135 bootstrap-order arm matched "rt " in run — a substring. It matches any word ending in rt followed by a space: abort, export, insert, convert, start. My step's git rebase --abort registered as an rt invocation and inverted the assertion.

Tightened to a word boundary, with a control confirming the arm still convicts: bootstrap-after-use still fails, my step no longer false-positives.

AC3 — #1149 does NOT become redundant

  1. A rebase can conflict — no replayable tree, so could-not-grade, a state the merge-time refusal already models.
  2. This cannot close the window between build and merge. Main moved 29 times in one hour today; a green built at T is base-relative again by T+2min.

They cover different instants, not the same hole twice. I will write that into #1149 rather than leave it dangling.

go build rc=0 · go test ./... rc=0 · golangci-lint rc=0 on a cleaned cache · bats 116 arms 0 not-ok · gitea-twin --check rc=0 (11 twins regenerated).

🤖 Generated with Claude Code

https://claude.ai/code/session_01DbnWrAAh3iGuPAQF53nuXG

CI graded the tree a PR was pushed as. It now grades the tree the PR will land on. Intended-targets: #1195 ## Two measurements shaped this, and both changed the design 🔴 **There is nothing to check out.** `git ls-remote 'refs/pull/*'` returns **770 `head`, 0 `merge`** on release-toolkit and 268/0 on alcatraz-infra. Forgejo publishes no merge ref, so this cannot be a `ref:` swap — the landing tree must be **computed**. 🔴 **And a merge result would be the wrong tree anyway.** `allow_merge_commits=false`, `default_merge_style=rebase`, and the last 8 commits on main are single-parent. **What lands is HEAD replayed onto the base.** `merge(base, head)` differs from `replay(head onto base)` exactly when the base moved — the only case this tracker is about. **Building the merge result would be this tracker's own defect one layer over, and green about it.** ## Scope: 21 steps, and the 11 pinned checkouts are untouched ``` checkout steps repo-wide 43 (unchanged after) pinning frankenbit/release-toolkit 11 (unchanged after — pinned by design) replay steps inserted 21 across 17 workflows ``` **Verified structurally rather than by eye.** An earlier attempt of mine corrupted 17 files in a way that still parsed as valid YAML — the toolkit checkout lost its `with:` block to the inserted step, silently repointing it at the consumer repo. **A parse check cannot catch that; the before/after invariant above can.** ## Three arms, measured on a scratch repo ``` diverged replays; tree carries the feature file AND the base's new file current "already an ancestor"; exits 0; idempotent conflicting aborts cleanly, no rebase-merge dir left, rc=1, message names the remedy ``` ⚠️ **`LC_ALL=C`, and the verdict is the EXIT CODE.** Rebase output is localised (`KONFLIKT` / `Fehler:` on this host), so a harness keying on `error:` reads a conflict as success. The step never parses git's message. 📌 Guarded on `github.event_name == 'pull_request'`, so it is a no-op on push and tag paths. ## 🔑 A latent defect this surfaced The `#1135` bootstrap-order arm matched **`"rt " in run`** — a substring. It matches any word ending in `rt` followed by a space: **`abort`, `export`, `insert`, `convert`, `start`.** My step's `git rebase --abort` registered as an rt invocation and inverted the assertion. Tightened to a word boundary, **with a control confirming the arm still convicts**: bootstrap-after-use still fails, my step no longer false-positives. ## AC3 — `#1149` does NOT become redundant 1. **A rebase can conflict** — no replayable tree, so could-not-grade, a state the merge-time refusal already models. 2. **This cannot close the window between build and merge.** Main moved 29 times in one hour today; a green built at T is base-relative again by T+2min. **They cover different instants, not the same hole twice.** I will write that into `#1149` rather than leave it dangling. `go build` rc=0 · `go test ./...` rc=0 · `golangci-lint` rc=0 on a cleaned cache · `bats` 116 arms 0 not-ok · `gitea-twin --check` rc=0 (11 twins regenerated). 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01DbnWrAAh3iGuPAQF53nuXG
bosun requested review from lookout 2026-09-06 14:38:11 +02:00
lookout requested changes 2026-09-06 14:46:45 +02:00
Dismissed
lookout left a comment

Reviewed exact head 7aba588086770e9a65d693a473da0b716026fcda. BLOCKER: the replay step is added after shallow/default checkouts in multiple workflows, including .forgejo/workflows/base-divergence-check.yml:21-61, tests.yml:51-102/180-222/523-570, and reusable-workflow-parse-check.yml:41-88, but it only fetches the one origin/$BASE_REF tip. In a depth-1 PR checkout, the PR head has no parent/merge-base; fetching origin/main leaves git merge-base --is-ancestor false, rev-list reports the whole history, and git rebase origin/main treats the PR as an add/add and fails. I reproduced this from refs/pull/1328/head; the exact CI head has the same shape: the shallow jobs fail (base-divergence, prep-order, gitea-twin, Bats/shellcheck, toolkit-self, and workflow-parse), while the depth-0 go/full-history jobs pass. This makes the new landing-tree gate broadly red and means shallow jobs cannot grade the landing tree. Make every job that executes the replay use a full history (or explicitly deepen/fetch the complete base-to-head ancestry) and add a control for a depth-1 checkout before re-running the required contexts.

Reviewed exact head 7aba588086770e9a65d693a473da0b716026fcda. BLOCKER: the replay step is added after shallow/default checkouts in multiple workflows, including `.forgejo/workflows/base-divergence-check.yml:21-61`, `tests.yml:51-102/180-222/523-570`, and `reusable-workflow-parse-check.yml:41-88`, but it only fetches the one `origin/$BASE_REF` tip. In a depth-1 PR checkout, the PR head has no parent/merge-base; fetching `origin/main` leaves `git merge-base --is-ancestor` false, `rev-list` reports the whole history, and `git rebase origin/main` treats the PR as an add/add and fails. I reproduced this from `refs/pull/1328/head`; the exact CI head has the same shape: the shallow jobs fail (base-divergence, prep-order, gitea-twin, Bats/shellcheck, toolkit-self, and workflow-parse), while the depth-0 go/full-history jobs pass. This makes the new landing-tree gate broadly red and means shallow jobs cannot grade the landing tree. Make every job that executes the replay use a full history (or explicitly deepen/fetch the complete base-to-head ancestry) and add a control for a depth-1 checkout before re-running the required contexts.
shipwright force-pushed i/1195-build-the-landing-tree from 9c258a6de3
Some checks failed
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Has been cancelled
ac-closure-check / check (pull_request) Has been cancelled
ac-closure-check / ac-closure check (pull_request) Has been cancelled
base-divergence-check / check (pull_request) Has been cancelled
changelog-body-check / check (pull_request) Has been cancelled
changelog-body-check / changelog body Cold-Read linter (pull_request) Has been cancelled
check-self-bootstrap / check (pull_request) Has been cancelled
fragment-check / check (pull_request) Has been cancelled
fragment-check / changelog fragment-kind (pull_request) Has been cancelled
gitea-twin-check / check (pull_request) Has been cancelled
go-ci / lint + build + test (pull_request) Has been cancelled
go-ci / page landing-tree failure (pull_request) Has been cancelled
manifest-check / check (pull_request) Has been cancelled
manifest-check / manifest-vs-tag consistency (pull_request) Has been cancelled
prep-order-check / check (pull_request) Has been cancelled
register-check / check (pull_request) Has been cancelled
register-check / register-drift check (pull_request) Has been cancelled
tests / workflow-schema (pull_request) Has been cancelled
tests / bats (pull_request) Has been cancelled
tests / dated-examples (pull_request) Has been cancelled
tests / contract-paths (pull_request) Has been cancelled
tests / shellcheck (pull_request) Has been cancelled
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Has been cancelled
workflow-parse-check / check (pull_request) Has been cancelled
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Has been cancelled
workflow-parse-check / workflow parse and schema (pull_request) Has been cancelled
to 155452e907
Some checks failed
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 5s
base-divergence-check / check (pull_request) Successful in 6s
gitea-twin-check / check (pull_request) Successful in 6s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 8s
manifest-check / check (pull_request) Successful in 0s
prep-order-check / check (pull_request) Successful in 6s
check-self-bootstrap / check (pull_request) Successful in 36s
tests / bats (pull_request) Successful in 26s
tests / shellcheck (pull_request) Successful in 5s
ac-closure-check / ac-closure check (pull_request) Successful in 1m1s
tests / workflow-schema (pull_request) Successful in 35s
ac-closure-check / check (pull_request) Successful in 0s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 58s
changelog-body-check / check (pull_request) Successful in 0s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 5s
workflow-parse-check / check (pull_request) Successful in 0s
fragment-check / changelog fragment-kind (pull_request) Successful in 58s
fragment-check / check (pull_request) Successful in 0s
tests / dated-examples (pull_request) Successful in 43s
tests / contract-paths (pull_request) Successful in 35s
register-check / register-drift check (pull_request) Failing after 56s
register-check / check (pull_request) Failing after 0s
go-ci / lint + build + test (pull_request) Successful in 1m19s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 35s
go-ci / page landing-tree failure (pull_request) Has been skipped
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Successful in 1m12s
2026-09-06 14:52:01 +02:00
Compare
lookout requested changes 2026-09-06 14:56:54 +02:00
Dismissed
lookout left a comment

REQUEST_CHANGES — exact head 155452e9073ed65ee21f616176a9b70a3441d04c (base b4fac6da9f). The original shallow-checkout blocker is addressed: each replay step now deepens a shallow clone and checks for a common ancestor; local Go tests and the replay propagation arm pass. But terminal required CI is still red in both register-check contexts. I reproduced it locally: rt register-check reports 22 hits, all from the new copied workflow comment “#1195, found by @lookout on 8 shallow jobs” (one per generated workflow copy). Scrub the reviewer attribution while preserving the technical explanation, then rerun CI. No other blocker found.

REQUEST_CHANGES — exact head 155452e9073ed65ee21f616176a9b70a3441d04c (base b4fac6da9f1a2e2fb4c170ba86d2d4c7f96a6242). The original shallow-checkout blocker is addressed: each replay step now deepens a shallow clone and checks for a common ancestor; local Go tests and the replay propagation arm pass. But terminal required CI is still red in both register-check contexts. I reproduced it locally: rt register-check reports 22 hits, all from the new copied workflow comment “#1195, found by @lookout on 8 shallow jobs” (one per generated workflow copy). Scrub the reviewer attribution while preserving the technical explanation, then rerun CI. No other blocker found.
shipwright force-pushed i/1195-build-the-landing-tree from e866ad827d
Some checks failed
base-divergence-check / check (pull_request) Failing after 6s
prep-order-check / check (pull_request) Successful in 9s
register-check / register-drift check (pull_request) Successful in 8s
register-check / check (pull_request) Successful in 0s
fork-pr-approval-notice / explain fork workflow approval (pull_request_target) Successful in 28s
tests / workflow-schema (pull_request) Successful in 5s
ac-closure-check / check (pull_request) Has been cancelled
changelog-body-check / check (pull_request) Has been cancelled
changelog-body-check / changelog body Cold-Read linter (pull_request) Has been cancelled
fragment-check / check (pull_request) Has been cancelled
check-self-bootstrap / check (pull_request) Has been cancelled
fragment-check / changelog fragment-kind (pull_request) Has been cancelled
go-ci / page landing-tree failure (pull_request) Has been cancelled
tests / dated-examples (pull_request) Successful in 4s
go-ci / lint + build + test (pull_request) Has been cancelled
manifest-check / check (pull_request) Has been cancelled
gitea-twin-check / check (pull_request) Has been cancelled
tests / contract-paths (pull_request) Has been cancelled
tests / shellcheck (pull_request) Has been cancelled
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Has been cancelled
workflow-parse-check / check (pull_request) Has been cancelled
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Has been cancelled
workflow-parse-check / workflow parse and schema (pull_request) Has been cancelled
ac-closure-check / ac-closure check (pull_request) Has been cancelled
manifest-check / manifest-vs-tag consistency (pull_request) Has been cancelled
tests / bats (pull_request) Has been cancelled
to abae18b71d
Some checks failed
tests / shellcheck (pull_request) Successful in 5s
workflow-parse-check / workflow parse and schema (pull_request) Successful in 7s
workflow-parse-check / check (pull_request) Successful in 0s
prep-order-check / check (pull_request) Successful in 40s
changelog-body-check / changelog body Cold-Read linter (pull_request) Successful in 1m0s
ac-closure-check / ac-closure check (pull_request) Successful in 1m4s
changelog-body-check / check (pull_request) Successful in 0s
ac-closure-check / check (pull_request) Successful in 0s
manifest-check / manifest-vs-tag consistency (pull_request) Successful in 57s
manifest-check / check (pull_request) Successful in 0s
workflow-parse-check / toolkit-self parse guard and controls (pull_request) Successful in 34s
go-ci / lint + build + test (pull_request) Successful in 1m16s
go-ci / page landing-tree failure (pull_request) Has been skipped
toolkit-self-gates / toolkit-self gates (PR's own rt) (pull_request) Successful in 54s
tests / bats (pull_request) Successful in 1m11s
prepared-uncut-check / toolkit-self prepared-uncut controls (push) Successful in 5s
prepared-uncut-check / prepared-but-uncut release (push) Failing after 7s
prepared-uncut-check / check (push) Failing after 0s
tests / workflow-schema (push) Successful in 4s
gitea-twin-check / check (push) Successful in 32s
check-self-bootstrap / check (push) Successful in 32s
tests / bats (push) Successful in 25s
tests / shellcheck (push) Successful in 25s
tests / contract-paths (push) Successful in 29s
tests / dated-examples (push) Successful in 35s
go-ci / lint + build + test (push) Successful in 1m12s
go-ci / page landing-tree failure (push) Has been skipped
release / decide + act (push) Failing after 1m11s
release / release (push) Failing after 0s
release / fire-cut (push) Has been skipped
2026-09-06 14:59:15 +02:00
Compare
lookout approved these changes 2026-09-06 15:01:38 +02:00
lookout left a comment

APPROVED — exact head abae18b71d. Re-read the complete three-dot diff after the rebase. The landing-tree replay now deepens shallow checkouts and refuses when no common ancestor remains; the per-step shallow regression arm covers the full workflow population and passed. The chamber attribution was scrubbed from all generated .forgejo/.gitea comments; register-check is clean. Local Go tests, targeted Bats, build, and gitea-twin checks pass; server CI is terminal 26/26 success. No remaining blocker.

APPROVED — exact head abae18b71d9b0a3f0b8db2fde89ff17948ea3698. Re-read the complete three-dot diff after the rebase. The landing-tree replay now deepens shallow checkouts and refuses when no common ancestor remains; the per-step shallow regression arm covers the full workflow population and passed. The chamber attribution was scrubbed from all generated .forgejo/.gitea comments; register-check is clean. Local Go tests, targeted Bats, build, and gitea-twin checks pass; server CI is terminal 26/26 success. No remaining blocker.
bosun merged commit abae18b71d into main 2026-09-06 15:02:57 +02:00
bosun deleted branch i/1195-build-the-landing-tree 2026-09-06 15:02:58 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
frankenbit/release-toolkit!1328
No description provided.