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
|
@@ -47,9 +47,10 @@
|
|
|
47
47
|
# about the order the operator ran things in: the lane gates test that the plan FILE EXISTS
|
|
48
48
|
# and nothing more, so `plan` → edit spec.md → `implement` generated at full length from a
|
|
49
49
|
# plan nobody had held against the spec it now contradicts. analyze-plan leaves a receipt of
|
|
50
|
-
# the bytes it
|
|
51
|
-
# lane generates. A feature with no receipt has simply never been gated
|
|
52
|
-
# existed — reported, never refused. One
|
|
50
|
+
# the bytes it checked and its verdict, and plan-gate-check reads it here, on the bootstrap
|
|
51
|
+
# path, before any lane generates. A feature with no receipt has simply never been gated
|
|
52
|
+
# since the receipt existed — reported, never refused. One whose receipt no longer matches,
|
|
53
|
+
# or whose verdict left plan gaps, stops; one whose verdict left only spec/model gaps warns.
|
|
53
54
|
# 3.2.0 — AND NOT delta-spec.md EITHER. The change path used to inline it "only so the
|
|
54
55
|
# paired tests can cite traceability ids", which made the rule true on the bootstrap path
|
|
55
56
|
# and false on the one where changes actually ship: a document in the payload is a document
|
|
@@ -86,11 +87,22 @@
|
|
|
86
87
|
# • FRONTEND — `## /aw-spec-implement-ui`, both paths. There was never a delta heading
|
|
87
88
|
# for this lane because the delta half of it was never built; it is built here.
|
|
88
89
|
#
|
|
89
|
-
#
|
|
90
|
-
#
|
|
91
|
-
#
|
|
92
|
-
#
|
|
93
|
-
#
|
|
90
|
+
# TWO PATHS PER LANE. Each lane owns the source path stacks.json declares for it and the
|
|
91
|
+
# test path lane-verify resolves beside it — `tests/` next to a .NET `src/`, the source
|
|
92
|
+
# path itself for a stack that keeps its tests inside — and writes nothing outside them.
|
|
93
|
+
# The one exception is registering a test project the lane had to create, in whatever
|
|
94
|
+
# file the lane's test command discovers tests through (a .NET solution file). A file
|
|
95
|
+
# written elsewhere belongs to the other lane or to no lane at all, and the project gate
|
|
96
|
+
# is deliberately stricter for the frontend: a manifest found only elsewhere in the
|
|
97
|
+
# repository is the service lane's, and accepting it is how a frontend that was never
|
|
98
|
+
# scaffolded is generated into anyway and reports green.
|
|
99
|
+
#
|
|
100
|
+
# A FILE LIST IS NOT A FINISHED LANE. Each generating lane is handed its plan's element
|
|
101
|
+
# list and reports every element back as done or blocked; `plan-coverage` then checks the
|
|
102
|
+
# code under the lane's source path for every identifier the plan introduces. Whatever
|
|
103
|
+
# either check leaves open gets one completion pass, and anything still open after it
|
|
104
|
+
# stops the run once both lanes have generated — so a pass that stopped at five use-cases
|
|
105
|
+
# of seven is reported, not shipped.
|
|
94
106
|
#
|
|
95
107
|
# A LANE'S GAP DISABLES THAT LANE, NOT THE RUN. Three things a lane needs are checked per
|
|
96
108
|
# lane and reported per lane: its source path is on disk, its plan is there, and a project
|
|
@@ -116,7 +128,7 @@
|
|
|
116
128
|
|
|
117
129
|
name: aw-spec-implement
|
|
118
130
|
description: "Generate the aggregate's source files and paired tests from its lane plans — the backend lane from backend-plan.md when a backend stack is declared, the frontend lane from frontend-plan.md when a frontend stack is, both when both are. One command covers backend-only, frontend-only and full-stack projects and absorbs the former implement-ui and implement-delta. Self-detecting off the changes on disk — with none open it generates from the master plans; with one or more open it ASKS which change and generates only what that change's delta plans mark ADDED or MODIFIED, leaving the masters untouched. Every lane is gated on its own source path, its own plan and its own scaffolded project, and a lane missing any of them is reported and skipped rather than failing the other lane; each runnable lane confirms before it writes. Model-driven, and it does not read the spec — analyze-plan already conformed the plans to it. The plan says WHAT to build; the bounded context's domain-model.md, in context alongside it, says what the domain IS — the entity names, the boundary and the text of every invariant the plan cites by id — joined on the delta path by that change's own model delta, since the master is not merged until finalize-delta. The stack binds here from the lane declaration and the constitution halves; the plans stay technology-agnostic."
|
|
119
|
-
version: 3.
|
|
131
|
+
version: 3.10.0
|
|
120
132
|
agent_agnostic: true
|
|
121
133
|
dialect: aw-spec.orchestrator/v1
|
|
122
134
|
|
|
@@ -162,19 +174,23 @@ vars:
|
|
|
162
174
|
delta_frontend_plan: ""
|
|
163
175
|
delta_frontend_plan_exists: "false"
|
|
164
176
|
wave: ""
|
|
165
|
-
# THE GATE RECEIPT — was this feature's plan pair
|
|
166
|
-
# anything moved since. analyze-plan writes it on
|
|
167
|
-
# reader. Bootstrap path only: a delta generates from delta plans, which
|
|
168
|
-
# gates, and the master receipt says nothing about those.
|
|
177
|
+
# THE GATE RECEIPT — was this feature's plan pair checked against this spec, with what
|
|
178
|
+
# verdict, and has anything moved since. analyze-plan writes it on every master run; this
|
|
179
|
+
# phase is the reader. Bootstrap path only: a delta generates from delta plans, which
|
|
180
|
+
# analyze-plan-delta gates, and the master receipt says nothing about those.
|
|
169
181
|
gate_tracked: "false"
|
|
170
182
|
gate_fresh: "false"
|
|
171
183
|
gate_reason: ""
|
|
172
184
|
gate_at: ""
|
|
185
|
+
gate_verdict: "" # conformant | routed-gaps | gaps — empty with no receipt
|
|
186
|
+
gate_routed_csv: "" # the gaps only /appweaver specify can close
|
|
187
|
+
gate_may_generate: "true"
|
|
188
|
+
gate_no_routed: "true" # lowered when the receipt's verdict is routed-gaps — a warning, not a stop
|
|
173
189
|
# DEFAULTED PERMISSIVE, DELIBERATELY, and it is the one flag here that is. Every tree that
|
|
174
190
|
# predates the receipt has none, and "never gated" is an unknown, not a stale plan —
|
|
175
191
|
# refusing on a missing file would block every existing feature on its first run. The flag
|
|
176
|
-
# is lowered only by a receipt that EXISTS and
|
|
177
|
-
#
|
|
192
|
+
# is lowered only by a receipt that EXISTS and refuses: the bytes moved since it was
|
|
193
|
+
# written, or its verdict left gaps a plan rewrite closes.
|
|
178
194
|
may_generate: "true"
|
|
179
195
|
# PER-LANE STATE. Each lane resolves its own plan, its own project and its own answer;
|
|
180
196
|
# a lane that is not declared never resolves any of them and its steps never run.
|
|
@@ -189,6 +205,23 @@ vars:
|
|
|
189
205
|
be_go: "false"
|
|
190
206
|
be_mode: "skip" # skip | bootstrap | delta
|
|
191
207
|
be_files: []
|
|
208
|
+
# COMPLETENESS, per lane — see step 8b and the checks after each lane generates.
|
|
209
|
+
be_element_names: ""
|
|
210
|
+
be_existing_text: " (not resolved)"
|
|
211
|
+
be_reserved: ""
|
|
212
|
+
be_collisions: ""
|
|
213
|
+
be_collisions_text: "none"
|
|
214
|
+
be_existing_count: "0"
|
|
215
|
+
be_elements: []
|
|
216
|
+
be_more_files: []
|
|
217
|
+
be_elements_more: []
|
|
218
|
+
be_complete: "true"
|
|
219
|
+
be_outcome: "" # complete | already-implemented | gaps | no-plan-elements
|
|
220
|
+
be_satisfied: "false" # the lane was already fully realised, so this run wrote nothing
|
|
221
|
+
be_coverage_note: ""
|
|
222
|
+
be_completion_ran: "false"
|
|
223
|
+
be_gap_names: ""
|
|
224
|
+
be_gaps_text: "none"
|
|
192
225
|
fe_plan: ""
|
|
193
226
|
fe_plan_ok: "false"
|
|
194
227
|
fe_project_ok: "false"
|
|
@@ -198,6 +231,23 @@ vars:
|
|
|
198
231
|
fe_go: "false"
|
|
199
232
|
fe_mode: "skip" # skip | bootstrap | delta
|
|
200
233
|
fe_files: []
|
|
234
|
+
fe_element_names: ""
|
|
235
|
+
fe_existing_text: " (not resolved)"
|
|
236
|
+
fe_reserved: ""
|
|
237
|
+
fe_collisions: ""
|
|
238
|
+
fe_collisions_text: "none"
|
|
239
|
+
fe_existing_count: "0"
|
|
240
|
+
fe_elements: []
|
|
241
|
+
fe_more_files: []
|
|
242
|
+
fe_elements_more: []
|
|
243
|
+
fe_complete: "true"
|
|
244
|
+
fe_outcome: ""
|
|
245
|
+
fe_satisfied: "false"
|
|
246
|
+
fe_coverage_note: ""
|
|
247
|
+
fe_completion_ran: "false"
|
|
248
|
+
fe_gap_names: ""
|
|
249
|
+
fe_gaps_text: "none"
|
|
250
|
+
lanes_complete: "true"
|
|
201
251
|
generate_any: "false"
|
|
202
252
|
record_edges: "false"
|
|
203
253
|
overview_ok: "false"
|
|
@@ -245,6 +295,7 @@ workflow:
|
|
|
245
295
|
- { name: be_declared, from: "$.backend_declared" }
|
|
246
296
|
- { name: be_lane_id, from: "$.backend_lane_id" }
|
|
247
297
|
- { name: be_source_path, from: "$.backend_source_path" }
|
|
298
|
+
- { name: be_test_path, from: "$.backend_test_path" }
|
|
248
299
|
- { name: be_root_exists, from: "$.backend_root_exists" }
|
|
249
300
|
- { name: be_profile, from: "$.backend_profile" }
|
|
250
301
|
- { name: be_title, from: "$.backend_title" }
|
|
@@ -252,9 +303,11 @@ workflow:
|
|
|
252
303
|
- { name: be_ecosystem, from: "$.backend_ecosystem" }
|
|
253
304
|
- { name: be_build, from: "$.backend_build" }
|
|
254
305
|
- { name: be_test, from: "$.backend_test" }
|
|
306
|
+
- { name: be_reserved, from: "$.backend_reserved_csv" }
|
|
255
307
|
- { name: fe_declared, from: "$.frontend_declared" }
|
|
256
308
|
- { name: fe_lane_id, from: "$.frontend_lane_id" }
|
|
257
309
|
- { name: fe_source_path, from: "$.frontend_source_path" }
|
|
310
|
+
- { name: fe_test_path, from: "$.frontend_test_path" }
|
|
258
311
|
- { name: fe_root_exists, from: "$.frontend_root_exists" }
|
|
259
312
|
- { name: fe_profile, from: "$.frontend_profile" }
|
|
260
313
|
- { name: fe_title, from: "$.frontend_title" }
|
|
@@ -262,6 +315,7 @@ workflow:
|
|
|
262
315
|
- { name: fe_ecosystem, from: "$.frontend_ecosystem" }
|
|
263
316
|
- { name: fe_build, from: "$.frontend_build" }
|
|
264
317
|
- { name: fe_test, from: "$.frontend_test" }
|
|
318
|
+
- { name: fe_reserved, from: "$.frontend_reserved_csv" }
|
|
265
319
|
|
|
266
320
|
- id: require_lanes
|
|
267
321
|
action: verify_context
|
|
@@ -425,11 +479,15 @@ workflow:
|
|
|
425
479
|
# spec.md, `implement` therefore generated from a plan that was never held against the
|
|
426
480
|
# spec it now contradicts, silently and at full length.
|
|
427
481
|
#
|
|
428
|
-
# plan-gate-check compares today's bytes against the receipt analyze-plan left
|
|
429
|
-
#
|
|
430
|
-
# own `**Version**:` headers cannot answer this and must not be
|
|
431
|
-
# them and spec.md to the same number in lockstep whether or not
|
|
432
|
-
# so the comparison reads equal always.
|
|
482
|
+
# plan-gate-check compares today's bytes against the receipt analyze-plan left — spec.md,
|
|
483
|
+
# the context's domain-model.md and each gated lane plan — and reads the verdict that
|
|
484
|
+
# run reached. The plans' own `**Version**:` headers cannot answer this and must not be
|
|
485
|
+
# used: close-delta stamps them and spec.md to the same number in lockstep whether or not
|
|
486
|
+
# a plan was re-derived, so the comparison reads equal always.
|
|
487
|
+
#
|
|
488
|
+
# THREE OUTCOMES FOR A RECEIPT. Moved bytes refuse. Verdict `gaps` refuses: that run left
|
|
489
|
+
# gaps a plan rewrite closes. Verdict `routed-gaps` generates and warns: what is left
|
|
490
|
+
# can only be closed in the spec or the model, and it is listed for /appweaver specify.
|
|
433
491
|
#
|
|
434
492
|
# BOOTSTRAP ONLY. A delta run generates from delta plans that analyze-plan-delta gates;
|
|
435
493
|
# the master receipt is silent about them, and reading it there would refuse a change
|
|
@@ -441,25 +499,41 @@ workflow:
|
|
|
441
499
|
subcommand: plan-gate-check
|
|
442
500
|
args: ["--feature-dir", "{{feature_dir}}"]
|
|
443
501
|
outputs:
|
|
444
|
-
- { name: gate_tracked,
|
|
445
|
-
- { name: gate_fresh,
|
|
446
|
-
- { name:
|
|
447
|
-
- { name:
|
|
502
|
+
- { name: gate_tracked, from: "$.tracked" }
|
|
503
|
+
- { name: gate_fresh, from: "$.gate_fresh" }
|
|
504
|
+
- { name: gate_verdict, from: "$.verdict" }
|
|
505
|
+
- { name: gate_may_generate, from: "$.may_generate" }
|
|
506
|
+
- { name: gate_routed_csv, from: "$.routed_csv" }
|
|
507
|
+
- { name: gate_reason, from: "$.reason" }
|
|
508
|
+
- { name: gate_at, from: "$.gated" }
|
|
448
509
|
|
|
449
510
|
# The ordered assignment is the AND: only a TRACKED feature can lower the flag, and
|
|
450
|
-
# what lowers it is
|
|
511
|
+
# what lowers it is plan-gate-check's may_generate. An untracked one never reaches
|
|
451
512
|
# this step's assignment and generates, which is the whole accommodation for trees
|
|
452
513
|
# that have not been gated since the receipt existed.
|
|
453
514
|
- id: flag_gate_block
|
|
454
515
|
condition: "{{gate_tracked}} == true"
|
|
455
516
|
action: set
|
|
456
|
-
vars: { may_generate: "{{
|
|
517
|
+
vars: { may_generate: "{{gate_may_generate}}" }
|
|
457
518
|
|
|
458
519
|
- id: require_gate_fresh
|
|
459
520
|
action: verify_context
|
|
460
521
|
require_true: may_generate
|
|
461
522
|
on_false: stop
|
|
462
|
-
on_false_message: "implement REFUSED —
|
|
523
|
+
on_false_message: "implement REFUSED — analyze-plan's receipt does not clear these plans: {{gate_reason}}. This phase generates from the plans and does NOT read the spec, on the strength of that gate having checked them against it, so generating now would realise a plan against requirements nobody held it to. Re-run /appweaver analyze-plan — it re-checks all four checks, repairs the drifting plan on approval, and re-issues the receipt — then re-run /appweaver implement. If what changed was a plan you re-derived with /appweaver plan main, that is the same path: the re-derived plans have not been gated yet. Nothing was generated."
|
|
524
|
+
|
|
525
|
+
# THE WARNING for a receipt whose only open gaps belong to specify. Generation goes on:
|
|
526
|
+
# no plan rewrite could close them, and the plan is what this phase builds from.
|
|
527
|
+
- id: flag_routed_gaps
|
|
528
|
+
condition: "{{gate_verdict}} == routed-gaps"
|
|
529
|
+
action: set
|
|
530
|
+
vars: { gate_no_routed: "false" }
|
|
531
|
+
|
|
532
|
+
- id: warn_routed_gaps
|
|
533
|
+
action: verify_context
|
|
534
|
+
require_true: gate_no_routed
|
|
535
|
+
on_false: continue
|
|
536
|
+
on_false_message: "WARNING — analyze-plan left gaps only the spec or the model can close, so the code generated now will not cover them: {{gate_routed_csv}}. Lift each into spec.md / domain-model.md by opening a change with /appweaver specify."
|
|
463
537
|
|
|
464
538
|
# 4. THE PROJECT each declared lane generates INTO. Deterministic structure gate:
|
|
465
539
|
# detect-project searches the LANE'S OWN subtree for an ecosystem manifest (.sln/
|
|
@@ -575,7 +649,7 @@ workflow:
|
|
|
575
649
|
- id: ask_backend
|
|
576
650
|
condition: "{{be_runnable}} == true"
|
|
577
651
|
action: ask
|
|
578
|
-
prompt: "Implement the BACKEND lane now? Lane `{{be_lane_id}}` — {{be_title}}, {{be_language}} ({{be_ecosystem}}) — generating from {{be_plan}} into {{be_source_path}}."
|
|
652
|
+
prompt: "Implement the BACKEND lane now? Lane `{{be_lane_id}}` — {{be_title}}, {{be_language}} ({{be_ecosystem}}) — generating from {{be_plan}} into {{be_source_path}}, tests into {{be_test_path}}."
|
|
579
653
|
options: ["yes", "no"]
|
|
580
654
|
answer_var: be_answer
|
|
581
655
|
- id: be_go_set
|
|
@@ -586,7 +660,7 @@ workflow:
|
|
|
586
660
|
- id: ask_frontend
|
|
587
661
|
condition: "{{fe_runnable}} == true"
|
|
588
662
|
action: ask
|
|
589
|
-
prompt: "Implement the FRONTEND lane now? Lane `{{fe_lane_id}}` — {{fe_title}}, {{fe_language}} ({{fe_ecosystem}}) — generating from {{fe_plan}} into {{fe_source_path}}."
|
|
663
|
+
prompt: "Implement the FRONTEND lane now? Lane `{{fe_lane_id}}` — {{fe_title}}, {{fe_language}} ({{fe_ecosystem}}) — generating from {{fe_plan}} into {{fe_source_path}}, tests into {{fe_test_path}}."
|
|
590
664
|
options: ["yes", "no"]
|
|
591
665
|
answer_var: fe_answer
|
|
592
666
|
- id: fe_go_set
|
|
@@ -616,6 +690,69 @@ workflow:
|
|
|
616
690
|
action: set
|
|
617
691
|
vars: { fe_mode: "{{mode}}" }
|
|
618
692
|
|
|
693
|
+
# 8b. EACH GENERATING LANE'S ELEMENT LIST, read off its plan by plan-coverage. The
|
|
694
|
+
# generation prompt carries it, and the model reports every name on it — so an
|
|
695
|
+
# element it did not get to is declared rather than silently absent.
|
|
696
|
+
- id: be_plan_elements
|
|
697
|
+
condition: "{{be_go}} == true"
|
|
698
|
+
action: execute_script
|
|
699
|
+
script: { ref: actions }
|
|
700
|
+
subcommand: plan-coverage
|
|
701
|
+
args: ["--plan", "{{be_plan}}", "--kind", "backend", "--mode", "{{be_mode}}", "--list-only", "--reserved", "{{be_reserved}}"]
|
|
702
|
+
outputs:
|
|
703
|
+
- { name: be_element_names, from: "$.names_text" }
|
|
704
|
+
- { name: be_collisions, from: "$.collisions_csv" }
|
|
705
|
+
- { name: be_collisions_text, from: "$.collisions_text" }
|
|
706
|
+
- id: fe_plan_elements
|
|
707
|
+
condition: "{{fe_go}} == true"
|
|
708
|
+
action: execute_script
|
|
709
|
+
script: { ref: actions }
|
|
710
|
+
subcommand: plan-coverage
|
|
711
|
+
args: ["--plan", "{{fe_plan}}", "--kind", "frontend", "--mode", "{{fe_mode}}", "--list-only", "--reserved", "{{fe_reserved}}"]
|
|
712
|
+
outputs:
|
|
713
|
+
- { name: fe_element_names, from: "$.names_text" }
|
|
714
|
+
- { name: fe_collisions, from: "$.collisions_csv" }
|
|
715
|
+
- { name: fe_collisions_text, from: "$.collisions_text" }
|
|
716
|
+
|
|
717
|
+
# 8c. THE CODE THAT IS ALREADY THERE, per lane, from the aggregate's OKF concept. This
|
|
718
|
+
# is the step that WRITES code, and it was the only one that resolved no source at
|
|
719
|
+
# all — plan, delta-plan, analyze-slice, build and run all read the real tree this
|
|
720
|
+
# way. Without it a lane extending a shared aggregate had to go and discover the
|
|
721
|
+
# established conventions for itself, or not bother, which is how two features end
|
|
722
|
+
# up spelling the same pattern two ways.
|
|
723
|
+
#
|
|
724
|
+
# A PATH LIST, not file contents: the generation steps declare `tools: Read` and open
|
|
725
|
+
# what they need, because a brownfield tree does not fit in a payload. Nothing is
|
|
726
|
+
# truncated — a file left off the list is a file the model does not know to EXTEND
|
|
727
|
+
# and may regenerate instead.
|
|
728
|
+
#
|
|
729
|
+
# `--under` narrows the concept to the lane's own two subtrees. A concept spans every
|
|
730
|
+
# lane that realises the aggregate, so without it the backend pass is handed the UI's
|
|
731
|
+
# files — a subtree it is forbidden to write into two rules later.
|
|
732
|
+
#
|
|
733
|
+
# Read-only, and greenfield-safe: no concept yet exits 0 with count 0, which is the
|
|
734
|
+
# first feature on a fresh tree and blocks nothing.
|
|
735
|
+
- id: be_existing_code
|
|
736
|
+
condition: "{{be_go}} == true"
|
|
737
|
+
action: execute_script
|
|
738
|
+
on_error: continue
|
|
739
|
+
script: { ref: xref }
|
|
740
|
+
subcommand: concept-paths
|
|
741
|
+
args: ["--feature-dir", "{{feature_dir}}", "--under", "{{be_source_path}}", "--under", "{{be_test_path}}"]
|
|
742
|
+
outputs:
|
|
743
|
+
- { name: be_existing_text, from: "$.paths_text" }
|
|
744
|
+
- { name: be_existing_count, from: "$.count" }
|
|
745
|
+
- id: fe_existing_code
|
|
746
|
+
condition: "{{fe_go}} == true"
|
|
747
|
+
action: execute_script
|
|
748
|
+
on_error: continue
|
|
749
|
+
script: { ref: xref }
|
|
750
|
+
subcommand: concept-paths
|
|
751
|
+
args: ["--feature-dir", "{{feature_dir}}", "--under", "{{fe_source_path}}", "--under", "{{fe_test_path}}"]
|
|
752
|
+
outputs:
|
|
753
|
+
- { name: fe_existing_text, from: "$.paths_text" }
|
|
754
|
+
- { name: fe_existing_count, from: "$.count" }
|
|
755
|
+
|
|
619
756
|
# 9. Each generating lane's code-generation rule files → sticky standards (configuration,
|
|
620
757
|
# not hardcoded). Loaded only for a lane that is actually going to generate, and the
|
|
621
758
|
# backend's heading is keyed by mode (see the header). No blocking gate: an
|
|
@@ -698,15 +835,47 @@ workflow:
|
|
|
698
835
|
loaded standards describe a DIFFERENT stack than the one above, the lane wins on
|
|
699
836
|
language and layout — the standards' stack-specific mechanics do not apply, so
|
|
700
837
|
follow their INTENT and STOP to surface the mismatch in your summary.
|
|
701
|
-
- WRITE ONLY
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
838
|
+
- WRITE ONLY INTO THE LANE'S TWO PATHS, both resolved for the `{{be_lane_id}}` lane
|
|
839
|
+
from .appweaver/stacks.json: production code under `{{be_source_path}}`, paired
|
|
840
|
+
tests under `{{be_test_path}}` (the same directory when the stack keeps its tests
|
|
841
|
+
inside its source). Those subtrees are this lane's, and a file outside them belongs
|
|
842
|
+
to another lane or to no lane at all. NEVER write into the frontend lane's subtree,
|
|
843
|
+
not even to consume a contract. Do not create a parallel source tree because the
|
|
844
|
+
layout inside them is unfamiliar; if the plan needs a place they have no home for,
|
|
845
|
+
STOP and surface it.
|
|
846
|
+
- NAMES THIS STACK ALREADY DEFINES: {{be_collisions_text}}.
|
|
847
|
+
Where that list is not `none`, the plan's name is RIGHT and stays exactly as the
|
|
848
|
+
plan spells it — it is the ubiquitous language, and renaming a domain type to
|
|
849
|
+
dodge a framework one is never the answer. What changes is how it is WRITTEN at
|
|
850
|
+
the use site: qualify it with its own enclosing namespace segment, every time.
|
|
851
|
+
In C# that is `Domain.Route`, not a bare `Route`, wherever the type is named —
|
|
852
|
+
declarations, parameters, return types, generic arguments and doc comments.
|
|
853
|
+
The conflict is INVISIBLE in the file: the framework name arrives through an
|
|
854
|
+
implicit/ambient import and appears in no line of it, so a bare name looks fine,
|
|
855
|
+
compiles in your head, and fails the build as an ambiguous reference (C# CS0104).
|
|
856
|
+
Do not add a `using` alias and do not fully qualify the whole namespace path —
|
|
857
|
+
one convention, so two features never disambiguate the same name two ways.
|
|
858
|
+
- THE CODE THAT IS ALREADY THERE. This aggregate already has {{be_existing_count}} file(s) in
|
|
859
|
+
this lane, listed from its OKF concept:
|
|
860
|
+
{{be_existing_text}}
|
|
861
|
+
READ the ones your elements touch BEFORE writing anything. They are this
|
|
862
|
+
codebase's established conventions — the identifier pattern, the persistence and mapping shape, the endpoint
|
|
863
|
+
and handler wiring, the error and DTO style — and new code follows
|
|
864
|
+
them rather than introducing a second way of doing the same thing. A listed file
|
|
865
|
+
that one of your elements maps onto is EXTENDED: add the member, leave every
|
|
866
|
+
existing member byte-for-byte alone, and never regenerate, rename or move it.
|
|
867
|
+
Nothing is left off that list, so a path not on it does not exist yet. A count of
|
|
868
|
+
0 means this is the aggregate's first code in this lane and the conventions come
|
|
869
|
+
from the loaded standards instead.
|
|
870
|
+
- A MISSING TEST PROJECT IS CREATED, NEVER A REASON TO SKIP THE TESTS. When
|
|
871
|
+
`{{be_test_path}}` holds no test project yet, create one there as the loaded
|
|
872
|
+
testing standard describes, referencing the production project it tests, and
|
|
873
|
+
register it wherever `{{be_test}}` discovers tests (for .NET, the solution file).
|
|
874
|
+
That registration is the ONLY edit allowed outside the lane's two paths; name the
|
|
875
|
+
file you edited in your summary.
|
|
707
876
|
- Follow the project's folder/layer convention + the loaded coding-standards,
|
|
708
877
|
dependency-policy and testing standards for HOW to structure, name and place files
|
|
709
|
-
WITHIN
|
|
878
|
+
WITHIN those subtrees — the plan says WHAT to build; these standards (identical for
|
|
710
879
|
every feature) say HOW.
|
|
711
880
|
- COMPONENTS: when the plan's External Integrations table depends on a framework
|
|
712
881
|
component (e.g. `IEmailService`, `IJobScheduler`), code against that component's
|
|
@@ -727,6 +896,12 @@ workflow:
|
|
|
727
896
|
CN / DC / IC / US) from its Traceability section. Include tests for the constraints
|
|
728
897
|
— e.g. an audit record is emitted, a DC-restricted field is NOT exposed on the
|
|
729
898
|
public surface, an IC- projection round-trips.
|
|
899
|
+
- WIRE WHAT YOU BUILD, in this same pass. Every port, adapter, handler and endpoint
|
|
900
|
+
the plan introduces is registered in the lane's composition root as the plan's §4.3
|
|
901
|
+
Wiring states. A dependency that is injected and never bound COMPILES GREEN — a
|
|
902
|
+
container graph is not compile-checked — and fails on the first request that needs
|
|
903
|
+
it. Where the project registers by assembly scan or convention, confirm the new
|
|
904
|
+
type is actually covered by it rather than assuming it is.
|
|
730
905
|
- Do NOT add behaviour the plan does not state, and do NOT omit any it does. If the
|
|
731
906
|
plan looks wrong or incomplete, STOP and surface it (it is fixed in plan /
|
|
732
907
|
analyze-plan) — never compensate from the spec or from memory.
|
|
@@ -740,8 +915,16 @@ workflow:
|
|
|
740
915
|
one changed, STOP and surface it.
|
|
741
916
|
- Where generated code depends on a plan Assumption (DA-n) or Workaround (WA-n), mark
|
|
742
917
|
it with a comment citing that id so it is easy to revisit later.
|
|
918
|
+
- REPORT EVERY PLAN ELEMENT. The plan's elements, by name: {{be_element_names}}.
|
|
919
|
+
Add an `elements` list to your closing JSON block with one entry per name, spelled
|
|
920
|
+
exactly as listed: {"element": "<name>", "status": "done" | "blocked", "reason":
|
|
921
|
+
"<what stops it, when blocked>"}. `done` means it is realised in code now,
|
|
922
|
+
including one that already existed; `blocked` means you could not realise it. An
|
|
923
|
+
element missing from the list counts as not done, and the code is checked for
|
|
924
|
+
each name after this step.
|
|
743
925
|
outputs:
|
|
744
926
|
- { name: be_files, from: "$.files" }
|
|
927
|
+
- { name: be_elements, from: "$.elements" }
|
|
745
928
|
|
|
746
929
|
# ═══════════ BACKEND LANE — delta, generate ONLY what the change adds ════════
|
|
747
930
|
# The delta plan is the authoritative source of WHAT changed — analyze-plan-delta already
|
|
@@ -816,12 +999,42 @@ workflow:
|
|
|
816
999
|
loaded standards describe a DIFFERENT stack than the one above, the lane wins on
|
|
817
1000
|
language and layout — follow the standards' INTENT and STOP to surface the
|
|
818
1001
|
mismatch in your summary.
|
|
819
|
-
- WRITE ONLY
|
|
820
|
-
|
|
821
|
-
lane or to no lane at all. NEVER write into the
|
|
1002
|
+
- WRITE ONLY INTO THE LANE'S TWO PATHS: production code under `{{be_source_path}}`,
|
|
1003
|
+
paired tests under `{{be_test_path}}`. Those subtrees are this lane's, and a file
|
|
1004
|
+
outside them belongs to another lane or to no lane at all. NEVER write into the
|
|
1005
|
+
frontend lane's subtree.
|
|
1006
|
+
- NAMES THIS STACK ALREADY DEFINES: {{be_collisions_text}}.
|
|
1007
|
+
Where that list is not `none`, the plan's name is RIGHT and stays exactly as the
|
|
1008
|
+
plan spells it — it is the ubiquitous language, and renaming a domain type to
|
|
1009
|
+
dodge a framework one is never the answer. What changes is how it is WRITTEN at
|
|
1010
|
+
the use site: qualify it with its own enclosing namespace segment, every time.
|
|
1011
|
+
In C# that is `Domain.Route`, not a bare `Route`, wherever the type is named —
|
|
1012
|
+
declarations, parameters, return types, generic arguments and doc comments.
|
|
1013
|
+
The conflict is INVISIBLE in the file: the framework name arrives through an
|
|
1014
|
+
implicit/ambient import and appears in no line of it, so a bare name looks fine,
|
|
1015
|
+
compiles in your head, and fails the build as an ambiguous reference (C# CS0104).
|
|
1016
|
+
Do not add a `using` alias and do not fully qualify the whole namespace path —
|
|
1017
|
+
one convention, so two features never disambiguate the same name two ways.
|
|
1018
|
+
- THE CODE THAT IS ALREADY THERE. This aggregate already has {{be_existing_count}} file(s) in
|
|
1019
|
+
this lane, listed from its OKF concept:
|
|
1020
|
+
{{be_existing_text}}
|
|
1021
|
+
READ the ones your elements touch BEFORE writing anything. They are this
|
|
1022
|
+
codebase's established conventions — the identifier pattern, the persistence and mapping shape, the endpoint
|
|
1023
|
+
and handler wiring, the error and DTO style — and new code follows
|
|
1024
|
+
them rather than introducing a second way of doing the same thing. A listed file
|
|
1025
|
+
that one of your elements maps onto is EXTENDED: add the member, leave every
|
|
1026
|
+
existing member byte-for-byte alone, and never regenerate, rename or move it.
|
|
1027
|
+
Nothing is left off that list, so a path not on it does not exist yet. A count of
|
|
1028
|
+
0 means this is the aggregate's first code in this lane and the conventions come
|
|
1029
|
+
from the loaded standards instead.
|
|
1030
|
+
- A MISSING TEST PROJECT IS CREATED, NEVER A REASON TO SKIP THE TESTS. When
|
|
1031
|
+
`{{be_test_path}}` holds no test project yet, create one there as the loaded
|
|
1032
|
+
testing standard describes and register it wherever `{{be_test}}` discovers tests
|
|
1033
|
+
(for .NET, the solution file) — the ONLY edit allowed outside the lane's two paths;
|
|
1034
|
+
name the file you edited in your summary.
|
|
822
1035
|
- Follow the project's EXISTING folder/layer convention + the loaded
|
|
823
1036
|
coding-standards, dependency-policy and testing standards for HOW to structure,
|
|
824
|
-
name and place files WITHIN
|
|
1037
|
+
name and place files WITHIN those subtrees. Match the surrounding code already there.
|
|
825
1038
|
- Realise EVERY ADDED/MODIFIED delta element as code: one file per Domain type /
|
|
826
1039
|
Application use-case / API endpoint / Infrastructure adapter, placed by layer.
|
|
827
1040
|
Preserve the ubiquitous-language names verbatim. Enforce each new/changed Domain
|
|
@@ -838,20 +1051,114 @@ workflow:
|
|
|
838
1051
|
The spec is not in context: take the id from the plan and cite it verbatim, never
|
|
839
1052
|
guess one from the element's shape. A delta-plan element that names no id is a
|
|
840
1053
|
planning gap — surface it rather than inventing the traceability.
|
|
1054
|
+
- WIRE WHAT YOU BUILD, in this same pass: every port, adapter, handler and endpoint
|
|
1055
|
+
this change introduces is registered in the lane's composition root, as the delta
|
|
1056
|
+
plan states. A dependency injected and never bound compiles green and fails on the
|
|
1057
|
+
first request; where registration is by assembly scan, confirm the new type is
|
|
1058
|
+
covered by it.
|
|
841
1059
|
- REGRESSION: for each element in the delta plan's "Regression targets", verify (add
|
|
842
1060
|
or adjust a test where needed) that the existing behaviour still holds after a
|
|
843
1061
|
shared element changed — but do NOT rewrite that existing behaviour.
|
|
844
1062
|
- Where generated code depends on a delta Assumption (DA-n) or Workaround (WA-n),
|
|
845
1063
|
mark it with a comment citing that id.
|
|
1064
|
+
- REPORT EVERY DELTA ELEMENT. The delta plan's ADDED and MODIFIED elements, by name:
|
|
1065
|
+
{{be_element_names}}. Add an `elements` list to your closing JSON block with one
|
|
1066
|
+
entry per name, spelled exactly as listed: {"element": "<name>", "status": "done"
|
|
1067
|
+
| "blocked", "reason": "<what stops it, when blocked>"}. An element missing from
|
|
1068
|
+
the list counts as not done, and the code is checked for each name after this step.
|
|
846
1069
|
outputs:
|
|
847
1070
|
- { name: be_files, from: "$.files" }
|
|
1071
|
+
- { name: be_elements, from: "$.elements" }
|
|
848
1072
|
|
|
849
|
-
|
|
1073
|
+
# WHAT THIS LANE ACTUALLY DID, judged on the code rather than on the file count. An empty
|
|
1074
|
+
# file list has two opposite meanings — the lane is already built, or the pass achieved
|
|
1075
|
+
# nothing — and only the code tells them apart, so plan-coverage runs FIRST and the gate
|
|
1076
|
+
# below reads its verdict. `--generated` carries the file list: empty makes this the
|
|
1077
|
+
# already-implemented probe, judged on the code alone, because an element no scan can
|
|
1078
|
+
# confirm (a port, an adapter) was confirmed by the run that created it.
|
|
1079
|
+
#
|
|
1080
|
+
# PARTIAL GENERATION. A non-empty file list is not a finished lane either: a pass that
|
|
1081
|
+
# stopped part-way returns the files it did write. Coverage then checks every plan element
|
|
1082
|
+
# two ways — the code must name each identifier the plan introduces, and the model's own
|
|
1083
|
+
# report must say each element is done — and whatever fails either check gets ONE
|
|
1084
|
+
# completion pass in the same envelope. What is still missing after it stops the run at
|
|
1085
|
+
# step 10b, once both lanes have had their turn.
|
|
1086
|
+
- id: be_coverage
|
|
850
1087
|
condition: "{{be_go}} == true"
|
|
1088
|
+
action: execute_script
|
|
1089
|
+
script: { ref: actions }
|
|
1090
|
+
subcommand: plan-coverage
|
|
1091
|
+
args: ["--plan", "{{be_plan}}", "--kind", "backend", "--mode", "{{be_mode}}", "--source-path", "{{be_source_path}}", "--test-path", "{{be_test_path}}", "--reported", "{{be_elements}}", "--generated", "{{be_files}}"]
|
|
1092
|
+
outputs:
|
|
1093
|
+
- { name: be_complete, from: "$.ok" }
|
|
1094
|
+
- { name: be_outcome, from: "$.outcome" }
|
|
1095
|
+
- { name: be_gap_names, from: "$.gap_names_csv" }
|
|
1096
|
+
- { name: be_gaps_text, from: "$.gaps_text" }
|
|
1097
|
+
- { name: be_coverage_note, from: "$.message" }
|
|
1098
|
+
|
|
1099
|
+
# NOTHING TO DO IS AN OUTCOME, not a failure. A lane whose every plan element is already
|
|
1100
|
+
# realised writes no files, and that is the correct result of re-running implement on a
|
|
1101
|
+
# finished feature — the other lane may still have work, and the OKF merge and the edges
|
|
1102
|
+
# downstream are reconcile-on-write, so the run carries on.
|
|
1103
|
+
- id: be_satisfied_flag
|
|
1104
|
+
condition: "{{be_outcome}} == already-implemented"
|
|
1105
|
+
action: set
|
|
1106
|
+
vars: { be_satisfied: "true" }
|
|
1107
|
+
|
|
1108
|
+
# The one empty-file case that IS unexplained: a plan no element could be read from
|
|
1109
|
+
# proves nothing about the code, so a pass that wrote nothing against it has no evidence
|
|
1110
|
+
# either way. That is the template-not-filled case the old file-count gate was reaching
|
|
1111
|
+
# for, and it is the only one left that stops the run here.
|
|
1112
|
+
- id: verify_be_evidence
|
|
1113
|
+
condition: "{{be_outcome}} == no-plan-elements"
|
|
851
1114
|
action: verify_context
|
|
852
1115
|
require_non_empty: be_files
|
|
853
1116
|
on_empty: stop
|
|
854
|
-
on_empty_message: "The backend lane generated no files
|
|
1117
|
+
on_empty_message: "The backend lane generated no files, and no plan element could be read from {{be_plan}} — so there is no evidence of what it should have built. The usual cause is an unfilled plan (still the empty template) or one whose headings do not follow the plan template. Fill it with /appweaver plan, check it with /appweaver analyze-plan (analyze-plan-delta for a change), then re-run implement."
|
|
1118
|
+
- id: be_completion_flag
|
|
1119
|
+
condition: "{{be_complete}} == false"
|
|
1120
|
+
action: set
|
|
1121
|
+
vars: { be_completion_ran: "true" }
|
|
1122
|
+
- id: gen_backend_complete
|
|
1123
|
+
condition: "{{be_completion_ran}} == true"
|
|
1124
|
+
action: agent_generate
|
|
1125
|
+
tools: "Read,Write,Edit"
|
|
1126
|
+
permission_mode: acceptEdits
|
|
1127
|
+
task: |
|
|
1128
|
+
COMPLETE the backend lane. The generation pass before this one left these plan
|
|
1129
|
+
elements unrealised: {{be_gap_names}}.
|
|
1130
|
+
Why each was flagged: {{be_gaps_text}}.
|
|
1131
|
+
The same plan, domain model and constitution are in context, and every rule of that
|
|
1132
|
+
pass still holds: realise each element STRICTLY as the plan states it; production
|
|
1133
|
+
code only under `{{be_source_path}}` and paired tests only under `{{be_test_path}}`;
|
|
1134
|
+
the `{{be_lane_id}}` lane's stack ({{be_title}}, {{be_language}}) and no other;
|
|
1135
|
+
shared aggregate files EXTENDED, never regenerated; nothing the plan does not state.
|
|
1136
|
+
Rules:
|
|
1137
|
+
- Realise each listed element now, with its paired test citing the spec id the plan
|
|
1138
|
+
gives it. Leave what the earlier pass wrote as it is, except to extend a shared file.
|
|
1139
|
+
- Use the plan's name for each element EXACTLY. An element that already exists
|
|
1140
|
+
under a different name is renamed to the plan's name, with its references — the
|
|
1141
|
+
plan's names are the ubiquitous language.
|
|
1142
|
+
- An element the plan names by intent (a port, an adapter, an endpoint route) is done
|
|
1143
|
+
when the code realises it, whatever the framework calls it; report it `done`.
|
|
1144
|
+
- If an element cannot be realised, do not work around it: report it `blocked` and
|
|
1145
|
+
say what stops you. A plan that is wrong is fixed in plan / analyze-plan.
|
|
1146
|
+
- Report every listed element in an `elements` list in your closing JSON block:
|
|
1147
|
+
{"element": "<name as listed>", "status": "done" | "blocked", "reason": "…"}.
|
|
1148
|
+
outputs:
|
|
1149
|
+
- { name: be_more_files, from: "$.files" }
|
|
1150
|
+
- { name: be_elements_more, from: "$.elements" }
|
|
1151
|
+
- id: be_coverage_recheck
|
|
1152
|
+
condition: "{{be_completion_ran}} == true"
|
|
1153
|
+
action: execute_script
|
|
1154
|
+
script: { ref: actions }
|
|
1155
|
+
subcommand: plan-coverage
|
|
1156
|
+
args: ["--plan", "{{be_plan}}", "--kind", "backend", "--mode", "{{be_mode}}", "--source-path", "{{be_source_path}}", "--test-path", "{{be_test_path}}", "--reported", "{{be_elements}}", "--reported", "{{be_elements_more}}"]
|
|
1157
|
+
outputs:
|
|
1158
|
+
- { name: be_complete, from: "$.ok" }
|
|
1159
|
+
- { name: be_outcome, from: "$.outcome" }
|
|
1160
|
+
- { name: be_gap_names, from: "$.gap_names_csv" }
|
|
1161
|
+
- { name: be_gaps_text, from: "$.gaps_text" }
|
|
855
1162
|
|
|
856
1163
|
# OKF knowledge — the feature has ONE concept across both lanes and both modes, so every
|
|
857
1164
|
# lane's files JOIN it rather than replace it (--merge unions them with what is already
|
|
@@ -868,6 +1175,15 @@ workflow:
|
|
|
868
1175
|
args: ["--feature-dir", "{{feature_dir}}", "--source-files", "{{be_files}}", "--merge", "--origin", "greenfield"]
|
|
869
1176
|
outputs:
|
|
870
1177
|
- { name: okf_concept, from: "$.concept" }
|
|
1178
|
+
- id: xref_concept_backend_more
|
|
1179
|
+
condition: "{{be_completion_ran}} == true"
|
|
1180
|
+
action: execute_script
|
|
1181
|
+
on_error: continue
|
|
1182
|
+
script: { ref: xref }
|
|
1183
|
+
subcommand: concept-upsert
|
|
1184
|
+
args: ["--feature-dir", "{{feature_dir}}", "--source-files", "{{be_more_files}}", "--merge", "--origin", "greenfield"]
|
|
1185
|
+
outputs:
|
|
1186
|
+
- { name: okf_concept, from: "$.concept" }
|
|
871
1187
|
|
|
872
1188
|
# ══════════════ THE LANE SWAP — the frontend's rules replace the backend's ═══
|
|
873
1189
|
# build_context already scoped the two lanes' PAYLOADS apart; this is the same boundary
|
|
@@ -932,16 +1248,46 @@ workflow:
|
|
|
932
1248
|
re-decide anything already fixed there. If the loaded standards describe a
|
|
933
1249
|
DIFFERENT stack than the one above, the lane wins on framework and layout — follow
|
|
934
1250
|
the standards' INTENT and STOP to surface the mismatch in your summary.
|
|
935
|
-
- WRITE ONLY
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
lane.
|
|
940
|
-
|
|
941
|
-
|
|
1251
|
+
- WRITE ONLY INTO THE LANE'S TWO PATHS, both resolved for the `{{fe_lane_id}}` lane:
|
|
1252
|
+
production code under `{{fe_source_path}}`, paired tests under `{{fe_test_path}}`
|
|
1253
|
+
(the same directory when the stack keeps its tests inside its source). Those
|
|
1254
|
+
subtrees are this lane's; a file outside them belongs to the service lane or to no
|
|
1255
|
+
lane. NEVER touch the service lane's code, not even to add a field the UI wants: a
|
|
1256
|
+
gap in the service surface is a contract delta raised back to that lane. Do not
|
|
1257
|
+
create a parallel source tree because the layout inside this one is unfamiliar; if
|
|
1258
|
+
the plan needs a place this subtree has no home for, STOP and surface it.
|
|
1259
|
+
- NAMES THIS STACK ALREADY DEFINES: {{fe_collisions_text}}.
|
|
1260
|
+
Where that list is not `none`, the plan's name is RIGHT and stays exactly as the
|
|
1261
|
+
plan spells it — it is the ubiquitous language, and renaming a domain type to
|
|
1262
|
+
dodge a framework one is never the answer. What changes is how it is WRITTEN at
|
|
1263
|
+
the use site: qualify it with its own enclosing namespace segment, every time.
|
|
1264
|
+
In C# that is `Domain.Route`, not a bare `Route`, wherever the type is named —
|
|
1265
|
+
declarations, parameters, return types, generic arguments and doc comments.
|
|
1266
|
+
The conflict is INVISIBLE in the file: the framework name arrives through an
|
|
1267
|
+
implicit/ambient import and appears in no line of it, so a bare name looks fine,
|
|
1268
|
+
compiles in your head, and fails the build as an ambiguous reference (C# CS0104).
|
|
1269
|
+
Do not add a `using` alias and do not fully qualify the whole namespace path —
|
|
1270
|
+
one convention, so two features never disambiguate the same name two ways.
|
|
1271
|
+
- THE CODE THAT IS ALREADY THERE. This aggregate already has {{fe_existing_count}} file(s) in
|
|
1272
|
+
this lane, listed from its OKF concept:
|
|
1273
|
+
{{fe_existing_text}}
|
|
1274
|
+
READ the ones your elements touch BEFORE writing anything. They are this
|
|
1275
|
+
codebase's established conventions — the component and screen layout, the server-action and data-fetch shape,
|
|
1276
|
+
the state and error handling, the locale-catalogue mechanics — and new code follows
|
|
1277
|
+
them rather than introducing a second way of doing the same thing. A listed file
|
|
1278
|
+
that one of your elements maps onto is EXTENDED: add the member, leave every
|
|
1279
|
+
existing member byte-for-byte alone, and never regenerate, rename or move it.
|
|
1280
|
+
Nothing is left off that list, so a path not on it does not exist yet. A count of
|
|
1281
|
+
0 means this is the aggregate's first code in this lane and the conventions come
|
|
1282
|
+
from the loaded standards instead.
|
|
1283
|
+
- A MISSING TEST SETUP IS CREATED, NEVER A REASON TO SKIP THE TESTS. When the lane
|
|
1284
|
+
has no test project or test runner yet, set one up inside the lane's paths as the
|
|
1285
|
+
loaded testing standard describes, so that `{{fe_test}}` runs the tests you write.
|
|
1286
|
+
Anything outside the lane's two paths that must change for that is the ONLY such
|
|
1287
|
+
edit allowed; name the file you edited in your summary.
|
|
942
1288
|
- Follow the UI constitution's folder structure, naming conventions and forbidden
|
|
943
1289
|
patterns, plus the loaded standards, for HOW to structure, name and place files
|
|
944
|
-
WITHIN
|
|
1290
|
+
WITHIN those subtrees — the plan says WHAT to build; these say HOW.
|
|
945
1291
|
- REALISE EVERY PLAN ELEMENT, changing nothing about WHAT it specifies:
|
|
946
1292
|
• §1 — one route/screen per row, with the navigation shape and the access
|
|
947
1293
|
conditions the row states.
|
|
@@ -974,8 +1320,16 @@ workflow:
|
|
|
974
1320
|
feature. If one of them has to change, STOP and surface it.
|
|
975
1321
|
- Where generated code depends on a plan Assumption (DA-n) or Workaround (WA-n), mark
|
|
976
1322
|
it with a comment citing that id so it is easy to revisit later.
|
|
1323
|
+
- REPORT EVERY PLAN ELEMENT. The plan's elements, by name: {{fe_element_names}}.
|
|
1324
|
+
Add an `elements` list to your closing JSON block with one entry per name, spelled
|
|
1325
|
+
exactly as listed: {"element": "<name>", "status": "done" | "blocked", "reason":
|
|
1326
|
+
"<what stops it, when blocked>"}. `done` means it is realised in code now,
|
|
1327
|
+
including one that already existed; `blocked` means you could not realise it. An
|
|
1328
|
+
element missing from the list counts as not done, and the code is checked for
|
|
1329
|
+
each name after this step.
|
|
977
1330
|
outputs:
|
|
978
1331
|
- { name: fe_files, from: "$.files" }
|
|
1332
|
+
- { name: fe_elements, from: "$.elements" }
|
|
979
1333
|
|
|
980
1334
|
# ═══════════ FRONTEND LANE — delta, generate ONLY what the change adds ═══════
|
|
981
1335
|
# The UI half of the CR loop, which never existed as its own command: the ⌛
|
|
@@ -1031,9 +1385,37 @@ workflow:
|
|
|
1031
1385
|
`{{fe_test}}`. Generate in THAT framework and no other. Take the router, state
|
|
1032
1386
|
approach, component library, design system and styling from the UI constitution +
|
|
1033
1387
|
the loaded standards, and MATCH the code already in the tree.
|
|
1034
|
-
- WRITE ONLY
|
|
1388
|
+
- WRITE ONLY INTO THE LANE'S TWO PATHS: production code under `{{fe_source_path}}`,
|
|
1389
|
+
paired tests under `{{fe_test_path}}`. NEVER touch the service lane's code, not
|
|
1035
1390
|
even to add a field the UI wants — a gap in the service surface is a contract delta
|
|
1036
1391
|
raised back to that lane, never worked around in the client.
|
|
1392
|
+
- NAMES THIS STACK ALREADY DEFINES: {{fe_collisions_text}}.
|
|
1393
|
+
Where that list is not `none`, the plan's name is RIGHT and stays exactly as the
|
|
1394
|
+
plan spells it — it is the ubiquitous language, and renaming a domain type to
|
|
1395
|
+
dodge a framework one is never the answer. What changes is how it is WRITTEN at
|
|
1396
|
+
the use site: qualify it with its own enclosing namespace segment, every time.
|
|
1397
|
+
In C# that is `Domain.Route`, not a bare `Route`, wherever the type is named —
|
|
1398
|
+
declarations, parameters, return types, generic arguments and doc comments.
|
|
1399
|
+
The conflict is INVISIBLE in the file: the framework name arrives through an
|
|
1400
|
+
implicit/ambient import and appears in no line of it, so a bare name looks fine,
|
|
1401
|
+
compiles in your head, and fails the build as an ambiguous reference (C# CS0104).
|
|
1402
|
+
Do not add a `using` alias and do not fully qualify the whole namespace path —
|
|
1403
|
+
one convention, so two features never disambiguate the same name two ways.
|
|
1404
|
+
- THE CODE THAT IS ALREADY THERE. This aggregate already has {{fe_existing_count}} file(s) in
|
|
1405
|
+
this lane, listed from its OKF concept:
|
|
1406
|
+
{{fe_existing_text}}
|
|
1407
|
+
READ the ones your elements touch BEFORE writing anything. They are this
|
|
1408
|
+
codebase's established conventions — the component and screen layout, the server-action and data-fetch shape,
|
|
1409
|
+
the state and error handling, the locale-catalogue mechanics — and new code follows
|
|
1410
|
+
them rather than introducing a second way of doing the same thing. A listed file
|
|
1411
|
+
that one of your elements maps onto is EXTENDED: add the member, leave every
|
|
1412
|
+
existing member byte-for-byte alone, and never regenerate, rename or move it.
|
|
1413
|
+
Nothing is left off that list, so a path not on it does not exist yet. A count of
|
|
1414
|
+
0 means this is the aggregate's first code in this lane and the conventions come
|
|
1415
|
+
from the loaded standards instead.
|
|
1416
|
+
- A MISSING TEST SETUP IS CREATED, NEVER A REASON TO SKIP THE TESTS: set one up
|
|
1417
|
+
inside the lane's paths so that `{{fe_test}}` runs the tests you write, and name
|
|
1418
|
+
any file outside them you had to edit for that in your summary.
|
|
1037
1419
|
- STATES ARE PART OF THE CHANGE. Every interaction this delta adds or alters ships
|
|
1038
1420
|
its FULL state set — loading, empty, error, permission-denied, in-flight — plus the
|
|
1039
1421
|
validation timing, focus placement and keyboard reachability the delta plan states.
|
|
@@ -1055,15 +1437,86 @@ workflow:
|
|
|
1055
1437
|
feature. If one of them has to change, STOP and surface it.
|
|
1056
1438
|
- Where generated code depends on a delta Assumption (DA-n) or Workaround (WA-n),
|
|
1057
1439
|
mark it with a comment citing that id.
|
|
1440
|
+
- REPORT EVERY DELTA ELEMENT. The delta plan's ADDED and MODIFIED elements, by name:
|
|
1441
|
+
{{fe_element_names}}. Add an `elements` list to your closing JSON block with one
|
|
1442
|
+
entry per name, spelled exactly as listed: {"element": "<name>", "status": "done"
|
|
1443
|
+
| "blocked", "reason": "<what stops it, when blocked>"}. An element missing from
|
|
1444
|
+
the list counts as not done, and the code is checked for each name after this step.
|
|
1058
1445
|
outputs:
|
|
1059
1446
|
- { name: fe_files, from: "$.files" }
|
|
1447
|
+
- { name: fe_elements, from: "$.elements" }
|
|
1060
1448
|
|
|
1061
|
-
|
|
1449
|
+
# WHAT THIS LANE ACTUALLY DID — the frontend twin of the backend check above, including
|
|
1450
|
+
# the already-implemented probe and the one empty-file case that still stops the run.
|
|
1451
|
+
- id: fe_coverage
|
|
1062
1452
|
condition: "{{fe_go}} == true"
|
|
1453
|
+
action: execute_script
|
|
1454
|
+
script: { ref: actions }
|
|
1455
|
+
subcommand: plan-coverage
|
|
1456
|
+
args: ["--plan", "{{fe_plan}}", "--kind", "frontend", "--mode", "{{fe_mode}}", "--source-path", "{{fe_source_path}}", "--test-path", "{{fe_test_path}}", "--reported", "{{fe_elements}}", "--generated", "{{fe_files}}"]
|
|
1457
|
+
outputs:
|
|
1458
|
+
- { name: fe_complete, from: "$.ok" }
|
|
1459
|
+
- { name: fe_outcome, from: "$.outcome" }
|
|
1460
|
+
- { name: fe_gap_names, from: "$.gap_names_csv" }
|
|
1461
|
+
- { name: fe_gaps_text, from: "$.gaps_text" }
|
|
1462
|
+
- { name: fe_coverage_note, from: "$.message" }
|
|
1463
|
+
|
|
1464
|
+
- id: fe_satisfied_flag
|
|
1465
|
+
condition: "{{fe_outcome}} == already-implemented"
|
|
1466
|
+
action: set
|
|
1467
|
+
vars: { fe_satisfied: "true" }
|
|
1468
|
+
|
|
1469
|
+
- id: verify_fe_evidence
|
|
1470
|
+
condition: "{{fe_outcome}} == no-plan-elements"
|
|
1063
1471
|
action: verify_context
|
|
1064
1472
|
require_non_empty: fe_files
|
|
1065
1473
|
on_empty: stop
|
|
1066
|
-
on_empty_message: "The frontend lane generated no files
|
|
1474
|
+
on_empty_message: "The frontend lane generated no files, and no plan element could be read from {{fe_plan}} — so there is no evidence of what it should have built. The usual cause is an unfilled plan (still the empty template) or one whose headings do not follow the plan template. Fill it with /appweaver plan-ui, check it with /appweaver analyze-plan (analyze-plan-delta for a change), then re-run implement."
|
|
1475
|
+
- id: fe_completion_flag
|
|
1476
|
+
condition: "{{fe_complete}} == false"
|
|
1477
|
+
action: set
|
|
1478
|
+
vars: { fe_completion_ran: "true" }
|
|
1479
|
+
- id: gen_frontend_complete
|
|
1480
|
+
condition: "{{fe_completion_ran}} == true"
|
|
1481
|
+
action: agent_generate
|
|
1482
|
+
tools: "Read,Write,Edit"
|
|
1483
|
+
permission_mode: acceptEdits
|
|
1484
|
+
task: |
|
|
1485
|
+
COMPLETE the frontend lane. The generation pass before this one left these plan
|
|
1486
|
+
elements unrealised: {{fe_gap_names}}.
|
|
1487
|
+
Why each was flagged: {{fe_gaps_text}}.
|
|
1488
|
+
The same plan, domain model and UI constitution are in context, and every rule of
|
|
1489
|
+
that pass still holds: realise each element STRICTLY as the plan states it, with its
|
|
1490
|
+
FULL state set; production code only under `{{fe_source_path}}` and paired tests
|
|
1491
|
+
only under `{{fe_test_path}}`; the `{{fe_lane_id}}` lane's stack ({{fe_title}},
|
|
1492
|
+
{{fe_language}}) and no other; never the service lane's code, the app shell, the
|
|
1493
|
+
global layout or the design system; nothing the plan does not state.
|
|
1494
|
+
Rules:
|
|
1495
|
+
- Realise each listed element now, with its paired test citing the spec id the plan
|
|
1496
|
+
gives it. Leave what the earlier pass wrote as it is.
|
|
1497
|
+
- Use the plan's name for each element EXACTLY. An element that already exists
|
|
1498
|
+
under a different name is renamed to the plan's name, with its references — the
|
|
1499
|
+
plan's names are the ubiquitous language.
|
|
1500
|
+
- A screen or a binding is done when the code realises it, whatever its route or
|
|
1501
|
+
file is called; report it `done`.
|
|
1502
|
+
- If an element cannot be realised, do not work around it: report it `blocked` and
|
|
1503
|
+
say what stops you. A plan that is wrong is fixed in plan / analyze-plan.
|
|
1504
|
+
- Report every listed element in an `elements` list in your closing JSON block:
|
|
1505
|
+
{"element": "<name as listed>", "status": "done" | "blocked", "reason": "…"}.
|
|
1506
|
+
outputs:
|
|
1507
|
+
- { name: fe_more_files, from: "$.files" }
|
|
1508
|
+
- { name: fe_elements_more, from: "$.elements" }
|
|
1509
|
+
- id: fe_coverage_recheck
|
|
1510
|
+
condition: "{{fe_completion_ran}} == true"
|
|
1511
|
+
action: execute_script
|
|
1512
|
+
script: { ref: actions }
|
|
1513
|
+
subcommand: plan-coverage
|
|
1514
|
+
args: ["--plan", "{{fe_plan}}", "--kind", "frontend", "--mode", "{{fe_mode}}", "--source-path", "{{fe_source_path}}", "--test-path", "{{fe_test_path}}", "--reported", "{{fe_elements}}", "--reported", "{{fe_elements_more}}"]
|
|
1515
|
+
outputs:
|
|
1516
|
+
- { name: fe_complete, from: "$.ok" }
|
|
1517
|
+
- { name: fe_outcome, from: "$.outcome" }
|
|
1518
|
+
- { name: fe_gap_names, from: "$.gap_names_csv" }
|
|
1519
|
+
- { name: fe_gaps_text, from: "$.gaps_text" }
|
|
1067
1520
|
|
|
1068
1521
|
- id: xref_concept_frontend
|
|
1069
1522
|
condition: "{{fe_go}} == true"
|
|
@@ -1074,6 +1527,34 @@ workflow:
|
|
|
1074
1527
|
args: ["--feature-dir", "{{feature_dir}}", "--source-files", "{{fe_files}}", "--merge", "--origin", "greenfield"]
|
|
1075
1528
|
outputs:
|
|
1076
1529
|
- { name: okf_concept, from: "$.concept" }
|
|
1530
|
+
- id: xref_concept_frontend_more
|
|
1531
|
+
condition: "{{fe_completion_ran}} == true"
|
|
1532
|
+
action: execute_script
|
|
1533
|
+
on_error: continue
|
|
1534
|
+
script: { ref: xref }
|
|
1535
|
+
subcommand: concept-upsert
|
|
1536
|
+
args: ["--feature-dir", "{{feature_dir}}", "--source-files", "{{fe_more_files}}", "--merge", "--origin", "greenfield"]
|
|
1537
|
+
outputs:
|
|
1538
|
+
- { name: okf_concept, from: "$.concept" }
|
|
1539
|
+
|
|
1540
|
+
# 10b. A LANE LEFT INCOMPLETE STOPS THE RUN — after both lanes have generated and every
|
|
1541
|
+
# file written is recorded in the OKF concept, and before the edges, the Overview
|
|
1542
|
+
# and the after-hooks, which all assume a finished slice. Re-running implement
|
|
1543
|
+
# finishes the job: shared files are extended, and a file that exists is not
|
|
1544
|
+
# regenerated.
|
|
1545
|
+
- id: lanes_incomplete_be
|
|
1546
|
+
condition: "{{be_complete}} == false"
|
|
1547
|
+
action: set
|
|
1548
|
+
vars: { lanes_complete: "false" }
|
|
1549
|
+
- id: lanes_incomplete_fe
|
|
1550
|
+
condition: "{{fe_complete}} == false"
|
|
1551
|
+
action: set
|
|
1552
|
+
vars: { lanes_complete: "false" }
|
|
1553
|
+
- id: require_complete_lanes
|
|
1554
|
+
action: verify_context
|
|
1555
|
+
require_true: lanes_complete
|
|
1556
|
+
on_false: stop
|
|
1557
|
+
on_false_message: "PARTIAL GENERATION — implement did not realise every plan element, even after one completion pass. Backend lane: {{be_gaps_text}}. Frontend lane: {{fe_gaps_text}}. Everything written so far is kept and recorded in the OKF concept. An element reported `blocked` names what stops it — a plan that is wrong is fixed with /appweaver plan (then analyze-plan or analyze-plan-delta). An element with no code under the lane's source path is still to be written, or was written under a name that is not the plan's: re-run /appweaver implement to finish, which extends existing files rather than regenerating them."
|
|
1077
1558
|
|
|
1078
1559
|
# 11. CROSS-SLICE EDGES — a Cross-References row written into every SIBLING aggregate
|
|
1079
1560
|
# this one uses, read off the master backend plan (§1 References-by-id + its External
|
|
@@ -1181,15 +1662,34 @@ outputs:
|
|
|
1181
1662
|
frontend_implemented: "{{fe_go}}"
|
|
1182
1663
|
frontend_plan: "{{fe_plan}}" # the document the frontend lane generated FROM
|
|
1183
1664
|
frontend_files: "{{fe_files}}"
|
|
1665
|
+
# Every plan element realised, per lane — `true` for a lane that did not generate.
|
|
1666
|
+
# `*_completion_pass` says whether the first pass left gaps a second one had to close.
|
|
1667
|
+
# `*_outcome` is the one word for what the lane did: complete (it generated and every
|
|
1668
|
+
# element is realised), already-implemented (it wrote nothing because nothing was left
|
|
1669
|
+
# to write), gaps, or no-plan-elements. `*_satisfied` is that second case alone.
|
|
1670
|
+
backend_complete: "{{be_complete}}"
|
|
1671
|
+
backend_outcome: "{{be_outcome}}"
|
|
1672
|
+
backend_satisfied: "{{be_satisfied}}"
|
|
1673
|
+
backend_coverage: "{{be_coverage_note}}"
|
|
1674
|
+
backend_completion_pass: "{{be_completion_ran}}"
|
|
1675
|
+
backend_more_files: "{{be_more_files}}"
|
|
1676
|
+
frontend_complete: "{{fe_complete}}"
|
|
1677
|
+
frontend_outcome: "{{fe_outcome}}"
|
|
1678
|
+
frontend_satisfied: "{{fe_satisfied}}"
|
|
1679
|
+
frontend_coverage: "{{fe_coverage_note}}"
|
|
1680
|
+
frontend_completion_pass: "{{fe_completion_ran}}"
|
|
1681
|
+
frontend_more_files: "{{fe_more_files}}"
|
|
1184
1682
|
domain_model: "{{domain_model}}" # the master model every generating lane read
|
|
1185
1683
|
delta_model: "{{delta_model}}" # its second half on the delta path — empty on the bootstrap path
|
|
1186
1684
|
okf_concept: "{{okf_concept}}"
|
|
1187
1685
|
xref_edge_count: "{{xref_edge_count}}"
|
|
1188
|
-
# Bootstrap path only. tracked=false means this feature has
|
|
1189
|
-
# since the gate began leaving a receipt — an unknown, not a stale plan,
|
|
1190
|
-
# nothing.
|
|
1686
|
+
# Bootstrap path only. tracked=false means this feature has not been through a master
|
|
1687
|
+
# analyze-plan run since the gate began leaving a receipt — an unknown, not a stale plan,
|
|
1688
|
+
# and it blocks nothing.
|
|
1191
1689
|
plan_gate_tracked: "{{gate_tracked}}"
|
|
1192
1690
|
plan_gate_fresh: "{{gate_fresh}}"
|
|
1193
1691
|
plan_gate_at: "{{gate_at}}"
|
|
1194
|
-
|
|
1692
|
+
plan_gate_verdict: "{{gate_verdict}}"
|
|
1693
|
+
plan_gate_routed_to_specify: "{{gate_routed_csv}}" # open spec/model gaps this code does not cover
|
|
1694
|
+
note: "Lanes come from .appweaver/stacks.json — backend declared {{be_declared}} (ready {{be_runnable}}, implemented {{be_go}}), frontend declared {{fe_declared}} (ready {{fe_runnable}}, implemented {{fe_go}}). A declared lane that was skipped printed its reason above and did not stop the other one; an undeclared lane produces nothing and that is not a failure. Each generating lane read its PLAN for what to build and {{domain_model}} for what the domain is — plus {{delta_model}} on the delta path, since the master model does not carry the change until finalize-delta merges it. Every one of those documents was READ and none was written: this phase generates code and nothing else. Each lane's outcome is backend={{be_outcome}}, frontend={{fe_outcome}} — `already-implemented` means the lane wrote no files because every plan element was already realised in its source path, which is the correct result of re-running implement on a finished feature and not a failure. On the bootstrap path the plans were checked against analyze-plan's receipt before anything generated (tracked={{gate_tracked}}, fresh={{gate_fresh}}, gated {{gate_at}}) — tracked=false means this feature has never passed analyze-plan since the gate began recording what it proved, which is an unknown rather than a stale plan and blocks nothing; run /appweaver analyze-plan once to start the record."
|
|
1195
1695
|
next: "This run was mode `{{mode}}`, change `{{active_change}}` (empty on the bootstrap path). BOOTSTRAP → /appweaver build → analyze-slice → run. DELTA → /appweaver build → analyze-slice-delta {{active_change}} → finalize-delta → analyze-slice → close-delta, with the change still OPEN throughout — compile first, then analyze-slice-delta verifies that every element the delta plans marked ADDED or MODIFIED is actually in the code with a paired test (the gate that catches a lane you declined at the prompt above), then finalize-delta merges it into spec.md + the context's domain-model.md while leaving it open, analyze-slice verifies the slice against those merged masters while a red result is still recoverable, and close-delta LAST archives the change and bumps the version."
|