aw-spec-cli 0.1.15 → 0.1.17

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 (69) hide show
  1. package/assets/.appweaver/DESIGN-FORMAT.md +18 -18
  2. package/assets/.appweaver/ORCH-DIALECT.md +1 -3
  3. package/assets/.appweaver/RULE-PARTITION.md +29 -13
  4. package/assets/.appweaver/STACK-PROFILES.md +10 -9
  5. package/assets/.appweaver/orchestrator/.state/smoke.state.json +32 -0
  6. package/assets/.appweaver/orchestrator/AGENT-PROFILE.md +4 -1
  7. package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +251 -0
  8. package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +104 -35
  9. package/assets/.appweaver/orchestrator/orchestrator.py +5 -4
  10. package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +94 -36
  11. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +1 -1
  12. package/assets/.appweaver/orchestrator/rev-templates/domain-model-template.skeleton.md +115 -0
  13. package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +2 -9
  14. package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +16 -40
  15. package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +38 -17
  16. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +8 -8
  17. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +10 -11
  18. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +673 -0
  19. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +535 -0
  20. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +643 -0
  21. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +78 -626
  22. package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +4 -4
  23. package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +7 -7
  24. package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +16 -14
  25. package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +2 -2
  26. package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +243 -144
  27. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +882 -464
  28. package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +4 -4
  29. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +32 -91
  30. package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +2 -2
  31. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +832 -477
  32. package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +2 -2
  33. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-bounded-context.orch.yaml +132 -0
  34. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-feature.orch.yaml +38 -5
  35. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +3 -3
  36. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +271 -892
  37. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +1096 -2911
  38. package/assets/.appweaver/scripts/bash/aw-xref.sh +1 -2
  39. package/assets/.appweaver/scripts/bash/common.sh +47 -0
  40. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +936 -2766
  41. package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +1 -2
  42. package/assets/.appweaver/scripts/python/aw-payload-parity.py +174 -0
  43. package/assets/.appweaver/scripts/python/aw-stack.py +6 -2
  44. package/assets/.appweaver/scripts/python/aw-xref.py +185 -292
  45. package/assets/.appweaver/templates/constitution-ui-template.md +1 -1
  46. package/assets/.appweaver/templates/delta-design-template.md +120 -30
  47. package/assets/.appweaver/templates/delta-domain-model-template.md +81 -0
  48. package/assets/.appweaver/templates/delta-spec-template.md +43 -17
  49. package/assets/.appweaver/templates/design-template.md +68 -98
  50. package/assets/.appweaver/templates/domain-model-template.md +130 -0
  51. package/assets/.appweaver/templates/okf-concept-template.md +2 -2
  52. package/assets/.appweaver/templates/source-map-template.md +3 -3
  53. package/assets/.appweaver/templates/spec-template.md +100 -122
  54. package/assets/.appweaver/templates/ui-delta-design-template.md +159 -0
  55. package/assets/.appweaver/templates/ui-design-template.md +46 -75
  56. package/assets/guardrails/projects/dotnet-default-project/domain-rule-bindings.md +7 -18
  57. package/assets/guardrails/projects/dotnet-default-project/tech-rule-bindings.md +34 -39
  58. package/assets/guardrails/requirement-spec.txt +2 -2
  59. package/assets/guardrails/technology/dotnet-webapi/testing.md +1 -1
  60. package/package.json +1 -1
  61. package/assets/.appweaver/orchestrator/modules/delta-design.orch.yaml +0 -105
  62. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-delta-design.orch.yaml +0 -251
  63. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-design.orch.yaml +0 -749
  64. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-delta.orch.yaml +0 -253
  65. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-ui.orch.yaml +0 -540
  66. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan-ui.orch.yaml +0 -597
  67. package/assets/.appweaver/orchestrator/workflows/aw-spec-story-plan.orch.yaml +0 -945
  68. package/assets/.appweaver/orchestrator/workflows/aw-spec-sync-stories.orch.yaml +0 -1040
  69. package/assets/.appweaver/templates/story-template.md +0 -147
