aw-spec-cli 0.1.20 → 0.1.22
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/assets/.appweaver/ORCH-DIALECT.md +8 -3
- package/assets/.appweaver/STACK-PROFILES.md +87 -8
- package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +30 -0
- package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +22 -1
- package/assets/.appweaver/orchestrator/orchestrator.py +65 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +6 -6
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +144 -52
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +78 -10
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +283 -25
- package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +4 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +202 -40
- package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +140 -36
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +557 -57
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +3 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +39 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-recall-delta.orch.yaml +28 -7
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +47 -23
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +101 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +141 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-prototype.orch.yaml +386 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-workflow-model.orch.yaml +135 -0
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +772 -216
- package/assets/.appweaver/scripts/bash/aw-xref.sh +4 -1
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +708 -209
- package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +4 -1
- package/assets/.appweaver/scripts/python/aw-crstate.py +319 -0
- package/assets/.appweaver/scripts/python/aw-foundation.py +151 -0
- package/assets/.appweaver/scripts/python/aw-gaps.py +119 -0
- package/assets/.appweaver/scripts/python/aw-payload-parity.py +19 -0
- package/assets/.appweaver/scripts/python/aw-plan-coverage.py +503 -0
- package/assets/.appweaver/scripts/python/aw-plangate.py +216 -0
- package/assets/.appweaver/scripts/python/aw-principles.py +108 -0
- package/assets/.appweaver/scripts/python/aw-stack.py +257 -28
- package/assets/.appweaver/scripts/python/aw-testlog.py +148 -0
- package/assets/.appweaver/scripts/python/aw-xref.py +141 -4
- package/assets/.appweaver/stack-profiles/angular.json +26 -0
- package/assets/.appweaver/stack-profiles/blazor-wasm.json +38 -0
- package/assets/.appweaver/stack-profiles/dotnet-webapi.json +39 -0
- package/assets/.appweaver/stack-profiles/java-spring.json +20 -0
- package/assets/.appweaver/stack-profiles/nextjs.json +26 -0
- package/assets/.appweaver/stack-profiles/node-express.json +27 -0
- package/assets/.appweaver/stack-profiles/python-fastapi.json +16 -0
- package/assets/.appweaver/stack-profiles/react-vite.json +26 -0
- package/assets/.appweaver/stack-profiles/sveltekit.json +26 -0
- package/assets/.appweaver/stack-profiles/vue-vite.json +26 -0
- package/assets/.appweaver/templates/constitution-domain-template.md +17 -2
- package/assets/.appweaver/templates/ui-model-template.md +67 -0
- package/assets/.appweaver/templates/workflow-model-template.md +62 -0
- package/assets/guardrails/projects/dotnet-default-project/domain-rule-bindings.md +10 -6
- package/assets/guardrails/projects/dotnet-default-project/tech-rule-bindings.md +4 -0
- package/assets/guardrails/technology/dotnet-webapi/auditing.md +3 -1
- package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +5 -3
- package/assets/guardrails/technology/dotnet-webapi/cqrs.md +5 -1
- package/assets/guardrails/technology/dotnet-webapi/domain-driven-design.md +13 -5
- package/assets/guardrails/technology/dotnet-webapi/examples/cqrs.md +2 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/domain-driven-design.md +6 -2
- package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +114 -0
- package/assets/guardrails/technology/dotnet-webapi/technology-constitution.md +3 -0
- package/assets/guardrails/technology/dotnet-webapi/testing.md +10 -0
- package/assets/guardrails/technology/nextjs/ui-constitution.md +8 -1
- package/package.json +1 -1
- package/assets/.appweaver/orchestrator/.state/smoke.state.json +0 -32
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
# and that is the act a change in flight forbids — the delta docs are the authoritative
|
|
31
31
|
# edit and the masters must not drift out from under them before finalize-delta merges.
|
|
32
32
|
# MASTER mode (no change open) — the full gate: check, ask, repair, and STOP on gaps
|
|
33
|
-
#
|
|
33
|
+
# a plan rewrite could have closed but did not. spec.md + the lane plans
|
|
34
|
+
# are the masters.
|
|
34
35
|
# REPORT mode (a change is open) — the same checks, read-only: no ask, no repair, no
|
|
35
36
|
# stop. It writes plan-analyze-report.md and routes on. The plans are
|
|
36
37
|
# DERIVED from spec.md + domain-model.md, so after finalize-delta merged a
|
|
@@ -40,6 +41,18 @@
|
|
|
40
41
|
# to be stale, and a stage that refuses to look is not a gate. It reports; it never writes
|
|
41
42
|
# a plan.
|
|
42
43
|
#
|
|
44
|
+
# TWO KINDS OF GAP, SPLIT BY WHO CAN CLOSE THEM (plan-gaps). A PLAN gap is closed by
|
|
45
|
+
# rewriting a lane plan, which this stage may do. A ROUTED gap can only be closed in
|
|
46
|
+
# spec.md or domain-model.md, which this stage may not write: a LIFT-FAILURE (a domain
|
|
47
|
+
# constraint the spec never lifted), structure the model does not define, behaviour the
|
|
48
|
+
# spec does not describe. Only plan gaps drive the repair loop and the stop; routed gaps
|
|
49
|
+
# are reported and handed to /appweaver specify. Stopping on them would stop every feature
|
|
50
|
+
# whose spec missed a constraint, with no repair this stage could ever make.
|
|
51
|
+
#
|
|
52
|
+
# EVERY MASTER RUN LEAVES A RECEIPT (.aw-plan-gate.json), green or not: the bytes it
|
|
53
|
+
# checked and the verdict — conformant, routed-gaps or gaps. implement reads it and
|
|
54
|
+
# refuses moved bytes or `gaps`, and warns on `routed-gaps`.
|
|
55
|
+
#
|
|
43
56
|
# WHICH MODE IS READ FROM THE DIRECTORY, AND DEFAULTS TO REPORT. changes/<id>/ is the
|
|
44
57
|
# evidence (cr-list), not active_version.json's `active_change` — the ledger is the most
|
|
45
58
|
# recently OPENED change and a crashed run can leave the two disagreeing. The permission to
|
|
@@ -60,7 +73,7 @@
|
|
|
60
73
|
|
|
61
74
|
name: aw-spec-analyze-plan
|
|
62
75
|
description: The spec↔plan conformance gate for every declared lane — confirm backend-plan.md and frontend-plan.md follow spec.md, that they bind to each other's contract, 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. Runs in one of two modes, decided from the changes/ directory rather than the ledger and defaulting to the read-only one — MASTER (no change open) checks, repairs on approval and stops on unreconciled gaps; REPORT (a change open) runs the same checks read-only and writes plan-analyze-report.md without asking, repairing or stopping, because the master plans may not be rewritten while a delta is in flight. It never opens, merges or closes a change.
|
|
63
|
-
version: 3.
|
|
76
|
+
version: 3.3.0
|
|
64
77
|
agent_agnostic: true
|
|
65
78
|
dialect: aw-spec.orchestrator/v1
|
|
66
79
|
|
|
@@ -68,6 +81,9 @@ scripts:
|
|
|
68
81
|
actions:
|
|
69
82
|
sh: .appweaver/scripts/bash/aw-spec-actions.sh
|
|
70
83
|
ps1: .appweaver/scripts/powershell/aw-spec-actions.ps1
|
|
84
|
+
xref:
|
|
85
|
+
sh: .appweaver/scripts/bash/aw-xref.sh
|
|
86
|
+
ps1: .appweaver/scripts/powershell/aw-xref.ps1
|
|
71
87
|
|
|
72
88
|
standards:
|
|
73
89
|
- { path: .appweaver/ai-rules.md } # kit-resident: the universal operating rules, every flow
|
|
@@ -87,8 +103,16 @@ vars:
|
|
|
87
103
|
no_open_change: "false" # RAISED only by cr-list answering that nothing is open
|
|
88
104
|
gate_mode: "report" # report | master — reported in the outputs
|
|
89
105
|
may_repair: "false" # the ask, the repair loop and the conformance stop are MASTER-only
|
|
90
|
-
gate_ok: "false" # raised by a
|
|
91
|
-
stamp_receipt: "false" # master mode
|
|
106
|
+
gate_ok: "false" # raised by a run with no plan gap left OR by report mode, which cannot repair
|
|
107
|
+
stamp_receipt: "false" # master mode ⇒ leave the receipt implement reads, whatever the verdict
|
|
108
|
+
repairs_left: "true" # lowered on the loop's final pass, which checks and never rewrites
|
|
109
|
+
# THE GAP SPLIT, from plan-gaps after each analyze pass. Defaulted to the refusing
|
|
110
|
+
# answer, so a classification that never arrived neither ends the loop nor passes.
|
|
111
|
+
plan_ok: "false" # no gap left that a plan rewrite closes
|
|
112
|
+
gate_verdict: "gaps" # conformant | routed-gaps | gaps
|
|
113
|
+
plan_gap_count: "0"
|
|
114
|
+
routed_gaps: "[]" # the gaps only /appweaver specify can close
|
|
115
|
+
routed_csv: ""
|
|
92
116
|
receipt_file: ""
|
|
93
117
|
receipt_gated: ""
|
|
94
118
|
receipt_count: "0"
|
|
@@ -358,19 +382,30 @@ workflow:
|
|
|
358
382
|
- { path: "{{be_plan_ctx}}", optional: true }
|
|
359
383
|
- { path: "{{fe_plan_ctx}}", optional: true }
|
|
360
384
|
|
|
361
|
-
# 5. Conformance + REPAIR loop (spec is the anchor): check →
|
|
362
|
-
# Repair on approval → re-check; "Report and Skip" writes plan-analyze-report.md
|
|
363
|
-
# and stops.
|
|
364
|
-
#
|
|
385
|
+
# 5. Conformance + REPAIR loop (spec is the anchor): check → split the gaps → REPORT +
|
|
386
|
+
# ASK → Repair on approval → re-check; "Report and Skip" writes plan-analyze-report.md
|
|
387
|
+
# and stops. The loop runs while a PLAN gap is open: once only routed gaps remain
|
|
388
|
+
# there is nothing a repair can change. The repair is PER LANE, so a frontend drift
|
|
389
|
+
# never rewrites a conformant backend plan.
|
|
390
|
+
#
|
|
391
|
+
# THREE REPAIRS, FOUR PASSES — the last pass checks and never rewrites. With the two
|
|
392
|
+
# equal, the third repair was the last thing to run: no pass ever saw its result, so a
|
|
393
|
+
# run that converged on it still reported `gaps` and told the operator it had not
|
|
394
|
+
# converged. Worse, plan_ok / gate_verdict / plan_gap_count then described the plans as
|
|
395
|
+
# they were BEFORE that repair, while plan-gate-stamp below hashed the files as they
|
|
396
|
+
# are AFTER it — a receipt pairing post-repair bytes with a pre-repair verdict, which
|
|
397
|
+
# plan-gate-check would later read as fresh. The extra pass costs one analyze in the
|
|
398
|
+
# case that used to end ambiguously, and it makes the last thing to touch the plans
|
|
399
|
+
# always earlier than the last thing to judge them, on every exit path.
|
|
365
400
|
- id: analyze_loop
|
|
366
401
|
action: loop
|
|
367
|
-
while: "{{
|
|
368
|
-
max_iterations:
|
|
402
|
+
while: "{{plan_ok}} != true"
|
|
403
|
+
max_iterations: 4
|
|
369
404
|
steps:
|
|
370
405
|
- id: analyze
|
|
371
406
|
action: agent_query
|
|
372
407
|
include_standards: true # the gate overlays (checklist) are in the standards
|
|
373
|
-
schema: { ok: true, backend_repair: false, frontend_repair: false, gaps: [ { severity: "high", check: "<spec-backend|spec-frontend|contract|model|overlay>", lane: "<backend|frontend>", spec_ref: "<FR/BR/CN/DC/IC/UX/US/SC or overlay or —>", where: "<plan section>", gap: "<how it drifts>" } ] }
|
|
408
|
+
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>" } ] }
|
|
374
409
|
mock: { ok: true, backend_repair: false, frontend_repair: false, gaps: [] }
|
|
375
410
|
task: |
|
|
376
411
|
spec.md is the ANCHOR. Gate this feature's LANE PLANS against it and against the
|
|
@@ -444,15 +479,37 @@ workflow:
|
|
|
444
479
|
/appweaver specify, not the plan — do not fabricate it here).
|
|
445
480
|
|
|
446
481
|
Tag every gap with its `check` and the `lane` whose document must change to close
|
|
447
|
-
it
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
482
|
+
it, and with its `route` — who can close it:
|
|
483
|
+
- route `specify` when ONLY spec.md or domain-model.md can close it: every
|
|
484
|
+
LIFT-FAILURE; a plan element needing an aggregate, entity, event or invariant
|
|
485
|
+
the model does not define; a state or behaviour the plan needs that the spec
|
|
486
|
+
does not describe and no DA-n records.
|
|
487
|
+
- route `plan` for everything a rewrite of a lane plan closes: a missing plan
|
|
488
|
+
home, a name that differs from the model's, an invariant restated instead of
|
|
489
|
+
cited, a contract binding, an element with no spec basis.
|
|
490
|
+
Set backend_repair true if any `plan`-route gap needs the backend plan rewritten,
|
|
491
|
+
and frontend_repair likewise. (If a plan is still the empty template, treat the
|
|
492
|
+
WHOLE spec as gaps against it.) Set ok=true ONLY when every applicable check
|
|
493
|
+
passes and no checklist constraint is unaccounted for.
|
|
451
494
|
outputs:
|
|
452
495
|
- { name: analyze_ok, from: "$.ok" }
|
|
453
496
|
- { name: analyze_gaps, from: "$.gaps" }
|
|
454
497
|
- { name: backend_repair, from: "$.backend_repair" }
|
|
455
498
|
- { name: frontend_repair, from: "$.frontend_repair" }
|
|
499
|
+
|
|
500
|
+
# WHO CAN CLOSE EACH GAP, decided by script from the tags above: a LIFT-FAILURE is
|
|
501
|
+
# routed to specify whatever its tag says, and an untagged gap is a plan gap.
|
|
502
|
+
- id: classify_gaps
|
|
503
|
+
action: execute_script
|
|
504
|
+
script: { ref: actions }
|
|
505
|
+
subcommand: plan-gaps
|
|
506
|
+
args: ["--gaps", "{{analyze_gaps}}"]
|
|
507
|
+
outputs:
|
|
508
|
+
- { name: plan_ok, from: "$.plan_ok" }
|
|
509
|
+
- { name: gate_verdict, from: "$.verdict" }
|
|
510
|
+
- { name: plan_gap_count, from: "$.plan_gaps" }
|
|
511
|
+
- { name: routed_gaps, from: "$.routed" }
|
|
512
|
+
- { name: routed_csv, from: "$.routed_csv" }
|
|
456
513
|
- id: conform_break
|
|
457
514
|
action: break
|
|
458
515
|
condition: "{{analyze_ok}} == true"
|
|
@@ -495,12 +552,32 @@ workflow:
|
|
|
495
552
|
action: break
|
|
496
553
|
condition: "{{may_repair}} == false"
|
|
497
554
|
|
|
555
|
+
# Only routed gaps left: no repair can change them, so do not ask for one.
|
|
556
|
+
- id: routed_only_break
|
|
557
|
+
action: break
|
|
558
|
+
condition: "{{plan_ok}} == true"
|
|
559
|
+
|
|
560
|
+
# THE LAST PASS CONFIRMS THE LAST REPAIR AND DOES NOT ADD ONE. Raised for every pass
|
|
561
|
+
# and lowered on the final one, so the ask below and both lane rewrites are skipped
|
|
562
|
+
# there while the analyze above still runs and still sets the verdict.
|
|
563
|
+
- id: repairs_left_yes
|
|
564
|
+
action: set
|
|
565
|
+
vars: { repairs_left: "true" }
|
|
566
|
+
- id: repairs_left_no
|
|
567
|
+
condition: "{{iteration}} == 3"
|
|
568
|
+
action: set
|
|
569
|
+
vars: { repairs_left: "false" }
|
|
570
|
+
|
|
498
571
|
- id: ask_repair
|
|
572
|
+
condition: "{{repairs_left}} == true"
|
|
499
573
|
action: ask
|
|
500
574
|
prompt: |
|
|
501
575
|
analyze-plan found spec↔plan gaps (spec.md is the anchor; domain-model.md is
|
|
502
576
|
read-only here):
|
|
503
577
|
{{analyze_gaps}}
|
|
578
|
+
{{plan_gap_count}} gap(s) have route `plan` — a repair rewrites the plan to close
|
|
579
|
+
them. Gaps with route `specify` are not repaired here; they are reported and
|
|
580
|
+
belong to /appweaver specify.
|
|
504
581
|
Repair the drifting plan(s) to conform now, or report the gaps and stop?
|
|
505
582
|
options: ["Repair", "Report and Skip"]
|
|
506
583
|
answer_var: repair_choice
|
|
@@ -528,9 +605,11 @@ workflow:
|
|
|
528
605
|
condition: "{{repair_choice}} == Report and Skip"
|
|
529
606
|
|
|
530
607
|
# WHICH DOCUMENT GETS REWRITTEN. A repair runs only where the analyze pass reported
|
|
531
|
-
# drift in that lane AND that lane is present
|
|
532
|
-
#
|
|
533
|
-
#
|
|
608
|
+
# drift in that lane AND that lane is present AND this pass still carries a repair —
|
|
609
|
+
# three ordered assignments per lane, because the dialect takes no compound
|
|
610
|
+
# condition. Cleared first so a lane that was repaired on the previous iteration and
|
|
611
|
+
# is clean on this one is not rewritten again, and cleared last on the final pass,
|
|
612
|
+
# which exists to check the previous repair rather than to add another.
|
|
534
613
|
- id: be_repair_clear
|
|
535
614
|
action: set
|
|
536
615
|
vars: { be_repair: "false" }
|
|
@@ -538,6 +617,10 @@ workflow:
|
|
|
538
617
|
condition: "{{backend_repair}} == true"
|
|
539
618
|
action: set
|
|
540
619
|
vars: { be_repair: "{{be_present}}" }
|
|
620
|
+
- id: be_repair_last_pass
|
|
621
|
+
condition: "{{repairs_left}} == false"
|
|
622
|
+
action: set
|
|
623
|
+
vars: { be_repair: "false" }
|
|
541
624
|
- id: fe_repair_clear
|
|
542
625
|
action: set
|
|
543
626
|
vars: { fe_repair: "false" }
|
|
@@ -545,6 +628,10 @@ workflow:
|
|
|
545
628
|
condition: "{{frontend_repair}} == true"
|
|
546
629
|
action: set
|
|
547
630
|
vars: { fe_repair: "{{fe_present}}" }
|
|
631
|
+
- id: fe_repair_last_pass
|
|
632
|
+
condition: "{{repairs_left}} == false"
|
|
633
|
+
action: set
|
|
634
|
+
vars: { fe_repair: "false" }
|
|
548
635
|
|
|
549
636
|
- id: repair_backend
|
|
550
637
|
condition: "{{be_repair}} == true"
|
|
@@ -553,7 +640,8 @@ workflow:
|
|
|
553
640
|
output_target: { type: file, path: "{{backend_plan}}" }
|
|
554
641
|
task: |
|
|
555
642
|
spec.md is the ANCHOR — update backend-plan.md (in context) to CONFORM to it,
|
|
556
|
-
closing the gaps whose lane is `backend` (the spec WINS
|
|
643
|
+
closing the gaps whose lane is `backend` and whose route is `plan` (the spec WINS
|
|
644
|
+
every time). Leave `specify`-route gaps as the DA-n notes described below:
|
|
557
645
|
{{analyze_gaps}}
|
|
558
646
|
- Add a plan home for each uncovered spec FR/BR/CN/DC/IC/US/SC (a lifted
|
|
559
647
|
CN-/DC-/IC- lands in a §1 domain invariant enforcement · the persistence
|
|
@@ -591,7 +679,9 @@ workflow:
|
|
|
591
679
|
output_target: { type: file, path: "{{frontend_plan}}" }
|
|
592
680
|
task: |
|
|
593
681
|
spec.md is the ANCHOR — update frontend-plan.md (in context) to CONFORM to it,
|
|
594
|
-
closing the gaps whose lane is `frontend` (the spec WINS
|
|
682
|
+
closing the gaps whose lane is `frontend` and whose route is `plan` (the spec WINS
|
|
683
|
+
every time). Leave each `specify`-route gap open, logged as a DA-n that routes to
|
|
684
|
+
/appweaver specify:
|
|
595
685
|
{{analyze_gaps}}
|
|
596
686
|
- Give every uncovered Experience Standard (UX-), user story and
|
|
597
687
|
interaction-state FR- a home: a screen in the navigation section, a flow row,
|
|
@@ -618,52 +708,51 @@ workflow:
|
|
|
618
708
|
already-conformant section VERBATIM.
|
|
619
709
|
Return the COMPLETE updated frontend-plan.md content only.
|
|
620
710
|
|
|
621
|
-
# THE STOP IS MASTER MODE'S ALONE. Two independent raises, because the two reasons to
|
|
622
|
-
# pass are unrelated: the plans conform, or this run was never allowed to change them.
|
|
623
|
-
# A read-only run that found gaps has done its whole job by reporting them — stopping
|
|
624
|
-
# would fail the operator for drift that finalize-delta created on purpose and that only
|
|
625
|
-
# /appweaver plan main can close.
|
|
626
|
-
- id: gate_ok_conformant
|
|
627
|
-
condition: "{{analyze_ok}} == true"
|
|
628
|
-
action: set
|
|
629
|
-
vars: { gate_ok: "true" }
|
|
630
|
-
- id: gate_ok_readonly
|
|
631
|
-
condition: "{{may_repair}} == false"
|
|
632
|
-
action: set
|
|
633
|
-
vars: { gate_ok: "true" }
|
|
634
|
-
|
|
635
|
-
- id: analyze_gate
|
|
636
|
-
action: verify_context
|
|
637
|
-
require_true: gate_ok
|
|
638
|
-
on_false: stop
|
|
639
|
-
on_false_message: "The lane plans do not conform to the spec (gaps: {{analyze_gaps}}) — repair was skipped (see plan-analyze-report.md), or it could not be reconciled in 3 passes. A 'LIFT-FAILURE:' gap means a domain constraint from the gate checklist was never lifted into the spec, and a `model` gap means the plan needs an entity or invariant domain-model.md does not define — both are fixed by /appweaver specify, which authors the spec and the model; this gate may not write either. A `contract` gap is closed in the lane its row names. Otherwise fix out of band, or re-run and choose Repair."
|
|
640
|
-
|
|
641
711
|
# THE RECEIPT. implement generates from the plans and deliberately does not read the
|
|
642
|
-
# spec, on the strength of this stage having
|
|
643
|
-
#
|
|
644
|
-
#
|
|
645
|
-
# that was present. plan-gate-check reads it at implement.
|
|
712
|
+
# spec, on the strength of this stage having checked them against it. Record WHAT was
|
|
713
|
+
# checked — the bytes of spec.md, the context's domain-model.md and each lane plan that
|
|
714
|
+
# was present — and the VERDICT on them. plan-gate-check reads it at implement.
|
|
646
715
|
#
|
|
647
|
-
#
|
|
648
|
-
#
|
|
649
|
-
#
|
|
650
|
-
# even repair them), and a red master run proved the opposite.
|
|
716
|
+
# EVERY MASTER RUN LEAVES ONE, and it is written BEFORE the stop below, so a red run
|
|
717
|
+
# records its `gaps` verdict too and implement refuses it. A REPORT-mode run leaves
|
|
718
|
+
# none: it checked the masters while a delta was in flight, and they are about to move.
|
|
651
719
|
- id: flag_receipt
|
|
652
720
|
condition: "{{may_repair}} == true"
|
|
653
721
|
action: set
|
|
654
|
-
vars: { stamp_receipt: "
|
|
722
|
+
vars: { stamp_receipt: "true" }
|
|
655
723
|
|
|
656
724
|
- id: plan_gate_stamp
|
|
657
725
|
condition: "{{stamp_receipt}} == true"
|
|
658
726
|
action: execute_script
|
|
659
727
|
script: { ref: actions }
|
|
660
728
|
subcommand: plan-gate-stamp
|
|
661
|
-
args: ["--feature-dir", "{{feature_dir}}", "--spec-version", "{{version}}", "--mode", "{{gate_mode}}"]
|
|
729
|
+
args: ["--feature-dir", "{{feature_dir}}", "--spec-version", "{{version}}", "--mode", "{{gate_mode}}", "--verdict", "{{gate_verdict}}", "--plan-gaps", "{{plan_gap_count}}", "--routed", "{{routed_gaps}}"]
|
|
662
730
|
outputs:
|
|
663
731
|
- { name: receipt_file, from: "$.file" }
|
|
664
732
|
- { name: receipt_gated, from: "$.gated" }
|
|
665
733
|
- { name: receipt_count, from: "$.count" }
|
|
666
734
|
|
|
735
|
+
# THE STOP IS MASTER MODE'S ALONE, and only a PLAN gap triggers it. Two independent
|
|
736
|
+
# raises, because the two reasons to pass are unrelated: no gap is left that a plan
|
|
737
|
+
# rewrite closes, or this run was never allowed to rewrite. A read-only run that found
|
|
738
|
+
# gaps has done its whole job by reporting them — stopping would fail the operator for
|
|
739
|
+
# drift that finalize-delta created on purpose and that only /appweaver plan main can
|
|
740
|
+
# close. Routed gaps pass here and are listed in the outputs for /appweaver specify.
|
|
741
|
+
- id: gate_ok_conformant
|
|
742
|
+
condition: "{{plan_ok}} == true"
|
|
743
|
+
action: set
|
|
744
|
+
vars: { gate_ok: "true" }
|
|
745
|
+
- id: gate_ok_readonly
|
|
746
|
+
condition: "{{may_repair}} == false"
|
|
747
|
+
action: set
|
|
748
|
+
vars: { gate_ok: "true" }
|
|
749
|
+
|
|
750
|
+
- id: analyze_gate
|
|
751
|
+
action: verify_context
|
|
752
|
+
require_true: gate_ok
|
|
753
|
+
on_false: stop
|
|
754
|
+
on_false_message: "The lane plans do not conform to the spec: {{plan_gap_count}} gap(s) a plan rewrite closes are still open (all gaps: {{analyze_gaps}}). Either you chose `Report and Skip`, in which case plan-analyze-report.md beside the plans lists them — or repair ran up to three times and the fourth pass, which checks and does not rewrite, still found these. Every gap above was read off the plans as they stand on disk now. The receipt records verdict `gaps`, so /appweaver implement will refuse until this gate is re-run clean. A `contract` gap is closed in the lane its row names. Gaps routed to `specify` ({{routed_csv}}) are not what stopped this run: they need /appweaver specify, which authors the spec and the model. Fix out of band, or re-run and choose Repair."
|
|
755
|
+
|
|
667
756
|
# (No change-close here by design — this stage never archives anything in either mode,
|
|
668
757
|
# and cr-archive belongs to close-delta, which runs after finalize-delta's merge.)
|
|
669
758
|
|
|
@@ -687,10 +776,13 @@ outputs:
|
|
|
687
776
|
domain_model: "{{domain_model}}"
|
|
688
777
|
conformant: "{{analyze_ok}}"
|
|
689
778
|
gaps: "{{analyze_gaps}}"
|
|
779
|
+
verdict: "{{gate_verdict}}" # conformant | routed-gaps | gaps
|
|
780
|
+
plan_gaps: "{{plan_gap_count}}" # open gaps a plan rewrite closes
|
|
781
|
+
routed_to_specify: "{{routed_csv}}" # open gaps only /appweaver specify can close
|
|
690
782
|
version: "{{version}}"
|
|
691
783
|
gate_mode: "{{gate_mode}}" # master (repair allowed) | report (read-only)
|
|
692
784
|
open_changes: "{{open_ids}}" # empty in master mode, by definition
|
|
693
|
-
gate_receipt: "{{receipt_file}}" # written
|
|
785
|
+
gate_receipt: "{{receipt_file}}" # written by every master run, with its verdict; implement reads it
|
|
694
786
|
gate_receipt_at: "{{receipt_gated}}"
|
|
695
787
|
note: "Ran in {{gate_mode}} mode ({{open_count}} change(s) open: {{open_ids}}). Checked: spec→backend-plan ({{be_present}}), spec→frontend-plan ({{fe_present}}), the plan↔plan contract binding ({{both_lanes}} — it needs both lanes) and both plans against domain-model.md. The domain model was READ, never written: a gap that needs a new entity, event or invariant is fixed by /appweaver specify. In REPORT mode no plan was rewritten either — the master plans are derived documents and may not move while a delta is in flight."
|
|
696
|
-
next: "MASTER mode (no change open,
|
|
788
|
+
next: "MASTER mode (no change open, 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 (change(s) {{open_ids}} open): this run was read-only and 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 two, 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."
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
# =============================================================================
|
|
71
71
|
|
|
72
72
|
name: aw-spec-analyze-slice-delta
|
|
73
|
-
version: 1.
|
|
73
|
+
version: 1.2.0
|
|
74
74
|
description: "The delta-spec↔delta-code gate — verify that the open change DOES WHAT IT WAS ASKED TO DO, before it reaches the master documents. delta-spec.md is the anchor, exactly as it is for analyze-plan-delta. Asks which open change it is gating, runs the slice's tests (the first execution on the change path, since build only compiles), then evaluates the code and its paired tests against the change's REQUIREMENTS — every ADDED or MODIFIED delta-spec item realised in code, every one covered by a test that cites its id, every invariant the model delta adds actually enforced — with the delta plan in context as the map from requirement to code and cross-checked in its own right, so an element the plan promised and nobody built is caught too. The dynamic twin of analyze-plan-delta and the delta twin of analyze-slice, which cannot see a missing implementation because a behaviour that was never built leaves no failing test. Verify-only — it reports each finding with the command that closes it and stops; it generates no code and repairs nothing."
|
|
75
75
|
agent_agnostic: true
|
|
76
76
|
dialect: aw-spec.orchestrator/v1
|
|
@@ -124,11 +124,24 @@ vars:
|
|
|
124
124
|
test_ok: "false"
|
|
125
125
|
test_tool: ""
|
|
126
126
|
test_log: ""
|
|
127
|
+
test_excerpt: ""
|
|
127
128
|
test_scoped: "false"
|
|
128
129
|
test_ran: "false"
|
|
129
130
|
test_matched: "false"
|
|
130
131
|
# Verdict.
|
|
131
132
|
requirements_ok: "false"
|
|
133
|
+
# Findings split by the command that closes them (gap-route). Defaults read as
|
|
134
|
+
# "nothing found", so a run where the router could not execute still prints.
|
|
135
|
+
gap_summary: "no findings"
|
|
136
|
+
gap_total: "0"
|
|
137
|
+
fix_code: "none"
|
|
138
|
+
fix_code_n: "0"
|
|
139
|
+
fix_plan: "none"
|
|
140
|
+
fix_plan_n: "0"
|
|
141
|
+
fix_spec: "none"
|
|
142
|
+
fix_spec_n: "0"
|
|
143
|
+
fix_review: "none"
|
|
144
|
+
fix_review_n: "0"
|
|
132
145
|
gate_ok: "false"
|
|
133
146
|
|
|
134
147
|
workflow:
|
|
@@ -155,9 +168,11 @@ workflow:
|
|
|
155
168
|
- { name: be_declared, from: "$.backend_declared" }
|
|
156
169
|
- { name: be_lane_id, from: "$.backend_lane_id" }
|
|
157
170
|
- { name: be_source_path, from: "$.backend_source_path" }
|
|
171
|
+
- { name: be_test_path, from: "$.backend_test_path" }
|
|
158
172
|
- { name: fe_declared, from: "$.frontend_declared" }
|
|
159
173
|
- { name: fe_lane_id, from: "$.frontend_lane_id" }
|
|
160
174
|
- { name: fe_source_path, from: "$.frontend_source_path" }
|
|
175
|
+
- { name: fe_test_path, from: "$.frontend_test_path" }
|
|
161
176
|
|
|
162
177
|
- id: require_lane
|
|
163
178
|
action: verify_context
|
|
@@ -316,6 +331,7 @@ workflow:
|
|
|
316
331
|
- { name: test_ok, from: "$.fence_green" }
|
|
317
332
|
- { name: test_tool, from: "$.tool" }
|
|
318
333
|
- { name: test_log, from: "$.log_tail" }
|
|
334
|
+
- { name: test_excerpt, from: "$.failing_excerpt" } # the lines that NAME the failure
|
|
319
335
|
- { name: test_scoped, from: "$.scoped" }
|
|
320
336
|
# A GREEN FENCE IS NOT ALWAYS AN EXECUTED SUITE. test-run reports fence_green true
|
|
321
337
|
# with ran=false on a project whose lanes declare no test command — the vacuous pass
|
|
@@ -414,9 +430,11 @@ workflow:
|
|
|
414
430
|
the pre-existing slice.
|
|
415
431
|
|
|
416
432
|
CHECK 7 — PLACEMENT. Every file this change added or edited sits under the lane that
|
|
417
|
-
owns it: this lane's source path
|
|
418
|
-
|
|
419
|
-
`placement` gap.
|
|
433
|
+
owns it: this lane's production code under its source path `{{be_source_path}}`, its
|
|
434
|
+
tests under its test path `{{be_test_path}}`. A service-lane element written into the
|
|
435
|
+
frontend lane's subtree — or outside every lane's paths — is a HIGH `placement` gap.
|
|
436
|
+
One edit outside them is allowed: registering a test project this change created in
|
|
437
|
+
the file the lane's test command discovers tests through (e.g. a .NET solution file).
|
|
420
438
|
|
|
421
439
|
PLAN-ONLY CHANGE — if the delta-spec is an unfilled stub, this change deliberately
|
|
422
440
|
alters only HOW the EXISTING spec is realised (a refactor, an architectural decision).
|
|
@@ -506,9 +524,11 @@ workflow:
|
|
|
506
524
|
gap. Judge it only over what this change touched.
|
|
507
525
|
|
|
508
526
|
CHECK 7 — PLACEMENT. Every file this change added or edited sits under this lane's
|
|
509
|
-
source path, `{{fe_source_path}}
|
|
510
|
-
HIGH `placement` gap — a gap in the
|
|
511
|
-
that lane, never a client-side edit
|
|
527
|
+
source path, `{{fe_source_path}}`, or — for a test — its test path, `{{fe_test_path}}`.
|
|
528
|
+
A file written into the service lane's subtree is a HIGH `placement` gap — a gap in the
|
|
529
|
+
service surface is a contract delta raised back to that lane, never a client-side edit
|
|
530
|
+
to it. The one edit allowed outside them is the test setup this change had to create,
|
|
531
|
+
when the lane's test command discovers tests through a file elsewhere.
|
|
512
532
|
|
|
513
533
|
PLAN-ONLY CHANGE — if the delta-spec is an unfilled stub, this change alters only HOW
|
|
514
534
|
the existing spec is realised. Checks 1 to 3 have no anchor and are SKIPPED, not
|
|
@@ -539,6 +559,30 @@ workflow:
|
|
|
539
559
|
action: set
|
|
540
560
|
vars: { requirements_ok: "false" }
|
|
541
561
|
|
|
562
|
+
# WHO CAN CLOSE WHAT. Both lanes' findings carry a `fix` tag already; this turns the tag
|
|
563
|
+
# into routing. It matters most for a `plan` finding: the delta plan is what is wrong, and
|
|
564
|
+
# `implement` generates FROM that plan, so sending it there reproduces the defect — which
|
|
565
|
+
# is what left the mock run's ChiefComplaintField gap closable only by hand-editing a
|
|
566
|
+
# generated plan. Deterministic, and it never drops a finding: one with no recognised
|
|
567
|
+
# `fix` is routed to `review` and counted, rather than folded into the largest bucket.
|
|
568
|
+
- id: route_gaps
|
|
569
|
+
action: execute_script
|
|
570
|
+
on_error: continue
|
|
571
|
+
script: { ref: actions }
|
|
572
|
+
subcommand: gap-route
|
|
573
|
+
args: ["--cr", "{{cr_id}}", "--gaps", "{{be_gaps}}", "--gaps", "{{fe_gaps}}"]
|
|
574
|
+
outputs:
|
|
575
|
+
- { name: gap_summary, from: "$.summary" }
|
|
576
|
+
- { name: gap_total, from: "$.total" }
|
|
577
|
+
- { name: fix_code, from: "$.implement_text" }
|
|
578
|
+
- { name: fix_code_n, from: "$.implement_count" }
|
|
579
|
+
- { name: fix_plan, from: "$.plan_text" }
|
|
580
|
+
- { name: fix_plan_n, from: "$.plan_count" }
|
|
581
|
+
- { name: fix_spec, from: "$.specify_text" }
|
|
582
|
+
- { name: fix_spec_n, from: "$.specify_count" }
|
|
583
|
+
- { name: fix_review, from: "$.review_text" }
|
|
584
|
+
- { name: fix_review_n, from: "$.review_count" }
|
|
585
|
+
|
|
542
586
|
# gate_ok = the tests ran green AND every gated lane's requirements are met.
|
|
543
587
|
- id: gate_flag
|
|
544
588
|
condition: "{{test_ok}} == true"
|
|
@@ -568,8 +612,8 @@ workflow:
|
|
|
568
612
|
merges the change into spec.md and domain-model.md.
|
|
569
613
|
Evidence:
|
|
570
614
|
- tests: green={{test_ok}}, tool `{{test_tool}}`, actually ran={{test_ran}},
|
|
571
|
-
matched a slice filter={{test_matched}}, slice-scoped={{test_scoped}}.
|
|
572
|
-
{{test_log}}
|
|
615
|
+
matched a slice filter={{test_matched}}, slice-scoped={{test_scoped}}. Failing
|
|
616
|
+
lines: {{test_excerpt}} · Log tail: {{test_log}}
|
|
573
617
|
- service lane gated={{be_gated}}, verdict ok={{be_ok}}, gaps: {{be_gaps}}
|
|
574
618
|
- experience lane gated={{fe_gated}}, verdict ok={{fe_ok}}, gaps: {{fe_gaps}}
|
|
575
619
|
Markdown format:
|
|
@@ -608,7 +652,31 @@ workflow:
|
|
|
608
652
|
action: verify_context
|
|
609
653
|
require_true: gate_ok
|
|
610
654
|
on_false: stop
|
|
611
|
-
on_false_message:
|
|
655
|
+
on_false_message: >
|
|
656
|
+
Change {{cr_id}} does NOT yet meet its delta spec. Tests green={{test_ok}} (tool
|
|
657
|
+
`{{test_tool}}`); service lane gated={{be_gated}} ok={{be_ok}}; experience lane
|
|
658
|
+
gated={{fe_gated}} ok={{fe_ok}}. {{gap_summary}}
|
|
659
|
+
|
|
660
|
+
EACH FINDING IS CLOSED BY A DIFFERENT COMMAND — they are not interchangeable, and a
|
|
661
|
+
plan defect sent to implement comes back unchanged, because implement generates FROM
|
|
662
|
+
the plan.
|
|
663
|
+
|
|
664
|
+
SPEC / MODEL ({{fix_spec_n}}): {{fix_spec}}
|
|
665
|
+
|
|
666
|
+
DELTA PLAN ({{fix_plan_n}}): {{fix_plan}}
|
|
667
|
+
|
|
668
|
+
CODE ({{fix_code_n}}): {{fix_code}}
|
|
669
|
+
|
|
670
|
+
UNROUTED ({{fix_review_n}}): {{fix_review}}
|
|
671
|
+
|
|
672
|
+
Work them in that order — the spec before the plan that realises it, the plan before
|
|
673
|
+
the code that maps to it. Re-running /appweaver plan {{cr_id}} re-derives the delta
|
|
674
|
+
plans with this report in context, so a plan finding is fixed by re-deriving rather
|
|
675
|
+
than by hand-editing a generated document. The full report is at
|
|
676
|
+
{{cr_dir}}/delta-slice-analyze-report.md. DO NOT run finalize-delta yet: merging now
|
|
677
|
+
would write requirements into spec.md and domain-model.md that the code does not
|
|
678
|
+
satisfy, and the masters would describe an intention rather than the system. Then
|
|
679
|
+
re-run build and re-run this gate.
|
|
612
680
|
|
|
613
681
|
# 6. Post-execution hooks.
|
|
614
682
|
- id: resolve_post_hooks
|