aw-spec-cli 0.1.20 → 0.1.22

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.
Files changed (62) hide show
  1. package/assets/.appweaver/ORCH-DIALECT.md +8 -3
  2. package/assets/.appweaver/STACK-PROFILES.md +87 -8
  3. package/assets/.appweaver/orchestrator/modules/delta-plan.orch.yaml +30 -0
  4. package/assets/.appweaver/orchestrator/modules/delta-spec.orch.yaml +22 -1
  5. package/assets/.appweaver/orchestrator/orchestrator.py +65 -3
  6. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan-delta.orch.yaml +6 -6
  7. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-plan.orch.yaml +144 -52
  8. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice-delta.orch.yaml +78 -10
  9. package/assets/.appweaver/orchestrator/workflows/aw-spec-analyze-slice.orch.yaml +283 -25
  10. package/assets/.appweaver/orchestrator/workflows/aw-spec-constitution.orch.yaml +4 -4
  11. package/assets/.appweaver/orchestrator/workflows/aw-spec-finalize-delta.orch.yaml +202 -40
  12. package/assets/.appweaver/orchestrator/workflows/aw-spec-foundation.orch.yaml +140 -36
  13. package/assets/.appweaver/orchestrator/workflows/aw-spec-implement.orch.yaml +557 -57
  14. package/assets/.appweaver/orchestrator/workflows/aw-spec-onboard.orch.yaml +3 -3
  15. package/assets/.appweaver/orchestrator/workflows/aw-spec-plan.orch.yaml +39 -0
  16. package/assets/.appweaver/orchestrator/workflows/aw-spec-recall-delta.orch.yaml +28 -7
  17. package/assets/.appweaver/orchestrator/workflows/aw-spec-select-stack.orch.yaml +47 -23
  18. package/assets/.appweaver/orchestrator/workflows/aw-spec-specify.orch.yaml +101 -1
  19. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-model.orch.yaml +141 -0
  20. package/assets/.appweaver/orchestrator/workflows/aw-spec-ui-prototype.orch.yaml +386 -0
  21. package/assets/.appweaver/orchestrator/workflows/aw-spec-workflow-model.orch.yaml +135 -0
  22. package/assets/.appweaver/scripts/bash/aw-spec-actions.sh +772 -216
  23. package/assets/.appweaver/scripts/bash/aw-xref.sh +4 -1
  24. package/assets/.appweaver/scripts/powershell/aw-spec-actions.ps1 +708 -209
  25. package/assets/.appweaver/scripts/powershell/aw-xref.ps1 +4 -1
  26. package/assets/.appweaver/scripts/python/aw-crstate.py +319 -0
  27. package/assets/.appweaver/scripts/python/aw-foundation.py +151 -0
  28. package/assets/.appweaver/scripts/python/aw-gaps.py +119 -0
  29. package/assets/.appweaver/scripts/python/aw-payload-parity.py +19 -0
  30. package/assets/.appweaver/scripts/python/aw-plan-coverage.py +503 -0
  31. package/assets/.appweaver/scripts/python/aw-plangate.py +216 -0
  32. package/assets/.appweaver/scripts/python/aw-principles.py +108 -0
  33. package/assets/.appweaver/scripts/python/aw-stack.py +257 -28
  34. package/assets/.appweaver/scripts/python/aw-testlog.py +148 -0
  35. package/assets/.appweaver/scripts/python/aw-xref.py +141 -4
  36. package/assets/.appweaver/stack-profiles/angular.json +26 -0
  37. package/assets/.appweaver/stack-profiles/blazor-wasm.json +38 -0
  38. package/assets/.appweaver/stack-profiles/dotnet-webapi.json +39 -0
  39. package/assets/.appweaver/stack-profiles/java-spring.json +20 -0
  40. package/assets/.appweaver/stack-profiles/nextjs.json +26 -0
  41. package/assets/.appweaver/stack-profiles/node-express.json +27 -0
  42. package/assets/.appweaver/stack-profiles/python-fastapi.json +16 -0
  43. package/assets/.appweaver/stack-profiles/react-vite.json +26 -0
  44. package/assets/.appweaver/stack-profiles/sveltekit.json +26 -0
  45. package/assets/.appweaver/stack-profiles/vue-vite.json +26 -0
  46. package/assets/.appweaver/templates/constitution-domain-template.md +17 -2
  47. package/assets/.appweaver/templates/ui-model-template.md +67 -0
  48. package/assets/.appweaver/templates/workflow-model-template.md +62 -0
  49. package/assets/guardrails/projects/dotnet-default-project/domain-rule-bindings.md +10 -6
  50. package/assets/guardrails/projects/dotnet-default-project/tech-rule-bindings.md +4 -0
  51. package/assets/guardrails/technology/dotnet-webapi/auditing.md +3 -1
  52. package/assets/guardrails/technology/dotnet-webapi/coding-standards.md +5 -3
  53. package/assets/guardrails/technology/dotnet-webapi/cqrs.md +5 -1
  54. package/assets/guardrails/technology/dotnet-webapi/domain-driven-design.md +13 -5
  55. package/assets/guardrails/technology/dotnet-webapi/examples/cqrs.md +2 -0
  56. package/assets/guardrails/technology/dotnet-webapi/examples/domain-driven-design.md +6 -2
  57. package/assets/guardrails/technology/dotnet-webapi/framework-api-map.md +114 -0
  58. package/assets/guardrails/technology/dotnet-webapi/technology-constitution.md +3 -0
  59. package/assets/guardrails/technology/dotnet-webapi/testing.md +10 -0
  60. package/assets/guardrails/technology/nextjs/ui-constitution.md +8 -1
  61. package/package.json +1 -1
  62. package/assets/.appweaver/orchestrator/.state/smoke.state.json +0 -32
