aw-spec-cli 0.1.18 → 0.1.19

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 (53) hide show
  1. package/assets/.appweaver/DESIGN-FORMAT.md +45 -21
  2. package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +62 -14
  3. package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +6 -4
  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/design-template.skeleton.md +18 -11
  8. package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +5 -3
  9. package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +298 -109
  10. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +161 -34
  11. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +125 -24
  12. package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +18 -7
  13. package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +182 -39
  14. package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +300 -35
  15. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +190 -31
  16. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +93 -8
  17. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +34 -7
  18. package/assets/.appweaver/orchestrator/workflows/aw-spec-recall-delta.orch.yaml +319 -0
  19. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +125 -24
  20. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +846 -35
  21. package/assets/.appweaver/scripts/bash/common.sh +28 -1
  22. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +843 -46
  23. package/assets/.appweaver/scripts/python/aw-inventory.py +3 -2
  24. package/assets/.appweaver/templates/design-template.md +41 -30
  25. package/assets/.appweaver/templates/spec-template.md +7 -4
  26. package/assets/.appweaver/templates/ui-design-template.md +7 -3
  27. package/assets/guardrails/domain/healthcare/auditing.domain.md +3 -3
  28. package/assets/guardrails/domain/pharma/auditing.domain.md +3 -3
  29. package/assets/guardrails/technology/dotnet-webapi/api-versioning.md +1 -1
  30. package/assets/guardrails/technology/dotnet-webapi/auditing.md +1 -1
  31. package/assets/guardrails/technology/dotnet-webapi/authorization.md +1 -1
  32. package/assets/guardrails/technology/dotnet-webapi/clean-architecture.md +1 -1
  33. package/assets/guardrails/technology/dotnet-webapi/cqrs.md +1 -1
  34. package/assets/guardrails/technology/dotnet-webapi/data-classification.md +1 -1
  35. package/assets/guardrails/technology/dotnet-webapi/eventing.md +1 -1
  36. package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +1 -1
  37. package/assets/guardrails/technology/dotnet-webapi/modular-monolith.md +1 -1
  38. package/assets/guardrails/technology/dotnet-webapi/persistence.md +1 -1
  39. package/assets/guardrails/technology/dotnet-webapi/vertical-slices.md +1 -1
  40. package/assets/guardrails/technology/dotnet-webapi/zero-trust.md +1 -1
  41. package/assets/guardrails/technology/nextjs/accessibility-implementation.md +1 -1
  42. package/assets/guardrails/technology/nextjs/api-integration.dotnet-webapi.md +1 -1
  43. package/assets/guardrails/technology/nextjs/api-integration.java-spring.md +1 -1
  44. package/assets/guardrails/technology/nextjs/auth-session.md +1 -1
  45. package/assets/guardrails/technology/nextjs/component-architecture.md +1 -1
  46. package/assets/guardrails/technology/nextjs/design-system.md +1 -1
  47. package/assets/guardrails/technology/nextjs/error-handling.md +1 -1
  48. package/assets/guardrails/technology/nextjs/forms-and-validation.md +1 -1
  49. package/assets/guardrails/technology/nextjs/i18n.md +1 -1
  50. package/assets/guardrails/technology/nextjs/performance-budgets.md +1 -1
  51. package/assets/guardrails/technology/nextjs/routing-navigation.md +1 -1
  52. package/assets/guardrails/technology/nextjs/state-management.md +1 -1
  53. package/package.json +1 -1
@@ -8,21 +8,32 @@ design document — not the engine. The authoring template is
8
8
 
9
9
  ## The contract
10
10
 
11
- A feature's design is **one document**, living beside its spec:
11
+ A feature's design is **one document**, living beside its spec — and the domain it
12
+ elaborates lives one level up, at the bounded context:
12
13
 
