aw-spec-cli 0.1.33 → 0.1.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -81
- package/assets/.appweaver/DESIGN-FORMAT.md +57 -25
- 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 -20
- package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +22 -48
- 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 +239 -40
- 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 +21 -22
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +453 -120
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-lane.orch.yaml +2 -2
- 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
|
@@ -24,6 +24,18 @@
|
|
|
24
24
|
# builds green, passes unit tests that construct their subject directly,
|
|
25
25
|
# and fails on the first request. Fixed up to 2×.
|
|
26
26
|
# 3. KNOWLEDGE refresh + review the slice's OKF concept (advisory).
|
|
27
|
+
# 4. TRACEABILITY does a test of the slice NAME every FR- and BR- its plans trace? Green
|
|
28
|
+
# tests cannot show a requirement whose test was never written, so each
|
|
29
|
+
# working lane's plan is read for its ids and the slice's test files for
|
|
30
|
+
# citations. It warns, and the gate fails at the END, like the no-tests case.
|
|
31
|
+
# 5. API does the built service serve the endpoints its API plan publishes?
|
|
32
|
+
# The frontend lane is bound to that API (api-draft.json), so the
|
|
33
|
+
# service's as-built document is written the way the lane says and
|
|
34
|
+
# compared with it. A planned endpoint not served, or served under another
|
|
35
|
+
# route, verb or operation id, fails the gate at the END; a field or status
|
|
36
|
+
# code that differs is reported. A lane that sets no way to write the
|
|
37
|
+
# document is not checked, and the run says so. A feature whose plan
|
|
38
|
+
# names no endpoint is not checked either, and the document is not written.
|
|
27
39
|
# Every fix made here is recorded in that concept, which is also where the slice's
|
|
28
40
|
# file list is READ from (2.3.0 — `aw-xref concept-paths`, replacing the retired
|
|
29
41
|
# `design-paths` scan for ```lang path=… fences that the tech-agnostic backend-plan.md no
|
|
@@ -61,9 +73,11 @@
|
|
|
61
73
|
# gate asks of the whole spec, narrowed to one change's ids and answered while the delta is
|
|
62
74
|
# still the only document that carries them. This gate cannot substitute for it: it is
|
|
63
75
|
# test-driven, and a requirement that was never implemented leaves NO test rather than a
|
|
64
|
-
# failing one
|
|
65
|
-
#
|
|
66
|
-
#
|
|
76
|
+
# failing one. Pass 4 catches the part of that a script can see — an FR- or BR- the master
|
|
77
|
+
# plans trace that no test names — but a change's NEW ids reach the master plans only when
|
|
78
|
+
# plan re-derives them, after this gate, so its twin checks those. What this gate does that
|
|
79
|
+
# its twin cannot is score the WHOLE slice, against masters that carry the change, with the
|
|
80
|
+
# fix loops and the referrer blast radius.
|
|
67
81
|
#
|
|
68
82
|
# THE WORKING LANE. Only the lanes the developer on this machine works on (.appweaver/
|
|
69
83
|
# lane.json — select-stack writes the default, select-lane narrows it) are tested, fixed and
|
|
@@ -77,8 +91,8 @@
|
|
|
77
91
|
# =============================================================================
|
|
78
92
|
|
|
79
93
|
name: aw-spec-analyze-slice
|
|
80
|
-
description: The design↔code conformance gate — run the slice's tests against its acceptance criteria, check the code against the domain gate overlays AND the bounded context's domain-model.md (every invariant the slice's own aggregate section states must be enforced as written; one another aggregate owns is reported, not blocking), verify the change did not break any referring aggregate (the OKF referrer blast radius) and write a triage report before stopping if it did, refresh + review its OKF concept,
|
|
81
|
-
version: 2.
|
|
94
|
+
description: The design↔code conformance gate — run the slice's tests against its acceptance criteria, check the code against the domain gate overlays AND the bounded context's domain-model.md (every invariant the slice's own aggregate section states must be enforced as written; one another aggregate owns is reported, not blocking), verify the change did not break any referring aggregate (the OKF referrer blast radius) and write a triage report before stopping if it did, refresh + review its OKF concept, record every fix in it, and check that a test of the slice names every FR- and BR- its lane plans trace (a requirement whose test was never written leaves the suite green; a reverse-engineered plan's gaps are reported, not blocking), and check that the built service serves every endpoint its API plan publishes — the frontend lane is bound to the plan, never to the running service — by writing the service's as-built API document the way the lane says and comparing the two (a missing or moved endpoint fails; a differing field is reported). Sits after finalize-delta on the change path, so the two masters it scores against already carry the change, and before close-delta, so a red gate leaves the change open and recoverable.
|
|
95
|
+
version: 2.11.0
|
|
82
96
|
agent_agnostic: true
|
|
83
97
|
dialect: aw-spec.orchestrator/v1
|
|
84
98
|
|
|
@@ -157,6 +171,46 @@ vars:
|
|
|
157
171
|
# readable in the outputs even when a step is skipped or errors out.
|
|
158
172
|
okf_ok: "unknown"
|
|
159
173
|
okf_orphans: "0"
|
|
174
|
+
# Pass 4 (traceability). A lane votes into trace_ok only when it is worked, and its vote
|
|
175
|
+
# is its check's own `ok` — a check that never answered votes not met.
|
|
176
|
+
fe_working: "false"
|
|
177
|
+
be_test_path: ""
|
|
178
|
+
fe_source_path: ""
|
|
179
|
+
fe_test_path: ""
|
|
180
|
+
frontend_plan: ""
|
|
181
|
+
be_trace_ok: "false"
|
|
182
|
+
be_trace_clean: "false"
|
|
183
|
+
be_trace_warning: ""
|
|
184
|
+
be_untraced: "not checked — no backend lane is worked here"
|
|
185
|
+
be_trace_vote: "true"
|
|
186
|
+
fe_trace_ok: "false"
|
|
187
|
+
fe_trace_clean: "false"
|
|
188
|
+
fe_trace_warning: ""
|
|
189
|
+
fe_untraced: "not checked — no frontend lane is worked here"
|
|
190
|
+
fe_trace_vote: "true"
|
|
191
|
+
trace_ok: "false"
|
|
192
|
+
# Pass 5 — the API check of the service lane. A refusing default for the verdict: it is
|
|
193
|
+
# raised to the check's `ok` only when the check ran, and stays "true" when this
|
|
194
|
+
# developer does not work on the service lane or the lane sets no way to write its
|
|
195
|
+
# document — both of which warn instead — or the plan names no endpoint to check.
|
|
196
|
+
api_needed: "false" # contract-verify --check: the plan names something to check
|
|
197
|
+
api_plan_note: "" # why it names nothing, when it does not
|
|
198
|
+
api_way: ""
|
|
199
|
+
api_doc: ""
|
|
200
|
+
api_placeholder: ""
|
|
201
|
+
api_export_ok: "false"
|
|
202
|
+
api_export_reason: ""
|
|
203
|
+
api_export_log: ""
|
|
204
|
+
api_has_way: "true"
|
|
205
|
+
api_export_vote: "true"
|
|
206
|
+
api_export_clean: "true"
|
|
207
|
+
api_ok: ""
|
|
208
|
+
api_checked: "false"
|
|
209
|
+
api_issues: "not checked — no as-built API document was written in this run"
|
|
210
|
+
api_warning: ""
|
|
211
|
+
api_note: ""
|
|
212
|
+
api_clean: "true"
|
|
213
|
+
api_vote: "true"
|
|
160
214
|
|
|
161
215
|
workflow:
|
|
162
216
|
|
|
@@ -181,6 +235,7 @@ workflow:
|
|
|
181
235
|
- { name: feature_dir, from: "$.feature_dir" }
|
|
182
236
|
- { name: spec_file, from: "$.spec_file" }
|
|
183
237
|
- { name: backend_plan, from: "$.backend_plan" } # the ports + §4.3 wiring the composition pass reads
|
|
238
|
+
- { name: frontend_plan, from: "$.frontend_plan" } # its §7 Traceability, read by pass 4
|
|
184
239
|
|
|
185
240
|
- id: require_feature
|
|
186
241
|
action: verify_context
|
|
@@ -270,6 +325,10 @@ workflow:
|
|
|
270
325
|
- { name: working_root, from: "$.working_root" }
|
|
271
326
|
- { name: working_test_path, from: "$.working_test_path" }
|
|
272
327
|
- { name: be_working, from: "$.backend_working" }
|
|
328
|
+
- { name: fe_working, from: "$.frontend_working" }
|
|
329
|
+
- { name: be_test_path, from: "$.backend_test_path" }
|
|
330
|
+
- { name: fe_source_path, from: "$.frontend_source_path" }
|
|
331
|
+
- { name: fe_test_path, from: "$.frontend_test_path" }
|
|
273
332
|
|
|
274
333
|
# The slice's source files, from its OKF concept — the context all three passes below
|
|
275
334
|
# work over (test fix loop, integrity triage, conformance). `--under` keeps the working
|
|
@@ -444,13 +503,38 @@ workflow:
|
|
|
444
503
|
# forbidden-patterns / refusal conditions / CI gates). The overlays load as the
|
|
445
504
|
# checklist — VALIDATION only, never an authoring input to feature code. No-op for a
|
|
446
505
|
# non-domain project. Fix violations (bounded 2×); the gate stops if any remain.
|
|
506
|
+
# A non-domain project's map holds the heading with a `_None_` line; a map with no such
|
|
507
|
+
# heading, or one naming a file that is not on disk, warns and carries on.
|
|
447
508
|
- id: resolve_gate_overlays
|
|
448
509
|
action: execute_script
|
|
449
510
|
script: { ref: actions }
|
|
450
511
|
subcommand: resolve-domain
|
|
451
512
|
args: ["--command", "aw-spec-gate"]
|
|
452
513
|
outputs:
|
|
453
|
-
- { name: gate_overlays,
|
|
514
|
+
- { name: gate_overlays, from: "$.candidates" }
|
|
515
|
+
- { name: gate_domain, from: "$.domain" }
|
|
516
|
+
- { name: gate_map_exists, from: "$.rulemap_exists" }
|
|
517
|
+
- { name: gate_heading_found, from: "$.heading_found" }
|
|
518
|
+
- { name: gate_missing, from: "$.missing" }
|
|
519
|
+
- id: gate_flags
|
|
520
|
+
action: set
|
|
521
|
+
vars: { gate_all_on_disk: "true" }
|
|
522
|
+
- id: gate_flag_missing
|
|
523
|
+
condition: "{{gate_missing}} != []"
|
|
524
|
+
action: set
|
|
525
|
+
vars: { gate_all_on_disk: "false" }
|
|
526
|
+
- id: warn_gate_heading
|
|
527
|
+
condition: "{{gate_map_exists}} == true"
|
|
528
|
+
action: verify_context
|
|
529
|
+
require_true: gate_heading_found
|
|
530
|
+
on_false: continue
|
|
531
|
+
on_false_message: "WARNING — guardrails/{{gate_domain}}/domain-rule-bindings.md has no `## /aw-spec-gate` heading, so the code is checked against no domain checklist. If that is not intended, add the heading and its overlay files — it must read exactly `## /aw-spec-gate`; a project with no checklist keeps the heading with a `_None_` line."
|
|
532
|
+
- id: warn_gate_missing
|
|
533
|
+
condition: "{{gate_map_exists}} == true"
|
|
534
|
+
action: verify_context
|
|
535
|
+
require_true: gate_all_on_disk
|
|
536
|
+
on_false: continue
|
|
537
|
+
on_false_message: "WARNING — guardrails/{{gate_domain}}/domain-rule-bindings.md maps these checklist files under `## /aw-spec-gate`, but they are not on disk, so the code was not checked against them: {{gate_missing}}. Correct the paths, or add the files."
|
|
454
538
|
- id: load_gate_overlays
|
|
455
539
|
action: load_standards
|
|
456
540
|
files_from_variable: gate_overlays
|
|
@@ -806,10 +890,187 @@ workflow:
|
|
|
806
890
|
- { name: okf_ok, from: "$.ok" }
|
|
807
891
|
- { name: okf_orphans, from: "$.orphan_count" }
|
|
808
892
|
|
|
809
|
-
#
|
|
810
|
-
#
|
|
811
|
-
#
|
|
812
|
-
#
|
|
893
|
+
# ═══════ PASS 4 — TRACEABILITY: does a test name every requirement the plans trace? ═══════
|
|
894
|
+
# Green tests prove that what was written works; they cannot show what was never written.
|
|
895
|
+
# A requirement whose paired test was never generated leaves the suite green, so each
|
|
896
|
+
# working lane's plan is read for the FR- and BR- ids its Traceability section traces, and
|
|
897
|
+
# the slice's TEST files for each one — the concept's list plus every file the fix loops
|
|
898
|
+
# above wrote, which is why this pass runs last: a test the conformance pass added counts.
|
|
899
|
+
# A citation is the id in a test's name, a comment, an attribute or a tag (`FR-004`,
|
|
900
|
+
# `FR_004`, `FR004`). FR numbers restart in every feature, so only this slice's tests are
|
|
901
|
+
# read; a concept that lists none falls back to every test under the lane's test path.
|
|
902
|
+
# Two readings are kept apart from a gap: a plan adopt reverse-engineered is REPORTED and
|
|
903
|
+
# never blocks (its legacy tests predate the spec ids), and an id the plan still traces
|
|
904
|
+
# that spec.md or the model no longer defines — a change removed it and plan has not
|
|
905
|
+
# re-derived the master plan yet — is stale, not required. Like the no-tests case it warns
|
|
906
|
+
# here and fails at the end, after everything else has reported. What it proves is that
|
|
907
|
+
# each requirement has a test that NAMES it, not that the test asserts what it says.
|
|
908
|
+
- id: trace_backend
|
|
909
|
+
condition: "{{be_working}} == true"
|
|
910
|
+
action: execute_script
|
|
911
|
+
on_error: continue
|
|
912
|
+
script: { ref: actions }
|
|
913
|
+
subcommand: test-citations
|
|
914
|
+
args: ["--plan", "{{backend_plan}}", "--kind", "backend", "--paths", "{{all_paths}}", "--paths", "{{fixed_files}}", "--paths", "{{conformance_fixes}}", "--paths", "{{wiring_fixes}}", "--source-path", "{{be_source_path}}", "--test-path", "{{be_test_path}}", "--spec", "{{spec_file}}", "--model", "{{domain_model}}"]
|
|
915
|
+
outputs:
|
|
916
|
+
- { name: be_trace_ok, from: "$.ok" }
|
|
917
|
+
- { name: be_trace_clean, from: "$.clean" }
|
|
918
|
+
- { name: be_trace_warning, from: "$.warning" }
|
|
919
|
+
- { name: be_untraced, from: "$.uncited_text" }
|
|
920
|
+
- id: warn_trace_backend
|
|
921
|
+
condition: "{{be_working}} == true"
|
|
922
|
+
action: verify_context
|
|
923
|
+
require_true: be_trace_clean
|
|
924
|
+
on_false: continue
|
|
925
|
+
on_false_message: "{{be_trace_warning}}"
|
|
926
|
+
- id: trace_frontend
|
|
927
|
+
condition: "{{fe_working}} == true"
|
|
928
|
+
action: execute_script
|
|
929
|
+
on_error: continue
|
|
930
|
+
script: { ref: actions }
|
|
931
|
+
subcommand: test-citations
|
|
932
|
+
args: ["--plan", "{{frontend_plan}}", "--kind", "frontend", "--paths", "{{all_paths}}", "--paths", "{{fixed_files}}", "--paths", "{{conformance_fixes}}", "--source-path", "{{fe_source_path}}", "--test-path", "{{fe_test_path}}", "--spec", "{{spec_file}}", "--model", "{{domain_model}}"]
|
|
933
|
+
outputs:
|
|
934
|
+
- { name: fe_trace_ok, from: "$.ok" }
|
|
935
|
+
- { name: fe_trace_clean, from: "$.clean" }
|
|
936
|
+
- { name: fe_trace_warning, from: "$.warning" }
|
|
937
|
+
- { name: fe_untraced, from: "$.uncited_text" }
|
|
938
|
+
- id: warn_trace_frontend
|
|
939
|
+
condition: "{{fe_working}} == true"
|
|
940
|
+
action: verify_context
|
|
941
|
+
require_true: fe_trace_clean
|
|
942
|
+
on_false: continue
|
|
943
|
+
on_false_message: "{{fe_trace_warning}}"
|
|
944
|
+
|
|
945
|
+
# trace_ok = every worked lane's check passed — a raise and two knock-downs, each lane
|
|
946
|
+
# voting only when it is worked.
|
|
947
|
+
- id: be_trace_vote_set
|
|
948
|
+
condition: "{{be_working}} == true"
|
|
949
|
+
action: set
|
|
950
|
+
vars: { be_trace_vote: "{{be_trace_ok}}" }
|
|
951
|
+
- id: fe_trace_vote_set
|
|
952
|
+
condition: "{{fe_working}} == true"
|
|
953
|
+
action: set
|
|
954
|
+
vars: { fe_trace_vote: "{{fe_trace_ok}}" }
|
|
955
|
+
- id: trace_seed
|
|
956
|
+
action: set
|
|
957
|
+
vars: { trace_ok: "true" }
|
|
958
|
+
- id: trace_clear_backend
|
|
959
|
+
condition: "{{be_trace_vote}} != true"
|
|
960
|
+
action: set
|
|
961
|
+
vars: { trace_ok: "false" }
|
|
962
|
+
- id: trace_clear_frontend
|
|
963
|
+
condition: "{{fe_trace_vote}} != true"
|
|
964
|
+
action: set
|
|
965
|
+
vars: { trace_ok: "false" }
|
|
966
|
+
|
|
967
|
+
# ═══════ PASS 5 — API: does the built service serve what its API plan publishes? ═══════
|
|
968
|
+
# The frontend lane binds to the API plan — api-draft.json, drafted by script from
|
|
969
|
+
# api-plan.md, or from the backend plan's API section for a feature planned before API
|
|
970
|
+
# plans existed — and never to the running service, so the code is held to the plan here.
|
|
971
|
+
# The service's as-built document is written the way the lane says (contract-export:
|
|
972
|
+
# `contract_write`, or `contract_run` + `contract`), after every fix loop above, to the
|
|
973
|
+
# lane's contracts/openapi.json, and compared with the operations THIS feature's API plan
|
|
974
|
+
# names, plus a change merged into spec.md and not closed yet (contract-verify).
|
|
975
|
+
# finalize-delta merges such a change into api-plan.md as well, and applying it again over
|
|
976
|
+
# the merged plan changes nothing. Runs for the developer who works on the service lane;
|
|
977
|
+
# the frontend developer's run never starts it.
|
|
978
|
+
#
|
|
979
|
+
# ONLY WHEN THERE IS SOMETHING TO CHECK. contract-verify --check reads what the check
|
|
980
|
+
# would (the draft and the merged, open changes) without the as-built document; a
|
|
981
|
+
# feature that plans no endpoint — a worker, a batch job, domain logic only — never runs
|
|
982
|
+
# the lane's export or its warnings. Only an explicit `needed: false` skips: a check that
|
|
983
|
+
# does not answer leaves the export armed.
|
|
984
|
+
- id: api_plan_check
|
|
985
|
+
condition: "{{be_working}} == true"
|
|
986
|
+
action: execute_script
|
|
987
|
+
on_error: continue
|
|
988
|
+
script: { ref: actions }
|
|
989
|
+
subcommand: contract-verify
|
|
990
|
+
args: ["--feature-dir", "{{feature_dir}}", "--check"]
|
|
991
|
+
outputs:
|
|
992
|
+
- { name: api_needed, from: "$.needed" }
|
|
993
|
+
- { name: api_plan_note, from: "$.note" }
|
|
994
|
+
- id: api_nothing_to_check
|
|
995
|
+
condition: "{{api_plan_note}} != "
|
|
996
|
+
action: set
|
|
997
|
+
vars: { api_issues: "{{api_plan_note}}" }
|
|
998
|
+
- id: api_export
|
|
999
|
+
condition: "{{api_needed}} != false"
|
|
1000
|
+
action: execute_script
|
|
1001
|
+
on_error: continue
|
|
1002
|
+
script: { ref: actions }
|
|
1003
|
+
subcommand: contract-export
|
|
1004
|
+
outputs:
|
|
1005
|
+
- { name: api_export_ok, from: "$.ok" }
|
|
1006
|
+
- { name: api_way, from: "$.way" }
|
|
1007
|
+
- { name: api_export_reason, from: "$.reason" }
|
|
1008
|
+
- { name: api_export_log, from: "$.log_tail" }
|
|
1009
|
+
- { name: api_doc, from: "$.doc" }
|
|
1010
|
+
- { name: api_placeholder, from: "$.placeholder" }
|
|
1011
|
+
- id: api_no_way_flag
|
|
1012
|
+
condition: "{{api_way}} == none"
|
|
1013
|
+
action: set
|
|
1014
|
+
vars: { api_has_way: "false" }
|
|
1015
|
+
- id: warn_api_no_way
|
|
1016
|
+
condition: "{{api_needed}} != false"
|
|
1017
|
+
action: verify_context
|
|
1018
|
+
require_true: api_has_way
|
|
1019
|
+
on_false: continue
|
|
1020
|
+
on_false_message: "API NOT CHECKED — {{api_export_reason}}. The frontend lane binds to the endpoints the API plan publishes (api-draft.json); without the service's as-built document nothing checks that the code serves them. `contract_write` is any command that writes the service's OpenAPI document to the path {{api_placeholder}} stands for — the stack's own generator, or a script that loads the application and dumps its document — with no server started."
|
|
1021
|
+
# An export that was attempted and failed — a no-way lane has already been told.
|
|
1022
|
+
- id: api_export_vote_set
|
|
1023
|
+
condition: "{{api_needed}} != false"
|
|
1024
|
+
action: set
|
|
1025
|
+
vars: { api_export_vote: "{{api_export_ok}}" }
|
|
1026
|
+
- id: api_export_failed
|
|
1027
|
+
condition: "{{api_export_vote}} != true"
|
|
1028
|
+
action: set
|
|
1029
|
+
vars: { api_export_clean: "false" }
|
|
1030
|
+
- id: api_export_no_way
|
|
1031
|
+
condition: "{{api_has_way}} == false"
|
|
1032
|
+
action: set
|
|
1033
|
+
vars: { api_export_clean: "true" }
|
|
1034
|
+
- id: warn_api_export
|
|
1035
|
+
condition: "{{api_needed}} != false"
|
|
1036
|
+
action: verify_context
|
|
1037
|
+
require_true: api_export_clean
|
|
1038
|
+
on_false: continue
|
|
1039
|
+
on_false_message: "API NOT CHECKED — the service's as-built API document could not be written: {{api_export_reason}}. The code compiled and its tests ran; the way the lane writes its document is what failed. Correct `contract_write` (or `contract_run` / `contract`) on the service lane in .appweaver/stacks.json, start anything it needs, and re-run analyze-slice. Output: {{api_export_log}}"
|
|
1040
|
+
- id: api_verify
|
|
1041
|
+
condition: "{{api_export_ok}} == true"
|
|
1042
|
+
action: execute_script
|
|
1043
|
+
on_error: continue
|
|
1044
|
+
script: { ref: actions }
|
|
1045
|
+
subcommand: contract-verify
|
|
1046
|
+
args: ["--feature-dir", "{{feature_dir}}"]
|
|
1047
|
+
outputs:
|
|
1048
|
+
- { name: api_ok, from: "$.ok" }
|
|
1049
|
+
- { name: api_checked, from: "$.checked" }
|
|
1050
|
+
- { name: api_issues, from: "$.issues_text" }
|
|
1051
|
+
- { name: api_warning, from: "$.warning" }
|
|
1052
|
+
- { name: api_note, from: "$.note" }
|
|
1053
|
+
- id: api_warning_flag
|
|
1054
|
+
condition: "{{api_warning}} != "
|
|
1055
|
+
action: set
|
|
1056
|
+
vars: { api_clean: "false" }
|
|
1057
|
+
- id: warn_api_fields
|
|
1058
|
+
condition: "{{api_export_ok}} == true"
|
|
1059
|
+
action: verify_context
|
|
1060
|
+
require_true: api_clean
|
|
1061
|
+
on_false: continue
|
|
1062
|
+
on_false_message: "{{api_warning}}"
|
|
1063
|
+
- id: api_vote_set
|
|
1064
|
+
condition: "{{api_export_ok}} == true"
|
|
1065
|
+
action: set
|
|
1066
|
+
vars: { api_vote: "{{api_ok}}" }
|
|
1067
|
+
|
|
1068
|
+
# THE LAST THREE GATES — a slice with no tests fails HERE, not at PASS 1, and one whose
|
|
1069
|
+
# tests leave a requirement unnamed fails at the next, and one whose service does not serve
|
|
1070
|
+
# its plan's API at the last, so everything the other passes
|
|
1071
|
+
# found has already been reported and any fix they made is on disk. They sit before the
|
|
1072
|
+
# after-hooks, because an extension wired to `after_analyze_slice` runs on a slice these
|
|
1073
|
+
# gates have passed.
|
|
813
1074
|
- id: untested_gate
|
|
814
1075
|
action: verify_context
|
|
815
1076
|
require_true: tests_present
|
|
@@ -826,6 +1087,38 @@ workflow:
|
|
|
826
1087
|
lane declares — or, if the tests exist, name them so each carries its aggregate's
|
|
827
1088
|
name, which is what the slice filter selects on. Then re-run /appweaver analyze-slice.
|
|
828
1089
|
|
|
1090
|
+
# THE TRACEABILITY GATE — pass 4's verdict, last for the same reason as the one above.
|
|
1091
|
+
- id: untraced_gate
|
|
1092
|
+
action: verify_context
|
|
1093
|
+
require_true: trace_ok
|
|
1094
|
+
on_false: stop
|
|
1095
|
+
on_false_message: >
|
|
1096
|
+
The slice's tests are green, but they do not name every requirement its plans trace —
|
|
1097
|
+
so a requirement whose test was never written passes here unchecked. Named by no test:
|
|
1098
|
+
backend — {{be_untraced}}; frontend — {{fe_untraced}}. Everything above ran and
|
|
1099
|
+
passed (domain conformance={{conformance_ok}}, composition={{wiring_ok}}). Run
|
|
1100
|
+
/appweaver fix-test-coverage: it writes a test for each id, or names the id in the
|
|
1101
|
+
test that already exercises it (`FR-004`, `FR_004` or `FR004` in its name, a comment,
|
|
1102
|
+
an attribute or a tag), and never touches production code. Then re-run
|
|
1103
|
+
/appweaver analyze-slice.
|
|
1104
|
+
|
|
1105
|
+
# THE API GATE — pass 5's verdict.
|
|
1106
|
+
- id: api_gate
|
|
1107
|
+
action: verify_context
|
|
1108
|
+
require_true: api_vote
|
|
1109
|
+
on_false: stop
|
|
1110
|
+
on_false_message: >
|
|
1111
|
+
The slice's tests are green, but the built service does not serve what the API plan
|
|
1112
|
+
publishes — and the frontend lane is bound to it: {{api_issues}}. Everything
|
|
1113
|
+
above ran and passed (domain conformance={{conformance_ok}},
|
|
1114
|
+
composition={{wiring_ok}}, traceability={{trace_ok}}). Make the code serve each
|
|
1115
|
+
endpoint at the route, verb and operation id the API plan states — /appweaver
|
|
1116
|
+
implement generates what it names — then /appweaver build and re-run /appweaver
|
|
1117
|
+
analyze-slice. Where the API plan is what is wrong, correct it with /appweaver plan,
|
|
1118
|
+
then analyze-plan: that redraws the contract, and the frontend lane re-checks against
|
|
1119
|
+
it. On a change that is open and not merged yet, run /appweaver analyze-slice-delta
|
|
1120
|
+
<CR-id> instead — this gate checks the master API plan, plus a change already merged.
|
|
1121
|
+
|
|
829
1122
|
- id: resolve_post_hooks
|
|
830
1123
|
action: execute_script
|
|
831
1124
|
script: { ref: actions }
|
|
@@ -861,6 +1154,19 @@ outputs:
|
|
|
861
1154
|
# nothing on this run, and the gate failed at the end saying so.
|
|
862
1155
|
tests_present: "{{tests_present}}"
|
|
863
1156
|
tests_matched: "{{test_matched}}"
|
|
1157
|
+
# Pass 4: the FR-/BR- ids each worked lane's plan traces that no test of the slice names —
|
|
1158
|
+
# `none` when every one is named. A reverse-engineered plan's are reported, never blocking.
|
|
1159
|
+
traceability_ok: "{{trace_ok}}"
|
|
1160
|
+
backend_untraced: "{{be_untraced}}"
|
|
1161
|
+
frontend_untraced: "{{fe_untraced}}"
|
|
1162
|
+
# Pass 5: what the built service serves vs what the API plan publishes. `api_checked`
|
|
1163
|
+
# false means no as-built document was written — the lane sets no way, or it failed, and
|
|
1164
|
+
# the run warned — or the plan names no endpoint, which `backend_api_issues` then says;
|
|
1165
|
+
# `api_issues` is `none` when every planned endpoint is served as planned.
|
|
1166
|
+
api_ok: "{{api_vote}}"
|
|
1167
|
+
api_checked: "{{api_checked}}"
|
|
1168
|
+
backend_api_issues: "{{api_issues}}"
|
|
1169
|
+
api_document: "{{api_doc}}" # the as-built document, when api_checked — commit it with the service
|
|
864
1170
|
referrer_count: "{{referrer_count}}"
|
|
865
1171
|
referrer_blast_radius: "{{referrer_names}}"
|
|
866
1172
|
okf_concept: "{{okf_concept}}"
|
|
@@ -36,18 +36,17 @@
|
|
|
36
36
|
# and its fix loop is never handed the frontend's files. With the default (every declared
|
|
37
37
|
# lane) every lane is compiled, as before.
|
|
38
38
|
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
# document and never starts the service. A failed export warns and the build stays green.
|
|
39
|
+
# NO API DOCUMENT IS WRITTEN HERE. The contract between the lanes is the API plan's draft
|
|
40
|
+
# (api-draft.json), and the service's as-built document is written and checked
|
|
41
|
+
# against it by analyze-slice, after its own fix loops — so it reflects the code that gate
|
|
42
|
+
# passes, not the code this loop left.
|
|
44
43
|
#
|
|
45
44
|
# Launch: /appweaver build [strategy]
|
|
46
45
|
# =============================================================================
|
|
47
46
|
|
|
48
47
|
name: aw-spec-build
|
|
49
|
-
description: Compile the feature by running the build command of every lane the developer works on (.appweaver/lane.json — every declared lane by default), fix compile errors against the design intent, then record the touched files in the slice's knowledge concept
|
|
50
|
-
version: 1.
|
|
48
|
+
description: Compile the feature by running the build command of every lane the developer works on (.appweaver/lane.json — every declared lane by default), fix compile errors against the design intent, then record the touched files in the slice's knowledge concept. Backend-only, frontend-only and full-stack projects all compile here — the gate requires a lane declaration, not a lane of a particular kind. Loads TECHNICAL rules only (tech-rule-bindings) — no domain rules reach this stage.
|
|
49
|
+
version: 1.6.0
|
|
51
50
|
agent_agnostic: true
|
|
52
51
|
dialect: aw-spec.orchestrator/v1
|
|
53
52
|
|
|
@@ -73,13 +72,6 @@ vars:
|
|
|
73
72
|
working_kind: "" # one kind when the developer works on one lane of two, else empty — every declared lane
|
|
74
73
|
working_root: ""
|
|
75
74
|
working_test_path: ""
|
|
76
|
-
be_working: "false" # the service lane is declared and this developer works on it — it publishes the API document
|
|
77
|
-
contract_ok: ""
|
|
78
|
-
export_doc: ""
|
|
79
|
-
contract_reason: ""
|
|
80
|
-
contract_log: ""
|
|
81
|
-
contract_already: "false"
|
|
82
|
-
contract_fresh: "true"
|
|
83
75
|
|
|
84
76
|
workflow:
|
|
85
77
|
|
|
@@ -192,38 +184,6 @@ workflow:
|
|
|
192
184
|
on_false: stop
|
|
193
185
|
on_false_message: "Build still failing after 3 fix attempts. Last log: {{build_log}}"
|
|
194
186
|
|
|
195
|
-
# THE API DOCUMENT, published from the code that just compiled — by the developer who
|
|
196
|
-
# works on the service lane, so the frontend developer reads it from the commit instead of
|
|
197
|
-
# starting the service. Advisory: a failed export warns and the build stays green.
|
|
198
|
-
- id: contract_export
|
|
199
|
-
condition: "{{be_working}} == true"
|
|
200
|
-
action: execute_script
|
|
201
|
-
on_error: continue
|
|
202
|
-
script: { ref: actions }
|
|
203
|
-
subcommand: contract-export
|
|
204
|
-
outputs:
|
|
205
|
-
- { name: contract_ok, from: "$.ok" }
|
|
206
|
-
- { name: export_doc, from: "$.doc" }
|
|
207
|
-
- { name: contract_reason, from: "$.reason" }
|
|
208
|
-
- { name: contract_already, from: "$.already_running" }
|
|
209
|
-
- { name: contract_log, from: "$.log_tail" }
|
|
210
|
-
- id: warn_contract_export
|
|
211
|
-
condition: "{{be_working}} == true"
|
|
212
|
-
action: verify_context
|
|
213
|
-
require_true: contract_ok
|
|
214
|
-
on_false: continue
|
|
215
|
-
on_false_message: "API DOCUMENT NOT EXPORTED — {{contract_reason}}. The build is green; only the published document is out of date. The service lane 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 there, start anything the service needs, and re-run build. Service output: {{contract_log}}"
|
|
216
|
-
- id: contract_stale_flag
|
|
217
|
-
condition: "{{contract_already}} == true"
|
|
218
|
-
action: set
|
|
219
|
-
vars: { contract_fresh: "false" }
|
|
220
|
-
- id: warn_contract_stale
|
|
221
|
-
condition: "{{be_working}} == true"
|
|
222
|
-
action: verify_context
|
|
223
|
-
require_true: contract_fresh
|
|
224
|
-
on_false: continue
|
|
225
|
-
on_false_message: "WARNING — the API document was {{contract_reason}}. Stop that service and re-run build to export the code as it is now."
|
|
226
|
-
|
|
227
187
|
# Record what the fix loop touched in the slice's OKF concept. This replaces the retired
|
|
228
188
|
# `design-reconcile` step, which copied on-disk file bodies back into the design doc's
|
|
229
189
|
# path-tagged fences — meaningless now that backend-plan.md describes contracts, not code (and
|
|
@@ -263,5 +223,4 @@ outputs:
|
|
|
263
223
|
# (a file moved or deleted without re-running the owning slice). Advisory, never gated.
|
|
264
224
|
stale_source_files: "{{paths_missing}}"
|
|
265
225
|
working_lane: "{{working_lane}}" # the lane(s) compiled — .appweaver/lane.json
|
|
266
|
-
api_document: "{{export_doc}}" # the service's API document, exported after the green compile — commit it for the frontend lane
|
|
267
226
|
next: "/appweaver analyze-slice"
|