aw-spec-cli 0.1.18 → 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 (77) hide show
  1. package/assets/.appweaver/DESIGN-FORMAT.md +63 -31
  2. package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +62 -14
  3. package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +10 -6
  4. package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +9 -1
  5. package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +21 -0
  6. package/assets/.appweaver/orchestrator/orchestrator.py +23 -1
  7. package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +1 -1
  8. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +22 -13
  9. package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +1 -1
  10. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +6 -4
  11. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +399 -131
  12. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +1 -1
  13. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +199 -38
  14. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +1 -1
  15. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +159 -25
  16. package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +20 -9
  17. package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +1 -1
  18. package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +183 -40
  19. package/assets/.appweaver/orchestrator/workflows/aw-spec-deploy.orch.yaml +1 -1
  20. package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +311 -36
  21. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +221 -40
  22. package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +217 -174
  23. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +494 -109
  24. package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +1 -1
  25. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +83 -18
  26. package/assets/.appweaver/orchestrator/workflows/aw-spec-recall-delta.orch.yaml +319 -0
  27. package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +1 -1
  28. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-feature.orch.yaml +29 -23
  29. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +143 -34
  30. package/assets/.appweaver/scripts/bash/aw-inventory.sh +15 -0
  31. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +878 -51
  32. package/assets/.appweaver/scripts/bash/aw-xref.sh +3 -0
  33. package/assets/.appweaver/scripts/bash/common.sh +28 -1
  34. package/assets/.appweaver/scripts/powershell/aw-inventory.ps1 +15 -0
  35. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +868 -51
  36. package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +3 -0
  37. package/assets/.appweaver/scripts/python/aw-inventory.py +1832 -65
  38. package/assets/.appweaver/scripts/python/aw-xref.py +500 -81
  39. package/assets/.appweaver/templates/delta-design-template.md +1 -1
  40. package/assets/.appweaver/templates/delta-domain-model-template.md +1 -1
  41. package/assets/.appweaver/templates/delta-spec-template.md +4 -3
  42. package/assets/.appweaver/templates/design-template.md +56 -40
  43. package/assets/.appweaver/templates/okf-concept-template.md +11 -1
  44. package/assets/.appweaver/templates/proposed-inventory-template.md +127 -0
  45. package/assets/.appweaver/templates/source-map-template.md +5 -3
  46. package/assets/.appweaver/templates/spec-template.md +24 -21
  47. package/assets/.appweaver/templates/ui-delta-design-template.md +1 -1
  48. package/assets/.appweaver/templates/ui-design-template.md +11 -7
  49. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +4489 -361
  50. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +2274 -125
  51. package/assets/guardrails/domain/healthcare/auditing.domain.md +3 -3
  52. package/assets/guardrails/domain/pharma/auditing.domain.md +3 -3
  53. package/assets/guardrails/technology/dotnet-webapi/api-versioning.md +1 -1
  54. package/assets/guardrails/technology/dotnet-webapi/auditing.md +1 -1
  55. package/assets/guardrails/technology/dotnet-webapi/authorization.md +1 -1
  56. package/assets/guardrails/technology/dotnet-webapi/clean-architecture.md +1 -1
  57. package/assets/guardrails/technology/dotnet-webapi/cqrs.md +1 -1
  58. package/assets/guardrails/technology/dotnet-webapi/data-classification.md +1 -1
  59. package/assets/guardrails/technology/dotnet-webapi/eventing.md +1 -1
  60. package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +1 -1
  61. package/assets/guardrails/technology/dotnet-webapi/modular-monolith.md +1 -1
  62. package/assets/guardrails/technology/dotnet-webapi/persistence.md +1 -1
  63. package/assets/guardrails/technology/dotnet-webapi/vertical-slices.md +1 -1
  64. package/assets/guardrails/technology/dotnet-webapi/zero-trust.md +1 -1
  65. package/assets/guardrails/technology/nextjs/accessibility-implementation.md +1 -1
  66. package/assets/guardrails/technology/nextjs/api-integration.dotnet-webapi.md +1 -1
  67. package/assets/guardrails/technology/nextjs/api-integration.java-spring.md +1 -1
  68. package/assets/guardrails/technology/nextjs/auth-session.md +1 -1
  69. package/assets/guardrails/technology/nextjs/component-architecture.md +1 -1
  70. package/assets/guardrails/technology/nextjs/design-system.md +1 -1
  71. package/assets/guardrails/technology/nextjs/error-handling.md +1 -1
  72. package/assets/guardrails/technology/nextjs/forms-and-validation.md +1 -1
  73. package/assets/guardrails/technology/nextjs/i18n.md +1 -1
  74. package/assets/guardrails/technology/nextjs/performance-budgets.md +1 -1
  75. package/assets/guardrails/technology/nextjs/routing-navigation.md +1 -1
  76. package/assets/guardrails/technology/nextjs/state-management.md +1 -1
  77. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  # Delta Backend Plan — [CR-ID]: [TITLE]