13
14
  ```
14
- specs/<Aggregate>/
15
- spec.md # behaviour (tech-agnostic) — WHAT / WHY — the source of truth
16
- backend-plan.md # structure & decisions (tech-agnostic HLD) — the MEDIATOR
17
- changes/ # open + archived change records (delta-spec + delta-design)
15
+ specs/<Context>/
16
+ domain-model.md # STRUCTURE — aggregates, entities, invariants (BR-nnn) — shared
17
+ <Aggregate>/
18
+ spec.md # BEHAVIOUR (tech-agnostic) — WHAT / WHY
19
+ backend-plan.md # structure & decisions (tech-agnostic HLD) — the MEDIATOR
20
+ changes/ # open + archived change records (delta-spec + delta plans)
18
21
  ```
19
22
 
20
- `backend-plan.md` is the **mediator** between the spec and the generated code:
23
+ **TWO AUTHORITIES, NOT ONE.** `domain-model.md` is the canonical definition of what the
24
+ domain *is*; `spec.md` is the canonical definition of what the system must *do*. They are
25
+ separate files because several specs in a context act on one aggregate, so a per-spec copy
26
+ of an invariant drifts. The spec cites invariants by id (`BR-nnn`) and never restates them.
27
+
28
+ `backend-plan.md` is the **mediator** between those two and the generated code:
21
29
 
22
30
  ```
23
- spec.md ──▶ backend-plan.md ──▶ code (+ tests)
24
- behaviour structure & generated by `implement`
25
- FR/BR/US/SC decisions (HLD) (stack bound at generation time)
31
+ domain-model.md ─┐
32
+ structure ├─▶ backend-plan.md ──▶ code (+ tests)
33
+ BR-nnn │ structure & generated by `implement`
34
+ spec.md ──┘ decisions (HLD) (stack bound at generation time)
35
+ behaviour
36
+ FR/US/SC/CN/DC/IC
26
37
  ```
27
38
 
28
39
  - **One design per aggregate.** The four clean-architecture layers (Domain,
@@ -34,8 +45,10 @@ FR/BR/US/SC decisions (HLD) (stack bound at generation time)
34
45
  **signatures + pre/post/invariant/raises**, use-cases, endpoint contracts, ports,
35
46
  and the significant technical decisions with rationale — but **no complete method
36
47
  bodies**. See `design-template.md` for the section structure (§0–§9). The domain
37
- layer (§1) follows spec.md exactly — its entities/value-objects are the spec's Key
38
- Entities and its invariants are the spec's Business Rules.
48
+ layer (§1) follows the context's `domain-model.md` exactly — its entities and
49
+ value-objects carry the model's names, its aggregate boundary is the model's Boundary
50
+ block, and its invariants **cite** the model's `BR-nnn` rather than restating them.
51
+ Behaviour comes from the spec, structure from the model.
39
52
  - **Technology-agnostic.** Behaviour and contracts use conceptual types, never a
40
53
  language. The SAME backend-plan.md must be generatable on a different stack. The target
41
54
  language/framework/persistence is bound only at `implement` time from the
@@ -145,12 +158,15 @@ The design document and the code are **not** a byte-for-byte copy of each other.
145
158
  ## The traceability spine
146
159
 
147
160
  ```
148
- FR/BR/US/SC ↔ design section (element / decision) ↔ code (+ tests) ↔ commit
161
+ FR/US/SC/CN/DC/IC (spec) ↔ design section (element / decision) ↔ code (+ tests) ↔ commit
162
+ BR-nnn (domain model) ↗
149
163
  ```
150
164
 
151
- Every design element traces **up** to a spec id, and the whole spec traces **down**
152
- into a design section (§6 Traceability). This is what makes the analyze gate and the
153
- review able to check coverage, and what keeps CR impact analysis exact.
165
+ Every design element traces **up** to an id, and the whole spec traces **down** into a
166
+ design section (§6 Traceability). The ids come from the two authorities: behaviour ids
167
+ from `spec.md`, invariant ids (`BR-nnn`) from the context's `domain-model.md`. An element
168
+ that traces to neither is an invention and the analyze gate raises it. This is what makes
169
+ the gate and the review able to check coverage, and what keeps CR impact analysis exact.
154
170
 
155
171
  ## Feature granularity (why a command is a delta, not a new feature)
156
172
 
@@ -161,12 +177,20 @@ with a shared entity, **feature = the aggregate** (`Order`), and individual comm
161
177
  (`CreateOrder`, `UpdateOrder`, …) are **user stories / deltas** on the same backend-plan.md:
162
178
 
163
179
  - `CreateOrder` = US-1; `UpdateOrder` = US-2.
164
- - Adding `UpdateOrder` is an additive CR: a Delta Spec (`+US-2`) and a Delta Design
165
- (`ADDED` new use-case/endpoint sections, `MODIFIED` the shared Order/root and
166
- repository sections — see `delta-design-template.md`). The design phase amends
167
- backend-plan.md doc-first, bumps the feature version (`v1.0 → v1.1`), and archives the CR;
168
- `implement` regenerates the touched slice; regression re-tests the shared-file
169
- dependents.
180
+ - Adding `UpdateOrder` is an additive CR: a **delta-spec** (`+US-2`), the change's own
181
+ **model delta** where the domain moves, and **delta lane plans** (`ADDED` new
182
+ use-case/endpoint sections, `MODIFIED` the shared Order/root and repository sections —
183
+ see `delta-design-template.md`). All three live inside `changes/<CR-id>/`, and the
184
+ MASTERS are not touched while the change is open: `plan` writes
185
+ `delta-backend-plan.md` / `delta-frontend-plan.md` beside the delta-spec, never
186
+ `backend-plan.md`. `implement` generates only what the delta marks ADDED or MODIFIED;
187
+ regression re-tests the shared-file dependents.
188
+ - **Nothing in the plan phase bumps a version or archives a change.** `finalize-delta`
189
+ MERGES the delta into `spec.md` and the context's `domain-model.md` (not the lane
190
+ plans — they are derived from those two and are re-derived by `/appweaver plan main`),
191
+ and `close-delta` is the sole stage that archives `changes/<CR-id>/` and moves the
192
+ version (`v1.0 → v1.1`). The two are deliberately separate so a red `analyze-slice`
193
+ between them is still "fix and re-run" rather than a change that already shipped.
170
194
 
