docs: spell out crew's four-edit migration; fold in crew#250 field facts (#209)

crew#250 verified two facts the design prose now carries: a queue-
displaced run is not independently rerunnable (gh run rerun / --failed /
--job all refuse), so a victim PR had no manual escape hatch; and the
displacing burst is deterministic — one review_requested event per
panelist per request — so displacement is the steady state of a working
fleet, scaling with panel size, not a traffic spike.

CONSUMERS.md now walks the adoption as one atomic four-edit PR with crew
as the worked example: the pin bump in every ceremony uses: reference,
the new labels-sweep.yml caller, the cron RELOCATED (bold warning: a
copied-not-moved schedule double-fires sweeps into the one shared group
and reads as the bug getting worse after the fix), and actions: write
replacing the labels caller's actions: read.

Refs #209

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
dan-claude-bot 2026-08-01 17:25:26 +00:00
parent 45aa806207
commit be660358f2
3 changed files with 46 additions and 9 deletions

View file

@ -12,8 +12,13 @@ name: labels-sweep
# one-running-plus-one-pending queue records every extra run as CANCELLED.
# That displacement is semantically lossless — the surviving sweep does the
# displaced run's work — but while the sweep rode pull_request_target runs
# the ❌ landed on that PR's checks and read as red CI. Here a displaced
# run attaches to no PR: the cancellations live on the Actions tab only.
# the ❌ landed on that PR's checks and read as red CI, with no manual
# escape hatch: GitHub refuses to rerun a queue-displaced run (crew#250).
# And displacement is the steady state of a working fleet, not a spike —
# one panel request emits one review_requested event per reviewer, so
# every review round over-fills the one-running-plus-one-pending queue.
# Here a displaced run attaches to no PR: the cancellations live on the
# Actions tab only.
#
# Bootstrap semantics: a manual dispatch of the caller bootstraps the
# taxonomy (its `bootstrap` input defaults to "yes"), exactly what

View file

@ -12,7 +12,12 @@ name: labels
# The reconcile sweep lived here until #209. Riding the PR-triggered run
# meant every displacement in the sweep's shared concurrency queue recorded
# a CANCELLED `reconcile` check on some PR — read as red CI by every human
# and agent, though the surviving sweep does the displaced run's work. The
# and agent, though the surviving sweep does the displaced run's work. Two
# field facts made that untenable (crew#250): a displaced run cannot be
# rerun — `gh run rerun`, `--failed`, and `--job` all refuse — so a victim
# PR has no manual escape hatch; and the displacing burst is deterministic,
# one `review_requested` event per panelist per request, so every review
# round displaces runs and the rate scales with panel size. The
# sweep now lives in labels-sweep.yml behind its own caller, and the
# trigger job below is its wake: it fires on every event this caller
# subscribes — the exact surface that used to run reconcile directly — so

View file

@ -289,7 +289,9 @@ together at the same pin:
one shared concurrency group, and GitHub records every queue-displaced
run as CANCELLED — harmless (the surviving sweep does its work) until it
rode a `pull_request_target` run and the ❌ landed on that PR's checks
as fake red CI. Behind its own caller, a displaced sweep cancels on the
as fake red CI that GitHub refuses to rerun (crew#250: `gh run rerun`
and its `--failed`/`--job` forms all decline a queue-displaced run).
Behind its own caller, a displaced sweep cancels on the
Actions tab, attached to no PR; PR checks show `scope` and the green
`trigger` only.
@ -437,11 +439,36 @@ the stub and ceremony's own caller stay byte-for-byte identical, the parity
The two-caller split (ceremony#209) is **unreleased**. A consumer pinned to
`0.4.0` or earlier keeps the previous single-caller shape — the labels
caller carrying the cron, `workflow_dispatch`, and `actions: read` — and
adopts the split at the pin bump to the first tag carrying ceremony#209,
as one atomic PR: the pin, the reshaped labels caller (cron and dispatch
removed, `actions: write` added), and the new sweep caller file. Never mix
refs to adopt it early, and never bump without the sweep caller — that is
the red-trigger failure mode above.
adopts the split at the pin bump to the first tag carrying ceremony#209.
Never mix refs to adopt it early.
The migration is **one atomic PR** with exactly four edits — crew, the
consumer whose displaced-check evidence drove #209 (crew#227, crew#250),
is the worked example; written here against `0.4.1` as the illustrative
first tag carrying the split:
1. **Pin bump, every reference together** ([Version pinning](#version-pinning)):
`0.4.0``0.4.1` in the labels caller's `uses:` line **and in every
other ceremony `uses:` in the repo** — crew also pins in
`release.yml` and its `ci.yml` guard steps. A repo on the doctrine
mirror re-runs `docs-sync --fix` in the same PR.
2. **New file `.github/workflows/labels-sweep.yml`** — the sweep caller
stub above, verbatim, `bootstrap` input included (the trigger's
`-f bootstrap=no` dispatch is refused if the input is undeclared).
3. **The hourly cron RELOCATES — it is moved, never copied.** Delete the
`schedule:` block (and the bare `workflow_dispatch:`) from the labels
caller in the same edit that adds the sweep caller.
**Warning**: a consumer that copies the sweep caller and leaves the
old schedule on the labels caller gets DOUBLE sweeps — every cron tick
fires both callers into the one shared `labels-reconcile` group — so
displacement goes **up**, and the fix reads as the bug getting worse.
4. **`actions: write` on the labels caller** — consumers carry
`actions: read` today (crew does); the trigger job's `gh workflow run`
is a write. The sweep caller keeps `actions: read`.
Bump without the sweep caller and the trigger job goes red on every PR
and issue event — the loud failure mode above — so never split these
four edits across PRs.
`pull_request_target` is intentional: fork PRs need the base repository's
token to write labels. The reusable workflows execute no PR code. They check