aw-spec-cli 0.1.27 → 0.1.29

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 (74) hide show
  1. package/assets/.appweaver/RULE-PARTITION.md +8 -9
  2. package/assets/.appweaver/STACK-PROFILES.md +74 -9
  3. package/assets/.appweaver/interpreter/run-skill.py +28 -7
  4. package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +17 -7
  5. package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +1 -1
  6. package/assets/.appweaver/orchestrator/modules/foundation-pack.orch.yaml +44 -1
  7. package/assets/.appweaver/orchestrator/modules/foundation-spec.orch.yaml +172 -5
  8. package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +5 -4
  9. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +3 -1
  10. package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +16 -8
  11. package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +15 -18
  12. package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +4 -1
  13. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +6 -4
  14. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +7 -6
  15. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +7 -1
  16. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +7 -1
  17. package/assets/.appweaver/orchestrator/workflows/aw-spec-deploy.orch.yaml +1 -1
  18. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +224 -16
  19. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +20 -19
  20. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +35 -11
  21. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +1 -1
  22. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +1 -1
  23. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +91 -7
  24. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +70 -7
  25. package/assets/.appweaver/scripts/python/aw-foundation.py +88 -12
  26. package/assets/.appweaver/scripts/python/aw-stack.py +481 -10
  27. package/assets/.appweaver/stack-profiles/dotnet-webapi.json +2 -0
  28. package/assets/.appweaver/stack-profiles/java-spring.json +2 -0
  29. package/assets/.appweaver/stacks.json +5 -2
  30. package/assets/.appweaver/templates/delta-design-template.md +7 -5
  31. package/assets/.appweaver/templates/design-template.md +3 -0
  32. package/assets/.appweaver/templates/ui-delta-design-template.md +1 -1
  33. package/assets/.appweaver/templates/ui-design-template.md +6 -4
  34. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.lane.json +6 -0
  35. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.lane.json +6 -0
  36. package/assets/foundations/foundation.spec.template.txt +26 -1
  37. package/assets/foundations/java/Hexagonal/Hexagonal.lane.json +6 -0
  38. package/assets/foundations/java/Hexagonal/Hexagonal.pack.txt +7 -0
  39. package/assets/guardrails/project-specific/domain-rule-bindings.md +20 -8
  40. package/assets/guardrails/project-specific/tech-rule-bindings.md +25 -37
  41. package/assets/guardrails/technology/dotnet-webapi/api-versioning.md +1 -1
  42. package/assets/guardrails/technology/dotnet-webapi/auditing.md +1 -1
  43. package/assets/guardrails/technology/dotnet-webapi/authorization.md +1 -1
  44. package/assets/guardrails/technology/dotnet-webapi/clean-architecture.md +1 -1
  45. package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +1 -1
  46. package/assets/guardrails/technology/dotnet-webapi/cqrs.md +1 -1
  47. package/assets/guardrails/technology/dotnet-webapi/data-classification.md +1 -1
  48. package/assets/guardrails/technology/dotnet-webapi/dependency-policy.md +1 -1
  49. package/assets/guardrails/technology/dotnet-webapi/eventing.md +1 -1
  50. package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +1 -1
  51. package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +1 -1
  52. package/assets/guardrails/technology/dotnet-webapi/modular-monolith.md +1 -1
  53. package/assets/guardrails/technology/dotnet-webapi/persistence.md +1 -1
  54. package/assets/guardrails/technology/dotnet-webapi/testing.md +1 -1
  55. package/assets/guardrails/technology/dotnet-webapi/vertical-slices.md +1 -1
  56. package/assets/guardrails/technology/dotnet-webapi/zero-trust.md +1 -1
  57. package/assets/guardrails/technology/nextjs/accessibility-implementation.md +1 -1
  58. package/assets/guardrails/technology/nextjs/api-client.md +1 -1
  59. package/assets/guardrails/technology/nextjs/api-integration.dotnet-webapi.md +1 -1
  60. package/assets/guardrails/technology/nextjs/api-integration.java-spring.md +1 -1
  61. package/assets/guardrails/technology/nextjs/auth-session.md +1 -1
  62. package/assets/guardrails/technology/nextjs/client-security.md +1 -1
  63. package/assets/guardrails/technology/nextjs/component-architecture.md +1 -1
  64. package/assets/guardrails/technology/nextjs/component-conventions.md +1 -1
  65. package/assets/guardrails/technology/nextjs/design-system.md +1 -1
  66. package/assets/guardrails/technology/nextjs/error-handling.md +1 -1
  67. package/assets/guardrails/technology/nextjs/forms-and-validation.md +1 -1
  68. package/assets/guardrails/technology/nextjs/frontend-testing.md +1 -1
  69. package/assets/guardrails/technology/nextjs/i18n.md +1 -1
  70. package/assets/guardrails/technology/nextjs/observability.md +1 -1
  71. package/assets/guardrails/technology/nextjs/performance-budgets.md +1 -1
  72. package/assets/guardrails/technology/nextjs/routing-navigation.md +1 -1
  73. package/assets/guardrails/technology/nextjs/state-management.md +1 -1
  74. package/package.json +1 -1
@@ -38,6 +38,12 @@
38
38
  # pipeline, so each runnable lane confirms first, naming its stack, its plan and the
39
39
  # subtree it will write into. Answering no to one lane leaves the other free to run.
40
40
  #
41
+ # THE FRONTEND BINDS TO THE SERVICE AS BUILT. Between the two lanes, the service's API
42
+ # document is exported from the running code, the frontend's client is generated from it,
43
+ # and the operation ids the frontend plan cites are checked against it; the frontend then
44
+ # generates with the document in context. Each of those steps warns rather than stops —
45
+ # see the API CONTRACT block before the lane swap.
46
+ #
41
47
  # THE PLAN SAYS WHAT TO BUILD, THE MODEL SAYS WHAT THE DOMAIN IS. This phase does NOT read
42
48
  # spec.md — analyze-plan already conformed the plans to it, so the plan is the complete,
43
49
  # authoritative source for WHICH elements exist, where each lives and what surface they
@@ -81,11 +87,10 @@
81
87
  # the constitution halves + this phase's rule sets. Each lane takes its rules from its own
82
88
  # heading of tech-rule-bindings, and the frontend set is loaded only when that lane runs,
83
89
  # so a backend-only project sees exactly the rules it did before:
84
- # • BACKEND — `## /aw-spec-implement` on the bootstrap path, `## /aw-spec-implement-delta`
85
- # on the delta path. Keyed by MODE, which is what the two commands did separately, so
86
- # no project's rule set changes by being merged into one command.
87
- # • FRONTEND — `## /aw-spec-implement-ui`, both paths. There was never a delta heading
88
- # for this lane because the delta half of it was never built; it is built here.
90
+ # • BACKEND — `## /aw-spec-implement-backend`, both paths.
91
+ # • FRONTEND — `## /aw-spec-implement-frontend`, both paths.
92
+ # A change's code is generated against the same rules as the master it changes, so
93
+ # neither lane has a separate delta heading.
89
94
  #
