aw-spec-cli 0.1.32 → 0.1.34

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 +56 -17
  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 -16
  12. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +30 -6
  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 +341 -36
  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 +28 -12
  26. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +453 -116
  27. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-lane.orch.yaml +7 -4
  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
@@ -17,8 +17,6 @@
17
17
  "build": "dotnet build",
18
18
  "test": "dotnet test",
19
19
  "run": "dotnet run --project {{host}}",
20
- "contract_run": "dotnet run --project {{host}} -- --environment Development --urls http://localhost:5000",
21
- "contract": "http://localhost:5000/swagger/v1/swagger.json",
22
20
  "host_patterns": [
23
21
  "**/*.AppHost.csproj",
24
22
  "**/*.Api.csproj",
@@ -17,8 +17,6 @@
17
17
  "build": "./mvnw clean install",
18
18
  "test": "./mvnw test",
19
19
  "run": "./mvnw spring-boot:run",
20
- "contract_run": "./mvnw spring-boot:run -Dspring-boot.run.arguments=--server.port=8080",
21
- "contract": "http://localhost:8080/v3/api-docs",
22
20
  "detect": [
23
21
  "pom.xml",
24
22
  "build.gradle"
@@ -0,0 +1,107 @@
1
+ # API Plan: [FEATURE]
2
+
3
+ **Feature**: `[Feature]`
4
+
5
+ **Plan home**: `specs/[Context]/[Feature]/api-plan.md`
6
+
7
+ **Source spec**: `specs/[Context]/[Feature]/spec.md`
8
+
9
+ **Backend plan**: `specs/[Context]/[Feature]/backend-plan.md` <!-- realises each endpoint below as a use-case -->
10
+
11
+ **Version**: v1.0 <!-- moves in lockstep with spec.md and the lane plans; close-delta stamps every applied change -->
12
+
13
+ **Status**: Draft
14
+
15
+ <!--
16
+ WHAT THIS DOCUMENT IS
17
+ =====================
18
+ The API CONTRACT of ONE feature: every endpoint the service lane publishes for it, and
19
+ the service lane's answers to the frontend lane's requests. It is the one document the
20
+ two lanes meet on, and the only part of the service's planning the frontend lane reads.
21
+
22
+ spec.md ──▶ api-plan.md ──┬──▶ api-draft.json drafted by script (contract-draft)
23
+ ├──▶ frontend-plan.md §5 binds to the operation ids
24
+ └──▶ backend-plan.md realises each endpoint as a use-case
25
+
26
+ IT IS A MASTER, LIKE spec.md. A change plans its API in changes/<CR-id>/delta-api-plan.md,
27
+ and finalize-delta merges that document into this one, by script and by whole endpoint
28
+ block (contract-merge). The backend plan is derived and never merged; this document is
29
+ merged, so what a change adds or changes is here from the moment the change is merged,
30
+ and every redraw of api-draft.json reads it from here.
31
+
32
+ THE FORM IS FIXED, IN EVERY PROJECT. Each endpoint is one block under "## Endpoints": the
33
+ heading `### `VERB /route`` with the fields below it. The contract scripts read exactly
34
+ this form — contract-draft writes api-draft.json from the blocks, contract-requests reads
35
+ the operation ids and the requests table, contract-merge replaces, adds and deletes whole
36
+ blocks by operation id — so an endpoint written as a table row or in prose reaches none
37
+ of them.
38
+
39
+ PROTOCOL LEVEL, TECHNOLOGY-AGNOSTIC. Route, verb, auth, request and response shapes,
40
+ status codes and the error contract — never controller code, framework attributes,
41
+ serializer settings or language types. Every shape is `{ field: type }` in conceptual
42
+ types (string, int, decimal, bool, enum(A|B), list<T>, id<T>, money, date, datetime): a
43
+ shape in prose reaches the frontend's client untyped. The stack binds at `implement`.
44
+ REST over HTTP is assumed, per the constitution. A service whose constitution publishes
45
+ another protocol states its operations in the same block form, but contract-draft drafts
46
+ only `VERB /route` headings, so api-draft.json carries none of the others.
47
+
48
+ WHAT LIVES ELSEWHERE
49
+ - The use-case behind each endpoint — handler orchestration, validation, authorization
50
+ rule, the DTOs it carries — is the backend plan's; **Maps to** names it. A shape written
51
+ as a DTO name instead of `{ field: type }` is read from that backend plan use-case.
52
+ - Traceability: each block's heading cites the spec ids it serves, and the backend plan's
53
+ traceability spine cites the endpoint as `VERB /route`.
54
+
55
+ HOW TO AUTHOR
56
+ - Fill every [PLACEHOLDER] and repeat the endpoint block once per endpoint.
57
+ - The OPERATION ID is the endpoint's name in the published API document, unique across
58
+ the service and never reused: the frontend plan binds to it, implement gives the
59
+ endpoint exactly it, and analyze-slice checks the built service serves it. An endpoint
60
+ the code already serves keeps the id it publishes, spelled exactly as the code spells
61
+ it; where it publishes none, write `—` and say so in the block — never an invented id,
62
+ which the built service would not carry.
63
+ - Write `None` under "## Endpoints" when the feature publishes no endpoint.
64
+ - Delete these authoring comments as you fill each section.
65
+ -->
66
+
67
+ ## Endpoints
68
+
69
+ ### `[VERB] [/route]` — [purpose] · Serves US-[n] · FR-[nnn]
70
+
71
+ - **Operation id**: `[OperationId]`
72
+ - **Auth**: [required role/scope]
73
+ - **Request**: `[path/query params]` + body `{ [field]: [type], … }`
74
+ - **Success**: `2xx` → `{ [response shape] }`
75
+ - **Errors** *(the error contract)*:
76
+
77
+ | Status | When | Body shape |
78
+ |---|---|---|
79
+ | 400 | [validation failure] | `{ errors: [{ field, message }] }` |
80
+ | 403 | [unauthorized] | `{ error }` |
81
+ | 409 | [conflict / duplicate — maps to a BR] | `{ error }` |
82
+
83
+ - **Maps to**: `[use-case]` (the backend plan's element that realises it)
84
+
85
+ ## Requests from the frontend lane
86
+
87
+ <!-- THE ANSWERS to the frontend plan's §5 "Contract deltas needed" table, one row per RQ-n
88
+ it raises. PUBLISH: add the endpoint above — under the proposed operation id unless it
89
+ clashes with one this service already uses — and name the id here. DECLINE: say why in
90
+ one line; a request the spec does not support is declined as a spec gap for `specify`,
91
+ never published on a guess. The frontend plan re-binds to the id given here. Keep every
92
+ answered row; write `None` instead of the table when the frontend plan raises no
93
+ request. -->
94
+
95
+ | Request | Outcome | Operation id | Why |
96
+ |---|---|---|---|
97
+ | RQ-[n] | published / declined | `[OperationId]` / — | [one line — required when declined] |
98
+
99
+ ## Change History
100
+
101
+ <!-- A row is appended when this document is re-derived (`plan main`) and when
102
+ finalize-delta merges a change into it — that row's Version reads `(pending)` until
103
+ close-delta stamps the number. Newest last. -->
104
+
105
+ | Version | Date | Change | User stories | CR |
106
+ |---------|------|--------|--------------|-----|
107
+ | v1.0 | [DATE] | Initial API | US-1 | — |
@@ -0,0 +1,87 @@
1
+ # Delta API Plan — [CR-ID]: [TITLE]
2
+
3
+ **Feature**: `[Feature]`
4
+
5
+ **Wave**: [N] <!-- script-stamped from the delta-spec; same wave = developable in parallel, higher wave = after -->
6
+
7
+ **Base version**: [vX.Y] <!-- the API plan's version when this delta opened; close-delta bumps the minor at the end of the chain -->
8
+
9
+ **Delta spec**: `changes/[CR-ID]/delta-spec.md`
10
+
11
+ **Delta backend plan**: `changes/[CR-ID]/delta-backend-plan.md` <!-- realises each endpoint below -->
12
+
13
+ <!--
14
+ ONE CHANGE'S API. What this change adds to, changes in and removes from the feature's API
15
+ plan at specs/[Context]/[Feature]/api-plan.md, and the frontend lane's requests it
16
+ answers. It is authored in the change's own directory, beside the delta-spec and the delta
17
+ backend plan, and it is the only part of the change's service planning the frontend lane
18
+ binds to.
19
+
20
+ finalize-delta MERGES IT into api-plan.md, by script (contract-merge), as it merges the
21
+ delta-spec into spec.md: a `changed` endpoint's block replaces the API plan's block with
22
+ the same operation id, an `added` one joins the endpoints, a `removed` one is deleted, and
23
+ each request answered here replaces or joins its row of the API plan's requests table. The
24
+ merge copies each block as it stands, so a changed endpoint is written WHOLE, never as the
25
+ difference. The delta backend plan is never merged.
26
+
27
+ While the change is open, plan and analyze-plan-delta draft this document, by script, into
28
+ changes/[CR-ID]/api-draft.json — the API the frontend lane binds to for this change, and
29
+ the one analyze-slice-delta checks the built service against.
30
+
31
+ OPERATION IDS ARE STABLE. A changed endpoint keeps the id the API plan gives it; a new one
32
+ takes an id unique across the service. A `changed` or `removed` row whose operation the
33
+ frontend plan binds to is reported by analyze-plan-delta until this change's frontend delta
34
+ plan — or a follow-up change — carries the matching change.
35
+
36
+ TECHNOLOGY-AGNOSTIC, in the API plan's own form: every shape `{ field: type }` in
37
+ conceptual types, no code.
38
+ -->
39
+
40
+ ## Contract deltas for the frontend lane
41
+
42
+ <!-- One row per endpoint this change adds, changes or removes. The Operation id, Contract
43
+ and Change columns are what the merge and contract-impact read. `None` when the change
44
+ leaves the API as it is — the answer a purely internal change gives. -->
45
+
46
+ | Operation id | Contract | Change | Shape | Serves |
47
+ |---|---|---|---|---|
48
+ | `[OperationId]` | `[VERB] [/route]` | added / changed / removed | [request → response field shapes] | FR-[nnn] · IC-[nnn] |
49
+
50
+ ## Endpoints added or changed
51
+
52
+ <!-- Every endpoint the table marks `added` or `changed`, IN FULL, as the API plan's endpoint
53
+ block. A removed endpoint has its row above and no block. `None` when the table is
54
+ `None`. -->
55
+
56
+ ### `[VERB] [/route]` — [purpose] · Serves FR-[nnn]
57
+
58
+ - **Operation id**: `[OperationId]`
59
+ - **Auth**: [required role/scope]
60
+ - **Request**: `[path/query params]` + body `{ [field]: [type], … }`
61
+ - **Success**: `2xx` → `{ [response shape] }`
62
+ - **Errors** *(the error contract)*:
63
+
64
+ | Status | When | Body shape |
65
+ |---|---|---|
66
+ | 400 | [validation failure] | `{ errors: [{ field, message }] }` |
67
+
68
+ - **Maps to**: `[use-case]` (the element that realises it)
69
+
70
+ ## Requests from the frontend lane
71
+
72
+ <!-- The open requests of the frontend plan's "Contract deltas needed" table that THIS change
73
+ answers — published under an operation id, with its endpoint above, or declined with the
74
+ reason. The merge writes each row into the API plan's requests table. A request this
75
+ change gives no basis for stays open for the master; write `None` when the change
76
+ answers none. -->
77
+
78
+ | Request | Outcome | Operation id | Why |
79
+ |---|---|---|---|
80
+ | RQ-[n] | published / declined | `[OperationId]` / — | [one line — required when declined] |
81
+
82
+ ## On merge
83
+
84
+ `finalize-delta` merges this document into the feature's `api-plan.md`, by script, with the
85
+ change's spec and model halves, and leaves the change OPEN. The API plan's Change History gets
86
+ a row for the merge, whose version `close-delta` stamps when it archives this file with the
87
+ change. None of it is this document's job — it records the change, it does not apply it.
@@ -12,6 +12,8 @@
12
12
 
13
13
  **Model delta**: `specs/[Context]/domain-model.[CR-ID].delta.md` <!-- "none" when this change is behaviour-only -->
14
14
 
15
+ **API delta**: `changes/[CR-ID]/delta-api-plan.md` <!-- the endpoints this change adds, changes or removes, which this plan realises -->
16
+
15
17
  <!--
16
18
  ONE CHANGE'S PLAN FOR THE SERVICE LANE. It applies to the feature's master plan at
17
19
  specs/[Context]/[Feature]/backend-plan.md — never a new plan document. It is authored in
@@ -21,9 +23,15 @@
21
23
 
22
24
  IT DOES NOT TOUCH backend-plan.md, AND NEITHER DOES finalize-delta. Many changes may be
23
25
  open at once, so a delta that edited the master would move the baseline every other open
24
- delta is authored against. The master plan is DERIVED from spec.md and domain-model.md —
25
- the two documents finalize-delta does merge — so it is re-derived from them rather than
26
- patched from this file.
26
+ delta is authored against. The master plan is DERIVED from spec.md, domain-model.md and
27
+ api-plan.md — the documents finalize-delta does merge — so it is re-derived from them
28
+ rather than patched from this file.
29
+
30
+ THE CHANGE'S API IS NOT PLANNED HERE. The endpoints it adds, changes or removes, and the
31
+ frontend lane's requests it answers, are in delta-api-plan.md beside this file: the only
32
+ part of the change's service planning the frontend lane binds to, and the one
33
+ finalize-delta merges into api-plan.md. This document plans the use-cases, ports and
34
+ adapters behind those endpoints.
27
35
 
28
36
  WHAT IT PLANS AGAINST — the EFFECTIVE MODEL, not the bare master:
29
37
  • specs/[Context]/domain-model.md — the master model, what the domain IS today
@@ -82,14 +90,14 @@ it realises. "Realisation only — no spec delta" for a plan-only change.]
82
90
 
83
91
  ## ADDED — new plan elements
84
92
 
85
- <!-- New use-cases/handlers, endpoints, ports, adapters, and the realisation of any new
86
- spec constraint / classification / contract. Serves = a spec id (FR-/BR-/CN-/DC-/IC-/US-);
87
- the plan reads the spec and the domain model, never the domain rule files. -->
93
+ <!-- New use-cases/handlers, ports, adapters, and the realisation of any new spec
94
+ constraint / classification / contract. A use-case behind an endpoint the API delta
95
+ adds names its operation id. Serves = a spec id (FR-/BR-/CN-/DC-/IC-/US-); the plan
96
+ reads the spec and the domain model, never the domain rule files. -->
88
97
 
89
98
  | Section (§) | Element | Kind | Serves |
90
99
  |---|---|---|---|
91
- | Application (§2) | `[Command/Query]` + handler | use-case | US-[n] · FR-[nnn] |
92
- | API (§3) | `[OperationId]` · `[VERB] [/route]` | endpoint | US-[n] · FR-[nnn] |
100
+ | Application (§2) | `[Command/Query]` + handler — serves `[OperationId]` | use-case | US-[n] · FR-[nnn] |
93
101
  | Domain (§1) | `[Event]` handling / `[VO]` mapping | model realisation | BR-[nnn] · CN-[nnn] |
94
102
  | Infrastructure (§4.2) | `I[External]` adapter | contract realisation | IC-[nnn] |
95
103
  | Cross-cutting (§5) | [audit / retention / exposure decision] | constraint realisation | CN-[nnn] · DC-[nnn] |
@@ -112,22 +120,15 @@ it realises. "Realisation only — no spec delta" for a plan-only change.]
112
120
  [Which sections of the master ripple; shared elements touched (e.g. the aggregate root's
113
121
  realisation); new migration needed? (yes/no); any contract change other systems couple to.]
114
122
 
115
- ## Contract deltas for the frontend lane
123
+ ## API changes
116
124
 
117
125
  <!--
118
- What this change adds to, alters in or removes from the service's PUBLISHED surface — the
119
- only part of this document the frontend lane may bind against. One row per contract; the
120
- frontend delta plan cites these rather than re-deriving them. "None" when the surface is
121
- unchanged, which is what a purely internal refactor should say. The operation id is the
122
- endpoint's name in the published API document, unique across the service; an endpoint
123
- the master plan already names keeps that id. A `changed` or `removed` row whose operation
124
- the frontend plan binds to is reported by analyze-plan-delta until the frontend delta plan
125
- of this change — or a follow-up change — carries the matching change.
126
+ The endpoints this change adds, changes or removes — its Contract deltas table and their
127
+ blocks — and the frontend lane's requests it answers are in delta-api-plan.md, beside this
128
+ file, not here. Keep this section as the one line below.
126
129
  -->
127
130
 
128
- | Operation id | Contract | Change | Shape | Serves |
129
- |---|---|---|---|---|
130
- | `[OperationId]` | `[VERB] [/route]` | added / changed / removed | [request → response field shapes] | IC-[nnn] · FR-[nnn] |
131
+ The endpoints this change adds, changes or removes, and the requests it answers, are in [delta-api-plan.md](delta-api-plan.md).
131
132
 
132
133
  ## Other open deltas
133
134
 
@@ -156,8 +157,9 @@ e.g. re-test CreateOrder when the Order root's realisation or its repository is
156
157
  ## On merge
157
158
 
158
159
  `finalize-delta` merges the change's SPEC half into `spec.md` and its MODEL half into the
159
- context's `domain-model.md`, in one transaction, and leaves the change OPEN. It does NOT
160
- merge this document: the master plan is derived from those two, so it is re-derived rather
161
- than patched. `close-delta` archives this file with the change, bumps the minor version and
160
+ context's `domain-model.md`, in one transaction, merges its `delta-api-plan.md` into the
161
+ feature's `api-plan.md` by script, and leaves the change OPEN. It does NOT merge this
162
+ document: the master plan is derived from those three, so it is re-derived rather than
163
+ patched. `close-delta` archives this file with the change, bumps the minor version and
162
164
  writes the Change History rows. None of it is this document's job — it records the change,
163
165
  it does not apply it.
@@ -87,6 +87,6 @@
87
87
  - **On merge**: the new US-[n] is tagged `Added: (this CR)` in the master; finalize-delta
88
88
  merges this delta into spec.md and its model delta into domain-model.md — the two
89
89
  documents that DEFINE the slice, in one transaction — and appends the spec's Change
90
- History row. The lane plans are not merged: they are derived from those two and are
91
- re-derived from them. close-delta (after analyze-slice) archives the change and bumps
92
- the minor version.
90
+ History row, then merges the change's delta API plan into api-plan.md by script. The
91
+ lane plans are not merged: they are derived from those three and are re-derived from
92
+ them. close-delta (after analyze-slice) archives the change and bumps the minor version.
@@ -8,6 +8,8 @@
8
8
 
9
9
  **Source model**: `specs/[Context]/domain-model.md` <!-- structure: what the domain IS -->
10
10
 
11
+ **API plan**: `specs/[Context]/[Feature]/api-plan.md` <!-- the endpoints this service publishes, which §2 realises -->
12
+
11
13
  **Version**: v1.0 <!-- moves in lockstep with the spec; every applied change request bumps this — see Change History -->
12
14
 
13
15
  **Status**: Draft
@@ -60,6 +62,11 @@
60
62
  - Physical persistence (PKs/FKs, columns, indexes, JSON shapes, migration SQL)
61
63
  belongs to a technical-data-model. This doc states WHAT is stored and WHICH
62
64
  port persists it, not the schema.
65
+ - The endpoints this feature publishes — route, verb, operation id, request and
66
+ response shapes, the error contract — and the answers to the frontend lane's
67
+ requests are in api-plan.md beside this plan, the API contract the frontend lane
68
+ binds to. Each endpoint there maps to a §2.2 use-case, which this doc realises;
69
+ §3 points there and restates none of it.
63
70
 
64
71
  TECHNOLOGY-AGNOSTIC (mandatory)
65
72
  - Express behaviour as SIGNATURES + pre/post/invariant/raises pseudocode and
@@ -243,53 +250,23 @@ text, and do not add a rule the model does not carry)*
243
250
  4. [persist via port] (single transaction boundary)
