aw-spec-cli 0.1.18 → 0.1.19
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/DESIGN-FORMAT.md +45 -21
- package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +62 -14
- package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +6 -4
- package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +9 -1
- package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +21 -0
- package/assets/.appweaver/orchestrator/orchestrator.py +23 -1
- package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +18 -11
- package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +5 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +298 -109
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +161 -34
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +125 -24
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +18 -7
- package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +182 -39
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +300 -35
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +190 -31
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +93 -8
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +34 -7
- package/assets/.appweaver/orchestrator/workflows/aw-spec-recall-delta.orch.yaml +319 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +125 -24
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +846 -35
- package/assets/.appweaver/scripts/bash/common.sh +28 -1
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +843 -46
- package/assets/.appweaver/scripts/python/aw-inventory.py +3 -2
- package/assets/.appweaver/templates/design-template.md +41 -30
- package/assets/.appweaver/templates/spec-template.md +7 -4
- package/assets/.appweaver/templates/ui-design-template.md +7 -3
- package/assets/guardrails/domain/healthcare/auditing.domain.md +3 -3
- package/assets/guardrails/domain/pharma/auditing.domain.md +3 -3
- package/assets/guardrails/technology/dotnet-webapi/api-versioning.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/auditing.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/authorization.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/clean-architecture.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/cqrs.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/data-classification.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/eventing.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/modular-monolith.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/persistence.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/vertical-slices.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/zero-trust.md +1 -1
- package/assets/guardrails/technology/nextjs/accessibility-implementation.md +1 -1
- package/assets/guardrails/technology/nextjs/api-integration.dotnet-webapi.md +1 -1
- package/assets/guardrails/technology/nextjs/api-integration.java-spring.md +1 -1
- package/assets/guardrails/technology/nextjs/auth-session.md +1 -1
- package/assets/guardrails/technology/nextjs/component-architecture.md +1 -1
- package/assets/guardrails/technology/nextjs/design-system.md +1 -1
- package/assets/guardrails/technology/nextjs/error-handling.md +1 -1
- package/assets/guardrails/technology/nextjs/forms-and-validation.md +1 -1
- package/assets/guardrails/technology/nextjs/i18n.md +1 -1
- package/assets/guardrails/technology/nextjs/performance-budgets.md +1 -1
- package/assets/guardrails/technology/nextjs/routing-navigation.md +1 -1
- package/assets/guardrails/technology/nextjs/state-management.md +1 -1
- package/package.json +1 -1
|
@@ -42,6 +42,22 @@
|
|
|
42
42
|
# spec.md — analyze-plan already conformed the plans to it, so the plan is the complete,
|
|
43
43
|
# authoritative source for WHICH elements exist, where each lives and what surface they
|
|
44
44
|
# publish, and anything missing from it is fixed in `plan`, never compensated for here.
|
|
45
|
+
#
|
|
46
|
+
# AND THAT SENTENCE IS NOW CHECKED. "analyze-plan already conformed them" was an assumption
|
|
47
|
+
# about the order the operator ran things in: the lane gates test that the plan FILE EXISTS
|
|
48
|
+
# and nothing more, so `plan` → edit spec.md → `implement` generated at full length from a
|
|
49
|
+
# plan nobody had held against the spec it now contradicts. analyze-plan leaves a receipt of
|
|
50
|
+
# the bytes it proved and plan-gate-check reads it here, on the bootstrap path, before any
|
|
51
|
+
# lane generates. A feature with no receipt has simply never been gated since the receipt
|
|
52
|
+
# existed — reported, never refused. One that HAS a receipt and no longer matches it stops.
|
|
53
|
+
# 3.2.0 — AND NOT delta-spec.md EITHER. The change path used to inline it "only so the
|
|
54
|
+
# paired tests can cite traceability ids", which made the rule true on the bootstrap path
|
|
55
|
+
# and false on the one where changes actually ship: a document in the payload is a document
|
|
56
|
+
# the generator can reason from, so a gap in a delta plan could be quietly filled from the
|
|
57
|
+
# requirement text and the plan never found to be wrong. Both paths now carry plan + model
|
|
58
|
+
# and nothing else. The ids are still cited and still required — the delta plan names the
|
|
59
|
+
# spec id each element serves, which is exactly what analyze-plan-delta conformed, and an
|
|
60
|
+
# element naming none is a planning gap to surface rather than a traceability to invent.
|
|
45
61
|
# But since the model split a plan CITES an invariant by id and never restates it, so the
|
|
46
62
|
# bounded context's domain-model.md is in context too, as the authority on the entity
|
|
47
63
|
# names, the aggregate boundary, the lifecycle states and the TEXT of every BR-nnn the plan
|
|
@@ -76,6 +92,14 @@
|
|
|
76
92
|
# found only elsewhere in the repository is the service lane's, and accepting it is how a
|
|
77
93
|
# frontend that was never scaffolded is generated into anyway and reports green.
|
|
78
94
|
#
|
|
95
|
+
# A LANE'S GAP DISABLES THAT LANE, NOT THE RUN. Three things a lane needs are checked per
|
|
96
|
+
# lane and reported per lane: its source path is on disk, its plan is there, and a project
|
|
97
|
+
# is scaffolded under it. Any of them missing skips that lane with the command that fixes
|
|
98
|
+
# it named, and every other declared lane still generates; only when NOTHING can run does
|
|
99
|
+
# the run stop, with all the reasons printed. The whole-run stop is reserved for states
|
|
100
|
+
# with no correct lane to fall back on — no lane declared at all, a lane declaring no
|
|
101
|
+
# source path, and two lanes claiming overlapping subtrees.
|
|
102
|
+
#
|
|
79
103
|
# WHAT IT DOES NOT DO. It never writes spec.md, a master plan or the domain model, and it
|
|
80
104
|
# never closes a change — finalize-delta merges the change's spec and model halves,
|
|
81
105
|
# analyze-slice verifies the slice, and close-delta archives it and bumps the version.
|
|
@@ -91,8 +115,8 @@
|
|
|
91
115
|
# =============================================================================
|
|
92
116
|
|
|
93
117
|
name: aw-spec-implement
|
|
94
|
-
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 plan and its own scaffolded project, and a lane missing
|
|
95
|
-
version: 3.
|
|
118
|
+
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.4.0
|
|
96
120
|
agent_agnostic: true
|
|
97
121
|
dialect: aw-spec.orchestrator/v1
|
|
98
122
|
|
|
@@ -138,6 +162,20 @@ vars:
|
|
|
138
162
|
delta_frontend_plan: ""
|
|
139
163
|
delta_frontend_plan_exists: "false"
|
|
140
164
|
wave: ""
|
|
165
|
+
# THE GATE RECEIPT — was this feature's plan pair ever PROVEN against this spec, and has
|
|
166
|
+
# anything moved since. analyze-plan writes it on a green master run; this phase is the
|
|
167
|
+
# reader. Bootstrap path only: a delta generates from delta plans, which analyze-plan-delta
|
|
168
|
+
# gates, and the master receipt says nothing about those.
|
|
169
|
+
gate_tracked: "false"
|
|
170
|
+
gate_fresh: "false"
|
|
171
|
+
gate_reason: ""
|
|
172
|
+
gate_at: ""
|
|
173
|
+
# DEFAULTED PERMISSIVE, DELIBERATELY, and it is the one flag here that is. Every tree that
|
|
174
|
+
# predates the receipt has none, and "never gated" is an unknown, not a stale plan —
|
|
175
|
+
# 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 no longer matches: that tree has been through
|
|
177
|
+
# the gate once, so the bytes moving since is a fact, not an absence of one.
|
|
178
|
+
may_generate: "true"
|
|
141
179
|
# PER-LANE STATE. Each lane resolves its own plan, its own project and its own answer;
|
|
142
180
|
# a lane that is not declared never resolves any of them and its steps never run.
|
|
143
181
|
# The engine has no compound conditions, so each AND is an ordered assignment: a step
|
|
@@ -182,22 +220,32 @@ workflow:
|
|
|
182
220
|
|
|
183
221
|
# 0. THE LANE MODEL. lane-verify with NO --require, because this phase requires neither
|
|
184
222
|
# kind: a backend-only and a frontend-only project are both correct states, and which
|
|
185
|
-
# lanes exist is exactly what it is here to find out.
|
|
186
|
-
#
|
|
187
|
-
#
|
|
188
|
-
#
|
|
223
|
+
# lanes exist is exactly what it is here to find out.
|
|
224
|
+
#
|
|
225
|
+
# --allow-missing-root, because a lane whose source path is not on disk is THAT LANE'S
|
|
226
|
+
# gap, not the run's. This phase is per-lane throughout — a missing plan or a missing
|
|
227
|
+
# project is reported at step 5 and the other lane still generates — and a missing root
|
|
228
|
+
# is the same kind of gap, most often a declared frontend that `foundation` has not
|
|
229
|
+
# unpacked yet. With the check left on it arrives here instead, as a whole-run stop
|
|
230
|
+
# that takes the ready lane down with it. It is re-checked per lane at step 5 from
|
|
231
|
+
# `*_root_exists`, which lane-verify reports whether or not the on-disk half is armed.
|
|
232
|
+
#
|
|
233
|
+
# What still stops the run: no lane declared at all, a lane declaring no source path,
|
|
234
|
+
# and two lanes claiming overlapping subtrees. Those are declaration errors with no
|
|
235
|
+
# correct lane to fall back to, and none of them is a state any phase can work around.
|
|
189
236
|
- id: lane_verify
|
|
190
237
|
action: execute_script
|
|
191
238
|
on_error: continue
|
|
192
239
|
script: { ref: actions }
|
|
193
240
|
subcommand: lane-verify
|
|
194
|
-
args: ["--command", "/appweaver implement"]
|
|
241
|
+
args: ["--command", "/appweaver implement", "--allow-missing-root"]
|
|
195
242
|
outputs:
|
|
196
243
|
- { name: lane_ok, from: "$.ok" }
|
|
197
244
|
- { name: lane_issues, from: "$.message" }
|
|
198
245
|
- { name: be_declared, from: "$.backend_declared" }
|
|
199
246
|
- { name: be_lane_id, from: "$.backend_lane_id" }
|
|
200
247
|
- { name: be_source_path, from: "$.backend_source_path" }
|
|
248
|
+
- { name: be_root_exists, from: "$.backend_root_exists" }
|
|
201
249
|
- { name: be_profile, from: "$.backend_profile" }
|
|
202
250
|
- { name: be_title, from: "$.backend_title" }
|
|
203
251
|
- { name: be_language, from: "$.backend_language" }
|
|
@@ -207,6 +255,7 @@ workflow:
|
|
|
207
255
|
- { name: fe_declared, from: "$.frontend_declared" }
|
|
208
256
|
- { name: fe_lane_id, from: "$.frontend_lane_id" }
|
|
209
257
|
- { name: fe_source_path, from: "$.frontend_source_path" }
|
|
258
|
+
- { name: fe_root_exists, from: "$.frontend_root_exists" }
|
|
210
259
|
- { name: fe_profile, from: "$.frontend_profile" }
|
|
211
260
|
- { name: fe_title, from: "$.frontend_title" }
|
|
212
261
|
- { name: fe_language, from: "$.frontend_language" }
|
|
@@ -318,6 +367,10 @@ workflow:
|
|
|
318
367
|
outputs:
|
|
319
368
|
- { name: cr_id, from: "$.cr_id" }
|
|
320
369
|
- { name: cr_dir, from: "$.cr_dir" }
|
|
370
|
+
# Resolved for reporting and DELIBERATELY NOT put in any context — see the header.
|
|
371
|
+
# This phase realises the delta PLAN; the requirement text reaching the generator is
|
|
372
|
+
# what lets a gap in the plan be compensated for instead of found. Do not add it to
|
|
373
|
+
# ctx_backend_delta / ctx_frontend_delta.
|
|
321
374
|
- { name: delta_spec, from: "$.delta_spec" }
|
|
322
375
|
# THIS CHANGE'S MODEL HALF — the structure the delta plans realise. It is context for
|
|
323
376
|
# every generating lane, exactly as the master model is: the delta plan cites the
|
|
@@ -350,6 +403,49 @@ workflow:
|
|
|
350
403
|
action: set
|
|
351
404
|
vars: { fe_plan: "{{delta_frontend_plan}}", fe_plan_ok: "{{delta_frontend_plan_exists}}" }
|
|
352
405
|
|
|
406
|
+
# 3b. WERE THESE PLANS PROVEN AGAINST THIS SPEC. This phase does not read spec.md — the
|
|
407
|
+
# header's reason is "analyze-plan already conformed the plans to it", which was an
|
|
408
|
+
# assumption about the order the operator ran things in and was checked by nothing:
|
|
409
|
+
# the lane gates below test that the plan FILE EXISTS and stop there. `plan`, edit
|
|
410
|
+
# spec.md, `implement` therefore generated from a plan that was never held against the
|
|
411
|
+
# spec it now contradicts, silently and at full length.
|
|
412
|
+
#
|
|
413
|
+
# plan-gate-check compares today's bytes against the receipt analyze-plan left when it
|
|
414
|
+
# passed — spec.md, the context's domain-model.md and each gated lane plan. The plans'
|
|
415
|
+
# own `**Version**:` headers cannot answer this and must not be used: close-delta stamps
|
|
416
|
+
# them and spec.md to the same number in lockstep whether or not a plan was re-derived,
|
|
417
|
+
# so the comparison reads equal always.
|
|
418
|
+
#
|
|
419
|
+
# BOOTSTRAP ONLY. A delta run generates from delta plans that analyze-plan-delta gates;
|
|
420
|
+
# the master receipt is silent about them, and reading it there would refuse a change
|
|
421
|
+
# for drift in documents this run is not building from.
|
|
422
|
+
- id: plan_gate_check
|
|
423
|
+
condition: "{{mode}} == bootstrap"
|
|
424
|
+
action: execute_script
|
|
425
|
+
script: { ref: actions }
|
|
426
|
+
subcommand: plan-gate-check
|
|
427
|
+
args: ["--feature-dir", "{{feature_dir}}"]
|
|
428
|
+
outputs:
|
|
429
|
+
- { name: gate_tracked, from: "$.tracked" }
|
|
430
|
+
- { name: gate_fresh, from: "$.gate_fresh" }
|
|
431
|
+
- { name: gate_reason, from: "$.reason" }
|
|
432
|
+
- { name: gate_at, from: "$.gated" }
|
|
433
|
+
|
|
434
|
+
# The ordered assignment is the AND: only a TRACKED feature can lower the flag, and
|
|
435
|
+
# what lowers it is the gate no longer being fresh. An untracked one never reaches
|
|
436
|
+
# this step's assignment and generates, which is the whole accommodation for trees
|
|
437
|
+
# that have not been gated since the receipt existed.
|
|
438
|
+
- id: flag_gate_block
|
|
439
|
+
condition: "{{gate_tracked}} == true"
|
|
440
|
+
action: set
|
|
441
|
+
vars: { may_generate: "{{gate_fresh}}" }
|
|
442
|
+
|
|
443
|
+
- id: require_gate_fresh
|
|
444
|
+
action: verify_context
|
|
445
|
+
require_true: may_generate
|
|
446
|
+
on_false: stop
|
|
447
|
+
on_false_message: "implement REFUSED — the master plans are no longer the ones analyze-plan passed: {{gate_reason}}. This phase generates from the plans and does NOT read the spec, on the strength of that gate having conformed them to it, so generating now would realise a plan against requirements nobody checked it against. 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."
|
|
448
|
+
|
|
353
449
|
# 4. THE PROJECT each declared lane generates INTO. Deterministic structure gate:
|
|
354
450
|
# detect-project searches the LANE'S OWN subtree for an ecosystem manifest (.sln/
|
|
355
451
|
# .csproj, pom.xml, build.gradle, package.json, go.mod, Cargo.toml, pyproject.toml),
|
|
@@ -396,6 +492,12 @@ workflow:
|
|
|
396
492
|
require_true: be_plan_ok
|
|
397
493
|
on_false: continue
|
|
398
494
|
on_false_message: "BACKEND LANE SKIPPED — lane `{{be_lane_id}}` ({{be_title}}) is declared in .appweaver/stacks.json, but the plan this run generates from is not there: {{be_plan}}. Run /appweaver plan (then /appweaver analyze-plan for the masters, or /appweaver analyze-plan-delta for a change) and re-run implement. Nothing is generated for this lane; any other declared lane still runs."
|
|
495
|
+
- id: warn_be_root
|
|
496
|
+
condition: "{{be_declared}} == true"
|
|
497
|
+
action: verify_context
|
|
498
|
+
require_true: be_root_exists
|
|
499
|
+
on_false: continue
|
|
500
|
+
on_false_message: "BACKEND LANE SKIPPED — lane `{{be_lane_id}}` ({{be_title}}) declares source path `{{be_source_path}}` in .appweaver/stacks.json, and that path is not a directory in this repository. A lane owns its subtree and this phase writes into it, so there is nothing to generate into: unpack a project there with /appweaver foundation <FoundationName> <AppName> where a bundle ships for {{be_profile}}, create one with the stack's own tooling, or re-run /appweaver select-stack and point the lane at the directory that really holds its source. Nothing is generated for this lane; any other declared lane still runs."
|
|
399
501
|
- id: warn_be_project
|
|
400
502
|
condition: "{{be_declared}} == true"
|
|
401
503
|
action: verify_context
|
|
@@ -408,6 +510,12 @@ workflow:
|
|
|
408
510
|
require_true: fe_plan_ok
|
|
409
511
|
on_false: continue
|
|
410
512
|
on_false_message: "FRONTEND LANE SKIPPED — lane `{{fe_lane_id}}` ({{fe_title}}) is declared in .appweaver/stacks.json, but the plan this run generates from is not there: {{fe_plan}}. Run /appweaver plan (then /appweaver analyze-plan for the masters, or /appweaver analyze-plan-delta for a change) and re-run implement. Nothing is generated for this lane; any other declared lane still runs."
|
|
513
|
+
- id: warn_fe_root
|
|
514
|
+
condition: "{{fe_declared}} == true"
|
|
515
|
+
action: verify_context
|
|
516
|
+
require_true: fe_root_exists
|
|
517
|
+
on_false: continue
|
|
518
|
+
on_false_message: "FRONTEND LANE SKIPPED — lane `{{fe_lane_id}}` ({{fe_title}}) declares source path `{{fe_source_path}}` in .appweaver/stacks.json, and that path is not a directory in this repository. A lane owns its subtree and this phase writes into it, so there is nothing to generate into: unpack a project there with /appweaver foundation <FoundationName> <AppName> where a bundle ships for {{fe_profile}}, create one with the stack's own tooling, or re-run /appweaver select-stack and point the lane at the directory that really holds its source. Nothing is generated for this lane; any other declared lane still runs."
|
|
411
519
|
- id: warn_fe_project
|
|
412
520
|
condition: "{{fe_declared}} == true"
|
|
413
521
|
action: verify_context
|
|
@@ -415,14 +523,18 @@ workflow:
|
|
|
415
523
|
on_false: continue
|
|
416
524
|
on_false_message: "FRONTEND LANE SKIPPED — no frontend project found under the {{fe_lane_id}} lane's source path `{{fe_source_path}}`. detect-project searched that subtree and then the whole repository, and answered at scope `{{fe_project_scope}}`; `lane` is the only scope this lane accepts. Scaffold a project there — /appweaver foundation <FoundationName> <AppName> where a bundle ships for {{fe_profile}}, or the stack's own tooling — and re-run implement. A manifest found elsewhere in the repository does NOT count: that one belongs to another lane, and generating this lane's code against it is how a frontend that was never built reports green."
|
|
417
525
|
|
|
418
|
-
# 6. RUNNABLE = declared AND its
|
|
419
|
-
#
|
|
420
|
-
# undeclared lane stays false either way —
|
|
421
|
-
# assigns.
|
|
526
|
+
# 6. RUNNABLE = declared AND its source path is on disk AND its plan is there AND its
|
|
527
|
+
# project is there, as one ordered assignment plus a knockdown per condition, since
|
|
528
|
+
# the engine has no compound conditions. An undeclared lane stays false either way —
|
|
529
|
+
# its `declared` value is what the raise assigns.
|
|
422
530
|
- id: be_runnable_raise
|
|
423
531
|
condition: "{{be_plan_ok}} == true"
|
|
424
532
|
action: set
|
|
425
533
|
vars: { be_runnable: "{{be_declared}}" }
|
|
534
|
+
- id: be_runnable_clear_root
|
|
535
|
+
condition: "{{be_root_exists}} == false"
|
|
536
|
+
action: set
|
|
537
|
+
vars: { be_runnable: "false" }
|
|
426
538
|
- id: be_runnable_clear
|
|
427
539
|
condition: "{{be_project_ok}} == false"
|
|
428
540
|
action: set
|
|
@@ -431,6 +543,10 @@ workflow:
|
|
|
431
543
|
condition: "{{fe_plan_ok}} == true"
|
|
432
544
|
action: set
|
|
433
545
|
vars: { fe_runnable: "{{fe_declared}}" }
|
|
546
|
+
- id: fe_runnable_clear_root
|
|
547
|
+
condition: "{{fe_root_exists}} == false"
|
|
548
|
+
action: set
|
|
549
|
+
vars: { fe_runnable: "false" }
|
|
434
550
|
- id: fe_runnable_clear
|
|
435
551
|
condition: "{{fe_project_ok}} == false"
|
|
436
552
|
action: set
|
|
@@ -471,7 +587,7 @@ workflow:
|
|
|
471
587
|
action: verify_context
|
|
472
588
|
require_true: generate_any
|
|
473
589
|
on_false: stop
|
|
474
|
-
on_false_message: "Nothing to implement — no declared lane is both ready and confirmed. Either every declared lane was skipped for a reason printed above (its plan or its project is missing), or each one that was ready was declined at the prompt. Backend lane declared {{be_declared}}, ready {{be_runnable}}; frontend lane declared {{fe_declared}}, ready {{fe_runnable}}. Fix the reasons named above, or re-run and confirm a lane."
|
|
590
|
+
on_false_message: "Nothing to implement — no declared lane is both ready and confirmed. Either every declared lane was skipped for a reason printed above (its source path, its plan or its project is missing), or each one that was ready was declined at the prompt. Backend lane declared {{be_declared}}, ready {{be_runnable}}; frontend lane declared {{fe_declared}}, ready {{fe_runnable}}. Fix the reasons named above, or re-run and confirm a lane."
|
|
475
591
|
|
|
476
592
|
# 8. EACH GENERATING LANE'S authoring MODE — the run's mode where the lane is going, and
|
|
477
593
|
# `skip` where it is not, which silences both of that lane's branches without a
|
|
@@ -490,18 +606,21 @@ workflow:
|
|
|
490
606
|
# backend's heading is keyed by mode (see the header). No blocking gate: an
|
|
491
607
|
# unconfigured project soft-continues, since the constitution halves still carry each
|
|
492
608
|
# lane's ratified base.
|
|
609
|
+
#
|
|
610
|
+
# EACH LANE'S RULES ARE LOADED BESIDE ITS OWN STEPS, AND THE SECOND LANE REPLACES
|
|
611
|
+
# THE FIRST'S. Both includes used to run here, before either lane generated — and
|
|
612
|
+
# sticky standards only accumulate, so on a full-stack run the backend generator was
|
|
613
|
+
# shown `## /aw-spec-implement-ui` and the frontend generator the service set. Each
|
|
614
|
+
# prompt says which lane it is in, but it said so inside an envelope that contradicted
|
|
615
|
+
# it, and the envelope is the part the model cannot argue with. The frontend include
|
|
616
|
+
# now sits immediately before the FRONTEND sections below and passes replace, which
|
|
617
|
+
# resets to the workflow's declared seed (ai-rules) before loading the UI set.
|
|
493
618
|
- id: tech_select
|
|
494
619
|
condition: "{{be_go}} == true"
|
|
495
620
|
action: include
|
|
496
621
|
module: .appweaver/orchestrator/modules/tech-select.orch.yaml
|
|
497
622
|
with: { command: "{{be_tech_command}}" }
|
|
498
623
|
|
|
499
|
-
- id: tech_select_ui
|
|
500
|
-
condition: "{{fe_go}} == true"
|
|
501
|
-
action: include
|
|
502
|
-
module: .appweaver/orchestrator/modules/tech-select.orch.yaml
|
|
503
|
-
with: { command: aw-spec-implement-ui }
|
|
504
|
-
|
|
505
624
|
# 10. Pre-execution hooks — see the hook-phase vars above.
|
|
506
625
|
- id: resolve_pre_hooks
|
|
507
626
|
action: execute_script
|
|
@@ -605,14 +724,22 @@ workflow:
|
|
|
605
724
|
# ═══════════ BACKEND LANE — delta, generate ONLY what the change adds ════════
|
|
606
725
|
# The delta plan is the authoritative source of WHAT changed — analyze-plan-delta already
|
|
607
726
|
# conformed it to the delta spec. The MASTER plan is the BASE (the unchanged elements the
|
|
608
|
-
# delta depends on)
|
|
609
|
-
#
|
|
727
|
+
# delta depends on).
|
|
728
|
+
#
|
|
729
|
+
# NO DELTA-SPEC HERE, exactly as the bootstrap path carries no spec. It used to be
|
|
730
|
+
# inlined "only so the paired tests can cite traceability ids", but a document in the
|
|
731
|
+
# payload is a document the generator can reason from, and the whole point of the
|
|
732
|
+
# contract is that this phase realises the PLAN: with the requirement text in reach, a
|
|
733
|
+
# gap in the plan can be silently compensated for from the spec and the plan is never
|
|
734
|
+
# found to be wrong. The ids are still available and still required — the delta plan
|
|
735
|
+
# cites the spec id each element serves, which is what analyze-plan-delta conformed.
|
|
736
|
+
# A plan that does not name an id is a planning gap to surface, and that is now visible
|
|
737
|
+
# instead of being papered over here.
|
|
610
738
|
- id: ctx_backend_delta
|
|
611
739
|
condition: "{{be_mode}} == delta"
|
|
612
740
|
action: build_context
|
|
613
741
|
context:
|
|
614
742
|
- { path: "{{be_plan}}" } # this change's delta-backend-plan.md
|
|
615
|
-
- { path: "{{delta_spec}}", optional: true }
|
|
616
743
|
- { path: "{{delta_model}}", optional: true } # this change's MODEL half — what it ADDS to / CHANGES in the model
|
|
617
744
|
- { path: "{{backend_plan}}", optional: true } # the master plan — READ ONLY, never amended here
|
|
618
745
|
- { path: "{{domain_model}}", optional: true } # the master model — the domain as it stands BEFORE this change
|
|
@@ -642,9 +769,12 @@ workflow:
|
|
|
642
769
|
winning wherever they differ — it is the newer statement, and the master has not
|
|
643
770
|
been merged yet (finalize-delta does that after this phase). Read there what every
|
|
644
771
|
BR-nnn the delta plan cites actually requires; the plan records WHERE each is
|
|
645
|
-
enforced and never restates it. You have NO domain rule files and NO spec
|
|
646
|
-
the
|
|
647
|
-
|
|
772
|
+
enforced and never restates it. You have NO domain rule files and NO spec AT ALL —
|
|
773
|
+
not the master and not this change's delta-spec. The requirement ids are in the
|
|
774
|
+
delta plan, which cites the one each element serves; that is the whole of what you
|
|
775
|
+
get. If a domain specific is in neither the plan nor the model, STOP and surface it
|
|
776
|
+
(it is fixed in specify / plan / analyze-plan-delta), never invent it from memory
|
|
777
|
+
and never infer it from an id.
|
|
648
778
|
- THE MODEL IS READ, NEVER MINED FOR WORK. Realise only what the DELTA PLAN calls
|
|
649
779
|
for: an item in the model delta that no delta-plan element realises is a PLANNING
|
|
650
780
|
gap — surface it, do not implement it. Everything in the master model that this
|
|
@@ -682,7 +812,10 @@ workflow:
|
|
|
682
812
|
the port isn't present, code to it and note that as the prerequisite.
|
|
683
813
|
- Author a paired test for every ADDED/MODIFIED behaviour / use-case / endpoint;
|
|
684
814
|
derive the cases from the delta plan's pre/post/invariant contracts and cite the
|
|
685
|
-
|
|
815
|
+
requirement id THE DELTA PLAN NAMES for that element (FR / BR / CN / DC / IC / US).
|
|
816
|
+
The spec is not in context: take the id from the plan and cite it verbatim, never
|
|
817
|
+
guess one from the element's shape. A delta-plan element that names no id is a
|
|
818
|
+
planning gap — surface it rather than inventing the traceability.
|
|
686
819
|
- REGRESSION: for each element in the delta plan's "Regression targets", verify (add
|
|
687
820
|
or adjust a test where needed) that the existing behaviour still holds after a
|
|
688
821
|
shared element changed — but do NOT rewrite that existing behaviour.
|
|
@@ -714,6 +847,22 @@ workflow:
|
|
|
714
847
|
outputs:
|
|
715
848
|
- { name: okf_concept, from: "$.concept" }
|
|
716
849
|
|
|
850
|
+
# ══════════════ THE LANE SWAP — the frontend's rules replace the backend's ═══
|
|
851
|
+
# build_context already scoped the two lanes' PAYLOADS apart; this is the same boundary
|
|
852
|
+
# for their STANDARDS, which the envelope carries and which nothing used to reset. It
|
|
853
|
+
# runs here rather than up with the backend's include because standards accumulate:
|
|
854
|
+
# loading both before either lane generated is precisely what showed each generator the
|
|
855
|
+
# other lane's rule set. `replace` resets to the declared seed (ai-rules stays) and then
|
|
856
|
+
# loads `## /aw-spec-implement-ui`, so from here down the envelope is the frontend's.
|
|
857
|
+
#
|
|
858
|
+
# Nothing after the frontend sections regenerates backend code — the OKF steps that
|
|
859
|
+
# follow run include_standards: false — so the swap needs no undo.
|
|
860
|
+
- id: tech_select_ui
|
|
861
|
+
condition: "{{fe_go}} == true"
|
|
862
|
+
action: include
|
|
863
|
+
module: .appweaver/orchestrator/modules/tech-select.orch.yaml
|
|
864
|
+
with: { command: aw-spec-implement-ui, replace: "true" }
|
|
865
|
+
|
|
717
866
|
# ═══════════ FRONTEND LANE — bootstrap, generate from the MASTER plan ════════
|
|
718
867
|
# The experience twin of the service generation, one lane over. Its own build_context,
|
|
719
868
|
# because the envelope persists across steps and the two lanes must not see each other's
|
|
@@ -815,7 +964,8 @@ workflow:
|
|
|
815
964
|
action: build_context
|
|
816
965
|
context:
|
|
817
966
|
- { path: "{{fe_plan}}" } # this change's delta-frontend-plan.md
|
|
818
|
-
-
|
|
967
|
+
# No delta-spec — see the service lane's note above: this phase realises the PLAN,
|
|
968
|
+
# and the ids the tests cite come from the plan's own rows.
|
|
819
969
|
- { path: "{{delta_model}}", optional: true } # this change's MODEL half — new terms, states and rules the UI must speak
|
|
820
970
|
- { path: "{{frontend_plan}}", optional: true } # the master plan — READ ONLY, never amended here
|
|
821
971
|
- { path: "{{domain_model}}", optional: true } # the master model — the ubiquitous language as it stands BEFORE this change
|
|
@@ -846,9 +996,10 @@ workflow:
|
|
|
846
996
|
READ TOGETHER, the delta winning wherever they differ — the master has not been
|
|
847
997
|
merged yet. A TERM THIS CHANGE INTRODUCES OR RENAMES IS IN THE DELTA, and the UI
|
|
848
998
|
must speak it exactly as the delta spells it, in labels, states and messages. Read
|
|
849
|
-
there what any BR-nnn the delta plan cites requires. NO domain rule files, and
|
|
850
|
-
spec
|
|
851
|
-
|
|
999
|
+
there what any BR-nnn the delta plan cites requires. NO domain rule files, and NO
|
|
1000
|
+
spec at all — not the master and not this change's delta-spec; the requirement ids
|
|
1001
|
+
come from the delta plan, which cites the one each element serves. If a domain
|
|
1002
|
+
specific is in neither the plan nor the model, STOP and surface it.
|
|
852
1003
|
- THE MODEL IS READ, NEVER MINED FOR WORK, and reading a rule is not permission to
|
|
853
1004
|
move it. Realise only what the DELTA PLAN calls for — an item in the model delta
|
|
854
1005
|
that no delta-plan element realises is a PLANNING gap, and a client-side check
|
|
@@ -872,7 +1023,9 @@ workflow:
|
|
|
872
1023
|
evaluation.
|
|
873
1024
|
- Author a paired test for every ADDED/MODIFIED screen, interaction and state,
|
|
874
1025
|
including the unwanted-behaviour states and an accessibility assertion per
|
|
875
|
-
interactive surface, citing the
|
|
1026
|
+
interactive surface, citing the requirement id THE DELTA PLAN NAMES for that row
|
|
1027
|
+
(UX-/US-/FR-/CN-/DC-/IC-/SC-). The spec is not in context: take the id from the
|
|
1028
|
+
plan and cite it verbatim. A row that names no id is a planning gap — surface it.
|
|
876
1029
|
- REGRESSION: for each element in the delta plan's regression targets, verify (add or
|
|
877
1030
|
adjust a test where needed) that the existing behaviour still holds after a shared
|
|
878
1031
|
component or state container changed — but do NOT rewrite that behaviour.
|
|
@@ -1010,5 +1163,11 @@ outputs:
|
|
|
1010
1163
|
delta_model: "{{delta_model}}" # its second half on the delta path — empty on the bootstrap path
|
|
1011
1164
|
okf_concept: "{{okf_concept}}"
|
|
1012
1165
|
xref_edge_count: "{{xref_edge_count}}"
|
|
1013
|
-
|
|
1166
|
+
# Bootstrap path only. tracked=false means this feature has never passed analyze-plan
|
|
1167
|
+
# since the gate began leaving a receipt — an unknown, not a stale plan, and it blocks
|
|
1168
|
+
# nothing.
|
|
1169
|
+
plan_gate_tracked: "{{gate_tracked}}"
|
|
1170
|
+
plan_gate_fresh: "{{gate_fresh}}"
|
|
1171
|
+
plan_gate_at: "{{gate_at}}"
|
|
1172
|
+
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. 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."
|
|
1014
1173
|
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."
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
# 1. FEATURE MAP — a HIGH-LEVEL OKF discovery index of the features/aggregates the
|
|
10
10
|
# code contains (folders/concepts + a bounded-context map + the tech stack). It
|
|
11
11
|
# is a shallow map to pick from, NOT a deep reverse — the deep per-feature
|
|
12
|
-
# reverse (spec.md +
|
|
13
|
-
# you are about to develop that feature.
|
|
12
|
+
# reverse (spec.md + the context's domain-model.md + the lane plans) is
|
|
13
|
+
# /appweaver adopt, done just-in-time when you are about to develop that feature.
|
|
14
14
|
#
|
|
15
15
|
# 2. GOVERNANCE SCAFFOLD — the PROJECT-level governing tier, established once from
|
|
16
16
|
# the whole-repo vantage so forward development is consistent from the first
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
|
|
124
124
|
name: aw-spec-onboard
|
|
125
125
|
description: Onboard an existing codebase for brownfield DEVELOPMENT — a deterministic whole-repo scan produces a high-level OKF feature map (folders/concepts) PLUS the project-level governance scaffold (split constitution + guardrails/projects/brf-<domain>/ with its DOMAIN rule files at domain/ + domain-rule-bindings + code-derived TECHNICAL rule files at service/ + tech-rule-bindings + activated domain), all provisional-from-scan and refined per slice by adopt. Where the scan finds a frontend lane in the CODE, it also authors that lane's half — constitution.ui.md (UX-*) — and its code-derived rule files at brf-<domain>/frontend/, mapped under `## /aw-spec-ui-constitution`; a backend-only repo gets none of it. Every rule tier is reverse-engineered from the CODE alone (never a greenfield rule file), evidenced-only, and WIRED per-workflow so the whole forward pipeline AND adopt govern against THIS codebase — never a greenfield fallback. It also reverse-engineers the repo's own technical structure into a project-specific design + delta-design template pair, installed as the project template overrides, and — where the lane exists — the frontend lane's own pair from the UI source. Every authoring step is shaped by a NEUTRAL rev-templates skeleton; no greenfield constitution, rule file or document template is ever placed in context. Accepts an optional concerns list to look for (onboard decides which are actually present). Reads any declared lane, never writes one. No migration content; never modifies source.
|
|
126
|
-
version: 1.
|
|
126
|
+
version: 1.7.0
|
|
127
127
|
agent_agnostic: true
|
|
128
128
|
dialect: aw-spec.orchestrator/v1
|
|
129
129
|
|
|
@@ -405,8 +405,9 @@ workflow:
|
|
|
405
405
|
|
|
406
406
|
THIS IS A MAP, NOT A DEEP REVERSE. Keep every feature concept SHALLOW — enough
|
|
407
407
|
to recognize and pick the feature to develop next. The deep per-feature reverse
|
|
408
|
-
(spec.md +
|
|
409
|
-
about to be developed. Do NOT deep-model
|
|
408
|
+
(spec.md + the context's domain-model.md + the lane plans) is /appweaver adopt, run
|
|
409
|
+
just-in-time when a feature is about to be developed. Do NOT deep-model
|
|
410
|
+
invariants/behaviour here.
|
|
410
411
|
|
|
411
412
|
Read the substrate first. Its `aggregate_signals` are CANDIDATE feature roots,
|
|
412
413
|
each with its files grouped by layer plus detected entities; `ui_attribution`
|
|
@@ -648,8 +649,8 @@ workflow:
|
|
|
648
649
|
charter; a later step in this same run authors it, so wire the bullet now), then the
|
|
649
650
|
domain identity/regulatory/interop files → domain principles.
|
|
650
651
|
- `## /aw-spec-specify` — the FULL domain set (specify models the domain, lifts CN-/DC-/IC-).
|
|
651
|
-
- `## /aw-spec-plan` — `_None —
|
|
652
|
-
- `## /aw-spec-implement` — `_None — implement loads no domain file. Domain reaches implement
|
|
652
|
+
- `## /aw-spec-plan` — `_None — plan loads no domain file. Domain reaches plan through the spec and the context's domain-model.md._`
|
|
653
|
+
- `## /aw-spec-implement` — `_None — implement loads no domain file. Domain reaches implement through the lane plans and the context's domain-model.md._`
|
|
653
654
|
- `## /aw-spec-gate` — the conformance-checklist set (the *.domain.md files).
|
|
654
655
|
Each bullet is a workspace-relative path `- guardrails/projects/{{domain_slug}}/domain/<file>`.
|
|
655
656
|
Write ONLY inside guardrails/projects/{{domain_slug}}/ (domain/ + the map). Report the
|
|
@@ -1415,7 +1416,13 @@ workflow:
|
|
|
1415
1416
|
# override_active ⇒ design_mode == bootstrap_bf) then authors EVERY new feature against the
|
|
1416
1417
|
# as-built architecture, and a CHANGE authors its delta-design against the SAME code-derived
|
|
1417
1418
|
# sections (cr-setup scaffolds the delta from resolve_template("delta-design-template") ⇒
|
|
1418
|
-
# the override) — no adopt required, consistent with the
|
|
1419
|
+
# the override) — no adopt required, consistent with the backend-plan.md adopt emits.
|
|
1420
|
+
#
|
|
1421
|
+
# THE TEMPLATE IDENTIFIERS KEEP THE `design-template` SPELLING DELIBERATELY. The DOCUMENTS
|
|
1422
|
+
# are backend-plan.md / frontend-plan.md now; the template NAMES are not, because a repo
|
|
1423
|
+
# that already ran onboard carries its override at overrides/design-template.md and
|
|
1424
|
+
# renaming the identifier would make that file stop resolving — silently falling back to
|
|
1425
|
+
# the kit's greenfield template and imposing a layering the codebase never chose.
|
|
1419
1426
|
#
|
|
1420
1427
|
# GROUNDED IN CODE + REVERSE-ENGINEERED FILES ONLY. The Part-1 OKF feature map is a SHALLOW
|
|
1421
1428
|
# discovery index (by design — NOT a deep reverse), so it is NOT the authority: the section
|
|
@@ -1597,6 +1604,83 @@ workflow:
|
|
|
1597
1604
|
on_empty: stop
|
|
1598
1605
|
on_empty_message: "No delta-design template was written to .appweaver/templates/overrides/delta-design-template.md. Re-run onboard after confirming the design template override was generated."
|
|
1599
1606
|
|
|
1607
|
+
# ═══════ CODE-DERIVED DOMAIN-MODEL TEMPLATE (the context's structure) ════════
|
|
1608
|
+
# The same argument as the design pair, for the document that carries the DOMAIN. A
|
|
1609
|
+
# bounded context's domain-model.md is where the aggregate root, its boundary, its
|
|
1610
|
+
# entities and the TEXT of every BR-nnn live; `specify` fills it on the forward path and
|
|
1611
|
+
# `adopt` fills it per reversed slice. Without a code-derived override both author
|
|
1612
|
+
# against the kit's GREENFIELD model template, whose shape assumes a domain that was
|
|
1613
|
+
# designed before it was built — the one assumption a brownfield repo is guaranteed to
|
|
1614
|
+
# break.
|
|
1615
|
+
#
|
|
1616
|
+
# NOT GATED ON A LANE. The domain model is ubiquitous language and invariants, which a
|
|
1617
|
+
# frontend-only project has as much as any other; WHERE an invariant is enforced is the
|
|
1618
|
+
# backend plan's concern and is gated with the service block above.
|
|
1619
|
+
#
|
|
1620
|
+
# A TEMPLATE OF A TEMPLATE. What this writes is not a filled model — it is the project's
|
|
1621
|
+
# domain-model TEMPLATE, keeping every [PLACEHOLDER] and authoring comment. What onboard
|
|
1622
|
+
# replaces is the STRUCTURE, never the content, and it must name NO aggregate and NO
|
|
1623
|
+
# entity: naming one would hand the downstream author the answer to the single question
|
|
1624
|
+
# the reverse exists to ask the code.
|
|
1625
|
+
- id: ctx_model_template
|
|
1626
|
+
action: build_context
|
|
1627
|
+
context:
|
|
1628
|
+
- { path: "{{inventory_json}}" } # PRIMARY: the COMPLETE deterministic substrate
|
|
1629
|
+
- { path: .appweaver/orchestrator/rev-templates/domain-model-template.skeleton.md } # SHAPE ONLY: the neutral bones + the pinned anchors
|
|
1630
|
+
- { path: "{{constitution_domain_file}}", optional: true } # the reversed DOMAIN frame — vocabulary, not structure
|
|
1631
|
+
- { path: "{{bundle_dir}}/aggregates/index.md", optional: true } # SECONDARY (shallow): the bounded-context / feature map
|
|
1632
|
+
- id: gen_model_template
|
|
1633
|
+
action: agent_generate
|
|
1634
|
+
tools: "Read,Write,Edit"
|
|
1635
|
+
permission_mode: acceptEdits
|
|
1636
|
+
task: |
|
|
1637
|
+
REVERSE-ENGINEER this repo's DOMAIN MODEL convention into a PROJECT-SPECIFIC
|
|
1638
|
+
domain-model TEMPLATE and Write it to
|
|
1639
|
+
.appweaver/templates/overrides/domain-model-template.md (create the overrides/ dir if
|
|
1640
|
+
absent). It is a TEMPLATE — section headers with [PLACEHOLDER] tokens + authoring
|
|
1641
|
+
HTML comments that `specify` (forward) and `adopt` (per reversed slice) fill per
|
|
1642
|
+
context — NOT a filled model.
|
|
1643
|
+
|
|
1644
|
+
GROUND EVERYTHING IN THE CODE. Read REPRESENTATIVE source files; the OKF map in
|
|
1645
|
+
context is a SHALLOW discovery index and corroborates, it does not decide.
|
|
1646
|
+
|
|
1647
|
+
KEEP THE PINNED ANCHORS from the skeleton in context — each is machinery something
|
|
1648
|
+
keys on, not taste:
|
|
1649
|
+
- `## Aggregate: <Name>` is the MERGE UNIT. finalize-delta merges a model delta one
|
|
1650
|
+
such section at a time, so the heading FORM cannot be reshaped per project. Keep it
|
|
1651
|
+
as ONE repeatable block.
|
|
1652
|
+
- `### Invariants` carries stable BR-nnn ids — specs cite them and the conformance
|
|
1653
|
+
gates trace them, so the id class cannot be renamed.
|
|
1654
|
+
- `**Serving specs**:` is what makes a cross-spec aggregate visible from the model
|
|
1655
|
+
side; keep it.
|
|
1656
|
+
- The Change History table is the model's version ledger. close-delta appends to it
|
|
1657
|
+
and stamps the context version; the model never writes its own.
|
|
1658
|
+
|
|
1659
|
+
WHAT YOU MAY ADAPT is everything else: which subsections an aggregate section carries
|
|
1660
|
+
and what they are CALLED, in this codebase's own vocabulary. If the code expresses
|
|
1661
|
+
structure through something it names differently, template THAT and say in a comment
|
|
1662
|
+
which code paths evidence it.
|
|
1663
|
+
|
|
1664
|
+
NAME NO AGGREGATE, NO ENTITY AND NO TECHNOLOGY. Every [BRACKET] token stays a token.
|
|
1665
|
+
Write the authoring comments so the downstream author derives from the code the way
|
|
1666
|
+
the skeleton's BROWNFIELD DERIVATION note describes — aggregate roots from the types
|
|
1667
|
+
referenced by id but never navigated into and the transaction boundaries the
|
|
1668
|
+
persistence layer commits; entity vs value object by IDENTITY; invariants from the
|
|
1669
|
+
guards and the persistence constraints, recording that the CODE is their current
|
|
1670
|
+
authority; the ubiquitous language from the names the code actually uses, recording
|
|
1671
|
+
BOTH where code and business disagree rather than silently picking one.
|
|
1672
|
+
|
|
1673
|
+
Write ONLY the override file; modify no source. Report the file written and the
|
|
1674
|
+
structural choices you derived, with the code paths that evidence them.
|
|
1675
|
+
outputs:
|
|
1676
|
+
- { name: model_template_files, from: "$.files" }
|
|
1677
|
+
|
|
1678
|
+
- id: verify_model_template
|
|
1679
|
+
action: verify_context
|
|
1680
|
+
require_non_empty: model_template_files
|
|
1681
|
+
on_empty: stop
|
|
1682
|
+
on_empty_message: "No domain-model template was written to .appweaver/templates/overrides/domain-model-template.md. Without it every reversed slice authors its aggregate against the kit's GREENFIELD model template, whose shape assumes a domain designed before it was built. Ensure the scan substrate (inventory_json) is present and re-run."
|
|
1683
|
+
|
|
1600
1684
|
# ═══════ UI DESIGN TEMPLATES (frontend lane only) — the LANE's own pair ═══════
|
|
1601
1685
|
# The lane's twin of the two steps above, on the same terms: reverse-engineered from
|
|
1602
1686
|
# the UI SOURCE, shaped by a NEUTRAL skeleton, installed in the project override slot
|
|
@@ -1820,6 +1904,7 @@ outputs:
|
|
|
1820
1904
|
delta_design_template_override: ".appweaver/templates/overrides/delta-design-template.md"
|
|
1821
1905
|
design_template_files: "{{design_template_files}}"
|
|
1822
1906
|
delta_design_template_files: "{{delta_design_template_files}}"
|
|
1907
|
+
model_template_files: "{{model_template_files}}" # the context's domain-model template — not lane-gated
|
|
1823
1908
|
# The lane's own template pair. Empty on a backend-only repo — no lane, no files.
|
|
1824
1909
|
ui_design_template_files: "{{ui_design_template_files}}"
|
|
1825
1910
|
ui_delta_design_template_files: "{{ui_delta_design_template_files}}"
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
|
|
86
86
|
name: aw-spec-plan
|
|
87
87
|
description: "Author the feature's lane plans from the spec and the bounded context's domain model — backend-plan.md when a backend lane is declared, frontend-plan.md when a frontend lane is, both when both are. Lanes come from .appweaver/stacks.json, so one command covers backend-only, frontend-only and full-stack projects; the former separate design-ui command is folded in. It ASKS what it is planning, the way implement asks what it is building: the master (`main`), one of the OPEN CHANGES, or a new plan-only change for a refactor with no spec delta — the argument doubles as the answer, and the menu appears only once a master exists, so a first run bootstraps with no prompt. `main` on a feature that already has masters RE-DERIVES them from the merged spec.md + domain-model.md — the operation finalize-delta's contract assumes when it merges a change's spec and model halves and no lane plan — and is confirmed before it rewrites anything. A change instead gets delta-backend-plan.md / delta-frontend-plan.md inside changes/<CR-id>/ while the masters stay untouched, written against the effective model (the master model, the change's own model delta, and the pending model deltas of LOWER waves, which are its predecessors) and against the feature's real source files from its OKF concept. Master authoring is template-driven: the kit's templates by default, or the code-derived as-built structure when onboard installed an override. Authoring only — a master gates at analyze-plan; a change ships through the CR chain."
|
|
88
|
-
version: 5.
|
|
88
|
+
version: 5.1.0
|
|
89
89
|
agent_agnostic: true
|
|
90
90
|
dialect: aw-spec.orchestrator/v1
|
|
91
91
|
|
|
@@ -200,18 +200,21 @@ workflow:
|
|
|
200
200
|
# project's standards are exactly what they were before the two commands merged.
|
|
201
201
|
# No blocking gate: an unconfigured project soft-continues (the constitutions still
|
|
202
202
|
# carry each lane's ratified base).
|
|
203
|
+
#
|
|
204
|
+
# ONLY THE BACKEND'S RULES LOAD HERE. The frontend's used to load alongside them,
|
|
205
|
+
# before either lane authored anything, and sticky standards only accumulate — so the
|
|
206
|
+
# service plan was authored with `## /aw-spec-plan-ui` in its envelope and the
|
|
207
|
+
# experience plan with the service set. Each prompt names its lane, but it said so
|
|
208
|
+
# inside an envelope that contradicted it. The UI set now loads at the frontend
|
|
209
|
+
# boundary instead, with `replace`, in both places a frontend document is authored:
|
|
210
|
+
# tech_select_ui_master before the master frontend sections, and the delta-plan
|
|
211
|
+
# module's own swap before the frontend delta plan.
|
|
203
212
|
- id: tech_select
|
|
204
213
|
condition: "{{be_declared}} == true"
|
|
205
214
|
action: include
|
|
206
215
|
module: .appweaver/orchestrator/modules/tech-select.orch.yaml
|
|
207
216
|
with: { command: aw-spec-plan }
|
|
208
217
|
|
|
209
|
-
- id: tech_select_ui
|
|
210
|
-
condition: "{{fe_declared}} == true"
|
|
211
|
-
action: include
|
|
212
|
-
module: .appweaver/orchestrator/modules/tech-select.orch.yaml
|
|
213
|
-
with: { command: aw-spec-plan-ui }
|
|
214
|
-
|
|
215
218
|
# 2. Resolve the current feature and require its spec.
|
|
216
219
|
- id: feature_paths
|
|
217
220
|
action: execute_script
|
|
@@ -722,6 +725,23 @@ workflow:
|
|
|
722
725
|
(the spec ids and BR-nnn that drove it). Do NOT invent a version number — the
|
|
723
726
|
version spine belongs to close-delta.
|
|
724
727
|
|
|
728
|
+
# ══════════════ THE LANE SWAP — the frontend's rules replace the backend's ═══
|
|
729
|
+
# Both tech-select includes used to run up at step 4, before either lane authored
|
|
730
|
+
# anything, and sticky standards only accumulate — so on a full-stack run the backend
|
|
731
|
+
# plan was authored with `## /aw-spec-plan-ui` in its envelope and the frontend plan with
|
|
732
|
+
# the service set. Each prompt names its lane, but it did so inside an envelope that
|
|
733
|
+
# contradicted it, and the envelope is the half the model cannot argue with.
|
|
734
|
+
#
|
|
735
|
+
# `fe_mode != skip` is what makes this the MASTER path's swap and not the delta path's:
|
|
736
|
+
# fe_mode is only set to a real mode by the master branches above, so on a `plan CR-…`
|
|
737
|
+
# run this does not fire and the delta module below does its own swap at its own
|
|
738
|
+
# frontend boundary.
|
|
739
|
+
- id: tech_select_ui_master
|
|
740
|
+
condition: "{{fe_mode}} != skip"
|
|
741
|
+
action: include
|
|
742
|
+
module: .appweaver/orchestrator/modules/tech-select.orch.yaml
|
|
743
|
+
with: { command: aw-spec-plan-ui, replace: "true" }
|
|
744
|
+
|
|
725
745
|
# ═══════════ FRONTEND LANE — bootstrap, greenfield experience template ═══════
|
|
726
746
|
# The experience twin of the service plan, and the MEDIATOR between spec.md and the
|
|
727
747
|
# frontend code. Its sections are the experience, not the four clean-architecture
|
|
@@ -993,7 +1013,14 @@ workflow:
|
|
|
993
1013
|
- { name: wave, from: "$.wave" }
|
|
994
1014
|
- { name: predecessor_files, from: "$.predecessor_files" }
|
|
995
1015
|
- { name: predecessor_count, from: "$.predecessor_count" }
|
|
1016
|
+
- { name: predecessor_ids, from: "$.predecessor_ids" }
|
|
996
1017
|
- { name: sibling_count, from: "$.sibling_count" }
|
|
1018
|
+
- { name: sibling_ids, from: "$.sibling_ids" }
|
|
1019
|
+
# Predecessors AND siblings in one list: the delta plan is authored against both, and
|
|
1020
|
+
# a build_context takes a single `context_from:` variable. Which entries are which is
|
|
1021
|
+
# carried by predecessor_ids / sibling_ids, because the planner's licence over the two
|
|
1022
|
+
# is opposite — a predecessor may be built on, a sibling may only be designed around.
|
|
1023
|
+
- { name: related_docs, from: "$.related_docs" }
|
|
997
1024
|
|
|
998
1025
|
# Author that change's delta plans — one per declared lane whose MASTER exists, inside
|
|
999
1026
|
# changes/<CR-id>/ beside its delta-spec. The masters are left UNTOUCHED; the change
|