aw-spec-cli 0.1.19 → 0.1.20

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 (46) hide show
  1. package/assets/.appweaver/DESIGN-FORMAT.md +17 -9
  2. package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +4 -2
  3. package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +1 -1
  4. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +4 -2
  5. package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +1 -1
  6. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +1 -1
  7. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +121 -42
  8. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +1 -1
  9. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +38 -4
  10. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +1 -1
  11. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +41 -8
  12. package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +1 -1
  13. package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +1 -1
  14. package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +1 -1
  15. package/assets/.appweaver/orchestrator/workflows/aw-spec-deploy.orch.yaml +1 -1
  16. package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +26 -16
  17. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +31 -9
  18. package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +217 -174
  19. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +405 -105
  20. package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +1 -1
  21. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +49 -11
  22. package/assets/.appweaver/orchestrator/workflows/aw-spec-recall-delta.orch.yaml +1 -1
  23. package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +1 -1
  24. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-feature.orch.yaml +29 -23
  25. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +18 -10
  26. package/assets/.appweaver/scripts/bash/aw-inventory.sh +15 -0
  27. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +32 -16
  28. package/assets/.appweaver/scripts/bash/aw-xref.sh +3 -0
  29. package/assets/.appweaver/scripts/powershell/aw-inventory.ps1 +15 -0
  30. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +25 -5
  31. package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +3 -0
  32. package/assets/.appweaver/scripts/python/aw-inventory.py +1829 -63
  33. package/assets/.appweaver/scripts/python/aw-xref.py +500 -81
  34. package/assets/.appweaver/templates/delta-design-template.md +1 -1
  35. package/assets/.appweaver/templates/delta-domain-model-template.md +1 -1
  36. package/assets/.appweaver/templates/delta-spec-template.md +4 -3
  37. package/assets/.appweaver/templates/design-template.md +16 -11
  38. package/assets/.appweaver/templates/okf-concept-template.md +11 -1
  39. package/assets/.appweaver/templates/proposed-inventory-template.md +127 -0
  40. package/assets/.appweaver/templates/source-map-template.md +5 -3
  41. package/assets/.appweaver/templates/spec-template.md +17 -17
  42. package/assets/.appweaver/templates/ui-delta-design-template.md +1 -1
  43. package/assets/.appweaver/templates/ui-design-template.md +4 -4
  44. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +4489 -361
  45. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +2274 -125
  46. package/package.json +1 -1
@@ -136,7 +136,7 @@ workflow:
136
136
  action: verify_context
137
137
  require_non_empty: feature_dir
138
138
  on_empty: stop
139
- on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the aggregate, e.g. Order), then re-run analyze-slice."
139
+ on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the feature, e.g. Order or PatientRegistration), then re-run analyze-slice."
140
140
 
141
141
  # The bounded context's DOMAIN MODEL — in every pass's context beside the spec, and the
142
142
  # authority the conformance pass scores against. Since the model split the spec no longer
@@ -162,6 +162,38 @@ workflow:
162
162
  - { name: domain_model, from: "$.domain_model" }
163
163
  - { name: domain_model_exists, from: "$.domain_model_exists" }
164
164
 
