actions/labels-reconcile — the bootstrap must retire the default GitHub labels it documents
#93
Labels
No labels
attention
blocked
blocker:ci-red
blocker:conflict
blocker:drill-pending
blocker:unrequested
bug
claimed
documentation
enhancement
epic
merge-next
needs-ruling
needs-triage
offsite
post-merge
ready
release
scope:docs
scope:guards
scope:labels
scope:release-flow
stale
state:addressing
state:bots-reviewing
state:building
state:needs-human
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: heavy-duty/ceremony#93
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
LABELS.mdL191-196 states, as fact:Nothing deletes them.
bootstrap_labels()L405-416 walkscore_label_rows()plus the consumer'slabels.confand issues onegh label create --forceper row. It upserts; it never removes.grep -rn 'label delete' actions/ .github/ lib/ bin/returns zero hits across the tree, and #10 — the issue that built the bootstrap — never specified retirement, so this was doctrine that outran its implementation rather than a regression.The proof is live. heavy-duty/incubator adopted the labels automation today (incubator#31 → incubator#32) and its bootstrap dispatch ran green at 20:15Z (run 30041309187): the full core taxonomy plus seven
scope:*rows were created correctly, andgood first issueis still on the repo. It is the first consumer bootstrapped since the family's other repos were cleaned by hand, so it is the first honest read of what the machine actually does. box, rig, cast and ceremony carry no defaults because a human deleted them, not because the bootstrap did.The cost is not cosmetic.
LABELS.mdis vendored doctrine — it ships to every consumer through.ceremony/and is the file an agent reads to learn what the board means. A guarantee stated there and absent from the machinery is the exact drift this repo exists to end, and every future consumer inherits the gap silently: adoption looks green, the board keeps aquestionlabel the taxonomy explicitly rejects.The spec
Retire the six defaults in
bootstrap_labels(), from one registry, tolerating both absence and refusal.retired_label_names()heredoc directly besidecore_label_rows()inlabels-reconcile.sh, carrying exactly the six namesLABELS.mdpublishes. One registry, same file, same reasoncore_label_rows()is not inlabels.conf: a rule that must hold in every governed repo cannot live in a per-repo file.bootstrap_labels(), alongside the upserts. The cron sweep does not delete, for the reason the header comment already gives for not creating: ~20 mutations is too chatty for a 15-minute tick.run(L59-61), soDRY_RUN=1narrates it like every other mutation.gh label deleteexits non-zero when the label does not exist, and the script executes underset -e. An unguarded call therefore aborts the whole dispatch on the second run of every repo — the same shape as #91, where a barereturnon a correct no-op exited 1. Absence is success and is logged at most once per name.blocker:drill-pendingis already on record inLABELS.mdas a row the bot bootstrap 403s on; a delete can 403 the same way. Log the name and continue to the next one — a token that cannot delete must still get the taxonomy it can create.@0.1.0, which predates this fix, exactly like theoffsite,needs-rulingandattentionrows. No consumer's board changes until it bumps and re-dispatches — including incubator's survivinggood first issue, whose actual cleanup is the operator button tracked on #1.LABELS.mdis not edited. Its sentence becomes true; changing it would be the wrong repair of the two.Tasks
retired_label_names()besidecore_label_rows()inactions/labels-reconcile/labels-reconcile.shwith the six names fromLABELS.md.bootstrap_labels()throughrun, after the upsert loop, tolerating a missing label and a refusal without aborting the dispatch.test/labels-reconcile.test.shwith the cases in the test plan below.docs/CONSUMERS.mdneeds no change (the adoption checklist already says defaults are retired; verify and say so in the PR rather than editing on assumption).Acceptance criteria
bootstrap_labels()deletes all six ofduplicate,invalid,question,wontfix,help wanted,good first issue, and no seventh name.labels-reconcile.sh, and matchesLABELS.mdname for name.set -eis live (the #91 lesson: sourcing hides exactly this class of bug).DRY_RUN=1narrates each deletion and performs none.pull_request_targetpaths delete nothing../test/run.shgreen.Test plan
runstubbed to record; assert the six delete calls appear, in the same dispatch as the upserts, and that the recorded upsert set is unchanged from today's.bootstrap_labelsreturns 0 and the remaining deletions still ran. Must fail before the fix's guard is in place.set -eunder execution — invoke the script as a subprocess withGITHUB_EVENT_NAME=workflow_dispatchand aghstub whoselabel deletealways fails; assert exit 0. This is the case a sourced test cannot see.DRY_RUN=1; assert sixDRY_RUN: gh label deletelines and zero real invocations.GITHUB_EVENT_NAME=schedule; assert zero delete calls.Dependencies
None.
Part of #1.Claiming — starting now. Branch
build/93-retire-default-labels, draft PR coming shortly.