docs: replace discussion intake with proposals #262

Merged
andres merged 3 commits from build/247-proposal-intake into main 2026-08-25 15:09:51 +00:00
15 changed files with 96 additions and 88 deletions

View file

@ -1,19 +0,0 @@
# Light on purpose: discussions are where ambiguity is ALLOWED — a form
# that demands rigor at the door defeats the room's purpose (issue #24,
# decision 4). If these prompts fight the flow in practice, delete them
# before adding fields to them.
body:
- type: textarea
attributes:
label: What's the itch?
description: >-
Vague is fine — a bug, an idea, a "we should…". Triage turns this
into work (or an answer); you don't have to.
validations:
required: false
- type: textarea
attributes:
label: What would "done" feel like?
description: Optional — a sketch of the outcome, if you can already see it.
validations:
required: false

View file

@ -1,15 +0,0 @@
# Light on purpose — same reasoning as ideas.yml (issue #24, decision 4):
# optional prompts only, delete before hardening.
body:
- type: textarea
attributes:
label: What's the question?
description: Ask it plainly — context and links help, none are required.
validations:
required: false
- type: textarea
attributes:
label: What have you tried or read already?
description: Optional — saves the answerer a lap.
validations:
required: false

View file

@ -1,13 +1,12 @@
# The new-issue interception (issue #24, decision 1): interception over
# instruction — prose alone has already proven insufficient everywhere else
# in this org. With blank issues disabled and exactly one form, a "New
# issue" click shows the discussion link first; that auto-suggest is native
# GitHub behavior, no automation needed.
# in this org. Blank issues stay disabled; the proposal contact link gives
# non-triage filers a reachable route beside triage's work-order form. That
# chooser is native forge behavior, no automation needed.
blank_issues_enabled: false
contact_links:
- name: Ideas, bugs, questions — start a Discussion
url: https://github.com/heavy-duty/ceremony/discussions
- name: Ideas, bugs, questions — file a Proposal
url: https://forgejo.heavyduty.builders/heavy-duty/ceremony/issues/new?template=proposal.yml
about: >-
Humans (and agents) never file issues here — discussions are where
intent lives. Triage converges every discussion to an outcome, and
only triage mints issues (TRIAGE.md).
Anyone may file a proposal. Triage converts it into a work issue or
refuses it with reasons; only triage mints work issues (TRIAGE.md).

34
.github/ISSUE_TEMPLATE/proposal.yml vendored Normal file
View file

@ -0,0 +1,34 @@
# This intake form applies no labels: queue labels are triage's explicit act
# (LABELS.md), and the issue-flow sweep catches non-triage authors, so the form
# must not pre-judge the proposal's queue state (#24 D2).
name: Proposal (anyone)
description: >-
Share an idea, bug, question, or rough "we should…" for triage to convert
into work or refuse with reasons.
body:
- type: markdown
attributes:
value: >-
Proposals are the low-bar intake door. Say what you noticed and why it
might matter; triage will decide whether it becomes a work issue.
- type: textarea
id: noticed
attributes:
label: What did you notice?
description: A rough idea, bug, question, or "we should…" is enough.
validations:
required: true
- type: textarea
id: why-it-matters
attributes:
label: Why might it matter?
description: Optional — describe the impact or opportunity if you can.
validations:
required: false
- type: textarea
id: known-context
attributes:
label: What do you already know?
description: Optional — add links, examples, constraints, or prior art.
validations:
required: false

View file

@ -6,8 +6,8 @@
# that (issue #24, decision 2).
name: Work order (triage only)
description: >-
The issue contract (TRIAGE.md) as a form. Only triage mints issues —
everyone else starts a Discussion. Triage may still compose by hand when
The issue contract (TRIAGE.md) as a form. Only triage mints work issues —
everyone else files a proposal. Triage may still compose by hand when
the form fights it: `gh issue create --body-file` bypasses forms and stays
legitimate for the triage identity.
body:
@ -25,7 +25,7 @@ body:
attributes:
label: Context
description: >-
Why this exists, with links — the discussion it came from, the code
Why this exists, with links — the proposal it came from, the code
it touches (permalinks at a pinned SHA, so line references cannot
rot), prior art in sibling repos.
validations:

View file