244
251
  5. [publish domain events]
245
252
  6. return [Response]
246
- On failure: [which error → which API status in §3]
253
+ On failure: [which error → which status of the endpoint's error contract in api-plan.md]
247
254
  ```
248
255
  - **Emits**: `[DomainEvent]` (from §1.2)
249
256
 
250
257
  ## 3. API Layer
251
258
 
252
259
  <!--
253
- The contract other systems couple to. Describe it at PROTOCOL level (REST assumed
254
- per the constitution — adapt for gRPC/GraphQL/CLI if the stack differs), NOT as
255
- controller code. Pin route, verb, auth, request/response shape, status codes, and
256
- the error contract. Delegates to an Application use-case; no business logic here.
257
- The OPERATION ID is the endpoint's name in the published API document, unique across
258
- the service: the frontend plan cites it, and implement gives the endpoint exactly it.
260
+ The contract other systems couple to is NOT written here. Every endpoint this feature
261
+ publishes — route, verb, operation id, auth, request and response shapes, status codes,
262
+ the error contract — and the answers to the frontend lane's requests are in api-plan.md
263
+ beside this plan: the API contract the frontend lane binds to, merged by finalize-delta
264
+ when a change lands, and drafted by script into api-draft.json. Each endpoint there
265
+ names the §2.2 use-case it maps to, and that use-case is where this document realises
266
+ it. Keep this section as the one line below.
259
267
  -->
260
268
 
261
- ### `[VERB] [/route]` — [purpose] · Serves US-Y · FR-00X
262
-
263
- - **Operation id**: `[OperationId]`
264
- - **Auth**: [required role/scope]
265
- - **Request**: `[path/query params]` + body `{ [field]: [type], … }`
266
- - **Success**: `2xx` → `{ [response shape] }`
267
- - **Errors** *(the error contract)*:
268
-
269
- | Status | When | Body shape |
270
- |---|---|---|
271
- | 400 | [validation failure] | `{ errors: [{ field, message }] }` |
272
- | 403 | [unauthorized] | `{ error }` |
273
- | 409 | [conflict / duplicate — maps to a BR] | `{ error }` |
274
-
275
- - **Maps to**: `[Command/Query]` (§2.2)
276
-
277
- ### Requests from the frontend lane
278
-
279
- <!-- THE ANSWERS to the frontend plan's §5 "Contract deltas needed" table, one row
280
- per RQ-n it raises. PUBLISH: add the endpoint above — under the proposed
281
- operation id unless it clashes with one this service already uses — and name
282
- the id here. DECLINE: say why in one line; a request the spec does not
283
- support is declined as a spec gap for `specify`, never published on a guess.
284
- The frontend plan re-binds to the id given here. Keep every answered row;
285
- write `None` instead of the table when the frontend plan raises no request.
286
- plan and analyze-plan draft the endpoints above, by script, into
287
- api-draft.json beside this plan, so a frontend can bind to an endpoint before
288
- the service is built. -->
289
-
290
- | Request | Outcome | Operation id | Why |
291
- |---|---|---|---|
292
- | RQ-[n] | published / declined | `[OperationId]` / — | [one line — required when declined] |
269
+ The endpoints this service publishes — route, verb, operation id, request, success and errors — and its answers to the frontend lane's requests are in [api-plan.md](api-plan.md), the API contract the frontend lane binds to.
293
270
 
294
271
  ## 4. Infrastructure Layer
295
272
 
@@ -365,7 +342,7 @@ text, and do not add a rule the model does not carry)*
365
342
 
366
343
  | Id | Source | Type | Design element(s) | Layer |
367
344
  |---|---|---|---|---|
368
- | FR-001 | spec | requirement | `[Root].[Behaviour]`, `[Command]`, `[VERB /route]` | Domain·App·API |
345
+ | FR-001 | spec | requirement | `[Root].[Behaviour]`, `[Command]`, `[VERB /route]` (api-plan.md) | Domain·App·API |
369
346
  | BR-001 | model | invariant | `[Root]` invariant / `[VO]` validation | Domain |
370
347
  | CN-001 | spec | constraint | [where realised — §1 invariant / §4 persistence / §5 cross-cutting] | [layer] |
371
348
  | DC-001 | spec | classification | [exposure enforcement — §2 projection / §5 data-protection] | App·Infra |
@@ -409,8 +386,9 @@ text, and do not add a rule the model does not carry)*
409
386
 
410
387
  <!--
411
388
  The living-truth ledger. A row is appended when this plan is RE-DERIVED to carry a
412
- change — this document is derived from spec.md and the context's domain-model.md, and
413
- finalize-delta merges a change into those two, never into this one. close-delta archives
389
+ change — this document is derived from spec.md, the context's domain-model.md and
390
+ api-plan.md, and finalize-delta merges a change into those three, never into this one.
391
+ close-delta archives
414
392
  the CR, bumps the minor version in active_version.json and stamps that number into this
415
393
  document's **Version** header, so a header ahead of the newest row below means exactly
416
394
  what it says: the plan has not been re-derived since that version. A change to this
@@ -22,6 +22,9 @@
22
22
 
23
23
  WRITERS, in order:
24
24
  • specify (first run in this context) — creates it and models the first aggregate(s).
25
+ • specify (a later feature's first run) and adopt — rewrite it to add that feature's
26
+ aggregate(s). A script checks each rewrite against the file as it was and puts it back
27
+ if an aggregate section, a BR-/XBR- rule or a ledger entry was lost.
25
28
  • specify (later runs) — writes specs/[Context]/domain-model.<CR-id>.delta.md instead;
26
29
  the master is untouched while a change is open.
27
30
  • finalize-delta — merges a delta into this file, ONE `## Aggregate:` SECTION AT A TIME.
@@ -10,7 +10,7 @@
10
10
 
11
11
  **Delta spec**: `changes/[CR-ID]/delta-spec.md`
12
12
 
13
- **Service delta**: `changes/[CR-ID]/delta-backend-plan.md` <!-- "none — experience-only change" when this change has no service half -->
13
+ **API delta**: `changes/[CR-ID]/delta-api-plan.md` <!-- "none — the change leaves the API unchanged" when it has no API half -->
14
14
 
15
15
  <!--
16
16
  ONE CHANGE'S PLAN FOR THE FRONTEND LANE. It applies to the feature's master plan at
@@ -33,7 +33,9 @@
33
33
  EXPERIENCE does with it.
34
34
 
35
35
  THE LANE BOUNDARY IS THE PUBLISHED SURFACE. Bind against the delta-spec's IC- ids and
36
- the service delta's "Contract deltas for the frontend lane" table — CITE those
36
+ the change's API delta (delta-api-plan.md) — its Contract deltas table and the endpoint
37
+ blocks under it — and, for an endpoint the change leaves alone, the feature's
38
+ api-plan.md. CITE those
37
39
  contracts, never re-derive or contradict them, and introduce no server-side behaviour,
38
40
  persistence assumption or handler detail. Anything the experience needs that the surface
39
41
  does not offer is a CONTRACT DELTA raised back to the service lane, never a workaround
@@ -108,15 +110,15 @@ CN-/DC-/IC-) it realises. "Realisation only — no spec delta" for a plan-only c
108
110
  ## Contract impact
