Compare commits

..

7 commits

Author SHA1 Message Date
codex-bot-andresmgsl
832a41b647 test: update roster drift fixture 2026-08-22 22:22:53 +00:00
4f887a756f Merge pull request 'docs: adopt upstream 0.6.1 and 0.6.2 doctrine' (#233) from codex-bot-andresmgsl/ceremony:build/229-upstream-doctrine into main
Reviewed-on: heavy-duty/ceremony#233
Reviewed-by: claude-bot-andresmgsl <andres+1@heavyduty.builders>
Reviewed-by: kimi-bot-andresmgsl <andres+4@heavyduty.builders>
Reviewed-by: glm-bot-andresmgsl <andres+5@heavyduty.builders>
2026-08-22 22:16:23 +00:00
claude-lead-andresmgsl
27f702a018 fix: roster names the renamed triage identity
Second leg of the same debt #232 records. The operator renamed
cluade-bot-andresmgsl to claude-bot-andresmgsl on 2026-08-20, closing the
misspelling; the account kept its id so history followed it, but the
roster compares logins as strings and went on naming the old form.

Both functional carriers move together, as #232's spec requires: the
`panel=`/`triage-actors=` lines and the CONTRIBUTING identity table. The
conf/prose sync guard is why they cannot move apart.

Verified: `test/labels.test.sh` is 43/44 before and after — unchanged.
The one failure is #232 spec item 4 (the `glm-reviewer-andresmgsl`
fixture at :249, now a no-op mutation), which is untouched here and
remains that issue's only outstanding work.

Historical attributions elsewhere stay as written, per triage's
2026-08-17 ruling recorded on #232.

Refs #232
2026-08-20 23:23:30 +00:00
codex-bot-andresmgsl
9f07c91faf docs: group the 229 changelog fragment 2026-08-20 01:36:32 +00:00
codex-bot-andresmgsl
78532e0777 docs: define post-merge release edge handling 2026-08-19 03:51:49 +00:00
codex-bot-andresmgsl
df4782ced9 docs: clarify builder waits and handoff ordering 2026-08-19 03:51:20 +00:00
codex-bot-andresmgsl
d12cc3d84f docs: route vendored doctrine through the manifest 2026-08-19 03:50:10 +00:00
6 changed files with 74 additions and 33 deletions

4
.github/labels.conf vendored
View file

@ -1,5 +1,5 @@
panel=codex-bot-andresmgsl glm-bot-andresmgsl cluade-bot-andresmgsl kimi-bot-andresmgsl
triage-actors=cluade-bot-andresmgsl
panel=codex-bot-andresmgsl glm-bot-andresmgsl claude-bot-andresmgsl kimi-bot-andresmgsl
triage-actors=claude-bot-andresmgsl
scope:release-flow|C5DEF5|The reusable release workflow, decide, the doors
scope:guards|C5DEF5|changelog-armed / changelog-monotonic / drill-recorded
scope:labels|C5DEF5|The labels workflow, reconciler, the taxonomy

View file

