aw-spec-cli 0.1.18 → 0.1.20

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 (77) hide show
  1. package/assets/.appweaver/DESIGN-FORMAT.md +63 -31
  2. package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +62 -14
  3. package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +10 -6
  4. package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +9 -1
  5. package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +21 -0
  6. package/assets/.appweaver/orchestrator/orchestrator.py +23 -1
  7. package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +1 -1
  8. package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +22 -13
  9. package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +1 -1
  10. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +6 -4
  11. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +399 -131
  12. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +1 -1
  13. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +199 -38
  14. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +1 -1
  15. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +159 -25
  16. package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +20 -9
  17. package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +1 -1
  18. package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +183 -40
  19. package/assets/.appweaver/orchestrator/workflows/aw-spec-deploy.orch.yaml +1 -1
  20. package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +311 -36
  21. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +221 -40
  22. package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +217 -174
  23. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +494 -109
  24. package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +1 -1
  25. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +83 -18
  26. package/assets/.appweaver/orchestrator/workflows/aw-spec-recall-delta.orch.yaml +319 -0
  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-specify.orch.yaml +143 -34
  30. package/assets/.appweaver/scripts/bash/aw-inventory.sh +15 -0
  31. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +878 -51
  32. package/assets/.appweaver/scripts/bash/aw-xref.sh +3 -0
  33. package/assets/.appweaver/scripts/bash/common.sh +28 -1
  34. package/assets/.appweaver/scripts/powershell/aw-inventory.ps1 +15 -0
  35. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +868 -51
  36. package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +3 -0
  37. package/assets/.appweaver/scripts/python/aw-inventory.py +1832 -65
  38. package/assets/.appweaver/scripts/python/aw-xref.py +500 -81
  39. package/assets/.appweaver/templates/delta-design-template.md +1 -1
  40. package/assets/.appweaver/templates/delta-domain-model-template.md +1 -1
  41. package/assets/.appweaver/templates/delta-spec-template.md +4 -3
  42. package/assets/.appweaver/templates/design-template.md +56 -40
  43. package/assets/.appweaver/templates/okf-concept-template.md +11 -1
  44. package/assets/.appweaver/templates/proposed-inventory-template.md +127 -0
  45. package/assets/.appweaver/templates/source-map-template.md +5 -3
  46. package/assets/.appweaver/templates/spec-template.md +24 -21
  47. package/assets/.appweaver/templates/ui-delta-design-template.md +1 -1
  48. package/assets/.appweaver/templates/ui-design-template.md +11 -7
  49. package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +4489 -361
  50. package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +2274 -125
  51. package/assets/guardrails/domain/healthcare/auditing.domain.md +3 -3
  52. package/assets/guardrails/domain/pharma/auditing.domain.md +3 -3
  53. package/assets/guardrails/technology/dotnet-webapi/api-versioning.md +1 -1
  54. package/assets/guardrails/technology/dotnet-webapi/auditing.md +1 -1
  55. package/assets/guardrails/technology/dotnet-webapi/authorization.md +1 -1
  56. package/assets/guardrails/technology/dotnet-webapi/clean-architecture.md +1 -1
  57. package/assets/guardrails/technology/dotnet-webapi/cqrs.md +1 -1
  58. package/assets/guardrails/technology/dotnet-webapi/data-classification.md +1 -1
  59. package/assets/guardrails/technology/dotnet-webapi/eventing.md +1 -1
  60. package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +1 -1
  61. package/assets/guardrails/technology/dotnet-webapi/modular-monolith.md +1 -1
  62. package/assets/guardrails/technology/dotnet-webapi/persistence.md +1 -1
  63. package/assets/guardrails/technology/dotnet-webapi/vertical-slices.md +1 -1
  64. package/assets/guardrails/technology/dotnet-webapi/zero-trust.md +1 -1
  65. package/assets/guardrails/technology/nextjs/accessibility-implementation.md +1 -1
  66. package/assets/guardrails/technology/nextjs/api-integration.dotnet-webapi.md +1 -1
  67. package/assets/guardrails/technology/nextjs/api-integration.java-spring.md +1 -1
  68. package/assets/guardrails/technology/nextjs/auth-session.md +1 -1
  69. package/assets/guardrails/technology/nextjs/component-architecture.md +1 -1
  70. package/assets/guardrails/technology/nextjs/design-system.md +1 -1
  71. package/assets/guardrails/technology/nextjs/error-handling.md +1 -1
  72. package/assets/guardrails/technology/nextjs/forms-and-validation.md +1 -1
  73. package/assets/guardrails/technology/nextjs/i18n.md +1 -1
  74. package/assets/guardrails/technology/nextjs/performance-budgets.md +1 -1
  75. package/assets/guardrails/technology/nextjs/routing-navigation.md +1 -1
  76. package/assets/guardrails/technology/nextjs/state-management.md +1 -1
  77. package/package.json +1 -1
