@cratis/pi 7.27.3 → 7.28.1
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/rules/reactors.md +30 -0
- package/package/corpus/rules/specs.scenarios.csharp.md +41 -0
- package/package/corpus/skills/cratis-application-slice-specifications/SKILL.md +13 -0
- package/package/corpus/skills/cratis-arc-command/SKILL.md +34 -11
- package/package/corpus/skills/cratis-arc-command/references/generated-values.md +166 -0
- package/package/corpus/skills/cratis-chronicle-reactor/SKILL.md +16 -1
- package/package/corpus/skills/cratis-chronicle-reactor/references/specifications.md +85 -0
- package/package/corpus/skills/cratis-fundamentals-concept/SKILL.md +13 -5
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/SKILL.md +3 -2
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/audit-format.md +2 -2
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/automation-patterns.md +4 -2
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/provenance.md +5 -3
- package/package/corpus/skills/cratis-screenplay-captures-and-reactions/SKILL.md +3 -2
- package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/invocation-identity.md +6 -5
- package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/specifying-triggers-and-clock.md +1 -1
- package/package/corpus/skills/cratis-screenplay-command-surface/SKILL.md +4 -4
- package/package/corpus/skills/cratis-screenplay-command-surface/references/context.md +6 -5
- package/package/corpus/skills/cratis-screenplay-command-surface/references/generated-values-and-responses.md +5 -5
- package/package/corpus/skills/cratis-screenplay-event-modeling/SKILL.md +4 -3
- package/package/corpus/skills/cratis-screenplay-event-modeling/references/parsed-not-runnable.md +4 -4
- package/package/corpus/skills/cratis-screenplay-legacy-extraction/references/generate-notes.md +6 -4
- package/package/corpus/skills/cratis-screenplay-model-authoring/SKILL.md +10 -7
- package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-tools.md +60 -10
- package/package/corpus/skills/cratis-screenplay-model-authoring/references/screen-authoring-workflow.md +6 -5
- package/package/corpus/skills/cratis-screenplay-model-authoring/verification.json +11 -1
- package/package/corpus/skills/cratis-screenplay-model-review/SKILL.md +29 -5
- package/package/corpus/skills/cratis-screenplay-model-review/references/anti-patterns.md +1 -1
- package/package/corpus/skills/cratis-screenplay-read-surface/references/guarded-actions.md +2 -2
- package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/SKILL.md +12 -11
- package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/gap-fill-handoff.md +3 -2
- package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/spec-forms-by-mode.md +4 -4
- package/package/corpus/skills/cratis-screenplay-slice-design/references/worked-example.md +1 -1
- package/package/corpus/skills/cratis-screenplay-specifications/SKILL.md +2 -2
- package/package/corpus/skills/cratis-screenplay-specifications/references/examples-and-routes.md +1 -1
- package/package/corpus/skills/cratis-screenplay-streams-and-consistency/SKILL.md +3 -3
- package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/consistency-and-concurrency.md +2 -2
- package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/stream-patterns.md +1 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +6 -6
- package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet.md +1 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +1 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/doc-contradictions.md +1 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +4 -3
- package/package/corpus/skills/cratis-screenplay-toolchain/references/provenance.md +7 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +7 -6
- package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.json +364 -28
- package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.version +1 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/sources-and-streams.md +1 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/traps.md +4 -4
- package/package/corpus/skills/cratis-screenplay-toolchain/references/verdicts.md +4 -4
- package/package/corpus/skills/cratis-screenplay-toolchain/references/versions.md +23 -13
- package/package/corpus/skills/cratis-screenplay-toolchain/verification.json +1 -1
- package/package/corpus/skills/cratis-screenplay-ui-composition/references/screen-composition-contract.md +6 -6
- package/package/corpus/skills/cratis-specifications-csharp/SKILL.md +34 -0
- package/package/corpus/skills/cratis-specifications-csharp/references/application-scenarios.md +121 -4
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +18 -8
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +5 -3
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/case-tables-and-whole-numbers.md +127 -0
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/verification.json +5 -1
- package/package.json +1 -1
|
@@ -278,4 +278,34 @@ async Task Because() => await _scenario.Given.ForEventSource(_id).Events(new Inv
|
|
|
278
278
|
[Fact] async Task should_notify_about_the_issued_invoice() => await _notifications.Received(1).Notify(Arg.Is<string>(_ => _.Contains("INV-1001")));
|
|
279
279
|
```
|
|
280
280
|
|
|
281
|
+
### Read-model dependencies in scenarios — Chronicle 19.46.0+
|
|
282
|
+
|
|
283
|
+
`ReactorScenario<TReactor>` does **not** build read models from `Given` events,
|
|
284
|
+
including `[Passive]` models. Seed the handler's read-model parameter explicitly
|
|
285
|
+
before firing the trigger:
|
|
286
|
+
|
|
287
|
+
```csharp
|
|
288
|
+
void Establish() => _scenario.Given.ForEventSourceId(_id).ReadModel(_order);
|
|
289
|
+
async Task Because() => await _scenario.Given.ForEventSource(_id).Events(_orderPlaced);
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
In a separate absence specification, replace the seeding with
|
|
293
|
+
`_scenario.Given.ForEventSourceId(_id).NoReadModel<Order>()` to deliberately pass
|
|
294
|
+
`null` to an `Order?` parameter. Without either setup, resolution to `null` throws
|
|
295
|
+
`ReadModelNotSeededForReactorScenario` (`Cratis.Chronicle.Testing.Reactors`), even
|
|
296
|
+
for a nullable parameter. Its message names the type and missing key, suggests
|
|
297
|
+
both setup methods, and lists other seeded keys for that type when any exist.
|
|
298
|
+
Use the key from `ICanResolveReadModelKey.Resolve` for seeding or absence when
|
|
299
|
+
implemented, not the triggering source id. `NoReadModel<T>()` does not remove a
|
|
300
|
+
seeded instance. This guard applies to `EventStoreForTesting`, not an explicitly
|
|
301
|
+
supplied store of another type; production read-model resolution is unchanged.
|
|
302
|
+
|
|
303
|
+
Also in Chronicle 19.46.0+, `Events(...)` surfaces a synchronously throwing
|
|
304
|
+
handler's own exception, preserving its stack, rather than the reflection
|
|
305
|
+
`TargetInvocationException`. Capture it with `Catch.Exception` and assert the
|
|
306
|
+
handler's exception type. `EventContext.From(...)` now defaults an omitted
|
|
307
|
+
`occurred` to `DateTimeOffset.UtcNow`, not local `Now`; scenario contexts,
|
|
308
|
+
`EventContext.Empty` and `EmptyWithEventSourceId(...)` use that helper. An
|
|
309
|
+
explicit occurrence time is preserved, not normalized to UTC.
|
|
310
|
+
|
|
281
311
|
For reactors that return side-effect events, assert the resulting appends through the scenario's event store; for non-event side effects, assert on the mocked services (as above). See [specs.scenarios.csharp.md](./specs.scenarios.csharp.md) for the full `*Scenario` family.
|
|
@@ -160,6 +160,47 @@ async Task Because() => await _scenario.Given.ForEventSource(_id).Events(new Aut
|
|
|
160
160
|
[Fact] async Task should_notify() => await _service.Received(1).Notify("Jane Austen");
|
|
161
161
|
```
|
|
162
162
|
|
|
163
|
+
#### Read-model setup — Chronicle 19.46.0+
|
|
164
|
+
|
|
165
|
+
In a class-based `ReactorScenario<TReactor>`, `Given` events invoke the reactor;
|
|
166
|
+
they **do not materialize read models**, even `[Passive]` ones. For each
|
|
167
|
+
read-model handler parameter, choose one setup before `Because()`:
|
|
168
|
+
|
|
169
|
+
```csharp
|
|
170
|
+
// Present-state specification: supply the instance the handler must receive.
|
|
171
|
+
void Establish() => _scenario.Given.ForEventSourceId(_id).ReadModel(_author);
|
|
172
|
+
|
|
173
|
+
// Separate absence specification: deliberately let an Author? parameter receive null.
|
|
174
|
+
void Establish() => _scenario.Given.ForEventSourceId(_id).NoReadModel<Author>();
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
These are alternatives in **separate specification classes**, not two
|
|
178
|
+
`Establish()` methods in one class. Both builders return
|
|
179
|
+
`ReactorSourceGivenBuilder<TReactor>` for chaining; neither setup is async.
|
|
180
|
+
Use the triggering event-source id by default, or the key returned by the
|
|
181
|
+
reactor's `ICanResolveReadModelKey.Resolve` when implemented. An absence
|
|
182
|
+
declaration is for that exact type and key and does not delete a seeded model.
|
|
183
|
+
|
|
184
|
+
If a recognized read-model parameter resolves to `null` without declared absence,
|
|
185
|
+
`Events(...)` throws `ReadModelNotSeededForReactorScenario` from
|
|
186
|
+
`Cratis.Chronicle.Testing.Reactors`, even if the parameter is nullable. The
|
|
187
|
+
message names the full type and missing key, explains `ReadModel(...)` and
|
|
188
|
+
`NoReadModel<T>()`, and lists seeded keys for that type when any exist. Fix the
|
|
189
|
+
fixture or its key; do not add `NoReadModel<T>()` just to silence missing setup.
|
|
190
|
+
The guard applies to `EventStoreForTesting`; it does not alter production
|
|
191
|
+
resolution or an explicitly supplied event store of another type.
|
|
192
|
+
|
|
193
|
+
**Handler failures:** in Chronicle 19.46.0+, a synchronous handler throw surfaces
|
|
194
|
+
its own exception, not `TargetInvocationException`, with its handler stack
|
|
195
|
+
preserved. Use `await Catch.Exception(() => _scenario.Given.ForEventSource(_id).Events(...))`
|
|
196
|
+
and assert the handler's exception type.
|
|
197
|
+
|
|
198
|
+
**Occurrence time:** in Chronicle 19.46.0+, `EventContext.From(...)` uses
|
|
199
|
+
`DateTimeOffset.UtcNow` when `occurred` is omitted (previously local `Now`).
|
|
200
|
+
`ReactorScenario` builds its contexts through this helper, as do
|
|
201
|
+
`EventContext.Empty` and `EmptyWithEventSourceId(...)`. Explicit occurrence times
|
|
202
|
+
keep their supplied offset; the positional constructor has no such default.
|
|
203
|
+
|
|
163
204
|
## Out-of-process Chronicle integration specs (advanced)
|
|
164
205
|
|
|
165
206
|
Reserve these for the host/transport boundary the scenario helpers can't reach. They test a complete slice — HTTP request → command → append → constraint → projection — against a real Chronicle store, and live under `when_<behavior>/` directly inside the slice folder (no `for_` folder; the "unit" is the whole slice).
|
|
@@ -30,6 +30,10 @@ This skill decides **when to add a scenario** and **what to cover**. The C# mech
|
|
|
30
30
|
|
|
31
31
|
> Re-verified at the versions above by **symbol and signature**: every type, attribute and member this skill names exists at that tag, and the public surface it describes is unchanged since the previous verification (Chronicle 16.45.x / Arc 22.10.4 — the Chronicle 16→18 client diff is converters, options and doc comments; no type was removed or renamed). Behavior claims were verified at the earlier tag unless a section says otherwise.
|
|
32
32
|
|
|
33
|
+
Reactor read-model setup and the `EventContext.From` UTC default below are
|
|
34
|
+
verified separately at **Chronicle 19.46.0**, the minimum version for that
|
|
35
|
+
guidance; see `cratis-chronicle-reactor/references/specifications.md` for sources.
|
|
36
|
+
|
|
33
37
|
`Cratis.Testing` is the meta-package that brings `Cratis.Arc.Testing` and
|
|
34
38
|
`Cratis.Arc.Chronicle.Testing` together. Reverify against the owning product
|
|
35
39
|
repository before claiming support for another version.
|
|
@@ -112,6 +116,15 @@ keep a scenario for that wiring and for appended-event behavior.
|
|
|
112
116
|
| Automation or Translation — a reactor | `ReactorScenario<TReactor>` | `cratis-specifications-csharp` |
|
|
113
117
|
| A host, transport, or real-infrastructure boundary | Out-of-process integration | `cratis-specifications-csharp` |
|
|
114
118
|
|
|
119
|
+
For a class-based reactor scenario on **Chronicle 19.46.0+**, explicitly seed
|
|
120
|
+
handler read-model parameters with `Given.ForEventSourceId(id).ReadModel(instance)`
|
|
121
|
+
or declare intentional absence with `.NoReadModel<T>()`. An unseeded model throws
|
|
122
|
+
`ReadModelNotSeededForReactorScenario` even if nullable; `Given` events do not
|
|
123
|
+
build read models, including passive ones. Use the reactor's resolved key, not
|
|
124
|
+
necessarily the trigger's source id. This is **not** the command-scenario event
|
|
125
|
+
seeding described in Step 5. Read `cratis-chronicle-reactor` for the setup examples,
|
|
126
|
+
exception diagnostics, synchronous handler throws and UTC context defaults.
|
|
127
|
+
|
|
115
128
|
## Step 3 — Cover every outcome of a State Change slice
|
|
116
129
|
|
|
117
130
|
One specification class for **each** of:
|
|
@@ -75,8 +75,9 @@ Rules the framework actually enforces:
|
|
|
75
75
|
operation collections, and `ARC0018` checks generated-invoker accessibility.
|
|
76
76
|
- Name the command as the action — `OpenDebitAccount`, not
|
|
77
77
|
`OpenDebitAccountCommand`.
|
|
78
|
-
- `Handle` parameters
|
|
79
|
-
than through a constructor.
|
|
78
|
+
- Unmarked `Handle` parameters resolve from `Provide()` or DI; ask for services
|
|
79
|
+
there rather than through a constructor. Server-owned new values use
|
|
80
|
+
`[GeneratedValue]` instead (below).
|
|
80
81
|
- Never inject `IEventLog` into `Handle` to append the command's own events —
|
|
81
82
|
`ARCCHR0007` warns, and it bypasses Arc's append pipeline. Express the append
|
|
82
83
|
through the return type.
|
|
@@ -137,8 +138,8 @@ Two consequences worth knowing before writing the first command:
|
|
|
137
138
|
the events in that same tuple are appended to. Returning more than one
|
|
138
139
|
unhandleable element throws `MultipleUnhandledTupleValues`. When the command
|
|
139
140
|
also returns an operation keyed by that id, have the caller supply the id
|
|
140
|
-
instead of
|
|
141
|
-
ownership key.
|
|
141
|
+
instead of generating a new value, so a retried request reuses the same
|
|
142
|
+
ownership key. A generated value alone does not provide idempotency.
|
|
142
143
|
- **Events never carry their own event source.** Cross-stream writes use
|
|
143
144
|
`EventForEventSourceId`; they are not expressed by a property on the event.
|
|
144
145
|
|
|
@@ -146,11 +147,8 @@ Two consequences worth knowing before writing the first command:
|
|
|
146
147
|
[Command]
|
|
147
148
|
public record Register<Thing>(<ConceptType> <Name>)
|
|
148
149
|
{
|
|
149
|
-
public (<ThingId>, <ThingRegistered>) Handle()
|
|
150
|
-
|
|
151
|
-
var id = <ThingId>.New();
|
|
152
|
-
return (id, new(<Name>));
|
|
153
|
-
}
|
|
150
|
+
public (<ThingId>, <ThingRegistered>) Handle([GeneratedValue("thing")] <ThingId> id) =>
|
|
151
|
+
(id, new(<Name>));
|
|
154
152
|
}
|
|
155
153
|
```
|
|
156
154
|
|
|
@@ -166,6 +164,28 @@ public record Transfer(<AccountId> From, <AccountId> To, <Money> Amount)
|
|
|
166
164
|
}
|
|
167
165
|
```
|
|
168
166
|
|
|
167
|
+
## Generate a server-owned new identifier
|
|
168
|
+
|
|
169
|
+
**Arc 22.66.0+**, verified at **v22.68.0**: the create-command example above
|
|
170
|
+
requires `<ThingId>` to implement `IGeneratable<ThingId>` with a static `New()`
|
|
171
|
+
strategy (Fundamentals 7.23.0+; see `cratis-fundamentals-concept`). Replace
|
|
172
|
+
`Guid.NewGuid()` or `<ThingId>.New()` inside `Handle()` with a generated parameter,
|
|
173
|
+
not a new request property. Return the id as the ordinary response or in the
|
|
174
|
+
id/event tuple so the caller receives it.
|
|
175
|
+
|
|
176
|
+
`[GeneratedValue]` is in `Cratis.Arc.Commands.ModelBound` and applies only to
|
|
177
|
+
parameters of a non-static command `Handle()`. Arc generates after `Provide()`
|
|
178
|
+
control results permit execution, validates the concept, then invokes `Handle`.
|
|
179
|
+
`Provide()` and DI cannot override it. Use a non-nullable self-generatable type,
|
|
180
|
+
not raw `Guid`; names default to the parameter name or an explicit attribute name
|
|
181
|
+
and are case-sensitive, non-empty and unique within the command.
|
|
182
|
+
|
|
183
|
+
Keep client-chosen ids/references as inputs and services/read models as ordinary
|
|
184
|
+
dependencies. A UUID is not a secret, token, authorization proof, idempotency key,
|
|
185
|
+
or a gapless/sequential invoice number. For validation failures, captures,
|
|
186
|
+
ARC0022–ARC0025, migration and the pinned-spec workflow, read
|
|
187
|
+
[generated values](references/generated-values.md).
|
|
188
|
+
|
|
169
189
|
## Where the event source id comes from
|
|
170
190
|
|
|
171
191
|
Chronicle resolves the command's event source id in this order:
|
|
@@ -330,8 +350,11 @@ Components guidance, not to this skill.
|
|
|
330
350
|
- The event source id resolves from exactly one place; `ARCCHR0002` is silent.
|
|
331
351
|
- `[Key]`, where used, is `Cratis.Chronicle.Keys.KeyAttribute`.
|
|
332
352
|
- No `IEventLog` is injected into `Handle`.
|
|
333
|
-
- Every value `Provide` returns is consumed by `Handle
|
|
334
|
-
-
|
|
353
|
+
- Every value `Provide` returns is consumed by an unmarked `Handle` parameter.
|
|
354
|
+
- Generated parameters follow [generated values](references/generated-values.md)
|
|
355
|
+
and are pinned before scenario execution (`cratis-specifications-csharp`).
|
|
356
|
+
- User-correctable rejections are validation results, never thrown exceptions;
|
|
357
|
+
`GeneratedValueRejected` instead signals a defective server generation strategy.
|
|
335
358
|
- Every secret or personal value is marked before it can reach the event log.
|
|
336
359
|
- `dotnet build` is clean in Debug and Release, with no suppressed `ARC*` or
|
|
337
360
|
`ARCCHR*` diagnostic left unjustified.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Server-generated Handle values
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Declare the value and command
|
|
6
|
+
- Resolution, validation and captures
|
|
7
|
+
- Analyzer diagnostics
|
|
8
|
+
- Migrate generation inside Handle
|
|
9
|
+
- Pin generated values in specifications
|
|
10
|
+
- Verified sources and release boundary
|
|
11
|
+
|
|
12
|
+
<!-- Copyright (c) Cratis. All rights reserved. -->
|
|
13
|
+
<!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
|
|
14
|
+
|
|
15
|
+
## Declare the value and command
|
|
16
|
+
|
|
17
|
+
Generated parameters arrived in Arc **22.66.0**, scenario pinning in **22.67.0**,
|
|
18
|
+
and analyzers in **22.68.0**. The examples and behavior here are verified at
|
|
19
|
+
**v22.68.0**, which pins Fundamentals **7.23.0**.
|
|
20
|
+
|
|
21
|
+
Use a concept for a server-owned new identifier. This standalone Arc example
|
|
22
|
+
allocates an id; it does not append an event or persist a cart:
|
|
23
|
+
|
|
24
|
+
```csharp
|
|
25
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
26
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
27
|
+
|
|
28
|
+
using Cratis.Arc.Commands.ModelBound;
|
|
29
|
+
using Cratis.Concepts;
|
|
30
|
+
|
|
31
|
+
namespace Shopping.Carts;
|
|
32
|
+
|
|
33
|
+
/// <summary>
|
|
34
|
+
/// Represents a cart identifier.
|
|
35
|
+
/// </summary>
|
|
36
|
+
/// <param name="Value">The underlying identifier.</param>
|
|
37
|
+
public record CartId(Guid Value) : ConceptAs<Guid>(Value), IGeneratable<CartId>
|
|
38
|
+
{
|
|
39
|
+
/// <summary>
|
|
40
|
+
/// Creates a new cart identifier.
|
|
41
|
+
/// </summary>
|
|
42
|
+
/// <returns>A new cart identifier.</returns>
|
|
43
|
+
public static CartId New() => new(GenerateValue.Uuid());
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/// <summary>
|
|
47
|
+
/// Allocates a server-owned cart identifier.
|
|
48
|
+
/// </summary>
|
|
49
|
+
[Command]
|
|
50
|
+
public record AllocateCartId
|
|
51
|
+
{
|
|
52
|
+
/// <summary>
|
|
53
|
+
/// Returns the allocated identifier to the caller.
|
|
54
|
+
/// </summary>
|
|
55
|
+
/// <param name="cartId">The server-generated identifier.</param>
|
|
56
|
+
/// <returns>The allocated identifier.</returns>
|
|
57
|
+
public CartId Handle([GeneratedValue("cart")] CartId cartId) => cartId;
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
For a Chronicle stream identity, derive `CartId` from `EventSourceId<Guid>`
|
|
62
|
+
instead; see `cratis-fundamentals-concept`. Return `(id, event)` to both append
|
|
63
|
+
and give the caller the new stream id, as in SKILL.md. An identifier is not an
|
|
64
|
+
event, and generation alone does not persist anything.
|
|
65
|
+
|
|
66
|
+
Keep existing/client-chosen identifiers and references on command properties.
|
|
67
|
+
Services and read models remain ordinary dependencies, not generated values.
|
|
68
|
+
UUID generation does not establish authorization, secrecy, idempotency, storage
|
|
69
|
+
freshness, or gapless/sequential numbering. Use the domain's authoritative
|
|
70
|
+
allocation mechanism for invoice numbers, not a random UUID strategy.
|
|
71
|
+
|
|
72
|
+
## Resolution, validation and captures
|
|
73
|
+
|
|
74
|
+
`GeneratedValueAttribute` targets parameters only. Use it on a command's public
|
|
75
|
+
instance `Handle()`, not a property, constructor or `Provide()` parameter.
|
|
76
|
+
The type must be non-nullable and implement `IGeneratable<TSelf>` for itself;
|
|
77
|
+
a raw `Guid`, nullable concept or by-reference parameter is invalid. Use domain
|
|
78
|
+
concepts; the runtime's type check is the self-generatable interface contract.
|
|
79
|
+
|
|
80
|
+
`[GeneratedValue]` uses the parameter name. `[GeneratedValue("cart")]` keeps the
|
|
81
|
+
pin/capture name stable across a parameter rename. Names are case-sensitive,
|
|
82
|
+
non-whitespace and unique within the command.
|
|
83
|
+
|
|
84
|
+
Arc first runs `Provide()` and checks its control results. Only if execution may
|
|
85
|
+
continue does it call the concept's `New()` strategy and validate the value before
|
|
86
|
+
invoking `Handle()`. Neither a provided value nor a DI registration overrides a
|
|
87
|
+
generated parameter. Unmarked parameters retain their normal resolution.
|
|
88
|
+
|
|
89
|
+
Discoverable concept validators run with the command's scoped provider and
|
|
90
|
+
cancellation token. Errors produce `GeneratedValueRejected`, an exception
|
|
91
|
+
outcome in `CommandResult`: a server-generation defect, not a request-validation
|
|
92
|
+
400. Warnings/information allow execution. Fix the strategy or invariant; do not
|
|
93
|
+
turn the defect into a user rejection or disable validation to make it pass.
|
|
94
|
+
|
|
95
|
+
Validated values enter `CommandContext.GeneratedValues` in parameter-resolution
|
|
96
|
+
order. Each capture has zero-based `Order`, `Name`, declared `Type` and `Value`;
|
|
97
|
+
`Get<CartId>("cart")` retrieves the latest matching capture. Rejected values are
|
|
98
|
+
not captured. A Handle parameter is not a request property and is not audited
|
|
99
|
+
as command input. Do not log or trace captures or validator failure text, which
|
|
100
|
+
can contain values. Returning a value or putting it in an event still follows the
|
|
101
|
+
ordinary response, event and compliance contracts.
|
|
102
|
+
|
|
103
|
+
## Analyzer diagnostics
|
|
104
|
+
|
|
105
|
+
Arc v22.68.0 reports these at compile time; none has a code fix. Runtime
|
|
106
|
+
handler-construction checks remain for declarations compiled without analyzers.
|
|
107
|
+
|
|
108
|
+
| Diagnostic | Severity | Fix |
|
|
109
|
+
| --- | --- | --- |
|
|
110
|
+
| ARC0022 | Error | Use a non-nullable type implementing `IGeneratable<TSelf>` for itself; no raw `Guid` or by-reference parameter. |
|
|
111
|
+
| ARC0023 | Error | Move the attribute to a non-static command `Handle()` parameter, not `Provide()`, a read model or controller. |
|
|
112
|
+
| ARC0024 | Error | Give each generated parameter a non-empty unique name; comparison is case-sensitive. |
|
|
113
|
+
| ARC0025 | Warning | Remove a redundant provided value of the generated type, or remove the attribute if `Provide()` should supply it. An unmarked parameter can still consume that provided type. |
|
|
114
|
+
|
|
115
|
+
## Migrate generation inside Handle
|
|
116
|
+
|
|
117
|
+
For `var id = new CartId(Guid.NewGuid());` or `var id = CartId.New();` in
|
|
118
|
+
`Handle()`, keep the request contract unchanged:
|
|
119
|
+
|
|
120
|
+
1. Make the concept implement `IGeneratable<CartId>` with static `New()` using
|
|
121
|
+
`GenerateValue.Uuid()` or `GenerateValue.UuidV7()`.
|
|
122
|
+
2. Replace the local allocation with `[GeneratedValue("cart")] CartId cartId`
|
|
123
|
+
on `Handle()`, then use that parameter in the existing return/operation shape.
|
|
124
|
+
3. Return the id if the caller needs it; a capture is not an automatic response.
|
|
125
|
+
4. Pin the concept by generated name in pipeline specifications. For a pure
|
|
126
|
+
direct-call specification, pass the known concept to `Handle()` yourself.
|
|
127
|
+
|
|
128
|
+
Do not migrate caller-owned inputs into server generation. A retried request
|
|
129
|
+
would otherwise allocate a different value; random generation is not an
|
|
130
|
+
idempotency mechanism. UUIDv7 reveals creation time and is not monotonic within
|
|
131
|
+
a millisecond; choose it for index locality only after checking storage ordering.
|
|
132
|
+
|
|
133
|
+
## Pin generated values in specifications
|
|
134
|
+
|
|
135
|
+
Use `cratis-specifications-csharp` and its `references/application-scenarios.md`
|
|
136
|
+
for the complete pinned example. `Cratis.Arc.Testing.Commands` supplies
|
|
137
|
+
`PinGeneratedValue(name, concept)`, `AllowGeneration()` and the `GeneratedValues`
|
|
138
|
+
capture helpers on `CommandScenario<TCommand>`.
|
|
139
|
+
|
|
140
|
+
Scenarios default to strict: an unpinned generated parameter yields
|
|
141
|
+
`GeneratedValueNotPinned` in the command result, not a throw from `Execute`.
|
|
142
|
+
Configure before execution. Nested pins use both generic arguments at the call
|
|
143
|
+
site: `PinGeneratedValue<TCommand, TOtherCommand>(name, concept)`.
|
|
144
|
+
|
|
145
|
+
## Verified sources and release boundary
|
|
146
|
+
|
|
147
|
+
Published guides:
|
|
148
|
+
|
|
149
|
+
- [Generated values](/arc/backend/csharp/commands/generated-values/)
|
|
150
|
+
- [Pin generated values in command specs](/arc/backend/csharp/testing/generated-values/)
|
|
151
|
+
- [Migrate generated identifiers](/arc/upgrading/generated-values/)
|
|
152
|
+
- Analyzer pages: [ARC0022](/arc/backend/csharp/code-analysis/arc0022/),
|
|
153
|
+
[ARC0023](/arc/backend/csharp/code-analysis/arc0023/),
|
|
154
|
+
[ARC0024](/arc/backend/csharp/code-analysis/arc0024/),
|
|
155
|
+
[ARC0025](/arc/backend/csharp/code-analysis/arc0025/).
|
|
156
|
+
|
|
157
|
+
Source at **Arc v22.68.0**: `Source/DotNET/Arc.Core/Commands/ModelBound/GeneratedValueAttribute.cs`,
|
|
158
|
+
`Commands/GeneratedValueParameters.cs`, `GeneratedValueFactories.cs`,
|
|
159
|
+
`CommandHandlerArgumentResolver.cs`, `GeneratedValueResolution.cs`;
|
|
160
|
+
`Source/DotNET/Arc.Core.CodeAnalysis/DiagnosticDescriptors.cs`; and
|
|
161
|
+
`Source/DotNET/Testing/Commands/CommandScenarioGeneratedValueExtensions.cs`.
|
|
162
|
+
|
|
163
|
+
This release has no freshness/collision guard, contextual clock/tenant/pattern
|
|
164
|
+
generation, or additional built-in strategies beyond Fundamentals' UUID/UUIDv7
|
|
165
|
+
helpers. Do not teach proposals as available APIs or invent Screenplay `generate`
|
|
166
|
+
syntax for this feature.
|
|
@@ -45,6 +45,11 @@ This skill is verified against these exact sources:
|
|
|
45
45
|
| `Cratis.Chronicle` | `18.3.0` | `Cratis.Chronicle.Reactors`, `Cratis.Chronicle.Reactors.SideEffects`, `Cratis.Chronicle.EventSequences`, `Cratis.Chronicle.Events` |
|
|
46
46
|
| `Cratis.Chronicle.CodeAnalysis` | `18.3.0` | `CHR0004`, `CHR0005`, `CHR0008`, `CHR0013`, `CHR0022`, `CHR0031`, `CHR0032` |
|
|
47
47
|
|
|
48
|
+
Scenario read-model seeding/absence, synchronous handler exception propagation,
|
|
49
|
+
and the `EventContext.From` UTC default are verified separately at **Chronicle
|
|
50
|
+
19.46.0**; they require **19.46.0+**. See the source paths in
|
|
51
|
+
[references/specifications.md](references/specifications.md).
|
|
52
|
+
|
|
48
53
|
Reverify product sources before claiming support for another version.
|
|
49
54
|
|
|
50
55
|
> **There is no `ReactorSideEffect` type.** It does not exist in Chronicle, in
|
|
@@ -363,7 +368,17 @@ when they serve that concern.
|
|
|
363
368
|
|
|
364
369
|
Start with `Specification` plus a direct call for pure reactor decisions; add `ReactorScenario<TReactor>` only where invocation, dependency wiring or side effects contribute proof. Specify the contract, not only the happy path: field lineage, contract-authorized filtering, repeated delivery, and unrelated events.
|
|
365
370
|
|
|
366
|
-
|
|
371
|
+
In Chronicle **19.46.0+**, a handler's unseeded read-model parameter throws
|
|
372
|
+
`ReadModelNotSeededForReactorScenario`, even if nullable. Seed it through
|
|
373
|
+
`Given.ForEventSourceId(id).ReadModel(instance)`, or declare intentional absence
|
|
374
|
+
with `.NoReadModel<T>()`. Use the resolved read-model key; `Given` events do not
|
|
375
|
+
build read models, including passive ones. A synchronous handler throw surfaces
|
|
376
|
+
the handler's exception rather than a reflection wrapper, and the scenario's
|
|
377
|
+
`EventContext.Occurred` defaults to UTC.
|
|
378
|
+
|
|
379
|
+
Read [references/specifications.md](references/specifications.md) before writing
|
|
380
|
+
or reviewing reactor specifications; it shows both setup alternatives and the
|
|
381
|
+
scope of these scenario-only guards.
|
|
367
382
|
|
|
368
383
|
## Verify
|
|
369
384
|
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
# Reactor specifications
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Specifications
|
|
6
|
+
- Read-model setup — Chronicle 19.46.0+
|
|
7
|
+
- Exceptions and occurrence time — Chronicle 19.46.0+
|
|
8
|
+
- Contract coverage
|
|
9
|
+
|
|
1
10
|
## Specifications
|
|
2
11
|
|
|
3
12
|
Start with `Specification` plus a direct call for pure reactor decisions,
|
|
@@ -9,6 +18,82 @@ non-event side effects; for handlers that return events, assert the resulting
|
|
|
9
18
|
appends through the scenario's event store. Cover the replay path separately
|
|
10
19
|
when the reactor has `[OnceOnly]` or `[Replay]` handlers.
|
|
11
20
|
|
|
21
|
+
## Read-model setup — Chronicle 19.46.0+
|
|
22
|
+
|
|
23
|
+
Class-based `ReactorScenario<TReactor>` does not build read models from `Given`
|
|
24
|
+
events, **including passive models**. Seed a pre-built instance in `Establish()`:
|
|
25
|
+
|
|
26
|
+
```csharp
|
|
27
|
+
void Establish() => _scenario.Given.ForEventSourceId(_id).ReadModel(_order);
|
|
28
|
+
async Task Because() => await _scenario.Given.ForEventSource(_id).Events(_orderPlaced);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
For a **separate absence specification**, use this setup instead, so an `Order?`
|
|
32
|
+
handler parameter deliberately receives `null`:
|
|
33
|
+
|
|
34
|
+
```csharp
|
|
35
|
+
void Establish() => _scenario.Given.ForEventSourceId(_id).NoReadModel<Order>();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The builders live in `Cratis.Chronicle.Testing.Reactors`. Exact signatures on
|
|
39
|
+
`ReactorSourceGivenBuilder<TReactor>` (`where TReactor : class, IReactor`):
|
|
40
|
+
|
|
41
|
+
```csharp
|
|
42
|
+
public ReactorSourceGivenBuilder<TReactor> ReadModel<TReadModel>(TReadModel readModel)
|
|
43
|
+
where TReadModel : class;
|
|
44
|
+
public ReactorSourceGivenBuilder<TReactor> NoReadModel<TReadModel>()
|
|
45
|
+
where TReadModel : class;
|
|
46
|
+
public Task Events(params object[] events);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Both `Given.ForEventSource(EventSourceId)` and
|
|
50
|
+
`Given.ForEventSourceId(EventSourceId)` return this builder. Seed or declare
|
|
51
|
+
absence using the triggering source id by default, or the key returned by
|
|
52
|
+
`ICanResolveReadModelKey.Resolve` when implemented. Declarations are shared
|
|
53
|
+
across the scenario's builders, match the **exact type and key**, and do not
|
|
54
|
+
remove a seeded instance. Do not declare absence to hide forgotten setup.
|
|
55
|
+
|
|
56
|
+
If a recognized read-model parameter resolves to `null` without declared
|
|
57
|
+
absence, `Events(...)` throws `ReadModelNotSeededForReactorScenario` from
|
|
58
|
+
`Cratis.Chronicle.Testing.Reactors`, **even for nullable parameters**. Its message
|
|
59
|
+
names the full read-model type and key, tells you to seed via `ReadModel(...)`
|
|
60
|
+
or declare `NoReadModel<T>()`, and lists other seeded keys for that type when
|
|
61
|
+
any exist. Check the key first if the fixture already seeds that type. This
|
|
62
|
+
guard applies only when the scenario uses `EventStoreForTesting` (including an
|
|
63
|
+
explicit instance); an explicitly supplied store of another type and production
|
|
64
|
+
read-model resolution are unchanged.
|
|
65
|
+
|
|
66
|
+
## Exceptions and occurrence time — Chronicle 19.46.0+
|
|
67
|
+
|
|
68
|
+
`Events(...)` rethrows a synchronously throwing handler's **own exception**,
|
|
69
|
+
unwrapping the `TargetInvocationException` previously surfaced by reflection,
|
|
70
|
+
and preserves the handler stack. Capture with
|
|
71
|
+
`await Catch.Exception(() => _scenario.Given.ForEventSource(_id).Events(_orderPlaced))`
|
|
72
|
+
and assert the handler's exception type, not a reflection wrapper.
|
|
73
|
+
|
|
74
|
+
`EventContext.From(...)` defaults omitted `occurred` to `DateTimeOffset.UtcNow`
|
|
75
|
+
(previously `DateTimeOffset.Now`). `ReactorScenario` uses this helper, as do
|
|
76
|
+
`EventContext.Empty` and `EmptyWithEventSourceId(...)`. Explicit timestamps keep
|
|
77
|
+
their supplied offset; the positional constructor does not default `Occurred`.
|
|
78
|
+
For deterministic time-dependent plain-call specs, supply a fixed occurrence
|
|
79
|
+
time rather than asserting an exact current instant.
|
|
80
|
+
|
|
81
|
+
Verified against **Chronicle tag `v19.46.0`**:
|
|
82
|
+
|
|
83
|
+
- `Source/Clients/Testing/Reactors/ReactorSourceGivenBuilder.cs` and
|
|
84
|
+
`ReactorScenarioGivenBuilder.cs`: seeding, absence and builder signatures.
|
|
85
|
+
- `Source/Clients/Testing/Reactors/ScenarioReactorMethodArgumentsResolver.cs` and
|
|
86
|
+
`ReadModelNotSeededForReactorScenario.cs`: guard scope, resolved key and message.
|
|
87
|
+
- `Source/Clients/Testing/Reactors/ReactorScenario.cs`: synchronous exception
|
|
88
|
+
unwrapping and context creation.
|
|
89
|
+
- `Source/Clients/DotNET/Events/EventContext.cs`: UTC default and explicit time.
|
|
90
|
+
- `Source/Clients/Testing.Specs/Reactors/for_ReactorScenario/when_resolving_read_model_dependencies/`:
|
|
91
|
+
seeded, absent, nullable, passive, custom-key and explicit-store examples.
|
|
92
|
+
- `Source/Clients/Testing.Specs/Reactors/for_ReactorScenario/when_a_reactor_handler_throws_synchronously.cs`
|
|
93
|
+
and `when_a_reactor_reads_the_occurrence_time.cs`: handler exception and UTC specs.
|
|
94
|
+
|
|
95
|
+
## Contract coverage
|
|
96
|
+
|
|
12
97
|
Specify the contract, not only the happy path:
|
|
13
98
|
|
|
14
99
|
- **Field lineage.** For each returned command or event, a specification asserts
|
|
@@ -78,10 +78,14 @@ Do not assume `string.Empty`, `0`, or `Guid.Empty` is universally invalid.
|
|
|
78
78
|
|
|
79
79
|
## Let a concept generate its own value
|
|
80
80
|
|
|
81
|
-
Check the Cratis.Fundamentals version the project resolves first. Arc
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
Check the Cratis.Fundamentals version the project resolves first. Arc first
|
|
82
|
+
pinned **7.23.0 in v22.66.0** (also verified at v22.68.0); the older-version
|
|
83
|
+
caveat is not a reason to add a direct reference for Arc 22.66.0+ when it already
|
|
84
|
+
resolves 7.23.0 or later. Chronicle **v19.43.0** still pins **7.22.0** in
|
|
85
|
+
`Directory.Packages.props`. For older Arc or Chronicle-only applications, when
|
|
86
|
+
the resolved version is below 7.23.0, add a direct `Cratis.Fundamentals` 7.23.0
|
|
87
|
+
or later package reference, or keep the existing `static New()` (without the
|
|
88
|
+
interface) until you can.
|
|
85
89
|
|
|
86
90
|
When the system, not the caller, creates a value, the concept declares how by
|
|
87
91
|
implementing `IGeneratable<TSelf>` (`Cratis.Concepts`, Cratis.Fundamentals
|
|
@@ -123,7 +127,11 @@ Do not generate when:
|
|
|
123
127
|
|
|
124
128
|
In specifications, construct the concept from a known value
|
|
125
129
|
(`new <ConceptName>(Guid.Parse("…"))`) and assert against it. Do not seed or
|
|
126
|
-
replace the generator.
|
|
130
|
+
replace the generator. In Arc **22.66.0+**, let a server-owned new identifier
|
|
131
|
+
reach `Handle()` through `[GeneratedValue]` rather than calling `New()` inside
|
|
132
|
+
it; see `cratis-arc-command` for declaration and migration, and
|
|
133
|
+
`cratis-specifications-csharp` for named scenario pins (Arc **22.67.0+**).
|
|
134
|
+
Guide: `/fundamentals/csharp/generating-values/`.
|
|
127
135
|
|
|
128
136
|
## Create a Guid-backed Chronicle stream identity
|
|
129
137
|
|
|
@@ -34,8 +34,9 @@ identity, effect and pending-work contract at that point; do not postpone it to
|
|
|
34
34
|
planner audits through v7. Deliver that scope as authorized gap-fill
|
|
35
35
|
(`references/realization-and-gap-fill.md`).
|
|
36
36
|
- Reaction `runs as system role "<Role>"` declares an invocation actor (ESM v10).
|
|
37
|
-
Without it the invoke has no caller. CLI 3.41.0's 4.114.0 compiler
|
|
38
|
-
|
|
37
|
+
Without it the invoke has no caller. Historical CLI 3.41.0's 4.114.0 compiler
|
|
38
|
+
rejected the syntax (PLAY0137); current CLI 3.46.1 instead refuses ESM v10
|
|
39
|
+
at render admission (CLI-RENDER-004). Checked model/diagnostics: captures-and-reactions
|
|
39
40
|
`references/invocation-identity.md`.
|
|
40
41
|
|
|
41
42
|
## Effect guarantees and recovery traps
|
|
@@ -11,8 +11,8 @@ technique: partial work stays visible and nothing is skipped because it looked r
|
|
|
11
11
|
|
|
12
12
|
Result is `complete` only when every column is filled or says why it does not apply (for example
|
|
13
13
|
"direct effect: immediate, internal, cannot fail"). `open` names the unresolved decision and who
|
|
14
|
-
answers. `blocked` names the actual capability gap (for example CLI
|
|
15
|
-
|
|
14
|
+
answers. `blocked` names the actual capability gap (for example current CLI
|
|
15
|
+
3.46.1 refuses ESM v10 at render admission with CLI-RENDER-004) with intended behavior.
|
|
16
16
|
|
|
17
17
|
## Per translation (capture or translator reaction)
|
|
18
18
|
| Source and type | Location | Correlation | Field dispositions | Target fields traced | Dedup and ordering | Trust boundary | Recovery owner | Named cases | Result |
|
|
@@ -71,8 +71,10 @@ When a todo list is not needed: the effect is immediate, internal and cannot fai
|
|
|
71
71
|
Screenplay 4.125.0 declares the actor with reaction-level `runs as system role
|
|
72
72
|
"<Role>"` (ESM v10); without it a gated invocation has no caller and denies.
|
|
73
73
|
`given caller` is not an invocation actor. Role requirements remain enforced;
|
|
74
|
-
claim conditions for this system principal remain unknown. CLI 3.41.0's
|
|
75
|
-
compiler
|
|
74
|
+
claim conditions for this system principal remain unknown. Historical CLI 3.41.0's
|
|
75
|
+
older compiler rejected the syntax (PLAY0137). Current CLI 3.46.1 bundles
|
|
76
|
+
Screenplay 4.130.0 / Stage 4.52.0 and refuses v10 at render admission
|
|
77
|
+
(CLI-RENDER-004; toolchain `references/versions.md`).
|
|
76
78
|
Use the checked model in captures-and-reactions `references/invocation-identity.md`.
|
|
77
79
|
Arc gap-fill uses `[ExecuteCommandsAsSystem("<role>")]` for returned commands,
|
|
78
80
|
not identity inferred from prose or an imperative pipeline call.
|
|
@@ -40,7 +40,9 @@ Changes in this version: the examples are complete fenced documents that compile
|
|
|
40
40
|
example's anonymous-booking spec gained the `given caller` PLAY0389 requires; the todo-list
|
|
41
41
|
example's list query, `reads` and retry sweep moved to marked design-only excerpts so the core
|
|
42
42
|
binds); tool-qualified verdict text; the trusted-actor text now names `[ExecuteCommandsAsSystem]`
|
|
43
|
-
(Arc v20.56.0).
|
|
43
|
+
(Arc v20.56.0). Actor syntax was reverified at Screenplay v4.125.0
|
|
44
44
|
`reactions.md`, `ReactionIdentityParser.cs`, `ReactionRefusalValidator.cs` and the
|
|
45
|
-
binder's v10 selection; the checked scenario
|
|
46
|
-
3.41.0's older parser and Stage 4.51.3's v7 planner
|
|
45
|
+
binder's v10 selection; the checked scenario passed reference execution. CLI
|
|
46
|
+
3.41.0's older parser and Stage 4.51.3's v7 planner were historical target limits.
|
|
47
|
+
Current CLI 3.46.1 bundles Screenplay 4.130.0 / Stage 4.52.0 and still refuses
|
|
48
|
+
v10 at render admission (CLI-RENDER-004; toolchain `references/versions.md`).
|
|
@@ -75,8 +75,9 @@ reference invocation's authenticated system principal with exactly those roles;
|
|
|
75
75
|
Read [invocation identity](references/invocation-identity.md) for the checked
|
|
76
76
|
scenario, claim/unknown semantics and PLAY0647–0652/0557 diagnostics.
|
|
77
77
|
|
|
78
|
-
CLI 3.41.0's 4.114.0 compiler
|
|
79
|
-
|
|
78
|
+
Historical CLI 3.41.0's 4.114.0 compiler rejected this source with PLAY0137.
|
|
79
|
+
Current CLI 3.46.1 bundles Screenplay 4.130.0 / Stage 4.52.0; its render version
|
|
80
|
+
gate still admits only through v7 (CLI-RENDER-004 for v10). Target realization is gap-fill,
|
|
80
81
|
using Arc `[ExecuteCommandsAsSystem]` for returned commands. Without that attribute
|
|
81
82
|
Arc supplies no principal and `[Authorize]`/`[Roles]` deny. Each invoked command
|
|
82
83
|
is atomic, not the whole cascade; earlier accepted facts remain after a later refusal.
|
|
@@ -69,11 +69,12 @@ module Work
|
|
|
69
69
|
denial; opaque/unknown cases are not guessed. `--check privilege` (PLAY0652)
|
|
70
70
|
reviews whether event producers require every elevated role, not runtime safety.
|
|
71
71
|
|
|
72
|
-
CLI 3.41.0
|
|
73
|
-
`cratis screenplay validate --executable --warnings-as-errors`
|
|
74
|
-
exit 5.
|
|
75
|
-
|
|
76
|
-
4.
|
|
72
|
+
Historical CLI 3.41.0 bundled Screenplay 4.114.0, which did not parse `runs as`:
|
|
73
|
+
the example's `cratis screenplay validate --executable --warnings-as-errors`
|
|
74
|
+
returned PLAY0137, exit 5. This is not a current parser claim. Current CLI 3.46.1
|
|
75
|
+
bundles Screenplay 4.130.0 but its render gate still admits only through v7
|
|
76
|
+
(CLI-RENDER-004 for v10); bundled Stage 4.52.0's direct planner audits through
|
|
77
|
+
v7 and refuses v10 with STAGE-ESM-016 (`references/versions.md` in toolchain).
|
|
77
78
|
Clock/application-trigger identities have no Stage Arc realization either.
|
|
78
79
|
Use authorized gap-fill with the model as contract; returned-command Arc identity
|
|
79
80
|
uses `[ExecuteCommandsAsSystem]`, never permission inferred from a model header.
|
|
@@ -19,7 +19,7 @@ specification IssuingTheWeeklyDigest
|
|
|
19
19
|
|
|
20
20
|
Under `cratis` before 3.28.2 these actions parsed and were checked against the application
|
|
21
21
|
but bound to nothing (`PLAY0268` names ESM v6, decision 0022); on 3.28.2 they bind.
|
|
22
|
-
|
|
22
|
+
Standalone 4.125.0 (checked; current pins in the toolchain `versions.md`) executes admitted scenarios through `screenplay test`
|
|
23
23
|
or MCP `run-specifications`; source compilation alone is authored evidence.
|
|
24
24
|
Clock rules: the clock is UTC and exact; an
|
|
25
25
|
occurrence fires once when it is **due after `given clock` and at or before
|