aw-spec-cli 0.1.19 → 0.1.21

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 (75) hide show
  1. package/assets/.appweaver/DESIGN-FORMAT.md +17 -9
  2. package/assets/.appweaver/ORCH-DIALECT.md +8 -3
  3. package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +26 -3
  4. package/assets/.appweaver/orchestrator/orchestrator.py +65 -3
  5. package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +1 -1
  6. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +4 -2
  7. package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +1 -1
  8. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +1 -1
  9. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +121 -42
  10. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +7 -7
  11. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +145 -52
  12. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +18 -10
  13. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +306 -28
  14. package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +1 -1
  15. package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +1 -1
  16. package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +1 -1
  17. package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +4 -4
  18. package/assets/.appweaver/orchestrator/workflows/aw-spec-deploy.orch.yaml +1 -1
  19. package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +114 -30
  20. package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +140 -36
  21. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +385 -61
  22. package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +217 -174
  23. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +407 -107
  24. package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +1 -1
  25. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +49 -11
  26. package/assets/.appweaver/orchestrator/workflows/aw-spec-recall-delta.orch.yaml +1 -1
  27. package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +1 -1
  28. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-feature.orch.yaml +29 -23
  29. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +47 -23
  30. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +19 -11
  31. package/assets/.appweaver/scripts/bash/aw-inventory.sh +15 -0
  32. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +683 -92
  33. package/assets/.appweaver/scripts/bash/aw-xref.sh +3 -0
  34. package/assets/.appweaver/scripts/powershell/aw-inventory.ps1 +15 -0
  35. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +625 -64
  36. package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +3 -0
  37. package/assets/.appweaver/scripts/python/aw-crstate.py +194 -0
  38. package/assets/.appweaver/scripts/python/aw-foundation.py +151 -0
  39. package/assets/.appweaver/scripts/python/aw-inventory.py +1829 -63
  40. package/assets/.appweaver/scripts/python/aw-payload-parity.py +3 -0
  41. package/assets/.appweaver/scripts/python/aw-plan-coverage.py +423 -0
  42. package/assets/.appweaver/scripts/python/aw-stack.py +251 -28
  43. package/assets/.appweaver/scripts/python/aw-testlog.py +148 -0
  44. package/assets/.appweaver/scripts/python/aw-xref.py +500 -81
  45. package/assets/.appweaver/stack-profiles/dotnet-webapi.json +1 -0
  46. package/assets/.appweaver/stack-profiles/java-spring.json +1 -0
  47. package/assets/.appweaver/stack-profiles/node-express.json +1 -0
  48. package/assets/.appweaver/stack-profiles/python-fastapi.json +1 -0
  49. package/assets/.appweaver/templates/constitution-domain-template.md +17 -2
  50. package/assets/.appweaver/templates/delta-design-template.md +1 -1
  51. package/assets/.appweaver/templates/delta-domain-model-template.md +1 -1
  52. package/assets/.appweaver/templates/delta-spec-template.md +4 -3
  53. package/assets/.appweaver/templates/design-template.md +16 -11
  54. package/assets/.appweaver/templates/okf-concept-template.md +11 -1
  55. package/assets/.appweaver/templates/proposed-inventory-template.md +127 -0
  56. package/assets/.appweaver/templates/source-map-template.md +5 -3
  57. package/assets/.appweaver/templates/spec-template.md +17 -17
  58. package/assets/.appweaver/templates/ui-delta-design-template.md +1 -1
  59. package/assets/.appweaver/templates/ui-design-template.md +4 -4
  60. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +4489 -361
  61. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +2274 -125
  62. package/assets/guardrails/projects/dotnet-default-project/domain-rule-bindings.md +10 -6
  63. package/assets/guardrails/projects/dotnet-default-project/tech-rule-bindings.md +4 -0
  64. package/assets/guardrails/technology/dotnet-webapi/auditing.md +3 -1
  65. package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +5 -3
  66. package/assets/guardrails/technology/dotnet-webapi/cqrs.md +5 -1
  67. package/assets/guardrails/technology/dotnet-webapi/domain-driven-design.md +13 -5
  68. package/assets/guardrails/technology/dotnet-webapi/examples/cqrs.md +2 -0
  69. package/assets/guardrails/technology/dotnet-webapi/examples/domain-driven-design.md +6 -2
  70. package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +70 -0
  71. package/assets/guardrails/technology/dotnet-webapi/technology-constitution.md +3 -0
  72. package/assets/guardrails/technology/dotnet-webapi/testing.md +10 -0
  73. package/assets/guardrails/technology/nextjs/ui-constitution.md +8 -1
  74. package/package.json +1 -1
  75. package/assets/.appweaver/orchestrator/.state/smoke.state.json +0 -32
@@ -2,27 +2,40 @@
2
2
  # aw-spec-onboard (orchestrator) — the entry step of the Brownfield DEVELOPMENT flow
3
3
  #
4
4
  # Onboard an EXISTING codebase into aw-spec so it can be DEVELOPED (evolved, not
5
- # migrated) governed exactly like greenfield and as lightly as OpenSpec. Runs ONCE
6
- # per repo, over the WHOLE codebase (project-level, not per-slice). It does two
7
- # things, both from a single deterministic whole-repo scan — no slice is adopted yet:
5
+ # migrated) governed exactly like greenfield and as lightly as OpenSpec. Runs ONCE PER
6
+ # BOUNDED CONTEXT, against the boundaries /appweaver inventory proposed and the
7
+ # operator confirmed. No slice is adopted yet; each run does three things:
8
8
  #
9
- # 1. FEATURE MAP — a HIGH-LEVEL OKF discovery index of the features/aggregates the
10
- # code contains (folders/concepts + a bounded-context map + the tech stack). It
11
- # is a shallow map to pick from, NOT a deep reverse — the deep per-feature
12
- # reverse (spec.md + the context's domain-model.md + the lane plans) is
13
- # /appweaver adopt, done just-in-time when you are about to develop that feature.
9
+ # 1. FEATURE MAP — a HIGH-LEVEL OKF discovery index of THIS CONTEXT's aggregates —
10
+ # ONE concept per aggregate, listing the features that act on it — plus the tech
11
+ # stack, added beside whatever earlier contexts already wrote. The bundle is the
12
+ # PROJECT's knowledge: a concept is an aggregate, never a feature. It is a shallow map to pick from, NOT a deep reverse — the deep
13
+ # per-feature reverse (spec.md + the context's domain-model.md + the lane plans)
14
+ # is /appweaver adopt, done just-in-time when you are about to develop that
15
+ # feature.
14
16
  #
15
- # 2. GOVERNANCE SCAFFOLD — the PROJECT-level governing tier, established once from
16
- # the whole-repo vantage so forward development is consistent from the first
17
- # change: the split constitution (technical + domain), the guardrails/projects/
18
- # brf-<domain>/domain/ rule-file set (+ domain-rule-bindings), the domain charter
19
- # that set is headed by, and the activated domain. Because nothing is adopted yet, this tier is
20
- # a PROVISIONAL scaffold evidenced by the SCAN (project identity + bounded-context
21
- # map are firm; principles/rules are marked provisional). adopt then RECONCILES
22
- # each with the slice's own evidence (BR-/CN-/DC-/IC- ids) when that feature is
23
- # developed — the "created here, updated when taking each slice" contract.
17
+ # 2. THE CONTEXT'S SPECS TREE — specs/<Context>/ with an EMPTY directory per feature,
18
+ # and the context made active in .appweaver/context.json. This is what makes the
19
+ # context real to the commands that read the tree rather than the bundle:
20
+ # select-bounded-context lists it, select-feature offers exactly its features, and
21
+ # adopt has somewhere to write. No spec.md and no domain-model.md — a placeholder
22
+ # for either reads as "the document exists" to every gate downstream.
24
23
  #
25
- # ONBOARD → adopt <Feature> (JIT) → specify → plan → analyze-plan-delta → implement → build → analyze-slice-delta → finalize-delta → analyze-slice → close-delta ← you are here
24
+ # 3. GOVERNANCE SCAFFOLD — the PROJECT-level governing tier: the split constitution
25
+ # (technical + domain), the guardrails/projects/brf-<domain>/domain/ rule-file set
26
+ # (+ domain-rule-bindings), the domain charter that set is headed by, and the
27
+ # activated domain. AUTHORED BY THE FIRST CONTEXT TO ONBOARD AND BY NO OTHER —
28
+ # re-deriving project principles from one context's evidence is the aggregate-
29
+ # scoping bias this tier exists to avoid, so every later run skips the whole block
30
+ # and contributes its own concepts and specs tree instead. Because nothing is
31
+ # adopted yet, the tier is a PROVISIONAL scaffold evidenced by the SCAN (project
32
+ # identity + bounded-context map are firm; principles/rules are marked
33
+ # provisional); /appweaver constitution is what amends it.
34
+ #
35
+ # inventory → [edit specs/proposed-inventory.md] → inventory apply
36
+ # → ONBOARD <Context> (once per context) ← you are here
37
+ # → adopt <Feature> (JIT) → specify → plan → analyze-plan-delta → implement → build
38
+ # → analyze-slice-delta → finalize-delta → analyze-slice → close-delta
26
39
  #
