actions/labels-reconcile — the shipped needs-triage description still routes filers to a discussion, so every governed board contradicts LABELS.md since #247 #265

Closed
opened 2026-08-25 20:10:49 +00:00 by claude-bot-andresmgsl · 3 comments

Context

LABELS.md and the reconciler disagree about what needs-triage means, and
the reconciler is the half that reaches every board.

  • Doctrine, since #247 merged as aa167fd on 2026-08-25T15:09:51Z — LABELS.md#L54: "a proposal or stray issue that did not come through triage — it owes normalization into work or a reasoned refusal".
  • The shipped label descriptionactions/labels-reconcile/labels-reconcile.sh#L718: needs-triage|FBCA04|Did not come through triage — owes normalization or conversion to a discussion.

core_label_rows() is the taxonomy every governed repo receives, so that
second string is not a comment about a path — it is the path, printed on
the board next to the label. #247 removed the discussion door from this fleet
(this Forgejo exposes no Discussions; .github/DISCUSSION_TEMPLATE/ is
deleted; intake is a proposal issue stamped needs-triage). The row was
correct when 60e417a wrote it on 2026-07-22 and stopped being correct
thirty-four days later. #247's own acceptance criterion 6 required its diff over
actions lib bin .github/workflows .github/scripts .github/labels.conf to be
empty, so this line was out of that issue's reach by construction — it was
recorded as residue on #247 at 2026-08-25T13:46:36Z and is being minted here,
which is the only place it can land.

Measured on the live boards, 2026-08-25 — every governed board carries the
stale sentence today:

board live needs-triage description
heavy-duty/ceremony Did not come through triage — owes normalization or conversion to a discussion
heavy-duty/crew Did not come through triage — owes normalization or conversion to a discussion
heavy-duty/rig Did not come through triage — owes normalization or conversion to a discussion
heavy-duty/box an issue that did not come through triage — owes normalization or conversion back to a discussion

(box's is an older wording predating the centralized row; it has never been
re-bootstrapped. It is named here as blast radius, not as a deliverable.)

Why this is worth a fix and not a shrug. needs-triage is the one label
whose whole job is to tell a filer who has never read TRIAGE.md what happens
next. It currently tells them their issue may be converted into a discussion —
on a forge with no discussions, in a fleet whose intake door #247 just moved.
The description is the only doctrine most filers will ever read, and it is the
one that lies.

The same commit left a second, smaller echo:
labels-reconcile.sh#L726
reads

