@cratis/pi 7.20.0 → 7.22.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.
Files changed (73) hide show
  1. package/package/corpus/rules/concepts.md +10 -2
  2. package/package/corpus/rules/vertical-slices.md +4 -2
  3. package/package/corpus/skills/cratis-fundamentals-concept/SKILL.md +58 -5
  4. package/package/corpus/skills/cratis-fundamentals-concept/verification.json +4 -1
  5. package/package/corpus/skills/cratis-screenplay-automations-and-translations/SKILL.md +19 -12
  6. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/audit-format.md +4 -3
  7. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/automation-patterns.md +13 -15
  8. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/cases-to-specify.md +4 -4
  9. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/effects-and-idempotency.md +21 -0
  10. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/provenance.md +4 -2
  11. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/todo-list-example.md +7 -4
  12. package/package/corpus/skills/cratis-screenplay-automations-and-translations/verification.json +4 -4
  13. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/SKILL.md +38 -36
  14. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/complete-examples.md +1 -1
  15. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/invocation-identity.md +84 -0
  16. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/refusals-and-redelivery.md +102 -0
  17. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/specifying-triggers-and-clock.md +4 -2
  18. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/verification.json +1 -1
  19. package/package/corpus/skills/cratis-screenplay-command-surface/SKILL.md +28 -16
  20. package/package/corpus/skills/cratis-screenplay-command-surface/references/context.md +9 -0
  21. package/package/corpus/skills/cratis-screenplay-command-surface/references/generated-values-and-responses.md +15 -13
  22. package/package/corpus/skills/cratis-screenplay-command-surface/references/operations.md +80 -0
  23. package/package/corpus/skills/cratis-screenplay-command-surface/references/policy-persona-seed.md +23 -1
  24. package/package/corpus/skills/cratis-screenplay-command-surface/verification.json +2 -2
  25. package/package/corpus/skills/cratis-screenplay-discovery/SKILL.md +9 -6
  26. package/package/corpus/skills/cratis-screenplay-discovery/references/storming-loop.md +6 -5
  27. package/package/corpus/skills/cratis-screenplay-event-modeling/SKILL.md +7 -5
  28. package/package/corpus/skills/cratis-screenplay-event-modeling/references/nine-steps.md +6 -5
  29. package/package/corpus/skills/cratis-screenplay-event-modeling/references/parsed-not-runnable.md +39 -49
  30. package/package/corpus/skills/cratis-screenplay-legacy-extraction/SKILL.md +5 -3
  31. package/package/corpus/skills/cratis-screenplay-legacy-extraction/references/generate-notes.md +48 -8
  32. package/package/corpus/skills/cratis-screenplay-model-authoring/SKILL.md +44 -42
  33. package/package/corpus/skills/cratis-screenplay-model-authoring/references/language-reference.md +46 -9
  34. package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-loop.md +35 -11
  35. package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-tools.md +118 -13
  36. package/package/corpus/skills/cratis-screenplay-model-authoring/verification.json +3 -3
  37. package/package/corpus/skills/cratis-screenplay-model-review/SKILL.md +11 -6
  38. package/package/corpus/skills/cratis-screenplay-model-review/references/anti-patterns.md +1 -1
  39. package/package/corpus/skills/cratis-screenplay-model-review/references/checklist.md +11 -2
  40. package/package/corpus/skills/cratis-screenplay-read-surface/SKILL.md +10 -0
  41. package/package/corpus/skills/cratis-screenplay-read-surface/references/guarded-actions.md +79 -0
  42. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/SKILL.md +9 -7
  43. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/gap-fill-handoff.md +6 -3
  44. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/verification.json +2 -2
  45. package/package/corpus/skills/cratis-screenplay-scenario-coverage/SKILL.md +3 -2
  46. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/spec-forms-by-mode.md +13 -2
  47. package/package/corpus/skills/cratis-screenplay-slice-design/SKILL.md +3 -2
  48. package/package/corpus/skills/cratis-screenplay-slice-design/references/command-inventory.md +3 -2
  49. package/package/corpus/skills/cratis-screenplay-slice-design/references/slicing.md +40 -0
  50. package/package/corpus/skills/cratis-screenplay-specifications/SKILL.md +24 -16
  51. package/package/corpus/skills/cratis-screenplay-specifications/references/examples-and-routes.md +103 -0
  52. package/package/corpus/skills/cratis-screenplay-specifications/references/reactions-and-cascades.md +5 -6
  53. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/SKILL.md +4 -4
  54. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/stream-patterns.md +4 -2
  55. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/verification.json +2 -2
  56. package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +34 -32
  57. package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet-example.md +1 -1
  58. package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet.md +47 -2
  59. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +57 -9
  60. package/package/corpus/skills/cratis-screenplay-toolchain/references/doc-contradictions.md +6 -1
  61. package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +19 -10
  62. package/package/corpus/skills/cratis-screenplay-toolchain/references/provenance.md +4 -2
  63. package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +8 -1
  64. package/package/corpus/skills/cratis-screenplay-toolchain/references/sources-and-streams.md +90 -27
  65. package/package/corpus/skills/cratis-screenplay-toolchain/references/traps.md +10 -6
  66. package/package/corpus/skills/cratis-screenplay-toolchain/references/verdicts.md +29 -12
  67. package/package/corpus/skills/cratis-screenplay-toolchain/references/versions.md +91 -136
  68. package/package/corpus/skills/cratis-screenplay-toolchain/verification.json +7 -5
  69. package/package/corpus/skills/cratis-screenplay-ui-composition/references/screen-composition-contract.md +20 -0
  70. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +9 -5
  71. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +8 -1
  72. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/verification.json +2 -2
  73. package/package.json +1 -1