27
40
  # Establishing the PROJECT-scoped constitution here (whole-repo vantage) — not from a
28
41
  # single adopted slice — is deliberate: it keeps governance project-scoped from day
@@ -112,32 +125,32 @@
112
125
  # pass was re-deriving an answer the run already had. `lane-declare` has one caller again
113
126
  # — select-stack — and this workflow only reads.
114
127
  #
115
- # Never modifies source — every write lands in the OKF bundle, the specs governance dir,
116
- # guardrails/projects/ (domain/ + service/ + frontend/ rule sets + both maps), or the
117
- # .appweaver/templates/overrides/ design templates.
128
+ # Never modifies source — every write lands in the OKF bundle, the context's specs/
129
+ # directories, guardrails/projects/ (domain/ + service/ + frontend/ rule sets + both
130
+ # maps), or the .appweaver/templates/overrides/ design templates.
118
131
  #
119
- # Launch: /appweaver onboard [domain-name / scope hint] [; concerns: a, b, c]
120
- # e.g. /appweaver onboard Pharma
121
- # e.g. /appweaver onboard "Pharma; concerns: auditing, concurrency, authorization"
132
+ # Launch: /appweaver onboard [<BoundedContext>] [; concerns: a, b, c]
133
+ # e.g. /appweaver onboard Clinical
134
+ # e.g. /appweaver onboard # the next context the map has open
135
+ # e.g. /appweaver onboard "Clinical; concerns: auditing, concurrency, authorization"
122
136
  # =============================================================================
123
137
 
124
138
  name: aw-spec-onboard