109
111
 
110
112
  <!--
111
- What this change consumes from the service lane, taken from the service delta's
112
- contract table: bindings added, changed, or no longer used. Anything the experience
113
+ What this change consumes from the service lane, taken from the API delta's
114
+ Contract deltas table: bindings added, changed, or no longer used. Anything the experience
113
115
  requires that the surface does not offer goes under "Contract deltas needed" and is
114
116
  raised back to the service lane. `None` when the binding surface is unchanged.
115
117
  -->
116
118
 
117
119
  | Contract | Consumed as | From |
118
120
  |---|---|---|
119
- | `[VERB] [/route]` | [what the screen does with it] | service delta / IC-[nnn] |
121
+ | `[VERB] [/route]` | [what the screen does with it] | API delta / IC-[nnn] |
120
122
 
121
123
  **Contract deltas needed**: [what the service must add for this experience to work] — or `None`
122
124
 
@@ -153,7 +155,8 @@ container or a navigation edge changed.]
153
155
  ## On merge
154
156
 
155
157
  `finalize-delta` merges the change's SPEC half into `spec.md` and its MODEL half into the
156
- context's `domain-model.md`, in one transaction, and leaves the change OPEN. It does NOT
157
- merge this document: the master plan is derived from those two, so it is re-derived rather
158
- than patched. `close-delta` archives this file with the change and bumps the ONE version both
158
+ context's `domain-model.md`, in one transaction, merges its `delta-api-plan.md` into the
159
+ feature's `api-plan.md` by script, and leaves the change OPEN. It does NOT merge this
160
+ document: the master plan is derived from those three, so it is re-derived rather than
161
+ patched. `close-delta` archives this file with the change and bumps the ONE version both
159
162
  lanes share. None of it is this document's job — it records the change, it does not apply it.