2
2
 
3
- **Feature (aggregate slice)**: `[Feature]`
3
+ **Feature**: `[Feature]`
4
4
 
5
5
  **Lane**: backend — the service lane declared in `.appweaver/stacks.json`
6
6
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  **Bounded context**: `[Context]`
4
4
 
5
- **Feature (aggregate slice)**: `[Feature]`
5
+ **Feature**: `[Feature]` <!-- the feature whose change this is; the aggregates it changes are listed under "Aggregates touched" -->
6
6
 
7
7
  **Wave**: [N] <!-- script-stamped; same wave = developable in parallel, higher wave = after -->
8
8
 
@@ -1,6 +1,6 @@
1
1
  # Delta Spec — [CR-ID]: [TITLE]
2
2
 
3
- **Feature (aggregate)**: [Aggregate]
3
+ **Feature**: [Feature]
4
4
 
5
5
  **Change type**: [new-requirement | changed-requirement | defect | refactor]
6
6
 
@@ -21,8 +21,9 @@
21
21
  Standards (UX-n). A CR that changes a retention/audit rule, a data-exposure rule, an
22
22
  interop obligation or a project-wide experience standard is a CN-/DC-/IC-/UX- delta, not
23
23
  a smuggled code change. A UX- delta states the standard only — never a screen, page or
24
- component, which the prototype and frontend-plan.md settle. Adding a command (e.g.
25
- UpdateOrder to the Order aggregate) is a new user story (US-n), NOT a new feature.
24
+ component, which the prototype and frontend-plan.md settle. Adding a command to THIS
25
+ feature (e.g. UpdateOrder to Order) is a new user story (US-n). Whether a capability is
26
+ a feature of its own is the developer's decision, made when they select the feature.
26
27
 
27
28
  MODEL CHANGES DO NOT BELONG HERE. A new entity, a changed aggregate boundary or a new
28
29
  or amended invariant (BR-n) goes in this change's domain-model delta — the "Model delta"
@@ -1,10 +1,12 @@
1
- # Backend Plan: [AGGREGATE]
1
+ # Backend Plan: [FEATURE]
2
2
 
3
- **Aggregate (feature)**: `[Aggregate]` <!-- the feature = the aggregate, e.g. Order -->
3
+ **Feature**: `[Feature]` <!-- the capability scope the developer chose; the aggregate(s) it acts on are the spec's "Acts on aggregate(s)" line -->
4
4
 
5
- **Plan home**: `specs/[Aggregate]/backend-plan.md`
5
+ **Plan home**: `specs/[Context]/[Feature]/backend-plan.md`
6
6
 
7
- **Source spec**: `specs/[Aggregate]/spec.md`
7
+ **Source spec**: `specs/[Context]/[Feature]/spec.md` <!-- behaviour: what the system must DO -->
8
+
9
+ **Source model**: `specs/[Context]/domain-model.md` <!-- structure: what the domain IS -->
8
10
 
9
11
  **Version**: v1.0 <!-- moves in lockstep with the spec; every applied change request bumps this — see Change History -->
10
12
 
@@ -13,29 +15,40 @@
13
15
  <!--
14
16
  WHAT THIS DOCUMENT IS
15
17
  =====================
16
- The single, living High-Level Design (HLD) for ONE aggregate. It is the
18
+ The single, living High-Level Design (HLD) for ONE feature — the capability scope
19
+ the developer chose, over the aggregate(s) its spec says it acts on. It is the
17
20
  MEDIATOR between spec.md (WHAT/WHY, tech-agnostic) and the generated code
18
21
  (HOW, tech-specific). It is NOT code: it carries structure, contracts,
19
22
  behaviour, and decisions — enough for ANY capable LLM to generate correct,
20
23
  spec-satisfying code on ANY target stack, but no complete method bodies.
21
24
 
22
- spec.md ──▶ backend-plan.md ──▶ code (+ tests)
23
- behaviour structure & generated by `implement`
24
- (FR/BR/US/SC) decisions (HLD) (stack-bound at generation time)
25
+ domain-model.md ─┐
26
+ structure ├─▶ backend-plan.md ──▶ code (+ tests)
27
+ (BR-nnn) │ structure & generated by `implement`
28
+ spec.md ──┘ decisions (HLD) (stack-bound at generation time)
29
+ behaviour
30
+ (FR/US/SC/CN/DC/IC)
25
31
 
26
32
  ANCHORING RULES
