diff --git a/BUILDER.md b/BUILDER.md index ac9e0c3..50878ff 100644 --- a/BUILDER.md +++ b/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 unclaimed child. Between epics and strays, prefer the issue that unblocks 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 writing or revising a deliverable — finish or release that work before 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; 2. the deliverable is in a review round where every outstanding verdict belongs to someone else — either the round is awaiting its first - verdicts, or it was answered whole and the non-approvers re-requested - (the review round, steps 1–2). This is the *live* round; shape 4 is - the *passed* one — they are sequential and do not overlap; + verdicts, or it was answered whole and the owed re-requests posted — + by head, not by verdict: every panelist after a push, the + 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 by triage on the issue; 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 issue and pick the next `ready` issue rather than idling on this one. 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, and its move is unchanged: unassign and restore `ready` (Claiming, below). @@ -194,9 +223,48 @@ CONTRIBUTING; everything below is the shared flow.) 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 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 ``"). 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 - covering every point, then push the fixes, then re-request exactly the - reviewers who did not approve. Prefer verification over argument: when a + covering every point, then push the fixes, then re-request **by head, + 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. 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 diff --git a/FLEET.md b/FLEET.md index ac0beba..ba6e677 100644 --- a/FLEET.md +++ b/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 ([`bin/duty.sh`](https://github.com/heavy-duty/crew/blob/01fb49cd717a0f4c83df286af86411c69e3c2363/shared/bin/duty.sh)): -**attention → triage signals → review queue → resume → build → handoff → -rebase → worktree hygiene → backlog hygiene (hourly)** — attention +**attention → triage signals → review queue → resume → ci-red → build → +handoff → rebase → worktree hygiene → backlog hygiene (hourly)** — attention 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 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 already **merged** is a post-merge wait, never resumed (#172, 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 pickable), or a completed review round on my PR — a changes-request with 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 opinionated review approves the current head, no panel request 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 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 -org-wide form was then retired by the 2026-07-25 scope ruling). The -notifier's `needs-ruling` queue is the one still on paper: at the stamped -crew SHA, `notify.sh`'s only label filter is `state:needs-human`. +org-wide form was then retired by the 2026-07-25 scope ruling). Two are +still on paper: the notifier's `needs-ruling` queue — at the stamped crew +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 diff --git a/changelog.d/189.md b/changelog.d/189.md new file mode 100644 index 0000000..d29e76f --- /dev/null +++ b/changelog.d/189.md @@ -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).