125
139
  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/projects/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 and refined per slice by adopt. 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`; 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.
126
- version: 1.7.0
140
+ version: 2.1.0
127
141
  agent_agnostic: true
128
142
  dialect: aw-spec.orchestrator/v1
129
143
 
130
144
  inputs:
131
145
  user_input:
132
146
  description: >-
133
- Optional free-text hint. May carry (a) a domain name for the governance project
134
- (e.g. Pharma → guardrails/projects/brf-pharma/); (b) a scope/focus hint for the
135
- feature map; and/or (c) a CONCERNS LIST to look for, as a "concerns: a, b, c"
136
- clause (e.g. "Pharma; concerns: auditing, concurrency, authorization"). The
137
- concerns are a SEARCH HINT only — both rule-set authors still DECIDE which
147
+ The BOUNDED CONTEXT to onboard, as named in the feature map that
148
+ /appweaver inventory produced (e.g. Billing). Onboard runs once per context;
149
+ with no argument it takes the first context in the map that is not yet
150
+ onboarded. May also carry a CONCERNS LIST to look for, as a
151
+ "concerns: a, b, c" clause (e.g. "Billing; concerns: auditing, concurrency").
152
+ The concerns are a SEARCH HINT only — the rule-set authors still DECIDE which
138
153
  concerns are actually present from the code, and are never limited to the list.
139
- When omitted, the domain defaults to the PROJECT name from the OKF overview,
140
- then the repo basename; concerns are auto-discovered from the code.
141
154
  required: false
142
155
  bind: USER_INPUT
143
156
 
@@ -164,6 +177,20 @@ vars:
164
177
  bundle_present: "false" # inventory bundle_guard driver
165
178
  conformant: "false" # OKF conformance-gate driver
166
179
  pack_present: "false" # project anti-clobber driver
180
+ # The governance tier — constitution halves, rule packs, document templates —
181
+ # is PROJECT-scoped, authored by the first context to onboard and left alone by
182
+ # every context after it. Re-authoring project principles from one context's
183
+ # evidence is the scoping bias the rev-constitution work removed; this var is
184
+ # what keeps the second run from doing it.
185
+ repo_gov: "false" # true once the project governance exists
186
+ # The governance project is named from the PROJECT, never from the context.
187
+ # Passing the context name here would produce one rule pack per bounded
188
+ # context, which is the same bias by another route.
189
+ gov_name: ""
190
+ context_known: "false"
191
+ is_blocked: "false"
192
+ in_cycle: "false"
193
+ already_onboarded: "false"
167
194
  technical_ok: "false" # technical-half lint guard
168
195
  domain_ok: "false" # domain-half lint guard
169
196
  ui_ok: "false" # UI-half lint guard
@@ -281,14 +308,106 @@ workflow:
281
308
  on_false: stop
282
309
  on_false_message: "Scan found no candidate features in {{root}} (file_count={{file_count}}). Point /appweaver onboard at a codebase with a recognizable domain/vertical-slice layout, or scan a subtree that contains one."
283
310
 
284
- # 1c. Curation guard (OKF rule): a bundle that already has concept files is
285
- # curation — regenerating from scratch would destroy it.
286
- - id: bundle_guard
311
+ # 1c. WHICH BOUNDED CONTEXT, AND IS IT THIS ONE'S TURN. onboard runs once per
312
+ # context, so before anything is written it reads the map inventory
313
+ # produced and asks four questions: is this a context the map knows, what
314
+ # does it hold, has it already been onboarded, and is everything it depends
315
+ # on onboarded first.
316
+ #
317
+ # This replaces the bundle-wide curation guard. That guard stopped whenever
318
+ # the bundle held any concept at all, which is indistinguishable from
319
+ # "context 1 has been onboarded" — so it made onboarding a second context
320
+ # impossible. The curation it protects is still protected, per context:
321
+ # a context whose concepts already exist is not regenerated.
322
+ - id: context_state
323
+ action: execute_script
324
+ script: { ref: inventory }
325
+ subcommand: context-state
326
+ args: ["--context", "{{USER_INPUT}}", "--bundle", "{{bundle_dir}}"]
327
+ on_error: continue
328
+ outputs:
329
+ - { name: map_present, from: "$.map_present" }
330
+ - { name: context_known, from: "$.context_known" }
331
+ - { name: bc, from: "$.context" }
332
+ - { name: bc_slug, from: "$.context_slug" }
333
+ - { name: bc_features, from: "$.features" }
334
+ - { name: bc_feature_count, from: "$.feature_count" }
335
+ - { name: pending_features, from: "$.pending_features" }
336
+ - { name: pending_count, from: "$.pending_count" }
337
+ - { name: bc_aggregates, from: "$.aggregates" }
338
+ - { name: bc_feature_aggregates, from: "$.feature_aggregates" }
339
+ - { name: pending_aggregates, from: "$.pending_aggregates" }
340
+ - { name: already_onboarded, from: "$.already_onboarded" }
341
+ - { name: is_blocked, from: "$.is_blocked" }
342
+ - { name: blocked_by, from: "$.blocked_by" }
343
+ - { name: in_cycle, from: "$.in_cycle" }
344
+ - { name: cycle_with, from: "$.cycle_with" }
345
+ - { name: is_first, from: "$.is_first" }
346
+ - { name: onboarded_contexts, from: "$.onboarded_contexts" }
347
+ - { name: remaining_contexts, from: "$.remaining_contexts" }
348
+ - { name: contexts_ordered, from: "$.contexts_ordered" }
349
+ - { name: feature_map, from: "$.feature_map" }
350
+ - { name: map_error, from: "$.error" }
351
+
352
+ # 1d. No map means the boundaries were never decided. Onboarding without them
353
+ # is what produced a flat aggregate list with no context level at all.
354
+ - id: require_map
355
+ action: verify_context
356
+ require_value: map_present
357
+ equals: "true"
358
+ on_mismatch: stop
359
+ on_mismatch_message: >
360
+ No feature map was found. Onboard works one BOUNDED CONTEXT at a time and
361
+ reads the map /appweaver inventory produces. Run `/appweaver inventory`,
362
+ review and edit `specs/proposed-inventory.md` — it is the boundary map and
363
+ it is yours to change — then run `/appweaver inventory apply`.
364
+
365
+ - id: require_context
366
+ action: verify_context
367
+ require_value: context_known
368
+ equals: "true"
369
+ on_mismatch: stop
370
+ on_mismatch_message: "{{map_error}}"
371
+
372
+ # 1e. Per-context curation guard — the narrow form of the old bundle guard.
373
+ - id: context_done_guard
374
+ action: verify_context
375
+ require_value: already_onboarded
376
+ equals: "false"
377
+ on_mismatch: stop
378
+ on_mismatch_message: >
379
+ Bounded context {{bc}} is already onboarded — every aggregate its
380
+ {{bc_feature_count}} feature(s) act on ({{bc_aggregates}}) already has a concept in
381
+ {{bundle_dir}}, and re-running would overwrite that curation. Contexts still open: {{remaining_contexts}}
382
+
383
+ # 1f. Dependency order. A context whose dependencies are still open would be
384
+ # modelled against aggregates that do not exist yet. A context inside a
385
+ # CYCLE is released rather than blocked — each member is waiting on the
386
+ # other, so blocking both deadlocks the sequence.
387
+ - id: context_order_gate
287
388
  action: verify_context
288
- require_value: bundle_present
389
+ require_value: is_blocked
289
390
  equals: "false"
290
391
  on_mismatch: stop
291
- on_mismatch_message: "The OKF feature-map bundle at {{bundle_dir}} already holds {{bundle_md_count}} concept file(s) — onboard would overwrite that curation. Back up or remove {{bundle_dir}} to re-onboard from scratch."
392
+ on_mismatch_message: >
393
+ Bounded context {{bc}} depends on a context that has not been onboarded yet:
394
+ {{blocked_by}}. Its features cite aggregates that will not exist until then, so
395
+ onboard in the order the map gives — {{contexts_ordered}} — or run
396
+ /appweaver onboard with no argument to take the next one automatically.
397
+ To change that order, edit the Depends On column in specs/proposed-inventory.md
398
+ and re-run /appweaver inventory apply.
399
+
400
+ - id: cycle_warning
401
+ action: verify_context
402
+ condition: "{{in_cycle}} == true"
403
+ require_value: in_cycle
404
+ equals: "never"
405
+ on_mismatch: continue
406
+ on_mismatch_message: >
407
+ NOTE: {{bc}} and {{cycle_with}} depend on each other. They cannot be ordered,
408
+ so {{bc}} is released rather than blocked — but the two share a seam, and the
409
+ aggregates each cites from the other will be incomplete until both are
410
+ onboarded. Break the cycle with a seam, or onboard the ring back to back.
292
411
 
293
412
  # 1d. FRONTEND LANE — the DECLARATION decides that it exists, and the CODE decides
294
413
  # what its governance says. Those are two different questions and they used to be
@@ -389,6 +508,7 @@ workflow:
389
508
  action: build_context
390
509
  context:
391
510
  - { path: "{{inventory_json}}" } # the deterministic substrate (aggregate_signals etc.)
511
+ - { path: "{{feature_map}}" } # the CONFIRMED boundaries: which features belong to which bounded context, and in what order
392
512
  - { path: .appweaver/templates/okf-concept-template.md } # OKF v0.1 format authority (frontmatter, index, log, rules) — format only, zero project content
393
513
  - id: author_bundle
394
514
  action: agent_generate
@@ -396,32 +516,55 @@ workflow:
396
516
  permission_mode: acceptEdits
397
517
  task: |
398
518
  Act as the OKF enrichment agent for the Brownfield DEVELOPMENT onboard step.
399
- Produce a CONFORMANT OKF v0.1 knowledge bundle at {{bundle_dir}} that is a
400
- HIGH-LEVEL FEATURE MAP — a discovery index of the features/aggregates this
401
- codebase contains, organized BY AGGREGATE ROOT — from the deterministic
402
- substrate {{inventory_json}} (in context). Follow the OKF concept template in
403
- context for format (frontmatter, index.md/log.md rules, cross-linking, hard rules).
404
- Domain/scope hint (optional): {{USER_INPUT}}
405
-
406
- THIS IS A MAP, NOT A DEEP REVERSE. Keep every feature concept SHALLOW — enough
407
- to recognize and pick the feature to develop next. The deep per-feature reverse
408
- (spec.md + the context's domain-model.md + the lane plans) is /appweaver adopt, run
409
- just-in-time when a feature is about to be developed. Do NOT deep-model
519
+ Extend the OKF v0.1 knowledge bundle at {{bundle_dir}} with the features of ONE
520
+ BOUNDED CONTEXT — a discovery index of what that context contains — from the
521
+ deterministic substrate {{inventory_json}} and the confirmed boundary map
522
+ {{feature_map}} (both in context). Follow the OKF concept template in context for
523
+ format (frontmatter, index.md/log.md rules, cross-linking, hard rules).
524
+
525
+ THE CONTEXT YOU ARE ONBOARDING IS `{{bc}}`.
526
+ Its features, already confirmed by the operator: {{bc_features}}
527
+ The aggregates those features act on: {{bc_aggregates}}
528
+ Which feature acts on which: {{bc_feature_aggregates}}
529
+ Aggregates still without a concept, to be written this run: {{pending_aggregates}}
530
+
531
+ THE BUNDLE IS THE PROJECT'S KNOWLEDGE, AND A CONCEPT IS AN AGGREGATE — NEVER A
532
+ FEATURE. Features are the specs tree's unit (this run creates their directories);
533
+ they are LISTED on their aggregate's concept and never given concepts of their own.
534
+ Several features can act on one aggregate — the map split it into capabilities —
535
+ and that aggregate still gets exactly one concept.
536
+
537
+ THE BOUNDARIES ARE DECIDED — DO NOT REDRAW THEM. The feature map is the output of
538
+ a scan the operator has already reviewed and edited by hand. Write one concept per
539
+ AGGREGATE the map names for this context, and no others. Do not merge two
540
+ aggregates, do not split one, do not invent an aggregate or a feature the map does
541
+ not list, and do not write a concept for an aggregate belonging to another bounded
542
+ context — those are onboarded by their own runs. Where the substrate's `aggregate_signals` disagree with the map,
543
+ THE MAP WINS; note the disagreement in `open_questions` on the concept.
544
+
545
+ THIS IS ADDITIVE. Other bounded contexts may already have concepts in this bundle.
546
+ Read the bundle before writing. Create the files this context needs, UPDATE the
547
+ shared index/log files in place, and NEVER delete, rewrite or re-scope a concept
548
+ belonging to another context. If a file you would create already exists, it belongs
549
+ to an earlier run — leave it alone.
550
+
551
+ THIS IS A MAP, NOT A DEEP REVERSE. Keep every concept SHALLOW — enough to
552
+ recognize the aggregate and pick a feature over it to develop next. Do NOT deep-model
410
553
  invariants/behaviour here.
411
554
 
412
- Read the substrate first. Its `aggregate_signals` are CANDIDATE feature roots,
413
- each with its files grouped by layer plus detected entities; `ui_attribution`
414
- says which FRONTEND files serve which of those roots (and which serve none);
555
+ Read the substrate for EVIDENCE about the map's aggregates. Its `aggregate_signals`
556
+ carry each root's files grouped by layer plus detected entities; `ui_attribution`
557
+ says which FRONTEND files serve which root (and which serve none);
415
558
  `git.history.churn` ranks significance; the category lists and `top_level_dirs`
416
- fill in the rest.
417
- Signals are input, not decisions — YOU draw the real feature boundaries:
418
- - Merge a src module and its mirror test module into ONE feature (e.g.
419
- src/.../MedicinalProducts + tests/.../MedicinalProducts → MedicinalProduct).
559
+ fill in the rest. Where several features act on one aggregate (two seams on one
560
+ root), its ONE concept carries the whole module — domain and behaviour files alike
561
+ — and names each feature with the capability it covers. Which files serve which
562
+ capability is recorded per feature later, in the source-map adopt writes.
420
563
  - Treat service-level / shared infrastructure (a shared persistence context,
421
564
  cross-cutting adapters, host / service-defaults projects) as a Platform/Shared
422
565
  concept, NOT a feature.
423
566
  - Fold value objects, entities, domain events, commands and endpoints into the
424
- feature that OWNS them — one feature concept, not one per type.
567
+ aggregate that OWNS them — one aggregate concept, not one per type.
425
568
  NAME EVERY CONCEPT IN THE CODE'S OWN VOCABULARY — read the identifiers the source
426
569
  actually uses. "Aggregate", "entity" and "value object" are how aw-spec ORGANIZES a
427
570
  feature map; they are not a claim that this codebase is modelled that way. Where the
@@ -429,9 +572,19 @@ workflow:
429
572
  grouping around it.
430
573
 
431
574
  Write the bundle (all paths under {{bundle_dir}}; bundle-relative links begin
432
- with "/", per OKF §5.1):
575
+ with "/", per OKF §5.1).
576
+
577
+ IS THIS THE FIRST CONTEXT IN THIS BUNDLE? `{{is_first}}`
578
+ The three `architecture/` notes below describe the WHOLE repository, not one
579
+ context, so they are written ONCE — by the first context to onboard. When
580
+ `{{is_first}}` is false they already exist: do not rewrite them, and add to them
581
+ only where this context introduces a technology or integration point the note
582
+ genuinely lacks. Everything else below is written on every run, for this
583
+ context's features only.
584
+
433
585
  - `index.md` (bundle root) — frontmatter EXACTLY `okf_version: "0.1"` and nothing
434
586
  else; body = sections of bulleted links reusing each concept's `description`.
587
+ On a later context, ADD this context's entries and leave the rest in place.
435
588
  - `architecture/overview.md` (type: Reference) — the system at a glance. Its
436
589
  `## Purpose` section MUST open with the whole solution/product name in bold