27
- - Every design element traces UP to a spec id (FR-/BR-/CN-/DC-/IC-/US-/SC-) and
28
- the whole spec is covered DOWN here (see §6 Traceability). No design element
29
- without a spec reason; no spec requirement without a design home.
30
- - THE SPEC IS THE ONLY DOMAIN INPUT. Design reads the spec + the technical/
31
- architecture standards — NOT the domain rule files. The domain reached this doc
32
- only as spec ids: business invariants (BR-), domain-derived constraints (CN- —
33
- retention/immutability/audit/limits), data classification (DC-), and interop
34
- obligations (IC-). Realise each of those; invent no domain rule the spec omits
35
- (if one seems missing, record it as an Assumption in §7, never smuggle it in).
36
- - Feature = aggregate. Commands (CreateOrder, UpdateOrder…) are USER STORIES,
37
- not features. One aggregate = one backend-plan.md = one owning design for its code
38
- files. A later requirement is a delta on THIS doc, never a new one.
33
+ - Every design element traces UP to an id — behaviour ids (FR-/US-/SC-/CN-/DC-/IC-)
34
+ from the spec, invariant ids (BR-) from the context's domain-model.md — and the
35
+ whole spec is covered DOWN here (see §6 Traceability). No design element without
36
+ a reason in one of those two; no spec requirement without a design home.
37
+ - TWO AUTHORITIES, NOT ONE. Structure comes from the MODEL, behaviour from the SPEC.
38
+ domain-model.md fixes the aggregate's entities, value objects, boundary and
39
+ invariants; spec.md says what the system must DO with them and cites each invariant
40
+ by id. Design reads BOTH, plus the technical/architecture standards — but NOT the
41
+ domain rule files: a domain rule reaches this doc only as an id already lifted into
42
+ one of the two (BR- in the model; CN-/DC-/IC- in the spec). Realise each of those;
43
+ invent no entity, value object or rule that neither states (if one seems missing,
44
+ record it as an Assumption in §7, never smuggle it in).
45
+ - One feature = one backend-plan.md. A feature is the capability scope the developer
46
+ chose: it may act on several aggregates, and several features may act on one. Its
47
+ operations (CreateOrder, UpdateOrder…) are USER STORIES here, and a later requirement
48
+ on this feature is a delta on THIS doc, never a new one. An aggregate's shared code
49
+ (its root, entities, value objects, repository) is realised by every plan whose
50
+ feature acts on it: each plan names only the members its feature needs, and the
51
+ code extends the shared file instead of regenerating it.
39
52
 
40
53
  WHAT LIVES ELSEWHERE (do NOT repeat it here — it is identical for every feature)
41
54
  - The clean-architecture layering + dependency rule (API → Application → Domain
@@ -68,13 +81,13 @@
68
81
  ## 0. Design Overview
69
82
 
70
83
  <!--
71
- One paragraph: the architectural shape of this aggregate and the 3–5 decisions
84
+ One paragraph: the architectural shape of this feature and the 3–5 decisions
72
85
  that matter most (why this boundary, the lifecycle model, the hardest trade-off).
73
86
  This is the orientation a reviewer or an LLM reads first. The standing layering /
74
87
  dependency rule is NOT restated here — it is the project architecture standard.
75
88
  -->
76
89
 
77
- [The architectural essence of this aggregate in 3–6 sentences: its purpose, its
90
+ [The architectural essence of this feature in 3–6 sentences: its purpose, its
78
91
  lifecycle spine, the key structural choices specific to it, and the single biggest
79
92
  trade-off. Layering follows the project architecture standard (constitution).]
80
93
 
@@ -111,9 +124,11 @@ trade-off. Layering follows the project architecture standard (constitution).]
111
124
  performance-as-a-limit land in §4 Infra / §5 Cross-Cutting.)
112
125
  You MAY add design-level structure — domain events, state machines, behaviour
113
126
  signatures — but ONLY to REALISE spec behaviour. Do NOT invent an entity, value
114
- object, or rule the spec does not state, and do NOT contradict it. If a genuinely
115
- new concept is unavoidable, record it as an Assumption (§7, DA-n) and flag it —
116
- never smuggle it in. Pure business model: no framework, no persistence, no I/O.
127
+ object, or invariant THE MODEL does not define, do NOT invent behaviour THE SPEC
128
+ does not state, and do NOT contradict either. If a genuinely new concept is
129
+ unavoidable, record it as an Assumption (§7, DA-n) and flag it — never smuggle it
130
+ in: a missing entity or invariant is a gap in the model, which /appweaver specify
131
+ owns and this document may not close. Pure business model: no framework, no persistence, no I/O.
117
132
  Model this section on a rich DDD reference (entities, VOs, events, state machines,
118
133
  invariants, behaviours). Repeat the blocks as the aggregate needs.
119
134
  -->
@@ -138,7 +153,7 @@ trade-off. Layering follows the project architecture standard (constitution).]
138
153
  <!--
139
154
  Per entity: attributes (conceptual types), lifecycle state machine if it has one,
140
155
  behaviours as SIGNATURE + pre/post/invariant/raises pseudocode (the most LLM-guidable,
141
- stack-neutral form), and the invariants it enforces (each = a spec BR-nnn).
156
+ stack-neutral form), and the invariants it enforces (each = a BR-nnn THE MODEL defines).
142
157
  -->
143
158
 
144
159
  #### `[Entity]` [(Aggregate Root)]
