aw-spec-cli 0.1.26 → 0.1.27

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.
Files changed (98) hide show
  1. package/assets/.agents/skills/appweaver/SKILL.md +7 -47
  2. package/assets/.appweaver/ORCH-DIALECT.md +13 -9
  3. package/assets/.appweaver/RULE-PARTITION.md +3 -3
  4. package/assets/.appweaver/STACK-PROFILES.md +188 -101
  5. package/assets/.appweaver/domain.json +1 -1
  6. package/assets/.appweaver/orchestrator/AGENT-PROFILE.md +38 -10
  7. package/assets/.appweaver/orchestrator/LAUNCHER.md +88 -0
  8. package/assets/.appweaver/orchestrator/README.md +120 -53
  9. package/assets/.appweaver/orchestrator/adapters/claude_agent_sdk.py +1 -1
  10. package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +6 -4
  11. package/assets/.appweaver/orchestrator/modules/foundation-lane.orch.yaml +237 -0
  12. package/assets/.appweaver/orchestrator/modules/foundation-pack.orch.yaml +349 -0
  13. package/assets/.appweaver/orchestrator/modules/foundation-spec.orch.yaml +381 -0
  14. package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +4 -4
  15. package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +3 -3
  16. package/assets/.appweaver/orchestrator/orchestrator.py +162 -63
  17. package/assets/.appweaver/orchestrator/rev-templates/domain-constitution.skeleton.md +2 -2
  18. package/assets/.appweaver/orchestrator/rev-templates/domain-requirements.skeleton.md +2 -2
  19. package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +5 -5
  20. package/assets/.appweaver/orchestrator/rev-templates/frontend-rule-file.skeleton.md +1 -1
  21. package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +14 -14
  22. package/assets/.appweaver/orchestrator/rev-templates/technical-constitution.skeleton.md +2 -2
  23. package/assets/.appweaver/orchestrator/rev-templates/technical-rule-file.skeleton.md +1 -1
  24. package/assets/.appweaver/orchestrator/rev-templates/ui-constitution.skeleton.md +3 -3
  25. package/assets/.appweaver/orchestrator/workflows/_smoke.orch.yaml +41 -3
  26. package/assets/.appweaver/orchestrator/workflows/aw-spec-add-component.orch.yaml +1 -1
  27. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +13 -13
  28. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +3 -3
  29. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +3 -3
  30. package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +4 -4
  31. package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +2 -2
  32. package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +61 -12
  33. package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +172 -293
  34. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +29 -28
  35. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +53 -53
  36. package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +2 -2
  37. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +3 -3
  38. package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +4 -4
  39. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-bounded-context.orch.yaml +26 -2
  40. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-domain.orch.yaml +21 -15
  41. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +14 -14
  42. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +2 -2
  43. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +3 -3
  44. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-prototype.orch.yaml +6 -6
  45. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +284 -128
  46. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +224 -70
  47. package/assets/.appweaver/scripts/python/aw-foundation.py +809 -20
  48. package/assets/.appweaver/scripts/python/aw-inventory.py +28 -21
  49. package/assets/.appweaver/scripts/python/aw-plan-coverage.py +2 -2
  50. package/assets/.appweaver/scripts/python/aw-rev-constitution.py +6 -6
  51. package/assets/.appweaver/scripts/python/aw-stack.py +195 -89
  52. package/assets/.appweaver/stack-profiles/angular.json +2 -1
  53. package/assets/.appweaver/stack-profiles/blazor-wasm.json +2 -1
  54. package/assets/.appweaver/stack-profiles/dotnet-webapi.json +16 -3
  55. package/assets/.appweaver/stack-profiles/go-chi.json +6 -1
  56. package/assets/.appweaver/stack-profiles/java-spring.json +12 -5
  57. package/assets/.appweaver/stack-profiles/nextjs.json +2 -1
  58. package/assets/.appweaver/stack-profiles/node-express.json +8 -2
  59. package/assets/.appweaver/stack-profiles/python-fastapi.json +9 -2
  60. package/assets/.appweaver/stack-profiles/react-vite.json +2 -1
  61. package/assets/.appweaver/stack-profiles/sveltekit.json +2 -1
  62. package/assets/.appweaver/stack-profiles/vue-vite.json +2 -1
  63. package/assets/.appweaver/stacks.json +37 -1
  64. package/assets/.appweaver/templates/constitution-ui-template.md +2 -2
  65. package/assets/.claude/skills/appweaver/SKILL.md +7 -46
  66. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.Reference.rules.json +31 -0
  67. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.Reference.rules.json +16 -0
  68. package/assets/foundations/foundation.spec.template.txt +73 -0
  69. package/assets/foundations/java/Hexagonal/Hexagonal.pack.txt +1 -1
  70. package/assets/foundations/java/Hexagonal/unpack-foundation.sh +4 -5
  71. package/assets/foundations/node/NextAppRouter/NextAppRouter.spec.txt +68 -0
  72. package/assets/guardrails/README.md +31 -17
  73. package/assets/guardrails/{projects/dotnet-default-project → project-specific}/domain-rule-bindings.md +5 -5
  74. package/assets/guardrails/{projects/dotnet-default-project → project-specific}/tech-rule-bindings.md +151 -114
  75. package/assets/guardrails/technology/dotnet-webapi/PACKAGING.md +58 -4
  76. package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +1 -1
  77. package/assets/guardrails/technology/dotnet-webapi/dependency-policy.md +1 -1
  78. package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +1 -1
  79. package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +1 -1
  80. package/assets/guardrails/technology/dotnet-webapi/testing.md +1 -1
  81. package/assets/guardrails/technology/nextjs/api-client.md +1 -1
  82. package/assets/guardrails/technology/nextjs/component-architecture.md +1 -1
  83. package/assets/guardrails/technology/nextjs/component-conventions.md +2 -2
  84. package/assets/guardrails/technology/nextjs/design-system.md +1 -1
  85. package/assets/guardrails/technology/nextjs/frontend-testing.md +1 -1
  86. package/assets/guardrails/technology/nextjs/routing-navigation.md +1 -1
  87. package/assets/guardrails/technology/nextjs/ui-constitution.md +3 -3
  88. package/package.json +1 -1
  89. package/assets/.agents/skills/appweaver-demo/SKILL.md +0 -59
  90. package/assets/.appweaver/orchestrator/.smoke-out/smoke.md +0 -6
  91. package/assets/.appweaver/orchestrator/workflows/aw-spec-demo.orch.yaml +0 -100
  92. package/assets/.claude/skills/appweaver-demo/SKILL.md +0 -59
  93. package/assets/.kilocode/agent.json +0 -28
  94. package/assets/.kilocode/workflows/appweaver-demo.md +0 -59
  95. package/assets/.kilocode/workflows/appweaver.md +0 -55
  96. /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/domain/domain-requirements.md +0 -0
  97. /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/frontend/ui-requirements.md +0 -0
  98. /package/assets/guardrails/{projects/dotnet-default-project → project-specific}/service/technical-requirements.md +0 -0
