dflow-sdd-ddd 0.15.0 → 0.16.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.
- package/CHANGELOG.md +156 -0
- package/CONTRIBUTING.md +1 -0
- package/README.en.md +7 -4
- package/README.md +7 -4
- package/bin/dflow.js +75 -0
- package/docs/closeout-check.en.md +204 -0
- package/docs/closeout-check.md +204 -0
- package/docs/commands.en.md +4 -2
- package/docs/commands.md +4 -2
- package/docs/release-versioning-policy.md +1 -0
- package/lib/closeout-check.js +690 -0
- package/lib/doc-shapes.json +198 -0
- package/lib/init.js +17 -2
- package/package.json +2 -2
- package/templates/brownfield/references/finish-feature-flow.md +29 -26
- package/templates/brownfield/references/finish-feature-minimal-host.md +38 -17
- package/templates/brownfield/references/finish-feature-record-correction.md +45 -0
- package/templates/brownfield/references/git-integration.md +62 -28
- package/templates/brownfield/references/modify-existing-flow.md +55 -29
- package/templates/brownfield/references/modify-existing-follow-up.md +2 -1
- package/templates/brownfield/references/modify-existing-post-hoc-hotfix.md +121 -3
- package/templates/brownfield/references/new-feature-flow.md +49 -31
- package/templates/brownfield/references/new-phase-flow.md +2 -2
- package/templates/brownfield/references/pr-review-checklist.md +29 -4
- package/templates/brownfield/scaffolding/Git-principles-gitflow.md +13 -5
- package/templates/brownfield/scaffolding/Git-principles-trunk.md +8 -4
- package/templates/brownfield/templates/_index.md +17 -13
- package/templates/common/references/flow-rationale-registry.md +20 -4
- package/templates/greenfield/references/finish-feature-flow.md +29 -26
- package/templates/greenfield/references/finish-feature-minimal-host.md +36 -16
- package/templates/greenfield/references/finish-feature-record-correction.md +45 -0
- package/templates/greenfield/references/git-integration.md +63 -29
- package/templates/greenfield/references/modify-existing-flow.md +42 -27
- package/templates/greenfield/references/modify-existing-follow-up.md +2 -1
- package/templates/greenfield/references/modify-existing-post-hoc-hotfix.md +121 -3
- package/templates/greenfield/references/new-feature-flow.md +49 -31
- package/templates/greenfield/references/new-phase-flow.md +2 -2
- package/templates/greenfield/references/pr-review-checklist.md +28 -4
- package/templates/greenfield/scaffolding/Git-principles-gitflow.md +13 -5
- package/templates/greenfield/scaffolding/Git-principles-trunk.md +8 -4
- package/templates/greenfield/templates/_index.md +18 -13
|
@@ -162,7 +162,18 @@ skip one and the boundary is a hole rather than a division of labour.
|
|
|
162
162
|
checkpoint 1 and closeout. A third, typically a host opened in its own
|
|
163
163
|
commit before the work landed, breaks the two-commit lifecycle while
|
|
164
164
|
every closeout check still passes, because those read only the hashes
|
|
165
|
-
the record points at.
|
|
165
|
+
the record points at. A third that comes **after** checkpoint 1 and
|
|
166
|
+
changes only the host's record text — no implementation path, no new
|
|
167
|
+
host file — may instead be a correction committed on its own once
|
|
168
|
+
checkpoint 1 was pushed (`references/finish-feature-record-correction.md`
|
|
169
|
+
sends the developer that way and asks for it to be named in the PR
|
|
170
|
+
description). Report which it is: the count still fails, and
|
|
171
|
+
accepting a correction commit is your call after reading its full
|
|
172
|
+
diff and the PR description. A correction that touches only a record
|
|
173
|
+
outside this directory — a baseline capture's document, a follow-up's
|
|
174
|
+
original `_index.md` — is not in this walk; the PR description is where
|
|
175
|
+
it is named.
|
|
176
|
+
**This count applies to a minimal host only**: a
|
|
166
177
|
phase-bearing feature has no fixed number of host commits, so there is
|
|
167
178
|
nothing to count there and this item is N/A.
|
|
168
179
|
This is also where closeout's minimal-host **selector** boundary is
|
|
@@ -175,9 +186,23 @@ skip one and the boundary is a hole rather than a division of labour.
|
|
|
175
186
|
so the developer asserts it and cites what the claim rests on —
|
|
176
187
|
`hotfix-identity:` beside `hotfix-branch:` in a **T2**'s
|
|
177
188
|
lightweight-spec frontmatter, or in the row Description for a **T3**.
|
|
178
|
-
**Open that source** — PR, incident, or tracker — and confirm it
|
|
179
|
-
this fix and
|
|
180
|
-
|
|
189
|
+
**Open that source** — PR, incident, or tracker — and confirm that it
|
|
190
|
+
names **this fix** and the recorded commit: one of the fix's own
|
|
191
|
+
commits, or the squash commit when the fix was squashed
|
|
192
|
+
(`references/modify-existing-post-hoc-hotfix.md` item 3). A fix merged
|
|
193
|
+
without a PR is identified by the source and the base branch's history
|
|
194
|
+
instead — the hotfix branch's name or the source's number in commit
|
|
195
|
+
messages.
|
|
196
|
+
**When the fix landed as a copy** — a rebase merge or a cherry-pick —
|
|
197
|
+
the recorded commit is that copy, and the source may not name it. Git
|
|
198
|
+
cannot prove that one commit is a copy of another: ancestry does not
|
|
199
|
+
follow copies, and patch comparison (`git cherry`, `git patch-id`)
|
|
200
|
+
cannot tell apart two changes that differ only in whitespace. A
|
|
201
|
+
`(cherry picked from commit …)` line or a matching subject is a clue,
|
|
202
|
+
not proof — settle it with the author from the source, and do not
|
|
203
|
+
report the identity as confirmed from command output alone.
|
|
204
|
+
Closeout already checked that a citation is *present*; only review can
|
|
205
|
+
check that it *matches*.
|
|
181
206
|
- [ ] **Hosted `Commit` cell identity — confirm each hash is *that row's own*
|
|
182
207
|
implementation commit** (phase-bearing host only). `finish-feature-flow.md`
|
|
183
208
|
Step 4 instruction 1 orders the value ("each row's own implementation
|
|
@@ -126,7 +126,11 @@ within **24 hours** after it lands. Run `/dflow:modify-existing` in
|
|
|
126
126
|
**post-hoc mode** (`references/modify-existing-flow.md` Step 1.8): it opens a
|
|
127
127
|
minimal host of its own for the fix, records the implementation checkpoint as
|
|
128
128
|
`reconciled ({merged-hotfix-hash})`, and reconciles rather than re-running work
|
|
129
|
-
that is already on the mainline.
|
|
129
|
+
that is already on the mainline. The hash it records is the hotfix's own
|
|
130
|
+
commit, **not** the tagged merge commit on `main` (step 3): the record is
|
|
131
|
+
never a merge commit, and step 4 merges the hotfix **branch**, so the tagged
|
|
132
|
+
commit does not come into `develop` with it.
|
|
133
|
+
`references/modify-existing-post-hoc-hotfix.md` item 3 has the rule.
|
|
130
134
|
What gets written is whatever the cascade's tier calls for — a **T2** lands a
|
|
131
135
|
lightweight spec (root cause + fix + a `dflow/specs/migration/tech-debt.md` entry
|
|
132
136
|
if the bug reveals a systemic issue); a **T3** lands one `_index.md` Lightweight
|
|
@@ -185,8 +189,12 @@ before making key Git operations:
|
|
|
185
189
|
|
|
186
190
|
### Before merging a feature branch to `develop`
|
|
187
191
|
|
|
188
|
-
- [ ] `/dflow:finish-feature` has
|
|
189
|
-
|
|
192
|
+
- [ ] **Closeout complete**: `/dflow:finish-feature` has announced closeout
|
|
193
|
+
complete for this host — its Local-closeout gate is satisfied (the
|
|
194
|
+
closeout commit landed and passed post-commit verification) and, if
|
|
195
|
+
the host carries `follow-up-of`, the Step 6 tracking commit has also
|
|
196
|
+
landed and been verified. `status: completed` or a directory already
|
|
197
|
+
under `completed/` does not show this on its own.
|
|
190
198
|
- [ ] `_index.md` status = `completed`, feature directory moved to
|
|
191
199
|
`dflow/specs/features/completed/` via `git mv`
|
|
192
200
|
- [ ] BC layer synced: `dflow/specs/domain/{context}/rules.md` and
|
|
@@ -196,8 +204,8 @@ before making key Git operations:
|
|
|
196
204
|
- [ ] Domain layer (`src/Domain/`) has no delivery-framework references
|
|
197
205
|
|
|
198
206
|
> **Minimal (zero-phase) host.** The items about this host's own record —
|
|
199
|
-
>
|
|
200
|
-
>
|
|
207
|
+
> **Closeout complete**, `_index.md` status `completed`, and the archival
|
|
208
|
+
> move — apply **unchanged**: they are what stops a host merging with
|
|
201
209
|
> its record still open. Every item naming a **Domain or bounded-context
|
|
202
210
|
> artifact** applies only to what this change **actually touched**: a **no-BC**
|
|
203
211
|
> host has no context to sync or document, a **T3** does no Domain work at all,
|
|
@@ -140,8 +140,12 @@ one is not.
|
|
|
140
140
|
|
|
141
141
|
### Gate Checks — Before merging a feature PR to `main`
|
|
142
142
|
|
|
143
|
-
- [ ] `/dflow:finish-feature` has
|
|
144
|
-
|
|
143
|
+
- [ ] **Closeout complete**: `/dflow:finish-feature` has announced closeout
|
|
144
|
+
complete for this host — its Local-closeout gate is satisfied (the
|
|
145
|
+
closeout commit landed and passed post-commit verification) and, if
|
|
146
|
+
the host carries `follow-up-of`, the Step 6 tracking commit has also
|
|
147
|
+
landed and been verified. `status: completed` or a directory already
|
|
148
|
+
under `completed/` does not show this on its own.
|
|
145
149
|
- [ ] `_index.md` status = `completed`, feature directory moved to
|
|
146
150
|
`dflow/specs/features/completed/` via `git mv`
|
|
147
151
|
- [ ] BC layer synced: `dflow/specs/domain/{context}/rules.md` and
|
|
@@ -153,8 +157,8 @@ one is not.
|
|
|
153
157
|
- [ ] PR has at least one review approval
|
|
154
158
|
|
|
155
159
|
> **Minimal (zero-phase) host.** The items about this host's own record —
|
|
156
|
-
>
|
|
157
|
-
>
|
|
160
|
+
> **Closeout complete**, `_index.md` status `completed`, and the archival
|
|
161
|
+
> move — apply **unchanged**: they are what stops a host merging with
|
|
158
162
|
> its record still open. Every item naming a **Domain or bounded-context
|
|
159
163
|
> artifact** applies only to what this change **actually touched**: a **no-BC**
|
|
160
164
|
> host has no context to sync or document, a **T3** does no Domain work at all,
|
|
@@ -6,7 +6,7 @@ created: {YYYY-MM-DD}
|
|
|
6
6
|
branch: feature/{SPEC-ID}-{slug}
|
|
7
7
|
# follow-up-of: {原 SPEC-ID} # 選用:本 feature 為某個已 completed feature 的 follow-up 時填入
|
|
8
8
|
---
|
|
9
|
-
<!-- dflow-shape: brownfield/_index.md
|
|
9
|
+
<!-- dflow-shape: brownfield/_index.md 3 — keep this line: dflow doctor reads it -->
|
|
10
10
|
|
|
11
11
|
<!--
|
|
12
12
|
Template note (for AI):
|
|
@@ -133,8 +133,8 @@ references/new-phase-flow.md。有衝突時以那些檔為準。
|
|
|
133
133
|
> Description 另外標明這是 hotfix,並寫出識別依據(PR/incident/tracker 編號)
|
|
134
134
|
> ——沒有依據的 hash 會擋下 closeout。此時路徑指的是**已合併的那個 hotfix**
|
|
135
135
|
> 碰到的檔案;本列 `Commit` 欄填的是**補文件那個 commit** 的 hash,不是 hotfix
|
|
136
|
-
> 的 hash(後者記在 Checkpoint Log 的 `reconciled (...)`
|
|
137
|
-
>
|
|
136
|
+
> 的 hash(後者記在 Checkpoint Log 的 `reconciled (...)` 列,記哪一顆見
|
|
137
|
+
> references/modify-existing-post-hoc-hotfix.md item 3)。兩者來源不同,不可互填。
|
|
138
138
|
>
|
|
139
139
|
> Tier 判準見 AI-AGENT-GUIDE.md § Ceremony Scaling 的 ordered cascade(步驟 0–4,先命中者勝)。
|
|
140
140
|
|
|
@@ -190,8 +190,9 @@ references/new-phase-flow.md。有衝突時以那些檔為準。
|
|
|
190
190
|
> 生命週期 checkpoint 的 commit / skip 時間線(讓三週後回溯不必手動重建)。
|
|
191
191
|
> 每個 checkpoint 無論 commit 或 skip 都記一列。Tier 決定 checkpoint 數:
|
|
192
192
|
> T1 三點(spec 完 / impl 完 / closeout)、T2 兩點(spec+impl 合併 / closeout)、
|
|
193
|
-
> T3 單一實作 commit
|
|
193
|
+
> T3 單一實作 commit(記它 hash 的那幾格由 host 的下一個 commit 帶進;
|
|
194
194
|
> host 若沒有後續 commit,允許一個只動 ledger 的 tracking commit 收尾,該 commit 不另成列)。
|
|
195
|
+
> `modify-existing` 的那一顆在更新文件那一步(Step 6)做完之後才 commit,連同那一步寫的文件一起帶。
|
|
195
196
|
> ⚠ **上面那些「點」在本表 `Checkpoint` 欄各有固定的字面值**:spec 里程碑寫
|
|
196
197
|
> **`spec-baseline`**、實作寫 **`implementation`**、關帳寫 **`closeout`**(下表的
|
|
197
198
|
> `spec-baseline` / `implementation` / `closeout` 三列就是這幾個值;表中另有一列
|
|
@@ -204,17 +205,18 @@ references/new-phase-flow.md。有衝突時以那些檔為準。
|
|
|
204
205
|
> **Minimal host(zero-phase)例外**——見 references/modify-existing-flow.md
|
|
205
206
|
> Step 1.7(standalone)、Step 1.6 的 follow-up minimal 變體,或 Step 1.8 的
|
|
206
207
|
> post-hoc hotfix(其 linkage 落在前兩者之一):這種 host 之後
|
|
207
|
-
> 沒有別的 commit 可以收攏
|
|
208
|
+
> 沒有別的 commit 可以收攏 row,所以**不分 tier 一律記兩個 checkpoint**
|
|
208
209
|
> (implementation——baseline capture 記 `spec-baseline`——然後 closeout),
|
|
209
|
-
>
|
|
210
|
-
>
|
|
211
|
-
> feature 底下的** T3,不適用於 minimal host。
|
|
210
|
+
> 而且每一列(T3 的 inline row 也一樣)都要**寫進 checkpoint 1 本身**;之後只補記
|
|
211
|
+
> checkpoint 1 hash 的那幾格,搭 closeout commit。上一段「T3 單一實作 commit /
|
|
212
|
+
> 由下一個 commit 帶進」講的是**掛在既有 feature 底下的** T3,不適用於 minimal host。
|
|
212
213
|
>
|
|
213
214
|
> Result 的合法值是 `committed ({hash})` / `skipped` / `failed`,外加
|
|
214
215
|
> **`reconciled ({merged-hotfix-hash})`**——只給 post-hoc hotfix(Step 1.8)的
|
|
215
216
|
> implementation 列用,意思是「本 checkpoint 記錄的是一個已經合併的變更」。
|
|
216
|
-
>
|
|
217
|
-
>
|
|
217
|
+
> 括號裡是**那個修正的 commit**(記哪一顆見
|
|
218
|
+
> references/modify-existing-post-hoc-hotfix.md item 3),不是本 host 補文件那個
|
|
219
|
+
> commit 的 hash(後者填在 Lightweight Changes 該列的 `Commit` 欄)。完整詞彙見
|
|
218
220
|
> references/git-integration.md § Commit Checkpoints, Branch Gate & AI Commits。
|
|
219
221
|
>
|
|
220
222
|
> **`branch-override` 是紀錄列,不是生命週期 checkpoint。** 在 branch gate 選了
|
|
@@ -229,9 +231,11 @@ references/new-phase-flow.md。有衝突時以那些檔為準。
|
|
|
229
231
|
> **minimal host**(Step 1.6 follow-up 變體/Step 1.7 standalone/Step 1.8
|
|
230
232
|
> post-hoc)**不提供**這個選項——那些 host 正是拿 `branch:` 當權威來斷言分支相等的。
|
|
231
233
|
>
|
|
232
|
-
>
|
|
233
|
-
>
|
|
234
|
-
>
|
|
234
|
+
> **checkpoint 的 commit 不可能帶著自己的 hash**:記它 hash 的那幾格(本表那一列的
|
|
235
|
+
> `committed ({hash})`、Lightweight Changes 填同一個 hash 的 `Commit` 格)一律在 commit
|
|
236
|
+
> 實際成功後才寫,搭 host 的**下一個** commit;pre-commit hook reject 或 commit
|
|
237
|
+
> 失敗記 `failed`、不寫假 hash。**例外:closeout 列不填 hash**——這個 host 之後再也
|
|
238
|
+
> 沒有 commit 會帶上它,所以該列於 commit 前寫入、隨歸檔目錄一起進 commit;
|
|
235
239
|
> 溯源用 `git log -1 -- completed/{SPEC-ID}-{slug}` 或選配的
|
|
236
240
|
> `Dflow-Checkpoint` trailer(見 references/git-integration.md)。
|
|
237
241
|
>
|
|
@@ -63,9 +63,9 @@ R-FF-CURSOR-02: [finish-feature-flow.md · Step 4 · "The `git mv` and this writ
|
|
|
63
63
|
|
|
64
64
|
R-FF-GITMV-01: [finish-feature-flow.md · Step 4 · "`git mv` is mandatory — never use plain `mv` + `git add`"] This preserves git's directory rename detection so `git log --follow` / `git blame` / PR diff quality stays intact across the move.
|
|
65
65
|
|
|
66
|
-
R-FF-SWEEPKEY-01: [gf · finish-feature-flow.md · Step 4 instruction 2 · "Key it on the flow that produced the change, never on the flow that opened the host"] Those differ, and keying on the host is how the deadlock came back: `modify-existing-flow.md` Step 1.6 opens a **phase-bearing** host for a T1 follow-up, and Step 5.4 puts a T1 new-phase or a T2 lightweight *inside* a host opened by `/dflow:new-feature` — each of those runs Step 5.3 as its own sweep. Ask "which flow opened this host" and a hosted **T2** on a phase-bearing **no-BC** host has no arm at all: half (a) is empty because Step 3 is skipped, and
|
|
66
|
+
R-FF-SWEEPKEY-01: [gf · finish-feature-flow.md · Step 4 instruction 2 · "Key it on the flow that produced the change, never on the flow that opened the host"] Those differ, and keying on the host is how the deadlock came back: `modify-existing-flow.md` Step 1.6 opens a **phase-bearing** host for a T1 follow-up, and Step 5.4 puts a T1 new-phase or a T2 lightweight *inside* a host opened by `/dflow:new-feature` — each of those runs Step 5.3 as its own sweep. Ask "which flow opened this host" and a hosted **T2** on a phase-bearing **no-BC** host has no arm at all: half (a) is empty because Step 3 is skipped, and a `glossary.md` correction to its Step 5.3 sweep, made after its checkpoint 1, belongs to a sweep the question refused to look at. Unstaged it fails the clean-tree item; staged it is attributable to nothing. Deriving from *this change's* flow is the fix — not widening the set to "anything dirty".
|
|
67
67
|
|
|
68
|
-
R-FF-SWEEPKEY-01: [bf · finish-feature-flow.md · Step 4 instruction 2 · "Key it on the flow that produced the change, never on the flow that opened the host"] Those differ, and keying on the host is how the deadlock came back: `modify-existing-flow.md` Step 1.6 opens a **phase-bearing** host for a T1 follow-up, and Step 6.4 puts a T1 new-phase or a T2 lightweight *inside* a host opened by `/dflow:new-feature` — each of those runs Step 6.3 as its own sweep. Ask "which flow opened this host" and a hosted **T2** on a phase-bearing **no-BC** host has no arm at all: half (a) is empty because Step 3 is skipped, and
|
|
68
|
+
R-FF-SWEEPKEY-01: [bf · finish-feature-flow.md · Step 4 instruction 2 · "Key it on the flow that produced the change, never on the flow that opened the host"] Those differ, and keying on the host is how the deadlock came back: `modify-existing-flow.md` Step 1.6 opens a **phase-bearing** host for a T1 follow-up, and Step 6.4 puts a T1 new-phase or a T2 lightweight *inside* a host opened by `/dflow:new-feature` — each of those runs Step 6.3 as its own sweep. Ask "which flow opened this host" and a hosted **T2** on a phase-bearing **no-BC** host has no arm at all: half (a) is empty because Step 3 is skipped, and a `glossary.md` correction to its Step 6.3 sweep, made after its checkpoint 1, belongs to a sweep the question refused to look at. Unstaged it fails the clean-tree item; staged it is attributable to nothing. Deriving from *this change's* flow is the fix — not widening the set to "anything dirty".
|
|
69
69
|
|
|
70
70
|
R-FF-SWEEPKEY-02: [finish-feature-flow.md · Step 4 instruction 2 · "do not go looking for a list that host never produced"] ⚠ Keying this on the minimal-host allow-list (`finish-feature-minimal-host.md`) is what deadlocked the one shape where both halves are empty: a **phase-bearing, no-BC** host that swept a global document has nothing from Step 3 *and* no Step 1 allow-list, while this instruction still requires the delta staged and the post-commit path check would then reject it as unpermitted — two mandatory requirements that could not both be met.
|
|
71
71
|
|
|
@@ -95,7 +95,7 @@ R-FF-INFLIGHT-01: [finish-feature-flow.md · Step 5 · "In-flight reminder"] Sur
|
|
|
95
95
|
|
|
96
96
|
R-FF-COMMITCELL-01: [finish-feature-minimal-host.md · Step 1 · "Do not collapse the middle case into the first"] it is the one that reads as *filled* to every rule written against empty / non-empty, which is exactly why it survives elsewhere.
|
|
97
97
|
|
|
98
|
-
R-FF-COMMITCELL-02: [finish-feature-minimal-host.md · Step 1 · "Deliberately not run on a phase-bearing host"] a hosted T3's row
|
|
98
|
+
R-FF-COMMITCELL-02: [finish-feature-minimal-host.md · Step 1 · "Deliberately not run on a phase-bearing host"] a hosted T3's row is not asserted against any one commit — only the cells holding its hash are placed, on the host's *next* commit (`references/git-integration.md` § Commit checkpoints) — and nothing requires a hosted row to declare implementation paths — so (c) has no defined input there, and demanding it would reject every hosted T3.
|
|
99
99
|
|
|
100
100
|
R-FF-BASELINECAP-01: [bf · finish-feature-minimal-host.md · Step 1 · "a `spec-baseline` checkpoint and a `Tier = baseline` row imply each other"] `modify-existing-flow.md` Step 1.7 states the contract: a baseline capture is observation-only, *there is no implementation work*, which is why its checkpoint is not named `implementation`. (1) and (2) alone are the ledger talking about itself; (3) is what makes the claim true of the commit.
|
|
101
101
|
|
|
@@ -105,19 +105,35 @@ R-FF-CKPTCOUNT-02: [finish-feature-minimal-host.md · Step 1 · "the Checkpoint
|
|
|
105
105
|
|
|
106
106
|
R-FF-FOLLOWUP-01: [finish-feature-minimal-host.md · Step 1 · "the reverse link was opened, not only closed"] Decidable from one commit and one blob per original, so it stays inside closeout's remit.
|
|
107
107
|
|
|
108
|
+
R-FF-RECONCILE-01: [finish-feature-minimal-host.md · Step 1 · "Minimal host, hotfix post-hoc only", (c) "touches **at least one** of the implementation paths"] The recorded commit is one of the fix's own commits, or the commit it landed as on the base branch (`modify-existing-post-hoc-hotfix.md` item 3), and a fix made of several commits has no single commit carrying all of it: the record names the last of them that touches a declared path. Requiring every declared path would block that legitimate record. The check is a plausibility test — identity is confirmed by `pr-review-checklist.md` — and "at least one" still rejects a commit unrelated to the declaration. The normal minimal host's "checkpoint 1 is *one* commit" check keeps asking for the declared paths without that qualifier, because there the commit *is* the implementation.
|
|
109
|
+
|
|
110
|
+
R-FF-RECORDFIX-01: [finish-feature-minimal-host.md · Step 1 · "Checkpoint 1's own record, corrected after checkpoint 1"] The closeout commit cannot take the correction: its closed list admits only what a flow step writes after checkpoint 1, and this is checkpoint 1's own content. So the correction goes into checkpoint 1 itself (an amend) or, once checkpoint 1 is pushed, into a commit of its own that review reports as a departure from the two-commit lifecycle — there is no declared "maintenance" row that makes a third commit legitimate. Such a row would let any third commit through on a label, the stray host-open commit the whole-history count exists to catch included, and a reviewer would still have to judge it.
|
|
111
|
+
|
|
108
112
|
R-FF-SUMMARY-01: [finish-feature-minimal-host.md · Step 5 · "Zero-phase minimal host — exact fields", on a no-BC host's `Related BR-IDs`] Forcing `none` here would erase a marker the approved zero-phase shape requires.
|
|
109
113
|
|
|
114
|
+
## finish-feature-record-correction.md
|
|
115
|
+
|
|
116
|
+
R-FF-RECORDFIX-02: [finish-feature-record-correction.md · "Not pushed, and checkpoint 1 is `HEAD`"] `git commit --amend` rewrites whatever commit is on top; with a later commit there, the amend would miss checkpoint 1 and leave its old hash an ancestor, so hash evidence (b) would no longer catch an entry nobody refilled. The entries holding checkpoint 1's hash are set back to checkpoint 1's state before staging because a hash on the same line as the correction, or on a neighbouring row — a T3 row's text beside its `Commit` cell, a compound host's next row — leaves `git add -p` a hunk it cannot split.
|
|
117
|
+
|
|
110
118
|
## init-project-flow.md
|
|
111
119
|
|
|
112
120
|
R-INIT-DEFERRED-01: [init-project-flow.md · Step 3.1 · "is NOT generated here", both bullets] Init creates neither a per-context `behavior.md` nor either `analysis.md`: an empty file created ahead of its content becomes a stale placeholder.
|
|
113
121
|
|
|
114
122
|
## modify-existing-flow.md
|
|
115
123
|
|
|
124
|
+
R-ME-CKPT-01: [gf · modify-existing-flow.md · Step 4 → Step 5 gate · "checkpoint 1 is offered at the end of Step 5"] Checkpoint 1 waits for the end of the documentation step so that one commit carries the change and the record that step writes: 5.1's verification finds a gap before anything is committed, not after; the documentation the developer confirmed in 5.2 does not sit uncommitted until closeout, which can be weeks away; and a T2 keeps the two commits its tier promises instead of a third, documentation-only one — which on a minimal host is a commit `pr-review-checklist.md`'s two-commit count flags.
|
|
125
|
+
|
|
126
|
+
R-ME-CKPT-01: [bf · modify-existing-flow.md · Step 5 → Step 6 gate · "checkpoint 1 is offered at the end of Step 6"] Checkpoint 1 waits for the end of the artifact step so that one commit carries the change and the record that step writes: 6.1's verification finds a gap before anything is committed, not after; the documentation the developer confirmed in 6.2 does not sit uncommitted until closeout, which can be weeks away; and a T2 keeps the two commits its tier promises instead of a third, documentation-only one — which on a minimal host is a commit `pr-review-checklist.md`'s two-commit count flags.
|
|
127
|
+
|
|
116
128
|
R-ME-BASELINE-01: [bf · modify-existing-flow.md · Step 2 · "Systematic Baseline Capture"] Baseline capture looks for system-level knowledge and records it in `analysis.md`, even though it runs only when the feature being modified has no prior spec: it is how a project that adopts Dflow midway gets its existing system into `analysis.md` in bulk, rather than one entry at a time. Every other entry point only records what the change in hand happens to touch; the observation-only route in Part A records without changing anything, but only what that observation reached.
|
|
117
129
|
|
|
130
|
+
## new-feature-flow.md
|
|
131
|
+
|
|
132
|
+
R-NF-PHASEDONE-01: [new-feature-flow.md · Step 8 · "8.4 Phase completion and handoff"] § 8.4 reconciles the Current BR Snapshot before handing off because `/dflow:finish-feature` Step 3 syncs the Snapshot into the bounded context as it stands: a Snapshot still holding the rule text planned at Step 4 would overwrite what § 8.3 wrote from the implementation. § 8.4 writes its own four-item list rather than pointing at `new-phase-flow.md` Step 7 because a first phase differs from a later one: its rules are in the phase-spec's Business Rules, not in a Delta; the task list is already handled by § 8.1 and § 8.2, while Step 7 keeps it; and § 8.3 has already synced the bounded context, which Step 7 leaves to closeout.
|
|
133
|
+
|
|
118
134
|
## new-phase-flow.md
|
|
119
135
|
|
|
120
|
-
R-NP-ANALYSIS-01: [new-phase-flow.md · Step 2 · "System-level knowledge?"] Step 2 records into `analysis.md` on the spot rather than leaving it to closeout, because deferring needs two things this flow does not have: somewhere to hold the answer until closeout (the phase-spec template has no section for it), and a closeout step that always runs (a host with no bounded context skips `/dflow:finish-feature` Step 3 entirely). Each track's Step 7 carves these two paths out of its "remain `/dflow:finish-feature` responsibilities" sentence for the same reason. Step 6 re-checks what Step 2 recorded - what the phase was to add or change against what it built, what Step 2 uncovered in the existing system against the system as it now stands, since knowledge Step 2 uncovered was true before the phase began and does not stop being true because the phase built nothing for it - instead of leaving that to closeout as well: no closeout step is sure to reach the entry (
|
|
136
|
+
R-NP-ANALYSIS-01: [new-phase-flow.md · Step 2 · "System-level knowledge?"] Step 2 records into `analysis.md` on the spot rather than leaving it to closeout, because deferring needs two things this flow does not have: somewhere to hold the answer until closeout (the phase-spec template has no section for it), and a closeout step that always runs (a host with no bounded context skips `/dflow:finish-feature` Step 3 entirely). Each track's Step 7 carves these two paths out of its "remain `/dflow:finish-feature` responsibilities" sentence for the same reason. Step 6 re-checks what Step 2 recorded - what the phase was to add or change against what it built, what Step 2 uncovered in the existing system against the system as it now stands, since knowledge Step 2 uncovered was true before the phase began and does not stop being true because the phase built nothing for it - instead of leaving that to closeout as well: no closeout step is sure to reach the entry (a host with no bounded context skips `/dflow:finish-feature` Step 3 entirely), and by then a checkpoint has usually committed it, so no diff would show it.
|
|
121
137
|
|
|
122
138
|
## templates/analysis.md
|
|
123
139
|
|
|
@@ -26,9 +26,10 @@ state, archives the feature directory, and emits a Git-strategy-neutral
|
|
|
26
26
|
stance — the AI helps at natural checkpoints, you keep the final say.
|
|
27
27
|
- The BC-layer sync in Step 3 **reuses the existing documentation-sync
|
|
28
28
|
mechanism** from `new-feature-flow` (§ 8.3) and `modify-existing-flow`
|
|
29
|
-
(Step 5.3) — it does not introduce a new sync flow.
|
|
30
|
-
|
|
31
|
-
closeout, with the `_index.md` Current BR Snapshot as
|
|
29
|
+
(Step 5.3) — it does not introduce a new sync flow. § 8.3 and Step 5.3
|
|
30
|
+
sync when the work they record completes; Step 3 runs the same mechanism
|
|
31
|
+
once more at feature closeout, with the `_index.md` Current BR Snapshot as
|
|
32
|
+
input.
|
|
32
33
|
|
|
33
34
|
**Step Gates** in this flow (stop-and-confirm before proceeding):
|
|
34
35
|
- Step 1 → Step 2 (validation passed → flip status)
|
|
@@ -163,8 +164,9 @@ Step 4's post-commit verification, and to Step 5's Integration Summary fields.
|
|
|
163
164
|
none. Decide from the artifact, not from a declaration:
|
|
164
165
|
"the feature is intentionally no-BR" is a claim, and the record is what
|
|
165
166
|
settles it. A classic BR-delta spec carrying ADDED / MODIFIED / RENAMED
|
|
166
|
-
entries **and** an empty Snapshot means
|
|
167
|
-
(`modify-existing-flow.md` Step
|
|
167
|
+
entries **and** an empty Snapshot means the completion checklist never
|
|
168
|
+
refreshed it (`modify-existing-flow.md` Step 5.3, before checkpoint 1)
|
|
169
|
+
and **blocks**.
|
|
168
170
|
|
|
169
171
|
If any check fails:
|
|
170
172
|
> "Cannot finish feature `{SPEC-ID}-{slug}` yet — {N} validation issues
|
|
@@ -388,10 +390,10 @@ Deltas are the audit trail. **Cross-reference each hosted lightweight-spec's
|
|
|
388
390
|
recorded delta the same way** — on any host shape, for the reason above.
|
|
389
391
|
|
|
390
392
|
> Note: this step does NOT read individual phase-specs to re-derive the BR
|
|
391
|
-
> set
|
|
392
|
-
>
|
|
393
|
-
> feature-level truth here. If the developer finds drift
|
|
394
|
-
> and the phase-specs, fix `_index.md` first, then re-run
|
|
393
|
+
> set. `/dflow:new-feature` § 8.4 and `/dflow:new-phase` Step 7 reconcile the
|
|
394
|
+
> Snapshot when they complete a phase, and we trust `_index.md` Current BR
|
|
395
|
+
> Snapshot as the feature-level truth here. If the developer finds drift
|
|
396
|
+
> between Snapshot and the phase-specs, fix `_index.md` first, then re-run
|
|
395
397
|
> `/dflow:finish-feature`.
|
|
396
398
|
|
|
397
399
|
Also update `architecture/tech-debt.md` / `models.md` / `glossary.md` /
|
|
@@ -494,13 +496,13 @@ Then, in this order:
|
|
|
494
496
|
|
|
495
497
|
1. **Record the checkpoint row first.** Write one row in the moved
|
|
496
498
|
`_index.md` Checkpoint Log — `closeout | committed` for Y, `closeout |
|
|
497
|
-
skipped` for N. The closeout row carries **no commit hash**:
|
|
498
|
-
commit
|
|
499
|
+
skipped` for N. The closeout row carries **no commit hash**: no later
|
|
500
|
+
commit of this host carries it. Trace it later via
|
|
499
501
|
`git log -1 -- dflow/specs/features/completed/{SPEC-ID}-{slug}` (or the
|
|
500
|
-
optional `Dflow-Checkpoint` trailer).
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
Branch Gate & AI Commits).
|
|
502
|
+
optional `Dflow-Checkpoint` trailer). On any other checkpoint row, a
|
|
503
|
+
`committed ({hash})` Result is written after its commit and carried by the
|
|
504
|
+
host's next commit (see `references/git-integration.md` § Commit
|
|
505
|
+
Checkpoints, Branch Gate & AI Commits).
|
|
504
506
|
**Backfill any unfilled hosted `Commit` cell in the same edit** — a hosted row
|
|
505
507
|
waits for the host's *next* commit and this is it. **Unfilled means empty *or*
|
|
506
508
|
holding a placeholder** — `{hash}`, `{pending}`, `(待 commit)`, anything that
|
|
@@ -534,10 +536,11 @@ Then, in this order:
|
|
|
534
536
|
`domain/analysis.md`, `architecture/tech-debt.md`) — Step 3 is **skipped
|
|
535
537
|
entirely for a no-BC host**, so this half is empty there; **and**
|
|
536
538
|
**(b)** the **documentation-sweep step of the flow that produced *this
|
|
537
|
-
change*** — take the paths from that step, not from a list kept here.
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
539
|
+
change*** — take the paths from that step, not from a list kept here. A
|
|
540
|
+
commit may already have carried them — `modify-existing-flow.md`'s
|
|
541
|
+
checkpoint 1 carries its own sweep, and a later phase's checkpoint may have
|
|
542
|
+
carried a `new-feature-flow.md` sweep — and staging an already-committed path
|
|
543
|
+
is a no-op, so stage them either way.
|
|
541
544
|
Those sweeps reach
|
|
542
545
|
Domain-layer documents under `dflow/specs/domain/`, plus the **global**
|
|
543
546
|
documents `glossary.md`, `domain/analysis.md` and
|
|
@@ -575,7 +578,8 @@ Then, in this order:
|
|
|
575
578
|
admitted. On a **phase-bearing** host there is **no allow-list at all** —
|
|
576
579
|
that check is minimal-host-only and lives in that branch file — so read the
|
|
577
580
|
sweep directly and **do not go looking for a list that host never produced.**
|
|
578
|
-
Read each delta (`git diff -- {path}
|
|
581
|
+
Read each delta (`git diff HEAD -- {path}`, which includes what is already
|
|
582
|
+
staged) and scope every one to *this change*;
|
|
579
583
|
staging only "what Step 3 wrote" leaves a no-BC host's global delta dirty and
|
|
580
584
|
the post-commit clean-tree check fails.
|
|
581
585
|
3. **Commit (Y) or stop (N).** For Y the AI commits. If a pre-commit hook
|
|
@@ -625,10 +629,9 @@ every item:
|
|
|
625
629
|
only when the baseline became unreadable *during* closeout.
|
|
626
630
|
Step 1 blocks unless every
|
|
627
631
|
spec in the host already reads `status: completed`, so those flips are
|
|
628
|
-
already **in** the baseline whichever step made them: a
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
host runs Step 1.7, whichever flow opened it. Either way the
|
|
632
|
+
already **in** the baseline whichever step made them: a lightweight-spec's
|
|
633
|
+
comes from `modify-existing-flow.md` Step 5.3, a phase-spec's from its
|
|
634
|
+
phase completing. Either way the
|
|
632
635
|
flips are not differences this check admits; they are part of what it
|
|
633
636
|
compares against. (They are differences only from the *pre-flip* record,
|
|
634
637
|
which is not the baseline.)
|
|
@@ -760,8 +763,8 @@ itself, state in the conversation *how* Step 4's post-commit verification
|
|
|
760
763
|
reached its result — not that it passed, but how it was computed:
|
|
761
764
|
|
|
762
765
|
1. **The baseline** — the tree Step 1 read, and which step put each spec's
|
|
763
|
-
`status: completed` flip into it (Step
|
|
764
|
-
the
|
|
766
|
+
`status: completed` flip into it (`modify-existing-flow.md` Step 5.3 for a
|
|
767
|
+
lightweight-spec; the phase completing for a phase-spec).
|
|
765
768
|
2. **The differences you derived, each with the step that ordered it** —
|
|
766
769
|
Step 2, Step 4's terminal Resume Pointer write, or Step 4 instruction 1. This
|
|
767
770
|
is the set the check *derives* instead of listing, so printing it is what
|
|
@@ -140,14 +140,16 @@ A `✗` here stops closeout there, on the same terms.
|
|
|
140
140
|
`Commit` must still name the **same single documentation commit**.
|
|
141
141
|
- [ ] **Minimal host (zero-phase) only** — **nothing that constitutes the change
|
|
142
142
|
itself is still uncommitted.** This is deliberately not "the host
|
|
143
|
-
directory is clean": **checkpoint 1 carries the change
|
|
144
|
-
commit carries
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
for a **
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
143
|
+
directory is clean": **checkpoint 1 carries the change and the record
|
|
144
|
+
Step 5 writes; the closeout commit carries what the flow writes after
|
|
145
|
+
checkpoint 1.** Checkpoint 1 is offered at the end of
|
|
146
|
+
`modify-existing-flow.md`'s Step 5 (§ 5.5) and holds the change itself —
|
|
147
|
+
for a **T2** its lightweight-spec plus the implementation source, for a
|
|
148
|
+
**T3** its `_index.md` row plus the implementation source — together with
|
|
149
|
+
Step 5's completion checklist. What the flow writes *after* checkpoint 1 —
|
|
150
|
+
Step 1.7's "Finalize + close" — is derived record and rides into the
|
|
151
|
+
closeout commit, and so may a correction to Step 5's record made after
|
|
152
|
+
checkpoint 1.
|
|
151
153
|
**A post-hoc host (Step 1.8) inverts the source half, and this is where
|
|
152
154
|
the reconciliation contract is enforced.** Its change is the *already
|
|
153
155
|
merged* hotfix; checkpoint 1 is the **documentation** commit. So that
|
|
@@ -187,8 +189,9 @@ A `✗` here stops closeout there, on the same terms.
|
|
|
187
189
|
to both phase-spec and lightweight-spec"): ticking the tasks this change
|
|
188
190
|
completed and labelling each unchecked one as follow-up (5.1), and — when
|
|
189
191
|
the developer accepted the offer — collapsing or removing the section
|
|
190
|
-
(5.2).
|
|
191
|
-
|
|
192
|
+
(5.2). That checklist runs before checkpoint 1, so these edits are
|
|
193
|
+
normally committed already; this admits a correction to them made after
|
|
194
|
+
checkpoint 1;
|
|
192
195
|
(iii) the Domain-layer documents **this change's Step 5.3 sweep** updates
|
|
193
196
|
— under `dflow/specs/domain/`, plus
|
|
194
197
|
`dflow/specs/architecture/tech-debt.md` — scoped to *this change's*
|
|
@@ -200,11 +203,23 @@ A `✗` here stops closeout there, on the same terms.
|
|
|
200
203
|
documents (`glossary.md`, `domain/analysis.md`,
|
|
201
204
|
`architecture/tech-debt.md`) belong to no bounded context, stay in its
|
|
202
205
|
sweep, and therefore still qualify under (iii).
|
|
203
|
-
Read each delta
|
|
204
|
-
|
|
206
|
+
Read each delta with `git diff HEAD -- {path}` — plain `git diff` hides
|
|
207
|
+
what is already staged — and do not infer it from the filename.
|
|
208
|
+
**The list is closed** — if a later change adds another
|
|
205
209
|
finalization field, add it here explicitly; "a host file is dirty" is never
|
|
206
210
|
on its own a reason to pass. (Unrelated work in progress elsewhere is
|
|
207
211
|
fine; say which files you judged unrelated.)
|
|
212
|
+
**Checkpoint 1's own record, corrected after checkpoint 1, is outside the
|
|
213
|
+
list** — the spec's content beyond (ii)'s edits, a row's own text, or the
|
|
214
|
+
reverse-link row a follow-up wrote into its original's `_index.md`. It
|
|
215
|
+
blocks: the closeout commit does not carry checkpoint 1's content. The
|
|
216
|
+
dispatch right after this item gives the repair.
|
|
217
|
+
|
|
218
|
+
**Open `references/finish-feature-record-correction.md` and follow it there.**
|
|
219
|
+
Do this only when the check above blocked on a correction to checkpoint 1's own
|
|
220
|
+
record: the repair depends on where checkpoint 1 stands now, and that file gives
|
|
221
|
+
it for each case. Otherwise go on to the next check.
|
|
222
|
+
|
|
208
223
|
- [ ] **Minimal host (zero-phase), no-BC only** — **the host did not commit a
|
|
209
224
|
bounded context it does not have.** This file's `nothing that constitutes
|
|
210
225
|
the change itself is still uncommitted` check reads the *working
|
|
@@ -273,10 +288,11 @@ A `✗` here stops closeout there, on the same terms.
|
|
|
273
288
|
assertion.
|
|
274
289
|
The plausibility conditions, all required: the
|
|
275
290
|
`reconciled ({merged-hotfix-hash})` value passes hash evidence — (a) and
|
|
276
|
-
(b) as usual, and for **(c)** its diff touches
|
|
277
|
-
the T2 lightweight-spec or the T3 row **declares**
|
|
278
|
-
declaration; an artifact naming none leaves (c)
|
|
279
|
-
**blocks** rather than passing vacuously). It
|
|
291
|
+
(b) as usual, and for **(c)** its diff touches **at least one** of the
|
|
292
|
+
implementation paths the T2 lightweight-spec or the T3 row **declares**
|
|
293
|
+
(Step 1.7 requires that declaration; an artifact naming none leaves (c)
|
|
294
|
+
nothing to compare and **blocks** rather than passing vacuously). It
|
|
295
|
+
must also **differ**
|
|
280
296
|
from the Lightweight Changes row's documentation-commit hash (different
|
|
281
297
|
provenance; see Step 1.8). The per-tier trace must exist too: a **T2**
|
|
282
298
|
carries `hotfix-branch:` in its lightweight-spec frontmatter, a **T3** has
|
|
@@ -288,6 +304,10 @@ A `✗` here stops closeout there, on the same terms.
|
|
|
288
304
|
for a **T3**. An uncited hash **blocks** closeout: it leaves pr-review
|
|
289
305
|
nothing to confirm against, and this gate is not a substitute for that
|
|
290
306
|
confirmation.
|
|
307
|
+
**When (b) fails for the `reconciled (...)` hash, do not report only
|
|
308
|
+
"not an ancestor".** Open `references/modify-existing-post-hoc-hotfix.md`
|
|
309
|
+
item 6: it names the causes and the repair for each; report the one that
|
|
310
|
+
is true.
|
|
291
311
|
|
|
292
312
|
> **Zero-phase minimal host (`modify-existing-flow.md` Step 1.7 / the Step 1.6
|
|
293
313
|
> minimal variant / Step 1.8's post-hoc hotfix, whose linkage resolves to one of
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Correcting Checkpoint 1's Own Record — Greenfield Clean Architecture
|
|
2
|
+
|
|
3
|
+
Branch file of `references/finish-feature-minimal-host.md`. It **adds** the
|
|
4
|
+
repair for one case that file's working-tree check blocks; it does not restate
|
|
5
|
+
or override anything in that file.
|
|
6
|
+
|
|
7
|
+
**You are here because** that file's `nothing that constitutes the change
|
|
8
|
+
itself is still uncommitted` check blocked on a correction to checkpoint 1's
|
|
9
|
+
own record — it owns that judgement — or because
|
|
10
|
+
`references/modify-existing-post-hoc-hotfix.md` item 6 found that a post-hoc
|
|
11
|
+
record names a different fix.
|
|
12
|
+
|
|
13
|
+
The correction belongs in checkpoint 1 itself, and whether it can go there
|
|
14
|
+
depends on where checkpoint 1 stands now. Report the case that is true and give
|
|
15
|
+
the developer its repair:
|
|
16
|
+
|
|
17
|
+
- **Not pushed, and checkpoint 1 is `HEAD`** (`git rev-parse HEAD` prints
|
|
18
|
+
checkpoint 1's hash) — first set every entry that holds checkpoint 1's hash
|
|
19
|
+
back to what checkpoint 1 has (`git show HEAD:{path}`); the refill below
|
|
20
|
+
writes them again. Then stage the correction alone (in `_index.md`, `git add
|
|
21
|
+
-p` only its hunk: the Resume Pointer rides the closeout commit), check that
|
|
22
|
+
`git diff --cached` shows nothing else, and `git commit --amend`. Then write
|
|
23
|
+
the new hash into every entry that names checkpoint 1 — the Checkpoint Log
|
|
24
|
+
`committed (...)` and each row's `Commit` cell. An entry left on the old hash
|
|
25
|
+
fails hash evidence (b).
|
|
26
|
+
- **Not pushed, but a later commit sits on top of checkpoint 1** — stop:
|
|
27
|
+
rewriting an earlier commit is the developer's to do.
|
|
28
|
+
- **Already pushed** — stop and leave it to the developer. Rewriting a pushed
|
|
29
|
+
commit is the team's call (refill the entries as above if they do). The other
|
|
30
|
+
way is to commit the correction on its own: add no Checkpoint Log row for it
|
|
31
|
+
(a second row blocks), and ask for it to be named in the PR description — it
|
|
32
|
+
departs from the two-commit lifecycle, and
|
|
33
|
+
`references/pr-review-checklist.md`'s whole-history item sees it only when it
|
|
34
|
+
touches this host's directory.
|
|
35
|
+
|
|
36
|
+
**A post-hoc host's `reconciled (...)`** names the hotfix, not checkpoint 1, so
|
|
37
|
+
refilling after an amend leaves it as it is — **unless the correction changes
|
|
38
|
+
which fix the record names** (`references/modify-existing-post-hoc-hotfix.md`
|
|
39
|
+
item 6, "The record names a different fix"). Then `reconciled (...)` names the
|
|
40
|
+
wrong fix too. Item 3 wrote it before checkpoint 1, so checkpoint 1 carries it:
|
|
41
|
+
correct it to the right fix's commit — the one item 3 says to record — as part
|
|
42
|
+
of the same correction, whichever way that lands (the amend, the developer's
|
|
43
|
+
rewrite, or the correction's own commit). Put that commit through item 6's test
|
|
44
|
+
before closeout continues; that item gives the repair if (b) fails for it as
|
|
45
|
+
well.
|