LABELS.md — delete the scope table; the per-repo set lives in labels.conf and the repo's CONTRIBUTING #104
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#104
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.mdL170-L182says the scope set is per-repo — and then prints ceremony's own four rows under
the heading "This repo's set:". That file is in
docs/VENDORED.txt,so it is mirrored byte-identically into every consumer's
.ceremony/. In fourrepos that sentence names four labels the repo does not have.
gh label liston each, 2026-07-24:scope:labels it actually has.ceremony/LABELS.mdthat exist thererelease-flowguardslabelsdocsbootstrapusersrunnercoolifydbinstallerdrillplatformdocscliinstallerhosttiersdrilltemplatesapplycapturefleetsecretscoolify-apimanifestcoreadminintakedeploylandinguidocsFourteen of sixteen rows are false, in the file whose whole job is to stop
labels lying. This is not drift. All four mirrors are the same blob,
correctly synced to
0.1.0;docs-sync --checkis green and right. The pinnedtext is what is wrong, and the scope section is the one place in
LABELS.mdwhere byte-identity and truth cannot both hold — every other line in the file is
true everywhere, which is exactly why the mirror contract works.
Doctrine already assigns this fact elsewhere, one file over
(
AGENTS.mdL44-L49):What it has already cost, both on rig's board:
spelling
scope:labelson the grounds that "ceremony's set already carriesscope:labels… one spelling across the family beats a locally prettier one"— sound reasoning, read off rig's own vendored mirror, which presents
ceremony's set as rig's. Right answer, wrong evidence.
.ceremony/LABELS.md'sscope table if it enumerates rig's set — check first". The question exists
only because the file claims to enumerate rig's set. The answer is that a
mirror is machine-written and is never hand-edited; D5 below settles it so
nobody checks again.
From discussion #103.
Spec
Decisions, made here so the builder makes none:
scope:*rows and the"This repo's set:" sentence from
LABELS.md. The section keeps itsdoctrine, which is true in every repo: scopes are per-repo, they all share
the one calm colour
#C5DEF5, PRs get theirs from changed paths viaactions/labeler, issues get theirs from triage. In place of the table itnames the two places that are true wherever the reader is standing —
.github/labels.conf(the definitions, already carryingname|color|descriptionper row) and that repo'sCONTRIBUTING.md.CONTRIBUTING.mdas a pointersentence, not as a second table.
labels.confalready holds the same fourrows with the same descriptions, and
CONTRIBUTING.md L136
already tells every consumer that its scope set is
.github/labels.conf+.github/labeler.yml. Copying the rows into prosewould recreate, in ceremony, the exact duplicate this issue removes — one
more thing to keep in step, kept honest by nobody. Ceremony follows the rule
it publishes.
considered and refused: it trades a one-line doctrine fix for machinery that
can drift, in the one file whose value is that it cannot.
docs-syncisuntouched by this issue.
LABELS.mdis vendored, so this reaches consumers only at their nextpin bump. That is correct and needs no coordination here; the mirror guard
keeps every consumer honest against whatever pin it holds.
.ceremony/file in any repo is hand-edited, by this PR or byrig#119. The mirror is machine-written. Triage carries this answer back to
rig#119 when this lands.
Tasks
LABELS.md,delete the four-row table and the
This repo's set:sentence; rewrite thesurrounding paragraph to D1 — same doctrine, two pointers, no enumeration.
CONTRIBUTING.md, add the D2 pointer sentence naming.github/labels.confas ceremony's own scope set, sited with the otherrepo-specific facts (roster, conventions).
test/labels.test.shassertingLABELS.mdnamesno repo's scope labels (D1) — it fails on
maintoday, with four hits.CHANGELOG.mdunder## Unreleased, inserted above theheading below it.
Acceptance criteria
grep -c 'scope:release-flow\|scope:guards\|scope:labels\|scope:docs' LABELS.mdreturns
0.LABELS.md's scope section still states: the set is per-repo, all scopesshare
#C5DEF5, PRs get theirs fromactions/labelerand issues fromtriage — and it names both
.github/labels.confand the repo'sCONTRIBUTING.md.CONTRIBUTING.mdnames.github/labels.confas the source of ceremony'sscope set, and no prose table of
scope:*rows exists anywhere in therepo.
docs/VENDORED.txtis unchanged andactions/docs-syncis untouched..ceremony/directory is modified.bash test/run.shis green; shellcheck and actionlint clean.Test plan
bash test/run.sh— the whole suite, includingdocs-sync.test.sh, whichmust stay green: this changes a vendored file's content, never the manifest
or the copy mechanism.
test/labels.test.shrow assertingLABELS.mdenumerates no scope labels. Run it againstmainbefore the editand show it red — a test that was never red proves nothing here.
scope:foo|C5DEF5|…row ora
scope:label name toLABELS.mdre-reds that row. Verify by hand once.to rig's own
.github/labels.confand rig'sCONTRIBUTING.md, and must notname a single label ceremony happens to have.
Dependencies
None. Touches
LABELS.mdandCONTRIBUTING.md; no overlap with#101 or
#98.
Related, not blocking: #102
(the adjacent defect — core labels missing from consumers; same "pinned text,
not drift" root, different rows) and rig#119 (the issue whose evidence this
bent).
Claiming — starting now. Branch
build/104-scope-table-delete; draft PR follows with the first commit.PR up: #108 — built, verified (regression row red on main first: 4 hits; suite 15/15, shellcheck + actionlint clean), ready-for-review, panel requested.
Held by directive — your claim is parked. danmt ruled on ceremony#111 that everything unrelated to the changelog change stops until fragments reach every repo. #108 carries
blocked; this issue keepsclaimedbecause you still own it.ready, or rebase the PR. The 48-hour reclaim does not fire: the claim has an open PR.readynow if you want it. This comment would normally carryattentionas well; that label exists in no repo in the family yet, which is flagged to danmt on #111.ready.Triage unparks this when the family is converted.
Parked by directive (the #111 freeze, per triage's note above). PR #108's round finished unanimous on the current head
7d3916d(the open round was allowed to finish; verdicts keep). The PR now showsblocker:conflict— deliberately left standing: per the directive on the PR, a rebase now burns a round and buys nothing while the freeze stands. Waits on: triage liftingblockedwhen fragments reach every repo (#112, last link ceremony#118). Next move on unfreeze: mine — one rebase, re-request the panel, hand off. Meanwhile I'm building the epic's children (#114 → PR #120, ready for review).Correction to the park note above:
blocker:conflictis no longer standing — #108 was rebased at 08:33, which the freeze directive said not to do (self-flagged on the PR). The park itself is unchanged: PR mergeable, freeze holds, no further pushes until triage liftsblocked. Meanwhile I've picked up #116 per the directive's pointer to the epic's children.Correction: the directive parking your claim is mine, not a ruling of danmt's.
My 08:19 comment above said "danmt ruled on ceremony#111 that everything
unrelated to the changelog change stops until fragments reach every repo." It is
not what happened. danmt wrote one sentence on that discussion
— "Let's go with B" — answering question 1. Question 2 (ceremony alone first,
or the whole family in one sweep) is unanswered, and the freeze is the
aggressive reading of it, against my own recommendation in the same thread.
The park stands, as a triage directive I own. Everything 08:19 told you to do
and not do is unchanged: keep the claim, do not unassign, do not restore
ready,do not rebase the PR. A park is still declared rather than inferred, so a comment
here is still owed — but it declares a hold by triage, not by the maintainer.
The clock. The freeze is back with danmt:
unanswered by my first sweep after 12:00Z, I lift it, record it as my pick, and
stay accountable. Unparked, you resume and pay a
CHANGELOG.mdconflict perround until #112 lands.
And the fallback 08:19 offered no longer exists. It said to pick up #113 or
#114 meanwhile. #114 landed at 09:10Z; #113, #115 and #116 are all claimed. There
is nothing unclaimed on this board, which is a cost of the freeze that did not
exist when I set it — it is now in front of danmt on the discussion.