165
+ # WHICH PART OF THAT MODEL THIS GATE SCORES. The model is filed by aggregate, the specs
166
+ # tree by feature. For a feature that is one capability over a shared aggregate
167
+ # (PatientRegistration over Patient) no section carries the feature's name, and scoring
168
+ # "the BR-nnn under this feature's section" found none and PASSED — every invariant the
169
+ # feature relies on silently demoted to a non-blocking note. Resolved from the spec's
170
+ # Acts-on line, then the boundary map, then the feature name.
171
+ - id: feature_aggregates
172
+ action: execute_script
173
+ script: { ref: xref }
174
+ subcommand: feature-aggregates
175
+ args: ["--feature-dir", "{{feature_dir}}"]
176
+ outputs:
177
+ - { name: owned_sections, from: "$.owned_sections" }
178
+ - { name: one_to_one, from: "$.one_to_one" }
179
+
180
+ # WHICH OF THOSE INVARIANTS BLOCK. A feature that alone answers for an aggregate owns
181
+ # its section outright, and every BR-nnn under it has to be enforced in this code. A
182
+ # feature that shares the aggregate with other features — whatever it is named —
183
+ # answers only for what its spec cites: the rest of that section is the other features'
184
+ # code, and blocking on it would fail each of them for work another one does. The
185
+ # engine has no conditional prompt text, so the rule is chosen by an ordered pair of
186
+ # sets and handed to the pass as one sentence.
187
+ - id: model_scope_capability
188
+ action: set
189
+ vars:
190
+ model_scope_rule: "this feature SHARES those sections with other features, so BLOCKING covers only the BR-nnn this feature's spec CITES from them; any other BR-nnn stated there belongs to another feature and is a model_notes entry, not a violation"
191
+ - id: model_scope_owned
192
+ condition: "{{one_to_one}} == true"
193
+ action: set
194
+ vars:
195
+ model_scope_rule: "this feature is the ONLY one that answers for that section, so BLOCKING covers EVERY BR-nnn stated there, whether or not the spec cites it"
196
+
165
197
  # Is a change OPEN on this feature? Read for NAVIGATION only — see the vars note. Safe
166
198
  # on the bootstrap path: with no active_version.json, version-read returns
167
199
  # active_change="" / has_change=false and exits 0, so nothing here is conditional on it.
@@ -316,8 +348,9 @@ workflow:
316
348
  authority on what the domain IS. The spec cites invariants by id; this document
317
349
  states them. It describes the WHOLE context while this gate scores ONE feature,
318
350
  so scope matters:
319
- • BLOCKING — every BR-nnn stated under `## Aggregate: {{feature}}`, the section
320
- this slice owns. The rule has to be enforced somewhere in this code, and the
351
+ • BLOCKING — the invariants of the section(s) this feature answers for,
352
+ {{owned_sections}}: {{model_scope_rule}}. Each blocking rule has to be
353
+ enforced somewhere in this code, and the
321
354
  enforcement has to say what the model says. An owned invariant with no
322
355
  enforcement, or one enforced with a different threshold, condition or
323
356
  direction than the model states, is a `violations` entry with the BR id as
@@ -326,7 +359,7 @@ workflow:
326
359
  • BLOCKING — the ubiquitous language of that same section. An entity, field or
327
360
  state the code names differently from the model is a violation; the model's
328
361
  name is the right one.
329
- • NOT BLOCKING — anything the model states under ANOTHER aggregate's section.
362
+ • NOT BLOCKING — anything the model states under any section not named above.
330
363
  This slice does not own those and often should not enforce them. Report each
331
364
  one this code appears to touch as a `model_notes` entry, naming the owning
332
365
  aggregate, and carry on.
@@ -335,8 +368,8 @@ workflow:
335
368
  invariant's text from its id, and never treat a rule the model does not state
336
369
  as one.
337
370
 
338
- ok=true ONLY when no checklist rule is violated AND no invariant this aggregate
339
- owns is unenforced or contradicted. `model_notes` never affects ok.
371
+ ok=true ONLY when no checklist rule is violated AND no BLOCKING invariant above
372
+ is unenforced or contradicted. `model_notes` never affects ok.
340
373
  outputs:
341
374
  - { name: conformance_ok, from: "$.ok" }
342
375
  - { name: conformance_violations, from: "$.violations" }
@@ -352,8 +385,8 @@ workflow:
352
385
  Fix these domain-conformance violations in the feature's code (in context),
353
386
  keeping the design's behaviour intact. A violation whose `rule` is an overlay
354
387
  rule is fixed against the gate checklist in the standards; one whose `rule` is a
355
- BR-nnn is fixed against the text domain-model.md states for it under
356
- `## Aggregate: {{feature}}` — enforce what the model says, where the code
388
+ BR-nnn is fixed against the text domain-model.md states for it under its section
389
+ among {{owned_sections}} — enforce what the model says, where the code
357
390
  already owns that decision, and name entities and fields the way the model names