90
95
  # TWO PATHS PER LANE. Each lane owns the lane root folder stacks.json declares for it and the
91
96
  # test path lane-verify resolves for it — `backend/tests/` inside a new lane root folder,
@@ -248,15 +253,37 @@ vars:
248
253
  fe_completion_ran: "false"
249
254
  fe_gap_names: ""
250
255
  fe_gaps_text: "none"
256
+ # THE API CONTRACT between the lanes — see the block before the lane swap. Every flag
257
+ # starts lowered, so a run without a frontend lane never touches any of it.
258
+ contract_go: "false"
259
+ contract_ok: ""
260
+ contract_doc: ""
261
+ contract_doc_exists: "false"
262
+ contract_reason: ""
263
+ contract_already: "false"
264
+ contract_fresh: "true"
265
+ contract_log: ""
266
+ contract_placeholder: ""
267
+ contract_export_status: ""
268
+ contract_status: "not exported — no API document is in context, so take each binding from the plan alone and say so in your summary"
269
+ client_go: "false"
270
+ client_ask: "false"
271
+ client_answer: ""
272
+ client_saved: "false"
273
+ client_run: "false"
274
+ client_present: "false"
275
+ client_ok: ""
276
+ client_cmd: ""
277
+ client_log: ""
278
+ client_status: "none was generated — write the calls in the lane's client layer from the API document, exactly as it states them"
279
+ check_ok: ""
280
+ check_reason: ""
251
281
  lanes_complete: "true"
252
282
  generate_any: "false"
253
283
  record_edges: "false"
254
284
  overview_ok: "false"
255
285
  domain_model: ""
256
286
  domain_model_exists: "false"
257
- # The backend lane's rule-set heading, keyed by MODE — see the header. The frontend
258
- # lane's is the same on both paths, so it is written inline at its include.
259
- be_tech_command: "aw-spec-implement"
260
287
  # HOOK PHASES. The merged command fires the phase of every branch it actually takes, so
261
288
  # an extensions.yml wired to any of the three former commands keeps working:
262
289
  # before/after_implement always, the _ui pair when the frontend lane generates, the _cr
@@ -317,6 +344,8 @@ workflow:
317
344
  - { name: fe_build, from: "$.frontend_build" }
318
345
  - { name: fe_test, from: "$.frontend_test" }
319
346
  - { name: fe_reserved, from: "$.frontend_reserved_csv" }
347
+ - { name: fe_workdir, from: "$.frontend_workdir" }
348
+ - { name: fe_client, from: "$.frontend_client" }
320
349
 
321
350
  - id: require_lanes
322
351
  action: verify_context
@@ -402,7 +431,6 @@ workflow:
402
431
  mode: "delta"
403
432
  pre_cr_phase: "before_implement_cr"
404
433
  post_cr_phase: "after_implement_cr"
405
- be_tech_command: "aw-spec-implement-delta"
406
434
 
407
435
  - id: pick_change
408
436
  condition: "{{mode}} == delta"
@@ -755,15 +783,15 @@ workflow:
755
783
  - { name: fe_existing_count, from: "$.count" }
756
784
 
757
785
  # 9. Each generating lane's code-generation rule files → sticky standards (configuration,
758
- # not hardcoded). Loaded only for a lane that is actually going to generate, and the
759
- # backend's heading is keyed by mode (see the header). No blocking gate: an
786
+ # not hardcoded). Loaded only for a lane that is actually going to generate, under
787
+ # the same heading on both paths (see the header). No blocking gate: an
760
788
  # unconfigured project soft-continues, since the constitution halves still carry each
761
789
  # lane's ratified base.
762
790
  #
763
791
  # EACH LANE'S RULES ARE LOADED BESIDE ITS OWN STEPS, AND THE SECOND LANE REPLACES
764
792
  # THE FIRST'S. Both includes used to run here, before either lane generated — and
765
793
  # sticky standards only accumulate, so on a full-stack run the backend generator was
766
- # shown `## /aw-spec-implement-ui` and the frontend generator the service set. Each
794
+ # shown `## /aw-spec-implement-frontend` and the frontend generator the service set. Each
767
795
  # prompt says which lane it is in, but it said so inside an envelope that contradicted
768
796
  # it, and the envelope is the part the model cannot argue with. The frontend include
769
797
  # now sits immediately before the FRONTEND sections below and passes replace, which
@@ -772,7 +800,7 @@ workflow:
772
800
  condition: "{{be_go}} == true"
773
801
  action: include
774
802
  module: .appweaver/orchestrator/modules/tech-select.orch.yaml
775
- with: { command: "{{be_tech_command}}" }
803
+ with: { command: aw-spec-implement-backend }
776
804
 
777
805
  # 10. Pre-execution hooks — see the hook-phase vars above.
778
806
  - id: resolve_pre_hooks
@@ -892,6 +920,11 @@ workflow:
892
920
  Cross-Cutting Concerns table (audit / retention / data-exposure — the CN-/DC-
893
921
  realisations); and each integration contract (IC-) in the External Integrations
894
922
  table. Implement every port the plan declares.
923
+ - GIVE EVERY ENDPOINT ITS OPERATION ID. Where the plan names an endpoint's
924
+ **Operation id**, set it as this stack's published API document names operations
925
+ (its OpenAPI operationId), spelled exactly as the plan writes it. The frontend lane
926
+ finds the endpoint by that id in the document exported from this code, so an
927
+ endpoint left on a framework-generated name is one it cannot find.
895
928
  - Author a paired test for every plan behaviour / use-case / endpoint; derive the
896
929
  cases from the plan's pre/post/invariant contracts and cite the spec id (FR / BR /
897
930
  CN / DC / IC / US) from its Traceability section. Include tests for the constraints
@@ -1042,6 +1075,10 @@ workflow:
1042
1075
  invariant, handler orchestration, API error contract, the Cross-Cutting Concerns
1043
1076
  realisations (audit / retention / data-exposure — CN-/DC-) and the External
1044
1077
  Integrations table's contracts (IC-) exactly as the delta plan states.
1078
+ - GIVE EVERY ENDPOINT THIS CHANGE ADDS OR CHANGES the operation id the delta plan
1079
+ names, set as this stack's published API document names operations (its OpenAPI
1080
+ operationId) and spelled exactly; an existing endpoint keeps the id it has. The
1081
+ frontend lane finds each endpoint by that id in the exported document.
1045
1082
  - COMPONENTS: if a delta element depends on a framework component, code against its
