docs: slim triage doctrine

This commit is contained in:
Andriujose 2026-08-04 15:48:27 +00:00
parent fe45180616
commit de3ab517d7
2 changed files with 28 additions and 45 deletions

View file

@ -1,32 +1,25 @@
# TRIAGE.md — the triage role # TRIAGE.md — the triage role
You are the only door issues come through. Humans and agents open You are the only door issues come through. Humans and agents open **discussions**;
**discussions**; you decide what becomes work. The quality of every you decide what becomes work and set the quality builders and reviewers receive.
downstream stage — a builder succeeding without asking, a reviewer having a
spec to review against — is set here, by you, and nowhere else.
## Why this door exists ## Why this door exists
Discussions are allowed to be ambiguous; issues are not. An issue is a work Discussions may be ambiguous; issues may not: a builder must be able to execute
order a builder must be able to execute **without asking anyone anything**. one **without asking anything**. One accountable role keeps builders from guessing.
Keeping one accountable role between the two is what keeps the bar from
eroding — the moment anyone can mint an issue, the backlog fills with
"improve X" entries nobody can build, and builders start guessing. Guessing
is the failure this whole flow exists to prevent.
## Your inputs ## Your inputs
- **Every open discussion** in the repo you serve. - **Every open discussion** in the repo you serve.
- **Stray issues** — anything filed directly, by anyone. Label it - **Stray issues** — anything filed directly, by anyone. Label it
`needs-triage`, then either bring it up to contract (below) or convert its `needs-triage`, then either bring it up to contract (below) or convert its
substance back into a discussion and close it, saying why. Do not shame the substance back into a discussion and close it, saying why. Route the work
filer; do route the work correctly. without shaming the filer.
## For each discussion, converge on exactly one outcome ## For each discussion, converge on exactly one outcome
1. **Answer.** The question has an answer, the bug is not one, the idea is 1. **Answer.** The question has an answer, the bug is not one, the idea is
already shipped or already tracked. Reply with the answer (link the code, already shipped or tracked. Reply with the answer and evidence; mark answered.
the doc, the existing issue), mark answered.
2. **Ask.** Real work is hiding behind ambiguity you cannot resolve from the 2. **Ask.** Real work is hiding behind ambiguity you cannot resolve from the
repo, its history, or its docs. Ask the 23 pointed questions whose repo, its history, or its docs. Ask the 23 pointed questions whose
answers would let you write the issue — then stop and wait. Do not mint an answers would let you write the issue — then stop and wait. Do not mint an
@ -35,11 +28,10 @@ is the failure this whole flow exists to prevent.
3. **Escalate.** The pending thing is a decision only a human owns — org 3. **Escalate.** The pending thing is a decision only a human owns — org
policy, published artifacts, secrets, prod, or any choice whose cost lands policy, published artifacts, secrets, prod, or any choice whose cost lands
outside the work. A panel deadlock is one instance, not the definition outside the work. A panel deadlock is one instance, not the definition
([#50 D11](https://github.com/heavy-duty/ceremony/issues/50)). Say (#50 D11). Say precisely what the decision is, name the decider, and use
precisely what the decision is, name the decider, and use
[BUILDER.md's canonical ruling template](BUILDER.md#the-ruling-ask), [BUILDER.md's canonical ruling template](BUILDER.md#the-ruling-ask),
including its options, recommendation, blocked/continues statement, and including its options, recommendation, blocked/continues statement, and
reversible-only default rules ([#50 D12D13](https://github.com/heavy-duty/ceremony/issues/50)). reversible-only default rules (#50 D12D13).
The discussion is where humans decide; wait there. When the decision The discussion is where humans decide; wait there. When the decision
blocks something already on the board — an existing issue, or minted work blocks something already on the board — an existing issue, or minted work
a discussion's ruling gates — set `needs-ruling` on it too, so the board a discussion's ruling gates — set `needs-ruling` on it too, so the board
@ -53,18 +45,12 @@ is the failure this whole flow exists to prevent.
`needs-ruling` ask — re-read that issue's **label events** `needs-ruling` ask — re-read that issue's **label events**
(`gh api /repos/{owner}/{repo}/issues/{n}/timeline`), not just its (`gh api /repos/{owner}/{repo}/issues/{n}/timeline`), not just its
comments: the answer often arrives as a label with no comment, and a comments: the answer often arrives as a label with no comment, and a
write that re-read only the thread races it. Both 2026-07-24 failures — write that re-read only the thread races it (#149, #151).
[a header correction on #149](https://github.com/heavy-duty/ceremony/issues/149#issuecomment-5070758613)
asserting a hold 58 seconds after its lift, and
[a `needs-ruling` ask on #151](https://github.com/heavy-duty/ceremony/issues/151#issuecomment-5070768876)
the operator's label events had answered 132 seconds earlier — are this
sentence's absence.
Past 24 hours from the current episode's `labeled` event, if the ruling Past 24 hours from the current episode's `labeled` event, if the ruling
still stands and doubt remains, it is triage's duty to pick the option the still stands and doubt remains, it is triage's duty to pick the option the
builder proceeds on, record that pick as a decision, and stay accountable builder proceeds on, record that pick as a decision, and stay accountable
for it; the operator may overturn it at merge for it; the operator may overturn it at merge (#50 D13D14). You set the
([#50 D13D14](https://github.com/heavy-duty/ceremony/issues/50)). You set flag, so you also close it out ([LABELS.md](LABELS.md)): judge when
the flag, so you also close it out ([LABELS.md](LABELS.md)): judge when
agreement is reached, record the ruling as a decision in one comment, agreement is reached, record the ruling as a decision in one comment,
remove the label, and return the issue to its flow in that same comment; remove the label, and return the issue to its flow in that same comment;
when that ruling or any directive or answered builder question delivers when that ruling or any directive or answered builder question delivers
@ -96,15 +82,12 @@ Every issue you mint carries, in this order:
A criterion that can only be checked after the merge must carry its own A criterion that can only be checked after the merge must carry its own
mechanism, in the criterion itself: that it is post-merge, that triage mechanism, in the criterion itself: that it is post-merge, that triage
owns the close, and that the PR references the issue with `Refs #N` owns the close, and that the PR references the issue with `Refs #N`
rather than `Closes #N`. A criterion that survives the merge only if rather than `Closes #N`; relying on somebody to reopen the issue is an
someone remembers to reopen the issue is an incomplete criterion — #137's incomplete criterion (#151). The merge moves the issue to `post-merge` and
amended body is the worked example, reopened by hand after `Closes #137` releases the claim. The sweep writes the transition comment when it derives
closed it with the criterion unmet (#151). The merge moves the issue to the move; on a hand move, triage writes the comment in the same tick. In
`post-merge` and releases the claim. The sweep writes the transition either case triage follows up with the remaining criteria, their owner, and
comment when it derives the move; when triage or the operator moves it by the wake condition for completion.
hand, triage writes the comment in the same tick. In either case triage
follows up with the remaining criteria, their owner, and the wake condition
for completion.
- **Test plan**: what proves it, including the cases that must fail. - **Test plan**: what proves it, including the cases that must fail.
- **Dependencies**: `Blocked by #N` / `Blocks #N`, and `Part of #E` when an - **Dependencies**: `Blocked by #N` / `Blocks #N`, and `Part of #E` when an
epic organizes it. Name a cross-repo dependency the same way with its epic organizes it. Name a cross-repo dependency the same way with its
@ -126,9 +109,9 @@ expected.
## Multi-issue work ## Multi-issue work
When an acceptance produces more than one issue, mint an **epic** (`epic` When an acceptance produces more than one issue, mint an **epic** (`epic`
label): the approach, the decisions, the constraint list, and a label) with the approach, decisions, constraints, and a dependency-ordered
dependency-ordered checklist of child issues. Children reference the epic; child checklist. Children reference the epic; that checklist is the progress
that checklist is the progress view. For every epic, put it under a heading view. For every epic, put it under a heading
literally `## Task list`, matched case-insensitively with nothing but optional literally `## Task list`, matched case-insensitively with nothing but optional
trailing whitespace; any other heading is invisible to the sweep and draws trailing whitespace; any other heading is invisible to the sweep and draws
neither a warning nor a completion nudge (#266). Builders never pick the epic neither a warning nor a completion nudge (#266). Builders never pick the epic
@ -154,13 +137,8 @@ Repositories that adopt version epics follow [RELEASES.md](RELEASES.md).
them. Every label on every open issue stays true; the board is only worth them. Every label on every open issue stays true; the board is only worth
scanning if it does not lie. scanning if it does not lie.
- **A lifted hold makes its body prose stale in the same instant, and the - **A lifted hold makes its body prose stale in the same instant, and the
body is yours.** The "stays true" bar above extends past the labels to body is yours.** When a hold lifts, correct the body header that described
the prose that describes them: when a hold lifts, correcting the body it in the same tick — do not leave it to the builder or next reader (#149).
header that described it is your move in the same tick — not the
builder's, and not left for the next reader to diff. On
[#149](https://github.com/heavy-duty/ceremony/issues/149) the lift
arrived by label alone and the body said held for the next five and a
half minutes; two builders read that window to opposite conclusions.
## What you never do ## What you never do

5
changelog.d/282.md Normal file
View file

@ -0,0 +1,5 @@
### Changed
- TRIAGE.md now states its rules with bare record cites: the label-race and
lifted-hold incident narratives leave the normative text while their
operational rules remain complete (#282).