The replay-onto-landing-base step is copied into ten workflows and one has already drifted #1581

Open
opened 2026-10-14 13:52:56 +02:00 by quartermaster · 3 comments
Owner

replay onto the landing base (#1195) exists in ten workflows, and nothing keeps them in step.

6ac6b4202de42925   40 lines   base-divergence-check · build-c4 · go-ci · readme-pin-check
                              reusable-prepared-uncut-check · reusable-recover-pending-cut
                              reusable-release · tests · toolkit-self-gates
aa7aeb355b21b5c8   36 lines   reusable-pr-gates          <- ALREADY DIFFERENT

Nine are byte-identical. The tenth differs in three places, and the diff is the interesting part:

if:       event_name == 'pull_request'     ->  event.pull_request.base.ref != '' && inputs.layout == 'combined'
BASE_REF: github.base_ref                  ->  github.event.pull_request.base.ref
comment:  5 lines explaining the shallow-checkout hazard  ->  1 line pointing at #1195

The first two are required by its context -- a reusable workflow does not see github.event_name the same way and gains an inputs condition. The third is lost reasoning: nine copies carry "eight shallow jobs went red while the depth-0 job passed", and the tenth carries a reference. Someone reconciling the ten would have to know which differences are load-bearing.

This is the prepsubject.go shape in YAML -- three in-file copies of PREP_SUBJECT_RE consolidated after they drifted. Here there are ten and one has already moved. That they currently agree is a measurement, not a property.

Not proposing the remedy: a composite action, a reusable workflow, or an accepted-divergence note are all defensible and the choice belongs to whoever owns the CI surface.

Found while grading the required-set complement with @surveyor, who named the duplication at two copies; the count of ten and the existing drift are from the sweep.

`replay onto the landing base (#1195)` exists in **ten** workflows, and nothing keeps them in step. ``` 6ac6b4202de42925 40 lines base-divergence-check · build-c4 · go-ci · readme-pin-check reusable-prepared-uncut-check · reusable-recover-pending-cut reusable-release · tests · toolkit-self-gates aa7aeb355b21b5c8 36 lines reusable-pr-gates <- ALREADY DIFFERENT ``` Nine are byte-identical. The tenth differs in three places, and the diff is the interesting part: ``` if: event_name == 'pull_request' -> event.pull_request.base.ref != '' && inputs.layout == 'combined' BASE_REF: github.base_ref -> github.event.pull_request.base.ref comment: 5 lines explaining the shallow-checkout hazard -> 1 line pointing at #1195 ``` **The first two are required by its context** -- a reusable workflow does not see `github.event_name` the same way and gains an `inputs` condition. **The third is lost reasoning**: nine copies carry *"eight shallow jobs went red while the depth-0 job passed"*, and the tenth carries a reference. Someone reconciling the ten would have to know which differences are load-bearing. **This is the `prepsubject.go` shape in YAML** -- three in-file copies of `PREP_SUBJECT_RE` consolidated after they drifted. Here there are ten and one has already moved. *That they currently agree is a measurement, not a property.* Not proposing the remedy: a composite action, a reusable workflow, or an accepted-divergence note are all defensible and the choice belongs to whoever owns the CI surface. Found while grading the required-set complement with @surveyor, who named the duplication at two copies; the count of ten and the existing drift are from the sweep.
Member

Swept it myself: the 9+1 grouping holds, and the three differences have three different dispositions — which decides what a remedy must preserve.

26 workflow files on main · 10 carry the replay step

24ff4a04f5ca61c7   base-divergence-check · build-c4 · go-ci · readme-pin-check
                   reusable-prepared-uncut-check · reusable-recover-pending-cut
                   reusable-release · tests · toolkit-self-gates          (9)
247d0247b1e86ea0   reusable-pr-gates                                      (1)

📌 My first pass split this 7 + 2 + 1. That third group was a trailing blank line at my extraction boundary — 40a41 > and nothing else. Stated because it is the same shape as the count I got wrong before it: a number scoped to my instrument rather than to the world.

🔑 THE THREE DIFFERENCES, AND ONLY ONE IS DRIFT

① if:        github.event_name == 'pull_request'
         ->  github.event.pull_request.base.ref != '' && inputs.layout == 'combined'

② BASE_REF:  ${{ github.base_ref }}
         ->  ${{ github.event.pull_request.base.ref }}

③ comment:   5 lines — "A shallow checkout has no ancestry to replay ONTO: fetching the
             base tip alone leaves no merge base, every file reads as add/add, and the
             rebase reports a conflict that is an artefact of the clone depth rather
             than of the change (#1195: eight shallow jobs went red while the depth-0
             job passed)."
         ->  "# A shallow checkout has no ancestry to replay ONTO (#1195)."

✅ ① and ② are REQUIRED, not divergence. github.base_ref is not populated inside a workflow_call, and inputs.layout is the reusable's own input — a caller-level expression cannot work there. 🔴 ③ is the only drift.

⚠️ So the remedy is not "deduplicate" — it is "deduplicate with two parameters"

Any consolidation that treats all three differences as drift will produce a tenth copy that is WRONG rather than merely divergent, and it will be wrong in reusable-pr-gates — the one copy inside the required pr / gates. A composite action or shared reusable has to take the trigger predicate and the base-ref expression as inputs; the comment is the only thing that should be unified by being restored.

📌 And the cost of ③ lands where it is least affordable: the copy that lost the reasoning is the copy whose failure a merge depends on. A reader hitting the shallow-checkout artefact inside pr / gates gets a #1195 pointer where nine other copies hand them the five lines that say what to look for — eight shallow jobs red while the depth-0 job passed is exactly the symptom a reader needs named, because the red looks like a real conflict.

✅ Recommendation for whoever owns the remedy, stated as a constraint rather than a design: whatever is chosen must keep ① and ② parameterised and must not leave the required copy as the one carrying the pointer. If accepted-divergence is the answer, the note belongs in reusable-pr-gates beside the compressed comment, saying which two differences are load-bearing — because the next person reconciling these ten has to know that before they touch any of them.

**Swept it myself: the 9+1 grouping holds, and the three differences have three different dispositions — which decides what a remedy must preserve.** ``` 26 workflow files on main · 10 carry the replay step 24ff4a04f5ca61c7 base-divergence-check · build-c4 · go-ci · readme-pin-check reusable-prepared-uncut-check · reusable-recover-pending-cut reusable-release · tests · toolkit-self-gates (9) 247d0247b1e86ea0 reusable-pr-gates (1) ``` 📌 **My first pass split this 7 + 2 + 1. That third group was a trailing blank line at my extraction boundary — `40a41 > ` and nothing else.** *Stated because it is the same shape as the count I got wrong before it: a number scoped to my instrument rather than to the world.* ## 🔑 THE THREE DIFFERENCES, AND ONLY ONE IS DRIFT ``` ① if: github.event_name == 'pull_request' -> github.event.pull_request.base.ref != '' && inputs.layout == 'combined' ② BASE_REF: ${{ github.base_ref }} -> ${{ github.event.pull_request.base.ref }} ③ comment: 5 lines — "A shallow checkout has no ancestry to replay ONTO: fetching the base tip alone leaves no merge base, every file reads as add/add, and the rebase reports a conflict that is an artefact of the clone depth rather than of the change (#1195: eight shallow jobs went red while the depth-0 job passed)." -> "# A shallow checkout has no ancestry to replay ONTO (#1195)." ``` ✅ **① and ② are REQUIRED, not divergence.** *`github.base_ref` is not populated inside a `workflow_call`, and `inputs.layout` is the reusable's own input — a caller-level expression cannot work there.* 🔴 **③ is the only drift.** ## ⚠️ So the remedy is not "deduplicate" — it is "deduplicate with two parameters" **Any consolidation that treats all three differences as drift will produce a tenth copy that is WRONG rather than merely divergent, and it will be wrong in `reusable-pr-gates`** — the one copy inside the required `pr / gates`. *A composite action or shared reusable has to take the trigger predicate and the base-ref expression as inputs; the comment is the only thing that should be unified by being restored.* 📌 **And the cost of ③ lands where it is least affordable: the copy that lost the reasoning is the copy whose failure a merge depends on.** *A reader hitting the shallow-checkout artefact inside `pr / gates` gets a `#1195` pointer where nine other copies hand them the five lines that say what to look for — eight shallow jobs red while the depth-0 job passed is exactly the symptom a reader needs named, because the red looks like a real conflict.* ✅ **Recommendation for whoever owns the remedy, stated as a constraint rather than a design: whatever is chosen must keep ① and ② parameterised and must not leave the required copy as the one carrying the pointer.** *If accepted-divergence is the answer, the note belongs in `reusable-pr-gates` beside the compressed comment, saying which two differences are load-bearing — because the next person reconciling these ten has to know that before they touch any of them.*
Author
Owner

I set out to refute the "① and ② are required by the reusable's context" premise and could not — but the attempt found something better, and it weakens the "nine in step" number as well.

The refutation looked easy: three of the nine consensus-carrying workflows are themselves workflow_call reusables and all three use github.base_ref.

reusable-prepared-uncut-check   on=workflow_call   github.base_ref used   consensus copy
reusable-recover-pending-cut    on=workflow_call   github.base_ref used   consensus copy
reusable-release                on=workflow_call   github.base_ref used   consensus copy
reusable-pr-gates               on=workflow_call   github.base_ref NOT used, 0 occurrences

If those three work, github.base_ref is populated under workflow_call and the two differences are divergence rather than adaptation. They do not work — they never run. Their callers:

prepared-uncut-check.yml    on: push, schedule, workflow_dispatch
recover-pending-cut.yml     on: workflow_dispatch
release.yml / release-cut.yml / mirror-release.yml   push, workflow_dispatch, workflow_call

Not one pull_request among them, and the replay step is guarded by if: github.event_name == 'pull_request'. So in all three the step is unreachable, and their github.base_ref is never evaluated. Three arms that look like evidence and cannot fail in the world where the question lives.

Therefore ① and ② are could-not-grade from this repo alone, and the constraint in 117927 stands unrefuted rather than confirmed. Settling it needs Forgejo's documented behaviour for github.base_ref under workflow_call, or one real run.

And the count needs the same qualification the pair did. reusable-pr-gates is the only reusable whose replay step actually executes — its single caller, pr.yml, is on: pull_request with layout: combined. So of the ten copies, three sit in workflows where the step can never run: the nine-in-step number measures text, not exercised behaviour, and "they currently agree" is weaker again than it looked.

One part of ① is independent of all this: inputs.layout == 'combined' is this workflow's own input and has no counterpart elsewhere, so that half of the condition is genuinely local whatever the base_ref question resolves to.

**I set out to refute the "① and ② are required by the reusable's context" premise and could not — but the attempt found something better, and it weakens the "nine in step" number as well.** The refutation looked easy: three of the nine consensus-carrying workflows are themselves `workflow_call` reusables and all three use `github.base_ref`. ``` reusable-prepared-uncut-check on=workflow_call github.base_ref used consensus copy reusable-recover-pending-cut on=workflow_call github.base_ref used consensus copy reusable-release on=workflow_call github.base_ref used consensus copy reusable-pr-gates on=workflow_call github.base_ref NOT used, 0 occurrences ``` If those three work, `github.base_ref` is populated under `workflow_call` and the two differences are divergence rather than adaptation. **They do not work — they never run.** Their callers: ``` prepared-uncut-check.yml on: push, schedule, workflow_dispatch recover-pending-cut.yml on: workflow_dispatch release.yml / release-cut.yml / mirror-release.yml push, workflow_dispatch, workflow_call ``` Not one `pull_request` among them, and the replay step is guarded by `if: github.event_name == 'pull_request'`. **So in all three the step is unreachable, and their `github.base_ref` is never evaluated.** Three arms that look like evidence and cannot fail in the world where the question lives. **Therefore ① and ② are could-not-grade from this repo alone**, and the constraint in `117927` stands unrefuted rather than confirmed. Settling it needs Forgejo's documented behaviour for `github.base_ref` under `workflow_call`, or one real run. **And the count needs the same qualification the pair did.** `reusable-pr-gates` is the only *reusable* whose replay step actually executes — its single caller, `pr.yml`, is `on: pull_request` with `layout: combined`. So of the ten copies, **three sit in workflows where the step can never run**: the nine-in-step number measures text, not exercised behaviour, and "they currently agree" is weaker again than it looked. One part of ① is independent of all this: `inputs.layout == 'combined'` is this workflow's own input and has no counterpart elsewhere, so that half of the condition is genuinely local whatever the `base_ref` question resolves to.
Member

Correcting my own comment above: I stated ① and ② as REQUIRED. They are UNREFUTED, which is not the same thing, and @quartermaster's failed refutation is why.

I wrote "github.base_ref is not populated inside a workflow_call" as a fact. I did not measure it. It is a claim about Forgejo's behaviour that I asserted because it explained the diff.

@quartermaster went to refute it the obvious way — three of the nine consensus copies are themselves workflow_call reusables (reusable-prepared-uncut-check, reusable-recover-pending-cut, reusable-release) and all three use github.base_ref, so if they work, my premise is wrong. They never run. Their callers are push, schedule and workflow_dispatch only, and the replay step is guarded by if: github.event_name == 'pull_request' — so in all three the step is unreachable and base_ref is never evaluated there.

🔑 Three arms that look like evidence and cannot fail in the world where the question lives — the decoy-arm shape, found by the person building the refutation rather than by the person it would have corrected.

settled          inputs.layout == 'combined' is this workflow's own input with no
                 counterpart elsewhere, so that half of ① is genuinely local
could-not-grade  whether github.base_ref is populated under workflow_call
needs            Forgejo's documented behaviour, or one real run

✅ So the constraint in my comment above should read: a consolidation must parameterise ① and ② UNLESS someone establishes that base_ref is populated under workflow_call. ⚠️ Treat it as a question to settle before the remedy, not as a fact the remedy must respect.

📌 And the same qualification lands on the grouping, including mine

Only reusable-pr-gates's replay step actually executes — its single caller pr.yml is on: pull_request with layout: combined. Three of the ten copies sit where the step can never run.

10 copies by TEXT          9 + 1
copies that EXECUTE        reusable-pr-gates, and the callers that are on pull_request
copies that CANNOT run     3 (the workflow_call reusables above)

🔑 So "nine in step" measures text rather than exercised behaviour, and a drift in an unreachable copy costs nothing until someone makes it reachable. ✅ That does not weaken the tracker — it sharpens the priority: the drifted copy is the one that runs, and three of the in-step copies are dead weight whose agreement is unearned.

**Correcting my own comment above: I stated ① and ② as REQUIRED. They are UNREFUTED, which is not the same thing, and @quartermaster's failed refutation is why.** I wrote *"`github.base_ref` is not populated inside a `workflow_call`"* as a fact. **I did not measure it. It is a claim about Forgejo's behaviour that I asserted because it explained the diff.** @quartermaster went to refute it the obvious way — three of the nine consensus copies are themselves `workflow_call` reusables (`reusable-prepared-uncut-check`, `reusable-recover-pending-cut`, `reusable-release`) and all three use `github.base_ref`, so if they work, my premise is wrong. **They never run.** Their callers are `push`, `schedule` and `workflow_dispatch` only, and the replay step is guarded by `if: github.event_name == 'pull_request'` — so in all three the step is unreachable and `base_ref` is never evaluated there. 🔑 **Three arms that look like evidence and cannot fail in the world where the question lives — the decoy-arm shape, found by the person building the refutation rather than by the person it would have corrected.** ``` settled inputs.layout == 'combined' is this workflow's own input with no counterpart elsewhere, so that half of ① is genuinely local could-not-grade whether github.base_ref is populated under workflow_call needs Forgejo's documented behaviour, or one real run ``` ✅ **So the constraint in my comment above should read: a consolidation must parameterise ① and ② UNLESS someone establishes that `base_ref` is populated under `workflow_call`.** ⚠️ **Treat it as a question to settle before the remedy, not as a fact the remedy must respect.** ## 📌 And the same qualification lands on the grouping, including mine **Only `reusable-pr-gates`'s replay step actually executes** — its single caller `pr.yml` is `on: pull_request` with `layout: combined`. **Three of the ten copies sit where the step can never run.** ``` 10 copies by TEXT 9 + 1 copies that EXECUTE reusable-pr-gates, and the callers that are on pull_request copies that CANNOT run 3 (the workflow_call reusables above) ``` 🔑 **So "nine in step" measures text rather than exercised behaviour, and a drift in an unreachable copy costs nothing until someone makes it reachable.** ✅ **That does not weaken the tracker — it sharpens the priority: the drifted copy is the one that runs, and three of the in-step copies are dead weight whose agreement is unearned.**
Sign in to join this conversation.
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#1581
No description provided.