1046
1083
  ABSTRACTION / port as the delta plan declares — do NOT hand-roll it. Installing the
1047
1084
  component (packages, wiring, config) is /appweaver add-component <Component>; if
@@ -1141,7 +1178,8 @@ workflow:
1141
1178
  under a different name is renamed to the plan's name, with its references — the
1142
1179
  plan's names are the ubiquitous language.
1143
1180
  - An element the plan names by intent (a port, an adapter, an endpoint route) is done
1144
- when the code realises it, whatever the framework calls it; report it `done`.
1181
+ when the code realises it, whatever the framework calls it; report it `done`. An
1182
+ endpoint still carries the operation id the plan names, set exactly.
1145
1183
  - If an element cannot be realised, do not work around it: report it `blocked` and
1146
1184
  say what stops you. A plan that is wrong is fixed in plan / analyze-plan.
1147
1185
  - Report every listed element in an `elements` list in your closing JSON block:
@@ -1186,13 +1224,156 @@ workflow:
1186
1224
  outputs:
1187
1225
  - { name: okf_concept, from: "$.concept" }
1188
1226
 
1227
+ # ══════════════ THE API CONTRACT — the built service, as the frontend sees it ═══
1228
+ # The frontend binds to the service through its published API document, and the document
1229
+ # that counts is the one the CODE serves: routes, verbs, parameters, field names and
1230
+ # status codes as built, which the plans only describe. So before the frontend lane
1231
+ # generates, three steps, each of which WARNS and carries on — the frontend still
1232
+ # generates, from its plan, when one of them cannot run:
1233
+ # 1. EXPORT — start the service with its lane's `contract_run`, save what it serves at
1234
+ # `contract` under its lane root folder, stop it (contract-export). The two values
1235
+ # come from the lane in stacks.json — where foundation records a pack's own — or
1236
+ # else from the stack profile.
1237
+ # 2. CLIENT — run the frontend lane's `client` command, which generates the client from
1238
+ # that document. A lane with none yet asks the developer once and records the
1239
+ # answer on the lane; an empty answer carries on without a generated client.
1240
+ # 3. CHECK — every operation id the frontend plan cites must be in the document
1241
+ # (contract-check, by script).
1242
+ # It runs whenever the frontend lane does, including when the service was built in an
1243
+ # earlier run, and only where a service lane is declared.
1244
+ - id: contract_arm
1245
+ condition: "{{fe_go}} == true"
1246
+ action: set
1247
+ vars: { contract_go: "{{be_declared}}" }
1248
+ - id: contract_export
1249
+ condition: "{{contract_go}} == true"
1250
+ action: execute_script
1251
+ on_error: continue
1252
+ script: { ref: actions }
1253
+ subcommand: contract-export
1254
+ outputs:
1255
+ - { name: contract_ok, from: "$.ok" }
1256
+ - { name: contract_doc, from: "$.doc" }
1257
+ - { name: contract_doc_exists, from: "$.doc_exists" }
1258
+ - { name: contract_reason, from: "$.reason" }
1259
+ - { name: contract_already, from: "$.already_running" }
1260
+ - { name: contract_ops, from: "$.operations" }
1261
+ - { name: contract_log, from: "$.log_tail" }
1262
+ - { name: contract_placeholder, from: "$.placeholder" }
1263
+ - { name: contract_export_status, from: "$.status" }
1264
+ - id: warn_contract_export
1265
+ condition: "{{contract_go}} == true"
1266
+ action: verify_context
1267
+ require_true: contract_ok
1268
+ on_false: continue
1269
+ on_false_message: "API DOCUMENT NOT EXPORTED — {{contract_reason}}. The service lane `{{be_lane_id}}` is started with its `contract_run` command and its document fetched from its `contract` URL, both read from .appweaver/stacks.json or else its stack profile; correct them on the lane there if they do not fit this project, start anything the service needs, and re-run implement. Until then the frontend lane binds from its plan alone. Service output: {{contract_log}}"
1270
+ - id: contract_stale_flag
1271
+ condition: "{{contract_already}} == true"
1272
+ action: set
1273
+ vars: { contract_fresh: "false" }
1274
+ - id: warn_contract_stale
1275
+ condition: "{{contract_go}} == true"
1276
+ action: verify_context
1277
+ require_true: contract_fresh
1278
+ on_false: continue
1279
+ on_false_message: "WARNING — the API document was {{contract_reason}}. Stop that service and re-run implement to export the code as it is now."
1280
+ - id: contract_status_set
1281
+ condition: "{{contract_doc_exists}} == true"
1282
+ action: set
1283
+ vars: { contract_status: "{{contract_export_status}}; it is in context" }
1284
+
1285
+ # 2. THE CLIENT, generated from the document — so only once there is one.
1286
+ - id: client_arm
1287
+ condition: "{{contract_doc_exists}} == true"
1288
+ action: set
1289
+ vars: { client_go: "{{fe_go}}" }
1290
+ - id: client_ask_arm
1291
+ condition: "{{fe_client}} == "
1292
+ action: set
1293
+ vars: { client_ask: "{{client_go}}" }
1294
+ - id: ask_client
1295
+ condition: "{{client_ask}} == true"
1296
+ action: ask
1297
+ prompt: |
1298
+ The frontend lane `{{fe_lane_id}}` ({{fe_title}}) has no `client` command, so its API
1299
+ client cannot be generated from the service's document ({{contract_doc}}).
1300
+ Type the command that generates it. It runs in `{{fe_workdir}}`, and
1301
+ {{contract_placeholder}} in it stands for the document's path — for example:
1302
+ npx openapi-typescript {{contract_placeholder}} -o lib/api/schema.d.ts
1303
+ It is saved on the lane in .appweaver/stacks.json and used on every run after this one.
1304
+ Leave it empty to carry on without a generated client.
1305
+ answer_var: client_answer
1306
+ - id: client_save
1307
+ condition: "{{client_ask}} == true"
1308
+ action: execute_script
1309
+ on_error: continue
1310
+ script: { ref: actions }
1311
+ subcommand: lane-set
1312
+ args: ["--id", "{{fe_lane_id}}", "--set", "client={{client_answer}}"]
1313
+ outputs:
1314
+ - { name: client_saved, from: "$.written" }
1315
+ - id: client_saved_set
1316
+ condition: "{{client_saved}} == true"
1317
+ action: set
1318
+ vars: { fe_client: "{{client_answer}}" }
1319
+ - id: client_run_arm
1320
+ condition: "{{fe_client}} != "
1321
+ action: set
1322
+ vars: { client_run: "{{client_go}}" }
1323
+ - id: contract_client
1324
+ condition: "{{client_run}} == true"
1325
+ action: execute_script
1326
+ on_error: continue
1327
+ script: { ref: actions }
1328
+ subcommand: contract-client
1329
+ outputs:
1330
+ - { name: client_ok, from: "$.ok" }
1331
+ - { name: client_cmd, from: "$.cmd" }
1332
+ - { name: client_log, from: "$.failing_excerpt" }
1333
+ - id: warn_client_failed
1334
+ condition: "{{client_run}} == true"
1335
+ action: verify_context
1336
+ require_true: client_ok
1337
+ on_false: continue
1338
+ on_false_message: "API CLIENT NOT GENERATED — the frontend lane's `client` command failed: {{client_log}}. Correct `client` on the `{{fe_lane_id}}` lane in .appweaver/stacks.json and re-run implement. Until then the frontend lane writes its calls from the API document."
1339
+ - id: client_status_set
1340
+ condition: "{{client_ok}} == true"
1341
+ action: set
1342
+ vars:
1343
+ client_present: "true"
1344
+ client_status: "generated just now by `{{client_cmd}}` from the API document — call the service THROUGH it, and never edit a generated file"
1345
+ - id: warn_no_client
1346
+ condition: "{{client_go}} == true"
1347
+ action: verify_context
1348
+ require_true: client_present
1349
+ on_false: continue
1350
+ on_false_message: "NO API CLIENT GENERATED — the frontend lane `{{fe_lane_id}}` has no working `client` command, so this run writes its calls from the API document {{contract_doc}} instead. Set `client` on the lane in .appweaver/stacks.json (`{{contract_placeholder}}` stands for the document) to generate the client on the next run."
1351
+
1352
+ # 3. THE CHECK — the operation ids the frontend plan cites, against the document.
1353
+ - id: contract_check
1354
+ condition: "{{contract_doc_exists}} == true"
1355
+ action: execute_script
1356
+ on_error: continue
1357
+ script: { ref: actions }
1358
+ subcommand: contract-check
1359
+ args: ["--plan", "{{fe_plan}}", "--doc", "{{contract_doc}}"]
1360
+ outputs:
1361
+ - { name: check_ok, from: "$.ok" }
1362
+ - { name: check_reason, from: "$.reason" }
1363
+ - id: warn_contract_check
1364
+ condition: "{{contract_doc_exists}} == true"
1365
+ action: verify_context
1366
+ require_true: check_ok
1367
+ on_false: continue
1368
+ on_false_message: "CONTRACT CHECK — {{check_reason}}. Each binding in {{fe_plan}} names the endpoint it calls by the operation id the backend plan gives it, and the built service must serve that id. Either the plan cites the wrong id (fix it with /appweaver plan, then analyze-plan) or the service never gave the endpoint that id (re-run implement for the backend lane). The frontend lane still generates; these bindings are where a call will fail."
1369
+
1189
1370
  # ══════════════ THE LANE SWAP — the frontend's rules replace the backend's ═══
