Each marker now says available-at-tag in the guide's existing L420
phrasing, verified by tag containment in #221; every never-mix-refs
sentence survives verbatim. The convention paragraph gains its missing
half: the release PR that ships machinery clears, in that same PR,
every marker its assembled section makes false.
Refs #221
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
round_outranks_draft consults the round before draft short-circuits: a
re-drafted PR carrying CHANGES_REQUESTED, an owed round-reply, or
push-staled approvals reads state:addressing; a live panel request on a
draft surfaces as state:bots-reviewing rather than being absorbed
(the must-not-paper-over combination, decided as: visible). Approvals do
not outrank draft, so a draft never reads needs-human, and a virgin
draft is byte-identical to before. LABELS.md's state:building row makes
draft evidence, not the definition.
Refs #205
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
One resolution point (panel_for_author) feeds set_required_bots; the
author's row when the conf defines one, the base panel= otherwise, minus
the author in either case. Bracket prefixes are matched quoted so the
case patterns cannot glob (D7, panela= tripwire). configured_label_rows
skips the rows so a dispatch bootstrap cannot mint a label named after
one. BUILDER.md/REVIEWER.md carry the one D9 wording; CONSUMERS.md
publishes the row as unreleased with the parse-failure warning.
Refs #224
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Consume the two displacement-fix fragments into the 0.4.1 section, stamp
VERSION and every CEREMONY_SELF_REF carrier, and record the doors-unchanged
drill ruling with the candidate-head evidence table.
Refs #212
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The sweep rode the same workflow run as the PR event that woke it, so
every displacement in the shared labels-reconcile queue recorded a
CANCELLED reconcile check on some PR — fake red CI that held review
requests. The reconcile + issueflow jobs move, unchanged, to a new
reusable labels-sweep.yml behind their own caller; labels.yml gains a
trigger job that dispatches the consumer's sweep caller with the plain
GITHUB_TOKEN (workflow_dispatch is a documented no-retrigger exemption)
on every event that used to run reconcile. A displaced sweep now cancels
on the Actions tab, attached to no PR; PR checks show scope + trigger.
Because every trigger-driven wake arrives as workflow_dispatch, the event
name alone no longer separates the operator's manual bootstrap from an
event-woken sweep: the sweep caller's bootstrap dispatch input does — the
trigger passes no, a bare manual dispatch defaults to yes. The sweep
reusable also takes pr_workflow_name, exported as SELF_WORKFLOW for the
#208 reconciler (harmless to earlier ones; zero file overlap with #208).
The trigger is deliberately loud: a pin bumped without the sweep caller,
its bootstrap input, or actions: write on the labels caller goes red at
the trigger job instead of silently never sweeping again — documented in
docs/CONSUMERS.md with the split stubs and the atomic-adoption note.
Refs #209
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The shared reconcile concurrency group displaces queued sweeps as
CANCELLED, and the displaced run's successor attaches to a different PR —
so on the victim the newest self entry stayed CANCELLED, scored FAILURE,
and the sweep set blocker:ci-red off its own corpse every cadence
(crew#227). Drop rollup entries whose workflowName matches SELF_WORKFLOW
(defaulting to the ambient GITHUB_WORKFLOW — the caller's name, so no
workflow edit and no hardcoded consumer name) before the newest-per-context
collapse; an empty name filters nothing. A self-only rollup now honestly
scores NONE, and a genuine foreign failure still blocks beside a cancelled
self entry — the must-fail guard against re-opening #136.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The trigger comments, CONSUMERS stub, changelog, and reusable labels.yml
comment said "events carry every real state change in seconds; the cron
only backstops a forgotten handoff." That is backwards: no subscribed
event wakes this sweep for a review verdict landing (no pull_request_review
trigger), blocker:ci-red set/cleared, blocker:conflict when another PR
merges, or the time-based stale/48h-reclaim. The hourly cron is the sole
discovery path for those four classes, not a forgotten-handoff net —
so the comments now name them and warn against deleting the cron (AC5).
codex-2 / kimi-2 (both blocking, round 2 @0a812c4b).
Round fixes on #200.
codex-1 (blocking): the issues narrowing dropped `edited`/`reopened`, but both
carry a queue-state change an event uniquely carries — `edited` a body rewrite
of the `Blocked by #N` declaration the sweep parses
(issueflow-reconcile.sh:179), `reopened` a closed issue re-entering the queue.
Dropping them tripped #199's must-fail. Narrow to
`[opened, closed, edited, reopened]`, dropping only the churn/validation
actions labeled/unlabeled/assigned/unassigned. Trigger tests now pin
edited/reopened present and the four dropped; labels.test.sh exact-list updated.
kimi (blocking): the "supersedes unreleased #144" prose was false — #144's
edited/reopened shipped in 0.3.0. Dissolved: we now keep them. CONSUMERS prose
rewritten to the real version history (0.2.0 #32 / 0.3.0 #144 / #199 narrows),
and the #137 review-request line corrected from "unreleased" to shipped-in-0.3.0.
kimi (non-blocking): reusable labels.yml comment no longer cites */15.
codex-2 (AC1 after-measurement / closing) escalated to triage on #199 — held,
not guessed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The tree is grouped (fragments carry ### headings) and changelog-armed
caps each '- ' entry at 300 chars; the single 574-char bullet failed
both. Rewrite as three '### Changed' bullets.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The advisory */15 cron fired a full-board sweep four times an hour at
GitHub's 1-minute billing floor; events carry real state changes in
seconds, so the cron only backstops a forgotten handoff. Relax it to
hourly and narrow the issues: trigger to [opened, closed] — the two
actions with promptness-critical reconcile behavior — dropping the
labeled/unlabeled churn source. Per-trigger why-comments added.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refs #189. Round 1 on #191 (codex blocking, kimi nit).
codex caught that advancing the stamp to crew@4da17c4 made the attention
section false. It did, and the error is mine in kind, not only in detail: a
reconciliation stamp is a claim about the WHOLE file against that tree, and I
audited only the ci-red surface across a 17-commit advance. That is the #187
failure mode, on the PR that closes#189.
What was false at the pinned SHA, all from the crew#66 ruling (danmt,
2026-07-27) landing in d578150e:
- "One wake is registry-independent, by design: attention" — no wake is
exempt now. _attention_partition splits rows against the registry; OUT rows
are reported and never acted on.
- "the assignment is what carries the authorization — there is nothing here
for a repo list to scope" — this is the position the ruling REJECTED. The
cost was argued first: a cross-repo handoff now waits on an operator adding
the repo, which is why an out-of-scope demand also pings the operator over
the boot-gate channel rather than only reaching duty.log.
- "a fix that bounds this wake to the registry would re-create the #16
incident" — that fix landed, with the ping as its mitigation.
- The parenthetical calling crew's repos-default.txt header a contradiction
"raised there as a discussion" — the discussion is crew#66, it was ruled,
and crew's header now names the attention wake explicitly. This file was
preserving the losing side of a settled question.
Also in range and owned by this section: d849f166 ledgered the wake, so
"a session that dies before acking is relaunched; that is the whole
crash-recovery story" no longer is. Dying relaunches; COMPLETING without
acking is a decline, and the ledger stops it re-firing until the issue
moves. Meaning, not mechanism, so it belongs here.
Re-audited the rest of the advance rather than spot-fixing: fleet.roster
still declares itself the TARGET environment (the roster paragraph holds),
and the roster/install commits touch role resolution inside crew, which this
file does not describe.
kimi's nit, which the earlier rewrite made mine: the paper inventory counted
one row while the triage-signals bullet marks a second. Both are needs-ruling
rows and both are now named — a number that has to be recounted every time a
wake lands is the thing that went wrong.
18/18 test files; changelog_fragment_problem OK; shellcheck, self-ref and
git diff --check clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Refs #189 — the post-merge, triage-owned task, now reachable: heavy-duty/crew#64
merged at 4da17c49594c2d86bd3793fa3567846cbca38e90.
#190 wrote the ci-red wake into FLEET.md deliberately marked on paper, per this
file's convention for a spec that is not yet running, and left the reconciliation
stamp at crew@01fb49c because advancing it to a SHA that did not carry the wake
would be the drift #187 exists to remove. crew#64 has merged, so both halves flip:
- The stamp advances to crew@4da17c4, and every crew permalink in the file with
it. A stamp and its evidence links naming different trees is worse than no
stamp: the reader diffs the wrong engine and finds no drift because the tree
they were pointed at is the one the prose was written against.
- The four on-paper markers go: the duty-order caveat, the ci-red bullet's
parenthetical, the Build bullet's "once ci-red deploys", and the closing
paper inventory — which now names one remaining paper wake, the notifier's
needs-ruling queue, not two.
The Build bullet is not a pure marker removal. crew#64's last review round
changed what it has to say: the operator ruled the round gate a whitelist, so
the wake admits a green head OR one with no checks configured, and holds a red
head AND one whose check has not finished. Copying the old "never a round at a
red head" through the flip would have shipped a fresh inaccuracy on the same
commit that claims the file is reconciled. The ci-red bullet gains the matching
sentence from the other side: an unfinished check is not a red head and wakes
nothing, because nothing has failed yet.
Verified at the stamped SHA rather than assumed: duty.sh's header carries
attention → … → resume → ci-red → build (and says it is what this file is
reconciled against), shared/README.md's duty order matches, and notify.sh's
only label filter is still state:needs-human — which is what keeps the
remaining paper claim true.
18/18 test files pass; changelog_fragment_problem OK (it caught a 387-char
entry against the 300 bound, now split); shellcheck, actionlint self-ref and
git diff --check clean.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The round protocol told the author to re-request exactly the reviewers
who did not approve, but the handoff predicate counts an approval only
at the current head: any push while answering a round staled the
earlier approver's verdict, doctrine said not to re-request them, and
the PR could never converge — the silent-stall shape of #26/#39.
Step 2 now re-requests by head, not by verdict: every panelist after a
push, the non-approvers alone at an unchanged head. Shape 2's wording
is aligned so the two paragraphs agree.
Defect raised by dan-claude-bot on #190; folded in at the operator's
direction while the paragraph is open. Refs #189.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
FLEET.md gains the ci-red wake between resume and build in crew#64's
engine position, marked on paper per this file's existing convention (the
notifier queue, triage's past-24h wake); the Build bullet records the
red-head exclusion as reported-not-swallowed; the reconciliation stamp
stays at crew@01fb49c because crew#64 has not merged.
Refs #189
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The two scope passages said the opposite of merged behaviour: a reviewer's
registry was 'the org itself' and 'no repo filter may gate' a request.
duty-review.sh implements repos.txt as the queue's scope since the
2026-07-25 operator ruling (crew#16) — out-of-scope requests WARN, never
act. The attention wake survives as the one stated registry-independent
exception: the assignment is the authorization (duty-attention.sh).
Mechanism moved to crew: the duty-loop anatomy and resilience prose is now
a pointer to crew's shared/README.md, folding the two drifted facts (cron
runs tick.sh; hygiene self-schedules inside the duty tick). Wake lists
follow the engine's duty order; the roster keeps the as-built bench beside
fleet.roster's target with the delta stated; stamp updated to crew@01fb49c.
Closes#187
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Binding to the first marker occurrence dropped every later sentence of a
repeated declaration and let earlier prose hijack the parse — the false
ready promotion on rig#154. Each occurrence now contributes its own
clause, terminated at its own first ./; (unterminated -> end of input),
and the union feeds the unchanged classification and decision table.
Closes#184
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
167/175 gain '### Added', 173/178 '### Changed', 180 '### Fixed' — every
bullet byte-identical, headings only (the #158 bar, inverted). CONSUMERS.md
names the sentinel and the flip procedure; changelog.d/README.md names the
sentinel. 182.md is this PR's own fragment, grouped atop the sentinel it
ships.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
During the ceremony#111 freeze, rig#126/#128 carried blocked beside
state:needs-human — the round had finished, but the hold said the merge
must not happen, and rig#126 was merged seven minutes after the
reconciler wrote the green label. decide_state() only joined the two
axes through blockers(), which emits branch facts; the hand-set blocked
label was never consulted.
blocked becomes the second exclusion on state:needs-human, exactly
parallel to needs-ruling: round says needs-human + has_label blocked ->
state:addressing. Deliberately not a blockers() emission — BLOCKERS is
machine-owned and the converge loop would strip the live hold on the
next tick, the same trap #51 names for needs-ruling.
Ruling record: discussion 122, armed default A fired 2026-07-25T09:00Z.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The park contract said declared-never-inferred but not that the
declaration stands, so a conservative builder re-declared every ~5
minutes — rig#145 collected 38 identical resumption audits in one
night. Now the declaration stands until the park's facts change; the
only repeat owed is the no-open-PR refresh inside the 48-hour reclaim
window. Decided on #177.
Closes#178
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
One definition in the fragment predicate; changelog-armed reds the PR
that writes the fragment and the assembler refuses at release, both by
inheritance. Doctrine names the number in BUILDER.md and CHANGELOG.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ceremony is a flat repo (#112 D3); changelog.d/135.md, 137.md, 144.md and
151.md landed with a '### Fixed'/'### Changed' heading, each individually
legal to changelog_fragment_problem, and together they made the directory
mixed-shape — 'bin/changelog-assemble 0.3.0 --check' refused on main.
Delete the heading line and its following blank line from each; every
bullet stays byte-identical (#157 D1). No fragment for this PR: its whole
diff is unpublished fragment text (#157 D2).
Closes#158
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BUILDER.md shape 5 gains its ending: the hold owner's most recent
queue-label event governs over stale prose, the timeline read comes
before standing down or up on a hold, a claim against stale prose cites
the events it read, and a refused claim has two exits. TRIAGE.md
requires re-reading label events before asserting label-borne state and
makes a lifted hold's stale body header triage's to correct in the same
tick.
Closes#154
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Reviewers bullet stated a gh-search request trigger and a sequential
first-this-second-that ordering; all four reviewer boxes actually run an
org-wide pulls-API requested_reviewers sweep merged with the repos.txt
backstop, deduplicated by (repo, PR) before acting (crew@b2fd864). The
on-paper list narrows to the notifier's needs-ruling queue, repos.txt is
the registry only on the triage box, and the Status block now carries the
crew ref this description was last reconciled against.
Part of the drift #148 reported; spec and citations in #149.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Merging #143 auto-closed #137 with a post-merge criterion unmet: the PR
carried Closes#137 as doctrine required, the criterion could only be
checked after the merge, and the contract was silent on the disagreement
between GitHub's keyword and the pipeline's close authority — the same
disagreement the cross-repo carve-out already resolved, one case over.
BUILDER.md gains the second exception beside the first: when the issue
body marks a criterion post-merge, the same-repo PR uses Refs #N and
triage closes by hand on the evidence. TRIAGE.md makes the criterion
carry its own mechanism; REVIEWER.md lists Refs #N as a spec pointer and
stops treating the reference-only PR as a defect; CONTRIBUTING.md points
at the one home instead of restating. No machinery, no label (#151 D5).
Closes#151
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The stub published [opened, labeled, unlabeled, assigned, unassigned,
closed] while ceremony's own caller listens on eight types — PR #32's
70db91f widened the caller by edited and reopened and the stub never
followed. Both are load-bearing: an edited body rewrites the Blocked-by
declaration the reconcile sweep parses, and a reopened issue re-enters
the queue wearing labels derived at close (#144).
The stub's list is now byte-identical to the caller's, a parity row in
test/labels.test.sh keeps it that way (red on a dropped type, a drift,
or a reorder in one file only), and one adoption note names the tag the
widened list rides in on. The caller does not narrow.
Closes#144
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both 0.2.0 drills ended at the same wall independently: bot tokens
deliberately lack delete_repo, so 'it gets deleted at the end' named a
step no builder in this fleet can perform. One drill held its release
draft in state:building retrying a 403 that cannot succeed; the other
shipped a record asserting a delete that had not happened. Step 1 now
names archive (archived:true, inside the repo scope) as the builder's
end state and the delete as the operator's, states that cleanup gates
nothing, and says why the archived leftover is safe to leave. The
record now states the disposal its author actually observed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>