437
590
  followed by "is a …" (e.g. "**Medicinal.Healthcare** is a …") — this bold token
@@ -464,11 +617,14 @@ workflow:
464
617
  unattributed` lists the files serving no single aggregate (app shell, layout,
465
618
  design system, global styles). Describe what they provide; they belong here
466
619
  precisely because no slice owns them.
467
- - `aggregates/<feature>.md` (type: Aggregate) — ONE per feature root, SHALLOW:
620
+ - `aggregates/<aggregate>.md` (type: Aggregate) — ONE per aggregate, SHALLOW, its
621
+ `title:` EXACTLY the aggregate's name as the map spells it (`MedicinalProduct`,
622
+ never `Medicinal Product` — later commands find the concept by that name):
468
623
  Responsibilities; the entities / value objects / domain events / commands / API
469
624
  endpoints / persistence it OWNS (named at a glance from the signal's layer
470
- files — a list, not a deep model); and the candidate `specs/<Feature>/` slice
471
- name (feature = aggregate). Set `source_files` to the module's files, grouped
625
+ files — a list, not a deep model); and `features:` in frontmatter — the map's
626
+ features that act on it, each of which is a `specs/{{bc}}/<Feature>/` directory
627
+ this run creates. Set `source_files` to the module's files, grouped
472
628
  with YAML comment headers by each file's OWN folder — the path segment that
473
629
  VARIES across the files after their shared parent (the layer folder in a
474
630
  vertical slice; the tier project in an n-tier app; tests → a single `tests`
@@ -480,18 +636,25 @@ workflow:
480
636
  is and move or drop one it got wrong. Keep the key and leave it EMPTY where the
481
637
  aggregate has no UI (and on a backend-only repo, where every concept has none);
482
638
  never fold these paths into `source_files`, which stays the service surface.
483
- - `aggregates/index.md` — the bounded-context / feature map (no frontmatter beyond
484
- OKF index rules) linking every feature concept.
639
+ - `aggregates/index.md` — the BOUNDED-CONTEXT / feature map (no frontmatter beyond
640
+ OKF index rules). Group the links under a `## <BoundedContext>` heading per
641
+ context, so the file shows which aggregates belong to which context rather than one
642
+ flat list, each link followed by the features that act on that aggregate. Add a
643
+ `## {{bc}}` section with this context's aggregates; leave every
644
+ other section exactly as it is.
485
645
  - An `index.md` in EVERY subdirectory (no frontmatter).
486
- - `log.md` (bundle root) — first line under a `## <today's date>` heading must be
487
- `Commit: ` + backtick + `{{head}}` + backtick (validator rule E4), then a
488
- one-line Initialization entry noting the concept count.
646
+ - `log.md` (bundle root) — APPEND under a `## <today's date>` heading whose first
647
+ line is `Commit: ` + backtick + `{{head}}` + backtick (validator rule E4), then a
648
+ one-line entry naming the bounded context onboarded and its concept count. Keep
649
+ every earlier dated entry.
489
650
  Do NOT write a migration-backlog, a seam/clean-torn analysis, or an adopt-order —
490
651
  those are migration artifacts and are out of scope for the development flow.
491
652
 
492
653
  Provenance + safety (OKF hard rules):
493
- - Stamp every concept `origin: reverse-engineered` and `generated_by:
494
- aw-spec-onboard/1.6.0` in frontmatter.
654
+ - Stamp every concept `origin: reverse-engineered`, `generated_by:
655
+ aw-spec-onboard/2.0.0` and `bounded_context: {{bc}}` in frontmatter. The
656
+ context key is what lets later commands filter features by the context they
657
+ belong to instead of listing every aggregate under every one.
495
658
  - The CODE is the source of truth; capture what IS (quirks included), not what
496
659
  SHOULD be. Where intent is unclear from code + git history, add a concrete
497
660
  `open_questions` entry rather than inventing one.
@@ -526,6 +689,76 @@ workflow:
526
689
  on_false: stop
527
690
  on_false_message: "The OKF feature map at {{bundle_dir}} is NON-CONFORMANT (errors: {{okf_errors}}). Fix the reported ERRORs (unparseable frontmatter, missing `type`, malformed index.md/log.md) and re-run."
528
691
 
692
+ # ═══════════ THE CONTEXT'S SPECS TREE — specs/<Context>/<Feature>/ ═══════════
693
+ # The concepts above say what this context CONTAINS; these two steps make that
694
+ # shape exist where every later command looks for it. Until now a context left
695
+ # no trace under specs/ at all: `list-contexts` reads the tree rather than the
696
+ # bundle, so the context it had just onboarded reported as absent, and
697
+ # select-feature's refusal-to-guess gate — contexts exist, none is active —
698
+ # could not even be reached. select-feature merges the bundle's aggregates into
699
+ # its list to cover the gap, but a feature that exists only as a concept has
700
+ # nowhere for adopt to write, and picking one would create its directory at
701
+ # whatever base happened to be active.
702
+ #
703
+ # DIRECTORIES ONLY. No spec.md, no domain-model.md, no plan: adopt reverse-
704
+ # engineers the first per feature and specify authors the second per context,
705
+ # and a placeholder for either reads as "the document exists" to every gate
706
+ # downstream. The directory says the feature is KNOWN; the documents say it is
707
+ # described.
708
+ - id: activate_context
709
+ action: execute_script
710
+ script: { ref: actions }
711
+ subcommand: set-context
712
+ args: ["--context", "{{bc}}"]
713
+ outputs:
714
+ - { name: bc_dir, from: "$.context_dir" }
715
+ - { name: bc_domain_model, from: "$.domain_model" }
716
+ - { name: bc_dir_created, from: "$.created" }
717
+
718
+ - id: scaffold_features
719
+ action: execute_script
720
+ script: { ref: inventory }
721
+ subcommand: scaffold-context
722
+ args: ["--context", "{{bc}}", "--map", "{{feature_map}}"]
723
+ on_error: continue
724
+ outputs:
725
+ - { name: scaffold_ok, from: "$.ok" }
726
+ - { name: feature_dirs, from: "$.feature_dirs" }
727
+ - { name: dirs_created, from: "$.created" }
728
+ - { name: dirs_created_num, from: "$.created_count" }
729
+ - { name: dirs_rejected, from: "$.rejected" }
730
+ - { name: dirs_rejected_any, from: "$.rejected_present" }
731
+ - { name: scaffold_error, from: "$.error" }
732
+
733
+ - id: scaffold_gate
734
+ action: verify_context
735
+ require_value: scaffold_ok
736
+ equals: "true"
737
+ on_mismatch: stop
738
+ on_mismatch_message: >
739
+ The feature directories for {{bc}} could not be created: {{scaffold_error}}
740
+ The OKF concepts for this context ARE written — only the specs/ tree is
741
+ missing, so fix the name the message reports in specs/proposed-inventory.md,
742
+ run /appweaver inventory apply, and re-run onboard for this context.
743
+
744
+ # A feature name the map carries that is not a usable directory identifier. Named
745
+ # rather than dropped silently: the concept exists, so the feature is pickable from
746
+ # the bundle and would land in a directory nobody chose.
747
+ # The never-satisfiable `equals` is the engine's announce-only idiom: the step is
748
+ # entered only when there IS something to report, and the comparison is written so
749
+ # it always misses, so the message is emitted and the run continues.
750
+ - id: scaffold_name_warning
751
+ action: verify_context
752
+ condition: "{{dirs_rejected_any}} == true"
753
+ require_value: dirs_rejected_any
754
+ equals: "never"
755
+ on_mismatch: continue
756
+ on_mismatch_message: >
757
+ These feature names are not valid directory identifiers and got no directory:
758
+ {{dirs_rejected}}. A feature name has to be a letter-led alphanumeric aggregate
759
+ (Order, MedicinalProduct). Rename them in specs/proposed-inventory.md, re-run
760
+ /appweaver inventory apply, then /appweaver select-feature will offer them.
761
+
529
762
  # ═══════════════ PART 2 — GOVERNANCE SCAFFOLD (project-level) ════════════════
530
763
  # Establish the governing tier ONCE, from the feature map just written (the whole-
531
764
  # repo vantage). No slice is adopted, so list-adopted returns slice_count=0 but STILL
@@ -548,11 +781,16 @@ workflow:
548
781
  # Slugify + `brf-` prefix the domain name and create guardrails/projects/brf-<domain>/.
549
782
  # Name: explicit arg → PROJECT name from the OKF overview → repo basename. Guarded
550
783
  # against clobbering a project that already holds .md files.
784
+ # The governance project is named from the PROJECT — `gov_name` is empty, so
785
+ # project-setup falls back to the project name from the OKF overview and then
786
+ # to the repo basename. Passing the bounded context here would create one rule
787
+ # pack per context and split the project's constitution along context lines,
788
+ # which is the aggregate-scoping bias in a new place.
551
789
  - id: pack_setup