358
391
  them. Do NOT weaken or delete a test to hide a violation, and do NOT edit
359
392
  domain-model.md or the spec to match the code: this is a gate on the code, and a
@@ -82,7 +82,7 @@ workflow:
82
82
  action: verify_context
83
83
  require_non_empty: feature_dir
84
84
  on_empty: stop
85
- on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the aggregate, e.g. Order), then re-run build."
85
+ on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the feature, e.g. Order or PatientRegistration), then re-run build."
86
86
 
87
87
  # Require A LANE — not a KIND of lane. build-compile runs EVERY declared lane's own
88
88
  # build command, so a two-lane project compiles both (the case the old first-match-wins
@@ -106,7 +106,7 @@ workflow:
106
106
  action: verify_context
107
107
  require_non_empty: feature_dir
108
108
  on_empty: stop
109
- on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the aggregate, e.g. Order), then re-run characterize."
109
+ on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the feature, e.g. Order or PatientRegistration), then re-run characterize."
110
110
 
111
111
  - id: verify_spec
112
112
  action: verify_context
@@ -136,7 +136,7 @@ workflow:
136
136
  action: verify_context
137
137
  require_non_empty: feature_dir
138
138
  on_empty: stop
139
- on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the aggregate, e.g. Order), then re-run close-delta."
139
+ on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the feature, e.g. Order or PatientRegistration), then re-run close-delta."
140
140
 
141
141
  # 2. WHICH CHANGE IS BEING CLOSED. The evidence is changes/<CR-id>/ on disk; a change
142
142
  # already closed has moved to changes/archive/. On the BOOTSTRAP path (implement →
@@ -36,7 +36,7 @@ workflow:
36
36
  action: verify_context
37
37
  require_non_empty: feature_dir
38
38
  on_empty: stop
39
- on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the aggregate, e.g. Order), then re-run deploy."
39
+ on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the feature, e.g. Order or PatientRegistration), then re-run deploy."
40
40
 
41
41
  # Pre-deploy hooks (e.g. a final smoke/build gate configured by the project).
42
42
  - id: resolve_pre_hooks
@@ -176,11 +176,12 @@ vars:
176
176
  merge_wave: "1"
177
177
  snapshot_dir: "" # changes/<id>/pre-merge/ — the before-image recall-delta restores
178
178
  snapshot_count: "0"
179
- # THE OKF OVERVIEW'S SUBJECT. The kit's working assumption is feature == aggregate; the
180
- # Overview step is the one place it is load-bearing rather than cosmetic, because it
181
- # selects a `## Aggregate:` section BY NAME. delta_aggregates is what the change's own
182
- # model delta declares, so the common case is exact rather than assumed; it is empty for
183
- # a behaviour-only change, which falls back to the feature name.
179
+ # THE OKF OVERVIEW'S SUBJECT. The Overview step selects a `## Aggregate:` section BY
180
+ # NAME, so it needs the aggregate, which is not always the feature: a feature that is
181
+ # one capability over a shared aggregate (PatientRegistration over Patient) has no
182
+ # section of its own name. delta_aggregates is what the change's own model delta
183
+ # declares; it is empty for a behaviour-only change, which falls back to the aggregate
184
+ # the feature answers for (feature-aggregates — the spec's Acts-on line).
184
185
  delta_aggregates: ""
185
186
  overview_scope: ""
186
187
  overview_section_ok: "false"
@@ -211,7 +212,7 @@ workflow:
211
212
  action: verify_context
212
213
  require_non_empty: feature_dir
213
214
  on_empty: stop
214
- on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the aggregate, e.g. Order), then re-run finalize-delta."
215
+ on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the feature, e.g. Order or PatientRegistration), then re-run finalize-delta."
215
216
 
216
217
  - id: verify_spec
217
218
  action: verify_context
@@ -700,16 +701,15 @@ workflow:
700
701
  # the context has no model: there would be nothing in context to distil, and a