@ -14,7 +14,7 @@ reviewer here"). That one word is your whole onboarding:
| you are the… | read | your job in one line |
|---|---|---|
| **triage** agent | [TRIAGE.md](TRIAGE.md) | turn discussions into buildable issues — or refuse well; you are the only door issues come through |
| **triage** agent | [TRIAGE.md](TRIAGE.md) | turn proposals into buildable work issues — or refuse well; you are the only door work issues come through |
| **builder** agent | [BUILDER.md](BUILDER.md) | turn one `ready` issue into one PR that meets its acceptance criteria |
| **reviewer** agent | [REVIEWER.md](REVIEWER.md) | verdicts on PRs — approve or request-changes, converge, hand to the human |
@ -23,7 +23,7 @@ are the shared state machine, and misusing one lies to every other agent on
the board.
**Not told a role?** Infer it from the task: asked to review a PR → reviewer;
asked to implement an issue → builder; asked to process discussions or the
asked to implement an issue → builder; asked to process proposals or the
backlog → triage. Still ambiguous → ask before acting. Do not free-lance
across roles in one session: a builder reviewing its own PR, or a reviewer
pushing fixes, breaks the separation the pipeline depends on.
@ -31,13 +31,13 @@ pushing fixes, breaks the separation the pipeline depends on.
## The pipeline you are part of
```
discussion ──▶ triage ──▶ issue ──▶ build ──▶ review ──▶ human merge ──▶ release
(anyone) (agent) (queue) (agent) (agents) (human) (ceremony)
proposal ──▶ triage ──▶ work issue ──▶ build ──▶ review ──▶ human merge ──▶ release
(anyone) (agent) (queue) (agent) (agents) (human) (ceremony)
```
Two rules bind every role:
- **Only triage mints issues.** Found work? Open or extend a discussion.
- **Only triage mints work issues.** Found work? File or extend a proposal.
- **Only humans merge.** Convergence ends at `state:needs-human`, never at
a merge button.

View file

