@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.
- package/package/corpus/rules/concepts.md +10 -2
- package/package/corpus/rules/vertical-slices.md +4 -2
- package/package/corpus/skills/cratis-fundamentals-concept/SKILL.md +58 -5
- package/package/corpus/skills/cratis-fundamentals-concept/verification.json +4 -1
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/SKILL.md +19 -12
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/audit-format.md +4 -3
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/automation-patterns.md +13 -15
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/cases-to-specify.md +4 -4
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/effects-and-idempotency.md +21 -0
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/provenance.md +4 -2
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/todo-list-example.md +7 -4
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/verification.json +4 -4
- package/package/corpus/skills/cratis-screenplay-captures-and-reactions/SKILL.md +38 -36
- package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/complete-examples.md +1 -1
- package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/invocation-identity.md +84 -0
- package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/refusals-and-redelivery.md +102 -0
- package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/specifying-triggers-and-clock.md +4 -2
- package/package/corpus/skills/cratis-screenplay-captures-and-reactions/verification.json +1 -1
- package/package/corpus/skills/cratis-screenplay-command-surface/SKILL.md +28 -16
- package/package/corpus/skills/cratis-screenplay-command-surface/references/context.md +9 -0
- package/package/corpus/skills/cratis-screenplay-command-surface/references/generated-values-and-responses.md +15 -13
- package/package/corpus/skills/cratis-screenplay-command-surface/references/operations.md +80 -0
- package/package/corpus/skills/cratis-screenplay-command-surface/references/policy-persona-seed.md +23 -1
- package/package/corpus/skills/cratis-screenplay-command-surface/verification.json +2 -2
- package/package/corpus/skills/cratis-screenplay-discovery/SKILL.md +9 -6
- package/package/corpus/skills/cratis-screenplay-discovery/references/storming-loop.md +6 -5
- package/package/corpus/skills/cratis-screenplay-event-modeling/SKILL.md +7 -5
- package/package/corpus/skills/cratis-screenplay-event-modeling/references/nine-steps.md +6 -5
- package/package/corpus/skills/cratis-screenplay-event-modeling/references/parsed-not-runnable.md +39 -49
- package/package/corpus/skills/cratis-screenplay-legacy-extraction/SKILL.md +5 -3
- package/package/corpus/skills/cratis-screenplay-legacy-extraction/references/generate-notes.md +48 -8
- package/package/corpus/skills/cratis-screenplay-model-authoring/SKILL.md +44 -42
- package/package/corpus/skills/cratis-screenplay-model-authoring/references/language-reference.md +46 -9
- package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-loop.md +35 -11
- package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-tools.md +118 -13
- package/package/corpus/skills/cratis-screenplay-model-authoring/verification.json +3 -3
- package/package/corpus/skills/cratis-screenplay-model-review/SKILL.md +11 -6
- package/package/corpus/skills/cratis-screenplay-model-review/references/anti-patterns.md +1 -1
- package/package/corpus/skills/cratis-screenplay-model-review/references/checklist.md +11 -2
- package/package/corpus/skills/cratis-screenplay-read-surface/SKILL.md +10 -0
- package/package/corpus/skills/cratis-screenplay-read-surface/references/guarded-actions.md +79 -0
- package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/SKILL.md +9 -7
- package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/gap-fill-handoff.md +6 -3
- package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/verification.json +2 -2
- package/package/corpus/skills/cratis-screenplay-scenario-coverage/SKILL.md +3 -2
- package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/spec-forms-by-mode.md +13 -2
- package/package/corpus/skills/cratis-screenplay-slice-design/SKILL.md +3 -2
- package/package/corpus/skills/cratis-screenplay-slice-design/references/command-inventory.md +3 -2
- package/package/corpus/skills/cratis-screenplay-slice-design/references/slicing.md +40 -0
- package/package/corpus/skills/cratis-screenplay-specifications/SKILL.md +24 -16
- package/package/corpus/skills/cratis-screenplay-specifications/references/examples-and-routes.md +103 -0
- package/package/corpus/skills/cratis-screenplay-specifications/references/reactions-and-cascades.md +5 -6
- package/package/corpus/skills/cratis-screenplay-streams-and-consistency/SKILL.md +4 -4
- package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/stream-patterns.md +4 -2
- package/package/corpus/skills/cratis-screenplay-streams-and-consistency/verification.json +2 -2
- package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +34 -32
- package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet-example.md +1 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet.md +47 -2
- package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +57 -9
- package/package/corpus/skills/cratis-screenplay-toolchain/references/doc-contradictions.md +6 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +19 -10
- package/package/corpus/skills/cratis-screenplay-toolchain/references/provenance.md +4 -2
- package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +8 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/sources-and-streams.md +90 -27
- package/package/corpus/skills/cratis-screenplay-toolchain/references/traps.md +10 -6
- package/package/corpus/skills/cratis-screenplay-toolchain/references/verdicts.md +29 -12
- package/package/corpus/skills/cratis-screenplay-toolchain/references/versions.md +91 -136
- package/package/corpus/skills/cratis-screenplay-toolchain/verification.json +7 -5
- package/package/corpus/skills/cratis-screenplay-ui-composition/references/screen-composition-contract.md +20 -0
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +9 -5
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +8 -1
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/verification.json +2 -2
- 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(
|
|
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(
|
|
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.
|
|
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(
|
|
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
|
|
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
|
-
-
|
|
32
|
-
-
|
|
33
|
-
|
|
34
|
-
|
|
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>`
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
-
|
|
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)"
|
|
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
|
|
15
|
-
|
|
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
|
|
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 |
|
|
68
|
+
| caller | n/a | declared reaction `runs as` actor (ESM v10), otherwise none |
|
|
69
69
|
|
|
70
70
|
## 4. The actor behind an invoke
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
|
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
|
-
-
|
|
62
|
-
`
|
|
63
|
-
|
|
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
|
|
44
|
-
|
|
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
|
|
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
|
|
26
|
-
|
|
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
|
|
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"
|
package/package/corpus/skills/cratis-screenplay-automations-and-translations/verification.json
CHANGED
|
@@ -4,13 +4,13 @@
|
|
|
4
4
|
"fixtures": [],
|
|
5
5
|
"assertions": [
|
|
6
6
|
{ "kind": "skill-contains", "value": "`[ExecuteCommandsAsSystem(\"<role>\")]`" },
|
|
7
|
-
{ "kind": "skill-contains", "value": "
|
|
8
|
-
{ "kind": "skill-contains", "value": "
|
|
9
|
-
{ "kind": "skill-contains", "value": "
|
|
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": "
|
|
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
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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`
|
|
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`?**
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
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);
|
|
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
|
|
355
|
-
|
|
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
|