aw-spec-cli 0.1.33 → 0.1.35

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 (75) hide show
  1. package/README.md +76 -81
  2. package/assets/.appweaver/DESIGN-FORMAT.md +57 -25
  3. package/assets/.appweaver/STACK-PROFILES.md +95 -60
  4. package/assets/.appweaver/orchestrator/LAUNCHER.md +1 -1
  5. package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +173 -32
  6. package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +29 -1
  7. package/assets/.appweaver/orchestrator/modules/foundation-pack.orch.yaml +7 -4
  8. package/assets/.appweaver/orchestrator/modules/foundation-spec.orch.yaml +49 -60
  9. package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +58 -0
  10. package/assets/.appweaver/orchestrator/orchestrator.py +26 -8
  11. package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +20 -20
  12. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +22 -48
  13. package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +9 -7
  14. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +5 -5
  15. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +239 -40
  16. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +254 -43
  17. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +248 -68
  18. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +251 -20
  19. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +316 -10
  20. package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +6 -47
  21. package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +62 -16
  22. package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +132 -9
  23. package/assets/.appweaver/orchestrator/workflows/aw-spec-fix-test-coverage.orch.yaml +965 -0
  24. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +222 -169
  25. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +21 -22
  26. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +453 -120
  27. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-lane.orch.yaml +2 -2
  28. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +83 -6
  29. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +45 -2
  30. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +324 -74
  31. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +275 -44
  32. package/assets/.appweaver/scripts/python/aw-foundation.py +16 -13
  33. package/assets/.appweaver/scripts/python/aw-gaps.py +11 -3
  34. package/assets/.appweaver/scripts/python/aw-model-guard.py +295 -0
  35. package/assets/.appweaver/scripts/python/aw-plan-coverage.py +412 -3
  36. package/assets/.appweaver/scripts/python/aw-plangate.py +23 -16
  37. package/assets/.appweaver/scripts/python/aw-stack.py +1794 -265
  38. package/assets/.appweaver/stack-profiles/dotnet-webapi.json +0 -2
  39. package/assets/.appweaver/stack-profiles/java-spring.json +0 -2
  40. package/assets/.appweaver/templates/api-plan-template.md +107 -0
  41. package/assets/.appweaver/templates/delta-api-plan-template.md +87 -0
  42. package/assets/.appweaver/templates/delta-design-template.md +25 -23
  43. package/assets/.appweaver/templates/delta-spec-template.md +3 -3
  44. package/assets/.appweaver/templates/design-template.md +20 -42
  45. package/assets/.appweaver/templates/domain-model-template.md +3 -0
  46. package/assets/.appweaver/templates/ui-delta-design-template.md +11 -8
  47. package/assets/.appweaver/templates/ui-design-template.md +4 -4
  48. package/assets/foundations/foundation.spec.template.txt +25 -18
  49. package/assets/guardrails/README.md +61 -25
  50. package/assets/guardrails/methodology/ux/accessibility-standards.md +38 -0
  51. package/assets/guardrails/methodology/ux/content-design.md +34 -0
  52. package/assets/guardrails/methodology/ux/interaction-states.md +45 -0
  53. package/assets/guardrails/methodology/ux/journey-mapping.md +41 -0
  54. package/assets/guardrails/project-specific/domain/domain-requirements.md +25 -38
  55. package/assets/guardrails/project-specific/domain-rule-bindings.md +33 -69
  56. package/assets/guardrails/project-specific/frontend/ui-requirements.md +2 -2
  57. package/assets/guardrails/project-specific/service/technical-requirements.md +2 -2
  58. package/assets/guardrails/project-specific/tech-rule-bindings.md +16 -13
  59. package/assets/guardrails/sample-healthcare/domain/domain-requirements.md +58 -0
  60. package/assets/guardrails/sample-healthcare/domain-rule-bindings.md +138 -0
  61. package/assets/guardrails/sample-healthcare/frontend/ui-requirements.md +43 -0
  62. package/assets/guardrails/sample-healthcare/service/technical-requirements.md +40 -0
  63. package/assets/guardrails/sample-healthcare/tech-rule-bindings.md +303 -0
  64. package/dist/commands/init.d.ts.map +1 -1
  65. package/dist/commands/init.js +216 -7
  66. package/dist/commands/init.js.map +1 -1
  67. package/dist/utils/config.js +1 -1
  68. package/dist/utils/config.js.map +1 -1
  69. package/dist/utils/foundation.d.ts +36 -0
  70. package/dist/utils/foundation.d.ts.map +1 -0
  71. package/dist/utils/foundation.js +109 -0
  72. package/dist/utils/foundation.js.map +1 -0
  73. package/dist/utils/paths.js +1 -1
  74. package/dist/utils/paths.js.map +1 -1
  75. package/package.json +1 -1
package/README.md CHANGED
@@ -37,7 +37,6 @@ git clone https://dev.azure.com/bytestrone-labs/AppWeaver/_git/appweaver
37
37
  cd platform/Appweaver.Spec.Cli
38
38
  npm install
39
39
  npm run build
40
- # Then run via node
41
40
  dist/index.js init
42
41
  ```
43
42
 
@@ -53,18 +52,12 @@ aw-spec init
53
52
 
54
53
  # Or specify a target directory
55
54
  aw-spec init my-project
56
-
57
- # Non-interactive (uses Claude skills by default)
58
- aw-spec init -y
59
-
60
- # Choose agent explicitly
61
- aw-spec init --agent antigravity
62
- aw-spec init --agent kilocode
63
-
64
- # Preview what would be copied (no changes)
65
- aw-spec init --dry-run
66
55
  ```
67
56
 
57
+ The interactive wizard prompts you to choose:
58
+ - **Project Scaffolding**: Unpacks clean enterprise starter code (Java Spring Boot Hexagonal, .NET WebApi Vertical Slice, or Modular Monolith) without agent folders.
59
+ - **Spec Workflow Setup**: Installs `.aw-spec/` pipelines and AI agent skills (Claude Code, Antigravity, Cursor, KiloCode).
60
+
68
61
  After initialization:
69
62
 