@@ -1,540 +0,0 @@
1
- # =============================================================================
2
- # aw-spec-implement-ui (orchestrator) — UI generation from ONE STORY'S DESIGN
3
- #
4
- # The frontend lane's executable end of the story loop: GENERATE the screens,
5
- # components, client state and paired tests for ONE STORY, strictly from the LATEST
6
- # design pass in that story's own UI design —
7
- # specs/<F>/stories/<ID>/story-frontend-plan.md. It is the twin of `implement`, one
8
- # lane over, and keeps the same contract:
9
- #
10
- # • ONE SLICE, NOT THE FEATURE. The pass names the files it changes; this phase edits
11
- # an existing tree, creating only what the pass says is new, and MERGES its files
12
- # into the feature's OKF concept rather than replacing the list.
13
- # • DESIGN-ONLY. spec.md is not a generation input. It is read once, AFTER the code
14
- # exists, by a read-only acceptance check that reports and never repairs.
15
- # • THE FRAMEWORK BINDS HERE. The design is technology-agnostic — a "component" is a
16
- # responsibility, its inputs are field shapes, its states are named. The framework,
17
- # router, state library, component library and styling approach come from
18
- # constitution.ui.md + the lane declaration + this command's rule set.
19
- # • ONE SUBTREE. The lane owns the source path .appweaver/stacks.json declares for it
20
- # and nothing outside it. A file written elsewhere belongs to the service lane.
21
- #
22
- # THE UI LANE CONSUMES THE CONTRACT; IT NEVER DEFINES ONE. interfaces.md is the
23
- # published surface and the pass binds to it by IF- id. A contract this slice needs that
24
- # the log does not carry is a DEFECT to surface — never an endpoint to invent, and never
25
- # a reason to reach into the service lane's code. Where the SAME story has a service
26
- # design it is in context too, as the newer word on what that surface will be.
27
- #
28
- # WHY A SEPARATE COMMAND, NOT A UI BRANCH INSIDE `implement`. The two lanes take their
29
- # code-generation rules from different map headings and write into disjoint subtrees.
30
- # Keying the rule maps on `## /aw-spec-implement-ui` gives the lane its own rule set for
31
- # zero mechanism change; a UI branch inside `implement` would generate frontend code
32
- # under the service lane's standards. (`story-plan` designs BOTH lanes in one run
33
- # because everything ahead of its authoring step is shared; here nothing is — the
34
- # lane, the subtree, the rules and the OKF key all differ.)
35
- #
36
- # GATES (all loud, all before any write): the frontend lane declared with its source
37
- # path; a project scaffolded under THAT path specifically — a manifest found only
38
- # elsewhere is the service lane's, and accepting it is how a frontend that was never
39
- # built reports green; an active feature; an OPEN story; and that story having a UI
40
- # design at all. A design behind the current spec, or a story the spec has moved past,
41
- # is ANNOUNCED, never refused; the route out of both is named.
42
- #
43
- # Launch: /appweaver implement-ui [<story-id>] [guidance] (asks when ambiguous)
44
- # Prereq: /appweaver story-plan (the story's UI design) · Next: /appweaver build
45
- # =============================================================================
46
-
47
- name: aw-spec-implement-ui
48
- description: "Generate the frontend lane's screens, components, client state and paired tests for ONE STORY, strictly from the LATEST design pass in stories/<ID>/story-frontend-plan.md, bound to the declared UI stack and written only under that lane's source path. Model-driven and design-only — the spec is never a generation input; it appears once afterwards in a read-only acceptance check that reports and never repairs. Consumes interfaces.md by IF- id and never publishes into it. Incremental by contract: it edits the lane's existing tree and MERGES its files into the feature's OKF concept under ui_source_files, so the service lane's list is untouched."
49
- version: 2.0.0
50
- agent_agnostic: true
51
- dialect: aw-spec.orchestrator/v1
52
-
53
- inputs:
54
- user_input:
55
- description: Optional story id and/or implementation guidance (e.g. "Order-001 reuse the shared date picker").
56
- required: false
57
- bind: USER_INPUT
58
-
59
- scripts:
60
- actions:
61
- sh: .appweaver/scripts/bash/aw-spec-actions.sh
62
- ps1: .appweaver/scripts/powershell/aw-spec-actions.ps1
63
- xref:
64
- sh: .appweaver/scripts/bash/aw-xref.sh
65
- ps1: .appweaver/scripts/powershell/aw-xref.ps1
66
-
67
- # Sticky standards seed = the UNIVERSAL always-on rule only (ai-rules). The lane's
68
- # FRONTEND code-generation rule files are CONFIGURATION, loaded per-command from
69
- # guardrails/projects/<project>/tech-rule-bindings.md under `## /aw-spec-implement-ui`
70
- # by the tech-select module. Per the rule-partition this phase loads NO domain rule
71
- # file — the domain reached the lane through spec → frontend-plan.md → the story's
72
- # design pass. The lane's ratified base arrives via constitution.ui.md (referred to
73
- # directly, as-is — NOT mapped).
74
- standards:
75
- - { path: .appweaver/ai-rules.md } # kit-resident: the universal operating rules, every flow
76
-
77
- vars:
78
- feature_dir: ""
79
- spec_file: ""
80
- # story resolution
81
- any_open: "false"
82
- open_ids: "[]"
83
- digest: ""
84
- resolved: "false"
85
- needs_pick: "false"
86
- pick_reason: ""
87
- picked_story: ""
88
- story: ""
89
- story_path: ""
90
- story_open: "false"
91
- status_msg: ""
92
- story_title: ""
93
- exercises_csv: ""
94
- constraints_csv: ""
95
- current_version: ""
96
- stale_csv: ""
97
- stale_note: ""
98
- story_dir: ""
99
- adr_path: ""
100
- if_path: ""
101
- # the story's UI design (+ the SERVICE design of the same story, for the contract)
102
- design_doc: ""
103
- design_exists: "false"
104
- design_pass: "0"
105
- design_spec_version: ""
106
- design_stale: "false"
107
- service_design_doc: ""
108
- # the feature's current code, per lane (OKF)
109
- okf_concept: ""
110
- coverage_digest: ""
111
- fe_source_csv: ""
112
- fe_source_count: "0"
113
- be_source_count: "0"
114
- # generation + enrichment
115
- files: ""
116
- accept_ok: "true"
117
- accept_gaps: ""
118
-
119
- workflow:
120
-
121
- # 0. FRONTEND code-generation rule files → sticky standards (configuration, not
122
- # hardcoded). No blocking gate: an unmapped project soft-continues, because
123
- # constitution.ui.md still carries the lane's conventions and forbidden patterns.
124
- - id: tech_select
125
- action: include
126
- module: .appweaver/orchestrator/modules/tech-select.orch.yaml
127
- with: { command: aw-spec-implement-ui }
128
-
129
- # 1. The active feature. spec.md is resolved here for the acceptance check ONLY —
130
- # it is not a generation input.
131
- - id: feature_paths
132
- action: execute_script
133
- on_error: continue # never crash raw on 'no feature set' — the gate below explains it
134
- script: { ref: actions }
135
- subcommand: feature-paths
136
- outputs:
137
- - { name: feature_dir, from: "$.feature_dir" }
138
- - { name: spec_file, from: "$.spec_file" }
139
- - id: require_feature
140
- action: verify_context
141
- require_non_empty: feature_dir
142
- on_empty: stop
143
- on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the aggregate, e.g. Order), then re-run implement-ui."
144
-
145
- # 2. WHICH STORY — the same resolution story-plan and implement use.
146
- - id: story_scan
147
- action: execute_script
148
- script: { ref: actions }
149
- subcommand: story-plan-check
150
- args: ["--feature-dir", "{{feature_dir}}", "--input", "{{USER_INPUT}}"]
151
- outputs:
152
- - { name: any_open, from: "$.any_open" }
153
- - { name: open_ids, from: "$.open_ids" }
154
- - { name: digest, from: "$.digest" }
155
- - { name: resolved, from: "$.resolved" }
156
- - { name: needs_pick, from: "$.needs_pick" }
157
- - { name: pick_reason, from: "$.pick_reason" }
158
- - { name: story, from: "$.story" }
159
- - { name: story_path, from: "$.story_path" }
160
- - { name: story_open, from: "$.story_open" }
161
- - { name: status_msg, from: "$.status_msg" }
162
- - { name: story_title, from: "$.story_title" }
163
- - { name: exercises_csv, from: "$.exercises_csv" }
164
- - { name: constraints_csv, from: "$.constraints_csv" }
165
- - { name: current_version, from: "$.current_version" }
166
- - { name: stale_csv, from: "$.stale_csv" }
167
- - { name: stale_note, from: "$.stale_note" }
168
- - { name: story_dir, from: "$.story_dir" }
169
- - { name: adr_path, from: "$.adr_path" }
170
- - { name: if_path, from: "$.if_path" }
171
- - { name: design_doc, from: "$.fe_doc_path" }
172
- - { name: design_exists, from: "$.fe_doc_exists" }
173
- - { name: design_pass, from: "$.fe_last_pass" }
174
- - { name: design_spec_version, from: "$.fe_doc_spec_version" }
175
- - { name: design_stale, from: "$.fe_doc_stale" }
176
- - { name: service_design_doc, from: "$.be_doc_path" }
177
- - id: require_open_backlog
178
- action: verify_context
179
- require_true: any_open
180
- on_false: stop
181
- on_false_message: "No open stories for this feature — there is nothing to implement. Stories are minted by /appweaver specify (bootstrap) and /appweaver sync-stories (when the spec moves)."
182
- - id: ask_story
183
- condition: "{{needs_pick}} == true"
184
- action: ask
185
- prompt: |
186
- Which story is this UI implementation for? ({{pick_reason}})
187
-
188
- {{digest}}
189
- options_from: "{{open_ids}}"
190
- answer_key: picked_story
191
- answer_var: picked_story
192
- - id: story_pick_check
193
- condition: "{{needs_pick}} == true"
194
- action: execute_script
195
- script: { ref: actions }
196
- subcommand: story-plan-check
197
- args: ["--feature-dir", "{{feature_dir}}", "--story", "{{picked_story}}"]
198
- outputs:
199
- - { name: resolved, from: "$.resolved" }
200
- - { name: story, from: "$.story" }
201
- - { name: story_path, from: "$.story_path" }
202
- - { name: story_open, from: "$.story_open" }
203
- - { name: status_msg, from: "$.status_msg" }
204
- - { name: story_title, from: "$.story_title" }
205
- - { name: exercises_csv, from: "$.exercises_csv" }
206
- - { name: constraints_csv, from: "$.constraints_csv" }
207
- - { name: stale_csv, from: "$.stale_csv" }
208
- - { name: stale_note, from: "$.stale_note" }
209
- - { name: story_dir, from: "$.story_dir" }
210
- - { name: design_doc, from: "$.fe_doc_path" }
211
- - { name: design_exists, from: "$.fe_doc_exists" }
212
- - { name: design_pass, from: "$.fe_last_pass" }
213
- - { name: design_spec_version, from: "$.fe_doc_spec_version" }
214
- - { name: design_stale, from: "$.fe_doc_stale" }
215
- - { name: service_design_doc, from: "$.be_doc_path" }
216
- - id: require_story
217
- action: verify_context
218
- require_true: resolved
219
- on_false: stop
220
- on_false_message: |
221
- Could not resolve a story from '{{picked_story}}'. Open stories:
222
- {{digest}}
223
- Re-run implement-ui naming one of them.
224
- - id: require_open_story
225
- action: verify_context
226
- require_true: story_open
227
- on_false: stop
228
- on_false_message: "{{status_msg}}"
229
-
230
- # 3. THE STORY MUST HAVE A UI DESIGN. A story with a service design and no UI one is
231
- # not a failure — it is a slice with no user-facing surface, and the message says
232
- # so rather than implying something is broken.
233
- - id: require_design
234
- action: verify_context
235
- require_true: design_exists
236
- on_false: stop
237
- on_false_message: "Story {{story}} has no UI design — {{story_dir}}/story-frontend-plan.md does not exist. Either this slice has no user-facing surface (nothing to do here; run /appweaver implement for the service half), or the UI lane was out of scope when it was designed — a frontend lane that is undeclared, or a frontend-plan.md that is missing or behind the spec, drops that lane from a story-plan run and says so. Fix whichever it was and re-run /appweaver story-plan {{story}}."
238
-
239
- # 3a. Announced, never refused — the same contract implement keeps. design_stale is a
240
- # JSON boolean, so `condition:` does the deciding and the value gate is only the
241
- # vehicle that prints (law 43); stale_csv is a string and compares directly.
242
- - id: design_stale_notice
243
- condition: "{{design_stale}} == true"
244
- action: verify_context
245
- require_value: design_stale
246
- equals: "false"
247
- on_mismatch: continue
248
- on_mismatch_message: "UI design pass {{design_pass}} was written against spec {{design_spec_version}} and the spec is now at {{current_version}}. Generating from it is not wrong — the move may not touch this story — but if it does, the code inherits a contract that no longer holds. Re-run /appweaver story-plan {{story}} to design against the current spec, or check the ids named below."
249
- - id: story_stale_notice
250
- action: verify_context
251
- require_value: stale_csv
252
- equals: ""
253
- on_mismatch: continue
254
- on_mismatch_message: "The spec has moved on ids THIS story carries: {{stale_csv}}. Whatever this run generates for them realises superseded wording. Consider /appweaver sync-stories to bring the backlog back in step, then /appweaver story-plan {{story}}, before building."
255
-
256
- # 4. THE FRONTEND LANE and its source path — the only subtree this phase may write
257
- # into, resolved before the project gate that searches it.
258
- - id: lane_gate
259
- action: include
260
- module: .appweaver/orchestrator/modules/lane-gate.orch.yaml
261
- with: { require: frontend, command: "/appweaver implement-ui" }
262
-
263
- # 5. Require a frontend PROJECT under the LANE'S OWN path. detect-project searches the
264
- # lane subtree first and falls back to the whole repository, reporting which scope
265
- # answered. THAT DISTINCTION IS THE GATE HERE. A repo-scope hit in a two-lane
266
- # project is the service lane's manifest, and accepting it is exactly the failure
267
- # the lane model exists to prevent — a frontend that was never scaffolded,
268
- # generated into anyway, reporting green.
269
- - id: detect_ui_project
270
- action: execute_script
271
- script: { ref: actions }
272
- subcommand: detect-project
273
- args: ["--root", "{{lane_source_path}}"]
274
- outputs:
275
- - { name: ui_project_present, from: "$.scaffolded" }
276
- - { name: project_markers, from: "$.markers" }
277
- - { name: project_scope, from: "$.scope" }
278
- - id: ui_project_gate
279
- action: verify_context
280
- require_value: project_scope
281
- equals: "lane"
282
- on_mismatch: stop
283
- on_mismatch_message: "No frontend project found under the {{lane_id}} lane's source path `{{lane_source_path}}`. implement-ui GENERATES this story's UI into an existing project tree, so one has to be scaffolded there first: run /appweaver foundation <FoundationName> <AppName> where a foundation bundle ships for this stack, or create the project with the stack's own tooling under that path. Any ecosystem manifest inside the lane's path marks it — package.json, go.mod, pyproject.toml, Cargo.toml, pom.xml, build.gradle(.kts) or .sln/.csproj. A manifest found elsewhere in the repository does NOT count: that one belongs to another lane, and generating this lane's code against it is how a frontend that was never built reports green."
284
-
285
- # 6. WHAT ALREADY EXISTS, per lane, from the feature's OKF concept. The UI list is
286
- # what this run edits; the service count tells the pass whether the contract it
287
- # binds to has been built yet. Advisory — a first UI story generates into a clean
288
- # tree and a missing bundle must never block generation.
289
- - id: coverage
290
- action: execute_script
291
- on_error: continue
292
- script: { ref: xref }
293
- subcommand: concept-coverage
294
- args: ["--feature-dir", "{{feature_dir}}", "--ids", "{{exercises_csv}}"]
295
- outputs:
296
- - { name: okf_concept, from: "$.concept" }
297
- - { name: coverage_digest, from: "$.digest" }
298
- - { name: fe_source_csv, from: "$.frontend_csv" }
299
- - { name: fe_source_count, from: "$.frontend_count" }
300
- - { name: be_source_count, from: "$.backend_count" }
301
-
302
- # 7. Pre-execution hooks.
303
- - id: resolve_pre_hooks
304
- action: execute_script
305
- script: { ref: actions }
306
- subcommand: resolve-hooks
307
- args: ["--phase", "before_implement_ui"]
308
- outputs:
309
- - { name: before_hooks, from: "$.hooks" }
310
- - id: dispatch_pre_hooks
311
- action: dispatch_hooks
312
- hooks_from_variable: before_hooks
313
-
314
- # ═══════════════════ GENERATION — one story's UI slice, one pass ═════════════
315
- # The pass constrains WHAT to build; constitution.ui.md, the lane and the loaded
316
- # standards fix HOW. spec.md is deliberately absent — the acceptance check below is
317
- # where it gets its say.
318
- - id: ctx_generate
319
- action: build_context
320
- vars:
321
- story_id: "{{story}}"
322
- story_title: "{{story_title}}"
323
- exercises_csv: "{{exercises_csv}}"
324
- constraints_csv: "{{constraints_csv}}"
325
- pass_number: "{{design_pass}}"
326
- coverage_digest: "{{coverage_digest}}"
327
- ui_source_files_csv: "{{fe_source_csv}}"
328
- ui_source_file_count: "{{fe_source_count}}"
329
- stale_note: "{{stale_note}}"
330
- context:
331
- - { path: "{{design_doc}}" } # the story's UI design — the LATEST pass is the input
332
- - { path: "{{story_path}}" } # the story's acceptance criteria — what "done" means
333
- - { path: "{{if_path}}", optional: true } # the PUBLISHED surface this slice binds to, by IF- id
334
- - { path: "{{service_design_doc}}", optional: true } # the SAME story's service design — the newer word on that surface
335
- - { path: "{{adr_path}}", optional: true } # ratified decisions — binding unless a pass supersedes them
336
- - { path: .appweaver/memory/constitution.ui.md, optional: true } # the lane's ratified UX-* base — conventions, forbidden patterns, gates
337
- - id: generate
338
- action: agent_generate
339
- tools: "Read,Write,Edit" # the existing UI code arrives as {{ui_source_files_csv}} paths, not inlined
340
- permission_mode: acceptEdits
341
- task: |
342
- Implement story {{story_id}} — {{story_title}} — in the frontend lane, from
343
- "## Design pass {{pass_number}}" of the UI story design in context.
344
- Guidance: {{USER_INPUT}}
345
-
346
- THAT PASS IS THE ONLY SOURCE OF WHAT TO BUILD. It is the LAST pass in the
347
- document; every earlier pass is superseded history, and any of them may carry
348
- hand edits that were deliberate. Read the last one and build exactly it. Do NOT
349
- consult or infer from spec.md — it is not in context on purpose.
350
-
351
- THIS IS ONE SLICE OF AN EXISTING FRONTEND, NOT THE WHOLE FEATURE.
352
- - The pass's "### Screens & components" section names, file by file, what to
353
- create and what to modify. Create ONLY the files it names as new; modify the
354
- named existing files IN PLACE. Every other file belongs to work already done —
355
- do not regenerate, reformat or "tidy" it.
356
- - The story delivers {{exercises_csv}} and must satisfy {{constraints_csv}}, of
357
- which the UX- constraints are yours to realise. Anything outside those ids is
358
- another story's work, even if you can see it is missing.
359
- - The code that already exists for this feature, per lane, is below. The UI files
360
- ({{ui_source_file_count}} on disk) are yours to read before you edit; the
361
- service list is there so you can see what the contract is actually backed by.
362
-
363
- {{coverage_digest}}
364
-
365
- {{ui_source_files_csv}}
366
-
367
- BIND THE STACK: this lane is `{{lane_id}}` — {{lane_title}}, language
368
- {{lane_language}} ({{lane_ecosystem}}), declared in .appweaver/stacks.json and
369
- built with `{{lane_build}}`, tested with `{{lane_test}}`. Generate in THAT
370
- framework and no other, using its idioms, its project layout and its test
371
- framework. Take the router, state approach, component library, design system and
372
- styling from the UI constitution + the loaded standards; the design is
373
- technology-agnostic, so do not re-decide anything already fixed there. If the
374
- loaded standards describe a DIFFERENT stack than the one above, the lane wins on
375
- framework and layout — follow the standards' INTENT and STOP to surface the
376
- mismatch in your summary.
377
-
378
- WRITE ONLY UNDER `{{lane_source_path}}` — the source path the `{{lane_id}}` lane
379
- declares. NEVER touch the service lane's code, not even to add a field the UI
380
- wants: a gap in the service surface is a contract delta raised back to that lane,
381
- not a file you edit. Do not create a parallel source tree because the layout
382
- inside this one is unfamiliar; if the pass needs a place this subtree has no home
383
- for, STOP and surface it.
384
-
385
- Rules:
386
- - THE PASS IS THE ONLY DOMAIN INPUT. You have it, the story, and the lane's
387
- frontend standards — and NO domain rule files. Introduce NO domain rule,
388
- identifier, terminology or behaviour the pass does not state. If a domain
389
- specific seems missing, STOP and surface it; never invent it from memory.
390
- - Follow the UI constitution's folder structure, naming conventions and forbidden
391
- patterns, plus the loaded standards, for HOW to structure, name and place files
392
- WITHIN that subtree — the pass says WHAT to build; these say HOW.
393
- - REALISE THE PASS EXACTLY, changing nothing about WHAT it specifies:
394
- • its "### Approach" — the routes and screens it touches, and where this
395
- slice's state lives. Anything the design says must NOT be held never reaches
396
- client state, storage, the URL or telemetry.
397
- • its "### Screens & components" — each component with the responsibility, the
398
- input shapes and the events the pass gives it. Compose the shared components
399
- it says it reuses; do not re-implement them.
400
- • its "### Contract binding" — call each interface BY ITS IF- id as the pass
401
- names it, with the request it states, and render EVERY state it lists:
402
- in-flight, empty, error and the failure behaviour. These are requirements,
403
- not polish, and they are the first thing a generator drops.
404
- - THE CONTRACT IS NOT YOURS TO INVENT. interfaces.md (in context) is the
405
- published surface; bind to the latest entry per id. If the pass names an
406
- interface the log does not carry, STOP and surface it — do not invent an
407
- endpoint, and do not reach into the service lane to add one. Where the SAME
408
- story's service design is in context, it is the newer word on what that surface
409
- will be; bind to it and say so in your summary.
410
- - THE CLIENT IS NOT AN AUTHORITY. A client-side validation or permission check
411
- restates a server rule for feedback; it never replaces it. Generate no
412
- server-side behaviour, no persistence and no business-rule evaluation here.
413
- - ADRs are DECIDED — follow them. The pass may propose a superseding one; a
414
- proposal is not yet ratified, so follow the pass and change nothing else.
415
- - Author a paired test for every acceptance criterion in the story and every
416
- behaviour the pass's "### Tests" section names — including the unwanted-state
417
- cases from its contract binding and an accessibility assertion per interactive
418
- surface — and cite the requirement id ({{exercises_csv}}, {{constraints_csv}})
419
- each test exists for. A snapshot alone is not a test.
420
- - Do NOT add behaviour the pass does not state, and do NOT omit any it does. If
421
- the pass looks wrong or incomplete, STOP and surface it — it is fixed by
422
- re-running /appweaver story-plan, never compensated for here.
423
- - This feature OWNS its files; never regenerate a file another feature owns, and
424
- do not modify the app shell, global layout or design system — they belong to no
425
- feature. If one of them has to change, STOP and surface it.
426
- {{stale_note}}
427
- outputs:
428
- - { name: files, from: "$.files" }
429
-
430
- - id: verify_generated
431
- action: verify_context
432
- require_non_empty: files
433
- on_empty: stop
434
- on_empty_message: "No files generated for story {{story}}. Check that UI design pass {{design_pass}} in {{design_doc}} actually describes changes (a pass whose '### Screens & components' section is empty has nothing to build), then re-run — or re-run /appweaver story-plan {{story}} to design the slice properly first."
435
-
436
- # 8. OKF — MERGE, into the UI LANE'S KEY. The feature has ONE concept across both
437
- # lanes: `--lane frontend` writes `ui_source_files`, so the service lane's
438
- # `source_files` is untouched whichever lane implements first, and `--merge` unions
439
- # this story's files with what the feature's earlier UI stories wrote. The
440
- # concept's Overview is NOT re-authored here: it describes the aggregate and its
441
- # invariants, which is the service design's subject, and rewriting it from a UI
442
- # slice would trade a domain description for an experience one.
443
- - id: xref_concept
444
- action: execute_script
445
- script: { ref: xref }
446
- subcommand: concept-upsert
447
- args: ["--feature-dir", "{{feature_dir}}", "--source-files", "{{files}}", "--merge", "--lane", "frontend", "--origin", "greenfield"]
448
- outputs:
449
- - { name: okf_concept, from: "$.concept" }
450
-
451
- # ═══════════════ ACCEPTANCE — the ONE place the spec is read ═════════════════
452
- # READ-ONLY and REPORT-ONLY: it never edits code, never edits the pass, and never
453
- # stops the run. A gap means one of two documents is wrong, and which one is a human
454
- # decision — the message names both routes.
455
- - id: ctx_accept
456
- action: build_context
457
- vars:
458
- story_id: "{{story}}"
459
- exercises_csv: "{{exercises_csv}}"
460
- constraints_csv: "{{constraints_csv}}"
461
- files_csv: "{{files}}"
462
- context:
463
- - { path: "{{story_path}}" } # the acceptance criteria
464
- - { path: "{{spec_file}}" } # the contract — the ONLY step in this workflow that reads it
465
- - { path: "{{design_doc}}" } # what was designed
466
- - id: accept_check
467
- action: agent_query
468
- tools: Read # the generated files arrive as paths, not inlined
469
- include_standards: false
470
- schema: { ok: "<true|false>", gaps: "<one line per gap, or empty>" }
471
- mock: { ok: "true", gaps: "" }
472
- task: |
473
- Story {{story_id}} was just implemented in the frontend lane. Judge ONLY this:
474
- does the UI that now exists satisfy the requirements the story delivers, AS THE
475
- SPEC WORDS THEM?
476
-
477
- In scope: {{exercises_csv}} (delivered) and {{constraints_csv}} (must hold) — the
478
- UX- ids among them are this lane's to realise. Resolve each id's wording from
479
- spec.md in context; that wording, not the design's restatement of it, is what the
480
- code is measured against.
481
-
482
- Read the files this run wrote:
483
- {{files_csv}}
484
- plus anything they import that you need to follow. Do not modify a single file.
485
-
486
- Report a gap ONLY where the UI fails to deliver an in-scope id as the spec words
487
- it, or breaks an in-scope constraint. These are NOT gaps, and reporting them is
488
- noise that hides the real ones:
489
- - server-side behaviour — this lane cannot implement it and must not;
490
- - a requirement no story has claimed yet, or one another story delivers;
491
- - style, naming, structure or test-coverage opinions — other gates own those;
492
- - anything the design pass deliberately deferred and named under its risks.
493
-
494
- One line per gap: the id, what the spec requires, and what the UI does instead.
495
- Set ok=false only when you found at least one. If the SPEC and the DESIGN disagree
496
- about an in-scope id, that IS a gap — say which document you believe is wrong and
497
- why, because the two routes out of it are different commands.
498
- outputs:
499
- - { name: accept_ok, from: "$.ok" }
500
- - { name: accept_gaps, from: "$.gaps" }
501
- - id: accept_notice
502
- condition: "{{accept_ok}} != true"
503
- action: verify_context
504
- require_value: accept_ok
505
- equals: "true"
506
- on_mismatch: continue
507
- on_mismatch_message: |
508
- ACCEPTANCE — story {{story}}'s UI does not yet satisfy the spec wording of the ids it delivers:
509
-
510
- {{accept_gaps}}
511
-
512
- Nothing was changed to fix this: the code follows UI design pass {{design_pass}}, so a gap
513
- here means either the design was wrong or the spec has moved. Route by which it is —
514
- the design is wrong: /appweaver story-plan {{story}} (a new pass supersedes this one);
515
- the spec is wrong: /appweaver sync-spec, then sync-stories, then story-plan.
516
- Run /appweaver build either way — a design that is right and code that does not compile
517
- is a third thing, and build is where that one surfaces.
518
-
519
- # 9. Post-execution hooks.
520
- - id: resolve_post_hooks
521
- action: execute_script
522
- script: { ref: actions }
523
- subcommand: resolve-hooks
524
- args: ["--phase", "after_implement_ui"]
525
- outputs:
526
- - { name: after_hooks, from: "$.hooks" }
527
- - id: dispatch_post_hooks
528
- action: dispatch_hooks
529
- hooks_from_variable: after_hooks
530
-
531
- outputs:
532
- story: "{{story}}"
533
- built_from: "{{design_doc}} — UI design pass {{design_pass}} (designed against spec {{design_spec_version}}; spec now {{current_version}})"
534
- requirements: "{{exercises_csv}}"
535
- files: "{{files}}"
536
- lane: "{{lane_id}} → {{lane_source_path}}"
537
- okf_concept: "{{okf_concept}} (this run's files MERGED into ui_source_files; the service lane's source_files is untouched)"
538
- acceptance: "ok={{accept_ok}} · gaps: {{accept_gaps}}"
539
- stale_ids: "{{stale_csv}}"
540
- next: "/appweaver build — it compiles every declared lane, so a break in either surfaces there. Then /appweaver analyze-slice. The story stays OPEN until /appweaver close-story ratifies its ADRs, flips its interface entries live and archives the passes."