1190
1371
  # build_context already scoped the two lanes' PAYLOADS apart; this is the same boundary
1191
1372
  # for their STANDARDS, which the envelope carries and which nothing used to reset. It
1192
1373
  # runs here rather than up with the backend's include because standards accumulate:
1193
1374
  # loading both before either lane generated is precisely what showed each generator the
1194
1375
  # other lane's rule set. `replace` resets to the declared seed (ai-rules stays) and then
1195
- # loads `## /aw-spec-implement-ui`, so from here down the envelope is the frontend's.
1376
+ # loads `## /aw-spec-implement-frontend`, so from here down the envelope is the frontend's.
1196
1377
  #
1197
1378
  # Nothing after the frontend sections regenerates backend code — the OKF steps that
1198
1379
  # follow run include_standards: false — so the swap needs no undo.
@@ -1200,12 +1381,13 @@ workflow:
1200
1381
  condition: "{{fe_go}} == true"
1201
1382
  action: include
1202
1383
  module: .appweaver/orchestrator/modules/tech-select.orch.yaml
1203
- with: { command: aw-spec-implement-ui, replace: "true" }
1384
+ with: { command: aw-spec-implement-frontend, replace: "true" }
1204
1385
 
1205
1386
  # ═══════════ FRONTEND LANE — bootstrap, generate from the MASTER plan ════════
1206
1387
  # The experience twin of the service generation, one lane over. Its own build_context,
1207
1388
  # because the envelope persists across steps and the two lanes must not see each other's
1208
1389
  # payload — the frontend binds to the service's PUBLISHED surface, never its internals.
1390
+ # That surface is the API document the contract block exported, when there is one.
1209
1391
  - id: ctx_frontend
1210
1392
  condition: "{{fe_mode}} == bootstrap"
1211
1393
  action: build_context
@@ -1213,6 +1395,7 @@ workflow:
1213
1395
  - { path: "{{fe_plan}}" }
1214
1396
  - { path: "{{domain_model}}", optional: true } # the UBIQUITOUS LANGUAGE this lane's labels, states and messages use — and what a cited BR-nnn requires
1215
1397
  - { path: .appweaver/memory/constitution.ui.md, optional: true } # the lane's ratified UX-* base — conventions, forbidden patterns, gates
1398
+ - { path: "{{contract_doc}}", optional: true } # the service's API document as BUILT — what every §5 binding calls
1216
1399
  - id: gen_frontend
1217
1400
  condition: "{{fe_mode}} == bootstrap"
1218
1401
  action: agent_generate
@@ -1306,6 +1489,17 @@ workflow:
1306
1489
  semantics and rollback each row states.
1307
1490
  • §6 — the cross-cutting decisions as code: what is hidden vs disabled,
1308
1491
  accessibility obligations, localization, performance and offline behaviour.
1492
+ - THE SERVICE'S API DOCUMENT IS THE CONTRACT. API document: {{contract_status}}.
1493
+ Each §5 row names its endpoint by Operation id; find that operation in the
1494
+ document and take EVERYTHING about the call from it — route, verb, path and query
1495
+ parameters, request and response field names and their casing, status codes and
1496
+ error codes. Never take a route, a field name or a paging convention from memory,
1497
+ from convention or from the loaded standards' examples: the document is what the
1498
+ built service actually answers. A §5 row whose id the document does not have is a
1499
+ broken binding — realise the screen, leave that call unbound, report the element
1500
+ `blocked` naming the id, and never guess a substitute.
1501
+ - THE CLIENT: {{client_status}}. The client lives in this lane's client layer; a
1502
+ generated client is called, never edited.
1309
1503
  - THE CLIENT IS NOT AN AUTHORITY. A client-side validation or permission check
1310
1504
  restates a server rule for feedback; it never replaces it. Generate no server-side
