@cratis/pi 7.123.0 → 7.124.0
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/package/corpus/agents/spec-writer.md +6 -6
- package/package/corpus/harnesses/copilot/instructions/application-profile.instructions.md +1 -1
- package/package/corpus/harnesses/copilot/instructions/specs.csharp.instructions.md +2 -2
- package/package/corpus/harnesses/copilot/instructions/specs.instructions.md +1 -1
- package/package/corpus/harnesses/copilot/instructions/specs.scenarios.csharp.instructions.md +16 -20
- package/package/corpus/harnesses/copilot/instructions/vertical-slices.instructions.md +5 -3
- package/package/corpus/harnesses/pi/agents/spec-writer.md +6 -6
- package/package/corpus/prompts/add-business-rule.prompt.md +2 -2
- package/package/corpus/rules/application-profile.md +1 -1
- package/package/corpus/rules/specs.csharp.md +2 -2
- package/package/corpus/rules/specs.md +1 -1
- package/package/corpus/rules/specs.scenarios.csharp.md +16 -20
- package/package/corpus/rules/vertical-slices.md +5 -3
- package/package/corpus/skills/cratis-application-slice-specifications/SKILL.md +31 -21
- package/package/corpus/skills/cratis-application-slice-specifications/references/query-and-decision-scenarios.md +48 -44
- package/package/corpus/skills/cratis-arc-command/SKILL.md +5 -0
- package/package/corpus/skills/cratis-arc-command/references/decisions-and-routing.md +16 -14
- package/package/corpus/skills/cratis-arc-command/references/fresh-identifiers.md +13 -15
- package/package/corpus/skills/cratis-arc-command-validation/SKILL.md +18 -12
- package/package/corpus/skills/cratis-arc-command-validation/references/protected-validator-construction.md +9 -5
- package/package/corpus/skills/cratis-chronicle-decision-reads/SKILL.md +12 -8
- package/package/corpus/skills/cratis-chronicle-decision-reads/references/admission-and-ownership.md +6 -2
- package/package/corpus/skills/cratis-chronicle-decision-reads/references/choosing-how-a-rule-holds.md +24 -30
- package/package/corpus/skills/cratis-chronicle-event-specifications/SKILL.md +5 -4
- package/package/corpus/skills/cratis-chronicle-read-model-specifications/SKILL.md +14 -3
- package/package/corpus/skills/cratis-chronicle-read-model-specifications/references/view-lifecycle-checks.md +6 -3
- package/package/corpus/skills/cratis-code-review/SKILL.md +10 -7
- package/package/corpus/skills/cratis-screenplay-command-surface/references/generated-values-and-responses.md +5 -1
- package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/chronicle-verification.md +5 -3
- package/package/corpus/skills/cratis-specifications-csharp/SKILL.md +20 -14
- package/package/corpus/skills/cratis-specifications-csharp/references/application-scenarios.md +20 -19
- package/package/corpus/skills/cratis-specifications-csharp/references/running-specs.md +32 -1
- package/package/corpus/skills/cratis-specifications-csharp/references/shared-lifecycle.md +32 -13
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +1 -1
- package/package.json +1 -1
|
@@ -10,8 +10,10 @@ metadata:
|
|
|
10
10
|
|
|
11
11
|
Start a pure decision with a plain method call: `Handle()`,
|
|
12
12
|
`Handle(providedValue)`, reducer logic or a reactor's decision needs no host,
|
|
13
|
-
services or harness
|
|
14
|
-
|
|
13
|
+
services or harness, including direct validator calls with supplied read-model state.
|
|
14
|
+
Add scenarios only for pipeline/authorization wiring, constraints, declarative
|
|
15
|
+
mapping or application-owned race policies; follow the
|
|
16
|
+
[scenario selection and cost rule](../../rules/specs.scenarios.csharp.md). The scenario family
|
|
15
17
|
exercises the real Arc and Chronicle code paths in-process — no HTTP, no fixture,
|
|
16
18
|
no server.
|
|
17
19
|
|
|
@@ -67,7 +69,8 @@ repository before claiming support for another version.
|
|
|
67
69
|
|
|
68
70
|
When the slice has a contract — a `.play` slice with its `specification`
|
|
69
71
|
blocks, or an agreed outline — its specifications are the **minimum list**: each
|
|
70
|
-
|
|
72
|
+
gets concrete assertions. Decision outcomes use focused classes; declarative
|
|
73
|
+
read-model mappings share one class per model with many read-only facts. Steps 3–7 then add what
|
|
71
74
|
the code reveals (each validator rule, each constraint). A rule found in the code
|
|
72
75
|
with no contract specification is a proposal for the contract (the `.play` model when one covers the slice, otherwise the agreed outline), not silent coverage:
|
|
73
76
|
list it in the report and, where a model exists, route it to
|
|
@@ -106,15 +109,16 @@ A behavior covering several subjects groups under
|
|
|
106
109
|
|
|
107
110
|
Specify a pure decision with the plain `Specification` base first. A direct
|
|
108
111
|
`Handle()` call does not run validation, authorization, `Provide()` or operations;
|
|
109
|
-
|
|
112
|
+
add a scenario only where that wiring adds proof. Keep shared lifecycle enabled
|
|
113
|
+
and measure scenario cost as described in the linked rule.
|
|
110
114
|
|
|
111
115
|
| Slice type | Scenario | Skill |
|
|
112
116
|
| --- | --- | --- |
|
|
113
|
-
| Pure command decision, reducer logic or reactor decision | Plain method call with `Specification` (default) | `cratis-specifications-csharp` |
|
|
117
|
+
| Pure command/validator decision, reducer logic or reactor decision | Plain method call with `Specification` and supplied read-model state (default) | `cratis-specifications-csharp` |
|
|
114
118
|
| State Change — command pipeline and appended events | `CommandScenario<TCommand>` | this one |
|
|
115
119
|
| Append semantics, a constraint | `EventScenario` | `cratis-chronicle-event-specifications` |
|
|
116
120
|
| Query pipeline — arguments, authorization, validation, interceptors | `QueryScenario<TReadModel>` | [query and decision scenarios](references/query-and-decision-scenarios.md) |
|
|
117
|
-
| State View —
|
|
121
|
+
| State View — declarative mapping or reducer wiring | One `ReadModelScenario<TReadModel>` class per read model, many assertions on shared setup | `cratis-chronicle-read-model-specifications` |
|
|
118
122
|
| Automation or Translation — a reactor | `ReactorScenario<TReactor>` | `cratis-specifications-csharp` |
|
|
119
123
|
| A host, transport, or real-infrastructure boundary | Out-of-process integration | `cratis-specifications-csharp` |
|
|
120
124
|
|
|
@@ -131,9 +135,11 @@ exception diagnostics, synchronous handler throws and UTC context defaults.
|
|
|
131
135
|
|
|
132
136
|
One specification class for **each** of:
|
|
133
137
|
|
|
134
|
-
1. **The happy path** —
|
|
135
|
-
|
|
136
|
-
|
|
138
|
+
1. **The happy path** — a plain call returns the expected event; add pipeline
|
|
139
|
+
coverage only for behavior that call cannot prove.
|
|
140
|
+
2. **Each validation failure** — instantiate `CommandValidator` or
|
|
141
|
+
`ConceptValidator` with the required state and validate directly. Use a
|
|
142
|
+
scenario only to prove pipeline wiring.
|
|
137
143
|
3. **Each business-rule rejection** — one `and_` class per condition in
|
|
138
144
|
`Handle()` that inspects a read model.
|
|
139
145
|
4. **Each constraint violation** — one class per constraint, written with
|
|
@@ -194,24 +200,26 @@ _scenario.Given.ForEventSource(_cartId).Events(new ItemAddedToCart(itemId));
|
|
|
194
200
|
_scenario.Given.ForEventSource(_cartId).ReadModel(new CartSummary { ItemCount = 3 });
|
|
195
201
|
```
|
|
196
202
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
203
|
+
Supply read-model state for a business decision. Seed events only when the
|
|
204
|
+
history itself matters, such as projection mapping or append-time uniqueness;
|
|
205
|
+
do not replay a projection merely to feed a pure command decision.
|
|
200
206
|
|
|
201
207
|
Both builder methods return `void`; there is nothing to await.
|
|
202
208
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
209
|
+
Read protection is invisible to application spec authors. Never configure modes,
|
|
210
|
+
call `UseDecisionReads`, seed events solely for infrastructure, or re-prove
|
|
211
|
+
the platform concurrency/guard matrix. Keep one cheap assembly-level
|
|
212
|
+
`DecisionReadAdmissions.ShouldAdmitDecisionReadsIn(assembly)` spec for the
|
|
213
|
+
application's own model/projection shapes: its only decision-read spec obligation.
|
|
214
|
+
If the harness cannot accept required state, report the upstream gap; never weaken
|
|
215
|
+
production guards for test speed. Read
|
|
216
|
+
[query and decision scenarios](references/query-and-decision-scenarios.md) for
|
|
217
|
+
query pipelines and application-owned race policies.
|
|
210
218
|
|
|
211
219
|
Validator and `Provide()` dependencies are registered in `_scenario.Services`;
|
|
212
220
|
the concrete validator itself is discovered automatically.
|
|
213
221
|
|
|
214
|
-
## Step 6 — Assert twice on
|
|
222
|
+
## Step 6 — Assert twice on pipeline validation failures
|
|
215
223
|
|
|
216
224
|
```csharp
|
|
217
225
|
[Fact] void should_not_succeed() => _result.ShouldNotBeSuccessful();
|
|
@@ -219,7 +227,9 @@ the concrete validator itself is discovered automatically.
|
|
|
219
227
|
```
|
|
220
228
|
|
|
221
229
|
`ShouldNotBeSuccessful()` alone cannot distinguish a validation rejection from an
|
|
222
|
-
unhandled exception, so both facts are required
|
|
230
|
+
unhandled exception, so both facts are required for pipeline validation specs.
|
|
231
|
+
For direct validator calls, assert the validation result and the specific rule.
|
|
232
|
+
**Do not assert on a message
|
|
223
233
|
string by default** — it is presentation text; assert one only when that exact
|
|
224
234
|
text is the specified behavior, and name that requirement in the fact. A `.play`
|
|
225
235
|
specification may pin the message (`then error "<message>"`); prefer pinning the
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
## Contents
|
|
4
4
|
|
|
5
5
|
- Query pipeline
|
|
6
|
-
-
|
|
6
|
+
- Application-owned race policies
|
|
7
7
|
- Sources
|
|
8
8
|
|
|
9
9
|
<!-- Copyright (c) Cratis. All rights reserved. -->
|
|
@@ -47,8 +47,10 @@ arbitrary stores.
|
|
|
47
47
|
Requires Arc 22.87.0 and Chronicle 19.54.0 for scenario `IReadModels.Observe<T>(filter)` snapshots from given events or pinned models,
|
|
48
48
|
including new emissions after scenario command appends. Pins need a readable key
|
|
49
49
|
or throw `PinnedReadModelCannotBeObserved`.
|
|
50
|
-
Requires Arc 22.91.1 and Chronicle 19.59.1 for
|
|
51
|
-
observe
|
|
50
|
+
Requires Arc 22.91.1 and Chronicle 19.59.1 for children, joins and reducers to
|
|
51
|
+
observe through scenario-owned storage (the initial Arc package was not published).
|
|
52
|
+
Check both package versions; upgrade or report a harness gap rather than configuring
|
|
53
|
+
decision-read modes in application specs.
|
|
52
54
|
|
|
53
55
|
For a query with `by`, `filter` or `scoped to`, seed instances for two keys, two filter values
|
|
54
56
|
or two tenants with distinct callers, as applicable, and assert that each call returns only its
|
|
@@ -65,50 +67,52 @@ execution runs the query through Arc's hosted query pipeline and establishes con
|
|
|
65
67
|
before `Provide`/`Handle` on the command path. A direct static query call does not
|
|
66
68
|
cover those pipeline hooks.
|
|
67
69
|
|
|
68
|
-
##
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
`
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
EventScenario
|
|
70
|
+
## Application-owned race policies
|
|
71
|
+
|
|
72
|
+
Start with a direct decision call supplied with read-model state. Follow the
|
|
73
|
+
[scenario rule](../../../rules/specs.scenarios.csharp.md): application authors do
|
|
74
|
+
not select read-protection modes, call `UseDecisionReads`, seed events only to
|
|
75
|
+
satisfy infrastructure, or prove the platform concurrency, conflict-refusal or
|
|
76
|
+
isolation matrix. Arc/Chronicle specs own it. The application's only decision-read
|
|
77
|
+
spec obligation is one cheap assembly-level check of its own model/projection
|
|
78
|
+
shapes, not one scenario per decision:
|
|
79
|
+
|
|
80
|
+
```csharp
|
|
81
|
+
DecisionReadAdmissions.ShouldAdmitDecisionReadsIn(assembly);
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
This API is in `Cratis.Arc.Chronicle.Testing.Commands`; it discovers declared reads
|
|
85
|
+
and checks admission without executing commands or running Chronicle. Keep the
|
|
86
|
+
spec's discovered projections representative of production; spec-only competing
|
|
87
|
+
definitions can make a model ambiguous. Explicit `IDecisionReads.Get` calls inside
|
|
88
|
+
method bodies are not statically discovered. If the harness cannot accept
|
|
89
|
+
required state for a business decision, report the upstream gap; never weaken
|
|
90
|
+
production guards or invent guard doubles.
|
|
91
|
+
|
|
92
|
+
Add a `CommandScenario<TCommand>` only when the application owns a race policy:
|
|
93
|
+
for example, two callers reserving the last seat must produce one reservation
|
|
94
|
+
and the specified rejection or retry outcome. Name that business contract and
|
|
95
|
+
assert it, rather than repeating the platform's generic stale-read tests.
|
|
96
|
+
Use event history only when it is part of the domain example.
|
|
97
|
+
|
|
98
|
+
For an application-owned race/retry policy only, `AppendConcurrently(id, events...)`
|
|
99
|
+
(or its routed overload) can supply controlled interference. It is not required
|
|
100
|
+
for every guarded decision. Requires Arc 22.92.0 without explicit decision-read
|
|
101
|
+
setup; older limitations are upgrade/report concerns, not application setup
|
|
102
|
+
instructions. A competing append alone proves no policy: assert the intended
|
|
103
|
+
business outcome and ensure the decision would otherwise append.
|
|
104
|
+
`ShouldHaveCompletedStream(ClosedStreamScope)` can assert an application-owned
|
|
105
|
+
completion outcome at the exact source and route. These APIs are in
|
|
106
|
+
`Cratis.Arc.Chronicle.Testing.Commands`.
|
|
107
|
+
|
|
108
|
+
The Chronicle-backed `CommandScenario` discovers constraints automatically.
|
|
109
|
+
Assert domain constraint refusals instead of disabling them; use `EventScenario`
|
|
110
|
+
for append-time uniqueness examples. Do not subclass or substitute its engine.
|
|
111
|
+
Provider boundaries remain separate: state fixtures are not a MongoDB substitute.
|
|
108
112
|
|
|
109
113
|
## Sources
|
|
110
114
|
|
|
111
115
|
- [Query scenarios](https://github.com/Cratis/Arc/blob/main/Documentation/backend/csharp/testing/query-scenario.md)
|
|
112
116
|
- [Stream decisions and routed specs](https://github.com/Cratis/Arc/blob/main/Documentation/backend/csharp/chronicle/commands/stream-decisions.md)
|
|
113
117
|
- [Decision-mode extension](https://github.com/Cratis/Arc/blob/main/Source/DotNET/Chronicle.Testing/Commands/CommandScenarioChronicleExtensions.cs)
|
|
114
|
-
- [
|
|
118
|
+
- [Application-shape admission assertion](https://github.com/Cratis/Arc/blob/main/Source/DotNET/Chronicle.Testing/Commands/DecisionReadAdmissions.cs)
|
|
@@ -274,6 +274,11 @@ Components guidance, not to this skill.
|
|
|
274
274
|
|
|
275
275
|
## Verify
|
|
276
276
|
|
|
277
|
+
Start pure `Handle()` and validator decisions with direct calls and supplied
|
|
278
|
+
read-model state. Add scenarios only for pipeline/authorization wiring,
|
|
279
|
+
constraints or application-owned race policies, not read-protection plumbing;
|
|
280
|
+
follow the [scenario selection and cost rule](../../rules/specs.scenarios.csharp.md).
|
|
281
|
+
|
|
277
282
|
- The command is a `record`, carries `[Command]`, and declares a public instance
|
|
278
283
|
`Handle`.
|
|
279
284
|
- The return shape matches what the command is supposed to do, and any
|
|
@@ -175,20 +175,22 @@ source id/type and stream route; reactor tuples/collections cannot mix it with e
|
|
|
175
175
|
|
|
176
176
|
## Decision specifications
|
|
177
177
|
|
|
178
|
-
`
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
178
|
+
Call `Handle()` and validators directly with read-model state for pure business
|
|
179
|
+
decisions. Follow the [scenario rule](../../../rules/specs.scenarios.csharp.md):
|
|
180
|
+
read-protection plumbing is invisible to application spec authors. They never
|
|
181
|
+
call `UseDecisionReads`, configure modes, seed events solely for infrastructure,
|
|
182
|
+
or re-prove the platform concurrency, conflict-refusal or isolation matrix;
|
|
183
|
+
Arc/Chronicle specs own it. The application's only decision-read spec obligation
|
|
184
|
+
is one cheap assembly-level shape-admission spec from that rule.
|
|
185
|
+
Never weaken production guards for test speed. Report a harness state-setup gap
|
|
186
|
+
upstream instead of working around it in application specs.
|
|
187
|
+
|
|
188
|
+
Add scenarios for pipeline/authorization wiring, constraints or an application-owned
|
|
189
|
+
race policy. Name the domain outcome (for example, one successful reservation and
|
|
190
|
+
one rejection), not the generic guard behavior. Read
|
|
191
|
+
[query and decision scenarios](../../cratis-application-slice-specifications/references/query-and-decision-scenarios.md)
|
|
192
|
+
for controlled interference and completion assertions. Keep shared lifecycle on
|
|
193
|
+
and measure the added cost.
|
|
192
194
|
|
|
193
195
|
## Sources
|
|
194
196
|
|
|
@@ -98,18 +98,16 @@ use an appropriate constraint or explicit concurrency scope for them.
|
|
|
98
98
|
|
|
99
99
|
## Specify the collision
|
|
100
100
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
Run `dotnet build -c Debug` and the affected specification project with
|
|
115
|
-
`dotnet test`; all collision and empty-source facts must pass.
|
|
101
|
+
The generated-value collision guard and its route, append and rollback matrix
|
|
102
|
+
belong in Arc/Chronicle specs, not every application. Follow the
|
|
103
|
+
[scenario rule](../../../rules/specs.scenarios.csharp.md): application authors
|
|
104
|
+
supply state and assert business decisions without configuring decision reads
|
|
105
|
+
or seeding events solely to satisfy infrastructure.
|
|
106
|
+
|
|
107
|
+
Add a scenario only for an application-owned collision/retry policy or generated
|
|
108
|
+
parameter pipeline wiring that a direct call cannot prove. `PinGeneratedValue(name, id)`
|
|
109
|
+
can make that domain example deterministic; assert its specified outcome, not
|
|
110
|
+
the platform guard matrix. If a harness rejects the state setup (for example
|
|
111
|
+
`GeneratedIdentifierCollisionRequiresDecisionReads`), report the upstream gap
|
|
112
|
+
rather than calling compatibility switches or weakening production guards.
|
|
113
|
+
Build the affected project and run its specifications with the project runner.
|
|
@@ -266,15 +266,19 @@ authorization and camelCase member paths are separate contracts.
|
|
|
266
266
|
|
|
267
267
|
## Step 6 — Specify the rejection
|
|
268
268
|
|
|
269
|
-
Every rule gets a specification
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
(
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
269
|
+
Every rule gets a failure specification: instantiate the validator with its
|
|
270
|
+
read-model state and validate directly, asserting the specific rejection. Add
|
|
271
|
+
`CommandScenario<TCommand>` only for pipeline/authorization wiring, constraints
|
|
272
|
+
or an application-owned race policy. Follow the
|
|
273
|
+
[scenario rule](../../rules/specs.scenarios.csharp.md): application specs never
|
|
274
|
+
configure read-protection modes, call `UseDecisionReads`, seed events solely for
|
|
275
|
+
infrastructure, or re-prove platform guards. Keep the single cheap assembly-level
|
|
276
|
+
application-shape admission spec specified by that rule; it is the application's
|
|
277
|
+
only decision-read spec obligation. Report harness gaps upstream; never weaken
|
|
278
|
+
production guards for speed.
|
|
279
|
+
|
|
280
|
+
For a pipeline validation rejection, assert **both** that the command did not
|
|
281
|
+
succeed and that it failed *as a validation*:
|
|
278
282
|
|
|
279
283
|
```csharp
|
|
280
284
|
[Fact] void should_not_succeed() => _result.ShouldNotBeSuccessful();
|
|
@@ -309,6 +313,8 @@ the fact. See
|
|
|
309
313
|
|
|
310
314
|
`dotnet build` in Debug and in Release, zero warnings and zero errors — the
|
|
311
315
|
analyzers above are how `ARC0005`, `ARC0006` and `ARC0013` surface. Then
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
316
|
+
run the specification project using its runner, with a direct validation
|
|
317
|
+
specification per rule and focused pipeline specs where wiring matters. Pipeline
|
|
318
|
+
validation specs assert both `ShouldNotBeSuccessful()` and
|
|
319
|
+
`ShouldHaveValidationErrors()`. A rule with no red-first specification has not
|
|
320
|
+
been shown to reject anything.
|
|
@@ -87,8 +87,12 @@ NativeAOT support for the unrelated dynamic validator opt-in.
|
|
|
87
87
|
|
|
88
88
|
## Specify the boundary
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
90
|
+
In application specs, call the validator directly with supplied read-model state
|
|
91
|
+
and assert its business decision. Keep the one cheap assembly-level application-shape
|
|
92
|
+
admission spec in [specs.scenarios.csharp.md](../../../rules/specs.scenarios.csharp.md).
|
|
93
|
+
|
|
94
|
+
Arc/Chronicle specs own the construction/guard matrix: fresh instances, callback
|
|
95
|
+
failures, refused DI graphs, cleanup, key matching and repeated execution. Do not
|
|
96
|
+
re-prove that matrix per application validator. A focused application pipeline
|
|
97
|
+
spec may prove its own registration/wiring; advisory Validate success alone is
|
|
98
|
+
not proof that Execute commits.
|
|
@@ -188,12 +188,16 @@ deciding writer is guarded or the rule is a constraint.
|
|
|
188
188
|
|
|
189
189
|
## Verify
|
|
190
190
|
|
|
191
|
-
-
|
|
192
|
-
|
|
193
|
-
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
-
|
|
191
|
+
- Review production enrollment in the intended store, namespace and stream;
|
|
192
|
+
surface refusal and never replace it with an unprotected read. One owner completes.
|
|
193
|
+
- Application specs call `Handle()` or the validator directly with supplied state.
|
|
194
|
+
Their only decision-read spec obligation is one cheap assembly-level
|
|
195
|
+
`DecisionReadAdmissions.ShouldAdmitDecisionReadsIn(assembly)` check of the
|
|
196
|
+
application's own model/projection shapes; see the
|
|
197
|
+
[scenario rule](../../rules/specs.scenarios.csharp.md).
|
|
198
|
+
- Arc/Chronicle specs alone prove platform conflict refusal, relevant/irrelevant
|
|
199
|
+
changes, absence guards, empty checked appends, isolation and commit lifecycle.
|
|
200
|
+
Their real-client/kernel integration proves the boundary; a default
|
|
199
201
|
`EventScenario` scope strategy returning `None` is not concurrency evidence.
|
|
202
|
+
- An application-owned race/retry policy may justify a focused scenario, not
|
|
203
|
+
repetition of that matrix. Never weaken production guards for spec speed.
|
package/package/corpus/skills/cratis-chronicle-decision-reads/references/admission-and-ownership.md
CHANGED
|
@@ -28,8 +28,12 @@ an adapter for arbitrary read-model storage:
|
|
|
28
28
|
Whole-source key admission supports string/Guid schemas, with canonical lowercase
|
|
29
29
|
D-form Guid source ids assumed. A renamed or custom-converted key is not made
|
|
30
30
|
safe by a cast in the caller. Runtime definition comparison is a diagnostic, not
|
|
31
|
-
proof of equality with an executing projection.
|
|
32
|
-
|
|
31
|
+
proof of equality with an executing projection. Arc/Chronicle own kernel-pair
|
|
32
|
+
integration and the platform guard matrix. Application specs have just one cheap
|
|
33
|
+
assembly-level shape-admission check,
|
|
34
|
+
`DecisionReadAdmissions.ShouldAdmitDecisionReadsIn(assembly)`; see the
|
|
35
|
+
[scenario rule](../../../rules/specs.scenarios.csharp.md). It checks the
|
|
36
|
+
application's own discovered models/projections without running Chronicle.
|
|
33
37
|
|
|
34
38
|
Do not silently replace a refused decision read with a materialized sink read.
|
|
35
39
|
Redesign the decision model as a focused admitted projection only when the
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
- Arc traps
|
|
13
13
|
- Chronicle-only traps
|
|
14
14
|
- Roll out with Measure
|
|
15
|
-
-
|
|
15
|
+
- Specify the business decision
|
|
16
16
|
- Costs
|
|
17
17
|
- Checklist for generated code
|
|
18
18
|
|
|
@@ -82,7 +82,7 @@ published scenario catalogue.
|
|
|
82
82
|
of the same source in one command are refused.
|
|
83
83
|
11. **Moving an existing app to `On`** (S12): `Measure` first.
|
|
84
84
|
12. **A command failed under protection** (S13): the [refusals](#refusals).
|
|
85
|
-
13. **Prove it** (S14): [
|
|
85
|
+
13. **Prove it** (S14): [specify the business decision](#specify-the-business-decision).
|
|
86
86
|
|
|
87
87
|
## The matrix
|
|
88
88
|
|
|
@@ -256,7 +256,7 @@ return `Commit()` last), `ReadOfSourceWithStagedEvents`, `ExplicitScopeDoesNotCo
|
|
|
256
256
|
| Injected `IEventLog.Append` in `Handle` | immediate write that survives a conflict rollback | return events |
|
|
257
257
|
| Aggregate `Commit()` whose result is ignored, or `Failed()` without `Commit()` | staged events still commit | return `await aggregate.Commit()` |
|
|
258
258
|
| `[Unprotected]` command taking `DecisionRead<T>` | resolves to an unguarded read | remove `[Unprotected]` |
|
|
259
|
-
|
|
|
259
|
+
| Per-decision specs rebuild the platform guard matrix | repeated infrastructure proof, not business coverage | [specify the business decision](#specify-the-business-decision) |
|
|
260
260
|
|
|
261
261
|
## Chronicle-only traps
|
|
262
262
|
|
|
@@ -304,31 +304,24 @@ then set `On` per project. Behaviour for callers does not change under `Measure`
|
|
|
304
304
|
or annotate `[Unprotected("why")]`. Under `On`, `ARCCHR0011` no longer applies;
|
|
305
305
|
fix `ARCCHR0024`, `0028` and `0033`.
|
|
306
306
|
|
|
307
|
-
##
|
|
308
|
-
|
|
309
|
-
`
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
result.ShouldHaveValidationErrorBecauseOf(ValidationResultReason.ConcurrencyViolation);
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
There is no `scenario.AppendConditions`. A pure decision test builds the command
|
|
329
|
-
and the validator with a hand-made read model. Chronicle-direct code asserts
|
|
330
|
-
`unitOfWork.GetAppendConditions()`. A default `EventScenario` scope strategy
|
|
331
|
-
returning `None` is not concurrency evidence.
|
|
307
|
+
## Specify the business decision
|
|
308
|
+
|
|
309
|
+
Start with a plain `Handle()` or validator call supplied with read-model state.
|
|
310
|
+
Follow the [scenario rule](../../../rules/specs.scenarios.csharp.md): read-protection
|
|
311
|
+
plumbing is invisible to application spec authors. They never configure modes,
|
|
312
|
+
call `UseDecisionReads`, seed events solely for infrastructure or re-prove platform
|
|
313
|
+
concurrency, conflict-refusal or isolation guards. Arc/Chronicle specs own that
|
|
314
|
+
matrix. The application's only decision-read spec obligation is one cheap
|
|
315
|
+
assembly-level `DecisionReadAdmissions.ShouldAdmitDecisionReadsIn(assembly)`
|
|
316
|
+
check of its own models/projections, not per-decision scenarios. Production
|
|
317
|
+
protection stays unchanged regardless of spec cost.
|
|
318
|
+
|
|
319
|
+
A scenario is justified for an application-owned race policy: for example, two
|
|
320
|
+
borrowers competing for the last copy must yield one loan and the specified
|
|
321
|
+
rejection or retry. Assert that domain outcome, not the engine's generic append
|
|
322
|
+
conditions. See [query and decision scenarios](../../cratis-application-slice-specifications/references/query-and-decision-scenarios.md)
|
|
323
|
+
for controlled interference. If the harness cannot accept required state, report
|
|
324
|
+
the upstream gap rather than adding infrastructure setup to application specs.
|
|
332
325
|
|
|
333
326
|
## Costs
|
|
334
327
|
|
|
@@ -349,7 +342,8 @@ append. Decision reads exist in the .NET and Elixir clients.
|
|
|
349
342
|
an explicit scope, enrolled **before** the events are staged.
|
|
350
343
|
- The model is admitted (source-keyed projection or admitted reducer, `Id`).
|
|
351
344
|
- Cross-key rules append one event per source atomically, with distinct event types.
|
|
352
|
-
-
|
|
353
|
-
|
|
345
|
+
- Business decisions have direct `Handle()`/validator specs with supplied state;
|
|
346
|
+
one cheap assembly-level spec checks application-shape admission. Arc/Chronicle,
|
|
347
|
+
not application specs, interleave appends to prove the platform guard matrix.
|
|
354
348
|
- What stays unguarded (an unguarded writer's own decision, external state,
|
|
355
349
|
revisions, `[Unprotected]` reads, `Off` mode) is stated.
|
|
@@ -52,10 +52,11 @@ version. Never translate an assertion name from memory.
|
|
|
52
52
|
(`When`, or `EventLog.Append` without a `concurrencyScope`) can never report
|
|
53
53
|
`HasConcurrencyViolations`. Only an append that passes an explicit scope on
|
|
54
54
|
`scenario.EventLog.Append(...)` reaches the in-process validator at all — and
|
|
55
|
-
that is a spec of the scope you hand-built, not of the application's strategy.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
that is a spec of the scope you hand-built, not of the application's strategy. The platform concurrency/guard matrix belongs only in Arc/Chronicle specs,
|
|
56
|
+
with real-kernel integration where required. Application decisions use direct
|
|
57
|
+
`Handle()`/validator calls with supplied state plus the one cheap assembly-level
|
|
58
|
+
shape-admission spec in [specs.scenarios.csharp.md](../../rules/specs.scenarios.csharp.md).
|
|
59
|
+
A default scenario must not claim concurrency coverage — it would pass vacuously.
|
|
59
60
|
|
|
60
61
|
## Step 1 — Create the scenario
|
|
61
62
|
|
|
@@ -15,6 +15,11 @@ default, with the event and current state supplied explicitly (for a self model,
|
|
|
15
15
|
`Model.Reduce(@event, current)`). Add
|
|
16
16
|
`ReadModelScenario<TReadModel>` only where declarative projection behavior,
|
|
17
17
|
event dispatch, filtering, metadata or read-model wiring contribute proof.
|
|
18
|
+
Follow the [scenario selection and cost rule](../../rules/specs.scenarios.csharp.md):
|
|
19
|
+
use one scenario class per read model, many read-only assertions on one shared
|
|
20
|
+
setup, and keep shared lifecycle enabled. Do not create a class per property,
|
|
21
|
+
mapping attribute or lifecycle event. Measure scenario cost with TRX durations
|
|
22
|
+
using [running-specs.md](../cratis-specifications-csharp/references/running-specs.md).
|
|
18
23
|
|
|
19
24
|
For a read-model scenario specification the **`Given` *is* the act**. There
|
|
20
25
|
is no separate `When`: seeding the events is what makes the projection run.
|
|
@@ -69,7 +74,8 @@ version.
|
|
|
69
74
|
|
|
70
75
|
## Step 1 — Create the scenario
|
|
71
76
|
|
|
72
|
-
|
|
77
|
+
Create one scenario for the read model's specification class. Share setup among
|
|
78
|
+
its read-only facts, never across specification classes.
|
|
73
79
|
|
|
74
80
|
```csharp
|
|
75
81
|
// Default, empty initial state
|
|
@@ -214,7 +220,11 @@ public class and_two_items_are_priced : Specification
|
|
|
214
220
|
|
|
215
221
|
Wrap files in `#if DEBUG … #endif` only when they compile into the application
|
|
216
222
|
assembly, so specification code ships only in Debug. Dedicated spec projects
|
|
217
|
-
need no wrapper. Keep one outcome per `should_` fact
|
|
223
|
+
need no wrapper. Keep one outcome per `should_` fact, not one scenario class per
|
|
224
|
+
assertion. Apply the event sequence once; capture intermediate states in `Because`
|
|
225
|
+
for create/update/delete assertions so facts remain read-only. Capture values or
|
|
226
|
+
immutable copies if later events mutate the same instance. Multiple event-source
|
|
227
|
+
keys may share this setup for isolation and child-key assertions.
|
|
218
228
|
|
|
219
229
|
## Step 6 — Cover the read model, not just one event
|
|
220
230
|
|
|
@@ -224,7 +234,8 @@ One summation example proves one event. Take the inventory from the contract
|
|
|
224
234
|
(the `.play` read model and its specifications, or the agreed outline); without
|
|
225
235
|
one, derive it from the projection and say so. Then check each line:
|
|
226
236
|
|
|
227
|
-
- **Every property is asserted** in
|
|
237
|
+
- **Every property is asserted** in a read-only fact in the model's shared
|
|
238
|
+
scenario class; do not multiply scenario startup for each field.
|
|
228
239
|
- **Every subscribed event has a specification.** Reconcile three lists in both
|
|
229
240
|
directions: the contract's event types, the projection's actual subscriptions,
|
|
230
241
|
and the events your specifications seed. Report any event in one list missing
|
|
@@ -16,9 +16,12 @@ Martin Dilger and Nebulit GmbH's build-state-view (see `provenance.md`), with th
|
|
|
16
16
|
migrations and projection specification harness replaced by `ReadModelScenario<TReadModel>`.
|
|
17
17
|
|
|
18
18
|
Take the contract first (the `.play` read model, its projection and its specifications, or the
|
|
19
|
-
agreed outline).
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
agreed outline). Give each contract specification assertions using its example
|
|
20
|
+
values in **one shared scenario class per read model**, not a class per property
|
|
21
|
+
or lifecycle event. Capture intermediate values or immutable snapshots in `Because`
|
|
22
|
+
as the event sequence advances; facts only inspect them. Add the cases below only
|
|
23
|
+
where the contract states the behavior; an uncontracted rule found in the projection
|
|
24
|
+
is a proposal for the contract, not silent coverage.
|
|
22
25
|
|
|
23
26
|
## How to use this list
|
|
24
27
|
For each read model, list its properties and its events in a small table (property, events that
|