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
|
@@ -57,6 +57,22 @@
|
|
|
57
57
|
# repair loops stay in analyze-slice, where the merged master is the anchor and the job is
|
|
58
58
|
# fixing what is BROKEN rather than building what is ABSENT.
|
|
59
59
|
#
|
|
60
|
+
# ONLY THE LANES THE CHANGE NAMES THAT YOU WORK ON ARE GATED (.appweaver/lane.json). The
|
|
61
|
+
# change menu lists only the changes whose **Lanes** line names a working lane. A lane is
|
|
62
|
+
# gated when the change names it, you work on it and the change has its delta plan, and each
|
|
63
|
+
# gated lane runs its OWN tests (`test-run --kind`), so a backend developer's gate is never
|
|
64
|
+
# failed by the frontend's suite. A named lane somebody else works on is gated by that
|
|
65
|
+
# developer's own run; this one says so in a note and does not wait for it.
|
|
66
|
+
#
|
|
67
|
+
# EACH GATED LANE'S RESULT IS RECORDED in the change's directory, pass or fail, as
|
|
68
|
+
# `.aw-slice-gate.<lane>.json` (slice-gate-stamp), and is committed with the change. pass =
|
|
69
|
+
# no test of the lane failed AND its requirement checks met; a lane that declares no test
|
|
70
|
+
# command is green with nothing run, and the record's tests_ran says so. Two developers
|
|
71
|
+
# write two different files, so their results never collide, and together they are the
|
|
72
|
+
# record of which lanes of the change were shown to be built. The REPORT is split the same
|
|
73
|
+
# way: a developer working one lane of two writes delta-slice-analyze-report.<lane>.md, and
|
|
74
|
+
# a developer on every lane writes delta-slice-analyze-report.md.
|
|
75
|
+
#
|
|
60
76
|
# NO NEW RULE-MAP HEADING. It loads `## /aw-spec-analyze-slice` — the same testing +
|
|
61
77
|
# coding-standards set its master twin reads — so no project has to add configuration to
|
|
62
78
|
# get this gate. The DOMAIN gate overlays are deliberately NOT loaded: full domain
|
|
@@ -70,8 +86,8 @@
|
|
|
70
86
|
# =============================================================================
|
|
71
87
|
|
|
72
88
|
name: aw-spec-analyze-slice-delta
|
|
73
|
-
version: 1.
|
|
74
|
-
description: "The delta-spec↔delta-code gate — verify that the open change DOES WHAT IT WAS ASKED TO DO, before it reaches the master documents. delta-spec.md is the anchor, exactly as it is for analyze-plan-delta. Asks which open change it is gating
|
|
89
|
+
version: 1.3.0
|
|
90
|
+
description: "The delta-spec↔delta-code gate — verify that the open change DOES WHAT IT WAS ASKED TO DO, before it reaches the master documents. delta-spec.md is the anchor, exactly as it is for analyze-plan-delta. Asks which open change it is gating (only the changes naming a lane you work on are listed) and gates only the lanes the change names that you work on. Each gated lane runs its own tests (the first execution on the change path, since build only compiles), then its code and paired tests are evaluated against the change's REQUIREMENTS — every ADDED or MODIFIED delta-spec item realised in code, every one covered by a test that cites its id, every invariant the model delta adds actually enforced — with the delta plan in context as the map from requirement to code and cross-checked in its own right, so an element the plan promised and nobody built is caught too. Each gated lane's pass or fail is recorded in the change as .aw-slice-gate.<lane>.json. The dynamic twin of analyze-plan-delta and the delta twin of analyze-slice, which cannot see a missing implementation because a behaviour that was never built leaves no failing test. Verify-only — it reports each finding with the command that closes it and stops; it generates no code and repairs nothing."
|
|
75
91
|
agent_agnostic: true
|
|
76
92
|
dialect: aw-spec.orchestrator/v1
|
|
77
93
|
|
|
@@ -109,27 +125,71 @@ vars:
|
|
|
109
125
|
delta_frontend_plan: ""
|
|
110
126
|
delta_frontend_plan_exists: "false"
|
|
111
127
|
domain_model: ""
|
|
112
|
-
# WHICH LANES THIS GATE CHECKS — a lane is gated when it is DECLARED
|
|
113
|
-
#
|
|
114
|
-
#
|
|
115
|
-
#
|
|
128
|
+
# WHICH LANES THIS GATE CHECKS — a lane is gated when it is DECLARED for this feature, the
|
|
129
|
+
# change's **Lanes** line NAMES it, this developer WORKS on it (.appweaver/lane.json) and
|
|
130
|
+
# the change has a delta plan for it. An experience-untouched change has no frontend delta
|
|
131
|
+
# plan, and skipping that lane's checks is correct rather than a pass by omission. Each AND
|
|
132
|
+
# is an ordered assignment; the engine has no compound conditions.
|
|
116
133
|
be_declared: "false"
|
|
117
134
|
fe_declared: "false"
|
|
118
135
|
fe_excluded: "false" # this feature records no surface in the declared frontend lane (feature-lanes)
|
|
136
|
+
be_working: "false"
|
|
137
|
+
fe_working: "false"
|
|
138
|
+
working_lane: ""
|
|
139
|
+
working_kind: "" # the one lane worked when one lane of two is; empty otherwise
|
|
140
|
+
working_root: "" # the working lane's root and test path when one lane of two is worked
|
|
141
|
+
working_test_path: ""
|
|
142
|
+
under_note: ""
|
|
143
|
+
report_file: "" # delta-slice-analyze-report[.<working_kind>].md in the change
|
|
144
|
+
cr_lanes_csv: ""
|
|
145
|
+
cr_touches_backend: "true" # every lane until cr-paths answers
|
|
146
|
+
cr_touches_frontend: "true"
|
|
147
|
+
be_named: "false" # declared AND the change names it
|
|
148
|
+
fe_named: "false"
|
|
149
|
+
be_awaited: "false" # named, not worked ⇒ gated by the developer who works on it
|
|
150
|
+
fe_awaited: "false"
|
|
151
|
+
no_awaited: "true"
|
|
152
|
+
awaited_txt: ""
|
|
153
|
+
asd_hidden_note: "" # open changes naming only a lane not worked here
|
|
154
|
+
asd_hidden_csv: ""
|
|
155
|
+
asd_preselect_hidden: ""
|
|
156
|
+
preselect_visible: "true"
|
|
119
157
|
be_gated: "false"
|
|
120
158
|
fe_gated: "false"
|
|
121
159
|
any_lane: "false"
|
|
122
160
|
# Slice evidence.
|
|
123
161
|
source_files: []
|
|
124
162
|
source_count: "0"
|
|
125
|
-
test_ok
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
163
|
+
# Each gated lane's own test run. `*_test_vote` is what a lane casts into test_ok — its
|
|
164
|
+
# result when gated, "true" when not — so a lane that was not gated never votes, and a
|
|
165
|
+
# gated lane whose run returned nothing votes red.
|
|
166
|
+
be_test_ok: "false"
|
|
167
|
+
be_test_tool: ""
|
|
168
|
+
be_test_log: ""
|
|
169
|
+
be_test_excerpt: ""
|
|
170
|
+
be_test_scoped: "false"
|
|
171
|
+
be_test_ran: "false"
|
|
172
|
+
be_test_matched: "false"
|
|
173
|
+
be_test_vote: "true"
|
|
174
|
+
fe_test_ok: "false"
|
|
175
|
+
fe_test_tool: ""
|
|
176
|
+
fe_test_log: ""
|
|
177
|
+
fe_test_excerpt: ""
|
|
178
|
+
fe_test_scoped: "false"
|
|
179
|
+
fe_test_ran: "false"
|
|
180
|
+
fe_test_matched: "false"
|
|
181
|
+
fe_test_vote: "true"
|
|
182
|
+
test_ok: "false" # every gated lane's tests green
|
|
183
|
+
# Each lane's state in words, for the report and the stop message; a gated lane's ends on
|
|
184
|
+
# its recorded verdict (pass | fail).
|
|
185
|
+
be_state: "not gated — no backend lane for this feature"
|
|
186
|
+
fe_state: "not gated — no frontend lane for this feature"
|
|
187
|
+
be_verdict: ""
|
|
188
|
+
fe_verdict: ""
|
|
189
|
+
# Verdict. `*_req_vote` is what a lane casts into requirements_ok: "true" when it was not
|
|
190
|
+
# gated; when it was, true only on its check's explicit ok=true.
|
|
191
|
+
be_req_vote: "true"
|
|
192
|
+
fe_req_vote: "true"
|
|
133
193
|
requirements_ok: "false"
|
|
134
194
|
# Findings split by the command that closes them (gap-route). Defaults read as
|
|
135
195
|
# "nothing found", so a run where the router could not execute still prints.
|
|
@@ -199,7 +259,8 @@ workflow:
|
|
|
199
259
|
# active_version.json for a service-only slice in a repo that also has a UI. Re-read with
|
|
200
260
|
# --feature-dir so a lane the feature records no surface in is absent here: its code is
|
|
201
261
|
# not gated against a plan it never had. With no feature resolved the argument is dropped
|
|
202
|
-
# and the repo's answer stands.
|
|
262
|
+
# and the repo's answer stands. The WORKING lanes are read here too, so a lane the feature
|
|
263
|
+
# records no surface in is not worked either.
|
|
203
264
|
- id: feature_lanes
|
|
204
265
|
action: execute_script
|
|
205
266
|
on_error: continue
|
|
@@ -207,9 +268,15 @@ workflow:
|
|
|
207
268
|
subcommand: lane-resolve
|
|
208
269
|
args: ["--feature-dir", "{{feature_dir}}"]
|
|
209
270
|
outputs:
|
|
210
|
-
- { name: be_declared,
|
|
211
|
-
- { name: fe_declared,
|
|
212
|
-
- { name: fe_excluded,
|
|
271
|
+
- { name: be_declared, from: "$.backend_declared" }
|
|
272
|
+
- { name: fe_declared, from: "$.frontend_declared" }
|
|
273
|
+
- { name: fe_excluded, from: "$.frontend_feature_excluded" }
|
|
274
|
+
- { name: be_working, from: "$.backend_working" }
|
|
275
|
+
- { name: fe_working, from: "$.frontend_working" }
|
|
276
|
+
- { name: working_lane, from: "$.working_lane" }
|
|
277
|
+
- { name: working_kind, from: "$.working_kind" }
|
|
278
|
+
- { name: working_root, from: "$.working_root" }
|
|
279
|
+
- { name: working_test_path, from: "$.working_test_path" }
|
|
213
280
|
|
|
214
281
|
- id: require_feature
|
|
215
282
|
action: verify_context
|
|
@@ -221,26 +288,44 @@ workflow:
|
|
|
221
288
|
# cr-list enumerates the open changes (evidence = changes/<CR-id>/ on disk), a bare CR
|
|
222
289
|
# id in the argument auto-selects, one open change auto-confirms, and the pick is
|
|
223
290
|
# ACTIVATED so finalize-delta and close-delta act on the change this gate cleared.
|
|
291
|
+
# Only the changes naming a working lane on their **Lanes** line are listed (`--lane`,
|
|
292
|
+
# last in the args so an empty value cannot be mistaken for the next flag).
|
|
224
293
|
- id: cr_list
|
|
225
294
|
action: execute_script
|
|
226
295
|
script: { ref: actions }
|
|
227
296
|
subcommand: cr-list
|
|
228
|
-
args: ["--feature-dir", "{{feature_dir}}", "--preselect", "{{USER_INPUT}}"]
|
|
297
|
+
args: ["--feature-dir", "{{feature_dir}}", "--preselect", "{{USER_INPUT}}", "--lane", "{{working_lane}}"]
|
|
229
298
|
outputs:
|
|
230
299
|
- { name: change_options, from: "$.select_options" }
|
|
231
300
|
- { name: matched_label, from: "$.matched_label" }
|
|
232
301
|
- { name: has_changes, from: "$.has_changes" }
|
|
233
302
|
- { name: change_count, from: "$.count" }
|
|
303
|
+
- { name: asd_hidden_csv, from: "$.hidden_ids_csv" }
|
|
304
|
+
- { name: asd_preselect_hidden, from: "$.preselect_hidden" }
|
|
305
|
+
|
|
306
|
+
- id: preselect_hidden_flag
|
|
307
|
+
condition: "{{asd_preselect_hidden}} != "
|
|
308
|
+
action: set
|
|
309
|
+
vars: { preselect_visible: "false" }
|
|
310
|
+
- id: require_visible_change
|
|
311
|
+
action: verify_context
|
|
312
|
+
require_true: preselect_visible
|
|
313
|
+
on_false: stop
|
|
314
|
+
on_false_message: "Change {{asd_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 code of yours to gate. Its own lane's developer gates it — or run /appweaver select-lane to work on that lane."
|
|
315
|
+
- id: hidden_note_set
|
|
316
|
+
condition: "{{asd_hidden_csv}} != "
|
|
317
|
+
action: set
|
|
318
|
+
vars: { asd_hidden_note: " Open for a lane you do not work on, and not listed: {{asd_hidden_csv}}." }
|
|
234
319
|
|
|
235
320
|
- id: require_change
|
|
236
321
|
action: verify_context
|
|
237
322
|
require_true: has_changes
|
|
238
323
|
on_false: stop
|
|
239
|
-
on_false_message: "No open change on this feature — there is no delta to gate. This is the CHANGE path's gate; on the bootstrap path the whole slice is gated by /appweaver analyze-slice after build. A change is opened by /appweaver specify."
|
|
324
|
+
on_false_message: "No open change on this feature names your working lane `{{working_lane}}` — there is no delta to gate.{{asd_hidden_note}} This is the CHANGE path's gate; on the bootstrap path the whole slice is gated by /appweaver analyze-slice after build. A change is opened by /appweaver specify."
|
|
240
325
|
|
|
241
326
|
- id: pick_change
|
|
242
327
|
action: user_select
|
|
243
|
-
prompt: "Which open change is being gated? This checks that the change was actually BUILT, before finalize-delta merges it into the masters."
|
|
328
|
+
prompt: "Which open change is being gated? This checks that the change was actually BUILT, before finalize-delta merges it into the masters.{{asd_hidden_note}}"
|
|
244
329
|
options_from_variable: change_options
|
|
245
330
|
preselect_from: matched_label
|
|
246
331
|
single_option_confirm: true
|
|
@@ -271,16 +356,70 @@ workflow:
|
|
|
271
356
|
- { name: delta_frontend_plan_exists, from: "$.delta_frontend_plan_exists" }
|
|
272
357
|
- { name: wave, from: "$.wave" }
|
|
273
358
|
- { name: domain_model, from: "$.domain_model" }
|
|
274
|
-
|
|
275
|
-
|
|
359
|
+
# The lanes this change touches — its delta-spec's **Lanes** line, every lane when it
|
|
360
|
+
# records none.
|
|
361
|
+
- { name: cr_lanes_csv, from: "$.lanes_csv" }
|
|
362
|
+
- { name: cr_touches_backend, from: "$.touches_backend" }
|
|
363
|
+
- { name: cr_touches_frontend, from: "$.touches_frontend" }
|
|
364
|
+
|
|
365
|
+
# 3a. WHICH LANES ARE GATED. Declared for this feature AND named on the change's **Lanes**
|
|
366
|
+
# line (NAMED). A named lane somebody else works on is AWAITED — its own developer
|
|
367
|
+
# gates it. A named lane you work on is GATED when this change has its delta plan.
|
|
368
|
+
- id: be_named_set
|
|
369
|
+
action: set
|
|
370
|
+
vars: { be_named: "{{be_declared}}" }
|
|
371
|
+
- id: fe_named_set
|
|
372
|
+
action: set
|
|
373
|
+
vars: { fe_named: "{{fe_declared}}" }
|
|
374
|
+
- id: be_not_in_change
|
|
375
|
+
condition: "{{cr_touches_backend}} == false"
|
|
376
|
+
action: set
|
|
377
|
+
vars: { be_named: "false" }
|
|
378
|
+
- id: fe_not_in_change
|
|
379
|
+
condition: "{{cr_touches_frontend}} == false"
|
|
380
|
+
action: set
|
|
381
|
+
vars: { fe_named: "false" }
|
|
382
|
+
- id: be_flag_awaited
|
|
383
|
+
condition: "{{be_working}} == false"
|
|
384
|
+
action: set
|
|
385
|
+
vars: { be_awaited: "{{be_named}}" }
|
|
386
|
+
- id: fe_flag_awaited
|
|
387
|
+
condition: "{{fe_working}} == false"
|
|
388
|
+
action: set
|
|
389
|
+
vars: { fe_awaited: "{{fe_named}}" }
|
|
276
390
|
- id: be_gated_flag
|
|
277
391
|
condition: "{{delta_backend_plan_exists}} == true"
|
|
278
392
|
action: set
|
|
279
|
-
vars: { be_gated: "{{
|
|
393
|
+
vars: { be_gated: "{{be_named}}" }
|
|
280
394
|
- id: fe_gated_flag
|
|
281
395
|
condition: "{{delta_frontend_plan_exists}} == true"
|
|
282
396
|
action: set
|
|
283
|
-
vars: { fe_gated: "{{
|
|
397
|
+
vars: { fe_gated: "{{fe_named}}" }
|
|
398
|
+
- id: be_not_worked
|
|
399
|
+
condition: "{{be_working}} == false"
|
|
400
|
+
action: set
|
|
401
|
+
vars: { be_gated: "false" }
|
|
402
|
+
- id: fe_not_worked
|
|
403
|
+
condition: "{{fe_working}} == false"
|
|
404
|
+
action: set
|
|
405
|
+
vars: { fe_gated: "false" }
|
|
406
|
+
|
|
407
|
+
# The other developer's half: said, never waited for. Only a lane that is not worked can
|
|
408
|
+
# be awaited, so at most one is.
|
|
409
|
+
- id: awaited_be_txt
|
|
410
|
+
condition: "{{be_awaited}} == true"
|
|
411
|
+
action: set
|
|
412
|
+
vars: { awaited_txt: "backend", no_awaited: "false" }
|
|
413
|
+
- id: awaited_fe_txt
|
|
414
|
+
condition: "{{fe_awaited}} == true"
|
|
415
|
+
action: set
|
|
416
|
+
vars: { awaited_txt: "frontend", no_awaited: "false" }
|
|
417
|
+
- id: note_awaited
|
|
418
|
+
action: verify_context
|
|
419
|
+
require_true: no_awaited
|
|
420
|
+
on_false: continue
|
|
421
|
+
on_false_message: "NOTE — change {{cr_id}} also names the {{awaited_txt}} lane, which you do not work on (.appweaver/lane.json). Its developer gates that half in their own run, and its result is recorded beside yours in {{cr_dir}}/.aw-slice-gate.{{awaited_txt}}.json. This run tests, checks and records your half only."
|
|
422
|
+
|
|
284
423
|
- id: any_lane_be
|
|
285
424
|
condition: "{{be_gated}} == true"
|
|
286
425
|
action: set
|
|
@@ -294,7 +433,7 @@ workflow:
|
|
|
294
433
|
action: verify_context
|
|
295
434
|
require_true: any_lane
|
|
296
435
|
on_false: stop
|
|
297
|
-
on_false_message: "Change {{cr_id}} has no delta plan for
|
|
436
|
+
on_false_message: "Change {{cr_id}} has no delta plan for a lane it names that you work on — it names `{{cr_lanes_csv}}`, you work on `{{working_lane}}` (.appweaver/lane.json); backend declared {{be_declared}} (delta plan {{delta_backend_plan_exists}}), frontend declared {{fe_declared}} (delta plan {{delta_frontend_plan_exists}}). There is nothing of yours to gate the code against. Run /appweaver plan {{cr_id}} to author the delta plans, then analyze-plan-delta → implement → build, and gate it here."
|
|
298
437
|
|
|
299
438
|
# 4. THE SLICE'S REAL SOURCE FILES, from its OKF concept — the same resolution
|
|
300
439
|
# analyze-slice uses. They arrive as a PATH LIST and the check steps declare
|
|
@@ -303,21 +442,27 @@ workflow:
|
|
|
303
442
|
# use-case or an endpoint and never a file. That is why this gate is a model pass over
|
|
304
443
|
# real files rather than a deterministic existence check — the same reason design-paths
|
|
305
444
|
# was retired when the plan stopped carrying ```lang path=…``` fences.
|
|
445
|
+
# `--under` keeps the working lane's own two subtrees when the developer works on one
|
|
446
|
+
# lane of two.
|
|
306
447
|
- id: concept_paths
|
|
307
448
|
action: execute_script
|
|
308
449
|
on_error: continue
|
|
309
450
|
script: { ref: xref }
|
|
310
451
|
subcommand: concept-paths
|
|
311
|
-
args: ["--feature-dir", "{{feature_dir}}"]
|
|
452
|
+
args: ["--feature-dir", "{{feature_dir}}", "--under", "{{working_root}}", "--under", "{{working_test_path}}"]
|
|
312
453
|
outputs:
|
|
313
454
|
- { name: source_files, from: "$.paths" }
|
|
314
455
|
- { name: source_count, from: "$.count" }
|
|
315
456
|
|
|
457
|
+
- id: under_note_set
|
|
458
|
+
condition: "{{working_root}} != "
|
|
459
|
+
action: set
|
|
460
|
+
vars: { under_note: " under your working lane's folders (`{{working_root}}`, `{{working_test_path}}`)" }
|
|
316
461
|
- id: require_source
|
|
317
462
|
action: verify_context
|
|
318
463
|
require_non_empty: source_files
|
|
319
464
|
on_empty: stop
|
|
320
|
-
on_empty_message: "The OKF concept for {{feature}} lists no source files, so there is no implementation to gate. Either /appweaver implement has not run for change {{cr_id}} yet, or it ran and reported no files. Run /appweaver implement {{cr_id}} → build, then re-run this gate."
|
|
465
|
+
on_empty_message: "The OKF concept for {{feature}} lists no source files{{under_note}}, so there is no implementation to gate. Either /appweaver implement has not run for change {{cr_id}} yet, or it ran and reported no files. Run /appweaver implement {{cr_id}} → build, then re-run this gate."
|
|
321
466
|
|
|
322
467
|
# 5. Pre-execution hooks.
|
|
323
468
|
- id: resolve_pre_hooks
|
|
@@ -338,19 +483,22 @@ workflow:
|
|
|
338
483
|
# scope=slice: this feature's tests only. Referring aggregates are the downstream fence's
|
|
339
484
|
# subject in finalize-delta and the integrity pass's in analyze-slice; this gate is about
|
|
340
485
|
# THIS change.
|
|
486
|
+
# ONE RUN PER GATED LANE (`--kind`), so each lane's result is its own: a lane is not failed
|
|
487
|
+
# by the other lane's suite, and a lane that is not gated runs nothing.
|
|
341
488
|
# NO FIX LOOP, deliberately — see the header. A red fence is reported and stops.
|
|
342
|
-
- id:
|
|
489
|
+
- id: run_tests_backend
|
|
490
|
+
condition: "{{be_gated}} == true"
|
|
343
491
|
action: execute_script
|
|
344
492
|
on_error: continue
|
|
345
493
|
script: { ref: actions }
|
|
346
494
|
subcommand: test-run
|
|
347
|
-
args: ["--feature-dir", "{{feature_dir}}", "--scope", "slice"]
|
|
495
|
+
args: ["--feature-dir", "{{feature_dir}}", "--scope", "slice", "--kind", "backend"]
|
|
348
496
|
outputs:
|
|
349
|
-
- { name:
|
|
350
|
-
- { name:
|
|
351
|
-
- { name:
|
|
352
|
-
- { name:
|
|
353
|
-
- { name:
|
|
497
|
+
- { name: be_test_ok, from: "$.fence_green" }
|
|
498
|
+
- { name: be_test_tool, from: "$.tool" }
|
|
499
|
+
- { name: be_test_log, from: "$.log_tail" }
|
|
500
|
+
- { name: be_test_excerpt, from: "$.failing_excerpt" } # the lines that NAME the failure
|
|
501
|
+
- { name: be_test_scoped, from: "$.scoped" }
|
|
354
502
|
# A GREEN FENCE IS NOT ALWAYS AN EXECUTED SUITE. test-run reports fence_green true
|
|
355
503
|
# with ran=false on a project whose lanes declare no test command — the vacuous pass
|
|
356
504
|
# its own ladder warns about. It is not made fatal here (that would fail every project
|
|
@@ -358,8 +506,45 @@ workflow:
|
|
|
358
506
|
# but it IS reported, so "BUILT ✓" is never read as "the tests passed" when nothing
|
|
359
507
|
# ran. The requirement checks below are what actually answer whether the change
|
|
360
508
|
# does what it asked for, and they do not depend on a suite existing.
|
|
361
|
-
- { name:
|
|
362
|
-
- { name:
|
|
509
|
+
- { name: be_test_ran, from: "$.ran" }
|
|
510
|
+
- { name: be_test_matched, from: "$.matched" }
|
|
511
|
+
- id: run_tests_frontend
|
|
512
|
+
condition: "{{fe_gated}} == true"
|
|
513
|
+
action: execute_script
|
|
514
|
+
on_error: continue
|
|
515
|
+
script: { ref: actions }
|
|
516
|
+
subcommand: test-run
|
|
517
|
+
args: ["--feature-dir", "{{feature_dir}}", "--scope", "slice", "--kind", "frontend"]
|
|
518
|
+
outputs:
|
|
519
|
+
- { name: fe_test_ok, from: "$.fence_green" }
|
|
520
|
+
- { name: fe_test_tool, from: "$.tool" }
|
|
521
|
+
- { name: fe_test_log, from: "$.log_tail" }
|
|
522
|
+
- { name: fe_test_excerpt, from: "$.failing_excerpt" }
|
|
523
|
+
- { name: fe_test_scoped, from: "$.scoped" }
|
|
524
|
+
- { name: fe_test_ran, from: "$.ran" }
|
|
525
|
+
- { name: fe_test_matched, from: "$.matched" }
|
|
526
|
+
|
|
527
|
+
# test_ok = every gated lane's tests green — a raise and two knock-downs, each lane voting
|
|
528
|
+
# only when it was gated.
|
|
529
|
+
- id: be_test_vote_set
|
|
530
|
+
condition: "{{be_gated}} == true"
|
|
531
|
+
action: set
|
|
532
|
+
vars: { be_test_vote: "{{be_test_ok}}" }
|
|
533
|
+
- id: fe_test_vote_set
|
|
534
|
+
condition: "{{fe_gated}} == true"
|
|
535
|
+
action: set
|
|
536
|
+
vars: { fe_test_vote: "{{fe_test_ok}}" }
|
|
537
|
+
- id: tests_seed
|
|
538
|
+
action: set
|
|
539
|
+
vars: { test_ok: "true" }
|
|
540
|
+
- id: tests_clear_backend
|
|
541
|
+
condition: "{{be_test_vote}} == false"
|
|
542
|
+
action: set
|
|
543
|
+
vars: { test_ok: "false" }
|
|
544
|
+
- id: tests_clear_frontend
|
|
545
|
+
condition: "{{fe_test_vote}} == false"
|
|
546
|
+
action: set
|
|
547
|
+
vars: { test_ok: "false" }
|
|
363
548
|
|
|
364
549
|
# ══════ PASS 2 — REQUIREMENTS. Does the code do what the change asked for? ══════
|
|
365
550
|
# THE REQUIREMENTS ARE THE ANCHOR; the plan is the map; the masters are read-only context
|
|
@@ -564,16 +749,34 @@ workflow:
|
|
|
564
749
|
|
|
565
750
|
# ═══════════════════════════ THE VERDICT ═══════════════════════════
|
|
566
751
|
# requirements_ok = every GATED lane passed. Expressed as a raise-then-knock-down chain,
|
|
567
|
-
# because the engine has no compound conditions and an ungated lane must not vote.
|
|
752
|
+
# because the engine has no compound conditions and an ungated lane must not vote. A gated
|
|
753
|
+
# lane votes met only on an explicit ok=true: a check that answered without `ok` votes not
|
|
754
|
+
# met, the same reading its .aw-slice-gate record gives it.
|
|
755
|
+
- id: be_req_vote_gated
|
|
756
|
+
condition: "{{be_gated}} == true"
|
|
757
|
+
action: set
|
|
758
|
+
vars: { be_req_vote: "false" }
|
|
759
|
+
- id: be_req_vote_met
|
|
760
|
+
condition: "{{be_ok}} == true"
|
|
761
|
+
action: set
|
|
762
|
+
vars: { be_req_vote: "true" }
|
|
763
|
+
- id: fe_req_vote_gated
|
|
764
|
+
condition: "{{fe_gated}} == true"
|
|
765
|
+
action: set
|
|
766
|
+
vars: { fe_req_vote: "false" }
|
|
767
|
+
- id: fe_req_vote_met
|
|
768
|
+
condition: "{{fe_ok}} == true"
|
|
769
|
+
action: set
|
|
770
|
+
vars: { fe_req_vote: "true" }
|
|
568
771
|
- id: requirements_seed
|
|
569
772
|
action: set
|
|
570
773
|
vars: { requirements_ok: "true" }
|
|
571
774
|
- id: requirements_clear_backend
|
|
572
|
-
condition: "{{
|
|
775
|
+
condition: "{{be_req_vote}} == false"
|
|
573
776
|
action: set
|
|
574
777
|
vars: { requirements_ok: "false" }
|
|
575
778
|
- id: requirements_clear_frontend
|
|
576
|
-
condition: "{{
|
|
779
|
+
condition: "{{fe_req_vote}} == false"
|
|
577
780
|
action: set
|
|
578
781
|
vars: { requirements_ok: "false" }
|
|
579
782
|
|
|
@@ -601,16 +804,84 @@ workflow:
|
|
|
601
804
|
- { name: fix_review, from: "$.review_text" }
|
|
602
805
|
- { name: fix_review_n, from: "$.review_count" }
|
|
603
806
|
|
|
604
|
-
# gate_ok =
|
|
807
|
+
# gate_ok = every gated lane's tests green AND every gated lane's requirements are met.
|
|
605
808
|
- id: gate_flag
|
|
606
809
|
condition: "{{test_ok}} == true"
|
|
607
810
|
action: set
|
|
608
811
|
vars: { gate_ok: "{{requirements_ok}}" }
|
|
609
812
|
|
|
813
|
+
# EACH GATED LANE'S RESULT, RECORDED IN THE CHANGE as .aw-slice-gate.<lane>.json — pass
|
|
814
|
+
# when no test of the lane failed and its requirement checks are met, else fail, with
|
|
815
|
+
# whether a suite actually ran. It is written before the gate below stops, so a red result
|
|
816
|
+
# replaces an earlier green one instead of leaving it standing.
|
|
817
|
+
- id: stamp_backend
|
|
818
|
+
condition: "{{be_gated}} == true"
|
|
819
|
+
action: execute_script
|
|
820
|
+
on_error: continue
|
|
821
|
+
script: { ref: actions }
|
|
822
|
+
subcommand: slice-gate-stamp
|
|
823
|
+
args: ["--cr-id", "{{cr_id}}", "--feature-dir", "{{feature_dir}}", "--tests-green", "{{be_test_ok}}", "--tests-ran", "{{be_test_ran}}", "--requirements-ok", "{{be_req_vote}}", "--findings", "{{be_gaps}}", "--lane", "backend"]
|
|
824
|
+
outputs:
|
|
825
|
+
- { name: be_verdict, from: "$.verdict" }
|
|
826
|
+
- id: stamp_frontend
|
|
827
|
+
condition: "{{fe_gated}} == true"
|
|
828
|
+
action: execute_script
|
|
829
|
+
on_error: continue
|
|
830
|
+
script: { ref: actions }
|
|
831
|
+
subcommand: slice-gate-stamp
|
|
832
|
+
args: ["--cr-id", "{{cr_id}}", "--feature-dir", "{{feature_dir}}", "--tests-green", "{{fe_test_ok}}", "--tests-ran", "{{fe_test_ran}}", "--requirements-ok", "{{fe_req_vote}}", "--findings", "{{fe_gaps}}", "--lane", "frontend"]
|
|
833
|
+
outputs:
|
|
834
|
+
- { name: fe_verdict, from: "$.verdict" }
|
|
835
|
+
|
|
836
|
+
# EACH LANE'S STATE IN WORDS. Ordered from the least to the most specific; a gated lane
|
|
837
|
+
# ends on its test result, its requirement verdict and what was recorded.
|
|
838
|
+
- id: be_state_unnamed
|
|
839
|
+
condition: "{{be_declared}} == true"
|
|
840
|
+
action: set
|
|
841
|
+
vars: { be_state: "not gated — the change's **Lanes** line does not name it" }
|
|
842
|
+
- id: be_state_no_plan
|
|
843
|
+
condition: "{{be_named}} == true"
|
|
844
|
+
action: set
|
|
845
|
+
vars: { be_state: "not gated — this change has no backend delta plan" }
|
|
846
|
+
- id: be_state_awaited
|
|
847
|
+
condition: "{{be_awaited}} == true"
|
|
848
|
+
action: set
|
|
849
|
+
vars: { be_state: "not gated here — you do not work on it, and its own developer gates it" }
|
|
850
|
+
- id: be_state_gated
|
|
851
|
+
condition: "{{be_gated}} == true"
|
|
852
|
+
action: set
|
|
853
|
+
vars: { be_state: "gated — tests green={{be_test_ok}} (tool `{{be_test_tool}}`, actually ran={{be_test_ran}}), requirements met={{be_req_vote}}, recorded `{{be_verdict}}` in .aw-slice-gate.backend.json" }
|
|
854
|
+
- id: fe_state_unnamed
|
|
855
|
+
condition: "{{fe_declared}} == true"
|
|
856
|
+
action: set
|
|
857
|
+
vars: { fe_state: "not gated — the change's **Lanes** line does not name it" }
|
|
858
|
+
- id: fe_state_no_plan
|
|
859
|
+
condition: "{{fe_named}} == true"
|
|
860
|
+
action: set
|
|
861
|
+
vars: { fe_state: "not gated — this change has no frontend delta plan" }
|
|
862
|
+
- id: fe_state_awaited
|
|
863
|
+
condition: "{{fe_awaited}} == true"
|
|
864
|
+
action: set
|
|
865
|
+
vars: { fe_state: "not gated here — you do not work on it, and its own developer gates it" }
|
|
866
|
+
- id: fe_state_gated
|
|
867
|
+
condition: "{{fe_gated}} == true"
|
|
868
|
+
action: set
|
|
869
|
+
vars: { fe_state: "gated — tests green={{fe_test_ok}} (tool `{{fe_test_tool}}`, actually ran={{fe_test_ran}}), requirements met={{fe_req_vote}}, recorded `{{fe_verdict}}` in .aw-slice-gate.frontend.json" }
|
|
870
|
+
|
|
610
871
|
# THE REPORT IS ALWAYS WRITTEN — green or red. A green one is the record that this change
|
|
611
872
|
# was verified built before it was merged, which is what makes the merge auditable; a red
|
|
612
873
|
# one is the work list. It lands beside the change's other documents, so close-delta
|
|
613
|
-
# archives it with them.
|
|
874
|
+
# archives it with them. A developer working one lane of two writes their own,
|
|
875
|
+
# delta-slice-analyze-report.<lane>.md, so two developers gating the same change never
|
|
876
|
+
# rewrite each other's report; a developer on every lane writes
|
|
877
|
+
# delta-slice-analyze-report.md.
|
|
878
|
+
- id: report_file_set
|
|
879
|
+
action: set
|
|
880
|
+
vars: { report_file: "{{cr_dir}}/delta-slice-analyze-report.md" }
|
|
881
|
+
- id: report_file_lane
|
|
882
|
+
condition: "{{working_kind}} != "
|
|
883
|
+
action: set
|
|
884
|
+
vars: { report_file: "{{cr_dir}}/delta-slice-analyze-report.{{working_kind}}.md" }
|
|
614
885
|
# An EMPTY envelope, on purpose. build_context REPLACES the payload and PERSISTS, so
|
|
615
886
|
# without this the report would inherit whichever lane's documents were checked last —
|
|
616
887
|
# and a report step holding the plans it is reporting on starts re-deriving findings
|
|
@@ -622,27 +893,31 @@ workflow:
|
|
|
622
893
|
- id: write_report
|
|
623
894
|
action: agent_author
|
|
624
895
|
include_standards: false
|
|
625
|
-
output_target: { type: file, path: "{{
|
|
896
|
+
output_target: { type: file, path: "{{report_file}}" }
|
|
626
897
|
task: |
|
|
627
898
|
Write a Delta Slice Analyze Report for change {{cr_id}} (wave {{wave}}) to the
|
|
628
899
|
output. This gate asked whether the change's CODE does what its DELTA SPEC asked for
|
|
629
900
|
— the requirements are the anchor, the delta plan was the map — before finalize-delta
|
|
630
901
|
merges the change into spec.md and domain-model.md.
|
|
631
|
-
Evidence
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
lines: {{
|
|
635
|
-
|
|
636
|
-
- experience lane
|
|
902
|
+
Evidence — the change names the lanes `{{cr_lanes_csv}}`; this developer works on
|
|
903
|
+
`{{working_lane}}`. Each gated lane ran its own tests and was checked on its own:
|
|
904
|
+
- service lane: {{be_state}}. Matched a slice filter={{be_test_matched}},
|
|
905
|
+
slice-scoped={{be_test_scoped}}. Failing lines: {{be_test_excerpt}} · Log tail:
|
|
906
|
+
{{be_test_log}} · gaps: {{be_gaps}}
|
|
907
|
+
- experience lane: {{fe_state}}. Matched a slice filter={{fe_test_matched}},
|
|
908
|
+
slice-scoped={{fe_test_scoped}}. Failing lines: {{fe_test_excerpt}} · Log tail:
|
|
909
|
+
{{fe_test_log}} · gaps: {{fe_gaps}}
|
|
637
910
|
Markdown format:
|
|
638
911
|
- "# Delta Slice Analyze Report — {{cr_id}}" plus today's date.
|
|
639
|
-
- A verdict line: "verdict: REQUIREMENTS MET ✓" when
|
|
640
|
-
gated lane passed, else "verdict: NOT READY ✗ · <n> finding(s)".
|
|
641
|
-
- "## Evidence" —
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
912
|
+
- A verdict line: "verdict: REQUIREMENTS MET ✓" when every gated lane's tests are
|
|
913
|
+
green and every gated lane passed, else "verdict: NOT READY ✗ · <n> finding(s)".
|
|
914
|
+
- "## Evidence" — one entry per lane, with the lane's state as given above. For a
|
|
915
|
+
gated lane: its test fence (tool, green or red, and the log tail when red), its
|
|
916
|
+
requirement verdict, and the result recorded in its .aw-slice-gate.<lane>.json. A
|
|
917
|
+
lane that was NOT gated is listed with the reason given, never as a pass — and one
|
|
918
|
+
its own developer gates is said to be theirs, not missing. WHERE A GATED LANE'S
|
|
919
|
+
`actually ran` IS FALSE, say so in plain words — its fence went green because the
|
|
920
|
+
lane declares no test command, not because a suite passed — and note that the
|
|
646
921
|
requirement findings below, not the fence, are what answer whether the change does
|
|
647
922
|
what it was asked to.
|
|
648
923
|
- "## Findings" as a table — | # | check | lane | severity | delta-spec ref | where |
|
|
@@ -671,9 +946,8 @@ workflow:
|
|
|
671
946
|
require_true: gate_ok
|
|
672
947
|
on_false: stop
|
|
673
948
|
on_false_message: >
|
|
674
|
-
Change {{cr_id}} does NOT yet meet its delta spec.
|
|
675
|
-
|
|
676
|
-
gated={{fe_gated}} ok={{fe_ok}}. {{gap_summary}}
|
|
949
|
+
Change {{cr_id}} does NOT yet meet its delta spec. Service lane: {{be_state}}.
|
|
950
|
+
Experience lane: {{fe_state}}. {{gap_summary}}
|
|
677
951
|
|
|
678
952
|
EACH FINDING IS CLOSED BY A DIFFERENT COMMAND — they are not interchangeable, and a
|
|
679
953
|
plan defect sent to implement comes back unchanged, because implement generates FROM
|
|
@@ -691,7 +965,7 @@ workflow:
|
|
|
691
965
|
the code that maps to it. Re-running /appweaver plan {{cr_id}} re-derives the delta
|
|
692
966
|
plans with this report in context, so a plan finding is fixed by re-deriving rather
|
|
693
967
|
than by hand-editing a generated document. The full report is at
|
|
694
|
-
{{
|
|
968
|
+
{{report_file}}. DO NOT run finalize-delta yet: merging now
|
|
695
969
|
would write requirements into spec.md and domain-model.md that the code does not
|
|
696
970
|
satisfy, and the masters would describe an intention rather than the system. Then
|
|
697
971
|
re-run build and re-run this gate.
|
|
@@ -714,16 +988,26 @@ outputs:
|
|
|
714
988
|
cr_dir: "{{cr_dir}}"
|
|
715
989
|
wave: "{{wave}}"
|
|
716
990
|
built: "{{gate_ok}}"
|
|
717
|
-
tests_green: "{{test_ok}}"
|
|
718
|
-
|
|
719
|
-
|
|
991
|
+
tests_green: "{{test_ok}}" # every gated lane's tests
|
|
992
|
+
working_lane: "{{working_lane}}"
|
|
993
|
+
change_lanes: "{{cr_lanes_csv}}"
|
|
720
994
|
backend_gated: "{{be_gated}}"
|
|
995
|
+
backend_state: "{{be_state}}"
|
|
996
|
+
backend_tests_green: "{{be_test_ok}}"
|
|
997
|
+
backend_tests_ran: "{{be_test_ran}}" # false + green = the lane declares no test command
|
|
998
|
+
backend_test_tool: "{{be_test_tool}}"
|
|
721
999
|
backend_ok: "{{be_ok}}"
|
|
722
1000
|
backend_gaps: "{{be_gaps}}"
|
|
1001
|
+
backend_verdict: "{{be_verdict}}" # as recorded in .aw-slice-gate.backend.json
|
|
723
1002
|
frontend_gated: "{{fe_gated}}"
|
|
1003
|
+
frontend_state: "{{fe_state}}"
|
|
1004
|
+
frontend_tests_green: "{{fe_test_ok}}"
|
|
1005
|
+
frontend_tests_ran: "{{fe_test_ran}}"
|
|
1006
|
+
frontend_test_tool: "{{fe_test_tool}}"
|
|
724
1007
|
frontend_ok: "{{fe_ok}}"
|
|
725
1008
|
frontend_gaps: "{{fe_gaps}}"
|
|
726
|
-
|
|
1009
|
+
frontend_verdict: "{{fe_verdict}}" # as recorded in .aw-slice-gate.frontend.json
|
|
1010
|
+
report: "{{report_file}}" # delta-slice-analyze-report.<lane>.md when one lane of two is worked
|
|
727
1011
|
source_count: "{{source_count}}"
|
|
728
|
-
note: "Gated change {{cr_id}} (wave {{wave}}) — delta-spec.md is the ANCHOR, so the question answered here is whether the CODE does what the change asked for, not whether it matches the plan. The delta plan is the MAP from a requirement to the element that serves it, and is cross-checked in its own right; the change's model delta supplies the invariants the code must enforce, and they are requirements too. The masters are read-only context for what was already there — they do not carry this change until finalize-delta merges it. Only a lane
|
|
1012
|
+
note: "Gated change {{cr_id}} (wave {{wave}}) — delta-spec.md is the ANCHOR, so the question answered here is whether the CODE does what the change asked for, not whether it matches the plan. The delta plan is the MAP from a requirement to the element that serves it, and is cross-checked in its own right; the change's model delta supplies the invariants the code must enforce, and they are requirements too. The masters are read-only context for what was already there — they do not carry this change until finalize-delta merges it. Only a lane the change names, that you work on and that has a delta plan for THIS change is gated: backend — {{be_state}}; frontend — {{fe_state}}. An ungated lane is reported as not gated, never as a pass, and a lane somebody else works on is gated in their own run. Each gated lane ran its own tests, here for the first time on the change path since build only compiles, and its pass or fail is recorded in {{cr_dir}}/.aw-slice-gate.<lane>.json. This gate verifies: it generated no code and repaired nothing, and every finding names the command that closes it."
|
|
729
1013
|
next: "/appweaver finalize-delta → analyze-slice → close-delta. The change MEETS ITS SPEC and is still OPEN: finalize-delta merges it into spec.md + the context's domain-model.md — writing requirements the code has now been shown to satisfy — analyze-slice then scores the WHOLE slice against those merged masters (behaviour, domain conformance and the referrer blast radius) while a red result is still recoverable, and close-delta LAST archives the change and bumps the version."
|