@@ -162,13 +177,14 @@ trade-off. Layering follows the project architecture standard (constitution).]
162
177
  ```
163
178
  [Entity].[Behaviour]([params])
164
179
  Pre-condition: [required state / inputs]
165
- Invariant: [what must hold — maps to a spec BR-nnn]
180
+ Invariant: [what must hold — maps to a BR-nnn in the domain model]
166
181
  Post-condition: [resulting state / outputs]
167
182
  Raises: [DomainEvent]
168
183
  Serves: FR-00X · US-Y · BR-00Z
169
184
  ```
170
185
 
171
- **Invariants** *(always-true; each maps to a spec BR-nnn — do not add rules absent from the spec)*
186
+ **Invariants** *(always-true; each cites a BR-nnn the domain model defines — never restate its
187
+ text, and do not add a rule the model does not carry)*
172
188
 
173
189
  - [Invariant statement] — **BR-00X**
174
190
 
@@ -287,7 +303,7 @@ trade-off. Layering follows the project architecture standard (constitution).]
287
303
 
288
304
  ### 4.3 Wiring & migrations
289
305
 
290
- - **Composition**: bind `[Port] → [Adapter]` for this aggregate.
306
+ - **Composition**: bind `[Port] → [Adapter]` for this feature.
291
307
  - **Migrations needed**: [yes → what changes conceptually / no]. The Run phase applies them.
292
308
 
293
309
  ## 5. Cross-Cutting Concerns
@@ -320,22 +336,22 @@ trade-off. Layering follows the project architecture standard (constitution).]
320
336
 
321
337
  <!--
322
338
  The two-way guarantee: every FR/BR/CN/DC/IC/US/SC has a design home, and every
323
- design element has a spec reason. This is what makes impact analysis exact and lets
324
- the analyze gate verify coverage. Keep it complete — EVERY CN-/DC-/IC- in the spec
339
+ design element has a reason in one of the two authorities. This is what makes impact
340
+ analysis exact and lets the analyze gate verify coverage. Keep it complete — EVERY CN-/DC-/IC- in the spec
325
341
  MUST appear as a row here (that is how the analyze gate proves no lifted constraint
326
342
  was dropped). The Domain rows MUST match the domain model's entities and BR-nnn
327
343
  invariants exactly.
328
344
  -->
329
345
 
330
- | Spec id | Type | Design element(s) | Layer |
331
- |---|---|---|---|
332
- | FR-001 | requirement | `[Root].[Behaviour]`, `[Command]`, `[VERB /route]` | Domain·App·API |
333
- | BR-001 | invariant | `[Root]` invariant / `[VO]` validation | Domain |
334
- | CN-001 | constraint | [where realised — §1 invariant / §4 persistence / §5 cross-cutting] | [layer] |
335
- | DC-001 | classification | [exposure enforcement — §2 projection / §5 data-protection] | App·Infra |
336
- | IC-001 | contract | [adapter/port realising it — §4.2] | Infra |
337
- | US-1 | story | [end-to-end elements realising it] | all |
338
- | SC-001 | success | [where it is met + how verified] | [layer] |
346
+ | Id | Source | Type | Design element(s) | Layer |
347
+ |---|---|---|---|---|
348
+ | FR-001 | spec | requirement | `[Root].[Behaviour]`, `[Command]`, `[VERB /route]` | Domain·App·API |
349
+ | BR-001 | model | invariant | `[Root]` invariant / `[VO]` validation | Domain |
350
+ | CN-001 | spec | constraint | [where realised — §1 invariant / §4 persistence / §5 cross-cutting] | [layer] |
351
+ | DC-001 | spec | classification | [exposure enforcement — §2 projection / §5 data-protection] | App·Infra |
352
+ | IC-001 | spec | contract | [adapter/port realising it — §4.2] | Infra |
353
+ | US-1 | spec | story | [end-to-end elements realising it] | all |
354
+ | SC-001 | spec | success | [where it is met + how verified] | [layer] |
339
355
 
340
356
  ## 7. Assumptions (to clarify later)
341
357
 
@@ -3,6 +3,8 @@ type: aggregate
3
3
  title: [Aggregate]
4
4
  description: [one line — what this aggregate is and the invariant/boundary it guards]
5
5
  origin: greenfield
6
+ bounded_context:
7
+ features:
6
8
  source_files:
7
9
  ui_source_files:
8
10
  ---
@@ -17,8 +19,16 @@ ui_source_files:
17
19
  as it generates the aggregate's code;
18
20
  • brownfield — `inventory` seeds it and `adopt` enriches it.
19
21
 
22
+ A CONCEPT IS AN AGGREGATE, NEVER A FEATURE. A feature is a capability scope the
23
+ developer chose; it may act on several aggregates, and several features may act on
24
+ one. `features:` lists every feature known to act on this aggregate — implement and
25
+ adopt add their feature, and a feature is never removed from it by a later write.
26
+ `bounded_context:` names the context the aggregate belongs to.
27
+
20
28
  WHO WRITES WHAT (do not cross these lanes):