171
195
  Two command-level features would both claim `src/Domain/Order.cs` and collide —
172
196
  which is exactly why the aggregate is the boundary.
@@ -28,6 +28,12 @@
28
28
  # wave means "after those land". So a lower-wave delta is committed to landing first
29
29
  # and may be built on; a same-wave one is visible but is never assumed, because
30
30
  # nothing orders the two against each other.
31
+ # • the SIBLING deltas — every open model delta at the SAME or a higher wave. VISIBLE
32
+ # is the operative word and the reason they are in context at all: this module tells
33
+ # the planner to name any sibling touching the same aggregate or component, and a
34
+ # planner that was never shown them can only stay silent — which the gate one stage
35
+ # later reads as a missed overlap. Their model deltas only, since the aggregate a
36
+ # sibling touches is what makes it an overlap.
31
37
  #
32
38
  # IT READS THE CODE. The feature's real source files arrive from its OKF concept
33
39
  # (concept-paths, resolved by the caller) as a PATH LIST, and the authoring steps declare
@@ -39,7 +45,8 @@
39
45
  # EXPECTS caller vars: feature_dir, spec_file, backend_plan, frontend_plan, domain_model,
40
46
  # be_existing, fe_existing, fe_lane_id, source_files, source_count, USER_INPUT,
41
47
  # and — resolved by the caller from the change it chose and activated — cr_id, cr_dir,
42
- # delta_spec, delta_model, wave, predecessor_files, predecessor_count, sibling_count.
48
+ # delta_spec, delta_model, wave, predecessor_files, predecessor_count, predecessor_ids,
49
+ # sibling_count, sibling_ids, related_docs.
43
50
  # PRODUCES: delta_backend_plan, delta_frontend_plan, downstream_count, impact_report.
44
51
  # =============================================================================
45
52
 
@@ -66,7 +73,13 @@ vars:
66
73
  wave: "1"
67
74
  predecessor_files: [] # every open model delta in a LOWER wave — this delta's predecessors
68
75
  predecessor_count: "0"
76
+ predecessor_ids: ""
69
77
  sibling_count: "0"
