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
|
@@ -177,7 +177,8 @@ project's decision (GitFlow → `develop`, Trunk / GitHub Flow → `main`).
|
|
|
177
177
|
### Commit checkpoints
|
|
178
178
|
|
|
179
179
|
At lifecycle milestones the AI offers a commit checkpoint, folded into the
|
|
180
|
-
|
|
180
|
+
prompt the flow already shows there — a Step Gate, or the flow's closing
|
|
181
|
+
announcement (it does not add a separate question):
|
|
181
182
|
|
|
182
183
|
```
|
|
183
184
|
✓ {milestone} complete
|
|
@@ -188,25 +189,36 @@ existing Step Gate prompt (it does not add a separate question):
|
|
|
188
189
|
|
|
189
190
|
Tier sets how many checkpoints a change has: T1 three (spec / implementation /
|
|
190
191
|
closeout), T2 two (spec+implementation merged / closeout), T3 a single commit.
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
192
|
+
**What a checkpoint carries follows from where its flow offers it.**
|
|
193
|
+
`references/modify-existing-flow.md` offers its checkpoint at the end of its
|
|
194
|
+
artifact step (Step 5), so a T2's merged commit — and a T3's single commit —
|
|
195
|
+
carries the change together with the documentation that step writes.
|
|
196
|
+
`/dflow:new-feature` and `/dflow:new-phase` offer the implementation checkpoint
|
|
197
|
+
at the gate into their completion step, so what that step writes rides the
|
|
198
|
+
host's next commit, whichever that is — for example the next phase's first
|
|
199
|
+
checkpoint, a hosted lightweight change's commit, or closeout.
|
|
200
|
+
"T3 = a single commit" means a single **implementation** commit. On a hosted T3
|
|
201
|
+
the entries that carry its hash ride the host's **next** commit (more work, or
|
|
202
|
+
closeout), as every checkpoint's do (below). If the host has no next commit
|
|
203
|
+
scheduled, one ledger-only tracking commit that references the T3 hash is
|
|
204
|
+
allowed. It is bookkeeping, not a lifecycle milestone: it adds no Checkpoint Log
|
|
205
|
+
row of its own (unlike closeout, which is a checkpoint and does get a row).
|
|
198
206
|
**Minimal host (zero-phase) exception — there, tier does not set the count.**
|
|
199
207
|
On a minimal host (`references/modify-existing-flow.md` Step 1.7 standalone, or
|
|
200
208
|
its Step 1.6 follow-up minimal variant) there is no later host commit for a row
|
|
201
209
|
to ride, so the count is **two for every tier** — implementation, then closeout
|
|
202
|
-
— and a T3's
|
|
203
|
-
|
|
204
|
-
describes a **hosted** T3, the case where a
|
|
210
|
+
— and every row, a T3's included, is written into checkpoint 1 itself; only the
|
|
211
|
+
entries that carry checkpoint 1's hash ride the closeout commit. Everything
|
|
212
|
+
above about "T3 = a single commit" describes a **hosted** T3, the case where a
|
|
213
|
+
later host commit exists.
|
|
205
214
|
Whether you choose Y or N, the AI records one row in the feature `_index.md`
|
|
206
215
|
Checkpoint Log — every checkpoint is accounted for (`committed` / `skipped` /
|
|
207
|
-
`failed`), even when no commit happens.
|
|
208
|
-
commit
|
|
209
|
-
|
|
216
|
+
`failed`), even when no commit happens.
|
|
217
|
+
**No checkpoint commit can contain its own hash.** The entries that carry a
|
|
218
|
+
checkpoint's hash — its Checkpoint Log Result `committed ({hash})`, and any
|
|
219
|
+
Lightweight Changes `Commit` cell holding that hash — are written after the
|
|
220
|
+
commit succeeds and ride the host's **next** commit. A hook rejection or failed
|
|
221
|
+
commit is recorded as `failed` (never a fake hash).
|
|
210
222
|
**One further Result value — `reconciled ({merged-hotfix-hash})`.** It records
|
|
211
223
|
that this checkpoint documents a change that was **already merged** before any
|
|
212
224
|
ceremony ran, and it is written only on a post-hoc hotfix host's implementation
|
|
@@ -215,8 +227,8 @@ belongs to the **merged hotfix**, not to this host's own documentation commit
|
|
|
215
227
|
that one goes in the Lightweight Changes row's `Commit` cell, and the two have
|
|
216
228
|
different provenance and must never be swapped. On every other host the three
|
|
217
229
|
values above are the whole vocabulary.
|
|
218
|
-
**Exception — the closeout row**:
|
|
219
|
-
|
|
230
|
+
**Exception — the closeout row**: no later commit of this host's lifecycle
|
|
231
|
+
carries it, so the closeout row is written before the commit
|
|
220
232
|
as `closeout | committed` with **no hash** (see
|
|
221
233
|
`references/finish-feature-flow.md` Step 4); trace that commit via
|
|
222
234
|
`git log -1 -- dflow/specs/features/completed/{SPEC-ID}-{slug}` or the optional
|
|
@@ -339,12 +351,25 @@ heavily enough that git's similarity index dropped below the rename
|
|
|
339
351
|
threshold; consider using `git mv` for the move, then making content
|
|
340
352
|
edits in a follow-up commit).
|
|
341
353
|
|
|
342
|
-
### CI / hook automation
|
|
354
|
+
### CI / hook automation
|
|
343
355
|
|
|
344
|
-
|
|
345
|
-
`dflow/specs/features/completed/`
|
|
346
|
-
|
|
347
|
-
|
|
356
|
+
Dflow ships `dflow check-closeout`, a gate for the closeout commit. For each
|
|
357
|
+
feature directory newly archived to `dflow/specs/features/completed/` it checks
|
|
358
|
+
that `_index.md` and every spec say `status: completed`, that nothing is left
|
|
359
|
+
under `active/`, that the Checkpoint Log has a real `closeout` row reading
|
|
360
|
+
`committed` or `skipped`, and — with `--staged` — that nothing under the
|
|
361
|
+
archived directory is left unstaged; it exits 1 when one fails. A project wires
|
|
362
|
+
it into a pre-commit hook (`--staged`) or a CI job (`--range <base>..<head>`)
|
|
363
|
+
itself — Dflow installs neither. `dflow check-closeout --help` names the page
|
|
364
|
+
with the hook and CI templates. When the hook refuses a closeout commit, handle
|
|
365
|
+
it as `references/finish-feature-flow.md` Step 4 instruction 3 says.
|
|
366
|
+
|
|
367
|
+
Passing it is not a clean closeout: the post-commit verification in
|
|
368
|
+
`references/finish-feature-flow.md` Step 4 still applies in full.
|
|
369
|
+
|
|
370
|
+
A hook that refuses paired `D` + `A` instead of `R` for the same feature
|
|
371
|
+
directory is compatible with the `git mv` rule, but it is not part of
|
|
372
|
+
`check-closeout`.
|
|
348
373
|
|
|
349
374
|
## Gate Checks by Branch Type
|
|
350
375
|
|
|
@@ -384,8 +409,12 @@ hotfix, or one added later):
|
|
|
384
409
|
- [ ] `_index.md` Current BR Snapshot has been synced to BC layer
|
|
385
410
|
(`rules.md` / `behavior.md` / `events.md` / `context-map.md`) —
|
|
386
411
|
typically by `/dflow:finish-feature`
|
|
387
|
-
- [ ]
|
|
388
|
-
|
|
412
|
+
- [ ] **Closeout complete**: `/dflow:finish-feature` has announced closeout
|
|
413
|
+
complete for this host — its Local-closeout gate is satisfied (the
|
|
414
|
+
closeout commit landed and passed post-commit verification) and, if
|
|
415
|
+
the host carries `follow-up-of`, the Step 6 tracking commit has also
|
|
416
|
+
landed and been verified. `status: completed` or a directory already
|
|
417
|
+
under `completed/` does not show this on its own.
|
|
389
418
|
- [ ] Domain layer: zero external dependencies
|
|
390
419
|
- [ ] No business logic outside Domain layer
|
|
391
420
|
- [ ] Domain Events documented in events.md
|
|
@@ -394,8 +423,8 @@ hotfix, or one added later):
|
|
|
394
423
|
- [ ] No ORM/serialization attributes on Domain entities
|
|
395
424
|
|
|
396
425
|
> **On a minimal (zero-phase) host**, split this list by what each item reads.
|
|
397
|
-
> Items about **this host's own record** — `_index.md` status,
|
|
398
|
-
>
|
|
426
|
+
> Items about **this host's own record** — `_index.md` status, **Closeout
|
|
427
|
+
> complete**, and the phase-spec check, which passes vacuously on an empty
|
|
399
428
|
> table — apply **unchanged**: they are what stops a host merging with its
|
|
400
429
|
> record still open. Every item that names a **Domain or bounded-context
|
|
401
430
|
> artifact**, the BR-Snapshot sync included, applies only to what this change
|
|
@@ -440,10 +469,15 @@ hotfix, or one added later):
|
|
|
440
469
|
- [ ] Fix approach is noted (which layer the fix belongs in)
|
|
441
470
|
|
|
442
471
|
### bugfix/ — Before Merging (Pre-PR / Pre-Integration)
|
|
443
|
-
- [ ] `_index.md` status: `completed
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
472
|
+
- [ ] `_index.md` status: `completed`
|
|
473
|
+
- [ ] **Closeout complete**: `/dflow:finish-feature` has announced closeout
|
|
474
|
+
complete for this host — its Local-closeout gate is satisfied (the
|
|
475
|
+
closeout commit landed and passed post-commit verification) and, if
|
|
476
|
+
the host carries `follow-up-of`, the Step 6 tracking commit has also
|
|
477
|
+
landed and been verified. `status: completed` or a directory already
|
|
478
|
+
under `completed/` does not show this on its own.
|
|
479
|
+
A `bugfix/` host closes out exactly like a `feature/` one; an
|
|
480
|
+
un-closed-out host must not merge.
|
|
447
481
|
- [ ] **The tier's artifact** has the fix documented — a **T2**'s lightweight
|
|
448
482
|
spec, or for a **T3** the host `_index.md` Lightweight Changes row, which
|
|
449
483
|
is its whole record. Do not ask a T3 for a spec file here either: the
|
|
@@ -286,6 +286,10 @@ drop the T3 evidence.
|
|
|
286
286
|
recorded, or a stale branch is still carrying it — and it is settled that
|
|
287
287
|
way with the developer, as duplicate / existing work or branch-history
|
|
288
288
|
cleanup. All identifiers are settled here, before the host exists.
|
|
289
|
+
|
|
290
|
+
For a **post-hoc hotfix** (Step 1.8), also run the branch-base check in
|
|
291
|
+
`references/modify-existing-post-hoc-hotfix.md` item 2 here, before step 3
|
|
292
|
+
creates anything: step 4 cuts from the base branch it settles.
|
|
289
293
|
3. **Create the minimal `_index.md`** from `templates/_index.md` at
|
|
290
294
|
`dflow/specs/features/active/{SPEC-ID}-{slug}/_index.md`, carrying all
|
|
291
295
|
**seven required sections** that template names — the Metadata front
|
|
@@ -329,9 +333,10 @@ skips the Domain / DDD-impact work and records an inline row in
|
|
|
329
333
|
`_index.md` Lightweight Changes — **one row per atomic T3 change**, so a
|
|
330
334
|
compound request records each of them here (see "minimal means zero-phase,
|
|
331
335
|
not one-artifact" above). The **implementation commit is checkpoint
|
|
332
|
-
1** — the
|
|
333
|
-
Log. (For a **post-hoc** host, Step 4 is
|
|
334
|
-
**documentation** commit instead; see Step 1.8
|
|
336
|
+
1** — offered at the end of Step 5 (§ 5.5), after Step 5 has written its
|
|
337
|
+
record, and recorded in the Checkpoint Log. (For a **post-hoc** host, Step 4 is
|
|
338
|
+
skipped and checkpoint 1 is the **documentation** commit instead; see Step 1.8
|
|
339
|
+
and Step 4's guard.)
|
|
335
340
|
|
|
336
341
|
**Every artifact gets a Lightweight Changes row, and every row is written
|
|
337
342
|
*before* checkpoint 1.** A **T3**'s row *is* its whole record; a **T2**'s row is
|
|
@@ -341,8 +346,8 @@ implementation paths. The **only** part that may appear afterwards is the
|
|
|
341
346
|
`Commit` cell, which cannot exist until its commit does: closeout's allow-list
|
|
342
347
|
admits that cell and no other change **to the row**, so a row added after
|
|
343
348
|
checkpoint 1 **blocks**. (The allow-list separately admits the Checkpoint Log
|
|
344
|
-
rows, the Resume Pointer and the Current BR Snapshot
|
|
345
|
-
|
|
349
|
+
rows, the Resume Pointer and the Current BR Snapshot; the first two are what
|
|
350
|
+
"Finalize + close" writes after checkpoint 1.)
|
|
346
351
|
|
|
347
352
|
**Name the implementation paths in the artifact.** Closeout's evidence checks
|
|
348
353
|
assert that a commit *touches the implementation paths this change describes* —
|
|
@@ -353,14 +358,17 @@ diff — enough to compare a commit against. An artifact that declares none
|
|
|
353
358
|
leaves that check nothing to compare, and finish-feature treats a missing
|
|
354
359
|
declaration as a **block**, not a pass.
|
|
355
360
|
|
|
356
|
-
**
|
|
357
|
-
|
|
358
|
-
lightweight-spec `status: completed
|
|
359
|
-
|
|
360
|
-
BC
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
361
|
+
**Before checkpoint 1 — Step 5 finalizes the record.** Step 5's completion
|
|
362
|
+
checklist runs before checkpoint 1, so everything it writes rides that commit.
|
|
363
|
+
For **every** T2, 5.3 sets the lightweight-spec `status: completed`. **Only when
|
|
364
|
+
that T2 is BC-bearing**, 5.3 also refreshes the host's Current BR Snapshot — a
|
|
365
|
+
no-BC T2 has no snapshot to refresh. A **T3** has no spec file and no snapshot
|
|
366
|
+
to refresh; Step 5 only re-verifies its row.
|
|
367
|
+
|
|
368
|
+
**Finalize + close — after checkpoint 1.** Before `/dflow:finish-feature`,
|
|
369
|
+
write what cannot exist until checkpoint 1 does, for every tier: each row's
|
|
370
|
+
commit evidence (the two surfaces below) and the Resume Pointer advanced to the
|
|
371
|
+
closeout-ready state.
|
|
364
372
|
|
|
365
373
|
**Commit evidence goes to two surfaces, always — every row, every tier.** They
|
|
366
374
|
answer different questions, so filling one is never filling the other, and
|
|
@@ -377,16 +385,18 @@ The **mode** changes only *which hash* each surface carries:
|
|
|
377
385
|
|
|
378
386
|
- **Normal** (T2 or T3) — Checkpoint Log Result `committed ({hash})` and the
|
|
379
387
|
row's `Commit` cell both name **checkpoint 1**, the single commit that
|
|
380
|
-
carried the artifact
|
|
381
|
-
fill both.
|
|
388
|
+
carried the artifact, the implementation and Step 5's record together. Two
|
|
389
|
+
cells, one hash; fill both.
|
|
382
390
|
- **Post-hoc hotfix** (Step 1.8; T2 or T3) — the Checkpoint Log Result stays
|
|
383
|
-
`reconciled ({merged-hotfix-hash})`, **never overwrite it
|
|
384
|
-
|
|
385
|
-
|
|
391
|
+
`reconciled ({merged-hotfix-hash})`, **never overwrite it** — only closeout
|
|
392
|
+
corrects it, through `references/modify-existing-post-hoc-hotfix.md` item 6 —
|
|
393
|
+
while the row's `Commit` cell carries the **documentation** commit's hash.
|
|
394
|
+
This is the one mode where the two values genuinely differ (Step 1.8 item 4).
|
|
386
395
|
|
|
387
396
|
**A declined checkpoint still owes its hash.** If the developer answered **N**
|
|
388
|
-
at the checkpoint-1 offer and made that commit themselves
|
|
389
|
-
|
|
397
|
+
at the checkpoint-1 offer and made that commit themselves — the change together
|
|
398
|
+
with Step 5's record — the Checkpoint Log row was written `skipped` honestly —
|
|
399
|
+
the AI did not commit — but it is now
|
|
390
400
|
**incomplete, not final**: complete it here to `committed ({hash})` with the
|
|
391
401
|
developer's actual hash. **That completion is for a normal checkpoint 1.** On a
|
|
392
402
|
**post-hoc** host the Result stays
|
|
@@ -396,7 +406,8 @@ developer's commit lands, never by overwriting the reconciliation hash, which
|
|
|
396
406
|
records a different commit entirely. A row left reading `skipped` blocks closeout, and
|
|
397
407
|
finish-feature cannot tell "declined then committed" from "never committed" on
|
|
398
408
|
your behalf. The **closeout** row is the deliberate exception — it carries no
|
|
399
|
-
hash at all, because
|
|
409
|
+
hash at all, because no later commit of this host carries it
|
|
410
|
+
(`references/git-integration.md` § Commit checkpoints). Its **Result is still
|
|
400
411
|
read** afterwards — finish-feature's post-commit gate rejects `failed` there. A
|
|
401
412
|
declined closeout stays `skipped` because that value records the declined offer
|
|
402
413
|
honestly, not because the row goes unread.
|
|
@@ -569,9 +580,10 @@ Wait for confirmation before entering Step 4.
|
|
|
569
580
|
> **Post-hoc hotfix (Step 1.8) — skip this step.** The implementation already
|
|
570
581
|
> landed on the mainline before any ceremony ran; that is the whole premise of
|
|
571
582
|
> post-hoc mode, and Step 1.8 item 2 forbids redoing it. There is nothing to
|
|
572
|
-
> implement here. Go straight to the Step 4 → Step 5 gate and
|
|
573
|
-
> **documentation only** — the T2 spec or T3
|
|
574
|
-
>
|
|
583
|
+
> implement here. Go straight to the Step 4 → Step 5 gate and on through Step 5;
|
|
584
|
+
> checkpoint 1 (§ 5.5) then commits **documentation only** — the T2 spec or T3
|
|
585
|
+
> row, this host's `_index.md` and what Step 5 wrote, and no source.
|
|
586
|
+
> Re-implementing the fix on this branch would satisfy the letter
|
|
575
587
|
> of the checkpoint while breaking §8's reconciliation contract, which is why
|
|
576
588
|
> closeout inspects that commit's changed paths.
|
|
577
589
|
|
|
@@ -589,9 +601,7 @@ Even for bug fixes, verify:
|
|
|
589
601
|
Announce to developer:
|
|
590
602
|
> "Implementation appears complete. Ready to update documentation (spec, models.md, rules.md, events.md, glossary, tech-debt)? `/dflow:next` to proceed."
|
|
591
603
|
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
Wait for confirmation before entering Step 5. This step gate is where the completion checklist is triggered — do not skip.
|
|
604
|
+
Wait for confirmation before entering Step 5. This step gate is where the completion checklist is triggered — do not skip. It offers **no** commit: checkpoint 1 is offered at the end of Step 5 (§ 5.5).
|
|
595
605
|
|
|
596
606
|
## Step 5: Update Documentation
|
|
597
607
|
|
|
@@ -632,6 +642,7 @@ Ask these one-by-one.
|
|
|
632
642
|
> **Table-cell formatting**: keep table cells concise — separate multiple short items with `<br>` (never chain them into one line with ;/; separators), and move long narrative detail out of the cell into a document section (full convention: the formatting comment at each spec doc's head).
|
|
633
643
|
|
|
634
644
|
- [ ] Update or create the feature / bug spec; set `status: completed` — **T3: N/A** (no spec file exists; the `_index.md` inline row is the record, and the host's own status is not touched)
|
|
645
|
+
- [ ] **BC-bearing T2, on every host** — refresh the host `_index.md` Current BR Snapshot from this spec's final delta (`templates/_index.md` regenerates it when a T2 lightweight-spec is finalized; on a minimal host this is the refresh Step 1.7 places before checkpoint 1). A spec with no BR delta leaves the Snapshot as it is. N/A for a no-BC T2 and a T3
|
|
635
646
|
- [ ] The items below are the Domain sweep — **N/A for a T3**. For a **no-BC change** (one whose host Goals & Scope says it touches no bounded context) the **BC-scoped** items are N/A — everything under `dflow/specs/domain/{context}/` plus `context-map.md`: there is no `{context}` to sweep, and inventing one plants the fiction Step 2's no-BC guard refuses. The **global** documents are *not* covered by that: `glossary.md`, `domain/analysis.md` and `architecture/tech-debt.md` belong to no bounded context, and a no-BC operational T2 can genuinely rename a term, change which roles reach a function, or discover architecture debt — judge those three from the actual change, as always. For a no-BR family T2 only the *BR-derived* items are N/A; run each remaining item where this change actually touches that document (an added event field still lands in `events.md`)
|
|
636
647
|
- [ ] `dflow/specs/domain/{context}/models.md` — Aggregate structure updates
|
|
637
648
|
- [ ] `dflow/specs/domain/{context}/analysis.md` — lifecycles, derived figures or mechanisms no single rule explains this change found or altered, in the owning context's copy, which may not be this host's; any spot this change worked around pending a domain decision, in those or in a rule or unrecorded knowledge that belongs there; and any open row there this change settled (created from `templates/analysis.md` the first time there is something to record; N/A when there is none)
|
|
@@ -678,3 +689,7 @@ directory — the closeout `git mv` happens at `/dflow:finish-feature` time
|
|
|
678
689
|
|
|
679
690
|
Only announce "change complete" after the appropriate archival step
|
|
680
691
|
above (or the Step 5.3 docs sweep) is done.
|
|
692
|
+
|
|
693
|
+
### 5.5 Commit checkpoint (checkpoint 1)
|
|
694
|
+
|
|
695
|
+
> Commit checkpoint (per `references/git-integration.md` § Commit Checkpoints, Branch Gate & AI Commits): fold the offer into the "change complete" announcement, then record the result in the `_index.md` Checkpoint Log. This commit is **checkpoint 1**: it carries the change — the spec or row plus the implementation — **and** everything Steps 2–5 wrote. Tier sets the count — T2 commits the merged spec+implementation here (closeout is the second checkpoint); T3 is a single implementation commit. The entries that carry this commit's hash — the Checkpoint Log Result and each Lightweight Changes `Commit` cell naming it — are written after the commit and ride the host's next commit; on a phase-bearing host, `/dflow:finish-feature` Step 4 backfills any `Commit` cell still unfilled at closeout. **Minimal host exception (Step 1.7 standalone *and* the Step 1.6 follow-up variant)**: a minimal host takes no host commit between checkpoint 1 and closeout, so **every row rides checkpoint 1 itself** — a T3 row included, written into `_index.md` *before* this commit, because finish-feature Step 1 reads **checkpoint 1's committed `_index.md`** for it. Only the entries that carry the hash come later: Step 1.7's "Finalize + close" writes them, and they ride the closeout commit. And a minimal host takes a second **closeout** checkpoint too: **every** minimal host records **two** checkpoints (implementation, then closeout), for T3 as well as T2. **Post-hoc hotfix (Step 1.8) — the same two checkpoints, but the first carries no implementation**: the fix is already on the mainline, so checkpoint 1 is the **documentation** commit (spec / row, `_index.md` and what Step 5 wrote, no source), and its Checkpoint Log Result is `reconciled ({merged-hotfix-hash})` rather than `committed`. "Commits the merged spec+implementation" above describes a normal host and does **not** apply here.
|
|
@@ -87,7 +87,8 @@ hardcoded `feature/` branch). Step 1.7's **step 1 does not apply**: it is the
|
|
|
87
87
|
standalone-classification gate, and this caller has already been classified as
|
|
88
88
|
a follow-up. Everything Step 1.7 states **after** step 4 *does* apply
|
|
89
89
|
unchanged — every artifact's row written before checkpoint 1, the
|
|
90
|
-
implementation-path declaration,
|
|
90
|
+
implementation-path declaration, the finalization before checkpoint 1 and
|
|
91
|
+
"Finalize + close" after it, and the two
|
|
91
92
|
commit-evidence surfaces — because finish-feature reads for all of it on a
|
|
92
93
|
follow-up host exactly as on a standalone one. Then record the change's
|
|
93
94
|
artifacts — a T2 lightweight-spec, one
|
|
@@ -32,6 +32,10 @@ If you arrived here with a T1, go back to Part A's routing.
|
|
|
32
32
|
includes *a related feature that is still in flight* — see above for why
|
|
33
33
|
it cannot be the host.
|
|
34
34
|
|
|
35
|
+
Make the choice here, and **act on it only after item 2's branch-base
|
|
36
|
+
check**: on either route, nothing is opened, linked or cut before that
|
|
37
|
+
check.
|
|
38
|
+
|
|
35
39
|
Do not skip this choice. If a feature that was in flight turns out to have
|
|
36
40
|
touched the same code, that is a **merge** question, settled when the
|
|
37
41
|
branches actually meet — see `finish-feature-flow.md` Step 5.
|
|
@@ -42,11 +46,69 @@ If you arrived here with a T1, go back to Part A's routing.
|
|
|
42
46
|
1.6's delegation to it) like any other minimal host — that branch *is* the
|
|
43
47
|
**post-hoc branch** the rest of this step names, and the value `_index.md`
|
|
44
48
|
`branch:` records.
|
|
49
|
+
|
|
50
|
+
**Branch-base check — run it before Step 1.7 step 3 creates anything**
|
|
51
|
+
(on the follow-up route: before Step 1.6 opens the host and writes the
|
|
52
|
+
reverse link). It settles which base branch this host's branch is cut
|
|
53
|
+
from. Closeout requires the commit item 3 records to be an ancestor of
|
|
54
|
+
this branch, so a branch cut from a base that does not contain that commit
|
|
55
|
+
yet passes every step until closeout and is blocked there. Settle that
|
|
56
|
+
commit with the developer first (item 3), then:
|
|
57
|
+
1. Settle the base branch and fetch it. The developer decides which
|
|
58
|
+
branch is the base — Dflow does not know it, though the project may
|
|
59
|
+
record it under `_conventions.md` § Git Policy — and it is the branch
|
|
60
|
+
Step 1.7 step 4 cuts from anyway. `{base-ref}` is that branch's latest
|
|
61
|
+
ref (for example `origin/develop`). Fetch the remote it belongs to
|
|
62
|
+
(`git fetch origin` for `origin/develop`; `git fetch --all` when
|
|
63
|
+
unsure): a bare `git fetch` updates only the default remote, so a base
|
|
64
|
+
on another remote stays stale and the steps below misjudge it. The fix
|
|
65
|
+
is merged and pushed by now, and it often reached the base on the
|
|
66
|
+
server — a PR merge or a squash — that this clone has not fetched yet.
|
|
67
|
+
2. Run `git cat-file -t {hash}`. It must print `commit`. If it prints
|
|
68
|
+
anything else or fails, and step 1's fetch failed, the commit may only
|
|
69
|
+
be missing from this clone: stop, say the check needs the fetch, and
|
|
70
|
+
run it again once the remote is reachable. Otherwise the hash is
|
|
71
|
+
mistyped, names an object that is not a commit, or names a commit that
|
|
72
|
+
remote does not have — stop and ask the developer. Do not guess.
|
|
73
|
+
3. Run `git show --stat {hash}`. At least one path it lists must be an
|
|
74
|
+
implementation path this record will declare. If none is, stop and
|
|
75
|
+
settle the commit with the developer — closeout's (c) would block it.
|
|
76
|
+
A last commit that touches only tests does this. Then run
|
|
77
|
+
`git rev-list --parents -n 1 {hash}`: more than two hashes means a
|
|
78
|
+
merge commit — for example the one a PR page shows as its merged
|
|
79
|
+
commit. Item 3 never records one, and a merge usually passes the path
|
|
80
|
+
check above, so stop here and settle the commit with the developer.
|
|
81
|
+
4. Run `git merge-base --is-ancestor {hash} {base-ref}`:
|
|
82
|
+
- **Exit `0`** — cut this host's branch from `{base-ref}` at Step 1.7
|
|
83
|
+
step 4. Do **not** let the new branch track the base: run
|
|
84
|
+
`git checkout -b {branch} --no-track {base-ref}`, or update the local
|
|
85
|
+
base branch the way the project normally does and cut from that. A
|
|
86
|
+
branch that tracks `origin/develop` can, under some push settings,
|
|
87
|
+
push its documentation commits straight to `develop`.
|
|
88
|
+
- **Exit `1`** — the fix is not in that base yet. Tell the developer
|
|
89
|
+
both causes. **The fix has not been merged back yet**: merge it back
|
|
90
|
+
first (under GitFlow, into `develop`). **The recorded commit is not
|
|
91
|
+
the one item 3 names**: under a squash or rebase merge, or a
|
|
92
|
+
cherry-pick into the base, the fix's own commits never reach it —
|
|
93
|
+
record the commit the fix landed as (item 3).
|
|
94
|
+
⚠ Do **not** cut from `main` instead to make the check pass: the
|
|
95
|
+
documentation branch would carry `main`'s merge commits into
|
|
96
|
+
`develop` when it merges, and its documents would start from
|
|
97
|
+
`main`'s older Domain documents and conflict there.
|
|
98
|
+
- **Any other exit code** — a mistyped ref or a failed command. Stop
|
|
99
|
+
and show the developer the output.
|
|
100
|
+
- **If step 1's fetch failed** (offline): exit `0` is still
|
|
101
|
+
trustworthy — the ref you cut from does contain the commit. Exit `1`
|
|
102
|
+
may only mean the local ref is behind; treat it as provisional and
|
|
103
|
+
say so.
|
|
45
104
|
3. **Implementation checkpoint Result = `reconciled ({merged-hotfix-hash})`.**
|
|
46
105
|
In the host's Checkpoint Log the implementation row's Result is
|
|
47
106
|
`reconciled (...)` — the value meaning "this checkpoint documents an
|
|
48
|
-
already-merged change" — carrying the
|
|
49
|
-
|
|
107
|
+
already-merged change" — carrying the hash of **one of the fix's own
|
|
108
|
+
commits**, or of **the commit the fix landed as** when it reached the base
|
|
109
|
+
branch by a squash, a rebase or a cherry-pick — a commit on the base
|
|
110
|
+
branch this host's branch is cut from (item 2).
|
|
111
|
+
It sits alongside the usual `committed` / `skipped` / `failed` Results (see
|
|
50
112
|
`references/git-integration.md` § Commit Checkpoints, Branch Gate & AI
|
|
51
113
|
Commits). That hash belongs to the **hotfix**, so it is **not** evidence
|
|
52
114
|
that this host's own first commit landed — the documentation work still owes
|
|
@@ -54,12 +116,27 @@ If you arrived here with a T1, go back to Part A's routing.
|
|
|
54
116
|
Committing the documentation together with closeout collapses the host to
|
|
55
117
|
one commit and fails finish-feature Step 1.
|
|
56
118
|
|
|
119
|
+
**Which commit that is depends on how the fix reached the base branch:**
|
|
120
|
+
|
|
121
|
+
| The fix reached the base branch by | Record |
|
|
122
|
+
|---|---|
|
|
123
|
+
| a merge (under GitFlow, merging the hotfix branch back into `develop`) or a fast-forward | the last of **the fix's own commits** that touches a declared implementation path — never a merge commit, and under GitFlow never the tagged merge commit on `main`, which the back-merge does not bring into `develop` |
|
|
124
|
+
| a squash merge | the squash commit on the base branch |
|
|
125
|
+
| a rebase merge or a cherry-pick | the last of the fix's commits **as they landed on the base branch** that touches a declared implementation path |
|
|
126
|
+
|
|
127
|
+
When the fix's own commits are on the base branch, record one of them even if
|
|
128
|
+
a copy of the fix got there first. Closeout accepts a commit that touches only
|
|
129
|
+
some of the declared paths: it asks for at least one. The hotfix branch's own
|
|
130
|
+
name still goes in `hotfix-branch:` (item 4).
|
|
131
|
+
|
|
57
132
|
**You are asserting this hash, not deriving it.** Nothing in the repository
|
|
58
133
|
records which commit was the hotfix, so no check in this flow can confirm
|
|
59
134
|
it — finish-feature's reconciliation gate is explicit that it tests
|
|
60
135
|
plausibility only. So state the identity
|
|
61
136
|
and **cite what it rests on**: the PR, incident, or tracker reference that
|
|
62
|
-
identifies this fix.
|
|
137
|
+
identifies this fix. **Cite the source, not the hash** — a corrected hash
|
|
138
|
+
(item 6) then never has to touch the citation. Record the citation
|
|
139
|
+
alongside the per-tier trace
|
|
63
140
|
(item 4). An **uncited** hash blocks closeout —
|
|
64
141
|
`references/pr-review-checklist.md` is what confirms the identity, and it
|
|
65
142
|
needs something to confirm against.
|
|
@@ -80,3 +157,44 @@ If you arrived here with a T1, go back to Part A's routing.
|
|
|
80
157
|
5. **Branch equality** for the host is asserted against the **post-hoc
|
|
81
158
|
documentation branch** (the `_index.md` `branch:` value), never the deleted
|
|
82
159
|
hotfix branch.
|
|
160
|
+
6. **Closeout: (b) fails on the `reconciled (...)` hash.**
|
|
161
|
+
`references/finish-feature-minimal-host.md`'s `Minimal host, hotfix
|
|
162
|
+
post-hoc only` check sends you here. Report which cause it is — never only
|
|
163
|
+
"not an ancestor" — and give the developer the repair for that cause. First
|
|
164
|
+
fetch the remote `{base-ref}` belongs to (item 2 step 1) and find the
|
|
165
|
+
commit item 3 says to record, then test where it is. If the fetch fails, a
|
|
166
|
+
result that depends on `{base-ref}`, or on a commit this clone does not
|
|
167
|
+
have, is provisional — say so, as item 2 does:
|
|
168
|
+
- **It is already on this branch** (`git merge-base --is-ancestor
|
|
169
|
+
{its-hash} HEAD` exits `0`) — the record names the right fix but the
|
|
170
|
+
wrong commit — for example the tagged merge commit on `main`. Correct
|
|
171
|
+
only the Checkpoint Log hash. The citation (item 3 cites the source, not
|
|
172
|
+
the hash), `hotfix-branch:` and the declared paths stay as they are, so
|
|
173
|
+
the correction rides the closeout commit — closeout's closed list admits
|
|
174
|
+
Checkpoint Log rows. Checkpoint 1 is not touched.
|
|
175
|
+
- **It is on the base branch but not on this branch** (`git merge-base
|
|
176
|
+
--is-ancestor {its-hash} {base-ref}` exits `0`) — this branch was cut
|
|
177
|
+
before the fix reached the base, so correcting the hash is not enough.
|
|
178
|
+
Merge `{base-ref}` into this branch — or, if nothing is pushed yet,
|
|
179
|
+
rebase this branch onto it and refill every Lightweight Changes row's
|
|
180
|
+
`Commit` cell — then record that commit. Set closeout's uncommitted
|
|
181
|
+
finalization edits aside first with `git stash push --include-untracked`
|
|
182
|
+
(a plain `git stash` leaves newly created files behind), check that
|
|
183
|
+
`git status --porcelain` prints nothing, and restore them afterwards
|
|
184
|
+
with `git stash pop`: `git rebase` refuses to run over uncommitted
|
|
185
|
+
edits, and `git merge` refuses when the base changed the same files. If
|
|
186
|
+
`git stash pop` reports a conflict — it can when the base changed the
|
|
187
|
+
same part of a file those edits touch — resolve it before closeout
|
|
188
|
+
continues.
|
|
189
|
+
- **It is not on the base branch either** — the fix was never merged back.
|
|
190
|
+
Merge it back first (under GitFlow, into `develop`), then take the case
|
|
191
|
+
above.
|
|
192
|
+
- ⚠ **Never merge `main` or the tag into this branch to make (b) pass.** It
|
|
193
|
+
lets the wrongly recorded commit pass unchanged, and it carries `main`'s
|
|
194
|
+
commits into `develop` when this branch merges.
|
|
195
|
+
- **The record names a different fix** (the citation, the hotfix branch and
|
|
196
|
+
the declared paths are all wrong) — checkpoint 1's own record is wrong,
|
|
197
|
+
and closeout cannot repair that. Follow
|
|
198
|
+
`references/finish-feature-record-correction.md`: it says when
|
|
199
|
+
checkpoint 1 can be amended and when to stop for the developer, and it
|
|
200
|
+
covers `reconciled (...)`, which names the wrong fix too.
|
|
@@ -449,7 +449,7 @@ During implementation, continuously verify:
|
|
|
449
449
|
**→ Step Gate: Step 7 → Step 8**
|
|
450
450
|
|
|
451
451
|
Announce to developer:
|
|
452
|
-
> "Implementation appears complete across all four layers. Ready to run the completion checklist (verify against spec, update domain docs + context-map, ensure test coverage,
|
|
452
|
+
> "Implementation appears complete across all four layers. Ready to run the completion checklist (verify against spec, update domain docs + context-map, ensure test coverage, complete the phase)? `/dflow:next` to proceed."
|
|
453
453
|
|
|
454
454
|
> Commit checkpoint (T1 milestone 2 of 3): offer to commit the implementation, then record the result in the `_index.md` Checkpoint Log. Milestone 3 (closeout) is the `/dflow:finish-feature` checkpoint.
|
|
455
455
|
|
|
@@ -507,33 +507,51 @@ Ask these one-by-one; do not dump all six at once.
|
|
|
507
507
|
- [ ] `dflow/specs/domain/context-map.md` — updated if cross-context interaction was added or changed
|
|
508
508
|
- [ ] `dflow/specs/architecture/tech-debt.md` — tech debt discovered during implementation recorded
|
|
509
509
|
|
|
510
|
-
### 8.4
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
- [ ]
|
|
523
|
-
|
|
524
|
-
- [ ]
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
510
|
+
### 8.4 Phase completion and handoff
|
|
511
|
+
|
|
512
|
+
This step completes the phase and hands the feature on. It does not close the
|
|
513
|
+
feature out: `/dflow:finish-feature` is the only closeout path — it flips the
|
|
514
|
+
`_index.md` `status`, moves the feature directory to `completed/`, and takes
|
|
515
|
+
the closeout commit checkpoint.
|
|
516
|
+
|
|
517
|
+
**Complete this phase** — all four items, whether or not another phase
|
|
518
|
+
follows:
|
|
519
|
+
|
|
520
|
+
- [ ] This phase-spec's frontmatter `status` changed from `in-progress` to
|
|
521
|
+
`completed`
|
|
522
|
+
- [ ] This phase's row in the `_index.md` Phase Specs table changed from
|
|
523
|
+
`in-progress` to `completed`
|
|
524
|
+
- [ ] `_index.md` Current BR Snapshot reconciled against this phase-spec's
|
|
525
|
+
**Business Rules** section — this is the feature's first phase, so it
|
|
526
|
+
has no Delta from prior phases. If implementation changed a rule, update
|
|
527
|
+
the phase-spec first, then reconcile. Touch only this phase's rows: a
|
|
528
|
+
row that another change in this host wrote — a lightweight change
|
|
529
|
+
hosted under this feature, for example — stays as it is. Where this
|
|
530
|
+
phase and such a change both changed the same rule, keep the later
|
|
531
|
+
change's text; if the host's record does not show which change came
|
|
532
|
+
later, ask the developer which text is current instead of choosing.
|
|
533
|
+
- [ ] `_index.md` Resume Pointer: rewrite **both** narrative lines — Current
|
|
534
|
+
Progress says this phase is completed, and Next Action names the
|
|
535
|
+
command the handoff below picks. Step 4 wrote "phase-1 in progress:
|
|
536
|
+
drafting phase-spec." and "finish phase-spec, then implement …" into
|
|
537
|
+
these two lines; either one left standing reads as open work.
|
|
538
|
+
|
|
539
|
+
`/dflow:finish-feature` relies on these four whenever the feature reaches it,
|
|
540
|
+
next or after later phases. Its Step 1 checks the phase-spec `status`, the
|
|
541
|
+
Phase Specs row and the Resume Pointer, and stops closeout on a stale one.
|
|
542
|
+
Its Step 3 syncs the Current BR Snapshot into the bounded context as it
|
|
543
|
+
stands, without re-deriving it from the phase-specs.
|
|
544
|
+
|
|
545
|
+
`Implementation Tasks` is not on this list: 8.1 verified it, and 8.2 may have
|
|
546
|
+
collapsed or removed it by team convention. BC document sync is not on it
|
|
547
|
+
either: 8.3 did it.
|
|
548
|
+
|
|
549
|
+
**Hand off:**
|
|
550
|
+
|
|
551
|
+
- Another phase is still ahead → run `/dflow:new-phase` next.
|
|
552
|
+
- No further phase — a single-phase feature, or this was the last phase →
|
|
553
|
+
run `/dflow:finish-feature` next. It is the only closeout path.
|
|
554
|
+
|
|
555
|
+
Announce that this phase is completed and name the next command. Do not
|
|
556
|
+
announce the feature as complete: `/dflow:finish-feature` announces that once
|
|
557
|
+
its closeout is complete.
|
|
@@ -347,5 +347,5 @@ state or archive the whole feature from `/dflow:new-phase`.
|
|
|
347
347
|
|
|
348
348
|
After completion, summarize for the developer:
|
|
349
349
|
> "Phase {N+1} is implemented and marked completed. `_index.md` is refreshed.
|
|
350
|
-
> If another slice is needed, run `/dflow:new-phase`; if
|
|
351
|
-
> run `/dflow:finish-feature
|
|
350
|
+
> If another slice is needed, run `/dflow:new-phase`; if there is no further
|
|
351
|
+
> phase, run `/dflow:finish-feature` to close the feature out."
|
|
@@ -160,7 +160,17 @@ skip one and the boundary is a hole rather than a division of labour.
|
|
|
160
160
|
checkpoint 1 and closeout. A third, typically a host opened in its own
|
|
161
161
|
commit before the work landed, breaks the two-commit lifecycle while
|
|
162
162
|
every closeout check still passes, because those read only the hashes
|
|
163
|
-
the record points at.
|
|
163
|
+
the record points at. A third that comes **after** checkpoint 1 and
|
|
164
|
+
changes only the host's record text — no implementation path, no new
|
|
165
|
+
host file — may instead be a correction committed on its own once
|
|
166
|
+
checkpoint 1 was pushed (`references/finish-feature-record-correction.md`
|
|
167
|
+
sends the developer that way and asks for it to be named in the PR
|
|
168
|
+
description). Report which it is: the count still fails, and
|
|
169
|
+
accepting a correction commit is your call after reading its full
|
|
170
|
+
diff and the PR description. A correction that touches only a record
|
|
171
|
+
outside this directory — a follow-up's original `_index.md` — is not in
|
|
172
|
+
this walk; the PR description is where it is named.
|
|
173
|
+
**This count applies to a minimal host only**: a
|
|
164
174
|
phase-bearing feature has no fixed number of host commits, so there is
|
|
165
175
|
nothing to count there and this item is N/A.
|
|
166
176
|
This is also where closeout's minimal-host **selector** boundary is
|
|
@@ -173,9 +183,23 @@ skip one and the boundary is a hole rather than a division of labour.
|
|
|
173
183
|
so the developer asserts it and cites what the claim rests on —
|
|
174
184
|
`hotfix-identity:` beside `hotfix-branch:` in a **T2**'s
|
|
175
185
|
lightweight-spec frontmatter, or in the row Description for a **T3**.
|
|
176
|
-
**Open that source** — PR, incident, or tracker — and confirm it
|
|
177
|
-
this fix and
|
|
178
|
-
|
|
186
|
+
**Open that source** — PR, incident, or tracker — and confirm that it
|
|
187
|
+
names **this fix** and the recorded commit: one of the fix's own
|
|
188
|
+
commits, or the squash commit when the fix was squashed
|
|
189
|
+
(`references/modify-existing-post-hoc-hotfix.md` item 3). A fix merged
|
|
190
|
+
without a PR is identified by the source and the base branch's history
|
|
191
|
+
instead — the hotfix branch's name or the source's number in commit
|
|
192
|
+
messages.
|
|
193
|
+
**When the fix landed as a copy** — a rebase merge or a cherry-pick —
|
|
194
|
+
the recorded commit is that copy, and the source may not name it. Git
|
|
195
|
+
cannot prove that one commit is a copy of another: ancestry does not
|
|
196
|
+
follow copies, and patch comparison (`git cherry`, `git patch-id`)
|
|
197
|
+
cannot tell apart two changes that differ only in whitespace. A
|
|
198
|
+
`(cherry picked from commit …)` line or a matching subject is a clue,
|
|
199
|
+
not proof — settle it with the author from the source, and do not
|
|
200
|
+
report the identity as confirmed from command output alone.
|
|
201
|
+
Closeout already checked that a citation is *present*; only review can
|
|
202
|
+
check that it *matches*.
|
|
179
203
|
- [ ] **Hosted `Commit` cell identity — confirm each hash is *that row's own*
|
|
180
204
|
implementation commit** (phase-bearing host only). `finish-feature-flow.md`
|
|
181
205
|
Step 4 instruction 1 orders the value ("each row's own implementation
|