1311
1505
  behaviour, no persistence and no business rule evaluation here.
@@ -1347,6 +1541,7 @@ workflow:
1347
1541
  - { path: "{{frontend_plan}}", optional: true } # the master plan — READ ONLY, never amended here
1348
1542
  - { path: "{{domain_model}}", optional: true } # the master model — the ubiquitous language as it stands BEFORE this change
1349
1543
  - { path: .appweaver/memory/constitution.ui.md, optional: true }
1544
+ - { path: "{{contract_doc}}", optional: true } # the service's API document as BUILT — what every binding row calls
1350
1545
  - id: gen_frontend_delta
1351
1546
  condition: "{{fe_mode}} == delta"
1352
1547
  action: agent_generate
@@ -1426,6 +1621,15 @@ workflow:
1426
1621
  service delta's "Contract deltas for the frontend lane" table as the delta plan
1427
1622
  cites them. Generate no server-side behaviour, no persistence and no business rule
1428
1623
  evaluation.
1624
+ - THE SERVICE'S API DOCUMENT IS THE CONTRACT. API document: {{contract_status}}.
1625
+ Each binding row leads with its endpoint's operation id; find that operation in
1626
+ the document and take EVERYTHING about the call from it — route, verb, path and
1627
+ query parameters, request and response field names and their casing, status
1628
+ codes and error codes — never from memory, convention or the standards' examples.
1629
+ A binding whose id the document does not have is broken: leave that call unbound,
1630
+ report the element `blocked` naming the id, and never guess a substitute.
1631
+ - THE CLIENT: {{client_status}}. The client lives in this lane's client layer; a
1632
+ generated client is called, never edited.
1429
1633
  - Author a paired test for every ADDED/MODIFIED screen, interaction and state,
1430
1634
  including the unwanted-behaviour states and an accessibility assertion per
1431
1635
  interactive surface, citing the requirement id THE DELTA PLAN NAMES for that row
@@ -1500,6 +1704,10 @@ workflow:
1500
1704
  plan's names are the ubiquitous language.
1501
1705
  - A screen or a binding is done when the code realises it, whatever its route or
1502
1706
  file is called; report it `done`.
1707
+ - A binding calls the operation its id names in the service's API document
1708
+ ({{contract_status}}), taking route, verb, parameters, field names and status codes
1709
+ from there, through the client ({{client_status}}). An id the document does not
1710
+ have stays `blocked`; never guess a substitute.
1503
1711
  - If an element cannot be realised, do not work around it: report it `blocked` and
1504
1712
  say what stops you. A plan that is wrong is fixed in plan / analyze-plan.
1505
1713
  - Report every listed element in an `elements` list in your closing JSON block:
@@ -95,8 +95,8 @@
95
95
  # guardrails/brf-<domain>/frontend/*.md — the code-derived lane rule set, the detail
96
96
  # layer under those UX-* principles, wired into tech-rule-bindings.md under the lane's
97
97
  # three headings: `## /aw-spec-ui-constitution` (what a later /appweaver constitution
98
- # re-ratifies the UI half from), `## /aw-spec-plan-ui` and `## /aw-spec-implement-ui`
99
- # (what the frontend lane of `plan` and of `implement` load).
98
+ # re-ratifies the UI half from), `## /aw-spec-plan-frontend` and
99
+ # `## /aw-spec-implement-frontend` (what the frontend lane of `plan` and of `implement` load).
100
100
  # .appweaver/templates/overrides/ui-design-template.md + ui-delta-design-template.md — the
101
101
  # lane's own document pair, reverse-engineered from the UI source the same way the
102
102
  # service pair is reverse-engineered from the service code. The lane is governed by a
@@ -149,7 +149,7 @@
149
149
  # =============================================================================
150
150
 
151
151
  name: aw-spec-onboard
152
- description: Onboard an existing codebase for brownfield DEVELOPMENT — a deterministic whole-repo scan produces a high-level OKF feature map (folders/concepts) PLUS the project-level governance scaffold (split constitution + guardrails/brf-<domain>/ with its DOMAIN rule files at domain/ + domain-rule-bindings + code-derived TECHNICAL rule files at service/ + tech-rule-bindings + activated domain), all provisional-from-scan. The first context authors that tier; every later context amends it additively from its own code (new rules, principles and map entries — never a rewrite, renumbering or deletion; a contradiction is recorded as a Divergence note), and a tier that does not exist yet, such as a lane declared after an earlier onboard, is authored in full. Naming an already-onboarded context re-runs that governance pass alone. Where the scan finds a frontend lane in the CODE, it also authors that lane's half — constitution.ui.md (UX-*) — and its code-derived rule files at brf-<domain>/frontend/, mapped under `## /aw-spec-ui-constitution`, `## /aw-spec-plan-ui` and `## /aw-spec-implement-ui`; a backend-only repo gets none of it. Every rule tier is reverse-engineered from the CODE alone (never a greenfield rule file), evidenced-only, and WIRED per-workflow so the whole forward pipeline AND adopt govern against THIS codebase — never a greenfield fallback. It also reverse-engineers the repo's own technical structure into a project-specific design + delta-design template pair, installed as the project template overrides, and — where the lane exists — the frontend lane's own pair from the UI source. Every authoring step is shaped by a NEUTRAL rev-templates skeleton; no greenfield constitution, rule file or document template is ever placed in context. Accepts an optional concerns list to look for (onboard decides which are actually present). Reads any declared lane, never writes one. No migration content; never modifies source.
152
+ description: Onboard an existing codebase for brownfield DEVELOPMENT — a deterministic whole-repo scan produces a high-level OKF feature map (folders/concepts) PLUS the project-level governance scaffold (split constitution + guardrails/brf-<domain>/ with its DOMAIN rule files at domain/ + domain-rule-bindings + code-derived TECHNICAL rule files at service/ + tech-rule-bindings + activated domain), all provisional-from-scan. The first context authors that tier; every later context amends it additively from its own code (new rules, principles and map entries — never a rewrite, renumbering or deletion; a contradiction is recorded as a Divergence note), and a tier that does not exist yet, such as a lane declared after an earlier onboard, is authored in full. Naming an already-onboarded context re-runs that governance pass alone. Where the scan finds a frontend lane in the CODE, it also authors that lane's half — constitution.ui.md (UX-*) — and its code-derived rule files at brf-<domain>/frontend/, mapped under `## /aw-spec-ui-constitution`, `## /aw-spec-plan-frontend` and `## /aw-spec-implement-frontend`; a backend-only repo gets none of it. Every rule tier is reverse-engineered from the CODE alone (never a greenfield rule file), evidenced-only, and WIRED per-workflow so the whole forward pipeline AND adopt govern against THIS codebase — never a greenfield fallback. It also reverse-engineers the repo's own technical structure into a project-specific design + delta-design template pair, installed as the project template overrides, and — where the lane exists — the frontend lane's own pair from the UI source. Every authoring step is shaped by a NEUTRAL rev-templates skeleton; no greenfield constitution, rule file or document template is ever placed in context. Accepts an optional concerns list to look for (onboard decides which are actually present). Reads any declared lane, never writes one. No migration content; never modifies source.
153
153
  version: 2.3.0
