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.
- package/assets/.appweaver/DESIGN-FORMAT.md +63 -31
- package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +62 -14
- package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +10 -6
- package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +9 -1
- package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +21 -0
- package/assets/.appweaver/orchestrator/orchestrator.py +23 -1
- package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +1 -1
- package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +22 -13
- package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +1 -1
- package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +6 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +399 -131
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +199 -38
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +159 -25
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +20 -9
- package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +183 -40
- package/assets/.appweaver/orchestrator/workflows/aw-spec-deploy.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +311 -36
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +221 -40
- package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +217 -174
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +494 -109
- package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +83 -18
- package/assets/.appweaver/orchestrator/workflows/aw-spec-recall-delta.orch.yaml +319 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-feature.orch.yaml +29 -23
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +143 -34
- package/assets/.appweaver/scripts/bash/aw-inventory.sh +15 -0
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +878 -51
- package/assets/.appweaver/scripts/bash/aw-xref.sh +3 -0
- package/assets/.appweaver/scripts/bash/common.sh +28 -1
- package/assets/.appweaver/scripts/powershell/aw-inventory.ps1 +15 -0
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +868 -51
- package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +3 -0
- package/assets/.appweaver/scripts/python/aw-inventory.py +1832 -65
- package/assets/.appweaver/scripts/python/aw-xref.py +500 -81
- package/assets/.appweaver/templates/delta-design-template.md +1 -1
- package/assets/.appweaver/templates/delta-domain-model-template.md +1 -1
- package/assets/.appweaver/templates/delta-spec-template.md +4 -3
- package/assets/.appweaver/templates/design-template.md +56 -40
- package/assets/.appweaver/templates/okf-concept-template.md +11 -1
- package/assets/.appweaver/templates/proposed-inventory-template.md +127 -0
- package/assets/.appweaver/templates/source-map-template.md +5 -3
- package/assets/.appweaver/templates/spec-template.md +24 -21
- package/assets/.appweaver/templates/ui-delta-design-template.md +1 -1
- package/assets/.appweaver/templates/ui-design-template.md +11 -7
- package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +4489 -361
- package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +2274 -125
- package/assets/guardrails/domain/healthcare/auditing.domain.md +3 -3
- package/assets/guardrails/domain/pharma/auditing.domain.md +3 -3
- package/assets/guardrails/technology/dotnet-webapi/api-versioning.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/auditing.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/authorization.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/clean-architecture.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/cqrs.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/data-classification.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/eventing.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/modular-monolith.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/persistence.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/vertical-slices.md +1 -1
- package/assets/guardrails/technology/dotnet-webapi/zero-trust.md +1 -1
- package/assets/guardrails/technology/nextjs/accessibility-implementation.md +1 -1
- package/assets/guardrails/technology/nextjs/api-integration.dotnet-webapi.md +1 -1
- package/assets/guardrails/technology/nextjs/api-integration.java-spring.md +1 -1
- package/assets/guardrails/technology/nextjs/auth-session.md +1 -1
- package/assets/guardrails/technology/nextjs/component-architecture.md +1 -1
- package/assets/guardrails/technology/nextjs/design-system.md +1 -1
- package/assets/guardrails/technology/nextjs/error-handling.md +1 -1
- package/assets/guardrails/technology/nextjs/forms-and-validation.md +1 -1
- package/assets/guardrails/technology/nextjs/i18n.md +1 -1
- package/assets/guardrails/technology/nextjs/performance-budgets.md +1 -1
- package/assets/guardrails/technology/nextjs/routing-navigation.md +1 -1
- package/assets/guardrails/technology/nextjs/state-management.md +1 -1
- package/package.json +1 -1
|
@@ -2,11 +2,21 @@
|
|
|
2
2
|
# aw-spec-adopt (orchestrator) — the JUST-IN-TIME per-feature step of Brownfield DEV
|
|
3
3
|
#
|
|
4
4
|
# Develop an EXISTING feature by first reverse-engineering ONE aggregate / vertical
|
|
5
|
-
# slice from its code into a living spec.md
|
|
6
|
-
# sidecar), THEN reconciling this feature's evidence into the project governance that
|
|
7
|
-
# /appweaver onboard established. Adopt is the inverse of implement: implement reads
|
|
8
|
-
#
|
|
9
|
-
# a reasoning step, stamped `origin: reverse-engineered` with
|
|
5
|
+
# slice from its code into a living spec.md, the bounded context's domain-model.md and
|
|
6
|
+
# aligned lane plans (+ a source-map.md sidecar), THEN reconciling this feature's evidence into the project governance that
|
|
7
|
+
# /appweaver onboard established. Adopt is the inverse of implement: implement reads the
|
|
8
|
+
# plans + the model and generates code; adopt reads code and generates the spec, the model
|
|
9
|
+
# and the plans — equally a reasoning step, stamped `origin: reverse-engineered` with
|
|
10
|
+
# per-item confidence.
|
|
11
|
+
#
|
|
12
|
+
# THE SPEC/MODEL SPLIT HOLDS ON THE REVERSE TOO (2026-09-14). The spec says what the slice
|
|
13
|
+
# DOES and cites BR-nnn by id; the bounded context's domain-model.md says what the domain IS
|
|
14
|
+
# and carries the aggregate root, its boundary, its entities and the TEXT of every invariant.
|
|
15
|
+
# Adopt used to write the model INTO the spec as Key Entities / Business Rules, which left a
|
|
16
|
+
# brownfield feature as the only kind the forward gates could not fully check: analyze-plan's
|
|
17
|
+
# check 4 has nothing to check without a model, and implement generated with no authority on
|
|
18
|
+
# the entity names it was using. The model is CONTEXT-level and shared, so a second adopted
|
|
19
|
+
# slice ADDS its aggregate section and never touches the ones already there.
|
|
10
20
|
#
|
|
11
21
|
# onboard → ADOPT <Feature> (JIT, one feature at a time) → [ forward / CR delta loop ] ← you are here
|
|
12
22
|
#
|
|
@@ -14,12 +24,15 @@
|
|
|
14
24
|
# develop, never the whole codebase (that scale is what onboard's shallow feature map
|
|
15
25
|
# avoids). A NEW feature (no existing code) is NOT adopted — it is authored straight
|
|
16
26
|
# through the forward pipeline (/appweaver specify → plan → implement), which
|
|
17
|
-
# onboard already made brownfield-ready (the code-derived
|
|
27
|
+
# onboard already made brownfield-ready (the code-derived plan template is the
|
|
18
28
|
# project default). So adopt = reverse an EXISTING feature; the forward pipeline = a
|
|
19
29
|
# new one. Both then evolve through the CR delta loop.
|
|
20
30
|
#
|
|
21
|
-
# The reverse output is a NORMAL feature: spec.md
|
|
22
|
-
# the CR delta loop + forward pipeline consume
|
|
31
|
+
# The reverse output is a NORMAL feature: spec.md, domain-model.md and backend-plan.md /
|
|
32
|
+
# frontend-plan.md are the very documents the CR delta loop + forward pipeline consume
|
|
33
|
+
# unchanged — under those names, so nothing downstream needs a brownfield special case.
|
|
34
|
+
# plan-scaffold's backend/frontend lanes also MIGRATE a legacy design.md / design.ui.md left
|
|
35
|
+
# by an adopt that ran before the rename, so an already-adopted repo is carried forward. All brownfield provenance
|
|
23
36
|
# lives in `origin:` frontmatter + the source-map sidecar. Adopt inits
|
|
24
37
|
# active_version.json (v1.0) so the CR loop works immediately after.
|
|
25
38
|
#
|
|
@@ -56,7 +69,7 @@
|
|
|
56
69
|
# =============================================================================
|
|
57
70
|
|
|
58
71
|
name: aw-spec-adopt
|
|
59
|
-
description: The JIT per-feature step of brownfield development — reverse-engineer ONE existing feature into a living spec.md
|
|
72
|
+
description: The JIT per-feature step of brownfield development — reverse-engineer ONE existing feature into a living spec.md, an aggregate section in the bounded context's shared domain-model.md, and backend-plan.md (+ frontend-plan.md where a frontend lane is declared and this slice owns part of its surface) + source-map.md (origin reverse-engineered, per-item confidence, code-derived plan template), then COMPLETE its shallow OKF concept (deepen it to the reversed reality + link the deep artifacts) and record its cross-slice edges. The spec cites BR-nnn by id and the model defines them, exactly as on the greenfield path, so a reversed slice is checkable by the same gates as any other. Fidelity gate is spec + model + plans vs code, and an invented entity, boundary or invariant is a fabrication exactly as an invented FR- is; the review is reported for out-of-band closure. The governance reconcile — carrying this feature's real evidence into the provisional rule files + constitution onboard wrote — is HELD (reconcile_governance=false), so an ordinary run does not touch the governance tier. A NEW feature is authored via the forward pipeline instead. Output is a normal feature for the CR + forward loop.
|
|
60
73
|
# 1.5.0 — user_input is now OPTIONAL: adopt CONSUMES the ACTIVE feature (select-feature's
|
|
61
74
|
# .appweaver/feature.json) when no arg is passed, so onboard→select-feature→adopt needs
|
|
62
75
|
# no re-typing; an explicit <Feature> still selects directly (and wins). One coalesced
|
|
@@ -66,7 +79,7 @@ description: The JIT per-feature step of brownfield development — reverse-engi
|
|
|
66
79
|
# 1.3.0 — reverse design scaffolds from the DEFAULT `design-template` (onboard's code-derived
|
|
67
80
|
# override) instead of the never-shipped `brownfield-design-template`, unifying the
|
|
68
81
|
# whole brownfield pipeline on one code-derived template.
|
|
69
|
-
version:
|
|
82
|
+
version: 2.0.0
|
|
70
83
|
agent_agnostic: true
|
|
71
84
|
dialect: aw-spec.orchestrator/v1
|
|
72
85
|
|
|
@@ -108,8 +121,22 @@ vars:
|
|
|
108
121
|
ui_lane: "false" # THIS slice reverses a UI half: a frontend lane is declared AND the slice owns UI files
|
|
109
122
|
ui_count: "0" # how many UI files the concept attributes to this aggregate (aw-inventory ui_source_files)
|
|
110
123
|
ui_source_files: ""
|
|
111
|
-
|
|
124
|
+
frontend_plan: ""
|
|
112
125
|
ui_tpl_source: ""
|
|
126
|
+
# THE LANE PLANS, under the names the forward pipeline reads. A reversed slice is a
|
|
127
|
+
# NORMAL feature, so it carries backend-plan.md / frontend-plan.md like any other —
|
|
128
|
+
# plan-scaffold's backend/frontend lanes also MIGRATE a legacy design.md / design.ui.md
|
|
129
|
+
# left by an earlier adopt, so a repo that was adopted before the rename is carried
|
|
130
|
+
# forward rather than left with two spellings of one master.
|
|
131
|
+
backend_plan: ""
|
|
132
|
+
# THE BOUNDED CONTEXT'S DOMAIN MODEL — shared by every feature in the context, and the
|
|
133
|
+
# authority on the aggregate root, its entities and the TEXT of every BR-nnn. Reversed
|
|
134
|
+
# here in the same run as the spec, exactly as greenfield `specify` authors the two
|
|
135
|
+
# together, so the model is never behind the spec that cites it.
|
|
136
|
+
context: ""
|
|
137
|
+
context_dir: ""
|
|
138
|
+
domain_model: ""
|
|
139
|
+
domain_model_exists: "false"
|
|
113
140
|
spec_exists: "false"
|
|
114
141
|
fidelity_ok: "false"
|
|
115
142
|
rulemap_exists: "false" # governance-present signal (onboard ran) — bound from resolve-domain
|
|
@@ -162,7 +189,36 @@ workflow:
|
|
|
162
189
|
action: verify_context
|
|
163
190
|
require_non_empty: feature_name
|
|
164
191
|
on_empty: stop
|
|
165
|
-
on_empty_message: "No feature to adopt. Either run /appweaver select-feature first (pick the
|
|
192
|
+
on_empty_message: "No feature to adopt. Either run /appweaver select-feature first (pick the feature from the boundary map onboard laid out), then /appweaver adopt; or name it directly: /appweaver adopt <Feature>."
|
|
193
|
+
|
|
194
|
+
# WHICH BOUNDED CONTEXT THIS FEATURE LANDS IN, and a refusal to guess — the same gate
|
|
195
|
+
# select-feature carries, and needed here for the same reason: this stage also creates a
|
|
196
|
+
# feature directory. scope_ok is false in exactly one state, contexts exist and none is
|
|
197
|
+
# selected, and in that state set-feature resolves the target under a bare specs/ where
|
|
198
|
+
# it is outside every context. Worse on this path than on the forward one, because an
|
|
199
|
+
# adopted name comes from the reversed code rather than from a menu: adopting an
|
|
200
|
+
# aggregate that happens to share a name with an empty bounded context would write that
|
|
201
|
+
# context's own spec.md and orphan every feature meant to live inside it. A repo with no
|
|
202
|
+
# contexts at all passes, which keeps the flat brownfield layout working untouched.
|
|
203
|
+
- id: context_scope
|
|
204
|
+
action: execute_script
|
|
205
|
+
script: { ref: actions }
|
|
206
|
+
subcommand: list-contexts
|
|
207
|
+
outputs:
|
|
208
|
+
- { name: active_context, from: "$.active" }
|
|
209
|
+
- { name: context_count, from: "$.count" }
|
|
210
|
+
- { name: scope_ok, from: "$.scope_ok" }
|
|
211
|
+
- { name: scope_message, from: "$.scope_message" }
|
|
212
|
+
|
|
213
|
+
- id: require_context_scope
|
|
214
|
+
action: verify_context
|
|
215
|
+
require_true: scope_ok
|
|
216
|
+
on_false: stop
|
|
217
|
+
on_false_message: >
|
|
218
|
+
{{scope_message}}
|
|
219
|
+
Adopting reverse-engineers one aggregate into a feature directory, so the context
|
|
220
|
+
that owns it has to be chosen before the directory is created — moving a feature
|
|
221
|
+
between contexts afterwards means re-specifying it in the new one.
|
|
166
222
|
|
|
167
223
|
# Create-or-select the feature dir + persist it active (idempotent in the no-arg
|
|
168
224
|
# path where it is already active; creates it in the explicit-arg path). set-feature
|
|
@@ -178,6 +234,26 @@ workflow:
|
|
|
178
234
|
- { name: spec_file, from: "$.spec_file" }
|
|
179
235
|
- { name: spec_exists, from: "$.spec_exists" }
|
|
180
236
|
|
|
237
|
+
# WHICH AGGREGATE THIS FEATURE ACTS ON. Usually the same name — one aggregate, one
|
|
238
|
+
# feature, the 1:1 default — but not when the boundary map split an aggregate into
|
|
239
|
+
# capabilities (PatientRegistration and PatientMerge over Patient). The reverse steps
|
|
240
|
+
# below write and judge the model section BY THIS NAME, and every later command finds
|
|
241
|
+
# the feature's part of the model the same way; writing it under the feature's name
|
|
242
|
+
# instead defines one root twice as soon as a sibling feature is adopted. No spec
|
|
243
|
+
# exists yet at this point, so it resolves from the confirmed boundary map, and a
|
|
244
|
+
# feature the map does not split resolves to its own name — exactly what this
|
|
245
|
+
# workflow always used.
|
|
246
|
+
- id: feature_aggregates
|
|
247
|
+
action: execute_script
|
|
248
|
+
script: { ref: xref }
|
|
249
|
+
subcommand: feature-aggregates
|
|
250
|
+
args: ["--feature-dir", "{{feature_dir}}"]
|
|
251
|
+
outputs:
|
|
252
|
+
- { name: aggregates_csv, from: "$.aggregates_csv" }
|
|
253
|
+
- { name: aggregate_sections, from: "$.sections" }
|
|
254
|
+
- { name: aggregate_source, from: "$.source" }
|
|
255
|
+
- { name: aggregate_primary, from: "$.primary" } # the concept this feature's OKF work lands on
|
|
256
|
+
|
|
181
257
|
# 1a. One-time baseline: refuse to clobber an already-adopted / authored spec.
|
|
182
258
|
# After adoption, changes go through the CR delta loop, not adopt.
|
|
183
259
|
# set-feature returns spec_exists as a JSON boolean; the condition path
|
|
@@ -191,14 +267,16 @@ workflow:
|
|
|
191
267
|
on_empty: stop
|
|
192
268
|
on_empty_message: "specs/ already has a spec.md for {{feature_name}} — adopt is a one-time baseline. For a change to an adopted slice use the CR delta loop (/appweaver specify → plan → analyze-plan-delta → implement → build → analyze-slice-delta → finalize-delta → analyze-slice → close-delta); to re-adopt from scratch, remove the feature dir first."
|
|
193
269
|
|
|
194
|
-
# 1b. Resolve
|
|
195
|
-
#
|
|
196
|
-
#
|
|
270
|
+
# 1b. Resolve the OKF concept of the aggregate this feature acts on → its source_files
|
|
271
|
+
# + module dir. The bundle is the PROJECT's knowledge and a concept is an aggregate,
|
|
272
|
+
# so a feature that is one capability over a shared aggregate reads the SHARED
|
|
273
|
+
# concept, which lists every capability's code; the source-map below narrows it to
|
|
274
|
+
# this feature's. The code itself is the source of truth (read during authoring).
|
|
197
275
|
- id: concept
|
|
198
276
|
action: execute_script
|
|
199
277
|
script: { ref: inventory }
|
|
200
278
|
subcommand: concept
|
|
201
|
-
args: ["--bundle", "{{bundle_dir}}", "--aggregate", "{{
|
|
279
|
+
args: ["--bundle", "{{bundle_dir}}", "--aggregate", "{{aggregate_primary}}"]
|
|
202
280
|
outputs:
|
|
203
281
|
- { name: concept_exists, from: "$.exists" }
|
|
204
282
|
- { name: concept_path, from: "$.concept_path" }
|
|
@@ -218,7 +296,7 @@ workflow:
|
|
|
218
296
|
action: verify_context
|
|
219
297
|
require_true: concept_exists
|
|
220
298
|
on_false: stop
|
|
221
|
-
on_false_message: "No feature '{{feature_name}}' in the onboard
|
|
299
|
+
on_false_message: "No concept for the aggregate '{{aggregate_primary}}' — the one feature '{{feature_name}}' acts on — in the onboard bundle under {{bundle_dir}}. If its bounded context has not been onboarded, run /appweaver onboard <Context> first; {{bundle_dir}}/aggregates/index.md lists each aggregate with the features that act on it. If '{{feature_name}}' is a NEW feature (no existing code), do NOT adopt it — author it through the forward pipeline (/appweaver specify → plan → implement), which onboard already made brownfield-ready."
|
|
222
300
|
|
|
223
301
|
# Governance prerequisite: the reverse steps below are authored AGAINST the project
|
|
224
302
|
# onboard established (the constitution halves + guardrails/projects/<project>/ rule set).
|
|
@@ -235,6 +313,16 @@ workflow:
|
|
|
235
313
|
- { name: gov_domain, from: "$.domain" }
|
|
236
314
|
- { name: rulemap_exists, from: "$.rulemap_exists" }
|
|
237
315
|
|
|
316
|
+
# ⌛ OPEN, now that onboard runs once per BOUNDED CONTEXT: this gate asks whether
|
|
317
|
+
# ANY context has been onboarded, and it needs to ask whether THIS FEATURE'S
|
|
318
|
+
# context has. The narrower question is already answered next door — require_concept
|
|
319
|
+
# stops when the feature has no OKF concept, and a feature only has one once its
|
|
320
|
+
# context was onboarded — so the sequence is safe today and the gap is in what the
|
|
321
|
+
# message says, not in what it lets through. Tightening it properly means resolving
|
|
322
|
+
# the feature's context from the concept's `bounded_context:` stamp and naming that
|
|
323
|
+
# context in the refusal. Related and unresolved: `fidelity_gate` is per feature and
|
|
324
|
+
# has no context-level equivalent — a context-wide one would fail a whole context on
|
|
325
|
+
# a single mismapped feature.
|
|
238
326
|
- id: require_governance
|
|
239
327
|
action: verify_context
|
|
240
328
|
require_true: rulemap_exists
|
|
@@ -242,27 +330,57 @@ workflow:
|
|
|
242
330
|
on_false_message: "No active governance for adopt to work against — run /appweaver onboard first. onboard establishes the PROJECT constitution + guardrails/projects/<project>/ rule set (provisional-from-scan) and activates it. Reversing '{{feature_name}}' without that scaffold would author the spec and design against no code-derived rules at all, and leave them with no governance home."
|
|
243
331
|
|
|
244
332
|
# 2. Scaffold the living docs. The SPEC reuses the forward spec-template (it is
|
|
245
|
-
# tech-agnostic WHAT/WHY — no architectural bias). The
|
|
333
|
+
# tech-agnostic WHAT/WHY — no architectural bias). The BACKEND PLAN scaffolds from the
|
|
246
334
|
# DEFAULT `design-template` — which /appweaver onboard REPLACED with the repo's
|
|
247
335
|
# code-derived override (resolve_template Priority-1, reverse-engineered from the
|
|
248
|
-
# code), so the reversed
|
|
336
|
+
# code), so the reversed plan's structural sections follow the code's own
|
|
249
337
|
# architecture rather than a fixed greenfield layering, describing the system
|
|
250
|
-
# as-built. (Falls back to the greenfield base if onboard has not run.)
|
|
338
|
+
# as-built. (Falls back to the greenfield base if onboard has not run.) The DOMAIN
|
|
339
|
+
# MODEL scaffolds into the bounded CONTEXT, not the feature — it is shared. All are
|
|
251
340
|
# still normal forward docs (same identity + spine) that the CR delta loop consumes
|
|
252
341
|
# unchanged. Then init active_version.json (v1.0).
|
|
342
|
+
#
|
|
343
|
+
# THE TEMPLATE IDENTIFIERS KEEP THE `design-template` SPELLING ON PURPOSE. The
|
|
344
|
+
# DOCUMENTS moved to the plan names; the template NAMES did not, because a repo that
|
|
345
|
+
# has already run onboard carries its code-derived override at
|
|
346
|
+
# .appweaver/templates/overrides/design-template.md. Renaming the identifier would
|
|
347
|
+
# make that file stop resolving and silently fall back to the kit's greenfield
|
|
348
|
+
# template — imposing a four-layer structure on a codebase that chose another, which
|
|
349
|
+
# is the exact failure require_ui_template below exists to prevent.
|
|
350
|
+
- id: context_paths
|
|
351
|
+
action: execute_script
|
|
352
|
+
script: { ref: actions }
|
|
353
|
+
subcommand: context-paths
|
|
354
|
+
outputs:
|
|
355
|
+
- { name: context, from: "$.context" }
|
|
356
|
+
- { name: context_dir, from: "$.context_dir" }
|
|
357
|
+
- { name: domain_model, from: "$.domain_model" }
|
|
358
|
+
- { name: domain_model_exists, from: "$.domain_model_exists" }
|
|
359
|
+
|
|
253
360
|
- id: scaffold_spec
|
|
254
361
|
action: execute_script
|
|
255
362
|
script: { ref: actions }
|
|
256
363
|
subcommand: scaffold
|
|
257
364
|
args: ["--feature-dir", "{{feature_dir}}", "--allow-existing"]
|
|
258
365
|
|
|
259
|
-
-
|
|
366
|
+
# Idempotent and non-destructive: a context whose model already exists (an earlier
|
|
367
|
+
# feature in it was adopted, or authored greenfield) keeps it, and the reverse below
|
|
368
|
+
# ADDS this aggregate's section rather than replacing the document.
|
|
369
|
+
- id: scaffold_model
|
|
370
|
+
action: execute_script
|
|
371
|
+
script: { ref: actions }
|
|
372
|
+
subcommand: model-scaffold
|
|
373
|
+
args: ["--feature-dir", "{{feature_dir}}"]
|
|
374
|
+
outputs:
|
|
375
|
+
- { name: domain_model, from: "$.domain_model" }
|
|
376
|
+
|
|
377
|
+
- id: scaffold_plan
|
|
260
378
|
action: execute_script
|
|
261
379
|
script: { ref: actions }
|
|
262
|
-
subcommand:
|
|
263
|
-
args: ["--feature-dir", "{{feature_dir}}"] #
|
|
380
|
+
subcommand: plan-scaffold
|
|
381
|
+
args: ["--feature-dir", "{{feature_dir}}", "--lane", "backend"] # `design-template` = onboard's code-derived override (greenfield base if onboard has not run)
|
|
264
382
|
outputs:
|
|
265
|
-
- { name:
|
|
383
|
+
- { name: backend_plan, from: "$.plan_doc" }
|
|
266
384
|
|
|
267
385
|
- id: version_init
|
|
268
386
|
action: execute_script
|
|
@@ -299,18 +417,18 @@ workflow:
|
|
|
299
417
|
condition: "{{ui_count}} == 0"
|
|
300
418
|
vars: { ui_lane: "false" }
|
|
301
419
|
|
|
302
|
-
# Scaffold the LANE's
|
|
303
|
-
# ui-design-template ->
|
|
304
|
-
# GENERATED that override from this repo's own UI source, so the reversed
|
|
420
|
+
# Scaffold the LANE's plan from ITS template pair (--lane frontend resolves
|
|
421
|
+
# ui-design-template -> frontend-plan.md), the twin of scaffold_plan above. onboard
|
|
422
|
+
# GENERATED that override from this repo's own UI source, so the reversed frontend plan
|
|
305
423
|
# follows the code's real composition axes rather than a fixed screen taxonomy.
|
|
306
|
-
- id:
|
|
424
|
+
- id: scaffold_ui_plan
|
|
307
425
|
condition: "{{ui_lane}} == true"
|
|
308
426
|
action: execute_script
|
|
309
427
|
script: { ref: actions }
|
|
310
|
-
subcommand:
|
|
311
|
-
args: ["--feature-dir", "{{feature_dir}}", "--lane", "
|
|
428
|
+
subcommand: plan-scaffold
|
|
429
|
+
args: ["--feature-dir", "{{feature_dir}}", "--lane", "frontend"]
|
|
312
430
|
outputs:
|
|
313
|
-
- { name:
|
|
431
|
+
- { name: frontend_plan, from: "$.plan_doc" }
|
|
314
432
|
- { name: ui_tpl_source, from: "$.template_source" }
|
|
315
433
|
- { name: ui_tpl_override, from: "$.override_active" }
|
|
316
434
|
|
|
@@ -365,7 +483,7 @@ workflow:
|
|
|
365
483
|
output_target: { type: file, path: "{{spec_file}}" }
|
|
366
484
|
task: |
|
|
367
485
|
Reverse-engineer the MASTER specification (the target spec.md in context)
|
|
368
|
-
for the
|
|
486
|
+
for the feature '{{feature_name}}' FROM ITS CODE. The bundle concept (in
|
|
369
487
|
context) is the INDEX — its `source_files` list the code that IS this slice;
|
|
370
488
|
READ those files (under {{module_dir}}, listed below) as the SOURCE OF TRUTH.
|
|
371
489
|
The concept is a summary; the CODE is authoritative — if they disagree, the
|
|
@@ -373,17 +491,26 @@ workflow:
|
|
|
373
491
|
|
|
374
492
|
Capture what the code ACTUALLY DOES, as-built (bugs/quirks included), in the
|
|
375
493
|
template's vocabulary:
|
|
376
|
-
-
|
|
494
|
+
- THIS FEATURE ACTS ON {{aggregates_csv}}. Write exactly that on the Domain Model
|
|
495
|
+
Reference's `**Acts on aggregate(s)**:` line, each name in backticks — every later
|
|
496
|
+
command finds this feature's part of the domain model by reading that line. The
|
|
497
|
+
feature is the capability scope the developer confirmed in the boundary map,
|
|
498
|
+
whatever it is named: its user stories are that capability's operations and no
|
|
499
|
+
others. Sharing a name with an aggregate does not make it that aggregate's only
|
|
500
|
+
feature — other features may act on the same aggregate. Keep US-1.
|
|
377
501
|
- Each command / endpoint / use-case the code exposes is a USER STORY (US-n),
|
|
378
502
|
never a separate feature. Derive its Given/When/Then from the code's paths.
|
|
379
503
|
- System Requirements in EARS (THE SYSTEM SHALL / WHEN / IF…THEN / WHILE /
|
|
380
504
|
WHERE), each atomic + testable, derived from observed behaviour.
|
|
381
|
-
- Always-true invariants the code enforces
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
505
|
+
- Always-true invariants the code enforces get stable BR-nnn ids, CITED here and
|
|
506
|
+
DEFINED in the domain model — see the next bullet.
|
|
507
|
+
- THE DOMAIN MODEL IS NOT THIS DOCUMENT'S. Fill "### Domain Model Reference" with
|
|
508
|
+
the aggregate's NAME and the ids of the invariants this spec relies on
|
|
509
|
+
(BR-nnn), and nothing more. Do NOT write the ubiquitous language, the aggregate
|
|
510
|
+
boundary, the entity/value-object split, the lifecycle states, or the TEXT of any
|
|
511
|
+
invariant: all of that lives in the bounded context's domain-model.md, which the
|
|
512
|
+
NEXT step reverses out of this same code, and several specs act on one aggregate
|
|
513
|
+
so a per-spec copy drifts. Cite by id; never restate.
|
|
387
514
|
- DOMAIN LIFT — where the CODE enforces them, lift into the three sections
|
|
388
515
|
(cite the source file): Constraints & NFRs (CN-, e.g. retention /
|
|
389
516
|
immutability / append-only audit the code implements), Data Classification
|
|
@@ -412,38 +539,118 @@ workflow:
|
|
|
412
539
|
rule the code does not exhibit. Behaviour that is clearly present is
|
|
413
540
|
"(certain)".
|
|
414
541
|
- Reference the source-map: note that legacy-artefact ↔ requirement links
|
|
415
|
-
live in `
|
|
542
|
+
live in `{{feature_dir}}/source-map.md` (authored next).
|
|
416
543
|
- This is v1.0: fill the Change History row; keep US-1's "Added: v1.0".
|
|
417
544
|
- Business-facing + testable; NO implementation mechanics (an external interop
|
|
418
545
|
OBLIGATION is an IC- requirement, never the adapter design).
|
|
419
546
|
|
|
420
547
|
Source files to read (the slice's code): {{source_files}}
|
|
421
548
|
|
|
422
|
-
#
|
|
549
|
+
# ══════════ REVERSE DOMAIN MODEL — the CONTEXT's structure, from the CODE ══════
|
|
550
|
+
# The greenfield split, applied to the reverse: the spec says what the system DOES, the
|
|
551
|
+
# bounded context's domain-model.md says what the domain IS — the aggregate root, its
|
|
552
|
+
# boundary, its entities and value objects, its lifecycle, and the TEXT of every BR-nnn
|
|
553
|
+
# the spec cites by id. Authored in the SAME run as the spec, exactly as `specify` does,
|
|
554
|
+
# so the model is never behind the spec that depends on it.
|
|
555
|
+
#
|
|
556
|
+
# THE MODEL IS THE CONTEXT'S, NOT THIS FEATURE'S. Every feature in the bounded context
|
|
557
|
+
# reads it, so adopting a second slice ADDS an aggregate section and must not touch the
|
|
558
|
+
# ones already there — a renumbered BR breaks every citation in every sibling spec,
|
|
559
|
+
# silently. The scaffold above is non-destructive for the same reason.
|
|
560
|
+
#
|
|
561
|
+
# THE CODE IS STILL THE ORACLE. No modelling rule file is loaded, for the reason the
|
|
562
|
+
# reversed spec loads none: a prescriptive standard states what a model OUGHT to be, and
|
|
563
|
+
# an anemic legacy slice must reverse as exactly that. A distinction the code does not
|
|
564
|
+
# draw is not a gap to fill in.
|
|
565
|
+
- id: ctx_reverse_model
|
|
566
|
+
action: build_context
|
|
567
|
+
context:
|
|
568
|
+
- { path: "{{domain_model}}" } # the model — template on the context's first slice, POPULATED on a later one
|
|
569
|
+
- { path: "{{spec_file}}" } # the reversed spec — the BR-nnn ids this model must define
|
|
570
|
+
- { path: "{{concept_path}}" } # source_files + seam
|
|
571
|
+
- { path: .appweaver/memory/constitution.domain.md, optional: true }
|
|
572
|
+
- id: reverse_model
|
|
573
|
+
action: agent_author
|
|
574
|
+
include_standards: false # the technical/arch sticky set is for the plans, never the model
|
|
575
|
+
tools: Read # the structure is reversed from the CODE, which arrives as a path list
|
|
576
|
+
output_target: { type: file, path: "{{domain_model}}" }
|
|
577
|
+
task: |
|
|
578
|
+
Reverse-engineer the BOUNDED CONTEXT's DOMAIN MODEL (the target domain-model.md in
|
|
579
|
+
context) for the aggregate(s) the feature '{{feature_name}}' acts on —
|
|
580
|
+
{{aggregates_csv}} — FROM ITS CODE. The reversed spec (in context) names them and
|
|
581
|
+
cites the invariant ids; this document DEFINES them. READ the source files listed
|
|
582
|
+
below — the code is the SOURCE OF TRUTH.
|
|
583
|
+
|
|
584
|
+
- THE SECTION IS NAMED AFTER THE AGGREGATE, NEVER THE FEATURE: {{aggregate_sections}},
|
|
585
|
+
exactly. Every later command finds this feature's part of the model by that
|
|
586
|
+
heading. Where the feature and the aggregate share a name the two are the same
|
|
587
|
+
thing; where they differ, a section headed '{{feature_name}}' is a defect — the
|
|
588
|
+
next feature over the same aggregate would define its root a second time.
|
|
589
|
+
- IF THAT SECTION ALREADY EXISTS, another feature over the same aggregate was adopted
|
|
590
|
+
first. EXTEND it and never write a second one: add `{{feature_name}}` to its
|
|
591
|
+
`Serving specs` line, and add only what THIS feature's code evidences that the
|
|
592
|
+
section lacks — an entity, a lifecycle state, a BR-nnn numbered after the highest
|
|
593
|
+
one already there. Leave what the earlier feature wrote exactly as it is.
|
|
594
|
+
- OTHERWISE ADD ONE `## Aggregate: <Name>` SECTION per aggregate, `{{feature_name}}`
|
|
595
|
+
on its `Serving specs` line: its boundary
|
|
596
|
+
(owns / references by id / out of scope), entities, value objects, domain events,
|
|
597
|
+
lifecycle states, and every always-true invariant the code enforces as a stable
|
|
598
|
+
BR-nnn with its RULE TEXT. The spec cites those ids and never restates them.
|
|
599
|
+
- IF THE MODEL ALREADY HAS CONTENT, this is the context's SECOND (or later) adopted
|
|
600
|
+
slice. ADD any of this feature's aggregates not already there as a new section and
|
|
601
|
+
EXTEND the ubiquitous language. Do NOT rewrite, renumber or "tidy" the aggregates
|
|
602
|
+
already there — other specs cite their ids, and a renumbered BR breaks every
|
|
603
|
+
citation silently. Add `{{feature_name}}` to the `Serving specs` line of any
|
|
604
|
+
existing aggregate this slice also acts on.
|
|
605
|
+
- MODEL WHAT THE CODE EXHIBITS, NOT WHAT GOOD DESIGN WOULD WANT. Classify entities
|
|
606
|
+
vs value objects by whether the code gives the thing an IDENTITY; draw the
|
|
607
|
+
boundary where the code actually draws it (what it loads and saves together).
|
|
608
|
+
A slice that is anemic, or models nothing at all, reverses as exactly that — an
|
|
609
|
+
aggregate with no invariants is a true finding, and the fidelity gate scores an
|
|
610
|
+
invented one as a fabrication. Where the code's own grouping is unclear, record
|
|
611
|
+
what it shows and mark the item "(inferred)".
|
|
612
|
+
- CROSS-AGGREGATE REFERENCES BY ID ONLY, never a navigable link — where the code
|
|
613
|
+
does hold a direct object reference across a boundary, record the reference by id
|
|
614
|
+
here and leave the coupling fact to the source-map's Seam section.
|
|
615
|
+
- Fill "## Cross-Aggregate Invariants" (XBR-n) with rules the code enforces ACROSS
|
|
616
|
+
two or more aggregates — they belong to no single spec, which is why they can only
|
|
617
|
+
live here. "None (as of v1.0)" when the code shows none; never delete the section.
|
|
618
|
+
- Fill "## Context Map" with this context's relationships to others where the code
|
|
619
|
+
evidences them, or "None (as of v1.0)". Never delete the section.
|
|
620
|
+
- TECHNOLOGY-AGNOSTIC. No types, no persistence, no framework, no layering. WHERE an
|
|
621
|
+
invariant is ENFORCED is a plan concern and belongs in backend-plan.md.
|
|
622
|
+
- Add `origin: reverse-engineered` near the identity block. Do NOT write the Context
|
|
623
|
+
version or the Change History version column — scripts stamp those.
|
|
624
|
+
|
|
625
|
+
Source files to read (the slice's code): {{source_files}}
|
|
626
|
+
|
|
627
|
+
# ═══════════ REVERSE BACKEND PLAN — from the SPEC + MODEL + CODE, AS-BUILT ═══
|
|
423
628
|
# Anchored to the reversed spec's ids (§4 Traceability → forward-compatible),
|
|
424
|
-
# grounded in the code's ACTUAL structure, tech-agnostic. NO domain files (rule
|
|
425
|
-
# partition)
|
|
426
|
-
#
|
|
427
|
-
#
|
|
428
|
-
|
|
629
|
+
# grounded in the code's ACTUAL structure, tech-agnostic. NO domain rule files (rule
|
|
630
|
+
# partition) — the domain reaches this plan as the reversed spec's ids and as the
|
|
631
|
+
# context's domain model, which is READ here and never written. The scaffolded
|
|
632
|
+
# backend-plan.md IS onboard's code-derived `design-template` override — its §2
|
|
633
|
+
# component sections follow the code's own folders/modules, not a fixed layering.
|
|
634
|
+
- id: ctx_reverse_plan
|
|
429
635
|
action: build_context
|
|
430
636
|
context:
|
|
431
|
-
- { path: "{{
|
|
432
|
-
- { path: "{{spec_file}}" } # the reversed spec = the
|
|
637
|
+
- { path: "{{backend_plan}}" } # the scaffolded code-derived template = structure + embedded guidance
|
|
638
|
+
- { path: "{{spec_file}}" } # the reversed spec = WHAT the slice must do
|
|
639
|
+
- { path: "{{domain_model}}" } # the reversed model = what the domain IS — READ, never written here
|
|
433
640
|
- { path: "{{concept_path}}" } # source_files + seam (structure hints)
|
|
434
641
|
- { path: .appweaver/DESIGN-FORMAT.md } # the HLD contract (see its Brownfield variant note)
|
|
435
642
|
- { path: "{{bundle_dir}}/architecture/overview.md", optional: true } # the as-built architecture (inventory) — cite, don't re-derive
|
|
436
643
|
- { path: .appweaver/memory/constitution.technical.md, optional: true } # technology base ONLY — no domain
|
|
437
|
-
- id:
|
|
644
|
+
- id: reverse_plan
|
|
438
645
|
action: agent_author
|
|
439
646
|
include_standards: true # the technical/architecture sticky set (reference only — the CODE wins)
|
|
440
647
|
tools: Read # grounded in the CODE, which arrives as {{source_files}} paths
|
|
441
|
-
output_target: { type: file, path: "{{
|
|
648
|
+
output_target: { type: file, path: "{{backend_plan}}" }
|
|
442
649
|
task: |
|
|
443
|
-
Reverse-engineer the
|
|
444
|
-
context — it is the BROWNFIELD
|
|
445
|
-
MEDIATES the reversed spec ↔ the existing code. Ground every element
|
|
446
|
-
CODE (read the source files listed below) but ANCHOR each to a spec id from
|
|
650
|
+
Reverse-engineer the BACKEND LANE's master plan (the target backend-plan.md in
|
|
651
|
+
context — it is the BROWNFIELD plan template) — the tech-agnostic HLD that
|
|
652
|
+
MEDIATES the reversed spec + domain model ↔ the existing code. Ground every element
|
|
653
|
+
in the CODE (read the source files listed below) but ANCHOR each to a spec id from
|
|
447
654
|
the reversed spec (in context) so §4 Traceability is complete and the doc is
|
|
448
655
|
forward-compatible. Guidance: {{feature_name}}
|
|
449
656
|
|
|
@@ -451,10 +658,12 @@ workflow:
|
|
|
451
658
|
it toward any reference architecture; the technical standards in context are a
|
|
452
659
|
vocabulary to NAME what you find, never a target to bend the code toward.
|
|
453
660
|
Rules:
|
|
454
|
-
- THE SPEC
|
|
455
|
-
actual STRUCTURE — and NO domain rule
|
|
456
|
-
|
|
457
|
-
→ surface it (it belongs in the spec
|
|
661
|
+
- THE SPEC AND THE MODEL ARE THE ONLY DOMAIN INPUTS. You have the reversed spec,
|
|
662
|
+
the reversed domain model and the code's actual STRUCTURE — and NO domain rule
|
|
663
|
+
files. Realise the spec ids; introduce no domain rule neither document states. A
|
|
664
|
+
concept the code exhibits but both lack → surface it (it belongs in the spec or
|
|
665
|
+
the model) and record a §5 DA-n; do not smuggle it in. DO NOT EDIT
|
|
666
|
+
domain-model.md — it is spec-tier and read-only here.
|
|
458
667
|
- STRUCTURE FOLLOWS THE CODE. Fill §1.1 As-Built Architecture from the code's
|
|
459
668
|
real shape (its folders / projects / modules — name the style, don't prescribe
|
|
460
669
|
one). Then create ONE §2 subsection per structural axis the slice's code
|
|
@@ -464,11 +673,14 @@ workflow:
|
|
|
464
673
|
fits no textbook layer (a UI tier, a worker, a shared library) gets its own
|
|
465
674
|
section; a layer the code lacks does NOT appear.
|
|
466
675
|
- KEEP THE NEUTRAL ANCHORS (the template pins these): §1.2 is the domain/data
|
|
467
|
-
MODEL and MUST match the
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
676
|
+
MODEL and MUST match the CONTEXT'S DOMAIN MODEL exactly — the same entity and
|
|
677
|
+
value-object NAMES, the same boundary, the same lifecycle states — with
|
|
678
|
+
cross-slice References-by-id kept here. Every BR-nnn the model defines gets a
|
|
679
|
+
named ENFORCEMENT POINT in this plan: cite it by id and NEVER restate what it
|
|
680
|
+
says, because the model is the only place that text lives. One §2 subsection is
|
|
681
|
+
the EXTERNAL INTEGRATIONS table (heading contains "Integration") realising the
|
|
682
|
+
spec's IC-. Realise CN- (structural → §1.2 invariants/events; retention/audit →
|
|
683
|
+
§2 persistence / §3 cross-cutting), DC- (§3 + projection surface).
|
|
472
684
|
- AS-BUILT DEBT, not architecture drift. §6 records ONLY debt the CODE ITSELF
|
|
473
685
|
evidences — stubs/no-ops, dead or duplicate code, torn seams (shared table/
|
|
474
686
|
transaction), TODOs, hard-coded values. The code being organised differently
|
|
@@ -486,28 +698,29 @@ workflow:
|
|
|
486
698
|
|
|
487
699
|
# ═══════ REVERSE UI DESIGN — the LANE's half, from the UI code, AS-BUILT ═══
|
|
488
700
|
# Runs only where this slice HAS a surface (ui_lane). The service design above is
|
|
489
|
-
# NOT its parent:
|
|
490
|
-
# spec's UX- and the user stories' interaction, and it CONSUMES
|
|
491
|
-
# rather than restating them. Both are in context for exactly that reason.
|
|
492
|
-
- id:
|
|
701
|
+
# NOT its parent: backend-plan.md realises the spec's FR/BR/CN-, frontend-plan.md
|
|
702
|
+
# realises the spec's UX- and the user stories' interaction, and it CONSUMES the backend
|
|
703
|
+
# plan's contracts rather than restating them. Both are in context for exactly that reason.
|
|
704
|
+
- id: ctx_reverse_ui_plan
|
|
493
705
|
condition: "{{ui_lane}} == true"
|
|
494
706
|
action: build_context
|
|
495
707
|
context:
|
|
496
|
-
- { path: "{{
|
|
708
|
+
- { path: "{{frontend_plan}}" } # the scaffolded code-derived lane template = structure + embedded guidance
|
|
497
709
|
- { path: "{{spec_file}}" } # the reversed spec — UX- + the user stories this surface serves
|
|
498
|
-
- { path: "{{
|
|
710
|
+
- { path: "{{backend_plan}}" } # the backend plan — the contracts the UI consumes, never re-specified here
|
|
711
|
+
- { path: "{{domain_model}}", optional: true } # the ubiquitous language labels and states must use — READ, never written
|
|
499
712
|
- { path: .appweaver/memory/constitution.ui.md, optional: true } # the lane's UX-* base, reversed by onboard from this same UI
|
|
500
713
|
- { path: "{{bundle_dir}}/architecture/frontend.md", optional: true } # the as-built UI architecture + the SHARED surface no slice owns
|
|
501
|
-
- id:
|
|
714
|
+
- id: reverse_ui_plan
|
|
502
715
|
condition: "{{ui_lane}} == true"
|
|
503
716
|
action: agent_author
|
|
504
717
|
include_standards: true # the lane's sticky technical set (reference only — the CODE wins)
|
|
505
718
|
tools: Read # same, for the lane's surface ({{ui_source_files}})
|
|
506
|
-
output_target: { type: file, path: "{{
|
|
719
|
+
output_target: { type: file, path: "{{frontend_plan}}" }
|
|
507
720
|
task: |
|
|
508
|
-
Reverse-engineer the FRONTEND LANE's
|
|
509
|
-
in context — it is this project's code-derived UI
|
|
510
|
-
|
|
721
|
+
Reverse-engineer the FRONTEND LANE's master plan (the target frontend-plan.md
|
|
722
|
+
in context — it is this project's code-derived UI plan template) for the
|
|
723
|
+
feature '{{feature_name}}', FROM ITS UI CODE. Fill the template; preserve its
|
|
511
724
|
section order.
|
|
512
725
|
|
|
513
726
|
THE UI CODE IS THE SOURCE OF TRUTH — describe the surface AS-BUILT, quirks
|
|
@@ -516,9 +729,11 @@ workflow:
|
|
|
516
729
|
surface with no loading states is recorded as having none, NEVER as needing them.
|
|
517
730
|
Rules:
|
|
518
731
|
- STAY IN THE LANE. Realise the spec's Experience Standards (UX-) and the
|
|
519
|
-
interaction its User Stories imply. The
|
|
732
|
+
interaction its User Stories imply. The backend plan (in context) supplies
|
|
520
733
|
the CONTRACTS this surface consumes — cite them; do NOT restate, re-derive or
|
|
521
|
-
contradict them, and introduce no server-side behaviour here.
|
|
734
|
+
contradict them, and introduce no server-side behaviour here. Where the domain
|
|
735
|
+
model is in context, use its UBIQUITOUS LANGUAGE exactly in labels, states and
|
|
736
|
+
messages, and cite BR-nnn rather than restating a rule.
|
|
522
737
|
- STRUCTURE FOLLOWS THE UI CODE. Fill each section from the lane's real shape —
|
|
523
738
|
its actual routes and screens, its own composition axes (however it groups
|
|
524
739
|
components), where client state and server data-fetching really live, its
|
|
@@ -543,8 +758,8 @@ workflow:
|
|
|
543
758
|
context:
|
|
544
759
|
- { path: .appweaver/templates/source-map-template.md } # the sidecar structure
|
|
545
760
|
- { path: "{{spec_file}}" }
|
|
546
|
-
- { path: "{{
|
|
547
|
-
- { path: "{{
|
|
761
|
+
- { path: "{{backend_plan}}" }
|
|
762
|
+
- { path: "{{frontend_plan}}", optional: true } # the lane's design, where this slice has one
|
|
548
763
|
- { path: "{{concept_path}}" } # both file lists to map
|
|
549
764
|
- id: source_map
|
|
550
765
|
action: agent_author
|
|
@@ -553,15 +768,21 @@ workflow:
|
|
|
553
768
|
output_target: { type: file, path: "{{feature_dir}}/source-map.md" }
|
|
554
769
|
task: |
|
|
555
770
|
Author the source-map sidecar (the target in context) from the template,
|
|
556
|
-
for
|
|
557
|
-
spine — it keeps spec.md /
|
|
771
|
+
for the feature '{{feature_name}}'. It is the SOURCE ANCHOR of the traceability
|
|
772
|
+
spine — it keeps spec.md / backend-plan.md clean while recording provenance here.
|
|
558
773
|
- One row per legacy artefact in the bundle concept's `source_files` (read
|
|
559
774
|
them under {{module_dir}}): map each to the spec ids (FR/BR/US/CN/DC/IC)
|
|
560
|
-
and the
|
|
775
|
+
and the backend-plan element (§/name) that now describe it, with CONFIDENCE
|
|
561
776
|
(certain | inferred). EVERY source file MUST appear — the Fidelity gate
|
|
562
777
|
checks full coverage both ways.
|
|
778
|
+
- THE CONCEPT IS THE AGGREGATE'S ('{{aggregate_primary}}') and lists every feature's
|
|
779
|
+
code on it. Where its `features:` names features besides '{{feature_name}}', a
|
|
780
|
+
file that serves ONLY one of those sibling capabilities is not this feature's:
|
|
781
|
+
record it under Unmapped / open as `sibling: <Feature>`, never as a mapped row.
|
|
782
|
+
The mapped rows ARE this feature's file list — later commands hand exactly those
|
|
783
|
+
files to their fix loops.
|
|
563
784
|
- Where this slice has a UI half, its files map the same way, to the UX-/US-
|
|
564
|
-
they realise and the
|
|
785
|
+
they realise and the frontend-plan.md section (§/name) that describes them —
|
|
565
786
|
one spine, both lanes. UI files to map: {{ui_source_files}}
|
|
566
787
|
- Also map DB tables, endpoints, and background jobs the slice owns.
|
|
567
788
|
- Fill the Seam section: the boundary this slice owns (endpoint / table
|
|
@@ -573,35 +794,58 @@ workflow:
|
|
|
573
794
|
- Baseline commit = the inventory HEAD.
|
|
574
795
|
Source files to map: {{source_files}}
|
|
575
796
|
|
|
576
|
-
#
|
|
577
|
-
#
|
|
578
|
-
# BLOCKING gaps = unmapped code / fabricated spec
|
|
579
|
-
# rest (inferred items, quirks, missing-invariant candidates) are
|
|
580
|
-
# → written to an Adopt Review report and closed OUT OF BAND (Brownfield
|
|
797
|
+
# ═══════ FIDELITY — do spec + model + plans describe the CODE? ══════════════
|
|
798
|
+
# documents ↔ CODE (NOT document ↔ document). The agent can READ the source files.
|
|
799
|
+
# BLOCKING gaps = unmapped code / a fabricated spec id, model element or plan element
|
|
800
|
+
# (structural). The rest (inferred items, quirks, missing-invariant candidates) are
|
|
801
|
+
# REVIEW items → written to an Adopt Review report and closed OUT OF BAND (Brownfield
|
|
802
|
+
# B1·R).
|
|
803
|
+
#
|
|
804
|
+
# THE MODEL IS JUDGED THE SAME WAY AS EVERYTHING ELSE, and it is the document most
|
|
805
|
+
# likely to be embellished: a reverse that "tidies" an anemic legacy slice into a clean
|
|
806
|
+
# aggregate produces a model the code does not have, which every later plan and slice
|
|
807
|
+
# gate would then be checked against. An invented entity, boundary or invariant is a
|
|
808
|
+
# fabrication exactly as an invented FR- is.
|
|
581
809
|
- id: fidelity
|
|
582
810
|
action: agent_query
|
|
583
811
|
context:
|
|
584
812
|
- "{{spec_file}}"
|
|
585
|
-
- "{{
|
|
586
|
-
-
|
|
813
|
+
- "{{domain_model}}"
|
|
814
|
+
- "{{backend_plan}}"
|
|
815
|
+
- { path: "{{frontend_plan}}", optional: true } # the lane's plan, where this slice has one
|
|
587
816
|
- "{{feature_dir}}/source-map.md"
|
|
588
817
|
- "{{concept_path}}"
|
|
589
818
|
include_standards: false
|
|
590
|
-
tools: Read # the check is
|
|
591
|
-
schema: { ok: true, report_needed: false, blocking_gaps: [ { severity: "high", artefact: "<source file / spec id /
|
|
819
|
+
tools: Read # the check is documents vs CODE; with no code it degrades to doc vs doc and certifies fabrication as ok
|
|
820
|
+
schema: { ok: true, report_needed: false, blocking_gaps: [ { severity: "high", artefact: "<source file / spec id / model element / plan element>", kind: "unmapped-code | fabricated-spec | fabricated-model | fabricated-plan", detail: "<why>" } ], review_items: [ { kind: "inferred | as-built-quirk | missing-invariant | confidence", where: "<spec/model/plan/source-map location>", note: "<what to confirm out of band>" } ] }
|
|
592
821
|
mock: { ok: true, report_needed: false, blocking_gaps: [], review_items: [] }
|
|
593
822
|
task: |
|
|
594
823
|
FIDELITY CHECK — do the reversed documents actually describe the CODE
|
|
595
|
-
(
|
|
824
|
+
(documents ↔ CODE, NOT document ↔ document)? Use the source-map (in context) and
|
|
596
825
|
READ the slice's source files (the concept's `source_files`, under
|
|
597
|
-
{{module_dir}}). Where
|
|
826
|
+
{{module_dir}}). Where frontend-plan.md is in context, it is judged the same way
|
|
598
827
|
against the slice's UI files ({{ui_source_files}}) — a screen, state store or
|
|
599
|
-
route it describes that the UI code does not have is a fabricated-
|
|
828
|
+
route it describes that the UI code does not have is a fabricated-plan, and a
|
|
600
829
|
UI file with no home in the source-map is unmapped-code. Classify findings:
|
|
601
830
|
- BLOCKING (structural — set ok=false if any):
|
|
602
|
-
(1) unmapped-code: a source file with NO
|
|
603
|
-
|
|
604
|
-
|
|
831
|
+
(1) unmapped-code: a source file with NO home in the source-map — one recorded
|
|
832
|
+
there as `sibling: <Feature>` has a home;
|
|
833
|
+
(2) fabricated-spec / fabricated-model / fabricated-plan: a spec id, model
|
|
834
|
+
element or plan element with NO basis in the code (reverse-engineering must
|
|
835
|
+
not invent behaviour or structure). For the MODEL specifically: an entity or
|
|
836
|
+
value object the code does not have, an aggregate boundary it does not draw,
|
|
837
|
+
a lifecycle state it never enters, or a BR-nnn whose rule nothing enforces.
|
|
838
|
+
An anemic slice reversing as an anemic model is CORRECT, not a gap.
|
|
839
|
+
- ONLY THIS FEATURE'S SECTIONS ARE THIS RUN'S. domain-model.md is the CONTEXT's and
|
|
840
|
+
may already carry sections from earlier adopted slices — judge ONLY
|
|
841
|
+
{{aggregate_sections}}. Do not report a sibling aggregate as unmapped because this
|
|
842
|
+
slice's code does not contain it. Where one of those sections' `Serving specs`
|
|
843
|
+
lists an EARLIER feature as well, the aggregate is shared: judge what this run
|
|
844
|
+
ADDED to it, and do not score the earlier feature's entities, states or
|
|
845
|
+
invariants as fabricated because this slice's code does not touch them.
|
|
846
|
+
- ALSO BLOCKING (fabricated-model): a `## Aggregate:` section this run created under
|
|
847
|
+
a name that is not one of {{aggregates_csv}} — most often '{{feature_name}}', the
|
|
848
|
+
feature's own name, used as if it were the aggregate's.
|
|
605
849
|
- REVIEW (does NOT block ok — these are the Adopt review worklist, closed out
|
|
606
850
|
of band): items marked "(inferred)"; as-built quirks the code shows but the
|
|
607
851
|
spec under-states; invariants the code enforces that may be missing/weak;
|
|
@@ -620,10 +864,10 @@ workflow:
|
|
|
620
864
|
condition: "{{report_needed}} == true"
|
|
621
865
|
action: agent_author
|
|
622
866
|
include_standards: false
|
|
623
|
-
context: ["{{spec_file}}", "{{
|
|
867
|
+
context: ["{{spec_file}}", "{{domain_model}}", "{{backend_plan}}", "{{feature_dir}}/source-map.md"]
|
|
624
868
|
output_target: { type: file, path: "{{feature_dir}}/adopt-review-report.md" }
|
|
625
869
|
task: |
|
|
626
|
-
Write an Adopt Review report (the target) for
|
|
870
|
+
Write an Adopt Review report (the target) for the feature '{{feature_name}}' (acting on {{aggregates_csv}}) —
|
|
627
871
|
the out-of-band worklist for this reverse-engineered baseline. Markdown:
|
|
628
872
|
- "# Adopt Review — {{feature_name}}" + today's date + "origin: reverse-engineered".
|
|
629
873
|
- "verdict:" line — "BLOCKING ✗ · <n>" if blocking gaps exist, else "REVIEW ○ · <m> item(s)".
|
|
@@ -637,22 +881,23 @@ workflow:
|
|
|
637
881
|
spec.md (a resolved [NEEDS CLARIFICATION] / Assumption) or log a deviation.
|
|
638
882
|
Review items: {{review_items}}
|
|
639
883
|
- "## How to proceed": resolve blocking gaps first; then the slice is a normal
|
|
640
|
-
feature — run /appweaver analyze-plan (spec↔
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
on-touch fence) — it is
|
|
884
|
+
feature — run /appweaver analyze-plan (the spec↔plan gate, which also checks both
|
|
885
|
+
plans against the context's domain model) if desired, then drive every change
|
|
886
|
+
through the CR delta loop. If a change edits untested legacy behaviour with blast
|
|
887
|
+
radius, characterize just that surface first (optional on-touch fence) — it is
|
|
888
|
+
not a required phase.
|
|
644
889
|
Return the report markdown only.
|
|
645
890
|
|
|
646
891
|
- id: fidelity_gate
|
|
647
892
|
action: verify_context
|
|
648
893
|
require_true: fidelity_ok
|
|
649
894
|
on_false: stop
|
|
650
|
-
on_false_message: "Fidelity FAILED for {{feature_name}} — the reversed
|
|
895
|
+
on_false_message: "Fidelity FAILED for {{feature_name}} — the reversed documents do not match the code (blocking gaps: {{blocking_gaps}}). See {{feature_dir}}/adopt-review-report.md. Fix the unmapped code / remove fabricated items (re-read the source, refine spec.md, {{domain_model}}, backend-plan.md and source-map.md), then re-run /appweaver adopt (after removing the dir) or resolve out of band. A `fabricated-model` gap means the reverse gave this slice structure its code does not have — an entity, a boundary, a lifecycle state or a BR-nnn nothing enforces; the fix is to record the domain as thin as the code really is, never to leave it flattering."
|
|
651
896
|
|
|
652
897
|
# ═══════════ OKF CONCEPT — COMPLETE the shallow scan concept (deep reverse) ═══
|
|
653
898
|
# onboard wrote this aggregate's OKF concept SHALLOW (a discovery stub — enough to pick the
|
|
654
|
-
# feature). Now that the deep reverse produced a TRUSTWORTHY spec.md +
|
|
655
|
-
# source-map.md, COMPLETE the concept: deepen its detail to the reversed reality, LINK the
|
|
899
|
+
# feature). Now that the deep reverse produced a TRUSTWORTHY spec.md + domain-model.md +
|
|
900
|
+
# backend-plan.md + source-map.md, COMPLETE the concept: deepen its detail to the reversed reality, LINK the
|
|
656
901
|
# authored artifacts, refresh source_files, and mark it ADOPTED. RECONCILE, not rewrite —
|
|
657
902
|
# keep OKF format + the bundle links; do NOT touch the Depends-On / Cross-References
|
|
658
903
|
# sections (xref_record owns those, next). Runs only after fidelity passes (deepened from
|
|
@@ -663,7 +908,8 @@ workflow:
|
|
|
663
908
|
context:
|
|
664
909
|
- { path: "{{concept_path}}" } # the shallow onboard concept to complete
|
|
665
910
|
- { path: "{{spec_file}}" } # the deep reversed spec (entities, US, BR/CN/DC/IC)
|
|
666
|
-
- { path: "{{
|
|
911
|
+
- { path: "{{domain_model}}" } # the deep reversed model (entities, boundary, invariants)
|
|
912
|
+
- { path: "{{backend_plan}}" } # the deep reversed plan (components, ports, integrations)
|
|
667
913
|
- { path: "{{feature_dir}}/source-map.md" } # the source anchor (files, seam, quirks)
|
|
668
914
|
- { path: .appweaver/templates/okf-concept-template.md } # OKF v0.1 format authority
|
|
669
915
|
- id: complete_concept
|
|
@@ -671,42 +917,57 @@ workflow:
|
|
|
671
917
|
tools: "Read,Write,Edit"
|
|
672
918
|
permission_mode: acceptEdits
|
|
673
919
|
task: |
|
|
674
|
-
COMPLETE the OKF
|
|
675
|
-
|
|
676
|
-
|
|
920
|
+
COMPLETE the OKF concept of the aggregate '{{aggregate_primary}}' at {{concept_path}} —
|
|
921
|
+
the aggregate this run adopted the feature '{{feature_name}}' over. onboard wrote it
|
|
922
|
+
SHALLOW (a discovery stub from the whole-repo scan). The deep reverse has now
|
|
923
|
+
produced a TRUSTWORTHY spec.md + domain-model.md + backend-plan.md + source-map.md (in
|
|
924
|
+
context); deepen the
|
|
677
925
|
concept to match and LINK those artifacts. Follow the OKF concept template in context.
|
|
926
|
+
THE CONCEPT IS THE AGGREGATE'S, NOT THE FEATURE'S. Where its `features:` names more
|
|
927
|
+
than one feature, another feature's adopt may already have deepened it, and nothing
|
|
928
|
+
that run wrote is this run's to remove — reconcile ADDITIVELY.
|
|
678
929
|
RECONCILE, do NOT rewrite:
|
|
679
930
|
- DEEPEN the responsibilities + the owned entities / value objects / domain events /
|
|
680
|
-
commands (user stories) / API endpoints / persistence to match the reversed spec
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
931
|
+
commands (user stories) / API endpoints / persistence to match the reversed spec,
|
|
932
|
+
model and plan — the ENTITIES and VALUE OBJECTS come from domain-model.md, which is
|
|
933
|
+
the authority on them; correct any drift the shallow scan got wrong (the deep docs
|
|
934
|
+
win). A sibling capability's commands and endpoints stay where they are.
|
|
935
|
+
- LINK the deep artifacts: add bundle links to {{feature_dir}}/spec.md,
|
|
936
|
+
backend-plan.md, source-map.md and the context's domain-model.md so the concept
|
|
937
|
+
points at the deep truth. Keep every link another feature's adopt added.
|
|
938
|
+
- UNION `source_files` with the source-map's mapped files (grouped by the code's OWN
|
|
939
|
+
folders, per OKF) — never drop a file already listed, which may be a sibling
|
|
940
|
+
capability's — and set `timestamp` to the baseline (inventory HEAD) commit time.
|
|
941
|
+
- Update frontmatter: keep `origin: reverse-engineered`; make sure `features:`
|
|
942
|
+
includes '{{feature_name}}'; stamp `generated_by: aw-spec-adopt`; and record that
|
|
943
|
+
'{{feature_name}}' is ADOPTED / deep-reversed. Where several features act on the
|
|
944
|
+
aggregate, record WHICH of them are adopted rather than marking the whole concept
|
|
945
|
+
done — the others are still shallow.
|
|
688
946
|
- Resolve any `open_questions` the deep reverse answered; keep the rest.
|
|
689
947
|
- Do NOT touch the concept's Depends-On / Cross-References sections (xref_record
|
|
690
948
|
maintains those next), and do NOT edit any OTHER aggregate concept.
|
|
691
|
-
Append a one-line `log.md` entry (bundle root) under today's date noting
|
|
692
|
-
was deep-adopted. Write ONLY {{concept_path}} (+ its dir index.md / bundle log.md if a
|
|
949
|
+
Append a one-line `log.md` entry (bundle root) under today's date noting the feature
|
|
950
|
+
'{{feature_name}}' of '{{aggregate_primary}}' was deep-adopted. Write ONLY {{concept_path}} (+ its dir index.md / bundle log.md if a
|
|
693
951
|
link or description changed). Report what you deepened.
|
|
694
952
|
outputs:
|
|
695
953
|
- { name: concept_completed, from: "$.files" }
|
|
696
954
|
|
|
697
|
-
# 3b. OKF cross-references (brownfield seed). The reversed
|
|
955
|
+
# 3b. OKF cross-references (brownfield seed). The reversed backend-plan.md now names this
|
|
698
956
|
# slice's cross-aggregate references (§1 References-by-id) + integration contracts
|
|
699
957
|
# (its External integrations table, IC-); record them into the shared OKF bundle — a
|
|
700
958
|
# Cross-References row in every
|
|
701
959
|
# SIBLING aggregate this slice uses (their inventory concepts already exist, so this
|
|
702
|
-
# resolves them rather than stubbing), plus
|
|
960
|
+
# resolves them rather than stubbing), plus the Depends-On of the aggregate this
|
|
961
|
+
# feature acts on — the union over every feature on that aggregate, so adopting one
|
|
962
|
+
# capability never erases another's edges. Keyed by --feature-dir so record resolves
|
|
963
|
+
# the aggregate itself rather than being told a feature name. Same
|
|
703
964
|
# reconcile-on-write helper as forward implement, stamped origin reverse-engineered,
|
|
704
965
|
# additive to the inventory bundle. Runs only after fidelity passes.
|
|
705
966
|
- id: xref_record
|
|
706
967
|
action: execute_script
|
|
707
968
|
script: { ref: xref }
|
|
708
969
|
subcommand: record
|
|
709
|
-
args: ["--
|
|
970
|
+
args: ["--feature-dir", "{{feature_dir}}", "--design", "{{backend_plan}}", "--bundle", "{{bundle_dir}}", "--origin", "reverse-engineered"]
|
|
710
971
|
outputs:
|
|
711
972
|
- { name: xref_wrote, from: "$.wrote" }
|
|
712
973
|
- { name: xref_edge_count, from: "$.edge_count" }
|
|
@@ -738,7 +999,7 @@ workflow:
|
|
|
738
999
|
action: build_context
|
|
739
1000
|
context:
|
|
740
1001
|
- { path: "{{spec_file}}" } # the feature's real BR-/CN-/DC-/IC-
|
|
741
|
-
- { path: "{{
|
|
1002
|
+
- { path: "{{backend_plan}}" }
|
|
742
1003
|
- { path: "{{feature_dir}}/source-map.md" }
|
|
743
1004
|
- { path: "guardrails/projects/{{gov_domain}}/domain-rule-bindings.md", optional: true }
|
|
744
1005
|
- { path: .appweaver/RULE-PARTITION.md } # the rule-partition authority (which command reads what)
|
|
@@ -751,7 +1012,7 @@ workflow:
|
|
|
751
1012
|
RECONCILE the domain rule-file set in guardrails/projects/{{gov_domain}}/domain/ with the
|
|
752
1013
|
newly-adopted feature '{{feature_name}}'. onboard authored these rule files from the
|
|
753
1014
|
whole-repo scan with per-feature specifics marked `PROVISIONAL — reconciled at
|
|
754
|
-
adopt`. READ this feature's reversed spec.md +
|
|
1015
|
+
adopt`. READ this feature's reversed spec.md + backend-plan.md + source-map.md (in
|
|
755
1016
|
context — the real evidence) and the EXISTING rule files under
|
|
756
1017
|
guardrails/projects/{{gov_domain}}/.
|
|
757
1018
|
|
|
@@ -780,7 +1041,7 @@ workflow:
|
|
|
780
1041
|
action: build_context
|
|
781
1042
|
context:
|
|
782
1043
|
- { path: "{{constitution_technical_file}}" }
|
|
783
|
-
- { path: "{{
|
|
1044
|
+
- { path: "{{backend_plan}}" }
|
|
784
1045
|
- { path: "{{feature_dir}}/source-map.md" }
|
|
785
1046
|
- id: reconcile_technical
|
|
786
1047
|
condition: "{{reconcile_governance}} == true" # HELD — governance reconcile paused (see vars)
|
|
@@ -790,7 +1051,7 @@ workflow:
|
|
|
790
1051
|
task: |
|
|
791
1052
|
RECONCILE the TECHNICAL constitution (target in context) with the adopted feature
|
|
792
1053
|
'{{feature_name}}'. onboard discovered the technology principle SET from the scan and
|
|
793
|
-
marked per-feature code coordinates `PROVISIONAL`. READ this feature's
|
|
1054
|
+
marked per-feature code coordinates `PROVISIONAL`. READ this feature's backend-plan.md +
|
|
794
1055
|
source-map.md (in context — the code-coordinate bridge: real file paths / type names).
|
|
795
1056
|
|
|
796
1057
|
RECONCILE, do NOT re-author:
|
|
@@ -921,12 +1182,19 @@ workflow:
|
|
|
921
1182
|
outputs:
|
|
922
1183
|
feature_dir: "{{feature_dir}}"
|
|
923
1184
|
spec_file: "{{spec_file}}"
|
|
924
|
-
|
|
925
|
-
|
|
1185
|
+
backend_plan: "{{backend_plan}}"
|
|
1186
|
+
frontend_plan: "{{frontend_plan}}" # empty where this slice has no UI half
|
|
1187
|
+
domain_model: "{{domain_model}}" # the CONTEXT's, shared — this run ADDED an aggregate section to it
|
|
1188
|
+
bounded_context: "{{context}}"
|
|
926
1189
|
ui_lane: "{{ui_lane}}"
|
|
927
1190
|
ui_count: "{{ui_count}}"
|
|
928
1191
|
source_map: "{{feature_dir}}/source-map.md"
|
|
929
|
-
|
|
1192
|
+
feature: "{{feature_name}}"
|
|
1193
|
+
# What the feature acts on. Equal to the feature on a 1:1 slice; not on a feature that
|
|
1194
|
+
# is one capability over a shared aggregate. aggregate_source says which of the spec,
|
|
1195
|
+
# the boundary map or the feature name answered.
|
|
1196
|
+
aggregate: "{{aggregates_csv}}"
|
|
1197
|
+
aggregate_source: "{{aggregate_source}}"
|
|
930
1198
|
source_count: "{{source_count}}"
|
|
931
1199
|
review_items: "{{review_items}}"
|
|
932
1200
|
concept_completed: "{{concept_completed}}"
|
|
@@ -936,4 +1204,4 @@ outputs:
|
|
|
936
1204
|
composed_file: "{{composed_file}}"
|
|
937
1205
|
technical_reconcile_ok: "{{technical_ok}}"
|
|
938
1206
|
domain_reconcile_ok: "{{domain_ok}}"
|
|
939
|
-
next: "Adopted {{feature_name}} (spec.md +
|
|
1207
|
+
next: "Adopted {{feature_name}} (spec.md + backend-plan.md + source-map.md, v1.0) and wrote {{aggregate_sections}} — the model section(s) for the aggregate(s) it acts on, resolved from the {{aggregate_source}} — in the bounded context `{{context}}`'s shared {{domain_model}}. The spec cites BR-nnn by id, the model carries their text, so this slice is checkable by the same gates as a greenfield one and analyze-plan's check 4 now has a model to check against. A section another feature over the same aggregate wrote first was EXTENDED, never duplicated; every other section is untouched. COMPLETED the OKF concept of {{aggregate_primary}} (deepened + linked the deep artifacts; {{xref_edge_count}} cross-slice edge(s) recorded). UI HALF: ui_lane={{ui_lane}} — where it is true this slice also has frontend-plan.md, reversed from the {{ui_count}} UI file(s) the feature map attributes to it; where it is false the repo declared no frontend lane, or this aggregate owns no part of its surface, and a service-only adoption is the correct outcome rather than a gap. The SHARED UI surface (app shell, layout, design system) belongs to no slice and stays in {{bundle_dir}}/architecture/frontend.md. NOTE — governance reconcile is currently HELD (reconcile_governance=false): this run did NOT modify the constitution halves or the guardrails/projects/{{gov_domain}}/ rule set, so they keep onboard's provisional scaffold. Close any items in {{feature_dir}}/adopt-review-report.md out of band. The slice is now a NORMAL feature: refine via /appweaver analyze-plan, 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 change edits untested legacy behaviour with blast radius, characterize just that surface first (optional on-touch fence). To restore governance reconcile, set reconcile_governance to \"true\" in the workflow vars."
|