aw-spec-cli 0.1.33 → 0.1.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/README.md +76 -81
  2. package/assets/.appweaver/DESIGN-FORMAT.md +57 -25
  3. package/assets/.appweaver/STACK-PROFILES.md +95 -60
  4. package/assets/.appweaver/orchestrator/LAUNCHER.md +1 -1
  5. package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +173 -32
  6. package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +29 -1
  7. package/assets/.appweaver/orchestrator/modules/foundation-pack.orch.yaml +7 -4
  8. package/assets/.appweaver/orchestrator/modules/foundation-spec.orch.yaml +49 -60
  9. package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +58 -0
  10. package/assets/.appweaver/orchestrator/orchestrator.py +26 -8
  11. package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +20 -20
  12. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +22 -48
  13. package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +9 -7
  14. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +5 -5
  15. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +239 -40
  16. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +254 -43
  17. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +248 -68
  18. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +251 -20
  19. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +316 -10
  20. package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +6 -47
  21. package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +62 -16
  22. package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +132 -9
  23. package/assets/.appweaver/orchestrator/workflows/aw-spec-fix-test-coverage.orch.yaml +965 -0
  24. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +222 -169
  25. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +21 -22
  26. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +453 -120
  27. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-lane.orch.yaml +2 -2
  28. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +83 -6
  29. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +45 -2
  30. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +324 -74
  31. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +275 -44
  32. package/assets/.appweaver/scripts/python/aw-foundation.py +16 -13
  33. package/assets/.appweaver/scripts/python/aw-gaps.py +11 -3
  34. package/assets/.appweaver/scripts/python/aw-model-guard.py +295 -0
  35. package/assets/.appweaver/scripts/python/aw-plan-coverage.py +412 -3
  36. package/assets/.appweaver/scripts/python/aw-plangate.py +23 -16
  37. package/assets/.appweaver/scripts/python/aw-stack.py +1794 -265
  38. package/assets/.appweaver/stack-profiles/dotnet-webapi.json +0 -2
  39. package/assets/.appweaver/stack-profiles/java-spring.json +0 -2
  40. package/assets/.appweaver/templates/api-plan-template.md +107 -0
  41. package/assets/.appweaver/templates/delta-api-plan-template.md +87 -0
  42. package/assets/.appweaver/templates/delta-design-template.md +25 -23
  43. package/assets/.appweaver/templates/delta-spec-template.md +3 -3
  44. package/assets/.appweaver/templates/design-template.md +20 -42
  45. package/assets/.appweaver/templates/domain-model-template.md +3 -0
  46. package/assets/.appweaver/templates/ui-delta-design-template.md +11 -8
  47. package/assets/.appweaver/templates/ui-design-template.md +4 -4
  48. package/assets/foundations/foundation.spec.template.txt +25 -18
  49. package/assets/guardrails/README.md +61 -25
  50. package/assets/guardrails/methodology/ux/accessibility-standards.md +38 -0
  51. package/assets/guardrails/methodology/ux/content-design.md +34 -0
  52. package/assets/guardrails/methodology/ux/interaction-states.md +45 -0
  53. package/assets/guardrails/methodology/ux/journey-mapping.md +41 -0
  54. package/assets/guardrails/project-specific/domain/domain-requirements.md +25 -38
  55. package/assets/guardrails/project-specific/domain-rule-bindings.md +33 -69
  56. package/assets/guardrails/project-specific/frontend/ui-requirements.md +2 -2
  57. package/assets/guardrails/project-specific/service/technical-requirements.md +2 -2
  58. package/assets/guardrails/project-specific/tech-rule-bindings.md +16 -13
  59. package/assets/guardrails/sample-healthcare/domain/domain-requirements.md +58 -0
  60. package/assets/guardrails/sample-healthcare/domain-rule-bindings.md +138 -0
  61. package/assets/guardrails/sample-healthcare/frontend/ui-requirements.md +43 -0
  62. package/assets/guardrails/sample-healthcare/service/technical-requirements.md +40 -0
  63. package/assets/guardrails/sample-healthcare/tech-rule-bindings.md +303 -0
  64. package/dist/commands/init.d.ts.map +1 -1
  65. package/dist/commands/init.js +216 -7
  66. package/dist/commands/init.js.map +1 -1
  67. package/dist/utils/config.js +1 -1
  68. package/dist/utils/config.js.map +1 -1
  69. package/dist/utils/foundation.d.ts +36 -0
  70. package/dist/utils/foundation.d.ts.map +1 -0
  71. package/dist/utils/foundation.js +109 -0
  72. package/dist/utils/foundation.js.map +1 -0
  73. package/dist/utils/paths.js +1 -1
  74. package/dist/utils/paths.js.map +1 -1
  75. package/package.json +1 -1
@@ -13,12 +13,14 @@
13
13
  # is ACTIVATED so the stages after this one act on the same delta.
14
14
  #
15
15
  # THE FIVE CHECKS:
16
- # 1. delta-spec.md → delta-backend-plan.md — every ADDED/MODIFIED spec item realised
16
+ # 1. delta-spec.md → delta-backend-plan.md + delta-api-plan.md — every ADDED/MODIFIED
17
+ # spec item realised, and every endpoint the change's API adds or changes realised by
18
+ # an element of its delta backend plan
17
19
  # 2. delta-spec.md → delta-frontend-plan.md — every experience item realised
18
- # 3. delta plan ↔ delta plan — CONTRACT BINDING across the change: what the frontend
19
- # delta binds to must appear in the service delta's "Contract deltas for the frontend
20
- # lane" table or in the master's published surface. A call neither publishes passes
21
- # both one-sided checks and fails at integration.
20
+ # 3. the change's API ↔ delta-frontend-plan.md — CONTRACT BINDING across the change: what
21
+ # the frontend delta binds to must appear in the change's API (its delta-api-plan.md)
22
+ # or in the feature's (api-plan.md). A call neither publishes passes both one-sided
23
+ # checks and fails at integration.
22
24
  # 4. THE EFFECTIVE MODEL — domain-model.md + this change's model delta + the model
23
25
  # deltas of every LOWER-WAVE change (its predecessors). Every structural item the
24
26
  # model delta adds has a realisation row; nothing structural is invented in a plan.
@@ -41,8 +43,16 @@
41
43
  # repaired or stopped on. Its delta plan not existing yet is a note, not a refusal — check 3
42
44
  # waits until both halves are on disk.
43
45
  #
46
+ # THE SERVICE HALF IS TWO DOCUMENTS. The endpoints a change adds, changes and removes, and
47
+ # the requests it answers, are in its delta-api-plan.md — the one finalize-delta merges into
48
+ # api-plan.md, block by block — and its delta-backend-plan.md realises them. Both are in
49
+ # context with the feature's API plan, and a repair rewrites the one the gap is in, the
50
+ # delta API plan first. A change planned before delta API plans existed keeps its API in
51
+ # its delta backend plan's contract table and API section, which every check then reads and
52
+ # an API repair rewrites.
53
+ #
44
54
  # A SERVICE CHANGE THAT BREAKS A FRONTEND BINDING IS A WARNING (contract-impact). An
45
- # operation the service delta changes or removes that the master frontend plan binds to,
55
+ # operation the change's API changes or removes that the master frontend plan binds to,
46
56
  # and that the change's frontend delta plan does not name, is reported by script before the
47
57
  # check — whatever lanes the change names. The frontend half may follow from its own
48
58
  # developer or in a follow-up change, so it never stops the gate.
@@ -72,8 +82,8 @@
72
82
  # =============================================================================
73
83
 
74
84
  name: aw-spec-analyze-plan-delta
75
- description: The delta-spec↔delta-plan conformance gate for ONE open change — confirm its delta-backend-plan.md and delta-frontend-plan.md realise delta-spec.md, bind to each other's contract deltas, realise this change's domain model delta, and only MODIFY elements the masters really define. Checked against the EFFECTIVE model (domain-model.md plus this change's model delta plus every lower-wave predecessor's, whose delta-specs are in context too) and told, deterministically, which other open changes touch the same aggregates. Gates only the lanes the change names that you work on — the other developer's delta plan is read for the contract check, its gaps are reported for them, and its absence is a note. Warns, by script, when the service delta changes or removes an operation the frontend binds to and the frontend half does not follow. Asks which open change it is gating when more than one names your lane; a CR id as the argument selects without a prompt. Does not modify the masters or close the change.
76
- version: 2.2.0
85
+ description: The delta-spec↔delta-plan conformance gate for ONE open change — confirm its delta-api-plan.md, delta-backend-plan.md and delta-frontend-plan.md realise delta-spec.md, that the frontend delta binds to the API the change and the feature publish, realise this change's domain model delta, and only MODIFY elements the masters really define. Checked against the EFFECTIVE model (domain-model.md plus this change's model delta plus every lower-wave predecessor's, whose delta-specs are in context too) and told, deterministically, which other open changes touch the same aggregates. Gates only the lanes the change names that you work on — the other developer's delta plan is read for the contract check, its gaps are reported for them, and its absence is a note. Warns, by script, when the service delta changes or removes an operation the frontend binds to and the frontend half does not follow. Asks which open change it is gating when more than one names your lane; a CR id as the argument selects without a prompt. Does not modify the masters or close the change.
86
+ version: 2.5.0
77
87
  agent_agnostic: true
78
88
  dialect: aw-spec.orchestrator/v1
79
89
 
@@ -158,6 +168,28 @@ vars:
158
168
  backend_repair: "false"
159
169
  frontend_repair: "false"
160
170
  delta_backend_plan: ""