78
+ sibling_ids: ""
79
+ # What actually goes into the authoring context: the predecessors' two halves AND the
80
+ # siblings' model deltas. Both kinds are SHOWN; the prompts say which ids carry which
81
+ # licence, because a planner asked to name an overlap has to be able to see one.
82
+ related_docs: []
70
83
  delta_backend_plan: ""
71
84
  delta_frontend_plan: ""
72
85
 
@@ -97,9 +110,13 @@ workflow:
97
110
  - id: ctx_backend_delta
98
111
  condition: "{{be_existing}} == true"
99
112
  action: build_context
100
- context_from: predecessor_files # the open model deltas in LOWER waves — committed
101
- # to landing first, so this plan may build on them.
102
- # Empty for a wave-1 delta, which is the common case.
113
+ context_from: related_docs # every other open change's model delta, plus each
114
+ # PREDECESSOR's delta-spec. Two kinds, opposite
115
+ # licence: a LOWER-wave predecessor is committed to
116
+ # landing first and may be built on; a SAME-wave
117
+ # sibling may only be designed around. The prompt
118
+ # names which ids are which. Empty when this is the
119
+ # only open change, the common case.
103
120
  context:
104
121
  - "{{delta_backend_plan}}" # the delta plan template to fill
105
122
  - "{{delta_spec}}" # the spec-side change (from specify)
@@ -144,11 +161,17 @@ workflow:
144
161
  invariant is ENFORCED. Cite ids; never restate what an invariant says. An item in
145
162
  the model delta with no row here is a structural change nothing implements.
146
163
  - THE EFFECTIVE MODEL IS master + this change's delta + the PREDECESSOR deltas in
147
- context (open changes in a LOWER wave, committed to landing first). You MAY build
148
- on a predecessor — record it under "## Depends on", which is what orders the
149
- finalizes. You may NOT assume a same-wave delta: nothing orders it against this
150
- one. Where one touches the same aggregate or element, say so under "Other open
151
- deltas" and plan around it. Until merged, every one of them is a proposal.
164
+ context. {{predecessor_count}} predecessor(s) — open changes in a LOWER wave,
165
+ committed to landing first: {{predecessor_ids}}. You MAY build on one; record it
166
+ under "## Depends on", which is what orders the finalizes.
167
+ - {{sibling_count}} SIBLING change(s) are open at the same or a higher wave:
168
+ {{sibling_ids}}. Their model deltas are in context too, and the licence over them
169
+ is the opposite one — nothing orders them against this change, so you may NOT
170
+ assume any of them lands. Read each one and, where it touches an aggregate or an
171
+ element this plan also touches, say so by id under "Other open deltas" and plan so
172
+ that either order of merging works. If consuming one is genuinely unavoidable,
173
+ that is a dependency, not an overlap: record it under "## Depends on" and say the
174
+ wave must be raised. Until merged, every one of them is a proposal.
152
175
  - PUBLISH WHAT THE FRONTEND LANE NEEDS. Fill "## Contract deltas for the frontend
153
176
  lane" with every addition or change to this feature's published surface, as field
154
177
  shapes. That table is the only part of this document the frontend delta plan may
@@ -168,12 +191,33 @@ workflow:
168
191
  stamp those.
169
192
  Guidance: {{USER_INPUT}}
170
193
 
194
+ # ══════════ THE LANE SWAP — the frontend's rules replace the backend's ═══════
195
+ # The delta twin of the swap `plan` performs before its own master frontend sections.
196
+ # Sticky standards only accumulate, and the caller loaded BOTH lanes' rule sets before
197
+ # including this module, so without this the service delta plan is authored with the UI
198
+ # rules in its envelope and the experience delta plan with the service rules. `replace`
199
+ # resets to the workflow's declared seed and loads `## /aw-spec-plan-ui`, so the backend
200
+ # delta above kept the service set and everything below this line is the frontend's.
201
+ #
202
+ # Conditioned on the same flag as the lane it precedes: a change with no frontend half
203
+ # authors nothing here and must not have its envelope swapped out from under the
204
+ # xref step that follows.
205
+ - id: tech_select_ui_delta
206
+ condition: "{{fe_existing}} == true"
207
+ action: include
208
+ module: .appweaver/orchestrator/modules/tech-select.orch.yaml
209
+ with: { command: aw-spec-plan-ui, replace: "true" }
210
+
171
211
  # ═════════════════════ FRONTEND LANE — the experience delta plan ═════════════