70
63
  ```bash
@@ -81,39 +74,20 @@ aw-spec specify "Your feature description"
81
74
 
82
75
  ### `aw-spec init [directory]`
83
76
 
84
- Initialize a new AppWeaver Spec project.
77
+ Initialize an AppWeaver project: Project Scaffolding or Spec Workflow Setup.
85
78
 
86
79
  | Option | Description |
87
80
  |--------|-------------|
88
- | `directory` | Target directory (default: current directory) |
89
- | `-a, --agent <agent>` | Agent skills to include: `claude`, `antigravity`, `kilocode` (default: prompt) |
90
- | `-y, --yes` | Skip prompts, use defaults (Claude) |
91
- | `--dry-run` | Show what would be copied without making changes |
92
-
93
- **Copied structure:**
94
- ```
95
- target-dir/
96
- ├── .aw-spec/ # Core spec configuration
97
- │ ├── extensions.yml # Extension registry
98
- │ ├── feature.json # Feature tracking
99
- │ ├── workflows/ # Workflow definitions
100
- │ ├── templates/ # Spec/plan/task templates
101
- │ └── scripts/ # Bash/PowerShell helpers
102
- ├── docs/ # Documentation scaffold
103
- │ ├── architecture/
104
- │ ├── domain/
105
- │ ├── governance/
106
- │ ├── security/
107
- │ ├── domainspecs/
108
- │ ├── glossary/
109
- │ ├── VerticalSlice/ # Vertical slice packaging
110
- │ └── ...
111
- └── .claude/skills/ # Or .agents/skills/, .kilocode/
112
- ├── aw-spec-specify/
113
- ├── aw-spec-plan/
114
- ├── aw-spec-implement/
115
- └── ... (13 skills total)
116
- ```
81
+ | `[directory]` | Target directory (default: current directory `.`) |
82
+ | `-i, --intent <intent>` | Action intent: `scaffolding` (Project Scaffolding) or `spec` (Spec Workflow Setup) |
83
+ | `-b, --backend <stack>` | Backend stack: `java-spring`, `dotnet-webapi`, or `none` |
84
+ | `-f, --frontend <stack>` | Frontend stack: `nextjs`, `react-vite`, or `none` |
85
+ | `--foundation <type>` | Foundation type: `hexagonal`, `vertical-slice`, `modular-monolith` |
86
+ | `--app-name <name>` | Application name for scaffolding |
87
+ | `--package <package>` | Root package or namespace |
88
+ | `-a, --agent <agent>` | Agent skills (for spec workflow): `claude`, `antigravity`, `kilocode`, `cursor`, etc. |
89
+ | `-y, --yes` | Skip prompts and use defaults |
90
+ | `--dry-run` | Show what would be created without making changes |
117
91
 
118
92
  ### `aw-spec doctor`
119
93
 
@@ -152,62 +126,83 @@ Choose based on your AI assistant. Skills provide guided workflows for spec-driv
152
126
 
153
127
  ## Project Structure (After Init)
154
128
 
129
+ The resulting structure depends on the chosen intent:
130
+
131
+ ### Option A: Project Scaffolding (Clean Application Code)
132
+
133
+ When choosing **Project Scaffolding**, the foundation unpacks directly into your project root. No `.aw-spec/` or AI agent folders are added, keeping the codebase completely clean and standard.
134
+
135
+ **Example: Java Spring Boot — Hexagonal Architecture (`hexagonal`):**
155
136
  ```
156
137
  my-project/
157
- ├── .aw-spec/
158
- │ ├── extensions.yml
159
- │ ├── feature.json
160
- │ ├── init-options.json
161
- │ ├── integration.json
138
+ ├── src/
139
+ │ ├── main/
140
+ │ │ ├── java/com/mycompany/order/
141
+ │ │ │ ├── domain/ # Enterprise domain models & business rules
142
+ │ │ │ ├── application/ # Use cases, inbound/outbound ports
143
+ │ │ │ └── infrastructure/ # Adapters: Web REST controllers, DB repositories
144
+ │ │ └── resources/
145
+ │ │ └── application.yml
146
+ │ └── test/
147
+ ├── pom.xml
148
+ ├── mvnw / mvnw.cmd
149
+ └── README.md
150
+ ```
151
+
152
+ **Example: .NET WebApi — Vertical Slice Architecture (`vertical-slice`):**
153
+ ```
154
+ my-project/
155
+ ├── src/
156
+ │ └── OrderService/
157
+ │ ├── Features/ # Self-contained vertical slices (Commands, Queries, Endpoints)
158
+ │ │ └── Orders/
159
+ │ │ ├── CreateOrder/
160
+ │ │ └── GetOrderById/
161
+ │ ├── Common/ # Cross-cutting concerns & behaviors
162
+ │ ├── Program.cs
163
+ │ └── OrderService.csproj
164
+ ├── OrderService.sln
165
+ └── README.md
166
+ ```
167
+
168
+ ---
169
+
170
+ ### Option B: Spec Workflow Setup (AI Agent Skills & Orchestration)
171
+
172
+ When choosing **Spec Workflow Setup**, the CLI installs the spec-driven development orchestration files and selected AI agent skills:
173
+
174
+ ```
175
+ my-project/
176
+ ├── .aw-spec/ # Core spec configuration
177
+ │ ├── extensions.yml # Extension registry
178
+ │ ├── feature.json # Feature tracking
179
+ │ ├── init-options.json # Stored setup configuration
180
+ │ ├── integration.json # Integration settings
162
181
  │ ├── workflows/
163
- │ │ └── workflow-registry.json
182
+ │ │ └── workflow-registry.json # Workflow pipeline definitions
164
183
  │ ├── extensions/
165
184
  │ │ └── agent-context/
166
- │ │ ├── scripts/
167
- │ │ └── commands/
168
- │ ├── templates/
185
+ │ ├── templates/ # Spec, plan, and task templates
169
186
  │ │ ├── spec-template.md
170
187
  │ │ ├── plan-template.md
171
188
  │ │ └── tasks-template.md
172
- │ ├── scripts/
173
- │ │ └── bash/
174
- │ │ └── common.sh
175
- │ ├── integrations/
189
+ │ ├── scripts/ # Automation & validation scripts
176
190
  │ └── memory/
177
- ├── docs/
191
+ ├── docs/ # Architecture & governance reference docs
178
192
  │ ├── architecture/
179
193
  │ ├── domain/
180
194
  │ ├── governance/
181
195
  │ ├── security/
182
- │ ├── domainspecs/
183
- │ ├── glossary/
184
- │ ├── interop/
185
- │ ├── ModularMonolith/
186
- │ ├── VerticalSlice/
187
- │ │ ├── VerticalSlice.pack.txt
188
- │ │ ├── PACKAGING.md
189
- │ │ ├── pack-foundation.sh
190
- │ │ └── unpack-foundation.sh
191
- │ ├── command.txt
192
- │ ├── components/
193
- │ ├── pharma-constitution.my-ref.md
194
- │ ├── requirement-spec.txt
195
- │ ├── technology-constitution.md
196
- │ └── README.md
197
- └── .claude/skills/ # Or .agents/skills/, .kilocode/
198
- ├── aw-spec-addcomponent/
199
- ├── aw-spec-agent-context-update/
200
- ├── aw-spec-analyze/
196
+ │ └── ...
197
+ └── .agents/skills/ # Or .claude/skills/, .kilocode/
198
+ ├── aw-spec-specify/
199
+ ├── aw-spec-plan/
200
+ ├── aw-spec-implement/
201
+ ├── aw-spec-tasks/
201
202
  ├── aw-spec-checklist/