171
+ # THE API — the change's delta-api-plan.md and the feature's api-plan.md, each in context
172
+ # with the backend lane's documents when it exists. A change planned before delta API
173
+ # plans has none: its delta backend plan carries its API, and an API repair goes there.
174
+ delta_api_plan: ""
175
+ delta_api_plan_exists: "false"
176
+ api_plan: ""
177
+ api_plan_exists: "false"
178
+ impact_go: "false" # a delta backend or delta API plan is on disk ⇒ contract-impact runs
179
+ api_delta_go: "false"
180
+ api_master_go: "false"
181
+ be_api_delta_ctx: ""
182
+ api_master_ctx: ""
183
+ api_repair: "false" # the analyze pass found a gap in an endpoint of the change's API
184
+ api_repair_go: "false" # …and this pass rewrites delta-api-plan.md for it
185
+ api_in_backend: "false" # …or, with no delta API plan, rewrites the delta backend plan
186
+ # What the delta backend plan's repair is told about the change's API — set below.
187
+ be_delta_api_rule: ""
188
+ change_draft_path: ""
189
+ change_draft_plan: "" # the document the change's draft was drawn from
190
+ change_draft_unread: "0"
191
+ change_draft_unread_text: "none"
192
+ change_draft_clean: "true"
161
193
  delta_frontend_plan: ""
162
194
  # The plan paths AS CONTEXT — bound only for a lane this run actually gates. feature-paths
163
195
  # and cr-paths resolve every path whatever the declaration says, so putting them straight
@@ -205,6 +237,8 @@ workflow:
205
237
  - { name: frontend_plan, from: "$.frontend_plan" }
206
238
  - { name: backend_plan_exists, from: "$.backend_plan_exists" }
207
239
  - { name: frontend_plan_exists, from: "$.frontend_plan_exists" }
240
+ - { name: api_plan, from: "$.api_plan" }
241
+ - { name: api_plan_exists, from: "$.api_plan_exists" }
208
242
 
209
243
  # THIS FEATURE'S LANES. lane_resolve above read the REPO's declaration; one feature may
210
244
  # own no part of a lane's surface — adopt records `lanes: [backend]` in
@@ -329,6 +363,8 @@ workflow:
329
363
  - { name: delta_frontend_plan, from: "$.delta_frontend_plan" }
330
364
  - { name: delta_backend_plan_exists, from: "$.delta_backend_plan_exists" }
331
365
  - { name: delta_frontend_plan_exists, from: "$.delta_frontend_plan_exists" }
366
+ - { name: delta_api_plan, from: "$.delta_api_plan" }
367
+ - { name: delta_api_plan_exists, from: "$.delta_api_plan_exists" }
332
368
  - { name: wave, from: "$.wave" }
333
369
  - { name: predecessor_docs, from: "$.predecessor_docs" }
334
370
  - { name: predecessor_count, from: "$.predecessor_count" }
@@ -464,9 +500,20 @@ workflow:
464
500
  on_false: continue
465
501
  on_false_message: "NOTE — change {{cr_id}} also names the {{awaited_txt}} lane, whose developer has not written its delta plan yet. This run gates your half only; the contract between the two halves (check 3) is checked once both delta plans are on disk."
466
502
 
467
- # D4b. What the service delta changes or removes that the frontend binds to, by script.
468
- - id: contract_impact
503
+ # D4b. What the change's API changes or removes that the frontend binds to, by script.
504
+ # contract-impact reads the delta API plan beside --delta-backend, and the delta
505
+ # backend plan's own contract table for a change planned before delta API plans;
506
+ # it runs when either document is on disk.
507
+ - id: impact_go_be
469
508
  condition: "{{delta_backend_plan_exists}} == true"
509
+ action: set
510
+ vars: { impact_go: "true" }
511
+ - id: impact_go_api
512
+ condition: "{{delta_api_plan_exists}} == true"
513
+ action: set
514
+ vars: { impact_go: "true" }
515
+ - id: contract_impact
516
+ condition: "{{impact_go}} == true"
470
517
  action: execute_script
471
518
  on_error: continue
472
519
  script: { ref: actions }
@@ -542,18 +589,74 @@ workflow:
542
589
  condition: "{{fe_seen}} == true"
543
590
  action: set
544
591
  vars: { fe_master_ctx: "{{frontend_plan}}" }