172
212
  - id: ctx_frontend_delta
173
213
  condition: "{{fe_existing}} == true"
174
214
  action: build_context
175
- context_from: predecessor_files # the same lower-wave model deltas — the ubiquitous
176
- # language and the aggregates this change assumes
215
+ context_from: related_docs # the same two kinds as the service lane: lower-wave
216
+ # predecessors (the ubiquitous language and the
217
+ # aggregates this change may assume) and same-wave
218
+ # siblings (visible, never assumed — this lane shares
219
+ # screens and components, so an unseen sibling is an
220
+ # unseen collision). The prompt names which is which.
177
221
  context:
178
222
  - "{{delta_frontend_plan}}" # the delta plan template to fill
179
223
  - "{{delta_spec}}" # the spec-side change (UX-/US-/FR- items)
@@ -225,9 +269,13 @@ workflow:
225
269
  labels, states and messages — the same terms, no synonyms — and cite BR-nnn rather
226
270
  than restating a rule.
227
271
  - THE EFFECTIVE MODEL IS master + this change's delta + the PREDECESSOR deltas in
228
- context (open changes in a LOWER wave). You MAY build on a predecessor — record it
229
- under "## Depends on". You may NOT assume a same-wave delta; where one touches the
230
- same screens or shared components, say so under "Other open deltas".
272
+ context. {{predecessor_count}} predecessor(s) — open changes in a LOWER wave:
273
+ {{predecessor_ids}}. You MAY build on one; record it under "## Depends on".
274
+ - {{sibling_count}} SIBLING change(s) are open at the same or a higher wave:
275
+ {{sibling_ids}}. Their model deltas are in context and nothing orders them against
276
+ this change, so you may NOT assume any of them lands. Where one touches the same
277
+ screens, shared components or contract surface, say so by id under "Other open
278
+ deltas" and plan so that either order of merging works.
231
279
  - TECHNOLOGY-AGNOSTIC: no framework, router, state library, component library or
232
280
  styling approach — responsibilities, field shapes, events and states only. The
233
281
  header's Lane field is `{{fe_lane_id}}`.
@@ -48,10 +48,12 @@ scripts:
48
48
 
49
49
  workflow:
50
50
 
51
- # Open the change + scaffold its THREE documents: delta-spec and delta-design under
52
- # changes/<cr-id>/, and the model delta BESIDE the context's master model. Many
53
- # changes may be open at once — every specify call on an established feature opens
54
- # its own, and the wave is what orders them.
51
+ # Open the change + scaffold its TWO documents: the delta-spec under changes/<cr-id>/,
52
+ # and the model delta BESIDE the context's master model. The delta PLANS are not
53
+ # scaffolded here — `plan` owns them and creates them with delta-plan-scaffold when it
54
+ # is run for this change, because a change that is never planned should not leave empty
55
+ # plan files behind. Many changes may be open at once — every specify call on an
56
+ # established feature opens its own, and the wave is what orders them.
55
57
  - id: cr_setup
56
58
  action: execute_script
57
59
  script: { ref: actions }
@@ -22,7 +22,15 @@
22
22
  # never asked about a UI lane it declined.
23
23
  #
24
24
  # Inputs (via include `with`):
25
- # require — the lane kind this phase cannot run without: backend | frontend
25
+ # require — the lane kind this phase cannot run without: backend | frontend, or an
26
+ # EMPTY string for "any lane will do". Empty is what a phase passes when it
27
+ # needs a declaration to work from but no particular kind of one — `build`
28
+ # compiles every declared lane, so a frontend-only project is as buildable
29
+ # as a backend-only one. It narrows nothing else: no lane declared at all, a
30
+ # lane with no source path, a source path that is not on disk and two lanes
31
+ # claiming overlapping subtrees all still stop the run. The required kind's
32
+ # fields below then bind from the backend block, which an empty-require
33
+ # caller reads none of.
26
34
  # command — the phase being gated, quoted back in the failure message
