aw-spec-cli 0.1.28 → 0.1.30
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
|
@@ -28,6 +28,25 @@
|
|
|
28
28
|
# Plus the OVERLAY BACKSTOP (the domain gate checklist over the constraints this change
|
|
29
29
|
# touches), and the WAVE DISCIPLINE check below.
|
|
30
30
|
#
|
|
31
|
+
# ONLY THE LANES THE CHANGE NAMES. A change's delta-spec carries a **Lanes** line, and
|
|
32
|
+
# `plan` writes a delta plan only for the lanes on it. A lane it leaves out is not gated, so
|
|
33
|
+
# a backend-only change is not refused for having no frontend delta plan. A change with no
|
|
34
|
+
# such line touches every lane.
|
|
35
|
+
#
|
|
36
|
+
# ONLY THE LANES YOU WORK ON ARE GATED (.appweaver/lane.json). The change menu lists only the
|
|
37
|
+
# changes naming a working lane. A named lane you work on is gated: its delta plan must
|
|
38
|
+
# exist, is checked and is repaired on approval. A named lane somebody else works on is
|
|
39
|
+
# READ: its delta plan, once its developer has written it, is in context for check 3 and
|
|
40
|
+
# nothing else, and a gap only that plan can close is reported for its developer rather than
|
|
41
|
+
# repaired or stopped on. Its delta plan not existing yet is a note, not a refusal — check 3
|
|
42
|
+
# waits until both halves are on disk.
|
|
43
|
+
#
|
|
44
|
+
# A SERVICE CHANGE THAT BREAKS A FRONTEND BINDING IS A WARNING (contract-impact). An
|
|
45
|
+
# operation the service delta changes or removes that the master frontend plan binds to,
|
|
46
|
+
# and that the change's frontend delta plan does not name, is reported by script before the
|
|
47
|
+
# check — whatever lanes the change names. The frontend half may follow from its own
|
|
48
|
+
# developer or in a follow-up change, so it never stops the gate.
|
|
49
|
+
#
|
|
31
50
|
# PREDECESSORS, NOT SIBLINGS. A wave is a dependency level. A LOWER-wave change is
|
|
32
51
|
# committed to landing first, so this delta may be planned on top of it — and both halves
|
|
33
52
|
# of each predecessor are in context, its model delta AND its delta-spec, because a plan
|
|
@@ -53,8 +72,8 @@
|
|
|
53
72
|
# =============================================================================
|
|
54
73
|
|
|
55
74
|
name: aw-spec-analyze-plan-delta
|
|
56
|
-
description: The delta-spec↔delta-plan conformance gate for ONE open change — confirm its delta-backend-plan.md and delta-frontend-plan.md realise delta-spec.md, bind to each other's contract deltas, realise this change's domain model delta, and only MODIFY elements the masters really define. Checked against the EFFECTIVE model (domain-model.md plus this change's model delta plus every lower-wave predecessor's, whose delta-specs are in context too) and told, deterministically, which other open changes touch the same aggregates. Asks which open change it is gating when more than one
|
|
57
|
-
version: 2.
|
|
75
|
+
description: The delta-spec↔delta-plan conformance gate for ONE open change — confirm its delta-backend-plan.md and delta-frontend-plan.md realise delta-spec.md, bind to each other's contract deltas, realise this change's domain model delta, and only MODIFY elements the masters really define. Checked against the EFFECTIVE model (domain-model.md plus this change's model delta plus every lower-wave predecessor's, whose delta-specs are in context too) and told, deterministically, which other open changes touch the same aggregates. Gates only the lanes the change names that you work on — the other developer's delta plan is read for the contract check, its gaps are reported for them, and its absence is a note. Warns, by script, when the service delta changes or removes an operation the frontend binds to and the frontend half does not follow. Asks which open change it is gating when more than one names your lane; a CR id as the argument selects without a prompt. Does not modify the masters or close the change.
|
|
76
|
+
version: 2.2.0
|
|
58
77
|
agent_agnostic: true
|
|
59
78
|
dialect: aw-spec.orchestrator/v1
|
|
60
79
|
|
|
@@ -87,9 +106,13 @@ vars:
|
|
|
87
106
|
sibling_count: "0"
|
|
88
107
|
overlap_report: ""
|
|
89
108
|
# PER-LANE PRESENCE. A lane is gated when it is declared AND has a master plan (only
|
|
90
|
-
# then is there a base for a delta) AND
|
|
91
|
-
# has no compound conditions, so each AND is
|
|
92
|
-
|
|
109
|
+
# then is there a base for a delta) AND the change's **Lanes** line names it AND this
|
|
110
|
+
# change has a delta plan for it. The engine has no compound conditions, so each AND is
|
|
111
|
+
# one ordered assignment.
|
|
112
|
+
cr_lanes_csv: ""
|
|
113
|
+
cr_touches_backend: "true" # every lane until cr-paths answers
|
|
114
|
+
cr_touches_frontend: "true"
|
|
115
|
+
be_gated: "false" # declared AND a master plan exists AND the change names it
|
|
93
116
|
fe_gated: "false"
|
|
94
117
|
be_present: "false" # gated AND this change's delta plan exists ⇒ check it
|
|
95
118
|
fe_present: "false"
|
|
@@ -97,7 +120,39 @@ vars:
|
|
|
97
120
|
fe_missing: "false"
|
|
98
121
|
deltas_ok: "true"
|
|
99
122
|
any_lane: "false"
|
|
100
|
-
both_lanes: "false" # both delta plans
|
|
123
|
+
both_lanes: "false" # both delta plans in context ⇒ the contract check applies
|
|
124
|
+
# THE WORKING LANES (.appweaver/lane.json). A named lane is GATED only when it is worked;
|
|
125
|
+
# one that is not is SEEN (its delta plan read for check 3) or AWAITED (not written yet).
|
|
126
|
+
be_working: "false"
|
|
127
|
+
fe_working: "false"
|
|
128
|
+
working_lane: ""
|
|
129
|
+
work_lanes: "" # the working lanes as a csv, for plan-gaps --lanes
|
|
130
|
+
working_kind: "" # the one lane worked when one lane of two is; empty otherwise
|
|
131
|
+
report_file: "" # delta-plan-analyze-report[.<working_kind>].md in the change
|
|
132
|
+
be_named: "false" # declared AND a master AND the change names it
|
|
133
|
+
fe_named: "false"
|
|
134
|
+
be_seen: "false" # named AND its delta plan on disk ⇒ in context
|
|
135
|
+
fe_seen: "false"
|
|
136
|
+
be_awaited: "false" # named, not worked, no delta plan yet ⇒ the other developer's half
|
|
137
|
+
fe_awaited: "false"
|
|
138
|
+
no_awaited: "true"
|
|
139
|
+
awaited_txt: ""
|
|
140
|
+
apd_hidden_note: "" # open changes naming only a lane not worked here
|
|
141
|
+
apd_hidden_csv: ""
|
|
142
|
+
apd_preselect_hidden: ""
|
|
143
|
+
preselect_visible: "true"
|
|
144
|
+
# THE GAP SPLIT (plan-gaps --lanes): a gap only the other developer's delta plan can close
|
|
145
|
+
# is listed for them and neither drives the repair nor the stop.
|
|
146
|
+
own_plan_gaps: "0"
|
|
147
|
+
own_routed: "0"
|
|
148
|
+
other_gaps: "0"
|
|
149
|
+
other_csv: ""
|
|
150
|
+
own_clear: "false" # the only gaps left are the other developer's
|
|
151
|
+
gate_ok: "false"
|
|
152
|
+
no_other_gaps: "true"
|
|
153
|
+
# D4b — operations the service delta changes or removes that the frontend binds to.
|
|
154
|
+
impact_csv: ""
|
|
155
|
+
no_impact: "true"
|
|
101
156
|
be_repair: "false"
|
|
102
157
|
fe_repair: "false"
|
|
103
158
|
backend_repair: "false"
|
|
@@ -126,6 +181,7 @@ workflow:
|
|
|
126
181
|
- { name: lanes_declared, from: "$.declared" }
|
|
127
182
|
- { name: be_declared, from: "$.backend_declared" }
|
|
128
183
|
- { name: fe_declared, from: "$.frontend_declared" }
|
|
184
|
+
- { name: working_lane, from: "$.working_lane" }
|
|
129
185
|
|
|
130
186
|
- id: require_lane
|
|
131
187
|
action: verify_context
|
|
@@ -166,6 +222,20 @@ workflow:
|
|
|
166
222
|
- { name: be_declared, from: "$.backend_declared" }
|
|
167
223
|
- { name: fe_declared, from: "$.frontend_declared" }
|
|
168
224
|
- { name: fe_excluded, from: "$.frontend_feature_excluded" }
|
|
225
|
+
- { name: be_working, from: "$.backend_working" }
|
|
226
|
+
- { name: fe_working, from: "$.frontend_working" }
|
|
227
|
+
- { name: working_kind, from: "$.working_kind" }
|
|
228
|
+
|
|
229
|
+
# The working lanes as one csv for plan-gaps — an ordered pair of sets; an empty item
|
|
230
|
+
# left by the second is dropped by plan-gaps.
|
|
231
|
+
- id: work_lanes_be
|
|
232
|
+
condition: "{{be_working}} == true"
|
|
233
|
+
action: set
|
|
234
|
+
vars: { work_lanes: "backend" }
|
|
235
|
+
- id: work_lanes_fe
|
|
236
|
+
condition: "{{fe_working}} == true"
|
|
237
|
+
action: set
|
|
238
|
+
vars: { work_lanes: "{{work_lanes}},frontend" }
|
|
169
239
|
|
|
170
240
|
- id: require_feature
|
|
171
241
|
action: verify_context
|
|
@@ -180,25 +250,43 @@ workflow:
|
|
|
180
250
|
on_false_message: "No spec.md for the current feature. Run /appweaver specify (and /appweaver plan) first."
|
|
181
251
|
|
|
182
252
|
# 2. WHICH CHANGES ARE OPEN. The evidence is changes/<cr-id>/ on disk; a closed change
|
|
183
|
-
# has moved to changes/archive/.
|
|
253
|
+
# has moved to changes/archive/. Only the changes naming a working lane on their
|
|
254
|
+
# **Lanes** line are listed (`--lane`, last in the args so an empty value cannot be
|
|
255
|
+
# mistaken for the next flag). `matched_label` resolves a CR id passed as the
|
|
184
256
|
# command's argument to the whole option string, so the pick below can auto-select it
|
|
185
257
|
# — the engine matches a preselection against the option text exactly.
|
|
186
258
|
- id: cr_list
|
|
187
259
|
action: execute_script
|
|
188
260
|
script: { ref: actions }
|
|
189
261
|
subcommand: cr-list
|
|
190
|
-
args: ["--feature-dir", "{{feature_dir}}", "--preselect", "{{USER_INPUT}}"]
|
|
262
|
+
args: ["--feature-dir", "{{feature_dir}}", "--preselect", "{{USER_INPUT}}", "--lane", "{{working_lane}}"]
|
|
191
263
|
outputs:
|
|
192
264
|
- { name: change_options, from: "$.select_options" }
|
|
193
265
|
- { name: matched_label, from: "$.matched_label" }
|
|
194
266
|
- { name: has_changes, from: "$.has_changes" }
|
|
195
267
|
- { name: change_count, from: "$.count" }
|
|
268
|
+
- { name: apd_hidden_csv, from: "$.hidden_ids_csv" }
|
|
269
|
+
- { name: apd_preselect_hidden, from: "$.preselect_hidden" }
|
|
270
|
+
|
|
271
|
+
- id: preselect_hidden_flag
|
|
272
|
+
condition: "{{apd_preselect_hidden}} != "
|
|
273
|
+
action: set
|
|
274
|
+
vars: { preselect_visible: "false" }
|
|
275
|
+
- id: require_visible_change
|
|
276
|
+
action: verify_context
|
|
277
|
+
require_true: preselect_visible
|
|
278
|
+
on_false: stop
|
|
279
|
+
on_false_message: "Change {{apd_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 of yours to gate. Its own lane's developer gates it — or run /appweaver select-lane to work on that lane."
|
|
280
|
+
- id: hidden_note_set
|
|
281
|
+
condition: "{{apd_hidden_csv}} != "
|
|
282
|
+
action: set
|
|
283
|
+
vars: { apd_hidden_note: " Open for a lane you do not work on, and not listed: {{apd_hidden_csv}}." }
|
|
196
284
|
|
|
197
285
|
- id: require_change
|
|
198
286
|
action: verify_context
|
|
199
287
|
require_true: has_changes
|
|
200
288
|
on_false: stop
|
|
201
|
-
on_false_message: "No open change on this feature — there is no delta to gate. Run /appweaver specify <change> (which opens the change and writes its delta-spec + model delta), then /appweaver plan to author its delta plans, then re-run analyze-plan-delta. To re-anchor the MASTERS instead, run /appweaver analyze-plan."
|
|
289
|
+
on_false_message: "No open change on this feature names your working lane `{{working_lane}}` — there is no delta to gate.{{apd_hidden_note}} Run /appweaver specify <change> (which opens the change and writes its delta-spec + model delta), then /appweaver plan to author its delta plans, then re-run analyze-plan-delta. To re-anchor the MASTERS instead, run /appweaver analyze-plan."
|
|
202
290
|
|
|
203
291
|
# 2b. Ask which one. A CR id in the argument auto-selects via matched_label; a feature
|
|
204
292
|
# with exactly one open change auto-confirms.
|
|
@@ -246,6 +334,11 @@ workflow:
|
|
|
246
334
|
- { name: predecessor_count, from: "$.predecessor_count" }
|
|
247
335
|
- { name: sibling_count, from: "$.sibling_count" }
|
|
248
336
|
- { name: domain_model, from: "$.domain_model" }
|
|
337
|
+
# The lanes this change touches — its delta-spec's **Lanes** line, every lane when it
|
|
338
|
+
# records none.
|
|
339
|
+
- { name: cr_lanes_csv, from: "$.lanes_csv" }
|
|
340
|
+
- { name: cr_touches_backend, from: "$.touches_backend" }
|
|
341
|
+
- { name: cr_touches_frontend, from: "$.touches_frontend" }
|
|
249
342
|
|
|
250
343
|
# 3b. WHICH OTHER OPEN CHANGES TOUCH THE SAME AGGREGATES. Deterministic: each pending
|
|
251
344
|
# model delta's `**Aggregates touched**:` header names the `## Aggregate:` sections
|
|
@@ -264,7 +357,8 @@ workflow:
|
|
|
264
357
|
- { name: predecessor_overlaps, from: "$.predecessor_overlaps" }
|
|
265
358
|
|
|
266
359
|
# 4. WHICH LANES ARE GATED. Declared AND a master plan exists (only then is there a base
|
|
267
|
-
# for a delta) — then split on whether this
|
|
360
|
+
# for a delta) AND named on the change's **Lanes** line — then split on whether this
|
|
361
|
+
# change has that lane's delta plan.
|
|
268
362
|
# A lane whose MASTER was bootstrapped in the same `plan` run has no delta plan by
|
|
269
363
|
# design: it was authored from the whole spec and there is nothing for a delta to
|
|
270
364
|
# add. Keying on the master's presence is what keeps that case out of the gate.
|
|
@@ -276,6 +370,56 @@ workflow:
|
|
|
276
370
|
condition: "{{frontend_plan_exists}} == true"
|
|
277
371
|
action: set
|
|
278
372
|
vars: { fe_gated: "{{fe_declared}}" }
|
|
373
|
+
# A lane the change's **Lanes** line leaves out has no part in it: no delta plan is
|
|
374
|
+
# written for it, so none is required here.
|
|
375
|
+
- id: be_not_in_change
|
|
376
|
+
condition: "{{cr_touches_backend}} == false"
|
|
377
|
+
action: set
|
|
378
|
+
vars: { be_gated: "false" }
|
|
379
|
+
- id: fe_not_in_change
|
|
380
|
+
condition: "{{cr_touches_frontend}} == false"
|
|
381
|
+
action: set
|
|
382
|
+
vars: { fe_gated: "false" }
|
|
383
|
+
# NAMED is kept before the working-lane knockdown: a named lane somebody else works on is
|
|
384
|
+
# read, not gated.
|
|
385
|
+
- id: be_named_set
|
|
386
|
+
action: set
|
|
387
|
+
vars: { be_named: "{{be_gated}}" }
|
|
388
|
+
- id: fe_named_set
|
|
389
|
+
action: set
|
|
390
|
+
vars: { fe_named: "{{fe_gated}}" }
|
|
391
|
+
- id: be_not_worked
|
|
392
|
+
condition: "{{be_working}} == false"
|
|
393
|
+
action: set
|
|
394
|
+
vars: { be_gated: "false" }
|
|
395
|
+
- id: fe_not_worked
|
|
396
|
+
condition: "{{fe_working}} == false"
|
|
397
|
+
action: set
|
|
398
|
+
vars: { fe_gated: "false" }
|
|
399
|
+
- id: be_flag_seen
|
|
400
|
+
condition: "{{delta_backend_plan_exists}} == true"
|
|
401
|
+
action: set
|
|
402
|
+
vars: { be_seen: "{{be_named}}" }
|
|
403
|
+
- id: fe_flag_seen
|
|
404
|
+
condition: "{{delta_frontend_plan_exists}} == true"
|
|
405
|
+
action: set
|
|
406
|
+
vars: { fe_seen: "{{fe_named}}" }
|
|
407
|
+
- id: be_flag_awaited
|
|
408
|
+
condition: "{{delta_backend_plan_exists}} == false"
|
|
409
|
+
action: set
|
|
410
|
+
vars: { be_awaited: "{{be_named}}" }
|
|
411
|
+
- id: be_awaited_mine
|
|
412
|
+
condition: "{{be_working}} == true"
|
|
413
|
+
action: set
|
|
414
|
+
vars: { be_awaited: "false" }
|
|
415
|
+
- id: fe_flag_awaited
|
|
416
|
+
condition: "{{delta_frontend_plan_exists}} == false"
|
|
417
|
+
action: set
|
|
418
|
+
vars: { fe_awaited: "{{fe_named}}" }
|
|
419
|
+
- id: fe_awaited_mine
|
|
420
|
+
condition: "{{fe_working}} == true"
|
|
421
|
+
action: set
|
|
422
|
+
vars: { fe_awaited: "false" }
|
|
279
423
|
- id: be_flag_present
|
|
280
424
|
condition: "{{delta_backend_plan_exists}} == true"
|
|
281
425
|
action: set
|
|
@@ -304,11 +448,47 @@ workflow:
|
|
|
304
448
|
action: set
|
|
305
449
|
vars: { deltas_ok: "false" }
|
|
306
450
|
|
|
451
|
+
# The other developer's half, not written yet: said, never refused. Only a lane that is
|
|
452
|
+
# not worked can be awaited, so at most one is.
|
|
453
|
+
- id: awaited_be_txt
|
|
454
|
+
condition: "{{be_awaited}} == true"
|
|
455
|
+
action: set
|
|
456
|
+
vars: { awaited_txt: "backend", no_awaited: "false" }
|
|
457
|
+
- id: awaited_fe_txt
|
|
458
|
+
condition: "{{fe_awaited}} == true"
|
|
459
|
+
action: set
|
|
460
|
+
vars: { awaited_txt: "frontend", no_awaited: "false" }
|
|
461
|
+
- id: note_awaited
|
|
462
|
+
action: verify_context
|
|
463
|
+
require_true: no_awaited
|
|
464
|
+
on_false: continue
|
|
465
|
+
on_false_message: "NOTE — change {{cr_id}} also names the {{awaited_txt}} lane, whose developer has not written its delta plan yet. This run gates your half only; the contract between the two halves (check 3) is checked once both delta plans are on disk."
|
|
466
|
+
|
|
467
|
+
# D4b. What the service delta changes or removes that the frontend binds to, by script.
|
|
468
|
+
- id: contract_impact
|
|
469
|
+
condition: "{{delta_backend_plan_exists}} == true"
|
|
470
|
+
action: execute_script
|
|
471
|
+
on_error: continue
|
|
472
|
+
script: { ref: actions }
|
|
473
|
+
subcommand: contract-impact
|
|
474
|
+
args: ["--delta-backend", "{{delta_backend_plan}}", "--frontend-plan", "{{frontend_plan}}", "--delta-frontend", "{{delta_frontend_plan}}"]
|
|
475
|
+
outputs:
|
|
476
|
+
- { name: impact_csv, from: "$.unaddressed_csv" }
|
|
477
|
+
- id: impact_flag
|
|
478
|
+
condition: "{{impact_csv}} != "
|
|
479
|
+
action: set
|
|
480
|
+
vars: { no_impact: "false" }
|
|
481
|
+
- id: warn_contract_impact
|
|
482
|
+
action: verify_context
|
|
483
|
+
require_true: no_impact
|
|
484
|
+
on_false: continue
|
|
485
|
+
on_false_message: "WARNING — change {{cr_id}} changes or removes operation(s) the frontend plan binds to, and its frontend delta plan does not carry the matching change: {{impact_csv}}. The change names {{cr_lanes_csv}}. Until the frontend follows, it calls an operation the service is changing: the frontend half of this change carries it (if the change names only the backend, widen it with `.appweaver/scripts/bash/aw-spec-actions.sh cr-lanes --cr-id {{cr_id}} --set both`, then the frontend developer runs /appweaver plan {{cr_id}}), or a follow-up change does."
|
|
486
|
+
|
|
307
487
|
- id: require_deltas
|
|
308
488
|
action: verify_context
|
|
309
489
|
require_true: deltas_ok
|
|
310
490
|
on_false: stop
|
|
311
|
-
on_false_message: "Change {{cr_id}} has no delta plan for a lane that has a master plan (backend missing={{be_missing}} · frontend missing={{fe_missing}}). Run /appweaver plan {{cr_id}} — it authors that change's delta plan for every lane whose master exists, against the delta spec, the effective model and the feature's real source files. This gate validates a delta plan; it does not write one."
|
|
491
|
+
on_false_message: "Change {{cr_id}} has no delta plan for a lane it touches ({{cr_lanes_csv}}) that has a master plan (backend missing={{be_missing}} · frontend missing={{fe_missing}}). Run /appweaver plan {{cr_id}} — it authors that change's delta plan for every lane the change names whose master exists, against the delta spec, the effective model and the feature's real source files. This gate validates a delta plan; it does not write one."
|
|
312
492
|
|
|
313
493
|
- id: any_backend
|
|
314
494
|
condition: "{{be_present}} == true"
|
|
@@ -325,15 +505,17 @@ workflow:
|
|
|
325
505
|
on_false: stop
|
|
326
506
|
on_false_message: "Change {{cr_id}} has no delta plan to gate on any declared lane. Run /appweaver plan {{cr_id}} first."
|
|
327
507
|
|
|
328
|
-
# Check 3 needs BOTH delta plans. One more ordered
|
|
508
|
+
# Check 3 needs BOTH delta plans in context — gated or only read. One more ordered
|
|
509
|
+
# assignment.
|
|
329
510
|
- id: flag_both_lanes
|
|
330
|
-
condition: "{{
|
|
511
|
+
condition: "{{be_seen}} == true"
|
|
331
512
|
action: set
|
|
332
|
-
vars: { both_lanes: "{{
|
|
513
|
+
vars: { both_lanes: "{{fe_seen}}" }
|
|
333
514
|
|
|
334
515
|
# Bind the CONTEXT paths per lane: the master (the base a MODIFIED element must name) for
|
|
335
|
-
# a gated lane, the delta plan
|
|
336
|
-
# empty, so its documents never reach the
|
|
516
|
+
# a gated lane, the delta plan — and its master — for a lane whose delta plan is in
|
|
517
|
+
# context. A lane that is neither leaves both empty, so its documents never reach the
|
|
518
|
+
# payload.
|
|
337
519
|
- id: be_master_ctx_path
|
|
338
520
|
condition: "{{be_gated}} == true"
|
|
339
521
|
action: set
|
|
@@ -343,13 +525,23 @@ workflow:
|
|
|
343
525
|
action: set
|
|
344
526
|
vars: { fe_master_ctx: "{{frontend_plan}}" }
|
|
345
527
|
- id: be_delta_ctx_path
|
|
346
|
-
condition: "{{
|
|
528
|
+
condition: "{{be_seen}} == true"
|
|
347
529
|
action: set
|
|
348
530
|
vars: { be_delta_ctx: "{{delta_backend_plan}}" }
|
|
349
531
|
- id: fe_delta_ctx_path
|
|
350
|
-
condition: "{{
|
|
532
|
+
condition: "{{fe_seen}} == true"
|
|
351
533
|
action: set
|
|
352
534
|
vars: { fe_delta_ctx: "{{delta_frontend_plan}}" }
|
|
535
|
+
# A read lane's master too: check 3(d) holds the experience delta to what the master
|
|
536
|
+
# frontend plan uses, whichever developer runs it.
|
|
537
|
+
- id: be_master_ctx_seen
|
|
538
|
+
condition: "{{be_seen}} == true"
|
|
539
|
+
action: set
|
|
540
|
+
vars: { be_master_ctx: "{{backend_plan}}" }
|
|
541
|
+
- id: fe_master_ctx_seen
|
|
542
|
+
condition: "{{fe_seen}} == true"
|
|
543
|
+
action: set
|
|
544
|
+
vars: { fe_master_ctx: "{{frontend_plan}}" }
|
|
353
545
|
|
|
354
546
|
# 4b. Load the domain GATE overlays (the domain-rule-bindings `/aw-spec-gate` checklist)
|
|
355
547
|
# as the conformance checklist — VALIDATION input only, NEVER authoring. analyze sees
|
|
@@ -398,6 +590,17 @@ workflow:
|
|
|
398
590
|
- { path: "{{fe_master_ctx}}", optional: true } # every MODIFIED element must name
|
|
399
591
|
- { path: "{{domain_model}}", optional: true } # the canonical model (READ ONLY)
|
|
400
592
|
|
|
593
|
+
# The report "Report and Skip" writes. A developer working one lane of two writes their
|
|
594
|
+
# own, delta-plan-analyze-report.<lane>.md, so two developers gating the same change never
|
|
595
|
+
# rewrite each other's report; a developer on every lane writes delta-plan-analyze-report.md.
|
|
596
|
+
- id: report_file_set
|
|
597
|
+
action: set
|
|
598
|
+
vars: { report_file: "{{cr_dir}}/delta-plan-analyze-report.md" }
|
|
599
|
+
- id: report_file_lane
|
|
600
|
+
condition: "{{working_kind}} != "
|
|
601
|
+
action: set
|
|
602
|
+
vars: { report_file: "{{cr_dir}}/delta-plan-analyze-report.{{working_kind}}.md" }
|
|
603
|
+
|
|
401
604
|
# 7. Conformance + REPAIR loop (the delta spec is the anchor): check → REPORT gaps +
|
|
402
605
|
# ASK → Repair on approval → re-check; "Report and Skip" writes the report + stops.
|
|
403
606
|
# Bounded (3×). The repair is PER LANE, so a frontend drift never rewrites a
|
|
@@ -416,8 +619,14 @@ workflow:
|
|
|
416
619
|
delta-spec.md is the ANCHOR for change {{cr_id}} (wave {{wave}}). Gate this
|
|
417
620
|
change's DELTA PLANS against it, against the masters they change, and against the
|
|
418
621
|
effective domain model, and list EVERY drift as a gap. Run the checks that apply
|
|
419
|
-
— service delta
|
|
420
|
-
both
|
|
622
|
+
— service delta in context: {{be_seen}}, experience delta in context: {{fe_seen}},
|
|
623
|
+
both: {{both_lanes}}. A check for an absent lane is SKIPPED, not failed.
|
|
624
|
+
WHICH DELTA PLANS ARE GATED: service {{be_present}}, experience {{fe_present}} —
|
|
625
|
+
the lanes the developer running this works on. Run checks 1, 2, 4 and 5 for a
|
|
626
|
+
GATED delta plan only. A delta plan in context and NOT gated belongs to another
|
|
627
|
+
developer: read it for check 3, where the two halves of the contract meet, and
|
|
628
|
+
nothing else. Every gap still carries the `lane` whose document must change to
|
|
629
|
+
close it, even when that lane is not gated here.
|
|
421
630
|
|
|
422
631
|
CHECK 1 — delta-spec.md → delta-backend-plan.md (when it is in context):
|
|
423
632
|
(a) every ADDED / MODIFIED delta-spec item — FR / BR / CN- / DC- / IC- / user
|
|
@@ -533,6 +742,41 @@ workflow:
|
|
|
533
742
|
- id: conform_break
|
|
534
743
|
action: break
|
|
535
744
|
condition: "{{analyze_ok}} == true"
|
|
745
|
+
|
|
746
|
+
# WHO CAN CLOSE EACH GAP. A gap tagged with a lane this developer does not work on is
|
|
747
|
+
# the other developer's: it is listed under `other` and, when nothing else is left,
|
|
748
|
+
# ends the loop without a repair. A LIFT-FAILURE is shared whatever its lane, so it
|
|
749
|
+
# keeps the gate red. With every lane worked nothing is `other` and the loop runs as
|
|
750
|
+
# it always has.
|
|
751
|
+
- id: classify_gaps
|
|
752
|
+
action: execute_script
|
|
753
|
+
script: { ref: actions }
|
|
754
|
+
subcommand: plan-gaps
|
|
755
|
+
args: ["--gaps", "{{analyze_gaps}}", "--lanes", "{{work_lanes}}"]
|
|
756
|
+
outputs:
|
|
757
|
+
- { name: own_plan_gaps, from: "$.plan_gaps" }
|
|
758
|
+
- { name: own_routed, from: "$.routed_gaps" }
|
|
759
|
+
- { name: other_gaps, from: "$.other_gaps" }
|
|
760
|
+
- { name: other_csv, from: "$.other_csv" }
|
|
761
|
+
- id: own_clear_reset
|
|
762
|
+
action: set
|
|
763
|
+
vars: { own_clear: "false" }
|
|
764
|
+
- id: own_clear_raise
|
|
765
|
+
condition: "{{other_gaps}} != 0"
|
|
766
|
+
action: set
|
|
767
|
+
vars: { own_clear: "true" }
|
|
768
|
+
- id: own_clear_plan
|
|
769
|
+
condition: "{{own_plan_gaps}} != 0"
|
|
770
|
+
action: set
|
|
771
|
+
vars: { own_clear: "false" }
|
|
772
|
+
- id: own_clear_routed
|
|
773
|
+
condition: "{{own_routed}} != 0"
|
|
774
|
+
action: set
|
|
775
|
+
vars: { own_clear: "false" }
|
|
776
|
+
- id: own_clear_break
|
|
777
|
+
action: break
|
|
778
|
+
condition: "{{own_clear}} == true"
|
|
779
|
+
|
|
536
780
|
- id: ask_repair
|
|
537
781
|
action: ask
|
|
538
782
|
prompt: |
|
|
@@ -546,7 +790,7 @@ workflow:
|
|
|
546
790
|
condition: "{{repair_choice}} == Report and Skip"
|
|
547
791
|
action: agent_author
|
|
548
792
|
include_standards: false
|
|
549
|
-
output_target: { type: file, path: "{{
|
|
793
|
+
output_target: { type: file, path: "{{report_file}}" }
|
|
550
794
|
task: |
|
|
551
795
|
Write a Delta Plan Analyze Report to the output from these delta-spec↔delta-plan
|
|
552
796
|
conformance gaps (the delta spec is the ANCHOR; the user chose to skip repair):
|
|
@@ -665,11 +909,27 @@ workflow:
|
|
|
665
909
|
headers — scripts stamp those.
|
|
666
910
|
Return the COMPLETE updated delta plan content only.
|
|
667
911
|
|
|
912
|
+
# THE STOP. Two independent raises: nothing drifts, or what drifts is only the other
|
|
913
|
+
# developer's to close — reported for them below.
|
|
914
|
+
- id: gate_ok_conformant
|
|
915
|
+
condition: "{{analyze_ok}} == true"
|
|
916
|
+
action: set
|
|
917
|
+
vars: { gate_ok: "true" }
|
|
918
|
+
- id: gate_ok_others_only
|
|
919
|
+
condition: "{{own_clear}} == true"
|
|
920
|
+
action: set
|
|
921
|
+
vars: { gate_ok: "true", no_other_gaps: "false" }
|
|
922
|
+
- id: note_other_gaps
|
|
923
|
+
action: verify_context
|
|
924
|
+
require_true: no_other_gaps
|
|
925
|
+
on_false: continue
|
|
926
|
+
on_false_message: "NOTE — your half of change {{cr_id}} passes. What is left is in the delta plan of a lane you do not work on, for its developer to close (their own analyze-plan-delta {{cr_id}} repairs it): {{other_csv}}"
|
|
927
|
+
|
|
668
928
|
- id: analyze_gate
|
|
669
929
|
action: verify_context
|
|
670
|
-
require_true:
|
|
930
|
+
require_true: gate_ok
|
|
671
931
|
on_false: stop
|
|
672
|
-
on_false_message: "The delta plans for {{cr_id}} do not realise the delta spec (gaps: {{analyze_gaps}}) — repair was skipped (see {{
|
|
932
|
+
on_false_message: "The delta plans for {{cr_id}} do not realise the delta spec (gaps: {{analyze_gaps}}) — repair was skipped (see {{report_file}}), or it could not be reconciled in 3 passes. A 'LIFT-FAILURE:' gap means a domain constraint from the gate checklist was never lifted into the delta spec, and a `model` gap means a plan needs structure the effective model does not define — both are fixed by /appweaver specify, which authors the delta spec and the model delta; this gate may not write either. A `wave` gap is closed by declaring '## Depends on' — which is what sets the wave, since specify derives it from that section and the merge fence re-checks it — or by planning around the sibling. Otherwise fix out of band, or re-run and choose Repair."
|
|
673
933
|
|
|
674
934
|
# 8. Post-execution hooks.
|
|
675
935
|
- id: resolve_post_hooks
|
|
@@ -690,8 +950,13 @@ outputs:
|
|
|
690
950
|
wave: "{{wave}}"
|
|
691
951
|
delta_backend_plan: "{{delta_backend_plan}}" # empty when that lane has no delta plan
|
|
692
952
|
delta_frontend_plan: "{{delta_frontend_plan}}"
|
|
693
|
-
conformant: "{{analyze_ok}}"
|
|
953
|
+
conformant: "{{analyze_ok}}" # every check passed, the other developer's half included; false on a run that finishes means only other_lane_gaps are left
|
|
694
954
|
gaps: "{{analyze_gaps}}"
|
|
695
955
|
overlaps: "{{overlap_report}}"
|
|
956
|
+
working_lane: "{{working_lane}}" # the developer's working lane(s) — .appweaver/lane.json
|
|
957
|
+
gated_backend: "{{be_present}}" # checked and repaired by this run
|
|
958
|
+
gated_frontend: "{{fe_present}}"
|
|
959
|
+
other_lane_gaps: "{{other_csv}}" # gaps only the other developer's delta plan can close
|
|
960
|
+
contract_impact: "{{impact_csv}}" # operations the service delta changes or removes that the frontend still binds to
|
|
696
961
|
note: "Gated change {{cr_id}} (wave {{wave}}) against its delta spec, the masters it changes, and the EFFECTIVE model — domain-model.md plus this change's model delta plus the {{predecessor_count}} predecessor change(s) from LOWER waves (each one's model delta and its delta-spec). Same-wave changes are visible but never assumed: {{sibling_count}} open at the same or a higher wave, overlapping this one on — {{overlap_report}}. The masters and the model were READ, never written."
|
|
697
962
|
next: "/appweaver implement {{cr_id}} → build → analyze-slice-delta → finalize-delta → analyze-slice → close-delta (implement is one command for both lanes and both paths — passing the id above skips its 'which change' prompt; the delta plans realise the delta spec; the change stays OPEN through finalize-delta's merge and analyze-slice's verification, and only close-delta archives it and bumps the version)"
|