dflow-sdd-ddd 0.13.0 → 0.15.0

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.
Files changed (96) hide show
  1. package/CHANGELOG.md +824 -1
  2. package/CONTRIBUTING.md +16 -10
  3. package/README.en.md +156 -200
  4. package/README.md +89 -144
  5. package/TEMPLATE-COVERAGE.md +15 -8
  6. package/TEMPLATE-LANGUAGE-GLOSSARY.md +15 -1
  7. package/bin/dflow.js +36 -4
  8. package/docs/commands.en.md +110 -0
  9. package/docs/commands.md +101 -0
  10. package/docs/doctor-uncertainty.en.md +212 -0
  11. package/docs/doctor-uncertainty.md +212 -0
  12. package/docs/evaluating-dflow.en.md +29 -11
  13. package/docs/evaluating-dflow.md +8 -6
  14. package/docs/npm-publish-checklist.md +3 -1
  15. package/docs/release-versioning-policy.md +8 -2
  16. package/docs/upgrading.en.md +196 -0
  17. package/docs/upgrading.md +197 -0
  18. package/docs/using-with-claude-code.en.md +25 -10
  19. package/docs/using-with-claude-code.md +20 -7
  20. package/docs/using-with-codex.en.md +18 -6
  21. package/docs/using-with-codex.md +16 -5
  22. package/docs/using-with-github-copilot.en.md +25 -10
  23. package/docs/using-with-github-copilot.md +21 -8
  24. package/lib/doc-shapes.json +997 -0
  25. package/lib/doctor-checks.js +2654 -0
  26. package/lib/init.js +3583 -107
  27. package/lib/render-diagrams.js +1474 -0
  28. package/lib/render.js +865 -49
  29. package/package.json +2 -2
  30. package/templates/brownfield/references/drift-verification.md +4 -0
  31. package/templates/brownfield/references/finish-feature-flow.md +635 -88
  32. package/templates/brownfield/references/finish-feature-follow-up.md +60 -0
  33. package/templates/brownfield/references/finish-feature-minimal-host.md +406 -0
  34. package/templates/brownfield/references/finish-feature-post-hoc-hotfix.md +95 -0
  35. package/templates/brownfield/references/git-integration.md +160 -15
  36. package/templates/brownfield/references/init-project-flow.md +26 -4
  37. package/templates/brownfield/references/modify-existing-flow.md +412 -87
  38. package/templates/brownfield/references/modify-existing-follow-up.md +121 -0
  39. package/templates/brownfield/references/modify-existing-post-hoc-hotfix.md +82 -0
  40. package/templates/brownfield/references/new-feature-flow.md +61 -6
  41. package/templates/brownfield/references/new-phase-flow.md +57 -7
  42. package/templates/brownfield/references/pr-review-checklist.md +303 -10
  43. package/templates/brownfield/scaffolding/AI-AGENT-GUIDE.md +158 -34
  44. package/templates/brownfield/scaffolding/CLAUDE-md-snippet.md +1 -1
  45. package/templates/brownfield/scaffolding/Git-principles-gitflow.md +75 -6
  46. package/templates/brownfield/scaffolding/Git-principles-trunk.md +82 -8
  47. package/templates/brownfield/scaffolding/_conventions.md +50 -28
  48. package/templates/brownfield/scaffolding/_overview.md +1 -0
  49. package/templates/brownfield/templates/_index.md +151 -7
  50. package/templates/brownfield/templates/analysis.md +79 -0
  51. package/templates/brownfield/templates/behavior.md +1 -0
  52. package/templates/brownfield/templates/context-definition.md +1 -0
  53. package/templates/brownfield/templates/context-map.md +2 -1
  54. package/templates/brownfield/templates/glossary.md +1 -0
  55. package/templates/brownfield/templates/lightweight-spec.md +154 -11
  56. package/templates/brownfield/templates/models.md +1 -0
  57. package/templates/brownfield/templates/phase-spec.md +9 -1
  58. package/templates/brownfield/templates/rules.md +1 -0
  59. package/templates/brownfield/templates/tech-debt.md +1 -0
  60. package/templates/common/references/ddd-modeling-guide.md +33 -16
  61. package/templates/{greenfield → common}/references/dflow-feedback-flow.md +2 -1
  62. package/templates/common/references/flow-rationale-registry.md +130 -0
  63. package/templates/common/skill/SKILL.md +13 -11
  64. package/templates/greenfield/references/drift-verification.md +4 -0
  65. package/templates/greenfield/references/finish-feature-flow.md +625 -89
  66. package/templates/greenfield/references/finish-feature-follow-up.md +60 -0
  67. package/templates/greenfield/references/finish-feature-minimal-host.md +363 -0
  68. package/templates/greenfield/references/finish-feature-post-hoc-hotfix.md +95 -0
  69. package/templates/greenfield/references/git-integration.md +148 -15
  70. package/templates/greenfield/references/init-project-flow.md +28 -8
  71. package/templates/greenfield/references/modify-existing-flow.md +378 -85
  72. package/templates/greenfield/references/modify-existing-follow-up.md +103 -0
  73. package/templates/greenfield/references/modify-existing-post-hoc-hotfix.md +82 -0
  74. package/templates/greenfield/references/new-feature-flow.md +67 -4
  75. package/templates/greenfield/references/new-phase-flow.md +56 -7
  76. package/templates/greenfield/references/pr-review-checklist.md +287 -8
  77. package/templates/greenfield/scaffolding/AI-AGENT-GUIDE.md +153 -32
  78. package/templates/greenfield/scaffolding/CLAUDE-md-snippet.md +5 -2
  79. package/templates/greenfield/scaffolding/Git-principles-gitflow.md +74 -6
  80. package/templates/greenfield/scaffolding/Git-principles-trunk.md +88 -12
  81. package/templates/greenfield/scaffolding/_conventions.md +50 -28
  82. package/templates/greenfield/scaffolding/_overview.md +6 -2
  83. package/templates/greenfield/templates/_index.md +137 -7
  84. package/templates/greenfield/templates/aggregate-design.md +1 -0
  85. package/templates/greenfield/templates/analysis.md +79 -0
  86. package/templates/greenfield/templates/behavior.md +1 -0
  87. package/templates/greenfield/templates/context-definition.md +1 -0
  88. package/templates/greenfield/templates/context-map.md +2 -1
  89. package/templates/greenfield/templates/events.md +4 -1
  90. package/templates/greenfield/templates/glossary.md +1 -0
  91. package/templates/greenfield/templates/lightweight-spec.md +154 -11
  92. package/templates/greenfield/templates/models.md +1 -0
  93. package/templates/greenfield/templates/phase-spec.md +9 -1
  94. package/templates/greenfield/templates/rules.md +1 -0
  95. package/templates/greenfield/templates/tech-debt.md +1 -0
  96. package/templates/brownfield/references/dflow-feedback-flow.md +0 -251