552
790
  action: execute_script
553
791
  script: { ref: revcon }
554
792
  subcommand: project-setup
555
- args: ["--name", "{{USER_INPUT}}", "--fallback", "{{project_name}}"]
793
+ args: ["--name", "{{gov_name}}", "--fallback", "{{project_name}}"]
556
794
  outputs:
557
795
  - { name: domain_slug, from: "$.domain_slug" }
558
796
  - { name: pack_dir, from: "$.pack_dir" }
@@ -560,18 +798,54 @@ workflow:
560
798
  - { name: domain_constitution_source, from: "$.domain_constitution_source" }
561
799
  - { name: pack_present, from: "$.pack_present" }
562
800
 
563
- - id: pack_guard
564
- action: verify_context
565
- require_value: pack_present
566
- equals: "false"
567
- on_mismatch: stop
568
- on_mismatch_message: "The project guardrails/projects/{{domain_slug}}/ already holds curated rule files — onboard would overwrite them. Back up or remove that folder to re-onboard, or amend it via /appweaver constitution."
801
+ # An existing pack is no longer a reason to stop — it is the signal that the
802
+ # project tier has already been authored and this run is onboarding a LATER
803
+ # bounded context. The tier is written once and amended by /appweaver
804
+ # constitution; what each later context still contributes is its own OKF
805
+ # concepts and its own domain model.
806
+ - id: repo_gov_present
807
+ action: set
808
+ condition: "{{pack_present}} == true"
809
+ vars: { repo_gov: "true" }
810
+
811
+ # WHAT THIS RUN AUTHORS. The engine compares one variable against one value and
812
+ # has no compound conditions, so "this lane exists AND the project tier has not
813
+ # been written yet" is computed here as an ordered pair of sets rather than
814
+ # asked at each step: default to the lane declaration, then clear everything
815
+ # once the project tier is present.
816
+ #
817
+ # The second set also SATISFIES the lint guards the skipped block would
818
+ # otherwise leave at their "not yet verified" default — the same move
819
+ # svc_lane_absent makes for a repo with no service lane. Without it a later
820
+ # context would stop at a gate checking work this run correctly did not do.
821
+ #
822
+ # ⌛ OPEN: should a LATER context amend the rule sets? Skipping the whole tier
823
+ # also skips the code-derived rule files, and a second context can evidence a
824
+ # domain or technical concern the first one's source never showed — that
825
+ # evidence reaches nothing today. The two halves of the tier differ here. The
826
+ # constitution halves, principle numbering, domain activation and the document
827
+ # templates are project-scoped, and re-deriving them per context IS the
828
+ # aggregate-scoping bias rev-constitution v1.1.0 removed; /appweaver
829
+ # constitution is their amendment path. The rule SETS
830
+ # (guardrails/projects/<p>/{domain,service,frontend}/) are evidenced-only, so
831
+ # amending them ADDITIVELY from a later context — add a rule for a concern this
832
+ # context exhibits, never rewrite or renumber an existing one — would be more
833
+ # evidence at the same project scope rather than one context's bias. That
834
+ # additive pass is not built; author-once is what runs.
835
+ - id: author_flags_default
836
+ action: set
837
+ vars: { author_repo: "true", author_svc: "{{svc_lane}}", author_ui_flag: "{{ui_lane}}" }
838
+ - id: author_flags_skip
839
+ action: set
840
+ condition: "{{repo_gov}} == true"
841
+ vars: { author_repo: "false", author_svc: "false", author_ui_flag: "false", technical_ok: "true", domain_ok: "true", ui_ok: "true", numbering_ok: "true" }
569
842
 
570
843
  # ── DOMAIN RULE SET (provisional, evidenced by the SCAN) ────────────────────
571
844
  # Feed NEUTRAL shape skeletons (rev-templates/, zero content to leak) + the rule-
572
845
  # partition authority + the project context (the feature map). NO adopted specs
573
846
  # exist — the evidence is the OKF overview + aggregates/index + platform.
574
847
  - id: ctx_pack
848
+ condition: "{{author_repo}} == true"
575
849
  action: build_context
576
850
  context:
577
851
  - { path: "{{inventory_json}}" } # the COMPLETE deterministic scan substrate — read representative SOURCE from its file lists (the OKF map only SUMMARISES this)
@@ -581,6 +855,7 @@ workflow:
581
855
  - { path: .appweaver/RULE-PARTITION.md } # the rule-partition authority (which command reads what)
582
856
  context_from: project_context
583
857
  - id: author_pack
858
+ condition: "{{author_repo}} == true"
584
859
  action: agent_generate
585
860
  tools: "Read,Write,Edit"
586
861
  permission_mode: acceptEdits
@@ -659,11 +934,13 @@ workflow:
659
934
  - { name: pack_files, from: "$.files" }
660
935
 
661
936
  - id: verify_pack
937
+ condition: "{{author_repo}} == true"
662
938
  action: verify_context
663
939
  require_non_empty: pack_files
664
940
  on_empty: stop
665
941
  on_empty_message: "No domain rule files were written to guardrails/projects/{{domain_slug}}/domain/. Ensure the feature map carries a modellable domain (a feature map + ubiquitous language) and re-run."
666
942
  - id: require_domain_rule_bindings
943
+ condition: "{{author_repo}} == true"
667
944
  action: verify_context
668
945
  required_files: ["{{domain_rule_bindings}}"]
669
946
 
@@ -671,12 +948,14 @@ workflow:
671
948
  # Named and placed exactly as a greenfield industry corpus names and places its charter,
672
949
  # and already wired as the first `## /aw-spec-constitution` bullet by the step above.
673
950
  - id: ctx_domain_source
951
+ condition: "{{author_repo}} == true"
674
952
  action: build_context
675
953
  context:
676
954
  - { path: "{{domain_rule_bindings}}" }
677
955
  - { path: .appweaver/orchestrator/rev-templates/domain-constitution.skeleton.md, optional: true }
678
956
  context_from: project_context
679
957
  - id: author_domain_source
958
+ condition: "{{author_repo}} == true"
680
959
  action: agent_author
681
960
  include_standards: false
682
961
  output_target: { type: file, path: "{{domain_constitution_source}}" }
@@ -719,6 +998,7 @@ workflow:
719
998
  # do, so a later call without the flag silently recreates the half an earlier call
720
999
  # was told to skip.
721
1000
  - id: setup_constitution
1001
+ condition: "{{author_repo}} == true"
722
1002
  action: execute_script
723
1003
  script: { ref: actions }
724
1004
  subcommand: setup-constitution
@@ -732,7 +1012,7 @@ workflow:
732
1012
  # set, which is empty), so nothing leaks into the Part-1 feature-map agent.
733
1013
  - id: ctx_technical
734
1014
  action: build_context
735
- condition: "{{svc_lane}} == true"
1015
+ condition: "{{author_svc}} == true"
736
1016
  context:
737
1017
  - { path: "{{constitution_technical_file}}" }
738
1018
  - { path: .appweaver/orchestrator/rev-templates/technical-constitution.skeleton.md, optional: true }
@@ -740,7 +1020,7 @@ workflow:
740
1020
  context_from: design_context
741
1021
  - id: author_technical
742
1022
  action: agent_author
743
- condition: "{{svc_lane}} == true"
1023
+ condition: "{{author_svc}} == true"
744
1024
  include_standards: false
745
1025
  output_target: { type: file, path: "{{constitution_technical_file}}" }
746
1026
  task: |
@@ -783,7 +1063,7 @@ workflow:
783
1063
 
784
1064
  - id: technical_validation_loop
785
1065
  action: loop
786
- condition: "{{svc_lane}} == true"
1066
+ condition: "{{author_svc}} == true"
787
1067
  while: "{{technical_ok}} != true"
788
1068
  max_iterations: 3
789
1069
  steps:
@@ -828,7 +1108,7 @@ workflow:
828
1108
  # ABSENCE is meaningful: a repo with no UI never gets the file at all.
829
1109
  - id: setup_ui_constitution
830
1110
  action: execute_script
831
- condition: "{{ui_lane}} == true"
1111
+ condition: "{{author_ui_flag}} == true"
832
1112
  script: { ref: actions }
833
1113
  subcommand: setup-constitution
834
1114
  args: ["--ui", "{{setup_tech_flag}}"]
@@ -838,7 +1118,7 @@ workflow:
838
1118
 
839
1119
  - id: ctx_ui
840
1120
  action: build_context
841
- condition: "{{ui_lane}} == true"
1121
+ condition: "{{author_ui_flag}} == true"
842
1122
  context:
843
1123
  - { path: "{{constitution_ui_file}}" } # the target half being filled
844
1124
  - { path: "{{inventory_json}}" } # PRIMARY: the COMPLETE deterministic substrate — frontend_signals + the UI file lists to read source from
