aw-spec-cli 0.1.28 → 0.1.30
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/.amp/agent.json +22 -0
- package/assets/.amp/settings-edit.json +5 -0
- package/assets/.amp/settings-read.json +12 -0
- package/assets/.appweaver/DESIGN-FORMAT.md +9 -0
- package/assets/.appweaver/STACK-PROFILES.md +102 -15
- package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +40 -18
- package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +56 -4
- package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +17 -1
- package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +12 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +289 -24
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +370 -85
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +349 -65
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +39 -7
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +63 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +5 -4
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +430 -138
- package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +392 -76
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-lane.orch.yaml +104 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +20 -3
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +26 -3
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +314 -44
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +249 -20
- package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +17 -2
- package/assets/.appweaver/scripts/python/aw-plangate.py +109 -19
- package/assets/.appweaver/scripts/python/aw-stack.py +1295 -9
- package/assets/.appweaver/templates/delta-design-template.md +7 -5
- package/assets/.appweaver/templates/delta-spec-template.md +2 -0
- package/assets/.appweaver/templates/design-template.md +17 -0
- package/assets/.appweaver/templates/ui-design-template.md +19 -4
- package/assets/.augment/agent.json +22 -0
- package/assets/.augment/commands/appweaver.md +12 -0
- package/assets/.cline/agent.json +22 -0
- package/assets/.clinerules/workflows/appweaver.md +7 -0
- package/assets/.codex/agent.json +22 -0
- package/assets/.continue/agent.json +22 -0
- package/assets/.continue/prompts/appweaver.md +13 -0
- package/assets/.cursor/agent.json +22 -0
- package/assets/.cursor/commands/appweaver.md +7 -0
- package/assets/.devin/agent.json +22 -0
- package/assets/.devin/workflows/appweaver.md +11 -0
- package/assets/.factory/agent.json +22 -0
- package/assets/.factory/commands/appweaver.md +12 -0
- package/assets/.gemini/agent.json +22 -0
- package/assets/.github/prompts/appweaver.prompt.md +13 -0
- package/assets/.kilo/agent.json +28 -0
- package/assets/.kilo/agents/appweaver-edit.md +12 -0
- package/assets/.kilo/agents/appweaver-read.md +12 -0
- package/assets/.kilo/commands/appweaver.md +11 -0
- package/assets/.kiro/agent.json +22 -0
- package/assets/.kiro/skills/appweaver/SKILL.md +12 -0
- package/assets/.opencode/agent.json +22 -0
- package/assets/.opencode/agents/appweaver-edit.md +12 -0
- package/assets/.opencode/agents/appweaver-read.md +13 -0
- package/assets/.opencode/commands/appweaver.md +11 -0
- package/assets/.roo/agent.json +22 -0
- package/assets/.roo/commands/appweaver.md +12 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +14 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/utils/config.d.ts.map +1 -1
- package/dist/utils/config.js +14 -0
- package/dist/utils/config.js.map +1 -1
- package/dist/utils/copy-assets.d.ts +16 -3
- package/dist/utils/copy-assets.d.ts.map +1 -1
- package/dist/utils/copy-assets.js +29 -14
- package/dist/utils/copy-assets.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "amp",
|
|
3
|
+
"runtime": "Amp CLI (amp -x)",
|
|
4
|
+
"note": "amp has no system-prompt flag, so 'system' is folded into the prompt (system: prepend), and no model flag (its --mode picks model, system prompt and tools together), so --model is ignored. No tools allowlist or bare mode, so isolation is best-effort: AGENTS.md still loads. -x is execute mode: the prompt is read from stdin and only the last assistant message is printed. --no-ide keeps the open editor's file and selection out of the prompt. Amp has no permission flags, so each step passes one of the kit's settings files with --settings-file: .amp/settings-edit.json allows every tool; .amp/settings-read.json rejects file writes, shell commands and subagents. That file stands in for the developer's own Amp user settings (MCP servers included) for spawned steps only; a workspace .amp/settings.json still applies on top of it. Amp has no launcher of its own: it reads .agents/skills/appweaver/SKILL.md. No sdk block: Amp has no Python SDK adapter, so sdk/sdk-apply are unavailable.",
|
|
5
|
+
"bin": "amp",
|
|
6
|
+
"args": ["-x", "--no-ide"],
|
|
7
|
+
"model_flag": null,
|
|
8
|
+
"system": "prepend",
|
|
9
|
+
"user": { "mode": "stdin" },
|
|
10
|
+
"tools_flag": null,
|
|
11
|
+
"approval": {
|
|
12
|
+
"acceptEdits": ["--settings-file", ".amp/settings-edit.json"],
|
|
13
|
+
"bypassPermissions": ["--settings-file", ".amp/settings-edit.json"],
|
|
14
|
+
"default": [],
|
|
15
|
+
"readonly": ["--settings-file", ".amp/settings-read.json"]
|
|
16
|
+
},
|
|
17
|
+
"isolation": {
|
|
18
|
+
"bare": [],
|
|
19
|
+
"fresh": []
|
|
20
|
+
},
|
|
21
|
+
"result_keys": ["result"]
|
|
22
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"amp.permissions": [
|
|
3
|
+
{ "tool": "create_file", "action": "reject" },
|
|
4
|
+
{ "tool": "edit_file", "action": "reject" },
|
|
5
|
+
{ "tool": "apply_patch", "action": "reject" },
|
|
6
|
+
{ "tool": "delete_file", "action": "reject" },
|
|
7
|
+
{ "tool": "Bash", "action": "reject" },
|
|
8
|
+
{ "tool": "shell_command", "action": "reject" },
|
|
9
|
+
{ "tool": "async_shell_command", "action": "reject" },
|
|
10
|
+
{ "tool": "Task", "action": "reject" }
|
|
11
|
+
]
|
|
12
|
+
}
|
|
@@ -128,6 +128,15 @@ a contract delta raised back to the service lane, never a client workaround. ⌛
|
|
|
128
128
|
will emit that surface as a `design-contract.md` projection; the rule does not change when
|
|
129
129
|
it does, only what §5 reads.
|
|
130
130
|
|
|
131
|
+
**Contract deltas are a request ledger between the two plans.** frontend-plan.md §5 "Contract
|
|
132
|
+
deltas needed" is a table, one `RQ-n` per operation the experience needs and the surface does
|
|
133
|
+
not offer, with the operation id and field shapes it proposes; a request keeps its id for
|
|
134
|
+
life. backend-plan.md §3 answers each in its "Requests from the frontend lane" table —
|
|
135
|
+
`published` under an operation id, or `declined` with the reason — so each lane's developer
|
|
136
|
+
writes only their own plan. `contract-requests` reads both: an open request is a backend-lane
|
|
137
|
+
gap at `analyze-plan`, a declined one or an answered one not yet re-bound is a frontend-lane
|
|
138
|
+
gap. With no backend plan at all, every binding is a request.
|
|
139
|
+
|
|
131
140
|
**`UX-` lives here and only here.** The service design excludes the spec's Experience
|
|
132
141
|
Standards by contract — it realises no experience standard, and a traceability row for one
|
|
133
142
|
would be a fabrication. So a `UX-` that reaches neither design is a dropped requirement,
|
|
@@ -174,6 +174,70 @@ Declaring **`(none)`** for a lane is a real answer and the way a project says it
|
|
|
174
174
|
|
|
175
175
|
---
|
|
176
176
|
|
|
177
|
+
## 2a. `.appweaver/lane.json` — the developer's working lane
|
|
178
|
+
|
|
179
|
+
`stacks.json` says which lanes the **project** has. `lane.json` says which of them the
|
|
180
|
+
**developer on this machine** works on — `backend`, `frontend` or `both`:
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
{
|
|
184
|
+
"_note": "This developer's working lane: backend, frontend or both. Not committed. …",
|
|
185
|
+
"lane": "frontend",
|
|
186
|
+
"set_by": "select-lane",
|
|
187
|
+
"updated": "2026-10-11T07:46:32Z"
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
- **Not committed** (the kit's `.gitignore` lists it). A backend developer and a frontend
|
|
192
|
+
developer on one repository each keep their own, so each can work on their lane at a
|
|
193
|
+
different time from the other.
|
|
194
|
+
- **`select-stack` writes the default** after every declaration — `both` when both lanes are
|
|
195
|
+
declared, otherwise the one that is — so a re-stacked project starts again from every
|
|
196
|
+
declared lane. **`select-lane` narrows it**; its options come from `stacks.json` (all three
|
|
197
|
+
when both lanes are declared, only the declared one otherwise, picked without a question).
|
|
198
|
+
- **A missing file reads as the default**, and so does one that names a lane `stacks.json`
|
|
199
|
+
no longer declares or that cannot be read — `working_note` says which. A stale choice never
|
|
200
|
+
switches a lane off.
|
|
201
|
+
|
|
202
|
+
Every reader (`lane-resolve`, `lane-verify`) reports **`<kind>_working`** beside
|
|
203
|
+
`<kind>_declared`, plus `working_lane`, `working_kinds[]` and three fields for callers that
|
|
204
|
+
narrow: `working_kind` (the ONE kind being worked, or empty when every declared lane is),
|
|
205
|
+
`working_root` and `working_test_path` (that lane's two paths, empty likewise). Empty is
|
|
206
|
+
deliberate — passed as `--kind` or `--under`, it means "every declared lane", which is the
|
|
207
|
+
behaviour from before the file existed.
|
|
208
|
+
|
|
209
|
+
**The rule the phases follow: write the working lane, read the declared one.**
|
|
210
|
+
|
|
211
|
+
| Phase | With a working lane narrower than the declared lanes |
|
|
212
|
+
|---|---|
|
|
213
|
+
| `plan` | scaffolds, authors, re-derives and delta-plans only the working lane; the menu and the re-derive question look only at its master. The other lane's plan is read — the frontend plan binds to the backend plan's published surface. The backend half answers the frontend's open contract requests and writes `api-draft.json`; the frontend half re-binds answered requests and raises new ones (§4.5) |
|
|
214
|
+
| `analyze-plan` | gates, repairs and receipts only the working lane's plan (`.aw-plan-gate.<lane>.json`, that lane's verdict); check 3 reads the other plan and the request ledger, and a finding only it can close is reported for its developer (`plan-gaps --lanes` → `other`). The frontend receipt also hashes the backend plan's §3, so a backend contract change re-gates the frontend |
|
|
215
|
+
| `implement` | offers, receipt-checks and generates only the working lane; a refused receipt skips that lane with the reason. The backend half exports the API document; the frontend half reads it, combined with the drafts, and never starts the service (§4.5) |
|
|
216
|
+
| `build` | compiles only the working lane (`build-compile --kind`); `lane-verify --working-only` does not require the other lane's root on disk. With the backend worked, a green compile re-exports the API document |
|
|
217
|
+
| `analyze-slice` | tests only the working lane (`test-run --kind`); the fix loops' file list is narrowed with `concept-paths --under`; the composition pass runs when the backend is worked |
|
|
218
|
+
| `specify`, `finalize-delta`, `close-delta` | **ignore it** — the spec is written whole, and a change merges and closes with whatever its lanes delivered |
|
|
219
|
+
|
|
220
|
+
**A change records the lanes it touches**, separately from anyone's working lane: the
|
|
221
|
+
`**Lanes**:` line of its `delta-spec.md` — `backend`, `frontend`, or `backend, frontend`.
|
|
222
|
+
`specify` asks when it opens a change, and `plan new` when it opens a plan-only one; the
|
|
223
|
+
options come from `stacks.json`, both lanes first as the default, and one declared lane is
|
|
224
|
+
taken without a question. The answer is not narrowed to the working lane of whoever opened
|
|
225
|
+
the change. A delta-spec without the line, or with the template's `[…]` placeholder, touches
|
|
226
|
+
every declared lane. `cr-lanes` (§6) reads and writes it; `cr-list` and `cr-paths` report it,
|
|
227
|
+
and `cr-list --lane` lists only the changes touching the given lanes.
|
|
228
|
+
|
|
229
|
+
What reads it:
|
|
230
|
+
|
|
231
|
+
| Phase | With a change that names fewer lanes than are declared |
|
|
232
|
+
|---|---|
|
|
233
|
+
| `plan` | the change menu lists only the changes touching a working lane (`cr-list --lane`) and names the others in its question; `plan CR-…` naming one of those stops and says why. A change's delta plans are written only for the lanes it names that are worked and have a master |
|
|
234
|
+
| `analyze-plan` | decides master or report mode per lane: a lane is repaired and receipted unless an open change names it (`cr-list --lane`), so a backend-only change leaves the frontend plan gateable while it is in flight. A report-mode lane's gaps are listed with those this run does not repair |
|
|
235
|
+
| `implement` | changes mode only for the changes naming a working lane (`cr-list --lane`); the others are named in a note and the lane builds from its master. On a change, a working lane it does not name is skipped with that reason; `implement CR-…` naming another lane's change stops |
|
|
236
|
+
| `analyze-plan-delta` | lists only the changes naming a working lane, and gates only the lanes the change names that are worked — a backend-only change needs no frontend delta plan. The other developer's delta plan is read for check 3; a gap only it can close is reported for them (`plan-gaps --lanes`), and its absence is a note. `contract-impact` warns when the service delta changes or removes an operation the frontend master binds to that the frontend delta does not name. A developer working one lane of two writes its report as `delta-plan-analyze-report.<lane>.md` |
|
|
237
|
+
| `analyze-slice-delta` | lists only the changes naming a working lane, and gates only the lanes the change names that are worked and have a delta plan. Each gated lane runs its own tests (`test-run --kind`) and has its result written to `changes/<CR-id>/.aw-slice-gate.<lane>.json` (`slice-gate-stamp`) — `pass` when no test failed and its requirement checks are met, else `fail`, with `tests_ran` saying whether a suite actually ran — committed with the change. A named lane somebody else works on is a note: its developer gates it in their own run. A developer working one lane of two writes the report as `delta-slice-analyze-report.<lane>.md` |
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
177
241
|
## 3. The ownership rule
|
|
178
242
|
|
|
179
243
|
**Lane root folders own their subtree and must be disjoint.** Two generators must never be able
|
|
@@ -445,18 +509,34 @@ A layout the table gets wrong is fixed by writing `test_root` on the lane in `st
|
|
|
445
509
|
### 4.5 `contract_run`, `contract` and `client` — the API contract between the lanes
|
|
446
510
|
|
|
447
511
|
The frontend lane binds to the service through the service's published API document, and
|
|
448
|
-
the document that counts is the one the **built code** serves.
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
512
|
+
the document that counts is the one the **built code** serves. **The backend lane publishes
|
|
513
|
+
it and the frontend lane reads it**, so the two can be built by different developers at
|
|
514
|
+
different times, and a frontend developer never needs the service's code built or its
|
|
515
|
+
runtime installed. Every step warns rather than stops:
|
|
516
|
+
|
|
517
|
+
1. **Export** (`contract-export`) — run by whoever works on the service lane: `implement`
|
|
518
|
+
after its backend half generates, and `build` after a green compile. Start the service
|
|
519
|
+
with the backend lane's `contract_run`, fetch its `contract` URL, write the document to
|
|
453
520
|
`<service lane root folder>/contracts/openapi.json`, and stop the service with
|
|
454
521
|
everything it started. A service already answering at the URL is used as it is, and
|
|
455
|
-
the run says it may be older than the code.
|
|
456
|
-
2. **
|
|
457
|
-
`
|
|
458
|
-
|
|
459
|
-
|
|
522
|
+
the run says it may be older than the code. The document is committed with the service.
|
|
523
|
+
2. **Draft** (`contract-draft`) — run by the backend lane's `plan` and `analyze-plan`:
|
|
524
|
+
`backend-plan.md` §3 drafted by script into `specs/<ctx>/<feature>/api-draft.json`, an
|
|
525
|
+
OpenAPI document of what the plan says the service will serve. Committed with the plan.
|
|
526
|
+
3. **Combine** (`contract-combine`) — run by the frontend half of `implement`: the exported
|
|
527
|
+
document plus every drafted operation it does not serve yet, each marked `x-aw-draft`,
|
|
528
|
+
written to `.appweaver/contracts/openapi.combined.json` (not committed). A drafted
|
|
529
|
+
operation whose id the service serves drops out; one whose route and verb the service
|
|
530
|
+
answers under another id is left out and reported.
|
|
531
|
+
4. **Client** (`contract-client --doc`) — run the frontend lane's `client` command, with
|
|
532
|
+
`{{contract}}` standing for the combined document as seen from where the command runs.
|
|
533
|
+
5. **Check** (`contract-check`) — every operation id the frontend plan cites must be an
|
|
534
|
+
`operationId` in the combined document; the ids that are only drafts are named apart.
|
|
535
|
+
|
|
536
|
+
Between the plans, what the frontend needs and the backend does not publish travels as a
|
|
537
|
+
**request ledger**: `frontend-plan.md` §5 "Contract deltas needed" holds one `RQ-n` per
|
|
538
|
+
request, and `backend-plan.md` §3 "Requests from the frontend lane" answers each —
|
|
539
|
+
published under an operation id, or declined. `contract-requests` reads both (§6).
|
|
460
540
|
|
|
461
541
|
Each key is read from the lane first and from its profile second, so a lane declared
|
|
462
542
|
before the keys existed still answers them. Where the values come from:
|
|
@@ -604,10 +684,17 @@ implementation and the twins cannot drift.
|
|
|
604
684
|
| `lane-declare --profile <id\|label\|none\|detected> [--kind k] [--id lane] [--source-path\|--root p] [--stack label] [--origin declared\|reverse-engineered] [--build/--test/--run/--migrate c] [--run-from repo\|root] [--no-prototype] [--require-existing-root]` | upsert a WHOLE lane — its one caller is `select-stack` (§5). `detected` declares a stack the kit ships no profile for (needs `--stack` and a lane root folder), which is how a legacy WebForms, JSP or ERB lane gets recorded at all |
|
|
605
685
|
| `lane-set (--id lane\|--kind k) [--set KEY=VALUE]… [--unset KEY]…` | change only `contract_run`, `contract` or `client` on a lane already declared, leaving the rest of it alone. An empty VALUE changes nothing; `--unset` puts the key back on the profile's value. Called by `foundation` (a pack's lane settings) and `implement` (the client command a developer supplies) — re-declaring would reset every other command |
|
|
606
686
|
| `contract-export [--timeout s]` | start the service lane with `contract_run`, fetch `contract`, save it to `<service root>/contracts/openapi.json`, stop the service and everything it started. A service already answering at the URL is used as it is, and said so (§4.5) |
|
|
607
|
-
| `contract-
|
|
608
|
-
| `contract-
|
|
609
|
-
| `
|
|
610
|
-
| `
|
|
687
|
+
| `contract-draft --feature-dir p` | draft `api-draft.json` beside the feature's plans from `backend-plan.md`'s API section, by script: each `### \`VERB /route\`` endpoint with its operation id, request and response field shapes (conceptual types → JSON schema, a use case's DTO standing in for a named shape) and error statuses. Rewritten only when it differs; removed when the plan names no endpoint (§4.5) |
|
|
688
|
+
| `contract-combine` | write `.appweaver/contracts/openapi.combined.json`: the exported document plus every feature's drafted operations it does not serve, marked `x-aw-draft`. `ok:false` with a reason when there is neither (§4.5) |
|
|
689
|
+
| `contract-requests --feature-dir p` | the request ledger: the frontend plan's `RQ-n` rows against the backend plan's answers — `open`, `published` (and whether the frontend still has to re-bind), `declined` — with one line per lane's to-do for a prompt to quote |
|
|
690
|
+
| `contract-client [--doc d]` | `run-phase --phase client` for the frontend lane — its `client` command, `{{contract}}` expanded to `--doc` (`implement` passes the combined document), else to the exported one |
|
|
691
|
+
| `contract-check --plan p [--doc d]` | the operation ids a frontend plan cites (its §5 `Operation id` column, or a delta plan's `Contract Binding` rows; never the request table) against the document's `operationId`s — by script, no model. `drafted[]` names the cited ids that are only draft operations |
|
|
692
|
+
| `contract-impact --delta-backend p --frontend-plan p [--delta-frontend p]` | the operations a change's service delta marks `changed` or `removed` in its "Contract deltas for the frontend lane" table that the frontend master plan binds to, and which of them the change's frontend delta plan does not name (`unaddressed[]`) — `analyze-plan-delta`'s warning. By script, no model |
|
|
693
|
+
| `lane-resolve [--kind k] [--id lane] [--feature-dir p]` | read; exit 0 always. `exists` reports the file, `declared` reports the lanes — the shipped-but-unfilled seed is `exists:true, declared:false`. Returns the matched lane **and** both kinds flattened — `backend_source_path`, `frontend_root_exists`, `backend_build` … — so a workflow binds one variable instead of calling twice — and the working-lane fields of §2a |
|
|
694
|
+
| `lane-verify [--require backend\|frontend]… [--allow-missing-root] [--working-only] [--command phase]` | **the gate**: is the declaration usable for the phase about to run. Never writes, and **always exits 0** — the calling workflow's `verify_context` owns the stop, so the reason arrives as text. `--working-only` checks on disk only the working lanes' root folders and the required kinds (§2a) |
|
|
695
|
+
| `lane-select [--lane backend\|frontend\|both] [--default] [--preselect text]` | read or write `.appweaver/lane.json` (§2a). No argument reads it and returns the `select_options[]` the declared stacks offer; `--lane` writes one of them; `--default` writes the default — `select-stack`'s call |
|
|
696
|
+
| `cr-lanes [--cr-id id [--feature-dir p] [--stamp] [--set both\|backend\|frontend]]` | the lanes a change touches (§2a). No `--cr-id` returns the `select_options[]` the declared stacks offer, both first; with it, reads that change's `**Lanes**:` line — `lanes[]` is what it touches among the lanes declared now, every declared lane when nothing is recorded. `--set` writes an answer (a whole option line is accepted); `--stamp` alone writes every declared lane |
|
|
697
|
+
| `slice-gate-stamp --cr-id id --lane backend\|frontend [--feature-dir p] [--tests-green b] [--tests-ran b] [--requirements-ok b] [--findings json]` | write one lane's `analyze-slice-delta` result to `changes/<id>/.aw-slice-gate.<lane>.json` (§2a): `verdict` `pass` when no test failed and the requirements are met, else `fail`, with `tests_ran` (false when the lane declares no test command, so nothing ran), the findings counts and the sha256 of the delta-spec and the lane's delta plan it was gated against. Findings that cannot be read are recorded as `null`, never as none |
|
|
611
698
|
| `lane-probe [--kind k] [--hint text]` | read; the **file** signals for "does this lane exist" — a declared lane, and a stack named in free prose. Retained for callers that want a soft hint; the authoritative answer is the declaration, read through `lane-resolve` or `lane-verify` |
|
|
612
699
|
|
|
613
700
|
Both `lane-declare` branches — declaring a lane and declaring `none` — emit the **same key
|
|
@@ -618,7 +705,7 @@ set**, so a caller binds outputs without knowing which branch ran.
|
|
|
618
705
|
| Subcommand | With a declaration | With none |
|
|
619
706
|
|---|---|---|
|
|
620
707
|
| `build-compile` | every declared lane's own `build`, via `run-phase` | the historic first-match-wins ladder |
|
|
621
|
-
| `test-run` | every declared lane's own `test`, via `run-phase` — **except** `--scope slice` on a repo where a .NET toolchain is present, which keeps the VSTest `--filter` path | the historic ladder |
|
|
708
|
+
| `test-run` | every declared lane's own `test`, via `run-phase` — **except** `--scope slice` on a repo where a .NET toolchain is present, which keeps the VSTest `--filter` path. `--kind` runs one lane only; `--kind frontend` always delegates, since the VSTest path runs the service's suite | the historic ladder |
|
|
622
709
|
| `run-migrate` | a lane's declared `migrate` (§4.2) when there is one; otherwise `dotnet ef` searched under the **service lane root folder** rather than an assumed `src/` | `dotnet ef` under `src/` |
|
|
623
710
|
| `find-host-project` | searches the service lane root folder, and reports the lane's `ecosystem` | searches `src/` |
|
|
624
711
|
| `foundation-list`, `list-components` | narrowed to the `ecosystem` of the lane being scaffolded, else of every declared lane; `foundation-list` also by each entry's `# kind:` / `# profiles:` (§4.1) | unfiltered / `dotnet` |
|
|
@@ -42,8 +42,17 @@
|
|
|
42
42
|
#
|
|
43
43
|
# Runs in the CALLER's context (include semantics): shares vars + the sticky standards
|
|
44
44
|
# (plan's per-lane rule sets) + the caller's scripts map + replay cache.
|
|
45
|
+
# ONLY THE WORKING LANES THE CHANGE NAMES ARE AUTHORED. be_existing / fe_existing arrive
|
|
46
|
+
# from the caller already narrowed to the developer's working lanes (.appweaver/lane.json)
|
|
47
|
+
# and to the lanes on the change's **Lanes** line, so a lane that is somebody else's, or
|
|
48
|
+
# that the change does not touch, gets no delta plan here. The other half of the change is
|
|
49
|
+
# READ: the frontend delta plan binds to delta_backend_plan_read, the change's service delta
|
|
50
|
+
# plan as the backend developer left it — absent for a frontend-only change, whose bindings
|
|
51
|
+
# are to the master's published surface.
|
|
52
|
+
#
|
|
45
53
|
# EXPECTS caller vars: feature_dir, spec_file, backend_plan, frontend_plan, domain_model,
|
|
46
54
|
# be_existing, fe_existing, fe_lane_id, source_files, source_count, USER_INPUT,
|
|
55
|
+
# delta_backend_plan_read,
|
|
47
56
|
# and — resolved by the caller from the change it chose and activated — cr_id, cr_dir,
|
|
48
57
|
# delta_spec, delta_model, wave, predecessor_files, predecessor_count, predecessor_ids,
|
|
49
58
|
# sibling_count, sibling_ids, related_docs.
|
|
@@ -82,6 +91,7 @@ vars:
|
|
|
82
91
|
related_docs: []
|
|
83
92
|
delta_backend_plan: ""
|
|
84
93
|
delta_frontend_plan: ""
|
|
94
|
+
delta_backend_plan_read: ""
|
|
85
95
|
|
|
86
96
|
workflow:
|
|
87
97
|
|
|
@@ -134,13 +144,16 @@ workflow:
|
|
|
134
144
|
# the lane's ratified technology base, the same one
|
|
135
145
|
# the master plan is authored under — no domain.
|
|
136
146
|
- { path: "{{cr_dir}}/delta-slice-analyze-report.md", optional: true }
|
|
147
|
+
- { path: "{{cr_dir}}/delta-slice-analyze-report.backend.md", optional: true }
|
|
137
148
|
# WHAT THE LAST GATE FOUND, when this change
|
|
138
|
-
# has already been through analyze-slice-delta
|
|
139
|
-
#
|
|
140
|
-
#
|
|
141
|
-
#
|
|
142
|
-
#
|
|
143
|
-
#
|
|
149
|
+
# has already been through analyze-slice-delta —
|
|
150
|
+
# the run that gated every lane, and the one that
|
|
151
|
+
# gated the backend alone. A `plan` finding there
|
|
152
|
+
# says THIS document is what was wrong, and
|
|
153
|
+
# re-deriving it is how that finding is closed —
|
|
154
|
+
# the alternative is hand-editing a generated
|
|
155
|
+
# plan, which every authoring rule forbids.
|
|
156
|
+
# Absent on a first pass.
|
|
144
157
|
- { path: .appweaver/DESIGN-FORMAT.md }
|
|
145
158
|
- id: author_backend_delta
|
|
146
159
|
condition: "{{be_existing}} == true"
|
|
@@ -159,8 +172,10 @@ workflow:
|
|
|
159
172
|
IS, and a delta that ignores the difference plans an edit to something that is not
|
|
160
173
|
there. Where the two disagree, plan against the code and record the divergence as
|
|
161
174
|
a WA-n.
|
|
162
|
-
- THE LAST GATE'S REPORT, when one is in context (delta-slice-analyze-report.md
|
|
163
|
-
|
|
175
|
+
- THE LAST GATE'S REPORT, when one is in context (delta-slice-analyze-report.md from
|
|
176
|
+
a run that gated every lane, delta-slice-analyze-report.backend.md from one that
|
|
177
|
+
gated the backend alone; when both are, the one with the later date is the last
|
|
178
|
+
gate). It records what analyze-slice-delta found the last time this change was gated. A
|
|
164
179
|
finding tagged `fix: plan` says THIS document was what was wrong — re-derive the
|
|
165
180
|
rows it names, against the code it names. EVIDENCE, never a requirement source: the
|
|
166
181
|
delta-spec stays the only authority on what the change must do, and a finding
|
|
@@ -245,21 +260,26 @@ workflow:
|
|
|
245
260
|
- { path: "{{delta_model}}", optional: true }
|
|
246
261
|
- "{{spec_file}}" # the current master spec (READ ONLY)
|
|
247
262
|
- "{{frontend_plan}}" # the current master plan (READ ONLY — never amended here)
|
|
248
|
-
- { path: "{{
|
|
263
|
+
- { path: "{{delta_backend_plan_read}}", optional: true }
|
|
249
264
|
# THE SERVICE HALF of this same change — its contract
|
|
250
|
-
# table is what this lane binds to.
|
|
265
|
+
# table is what this lane binds to. READ here, and
|
|
266
|
+
# authored above only when the backend is a working
|
|
267
|
+
# lane: another developer may own it. Optional: an
|
|
251
268
|
# experience-only change has no service delta, and a
|
|
252
269
|
# frontend-only project has no service lane at all.
|
|
253
270
|
- { path: "{{domain_model}}", optional: true }
|
|
254
271
|
- { path: .appweaver/memory/constitution.ui.md, optional: true }
|
|
255
272
|
- { path: "{{cr_dir}}/delta-slice-analyze-report.md", optional: true }
|
|
273
|
+
- { path: "{{cr_dir}}/delta-slice-analyze-report.frontend.md", optional: true }
|
|
256
274
|
# WHAT THE LAST GATE FOUND, when this change
|
|
257
|
-
# has already been through analyze-slice-delta
|
|
258
|
-
#
|
|
259
|
-
#
|
|
260
|
-
#
|
|
261
|
-
#
|
|
262
|
-
#
|
|
275
|
+
# has already been through analyze-slice-delta —
|
|
276
|
+
# the run that gated every lane, and the one that
|
|
277
|
+
# gated the frontend alone. A `plan` finding there
|
|
278
|
+
# says THIS document is what was wrong, and
|
|
279
|
+
# re-deriving it is how that finding is closed —
|
|
280
|
+
# the alternative is hand-editing a generated
|
|
281
|
+
# plan, which every authoring rule forbids.
|
|
282
|
+
# Absent on a first pass.
|
|
263
283
|
- { path: .appweaver/DESIGN-FORMAT.md }
|
|
264
284
|
- id: author_frontend_delta
|
|
265
285
|
condition: "{{fe_existing}} == true"
|
|
@@ -276,8 +296,10 @@ workflow:
|
|
|
276
296
|
feature: {{source_files}}. Read the ones this change touches — a delta that plans
|
|
277
297
|
an edit to a component that is not there, or that duplicates one that is, costs a
|
|
278
298
|
whole implementation pass to discover.
|
|
279
|
-
- THE LAST GATE'S REPORT, when one is in context (delta-slice-analyze-report.md
|
|
280
|
-
|
|
299
|
+
- THE LAST GATE'S REPORT, when one is in context (delta-slice-analyze-report.md from
|
|
300
|
+
a run that gated every lane, delta-slice-analyze-report.frontend.md from one that
|
|
301
|
+
gated the frontend alone; when both are, the one with the later date is the last
|
|
302
|
+
gate). It records what analyze-slice-delta found the last time this change was gated. A
|
|
281
303
|
finding tagged `fix: plan` says THIS document was what was wrong — re-derive the
|
|
282
304
|
rows it names, against the code it names. EVIDENCE, never a requirement source: the
|
|
283
305
|
delta-spec stays the only authority on what the change must do, and a finding
|
|
@@ -25,11 +25,17 @@
|
|
|
25
25
|
# Runs in the CALLER's context (include semantics): shares vars + the sticky standards
|
|
26
26
|
# (specify's DDD authority + the selected domain rule files) + the caller's scripts map
|
|
27
27
|
# + replay cache.
|
|
28
|
+
# THE CHANGE'S LANES. Before opening the change this module asks which lanes it touches —
|
|
29
|
+
# both (the default), backend or frontend, from the stacks declared — and stamps the answer
|
|
30
|
+
# on the delta-spec's **Lanes** line. That is the only thing the answer does here: the
|
|
31
|
+
# delta is still specified whole. It does not follow .appweaver/lane.json either; the
|
|
32
|
+
# question is about the change, not about who is running specify.
|
|
33
|
+
#
|
|
28
34
|
# EXPECTS caller vars: feature_dir, spec_file, USER_INPUT, domain_model,
|
|
29
35
|
# pending_model_files.
|
|
30
|
-
# PRODUCES: cr_id, cr_dir, delta_spec, delta_model, wave, open_count (and,
|
|
31
|
-
# an OPEN change). The change's LANE PLANS are scaffolded by `plan`,
|
|
32
|
-
#
|
|
36
|
+
# PRODUCES: cr_id, cr_dir, delta_spec, delta_model, wave, open_count, change_lanes_csv (and,
|
|
37
|
+
# via cr-setup, an OPEN change). The change's LANE PLANS are scaffolded by `plan`,
|
|
38
|
+
# per declared lane.
|
|
33
39
|
# cr_dir is what lets the caller's quality loop target THIS change
|
|
34
40
|
# (create-checklist --kind delta).
|
|
35
41
|
# =============================================================================
|
|
@@ -46,8 +52,38 @@ scripts:
|
|
|
46
52
|
sh: .appweaver/scripts/bash/aw-spec-actions.sh
|
|
47
53
|
ps1: .appweaver/scripts/powershell/aw-spec-actions.ps1
|
|
48
54
|
|
|
55
|
+
vars:
|
|
56
|
+
change_lane_options: []
|
|
57
|
+
change_lane_has: "false" # the declared stacks offer an answer (no lane declared ⇒ nothing to ask)
|
|
58
|
+
change_lanes: "" # the answer picked; empty ⇒ every declared lane is stamped
|
|
59
|
+
change_lanes_csv: ""
|
|
60
|
+
|
|
49
61
|
workflow:
|
|
50
62
|
|
|
63
|
+
# THE LANES THIS CHANGE TOUCHES, asked before the change is opened so that a cancelled
|
|
64
|
+
# answer leaves nothing behind. The options come from stacks.json: both — listed first,
|
|
65
|
+
# so it is the default — then each lane alone. One declared lane is the only answer and
|
|
66
|
+
# is taken without a question; with no lane declared there is nothing to ask. The answer
|
|
67
|
+
# is written onto the delta-spec's **Lanes** line once the change exists. The spec half
|
|
68
|
+
# below is authored whole whatever the answer: which lanes plan and build a change is a
|
|
69
|
+
# delivery question, not a requirements one.
|
|
70
|
+
- id: change_lane_options
|
|
71
|
+
action: execute_script
|
|
72
|
+
script: { ref: actions }
|
|
73
|
+
subcommand: cr-lanes
|
|
74
|
+
outputs:
|
|
75
|
+
- { name: change_lane_options, from: "$.select_options" }
|
|
76
|
+
- { name: change_lane_has, from: "$.has_options" }
|
|
77
|
+
|
|
78
|
+
- id: ask_change_lanes
|
|
79
|
+
condition: "{{change_lane_has}} == true"
|
|
80
|
+
action: user_select
|
|
81
|
+
prompt: "Which lanes does this change touch? The answer is recorded on the change's **Lanes** line as the lanes that plan and build it; the spec is written whole either way."
|
|
82
|
+
options_from_variable: change_lane_options
|
|
83
|
+
single_option_confirm: true
|
|
84
|
+
outputs:
|
|
85
|
+
- { name: change_lanes, from: selection }
|
|
86
|
+
|
|
51
87
|
# Open the change + scaffold its TWO documents: the delta-spec under changes/<cr-id>/,
|
|
52
88
|
# and the model delta BESIDE the context's master model. The delta PLANS are not
|
|
53
89
|
# scaffolded here — `plan` owns them and creates them with delta-plan-scaffold when it
|
|
@@ -67,6 +103,19 @@ workflow:
|
|
|
67
103
|
- { name: wave, from: "$.wave" }
|
|
68
104
|
- { name: open_count, from: "$.open_count" }
|
|
69
105
|
|
|
106
|
+
# The answer, onto the delta-spec's **Lanes** line — before the author fills the document
|
|
107
|
+
# around it. --set goes last: an empty answer is dropped by PowerShell 5.1, and the
|
|
108
|
+
# script then stamps every declared lane. A failure leaves the template placeholder,
|
|
109
|
+
# which reads as every declared lane, so it does not stop the change from being written.
|
|
110
|
+
- id: stamp_change_lanes
|
|
111
|
+
action: execute_script
|
|
112
|
+
on_error: continue
|
|
113
|
+
script: { ref: actions }
|
|
114
|
+
subcommand: cr-lanes
|
|
115
|
+
args: ["--cr-id", "{{cr_id}}", "--feature-dir", "{{feature_dir}}", "--stamp", "--set", "{{change_lanes}}"]
|
|
116
|
+
outputs:
|
|
117
|
+
- { name: change_lanes_csv, from: "$.lanes_csv" }
|
|
118
|
+
|
|
70
119
|
- id: ctx
|
|
71
120
|
action: build_context
|
|
72
121
|
context_from: pending_model_files # EVERY other open delta's model change, so this
|
|
@@ -142,7 +191,10 @@ workflow:
|
|
|
142
191
|
Wave rationale — that is a wave dependency, and the wave must then be RAISED above
|
|
143
192
|
that delta's — name it under `## Depends on` and the wave is raised from that. Do not silently assume their
|
|
144
193
|
changes: until merged they are proposals, not the master.
|
|
145
|
-
- Do NOT edit the Wave / Created / Base version headers — scripts stamp
|
|
194
|
+
- Do NOT edit the Wave / Lanes / Created / Base version headers — scripts stamp
|
|
195
|
+
those. Lanes ({{change_lanes_csv}}) says which lanes plan and build this change;
|
|
196
|
+
it does NOT narrow what you write here — the delta is specified whole, behaviour and
|
|
197
|
+
experience alike.
|
|
146
198
|
Change request: {{USER_INPUT}}
|
|
147
199
|
|
|
148
200
|
# The MODEL half of the same change, authored in the same run so the model can never
|
|
@@ -33,6 +33,16 @@
|
|
|
33
33
|
# caller reads none of.
|
|
34
34
|
# command — the phase being gated, quoted back in the failure message
|
|
35
35
|
#
|
|
36
|
+
# THE WORKING LANE. A declared lane that the developer on this machine does not work on
|
|
37
|
+
# (.appweaver/lane.json — select-stack writes the default, select-lane narrows it) is not
|
|
38
|
+
# required to be on disk here: a backend developer's build must not stop because the
|
|
39
|
+
# frontend lane, somebody else's, has not been scaffolded yet. `--working-only` narrows the
|
|
40
|
+
# on-disk check to the working lanes and the required kind; a lane with no root and two
|
|
41
|
+
# lanes overlapping are still checked for every lane. The working lane's fields come back
|
|
42
|
+
# too — `working_kind` is the ONE kind being worked, or empty when every declared lane is,
|
|
43
|
+
# which is what a caller passes as `--kind` so that both lanes behave as before — and
|
|
44
|
+
# `be_working` / `fe_working` say per kind whether it is declared and worked here.
|
|
45
|
+
#
|
|
36
46
|
# Produces, for the required kind: WHERE it lives (lane_root / lane_source_path),
|
|
37
47
|
# WHAT it is (lane_profile / lane_title / lane_language / lane_ecosystem) and HOW it
|
|
38
48
|
# is driven (lane_build / lane_test / lane_run), plus both kinds' flattened fields,
|
|
@@ -66,9 +76,15 @@ workflow:
|
|
|
66
76
|
action: execute_script
|
|
67
77
|
script: { ref: actions }
|
|
68
78
|
subcommand: lane-verify
|
|
69
|
-
args: ["--require", "{{require}}", "--command", "{{command}}"]
|
|
79
|
+
args: ["--require", "{{require}}", "--command", "{{command}}", "--working-only"]
|
|
70
80
|
outputs:
|
|
71
81
|
- { name: lane_ok, from: "$.ok" }
|
|
82
|
+
- { name: be_working, from: "$.backend_working" }
|
|
83
|
+
- { name: fe_working, from: "$.frontend_working" }
|
|
84
|
+
- { name: working_lane, from: "$.working_lane" }
|
|
85
|
+
- { name: working_kind, from: "$.working_kind" }
|
|
86
|
+
- { name: working_root, from: "$.working_root" }
|
|
87
|
+
- { name: working_test_path, from: "$.working_test_path" }
|
|
72
88
|
- { name: lane_issues, from: "$.message" }
|
|
73
89
|
- { name: be_lane_id, from: "$.backend_lane_id" }
|
|
74
90
|
- { name: be_source_path, from: "$.backend_source_path" }
|
|
@@ -230,9 +230,18 @@ does none.]
|
|
|
230
230
|
|---|---|---|---|---|---|---|
|
|
231
231
|
| `[Screen]` | `[OperationId]` | `[operation]` | [field: type, …] | [field: type, …] | [§4 state] | FR-00X · IC-00X |
|
|
232
232
|
|
|
233
|
-
**Contract deltas needed
|
|
234
|
-
|
|
235
|
-
|
|
233
|
+
**Contract deltas needed**
|
|
234
|
+
|
|
235
|
+
<!-- THE REQUEST LEDGER. One row per operation the experience needs that the
|
|
236
|
+
contract does not offer — raised back to the service lane, never worked
|
|
237
|
+
around in the client. Each request keeps its RQ-n for life. The backend plan
|
|
238
|
+
answers in its "Requests from the frontend lane" table, published under an
|
|
239
|
+
operation id or declined with the reason; an answered request is re-bound
|
|
240
|
+
above to that id. Write `None` instead of the table when there is none. -->
|
|
241
|
+
|
|
242
|
+
| Request | Operation id | Needed by | Sends (field shape) | Receives (field shape) | Serves |
|
|
243
|
+
|---|---|---|---|---|---|
|
|
244
|
+
| RQ-[n] | `[ProposedOperationId]` | `[Screen / component]` | [field: type, …] | [field: type, …] | FR-00X |
|
|
236
245
|
|
|
237
246
|
## 6. Cross-Cutting
|
|
238
247
|
|