@cratis/pi 7.66.0 → 7.68.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/product-sync.json +3 -3
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/realization-and-gap-fill.md +1 -1
- package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/atomic-batches-and-source-mappings.md +1 -1
- package/package/corpus/skills/cratis-screenplay-command-surface/SKILL.md +4 -3
- package/package/corpus/skills/cratis-screenplay-command-surface/references/date-comparisons.md +13 -2
- package/package/corpus/skills/cratis-screenplay-model-authoring/references/language-reference.md +2 -2
- package/package/corpus/skills/cratis-screenplay-model-authoring/references/state-and-recovery.md +1 -0
- package/package/corpus/skills/cratis-screenplay-model-review/references/checklist.md +1 -1
- package/package/corpus/skills/cratis-screenplay-model-review/references/public-keys-and-routes.md +4 -2
- package/package/corpus/skills/cratis-screenplay-model-review/references/report-template.md +2 -2
- package/package/corpus/skills/cratis-screenplay-modeling-lifecycle/SKILL.md +1 -1
- package/package/corpus/skills/cratis-screenplay-modeling-lifecycle/references/phases.md +1 -1
- package/package/corpus/skills/cratis-screenplay-modeling-lifecycle/references/stop-or-assume.md +1 -1
- package/package/corpus/skills/cratis-screenplay-modeling-lifecycle/references/verdicts-and-modes.md +6 -1
- package/package/corpus/skills/cratis-screenplay-projections/SKILL.md +8 -1
- package/package/corpus/skills/cratis-screenplay-projections/references/pdl-grammar.md +42 -2
- package/package/corpus/skills/cratis-screenplay-projections/references/reducer-identity.md +88 -0
- package/package/corpus/skills/cratis-screenplay-projections/verification.json +2 -1
- package/package/corpus/skills/cratis-screenplay-read-surface/SKILL.md +14 -7
- package/package/corpus/skills/cratis-screenplay-read-surface/references/equality-filters.md +1 -1
- package/package/corpus/skills/cratis-screenplay-read-surface/references/named-keys.md +168 -58
- package/package/corpus/skills/cratis-screenplay-read-surface/verification.json +2 -2
- package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/gap-fill-handoff.md +1 -1
- package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/renderability-gate.md +1 -1
- package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/scenario-examples.md +2 -2
- package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/spec-forms-by-mode.md +3 -3
- package/package/corpus/skills/cratis-screenplay-slice-design/SKILL.md +5 -7
- package/package/corpus/skills/cratis-screenplay-slice-design/references/public-boundaries-and-keys.md +5 -3
- package/package/corpus/skills/cratis-screenplay-slice-design/references/read-model-design.md +7 -3
- package/package/corpus/skills/cratis-screenplay-specifications/SKILL.md +3 -2
- package/package/corpus/skills/cratis-screenplay-specifications/references/query-rejections.md +4 -0
- package/package/corpus/skills/cratis-screenplay-specifications/references/vocabulary.md +17 -0
- package/package/corpus/skills/cratis-screenplay-streams-and-consistency/SKILL.md +3 -1
- package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/read-model-keys.md +46 -0
- package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +11 -5
- package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet.md +17 -2
- package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +22 -8
- package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +31 -9
- package/package/corpus/skills/cratis-screenplay-toolchain/references/language-admission.md +15 -5
- package/package/corpus/skills/cratis-screenplay-toolchain/references/production-routes-and-filters.md +1 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +3 -3
- package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.json +1722 -76
- package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.version +1 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/traps.md +3 -2
- package/package/corpus/skills/cratis-screenplay-toolchain/references/verdicts.md +64 -3
- package/package/corpus/skills/cratis-screenplay-toolchain/verification.json +8 -2
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +5 -4
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +12 -7
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/sandbox-and-specrunner.md +17 -0
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/verification.json +1 -1
- package/package.json +1 -1
|
@@ -39,72 +39,188 @@ Chronicle's object keys are not ordered, encoded event stream ids.
|
|
|
39
39
|
Choose a composite key when independent coordinates identify the business view,
|
|
40
40
|
such as resource and reporting period. Prefer the natural single id when the view
|
|
41
41
|
is one entity's state. Do not concatenate parts into an invented string id merely
|
|
42
|
-
to pass binding; keep the truthful model
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
to pass binding; keep the truthful model. Read-model keys do not supply projection
|
|
43
|
+
routes: align each PDL `from ... key` block with the declared parts (several flat
|
|
44
|
+
parts take an untyped `key` block naming every one; a single key of composite type
|
|
45
|
+
is a different shape, and one read model has exactly one of them).
|
|
45
46
|
|
|
46
47
|
## Supply every part
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
Requires Screenplay 4.204.0 (ESM v27; `screenplay --version`) to bind a read model with
|
|
50
|
+
two or more `key` marks; older binders refuse it with PLAY0268. A model with one `key`
|
|
51
|
+
mark keeps its earlier ESM version and bytes, so only models that use several parts
|
|
52
|
+
select v27.
|
|
53
|
+
|
|
54
|
+
A scalar query keeps `by name Type` on its own body line. Each lookup shape for a
|
|
55
|
+
composite-keyed read model is separate:
|
|
56
|
+
|
|
57
|
+
| Shape | Form | Result |
|
|
58
|
+
| --- | --- | --- |
|
|
59
|
+
| Optional single-instance query | bare `by` header, then every key part once as `name Type` | binds; the caller supplies every part |
|
|
60
|
+
| List query | equality `filter name Type [optional]` lines (one filter per narrowed part) | binds; a row matches when every supplied filter is equal |
|
|
61
|
+
| List query, one scalar `by` | `by name Type` on one line | binds as for a single key |
|
|
62
|
+
| List query with a `by` block | bare `by` header over a collection | PLAY0268: use filters |
|
|
63
|
+
| Non-optional single return, or a part with a `from` source | any `by` block | PLAY0268 |
|
|
64
|
+
| Missing part | any single-instance lookup | PLAY0661 |
|
|
65
|
+
| Unknown, optional, collection or ill-typed part; fewer than two parts | `by` block | PLAY0662 |
|
|
66
|
+
|
|
67
|
+
Do not combine scalar and block `by` forms. A caller-supplied part is never a trusted
|
|
68
|
+
tenant or subject: keep ownership at the runtime boundary.
|
|
69
|
+
|
|
70
|
+
Each `by` part runs its concept rules at execution, like a single `by` argument. A
|
|
71
|
+
specification argument that violates a rule still binds, so a Validation rejection
|
|
72
|
+
can be specified.
|
|
73
|
+
|
|
74
|
+
Command and trigger reads use a child `by` block of `part = source`, with required,
|
|
75
|
+
noncollection sources of compatible nominal types, not literals. Neither executes
|
|
76
|
+
over a composite view in the usual way:
|
|
77
|
+
|
|
78
|
+
- A command `reads … by` without the application-root `command reads protected`
|
|
79
|
+
preamble is PLAY0271. With the preamble it is PLAY0781 (reason ByParts), PLAY0782
|
|
80
|
+
first when the command has no `identifier`, and PLAY0273 when the key is not an
|
|
81
|
+
input property.
|
|
82
|
+
- A trigger `reads … by` binds when the reaction only invokes commands (information
|
|
83
|
+
PLAY0270); a reaction that produces events directly or runs code is PLAY0268.
|
|
53
84
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
single `reads View by value` form remains available for a single key.
|
|
85
|
+
Screen `data ... via query ... by value`, forms and navigation remain scalar
|
|
86
|
+
lookups: they cannot supply a composite single-instance key (PLAY0661). Do not
|
|
87
|
+
invent UI tuple syntax.
|
|
58
88
|
|
|
59
|
-
|
|
89
|
+
One executable example: a composite-keyed read model, a projection whose root `from`
|
|
90
|
+
and `remove with` name every part in an untyped `key` block, a list query with
|
|
91
|
+
equality filters, an optional single-instance query with a `by` block, and
|
|
92
|
+
specifications that run.
|
|
60
93
|
|
|
61
94
|
```screenplay
|
|
62
|
-
concept
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
95
|
+
concept InvoiceId : String
|
|
96
|
+
validate
|
|
97
|
+
min 3 message "Invoice id is too short"
|
|
98
|
+
concept PaymentMethod : Enum
|
|
99
|
+
card
|
|
100
|
+
cash
|
|
101
|
+
|
|
102
|
+
module Billing
|
|
103
|
+
feature Payments
|
|
66
104
|
slice StateView Totals
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
105
|
+
event PaymentReceived
|
|
106
|
+
invoice InvoiceId
|
|
107
|
+
method PaymentMethod
|
|
108
|
+
amount Int
|
|
109
|
+
event PaymentRemoved
|
|
110
|
+
invoice InvoiceId
|
|
111
|
+
method PaymentMethod
|
|
112
|
+
readmodel PaymentTotals
|
|
113
|
+
invoiceId InvoiceId key
|
|
114
|
+
method PaymentMethod key
|
|
115
|
+
total Int
|
|
116
|
+
query TotalsForInvoice => PaymentTotals[]
|
|
117
|
+
filter invoiceId InvoiceId
|
|
118
|
+
filter method PaymentMethod optional
|
|
119
|
+
query Total => PaymentTotals optional
|
|
72
120
|
by
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
121
|
+
invoiceId InvoiceId
|
|
122
|
+
method PaymentMethod
|
|
123
|
+
projection PaymentTotals => PaymentTotals
|
|
124
|
+
no automap
|
|
125
|
+
from PaymentReceived
|
|
126
|
+
key
|
|
127
|
+
invoiceId = invoice
|
|
128
|
+
method = method
|
|
129
|
+
total = amount
|
|
130
|
+
remove with PaymentRemoved
|
|
131
|
+
key
|
|
132
|
+
invoiceId = invoice
|
|
133
|
+
method = method
|
|
134
|
+
specification TwoMethodsOneInvoice
|
|
135
|
+
given readmodel PaymentTotals
|
|
136
|
+
invoiceId = "INV-1"
|
|
137
|
+
method = "card"
|
|
138
|
+
total = 12
|
|
139
|
+
given readmodel PaymentTotals
|
|
140
|
+
invoiceId = "INV-1"
|
|
141
|
+
method = "cash"
|
|
142
|
+
total = 8
|
|
143
|
+
when query Total
|
|
144
|
+
invoiceId = "INV-1"
|
|
145
|
+
method = "cash"
|
|
146
|
+
then result
|
|
147
|
+
total = 8
|
|
148
|
+
specification FilterOnePart
|
|
149
|
+
given readmodel PaymentTotals
|
|
150
|
+
invoiceId = "INV-1"
|
|
151
|
+
method = "card"
|
|
152
|
+
total = 12
|
|
153
|
+
given readmodel PaymentTotals
|
|
154
|
+
invoiceId = "INV-2"
|
|
155
|
+
method = "card"
|
|
156
|
+
total = 3
|
|
157
|
+
when query TotalsForInvoice
|
|
158
|
+
invoiceId = "INV-1"
|
|
159
|
+
then result
|
|
160
|
+
invoiceId = "INV-1"
|
|
161
|
+
method = "card"
|
|
162
|
+
total = 12
|
|
163
|
+
specification RemoveOneMethod
|
|
164
|
+
given readmodel PaymentTotals
|
|
165
|
+
invoiceId = "INV-1"
|
|
166
|
+
method = "card"
|
|
167
|
+
total = 12
|
|
168
|
+
given readmodel PaymentTotals
|
|
169
|
+
invoiceId = "INV-1"
|
|
170
|
+
method = "cash"
|
|
171
|
+
total = 8
|
|
172
|
+
when append PaymentRemoved
|
|
173
|
+
invoice = "INV-1"
|
|
174
|
+
method = "card"
|
|
175
|
+
then no readmodel PaymentTotals for {"invoiceId":"INV-1","method":"card"}
|
|
176
|
+
then readmodel PaymentTotals
|
|
177
|
+
invoiceId = "INV-1"
|
|
178
|
+
method = "cash"
|
|
179
|
+
total = 8
|
|
180
|
+
specification RecreateRemovedInstance
|
|
181
|
+
given PaymentReceived
|
|
182
|
+
invoice = "INV-1"
|
|
183
|
+
method = "card"
|
|
184
|
+
amount = 12
|
|
185
|
+
given PaymentRemoved
|
|
186
|
+
invoice = "INV-1"
|
|
187
|
+
method = "card"
|
|
188
|
+
when append PaymentReceived
|
|
189
|
+
invoice = "INV-1"
|
|
190
|
+
method = "card"
|
|
191
|
+
amount = 20
|
|
192
|
+
then readmodel PaymentTotals
|
|
193
|
+
invoiceId = "INV-1"
|
|
194
|
+
method = "card"
|
|
195
|
+
total = 20
|
|
86
196
|
```
|
|
87
197
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
keep tenant/subject ownership at the runtime boundary, not in editable UI filters.
|
|
198
|
+
Projection rules for the same shape are in the projections skill (`SKILL.md`, keys).
|
|
199
|
+
Verify with `screenplay <folder> --warnaserror` (0 errors, 0 warnings) and
|
|
200
|
+
`screenplay test <folder>` (all passed, none Unsupported).
|
|
92
201
|
|
|
93
202
|
## Specifications and executable boundary
|
|
94
203
|
|
|
95
|
-
`given readmodel` and `then readmodel` state every key part (PLAY0351 if missing
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
204
|
+
`given readmodel` and `then readmodel` state every key part (PLAY0351 if missing;
|
|
205
|
+
a repeated part is PLAY0519). `then no readmodel` takes an object naming every part
|
|
206
|
+
(missing PLAY0661, unknown PLAY0662, repeated member PLAY0294). Parts match one by
|
|
207
|
+
one, in any order; Uuid parts compare as ordinal text with no case folding. Query
|
|
208
|
+
arguments supply every `by` part (single) or the filters (list); a missing, unknown
|
|
209
|
+
or repeated argument is PLAY0468. A single-instance query result may omit parts the
|
|
210
|
+
arguments supply; list-query result rows state every part. A stated part that
|
|
211
|
+
differs from the argument makes the row fail to match at run time, not at binding.
|
|
212
|
+
|
|
213
|
+
Projections on a composite-keyed read model admit only root `from` and `remove with`.
|
|
214
|
+
Joins, `children`, `remove via join`, `every`, `all`, `nested`, `clear with`,
|
|
215
|
+
`variant` and reducers are PLAY0268. This is not ESM v10 admission.
|
|
216
|
+
|
|
217
|
+
Stage does not admit v27: it refuses the whole model with `STAGE-ESM-016`, so
|
|
218
|
+
`cratis render` cannot deliver it. Verify and reference-test the model with the
|
|
219
|
+
standalone compiler, then hand the delivery to gap-fill
|
|
220
|
+
(`cratis-screenplay-render-and-gap-fill`) with the model as the contract.
|
|
221
|
+
Eligible command reads separately opt into v25 with `command reads protected`;
|
|
222
|
+
a composite lookup there is still refused (PLAY0781 ByParts). See command-surface
|
|
223
|
+
[protected reads](../../cratis-screenplay-command-surface/references/protected-reads.md).
|
|
108
224
|
|
|
109
225
|
## Repairs and evidence
|
|
110
226
|
|
|
@@ -116,9 +232,3 @@ model and projection/query shape, not just the key modifier.
|
|
|
116
232
|
- Read-model property rename remains unsupported until its mapping chain can be
|
|
117
233
|
preserved. Use the model-authoring proposal/preview/apply contract, not a text
|
|
118
234
|
shortcut around an identity-preserving refusal.
|
|
119
|
-
|
|
120
|
-
Source: Screenplay `Documentation/screenplay/{readmodels,queries,commands,reactions,specifications}.md`,
|
|
121
|
-
`fixtures/named-read-model-keys.play`, and
|
|
122
|
-
`Source/DotNET/Screenplay/Semantics/SemanticModelBinder.ReadModels.cs` (identity inference).
|
|
123
|
-
Its authoring delivery does not include
|
|
124
|
-
an executable composite-key contract.
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
"input": "Declare a Screenplay query and the screen that binds to it.",
|
|
4
4
|
"fixtures": [],
|
|
5
5
|
"assertions": [
|
|
6
|
-
{ "kind": "skill-contains", "value": "query
|
|
6
|
+
{ "kind": "skill-contains", "value": "query Total => PaymentTotals optional", "file": "references/named-keys.md" },
|
|
7
7
|
{ "kind": "skill-contains", "value": "command reads only", "file": "references/named-keys.md" },
|
|
8
|
-
{ "kind": "skill-contains", "value": "
|
|
8
|
+
{ "kind": "skill-contains", "value": "Requires Screenplay 4.204.0 (ESM v27", "file": "references/named-keys.md" },
|
|
9
9
|
{ "kind": "play-compiles" },
|
|
10
10
|
{ "kind": "skill-contains", "value": "Caller-supplied equality query filters (ESM v14)", "file": "references/equality-filters.md" },
|
|
11
11
|
{ "kind": "skill-contains", "value": "Supplied `null` is refused", "file": "references/equality-filters.md" },
|
package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/gap-fill-handoff.md
CHANGED
|
@@ -108,7 +108,7 @@ reaction or drop an effect to dodge rendering.
|
|
|
108
108
|
Preserve declared `reaction batches atomic` boundaries: each trigger occurrence's
|
|
109
109
|
direct productions and each selected refusal branch are separate batches, with
|
|
110
110
|
invoked commands independent. Stage refuses v22 (STAGE-ESM-016) and atomic mode
|
|
111
|
-
in admitted v23–
|
|
111
|
+
in admitted v23–v26 (STAGE-ESM-043); the declaration is not external-effect deduplication.
|
|
112
112
|
For described handlers, hand off only payload computation under the v23 result
|
|
113
113
|
contract; Stage STAGE-IMPL-002 means no stubs, even Stub mode. Protected v25 reads
|
|
114
114
|
refuse Cratis C# rendering with STAGE-ESM-044 despite version admission and need
|
package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/renderability-gate.md
CHANGED
|
@@ -31,7 +31,7 @@ ESM). Only the probe answers renderability. `PLAY0270` entries are information,
|
|
|
31
31
|
| Class | Meaning | Typical examples (each verified in `admission.md`) | Action |
|
|
32
32
|
| --- | --- | --- | --- |
|
|
33
33
|
| **Model fix (in mode)** | the model is in, or the user chose, renderable mode and breaks its own subset in a way that has a renderable equivalent with the same meaning | a `produces` whose `for` is not the command identifier; two projections for one read model (`-007`); a policy Stage cannot express portably (`-015`; role-only and opaque pure policies render) | edit request to the modeler session with address, change and rationale |
|
|
34
|
-
| **Capability gap** | the intended meaning needs a construct Stage does not render yet | DateTime equality filters and required parameters after optional filters (`-010`); context/single-result filters, opaque `scoped to`/`performer` and
|
|
34
|
+
| **Capability gap** | the intended meaning needs a construct Stage does not render yet | DateTime equality filters and required parameters after optional filters (`-010`); context/single-result filters, opaque `scoped to`/`performer` and a list-query `by` block remain PLAY0268; a read model with several key parts (v27) refuses `STAGE-ESM-016`; Translate, clocks, captures, non-event triggers and opaque reaction bodies (`-024`); claim-reading/opaque `runs as` gates (`-034`), legacy `from` (`-035`), mixed effects in one handler (`-037`, retries can duplicate events; keep it whole), unsupported reaction mappings (`-039`); unsupported generated types/result combinations (`-028`/`-038`); `then no readmodel` (`-027`); evolved events (`STAGE-ESM-026`); unsupported expression/enum production conditions (`-006`; supported conditional productions render); legacy reads (`PLAY0271`), protected-read rendering (STAGE-ESM-044 despite v25 admission; semantic Host/executor support is separate); code validation (`-005`); protected identities/enums (`-040`) or unadmitted explicit subject lineage (`PLAY0268`); attached command handlers (PLAY0268), described handlers (v23, STAGE-IMPL-002 even Stub mode), atomic mode (STAGE-ESM-016 for v22, STAGE-ESM-043 in admitted v23–v26) | keep the model; fallback record entry; options a to c in `SKILL.md`; link the Stage issue |
|
|
35
35
|
| **Tool skew** | the bundled compiler disagrees with documented semantics | the false `PLAY0285` on reaction cascades from an older bundle; codes the standalone compiler does not raise | record in the session state and the fallback record; never "fix" a correct model |
|
|
36
36
|
| **Environment** | not the model | restore failures, missing SDK, a destination that is not writable | fix the environment or report blocked |
|
|
37
37
|
|
package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/scenario-examples.md
CHANGED
|
@@ -219,6 +219,6 @@ empty-list intent is a separate claim from a keyed row being absent (`view-and-s
|
|
|
219
219
|
queries are executable too (`ListOpenInvoices` in the backing example); caller-supplied equality filters on collections bind as ESM v14.
|
|
220
220
|
Pass `by` and filters in query arguments; PLAY0468 reports unknown, repeated or
|
|
221
221
|
missing required arguments. Optional filters may be omitted, supplied null is refused.
|
|
222
|
-
Context-sourced/single-result filters, opaque `scoped to`/`performer`, and
|
|
223
|
-
`by` remain PLAY0268. Compiled coverage and renderer ceilings:
|
|
222
|
+
Context-sourced/single-result filters, opaque `scoped to`/`performer`, and a list-query
|
|
223
|
+
`by` block remain PLAY0268. Compiled coverage and renderer ceilings:
|
|
224
224
|
read-surface [equality filters](../../cratis-screenplay-read-surface/references/equality-filters.md).
|
package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/spec-forms-by-mode.md
CHANGED
|
@@ -18,7 +18,7 @@ Typed example/override forms: `cratis-screenplay-specifications`
|
|
|
18
18
|
| `then readmodel` / `then query` (keyed `ById`, `arguments`, `result`) | yes | yes | yes |
|
|
19
19
|
| `then query` on an unfiltered list or a list narrowed by one `by` key (observable too) | yes | yes: no `arguments` for an unkeyed list, one `result` per row stating the read-model identifier, no `result` = empty list | snapshot and observable lists render |
|
|
20
20
|
| Collection query with caller-supplied equality `filter`, including observable | yes | yes, ESM v14: same-named scalar property/type, AND with `by`; optional omission allowed, supplied null refused; PLAY0468 checks arguments; row order does not matter | yes on supported snapshot/observable collections; DateTime/filter parameter order refuse -010; independent Stage executor still refuses filtered assertions (-010) |
|
|
21
|
-
| Context `from`, single-result filters, `scoped to`, `performer` or
|
|
21
|
+
| Context `from`, single-result filters, `scoped to`, `performer` or a list-query `by` block | yes | PLAY0268: query context, collection-only filtering, opaque scope/implementation or a multipart list lookup are unadmitted | no |
|
|
22
22
|
| `then no readmodel <RM> for "<key>"` | yes | yes | no |
|
|
23
23
|
| `when query` -> `then result` / `then no result` | yes | yes | same as `then query`: only the query-only cases below |
|
|
24
24
|
| `given clock` / `when clock`, `when trigger`, record-source `given`/`when capture` | yes | yes (standalone and any cratis whose compiler admits v6; an older bundle does not, see toolchain `references/executable-subset.md`) | no |
|
|
@@ -34,12 +34,12 @@ Typed example/override forms: `cratis-screenplay-specifications`
|
|
|
34
34
|
| Refusal branches, `$refusal` | yes | ESM v19; first matching branch wins | Stage supported subset; -039 for unfaithful refusal details/trigger groups, -011 for specification limits |
|
|
35
35
|
| Query `then error` | yes | ESM v18; one query/one error, no result/denial | requires target v18 admission; a v19-capable renderer does not necessarily admit v18 |
|
|
36
36
|
| Composite (JSON) values in specs | yes | yes | no |
|
|
37
|
-
| Same-primitive `Date`/`DateTime` comparisons in `require`, `produces when` and command or property validation rules (v26; Requires Screenplay 4.199.0; see [date comparisons](../../cratis-screenplay-command-surface/references/date-comparisons.md)) | spec them | binds and executes; a `DateTime` input without an offset is a Validation rejection |
|
|
37
|
+
| Same-primitive `Date`/`DateTime` comparisons in `require`, `produces when` and command or property validation rules (v26; Requires Screenplay 4.199.0; see [date comparisons](../../cratis-screenplay-command-surface/references/date-comparisons.md)) | spec them | binds and executes; a `DateTime` input without an offset is a Validation rejection | Host/executor run it (Requires Stage 4.135.0); renderer STAGE-ESM-046: gap-fill |
|
|
38
38
|
| Date rules using `today`, `$context`, mixed `Date`/`DateTime`, concept or reaction-`where` positions; nested paths | spec them in design | rule does not bind: `recorded` | `recorded` |
|
|
39
39
|
| Bodied rules, code policies | spec them | spec reported **unsupported**, never passed | no |
|
|
40
40
|
| Pending described command handlers (v23) | specify intent | binds; denial/validation execute, body-reaching specs Unsupported ImplementationBody; all-Unsupported is not green | STAGE-IMPL-002 even Stub mode |
|
|
41
41
|
| Attached command handlers, `file` constraints, query `performer`s | spec them in design | blocked: PLAY0268 at binding, no spec runs (V3 blocked) | no |
|
|
42
|
-
| Atomic reaction mode (v22) | declare for new models | failed batch adds no facts or view changes; earlier batches/commands remain; `then error` alone is insufficient | v22 STAGE-ESM-016; mode in admitted v23–
|
|
42
|
+
| Atomic reaction mode (v22) | declare for new models | failed batch adds no facts or view changes; earlier batches/commands remain; `then error` alone is insufficient | v22 STAGE-ESM-016; mode in admitted v23–v26 STAGE-ESM-043 |
|
|
43
43
|
| Protected command reads (v25) | declare opt-in for eligible reads | absence Validation; matching intervening facts Conflict; race vectors are not a new spec construct | Cratis C# rendering STAGE-ESM-044; semantic Host/executor execute admitted reads, non-Error protected requirements STAGE-ESM-045; v25 pair admitted |
|
|
44
44
|
|
|
45
45
|
Requires Screenplay 4.105.0 or later (`screenplay --version`) for list-query specifications, and 4.143.0 or later for collection equality filters (ESM v14).
|
|
@@ -38,8 +38,7 @@ Ask the batch below only for what the request leaves open: (1) origin of each ac
|
|
|
38
38
|
## Procedure
|
|
39
39
|
|
|
40
40
|
1. **Fix the mode** for the scope (`cratis-screenplay-modeling-lifecycle`): design, executable
|
|
41
|
-
or renderable. It decides which shapes you may use (steps 6, 9). Read the existing model
|
|
42
|
-
before adding to it.
|
|
41
|
+
or renderable. It decides which shapes you may use (steps 6, 9). Read the existing model first.
|
|
43
42
|
2. **Find each event's origin.** For every event ask who or what makes it happen and through
|
|
44
43
|
which path: a persona's screen `action` or form, a reaction's `invokes`, a capture. The
|
|
45
44
|
origin must be **reachable** (some screen, form, reaction or integration leads to the
|
|
@@ -54,8 +53,7 @@ Ask the batch below only for what the request leaves open: (1) origin of each ac
|
|
|
54
53
|
separate reasons change these values, then split (`references/slicing.md` *Generic edits*).
|
|
55
54
|
One input per thing the caller decides or supplies; `identifier` on the property naming the
|
|
56
55
|
instance (omit only for allocation); inline `produces event <Name>` (no `for`) when the command owns the event; plain `produces <Name>` needs `for <identifier>`. Trace each input
|
|
57
|
-
(`references/field-lineage.md`) and list the values each rule reads: input, state or context
|
|
58
|
-
(`references/command-inventory.md`). A conditional input is a granularity question: two
|
|
56
|
+
(`references/field-lineage.md`) and list the values each rule reads: input, state or context. A conditional input is a granularity question: two
|
|
59
57
|
decisions are two commands; one decision with a dependent rule is an implication
|
|
60
58
|
(`require a == false or b > c`). Never a boolean attestation input (`confirmsX == true`)
|
|
61
59
|
standing in for a rule. Place each rule in its layer (`references/rule-layers.md`). A rule
|
|
@@ -89,7 +87,7 @@ Ask the batch below only for what the request leaves open: (1) origin of each ac
|
|
|
89
87
|
6. **Design the read side** (`references/read-model-design.md`). Enumerate every screen and
|
|
90
88
|
automation first: one read model per screen component or automation need; the typical
|
|
91
89
|
slice is `read model -> screen -> command -> event`. Pick the builder (declarative projection first, reducer when
|
|
92
|
-
guards cannot be expressed). The query follows the business view: a list where people scan a
|
|
90
|
+
guards cannot be expressed; a lookup `by` another identity type warns `PLAY0690`). The query follows the business view: a list where people scan a
|
|
93
91
|
list, a keyed lookup where they open one thing. For **executable or renderable scope**, every
|
|
94
92
|
read model needs one unambiguous identity: explicit trailing `key` first. Read `references/read-model-design.md` ("Executable identity of a read model") for the fallback order, the key decision table and the Stage rule.
|
|
95
93
|
|
|
@@ -122,7 +120,7 @@ Ask the batch below only for what the request leaves open: (1) origin of each ac
|
|
|
122
120
|
|
|
123
121
|
- At most one `identifier` per command; never on an event property or read-model property (use `key`). At most one builder per read model (`PLAY0191`). Read `references/read-model-design.md` ("Identifier and key contract") for the exact rules.
|
|
124
122
|
|
|
125
|
-
- A query's `by` goes on its own body line; `from`, single-result filters, scope, performer and
|
|
123
|
+
- A query's `by` goes on its own body line; `from`, single-result filters, scope, performer and a list-query `by` block remain `PLAY0268`; equality filters on collections bind as ESM v14. Read `references/read-model-design.md` ("Query binding") for the binding rules.
|
|
126
124
|
|
|
127
125
|
- A `unique` constraint names a property the event declares directly; the constraint name is
|
|
128
126
|
its identity (renaming starts an empty index).
|
|
@@ -146,7 +144,7 @@ collections, invariants, who sees which rows); report a finding only with a doma
|
|
|
146
144
|
|
|
147
145
|
## Public boundaries and view identity
|
|
148
146
|
|
|
149
|
-
Translate crosses an application boundary (inbound consumes foreign public events; outbound folds private facts into exactly one local public event type); commands never publish public events. Mark view identity with trailing `key`; composite view keys
|
|
147
|
+
Translate crosses an application boundary (inbound consumes foreign public events; outbound folds private facts into exactly one local public event type); commands never publish public events. Mark view identity with trailing `key`; flat composite view keys bind as ESM v27 (Requires Screenplay 4.204.0) - keep the true identity. Read [references/public-boundaries-and-keys.md](references/public-boundaries-and-keys.md) when a slice crosses an application boundary or a view needs a composite identity.
|
|
150
148
|
|
|
151
149
|
## Identity-affecting edits on an existing model
|
|
152
150
|
|
|
@@ -11,6 +11,8 @@ the slice outline and trace every exported field; read automations-and-translati
|
|
|
11
11
|
Mark view identity with trailing `key`. Use a composite key for independent view
|
|
12
12
|
coordinates (resource + period), a natural single id for one entity's state.
|
|
13
13
|
Supply every named part in single-instance queries and command/trigger reads;
|
|
14
|
-
see read-surface `references/named-keys.md`.
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
see read-surface `references/named-keys.md`. Flat composite view keys bind as ESM v27
|
|
15
|
+
(older binders refuse with PLAY0268; compiler requirement in named-keys), as do composite
|
|
16
|
+
stream routes. Command and trigger reads by parts stay refused, and Stage does not admit
|
|
17
|
+
v27. Keep the true identity rather than inventing a concatenated id; choosing between
|
|
18
|
+
shapes: streams-and-consistency `references/read-model-keys.md`.
|
package/package/corpus/skills/cratis-screenplay-slice-design/references/read-model-design.md
CHANGED
|
@@ -130,7 +130,10 @@ Observable delivery does not make a materialized projection decision-consistent;
|
|
|
130
130
|
decision needs a guarded read (`rule-layers.md`, `cratis-screenplay-streams-and-consistency`). Prefer a
|
|
131
131
|
declarative projection (mappings, event joins, counters, bounded children, removals); a join
|
|
132
132
|
consumes event facts, not another read model. Use a reducer when prior-state, attempt or
|
|
133
|
-
ordering guards cannot be expressed declaratively
|
|
133
|
+
ordering guards cannot be expressed declaratively, and the view is only ever looked up by the
|
|
134
|
+
event-source identity: a reducer cannot be re-keyed, so a query `by` another identity type warns
|
|
135
|
+
`PLAY0690`; aggregate by a payload value with a projection keyed on each `from`, or a join
|
|
136
|
+
(projections [reducer identity](../../cratis-screenplay-projections/references/reducer-identity.md)). Review every writer of a property: AutoMap
|
|
134
137
|
can introduce updates from other events. Use variants only when lifecycle stages have different
|
|
135
138
|
shapes. Keep growing histories in a separate view; never combine several people's PII under
|
|
136
139
|
one read-model instance (compose queries across person-scoped views instead).
|
|
@@ -327,8 +330,9 @@ module Berths
|
|
|
327
330
|
- A query's `by` goes on its own body line. Optional keyed and collection queries
|
|
328
331
|
bind, including observable delivery. Caller-supplied equality filters on collections
|
|
329
332
|
bind as ESM v14; `by` ANDs with supplied filters. `from`, single-result
|
|
330
|
-
filters, scope, performer and
|
|
331
|
-
context/cardinality/opaque/multipart gaps.
|
|
333
|
+
filters, scope, performer and a `by` block on a list query remain PLAY0268 for their
|
|
334
|
+
respective context/cardinality/opaque/multipart gaps. A composite-keyed optional
|
|
335
|
+
single-instance query takes a `by` block naming every part (ESM v27). Read read-surface
|
|
332
336
|
[equality filters](../../cratis-screenplay-read-surface/references/equality-filters.md).
|
|
333
337
|
|
|
334
338
|
## Executable identity of a read model
|
|
@@ -175,8 +175,9 @@ Use `when append <PrivateEvent>` then `then <PublicEvent>`, not `then readmodel`
|
|
|
175
175
|
follow-up events are exhaustive and ordered. Read
|
|
176
176
|
[publication and fold cases](../cratis-screenplay-automations-and-translations/references/public-events-and-direction.md)
|
|
177
177
|
when specifying outbound facts or event-source captures: it owns the minimum
|
|
178
|
-
compiler, PLAY0700/0701, key folding and Unsupported boundaries. Composite
|
|
179
|
-
fixtures
|
|
178
|
+
compiler, PLAY0700/0701, key folding and Unsupported boundaries. Composite-keyed
|
|
179
|
+
view fixtures state every key part (Requires Screenplay 4.204.0, ESM v27); see
|
|
180
|
+
`references/vocabulary.md` and read-surface `references/named-keys.md`.
|
|
180
181
|
|
|
181
182
|
## Reusable fixtures, routes and recovery intent
|
|
182
183
|
|
package/package/corpus/skills/cratis-screenplay-specifications/references/query-rejections.md
CHANGED
|
@@ -10,6 +10,10 @@ through their concept's `validate` rules in every ESM version. An omitted option
|
|
|
10
10
|
filter is not validated. A violation is a Validation rejection carrying the rule's
|
|
11
11
|
message; a valid key with no matching instance is absence.
|
|
12
12
|
|
|
13
|
+
On a composite-keyed read model every `by` part of a single-instance query is validated
|
|
14
|
+
the same way; an argument that breaks a part's concept rule binds and rejects with
|
|
15
|
+
Validation (Requires Screenplay 4.204.0, ESM v27).
|
|
16
|
+
|
|
13
17
|
Use exactly one query request and one `then error`, bare or with a message. No
|
|
14
18
|
command/append/reaction action, result, `then no result` or `then denied` may
|
|
15
19
|
accompany it (PLAY0465). An actionless `then query` with `arguments` and no `result`
|
|
@@ -35,6 +35,23 @@ This reference holds the given/when/then construct table and the enumeration and
|
|
|
35
35
|
| `for <value>` | the event source of a `given`/`then` event, or of the `when` command or appended event |
|
|
36
36
|
| `<property> = <value>` | a literal, `null`, or a one-line JSON-shaped object or list: `lines = [{"sku":"A-1","quantity":2}]` |
|
|
37
37
|
|
|
38
|
+
## Composite-keyed read models
|
|
39
|
+
|
|
40
|
+
Requires Screenplay 4.204.0 (ESM v27; `screenplay --version`); older binders refuse a
|
|
41
|
+
read model with two or more `key` marks, and every specification over it, with PLAY0268.
|
|
42
|
+
|
|
43
|
+
- `given readmodel` and `then readmodel` state every key part (missing part PLAY0351,
|
|
44
|
+
repeated part PLAY0519).
|
|
45
|
+
- `then no readmodel <Type> for {"part":"value",...}` names every part (missing PLAY0661,
|
|
46
|
+
unknown PLAY0662, repeated member PLAY0294).
|
|
47
|
+
- `when query` or `then query … arguments` supplies every `by` part of a single-instance
|
|
48
|
+
query, or the equality filters of a list query (missing, unknown or repeated PLAY0468).
|
|
49
|
+
- A single-instance `then result` may omit parts the arguments supply; list rows state
|
|
50
|
+
every part. A stated part that disagrees with the argument fails to match at run time.
|
|
51
|
+
- Parts match one by one in any order; Uuid parts compare as ordinal text.
|
|
52
|
+
|
|
53
|
+
The complete model with these specifications is in read-surface `references/named-keys.md`.
|
|
54
|
+
|
|
38
55
|
## Parse and binding diagnostics
|
|
39
56
|
|
|
40
57
|
PLAY0358 is a syntax error; PLAY0388 also occurs at parse time for extra text
|
|
@@ -138,6 +138,8 @@ Requires Chronicle 19.59.6 or later (19.59.3 for the InMemory provider) for the
|
|
|
138
138
|
|
|
139
139
|
**Modeling defaults** (deviate with a recorded reason)
|
|
140
140
|
- One business identity per stream; cross-stream references are payload properties.
|
|
141
|
+
- A read model's key is not a stream identity. Read [references/read-model-keys.md](references/read-model-keys.md)
|
|
142
|
+
when choosing one id, flat composite key parts (v27) or a composite-typed key.
|
|
141
143
|
- Copy the source id into the payload only when a consumer needs it as a value.
|
|
142
144
|
- Give each invariant an authoritative atomic decision point and inspect every path that could
|
|
143
145
|
violate it. A constraint violation rejects that command's whole append set; a reaction cascade
|
|
@@ -145,7 +147,7 @@ Requires Chronicle 19.59.6 or later (19.59.3 for the InMemory provider) for the
|
|
|
145
147
|
- New models declare `reaction batches atomic`: direct productions per trigger
|
|
146
148
|
occurrence and each selected refusal branch are separate batches; invoked commands
|
|
147
149
|
stay independent. Legacy absence retains per-fact appends. Stage refuses v22
|
|
148
|
-
with STAGE-ESM-016 and atomic mode in admitted v23–
|
|
150
|
+
with STAGE-ESM-016 and atomic mode in admitted v23–v26 with STAGE-ESM-043. Read
|
|
149
151
|
[atomic boundaries](../cratis-screenplay-captures-and-reactions/references/atomic-batches-and-source-mappings.md)
|
|
150
152
|
when defining failure rollback; batching is not redelivery deduplication.
|
|
151
153
|
- Match duplicate protection to scope. A property constraint lets a source re-claim its own
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<!-- Copyright (c) Cratis. All rights reserved. -->
|
|
2
|
+
<!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
|
|
3
|
+
|
|
4
|
+
# Read-model keys: one id, flat parts or a composite-typed key
|
|
5
|
+
|
|
6
|
+
Requires Screenplay 4.204.0 (ESM v27; `screenplay --version`) for a read model with two or
|
|
7
|
+
more `key` marks; older binders refuse it with PLAY0268. A read model with one `key` mark
|
|
8
|
+
keeps its earlier version and bytes.
|
|
9
|
+
|
|
10
|
+
A read model's key says which instance a lookup or projection reaches. It is not a stream
|
|
11
|
+
identity and not an atomic decision point: choose it after the streams, and keep invariants
|
|
12
|
+
in constraints and commands.
|
|
13
|
+
|
|
14
|
+
## Choose the shape
|
|
15
|
+
|
|
16
|
+
| Business shape | Key | Why |
|
|
17
|
+
| --- | --- | --- |
|
|
18
|
+
| The view is one entity's state | One natural `key` property (default) | Binds on every supported version, and the event source usually supplies it |
|
|
19
|
+
| Independent coordinates identify the view (resource and period, plant and field), read by filtering on some parts or by all parts | Several flat `key` properties (v27) | Each part keeps its name and type; a list narrows by any part with equality filters |
|
|
20
|
+
| One value object already identifies the entity everywhere (it is also a command or event value) | One `key` property whose type is a composite `type` | Executes on earlier versions; projections use a typed `key TypeName` block |
|
|
21
|
+
|
|
22
|
+
A read model has exactly one of the two composite shapes: mixing flat parts with a
|
|
23
|
+
composite-typed key is PLAY0660, though one application may hold read models of both.
|
|
24
|
+
Do not concatenate parts into a string id to avoid a composite key, and do not invent a
|
|
25
|
+
composite type only to carry flat parts: both hide the identity the model should state.
|
|
26
|
+
|
|
27
|
+
## What flat parts do and do not do
|
|
28
|
+
|
|
29
|
+
- **Equality is per part**, in any order. Uuid parts compare as ordinal text with no case
|
|
30
|
+
folding, so write one spelling of each uuid in events, fixtures and query arguments.
|
|
31
|
+
- **A projection names every part** in an untyped `key` block on each root `from` and
|
|
32
|
+
`remove with`. The parts come from the event payload; they need not match the event
|
|
33
|
+
source. `remove with` deletes one instance and a later `from` recreates it.
|
|
34
|
+
- **A composite key does not enforce uniqueness.** Two events can still claim the same
|
|
35
|
+
part values; use a `unique` constraint over the same properties when the store must
|
|
36
|
+
refuse the duplicate (`references/consistency-and-concurrency.md`).
|
|
37
|
+
- **Lookups.** An optional single-instance query names every part in a `by` block; a list
|
|
38
|
+
uses equality filters. A command or reaction that must read the view by parts is refused
|
|
39
|
+
(PLAY0271, PLAY0781 ByParts, or PLAY0268 for a producing reaction), so decide on a stream
|
|
40
|
+
the command owns instead, or restructure the read. Do not drop the read to bind.
|
|
41
|
+
- **Limits.** Joins, `children`, `nested`, `every`, `all`, `variant` and reducers on the
|
|
42
|
+
composite-keyed view are PLAY0268. Stage refuses v27 with STAGE-ESM-016, so deliver it
|
|
43
|
+
through gap-fill with the model as the contract.
|
|
44
|
+
|
|
45
|
+
Read read-surface `references/named-keys.md` for one complete executable example and the
|
|
46
|
+
projections skill `references/pdl-grammar.md` for the key block syntax.
|
|
@@ -39,6 +39,10 @@ superseded statement needs context; exceptions do not change the contract.
|
|
|
39
39
|
2. **Check the folder, warnings as errors.** `screenplay <folder> --warnaserror` or
|
|
40
40
|
`cratis screenplay validate <folder> --warnings-as-errors`. Warnings hide defects:
|
|
41
41
|
PLAY0029 (a misspelt keyword or a `type` inside a slice) drops a construct silently.
|
|
42
|
+
A committed `screenplay.json` at the model root declares the repository's gate (checks, warnings
|
|
43
|
+
as errors, scope, open questions): run without repeating those flags (confirm with
|
|
44
|
+
`--print-gate` before dropping `--warnaserror`), read it with
|
|
45
|
+
`--print-gate`, and treat a refused file as "could not run" (`references/verdicts.md`).
|
|
42
46
|
3. **Pick the compiler deliberately and name it.** Standalone `screenplay` for
|
|
43
47
|
language checks and reference specifications; `cratis` for rendering
|
|
44
48
|
and generation. Report both tool and version, rather than transferring a verdict across
|
|
@@ -63,6 +67,7 @@ superseded statement needs context; exceptions do not change the contract.
|
|
|
63
67
|
| --- | --- | --- |
|
|
64
68
|
| Check root | `screenplay <root> --warnaserror --no-color` | `cratis screenplay validate <root> --warnings-as-errors -o json-compact` |
|
|
65
69
|
| Scope/checks | `--scope <address>`, `--check <names>`; a scoped pass is not whole-application success | `validate --executable` (bundled binder, no write), `--check <names>`, `--scope`; `render --scope`/`--check`; `cratis screenplay conform` |
|
|
70
|
+
| Declared gate | `screenplay <root> --print-gate`, `--format json`, `--no-gate-file` | `validate <root> --print-gate`, `--no-gate-file`; the same `screenplay.json` |
|
|
66
71
|
| Reference execution | `screenplay test <root>` or MCP `run-specifications` | Discover bundled MCP capability; target tests are not V4 |
|
|
67
72
|
| MCP | `screenplay mcp <root>`; discover schemas | `cratis screenplay mcp [root]`; registered by `cratis ai install` |
|
|
68
73
|
| Render boundary | Binder admission is not Stage admission | The CLI renders only ESM versions it knows; a newer bound model gets `CLI-RENDER-004` |
|
|
@@ -101,7 +106,7 @@ changes with the root folder name.
|
|
|
101
106
|
- **Executable** (binds, V3): `references/executable-subset.md`. Optional keyed lookups, unfiltered
|
|
102
107
|
lists and lists narrowed by one `by` key (observable too) bind; caller-supplied equality
|
|
103
108
|
filters on collections bind as ESM v14. Context `from`, single-result
|
|
104
|
-
filters, opaque `scoped to`/`performer` and
|
|
109
|
+
filters, opaque `scoped to`/`performer` and a `by` block on a list query remain PLAY0268. Read
|
|
105
110
|
read-surface [equality filters](../cratis-screenplay-read-surface/references/equality-filters.md).
|
|
106
111
|
Pending handlers beside unconditional productions bind as described commands (v23),
|
|
107
112
|
but reached bodies are Unsupported; attached handlers remain PLAY0268.
|
|
@@ -120,9 +125,10 @@ changes with the root folder name.
|
|
|
120
125
|
- **Public contracts and routes (v9/v10/v11):** public contracts and direction select v9;
|
|
121
126
|
reaction identity, production overrides and observer filters select v10;
|
|
122
127
|
qualifying retained non-route Double literals select v11.
|
|
123
|
-
|
|
124
|
-
`key`
|
|
125
|
-
`references/
|
|
128
|
+
Flat composite read-model keys select v27 (Requires Screenplay 4.204.0; older binders
|
|
129
|
+
report PLAY0268); one explicit `key` keeps its earlier version. Read
|
|
130
|
+
`references/production-routes-and-filters.md`, [language admission](references/language-admission.md)
|
|
131
|
+
and read-surface `references/named-keys.md`.
|
|
126
132
|
- **Enum numbers (v12):** read command-surface `references/enum-numbers.md` for
|
|
127
133
|
pins, stored numbers and Stage output; `references/diagnostics.md` owns PLAY0667–0671.
|
|
128
134
|
- **Concept strategies (v15):** read
|
|
@@ -189,7 +195,7 @@ Read [references/diagnostics.md](references/diagnostics.md) when a PLAY, STAGE o
|
|
|
189
195
|
7. Mark read-model identity with trailing `key`, not `identifier`. Otherwise single-instance
|
|
190
196
|
queries must agree on `by`; only with none and an admitted list query can `*Id`
|
|
191
197
|
inference run. Queryless views need `key` (read-surface `references/named-keys.md`).
|
|
192
|
-
Align projection keys
|
|
198
|
+
Align projection keys; several parts need an untyped `key` block (v27).
|
|
193
199
|
8. Projection `key` routes only on `from`; joins never create; `all` is per source.
|
|
194
200
|
9. `null` only for optional read-model properties in specifications.
|
|
195
201
|
10. `then` events are exhaustive and ordered; after `when append` they list only what followed.
|