aw-spec-cli 0.1.29 → 0.1.31
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/.amp/agent.json +22 -0
- package/assets/.amp/settings-edit.json +5 -0
- package/assets/.amp/settings-read.json +12 -0
- package/assets/.appweaver/DESIGN-FORMAT.md +9 -0
- package/assets/.appweaver/STACK-PROFILES.md +102 -15
- package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +40 -18
- package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +56 -4
- package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +17 -1
- package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +12 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +289 -24
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +370 -85
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +349 -65
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +39 -7
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +63 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +5 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +430 -138
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +392 -76
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-lane.orch.yaml +104 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +20 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +26 -3
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +314 -44
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +249 -20
- package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +17 -2
- package/assets/.appweaver/scripts/python/aw-plangate.py +109 -19
- package/assets/.appweaver/scripts/python/aw-stack.py +1295 -9
- package/assets/.appweaver/templates/delta-design-template.md +7 -5
- package/assets/.appweaver/templates/delta-spec-template.md +2 -0
- package/assets/.appweaver/templates/design-template.md +17 -0
- package/assets/.appweaver/templates/ui-design-template.md +19 -4
- package/assets/.augment/agent.json +22 -0
- package/assets/.augment/commands/appweaver.md +12 -0
- package/assets/.cline/agent.json +22 -0
- package/assets/.clinerules/workflows/appweaver.md +7 -0
- package/assets/.codex/agent.json +22 -0
- package/assets/.continue/agent.json +22 -0
- package/assets/.continue/prompts/appweaver.md +13 -0
- package/assets/.cursor/agent.json +22 -0
- package/assets/.cursor/commands/appweaver.md +7 -0
- package/assets/.devin/agent.json +22 -0
- package/assets/.devin/workflows/appweaver.md +11 -0
- package/assets/.factory/agent.json +22 -0
- package/assets/.factory/commands/appweaver.md +12 -0
- package/assets/.gemini/agent.json +22 -0
- package/assets/.github/prompts/appweaver.prompt.md +13 -0
- package/assets/.kilo/agent.json +28 -0
- package/assets/.kilo/agents/appweaver-edit.md +12 -0
- package/assets/.kilo/agents/appweaver-read.md +12 -0
- package/assets/.kilo/commands/appweaver.md +11 -0
- package/assets/.kiro/agent.json +22 -0
- package/assets/.kiro/skills/appweaver/SKILL.md +12 -0
- package/assets/.opencode/agent.json +22 -0
- package/assets/.opencode/agents/appweaver-edit.md +12 -0
- package/assets/.opencode/agents/appweaver-read.md +13 -0
- package/assets/.opencode/commands/appweaver.md +11 -0
- package/assets/.roo/agent.json +22 -0
- package/assets/.roo/commands/appweaver.md +12 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +14 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +14 -0
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/copy-assets.d.ts +16 -3
- package/dist/utils/copy-assets.d.ts.map +1 -1
- package/dist/utils/copy-assets.js +29 -14
- package/dist/utils/copy-assets.js.map +1 -1
- package/package.json +1 -1
|
@@ -16,6 +16,34 @@
|
|
|
16
16
|
# With NO lane declared at all the phase stops and names select-stack — a plan written
|
|
17
17
|
# against no declared stack invents its own.
|
|
18
18
|
#
|
|
19
|
+
# IT PLANS THE DEVELOPER'S WORKING LANE. .appweaver/lane.json (select-stack writes the
|
|
20
|
+
# default, select-lane narrows it, not committed) says which declared lanes the developer
|
|
21
|
+
# on this machine works on. Only a WORKING lane is scaffolded, authored, re-derived or
|
|
22
|
+
# delta-planned here; a lane that is declared but somebody else's is READ, never written —
|
|
23
|
+
# the frontend plan still binds to the backend plan's published surface when another
|
|
24
|
+
# developer owns it. The menu and the re-derive question below look only at the working
|
|
25
|
+
# lanes' masters, so a frontend developer planning a feature whose backend is already
|
|
26
|
+
# planned gets a first-run bootstrap of the frontend plan, with no question and no rewrite
|
|
27
|
+
# of the backend plan. With the default (every declared lane) nothing changes.
|
|
28
|
+
#
|
|
29
|
+
# A CHANGE IS PLANNED ONLY IN THE LANES IT NAMES. Each change's delta-spec carries a
|
|
30
|
+
# **Lanes** line (specify asks for it). The menu lists only the changes that touch a
|
|
31
|
+
# working lane — the others are named in the question instead — and a change's delta plans
|
|
32
|
+
# are written for the lanes that are on its line, worked here and planned already. A
|
|
33
|
+
# backend-only change gets no frontend delta plan, even from a developer on `both`. A
|
|
34
|
+
# change with no such line touches every lane.
|
|
35
|
+
#
|
|
36
|
+
# THE CONTRACT HAND-OFF BETWEEN THE TWO PLANS. Each lane's developer writes only their own
|
|
37
|
+
# plan, so what the frontend needs from the service travels as a REQUEST LEDGER:
|
|
38
|
+
# frontend-plan.md §5 "Contract deltas needed" holds one RQ-n per operation it needs and the
|
|
39
|
+
# surface lacks — every binding, when there is no backend plan yet — and backend-plan.md §3
|
|
40
|
+
# answers each in "Requests from the frontend lane", published under an operation id or
|
|
41
|
+
# declined with the reason. contract-requests reads both before each lane is authored: the
|
|
42
|
+
# backend plan is told which requests are open, the frontend plan which were answered (to
|
|
43
|
+
# re-bind) or declined (to plan around). After the backend half, contract-draft writes
|
|
44
|
+
# api-draft.json beside the plan from its API section, by script, so a frontend can
|
|
45
|
+
# generate its client against endpoints the service has planned and not built yet.
|
|
46
|
+
#
|
|
19
47
|
# ONE COMMAND, TWO LANES, TWO RULE SETS. The lanes take their rules from different
|
|
20
48
|
# headings of tech-rule-bindings (`## /aw-spec-plan-backend` for the service,
|
|
21
49
|
# `## /aw-spec-plan-frontend` for the frontend), and each set is loaded only when its lane
|
|
@@ -64,7 +92,8 @@
|
|
|
64
92
|
# analyze-slice-delta → finalize-delta → analyze-slice → close-delta.
|
|
65
93
|
# • new → open a plan-only change first, then plan it: a refactor or architectural
|
|
66
94
|
# decision where the realisation of EXISTING spec ids moves with no spec delta. Its
|
|
67
|
-
# delta-spec stays an unfilled stub, and that stub is the signal downstream.
|
|
95
|
+
# delta-spec stays an unfilled stub, and that stub is the signal downstream. It asks
|
|
96
|
+
# which lanes the change touches, as specify does, and stamps the stub's **Lanes** line.
|
|
68
97
|
# The argument doubles as the answer — `plan main`, `plan CR-…` and `plan new` all skip
|
|
69
98
|
# the prompt — and only the WHOLE argument counts, so guidance prose never selects.
|
|
70
99
|
#
|
|
@@ -88,7 +117,7 @@
|
|
|
88
117
|
|
|
89
118
|
name: aw-spec-plan
|
|
90
119
|
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."
|
|
91
|
-
version: 5.
|
|
120
|
+
version: 5.5.0
|
|
92
121
|
agent_agnostic: true
|
|
93
122
|
dialect: aw-spec.orchestrator/v1
|
|
94
123
|
|
|
@@ -125,6 +154,19 @@ vars:
|
|
|
125
154
|
fe_excluded: "false" # this feature records no surface in the declared frontend lane (feature-lanes)
|
|
126
155
|
be_lane_id: ""
|
|
127
156
|
fe_lane_id: ""
|
|
157
|
+
# THE WORKING LANES (.appweaver/lane.json) — the declared lanes this developer writes.
|
|
158
|
+
# A declared lane that is not working is READ (its plan reaches the other lane's
|
|
159
|
+
# context) and never scaffolded, authored, re-derived or delta-planned.
|
|
160
|
+
be_working: "false"
|
|
161
|
+
fe_working: "false"
|
|
162
|
+
any_working: "false"
|
|
163
|
+
working_lane: ""
|
|
164
|
+
# The backend plans AS READ CONTEXT for the frontend lane — bound only when the backend
|
|
165
|
+
# lane is declared, so a plan left behind by a removed lane never reaches the payload.
|
|
166
|
+
be_plan_read: ""
|
|
167
|
+
delta_backend_plan_read: ""
|
|
168
|
+
rederive_be_txt: ""
|
|
169
|
+
rederive_fe_txt: ""
|
|
128
170
|
active_change: ""
|
|
129
171
|
has_change: "false"
|
|
130
172
|
version: ""
|
|
@@ -134,7 +176,7 @@ vars:
|
|
|
134
176
|
fe_mode: "skip" # skip | bootstrap_gf | bootstrap_bf | update
|
|
135
177
|
be_brownfield: "false" # plan-scaffold.override_active — onboard installed the code-derived template
|
|
136
178
|
fe_brownfield: "false"
|
|
137
|
-
be_created: "false" # plan-scaffold.created —
|
|
179
|
+
be_created: "false" # plan-scaffold.created — reported only; NEW vs EXISTING is read from feature-paths before the scaffold
|
|
138
180
|
fe_created: "false"
|
|
139
181
|
be_migrated: "false" # a legacy design.md was renamed into backend-plan.md this run
|
|
140
182
|
fe_migrated: "false"
|
|
@@ -166,6 +208,21 @@ vars:
|
|
|
166
208
|
main_label: "" # cr-list --include-main's exact label, to test the selection against
|
|
167
209
|
new_label: "" # cr-list --include-new's
|
|
168
210
|
open_new: "false" # the NEW row was chosen ⇒ open a plan-only change before planning it
|
|
211
|
+
change_lane_options: [] # the NEW row's question: which lanes the plan-only change touches
|
|
212
|
+
change_lane_has: "false"
|
|
213
|
+
change_lanes_ask: "false" # open_new AND the declared stacks offer an answer
|
|
214
|
+
change_lanes: "" # the answer; empty ⇒ every declared lane is stamped
|
|
215
|
+
change_lanes_csv: "" # what the new change's **Lanes** line records
|
|
216
|
+
# THE CHANGE'S LANES. The menu lists only the changes touching the working lane(s); a
|
|
217
|
+
# change's delta plans are written only for the lanes its **Lanes** line names.
|
|
218
|
+
plan_hidden_csv: "" # open changes left out of the menu: they touch only the other lane
|
|
219
|
+
plan_hidden_note: "" # …said in the menu's question when there are any
|
|
220
|
+
plan_preselect_hidden: "" # the argument named one of those
|
|
221
|
+
preselect_visible: "true"
|
|
222
|
+
cr_lanes_csv: "" # the lanes the chosen change touches
|
|
223
|
+
cr_touches_backend: "true" # every lane until cr-paths answers
|
|
224
|
+
cr_touches_frontend: "true"
|
|
225
|
+
delta_any: "false" # some lane is left to delta-plan after that narrowing
|
|
169
226
|
has_changes: "false"
|
|
170
227
|
rederive_needed: "false" # main was chosen on a feature that already has masters
|
|
171
228
|
rederive: "false" # …and the rewrite was confirmed
|
|
@@ -178,6 +235,12 @@ vars:
|
|
|
178
235
|
model_scope_plan: "" # which part of those sections the domain layer realises
|
|
179
236
|
source_files: [] # the feature's real source files, from its OKF concept
|
|
180
237
|
source_count: "0"
|
|
238
|
+
# THE REQUEST LEDGER and the draft (contract-requests / contract-draft).
|
|
239
|
+
req_backend_text: "none" # the frontend's requests still open — what the backend plan answers
|
|
240
|
+
req_frontend_text: "none" # answered requests to re-bind and declined ones to plan around
|
|
241
|
+
req_summary: ""
|
|
242
|
+
draft_path: ""
|
|
243
|
+
draft_ops: "0"
|
|
181
244
|
|
|
182
245
|
workflow:
|
|
183
246
|
|
|
@@ -199,6 +262,9 @@ workflow:
|
|
|
199
262
|
- { name: fe_lane_id, from: "$.frontend_lane_id" }
|
|
200
263
|
- { name: fe_language, from: "$.frontend_language" }
|
|
201
264
|
- { name: fe_root, from: "$.frontend_source_path" }
|
|
265
|
+
- { name: working_lane, from: "$.working_lane" }
|
|
266
|
+
- { name: be_working, from: "$.backend_working" } # re-read per feature below
|
|
267
|
+
- { name: fe_working, from: "$.frontend_working" }
|
|
202
268
|
|
|
203
269
|
- id: require_lane
|
|
204
270
|
action: verify_context
|
|
@@ -222,7 +288,7 @@ workflow:
|
|
|
222
288
|
# tech_select_ui_master before the master frontend sections, and the delta-plan
|
|
223
289
|
# module's own swap before the frontend delta plan.
|
|
224
290
|
- id: tech_select
|
|
225
|
-
condition: "{{
|
|
291
|
+
condition: "{{be_working}} == true"
|
|
226
292
|
action: include
|
|
227
293
|
module: .appweaver/orchestrator/modules/tech-select.orch.yaml
|
|
228
294
|
with: { command: aw-spec-plan-backend }
|
|
@@ -238,6 +304,14 @@ workflow:
|
|
|
238
304
|
- { name: feature_dir, from: "$.feature_dir" }
|
|
239
305
|
- { name: spec_file, from: "$.spec_file" }
|
|
240
306
|
- { name: spec_exists, from: "$.spec_exists" }
|
|
307
|
+
# Both plans' paths and whether each is on disk (either spelling — the legacy design.md
|
|
308
|
+
# / design.ui.md resolve here too). NEW vs EXISTING per lane is decided from these,
|
|
309
|
+
# BEFORE anything is scaffolded, so a run that stops at the re-derive question leaves
|
|
310
|
+
# no template behind for the next run to mistake for an authored plan.
|
|
311
|
+
- { name: backend_plan, from: "$.backend_plan" }
|
|
312
|
+
- { name: backend_plan_exists, from: "$.backend_plan_exists" }
|
|
313
|
+
- { name: frontend_plan, from: "$.frontend_plan" }
|
|
314
|
+
- { name: frontend_plan_exists, from: "$.frontend_plan_exists" }
|
|
241
315
|
|
|
242
316
|
# THIS FEATURE'S LANES. lane_resolve above read the REPO's declaration; one feature may
|
|
243
317
|
# own no part of a lane's surface — adopt records `lanes: [backend]` in
|
|
@@ -255,6 +329,27 @@ workflow:
|
|
|
255
329
|
- { name: be_declared, from: "$.backend_declared" }
|
|
256
330
|
- { name: fe_declared, from: "$.frontend_declared" }
|
|
257
331
|
- { name: fe_excluded, from: "$.frontend_feature_excluded" }
|
|
332
|
+
- { name: be_working, from: "$.backend_working" }
|
|
333
|
+
- { name: fe_working, from: "$.frontend_working" }
|
|
334
|
+
|
|
335
|
+
# A WORKING LANE THIS FEATURE HAS. The working lanes are the developer's; the feature may
|
|
336
|
+
# record no surface in one of them (feature-lanes), and then there is nothing here for
|
|
337
|
+
# this developer to plan. Stopping says so — skipping silently would report a plan run
|
|
338
|
+
# that wrote nothing.
|
|
339
|
+
- id: any_working_be
|
|
340
|
+
condition: "{{be_working}} == true"
|
|
341
|
+
action: set
|
|
342
|
+
vars: { any_working: "true" }
|
|
343
|
+
- id: any_working_fe
|
|
344
|
+
condition: "{{fe_working}} == true"
|
|
345
|
+
action: set
|
|
346
|
+
vars: { any_working: "true" }
|
|
347
|
+
|
|
348
|
+
# The backend plan as READ context for the frontend lane, on a declared backend only.
|
|
349
|
+
- id: be_plan_read_set
|
|
350
|
+
condition: "{{be_declared}} == true"
|
|
351
|
+
action: set
|
|
352
|
+
vars: { be_plan_read: "{{backend_plan}}" }
|
|
258
353
|
|
|
259
354
|
# The BOUNDED CONTEXT's domain model — where the aggregate root, its entities and its
|
|
260
355
|
# invariants (BR-n) live. The spec cites them by id; this phase records where each is
|
|
@@ -313,6 +408,12 @@ workflow:
|
|
|
313
408
|
on_false: stop
|
|
314
409
|
on_false_message: "No spec.md for the current feature. Run /appweaver specify first."
|
|
315
410
|
|
|
411
|
+
- id: require_working_lane
|
|
412
|
+
action: verify_context
|
|
413
|
+
require_true: any_working
|
|
414
|
+
on_false: stop
|
|
415
|
+
on_false_message: "Nothing to plan for your working lane `{{working_lane}}` (.appweaver/lane.json): this feature records no surface in it (backend declared for this feature={{be_declared}}, frontend={{fe_declared}}). Run /appweaver select-lane to work on another lane, or /appweaver select-feature to plan a feature that has this lane."
|
|
416
|
+
|
|
316
417
|
# 3. Read the open change state (set by specify). The delta path uses it to decide
|
|
317
418
|
# whether there is anything to plan at all.
|
|
318
419
|
- id: read_change
|
|
@@ -340,59 +441,33 @@ workflow:
|
|
|
340
441
|
- { name: source_files, from: "$.paths" }
|
|
341
442
|
- { name: source_count, from: "$.count" }
|
|
342
443
|
|
|
343
|
-
# 5.
|
|
344
|
-
#
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
outputs:
|
|
352
|
-
- { name: backend_plan, from: "$.plan_doc" }
|
|
353
|
-
- { name: be_brownfield, from: "$.override_active" } # true ⇒ onboard installed the code-derived template
|
|
354
|
-
- { name: be_created, from: "$.created" } # true ⇒ the document was ABSENT ⇒ bootstrap
|
|
355
|
-
- { name: be_migrated, from: "$.migrated" } # true ⇒ a legacy design.md was renamed into place
|
|
356
|
-
|
|
357
|
-
- id: fe_scaffold
|
|
358
|
-
condition: "{{fe_declared}} == true"
|
|
359
|
-
action: execute_script
|
|
360
|
-
script: { ref: actions }
|
|
361
|
-
subcommand: plan-scaffold
|
|
362
|
-
args: ["--feature-dir", "{{feature_dir}}", "--lane", "frontend"]
|
|
363
|
-
outputs:
|
|
364
|
-
- { name: frontend_plan, from: "$.plan_doc" }
|
|
365
|
-
- { name: fe_brownfield, from: "$.override_active" }
|
|
366
|
-
- { name: fe_created, from: "$.created" }
|
|
367
|
-
- { name: fe_migrated, from: "$.migrated" }
|
|
368
|
-
|
|
369
|
-
# 5a. Self-detect NEW-vs-EXISTING per lane, from each plan document's OWN existence
|
|
370
|
-
# (symmetric with specify's spec.md trigger). A scaffold reports created=true only
|
|
371
|
-
# when it had to CREATE the document, so created=false on a DECLARED lane means the
|
|
372
|
-
# plan pre-existed and that lane's change is a delta.
|
|
373
|
-
# A MIGRATED document counts as pre-existing: it is the same plan under its new
|
|
374
|
-
# name, and its content was authored before this run.
|
|
375
|
-
# Taking the lane's own `declared` value under the created/not-created condition is
|
|
376
|
-
# how the AND is expressed — an undeclared lane's flags stay false either way.
|
|
444
|
+
# 5. Self-detect NEW-vs-EXISTING per WORKING lane, from each plan document's OWN
|
|
445
|
+
# existence (symmetric with specify's spec.md trigger), read off feature-paths BEFORE
|
|
446
|
+
# anything is written. A legacy design.md / design.ui.md counts as existing: it is the
|
|
447
|
+
# same plan under its old name, authored before this run, and the scaffold at 5f
|
|
448
|
+
# renames it into place.
|
|
449
|
+
# Taking the lane's own `working` value under the exists/not-exists condition is how
|
|
450
|
+
# the AND is expressed — a lane that is not worked keeps both flags false, so it is
|
|
451
|
+
# never offered, re-derived, bootstrapped or delta-planned here.
|
|
377
452
|
- id: be_flag_new
|
|
378
|
-
condition: "{{
|
|
453
|
+
condition: "{{backend_plan_exists}} == false"
|
|
379
454
|
action: set
|
|
380
|
-
vars: { be_new: "{{
|
|
455
|
+
vars: { be_new: "{{be_working}}" }
|
|
381
456
|
- id: be_flag_existing
|
|
382
|
-
condition: "{{
|
|
457
|
+
condition: "{{backend_plan_exists}} == true"
|
|
383
458
|
action: set
|
|
384
|
-
vars: { be_existing: "{{
|
|
459
|
+
vars: { be_existing: "{{be_working}}" }
|
|
385
460
|
- id: fe_flag_new
|
|
386
|
-
condition: "{{
|
|
461
|
+
condition: "{{frontend_plan_exists}} == false"
|
|
387
462
|
action: set
|
|
388
|
-
vars: { fe_new: "{{
|
|
463
|
+
vars: { fe_new: "{{fe_working}}" }
|
|
389
464
|
- id: fe_flag_existing
|
|
390
|
-
condition: "{{
|
|
465
|
+
condition: "{{frontend_plan_exists}} == true"
|
|
391
466
|
action: set
|
|
392
|
-
vars: { fe_existing: "{{
|
|
467
|
+
vars: { fe_existing: "{{fe_working}}" }
|
|
393
468
|
|
|
394
|
-
# Either
|
|
395
|
-
# ONCE. That is the precondition for both of the things the menu below offers — a delta
|
|
469
|
+
# Either WORKING lane having a pre-existing master means this feature HAS BEEN PLANNED
|
|
470
|
+
# ONCE, for this developer. That is the precondition for both of the things the menu below offers — a delta
|
|
396
471
|
# has to have a master to be a delta OF, and a re-derivation has to have a document to
|
|
397
472
|
# re-derive. The two raises are independent so neither can cancel the other.
|
|
398
473
|
- id: master_exists_backend
|
|
@@ -420,12 +495,18 @@ workflow:
|
|
|
420
495
|
# needs one to be a delta of, and so does a plan-only change. So a first run authors the
|
|
421
496
|
# masters with no prompt at all, exactly as before — and if a change is already open on
|
|
422
497
|
# such a feature, it waits for the next run, when the menu will offer it.
|
|
498
|
+
#
|
|
499
|
+
# ONLY THE CHANGES THAT TOUCH YOUR WORKING LANE. `--lane` keeps the changes whose
|
|
500
|
+
# **Lanes** line names the working lane (every change, for `both`); a change for the other
|
|
501
|
+
# lane only has no delta plan for this developer to write, and is named in the question
|
|
502
|
+
# instead of offered. It goes last in the args, where an empty value cannot be mistaken
|
|
503
|
+
# for the next flag.
|
|
423
504
|
- id: cr_list
|
|
424
505
|
condition: "{{master_exists}} == true"
|
|
425
506
|
action: execute_script
|
|
426
507
|
script: { ref: actions }
|
|
427
508
|
subcommand: cr-list
|
|
428
|
-
args: ["--feature-dir", "{{feature_dir}}", "--preselect", "{{USER_INPUT}}", "--include-main", "--include-new"]
|
|
509
|
+
args: ["--feature-dir", "{{feature_dir}}", "--preselect", "{{USER_INPUT}}", "--include-main", "--include-new", "--lane", "{{working_lane}}"]
|
|
429
510
|
outputs:
|
|
430
511
|
- { name: change_options, from: "$.select_options" }
|
|
431
512
|
- { name: matched_label, from: "$.matched_label" }
|
|
@@ -433,6 +514,25 @@ workflow:
|
|
|
433
514
|
- { name: new_label, from: "$.new_label" }
|
|
434
515
|
- { name: has_changes, from: "$.has_changes" }
|
|
435
516
|
- { name: change_count, from: "$.count" }
|
|
517
|
+
- { name: plan_hidden_csv, from: "$.hidden_ids_csv" }
|
|
518
|
+
- { name: plan_preselect_hidden, from: "$.preselect_hidden" }
|
|
519
|
+
|
|
520
|
+
# `plan CR-…` naming a change for the other lane only stops here, rather than showing a
|
|
521
|
+
# menu that leaves the named change out without saying why.
|
|
522
|
+
- id: preselect_hidden_flag
|
|
523
|
+
condition: "{{plan_preselect_hidden}} != "
|
|
524
|
+
action: set
|
|
525
|
+
vars: { preselect_visible: "false" }
|
|
526
|
+
- id: require_visible_change
|
|
527
|
+
action: verify_context
|
|
528
|
+
require_true: preselect_visible
|
|
529
|
+
on_false: stop
|
|
530
|
+
on_false_message: "Change {{plan_preselect_hidden}} does not touch your working lane `{{working_lane}}` (.appweaver/lane.json): its **Lanes** line names only the other lane, so there is no delta plan for you to write. Run /appweaver select-lane to work on that lane — or, if the change does need your lane, widen it first with `.appweaver/scripts/bash/aw-spec-actions.sh cr-lanes --cr-id {{plan_preselect_hidden}} --set both`."
|
|
531
|
+
|
|
532
|
+
- id: hidden_note_set
|
|
533
|
+
condition: "{{plan_hidden_csv}} != "
|
|
534
|
+
action: set
|
|
535
|
+
vars: { plan_hidden_note: " Not listed, because they touch only the other lane: {{plan_hidden_csv}}." }
|
|
436
536
|
|
|
437
537
|
# The argument doubles as the answer: `plan main` and `plan CR-…` both resolve to a
|
|
438
538
|
# label in matched_label and skip the prompt. Only the WHOLE argument counts as one of
|
|
@@ -440,7 +540,7 @@ workflow:
|
|
|
440
540
|
- id: pick_target
|
|
441
541
|
condition: "{{master_exists}} == true"
|
|
442
542
|
action: user_select
|
|
443
|
-
prompt: "What is being planned? `main` re-plans the feature's master from its spec and domain model. A CR row authors that change's delta plans only, leaving the masters untouched — deltas sharing a wave are independent, and a higher wave is planned on top of the lower ones. `new` opens a plan-only change, for a refactor or architectural decision with no spec delta."
|
|
543
|
+
prompt: "What is being planned? `main` re-plans the feature's master from its spec and domain model. A CR row authors that change's delta plans only, leaving the masters untouched — deltas sharing a wave are independent, and a higher wave is planned on top of the lower ones. `new` opens a plan-only change, for a refactor or architectural decision with no spec delta.{{plan_hidden_note}}"
|
|
444
544
|
options_from_variable: change_options
|
|
445
545
|
preselect_from: matched_label
|
|
446
546
|
single_option_confirm: true
|
|
@@ -482,10 +582,20 @@ workflow:
|
|
|
482
582
|
action: set
|
|
483
583
|
vars: { rederive_needed: "{{master_exists}}" }
|
|
484
584
|
|
|
585
|
+
# Which masters a yes rewrites — only the working lanes' — named in the question.
|
|
586
|
+
- id: rederive_be_named
|
|
587
|
+
condition: "{{be_existing}} == true"
|
|
588
|
+
action: set
|
|
589
|
+
vars: { rederive_be_txt: "backend-plan.md " }
|
|
590
|
+
- id: rederive_fe_named
|
|
591
|
+
condition: "{{fe_existing}} == true"
|
|
592
|
+
action: set
|
|
593
|
+
vars: { rederive_fe_txt: "frontend-plan.md " }
|
|
594
|
+
|
|
485
595
|
- id: confirm_rederive
|
|
486
596
|
condition: "{{rederive_needed}} == true"
|
|
487
597
|
action: ask
|
|
488
|
-
prompt: "This feature already has master plan(s)
|
|
598
|
+
prompt: "This feature already has the master plan(s) {{rederive_be_txt}}{{rederive_fe_txt}}for your working lane `{{working_lane}}`. Re-derive them from the current spec.md and domain-model.md? Recorded architectural decisions (DA-n) and workarounds (WA-n) are carried forward, but any section the spec and model no longer support IS REWRITTEN — including hand edits. A lane you do not work on is not touched. Answer no to stop without touching them."
|
|
489
599
|
options: ["no", "yes"]
|
|
490
600
|
answer_var: rederive_answer
|
|
491
601
|
|
|
@@ -501,6 +611,40 @@ workflow:
|
|
|
501
611
|
on_false: stop
|
|
502
612
|
on_false_message: "Stopped — the master plans were left untouched. Re-run and answer yes to re-derive them, or pick a change instead (/appweaver plan CR-…) to author that change's delta plans without touching a master."
|
|
503
613
|
|
|
614
|
+
# 5f. Scaffold each WORKING lane's plan now that the run is going ahead (idempotent — it
|
|
615
|
+
# returns the existing path when the plan is there, and RENAMES a legacy design.md /
|
|
616
|
+
# design.ui.md into the plan name). It sits after the question on purpose: a template
|
|
617
|
+
# copied in before a `no` stays on disk, and the next run reads it as a master.
|
|
618
|
+
- id: be_scaffold
|
|
619
|
+
condition: "{{be_working}} == true"
|
|
620
|
+
action: execute_script
|
|
621
|
+
script: { ref: actions }
|
|
622
|
+
subcommand: plan-scaffold
|
|
623
|
+
args: ["--feature-dir", "{{feature_dir}}", "--lane", "backend"]
|
|
624
|
+
outputs:
|
|
625
|
+
- { name: backend_plan, from: "$.plan_doc" }
|
|
626
|
+
- { name: be_brownfield, from: "$.override_active" } # true ⇒ onboard installed the code-derived template
|
|
627
|
+
- { name: be_created, from: "$.created" }
|
|
628
|
+
- { name: be_migrated, from: "$.migrated" } # true ⇒ a legacy design.md was renamed into place
|
|
629
|
+
|
|
630
|
+
- id: fe_scaffold
|
|
631
|
+
condition: "{{fe_working}} == true"
|
|
632
|
+
action: execute_script
|
|
633
|
+
script: { ref: actions }
|
|
634
|
+
subcommand: plan-scaffold
|
|
635
|
+
args: ["--feature-dir", "{{feature_dir}}", "--lane", "frontend"]
|
|
636
|
+
outputs:
|
|
637
|
+
- { name: frontend_plan, from: "$.plan_doc" }
|
|
638
|
+
- { name: fe_brownfield, from: "$.override_active" }
|
|
639
|
+
- { name: fe_created, from: "$.created" }
|
|
640
|
+
- { name: fe_migrated, from: "$.migrated" }
|
|
641
|
+
|
|
642
|
+
# The scaffold may have renamed a legacy design.md, so the READ path is taken again.
|
|
643
|
+
- id: be_plan_read_scaffolded
|
|
644
|
+
condition: "{{be_working}} == true"
|
|
645
|
+
action: set
|
|
646
|
+
vars: { be_plan_read: "{{backend_plan}}" }
|
|
647
|
+
|
|
504
648
|
# 5e. Resolve each lane's authoring MODE. Four ordered assignments per lane: the
|
|
505
649
|
# greenfield default for a new lane, the code-derived override replacing it, a
|
|
506
650
|
# `skip` for any lane that is not new — which silences both bootstrap branches on
|
|
@@ -552,6 +696,20 @@ workflow:
|
|
|
552
696
|
action: set
|
|
553
697
|
vars: { fe_mode: "update" }
|
|
554
698
|
|
|
699
|
+
# 5g. THE REQUEST LEDGER as it stands before either lane is authored — the requests the
|
|
700
|
+
# frontend plan has raised that the backend plan has not answered yet. Read by script
|
|
701
|
+
# from both plans; advisory, so a plan without the tables reads as no request.
|
|
702
|
+
- id: contract_requests_backend
|
|
703
|
+
condition: "{{be_working}} == true"
|
|
704
|
+
action: execute_script
|
|
705
|
+
on_error: continue
|
|
706
|
+
script: { ref: actions }
|
|
707
|
+
subcommand: contract-requests
|
|
708
|
+
args: ["--feature-dir", "{{feature_dir}}"]
|
|
709
|
+
outputs:
|
|
710
|
+
- { name: req_backend_text, from: "$.backend_text" }
|
|
711
|
+
- { name: req_summary, from: "$.summary" }
|
|
712
|
+
|
|
555
713
|
# 6. Pre-execution hooks.
|
|
556
714
|
- id: resolve_pre_hooks
|
|
557
715
|
action: execute_script
|
|
@@ -624,6 +782,14 @@ workflow:
|
|
|
624
782
|
service's published API document (e.g. `CreatePatient`), unique across the
|
|
625
783
|
service and never reused. The frontend plan cites it, and implement gives the
|
|
626
784
|
endpoint exactly this id, so the two lanes meet on it.
|
|
785
|
+
- ANSWER THE FRONTEND LANE'S CONTRACT REQUESTS. Still open in the frontend plan's §5
|
|
786
|
+
"Contract deltas needed": {{req_backend_text}}. Answer each one in §3's "Requests
|
|
787
|
+
from the frontend lane" table (| Request | Outcome | Operation id | Why |): PUBLISH
|
|
788
|
+
it as a §3 endpoint, under the operation id it proposes unless that clashes with
|
|
789
|
+
one this service already uses, or DECLINE it with the reason. Publish only what
|
|
790
|
+
the spec supports — a request the spec gives no basis for is declined as a spec gap
|
|
791
|
+
for /appweaver specify, never published on a guess. `none` means no request is
|
|
792
|
+
open: write `None` under that heading when the table would be empty.
|
|
627
793
|
- CONSTITUTION-MANDATED CROSS-CUTTING (from the loaded technical constitution, NOT
|
|
628
794
|
the spec): a NON-NEGOTIABLE technical principle you must apply that has NO
|
|
629
795
|
per-feature spec id. APPLY it (it is non-negotiable), and because it is not
|
|
@@ -715,6 +881,14 @@ workflow:
|
|
|
715
881
|
service's published API document, unique across the service. Where the code
|
|
716
882
|
already gives the endpoint one, record THAT id exactly as the code spells it; the
|
|
717
883
|
frontend plan cites it and implement finds the endpoint by it.
|
|
884
|
+
- ANSWER THE FRONTEND LANE'S CONTRACT REQUESTS. Still open in the frontend plan's
|
|
885
|
+
"Contract deltas needed" table: {{req_backend_text}}. Answer each one in a
|
|
886
|
+
"Requests from the frontend lane" table beside this feature's endpoints (| Request
|
|
887
|
+
| Outcome | Operation id | Why |): PUBLISH it as an endpoint, under the operation id
|
|
888
|
+
it proposes unless that clashes with one the service already uses, or DECLINE it
|
|
889
|
+
with the reason. Publish only what the spec supports — a request the spec gives no
|
|
890
|
+
basis for is declined as a spec gap for /appweaver specify. `none` means no request
|
|
891
|
+
is open: write `None` under that heading when the table would be empty.
|
|
718
892
|
- CONSTITUTION-MANDATED CROSS-CUTTING (from the loaded technical constitution, NOT
|
|
719
893
|
the spec): a NON-NEGOTIABLE technical principle with no per-feature spec id —
|
|
720
894
|
APPLY it, and LOG it as a §5 DA-n whose basis cites the mandating principle
|
|
@@ -787,6 +961,14 @@ workflow:
|
|
|
787
961
|
- OPERATION IDS ARE STABLE. Every endpoint keeps the operation id it already has —
|
|
788
962
|
the frontend plan and the built code both use it. A new endpoint gets one, unique
|
|
789
963
|
across the service; an endpoint without one gets one now.
|
|
964
|
+
- ANSWER THE FRONTEND LANE'S CONTRACT REQUESTS. Still open in the frontend plan's §5
|
|
965
|
+
"Contract deltas needed": {{req_backend_text}}. Answer each one in the "Requests
|
|
966
|
+
from the frontend lane" table of the API section (| Request | Outcome | Operation id
|
|
967
|
+
| Why |) — add the table if the document has none: PUBLISH it as an endpoint, under
|
|
968
|
+
the operation id it proposes unless that clashes with one already in use, or
|
|
969
|
+
DECLINE it with the reason. Publish only what the spec supports — a request the
|
|
970
|
+
spec gives no basis for is declined as a spec gap for /appweaver specify. Keep
|
|
971
|
+
every row the table already has. `none` means no request is open.
|
|
790
972
|
- THE CODE THAT EXISTS IS THE WHAT-IS AUTHORITY. {{source_count}} source file(s)
|
|
791
973
|
realise this feature: {{source_files}}. READ them, and where the plan and the code
|
|
792
974
|
disagree about STRUCTURE, the code is what is actually there — conform to it and
|
|
@@ -799,6 +981,34 @@ workflow:
|
|
|
799
981
|
(the spec ids and BR-nnn that drove it). Do NOT invent a version number — the
|
|
800
982
|
version spine belongs to close-delta.
|
|
801
983
|
|
|
984
|
+
# ══════════════ THE DRAFT — the backend plan's API section as a document ══════
|
|
985
|
+
# api-draft.json beside the plan, drawn by script from the API section as it now stands,
|
|
986
|
+
# so the frontend lane can generate its client against what the service has planned
|
|
987
|
+
# before the service is built. Rewritten only when it differs; removed when the plan
|
|
988
|
+
# names no endpoint. Advisory — a plan the script cannot read leaves the run going.
|
|
989
|
+
- id: contract_draft
|
|
990
|
+
condition: "{{be_working}} == true"
|
|
991
|
+
action: execute_script
|
|
992
|
+
on_error: continue
|
|
993
|
+
script: { ref: actions }
|
|
994
|
+
subcommand: contract-draft
|
|
995
|
+
args: ["--feature-dir", "{{feature_dir}}"]
|
|
996
|
+
outputs:
|
|
997
|
+
- { name: draft_path, from: "$.path" }
|
|
998
|
+
- { name: draft_ops, from: "$.operations" }
|
|
999
|
+
|
|
1000
|
+
# THE LEDGER AGAIN, for the frontend half: the backend plan may have just answered.
|
|
1001
|
+
- id: contract_requests_frontend
|
|
1002
|
+
condition: "{{fe_working}} == true"
|
|
1003
|
+
action: execute_script
|
|
1004
|
+
on_error: continue
|
|
1005
|
+
script: { ref: actions }
|
|
1006
|
+
subcommand: contract-requests
|
|
1007
|
+
args: ["--feature-dir", "{{feature_dir}}"]
|
|
1008
|
+
outputs:
|
|
1009
|
+
- { name: req_frontend_text, from: "$.frontend_text" }
|
|
1010
|
+
- { name: req_summary, from: "$.summary" }
|
|
1011
|
+
|
|
802
1012
|
# ══════════════ THE LANE SWAP — the frontend's rules replace the backend's ═══
|
|
803
1013
|
# Both tech-select includes used to run up at step 4, before either lane authored
|
|
804
1014
|
# anything, and sticky standards only accumulate — so on a full-stack run the backend
|
|
@@ -830,7 +1040,7 @@ workflow:
|
|
|
830
1040
|
- { path: "{{domain_model}}", optional: true } # the ubiquitous language this lane's labels and messages use
|
|
831
1041
|
- { path: .appweaver/DESIGN-FORMAT.md } # the design-doc contract + its frontend lane variant
|
|
832
1042
|
- { path: .appweaver/memory/constitution.ui.md, optional: true } # the lane's ratified UX-* base — optional: a lane may be declared before it is ratified
|
|
833
|
-
- { path: "{{
|
|
1043
|
+
- { path: "{{be_plan_read}}", optional: true } # §5 ONLY — the service's published surface, never its internals
|
|
834
1044
|
- id: gen_frontend
|
|
835
1045
|
condition: "{{fe_mode}} == bootstrap_gf"
|
|
836
1046
|
action: agent_author
|
|
@@ -877,14 +1087,20 @@ workflow:
|
|
|
877
1087
|
the spec's IC- ids, and where the backend plan is in context, the API contracts
|
|
878
1088
|
it states. CITE those contracts; do NOT restate, re-derive or contradict them,
|
|
879
1089
|
and introduce NO server-side behaviour, persistence assumption or handler detail.
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
1090
|
+
- WHAT THE SURFACE DOES NOT OFFER IS A CONTRACT REQUEST, never a workaround in the
|
|
1091
|
+
client: one row in §5's "Contract deltas needed" table per operation, with a new
|
|
1092
|
+
RQ-n (never renumber or reuse one), the operation id you propose, what it sends
|
|
1093
|
+
and receives as field shapes, and the spec ids it serves. The binding row that
|
|
1094
|
+
needs it cites that proposed id and names the RQ-n in its Serves cell. With NO
|
|
1095
|
+
backend plan in context, EVERY binding is a request. The backend developer
|
|
1096
|
+
answers each in the backend plan; this plan never edits that one.
|
|
1097
|
+
- THE BACKEND'S ANSWERS SO FAR: {{req_frontend_text}}. Re-bind every binding row of
|
|
1098
|
+
an answered request to the operation id the backend gave it, and plan around a
|
|
1099
|
+
declined one — or log a §8 DA-n routing the need to /appweaver specify. `none`
|
|
1100
|
+
means no answer is waiting on this plan.
|
|
884
1101
|
- EVERY §5 ROW CITES ITS OPERATION ID, copied exactly from the endpoint's
|
|
885
|
-
**Operation id** in the backend plan's §3
|
|
886
|
-
|
|
887
|
-
`—` and record it in the same §8 DA-n.
|
|
1102
|
+
**Operation id** in the backend plan's §3, or the id its request proposes —
|
|
1103
|
+
implement looks the endpoint up by it in the API document.
|
|
888
1104
|
- CONSTITUTION-MANDATED CROSS-CUTTING (from the loaded UI constitution, NOT the
|
|
889
1105
|
spec): a NON-NEGOTIABLE UX principle you must apply that has no per-feature spec
|
|
890
1106
|
id. APPLY it, and because it is not spec-derived, LOG it as a §8 DA-n whose
|
|
@@ -926,7 +1142,7 @@ workflow:
|
|
|
926
1142
|
- { path: .appweaver/DESIGN-FORMAT.md } # the design-doc contract + its frontend lane variant
|
|
927
1143
|
- { path: .appweaver/memory/constitution.ui.md, optional: true } # the lane's UX-* base, reversed by onboard from this same UI
|
|
928
1144
|
- { path: knowledge/architecture/frontend.md, optional: true } # the as-built UI architecture + the SHARED surface no slice owns
|
|
929
|
-
- { path: "{{
|
|
1145
|
+
- { path: "{{be_plan_read}}", optional: true } # §5 ONLY — the service's published surface, never its internals
|
|
930
1146
|
- id: gen_frontend_brownfield
|
|
931
1147
|
condition: "{{fe_mode}} == bootstrap_bf"
|
|
932
1148
|
action: agent_author
|
|
@@ -968,11 +1184,18 @@ workflow:
|
|
|
968
1184
|
- THE LANE BOUNDARY: bind against the service's PUBLISHED surface only — the
|
|
969
1185
|
spec's IC- ids and, where the backend plan is in context, the API contracts it
|
|
970
1186
|
states. Cite them; do not restate, re-derive or contradict them, and introduce no
|
|
971
|
-
server-side behaviour.
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
1187
|
+
server-side behaviour.
|
|
1188
|
+
- WHAT THE SURFACE LACKS IS A CONTRACT REQUEST, never a client workaround: one row
|
|
1189
|
+
in the "Contract deltas needed" table per operation, with a new RQ-n (never
|
|
1190
|
+
renumbered or reused), the operation id you propose, what it sends and receives,
|
|
1191
|
+
and the spec ids it serves; the binding row that needs it cites that id and names
|
|
1192
|
+
the RQ-n. With NO backend plan in context, EVERY binding is a request.
|
|
1193
|
+
- THE BACKEND'S ANSWERS SO FAR: {{req_frontend_text}}. Re-bind an answered
|
|
1194
|
+
request's binding rows to the id the backend gave it; plan around a declined one,
|
|
1195
|
+
or log a DA-n routing the need to /appweaver specify. `none` means nothing waits.
|
|
1196
|
+
- EVERY BINDING ROW CITES ITS OPERATION ID, copied exactly from the backend plan, or
|
|
1197
|
+
the id its request proposes — implement looks the endpoint up by it in the API
|
|
1198
|
+
document.
|
|
976
1199
|
- CONSTITUTION-MANDATED CROSS-CUTTING with no per-feature spec id: apply it, and
|
|
977
1200
|
log it as a DA-n citing the mandating principle ("per constitution.ui.md
|
|
978
1201
|
UX-<n>"). Do not fabricate a spec id for it and do not leave it uncited.
|
|
@@ -1002,7 +1225,7 @@ workflow:
|
|
|
1002
1225
|
- { path: "{{domain_model}}", optional: true } # the ubiquitous language this lane's labels and messages use
|
|
1003
1226
|
- { path: .appweaver/DESIGN-FORMAT.md } # the design-doc contract + its frontend lane variant
|
|
1004
1227
|
- { path: .appweaver/memory/constitution.ui.md, optional: true } # the lane's ratified UX-* base
|
|
1005
|
-
- { path: "{{
|
|
1228
|
+
- { path: "{{be_plan_read}}", optional: true } # §5 ONLY — the service's published surface, never its internals
|
|
1006
1229
|
- id: gen_frontend_update
|
|
1007
1230
|
condition: "{{fe_mode}} == update"
|
|
1008
1231
|
action: agent_author
|
|
@@ -1029,11 +1252,19 @@ workflow:
|
|
|
1029
1252
|
the component boundaries and naming actually there.
|
|
1030
1253
|
- THE LANE BOUNDARY IS UNCHANGED: bind against the service's PUBLISHED surface only
|
|
1031
1254
|
— the spec's IC- ids and, where the backend plan is in context, the API contracts
|
|
1032
|
-
it states.
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1255
|
+
it states.
|
|
1256
|
+
- WHAT THE SURFACE LACKS IS A CONTRACT REQUEST, never a client workaround: one row
|
|
1257
|
+
in §5's "Contract deltas needed" table per operation, with a new RQ-n, the
|
|
1258
|
+
operation id you propose, what it sends and receives, and the spec ids it serves;
|
|
1259
|
+
the binding row that needs it cites that id and names the RQ-n. KEEP every request
|
|
1260
|
+
already in the table with its id — the backend plan's answers refer to it. With NO
|
|
1261
|
+
backend plan in context, EVERY binding is a request.
|
|
1262
|
+
- THE BACKEND'S ANSWERS SO FAR: {{req_frontend_text}}. Re-bind an answered
|
|
1263
|
+
request's binding rows to the id the backend gave it; plan around a declined one,
|
|
1264
|
+
or log a §8 DA-n routing the need to /appweaver specify. `none` means nothing waits.
|
|
1265
|
+
- EVERY BINDING ROW CITES ITS OPERATION ID, copied exactly from the backend plan or
|
|
1266
|
+
the id its request proposes; a row that has none yet gets one now, and a row whose
|
|
1267
|
+
id the backend plan no longer has is re-bound.
|
|
1037
1268
|
- TECHNOLOGY-AGNOSTIC: no framework, router, state library, component library or
|
|
1038
1269
|
styling approach — responsibilities, field shapes, events and states only.
|
|
1039
1270
|
- ADD ONE Change History row for this re-derivation, describing what MOVED and why.
|
|
@@ -1048,6 +1279,33 @@ workflow:
|
|
|
1048
1279
|
# unchanged and the realisation of EXISTING spec ids moves (a refactor, an architectural
|
|
1049
1280
|
# decision). cr-setup scaffolds the delta-spec, which stays an unfilled stub on this
|
|
1050
1281
|
# path — that stub IS the signal to every downstream gate that no requirement moved.
|
|
1282
|
+
#
|
|
1283
|
+
# It is asked first which lanes the change touches, as specify asks when it opens one:
|
|
1284
|
+
# both — listed first, the default — or one lane alone, from the stacks declared, and
|
|
1285
|
+
# with one declared lane there is no question. The answer is not narrowed to this
|
|
1286
|
+
# developer's working lane: a refactor may need both lanes even when one developer
|
|
1287
|
+
# opened it. It is stamped on the stub's **Lanes** line.
|
|
1288
|
+
- id: change_lane_options
|
|
1289
|
+
condition: "{{open_new}} == true"
|
|
1290
|
+
action: execute_script
|
|
1291
|
+
script: { ref: actions }
|
|
1292
|
+
subcommand: cr-lanes
|
|
1293
|
+
outputs:
|
|
1294
|
+
- { name: change_lane_options, from: "$.select_options" }
|
|
1295
|
+
- { name: change_lane_has, from: "$.has_options" }
|
|
1296
|
+
- id: change_lanes_ask_arm
|
|
1297
|
+
condition: "{{open_new}} == true"
|
|
1298
|
+
action: set
|
|
1299
|
+
vars: { change_lanes_ask: "{{change_lane_has}}" }
|
|
1300
|
+
- id: ask_change_lanes
|
|
1301
|
+
condition: "{{change_lanes_ask}} == true"
|
|
1302
|
+
action: user_select
|
|
1303
|
+
prompt: "Which lanes does this plan-only change touch? The answer is recorded on the change's **Lanes** line as the lanes that plan and build it."
|
|
1304
|
+
options_from_variable: change_lane_options
|
|
1305
|
+
single_option_confirm: true
|
|
1306
|
+
outputs:
|
|
1307
|
+
- { name: change_lanes, from: selection }
|
|
1308
|
+
|
|
1051
1309
|
- id: open_change
|
|
1052
1310
|
condition: "{{open_new}} == true"
|
|
1053
1311
|
action: execute_script
|
|
@@ -1057,6 +1315,19 @@ workflow:
|
|
|
1057
1315
|
outputs:
|
|
1058
1316
|
- { name: opened_cr, from: "$.cr_id" }
|
|
1059
1317
|
|
|
1318
|
+
# --set goes last: an empty answer is dropped by PowerShell 5.1, and the script then
|
|
1319
|
+
# stamps every declared lane. A failure leaves the template placeholder, which reads as
|
|
1320
|
+
# every declared lane.
|
|
1321
|
+
- id: stamp_change_lanes
|
|
1322
|
+
condition: "{{open_new}} == true"
|
|
1323
|
+
action: execute_script
|
|
1324
|
+
on_error: continue
|
|
1325
|
+
script: { ref: actions }
|
|
1326
|
+
subcommand: cr-lanes
|
|
1327
|
+
args: ["--cr-id", "{{opened_cr}}", "--feature-dir", "{{feature_dir}}", "--stamp", "--set", "{{change_lanes}}"]
|
|
1328
|
+
outputs:
|
|
1329
|
+
- { name: change_lanes_csv, from: "$.lanes_csv" }
|
|
1330
|
+
|
|
1060
1331
|
# Coalesce the two ways in. An existing change arrived as a LABEL ("CR-… · wave 2 ·
|
|
1061
1332
|
# title") and the scripts take its first token; a just-opened one arrives as a bare id.
|
|
1062
1333
|
- id: cr_choice_picked
|
|
@@ -1100,16 +1371,58 @@ workflow:
|
|
|
1100
1371
|
- { name: predecessor_ids, from: "$.predecessor_ids" }
|
|
1101
1372
|
- { name: sibling_count, from: "$.sibling_count" }
|
|
1102
1373
|
- { name: sibling_ids, from: "$.sibling_ids" }
|
|
1374
|
+
# THIS CHANGE'S SERVICE HALF, as READ context for its frontend delta plan — the
|
|
1375
|
+
# contract table the experience binds to, which the backend developer may have
|
|
1376
|
+
# authored in a run of their own. Bound below only on a declared backend lane.
|
|
1377
|
+
- { name: cr_delta_backend_plan, from: "$.delta_backend_plan" }
|
|
1103
1378
|
# Predecessors AND siblings in one list: the delta plan is authored against both, and
|
|
1104
1379
|
# a build_context takes a single `context_from:` variable. Which entries are which is
|
|
1105
1380
|
# carried by predecessor_ids / sibling_ids, because the planner's licence over the two
|
|
1106
1381
|
# is opposite — a predecessor may be built on, a sibling may only be designed around.
|
|
1107
1382
|
- { name: related_docs, from: "$.related_docs" }
|
|
1383
|
+
# The lanes this change touches — its delta-spec's **Lanes** line, every lane when it
|
|
1384
|
+
# records none.
|
|
1385
|
+
- { name: cr_lanes_csv, from: "$.lanes_csv" }
|
|
1386
|
+
- { name: cr_touches_backend, from: "$.touches_backend" }
|
|
1387
|
+
- { name: cr_touches_frontend, from: "$.touches_frontend" }
|
|
1388
|
+
|
|
1389
|
+
- id: delta_backend_plan_read_set
|
|
1390
|
+
condition: "{{be_declared}} == true"
|
|
1391
|
+
action: set
|
|
1392
|
+
vars: { delta_backend_plan_read: "{{cr_delta_backend_plan}}" }
|
|
1393
|
+
|
|
1394
|
+
# ONLY THE LANES THE CHANGE NAMES. be_existing / fe_existing already mean "a working lane
|
|
1395
|
+
# with a master plan"; a lane the change's **Lanes** line leaves out is knocked down here,
|
|
1396
|
+
# so a backend-only change gets no frontend delta plan even from a developer on `both`.
|
|
1397
|
+
# This runs after every master-path use of the two flags — the delta-plan module below is
|
|
1398
|
+
# the only reader left.
|
|
1399
|
+
- id: be_not_in_change
|
|
1400
|
+
condition: "{{cr_touches_backend}} == false"
|
|
1401
|
+
action: set
|
|
1402
|
+
vars: { be_existing: "false" }
|
|
1403
|
+
- id: fe_not_in_change
|
|
1404
|
+
condition: "{{cr_touches_frontend}} == false"
|
|
1405
|
+
action: set
|
|
1406
|
+
vars: { fe_existing: "false" }
|
|
1407
|
+
- id: delta_any_be
|
|
1408
|
+
condition: "{{be_existing}} == true"
|
|
1409
|
+
action: set
|
|
1410
|
+
vars: { delta_any: "true" }
|
|
1411
|
+
- id: delta_any_fe
|
|
1412
|
+
condition: "{{fe_existing}} == true"
|
|
1413
|
+
action: set
|
|
1414
|
+
vars: { delta_any: "true" }
|
|
1415
|
+
- id: require_delta_lane
|
|
1416
|
+
condition: "{{plan_target}} == delta"
|
|
1417
|
+
action: verify_context
|
|
1418
|
+
require_true: delta_any
|
|
1419
|
+
on_false: stop
|
|
1420
|
+
on_false_message: "Change {{cr_id}} touches {{cr_lanes_csv}}, but no lane on that list is both one you work on (`{{working_lane}}`) and planned already — a delta plan needs a master plan to be a delta of (backend master on disk = {{backend_plan_exists}}, frontend = {{frontend_plan_exists}}). Run /appweaver plan main to author the missing master first, or /appweaver select-lane to work on the lane this change needs."
|
|
1108
1421
|
|
|
1109
|
-
# Author that change's delta plans — one per
|
|
1110
|
-
# changes/<CR-id>/ beside its delta-spec. The masters are left
|
|
1111
|
-
# stays OPEN and finalize-delta merges it later. Runs in this
|
|
1112
|
-
# the lane rule sets + source_files).
|
|
1422
|
+
# Author that change's delta plans — one per lane the change names that you work on and
|
|
1423
|
+
# whose MASTER exists, inside changes/<CR-id>/ beside its delta-spec. The masters are left
|
|
1424
|
+
# UNTOUCHED; the change stays OPEN and finalize-delta merges it later. Runs in this
|
|
1425
|
+
# context (shares vars + the lane rule sets + source_files).
|
|
1113
1426
|
- id: delta_plan_module
|
|
1114
1427
|
condition: "{{plan_target}} == delta"
|
|
1115
1428
|
action: include
|
|
@@ -1181,10 +1494,13 @@ outputs:
|
|
|
1181
1494
|
domain_model: "{{domain_model}}"
|
|
1182
1495
|
plan_mode: "{{plan_mode}}"
|
|
1183
1496
|
plan_target: "{{plan_target}}"
|
|
1497
|
+
working_lane: "{{working_lane}}" # the developer's working lane(s) — .appweaver/lane.json
|
|
1184
1498
|
be_mode: "{{be_mode}}"
|
|
1185
1499
|
fe_mode: "{{fe_mode}}"
|
|
1186
1500
|
version: "{{version}}"
|
|
1187
1501
|
change_id: "{{active_change}}"
|
|
1188
1502
|
source_count: "{{source_count}}"
|
|
1189
|
-
|
|
1503
|
+
api_draft: "{{draft_path}}" # api-draft.json, drafted by script from the backend plan's API section ({{draft_ops}} operation(s)) — commit it with the plan
|
|
1504
|
+
contract_requests: "{{req_summary}}" # the frontend plan's RQ-n requests and the backend plan's answers
|
|
1505
|
+
note: "This run was pointed at `{{plan_target}}` (plan_mode {{plan_mode}}); backend lane {{be_mode}}, frontend lane {{fe_mode}}. Lanes come from .appweaver/stacks.json: backend declared = {{be_declared}}, frontend declared = {{fe_declared}}; your working lane is `{{working_lane}}` (.appweaver/lane.json — backend worked = {{be_working}}, frontend worked = {{fe_working}}). A working lane gets a plan; a declared lane you do not work on is read, never written, and an undeclared one gets nothing — neither is a failure. Contract requests: {{req_summary}} — the frontend plan raises them in §5 'Contract deltas needed' and the backend plan answers them in its API section; commit the plans so the other lane's developer sees them. A lane whose mode is `update` had its MASTER re-derived from the current spec and model, with its DA-n and WA-n ledgers carried forward — that rewrite was confirmed before it ran. The domain model at {{domain_model}} was READ, never written — it is spec-tier, and this phase records where each invariant is ENFORCED rather than what it says."
|
|
1190
1506
|
next: "MAIN (masters authored or re-derived): /appweaver analyze-plan (spec↔plan gate) → implement. DELTA (change {{active_change}} open, delta plans authored): /appweaver analyze-plan-delta → implement → build → analyze-slice-delta → finalize-delta → analyze-slice → close-delta — implement is the same command on both paths and ASKS which open change it is building, so pass the id (/appweaver implement {{active_change}}) to skip the prompt (finalize-delta merges the delta into spec.md and domain-model.md — not the lane plans, which are derived from those two — but leaves the change open; analyze-slice verifies the slice against the merged masters; close-delta archives the change and bumps the minor version). Once a change has merged, /appweaver plan main re-derives the masters from the documents it merged into."
|