21
- • Frontmatter, Overview, Depends-On → THIS aggregate's implement/adopt.
29
+ • Frontmatter, Overview, Depends-On → the implement/adopt of every feature that
30
+ acts on this aggregate. Depends-On is the
31
+ union over all of them.
22
32
  • Cross-References → the OTHER aggregates that USE this one; each
23
33
  writes its own row (never hand-edit them here).
24
34
  One addition inside the first lane: `analyze-slice` MERGES (never replaces) the files its
@@ -0,0 +1,127 @@
1
+ # Proposed Inventory
2
+
3
+ <!-- TEMPLATE-NOTE
4
+ This is the TEMPLATE for the document `/appweaver inventory` generates at
5
+ specs/proposed-inventory.md. Every TEMPLATE-NOTE block is stripped on generation,
6
+ so nothing in here reaches the produced file.
7
+
8
+ UNLIKE EVERY OTHER TEMPLATE IN THIS DIRECTORY, THIS ONE IS FILLED BY A SCRIPT,
9
+ NOT BY AN AGENT. aw-inventory.py substitutes each token below with the result of
10
+ its scan. There are no [PLACEHOLDER] tokens for an author to complete — a token
11
+ left in the output is a bug, not an unfinished section.
12
+
13
+ Override it per project at
14
+ .appweaver/templates/overrides/proposed-inventory-template.md to change the
15
+ wording, the ordering or the guidance. Keep every token you want filled; drop
16
+ one and that section simply does not appear.
17
+
18
+ Tokens, each written in single braces:
19
+ root · head · date · strategy · reason · files · code · coverage
20
+ probe_table · context_table · feature_table
21
+ splits_section · cycles_section
22
+ -->
23
+ <!-- Generated by `/appweaver inventory`. Edit freely, then run
24
+ `/appweaver inventory apply`. -->
25
+
26
+ **Repository:** `{root}` · **Commit:** `{head}` · **Generated:** {date}
27
+ **Pass A strategy:** `{strategy}` — {reason}
28
+ **Scanned:** {files} files, {code} source files · **Coverage:** {coverage}%
29
+
30
+ This file is the **boundary map for this codebase, and it is yours to change.** Nothing
31
+ below was decided by a person yet — it is what a deterministic scan of the source
32
+ proposes. Read it, correct it, then run `/appweaver inventory apply`, which validates
33
+ your edits and regenerates the machine map that `/appweaver onboard` reads.
34
+
35
+ ## How to edit this file
36
+
37
+ - **Rename** a feature or a bounded context by editing its cell. Names are the
38
+ identity — renaming a feature here renames the slice onboard will create.
39
+ - **Move** a feature to another context by editing its Bounded Context cell.
40
+ A feature lives in exactly one context.
41
+ - **Merge** two features by giving them the same name; their files combine, and the
42
+ merged feature acts on every aggregate its rows name — that is how one feature spans
43
+ several aggregates. Keep those rows in the same Bounded Context.
44
+ - **Split** a feature by adding a row with the same Aggregate and a different
45
+ Feature name. Name the split from the capability, not the noun —
46
+ `PatientRegistration`, not a second `Patient`.
47
+ - **Reorder** by editing Depends On. Waves are recomputed on apply, so you do
48
+ not maintain wave numbers by hand.
49
+ - Rows you delete are dropped from the map and never onboarded.
50
+
51
+ The Aggregate column must name an aggregate the scan found; everything else is
52
+ yours. `apply` reports anything it cannot resolve rather than guessing.
53
+
54
+ ## How these boundaries were found
55
+
56
+ Three passes over the source. None of them reads a specification, a rule file or an
57
+ exemplar from another project — the code is the only evidence.
58
+
59
+ **Pass A — what must stay consistent together.** Groups the source into candidate
60
+ aggregates. Three strategies can do this, and only those the evidence supports are
61
+ offered:
62
+
63
+ | strategy | the evidence it reads | available when |
64
+ |---|---|---|
65
+ | `structure` | the repo's own organising axis — a vertical slice, a layer folder under a module, a layer carried as a project-name suffix, or a layer at the top with the module repeated as a noun | always |
66
+ | `reference` | the `using` / `import` / `require` graph, clustered after removing the high-fan-in nodes that are shared kernel rather than features | enough import-parseable source |
67
+ | `persistence` | the schema itself — `DbSet<T>`, `[Table]`, JPA `@Entity`, `schema.prisma`, `CREATE TABLE` — with roots derived by ownership: an entity that owns others' lifecycles and is referenced from outside by id | ORM / schema / migration evidence found |
68
+
69
+ `structure` always runs whichever strategy is chosen, because the other two produce
70
+ unnamed clusters and need it to give each one a directory and a human name.
71
+
72
+ **Pass B — what can be cut over together.** Reads the application, API and UI surface
73
+ only, and emits *signals*, never decisions: route families (`[Route("orders")]`,
74
+ `@RequestMapping`, `app.get('/orders/…')`), command/handler groups, UI router segments,
75
+ and rates of change from git history. **Two distinct route families on one aggregate is
76
+ a split candidate** — proposed below, never applied.
77
+
78
+ Three of the five tests for a feature boundary are computable — one cutover seam,
79
+ stable file ownership, one bounded context — and two are not: whether it serves one
80
+ business need, and whether it can be demonstrated independently. Those two are why this
81
+ file is editable.
82
+
83
+ **Pass C — the proposal.** One aggregate becomes one feature with the same name. That
84
+ is the default and not a failure. A split is proposed only where Pass B found the
85
+ evidence, and is shown with that evidence for you to accept or ignore. One endpoint is
86
+ never a feature; neither is one whole bounded context.
87
+
88
+ **Bounded contexts** are derived above Pass A and voted from where each candidate's
89
+ files actually live. A feature belongs to exactly one context — the context of the
90
+ primary aggregate it acts on. A feature that needs another context's aggregate
91
+ references it by id and stays a separate feature over there.
92
+
93
+ ## Strategy probe
94
+
95
+ The clustering each available strategy produced on this tree. The chosen one is
96
+ marked; re-run with `--strategy <name>` to pick another.
97
+
98
+ {probe_table}
99
+
100
+ ## Bounded Contexts
101
+
102
+ Onboard one context at a time, in this order. A context is ready when every context it
103
+ depends on has been onboarded.
104
+
105
+ {context_table}
106
+
107
+ ## Features
108
+
109
+ Dependency order. **Wave 0 depends on nothing** and can be onboarded first; a feature in
110
+ wave N depends only on features in earlier waves. Edit any cell except Wave, which is
111
+ recomputed.
112
+
113
+ {feature_table}
114
+ {splits_section}{cycles_section}
115
+ ## What happens after you apply this
116
+
117
+ ```
118
+ /appweaver inventory apply validates these edits, regenerates the machine map
119
+ /appweaver onboard <Context> once per context, in the order above:
120
+ reverse-engineers the governance and creates
121
+ specs/<Context>/<Feature>/ for each feature
122
+ /appweaver adopt <Feature> just-in-time, per feature: reverse-engineers its
123
+ spec, plans and domain-model section
124
+ ```
125
+
126
+ Re-running `/appweaver inventory` re-derives this file from the code and **discards
127
+ your edits** — apply them first. Re-running `apply` is safe and idempotent.
@@ -1,8 +1,10 @@
1
- # Source Map: [AGGREGATE]
1
+ # Source Map: [FEATURE]
2
2
 