701
702
  # query with no source invents one. Best-effort; an empty answer is a no-op.
702
703
  # WHICH AGGREGATE SECTION(S) THIS CHANGE ACTUALLY TOUCHED, read off the model delta's
703
- # own `## Aggregate:` headings rather than assumed from the feature name. The kit's
704
- # working assumption is feature == aggregate, and it holds today — but the Overview step
705
- # below is the one place that assumption is LOAD-BEARING rather than cosmetic: it selects
706
- # a section by name, and a feature whose name is not an aggregate name selects nothing,
707
- # producing an empty answer that the writer then declines. Driving it off the delta's
708
- # declared aggregates makes the common case exact and the uncommon case visible.
704
+ # own `## Aggregate:` headings rather than assumed from the feature name. The Overview
705
+ # step below selects a section by name, and a feature whose name is not an aggregate
706
+ # name — one capability over a shared aggregate — selects nothing, producing an empty
707
+ # answer that the writer then declines. Driving it off the delta's declared aggregates
708
+ # makes a model change exact.
709
709
  #
710
710
  # A BEHAVIOUR-ONLY CHANGE HAS NO MODEL DELTA, so this reports none and the step falls
711
- # back to the feature name — which is correct, not a degradation: there is no model
712
- # change to distil and the concept's existing Overview stands.
711
+ # back to the aggregate the feature answers for — which is correct, not a degradation:
712
+ # there is no model change to distil and the concept's existing Overview stands.
713
713
  - id: cr_aggregates
714
714
  action: execute_script
715
715
  on_error: continue # informational — a missing model delta is the ordinary case
@@ -720,9 +720,19 @@ workflow:
720
720
  - { name: delta_aggregates, from: "$.aggregates_csv" }
721
721
  - { name: delta_aggregate_list, from: "$.aggregates" }
722
722
 
723
+ # The fallback subject: the aggregate this feature answers for, which is the feature
724
+ # itself on a 1:1 slice and the shared aggregate on a capability over one.
725
+ - id: feature_aggregates
726
+ action: execute_script
727
+ script: { ref: xref }
728
+ subcommand: feature-aggregates
729
+ args: ["--feature-dir", "{{feature_dir}}"]
730
+ outputs:
731
+ - { name: owned_csv, from: "$.owned_csv" }
732
+
723
733
  - id: overview_scope_feature
724
734
  action: set
725
- vars: { overview_scope: "{{feature}}" }
735
+ vars: { overview_scope: "{{owned_csv}}" }
726
736
  - id: overview_scope_delta
727
737
  condition: "{{delta_aggregates}} != "
728
738
  action: set
@@ -823,4 +833,4 @@ outputs:
823
833
  model_merged: "{{delta_model_exists}}" # true ⇒ domain-model.md was the second target of this merge.
824
834
  # false = a behaviour-only change: the spec merge was the
825
835
  # whole merge, not a half of one.
