wdi-method 0.6.24 → 0.6.26
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.
- package/CHANGELOG.md +25 -0
- package/README.id.md +2 -1
- package/README.ja.md +2 -1
- package/README.md +2 -1
- package/README.zh.md +2 -1
- package/bin/wdi-method.js +18 -0
- package/kit/.constitution/method/repo-guide.md +11 -6
- package/kit/.constitution/method/scripts/validate.py +48 -1
- package/kit/skills/wdi-autopilot/SKILL.md +11 -2
- package/kit/skills/wdi-build/SKILL.md +5 -2
- package/kit/skills/wdi-daily-what-to-build/SKILL.md +29 -5
- package/kit/skills/wdi-daily-what-to-test/SKILL.md +4 -1
- package/kit-overlay/repo-guide.md +11 -6
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,31 @@ version contains every fix below it.
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
+
## [0.6.26] - 2026-09-20
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **Validation Rule `spec-folder-location` in `validate.py`:** Added upfront validation that every spec in `specs.yaml` has a valid `spec_folder`. For active specs, `spec_folder` MUST be within `.scratch/<spec-id>-<slug>/` (or legacy `_bmad-output/specs/`). Specs placed inside `.work/` or other unauthorized roots (such as `docs/` or repo root) fail immediately with finding `spec-folder-location`, preventing misplaced specs from progressing through implementation before failing during lifecycle archival.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **Non-Authoritative Execution Scratch Taxonomy in `repo-guide.md`:** Clarified section heading to `## .work/ — non-authoritative execution scratch` and added explicit normative rules: `.work/` is execution scratch only and MUST NOT contain `SPEC.md`, ticket files, or any `spec_folder` target. Active specifications and ticket efforts MUST live under `.scratch/<spec-id>-<slug>/`.
|
|
22
|
+
- **Deterministic Spec Location in `wdi-daily-what-to-build` & `wdi-build`:** Added explicit target contracts in `wdi-daily-what-to-build` (Step 3) and `wdi-build` (Phase 1 & Phase 2), mandating `.scratch/<spec-id>-<slug>/` and forbidding `.work/` or `docs/`. Preflight check instructs immediate correction if `spec-folder-location` fails.
|
|
23
|
+
|
|
24
|
+
**What a repo that already has the method installed does about it.** Run `npx wdi-method@latest update`. It updates `validate.py`, the repo guide, and the build skills. Active specs mistakenly authored in `.work/` should be moved to `.scratch/<spec-id>-<slug>/` with `spec_folder` updated in `specs.yaml`.
|
|
25
|
+
|
|
26
|
+
## [0.6.25] - 2026-09-19
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- **Ephemeral Subagent Handoff Lifecycle & Mandatory Scratch Deletion:** `wdi-daily-what-to-build` mandates that subagent handoff packets, raw CLI logs, and review outputs are disposable execution scratch (not product evidence). Review outputs are strictly scoped to `<slug>-review-output.md`, and all scratch files under `.work/wdi-daily-what-to-build/` MUST be deleted upon coordinator fold-in and stamping. Raw review files MUST NOT be staged, committed, or archived into `.scratch/` or `.archive/`.
|
|
31
|
+
- **Distillation Scope Extension:** `wdi-build` Phase 4 Distillation checklist explicitly requires verifying and cleaning lingering triage scratch under `.work/wdi-daily-what-to-build/` before closing a spec.
|
|
32
|
+
- **Selective Staging Discipline on Autopilot:** `wdi-autopilot` explicitly prohibits broad wildcard staging (`git add .`, `git add -A`, `git add --all`). Staging is restricted to application code, tests, `.control/`, and `.scratch/<active-spec>/`. Ephemeral execution scratch under `.work/` is barred from the run branch, and mandate finish requires a clean sweep of temporary `.work/` files.
|
|
33
|
+
- **Enriched Ephemeral Precondition Guidance:** `wdi-daily-what-to-test` enriches Step 0.4 halt guidance when untracked files match `.work/` scratch, providing direct remediation instructions instead of generic dirty tree errors.
|
|
34
|
+
- **Scaffold Ignore for Raw Tool Dumps:** `bin/wdi-method.js` now automatically ensures `.work/*.txt`, `.work/*.log`, and `.work/tmp/` are ignored in `.gitignore` on install/update, preventing raw CLI redirection dumps from causing dirty working tree preflight halts.
|
|
35
|
+
|
|
36
|
+
**What a repo that already has the method installed does about it.** Run `npx wdi-method@latest update`. It updates the daily skills with strict scratch cleanup and staging guardrails, and ensures ephemeral tool dumps in `.work/` are ignored in `.gitignore`.
|
|
37
|
+
|
|
13
38
|
## [0.6.24] - 2026-09-18
|
|
14
39
|
|
|
15
40
|
### Added
|
package/README.id.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# WDI Method
|
|
2
2
|
|
|
3
|
-
[English](README.md) | [Bahasa Indonesia](README.id.md) | [日本語](README.ja.md) | [简体中文](README.zh.md)
|
|
3
|
+
[English](README.md) | [Bahasa Indonesia](README.id.md) | [日本語](README.ja.md) | [简体中文](README.zh.md)
|
|
4
|
+
[Changelog](CHANGELOG.md) | [Contributing](CONTRIBUTING.md) | [License](LICENSE) | [Security](SECURITY.md) | [Privacy](PRIVACY.md)
|
|
4
5
|
|
|
5
6
|
**Lapisan tinjauan yang melengkapi BMad — spesifikasi terverifikasi yang dibaca manusia untuk memeriksa keputusan teknis sebelum kode ditulis, disesuaikan dengan skala perubahan nyata.**
|
|
6
7
|
|
package/README.ja.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# WDI Method
|
|
2
2
|
|
|
3
|
-
[English](README.md) | [Bahasa Indonesia](README.id.md) | [日本語](README.ja.md) | [简体中文](README.zh.md)
|
|
3
|
+
[English](README.md) | [Bahasa Indonesia](README.id.md) | [日本語](README.ja.md) | [简体中文](README.zh.md)
|
|
4
|
+
[Changelog](CHANGELOG.md) | [Contributing](CONTRIBUTING.md) | [License](LICENSE) | [Security](SECURITY.md) | [Privacy](PRIVACY.md)
|
|
4
5
|
|
|
5
6
|
**BMadが薄く残したレビュー層 — コードを書く前に技術的な決定を人間が検証するための仕様書フレームワーク。変更規模に応じて適切な粒度を提供します。**
|
|
6
7
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# WDI Method
|
|
2
2
|
|
|
3
|
-
[English](README.md) | [Bahasa Indonesia](README.id.md) | [日本語](README.ja.md) | [简体中文](README.zh.md)
|
|
3
|
+
[English](README.md) | [Bahasa Indonesia](README.id.md) | [日本語](README.ja.md) | [简体中文](README.zh.md)
|
|
4
|
+
[Changelog](CHANGELOG.md) | [Contributing](CONTRIBUTING.md) | [License](LICENSE) | [Security](SECURITY.md) | [Privacy](PRIVACY.md)
|
|
4
5
|
|
|
5
6
|
**The review layer BMad leaves thin — verifiable specifications a human reads to check technical decisions before code is written, sized to what the change actually deserves.**
|
|
6
7
|
|
package/README.zh.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# WDI Method
|
|
2
2
|
|
|
3
|
-
[English](README.md) | [Bahasa Indonesia](README.id.md) | [日本語](README.ja.md) | [简体中文](README.zh.md)
|
|
3
|
+
[English](README.md) | [Bahasa Indonesia](README.id.md) | [日本語](README.ja.md) | [简体中文](README.zh.md)
|
|
4
|
+
[Changelog](CHANGELOG.md) | [Contributing](CONTRIBUTING.md) | [License](LICENSE) | [Security](SECURITY.md) | [Privacy](PRIVACY.md)
|
|
4
5
|
|
|
5
6
|
**BMad 所精简保留的审查层 —— 供人类在编写代码前验证技术决策的规范说明框架,根据实际变更规模匹配相应的文档粒度。**
|
|
6
7
|
|
package/bin/wdi-method.js
CHANGED
|
@@ -917,6 +917,23 @@ function ensureGitignoreSmoke(target) {
|
|
|
917
917
|
}
|
|
918
918
|
}
|
|
919
919
|
|
|
920
|
+
function ensureGitignoreScratchDumps(target) {
|
|
921
|
+
const gitignorePath = path.join(target, ".gitignore");
|
|
922
|
+
const rules = [".work/*.txt", ".work/*.log", ".work/tmp/"];
|
|
923
|
+
if (fs.existsSync(gitignorePath)) {
|
|
924
|
+
const content = fs.readFileSync(gitignorePath, "utf8");
|
|
925
|
+
const lines = content.split(/\r?\n/).map((l) => l.trim());
|
|
926
|
+
const missing = rules.filter((r) => !lines.includes(r) && !lines.includes(`/${r}`));
|
|
927
|
+
if (missing.length === 0) return;
|
|
928
|
+
const separator = content.endsWith("\n") ? "" : "\n";
|
|
929
|
+
fs.writeFileSync(gitignorePath, `${content}${separator}# Ephemeral execution scratch and raw tool dumps\n${missing.join("\n")}\n`, "utf8");
|
|
930
|
+
note(`added ${missing.join(", ")} to .gitignore`);
|
|
931
|
+
} else {
|
|
932
|
+
fs.writeFileSync(gitignorePath, `# Ephemeral execution scratch and raw tool dumps\n${rules.join("\n")}\n`, "utf8");
|
|
933
|
+
note(`created .gitignore with ${rules.join(", ")}`);
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
|
|
920
937
|
function seedDailyTierScaffold(target) {
|
|
921
938
|
const control = path.join(target, ".control");
|
|
922
939
|
if (!fs.existsSync(control)) return;
|
|
@@ -949,6 +966,7 @@ function seedDailyTierScaffold(target) {
|
|
|
949
966
|
|
|
950
967
|
ensureGitignoreCustomDispatch(target);
|
|
951
968
|
ensureGitignoreSmoke(target);
|
|
969
|
+
ensureGitignoreScratchDumps(target);
|
|
952
970
|
|
|
953
971
|
const localDispatchDest = path.join(control, "custom-dispatch.yaml");
|
|
954
972
|
if (!fs.existsSync(localDispatchDest) && fs.existsSync(exampleSrc)) {
|
|
@@ -40,10 +40,11 @@ fact and MUST NOT state the commercial one. *"Retention is 90 days"* is a techni
|
|
|
40
40
|
*"Retention is 90 days because the client would not pay for more"* is a commercial one wearing a
|
|
41
41
|
technical coat.
|
|
42
42
|
|
|
43
|
-
## `.work/` —
|
|
43
|
+
## `.work/` — non-authoritative execution scratch
|
|
44
44
|
|
|
45
|
-
`.work/` holds work in progress that has no home yet: notes while reading
|
|
46
|
-
|
|
45
|
+
`.work/` holds execution scratch and work in progress that has no home yet: notes while reading
|
|
46
|
+
an unfamiliar system, exploratory output, disposable reviewer transport, a working paper for a change
|
|
47
|
+
spanning several sessions.
|
|
47
48
|
|
|
48
49
|
It is **committed**, so that a session picked up on another machine finds it, and so a reviewer can
|
|
49
50
|
see what a change was actually reasoning about.
|
|
@@ -55,6 +56,9 @@ pattern that drops the folder is not, because it leaves the material on one mach
|
|
|
55
56
|
|
|
56
57
|
It is **ephemeral**, and the two together are what make its rules matter:
|
|
57
58
|
|
|
59
|
+
- `.work/` is execution scratch only. It MUST NOT contain `SPEC.md`, ticket files, or any `spec_folder`
|
|
60
|
+
target. Active specification workspaces MUST live at `.scratch/<spec-id>-<slug>/` where `wdi-build`
|
|
61
|
+
and the registry track them.
|
|
58
62
|
- Any durable outcome MUST be moved out before the task closes — to the corpus if it is truth, to
|
|
59
63
|
`_bmad-output/` if it is a run's byproduct.
|
|
60
64
|
- Obsolete scratch MUST be deleted when its task closes. `.work/` that only grows stops being
|
|
@@ -64,9 +68,10 @@ It is **ephemeral**, and the two together are what make its rules matter:
|
|
|
64
68
|
- Nothing MUST be read from `.work/` as authority. If something there is right, it belongs
|
|
65
69
|
somewhere with an owner.
|
|
66
70
|
|
|
67
|
-
`.work/` MUST NOT be confused with `_bmad-output/`.
|
|
68
|
-
never curated, and is cited by path. `.
|
|
69
|
-
|
|
71
|
+
`.work/` MUST NOT be confused with `_bmad-output/` or `.scratch/`. `_bmad-output/` holds the output of
|
|
72
|
+
skill runs, is never curated, and is cited by path. `.scratch/` holds active specifications and tickets
|
|
73
|
+
tracked in `specs.yaml`. `.work/` holds disposable execution scratch written by hand or during triage
|
|
74
|
+
(such as `.work/wdi-daily-what-to-build/`), and is meant to empty out.
|
|
70
75
|
|
|
71
76
|
## Referring to things outside this repository
|
|
72
77
|
|
|
@@ -973,6 +973,53 @@ def archived_spec_closed(c: Corpus, r: Result) -> None:
|
|
|
973
973
|
"only closed specs may be archived")
|
|
974
974
|
|
|
975
975
|
|
|
976
|
+
def spec_folder_location(c: Corpus, r: Result) -> None:
|
|
977
|
+
"""A spec's `spec_folder` MUST be within an allowed root.
|
|
978
|
+
|
|
979
|
+
Active specs MUST live at `.scratch/<spec-id>-<slug>/` (or legacy `_bmad-output/specs/`).
|
|
980
|
+
Closed specs may remain in `.scratch/` or be archived under `.archive/specs/<spec-id>-<slug>/`.
|
|
981
|
+
`.work/` is execution scratch only and MUST NOT be used for `spec_folder`.
|
|
982
|
+
"""
|
|
983
|
+
for spec in c.spec_list:
|
|
984
|
+
sid = str(spec.get("id") or "").strip()
|
|
985
|
+
folder = str(spec.get("spec_folder") or "").strip()
|
|
986
|
+
if not folder:
|
|
987
|
+
for t in spec.get("tickets") or []:
|
|
988
|
+
if isinstance(t, dict) and str(t.get("spec_folder") or "").strip():
|
|
989
|
+
folder = str(t.get("spec_folder")).strip()
|
|
990
|
+
break
|
|
991
|
+
if not folder:
|
|
992
|
+
continue
|
|
993
|
+
clean = folder.replace("\\", "/").strip()
|
|
994
|
+
while clean.startswith("./"):
|
|
995
|
+
clean = clean[2:]
|
|
996
|
+
if clean.startswith("/"):
|
|
997
|
+
clean = clean.lstrip("/")
|
|
998
|
+
clean = clean.rstrip("/")
|
|
999
|
+
norm = os.path.normpath(clean).replace("\\", "/") if clean else ""
|
|
1000
|
+
|
|
1001
|
+
# Check for forbidden .work/ root
|
|
1002
|
+
if clean == ".work" or clean.startswith(".work/") or norm == ".work" or norm.startswith(".work/"):
|
|
1003
|
+
r.fail("spec-folder-location", sid,
|
|
1004
|
+
f"spec_folder `{folder}` is inside `.work/` — `.work/` is execution scratch only; "
|
|
1005
|
+
f"active specs MUST live at `.scratch/{sid}-<slug>/`")
|
|
1006
|
+
continue
|
|
1007
|
+
|
|
1008
|
+
status = str(spec.get("status") or "").strip()
|
|
1009
|
+
is_closed = status == "closed"
|
|
1010
|
+
|
|
1011
|
+
allowed_roots = [".scratch", "_bmad-output/specs"]
|
|
1012
|
+
if is_closed:
|
|
1013
|
+
allowed_roots.append(".archive/specs")
|
|
1014
|
+
|
|
1015
|
+
is_allowed = any(clean == a or clean.startswith(f"{a}/") or norm == a or norm.startswith(f"{a}/")
|
|
1016
|
+
for a in allowed_roots)
|
|
1017
|
+
if not is_allowed:
|
|
1018
|
+
allowed_desc = ", ".join(f"`{a}/`" for a in allowed_roots)
|
|
1019
|
+
r.fail("spec-folder-location", sid,
|
|
1020
|
+
f"spec_folder `{folder}` is outside allowed roots ({allowed_desc})")
|
|
1021
|
+
|
|
1022
|
+
|
|
976
1023
|
PLATFORM = "_platform"
|
|
977
1024
|
CROSS_CUTTING = ".how/_platform/cross-cutting.md"
|
|
978
1025
|
# The section heading entity-one-writer looks for. A heading a SCRIPT matches is a machine-facing key, and
|
|
@@ -1904,7 +1951,7 @@ def run_checks(c: Corpus, asof: dt.date) -> Result:
|
|
|
1904
1951
|
# no two copies left to compare.
|
|
1905
1952
|
# V19 is REPEALED. It checked one line item — an `RTR-` file in .control/reports/ — and the
|
|
1906
1953
|
# retrospective it archived was the only thing spec size `L` ever decided. Both went together.
|
|
1907
|
-
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, archived_spec_closed, defect_root_cause, entity_one_writer, spec_after_g4, high_risk_named, mandate_accept, cites_resolve, container_built, custom_room_declared, corpus_in_git, engines_invocable, withdrawn_recorded, id_allocated_once):
|
|
1954
|
+
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, archived_spec_closed, spec_folder_location, defect_root_cause, entity_one_writer, spec_after_g4, high_risk_named, mandate_accept, cites_resolve, container_built, custom_room_declared, corpus_in_git, engines_invocable, withdrawn_recorded, id_allocated_once):
|
|
1908
1955
|
fn(c, r)
|
|
1909
1956
|
plan_dates(c, r, asof)
|
|
1910
1957
|
return r
|
|
@@ -150,6 +150,11 @@ only on one machine. What an iteration MUST NOT do is start a metered runner: no
|
|
|
150
150
|
marked ready, no re-run requested on a ticket that is not finished. Evidence during the run is the **local**
|
|
151
151
|
suite, which `wdi-build` Phase 3 Step 2 already requires and which costs nothing. See § Cycle-end CI.
|
|
152
152
|
|
|
153
|
+
**Selective Staging Discipline:** Staging MUST be strictly selective (`git add <path>`). The coordinator
|
|
154
|
+
and builders MUST NOT use broad wildcard staging (`git add .`, `git add -A`, `git add --all`). Staging MUST include
|
|
155
|
+
only application code, tests, `.control/`, and `.scratch/<active-spec>/`. Ephemeral execution scratch under `.work/`
|
|
156
|
+
MUST NOT be staged or committed into the run branch.
|
|
157
|
+
|
|
153
158
|
**Runnable** means: not listed under Blocked in `## Resume`, and not parked by the mandate. A blocked row is
|
|
154
159
|
retried only when the owner unblocks it or a later change removes the cause — and the ledger row that
|
|
155
160
|
recorded the block says which. A run that re-picks a blocked step spends the whole mandate window on it, and
|
|
@@ -401,10 +406,13 @@ When § The work table reaches § Finish:
|
|
|
401
406
|
(e.g. `ci_override: local-only-approved-by: "<Person, Date>"` per `.constitution/method/ci-guide.md`),
|
|
402
407
|
the run MUST NOT mark the draft PR ready (`gh pr ready`). The PR MUST remain as a Draft, no cloud runner
|
|
403
408
|
is awaited, and the final output report explicitly states: *"locally verified; cloud verification intentionally deferred by mandate"*.
|
|
404
|
-
5. **
|
|
409
|
+
5. **Clean ephemeral execution scratch:** delete all temporary scratch files under `.work/` created during
|
|
410
|
+
this mandate run (such as temporary triage outputs, diff dumps, and scratch files). Ephemeral execution scratch
|
|
411
|
+
MUST NOT survive the mandate finish or be left on the run branch.
|
|
412
|
+
6. **Cancel the loop cleanly:** in Claude Code, inspect scheduled jobs via `CronList`, identify the job firing
|
|
405
413
|
`/wdi-autopilot`, and call `CronDelete` on its task ID to eliminate zombie loop firings; elsewhere, call the platform's
|
|
406
414
|
loop cancellation mechanism or inform the owner that the loop has completed its mandate and has nothing left to do.
|
|
407
|
-
|
|
415
|
+
7. Write the final report as the Output below. The owner merges; the run never does.
|
|
408
416
|
|
|
409
417
|
## Red Flags — STOP
|
|
410
418
|
|
|
@@ -415,6 +423,7 @@ When § The work table reaches § Finish:
|
|
|
415
423
|
- Closing a spec while the run branch's own full suite is red, or marking the PR ready while CI is red
|
|
416
424
|
- **Starting a cloud run before § Finish** — a PR marked ready mid-run, a workflow dispatched to check a
|
|
417
425
|
ticket, or an intermediate push left free to match a bare `on: push` trigger
|
|
426
|
+
- Staging with broad wildcards (`git add .`, `git add -A`, `git add --all`) or committing ephemeral `.work/` scratch into the run branch
|
|
418
427
|
- Answering the quota problem by committing less often, instead of by fixing what a push triggers
|
|
419
428
|
- Spending the one cloud run on a head whose local suite was never run
|
|
420
429
|
- Re-merging a branch whose merge was reverted, instead of cutting a new one
|
|
@@ -85,7 +85,7 @@ that is where they are born.
|
|
|
85
85
|
| `fr` | The `FR` this spec satisfies. Ideally one — an `FR` is human-testable from birth |
|
|
86
86
|
| `size` | `S` · `M` · `L`. MAY be raised mid-flight; MUST NOT be lowered |
|
|
87
87
|
| `depends_on` | At **spec** level. A spec declaring none runs in parallel with its neighbours |
|
|
88
|
-
| `spec_folder` |
|
|
88
|
+
| `spec_folder` | MUST be `.scratch/<spec-id>-<slug>/` (one per spec, not one per spec × component). MUST NOT use `.work/` or `docs/` |
|
|
89
89
|
| `tickets` | Flat, one row per ticket: `id` · `component` · `satisfies: [UC]` · `blocked_by` · `touches` · test names |
|
|
90
90
|
| a ticket `id` | `<spec-id>-<NN>` — `SPEC-3-01`. The engine numbers its files from `01` per feature, which is unique only inside one spec; the RTM needs a key that is unique across the corpus |
|
|
91
91
|
|
|
@@ -139,7 +139,8 @@ is here and name the prior art.
|
|
|
139
139
|
sequenced expand → migrate in batches → contract; `delivery-flow-guide.md` owns that rule.
|
|
140
140
|
- **Ticket files land under `spec_folder`, and `spec_folder` is `.scratch/<spec-id>-<slug>/`.** Their
|
|
141
141
|
**shape** is the engine's — one file per ticket, numbered in dependency order, blocking edges declared
|
|
142
|
-
— and the location is ours, written in `docs/agents/issue-tracker.md` where the engines read it.
|
|
142
|
+
— and the location is ours, written in `docs/agents/issue-tracker.md` where the engines read it. MUST
|
|
143
|
+
NOT use `.work/` or `docs/` (`spec-folder-location` enforces this). The
|
|
143
144
|
id in front of the slug is not decoration: four live repos wrote that leaf four different ways, one of
|
|
144
145
|
them all four inside a single repo, and a folder nothing can trace back to a row in `specs.yaml` is
|
|
145
146
|
how a spec goes missing. A ticket at the repo root, or under `docs/`, or in a `.scratch/` directory
|
|
@@ -347,6 +348,8 @@ out.
|
|
|
347
348
|
4. **Distillation.** Every applicable row of the ownership table in `corpus-guide.md` has been landed by its
|
|
348
349
|
owner. Anything durable in the spec folder leaves it now, or dies with it — **the ticket files included.**
|
|
349
350
|
Their prose is working output; what survives is the index in `specs.yaml` and whatever the checklist routed.
|
|
351
|
+
Distillation also encompasses deleting any lingering ephemeral triage scratch under `.work/wdi-daily-what-to-build/`
|
|
352
|
+
for this spec. A spec MUST NOT close with uncleaned `.work/` scratch files.
|
|
350
353
|
5. **RTM green.** Every traceability row for this spec is closed. New risks are in the risk register with an
|
|
351
354
|
owner.
|
|
352
355
|
6. Mark the spec `status: closed` in `specs.yaml`.
|
|
@@ -50,6 +50,13 @@ Invoke `wdi-build` Phase 1 (open spec and author tickets via `to-spec` / `to-tic
|
|
|
50
50
|
active development branch (`policy.development_branch`, default `main`), per the Delivery Flow standing
|
|
51
51
|
exception.
|
|
52
52
|
|
|
53
|
+
### Spec Location & Target Contract (`spec-folder-location`)
|
|
54
|
+
The specification and its ticket files MUST land under `.scratch/<spec-id>-<slug>/` and `spec_folder`
|
|
55
|
+
in `.control/registry/specs.yaml` MUST name that exact path.
|
|
56
|
+
- MUST NOT place `SPEC.md` or ticket files in `.work/` or `docs/`.
|
|
57
|
+
- `.work/` is reserved strictly for ephemeral execution scratch (such as `.work/wdi-daily-what-to-build/`);
|
|
58
|
+
a spec in `.work/` violates `spec-folder-location` and fails lifecycle archiving.
|
|
59
|
+
|
|
53
60
|
### Ticket Dependency Contract (Upfront `parallel-tickets-blocked`)
|
|
54
61
|
Author `touches` and `blocked_by` together; do NOT defer dependency relationships until validation.
|
|
55
62
|
For every pair of tickets in the same spec whose `touches` lists intersect, there MUST be a directed
|
|
@@ -61,9 +68,11 @@ Before leaving Step 3, run validator preflight:
|
|
|
61
68
|
```bash
|
|
62
69
|
uv run .constitution/method/scripts/validate.py --check --baseline
|
|
63
70
|
```
|
|
64
|
-
If `
|
|
65
|
-
|
|
66
|
-
|
|
71
|
+
If `spec-folder-location` reports an invalid `spec_folder` (e.g. under `.work/`), move the folder to
|
|
72
|
+
`.scratch/<spec-id>-<slug>/` and update `specs.yaml` immediately. If `parallel-tickets-blocked` reports
|
|
73
|
+
unsequenced tickets, add the missing `blocked_by` edge to an upstream ticket immediately. Findings already
|
|
74
|
+
matching `.github/validate-baseline.txt` are pre-existing debt, not new blockers; only new RED findings must
|
|
75
|
+
be repaired before dispatching review.
|
|
67
76
|
|
|
68
77
|
**Stop at the boundary of Phase 1.** Once the spec and ticket files exist on disk, do NOT proceed into
|
|
69
78
|
Phase 2 (worktree isolation and ticket implementation) or Phase 3 (closing the spec) — each of those is
|
|
@@ -108,6 +117,8 @@ Reviewer resolution:
|
|
|
108
117
|
stop and report immediately (fail-closed).
|
|
109
118
|
- Dispatch execution & process discipline:
|
|
110
119
|
- Cap shell-out dispatch at a hard wall-clock limit (default 600s, or `timeout_s` if defined in `custom-dispatch.yaml`).
|
|
120
|
+
- If review output is written to disk, it MUST be scoped to the slug: `.work/wdi-daily-what-to-build/<slug>-review-output.md`
|
|
121
|
+
(MUST NOT use un-scoped generic names like `terra-review-output.md` or `review.md`).
|
|
111
122
|
- Run backgrounded with polling or synchronous wait. If the timeout expires, or the process exits non-zero,
|
|
112
123
|
or the output file cannot be read: terminate the entire process tree by its PID (MUST NOT use process name-based
|
|
113
124
|
killing). Record in the final report: `peer review: fell back to coordinator self-review after timeout/failure`.
|
|
@@ -137,6 +148,18 @@ under the coordinator's orchestration, the coordinator writes the `spec_reviewed
|
|
|
137
148
|
```
|
|
138
149
|
The coordinator MUST NOT delegate registry stamping to external shell-out processes.
|
|
139
150
|
|
|
151
|
+
### Clean Ephemeral Review Artifacts (Mandatory Deletion)
|
|
152
|
+
Handoff packets, raw reviewer transcripts, and shell redirection logs generated during this triage pass are
|
|
153
|
+
disposable execution scratch, NOT product evidence. Once the advisory review is evaluated, folded into the draft,
|
|
154
|
+
and stamped in `specs.yaml`:
|
|
155
|
+
- The coordinator MUST delete all scratch files created under `.work/wdi-daily-what-to-build/` for this `<slug>`
|
|
156
|
+
(including `<slug>-second-opinion.md`, `<slug>-review-output.md`, and any temporary CLI stdout/stderr dumps such
|
|
157
|
+
as `.work/*.txt` or `.work/*.log`).
|
|
158
|
+
- Handoff packets and raw review text MUST NOT be left in the working tree, MUST NOT be staged or committed to git,
|
|
159
|
+
and MUST NOT be archived or moved into `.scratch/` or `.archive/` (distillation deletes scratch; archiving is
|
|
160
|
+
reserved for completed specification documents).
|
|
161
|
+
- A triage pass MUST NOT hand off with uncleaned `.work/wdi-daily-what-to-build/` artifacts on disk.
|
|
162
|
+
|
|
140
163
|
### Validation
|
|
141
164
|
Run canonical validation using `uv`:
|
|
142
165
|
```bash
|
|
@@ -151,5 +174,6 @@ uv run .constitution/method/scripts/validate.py --generate --baseline
|
|
|
151
174
|
## 6. Stop and hand off
|
|
152
175
|
|
|
153
176
|
Report what now exists (or that the notes were green) and its file path. State explicitly whether `spec_reviewed`
|
|
154
|
-
was stamped or if peer review fell back to coordinator self-review
|
|
155
|
-
|
|
177
|
+
was stamped or if peer review fell back to coordinator self-review, and confirm that all ephemeral `.work/` scratch
|
|
178
|
+
artifacts have been deleted. MUST NOT commit, push, or start `wdi-autopilot` in this same run — state that as the
|
|
179
|
+
next step and wait for the maintainer to request it.
|
|
@@ -32,7 +32,10 @@ closed tickets and specs, never invented from memory.
|
|
|
32
32
|
immediately and report to the maintainer; per `.constitution/method/branch-guide.md`, MUST NOT guess
|
|
33
33
|
or silently fall back to `main`.
|
|
34
34
|
4. Verify the primary working tree is clean (`git status --porcelain`). If uncommitted changes exist,
|
|
35
|
-
stop and report without modifying git state.
|
|
35
|
+
stop and report without modifying git state. If the uncommitted files match known ephemeral triage scratch
|
|
36
|
+
under `.work/` (such as uncleaned `.work/wdi-daily-what-to-build/` packets or raw CLI dump logs), explicitly
|
|
37
|
+
report them as abandoned scratch from a previous run and provide the exact remediation command
|
|
38
|
+
(e.g. `Remove-Item <paths>`) rather than an ambiguous dirty tree error.
|
|
36
39
|
|
|
37
40
|
## 1. Sync (Fast-Forward Only)
|
|
38
41
|
|
|
@@ -40,10 +40,11 @@ fact and MUST NOT state the commercial one. *"Retention is 90 days"* is a techni
|
|
|
40
40
|
*"Retention is 90 days because the client would not pay for more"* is a commercial one wearing a
|
|
41
41
|
technical coat.
|
|
42
42
|
|
|
43
|
-
## `.work/` —
|
|
43
|
+
## `.work/` — non-authoritative execution scratch
|
|
44
44
|
|
|
45
|
-
`.work/` holds work in progress that has no home yet: notes while reading
|
|
46
|
-
|
|
45
|
+
`.work/` holds execution scratch and work in progress that has no home yet: notes while reading
|
|
46
|
+
an unfamiliar system, exploratory output, disposable reviewer transport, a working paper for a change
|
|
47
|
+
spanning several sessions.
|
|
47
48
|
|
|
48
49
|
It is **committed**, so that a session picked up on another machine finds it, and so a reviewer can
|
|
49
50
|
see what a change was actually reasoning about.
|
|
@@ -55,6 +56,9 @@ pattern that drops the folder is not, because it leaves the material on one mach
|
|
|
55
56
|
|
|
56
57
|
It is **ephemeral**, and the two together are what make its rules matter:
|
|
57
58
|
|
|
59
|
+
- `.work/` is execution scratch only. It MUST NOT contain `SPEC.md`, ticket files, or any `spec_folder`
|
|
60
|
+
target. Active specification workspaces MUST live at `.scratch/<spec-id>-<slug>/` where `wdi-build`
|
|
61
|
+
and the registry track them.
|
|
58
62
|
- Any durable outcome MUST be moved out before the task closes — to the corpus if it is truth, to
|
|
59
63
|
`_bmad-output/` if it is a run's byproduct.
|
|
60
64
|
- Obsolete scratch MUST be deleted when its task closes. `.work/` that only grows stops being
|
|
@@ -64,9 +68,10 @@ It is **ephemeral**, and the two together are what make its rules matter:
|
|
|
64
68
|
- Nothing MUST be read from `.work/` as authority. If something there is right, it belongs
|
|
65
69
|
somewhere with an owner.
|
|
66
70
|
|
|
67
|
-
`.work/` MUST NOT be confused with `_bmad-output/`.
|
|
68
|
-
never curated, and is cited by path. `.
|
|
69
|
-
|
|
71
|
+
`.work/` MUST NOT be confused with `_bmad-output/` or `.scratch/`. `_bmad-output/` holds the output of
|
|
72
|
+
skill runs, is never curated, and is cited by path. `.scratch/` holds active specifications and tickets
|
|
73
|
+
tracked in `specs.yaml`. `.work/` holds disposable execution scratch written by hand or during triage
|
|
74
|
+
(such as `.work/wdi-daily-what-to-build/`), and is meant to empty out.
|
|
70
75
|
|
|
71
76
|
## Referring to things outside this repository
|
|
72
77
|
|