aw-spec-cli 0.1.23 → 0.1.25

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 (38) hide show
  1. package/assets/.appweaver/ORCH-DIALECT.md +3 -3
  2. package/assets/.appweaver/RULE-PARTITION.md +41 -28
  3. package/assets/.appweaver/orchestrator/orchestrator.py +92 -14
  4. package/assets/.appweaver/orchestrator/rev-templates/ai-rules.reference.md +3 -3
  5. package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +19 -12
  6. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +25 -17
  7. package/assets/.appweaver/orchestrator/rev-templates/domain-requirements.skeleton.md +2 -2
  8. package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +10 -10
  9. package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +28 -17
  10. package/assets/.appweaver/orchestrator/rev-templates/technical-constitution.skeleton.md +22 -24
  11. package/assets/.appweaver/orchestrator/rev-templates/technical-rule-file.skeleton.md +1 -1
  12. package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +29 -19
  13. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +27 -20
  14. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +184 -37
  15. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +18 -0
  16. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +19 -0
  17. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +18 -0
  18. package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +55 -29
  19. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +650 -205
  20. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +19 -0
  21. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-feature.orch.yaml +5 -5
  22. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +2 -2
  23. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +13 -3
  24. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-prototype.orch.yaml +40 -1
  25. package/assets/.appweaver/orchestrator/workflows/aw-spec-workflow-model.orch.yaml +2 -1
  26. package/assets/.appweaver/scripts/bash/aw-rev-constitution.sh +1 -1
  27. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +69 -7
  28. package/assets/.appweaver/scripts/powershell/aw-rev-constitution.ps1 +1 -1
  29. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +58 -2
  30. package/assets/.appweaver/scripts/python/aw-inventory.py +1809 -156
  31. package/assets/.appweaver/scripts/python/aw-rev-constitution.py +106 -145
  32. package/assets/.appweaver/scripts/python/aw-stack.py +45 -1
  33. package/assets/.appweaver/scripts/python/aw-xref.py +73 -2
  34. package/assets/.appweaver/scripts/python/validate_okf.py +10 -5
  35. package/assets/.appweaver/templates/okf-concept-template.md +10 -2
  36. package/assets/.appweaver/templates/proposed-inventory-template.md +100 -48
  37. package/assets/.appweaver/templates/source-map-template.md +14 -6
  38. package/package.json +1 -1
@@ -13,86 +13,121 @@
13
13
  Override it per project at
14
14
  .appweaver/templates/overrides/proposed-inventory-template.md to change the
15
15
  wording, the ordering or the guidance. Keep every token you want filled; drop
16
- one and that section simply does not appear.
16
+ one and that section simply does not appear. The `## Features` heading and its
17
+ table's column ORDER are what `apply` parses — keep both.
17
18
 
18
19
  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
20
+ root · head · date · strategy · reason · scanned · files · code · coverage
21
+ probe_table · context_table · aggregate_table · feature_table · operation_table
22
+ review_section · splits_section · cycles_section · unplaced_section
23
+ `scanned` says what was read, lane by lane; `files` (every file in the declared
24
+ lanes) and `code` (service-lane source files) are its two numbers on their own.
22
25
  -->
23
26
  <!-- Generated by `/appweaver inventory`. Edit freely, then run
24
27
  `/appweaver inventory apply`. -->
25
28
 
26
29
  **Repository:** `{root}` · **Commit:** `{head}` · **Generated:** {date}
27
30
  **Pass A strategy:** `{strategy}` — {reason}
28
- **Scanned:** {files} files, {code} source files · **Coverage:** {coverage}%
31
+ **Scanned:** {scanned} · **Coverage:** {coverage}%
29
32
 
30
33
  This file is the **boundary map for this codebase, and it is yours to change.** Nothing
31
34
  below was decided by a person yet — it is what a deterministic scan of the source
32
35
  proposes. Read it, correct it, then run `/appweaver inventory apply`, which validates
33
36
  your edits and regenerates the machine map that `/appweaver onboard` reads.
34
37
 
38
+ ## The model this map describes
39
+
40
+ The same four levels the forward pipeline writes, read back from the code:
41
+
42
+ | Level | What it is | Where the specs keep it | Where the code keeps it |
43
+ |---|---|---|---|
44
+ | **Bounded context** | a boundary with its own model and language | `specs/<Context>/` and its one `domain-model.md` | the module folder — one per context |
45
+ | **Aggregate** | what must stay consistent together | a `## Aggregate: <Root>` section of that `domain-model.md` | a type declared as an aggregate root, in the module's `Domain/` |
46
+ | **Feature** | a capability the developer chose | `specs/<Context>/<Feature>/spec.md` | the UI lane's `features/<Feature>/` folder, named verbatim |
47
+ | **Operation** | one command or query the code exposes | the behaviour the `spec.md`'s user stories (`US-n`) and requirements describe | one slice under the module's `Features/` (command or query + handler + endpoint + validator), or a handler class where the solution keeps them in its own project |
48
+
49
+ - A feature lives in **exactly one** bounded context.
50
+ - An operation is **not** a user story. A story usually needs several operations (record
51
+ a draft, then add, revise and remove its notes), and a read can serve stories in
52
+ several features. The stories are written with the feature's spec — by `adopt`, for
53
+ code that exists; this map only places the operations.
54
+ - A feature may act on **several** aggregates, and several features may act on **one**
55
+ aggregate — within its context. Another context's aggregate is referenced by id.
56
+ - **An operation is never a feature, and a bounded context is never an aggregate.** A
57
+ slice folder under the service's `Features/` is one operation of its module, however
58
+ it is named.
59
+
35
60
  ## How to edit this file
