dflow-sdd-ddd 0.13.0 → 0.15.0

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