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
|
@@ -153,7 +153,7 @@ workflow:
|
|
|
153
153
|
action: verify_context
|
|
154
154
|
require_non_empty: feature_dir
|
|
155
155
|
on_empty: stop
|
|
156
|
-
on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the
|
|
156
|
+
on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the feature, e.g. Order or PatientRegistration), then re-run analyze-plan-delta."
|
|
157
157
|
|
|
158
158
|
- id: verify_spec
|
|
159
159
|
action: verify_context
|
|
@@ -25,13 +25,30 @@
|
|
|
25
25
|
# rule set, without the template selection and without the feature's real source files,
|
|
26
26
|
# which is exactly the work `plan` does properly.
|
|
27
27
|
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
# the
|
|
32
|
-
# change
|
|
28
|
+
# TWO MODES, AND THE WRITE IS WHAT SEPARATES THEM. This stage NEVER opens, merges or
|
|
29
|
+
# closes a change; what it can do is REWRITE the master lane plans through its repair loop,
|
|
30
|
+
# and that is the act a change in flight forbids — the delta docs are the authoritative
|
|
31
|
+
# edit and the masters must not drift out from under them before finalize-delta merges.
|
|
32
|
+
# MASTER mode (no change open) — the full gate: check, ask, repair, and STOP on gaps
|
|
33
|
+
# that could not be reconciled. spec.md + the lane plans are the masters.
|
|
34
|
+
# REPORT mode (a change is open) — the same checks, read-only: no ask, no repair, no
|
|
35
|
+
# stop. It writes plan-analyze-report.md and routes on. The plans are
|
|
36
|
+
# DERIVED from spec.md + domain-model.md, so after finalize-delta merged a
|
|
37
|
+
# change the drift it reports is the EXPECTED consequence of that merge and
|
|
38
|
+
# the remedy is /appweaver plan main, not a repair here.
|
|
39
|
+
# Report mode exists because the finalize→close window is exactly when the plans are known
|
|
40
|
+
# to be stale, and a stage that refuses to look is not a gate. It reports; it never writes
|
|
41
|
+
# a plan.
|
|
42
|
+
#
|
|
43
|
+
# WHICH MODE IS READ FROM THE DIRECTORY, AND DEFAULTS TO REPORT. changes/<id>/ is the
|
|
44
|
+
# evidence (cr-list), not active_version.json's `active_change` — the ledger is the most
|
|
45
|
+
# recently OPENED change and a crashed run can leave the two disagreeing. The permission to
|
|
46
|
+
# write is RAISED only by cr-list answering that nothing is open, so a reading that never
|
|
47
|
+
# arrives leaves this stage read-only rather than rewriting masters mid-delta.
|
|
48
|
+
#
|
|
49
|
+
# The change is closed by close-delta, the SINGLE cr-archive caller, and only after
|
|
33
50
|
# finalize-delta has merged the delta into the masters. Also runnable on demand to
|
|
34
|
-
# re-anchor a hand-edited spec —
|
|
51
|
+
# re-anchor a hand-edited spec — in master mode, which means once every change is closed.
|
|
35
52
|
#
|
|
36
53
|
# RENAMED FROM `analyze-design`, following design → plan. It also absorbs the ⌛
|
|
37
54
|
# `analyze-design-ui` phase that was never built as its own command: the frontend lane is
|
|
@@ -42,8 +59,8 @@
|
|
|
42
59
|
# =============================================================================
|
|
43
60
|
|
|
44
61
|
name: aw-spec-analyze-plan
|
|
45
|
-
description: The spec↔plan conformance gate for every declared lane — confirm backend-plan.md and frontend-plan.md follow spec.md, that they bind to each other's contract, and that neither contradicts the bounded context's domain model (domain overlays are a backstop); with approval, repair the drifting plan. Lanes come from .appweaver/stacks.json, so one command gates backend-only, frontend-only and full-stack projects.
|
|
46
|
-
version: 3.
|
|
62
|
+
description: The spec↔plan conformance gate for every declared lane — confirm backend-plan.md and frontend-plan.md follow spec.md, that they bind to each other's contract, and that neither contradicts the bounded context's domain model (domain overlays are a backstop); with approval, repair the drifting plan. Lanes come from .appweaver/stacks.json, so one command gates backend-only, frontend-only and full-stack projects. Runs in one of two modes, decided from the changes/ directory rather than the ledger and defaulting to the read-only one — MASTER (no change open) checks, repairs on approval and stops on unreconciled gaps; REPORT (a change open) runs the same checks read-only and writes plan-analyze-report.md without asking, repairing or stopping, because the master plans may not be rewritten while a delta is in flight. It never opens, merges or closes a change.
|
|
63
|
+
version: 3.2.0
|
|
47
64
|
agent_agnostic: true
|
|
48
65
|
dialect: aw-spec.orchestrator/v1
|
|
49
66
|
|
|
@@ -58,9 +75,23 @@ standards:
|
|
|
58
75
|
vars:
|
|
59
76
|
analyze_ok: "false"
|
|
60
77
|
active_change: ""
|
|
61
|
-
has_change: "false"
|
|
62
78
|
version: ""
|
|
63
|
-
|
|
79
|
+
# WHICH MODE THIS RUN IS IN, read from the changes/ DIRECTORY and defaulted to the
|
|
80
|
+
# read-only answer. has_changes starts at the BLOCKING value because an unanswered
|
|
81
|
+
# question is not a clean answer: cr-list runs without on_error: continue, so a failure
|
|
82
|
+
# stops the run outright, and a field that never arrived leaves this stage read-only
|
|
83
|
+
# instead of letting the repair loop rewrite master plans while a delta is in flight.
|
|
84
|
+
has_changes: "true"
|
|
85
|
+
open_ids: "" # cr-list's ids_csv — what is open, named, for the operator
|
|
86
|
+
open_count: "0"
|
|
87
|
+
no_open_change: "false" # RAISED only by cr-list answering that nothing is open
|
|
88
|
+
gate_mode: "report" # report | master — reported in the outputs
|
|
89
|
+
may_repair: "false" # the ask, the repair loop and the conformance stop are MASTER-only
|
|
90
|
+
gate_ok: "false" # raised by a conformant run OR by report mode, which cannot repair
|
|
91
|
+
stamp_receipt: "false" # master mode AND conformant ⇒ leave the receipt implement reads
|
|
92
|
+
receipt_file: ""
|
|
93
|
+
receipt_gated: ""
|
|
94
|
+
receipt_count: "0"
|
|
64
95
|
lanes_declared: "false"
|
|
65
96
|
be_declared: "false"
|
|
66
97
|
fe_declared: "false"
|
|
@@ -91,6 +122,10 @@ vars:
|
|
|
91
122
|
be_plan_ctx: ""
|
|
92
123
|
fe_plan_ctx: ""
|
|
93
124
|
domain_model: ""
|
|
125
|
+
owned_sections: "" # the model section(s) this feature answers for — feature-aggregates
|
|
126
|
+
shared_with_csv: ""
|
|
127
|
+
one_to_one: "true"
|
|
128
|
+
model_scope_plan: "" # which part of those sections check 4(a) holds the plan to
|
|
94
129
|
|
|
95
130
|
workflow:
|
|
96
131
|
|
|
@@ -144,11 +179,40 @@ workflow:
|
|
|
144
179
|
- { name: domain_model, from: "$.domain_model" }
|
|
145
180
|
- { name: domain_model_exists, from: "$.domain_model_exists" }
|
|
146
181
|
|
|
182
|
+
# WHICH PART OF THAT MODEL CHECK 4 HOLDS THE PLAN TO. A feature is a capability scope the
|
|
183
|
+
# developer chose — it may act on several aggregates, and several features may act on
|
|
184
|
+
# one — so "the plan matches its aggregate's section" is only exact for a feature that
|
|
185
|
+
# alone answers for that aggregate. Resolved from the spec's Acts-on line, then the
|
|
186
|
+
# boundary map, then the feature name.
|
|
187
|
+
- id: feature_aggregates
|
|
188
|
+
action: execute_script
|
|
189
|
+
on_error: continue
|
|
190
|
+
script: { ref: xref }
|
|
191
|
+
subcommand: feature-aggregates
|
|
192
|
+
args: ["--feature-dir", "{{feature_dir}}"]
|
|
193
|
+
outputs:
|
|
194
|
+
- { name: owned_sections, from: "$.owned_sections" }
|
|
195
|
+
- { name: shared_with_csv, from: "$.shared_with_csv" }
|
|
196
|
+
- { name: one_to_one, from: "$.one_to_one" }
|
|
197
|
+
|
|
198
|
+
# A shared section is realised by several plans, each covering what its own feature
|
|
199
|
+
# acts on; flagging every element one plan leaves out would fail each of them for work
|
|
200
|
+
# another feature's plan carries. Ordered pair of sets — no conditional prompt text.
|
|
201
|
+
- id: model_scope_shared
|
|
202
|
+
action: set
|
|
203
|
+
vars:
|
|
204
|
+
model_scope_plan: "{{owned_sections}}, which this feature SHARES with other features: every element the plan realises must carry the model's name and sit inside the model's boundary, but an element of the section the plan leaves out is NOT a gap unless this feature's requirements act on it — another feature's plan realises it"
|
|
205
|
+
- id: model_scope_sole
|
|
206
|
+
condition: "{{one_to_one}} == true"
|
|
207
|
+
action: set
|
|
208
|
+
vars:
|
|
209
|
+
model_scope_plan: "{{owned_sections}}. This feature is the only one that answers for it, so the plan's domain layer must realise that whole section"
|
|
210
|
+
|
|
147
211
|
- id: require_feature
|
|
148
212
|
action: verify_context
|
|
149
213
|
require_non_empty: feature_dir
|
|
150
214
|
on_empty: stop
|
|
151
|
-
on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the
|
|
215
|
+
on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the feature, e.g. Order or PatientRegistration), then re-run analyze-plan."
|
|
152
216
|
|
|
153
217
|
- id: verify_spec
|
|
154
218
|
action: verify_context
|
|
@@ -156,33 +220,46 @@ workflow:
|
|
|
156
220
|
on_false: stop
|
|
157
221
|
on_false_message: "No spec.md for the current feature. Run /appweaver specify (and /appweaver plan) first."
|
|
158
222
|
|
|
159
|
-
# 1b.
|
|
160
|
-
#
|
|
161
|
-
-
|
|
223
|
+
# 1b. IS ANY CHANGE OPEN — asked of the changes/ DIRECTORY, which is what "open" means.
|
|
224
|
+
# Not version-read's `has_change`: that is bool(active_change), the most recently
|
|
225
|
+
# OPENED change in active_version.json, and a run that died between cr-setup writing
|
|
226
|
+
# the directory and the ledger recording it leaves the two disagreeing. The stage
|
|
227
|
+
# that may rewrite masters has to read the authority every other delta stage reads.
|
|
228
|
+
# No on_error: continue — a cr-list that cannot answer stops the run.
|
|
229
|
+
- id: cr_list
|
|
162
230
|
action: execute_script
|
|
163
231
|
script: { ref: actions }
|
|
164
|
-
subcommand:
|
|
232
|
+
subcommand: cr-list
|
|
165
233
|
args: ["--feature-dir", "{{feature_dir}}"]
|
|
166
234
|
outputs:
|
|
235
|
+
- { name: has_changes, from: "$.has_changes" }
|
|
236
|
+
- { name: open_ids, from: "$.ids_csv" }
|
|
237
|
+
- { name: open_count, from: "$.count" }
|
|
167
238
|
- { name: active_change, from: "$.active_change" }
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
239
|
+
|
|
240
|
+
- id: read_version
|
|
241
|
+
action: execute_script
|
|
242
|
+
script: { ref: actions }
|
|
243
|
+
subcommand: version-read
|
|
244
|
+
args: ["--feature-dir", "{{feature_dir}}"]
|
|
245
|
+
outputs:
|
|
246
|
+
- { name: version, from: "$.version" }
|
|
247
|
+
|
|
248
|
+
# 1c. THE WRITE PERMISSION, raised then verified. Nothing open ⇒ spec.md + the lane plans
|
|
249
|
+
# ARE the masters ⇒ this stage owns them and may repair. Anything else — a change
|
|
250
|
+
# open, or an answer that never arrived — leaves may_repair down and the run is
|
|
251
|
+
# read-only: the checks still run and still report, but no plan is rewritten under a
|
|
252
|
+
# delta in flight. The permission is raised by the good state, never knocked down by
|
|
253
|
+
# the bad one, so the failure direction is refusal to write.
|
|
254
|
+
- id: no_open_change_raise
|
|
255
|
+
condition: "{{has_changes}} == false"
|
|
178
256
|
action: set
|
|
179
|
-
vars: { no_open_change: "
|
|
257
|
+
vars: { no_open_change: "true" }
|
|
180
258
|
|
|
181
|
-
- id:
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
on_false_message: "Change {{active_change}} is OPEN on this feature — analyze-plan is the BOOTSTRAP gate and must not rewrite the master plans while a delta is in flight. Gate the delta instead: /appweaver analyze-plan-delta → implement → build → analyze-slice-delta → finalize-delta (merges the delta into spec.md and domain-model.md — not the lane plans, which are derived from those two) → analyze-slice → close-delta (archives the change + bumps the version). Re-run analyze-plan once every change is closed, to re-anchor the masters."
|
|
259
|
+
- id: enter_master_mode
|
|
260
|
+
condition: "{{no_open_change}} == true"
|
|
261
|
+
action: set
|
|
262
|
+
vars: { gate_mode: "master", may_repair: "true" }
|
|
186
263
|
|
|
187
264
|
# 2. WHICH LANES ARE GATED. Present = declared AND on disk; missing = declared AND not.
|
|
188
265
|
# Taking the lane's own `declared` value under the exists condition is how the AND is
|
|
@@ -344,9 +421,10 @@ workflow:
|
|
|
344
421
|
|
|
345
422
|
CHECK 4 — the plans → domain-model.md (when the model is in context; skip if it
|
|
346
423
|
is not):
|
|
347
|
-
(a) the backend plan's DOMAIN layer matches the model EXACTLY
|
|
348
|
-
|
|
349
|
-
its Boundary block, states are
|
|
424
|
+
(a) the backend plan's DOMAIN layer matches the model EXACTLY. The section(s)
|
|
425
|
+
this feature answers for: {{model_scope_plan}}. Entities and value objects carry
|
|
426
|
+
the section's names (SAME names), the boundary is its Boundary block, states are
|
|
427
|
+
the lifecycle it describes;
|
|
350
428
|
(b) EVERY invariant (BR-nnn) the spec cites has a named ENFORCEMENT POINT in the
|
|
351
429
|
backend plan. An invariant nothing enforces is a HIGH gap; a plan that RESTATES
|
|
352
430
|
what an invariant says instead of citing it by id is a gap too — the model is the
|
|
@@ -378,6 +456,45 @@ workflow:
|
|
|
378
456
|
- id: conform_break
|
|
379
457
|
action: break
|
|
380
458
|
condition: "{{analyze_ok}} == true"
|
|
459
|
+
|
|
460
|
+
# REPORT MODE — a change is open (or the mode could not be established), so the
|
|
461
|
+
# master plans are off limits and there is nothing to ask: repair is not on offer.
|
|
462
|
+
# Write the report and leave the loop. The report itself has to name the two
|
|
463
|
+
# readings, because the same gaps mean opposite things either side of the merge.
|
|
464
|
+
- id: write_report_readonly
|
|
465
|
+
condition: "{{may_repair}} == false"
|
|
466
|
+
action: agent_author
|
|
467
|
+
include_standards: false
|
|
468
|
+
output_target: { type: file, path: "{{feature_dir}}/plan-analyze-report.md" }
|
|
469
|
+
task: |
|
|
470
|
+
Write a Plan Analyze Report to the output from these spec↔plan conformance gaps
|
|
471
|
+
(spec.md is the ANCHOR). This run was READ-ONLY: change(s) {{open_ids}} are open
|
|
472
|
+
on this feature, so the master lane plans were checked but NOT repaired.
|
|
473
|
+
{{analyze_gaps}}
|
|
474
|
+
Markdown format:
|
|
475
|
+
- "# Plan Analyze Report — <aggregate>" plus today's date.
|
|
476
|
+
- A verdict line: "verdict: GAPS ✗ · <n> gap(s) · read-only (change open: {{open_ids}})".
|
|
477
|
+
- "## Gaps" as a table: | # | check | lane | severity | spec ref | plan location | gap |.
|
|
478
|
+
- "## How to read this" — state BOTH readings and that only the operator knows
|
|
479
|
+
which applies, because it depends on whether finalize-delta has already run:
|
|
480
|
+
(a) AFTER finalize-delta merged a change, these gaps are EXPECTED. The lane
|
|
481
|
+
plans are DERIVED from spec.md + domain-model.md and finalize-delta merges the
|
|
482
|
+
change into those two documents only, so the plans stand at their last authored
|
|
483
|
+
content and the spec has moved ahead of them. The remedy is
|
|
484
|
+
/appweaver plan main (which re-derives them, carrying DA-n / WA-n forward),
|
|
485
|
+
after /appweaver close-delta, not a repair of either plan.
|
|
486
|
+
(b) BEFORE finalize-delta, the masters have not moved, so these gaps are real
|
|
487
|
+
master drift — but this is still not the stage that fixes it, because the
|
|
488
|
+
change in flight is planned in its OWN delta plans. Gate those with
|
|
489
|
+
/appweaver analyze-plan-delta, and re-run /appweaver analyze-plan in master
|
|
490
|
+
mode once every change is closed.
|
|
491
|
+
- "## Not repaired here": this report is the whole output of a read-only run. No
|
|
492
|
+
plan document was written.
|
|
493
|
+
Return the complete report markdown only.
|
|
494
|
+
- id: readonly_break
|
|
495
|
+
action: break
|
|
496
|
+
condition: "{{may_repair}} == false"
|
|
497
|
+
|
|
381
498
|
- id: ask_repair
|
|
382
499
|
action: ask
|
|
383
500
|
prompt: |
|
|
@@ -501,13 +618,53 @@ workflow:
|
|
|
501
618
|
already-conformant section VERBATIM.
|
|
502
619
|
Return the COMPLETE updated frontend-plan.md content only.
|
|
503
620
|
|
|
621
|
+
# THE STOP IS MASTER MODE'S ALONE. Two independent raises, because the two reasons to
|
|
622
|
+
# pass are unrelated: the plans conform, or this run was never allowed to change them.
|
|
623
|
+
# A read-only run that found gaps has done its whole job by reporting them — stopping
|
|
624
|
+
# would fail the operator for drift that finalize-delta created on purpose and that only
|
|
625
|
+
# /appweaver plan main can close.
|
|
626
|
+
- id: gate_ok_conformant
|
|
627
|
+
condition: "{{analyze_ok}} == true"
|
|
628
|
+
action: set
|
|
629
|
+
vars: { gate_ok: "true" }
|
|
630
|
+
- id: gate_ok_readonly
|
|
631
|
+
condition: "{{may_repair}} == false"
|
|
632
|
+
action: set
|
|
633
|
+
vars: { gate_ok: "true" }
|
|
634
|
+
|
|
504
635
|
- id: analyze_gate
|
|
505
636
|
action: verify_context
|
|
506
|
-
require_true:
|
|
637
|
+
require_true: gate_ok
|
|
507
638
|
on_false: stop
|
|
508
639
|
on_false_message: "The lane plans do not conform to the spec (gaps: {{analyze_gaps}}) — repair was skipped (see plan-analyze-report.md), or it could not be reconciled in 3 passes. A 'LIFT-FAILURE:' gap means a domain constraint from the gate checklist was never lifted into the spec, and a `model` gap means the plan needs an entity or invariant domain-model.md does not define — both are fixed by /appweaver specify, which authors the spec and the model; this gate may not write either. A `contract` gap is closed in the lane its row names. Otherwise fix out of band, or re-run and choose Repair."
|
|
509
640
|
|
|
510
|
-
#
|
|
641
|
+
# THE RECEIPT. implement generates from the plans and deliberately does not read the
|
|
642
|
+
# spec, on the strength of this stage having conformed them to it — which until now was
|
|
643
|
+
# an assumption about the order the operator ran things in, checked by nothing. Record
|
|
644
|
+
# WHAT was proven: the bytes of spec.md, the context's domain-model.md and each lane plan
|
|
645
|
+
# that was present. plan-gate-check reads it at implement.
|
|
646
|
+
#
|
|
647
|
+
# ONLY A GREEN MASTER RUN LEAVES ONE. The AND is the kit's ordered assignment — under
|
|
648
|
+
# master mode, take the conformance verdict as the answer — because the engine has no
|
|
649
|
+
# compound conditions. A REPORT-mode run proves nothing about the masters (it may not
|
|
650
|
+
# even repair them), and a red master run proved the opposite.
|
|
651
|
+
- id: flag_receipt
|
|
652
|
+
condition: "{{may_repair}} == true"
|
|
653
|
+
action: set
|
|
654
|
+
vars: { stamp_receipt: "{{analyze_ok}}" }
|
|
655
|
+
|
|
656
|
+
- id: plan_gate_stamp
|
|
657
|
+
condition: "{{stamp_receipt}} == true"
|
|
658
|
+
action: execute_script
|
|
659
|
+
script: { ref: actions }
|
|
660
|
+
subcommand: plan-gate-stamp
|
|
661
|
+
args: ["--feature-dir", "{{feature_dir}}", "--spec-version", "{{version}}", "--mode", "{{gate_mode}}"]
|
|
662
|
+
outputs:
|
|
663
|
+
- { name: receipt_file, from: "$.file" }
|
|
664
|
+
- { name: receipt_gated, from: "$.gated" }
|
|
665
|
+
- { name: receipt_count, from: "$.count" }
|
|
666
|
+
|
|
667
|
+
# (No change-close here by design — this stage never archives anything in either mode,
|
|
511
668
|
# and cr-archive belongs to close-delta, which runs after finalize-delta's merge.)
|
|
512
669
|
|
|
513
670
|
# 6. Post-execution hooks.
|
|
@@ -531,5 +688,9 @@ outputs:
|
|
|
531
688
|
conformant: "{{analyze_ok}}"
|
|
532
689
|
gaps: "{{analyze_gaps}}"
|
|
533
690
|
version: "{{version}}"
|
|
534
|
-
|
|
535
|
-
|
|
691
|
+
gate_mode: "{{gate_mode}}" # master (repair allowed) | report (read-only)
|
|
692
|
+
open_changes: "{{open_ids}}" # empty in master mode, by definition
|
|
693
|
+
gate_receipt: "{{receipt_file}}" # written only by a GREEN master run; implement reads it
|
|
694
|
+
gate_receipt_at: "{{receipt_gated}}"
|
|
695
|
+
note: "Ran in {{gate_mode}} mode ({{open_count}} change(s) open: {{open_ids}}). Checked: spec→backend-plan ({{be_present}}), spec→frontend-plan ({{fe_present}}), the plan↔plan contract binding ({{both_lanes}} — it needs both lanes) and both plans against domain-model.md. The domain model was READ, never written: a gap that needs a new entity, event or invariant is fixed by /appweaver specify. In REPORT mode no plan was rewritten either — the master plans are derived documents and may not move while a delta is in flight."
|
|
696
|
+
next: "MASTER mode (no change open, conformant={{analyze_ok}}): /appweaver implement — the plans conform to the spec; version unchanged, this gate closes nothing. REPORT mode (change(s) {{open_ids}} open): this run was read-only and wrote plan-analyze-report.md only. If finalize-delta has already merged, the gaps ARE that merge — the lane plans are derived from spec.md + domain-model.md and finalize-delta moves only those two, so re-derive with /appweaver plan main after /appweaver close-delta, then re-run /appweaver analyze-plan in master mode. If the change has NOT merged yet, gate it where it lives: /appweaver analyze-plan-delta."
|
|
@@ -182,7 +182,7 @@ workflow:
|
|
|
182
182
|
action: verify_context
|
|
183
183
|
require_non_empty: feature_dir
|
|
184
184
|
on_empty: stop
|
|
185
|
-
on_empty_message: "No active feature. Run /appweaver select-feature first (pick the
|
|
185
|
+
on_empty_message: "No active feature. Run /appweaver select-feature first (pick the feature, e.g. Order or PatientRegistration), then re-run analyze-slice-delta."
|
|
186
186
|
|
|
187
187
|
# 3. WHICH CHANGE. Same selection contract as plan, analyze-plan-delta and implement:
|
|
188
188
|
# cr-list enumerates the open changes (evidence = changes/<CR-id>/ on disk), a bare CR
|
|
@@ -3,13 +3,17 @@
|
|
|
3
3
|
#
|
|
4
4
|
# The second of the two discrete conformance gates on the forward path, and the
|
|
5
5
|
# sibling of analyze-plan:
|
|
6
|
-
# analyze-plan gates spec ↔
|
|
7
|
-
# analyze-slice gates
|
|
6
|
+
# analyze-plan gates spec + model ↔ plans — STATIC, before implement
|
|
7
|
+
# analyze-slice gates spec + model ↔ code — DYNAMIC, after build
|
|
8
|
+
# Both anchor on the same two masters. The difference is what they score against them and
|
|
9
|
+
# how: analyze-plan reads documents and never runs anything; this gate runs the slice's
|
|
10
|
+
# tests and reads the code they cover.
|
|
8
11
|
# "Slice" is the unit under analysis: the aggregate's code, its paired tests, and
|
|
9
12
|
# its OKF knowledge concept. Three passes over it —
|
|
10
13
|
# 1. BEHAVIOUR run the tests (paired to the spec's acceptance criteria by the
|
|
11
14
|
# design docs); on red, fix up to 3×.
|
|
12
|
-
# 2. CONFORMANCE check the code against the domain gate overlays
|
|
15
|
+
# 2. CONFORMANCE check the code against the domain gate overlays AND the bounded
|
|
16
|
+
# context's domain-model.md (validate-only).
|
|
13
17
|
# 3. KNOWLEDGE refresh + review the slice's OKF concept (advisory).
|
|
14
18
|
# Every fix made here is recorded in that concept, which is also where the slice's
|
|
15
19
|
# file list is READ from (2.3.0 — `aw-xref concept-paths`, replacing the retired
|
|
@@ -17,7 +21,22 @@
|
|
|
17
21
|
# longer carries; the paired `design-reconcile` write-back is retired with it, its job
|
|
18
22
|
# already done by the concept-upsert --merge steps in pass 3).
|
|
19
23
|
#
|
|
20
|
-
# TWO
|
|
24
|
+
# TWO MASTERS, NOT ONE (2.4.0). The spec says what the feature must DO; the bounded
|
|
25
|
+
# context's domain-model.md says what the domain IS — the aggregate boundary, the entities,
|
|
26
|
+
# and the text of every invariant the spec cites by BR id. Since the model split, the spec
|
|
27
|
+
# carries the ids and not the rules, so a gate reading only the spec scores code against a
|
|
28
|
+
# document that no longer states what it is checking for. Both are in every pass's context
|
|
29
|
+
# and the conformance pass scores against both.
|
|
30
|
+
#
|
|
31
|
+
# SCOPE IS WHAT KEEPS THE MODEL FAIR HERE. domain-model.md describes the whole context
|
|
32
|
+
# while this gate scores ONE feature. An invariant under the slice's own `## Aggregate:`
|
|
33
|
+
# section is BLOCKING — unenforced or enforced differently than stated is a violation, and
|
|
34
|
+
# so is naming an entity or field differently from the model. An invariant under another
|
|
35
|
+
# aggregate's section is REPORTED and never blocking: this slice does not own it and often
|
|
36
|
+
# should not enforce it. A feature outside every bounded context has no model, and the pass
|
|
37
|
+
# degrades to overlays + spec, exactly as it behaved before.
|
|
38
|
+
#
|
|
39
|
+
# TWO POSITIONS, one gate — and in BOTH the merged masters are the whole truth:
|
|
21
40
|
# BOOTSTRAP implement → build → analyze-slice → run
|
|
22
41
|
# CHANGE implement (the delta) → build → analyze-slice-delta → finalize-delta
|
|
23
42
|
# → analyze-slice → close-delta
|
|
@@ -42,8 +61,8 @@
|
|
|
42
61
|
# =============================================================================
|
|
43
62
|
|
|
44
63
|
name: aw-spec-analyze-slice
|
|
45
|
-
description: The design↔code conformance gate — run the slice's tests against its acceptance criteria, check the code against the domain gate overlays, verify the change did not break any referring aggregate (the OKF referrer blast radius) and write a triage report before stopping if it did, refresh + review its OKF concept, and record every fix in it. Sits after finalize-delta on the change path, so the
|
|
46
|
-
version: 2.
|
|
64
|
+
description: The design↔code conformance gate — run the slice's tests against its acceptance criteria, check the code against the domain gate overlays AND the bounded context's domain-model.md (every invariant the slice's own aggregate section states must be enforced as written; one another aggregate owns is reported, not blocking), verify the change did not break any referring aggregate (the OKF referrer blast radius) and write a triage report before stopping if it did, refresh + review its OKF concept, and record every fix in it. Sits after finalize-delta on the change path, so the two masters it scores against already carry the change, and before close-delta, so a red gate leaves the change open and recoverable.
|
|
65
|
+
version: 2.4.0
|
|
47
66
|
agent_agnostic: true
|
|
48
67
|
dialect: aw-spec.orchestrator/v1
|
|
49
68
|
|
|
@@ -69,6 +88,10 @@ standards:
|
|
|
69
88
|
vars:
|
|
70
89
|
test_ok: "false"
|
|
71
90
|
conformance_ok: "false"
|
|
91
|
+
# Invariants the model states under ANOTHER aggregate's section that this slice appears
|
|
92
|
+
# to touch — reported, never blocking, since this slice does not own them. Defaulted so
|
|
93
|
+
# the gate message and the outputs read a real value on a run that skipped the pass.
|
|
94
|
+
model_notes: ""
|
|
72
95
|
# NAVIGATION ONLY. Whether a change is open decides where this gate sends you next
|
|
73
96
|
# (close-delta vs run) — nothing else in this workflow reads them. On the CHANGE path
|
|
74
97
|
# finalize-delta has already merged the delta into the master docs, so the delta files
|
|
@@ -105,6 +128,7 @@ workflow:
|
|
|
105
128
|
script: { ref: actions }
|
|
106
129
|
subcommand: feature-paths
|
|
107
130
|
outputs:
|
|
131
|
+
- { name: feature, from: "$.feature" }
|
|
108
132
|
- { name: feature_dir, from: "$.feature_dir" }
|
|
109
133
|
- { name: spec_file, from: "$.spec_file" }
|
|
110
134
|
|
|
@@ -112,7 +136,63 @@ workflow:
|
|
|
112
136
|
action: verify_context
|
|
113
137
|
require_non_empty: feature_dir
|
|
114
138
|
on_empty: stop
|
|
115
|
-
on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the
|
|
139
|
+
on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the feature, e.g. Order or PatientRegistration), then re-run analyze-slice."
|
|
140
|
+
|
|
141
|
+
# The bounded context's DOMAIN MODEL — in every pass's context beside the spec, and the
|
|
142
|
+
# authority the conformance pass scores against. Since the model split the spec no longer
|
|
143
|
+
# states the aggregate boundary, the entities or the text of an invariant: it cites BR-nnn
|
|
144
|
+
# by id and the model holds them. A gate reading only the spec therefore scores code
|
|
145
|
+
# against a document that no longer carries what it is checking for.
|
|
146
|
+
#
|
|
147
|
+
# On the CHANGE path this gate runs after finalize-delta, which has already merged the
|
|
148
|
+
# change's model half into the master — so the master is complete here and the change's
|
|
149
|
+
# `domain-model.<CR>.delta.md` is deliberately NOT loaded, exactly as its delta-spec is not.
|
|
150
|
+
#
|
|
151
|
+
# optional: on every context entry below, because a feature outside every bounded context
|
|
152
|
+
# legitimately has no model and a required file that is missing announces itself.
|
|
153
|
+
# on_error: continue for the same reason — a missing model degrades this gate to its
|
|
154
|
+
# pre-model behaviour (spec + overlays), it never blocks.
|
|
155
|
+
- id: context_paths
|
|
156
|
+
action: execute_script
|
|
157
|
+
on_error: continue
|
|
158
|
+
script: { ref: actions }
|
|
159
|
+
subcommand: context-paths
|
|
160
|
+
outputs:
|
|
161
|
+
- { name: context, from: "$.context" }
|
|
162
|
+
- { name: domain_model, from: "$.domain_model" }
|
|
163
|
+
- { name: domain_model_exists, from: "$.domain_model_exists" }
|
|
164
|
+
|
|
165
|
+
# WHICH PART OF THAT MODEL THIS GATE SCORES. The model is filed by aggregate, the specs
|
|
166
|
+
# tree by feature. For a feature that is one capability over a shared aggregate
|
|
167
|
+
# (PatientRegistration over Patient) no section carries the feature's name, and scoring
|
|
168
|
+
# "the BR-nnn under this feature's section" found none and PASSED — every invariant the
|
|
169
|
+
# feature relies on silently demoted to a non-blocking note. Resolved from the spec's
|
|
170
|
+
# Acts-on line, then the boundary map, then the feature name.
|
|
171
|
+
- id: feature_aggregates
|
|
172
|
+
action: execute_script
|
|
173
|
+
script: { ref: xref }
|
|
174
|
+
subcommand: feature-aggregates
|
|
175
|
+
args: ["--feature-dir", "{{feature_dir}}"]
|
|
176
|
+
outputs:
|
|
177
|
+
- { name: owned_sections, from: "$.owned_sections" }
|
|
178
|
+
- { name: one_to_one, from: "$.one_to_one" }
|
|
179
|
+
|
|
180
|
+
# WHICH OF THOSE INVARIANTS BLOCK. A feature that alone answers for an aggregate owns
|
|
181
|
+
# its section outright, and every BR-nnn under it has to be enforced in this code. A
|
|
182
|
+
# feature that shares the aggregate with other features — whatever it is named —
|
|
183
|
+
# answers only for what its spec cites: the rest of that section is the other features'
|
|
184
|
+
# code, and blocking on it would fail each of them for work another one does. The
|
|
185
|
+
# engine has no conditional prompt text, so the rule is chosen by an ordered pair of
|
|
186
|
+
# sets and handed to the pass as one sentence.
|
|
187
|
+
- id: model_scope_capability
|
|
188
|
+
action: set
|
|
189
|
+
vars:
|
|
190
|
+
model_scope_rule: "this feature SHARES those sections with other features, so BLOCKING covers only the BR-nnn this feature's spec CITES from them; any other BR-nnn stated there belongs to another feature and is a model_notes entry, not a violation"
|
|
191
|
+
- id: model_scope_owned
|
|
192
|
+
condition: "{{one_to_one}} == true"
|
|
193
|
+
action: set
|
|
194
|
+
vars:
|
|
195
|
+
model_scope_rule: "this feature is the ONLY one that answers for that section, so BLOCKING covers EVERY BR-nnn stated there, whether or not the spec cites it"
|
|
116
196
|
|
|
117
197
|
# Is a change OPEN on this feature? Read for NAVIGATION only — see the vars note. Safe
|
|
118
198
|
# on the bootstrap path: with no active_version.json, version-read returns
|
|
@@ -185,6 +265,7 @@ workflow:
|
|
|
185
265
|
test_log: "{{test_log}}"
|
|
186
266
|
context:
|
|
187
267
|
- { path: "{{spec_file}}" }
|
|
268
|
+
- { path: "{{domain_model}}", optional: true }
|
|
188
269
|
context_from: all_paths
|
|
189
270
|
- id: fix
|
|
190
271
|
action: agent_generate
|
|
@@ -193,7 +274,10 @@ workflow:
|
|
|
193
274
|
task: |
|
|
194
275
|
Tests failed. Make them pass by fixing the code (or a genuinely wrong
|
|
195
276
|
test) in the files in context, keeping behaviour aligned with the spec's
|
|
196
|
-
acceptance criteria (spec in context).
|
|
277
|
+
acceptance criteria (spec in context). Where the spec cites an invariant
|
|
278
|
+
by id (BR-nnn), the bounded context's domain-model.md in context carries
|
|
279
|
+
its text and the entity names it is stated over — read the rule there
|
|
280
|
+
rather than inferring it from the id. Test log:
|
|
197
281
|
{{test_log}}
|
|
198
282
|
outputs:
|
|
199
283
|
- { name: fixed_files, from: "$.files" }
|
|
@@ -238,27 +322,58 @@ workflow:
|
|
|
238
322
|
action: build_context
|
|
239
323
|
context:
|
|
240
324
|
- { path: "{{spec_file}}" }
|
|
325
|
+
- { path: "{{domain_model}}", optional: true }
|
|
241
326
|
context_from: all_paths
|
|
242
327
|
- id: check_overlays
|
|
243
328
|
action: agent_query
|
|
244
329
|
include_standards: true # the gate overlays (checklist) are in the standards
|
|
245
|
-
schema: { ok: true, violations: [ { rule: "<overlay rule /
|
|
246
|
-
mock: { ok: true, violations: [] }
|
|
330
|
+
schema: { ok: true, violations: [ { rule: "<overlay rule / BR-nnn>", where: "<file:symbol>", issue: "<what is violated>" } ], model_notes: [ { rule: "<BR-nnn>", owner: "<the aggregate that states it>", issue: "<what is unenforced or mismatched>" } ] }
|
|
331
|
+
mock: { ok: true, violations: [], model_notes: [] }
|
|
247
332
|
task: |
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
333
|
+
TWO authorities, checked in one pass over the feature's generated code + tests
|
|
334
|
+
(in context).
|
|
335
|
+
|
|
336
|
+
1. THE DOMAIN GATE CHECKLIST, loaded in the standards (the overlay
|
|
337
|
+
forbidden-patterns, refusal conditions, and CI gates). Check the code against
|
|
338
|
+
EACH checklist rule and list EVERY violation, e.g.: a hard delete of a
|
|
339
|
+
retention-protected aggregate / version history / audit record; a second write
|
|
340
|
+
path bypassing the aggregate or interop adapter; an invented/free-text coded
|
|
341
|
+
value where a validated code is required; a missing or weakened audit emission
|
|
342
|
+
on an audited operation; a data-classification-restricted field exposed on the
|
|
343
|
+
public surface or written to logs/metrics/traces. Also confirm the constraint
|
|
344
|
+
TESTS exist (audit is emitted, a restricted field is not exposed, an interop
|
|
345
|
+
projection round-trips).
|
|
346
|
+
|
|
347
|
+
2. THE BOUNDED CONTEXT'S DOMAIN MODEL, `domain-model.md` in context — the
|
|
348
|
+
authority on what the domain IS. The spec cites invariants by id; this document
|
|
349
|
+
states them. It describes the WHOLE context while this gate scores ONE feature,
|
|
350
|
+
so scope matters:
|
|
351
|
+
• BLOCKING — the invariants of the section(s) this feature answers for,
|
|
352
|
+
{{owned_sections}}: {{model_scope_rule}}. Each blocking rule has to be
|
|
353
|
+
enforced somewhere in this code, and the
|
|
354
|
+
enforcement has to say what the model says. An owned invariant with no
|
|
355
|
+
enforcement, or one enforced with a different threshold, condition or
|
|
356
|
+
direction than the model states, is a `violations` entry with the BR id as
|
|
357
|
+
its `rule`. The model wins: it is what finalize-delta merged and what the
|
|
358
|
+
plans were conformed against.
|
|
359
|
+
• BLOCKING — the ubiquitous language of that same section. An entity, field or
|
|
360
|
+
state the code names differently from the model is a violation; the model's
|
|
361
|
+
name is the right one.
|
|
362
|
+
• NOT BLOCKING — anything the model states under any section not named above.
|
|
363
|
+
This slice does not own those and often should not enforce them. Report each
|
|
364
|
+
one this code appears to touch as a `model_notes` entry, naming the owning
|
|
365
|
+
aggregate, and carry on.
|
|
366
|
+
If no domain-model.md is in context, this feature is outside every bounded
|
|
367
|
+
context: skip part 2 entirely and report nothing for it. Never infer an
|
|
368
|
+
invariant's text from its id, and never treat a rule the model does not state
|
|
369
|
+
as one.
|
|
370
|
+
|
|
371
|
+
ok=true ONLY when no checklist rule is violated AND no BLOCKING invariant above
|
|
372
|
+
is unenforced or contradicted. `model_notes` never affects ok.
|
|
259
373
|
outputs:
|
|
260
374
|
- { name: conformance_ok, from: "$.ok" }
|
|
261
375
|
- { name: conformance_violations, from: "$.violations" }
|
|
376
|
+
- { name: model_notes, from: "$.model_notes" }
|
|
262
377
|
- id: conformance_break
|
|
263
378
|
action: break
|
|
264
379
|
condition: "{{conformance_ok}} == true"
|
|
@@ -268,9 +383,15 @@ workflow:
|
|
|
268
383
|
permission_mode: acceptEdits
|
|
269
384
|
task: |
|
|
270
385
|
Fix these domain-conformance violations in the feature's code (in context),
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
386
|
+
keeping the design's behaviour intact. A violation whose `rule` is an overlay
|
|
387
|
+
rule is fixed against the gate checklist in the standards; one whose `rule` is a
|
|
388
|
+
BR-nnn is fixed against the text domain-model.md states for it under its section
|
|
389
|
+
among {{owned_sections}} — enforce what the model says, where the code
|
|
390
|
+
already owns that decision, and name entities and fields the way the model names
|
|
391
|
+
them. Do NOT weaken or delete a test to hide a violation, and do NOT edit
|
|
392
|
+
domain-model.md or the spec to match the code: this is a gate on the code, and a
|
|
393
|
+
model that is genuinely wrong is corrected upstream through /appweaver specify.
|
|
394
|
+
After fixing, re-run the tests (Bash) to confirm they stay green.
|
|
274
395
|
Violations: {{conformance_violations}}
|
|
275
396
|
outputs:
|
|
276
397
|
- { name: conformance_fixes, from: "$.files" }
|
|
@@ -279,7 +400,7 @@ workflow:
|
|
|
279
400
|
action: verify_context
|
|
280
401
|
require_true: conformance_ok
|
|
281
402
|
on_false: stop
|
|
282
|
-
on_false_message: "Code
|
|
403
|
+
on_false_message: "Code fails domain conformance after 2 fix attempts (violations: {{conformance_violations}}). Each entry is either a gate-checklist rule or an invariant (BR-nnn) the aggregate's own section of {{domain_model}} states and this code does not enforce as written. Both are constraints plan/implement must satisfy — fix the code, or if the constraint itself is wrong, correct it upstream (/appweaver specify → plan) rather than editing the model to match what was built. Invariants owned by other aggregates in this context were reported, not enforced here: {{model_notes}}"
|
|
283
404
|
|
|
284
405
|
# ═══════ INTEGRITY — did this feature's change break any aggregate that USES it? ═══════
|
|
285
406
|
# The slice is green + domain-conformant on its own. But a change to a feature can break
|
|
@@ -325,6 +446,7 @@ workflow:
|
|
|
325
446
|
integrity_log: "{{integrity_log}}"
|
|
326
447
|
context:
|
|
327
448
|
- { path: "{{spec_file}}" }
|
|
449
|
+
- { path: "{{domain_model}}", optional: true }
|
|
328
450
|
context_from: all_paths
|
|
329
451
|
- id: write_broken_referrers
|
|
330
452
|
action: agent_author
|
|
@@ -436,6 +558,18 @@ workflow:
|
|
|
436
558
|
|
|
437
559
|
outputs:
|
|
438
560
|
feature_dir: "{{feature_dir}}"
|
|
561
|
+
bounded_context: "{{context}}"
|
|
562
|
+
# The second master this gate scored against — the RESOLVED path, which context-paths
|
|
563
|
+
# reports whether or not the file is there. `model_scored` is the one that says whether
|
|
564
|
+
# it actually reached the passes: false means the conformance pass checked the gate
|
|
565
|
+
# overlays alone, either because the feature is outside every bounded context or because
|
|
566
|
+
# its context has not been modelled yet.
|
|
567
|
+
domain_model: "{{domain_model}}"
|
|
568
|
+
model_scored: "{{domain_model_exists}}"
|
|
569
|
+
# Invariants another aggregate in this context owns that this slice appears to touch.
|
|
570
|
+
# Reported by the conformance pass and never gated — surfaced so a real cross-aggregate
|
|
571
|
+
# leak is visible rather than only living in one query's answer.
|
|
572
|
+
model_notes: "{{model_notes}}"
|
|
439
573
|
test_tool: "{{test_tool}}"
|
|
440
574
|
referrer_count: "{{referrer_count}}"
|
|
441
575
|
referrer_blast_radius: "{{referrer_names}}"
|