wdi-method 0.6.1 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -22,7 +22,12 @@ created: '{YYYY-MM-DD}'
22
22
 
23
23
  Do not confuse this with AD-N in the architecture spine, which is a living rule edited in place.
24
24
 
25
- Add `type:` to the frontmatter when it is useful — `risk-acceptance`, `course-correction`. -->
25
+ Add `type:` to the frontmatter when it is useful — `risk-acceptance`, `course-correction`. A `mandate`
26
+ is the one type with a fixed shape: `wdi-autopilot` opens it, its parameters live under `mandate:` on the
27
+ registry row only, and its `accepted_by` is a person and a date — never another DEC-.
28
+
29
+ `accepted_by:` — who raised this to `accepted`: a person and a date, or the `DEC-` of the mandate that
30
+ delegated it. Leave it out at `draft`. -->
26
31
 
27
32
  ## Decision
28
33
 
@@ -1,182 +1,183 @@
1
- ---
2
- status: Accepted
3
- ---
4
-
5
- # Method Glossary
6
-
7
- **Loaded when:** a method term is unclear, and before coining a new one.
8
-
9
- The words this method uses for **itself**. What the product is about belongs to
10
- `.control/product-glossary.md` instead. A term defined here MUST NOT be redefined there, and the
11
- reverse holds too. The test: would this term still apply on a different product? Yes → here.
12
-
13
- ## Layers
14
-
15
- | Term | Means |
16
- |---|---|
17
- | **Corpus** | The four layers below. `_bmad-output/` is not part of it |
18
- | **`.constitution/`** | How we work. Rules. Rarely changes |
19
- | **`.control/`** | What currently holds and what has been decided. Facts. Changes often. Equals `{project_knowledge}` |
20
- | **`.what/`** | What was promised |
21
- | **`.how/`** | How it is built |
22
- | **Workspace** | `_bmad-output/` — work in progress, committed but not curated |
23
- | **Placement test** | Is this file still true after its spec has passed? Yes → corpus. No → workspace |
24
-
25
- ## Units
26
-
27
- | Term | Means |
28
- |---|---|
29
- | **Product Component** (PC) | A domain slice — the box at C4 L3. Lives in `.what/<pc>/` and `.how/<pc>/`, and its `containers:` says where it runs |
30
- | **Logical Component** (LC) | One addressable unit of build. Registered in `components.yaml` with `type` · `container` · `owner` · `area` |
31
- | **Container** | Something that **runs its own code or stores its own data** and can be replaced without rebuilding another one. The C4 L2 term, and the value of an LC's `container` field. Two questions decide it and both MUST be yes — `architecture-guide.md` owns the test. Shipping two containers in one release does **not** merge them |
32
- | **`built`** | A container's one boolean. `true` when we write what is inside it, `false` when we deploy someone else's implementation. It decides whether the container gets an L3, an `LC`, and a heading in the codebase map — `container-built` checks all three |
33
- | **External system** | Something the product talks to whose **runtime we do not deploy**. It belongs at C4 L1, and MUST NOT be a container, an `LC`'s `container`, or a heading in the codebase map. What we lean on it for lives in `cross-cutting.md` or an integration contract |
34
- | **`_platform`** | **Not a component.** The home for what belongs to no Product Component: the spine, the C4 set, `cross-cutting.md`, the three inventories, and whatever it **owns**. A legitimate value in every position that asks which component owns something — `platform_owns`, an inventory row, an `LC`. Four kinds today: data · endpoint · job · screen. It carries no `mode`, no `risk_accepted`, and no G4 |
35
- | **Library** | An includable artifact — compiled into or imported by something else, never run on its own. Not a container |
36
- | **Slot** | A numbered sub-folder of a PC. `.what/<pc>/` 02–05 is reading order; `.how/<pc>/` 01–06 is ABCE classification. The two numberings do **not** mean the same thing |
37
- | **Kernel** | The `SRS-<pc>.md` or `SDD-<pc>.md` file itself. Content SHOULD stay in it until it grows past roughly 400 lines — a suggestion, not a threshold |
38
-
39
- A PC is not a container: a container runs, a PC is a domain. One container holds several PCs, and
40
- one PC may appear in more than one container. Because they cross, neither list implies the other, and
41
- the crossing MUST be written down rather than inferred — that is the PC × container matrix at C4 L2,
42
- rendered from each PC's `containers:`.
43
-
44
- ## Flow
45
-
46
- There is no "stage". The five gates are the only flow vocabulary, and the word **area** is not used at all —
47
- there is only Product Component.
48
-
49
- | Term | Means |
50
- |---|---|
51
- | **Gate** | One of five decision points: G1 Problem · G2 Product · G3 Blueprint · G4 Component · G5 Release. Named after what is decided there, not after the work before it |
52
- | **`mode`** | The one knob for **document depth**, and nothing else. `catalog` · `outline` · `guarded` · `deep`, default `catalog`. Two scopes — global in `index.yaml`, per component in `components.yaml`, and the per-component one wins. **No third scope** |
53
- | **`risk_accepted`** | The one field for **review intensity**, and nothing else. `low` · `medium` · `high`. It MUST NOT be derived from `mode`, nor `mode` from it |
54
- | **Blueprint** | The whole-product portrait decided once at G3: one line per use case, table, endpoint, and screen, plus entities, actors, the spine, C4, and cross-component rules. It names a **gate and a skill**, never a document or a folder |
55
- | **Spec** | One unit of delivered work: the tickets that reach one outcome. Opens at G4 or G5, closes at G5, recorded in `specs.yaml`. Its document is `SPEC.md`, **optional at size `S`** — one term, one entry, and the document is named after the unit the way a `DEC-` file is named after its decision |
56
- | **Release** | What a PRD promises. One release MAY span several specs; the relation is data, never inferred from numbering |
57
- | **Spec size** | `S` ≤3 tickets no new FR · `M` 4–12 · `L` >12 or a new container. MAY be raised mid-flight, MUST NOT be lowered. It does **not** choose which gates are active — that is `mode`. It decides two things: whether G4 and G5 merge into one session (`S`), and whether `SPEC.md` is written at all (`M` and up) |
58
- | **Fast Path** | A fix that skips all gates: ≤1 ticket, no FR/UC/`AD-N`/domain-model change, no money, personal data, or third-party integration |
59
- | **Step** | One of the five points inside `wdi-build`'s ship pipeline — plan · build · panel · publish · CI. It is **not** a gate and not a stage, and the word MUST NOT be used for anything at gate altitude |
60
-
61
- ## Artifacts
62
-
63
- | Term | Means |
64
- |---|---|
65
- | **Brief** | One problem, one user, one measure. Singleton, spans releases |
66
- | **PRD** | What is promised for **one initiative**, across every release it touches. FR and NFR numbered from the registry |
67
- | **SRS** | Per PC: what the system must do. `.what/` — slices space, while the PRD slices initiative. It **exists at every `mode`**, carrying the actor list and the use case catalogue |
68
- | **SDD** | Per PC: how it is built. `.how/`. At `mode: catalog` it is a skeleton, and that is a finished state |
69
- | **Inventory** | One of three living registers at product level — tables, endpoints, screens. Written as a plan when there is no code, **derived** from code once there is |
70
- | **Architecture spine** | `ARCHITECTURE-SPINE.md` — invariants as `AD-N`, each carrying Binds · Prevents · Rule. It constrains; it does not describe |
71
- | **C4** | L1 system context · L2 containers · L3 components, one file per container. L1+L2 together are what other methods call the HLD |
72
- | **`DESIGN.md`** | UX per PC, in `.how/<pc>/01-ux/` |
73
- | **`EXPERIENCE.md`** | The user-facing journey, in `.what/<pc>/04-usecases/` |
74
- | **`DEC-`** | One decision worth remembering, numbered globally. Lives in `.control/decisions/`. Recording is **not mandatory**; it freezes at `applied`, not at `accepted` |
75
- | **SPEC** | The document of **one spec**: a projection of `.what/` + `.how/` that MUST NOT contain anything new. Not read by humans, and **not written at size `S`** — there the tickets are the contract |
76
- | **Ticket** | One unit of build: a tracer-bullet vertical slice, complete through every layer, verifiable on its own, sized to one fresh context window. Carries the tickets that **block** it. Status is read from the ticket itself, never copied elsewhere |
77
- | **Structure map** | `.control/structure-codebase.md` and `structure-document.md` — where things actually are today |
78
- | **Memlog** | The record of *why* while an artifact was written. Never copied into a document; a source when writing a `DEC-`. It is a **run log**, and it MUST NOT be searched as an index of decisions `.control/generated/decisions.md` is that |
79
-
80
- ## Identifiers
81
-
82
- | Code | For |
83
- |---|---|
84
- | `BG-` · `FR-` · `NFR-` · `UJ-` | Business goal · functional requirement · non-functional requirement · user journey |
85
- | `UC-` | Use case |
86
- | `AD-` | An invariant in the architecture spine |
87
- | `DEC-` | A decision |
88
- | `LC-` | A Logical Component |
89
- | `OQ-` | An open question |
90
- | `RTR-` | **Retired.** It was an archived retrospective in `.control/reports/`; the retrospective step and `V19` went together. A frozen `RTR-` file stays where it is |
91
- | `CAP-` | A capability the planning unit |
92
- | `NT-` | A non-technical fact |
93
- | `BUG-` · `HOT-` | A defect · a hotfix |
94
- | `goal-has-fr`–`container-built` | Validators. `V10` fell and its number is not reused |
95
-
96
- IDs are allocated **globally** and never restart per document, per component, or per release. The chain
97
- that must hold end to end: `BG FR UC ticket test`.
98
-
99
- `ADR-` is **retired**. It was renamed to `DEC-` on 2026-08-18 with the numbers unchanged, so `ADR-004`
100
- inside a document frozen before that date is an alias for `DEC-004`, and those documents MUST NOT be
101
- rewritten for the prefix.
102
-
103
- ## Registry and generated
104
-
105
- | Term | Means |
106
- |---|---|
107
- | **Registry** | `.control/registry/` — the source of truth for IDs and plans. Written through `wdi-*` skills |
108
- | **Generated** | `.control/generated/` — derived from the registry. Written by the generator only, by hand **never** |
109
- | **RTM** | Requirements traceability matrix. Generated, never hand-maintained |
110
- | **Validator** | A script that answers what can be counted. It does not replace a gate checklist, which answers what must be judged |
111
-
112
- ## BMad terms
113
-
114
- BMad terms live in a WDI glossary because WDI runs on BMad. Each is defined **as WDI uses it**;
115
- where BMad's own meaning is wider, the narrower one here wins.
116
-
117
- | Term | Means |
118
- |---|---|
119
- | **Stories mode** | **Retired.** It was BMad's route — `SPEC.md` + `stories.yaml` produced by `bmad-spec`. The engine layer below G5 no longer runs it; `bmad-guide.md` says what replaced it |
120
- | **Skill class** | `A` living document, straight to the corpus · `B` living but wrongly granular, lands neutral then is placed · `C` spent after its work · `D` no artifact |
121
- | **Companion** | A side file a BMad skill produces next to its main output. The lasting ones are promoted by the distillation table |
122
- | **Distillation** | Promoting what is durable out of `_bmad-output/` before a spec closes. What is not promoted dies with the folder |
123
- | **`persistent_facts`** | Files a skill always reads. Routing alone does not achieve this |
124
- | **`doc_standards`** | Rule files a skill checks its output against. Facts MUST NOT be installed here, and neither MUST anything at `status: Reference` |
125
- | **`{project_knowledge}`** | The config variable pointing at `.control/` |
126
- | **`_bmad/custom/`** | Where every BMad override lives. `.claude/skills/bmad-*/customize.toml` MUST NOT be edited — it is overwritten on update |
127
-
128
- ## Retired — MUST NOT be used as current
129
-
130
- | Retired | Instead |
131
- |---|---|
132
- | `ADR-` | `DEC-` — same numbers, new prefix |
133
- | `ANX-`, and the annex concept | Nothing. Zero annexes were ever born |
134
- | `SCP-` | A `DEC-` of `type: course-correction` |
135
- | `layer:` on a decision | `touches:`, filled from what actually changed |
136
- | "Stage 1"…"Stage 5" as flow vocabulary | The five gates |
137
- | `epics.md` · `sprint-status.yaml` · `bmad-sprint-planning` · `bmad-create-epics-and-stories` · `stories.yaml` | Tickets, each carrying its own status and its blocking edges |
138
- | Validator `V10` | Nothing. Its number is not reused |
139
- | `bmad-help` as the answer to "where am I" | `wdi-help` |
140
- | The skills `wdi-analysis` · `wdi-architecture` · `wdi-design` · `wdi-glossary` · `wdi-structure` · `wdi-apply` · `wdi-correct-course` · `wdi-wave` · `wdi-ship-story` · `wdi-product-brief` · `wdi-meeting` · `wdi-project-log` | The seventeen in `why/README.md`. `why/rationale.md` says which absorbed which, and why |
141
- | An Indonesian synonym for a `mode` value *ringkas*, *terjaga*, *katalog* as prose | The English value, used as written: `catalog` · `outline` · `guarded` · `deep` |
142
-
143
- ## Synonyms that MUST NOT be coined
144
-
145
- A synonym for a term that already has an entry is drift, and `wdi-reconcile` hunts for it.
146
-
147
- | Do not say | Say | Because |
148
- |---|---|---|
149
- | application · app · service, for a deployable | **container** | The term is already defined at C4 L2 and carried by every LC |
150
- | infrastructure · third-party · dependency, for something inside the boundary | **container** with `built: false` | Calling it something else is how a container ends up with no row, no owner, and no NFR |
151
- | container, for something whose runtime we do not deploy | **external system** | It has no `built`, no L3, and no heading. Registering it as a container promises a section of the codebase map that will never exist |
152
- | module · package, for a unit of build | **Logical Component** | `components.yaml` names it, and `lc-registered` resolves against that name |
153
- | epic · sprint, for a batch of work | **spec** | Both belong to the sprint route this method dropped |
154
- | **wave**, for a unit of delivered work | **spec** | Retired when the engine layer below G5 changed. See the retired-alias rule below |
155
- | **story**, for a unit of build | **ticket** | Same retirement. A ticket is a vertical slice that blocks and is blocked; a story was a row in a file BMad owned |
156
- | area, for a domain slice | **Product Component** | The word "area" is not used anywhere in this method |
157
- | platform, for a Product Component | **`_platform`**, and only for what is not one | Registering `_platform` as a PC gives it a `mode`, an SRS, and a G4 it has no use for |
158
- | profile · tier · level, for document depth | **`mode`** | One knob, four values, and no matrix behind it |
159
- | feature, for a domain slice | **Product Component** | A feature is a promise; a PC is a folder pair with an owner |
160
- | requirements document | **PRD** or **SRS** | They cut different axes time versus space and merging the names merges the documents |
161
-
162
- ## Retired terms keep their frozen documents
163
-
164
- `wave` and `story` are **retired aliases** of `spec` and `ticket`. A `wave` or a `story` appearing in a
165
- document frozen before the change a closed `DEC-`, an `RTR-`, minutes, `why/rationale.md`'s record of what
166
- happened reads as its replacement, and those documents **MUST NOT be rewritten for the term.** This is the
167
- same rule Article 6 already applies to `ADR-NNN` `DEC-NNN`, and for the same reason: a frozen record that
168
- cites a name is evidence, and rewriting evidence to tidy a vocabulary destroys the thing that made it useful.
169
-
170
- What MUST use the new term: every `Accepted` guide, every skill, every registry, and anything written from
171
- here on.
172
-
173
- ## Rules
174
-
175
- - A new method term MUST be added here in the same pass it first appears, not defined where it is
176
- used. Adding one is a change to the **method itself** `wdi-blueprint` MAY propose it and MUST NOT
177
- write it, because a method term binds every project the method is installed in.
178
- - One term MUST NOT have two entries. Two meanings mean two terms.
179
- - A domain term MUST go to `.control/product-glossary.md` instead. If it is unclear which, ask whether the
180
- term would survive being applied to a different product: yes here, no there.
181
- - Common technical terms stay in English when the industry name is the one that matches the code,
182
- the error message, or the reader's expectation.
1
+ ---
2
+ status: Accepted
3
+ ---
4
+
5
+ # Method Glossary
6
+
7
+ **Loaded when:** a method term is unclear, and before coining a new one.
8
+
9
+ The words this method uses for **itself**. What the product is about belongs to
10
+ `.control/product-glossary.md` instead. A term defined here MUST NOT be redefined there, and the
11
+ reverse holds too. The test: would this term still apply on a different product? Yes → here.
12
+
13
+ ## Layers
14
+
15
+ | Term | Means |
16
+ |---|---|
17
+ | **Corpus** | The four layers below. `_bmad-output/` is not part of it |
18
+ | **`.constitution/`** | How we work. Rules. Rarely changes |
19
+ | **`.control/`** | What currently holds and what has been decided. Facts. Changes often. Equals `{project_knowledge}` |
20
+ | **`.what/`** | What was promised |
21
+ | **`.how/`** | How it is built |
22
+ | **Workspace** | `_bmad-output/` — work in progress, committed but not curated |
23
+ | **Placement test** | Is this file still true after its spec has passed? Yes → corpus. No → workspace |
24
+
25
+ ## Units
26
+
27
+ | Term | Means |
28
+ |---|---|
29
+ | **Product Component** (PC) | A domain slice — the box at C4 L3. Lives in `.what/<pc>/` and `.how/<pc>/`, and its `containers:` says where it runs |
30
+ | **Logical Component** (LC) | One addressable unit of build. Registered in `components.yaml` with `type` · `container` · `owner` · `area` |
31
+ | **Container** | Something that **runs its own code or stores its own data** and can be replaced without rebuilding another one. The C4 L2 term, and the value of an LC's `container` field. Two questions decide it and both MUST be yes — `architecture-guide.md` owns the test. Shipping two containers in one release does **not** merge them |
32
+ | **`built`** | A container's one boolean. `true` when we write what is inside it, `false` when we deploy someone else's implementation. It decides whether the container gets an L3, an `LC`, and a heading in the codebase map — `container-built` checks all three |
33
+ | **External system** | Something the product talks to whose **runtime we do not deploy**. It belongs at C4 L1, and MUST NOT be a container, an `LC`'s `container`, or a heading in the codebase map. What we lean on it for lives in `cross-cutting.md` or an integration contract |
34
+ | **`_platform`** | **Not a component.** The home for what belongs to no Product Component: the spine, the C4 set, `cross-cutting.md`, the three inventories, and whatever it **owns**. A legitimate value in every position that asks which component owns something — `platform_owns`, an inventory row, an `LC`. Four kinds today: data · endpoint · job · screen. It carries no `mode`, no `risk_accepted`, and no G4 |
35
+ | **Library** | An includable artifact — compiled into or imported by something else, never run on its own. Not a container |
36
+ | **Slot** | A numbered sub-folder of a PC. `.what/<pc>/` 02–05 is reading order; `.how/<pc>/` 01–06 is ABCE classification. The two numberings do **not** mean the same thing |
37
+ | **Kernel** | The `SRS-<pc>.md` or `SDD-<pc>.md` file itself. Content SHOULD stay in it until it grows past roughly 400 lines — a suggestion, not a threshold |
38
+
39
+ A PC is not a container: a container runs, a PC is a domain. One container holds several PCs, and
40
+ one PC may appear in more than one container. Because they cross, neither list implies the other, and
41
+ the crossing MUST be written down rather than inferred — that is the PC × container matrix at C4 L2,
42
+ rendered from each PC's `containers:`.
43
+
44
+ ## Flow
45
+
46
+ There is no "stage". The five gates are the only flow vocabulary, and the word **area** is not used at all —
47
+ there is only Product Component.
48
+
49
+ | Term | Means |
50
+ |---|---|
51
+ | **Gate** | One of five decision points: G1 Problem · G2 Product · G3 Blueprint · G4 Component · G5 Release. Named after what is decided there, not after the work before it |
52
+ | **`mode`** | The one knob for **document depth**, and nothing else. `catalog` · `outline` · `guarded` · `deep`, default `catalog`. Two scopes — global in `index.yaml`, per component in `components.yaml`, and the per-component one wins. **No third scope** |
53
+ | **`risk_accepted`** | The one field for **review intensity**, and nothing else. `low` · `medium` · `high`. It MUST NOT be derived from `mode`, nor `mode` from it |
54
+ | **Blueprint** | The whole-product portrait decided once at G3: one line per use case, table, endpoint, and screen, plus entities, actors, the spine, C4, and cross-component rules. It names a **gate and a skill**, never a document or a folder |
55
+ | **Spec** | One unit of delivered work: the tickets that reach one outcome. Opens at G4 or G5, closes at G5, recorded in `specs.yaml`. Its document is `SPEC.md`, **optional at size `S`** — one term, one entry, and the document is named after the unit the way a `DEC-` file is named after its decision |
56
+ | **Release** | What a PRD promises. One release MAY span several specs; the relation is data, never inferred from numbering |
57
+ | **Spec size** | `S` ≤3 tickets no new FR · `M` 4–12 · `L` >12 or a new container. MAY be raised mid-flight, MUST NOT be lowered. It does **not** choose which gates are active — that is `mode`. It decides two things: whether G4 and G5 merge into one session (`S`), and whether `SPEC.md` is written at all (`M` and up) |
58
+ | **Fast Path** | A fix that skips all gates: ≤1 ticket, no FR/UC/`AD-N`/domain-model change, no money, personal data, or third-party integration |
59
+ | **Step** | One of the five points inside `wdi-build`'s ship pipeline — plan · build · panel · publish · CI. It is **not** a gate and not a stage, and the word MUST NOT be used for anything at gate altitude |
60
+
61
+ ## Artifacts
62
+
63
+ | Term | Means |
64
+ |---|---|
65
+ | **Brief** | One problem, one user, one measure. Singleton, spans releases |
66
+ | **PRD** | What is promised for **one initiative**, across every release it touches. FR and NFR numbered from the registry |
67
+ | **SRS** | Per PC: what the system must do. `.what/` — slices space, while the PRD slices initiative. It **exists at every `mode`**, carrying the actor list and the use case catalogue |
68
+ | **SDD** | Per PC: how it is built. `.how/`. At `mode: catalog` it is a skeleton, and that is a finished state |
69
+ | **Inventory** | One of three living registers at product level — tables, endpoints, screens. Written as a plan when there is no code, **derived** from code once there is |
70
+ | **Architecture spine** | `ARCHITECTURE-SPINE.md` — invariants as `AD-N`, each carrying Binds · Prevents · Rule. It constrains; it does not describe |
71
+ | **C4** | L1 system context · L2 containers · L3 components, one file per container. L1+L2 together are what other methods call the HLD |
72
+ | **`DESIGN.md`** | UX per PC, in `.how/<pc>/01-ux/` |
73
+ | **`EXPERIENCE.md`** | The user-facing journey, in `.what/<pc>/04-usecases/` |
74
+ | **`DEC-`** | One decision worth remembering, numbered globally. Lives in `.control/decisions/`. Recording is **not mandatory**; it freezes at `applied`, not at `accepted` |
75
+ | **SPEC** | The document of **one spec**: a projection of `.what/` + `.how/` that MUST NOT contain anything new. Not read by humans, and **not written at size `S`** — there the tickets are the contract |
76
+ | **Ticket** | One unit of build: a tracer-bullet vertical slice, complete through every layer, verifiable on its own, sized to one fresh context window. Carries the tickets that **block** it. Status is read from the ticket itself, never copied elsewhere |
77
+ | **Structure map** | `.control/structure-codebase.md` and `structure-document.md` — where things actually are today |
78
+ | **Mandate** | A `DEC-` of `type: mandate`: the owner's one dated, expiring delegation that lets `wdi-autopilot` decide what the skills would otherwise have asked. Its parameters live on its registry row only; every decision taken under it is a row in the ledger, `.control/memlog/autopilot-<date>.md` |
79
+ | **Memlog** | The record of *why* while an artifact was written. Never copied into a document; a source when writing a `DEC-`. It is a **run log**, and it MUST NOT be searched as an index of decisions — `.control/generated/decisions.md` is that |
80
+
81
+ ## Identifiers
82
+
83
+ | Code | For |
84
+ |---|---|
85
+ | `BG-` · `FR-` · `NFR-` · `UJ-` | Business goal · functional requirement · non-functional requirement · user journey |
86
+ | `UC-` | Use case |
87
+ | `AD-` | An invariant in the architecture spine |
88
+ | `DEC-` | A decision |
89
+ | `LC-` | A Logical Component |
90
+ | `OQ-` | An open question |
91
+ | `RTR-` | **Retired.** It was an archived retrospective in `.control/reports/`; the retrospective step and `V19` went together. A frozen `RTR-` file stays where it is |
92
+ | `CAP-` | A capability the planning unit |
93
+ | `NT-` | A non-technical fact |
94
+ | `BUG-` · `HOT-` | A defect · a hotfix |
95
+ | `goal-has-fr`–`container-built` | Validators. `V10` fell and its number is not reused |
96
+
97
+ IDs are allocated **globally** and never restart per document, per component, or per release. The chain
98
+ that must hold end to end: `BG → FR → UC → ticket → test`.
99
+
100
+ `ADR-` is **retired**. It was renamed to `DEC-` on 2026-08-18 with the numbers unchanged, so `ADR-004`
101
+ inside a document frozen before that date is an alias for `DEC-004`, and those documents MUST NOT be
102
+ rewritten for the prefix.
103
+
104
+ ## Registry and generated
105
+
106
+ | Term | Means |
107
+ |---|---|
108
+ | **Registry** | `.control/registry/` — the source of truth for IDs and plans. Written through `wdi-*` skills |
109
+ | **Generated** | `.control/generated/` derived from the registry. Written by the generator only, by hand **never** |
110
+ | **RTM** | Requirements traceability matrix. Generated, never hand-maintained |
111
+ | **Validator** | A script that answers what can be counted. It does not replace a gate checklist, which answers what must be judged |
112
+
113
+ ## BMad terms
114
+
115
+ BMad terms live in a WDI glossary because WDI runs on BMad. Each is defined **as WDI uses it**;
116
+ where BMad's own meaning is wider, the narrower one here wins.
117
+
118
+ | Term | Means |
119
+ |---|---|
120
+ | **Stories mode** | **Retired.** It was BMad's route `SPEC.md` + `stories.yaml` produced by `bmad-spec`. The engine layer below G5 no longer runs it; `bmad-guide.md` says what replaced it |
121
+ | **Skill class** | `A` living document, straight to the corpus · `B` living but wrongly granular, lands neutral then is placed · `C` spent after its work · `D` no artifact |
122
+ | **Companion** | A side file a BMad skill produces next to its main output. The lasting ones are promoted by the distillation table |
123
+ | **Distillation** | Promoting what is durable out of `_bmad-output/` before a spec closes. What is not promoted dies with the folder |
124
+ | **`persistent_facts`** | Files a skill always reads. Routing alone does not achieve this |
125
+ | **`doc_standards`** | Rule files a skill checks its output against. Facts MUST NOT be installed here, and neither MUST anything at `status: Reference` |
126
+ | **`{project_knowledge}`** | The config variable pointing at `.control/` |
127
+ | **`_bmad/custom/`** | Where every BMad override lives. `.claude/skills/bmad-*/customize.toml` MUST NOT be edited — it is overwritten on update |
128
+
129
+ ## Retired — MUST NOT be used as current
130
+
131
+ | Retired | Instead |
132
+ |---|---|
133
+ | `ADR-` | `DEC-` same numbers, new prefix |
134
+ | `ANX-`, and the annex concept | Nothing. Zero annexes were ever born |
135
+ | `SCP-` | A `DEC-` of `type: course-correction` |
136
+ | `layer:` on a decision | `touches:`, filled from what actually changed |
137
+ | "Stage 1"…"Stage 5" as flow vocabulary | The five gates |
138
+ | `epics.md` · `sprint-status.yaml` · `bmad-sprint-planning` · `bmad-create-epics-and-stories` · `stories.yaml` | Tickets, each carrying its own status and its blocking edges |
139
+ | Validator `V10` | Nothing. Its number is not reused |
140
+ | `bmad-help` as the answer to "where am I" | `wdi-help` |
141
+ | The skills `wdi-analysis` · `wdi-architecture` · `wdi-design` · `wdi-glossary` · `wdi-structure` · `wdi-apply` · `wdi-correct-course` · `wdi-wave` · `wdi-ship-story` · `wdi-product-brief` · `wdi-meeting` · `wdi-project-log` | The eighteen in `why/README.md`. `why/rationale.md` says which absorbed which, and why |
142
+ | An Indonesian synonym for a `mode` value — *ringkas*, *terjaga*, *katalog* as prose | The English value, used as written: `catalog` · `outline` · `guarded` · `deep` |
143
+
144
+ ## Synonyms that MUST NOT be coined
145
+
146
+ A synonym for a term that already has an entry is drift, and `wdi-reconcile` hunts for it.
147
+
148
+ | Do not say | Say | Because |
149
+ |---|---|---|
150
+ | application · app · service, for a deployable | **container** | The term is already defined at C4 L2 and carried by every LC |
151
+ | infrastructure · third-party · dependency, for something inside the boundary | **container** with `built: false` | Calling it something else is how a container ends up with no row, no owner, and no NFR |
152
+ | container, for something whose runtime we do not deploy | **external system** | It has no `built`, no L3, and no heading. Registering it as a container promises a section of the codebase map that will never exist |
153
+ | module · package, for a unit of build | **Logical Component** | `components.yaml` names it, and `lc-registered` resolves against that name |
154
+ | epic · sprint, for a batch of work | **spec** | Both belong to the sprint route this method dropped |
155
+ | **wave**, for a unit of delivered work | **spec** | Retired when the engine layer below G5 changed. See the retired-alias rule below |
156
+ | **story**, for a unit of build | **ticket** | Same retirement. A ticket is a vertical slice that blocks and is blocked; a story was a row in a file BMad owned |
157
+ | area, for a domain slice | **Product Component** | The word "area" is not used anywhere in this method |
158
+ | platform, for a Product Component | **`_platform`**, and only for what is not one | Registering `_platform` as a PC gives it a `mode`, an SRS, and a G4 it has no use for |
159
+ | profile · tier · level, for document depth | **`mode`** | One knob, four values, and no matrix behind it |
160
+ | feature, for a domain slice | **Product Component** | A feature is a promise; a PC is a folder pair with an owner |
161
+ | requirements document | **PRD** or **SRS** | They cut different axes — time versus space — and merging the names merges the documents |
162
+
163
+ ## Retired terms keep their frozen documents
164
+
165
+ `wave` and `story` are **retired aliases** of `spec` and `ticket`. A `wave` or a `story` appearing in a
166
+ document frozen before the change a closed `DEC-`, an `RTR-`, minutes, `why/rationale.md`'s record of what
167
+ happened reads as its replacement, and those documents **MUST NOT be rewritten for the term.** This is the
168
+ same rule Article 6 already applies to `ADR-NNN` `DEC-NNN`, and for the same reason: a frozen record that
169
+ cites a name is evidence, and rewriting evidence to tidy a vocabulary destroys the thing that made it useful.
170
+
171
+ What MUST use the new term: every `Accepted` guide, every skill, every registry, and anything written from
172
+ here on.
173
+
174
+ ## Rules
175
+
176
+ - A new method term MUST be added here in the same pass it first appears, not defined where it is
177
+ used. Adding one is a change to the **method itself** `wdi-blueprint` MAY propose it and MUST NOT
178
+ write it, because a method term binds every project the method is installed in.
179
+ - One term MUST NOT have two entries. Two meanings mean two terms.
180
+ - A domain term MUST go to `.control/product-glossary.md` instead. If it is unclear which, ask whether the
181
+ term would survive being applied to a different product: yes here, no there.
182
+ - Common technical terms stay in English when the industry name is the one that matches the code,
183
+ the error message, or the reader's expectation.
@@ -55,6 +55,7 @@ CHECK_ORDER = (
55
55
  "entity-one-writer",
56
56
  "spec-after-g4",
57
57
  "high-risk-named",
58
+ "mandate-accept",
58
59
  "cites-resolve",
59
60
  "container-built",
60
61
  "custom-room-declared",
@@ -969,7 +970,8 @@ def high_risk_named(c: Corpus, r: Result) -> None: # was V23
969
970
  to resolve: a repo pointing at a decision is making a checkable claim, and a pointer to a decision
970
971
  that does not exist is worse than no pointer.
971
972
  """
972
- known = {str(x.get("id")) for x in c.decs}
973
+ by_id = {str(x.get("id")): x for x in c.decs}
974
+ known = set(by_id)
973
975
  for pc in c.pcs:
974
976
  pid = str(pc.get("id"))
975
977
  if str(pc.get("risk_accepted") or "").strip() != "high":
@@ -985,6 +987,104 @@ def high_risk_named(c: Corpus, r: Result) -> None: # was V23
985
987
  f"`risk_accepted_by` names nobody — a person and a date is enough")
986
988
  elif ref.startswith("DEC-") and ref not in known:
987
989
  r.fail("high-risk-named", pid, f"`risk_accepted_by: {ref}` does not exist in decisions.yaml")
990
+ elif str(by_id.get(ref, {}).get("type") or "") == "mandate":
991
+ # A mandate delegates the decisions the owner would have taken. Accepting a HIGH risk on a
992
+ # component that touches money or personal data is not one of them: the whole point of this
993
+ # check is that a PERSON is named, and pointing at the delegation names nobody. Left legal, an
994
+ # unattended run could raise the risk itself and switch off the code panel wdi-build requires.
995
+ r.fail("high-risk-named", pid, f"`risk_accepted_by: {ref}` is a `type: mandate` — a run MUST NOT "
996
+ f"accept a sensitive risk for the owner; name a person and a date")
997
+
998
+
999
+ def _dec_date(c: Corpus, dec: dict) -> dt.date | None:
1000
+ """The day a decision was taken: `date` on its row, else `date`/`created` in its file's frontmatter."""
1001
+ def as_date(v: object) -> dt.date | None:
1002
+ if isinstance(v, dt.datetime):
1003
+ return v.date()
1004
+ if isinstance(v, dt.date):
1005
+ return v
1006
+ try:
1007
+ return dt.date.fromisoformat(str(v).strip()) if v else None
1008
+ except ValueError:
1009
+ return None
1010
+ got = as_date(dec.get("date"))
1011
+ if got:
1012
+ return got
1013
+ did = str(dec.get("id") or "")
1014
+ for path in sorted(c.root.glob(f".control/decisions/{did}-*.md")):
1015
+ fm = frontmatter(path) or {}
1016
+ got = as_date(fm.get("date")) or as_date(fm.get("created"))
1017
+ if got:
1018
+ return got
1019
+ return None
1020
+
1021
+
1022
+ def mandate_accept(c: Corpus, r: Result) -> None:
1023
+ """A decision accepted BY DELEGATION points at a real mandate that had not lapsed when it was taken.
1024
+
1025
+ `wdi-autopilot` lets the agent accept decisions the owner would have accepted, and that is legal
1026
+ only because the owner accepted the MANDATE in person. So three things hold: a mandate is never
1027
+ itself accepted by another decision — the chain of authority has a person at its root; an accepted
1028
+ mandate names the day it ends, or it is standing permission; and a decision whose `accepted_by` is
1029
+ a `DEC-` names one that is `type: mandate`, accepted, and unexpired on the decision's own date.
1030
+
1031
+ It says nothing about WHAT was decided — that is the ledger's job and the owner's review.
1032
+ """
1033
+ by_id = {str(d.get("id")): d for d in c.decs}
1034
+ for dec in c.decs:
1035
+ did = str(dec.get("id"))
1036
+ ref = str(dec.get("accepted_by") or "").strip()
1037
+ status = str(dec.get("status") or "")
1038
+ if str(dec.get("type") or "") == "mandate":
1039
+ if ref.startswith("DEC-"):
1040
+ r.fail("mandate-accept", did,
1041
+ f"is a mandate accepted by delegation (`accepted_by: {ref}`) — the mandate is the one "
1042
+ f"decision the owner accepts in person")
1043
+ if status in ("accepted", "applied"):
1044
+ if not ref:
1045
+ r.fail("mandate-accept", did, "is an accepted mandate and `accepted_by` names nobody — "
1046
+ "a person and a date is enough")
1047
+ params = dec.get("mandate") if isinstance(dec.get("mandate"), dict) else {}
1048
+ raw = str(params.get("expires") or "").strip()
1049
+ if not raw:
1050
+ r.fail("mandate-accept", did, "has no `mandate.expires` — a mandate with no end is standing "
1051
+ "permission, and the loop it drives expires anyway")
1052
+ ledger = c.root / ".control/memlog" / f"autopilot-{did}.md"
1053
+ if not ledger.exists():
1054
+ # Every claim the mandate rests on — every decision recorded, nothing decided that was
1055
+ # parked — is checkable only against this file. Absent, the run holds the owner's
1056
+ # authority with no account of what it did with it.
1057
+ r.fail("mandate-accept", did, f"has no ledger at `.control/memlog/autopilot-{did}.md` — "
1058
+ f"the record is what the delegation was granted against")
1059
+ if raw and _dec_date(c, {"date": params.get("expires")}) is None:
1060
+ # An unparseable expiry is WORSE than a missing one: it passes a presence check and then
1061
+ # silently disables the lapse comparison for every decision taken under this mandate.
1062
+ r.fail("mandate-accept", did, f"`mandate.expires: {raw}` is not a date — write `YYYY-MM-DD`. "
1063
+ f"An expiry nothing can read stops nothing")
1064
+ continue
1065
+ if not ref.startswith("DEC-"):
1066
+ continue
1067
+ target = by_id.get(ref)
1068
+ if target is None:
1069
+ r.fail("mandate-accept", did, f"`accepted_by: {ref}` does not exist in decisions.yaml")
1070
+ continue
1071
+ if str(target.get("type") or "") != "mandate":
1072
+ r.fail("mandate-accept", did, f"`accepted_by: {ref}` is not a `type: mandate` decision — only a mandate "
1073
+ f"delegates acceptance")
1074
+ continue
1075
+ if str(target.get("status") or "") not in ("accepted", "applied"):
1076
+ r.fail("mandate-accept", did, f"`accepted_by: {ref}` is `{target.get('status')}`, not accepted — "
1077
+ f"nothing was delegated yet")
1078
+ continue
1079
+ params = target.get("mandate") if isinstance(target.get("mandate"), dict) else {}
1080
+ expires = _dec_date(c, {"date": params.get("expires")})
1081
+ when = _dec_date(c, dec)
1082
+ if when is None:
1083
+ r.fail("mandate-accept", did, f"is accepted under `{ref}` but no date says when — `date:` in its "
1084
+ f"frontmatter is what the expiry is checked against")
1085
+ elif expires and when > expires:
1086
+ r.fail("mandate-accept", did, f"was taken on {when.isoformat()}, after `{ref}` expired on "
1087
+ f"{expires.isoformat()} — the delegation had lapsed")
988
1088
 
989
1089
 
990
1090
  def defect_root_cause(c: Corpus, r: Result) -> None: # was V20
@@ -1357,7 +1457,7 @@ def run_checks(c: Corpus, asof: dt.date) -> Result:
1357
1457
  # no two copies left to compare.
1358
1458
  # V19 is REPEALED. It checked one line item — an `RTR-` file in .control/reports/ — and the
1359
1459
  # retrospective it archived was the only thing spec size `L` ever decided. Both went together.
1360
- for fn in (goal_has_fr, fr_has_uc, uc_scheduled, ticket_has_test, nfr_has_enforcer, refs_resolve, no_cycles, applied_dec_touches, locked_gate_passed, parallel_tickets_blocked, lc_registered, review_trace, chain_links, memlog_home, spec_names_release_prd, ticket_status_one_home, defect_root_cause, entity_one_writer, spec_after_g4, high_risk_named, cites_resolve, container_built, custom_room_declared, id_allocated_once):
1460
+ for fn in (goal_has_fr, fr_has_uc, uc_scheduled, ticket_has_test, nfr_has_enforcer, refs_resolve, no_cycles, applied_dec_touches, locked_gate_passed, parallel_tickets_blocked, lc_registered, review_trace, chain_links, memlog_home, spec_names_release_prd, ticket_status_one_home, defect_root_cause, entity_one_writer, spec_after_g4, high_risk_named, mandate_accept, cites_resolve, container_built, custom_room_declared, id_allocated_once):
1361
1461
  fn(c, r)
1362
1462
  plan_dates(c, r, asof)
1363
1463
  return r
@@ -101,7 +101,7 @@ and the Fast Path do not.
101
101
  | `wdi-method update` printed an `upgrade` line | `wdi-upgrade`, before any other skill — it moves content into the new shape, never invents it, one commit |
102
102
  | You do not know where you are | `wdi-help` |
103
103
 
104
- ## Seventeen skills
104
+ ## Eighteen skills
105
105
 
106
106
  Named for the **gate they serve**, so *"which skill do I run"* is answered by *"which gate am I at"*.
107
107
 
@@ -126,6 +126,7 @@ Named for the **gate they serve**, so *"which skill do I run"* is answered by *"
126
126
  | `wdi-log` | A meeting finished, or a non-technical fact now binds |
127
127
  | `wdi-help` | "Where am I, what next" |
128
128
  | `wdi-explain-to-me` | "Brief me so I can decide this" — an open question, a defect, a design fork. Reads everything, writes nothing; the decision then goes to `wdi-decision` or `wdi-question` |
129
+ | `wdi-autopilot` | "Deliver every `FR` and do not ask me in between." A preflight the owner confirms becomes one `DEC-` of `type: mandate`; a loop then fires the skill, and it runs every other skill, decides what they would have asked, and writes each decision to one ledger the owner reviews in parallel |
129
130
  | `wdi-upgrade` | `wdi-method update` just moved the method version, and the summary listed content still in the old shape. Moves it, never invents it; one commit |
130
131
  | `wdi-reconcile` | Any time. Read-only — it reports, it never edits |
131
132
  | `wdi-review` | Over any document, any time |