27
35
  #
28
36
  # Produces, for the required kind: WHERE it lives (lane_root / lane_source_path),
@@ -110,6 +110,27 @@ workflow:
110
110
  multi: true
111
111
  answer_var: tg_subset
112
112
 
113
+ # 2b. SWAP, don't stack — `replace` (passed by the caller through `with:`).
114
+ #
115
+ # A phase that generates for two lanes includes this module twice, and standards only
116
+ # ever ACCUMULATE: the second lane inherited the first's rule set, so a full-stack run
117
+ # showed the frontend generator the service rules and the backend generator the UI
118
+ # rules, and each prompt had to argue against its own envelope. The caller's FIRST
119
+ # include leaves `replace` unset — that lane's rules simply join the declared seed —
120
+ # and the second passes replace: "true" immediately before its own lane's steps.
121
+ #
122
+ # IT IS ITS OWN STEP, not a flag on the loads below, because the loads are conditional
123
+ # and the reset must not be. A lane whose map resolves nothing fires NO load step at all
124
+ # (no map ⇒ no candidates ⇒ the selection box never runs), and on that path a flag
125
+ # attached to the loads would leave the OTHER lane's rules standing — "no rules
126
+ # configured for this lane" silently meaning "keep the other lane's", which is the exact
127
+ # confusion this exists to remove. load_standards with no files is a pure reset.
128
+ - id: swap_lane_rules
129
+ action: load_standards
130
+ condition: "{{replace}} == true"
131
+ files: []
132
+ replace: "true"
133
+
113
134
  # 3. Load the selection into the sticky standards set (system block, D3).
114
135
  - id: load_all
115
136
  action: load_standards
@@ -183,6 +183,14 @@ class Orchestrator:
183
183
  # system prefix stays byte-stable across steps (prompt-cache lever)
184
184
  # while build_context keeps declaring only the per-request delta.
185
185
  self.standards = list(wf.get("standards", []) or [])
186
+ # The workflow's DECLARED seed, kept apart from what steps load later. A phase
187
+ # that generates for two lanes needs each lane's rule set and NOT the other's,
188
+ # but standards only ever accumulate — so the second lane inherited the first's
189
+ # rules and both prompts had to argue their way out of an envelope that
190
+ # contradicted them. `load_standards: replace` resets to this seed and then
191
+ # appends, which swaps the lane rules while leaving the always-on set (ai-rules
192
+ # and anything else the workflow declared up front) exactly where it was.
193
+ self.standards_seed = list(self.standards)
186
194
  # F1: top-level scripts ref map {ref: {sh: path, ps1: path}} (decl shape)
187
195
  self.scripts = dict(wf.get("scripts", {}) or {})
188
196
  # every file that has entered any payload (verify_context required_files)
@@ -960,8 +968,22 @@ class Orchestrator:
960
968
  def act_load_standards(self, step):