202
203
  ├── aw-spec-clarify/
203
- ├── aw-spec-constitution/
204
204
  ├── aw-spec-foundation/
205
- ├── aw-spec-implement/
206
- ├── aw-spec-plan/
207
- ├── aw-spec-select-domain/
208
- ├── aw-spec-specify/
209
- ├── aw-spec-tasks/
210
- └── aw-spec-taskstoissues/
205
+ └── ... (13 skills total)
211
206
  ```
212
207
 
213
208
  ---
@@ -16,6 +16,7 @@ specs/<Context>/
16
16
  domain-model.md # STRUCTURE — aggregates, entities, invariants (BR-nnn) — shared
17
17
  <Aggregate>/
18
18
  spec.md # BEHAVIOUR (tech-agnostic) — WHAT / WHY
19
+ api-plan.md # the API CONTRACT — the endpoints the service publishes
19
20
  backend-plan.md # structure & decisions (tech-agnostic HLD) — the MEDIATOR
20
21
  changes/ # open + archived change records (delta-spec + delta plans)
21
22
  ```
@@ -38,8 +39,10 @@ FR/US/SC/CN/DC/IC
38
39
 
39
40
  - **One design per feature.** The four clean-architecture layers (Domain,
40
41
  Application, API, Infrastructure) are **sections** of this one document, each at
41
- design level. A feature is a capability scope the developer chooses — it may act on
42
- several aggregates, and several features may act on one; its operations are user
42
+ design level — except the endpoints themselves, which are in `api-plan.md` (see
43
+ *The API plan* below); §3 points there. A feature is a capability scope the
44
+ developer chooses — it may act on several aggregates, and several features may act
45
+ on one; its operations are user
43
46
  stories inside it. *(This is
44
47
  the **greenfield** layout, authored from `design-template.md`. See the Brownfield
45
48
  variant below for reverse-engineered / existing-codebase designs.)*
@@ -67,6 +70,37 @@ FR/US/SC/CN/DC/IC
67
70
  applied in the `implement` phase. `backend-plan.md` stays feature-specific and
68
71
  technology-agnostic.
69
72
 
73
+ ## The API plan (`api-plan.md`)
74
+
75
+ The endpoints a feature's service publishes — route, verb, operation id, request and
76
+ response shapes, the error contract — and its answers to the frontend lane's requests are
77
+ **one document of their own**, `api-plan.md`, beside the backend plan. It is the API
78
+ contract between the lanes: the frontend plan binds to its operation ids, `implement`
79
+ serves it, and `contract-draft` writes `api-draft.json` from it by script. The backend plan
80
+ realises each endpoint as a use-case and names it under the endpoint's **Maps to**.
81
+
82
+ - **A master, like `spec.md`.** A change plans its API in
83
+ `changes/<CR-id>/delta-api-plan.md` — a Contract deltas table (one row per endpoint
84
+ `added`, `changed` or `removed`), each added or changed endpoint written whole, and the
85
+ requests the change answers — and `finalize-delta` merges it into `api-plan.md` by script
86
+ (`contract-merge`), by whole endpoint block keyed by operation id. The backend plan is
87
+ derived and never merged; the API plan is merged, so what a change adds or changes is in
88
+ the document every redraw reads from the moment the change is merged.
89
+ - **One form in every project.** Each endpoint is a block under `## Endpoints`: the heading
90
+ `### `VERB /route`` and its fields, every shape `{ field: type }`. The contract scripts
91
+ read exactly that form, so it is the kit's template (`api-plan-template.md`,
92
+ `delta-api-plan-template.md`) in greenfield and brownfield repos alike; an override
93
+ generated by `onboard` shapes the backend plan, never the API plan.
94
+ - **Operation ids are stable.** An endpoint keeps its id for life; a new one takes an id
95
+ unique across the service. An endpoint the code already serves keeps the id the code
96
+ publishes, and one it serves under no id writes `—`, never an invented id.
97
+ - **Authored first.** `plan` writes the API plan before the backend plan on both paths —
98
+ the master, and a change's delta — so the contract is fixed before what realises it.
99
+ - **Features planned before it** keep their endpoints in the backend plan's API section,
100
+ which every reader falls back to while no `api-plan.md` exists. A re-derivation
101
+ (`plan main`) offers to move them once, by script (`api-split`), and `finalize-delta`
102
+ moves them when it first merges a change's API into the feature.
103
+
70
104
  ## Brownfield variant (existing codebases)
71
105
 
72
106
  A design reverse-engineered from — or added forward to — an **existing** codebase is
@@ -82,18 +116,14 @@ same traceability spine and the two deferral ledgers — with **one difference t
82
116
  are **derived from the code's own organisation** (its folders / projects / modules)
83
117
  rather than the fixed Domain/Application/API/Infrastructure four. A component the
84
118
  code has that fits no textbook layer (a UI tier, a worker, a host project) gets its
85
- own section; a layer the code lacks does not appear. Three neutral anchors are kept
119
+ own section; a layer the code lacks does not appear. Two neutral anchors are kept
86
120
  because every system has them and the tooling keys on them: **§1 is the domain/data
87
- model** (the cross-reference tool reads it for `<Other>Id` reference edges), one
121
+ model** (the cross-reference tool reads it for `<Other>Id` reference edges), and one
88
122
  **§2 subsection is the External Integrations table** (matched by heading keyword, so
89
- `aw-xref` extracts contract edges from either layout), and **each published endpoint
90
- is an endpoint block** — the greenfield §3 form, `#### `VERB /route`` with its
91
- **Operation id**, followed by the "Requests from the frontend lane" table — inside
92
- whichever §2 axis publishes it. The contract scripts read exactly that form: the API
93
- draft is written from the headings, and the request ledger between the two lanes reads
94
- the operation ids and the table. An endpoint the code already serves keeps the id it
95
- publishes; where it publishes none the plan writes `—` and records a §5 assumption,
96
- never an invented id. The `debt` ledger records
123
+ `aw-xref` extracts contract edges from either layout). The published endpoints are not
124
+ in the plan at all: they are in the feature's `api-plan.md`, whose form is the same in
125
+ every project (see *The API plan* above), and the §2 axis that publishes them ends with
126
+ a line pointing there. The `debt` ledger records
97
127
  only debt the **code itself** evidences (stubs, dead code, torn seams) — being
98
128
  organised unlike a reference architecture is **not** debt, it is the as-built shape;
99
129
  migrating toward a target is a separate modernization decision.
