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
|
@@ -5,12 +5,13 @@
|
|
|
5
5
|
# specify → plan → analyze-plan → implement.
|
|
6
6
|
#
|
|
7
7
|
# FOUR CHECKS, one per way a plan can be wrong:
|
|
8
|
-
# 1. spec.md → backend-plan.md
|
|
8
|
+
# 1. spec.md → backend-plan.md + api-plan.md — every spec item has a service home, and
|
|
9
|
+
# every endpoint the API plan publishes is realised by a use-case of the backend plan
|
|
9
10
|
# 2. spec.md → frontend-plan.md — every experience item has a screen home
|
|
10
|
-
# 3.
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
11
|
+
# 3. api-plan.md ↔ frontend-plan.md — CONTRACT BINDING: every call the frontend makes
|
|
12
|
+
# exists in the service's published API, with the same field shapes. This is the
|
|
13
|
+
# check neither one-sided pass can make: a frontend call the backend never defines
|
|
14
|
+
# passes both coverage checks and fails at integration.
|
|
14
15
|
# 4. the plans → domain-model.md — no invented aggregate, no unenforced invariant. The
|
|
15
16
|
# model is spec-tier and is READ here, never written.
|
|
16
17
|
# Plus the OVERLAY BACKSTOP: the domain gate checklist, as a fifth pass over both plans.
|
|
@@ -30,19 +31,30 @@
|
|
|
30
31
|
# refuses the backend's implement, and the reverse. With the default (every declared
|
|
31
32
|
# lane) every plan is gated, as before — each in its own receipt.
|
|
32
33
|
#
|
|
34
|
+
# THE BACKEND LANE IS TWO DOCUMENTS. Its endpoints and its answers to the frontend's
|
|
35
|
+
# requests are in api-plan.md, and backend-plan.md realises each endpoint as a use-case.
|
|
36
|
+
# Both are in context when the backend plan is, both are hashed into the backend receipt,
|
|
37
|
+
# and a repair rewrites the one the gap is in: api-plan.md first, for a gap in an endpoint
|
|
38
|
+
# or a request's answer, then backend-plan.md, which realises what the API plan states. A
|
|
39
|
+
# feature planned before API plans existed keeps its endpoints in its backend plan's API
|
|
40
|
+
# section; that section is then the API every check reads, and an API repair rewrites the
|
|
41
|
+
# backend plan. (`plan main` offers to move them out.)
|
|
42
|
+
#
|
|
33
43
|
# THE REQUEST LEDGER IS READ BY SCRIPT. What the frontend plan asks of the service sits in
|
|
34
|
-
# its §5 "Contract deltas needed" table, one RQ-n per request, and the
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
44
|
+
# its §5 "Contract deltas needed" table, one RQ-n per request, and the API plan answers each
|
|
45
|
+
# in its "Requests from the frontend lane" table. contract-requests reads both on every
|
|
46
|
+
# pass, so check 3 is TOLD which requests are open (a backend-lane gap: answer it, by
|
|
47
|
+
# publishing or declining) and which wait on the frontend (answered and not re-bound, or
|
|
48
|
+
# declined). A frontend developer's run therefore reports open requests for the backend
|
|
39
49
|
# developer instead of stopping on them, and a backend developer's repair answers them.
|
|
40
|
-
# A master run that gates the backend
|
|
41
|
-
#
|
|
50
|
+
# A master run that gates the backend lane also redraws api-draft.json from the API plan, so
|
|
51
|
+
# the draft the frontend generates against matches the plan as repaired, and warns when the
|
|
52
|
+
# redraw lost an operation the previous draft had.
|
|
42
53
|
#
|
|
43
|
-
# THE FRONTEND RECEIPT HASHES THE
|
|
44
|
-
#
|
|
45
|
-
# operation — the frontend lane is stale at implement
|
|
54
|
+
# THE FRONTEND RECEIPT HASHES THE SERVICE'S PUBLISHED API TOO (api-plan.md, or the backend
|
|
55
|
+
# plan's API section for a feature planned before it): when the backend developer changes
|
|
56
|
+
# it — an answered request, a renamed operation — the frontend lane is stale at implement
|
|
57
|
+
# until its plan is gated again.
|
|
46
58
|
#
|
|
47
59
|
# THIS STAGE VALIDATES; `plan` AUTHORS. A declared lane whose plan document is MISSING
|
|
48
60
|
# STOPS the run naming /appweaver plan — it is not scaffolded and repaired here. Filling
|
|
@@ -108,8 +120,8 @@
|
|
|
108
120
|
# =============================================================================
|
|
109
121
|
|
|
110
122
|
name: aw-spec-analyze-plan
|
|
111
|
-
description: The spec↔plan conformance gate for every declared lane — confirm backend-plan.md and frontend-plan.md follow spec.md, that
|
|
112
|
-
version: 3.
|
|
123
|
+
description: The spec↔plan conformance gate for every declared lane — confirm backend-plan.md with its api-plan.md and frontend-plan.md follow spec.md, that the frontend binds to the API the service publishes, and that neither contradicts the bounded context's domain model (domain overlays are a backstop); with approval, repair the drifting plan. Lanes come from .appweaver/stacks.json, so one command gates backend-only, frontend-only and full-stack projects. Each gated lane runs in one of two modes, decided from the changes/ directory rather than the ledger and defaulting to the read-only one — MASTER (no open change names that lane on its **Lanes** line) checks, repairs on approval and stops on unreconciled gaps; REPORT (an open change names it) runs the same checks read-only, because a master plan may not be rewritten while a delta to that lane is in flight. With no lane in master mode the run writes plan-analyze-report.md without asking, repairing or stopping. It never opens, merges or closes a change.
|
|
124
|
+
version: 3.9.1
|
|
113
125
|
agent_agnostic: true
|
|
114
126
|
dialect: aw-spec.orchestrator/v1
|
|
115
127
|
|
|
@@ -190,6 +202,25 @@ vars:
|
|
|
190
202
|
req_frontend_text: "none"
|
|
191
203
|
req_summary: "no contract request"
|
|
192
204
|
draft_path: ""
|
|
205
|
+
draft_plan: "" # the document it was drawn from: api-plan.md, or the backend plan
|
|
206
|
+
draft_unread: "0"
|
|
207
|
+
draft_unread_text: "none"
|
|
208
|
+
draft_clean: "true"
|
|
209
|
+
draft_dropped: "0" # operations the previous draft had and this one does not
|
|
210
|
+
draft_dropped_text: "none"
|
|
211
|
+
draft_kept: "true"
|
|
212
|
+
# THE API PLAN — the backend lane's second document. In context with the backend plan;
|
|
213
|
+
# absent for a feature planned before API plans existed, whose API section is then the
|
|
214
|
+
# API every check reads and every API repair rewrites.
|
|
215
|
+
api_plan: ""
|
|
216
|
+
api_plan_exists: "false"
|
|
217
|
+
api_ctx_go: "false"
|
|
218
|
+
api_plan_ctx: ""
|
|
219
|
+
api_repair: "false" # the analyze pass found a gap in an endpoint or a request's answer
|
|
220
|
+
api_repair_go: "false" # …and this pass rewrites api-plan.md for it
|
|
221
|
+
api_in_backend: "false" # …or, with no API plan, rewrites the backend plan's API section
|
|
222
|
+
# What the backend plan's repair is told about the API.
|
|
223
|
+
be_repair_api_rule: "THE ENDPOINTS ARE IN api-plan.md (in context), repaired before this document whenever a gap was in an endpoint or a request's answer. Do NOT publish or restate endpoints here: REALISE each endpoint of the API plan as the use-case its **Maps to** names, with request and response DTOs matching its shapes. A gap in an endpoint itself — its route, shapes, operation id or a request's answer — is the API plan's, not this document's."
|
|
193
224
|
# PER-LANE PRESENCE. A lane is PRESENT when it is declared and its plan document is on
|
|
194
225
|
# disk — its plan is then in context — and MISSING when it is WORKED and the document is
|
|
195
226
|
# not. The engine has no
|
|
@@ -262,6 +293,8 @@ workflow:
|
|
|
262
293
|
- { name: frontend_plan, from: "$.frontend_plan" }
|
|
263
294
|
- { name: backend_plan_exists, from: "$.backend_plan_exists" }
|
|
264
295
|
- { name: frontend_plan_exists, from: "$.frontend_plan_exists" }
|
|
296
|
+
- { name: api_plan, from: "$.api_plan" }
|
|
297
|
+
- { name: api_plan_exists, from: "$.api_plan_exists" }
|
|
265
298
|
|
|
266
299
|
# THIS FEATURE'S LANES. lane_resolve above read the REPO's declaration; one feature may
|
|
267
300
|
# own no part of a lane's surface — adopt records `lanes: [backend]` in
|
|
@@ -538,18 +571,54 @@ workflow:
|
|
|
538
571
|
condition: "{{fe_present}} == true"
|
|
539
572
|
action: set
|
|
540
573
|
vars: { fe_plan_ctx: "{{frontend_plan}}" }
|
|
574
|
+
# The API plan rides with the backend plan: in context whenever that one is, when it
|
|
575
|
+
# exists. A feature planned before API plans has none, and its backend plan's API section
|
|
576
|
+
# is read in its place — which is also where an API repair then goes.
|
|
577
|
+
- id: api_ctx_arm
|
|
578
|
+
condition: "{{be_present}} == true"
|
|
579
|
+
action: set
|
|
580
|
+
vars: { api_ctx_go: "{{api_plan_exists}}" }
|
|
581
|
+
- id: api_ctx_path
|
|
582
|
+
condition: "{{api_ctx_go}} == true"
|
|
583
|
+
action: set
|
|
584
|
+
vars: { api_plan_ctx: "{{api_plan}}" }
|
|
541
585
|
|
|
542
586
|
# 2b. Load the domain GATE overlays (the domain-rule-bindings `/aw-spec-gate` checklist) as
|
|
543
587
|
# the conformance checklist — VALIDATION input only, NEVER authoring. The analyze
|
|
544
588
|
# step sees them (include_standards: true); the repair steps do NOT (a plan conforms
|
|
545
|
-
# to the SPEC, not to the overlays). Empty/no-op for a non-domain project
|
|
589
|
+
# to the SPEC, not to the overlays). Empty/no-op for a non-domain project — a map whose
|
|
590
|
+
# heading holds a `_None_` line. A map with no such heading, or one naming a file that
|
|
591
|
+
# is not on disk, warns and carries on.
|
|
546
592
|
- id: resolve_gate_overlays
|
|
547
593
|
action: execute_script
|
|
548
594
|
script: { ref: actions }
|
|
549
595
|
subcommand: resolve-domain
|
|
550
596
|
args: ["--command", "aw-spec-gate"]
|
|
551
597
|
outputs:
|
|
552
|
-
- { name: gate_overlays,
|
|
598
|
+
- { name: gate_overlays, from: "$.candidates" }
|
|
599
|
+
- { name: gate_domain, from: "$.domain" }
|
|
600
|
+
- { name: gate_map_exists, from: "$.rulemap_exists" }
|
|
601
|
+
- { name: gate_heading_found, from: "$.heading_found" }
|
|
602
|
+
- { name: gate_missing, from: "$.missing" }
|
|
603
|
+
- id: gate_flags
|
|
604
|
+
action: set
|
|
605
|
+
vars: { gate_all_on_disk: "true" }
|
|
606
|
+
- id: gate_flag_missing
|
|
607
|
+
condition: "{{gate_missing}} != []"
|
|
608
|
+
action: set
|
|
609
|
+
vars: { gate_all_on_disk: "false" }
|
|
610
|
+
- id: warn_gate_heading
|
|
611
|
+
condition: "{{gate_map_exists}} == true"
|
|
612
|
+
action: verify_context
|
|
613
|
+
require_true: gate_heading_found
|
|
614
|
+
on_false: continue
|
|
615
|
+
on_false_message: "WARNING — guardrails/{{gate_domain}}/domain-rule-bindings.md has no `## /aw-spec-gate` heading, so the plans are 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."
|
|
616
|
+
- id: warn_gate_missing
|
|
617
|
+
condition: "{{gate_map_exists}} == true"
|
|
618
|
+
action: verify_context
|
|
619
|
+
require_true: gate_all_on_disk
|
|
620
|
+
on_false: continue
|
|
621
|
+
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 plans were not checked against them: {{gate_missing}}. Correct the paths, or add the files."
|
|
553
622
|
- id: load_gate_overlays
|
|
554
623
|
action: load_standards
|
|
555
624
|
files_from_variable: gate_overlays
|
|
@@ -576,6 +645,7 @@ workflow:
|
|
|
576
645
|
context:
|
|
577
646
|
- { path: "{{spec_file}}" } # THE ANCHOR
|
|
578
647
|
- { path: "{{domain_model}}", optional: true } # spec-tier, READ here and never written
|
|
648
|
+
- { path: "{{api_plan_ctx}}", optional: true } # the service's published API, with the backend plan
|
|
579
649
|
- { path: "{{be_plan_ctx}}", optional: true }
|
|
580
650
|
- { path: "{{fe_plan_ctx}}", optional: true }
|
|
581
651
|
|
|
@@ -613,11 +683,19 @@ workflow:
|
|
|
613
683
|
- { name: req_frontend_text, from: "$.frontend_text" }
|
|
614
684
|
- { name: req_summary, from: "$.summary" }
|
|
615
685
|
|
|
686
|
+
# With no API plan the backend plan's API section is the API, so its repair carries
|
|
687
|
+
# the rules the API repair does — the requests as this pass reads them included.
|
|
688
|
+
- id: be_repair_api_rule_in_plan
|
|
689
|
+
condition: "{{api_plan_exists}} == false"
|
|
690
|
+
action: set
|
|
691
|
+
vars:
|
|
692
|
+
be_repair_api_rule: "THE ENDPOINTS ARE IN THIS DOCUMENT'S API SECTION — this feature was planned before API plans existed. CONTRACT gaps whose lane is `backend`: PUBLISH the missing surface there as endpoint blocks (the `VERB /route` heading, **Operation id**, Request, Success, the Errors table, every shape `{ field: type }`), so the frontend plan has something real to bind to. ANSWER EVERY OPEN CONTRACT REQUEST: {{req_backend_text}}. Record each in the API section's 'Requests from the frontend lane' table (| Request | Outcome | Operation id | Why |; add the table if there is none): PUBLISH it as an endpoint, under the operation id it proposes unless that clashes with one already in use, or DECLINE it with the reason — a request the spec gives no basis for is declined as a spec gap for /appweaver specify, never published on a guess. Keep every row the table already has."
|
|
693
|
+
|
|
616
694
|
- id: analyze
|
|
617
695
|
action: agent_query
|
|
618
696
|
include_standards: true # the gate overlays (checklist) are in the standards
|
|
619
|
-
schema: { ok: true, backend_repair: false, frontend_repair: false, gaps: [ { severity: "high", check: "<spec-backend|spec-frontend|contract|model|overlay>", lane: "<backend|frontend>", route: "<plan|specify>", spec_ref: "<FR/BR/CN/DC/IC/UX/US/SC or overlay or —>", where: "<plan section>", gap: "<how it drifts>" } ] }
|
|
620
|
-
mock: { ok: true, backend_repair: false, frontend_repair: false, gaps: [] }
|
|
697
|
+
schema: { ok: true, backend_repair: false, api_repair: false, frontend_repair: false, gaps: [ { severity: "high", check: "<spec-backend|spec-frontend|contract|model|overlay>", lane: "<backend|frontend>", route: "<plan|specify>", spec_ref: "<FR/BR/CN/DC/IC/UX/US/SC or overlay or —>", where: "<plan section>", gap: "<how it drifts>" } ] }
|
|
698
|
+
mock: { ok: true, backend_repair: false, api_repair: false, frontend_repair: false, gaps: [] }
|
|
621
699
|
task: |
|
|
622
700
|
spec.md is the ANCHOR. Gate this feature's LANE PLANS against it and against the
|
|
623
701
|
bounded context's domain model, and list EVERY drift as a gap. Run the checks
|
|
@@ -631,16 +709,32 @@ workflow:
|
|
|
631
709
|
gap still carries the `lane` whose document must change to close it, even when
|
|
632
710
|
that lane is not gated here — it is reported for that lane's developer.
|
|
633
711
|
|
|
634
|
-
|
|
712
|
+
THE SERVICE'S API is api-plan.md when it is in context — the endpoints the
|
|
713
|
+
service publishes and its answers to the frontend's requests, a document of the
|
|
714
|
+
backend lane beside backend-plan.md, which realises each endpoint as a use-case.
|
|
715
|
+
With no api-plan.md in context the feature was planned before API plans existed,
|
|
716
|
+
and the backend plan's API section is the API. Below, "the API" means whichever
|
|
717
|
+
of the two this feature has.
|
|
718
|
+
|
|
719
|
+
CHECK 1 — spec.md → backend-plan.md and the API (when the backend plan is in
|
|
720
|
+
context):
|
|
635
721
|
(a) every spec item — FR / Business Rule / Constraint (CN-) / Data
|
|
636
722
|
Classification (DC-) / Integration Contract (IC-) / user story / success
|
|
637
723
|
criterion — has a service home, and the Traceability section is complete. A
|
|
638
724
|
lifted CN-/DC-/IC- with no plan row is a HIGH gap. EXCEPT the Experience
|
|
639
725
|
Standards (UX-), which the service plan excludes by contract;
|
|
640
|
-
(b) NO plan element
|
|
641
|
-
basis is a drift unless already logged as a DA-n
|
|
726
|
+
(b) NO plan element — and no endpoint of the API — exceeds or contradicts the
|
|
727
|
+
spec: anything without a spec basis is a drift unless already logged as a DA-n
|
|
728
|
+
assumption;
|
|
642
729
|
(c) the layers are coherent (Application→Domain, API→Application, Infra
|
|
643
|
-
implements the declared ports) and it stays high-level + technology-agnostic
|
|
730
|
+
implements the declared ports) and it stays high-level + technology-agnostic;
|
|
731
|
+
(d) with an api-plan.md: every endpoint it publishes names under **Maps to** a
|
|
732
|
+
use-case the backend plan defines, with DTOs matching its shapes — an endpoint
|
|
733
|
+
nothing realises is a HIGH gap on lane `backend` — and the backend plan restates
|
|
734
|
+
no endpoint (its API section is the one line pointing to api-plan.md). Every
|
|
735
|
+
endpoint is a `VERB /route` block with its shapes as `{ field: type }`: one
|
|
736
|
+
written as a table row or in prose reaches neither api-draft.json nor the
|
|
737
|
+
frontend, a HIGH gap.
|
|
644
738
|
|
|
645
739
|
CHECK 2 — spec.md → frontend-plan.md (when the frontend plan is in context):
|
|
646
740
|
(a) every Experience Standard (UX-) has a home here — the service plan excludes
|
|
@@ -654,21 +748,21 @@ workflow:
|
|
|
654
748
|
(d) it stays technology-agnostic — no framework, router, state library, component
|
|
655
749
|
library or styling approach.
|
|
656
750
|
|
|
657
|
-
CHECK 3 — CONTRACT BINDING,
|
|
751
|
+
CHECK 3 — CONTRACT BINDING, the API ↔ frontend-plan.md (ONLY when
|
|
658
752
|
{{both_lanes}} is true; skip entirely otherwise). This is the check neither
|
|
659
753
|
one-sided pass can make, and it runs whichever of the two plans is gated:
|
|
660
754
|
(a) EVERY call, endpoint or payload the frontend plan binds to EXISTS in the
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
755
|
+
API. One that does not is a HIGH gap on the `contract` check — lane `backend`
|
|
756
|
+
when the spec requires the capability (the service must publish it), lane
|
|
757
|
+
`frontend` when the experience invented it;
|
|
664
758
|
(b) the FIELD SHAPES agree in both directions — a field the frontend reads that
|
|
665
759
|
the service never returns, and a required field the service demands that the
|
|
666
760
|
frontend never sends, are both HIGH gaps;
|
|
667
761
|
(c) THE REQUEST LEDGER, read by script from both plans ({{req_summary}}). OPEN —
|
|
668
762
|
raised in the frontend plan's "Contract deltas needed" and not answered in the
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
763
|
+
API's "Requests from the frontend lane": {{req_backend_text}}. Report EACH as a
|
|
764
|
+
HIGH `contract` gap on lane `backend`, route `plan`, naming the RQ-n: the API
|
|
765
|
+
must publish it or decline it. WAITING ON THE FRONTEND PLAN —
|
|
672
766
|
answered and not yet re-bound, or declined: {{req_frontend_text}}. Report EACH as
|
|
673
767
|
a HIGH `contract` gap on lane `frontend`, route `plan`. `none` means nothing in
|
|
674
768
|
that group. A binding row that cites an open request's proposed id is that
|
|
@@ -676,12 +770,13 @@ workflow:
|
|
|
676
770
|
(d) the frontend plan cites the service's published surface and does NOT restate,
|
|
677
771
|
re-derive or contradict it, and states no server-side behaviour or persistence
|
|
678
772
|
assumption;
|
|
679
|
-
(e) OPERATION IDS MATCH. Every §5 row's Operation id is the one the
|
|
680
|
-
|
|
681
|
-
across the
|
|
682
|
-
name is a HIGH `contract` gap on lane `frontend`;
|
|
683
|
-
endpoints sharing one, is one on lane `backend`. Implement finds each
|
|
684
|
-
this id in the
|
|
773
|
+
(e) OPERATION IDS MATCH. Every §5 row's Operation id is the one the API gives
|
|
774
|
+
that endpoint, spelled exactly, and every endpoint of the API has one, unique
|
|
775
|
+
across the service. A §5 row with no id (`—` without a DA-n) or with an id the API
|
|
776
|
+
does not name is a HIGH `contract` gap on lane `frontend`; an endpoint with no id,
|
|
777
|
+
or two endpoints sharing one, is one on lane `backend`. Implement finds each
|
|
778
|
+
endpoint by this id in the API document drafted from the API, and analyze-slice
|
|
779
|
+
checks the service serves it under it.
|
|
685
780
|
|
|
686
781
|
CHECK 4 — the plans → domain-model.md (when the model is in context; skip if it
|
|
687
782
|
is not):
|
|
@@ -716,14 +811,18 @@ workflow:
|
|
|
716
811
|
- route `plan` for everything a rewrite of a lane plan closes: a missing plan
|
|
717
812
|
home, a name that differs from the model's, an invariant restated instead of
|
|
718
813
|
cited, a contract binding, an element with no spec basis.
|
|
719
|
-
Set
|
|
720
|
-
|
|
814
|
+
Set api_repair true if any `plan`-route gap is in an endpoint of the API or in a
|
|
815
|
+
request's answer — its route, shapes, operation id, a missing endpoint, an open
|
|
816
|
+
request — and backend_repair true if any needs the backend plan itself rewritten
|
|
817
|
+
(a use-case, the domain, a port, the ledgers); both when both are. Set
|
|
818
|
+
frontend_repair likewise. (If a plan is still the empty template, treat the
|
|
721
819
|
WHOLE spec as gaps against it.) Set ok=true ONLY when every applicable check
|
|
722
820
|
passes and no checklist constraint is unaccounted for.
|
|
723
821
|
outputs:
|
|
724
822
|
- { name: analyze_ok, from: "$.ok" }
|
|
725
823
|
- { name: analyze_gaps, from: "$.gaps" }
|
|
726
824
|
- { name: backend_repair, from: "$.backend_repair" }
|
|
825
|
+
- { name: api_repair, from: "$.api_repair" }
|
|
727
826
|
- { name: frontend_repair, from: "$.frontend_repair" }
|
|
728
827
|
|
|
729
828
|
# WHO CAN CLOSE EACH GAP, decided by script from the tags above: a LIFT-FAILURE is
|
|
@@ -777,9 +876,9 @@ workflow:
|
|
|
777
876
|
- "## How to read this" — state BOTH readings and that only the operator knows
|
|
778
877
|
which applies, because it depends on whether finalize-delta has already run:
|
|
779
878
|
(a) AFTER finalize-delta merged a change, these gaps are EXPECTED. The lane
|
|
780
|
-
plans are DERIVED from spec.md + domain-model.md and finalize-delta
|
|
781
|
-
change into those
|
|
782
|
-
content and the spec
|
|
879
|
+
plans are DERIVED from spec.md + domain-model.md + api-plan.md and finalize-delta
|
|
880
|
+
merges the change into those documents only, so the lane plans stand at their
|
|
881
|
+
last authored content and the spec and the API have moved ahead of them. The remedy is
|
|
783
882
|
/appweaver plan main (which re-derives them, carrying DA-n / WA-n forward),
|
|
784
883
|
after /appweaver close-delta, not a repair of either plan.
|
|
785
884
|
(b) BEFORE finalize-delta, the masters have not moved, so these gaps are real
|
|
@@ -869,6 +968,31 @@ workflow:
|
|
|
869
968
|
condition: "{{backend_repair}} == true"
|
|
870
969
|
action: set
|
|
871
970
|
vars: { be_repair: "{{be_may_repair}}" }
|
|
971
|
+
# THE API'S OWN REPAIR, by the same ordered assignments. With no api-plan.md the API is
|
|
972
|
+
# the backend plan's API section, so an API gap raises the backend repair instead.
|
|
973
|
+
- id: api_repair_clear
|
|
974
|
+
action: set
|
|
975
|
+
vars: { api_repair_go: "false", api_in_backend: "false" }
|
|
976
|
+
- id: api_repair_flag
|
|
977
|
+
condition: "{{api_repair}} == true"
|
|
978
|
+
action: set
|
|
979
|
+
vars: { api_repair_go: "{{be_may_repair}}" }
|
|
980
|
+
- id: api_repair_in_backend
|
|
981
|
+
condition: "{{api_plan_exists}} == false"
|
|
982
|
+
action: set
|
|
983
|
+
vars: { api_in_backend: "{{api_repair_go}}" }
|
|
984
|
+
- id: api_repair_no_plan
|
|
985
|
+
condition: "{{api_plan_exists}} == false"
|
|
986
|
+
action: set
|
|
987
|
+
vars: { api_repair_go: "false" }
|
|
988
|
+
- id: be_repair_for_api
|
|
989
|
+
condition: "{{api_in_backend}} == true"
|
|
990
|
+
action: set
|
|
991
|
+
vars: { be_repair: "true" }
|
|
992
|
+
- id: api_repair_last_pass
|
|
993
|
+
condition: "{{repairs_left}} == false"
|
|
994
|
+
action: set
|
|
995
|
+
vars: { api_repair_go: "false" }
|
|
872
996
|
- id: be_repair_last_pass
|
|
873
997
|
condition: "{{repairs_left}} == false"
|
|
874
998
|
action: set
|
|
@@ -885,6 +1009,40 @@ workflow:
|
|
|
885
1009
|
action: set
|
|
886
1010
|
vars: { fe_repair: "false" }
|
|
887
1011
|
|
|
1012
|
+
# The API first, so the backend repair below reads the API as repaired: files in the
|
|
1013
|
+
# envelope are read when each request is assembled.
|
|
1014
|
+
- id: repair_api
|
|
1015
|
+
condition: "{{api_repair_go}} == true"
|
|
1016
|
+
action: agent_author
|
|
1017
|
+
include_standards: false # rewrite-in-place: spec anchors — NOT the overlays
|
|
1018
|
+
output_target: { type: file, path: "{{api_plan}}" }
|
|
1019
|
+
task: |
|
|
1020
|
+
spec.md is the ANCHOR — update api-plan.md (in context), the endpoints this
|
|
1021
|
+
service publishes, to CONFORM to it, closing the gaps whose lane is `backend` that
|
|
1022
|
+
are in an endpoint or a request's answer (the spec WINS every time):
|
|
1023
|
+
{{analyze_gaps}}
|
|
1024
|
+
- CONTRACT gaps: PUBLISH the missing endpoint as a block under "## Endpoints" —
|
|
1025
|
+
the `### `VERB /route`` heading, then **Operation id**, **Auth**, **Request**,
|
|
1026
|
+
**Success**, the **Errors** table and **Maps to** — every shape as
|
|
1027
|
+
`{ field: type }`, so the frontend plan has something real to bind to. Correct a
|
|
1028
|
+
shape or an error contract the spec contradicts.
|
|
1029
|
+
- OPERATION IDS ARE STABLE: an endpoint keeps the id it has; one without an id gets
|
|
1030
|
+
one unique across the service; two endpoints sharing one are split.
|
|
1031
|
+
- ANSWER EVERY OPEN CONTRACT REQUEST: {{req_backend_text}}. Record each in
|
|
1032
|
+
"Requests from the frontend lane" (| Request | Outcome | Operation id | Why |):
|
|
1033
|
+
PUBLISH it as an endpoint, under the operation id it proposes unless that
|
|
1034
|
+
clashes with one already in use, or DECLINE it with the reason — a request the
|
|
1035
|
+
spec gives no basis for is declined as a spec gap for /appweaver specify, never
|
|
1036
|
+
published on a guess. Keep every row the table already has.
|
|
1037
|
+
- REMOVE an endpoint no spec id calls for. The draft drawn after this run reports
|
|
1038
|
+
every operation the previous api-draft.json had and this document no longer has.
|
|
1039
|
+
- **Maps to** names the use-case the backend plan realises the endpoint with; a
|
|
1040
|
+
new endpoint names the use-case the backend plan's repair will add.
|
|
1041
|
+
- Preserve every already-conformant block VERBATIM. Do NOT change the spec, the
|
|
1042
|
+
domain model, the backend plan or the frontend plan. Add one Change History row
|
|
1043
|
+
for the repair; do not invent a version number.
|
|
1044
|
+
Return the COMPLETE updated api-plan.md content only.
|
|
1045
|
+
|
|
888
1046
|
- id: repair_backend
|
|
889
1047
|
condition: "{{be_repair}} == true"
|
|
890
1048
|
action: agent_author
|
|
@@ -906,15 +1064,7 @@ workflow:
|
|
|
906
1064
|
what one says. DO NOT EDIT domain-model.md — it is spec-tier and read-only
|
|
907
1065
|
here. If a gap can only be closed by ADDING to the model, you cannot close it:
|
|
908
1066
|
leave it open and add a DA-n saying it routes to /appweaver specify.
|
|
909
|
-
-
|
|
910
|
-
section as field shapes, so the frontend plan has something real to bind to.
|
|
911
|
-
- ANSWER EVERY OPEN CONTRACT REQUEST: {{req_backend_text}}. Record each in the API
|
|
912
|
-
section's "Requests from the frontend lane" table (| Request | Outcome |
|
|
913
|
-
Operation id | Why |; add the table if there is none): PUBLISH it as an endpoint,
|
|
914
|
-
under the operation id it proposes unless that clashes with one already in use,
|
|
915
|
-
or DECLINE it with the reason — a request the spec gives no basis for is
|
|
916
|
-
declined as a spec gap for /appweaver specify, never published on a guess.
|
|
917
|
-
Keep every row the table already has.
|
|
1067
|
+
- {{be_repair_api_rule}}
|
|
918
1068
|
- REMOVE, or move to a DA-n assumption, any plan element with no spec basis —
|
|
919
1069
|
never keep a plan that exceeds or contradicts the spec. EXCEPTION: do NOT
|
|
920
1070
|
remove a cross-cutting element that is (or may be) mandated by the technical
|
|
@@ -928,9 +1078,9 @@ workflow:
|
|
|
928
1078
|
note "lift-failure: <constraint> — re-run /appweaver specify to lift it into
|
|
929
1079
|
CN-/DC-/IC-". (The gate will stop and direct the user to specify.)
|
|
930
1080
|
- Keep the Traceability section in sync. Preserve every already-conformant
|
|
931
|
-
section VERBATIM. Do NOT change the spec, the domain model
|
|
932
|
-
Close only the gaps whose lane is `backend`; a frontend gap is not
|
|
933
|
-
document's.
|
|
1081
|
+
section VERBATIM. Do NOT change the spec, the domain model, the frontend plan or
|
|
1082
|
+
api-plan.md. Close only the gaps whose lane is `backend`; a frontend gap is not
|
|
1083
|
+
this document's.
|
|
934
1084
|
Return the COMPLETE updated backend-plan.md content only.
|
|
935
1085
|
|
|
936
1086
|
- id: repair_frontend
|
|
@@ -951,10 +1101,10 @@ workflow:
|
|
|
951
1101
|
- Realise each CN-/DC-/IC-/SC- with an experience obligation, citing its spec id
|
|
952
1102
|
— the authorization surface and access conditions, what may not reach the
|
|
953
1103
|
client or its logs, storage and URLs, the binding rows, the performance row.
|
|
954
|
-
- CONTRACT gaps whose lane is `frontend`: bind ONLY to the service
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
assumption. A capability the experience needs that the surface does not offer
|
|
1104
|
+
- CONTRACT gaps whose lane is `frontend`: bind ONLY to the service's published
|
|
1105
|
+
API in context — api-plan.md, or the API section of a backend plan written
|
|
1106
|
+
before API plans existed. CITE it; do not restate, re-derive or contradict it,
|
|
1107
|
+
and introduce NO server-side behaviour or persistence assumption. A capability the experience needs that the surface does not offer
|
|
958
1108
|
is a CONTRACT REQUEST in §5's "Contract deltas needed" table — a new RQ-n, the
|
|
959
1109
|
operation id it proposes, what it sends and receives, the spec ids it serves —
|
|
960
1110
|
and the binding row that needs it cites that id; it is the service lane's to
|
|
@@ -964,7 +1114,7 @@ workflow:
|
|
|
964
1114
|
declined one, or log a DA-n routing the need to /appweaver specify.
|
|
965
1115
|
- Use the domain model's UBIQUITOUS LANGUAGE exactly in labels, states and
|
|
966
1116
|
messages, and cite BR-nnn rather than restating a rule. DO NOT EDIT
|
|
967
|
-
domain-model.md or backend-plan.md.
|
|
1117
|
+
domain-model.md, api-plan.md or backend-plan.md.
|
|
968
1118
|
- A state the UI can reach that the spec does not describe is a SPEC gap: log it
|
|
969
1119
|
as a DA-n that routes to /appweaver specify; never invent the requirement here.
|
|
970
1120
|
- Stay TECHNOLOGY-AGNOSTIC: no framework, router, state library, component
|
|
@@ -999,9 +1149,13 @@ workflow:
|
|
|
999
1149
|
action: set
|
|
1000
1150
|
vars: { stamp_fe: "{{fe_may_repair}}" }
|
|
1001
1151
|
|
|
1002
|
-
# THE DRAFT, redrawn from the
|
|
1003
|
-
#
|
|
1004
|
-
#
|
|
1152
|
+
# THE DRAFT, redrawn from the API plan as this run leaves it (the backend plan's API
|
|
1153
|
+
# section, for a feature planned before API plans existed) — a repair may have published
|
|
1154
|
+
# an endpoint or answered a request. It is the API contract the frontend lane binds to
|
|
1155
|
+
# and analyze-slice checks the code against. Master mode only, like the receipt, and only
|
|
1156
|
+
# for a gated backend lane. Advisory: it never fails the gate. A shape it cannot type is
|
|
1157
|
+
# reported, because the frontend's client gets that data untyped, and so is an operation
|
|
1158
|
+
# the previous draft had and this one does not, because the frontend may still bind to it.
|
|
1005
1159
|
- id: contract_draft
|
|
1006
1160
|
condition: "{{stamp_be}} == true"
|
|
1007
1161
|
action: execute_script
|
|
@@ -1010,7 +1164,32 @@ workflow:
|
|
|
1010
1164
|
subcommand: contract-draft
|
|
1011
1165
|
args: ["--feature-dir", "{{feature_dir}}"]
|
|
1012
1166
|
outputs:
|
|
1013
|
-
- { name: draft_path,
|
|
1167
|
+
- { name: draft_path, from: "$.path" }
|
|
1168
|
+
- { name: draft_plan, from: "$.plan" }
|
|
1169
|
+
- { name: draft_unread, from: "$.unread_count" }
|
|
1170
|
+
- { name: draft_unread_text, from: "$.unread_text" }
|
|
1171
|
+
- { name: draft_dropped, from: "$.dropped_count" }
|
|
1172
|
+
- { name: draft_dropped_text, from: "$.dropped_text" }
|
|
1173
|
+
- id: draft_unread_flag
|
|
1174
|
+
condition: "{{draft_unread}} != 0"
|
|
1175
|
+
action: set
|
|
1176
|
+
vars: { draft_clean: "false" }
|
|
1177
|
+
- id: warn_draft_unread
|
|
1178
|
+
condition: "{{stamp_be}} == true"
|
|
1179
|
+
action: verify_context
|
|
1180
|
+
require_true: draft_clean
|
|
1181
|
+
on_false: continue
|
|
1182
|
+
on_false_message: "API DRAFT — {{draft_unread}} endpoint shape(s) in {{draft_plan}} are not written as `{ field: type }`, so the frontend's client gets that data untyped: {{draft_unread_text}}. Write each request and response the way the template's endpoint block does, then re-run analyze-plan."
|
|
1183
|
+
- id: draft_dropped_flag
|
|
1184
|
+
condition: "{{draft_dropped}} != 0"
|
|
1185
|
+
action: set
|
|
1186
|
+
vars: { draft_kept: "false" }
|
|
1187
|
+
- id: warn_draft_dropped
|
|
1188
|
+
condition: "{{stamp_be}} == true"
|
|
1189
|
+
action: verify_context
|
|
1190
|
+
require_true: draft_kept
|
|
1191
|
+
on_false: continue
|
|
1192
|
+
on_false_message: "API DRAFT — {{draft_dropped}} operation(s) the previous api-draft.json had are no longer in {{draft_plan}}: {{draft_dropped_text}}. The frontend lane may still bind to them. If a repair removed them on purpose, the frontend plan has to stop binding to them; if not, restore their blocks in {{draft_plan}} and re-run analyze-plan."
|
|
1014
1193
|
|
|
1015
1194
|
- id: plan_gate_stamp_backend
|
|
1016
1195
|
condition: "{{stamp_be}} == true"
|
|
@@ -1072,6 +1251,7 @@ outputs:
|
|
|
1072
1251
|
feature_dir: "{{feature_dir}}"
|
|
1073
1252
|
bounded_context: "{{context}}"
|
|
1074
1253
|
backend_plan: "{{backend_plan}}" # empty when no backend lane is declared
|
|
1254
|
+
api_plan: "{{api_plan_ctx}}" # api-plan.md, gated with the backend plan; empty for a feature planned before API plans, whose backend plan carries its API
|
|
1075
1255
|
frontend_plan: "{{frontend_plan}}" # empty when no frontend lane is declared
|
|
1076
1256
|
frontend_excluded: "{{fe_excluded}}" # true = a frontend lane is declared and this feature records no surface in it (feature-lanes)
|
|
1077
1257
|
domain_model: "{{domain_model}}"
|
|
@@ -1092,7 +1272,7 @@ outputs:
|
|
|
1092
1272
|
frontend_receipt: "{{fe_receipt}}" # .aw-plan-gate.frontend.json, with the frontend's own verdict ({{fe_verdict}})
|
|
1093
1273
|
gate_receipt_at: "{{receipt_gated}}"
|
|
1094
1274
|
other_lane_gaps: "{{other_csv}}" # findings in a plan this run does not repair — another developer's lane, or one an open change names
|
|
1095
|
-
contract_requests: "{{req_summary}}" # the frontend plan's RQ-n requests and the
|
|
1096
|
-
api_draft: "{{draft_path}}" # api-draft.json, redrawn from
|
|
1097
|
-
note: "Ran for your working lane `{{working_lane}}` — backend plan: {{be_lane_mode}}; frontend plan: {{fe_lane_mode}} ({{open_count}} change(s) open: {{open_ids}}). A lane is in master mode unless an open change names it on its **Lanes** line. Gated: spec→backend-plan ({{be_gated}}), spec→frontend-plan ({{fe_gated}}), the plan
|
|
1098
|
-
next: "MASTER mode (no open change names the lane, verdict={{gate_verdict}}): /appweaver implement — no gap a plan rewrite closes is left; version unchanged, this gate closes nothing. If the verdict is routed-gaps, implement generates and warns: {{routed_csv}} — each is a spec or model gap, lifted by opening a change with /appweaver specify. REPORT mode (an open change names the lane — backend: {{be_open_ids}}; frontend: {{fe_open_ids}}): that lane's plan was checked read-only, and a run with no lane in master mode wrote plan-analyze-report.md only. If finalize-delta has already merged, the gaps ARE that merge — the lane plans are derived from spec.md + domain-model.md and finalize-delta moves only those
|
|
1275
|
+
contract_requests: "{{req_summary}}" # the frontend plan's RQ-n requests and the API plan's answers, as this run left them
|
|
1276
|
+
api_draft: "{{draft_path}}" # api-draft.json, redrawn from {{draft_plan}} — commit it with the plans
|
|
1277
|
+
note: "Ran for your working lane `{{working_lane}}` — backend plan: {{be_lane_mode}}; frontend plan: {{fe_lane_mode}} ({{open_count}} change(s) open: {{open_ids}}). A lane is in master mode unless an open change names it on its **Lanes** line. Gated: spec→backend-plan ({{be_gated}}), spec→frontend-plan ({{fe_gated}}), the frontend plan's contract binding against the API ({{both_lanes}} — it needs both lanes' plans, and reads the one you do not work on without repairing it) and each gated plan against domain-model.md. {{other_gaps}} finding(s) are in a plan this run does not repair — a lane you do not work on, for its developer, or a lane an open change names — and are reported, not repaired: {{other_csv}}. The domain model was READ, never written: a gap that needs a new entity, event or invariant is fixed by /appweaver specify. A plan in REPORT mode was not rewritten either — a master plan may not move while a delta that names its lane is in flight."
|
|
1278
|
+
next: "MASTER mode (no open change names the lane, verdict={{gate_verdict}}): /appweaver implement — no gap a plan rewrite closes is left; version unchanged, this gate closes nothing. If the verdict is routed-gaps, implement generates and warns: {{routed_csv}} — each is a spec or model gap, lifted by opening a change with /appweaver specify. REPORT mode (an open change names the lane — backend: {{be_open_ids}}; frontend: {{fe_open_ids}}): that lane's plan was checked read-only, and a run with no lane in master mode wrote plan-analyze-report.md only. If finalize-delta has already merged, the gaps ARE that merge — the lane plans are derived from spec.md + domain-model.md + api-plan.md and finalize-delta moves only those, so re-derive with /appweaver plan main after /appweaver close-delta, then re-run /appweaver analyze-plan in master mode. If the change has NOT merged yet, gate it where it lives: /appweaver analyze-plan-delta."
|