dflow-sdd-ddd 0.14.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.
- package/CHANGELOG.md +759 -0
- package/CONTRIBUTING.md +10 -1
- package/README.en.md +155 -210
- package/README.md +88 -145
- package/TEMPLATE-COVERAGE.md +13 -6
- package/TEMPLATE-LANGUAGE-GLOSSARY.md +15 -1
- package/bin/dflow.js +15 -4
- package/docs/commands.en.md +110 -0
- package/docs/commands.md +101 -0
- package/docs/doctor-uncertainty.en.md +212 -0
- package/docs/doctor-uncertainty.md +212 -0
- package/docs/evaluating-dflow.en.md +29 -11
- package/docs/evaluating-dflow.md +8 -6
- package/docs/release-versioning-policy.md +5 -0
- package/docs/upgrading.en.md +196 -0
- package/docs/upgrading.md +197 -0
- package/docs/using-with-claude-code.en.md +13 -4
- package/docs/using-with-claude-code.md +13 -4
- package/docs/using-with-codex.en.md +13 -4
- package/docs/using-with-codex.md +13 -4
- package/docs/using-with-github-copilot.en.md +13 -4
- package/docs/using-with-github-copilot.md +13 -4
- package/lib/doc-shapes.json +997 -0
- package/lib/doctor-checks.js +2500 -24
- package/lib/init.js +2846 -143
- package/lib/render-diagrams.js +1474 -0
- package/lib/render.js +865 -49
- package/package.json +2 -2
- package/templates/brownfield/references/drift-verification.md +4 -0
- package/templates/brownfield/references/finish-feature-flow.md +635 -88
- package/templates/brownfield/references/finish-feature-follow-up.md +60 -0
- package/templates/brownfield/references/finish-feature-minimal-host.md +406 -0
- package/templates/brownfield/references/finish-feature-post-hoc-hotfix.md +95 -0
- package/templates/brownfield/references/git-integration.md +160 -15
- package/templates/brownfield/references/init-project-flow.md +23 -3
- package/templates/brownfield/references/modify-existing-flow.md +412 -87
- package/templates/brownfield/references/modify-existing-follow-up.md +121 -0
- package/templates/brownfield/references/modify-existing-post-hoc-hotfix.md +82 -0
- package/templates/brownfield/references/new-feature-flow.md +61 -6
- package/templates/brownfield/references/new-phase-flow.md +57 -7
- package/templates/brownfield/references/pr-review-checklist.md +303 -10
- package/templates/brownfield/scaffolding/AI-AGENT-GUIDE.md +151 -34
- package/templates/brownfield/scaffolding/CLAUDE-md-snippet.md +1 -1
- package/templates/brownfield/scaffolding/Git-principles-gitflow.md +75 -6
- package/templates/brownfield/scaffolding/Git-principles-trunk.md +82 -8
- package/templates/brownfield/scaffolding/_conventions.md +50 -28
- package/templates/brownfield/scaffolding/_overview.md +1 -0
- package/templates/brownfield/templates/_index.md +151 -7
- package/templates/brownfield/templates/analysis.md +79 -0
- package/templates/brownfield/templates/behavior.md +1 -0
- package/templates/brownfield/templates/context-definition.md +1 -0
- package/templates/brownfield/templates/context-map.md +2 -1
- package/templates/brownfield/templates/glossary.md +1 -0
- package/templates/brownfield/templates/lightweight-spec.md +154 -11
- package/templates/brownfield/templates/models.md +1 -0
- package/templates/brownfield/templates/phase-spec.md +9 -1
- package/templates/brownfield/templates/rules.md +1 -0
- package/templates/brownfield/templates/tech-debt.md +1 -0
- package/templates/common/references/ddd-modeling-guide.md +33 -16
- package/templates/{greenfield → common}/references/dflow-feedback-flow.md +2 -1
- package/templates/common/references/flow-rationale-registry.md +130 -0
- package/templates/common/skill/SKILL.md +13 -11
- package/templates/greenfield/references/drift-verification.md +4 -0
- package/templates/greenfield/references/finish-feature-flow.md +625 -89
- package/templates/greenfield/references/finish-feature-follow-up.md +60 -0
- package/templates/greenfield/references/finish-feature-minimal-host.md +363 -0
- package/templates/greenfield/references/finish-feature-post-hoc-hotfix.md +95 -0
- package/templates/greenfield/references/git-integration.md +148 -15
- package/templates/greenfield/references/init-project-flow.md +23 -3
- package/templates/greenfield/references/modify-existing-flow.md +378 -85
- package/templates/greenfield/references/modify-existing-follow-up.md +103 -0
- package/templates/greenfield/references/modify-existing-post-hoc-hotfix.md +82 -0
- package/templates/greenfield/references/new-feature-flow.md +67 -4
- package/templates/greenfield/references/new-phase-flow.md +56 -7
- package/templates/greenfield/references/pr-review-checklist.md +287 -8
- package/templates/greenfield/scaffolding/AI-AGENT-GUIDE.md +146 -32
- package/templates/greenfield/scaffolding/CLAUDE-md-snippet.md +5 -2
- package/templates/greenfield/scaffolding/Git-principles-gitflow.md +74 -6
- package/templates/greenfield/scaffolding/Git-principles-trunk.md +88 -12
- package/templates/greenfield/scaffolding/_conventions.md +50 -28
- package/templates/greenfield/scaffolding/_overview.md +6 -2
- package/templates/greenfield/templates/_index.md +137 -7
- package/templates/greenfield/templates/aggregate-design.md +1 -0
- package/templates/greenfield/templates/analysis.md +79 -0
- package/templates/greenfield/templates/behavior.md +1 -0
- package/templates/greenfield/templates/context-definition.md +1 -0
- package/templates/greenfield/templates/context-map.md +2 -1
- package/templates/greenfield/templates/events.md +4 -1
- package/templates/greenfield/templates/glossary.md +1 -0
- package/templates/greenfield/templates/lightweight-spec.md +154 -11
- package/templates/greenfield/templates/models.md +1 -0
- package/templates/greenfield/templates/phase-spec.md +9 -1
- package/templates/greenfield/templates/rules.md +1 -0
- package/templates/greenfield/templates/tech-debt.md +1 -0
- package/templates/brownfield/references/dflow-feedback-flow.md +0 -251
|
@@ -34,20 +34,45 @@ touches and read them all.
|
|
|
34
34
|
{reason}." (If you can't, pause and ask the author.)
|
|
35
35
|
- [ ] Only then proceed to the code-review sections below
|
|
36
36
|
|
|
37
|
-
If the PR
|
|
37
|
+
If the PR records its change in neither a spec nor an `_index.md` row (a T3
|
|
38
|
+
inline row or a `Tier = baseline` row is such a record, and a host that
|
|
39
|
+
carries one needs no spec), first check whether it only records existing
|
|
40
|
+
behaviour or a decision in Domain documents, without changing output.
|
|
41
|
+
That PR is observation-only, and some observation-only records legitimately
|
|
42
|
+
have no host: answer it with the reply under "If the spec is missing or
|
|
43
|
+
incomplete" at the end of Spec Compliance, not with the one below. For any
|
|
44
|
+
other PR with no such record:
|
|
38
45
|
```
|
|
39
46
|
"I don't see a feature directory or _index.md for this PR. Before I
|
|
40
|
-
review the code, can you point me to
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
47
|
+
review the code, can you point me to the host feature? SDD relies on
|
|
48
|
+
the recorded change being the review anchor.
|
|
49
|
+
|
|
50
|
+
If this change belongs to a feature that already exists, run
|
|
51
|
+
/dflow:modify-existing or /dflow:bug-fix against it — the cascade
|
|
52
|
+
decides what gets recorded (a T2 lands a lightweight spec; a T3 lands
|
|
53
|
+
one inline row in that feature's _index.md and no spec file). If it is
|
|
54
|
+
genuinely new work, run /dflow:new-feature.
|
|
55
|
+
|
|
56
|
+
If no feature exists to host it at all, that is the standalone case and
|
|
57
|
+
it has a defined route: /dflow:modify-existing opens a minimal
|
|
58
|
+
(zero-phase) host for it — Step 1.7, or Step 1.6's minimal variant when
|
|
59
|
+
the change is a follow-up on a completed feature. Send it there rather
|
|
60
|
+
than inventing a home by hand."
|
|
44
61
|
```
|
|
45
62
|
|
|
46
63
|
## Spec Compliance
|
|
47
64
|
|
|
48
65
|
Per-feature checks:
|
|
49
66
|
- [ ] **Feature directory exists** with `_index.md` + at least one
|
|
50
|
-
phase-spec (or one lightweight-spec for a T2-only feature)
|
|
67
|
+
phase-spec (or one lightweight-spec for a T2-only feature).
|
|
68
|
+
**Exception — a host whose whole record is inline.** A **T3-only**
|
|
69
|
+
minimal host has no spec file by design: a T3 never produces one.
|
|
70
|
+
A **baseline-only** host has none either — a baseline capture writes
|
|
71
|
+
Domain documents directly and records a `Tier = baseline` row. For both,
|
|
72
|
+
the requirement is at least one `_index.md` Lightweight Changes row,
|
|
73
|
+
not a spec file. Do **not** ask the author to add a spec to satisfy
|
|
74
|
+
this line — that manufactures the artifact the tier forbids and the
|
|
75
|
+
flow refuses to write.
|
|
51
76
|
- [ ] **`_index.md` Current BR Snapshot is up to date** — reflects
|
|
52
77
|
the cumulative effect of all phase-specs / lightweight-specs in
|
|
53
78
|
the directory
|
|
@@ -55,7 +80,9 @@ Per-feature checks:
|
|
|
55
80
|
phase-spec file exists and its `status` matches the row's claim
|
|
56
81
|
- [ ] **For follow-up features**: `_index.md` Metadata has `follow-up-of:
|
|
57
82
|
{原 SPEC-ID}` AND the original feature's `_index.md`
|
|
58
|
-
Follow-up Tracking row references this feature
|
|
83
|
+
Follow-up Tracking row references this feature. **`follow-up-of` may
|
|
84
|
+
be a YAML array** — when it names several originals, *each* of them
|
|
85
|
+
must carry the row; checking the first one is not checking the field.
|
|
59
86
|
|
|
60
87
|
Per-phase-spec / lightweight-spec checks (run for **each** spec file the
|
|
61
88
|
PR touches, not just one):
|
|
@@ -63,6 +90,23 @@ PR touches, not just one):
|
|
|
63
90
|
- [ ] **Business rules covered** — all BR-* rules in this spec
|
|
64
91
|
implemented
|
|
65
92
|
- [ ] **Edge cases handled** — EC-* in this spec addressed
|
|
93
|
+
- [ ] **No-BR family evidence** — for a lightweight-spec whose Behavior
|
|
94
|
+
Delta is a `BR:` / `BR Delta:` none line, check that family's
|
|
95
|
+
evidence instead: (a) `Output Footprint`; (b) `Contract Delta` +
|
|
96
|
+
`**Downstream consumers**`; (c) `Operational Rationale` +
|
|
97
|
+
`**Trace**`; (d) `Performance Delta` + `**SLA / resource
|
|
98
|
+
context**`; (e) `Governing BR-IDs` + root cause + a regression
|
|
99
|
+
check; (f) `Change Rationale` with `**Before**` / `**After**` +
|
|
100
|
+
`**Regression**`. The BR / scenario / Domain items above are
|
|
101
|
+
**N/A** for these specs — record them as N/A rather than passing
|
|
102
|
+
them on an empty rule set, and never fabricate a BR or a
|
|
103
|
+
`behavior.md` anchor to make one pass. Domain documents are not
|
|
104
|
+
automatically N/A: a contract change that touches documented
|
|
105
|
+
behavior still belongs in `behavior.md`. A spec in the
|
|
106
|
+
classic BR-delta form, or a bug spec with the older single `BR:`
|
|
107
|
+
line, is accepted as-is. A change matching more than one family
|
|
108
|
+
must carry **every** matching family's evidence, not just the one
|
|
109
|
+
its BR line names
|
|
66
110
|
- [ ] **Delta integrity** (phase 2+ only) — the Delta-from-prior-phases
|
|
67
111
|
section's ADDED / MODIFIED / REMOVED / RENAMED entries actually
|
|
68
112
|
match the diff against the prior phase-spec's BR set
|
|
@@ -70,19 +114,267 @@ PR touches, not just one):
|
|
|
70
114
|
If the closeout commit is in this PR (`/dflow:finish-feature` was run):
|
|
71
115
|
- [ ] **BC layer sync landed** — `dflow/specs/domain/{context}/rules.md` and
|
|
72
116
|
`behavior.md` reflect the feature's net effect (compare against
|
|
73
|
-
`_index.md` Current BR Snapshot)
|
|
117
|
+
`_index.md` Current BR Snapshot). **N/A for a no-BC host** — one whose
|
|
118
|
+
Goals & Scope declares no bounded context has nothing to sync, and a
|
|
119
|
+
`{context}` document invented to satisfy this line is a fiction, never a
|
|
120
|
+
pass.
|
|
121
|
+
⚠ **Do not read that as "closeout already blocks it" without qualifying
|
|
122
|
+
where.** Closeout blocks it in the commits it actually reads — checkpoint
|
|
123
|
+
1, and only on a **minimal** host, plus the closeout commit on any host.
|
|
124
|
+
A fiction committed by a **phase-bearing** no-BC host anywhere in between
|
|
125
|
+
passes every closeout check. That range is the *"A no-BC host committed no
|
|
126
|
+
BC-scoped Domain material"* item in the delegated block below, and it is
|
|
127
|
+
yours to run. **N/A for a baseline capture** — a baseline
|
|
128
|
+
writes Domain documents directly, so there is no separate sync to land.
|
|
129
|
+
**N/A for a T3**, which does no Domain work at all. Record the N/A rather
|
|
130
|
+
than ticking it against an empty comparison — but note `glossary.md` and
|
|
131
|
+
`migration/tech-debt.md` belong to no bounded context, stay in a no-BC
|
|
132
|
+
host's sweep, and are a baseline capture's own capture destinations, so
|
|
133
|
+
this N/A does not reach them.
|
|
74
134
|
- [ ] **Whole feature directory `git mv`'d** to `completed/` — git
|
|
75
135
|
shows `renamed:` (not `deleted:` + `new file:`)
|
|
76
136
|
- [ ] **Integration Summary** was emitted to the conversation (not
|
|
77
137
|
written to a file — it's ephemeral)
|
|
138
|
+
- [ ] **Every Lightweight Changes row now carries a `Commit` hash.**
|
|
139
|
+
Before closeout an empty cell can be legitimate: on a **hosted** row
|
|
140
|
+
the cell is filled by the host's *next* commit, and closeout is
|
|
141
|
+
allowed to be that commit. (A **minimal** host is stricter — its rows
|
|
142
|
+
are written before checkpoint 1, and closeout already refuses an empty
|
|
143
|
+
cell there.) After closeout there is no next commit, so an empty cell
|
|
144
|
+
will never be filled. That is why closeout does not assert this for a
|
|
145
|
+
phase-bearing host, and why it is checkable here.
|
|
146
|
+
⚠ **A placeholder is not a hash.** `{hash}`, `{pending}`, `(待 commit)` —
|
|
147
|
+
anything that is not a resolvable commit — counts as **unfilled**, not as
|
|
148
|
+
carrying one. It is the harder case to catch precisely because the cell is
|
|
149
|
+
**non-empty**: every rule downstream is written against empty / non-empty,
|
|
150
|
+
so a placeholder reads as filled to all of them. Resolve each value
|
|
151
|
+
(`git cat-file -t {value}`) rather than checking the cell is populated.
|
|
152
|
+
|
|
153
|
+
**Delegated to review by `finish-feature-flow.md`.** Closeout states at each
|
|
154
|
+
of these sites that it does *not* prove them. They are not optional extras:
|
|
155
|
+
skip one and the boundary is a hole rather than a division of labour.
|
|
156
|
+
|
|
157
|
+
- [ ] **Whole history — no stray host-open commit.** Closeout validates the
|
|
158
|
+
hashes the record names and cannot see the rest of the branch. List
|
|
159
|
+
this branch's commits that touch the host directory:
|
|
160
|
+
`git log --oneline {base}..HEAD -- 'dflow/specs/features/active/{SPEC-ID}-{slug}/' 'dflow/specs/features/completed/{SPEC-ID}-{slug}/'`
|
|
161
|
+
For a **minimal (zero-phase) host** there must be exactly two —
|
|
162
|
+
checkpoint 1 and closeout. A third, typically a host opened in its own
|
|
163
|
+
commit before the work landed, breaks the two-commit lifecycle while
|
|
164
|
+
every closeout check still passes, because those read only the hashes
|
|
165
|
+
the record points at. **This count applies to a minimal host only**: a
|
|
166
|
+
phase-bearing feature has no fixed number of host commits, so there is
|
|
167
|
+
nothing to count there and this item is N/A.
|
|
168
|
+
This is also where closeout's minimal-host **selector** boundary is
|
|
169
|
+
settled: that selector reads the host's persisted shape today and
|
|
170
|
+
cannot know it was opened minimal and *stayed* minimal. The commit walk
|
|
171
|
+
is what shows that.
|
|
172
|
+
- [ ] **Hotfix identity — confirm it against the cited source** (post-hoc
|
|
173
|
+
host only). Closeout tests **plausibility only**, and says so: which
|
|
174
|
+
commit was *the* merged hotfix is not derivable from inside the flow,
|
|
175
|
+
so the developer asserts it and cites what the claim rests on —
|
|
176
|
+
`hotfix-identity:` beside `hotfix-branch:` in a **T2**'s
|
|
177
|
+
lightweight-spec frontmatter, or in the row Description for a **T3**.
|
|
178
|
+
**Open that source** — PR, incident, or tracker — and confirm it names
|
|
179
|
+
this fix and this commit. Closeout already checked that a citation is
|
|
180
|
+
*present*; only review can check that it *matches*.
|
|
181
|
+
- [ ] **Hosted `Commit` cell identity — confirm each hash is *that row's own*
|
|
182
|
+
implementation commit** (phase-bearing host only). `finish-feature-flow.md`
|
|
183
|
+
Step 4 instruction 1 orders the value ("each row's own implementation
|
|
184
|
+
hash, never the closeout hash") and its post-commit verification **states
|
|
185
|
+
that it cannot decide it**: the hash-evidence test is minimal-host-only
|
|
186
|
+
and lives in `finish-feature-minimal-host.md`, so on a phase-bearing host
|
|
187
|
+
no closeout check reads the value at all. The presence item above asserts the cell is **non-empty**;
|
|
188
|
+
this one asserts it is **right**, and the two are not interchangeable.
|
|
189
|
+
For each Lightweight Changes row, take its `Commit` hash and run
|
|
190
|
+
`git show --stat {hash}`. **Take the row's declaration if it has one and
|
|
191
|
+
require the commit to touch it** — a **T2**'s own spec file
|
|
192
|
+
(`lightweight-*.md` / `BUG-*.md`), a **T3**'s Description implementation
|
|
193
|
+
paths, a **`Tier = baseline`** row's capture documents — a capture
|
|
194
|
+
is **observation-only**, so what it declares is documents, never
|
|
195
|
+
implementation paths. (A phase-bearing host may legitimately hold a
|
|
196
|
+
baseline row alongside phase work; `finish-feature-minimal-host.md` says so
|
|
197
|
+
where it explains why such a host never reaches the zero-phase checks.)
|
|
198
|
+
**If the row declares nothing, that is by design on a hosted row — with
|
|
199
|
+
one exception.** A **T2** links to its own spec file on *every* host shape:
|
|
200
|
+
`finish-feature-flow.md` Step 1 carries two `Tier = T2` checks that no
|
|
201
|
+
host shape escapes — one of them says so in as many words — and
|
|
202
|
+
`finish-feature-minimal-host.md`'s phase-bearing exemption note confirms
|
|
203
|
+
those hosts keep them. A T2 row with
|
|
204
|
+
no such link is **malformed, not exempt** — find the spec file or flag the
|
|
205
|
+
row. For a **T3**, and for a **baseline** row, the absence is the
|
|
206
|
+
sanctioned state — and for the baseline it is the same hosted exemption
|
|
207
|
+
that covers a hosted T3, which `templates/_index.md` extends to baseline
|
|
208
|
+
rows in the same breath. It is not a property of captures.
|
|
209
|
+
⚠ The record then gives you nothing to compare against, and that is
|
|
210
|
+
deliberate: `finish-feature-minimal-host.md` exempts phase-bearing hosts
|
|
211
|
+
from its `Commit` cell path check for exactly this reason
|
|
212
|
+
(`references/flow-rationale-registry.md`, `R-FF-COMMITCELL-02`:
|
|
213
|
+
"demanding it would reject every hosted T3"), and `templates/_index.md`
|
|
214
|
+
calls declaring them good
|
|
215
|
+
practice with no gate behind it. **Do not read "touches nothing declared"
|
|
216
|
+
as a pass.** What remains checkable is weaker and is worth stating as
|
|
217
|
+
such: the hash is **not** the closeout commit, is **not** any other row's
|
|
218
|
+
hash, and is a commit on this host's branch — or on a branch this host
|
|
219
|
+
recorded a `branch-override` for. Past that, ask the developer which
|
|
220
|
+
commit carried the row. If identity matters for this change, say so and
|
|
221
|
+
have the row declare its paths — that is what makes the comparison above
|
|
222
|
+
available.
|
|
223
|
+
⚠ **Do not let tier decide that a declaration must exist.** Tier says what
|
|
224
|
+
the declaration would have been; the one hosted row required to carry one
|
|
225
|
+
is a T2, and that requirement lives in Step 1, not here. Keying this check
|
|
226
|
+
on tier produced three successive versions that each named an input some
|
|
227
|
+
row was not required to carry.
|
|
228
|
+
A cell holding the **closeout** hash, or another row's hash, is what this
|
|
229
|
+
exists to catch: both are non-empty, both pass every closeout check, and
|
|
230
|
+
neither is what instruction 1 ordered.
|
|
231
|
+
**N/A for a minimal host** — there `finish-feature-minimal-host.md`'s
|
|
232
|
+
hash-evidence test already runs (a)–(c) against every row before closeout
|
|
233
|
+
may proceed.
|
|
234
|
+
- [ ] **A recorded branch override still matches where the closeout landed**
|
|
235
|
+
(only when the host carries a `branch-override` row). Closeout passes its
|
|
236
|
+
branch check on any such row naming the branch it ran on, and **states
|
|
237
|
+
that it cannot decide** whether that override was still the current
|
|
238
|
+
intent — nothing expires a row once the developer returns to the host's
|
|
239
|
+
own branch. You can see what closeout cannot: which branch the closeout
|
|
240
|
+
commit sits on, and whether the work had already been integrated by then.
|
|
241
|
+
Two cases to reject, both instances of one rule — **the branch this
|
|
242
|
+
closeout landed on is not where this host's work was finished**: a closeout
|
|
243
|
+
committed onto the **base** branch *after* the feature branch was merged
|
|
244
|
+
(that puts the closeout commit outside the review this checklist is part
|
|
245
|
+
of), and a closeout committed onto a branch an override named earlier but
|
|
246
|
+
which the work has since **left** — a superseded spike, say. Closeout
|
|
247
|
+
distinguishes neither, because it accepts any branch this host ever
|
|
248
|
+
recorded an override for.
|
|
249
|
+
- [ ] **The closeout commit carries only this host's delta.** Closeout's spill
|
|
250
|
+
check derives its permitted set from Step 4 instruction 2, which defines
|
|
251
|
+
one for **every** host shape — so there is a permitted-file list to read
|
|
252
|
+
against on a phase-bearing feature too. What that does not change is what
|
|
253
|
+
the check proves: it is a **path-level spill check**, so it proves no
|
|
254
|
+
unpermitted *file* entered the commit, never that the permitted ones carry
|
|
255
|
+
only this change. An unrelated BR edit inside `rules.md`, or another
|
|
256
|
+
feature's term in `glossary.md`, passes it untouched. Read each
|
|
257
|
+
permitted file's diff against the intended delta in the spec / row.
|
|
258
|
+
- [ ] **A follow-up's reverse link was opened, not only closed.** The
|
|
259
|
+
original's Follow-up Tracking row must have existed as `in-progress`
|
|
260
|
+
before the flip to `completed` — `absent → in-progress → completed`,
|
|
261
|
+
never created straight as `completed`. Closeout verifies this for a
|
|
262
|
+
**minimal** host only, from checkpoint 1's committed blob; a
|
|
263
|
+
**phase-bearing** follow-up has no single commit required to carry the
|
|
264
|
+
row, so closeout has nothing equivalent to read and the opening half
|
|
265
|
+
arrives here unchecked. Confirm it from the branch history
|
|
266
|
+
(`git log -p {base}..HEAD -- <original feature>/_index.md`), for
|
|
267
|
+
**each** SPEC-ID in `follow-up-of`.
|
|
268
|
+
- [ ] **A no-BC host committed no BC-scoped Domain material** — **every no-BC
|
|
269
|
+
host, not only phase-bearing ones.** Closeout inspects only **checkpoint
|
|
270
|
+
1's** diff on a minimal host, and a phase-bearing host has no single
|
|
271
|
+
checkpoint to inspect at all. **Neither is a branch-range proof**, and
|
|
272
|
+
closeout cannot take a range — it needs a base branch and Dflow
|
|
273
|
+
deliberately does not know yours. **You have it.** Run
|
|
274
|
+
`git diff --name-status {base}..HEAD -- 'dflow/specs/domain/'` and confirm
|
|
275
|
+
no BC-scoped Domain document — **the set this track's own no-BC closeout
|
|
276
|
+
check names**, `context-map.md` included — was **added, modified, deleted
|
|
277
|
+
or renamed**. A no-BC host is one whose Goals & Scope declares no bounded
|
|
278
|
+
context, the same identification the BC-layer-sync item above uses.
|
|
279
|
+
⚠ **The path filter is deliberately wider than the prohibited set, so read
|
|
280
|
+
the output before flagging.** `context-map.md` sits at `domain/` top level
|
|
281
|
+
rather than under `{context}/`, and the filter has to reach up there to
|
|
282
|
+
catch it — which means it also lists `domain/glossary.md` and
|
|
283
|
+
`domain/analysis.md`. Both belong to no bounded context and stay
|
|
284
|
+
legitimate for a no-BC host: **seeing either here is not a finding.**
|
|
285
|
+
`migration/tech-debt.md` is outside the filter entirely and never appears.
|
|
286
|
+
⚠ **A baseline capture is not a no-BC host** and this item does not apply
|
|
287
|
+
to it: writing Domain documents is exactly what a baseline is for. Closeout's
|
|
288
|
+
own no-BC check states the same exemption.
|
|
78
289
|
|
|
79
290
|
If the spec is missing or incomplete:
|
|
80
291
|
```
|
|
81
292
|
"I notice this PR doesn't have a matching feature directory / _index.md.
|
|
82
|
-
|
|
83
|
-
|
|
293
|
+
Can you describe what this change does? If it only records existing
|
|
294
|
+
behaviour or a decision without changing output, it is observation-only
|
|
295
|
+
and tier-exempt — it is captured in whichever Domain documents it
|
|
296
|
+
actually wrote (there is no fixed list) and stops there. It needs no host
|
|
297
|
+
when it is an analysis.md record made with no workflow running and
|
|
298
|
+
committed on its own, or a capture about no bounded context at all; any
|
|
299
|
+
other capture with no active feature to attach it to gets a baseline
|
|
300
|
+
minimal host, whose Tier = baseline row declares the documents it wrote —
|
|
301
|
+
not a spec. Otherwise: if it belongs to a feature
|
|
302
|
+
we already have, we can record it there retroactively — the tier decides
|
|
303
|
+
what gets written (T2: a lightweight spec; T3: one inline _index.md
|
|
304
|
+
row). If it's genuinely new work, it wants /dflow:new-feature. If
|
|
305
|
+
there's no feature it could belong to, that's the standalone case and
|
|
306
|
+
it has a defined route: /dflow:modify-existing opens a minimal
|
|
307
|
+
(zero-phase) host for it — Step 1.7, or Step 1.6's minimal variant when
|
|
308
|
+
it's a follow-up on a completed feature. Let's send it there rather
|
|
309
|
+
than inventing a home by hand."
|
|
84
310
|
```
|
|
85
311
|
|
|
312
|
+
## Risk-Triggered Modeling Review
|
|
313
|
+
|
|
314
|
+
Use the spec and diff to identify these risks; do not use a keyword-only scan.
|
|
315
|
+
Only when a signal matches, read the named section in
|
|
316
|
+
`dflow/specs/shared/dflow-workflows/references/ddd-modeling-guide.md`. If no
|
|
317
|
+
signal matches, skip this section's guide lookup, create no artifact, and
|
|
318
|
+
continue with the existing checklist below.
|
|
319
|
+
|
|
320
|
+
| Risk signal | Read in the modeling guide |
|
|
321
|
+
|---|---|
|
|
322
|
+
| One use case mutates / saves multiple Aggregate roots, or adds a multi-root Unit of Work | Aggregate Design Rules; Domain Services |
|
|
323
|
+
| The diff crosses Bounded Contexts or changes an event payload, handler, or delivery expectation | Domain Events; Event Handling Guidelines |
|
|
324
|
+
| Deadline, retry, out-of-order callback, compensation, business-visible progress, or a claim that local persistence and an external provider / service fact form one atomic outcome | Aggregate Design Rules; Long-Running Processes; failure-path guidance under Event Handling Guidelines |
|
|
325
|
+
| `unique`, `only one active`, or another set-based invariant | Set-Based / Uniqueness Invariants |
|
|
326
|
+
| A Domain Service is added or changed | Domain Services; Long-Running Processes when the flow has state |
|
|
327
|
+
|
|
328
|
+
For every matched risk, record one disposition in the review:
|
|
329
|
+
|
|
330
|
+
- **Finding** — identify the violated guarantee at the boundary named by the
|
|
331
|
+
matched risk, its severity, and merge disposition. For a match involving an
|
|
332
|
+
external provider / service fact, state that a local transaction cannot make
|
|
333
|
+
that fact atomic with local state; implementing or repairing a local
|
|
334
|
+
transaction / Unit of Work alone is not sufficient closure.
|
|
335
|
+
- **Accepted with rationale** — state why the boundary / transaction / service
|
|
336
|
+
role is sound and when to revisit it. For such an exception, the rationale
|
|
337
|
+
must already exist or be added to the appropriate Aggregate / Domain Service
|
|
338
|
+
row and Notes in `models.md`; when it protects an invariant, update the
|
|
339
|
+
related `rules.md` entry too. The PR conversation points to that decision and
|
|
340
|
+
is not its only home. This disposition evaluates the rationale's adequacy,
|
|
341
|
+
not only its existence: it must explain how it answers every matched risk.
|
|
342
|
+
For a match involving an external provider / service fact, acknowledge that
|
|
343
|
+
a local transaction cannot make that fact atomic with local state and explain
|
|
344
|
+
how the outcome progresses across the boundary, including idempotency and
|
|
345
|
+
retry / compensation (or a justified equivalent). For a Domain Service match,
|
|
346
|
+
name the actual domain rule or decision the accepted operation carries; an
|
|
347
|
+
operation that only orders root calls is Application-layer orchestration and
|
|
348
|
+
remains a Finding, even when another operation of the same service holds a
|
|
349
|
+
real rule. If the rationale does not cover the matched risk, use Finding
|
|
350
|
+
rather than this disposition.
|
|
351
|
+
- **Not applicable** — explain from the spec and diff why the match is only
|
|
352
|
+
superficial.
|
|
353
|
+
|
|
354
|
+
Multiple signals for the same design decision may share one disposition, but
|
|
355
|
+
every matched risk must have an auditable disposition. This is not a per-signal
|
|
356
|
+
form.
|
|
357
|
+
|
|
358
|
+
### Closing a blocking modeling finding
|
|
359
|
+
|
|
360
|
+
A DDD / domain-correctness blocker must state:
|
|
361
|
+
|
|
362
|
+
- the code boundary or enforcement needed to restore the guarantee;
|
|
363
|
+
- the existing durable surfaces that must change, as applicable — the spec,
|
|
364
|
+
domain `models.md` / `rules.md` / `context.md` / `context-map.md` /
|
|
365
|
+
`behavior.md`, or `migration/tech-debt.md`;
|
|
366
|
+
- the automated tests or observable evidence that re-verify the guarantee; and
|
|
367
|
+
- that the unimplemented guarantee must not remain marked `completed` before
|
|
368
|
+
re-review.
|
|
369
|
+
|
|
370
|
+
If the review offers defer as an option, it must list the owner, known risk,
|
|
371
|
+
exit criteria, and `migration/tech-debt.md` landing surface as closure
|
|
372
|
+
conditions. If the team defers the finding, record those items on that surface;
|
|
373
|
+
rationale, a re-evaluation condition, or "future refactor" alone is not
|
|
374
|
+
closure. The reviewer defines the evidence needed to unblock, not the author's
|
|
375
|
+
implementation. Use the existing PR comment / conversation surface; do not
|
|
376
|
+
create a separate review report.
|
|
377
|
+
|
|
86
378
|
## Domain Layer Quality
|
|
87
379
|
|
|
88
380
|
- [ ] **No delivery-framework references in Domain** — `src/Domain/` must have zero dependencies on HTTP request/response objects, session/cookie context, job-runner context, CLI flag parsers, or ViewState equivalents
|
|
@@ -158,6 +450,7 @@ uses '報銷 (Expense Claim)'. Should we align the naming?"
|
|
|
158
450
|
|
|
159
451
|
- [ ] **models.md updated** — New entities/VOs/services documented?
|
|
160
452
|
- [ ] **rules.md updated** — New or changed business rules recorded?
|
|
453
|
+
- [ ] **analysis.md updated** — did this change touch a status transition, an ordered cross-context flow, which roles reach a function, or the way a figure is computed? If so, is the matching entry in `analysis.md` updated? Open one Evidence source it cites and confirm it still says what the entry claims. An entry whose Evidence is `inferred` names what its conclusion was drawn from: confirm instead that the conclusion still follows from it. An entry whose Evidence is `assumed` has no source to open: confirm instead that it says what it rests on and that the question of confirming it is recorded where the Evidence convention at the top of `analysis.md` says, and report it as unverified rather than blocking on it.
|
|
161
454
|
- [ ] **context.md boundaries respected** — Does this change stay within its context?
|
|
162
455
|
|
|
163
456
|
## Tech Debt Awareness
|
|
@@ -64,8 +64,8 @@ are not available in the current AI tool:
|
|
|
64
64
|
|
|
65
65
|
| Workflow | Use when |
|
|
66
66
|
|---|---|
|
|
67
|
-
| `/dflow:new-feature` | A new user-
|
|
68
|
-
| `/dflow:modify-existing` | Existing behavior
|
|
67
|
+
| `/dflow:new-feature` | A genuinely new feature, page, or capability — a **newly created** navigable surface (its own route and its own content tree), a new user-executable domain operation, or a new independently-consumable output. Adding a control to an existing surface — or a menu entry pointing at a route that already exists — is modify-existing. |
|
|
68
|
+
| `/dflow:modify-existing` | Existing behavior or an existing surface changes — including adding a presentation / interaction control (copy button, filter, sort, quick-view) to an existing screen. |
|
|
69
69
|
| `/dflow:bug-fix` | A defect can be described with expected vs actual behavior. |
|
|
70
70
|
| `/dflow:new-phase` | An active feature needs another implementation slice. |
|
|
71
71
|
| `/dflow:finish-feature` | Implementation is complete and needs drift closure. |
|
|
@@ -81,8 +81,8 @@ Machine-readable source for rendering tool-specific thin wrappers:
|
|
|
81
81
|
<!-- dflow-command-registry:start -->
|
|
82
82
|
| id | label | description | arg-hint | scope |
|
|
83
83
|
|---|---|---|---|---|
|
|
84
|
-
| new-feature | /dflow:new-feature | Start a new
|
|
85
|
-
| modify-existing | /dflow:modify-existing | Change existing behavior. | change request | workflow |
|
|
84
|
+
| new-feature | /dflow:new-feature | Start a genuinely new feature, page, or capability (new navigable surface, domain operation, or consumable output). | feature request | workflow |
|
|
85
|
+
| modify-existing | /dflow:modify-existing | Change existing behavior, or add a control to an existing surface. | change request | workflow |
|
|
86
86
|
| bug-fix | /dflow:bug-fix | Investigate a defect described by expected vs actual behavior. | expected vs actual | workflow |
|
|
87
87
|
| new-phase | /dflow:new-phase | Add another implementation slice to an active feature. | feature id or phase goal | workflow |
|
|
88
88
|
| finish-feature | /dflow:finish-feature | Close implementation with drift checks and archived feature state. | feature id | workflow |
|
|
@@ -103,16 +103,36 @@ input like this (supporting files live in the workflow bundle at
|
|
|
103
103
|
- **"Quick question about..." / "How does X work?"** → check
|
|
104
104
|
`dflow/specs/domain/` first and answer from the documented domain knowledge.
|
|
105
105
|
If no spec exists yet, suggest documenting the answer as domain knowledge.
|
|
106
|
+
- **Knowledge that no single context document holds** — an ordered flow that
|
|
107
|
+
crosses contexts (always the domain-root copy), the lifecycle a status field
|
|
108
|
+
moves through, a figure computed rather than stored, the mechanism behind a
|
|
109
|
+
behavior no single rule explains, which roles reach which function (always
|
|
110
|
+
the domain-root copy), or a spot in one of these that this project keeps
|
|
111
|
+
working around until a domain decision settles it (in the copy that holds
|
|
112
|
+
the knowledge it is stuck on) → **record it in
|
|
113
|
+
`analysis.md`**: `dflow/specs/domain/{context}/analysis.md` when one context
|
|
114
|
+
owns what it describes, otherwise `dflow/specs/domain/analysis.md`. Create
|
|
115
|
+
the file from `templates/analysis.md` the first time there is something to
|
|
116
|
+
record. With no workflow running, offer to commit that record on its own.
|
|
106
117
|
- **"What should I work on next?" / sprint planning** → review
|
|
107
118
|
`dflow/specs/features/backlog/` and suggest work based on migration value.
|
|
108
119
|
- **"I'm creating a branch"** → read `references/git-integration.md`; verify
|
|
109
|
-
branch naming and
|
|
120
|
+
branch naming, and make sure the tier's own record exists before coding starts
|
|
121
|
+
(T1 / T2: a spec; T3: the host `_index.md` row — a T3 branch has no spec file).
|
|
110
122
|
- **"I'm designing a domain model" / "How should I model X?" / building or
|
|
111
123
|
reshaping an Aggregate** → read `references/ddd-modeling-guide.md` (DDD
|
|
112
124
|
tactical patterns: aggregates, invariants, value objects, domain events). It
|
|
113
125
|
is written with Greenfield artifact names; see its **Edition note** for where
|
|
114
126
|
Brownfield records the same decisions (`models.md` / `rules.md` /
|
|
115
127
|
`behavior.md` / `migration/tech-debt.md`).
|
|
128
|
+
- **"Why does this rule exist?" / "This rule seems wrong"** → look the rule up in
|
|
129
|
+
`references/flow-rationale-registry.md`. Grep the rule id when you have one
|
|
130
|
+
(`grep -E '^R-FF-BRANCH-02:'`), otherwise a **short** fragment of the rule —
|
|
131
|
+
four to eight words, because the flow files are hard-wrapped and a longer
|
|
132
|
+
phrase spans a line break. A lookup may return two lines tagged `gf ·` / `bf ·`;
|
|
133
|
+
take this project's edition, which the workflow bundle's
|
|
134
|
+
`.dflow-bundle-manifest.json` records in its `edition` field. **Do not read
|
|
135
|
+
that file whole** — it is a lookup table, not a document.
|
|
116
136
|
- **"Turn the specs into HTML" / "make the specs easier to read"** → run the
|
|
117
137
|
CLI command `dflow render` (a human-readability tool, not a `/dflow:*`
|
|
118
138
|
workflow). It mirrors `dflow/specs/` into a browsable static HTML tree
|
|
@@ -121,10 +141,18 @@ input like this (supporting files live in the workflow bundle at
|
|
|
121
141
|
- **"Dflow seems wrong" / "this template is confusing"** (or you notice Dflow
|
|
122
142
|
guidance drift) → suggest `/dflow:report-dflow-feedback`; never submit
|
|
123
143
|
anything upstream automatically.
|
|
124
|
-
- **Anything else code-related** →
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
144
|
+
- **Anything else code-related** → run it through § Ceremony Scaling's ordered
|
|
145
|
+
cascade rather than a business-logic yes/no. Only the cascade's step 2 sends
|
|
146
|
+
work outside Dflow, and it is narrower than "not business logic": a display
|
|
147
|
+
typo, an appearance change, a machine-consumed contract edit, security / CVE
|
|
148
|
+
work and a deliberate runtime performance change are all tracked. If the
|
|
149
|
+
cascade lands the request anywhere at or above T3, suggest the matching
|
|
150
|
+
`/dflow:*` command and wait for confirmation (see § Workflow Transparency);
|
|
151
|
+
only if it lands below workflow, help directly with no ceremony. If step 0
|
|
152
|
+
takes it out of the cascade instead — observation-only work — it is neither:
|
|
153
|
+
say so and record it, do not treat "no tier" as "no ceremony". This applies
|
|
154
|
+
once you are already reading this guide — what makes a tool load it in the
|
|
155
|
+
first place is that tool's own trigger configuration, which is narrower.
|
|
128
156
|
|
|
129
157
|
## Status / Control Commands
|
|
130
158
|
|
|
@@ -250,6 +278,8 @@ Dflow-owned project documents live under `dflow/specs/`.
|
|
|
250
278
|
| System overview | `dflow/specs/shared/_overview.md` |
|
|
251
279
|
| Domain glossary | `dflow/specs/domain/glossary.md` |
|
|
252
280
|
| Context map | `dflow/specs/domain/context-map.md` |
|
|
281
|
+
| Domain analysis (cross-context) | `dflow/specs/domain/analysis.md` |
|
|
282
|
+
| Domain analysis (per context) | `dflow/specs/domain/{context}/analysis.md` |
|
|
253
283
|
| Active feature specs | `dflow/specs/features/active/` |
|
|
254
284
|
| Completed feature snapshots | `dflow/specs/features/completed/` |
|
|
255
285
|
| Technical debt | `dflow/specs/architecture/tech-debt.md` or `dflow/specs/migration/tech-debt.md` |
|
|
@@ -265,10 +295,13 @@ dflow/specs/
|
|
|
265
295
|
│ └── _conventions.md # Spec writing conventions
|
|
266
296
|
├── domain/ # Domain knowledge (DDD preparation)
|
|
267
297
|
│ ├── glossary.md # Ubiquitous Language
|
|
298
|
+
│ ├── context-map.md # Bounded Context relationships (created when needed)
|
|
299
|
+
│ ├── analysis.md # Cross-context flows and role reach
|
|
268
300
|
│ └── {bounded-context}/ # e.g., expense/, hr/, leave/
|
|
269
301
|
│ ├── context.md # Context boundary & responsibilities
|
|
270
302
|
│ ├── models.md # Entity, VO, Aggregate definitions
|
|
271
303
|
│ ├── rules.md # Business rules index (BR-ID + one-line)
|
|
304
|
+
│ ├── analysis.md # Lifecycles, derived figures, mechanisms
|
|
272
305
|
│ └── behavior.md # Consolidated behavior (Given/When/Then)
|
|
273
306
|
├── features/
|
|
274
307
|
│ ├── active/ # Currently in development
|
|
@@ -297,29 +330,112 @@ dflow/specs/
|
|
|
297
330
|
## Ceremony Scaling
|
|
298
331
|
|
|
299
332
|
Not everything needs full ceremony — match effort to impact. Dflow uses three
|
|
300
|
-
tiers — **T1 Heavy / T2 Light / T3 Trivial** —
|
|
301
|
-
`/dflow:new-feature` and `/dflow:new-phase`
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
333
|
+
tiers — **T1 Heavy / T2 Light / T3 Trivial** — plus a **below-workflow** level
|
|
334
|
+
Dflow doesn't track at all. `/dflow:new-feature` and `/dflow:new-phase` are
|
|
335
|
+
always T1 (no judgement). For `/dflow:modify-existing` and `/dflow:bug-fix`,
|
|
336
|
+
classify the change with the **ordered cascade — the first step that matches
|
|
337
|
+
wins** (order matters: a later catch-all would otherwise swallow the trivial and
|
|
338
|
+
below-workflow cases):
|
|
339
|
+
|
|
340
|
+
0. **Scope.** The cascade classifies a *modification*. Genuinely new work — a
|
|
341
|
+
new feature, page, or capability — is `/dflow:new-feature` (T1), even with no
|
|
342
|
+
new BR / Domain / schema. Adding a presentation or interaction control to an
|
|
343
|
+
**existing** surface (copy button, date-range filter, sort control, quick-view
|
|
344
|
+
drawer / tab, or filling a missing `aria-label`) is a *modification* (stays in
|
|
345
|
+
the cascade). A new user-executable domain operation (e.g. one-click return), a
|
|
346
|
+
new independently-consumable output or delivery channel (Download-PDF / export /
|
|
347
|
+
emailed report), or a **newly created** navigable surface (its own route and its
|
|
348
|
+
own content tree) **is** new-feature. Adding a menu entry or link that points at
|
|
349
|
+
a route that already exists is an access control on an existing surface —
|
|
350
|
+
a modification, not a new surface. **Unit of classification**: classify one
|
|
351
|
+
coherent requested change. Split a compound request into its atomic changes,
|
|
352
|
+
run each through the cascade, and let the highest tier govern the whole — each
|
|
353
|
+
lower-tier part still records its own artifact under the same host. Mechanical
|
|
354
|
+
fallout you did not ask for (formatter noise, lint churn) neither raises nor
|
|
355
|
+
lowers the result.
|
|
356
|
+
**Observation-only work is also outside the
|
|
357
|
+
cascade**: capturing existing behaviour as a baseline (Brownfield) changes no
|
|
358
|
+
output, so it carries no tier at all — record it and do not read step 2's
|
|
359
|
+
"below workflow" as permission to skip the record.
|
|
360
|
+
1. **T1 — Heavy.** A **new** business rule or normative constraint (permission /
|
|
361
|
+
eligibility / threshold / approval / required outcome — regardless of whether a
|
|
362
|
+
BR-ID already exists). *New* means a rule that can be stated and broken on its
|
|
363
|
+
own: take the change away and the original rule still works exactly as before.
|
|
364
|
+
Changing an existing rule's parameters is **T2** — a different threshold value,
|
|
365
|
+
or adding to a set the rule already checks (one more allowed country, one more
|
|
366
|
+
approver role). Adding an independent condition the rule never had (an approver
|
|
367
|
+
predicate for a specific payment channel) is a new rule, and T1. A Domain concept (Aggregate / Entity / VO / Event)
|
|
368
|
+
**added or structurally changed** (identity, VO equality components, aggregate
|
|
369
|
+
boundary, or removing / renaming / redefining a spec-tracked member — a Domain
|
|
370
|
+
concept **rename** is T1); a persistent **data-structure** change (table /
|
|
371
|
+
column / relation / index added, removed, renamed, or its type / nullability /
|
|
372
|
+
constraint / logical definition changed); an **architectural** change
|
|
373
|
+
(inter-layer dependency direction, deployment / module boundary, runtime /
|
|
374
|
+
platform ownership, or overturning an architecture decision — behavior-
|
|
375
|
+
preserving still counts); or a **breaking** cross-consumer contract (API /
|
|
376
|
+
event). Contracts run **inbound** too — a required env var / deployment config
|
|
377
|
+
key, a CLI flag, an exit code, a scheduled-automation calling convention. What
|
|
378
|
+
breaks a caller is T1: removing or renaming one, changing what one means, or
|
|
379
|
+
adding a **required** key with no backward-compatible default (deployments must
|
|
380
|
+
act) — making an existing operation's parameter **required** breaks callers the
|
|
381
|
+
same way. Adding an *optional* key or parameter with a backward-compatible
|
|
382
|
+
default is non-breaking — T2 via step 4.
|
|
383
|
+
2. **Below workflow — not tracked.** No audience-perceivable output delta **and**
|
|
384
|
+
no machine-consumed-contract or operational-semantics touch: auto-formatter
|
|
385
|
+
runs, whitespace, internal comments, internal-doc typos, commit messages, and
|
|
386
|
+
behavior-preserving **routine** refactors / dependency bumps. **Routine** =
|
|
387
|
+
touches no operational-semantics axis (security / safety / resilience /
|
|
388
|
+
compliance / payment) and is not architectural — **breadth is not the test** (a
|
|
389
|
+
behavior-preserving refactor across hundreds of call sites is still below
|
|
390
|
+
workflow; a single-file change that touches an operational axis is not). Never
|
|
391
|
+
below workflow, even when invisible: any BR-ID delta, any machine-consumed
|
|
392
|
+
structured-log / export / contract change, any deliberate runtime performance /
|
|
393
|
+
resource / SLA change, or any security / CVE / compliance work — those reach
|
|
394
|
+
step 1 or 4 by audience. `git commit` directly.
|
|
395
|
+
3. **T3 — Trivial.** A **local, low-risk, meaning-preserving pure copy or
|
|
396
|
+
appearance change a product audience perceives** — display-text typo / wording
|
|
397
|
+
polish, colour, spacing, layout polish, or polishing existing alt / ARIA
|
|
398
|
+
wording — on a **single screen / component or single independently-consumed
|
|
399
|
+
page / file**, at the **element level**. **Excluded from T3**: high-consequence
|
|
400
|
+
content (security warnings, password hints, consent, payment / legal notices);
|
|
401
|
+
meaning-changing appearance (danger / status-colour semantics); anything
|
|
402
|
+
affecting operability, default state, interaction order, or task completion
|
|
403
|
+
("just CSS" is no exemption); adding a **missing** accessible name (compliance
|
|
404
|
+
remediation); and text a machine consumes — an API error string or code a client
|
|
405
|
+
parses is contract, not display copy, so it is never T3: route it by the contract
|
|
406
|
+
axis instead (breaks the consumer → step 1, T1; otherwise → step 4, T2). **Locality is
|
|
407
|
+
the rendered audience footprint, not the number of source files**: one shared
|
|
408
|
+
component or localization key whose output appears on several screens is beyond
|
|
409
|
+
the local unit (T2), while edits to several files that surface in one place stay
|
|
410
|
+
T3. Anything beyond that unit is T2 — a typo swept across many screens, a
|
|
411
|
+
whole-screen visual rewrite, a cross-page sweep. The limit follows the whole
|
|
412
|
+
intent, so splitting one cross-screen typo sweep into per-screen requests does
|
|
413
|
+
not turn it into several T3s.
|
|
414
|
+
4. **T2 — Light (catch-all — everything else).** Functional / semantic behavior
|
|
415
|
+
delta (logic, validation, interaction flow, display calculation, an
|
|
416
|
+
**existing** BR's delta, non-breaking contract semantics); performance-only
|
|
417
|
+
changes (perceivable or not); and copy / appearance sweeps escalated from step
|
|
418
|
+
3. Functional bug fixes are T2 (root-cause + regression notes).
|
|
419
|
+
|
|
420
|
+
| Tier | Output | Command / Trigger |
|
|
421
|
+
|---|---|---|
|
|
422
|
+
| **T1 Heavy** | Independent `phase-spec-YYYY-MM-DD-{slug}.md` placed in the feature directory + `_index.md` Phase Specs row + refresh BR Snapshot | `/dflow:new-feature` / `/dflow:new-phase` — also where a `/dflow:modify-existing` or `/dflow:bug-fix` request goes when the cascade lands it at T1 |
|
|
423
|
+
| **T2 Light** | Independent `lightweight-YYYY-MM-DD-{slug}.md` (or `BUG-{NUMBER}-{slug}.md`) inside the feature directory + `_index.md` Lightweight Changes row (outbound link) + refresh BR Snapshot | `/dflow:modify-existing` or `/dflow:bug-fix` — the usual landing for a functional defect |
|
|
424
|
+
| **T3 Trivial** | **Inline row in the host `_index.md` Lightweight Changes only** (no independent spec file) | `/dflow:modify-existing` or `/dflow:bug-fix` (`_index`-only branch — e.g. a defect that is only a display-text typo) |
|
|
425
|
+
|
|
426
|
+
**Audience** = any human audience of the product perceives the output: UI
|
|
427
|
+
(including alt / ARIA read by assistive tech), email, exports. Public / adopter-
|
|
428
|
+
facing docs (product README, public API reference) and operator surfaces
|
|
429
|
+
(dashboard labels, alerts) are product-audience: pure wording = T3 (single page;
|
|
430
|
+
a cross-page sweep escalates to T2 at step 3), meaning change = T2. Raw internal
|
|
431
|
+
diagnostic logs / traces are internal (copy-only fixes are below workflow).
|
|
432
|
+
Structured logs / machine-readable exports a downstream consumer depends on are
|
|
433
|
+
contract: breaking cross-consumer = step 1 T1, non-breaking = step 4 T2.
|
|
434
|
+
|
|
435
|
+
**Project conventions can only escalate.** `_conventions.md` Ceremony (Project
|
|
436
|
+
Application) rows are a floor-raising overlay applied *after* the cascade: a
|
|
437
|
+
project may push a T2 up to T1, but may not lower a cascade T1, nor drop a
|
|
438
|
+
tracked class below workflow.
|
|
323
439
|
|
|
324
440
|
**Lightweight spec** = Problem + Expected behavior + 1–2 Given/When/Then. The
|
|
325
441
|
instantiated file is placed inside the feature directory (see
|
|
@@ -393,7 +509,8 @@ during the completion checklist, not via template section markers.
|
|
|
393
509
|
- Did we discover scattered business logic? → Record in tech-debt.md
|
|
394
510
|
- Are there duplicated calculations? → Record
|
|
395
511
|
- Direct SQL in delivery/entrypoint code? → Record
|
|
396
|
-
- Magic numbers
|
|
512
|
+
- Magic numbers? → Record and add to glossary
|
|
513
|
+
- Undocumented status values? → List them in their field's lifecycle in `analysis.md`
|
|
397
514
|
|
|
398
515
|
## Workflow Steps
|
|
399
516
|
|
|
@@ -411,7 +528,7 @@ directory first. For example:
|
|
|
411
528
|
|---|---|
|
|
412
529
|
| `/dflow:new-feature` | `dflow/specs/shared/dflow-workflows/references/new-feature-flow.md` |
|
|
413
530
|
| `/dflow:modify-existing` | `dflow/specs/shared/dflow-workflows/references/modify-existing-flow.md` |
|
|
414
|
-
| `/dflow:bug-fix` | `dflow/specs/shared/dflow-workflows/references/modify-existing-flow.md` (
|
|
531
|
+
| `/dflow:bug-fix` | `dflow/specs/shared/dflow-workflows/references/modify-existing-flow.md` (same flow; tier comes from the cascade, not from the command) |
|
|
415
532
|
| `/dflow:new-phase` | `dflow/specs/shared/dflow-workflows/references/new-phase-flow.md` |
|
|
416
533
|
| `/dflow:finish-feature` | `dflow/specs/shared/dflow-workflows/references/finish-feature-flow.md` |
|
|
417
534
|
| `/dflow:verify` | `dflow/specs/shared/dflow-workflows/references/drift-verification.md` |
|