@@ -0,0 +1,62 @@
1
+ # Workflow Model: [Feature Name]
2
+
3
+ **Aggregate (feature)**: `[Aggregate]`
4
+ **Spec Reference**: `specs/[Aggregate]/spec.md`
5
+ **Version**: v1.0
6
+ **Status**: Active
7
+
8
+ ## Overview
9
+
10
+ [Summary of the user workflows derived from the feature specification.]
11
+
12
+ ## Workflows
13
+
14
+ ### WF-1 - [Workflow Title]
15
+
16
+ - **Actor / Persona**: [Primary user role executing this workflow — e.g. Project Manager]
17
+ - **Goal**: [What the user is trying to accomplish]
18
+ - **Preconditions**: [Initial system state or permissions required]
19
+
20
+ #### Primary Flow
21
+
22
+ 1. [Step 1: User initiates or accesses interaction]
23
+ 2. [Step 2: System presents data or inputs]
24
+ 3. [Step 3: User enters parameters or performs action]
25
+ 4. [Step 4: System processes and validates]
26
+ 5. [Step 5: User views confirmation or resulting state]
27
+
28
+ #### Alternative Paths & Decision Points
29
+
30
+ - **If [Condition / Decision A]**: [Alternative interaction path]
31
+ - **If [Condition / Decision B]**: [Cancellation / Exit path without state mutation]
32
+
33
+ #### Validation & Error Handling
34
+
35
+ - **If [Validation Rule Fails]**: System blocks progression and displays inline error feedback.
36
+
37
+ #### State Transitions
38
+
39
+ - **Initial State**: `[State A]`
40
+ - **Resulting State**: `[State B]`
41
+
42
+ ---
43
+
44
+ ### WF-2 - [Next Workflow Title]
45
+
46
+ - **Actor / Persona**: [User role]
47
+ - **Goal**: [User goal]
48
+ - **Preconditions**: [Preconditions]
49
+
50
+ #### Primary Flow
51
+
52
+ 1. [Step 1]
53
+ 2. [Step 2]
54
+
55
+ #### Alternative Paths & Decision Points
56
+
57
+ - **If [Condition]**: [Flow]
58
+
59
+ #### State Transitions
60
+
61
+ - **Initial State**: `[State]`
62
+ - **Resulting State**: `[State]`
@@ -26,13 +26,16 @@ through the spec/design (as CN-/DC-/IC- ids).
26
26
 
27
27
  ## /aw-spec-constitution
28
28
  <!-- What the DOMAIN half ratifies into constitution.domain.md as domain principles XVI+.
