aw-spec-cli 0.1.32 → 0.1.34
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/README.md +76 -81
- package/assets/.appweaver/DESIGN-FORMAT.md +56 -17
- package/assets/.appweaver/STACK-PROFILES.md +95 -60
- package/assets/.appweaver/orchestrator/LAUNCHER.md +1 -1
- package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +173 -32
- package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +29 -1
- package/assets/.appweaver/orchestrator/modules/foundation-pack.orch.yaml +7 -4
- package/assets/.appweaver/orchestrator/modules/foundation-spec.orch.yaml +49 -60
- package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +58 -0
- package/assets/.appweaver/orchestrator/orchestrator.py +26 -8
- package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +20 -16
- package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +30 -6
- package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +9 -7
- package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +5 -5
- package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +341 -36
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +254 -43
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +248 -68
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +251 -20
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +316 -10
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +6 -47
- package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +62 -16
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +132 -9
- package/assets/.appweaver/orchestrator/workflows/aw-spec-fix-test-coverage.orch.yaml +965 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +222 -169
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +28 -12
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +453 -116
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-lane.orch.yaml +7 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +83 -6
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +45 -2
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +324 -74
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +275 -44
- package/assets/.appweaver/scripts/python/aw-foundation.py +16 -13
- package/assets/.appweaver/scripts/python/aw-gaps.py +11 -3
- package/assets/.appweaver/scripts/python/aw-model-guard.py +295 -0
- package/assets/.appweaver/scripts/python/aw-plan-coverage.py +412 -3
- package/assets/.appweaver/scripts/python/aw-plangate.py +23 -16
- package/assets/.appweaver/scripts/python/aw-stack.py +1794 -265
- package/assets/.appweaver/stack-profiles/dotnet-webapi.json +0 -2
- package/assets/.appweaver/stack-profiles/java-spring.json +0 -2
- package/assets/.appweaver/templates/api-plan-template.md +107 -0
- package/assets/.appweaver/templates/delta-api-plan-template.md +87 -0
- package/assets/.appweaver/templates/delta-design-template.md +25 -23
- package/assets/.appweaver/templates/delta-spec-template.md +3 -3
- package/assets/.appweaver/templates/design-template.md +20 -42
- package/assets/.appweaver/templates/domain-model-template.md +3 -0
- package/assets/.appweaver/templates/ui-delta-design-template.md +11 -8
- package/assets/.appweaver/templates/ui-design-template.md +4 -4
- package/assets/foundations/foundation.spec.template.txt +25 -18
- package/assets/guardrails/README.md +61 -25
- package/assets/guardrails/methodology/ux/accessibility-standards.md +38 -0
- package/assets/guardrails/methodology/ux/content-design.md +34 -0
- package/assets/guardrails/methodology/ux/interaction-states.md +45 -0
- package/assets/guardrails/methodology/ux/journey-mapping.md +41 -0
- package/assets/guardrails/project-specific/domain/domain-requirements.md +25 -38
- package/assets/guardrails/project-specific/domain-rule-bindings.md +33 -69
- package/assets/guardrails/project-specific/frontend/ui-requirements.md +2 -2
- package/assets/guardrails/project-specific/service/technical-requirements.md +2 -2
- package/assets/guardrails/project-specific/tech-rule-bindings.md +16 -13
- package/assets/guardrails/sample-healthcare/domain/domain-requirements.md +58 -0
- package/assets/guardrails/sample-healthcare/domain-rule-bindings.md +138 -0
- package/assets/guardrails/sample-healthcare/frontend/ui-requirements.md +43 -0
- package/assets/guardrails/sample-healthcare/service/technical-requirements.md +40 -0
- package/assets/guardrails/sample-healthcare/tech-rule-bindings.md +303 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +216 -7
- package/dist/commands/init.js.map +1 -1
- package/dist/utils/config.js +1 -1
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/foundation.d.ts +36 -0
- package/dist/utils/foundation.d.ts.map +1 -0
- package/dist/utils/foundation.js +109 -0
- package/dist/utils/foundation.js.map +1 -0
- package/dist/utils/paths.js +1 -1
- package/dist/utils/paths.js.map +1 -1
- package/package.json +1 -1
|
@@ -19,9 +19,11 @@
|
|
|
19
19
|
#
|
|
20
20
|
# This stage AUTHORS nothing and generates NO code — no model is invoked. It moves
|
|
21
21
|
# changes/<id>/ into changes/archive/, bumps the minor version, clears active_change, and
|
|
22
|
-
# STAMPS that version into the `**Version**:` header of spec.md
|
|
23
|
-
# the change's own Change History
|
|
24
|
-
#
|
|
22
|
+
# STAMPS that version into the `**Version**:` header of spec.md, backend-plan.md and
|
|
23
|
+
# api-plan.md and into the change's own Change History rows — spec.md's, and api-plan.md's
|
|
24
|
+
# where finalize-delta merged the change's API into it — which finalize-delta left reading
|
|
25
|
+
# `(pending)`: the single irreversible act of the CR loop, deliberately isolated in a stage
|
|
26
|
+
# of its own.
|
|
25
27
|
#
|
|
26
28
|
# TWO SPINES, NOT ONE. The feature's version records what THIS feature shipped. The
|
|
27
29
|
# bounded context's version records the shared domain-model.md, which every feature in the
|
|
@@ -36,24 +38,29 @@
|
|
|
36
38
|
# deterministic except the summary, which needs a sentence about the change — and this
|
|
37
39
|
# stage invokes no model by design. Left unwritten rather than half-filled.
|
|
38
40
|
#
|
|
39
|
-
# THE VERSION SPINE LIVES HERE, AND ONLY HERE. The number
|
|
40
|
-
#
|
|
41
|
-
#
|
|
41
|
+
# THE VERSION SPINE LIVES HERE, AND ONLY HERE. The number's carriers — the `**Version**:`
|
|
42
|
+
# headers of spec.md and of the feature's plans (backend-plan.md, api-plan.md and
|
|
43
|
+
# frontend-plan.md, whichever it has), the change's Change History rows in spec.md and
|
|
44
|
+
# api-plan.md, and active_version.json — all move in this one step by one deterministic
|
|
45
|
+
# mechanism. Before, backend-plan.md's
|
|
42
46
|
# header was bumped by the MODEL at finalize-delta (a stage early, and guessing the target
|
|
43
47
|
# since the number was never passed into the merge prompt) while spec.md's header was bumped
|
|
44
48
|
# by nobody at all, leaving the "living truth" document permanently at v1.0.
|
|
45
49
|
#
|
|
46
|
-
# THE CHANGE HISTORY ROW IS
|
|
50
|
+
# THE CHANGE HISTORY ROW IS A CARRIER TOO, and it joined the spine for the same reason
|
|
47
51
|
# the headers did. finalize-delta appends the row when it MERGES — a stage before this number
|
|
48
52
|
# exists — and used to write version-read's `next_version` into it: a PREDICTION of the bump.
|
|
49
53
|
# A change that merged and never closed (an abandoned run, a red analyze-slice) then left
|
|
50
54
|
# spec.md asserting a version nothing ever issued. The merge now writes `(pending)` and
|
|
51
55
|
# version-stamp --cr-id fills it here, so the row and its number land together. That is the
|
|
52
|
-
# rule domain-model.md was always held to, and spec.md was the document breaking it.
|
|
56
|
+
# rule domain-model.md was always held to, and spec.md was the document breaking it. The
|
|
57
|
+
# API plan's row, which finalize-delta's API merge writes the same way, is filled by the
|
|
58
|
+
# same call.
|
|
53
59
|
#
|
|
54
60
|
# This stage no longer merges the lane plans at all (they are derived from spec.md +
|
|
55
61
|
# domain-model.md), so a plan header stamped here is stating the version the slice ships as,
|
|
56
|
-
# not that the plan was re-derived for it.
|
|
62
|
+
# not that the plan was re-derived for it. api-plan.md is different: it is a master, merged at
|
|
63
|
+
# finalize-delta, so its header states the version its content ships as.
|
|
57
64
|
#
|
|
58
65
|
# NOTE: nothing MECHANICALLY proves analyze-slice ran green before this point — the
|
|
59
66
|
# stage boundary is operator-driven, as everywhere else in this pipeline. And nothing
|
|
@@ -63,6 +70,14 @@
|
|
|
63
70
|
# back — it is found by `cr-list` (every stage that asks which change shows it), not by
|
|
64
71
|
# the next command refusing.
|
|
65
72
|
#
|
|
73
|
+
# THE CHANGE'S API IS MERGED BEFORE IT IS ARCHIVED. finalize-delta merges the change's API
|
|
74
|
+
# into api-plan.md and stops when it cannot, naming the command that finishes the merge. The
|
|
75
|
+
# archive takes the change out of the set contract-combine applies over the feature's draft,
|
|
76
|
+
# so a change archived with its API unmerged takes its endpoints out of the frontend lane's
|
|
77
|
+
# document for good, and api-plan.md never gets them. Step 2c asks `contract-merge --check`
|
|
78
|
+
# before anything moves, and stops when the change carries an API delta that api-plan.md has
|
|
79
|
+
# no Change History row for — every merge writes one. A change with no API delta passes.
|
|
80
|
+
#
|
|
66
81
|
# WHICH CHANGE IS CLOSED IS ASKED, NEVER INFERRED. MANY changes may be open at once, and
|
|
67
82
|
# active_version.json's `active_change` is only the most recently opened or activated —
|
|
68
83
|
# every /appweaver specify overwrites it. Taking that field as "the" change is how a bare
|
|
@@ -78,8 +93,8 @@
|
|
|
78
93
|
# =============================================================================
|
|
79
94
|
|
|
80
95
|
name: aw-spec-close-delta
|
|
81
|
-
description: Close ONE chosen open change — archive changes/<id>/ into changes/archive/, bump the minor version, clear active_change, and stamp that version into the feature's master headers (spec.md, backend-plan.md, and frontend-plan.md where the feature has a UI half), then anchor the close in the OKF freshness log. ASKS which change (a bare CR id as the argument skips the prompt) and confirms even a lone one, rather than taking whichever was last opened. The final CR stage, run after finalize-delta merged the delta and analyze-slice verified the slice. The sole owner of the version spine; invokes no model and generates no code.
|
|
82
|
-
version: 1.
|
|
96
|
+
description: Close ONE chosen open change — archive changes/<id>/ into changes/archive/, bump the minor version, clear active_change, and stamp that version into the feature's master headers (spec.md, backend-plan.md, api-plan.md, and frontend-plan.md where the feature has a UI half) and into the change's Change History rows in spec.md and api-plan.md, then anchor the close in the OKF freshness log. ASKS which change (a bare CR id as the argument skips the prompt) and confirms even a lone one, rather than taking whichever was last opened. Stops before the archive when the change carries an API delta that is not merged into api-plan.md. The final CR stage, run after finalize-delta merged the delta and analyze-slice verified the slice. The sole owner of the version spine; invokes no model and generates no code.
|
|
97
|
+
version: 1.6.0
|
|
83
98
|
agent_agnostic: true
|
|
84
99
|
dialect: aw-spec.orchestrator/v1
|
|
85
100
|
|
|
@@ -99,7 +114,7 @@ scripts:
|
|
|
99
114
|
|
|
100
115
|
# No standards seed and no domain/tech rule selection: this stage authors nothing, so it
|
|
101
116
|
# has no prompt to govern. It is pure bookkeeping over active_version.json + changes/ +
|
|
102
|
-
# the
|
|
117
|
+
# the masters' version headers.
|
|
103
118
|
standards: []
|
|
104
119
|
|
|
105
120
|
vars:
|
|
@@ -110,6 +125,8 @@ vars:
|
|
|
110
125
|
stamped_docs: "" # which master headers version-stamp actually rewrote
|
|
111
126
|
stamped_count: "0"
|
|
112
127
|
history_filled: "false" # whether the merge's `(pending)` Change History row was completed here
|
|
128
|
+
history_rows: "" # every document whose pending row was completed: spec.md, api-plan.md
|
|
129
|
+
api_merged_ok: "true" # false unless contract-merge --check answers that nothing is still to merge
|
|
113
130
|
# The CONTEXT's spine, moved only when the closing change carried a model delta.
|
|
114
131
|
# Defaulted so the outputs read a real value on a behaviour-only close, where the step
|
|
115
132
|
# runs and correctly declines to bump.
|
|
@@ -209,6 +226,31 @@ workflow:
|
|
|
209
226
|
- { name: delta_model_exists, from: "$.delta_model_exists" }
|
|
210
227
|
- { name: context_dir, from: "$.context_dir" }
|
|
211
228
|
|
|
229
|
+
# 2c. IS THE CHANGE'S API MERGED? Asked before the archive, which takes the change out of
|
|
230
|
+
# the set contract-combine applies: a change archived with its API unmerged takes its
|
|
231
|
+
# endpoints out of the frontend lane's document for good. Read-only. The change's API
|
|
232
|
+
# delta is read as the merge reads it (its delta API plan, or its delta backend plan's
|
|
233
|
+
# API section); api-plan.md's Change History row naming the change is the record of the
|
|
234
|
+
# merge. No on_error, and only an explicit `needed: false` passes: a check that does
|
|
235
|
+
# not answer stops the stage before anything irreversible runs.
|
|
236
|
+
- id: api_merge_check
|
|
237
|
+
action: execute_script
|
|
238
|
+
script: { ref: actions }
|
|
239
|
+
subcommand: contract-merge
|
|
240
|
+
args: ["--feature-dir", "{{feature_dir}}", "--cr", "{{active_change}}", "--check"]
|
|
241
|
+
outputs:
|
|
242
|
+
- { name: api_merge_needed, from: "$.needed" }
|
|
243
|
+
- { name: api_merge_reason, from: "$.reason" }
|
|
244
|
+
- id: api_merge_pending_flag
|
|
245
|
+
condition: "{{api_merge_needed}} != false"
|
|
246
|
+
action: set
|
|
247
|
+
vars: { api_merged_ok: "false" }
|
|
248
|
+
- id: require_api_merged
|
|
249
|
+
action: verify_context
|
|
250
|
+
require_true: api_merged_ok
|
|
251
|
+
on_false: stop
|
|
252
|
+
on_false_message: "close-delta STOPPED before archiving — nothing was archived and the version did not move. Change {{active_change}} carries an API delta that is not merged into the feature's api-plan.md ({{api_merge_reason}}). Archiving it now would take its endpoints out of the frontend lane's document for good, and spend a version number on an API the master does not carry. If finalize-delta stopped at its API merge, finish that merge — `.appweaver/scripts/bash/aw-spec-actions.sh contract-merge --feature-dir {{feature_dir}} --cr {{active_change}}` (PowerShell: `.appweaver/scripts/powershell/aw-spec-actions.ps1 contract-merge --feature-dir {{feature_dir}} --cr {{active_change}}`); it merges by whole endpoint block and a second run changes nothing. If finalize-delta has not run for this change, run /appweaver finalize-delta instead — it merges the spec, the model and the API together — then /appweaver analyze-slice. Then re-run /appweaver close-delta."
|
|
253
|
+
|
|
212
254
|
# 3. Pre-execution hooks.
|
|
213
255
|
- id: resolve_pre_hooks
|
|
214
256
|
action: execute_script
|
|
@@ -236,9 +278,11 @@ workflow:
|
|
|
236
278
|
- { name: previous_version, from: "$.previous" }
|
|
237
279
|
- { name: archived_dir, from: "$.archived_dir" }
|
|
238
280
|
|
|
239
|
-
# 4b. STAMP the number just computed into the
|
|
240
|
-
# Change History
|
|
241
|
-
# carry it from the same instant by the same mechanism.
|
|
281
|
+
# 4b. STAMP the number just computed into the master headers AND into this change's
|
|
282
|
+
# Change History rows, so spec.md, backend-plan.md, api-plan.md, the rows and
|
|
283
|
+
# active_version.json all carry it from the same instant by the same mechanism. The
|
|
284
|
+
# API plan's row is the one finalize-delta's API merge wrote; a change with no API
|
|
285
|
+
# wrote none, and only spec.md's is filled. Previously backend-plan.md's
|
|
242
286
|
# header was bumped by the MODEL back at finalize-delta (guessing the target — the
|
|
243
287
|
# number was never passed to it) and spec.md's header was bumped by nobody, so it sat
|
|
244
288
|
# at v1.0 for the life of the feature.
|
|
@@ -259,6 +303,7 @@ workflow:
|
|
|
259
303
|
- { name: stamped_docs, from: "$.stamped" }
|
|
260
304
|
- { name: stamped_count, from: "$.count" }
|
|
261
305
|
- { name: history_filled, from: "$.history_row_filled" }
|
|
306
|
+
- { name: history_rows, from: "$.history_rows_filled" }
|
|
262
307
|
|
|
263
308
|
# 4c. THE CONTEXT'S OWN VERSION, which is a DIFFERENT spine from the feature's. The
|
|
264
309
|
# feature version says what this feature shipped; domain-model.md is shared by every
|
|
@@ -316,6 +361,7 @@ outputs:
|
|
|
316
361
|
previous_version: "{{previous_version}}"
|
|
317
362
|
archived_dir: "{{archived_dir}}"
|
|
318
363
|
stamped_docs: "{{stamped_docs}}"
|
|
364
|
+
history_rows: "{{history_rows}}"
|
|
319
365
|
# The bounded context's own spine — a DIFFERENT number from the feature's, moved only
|
|
320
366
|
# when this change carried a model delta. context_bumped=false on a behaviour-only
|
|
321
367
|
# change is the correct outcome, not a skipped step.
|
|
@@ -323,4 +369,4 @@ outputs:
|
|
|
323
369
|
context_version: "{{context_version}}"
|
|
324
370
|
context_version_bumped: "{{context_bumped}}"
|
|
325
371
|
model_touched: "{{delta_model_exists}}"
|
|
326
|
-
next: "Change {{active_change}} CLOSED — archived to {{archived_dir}}, version {{previous_version}} -> {{version}}, stamped into {{stamped_count}} master header(s) ({{stamped_docs}}) and into this change's Change History row (row completed={{history_filled}} — it read `(pending)` from the moment finalize-delta merged, because the number did not exist until now; false means it was already filled, which is the ordinary outcome of a re-run). spec.md, backend-plan.md,
|
|
372
|
+
next: "Change {{active_change}} CLOSED — archived to {{archived_dir}}, version {{previous_version}} -> {{version}}, stamped into {{stamped_count}} master header(s) ({{stamped_docs}}) and into this change's Change History row (row completed={{history_filled}} — it read `(pending)` from the moment finalize-delta merged, because the number did not exist until now; false means it was already filled, which is the ordinary outcome of a re-run). Rows completed: {{history_rows}} — api-plan.md's is there when finalize-delta merged the change's API into it. spec.md, backend-plan.md, api-plan.md, those rows and active_version.json now all read {{version}} — and frontend-plan.md too where the feature has a UI half ({{stamped_docs}} names what was actually rewritten); the masters describe the shipped state and the feature is free to take a new change. Bounded context `{{bounded_context}}`: context version moved={{context_bumped}} ({{context_version_before}} -> {{context_version}}) — {{context_bump_reason}}. That number is the CONTEXT's, not this feature's: domain-model.md is shared by every feature in it, so only a change that merged a model delta moves it. THE LANE PLANS STILL STAND WHERE THEY WERE AUTHORED: finalize-delta merged this change into spec.md, domain-model.md and api-plan.md only, because backend-plan.md / frontend-plan.md are DERIVED from those and nothing derives them again on its own. Re-derive with /appweaver plan main (it carries DA-n / WA-n forward and asks before rewriting), then /appweaver analyze-plan re-anchors the spec↔plan gate — it repairs and stops only once NO change is open, and runs read-only until then. Next: /appweaver run → deploy, or start the next change with /appweaver specify."
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
# aw-spec-finalize-delta (orchestrator) — MERGE the delta into the master docs
|
|
3
3
|
#
|
|
4
4
|
# The fourth of the five CR stages. Fold the open change's delta into the two documents that
|
|
5
|
-
# DEFINE the slice — the feature's spec.md and the bounded context's domain-model.md —
|
|
5
|
+
# DEFINE the slice — the feature's spec.md and the bounded context's domain-model.md — and its
|
|
6
|
+
# API delta into the feature's api-plan.md, the API contract the frontend lane binds to; then
|
|
6
7
|
# refresh the OKF knowledge layer. After this the masters describe the shipped-plus-change
|
|
7
8
|
# state, but THE CHANGE REMAINS OPEN.
|
|
8
9
|
#
|
|
@@ -14,6 +15,18 @@
|
|
|
14
15
|
# requirement reached is a rule nothing asks for. ONE agent step writes both, so there is no
|
|
15
16
|
# window in which one is in and the other is not.
|
|
16
17
|
#
|
|
18
|
+
# THE API PLAN IS THE THIRD MASTER, MERGED BY SCRIPT AFTER THE TWO:
|
|
19
|
+
# • specs/<Feature>/api-plan.md ← changes/<id>/delta-api-plan.md
|
|
20
|
+
# The endpoints the service publishes are agreed between the lanes, not derived from the
|
|
21
|
+
# spec, so api-plan.md is a master like spec.md and is merged, not re-derived. `contract-merge`
|
|
22
|
+
# merges whole endpoint blocks, keyed by operation id, with no model involved, and redraws the
|
|
23
|
+
# feature's api-draft.json from the result. It runs once the spec and model merge has landed
|
|
24
|
+
# and is not part of that transaction: the script is deterministic, a second run changes
|
|
25
|
+
# nothing, and a run that did not answer stops this stage naming the command that finishes it.
|
|
26
|
+
# A change planned before delta API plans existed keeps its API in its delta backend plan, and
|
|
27
|
+
# the script reads it there; a feature planned before API plans existed keeps its endpoints in
|
|
28
|
+
# its backend plan, and its first merge moves them into a new api-plan.md (api-split) first.
|
|
29
|
+
#
|
|
17
30
|
# THE MODEL MERGES ONE `## Aggregate:` SECTION AT A TIME — the section is the merge unit, and
|
|
18
31
|
# only the sections the delta's "Aggregates touched" header names are opened. Two open deltas
|
|
19
32
|
# on DIFFERENT aggregates therefore never collide; two on the SAME one are a real semantic
|
|
@@ -73,7 +86,9 @@
|
|
|
73
86
|
# proves it ran — the stage boundary is operator-driven, as everywhere else in this
|
|
74
87
|
# pipeline — but it is the difference between a master that describes the system and one
|
|
75
88
|
# that describes an intention.
|
|
76
|
-
# finalize-delta edits ONLY spec.md and domain-model.md
|
|
89
|
+
# finalize-delta edits ONLY spec.md and domain-model.md, and by script api-plan.md and the
|
|
90
|
+
# api-draft.json drawn from it — plus, on a feature whose endpoints were still in its backend
|
|
91
|
+
# plan, that plan, to move them out. It generates no code.
|
|
77
92
|
#
|
|
78
93
|
# WHICH CHANGE IS MERGED IS ASKED, NEVER INFERRED. MANY changes may be open at once, and
|
|
79
94
|
# active_version.json's `active_change` is only the most recently opened or activated — every
|
|
@@ -138,8 +153,8 @@
|
|
|
138
153
|
# =============================================================================
|
|
139
154
|
|
|
140
155
|
name: aw-spec-finalize-delta
|
|
141
|
-
description: Merge ONE chosen open change's delta-spec into the feature's spec.md and its model delta into the bounded context's domain-model.md — one aggregate section at a time, only the aggregates the delta names — in a single transaction, and append the spec's Change History row. ASKS which change (a bare CR id as the argument skips the prompt) and activates it, rather than taking whichever was last opened. Fenced by three hard refusals read off disk before anything is written — a moved base_version (rebase first), another change merged but not yet closed, and an open LOWER-wave predecessor — then by a SCOPED regression fence over the whole blast radius (fence_green) — the transitive REFERRER closure and the features that CO-OWN the aggregates this delta touches, which hold no edge to it but whose code is in the same files — writing a triage report and asking Abort/Override on red. Snapshots
|
|
142
|
-
version: 2.
|
|
156
|
+
description: Merge ONE chosen open change's delta-spec into the feature's spec.md and its model delta into the bounded context's domain-model.md — one aggregate section at a time, only the aggregates the delta names — in a single transaction, and append the spec's Change History row; then merge its delta API plan into the feature's api-plan.md by script — whole endpoint blocks keyed by operation id, the answered frontend requests and a Change History row — and redraw api-draft.json from it. ASKS which change (a bare CR id as the argument skips the prompt) and activates it, rather than taking whichever was last opened. Fenced by three hard refusals read off disk before anything is written — a moved base_version (rebase first), another change merged but not yet closed, and an open LOWER-wave predecessor — then by a SCOPED regression fence over the whole blast radius (fence_green) — the transitive REFERRER closure and the features that CO-OWN the aggregates this delta touches, which hold no edge to it but whose code is in the same files — writing a triage report and asking Abort/Override on red. Snapshots the masters, the backend plan and the API draft to changes/<id>/pre-merge/ immediately before the rewrite. The lane plans are NOT merged — backend-plan.md and frontend-plan.md are derived from these two documents and are re-derived by /appweaver plan main. Leaves the change OPEN — analyze-slice runs next against the merged masters, and close-delta archives the change and bumps the version.
|
|
157
|
+
version: 2.6.0
|
|
143
158
|
agent_agnostic: true
|
|
144
159
|
dialect: aw-spec.orchestrator/v1
|
|
145
160
|
|
|
@@ -230,6 +245,27 @@ vars:
|
|
|
230
245
|
overview_reason: ""
|
|
231
246
|
backend_plan: "" # READ, never written here — the OKF edges are parsed out of it
|
|
232
247
|
backend_plan_exists: "false"
|
|
248
|
+
delta_api_plan: "" # changes/<id>/delta-api-plan.md — the change's API half
|
|
249
|
+
# THE API MERGE (contract-merge). api_merge_ok defaults DOWN and is raised only by a run
|
|
250
|
+
# that answered, so a script that failed leaves the stop after it to say so.
|
|
251
|
+
api_merge_ok: "false"
|
|
252
|
+
api_merged: "false" # false with a reason: the change has no API to merge
|
|
253
|
+
api_merge_written: "false"
|
|
254
|
+
api_split: "false" # the feature's endpoints were moved out of its backend plan first
|
|
255
|
+
api_plan: ""
|
|
256
|
+
api_delta: "" # the document the change's API was read from
|
|
257
|
+
api_added: ""
|
|
258
|
+
api_changed: ""
|
|
259
|
+
api_removed: ""
|
|
260
|
+
api_requests: "" # the frontend requests whose answers joined the API plan
|
|
261
|
+
api_history_row: "false"
|
|
262
|
+
api_draft: ""
|
|
263
|
+
api_draft_operations: "0"
|
|
264
|
+
api_dropped_text: "none" # operations the redraw dropped that the change does not remove
|
|
265
|
+
api_merge_warning: ""
|
|
266
|
+
api_merge_reason: ""
|
|
267
|
+
api_merge_clean: "true"
|
|
268
|
+
api_draft_kept: "true"
|
|
233
269
|
|
|
234
270
|
workflow:
|
|
235
271
|
|
|
@@ -336,6 +372,7 @@ workflow:
|
|
|
336
372
|
- { name: delta_model, from: "$.delta_model" }
|
|
337
373
|
- { name: delta_model_exists, from: "$.delta_model_exists" }
|
|
338
374
|
- { name: delta_backend_plan, from: "$.delta_backend_plan" }
|
|
375
|
+
- { name: delta_api_plan, from: "$.delta_api_plan" }
|
|
339
376
|
- { name: domain_model, from: "$.domain_model" }
|
|
340
377
|
- { name: domain_model_exists, from: "$.domain_model_exists" }
|
|
341
378
|
|
|
@@ -595,9 +632,11 @@ workflow:
|
|
|
595
632
|
context:
|
|
596
633
|
- { path: "{{spec_file}}" }
|
|
597
634
|
- { path: "{{delta_spec}}" }
|
|
598
|
-
# The delta
|
|
599
|
-
# have broken a dependent
|
|
635
|
+
# The delta plans are how the change was BUILT — the most direct account of what could
|
|
636
|
+
# have broken a dependent, and the delta API plan of a broken contract between slices.
|
|
637
|
+
# Optional: a frontend-only change never has them.
|
|
600
638
|
- { path: "{{delta_backend_plan}}", optional: true }
|
|
639
|
+
- { path: "{{delta_api_plan}}", optional: true }
|
|
601
640
|
- id: write_broken_downstream
|
|
602
641
|
action: agent_author
|
|
603
642
|
condition: "{{blast_any}}"
|
|
@@ -755,6 +794,8 @@ workflow:
|
|
|
755
794
|
these two documents and are re-derived by /appweaver plan main after this merge; neither is
|
|
756
795
|
in context and neither is to be opened, read or edited. Do not restate a plan's
|
|
757
796
|
wording in a master: the plan is how the change was built, not what was agreed.
|
|
797
|
+
api-plan.md is not yours either: the change's API is merged into it by script once
|
|
798
|
+
this merge has landed, so do not open or edit it.
|
|
758
799
|
BOTH MASTERS MOVE TOGETHER. Where there is a model delta, edit spec.md and
|
|
759
800
|
domain-model.md in the same pass — a merged requirement citing a BR- the model never
|
|
760
801
|
gained, or a merged invariant no requirement reached, is exactly the split state this
|
|
@@ -819,8 +860,8 @@ workflow:
|
|
|
819
860
|
row's `(pending)` cell, at the moment it bumps active_version.json, so every carrier
|
|
820
861
|
of the number changes in one step by one mechanism. Do not invent a version anywhere.
|
|
821
862
|
Preserve every unrelated section of BOTH masters byte-for-byte. Do NOT touch the
|
|
822
|
-
delta documents (close-delta archives them later), do NOT open or edit any lane plan
|
|
823
|
-
and do NOT touch any source code. Report the files you changed.
|
|
863
|
+
delta documents (close-delta archives them later), do NOT open or edit any lane plan
|
|
864
|
+
or the API plan, and do NOT touch any source code. Report the files you changed.
|
|
824
865
|
outputs:
|
|
825
866
|
- { name: merged_docs, from: "$.files" }
|
|
826
867
|
|
|
@@ -957,6 +998,81 @@ workflow:
|
|
|
957
998
|
outputs:
|
|
958
999
|
- { name: xref_log, from: "$.log" }
|
|
959
1000
|
|
|
1001
|
+
# 4d. THE API MERGE — the change's delta API plan into the feature's api-plan.md, by script.
|
|
1002
|
+
# Whole endpoint blocks, keyed by operation id (by verb and route for a block without
|
|
1003
|
+
# one, which keeps the id its row or the block it replaces gives that route): a changed
|
|
1004
|
+
# block replaces the API plan's, an added one goes after the last, a
|
|
1005
|
+
# removed one is deleted, and a Contract deltas row with no block is written from the
|
|
1006
|
+
# row and reported — never over a block the change wrote on the same route. The requests the change answers replace or join the requests table,
|
|
1007
|
+
# and a Change History row is written with `(pending)` in its Version cell for
|
|
1008
|
+
# close-delta to stamp. api-draft.json is redrawn from the result in the same call.
|
|
1009
|
+
# A change with no API delta merges nothing, which is the whole outcome for a
|
|
1010
|
+
# behaviour-only or frontend-only change. One planned before delta API plans existed
|
|
1011
|
+
# is read from its delta backend plan's API section; a feature with no api-plan.md yet
|
|
1012
|
+
# has its endpoints moved out of its backend plan into one first (api-split).
|
|
1013
|
+
# After the spec and model merge, so the API never moves when the merge above wrote
|
|
1014
|
+
# nothing; after the OKF refresh, so a run that fails here still leaves the knowledge
|
|
1015
|
+
# layer current. on_error: continue, so a failure reaches the stop below, which names
|
|
1016
|
+
# the command that finishes the merge.
|
|
1017
|
+
- id: merge_api
|
|
1018
|
+
action: execute_script
|
|
1019
|
+
on_error: continue
|
|
1020
|
+
script: { ref: actions }
|
|
1021
|
+
subcommand: contract-merge
|
|
1022
|
+
args: ["--feature-dir", "{{feature_dir}}", "--cr", "{{active_change}}"]
|
|
1023
|
+
outputs:
|
|
1024
|
+
- { name: api_merge_ok, from: "$.ok" }
|
|
1025
|
+
- { name: api_merged, from: "$.merged" }
|
|
1026
|
+
- { name: api_merge_written, from: "$.written" }
|
|
1027
|
+
- { name: api_split, from: "$.split" }
|
|
1028
|
+
- { name: api_plan, from: "$.path" }
|
|
1029
|
+
- { name: api_delta, from: "$.delta" }
|
|
1030
|
+
- { name: api_added, from: "$.added" }
|
|
1031
|
+
- { name: api_changed, from: "$.changed" }
|
|
1032
|
+
- { name: api_removed, from: "$.removed" }
|
|
1033
|
+
- { name: api_requests, from: "$.requests" }
|
|
1034
|
+
- { name: api_history_row, from: "$.history_row" }
|
|
1035
|
+
- { name: api_draft, from: "$.draft" }
|
|
1036
|
+
- { name: api_draft_operations, from: "$.draft_operations" }
|
|
1037
|
+
- { name: api_dropped_text, from: "$.dropped_text" }
|
|
1038
|
+
- { name: api_merge_warning, from: "$.warning" }
|
|
1039
|
+
- { name: api_merge_reason, from: "$.reason" }
|
|
1040
|
+
|
|
1041
|
+
# spec.md and domain-model.md already carry the change when this fires. Re-running
|
|
1042
|
+
# finalize-delta would merge them a second time and retake the pre-merge snapshot from the
|
|
1043
|
+
# merged masters, so the message names the script instead, which a second run leaves as it
|
|
1044
|
+
# is. Stopping here keeps the post hooks from taking a half-merged change for a merged one,
|
|
1045
|
+
# and keeps the change from reaching close-delta, whose archive would take its endpoints out
|
|
1046
|
+
# of the frontend lane's document for good.
|
|
1047
|
+
- id: require_api_merged
|
|
1048
|
+
action: verify_context
|
|
1049
|
+
require_true: api_merge_ok
|
|
1050
|
+
on_false: stop
|
|
1051
|
+
on_false_message: "finalize-delta STOPPED after the merge — change {{active_change}} IS merged into spec.md and the context's domain-model.md, but merging its API into the feature's api-plan.md did not complete: the contract-merge script did not answer. Run it to see why and, once the cause is fixed, to finish the merge — `.appweaver/scripts/bash/aw-spec-actions.sh contract-merge --feature-dir {{feature_dir}} --cr {{active_change}}` (PowerShell: `.appweaver/scripts/powershell/aw-spec-actions.ps1 contract-merge --feature-dir {{feature_dir}} --cr {{active_change}}`). It merges by whole endpoint block and a second run changes nothing. Do NOT re-run /appweaver finalize-delta: it would merge spec.md and domain-model.md a second time. Then continue with /appweaver analyze-slice; do not run /appweaver close-delta until the API is merged, because archiving the change takes its endpoints out of the frontend lane's document."
|
|
1052
|
+
|
|
1053
|
+
# What the merge could not do exactly as the change says: an endpoint written from its
|
|
1054
|
+
# Contract deltas row because the change wrote no block for it, a row whose route the
|
|
1055
|
+
# change's block took under another id, or a changed endpoint the API plan did not have.
|
|
1056
|
+
# Reported, not blocking — the change is merged either way.
|
|
1057
|
+
- id: api_merge_clean_flag
|
|
1058
|
+
condition: "{{api_merge_warning}} != "
|
|
1059
|
+
action: set
|
|
1060
|
+
vars: { api_merge_clean: "false" }
|
|
1061
|
+
- id: warn_api_merge
|
|
1062
|
+
action: verify_context
|
|
1063
|
+
require_true: api_merge_clean
|
|
1064
|
+
on_false: continue
|
|
1065
|
+
on_false_message: "{{api_merge_warning}}"
|
|
1066
|
+
- id: api_draft_dropped_flag
|
|
1067
|
+
condition: "{{api_dropped_text}} != none"
|
|
1068
|
+
action: set
|
|
1069
|
+
vars: { api_draft_kept: "false" }
|
|
1070
|
+
- id: warn_api_draft_dropped
|
|
1071
|
+
action: verify_context
|
|
1072
|
+
require_true: api_draft_kept
|
|
1073
|
+
on_false: continue
|
|
1074
|
+
on_false_message: "API DRAFT — after the merge, {{api_draft}} no longer has operation(s) the previous draft had and change {{active_change}} does not remove: {{api_dropped_text}}. The frontend lane may still bind to them. If they were dropped on purpose, remove them through a change; if not, restore their blocks in {{api_plan}}."
|
|
1075
|
+
|
|
960
1076
|
# 5. NO ARCHIVE, NO VERSION BUMP HERE. Both moved to close-delta, which runs after
|
|
961
1077
|
# analyze-slice — see the header. The change stays OPEN past this stage on purpose:
|
|
962
1078
|
# it is what keeps a red analyze-slice recoverable ("fix and re-run") instead of
|
|
@@ -996,4 +1112,11 @@ outputs:
|
|
|
996
1112
|
model_merged: "{{delta_model_exists}}" # true ⇒ domain-model.md was the second target of this merge.
|
|
997
1113
|
# false = a behaviour-only change: the spec merge was the
|
|
998
1114
|
# whole merge, not a half of one.
|
|
999
|
-
|
|
1115
|
+
# The API plan, the third master: whether the change's API was merged into it, and the
|
|
1116
|
+
# draft redrawn from it. api_split=true ⇒ the feature's endpoints were moved out of its
|
|
1117
|
+
# backend plan into a new api-plan.md first.
|
|
1118
|
+
api_plan: "{{api_plan}}"
|
|
1119
|
+
api_merged: "{{api_merged}}"
|
|
1120
|
+
api_split: "{{api_split}}"
|
|
1121
|
+
api_draft: "{{api_draft}}"
|
|
1122
|
+
next: "Delta MERGED into spec.md, and into the context's domain-model.md one aggregate section at a time where the change carried a model delta (model_merged={{delta_model_exists}} — false means a behaviour-only change, so the spec merge was the whole merge). THE API: merged={{api_merged}} into {{api_plan}} from {{api_delta}} — added {{api_added}}, changed {{api_changed}}, removed {{api_removed}}, requests answered {{api_requests}}, Change History row written={{api_history_row}} (its version reads `(pending)` until close-delta stamps it); {{api_draft}} redrawn with {{api_draft_operations}} operation(s). merged=false means the change has no API to merge: {{api_merge_reason}}. api_split={{api_split}} — true means the feature's endpoints and requests table were first moved out of its backend plan into api-plan.md, the only edit this stage makes to a lane plan. The lane plans were NOT merged — they are DERIVED from these masters, so backend-plan.md / frontend-plan.md now stand BEHIND the spec and model at their last authored content. That drift starts here and lasts until /appweaver plan main re-derives them, carrying the recorded decisions (DA-n) and workarounds (WA-n) forward and rewriting what the spec and model no longer support. analyze-plan is not what closes it and cannot repair it while this change is open: with a change open it runs READ-ONLY, reporting the drift into plan-analyze-report.md without rewriting either plan. The full gate — check, repair, stop — comes back once the last change is closed, so the order is close-delta, then plan main, then analyze-plan. OKF edges reconciled ({{xref_edge_count}} dep(s)), {{downstream_count}} downstream slice(s) fenced (gate: {{gate_decision}}). The concept Overview was distilled for aggregate(s) `{{overview_scope}}` — taken from what this change's model delta DECLARES it touched, not assumed from the feature name (empty on a behaviour-only change, which falls back to the aggregate the feature answers for). section_found={{overview_section_ok}}, written={{overview_written}}{{overview_reason}} — written=false is normal for a behaviour-only change (nothing to distil, the existing Overview stands), but section_found=false means domain-model.md has no `## Aggregate:` section under that name and the concept's Overview was left as it was: check that the spec's Acts on aggregate(s) line names an aggregate the model defines. Change {{active_change}} is STILL OPEN and the version is still {{version}}. Next: /appweaver analyze-slice — it now reads masters that carry this change, and a red result is still recoverable because nothing has been archived. Then /appweaver close-delta archives the change and bumps the version."
|