diff --git a/.github/workflows/labels-sweep.yml b/.github/workflows/labels-sweep.yml index 760590b..705f4bf 100644 --- a/.github/workflows/labels-sweep.yml +++ b/.github/workflows/labels-sweep.yml @@ -37,12 +37,13 @@ on: bootstrap: description: >- Bootstrap the label taxonomy before sweeping. The CALLER passes - this through from its own workflow_dispatch input; a called - workflow cannot read the caller's dispatch inputs on every forge - (Forgejo drops them at the workflow_call boundary — ceremony#215, - probe runs 6/7 vs merged runs 459/523), so the value must arrive - through this declared boundary, never via github.event.inputs. - Absent means "no": an event- or cron-woken sweep must never + this through from its own workflow_dispatch input. The measured + invariant (ceremony#215): the value must be DECLARED here and + EXPLICITLY passed — on this instance the called workflow did not + see the caller's event inputs as an implicit substitute (runs + 459/523 bootstrapped on a bootstrap=no dispatch) while the + top-level caller received the value in both contexts (probe runs + 6/7). Absent means "no": an event- or cron-woken sweep must never re-upsert ~20 labels. type: string required: false @@ -101,14 +102,14 @@ jobs: # # bootstrap: read from the DECLARED workflow_call input and nothing # else. The old gate read `github.event.inputs.bootstrap` from inside - # this called workflow — which Forgejo leaves empty at the - # workflow_call boundary even though the top-level caller receives the - # value in both contexts (ceremony#215; probe runs 6/7 measured the - # boundary, merged runs 459/523 paid for it: every dispatch-woken - # sweep bootstrapped). The caller passes the value through - # `with.bootstrap`; anything not exactly "yes" is fed through for - # labels-reconcile's own yes|no validation to judge, so a typo refuses - # loudly instead of silently bootstrapping. + # this called workflow, and on this instance that context arrived + # empty (runs 459/523: every dispatch-woken sweep bootstrapped on a + # bootstrap=no body) while the top-level caller received the value in + # both contexts (probe runs 6/7) — ceremony#215. The reliable channel + # is declare-and-pass, so that is the only one used. The caller passes + # the value through `with.bootstrap`; anything not exactly yes|no is + # fed through for labels-reconcile's own validation to judge, so a + # typo refuses loudly instead of silently bootstrapping. - name: reconcile state + stale if: github.repository != 'heavy-duty/ceremony' uses: ./.ceremony-src/actions/labels-reconcile diff --git a/.github/workflows/self-labels-sweep.yml b/.github/workflows/self-labels-sweep.yml index e2dcca3..b929cb5 100644 --- a/.github/workflows/self-labels-sweep.yml +++ b/.github/workflows/self-labels-sweep.yml @@ -45,9 +45,10 @@ jobs: # named `labels` (self-labels.yml). uses: ./.github/workflows/labels-sweep.yml with: - # The dispatch input crosses the workflow_call boundary HERE, or not at - # all: the called workflow cannot read this caller's dispatch inputs on - # this forge (ceremony#215). On `schedule` the top-level context is + # The dispatch input crosses the workflow_call boundary HERE, or not + # at all: on this instance the called workflow did not see this + # caller's event inputs implicitly (ceremony#215), so declare-and-pass + # is the only channel used. On `schedule` the top-level context is # empty, and empty maps to "no" EXPLICITLY — a cron that bootstraps is # the failure kimi named before it could exist. bootstrap: ${{ inputs.bootstrap || 'no' }} diff --git a/changelog.d/215.md b/changelog.d/215.md index f89ef00..9411adf 100644 --- a/changelog.d/215.md +++ b/changelog.d/215.md @@ -1,8 +1,9 @@ ### Fixed - The sweep's `bootstrap` value crosses the `workflow_call` boundary as a - declared input passed by the caller — a called workflow cannot read the - caller's dispatch inputs on this forge (#215). + declared input, explicitly passed by the caller — the one channel measured + to work; the called workflow did not see the caller's event inputs as an + implicit substitute on this instance (#215). - Before the bridge, `github.event.inputs` was empty inside the called workflow, so every dispatch-woken sweep bootstrapped: ~20 label upserts on diff --git a/docs/CONSUMERS.md b/docs/CONSUMERS.md index e5153f6..9afc321 100644 --- a/docs/CONSUMERS.md +++ b/docs/CONSUMERS.md @@ -459,10 +459,11 @@ jobs: sweep: uses: heavy-duty/ceremony/.github/workflows/labels-sweep.yml@ with: - # Pass the dispatch input through the workflow_call boundary — the - # called workflow cannot read this caller's dispatch inputs on every - # forge (ceremony#215). Empty (schedule) maps to "no" explicitly, so a - # cron-woken sweep never re-upserts the taxonomy. + # Pass the dispatch input through the workflow_call boundary + # explicitly — a called workflow must not rely on reading the caller's + # event inputs (ceremony#215 measured that failing). Empty (schedule) + # maps to "no" explicitly, so a cron-woken sweep never re-upserts the + # taxonomy. bootstrap: ${{ inputs.bootstrap || 'no' }} # If this repo's PR-facing labels caller is named anything but `labels`, # pass that name alongside: `pr_workflow_name: `. The sweep exports