@@ -129,7 +159,7 @@ states it can be in, and the framework binds in the FRONTEND LANE of `implement`
129
159
 
130
160
  **§5 Contract Binding is the lane boundary.** The UI design reads the whole spec — the
131
161
  experience is stated there — but only the service's **published surface**: the spec's `IC-`
132
- ids and the API contracts `backend-plan.md` states. No table, handler or persistence choice
162
+ ids and the endpoints `api-plan.md` states. No table, handler or persistence choice
133
163
  crosses that line, and an operation the experience needs that the surface does not offer is
134
164
  a contract delta raised back to the service lane, never a client workaround. ⌛ `design`
135
165
  will emit that surface as a `design-contract.md` projection; the rule does not change when
@@ -138,11 +168,11 @@ it does, only what §5 reads.
138
168
  **Contract deltas are a request ledger between the two plans.** frontend-plan.md §5 "Contract
139
169
  deltas needed" is a table, one `RQ-n` per operation the experience needs and the surface does
140
170
  not offer, with the operation id and field shapes it proposes; a request keeps its id for
141
- life. backend-plan.md §3 answers each in its "Requests from the frontend lane" table —
171
+ life. api-plan.md answers each in its "Requests from the frontend lane" table —
142
172
  `published` under an operation id, or `declined` with the reason — so each lane's developer
143
- writes only their own plan. `contract-requests` reads both: an open request is a backend-lane
173
+ writes only their own plans. `contract-requests` reads both: an open request is a backend-lane
144
174
  gap at `analyze-plan`, a declined one or an answered one not yet re-bound is a frontend-lane
145
- gap. With no backend plan at all, every binding is a request.
175
+ gap. With no API plan at all, every binding is a request.
146
176
 
147
177
  **`UX-` lives here and only here.** The service design excludes the spec's Experience
148
178
  Standards by contract — it realises no experience standard, and a traceability row for one
@@ -198,16 +228,18 @@ backend-plan.md:
198
228
 
199
229
  - `CreateOrder` = US-1; `UpdateOrder` = US-2.
200
230
  - Adding `UpdateOrder` is an additive CR: a **delta-spec** (`+US-2`), the change's own
201
- **model delta** where the domain moves, and **delta lane plans** (`ADDED` new
202
- use-case/endpoint sections, `MODIFIED` the shared Order/root and repository sections —
203
- see `delta-design-template.md`). All three live inside `changes/<CR-id>/`, and the
204
- MASTERS are not touched while the change is open: `plan` writes
205
- `delta-backend-plan.md` / `delta-frontend-plan.md` beside the delta-spec, never
206
- `backend-plan.md`. `implement` generates only what the delta marks ADDED or MODIFIED;
207
- regression re-tests the shared-file dependents.
231
+ **model delta** where the domain moves, a **delta API plan** (the `UpdateOrder` endpoint,
232
+ `added` — see `delta-api-plan-template.md`) and **delta lane plans** (`ADDED` the new
233
+ use-case, `MODIFIED` the shared Order/root and repository sections — see
234
+ `delta-design-template.md`). All of them live inside `changes/<CR-id>/`, and the
235
+ MASTERS are not touched while the change is open: `plan` writes `delta-api-plan.md`,
236
+ `delta-backend-plan.md` and `delta-frontend-plan.md` beside the delta-spec, never
237
+ `api-plan.md` or `backend-plan.md`. `implement` generates only what the delta marks
238
+ ADDED or MODIFIED; regression re-tests the shared-file dependents.
208
239
  - **Nothing in the plan phase bumps a version or archives a change.** `finalize-delta`
209
- MERGES the delta into `spec.md` and the context's `domain-model.md` (not the lane
210
- plans — they are derived from those two and are re-derived by `/appweaver plan main`),
240
+ MERGES the delta into `spec.md`, the context's `domain-model.md` and `api-plan.md` (not
241
+ the lane plans — they are derived from those three and are re-derived by
242
+ `/appweaver plan main`),
211
243
  and `close-delta` is the sole stage that archives `changes/<CR-id>/` and moves the
212
244
  version (`v1.0 → v1.1`). The two are deliberately separate so a red `analyze-slice`
213
245
  between them is still "fix and re-run" rather than a change that already shipped.
@@ -56,9 +56,10 @@ no heading to key on. Where the two lanes are folded into one command, as `plan`
56
56
  | `run_from` | *(optional)* **where the commands run**: `repo` (the default, and the shape of every lane written before this key existed) at the repository root, or `root` inside the lane root folder. `select-stack` decides it from where the stack's build file sits — see §3.1 |
57
57
  | `build` / `test` / `run` | project-supplied command strings the engine shells out to. These are the matched **profile's** defaults and may not fit a legacy layout — reviewing them is what `select-stack` is for. `{{root}}` in a command resolves to this lane's `root`, as seen from where the command runs (§4.2) |
58
58
  | `migrate` | *(optional)* the lane's schema-migration command, recorded only when the profile declares one. Absent, `run-migrate` falls back to `dotnet ef` and otherwise reports that nothing ran (§4.2) |
59
- | `contract_run` | *(optional, backend)* the command that starts the service on its own so `implement` can export its API document (§4.5). Absent, the profile's is used. `foundation` sets it from a pack's `<pack>.lane.json` |
60
- | `contract` | *(optional, backend)* the URL the running service serves its API document at (§4.5). Absent, the profile's is used |
61
- | `client` | *(optional, frontend)* the command that generates the frontend's API client from that document; `{{contract}}` in it is the document's path. No shipped profile has one: `implement` asks the developer the first time and records the answer here (§4.5) |
59
+ | `contract_write` | *(optional, backend)* a command that writes the service's as-built API document to `{{contract}}` with no server started, which `analyze-slice` runs to check the API the code serves against the plan (§4.5). `foundation` sets it from a pack's `<pack>.lane.json` or a spec's header, or asks for it on the spec route |
60
+ | `contract_run` | *(optional, backend)* or: the command that starts the service on its own so its document can be fetched (§4.5). `foundation` sets it from a pack's `<pack>.lane.json` or a spec's header |
61
+ | `contract` | *(optional, backend)* with `contract_run`: the URL the running service serves its API document at (§4.5) |
62
+ | `client` | *(optional, frontend)* the command that generates the frontend's API client from the API document; `{{contract}}` in it is the document's path. No shipped profile has one: `implement` asks the developer the first time and records the answer here (§4.5) |
62
63
 
63
64
  ### Three properties matter more than the schema
64
65
 
@@ -218,11 +219,11 @@ behaviour from before the file existed.
218
219
 
219
220
  | Phase | With a working lane narrower than the declared lanes |
220
221
  |---|---|
