@cratis/pi 6.2.0 → 6.3.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 (22) hide show
  1. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/SKILL.md +90 -15
  2. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/verification.json +5 -1
  3. package/package/corpus/skills/cratis-screenplay-command-surface/SKILL.md +162 -64
  4. package/package/corpus/skills/cratis-screenplay-command-surface/references/context.md +20 -8
  5. package/package/corpus/skills/cratis-screenplay-command-surface/verification.json +33 -1
  6. package/package/corpus/skills/cratis-screenplay-event-modeling/SKILL.md +63 -31
  7. package/package/corpus/skills/cratis-screenplay-event-modeling/references/nine-steps.md +35 -13
  8. package/package/corpus/skills/cratis-screenplay-event-modeling/verification.json +12 -0
  9. package/package/corpus/skills/cratis-screenplay-model-authoring/SKILL.md +50 -9
  10. package/package/corpus/skills/cratis-screenplay-model-authoring/references/language-reference.md +78 -22
  11. package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-tools.md +21 -5
  12. package/package/corpus/skills/cratis-screenplay-model-authoring/verification.json +16 -0
  13. package/package/corpus/skills/cratis-screenplay-projections/SKILL.md +155 -43
  14. package/package/corpus/skills/cratis-screenplay-projections/references/pdl-grammar.md +81 -37
  15. package/package/corpus/skills/cratis-screenplay-projections/verification.json +6 -1
  16. package/package/corpus/skills/cratis-screenplay-read-surface/SKILL.md +64 -17
  17. package/package/corpus/skills/cratis-screenplay-read-surface/verification.json +4 -1
  18. package/package/corpus/skills/cratis-screenplay-specifications/SKILL.md +201 -115
  19. package/package/corpus/skills/cratis-screenplay-specifications/verification.json +13 -1
  20. package/package/corpus/skills/cratis-screenplay-ui-composition/SKILL.md +133 -24
  21. package/package/corpus/skills/cratis-screenplay-ui-composition/verification.json +4 -1
  22. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "skill": "cratis-screenplay-command-surface",
3
- "input": "Declare a Screenplay command with validation, authorization and concurrency.",
3
+ "input": "Declare a Screenplay command with validation, authorization, a uniqueness constraint and a state-dependent rule.",
4
4
  "fixtures": [],
5
5
  "assertions": [
6
6
  {
@@ -26,6 +26,38 @@
26
26
  {
27
27
  "kind": "skill-contains",
28
28
  "value": "`identifier` on an **event** property is an error"
29
+ },
30
+ {
31
+ "kind": "skill-contains",
32
+ "value": "`reads` is not a protected read"
33
+ },
34
+ {
35
+ "kind": "skill-contains",
36
+ "value": "Adding a\n`concurrency` block does not fix this"
37
+ },
38
+ {
39
+ "kind": "skill-contains",
40
+ "value": "Validation severity is not compiler severity"
41
+ },
42
+ {
43
+ "kind": "skill-contains",
44
+ "value": "Chronicle's constraints enforce **uniqueness only**"
45
+ },
46
+ {
47
+ "kind": "skill-contains",
48
+ "value": "Do not use `constraint … file <Path>` for other rules"
49
+ },
50
+ {
51
+ "kind": "skill-contains",
52
+ "value": "combine with AND, in authored"
53
+ },
54
+ {
55
+ "kind": "skill-contains",
56
+ "value": "(`PLAY0441`)"
57
+ },
58
+ {
59
+ "kind": "skill-contains",
60
+ "value": "never both (`PLAY0440`)"
29
61
  }
30
62
  ]
31
63
  }
@@ -32,11 +32,14 @@ source is the single flow model.
32
32
 
33
33
  | Package | Version | Purpose |
34
34
  | --- | --- | --- |
35
- | `Cratis.Screenplay` | `4.12.1` | Compiler: parser, validator, diagnostics, folder merge, semantic binder |
36
- | `Cratis.Screenplay.Tool` | `4.12.1` | The `screenplay` dotnet tool |
35
+ | `Cratis.Screenplay` | `4.31.0` | Compiler: parser, validator, diagnostics, folder merge, semantic binder |
36
+ | `Cratis.Screenplay.Tool` | `4.31.0` | The `screenplay` dotnet tool |
37
37
 
38
- Read from the Screenplay repository at tag `v4.12.1` (commit `122eee8`). Reverify
39
- before claiming another version behaves the same.
38
+ Checked against the Screenplay repository at tag `v4.31.0` (commit `355dffb`):
39
+ `Documentation/screenplay/{slices,commands,folders,printing,interactions,specifications}.md`,
40
+ `projections/keys.md`, and decisions 0001 to 0014. The examples in
41
+ [nine-steps.md](references/nine-steps.md) compile with that version's compiler.
42
+ Reverify before claiming another version behaves the same.
40
43
 
41
44
  > **Method lineage.** The two-phase process, the nine steps, the four patterns and