3
- **Aggregate (feature)**: `[Aggregate]` <!-- the feature = the aggregate, e.g. MedicinalProduct -->
3
+ **Feature**: `[Feature]` <!-- the capability scope confirmed in the boundary map, e.g. MedicinalProduct or PatientRegistration -->
4
4
 
5
- **Source home**: `specs/[Aggregate]/source-map.md`
5
+ **Acts on aggregate(s)**: `[Aggregate]` <!-- the same names the spec's Domain Model Reference gives -->
6
+
7
+ **Source home**: `specs/[Context]/[Feature]/source-map.md`
6
8
 
7
9
  **Origin**: `reverse-engineered` <!-- greenfield | reverse-engineered | migrated -->
8
10
 
@@ -1,8 +1,8 @@
1
- # Specification: [AGGREGATE]
1
+ # Specification: [FEATURE]
2
2
 
3
- **Aggregate (feature)**: `[Aggregate]` <!-- the feature = the aggregate, e.g. Order -->
3
+ **Feature**: `[Feature]` <!-- the capability scope the developer chose, e.g. Order or PatientRegistration; the aggregate(s) it acts on are named under Domain Model Reference -->
4
4
 
5
- **Spec home**: `specs/[Aggregate]/`
5
+ **Spec home**: `specs/[Context]/[Feature]/`
6
6
 
7
7
  **Version**: v1.0 <!-- living truth; every applied change request bumps this — see Change History -->
8
8
 
@@ -17,13 +17,13 @@
17
17
  and is referenced from here by name and id. That split is what lets one aggregate be
18
18
  acted on by several specs without any of them owning its definition.
19
19
 
20
- Every operation on the aggregate (CreateOrder, UpdateOrder, …) is a USER STORY below —
21
- NOT a separate feature. A later requirement is a new US-n added as a delta (see
20
+ Every operation within this feature's scope (CreateOrder, UpdateOrder, …) is a USER
21
+ STORY below. A later requirement on this feature is a new US-n added as a delta (see
22
22
  delta-spec-template.md), never a new spec folder. One spec + one plan per declared
23
23
  lane — the PLAN derives from this document and the domain model together.
24
24
 
25
25
  Section order is intentional: establish the business need and scope, then the stable
26
- core the aggregate's BEHAVIOUR is (requirements → constraints → data classification →
26
+ core the feature's BEHAVIOUR is (requirements → constraints → data classification →
27
27
  integration contracts → experience standards → edge cases), then the prioritized user