221
- | `plan` | scaffolds, authors, re-derives and delta-plans only the working lane; the menu and the re-derive question look only at its master. The other lane's plan is read — the frontend plan binds to the backend plan's published surface. The backend half answers the frontend's open contract requests and writes `api-draft.json`; the frontend half re-binds answered requests and raises new ones (§4.5) |
222
- | `analyze-plan` | gates, repairs and receipts only the working lane's plan (`.aw-plan-gate.<lane>.json`, that lane's verdict); check 3 reads the other plan and the request ledger, and a finding only it can close is reported for its developer (`plan-gaps --lanes` → `other`). The frontend receipt also hashes the backend plan's §3, so a backend contract change re-gates the frontend |
223
- | `implement` | offers, receipt-checks and generates only the working lane; a refused receipt skips that lane with the reason. The backend half exports the API document; the frontend half reads it, combined with the drafts, and never starts the service (§4.5) |
224
- | `build` | compiles only the working lane (`build-compile --kind`); `lane-verify --working-only` does not require the other lane's root on disk. With the backend worked, a green compile re-exports the API document |
225
- | `analyze-slice` | tests only the working lane (`test-run --kind`); the fix loops' file list is narrowed with `concept-paths --under`; the composition pass runs when the backend is worked |
222
+ | `plan` | scaffolds, authors, re-derives and delta-plans only the working lane; the menu and the re-derive question look only at its master. The frontend plan binds to the API plan (`api-plan.md`), the backend lane's published surface, and never reads the backend plan. The backend half writes the API plan first — answering the frontend's open contract requests there — and `api-draft.json` from it; the frontend half re-binds answered requests and raises new ones (§4.5) |
223
+ | `analyze-plan` | gates, repairs and receipts only the working lane's documents (`.aw-plan-gate.<lane>.json`, that lane's verdict; the backend's covers `api-plan.md` too); check 3 reads the API plan, the frontend plan and the request ledger, and a finding only the other lane can close is reported for its developer (`plan-gaps --lanes` → `other`). The frontend receipt also hashes `api-plan.md`, so a contract change re-gates the frontend |
224
+ | `implement` | offers, receipt-checks and generates only the working lane; a refused receipt skips that lane with the reason. The backend half serves every endpoint of `api-plan.md` as written; the frontend half binds to the features' drafts, combined, and never starts the service (§4.5) |
225
+ | `build` | compiles only the working lane (`build-compile --kind`); `lane-verify --working-only` does not require the other lane's root on disk |
226
+ | `analyze-slice` | tests only the working lane (`test-run --kind`); the fix loops' file list is narrowed with `concept-paths --under`; the composition pass and the API check — the built service against the API plan (§4.5) — run when the backend is worked |
226
227
  | `specify`, `finalize-delta`, `close-delta` | **ignore it** — the spec is written whole, and a change merges and closes with whatever its lanes delivered |
227
228
 
228
229
  **A change records the lanes it touches**, separately from anyone's working lane: the
@@ -292,9 +293,11 @@ workflow.**
292
293
  "host_patterns": [], // optional — where the runnable project sits, for
293
294
  // `{{host}}` in a command — see §4.2
294
295
  "migrate": "", // optional — schema migration, if the stack has one
295
- "contract_run": "", // optional, backend — start the service to export
296
- // its API document — see §4.5
297
- "contract": "", // optional, backend — the URL it serves it at
296
+ "contract_write": "", // optional, backend — write the as-built API
297
+ // document to {{contract}} — see §4.5
298
+ "contract_run": "", // optional, backend — or start the service to
299
+ // fetch it …
300
+ "contract": "", // … from this URL
298
301
  "client": "", // optional, frontend — generate the API client
299
302
  // from `{{contract}}` — see §4.5
300
303
  "prototype_run": "npm run dev --prefix prototype", // frontend only — fills the prototype block