42
45
  > the GWT discipline follow **Event Modeling** (Adam Dymitruk; Martin Dilger,
@@ -83,9 +86,9 @@ Every behavior is exactly one. An unknown slice type is a compile error:
83
86
  appear as many times as the behavior needs. Only `description` is limited to one.
84
87
 
85
88
  **Automation has four required components** — a triggering occurrence, the state
86
- it consults, conditional logic, and a resulting command or event. If the events
87
- are always unconditionally co-produced, it is **not** an automation: model it as
88
- one `StateChange` slice with several `produces` blocks.
89
+ it consults (the trigger's `reads`), conditional logic, and a resulting command
90
+ or event. If the events are always unconditionally co-produced, it is **not** an
91
+ automation: model it as one `StateChange` slice with several `produces` blocks.
89
92
 
90
93
  **Translation is workflow-specific anti-corruption.** Generic infrastructure every
91
94
  workflow needs (event persistence, message transport) is not a `Translate` slice.
@@ -96,11 +99,16 @@ Two divergences matter, and getting them wrong produces a model that will not
96
99
  compile or will not be safe. Both are deliberate.
97
100
 
98
101
  - **A command may read state.** The generic method forbids `ReadModel → Command`
99
- edges. Screenplay ships `reads <ReadModel> [by <property>]` on a command
100
- precisely so a state-dependent rule can be decided under concurrency. Use it for
101
- genuine consistency boundaries, and pair it with `concurrency` so the decision is
102
- enforced at append time rather than merely consulted. Do not use it to fetch
103
- data the command could carry as input.
102
+ edges. Screenplay ships `reads <ReadModel> [as <alias>] [by <property>]` so the
103
+ model shows what a state-dependent decision consulted. **It is not a protected
104
+ read today:** nothing checks at append time that the state is still current,
105
+ the executable model rejects `reads` and `concurrency` (`PLAY0271`), and adding
106
+ `concurrency` does not make the decision safe (decision 0003, Screenplay #129).
107
+ Model uniqueness as a `unique` constraint; for any other state-dependent rule,
108
+ record that the target must enforce it consistently. Do not use `reads` to
109
+ fetch data the command could carry as input. A reaction trigger declares the
110
+ views an automation decides from with the same `reads`, and the same caveat
111
+ applies.
104
112
  - **Some validation *does* belong in the model.** The generic method routes format
105
113
  rules to the type system. Screenplay's type system *is* the `concept`, and a
106
114
  concept carries its own `validate` block — so a format rule lives on the concept
@@ -122,7 +130,7 @@ compile or will not be safe. Both are deliberate.
122
130
  `Created`. One purpose per event; an event needing an optional property to cover
123
131
  two situations is two events.
124
132
  - **The event-source identity is never an event property.** The command binds it
125
- with `identifier` on exactly one property; marking an *event* property
133
+ with `identifier` on at most one property; marking an *event* property
126
134
  `identifier` is an error: *an event never carries its event source id*.
127
135
  - **Domain facts, not runtime context.** Test: would this field have the same value
128
136
  if the event were replayed on a different machine? If not, it does not belong.
@@ -170,8 +178,13 @@ produced in another resolves. Compiling files individually reports unknown types
170
178
  events and policies (`PLAY0165`, `PLAY0166`, `PLAY0167`) that are not missing.
171
179
  Duplicates *across* files are real errors naming both ends (`PLAY0172`, `PLAY0173`).
172
180
 
173
- Round-tripping a folder does not preserve **declaration order** — modules, features
174
- and slices come back sorted by name. Never encode meaning in order.
181
+ Round-tripping a folder does not preserve the order of **modules, features and
182
+ slices**: they come back sorted by name, and members of one module or feature
183
+ that come from different files print in canonical kind order. Order *within* one
184
+ file is kept, and some order carries meaning: `authorize` gates and policy
185
+ operands evaluate left to right, and specification events compare in authored
186
+ order unless `then events in any order` is stated. Never encode meaning in the
187
+ order of modules, features or slices.
175
188
 
176
189
  ## Verify
177
190
 
@@ -188,26 +201,45 @@ screenplay .cratis/screenplay/ --warnaserror
188
201
  - [ ] Personal data is classified on the `concept`, with a reason.
189
202
  - [ ] Specifications name the rejections, not only the happy path.
190
203
  - [ ] If the model must reach a runtime, every slice is `StateChange` or
191
- `StateView` and stays inside the admitted vertical (below).
204
+ `StateView` and binds to the executable model (below).
192
205
 
193
206
  ## Parsed is not runnable
194
207
 
195
208
  The compiler accepts far more than anything executes. Between the syntax tree and
196
- any runtime sits the **executable semantic model (ESM v1)**, and it fails closed.
197
- `SemanticSliceKind` has exactly three members — `Unknown = -1`, `StateChange`,
198
- `StateView` — so an `Automation` or `Translate` slice is rejected outright:
199
- *Slice '<name>' of type '<type>' is not admitted by ESM v1.*
200
-
201
- **Exactly 40 constructs** bind to `UnsupportedSemanticSyntax` (`PLAY0268`) rather
202
- than to a weaker model — imports, policies, personas, triggers, `authorize`, event
203
- and produced-event tags, conditional `produces … when`, code-backed validation,
204
- query filters/scope/performers, `@pii` concepts, projection parent keys, reducers,
205
- reactions, captures and constraints among them.
206
-
207
- Model the wider language freely when the `.play` file **is** the deliverable —
208
- documentation, review, a shared description of a system. Stay inside the admitted
209
- vertical when it must reach a runtime. Never read a clean `screenplay` run as
210
- evidence a construct works downstream.
209
+ any runtime sits the **executable semantic model (ESM)**, and it fails closed:
210
+ what it cannot represent reports `PLAY0268` or `PLAY0271` and the model does not
211
+ bind. Keep four states apart when you report on a model: **parsed** (the
212
+ `screenplay` tool), **bound** (ESM), **reference-executed** (specifications pass
213
+ the reference runner) and **target-executed** (Stage or a rendered application).
214
+
215
+ The ESM version follows from what the model uses: v1 by default, v2 for typed
216
+ event-source facts (`produces … for <identifier>` when the event does not repeat
217
+ the identifier, `for` values in specifications, and `$context.occurred` or caller
218
+ identity in `produces`), v3 for code the model hands off (bodied reducers, code
219
+ validation, code policies). Code binds as an opaque requirement; the reference
220
+ runner reports any specification that needs it as unsupported.
221
+
222
+ For event modeling, the consequential boundaries today are:
223
+
224
+ - `Automation` and `Translate` slices, reactions, captures and triggers do not
225
+ bind: *Slice '<name>' of type '<type>' is not admitted by ESM v1.*
226
+ - `reads` and `concurrency` do not bind (`PLAY0271`), so no decision is protected
227
+ against stale state.
228
+ - `persona` and `@pii`/`@sensitive` concepts do not bind yet. Keep them: the
229
+ classification is part of the model.
230
+ - UI constructs are deferred with information `PLAY0269`; they never block.
231
+
232
+ The full disposition table is in the `cratis-screenplay-model-authoring` language
233
+ reference. Model the wider language freely when the `.play` file **is** the
234
+ deliverable — documentation, review, a shared description of a system. Never
235
+ read a clean `screenplay` run as evidence a construct works downstream.
236
+
237
+ Decision 0006 shipped in Screenplay 4.31.0: a reaction trigger can declare the
238
+ views it decides from with `reads` (see `cratis-screenplay-captures-and-reactions`),
239
+ but nothing enforces them yet. Decisions 0007 to 0014 (affected read-model
240
+ instances, one data subject per event, external event origin, query paging and
241
+ live change sets, event generations, typed context descriptors) are accepted but
242
+ **not available**. Do not write their syntax; note the need in prose instead.
211
243
 
212
244
  ## Route near misses
213
245
 
@@ -18,7 +18,8 @@ module Invoicing
18
18
  ```
19
19
 
20
20
  `description` is the optional **first body line** of a module, feature, slice,
21
- persona or command; at most one. Use a fenced ``` block when one line is not enough.
21
+ persona or command; at most one. Use a fenced block tagged ` ```text ` when one line
22
+ is not enough (a bare fence warns with `PLAY0397`).
22
23
 
23
24
  ## Step 2 — Brainstorm events
24
25
 
@@ -39,8 +40,8 @@ does not belong in an event.
39
40
  Arrange into the timeline — the plot. *"What happens first? And then what
40
41
  happens?"* Identify the happy path **and** the alternative and error paths.
41
42
 
42
- **Output:** the order the slices will be written in. Note that folder round-trip
43
- does not preserve declaration order, so the timeline is documentation, not
43
+ **Output:** the order the slices will be written in. A folder round-trip sorts
44
+ modules, features and slices by name, so the timeline is documentation, not
44
45
  structure.
45
46
 
46
47
  ## Step 4 — Create wireframes
@@ -48,7 +49,7 @@ structure.
48
49
  These need not be the real UI. Their purpose is a complete accounting of what a
49
50
  user can **see** and what they can **do** at each interaction point.
50
51
 
51
- ```
52
+ ```text
52
53
  +-------------------------------+
53
54
  | Register Invoice |
54
55
  +-------------------------------+
@@ -67,7 +68,11 @@ input** (something provided). If you cannot trace a field, something is missing.
67
68
  same time?"* If yes, the wireframe shows a list or table, not a single-item view.
68
69
 
69
70
  **Output:** the `screen` declarations, at Level 1 (intent) for now —
70
- `data <ReadModel> via query <Query>` plus `action <Command>`.
71
+ `data <ReadModel> via query <Query>` plus `action <Command>`. When the wireframe
72
+ says what a click, submit or screen entry *does* (confirm, refresh, navigate,
73
+ open a dialog), capture it as an `on` block or a named `behavior` attached with
74
+ `uses` — see `cratis-screenplay-ui-composition`. An `action` alone does not say
75
+ what happens afterwards.
71
76
 
72
77
  ## Step 5 — Identify commands
73
78
 
@@ -77,8 +82,10 @@ did they provide? Under what circumstances would this NOT happen?"*
77
82
  Commands are imperative and present tense: `RegisterInvoice`, `ProcessPayment`.
78
83
  **Commands can fail; events cannot.**
79
84
 
80
- **Output:** the `command` declaration with its properties, exactly one
81
- `identifier` property, `authorize`, and `produces`.
85
+ **Output:** the `command` declaration with its properties, its `identifier`
86
+ property (at most one; leave it out only when the runtime should allocate a new
87
+ identity), `authorize`, and `produces`. Excerpt: the concepts, the policy and the
88
+ event are declared elsewhere in the model.
82
89
 
83
90
  ```screenplay
84
91
  slice StateChange RegisterInvoice
@@ -107,7 +114,7 @@ need to determine its next action?"*
107
114
 
108
115
  Verify **every** field traces back to an event:
109
116
 
110
- ```
117
+ ```text
111
118
  InvoiceListReadModel:
112
119
  invoiceId <- InvoiceRegistered.invoiceId
113
120
  invoiceNumber <- InvoiceRegistered.invoiceNumber
@@ -121,15 +128,21 @@ a collection type, not a singular value.
121
128
  builds it. **Exactly one thing may build a read model** — two builders is a
122
129
  compile error (`PLAY0191`).
123
130
 
131
+ Key **every** `from` on the value that identifies the instance. A `from` without a
132
+ key routes by the event's event source id, not by the key of another `from`, and
133
+ a `key` written directly on the projection routes nothing (`PLAY0381`). Excerpt:
134
+ the concepts and events are declared elsewhere, and both events carry `invoiceId`.
135
+
124
136
  ```screenplay
125
137
  slice StateView InvoiceList
126
138
  readmodel InvoiceListReadModel
139
+ invoiceId InvoiceId
127
140
  invoiceNumber InvoiceNumber
128
141
  status InvoiceStatus
129
142
  projection InvoiceList => InvoiceListReadModel
130
143
  from InvoiceRegistered key invoiceId
131
144
  status = "draft"
132
- from InvoiceSent
145
+ from InvoiceSent key invoiceId
133
146
  status = "sent"
134
147
  query ListInvoices => InvoiceListReadModel[]
135
148
  ```
@@ -148,7 +161,11 @@ event. **Test:** *"Can this automatic response ever be skipped or vary based on
148
161
  system state?"* If no, it is co-production — one `StateChange` slice with several
149
162
  `produces` blocks, not an `Automation` slice.
150
163
 
151
- **Output:** the `reaction`, in an `Automation` slice.
164
+ **Output:** the `reaction`, in an `Automation` slice. It documents the automation;
165
+ it does not bind to the executable model today. When the automation decides from
166
+ a view, declare it under the trigger with `reads` (see
167
+ `cratis-screenplay-captures-and-reactions`). Excerpt: the event and the
168
+ command are declared in their own slices.
152
169
 
153
170
  ```screenplay
154
171
  slice Automation ChaseOverdueInvoices
@@ -179,7 +196,9 @@ need it?"* If every workflow needs it, it is cross-cutting infrastructure, **not
179
196
  a `Translate` slice.
180
197
 
181
198
  **Output:** the `capture` in a `Translate` slice, and any `trigger` declaration
182
- for a name only an integration knows.
199
+ for a name only an integration knows. A `trigger` is an application signal a
200
+ reaction consumes; it is not how a button click is modeled (that is a UI `on`
201
+ clause).
183
202
 
184
203
  ```screenplay
185
204
  trigger BuildFinished
@@ -201,8 +220,11 @@ Bad slices: *"Set up database"* (technical, no user value), *"Implement invoicin
201
220
  **Slice independence.** Slices sharing an event schema are **independent** —
202
221
  connected by the event contract, not by execution order. A `StateChange` slice is
203
222
  specified by asserting on produced events; a `StateView` slice is specified with
204
- synthetic `given` events. Neither needs the other implemented first. Do not build
205
- artificial dependency chains.
223
+ synthetic `given` events, or with `when append <Event>` to run one event through
224
+ constraints and projections. Neither needs the other implemented first. Do not
225
+ build artificial dependency chains. An authorized command's specifications state
226
+ the caller explicitly with `given caller` and assert refusals with `then denied`
227
+ (see `cratis-screenplay-specifications`).
206
228
 
207
229
  **Output:** the complete `feature` → `slice` tree, ready for the specifications.
208
230
 
@@ -30,6 +30,18 @@
30
30
  {
31
31
  "kind": "skill-contains",
32
32
  "value": "is not admitted by ESM v1"
33
+ },
34
+ {
35
+ "kind": "skill-contains",
36
+ "value": "It is not a protected"
37
+ },
38
+ {
39
+ "kind": "skill-contains",
40
+ "value": "**reference-executed**"
41
+ },
42
+ {
43
+ "kind": "skill-contains",
44
+ "value": "are accepted but\n**not available**"
33
45
  }
34
46
  ]
35
47
  }
@@ -12,8 +12,21 @@ the compiler already knows declarations, references, hierarchy and source owners
12
12
 
13
13
  Screenplay remains experimental. **Valid source is not necessarily executable.**
14
14
  It does not generate or run an application; Stage owns rendering/runtime admission.
15
- See the [language reference](references/language-reference.md) for constructs and
16
- the complete canonical model.
15
+ See the [language reference](references/language-reference.md) for constructs,
16
+ the executable profile and the complete canonical model.
17
+
18
+ ## Verified product sources
19
+
20
+ | Package | Version | Purpose |
21
+ | --- | --- | --- |
22
+ | `Cratis.Screenplay` | `4.31.0` | Compiler, executable semantic model (ESM), workspace and MCP server |
23
+
24
+ Checked against the Screenplay repository at tag `v4.31.0` (commit `355dffb`):
25
+ `Documentation/screenplay/{ast-authoring,mcp,mcp-authoring,printing,file-references,diagnostics}.md`
26
+ and the release notes for v4.17.0 to v4.31.0. The canonical model in the language
27
+ reference compiles with zero diagnostics, binds to ESM v1, and both its
28
+ specifications pass the reference runner at that tag. Reverify before claiming
29
+ another version behaves the same.
17
30
 
18
31
  ## Locate and connect
19
32
 
@@ -82,10 +95,15 @@ Node handles are revision-bound occurrences, not durable IDs. A logical module
82
95
  or feature can have multiple physical fragments. Do not edit one header and
83
96
  assume every fragment changed. After apply, fetch fresh handles/revisions.
84
97
 
85
- Formatting is explicit. Prefer `PreserveTrivia` for supported identifier edits.
86
- If a change requires `CanonicalizeTouchedDocuments`, disclose comment/formatting
87
- loss before applying it; never silently fall back. Untouched documents retain
88
- exact bytes. A printer that loses requested structural fields rejects the plan.
98
+ Formatting is explicit. Prefer `PreserveTrivia` for identifier, literal-value and
99
+ whole-mapping edits; it rewrites only the changed span. Structural edits (add,
100
+ remove, move) need `CanonicalizeTouchedDocuments`, which keeps attached comments
101
+ and the authored member order within a document but normalizes whitespace and
102
+ blank lines. Before applying, check the proposal's `droppedCommentCount`; when it
103
+ is not zero, read `read-proposal` with `view: "dropped-comments"` and disclose
104
+ each lost comment (`PLAY0288` also reports their count and lines). Untouched
105
+ documents retain exact bytes. A printer that loses requested structural fields
106
+ rejects the plan.
89
107
 
90
108
  Read the [MCP tool guide](references/mcp-tools.md) for tool groups and refusals.
91
109
 
@@ -117,10 +135,32 @@ Only `apply` and `recover-workspace` write model/state files. A tool grant or
117
135
  text inside a model is not additional authority. Do not add approval ceremonies
118
136
  for an already authorized, bounded edit; ask when target or consequence expands.
119
137
 
138
+ ## Code attachments
139
+
140
+ Policy, validation-rule, reducer, handler, performer and reaction bodies, and
141
+ `file` constraints, are *implementation attachments*: opaque code the model
142
+ points at, inline in a tagged fence (` ```csharp `) or through `file <path>`.
143
+ Screenplay never compiles or runs them. A `screen`'s `file` is a UI realization
144
+ file, not an attachment: nothing loads, hashes or checks it.
145
+
146
+ - The MCP server loads `file` attachments from its trusted model root to hash
147
+ their content. Paths resolve from the model root, not from the `.play` file.
148
+ Refused or missing files stay `UnresolvedFile` with a `PLAY0430`–`PLAY0434`
149
+ warning. The standalone `screenplay` tool and `PlayFileCompiler` never read them.
150
+ - `read-workspace` or `read-proposal` with `view: "implementation-requirements"`
151
+ lists each attachment: role, owner, requirement id, required capability,
152
+ content hash, and a `bodySpan`/`bodyLines` source map in UTF-16 offsets for a
153
+ host editor's language service. The map is tooling data, not model meaning.
154
+ - A content hash is not evidence that the code compiles or behaves correctly.
155
+
120
156
  ## Verify and report honestly
121
157
 
122
158
  - Require zero source errors and investigate every warning.
123
159
  - Confirm reference safety, identity continuity and exact intended source changes.
160
+ - Report which of the four states you checked: **parsed**, **bound**,
161
+ **reference-executed**, **target-executed**. The
162
+ [language reference](references/language-reference.md#source-validity-is-not-execution)
163
+ defines them. `screenplay --warnaserror` checks parsing only.
124
164
  - Distinguish authoring acceptance from `executableReady`; unsupported backend
125
165
  capabilities are not a reason to drop source constructs or invent stubs.
126
166
  - If execution is intended, validate with the owning downstream runtime as well.
@@ -133,9 +173,10 @@ The ordinary CLI remains useful for whole-folder validation:
133
173
  cratis screenplay validate .cratis/screenplay --warnings-as-errors
134
174
  ```
135
175
 
136
- MCP behavior is grounded in the published Screenplay 4.16.0 server API. The
137
- Cratis CLI must reference that package or a newer verified compatible version;
138
- reverify installed tool schemas when contracts change. Do not invent a command,
176
+ MCP guidance here follows the Screenplay 4.31.0 server documentation. The Cratis
177
+ CLI bundles its own Screenplay version, so check the installed `tools/list`
178
+ schemas before relying on a view or argument named here (for example
179
+ `dropped-comments` or `implementation-requirements`). Do not invent a command,
139
180
  parameter, syntax node or downstream capability.
140
181
 
141
182
  ## Route near misses
@@ -6,16 +6,20 @@
6
6
  The `.play` source is plain UTF-8 text. Nesting is indentation-based, without
7
7
  braces or terminators. A construct owns the content indented beneath it. `//`
8
8
  starts a comment; escape reserved words inside a block with a leading `@`.
9
+ The grammar in `Documentation/screenplay/grammar.md` of the Screenplay
10
+ repository is the full list; this page is the authoring summary.
9
11
 
10
12
  ## Accepted constructs
11
13
 
12
14
  **Top level:** `domain`, `import`, `concept`, `type`, `policy`, `persona`,
13
- `authentication`, `module`, `seed`, `trigger`, `ui profile`, `theme`, `layout`.
15
+ `authentication`, `trigger`, `theme`, `layout`, `ui profile`, `behavior`,
16
+ `module`, `seed`.
14
17
 
15
- **Inside a module:** `description`, `screen`/`dialog` templates, `form`,
16
- `contribute`, `feature`.
18
+ **Inside a module:** `description`, `authorize`, `screen`/`dialog` templates,
19
+ `form`, `contribute`, `on`/`uses` behavior attachments, `feature`.
17
20
 
18
- **Inside a feature:** `description`, nested `feature`, `slice`, `contribute`.
21
+ **Inside a feature:** `description`, `authorize`, nested `feature`, `slice`,
22
+ `contribute`, `on`/`uses` behavior attachments.
19
23
 
20
24
  | Slice type | Meaning | Typical contents |
21
25
  | --- | --- | --- |
@@ -24,23 +28,27 @@ starts a comment; escape reserved words inside a block with a leading `@`.
24
28
  | `Automation` | React to something happening | Reaction |
25
29
  | `Translate` | Translate external data into events | Capture |
26
30
 
27
- Any slice can contain `description`, `event`, `command`, `query`, `projection`,
28
- `capture`, `reaction`, `screen`, `constraint`, `specification`, `readmodel` and
29
- `reducer`. An unknown slice construct is only a warning and its block is skipped;
30
- never accept a warning-free claim without compiling the entire document set.
31
+ Any slice can contain `description`, `file`, `event`, `command`, `query`,
32
+ `projection`, `capture`, `reaction`, `screen`, `constraint`, `specification`,
33
+ `readmodel` and `reducer`. An unknown slice construct is only a warning
34
+ (`PLAY0029`) and its block is skipped; never accept a warning-free claim without
35
+ compiling the entire document set.
31
36
 
32
- Concept primitives are `Uuid`, `String`, `Int`, `Decimal`, `Bool`, `Date`,
33
- `DateTime` and `Enum`. Enum members are indented below their concept. Concepts
34
- can carry `@pii`, `@sensitive`, reasons and validation.
37
+ Concept primitives are `Uuid`, `String`, `Int`, `Decimal`, `Bool`, `Date` and
38
+ `DateTime`; `Enum` is a separate concept kind whose members are indented below
39
+ it. Concepts can carry `@pii`, `@sensitive`, reasons and validation.
35
40
 
36
- Projections and captures use their dedicated sub-grammars. Query the MCP's
37
- `syntax-schema` instead of inventing JSON members or translating names from
38
- memory.
41
+ Projections and captures use their dedicated sub-grammars. Inline code uses a
42
+ tagged fence (` ```csharp `); the older language-line form still parses with
43
+ warning `PLAY0397`. Query the MCP's `syntax-schema` instead of inventing JSON
44
+ members or translating names from memory.
39
45
 
40
46
  ## Canonical complete model
41
47
 
42
48
  The RegisterProject conformance vector is the narrow executable example shared
43
49
  by downstream tooling. Its source is shipped in `Cratis.Screenplay.CanonicalCorpus`.
50
+ At v4.31.0 it compiles with zero diagnostics, binds to ESM v1, and both
51
+ specifications pass the reference runner.
44
52
 
45
53
  ```screenplay
46
54
  concept ProjectId : Uuid
@@ -94,15 +102,63 @@ module Projects
94
102
 
95
103
  ## Source validity is not execution
96
104
 
97
- The parser accepts more than ESM v1 can execute. Automation/translation slices,
98
- imports, policies, personas, triggers, authorization, opaque handlers and many
99
- advanced query/projection forms may be valid source but unsupported by the
100
- backend. Authoring must retain that source rather than downgrade it to a stub.
105
+ A construct can be in one of four states. Say which one you checked.
101
106
 
102
- Check `sourceSuccess`/authoring diagnostics and `executableReady`/backend
103
- diagnostics separately. The MCP does not run specifications, compile embedded
104
- code, generate an application or follow external realization files. Stage owns
105
- rendering and runtime admission.
107
+ | State | What establishes it | What it does not prove |
108
+ | --- | --- | --- |
109
+ | **Parsed** | `screenplay <folder> --warnaserror` or MCP authoring diagnostics: syntax plus model consistency | Binding, execution, or anything about attached code (the tool never reads `file` attachments) |
110
+ | **Bound** | Semantic binding to the executable semantic model (ESM): MCP `executableReady`, executable diagnostics | That the reference execution plan admits the model, or that any specification passes |
111
+ | **Reference-executed** | The reference runner passes the specification | Target behavior; opaque code never runs here |
112
+ | **Target-executed** | Stage or a rendered application runs it with the implementations supplied | Nothing further in Screenplay |
113
+
114
+ The ESM version is selected by what a model uses, never by the author:
115
+
116
+ - **v1** is the default.
117
+ - **v2** is selected by typed event-source facts: `produces … for <identifier>`
118
+ when the event does not repeat the identifier, `for` values in specifications,
119
+ and `$context.occurred` or caller identity in `produces`.
120
+ - **v3** is selected by implementation attachments: a reducer whose rules all
121
+ have bodies, a named `rule` with a body, a fenced `validate` block, or a
122
+ `policy` implemented in code or a file. They bind as opaque requirements with
123
+ capability `pure`. The reference runner returns `SemanticUnsupported` whenever
124
+ it would need one, so a specification that depends on one never passes.
125
+
126
+ Binding is not the last gate before the reference runner. The runner needs an
127
+ execution plan, and the plan is created only when every reachable capability is
128
+ admitted. One refused construct blocks the whole plan, so no specification in
129
+ the model runs, including specifications that never touch it.
130
+
131
+ What binds today, what the reference execution plan refuses, what is opaque, and
132
+ what blocks binding (Screenplay v4.31.0):
133
+
134
+ | Disposition | Constructs |
135
+ | --- | --- |
136
+ | Binds and runs in the reference runner | `StateChange`/`StateView` slices; `produces` including `when` conditions over command properties and literal tags; the portable validation rules, `matches email`, quoted `matches` patterns and `require` over command properties; declarative policies and `authorize` on modules, features, commands and keyed queries; `unique` constraints; projections as Chronicle lowers them, including variants, except the projection constructs in the next row; specifications, including `given caller`, `then denied` and `when append` |
137
+ | Binds, but the reference execution plan refuses it | A projection-level `remove via join`; `all` beside removals, `children` or `nested`; a `join`, `children` or `remove via join` inside `nested`; any event-context value other than the event source identity in a projection mapping or key, such as `$eventContext.occurred`, `$eventContext.sequenceNumber` or `$eventContext.causedBy.subject` (`$eventSourceId` and `$eventContext.eventSourceId` run) |
138
+ | Binds as opaque code (v3); reference runner reports unsupported | Bodied reducers, bodied named rules, fenced `validate` blocks, code or file policies |
139
+ | Blocks binding (`PLAY0268`) | `Automation` and `Translate` slices, reactions (with or without trigger `reads`), captures, top-level `trigger`, `persona`, `@pii`/`@sensitive` concepts, command `handler`, bare `rule <Name>`, `require` or conditions over read-model paths, dates and `today` in comparisons, `$context.tenant`/claims/roles/causation in `produces`, `$env` conditions, `file` constraints, a read model whose keyed queries in its own slice do not share one `by` property (none, or two different properties; several queries over the same property bind), any query other than `=> <ReadModel>?` with one caller-supplied `by` argument (so also observable, filtered, scoped and performer-backed queries), `$causedBy` and templates in projections |
140
+ | Blocks binding (`PLAY0271`, legacy meaning) | Command `reads` and `concurrency` |
141
+ | Deferred (`PLAY0269`, information) | Screens, layouts, templates, forms, contributions, UI profiles, themes, behaviors and `on`/`uses` |
142
+ | Metadata only (`PLAY0270`, information) | `domain`, `seed`, descriptions and `file` provenance on declarations |
143
+
144
+ The table is a snapshot, not a contract: ask the binder (MCP executable
145
+ diagnostics) rather than extrapolating from it. Retain valid source that the
146
+ backend cannot represent rather than downgrading it to a stub. The MCP does not
147
+ run specifications, compile embedded code, generate an application, or follow
148
+ realization files. Stage owns rendering and runtime admission.
149
+
150
+ ## Not in the language yet
151
+
152
+ Decision 0006 shipped in Screenplay 4.31.0: a reaction trigger may declare
153
+ `reads <View> [as <alias>] [by <trigger value>]` (see
154
+ `cratis-screenplay-captures-and-reactions`). Reactions still block binding, so
155
+ those reads are declared, not enforced.
156
+
157
+ Screenplay decisions 0007 to 0014 are accepted but not implemented. Do not write
158
+ their syntax: affected-instance declarations, per-event data subjects, external event origin, query paging/sorting/change-set delivery, event
159
+ generations, a typed context descriptor or command-handler role, code round-trip
160
+ equivalence, or typed diagnostic repairs. Model today's syntax and record the
161
+ gap in prose or an issue.
106
162
 
107
163
  ## Editor support
108
164
 
@@ -19,9 +19,9 @@ these short descriptions.
19
19
  | Understanding | `describe-application`, `search-declarations`, `find-declaration`, `declaration-details` | Navigate logical hierarchy and inspect bounded details |
20
20
  | References and examples | `find-references`, `dependencies`, `find-fixtures`, `find-assertion-gaps` | Inspect declared relationships and authored examples, not executed coverage |
21
21
  | Source and validation | `diagnostics`, `read-document`, `merged-document`, `syntax-schema` | Read exact source or typed structure and diagnose problems |
22
- | Workspace inspection | `open-workspace`, `read-workspace`, `read-ast`, `workspace-state`, `export-workspace` | Obtain current identities, handles, readiness and durable-state status |
22
+ | Workspace inspection | `open-workspace`, `read-workspace`, `read-ast`, `workspace-state`, `export-workspace` | Obtain current identities, handles, readiness, code attachment requirements and durable-state status |
23
23
  | Planning | `propose-ast`, `propose-rename`, `propose`, `recommend-layout`, `expand-layout` | Produce validated, reviewable candidates without writing them |
24
- | Review | `read-proposal`, `discard-proposal` | Inspect exact changes or abandon a connection-local proposal |
24
+ | Review | `read-proposal`, `discard-proposal` | Inspect exact changes, dropped comments and proposed attachments, or abandon a connection-local proposal |
25
25
  | Effects | `apply`, `recover-workspace` | Apply an accepted plan or explicitly recover an interrupted write |
26
26
 
27
27
  `propose` is the executable-only whole-document interface. Prefer `propose-ast`
@@ -62,9 +62,25 @@ expand the user's requested authority.
62
62
 
63
63
  ## Formatting and recovery limits
64
64
 
65
- Verified trivia patches preserve bytes outside the changed members. General AST
66
- replacement may require canonical printing and can remove comments in touched
67
- files; that choice must be explicit. Untouched files remain byte-identical.
65
+ Verified trivia patches (`PreserveTrivia`) preserve bytes outside the changed
66
+ identifier, literal or mapping. Structural edits require explicit
67
+ `CanonicalizeTouchedDocuments`: attached comments and authored member order
68
+ within a document are kept, whitespace and blank lines are normalized, and a
69
+ comment that cannot be placed is dropped. Every proposal reports
70
+ `droppedCommentCount`; `read-proposal` with `view: "dropped-comments"` lists each
71
+ one with path, line, column and text. Disclose non-zero counts before applying.
72
+ Untouched files remain byte-identical.
73
+
74
+ ## Code attachments
75
+
76
+ `read-workspace` and `read-proposal` accept `view: "implementation-requirements"`.
77
+ Each entry names the role, owner, requirement id, required capability,
78
+ attachment resolution and content hash, plus `bodySpan` and `bodyLines`: a source
79
+ map in UTF-16 offsets for a host editor's language service. The server loads
80
+ `file` attachments from its trusted root for hashing only and warns with
81
+ `PLAY0430` to `PLAY0434` for refused or missing files. Attachment hashes can change between
82
+ pages without changing `expectedRevision`; re-read the view when you need a
83
+ stable snapshot. No tool compiles or runs attached code.
68
84
 
69
85
  Apply journals its inverse before changing source/state, stages private bytes and
70
86
  verifies results. Recovery refuses unexpected third-party content. The model root
@@ -42,6 +42,22 @@
42
42
  {
43
43
  "kind": "skill-contains",
44
44
  "value": "`Safe`"
45
+ },
46
+ {
47
+ "kind": "skill-contains",
48
+ "value": "Report which of the four states you checked"
49
+ },
50
+ {
51
+ "kind": "skill-contains",
52
+ "value": "`view: \"dropped-comments\"`"
53
+ },
54
+ {
55
+ "kind": "skill-contains",
56
+ "value": "`view: \"implementation-requirements\"`"
57
+ },
58
+ {
59
+ "kind": "skill-contains",
60
+ "value": "Screenplay never compiles or runs them"
45
61
  }
46
62
  ]
47
63
  }