@@ -64,15 +64,23 @@ public record AuthorName(string Value) : ConceptAs<string>(Value)
64
64
  ## Chronicle stream identity rules
65
65
 
66
66
  ```csharp
67
- public record AuthorId(Guid Value) : EventSourceId<Guid>(Value)
67
+ public record AuthorId(Guid Value) : EventSourceId<Guid>(Value), IGeneratable<AuthorId>
68
68
  {
69
- public static AuthorId New() => new(Guid.NewGuid());
69
+ public static AuthorId New() => new(GenerateValue.Uuid());
70
70
  public static implicit operator AuthorId(Guid value) => new(value);
71
71
  }
72
72
  ```
73
73
 
74
74
  - `New()`, primitive → derived ID conversion, and sentinels are optional domain
75
75
  conveniences; `EventSourceId<T>` does not create an arbitrary derived type.
76
+ - When the system creates the value, implement `IGeneratable<TSelf>` and use
77
+ `GenerateValue.Uuid()` (or `GenerateValue.UuidV7()` when index locality
78
+ matters), both from `Cratis.Concepts` in Cratis.Fundamentals 7.23.0 or later.
79
+ Never `System.Random`. A client-supplied identifier is an input, not something
80
+ to generate; see the **cratis-fundamentals-concept** skill.
81
+ - Arc and Chronicle can resolve an older Cratis.Fundamentals. Check the resolved
82
+ version first; if it is below 7.23.0, add a direct `Cratis.Fundamentals`
83
+ 7.23.0 or later reference, or keep the existing `static New()` (without the interface) until you can.
76
84
  - The exact `EventSourceId<T>` base supports conversions among its underlying
77
85
  `T`, string, typed ID, and untyped `EventSourceId`, but those operators do not
78
86
  construct your derived domain record from every source form.
@@ -54,10 +54,10 @@ Every domain identifier or named value is a typed record — raw `string`/`Guid`
54
54
  - **[contract] Chronicle stream identities** derive from `EventSourceId<T>` with an `IComparable` underlying primitive. Add `NotSet`, `New()`, or a `T` → derived-id operator only when the domain API justifies it; typed empty/zero values are real specified stream IDs. The base conversion surface does not construct every derived domain record automatically.
55
55
 
56
56
  ```csharp
57
- public record AuthorId(Guid Value) : EventSourceId<Guid>(Value)
57
+ public record AuthorId(Guid Value) : EventSourceId<Guid>(Value), IGeneratable<AuthorId>
58
58
  {
59
59
  public static readonly AuthorId NotSet = new(Guid.Empty);
60
- public static AuthorId New() => new(Guid.NewGuid());
60
+ public static AuthorId New() => new(GenerateValue.Uuid());
61
61
  public static implicit operator AuthorId(Guid value) => new(value);
62
62
  }
63
63
 
@@ -67,6 +67,8 @@ public record AuthorName(string Value) : ConceptAs<string>(Value)
67
67
  }
68
68
  ```
69
69
 
70
+ `IGeneratable<T>` and `GenerateValue` need Cratis.Fundamentals 7.23.0 or later. Arc and Chronicle can resolve an older version; add a direct reference or keep a plain `static New()` until then (see [concepts.md](./concepts.md)).
71
+
70
72
  **[convention] Placement:** slice-specific concept → in the slice file; feature-shared → feature folder; module-shared → module folder; app-wide → `Common/`. Scan `Common/` and the feature folder before creating a new concept. See [concepts.md](./concepts.md) for full patterns, or invoke the **cratis-fundamentals-concept** skill.
71
73
 
72
74
  ## Commands
@@ -15,7 +15,7 @@ This skill is verified against these exact public releases:
15
15
 
16
16
  | Package | Version | Purpose |
17
17
  | --- | --- | --- |
18
- | `Cratis.Fundamentals` | `7.19.2` | `Cratis.Concepts.ConceptAs<T>` |
18
+ | `Cratis.Fundamentals` | `7.23.0` | `Cratis.Concepts.ConceptAs<T>`, `IGeneratable<TSelf>` and `GenerateValue` |
19
19
  | `Cratis.Chronicle` | `18.3.0` | `Cratis.Chronicle.Events.EventSourceId` and `EventSourceId<T>` |
20
20
 
21
21
  Reverify product sources before claiming support for another version.
@@ -76,6 +76,55 @@ A `NotSet` or `Empty` value is optional domain policy. Add one only when the
76
76
  chosen primitive value is impossible or explicitly reserved in that domain.
77
77
  Do not assume `string.Empty`, `0`, or `Guid.Empty` is universally invalid.
78
78
 