154
154
  agent_agnostic: true
155
155
  dialect: aw-spec.orchestrator/v1
@@ -1036,8 +1036,10 @@ workflow:
1036
1036
  charter; a later step in this same run authors it, so wire the bullet now), then the
1037
1037
  domain identity/regulatory/interop files → domain principles.
1038
1038
  - `## /aw-spec-specify` — the FULL domain set (specify models the domain, lifts CN-/DC-/IC-).
1039
- - `## /aw-spec-plan` — `_None — plan loads no domain file. Domain reaches plan through the spec and the context's domain-model.md._`
1040
- - `## /aw-spec-implement` — `_None — implement loads no domain file. Domain reaches implement through the lane plans and the context's domain-model.md._`
1039
+ - `## /aw-spec-plan-backend` — `_None — the service lane of plan loads no domain file. Domain reaches it through the spec and the context's domain-model.md._`
1040
+ - `## /aw-spec-plan-frontend` — `_None — the frontend lane of plan loads no domain file. Domain reaches it through the spec and the context's domain-model.md._`
1041
+ - `## /aw-spec-implement-backend` — `_None — the service lane of implement loads no domain file. Domain reaches it through backend-plan.md and the context's domain-model.md._`
1042
+ - `## /aw-spec-implement-frontend` — `_None — the frontend lane of implement loads no domain file. Domain reaches it through frontend-plan.md and the context's domain-model.md._`
1041
1043
  - `## /aw-spec-gate` — the conformance-checklist set (the *.domain.md files).
1042
1044
  Each bullet is a workspace-relative path `- guardrails/{{domain_slug}}/domain/<file>`.
1043
1045
  Write ONLY inside guardrails/{{domain_slug}}/ (domain/ + the map). Report the
@@ -1367,7 +1369,7 @@ workflow:
1367
1369
  existing files (frontmatter origin: reverse-engineered, generated_by:
1368
1370
  {{generated_by}}, concern); every rule cites a UI code coordinate from this
1369
1371
  context and the UX numeral it details. Wire it into tech-rule-bindings.md under
1370
- `## /aw-spec-plan-ui` and/or `## /aw-spec-implement-ui` as its rules serve
1372
+ `## /aw-spec-plan-frontend` and/or `## /aw-spec-implement-frontend` as its rules serve
1371
1373
  planning or generating, and give it its table row. frontend/ui-constitution.md
1372
1374
  stays the only file under `## /aw-spec-ui-constitution` that is not also a
1373
1375
  concern file.
@@ -1580,8 +1582,8 @@ workflow:
1580
1582
  named after the concern the code exhibits. Wire it into
1581
1583
  domain-rule-bindings.md under `## /aw-spec-specify` and `## /aw-spec-gate`
1582
1584
  (plus `## /aw-spec-constitution` for an identity / regulatory file), as the
1583
- existing files are wired. `## /aw-spec-plan` and `## /aw-spec-implement` keep
1584
- loading no domain file.
1585
+ existing files are wired. The plan and implement headings (`-backend` and
1586
+ `-frontend`) keep loading no domain file.
1585
1587
  - NEW rules appended to an EXISTING rule file, where this context's code enforces
1586
1588
  a rule of that concern the file does not state — each citing this context's code
1587
1589
  and marked `(context: {{bc}})`. Mark unresolved specifics `PROVISIONAL —
@@ -1859,12 +1861,11 @@ workflow:
1859
1861
  ONLY a heading you have a generated file for (an absent heading soft-continues → loads
1860
1862
  nothing):
1861
1863
  - `## /aw-spec-specify` — EXACTLY ONE bullet: `service/domain-modelling.md`, the modelling methodology. NEVER an architecture / persistence / codegen / security file here — specify is the domain phase and any technology rule under this heading breaks its domain purity. Omit the heading only if you did not write domain-modelling.md.
1862
- - `## /aw-spec-plan` — the as-built architecture / cross-cutting rules the SERVICE lane's plan author mediates the spec against.
1863
- - `## /aw-spec-implement` — the code-generation / convention set the SERVICE lane's generator builds against (from backend-plan.md).
1864
- - `## /aw-spec-implement-delta` — the same set for the service lane on the DELTA path. `implement` is one command that keys this heading when it is generating a change's delta plan and the one above when it is generating the master, so a project that wants the same rules on both paths repeats them here.
1864
+ - `## /aw-spec-plan-backend` — the as-built architecture / cross-cutting rules the SERVICE lane's plan author mediates the spec against.
1865
+ - `## /aw-spec-implement-backend` — the code-generation / convention set the SERVICE lane's generator builds against (from backend-plan.md), on both the master and the delta path.
1865
1866
  - `## /aw-spec-build` — the layering + convention rules the compile-fixer respects.
1866
1867
  - `## /aw-spec-analyze-slice` — the conformance rules the plan↔code gate validates against.