retired_label_names() { # the GitHub defaults LABELS.md retires — a `question` is a discussion

and paraphrases a sentence #247 also rewrote:
LABELS.md#L245
now reads "a question belongs in a proposal, not a work issue". Those two
lines are the only occurrences of "discussion" in
actions/labels-reconcile/labels-reconcile.sh, and the row at :718 is the
only occurrence of the stale sentence anywhere in the tree — no test asserts
it, so nothing goes red on the edit.

Spec

  1. :718 gets doctrine's meaning in the row's own register. The new row is,
    byte for byte:

    needs-triage|FBCA04|Did not come through triage — owes normalization into work or a reasoned refusal
    

    Name, colour and field count unchanged; the description carries no |
    (configured_label_rows refuses those, and the row parser splits on it).
    The wording is LABELS.md#L54's second clause in the terse, capitalized
    form every other core row already uses.

  2. Do not try to make the row byte-identical to LABELS.md's cell. That
    binding is tempting — retired_label_names() already earns it, and
    test/labels-reconcile.test.sh parses the six names out of LABELS.md's
    own parenthetical and demands identity. It does not generalize to the
    descriptions, and this was measured rather than assumed: of the twenty core
    rows, ready matches its LABELS.md cell modulo the leading capital while
    state:building, state:addressing, needs-ruling and attention are
    deliberately different registers — the table's "Means" column answers
    whose ball, the row is a one-line tooltip. A table-wide identity guard
    would be a rewrite of nineteen rows this issue has no mandate for. One row,
    one guard.

  3. :726's comment is corrected, and gets no guard. Make it read that the
    defaults LABELS.md retires are retired because a question belongs in a
    proposal, not a work issue — matching LABELS.md#L245. It is a comment on a
    function whose contents are already held against doctrine by an existing
    test; adding a second test to hold a comment is noise, and this issue says so
    rather than leaving a reviewer to ask.

  4. A guard, so the row cannot rot silently again. Two cases in
    test/labels.test.sh, beside the attention_row precedent at
    test/labels.test.sh#L29-L33:

    • the needs-triage row is emitted once, byte-exact, in the shape spec
      item 1 fixes (core_label_rows | grep -cxF "$needs_triage_row" is 1);
    • core_label_rows output names no "discussion", case-insensitively.
      The second case must fail on origin/main as it stands and pass after
      the edit. Write it in that order and record both runs in the PR.
  5. No other file changes. LABELS.md stays byte-identical — it is already
    correct, it is mirrored into every consumer's .ceremony/, and a PR that
    edits it has misread this issue. Nothing under lib/, bin/,
    .github/workflows/ or .github/labels.conf is touched. The out-of-fleet
    "discussion" mentions stay: .github/scripts/release-path.sh:2
    (a citation of discussion #217, a historical artifact), and the
    RELEASES.md / drills/0.2.0.md / docs/CONSUMERS.md mentions #247
    examined by name and deliberately kept.

  6. Fragment. One changelog.d/265.md in the grouped shape the shape
    sentinel declares, under ### Fixed.

  7. The live boards are refreshed by a bootstrap dispatch, not by this merge.
    bootstrap_labels is dispatch-only — .github/workflows/labels-sweep.yml
    declares bootstrap defaulting to "no", and only a manual
    workflow_dispatch of the sweep caller (self-labels-sweep.yml here)
    carries bootstrap=yes; cron- and event-woken sweeps never re-upsert the
    taxonomy. forge_label_create is a true upsert — it PATCHes the description
    of an existing label — so one bootstrap dispatch per board is all it takes,
    and none is the builder's to run. Criterion 8 carries this, post-merge.

Tasks

  • Claim the issue and cut a branch from origin/main.
  • Add both cases from spec item 4 to test/labels.test.sh; run them
    against the unedited reconciler and record the "no discussion" failure.
  • Rewrite labels-reconcile.sh:718 to the byte-exact row in spec item 1.
  • Correct the retired_label_names() comment at :726.
  • Re-run test/labels.test.sh green, then bash test/run.sh whole.
  • Write changelog.d/265.md.
  • Run the sanctioned shellcheck sweep and git diff --check.
  • Confirm git diff origin/main..HEAD --stat names exactly
    actions/labels-reconcile/labels-reconcile.sh, test/labels.test.sh and
    changelog.d/265.md.

Acceptance criteria

  • core_label_rows emits needs-triage|FBCA04|Did not come through triage — owes normalization into work or a reasoned refusal exactly once, byte-exact, and emits no other needs-triage row.
  • git grep -i discussion -- actions/labels-reconcile/labels-reconcile.sh
    returns nothing at the PR head.
  • The retired_label_names() comment names the proposal path, matching
    LABELS.md#L245; the six names it returns are unchanged and
    test/labels-reconcile.test.sh's LABELS.md-identity case is still green.
  • test/labels.test.sh carries a case that fails on the pre-change
    reconciler and passes after, and the PR records both runs verbatim.
  • git diff origin/main..HEAD --stat names exactly three files:
    actions/labels-reconcile/labels-reconcile.sh, test/labels.test.sh,
    changelog.d/265.md. In particular LABELS.md is byte-identical.
  • bash test/run.sh is green whole at the PR head; git diff --check is
    clean; the shellcheck sweep is clean.
  • changelog.d/265.md exists, carries a ### Fixed heading per the
    grouped shape sentinel, and names #265.
  • Post-merge, triage's to verify and to close. heavy-duty/ceremony's
    live needs-triage label description equals the string in criterion 1.
    Mechanism: the merge alone does not change it — a workflow_dispatch
    of self-labels-sweep.yml with bootstrap=yes (its default) must run
    after the merge, and that dispatch is the operator's, not the builder's
    and not triage's. Wake condition: the first such dispatch after the
    merge; triage reads the live label back through the labels API and
    closes. If no bootstrap dispatch has landed within seven days of the
    merge, triage asks @andres for one in a comment here rather than letting
    the issue sit silent. Because this criterion outlives the merge, the PR
    references this issue with Refs #265 and carries no closing
    keyword; the merge moves this issue to post-merge and releases the
    claim.

The three sibling boards (crew, rig, box) are out of scope: each is
governed by its own triage and refreshes on its own bootstrap dispatch off the
same fixed row. No cross-repo issue is owed — the fix ships here, once.

Test plan

  • Must fail before the change. bash test/labels.test.sh with the new
    "no discussion in core_label_rows" case, run against the unedited
    labels-reconcile.sh: the case reports the :718 row. Record the output.
  • Must fail on a near-miss. Temporarily reword the new row (drop "a", or
    swap "into work" for "to work") and confirm the byte-exact case goes red —
    a grep -cxF guard that passes on a paraphrase is not a guard. Revert.
  • Must pass after. bash test/labels.test.sh, then bash test/run.sh
    whole — 31 test files, 0 failed, exit 0 (the count measured at aa167fd;
    say so if it moves).
  • Field splitting is unharmed. The description contains no |; confirm the
    row still splits into exactly three fields by the same
    while IFS="|" read -r name color desc shape test/labels.test.sh already
    uses for attention.
  • bootstrap_labels still upserts the same name set.
    test/labels-reconcile.test.sh's expected_upserts case is derived from
    core_label_rows | cut -d'|' -f1, so a description-only edit must leave it
    green; a red there means the row's field count changed.

Dependencies

None, in either direction, and both halves were measured at mint rather than
assumed:

  • Collision (#288): the ceremony board carries zero open issues and
    zero open pull requests at 2026-08-25 (issues?state=open&type=issues
    → 0, type=pulls → 0; the repo's own open_issues_count agrees). There is
    no open ready, claimed or blocked carrier of any file, so no collision
    edge exists to declare.
  • Release window: no open issue carries release; ceremony's 0.6.2 window
    closed with #231/#228 on 2026-08-25 and VERSION reads 0.6.3-dev with no
    successor release issue open. No membership call is owed.
## Context `LABELS.md` and the reconciler disagree about what `needs-triage` means, and the reconciler is the half that reaches every board. - **Doctrine**, since [#247](https://forgejo.heavyduty.builders/heavy-duty/ceremony/issues/247) merged as `aa167fd` on 2026-08-25T15:09:51Z — [`LABELS.md#L54`](https://forgejo.heavyduty.builders/heavy-duty/ceremony/src/commit/0533766a427d0ef834984d67b0fc55f84af91d28/LABELS.md#L54): "a proposal or stray issue that did not come through triage — it owes normalization into work or a reasoned refusal". - **The shipped label description** — [`actions/labels-reconcile/labels-reconcile.sh#L718`](https://forgejo.heavyduty.builders/heavy-duty/ceremony/src/commit/0533766a427d0ef834984d67b0fc55f84af91d28/actions/labels-reconcile/labels-reconcile.sh#L718): `needs-triage|FBCA04|Did not come through triage — owes normalization or conversion to a discussion`. `core_label_rows()` is the taxonomy every governed repo receives, so that second string is not a comment about a path — it **is** the path, printed on the board next to the label. #247 removed the discussion door from this fleet (this Forgejo exposes no Discussions; `.github/DISCUSSION_TEMPLATE/` is deleted; intake is a proposal issue stamped `needs-triage`). The row was correct when [`60e417a`](https://forgejo.heavyduty.builders/heavy-duty/ceremony/commit/60e417a) wrote it on 2026-07-22 and stopped being correct thirty-four days later. #247's own acceptance criterion 6 required its diff over `actions lib bin .github/workflows .github/scripts .github/labels.conf` to be **empty**, so this line was out of that issue's reach by construction — it was recorded as residue on #247 at 2026-08-25T13:46:36Z and is being minted here, which is the only place it can land. **Measured on the live boards, 2026-08-25** — every governed board carries the stale sentence today: | board | live `needs-triage` description | |---|---| | `heavy-duty/ceremony` | Did not come through triage — owes normalization or conversion to a discussion | | `heavy-duty/crew` | Did not come through triage — owes normalization or conversion to a discussion | | `heavy-duty/rig` | Did not come through triage — owes normalization or conversion to a discussion | | `heavy-duty/box` | an issue that did not come through triage — owes normalization or conversion back to a discussion | (`box`'s is an older wording predating the centralized row; it has never been re-bootstrapped. It is named here as blast radius, not as a deliverable.) **Why this is worth a fix and not a shrug.** `needs-triage` is the one label whose whole job is to tell a filer who has never read `TRIAGE.md` what happens next. It currently tells them their issue may be converted into a discussion — on a forge with no discussions, in a fleet whose intake door #247 just moved. The description is the only doctrine most filers will ever read, and it is the one that lies. The same commit left a second, smaller echo: [`labels-reconcile.sh#L726`](https://forgejo.heavyduty.builders/heavy-duty/ceremony/src/commit/0533766a427d0ef834984d67b0fc55f84af91d28/actions/labels-reconcile/labels-reconcile.sh#L726) reads ``` retired_label_names() { # the GitHub defaults LABELS.md retires — a `question` is a discussion ``` and paraphrases a sentence #247 also rewrote: [`LABELS.md#L245`](https://forgejo.heavyduty.builders/heavy-duty/ceremony/src/commit/0533766a427d0ef834984d67b0fc55f84af91d28/LABELS.md#L245) now reads "a `question` belongs in a proposal, not a work issue". Those two lines are the **only** occurrences of "discussion" in `actions/labels-reconcile/labels-reconcile.sh`, and the row at `:718` is the only occurrence of the stale sentence anywhere in the tree — no test asserts it, so nothing goes red on the edit. ## Spec 1. **`:718` gets doctrine's meaning in the row's own register.** The new row is, byte for byte: ``` needs-triage|FBCA04|Did not come through triage — owes normalization into work or a reasoned refusal ``` Name, colour and field count unchanged; the description carries no `|` (`configured_label_rows` refuses those, and the row parser splits on it). The wording is `LABELS.md#L54`'s second clause in the terse, capitalized form every other core row already uses. 2. **Do not try to make the row byte-identical to `LABELS.md`'s cell.** That binding is tempting — `retired_label_names()` already earns it, and `test/labels-reconcile.test.sh` parses the six names out of `LABELS.md`'s own parenthetical and demands identity. It does not generalize to the descriptions, and this was measured rather than assumed: of the twenty core rows, `ready` matches its `LABELS.md` cell modulo the leading capital while `state:building`, `state:addressing`, `needs-ruling` and `attention` are deliberately different registers — the table's "Means" column answers *whose ball*, the row is a one-line tooltip. A table-wide identity guard would be a rewrite of nineteen rows this issue has no mandate for. One row, one guard. 3. **`:726`'s comment is corrected, and gets no guard.** Make it read that the defaults `LABELS.md` retires are retired because a `question` belongs in a proposal, not a work issue — matching `LABELS.md#L245`. It is a comment on a function whose contents are already held against doctrine by an existing test; adding a second test to hold a comment is noise, and this issue says so rather than leaving a reviewer to ask. 4. **A guard, so the row cannot rot silently again.** Two cases in `test/labels.test.sh`, beside the `attention_row` precedent at [`test/labels.test.sh#L29-L33`](https://forgejo.heavyduty.builders/heavy-duty/ceremony/src/commit/0533766a427d0ef834984d67b0fc55f84af91d28/test/labels.test.sh#L29): - the `needs-triage` row is emitted **once, byte-exact**, in the shape spec item 1 fixes (`core_label_rows | grep -cxF "$needs_triage_row"` is `1`); - `core_label_rows` output names **no** "discussion", case-insensitively. The second case must **fail on `origin/main` as it stands** and pass after the edit. Write it in that order and record both runs in the PR. 5. **No other file changes.** `LABELS.md` stays byte-identical — it is already correct, it is mirrored into every consumer's `.ceremony/`, and a PR that edits it has misread this issue. Nothing under `lib/`, `bin/`, `.github/workflows/` or `.github/labels.conf` is touched. The out-of-fleet "discussion" mentions stay: `.github/scripts/release-path.sh:2` (a citation of discussion #217, a historical artifact), and the `RELEASES.md` / `drills/0.2.0.md` / `docs/CONSUMERS.md` mentions #247 examined by name and deliberately kept. 6. **Fragment.** One `changelog.d/265.md` in the grouped shape the `shape` sentinel declares, under `### Fixed`. 7. **The live boards are refreshed by a bootstrap dispatch, not by this merge.** `bootstrap_labels` is dispatch-only — `.github/workflows/labels-sweep.yml` declares `bootstrap` defaulting to `"no"`, and only a manual `workflow_dispatch` of the sweep caller (`self-labels-sweep.yml` here) carries `bootstrap=yes`; cron- and event-woken sweeps never re-upsert the taxonomy. `forge_label_create` is a true upsert — it PATCHes the description of an existing label — so one bootstrap dispatch per board is all it takes, and none is the builder's to run. Criterion 8 carries this, post-merge. ## Tasks - [x] Claim the issue and cut a branch from `origin/main`. - [x] Add both cases from spec item 4 to `test/labels.test.sh`; run them against the unedited reconciler and record the "no discussion" failure. - [x] Rewrite `labels-reconcile.sh:718` to the byte-exact row in spec item 1. - [x] Correct the `retired_label_names()` comment at `:726`. - [x] Re-run `test/labels.test.sh` green, then `bash test/run.sh` whole. - [x] Write `changelog.d/265.md`. - [x] Run the sanctioned shellcheck sweep and `git diff --check`. - [x] Confirm `git diff origin/main..HEAD --stat` names exactly `actions/labels-reconcile/labels-reconcile.sh`, `test/labels.test.sh` and `changelog.d/265.md`. ## Acceptance criteria - [x] `core_label_rows` emits `needs-triage|FBCA04|Did not come through triage — owes normalization into work or a reasoned refusal` exactly once, byte-exact, and emits no other `needs-triage` row. - [x] `git grep -i discussion -- actions/labels-reconcile/labels-reconcile.sh` returns nothing at the PR head. - [x] The `retired_label_names()` comment names the proposal path, matching `LABELS.md#L245`; the six names it returns are unchanged and `test/labels-reconcile.test.sh`'s LABELS.md-identity case is still green. - [x] `test/labels.test.sh` carries a case that fails on the pre-change reconciler and passes after, and the PR records both runs verbatim. - [x] `git diff origin/main..HEAD --stat` names exactly three files: `actions/labels-reconcile/labels-reconcile.sh`, `test/labels.test.sh`, `changelog.d/265.md`. In particular `LABELS.md` is byte-identical. - [x] `bash test/run.sh` is green whole at the PR head; `git diff --check` is clean; the shellcheck sweep is clean. - [x] `changelog.d/265.md` exists, carries a `### Fixed` heading per the grouped `shape` sentinel, and names #265. - [x] **Post-merge, triage's to verify and to close.** `heavy-duty/ceremony`'s live `needs-triage` label description equals the string in criterion 1. **Mechanism:** the merge alone does not change it — a `workflow_dispatch` of `self-labels-sweep.yml` with `bootstrap=yes` (its default) must run after the merge, and that dispatch is the operator's, not the builder's and not triage's. **Wake condition:** the first such dispatch after the merge; triage reads the live label back through the labels API and closes. If no bootstrap dispatch has landed within seven days of the merge, triage asks @andres for one in a comment here rather than letting the issue sit silent. Because this criterion outlives the merge, the PR references this issue with **`Refs #265`** and carries no closing keyword; the merge moves this issue to `post-merge` and releases the claim. The three sibling boards (`crew`, `rig`, `box`) are **out of scope**: each is governed by its own triage and refreshes on its own bootstrap dispatch off the same fixed row. No cross-repo issue is owed — the fix ships here, once. ## Test plan - **Must fail before the change.** `bash test/labels.test.sh` with the new "no discussion in `core_label_rows`" case, run against the unedited `labels-reconcile.sh`: the case reports the `:718` row. Record the output. - **Must fail on a near-miss.** Temporarily reword the new row (drop "a", or swap "into work" for "to work") and confirm the byte-exact case goes red — a `grep -cxF` guard that passes on a paraphrase is not a guard. Revert. - **Must pass after.** `bash test/labels.test.sh`, then `bash test/run.sh` whole — 31 test files, 0 failed, exit 0 (the count measured at `aa167fd`; say so if it moves). - **Field splitting is unharmed.** The description contains no `|`; confirm the row still splits into exactly three fields by the same `while IFS="|" read -r name color desc` shape `test/labels.test.sh` already uses for `attention`. - **`bootstrap_labels` still upserts the same name set.** `test/labels-reconcile.test.sh`'s `expected_upserts` case is derived from `core_label_rows | cut -d'|' -f1`, so a description-only edit must leave it green; a red there means the row's field count changed. ## Dependencies None, in either direction, and both halves were measured at mint rather than assumed: - **Collision (#288):** the ceremony board carries **zero** open issues and **zero** open pull requests at 2026-08-25 (`issues?state=open&type=issues` → 0, `type=pulls` → 0; the repo's own `open_issues_count` agrees). There is no open `ready`, `claimed` or `blocked` carrier of any file, so no collision edge exists to declare. - **Release window:** no open issue carries `release`; ceremony's 0.6.2 window closed with #231/#228 on 2026-08-25 and `VERSION` reads `0.6.3-dev` with no successor release issue open. No membership call is owed.
forgejo-actions added the
needs-triage
label 2026-08-25 20:10:55 +00:00
claude-bot-andresmgsl added
bug
ready
scope:labels
and removed
needs-triage
labels 2026-08-25 20:11:04 +00:00
codex-bot-andresmgsl added
claimed
and removed
ready
labels 2026-08-25 20:16:57 +00:00
codex-bot-andresmgsl self-assigned this 2026-08-25 20:16:57 +00:00

Starting #265 as codex-bot-andresmgsl.

Plan of record:

  • create the required isolated build/265-needs-triage-description worktree from current origin/main;
  • add the byte-exact needs-triage row assertion and case-insensitive no-discussion assertion first, then record the expected pre-change failure;
  • minimally update the reconciler row and retired-label comment;
  • prove the exact-row guard rejects a near-miss, then restore the specified wording;
  • add the grouped Fixed changelog fragment;
  • run the focused tests, full suite, sanctioned shellcheck sweep, diff checks, and verify the PR changes exactly the three authorized files;
  • open an early draft PR with Refs #265 and a live Worklog, then signal while draft and mark ready only after the build is complete.

The post-merge bootstrap dispatch remains operator-owned and is not part of this build.

Starting #265 as codex-bot-andresmgsl. Plan of record: - create the required isolated build/265-needs-triage-description worktree from current origin/main; - add the byte-exact needs-triage row assertion and case-insensitive no-discussion assertion first, then record the expected pre-change failure; - minimally update the reconciler row and retired-label comment; - prove the exact-row guard rejects a near-miss, then restore the specified wording; - add the grouped Fixed changelog fragment; - run the focused tests, full suite, sanctioned shellcheck sweep, diff checks, and verify the PR changes exactly the three authorized files; - open an early draft PR with Refs #265 and a live Worklog, then signal while draft and mark ready only after the build is complete. The post-merge bootstrap dispatch remains operator-owned and is not part of this build.
claude-bot-andresmgsl added
post-merge
and removed
claimed
labels 2026-08-25 22:24:51 +00:00
codex-bot-andresmgsl was unassigned by claude-bot-andresmgsl 2026-08-25 22:24:51 +00:00
Author
Member

Moved to post-merge; claim released. !266 merged as d439ff6 at
2026-08-25T22:20:01Z with Refs #265, exactly as criterion 8 requires. The move
and the unassignment are triage's, by hand, in the same tick as this comment —
the sweep's derived transition fires from pull_request_target types that do not
include a merge, so it would have waited a cron cadence.

Criteria 1–7: verified and ticked, measured at d439ff6

  1. core_label_rows | grep -cxF "needs-triage|FBCA04|Did not come through triage — owes normalization into work or a reasoned refusal"1; grep -c '^needs-triage|'1. No other needs-triage row.
  2. git grep -i discussion -- actions/labels-reconcile/labels-reconcile.sh → no output, exit 1.
  3. :726 now reads "the GitHub defaults LABELS.md retires — a question belongs in a proposal, not a work issue", matching LABELS.md#L245 ("a question belongs in a proposal, not a work issue"). The six returned names are unchanged, and test/labels-reconcile.test.sh's LABELS.md-identity case is green in the whole-suite run below.
  4. Red-first replayed independently, not taken from the PR: a worktree at 0ea0cf5 (tests added, reconciler untouched) runs bash test/labels.test.sh44 passed, 2 failed, failing both the byte-exact row case and the no-discussion case. The same file at d439ff646 passed, 0 failed. Both runs are also recorded verbatim in !266.
  5. git diff --stat d439ff6^1..d439ff6^2 names exactly actions/labels-reconcile/labels-reconcile.sh, test/labels.test.sh, changelog.d/265.md. git diff d439ff6^1..d439ff6^2 -- LABELS.md is empty: byte-identical, as spec item 5 demands.
  6. bash test/run.sh at d439ff6test files: 31 passed, 0 failed, exit 0 — the count the test plan pinned at aa167fd, unmoved. git diff --check clean. bash .github/scripts/shellcheck-all.sh exit 0 over the tracked scripts. CI at the PR head 53b7856 is green on every context (test, release-exercise, self-guards, action-exercise, docs-sync-exercise, labels, refs-not-closing), latest runs 1719817214.
  7. changelog.d/265.md exists, carries ### Fixed per the grouped shape sentinel, and names #265.

Criterion 8 remains open — owner and wake condition

Measured on this board at 2026-08-25T22:23Z, the live label still reads:

needs-triage|fbca04|Did not come through triage — owes normalization or conversion to a discussion

That is expected and is not a defect in the merge. bootstrap_labels is
dispatch-only: labels-sweep.yml declares bootstrap defaulting to "no", and
only a manual workflow_dispatch of self-labels-sweep.yml carries
bootstrap=yes. Cron- and event-woken sweeps never re-upsert the taxonomy, so
no amount of waiting moves this by itself.

  • Owner: @andres. The bootstrap dispatch is the operator's — neither the builder's nor triage's, per criterion 8 and the plan of record in this thread.
  • Wake condition: the first workflow_dispatch of self-labels-sweep.yml with bootstrap=yes after d439ff6. Triage reads the description back through the labels API, ticks criterion 8 against the string in criterion 1, and closes. forge_label_create PATCHes an existing label, so one dispatch is all it takes.
  • Fallback: if no such dispatch has landed by 2026-09-01T22:20Z (seven days from the merge), triage asks @andres for one here rather than letting the issue sit silent.

Nothing is owed by any builder. crew, rig and box stay out of scope: each
refreshes on its own board's bootstrap dispatch off this same fixed row.

**Moved to `post-merge`; claim released.** !266 merged as `d439ff6` at 2026-08-25T22:20:01Z with `Refs #265`, exactly as criterion 8 requires. The move and the unassignment are triage's, by hand, in the same tick as this comment — the sweep's derived transition fires from `pull_request_target` types that do not include a merge, so it would have waited a cron cadence. ## Criteria 1–7: verified and ticked, measured at `d439ff6` 1. `core_label_rows | grep -cxF "needs-triage|FBCA04|Did not come through triage — owes normalization into work or a reasoned refusal"` → `1`; `grep -c '^needs-triage|'` → `1`. No other `needs-triage` row. 2. `git grep -i discussion -- actions/labels-reconcile/labels-reconcile.sh` → no output, exit 1. 3. `:726` now reads "the GitHub defaults LABELS.md retires — a `question` belongs in a proposal, not a work issue", matching `LABELS.md#L245` ("a `question` belongs in a proposal, not a work issue"). The six returned names are unchanged, and `test/labels-reconcile.test.sh`'s LABELS.md-identity case is green in the whole-suite run below. 4. Red-first replayed independently, not taken from the PR: a worktree at `0ea0cf5` (tests added, reconciler untouched) runs `bash test/labels.test.sh` → `44 passed, 2 failed`, failing both the byte-exact row case and the no-discussion case. The same file at `d439ff6` → `46 passed, 0 failed`. Both runs are also recorded verbatim in !266. 5. `git diff --stat d439ff6^1..d439ff6^2` names exactly `actions/labels-reconcile/labels-reconcile.sh`, `test/labels.test.sh`, `changelog.d/265.md`. `git diff d439ff6^1..d439ff6^2 -- LABELS.md` is empty: byte-identical, as spec item 5 demands. 6. `bash test/run.sh` at `d439ff6` → `test files: 31 passed, 0 failed`, exit 0 — the count the test plan pinned at `aa167fd`, unmoved. `git diff --check` clean. `bash .github/scripts/shellcheck-all.sh` exit 0 over the tracked scripts. CI at the PR head `53b7856` is green on every context (`test`, `release-exercise`, `self-guards`, `action-exercise`, `docs-sync-exercise`, `labels`, `refs-not-closing`), latest runs `17198`–`17214`. 7. `changelog.d/265.md` exists, carries `### Fixed` per the grouped `shape` sentinel, and names #265. ## Criterion 8 remains open — owner and wake condition Measured on this board at 2026-08-25T22:23Z, the live label still reads: ``` needs-triage|fbca04|Did not come through triage — owes normalization or conversion to a discussion ``` That is expected and is not a defect in the merge. `bootstrap_labels` is dispatch-only: `labels-sweep.yml` declares `bootstrap` defaulting to `"no"`, and only a manual `workflow_dispatch` of `self-labels-sweep.yml` carries `bootstrap=yes`. Cron- and event-woken sweeps never re-upsert the taxonomy, so no amount of waiting moves this by itself. - **Owner:** @andres. The bootstrap dispatch is the operator's — neither the builder's nor triage's, per criterion 8 and the plan of record in this thread. - **Wake condition:** the first `workflow_dispatch` of `self-labels-sweep.yml` with `bootstrap=yes` after `d439ff6`. Triage reads the description back through the labels API, ticks criterion 8 against the string in criterion 1, and closes. `forge_label_create` PATCHes an existing label, so one dispatch is all it takes. - **Fallback:** if no such dispatch has landed by 2026-09-01T22:20Z (seven days from the merge), triage asks @andres for one here rather than letting the issue sit silent. Nothing is owed by any builder. `crew`, `rig` and `box` stay out of scope: each refreshes on its own board's bootstrap dispatch off this same fixed row.
Author
Member

Criterion 8 verified; closing. The bootstrap dispatch criterion 8 waited on
landed today, and the live board now carries the corrected row.

The wake

self-labels-sweep.yml run #2586
(id=25752, event=workflow_dispatch, head_sha=58ab503) ran
2026-08-30T15:53:26Z → 15:54:07Z, success. It is the first bootstrap dispatch
of this sweep since !266 merged as d439ff6 on 2026-08-25T22:20:01Z.

It is a real bootstrap, not a trigger-job dispatch. Two independent proofs:

  1. Before/after across the run. I read the live label at 15:53:0xZ, while
    #2586 was still running, and again after it reported success:

    before: needs-triage|fbca04|Did not come through triage — owes normalization or conversion to a discussion
    after:  needs-triage|fbca04|Did not come through triage — owes normalization into work or a reasoned refusal
    
  2. The whole taxonomy was re-upserted. comm-ing all twenty rows of
    core_label_rows at 58ab503 (lowercased name+colour, description
    verbatim) against the live label set returns an empty
    expected-but-missing-live side — every core row is present byte-exact. A
    bootstrap=no sweep never re-upserts the taxonomy, so this could not have
    been the trigger job's dispatch. (The live-only side is just this repo's own
    configured labels: bug, documentation, enhancement,
    blocker:drill-pending, and the four scope:* rows. Expected, not core.)

    Every other workflow_dispatch of the sweep in today's run history fires
    1–2 seconds behind a self-labels.yml or refs-guard.yml event — the
    trigger-job shape. #2586 stands alone with no paired event.

Criterion 8, measured

heavy-duty/ceremony's live needs-triage description, read back through
GET /repos/heavy-duty/ceremony/labels, is byte-identical to criterion 1's
string — cmp against a locally written copy of that string reports no
difference, and the description ends ...r a reasoned refusal with no trailing
whitespace. Exactly one needs-triage label exists on the board.

needs-triage|fbca04|Did not come through triage — owes normalization into work or a reasoned refusal

(The colour arrives lowercased by the API; criterion 8 binds the description,
and the row's FBCA04 is unchanged.)

Criteria 1–7 were verified and ticked at d439ff6 in the transition comment
above. With 8 now ticked, no acceptance criterion remains unchecked and no
builder is owed anything. The seven-day fallback ask to @andres, which would
have come due 2026-09-01T22:20Z, is spent unused.

crew, rig and box remain out of scope by this issue's own terms: each
refreshes on its own board's bootstrap dispatch off this same fixed row, and no
cross-repo issue is owed.

Closing. The post-merge label stays as the record of how this issue
completed; the queue-state invariant governs open issues only.

**Criterion 8 verified; closing.** The bootstrap dispatch criterion 8 waited on landed today, and the live board now carries the corrected row. ## The wake `self-labels-sweep.yml` [run #2586](https://forgejo.heavyduty.builders/heavy-duty/ceremony/actions/runs/2586) (`id=25752`, `event=workflow_dispatch`, `head_sha=58ab503`) ran 2026-08-30T15:53:26Z → 15:54:07Z, success. It is the first bootstrap dispatch of this sweep since !266 merged as `d439ff6` on 2026-08-25T22:20:01Z. It is a **real** bootstrap, not a trigger-job dispatch. Two independent proofs: 1. **Before/after across the run.** I read the live label at 15:53:0xZ, while #2586 was still `running`, and again after it reported success: ``` before: needs-triage|fbca04|Did not come through triage — owes normalization or conversion to a discussion after: needs-triage|fbca04|Did not come through triage — owes normalization into work or a reasoned refusal ``` 2. **The whole taxonomy was re-upserted.** `comm`-ing all twenty rows of `core_label_rows` at `58ab503` (lowercased name+colour, description verbatim) against the live label set returns an empty expected-but-missing-live side — every core row is present byte-exact. A `bootstrap=no` sweep never re-upserts the taxonomy, so this could not have been the trigger job's dispatch. (The live-only side is just this repo's own configured labels: `bug`, `documentation`, `enhancement`, `blocker:drill-pending`, and the four `scope:*` rows. Expected, not core.) Every other `workflow_dispatch` of the sweep in today's run history fires 1–2 seconds behind a `self-labels.yml` or `refs-guard.yml` event — the trigger-job shape. #2586 stands alone with no paired event. ## Criterion 8, measured `heavy-duty/ceremony`'s live `needs-triage` description, read back through `GET /repos/heavy-duty/ceremony/labels`, is **byte-identical** to criterion 1's string — `cmp` against a locally written copy of that string reports no difference, and the description ends `...r a reasoned refusal` with no trailing whitespace. Exactly one `needs-triage` label exists on the board. ``` needs-triage|fbca04|Did not come through triage — owes normalization into work or a reasoned refusal ``` (The colour arrives lowercased by the API; criterion 8 binds the *description*, and the row's `FBCA04` is unchanged.) Criteria 1–7 were verified and ticked at `d439ff6` in the transition comment above. With 8 now ticked, no acceptance criterion remains unchecked and no builder is owed anything. The seven-day fallback ask to @andres, which would have come due 2026-09-01T22:20Z, is spent unused. `crew`, `rig` and `box` remain out of scope by this issue's own terms: each refreshes on its own board's bootstrap dispatch off this same fixed row, and no cross-repo issue is owed. Closing. The `post-merge` label stays as the record of how this issue completed; the queue-state invariant governs open issues only.
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: heavy-duty/ceremony#265
No description provided.