@@ -846,7 +1126,7 @@ workflow:
846
1126
  - { path: "{{bundle_dir}}/architecture/frontend.md", optional: true } # SECONDARY (shallow): the OKF as-built frontend note — corroborate, don't rely on alone
847
1127
  - id: author_ui
848
1128
  action: agent_author
849
- condition: "{{ui_lane}} == true"
1129
+ condition: "{{author_ui_flag}} == true"
850
1130
  include_standards: false
851
1131
  tools: Read # EVIDENCE = THE UI CODE ITSELF; the inventory inlines the file LISTS, not the files
852
1132
  output_target: { type: file, path: "{{constitution_ui_file}}" }
@@ -915,7 +1195,7 @@ workflow:
915
1195
 
916
1196
  - id: ui_validation_loop
917
1197
  action: loop
918
- condition: "{{ui_lane}} == true"
1198
+ condition: "{{author_ui_flag}} == true"
919
1199
  while: "{{ui_ok}} != true"
920
1200
  max_iterations: 3
921
1201
  steps:
@@ -948,15 +1228,17 @@ workflow:
948
1228
  # repo no half was created, so the run reports that rather than a bare false a reader
949
1229
  # would take for a half that needs a manual touch.
950
1230
  - id: ui_validation_state_absent
1231
+ condition: "{{author_repo}} == true"
951
1232
  action: set
952
1233
  vars: { ui_validation_state: "n/a — no frontend lane, no UI half authored" }
953
1234
  - id: ui_validation_state_present
954
1235
  action: set
955
- condition: "{{ui_lane}} == true"
1236
+ condition: "{{author_ui_flag}} == true"
956
1237
  vars: { ui_validation_state: "{{ui_ok}}" }
957
1238
 
958
1239
  # DOMAIN HALF — from the project + charter, principles continue the technical numbering.
959
1240
  - id: ctx_domain
1241
+ condition: "{{author_repo}} == true"
960
1242
  action: build_context
961
1243
  context:
962
1244
  - { path: "{{constitution_domain_file}}" }
@@ -965,6 +1247,7 @@ workflow:
965
1247
  - { path: "{{domain_rule_bindings}}" }
966
1248
  context_from: project_context
967
1249
  - id: author_domain
1250
+ condition: "{{author_repo}} == true"
968
1251
  action: agent_author
969
1252
  include_standards: false
970
1253
  output_target: { type: file, path: "{{constitution_domain_file}}" }
@@ -987,8 +1270,8 @@ workflow:
987
1270
  numeral is whatever the code supported — never a value carried over from another
988
1271
  constitution. If it mandates no modelling methodology, say so plainly rather than
989
1272
  supplying one.
990
- - Author ONLY the domain layer: domain principles, domain folder additions,
991
- regulatory/security posture, domain governance — from the project + charter. NUMBER
1273
+ - Author ONLY the domain layer: project identity, domain principles, domain folder
1274
+ additions, regulatory/security posture, domain governance — from the project + charter. NUMBER
992
1275
  them by CONTINUING the technical half's roman numerals: READ
993
1276
  constitution.technical.md (in context), find its LAST numeral N, start the first
994
1277
  domain principle at N+1 (do NOT assume it ends at XV). TITLE each by DOMAIN
@@ -1005,6 +1288,7 @@ workflow:
1005
1288
  Return the complete updated domain addenda content only.
1006
1289
 
1007
1290
  - id: domain_validation_loop
1291
+ condition: "{{author_repo}} == true"
1008
1292
  action: loop
1009
1293
  while: "{{domain_ok}} != true"
1010
1294
  max_iterations: 3
@@ -1036,6 +1320,7 @@ workflow:
1036
1320
 
1037
1321
  # ── COMPOSE + ACTIVATE ───────────────────────────────────────────────────────
1038
1322
  - id: compose_constitution
1323
+ condition: "{{author_repo}} == true"
1039
1324
  action: execute_script
1040
1325
  script: { ref: actions }
1041
1326
  subcommand: compose-constitution
@@ -1058,6 +1343,7 @@ workflow:
1058
1343
  # Ordered override — the var holds "ok" unless the check reported a problem, because
1059
1344
  # require_non_empty reports on EMPTY.
1060
1345
  - id: numbering_default
1346
+ condition: "{{author_repo}} == true"
1061
1347
  action: set
1062
1348
  vars: { numbering_gate: "ok" }
1063
1349
  - id: numbering_detect
@@ -1065,6 +1351,7 @@ workflow:
1065
1351
  condition: "{{numbering_ok}} == false"
1066
1352
  vars: { numbering_gate: "" }
1067
1353
  - id: numbering_warning
1354
+ condition: "{{author_repo}} == true"
1068
1355
  action: verify_context
1069
1356
  require_non_empty: numbering_gate
1070
1357
  on_empty: continue
@@ -1080,6 +1367,7 @@ workflow:
1080
1367
  # Auto-activate: point .appweaver/domain.json at the scaffolded project so the forward CR
1081
1368
  # loop governs development with it from the first change.
1082
1369
  - id: activate_domain
1370
+ condition: "{{author_repo}} == true"
1083
1371
  action: execute_script
1084
1372
  script: { ref: actions }
1085
1373
  subcommand: set-domain
@@ -1111,7 +1399,7 @@ workflow:
1111
1399
  # lives inside pack_dir, so pack_guard (above) already protects it from clobber.
1112
1400
  - id: ctx_tech_pack
1113
1401
  action: build_context
1114
- condition: "{{svc_lane}} == true"
1402
+ condition: "{{author_svc}} == true"
1115
1403
  context:
1116
1404
  - { path: "{{inventory_json}}" } # PRIMARY: the COMPLETE deterministic substrate — read representative SOURCE from its file lists
1117
1405
  - { path: "{{constitution_technical_file}}" } # PRIMARY: the VALIDATED as-built technology base — the ratified principles these files detail
@@ -1122,7 +1410,7 @@ workflow:
1122
1410
  context_from: design_context
1123
1411
  - id: author_tech_pack
1124
1412
  action: agent_generate
1125
- condition: "{{svc_lane}} == true"
1413
+ condition: "{{author_svc}} == true"
1126
1414
  tools: "Read,Write,Edit"
1127
1415
  permission_mode: acceptEdits
1128
1416
  task: |
@@ -1210,11 +1498,12 @@ workflow:
1210
1498
 
1211
1499
  - id: verify_tech_pack
1212
1500
  action: verify_context
1213
- condition: "{{svc_lane}} == true"
1501
+ condition: "{{author_svc}} == true"
1214
1502
  require_non_empty: tech_pack_files
1215
1503
  on_empty: stop
1216
1504
  on_empty_message: "No technical rule files were written to guardrails/projects/{{domain_slug}}/service/. Ensure the scan substrate (inventory_json) + the validated technical constitution carry an as-built technology base and re-run."
1217
1505
  - id: require_tech_rule_bindings
1506
+ condition: "{{author_repo}} == true"
1218
1507
  action: verify_context
1219
1508
  required_files: ["{{pack_dir}}/tech-rule-bindings.md"]
1220
1509
 
@@ -1227,7 +1516,7 @@ workflow:
1227
1516
  # file, and the run's remaining work is worth keeping either way.
1228
1517
  - id: probe_specify_wiring
1229
1518
  action: execute_script
1230
- condition: "{{svc_lane}} == true"
1519
+ condition: "{{author_svc}} == true"
1231
1520
  on_error: continue
1232
1521
  script: { ref: actions }
1233
1522
  subcommand: resolve-tech
@@ -1236,7 +1525,7 @@ workflow:
1236
1525
  - { name: specify_rules, from: "$.candidates" }
1237
1526
  - id: warn_specify_wiring
1238
1527
  action: verify_context
1239
- condition: "{{svc_lane}} == true"
1528
+ condition: "{{author_svc}} == true"
1240
1529
  require_non_empty: specify_rules
1241
1530
  on_empty: continue
1242
1531
  on_empty_message: >
@@ -1260,7 +1549,7 @@ workflow:
1260
1549
  # find the lane on every future run without stacks.json or a named stack.
1261
1550
  - id: ctx_ui_pack
1262
1551
  action: build_context
1263
- condition: "{{ui_lane}} == true"
1552
+ condition: "{{author_ui_flag}} == true"
1264
1553
  context:
1265
1554
  - { path: "{{inventory_json}}" } # PRIMARY: the COMPLETE deterministic substrate — frontend_signals + the UI file lists to read source from
1266
1555
  - { path: "{{constitution_ui_file}}" } # PRIMARY: the VALIDATED as-built UX-* base — the ratified principles these files detail
@@ -1271,7 +1560,7 @@ workflow:
1271
1560
  - { path: "{{bundle_dir}}/architecture/frontend.md", optional: true } # SECONDARY (shallow): the OKF as-built frontend note
1272
1561
  - id: author_ui_pack
