Merge pull request #190 from claude-bot-andresmgsl/build/189-ci-red-doctrine
docs: the check at the head — round precondition, CI-red recovery, and the ci-red wake on paper
This commit is contained in:
commit
e3820dbf9a
3 changed files with 114 additions and 12 deletions
80
BUILDER.md
80
BUILDER.md
|
|
@ -11,6 +11,27 @@ triage bug, and the move is to say so on the issue, not to guess.
|
||||||
- Respect dependency order: inside an epic, take the earliest unblocked
|
- Respect dependency order: inside an epic, take the earliest unblocked
|
||||||
unclaimed child. Between epics and strays, prefer the issue that unblocks
|
unclaimed child. Between epics and strays, prefer the issue that unblocks
|
||||||
the most other work.
|
the most other work.
|
||||||
|
- **Your own red head outranks a new claim.** A failing check at the head
|
||||||
|
of a PR you authored is picked up **before claiming another issue** —
|
||||||
|
repairing your own red PR comes ahead of new work, which is why the
|
||||||
|
engine's duty order evaluates ci-red between resume and build (crew#17:
|
||||||
|
ceremony#163 sat with full-panel approvals at its head, mergeable, and
|
||||||
|
stranded on an HTTP 429 in a job that never ran the PR's code, because no
|
||||||
|
wake covered a red head that owed no round and had no conflict). Red and
|
||||||
|
green here are the ruled terms of the review round below: a cancelled or
|
||||||
|
stale check is not a green head; a skipped or neutral one is. The
|
||||||
|
recovery path (crew#17): inspect the check at the head and record the
|
||||||
|
failing check and its failure class; rerun a clearly retryable
|
||||||
|
infrastructure failure without changing code; when the failure belongs to
|
||||||
|
the branch, return to the normal fix-round and worklog discipline; leave
|
||||||
|
visible evidence when a rerun cannot be started or the cause is
|
||||||
|
uncertain; never repeatedly rerun a deterministic branch failure without
|
||||||
|
a corrective commit; and proceed to handoff once the check is green and
|
||||||
|
current-head approvals stand. A PR of yours with a red head is **not
|
||||||
|
parked** — the next move is yours, whatever the round's verdict state
|
||||||
|
says (shape 2 below carves this out explicitly). How the engine detects a red
|
||||||
|
head — its ledger, its quiet rules, the rollup's node shapes — is crew's
|
||||||
|
to describe, not this file's.
|
||||||
- **One build at a time.** You hold at most one issue on which you are
|
- **One build at a time.** You hold at most one issue on which you are
|
||||||
writing or revising a deliverable — finish or release that work before
|
writing or revising a deliverable — finish or release that work before
|
||||||
starting new work. The rule counts build work in flight, not claims: a
|
starting new work. The rule counts build work in flight, not claims: a
|
||||||
|
|
@ -20,9 +41,16 @@ triage bug, and the move is to say so on the issue, not to guess.
|
||||||
its `Blocked:` line stops the remaining work;
|
its `Blocked:` line stops the remaining work;
|
||||||
2. the deliverable is in a review round where every outstanding verdict
|
2. the deliverable is in a review round where every outstanding verdict
|
||||||
belongs to someone else — either the round is awaiting its first
|
belongs to someone else — either the round is awaiting its first
|
||||||
verdicts, or it was answered whole and the non-approvers re-requested
|
verdicts, or it was answered whole and the owed re-requests posted —
|
||||||
(the review round, steps 1–2). This is the *live* round; shape 4 is
|
by head, not by verdict: every panelist after a push, the
|
||||||
the *passed* one — they are sequential and do not overlap;
|
non-approvers alone at an unchanged head (the review round, steps
|
||||||
|
1–2). This is the *live* round; shape 4 is
|
||||||
|
the *passed* one — they are sequential and do not overlap. A red
|
||||||
|
check at the current head takes the deliverable **out of this
|
||||||
|
shape**: mid-round CI going red is exactly the state that reads as
|
||||||
|
"waiting on the panel" and is not — the next move is yours (the
|
||||||
|
red-head rule above), and reading it as parked is what strands the
|
||||||
|
PR;
|
||||||
3. every remaining acceptance criterion is operator-owned, stated as such
|
3. every remaining acceptance criterion is operator-owned, stated as such
|
||||||
by triage on the issue;
|
by triage on the issue;
|
||||||
4. the deliverable is **handed off** — the round passed, no `blocker:*`
|
4. the deliverable is **handed off** — the round passed, no `blocker:*`
|
||||||
|
|
@ -53,7 +81,8 @@ triage bug, and the move is to say so on the issue, not to guess.
|
||||||
that, or, if the events genuinely do not resolve it, say so on the
|
that, or, if the events genuinely do not resolve it, say so on the
|
||||||
issue and pick the next `ready` issue rather than idling on this one.
|
issue and pick the next `ready` issue rather than idling on this one.
|
||||||
Not parked — these are what the rule defends against: waiting on
|
Not parked — these are what the rule defends against: waiting on
|
||||||
yourself, waiting on CI, or waiting for a good moment. An issue you have
|
yourself, waiting on CI (a red head is your own work, above; a pending
|
||||||
|
one resolves without you), or waiting for a good moment. An issue you have
|
||||||
simply stopped working on is not parked either — that is abandonment,
|
simply stopped working on is not parked either — that is abandonment,
|
||||||
and its move is unchanged: unassign and restore `ready` (Claiming,
|
and its move is unchanged: unassign and restore `ready` (Claiming,
|
||||||
below).
|
below).
|
||||||
|
|
@ -194,9 +223,48 @@ CONTRIBUTING; everything below is the shared flow.)
|
||||||
does not become required. On rig#112 this distinction mattered: requesting
|
does not become required. On rig#112 this distinction mattered: requesting
|
||||||
codex and grok was correct for rig's panel even though ceremony's bench was
|
codex and grok was correct for rig's panel even though ceremony's bench was
|
||||||
larger, and the doctrine had not said which roster governed.
|
larger, and the doctrine had not said which roster governed.
|
||||||
|
**A review request requires a green check at the head.** A red check is
|
||||||
|
the author's own signal, not the panel's work: if the check is red, that
|
||||||
|
is your next task, not the panel's — fix it and push, then request. This
|
||||||
|
binds *you*, whether or not any engine enforces it. "My local suite
|
||||||
|
passed" is evidence about your machine; the check at the head is the
|
||||||
|
shared artifact the panel actually reads, and a reviewer's first act is
|
||||||
|
to read it. The one exception is a failure genuinely outside the PR — a
|
||||||
|
runner outage, a flaky dependency, a failure already present on the
|
||||||
|
default branch — and it is an exception only if the request says so
|
||||||
|
explicitly and names the evidence (e.g. "the same job fails identically
|
||||||
|
on `origin/main` at `<sha>`"). Silence about a red check is what is
|
||||||
|
prohibited; an argued exception shifts the burden to the author.
|
||||||
|
*Green* is a ruled term (operator, 2026-07-27): a **cancelled or
|
||||||
|
stale** check is not a green head — the rollup is scoped to the current
|
||||||
|
head, so what survives there is same-head cancellation, not
|
||||||
|
supersession by a newer push — while a **skipped or neutral** one *is*
|
||||||
|
green: those are deliberate "passed / not applicable" conclusions, and
|
||||||
|
reddening them would red every conditional job the fleet skips on
|
||||||
|
purpose. The costs behind the line are asymmetric: a false green spends
|
||||||
|
a three-reviewer round; a false red spends one author session.
|
||||||
2. **Wait for every verdict, then answer the round whole** — one reply
|
2. **Wait for every verdict, then answer the round whole** — one reply
|
||||||
covering every point, then push the fixes, then re-request exactly the
|
covering every point, then push the fixes, then re-request **by head,
|
||||||
reviewers who did not approve. Prefer verification over argument: when a
|
not by verdict**: if answering the round pushed any commit, every
|
||||||
|
panelist's approval is now stale — an approval is of a specific tree,
|
||||||
|
and the handoff predicate counts only approvals at the current head —
|
||||||
|
so **every panelist is re-requested, the approvers included**; a
|
||||||
|
panelist left un-re-requested after a push can never approve the tree
|
||||||
|
you shipped, and the PR sits looking finished with a full set of
|
||||||
|
verdicts and nothing owed by anyone, the same silent-stall shape as
|
||||||
|
[#26](https://github.com/heavy-duty/ceremony/issues/26)/[#39](https://github.com/heavy-duty/ceremony/issues/39).
|
||||||
|
Only when the head did not move — the round was answered with argument
|
||||||
|
or evidence and nothing was pushed — do you re-request just the
|
||||||
|
non-approvers: a standing approval already covers this exact head, and
|
||||||
|
the engine absorbs a re-request at an unchanged head (the re-request
|
||||||
|
rule, [#94](https://github.com/heavy-duty/ceremony/issues/94); its
|
||||||
|
mechanism is crew's to describe). **The re-request carries the same
|
||||||
|
green-check-at-head precondition as the first request**, argued
|
||||||
|
exception included. This is where the measured cost landed: crew#40
|
||||||
|
burned two consecutive heads and four reviewer-rounds, every one
|
||||||
|
relaying a CI failure already visible in the job log (crew#45). A fix
|
||||||
|
push whose check comes up red is not ready to go back to the panel; it
|
||||||
|
is your next fix. Prefer verification over argument: when a
|
||||||
reviewer doubts behavior, add the test that settles it.
|
reviewer doubts behavior, add the test that settles it.
|
||||||
3. Never dismiss a review, never merge, never mark your own work as passed.
|
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
|
A blocking point you disagree with is answered with evidence or escalated
|
||||||
|
|
|
||||||
30
FLEET.md
30
FLEET.md
|
|
@ -132,9 +132,13 @@ wake is no longer on paper: `duty-attention.sh` is deployed engine, and
|
||||||
|
|
||||||
The engine's duty order is fleet-standard
|
The engine's duty order is fleet-standard
|
||||||
([`bin/duty.sh`](https://github.com/heavy-duty/crew/blob/01fb49cd717a0f4c83df286af86411c69e3c2363/shared/bin/duty.sh)):
|
([`bin/duty.sh`](https://github.com/heavy-duty/crew/blob/01fb49cd717a0f4c83df286af86411c69e3c2363/shared/bin/duty.sh)):
|
||||||
**attention → triage signals → review queue → resume → build → handoff →
|
**attention → triage signals → review queue → resume → ci-red → build →
|
||||||
rebase → worktree hygiene → backlog hygiene (hourly)** — attention
|
handoff → rebase → worktree hygiene → backlog hygiene (hourly)** — attention
|
||||||
role-independent and first, then each duty family the box's roles enable.
|
role-independent and first, then each duty family the box's roles enable.
|
||||||
|
One position in that order is **on paper**: ci-red is
|
||||||
|
[crew#64](https://github.com/heavy-duty/crew/pull/64)'s, unmerged at the
|
||||||
|
stamped SHA, where `duty.sh` still runs resume straight into build — it
|
||||||
|
reads as deployed engine only once that PR merges.
|
||||||
The earlier form of this file folded handoff and rebase into the other
|
The earlier form of this file folded handoff and rebase into the other
|
||||||
builder wakes; they are duties of their own.
|
builder wakes; they are duties of their own.
|
||||||
|
|
||||||
|
|
@ -163,10 +167,23 @@ builder wakes; they are duties of their own.
|
||||||
— a session died between first push and PR creation. A branch whose PR
|
— a session died between first push and PR creation. A branch whose PR
|
||||||
already **merged** is a post-merge wait, never resumed (#172,
|
already **merged** is a post-merge wait, never resumed (#172,
|
||||||
incubator#55/#64).
|
incubator#55/#64).
|
||||||
|
- **ci-red** (builders; **on paper** — crew#64's spec, unmerged at the
|
||||||
|
stamped SHA): a non-draft PR of mine whose check at the current head is
|
||||||
|
failing. Evaluated before the build wake, so a red PR of mine outranks a
|
||||||
|
new claim — repairing my own red head comes ahead of new work
|
||||||
|
(ceremony#163: full-panel approvals at the head, mergeable, stranded on
|
||||||
|
a transient failure no wake covered). A round owed at a red head is
|
||||||
|
excluded from the build wake below but reported rather than silent, and
|
||||||
|
an unchanged red head goes quiet after one attempt, through the
|
||||||
|
`report_suppressed` path — suppressed, still said. How a red head is
|
||||||
|
detected and kept quiet is the engine's mechanism, described in crew's
|
||||||
|
`shared/README.md`, not here.
|
||||||
- **Build**: a `ready` **unclaimed** issue (an assignee means mid-claim, not
|
- **Build**: a `ready` **unclaimed** issue (an assignee means mid-claim, not
|
||||||
pickable), or a completed review round on my PR — a changes-request with
|
pickable), or a completed review round on my PR — a changes-request with
|
||||||
no panel review request still outstanding; whole rounds, never single
|
no panel review request still outstanding; whole rounds, never single
|
||||||
verdicts.
|
verdicts, and — once ci-red deploys — never a round at a red head: that
|
||||||
|
head has already woken ci-red above, and the excluded round is reported,
|
||||||
|
not swallowed.
|
||||||
- **Handoff**: a round of mine that converged — every panelist's latest
|
- **Handoff**: a round of mine that converged — every panelist's latest
|
||||||
opinionated review approves the current head, no panel request
|
opinionated review approves the current head, no panel request
|
||||||
outstanding, mergeable right now, `state:needs-human` not already set.
|
outstanding, mergeable right now, `state:needs-human` not already set.
|
||||||
|
|
@ -231,9 +248,10 @@ The duty engine is crew's shared tree, one source deployed to every box;
|
||||||
makes the registry rule an operator decision rather than a sweep's. Specs
|
makes the registry rule an operator decision rather than a sweep's. Specs
|
||||||
written in this file have a record of becoming engine: the attention wake
|
written in this file have a record of becoming engine: the attention wake
|
||||||
and the reviewers' request sweep both started here as paper (the sweep's
|
and the reviewers' request sweep both started here as paper (the sweep's
|
||||||
org-wide form was then retired by the 2026-07-25 scope ruling). The
|
org-wide form was then retired by the 2026-07-25 scope ruling). Two are
|
||||||
notifier's `needs-ruling` queue is the one still on paper: at the stamped
|
still on paper: the notifier's `needs-ruling` queue — at the stamped crew
|
||||||
crew SHA, `notify.sh`'s only label filter is `state:needs-human`.
|
SHA, `notify.sh`'s only label filter is `state:needs-human` — and the
|
||||||
|
builders' ci-red wake above, engine the moment crew#64 merges.
|
||||||
|
|
||||||
### Conventions on the board
|
### Conventions on the board
|
||||||
|
|
||||||
|
|
|
||||||
16
changelog.d/189.md
Normal file
16
changelog.d/189.md
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- `BUILDER.md` gates both review-request points on a green check at the
|
||||||
|
head, carries crew#45's argued exception for failures outside the PR,
|
||||||
|
and states the ruled classification: cancelled and stale are not a
|
||||||
|
green head; skipped and neutral are (#189).
|
||||||
|
- `BUILDER.md` documents CI-red recovery in pickup precedence: a red head
|
||||||
|
of your own PR is picked up before claiming another issue, is never a
|
||||||
|
parked claim, and follows crew#17's recovery path (#189).
|
||||||
|
- `FLEET.md` writes the ci-red wake into the duty order between resume
|
||||||
|
and build, marked on paper until crew#64 merges, with the
|
||||||
|
reconciliation stamp unchanged (#189).
|
||||||
|
- `BUILDER.md` re-requests by head, not by verdict: a push while
|
||||||
|
answering a round stales every approval, so every panelist is
|
||||||
|
re-requested; only an unchanged head re-requests the non-approvers
|
||||||
|
alone (#190).
|
||||||
Loading…
Reference in a new issue