79
+ ## Let a concept generate its own value
80
+
81
+ Check the Cratis.Fundamentals version the project resolves first. Arc and
82
+ Chronicle can bring an older one; when it is below 7.23.0, add a direct
83
+ `Cratis.Fundamentals` 7.23.0 or later package reference, or keep the existing
84
+ `static New()` (without the interface) until you can.
85
+
86
+ When the system, not the caller, creates a value, the concept declares how by
87
+ implementing `IGeneratable<TSelf>` (`Cratis.Concepts`, Cratis.Fundamentals
88
+ 7.23.0 or later). The interface requires `static abstract TSelf New()`, so
89
+ generic code constrained on `where T : IGeneratable<T>` calls `T.New()` without
90
+ reflection. Generate a UUID with `GenerateValue`, never with `Guid.NewGuid()` in
91
+ scattered call sites and never with `System.Random`:
92
+
93
+ ```csharp
94
+ using Cratis.Concepts;
95
+
96
+ public record <ConceptName>(Guid Value) : ConceptAs<Guid>(Value), IGeneratable<<ConceptName>>
97
+ {
98
+ public static <ConceptName> New() => new(GenerateValue.Uuid());
99
+ }
100
+ ```
101
+
102
+ Both helpers return a `Guid` with the RFC 9562 variant and fill their random
103
+ bits from `RandomNumberGenerator`:
104
+
105
+ - `GenerateValue.Uuid()` — version 4, 122 random bits. The default.
106
+ - `GenerateValue.UuidV7()` — version 7: Unix-epoch milliseconds first, then 74
107
+ random bits. Choose it only when database index locality or rough creation
108
+ order matters, after checking how the database stores and compares UUIDs. It reveals the creation time, it is **not** monotonic within a
109
+ millisecond, and clock adjustments can reorder values.
110
+
111
+ Neither helper guarantees uniqueness; a collision is extremely unlikely, not
112
+ impossible. `IGeneratable<TSelf>` is not limited to Guid-backed concepts, but
113
+ `GenerateValue` only produces UUIDs.
114
+
115
+ Do not generate when:
116
+
117
+ - The client supplies the identifier. It is an input; keep it.
118
+ - The value must be secret or authenticate someone. A UUID is an identifier,
119
+ not a token; use a dedicated secure-token API.
120
+ - The same input must yield the same value. Random generation is not
121
+ idempotency; derive the value deterministically, or persist and reuse the
122
+ first one.
123
+
124
+ In specifications, construct the concept from a known value
125
+ (`new <ConceptName>(Guid.Parse("…"))`) and assert against it. Do not seed or
126
+ replace the generator. Guide: `/fundamentals/csharp/generating-values/`.
127
+
79
128
  ## Create a Guid-backed Chronicle stream identity
80
129
 
81
130
  Use this shape only for an identity actually supplied to Chronicle append/read
@@ -86,6 +135,7 @@ operations as the event-source ID.
86
135
  // Licensed under the MIT license. See LICENSE file in the project root for full license information.
87
136
 
88
137
  using Cratis.Chronicle.Events;
138
+ using Cratis.Concepts;
89
139
 
90
140
  namespace <NamespaceRoot>.<Feature>;
91
141
 
@@ -93,13 +143,13 @@ namespace <NamespaceRoot>.<Feature>;
93
143
  /// Represents the event-source identity of a <description>.
94
144
  /// </summary>
95
145
  /// <param name="Value">The underlying Guid value.</param>
96
- public record <ConceptName>(Guid Value) : EventSourceId<Guid>(Value)
146
+ public record <ConceptName>(Guid Value) : EventSourceId<Guid>(Value), IGeneratable<<ConceptName>>
97
147
  {
98
148
  /// <summary>
99
149
  /// Creates a new <ConceptName>.
100
150
  /// </summary>
101
151
  /// <returns>A new <ConceptName>.</returns>
102
- public static <ConceptName> New() => new(Guid.NewGuid());
152
+ public static <ConceptName> New() => new(GenerateValue.Uuid());
103
153
 
104
154
  /// <summary>
105
155
  /// Converts a Guid to a <ConceptName>.
@@ -108,8 +158,8 @@ public record <ConceptName>(Guid Value) : EventSourceId<Guid>(Value)
108
158
  }