@@ -1,8 +1,9 @@
1
1
  # =============================================================================
2
2
  # aw-spec-specify (orchestrator) — author the SPEC for the ACTIVE feature
3
3
  #
4
- # Spec-anchored pipeline, spec phase. feature = AGGREGATE (picked/created by
5
- # /appweaver select-feature, which sets .appweaver/feature.json). specify does
4
+ # Spec-anchored pipeline, spec phase. The feature is a capability scope the developer
5
+ # picked/created with /appweaver select-feature (.appweaver/feature.json); it may act on
6
+ # several aggregates, and several features may act on one. specify does
6
7
  # NOT guess or create the feature — it CONSUMES the active one, and is phase-pure
7
8
  # (spec side only; the single backend-plan.md is the `design` phase).
8
9
  #
@@ -15,7 +16,14 @@
15
16
  # assert different rules for it and nothing arbitrates. Authoring both here is also what
16
17
  # keeps the model in step with the spec version: it never waits for plan or implement.
17
18
  #
18
- # Auto-detects first-vs-subsequent from spec.md:
19
+ # Auto-detects first-vs-subsequent from feature-paths' needs_bootstrap — NOT from spec.md's
20
+ # presence. The two differ on one state and it is the one that corrupts: a first run that
21
+ # wrote spec.md and then died leaves the file on disk with the unfinished-bootstrap marker
22
+ # still up, and the file alone reads as a finished spec to EXTEND. version-init raises that
23
+ # marker (--bootstrap, which adopt must never pass — a finished reversal is not a crashed
24
+ # draft) and version-bootstrap-done lowers it AFTER the converge block, so the whole
25
+ # authoring window is recoverable. An interrupted draft ASKS before it is overwritten,
26
+ # because a deliberate stop and a crash look identical from here:
19
27
  # • BOOTSTRAP (no spec.md) → author the MASTER spec (US-1) + the context's MASTER
20
28
  # domain model + init active_version.json. On the context's second feature the model
21
29
  # already exists and gains a section rather than being replaced.
@@ -33,11 +41,12 @@
33
41
  # defaults a new delta to the wave already in flight (parallel by default); `cr-wave`
34
42
  # raises one that turns out to build on another.
35
43
  #
36
- # ⚠️ finalize-delta and close-delta still resolve "the" change through
37
- # active_version.json.active_change — the most recently opened. plan, analyze-plan-delta
38
- # and implement ASK which change and re-activate the answer, so the choice reaches those
39
- # two; threading an explicit --cr-id through the whole chain is the next step and is not
40
- # done yet.
44
+ # EVERY DELTA STAGE NOW ASKS WHICH CHANGE. plan, analyze-plan-delta, implement,
45
+ # recall-delta, finalize-delta and close-delta all list what is open, ask, and activate the
46
+ # answer, with a bare CR id as the argument doubling as the answer. None of them takes
47
+ # active_version.json's `active_change` on trust — which matters most here, because THIS
48
+ # phase overwrites that field on every run: a bare finalize used to merge whichever change
49
+ # was opened last, and `cr-setup` scaffolds a delta-spec stub the moment it opens one.
41
50
  #
42
51
  # Both paths then run ONE converge block — checklist + clarify + validate — over the
43
52
  # document THIS invocation authored, never the other one:
@@ -66,7 +75,7 @@
66
75
 
67
76
  name: aw-spec-specify
68
77
  description: Author the ACTIVE feature's specification AND its bounded context's domain model, together. The aggregate root, its entities, events and invariants (BR-n) live in specs/<Context>/domain-model.md — the one canonical definition every spec in the context cites by id and never restates. First call writes the master spec (US-1) plus the master model; a later call opens its OWN change (many may be open at once) and writes that change's delta-spec and delta-domain-model, leaving both masters untouched for finalize-delta to merge. Each change carries a WAVE — deltas sharing one are independent and developable in parallel, a higher wave is implemented after the lower ones land — and its model delta sits beside the master so every other open delta can see it while being authored. Spec phase only — plan/design is separate.
