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.
- package/assets/.appweaver/DESIGN-FORMAT.md +17 -9
- package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +4 -2
- package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +1 -1
- package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +4 -2
- package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +1 -1
- package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +121 -42
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +38 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +41 -8
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-deploy.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +26 -16
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +31 -9
- package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +217 -174
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +405 -105
- package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +49 -11
- package/assets/.appweaver/orchestrator/workflows/aw-spec-recall-delta.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-feature.orch.yaml +29 -23
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +18 -10
- package/assets/.appweaver/scripts/bash/aw-inventory.sh +15 -0
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +32 -16
- package/assets/.appweaver/scripts/bash/aw-xref.sh +3 -0
- package/assets/.appweaver/scripts/powershell/aw-inventory.ps1 +15 -0
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +25 -5
- package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +3 -0
- package/assets/.appweaver/scripts/python/aw-inventory.py +1829 -63
- package/assets/.appweaver/scripts/python/aw-xref.py +500 -81
- package/assets/.appweaver/templates/delta-design-template.md +1 -1
- package/assets/.appweaver/templates/delta-domain-model-template.md +1 -1
- package/assets/.appweaver/templates/delta-spec-template.md +4 -3
- package/assets/.appweaver/templates/design-template.md +16 -11
- package/assets/.appweaver/templates/okf-concept-template.md +11 -1
- package/assets/.appweaver/templates/proposed-inventory-template.md +127 -0
- package/assets/.appweaver/templates/source-map-template.md +5 -3
- package/assets/.appweaver/templates/spec-template.md +17 -17
- package/assets/.appweaver/templates/ui-delta-design-template.md +1 -1
- package/assets/.appweaver/templates/ui-design-template.md +4 -4
- package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +4489 -361
- package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +2274 -125
- 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
|
|
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 —
|
|
320
|
-
|
|
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
|
|
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
|
|
339
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
180
|
-
#
|
|
181
|
-
#
|
|
182
|
-
#
|
|
183
|
-
# a behaviour-only change, which falls back to the
|
|
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
|
|
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
|
|
704
|
-
#
|
|
705
|
-
#
|
|
706
|
-
#
|
|
707
|
-
#
|
|
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
|
|
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: "{{
|
|
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
|
|
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
|
|
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.
|
|
674
|
-
any other `## Aggregate:` section
|
|
675
|
-
|
|
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
|
-
-
|
|
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
|
|
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
|
|
1123
|
-
|
|
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
|