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.
- package/README.md +76 -81
- package/assets/.appweaver/DESIGN-FORMAT.md +56 -17
- package/assets/.appweaver/STACK-PROFILES.md +95 -60
- package/assets/.appweaver/orchestrator/LAUNCHER.md +1 -1
- package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +173 -32
- package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +29 -1
- package/assets/.appweaver/orchestrator/modules/foundation-pack.orch.yaml +7 -4
- package/assets/.appweaver/orchestrator/modules/foundation-spec.orch.yaml +49 -60
- package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +58 -0
- package/assets/.appweaver/orchestrator/orchestrator.py +26 -8
- package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +20 -16
- package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +30 -6
- package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +9 -7
- package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +5 -5
- package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +341 -36
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +254 -43
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +248 -68
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +251 -20
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +316 -10
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +6 -47
- package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +62 -16
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +132 -9
- package/assets/.appweaver/orchestrator/workflows/aw-spec-fix-test-coverage.orch.yaml +965 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +222 -169
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +28 -12
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +453 -116
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-lane.orch.yaml +7 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +83 -6
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +45 -2
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +324 -74
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +275 -44
- package/assets/.appweaver/scripts/python/aw-foundation.py +16 -13
- package/assets/.appweaver/scripts/python/aw-gaps.py +11 -3
- package/assets/.appweaver/scripts/python/aw-model-guard.py +295 -0
- package/assets/.appweaver/scripts/python/aw-plan-coverage.py +412 -3
- package/assets/.appweaver/scripts/python/aw-plangate.py +23 -16
- package/assets/.appweaver/scripts/python/aw-stack.py +1794 -265
- package/assets/.appweaver/stack-profiles/dotnet-webapi.json +0 -2
- package/assets/.appweaver/stack-profiles/java-spring.json +0 -2
- package/assets/.appweaver/templates/api-plan-template.md +107 -0
- package/assets/.appweaver/templates/delta-api-plan-template.md +87 -0
- package/assets/.appweaver/templates/delta-design-template.md +25 -23
- package/assets/.appweaver/templates/delta-spec-template.md +3 -3
- package/assets/.appweaver/templates/design-template.md +20 -42
- package/assets/.appweaver/templates/domain-model-template.md +3 -0
- package/assets/.appweaver/templates/ui-delta-design-template.md +11 -8
- package/assets/.appweaver/templates/ui-design-template.md +4 -4
- package/assets/foundations/foundation.spec.template.txt +25 -18
- package/assets/guardrails/README.md +61 -25
- package/assets/guardrails/methodology/ux/accessibility-standards.md +38 -0
- package/assets/guardrails/methodology/ux/content-design.md +34 -0
- package/assets/guardrails/methodology/ux/interaction-states.md +45 -0
- package/assets/guardrails/methodology/ux/journey-mapping.md +41 -0
- package/assets/guardrails/project-specific/domain/domain-requirements.md +25 -38
- package/assets/guardrails/project-specific/domain-rule-bindings.md +33 -69
- package/assets/guardrails/project-specific/frontend/ui-requirements.md +2 -2
- package/assets/guardrails/project-specific/service/technical-requirements.md +2 -2
- package/assets/guardrails/project-specific/tech-rule-bindings.md +16 -13
- package/assets/guardrails/sample-healthcare/domain/domain-requirements.md +58 -0
- package/assets/guardrails/sample-healthcare/domain-rule-bindings.md +138 -0
- package/assets/guardrails/sample-healthcare/frontend/ui-requirements.md +43 -0
- package/assets/guardrails/sample-healthcare/service/technical-requirements.md +40 -0
- package/assets/guardrails/sample-healthcare/tech-rule-bindings.md +303 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +216 -7
- package/dist/commands/init.js.map +1 -1
- package/dist/utils/config.js +1 -1
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/foundation.d.ts +36 -0
- package/dist/utils/foundation.d.ts.map +1 -0
- package/dist/utils/foundation.js +109 -0
- package/dist/utils/foundation.js.map +1 -0
- package/dist/utils/paths.js +1 -1
- package/dist/utils/paths.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
#
|
|
4
4
|
# GENERATE the source files + paired tests for the aggregate, STRICTLY from its lane
|
|
5
5
|
# plans — the mediators between the spec and the code:
|
|
6
|
-
# • specs/<Context>/<Feature>/backend-plan.md when a BACKEND lane is declared
|
|
6
|
+
# • specs/<Context>/<Feature>/backend-plan.md when a BACKEND lane is declared, with the
|
|
7
|
+
# api-plan.md beside it — the endpoints that plan realises
|
|
7
8
|
# • specs/<Context>/<Feature>/frontend-plan.md when a FRONTEND lane is declared
|
|
8
9
|
#
|
|
9
10
|
# THE LANES COME FROM stacks.json, NOT FROM A FLAG — select-stack is the sole writer of
|
|
@@ -54,15 +55,18 @@
|
|
|
54
55
|
# pipeline, so each runnable lane confirms first, naming its stack, its plan and the
|
|
55
56
|
# subtree it will write into. Answering no to one lane leaves the other free to run.
|
|
56
57
|
#
|
|
57
|
-
# THE
|
|
58
|
-
#
|
|
59
|
-
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
#
|
|
58
|
+
# THE API PLAN IS THE CONTRACT, AND BOTH LANES BUILD TO IT. The service lane serves every
|
|
59
|
+
# endpoint of the feature's api-plan.md — a change's delta-api-plan.md on the delta path —
|
|
60
|
+
# at the route, verb and operation id it states; analyze-slice checks the built service
|
|
61
|
+
# serves it, and this phase never starts the service. A feature or change planned before
|
|
62
|
+
# API plans existed keeps its endpoints in its backend plan, which is read in their place.
|
|
63
|
+
# When the frontend lane generates, it reads the operations the API plans draft
|
|
64
|
+
# (api-draft.json, with each open change's draft applied), combined into one document,
|
|
65
|
+
# generates its client from it and checks the operation ids its plan cites against it; the
|
|
66
|
+
# feature's api-plan.md is in its context too, and the backend plan never is. Contract
|
|
67
|
+
# requests the API plan has not answered are named, and the bindings that wait on them are
|
|
68
|
+
# left unbound while the rest of the lane generates. Every one of those steps warns rather
|
|
69
|
+
# than stops — see the API CONTRACT block before the lane swap.
|
|
66
70
|
#
|
|
67
71
|
# THE PLAN SAYS WHAT TO BUILD, THE MODEL SAYS WHAT THE DOMAIN IS. This phase does NOT read
|
|
68
72
|
# spec.md — analyze-plan already conformed the plans to it, so the plan is the complete,
|
|
@@ -154,8 +158,8 @@
|
|
|
154
158
|
# =============================================================================
|
|
155
159
|
|
|
156
160
|
name: aw-spec-implement
|
|
157
|
-
description: "Generate the aggregate's source files and paired tests from its lane plans — the backend lane from backend-plan.md when a backend stack is declared, the frontend lane from frontend-plan.md when a frontend stack is, both when both are. One command covers backend-only, frontend-only and full-stack projects and absorbs the former implement-ui and implement-delta. Self-detecting off the changes on disk — with none open that names a lane you work on (its **Lanes** line) it generates from the master plans; with one or more it ASKS which change and generates only what that change's delta plans mark ADDED or MODIFIED, for the lanes the change names, leaving the masters untouched. Every lane is gated on its own lane root folder, its own plan and its own scaffolded project, and a lane missing any of them is reported and skipped rather than failing the other lane; each runnable lane confirms before it writes. Model-driven, and it does not read the spec — analyze-plan already conformed the plans to it. The plan says WHAT to build; the bounded context's domain-model.md, in context alongside it, says what the domain IS — the entity names, the boundary and the text of every invariant the plan cites by id — joined on the delta path by that change's own model delta, since the master is not merged until finalize-delta. The stack binds here from the lane declaration and the constitution halves; the plans stay technology-agnostic."
|
|
158
|
-
version: 3.
|
|
161
|
+
description: "Generate the aggregate's source files and paired tests from its lane plans — the backend lane from backend-plan.md, serving the endpoints of the api-plan.md beside it, when a backend stack is declared, the frontend lane from frontend-plan.md when a frontend stack is, both when both are. One command covers backend-only, frontend-only and full-stack projects and absorbs the former implement-ui and implement-delta. Self-detecting off the changes on disk — with none open that names a lane you work on (its **Lanes** line) it generates from the master plans; with one or more it ASKS which change and generates only what that change's delta plans mark ADDED or MODIFIED, for the lanes the change names, leaving the masters untouched. Every lane is gated on its own lane root folder, its own plan and its own scaffolded project, and a lane missing any of them is reported and skipped rather than failing the other lane; each runnable lane confirms before it writes. Model-driven, and it does not read the spec — analyze-plan already conformed the plans to it. The plan says WHAT to build; the bounded context's domain-model.md, in context alongside it, says what the domain IS — the entity names, the boundary and the text of every invariant the plan cites by id — joined on the delta path by that change's own model delta, since the master is not merged until finalize-delta. The stack binds here from the lane declaration and the constitution halves; the plans stay technology-agnostic."
|
|
162
|
+
version: 3.16.0
|
|
159
163
|
agent_agnostic: true
|
|
160
164
|
dialect: aw-spec.orchestrator/v1
|
|
161
165
|
|
|
@@ -200,7 +204,17 @@ vars:
|
|
|
200
204
|
delta_backend_plan_exists: "false"
|
|
201
205
|
delta_frontend_plan: ""
|
|
202
206
|
delta_frontend_plan_exists: "false"
|
|
207
|
+
delta_api_plan: ""
|
|
208
|
+
delta_api_plan_exists: "false"
|
|
203
209
|
wave: ""
|
|
210
|
+
# THE FEATURE'S API PLAN, and the one the backend lane serves this run (be_api_doc) —
|
|
211
|
+
# api-plan.md on the bootstrap path, the change's delta-api-plan.md on the delta path;
|
|
212
|
+
# be_api_doc is empty where there is none, because the (delta) backend plan still carries
|
|
213
|
+
# its own API.
|
|
214
|
+
api_plan: ""
|
|
215
|
+
api_plan_exists: "false"
|
|
216
|
+
be_api_doc: ""
|
|
217
|
+
be_api_ok: "false"
|
|
204
218
|
# THE GATE RECEIPT — was this feature's plan pair checked against this spec, with what
|
|
205
219
|
# verdict, and has anything moved since. analyze-plan writes it on every master run; this
|
|
206
220
|
# phase is the reader. Bootstrap path only: a delta generates from delta plans, which
|
|
@@ -304,18 +318,8 @@ vars:
|
|
|
304
318
|
fe_gap_names: ""
|
|
305
319
|
fe_gaps_text: "none"
|
|
306
320
|
# THE API CONTRACT between the lanes — see the block before the lane swap. Every flag
|
|
307
|
-
# starts lowered: the
|
|
308
|
-
# the frontend half reads only when the frontend lane does.
|
|
309
|
-
contract_go: "false" # PUBLISH — the service lane generated in this run
|
|
310
|
-
contract_ok: ""
|
|
311
|
-
export_doc: "" # the service's exported document (contracts/openapi.json)
|
|
312
|
-
export_doc_exists: "false"
|
|
313
|
-
contract_reason: ""
|
|
314
|
-
contract_already: "false"
|
|
315
|
-
contract_fresh: "true"
|
|
316
|
-
contract_log: ""
|
|
321
|
+
# starts lowered: the frontend half reads only when the frontend lane generates.
|
|
317
322
|
contract_placeholder: ""
|
|
318
|
-
contract_export_status: ""
|
|
319
323
|
combine_go: "false" # READ — the frontend lane generates and a service lane is declared
|
|
320
324
|
combined_ok: ""
|
|
321
325
|
combined_status: ""
|
|
@@ -325,13 +329,15 @@ vars:
|
|
|
325
329
|
clashes_clear: "true"
|
|
326
330
|
contract_doc: "" # what the frontend binds to: the combined document
|
|
327
331
|
contract_doc_exists: "false"
|
|
328
|
-
contract_status: "none — no API document is in context, so take each binding from the plan alone and say so in your summary"
|
|
329
|
-
req_open_csv: "" # the frontend plan's contract requests the
|
|
332
|
+
contract_status: "none — no API document is in context, so take each binding from the feature's API plan where it is in context, and from the plan alone otherwise, and say so in your summary"
|
|
333
|
+
req_open_csv: "" # the frontend plan's contract requests the API plan has not answered
|
|
330
334
|
req_backend_text: "none"
|
|
331
335
|
req_summary: ""
|
|
332
336
|
req_clear: "true"
|
|
333
|
-
|
|
334
|
-
|
|
337
|
+
check_unserved: ""
|
|
338
|
+
unserved_clear: "true"
|
|
339
|
+
check_removed: ""
|
|
340
|
+
removed_clear: "true"
|
|
335
341
|
client_go: "false"
|
|
336
342
|
client_ask: "false"
|
|
337
343
|
client_answer: ""
|
|
@@ -441,6 +447,8 @@ workflow:
|
|
|
441
447
|
- { name: backend_plan_exists, from: "$.backend_plan_exists" }
|
|
442
448
|
- { name: frontend_plan, from: "$.frontend_plan" }
|
|
443
449
|
- { name: frontend_plan_exists, from: "$.frontend_plan_exists" }
|
|
450
|
+
- { name: api_plan, from: "$.api_plan" }
|
|
451
|
+
- { name: api_plan_exists, from: "$.api_plan_exists" }
|
|
444
452
|
|
|
445
453
|
- id: require_feature
|
|
446
454
|
action: verify_context
|
|
@@ -574,6 +582,10 @@ workflow:
|
|
|
574
582
|
- { name: delta_backend_plan_exists, from: "$.delta_backend_plan_exists" }
|
|
575
583
|
- { name: delta_frontend_plan, from: "$.delta_frontend_plan" }
|
|
576
584
|
- { name: delta_frontend_plan_exists, from: "$.delta_frontend_plan_exists" }
|
|
585
|
+
# THIS CHANGE'S API — the endpoints it adds, changes or removes. Absent for a change
|
|
586
|
+
# planned before delta API plans existed, whose delta backend plan carries them.
|
|
587
|
+
- { name: delta_api_plan, from: "$.delta_api_plan" }
|
|
588
|
+
- { name: delta_api_plan_exists, from: "$.delta_api_plan_exists" }
|
|
577
589
|
- { name: wave, from: "$.wave" }
|
|
578
590
|
# The lanes the change names — its delta-spec's **Lanes** line, every lane when it
|
|
579
591
|
# records none.
|
|
@@ -584,14 +596,28 @@ workflow:
|
|
|
584
596
|
# 3. WHICH PLAN EACH LANE GENERATES FROM, resolved once per lane from the mode — the
|
|
585
597
|
# master on the bootstrap path, this change's delta plan on the delta path. Every gate
|
|
586
598
|
# and prompt below reads be_plan / fe_plan, so neither has to re-branch on the mode.
|
|
599
|
+
# The backend lane's API plan resolves beside its plan, and is emptied where it is not
|
|
600
|
+
# on disk: that plan still carries its own API section.
|
|
587
601
|
- id: be_plan_bootstrap
|
|
588
602
|
condition: "{{mode}} == bootstrap"
|
|
589
603
|
action: set
|
|
590
|
-
vars:
|
|
604
|
+
vars:
|
|
605
|
+
be_plan: "{{backend_plan}}"
|
|
606
|
+
be_plan_ok: "{{backend_plan_exists}}"
|
|
607
|
+
be_api_doc: "{{api_plan}}"
|
|
608
|
+
be_api_ok: "{{api_plan_exists}}"
|
|
591
609
|
- id: be_plan_delta
|
|
592
610
|
condition: "{{mode}} == delta"
|
|
593
611
|
action: set
|
|
594
|
-
vars:
|
|
612
|
+
vars:
|
|
613
|
+
be_plan: "{{delta_backend_plan}}"
|
|
614
|
+
be_plan_ok: "{{delta_backend_plan_exists}}"
|
|
615
|
+
be_api_doc: "{{delta_api_plan}}"
|
|
616
|
+
be_api_ok: "{{delta_api_plan_exists}}"
|
|
617
|
+
- id: be_api_absent
|
|
618
|
+
condition: "{{be_api_ok}} != true"
|
|
619
|
+
action: set
|
|
620
|
+
vars: { be_api_doc: "" }
|
|
595
621
|
- id: fe_plan_bootstrap
|
|
596
622
|
condition: "{{mode}} == bootstrap"
|
|
597
623
|
action: set
|
|
@@ -906,15 +932,17 @@ workflow:
|
|
|
906
932
|
action: set
|
|
907
933
|
vars: { fe_mode: "{{mode}}" }
|
|
908
934
|
|
|
909
|
-
# 8b. EACH GENERATING LANE'S ELEMENT LIST, read off its plan by plan-coverage
|
|
910
|
-
#
|
|
911
|
-
#
|
|
935
|
+
# 8b. EACH GENERATING LANE'S ELEMENT LIST, read off its plan by plan-coverage — and, for
|
|
936
|
+
# the backend lane, the endpoints of the API plan it serves (`--api-plan`; an empty
|
|
937
|
+
# path reads the endpoints from the plan's own API section). The generation prompt
|
|
938
|
+
# carries it, and the model reports every name on it — so an element it did not get to
|
|
939
|
+
# is declared rather than silently absent.
|
|
912
940
|
- id: be_plan_elements
|
|
913
941
|
condition: "{{be_go}} == true"
|
|
914
942
|
action: execute_script
|
|
915
943
|
script: { ref: actions }
|
|
916
944
|
subcommand: plan-coverage
|
|
917
|
-
args: ["--plan", "{{be_plan}}", "--kind", "backend", "--mode", "{{be_mode}}", "--list-only", "--reserved", "{{be_reserved}}"]
|
|
945
|
+
args: ["--plan", "{{be_plan}}", "--kind", "backend", "--mode", "{{be_mode}}", "--api-plan", "{{be_api_doc}}", "--list-only", "--reserved", "{{be_reserved}}"]
|
|
918
946
|
outputs:
|
|
919
947
|
- { name: be_element_names, from: "$.names_text" }
|
|
920
948
|
- { name: be_collisions, from: "$.collisions_csv" }
|
|
@@ -1011,6 +1039,7 @@ workflow:
|
|
|
1011
1039
|
action: build_context
|
|
1012
1040
|
context:
|
|
1013
1041
|
- { path: "{{be_plan}}" }
|
|
1042
|
+
- { path: "{{api_plan}}", optional: true } # the endpoints the plan realises — absent where the plan still carries its own API section
|
|
1014
1043
|
- { path: "{{domain_model}}", optional: true } # the CONTEXT'S canonical model — what each cited BR-nnn REQUIRES
|
|
1015
1044
|
- { path: .appweaver/memory/constitution.technical.md, optional: true } # technology base ONLY — no domain rules
|
|
1016
1045
|
- id: gen_backend
|
|
@@ -1020,10 +1049,11 @@ workflow:
|
|
|
1020
1049
|
permission_mode: acceptEdits
|
|
1021
1050
|
task: |
|
|
1022
1051
|
Generate the production code AND paired tests for this aggregate STRICTLY from its
|
|
1023
|
-
backend-plan.md (in context)
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1052
|
+
backend-plan.md (in context), serving the endpoints of the api-plan.md beside it (in
|
|
1053
|
+
context where the feature has one). The plans are the complete, authoritative source
|
|
1054
|
+
of WHAT to build — do NOT consult or infer from the spec; analyze-plan already
|
|
1055
|
+
conformed them to it. This phase is the HOME of the technology-specific,
|
|
1056
|
+
solution-wide code-generation rules. Guidance: {{USER_INPUT}}
|
|
1027
1057
|
Rules:
|
|
1028
1058
|
- TWO DOMAIN INPUTS, WITH DIFFERENT JOBS. The PLAN is the only authority on WHAT TO
|
|
1029
1059
|
BUILD — which elements exist, where each one lives, what surface they publish. The
|
|
@@ -1102,21 +1132,30 @@ workflow:
|
|
|
1102
1132
|
- Realise EVERY plan element as code, changing nothing about WHAT it specifies: one
|
|
1103
1133
|
file per Domain type / Application use-case / API endpoint / Infrastructure
|
|
1104
1134
|
adapter, placed by layer. Preserve the ubiquitous-language names verbatim.
|
|
1105
|
-
- Enforce EXACTLY as the
|
|
1106
|
-
orchestration and
|
|
1135
|
+
- Enforce EXACTLY as the plans state: every Domain invariant, Application handler
|
|
1136
|
+
orchestration and endpoint error contract; the cross-cutting constraints in the
|
|
1107
1137
|
Cross-Cutting Concerns table (audit / retention / data-exposure — the CN-/DC-
|
|
1108
1138
|
realisations); and each integration contract (IC-) in the External Integrations
|
|
1109
1139
|
table. Implement every port the plan declares.
|
|
1110
|
-
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1140
|
+
- SERVE EVERY ENDPOINT OF THE API PLAN EXACTLY AS IT IS WRITTEN. api-plan.md is the
|
|
1141
|
+
API contract: each endpoint block gives the route, verb, **Operation id**, request
|
|
1142
|
+
and response field shapes and the error contract, and **Maps to** names the
|
|
1143
|
+
backend plan's use-case that serves it. Where api-plan.md is not in context, the
|
|
1144
|
+
backend plan's own API section carries the same blocks. Serve each endpoint at the
|
|
1145
|
+
route and verb it gives, with its field names and status codes as stated, and set
|
|
1146
|
+
its operation id as this stack's published API document names operations (its
|
|
1147
|
+
OpenAPI operationId), spelled exactly as the block writes it. The frontend lane
|
|
1148
|
+
binds to the endpoint by that id, and analyze-slice checks that the built service
|
|
1149
|
+
serves it there, so an endpoint left on a framework-generated name is one the
|
|
1150
|
+
frontend calls and cannot reach.
|
|
1115
1151
|
- Author a paired test for every plan behaviour / use-case / endpoint; derive the
|
|
1116
1152
|
cases from the plan's pre/post/invariant contracts and cite the spec id (FR / BR /
|
|
1117
1153
|
CN / DC / IC / US) from its Traceability section. Include tests for the constraints
|
|
1118
1154
|
— e.g. an audit record is emitted, a DC-restricted field is NOT exposed on the
|
|
1119
|
-
public surface, an IC- projection round-trips.
|
|
1155
|
+
public surface, an IC- projection round-trips. THE CITATION IS CHECKED: analyze-slice
|
|
1156
|
+
fails a slice in which some FR- or BR- of that section is named by no test. Write the
|
|
1157
|
+
id in the test's name, a comment, an attribute or a tag, in whichever form this
|
|
1158
|
+
language allows — `FR-004`, `FR_004` or `FR004`.
|
|
1120
1159
|
- WIRE WHAT YOU BUILD, in this same pass. Every port, adapter, handler and endpoint
|
|
1121
1160
|
the plan introduces is registered in the lane's composition root as the plan's §4.3
|
|
1122
1161
|
Wiring states. A dependency that is injected and never bound COMPILES GREEN — a
|
|
@@ -1136,21 +1175,22 @@ workflow:
|
|
|
1136
1175
|
one changed, STOP and surface it.
|
|
1137
1176
|
- Where generated code depends on a plan Assumption (DA-n) or Workaround (WA-n), mark
|
|
1138
1177
|
it with a comment citing that id so it is easy to revisit later.
|
|
1139
|
-
- REPORT EVERY PLAN ELEMENT. The plan
|
|
1140
|
-
Add an `elements` list to your closing JSON block with one
|
|
1141
|
-
exactly as listed: {"element": "<name>", "status": "done"
|
|
1142
|
-
"<what stops it, when blocked>"}. `done` means it is
|
|
1143
|
-
including one that already existed; `blocked` means you
|
|
1144
|
-
element missing from the list counts as not done, and the
|
|
1145
|
-
each name after this step.
|
|
1178
|
+
- REPORT EVERY PLAN ELEMENT. The elements of the plan and its API plan, by name:
|
|
1179
|
+
{{be_element_names}}. Add an `elements` list to your closing JSON block with one
|
|
1180
|
+
entry per name, spelled exactly as listed: {"element": "<name>", "status": "done"
|
|
1181
|
+
| "blocked", "reason": "<what stops it, when blocked>"}. `done` means it is
|
|
1182
|
+
realised in code now, including one that already existed; `blocked` means you
|
|
1183
|
+
could not realise it. An element missing from the list counts as not done, and the
|
|
1184
|
+
code is checked for each name after this step.
|
|
1146
1185
|
outputs:
|
|
1147
1186
|
- { name: be_files, from: "$.files" }
|
|
1148
1187
|
- { name: be_elements, from: "$.elements" }
|
|
1149
1188
|
|
|
1150
1189
|
# ═══════════ BACKEND LANE — delta, generate ONLY what the change adds ════════
|
|
1151
1190
|
# The delta plan is the authoritative source of WHAT changed — analyze-plan-delta already
|
|
1152
|
-
# conformed it to the delta spec
|
|
1153
|
-
#
|
|
1191
|
+
# conformed it to the delta spec — and the change's delta-api-plan.md of the endpoints it
|
|
1192
|
+
# adds, changes or removes. The MASTER plan and API plan are the BASE (the unchanged
|
|
1193
|
+
# elements and endpoints the delta depends on).
|
|
1154
1194
|
#
|
|
1155
1195
|
# NO DELTA-SPEC HERE, exactly as the bootstrap path carries no spec. It used to be
|
|
1156
1196
|
# inlined "only so the paired tests can cite traceability ids", but a document in the
|
|
@@ -1166,8 +1206,10 @@ workflow:
|
|
|
1166
1206
|
action: build_context
|
|
1167
1207
|
context:
|
|
1168
1208
|
- { path: "{{be_plan}}" } # this change's delta-backend-plan.md
|
|
1209
|
+
- { path: "{{delta_api_plan}}", optional: true } # this change's API — absent for a change whose delta plan carries it
|
|
1169
1210
|
- { path: "{{delta_model}}", optional: true } # this change's MODEL half — what it ADDS to / CHANGES in the model
|
|
1170
1211
|
- { path: "{{backend_plan}}", optional: true } # the master plan — READ ONLY, never amended here
|
|
1212
|
+
- { path: "{{api_plan}}", optional: true } # the master API plan — READ ONLY, the endpoints as they stand BEFORE this change
|
|
1171
1213
|
- { path: "{{domain_model}}", optional: true } # the master model — the domain as it stands BEFORE this change
|
|
1172
1214
|
- { path: .appweaver/memory/constitution.technical.md, optional: true } # technology base ONLY — no domain rules
|
|
1173
1215
|
- id: gen_backend_delta
|
|
@@ -1177,14 +1219,16 @@ workflow:
|
|
|
1177
1219
|
permission_mode: acceptEdits
|
|
1178
1220
|
task: |
|
|
1179
1221
|
Implement ONLY change {{cr_id}} (wave {{wave}}) into the existing project tree,
|
|
1180
|
-
STRICTLY from its delta-backend-plan.md
|
|
1181
|
-
authoritative source of WHAT changed —
|
|
1182
|
-
delta
|
|
1183
|
-
|
|
1222
|
+
STRICTLY from its delta-backend-plan.md and its delta-api-plan.md (in context where
|
|
1223
|
+
the change has one). The delta plans are the authoritative source of WHAT changed —
|
|
1224
|
+
analyze-plan-delta already conformed them to the delta spec. The master
|
|
1225
|
+
backend-plan.md and api-plan.md (in context) are the BASE: the unchanged elements and
|
|
1226
|
+
endpoints the delta depends on; do NOT regenerate them. Guidance: {{USER_INPUT}}
|
|
1184
1227
|
Rules:
|
|
1185
1228
|
- SCOPE = THE DELTA ONLY. Realise exactly the elements the delta plan marks ADDED
|
|
1186
|
-
(create the new file) or MODIFIED (edit the existing file in place)
|
|
1187
|
-
|
|
1229
|
+
(create the new file) or MODIFIED (edit the existing file in place), and the
|
|
1230
|
+
endpoints its API delta adds, changes or removes. Touch NOTHING the delta does not
|
|
1231
|
+
list, except the regression re-tests below.
|
|
1188
1232
|
- TWO DOMAIN INPUTS, WITH DIFFERENT JOBS. The DELTA PLAN is the only authority on
|
|
1189
1233
|
WHAT TO BUILD in this change — which elements are added or edited, where each one
|
|
1190
1234
|
lives, what surface they publish. The DOMAIN MODEL is the authority on WHAT THE
|
|
@@ -1262,10 +1306,16 @@ workflow:
|
|
|
1262
1306
|
invariant, handler orchestration, API error contract, the Cross-Cutting Concerns
|
|
1263
1307
|
realisations (audit / retention / data-exposure — CN-/DC-) and the External
|
|
1264
1308
|
Integrations table's contracts (IC-) exactly as the delta plan states.
|
|
1265
|
-
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1309
|
+
- SERVE THE CHANGE'S API EXACTLY AS IT IS WRITTEN. delta-api-plan.md lists every
|
|
1310
|
+
endpoint the change adds, changes or removes in its Contract deltas table, and
|
|
1311
|
+
writes each added or changed endpoint whole below it; a change planned before delta
|
|
1312
|
+
API plans existed carries the same in its delta backend plan. Serve each added or
|
|
1313
|
+
changed endpoint at the route and verb its block gives, with its field names,
|
|
1314
|
+
status codes and errors as stated, and set the operation id it names as this
|
|
1315
|
+
stack's published API document names operations (its OpenAPI operationId), spelled
|
|
1316
|
+
exactly; an existing endpoint keeps the id it has, and one the change removes is no
|
|
1317
|
+
longer served. The frontend lane binds to each endpoint by that id, and
|
|
1318
|
+
analyze-slice-delta checks the built service against the change's API draft.
|
|
1269
1319
|
- COMPONENTS: if a delta element depends on a framework component, code against its
|
|
1270
1320
|
ABSTRACTION / port as the delta plan declares — do NOT hand-roll it. Installing the
|
|
1271
1321
|
component (packages, wiring, config) is /appweaver add-component <Component>; if
|
|
@@ -1275,7 +1325,10 @@ workflow:
|
|
|
1275
1325
|
requirement id THE DELTA PLAN NAMES for that element (FR / BR / CN / DC / IC / US).
|
|
1276
1326
|
The spec is not in context: take the id from the plan and cite it verbatim, never
|
|
1277
1327
|
guess one from the element's shape. A delta-plan element that names no id is a
|
|
1278
|
-
planning gap — surface it rather than inventing the traceability.
|
|
1328
|
+
planning gap — surface it rather than inventing the traceability. THE CITATION IS
|
|
1329
|
+
CHECKED: analyze-slice-delta fails a lane in which some FR- or BR- its delta plan
|
|
1330
|
+
rows serve is named by no test — written as `FR-004`, `FR_004` or `FR004` in the
|
|
1331
|
+
test's name, a comment, an attribute or a tag, whichever this language allows.
|
|
1279
1332
|
- WIRE WHAT YOU BUILD, in this same pass: every port, adapter, handler and endpoint
|
|
1280
1333
|
this change introduces is registered in the lane's composition root, as the delta
|
|
1281
1334
|
plan states. A dependency injected and never bound compiles green and fails on the
|
|
@@ -1286,11 +1339,12 @@ workflow:
|
|
|
1286
1339
|
shared element changed — but do NOT rewrite that existing behaviour.
|
|
1287
1340
|
- Where generated code depends on a delta Assumption (DA-n) or Workaround (WA-n),
|
|
1288
1341
|
mark it with a comment citing that id.
|
|
1289
|
-
- REPORT EVERY DELTA ELEMENT. The delta plan's ADDED and MODIFIED elements
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
the list counts as not done, and
|
|
1342
|
+
- REPORT EVERY DELTA ELEMENT. The delta plan's ADDED and MODIFIED elements and the
|
|
1343
|
+
endpoints its API delta adds or changes, by name: {{be_element_names}}. Add an
|
|
1344
|
+
`elements` list to your closing JSON block with one entry per name, spelled exactly
|
|
1345
|
+
as listed: {"element": "<name>", "status": "done" | "blocked", "reason": "<what
|
|
1346
|
+
stops it, when blocked>"}. An element missing from the list counts as not done, and
|
|
1347
|
+
the code is checked for each name after this step.
|
|
1294
1348
|
outputs:
|
|
1295
1349
|
- { name: be_files, from: "$.files" }
|
|
1296
1350
|
- { name: be_elements, from: "$.elements" }
|
|
@@ -1313,7 +1367,7 @@ workflow:
|
|
|
1313
1367
|
action: execute_script
|
|
1314
1368
|
script: { ref: actions }
|
|
1315
1369
|
subcommand: plan-coverage
|
|
1316
|
-
args: ["--plan", "{{be_plan}}", "--kind", "backend", "--mode", "{{be_mode}}", "--source-path", "{{be_source_path}}", "--test-path", "{{be_test_path}}", "--reported", "{{be_elements}}", "--generated", "{{be_files}}"]
|
|
1370
|
+
args: ["--plan", "{{be_plan}}", "--kind", "backend", "--mode", "{{be_mode}}", "--api-plan", "{{be_api_doc}}", "--source-path", "{{be_source_path}}", "--test-path", "{{be_test_path}}", "--reported", "{{be_elements}}", "--generated", "{{be_files}}"]
|
|
1317
1371
|
outputs:
|
|
1318
1372
|
- { name: be_complete, from: "$.ok" }
|
|
1319
1373
|
- { name: be_outcome, from: "$.outcome" }
|
|
@@ -1353,8 +1407,8 @@ workflow:
|
|
|
1353
1407
|
COMPLETE the backend lane. The generation pass before this one left these plan
|
|
1354
1408
|
elements unrealised: {{be_gap_names}}.
|
|
1355
1409
|
Why each was flagged: {{be_gaps_text}}.
|
|
1356
|
-
The same
|
|
1357
|
-
pass still holds: realise each element STRICTLY as the
|
|
1410
|
+
The same plans, domain model and constitution are in context, and every rule of that
|
|
1411
|
+
pass still holds: realise each element STRICTLY as the plans state it; production
|
|
1358
1412
|
code only under `{{be_source_path}}` and paired tests only under `{{be_test_path}}`;
|
|
1359
1413
|
the `{{be_lane_id}}` lane's stack ({{be_title}}, {{be_language}}) and no other;
|
|
1360
1414
|
shared aggregate files EXTENDED, never regenerated; nothing the plan does not state.
|
|
@@ -1366,7 +1420,7 @@ workflow:
|
|
|
1366
1420
|
plan's names are the ubiquitous language.
|
|
1367
1421
|
- An element the plan names by intent (a port, an adapter, an endpoint route) is done
|
|
1368
1422
|
when the code realises it, whatever the framework calls it; report it `done`. An
|
|
1369
|
-
endpoint still carries the operation id
|
|
1423
|
+
endpoint still carries the operation id its API plan names, set exactly.
|
|
1370
1424
|
- If an element cannot be realised, do not work around it: report it `blocked` and
|
|
1371
1425
|
say what stops you. A plan that is wrong is fixed in plan / analyze-plan.
|
|
1372
1426
|
- Report every listed element in an `elements` list in your closing JSON block:
|
|
@@ -1379,7 +1433,7 @@ workflow:
|
|
|
1379
1433
|
action: execute_script
|
|
1380
1434
|
script: { ref: actions }
|
|
1381
1435
|
subcommand: plan-coverage
|
|
1382
|
-
args: ["--plan", "{{be_plan}}", "--kind", "backend", "--mode", "{{be_mode}}", "--source-path", "{{be_source_path}}", "--test-path", "{{be_test_path}}", "--reported", "{{be_elements}}", "--reported", "{{be_elements_more}}"]
|
|
1436
|
+
args: ["--plan", "{{be_plan}}", "--kind", "backend", "--mode", "{{be_mode}}", "--api-plan", "{{be_api_doc}}", "--source-path", "{{be_source_path}}", "--test-path", "{{be_test_path}}", "--reported", "{{be_elements}}", "--reported", "{{be_elements_more}}"]
|
|
1383
1437
|
outputs:
|
|
1384
1438
|
- { name: be_complete, from: "$.ok" }
|
|
1385
1439
|
- { name: be_outcome, from: "$.outcome" }
|
|
@@ -1411,68 +1465,32 @@ workflow:
|
|
|
1411
1465
|
outputs:
|
|
1412
1466
|
- { name: okf_concept, from: "$.concept" }
|
|
1413
1467
|
|
|
1414
|
-
# ══════════════ THE API CONTRACT —
|
|
1415
|
-
# The frontend binds to the service through
|
|
1416
|
-
#
|
|
1417
|
-
#
|
|
1418
|
-
#
|
|
1419
|
-
#
|
|
1420
|
-
#
|
|
1421
|
-
#
|
|
1422
|
-
#
|
|
1423
|
-
#
|
|
1424
|
-
#
|
|
1425
|
-
#
|
|
1426
|
-
#
|
|
1427
|
-
#
|
|
1428
|
-
#
|
|
1429
|
-
#
|
|
1430
|
-
#
|
|
1431
|
-
#
|
|
1432
|
-
# serve yet, written to .appweaver/contracts/openapi.combined.json (contract-combine).
|
|
1433
|
-
# That is how a frontend binds to an endpoint the backend has planned and not built.
|
|
1434
|
-
# 4. CLIENT — run the frontend lane's `client` command against the combined document. A
|
|
1468
|
+
# ══════════════ THE API CONTRACT — planned by the backend, bound to by the frontend ═══
|
|
1469
|
+
# The frontend binds to the service through an API document, and the document that counts
|
|
1470
|
+
# is the API plan's: every endpoint api-plan.md names — its backend plan's API section,
|
|
1471
|
+
# for a feature planned before API plans existed — with route, verb, parameters, field
|
|
1472
|
+
# names and status codes, drafted by script into api-draft.json beside it, and, while a
|
|
1473
|
+
# change is open, the change's own draft over it. The code is held to that document
|
|
1474
|
+
# (analyze-slice and analyze-slice-delta check the built service against it), so the two
|
|
1475
|
+
# lanes can be built by different developers at different times and in either order, and
|
|
1476
|
+
# nothing here starts the service. Every step below WARNS and carries on — the frontend
|
|
1477
|
+
# still generates, from its plan, when one of them cannot run.
|
|
1478
|
+
# 1. REQUESTS — the frontend plan's contract requests the API plan has not answered yet
|
|
1479
|
+
# (contract-requests), named to whichever lane runs.
|
|
1480
|
+
# 2. COMBINE (when the frontend lane generates) — every operation the API plans draft,
|
|
1481
|
+
# with the open changes applied, written to
|
|
1482
|
+
# .appweaver/contracts/openapi.combined.json (contract-combine). The service lane's
|
|
1483
|
+
# as-built document, when one is committed, adds the operations no plan describes and
|
|
1484
|
+
# marks the planned ones it does not serve yet.
|
|
1485
|
+
# 3. CLIENT — run the frontend lane's `client` command against the combined document. A
|
|
1435
1486
|
# lane with none yet asks the developer once and records the answer on the lane; an
|
|
1436
1487
|
# empty answer carries on without a generated client.
|
|
1437
|
-
#
|
|
1438
|
-
# document (contract-check, by script);
|
|
1439
|
-
|
|
1440
|
-
condition: "{{be_go}} == true"
|
|
1441
|
-
action: set
|
|
1442
|
-
vars: { contract_go: "true" }
|
|
1443
|
-
- id: contract_export
|
|
1444
|
-
condition: "{{contract_go}} == true"
|
|
1445
|
-
action: execute_script
|
|
1446
|
-
on_error: continue
|
|
1447
|
-
script: { ref: actions }
|
|
1448
|
-
subcommand: contract-export
|
|
1449
|
-
outputs:
|
|
1450
|
-
- { name: contract_ok, from: "$.ok" }
|
|
1451
|
-
- { name: export_doc, from: "$.doc" }
|
|
1452
|
-
- { name: export_doc_exists, from: "$.doc_exists" }
|
|
1453
|
-
- { name: contract_reason, from: "$.reason" }
|
|
1454
|
-
- { name: contract_already, from: "$.already_running" }
|
|
1455
|
-
- { name: contract_ops, from: "$.operations" }
|
|
1456
|
-
- { name: contract_log, from: "$.log_tail" }
|
|
1457
|
-
- { name: contract_export_status, from: "$.status" }
|
|
1458
|
-
- id: warn_contract_export
|
|
1459
|
-
condition: "{{contract_go}} == true"
|
|
1460
|
-
action: verify_context
|
|
1461
|
-
require_true: contract_ok
|
|
1462
|
-
on_false: continue
|
|
1463
|
-
on_false_message: "API DOCUMENT NOT EXPORTED — {{contract_reason}}. The service lane `{{be_lane_id}}` is started with its `contract_run` command and its document fetched from its `contract` URL, both read from .appweaver/stacks.json or else its stack profile; correct them on the lane there if they do not fit this project, start anything the service needs, and re-run implement or build. Until it is exported and committed, the frontend lane binds to the last committed document plus the backend plan's draft. Service output: {{contract_log}}"
|
|
1464
|
-
- id: contract_stale_flag
|
|
1465
|
-
condition: "{{contract_already}} == true"
|
|
1466
|
-
action: set
|
|
1467
|
-
vars: { contract_fresh: "false" }
|
|
1468
|
-
- id: warn_contract_stale
|
|
1469
|
-
condition: "{{contract_go}} == true"
|
|
1470
|
-
action: verify_context
|
|
1471
|
-
require_true: contract_fresh
|
|
1472
|
-
on_false: continue
|
|
1473
|
-
on_false_message: "WARNING — the API document was {{contract_reason}}. Stop that service and re-run implement to export the code as it is now."
|
|
1488
|
+
# 4. CHECK — every operation id the frontend plan cites must be in the combined
|
|
1489
|
+
# document (contract-check, by script); one an open change removes, and one the
|
|
1490
|
+
# service does not serve yet, are named apart.
|
|
1474
1491
|
|
|
1475
|
-
#
|
|
1492
|
+
# 1. THE REQUEST LEDGER — read from the frontend plan and the API plan, for whichever lane
|
|
1493
|
+
# runs.
|
|
1476
1494
|
- id: contract_requests
|
|
1477
1495
|
action: execute_script
|
|
1478
1496
|
on_error: continue
|
|
@@ -1492,15 +1510,15 @@ workflow:
|
|
|
1492
1510
|
action: verify_context
|
|
1493
1511
|
require_true: req_clear
|
|
1494
1512
|
on_false: continue
|
|
1495
|
-
on_false_message: "FRONTEND CONTRACT REQUESTS OPEN — the frontend plan asks the service for {{req_open_csv}}, and
|
|
1513
|
+
on_false_message: "FRONTEND CONTRACT REQUESTS OPEN — the frontend plan asks the service for {{req_open_csv}}, and the API plan has not answered them: {{req_backend_text}}. This run generated the backend lane from its plans as they stand. Answer each request in the API plan's requests table — publish it under an operation id, or decline it with the reason — with /appweaver plan or /appweaver analyze-plan for the backend lane, then re-run implement."
|
|
1496
1514
|
- id: warn_requests_frontend
|
|
1497
1515
|
condition: "{{fe_go}} == true"
|
|
1498
1516
|
action: verify_context
|
|
1499
1517
|
require_true: req_clear
|
|
1500
1518
|
on_false: continue
|
|
1501
|
-
on_false_message: "CONTRACT REQUESTS STILL OPEN — {{req_open_csv}}: the frontend plan asks the service for these and the
|
|
1519
|
+
on_false_message: "CONTRACT REQUESTS STILL OPEN — {{req_open_csv}}: the frontend plan asks the service for these and the API plan has not answered them. The bindings that wait on them are left unbound and marked in this run, and the rest of the frontend lane generates. The backend lane's developer answers them in the API plan (api-plan.md, or the backend plan of a feature planned before API plans existed); re-run implement once they are published."
|
|
1502
1520
|
|
|
1503
|
-
#
|
|
1521
|
+
# 2. THE COMBINED DOCUMENT — what the frontend reads, never the running service.
|
|
1504
1522
|
- id: combine_arm
|
|
1505
1523
|
condition: "{{fe_go}} == true"
|
|
1506
1524
|
action: set
|
|
@@ -1524,7 +1542,7 @@ workflow:
|
|
|
1524
1542
|
action: verify_context
|
|
1525
1543
|
require_true: combined_ok
|
|
1526
1544
|
on_false: continue
|
|
1527
|
-
on_false_message: "NO API DOCUMENT — {{combined_reason}}. The backend lane
|
|
1545
|
+
on_false_message: "NO API DOCUMENT — {{combined_reason}}. The backend lane drafts its API plan's endpoints into api-draft.json beside it when plan or analyze-plan runs and when finalize-delta merges a change, and a change's into its change folder; once they are committed and pulled here, re-run implement. Until then the frontend lane binds from its plan and the feature's API plan."
|
|
1528
1546
|
- id: contract_doc_set
|
|
1529
1547
|
condition: "{{combined_ok}} == true"
|
|
1530
1548
|
action: set
|
|
@@ -1540,9 +1558,9 @@ workflow:
|
|
|
1540
1558
|
action: verify_context
|
|
1541
1559
|
require_true: clashes_clear
|
|
1542
1560
|
on_false: continue
|
|
1543
|
-
on_false_message: "
|
|
1561
|
+
on_false_message: "API DOCUMENT CLASH — {{combined_clashes}}. Each is left as the plan states it: an endpoint drafted twice keeps its first draft, and a route the service answers under another operation id keeps the plan's id, which the frontend binds by. The backend lane corrects the plan (/appweaver plan or analyze-plan) or the code (analyze-slice reports the served id that differs)."
|
|
1544
1562
|
|
|
1545
|
-
#
|
|
1563
|
+
# 3. THE CLIENT, generated from the combined document — so only once there is one.
|
|
1546
1564
|
- id: client_arm
|
|
1547
1565
|
condition: "{{contract_doc_exists}} == true"
|
|
1548
1566
|
action: set
|
|
@@ -1610,7 +1628,7 @@ workflow:
|
|
|
1610
1628
|
on_false: continue
|
|
1611
1629
|
on_false_message: "NO API CLIENT GENERATED — the frontend lane `{{fe_lane_id}}` has no working `client` command, so this run writes its calls from the API document {{contract_doc}} instead. Set `client` on the lane in .appweaver/stacks.json (`{{contract_placeholder}}` stands for the document) to generate the client on the next run."
|
|
1612
1630
|
|
|
1613
|
-
#
|
|
1631
|
+
# 4. THE CHECK — the operation ids the frontend plan cites, against the combined document.
|
|
1614
1632
|
- id: contract_check
|
|
1615
1633
|
condition: "{{client_go}} == true"
|
|
1616
1634
|
action: execute_script
|
|
@@ -1619,25 +1637,36 @@ workflow:
|
|
|
1619
1637
|
subcommand: contract-check
|
|
1620
1638
|
args: ["--plan", "{{fe_plan}}", "--doc", "{{contract_doc}}"]
|
|
1621
1639
|
outputs:
|
|
1622
|
-
- { name: check_ok,
|
|
1623
|
-
- { name: check_reason,
|
|
1624
|
-
- { name:
|
|
1640
|
+
- { name: check_ok, from: "$.ok" }
|
|
1641
|
+
- { name: check_reason, from: "$.reason" }
|
|
1642
|
+
- { name: check_unserved, from: "$.unserved_csv" }
|
|
1643
|
+
- { name: check_removed, from: "$.removed_csv" }
|
|
1625
1644
|
- id: warn_contract_check
|
|
1626
1645
|
condition: "{{client_go}} == true"
|
|
1627
1646
|
action: verify_context
|
|
1628
1647
|
require_true: check_ok
|
|
1629
1648
|
on_false: continue
|
|
1630
|
-
on_false_message: "CONTRACT CHECK — {{check_reason}}. Each binding in {{fe_plan}} names the endpoint it calls by the operation id the
|
|
1631
|
-
- id:
|
|
1632
|
-
condition: "{{
|
|
1649
|
+
on_false_message: "CONTRACT CHECK — {{check_reason}}. Each binding in {{fe_plan}} names the endpoint it calls by the operation id the API plan gives it, or the id its contract request proposes. An id in no document belongs to a contract request the backend has not answered (open now: [{{req_open_csv}}]), or the frontend plan cites the wrong id (fix it with /appweaver plan, then analyze-plan), or the API plan has not published the endpoint yet. The frontend lane still generates; these bindings are where a call will fail."
|
|
1650
|
+
- id: unserved_flag
|
|
1651
|
+
condition: "{{check_unserved}} != "
|
|
1652
|
+
action: set
|
|
1653
|
+
vars: { unserved_clear: "false" }
|
|
1654
|
+
- id: warn_unserved
|
|
1655
|
+
condition: "{{client_go}} == true"
|
|
1656
|
+
action: verify_context
|
|
1657
|
+
require_true: unserved_clear
|
|
1658
|
+
on_false: continue
|
|
1659
|
+
on_false_message: "BOUND TO OPERATIONS NOT SERVED YET — {{check_unserved}}: the API plan publishes these, and the service's as-built document does not serve them yet. The frontend binds to them through the client as to any other operation; the calls fail at run time until the backend lane implements them."
|
|
1660
|
+
- id: removed_flag
|
|
1661
|
+
condition: "{{check_removed}} != "
|
|
1633
1662
|
action: set
|
|
1634
|
-
vars: {
|
|
1635
|
-
- id:
|
|
1663
|
+
vars: { removed_clear: "false" }
|
|
1664
|
+
- id: warn_removed
|
|
1636
1665
|
condition: "{{client_go}} == true"
|
|
1637
1666
|
action: verify_context
|
|
1638
|
-
require_true:
|
|
1667
|
+
require_true: removed_clear
|
|
1639
1668
|
on_false: continue
|
|
1640
|
-
on_false_message: "BOUND TO
|
|
1669
|
+
on_false_message: "BOUND TO OPERATIONS AN OPEN CHANGE REMOVES — {{check_removed}}: each is still in the API document, marked deprecated, until the service stops serving it once its change is implemented — or, where the change serves another operation on its route, is already replaced by that one, and the client no longer has it. Re-bind those elements — in the change's frontend delta plan (/appweaver plan <CR-id>) or a follow-up change — before then."
|
|
1641
1670
|
|
|
1642
1671
|
# ══════════════ THE LANE SWAP — the frontend's rules replace the backend's ═══
|
|
1643
1672
|
# build_context already scoped the two lanes' PAYLOADS apart; this is the same boundary
|
|
@@ -1659,7 +1688,8 @@ workflow:
|
|
|
1659
1688
|
# The experience twin of the service generation, one lane over. Its own build_context,
|
|
1660
1689
|
# because the envelope persists across steps and the two lanes must not see each other's
|
|
1661
1690
|
# payload — the frontend binds to the service's PUBLISHED surface, never its internals.
|
|
1662
|
-
# That surface is the API document the contract block
|
|
1691
|
+
# That surface is the API document the contract block combined, when there is one, and
|
|
1692
|
+
# the feature's API plan it was drafted from; the backend plan is never in context here.
|
|
1663
1693
|
- id: ctx_frontend
|
|
1664
1694
|
condition: "{{fe_mode}} == bootstrap"
|
|
1665
1695
|
action: build_context
|
|
@@ -1667,7 +1697,8 @@ workflow:
|
|
|
1667
1697
|
- { path: "{{fe_plan}}" }
|
|
1668
1698
|
- { path: "{{domain_model}}", optional: true } # the UBIQUITOUS LANGUAGE this lane's labels, states and messages use — and what a cited BR-nnn requires
|
|
1669
1699
|
- { path: .appweaver/memory/constitution.ui.md, optional: true } # the lane's ratified UX-* base — conventions, forbidden patterns, gates
|
|
1670
|
-
- { path: "{{contract_doc}}", optional: true } # the combined API document — the
|
|
1700
|
+
- { path: "{{contract_doc}}", optional: true } # the combined API document — every operation the API plans publish, with the open changes applied
|
|
1701
|
+
- { path: "{{api_plan}}", optional: true } # the feature's API plan — the endpoint blocks the document is drafted from, and the answers to this plan's requests
|
|
1671
1702
|
- id: gen_frontend
|
|
1672
1703
|
condition: "{{fe_mode}} == bootstrap"
|
|
1673
1704
|
action: agent_generate
|
|
@@ -1761,15 +1792,24 @@ workflow:
|
|
|
1761
1792
|
semantics and rollback each row states.
|
|
1762
1793
|
• §6 — the cross-cutting decisions as code: what is hidden vs disabled,
|
|
1763
1794
|
accessibility obligations, localization, performance and offline behaviour.
|
|
1764
|
-
- THE
|
|
1795
|
+
- THE API DOCUMENT IS THE CONTRACT. API document: {{contract_status}}.
|
|
1765
1796
|
Each §5 row names its endpoint by Operation id; find that operation in the
|
|
1766
1797
|
document and take EVERYTHING about the call from it — route, verb, path and query
|
|
1767
1798
|
parameters, request and response field names and their casing, status codes and
|
|
1768
1799
|
error codes. Never take a route, a field name or a paging convention from memory,
|
|
1769
|
-
from convention or from the loaded standards' examples: the document is
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1800
|
+
from convention or from the loaded standards' examples: the document is drafted
|
|
1801
|
+
from the API plans, and the service is checked against it. This feature's
|
|
1802
|
+
api-plan.md is in context too where it has one — the endpoint blocks the document
|
|
1803
|
+
was drafted from, and the answers to this plan's contract requests. Read it for
|
|
1804
|
+
what a block states that the document cannot carry, such as when each error is
|
|
1805
|
+
returned; where the two differ on a route, verb, field or status, follow the
|
|
1806
|
+
document, which the client was generated from. Bind to every
|
|
1807
|
+
operation in it the same way, through the client, and never stub, mock or fake a
|
|
1808
|
+
response in production code — also one marked `x-aw-unserved` (planned, not served
|
|
1809
|
+
yet) or `deprecated` (an open change removes it: bind to it only where the plan
|
|
1810
|
+
says to, and say so in your summary). An id in the document's `x-aw-removed` list
|
|
1811
|
+
is one an open change removes and has replaced on its route: it is not in the
|
|
1812
|
+
client, so its row is a broken binding (below) — name that change when you report it.
|
|
1773
1813
|
- A BINDING THAT WAITS ON AN OPEN CONTRACT REQUEST (open now: [{{req_open_csv}}]) is
|
|
1774
1814
|
not broken: its operation is in no document because the backend has not answered. Realise
|
|
1775
1815
|
the screen or component in full, write nothing that pretends to call the service
|
|
@@ -1785,7 +1825,10 @@ workflow:
|
|
|
1785
1825
|
- Author a paired test for every screen, interaction and state the plan names —
|
|
1786
1826
|
including the unwanted-behaviour states from §4 and an accessibility assertion per
|
|
1787
1827
|
interactive surface — and cite the spec id (UX-/US-/FR-/CN-/DC-/IC-/SC-) from the
|
|
1788
|
-
plan's §7 Traceability in each test. A snapshot alone is not a test.
|
|
1828
|
+
plan's §7 Traceability in each test. A snapshot alone is not a test. THE CITATION IS
|
|
1829
|
+
CHECKED: analyze-slice fails a slice in which some FR- or BR- of §7 is named by no
|
|
1830
|
+
test — written as `FR-004`, `FR_004` or `FR004` in the test's name, a comment, an
|
|
1831
|
+
attribute or a tag.
|
|
1789
1832
|
- Do NOT add behaviour the plan does not state, and do NOT omit any it does. If the
|
|
1790
1833
|
plan looks wrong or incomplete, STOP and surface it (it is fixed in plan /
|
|
1791
1834
|
analyze-plan) — never compensate from the spec or from memory.
|
|
@@ -1820,7 +1863,9 @@ workflow:
|
|
|
1820
1863
|
- { path: "{{frontend_plan}}", optional: true } # the master plan — READ ONLY, never amended here
|
|
1821
1864
|
- { path: "{{domain_model}}", optional: true } # the master model — the ubiquitous language as it stands BEFORE this change
|
|
1822
1865
|
- { path: .appweaver/memory/constitution.ui.md, optional: true }
|
|
1823
|
-
- { path: "{{contract_doc}}", optional: true } # the combined API document — the
|
|
1866
|
+
- { path: "{{contract_doc}}", optional: true } # the combined API document — every operation the API plans publish, with the open changes applied
|
|
1867
|
+
- { path: "{{delta_api_plan}}", optional: true } # this change's API delta — its Contract deltas table and the endpoints it writes whole
|
|
1868
|
+
- { path: "{{api_plan}}", optional: true } # the feature's API plan — the endpoints as they stand BEFORE this change
|
|
1824
1869
|
- id: gen_frontend_delta
|
|
1825
1870
|
condition: "{{fe_mode}} == delta"
|
|
1826
1871
|
action: agent_generate
|
|
@@ -1897,16 +1942,21 @@ workflow:
|
|
|
1897
1942
|
A new interaction without them is an incomplete implementation, not a later
|
|
1898
1943
|
refinement.
|
|
1899
1944
|
- BIND AGAINST THE PUBLISHED SURFACE ONLY: the delta plan's binding rows and the
|
|
1900
|
-
|
|
1901
|
-
|
|
1945
|
+
change's API delta — the "Contract deltas for the frontend lane" table of
|
|
1946
|
+
delta-api-plan.md, in context where the change has one — as the delta plan cites
|
|
1947
|
+
them. Generate no server-side behaviour, no persistence and no business rule
|
|
1902
1948
|
evaluation.
|
|
1903
|
-
- THE
|
|
1949
|
+
- THE API DOCUMENT IS THE CONTRACT. API document: {{contract_status}}.
|
|
1904
1950
|
Each binding row leads with its endpoint's operation id; find that operation in
|
|
1905
1951
|
the document and take EVERYTHING about the call from it — route, verb, path and
|
|
1906
1952
|
query parameters, request and response field names and their casing, status
|
|
1907
1953
|
codes and error codes — never from memory, convention or the standards' examples.
|
|
1908
|
-
|
|
1909
|
-
|
|
1954
|
+
It carries this change's own API changes over the master's. The feature's
|
|
1955
|
+
api-plan.md and this change's delta-api-plan.md, in context where they exist, are
|
|
1956
|
+
what it was drafted from: read them for what a block states that the document
|
|
1957
|
+
cannot carry, and follow the document where they differ. Bind to every
|
|
1958
|
+
operation through the client the same way — also one marked `x-aw-unserved`
|
|
1959
|
+
(planned, not served yet) — and never stub, mock or fake its response.
|
|
1910
1960
|
A binding whose id the document does not have is broken: leave that call unbound,
|
|
1911
1961
|
report the element `blocked` naming the id, and never guess a substitute.
|
|
1912
1962
|
- THE CLIENT: {{client_status}}. The client lives in this lane's client layer; a
|
|
@@ -1916,6 +1966,9 @@ workflow:
|
|
|
1916
1966
|
interactive surface, citing the requirement id THE DELTA PLAN NAMES for that row
|
|
1917
1967
|
(UX-/US-/FR-/CN-/DC-/IC-/SC-). The spec is not in context: take the id from the
|
|
1918
1968
|
plan and cite it verbatim. A row that names no id is a planning gap — surface it.
|
|
1969
|
+
THE CITATION IS CHECKED: analyze-slice-delta fails the lane when some FR- or BR- the
|
|
1970
|
+
delta plan rows serve is named by no test (`FR-004`, `FR_004` or `FR004`, in the
|
|
1971
|
+
test's name, a comment, an attribute or a tag).
|
|
1919
1972
|
- REGRESSION: for each element in the delta plan's regression targets, verify (add or
|
|
1920
1973
|
adjust a test where needed) that the existing behaviour still holds after a shared
|
|
1921
1974
|
component or state container changed — but do NOT rewrite that behaviour.
|
|
@@ -2150,13 +2203,13 @@ outputs:
|
|
|
2150
2203
|
cr_id: "{{active_change}}"
|
|
2151
2204
|
backend_implemented: "{{be_go}}"
|
|
2152
2205
|
backend_plan: "{{be_plan}}" # the document the backend lane generated FROM
|
|
2206
|
+
api_plan: "{{be_api_doc}}" # the API plan it served — empty where that plan carries its own API section
|
|
2153
2207
|
backend_files: "{{be_files}}"
|
|
2154
2208
|
frontend_implemented: "{{fe_go}}"
|
|
2155
2209
|
frontend_plan: "{{fe_plan}}" # the document the frontend lane generated FROM
|
|
2156
2210
|
frontend_files: "{{fe_files}}"
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
contract_requests: "{{req_summary}}" # the frontend plan's RQ-n requests and the backend plan's answers
|
|
2211
|
+
frontend_api_document: "{{contract_doc}}" # what the frontend bound to: every operation the API plans publish, with the open changes applied (not committed)
|
|
2212
|
+
contract_requests: "{{req_summary}}" # the frontend plan's RQ-n requests and the API plan's answers
|
|
2160
2213
|
# Every plan element realised, per lane — `true` for a lane that did not generate.
|
|
2161
2214
|
# `*_completion_pass` says whether the first pass left gaps a second one had to close.
|
|
2162
2215
|
# `*_outcome` is the one word for what the lane did: complete (it generated and every
|
|
@@ -2192,5 +2245,5 @@ outputs:
|
|
|
2192
2245
|
frontend_plan_gate_at: "{{fe_gate_at}}"
|
|
2193
2246
|
frontend_plan_gate_verdict: "{{fe_gate_verdict}}"
|
|
2194
2247
|
frontend_plan_gate_routed_to_specify: "{{fe_gate_routed_csv}}"
|
|
2195
|
-
note: "Lanes come from .appweaver/stacks.json, and the ones you work on from .appweaver/lane.json (`{{working_lane}}`) — backend declared {{be_declared}} (worked {{be_working}}, ready {{be_runnable}}, implemented {{be_go}}), frontend declared {{fe_declared}} (worked {{fe_working}}, ready {{fe_runnable}}, implemented {{fe_go}}). A declared lane you do not work on is left to its developer and is not reported here. A declared lane that was skipped printed its reason above and did not stop the other one; an undeclared lane produces nothing and that is not a failure. Each generating lane read its PLAN for what to build and {{domain_model}} for what the domain is — plus {{delta_model}} on the delta path, since the master model does not carry the change until finalize-delta merges it. Every one of those documents was READ and none was written: this phase generates code and nothing else. Each lane's outcome is backend={{be_outcome}}, frontend={{fe_outcome}} — `already-implemented` means the lane wrote no files because every plan element was already realised in its lane root folder, which is the correct result of re-running implement on a finished feature and not a failure. On the bootstrap path each working lane's plan was checked against that lane's analyze-plan receipt before anything generated (backend tracked={{be_gate_tracked}}, fresh={{be_gate_fresh}}, gated {{be_gate_at}}; frontend tracked={{fe_gate_tracked}}, fresh={{fe_gate_fresh}}, gated {{fe_gate_at}}) — tracked=false means that lane has never passed analyze-plan since the gate began recording what it proved, which is an unknown rather than a stale plan and blocks nothing; run /appweaver analyze-plan once to start the record."
|
|
2248
|
+
note: "Lanes come from .appweaver/stacks.json, and the ones you work on from .appweaver/lane.json (`{{working_lane}}`) — backend declared {{be_declared}} (worked {{be_working}}, ready {{be_runnable}}, implemented {{be_go}}), frontend declared {{fe_declared}} (worked {{fe_working}}, ready {{fe_runnable}}, implemented {{fe_go}}). A declared lane you do not work on is left to its developer and is not reported here. A declared lane that was skipped printed its reason above and did not stop the other one; an undeclared lane produces nothing and that is not a failure. Each generating lane read its PLAN for what to build — the backend lane with the API plan beside it, where there is one ({{be_api_doc}}) — and {{domain_model}} for what the domain is — plus {{delta_model}} on the delta path, since the master model does not carry the change until finalize-delta merges it. Every one of those documents was READ and none was written: this phase generates code and nothing else. Each lane's outcome is backend={{be_outcome}}, frontend={{fe_outcome}} — `already-implemented` means the lane wrote no files because every plan element was already realised in its lane root folder, which is the correct result of re-running implement on a finished feature and not a failure. On the bootstrap path each working lane's plan was checked against that lane's analyze-plan receipt before anything generated (backend tracked={{be_gate_tracked}}, fresh={{be_gate_fresh}}, gated {{be_gate_at}}; frontend tracked={{fe_gate_tracked}}, fresh={{fe_gate_fresh}}, gated {{fe_gate_at}}) — tracked=false means that lane has never passed analyze-plan since the gate began recording what it proved, which is an unknown rather than a stale plan and blocks nothing; run /appweaver analyze-plan once to start the record."
|
|
2196
2249
|
next: "This run was mode `{{mode}}`, change `{{active_change}}` (empty on the bootstrap path). BOOTSTRAP → /appweaver build → analyze-slice → run. DELTA → /appweaver build → analyze-slice-delta {{active_change}} → finalize-delta → analyze-slice → close-delta, with the change still OPEN throughout — compile first, then analyze-slice-delta verifies that every element the delta plans marked ADDED or MODIFIED is actually in the code with a paired test (the gate that catches a lane you declined at the prompt above), then finalize-delta merges it into spec.md + the context's domain-model.md while leaving it open, analyze-slice verifies the slice against those merged masters while a red result is still recoverable, and close-delta LAST archives the change and bumps the version."
|