1867
- - `## /aw-spec-adopt` — the technical reference set the reversed plan mediates against (a subset of plan's).
1868
+ - `## /aw-spec-adopt-backend` — the technical reference set the reversed backend plan mediates against (a subset of `## /aw-spec-plan-backend`'s).
1868
1869
  - `## /aw-spec-constitution` — the standards a later `/appweaver constitution` re-ratifies the TECHNICAL half from. You authored that half from code evidence before these files existed; this heading is what makes a re-run author from THIS project's rules rather than from an empty set. Ratifiable standards only, no worked `examples/` sample, no domain file.
1869
1870
  - `## /aw-spec-run` — the runtime / execution conventions the app-run step honors (add ONLY if the code evidences a runtime/hosting concern file; NOT data-migration — migration is the deferred later phase).
1870
1871
  Each bullet is a
@@ -1925,7 +1926,7 @@ workflow:
1925
1926
  # (or creates the file, in a project with no service lane). `## /aw-spec-ui-constitution`
1926
1927
  # is what makes a later /appweaver constitution re-ratify the UI half from THIS project's
1927
1928
  # lane rules, and the authoritative signal that the project HAS a frontend lane.
1928
- # `## /aw-spec-plan-ui` and `## /aw-spec-implement-ui` are what the frontend lane of
1929
+ # `## /aw-spec-plan-frontend` and `## /aw-spec-implement-frontend` are what the frontend lane of
1929
1930
  # `plan` and of `implement` load; without them that lane plans and generates against no
1930
1931
  # project rule at all.
1931
1932
  - id: ctx_ui_pack
@@ -1997,10 +1998,10 @@ workflow:
1997
1998
  `frontend/ui-constitution.md` first. It is what a later /appweaver constitution
1998
1999
  re-ratifies the UI half from, and the authoritative signal that the project has a
1999
2000
  frontend lane; precede the bullets with a short HTML comment saying both.
2000
- 2. `## /aw-spec-plan-ui` — the files the FRONTEND lane of `plan` authors
2001
+ 2. `## /aw-spec-plan-frontend` — the files the FRONTEND lane of `plan` authors
2001
2002
  frontend-plan.md against: those whose rules decide a feature's screens, navigation,
2002
2003
  client state, interaction states, forms, accessibility and service binding.
2003
- 3. `## /aw-spec-implement-ui` — the files the FRONTEND lane of `implement` generates
2004
+ 3. `## /aw-spec-implement-frontend` — the files the FRONTEND lane of `implement` generates
2004
2005
  code against, on the master and the delta path alike: those whose rules govern
2005
2006
  component conventions, state and data fetching, styling, forms and UI tests.
2006
2007
  A file whose rules carry both a planning half and a generating half is listed under both
@@ -2060,7 +2061,7 @@ workflow:
2060
2061
  on_error: continue
2061
2062
  script: { ref: actions }
2062
2063
  subcommand: resolve-tech
2063
- args: ["--command", "aw-spec-plan-ui"]
2064
+ args: ["--command", "aw-spec-plan-frontend"]
2064
2065
  outputs:
2065
2066
  - { name: ui_plan_rules, from: "$.candidates" }
2066
2067
  - id: warn_ui_plan_wiring
@@ -2070,7 +2071,7 @@ workflow:
2070
2071
  on_empty: continue
2071
2072
  on_empty_message: >
2072
2073
  guardrails/{{domain_slug}}/tech-rule-bindings.md maps nothing under
2073
- `## /aw-spec-plan-ui`, so the frontend lane of /appweaver plan will author
2074
+ `## /aw-spec-plan-frontend`, so the frontend lane of /appweaver plan will author
2074
2075
  frontend-plan.md with no project rule file. Add the heading, bulleting the
2075
2076
  frontend/ files whose rules shape a feature's screens, state and interactions.
2076
2077
  - id: probe_ui_impl_wiring
@@ -2079,7 +2080,7 @@ workflow:
2079
2080
  on_error: continue
2080
2081
  script: { ref: actions }
2081
2082
  subcommand: resolve-tech
2082
- args: ["--command", "aw-spec-implement-ui"]
2083
+ args: ["--command", "aw-spec-implement-frontend"]
2083
2084
  outputs:
2084
2085
  - { name: ui_impl_rules, from: "$.candidates" }
2085
2086
  - id: warn_ui_impl_wiring
@@ -2089,7 +2090,7 @@ workflow:
2089
2090
  on_empty: continue
2090
2091
  on_empty_message: >
2091
2092
  guardrails/{{domain_slug}}/tech-rule-bindings.md maps nothing under
2092
- `## /aw-spec-implement-ui`, so the frontend lane of /appweaver implement will
2093
+ `## /aw-spec-implement-frontend`, so the frontend lane of /appweaver implement will
2093
2094
  generate UI code with no project rule file. Add the heading, bulleting the
2094
2095
  frontend/ files whose rules govern component, state, styling and test conventions.
2095
2096
 
@@ -17,11 +17,14 @@
17
17
  # against no declared stack invents its own.
18
18
  #
19
19
  # ONE COMMAND, TWO LANES, TWO RULE SETS. The lanes take their rules from different
20
- # headings of tech-rule-bindings (`## /aw-spec-plan` for the service, `## /aw-spec-plan-ui`
21
- # for the frontend), and the frontend set is loaded ONLY when that lane is declared — so
22
- # a backend-only project sees exactly the rules it did before. In a two-lane project both
23
- # sets are sticky for the whole run; the lane boundary is held by the prompts instead,
24
- # and §5 Contract Binding is where it is stated.
20
+ # headings of tech-rule-bindings (`## /aw-spec-plan-backend` for the service,
21
+ # `## /aw-spec-plan-frontend` for the frontend), and each set is loaded only when its lane
22
+ # is declared. The two are never loaded together: the service set loads at step 1, before
23
+ # the backend sections, and the frontend set REPLACES it at the lane swap before the
24
+ # frontend sections — tech_select_ui_master on the master path, the delta-plan module's
25
+ # own swap on the change path. Each plan is therefore authored with only its own lane's
26
+ # rule set in its envelope. Where the two plans meet is stated in the frontend plan's
27
+ # §5 Contract Binding, which binds to the service's published surface only.
25
28
  #
26
29
  # RENAMED FROM `design`. design.md → backend-plan.md, design.ui.md → frontend-plan.md,
27
30
  # and the former separate `design-ui` command is FOLDED IN here. The scaffold MIGRATES a
@@ -204,15 +207,15 @@ workflow:
204
207
  on_false_message: "No lane is declared in .appweaver/stacks.json, so there is nothing to plan. Run /appweaver select-stack and declare the backend stack, the frontend stack, or both — plus each one's lane root folder — then re-run plan. The declaration is what tells this phase which documents to write; a plan written against no declared stack invents its own."
205
208
 
206
209
  # 1. TECHNICAL rule files → sticky standards (configuration, not hardcoded).
207
- # The service lane's set is loaded under `## /aw-spec-plan`; the frontend lane's under
208
- # `## /aw-spec-plan-ui`, and ONLY when that lane is declared — so a backend-only
210
+ # The service lane's set is loaded under `## /aw-spec-plan-backend`; the frontend lane's
211
+ # under `## /aw-spec-plan-frontend`, and ONLY when that lane is declared — so a backend-only
209
212
  # project's standards are exactly what they were before the two commands merged.
210
213
  # No blocking gate: an unconfigured project soft-continues (the constitutions still
211
214
  # carry each lane's ratified base).
212
215
  #
213
216
  # ONLY THE BACKEND'S RULES LOAD HERE. The frontend's used to load alongside them,
214
217
  # before either lane authored anything, and sticky standards only accumulate — so the
215
- # service plan was authored with `## /aw-spec-plan-ui` in its envelope and the
218
+ # service plan was authored with `## /aw-spec-plan-frontend` in its envelope and the
216
219
  # experience plan with the service set. Each prompt names its lane, but it said so
217
220
  # inside an envelope that contradicted it. The UI set now loads at the frontend
218
221
  # boundary instead, with `replace`, in both places a frontend document is authored:
@@ -222,7 +225,7 @@ workflow:
222
225
  condition: "{{be_declared}} == true"
223
226
  action: include
224
227
  module: .appweaver/orchestrator/modules/tech-select.orch.yaml
225
- with: { command: aw-spec-plan }
228
+ with: { command: aw-spec-plan-backend }
226
229
 
227
230
  # 2. Resolve the current feature and require its spec.
228
231
  - id: feature_paths
@@ -617,6 +620,10 @@ workflow:
617
620
  as field shapes. That section is the ONLY part of this document the frontend plan
618
621
  may read; keep it complete and self-contained, because a contract the UI needs and
619
622
  this document never states becomes a client-side workaround.
623
+ - NAME EVERY ENDPOINT. Each §3 endpoint carries an **Operation id** — its name in the
624
+ service's published API document (e.g. `CreatePatient`), unique across the
625
+ service and never reused. The frontend plan cites it, and implement gives the
626
+ endpoint exactly this id, so the two lanes meet on it.
620
627
  - CONSTITUTION-MANDATED CROSS-CUTTING (from the loaded technical constitution, NOT
621
628
  the spec): a NON-NEGOTIABLE technical principle you must apply that has NO
622
629
  per-feature spec id. APPLY it (it is non-negotiable), and because it is not
@@ -704,6 +711,10 @@ workflow:
704
711
  - PUBLISH THE SURFACE THE FRONTEND LANE BINDS TO: the section carrying this feature's
705
712
  endpoints states each contract as field shapes, completely, because it is the only
706
713
  part of this document the frontend plan may read.
714
+ - NAME EVERY ENDPOINT with its route, verb and operation id — its name in the
715
+ service's published API document, unique across the service. Where the code
716
+ already gives the endpoint one, record THAT id exactly as the code spells it; the
717
+ frontend plan cites it and implement finds the endpoint by it.
707
718
  - CONSTITUTION-MANDATED CROSS-CUTTING (from the loaded technical constitution, NOT
708
719
  the spec): a NON-NEGOTIABLE technical principle with no per-feature spec id —
709
720
  APPLY it, and LOG it as a §5 DA-n whose basis cites the mandating principle
@@ -773,6 +784,9 @@ workflow:
773
784
  workarounds are DECISIONS THIS TEAM MADE, not derivations from the spec — keep
774
785
  every one, with its id and its basis, unless the thing it decided about is gone.
775
786
  Never renumber a surviving entry: its id is cited elsewhere.
787
+ - OPERATION IDS ARE STABLE. Every endpoint keeps the operation id it already has —
788
+ the frontend plan and the built code both use it. A new endpoint gets one, unique
789
+ across the service; an endpoint without one gets one now.
776
790
  - THE CODE THAT EXISTS IS THE WHAT-IS AUTHORITY. {{source_count}} source file(s)
777
791
  realise this feature: {{source_files}}. READ them, and where the plan and the code
778
792
  disagree about STRUCTURE, the code is what is actually there — conform to it and
@@ -788,7 +802,7 @@ workflow:
788
802
  # ══════════════ THE LANE SWAP — the frontend's rules replace the backend's ═══
789
803
  # Both tech-select includes used to run up at step 4, before either lane authored
790
804
  # anything, and sticky standards only accumulate — so on a full-stack run the backend
791
- # plan was authored with `## /aw-spec-plan-ui` in its envelope and the frontend plan with
805
+ # plan was authored with `## /aw-spec-plan-frontend` in its envelope and the frontend plan with
792
806
  # the service set. Each prompt names its lane, but it did so inside an envelope that
793
807
  # contradicted it, and the envelope is the half the model cannot argue with.
794
808
  #
@@ -800,7 +814,7 @@ workflow:
800
814
  condition: "{{fe_mode}} != skip"
801
815
  action: include
802
816
  module: .appweaver/orchestrator/modules/tech-select.orch.yaml
803
- with: { command: aw-spec-plan-ui, replace: "true" }
817
+ with: { command: aw-spec-plan-frontend, replace: "true" }
804
818
 
805
819
  # ═══════════ FRONTEND LANE — bootstrap, greenfield experience template ═══════
806
820
  # The experience twin of the service plan, and the MEDIATOR between spec.md and the
@@ -867,6 +881,10 @@ workflow:
867
881
  DELTA raised back to the service lane under "Contract deltas needed" — never a
868
882
  workaround in the client. Where no service plan is in context, bind from the
869
883
  spec's IC- surface and record that as a §8 DA-n.
884
+ - EVERY §5 ROW CITES ITS OPERATION ID, copied exactly from the endpoint's
885
+ **Operation id** in the backend plan's §3 — implement looks the endpoint up by it
886
+ in the service's exported API document. Where no service plan names one, write
887
+ `—` and record it in the same §8 DA-n.
870
888
  - CONSTITUTION-MANDATED CROSS-CUTTING (from the loaded UI constitution, NOT the
871
889
  spec): a NON-NEGOTIABLE UX principle you must apply that has no per-feature spec
872
890
  id. APPLY it, and because it is not spec-derived, LOG it as a §8 DA-n whose
@@ -952,6 +970,9 @@ workflow:
952
970
  states. Cite them; do not restate, re-derive or contradict them, and introduce no
953
971
  server-side behaviour. What the experience needs and the surface lacks is a
954
972
  contract delta raised back to the service lane, never a client workaround.
973
+ - EVERY BINDING ROW CITES ITS OPERATION ID, copied exactly from the backend plan —
974
+ implement looks the endpoint up by it in the service's exported API document.
975
+ Where no service plan names one, write `—` and record it as a DA-n.
955
976
  - CONSTITUTION-MANDATED CROSS-CUTTING with no per-feature spec id: apply it, and
956
977
  log it as a DA-n citing the mandating principle ("per constitution.ui.md
957
978
  UX-<n>"). Do not fabricate a spec id for it and do not leave it uncited.
@@ -1010,6 +1031,9 @@ workflow:
1010
1031
  — the spec's IC- ids and, where the backend plan is in context, the API contracts
1011
1032
  it states. What the experience needs and the surface lacks is a contract delta
1012
1033
  raised back to the service lane, never a client workaround.
1034
+ - EVERY BINDING ROW CITES ITS OPERATION ID, copied exactly from the backend plan; a
1035
+ row that has none yet gets it now, and a row whose id the backend plan no longer
1036
+ has is re-bound. Where no service plan names one, write `—` with a DA-n.
1013
1037
  - TECHNOLOGY-AGNOSTIC: no framework, router, state library, component library or
1014
1038
  styling approach — responsibilities, field shapes, events and states only.
1015
1039
  - ADD ONE Change History row for this re-derivation, describing what MOVED and why.