109
159
  ```
110
160
 
111
- `New()` and the primitive-to-derived conversion are conveniences on this domain
112
- type. `EventSourceId<T>` does not construct an arbitrary derived identity for
161
+ `New()` (through `IGeneratable<TSelf>`) and the primitive-to-derived conversion
162
+ are conveniences on this domain type. `EventSourceId<T>` does not construct an arbitrary derived identity for
113
163
  you.
114
164
 
115
165
  ## Create a non-Guid Chronicle stream identity
@@ -185,6 +235,9 @@ repository structure.
185
235
  - `ConceptAs<T>` and `EventSourceId<T>` use an `IComparable` underlying type.
186
236
  - A concept contains exactly one wrapped value and no extra properties.
187
237
  - Enums remain enums.
238
+ - A concept that creates its own value implements `IGeneratable<TSelf>`; a
239
+ Guid-backed one uses `GenerateValue`, not `Guid.NewGuid()` or `Random`.
240
+ Client-supplied, secret or idempotent values are not generated.
188
241
  - Null absence uses a nullable concept reference rather than a null wrapped
189
242
  value.
190
243
  - Primitive-to-derived conversions and sentinels exist only when justified by
@@ -3,6 +3,9 @@
3
3
  "input": "Create a strongly typed value for a domain concept.",
4
4
  "fixtures": [],
5
5
  "assertions": [
6
- { "kind": "skill-contains", "value": "ConceptAs<T>" }
6
+ { "kind": "skill-contains", "value": "ConceptAs<T>" },
7
+ { "kind": "skill-contains", "value": "IGeneratable<TSelf>" },
8
+ { "kind": "skill-contains", "value": "GenerateValue.Uuid()" },
9
+ { "kind": "skill-contains", "value": "not** monotonic within a" }
7
10
  ]
8
11
  }
@@ -28,10 +28,15 @@ identity, effect and pending-work contract at that point; do not postpone it to
28
28
  4.66.0). Probed on 3.28.2: the complete examples are `executableReady`. A cratis bundle before 3.28.2
29
29
  (4.60.1) reports PLAY0268 at binding: report "V3 blocked: PLAY0268 (ESM v6)" and
30
30
  name the tool, never remove them.
31
- - No MCP tool, `validate` or render runs Automation or Translate specs. V4 is "not run: no route".
32
- - Stage 4.24.2 (bundled in cratis 3.28.3) renders no Automation or Translate slice (Stage#79); `cratis render` refuses the whole v6 model with STAGE-ESM-016: the whole automation is
33
- gap-fill or hand-written delivery with the model as contract (`references/realization-and-gap-fill.md`).
34
- - Invoked commands run with no caller; `.play` cannot name an actor (Screenplay#383).
31
+ - Standalone 4.125.0 runs admitted scenarios through `screenplay test` or MCP
32
+ `run-specifications`; source validation and render publication do not run V4.
33
+ - Stage 4.51.3 refuses Automation/Translate members with STAGE-ESM-024; its direct
34
+ planner audits through v7. Deliver that scope as authorized gap-fill
35
+ (`references/realization-and-gap-fill.md`).
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 rejects the
38
+ new syntax (PLAY0137). Checked model/diagnostics: captures-and-reactions
39
+ `references/invocation-identity.md`.
35
40
 
36
41
  ## Effect guarantees and recovery traps
37
42
  | Guarantee | What it promises | What can show it |
@@ -113,12 +118,12 @@ or actor that nobody confirmed. Read `references/worked-integration.md` when you
113
118
  supersession), the work-item key and the recovery path. Direct reaction only for an immediate,
114
119
  internal, always-possible effect; say why no pending state is needed. A translation is not
115
120
  automatically infallible.
116
- 4. **Effect and actor.** `produces <Fact>` when nothing should refuse the fact. `invokes <Command>`
117
- when the step is a decision that may reject; it carries **no caller**, so gated commands reject it.
118
- Record one actor decision: internal ungated command (only when safe and unreachable), direct
119
- `produces`, or gated command with a trusted actor and the capability gap (Screenplay#383). The code
120
- realization of the actor is a reactor with `[ExecuteCommandsAsSystem("<role>")]` and a policy
121
- requiring that role; never invent `runs as`. Never strip authorization to pass a tool.
121
+ 4. **Effect and actor.** `produces <Fact>` records a decided fact; `invokes <Command>`
122
+ requests a decision. Keep its gate and declare the trusted role with reaction
123
+ `runs as system role "<Role>"` (ESM v10). An undeclared actor remains caller-less.
124
+ CLI/Stage realization is a separate gap; a returned-command reactor uses
125
+ `[ExecuteCommandsAsSystem("<role>")]` and the matching policy. Never strip a
126
+ gate or supply `given caller` as a fictional reaction identity.
122
127
  5. **Trace inputs.** Every trigger value, command input, event property and destination needs a
123
128
  supported source; every filter a business reason. Gaps are questions, not invented mappings.
124
129
  6. **Repetition and termination.** Identify one logical work occurrence and what a retry is. Guard the
@@ -140,7 +145,8 @@ or actor that nobody confirmed. Read `references/worked-integration.md` when you
140
145
  - Clock triggers take no values (PLAY0450) and no `by` on reads (PLAY0443). `for each <View>` is
141
146
  reserved, not available.
142
147
  - Capture `when` cannot mix `and` and `or` (PLAY0089). A capture without `key` does not bind.
143
- - Undeclared events in capture `append` and `remove with` pass V1 and fail only at binding (V3, PLAY0273): run V3.
148
+ - Current V1 warns on undeclared capture/removal events (PLAY0166); V3 remains a
149
+ separate binder check.
144
150
  - A trigger with `reads` that `produces` directly fails binding: decide in a command. `reads` never protects.
145
151
  - An authorized command exercised in a spec without `given caller` is PLAY0389 at binding.
146
152
  - A list query (`=> Item[]`) and a clock sweep that iterates items do not bind; show them only as marked
@@ -175,7 +181,8 @@ Never report a verdict without the tool and version that produced it.
175
181
 
176
182
  ## Verify
177
183
  - V1 and V3 per `cratis-screenplay-toolchain`, each with tool and version. On a cratis before 3.28.2
178
- bundle report "V3 blocked: PLAY0268 (ESM v6)"; on 4.66.0 (standalone or cratis 3.28.2) these slices bind. V4 is "not run: no route" for these slices.
184
+ bundle report "V3 blocked: PLAY0268 (ESM v6)". Current admitted scenarios use
185
+ standalone `screenplay test`/MCP for V4; unsupported or unbound is not passed.
179
186
  - For each external source and type: its translation, or an explicit out-of-scope reason; check
180
187
  target-field completeness as well as source-field dispositions.
181
188
  - One happy path is not coverage: cite the spec or the missing case for each branch, denial, competing
@@ -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 capability gap (for example Screenplay#383 for the actor, or a
15
- list query that does not bind) with the intended behaviour.
14
+ answers. `blocked` names the actual capability gap (for example CLI 3.41.0's
15
+ older compiler cannot parse a declared ESM v10 reaction actor) 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 |
@@ -45,4 +45,5 @@ never skip it silently or call the chain complete.
45
45
  | Unreviewed | `RecordCompletion` denial for a non-coordinator is specified; query authorization not in scope | stated |
46
46
 
47
47
  Then the verdict line per `cratis-screenplay-toolchain`: tool and version on each of V1 to V4
48
- (V4 for these slices: "not run: no route").
48
+ (V4 uses standalone `screenplay test` or MCP `run-specifications`; report the
49
+ actual result, or a specific host/input limitation if not run).
@@ -65,16 +65,17 @@ When a todo list is not needed: the effect is immediate, internal and cannot fai
65
65
  | can it be refused? | only by append-time constraints | authorization, validation, `require`, constraints |
66
66
  | destination | `for` value; without `for`, the trigger fact's source | the command's identifier |
67
67
  | with trigger `reads` | fails binding (unprotected decision) | allowed; protection is the command's job |
68
- | caller | n/a | **none**: gated commands reject |
68
+ | caller | n/a | declared reaction `runs as` actor (ESM v10), otherwise none |
69
69
 
70
70
  ## 4. The actor behind an invoke
71
- On Screenplay 4.66.0 there is no caller: the invoked command runs its full pipeline (authorization, validation,
72
- requirements, constraints) with no caller, a command that needs one rejects, and the rejection
73
- ends the scenario. Screenplay has no syntax for an identity (Screenplay#383, open); never invent
74
- `runs as` or a caller line. At code level the realization is a Chronicle reactor whose returned
75
- commands run as a trusted system actor: `[ExecuteCommandsAsSystem("<role>")]` (Arc, since
76
- v20.56.0; also in a Stage-rendered app, whose Arc is 22.25.0) with a policy that requires that
77
- role. Record the intended actor in the model; the attribute lives in gap-fill code.
71
+ Screenplay 4.125.0 declares the actor with reaction-level `runs as system role
72
+ "<Role>"` (ESM v10); without it a gated invocation has no caller and denies.
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 older
75
+ compiler rejects the syntax (PLAY0137), and Stage 4.51.3 admits through v7 only.
76
+ Use the checked model in captures-and-reactions `references/invocation-identity.md`.
77
+ Arc gap-fill uses `[ExecuteCommandsAsSystem("<role>")]` for returned commands,
78
+ not identity inferred from prose or an imperative pipeline call.
78
79
 
79
80
  Decide and record one of:
80
81
  1. **Internal ungated command** - only if the security design supports it: not reachable by
@@ -84,13 +85,10 @@ Decide and record one of:
84
85
  requirement in `STATE.md`.
85
86
  2. **Direct `produces`** - when no decision is left (the fact is already decided) and nothing
86
87
  should refuse it.
87
- 3. **Gated command + trusted actor + recorded gap** - when the command must stay protected.
88
- Keep the gate (a policy requiring the service role), name the role as the intended actor,
89
- and record that Screenplay 4.66.0 cannot declare it. The reference rejects the caller-less invoke,
90
- so the automation spec cannot pass: do not write a fake passing spec. Report V4 as "not run:
91
- no route" (no available route executes these specs) and record the expected rejection and
92
- the trusted-actor gap separately, citing the reaction semantics (a command that requires a
93
- caller rejects the reaction).
88
+ 3. **Gated command + declared trusted actor** - keep the service-role policy and
89
+ declare matching `runs as system role` on the reaction. Reference-test the
90
+ scenario with standalone 4.125.0; separately record CLI/Stage target refusal.
91
+ A missing actor must not be excused by removing the gate or inventing a caller.
94
92
  Never remove an existing gate only to make a reaction spec pass.
95
93
  Omitting an HTTP route is not an authorization proof: the exposure requirement stays a target
96
94
  requirement with its negative case (an outside caller is refused).
@@ -16,7 +16,7 @@ One spec in the slice does not cover the others.
16
16
  | queue opens / closes | item appears, item disappears | `then query …ById`; `when append <Closing>` + `then no readmodel … for` |
17
17
  | already done | trigger re-delivered after the result exists | `given <Result>` + `when <Command>` -> `then error "<fixed constraint message>"` |
18
18
  | invoked command rejects | validation or constraint refuses | command spec in its StateChange slice; record what the queue shows afterwards |
19
- | no caller | invoked command is gated | record the expected rejection and the actor decision (`automation-patterns.md` §4); V4 is "not run: no route" |
19
+ | no declared actor | invoked command is gated | specify its denial; for the trusted path declare reaction `runs as system role` and reference-test with standalone 4.125.0 |
20
20
  | clock boundary | due exactly at the instant, just before, just after | `given clock` + `when clock`; boundary semantics are contested in the docs, mark the expectation as an assumption |
21
21
  | each branch | does every filter and conditional production have both outcomes? | concrete triggering and non-triggering values; assert the resulting facts or view |
22
22
  | denied actor | every command and query under an inherited module/feature `authorize` needs its own denial; also, can an unauthorized caller reach a gated invoked command by another origin? | command spec with otherwise-valid inputs, `given caller` carrying the wrong role/claim (or no caller) and `then denied`; separate from the caller-less reaction gap |
@@ -58,9 +58,9 @@ One spec in the slice does not cover the others.
58
58
  The decision must not depend on it (it is not protected).
59
59
 
60
60
  ## Spec limits (tool differences: `cratis-screenplay-toolchain` `references/versions.md`)
61
- - These Automation/Translate specs parse and bind (V3) on Screenplay 4.66.0, but no MCP tool,
62
- `validate` or Stage render runs them (Stage renders no Automation or Translate slice). Report
63
- V4 as "not run: no route"; never as passed.
61
+ - Current admitted Automation/Translate specifications run through standalone
62
+ `screenplay test` or MCP `run-specifications`. Validate/render alone is not V4;
63
+ report unsupported/unbound separately from passing scenarios.
64
64
  - With Screenplay 4.66.0 (standalone or cratis 3.28.2), a command spec lists the cascade (v6 semantics: after
65
65
  `when <Command>`, `then` lists every new fact, including reaction appends). Only when a
66
66
  cratis before 3.28.2 bundle (4.60.1) is the V1 tool does it report a false PLAY0285 on a cascade (cli#242):
@@ -25,6 +25,27 @@ or reaction. Choose and record one of:
25
25
  Payments, legal notices and anything costly or irreversible: prefer 2 or 3 and an idempotency
26
26
  key; write a reconciliation case.
27
27
 
28
+ ## Refusal disposition and redelivery
29
+
30
+ At Screenplay 4.125.0 an invocation can state ordered `on refused` selectors for
31
+ validation, constraint (optionally named) or explicit authorization denial.
32
+ Bare refusal does not include authorization. A matching branch declares a fact
33
+ or leaf `acknowledge`; `$refusal.reason`/`.message` are String details and
34
+ `.constraint` belongs only to constraint selectors. This is **authoring-only**
35
+ (PLAY0268), not evidence that a duplicate was safely acknowledged at runtime.
36
+
37
+ Recovery syntax `when redelivered <Event> to <Reaction>` selects exactly one
38
+ existing given occurrence; it is not append or replay. `then no events` makes a
39
+ no-new-facts contract explicit but remains unadmitted too. Full selectors,
40
+ occurrence matching and checked source examples: captures-and-reactions
41
+ `references/refusals-and-redelivery.md`.
42
+
43
+ Infrastructure/contract errors, Unsupported and concurrency are never domain
44
+ refusals. No `by concurrency` exists: fail/retry transient contention. Record the
45
+ actual target's disposition, trusted actor, durable delivery identity and external
46
+ idempotency/reconciliation owner. A branch or observer receipt alone proves no
47
+ cascade transaction or exactly-once external effect.
48
+
28
49
  ## Retry identity
29
50
  - The retry must carry the same identity as the first attempt: the stream id chosen before
30
51
  the first try (never a fresh id per attempt), and the same idempotency key outward.
@@ -40,5 +40,7 @@ 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, available in a rendered app's Arc 22.25.0) and Screenplay#383; Stage renders no
44
- Automation or Translate slice (Stage#79).
43
+ (Arc v20.56.0). Current actor syntax was reverified at Screenplay v4.125.0
44
+ `reactions.md`, `ReactionIdentityParser.cs`, `ReactionRefusalValidator.cs` and the
45
+ binder's v10 selection; the checked scenario passes reference execution. CLI
46
+ 3.41.0's older parser and Stage 4.51.3's v7 planner remain target limits.
@@ -13,7 +13,8 @@ The first spec lists the whole cascade (`then` names every new fact: `CoursePass
13
13
  `CertificateSent` through the reaction), and `given clock` supplies the instant that