69
- version: 3.0.0
78
+ version: 3.5.0
70
79
  agent_agnostic: true
71
80
  dialect: aw-spec.orchestrator/v1
72
81
 
@@ -115,6 +124,19 @@ vars:
115
124
  # the checklist. NEVER hand-set to spec_file on the delta
116
125
  # path — that is what silently drifts an adopted spec.
117
126
  version: "" # current active_version.json version (for the report)
127
+ bootstrap_cleared: "false" # whether THIS run lowered the unfinished-first-draft marker
128
+ # THE BOOTSTRAP BRANCH AND ITS CRASH-RESUME. is_bootstrap is what every branch below
129
+ # reads; it starts from feature-paths' needs_bootstrap, which is `no spec.md` OR `a first
130
+ # draft is still marked unfinished`. The second half is the crash case, and it is the one
131
+ # that used to become a delta against a v1.0 nobody finished.
132
+ spec_exists: "false"
133
+ needs_bootstrap: "true" # defaulted to BOOTSTRAP: with no answer, authoring a first
134
+ # draft is recoverable, while extending a spec that may not
135
+ # exist is not
136
+ bootstrap_pending: "false"
137
+ is_bootstrap: "false"
138
+ resume_bootstrap: "false" # bootstrap_pending AND spec.md on disk ⇒ a draft was interrupted
139
+ resume_choice: ""
118
140
 
119
141
  workflow:
120
142
 
@@ -129,12 +151,20 @@ workflow:
129
151
  - { name: feature_dir, from: "$.feature_dir" }
130
152
  - { name: spec_file, from: "$.spec_file" }
131
153
  - { name: spec_exists, from: "$.spec_exists" }
154
+ # WHICH BRANCH THIS RUN TAKES. needs_bootstrap, not spec_exists — the two differ on
155
+ # exactly one state, and it is the one that corrupts: a FIRST run that wrote spec.md
156
+ # and then died leaves the file on disk with the unfinished-bootstrap marker still up,
157
+ # and branching on the file alone reads that as a finished spec to EXTEND. The next
158
+ # call then opens a change against a v1.0 nobody finished. feature-paths already
159
+ # computed this in both shells; nothing read it.
160
+ - { name: needs_bootstrap, from: "$.needs_bootstrap" }
161
+ - { name: bootstrap_pending, from: "$.bootstrap_pending" }
132
162
 
133
163
  - id: require_feature
134
164
  action: verify_context
135
165
  require_non_empty: feature_dir
136
166
  on_empty: stop
137
- on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the aggregate, e.g. Order), then re-run specify."
167
+ on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the feature, e.g. Order or PatientRegistration), then re-run specify."
138
168
 
139
169
  # 1b. Resolve the BOUNDED CONTEXT's domain model — the canonical home of the aggregate
140
170
  # root, its entities and its invariants, which this spec references and never
@@ -185,27 +215,78 @@ workflow:
185
215
  action: dispatch_hooks
186
216
  hooks_from_variable: before_hooks
187
217
 