592
+ # The API documents ride with the backend lane's: the change's delta API plan with its
593
+ # delta backend plan, the feature's API plan with the master backend plan — each only when
594
+ # it exists.
595
+ - id: api_delta_arm
596
+ condition: "{{be_seen}} == true"
597
+ action: set
598
+ vars: { api_delta_go: "{{delta_api_plan_exists}}" }
599
+ - id: api_delta_ctx_path
600
+ condition: "{{api_delta_go}} == true"
601
+ action: set
602
+ vars: { be_api_delta_ctx: "{{delta_api_plan}}" }
603
+ - id: api_master_arm
604
+ condition: "{{be_master_ctx}} != "
605
+ action: set
606
+ vars: { api_master_go: "{{api_plan_exists}}" }
607
+ - id: api_master_ctx_path
608
+ condition: "{{api_master_go}} == true"
609
+ action: set
610
+ vars: { api_master_ctx: "{{api_plan}}" }
611
+
612
+ # What the delta backend plan's repair is told about the change's API: the delta API
613
+ # plan, or — for a change planned before those — its own contract table and API section.
614
+ - id: be_delta_api_rule_api
615
+ action: set
616
+ vars:
617
+ be_delta_api_rule: "THE CHANGE'S API IS IN delta-api-plan.md (in context), repaired before this document whenever a gap was in one of its endpoints. Do NOT publish or restate endpoints here: REALISE each endpoint it adds or changes as the use-case its **Maps to** names, ADDED or MODIFIED here, with request and response DTOs matching its shapes. A gap in an endpoint itself — its row, its block, its operation id, a request's answer — is the delta API plan's, not this document's."
618
+ - id: be_delta_api_rule_in_plan
619
+ condition: "{{delta_api_plan_exists}} == false"
620
+ action: set
621
+ vars:
622
+ be_delta_api_rule: "THIS CHANGE'S API IS IN THIS DOCUMENT — it was planned before delta API plans existed. CONTRACT gaps whose lane is `backend`: publish the missing surface in '## Contract deltas for the frontend lane' — one row per endpoint added, changed or removed, with its operation id — and write each added or changed endpoint in full under '## API — added and changed endpoints', every shape `{ field: type }`. Those are the only parts of this document the experience delta may bind to."
545
623
 
546
624
  # 4b. Load the domain GATE overlays (the domain-rule-bindings `/aw-spec-gate` checklist)
547
625
  # as the conformance checklist — VALIDATION input only, NEVER authoring. analyze sees
548
626
  # them (include_standards: true); the repair steps do NOT (the delta conforms to the
549
- # delta SPEC, not to the overlays). Empty/no-op for a non-domain project.
627
+ # delta SPEC, not to the overlays). Empty/no-op for a non-domain project — a map whose
628
+ # heading holds a `_None_` line. A map with no such heading, or one naming a file that
629
+ # is not on disk, warns and carries on.
550
630
  - id: resolve_gate_overlays
551
631
  action: execute_script
552
632
  script: { ref: actions }
553
633
  subcommand: resolve-domain
554
634
  args: ["--command", "aw-spec-gate"]
555
635
  outputs:
556
- - { name: gate_overlays, from: "$.candidates" }
636
+ - { name: gate_overlays, from: "$.candidates" }
637
+ - { name: gate_domain, from: "$.domain" }
638
+ - { name: gate_map_exists, from: "$.rulemap_exists" }
639
+ - { name: gate_heading_found, from: "$.heading_found" }
640
+ - { name: gate_missing, from: "$.missing" }
641
+ - id: gate_flags
642
+ action: set
643
+ vars: { gate_all_on_disk: "true" }
644
+ - id: gate_flag_missing
645
+ condition: "{{gate_missing}} != []"
646
+ action: set
647
+ vars: { gate_all_on_disk: "false" }
648
+ - id: warn_gate_heading
649
+ condition: "{{gate_map_exists}} == true"
650
+ action: verify_context
651
+ require_true: gate_heading_found
652
+ on_false: continue
653
+ on_false_message: "WARNING — guardrails/{{gate_domain}}/domain-rule-bindings.md has no `## /aw-spec-gate` heading, so the change's 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."
654
+ - id: warn_gate_missing
655
+ condition: "{{gate_map_exists}} == true"
656
+ action: verify_context
657
+ require_true: gate_all_on_disk
658
+ on_false: continue
659
+ 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 change's plans were not checked against them: {{gate_missing}}. Correct the paths, or add the files."
557
660
  - id: load_gate_overlays
558
661
  action: load_standards
559
662
  files_from_variable: gate_overlays
@@ -583,9 +686,11 @@ workflow:
583
686
  context:
584
687
  - { path: "{{delta_spec}}" } # THE ANCHOR for this change
585
688
  - { path: "{{delta_model}}", optional: true } # its model half — unfilled on a plan-only change
689
+ - { path: "{{be_api_delta_ctx}}", optional: true } # the change's API — merged into api-plan.md at finalize-delta
586
690
  - { path: "{{be_delta_ctx}}", optional: true }
587
691
  - { path: "{{fe_delta_ctx}}", optional: true }
588
692
  - { path: "{{spec_file}}" } # the master spec (READ ONLY)
693
+ - { path: "{{api_master_ctx}}", optional: true } # the feature's API (READ ONLY) — what a changed or removed endpoint must name
589
694
  - { path: "{{be_master_ctx}}", optional: true } # the master plans (READ ONLY) — the base
590
695
  - { path: "{{fe_master_ctx}}", optional: true } # every MODIFIED element must name
591
696
  - { path: "{{domain_model}}", optional: true } # the canonical model (READ ONLY)
@@ -613,8 +718,8 @@ workflow:
613
718
  - id: analyze