1273
1562
  action: agent_generate
1274
- condition: "{{ui_lane}} == true"
1563
+ condition: "{{author_ui_flag}} == true"
1275
1564
  tools: "Read,Write,Edit"
1276
1565
  permission_mode: acceptEdits
1277
1566
  task: |
@@ -1343,7 +1632,7 @@ workflow:
1343
1632
 
1344
1633
  - id: verify_ui_pack
1345
1634
  action: verify_context
1346
- condition: "{{ui_lane}} == true"
1635
+ condition: "{{author_ui_flag}} == true"
1347
1636
  require_non_empty: ui_pack_files
1348
1637
  on_empty: stop
1349
1638
  on_empty_message: "A frontend lane was detected ({{ui_evidence}}) but no lane rule files were written to guardrails/projects/{{domain_slug}}/frontend/. Check that the scan substrate's frontend_signals carry readable UI source, then re-run."
@@ -1355,7 +1644,7 @@ workflow:
1355
1644
  # it. Announce, don't stop — the rule files are on disk and the heading is one edit away.
1356
1645
  - id: probe_ui_wiring
1357
1646
  action: execute_script
1358
- condition: "{{ui_lane}} == true"
1647
+ condition: "{{author_ui_flag}} == true"
1359
1648
  on_error: continue
1360
1649
  script: { ref: actions }
1361
1650
  subcommand: resolve-tech
@@ -1364,7 +1653,7 @@ workflow:
1364
1653
  - { name: ui_map_rules, from: "$.candidates" }
1365
1654
  - id: warn_ui_wiring
1366
1655
  action: verify_context
1367
- condition: "{{ui_lane}} == true"
1656
+ condition: "{{author_ui_flag}} == true"
1368
1657
  require_non_empty: ui_map_rules
1369
1658
  on_empty: continue
1370
1659
  on_empty_message: >
@@ -1392,6 +1681,7 @@ workflow:
1392
1681
  # the run reports the lanes it actually scanned under rather than a second opinion
1393
1682
  # about them.
1394
1683
  - id: lane_readback
1684
+ condition: "{{author_repo}} == true"
1395
1685
  action: execute_script
1396
1686
  on_error: continue
1397
1687
  script: { ref: actions }
@@ -1451,7 +1741,7 @@ workflow:
1451
1741
  # plus a NEUTRAL skeleton for the bones. No greenfield template is in context.
1452
1742
  - id: ctx_design_template
1453
1743
  action: build_context
1454
- condition: "{{svc_lane}} == true"
1744
+ condition: "{{author_svc}} == true"
1455
1745
  context:
1456
1746
  - { path: "{{inventory_json}}" } # PRIMARY: the COMPLETE deterministic substrate (top_level_dirs, aggregate_signals' per-layer file groupings) — the OKF markdown only SUMMARISES this
1457
1747
  - { path: "{{constitution_technical_file}}" } # PRIMARY: the VALIDATED as-built technology base (framework/persistence/concurrency/hosting/testing/cross-cutting)
@@ -1462,7 +1752,7 @@ workflow:
1462
1752
  - { path: "{{bundle_dir}}/aggregates/index.md", optional: true } # SECONDARY (shallow): the bounded-context / feature map
1463
1753
  - id: gen_design_template
1464
1754
  action: agent_generate
1465
- condition: "{{svc_lane}} == true"
1755
+ condition: "{{author_svc}} == true"
1466
1756
  tools: "Read,Write,Edit"
1467
1757
  permission_mode: acceptEdits
1468
1758
  task: |
@@ -1552,7 +1842,7 @@ workflow:
1552
1842
 
1553
1843
  - id: verify_design_template
1554
1844
  action: verify_context
1555
- condition: "{{svc_lane}} == true"
1845
+ condition: "{{author_svc}} == true"
1556
1846
  require_non_empty: design_template_files
1557
1847
  on_empty: stop
1558
1848
  on_empty_message: "No design template was written to .appweaver/templates/overrides/design-template.md. Ensure the scan substrate (inventory_json) + the technical constitution are present and re-run."
@@ -1563,14 +1853,14 @@ workflow:
1563
1853
  # master's OWN section structure").
1564
1854
  - id: ctx_delta_design_template
1565
1855
  action: build_context
1566
- condition: "{{svc_lane}} == true"
1856
+ condition: "{{author_svc}} == true"
1567
1857
  context:
1568
1858
  - { path: .appweaver/templates/overrides/design-template.md, optional: true } # PRIMARY: the JUST-generated code-derived master — mirror its ACTUAL sections
1569
1859
  - { path: .appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md } # SHAPE ONLY: the neutral change-record bones (zero layering, zero technology)
1570
1860
  - { path: "{{constitution_technical_file}}" } # the validated as-built technology base (keep the delta consistent with the master)
1571
1861
  - id: gen_delta_design_template
1572
1862
  action: agent_generate
1573
- condition: "{{svc_lane}} == true"
1863
+ condition: "{{author_svc}} == true"
1574
1864
  tools: "Read,Write,Edit"
1575
1865
  permission_mode: acceptEdits
1576
1866
  task: |
@@ -1599,7 +1889,7 @@ workflow:
1599
1889
 
1600
1890
  - id: verify_delta_design_template
1601
1891
  action: verify_context
1602
- condition: "{{svc_lane}} == true"
1892
+ condition: "{{author_svc}} == true"
1603
1893
  require_non_empty: delta_design_template_files
1604
1894
  on_empty: stop
1605
1895
  on_empty_message: "No delta-design template was written to .appweaver/templates/overrides/delta-design-template.md. Re-run onboard after confirming the design template override was generated."
@@ -1623,6 +1913,7 @@ workflow:
1623
1913
  # entity: naming one would hand the downstream author the answer to the single question
1624
1914
  # the reverse exists to ask the code.
1625
1915
  - id: ctx_model_template
1916
+ condition: "{{author_repo}} == true"
1626
1917
  action: build_context
1627
1918
  context:
1628
1919
  - { path: "{{inventory_json}}" } # PRIMARY: the COMPLETE deterministic substrate
@@ -1630,6 +1921,7 @@ workflow:
1630
1921
  - { path: "{{constitution_domain_file}}", optional: true } # the reversed DOMAIN frame — vocabulary, not structure
1631
1922
  - { path: "{{bundle_dir}}/aggregates/index.md", optional: true } # SECONDARY (shallow): the bounded-context / feature map
1632
1923
  - id: gen_model_template
1924
+ condition: "{{author_repo}} == true"
1633
1925
  action: agent_generate
1634
1926
  tools: "Read,Write,Edit"
1635
1927
  permission_mode: acceptEdits
@@ -1676,6 +1968,7 @@ workflow:
1676
1968
  - { name: model_template_files, from: "$.files" }
1677
1969
 
1678
1970
  - id: verify_model_template
1971
+ condition: "{{author_repo}} == true"
1679
1972
  action: verify_context
1680
1973
  require_non_empty: model_template_files
1681
1974
  on_empty: stop
@@ -1709,7 +2002,7 @@ workflow:
1709
2002
  # nothing breaks for their absence in a repo that never onboarded.
1710
2003
  - id: ctx_ui_design_template
1711
2004
  action: build_context
1712
- condition: "{{ui_lane}} == true"
2005
+ condition: "{{author_ui_flag}} == true"
1713
2006
  context:
1714
2007
  - { path: "{{inventory_json}}" } # PRIMARY: the COMPLETE deterministic substrate — frontend_signals + the component/route/store/style file lists to read source from
1715
2008
  - { path: "{{constitution_ui_file}}" } # PRIMARY: the VALIDATED as-built UX-* base — the ratified principles this structure must serve
@@ -1718,7 +2011,7 @@ workflow:
1718
2011
  - { path: "{{bundle_dir}}/architecture/frontend.md", optional: true } # SECONDARY (shallow): the OKF as-built frontend note
1719
2012
  - id: gen_ui_design_template
1720
2013
  action: agent_generate
1721
- condition: "{{ui_lane}} == true"
2014
+ condition: "{{author_ui_flag}} == true"
1722
2015
  tools: "Read,Write,Edit"
1723
2016
  permission_mode: acceptEdits
1724
2017
  task: |
@@ -1796,7 +2089,7 @@ workflow:
1796
2089
 
1797
2090
  - id: verify_ui_design_template
1798
2091
  action: verify_context
1799
- condition: "{{ui_lane}} == true"
2092
+ condition: "{{author_ui_flag}} == true"
1800
2093
  require_non_empty: ui_design_template_files
1801
2094
  on_empty: stop
1802
2095
  on_empty_message: "A frontend lane was detected ({{ui_evidence}}) but no UI design template was written to .appweaver/templates/overrides/ui-design-template.md. Check that the scan substrate's frontend_signals carry readable UI source, then re-run."
@@ -1805,14 +2098,14 @@ workflow:
1805
2098
  # as the service delta mirrors the service master.