36
61
 
37
62
  - **Rename** a feature or a bounded context by editing its cell. Names are the
38
63
  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.
64
+ - **Move** a feature to another context by editing its Bounded Context cell. Every row
65
+ of one feature must name the same context.
66
+ - **One feature, several aggregates** is several rows with the same Feature name and
67
+ different Aggregates. That is how the table writes many-to-many: add a row to make a
68
+ feature act on another aggregate, delete one to stop it.
69
+ - **Move an operation** between features by editing the Operations cells. The cell on
70
+ a row lists what that feature does to that row's aggregate. A read may sit under
71
+ several features; a command normally belongs to one.
72
+ - **Merge** two features by giving them the same name; their operations combine.
73
+ - **Split** a feature by adding a row with the same Aggregate and a different Feature
74
+ name, then moving operations to it. Name the split from the capability, not the
75
+ noun — `PatientRegistration`, not a second `Patient`.
76
+ - **Reorder** by editing Depends On. Waves are recomputed on apply, so you do not
77
+ maintain wave numbers by hand.
49
78
  - Rows you delete are dropped from the map and never onboarded.
50
79
 
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.
80
+ The Aggregate column must name an aggregate the scan found, and every name in an
81
+ Operations cell an operation it found; everything else is yours. `apply` reports
82
+ anything it cannot resolve rather than guessing.
53
83
 
54
84
  ## How these boundaries were found
55
85
 
56
86
  Three passes over the source. None of them reads a specification, a rule file or an
57
87
  exemplar from another project — the code is the only evidence.
58
88
 
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:
89
+ **Pass A — the aggregates.** Four strategies, each offered only where its evidence
90
+ exists:
62
91
 
63
92
  | strategy | the evidence it reads | available when |
64
93
  |---|---|---|
94
+ | `domain` | the aggregate roots the code **declares** — a type deriving from an aggregate-root base or carrying an aggregate-root marker; its context is the module folder holding its `Domain/` layer; it owns what it alone reaches, then what is named after it or used by it alone (its DTOs, errors, mappings, ports); its operations are its module's slices and command/query handlers anywhere in the lane, so a solution split one project per layer reads the same as one split per module | at least one root is declared |
65
95
  | `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
96
  | `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.
97
+ | `persistence` | the entities the code tells its ORM about — `DbSet<T>`, `IEntityTypeConfiguration<T>`, `modelBuilder.Entity<T>()`, `[Table]`, JPA `@Entity`, `schema.prisma`, `CREATE TABLE` — plus what they hold collections of, with roots derived by ownership: an entity that owns others' lifecycles and is referenced from outside by id. Read from class shape only where nothing is declared | ORM / schema / migration evidence found |
98
+
99
+ **Declared beats measured.** Where the code declares its roots and operations act on
100
+ them, `domain` is chosen whatever the others score: a declaration is the boundary
101
+ itself. Otherwise the highest-coverage strategy is proposed — coverage says how much of
102
+ the code a strategy placed, not whether it placed it right, so read the counts beside
103
+ it. `structure` always runs underneath, because the other strategies need it to give a
104
+ cluster a directory and a human name.
105
+
106
+ **Pass B — the operations and their seams.** Reads the application, API and UI surface
107
+ only: each operation's route (`Get("/care/encounters/{id}")`, `[HttpPost]`,
108
+ `@GetMapping`, `app.get(…)`), the aggregate it acts on, and whether it creates one.
109
+ Route families are read below the bounded context's own prefix. **Two route families
110
+ on one aggregate is a split candidate** — proposed below, never applied.
111
+
112
+ **Pass C — the features.** A feature is a capability, so it is proposed only from
113
+ evidence that names one:
114
+
115
+ 1. every UI `features/<Feature>/` folder becomes a feature, named verbatim, holding the
116
+ operations it calls and acting on those operations' aggregates;
117
+ 2. a read no feature calls joins every feature acting on its aggregate — reads are
118
+ shared, and they are not what separates two capabilities;
119
+ 3. what is left — commands no feature calls, and aggregates no UI feature touches —
120
+ becomes **one feature per aggregate, named after it**. That default is a placeholder
121
+ for a capability the code does not name: rename it.
122
+
123
+ **Order** follows creation: on each aggregate the feature holding its creating operation
124
+ goes first, every other feature on it follows, and an aggregate that references another
125
+ by id follows that one's creator. Reads never order anything.
92
126
 