614
719
  action: agent_query
615
720
  include_standards: true # the gate overlays (checklist) are in the standards
616
- schema: { ok: true, backend_repair: false, frontend_repair: false, gaps: [ { severity: "high", check: "<spec-backend|spec-frontend|contract|model|master|wave|overlay>", lane: "<backend|frontend>", spec_ref: "<delta FR/BR/CN/DC/IC/UX/US or overlay or —>", where: "<delta-plan section>", gap: "<how it drifts>" } ] }
617
- mock: { ok: true, backend_repair: false, frontend_repair: false, gaps: [] }
721
+ schema: { ok: true, backend_repair: false, api_repair: false, frontend_repair: false, gaps: [ { severity: "high", check: "<spec-backend|spec-frontend|contract|model|master|wave|overlay>", lane: "<backend|frontend>", spec_ref: "<delta FR/BR/CN/DC/IC/UX/US or overlay or —>", where: "<delta-plan section>", gap: "<how it drifts>" } ] }
722
+ mock: { ok: true, backend_repair: false, api_repair: false, frontend_repair: false, gaps: [] }
618
723
  task: |
619
724
  delta-spec.md is the ANCHOR for change {{cr_id}} (wave {{wave}}). Gate this
620
725
  change's DELTA PLANS against it, against the masters they change, and against the
@@ -628,7 +733,16 @@ workflow:
628
733
  nothing else. Every gap still carries the `lane` whose document must change to
629
734
  close it, even when that lane is not gated here.
630
735
 
631
- CHECK 1 — delta-spec.md → delta-backend-plan.md (when it is in context):
736
+ THE CHANGE'S API is its delta-api-plan.md when it is in context — the endpoints
737
+ the change adds, changes and removes (its Contract deltas table and the whole
738
+ blocks under it) and the requests it answers; finalize-delta merges it into the
739
+ feature's api-plan.md by script, block by block. With no delta-api-plan.md in
740
+ context the change was planned before those existed, and its delta backend plan's
741
+ contract table and API section are its API. THE FEATURE'S API is api-plan.md when
742
+ it is in context, else the master backend plan's API section.
743
+
744
+ CHECK 1 — delta-spec.md → delta-backend-plan.md and the change's API (when the
745
+ delta backend plan is in context):
632
746
  (a) every ADDED / MODIFIED delta-spec item — FR / BR / CN- / DC- / IC- / user
633
747
  story — has a home in the delta plan (an ADDED or MODIFIED element that serves
634
748
  it). A delta-spec item with no delta-plan element is a HIGH gap. EXCEPT the
@@ -640,7 +754,14 @@ workflow:
640
754
  (d) PLAN-ONLY CHANGE — if the delta-spec is an unfilled stub, the spec is
641
755
  deliberately unchanged and this change moves only HOW existing ids are realised.
642
756
  Then every changed element must still trace to an EXISTING spec id in the master
643
- spec (in context). An element tracing to nothing at all is still a HIGH gap.
757
+ spec (in context). An element tracing to nothing at all is still a HIGH gap;
758
+ (e) with a delta-api-plan.md: every endpoint it adds or changes names under
759
+ **Maps to** a use-case the delta backend plan ADDS or MODIFIES, or one the master
760
+ backend plan defines — an endpoint nothing realises is a HIGH gap on lane
761
+ `backend` — and the delta backend plan restates none of it. Every `added` or
762
+ `changed` row has its block, written WHOLE (the merge puts it in place of the
763
+ API plan's block as it stands, so a block that carries only the difference loses
764
+ the rest), every shape as `{ field: type }`; a `removed` row has no block.
644
765
 
645
766
  CHECK 2 — delta-spec.md → delta-frontend-plan.md (when it is in context):
646
767
  (a) every UX- item in the delta-spec has a home HERE — the service lane excludes
@@ -656,8 +777,7 @@ workflow:
656
777
  CHECK 3 — CONTRACT BINDING across the change (ONLY when {{both_lanes}} is true;
657
778
  skip entirely otherwise):
658
779
  (a) EVERY call, endpoint or payload the experience delta binds to is EITHER in
659
- the service delta's "Contract deltas for the frontend lane" table OR already in
660
- the MASTER backend plan's published surface. One that is in neither is a HIGH
780
+ the change's API OR already in the feature's API. One that is in neither is a HIGH
661
781
  `contract` gap — lane `backend` when the delta-spec requires the capability, lane
662
782
  `frontend` when the experience invented it;
663
783
  (b) FIELD SHAPES agree in both directions — a field the experience reads that the
@@ -666,14 +786,15 @@ workflow:
666
786
  (c) anything the experience delta raised under "Contract deltas needed" is
667
787
  UNRESOLVED by definition: report it so it is closed here rather than at
668
788
  integration;
669
- (d) a contract the service delta REMOVES or narrows that the master frontend plan
789
+ (d) a contract the change's API REMOVES or narrows that the master frontend plan
670
790
  still uses is a HIGH gap — the experience delta has to carry the matching change;