@ -33,7 +33,10 @@ triage bug, and the move is to say so on the issue, not to guess.
re-requests posted, by head and not by verdict (steps 12). A red check
at the head takes it out of this shape: the next move is yours;
3. every remaining acceptance criterion is operator-owned, stated so by
triage on the issue;
triage on the issue. **An operator-owned remainder parks the claim and
never the handoff**: this shape is reached only from the far side of
shape 4, because it is the state finishing the work puts you in and
would otherwise excuse the handoff it should follow (#336);
4. it is **handed off** — round passed, no `blocker:*` standing,
`state:needs-human` set per Handoff, the merge the human's. Shapes 2
and 4 are sequential and never overlap;
@ -174,7 +177,9 @@ such as the panel roster live in that repo's own CONTRIBUTING.)
blocking (#139, #276). **Then classify that entry by `conclusion`, never
`status`**, which can disagree with it (#259). No conclusion is not
green: a configured run in progress is waited on, and waiting is
compliance, not a stall. Cancelled or stale is not green, *stale* being a
compliance, not a stall — the wait is the **request's**, and never a
reason to withhold the declaration that a round was answered (step 2).
Cancelled or stale is not green, *stale* being a
superseded head's check, which a head-scoped rollup never shows. Skipped
or neutral is green, those being deliberate "passed / not applicable"
conclusions. No checks configured is green — the third ruled case, not an
@ -200,8 +205,19 @@ such as the panel roster live in that repo's own CONTRIBUTING.)
head, and its mechanism is crew's to describe (#94). **The re-request
carries the same green-check-at-head precondition**, argued exception
included: a fix push whose check comes up red is your next fix, not the
panel's. Prefer verification over argument — add the test that settles
the doubt.
panel's. **Where an engine mediates the request, that precondition binds
the engine's act and not yours**: declaring a round answered is not
requesting the panel, so declare it as soon as the round's fixes are
pushed and stop. The engine holds the request while the head is pending
or red, so an early declaration cannot produce an early request while a
withheld one is indistinguishable from a session that died (#330).
**Never wait on an event you have no wake for** — where the engine is
what observes the check settling, the wait is the engine's to keep
(#330). **Never block on a producer you cannot prove alive either**:
where a job signals its own completion, that signal is the wake and the
finished output is read afterwards, because a follow on a file nothing is
writing cannot tell *not yet* from *never* (#336). Prefer verification
over argument — add the test that settles the doubt.
3. Never dismiss a review, never merge, never mark your own work as passed.
A blocking point you disagree with is answered with evidence or escalated
in the PR; silence and force-forward are not options, and a panel
@ -218,8 +234,9 @@ may draft a PR but only the builder undrafts it. **Where a draft suppressed
the checks, green is proven at the flip and the request still follows it** —
marking ready runs the checks the draft held back, so the order is flip, let
the head answer, then request, step 1's precondition and not a second one.
Waiting there is compliance, and `blocker:unrequested` does not fire while a
head's checks are pending or red (#236).
Waiting there is compliance — again the request's wait, not the
declaration's — and `blocker:unrequested` does not fire while a head's
checks are pending or red (#236).
## The ruling ask

View file

@ -48,7 +48,7 @@ the box is the blast-radius boundary; roles are what a session is told, and
| identity | box (rig tenant) | standing work |
|---|---|---|
| `cluade-bot-andresmgsl` | `triage` (claude-box) | **triage** — the only door issues come through; this identity mints issues and nothing else writes them (#18's `triage-actors`) — and review. It does not build. |
| `claude-bot-andresmgsl` | `triage` (claude-box) | **triage** — the only door issues come through; this identity mints issues and nothing else writes them (#18's `triage-actors`) — and review. It does not build. |
| `codex-bot-andresmgsl` | codex-box | build + review |
| `glm-bot-andresmgsl` | glm-box | review |
| `kimi-bot-andresmgsl` | kimi-box | review |
@ -97,14 +97,13 @@ table repeats it (#104).
## Doctrine conventions
The vendored role files — `AGENTS.md`, `TRIAGE.md`, `BUILDER.md`,
`REVIEWER.md`, `LABELS.md`, and `RELEASES.md` — state each normative rule
completely, keep at most one sentence of why, and cite its record only with a
bare parenthetical such as `(#N)`, `(#N D3)`, or `(#N, #M)`. Incident
narrative — timestamps, actors, quoted comments, measured counts, and links to
specific comments — belongs in that record. If a rule cannot be followed
without chasing its cite, the rule is under-stated: fix the statement, not the
citation. (#280)
The vendored role files — the set [`docs/VENDORED.txt`](docs/VENDORED.txt)
declares — state each normative rule completely, keep at most one sentence of
why, and cite its record only with a bare parenthetical such as `(#N)`,
`(#N D3)`, or `(#N, #M)`. Incident narrative — timestamps, actors, quoted
comments, measured counts, and links to specific comments — belongs in that
record. If a rule cannot be followed without chasing its cite, the rule is
under-stated: fix the statement, not the citation. (#280)
Normative text in those files does not cite issues from other repositories.
Consumers read the vendored bytes outside this organization's context, and a
@ -119,21 +118,12 @@ every session. (#280)
## How the other repos use this
Two consumption modes, split by what has a runtime:
- **Machinery is consumed by reference.** Workflows and actions are fetched
by GitHub at run time from the ref the caller pins — no copy exists in the
consumer.
- **Doctrine is consumed as a machine-verified mirror.** A document's only
"runtime" is an agent reading the working tree of the repo it stands in —
a doc that requires a cross-repo fetch before it governs is a doc that
sometimes goes unread. So the agent-facing set — **AGENTS.md, TRIAGE.md,
BUILDER.md, REVIEWER.md, LABELS.md, RELEASES.md** — is vendored into each governed
repo at **`.ceremony/`**, byte-identical to this repo at the pinned ref,
by the sync tool (issue #19). A CI guard diffs the mirror against the pin
on every PR: hand-editing a vendored file, or bumping the pin without
re-syncing, goes red. It is a copy that cannot drift — which is the only
kind of copy this org allows.
Two consumption modes, split by what has a runtime: **machinery by
reference**, fetched at run time from the ref a caller pins, and **doctrine
as a mirror** — the set [`docs/VENDORED.txt`](docs/VENDORED.txt) declares,
vendored at `.ceremony/` and held to the pin by a guard (issue #19). The
[README](README.md) states both modes in full, and why they differ; what
follows is only what they leave a governed repo to carry.
A governed repo (box, rig, cast, incubator, …) therefore carries:

View file

@ -86,6 +86,37 @@ edges rather than merely appending membership at the sink. It follows that
every `ready` issue is a gate member. `epic` and `post-merge` issues are exempt
because neither is claimable (#292).
A member that lands `post-merge` releases nothing: that exemption is about
claimability, while a `post-merge` issue is still open and an open predecessor
holds its successors, so every successor declaring on it stays held and the
window stops advancing along that edge (#329).
**When a member reaches `post-merge` and any open declaration names it, triage
splits the remainder**: mint a fresh issue carrying the outstanding criteria
verbatim, naming its owner and its wake condition and citing the original, then
close the original on what it delivered. Triage owns this because only triage
mints issues and `post-merge` is its completion queue (#329).
**The release edge is the original's close, never the remainder's.** Each
successor's declaration names the original's number, so closing the new issue
releases nothing (#329).
**Split only when an open declaration names the issue.** The trigger is a check
rather than a judgement — run the blocker parse over every open `blocked` body
and see whether this number appears — because an issue that strands nothing is
`post-merge` working as intended (#329).
**Never close work out from under a builder.** Where the original is assigned,
`claimed`, or carrying an open PR, amend its body to hand the outstanding
criteria to the new issue and let its holder close it, so the release edge above
is reached without taking the work from them (#329).
**Do not instead teach the blocker parse that `post-merge` counts as landed.**
That promotes a successor while its predecessor still owes acceptance criteria,
inverts a parser whose deliberate error direction is to hold or flag a reference
it cannot read rather than release it, and needs label data a reference-state
lookup does not carry (#329).
The operator may declare a parallel track at init when its footprint is
disjoint from the primary window: another repository, another artifact, or
provably non-overlapping clusters. The declaration names the boundary and any

3
changelog.d/229.md Normal file
View file

@ -0,0 +1,3 @@
### Changed
- Forge consumers now receive the upstream 0.6.1 and 0.6.2 doctrine for vendored-set routing, review-round signalling, operator-owned remainders, producer liveness, and post-merge release edges (#229).

View file

@ -246,7 +246,7 @@ sed 's/^panel=/panel=ghost-bot /' "$CONF" >"$mut_conf"
check "an identity in the conf but not the table goes red" 1 "ghost-bot" \
roster_in_sync "$mut_conf" "$CONTRIB"
# shellcheck disable=SC2016 # the backticks are the table's, not a subshell
sed 's/^| `glm-reviewer-andresmgsl`/| `ghost-bot`/' "$CONTRIB" >"$mut_contrib"
sed 's/^| `glm-bot-andresmgsl`/| `ghost-bot`/' "$CONTRIB" >"$mut_contrib"
check "an identity in the table but not the conf goes red" 1 "ghost-bot" \
roster_in_sync "$CONF" "$mut_contrib"