@@ -0,0 +1,349 @@
1
+ # =============================================================================
2
+ # foundation-pack (orchestrator) — scaffold ONE lane by unpacking a foundation pack
3
+ #
4
+ # Included by foundation-lane when the operator picks a `[pack]` entry. Almost entirely
5
+ # deterministic: locate the verified byte-for-byte bundle, confirm, dry-run for
6
+ # collisions, unpack into the lane root folder exactly as packed with the sentinel renamed,
7
+ # optionally add the reference sample on top, and check that no sentinel is left behind.
8
+ #
9
+ # Every file in a pack lands as packed, replacing a file already there — except the ones
10
+ # its RULE FILE (<pack name>.rules.json beside the pack) says to merge. The model is used
11
+ # ONLY for those merges: an `agent_author` (read-only generation, the ENGINE writes the
12
+ # file) with include_standards: false and a two-file context — the file that was there
13
+ # and the pack's version — following the rule's own instruction.
14
+ #
15
+ # Every refusal RETURNS rather than stops: the run carries on with the next lane, and the
16
+ # reason lands in fl_status (message_var), which the caller reports per lane.
17
+ #
18
+ # Inputs (shared vars, set by foundation-lane):
19
+ # fl_name, app, fl_kind, fl_lane_id, fl_title, fl_language, fl_ecosystem,
20
+ # fl_source_path, fl_test_path, fl_overwrite
21
+ # Produces: fl_status, fl_files (files written), and the fp_* details.
22
+ # =============================================================================
23
+
24
+ name: foundation-pack
25
+ dialect: aw-spec.orchestrator/v1
26
+
27
+ scripts:
28
+ actions:
29
+ sh: .appweaver/scripts/bash/aw-spec-actions.sh
30
+ ps1: .appweaver/scripts/powershell/aw-spec-actions.ps1
31
+
32
+ workflow:
33
+
34
+ # 0. This module runs once per lane in the same run, and vars are shared — the second
35
+ # lane must not inherit the first lane's overwrite answer or reference choice.
36
+ - id: fp_reset
37
+ action: set
38
+ vars:
39
+ fp_overwrite: "no"
40
+ fp_has_collisions: "false"
41
+ fp_want_reference: "no"
42
+ fp_has_reference: "false"
43
+ fp_merge_state: ".appweaver/orchestrator/.state/foundation-{{fl_lane_id}}.merge/"
44
+ fp_rules_ok: ""
45
+ fp_rules_reason: ""
46
+ fp_rules_file: ""
47
+ fp_merges: "[]"
48
+ fp_rules_note: ""
49
+ fp_ref_rules_ok: ""
50
+ fp_ref_rules_reason: ""
51
+ fp_ref_rules_file: ""
52
+ fp_ref_merges: "[]"
53
+ fp_ref_rules_note: ""
54
+ fp_ref_go: "no"
55
+ fp_ok: ""
56
+ fp_written: "0"
57
+ fp_tests_message: ""
58
+ fp_tests_note: ""
59
+ fp_ref_ok: ""
60
+ fp_ref_written: "0"
61
+ fp_ref_tests_message: ""
62
+ fp_ref_note: ""
63
+ fp_clean: ""
64
+ fp_residue: ""
65
+ fp_residue_note: "not checked"
66
+
67
+ # 1. Locate the bundle + its unpacker and read the (bounded) pack header: the sentinel,
68
+ # the file count, and whether a Reference pack ships beside it.
69
+ - id: fp_locate
70
+ action: execute_script
71
+ script: { ref: actions }
72
+ subcommand: foundation-locate
73
+ args: ["--name", "{{fl_name}}", "--app", "{{app}}", "--out", "{{fl_source_path}}"]
74
+ outputs:
75
+ - { name: fp_locate_ok, from: "$.ok" }
76
+ - { name: fp_locate_msg, from: "$.reason" }
77
+ - { name: fp_available, from: "$.available" }
78
+ - { name: fp_sentinel, from: "$.sentinel" }
79
+ - { name: fp_file_count, from: "$.file_count" }
80
+ - { name: fp_has_reference, from: "$.has_reference" }
81
+
82
+ - id: fp_locate_gate
83
+ action: verify_context
84
+ require_true: fp_locate_ok
85
+ on_false: return
86
+ message_var: fl_status
87
+ on_false_message: "not scaffolded — {{fp_locate_msg}} (packs available: {{fp_available}})"
88
+
89
+ # 1b. The lane already had files and foundation-lane's overwrite question was answered
90
+ # yes before the pick list: that answer stands, so the unpack overwrites and the
91
+ # collision question below is not asked a second time.
92
+ - id: fp_overwrite_agreed
93
+ action: set
94
+ condition: "{{fl_overwrite}} == yes"
95
+ vars: { fp_overwrite: "yes" }
96
+
97
+ # 2. Confirm (checkpoint kind 'ask' under every strategy).
98
+ - id: fp_confirm
99
+ action: ask
100
+ prompt: |
101
+ Foundation: {{fl_name}} pack (sentinel {{fp_sentinel}}, {{fp_file_count}} files)
102
+ App name: {{app}}
103
+ Lane: {{fl_lane_id}} — {{fl_title}}, {{fl_language}} ({{fl_ecosystem}})
104
+ Folder: {{fl_source_path}} <- the pack unpacks here as packed: build files, source and tests
105
+ Tests: {{fl_test_path}}
106
+ Overwrite: {{fp_overwrite}} <- yes: files the pack writes replace existing ones
107
+ The sentinel {{fp_sentinel}} is renamed to {{app}} in file contents and paths, as the
108
+ replacement contract in the pack's header describes. Proceed?
109
+ options: ["yes", "no"]
110
+ answer_var: fp_proceed
111
+
112
+ - id: fp_confirm_gate
113
+ action: verify_context
114
+ require_value: fp_proceed
115
+ equals: "yes"
116
+ on_mismatch: return
117
+ message_var: fl_status
118
+ on_mismatch_message: "not scaffolded — the {{fl_name}} pack was declined at the confirmation; nothing was written to {{fl_source_path}}"
119
+
120
+ # 3. Dry-run to surface collisions, then confirm overwrite if needed — only for a lane
121
+ # that was empty: one that already had files was asked before the pick list (step 1b).
122
+ - id: fp_dry_run
123
+ action: execute_script
124
+ condition: "{{fl_overwrite}} != yes"
125
+ script: { ref: actions }
126
+ subcommand: foundation-unpack
127
+ args: ["--name", "{{fl_name}}", "--app", "{{app}}", "--out", "{{fl_source_path}}", "--dry-run"]
128
+ outputs:
129
+ - { name: fp_has_collisions, from: "$.has_collisions" }
130
+
131
+ - id: fp_ask_overwrite
132
+ action: ask
133
+ condition: "{{fp_has_collisions}} == true"
134
+ prompt: "Files the {{fl_name}} pack writes already exist under {{fl_source_path}}. Overwrite them?"
135
+ options: ["yes", "no"]
136
+ answer_var: fp_overwrite
137
+
138
+ - id: fp_overwrite_gate
139
+ action: verify_context
140
+ condition: "{{fp_has_collisions}} == true"
141
+ require_value: fp_overwrite
142
+ equals: "yes"
143
+ on_mismatch: return
144
+ message_var: fl_status
145
+ on_mismatch_message: "not scaffolded — files the {{fl_name}} pack writes already exist under {{fl_source_path}} and overwriting them was declined"
146
+
147
+ # 4. The pack's rule file: which of its files are merged with what the lane holds now.
148
+ # Read before anything is written, so a broken rule file leaves the lane untouched;
149
+ # the files to merge with are put aside under fp_merge_state.
150
+ - id: fp_rules
151
+ action: execute_script
152
+ script: { ref: actions }
153
+ subcommand: foundation-rules
154
+ args: ["--name", "{{fl_name}}", "--app", "{{app}}", "--out", "{{fl_source_path}}", "--state", "{{fp_merge_state}}"]
155
+ outputs:
156
+ - { name: fp_rules_ok, from: "$.ok" }
157
+ - { name: fp_rules_reason, from: "$.reason" }
158
+ - { name: fp_rules_file, from: "$.rules_file" }
159
+ - { name: fp_merges, from: "$.merges" }
160
+ - { name: fp_rules_note, from: "$.note" }
161
+
162
+ - id: fp_rules_gate
163
+ action: verify_context
164
+ require_true: fp_rules_ok
165
+ on_false: return
166
+ message_var: fl_status
167
+ on_false_message: "not scaffolded — {{fp_rules_reason}}; nothing was written to {{fl_source_path}}"
168
+
169
+ # 5. Unpack for real, and check it worked: an unpacker that refuses (existing files, a
170
+ # bad name) exits non-zero with 0 files written, and reporting that as a scaffold is
171
+ # how a lane with no project gets as far as implement.
172
+ - id: fp_unpack
173
+ action: execute_script
174
+ script: { ref: actions }
175
+ subcommand: foundation-unpack
176
+ args: ["--name", "{{fl_name}}", "--app", "{{app}}", "--out", "{{fl_source_path}}", "--test-path", "{{fl_test_path}}", "--force", "{{fp_overwrite}}"]
177
+ outputs:
178
+ - { name: fp_ok, from: "$.ok" }
179
+ - { name: fp_written, from: "$.written" }
180
+ - { name: fp_tests_message, from: "$.tests_message" }
181
+ - { name: fp_unpack_out, from: "$.stdout" }
182
+
183
+ - id: fp_unpack_gate
184
+ action: verify_context
185
+ require_true: fp_ok
186
+ on_false: return
187
+ message_var: fl_status
188
+ on_false_message: "NOT scaffolded — the {{fl_name}} unpacker failed and wrote {{fp_written}} file(s). Its output ends: {{fp_unpack_out}}"
189
+
190
+ # 6. The merges the rule file asks for: the file that was there (put aside) and the
191
+ # pack's version (now on disk) become one, as the rule's instruction says.
192
+ - id: fp_merge
193
+ action: loop
194
+ over: "{{fp_merges}}"
195
+ as: m
196
+ steps:
197
+ - id: fp_merge_file
198
+ action: agent_author
199
+ context: ["{{m.existing}}", "{{m.target}}"]
200
+ include_standards: false
201
+ task: |
202
+ Merge two versions of {{m.target}} into one file.
203
+ EXISTING {{m.existing}} — the file as it was in the lane before the {{fl_name}} pack was unpacked
204
+ INCOMING {{m.target}} — the file as the pack ships it, with {{fp_sentinel}} renamed to {{app}}
205
+ The pack's rule file ({{fp_rules_file}}) says how, in its rule for {{m.rule}}:
206
+ {{m.instruction}}
207
+ Change nothing that instruction does not ask for.
208
+ output_target: { type: file, path: "{{m.target}}" }
209
+
210
+ - id: fp_rules_done
211
+ action: execute_script
212
+ script: { ref: actions }
213
+ subcommand: foundation-rules-done
214
+ args: ["--state", "{{fp_merge_state}}"]
215
+
216
+ # 7. Optional reference sample — offered only when the pack ships one. It goes on top
217
+ # of the base project the same way: its own rule file, the unpack, its merges.
218
+ - id: fp_ask_reference
219
+ action: ask
220
+ condition: "{{fp_has_reference}} == true"
221
+ prompt: "The {{fl_name}} foundation also ships a reference sample ({{fl_name}}.Reference.pack.txt): worked example code unpacked on top of the base project. Include it?"
222
+ options: ["yes", "no"]
223
+ answer_var: fp_want_reference
224
+
225
+ - id: fp_ref_rules
226
+ action: execute_script
227
+ condition: "{{fp_want_reference}} == yes"
228
+ script: { ref: actions }
229
+ subcommand: foundation-rules
230
+ args: ["--name", "{{fl_name}}", "--app", "{{app}}", "--out", "{{fl_source_path}}", "--reference", "--state", "{{fp_merge_state}}"]
231
+ outputs:
232
+ - { name: fp_ref_rules_ok, from: "$.ok" }
233
+ - { name: fp_ref_rules_reason, from: "$.reason" }
234
+ - { name: fp_ref_rules_file, from: "$.rules_file" }
235
+ - { name: fp_ref_merges, from: "$.merges" }
236
+ - { name: fp_ref_rules_note, from: "$.note" }
237
+
238
+ # A broken rule file keeps the sample out but leaves the base project in place, so this
239
+ # reports and carries on rather than returning.
240
+ - id: fp_ref_rules_gate
241
+ action: verify_context
242
+ condition: "{{fp_want_reference}} == yes"
243
+ require_true: fp_ref_rules_ok
244
+ on_false: continue
245
+ message_var: fp_ref_note
246
+ on_false_message: "; the reference sample was NOT added — {{fp_ref_rules_reason}}"
247
+
248
+ - id: fp_ref_go
249
+ action: set
250
+ condition: "{{fp_ref_rules_ok}} == true"
251
+ vars: { fp_ref_go: "yes" }
252
+
253
+ - id: fp_reference_unpack
254
+ action: execute_script
255
+ condition: "{{fp_ref_go}} == yes"
256
+ script: { ref: actions }
257
+ subcommand: foundation-unpack
258
+ args: ["--name", "{{fl_name}}", "--app", "{{app}}", "--out", "{{fl_source_path}}", "--test-path", "{{fl_test_path}}", "--reference"]
259
+ outputs:
260
+ - { name: fp_ref_ok, from: "$.ok" }
261
+ - { name: fp_ref_written, from: "$.written" }
262
+ - { name: fp_ref_tests_message, from: "$.tests_message" }
263
+ - { name: fp_ref_out, from: "$.stdout" }
264
+
265
+ # A failed reference sample does not undo the base project, so this reports and carries
266
+ # on to the residue check rather than returning.
267
+ - id: fp_reference_gate
268
+ action: verify_context
269
+ condition: "{{fp_ref_go}} == yes"
270
+ require_true: fp_ref_ok
271
+ on_false: continue
272
+ message_var: fp_ref_note
273
+ on_false_message: "; the reference sample FAILED to unpack ({{fp_ref_out}})"
274
+
275
+ - id: fp_reference_done
276
+ action: set
277
+ condition: "{{fp_ref_ok}} == true"
278
+ vars: { fp_ref_note: "; reference sample added ({{fp_ref_written}} file(s))" }
279
+
280
+ # The sample's own test tree is lifted onto the lane's test path like the base pack's;
281
+ # say what happened to it, or the lane line reports only the base pack's tests.
282
+ - id: fp_reference_tests_noted
283
+ action: set
284
+ condition: "{{fp_ref_tests_message}} != "
285
+ vars: { fp_ref_note: "{{fp_ref_note}} — its tests: {{fp_ref_tests_message}}" }
286
+
287
+ # The sample's merges: what the base project (or the lane before it) had, and the
288
+ # sample's version, become one as the sample's rule file says.
289
+ - id: fp_ref_merge
290
+ action: loop
291
+ condition: "{{fp_ref_ok}} == true"
292
+ over: "{{fp_ref_merges}}"
293
+ as: m
294
+ steps:
295
+ - id: fp_ref_merge_file
296
+ action: agent_author
297
+ context: ["{{m.existing}}", "{{m.target}}"]
298
+ include_standards: false
299
+ task: |
300
+ Merge two versions of {{m.target}} into one file.
301
+ EXISTING {{m.existing}} — the file as it was in the lane before the {{fl_name}} reference sample was unpacked
302
+ INCOMING {{m.target}} — the file as the reference sample ships it, with {{fp_sentinel}} renamed to {{app}}
303
+ The sample's rule file ({{fp_ref_rules_file}}) says how, in its rule for {{m.rule}}:
304
+ {{m.instruction}}
305
+ Change nothing that instruction does not ask for.
306
+ output_target: { type: file, path: "{{m.target}}" }
307
+
308
+ - id: fp_ref_merged_noted
309
+ action: set
310
+ condition: "{{fp_ref_ok}} == true"
311
+ vars: { fp_ref_note: "{{fp_ref_note}}{{fp_ref_rules_note}}" }
312
+
313
+ - id: fp_ref_rules_done
314
+ action: execute_script
315
+ condition: "{{fp_ref_go}} == yes"
316
+ script: { ref: actions }
317
+ subcommand: foundation-rules-done
318
+ args: ["--state", "{{fp_merge_state}}"]
319
+
320
+ # 8. Verify — sentinel residue must be zero in the generated tree.
321
+ - id: fp_verify
322
+ action: execute_script
323
+ script: { ref: actions }
324
+ subcommand: foundation-verify
325
+ args: ["--out", "{{fl_source_path}}", "--sentinel", "{{fp_sentinel}}"]
326
+ outputs:
327
+ - { name: fp_clean, from: "$.clean" }
328
+ - { name: fp_residue, from: "$.residue" }
329
+
330
+ - id: fp_residue_clean
331
+ action: set
332
+ condition: "{{fp_clean}} == true"
333
+ vars: { fp_residue_note: "no sentinel left" }
334
+
335
+ - id: fp_residue_found
336
+ action: set
337
+ condition: "{{fp_clean}} == false"
338
+ vars: { fp_residue_note: "SENTINEL {{fp_sentinel}} STILL IN {{fp_residue}}" }
339
+
340
+ - id: fp_tests_noted
341
+ action: set
342
+ condition: "{{fp_tests_message}} != "
343
+ vars: { fp_tests_note: "; {{fp_tests_message}}" }
344
+
345
+ - id: fp_done
346
+ action: set
347
+ vars:
348
+ fl_files: "{{fp_written}}"
349
+ fl_status: "scaffolded from the {{fl_name}} pack — {{fp_written}} file(s) into {{fl_source_path}}{{fp_tests_note}}{{fp_rules_note}}{{fp_ref_note}}; {{fp_residue_note}}"