@@ -514,53 +517,78 @@ A layout the table gets wrong is fixed by writing `test_root` on the lane in `st
514
517
  | `go-chi` | `backend/` | *(inside the lane root folder)* | `internal/` | — |
515
518
  | every frontend | `frontend/` | *(inside the lane root folder)* | `web/` | — |
516
519
 
517
- ### 4.5 `contract_run`, `contract` and `client` — the API contract between the lanes
518
-
519
- The frontend lane binds to the service through the service's published API document, and
520
- the document that counts is the one the **built code** serves. **The backend lane publishes
521
- it and the frontend lane reads it**, so the two can be built by different developers at
522
- different times, and a frontend developer never needs the service's code built or its
523
- runtime installed. Every step warns rather than stops:
524
-
525
- 1. **Export** (`contract-export`) — run by whoever works on the service lane: `implement`
526
- after its backend half generates, and `build` after a green compile. Start the service
527
- with the backend lane's `contract_run`, fetch its `contract` URL, write the document to
528
- `<service lane root folder>/contracts/openapi.json`, and stop the service with
529
- everything it started. A service already answering at the URL is used as it is, and
530
- the run says it may be older than the code. The document is committed with the service.
531
- 2. **Draft** (`contract-draft`) — run by the backend lane's `plan` and `analyze-plan`:
532
- `backend-plan.md` §3 drafted by script into `specs/<ctx>/<feature>/api-draft.json`, an
533
- OpenAPI document of what the plan says the service will serve. Committed with the plan.
534
- 3. **Combine** (`contract-combine`) — run by the frontend half of `implement`: the exported
535
- document plus every drafted operation it does not serve yet, each marked `x-aw-draft`,
536
- written to `.appweaver/contracts/openapi.combined.json` (not committed). A drafted
537
- operation whose id the service serves drops out; one whose route and verb the service
538
- answers under another id is left out and reported.
539
- 4. **Client** (`contract-client --doc`) — run the frontend lane's `client` command, with
520
+ ### 4.5 `contract_write`, `contract_run`, `contract` and `client` — the API between the lanes
521
+
522
+ **The contract between the lanes is the API plan.** Each feature's `api-plan.md`, beside its
523
+ backend plan, states the endpoints the service publishes — route, verb, operation id, field
524
+ shapes, errors — in one form in every project, so the scripts read it the same way on every stack.
525
+ The frontend lane binds to those endpoints, drafted from the API plan by script, and the built
526
+ service is checked against that document rather than read from. So the frontend works the same on
527
+ every stack and in a brownfield repo, can be built before the backend is, and never needs the
528
+ service's code built, started or its runtime installed. The API plan is a master: a change plans
529
+ its API in `changes/<CR-id>/delta-api-plan.md`, and `finalize-delta` merges it in by script. A
530
+ feature planned before API plans existed keeps its endpoints in its backend plan's API section,
531
+ which every step below reads instead until `api-split` moves them out. Every step warns rather
532
+ than stops, except the backend gates' check and the merge:
533
+
534
+ 1. **Draft** (`contract-draft`) — run by the backend lane's `plan` and `analyze-plan`, and by
535
+ `adopt`: `api-plan.md` drafted by script into `specs/<ctx>/<feature>/api-draft.json`.
536
+ Committed with the plan. A shape not written as `{ field: type }` is reported, since the
537
+ frontend's client gets it untyped, and so is an operation the previous draft had and this one
538
+ does not.
539
+ 2. **Draft a change** (`contract-draft --cr`) — run by `plan` and `analyze-plan-delta` on a
540
+ change: the endpoints its `delta-api-plan.md` adds or changes, written as full blocks, and the
541
+ ones it removes, into `changes/<CR-id>/api-draft.json`.
542
+ 3. **Merge** (`contract-merge`) — run by `finalize-delta`: the change's delta API plan merged
543
+ into `api-plan.md` by whole endpoint block, keyed by operation id, with the requests it
544
+ answers; `api-draft.json` is redrawn from the result. A run that does not answer stops
545
+ `finalize-delta` with the command that finishes it, and `close-delta` will not archive a
546
+ change whose API delta `api-plan.md` has not recorded (`contract-merge --check`).
547
+ 4. **Combine** (`contract-combine`) — run by the frontend half of `implement`: every feature's
548
+ draft with each open change's applied over it, written to
549
+ `.appweaver/contracts/openapi.combined.json` (not committed). An operation an open change
550
+ removes stays, marked `deprecated` with the change that removes it, so a frontend still bound
551
+ to it is told rather than broken. Where an open change serves another operation on its
552
+ route, that one takes the route, and the removed one moves to the document's `x-aw-removed`
553
+ list with its route and change, so a binding to it is still reported as removed.
554
+ 5. **Client** (`contract-client --doc`) — run the frontend lane's `client` command, with
540
555
  `{{contract}}` standing for the combined document as seen from where the command runs.
541
- 5. **Check** (`contract-check`) — every operation id the frontend plan cites must be an
542
- `operationId` in the combined document; the ids that are only drafts are named apart.
556
+ 6. **Check** (`contract-check`) — every operation id the frontend plan cites must be an
557
+ `operationId` in the combined document; the ids an open change removes, and those the
558
+ service does not serve yet, are named apart.
559
+ 7. **Verify** (`contract-export` + `contract-verify`) — run by the backend gates: after its fix
560
+ loops `analyze-slice` writes the service's AS-BUILT document to
561
+ `<service lane root folder>/contracts/openapi.json` and compares it with the feature's draft
562
+ (plus a change merged and not yet closed); `analyze-slice-delta` does it for the change's own
563
+ draft. A planned endpoint not served, or served under another route, verb or operation id,
564
+ fails the gate; a field or status code that differs warns. A feature whose plan names no
565
+ endpoint, or a change that drafts no API change, is not checked and the lane's export is
566
+ not run (`contract-verify --check` asks first). Committed, the as-built document
567
+ also adds the operations no plan describes to the frontend's combined document, marked
568
+ `x-aw-unplanned` — the endpoints of a brownfield feature nobody has adopted yet.
543
569
 
544
570
  Between the plans, what the frontend needs and the backend does not publish travels as a
545
571
  **request ledger**: `frontend-plan.md` §5 "Contract deltas needed" holds one `RQ-n` per
546
- request, and `backend-plan.md` §3 "Requests from the frontend lane" answers each —
572
+ request, and `api-plan.md` "Requests from the frontend lane" answers each —
547
573
  published under an operation id, or declined. `contract-requests` reads both (§6).
548
574
 
549
- Each key is read from the lane first and from its profile second, so a lane declared
550
- before the keys existed still answers them. Where the values come from:
575
+ **How the as-built document is written is the lane's setting**, because only the project knows
576
+ it, and a lane that sets none is simply not checked:
551
577
 
552
- | Key | Profile default | Set on the lane by |
578
+ | Key | What it is | Set on the lane by |
553
579
  |---|---|---|
554
- | `contract_run` | `dotnet-webapi`: `dotnet run --project {{host}} -- --environment Development --urls http://localhost:5000`<br>`java-spring`: `./mvnw spring-boot:run -Dspring-boot.run.arguments=--server.port=8080` | `foundation`: on the pack route from the pack's `<pack>.lane.json` — the shipped .NET packs start their API project alone (the AppHost needs Docker), the Java `Hexagonal` pack its one Maven module; on the spec route from the spec's `# contract-run:` header line, or the operator's answer when it has none |
555
- | `contract` | `dotnet-webapi`: `http://localhost:5000/swagger/v1/swagger.json`<br>`java-spring`: `http://localhost:8080/v3/api-docs` (springdoc's default path) | `foundation`, the same way — the `# contract:` header line on the spec route |
556
- | `client` | none — no generator is assumed | `foundation` on the spec route, from the `# client:` header line or the operator's answer; else `implement`, which asks the first time and records the answer |
580
+ | `contract_write` | a command that writes the service's OpenAPI JSON to `{{contract}}` with no server started — the stack's own generator, or a script that loads the application and dumps its document (a FastAPI app's `app.openapi()`, for instance). Preferred: nothing of the service runs. It writes to a scratch path, and only a document that reads as OpenAPI replaces the committed one | `foundation`: from the pack's `<pack>.lane.json`; on the spec route from the spec's `# contract-write:` header line, or the operator's answer when the header gives no way |
581
+ | `contract_run` + `contract` | start the service on its own, fetch its document from the URL, stop it and everything it started. For a stack that can only serve its document; a service already answering at the URL is used, and said to maybe be older than the code. Starting a service runs its startup code — the shipped .NET packs migrate a local SQLite file | `foundation`: from the pack's `<pack>.lane.json` (the shipped packs set these), or the spec's `# contract-run:` / `# contract:` header lines |
582
+ | `client` | the frontend's client generator | `foundation` on the spec route, from the `# client:` header line or the operator's answer; else `implement`, which asks the first time and records the answer |
557
583
 
558
- On the spec route an empty answer keeps the lane's current value, so a lane nobody set
559
- anything on stays on the profile's default. `foundations/foundation.spec.template.txt`
560
- shows the three header lines; `<App>` in them is the app name given at `foundation`.
584
+ No stack profile sets a way to write the document: starting a service runs whatever its
585
+ configuration points at, so the kit never does it unless the project says so. Each key is still
586
+ read from the lane first and from its profile second, so a project's own profile may carry one.
587
+ `foundations/foundation.spec.template.txt` shows the header lines; `<App>` in them is the app name
588
+ given at `foundation`.
561
589
 
562
590
  `--environment Development` matters for the .NET packs: outside Development they redirect
563
- to HTTPS, and the export fetches over http. Their API projects also read
591
+ to HTTPS, and `contract-export` fetches over http. Their API projects also read
564
592
  `ConnectionStrings:SqliteConnection` when started without the AppHost, and the packs'
565
593
  configuration carries none, so their commands pass one. A pack's `<pack>.lane.json` sits
566
594
  beside its `.pack.txt`, names the pack's sentinel the way its files do, and is renamed with
@@ -584,10 +612,10 @@ grep -rl "lane-declare" .appweaver/orchestrator/workflows/ # must print exactl
584
612
  # aw-spec-select-stack.orch.yaml — a person picks
585
613
  ```
586
614
 
587
- **`lane-set` changes three keys on a lane that is already there, and nothing else** —
588
- `contract_run`, `contract` and `client` (§4.5). Its callers are `foundation`, recording
589
- what a pack knows about starting its service, and `implement`, recording the client
590
- command a developer types. They cannot use `lane-declare`, which rebuilds the whole lane
615
+ **`lane-set` changes four keys on a lane that is already there, and nothing else** —
616
+ `contract_write`, `contract_run`, `contract` and `client` (§4.5). Its callers are
617
+ `foundation`, recording what a pack or a spec knows about writing its service's API
618
+ document, and `implement`, recording the client command a developer types. They cannot use `lane-declare`, which rebuilds the whole lane
591
619
  and would reset every command on it to the profile's default.
592
620
 
593
621
  `onboard` used to be a second caller. Before `select-stack` was the first command of the
@@ -689,15 +717,19 @@ implementation and the twins cannot drift.
689
717
  |---|---|
690
718
  | `stack-list [--kind k] [--preselect text] [--include-none] [--suggest]` | enumerate the installed profiles; returns `select_options[]`, and `preselect` when the text names one of *this kind's* ids. `--suggest` also runs detection, so the menu **leads with** the stack this repo's files point at and `root_options[]` leads with the directory the evidence sits in |
691
719
  | `stack-detect [--kind k] [--exclude-root p]…` | match the repo's OWN files against the installed profiles — the brownfield candidate list, since an existing repo already answered the question. Writes nothing. `--exclude-root` keeps a service profile from relocating onto a subtree another lane owns |
720
+ | `stack-rules --kind k [--declared]` | for each profile of the kind, how many of the files the active project's `tech-rule-bindings.md` names under `guardrails/technology/{{<kind>_stack}}/` exist with that profile put in, resolved with `resolve-tech`'s placeholder table: `complete`, `partial`, `none`, or `not-mapped` when the map names no stack folder for the lane. `note` is the line `select-stack` puts in the menu; `--declared` adds the declared lane's verdict, `ok`, and the `warning` `select-stack` raises when it is partial or none. Read-only (§7) |
692
721
  | `lane-declare --profile <id\|label\|none\|detected> [--kind k] [--id lane] [--source-path\|--root p] [--stack label] [--origin declared\|reverse-engineered] [--build/--test/--run/--migrate c] [--run-from repo\|root] [--no-prototype] [--require-existing-root]` | upsert a WHOLE lane — its one caller is `select-stack` (§5). `detected` declares a stack the kit ships no profile for (needs `--stack` and a lane root folder), which is how a legacy WebForms, JSP or ERB lane gets recorded at all |
693
- | `lane-set (--id lane\|--kind k) [--set KEY=VALUE]… [--unset KEY]…` | change only `contract_run`, `contract` or `client` on a lane already declared, leaving the rest of it alone. An empty VALUE changes nothing; `--unset` puts the key back on the profile's value. Called by `foundation` (a pack's lane settings) and `implement` (the client command a developer supplies) — re-declaring would reset every other command |
694
- | `contract-export [--timeout s]` | start the service lane with `contract_run`, fetch `contract`, save it to `<service root>/contracts/openapi.json`, stop the service and everything it started. A service already answering at the URL is used as it is, and said so (§4.5) |
695
- | `contract-draft --feature-dir p` | draft `api-draft.json` beside the feature's plans from `backend-plan.md`'s API section, by script: each `### \`VERB /route\`` endpoint with its operation id, request and response field shapes (conceptual types → JSON schema, a use case's DTO standing in for a named shape) and error statuses. Rewritten only when it differs; removed when the plan names no endpoint (§4.5) |
696
- | `contract-combine` | write `.appweaver/contracts/openapi.combined.json`: the exported document plus every feature's drafted operations it does not serve, marked `x-aw-draft`. `ok:false` with a reason when there is neither (§4.5) |
697
- | `contract-requests --feature-dir p` | the request ledger: the frontend plan's `RQ-n` rows against the backend plan's answers — `open`, `published` (and whether the frontend still has to re-bind), `declined` — with one line per lane's to-do for a prompt to quote |
698
- | `contract-client [--doc d]` | `run-phase --phase client` for the frontend lane — its `client` command, `{{contract}}` expanded to `--doc` (`implement` passes the combined document), else to the exported one |
699
- | `contract-check --plan p [--doc d]` | the operation ids a frontend plan cites (its §5 `Operation id` column, or a delta plan's `Contract Binding` rows; never the request table) against the document's `operationId`s — by script, no model. `drafted[]` names the cited ids that are only draft operations |
700
- | `contract-impact --delta-backend p --frontend-plan p [--delta-frontend p]` | the operations a change's service delta marks `changed` or `removed` in its "Contract deltas for the frontend lane" table that the frontend master plan binds to, and which of them the change's frontend delta plan does not name (`unaddressed[]`) — `analyze-plan-delta`'s warning. By script, no model |
722
+ | `lane-set (--id lane\|--kind k) [--set KEY=VALUE]… [--unset KEY]…` | change only `contract_write`, `contract_run`, `contract` or `client` on a lane already declared, leaving the rest of it alone. An empty VALUE changes nothing; `--unset` puts the key back on the profile's value. Called by `foundation` (a pack's lane settings) and `implement` (the client command a developer supplies) — re-declaring would reset every other command |
723
+ | `contract-export [--timeout s]` | write the service lane's as-built API document to `<service root>/contracts/openapi.json`: run its `contract_write` command (to a scratch path, kept only when it reads as OpenAPI), or start the service with `contract_run`, fetch `contract` and stop it and everything it started. Returns the `way` used and, on a failure, its `cause`; a lane with neither writes nothing (`cause: no-way`) (§4.5) |
724
+ | `contract-draft --feature-dir p [--cr id]` | draft `api-draft.json` beside the feature's plans from `api-plan.md` (for a feature planned before it, the backend plan's API section), by script: each `### \`VERB /route\`` endpoint with its operation id, request and response field shapes (conceptual types → JSON schema, a use case's DTO standing in for a named shape) and error statuses with their body shapes. `unread` lists the shapes it could not type, and `dropped` the operations the draft it replaced had. Rewritten only when it differs; removed when the plan names no endpoint. With `--cr`, the change's draft in its change folder, from its `delta-api-plan.md` (§4.5) |
725
+ | `contract-merge --feature-dir p --cr id` | merge the change's `delta-api-plan.md` into the feature's `api-plan.md` — whole endpoint blocks keyed by operation id (verb and route for a block with none, which is written with the id its row or the block it replaces gives that route): changed ones replaced, added ones after the last, removed ones deleted, a Contract deltas row with no block written from the row and reported (never over a block the change wrote on the same route) — plus the requests it answers and a `(pending)` Change History row; redraws `api-draft.json` and reports what it dropped. A feature with no `api-plan.md` has its backend plan's API moved into one first. A second run changes nothing. `finalize-delta`'s call (§4.5). With `--check` it writes nothing and reports `needed` — the change carries an API delta `api-plan.md` has no Change History row for — which `close-delta` asks before it archives |
726
+ | `api-split --feature-dir p [--check] [--cr id]` | move a feature's endpoint blocks and requests table out of its backend plan into a new `api-plan.md`, leaving one line where they were, and redraw `api-draft.json`. `--check` only reports whether the backend plan still carries the API (`needed`); `--cr` checks a change's delta backend plan the same way. `plan main` offers it |
727
+ | `contract-combine` | write `.appweaver/contracts/openapi.combined.json`: every feature's draft with each open change's applied — added, replaced, or marked `deprecated` with `x-aw-removed-by`, or, where an open change serves another operation on its route, listed in the document's `x-aw-removed` — plus, from a committed as-built document, the operations no plan describes (`x-aw-unplanned`), and `x-aw-unserved` on planned ones it does not serve. `ok:false` with a reason when there is nothing (§4.5) |
728
+ | `contract-requests --feature-dir p` | the request ledger: the frontend plan's `RQ-n` rows against the API plan's answers — `open`, `published` (and whether the frontend still has to re-bind), `declined` — with one line per lane's to-do for a prompt to quote |
729
+ | `contract-client [--doc d]` | `run-phase --phase client` for the frontend lane — its `client` command, `{{contract}}` expanded to `--doc` (`implement` passes the combined document), else to the as-built one |
730
+ | `contract-check --plan p [--doc d]` | the operation ids a frontend plan cites (its §5 `Operation id` column, or a delta plan's `Contract Binding` rows; never the request table) against the combined document's `operationId`s — by script, no model. Also names the cited ids an open change removes, the service does not serve yet, and the service serves with no plan describing them |
731
+ | `contract-impact --delta-backend p --frontend-plan p [--delta-frontend p]` | the operations a change's API delta marks `changed` or `removed` in its "Contract deltas for the frontend lane" table — the `delta-api-plan.md` beside the delta backend plan when there is one — that the frontend master plan binds to, and which of them the change's frontend delta plan does not name (`unaddressed[]`) — `analyze-plan-delta`'s warning. By script, no model |
732
+ | `contract-verify --feature-dir p [--cr id] [--doc d] [--check]` | the as-built document against the operations the feature's draft names, with any change merged into its spec and not yet closed applied — or, with `--cr`, against that change's draft alone. `missing`, `moved`, `renamed` and `still_served` are findings (`ok:false`) — a removed operation is still served when its id is, or its route is answered while the plan keeps no other operation on it; differing fields and status codes, and served operations no plan describes, are the `warning`. `checked:false` with a `note` when there is nothing to check against. `--check` reads no as-built document and reports `needed` — the plan names something to check — which the gates ask before they write the document. By script, no model |
701
733
  | `lane-resolve [--kind k] [--id lane] [--feature-dir p]` | read; exit 0 always. `exists` reports the file, `declared` reports the lanes — the shipped-but-unfilled seed is `exists:true, declared:false`. Returns the matched lane **and** both kinds flattened — `backend_source_path`, `frontend_root_exists`, `backend_build` … — so a workflow binds one variable instead of calling twice — and the working-lane fields of §2a |
702
734
  | `lane-verify [--require backend\|frontend]… [--allow-missing-root] [--working-only] [--command phase]` | **the gate**: is the declaration usable for the phase about to run. Never writes, and **always exits 0** — the calling workflow's `verify_context` owns the stop, so the reason arrives as text. `--working-only` checks on disk only the working lanes' root folders and the required kinds (§2a). Whatever the flags, `kinds_on_disk[]` lists the kinds whose lane root folder exists and `missing_roots` the issue each declared lane without one raises when `--allow-missing-root` is not passed |
703
735
  | `lane-select [--lane backend\|frontend\|both] [--default] [--preselect text]` | read or write `.appweaver/lane.json` (§2a). No argument reads it and returns the `select_options[]` the declared stacks offer; `--lane` writes one of them; `--default` writes the default — `select-stack`'s call |
@@ -745,7 +777,10 @@ they are content the kit cannot invent:
745
777
  - **Technical rules** — a corpus at `guardrails/technology/<id>/`, mapped from the project's
746
778
  `tech-rule-bindings.md` (§7a). Until one exists the stack runs with the universal
747
779
  `ai-rules.md` and the technical constitution, which is the greenfield-safe default, not an
748
- error.
780
+ error. It is said, not left to be discovered: `select-stack`'s menu names the stacks the
781
+ active map has rule files for, a lane declared on a stack with none or only some of them
782
+ raises a warning (`stack-rules`), and each later phase reports the missing folder once
783
+ rather than file by file.
749
784
  - **A foundation pack or spec** — `foundations/<ecosystem>/<Name>/`, only if you want
750
785
  `/appweaver foundation` to offer one for this stack (give it `# kind:` / `# profiles:`
751
786
  header lines). Without one, `foundation` still offers `[manual spec]` for the lane, and
@@ -81,7 +81,7 @@ If the user names a strategy your row does not support — or you have no row an
81
81
  - If `pending.note` is present, your previous response was rejected — follow the note and rewrite `response_path`.
82
82
 
83
83
  4. **Report**:
84
- Report the final JSON (`status`, `outputs`, and any `reason`) to the user. On `stopped`, relay the gate message verbatim — it tells the user what to fix or run first.
84
+ Report the final JSON (`status`, `outputs`, and any `reason`) to the user. On `stopped`, relay the gate message verbatim — it tells the user what to fix or run first. Relay every entry of `warnings` too, verbatim and one per line, on `ok` and on `stopped` alike: each is a check that failed and let the run continue — a lane skipped, a rule file not loaded, a document not exported — and the run log that also shows it is not printed under `--json`.
85
85
 
86
86
  ## Adding an agent
87
87