93
127
  ## Strategy probe
94
128
 
95
- The clustering each available strategy produced on this tree. The chosen one is
129
+ The clustering each available strategy produced on this tree, with the first names it
130
+ found — judge a strategy by what it found, not only by how many. The chosen one is
96
131
  marked; re-run with `--strategy <name>` to pick another.
97
132
 
98
133
  {probe_table}
@@ -104,14 +139,31 @@ depends on has been onboarded.
104
139
 
105
140
  {context_table}
106
141
 
142
+ ## Aggregates
143
+
144
+ What each context's model holds, and which features act on each aggregate. Files is
145
+ every file the aggregate owns — its model, persistence, application-layer files and
146
+ operations. Read-only — change which features act on what in the Features table below.
147
+
148
+ {aggregate_table}
149
+
107
150
  ## Features
108
151
 
109
152
  Dependency order. **Wave 0 depends on nothing** and can be onboarded first; a feature in
110
153
  wave N depends only on features in earlier waves. Edit any cell except Wave, which is
111
- recomputed.
154
+ recomputed. One row per feature **per aggregate it acts on**. Files is what the feature
155
+ brings: its operations' files and its UI feature folder — plus its aggregate's own files
156
+ when it is the only feature on that aggregate.
112
157
 
113
158
  {feature_table}
114
- {splits_section}{cycles_section}
159
+ {review_section}{splits_section}{cycles_section}
160
+ ## Operations
161
+
162
+ Every operation the scan found, what it acts on, and the feature(s) it serves.
163
+ Read-only — move an operation by editing the Operations cells above.
164
+
165
+ {operation_table}
166
+ {unplaced_section}
115
167
  ## What happens after you apply this
116
168
 
117
169
  ```
@@ -53,15 +53,21 @@
53
53
 
54
54
  <!--
55
55
  ACTION REQUIRED: one row per legacy artefact this slice owns. Every source file
56
- in the OKF bundle concept's `source_files` MUST appear here (Fidelity checks
57
- full coverage both ways: no unmapped code, no spec id without a code anchor).
56
+ in the OKF bundle concept's `source_files` MUST have a home (Fidelity checks full
57
+ coverage both ways: no unmapped code, no spec id without a code anchor) — a row
58
+ here, or, when the file serves ONLY another feature over the same aggregate, a
59
+ `sibling: <Feature>` line under Unmapped / open. The rows are this feature's file
60
+ list: later phases hand exactly these files to their fix loops.
61
+ "Design element" names the plan's OWN section — its number and heading as that
62
+ plan has them. The plan's structure follows the code, so the numbering is whatever
63
+ the plan uses, never a fixed layering.
58
64
  -->
59
65
 
60
66
  | # | Legacy artefact | Kind | Spec ids | Design element | Confidence | Notes / quirk |
61
67
  |---|---|---|---|---|---|---|
62
- | SM-001 | `src/.../MedicinalProduct.cs` | file (aggregate root) | US-1, BR-001 | §1 Domain · MedicinalProduct | certain | |
63
- | SM-002 | `PRODUCTS` | table | FR-003, DC-001 | §4 Infra · MedicinalProductRepository | inferred | NDC stored unformatted — see WA/CN |
64
- | SM-003 | `POST /product` | endpoint | US-1, FR-001 | §3 API · RegisterMedicinalProduct | certain | |
68
+ | SM-001 | `src/.../MedicinalProduct.cs` | file (aggregate root) | US-1, BR-001 | backend-plan §[n] [domain section] · MedicinalProduct | certain | |
69
+ | SM-002 | `PRODUCTS` | table | FR-003, DC-001 | backend-plan §[n] [persistence section] · MedicinalProductRepository | inferred | NDC stored unformatted — see WA/CN |
70
+ | SM-003 | `POST /product` | endpoint | US-1, FR-001 | backend-plan §[n] [endpoint section] · RegisterMedicinalProduct | certain | |
65
71
 
66
72
  ## As-built quirks captured
67
73
 
@@ -80,8 +86,10 @@
80
86
  <!--
81
87
  Source files the reverse pass could not confidently place, and spec ids with no
82
88
  code home found. Both are Fidelity gaps to resolve (out of band or by refining
83
- the reverse spec/design). Empty when the map is complete.
89
+ the reverse spec/design). Empty when the map is complete. Sibling files are not
90
+ gaps: they are placed, in another feature, and listed so the placement is visible.
84
91
  -->
85
92
 
86
93
  - **Unmapped code**: [files not yet placed, or "none"]
94
+ - **Sibling files**: [`<path>` — sibling: <Feature>, one per file that serves only another feature over the same aggregate, or "none"]
87
95
  - **Unanchored spec ids**: [spec items with no code, or "none"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aw-spec-cli",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "description": "AppWeaver Spec-Driven Development CLI - scaffolds projects with vertical slices, DDD, CQRS, and agent skills",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",