29
- The industry constitution first, then the STANDARD industry rules — identity,
30
- regulatory, interop, security overlays — which every project on this corpus shares, and
31
- LAST the PROJECT-SUPPLIED domain-requirements.md the project team authors. Only that
32
- last file is expected to differ between two projects on the same corpus, and its mapping is
33
- OPTIONAL: the project owner supplies the file, and where it is absent the set loads
34
- without it rather than failing. -->
29
+ The industry constitution first, then the STANDARD industry rules — the modelling
30
+ overlay the Adopted Modelling Standard section cites, identity, regulatory, interop,
31
+ security overlays, and the folder overlay the Domain Folder Additions section cites —
32
+ which every project on this corpus shares, and LAST the PROJECT-SUPPLIED
33
+ domain-requirements.md the project team authors. Only that last file is expected to
34
+ differ between two projects on the same corpus, and its mapping is OPTIONAL: the project
35
+ owner supplies the file, and where it is absent the set loads without it rather than
36
+ failing. -->
35
37
  - guardrails/domain/healthcare/domain-constitution.md
38
+ - guardrails/domain/healthcare/domain-driven-design.domain.md
36
39
  - guardrails/domain/healthcare/clinical-terms.md
37
40
  - guardrails/domain/healthcare/terminology.md
38
41
  - guardrails/domain/healthcare/consent.md
@@ -45,6 +48,7 @@ through the spec/design (as CN-/DC-/IC- ids).
45
48
  - guardrails/domain/healthcare/authorization.domain.md
46
49
  - guardrails/domain/healthcare/zero-trust.domain.md
47
50
  - guardrails/domain/healthcare/ai-rules.domain.md
51
+ - guardrails/domain/healthcare/folder-structure.domain.md
48
52
  - guardrails/projects/dotnet-default-project/domain/domain-requirements.md
49
53
 
50
54
  ## /aw-spec-specify
@@ -141,6 +141,7 @@ NOT listed here — every consumer refers to it directly, as-is.
141
141
  - guardrails/technology/dotnet-webapi/coding-standards.md
142
142
  - guardrails/technology/dotnet-webapi/dependency-policy.md
143
143
  - guardrails/technology/dotnet-webapi/folder-structure.md
144
+ - guardrails/technology/dotnet-webapi/framework-api-map.md
144
145
  - guardrails/technology/dotnet-webapi/testing.md
145
146
  - guardrails/technology/dotnet-webapi/PACKAGING.md
146
147
 
@@ -181,6 +182,7 @@ NOT listed here — every consumer refers to it directly, as-is.
181
182
  - guardrails/technology/dotnet-webapi/coding-standards.md
182
183
  - guardrails/technology/dotnet-webapi/dependency-policy.md
183
184
  - guardrails/technology/dotnet-webapi/folder-structure.md
185
+ - guardrails/technology/dotnet-webapi/framework-api-map.md
184
186
  - guardrails/technology/dotnet-webapi/testing.md
185
187
  - guardrails/technology/dotnet-webapi/PACKAGING.md
186
188
 
@@ -199,6 +201,7 @@ NOT listed here — every consumer refers to it directly, as-is.
199
201
  resolve-domain `## /aw-spec-gate`). Validation input only — never authoring. -->
200
202
  - guardrails/technology/dotnet-webapi/testing.md
201
203
  - guardrails/technology/dotnet-webapi/coding-standards.md
204
+ - guardrails/technology/dotnet-webapi/framework-api-map.md
202
205
 
203
206
  ## /aw-spec-constitution
204
207
  <!-- What the TECHNICAL half of the split constitution ratifies into
@@ -214,6 +217,7 @@ NOT listed here — every consumer refers to it directly, as-is.
214
217
  - guardrails/technology/dotnet-webapi/clean-architecture.md
215
218
  - guardrails/technology/dotnet-webapi/modular-monolith.md
216
219
  - guardrails/technology/dotnet-webapi/vertical-slices.md
220
+ - guardrails/technology/dotnet-webapi/domain-driven-design.md
217
221
  - guardrails/technology/dotnet-webapi/cqrs.md
218
222
  - guardrails/technology/dotnet-webapi/persistence.md
219
223
  - guardrails/technology/dotnet-webapi/eventing.md