826
- next: "Delta MERGED into spec.md, and into the context's domain-model.md one aggregate section at a time where the change carried a model delta (model_merged={{delta_model_exists}} — false means a behaviour-only change, so the spec merge was the whole merge). The lane plans were NOT touched — they are DERIVED from these two masters, so backend-plan.md / frontend-plan.md now stand BEHIND the spec and model at their last authored content. That drift starts here and lasts until /appweaver plan main re-derives them, carrying the recorded decisions (DA-n) and workarounds (WA-n) forward and rewriting what the spec and model no longer support. analyze-plan is not what closes it and cannot repair it while this change is open: with a change open it runs READ-ONLY, reporting the drift into plan-analyze-report.md without rewriting either plan. The full gate — check, repair, stop — comes back once the last change is closed, so the order is close-delta, then plan main, then analyze-plan. OKF edges reconciled ({{xref_edge_count}} dep(s)), {{downstream_count}} downstream slice(s) fenced (gate: {{gate_decision}}). The concept Overview was distilled for aggregate(s) `{{overview_scope}}` — taken from what this change's model delta DECLARES it touched, not assumed from the feature name (empty on a behaviour-only change, which falls back to the feature). section_found={{overview_section_ok}}, written={{overview_written}}{{overview_reason}} — written=false is normal for a behaviour-only change (nothing to distil, the existing Overview stands), but section_found=false means domain-model.md has no `## Aggregate:` section under that name and the concept's Overview was left as it was: check that the feature name matches the aggregate the model defines. Change {{active_change}} is STILL OPEN and the version is still {{version}}. Next: /appweaver analyze-slice — it now reads masters that carry this change, and a red result is still recoverable because nothing has been archived. Then /appweaver close-delta archives the change and bumps the version."
836
+ next: "Delta MERGED into spec.md, and into the context's domain-model.md one aggregate section at a time where the change carried a model delta (model_merged={{delta_model_exists}} — false means a behaviour-only change, so the spec merge was the whole merge). The lane plans were NOT touched — they are DERIVED from these two masters, so backend-plan.md / frontend-plan.md now stand BEHIND the spec and model at their last authored content. That drift starts here and lasts until /appweaver plan main re-derives them, carrying the recorded decisions (DA-n) and workarounds (WA-n) forward and rewriting what the spec and model no longer support. analyze-plan is not what closes it and cannot repair it while this change is open: with a change open it runs READ-ONLY, reporting the drift into plan-analyze-report.md without rewriting either plan. The full gate — check, repair, stop — comes back once the last change is closed, so the order is close-delta, then plan main, then analyze-plan. OKF edges reconciled ({{xref_edge_count}} dep(s)), {{downstream_count}} downstream slice(s) fenced (gate: {{gate_decision}}). The concept Overview was distilled for aggregate(s) `{{overview_scope}}` — taken from what this change's model delta DECLARES it touched, not assumed from the feature name (empty on a behaviour-only change, which falls back to the aggregate the feature answers for). section_found={{overview_section_ok}}, written={{overview_written}}{{overview_reason}} — written=false is normal for a behaviour-only change (nothing to distil, the existing Overview stands), but section_found=false means domain-model.md has no `## Aggregate:` section under that name and the concept's Overview was left as it was: check that the spec's Acts on aggregate(s) line names an aggregate the model defines. Change {{active_change}} is STILL OPEN and the version is still {{version}}. Next: /appweaver analyze-slice — it now reads masters that carry this change, and a red result is still recoverable because nothing has been archived. Then /appweaver close-delta archives the change and bumps the version."
@@ -293,7 +293,7 @@ workflow:
293
293
  action: verify_context
294
294
  require_non_empty: feature_dir
295
295
  on_empty: stop
296
- on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the aggregate, e.g. Order), then re-run implement."
296
+ on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the feature, e.g. Order or PatientRegistration), then re-run implement."
297
297
 
298
298
  # The bounded context's DOMAIN MODEL — in every generating lane's payload as the authority
299
299
  # on what the plan's cited BR-nnn actually require and on the ubiquitous language, and the
@@ -309,6 +309,21 @@ workflow:
309
309
  - { name: domain_model, from: "$.domain_model" }
310
310
  - { name: domain_model_exists, from: "$.domain_model_exists" }
311
311
 
312
+ # WHICH PART OF THAT MODEL IS THIS FEATURE'S. The model is filed by aggregate, the specs
313
+ # tree by feature, and the two names differ for a feature that is one capability over a
314
+ # shared aggregate (PatientRegistration over Patient) — reading the model by the
315
+ # feature's name finds no section there. Resolved from the spec's Acts-on line, then the
316
+ # boundary map, then the feature name, so a 1:1 feature resolves to exactly the section
317
+ # this workflow always read.
318
+ - id: feature_aggregates
319
+ action: execute_script
320
+ script: { ref: xref }
321
+ subcommand: feature-aggregates
322
+ args: ["--feature-dir", "{{feature_dir}}"]
323
+ outputs:
324
+ - { name: owned_csv, from: "$.owned_csv" }
325
+ - { name: owned_sections, from: "$.owned_sections" }
326
+
312
327
  # 2. WHICH CHANGES ARE OPEN — the evidence is changes/<CR-id>/ on disk; a closed change
