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 — Brownfield Progressive Extraction
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,406 @@
1
+ # Minimal Host (Zero-Phase) Closeout — Brownfield Progressive Extraction
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; 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; for a **baseline**
41
+ row, the capture it records — and for a
42
+ baseline the capture must be **added or modified** by that commit and
43
+ **exist in its tree**, never deleted or renamed away: a commit that
44
+ *removes* the document cannot be the one that captured it, yet it changes
45
+ the same path. This applies to
46
+ **T2, T3, and baseline rows alike**. Three failures, all blocking —
47
+ **report the one that is true**, because the message is the developer's
48
+ only clue about what to do next: an **empty** cell means that change is not
49
+ committed yet; a cell holding a **placeholder** (`{hash}`, `{pending}`,
50
+ `(待 commit)` — anything `git cat-file -t` cannot resolve) means the cell
51
+ was **never filled in**, which is a different repair and may well have a
52
+ commit sitting there unrecorded; a **resolvable** value that fails (a)–(c)
53
+ means the hash is the wrong one. ⚠ Do not collapse the middle case into the
54
+ first.
55
+ (`modify-existing-flow.md` Step 1.7 "Finalize + close" is where the
56
+ **cell** gets backfilled once its commit exists.)
57
+ **Deliberately not run on a phase-bearing host.** Those hosts keep
58
+ `references/finish-feature-flow.md` Step 1's two `Tier = T2` checks, which
59
+ never covered a T3 row anyway — a T3 has
60
+ no spec file in Dflow (`references/git-integration.md` § Gate Checks by
61
+ Branch Type).
62
+ - [ ] **Minimal host (zero-phase), baseline only** — **a `spec-baseline`
63
+ checkpoint and a `Tier = baseline` row imply each other**, and the host
64
+ carries the capture and nothing else, proved against the **commit**, not
65
+ only the ledger. This check selects when **either** appears: checkpoint 1
66
+ named `spec-baseline`, **or** any `Tier = baseline` row in the Lightweight
67
+ Changes table. Selecting on the checkpoint alone leaves the other
68
+ direction open — a baseline row sitting under an ordinary
69
+ `implementation | committed ({hash})` checkpoint would never be examined,
70
+ while `modify-existing-flow.md` Step 1.7 says a baseline capture is
71
+ observation-only and **never** uses `implementation`. So checkpoint 1
72
+ **must** read `spec-baseline` with Result `committed ({hash})`, and all
73
+ three of these hold:
74
+ (1) the Lightweight Changes table holds **exactly one** row and it is the
75
+ `Tier = baseline` one;
76
+ (2) the Current BR Snapshot is **empty**;
77
+ (3) that commit's diff (`git show --stat {hash}`) contains **only this
78
+ list and nothing else** — (i) the BC-layer documents the `Tier = baseline`
79
+ row declares, (ii) this host's own `_index.md`, (iii) for a
80
+ **follow-up** baseline, the `_index.md` of **every** original this host's
81
+ `follow-up-of` names — it may be a YAML array, and Step 1.6 requires the
82
+ opening reverse-link row in **each** of them to ride this commit, so a
83
+ singular reading would reject the second parent — and (iv) the **global**
84
+ documents a capture records into (`glossary.md`, `domain/analysis.md`,
85
+ `migration/tech-debt.md`), which belong to no bounded context and are
86
+ named as capture destinations by Part A's observation-only routing and by
87
+ Step 2's Systematic Baseline Capture. **Any other path blocks —
88
+ implementation source above all.**
89
+ (A **phase-bearing** host may legitimately hold a `Tier = baseline` row
90
+ alongside other work; it is not zero-phase and never reaches this check.)
91
+ - [ ] **Minimal host (zero-phase) only** — the Lightweight Changes table has
92
+ **at least one row** (a T2, T3, or baseline row). An empty Phase Specs
93
+ table **and** an empty Lightweight Changes table is an **empty host** →
94
+ reject closeout.
95
+ - [ ] **Minimal host (zero-phase) only** — **every spec file in the host
96
+ directory is named by a row.** The row-driven checks — this file's
97
+ `Commit` cell check and `references/finish-feature-flow.md` Step 1's two
98
+ `Tier = T2` items — walk rows → files, so a spec file that no row names is
99
+ never examined by them; this item closes
100
+ the other direction. A `phase-spec-*` always fails (the Phase Specs table
101
+ is empty by definition); a `lightweight-*.md` / `BUG-*.md` with no
102
+ Tier = T2 row fails the same way. A **T3-only** or **baseline** host
103
+ carries no spec file at all, so any spec file there fails this check.
104
+ - [ ] **Minimal host (zero-phase) only** — the Checkpoint Log shows a
105
+ **committed** first checkpoint before this closeout: Checkpoint
106
+ `implementation` with Result `committed ({hash})` (normal) or `reconciled
107
+ ({merged-hotfix-hash})` (hotfix post-hoc), or — for a **baseline** host —
108
+ Checkpoint `spec-baseline` with Result `committed ({hash})`. A first
109
+ checkpoint still reading `skipped` or `failed` **blocks** closeout — but
110
+ they are not the same problem. `failed` means the commit was attempted and
111
+ did not land: the work is genuinely uncommitted and has to land. `skipped`
112
+ means only that **the AI's offer was declined**
113
+ (`references/git-integration.md` § Commit Checkpoints), *not* that no
114
+ commit exists — the developer may have made it themselves, which leaves
115
+ the ledger **incomplete rather than final**. Complete it:
116
+ `modify-existing-flow.md` Step 1.7's "Finalize + close" backfills the row
117
+ to `committed ({hash})` with the developer's real hash. Do **not** waive
118
+ this check for a `skipped` row, and do **not** write a hash you have not
119
+ verified.
120
+ - [ ] **Minimal host (zero-phase) only** — **the Checkpoint Log carries exactly
121
+ one row at this point.** A minimal host takes exactly two checkpoints and
122
+ the second is the closeout row `references/finish-feature-flow.md` Step 4
123
+ instruction 1 adds, so before closeout there is exactly one: the first
124
+ checkpoint the preceding item validated. Any second pre-closeout row
125
+ **blocks** — **report the one that is true**, because the repairs differ.
126
+ What separates them is **whether the row records a checkpoint this host
127
+ actually reached**, not what its cells hold. A row that records none is
128
+ repaired **by deleting it**, however it is filled in: a `closeout` row is
129
+ one, because no closeout has run yet — Step 4 instruction 1 writes it at
130
+ closeout — and so is any row carried over from `templates/_index.md`'s
131
+ example table. A row that does record a reached checkpoint — a second
132
+ `implementation` or `spec-baseline`, a leftover from an abandoned attempt,
133
+ or one this list does not name — says the host did not take the two-commit
134
+ lifecycle, and that is settled with the developer, not by deleting a line.
135
+ A failed or declined attempt does **not** add a row: both are recorded by
136
+ editing the existing one in place.
137
+ This counts the rows in **this
138
+ host's own table** — it is not the whole-history assertion, which stays
139
+ with `references/pr-review-checklist.md`.
140
+ - [ ] **Minimal host (zero-phase) only** — **that first commit is real, and it
141
+ is this host's.** The Checkpoint Log is prose; verify the hash behind it
142
+ against **hash evidence**. Take the hash that stands for checkpoint 1 —
143
+ for a **normal** host the `committed ({hash})` value; for a **baseline**
144
+ host the `spec-baseline` row's `committed ({hash})` value; for a **hotfix
145
+ post-hoc** host the Lightweight Changes row's `Commit` cell (**not** the
146
+ `reconciled (...)` hash, which names the already-merged hotfix). For (c),
147
+ touching *some* path under
148
+ `dflow/specs/features/active/{SPEC-ID}-{slug}/` is **not enough** — a
149
+ stray host-open commit does that much while the work is still
150
+ uncommitted. Require the tier's artifact **among the commit's changed
151
+ paths** — (c) is what this commit wrote, not what its tree contains: a
152
+ **T2**'s `lightweight-*.md` / `BUG-*.md` spec file; for a **T3** an
153
+ `_index.md` the commit **changed** *and* which, as committed at that hash,
154
+ already carries this change's Lightweight Changes row — `git show --stat
155
+ {hash}` **and** `git show
156
+ {hash}:dflow/specs/features/active/{SPEC-ID}-{slug}/_index.md`, both, not
157
+ either; for a **baseline**, the capture it claims to record —
158
+ **added or modified** and present in that commit's tree, never deleted or
159
+ renamed away — together with the `Tier = baseline` row. Any of (a)–(c)
160
+ failing **blocks** closeout.
161
+ - [ ] **Minimal host (zero-phase) only** — **checkpoint 1 is *one* commit, and
162
+ every row names it.** For a **normal** host the Checkpoint Log's
163
+ `committed ({hash})` and **every** Lightweight Changes row's `Commit` must
164
+ be the **same** hash, and that commit's diff must **touch the
165
+ implementation paths** its lightweight-spec or rows describe. Step 1.7
166
+ requires the artifact to **declare** those paths; an artifact naming none
167
+ leaves nothing to compare against, so a missing declaration **blocks** —
168
+ it never passes vacuously. For a **baseline** host the same equality holds
169
+ between the `spec-baseline` row's `committed ({hash})` and the
170
+ `Tier = baseline` row's `Commit`; its counterpart to "implementation
171
+ paths" is the documents that capture recorded.
172
+ Assert the **equality itself**, not merely that each value passes hash
173
+ evidence on its own: two hashes that each resolve, are each reachable, and
174
+ each contain some named artifact describe a **three**-commit host —
175
+ host+spec at A, implementation at B, closeout at C — which clears every
176
+ other check on this list while breaking the two-commit lifecycle.
177
+ **Exempt — post-hoc hotfix only, and only this much:** the
178
+ `reconciled (...)` checkpoint hash and the row `Commit` cells name
179
+ different commits **by design** (Step 1.8), so do not assert equality
180
+ *between those two*, and do not apply the implementation-path condition to
181
+ this host's own commit — this file's `Minimal host, hotfix post-hoc only`
182
+ check tests the merged hotfix instead.
183
+ **Everything else still holds:** a post-hoc host can be compound too
184
+ (Step 1.7, "minimal means zero-phase, not one-artifact"), so **every** row
185
+ `Commit` must still name the **same single documentation commit**.
186
+ - [ ] **Minimal host (zero-phase) only** — **nothing that constitutes the change
187
+ itself is still uncommitted.** This is deliberately not "the host
188
+ directory is clean": **checkpoint 1 carries the change, the closeout
189
+ commit carries the record the flow writes afterwards.** Checkpoint 1 sits
190
+ at `modify-existing-flow.md`'s Step 5 → Step 6 gate and holds the change
191
+ itself — for a **T2** its lightweight-spec plus the implementation source,
192
+ for a **T3** its `_index.md` row plus the implementation source, and for a
193
+ **baseline** host the capture itself, which *is* that host's
194
+ change. What the flow writes *after* that gate — Step 6's completion
195
+ checklist and Step 1.7's "Finalize + close" — is derived record and rides
196
+ into the closeout commit.
197
+ **A post-hoc host (Step 1.8) inverts the source half, and this is where
198
+ the reconciliation contract is enforced.** Its change is the *already
199
+ merged* hotfix; checkpoint 1 is the **documentation** commit. So that
200
+ commit must carry the spec / row and this host's `_index.md` and must
201
+ **not** touch any implementation path the artifact declares — read
202
+ `git show --stat {checkpoint-1-hash}` and block if one appears. A
203
+ re-implementation committed there passes every other gate on this list
204
+ (rows agree, the `reconciled` hash differs from it and touches the
205
+ declared paths, the tree is clean) while breaking §8's "reconcile, do not
206
+ re-run" outright, so nothing else catches it.
207
+ **What this proves and what it does not — do not widen it here.** It
208
+ proves checkpoint 1 is documentation-only. It does **not** prove the
209
+ branch carries no re-implementation elsewhere: a second commit beside
210
+ checkpoint 1, or a re-implementation in a path the artifact does not
211
+ declare, both survive it. Widening it to the branch was tried and does not
212
+ work from inside closeout — the range needs a base branch, and Dflow
213
+ deliberately does not know yours. ⚠ **No check covers it today.** The
214
+ whole-history item `references/finish-feature-flow.md` Step 1 assigns to
215
+ `references/pr-review-checklist.md` is **not** it: that one counts commits
216
+ under this host's spec directory, so a re-implementation commit touching
217
+ only source never appears in its output. Review is where the missing
218
+ assertion belongs — a reviewer has the base branch in front of them — but
219
+ do not read the existing item as discharging it.
220
+ **Blocks closeout:** any of the **implementation source** files this
221
+ host's lightweight-spec or rows describe, staged or unstaged in
222
+ `git status --porcelain`; for a **baseline** host the documents
223
+ its `Tier = baseline` row records, which are that capture's own content
224
+ and belong in the `spec-baseline` commit — never in closeout; any
225
+ **untracked** file under
226
+ `dflow/specs/features/active/{SPEC-ID}-{slug}/`; and any tracked file
227
+ dirty beyond the closed list below.
228
+ **May ride into the closeout commit — this list and nothing else:**
229
+ (i) `_index.md`, with its uncommitted delta confined to Lightweight
230
+ Changes `Commit` cells, Checkpoint Log rows, Resume Pointer, and Current
231
+ BR Snapshot;
232
+ (ii) an **already-committed** `lightweight-*.md` / `BUG-*.md`, with its
233
+ uncommitted delta confined to the frontmatter `status:` flip to
234
+ `completed` and the `Implementation Tasks` edits
235
+ `modify-existing-flow.md` Step 6's completion checklist makes ("applies
236
+ to both phase-spec and lightweight-spec"): ticking the tasks this change
237
+ completed and labelling each unchecked one as follow-up (6.1), and — when
238
+ the developer accepted the offer — collapsing or removing the section
239
+ (6.2). On a minimal host that checklist necessarily runs *after*
240
+ checkpoint 1, so these edits are uncommitted here by construction;
241
+ (iii) the Domain-layer documents **this change's Step 6.3 sweep** updates
242
+ — under `dflow/specs/domain/`, plus
243
+ `dflow/specs/migration/tech-debt.md` — scoped to *this change's* delta.
244
+ A **T3** has no Domain sweep at all (`modify-existing-flow.md` Step 6's
245
+ tier-conditional note), so
246
+ nothing qualifies under (iii) for a T3. A **no-BC** host has no
247
+ *BC-scoped* sweep — a dirty `dflow/specs/domain/{context}/…` or
248
+ `context-map.md` under one is fiction and **blocks** — but the **global**
249
+ documents (`glossary.md`, `domain/analysis.md`,
250
+ `migration/tech-debt.md`) belong to no bounded context, stay in its sweep,
251
+ and therefore still qualify under (iii). **(iii) never covers a baseline
252
+ host** either — its capture *is* the change, and is blocked
253
+ above.
254
+ Read each delta (`git diff -- {path}`) — do not infer it from the
255
+ filename. **The list is closed** — if a later change adds another
256
+ finalization field, add it here explicitly; "a host file is dirty" is never
257
+ on its own a reason to pass. (Unrelated work in progress elsewhere is
258
+ fine; say which files you judged unrelated.)
259
+ - [ ] **Minimal host (zero-phase), no-BC only** — **the host did not commit a
260
+ bounded context it does not have.** This file's `nothing that constitutes
261
+ the change itself is still uncommitted` check reads the *working
262
+ tree*; this one reads the **committed** side, because a fictitious
263
+ `{context}` invented at Step 2 and committed into checkpoint 1 leaves a
264
+ perfectly clean tree. Inspect checkpoint 1's diff
265
+ (`git show --stat {hash}`, with status — **not path names alone**): for a
266
+ host that declared itself no-BC that commit must **not touch, in any way**
267
+ — add, modify, delete or rename — any `dflow/specs/domain/{context}/…`
268
+ document. A deletion is a BC-layer change like any other, and reading only
269
+ the path list would accept one as if nothing had happened. The documents:
270
+ `rules.md`, `behavior.md`, `models.md`, `analysis.md` — and no
271
+ `context-map.md` (the Brownfield context map is optional and grows
272
+ organically, so a no-BC host inventing a row in it is the same fiction).
273
+ Any of them **blocks**
274
+ (`modify-existing-flow.md` Step 2's no-BC guard is where this should have
275
+ been caught first). A **baseline** host is not a no-BC host and this
276
+ check does not apply to it — its capture is the point.
277
+ **Do not over-reach:** this rejects only Domain documents that commit
278
+ *added or changed* — pre-existing Domain files it never touched are
279
+ irrelevant, and the **global** documents (`glossary.md`,
280
+ `domain/analysis.md`, `migration/tech-debt.md`) belong to no bounded
281
+ context and stay legitimate for a no-BC host, exactly as that check's
282
+ allow-list says.
283
+ **What this check cannot decide — stated, not asserted:** ⚠ **the rule it
284
+ enforces is not minimal-host-only; only this proof is.** *No no-BC host of
285
+ any shape may commit BC-scoped Domain material* — and what this reads is
286
+ **checkpoint 1**, one commit. It is not a branch-range proof: a second
287
+ commit beside checkpoint 1 carrying a `domain/{context}/…` document
288
+ survives it, and a **phase-bearing** no-BC host has no single checkpoint to
289
+ inspect at all, so it never runs this check in the first place. Closeout
290
+ cannot widen it — the range needs a base branch and Dflow deliberately does
291
+ not know yours (the same limit that working-tree check states).
292
+ **The branch-range assertion is confirmed by
293
+ `references/pr-review-checklist.md`'s "A no-BC host committed no BC-scoped
294
+ Domain material" item**, in that file's *Delegated to review by
295
+ `finish-feature-flow.md`* block, which applies to **every** no-BC host.
296
+ Its exemptions match this check's: the global documents stay legitimate,
297
+ and a **baseline** host is not a no-BC host there either.
298
+ Keep this check anyway: it blocks earlier and more cheaply than review.
299
+ - [ ] **Minimal host (zero-phase), follow-up only** — **the reverse link was
300
+ opened, not only closed.** Step 1.6 requires the original feature's
301
+ Follow-up Tracking row for this host to be created as `in-progress` and to
302
+ ride checkpoint 1; `references/finish-feature-flow.md` Step 6 flips it to
303
+ `completed` afterwards. Verify the
304
+ opening half here, from committed state: for **every** SPEC-ID this host's
305
+ `follow-up-of` names — it may be a YAML array, so check each one —
306
+ `git show {checkpoint-1-hash}:dflow/specs/features/completed/{原 SPEC-ID}-{原 slug}/_index.md`
307
+ must already carry this host's row with Status `in-progress`. A row absent
308
+ there **blocks** closeout: the Step 6 flip would then create it directly as
309
+ `completed`, and the `absent → in-progress → completed` history the
310
+ follow-up contract requires never happened. A **completed-only baseline**
311
+ host is a follow-up variant and takes this check too.
312
+ **What this check cannot decide — stated, not asserted:** ⚠ **only this
313
+ *proof* is minimal-host-only.** `references/finish-feature-flow.md`'s
314
+ Step 5 → Step 6 post-Local-closeout confirmation carries the requirement
315
+ itself and names who confirms it for a phase-bearing follow-up host; do
316
+ not read this check's scope as the requirement's scope. The evidence is what stops here: that host has no
317
+ single commit required to carry the row, so there is no committed blob for
318
+ this check to read and it never runs there.
319
+ - [ ] **Minimal host, hotfix post-hoc only** — the reconciliation record is
320
+ complete, **within a stated boundary**. This check proves **plausibility,
321
+ not identity**: that `{merged-hotfix-hash}` is a credible candidate, and
322
+ that the developer has said on the record which fix it is and how they
323
+ know. Whether it is *the* merged hotfix is **not decidable from inside
324
+ this flow** — the repository holds no independent record of which commit
325
+ that was; only the developer and the issue tracker do. Do not read a pass
326
+ here as identity confirmed. Identity is
327
+ **asserted** at `modify-existing-flow.md` Step 1.8 and **confirmed** by
328
+ `references/pr-review-checklist.md` — the same assignment
329
+ `references/finish-feature-flow.md` Step 1 gives the whole-history
330
+ assertion.
331
+ The plausibility conditions, all required: the
332
+ `reconciled ({merged-hotfix-hash})` value passes hash evidence — (a) and
333
+ (b) as usual, and for **(c)** its diff touches the implementation paths
334
+ the T2 lightweight-spec or the T3 row **declares** (Step 1.7 requires that
335
+ declaration; an artifact naming none leaves (c) nothing to compare and
336
+ **blocks** rather than passing vacuously). It must also **differ**
337
+ from the Lightweight Changes row's documentation-commit hash (different
338
+ provenance; see Step 1.8). The per-tier trace must exist too: a **T2**
339
+ carries `hotfix-branch:` in its lightweight-spec frontmatter, a **T3** has
340
+ its Lightweight Changes row Description marked as a hotfix. Finally the
341
+ developer's identity assertion must be **present and cited** — Step 1.8
342
+ requires the source it rests on (PR / incident / tracker reference), and
343
+ it lives with the per-tier trace, so look for it there: beside
344
+ `hotfix-branch:` in a **T2**'s lightweight-spec, in the row Description
345
+ for a **T3**. An uncited hash **blocks** closeout: it leaves pr-review
346
+ nothing to confirm against, and this gate is not a substitute for that
347
+ confirmation.
348
+
349
+ > **Zero-phase minimal host (`modify-existing-flow.md` Step 1.7 / the Step 1.6
350
+ > minimal variant / Step 1.8's post-hoc hotfix, whose linkage resolves to one of
351
+ > those two).** A standalone / follow-up minimal host, or a baseline
352
+ > capture, closes out with an **empty Phase Specs table** — that is valid, not
353
+ > a failure: the "every
354
+ > Phase Specs row is completed" check passes vacuously and there is no
355
+ > `phase-spec-*` file to look for. A no-BR / T3 host also has an intentionally
356
+ > empty Current BR Snapshot — `references/finish-feature-flow.md` Step 1's
357
+ > **Current BR Snapshot** check decides that from the host's own record, not
358
+ > from a declaration. Do **not**
359
+ > manufacture a phase-spec or a BR row to make a check "pass".
360
+
361
+ ## Step 3 — sync input
362
+
363
+ **Minimal host — sync input.** A minimal host has no phase-spec: read the
364
+ "phase-spec" references in `references/finish-feature-flow.md` Step 3's sync
365
+ instructions ("each phase-spec's Delta") as the host's **lightweight-spec**
366
+ recorded delta plus its Current BR Snapshot. A
367
+ no-BR family that changed a documented behaviour still syncs `behavior.md` from
368
+ that lightweight-spec's delta.
369
+ ⚠ What is minimal-host-only here is the **input binding** — the instruction to
370
+ read "phase-spec" as "lightweight-spec", which a host with no phase-spec needs
371
+ and a phase-bearing one must not apply. It is **not** that step's
372
+ **Every host — lightweight-spec deltas are a sync input too** paragraph, which
373
+ every host shape needs.
374
+
375
+ ## Step 4 — post-commit verification, additionally
376
+
377
+ Add this to `references/finish-feature-flow.md` Step 4's post-commit
378
+ verification, inside its archived-host-directory item:
379
+
380
+ **Minimal host (zero-phase) additionally**: the **first** checkpoint row
381
+ still carries the hash this file's Step 1 checks validated —
382
+ `implementation` with `committed ({hash})`,
383
+ `reconciled ({merged-hotfix-hash})`, or — for a **baseline** host —
384
+ `spec-baseline` with `committed ({hash})`.
385
+
386
+ ## Step 5 — Integration Summary, exact fields
387
+
388
+ **Zero-phase minimal host — exact fields** (these must match the
389
+ `references/finish-feature-flow.md` Step 3 branch — do not require a field that
390
+ step left empty). A standalone or follow-up
391
+ minimal host has `Phase Count: 0`, an empty Phase List, and at least one row in
392
+ Lightweight Changes.
393
+
394
+ - a **no-BC host** (that step's case ii) sets `BC: none` (nothing was synced).
395
+ **`Related BR-IDs` is not fixed to `none`**: it reports what this change's own
396
+ record carries, not what was synced, so it takes the same values a BC-bearing
397
+ host would — **empty**, or the **per-family no-BR marker** when the T2 carries
398
+ one. A T3-only no-BC host has neither and leaves it empty.
399
+ - a **BC-bearing host** (that step's case i) sets `BC:` to the context and `Related
400
+ BR-IDs:` to what it actually touched — a real set, the per-family no-BR
401
+ marker, or empty for a no-BR host.
402
+ - a **baseline minimal host** (that step's case iii) sets `BC:` to the captured
403
+ context (not `none`); **every other field keeps its zero-phase form**, and
404
+ `Related BR-IDs:` is **empty** — an observation-only capture has no BR delta,
405
+ and BRs it merely *found* already in the code are system state, not this
406
+ change's evidence.
@@ -0,0 +1,95 @@
1
+ # Post-Hoc Hotfix Reconciliation — Brownfield Progressive Extraction
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
+ (or `spec-baseline`) checkpoint and one closeout, and every Lightweight
40
+ Changes row must belong to that first commit. This host closes on what it
41
+ already carries, and the delta is routed **after** Step 4 archives it — by
42
+ the **A tracked delta (T3 or above)** bullet of § After closeout, the same
43
+ route every post-closeout leftover takes.
44
+ Do **not** route it now: you are mid-closeout, and routing would open a
45
+ second host before this one is sealed. Note it, finish the closeout, then
46
+ take § After closeout's route — back through `/dflow:modify-existing`, which
47
+ picks the host the way it always does. Do not decide that here: by then this feature
48
+ is *completed*, so the normal completed-feature disambiguation applies and
49
+ the answer may be 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, or an extracted model, the
76
+ owning document (`rules.md` / `behavior.md` / `models.md`) **must** be
77
+ updated. That update is itself a tracked change and takes the route above;
78
+ 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.