aw-spec-cli 0.1.19 → 0.1.21
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 +17 -9
- package/assets/.appweaver/ORCH-DIALECT.md +8 -3
- package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +26 -3
- package/assets/.appweaver/orchestrator/orchestrator.py +65 -3
- package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +1 -1
- package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +4 -2
- 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 +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +121 -42
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +7 -7
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +145 -52
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +18 -10
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +306 -28
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +4 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-deploy.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +114 -30
- package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +140 -36
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +385 -61
- package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +217 -174
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +407 -107
- package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +1 -1
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +49 -11
- package/assets/.appweaver/orchestrator/workflows/aw-spec-recall-delta.orch.yaml +1 -1
- 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-select-stack.orch.yaml +47 -23
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +19 -11
- package/assets/.appweaver/scripts/bash/aw-inventory.sh +15 -0
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +683 -92
- package/assets/.appweaver/scripts/bash/aw-xref.sh +3 -0
- package/assets/.appweaver/scripts/powershell/aw-inventory.ps1 +15 -0
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +625 -64
- package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +3 -0
- package/assets/.appweaver/scripts/python/aw-crstate.py +194 -0
- package/assets/.appweaver/scripts/python/aw-foundation.py +151 -0
- package/assets/.appweaver/scripts/python/aw-inventory.py +1829 -63
- package/assets/.appweaver/scripts/python/aw-payload-parity.py +3 -0
- package/assets/.appweaver/scripts/python/aw-plan-coverage.py +423 -0
- package/assets/.appweaver/scripts/python/aw-stack.py +251 -28
- package/assets/.appweaver/scripts/python/aw-testlog.py +148 -0
- package/assets/.appweaver/scripts/python/aw-xref.py +500 -81
- package/assets/.appweaver/stack-profiles/dotnet-webapi.json +1 -0
- package/assets/.appweaver/stack-profiles/java-spring.json +1 -0
- package/assets/.appweaver/stack-profiles/node-express.json +1 -0
- package/assets/.appweaver/stack-profiles/python-fastapi.json +1 -0
- package/assets/.appweaver/templates/constitution-domain-template.md +17 -2
- 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 +16 -11
- 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 +17 -17
- package/assets/.appweaver/templates/ui-delta-design-template.md +1 -1
- package/assets/.appweaver/templates/ui-design-template.md +4 -4
- package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +4489 -361
- package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +2274 -125
- package/assets/guardrails/projects/dotnet-default-project/domain-rule-bindings.md +10 -6
- package/assets/guardrails/projects/dotnet-default-project/tech-rule-bindings.md +4 -0
- package/assets/guardrails/technology/dotnet-webapi/auditing.md +3 -1
- package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +5 -3
- package/assets/guardrails/technology/dotnet-webapi/cqrs.md +5 -1
- package/assets/guardrails/technology/dotnet-webapi/domain-driven-design.md +13 -5
- package/assets/guardrails/technology/dotnet-webapi/examples/cqrs.md +2 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/domain-driven-design.md +6 -2
- package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +70 -0
- package/assets/guardrails/technology/dotnet-webapi/technology-constitution.md +3 -0
- package/assets/guardrails/technology/dotnet-webapi/testing.md +10 -0
- package/assets/guardrails/technology/nextjs/ui-constitution.md +8 -1
- package/package.json +1 -1
- package/assets/.appweaver/orchestrator/.state/smoke.state.json +0 -32
|
@@ -1,37 +1,52 @@
|
|
|
1
1
|
# =============================================================================
|
|
2
|
-
# aw-spec-inventory (orchestrator) —
|
|
2
|
+
# aw-spec-inventory (orchestrator) — brownfield discovery
|
|
3
3
|
#
|
|
4
|
-
# The
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# backlog. Each candidate aggregate is a future specs/<Feature>/ vertical slice —
|
|
8
|
-
# this bundle is the BASE the forward brownfield steps read to reverse-engineer
|
|
9
|
-
# spec.md + backend-plan.md per slice.
|
|
4
|
+
# The first command of the brownfield sequence after select-stack. It answers
|
|
5
|
+
# one question and writes it down: WHICH FEATURES AND BOUNDED CONTEXTS does this
|
|
6
|
+
# codebase contain, and in what order can they be onboarded?
|
|
10
7
|
#
|
|
11
|
-
#
|
|
8
|
+
# select-stack → INVENTORY → [edit the proposal] → inventory apply
|
|
9
|
+
# → onboard <BoundedContext> (once per context)
|
|
10
|
+
# ← you are here
|
|
12
11
|
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
12
|
+
# Three passes over the code. The generated document explains each of them to the
|
|
13
|
+
# operator reading it; the wording lives in the template
|
|
14
|
+
# .appweaver/templates/proposed-inventory-template.md, overridable per project:
|
|
15
|
+
# A aggregate identification — what must stay consistent together. Three
|
|
16
|
+
# strategies (structure / reference graph / persistence), each offered only
|
|
17
|
+
# where the evidence for it exists, each reporting its own numbers.
|
|
18
|
+
# B the seam overlay — what can be cut over together. Always runs, over
|
|
19
|
+
# application/API/UI only. Emits signals, never decisions.
|
|
20
|
+
# C the proposal — 1:1 aggregate-to-feature by default, splits proposed with
|
|
21
|
+
# their evidence and never applied, grouped into bounded contexts and
|
|
22
|
+
# ordered into dependency waves.
|
|
19
23
|
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
24
|
+
# The deliverable is `specs/proposed-inventory.md` — an EDITABLE document. The
|
|
25
|
+
# operator renames, moves, merges, splits and re-orders in that file, then runs
|
|
26
|
+
# `/appweaver inventory apply`, which validates every edit and regenerates the
|
|
27
|
+
# machine map `.appweaver/inventory/feature-map.json` that onboard reads.
|
|
22
28
|
#
|
|
23
|
-
#
|
|
29
|
+
# It does NOT author specs, plans or governance (that is onboard, per context)
|
|
30
|
+
# and never modifies source.
|
|
31
|
+
#
|
|
32
|
+
# Launch: /appweaver inventory [structure|reference|persistence] [focus hints]
|
|
33
|
+
# /appweaver inventory apply
|
|
24
34
|
# =============================================================================
|
|
25
35
|
|
|
26
36
|
name: aw-spec-inventory
|
|
27
|
-
description:
|
|
28
|
-
version:
|
|
37
|
+
description: Brownfield discovery — scan an existing codebase and propose its Features and Bounded Contexts, in dependency order with their dependencies, as an editable specs/proposed-inventory.md. Runs three passes (aggregate identification by a selectable evidence-gated strategy, a seam overlay over application/API/UI, and a 1:1-by-default feature proposal with evidenced splits offered but never applied). `apply` validates the operator's edits and regenerates the machine map onboard consumes. Never modifies source.
|
|
38
|
+
version: 2.0.0
|
|
29
39
|
agent_agnostic: true
|
|
30
40
|
dialect: aw-spec.orchestrator/v1
|
|
31
41
|
|
|
32
42
|
inputs:
|
|
33
43
|
user_input:
|
|
34
|
-
description:
|
|
44
|
+
description: >-
|
|
45
|
+
Either the literal word `apply` — validate the edited specs/proposed-inventory.md
|
|
46
|
+
and regenerate the machine map — or an optional Pass A strategy name
|
|
47
|
+
(structure | reference | persistence) to force, plus free-text focus hints.
|
|
48
|
+
With no argument, the highest-coverage available strategy is proposed and the
|
|
49
|
+
operator confirms it from a menu carrying each strategy's measured numbers.
|
|
35
50
|
required: false
|
|
36
51
|
bind: USER_INPUT
|
|
37
52
|
|
|
@@ -43,181 +58,190 @@ scripts:
|
|
|
43
58
|
sh: .appweaver/scripts/bash/aw-spec-actions.sh
|
|
44
59
|
ps1: .appweaver/scripts/powershell/aw-spec-actions.ps1
|
|
45
60
|
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
# and the clean/torn seam test — in terms no stack owns, which is what lets this
|
|
49
|
-
# scan run against an arbitrary codebase. A rule file here would reach every step
|
|
50
|
-
# (this is the sticky set) and would hand the agent one project's house style as
|
|
51
|
-
# the shape to look for.
|
|
61
|
+
# Nothing project-shaped in the sticky set: every pass here is deterministic and
|
|
62
|
+
# reads the code, so no rule file or exemplar has any part to play.
|
|
52
63
|
standards:
|
|
53
64
|
- { path: .appweaver/ai-rules.md } # kit-resident: the universal operating rules, every flow
|
|
54
65
|
|
|
55
66
|
vars:
|
|
56
|
-
|
|
57
|
-
|
|
67
|
+
mode: "propose" # apply-mode driver
|
|
68
|
+
strategy: "" # forced Pass A strategy; empty = probe default
|
|
69
|
+
feature_count: "0"
|
|
70
|
+
proposal_ok: "false"
|
|
58
71
|
|
|
59
72
|
workflow:
|
|
60
73
|
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
# 0. MODE. The engine compares variables as text and has no compound
|
|
75
|
+
# conditions, so the two entry points are separated by one ordered set.
|
|
76
|
+
- id: mode_apply
|
|
77
|
+
action: set
|
|
78
|
+
condition: "{{USER_INPUT}} == apply"
|
|
79
|
+
vars: { mode: "apply" }
|
|
80
|
+
|
|
81
|
+
# ═══════════════════ APPLY — read the operator's edits back ═══════════════
|
|
82
|
+
# Runs first and stops the workflow, so the propose half never re-derives a
|
|
83
|
+
# map over the top of an edited one.
|
|
84
|
+
|
|
85
|
+
- id: apply_edits
|
|
65
86
|
action: execute_script
|
|
87
|
+
condition: "{{mode}} == apply"
|
|
66
88
|
script: { ref: inventory }
|
|
67
|
-
subcommand:
|
|
89
|
+
subcommand: apply
|
|
90
|
+
on_error: continue
|
|
68
91
|
outputs:
|
|
69
|
-
- { name:
|
|
70
|
-
- { name:
|
|
71
|
-
- { name:
|
|
72
|
-
- { name:
|
|
73
|
-
- { name:
|
|
74
|
-
- { name:
|
|
75
|
-
- { name:
|
|
76
|
-
- { name:
|
|
77
|
-
|
|
78
|
-
# 1b. Substance gate: a scan that found no aggregate candidates has nothing to
|
|
79
|
-
# organize a bundle around (empty repo, or no recognizable domain layout).
|
|
80
|
-
- id: require_aggregates
|
|
81
|
-
action: verify_context
|
|
82
|
-
require_true: aggregate_count
|
|
83
|
-
on_false: stop
|
|
84
|
-
on_false_message: "Scan found no candidate aggregates in {{root}} (file_count={{file_count}}). Point /appweaver inventory at a codebase with a recognizable domain/vertical-slice layout, or scan a subtree that contains one."
|
|
92
|
+
- { name: proposal_ok, from: "$.ok" }
|
|
93
|
+
- { name: feature_map, from: "$.feature_map" }
|
|
94
|
+
- { name: feature_count, from: "$.feature_count" }
|
|
95
|
+
- { name: context_count, from: "$.context_count" }
|
|
96
|
+
- { name: wave_count, from: "$.wave_count" }
|
|
97
|
+
- { name: cycle_count, from: "$.cycle_count" }
|
|
98
|
+
- { name: contexts_ordered, from: "$.contexts_ordered" }
|
|
99
|
+
- { name: apply_problems, from: "$.problems" }
|
|
85
100
|
|
|
86
|
-
#
|
|
87
|
-
#
|
|
88
|
-
|
|
89
|
-
- id: bundle_guard
|
|
101
|
+
# A rejected edit names the row it could not resolve. Stopping here is the
|
|
102
|
+
# point: a map built from a half-understood file would be onboarded silently.
|
|
103
|
+
- id: apply_gate
|
|
90
104
|
action: verify_context
|
|
91
|
-
|
|
92
|
-
|
|
105
|
+
condition: "{{mode}} == apply"
|
|
106
|
+
require_value: proposal_ok
|
|
107
|
+
equals: "true"
|
|
93
108
|
on_mismatch: stop
|
|
94
|
-
on_mismatch_message:
|
|
109
|
+
on_mismatch_message: >
|
|
110
|
+
specs/proposed-inventory.md could not be applied: {{apply_problems}}
|
|
111
|
+
Fix those rows and re-run /appweaver inventory apply. The Aggregate column
|
|
112
|
+
must name an aggregate the scan found; every Depends On value must name a
|
|
113
|
+
Feature that exists in the same table.
|
|
95
114
|
|
|
96
|
-
|
|
97
|
-
|
|
115
|
+
- id: apply_report
|
|
116
|
+
action: verify_context
|
|
117
|
+
condition: "{{mode}} == apply"
|
|
118
|
+
require_non_empty: feature_map
|
|
119
|
+
on_empty: stop
|
|
120
|
+
on_empty_message: "apply reported success but wrote no map — re-run /appweaver inventory."
|
|
121
|
+
|
|
122
|
+
- id: applied
|
|
123
|
+
action: set
|
|
124
|
+
condition: "{{mode}} == apply"
|
|
125
|
+
vars: { next_hint: "Onboard the contexts in order: {{contexts_ordered}}" }
|
|
126
|
+
|
|
127
|
+
# ═══════════════════ PROPOSE — discover and write the map ═════════════════
|
|
128
|
+
|
|
129
|
+
# 1. WHICH LANES, AND WHERE IS THEIR SOURCE. Same declaration onboard reads:
|
|
130
|
+
# the scan is scoped to the declared subtrees so backend candidates are not
|
|
131
|
+
# drawn from UI source and vice versa.
|
|
132
|
+
- id: lane_model
|
|
98
133
|
action: execute_script
|
|
134
|
+
condition: "{{mode}} == propose"
|
|
99
135
|
script: { ref: actions }
|
|
100
|
-
subcommand:
|
|
101
|
-
args: ["--
|
|
102
|
-
outputs:
|
|
103
|
-
- { name: before_hooks, from: "$.hooks" }
|
|
104
|
-
- id: dispatch_pre_hooks
|
|
105
|
-
action: dispatch_hooks
|
|
106
|
-
hooks_from_variable: before_hooks
|
|
107
|
-
|
|
108
|
-
# 3. ENRICHMENT — turn the substrate into an aggregate-organized OKF bundle.
|
|
109
|
-
# Context is fed via build_context (agent_generate reads the envelope, NOT a
|
|
110
|
-
# step-level context: key): the factual substrate, the OKF format authority
|
|
111
|
-
# (generate.md), and the brownfield design (seam/backlog framing).
|
|
112
|
-
- id: ctx_author
|
|
113
|
-
action: build_context
|
|
114
|
-
context:
|
|
115
|
-
- { path: "{{inventory_json}}" } # the deterministic substrate (aggregate_signals etc.)
|
|
116
|
-
- { path: .appweaver/templates/okf-concept-template.md } # OKF v0.1 format authority (frontmatter, index, log, rules)
|
|
117
|
-
- { path: Brownfield-Pipeline.md } # seam-as-unit-of-work, migration backlog, source anchor
|
|
118
|
-
- id: author_bundle
|
|
119
|
-
action: agent_generate
|
|
120
|
-
tools: "Read,Write,Edit"
|
|
121
|
-
permission_mode: acceptEdits
|
|
122
|
-
task: |
|
|
123
|
-
Act as the OKF enrichment agent for the Brownfield-Pipeline INVENTORY (B0)
|
|
124
|
-
phase. Produce a CONFORMANT OKF v0.1 knowledge bundle at {{bundle_dir}},
|
|
125
|
-
organized BY AGGREGATE ROOT, from the deterministic substrate
|
|
126
|
-
{{inventory_json}} (in context). Follow the OKF concept template in context for
|
|
127
|
-
format (frontmatter, index.md/log.md rules, cross-linking, hard rules) —
|
|
128
|
-
but ORGANIZE around aggregates, not services/modules. Scope/focus hints:
|
|
129
|
-
{{USER_INPUT}}
|
|
130
|
-
|
|
131
|
-
Read the substrate first. Its `aggregate_signals` are CANDIDATE roots,
|
|
132
|
-
each with its files grouped by layer (domain / feature / infra / api) plus
|
|
133
|
-
detected entities; `git.history.churn` ranks significance; the category
|
|
134
|
-
lists (data_layer_files, route_like_files, api_definitions, ops_files,
|
|
135
|
-
docs, adr_docs) and `top_level_dirs` fill in the rest. Signals are input,
|
|
136
|
-
NOT decisions — YOU draw the real boundaries.
|
|
137
|
-
|
|
138
|
-
Consolidate the candidates into REAL aggregates:
|
|
139
|
-
- Merge a src module and its mirror test module into ONE aggregate (e.g.
|
|
140
|
-
src/.../MedicinalProducts + tests/.../MedicinalProducts → MedicinalProduct).
|
|
141
|
-
- Treat service-level / shared infrastructure (a shared DbContext, cross-
|
|
142
|
-
cutting adapters) as a Platform/Shared concept, NOT an aggregate.
|
|
143
|
-
- Fold value objects, entities, domain events and CQRS commands/endpoints
|
|
144
|
-
into the aggregate that OWNS them — one aggregate concept, not one per type.
|
|
145
|
-
|
|
146
|
-
Write the bundle (all paths under {{bundle_dir}}, bundle-relative links
|
|
147
|
-
begin with "/", per OKF §5.1):
|
|
148
|
-
- `index.md` (bundle root) — frontmatter EXACTLY `okf_version: "0.1"` and
|
|
149
|
-
nothing else; body = sections of bulleted links reusing each concept's
|
|
150
|
-
`description`.
|
|
151
|
-
- `architecture/overview.md` (type: Reference) — system purpose, the
|
|
152
|
-
AGGREGATE MAP (each aggregate + its seam), tech stack, and links to every
|
|
153
|
-
other concept.
|
|
154
|
-
- `aggregates/<aggregate>.md` (type: Aggregate) — ONE per aggregate root.
|
|
155
|
-
Cover: Responsibilities; the entities / value objects / domain events /
|
|
156
|
-
commands / API endpoints / persistence it owns (from the signal's layer
|
|
157
|
-
files); invariants (INFERRED from code — mark confidence, park anything
|
|
158
|
-
unclear in `open_questions`, never guess); the SEAM (the boundary you
|
|
159
|
-
could route across — repository, endpoint, table owner, queue — and
|
|
160
|
-
whether it is CLEAN or TORN, i.e. shares a transaction/table with another
|
|
161
|
-
slice); and the candidate `specs/<Feature>/` slice name (feature =
|
|
162
|
-
aggregate). Set `source_files` to the module's files, grouped with YAML
|
|
163
|
-
comment headers by each file's OWN folder — the path segment that VARIES
|
|
164
|
-
across the files after their shared parent directory (the layer folder in
|
|
165
|
-
a vertical slice; the tier project in an n-tier / layered app; tests → a
|
|
166
|
-
single `tests` group). Do NOT impose a fixed Domain/Application/UI
|
|
167
|
-
taxonomy — the CODE's folders ARE the grouping, and the toolchain
|
|
168
|
-
re-derives them the same way on every later write. Set `timestamp` to the
|
|
169
|
-
latest commit time across them.
|
|
170
|
-
- `data/` and `api/` concepts only where a data model or API surface needs
|
|
171
|
-
its own home beyond the owning aggregate (medium granularity: prefer
|
|
172
|
-
folding into the aggregate).
|
|
173
|
-
- `migration-backlog.md` (type: Reference, at bundle root) — the B0
|
|
174
|
-
deliverable: a table `| aggregate | candidate slice | seam (clean/torn) |
|
|
175
|
-
depends on | risks | adopt order |`, sequenced so clean seams go first
|
|
176
|
-
and TORN seams are flagged as remediation items (introduce the seam
|
|
177
|
-
before adopting). This is the strangler rollout plan.
|
|
178
|
-
- An `index.md` in EVERY subdirectory (no frontmatter).
|
|
179
|
-
- `log.md` (bundle root) — first line under a `## <today's date>` heading
|
|
180
|
-
must be `Commit: ` + backtick + `{{head}}` + backtick (validator rule E4),
|
|
181
|
-
then a one-line Initialization entry noting the concept count.
|
|
182
|
-
|
|
183
|
-
Provenance + safety (OKF hard rules):
|
|
184
|
-
- Stamp every concept `origin: reverse-engineered` and `generated_by:
|
|
185
|
-
aw-spec-inventory/1.1.0` in frontmatter.
|
|
186
|
-
- The CODE is the source of truth; capture what IS (bugs/quirks included),
|
|
187
|
-
not what SHOULD be. Where intent/invariants are unclear from code + git
|
|
188
|
-
history, add a concrete `open_questions` entry rather than inventing one.
|
|
189
|
-
- NEVER fabricate facts, and NEVER emit secrets/tokens/credentials/internal
|
|
190
|
-
hostnames found in the code — describe shape, never values.
|
|
191
|
-
- Write ONLY inside {{bundle_dir}}; do NOT modify any source file.
|
|
192
|
-
Report the bundle tree and the concept count by type.
|
|
136
|
+
subcommand: lane-verify
|
|
137
|
+
args: ["--command", "/appweaver inventory"]
|
|
193
138
|
outputs:
|
|
194
|
-
- { name:
|
|
139
|
+
- { name: lane_model_ok, from: "$.ok" }
|
|
140
|
+
- { name: lane_model_issues, from: "$.message" }
|
|
141
|
+
- { name: be_root, from: "$.backend_source_path" }
|
|
142
|
+
- { name: fe_root, from: "$.frontend_source_path" }
|
|
195
143
|
|
|
196
|
-
- id:
|
|
144
|
+
- id: lane_model_gate
|
|
197
145
|
action: verify_context
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
146
|
+
condition: "{{mode}} == propose"
|
|
147
|
+
require_true: lane_model_ok
|
|
148
|
+
on_false: stop
|
|
149
|
+
on_false_message: >
|
|
150
|
+
/appweaver inventory cannot run: {{lane_model_issues}}
|
|
151
|
+
The scan is scoped to the declared lanes, so it has to be told which subtree
|
|
152
|
+
holds which lane before it starts. Run /appweaver select-stack first — it
|
|
153
|
+
detects what this repo already is and lets you correct the proposal.
|
|
201
154
|
|
|
202
|
-
#
|
|
203
|
-
|
|
155
|
+
# 2. PASS A + B + C. One deterministic call: every AVAILABLE strategy's
|
|
156
|
+
# clustering is run (cheap — the expensive half is authoring, which does not
|
|
157
|
+
# happen here), the seam overlay is laid over the chosen one, and the
|
|
158
|
+
# proposal is written with its dependency waves.
|
|
159
|
+
- id: propose
|
|
204
160
|
action: execute_script
|
|
161
|
+
condition: "{{mode}} == propose"
|
|
205
162
|
script: { ref: inventory }
|
|
206
|
-
subcommand:
|
|
207
|
-
args: ["--
|
|
163
|
+
subcommand: propose
|
|
164
|
+
args: ["--service-root", "{{be_root}}", "--ui-root", "{{fe_root}}", "--strategy", "{{strategy}}"]
|
|
208
165
|
outputs:
|
|
209
|
-
- { name:
|
|
210
|
-
- { name:
|
|
211
|
-
- { name:
|
|
212
|
-
- { name:
|
|
166
|
+
- { name: proposal_ok, from: "$.ok" }
|
|
167
|
+
- { name: proposal_md, from: "$.proposal_md" }
|
|
168
|
+
- { name: feature_map, from: "$.feature_map" }
|
|
169
|
+
- { name: root, from: "$.root" }
|
|
170
|
+
- { name: chosen_strategy, from: "$.strategy" }
|
|
171
|
+
- { name: feature_count, from: "$.feature_count" }
|
|
172
|
+
- { name: context_count, from: "$.context_count" }
|
|
173
|
+
- { name: wave_count, from: "$.wave_count" }
|
|
174
|
+
- { name: cycle_count, from: "$.cycle_count" }
|
|
175
|
+
- { name: coverage_pct, from: "$.coverage_pct" }
|
|
176
|
+
- { name: split_candidates, from: "$.split_candidates" }
|
|
177
|
+
- { name: contexts_ordered, from: "$.contexts_ordered" }
|
|
178
|
+
- { name: strategy_options, from: "$.strategy_options" }
|
|
213
179
|
|
|
214
|
-
|
|
180
|
+
# 2b. Substance gate. Zero features is the one outcome that leaves onboard with
|
|
181
|
+
# nothing to do, and it is reported as what it is rather than as a crash.
|
|
182
|
+
- id: require_features
|
|
215
183
|
action: verify_context
|
|
216
|
-
|
|
184
|
+
condition: "{{mode}} == propose"
|
|
185
|
+
require_true: feature_count
|
|
217
186
|
on_false: stop
|
|
218
|
-
on_false_message:
|
|
187
|
+
on_false_message: >
|
|
188
|
+
No candidate features were found in {{root}}. Every Pass A strategy either
|
|
189
|
+
returned nothing or was unavailable for want of evidence. Point
|
|
190
|
+
/appweaver inventory at a subtree that holds application source, or check
|
|
191
|
+
that the lane declaration names the right path.
|
|
192
|
+
|
|
193
|
+
# 3. THE STRATEGY PICK. Offered from the probe, each option carrying its own
|
|
194
|
+
# measured numbers — features found, share of source covered, how many
|
|
195
|
+
# one-file candidates it produced. A strategy that would return nothing is
|
|
196
|
+
# not in the list, because choosing it would be the zero-candidate stop
|
|
197
|
+
# arrived at deliberately. One option auto-confirms.
|
|
198
|
+
- id: pick_strategy
|
|
199
|
+
action: user_select
|
|
200
|
+
condition: "{{mode}} == propose"
|
|
201
|
+
prompt: >
|
|
202
|
+
Pass A found these candidate boundaries. Which evidence should the feature
|
|
203
|
+
map be built from? (`{{chosen_strategy}}` is proposed: highest coverage,
|
|
204
|
+
ties broken by fewest single-file candidates.)
|
|
205
|
+
options_from_variable: strategy_options
|
|
206
|
+
preselect_from: chosen_strategy
|
|
207
|
+
single_option_confirm: true
|
|
208
|
+
outputs:
|
|
209
|
+
- { name: picked, from: selection }
|
|
210
|
+
|
|
211
|
+
# 4. Re-derive on the operator's pick. Deterministic and about a second, so it
|
|
212
|
+
# is re-run unconditionally rather than branched on whether the pick moved.
|
|
213
|
+
- id: repropose
|
|
214
|
+
action: execute_script
|
|
215
|
+
condition: "{{mode}} == propose"
|
|
216
|
+
script: { ref: inventory }
|
|
217
|
+
subcommand: propose
|
|
218
|
+
args: ["--service-root", "{{be_root}}", "--ui-root", "{{fe_root}}", "--strategy", "{{picked}}"]
|
|
219
|
+
outputs:
|
|
220
|
+
- { name: proposal_md, from: "$.proposal_md" }
|
|
221
|
+
- { name: feature_map, from: "$.feature_map" }
|
|
222
|
+
- { name: chosen_strategy, from: "$.strategy" }
|
|
223
|
+
- { name: feature_count, from: "$.feature_count" }
|
|
224
|
+
- { name: context_count, from: "$.context_count" }
|
|
225
|
+
- { name: wave_count, from: "$.wave_count" }
|
|
226
|
+
- { name: cycle_count, from: "$.cycle_count" }
|
|
227
|
+
- { name: coverage_pct, from: "$.coverage_pct" }
|
|
228
|
+
- { name: split_candidates, from: "$.split_candidates" }
|
|
229
|
+
- { name: contexts_ordered, from: "$.contexts_ordered" }
|
|
230
|
+
|
|
231
|
+
# 5. Hooks, after the map exists and before the operator is handed it.
|
|
232
|
+
- id: resolve_pre_hooks
|
|
233
|
+
action: execute_script
|
|
234
|
+
condition: "{{mode}} == propose"
|
|
235
|
+
script: { ref: actions }
|
|
236
|
+
subcommand: resolve-hooks
|
|
237
|
+
args: ["--phase", "before_inventory"]
|
|
238
|
+
outputs:
|
|
239
|
+
- { name: before_hooks, from: "$.hooks" }
|
|
240
|
+
- id: dispatch_pre_hooks
|
|
241
|
+
action: dispatch_hooks
|
|
242
|
+
condition: "{{mode}} == propose"
|
|
243
|
+
hooks_from_variable: before_hooks
|
|
219
244
|
|
|
220
|
-
# 5. Post-execution hooks.
|
|
221
245
|
- id: resolve_post_hooks
|
|
222
246
|
action: execute_script
|
|
223
247
|
script: { ref: actions }
|
|
@@ -230,9 +254,28 @@ workflow:
|
|
|
230
254
|
hooks_from_variable: after_hooks
|
|
231
255
|
|
|
232
256
|
outputs:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
257
|
+
proposal: "{{proposal_md}}"
|
|
258
|
+
feature_map: "{{feature_map}}"
|
|
259
|
+
strategy: "{{chosen_strategy}}"
|
|
260
|
+
features: "{{feature_count}}"
|
|
261
|
+
contexts: "{{context_count}}"
|
|
262
|
+
waves: "{{wave_count}}"
|
|
263
|
+
cycles: "{{cycle_count}}"
|
|
264
|
+
coverage_pct: "{{coverage_pct}}"
|
|
265
|
+
split_candidates: "{{split_candidates}}"
|
|
266
|
+
contexts_ordered: "{{contexts_ordered}}"
|
|
267
|
+
|
|
268
|
+
next: >
|
|
269
|
+
{{feature_count}} feature(s) across {{context_count}} bounded context(s) were
|
|
270
|
+
proposed from `{{chosen_strategy}}` evidence ({{coverage_pct}}% of source
|
|
271
|
+
covered), ordered into {{wave_count}} dependency wave(s).
|
|
272
|
+
|
|
273
|
+
READ AND EDIT specs/proposed-inventory.md — it is the boundary map, and it is
|
|
274
|
+
yours. Rename features and contexts, move a feature to another context, merge
|
|
275
|
+
two by giving them one name, split one by adding a row with the same Aggregate,
|
|
276
|
+
and set Depends On to change the order. {{split_candidates}} split(s) were
|
|
277
|
+
PROPOSED with their evidence and none were applied.
|
|
278
|
+
|
|
279
|
+
Then run `/appweaver inventory apply` to validate those edits and regenerate the
|
|
280
|
+
machine map, and onboard the contexts one at a time in the order it reports:
|
|
281
|
+
{{contexts_ordered}}
|