Decision process
Decision process
How Gemba captures, ratifies, and supersedes design + implementation decisions.
Why a separate process at all
Definition-of-Done blocks on a task bead are implementation scope — “what does done look like for this slice of work.” Decisions are guidepost scope — “what shape does the system have, going forward.”
Conflating the two hides decisions inside task descriptions, makes them un-discoverable later, and weakens the claim that “we decided X on date Y, here is why” — the kind of claim a future reader needs when they wonder if a constraint is still load-bearing.
Decisions get a separate type, a separate numbering convention, and a separate ceremony.
Lifecycle
draft ─────▶ in_review ─────▶ ratified (closed) │ └────────▶ rejected (closed)A ratified decision is never re-opened in place. To change course, file a new D# that explicitly supersedes the prior one.
| Stage | bd status | Label | Trigger |
|---|---|---|---|
| draft | open | d:draft | author creating the bead |
| in_review | open | d:in-review | author signals “ready” + files a gate dep |
| ratified | closed | d:ratified | the gate resolves with approval |
| rejected | closed | d:rejected | the gate resolves against the proposal |
| superseded | closed (was ratified) | d:superseded | a new D# files a supersedes edge |
Numbering — D#
- Every decision bead’s title carries a
D#:prefix (D1:,D2:, …,D14:). No zero-padding, no hyphen — matches the milestone convention (M1,M2). - A
d:#label mirrors the number for query (bd query "label=d:14"resolves the bead by handle). - Numbers are monotonically assigned at creation time and never reused. A superseded decision keeps its number.
- The bead’s own id (
gm-xxxxx) is canonical for tooling;D#is the human handle used in code comments, commit messages, and design-doc frontmatter.
Linkage — design doc ↔ decision bead
Every file under docs/design/*.md carries YAML frontmatter:
---title: Parallelism boundarydecision: gm-root.16 # bead id; OR "none"d: D9 # human handle when applicableratified_at: 2026-04-27 # set on close; mirrors bead history---Every decision bead’s description carries a Doc: line pointing at
the matching path under docs/design/, OR Doc: none when the
decision is meta and produces no doc.
A linter (make lint-decisions) validates both directions in CI:
every doc has frontmatter, every decision has a Doc: line, every
back-reference resolves. The linter is wired to run on every PR
that touches docs/design/ or modifies a decision bead.
Authoring a new decision
- Pick the next
D#. Run:bd query "label~d:" -a --json | jq '[.[] | .labels[] | select(startswith("d:")) | sub("d:";"") | tonumber] | max + 1' - Create the bead:
bd create --type decision \--title "D#: <topic>" \--priority 1 \--labels "decision,d:#,d:draft,fed:safe,risk:low,surface:docs"
- Write the description. Required sections:
- Goal — one paragraph
- Why now — context that makes the decision necessary
- Decision — what’s being chosen, with the rejected alternatives if relevant
- DoD — when do we consider this decision implemented
- Out of scope — what this decision deliberately does not cover
- Doc: — path to the design doc this decision will produce,
or
Doc: none
- (Optional but encouraged) File the companion design doc with the
matching
decision:frontmatter; commit both in the same PR.
Moving to in_review
bd label remove <id> d:draftbd label add <id> d:in-review- File a
gate-typed bead as a dependency, naming the approver(s) as assignees. The gate’s resolution drives the next step.
Ratifying
- The approver closes the gate with the consensus / approval note.
-
bd close <decision-id> -m "Ratified — <one-paragraph rationale>"
-
bd label remove <id> d:in-reviewbd label add <id> d:ratified
- The companion design doc is published (or already merged) with
ratified_at: <date>filled in.
Rejecting
- The gate closes against the proposal.
-
bd close <decision-id> -m "Rejected — <alternative chosen>"
bd label add <id> d:rejected. No design doc; the rejection note IS the artifact. Future readers find it viabd query "label=d:#".
Superseding
A ratified decision is never re-opened in place. To change course:
- File a new
D#with the new direction. -
bd dep add <new-id> supersedes:<old-id>
- Mark the old decision:
bd label add <old-id> d:superseded. - Update the companion design doc’s frontmatter:
superseded_by: <new-bead-id>
Worked examples
D4 — ratified
gm-sf51: D4: Insights data source — Prometheus proxy vs in-process retention. Ratified 2026-04-29 with close-reason naming Path A
(Prometheus proxy) as the chosen path. Companion doc not yet
published — the implementation epic that depends on it (gm-e9m0)
will produce it.
D6 — ratified
gm-d1m1: D6: Decision-capture convention. This document.
Ratified 2026-04-29 once the implementation epic gm-gas6 proved
the convention end-to-end (5 decisions migrated, 16 design docs
frontmatter’d, linter built + wired into CI). The epic was both
the gate AND the proof — atypical, but appropriate for a
meta-decision whose ratification is its successful application.
Rejected example
(none yet)
Superseded example
(none yet)
Where next
- The implementation epic for this convention:
gm-gas6. - Decision beads:
bd query "label=decision" -a. - The linter:
make lint-decisions(lands as part ofgm-gas6.3).