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
|
@@ -22,12 +22,19 @@
|
|
|
22
22
|
# interactive "continue or exit?" gate on every build to load rules that could never
|
|
23
23
|
# have been found. Removing it makes greenfield `build` non-interactive.
|
|
24
24
|
#
|
|
25
|
+
# 1.3.0 — the lane gate requires A LANE, not a BACKEND lane. Every declared lane is
|
|
26
|
+
# compiled by its own build command, so what this stage needs is a declaration to compile
|
|
27
|
+
# from, not a particular kind of one; requiring the service lane blocked a frontend-only
|
|
28
|
+
# project that `plan` and `implement` both accept. The rest of the gate is unchanged: no
|
|
29
|
+
# lane declared, a lane with no source path, a source path that is not on disk, and two
|
|
30
|
+
# lanes claiming overlapping subtrees all still stop the run.
|
|
31
|
+
#
|
|
25
32
|
# Launch: /appweaver build [strategy]
|
|
26
33
|
# =============================================================================
|
|
27
34
|
|
|
28
35
|
name: aw-spec-build
|
|
29
|
-
description: Compile the feature, fix compile errors against the design intent, then record the touched files in the slice's knowledge concept. Loads TECHNICAL rules only (tech-rule-bindings) — no domain rules reach this stage.
|
|
30
|
-
version: 1.
|
|
36
|
+
description: Compile the feature by running EVERY declared lane's own build command, fix compile errors against the design intent, then record the touched files in the slice's knowledge concept. Backend-only, frontend-only and full-stack projects all compile here — the gate requires a lane declaration, not a lane of a particular kind. Loads TECHNICAL rules only (tech-rule-bindings) — no domain rules reach this stage.
|
|
37
|
+
version: 1.3.0
|
|
31
38
|
agent_agnostic: true
|
|
32
39
|
dialect: aw-spec.orchestrator/v1
|
|
33
40
|
|
|
@@ -75,16 +82,20 @@ workflow:
|
|
|
75
82
|
action: verify_context
|
|
76
83
|
require_non_empty: feature_dir
|
|
77
84
|
on_empty: stop
|
|
78
|
-
on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the
|
|
79
|
-
|
|
80
|
-
# Require
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
85
|
+
on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the feature, e.g. Order or PatientRegistration), then re-run build."
|
|
86
|
+
|
|
87
|
+
# Require A LANE — not a KIND of lane. build-compile runs EVERY declared lane's own
|
|
88
|
+
# build command, so a two-lane project compiles both (the case the old first-match-wins
|
|
89
|
+
# sniffer got wrong by reporting green for a frontend it never touched) and a one-lane
|
|
90
|
+
# project compiles the one it has, whichever kind that is. A frontend-only project is a
|
|
91
|
+
# legal project: `plan` and `implement` both accept one, so refusing it here stopped it
|
|
92
|
+
# at the first stage that had no reason to care. Passing no required kind leaves every
|
|
93
|
+
# other check armed — no lane declared at all, a lane with no source path, a source path
|
|
94
|
+
# that is not on disk, and two lanes claiming overlapping subtrees.
|
|
84
95
|
- id: lane_gate
|
|
85
96
|
action: include
|
|
86
97
|
module: .appweaver/orchestrator/modules/lane-gate.orch.yaml
|
|
87
|
-
with: { require:
|
|
98
|
+
with: { require: "", command: "/appweaver build" }
|
|
88
99
|
|
|
89
100
|
# The slice's source files, from its OKF concept — what the fix loop below is handed.
|
|
90
101
|
# This replaces the retired `design-paths` fence scan: the tech-agnostic backend-plan.md
|
|
@@ -106,7 +106,7 @@ workflow:
|
|
|
106
106
|
action: verify_context
|
|
107
107
|
require_non_empty: feature_dir
|
|
108
108
|
on_empty: stop
|
|
109
|
-
on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the
|
|
109
|
+
on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the feature, e.g. Order or PatientRegistration), then re-run characterize."
|
|
110
110
|
|
|
111
111
|
- id: verify_spec
|
|
112
112
|
action: verify_context
|
|
@@ -18,38 +18,77 @@
|
|
|
18
18
|
# once the slice is green, domain-conformant and has not broken a referrer.
|
|
19
19
|
#
|
|
20
20
|
# This stage AUTHORS nothing and generates NO code — no model is invoked. It moves
|
|
21
|
-
# changes/<id>/ into changes/archive/, bumps the minor version, clears active_change,
|
|
22
|
-
#
|
|
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 + backend-plan.md and into
|
|
23
|
+
# the change's own Change History row, which finalize-delta left reading `(pending)` — the
|
|
23
24
|
# single irreversible act of the CR loop, deliberately isolated in a stage of its own.
|
|
24
25
|
#
|
|
25
|
-
#
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
26
|
+
# TWO SPINES, NOT ONE. The feature's version records what THIS feature shipped. The
|
|
27
|
+
# bounded context's version records the shared domain-model.md, which every feature in the
|
|
28
|
+
# context reads — so a change to it is a change to all of them and no single feature's
|
|
29
|
+
# number can carry it. This stage owns both, and moves the context's ONLY when the closing
|
|
30
|
+
# change actually merged a model delta: a behaviour-only change leaves domain-model.md
|
|
31
|
+
# alone at finalize and leaves its version alone here. The model's `**Context version**:`
|
|
32
|
+
# header has always declared itself script-stamped, and specify forbids the authoring model
|
|
33
|
+
# from writing it; this is the step that makes both of those statements true.
|
|
34
|
+
#
|
|
35
|
+
# ⌛ The model's own Change History table is still not written by anything. Its columns are
|
|
36
|
+
# deterministic except the summary, which needs a sentence about the change — and this
|
|
37
|
+
# stage invokes no model by design. Left unwritten rather than half-filled.
|
|
38
|
+
#
|
|
39
|
+
# THE VERSION SPINE LIVES HERE, AND ONLY HERE. The number has FOUR carriers — spec.md's
|
|
40
|
+
# header, backend-plan.md's header, spec.md's Change History row, and active_version.json —
|
|
41
|
+
# and all four move in this one step by one deterministic mechanism. Before, backend-plan.md's
|
|
42
|
+
# header was bumped by the MODEL at finalize-delta (a stage early, and guessing the target
|
|
43
|
+
# since the number was never passed into the merge prompt) while spec.md's header was bumped
|
|
44
|
+
# by nobody at all, leaving the "living truth" document permanently at v1.0.
|
|
45
|
+
#
|
|
46
|
+
# THE CHANGE HISTORY ROW IS THE FOURTH CARRIER, and it joined the spine for the same reason
|
|
47
|
+
# the headers did. finalize-delta appends the row when it MERGES — a stage before this number
|
|
48
|
+
# exists — and used to write version-read's `next_version` into it: a PREDICTION of the bump.
|
|
49
|
+
# A change that merged and never closed (an abandoned run, a red analyze-slice) then left
|
|
50
|
+
# spec.md asserting a version nothing ever issued. The merge now writes `(pending)` and
|
|
51
|
+
# 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.
|
|
53
|
+
#
|
|
54
|
+
# This stage no longer merges the lane plans at all (they are derived from spec.md +
|
|
55
|
+
# 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.
|
|
35
57
|
#
|
|
36
58
|
# NOTE: nothing MECHANICALLY proves analyze-slice ran green before this point — the
|
|
37
|
-
# stage boundary is operator-driven, as everywhere else in this pipeline.
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
59
|
+
# stage boundary is operator-driven, as everywhere else in this pipeline. And nothing
|
|
60
|
+
# backstops a forgotten close either: MANY changes may be open at once, so `specify`
|
|
61
|
+
# opens a new one rather than refusing while an earlier one is unclosed. A change that is
|
|
62
|
+
# merged but never closed therefore sits in the open set indefinitely, holding the version
|
|
63
|
+
# back — it is found by `cr-list` (every stage that asks which change shows it), not by
|
|
64
|
+
# the next command refusing.
|
|
41
65
|
#
|
|
42
|
-
#
|
|
66
|
+
# WHICH CHANGE IS CLOSED IS ASKED, NEVER INFERRED. MANY changes may be open at once, and
|
|
67
|
+
# active_version.json's `active_change` is only the most recently opened or activated —
|
|
68
|
+
# every /appweaver specify overwrites it. Taking that field as "the" change is how a bare
|
|
69
|
+
# close archives and version-bumps a change nobody merged while the merged one stays open.
|
|
70
|
+
# This stage opens with the same list → pick → activate sequence as finalize-delta, plan,
|
|
71
|
+
# implement, analyze-plan-delta and recall-delta, and the argument doubles as the answer
|
|
72
|
+
# (`close-delta CR-…` skips the prompt). The pick is confirmed even when only one change is
|
|
73
|
+
# open: this is the stage that spends a version number, and that is not undone.
|
|
74
|
+
#
|
|
75
|
+
# Launch: /appweaver close-delta [CR-id] (a bare id skips the prompt)
|
|
43
76
|
# Prereq: an OPEN change whose delta was merged by finalize-delta and whose slice
|
|
44
77
|
# passed /appweaver analyze-slice.
|
|
45
78
|
# =============================================================================
|
|
46
79
|
|
|
47
80
|
name: aw-spec-close-delta
|
|
48
|
-
description: Close
|
|
49
|
-
version: 1.
|
|
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.4.0
|
|
50
83
|
agent_agnostic: true
|
|
51
84
|
dialect: aw-spec.orchestrator/v1
|
|
52
85
|
|
|
86
|
+
inputs:
|
|
87
|
+
user_input:
|
|
88
|
+
description: "Optional CR id of the change to close. A bare id selects it and skips the prompt; anything else is ignored and the menu is shown."
|
|
89
|
+
required: false
|
|
90
|
+
bind: USER_INPUT
|
|
91
|
+
|
|
53
92
|
scripts:
|
|
54
93
|
actions:
|
|
55
94
|
sh: .appweaver/scripts/bash/aw-spec-actions.sh
|
|
@@ -65,10 +104,21 @@ standards: []
|
|
|
65
104
|
|
|
66
105
|
vars:
|
|
67
106
|
active_change: ""
|
|
68
|
-
|
|
107
|
+
cr_choice: "" # the LABEL the pick returns ("CR-… · wave 2 · title"); scripts take its first token
|
|
108
|
+
has_changes: "false" # from cr-list — the DIRECTORY's answer to "is anything open", not the ledger's
|
|
69
109
|
version: ""
|
|
70
110
|
stamped_docs: "" # which master headers version-stamp actually rewrote
|
|
71
111
|
stamped_count: "0"
|
|
112
|
+
history_filled: "false" # whether the merge's `(pending)` Change History row was completed here
|
|
113
|
+
# The CONTEXT's spine, moved only when the closing change carried a model delta.
|
|
114
|
+
# Defaulted so the outputs read a real value on a behaviour-only close, where the step
|
|
115
|
+
# runs and correctly declines to bump.
|
|
116
|
+
delta_model_exists: "false"
|
|
117
|
+
context_bumped: "false"
|
|
118
|
+
context_version: ""
|
|
119
|
+
context_version_before: ""
|
|
120
|
+
context_bump_reason: ""
|
|
121
|
+
bounded_context: ""
|
|
72
122
|
|
|
73
123
|
workflow:
|
|
74
124
|
|
|
@@ -86,25 +136,78 @@ workflow:
|
|
|
86
136
|
action: verify_context
|
|
87
137
|
require_non_empty: feature_dir
|
|
88
138
|
on_empty: stop
|
|
89
|
-
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 close-delta."
|
|
140
|
+
|
|
141
|
+
# 2. WHICH CHANGE IS BEING CLOSED. The evidence is changes/<CR-id>/ on disk; a change
|
|
142
|
+
# already closed has moved to changes/archive/. On the BOOTSTRAP path (implement →
|
|
143
|
+
# build → analyze-slice) there is none and this stage does not apply at all.
|
|
144
|
+
# `matched_label` resolves a CR id passed as the argument to the whole option string,
|
|
145
|
+
# which is how a bare `close-delta CR-…` skips the prompt.
|
|
146
|
+
- id: cr_list
|
|
147
|
+
action: execute_script
|
|
148
|
+
script: { ref: actions }
|
|
149
|
+
subcommand: cr-list
|
|
150
|
+
args: ["--feature-dir", "{{feature_dir}}", "--preselect", "{{USER_INPUT}}"]
|
|
151
|
+
outputs:
|
|
152
|
+
- { name: change_options, from: "$.select_options" }
|
|
153
|
+
- { name: matched_label, from: "$.matched_label" }
|
|
154
|
+
- { name: has_changes, from: "$.has_changes" }
|
|
155
|
+
- { name: change_count, from: "$.count" }
|
|
156
|
+
|
|
157
|
+
- id: require_changes
|
|
158
|
+
action: verify_context
|
|
159
|
+
require_true: has_changes
|
|
160
|
+
on_false: stop
|
|
161
|
+
on_false_message: "No open change on this feature — nothing to close. A change is opened by /appweaver specify and merged by /appweaver finalize-delta before it can be closed here. If you have not merged yet, run /appweaver finalize-delta → analyze-slice first. A change already closed is under changes/archive/."
|
|
162
|
+
|
|
163
|
+
# single_option_confirm so a feature with exactly one open change still confirms the id
|
|
164
|
+
# out loud. This is the stage that spends a version number and archives the change's
|
|
165
|
+
# documents, and neither is undone.
|
|
166
|
+
- id: pick_change
|
|
167
|
+
action: user_select
|
|
168
|
+
prompt: "Which open change is being CLOSED? Close the change finalize-delta MERGED and analyze-slice then verified — closing one that was never merged archives its delta documents and spends a version number on work the masters do not carry. To withdraw an unmerged change instead, stop and run /appweaver recall-delta, which archives it and bumps nothing."
|
|
169
|
+
options_from_variable: change_options
|
|
170
|
+
preselect_from: matched_label
|
|
171
|
+
single_option_confirm: true
|
|
172
|
+
outputs:
|
|
173
|
+
- { name: cr_choice, from: selection }
|
|
174
|
+
|
|
175
|
+
# Make the chosen change the ACTIVE one, and VALIDATE it in the same call: cr-activate
|
|
176
|
+
# refuses an id the ledger does not carry, which here means a directory with no ledger row
|
|
177
|
+
# — cr-archive would find nothing to drop from the open set and the version would move for
|
|
178
|
+
# a change the ledger never knew about.
|
|
179
|
+
- id: activate
|
|
180
|
+
action: execute_script
|
|
181
|
+
script: { ref: actions }
|
|
182
|
+
subcommand: cr-activate
|
|
183
|
+
args: ["--cr-id", "{{cr_choice}}", "--feature-dir", "{{feature_dir}}"]
|
|
184
|
+
outputs:
|
|
185
|
+
- { name: active_change, from: "$.active_change" }
|
|
90
186
|
|
|
91
|
-
#
|
|
92
|
-
#
|
|
187
|
+
# 2a. The version BEFORE the bump, for the log line below. cr-archive computes and
|
|
188
|
+
# returns the new one; this is no longer the selector.
|
|
93
189
|
- id: read_change
|
|
94
190
|
action: execute_script
|
|
95
191
|
script: { ref: actions }
|
|
96
192
|
subcommand: version-read
|
|
97
193
|
args: ["--feature-dir", "{{feature_dir}}"]
|
|
98
194
|
outputs:
|
|
99
|
-
- { name: active_change, from: "$.active_change" }
|
|
100
|
-
- { name: has_change, from: "$.has_change" }
|
|
101
195
|
- { name: version, from: "$.version" }
|
|
102
196
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
197
|
+
# 2b. DID THIS CHANGE TOUCH THE DOMAIN MODEL? Asked HERE, before the archive, because
|
|
198
|
+
# cr-archive moves the change's model delta out from beside the master and into
|
|
199
|
+
# changes/archive/<id>/ — after that the evidence is gone from where this question
|
|
200
|
+
# looks for it. The answer decides whether the CONTEXT version moves at step 4c.
|
|
201
|
+
- id: cr_paths
|
|
202
|
+
action: execute_script
|
|
203
|
+
on_error: continue
|
|
204
|
+
script: { ref: actions }
|
|
205
|
+
subcommand: cr-paths
|
|
206
|
+
args: ["--cr-id", "{{active_change}}", "--feature-dir", "{{feature_dir}}"]
|
|
207
|
+
outputs:
|
|
208
|
+
- { name: delta_model, from: "$.delta_model" }
|
|
209
|
+
- { name: delta_model_exists, from: "$.delta_model_exists" }
|
|
210
|
+
- { name: context_dir, from: "$.context_dir" }
|
|
108
211
|
|
|
109
212
|
# 3. Pre-execution hooks.
|
|
110
213
|
- id: resolve_pre_hooks
|
|
@@ -133,20 +236,53 @@ workflow:
|
|
|
133
236
|
- { name: previous_version, from: "$.previous" }
|
|
134
237
|
- { name: archived_dir, from: "$.archived_dir" }
|
|
135
238
|
|
|
136
|
-
# 4b. STAMP the number just computed into the two master headers
|
|
137
|
-
# backend-plan.md and active_version.json all
|
|
138
|
-
# same mechanism. Previously backend-plan.md's
|
|
139
|
-
# finalize-delta (guessing the target — the
|
|
140
|
-
# spec.md's header was bumped by nobody, so it sat
|
|
141
|
-
#
|
|
239
|
+
# 4b. STAMP the number just computed into the two master headers AND into this change's
|
|
240
|
+
# Change History row, so spec.md, backend-plan.md, the row and active_version.json all
|
|
241
|
+
# carry it from the same instant by the same mechanism. Previously backend-plan.md's
|
|
242
|
+
# header was bumped by the MODEL back at finalize-delta (guessing the target — the
|
|
243
|
+
# number was never passed to it) and spec.md's header was bumped by nobody, so it sat
|
|
244
|
+
# at v1.0 for the life of the feature.
|
|
245
|
+
#
|
|
246
|
+
# --cr-id is what completes the row. finalize-delta appends it at MERGE time, a stage
|
|
247
|
+
# before this number exists, so it writes `(pending)` in the Version cell rather than
|
|
248
|
+
# version-read's prediction of the bump: a change that merged and never closed would
|
|
249
|
+
# otherwise leave spec.md asserting a version nothing ever issued. The row is found by
|
|
250
|
+
# its CR cell, and only a still-pending cell is written — a row already carrying a
|
|
251
|
+
# number belongs to a change that closed, and rewriting it would rewrite history.
|
|
252
|
+
# Deterministic and idempotent; only the values move.
|
|
142
253
|
- id: stamp_version
|
|
143
254
|
action: execute_script
|
|
144
255
|
script: { ref: actions }
|
|
145
256
|
subcommand: version-stamp
|
|
146
|
-
args: ["--feature-dir", "{{feature_dir}}", "--version", "{{version}}"]
|
|
257
|
+
args: ["--feature-dir", "{{feature_dir}}", "--version", "{{version}}", "--cr-id", "{{active_change}}"]
|
|
258
|
+
outputs:
|
|
259
|
+
- { name: stamped_docs, from: "$.stamped" }
|
|
260
|
+
- { name: stamped_count, from: "$.count" }
|
|
261
|
+
- { name: history_filled, from: "$.history_row_filled" }
|
|
262
|
+
|
|
263
|
+
# 4c. THE CONTEXT'S OWN VERSION, which is a DIFFERENT spine from the feature's. The
|
|
264
|
+
# feature version says what this feature shipped; domain-model.md is shared by every
|
|
265
|
+
# feature in the bounded context, so a change to it is a change to all of them and no
|
|
266
|
+
# single feature's number can record it. The model's header has always declared
|
|
267
|
+
# itself script-stamped and specify forbids the authoring model from writing it —
|
|
268
|
+
# this is the step that makes both statements true.
|
|
269
|
+
#
|
|
270
|
+
# Conditional on the change having carried a model delta: a behaviour-only change
|
|
271
|
+
# leaves domain-model.md alone at finalize and must leave its version alone here.
|
|
272
|
+
# `bumped: false` is a normal outcome, not a failure — most changes never touch the
|
|
273
|
+
# model — so on_error: continue and the gate is the report, not a stop.
|
|
274
|
+
- id: bump_context_version
|
|
275
|
+
action: execute_script
|
|
276
|
+
on_error: continue
|
|
277
|
+
script: { ref: actions }
|
|
278
|
+
subcommand: context-version-bump
|
|
279
|
+
args: ["--feature-dir", "{{feature_dir}}", "--cr-id", "{{active_change}}", "--touched-model", "{{delta_model_exists}}"]
|
|
147
280
|
outputs:
|
|
148
|
-
- { name:
|
|
149
|
-
- { name:
|
|
281
|
+
- { name: context_bumped, from: "$.bumped" }
|
|
282
|
+
- { name: context_version, from: "$.version" }
|
|
283
|
+
- { name: context_version_before, from: "$.previous" }
|
|
284
|
+
- { name: context_bump_reason, from: "$.reason" }
|
|
285
|
+
- { name: bounded_context, from: "$.context" }
|
|
150
286
|
|
|
151
287
|
# 5. Anchor the CLOSE in the OKF bundle's freshness journal (log.md, OKF §7).
|
|
152
288
|
# finalize-delta logs the MERGE; this logs the SHIP — the version bump is the event
|
|
@@ -180,4 +316,11 @@ outputs:
|
|
|
180
316
|
previous_version: "{{previous_version}}"
|
|
181
317
|
archived_dir: "{{archived_dir}}"
|
|
182
318
|
stamped_docs: "{{stamped_docs}}"
|
|
183
|
-
|
|
319
|
+
# The bounded context's own spine — a DIFFERENT number from the feature's, moved only
|
|
320
|
+
# when this change carried a model delta. context_bumped=false on a behaviour-only
|
|
321
|
+
# change is the correct outcome, not a skipped step.
|
|
322
|
+
bounded_context: "{{bounded_context}}"
|
|
323
|
+
context_version: "{{context_version}}"
|
|
324
|
+
context_version_bumped: "{{context_bumped}}"
|
|
325
|
+
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, that row 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 and domain-model.md only, because backend-plan.md / frontend-plan.md are DERIVED from those two 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."
|
|
@@ -36,7 +36,7 @@ workflow:
|
|
|
36
36
|
action: verify_context
|
|
37
37
|
require_non_empty: feature_dir
|
|
38
38
|
on_empty: stop
|
|
39
|
-
on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the
|
|
39
|
+
on_empty_message: "No active feature. Run /appweaver select-feature first (pick or create the feature, e.g. Order or PatientRegistration), then re-run deploy."
|
|
40
40
|
|
|
41
41
|
# Pre-deploy hooks (e.g. a final smoke/build gate configured by the project).
|
|
42
42
|
- id: resolve_pre_hooks
|