671
791
  (e) OPERATION IDS MATCH. Every binding row the experience delta adds or changes
672
- leads with an operation id, and that id is the one the service delta's table or
673
- the master backend plan gives the endpoint, spelled exactly. A binding with no id,
674
- or with an id neither names, is a HIGH `contract` gap on lane `frontend`; a
675
- service-delta row with no operation id is one on lane `backend`. Implement finds
676
- each endpoint by this id in the service's exported API document.
792
+ leads with an operation id, and that id is the one the change's API or the
793
+ feature's API gives the endpoint, spelled exactly. A binding with no id, or with
794
+ an id neither names, is a HIGH `contract` gap on lane `frontend`; a Contract
795
+ deltas row with no operation id is one on lane `backend`. Implement finds each
796
+ endpoint by this id in the API document drafted from the API plans, this change's
797
+ included.
677
798
 
678
799
  CHECK 4 — THE EFFECTIVE MODEL. It is domain-model.md PLUS this change's model
679
800
  delta PLUS the model deltas of every LOWER-WAVE change in context (its
@@ -701,9 +822,14 @@ workflow:
701
822
  cannot MODIFY what the master does not define (that would be an ADD). A dangling
702
823
  MODIFIED reference is a HIGH `master` gap;
703
824
  (b) every MODIFIED / REMOVED spec id names one the master spec really defines;
704
- (c) nothing in a delta plan edits the master: the delta plans are the whole plan
705
- for this change, and no stage merges them back — a master plan is re-derived from
706
- the spec and the model that finalize-delta merges.
825
+ (c) nothing in a delta plan edits the master: the delta lane plans are the whole
826
+ plan for this change, and no stage merges them back — a master plan is
827
+ re-derived from the spec, the model and the API that finalize-delta merges;
828
+ (d) every `changed` or `removed` endpoint of the change's API names an endpoint
829
+ the feature's API really has, by its operation id — the merge finds it by that id
830
+ — and an `added` one takes an id the feature's API does not already use. A
831
+ `changed` endpoint the feature does not have is a HIGH `master` gap on lane
832
+ `backend`: it is an `added` one.
707
833
 
708
834
  CHECK 6 — WAVE DISCIPLINE. This change is wave {{wave}}. Other open changes
709
835
  touching the same aggregates, computed from the pending model deltas:
@@ -730,14 +856,18 @@ workflow:
730
856
  a delta plan).
731
857
 
732
858
  Tag every gap with its `check` and the `lane` whose document must change to close
733
- it. Set backend_repair true if any gap needs the service delta rewritten, and
734
- frontend_repair likewise. (If a delta plan is still the empty template, treat the
735
- WHOLE delta spec as gaps against it.) Set ok=true ONLY when every applicable
736
- check passes and no touched checklist constraint is unaccounted for.
859
+ it. Set api_repair true if any gap is in an endpoint of the change's API — a
860
+ Contract deltas row, a block, an operation id, a request's answer — and
861
+ backend_repair true if any needs the delta backend plan itself rewritten; both
862
+ when both are. Set frontend_repair likewise. (If a delta plan is still the empty
863
+ template, treat the WHOLE delta spec as gaps against it.) Set ok=true ONLY when
864
+ every applicable check passes and no touched checklist constraint is unaccounted
865
+ for.
737
866
  outputs:
738
867
  - { name: analyze_ok, from: "$.ok" }
739
868
  - { name: analyze_gaps, from: "$.gaps" }
740
869
  - { name: backend_repair, from: "$.backend_repair" }
870
+ - { name: api_repair, from: "$.api_repair" }
741
871
  - { name: frontend_repair, from: "$.frontend_repair" }
742
872
  - id: conform_break
743
873
  action: break
@@ -821,6 +951,27 @@ workflow:
821
951
  condition: "{{backend_repair}} == true"
822
952
  action: set
823
953
  vars: { be_repair: "{{be_present}}" }
954
+ # The change's API by the same assignments. With no delta API plan the change's API
955
+ # is in its delta backend plan, so an API gap raises that repair instead.
956
+ - id: api_repair_clear
957
+ action: set
958
+ vars: { api_repair_go: "false", api_in_backend: "false" }
959
+ - id: api_repair_flag
960
+ condition: "{{api_repair}} == true"
961
+ action: set
962
+ vars: { api_repair_go: "{{be_present}}" }
963
+ - id: api_repair_in_backend
964
+ condition: "{{delta_api_plan_exists}} == false"
965
+ action: set
966
+ vars: { api_in_backend: "{{api_repair_go}}" }
967
+ - id: api_repair_no_plan
968
+ condition: "{{delta_api_plan_exists}} == false"
969
+ action: set
970
+ vars: { api_repair_go: "false" }
971
+ - id: be_repair_for_api
972
+ condition: "{{api_in_backend}} == true"
973
+ action: set
974
+ vars: { be_repair: "true" }
824
975
  - id: fe_repair_clear