@@ -0,0 +1,60 @@
1
+ # Step 6: Reverse-Update Follow-up Tracking — Greenfield Clean Architecture
2
+
3
+ Branch file of `references/finish-feature-flow.md`. It **adds** the follow-up
4
+ closing rules; it does not restate or override anything in that flow.
5
+
6
+ **You are here because** that flow's Step 6 dispatched you — it owns whether
7
+ this route applies.
8
+
9
+ For features that were created as follow-ups of an earlier completed
10
+ feature, update the Follow-up Tracking table of **every** original this host's
11
+ `follow-up-of` names — one parent, or several when the field is a YAML array.
12
+ For each of them:
13
+
14
+ 1. Locate `dflow/specs/features/completed/{原 SPEC-ID}-{原 slug}/_index.md`
15
+ 2. Find the Follow-up Tracking section's row for this feature's SPEC-ID
16
+ 3. Flip Status → `completed`
17
+
18
+ ```bash
19
+ # The AI makes the edit and may offer to commit it (Y / N), per the AI commit policy
20
+ ```
21
+
22
+ This flip is a **sanctioned post-completion mutation, not a checkpoint** —
23
+ the follow-up host is already closed out and archived, so it is recorded in
24
+ **no** Checkpoint Log (neither this original feature's nor the follow-up
25
+ host's). It **must still be committed**, though: the flip is a real edit to
26
+ the original feature's `_index.md`. Require the tracking commit — the AI offers
27
+ it (Y / N); if the developer declines or the commit fails, **stop and do not
28
+ declare closeout complete** until the flip is committed. After it commits,
29
+ verify **per original** with
30
+ `git show HEAD:dflow/specs/features/completed/{原 SPEC-ID}-{原 slug}/_index.md`
31
+ that the Follow-up Tracking row now reads `completed` in the **committed** blob,
32
+ and that `git status --short` is clean. **Then check the commit itself, two ways
33
+ — neither replaces the other.**
34
+ **(1) Its full path set** (`git show --stat HEAD`) contains **only** the
35
+ `_index.md` of the originals this host's `follow-up-of` names: nothing under the
36
+ archived follow-up host — that would be a third host-mutating commit, which the
37
+ two-checkpoint lifecycle does not allow — and nothing else at all.
38
+ **(2) Its patch per original** (`git show HEAD -- {that path}`) carries **that
39
+ row's own transition** — the `in-progress` line removed, the `completed` line
40
+ added — and **no Checkpoint Log change**: this flip enters *neither* ledger, so
41
+ a Checkpoint Log row appearing in a parent is a violation even when the flip
42
+ itself is correct.
43
+ Why both: the blob proves the final state, not who wrote it — a commit that
44
+ merely edits other text in parent A while flipping parent B leaves both blobs
45
+ reading `completed` with the flips split across two commits — and the patch in
46
+ (2) is **path-filtered**, so it cannot see what else the commit touched. Only
47
+ (1) can. The commit message references the
48
+ follow-up host's SPEC-ID. Where there are several originals, flip them **in one
49
+ commit** — for a minimal follow-up host that keeps this the single post-closeout
50
+ tracking commit named in `modify-existing-flow.md` Step 1.6's minimal variant.
51
+
52
+ After the update:
53
+ > "Follow-up Tracking row updated to Status = `completed` in
54
+ > `{原 SPEC-ID}-{原 slug}/_index.md` (and every other original listed).
55
+ > Closeout complete."
56
+
57
+ The connection is bidirectional and weakly redundant: the new feature's
58
+ `follow-up-of` field is the authoritative source; the old feature's
59
+ Follow-up Tracking row is a derived index. If they ever disagree, trust
60
+ `follow-up-of`.
@@ -0,0 +1,363 @@
1
+ # Minimal Host (Zero-Phase) Closeout — Greenfield Clean Architecture
2
+
3
+ Branch file of `references/finish-feature-flow.md`. It **adds** the checks and
4
+ field rules a minimal (zero-phase) host takes; it does not restate or override
5
+ anything in that flow.
6
+
7
+ **You are here when** `references/finish-feature-flow.md` Step 1's minimal-host
8
+ selector sent you — it states the condition; this file does not restate it.
9
+
10
+ **Keep this file for the whole closeout.** It adds to four of that flow's
11
+ steps — Step 1, Step 3, Step 4's post-commit verification, and Step 5 — and each
12
+ of those places points back here.
13
+
14
+ ## Hash evidence
15
+
16
+ **Hash evidence** (several checks in this file use this test). A hash recorded in
17
+ `_index.md` passes *hash evidence* when all three hold:
18
+ - **(a) it is a commit** — `git cat-file -t {hash}` reports `commit`;
19
+ - **(b) it is on this branch** — `git merge-base --is-ancestor {hash} HEAD`
20
+ succeeds;
21
+ - **(c) its diff carries what the record claims** — the commit's **changed
22
+ paths** include the artifact that row or checkpoint points at; each check
23
+ in this file names which. **Tree presence is not enough**: every commit
24
+ inherits the files an earlier one added, so a commit that only touched the
25
+ implementation would otherwise satisfy (c) for an artifact it never wrote. (a)
26
+ and (b) alone prove only that *some* earlier commit exists on this branch; (c)
27
+ is what ties it to the record.
28
+
29
+ ## Step 1 — additional validation checks
30
+
31
+ Run these as part of `references/finish-feature-flow.md` Step 1's checklist, in
32
+ the order given here, and report `✓` / `✗` for each exactly as that flow says.
33
+ A `✗` here stops closeout there, on the same terms.
34
+
35
+ - [ ] **Minimal host (zero-phase) only** — every row in `_index.md` Lightweight
36
+ Changes has a **non-empty `Commit` cell that passes hash evidence**; for
37
+ (c), the commit carries that row's own work: a **T2**'s
38
+ `lightweight-*.md` / `BUG-*.md` file, or for a **T3** an `_index.md` that
39
+ already carries this row at that hash — Step 1.7 writes every row *before*
40
+ checkpoint 1, which is what makes that provable here. This applies to
41
+ **T2 and T3 rows alike**. Three failures, all blocking — **report the one
42
+ that is true**, because the message is the developer's only clue about what
43
+ to do next: an **empty** cell means that change is not committed yet; a
44
+ cell holding a **placeholder** (`{hash}`, `{pending}`, `(待 commit)` —
45
+ anything `git cat-file -t` cannot resolve) means the cell was **never
46
+ filled in**, which is a different repair and may well have a commit sitting
47
+ there unrecorded; a **resolvable** value that fails (a)–(c) means the hash
48
+ is the wrong one. ⚠ Do not collapse the middle case into the first.
49
+ (`modify-existing-flow.md` Step 1.7 "Finalize + close" is where the
50
+ **cell** gets backfilled once its commit exists.)
51
+ **Deliberately not run on a phase-bearing host.** Those hosts keep
52
+ `references/finish-feature-flow.md` Step 1's two `Tier = T2` checks, which
53
+ never covered a T3 row anyway — a T3 has
54
+ no spec file in Dflow (`references/git-integration.md` § Gate Checks by
55
+ Branch Type).
56
+ - [ ] **Minimal host (zero-phase) only** — the Lightweight Changes table has
57
+ **at least one row** (a T2 or T3 row). An empty Phase Specs table **and**
58
+ an empty Lightweight Changes table is an **empty host** → reject closeout.
59
+ - [ ] **Minimal host (zero-phase) only** — **every spec file in the host
60
+ directory is named by a row.** The row-driven checks — this file's
61
+ `Commit` cell check and `references/finish-feature-flow.md` Step 1's two
62
+ `Tier = T2` items — walk rows → files, so a spec file that no row names is
63
+ never examined by them; this item closes
64
+ the other direction. A `phase-spec-*` always fails (the Phase Specs table
65
+ is empty by definition); a `lightweight-*.md` / `BUG-*.md` with no
66
+ Tier = T2 row fails the same way. A **T3-only** host carries no spec file
67
+ at all, so any spec file there fails this check.
68
+ - [ ] **Minimal host (zero-phase) only** — the Checkpoint Log shows a
69
+ **committed** first checkpoint before this closeout: Checkpoint
70
+ `implementation` with Result `committed ({hash})` (normal) or `reconciled
71
+ ({merged-hotfix-hash})` (hotfix post-hoc). A first checkpoint still
72
+ reading `skipped` or `failed` **blocks** closeout — but they are not the
73
+ same problem. `failed` means the commit was attempted and did not land:
74
+ the work is genuinely uncommitted and has to land. `skipped` means only
75
+ that **the AI's offer was declined** (`references/git-integration.md`
76
+ § Commit Checkpoints), *not* that no commit exists — the developer may
77
+ have made it themselves, which leaves the ledger **incomplete rather than
78
+ final**. Complete it: `modify-existing-flow.md` Step 1.7's "Finalize +
79
+ close" backfills the row to `committed ({hash})` with the developer's real
80
+ hash. Do **not** waive this check for a `skipped` row, and do **not** write
81
+ a hash you have not verified.
82
+ - [ ] **Minimal host (zero-phase) only** — **the Checkpoint Log carries exactly
83
+ one row at this point.** A minimal host takes exactly two checkpoints and
84
+ the second is the closeout row `references/finish-feature-flow.md` Step 4
85
+ instruction 1 adds, so before closeout there is exactly one: the first
86
+ checkpoint the preceding item validated. Any second pre-closeout row
87
+ **blocks** — **report the one that is true**, because the repairs differ.
88
+ What separates them is **whether the row records a checkpoint this host
89
+ actually reached**, not what its cells hold. A row that records none is
90
+ repaired **by deleting it**, however it is filled in: a `closeout` row is
91
+ one, because no closeout has run yet — Step 4 instruction 1 writes it at
92
+ closeout — and so is any row carried over from `templates/_index.md`'s
93
+ example table. A row that does record a reached checkpoint — a second
94
+ `implementation`, a leftover from an abandoned attempt, or one this list
95
+ does not name — says the host did not take the two-commit lifecycle, and
96
+ that is settled with the developer, not by deleting a line. A failed or
97
+ declined attempt does **not** add a row: both are recorded by editing the
98
+ existing one in place.
99
+ This counts the rows in **this host's own table** — it is not
100
+ the whole-history assertion, which stays with
101
+ `references/pr-review-checklist.md`.
102
+ - [ ] **Minimal host (zero-phase) only** — **that first commit is real, and it
103
+ is this host's.** The Checkpoint Log is prose; verify the hash behind it
104
+ against **hash evidence**. Take the hash that stands for checkpoint 1 —
105
+ for a **normal** host the `committed ({hash})` value; for a **hotfix
106
+ post-hoc** host the Lightweight Changes row's `Commit` cell (**not** the
107
+ `reconciled (...)` hash, which names the already-merged hotfix). For (c),
108
+ touching *some* path under
109
+ `dflow/specs/features/active/{SPEC-ID}-{slug}/` is **not enough** — a
110
+ stray host-open commit does that much while the work is still
111
+ uncommitted. Require the tier's artifact **among the commit's changed
112
+ paths** — (c) is what this commit wrote, not what its tree contains: a
113
+ **T2**'s `lightweight-*.md` / `BUG-*.md` spec file, or for a **T3** an
114
+ `_index.md` the commit **changed** *and* which, as committed at that hash,
115
+ already carries this change's Lightweight Changes row — `git show --stat
116
+ {hash}` **and** `git show
117
+ {hash}:dflow/specs/features/active/{SPEC-ID}-{slug}/_index.md`, both, not
118
+ either. Any of (a)–(c) failing **blocks** closeout.
119
+ - [ ] **Minimal host (zero-phase) only** — **checkpoint 1 is *one* commit, and
120
+ every row names it.** For a **normal** host the Checkpoint Log's
121
+ `committed ({hash})` and **every** Lightweight Changes row's `Commit` must
122
+ be the **same** hash, and that commit's diff must **touch the
123
+ implementation paths** its lightweight-spec or rows describe. Step 1.7
124
+ requires the artifact to **declare** those paths; an artifact naming none
125
+ leaves nothing to compare against, so a missing declaration **blocks** —
126
+ it never passes vacuously.
127
+ Assert the **equality itself**, not merely that each value passes hash
128
+ evidence on its own: two hashes that each resolve, are each reachable, and
129
+ each contain some named artifact describe a **three**-commit host —
130
+ host+spec at A, implementation at B, closeout at C — which clears every
131
+ other check on this list while breaking the two-commit lifecycle.
132
+ **Exempt — post-hoc hotfix only, and only this much:** the
133
+ `reconciled (...)` checkpoint hash and the row `Commit` cells name
134
+ different commits **by design** (Step 1.8), so do not assert equality
135
+ *between those two*, and do not apply the implementation-path condition to
136
+ this host's own commit — this file's `Minimal host, hotfix post-hoc only`
137
+ check tests the merged hotfix instead.
138
+ **Everything else still holds:** a post-hoc host can be compound too
139
+ (Step 1.7, "minimal means zero-phase, not one-artifact"), so **every** row
140
+ `Commit` must still name the **same single documentation commit**.
141
+ - [ ] **Minimal host (zero-phase) only** — **nothing that constitutes the change
142
+ itself is still uncommitted.** This is deliberately not "the host
143
+ directory is clean": **checkpoint 1 carries the change, the closeout
144
+ commit carries the record the flow writes afterwards.** Checkpoint 1 sits
145
+ at `modify-existing-flow.md`'s Step 4 → Step 5 gate and holds the change
146
+ itself — for a **T2** its lightweight-spec plus the implementation source,
147
+ for a **T3** its `_index.md` row plus the implementation source. What the
148
+ flow writes *after* that gate — Step 5's completion checklist and Step
149
+ 1.7's "Finalize + close" — is derived record and rides into the closeout
150
+ commit.
151
+ **A post-hoc host (Step 1.8) inverts the source half, and this is where
152
+ the reconciliation contract is enforced.** Its change is the *already
153
+ merged* hotfix; checkpoint 1 is the **documentation** commit. So that
154
+ commit must carry the spec / row and this host's `_index.md` and must
155
+ **not** touch any implementation path the artifact declares — read
156
+ `git show --stat {checkpoint-1-hash}` and block if one appears. A
157
+ re-implementation committed there passes every other gate on this list
158
+ (rows agree, the `reconciled` hash differs from it and touches the
159
+ declared paths, the tree is clean) while breaking §8's "reconcile, do not
160
+ re-run" outright, so nothing else catches it.
161
+ **What this proves and what it does not — do not widen it here.** It
162
+ proves checkpoint 1 is documentation-only. It does **not** prove the
163
+ branch carries no re-implementation elsewhere: a second commit beside
164
+ checkpoint 1, or a re-implementation in a path the artifact does not
165
+ declare, both survive it. Widening it to the branch was tried and does not
166
+ work from inside closeout — the range needs a base branch, and Dflow
167
+ deliberately does not know yours. ⚠ **No check covers it today.** The
168
+ whole-history item `references/finish-feature-flow.md` Step 1 assigns to
169
+ `references/pr-review-checklist.md` is **not** it: that one counts commits
170
+ under this host's spec directory, so a re-implementation commit touching
171
+ only source never appears in its output. Review is where the missing
172
+ assertion belongs — a reviewer has the base branch in front of them — but
173
+ do not read the existing item as discharging it.
174
+ **Blocks closeout:** any of the **implementation source** files this
175
+ host's lightweight-spec or rows describe, staged or unstaged in
176
+ `git status --porcelain`; any **untracked** file under
177
+ `dflow/specs/features/active/{SPEC-ID}-{slug}/`; and any tracked file
178
+ dirty beyond the closed list below.
179
+ **May ride into the closeout commit — this list and nothing else:**
180
+ (i) `_index.md`, with its uncommitted delta confined to Lightweight
181
+ Changes `Commit` cells, Checkpoint Log rows, Resume Pointer, and Current
182
+ BR Snapshot;
183
+ (ii) an **already-committed** `lightweight-*.md` / `BUG-*.md`, with its
184
+ uncommitted delta confined to the frontmatter `status:` flip to
185
+ `completed` and the `Implementation Tasks` edits
186
+ `modify-existing-flow.md` Step 5's completion checklist makes ("applies
187
+ to both phase-spec and lightweight-spec"): ticking the tasks this change
188
+ completed and labelling each unchecked one as follow-up (5.1), and — when
189
+ the developer accepted the offer — collapsing or removing the section
190
+ (5.2). On a minimal host that checklist necessarily runs *after*
191
+ checkpoint 1, so these edits are uncommitted here by construction;
192
+ (iii) the Domain-layer documents **this change's Step 5.3 sweep** updates
193
+ — under `dflow/specs/domain/`, plus
194
+ `dflow/specs/architecture/tech-debt.md` — scoped to *this change's*
195
+ delta. A **T3** has no Domain sweep at all (`modify-existing-flow.md`
196
+ Step 5's tier-conditional
197
+ note), so nothing qualifies under (iii) for a T3. A **no-BC** host has no
198
+ *BC-scoped* sweep — a dirty `dflow/specs/domain/{context}/…` or
199
+ `context-map.md` under one is fiction and **blocks** — but the **global**
200
+ documents (`glossary.md`, `domain/analysis.md`,
201
+ `architecture/tech-debt.md`) belong to no bounded context, stay in its
202
+ sweep, and therefore still qualify under (iii).
203
+ Read each delta (`git diff -- {path}`) — do not infer it from the
204
+ filename. **The list is closed** — if a later change adds another
205
+ finalization field, add it here explicitly; "a host file is dirty" is never
206
+ on its own a reason to pass. (Unrelated work in progress elsewhere is
207
+ fine; say which files you judged unrelated.)
208
+ - [ ] **Minimal host (zero-phase), no-BC only** — **the host did not commit a
209
+ bounded context it does not have.** This file's `nothing that constitutes
210
+ the change itself is still uncommitted` check reads the *working
211
+ tree*; this one reads the **committed** side, because a fictitious
212
+ `{context}` invented at Step 2 and committed into checkpoint 1 leaves a
213
+ perfectly clean tree. Inspect checkpoint 1's diff
214
+ (`git show --stat {hash}`, with status — **not path names alone**): for a
215
+ host that declared itself no-BC that commit must **not touch, in any way**
216
+ — add, modify, delete or rename — any `dflow/specs/domain/{context}/…`
217
+ document. A deletion is a BC-layer change like any other, and reading only
218
+ the path list would accept one as if nothing had happened. The documents:
219
+ `rules.md`, `behavior.md`, `events.md`, `models.md`, `analysis.md` — and
220
+ no `context-map.md`. Any of them **blocks**
221
+ (`modify-existing-flow.md` Step 2's no-BC guard is where this should have
222
+ been caught first).
223
+ **Do not over-reach:** this rejects only Domain documents that commit
224
+ *added or changed* — pre-existing Domain files it never touched are
225
+ irrelevant, and the **global** documents (`glossary.md`,
226
+ `domain/analysis.md`, `architecture/tech-debt.md`) belong to no bounded
227
+ context and stay legitimate for a no-BC host, exactly as that check's
228
+ allow-list says.
229
+ **What this check cannot decide — stated, not asserted:** ⚠ **the rule it
230
+ enforces is not minimal-host-only; only this proof is.** *No no-BC host of
231
+ any shape may commit BC-scoped Domain material* — and what this reads is
232
+ **checkpoint 1**, one commit. It is not a branch-range proof: a second
233
+ commit beside checkpoint 1 carrying a `domain/{context}/…` document
234
+ survives it, and a **phase-bearing** no-BC host has no single checkpoint to
235
+ inspect at all, so it never runs this check in the first place. Closeout
236
+ cannot widen it — the range needs a base branch and Dflow deliberately does
237
+ not know yours (the same limit that working-tree check states).
238
+ **The branch-range assertion is confirmed by
239
+ `references/pr-review-checklist.md`'s "A no-BC host committed no BC-scoped
240
+ Domain material" item**, in that file's *Delegated to review by
241
+ `finish-feature-flow.md`* block, which applies to **every** no-BC host.
242
+ Keep this check anyway: it blocks earlier and more cheaply than review.
243
+ - [ ] **Minimal host (zero-phase), follow-up only** — **the reverse link was
244
+ opened, not only closed.** Step 1.6 requires the original feature's
245
+ Follow-up Tracking row for this host to be created as `in-progress` and to
246
+ ride checkpoint 1; `references/finish-feature-flow.md` Step 6 flips it to
247
+ `completed` afterwards. Verify the
248
+ opening half here, from committed state: for **every** SPEC-ID this host's
249
+ `follow-up-of` names — it may be a YAML array, so check each one —
250
+ `git show {checkpoint-1-hash}:dflow/specs/features/completed/{原 SPEC-ID}-{原 slug}/_index.md`
251
+ must already carry this host's row with Status `in-progress`. A row absent
252
+ there **blocks** closeout: the Step 6 flip would then create it directly as
253
+ `completed`, and the `absent → in-progress → completed` history the
254
+ follow-up contract requires never happened.
255
+ **What this check cannot decide — stated, not asserted:** ⚠ **only this
256
+ *proof* is minimal-host-only.** `references/finish-feature-flow.md`'s
257
+ Step 5 → Step 6 post-Local-closeout confirmation carries the requirement
258
+ itself and names who confirms it for a phase-bearing follow-up host; do
259
+ not read this check's scope as the requirement's scope. The evidence is what stops here: that host has no
260
+ single commit required to carry the row, so there is no committed blob for
261
+ this check to read and it never runs there.
262
+ - [ ] **Minimal host, hotfix post-hoc only** — the reconciliation record is
263
+ complete, **within a stated boundary**. This check proves **plausibility,
264
+ not identity**: that `{merged-hotfix-hash}` is a credible candidate, and
265
+ that the developer has said on the record which fix it is and how they
266
+ know. Whether it is *the* merged hotfix is **not decidable from inside
267
+ this flow** — the repository holds no independent record of which commit
268
+ that was; only the developer and the issue tracker do. Do not read a pass
269
+ here as identity confirmed. Identity is
270
+ **asserted** at `modify-existing-flow.md` Step 1.8 and **confirmed** by
271
+ `references/pr-review-checklist.md` — the same assignment
272
+ `references/finish-feature-flow.md` Step 1 gives the whole-history
273
+ assertion.
274
+ The plausibility conditions, all required: the
275
+ `reconciled ({merged-hotfix-hash})` value passes hash evidence — (a) and
276
+ (b) as usual, and for **(c)** its diff touches the implementation paths
277
+ the T2 lightweight-spec or the T3 row **declares** (Step 1.7 requires that
278
+ declaration; an artifact naming none leaves (c) nothing to compare and
279
+ **blocks** rather than passing vacuously). It must also **differ**
280
+ from the Lightweight Changes row's documentation-commit hash (different
281
+ provenance; see Step 1.8). The per-tier trace must exist too: a **T2**
282
+ carries `hotfix-branch:` in its lightweight-spec frontmatter, a **T3** has
283
+ its Lightweight Changes row Description marked as a hotfix. Finally the
284
+ developer's identity assertion must be **present and cited** — Step 1.8
285
+ requires the source it rests on (PR / incident / tracker reference), and
286
+ it lives with the per-tier trace, so look for it there: beside
287
+ `hotfix-branch:` in a **T2**'s lightweight-spec, in the row Description
288
+ for a **T3**. An uncited hash **blocks** closeout: it leaves pr-review
289
+ nothing to confirm against, and this gate is not a substitute for that
290
+ confirmation.
291
+
292
+ > **Zero-phase minimal host (`modify-existing-flow.md` Step 1.7 / the Step 1.6
293
+ > minimal variant / Step 1.8's post-hoc hotfix, whose linkage resolves to one of
294
+ > those two).** A standalone or follow-up minimal host closes out with
295
+ > an **empty Phase Specs table** — that is valid, not a failure: the "every
296
+ > Phase Specs row is completed" check passes vacuously and there is no
297
+ > `phase-spec-*` file to look for. A no-BR / T3 host also has an intentionally
298
+ > empty Current BR Snapshot — `references/finish-feature-flow.md` Step 1's
299
+ > **Current BR Snapshot** check decides that from the host's own record, not
300
+ > from a declaration. Do **not**
301
+ > manufacture a phase-spec or a BR row to make a check "pass".
302
+
303
+ ## Step 3 — sync input
304
+
305
+ **Minimal host — sync input.** A minimal host has no phase-spec: read the
306
+ "phase-spec" references in `references/finish-feature-flow.md` Step 3's sync
307
+ instructions (events "introduced by phase-specs", "each phase-spec's Delta") as
308
+ the host's **lightweight-spec** recorded delta
309
+ plus its Current BR Snapshot. A no-BR family that changed an event field or a
310
+ documented behaviour still syncs `events.md` / `behavior.md` from that
311
+ lightweight-spec's delta.
312
+ ⚠ What is minimal-host-only here is the **input binding** — the instruction to
313
+ read "phase-spec" as "lightweight-spec", which a host with no phase-spec needs
314
+ and a phase-bearing one must not apply. It is **not** that step's
315
+ **Every host — lightweight-spec deltas are a sync input too** paragraph, which
316
+ every host shape needs.
317
+
318
+ ## Step 4 — post-commit verification, additionally
319
+
320
+ Add this to `references/finish-feature-flow.md` Step 4's post-commit
321
+ verification, inside its archived-host-directory item:
322
+
323
+ **Minimal host (zero-phase) additionally**: the **first** checkpoint row
324
+ still carries the hash this file's Step 1 checks validated —
325
+ `implementation` with `committed ({hash})` or
326
+ `reconciled ({merged-hotfix-hash})`.
327
+
328
+ ## Step 5 — Integration Summary, exact fields
329
+
330
+ **Zero-phase minimal host — exact fields** (these must match the
331
+ `references/finish-feature-flow.md` Step 3 branch — do not require a field that
332
+ step left empty). A standalone or follow-up
333
+ minimal host has `Phase Count: 0`, an empty Phase List, and at least one row in
334
+ Lightweight Changes.
335
+
336
+ - a **no-BC host** (that step's case ii) sets the fields that report a **sync** to
337
+ none — `BC: none`, `Aggregates affected: none`, `Domain Events Changes:
338
+ none` (nothing was synced). **`Related BR-IDs` is not one of them**: it
339
+ reports what this change's own record carries, not what was synced, so it
340
+ takes the same values a BC-bearing host would — **empty**, or the
341
+ **per-family no-BR marker** when the T2 carries one. A T3-only no-BC host has
342
+ neither and leaves it empty.
343
+ - a **BC-bearing host** (that step's case i) sets `BC:` to the context and fills
344
+ each Domain field with **what it actually touched**: `Related BR-IDs:` a real
345
+ set, the per-family no-BR marker, or empty for a no-BR host; `Aggregates
346
+ affected:` and `Domain Events Changes:` the ones it changed, or `none` for
347
+ those it did not.
348
+
349
+ **What is scoped here and what is not.** This block fixes the *whole* field set
350
+ for a zero-phase host — `Phase Count: 0`, the empty Phase List, and which fields
351
+ each Step 3 branch leaves empty — and that part is genuinely zero-phase-only.
352
+ The `none`-for-unchanged rule on the last bullet is **not**: every BC-bearing
353
+ host needs it, and it is now stated where every one of them reads it, in
354
+ **`references/finish-feature-flow.md` Step 3 case (i)**. The two say the same
355
+ thing on purpose; if you change one, change the other.
356
+
357
+ ⚠ **No proof obligation is delegated from this block, and that is not an
358
+ omission.** These are field-filling instructions — they order values, they do
359
+ not test anything — so there is no evidence duty here for another host shape to
360
+ discharge or for review to take over. **N/A, stated rather than left blank**:
361
+ elsewhere in this file a scoped check that cannot reach another host shape hands
362
+ that shape to `references/pr-review-checklist.md` by name, and a reader who
363
+ finds no such hand-off here should not conclude one went missing.
@@ -0,0 +1,95 @@
1
+ # Post-Hoc Hotfix Reconciliation — Greenfield Clean Architecture
2
+
3
+ Branch file of `references/finish-feature-flow.md`. It **adds** the
4
+ reconciliation rules; it does not restate or override anything in that flow.
5
+
6
+ **Two different places in `references/finish-feature-flow.md` send you here, at
7
+ two different times. Read only the section that matches the one that sent you.**
8
+
9
+ - **Step 1's pre-checklist callout** — the branches met while this host was
10
+ still open → § Before closeout.
11
+ - **Step 5** — Step 4 has already archived and committed this host → § After
12
+ closeout.
13
+
14
+ ## Before closeout
15
+
16
+ **You are here when** `references/finish-feature-flow.md` Step 1's hotfix
17
+ callout sent you — it states the condition; this file does not restate it.
18
+
19
+ **What you classify here is the merge-resolution delta, not the hotfix.** The
20
+ hotfix records itself in its **own** minimal host through Step 1.8 — follow-up
21
+ or standalone, never an in-flight feature — and that host is where
22
+ `reconciled ({merged-hotfix-hash})`, the identity citation and the per-tier
23
+ trace live. If the hotfix has not been documented yet, run Step 1.8 for it
24
+ first and come back; do **not** absorb it into this feature, whose ordinary
25
+ checkpoints would record none of that. What is left for this host is only what
26
+ *choosing between the two versions* changed. **Classify that by the cascade,
27
+ then record what the classification calls for:**
28
+
29
+ - **No tracked delta** — the cascade's **below workflow** level. It stays in
30
+ the integration commit message; do **not** manufacture a row or a document.
31
+ Nothing to validate, so nothing changes below. This is the common case.
32
+ - **A tracked delta (T3 or above), phase-bearing host** — record it in this
33
+ host and let it ride the normal checkpoints, then run
34
+ `references/finish-feature-flow.md` Step 1's checklist against the result. A
35
+ phase-bearing host has no fixed commit count, so an extra checkpoint is
36
+ ordinary.
37
+ - **A tracked delta (T3 or above), minimal (zero-phase) host** — it does
38
+ **not** go into this host: the two-commit lifecycle has one implementation
39
+ checkpoint and one closeout, and every Lightweight Changes row must belong
40
+ to that first commit. This host closes on what it already carries, and the
41
+ delta is routed **after** Step 4 archives it — by the **A tracked delta (T3
42
+ or above)** bullet of § After closeout, the same route every post-closeout
43
+ leftover takes. Do **not** route it now:
44
+ you are mid-closeout, and routing would open a second host before this one
45
+ is sealed. Note it, finish the closeout, then take § After closeout's route —
46
+ back through `/dflow:modify-existing`, which picks the host the way it
47
+ always does. Do not decide that here: by then this feature is *completed*,
48
+ so the normal completed-feature disambiguation applies and the answer may be
49
+ a follow-up or a standalone host.
50
+
51
+ Classification decides, never "is it worth writing down". After closeout the
52
+ host is frozen — § After closeout says what is left over, and applies the same
53
+ cascade.
54
+
55
+ ## After closeout
56
+
57
+ **You are here when** `references/finish-feature-flow.md` Step 5 sent you.
58
+
59
+ **A mainline hotfix that overlapped this feature.** A T2 / T3 post-hoc hotfix
60
+ (`modify-existing-flow.md` Step 1.8) records itself in its own host, so when
61
+ this feature's branch finally meets the mainline both may have touched the same
62
+ code, and whoever merges picks between two existing versions. By the time you
63
+ read this, **Step 4 has already archived and committed this feature — its host
64
+ is frozen.** Classify whatever is left by the cascade (`AI-AGENT-GUIDE.md`
65
+ § Ceremony Scaling), never by "is it worth writing down":
66
+
67
+ - **No conflict, or a resolution with no tracked delta** — it stays in the
68
+ integration commit message. That is the cascade's **below workflow** level:
69
+ do not manufacture a document, and do not reopen this feature.
70
+ - **A tracked delta (T3 or above)** — completed features are frozen, so it goes
71
+ where every post-completion change goes: back through
72
+ `/dflow:modify-existing`, which opens a follow-up or standalone host for it.
73
+ Do **not** edit the archived `_index.md`.
74
+ - **The resolution moves system state** — if choosing between the two versions
75
+ changes a business rule, a documented behaviour, an event, or the domain
76
+ model, the owning document (`rules.md` / `behavior.md` / `events.md` /
77
+ `models.md`) **must** be updated. That update is itself a tracked change and
78
+ takes the route above; system-state truth is never below workflow.
79
+ - **It is bigger than a merge** — if resolving it means *new or changed*
80
+ behaviour rather than choosing between two that already exist, it is not a
81
+ merge question at all: run it through the cascade and open the flow its tier
82
+ calls for.
83
+
84
+ **Reconciling before closeout is simpler.** If the branches meet while this
85
+ feature is still in flight — a rebase onto the mainline, say — handle it then
86
+ as ordinary in-flow work — but **which host takes it depends on this host's
87
+ shape**. A **phase-bearing** host absorbs a tracked delta (T3 or above) and
88
+ rides the normal checkpoints; a **minimal (zero-phase)** host **cannot** once
89
+ checkpoint 1 has landed, because every Lightweight Changes row must belong to
90
+ that commit — it closes on what it carries and the delta is routed afterwards.
91
+ No tracked delta stays below workflow, in the integration commit message.
92
+ § Before closeout states that whole side in full, minimal-host branch
93
+ included. The four bullets above decide it whichever side of closeout you are on —
94
+ they are principles, not a checklist; the situation is rare and varied, so use
95
+ judgement.