1806
2099
  - id: ctx_ui_delta_design_template
1807
2100
  action: build_context
1808
- condition: "{{ui_lane}} == true"
2101
+ condition: "{{author_ui_flag}} == true"
1809
2102
  context:
1810
2103
  - { path: .appweaver/templates/overrides/ui-design-template.md, optional: true } # PRIMARY: the JUST-generated lane master — mirror its ACTUAL sections
1811
2104
  - { path: .appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md } # SHAPE ONLY: the neutral change-record bones (zero framework)
1812
2105
  - { path: "{{constitution_ui_file}}" } # the validated UX-* base (keep the delta consistent with the master)
1813
2106
  - id: gen_ui_delta_design_template
1814
2107
  action: agent_generate
1815
- condition: "{{ui_lane}} == true"
2108
+ condition: "{{author_ui_flag}} == true"
1816
2109
  tools: "Read,Write,Edit"
1817
2110
  permission_mode: acceptEdits
1818
2111
  task: |
@@ -1846,7 +2139,7 @@ workflow:
1846
2139
 
1847
2140
  - id: verify_ui_delta_design_template
1848
2141
  action: verify_context
1849
- condition: "{{ui_lane}} == true"
2142
+ condition: "{{author_ui_flag}} == true"
1850
2143
  require_non_empty: ui_delta_design_template_files
1851
2144
  on_empty: stop
1852
2145
  on_empty_message: "No UI delta-design template was written to .appweaver/templates/overrides/ui-delta-design-template.md. Re-run onboard after confirming the UI design template override was generated."
@@ -1865,6 +2158,13 @@ workflow:
1865
2158
 
1866
2159
  outputs:
1867
2160
  bundle_dir: "{{bundle_dir}}"
2161
+ # The context's specs tree — created here, empty by design. It is what makes the
2162
+ # context visible to list-contexts and its features pickable by select-feature.
2163
+ bounded_context: "{{bc}}"
2164
+ context_dir: "{{bc_dir}}"
2165
+ context_domain_model: "{{bc_domain_model}}"
2166
+ feature_dirs: "{{feature_dirs}}"
2167
+ feature_dirs_created: "{{dirs_created}}"
1868
2168
  aggregate_count: "{{aggregate_count}}"
1869
2169
  concepts: "{{concepts}}"
1870
2170
  warnings: "{{okf_warnings}}"
@@ -1910,4 +2210,4 @@ outputs:
1910
2210
  ui_delta_design_template_files: "{{ui_delta_design_template_files}}"
1911
2211
  technical_validation_ok: "{{technical_ok}}"
1912
2212
  domain_validation_ok: "{{domain_ok}}"
1913
- next: "Onboarded {{project_name}}: a high-level feature map at {{bundle_dir}} + a PROVISIONAL project governance scaffold, domain {{active_domain}} ACTIVATED, and — reverse-engineered from THIS code alone — the rule tiers wired per-workflow: the DOMAIN set (guardrails/projects/{{domain_slug}}/domain/*.domain.md + domain-rule-bindings.md) always, and each LANE's set where that lane is declared. ONE HALF AND ONE RULE SET PER LANE: service_lane / ui_lane report which lanes .appweaver/stacks.json declared, and the declaration is what decided. A declared service lane gets constitution.technical.md, guardrails/projects/{{domain_slug}}/service/*.md + tech-rule-bindings.md, and the service design/delta-design template overrides; a declared UI lane gets constitution.ui.md, guardrails/projects/{{domain_slug}}/frontend/*.md mapped under ## /aw-spec-ui-constitution, and its own template pair. A lane declared (none) in select-stack gets none of it, which is the correct outcome and not an omission. LANE DECLARATION: read, never written — select-stack is its sole writer, and this run scanned the source paths it named (scanned_service_root / scanned_ui_root). The scan was SCOPED by them, so the backend substrate excludes the UI subtree and the frontend substrate is that subtree: scanned_backend_files / scanned_ui_files report each. ui_source_evidence_found false means the UI lane's declared path held nothing a scan recognises as UI, so its governance is thin — move the source path with /appweaver select-stack and re-run. The build/test/run commands on each lane are that PROFILE's defaults and may not match a legacy layout — review them, and re-run /appweaver select-stack to correct any lane. Because the domain is activated, resolve-domain + resolve-tech now route the WHOLE forward pipeline AND adopt to these code-derived rules — never another project's rules as a fallback. Code-derived design + delta-design templates are installed as the project template overrides (.appweaver/templates/overrides/) so a NEW feature is developed against the as-built architecture with NO adopt — every section derived from a NEUTRAL skeleton plus this repo's own structure, with no greenfield template in context. Where the lane exists, the SAME pair is generated for it (ui-design-template.md + ui-delta-design-template.md) from the UI source; ui-design-template.md is consumed by /appweaver adopt, which reverses a slice's design.ui.md from it wherever that slice owns part of the lane's surface; ui-delta-design-template.md is consumed by the frontend lane of /appweaver plan on its DELTA path, and the plan it produces is generated by the frontend lane of /appweaver implement. Develop an EXISTING feature just-in-time: /appweaver adopt <Feature> reverse-engineers its spec.md + design.md + source-map.md and completes that feature's OKF concept; its governance reconcile is currently HELD, so the scaffold this run wrote stays as it is. Develop a NEW feature straight through the forward pipeline (/appweaver specify → plan → implement). Then drive every change through the CR delta loop (/appweaver specify → plan → analyze-plan-delta → implement → build → analyze-slice-delta → finalize-delta → analyze-slice → close-delta). If a validation_ok is false, its constitution half needs a manual touch (see its Sync Impact Report)."
2213
+ next: "Onboarded bounded context {{bc}} ({{bc_feature_count}} feature(s): {{bc_features}}). Its aggregate concepts ({{bc_aggregates}}) are in {{bundle_dir}}, each keyed `bounded_context: {{bc}}` and listing the features that act on it — the bundle is the project's knowledge, one concept per aggregate, never one per feature — and its specs tree now exists at {{bc_dir}}/ with a directory per feature ({{feature_dirs}}) — EMPTY on purpose: the directory says the feature is known, and the documents that describe it are written per feature by /appweaver adopt and per context by /appweaver specify. {{bc}} is now the ACTIVE bounded context (.appweaver/context.json), so /appweaver select-feature lists exactly these features and nothing from a neighbouring context; switch with /appweaver select-bounded-context. ONBOARD RUNS ONCE PER CONTEXT: contexts already done — {{onboarded_contexts}}; still open — {{remaining_contexts}}; the order the map gives is {{contexts_ordered}}. Run /appweaver onboard <NextContext> for each remaining one, or with no argument to take the next one automatically. THE PROJECT TIER IS WRITTEN ONCE, BY THE FIRST CONTEXT (this run was first: {{is_first}}). That tier is the PROVISIONAL governance scaffold — the split constitution, the domain rule set at guardrails/projects/{{domain_slug}}/domain/*.domain.md + domain-rule-bindings.md, each declared LANE\'s rule set and constitution half, the activated domain {{active_domain}}, and the code-derived design / delta-design / domain-model template overrides in .appweaver/templates/overrides/. A later context does NOT re-author any of it: re-deriving project principles from one context\'s evidence is the scoping bias the governance tier exists to avoid. Amend it with /appweaver constitution. ONE HALF AND ONE RULE SET PER LANE: service_lane / ui_lane report which lanes .appweaver/stacks.json declared, and the declaration is what decided. A lane declared (none) in select-stack gets none of it, which is the correct outcome and not an omission. LANE DECLARATION: read, never written — select-stack is its sole writer, and this run scanned the source paths it named (scanned_service_root / scanned_ui_root); scanned_backend_files / scanned_ui_files report each. ui_source_evidence_found false means the UI lane\'s declared path held nothing a scan recognises as UI, so its governance is thin — move the source path with /appweaver select-stack and re-run. The build/test/run commands on each lane are that PROFILE\'s defaults and may not match a legacy layout — review them. Because the domain is activated, resolve-domain + resolve-tech route the WHOLE forward pipeline to these code-derived rules — never another project\'s rules as a fallback. THE BOUNDARIES CAME FROM THE MAP, not from this run: /appweaver inventory proposed them and you confirmed them in specs/proposed-inventory.md. To change a boundary, edit that file and run /appweaver inventory apply — a context whose concepts already exist is not re-onboarded. Develop an EXISTING feature just-in-time: /appweaver adopt <Feature> reverse-engineers its spec.md + design.md + source-map.md and deepens the OKF concept of the aggregate it acts on. Develop a NEW feature straight through the forward pipeline (/appweaver specify → plan → implement). Then drive every change through the CR delta loop (/appweaver specify → plan → analyze-plan-delta → implement → build → analyze-slice-delta → finalize-delta → analyze-slice → close-delta). If a validation_ok is false, its constitution half needs a manual touch (see its Sync Impact Report)."