825
976
  action: set
826
977
  vars: { fe_repair: "false" }
@@ -829,6 +980,36 @@ workflow:
829
980
  action: set
830
981
  vars: { fe_repair: "{{fe_present}}" }
831
982
 
983
+ # The change's API first, so the delta backend repair below reads it as repaired.
984
+ - id: repair_api
985
+ condition: "{{api_repair_go}} == true"
986
+ action: agent_author
987
+ include_standards: false # rewrite-in-place: the delta spec anchors — NOT the overlays
988
+ output_target: { type: file, path: "{{delta_api_plan}}" }
989
+ task: |
990
+ delta-spec.md is the ANCHOR — update the DELTA API PLAN for {{cr_id}} (in context)
991
+ to REALISE it, closing the gaps whose lane is `backend` that are in one of its
992
+ endpoints (the delta spec WINS every time):
993
+ {{analyze_gaps}}
994
+ - "## Contract deltas for the frontend lane": one row per endpoint the change
995
+ adds, changes or removes, with its operation id. A changed or removed endpoint
996
+ names one the feature's API (in context) really has, by its id; one it does not
997
+ have is `added`. A new endpoint takes an id unique across the service.
998
+ - "## Endpoints added or changed": each `added` or `changed` endpoint as a WHOLE
999
+ block — the `### `VERB /route`` heading, then **Operation id**, **Auth**,
1000
+ **Request**, **Success**, the **Errors** table and **Maps to**, every shape as
1001
+ `{ field: type }`. finalize-delta puts this block in place of the API plan's, so
1002
+ it carries the unchanged fields too. A removed endpoint has no block.
1003
+ - "## Requests from the frontend lane": only the requests this change's delta spec
1004
+ gives a basis for; `None` when it answers none.
1005
+ - REMOVE any endpoint with no delta-spec basis (on a PLAN-ONLY change, no existing
1006
+ spec id); **Maps to** names the use-case the delta backend plan realises it with.
1007
+ - Preserve every already-conformant row and block VERBATIM. Do NOT change the
1008
+ delta spec, the feature's API plan, either delta lane plan, the masters or the
1009
+ domain model. Do NOT edit the Wave / Base version / Delta spec / Delta backend
1010
+ plan headers — scripts stamp those.
1011
+ Return the COMPLETE updated delta API plan content only.
1012
+
832
1013
  - id: repair_backend
833
1014
  condition: "{{be_repair}} == true"
834
1015
  action: agent_author
@@ -852,9 +1033,7 @@ workflow:
852
1033
  EDIT domain-model.md or the model delta: they are spec-tier. A gap that can
853
1034
  only be closed by ADDING to the model stays open with a DA-n saying it routes
854
1035
  to /appweaver specify.
855
- - CONTRACT gaps whose lane is `backend`: publish the missing surface in
856
- "## Contract deltas for the frontend lane" as field shapes. That table is the
857
- only part of this document the experience delta may bind to.
1036
+ - {{be_delta_api_rule}}
858
1037
  - WAVE gaps: name a lower-wave change you build on under "## Depends on", and
859
1038
  name a same-wave overlap under "Other open deltas" — you may NOT assume a
860
1039
  same-wave change's structure or contract, because nothing orders it against
@@ -867,8 +1046,9 @@ workflow:
867
1046
  the delta spec".
868
1047
  - Keep the technology-agnostic form (signatures + pre/post/invariant, field
869
1048
  shapes — NO code). Preserve every already-conformant section VERBATIM. Do NOT
870
- change the delta spec, the masters or the domain model. Do NOT edit the Wave /
871
- Base version / Delta spec / Model delta headers — scripts stamp those.
1049
+ change the delta spec, the delta API plan, the masters or the domain model. Do
1050
+ NOT edit the Wave / Base version / Delta spec / Model delta / API delta headers
1051
+ — scripts stamp those.
872
1052
  Return the COMPLETE updated delta plan content only.
873
1053
 
874
1054
  - id: repair_frontend
@@ -888,10 +1068,11 @@ workflow:
888
1068
  from the master frontend plan (in context); if the master does not define it,
889
1069
  make it an ADDED element instead. A shared component is MODIFIED in place,
890
1070
  never copied into the change.
891
- - CONTRACT gaps whose lane is `frontend`: bind ONLY to the service delta's
892
- "## Contract deltas for the frontend lane" table and to the master plan's
893
- published surface. CITE them; do not restate, re-derive or contradict them, and
894
- introduce NO server-side behaviour or persistence assumption. A capability the
1071
+ - CONTRACT gaps whose lane is `frontend`: bind ONLY to the change's API (its
1072
+ delta API plan — or, for a change planned before those, its delta backend plan's
1073
+ contract table) and to the feature's API. CITE them; do not restate, re-derive
1074
+ or contradict them, and introduce NO server-side behaviour or persistence
1075
+ assumption. A capability the
895
1076
  experience needs that neither offers stays under "Contract deltas needed" — it