@@ -192,11 +192,11 @@ a lost connection mid-flight.]
192
192
 
193
193
  <!-- THE LANE BOUNDARY. One row per service operation this feature's UI depends
194
194
  on. Bind against the service's PUBLISHED SURFACE — the spec's IC- ids and
195
- the API contracts backend-plan.md states — and never against the service's
195
+ the endpoints api-plan.md states — and never against the service's
196
196
  internals: no table, no handler, no persistence assumption crosses this
197
197
  line. An interface the experience needs and the service does not offer is a
198
198
  CONTRACT DELTA raised back to the service lane, never a workaround in the
199
- client. The OPERATION ID is the one backend-plan.md §3 gives the endpoint —
199
+ client. The OPERATION ID is the one api-plan.md gives the endpoint —
200
200
  the name implement finds it by in the API document, and checks before
201
201
  generating. A row that needs an operation the service does not publish yet
202
202
  cites the operation id its request below proposes, and names the RQ-n in
@@ -212,10 +212,10 @@ it invalidates, and how an optimistic update rolls back.]
212
212
  **Contract deltas needed**
213
213
 
214
214
  <!-- THE REQUEST LEDGER. One row per operation the experience needs that the
215
- service's published surface does not offer — and, when there is no backend
215
+ service's published surface does not offer — and, when there is no API
216
216
  plan yet, one per binding. Each request keeps its RQ-n for life: never