@ -140,8 +140,8 @@ triage bug, and the move is to say so on the issue, not to guess.
its red-flag profile are in REVIEWER.md §What you review against, item 2
(#216).
- **Scope discipline: the PR does the issue — whole, and nothing else.**
Adjacent problems go to a discussion, or a comment on the relevant issue;
you do not mint issues — nobody but triage does — and you do not fix
Adjacent problems go to a proposal, or a comment on the relevant issue;
you do not mint work issues — nobody but triage does — and you do not fix
drive-by findings in the same PR.
## The review round

View file

@ -10,22 +10,22 @@ the two is a bug.
Work moves through one pipeline, and every stage has an owner:
```
discussion ──▶ triage ──▶ issue ──▶ build ──▶ review ──▶ human merge ──▶ release
(anyone) (agent) (queue) (agent) (agents) (human) (ceremony)
proposal ──▶ triage ──▶ work issue ──▶ build ──▶ review ──▶ human merge ──▶ release
(anyone) (agent) (queue) (agent) (agents) (human) (ceremony)
```
- **Discussions are where intent lives.** Anyone — human or agent — who has an
idea, a bug, a question, or a "we should…" opens a **discussion**, not an
issue. Discussions are allowed to be vague; that is what they are for.
- **Issues are minted only by triage.** Nobody else writes issues — not
humans, not builders, not reviewers. An issue is a work order with a quality
- **Proposals are where intent lives.** Anyone — human or agent — who has an
idea, a bug, a question, or a "we should…" files a **proposal**, not a work
issue. Proposals are allowed to be vague; that is what they are for.
- **Work issues are minted only by triage.** Nobody else writes work issues —
not humans, not builders, not reviewers. A work issue is a work order with a quality
bar (the issue contract in [TRIAGE.md](TRIAGE.md)), and the bar holds
because exactly one role is accountable for it. An issue that appears
through any other door gets `needs-triage` and is normalized or converted
back into a discussion.
back into a proposal.
- **Builders turn one issue into one PR.** [BUILDER.md](BUILDER.md).
- **Reviewers converge on a verdict.** [REVIEWER.md](REVIEWER.md).
- **Humans decide twice**: in the discussion (what is worth doing, and any
- **Humans decide twice**: in the proposal (what is worth doing, and any
call triage escalates back) and at the merge (whether it ships). Everything
between those two points is agent work by default.
- **Merging a release PR ships it** — the release ceremony this repo's
@ -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 |
|---|---|---|
| `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. |
| `claude-bot-andresmgsl` | `triage` (claude-box) | **triage** — the only door work issues come through; this identity mints work 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 |
@ -62,7 +62,7 @@ panel-minus-author, and three is what it currently comes to, not a second
rule. Builders and triage default to different models so the issue contract
is honestly exercised — a spec gap should surface as a question on the
issue, not be silently filled by shared priors. Humans (`andres`) decide in
discussions and merge; the roster is config, not doctrine — swapping a
proposals and merge; the roster is config, not doctrine — swapping a
vendor is an edit to this table (and to `panel=` in
`.github/labels.conf` once #10 lands), nothing more.
@ -143,7 +143,8 @@ A governed repo (box, rig, cast, incubator, …) therefore carries:
- the **`scope:*` label set** (`.github/labels.conf` + `.github/labeler.yml`),
- the **drill meaning** (`drills/README.md`),
- the repo's own code conventions;
- **Discussions enabled**, so the triage door exists.
- **An intake door is open**: install the proposal form and `needs-triage`
flow, or use a forge-native intake surface.
One pin governs both the machinery and the doctrine: the ref a repo's
workflows call is the ref its `.ceremony/` mirror is verified against.

View file

@ -136,7 +136,7 @@ The earlier form of this file folded handoff and rebase into the other
builder wakes; they are duties of their own.
- **Triage signals**, per registry repo: `needs-triage` issues,
queue-unlabeled strays, discussions without triage's voice, unread
queue-unlabeled strays, proposals without triage's voice, unread
`@`-mentions (their own session), and `blocked` issues whose named blockers
have all landed — a lead the session verifies, never a label the engine
flips. Backlog hygiene (stale claims, label invariants) runs hourly,

View file

@ -51,7 +51,7 @@ strips it on sight).
| Label | Color | Means | Set by |
|---|---|---|---|
| `needs-triage` | `#FBCA04` | an issue that did not come through triage — it owes normalization or conversion back to a discussion | anyone who spots one; cleared by triage |
| `needs-triage` | `#FBCA04` | a proposal or stray issue that did not come through triage — it owes normalization into work or a reasoned refusal | anyone who spots one; cleared by triage |
| `ready` | `#0E8A16` | triaged, spec complete, unblocked — a builder can start now and succeed | triage |
| `claimed` | `#1D76DB` | a builder owns it: assignee set, a draft PR expected shortly | the claiming builder |
| `blocked` | `#6A737D` | waiting on another issue or PR (`Blocked by #N` in the body names it) | triage; anyone may correct it |
@ -242,4 +242,4 @@ full-board reconcile. The sweep warns when the core taxonomy declares a label
the repository lacks. The same workflow reconciles issue-flow labels on issue
events and during the scheduled sweep. Default GitHub labels (`duplicate`,
`invalid`, `question`, `wontfix`, `help wanted`, `good first issue`) are
deleted at bootstrap — a `question` is a discussion, not an issue.
deleted at bootstrap — a `question` belongs in a proposal, not a work issue.

View file

@ -151,7 +151,7 @@ window stops advancing along that edge (#329).
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).
mints work 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

View file

@ -123,9 +123,9 @@ saw Y" outranks one that says "this looks like it might".
## What you do not do
- **Re-litigate the spec.** The issue's decisions were made in triage and,
above it, in a discussion where humans had their say. If you think the
above it, in a proposal where humans had their say. If you think the
spec itself is wrong, say so with reasons — as a comment pointing at the
discussion, while still reviewing the implementation against the spec as
proposal, while still reviewing the implementation against the spec as
written. Spec changes go through triage, not through a review round.
- **Merge, or tell the builder to merge.** Convergence hands the PR to a
human; only humans merge.

View file

@ -1,22 +1,25 @@
# TRIAGE.md — the triage role
You are the only door issues come through. Humans and agents open **discussions**;
you decide what becomes work and set the quality builders and reviewers receive.
You are the only door work issues come through. Humans and agents file
**proposals**; you decide what becomes work and set the quality builders and
reviewers receive.
## Why this door exists
Discussions may be ambiguous; issues may not: a builder must be able to execute
one **without asking anything**. One accountable role keeps builders from guessing.
Proposals may be ambiguous; work issues may not: a builder must be able to
execute one **without asking anything**. One accountable role keeps builders
from guessing.
## Your inputs
- **Every open discussion** in the repo you serve.
- **Stray issues** — anything filed directly, by anyone. Label it
- **Every open proposal** in the repo you serve.
- **Stray issues** — anything filed outside the proposal form by a non-triage
actor. Label it
`needs-triage`, then either bring it up to contract (below) or convert its
substance back into a discussion and close it, saying why. Route the work
substance into a proposal and close it, saying why. Route the work
without shaming the filer.
## For each discussion, converge on exactly one outcome
## For each proposal, converge on exactly one outcome
1. **Answer.** The question has an answer, the bug is not one, the idea is
already shipped or tracked. Link the code, doc, or issue; mark answered.
@ -32,9 +35,9 @@ one **without asking anything**. One accountable role keeps builders from guessi
[BUILDER.md's canonical ruling template](BUILDER.md#the-ruling-ask),
including its options, recommendation, blocked/continues statement, and
reversible-only default rules (#50 D12D13).
The discussion is where humans decide; wait there. When the decision
The proposal is where humans decide; wait there. When the decision
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 proposal's ruling gates — set `needs-ruling` on it too, so the board
shows where the human's turn is; the issue keeps its queue label.
When you direct a builder to hold a claim, say the claim is **parked**,
name what it waits on, and set `attention` so the assignee's ack is visible
@ -61,7 +64,7 @@ one **without asking anything**. One accountable role keeps builders from guessi
This is not a substitute for minting work or for `needs-ruling`.
4. **Decline.** Real idea, wrong repo or wrong time. Say why plainly, link
where it belongs if anywhere, close. A refusal with reasons is a good
outcome; a zombie discussion is not.
outcome; a zombie proposal is not.
5. **Accept.** It justifies work → mint the issue(s). The contract below is
the bar.
@ -71,7 +74,7 @@ Every issue you mint carries, in this order:
- **A title that names the deliverable** — "lib/version.sh — one version
abstraction, two backends", never "improve version handling".
- **Context**: why this exists, with links — the discussion it came from,
- **Context**: why this exists, with links — the proposal it came from,
the code it touches (permalinks at a pinned SHA, so line references cannot
rot), prior art in sibling repos.
- **The spec**: decisions made, not options listed. If the spec still has an
@ -159,4 +162,4 @@ Repositories that adopt version epics follow [RELEASES.md](RELEASES.md).
- Assign a builder — builders pick and claim ([BUILDER.md](BUILDER.md)).
- Make the human's decisions (outcome 3 exists for those), or soften a
refusal into a vague issue to avoid saying no.
- Mint an issue to "discuss" something — that is a discussion.
- Mint a work issue to explore an idea — file a proposal instead.

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

@ -0,0 +1,3 @@
### Changed
- Replace the unavailable intake rule with a proposal form that triage converts into work or refuses with reasons (#247).

View file

@ -605,7 +605,7 @@ goes down. Add the row only at or after the pin bump that carries it, never
before it and never through mixed refs.
Both actor lists are whitespace-separated. `triage-actors` names the identities
allowed to mint issues without the sweep applying `needs-triage`. Label rows use exactly
allowed to mint work issues without the sweep applying `needs-triage`. Label rows use exactly
`name|color|description`; blank lines are ignored and extra pipes are refused.
**Every account in `panel=` must be able to read the repository.** Requesting a
@ -851,15 +851,16 @@ published release.
## Adopting the agent team flow
The team flow (discussion → triage → issue → build → review → human
The team flow (proposal → triage → work issue → build → review → human
merge) is **optional per repo and separable from the release ceremony**:
a repo can adopt release-only and take the team flow later — incubator's
initial posture (#16). The model is this repo's own
[CONTRIBUTING](../CONTRIBUTING.md) ("How the other repos use this");
this is the checklist:
- [ ] **Enable Discussions** — the triage door exists or the pipeline
has no intake.
- [ ] **Open the intake door** — install `proposal.yml` and the automatic
`needs-triage` flow. A repo whose forge provides Discussions may keep
them as its intake door and point `config.yml`'s contact link there.
- [ ] **Vendor the doctrine**: run `docs-sync --fix` (#19) to materialize
`.ceremony/{AGENTS,TRIAGE,BUILDER,REVIEWER,LABELS}.md`
byte-identical to this repo at the pinned ref — plus the generated
@ -893,7 +894,8 @@ this is the checklist:
`workflow_dispatch` once ([above](#labels-automation)), or the hand
commands in [LABELS.md](../LABELS.md).
- [ ] **State the single-writer rule** in the repo's own docs: only
triage mints issues; everyone else opens discussions.
triage mints work issues; anyone may file a proposal, which triage
converts or refuses.
### The pin-bump procedure