961
969
  """F4 — append files to the sticky standards set (dedup; `optional:`
962
970
  tolerated). _assemble_system prepends the set to EVERY payload, so a
963
- skill loads its standards once (decl load_context → system per D3)."""
971
+ skill loads its standards once (decl load_context → system per D3).
972
+
973
+ `replace: true` first resets the set to the workflow's DECLARED seed,
974
+ dropping everything steps have loaded since. That is how a phase serving
975
+ two lanes gives each one its own rule set instead of the union: the
976
+ second lane replaces the first's rules rather than stacking on them.
977
+ The seed survives, so the always-on standards are never dropped."""
964
978
  p = step.get("parameters") or step
979
+ # Through _cond, so a rendered "{{flag}}" that resolves to "false" is FALSE.
980
+ # Plain truthiness would read that non-empty string as true and silently drop
981
+ # every loaded standard on the path meant to keep them.
982
+ if self._cond(str(p.get("replace", ""))):
983
+ dropped = len(self.standards) - len(self.standards_seed)
984
+ self.standards = list(self.standards_seed)
985
+ self.emit(f"[load_standards] replace — reset to the declared seed "
986
+ f"({len(self.standards_seed)} file(s), {max(dropped, 0)} dropped)")
965
987
  files = p.get("files") or []
966
988
  if p.get("files_from_variable"):
967
989
  files = [{"path": x} for x in (self.vars.get(p["files_from_variable"]) or [])]
@@ -71,12 +71,16 @@
71
71
  contracts, behaviour and decisions; it is not code.
72
72
 
73
73
  ANCHORING RULES
74
- - Every design element traces UP to a spec id (FR-/BR-/CN-/DC-/IC-/US-/SC-)
75
- and the whole spec is covered DOWN here (§4). No element without a spec
76
- reason; no requirement without a design home.
77
- - THE SPEC IS THE ONLY DOMAIN INPUT. Design reads the spec + the technical
78
- standards, never the domain rule files. A domain rule the spec omits is
79
- recorded as a §5 assumption, never smuggled in.
74
+ - Every design element traces UP to an id (FR-/BR-/CN-/DC-/IC-/US-/SC-) and the
75
+ whole spec is covered DOWN here (§4). No element without a reason in an
76
+ authority; no requirement without a design home.
77
+ - THE AUTHORITIES ARE THE SPEC AND, WHERE THE CONTEXT HAS ONE, ITS
78
+ domain-model.md — never the domain rule files. The spec is always the
79
+ behaviour authority. Where specs/[Context]/domain-model.md exists it is the
80
+ STRUCTURE authority and outranks the spec on entities, value objects, the
81
+ aggregate boundary and the BR-nnn invariants; where it does not, the spec
82
+ carries that structure alone. A domain rule neither states is recorded as a
83
+ §5 assumption, never smuggled in.
80
84
  - Feature = aggregate. A later requirement is a DELTA on this document.
81
85
 
82
86
  STRUCTURE FOLLOWS THIS PROJECT'S CODE
@@ -134,11 +138,14 @@
134
138
 
135
139
  ### 1.2 Domain / Data Model
136
140
 
137
- <!-- PINNED ANCHOR — follow spec.md exactly. Entities & value objects are the
138
- spec's Key Entities (SAME names); invariants are its Business Rules
139
- (BR-nnn, cite each); the boundary is its Aggregate Boundary; states are its
140
- lifecycle. Cross-slice references are BY ID and live here — the
141
- cross-reference tool reads this section for those edges. -->
141
+ <!-- PINNED ANCHOR — follow the STRUCTURE authority exactly. Where the context has
142
+ a specs/[Context]/domain-model.md, that is it: entities & value objects carry
143
+ the model's names, invariants cite its BR-nnn (never restate them), the
144
+ boundary is its Boundary block, states are the lifecycle it describes. Where
145
+ the context has no model yet, the same four come from spec.md's Key Entities,
146
+ Business Rules, Aggregate Boundary and lifecycle. Cross-slice references are
147
+ BY ID and live here either way — the cross-reference tool reads this section
148
+ for those edges. -->
142
149
 
143
150
  | Element | Kind | Fields / shape | Invariants (BR-) |
144
151
  |---|---|---|---|
@@ -83,9 +83,11 @@
83
83
  - Every element traces UP to a spec id (FR-/BR-/CN-/DC-/IC-/US-/SC-) and the
84
84
  experience obligations of the spec are covered DOWN here (§7). No screen
85
85
  without a spec reason; no user story without a screen home.
86
- - THE SPEC IS THE ONLY DOMAIN INPUT — the same rule the service design keeps.
87
- This document reads the spec + the lane's own standards, never the domain
88
- rule files.
86
+ - THE SPEC IS THE ONLY DOMAIN INPUT for this lane. This document reads the spec
87
+ + the lane's own standards, never the domain rule files. (The service lane
88
+ reads a second authority, the context's domain-model.md, because it realises
89
+ the aggregate's structure. This lane consumes the published surface at §5, not
90
+ the domain, so the model is not in its context.)
89
91
  - THE CONTRACT IS THE ONLY SERVICE INPUT (§5). Read the design contract, never
90
92
  the service design.
91
93