188
- # ═══════════════════════ BOOTSTRAP — no spec.md yet ═══════════════════════
218
+ # ═══════════ WHICH BRANCH — and the one case where it is ASKED ═══════════
219
+ # is_bootstrap takes needs_bootstrap's answer. Two states reach it:
220
+ # no spec.md → an ordinary first run. Nothing is asked.
221
+ # spec.md + the marker still up → a first draft was INTERRUPTED. Re-authoring is
222
+ # the designed recovery, but it OVERWRITES what is
223
+ # on disk, and a deliberate stop is indistinguishable
224
+ # from a crash. So that case, and only that case,
225
+ # asks before it writes.
226
+ - id: branch_from_bootstrap
227
+ action: set
228
+ vars: { is_bootstrap: "{{needs_bootstrap}}" }
229
+
230
+ # The AND, as an ordered assignment (the engine has no compound conditions): under a
231
+ # raised marker, take spec.md's presence as the answer. A marker with no spec.md is a
232
+ # first run that died before writing anything — there is nothing to overwrite and
233
+ # nothing to ask.
234
+ - id: flag_resume
235
+ condition: "{{bootstrap_pending}} == true"
236
+ action: set
237
+ vars: { resume_bootstrap: "{{spec_exists}}" }
238
+
239
+ - id: ask_resume
240
+ condition: "{{resume_bootstrap}} == true"
241
+ action: ask
242
+ prompt: |
243
+ A FIRST DRAFT of this feature's spec.md was started and never finished — the
244
+ unfinished-bootstrap marker in active_version.json is still up, which means the last
245
+ run wrote the file and then stopped before completing it.
246
+
247
+ Re-author it (the draft is replaced from your input, and the domain model with it), or
248
+ treat what is on disk as the finished v1.0 and open a CHANGE against it instead?
249
+
250
+ Re-authoring OVERWRITES specs/…/spec.md. Treat-as-finished keeps it exactly as it is
251
+ and clears the marker, so this is asked once either way.
252
+ options: ["Re-author the first draft", "Treat it as finished"]
253
+ answer_var: resume_choice
254
+
255
+ # Taking it as finished is a decision about the DOCUMENT, so it clears the marker and
256
+ # hands the run to the delta path — the same path an ordinary later specify takes.
257
+ - id: accept_draft
258
+ condition: "{{resume_choice}} == Treat it as finished"
259
+ action: set
260
+ vars: { is_bootstrap: "false" }
261
+
262
+ - id: accept_draft_clear
263
+ condition: "{{resume_choice}} == Treat it as finished"
264
+ action: execute_script
265
+ script: { ref: actions }
266
+ subcommand: version-bootstrap-done
267
+ args: ["--feature-dir", "{{feature_dir}}"]
268
+
269
+ # ═══════════════════════ BOOTSTRAP — no finished spec.md yet ══════════════
189
270
  # Copy the spec template into the (already-existing) feature dir + init version.
190
271
  - id: boot_scaffold
191
- condition: "{{spec_exists}} == false"
272
+ condition: "{{is_bootstrap}} == true"
192
273
  action: execute_script
193
274
  script: { ref: actions }
194
275
  subcommand: scaffold
195
276
  args: ["--feature-dir", "{{feature_dir}}", "--allow-existing"]
196
277
 
197
278
  - id: boot_version_init
198
- condition: "{{spec_exists}} == false"
279
+ condition: "{{is_bootstrap}} == true"
199
280
  action: execute_script
200
281
  script: { ref: actions }
201
282
  subcommand: version-init
202
- args: ["--feature-dir", "{{feature_dir}}"]
283
+ args: ["--feature-dir", "{{feature_dir}}", "--bootstrap"]
203
284
 
204
285
  # Copy the domain-model template into the CONTEXT (not the feature) when the context
205
286
  # has no model yet. Idempotent and non-destructive: the second feature in a context
206
287
  # finds the model already there and adds its aggregate to it rather than replacing it.
207
288
  - id: boot_model_scaffold
208
- condition: "{{spec_exists}} == false"
289
+ condition: "{{is_bootstrap}} == true"
209
290
  action: execute_script
210
291
  script: { ref: actions }
211
292
  subcommand: model-scaffold
@@ -215,7 +296,7 @@ workflow:
215
296
  - { name: model_was_created, from: "$.created" }
216
297
 
217
298
  - id: boot_ctx
218
- condition: "{{spec_exists}} == false"
299
+ condition: "{{is_bootstrap}} == true"
219
300
  action: build_context
220
301
  context:
221
302
  - "{{spec_file}}" # the copied template = section structure
@@ -241,17 +322,21 @@ workflow:
241
322
  # no file and no ux/ rules mapped, the section resolves to
242
323
  # "None" and the spec is unchanged from a backend-only one.
243
324
  - id: boot_generate
244
- condition: "{{spec_exists}} == false"
325
+ condition: "{{is_bootstrap}} == true"
245
326
  action: agent_author
246
327
  output_target: { type: file, path: "{{spec_file}}" }
247
328
  task: |
248
- Author the MASTER specification for this aggregate by filling out the
329
+ Author the MASTER specification for the feature `{{feature}}` by filling out the
249
330
  template in context. This is the first user story, US-1. Base everything on:
250
331
 
251
332
  {{USER_INPUT}}
252
333
 
253
334
  Rules for the content you generate:
254
- - The feature IS the aggregate slice; set the Aggregate field and keep US-1's id.
335
+ - The feature is a CAPABILITY SCOPE the developer chose; set the Feature field to
336
+ `{{feature}}` and keep US-1's id. It may act on several aggregates, and other
337
+ features may act on the same ones: name every aggregate its requirements act on
338
+ in the Domain Model Reference's `**Acts on aggregate(s)**:` line, each in
339
+ backticks — every later command finds this feature's part of the model there.
255
340
  - Preserve the template's section order and headings.
256
341
  - SPECIFY IS THE ONLY PHASE THAT READS THE DOMAIN RULES. Design and implement
257
342
  work from the spec + the domain model, never the domain docs — so this pair is
@@ -334,7 +419,7 @@ workflow:
334
419
  # which a frontend-only project has as much as any other; where an invariant is
335
420
  # ENFORCED is a plan concern and is recorded in backend-plan.md.
336
421
  - id: boot_model_ctx
337
- condition: "{{spec_exists}} == false"
422
+ condition: "{{is_bootstrap}} == true"
338
423
  action: build_context
339
424
  context:
340
425
  - "{{domain_model}}" # the model (template on a first feature, populated on a later one)
@@ -343,7 +428,7 @@ workflow:
343
428
  - { path: .appweaver/memory/constitution.ui.md, optional: true }
344
429
 
345
430
  - id: boot_model_generate
346
- condition: "{{spec_exists}} == false"
431
+ condition: "{{is_bootstrap}} == true"
347
432
  action: agent_author
348
433
  output_target: { type: file, path: "{{domain_model}}" }
349
434
  task: |
@@ -356,11 +441,14 @@ workflow:
356
441
  section per root: its boundary (owns / references by id / out of scope), entities,
357
442
  value objects, domain events, and its invariants as stable BR-nnn ids. The spec
358
443
  cites those ids; this document defines them.