896
1077
  is the service lane's to publish, never a client-side workaround.
897
1078
  - WAVE gaps: name a lower-wave change you build on under "## Depends on", and a
@@ -905,10 +1086,38 @@ workflow:
905
1086
  requirement here.
906
1087
  - Stay TECHNOLOGY-AGNOSTIC: no framework, router, state library, component
907
1088
  library or styling approach. Preserve every already-conformant section
908
- VERBATIM. Do NOT edit the Wave / Base version / Delta spec / Service delta
909
- headers — scripts stamp those.
1089
+ VERBATIM. Do NOT edit the Wave / Base version / Delta spec / API delta headers
1090
+ — scripts stamp those.
910
1091
  Return the COMPLETE updated delta plan content only.
911
1092
 
1093
+ # THE CHANGE'S API DRAFT, redrawn from the change's API as this run leaves it — its delta
1094
+ # API plan, or the delta backend plan of a change planned before those; a repair may have
1095
+ # added, changed or removed an endpoint. The frontend lane binds to it while the change is
1096
+ # open, and analyze-slice-delta checks the built service against it. Advisory: it never
1097
+ # fails the gate.
1098
+ - id: contract_draft_change
1099
+ condition: "{{be_present}} == true"
1100
+ action: execute_script
1101
+ on_error: continue
1102
+ script: { ref: actions }
1103
+ subcommand: contract-draft
1104
+ args: ["--feature-dir", "{{feature_dir}}", "--cr", "{{cr_id}}"]
1105
+ outputs:
1106
+ - { name: change_draft_path, from: "$.path" }
1107
+ - { name: change_draft_plan, from: "$.plan" }
1108
+ - { name: change_draft_unread, from: "$.unread_count" }
1109
+ - { name: change_draft_unread_text, from: "$.unread_text" }
1110
+ - id: change_draft_unread_flag
1111
+ condition: "{{change_draft_unread}} != 0"
1112
+ action: set
1113
+ vars: { change_draft_clean: "false" }
1114
+ - id: warn_change_draft_unread
1115
+ condition: "{{be_present}} == true"
1116
+ action: verify_context
1117
+ require_true: change_draft_clean
1118
+ on_false: continue
1119
+ on_false_message: "API DRAFT — {{change_draft_unread}} endpoint shape(s) in {{change_draft_plan}} are not written as `{ field: type }`, so the frontend's client gets that data untyped: {{change_draft_unread_text}}. Write each endpoint the change adds or changes as a whole block under its endpoints section, the way the API plan does."
1120
+
912
1121
  # THE STOP. Two independent raises: nothing drifts, or what drifts is only the other
913
1122
  # developer's to close — reported for them below.
914
1123
  - id: gate_ok_conformant
@@ -948,6 +1157,7 @@ outputs:
948
1157
  cr_id: "{{cr_id}}"
949
1158
  cr_dir: "{{cr_dir}}"
950
1159
  wave: "{{wave}}"
1160
+ delta_api_plan: "{{be_api_delta_ctx}}" # the change's API, gated with its delta backend plan; empty for a change planned before delta API plans
951
1161
  delta_backend_plan: "{{delta_backend_plan}}" # empty when that lane has no delta plan
952
1162
  delta_frontend_plan: "{{delta_frontend_plan}}"
953
1163
  conformant: "{{analyze_ok}}" # every check passed, the other developer's half included; false on a run that finishes means only other_lane_gaps are left
@@ -957,6 +1167,7 @@ outputs:
957
1167
  gated_backend: "{{be_present}}" # checked and repaired by this run
958
1168
  gated_frontend: "{{fe_present}}"
959
1169
  other_lane_gaps: "{{other_csv}}" # gaps only the other developer's delta plan can close
960
- contract_impact: "{{impact_csv}}" # operations the service delta changes or removes that the frontend still binds to
1170
+ contract_impact: "{{impact_csv}}" # operations the change's API changes or removes that the frontend still binds to
1171
+ change_api_draft: "{{change_draft_path}}" # changes/<CR-id>/api-draft.json, redrawn from {{change_draft_plan}}
961
1172
  note: "Gated change {{cr_id}} (wave {{wave}}) against its delta spec, the masters it changes, and the EFFECTIVE model — domain-model.md plus this change's model delta plus the {{predecessor_count}} predecessor change(s) from LOWER waves (each one's model delta and its delta-spec). Same-wave changes are visible but never assumed: {{sibling_count}} open at the same or a higher wave, overlapping this one on — {{overlap_report}}. The masters and the model were READ, never written."
962
1173
  next: "/appweaver implement {{cr_id}} → build → analyze-slice-delta → finalize-delta → analyze-slice → close-delta (implement is one command for both lanes and both paths — passing the id above skips its 'which change' prompt; the delta plans realise the delta spec; the change stays OPEN through finalize-delta's merge and analyze-slice's verification, and only close-delta archives it and bumps the version)"