313
328
  # has moved to changes/archive/. Any open change makes this run a DELTA run.
314
329
  # `matched_label` resolves a CR id passed as the argument to the whole option string,
@@ -670,9 +685,9 @@ workflow:
670
685
  - THE MODEL IS READ, NEVER MINED FOR WORK. It describes the WHOLE bounded context,
671
686
  while this run builds one feature. Realise only what the PLAN calls for: an entity,
672
687
  event or invariant in the model that no plan element realises is a PLANNING gap —
673
- surface it, do not implement it. `{{feature}}` is the aggregate this feature owns;
674
- any other `## Aggregate:` section belongs to another slice, and you read it only to
675
- honour a reference the plan makes, never to generate its code.
688
+ surface it, do not implement it. The section(s) this feature answers for are
689
+ {{owned_sections}}; any other `## Aggregate:` section you read only to honour a
690
+ reference the plan makes, never to generate its code.
676
691
  - BIND THE STACK: this lane is `{{be_lane_id}}` — {{be_title}}, language
677
692
  {{be_language}} ({{be_ecosystem}}), declared in .appweaver/stacks.json and compiled
678
693
  with `{{be_build}}`, tested with `{{be_test}}`. Generate in THAT language and
@@ -715,7 +730,14 @@ workflow:
715
730
  - Do NOT add behaviour the plan does not state, and do NOT omit any it does. If the
716
731
  plan looks wrong or incomplete, STOP and surface it (it is fixed in plan /
717
732
  analyze-plan) — never compensate from the spec or from memory.
718
- - This aggregate OWNS its files; never regenerate a file another feature owns.
733
+ - SHARED AGGREGATE FILES ARE EXTENDED, NEVER REGENERATED. A feature is a capability
734
+ scope, and other features may act on the same aggregate: its root, entities,
735
+ value objects and repository are shared code. Where such a file already exists,
736
+ ADD only the members this plan needs and leave every existing member, signature
737
+ and test exactly as it is — another feature's code depends on them. Create a file
738
+ only when it does not exist yet. A file that serves only another feature (its
739
+ use-case, endpoint or handler) is not this feature's to touch; if this plan needs
740
+ one changed, STOP and surface it.
719
741
  - Where generated code depends on a plan Assumption (DA-n) or Workaround (WA-n), mark
720
742
  it with a comment citing that id so it is easy to revisit later.
721
743
  outputs:
@@ -1112,15 +1134,15 @@ workflow:
1112
1134
  schema: { overview: "<2-4 sentences of prose>" }
1113
1135
  mock: { overview: "" }
1114
1136
  task: |
1115
- Write the OKF knowledge-concept Overview for the aggregate `{{feature}}`. 2-4
1116
- sentences of PROSE:
1137
+ Write the OKF knowledge-concept Overview for the feature `{{feature}}` — that is,
1138
+ for the aggregate it answers for, {{owned_csv}}. 2-4 sentences of PROSE:
1117
1139
  - name the aggregate ROOT and what the aggregate IS;
1118
1140
  - state the INVARIANTS it guards (its BR-nnn — what they require, not their ids);
1119
1141
  - state its TRANSACTION BOUNDARY — what it OWNS inside the boundary vs what it only
1120
1142
  REFERENCES by id.
1121
1143
  The bounded context's domain-model.md is the source where it is in context: read
1122
- ONLY its `## Aggregate: {{feature}}` section — the other aggregates are other
1123
- slices' concepts. Where it is not in context, distil the same three things from
1144
+ ONLY {{owned_sections}} — the other sections belong to other aggregates. Where more
1145
+ than one is named, describe the FIRST. Where it is not in context, distil the same three things from
1124
1146
  backend-plan.md's domain section instead.
1125
1147
  Plain prose only: no headings, no bullets, no code fences, no file paths, and no
1126
1148
  restating of the dependency edges (those live in the Depends-On / Cross-References