359
- - IF THE MODEL ALREADY HAS CONTENT, this is the context's SECOND (or later) feature.
360
- ADD this feature's aggregate as a new section and EXTEND the ubiquitous language.
361
- Do NOT rewrite, renumber or "tidy" the aggregates already there — other specs cite
362
- their ids, and a renumbered BR breaks every citation silently. Add `{{feature}}` to
363
- the `Serving specs` line of any existing aggregate this feature also acts on.
444
+ - IF THE MODEL ALREADY HAS CONTENT, this is the context's SECOND (or later) feature,
445
+ and the aggregates it acts on may already be there. An aggregate that already has
446
+ a section is EXTENDED in place — add what this feature's requirements need, and add
447
+ `{{feature}}` to its `Serving specs` line — never duplicated, and never given a
448
+ second section named after the feature. Only an aggregate the model does not have
449
+ yet gets a new section. EXTEND the ubiquitous language. Do NOT rewrite, renumber
450
+ or "tidy" what is already there — other specs cite those ids, and a renumbered BR
451
+ breaks every citation silently.
364
452
  - DDD IS THE RATIFIED MODELLING STANDARD (NON-NEGOTIABLE → the modelling-methodology
365
453
  standard in the sticky standards, wired per-project via tech-rule-bindings
366
454
  "## /aw-spec-specify", plus the domain's own DDD overlay): a consistent ubiquitous
@@ -379,15 +467,18 @@ workflow:
379
467
 
380
468
  # ═════════════════════════ DELTA — spec.md exists ═════════════════════════
381
469
  # A later requirement = a new user story on the SAME aggregate. Delegate to the
382
- # delta-spec module: it opens the change (cr-setup, single-active-change guarded) and
383
- # authors the delta-spec ONLY — the master spec.md is left UNTOUCHED. The change
384
- # stays OPEN; finalize-delta merges the delta into spec.md later in the chain. Runs in
385
- # this context (shares vars + the DDD + domain sticky standards). The former standalone
386
- # `cr` capture's spec half now lives here. Downstream: plan (the delta plans) →
470
+ # delta-spec module: it opens the change (cr-setup) and authors BOTH of the change's
471
+ # halves — the delta-spec under changes/<cr-id>/ and the model delta beside the context's
472
+ # master model — leaving the master spec.md and domain-model.md UNTOUCHED. MANY changes
473
+ # may be open at once: every call on an established feature opens its own, the wave is
474
+ # what orders them, and the single-active-change guard that used to refuse a second one
475
+ # is gone. The change stays OPEN; finalize-delta merges both halves later in the chain.
476
+ # Runs in this context (shares vars + the DDD + domain sticky standards). The former
477
+ # standalone `cr` capture's spec half now lives here. Downstream: plan (the delta plans) →
387
478
  # analyze-plan-delta → implement → build → analyze-slice-delta → finalize-delta → analyze-slice →
388
479
  # close-delta (close-delta is what finally archives the change and bumps the version).
389
480
  - id: delta_spec_module
390
- condition: "{{spec_exists}} == true"
481
+ condition: "{{is_bootstrap}} == false"
391
482
  action: include
392
483
  module: .appweaver/orchestrator/modules/delta-spec.orch.yaml
393
484
 
@@ -404,7 +495,7 @@ workflow:
404
495
  # content; note it rewrites the file, so it is deliberately scoped to the path that
405
496
  # authored the document (a delta run no longer resets the master's scored boxes).
406
497
  - id: create_checklist
407
- condition: "{{spec_exists}} == false"
498
+ condition: "{{is_bootstrap}} == true"
408
499
  action: execute_script
409
500
  script: { ref: actions }
410
501
  subcommand: create-checklist
@@ -418,7 +509,7 @@ workflow:
418
509
  # checklist's items assume a full spec and would mis-fire here, which is exactly why
419
510
  # this is a separate checklist rather than the same one re-pointed.
420
511
  - id: create_delta_checklist
421
- condition: "{{spec_exists}} == true"
512
+ condition: "{{is_bootstrap}} == false"
422
513
  action: execute_script
423
514
  script: { ref: actions }
424
515
  subcommand: create-checklist
@@ -526,6 +617,24 @@ workflow:
526
617
  outputs:
527
618
  - { name: checklist_passed, from: "$.after_checked" }
528
619
 
620
+ # 7b. THE FIRST DRAFT IS FINISHED — lower the marker. Placed HERE, after the converge
621
+ # block, because that is the last thing the bootstrap path does to the document: a
622
+ # run that died inside the checklist or the clarify loop left a spec.md that is
623
+ # present but not yet what it will be, and clearing earlier would certify exactly the
624
+ # half-written state the marker exists to catch. Everything between version-init
625
+ # --bootstrap and this step is the window a crash is recoverable in.
626
+ #
627
+ # Idempotent: clearing a marker that is already down is the ordinary outcome of a
628
+ # re-run and is not an error, so this needs no guard beyond the branch.
629
+ - id: boot_done
630
+ condition: "{{is_bootstrap}} == true"
631
+ action: execute_script
632
+ script: { ref: actions }
633
+ subcommand: version-bootstrap-done
634
+ args: ["--feature-dir", "{{feature_dir}}"]
635
+ outputs:
636
+ - { name: bootstrap_cleared, from: "$.cleared" }
637
+
529
638
  # 8. Read the current version for the report (both paths).
530
639
  - id: version_read
531
640
  action: execute_script
@@ -11,6 +11,21 @@
11
11
  # [--service-root <p>] [--ui-root <p>] (the declared lane paths:
12
12
  # backend signals come from outside the UI subtree, frontend
13
13
  # signals from inside it, so neither carries the other's files)
14
+ # aw-inventory.sh propose [--root <dir>] [--service-root <p>] [--ui-root <p>]
15
+ # [--strategy structure|reference|persistence] [--out <md>] [--map <json>]
16
+ # (Pass A+B+C: writes the editable specs/proposed-inventory.md
17
+ # and the machine map onboard reads)
18
+ # aw-inventory.sh apply [--root <dir>] [--proposal <md>] [--map <json>]
19
+ # (validates the operator's edits to the proposal and
20
+ # regenerates the machine map; reports the row it cannot resolve)
21
+ # aw-inventory.sh scaffold-context --context <Name> [--root <dir>] [--map <json>]
22
+ # (creates specs/<Context>/<Feature>/ for every feature the map
23
+ # assigns to that context — directories only, no documents)
24
+ # aw-inventory.sh concept --bundle <dir> --aggregate <Name>
25
+ # aw-inventory.sh list-aggregates --bundle <dir> [--context <Name>] [--root <dir>] [--map <json>]
26
+ # (--context drops concepts stamped with a DIFFERENT bounded
27
+ # context; unstamped concepts are always kept. `pickable` offers
28
+ # each concept as the features the map puts on it)
14
29
  # aw-inventory.sh validate --bundle <dir> [--repo-root <dir>]
15
30
  set -euo pipefail
16
31
  DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"