217
217
  renumber or reuse one. Propose the operation id and the field shapes; the
218
- backend plan answers in its "Requests from the frontend lane" table —
218
+ API plan answers in its "Requests from the frontend lane" table —
219
219
  published under an operation id, or declined with the reason. An answered
220
220
  request is re-bound in the table above to the id the backend gave it; a
221
221
  declined one is planned around, or routed to `specify` when the spec needs
@@ -24,20 +24,26 @@
24
24
  # Vue, SvelteKit and the Express backend alike)
25
25
  # # title: the label in the pick list
26
26
  #
27
- # Three more header lines carry the API CONTRACT between the lanes. /appweaver foundation
28
- # records them on the lane in .appweaver/stacks.json once the project is built, and
29
- # /appweaver implement uses them to export the service's OpenAPI document and generate the
30
- # frontend's client from it before it generates the frontend. A spec that leaves one out
31
- # is asked for it at the end of the build; leaving the answer empty keeps the stack
32
- # profile's default.
27
+ # Four more header lines carry the API settings of the lanes. /appweaver foundation
28
+ # records them on the lane in .appweaver/stacks.json once the project is built. The API
29
+ # CONTRACT between the lanes is each feature's API plan (api-plan.md), which the frontend
30
+ # binds to; a backend lane's settings say how its service's AS-BUILT document is had, so
31
+ # /appweaver analyze-slice can check the API the code serves against the API plan. A spec
32
+ # that gives neither backend way is asked for `contract-write` at the end of the build,
33
+ # and one that gives no client is asked for it; an empty answer keeps the lane's value.
33
34
  #