28
28
  journeys that exercise it, then measurable success.
29
29
 
@@ -39,11 +39,11 @@
39
39
  ## Business Need
40
40
 
41
41
  <!--
42
- ACTION REQUIRED: Why this aggregate exists — the problem, the affected users,
42
+ ACTION REQUIRED: Why this feature exists — the problem, the affected users,
43
43
  and the value delivered. Business-facing; no implementation detail.
44
44
  -->
45
45
 
46
- [The problem this aggregate solves, who it serves, and the value it delivers.]
46
+ [The problem this feature solves, who it serves, and the value it delivers.]
47
47
 
48
48
  ## Scope & Assumptions
49
49
 
@@ -83,7 +83,7 @@
83
83
  ### Experience Scope
84
84
 
85
85
  <!--
86
- The experience envelope this aggregate is specified against: WHO reaches it through a
86
+ The experience envelope this feature is specified against: WHO reaches it through a
87
87
  UI, THROUGH WHAT, and the floor the frontend lane has to hold. Scope, not requirement —
88
88
  it bounds what the Experience Standards and the prototype are held to, and it is the
89
89
  only place the spec describes the delivery surface at all.
@@ -97,7 +97,7 @@
97
97
  surface to bound: write "None (as of vX.Y)" — never delete the section.
98
98
  -->
99
99
 
100
- - **Actors**: [the user roles that reach this aggregate through a UI — e.g. clinician, scheduler; distinct from a system/API caller]
100
+ - **Actors**: [the user roles that reach this feature through a UI — e.g. clinician, scheduler; distinct from a system/API caller]
101
101
  - **Channels**: [where the experience is delivered — e.g. responsive web; internal back-office only]
102
102
  - **Device / viewport floor**: [the smallest supported surface — e.g. 360 px wide]
103
103
  - **Browser / platform floor**: [the oldest supported targets — e.g. the last two major versions of evergreen browsers]
@@ -130,7 +130,7 @@
130
130
 
131
131
  <!--
132
132
  ACTION REQUIRED (when the domain applies; else "None (as of vX.Y)"). Constraints the
133
- aggregate MUST satisfy that are NEITHER functional behaviour (those are FR) NOR
133
+ feature MUST satisfy that are NEITHER functional behaviour (those are FR) NOR
134
134
  always-true business invariants (those are BR): the regulatory, retention,
135
135
  immutability, audit-mandate, and performance-as-a-limit rules. Many are LIFTED here