@@ -51,7 +51,9 @@ implements. The interceptor populates every audit field automatically (no manual
51
51
  | **Advanced** | Basic markers **+ `IFieldAudited`** | Basic + field-level before/after (`PropertyChange`: original → new) | entity + property-level previous/new |
52
52
 
53
53
  Field-level before/after values exist **only** at the Advanced tier. Children marked
54
- `IAggregateChild` fold into the root's `AuditLog`.
54
+ `IAggregateChild` (`AppWeaver.Auditing.Interfaces`, package `AppWeaver.Auditing` —
55
+ [[framework-api-map]]) fold into the root's `AuditLog`; an unmarked child gets a standalone
56
+ entry instead, which is the silent failure this marker exists to prevent.
55
57
 
56
58
  ## Canonical example
57
59
 
@@ -7,9 +7,11 @@
7
7
  - Solution and projects: `<SampleProjectName>.<Role>` (e.g. `<SampleProjectName>.Api`,
8
8
  `<SampleProjectName>.AppHost`, `<SampleProjectName>.ServiceDefaults`).
9
9
  - Namespaces mirror the folder path exactly; **file-scoped namespaces only**.
10
- - Aggregates: `class <Aggregate> : EntityBase<<Aggregate>Id>, IAggregateRoot,
11
- IFullAuditedObject, ISoftDeletable, IConcurrencyTracked, IHasDomainEvents,
12
- INamedEntity<<Aggregate>Id>`.
10
+ - Aggregates: `class <Aggregate> : AggregateRootBase<<Aggregate>Id>, IFullAuditedObject,
11
+ ISoftDeletable, IConcurrencyTracked, INamedEntity<<Aggregate>Id>` —
12
+ `AggregateRootBase<TId>` already carries `EntityBase<TId>`, `IAggregateRoot` and
13
+ `IHasDomainEvents`. Child entities take `EntityBase<TId>` plus `IAggregateChild`.
14
+ Packages and namespaces: [[framework-api-map]].
13
15
  - Commands/Queries: `record <Verb><Aggregate>Command(...) : ICommand<Result<TDto>>`.
14
16
  - DTOs: `record <Aggregate>Dto { public required Guid Id { get; init; } ... }` — no setters;
15
17
  required init for non-nullable members.
@@ -47,7 +47,11 @@ Enabled at startup, in order:
47
47
 
48
48
  - Write handlers **MUST** wrap mutating work in
49
49
  `IUnitOfWork.ExecuteInTransactionAsync(..., IsolationLevel.ReadCommitted, ct)` and call
50
- `SaveChangesAsync` **inside** the lambda.
50
+ `SaveChangesAsync` **inside** the lambda. That method is an extension in
51
+ `AppWeaver.Repository.Extensions` over `AppWeaver.Repository.Abstractions.IUnitOfWork` —
52
+ add both usings. It does NOT extend the `AppWeaver.SharedKernel` interface of the same
53
+ name, and injecting that one is why the method can appear not to exist
54
+ ([[framework-api-map]]).
51
55
  - They **MUST** publish domain events and call `ClearDomainEvents()` before returning.
52
56
  - **One command mutates one aggregate per transaction** — cross-aggregate effects flow
53
57
  through domain events or follow-up commands (see [[eventing]]).
@@ -15,10 +15,14 @@
15
15
  ## Aggregate design
16
16
 
17
17
  - Every entity exposed to the Application layer is reached through an **Aggregate Root**.
18
- - Aggregate roots implement `IAggregateRoot`, `EntityBase<TId>`, and the
19
- audit/soft-delete/concurrency/domain-event interfaces they need:
20
- `IFullAuditedObject` or `IAuditableEntityBase`, `ISoftDeletable`, `IConcurrencyTracked`,
21
- `IHasDomainEvents`, `INamedEntity<TId>` when listable.
18
+ - Aggregate roots derive from `AggregateRootBase<TId>`
19
+ (`AppWeaver.DomainAbstraction.Entities`), which already carries `EntityBase<TId>`,
20
+ `IAggregateRoot` and domain-event support — do not reassemble those by hand. They add the
21
+ audit/soft-delete/concurrency interfaces they need: `IFullAuditedObject`
22
+ (`AppWeaver.Auditing.Interfaces`) or `IAuditableEntityBase`, `ISoftDeletable`,
23
+ `IConcurrencyTracked` (`AppWeaver.DomainAbstraction.Entities`), and `INamedEntity<TId>`
24
+ when listable. Every package and namespace is in [[framework-api-map]]; a type that seems
25
+ to be missing is a missing package reference, not an absent API.
22
26
 
23
27
  ### Aggregate root responsibilities
24
28
 
@@ -28,7 +32,11 @@
28
32
 
29
33
  ### Child entity ownership
30
34
 
31
- - Child entities implement `IAggregateChild` and expose `GetAggregateRoot()`.
35
+ - Child entities derive from `EntityBase<TId>` (`AppWeaver.DomainAbstraction.Entities`) and
36
+ implement `IAggregateChild` (`AppWeaver.Auditing.Interfaces` — a DIFFERENT package from the
37
+ aggregate types, see [[framework-api-map]]), returning the in-memory root instance from
38
+ `GetAggregateRoot()`. That linkage is what folds the child's changes into the root's audit
39
+ entry instead of leaving a standalone one.
32
40
  - They are mutated **only** through methods on the aggregate root.
33
41
 
34
42
  ## Transactional / consistency boundaries
@@ -21,6 +21,8 @@ public record CreateProjectCommand(
21
21
  ) : ICommand<Result<ProjectDto>>;
22
22
 
23
23
  // Write handler — primary-ctor DI, transaction, publish + clear events, Result<T>
24
+ // using AppWeaver.Repository.Abstractions; // IRepository<T>, IUnitOfWork
25
+ // using AppWeaver.Repository.Extensions; // ExecuteInTransactionAsync — the extension below
24
26
  public class CreateProjectCommandHandler(
25
27
  IRepository<Project> _repo, IUnitOfWork _uow, IPublisher _eventBus
26
28
  ) : ICommandHandler<CreateProjectCommand, Result<ProjectDto>>
@@ -19,9 +19,11 @@ domain events, and an invariant enforced **inside** the aggregate:
19
19
  [ValueObject<Guid>]
20
20
  public partial struct ProjectId { }
21
21
 
22
+ // using AppWeaver.DomainAbstraction.Entities; // AggregateRootBase, ISoftDeletable, IConcurrencyTracked
23
+ // using AppWeaver.Auditing.Interfaces; // IFullAuditedObject, IFieldAudited (package AppWeaver.Auditing)
22
24
  public class Project :
23
- EntityBase<ProjectId>, IAggregateRoot, IFullAuditedObject, IFieldAudited,
24
- ISoftDeletable, IConcurrencyTracked, IHasDomainEvents, INamedEntity<ProjectId>
25
+ AggregateRootBase<ProjectId>, IFullAuditedObject, IFieldAudited,
26
+ ISoftDeletable, IConcurrencyTracked, INamedEntity<ProjectId>
25
27
  {
26
28
  private readonly List<ProjectTask> _tasks = new();
27
29
 
@@ -100,6 +102,8 @@ setters, and is mutated **only** through methods the parent aggregate calls:
100
102
  [ValueObject<Guid>]
101
103
  public partial struct ProjectTaskId { }
102
104
 
105
+ // using AppWeaver.DomainAbstraction.Entities; // EntityBase
106
+ // using AppWeaver.Auditing.Interfaces; // IAggregateChild (package AppWeaver.Auditing)
103
107
  public class ProjectTask : EntityBase<ProjectTaskId>, IAggregateChild
104
108
  {
105
109
  public ProjectId ProjectId { get; private set; } // FK back to the root
@@ -0,0 +1,114 @@
1
+ # Framework API Map — which package and namespace each cited type comes from
2
+
3
+ > Pure technology (domain-agnostic). NON-NEGOTIABLE where it names a package.
4
+ > Commands: `/aw-spec-implement`, `/aw-spec-implement-delta`, `/aw-spec-analyze-slice`.
5
+ >
6
+ > The rules in this corpus name framework types — `AggregateRootBase<TId>`,
7
+ > `IAggregateChild`, `IUnitOfWork`. This file says where each one LIVES. Without it a
8
+ > generator searches for a bare type name, finds a same-named type in another package or
9
+ > none at all, and concludes the API does not exist — then hand-rolls a substitute or
10
+ > silently drops the rule that required it.
11
+
12
+ ## The trap this file exists for
13
+
14
+ **Several of these names exist TWICE**, once in `AppWeaver.SharedKernel` and once in the
15
+ split packages (`AppWeaver.DomainAbstraction`, `AppWeaver.Repository`, `AppWeaver.Auditing`).
16
+ The two sets are not interchangeable:
17
+
18
+ - `AppWeaver.Repository.Abstractions.IUnitOfWork` takes an isolation level on
19
+ `BeginTransactionAsync` and is what `ExecuteInTransactionAsync` extends.
20
+ `AppWeaver.SharedKernel.UnitOfWork.IUnitOfWork` does neither — inject that one and the
21
+ transaction helper is not in scope, which reads exactly like "the method does not exist".
22
+ - `EntityBase<TId>`, `IAggregateRoot`, `DomainEventBase`, `ISoftDeletable` and the other
23
+ entity interfaces have SharedKernel twins in the same shape.
24
+
25
+ **Use the split packages.** They are what the shipped foundation references; SharedKernel is
26
+ not referenced by it. Never import a SharedKernel namespace into generated code, and never
27
+ mix the two sets in one type.
28
+
29
+ ## The map
30
+
31
+ | Type | Package | Namespace |
32
+ |---|---|---|
33
+ | `AggregateRootBase<TId>` | `AppWeaver.DomainAbstraction` | `AppWeaver.DomainAbstraction.Entities` |
34
+ | `EntityBase<TId>` | `AppWeaver.DomainAbstraction` | `AppWeaver.DomainAbstraction.Entities` |
35
+ | `IEntity<TId>` | `AppWeaver.DomainAbstraction` | `AppWeaver.DomainAbstraction.Entities` |
36
+ | `IAuditableEntityBase`, `ISoftDeletable`, `IConcurrencyTracked` | `AppWeaver.DomainAbstraction` | `AppWeaver.DomainAbstraction.Entities` |
37
+ | `IAggregateRoot` | `AppWeaver.DomainAbstraction` | `AppWeaver.DomainAbstraction.Aggregates` |
38
+ | `DomainEventBase`, `IHasDomainEvents` | `AppWeaver.DomainAbstraction` | `AppWeaver.DomainAbstraction.DomainEvents` |
39
+ | `IAggregateChild`, `IFullAuditedObject`, `IFieldAudited` | **`AppWeaver.Auditing`** | `AppWeaver.Auditing.Interfaces` |
40
+ | `IUnitOfWork`, `IRepository<T>`, `IReadRepository<T>` | `AppWeaver.Repository` | `AppWeaver.Repository.Abstractions` |
41
+ | `ExecuteInTransactionAsync(...)` (extension on `IUnitOfWork`) | `AppWeaver.Repository` | `AppWeaver.Repository.Extensions` |
42
+ | `ContextAwareDbContext<T>`, `EfRepository<T>` | `AppWeaver.Repository.EfCore` | `AppWeaver.Repository.EfCore` |
43
+ | `INamedEntity`, `INamedEntity<TId>` | `AppWeaver.DomainAbstraction` | `AppWeaver.DomainAbstraction.Entities` |
44
+ | `IAuditedObject` | `AppWeaver.Auditing` | `AppWeaver.Auditing.Interfaces` |
45
+ | `Result`, `Result<T>` | `AppWeaver.Results` | `AppWeaver.Results` |
46
+ | `ICommand<T>`, `ICommandHandler<TCommand, TResponse>` | `AppWeaver.Mediator` | `AppWeaver.Mediator.Interfaces` |
47
+ | `IPublisher` | `AppWeaver.EventBus` | `AppWeaver.EventBus` |
48
+
49
+ The auditing interfaces are the ones most often reported missing: they are in a DIFFERENT
50
+ package from the aggregate types, so a project that references `AppWeaver.DomainAbstraction`
51
+ alone cannot see `IAggregateChild` at all. A rule that requires one requires its package.
52
+
53
+ ## The other direction — framework types that shadow DOMAIN names
54
+
55
+ The map above is about a framework type the code cannot find. The opposite failure is a
56
+ framework type it finds *too easily*: a domain noun that the ambient scope already defines.
57
+
58
+ `Microsoft.NET.Sdk.Web` turns on implicit usings, so `System`, `System.Collections.Generic`,
59
+ `System.IO`, `System.Threading.Tasks`, `Microsoft.AspNetCore.Http` and
60
+ `Microsoft.AspNetCore.Routing` are in scope in **every** file without appearing in any
61
+ `using` line. A domain type sharing a name with one of theirs — `Route`, `Task`, `Activity`,
62
+ `Path`, `File`, `Timer`, `Index`, `Range`, `Version`, `Results`, `Endpoint`, `Environment`,
63
+ `Stream`, `Type`, `Queue`, `Stack` — is then an **ambiguous reference, CS0104**:
64
+
65
+ ```csharp
66
+ using Acme.Clinic.Service.Care.Domain; // brings in the domain Route
67
+
68
+ public static Route? Route(string? value) // CS0104: Care.Domain.Route
69
+ // vs Microsoft.AspNetCore.Routing.Route
70
+ ```
71
+
72
+ The conflict is invisible in the file. Nothing in it names `Microsoft.AspNetCore.Routing`,
73
+ so the bare name reads as correct and fails only at build.
74
+
75
+ **The domain name is not the problem and never changes.** It is the ubiquitous language,
76
+ the plan spells it, and the code spells it back verbatim. What changes is how it is
77
+ written at the use site:
78
+
79
+ ```csharp
80
+ public static Domain.Route? Route(string? value) =>
81
+ string.IsNullOrWhiteSpace(value) ? null : Domain.Route.From(value);
82
+ ```
83
+
84
+ - **Qualify with the type's own enclosing namespace segment** — `Domain.Route` — at every
85
+ site the type is named: declarations, parameters, return types, generic arguments and
86
+ `<see cref="…"/>` comments.
87
+ - **Not a `using` alias and not the full namespace path.** One convention, so two features
88
+ never disambiguate the same name two ways.
89
+ - **Never rename the domain type** to avoid the clash, and never drop the domain type in
90
+ favour of the framework one.
91
+
92
+ `/aw-spec-implement` is told which of *this* plan's element names are affected before it
93
+ writes anything — the list comes from the lane's stack profile (`reserved_names` in
94
+ `.appweaver/stack-profiles/<id>.json`), so it is the same answer on every run rather than
95
+ something each pass has to notice for itself.
96
+
97
+ ## Rules
98
+
99
+ - **Cite a framework type with its namespace** in plans and generated code, and add the
100
+ `using` for the namespace in the table above — not a guess from the type's name.
101
+ - **A missing type is a MISSING PACKAGE REFERENCE, not an absent API.** Before concluding
102
+ a rule cannot be followed, check this table and the project's package references. Say so
103
+ in the run's summary rather than hand-rolling a substitute — a hand-rolled
104
+ `IAggregateChild` gives the auditing interceptor nothing to hook.
105
+ - **`AggregateRootBase<TId>` is the base for an aggregate root.** It already combines
106
+ `EntityBase<TId>`, `IAggregateRoot` and domain-event support
107
+ (`RegisterDomainEvent` / `DomainEvents` / `ClearDomainEvents`). Assembling those by hand
108
+ duplicates what the package ships. `TId` is `where TId : struct, IEquatable<TId>`, which
109
+ the `[ValueObject<Guid>]` partial-struct id satisfies.
110
+ - **`EntityBase<TId>` is the base for a CHILD entity**, which adds `IAggregateChild`.
111
+
112
+ ## Related
113
+
114
+ - [[domain-driven-design]] · [[coding-standards]] · [[cqrs]] · [[auditing]] · [[persistence]]
@@ -124,6 +124,9 @@ Governed in full by the technical rule files; this file does not duplicate them.
124
124
  `guardrails/technology/dotnet-webapi/coding-standards.md`
125
125
  - Package governance (approved/banned packages, supply-chain, licensing):
126
126
  `guardrails/technology/dotnet-webapi/dependency-policy.md`
127
+ - Which package and namespace each framework type cited by these rules comes from, and the
128
+ same-named types that must NOT be mixed:
129
+ `guardrails/technology/dotnet-webapi/framework-api-map.md`
127
130
  - AI operational rules (generation, context loading, refusal conditions):
128
131
  `.appweaver/ai-rules.md` — the domain half extends this with domain-specific masking,
129
132
  code-set and refusal rules
@@ -38,6 +38,16 @@ Required for **every** Command/Query handler and MUST cover:
38
38
  - Integration and contract tests spin up real PostgreSQL (and other backing services)
39
39
  via Testcontainers / Aspire — no faked persistence in integration tests.
40
40
 
41
+ ## Container validation
42
+
43
+ - One test per service project builds the application's service provider with
44
+ `ValidateOnBuild` and `ValidateScopes` enabled and asserts it succeeds — the registrations
45
+ the app runs with, not a subset re-declared in the test.
46
+ - Every handler, endpoint and adapter the app registers MUST resolve from it. A dependency
47
+ that is injected and never bound compiles green, because a container graph is not
48
+ compile-checked, and fails on the first request that needs it. This test is what turns
49
+ that into a red `dotnet test`.
50
+
41
51
  ## Test data hygiene
42
52
 
43
53
  - Tests use a **shared fixture library** rather than inlining fabricated data.
@@ -83,6 +83,13 @@ Every route, form and interaction state ships with tests: component behaviour, c
83
83
  integration against the generated types, and an accessibility assertion per interactive surface.
84
84
  Snapshot-only tests do not count as coverage.
85
85
 
86
+ **The runner is wired up, not assumed.** The lane's `package.json` defines the `test` script
87
+ its declared command runs (`npm test` unless `.appweaver/stacks.json` says otherwise), pointing
88
+ at the runner the tests are written for. A scaffold ships without one — `create-next-app`
89
+ defines no `test` script — so the first feature that writes a test installs the runner and adds
90
+ the script in the same pass. A lane whose declared test command has nothing to run is not a
91
+ passing lane: `analyze-slice` reports it as untested and fails the gate.
92
+
86
93
  ## Where Each Principle Is Detailed
87
94
 
88
95
  This file is the thin authority; the enforceable rules live in the corpus beside it. Each
@@ -125,7 +132,7 @@ web/
125
132
  lib/api/ # the GENERATED contract client + typed wrappers (never hand-edited)
126
133
  lib/ # cross-feature client utilities
127
134
  locales/ # locale catalogues
128
- tests/ # component, integration and accessibility tests
135
+ tests/ # component, integration and accessibility tests — see "Test runner"
129
136
  ```
130
137
 
131
138
  Generated contract clients land in `lib/api/` and are regenerated, never patched. A feature
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aw-spec-cli",
3
- "version": "0.1.20",
3
+ "version": "0.1.22",
4
4
  "description": "AppWeaver Spec-Driven Development CLI - scaffolds projects with vertical slices, DDD, CQRS, and agent skills",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,32 +0,0 @@
1
- {
2
- "vars": {},
3
- "strategy": "agent",
4
- "model": "",
5
- "input": "",
6
- "answers": {},
7
- "selects": {},
8
- "agent_profile": "",
9
- "isolation": "bare",
10
- "os": "posix",
11
- "cache": {
12
- "script_ro": {
13
- "domains": [
14
- "dotnet-default-project"
15
- ]
16
- }
17
- },
18
- "pending": {
19
- "kind": "ask",
20
- "key": "pick_mode",
21
- "step": "pick_mode",
22
- "prompt": "Smoke mode?",
23
- "options": [
24
- "fast",
25
- "slow"
26
- ],
27
- "multi": false,
28
- "instructions": "Ask the USER this question (the options are the allowed choices). Write the answer as PLAIN TEXT to response_path, then re-run the resume command.",
29
- "response_path": ".appweaver/orchestrator/.state/smoke.state.json.response.md",
30
- "resume": "python3 .appweaver/orchestrator/orchestrator.py .appweaver/orchestrator/workflows/_smoke.orch.yaml --checkpoint .appweaver/orchestrator/.state/smoke.state.json --json"
31
- }
32
- }