34
- # # contract-run: (backend) the command that starts the API ON ITS OWN — no
35
+ # # contract-write: (backend) a command that WRITES the service's OpenAPI JSON to
36
+ # {{contract}} with no server started — the stack's own generator, or
37
+ # a script that loads the application and dumps its document. Run in
38
+ # the lane root folder. Preferred: nothing of the service runs
39
+ # # contract-run: (backend) or: the command that starts the API ON ITS OWN — no
35
40
  # orchestration host, nothing it needs that is not on this machine —
36
41
  # run in the lane root folder. <App> stands for the app name given
37
42
  # at /appweaver foundation
38
- # # contract: (backend) the URL that running API serves its OpenAPI document at
39
- # # client: (frontend) the command that generates the API client from that
40
- # document; {{contract}} in it stands for the document's path
43
+ # # contract: (backend) with contract-run: the URL that running API serves its
44
+ # OpenAPI document at
45
+ # # client: (frontend) the command that generates the API client from an
46
+ # OpenAPI document; {{contract}} in it stands for the document's path
41
47
  #
42
48
  # The header is the leading block of `#` lines; the first line that does not start with
43
49
  # `#` ends it. Everything after this header block is the spec itself, written for the
@@ -82,17 +88,18 @@ Settings files, environment variables, ports, connection strings (placeholders,
82
88
  secrets).