14
14
  `$context.occurred` needs. Both 4.66.0 tools accept that cascade; the cratis 3.27.1 bundle reported a false PLAY0285 on it
15
15
  (cli#242). These specs were not
16
- run (V4: not run, no route); the expectations follow the v4.66.0 reference semantics.
16
+ run in that historical probe; current admitted scenarios can be run with
17
+ standalone `screenplay test` or MCP `run-specifications`.
17
18
 
18
19
  What the model proves and what it does not:
19
20
 
@@ -22,8 +23,10 @@ What the model proves and what it does not:
22
23
  - Not proven: that the certificate email reaches the person once. See
23
24
  `references/effects-and-idempotency.md`.
24
25
  - The actor behind `SendCertificate` is a recorded security decision in the `Certification`
25
- module `description`, because reaction invocations carry no caller on Screenplay 4.66.0 (Screenplay#383).
26
- - No local engine runs Automation specifications: report them as authored, not as run.
26
+ module `description`: this example declares no reaction identity, so its
27
+ invocations remain caller-less. A gated trusted path can instead declare
28
+ `runs as system role` on 4.125.0 (ESM v10), with separate CLI/Stage refusal.
29
+ - Report reference outcomes only after executing the selected scenarios.
27
30
 
28
31
  ```screenplay
29
32
  // Todo-list automation. Shape: CoursePassed opens an item -> CertificateSender invokes
@@ -101,7 +104,7 @@ module Courses
101
104
  for "0d3b9e2a-6c4f-4f1e-8b7a-5e2d1c3b4a01"
102
105
 
103
106
  module Certification
104
- description "Trusted background boundary. No persona or screen issues SendCertificate; only the CertificateSender reaction invokes it, and reaction invocations carry no caller. Leaving the command ungated is a SECURITY DECISION, accepted only because: (1) it appends a fact keyed to one enrolment, (2) a repeat is rejected by IssueOnce, (3) the realization must not expose it to external callers (requirement to verify in the target). If (3) cannot hold, gate it with a service-actor policy and record the capability gap instead (reaction invocations carry no caller: Screenplay#383)."
107
+ description "Trusted background boundary. No persona or screen issues SendCertificate; only the CertificateSender reaction invokes it, and reaction invocations carry no caller. Leaving the command ungated is a SECURITY DECISION, accepted only because: (1) it appends a fact keyed to one enrolment, (2) a repeat is rejected by IssueOnce, (3) the realization must not expose it to external callers (requirement to verify in the target). If (3) cannot hold, gate it with a service-actor policy and declare runs as system role on the reaction (ESM v10), retaining the CLI/Stage realization gap."
105
108
  feature Certificates
106
109
  slice StateView CertificatesToSend
107
110
  description "Work queue: membership means 'still to send'; there is no status flag"
@@ -4,13 +4,13 @@
4
4
  "fixtures": [],
5
5
  "assertions": [
6
6
  { "kind": "skill-contains", "value": "`[ExecuteCommandsAsSystem(\"<role>\")]`" },
7
- { "kind": "skill-contains", "value": "Screenplay#383" },
8
- { "kind": "skill-contains", "value": "renders no Automation or Translate slice" },
9
- { "kind": "skill-contains", "value": "never invent `runs as`" },
7
+ { "kind": "skill-contains", "value": "ESM v10" },
8
+ { "kind": "skill-contains", "value": "STAGE-ESM-024" },
9
+ { "kind": "skill-contains", "value": "runs as system role" },
10
10
  { "kind": "skill-contains", "value": "**One meaning of Translation:**" },
11
11
  { "kind": "skill-contains", "value": "complete, open or blocked" },
12
12
  { "kind": "skill-contains", "value": "never write a mapping" },
13
- { "kind": "skill-contains", "value": "V4 is \"not run: no route\"" },
13
+ { "kind": "skill-contains", "value": "run-specifications" },
14
14
  { "kind": "skill-contains", "value": "never skipped silently" },
15
15
  { "kind": "skill-contains", "value": "not applicable: no queue" }
16
16
  ]
@@ -32,16 +32,10 @@ source is the single flow model.
32
32
  | `Cratis.Screenplay` | main `fd18129` | Command-only inline event boundary |
33
33
  | `Cratis.Screenplay` | `4.66.0` (`c89198b`) | ESM v6: reactions, clock, trigger and capture specifications bind; `invokes` caller rule; probed with the standalone tool and its MCP server |
34
34
 
35
- The update follows `commands.md`, `events.md` and `diagnostics.md` at that main
36
- commit (after v4.52.0).
37
-
38
- Historical baseline evidence: the original examples were checked against the Screenplay repository at tag `v4.31.0` (commit `355dffb`):
39
- `Documentation/screenplay/{captures,captures/grammar,reactions,triggers,interactions,file-references,grammar,diagnostics}.md`
40
- and decisions 0003, 0006 and 0009; those original examples compiled with that
41
- version's compiler. The specification actions and ESM v6 text were checked at
42
- `v4.66.0` (see its row above), and the complete examples here and in
43
- `references/complete-examples.md` compile with the standalone 4.68.0 compiler.
44
- Reverify before claiming another version behaves the same.
35
+ The table records historical examples/probes; they are not reclassified as
36
+ current execution evidence. Refusal/redelivery guidance follows released
37
+ v4.125.0 `reactions.md`/`specifications.md`. Current pins are in toolchain
38
+ `references/versions.md`; reverify before promoting an old probe to that version.
45
39
 
46
40
  ⚠️ **Which tool admits them depends on its Screenplay version.** The ESM level
47
41
  decides, not the slice type:
@@ -50,14 +44,10 @@ decides, not the slice type:
50
44
  `Translate` slices, reactions, declared triggers and captures bind, and the
51
45
  reference runner executes them. Probed: the complete example below is
52
46
  `executableReady` over `screenplay mcp`.
53
- - **`cratis` 3.28.2 (bundles Screenplay 4.66.0, ESM v1-v6):** the same as the standalone
54
- tool. Probed: the complete examples validate with warnings as errors and are
55
- `executableReady` over `cratis screenplay mcp`. `cratis` before 3.28.2 (Screenplay
56
- 4.60.1, ESM v1-v5) failed an `Automation` or `Translate` slice at binding with `PLAY0268`
57
- (*Slice '<name>' of type '<type>' is not admitted by ESM v1*), reported reactions as
58
- *requires portable occurrence and effect semantics* and captures as *require a portable
59
- compiled CDL plan*, and gave a false `PLAY0285` on a specification that follows a reaction
60
- cascade (Cratis/cli#242).
47
+ - **Historical CLI 3.28.2 / Screenplay 4.66.0 probe:** complete examples validated
48
+ and were executableReady through MCP. Earlier 4.60.1 bundles refused v6 at
49
+ binding and falsely reported PLAY0285 on cascades. Toolchain `references/versions.md`
50
+ separates that history from current pins.
61
51
  - **Stage 4.24.2** admits ESM v1-v4 and renders no `Automation` or `Translate`
62
52
  slice. The automation is gap-fill, with the `.play` slice and its specifications
63
53
  as the contract: `cratis-screenplay-render-and-gap-fill`.
@@ -69,25 +59,26 @@ Method (the four-part automation test, loops, translations versus automations):
69
59
 
70
60
  ## Specify what sets them off
71
61
 
72
- A specification names what sets the automation off: `when clock`, `when trigger` or `when capture`. No command runs these specifications; report one as authored, not executed.
62
+ A specification names what sets the automation off: `when clock`, `when trigger`
63
+ or `when capture`. Execute admitted scenarios through `screenplay test` or MCP
64
+ `run-specifications`; source compilation alone is only authored evidence.
73
65
 
74
66
  Read [references/specifying-triggers-and-clock.md](references/specifying-triggers-and-clock.md) when writing a specification for a reaction, trigger or capture, or when the clock, occurrence or limit rules matter.
75
67
 
76
68
  ## Caller-less invokes and unprotected reads
77
69
 
78
- **Who is the caller of an `invokes`?** Nobody. In the reference execution the invoked
79
- command runs its full pipeline - authorization, validation, requirements,
80
- constraints - **with no caller**; a command that needs one rejects, and the
81
- rejection ends the scenario. Each invoked command is atomic, but the cascade is not,
82
- so facts accepted earlier remain. There is no syntax for a trusted identity in the verified Screenplay versions
83
- (Screenplay#383, open): never invent `runs as` or a `given caller` for a reaction.
84
- Say so in the model: a `description` on the reaction that names the trusted actor
85
- the target must use. At code level a rendered or hand-written target runs such a
86
- command as the system with `[ExecuteCommandsAsSystem]` (Arc 20.56.0 and later, so
87
- also in a rendered application's Arc 22.25.0). An authorized command a reaction
88
- invokes needs that decision made explicit, in the model's description and in the
89
- gap-fill code, not left to a rejection nobody expected. Cascades and their
90
- specification limits: `cratis-screenplay-specifications`.
70
+ **Who is the caller of an `invokes`?** Without a declared actor, nobody.
71
+ Screenplay 4.125.0 supports reaction-level `runs as system role "<Role>"`
72
+ (optional roles, joined with `and role`). It selects ESM v10 and supplies the
73
+ reference invocation's authenticated system principal with exactly those roles;
74
+ `given caller` does not supply it. Keep gates and declare the least-privilege actor.
75
+ Read [invocation identity](references/invocation-identity.md) for the checked
76
+ scenario, claim/unknown semantics and PLAY0647–0652/0557 diagnostics.
77
+
78
+ CLI 3.41.0's 4.114.0 compiler rejects this source with PLAY0137; its version gate
79
+ and Stage 4.51.3 planner admit only through v7. Target realization is gap-fill,
80
+ using Arc `[ExecuteCommandsAsSystem]` for returned commands. Each invoked command
81
+ is atomic, not the whole cascade; earlier accepted facts remain after a later refusal.
91
82
 
92
83
  ⚠️ **Declared, not enforced.** A trigger `reads` gives no runtime protection. From
93
84
  ESM v6 the binder refuses to treat it as one: a trigger with `reads` that **produces
@@ -101,9 +92,19 @@ the input selection or not; nested paths and read aliases fail binding): keep th
101
92
  the invoked command or the implementation. Under `cratis` before 3.28.2 none of this
102
93
  bound at all (`PLAY0268`); `cratis` 3.28.2 binds it like the standalone tool.
103
94
 
95
+ ## Refusals and recovery redelivery
96
+
97
+ At 4.125.0, invocation refusal selectors, `$refusal` branch values,
98
+ `acknowledge`, `when redelivered ... to ...` and `then no events` are valid
99
+ authoring intent but refuse binding with PLAY0268. Read
100
+ [refusals and redelivery](references/refusals-and-redelivery.md) for first-match
101
+ selectors, typed values, occurrence matching, diagnostics and the checked
102
+ unbound example. Never acknowledge infrastructure or concurrency failures.
103
+
104
104
  ## Complete example (ESM v6)
105
105
 
106
- One document with every construct (application trigger, reactions on an event, a trigger, a view read and the clock, and a capture with specifications) is kept in the reference file.
106
+ The reference document covers v6 triggers, event/clock reactions, view reads and
107
+ capture specifications. Refusal/redelivery forms use their separate checked reference.
107
108
 
108
109
  Read [references/complete-examples.md](references/complete-examples.md) when you need a complete, compiling parent document for an excerpt or want to check the authoring and binding prerequisites.
109
110
 
@@ -338,7 +339,8 @@ something is reported. `Startup` and `Shutdown` are registered the second way.
338
339
  `PLAY0268` at binding and a false `PLAY0285` on cascade specifications, and report them
339
340
  as tool skew.
340
341
  - [ ] The tool that bound the model is named (Screenplay 4.61 or later, so standalone or
341
- `cratis` 3.28.2 or later, for ESM v6 constructs); no tool runs the specifications.
342
+ `cratis` 3.28.2 or later, for ESM v6 constructs); reference scenarios use
343
+ `screenplay test`/MCP. Unadmitted refusal/redelivery is not executed evidence.
342
344
  - [ ] Each automation has all four components — occurrence, state consulted,
343
345
  conditional logic, resulting command or event. If it always fires
344
346
  unconditionally it is co-production, not an automation.
@@ -351,8 +353,8 @@ something is reported. `Startup` and `Shutdown` are registered the second way.
351
353
  value the trigger takes, and clock triggers read without `by`.
352
354
  - [ ] Nobody reports trigger or command `reads` as protected; UI clicks are
353
355
  interactions, not triggers.
354
- - [ ] Every `invokes` of an authorized command names the trusted actor in a
355
- description; no caller is invented for a reaction.
356
+ - [ ] Every gated invocation declares its trusted actor with reaction `runs as`
357
+ (ESM v10) or records the target gap explicitly; `given caller` is not that actor.
356
358
 
357
359
  ## Route near misses
358
360
 
@@ -97,7 +97,7 @@ module Delivery
97
97
 
98
98
  ## Reaction with `produces` and `invokes`
99
99
 
100
- Parent of the `Provisioner` excerpt. The invoked command runs with no caller in the
100
+ Parent of the `Provisioner` excerpt. The reaction declares no `runs as system`, so the invoked command runs with no caller in the
101
101
  reference execution.
102
102
 
103
103
  ```screenplay