aw-spec-cli 0.1.7 → 0.1.9
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 +200 -0
- package/assets/.appweaver/ORCH-DIALECT.md +156 -0
- package/assets/.appweaver/RULE-PARTITION.md +175 -0
- package/assets/.appweaver/STACK-PROFILES.md +461 -0
- package/assets/.appweaver/ai-rules.md +180 -0
- package/assets/.appweaver/domain.json +1 -0
- package/assets/.appweaver/extensions/.registry +19 -0
- package/assets/.appweaver/extensions/agent-context/README.md +57 -0
- package/assets/.appweaver/extensions/agent-context/agent-context-config.yml +4 -0
- package/assets/.appweaver/extensions/agent-context/commands/aw-spec.agent-context.update.md +26 -0
- package/assets/.appweaver/extensions/agent-context/extension.yml +37 -0
- package/assets/.appweaver/extensions/agent-context/scripts/bash/update-agent-context.sh +201 -0
- package/assets/.appweaver/extensions/agent-context/scripts/powershell/update-agent-context.ps1 +237 -0
- package/assets/.appweaver/extensions.yml +16 -0
- package/assets/.appweaver/feature.json +3 -0
- package/assets/.appweaver/init-options.json +9 -0
- package/assets/.appweaver/integration.json +15 -0
- package/assets/.appweaver/integrations/aw-spec.manifest.json +9 -0
- package/assets/.appweaver/interpreter/run-skill.py +1176 -0
- package/assets/.appweaver/memory/constitution.md +50 -0
- package/assets/.appweaver/orchestrator/.smoke-out/smoke.md +6 -0
- package/assets/.appweaver/orchestrator/AGENT-PROFILE.md +94 -0
- package/assets/.appweaver/orchestrator/README.md +300 -0
- package/assets/.appweaver/orchestrator/adapters/claude_agent_sdk.py +74 -0
- package/assets/.appweaver/orchestrator/adapters/google_antigravity.py +74 -0
- package/assets/.appweaver/orchestrator/modules/delta-design.orch.yaml +105 -0
- package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +101 -0
- package/assets/.appweaver/orchestrator/modules/domain-select.orch.yaml +90 -0
- package/assets/.appweaver/orchestrator/modules/lane-gate.orch.yaml +126 -0
- package/assets/.appweaver/orchestrator/modules/tech-select.orch.yaml +123 -0
- package/assets/.appweaver/orchestrator/orchestrator.py +1721 -0
- package/assets/.appweaver/orchestrator/rev-templates/ai-rules.reference.md +40 -0
- package/assets/.appweaver/orchestrator/rev-templates/delta-design-template.skeleton.md +101 -0
- package/assets/.appweaver/orchestrator/rev-templates/design-template.skeleton.md +245 -0
- package/assets/.appweaver/orchestrator/rev-templates/domain-constitution.skeleton.md +63 -0
- package/assets/.appweaver/orchestrator/rev-templates/domain-requirements.skeleton.md +48 -0
- package/assets/.appweaver/orchestrator/rev-templates/domain-rule-bindings.skeleton.md +59 -0
- package/assets/.appweaver/orchestrator/rev-templates/domain-rule-file.skeleton.md +39 -0
- package/assets/.appweaver/orchestrator/rev-templates/frontend-rule-file.skeleton.md +63 -0
- package/assets/.appweaver/orchestrator/rev-templates/tech-rule-bindings.skeleton.md +116 -0
- package/assets/.appweaver/orchestrator/rev-templates/technical-constitution.skeleton.md +106 -0
- package/assets/.appweaver/orchestrator/rev-templates/technical-rule-file.skeleton.md +54 -0
- package/assets/.appweaver/orchestrator/rev-templates/ui-constitution.skeleton.md +125 -0
- package/assets/.appweaver/orchestrator/rev-templates/ui-delta-design-template.skeleton.md +123 -0
- package/assets/.appweaver/orchestrator/rev-templates/ui-design-template.skeleton.md +294 -0
- package/assets/.appweaver/orchestrator/workflows/_smoke.orch.yaml +160 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-add-component.orch.yaml +270 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-adopt.orch.yaml +934 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-delta-design.orch.yaml +251 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-design.orch.yaml +265 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +437 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-build.orch.yaml +197 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-characterize.orch.yaml +475 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-close-delta.orch.yaml +181 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +727 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-demo.orch.yaml +100 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-dependency-tree.orch.yaml +69 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-deploy.orch.yaml +85 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-design-ui.orch.yaml +386 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-design.orch.yaml +382 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +462 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +265 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-delta.orch.yaml +253 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement-ui.orch.yaml +267 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +287 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-inventory.orch.yaml +238 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +1822 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-parity.orch.yaml +293 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-run.orch.yaml +194 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-domain.orch.yaml +83 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-feature.orch.yaml +128 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +296 -0
- package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +439 -0
- package/assets/.appweaver/scripts/bash/aw-inventory.sh +17 -0
- package/assets/.appweaver/scripts/bash/aw-parity.sh +13 -0
- package/assets/.appweaver/scripts/bash/aw-rev-constitution.sh +13 -0
- package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +2626 -0
- package/assets/.appweaver/scripts/bash/aw-xref.sh +15 -0
- package/assets/.appweaver/scripts/bash/common.sh +533 -0
- package/assets/.appweaver/scripts/powershell/aw-inventory.ps1 +17 -0
- package/assets/.appweaver/scripts/powershell/aw-parity.ps1 +13 -0
- package/assets/.appweaver/scripts/powershell/aw-rev-constitution.ps1 +13 -0
- package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +2232 -0
- package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +15 -0
- package/assets/.appweaver/scripts/python/aw-component-catalog.py +121 -0
- package/assets/.appweaver/scripts/python/aw-inventory.py +1180 -0
- package/assets/.appweaver/scripts/python/aw-parity.py +380 -0
- package/assets/.appweaver/scripts/python/aw-rev-constitution.py +329 -0
- package/assets/.appweaver/scripts/python/aw-stack.py +1251 -0
- package/assets/.appweaver/scripts/python/aw-xref.py +1330 -0
- package/assets/.appweaver/scripts/python/validate_okf.py +352 -0
- package/assets/.appweaver/stack-profiles/angular.json +16 -0
- package/assets/.appweaver/stack-profiles/blazor-wasm.json +17 -0
- package/assets/.appweaver/stack-profiles/dotnet-webapi.json +15 -0
- package/assets/.appweaver/stack-profiles/go-chi.json +14 -0
- package/assets/.appweaver/stack-profiles/java-spring.json +16 -0
- package/assets/.appweaver/stack-profiles/nextjs.json +16 -0
- package/assets/.appweaver/stack-profiles/node-express.json +15 -0
- package/assets/.appweaver/stack-profiles/python-fastapi.json +16 -0
- package/assets/.appweaver/stack-profiles/react-vite.json +17 -0
- package/assets/.appweaver/stack-profiles/sveltekit.json +16 -0
- package/assets/.appweaver/stack-profiles/vue-vite.json +17 -0
- package/assets/.appweaver/stacks.json +3 -0
- package/assets/.appweaver/templates/constitution-domain-template.md +116 -0
- package/assets/.appweaver/templates/constitution-technical-template.md +108 -0
- package/assets/.appweaver/templates/constitution-ui-template.md +116 -0
- package/assets/.appweaver/templates/delta-design-template.md +69 -0
- package/assets/.appweaver/templates/delta-spec-template.md +63 -0
- package/assets/.appweaver/templates/design-template.md +383 -0
- package/assets/.appweaver/templates/okf-concept-template.md +114 -0
- package/assets/.appweaver/templates/parity-manifest-template.json +49 -0
- package/assets/.appweaver/templates/source-map-template.md +85 -0
- package/assets/.appweaver/templates/spec-template.md +309 -0
- package/assets/.appweaver/templates/ui-design-template.md +273 -0
- package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.Reference.pack.txt +25248 -0
- package/assets/foundations/dotnet/ModularMonolith/ModularMonolith.pack.txt +5726 -0
- package/assets/foundations/dotnet/ModularMonolith/pack-foundation.ps1 +145 -0
- package/assets/foundations/dotnet/ModularMonolith/pack-foundation.sh +196 -0
- package/assets/foundations/dotnet/ModularMonolith/pack-reference-foundation.ps1 +157 -0
- package/assets/foundations/dotnet/ModularMonolith/pack-reference-foundation.sh +209 -0
- package/assets/foundations/dotnet/ModularMonolith/unpack-foundation.ps1 +126 -0
- package/assets/foundations/dotnet/ModularMonolith/unpack-foundation.sh +217 -0
- package/assets/foundations/dotnet/ModularMonolith/unpack-reference-foundation.ps1 +129 -0
- package/assets/foundations/dotnet/ModularMonolith/unpack-reference-foundation.sh +218 -0
- package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.Reference.pack.txt +19318 -0
- package/assets/foundations/dotnet/VerticalSlice/VerticalSlice.pack.txt +2833 -0
- package/assets/foundations/dotnet/VerticalSlice/pack-foundation.ps1 +145 -0
- package/assets/foundations/dotnet/VerticalSlice/pack-foundation.sh +196 -0
- package/assets/foundations/dotnet/VerticalSlice/pack-reference-foundation.ps1 +157 -0
- package/assets/foundations/dotnet/VerticalSlice/pack-reference-foundation.sh +209 -0
- package/assets/foundations/dotnet/VerticalSlice/unpack-foundation.ps1 +126 -0
- package/assets/foundations/dotnet/VerticalSlice/unpack-foundation.sh +217 -0
- package/assets/foundations/dotnet/VerticalSlice/unpack-reference-foundation.ps1 +129 -0
- package/assets/foundations/dotnet/VerticalSlice/unpack-reference-foundation.sh +218 -0
- package/assets/foundations/dotnet/components/Email/README.md +119 -0
- package/assets/foundations/dotnet/components/Email/ReferenceEndpoints/SendEmailEndpoint.cs +84 -0
- package/assets/foundations/dotnet/components/Email/integration.md +300 -0
- package/assets/foundations/dotnet/components/Jobs/README.md +113 -0
- package/assets/foundations/dotnet/components/Jobs/integration.md +259 -0
- package/assets/foundations/dotnet/components/QrGenerator/README.md +85 -0
- package/assets/foundations/dotnet/components/QrGenerator/ReferenceEndpoints/GenerateQrEndpoint.cs +57 -0
- package/assets/foundations/dotnet/components/QrGenerator/integration.md +230 -0
- package/assets/foundations/dotnet/components/README.md +74 -0
- package/assets/guardrails/README.md +222 -0
- package/assets/guardrails/domain/healthcare/ai-rules.domain.md +34 -0
- package/assets/guardrails/domain/healthcare/api-versioning.domain.md +17 -0
- package/assets/guardrails/domain/healthcare/auditing.domain.md +97 -0
- package/assets/guardrails/domain/healthcare/authorization.domain.md +26 -0
- package/assets/guardrails/domain/healthcare/clinical-terms.md +20 -0
- package/assets/guardrails/domain/healthcare/coding-standards.domain.md +26 -0
- package/assets/guardrails/domain/healthcare/consent.md +19 -0
- package/assets/guardrails/domain/healthcare/cqrs.domain.md +12 -0
- package/assets/guardrails/domain/healthcare/data-classification.domain.md +28 -0
- package/assets/guardrails/domain/healthcare/dependency-policy.domain.md +11 -0
- package/assets/guardrails/domain/healthcare/dicom.md +15 -0
- package/assets/guardrails/domain/healthcare/domain-constitution.md +119 -0
- package/assets/guardrails/domain/healthcare/domain-driven-design.domain.md +28 -0
- package/assets/guardrails/domain/healthcare/eventing.domain.md +18 -0
- package/assets/guardrails/domain/healthcare/fhir.md +36 -0
- package/assets/guardrails/domain/healthcare/folder-structure.domain.md +25 -0
- package/assets/guardrails/domain/healthcare/hipaa.md +34 -0
- package/assets/guardrails/domain/healthcare/hl7.md +15 -0
- package/assets/guardrails/domain/healthcare/ihe-conformance.md +31 -0
- package/assets/guardrails/domain/healthcare/integration-terms.md +21 -0
- package/assets/guardrails/domain/healthcare/persistence.domain.md +20 -0
- package/assets/guardrails/domain/healthcare/terminology.md +30 -0
- package/assets/guardrails/domain/healthcare/testing.domain.md +15 -0
- package/assets/guardrails/domain/healthcare/ux/accessibility-standards.md +36 -0
- package/assets/guardrails/domain/healthcare/ux/content-design.md +32 -0
- package/assets/guardrails/domain/healthcare/ux/interaction-states.md +44 -0
- package/assets/guardrails/domain/healthcare/ux/journey-mapping.md +40 -0
- package/assets/guardrails/domain/healthcare/vertical-slices.domain.md +18 -0
- package/assets/guardrails/domain/healthcare/zero-trust.domain.md +12 -0
- package/assets/guardrails/domain/pharma/ai-rules.domain.md +32 -0
- package/assets/guardrails/domain/pharma/api-versioning.domain.md +20 -0
- package/assets/guardrails/domain/pharma/atc.md +22 -0
- package/assets/guardrails/domain/pharma/auditing.domain.md +90 -0
- package/assets/guardrails/domain/pharma/authorization.domain.md +25 -0
- package/assets/guardrails/domain/pharma/coding-standards.domain.md +28 -0
- package/assets/guardrails/domain/pharma/cqrs.domain.md +16 -0
- package/assets/guardrails/domain/pharma/data-classification.domain.md +24 -0
- package/assets/guardrails/domain/pharma/data-provenance.md +21 -0
- package/assets/guardrails/domain/pharma/dependency-policy.domain.md +11 -0
- package/assets/guardrails/domain/pharma/domain-constitution.md +113 -0
- package/assets/guardrails/domain/pharma/domain-driven-design.domain.md +36 -0
- package/assets/guardrails/domain/pharma/domain-requirements.sample.md +103 -0
- package/assets/guardrails/domain/pharma/eventing.domain.md +18 -0
- package/assets/guardrails/domain/pharma/fhir.md +31 -0
- package/assets/guardrails/domain/pharma/folder-structure.domain.md +26 -0
- package/assets/guardrails/domain/pharma/hl7.md +17 -0
- package/assets/guardrails/domain/pharma/idmp.md +26 -0
- package/assets/guardrails/domain/pharma/integration-terms.md +21 -0
- package/assets/guardrails/domain/pharma/ndc.md +28 -0
- package/assets/guardrails/domain/pharma/persistence.domain.md +23 -0
- package/assets/guardrails/domain/pharma/pharma-terms.md +27 -0
- package/assets/guardrails/domain/pharma/product-lifecycle.domain.md +30 -0
- package/assets/guardrails/domain/pharma/regulatory-compliance.md +19 -0
- package/assets/guardrails/domain/pharma/terminology.md +32 -0
- package/assets/guardrails/domain/pharma/testing.domain.md +19 -0
- package/assets/guardrails/domain/pharma/vertical-slices.domain.md +17 -0
- package/assets/guardrails/domain/pharma/zero-trust.domain.md +12 -0
- package/assets/guardrails/projects/dotnet-default-project/domain/domain-requirements.md +58 -0
- package/assets/guardrails/projects/dotnet-default-project/domain-rule-bindings.md +113 -0
- package/assets/guardrails/projects/dotnet-default-project/frontend/ui-requirements.md +43 -0
- package/assets/guardrails/projects/dotnet-default-project/service/technical-requirements.md +40 -0
- package/assets/guardrails/projects/dotnet-default-project/tech-rule-bindings.md +263 -0
- package/assets/guardrails/requirement-spec.txt +27 -0
- package/assets/guardrails/technology/dotnet-webapi/PACKAGING.md +184 -0
- package/assets/guardrails/technology/dotnet-webapi/api-versioning.md +44 -0
- package/assets/guardrails/technology/dotnet-webapi/auditing.md +96 -0
- package/assets/guardrails/technology/dotnet-webapi/authorization-matrix.md +14 -0
- package/assets/guardrails/technology/dotnet-webapi/authorization.md +39 -0
- package/assets/guardrails/technology/dotnet-webapi/clean-architecture.md +54 -0
- package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +87 -0
- package/assets/guardrails/technology/dotnet-webapi/cqrs.md +63 -0
- package/assets/guardrails/technology/dotnet-webapi/data-classification.md +38 -0
- package/assets/guardrails/technology/dotnet-webapi/dependency-policy.md +40 -0
- package/assets/guardrails/technology/dotnet-webapi/domain-driven-design.md +91 -0
- package/assets/guardrails/technology/dotnet-webapi/eventing.md +57 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/api-versioning.md +75 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/auditing.md +84 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/authorization.md +68 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/clean-architecture.md +37 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/cqrs.md +97 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/domain-driven-design.md +141 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/eventing.md +46 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/persistence.md +207 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/vertical-slices.md +151 -0
- package/assets/guardrails/technology/dotnet-webapi/examples/zero-trust.md +48 -0
- package/assets/guardrails/technology/dotnet-webapi/folder-structure.md +61 -0
- package/assets/guardrails/technology/dotnet-webapi/modular-monolith.md +47 -0
- package/assets/guardrails/technology/dotnet-webapi/persistence.md +82 -0
- package/assets/guardrails/technology/dotnet-webapi/technology-constitution.md +162 -0
- package/assets/guardrails/technology/dotnet-webapi/testing.md +55 -0
- package/assets/guardrails/technology/dotnet-webapi/vertical-slices.md +70 -0
- package/assets/guardrails/technology/dotnet-webapi/zero-trust.md +48 -0
- package/assets/guardrails/technology/java-spring/README.md +62 -0
- package/assets/guardrails/technology/nextjs/accessibility-implementation.md +56 -0
- package/assets/guardrails/technology/nextjs/api-client.md +56 -0
- package/assets/guardrails/technology/nextjs/api-integration.dotnet-webapi.md +174 -0
- package/assets/guardrails/technology/nextjs/api-integration.java-spring.md +203 -0
- package/assets/guardrails/technology/nextjs/auth-session.md +68 -0
- package/assets/guardrails/technology/nextjs/client-security.md +69 -0
- package/assets/guardrails/technology/nextjs/component-architecture.md +60 -0
- package/assets/guardrails/technology/nextjs/component-conventions.md +58 -0
- package/assets/guardrails/technology/nextjs/design-system.md +60 -0
- package/assets/guardrails/technology/nextjs/error-handling.md +72 -0
- package/assets/guardrails/technology/nextjs/forms-and-validation.md +75 -0
- package/assets/guardrails/technology/nextjs/frontend-testing.md +94 -0
- package/assets/guardrails/technology/nextjs/i18n.md +57 -0
- package/assets/guardrails/technology/nextjs/observability.md +67 -0
- package/assets/guardrails/technology/nextjs/performance-budgets.md +66 -0
- package/assets/guardrails/technology/nextjs/routing-navigation.md +52 -0
- package/assets/guardrails/technology/nextjs/state-management.md +70 -0
- package/assets/guardrails/technology/nextjs/ui-constitution.md +166 -0
- package/dist/commands/init.js +2 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/utils/copy-assets.js +8 -8
- package/dist/utils/copy-assets.js.map +1 -1
- package/package.json +1 -1
- package/assets/docs/pharma-constitution.my-ref.md +0 -86
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
# Stack profiles and the lane model
|
|
2
|
+
|
|
3
|
+
Authoritative on two files: `.appweaver/stacks.json` (the lane declaration a project
|
|
4
|
+
makes) and `.appweaver/stack-profiles/*.json` (the candidates it chooses from).
|
|
5
|
+
|
|
6
|
+
`DESIGN-FORMAT.md` is to `design.md` what this document is to `stacks.json`.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 1. What a lane is
|
|
11
|
+
|
|
12
|
+
A **lane** is a technology target that owns disjoint source paths, compiles and tests
|
|
13
|
+
independently, and carries its own technical rules and constitution half — while
|
|
14
|
+
*sharing* the feature, the spec, the domain, the version, and the knowledge bundle with
|
|
15
|
+
every other lane.
|
|
16
|
+
|
|
17
|
+
> One spec, one prototype, two designs, two implements, one build, one version.
|
|
18
|
+
|
|
19
|
+
A lane is not a project, not a module, and not a layer. Two lanes exist when two
|
|
20
|
+
toolchains do, which is why `kind` has exactly two values today (`backend`, `frontend`)
|
|
21
|
+
and why nothing in the format assumes there are only two lanes.
|
|
22
|
+
|
|
23
|
+
**Lanes get command names, never a `--lane` flag.** Rule maps are keyed on
|
|
24
|
+
`## /aw-spec-<command>`, so a lane's phases are reached as `ui-implement`, `ui-foundation`
|
|
25
|
+
and so on. A flag would have no heading to key on.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 2. `.appweaver/stacks.json`
|
|
30
|
+
|
|
31
|
+
```jsonc
|
|
32
|
+
{
|
|
33
|
+
"lanes": [
|
|
34
|
+
{ "id": "service", "kind": "backend", "profile": "dotnet-webapi", "root": "src/",
|
|
35
|
+
"build": "dotnet build", "test": "dotnet test", "run": "dotnet run --project src/" },
|
|
36
|
+
{ "id": "web", "kind": "frontend", "profile": "react-vite", "root": "web/",
|
|
37
|
+
"run_from": "root",
|
|
38
|
+
"build": "npm run build", "test": "npm test", "run": "npm run dev" }
|
|
39
|
+
],
|
|
40
|
+
"prototype": { "root": "prototype/", "run": "npm run dev --prefix prototype" }
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
| Field | Meaning |
|
|
45
|
+
|---|---|
|
|
46
|
+
| `id` | the lane's **role** in the project (`service`, `web`). Paths, rules and the constitution half hang off it. Defaults: `service` for backend, `web` for frontend |
|
|
47
|
+
| `kind` | `backend` or `frontend` — selects which phases and which rule headings apply |
|
|
48
|
+
| `profile` | the stack profile the lane was declared from. Records the technology, so re-stacking a lane never renames the lane. `detected` where the kit ships no profile for what the code is |
|
|
49
|
+
| `stack` | *(optional)* what the code was found to be, when `profile` is `detected` — e.g. `asp.net-webforms`. The honest record for a legacy lane |
|
|
50
|
+
| `origin` | *(optional)* `reverse-engineered` on a lane `onboard` derived from an existing codebase. Absent means a person declared it, which is the greenfield shape and the historical one |
|
|
51
|
+
| `root` | the lane's **source path** — the subtree it owns (see §3). `--source-path` and `--root` are two spellings of this one field |
|
|
52
|
+
| `run_from` | *(optional)* **where the commands run**: `repo` (the default, and the shape of every lane written before this key existed) at the repository root, or `root` inside the lane's own source path. See §3.1 |
|
|
53
|
+
| `build` / `test` / `run` | project-supplied command strings the engine shells out to. These are the matched **profile's** defaults and may not fit a legacy layout — reviewing them is what `select-stack` is for. `{{root}}` in a command resolves to this lane's `root` (§4.2) |
|
|
54
|
+
| `migrate` | *(optional)* the lane's schema-migration command, recorded only when the profile declares one. Absent, `run-migrate` falls back to `dotnet ef` and otherwise reports that nothing ran (§4.2) |
|
|
55
|
+
|
|
56
|
+
### Three properties matter more than the schema
|
|
57
|
+
|
|
58
|
+
1. **`root` is ownership, and it is the source path.** `implement` writes only under a
|
|
59
|
+
backend lane's root, `ui-implement` only under a frontend lane's, `build`/`test`/`run`
|
|
60
|
+
act on it, and `onboard` reverse-engineers out of it.
|
|
61
|
+
2. **The commands are project-supplied strings.** The engine stays stdlib-only and
|
|
62
|
+
stack-ignorant. This is how `build` already avoids knowing what a compiler is, and it
|
|
63
|
+
is the only thing that makes "any frontend stack" tractable.
|
|
64
|
+
3. **`prototype` is not a lane.** It has a root and a run command so an operator can look
|
|
65
|
+
at it, and nothing else. It is never built by `build`, never tested by `analyze-slice`,
|
|
66
|
+
never deployed, and never gated.
|
|
67
|
+
|
|
68
|
+
### 3.1 `root` is where the code is; `run_from` is where the commands run
|
|
69
|
+
|
|
70
|
+
These are two questions and for most stacks they have two answers. `dotnet build` needs the
|
|
71
|
+
solution file at the top while the lane owns `src/`; `go build ./...` needs the go.mod there
|
|
72
|
+
while the lane owns `internal/`. Those profiles leave `run_from` at its default and run at
|
|
73
|
+
the repository root.
|
|
74
|
+
|
|
75
|
+
A stack whose **manifest lives inside the subtree** needs the other answer, and cannot work
|
|
76
|
+
without it: a Maven wrapper at `backend/orderservice/mvnw` is unreachable from the repository
|
|
77
|
+
root, so `java-spring` declares `run_from: "root"`. The five npm frontends and `blazor-wasm`
|
|
78
|
+
declare it too, which is what let their commands stop hardcoding `--prefix web` — the lane
|
|
79
|
+
already declares that directory, and a lane rooted at `client/` was previously building `web/`
|
|
80
|
+
regardless.
|
|
81
|
+
|
|
82
|
+
Two consequences worth knowing:
|
|
83
|
+
|
|
84
|
+
- **Declare a `run_from: "root"` lane at the directory holding its manifest**, not at its
|
|
85
|
+
source directory. `java-spring`'s profile default root is `src/main/java/`, which is where
|
|
86
|
+
the *code* goes; detection proposes the directory `pom.xml` actually sits in, which is the
|
|
87
|
+
one to accept. A lane rooted at `src/main/java/` will fail loudly with `./mvnw: not found`
|
|
88
|
+
rather than silently.
|
|
89
|
+
- **A single-module project declares `.`** — stored as `./`, the repository root. It owns
|
|
90
|
+
everything, so it overlaps every other lane by definition and cannot be combined with one.
|
|
91
|
+
|
|
92
|
+
### Where the source path is checked against the disk
|
|
93
|
+
|
|
94
|
+
`lane-declare` records a path; it does **not** require the path to exist. In a greenfield
|
|
95
|
+
project it does not exist yet — the whole point of declaring `src/` on day one is that
|
|
96
|
+
`implement` will create it.
|
|
97
|
+
|
|
98
|
+
`lane-verify` is the check, and it runs where the path has to be real: before `implement`,
|
|
99
|
+
`implement-delta`, `build`, `run`, and before `onboard` reverse-engineers a codebase out of
|
|
100
|
+
it. That split is what lets one file serve a project with no code yet and a project that is
|
|
101
|
+
nothing but code.
|
|
102
|
+
|
|
103
|
+
Two failure classes, deliberately distinguished:
|
|
104
|
+
|
|
105
|
+
- **MISSING** — the phase needs a lane of this kind and none is declared. Reported only for
|
|
106
|
+
the kinds a caller names with `--require`, because "no frontend lane" is a correct and
|
|
107
|
+
common state that must never fail a backend build.
|
|
108
|
+
- **BROKEN** — a lane *is* declared and its source path is empty, is not a directory, or
|
|
109
|
+
overlaps another lane's. Checked for **every** declared lane whether or not the caller
|
|
110
|
+
asked about it. A stack named against a path that is not there is a mistake in every
|
|
111
|
+
phase, and letting it through means discovering it as an empty build or a generator
|
|
112
|
+
writing into a directory it created by accident. The overlap check is a second reading of
|
|
113
|
+
a rule `lane-declare` already enforces, and it earns its place because a hand-edited file
|
|
114
|
+
never passes `lane-declare`.
|
|
115
|
+
|
|
116
|
+
### The file ships empty, and may be filled in by hand
|
|
117
|
+
|
|
118
|
+
The kit installs `.appweaver/stacks.json` holding `{"lanes": []}`, alongside `domain.json` and
|
|
119
|
+
`feature.json`. It is there so a project can open it and fill it in directly — the block at
|
|
120
|
+
the top of this section is the whole schema, and `select-stack` writes nothing a person
|
|
121
|
+
could not have typed.
|
|
122
|
+
|
|
123
|
+
**An empty file and an absent one are the same state.** Shipping the file means its presence
|
|
124
|
+
no longer says anything about whether a lane was declared, so `declared` reports on the
|
|
125
|
+
`lanes` array and never on the file: `resolve` reports `exists: true, declared: false` for
|
|
126
|
+
the untouched seed, and `verify` raises the same "no lane is declared" issue it raises when
|
|
127
|
+
the file is missing, naming which of the two it found.
|
|
128
|
+
|
|
129
|
+
Hand-editing and `select-stack` are the same file and the same schema, so they interleave
|
|
130
|
+
freely: fill in the service lane by hand and run `select-stack` later to add the UI one, or
|
|
131
|
+
run it first and correct a source path in the editor. What hand-editing gives up is the
|
|
132
|
+
checking `select-stack` does on the way in — an unknown `profile`, a missing `root`, and two
|
|
133
|
+
lanes whose roots overlap are all refused there and merely written here. `lane-verify` still
|
|
134
|
+
catches the last two before any phase acts on them; a profile id that matches nothing
|
|
135
|
+
surfaces as a wrong or empty stack later. Running `select-stack` once over a hand-written
|
|
136
|
+
file re-checks all three.
|
|
137
|
+
|
|
138
|
+
### Absence is not a valid state for a governed project
|
|
139
|
+
|
|
140
|
+
`lane-resolve` still reports `declared: false` and exits 0 when the file is missing — reading
|
|
141
|
+
is never fatal. What changed is that the phases which *act* on a lane no longer proceed
|
|
142
|
+
without one. `constitution`, `onboard`, `implement`, `implement-delta`, `build` and `run` all
|
|
143
|
+
call `lane-verify` and stop with the fix named, because each of them needs an answer this
|
|
144
|
+
file is the only place to get: which lanes to govern, which subtree to scan, where to write.
|
|
145
|
+
|
|
146
|
+
Declaring **`(none)`** for a lane is a real answer and the way a project says it has none.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 3. The ownership rule
|
|
151
|
+
|
|
152
|
+
**Lane roots own their subtree and must be disjoint.** Two generators must never be able
|
|
153
|
+
to write the same file.
|
|
154
|
+
|
|
155
|
+
`lane-declare` refuses a declaration whose root contains, or is contained by, another
|
|
156
|
+
lane's — compared as `/`-terminated paths, so `src/` is clear of `src-gen/` but collides
|
|
157
|
+
with `src/api/`. The refusal is a non-zero exit and **`stacks.json` is left untouched**.
|
|
158
|
+
|
|
159
|
+
This is checked at declaration time on purpose. The alternative — discovering it when two
|
|
160
|
+
implement phases fight over a file — is a much worse place to find out.
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## 4. Stack profiles — `.appweaver/stack-profiles/*.json`
|
|
165
|
+
|
|
166
|
+
One JSON file per selectable stack. `stack-list` enumerates them; this is the extension
|
|
167
|
+
point, so **a project adds its own stack by dropping a file in here, never by editing a
|
|
168
|
+
workflow.**
|
|
169
|
+
|
|
170
|
+
```jsonc
|
|
171
|
+
{
|
|
172
|
+
"id": "react-vite", // required — unique, and unique ACROSS kinds
|
|
173
|
+
"kind": "frontend", // required — backend | frontend
|
|
174
|
+
"title": "React + Vite", // shown in the menu
|
|
175
|
+
"language": "TypeScript", // shown in the menu, parenthesised
|
|
176
|
+
"ecosystem": "node", // which stack-partitioned corpus this stack draws from
|
|
177
|
+
"root": "web/", // the lane root this profile defaults to
|
|
178
|
+
"run_from": "root", // where the commands run — see §3.1
|
|
179
|
+
"build": "npm run build",
|
|
180
|
+
"test": "npm test",
|
|
181
|
+
"run": "npm run dev",
|
|
182
|
+
"migrate": "", // optional — schema migration, if the stack has one
|
|
183
|
+
"prototype_run": "npm run dev --prefix prototype", // frontend only — fills the prototype block
|
|
184
|
+
"detect": ["web/package.json", "web/vite.config.*"] // ANY-of markers — how stack-detect recognises this stack
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
`id` and `kind` are required; a file missing either, or containing invalid JSON, is
|
|
189
|
+
**skipped rather than fatal** — one bad profile must not make the menu unopenable.
|
|
190
|
+
|
|
191
|
+
### 4.1 `ecosystem` — which stack-partitioned corpus this stack draws from
|
|
192
|
+
|
|
193
|
+
`language` names what a person writes; `ecosystem` names the **toolchain family the kit
|
|
194
|
+
partitions its corpora by**, and the two are not the same question. `dotnet-webapi` and
|
|
195
|
+
`blazor-wasm` are C# and F#-adjacent respectively but share one ecosystem, `dotnet`; the five
|
|
196
|
+
JavaScript frontends and `node-express` share `node`. It is the directory key for the two
|
|
197
|
+
trees that are physically per-ecosystem:
|
|
198
|
+
|
|
199
|
+
| Tree | Keyed by | Read through |
|
|
200
|
+
|---|---|---|
|
|
201
|
+
| `foundations/<ecosystem>/<Name>/` | `ecosystem` | `foundation-list`, `foundation-locate` |
|
|
202
|
+
| `foundations/<ecosystem>/components/<C>/` | `ecosystem` | `list-components`, `add-component` |
|
|
203
|
+
|
|
204
|
+
**Why those two are filtered and the rule corpora are not.** A foundation bundle is a whole
|
|
205
|
+
compiling project and a component runbook edits a host project's build files — both are
|
|
206
|
+
executable artifacts in one toolchain, so offering a `dotnet` bundle to a Spring repo does not
|
|
207
|
+
produce a scaffold, it produces a second foreign project beside the real one. `foundation-list`
|
|
208
|
+
therefore narrows to the declared lanes' ecosystems, and reports `all_foundations` alongside so
|
|
209
|
+
the gate can say *what exists and why none of it applies*. A repo that has declared nothing yet
|
|
210
|
+
is not filtered — there is no answer to filter on.
|
|
211
|
+
|
|
212
|
+
The technical RULE corpora at `guardrails/technology/<stack>/` are keyed by **profile id**, not
|
|
213
|
+
ecosystem, because Spring and Quarkus are both `java` and do not share a persistence rule. They
|
|
214
|
+
are selected through the project's `tech-rule-bindings.md` rather than filtered here — see §7.
|
|
215
|
+
|
|
216
|
+
### 4.2 `run_from`, `{{root}}` and `migrate`
|
|
217
|
+
|
|
218
|
+
A profile command sometimes has to name the source path — `dotnet run --project src/`. Written
|
|
219
|
+
literally that is the profile's *default* root frozen into the command, and it stays frozen when
|
|
220
|
+
a lane declares a different one. Write **`{{root}}`** instead and it resolves to the lane's own
|
|
221
|
+
root, expanded at run time so a hand-edited `root` in `stacks.json` stays consistent with it:
|
|
222
|
+
|
|
223
|
+
```jsonc
|
|
224
|
+
"run": "dotnet run --project {{root}}", // Services/Api/ ⇒ dotnet run --project Services/Api
|
|
225
|
+
"build": "python -m compileall {{root}}" // repo-root lane ⇒ python -m compileall .
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
A command with no placeholder is used verbatim, so every literal command already on disk is
|
|
229
|
+
unaffected. `{{root}}` is the answer when the command needs the *path*; `run_from: "root"` (§3.1)
|
|
230
|
+
is the answer when it needs the *working directory*.
|
|
231
|
+
|
|
232
|
+
`migrate` is an optional fourth phase command, alongside `build`/`test`/`run`. **No shipped
|
|
233
|
+
profile declares one**, deliberately: Flyway, Liquibase, Alembic, Prisma and golang-migrate all
|
|
234
|
+
coexist and no sniffer can pick between them, so a default here would be a guess dressed up as
|
|
235
|
+
configuration. Declare it and `run-migrate` runs it in the lane's working directory like any
|
|
236
|
+
other phase; leave it and `run-migrate` keeps its .NET `dotnet ef` path, reporting `ran:false`
|
|
237
|
+
elsewhere rather than implying a migration succeeded.
|
|
238
|
+
|
|
239
|
+
`detect` is an **ANY-of** list, not an all-of: `java-spring` names both `pom.xml` and
|
|
240
|
+
`build.gradle` because a project has one or the other, and requiring both would make it
|
|
241
|
+
undetectable. `stack-detect` scores a profile by how many of its patterns hit. Patterns are
|
|
242
|
+
matched first as written (repo-root-relative, with `**` spanning separators), then relocated
|
|
243
|
+
under any directory prefix — so a profile shipping `web/package.json` still recognises the
|
|
244
|
+
same stack in `client/` or `apps/portal/`, which a brownfield repo that never saw our
|
|
245
|
+
profiles will need. An anchored hit outranks a relocated one.
|
|
246
|
+
|
|
247
|
+
`detect` and `root` are independent, and deliberately so: `go-chi` detects on `go.mod` at the
|
|
248
|
+
repo root and declares a root of `internal/`. Detection reports the shallowest directory its
|
|
249
|
+
evidence actually sits in, and that directory is what `select-stack` offers first when it asks
|
|
250
|
+
for the lane's source path — ahead of the profile's own default, because a repo that already
|
|
251
|
+
exists did not choose its layout from our profiles. The operator picks from the list or types
|
|
252
|
+
a path the kit has never seen.
|
|
253
|
+
|
|
254
|
+
**Detection leads the menu; it never fills `preselect`.** The engine treats `preselect_from`
|
|
255
|
+
as the answer, ahead of a headless `--select`, so filling it from a scan would let a repo's
|
|
256
|
+
files silently overrule an operator who named a stack on the command line. Leading the option
|
|
257
|
+
list is the right strength for a proposal — it is what an interactive menu opens on and what
|
|
258
|
+
`--non-interactive` takes, and both remain choices anyone can override.
|
|
259
|
+
|
|
260
|
+
**Profile ids must be unique across kinds, not just within one.** The direct-argument fast
|
|
261
|
+
path (`select-stack dotnet-webapi react-vite`) matches each id against its own kind's list,
|
|
262
|
+
and that is what lets a single argument answer both selections unambiguously. An id
|
|
263
|
+
appearing under two kinds breaks it.
|
|
264
|
+
|
|
265
|
+
The menu label is `<id> — <title> (<language>)`, and the id is its leading token. That is
|
|
266
|
+
the contract between `stack-list` and `lane-declare`: `--profile` accepts either a bare id
|
|
267
|
+
or a full menu label.
|
|
268
|
+
|
|
269
|
+
**The id is also what `lane-probe` looks for in free prose** — the whole id and its `-`/`_`
|
|
270
|
+
parts of three characters or more, so `react-vite` is found by "react". `title` and `language`
|
|
271
|
+
are deliberately *not* searched: "TypeScript", "Next" and "Web" all appear in ordinary prose
|
|
272
|
+
about a backend, and the two errors are not symmetric. A false positive authors a governed file
|
|
273
|
+
the project never asked for; a false negative only produces a warning that names the fix. Pick
|
|
274
|
+
ids accordingly — a profile whose id is a common English word will be matched too eagerly.
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## 5. Who may write this file
|
|
279
|
+
|
|
280
|
+
**`lane-declare` writes it. Nothing else does, and it has exactly ONE caller** — so the
|
|
281
|
+
rule is a grep, not a convention:
|
|
282
|
+
|
|
283
|
+
```sh
|
|
284
|
+
grep -rl "lane-declare" .appweaver/orchestrator/workflows/ # must print exactly one file
|
|
285
|
+
# aw-spec-select-stack.orch.yaml — a person picks
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
`onboard` used to be a second caller. Before `select-stack` was the first command of the
|
|
289
|
+
brownfield sequence a repo could reach `onboard` undeclared, so `onboard` ran its own
|
|
290
|
+
detection pass, recorded what it found marked `origin: reverse-engineered`, and was gated
|
|
291
|
+
never to overwrite a lane a person had confirmed. With the declaration now **required** at
|
|
292
|
+
the top of `onboard` — it is what tells the scan which subtrees to read — that gate can
|
|
293
|
+
never open, and the pass was re-deriving an answer the run already had. The detection moved
|
|
294
|
+
to where a person can see it: `stack-list --suggest`, inside `select-stack`.
|
|
295
|
+
|
|
296
|
+
The `origin` key stays in the schema and stays optional. Nothing writes
|
|
297
|
+
`reverse-engineered` today; a future caller that proposes a lane without a person in the
|
|
298
|
+
loop would, and readers that branch on it keep working.
|
|
299
|
+
|
|
300
|
+
`lane-resolve` reads and can never write, which is why these are separate subcommands
|
|
301
|
+
rather than one with a mode flag: a reader that could write, given the wrong argument,
|
|
302
|
+
gives up the property. `lane-verify` cannot write either, and always exits 0 — the calling
|
|
303
|
+
workflow's gate owns the stop, so the reason reaches it as text instead of as an exit code
|
|
304
|
+
nobody sees.
|
|
305
|
+
|
|
306
|
+
**A person with a text editor is not a violation of this** — it is the other supported way
|
|
307
|
+
to fill the file in, and the kit ships it empty for that. "One writer" is a rule about the
|
|
308
|
+
*kit*: no second workflow may reach in and set a lane behind the operator's back. What it
|
|
309
|
+
costs is that a hand-edited file skips the writer's checks, which is why `lane-verify`
|
|
310
|
+
re-runs the roots-disjoint one on every read (see §2).
|
|
311
|
+
|
|
312
|
+
Consequences worth stating, because they are the reason for the design:
|
|
313
|
+
|
|
314
|
+
- **`foundation` / `ui-foundation` scaffold *against* a declared lane** and verify what
|
|
315
|
+
they produced against it — stopping `STACK-MISMATCH:` rather than rewriting the
|
|
316
|
+
declaration to fit the scaffold. A wrong declaration surfaces at the scaffold instead of
|
|
317
|
+
being absorbed by it, and the lane a project *chose* stays the authority over the lane a
|
|
318
|
+
generator *happened to produce*.
|
|
319
|
+
- **`build` runs every declared lane's own build command**, in declaration order, and
|
|
320
|
+
fails if any lane fails. Without a declaration it falls back to the historic
|
|
321
|
+
first-match-wins sniffer, which is right for one lane and silently skips the second —
|
|
322
|
+
reporting green for a frontend it never compiled.
|
|
323
|
+
|
|
324
|
+
## 5a. What this file IS for
|
|
325
|
+
|
|
326
|
+
**It records which lanes a project has.** That is its first job, and everything else
|
|
327
|
+
follows from it:
|
|
328
|
+
|
|
329
|
+
| Question | Answered by |
|
|
330
|
+
|---|---|
|
|
331
|
+
| Which constitution halves does this project ratify? | a declared service lane ⇒ `constitution.technical.md`; a declared UI lane ⇒ `constitution.ui.md`. `(none)` ⇒ no half, and no file |
|
|
332
|
+
| Which rule sets does `onboard` generate? | the same, per lane — `service/` and `frontend/` under the project folder |
|
|
333
|
+
| Which subtree does `implement` write into? | that lane's `root` |
|
|
334
|
+
| What does `build` compile, and `run` migrate? | every declared lane's own command, against its own root |
|
|
335
|
+
| What does `onboard` scan? | the declared source paths — backend signals from outside the UI subtree, frontend signals from inside it |
|
|
336
|
+
|
|
337
|
+
This is a change of authority, and worth being explicit about. The question "does this
|
|
338
|
+
project have a UI lane" used to be answered by OR-ing three heuristics: a
|
|
339
|
+
`## /aw-spec-ui-constitution` heading in the technical rule map, a frontend lane in this
|
|
340
|
+
file, and a UI stack named in the request. A heuristic OR can only ever turn a lane **on**.
|
|
341
|
+
It had no way to express *this project has no UI*, so a stale heading or the word "react" in
|
|
342
|
+
a request authored a ratified governance file for a lane that does not exist.
|
|
343
|
+
|
|
344
|
+
The declaration answers in both directions, and it is the same file `build`, `implement` and
|
|
345
|
+
`onboard` are held to. So it decides — and the rule map goes back to doing the job it is
|
|
346
|
+
good at: **supplying the rules a lane's half ratifies**, not asserting that the lane exists.
|
|
347
|
+
A mapped `## /aw-spec-ui-constitution` with no declared lane is reported as an
|
|
348
|
+
inconsistency, naming both fixes (declare the lane, or drop the mapping if it was retired).
|
|
349
|
+
|
|
350
|
+
`stacks.json` also serves the steps a rule file cannot reach: `build`, `analyze-slice`, `run`
|
|
351
|
+
and `deploy` shell out from `execute_script` steps, and a bash script cannot read a markdown
|
|
352
|
+
rule. Supplying the commands here is what stops them guessing.
|
|
353
|
+
|
|
354
|
+
Choosing `(none)` for either lane routes through the same writer, which is what makes a
|
|
355
|
+
re-run correct: a lane declared in an earlier run is removed — along with the `prototype`
|
|
356
|
+
block for a retired frontend — rather than left stranded.
|
|
357
|
+
|
|
358
|
+
## 5b. The starting sequence
|
|
359
|
+
|
|
360
|
+
`select-stack` is the **first command of both sequences**, and the setup order now has one
|
|
361
|
+
constraint where it previously had none. That is a deliberate trade: what it buys is that
|
|
362
|
+
every later phase can ask this file a question and get an answer, instead of inferring one.
|
|
363
|
+
|
|
364
|
+
```
|
|
365
|
+
GREENFIELD select-stack → select-domain → constitution → select-feature → specify → …
|
|
366
|
+
BROWNFIELD select-stack → onboard → select-feature → adopt → …
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
`select-domain` is greenfield-only: `onboard` derives the project from the code and
|
|
370
|
+
activates it. On an existing codebase `select-stack` is mostly confirmation — it detects the
|
|
371
|
+
stack and the source path from the repo's own files and leads the menu with them — but it is
|
|
372
|
+
a person's confirmation, which is what detection on a legacy repo needs.
|
|
373
|
+
|
|
374
|
+
## 6. Subcommands
|
|
375
|
+
|
|
376
|
+
Deterministic work lives in `aw-spec-actions` — **a true bash + powershell pair.** Both
|
|
377
|
+
shells delegate to `.appweaver/scripts/python/aw-stack.py`, so the JSON contract has one
|
|
378
|
+
implementation and the twins cannot drift.
|
|
379
|
+
|
|
380
|
+
| Subcommand | Does |
|
|
381
|
+
|---|---|
|
|
382
|
+
| `stack-list [--kind k] [--preselect text] [--include-none] [--suggest]` | enumerate the installed profiles; returns `select_options[]`, and `preselect` when the text names one of *this kind's* ids. `--suggest` also runs detection, so the menu **leads with** the stack this repo's files point at and `root_options[]` leads with the directory the evidence sits in |
|
|
383
|
+
| `stack-detect [--kind k] [--exclude-root p]…` | match the repo's OWN files against the installed profiles — the brownfield candidate list, since an existing repo already answered the question. Writes nothing. `--exclude-root` keeps a service profile from relocating onto a subtree another lane owns |
|
|
384
|
+
| `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 lane — **the sole writer**. `detected` declares a stack the kit ships no profile for (needs `--stack` and a source path), which is how a legacy WebForms, JSP or ERB lane gets recorded at all |
|
|
385
|
+
| `lane-resolve [--kind k] [--id lane]` | 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 |
|
|
386
|
+
| `lane-verify [--require backend\|frontend]… [--allow-missing-root] [--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 |
|
|
387
|
+
| `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` |
|
|
388
|
+
|
|
389
|
+
Both `lane-declare` branches — declaring a lane and declaring `none` — emit the **same key
|
|
390
|
+
set**, so a caller binds outputs without knowing which branch ran.
|
|
391
|
+
|
|
392
|
+
### Which subcommands consume the lane model
|
|
393
|
+
|
|
394
|
+
| Subcommand | With a declaration | With none |
|
|
395
|
+
|---|---|---|
|
|
396
|
+
| `build-compile` | every declared lane's own `build`, via `run-phase` | the historic first-match-wins ladder |
|
|
397
|
+
| `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 |
|
|
398
|
+
| `run-migrate` | a lane's declared `migrate` (§4.2) when there is one; otherwise `dotnet ef` searched under the **service lane's root** rather than an assumed `src/` | `dotnet ef` under `src/` |
|
|
399
|
+
| `find-host-project` | searches the service lane's root, and reports the lane's `ecosystem` | searches `src/` |
|
|
400
|
+
| `foundation-list`, `list-components` | narrowed to the declared lanes' `ecosystem` (§4.1) | unfiltered / `dotnet` |
|
|
401
|
+
| `resolve-tech` | expands stack placeholders and flags a corpus mismatch (§7a) | no placeholders resolve; nothing is flagged |
|
|
402
|
+
|
|
403
|
+
**Why `--scope slice` is the one exception.** VSTest's `--filter FullyQualifiedName~` is the
|
|
404
|
+
only per-test selector any shipped profile has, and `analyze-slice`'s integrity fence depends
|
|
405
|
+
on it together with the zero-match vacuous-pass guard. On every other stack the lane's whole
|
|
406
|
+
declared suite runs and the result reports `scoped:false`, which over-includes — the safe
|
|
407
|
+
direction, and the direction that command already documents. What it no longer does is report
|
|
408
|
+
`fence_green:true` for a suite it never ran.
|
|
409
|
+
|
|
410
|
+
---
|
|
411
|
+
|
|
412
|
+
## 7. Adding a stack
|
|
413
|
+
|
|
414
|
+
1. Write `.appweaver/stack-profiles/<id>.json` per §4 — including `ecosystem`.
|
|
415
|
+
2. Re-run `/appweaver select-stack` — it appears in the menu.
|
|
416
|
+
|
|
417
|
+
No workflow or script changes. If adding a stack ever requires touching a workflow, the lane
|
|
418
|
+
model is wrong and that is the bug to fix.
|
|
419
|
+
|
|
420
|
+
That gives the new stack every phase that is driven by a **command** — build, test, run,
|
|
421
|
+
migrate — plus the correct source path everywhere, immediately. Two things are opt-in because
|
|
422
|
+
they are content the kit cannot invent:
|
|
423
|
+
|
|
424
|
+
- **Technical rules** — a corpus at `guardrails/technology/<id>/`, mapped from the project's
|
|
425
|
+
`tech-rule-bindings.md` (§7a). Until one exists the stack runs with the universal
|
|
426
|
+
`ai-rules.md` and the technical constitution, which is the greenfield-safe default, not an
|
|
427
|
+
error.
|
|
428
|
+
- **A foundation bundle** — `foundations/<ecosystem>/<Name>/`, only if you want `/appweaver
|
|
429
|
+
foundation` to scaffold this stack. Scaffolding with the stack's own tooling and then
|
|
430
|
+
declaring the result with `select-stack` is fully supported: `implement` generates INTO a
|
|
431
|
+
project tree and does not require that the kit created it.
|
|
432
|
+
|
|
433
|
+
## 7a. Mapping rules to a stack without pinning the map to one
|
|
434
|
+
|
|
435
|
+
`resolve-tech` reads the project's `tech-rule-bindings.md` and collects the `- ` bullets under
|
|
436
|
+
`## /<command>`. A bullet may name its stack with a **placeholder**, resolved from the lanes in
|
|
437
|
+
`stacks.json`:
|
|
438
|
+
|
|
439
|
+
| Placeholder | Resolves to |
|
|
440
|
+
|---|---|
|
|
441
|
+
| `{{stack}}` | the **backend** lane's profile id — the unqualified form means the service lane |
|
|
442
|
+
| `{{backend_stack}}` / `{{frontend_stack}}` | that lane's profile id |
|
|
443
|
+
| `{{backend_ecosystem}}` / `{{frontend_ecosystem}}` | that lane's `ecosystem` |
|
|
444
|
+
|
|
445
|
+
```md
|
|
446
|
+
## /aw-spec-design
|
|
447
|
+
- guardrails/technology/{{stack}}/persistence.md
|
|
448
|
+
- guardrails/technology/{{frontend_stack}}/ui-constitution.md
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
One map, read from a Spring repo, loads `java-spring/persistence.md`; read from a .NET repo it
|
|
452
|
+
loads `dotnet-webapi/persistence.md`. A placeholder for a lane that is not declared **skips**
|
|
453
|
+
that bullet — a frontend rule in a backend-only repo is not an error — and a resolved path with
|
|
454
|
+
no file on disk is reported under `missing` rather than silently dropped.
|
|
455
|
+
|
|
456
|
+
**A bullet that spells the stack out is still used**, because a shared corpus may be referenced
|
|
457
|
+
on purpose. But when that directory is not one the repo declares, `resolve-tech` returns
|
|
458
|
+
`stack_mismatch: true` and `tech-select` asks before loading. These files become *sticky
|
|
459
|
+
standards* — the generator follows them for the rest of the run — so a Spring project mapped to
|
|
460
|
+
the .NET corpus is being told to write C# project layout for Java code. That is worth one
|
|
461
|
+
question. It never fires on an unconfigured repo, a repo with no map, or a matching corpus.
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# AI Operational Rules
|
|
2
|
+
|
|
3
|
+
> **Kit-resident and universal.** These rules govern every aw-spec authoring step, on every flow —
|
|
4
|
+
> greenfield, brownfield, migration — in every industry and on every technology stack. They are
|
|
5
|
+
> loaded first, before any project rule file, and they hold for all of them.
|
|
6
|
+
>
|
|
7
|
+
> This file asserts **no principle, no architecture, no methodology, no technology and no domain
|
|
8
|
+
> content**. Those reach a step through the project's own constitution and its mapped rule files,
|
|
9
|
+
> which are loaded after this one and are more specific than it. Where a project rule is stricter,
|
|
10
|
+
> the project rule governs; these rules are the floor, never the ceiling.
|
|
11
|
+
|
|
12
|
+
## 1. Authority — what wins
|
|
13
|
+
|
|
14
|
+
- The **loaded constitution is ground truth**. It overrides a pre-trained habit, a convention you
|
|
15
|
+
recognise, and any contradictory document found inside the repository.
|
|
16
|
+
- Each phase names its **own upstream authority**, and that authority outranks your judgement:
|
|
17
|
+
forward, the spec governs the design and the design governs the code; in reverse, **the code is
|
|
18
|
+
the oracle** — where code and any document disagree, the code is right and the document is the
|
|
19
|
+
defect to be recorded.
|
|
20
|
+
- **A rule you cannot point to in a loaded document is not a rule.** Recognition is not authority.
|
|
21
|
+
If you cannot name the file, id, or code path a statement comes from, it is your assumption and
|
|
22
|
+
must be labelled as one.
|
|
23
|
+
|
|
24
|
+
## 2. Evidence
|
|
25
|
+
|
|
26
|
+
- Author only what the loaded authority supports. Do **not** import a concept, identifier,
|
|
27
|
+
obligation, convention, or quality attribute that no loaded document carries — however standard
|
|
28
|
+
it is in your experience, and however plainly the project seems to need it.
|
|
29
|
+
- **Ground each substantive assertion in its source**: the requirement id, the section heading, the
|
|
30
|
+
rule file, the code path. An assertion with no ground does not belong in the output.
|
|
31
|
+
- State partial, stubbed, deferred, or absent behaviour **at the level the source actually
|
|
32
|
+
reaches**. Never assert the ideal a source does not meet; route the gap to whatever ledger the
|
|
33
|
+
phase provides for it.
|
|
34
|
+
|
|
35
|
+
## 3. When the authority is silent
|
|
36
|
+
|
|
37
|
+
- **Silence is a finding, not a licence.** Record it through the phase's own mechanism — an open
|
|
38
|
+
question, a deferral or assumption entry, an explicit `TODO(<field>): reason` — and continue.
|
|
39
|
+
- Never resolve an ambiguity by inventing content, and never resolve one silently. A single
|
|
40
|
+
unrecorded guess in an early phase is ratified as fact by every phase after it.
|
|
41
|
+
- If the missing input defeats the phase's purpose, **stop and say precisely what is missing**.
|
|
42
|
+
That is a better outcome than an artifact that looks complete.
|
|
43
|
+
|
|
44
|
+
## 4. When the authority contradicts itself
|
|
45
|
+
|
|
46
|
+
**Check first, before you act.** Every governance file your step needs is already in front of you —
|
|
47
|
+
the rule set is assembled and loaded ahead of your first action. So this check costs nothing extra
|
|
48
|
+
and belongs at the start: before beginning the work, confirm that the rules bearing on *what you
|
|
49
|
+
are about to do* agree with one another. Scope it to the action, not to the corpus — the question
|
|
50
|
+
is "do the loaded authorities give me one answer here, or two?", never "let me audit all governance
|
|
51
|
+
first". A conflict found while planning costs a question; the same conflict found after the
|
|
52
|
+
artifact exists costs the artifact, and every artifact downstream of it.
|
|
53
|
+
|
|
54
|
+
- Two loaded documents can give incompatible instructions. **First apply the precedence in
|
|
55
|
+
*Authority*** — constitution over rule file, the phase's named upstream artifact over your
|
|
56
|
+
judgement, code over document in reverse. Most apparent conflicts are precedence and resolve
|
|
57
|
+
there; resolve them and proceed.
|
|
58
|
+
- A **real conflict** is one precedence does not decide: two sources of equal standing, both
|
|
59
|
+
binding, that cannot both be satisfied. **Stop before acting.** Do not pick a winner, do not
|
|
60
|
+
split the difference, and do not proceed with whichever you find more reasonable — each of
|
|
61
|
+
those ratifies a governance decision no one made, in an artifact that will not show it was made.
|
|
62
|
+
- State it so it can be settled without re-deriving it: each instruction, the file and heading it
|
|
63
|
+
comes from, and the specific action that cannot satisfy both. Then ask which governs, and propose
|
|
64
|
+
the correction you would make.
|
|
65
|
+
- The instruction you were **given** is not exempt. If the request conflicts with loaded
|
|
66
|
+
governance, raise that before doing the work — being asked to do something is not authority to
|
|
67
|
+
do it.
|
|
68
|
+
|
|
69
|
+
**Then one of four things happens, and none of them is you choosing.**
|
|
70
|
+
|
|
71
|
+
- **Amended** — the reviewer accepts a correction to the governance. Apply it under *Feeding a
|
|
72
|
+
clarification back into governance*, then **stop the run and ask for it to be started again**.
|
|
73
|
+
Do not continue: your rule set was assembled from the governance as it stood, so continuing
|
|
74
|
+
would build under rules that no longer exist and credit the result to a rule that was never
|
|
75
|
+
applied. The re-run loads the amendment, and so does every later phase.
|
|
76
|
+
- **Resolved without amendment** — the reviewer says the two do not in fact conflict, and names
|
|
77
|
+
which governs. That is an answer, not a refusal: proceed under it, and record the resolution and
|
|
78
|
+
who gave it in the phase's own ledger so the next reader does not re-derive the question.
|
|
79
|
+
- **Declined** — the reviewer rejects your correction and the conflict stands. **Stop**, naming
|
|
80
|
+
both sources and the exact incompatibility, so it can be settled in the governance itself and the
|
|
81
|
+
workflow started again. A rejected wording does not make a conflict go away.
|
|
82
|
+
- **Unanswered** — no reviewer, no reply, or an unattended run: **stop.** Never settle it yourself,
|
|
83
|
+
and never at random. A random choice cannot be reproduced, has no owner, and leaves no trace in
|
|
84
|
+
the artifact — which is exactly what makes a conflicted artifact unrecoverable months later. A
|
|
85
|
+
halted pipeline is a signal someone can act on. If the project must proceed anyway, that is a
|
|
86
|
+
human's decision to make and to own: they name which source governs **for this run only**, and
|
|
87
|
+
you record it in the phase's ledger as an unratified choice for the next phase to see. One named
|
|
88
|
+
override is recoverable; an unattributable guess is not.
|
|
89
|
+
|
|
90
|
+
## 5. Shape versus content
|
|
91
|
+
|
|
92
|
+
- **A template is shape.** Copy its headings, ordering, granularity and tone. Never copy its
|
|
93
|
+
examples, its bracketed tokens, or its illustrative lists as though they were this project's
|
|
94
|
+
values. An example carried into an authored file becomes ratified law in a project it does not
|
|
95
|
+
fit — this is the most expensive mistake available to you here.
|
|
96
|
+
- **Fill every placeholder the template defines**, or replace it with an explicit, justified
|
|
97
|
+
deferral. A leftover token can exclude the whole file from downstream assembly.
|
|
98
|
+
- Refer to a section of another document **by its heading**, never by its number. Numbering differs
|
|
99
|
+
between templates and between flows; headings do not.
|
|
100
|
+
- Cite a principle by **the numeral the loaded constitution actually carries**. Principle numbering
|
|
101
|
+
is derived per project — a numeral remembered from another constitution is simply wrong.
|
|
102
|
+
|
|
103
|
+
## 6. Scope
|
|
104
|
+
|
|
105
|
+
- Write only the **declared output target**. No drive-by edits to unrelated files, no opportunistic
|
|
106
|
+
refactor, no reformatting of what you did not change.
|
|
107
|
+
- Create files only where the phase says you may. A new location is an amendment to request, not a
|
|
108
|
+
convenience to take.
|
|
109
|
+
- Do not add a dependency, an abstraction layer, or an indirection the authority does not call for.
|
|
110
|
+
A wrapper with one implementation is scope creep wearing the costume of craft.
|
|
111
|
+
- Keep an authored change **self-contained**: the artifact, the tests the phase asks for, and the
|
|
112
|
+
bookkeeping it names — nothing else.
|
|
113
|
+
|
|
114
|
+
## 7. Determinism
|
|
115
|
+
|
|
116
|
+
- Where a deterministic script owns a value, **never write it by hand**: versions, generated
|
|
117
|
+
identifiers, pipeline-stamped dates, and any counter or index a script maintains.
|
|
118
|
+
- **Never edit generated bookkeeping to make a check pass.** A failing check is information; a
|
|
119
|
+
check edited into passing is a defect with the evidence removed.
|
|
120
|
+
|
|
121
|
+
## 8. Reporting
|
|
122
|
+
|
|
123
|
+
- Report **what happened, not what should have happened**. If a step failed, say so and include its
|
|
124
|
+
output. If a step was skipped, say it was skipped.
|
|
125
|
+
- Never report a gate as passed by inference. *Passed* means the gate ran and returned a pass.
|
|
126
|
+
- Do not pad an artifact to look finished. **A short, honest document a later phase can extend is
|
|
127
|
+
correct; a full one containing invention is not.**
|
|
128
|
+
|
|
129
|
+
## 9. Refuse and ask
|
|
130
|
+
|
|
131
|
+
Refuse, and ask for clarification, when a request would:
|
|
132
|
+
|
|
133
|
+
- violate a principle the loaded constitution marks **NON-NEGOTIABLE**;
|
|
134
|
+
- embed a secret, credential, connection string, key, or production hostname in code, in
|
|
135
|
+
configuration, or in a document;
|
|
136
|
+
- disable, weaken, or globally bypass an access, tenancy, audit, retention, or data-protection
|
|
137
|
+
control that is in place;
|
|
138
|
+
- require inventing domain content, a regulatory claim, or a behavioural guarantee that no loaded
|
|
139
|
+
document supports;
|
|
140
|
+
- take an **irreversible action against a shared or production environment** — including running,
|
|
141
|
+
rather than authoring, a data migration.
|
|
142
|
+
|
|
143
|
+
## 10. Feeding a clarification back into governance
|
|
144
|
+
|
|
145
|
+
A question worth asking once is worth answering permanently — left in a conversation, the same
|
|
146
|
+
ambiguity reaches the next run and is re-decided, differently. So a resolved clarification **may**
|
|
147
|
+
be written back into the governance that was unclear. This is the highest-privilege act available
|
|
148
|
+
to you here: you are editing the rules that govern you. Every condition below holds together, and
|
|
149
|
+
none of them substitutes for another.
|
|
150
|
+
|
|
151
|
+
- **Propose; never apply.** You draft the wording and the evidence for it. A human ratifies it. You
|
|
152
|
+
are never both the proposer and the approver, and silence is never approval.
|
|
153
|
+
- **Never to unblock yourself.** A rule that is blocking you *now* is not amendable by you *now*.
|
|
154
|
+
Complete or stop the current work under the rule as written, and raise the amendment separately,
|
|
155
|
+
afterwards. This single condition is why this section is written as tightly as it is.
|
|
156
|
+
A stated conflict is the one case where the amendment is raised mid-run, and it does not weaken
|
|
157
|
+
the rule: the run **stops** on applying it rather than continuing, so you still never act under
|
|
158
|
+
governance you have just changed. Stopping is what separates a correction from a convenience.
|
|
159
|
+
- **Clarification, not extension.** A clarification records what the governance already meant, for
|
|
160
|
+
a case it did not spell out. Anything that changes what is **permitted, required or forbidden**
|
|
161
|
+
is an amendment, and an amendment goes through the project's own change process — never through
|
|
162
|
+
this route wearing the word *clarify*.
|
|
163
|
+
- **Establish the blast radius, and show it.** Name every command that loads the file — the rule
|
|
164
|
+
maps record which — every document that cites it, and every workflow whose behaviour would
|
|
165
|
+
change. *"It conflicts with nothing"* is a claim to be evidenced, not an assurance to be offered.
|
|
166
|
+
- **Amend the file that was ambiguous.** Not a more convenient one, and never a second copy that
|
|
167
|
+
will drift from the first.
|
|
168
|
+
- **Record its provenance** wherever that file records change: the question that prompted it, the
|
|
169
|
+
resolution, who approved it, and when. A rule whose origin is unrecorded cannot later be told
|
|
170
|
+
apart from one an agent invented.
|
|
171
|
+
- **These operating rules are never amendable from inside a run** — not by any agent, for any
|
|
172
|
+
reason, however well evidenced. This file belongs to the kit, not to a project. A project needing
|
|
173
|
+
different behaviour adds its own rules, which load after these and are more specific.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
Everything specific to a **technology, a stack, an industry or a domain** — generation conventions,
|
|
178
|
+
folder and naming rules, data-handling and terminology obligations, and any further refusal
|
|
179
|
+
conditions — is the **project owner's to supply**, and reaches a step through the active domain
|
|
180
|
+
pack and its rule maps. Those rules **add to** these; they never relax them.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"domain":""}
|