83
89
 
84
90
  ## API document
85
- Backend: the API serves its OpenAPI document at the `# contract:` URL, and the
86
- `# contract-run:` command starts it on its own on the port that URL names — over http, with
87
- every setting it needs to start present in its configuration (a local database file, not a
88
- container). Frontend: say which tool the `# client:` command runs, so it is installed as a
89
- development dependency.
91
+ Backend: the `# contract-write:` command writes the API's OpenAPI document without starting
92
+ a server — say which tool or script it runs, so it is part of the project. Or, with
93
+ `# contract-run:` and `# contract:`, the API serves its document at that URL and the command
94
+ starts it on its own on the port the URL names — over http, with every setting it needs to
95
+ start present in its configuration (a local database file, not a container). Frontend: say
96
+ which tool the `# client:` command runs, so it is installed as a development dependency.
90
97
 
91
98
  ## Tests
92
99
  The test project(s): framework, where they live (the lane's test path), and the one test that
93
100
  must pass on a fresh scaffold.
94
101
 
95
102
  ## Done when
96
- How to confirm the scaffold works — the lane's build passes, the test command passes, the app
97
- starts and answers a named URL (for a backend, the `# contract:` URL, started with the
98
- `# contract-run:` command).
103
+ How to confirm the scaffold works — the lane's build passes, the test command passes, and for
104
+ a backend its API document is written: by the `# contract-write:` command, or served at the
105
+ `# contract:` URL once `# contract-run:` starts it.