136
136
  by specify from the domain rule files (e.g. persistence.domain, auditing.domain,
@@ -147,8 +147,8 @@
147
147
  ## Data Classification *(domain lift — DC)*
148
148
 
149
149
  <!--
150
- ACTION REQUIRED (when the aggregate handles sensitive data; else "None (as of vX.Y)").
151
- The sensitivity taxonomy for this aggregate's data and the exposure rules that follow:
150
+ ACTION REQUIRED (when the feature handles sensitive data; else "None (as of vX.Y)").
151
+ The sensitivity taxonomy for this feature's data and the exposure rules that follow:
152
152
  which categories exist, which Key-Entity fields fall in each, and where each category
153
153
  MAY / MUST NOT appear (public API surface, logs, metrics, traces, external projections).
154
154
  Lifted by specify from the domain data-classification rules. Design enforces these; the
@@ -165,8 +165,8 @@
165
165
  ## Integration Contracts *(domain lift — IC)*
166
166
 
167
167
  <!--
168
- ACTION REQUIRED (when the aggregate interoperates; else "None (as of vX.Y)"). The
169
- external contracts this aggregate MUST satisfy — interoperability obligations lifted by
168
+ ACTION REQUIRED (when the feature interoperates; else "None (as of vX.Y)"). The
169
+ external contracts this feature MUST satisfy — interoperability obligations lifted by
170
170
  specify from the domain interop rules (e.g. FHIR/HL7/DICOM projections, terminology
171
171
  services, inbound feeds). State each at CONTRACT level: which standard, which resources,
172
172
  direction (inbound/outbound), projection vs system-of-record — NOT the adapter design
@@ -182,7 +182,7 @@
182
182
 
183
183
  <!--
184
184
  ACTION REQUIRED (when the frontend lane's rules apply; else "None (as of vX.Y)").
185
- The PROJECT-WIDE experience standards this aggregate's UI must satisfy, lifted here by
185
+ The PROJECT-WIDE experience standards this feature's UI must satisfy, lifted here by
186
186
  specify out of the frontend lane's constitution (constitution.ui.md — the UX-* principle
187
187
  series) and the mapped ux/ rule files, exactly as CN-/DC-/IC- lift the domain rules.
188
188
  The lift is what makes them binding: the prototype phase and the FRONTEND LANES of plan
@@ -208,7 +208,7 @@
208
208
  - **UX-001**: [Accessibility conformance — e.g. every user-facing surface MUST meet [standard, level]; every task in the User Stories is completable keyboard-only. — lifted from UX-II, ux/accessibility-standards.md]
209
209
  - **UX-002**: [Interaction states — e.g. every asynchronous operation MUST present its loading, empty, partial-failure, recovery and success states; no state leaves the user without a next action. — lifted from UX-IV, ux/interaction-states.md]
210
210
  - **UX-003**: [Content and language — e.g. user-facing text uses the context's ubiquitous language; every error names what happened and what to do next; regulated wording is reproduced verbatim. — lifted from UX-V, ux/content-design.md]
211
- - **UX-004**: [Journey integrity — e.g. each US-n is completable without leaving this aggregate's surface; destructive actions are confirmed and reversible. — lifted from ux/journey-mapping.md]
211
+ - **UX-004**: [Journey integrity — e.g. each US-n is completable without leaving this feature's surface; destructive actions are confirmed and reversible. — lifted from ux/journey-mapping.md]
212
212
  - **UX-005**: [Responsiveness-as-a-limit — e.g. an interaction acknowledges input within [n] ms and shows progress past [n] s. A front-end bound; the server-side budget it depends on is CN-nnn.]
213
213
 
214
214
  ## Edge Cases & Exceptional Scenarios
@@ -289,10 +289,13 @@
289
289
 
290
290
  <!--
291
291
  The living-truth ledger. Every applied change request appends a row here, carrying
292
- the version it ships as. finalize-delta writes the row when it merges the delta;
293
- close-delta then archives the CR, bumps the minor version in active_version.json and
294
- stamps that same number into this document's **Version** header — one mechanism, one
295
- stage, so header, row and active_version.json never disagree. Newest last.
292
+ the version it ships as. finalize-delta writes the row when it MERGES the delta, with
293
+ the CR id and `(pending)` in the Version cell — at that point the number does not exist
294
+ yet. close-delta then archives the CR, bumps the minor version in active_version.json,
295
+ and stamps that same number into this document's **Version** header AND into the pending
296
+ cell — one mechanism, one stage, so header, row and active_version.json never disagree.
297
+ A row still reading `(pending)` is a change that merged and has not closed. The model
298
+ never writes a version here or anywhere; scripts stamp it. Newest last.
296
299
  -->
297
300
 
298
301
  | Version | Date | Change | User stories | CR |
@@ -1,6 +1,6 @@
1
1
  # Delta Frontend Plan — [CR-ID]: [TITLE]
2
2
 
3
- **Feature (aggregate slice)**: `[Feature]`
3
+ **Feature**: `[Feature]`
4
4
 
5
5
  **Lane**: `[lane id]` — the frontend lane declared in `.appweaver/stacks.json`
6
6
 
@@ -1,10 +1,10 @@
1
- # Frontend Plan: [AGGREGATE]
1
+ # Frontend Plan: [FEATURE]
2
2
 
3
- **Aggregate (feature)**: `[Aggregate]` <!-- the feature = the aggregate, e.g. Order -->
3
+ **Feature**: `[Feature]` <!-- the capability scope the developer chose; the aggregate(s) it acts on are the spec's "Acts on aggregate(s)" line -->
4
4
 
5
- **Plan home**: `specs/[Aggregate]/frontend-plan.md`
5
+ **Plan home**: `specs/[Context]/[Feature]/frontend-plan.md`
6
6
 
7
- **Source spec**: `specs/[Aggregate]/spec.md`
7
+ **Source spec**: `specs/[Context]/[Feature]/spec.md`
8
8
 
9
9
  **Lane**: `[lane id]` — the frontend lane declared in `.appweaver/stacks.json`
10
10
 
@@ -32,9 +32,13 @@
32
32
  - UX- LIVES HERE AND ONLY HERE. The spec's Experience Standards are this
33
33
  document's to realise — backend-plan.md deliberately excludes them, so a UX- that
34
34
  reaches neither design is a dropped requirement.
35
- - THE SPEC IS THE ONLY DOMAIN INPUT — the same rule backend-plan.md keeps. This
36
- document reads the spec + the lane's own standards, never the domain rule
37
- files. A domain rule the spec omits is an §8 assumption, never an invention.
35
+ - THE SPEC IS THE ONLY DOMAIN INPUT for this lane. This document reads the spec
36
+ + the lane's own standards, never the domain rule files. A domain rule the
37
+ spec omits is an §8 assumption, never an invention. (The SERVICE lane reads a
38
+ second authority, the context's domain-model.md, because it realises the
39
+ aggregate's structure. This lane does not: it consumes the published surface
40
+ at §5, not the domain, so the model is not in its context and an entity or
41
+ invariant is never this document's to state.)
38
42
  - THE SERVICE LANE ENTERS ONLY AT §5. Cite the operations this surface
39
43
  consumes; never restate, re-derive or contradict the service design, and
40
44
  never place server-side behaviour here.