@cratis/pi 7.65.0 → 7.67.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 (51) hide show
  1. package/package/corpus/product-sync.json +3 -3
  2. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/realization-and-gap-fill.md +1 -1
  3. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/atomic-batches-and-source-mappings.md +1 -1
  4. package/package/corpus/skills/cratis-screenplay-command-surface/SKILL.md +4 -3
  5. package/package/corpus/skills/cratis-screenplay-command-surface/references/date-comparisons.md +13 -2
  6. package/package/corpus/skills/cratis-screenplay-model-authoring/references/language-reference.md +2 -2
  7. package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-tools.md +2 -2
  8. package/package/corpus/skills/cratis-screenplay-model-authoring/references/screen-authoring-workflow.md +13 -0
  9. package/package/corpus/skills/cratis-screenplay-model-review/references/checklist.md +1 -1
  10. package/package/corpus/skills/cratis-screenplay-model-review/references/public-keys-and-routes.md +4 -2
  11. package/package/corpus/skills/cratis-screenplay-projections/SKILL.md +5 -0
  12. package/package/corpus/skills/cratis-screenplay-projections/references/pdl-grammar.md +42 -2
  13. package/package/corpus/skills/cratis-screenplay-read-surface/SKILL.md +9 -7
  14. package/package/corpus/skills/cratis-screenplay-read-surface/references/equality-filters.md +1 -1
  15. package/package/corpus/skills/cratis-screenplay-read-surface/references/named-keys.md +168 -58
  16. package/package/corpus/skills/cratis-screenplay-read-surface/verification.json +2 -2
  17. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/gap-fill-handoff.md +1 -1
  18. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/renderability-gate.md +1 -1
  19. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/scenario-examples.md +2 -2
  20. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/spec-forms-by-mode.md +3 -3
  21. package/package/corpus/skills/cratis-screenplay-slice-design/SKILL.md +2 -2
  22. package/package/corpus/skills/cratis-screenplay-slice-design/references/public-boundaries-and-keys.md +5 -3
  23. package/package/corpus/skills/cratis-screenplay-slice-design/references/read-model-design.md +3 -2
  24. package/package/corpus/skills/cratis-screenplay-specifications/SKILL.md +3 -2
  25. package/package/corpus/skills/cratis-screenplay-specifications/references/query-rejections.md +4 -0
  26. package/package/corpus/skills/cratis-screenplay-specifications/references/vocabulary.md +17 -0
  27. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/SKILL.md +3 -1
  28. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/read-model-keys.md +46 -0
  29. package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +6 -5
  30. package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet.md +2 -2
  31. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostic-arguments.md +7 -0
  32. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +30 -6
  33. package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +31 -9
  34. package/package/corpus/skills/cratis-screenplay-toolchain/references/language-admission.md +15 -5
  35. package/package/corpus/skills/cratis-screenplay-toolchain/references/preferred-syntax.md +2 -1
  36. package/package/corpus/skills/cratis-screenplay-toolchain/references/production-routes-and-filters.md +1 -1
  37. package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +3 -3
  38. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.json +3241 -1287
  39. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.version +1 -1
  40. package/package/corpus/skills/cratis-screenplay-toolchain/references/traps.md +2 -2
  41. package/package/corpus/skills/cratis-screenplay-toolchain/verification.json +1 -1
  42. package/package/corpus/skills/cratis-screenplay-ui-composition/SKILL.md +4 -3
  43. package/package/corpus/skills/cratis-screenplay-ui-composition/references/application-shell.md +1 -1
  44. package/package/corpus/skills/cratis-screenplay-ui-composition/references/screen-composition-contract.md +1 -1
  45. package/package/corpus/skills/cratis-screenplay-ui-composition/references/ui-profile-and-theme.md +124 -2
  46. package/package/corpus/skills/cratis-screenplay-ui-composition/verification.json +25 -0
  47. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +5 -4
  48. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +12 -7
  49. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/sandbox-and-specrunner.md +17 -0
  50. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/verification.json +1 -1
  51. package/package.json +1 -1
@@ -171,9 +171,9 @@
171
171
  }
172
172
  ],
173
173
  "synced": {
174
- "version": "4.199.0",
174
+ "version": "4.204.0",
175
175
  "date": "2026-10-16",
176
- "by": "Cratis/AI#735"
176
+ "by": "Cratis/AI#743"
177
177
  },
178
178
  "covers": {
179
179
  "skills": [
@@ -201,7 +201,7 @@
201
201
  ],
202
202
  "rules": []
203
203
  },
204
- "notes": "Standalone 4.199.0 and byte-identical compiler contract pinned. Cratis/AI#735: chronological Date/DateTime ordering in command conditions and command/property literal validation (ESM v26), UTC tick precision and pre-rule offset validation; then matching remains ordinal. Source-checked Screenplay v4.199.0 commands, diagnostics, interoperability and specifications documentation plus decision 0087. Stage v4.127.1 still refuses v26 with STAGE-ESM-016 (stage-rendering.md and SemanticVersionFeatures.Supports); no render/runtime probe. Cratis/AI#576: prior mechanical compiler catch-up. Language batch #717/#722/#723/#724/#720/#728/#734 teaches atomic reaction batches (v22), described payload handlers (v23), portable linear matching, ordinal text rules (v24), protected command reads (v25), diagnostic arguments and event-source invokes mappings. Facts read at Screenplay v4.198.0 and introducing tags; Stage v4.127.0 admits exact v1-v21 and v23-v25 pairs but refuses v22/v26 and mixed pairs (STAGE-ESM-016), protected reads (044), atomic mode (043) and described handlers (STAGE-IMPL-002), even Stub mode. Stage text rules execute/render; no new renderer/runtime probe or Stage pin uplift. Cratis/AI#706: application navigation regions (module inherit, extend or override), toolbar slice buttons, blueprint template references and sample data packs in cratis-screenplay-ui-composition (references/application-shell.md), with the canonical shell vector and the rejection codes PLAY0710-PLAY0722 and PLAY0740-PLAY0765. Examples moved to the executable-state rules since 4.164: translator reactions in an Automation slice beside the Translate slice (PLAY0694) and the first record of a capture key appended with `when added`. Earlier: Standalone 4.164.0 and byte-identical compiler contract pinned. Cratis/AI#663: one origin per capture (PLAY0687). #668: executable no-event/redelivery v17. #684: concept query-argument validation in every version and query-error assertions v18. #681: executable refusal branches and refusal values v19. #666: proposal summary/severity counts and exact structural source proposals. Generated-concept rules select v20 with PLAY0688/0689 proofs and derived-matches repair; generated secrets and preview strategies remain refused. Release-baseline from-esm admission reads storedName. Standalone binding is not renderer admission: Stage 4.103.0 admits v1-v17 and v19; CLI 3.62.0 bundles Screenplay 4.159.0 / Stage 4.99.0 and renders through v16. Prior evidence remains unless superseded; no new renderer, Docker or browser probe."
204
+ "notes": "Standalone 4.204.0 and byte-identical compiler contract pinned. Cratis/AI#743: flat composite read-model keys (ESM v27): untyped projection key blocks on root from and remove with, equality-filter lists, single-instance by blocks and per-part fixtures, with PLAY0661/PLAY0662/PLAY0268 refusals checked against the 4.204.0 compiler; Stage origin/main still refuses v27 with STAGE-ESM-016 (stage-rendering.md); Stage v4.135.0 v26 admission (Host and executor run date comparisons; renderer STAGE-ESM-046) was source-checked for this sync; no render or runtime probe. Prior: Standalone 4.201.0 and byte-identical compiler contract pinned. Cratis/AI#733: the ui profile root template, shell options, appearance and new screens default (PLAY0788-PLAY0799, quick fix for the legacy layout line, ui-profiles MCP tool, 44 tools). Cratis/AI#735: chronological Date/DateTime ordering in command conditions and command/property literal validation (ESM v26), UTC tick precision and pre-rule offset validation; then matching remains ordinal. Source-checked Screenplay v4.199.0 commands, diagnostics, interoperability and specifications documentation plus decision 0087. Stage v4.127.1 still refuses v26 with STAGE-ESM-016 (stage-rendering.md and SemanticVersionFeatures.Supports); no render/runtime probe. Cratis/AI#576: prior mechanical compiler catch-up. Language batch #717/#722/#723/#724/#720/#728/#734 teaches atomic reaction batches (v22), described payload handlers (v23), portable linear matching, ordinal text rules (v24), protected command reads (v25), diagnostic arguments and event-source invokes mappings. Facts read at Screenplay v4.198.0 and introducing tags; Stage v4.127.0 admits exact v1-v21 and v23-v25 pairs but refuses v22/v26 and mixed pairs (STAGE-ESM-016), protected reads (044), atomic mode (043) and described handlers (STAGE-IMPL-002), even Stub mode. Stage text rules execute/render; no new renderer/runtime probe or Stage pin uplift. Cratis/AI#706: application navigation regions (module inherit, extend or override), toolbar slice buttons, blueprint template references and sample data packs in cratis-screenplay-ui-composition (references/application-shell.md), with the canonical shell vector and the rejection codes PLAY0710-PLAY0722 and PLAY0740-PLAY0765. Examples moved to the executable-state rules since 4.164: translator reactions in an Automation slice beside the Translate slice (PLAY0694) and the first record of a capture key appended with `when added`. Earlier: Standalone 4.164.0 and byte-identical compiler contract pinned. Cratis/AI#663: one origin per capture (PLAY0687). #668: executable no-event/redelivery v17. #684: concept query-argument validation in every version and query-error assertions v18. #681: executable refusal branches and refusal values v19. #666: proposal summary/severity counts and exact structural source proposals. Generated-concept rules select v20 with PLAY0688/0689 proofs and derived-matches repair; generated secrets and preview strategies remain refused. Release-baseline from-esm admission reads storedName. Standalone binding is not renderer admission: Stage 4.103.0 admits v1-v17 and v19; CLI 3.62.0 bundles Screenplay 4.159.0 / Stage 4.99.0 and renders through v16. Prior evidence remains unless superseded; no new renderer, Docker or browser probe."
205
205
  },
206
206
  {
207
207
  "id": "scene",
@@ -23,7 +23,7 @@ rejected model renderable, and never claim a whole-application V5 from a subset.
23
23
  with `cratis-screenplay-render-and-gap-fill`.
24
24
 
25
25
  Application-root `reaction batches atomic` also blocks Stage delivery: v22
26
- refuses STAGE-ESM-016; mode in admitted v23–v25 refuses STAGE-ESM-043. Preserve the
26
+ refuses STAGE-ESM-016; mode in admitted v23–v26 refuses STAGE-ESM-043. Preserve the
27
27
  per-occurrence/selected-branch batch boundary and independent invoked commands.
28
28
  Atomic appends do not prove redelivery deduplication or external exactly-once effects.
29
29
 
@@ -36,7 +36,7 @@ batch and unchanged read models with evaluator world/read-model assertions; earl
36
36
  accepted work can remain. `then no events` means accepted zero outcomes and cannot
37
37
  accompany `then error`. Do not invent a mixed success/error specification form.
38
38
 
39
- Stage refuses ESM v22 with STAGE-ESM-016. Even an admitted v23–v25 model carrying
39
+ Stage refuses ESM v22 with STAGE-ESM-016. Even an admitted v23–v26 model carrying
40
40
  atomic mode is refused with STAGE-ESM-043 by renderer, Host and specification executor.
41
41
  Keep the declaration and report authorized gap-fill; do not promise a render date or
42
42
  strip atomicity to lower the version.
@@ -155,8 +155,9 @@ reads/concurrency cannot combine (PLAY0783). The Cratis C# renderer refuses prot
155
155
  semantic Host/executor support is separate.
156
156
  Uniqueness still uses a constraint; reference success is not target realization.
157
157
 
158
- Do not use `reads` to fetch data the caller could supply. A composite-key view's `by` block is
159
- `PLAY0268` (read-surface `references/named-keys.md`).
158
+ Do not use `reads` to fetch data the caller could supply. A composite-key view's `by` block in a
159
+ command read is `PLAY0271`, or `PLAY0781` ByParts under `command reads protected`
160
+ (read-surface `references/named-keys.md`).
160
161
 
161
162
  ## `validate`
162
163
 
@@ -182,7 +183,7 @@ Requires Screenplay 4.199.0 (ESM v26; `screenplay --version`) for Date/DateTime
182
183
  comparisons; older binders report PLAY0268. Read [date comparisons](references/date-comparisons.md)
183
184
  when ordering a retention window with `require to >= from`, comparing instants
184
185
  across offsets, or rejecting offset-less inputs before rules. It covers admitted
185
- positions, PLAY0268/0273, ordinal `then` matching and Stage's v26 refusal.
186
+ positions, PLAY0268/0273, ordinal `then` matching and Stage's STAGE-ESM-046 renderer refusal.
186
187
 
187
188
  **Rules whose logic is code.** A bare `rule <Name>` has no portable meaning (`PLAY0268`) and a bodied rule binds only as
188
189
  opaque code. Read [references/validate-rules.md](references/validate-rules.md) when a rule's logic must live in a `file`
@@ -3,6 +3,11 @@
3
3
 
4
4
  # Chronological command date comparisons
5
5
 
6
+ ## Contents
7
+
8
+ - Retention window and rejection specifications
9
+ - Missing-offset input rejection
10
+
6
11
  Requires Screenplay 4.199.0 (ESM v26; `screenplay --version`); older binders refuse date comparisons with PLAY0268. Upgrade the compiler without weakening the rule.
7
12
 
8
13
  Use `==`, `!=`, `>`, `>=`, `<` or `<=` with matching primitives: Date/Date or
@@ -27,13 +32,19 @@ Targets must enforce this before deserialization attaches a local offset, and
27
32
  preserve tick precision or refuse the comparison; JavaScript `Date` alone truncates
28
33
  precision. Client validators omit date ordering rules. Optional absent values still
29
34
  pass validation rules other than `not empty`; optional condition operands refuse.
35
+ A .NET host that executes commands itself can reuse the reference evaluator's date semantics (Requires Screenplay 4.203.0): see [date comparison checks](https://github.com/Cratis/Screenplay/blob/main/Documentation/screenplay/date-comparison-checks.md) for `SemanticDateComparisons` and `SemanticConditionEvaluator`.
30
36
 
31
37
  PLAY0268 still refuses mixed Date/DateTime, `$context` operands (including
32
38
  `$context.occurred`), `today`, protected read paths, date rules on concepts and
33
39
  reaction `where`. A refused whole comparison reports only PLAY0268, without
34
40
  validating its literals. A `given clock` does not admit `today` or now.
35
- Stage refuses v26 with STAGE-ESM-016; standalone binding/reference execution is
36
- not rendering. Preserve the rule and route delivery to authorized gap-fill.
41
+ Requires Stage 4.135.0 for v26 admission; older Stage refuses v26 with STAGE-ESM-016.
42
+ The semantic Host and specification executor run the comparisons, including through
43
+ concepts, and reject an offset-less DateTime input after authorization and before any
44
+ rule. The renderer, legacy engines and default sandbox engine refuse them with
45
+ STAGE-ESM-046, naming the property, and emit no artifacts or date validators. Standalone
46
+ binding/reference execution is not rendering: preserve the rule and route delivery to
47
+ authorized gap-fill.
37
48
 
38
49
  ## Retention window and rejection specifications
39
50
 
@@ -272,9 +272,9 @@ See read-surface `references/named-keys.md` for the collection-key exclusion alg
272
272
  | Described handlers (ESM v23) | Pending implementation beside unconditional produces; payload-only contract, reached body Unsupported ImplementationBody; Stage STAGE-IMPL-002 even Stub mode |
273
273
  | Ordinal text rules (ESM v24) | contains/not contains/starts with/ends with on scalar non-enum text properties; quoted literals, not conditions; Stage semantic engines execute/render |
274
274
  | Protected command reads (ESM v25) | Root `command reads protected`; eligible read paths in requirements and production mappings, absence Validation, concurrent matching facts Conflict; Stage admits v25; Cratis C# rendering refuses STAGE-ESM-044, semantic Host/executor execute admitted reads with non-Error protected requirements refused STAGE-ESM-045 |
275
- | Chronological command dates (ESM v26) | Same-primitive Date/DateTime `==`, `!=`, `>`, `>=`, `<`, `<=` in require/produces-when (property or literal RHS) and command/property rules (literal RHS only). DateTime uses UTC ticks, participating offset-less inputs reject Validation before rules; then matching stays ordinal. Requires Screenplay 4.199.0 (`screenplay --version`); older binders refuse PLAY0268. Stage refuses v26 STAGE-ESM-016. Read command-surface `references/date-comparisons.md`. |
275
+ | Chronological command dates (ESM v26) | Same-primitive Date/DateTime `==`, `!=`, `>`, `>=`, `<`, `<=` in require/produces-when (property or literal RHS) and command/property rules (literal RHS only). DateTime uses UTC ticks, participating offset-less inputs reject Validation before rules; then matching stays ordinal. Requires Screenplay 4.199.0 (`screenplay --version`); older binders refuse PLAY0268. The Stage Host and executor run v26 (older Stage refuses STAGE-ESM-016); the renderer and legacy engines refuse STAGE-ESM-046 (toolchain `language-admission.md`). Read command-surface `references/date-comparisons.md`. |
276
276
  | Current routing and actor admission | Sources/streams and command/specification routes bind and reference-execute as v8; reaction `runs as system role` supplies the invocation actor as v10. Whole-workspace binding determines executable availability; CLI/Stage realization remains separate |
277
- | Blocks binding (`PLAY0268`) | enum/identity compliance and events combining personal or explicitly subject-scoped secret values with explicit subject marks; a compiler that stops before v13 refuses all `pii`/`secret` concepts ("compliance attributes require portable data-subject semantics"), while v13 binds them and Stage renders protection; attached command `handler` (PLAY0035 beside productions; pending described intent instead binds v23), bare `rule <Name>`, read paths without protected opt-in or in unsupported positions such as `produces when`, date comparisons with mixed primitives, optional condition operands, `$context`, protected read paths or `today`, date rules on concepts or reaction `where`, `$context.tenant`/claims/roles/causation in `produces`, `$env` conditions, `file` constraints, unquoted `import` of an external contract, a read model with neither explicit `key` nor unambiguous query-based identity as described above (composite keys remain unadmitted), queries with context `from` sources (typed query context is unadmitted), single-result filters (collections only), `scoped to` (opaque scope), `performer` (opaque implementation) or composite `by` blocks; optional keyed and collection queries, including caller-supplied equality filters and observable delivery, bind, `$causedBy` and templates in projections |
277
+ | Blocks binding (`PLAY0268`) | enum/identity compliance and events combining personal or explicitly subject-scoped secret values with explicit subject marks; a compiler that stops before v13 refuses all `pii`/`secret` concepts ("compliance attributes require portable data-subject semantics"), while v13 binds them and Stage renders protection; attached command `handler` (PLAY0035 beside productions; pending described intent instead binds v23), bare `rule <Name>`, read paths without protected opt-in or in unsupported positions such as `produces when`, date comparisons with mixed primitives, optional condition operands, `$context`, protected read paths or `today`, date rules on concepts or reaction `where`, `$context.tenant`/claims/roles/causation in `produces`, `$env` conditions, `file` constraints, unquoted `import` of an external contract, a read model with neither explicit `key` nor unambiguous query-based identity as described above (several key marks bind as v27; older binders refuse PLAY0268; toolchain `language-admission.md`), queries with context `from` sources (typed query context is unadmitted), single-result filters (collections only), `scoped to` (opaque scope), `performer` (opaque implementation) or a `by` block on a list query or non-optional single result; optional keyed and collection queries, including caller-supplied equality filters and observable delivery, bind, `$causedBy` and templates in projections |
278
278
  | Blocks binding (`PLAY0271`, legacy meaning) | Command reads without protected opt-in and `concurrency`; combined protected reads/concurrency is PLAY0783 |
279
279
  | Deferred (`PLAY0269`, information) | Screens, layouts, templates, forms, contributions, UI profiles, themes, behaviors and `on`/`uses` |
280
280
  | Metadata only (`PLAY0270`, information) | `domain`, `seed`, `persona`, trigger and other descriptions, and `file` provenance on declarations |
@@ -25,7 +25,7 @@
25
25
  - Formatting and recovery limits
26
26
  - Code attachments
27
27
 
28
- The standalone MCP server lists 43 tools (including the MCP-Apps visualization tool); `tools/list` is the authority for the installed server.
28
+ The standalone MCP server lists 44 tools (including the MCP-Apps visualization tool); `tools/list` is the authority for the installed server.
29
29
 
30
30
  The supported CLI launch is `cratis screenplay mcp <model-root>`, or `cratis screenplay mcp`
31
31
  alone inside a project, where the CLI locates the model (the project's `.play` files, else
@@ -51,7 +51,7 @@ the [MCP loop](mcp-loop.md).
51
51
  | --- | --- | --- |
52
52
  | Understanding | `describe-application`, `search-declarations`, `find-declaration`, `declaration-details` | Navigate logical hierarchy and inspect bounded details |
53
53
  | References and examples | `find-references`, `dependencies`, `dependency-graph`, `find-fixtures`, `find-assertion-gaps`, `find-specification-obligations`, `find-modeling-smells`, `semantic-diff` | Inspect declared relationships and authored examples, not executed coverage |
54
- | Source and validation | `diagnostics`, `read-document`, `merged-document`, `syntax-schema` | Read exact source or typed structure and diagnose problems |
54
+ | Source and validation | `diagnostics`, `ui-profiles`, `read-document`, `merged-document`, `syntax-schema` | Read exact source or typed structure and diagnose problems |
55
55
  | Workspace inspection | `open-workspace`, `read-workspace`, `read-ast`, `workspace-state`, `export-workspace`, `repair-capabilities` | Obtain current identities, handles, readiness, code attachment requirements, source-map locations, durable-state status and the repair catalog |
56
56
  | Visual (MCP-Apps hosts only) | `visualize-model` | Draw the board for the model or a `proposalId`; its `sketch` argument previews a what-if of whole documents. Reads only |
57
57
  | Planning | `propose-source`, `propose-ast`, `propose-rename`, `propose-move`, `propose-repair`, `propose-property`, `propose-number-enum-members`, `propose-extract-inline-event`, `propose`, `recommend-layout`, `expand-layout` | Produce validated, reviewable candidates without writing them |
@@ -170,6 +170,19 @@ open, read, propose, review, apply, reopen loop; the syntax and rules are in
170
170
  5. Switching a module from inherit to override copies the application's items; retarget each copy to the module's own
171
171
  features first or the proposal is refused.
172
172
 
173
+ ### The profile's shell
174
+
175
+ `ui-profiles` (Screenplay 4.201.0 or later) reads each `ui profile`'s root template, shell options, appearance, new screens default and
176
+ shell diagnostics, and lists the own templates that could be the root template (`applicableRootTemplates`) or the new screens
177
+ default (`applicableNewScreenTemplates`); pick from those instead of guessing. Edit `RootTemplateSyntax` (`name`, `blueprint`,
178
+ `version`), `ShellOptionSyntax` (`add` to the root's `options`; `syntaxKind` is `Word`, `Text`, `Number` or `Flag`),
179
+ `ProfileAppearanceSyntax` (`colorScheme`, `accent`) and `NewScreenTemplateSyntax` with `propose-ast`. A refusal is the answer:
180
+ `PLAY0790` (a template nothing declares), `PLAY0792` (a blueprint the profile does not list), `PLAY0794` (a template that cannot
181
+ be the shell), `PLAY0795` (no `content` slot), `PLAY0797` (a bad color scheme or accent), `PLAY0799` (a new screens default that
182
+ cannot start a screen). `PLAY0796` (an option the shell does not expose) and `PLAY0791` (the legacy `layout` line) are warnings:
183
+ the proposal is accepted and `ui-profiles` shows them. Replay against the `ui-profile-root-positive` vector and its rejection
184
+ vectors (`ui-profile-root-unknown`, `ui-profile-root-not-a-shell`, `ui-profile-root-invalid`) in `Cratis.Screenplay.CanonicalCorpus`.
185
+
173
186
  Requires Screenplay 4.188.0 or later (`screenplay --version`) to `add` the first region, button or sub-item to a member
174
187
  the node JSON omits while empty; an older MCP server answers "Unknown typed syntax member".
175
188
 
@@ -180,7 +180,7 @@ Nebulit (`provenance.md`).
180
180
  | Id | Check | Evidence | Tier |
181
181
  |---|---|---|---|
182
182
  | H1 | Query shape follows the business view (list where people scan; lookup where they open one) | queries, screens | D |
183
- | H2 | Executable scope: a keyed `=> RM optional` query with `by` named like a read-model property, or a collection (`=> RM[]`, observable too) with caller-supplied `by` and/or equality filters. `from`, single-result filters, opaque `scoped to`/`performer` and composite `by` remain PLAY0268. The projection routes by the same identity (a `from` key or an event property, or `$eventSourceId`; `$eventSourceId` is not mandated). Filtered models: supported v14 equality filters render within the CLI bundle's ESM ceiling. Renderable scope only: Stage-specific identity/filter limits; keyed optional snapshot lookups and snapshot/observable collections render (Requires Stage 4.90.0 for snapshot lists; older renderers report `STAGE-ESM-010`). Check query concept-validation parity separately; primitive-argument targets answer absence instead of Validation | queries, projections | C (executable); C (render admission, renderable only) |
183
+ | H2 | Executable scope: a keyed `=> RM optional` query with `by` named like a read-model property, or a collection (`=> RM[]`, observable too) with caller-supplied `by` and/or equality filters. `from`, single-result filters, opaque `scoped to`/`performer` and a list-query `by` block remain PLAY0268. A read model with several key parts binds as v27 (Requires Screenplay 4.204.0). The projection routes by the same identity (a `from` key or an event property, or `$eventSourceId`; `$eventSourceId` is not mandated). Filtered models: supported v14 equality filters render within the CLI bundle's ESM ceiling. Renderable scope only: Stage-specific identity/filter limits; keyed optional snapshot lookups and snapshot/observable collections render (Requires Stage 4.90.0 for snapshot lists; older renderers report `STAGE-ESM-010`). Check query concept-validation parity separately; primitive-argument targets answer absence instead of Validation | queries, projections | C (executable); C (render admission, renderable only) |
184
184
  | H3 | One builder per read model; projection `key` only on `from` | projections | C |
185
185
  | H4 | Screens show one actor's point of view; a form submits one command | screens, forms | D |
186
186
 
@@ -16,8 +16,10 @@ Add these to the element sweep, with evidence pinned to the declaration:
16
16
  - Is the view identity explicitly marked `key` or unambiguously inferred? Does each
17
17
  single-instance query/read supply every part exactly once, with compatible types,
18
18
  and do state fixtures contain all parts? Do PDL keys align with the view's key?
19
- Composite view keys still refuse binding (PLAY0268); compilation
20
- is not executable evidence. Read read-surface `references/named-keys.md`.
19
+ Flat composite view keys bind as ESM v27 (older binders refuse with PLAY0268;
20
+ compiler requirement in read-surface `references/named-keys.md`); compilation alone is not executable evidence. Does
21
+ each projection `from` and `remove with` name every part in an untyped `key` block?
22
+ Read read-surface `references/named-keys.md`.
21
23
  - Does a production override replace the whole source/stream/id route, rather than
22
24
  assume partial inheritance? Is its `for` destination still explicit and compatible?
23
25
  Are skipped production routes valid, so eager resolution cannot fail unexpectedly?
@@ -100,6 +100,7 @@ the executable model routes any event by it, and it is not a default for the
100
100
  | From-level block | indented `key invoiceId` inside the `from` |
101
101
  | Per event, several events | `from A key idA, B key idB, C` |
102
102
  | Composite | `key OrderKey` with indented `<property> = <expr>` parts |
103
+ | Flat composite parts | untyped `key` block naming every key part (Requires 4.204.0; ESM v27) |
103
104
  | Literal (constant) | `key literal "site-stats"` — every event updates the **same** instance |
104
105
  | Children identity | `children lines identified by lineNumber` |
105
106
  | **Default** | **the event source id** — `from X` ≡ `from X key $eventSourceId` |
@@ -120,6 +121,10 @@ subscribe to it exactly like a standalone event. Verified extraction preserves
120
121
  canonical ESM and identities, so it changes no projection contract. Removing a
121
122
  payload property is different and requires consumer/persistence review.
122
123
 
124
+ A read model with several flat `key` parts needs that block in every root `from` and
125
+ `remove with` (`PLAY0661`/`PLAY0662`); other blocks and reducers there are `PLAY0268`
126
+ (`references/pdl-grammar.md`).
127
+
123
128
  A second key on one `from` is error `PLAY0060`. A template expression in a
124
129
  composite key is error `PLAY0073`; an empty composite key is `PLAY0074`.
125
130
 
@@ -6,6 +6,7 @@
6
6
  - Parser regexes
7
7
  - Diagnostics
8
8
  - Syntax that parses but means something else
9
+ - Flat composite read-model keys
9
10
  - Worked examples
10
11
 
11
12
  Checked against `Documentation/screenplay/projections/{grammar,semantic-model,keys,variants}.md`
@@ -69,11 +70,11 @@ NestedBlock = "nested", Ident, NL,
69
70
  ClearWithBlock = "clear", "with", TypeRef, NL ;
70
71
 
71
72
  RemoveWithBlock = "remove", "with", TypeRef, [ "key", Expr ], NL,
72
- [ INDENT, [ ParentDecl ], DEDENT ] ;
73
+ [ INDENT, [ CompositeKeyDecl ], [ ParentDecl ], DEDENT ] ;
73
74
  RemoveWithJoinBlock = "remove", "via", "join", "on", TypeRef, [ "key", Expr ], NL ;
74
75
 
75
76
  KeyDecl = "key", Expr, NL ;
76
- CompositeKeyDecl= "key", TypeRef, [ "{" ], NL,
77
+ CompositeKeyDecl= "key", [ TypeRef ], [ "{" ], NL,
77
78
  INDENT, KeyPart, { NL, KeyPart }, DEDENT, [ "}", NL ] ;
78
79
  KeyPart = Ident, "=", Expr ;
79
80
 
@@ -172,6 +173,45 @@ LiteralKeyword = "literal", " ", Literal ; (* parsed at the Expr level *)
172
173
  | `all` beside removals, `children` or `nested` | Binds, but the reference execution plan refuses it |
173
174
  | `join`, `children` or `remove via join` inside `nested` | Not wired by Chronicle's engine; binds, but the reference execution plan refuses it |
174
175
 
176
+ ## Flat composite read-model keys
177
+
178
+ Requires Screenplay 4.204.0 (ESM v27; `screenplay --version`); older binders refuse a
179
+ read model with two or more `key` marks with PLAY0268.
180
+
181
+ A read model with several flat `key` properties takes an **untyped** `key` block (no
182
+ type name) in each root `from` and `remove with`, naming every key part once as
183
+ `<property> = <expr>`. It differs from the typed composite key above, which fills one
184
+ single property of composite type.
185
+
186
+ ```screenplay excerpt
187
+ projection PaymentTotals => PaymentTotals
188
+ no automap
189
+ from PaymentReceived
190
+ key
191
+ invoiceId = invoice
192
+ method = method
193
+ total = amount
194
+ remove with PaymentRemoved
195
+ key
196
+ invoiceId = invoice
197
+ method = method
198
+ ```
199
+
200
+ The block applies to every event the `from` names. Part order does not matter; creating
201
+ an instance writes each part to its property even with `no automap`, and a mapping that
202
+ contradicts a part fails the projection. `remove with` deletes only the instance whose
203
+ parts all match, and a later `from` recreates it.
204
+
205
+ | Written | Code |
206
+ | --- | --- |
207
+ | `from` or `remove with` with no key, `key <expr>`, an inline `from A key x`, or `parent` | PLAY0661 |
208
+ | A part missing from the block | PLAY0661 |
209
+ | An unknown, repeated or ill-typed part, a non-simple expression, or a typed key block on a composite-keyed read model | PLAY0662 |
210
+ | `join`, `children`, `remove via join`, `every`, `all`, `nested`, `clear with`, `variant`, or a reducer on the read model | PLAY0268 |
211
+
212
+ The complete executable example, with queries and specifications, is in read-surface
213
+ `references/named-keys.md`.
214
+
175
215
  ## Worked examples
176
216
 
177
217
  Each example is an excerpt: the events and read models it names are declared
@@ -54,11 +54,13 @@ identity (all such queries must agree). Only with no single-instance identifier
54
54
  and an admitted list query does the binder infer an unambiguous `*Id`; queryless
55
55
  read models need an explicit `key`. See named keys below for collection-key exclusions.
56
56
  One explicit key binds byte-identically to equivalent inference. Several marks
57
- form a composite key, supplied by name in query/read
58
- `by` blocks. Composite keys and block queries remain
59
- **authoring-only** (PLAY0268); the scalar optional snapshot shape binds.
60
- Read [named keys](references/named-keys.md) for complete examples, trigger/command
61
- reads, all-parts fixtures, PLAY0660–0662 and command-read-only PLAY0661 repair.
57
+ form a flat composite key: an optional single-instance query names every part in a
58
+ `by` block, a list query narrows with equality filters, and fixtures state every part.
59
+ Requires Screenplay 4.204.0 (ESM v27; `screenplay --version`); older binders refuse
60
+ several key marks with PLAY0268. A list query over such a read model cannot use a
61
+ `by` block (PLAY0268).
62
+ Read [named keys](references/named-keys.md) for one complete executable example,
63
+ trigger/command reads, all-parts fixtures, PLAY0660–0662 and command-read-only PLAY0661 repair.
62
64
  A `=>` target resolving to an event is an event-target builder, not a read model;
63
65
  keep event and read-model names distinct (see projections' public-event targets).
64
66
 
@@ -78,7 +80,7 @@ query ListInvoices => InvoiceListReadModel[]
78
80
  **Name the compiler and renderer.** Optional keyed queries and collection queries
79
81
  bind, including `observable`. Caller-supplied equality
80
82
  filters on collections bind as ESM v14; `from`, single-result filters, `scoped to`,
81
- `performer` and composite `by` remain PLAY0268, each with its reason. Read
83
+ `performer` and a `by` block on a list query (or on a non-optional single result) remain PLAY0268, each with its reason. Read
82
84
  [equality filters](references/equality-filters.md) for the admitted shape, a complete
83
85
  compiled specification model and the Stage/CLI ceilings. Keep a list the domain needs.
84
86
 
@@ -177,7 +179,7 @@ primitive/concept/enum properties, same nominal type ignoring optionality, no
177
179
  `from`, distinct names not repeating `by`. `by` and supplied filters AND together;
178
180
  optional filters may be omitted, but supplied null is refused. PLAY0268 still
179
181
  rejects context sources, single-result filters, opaque scope/performer and
180
- composite `by`; a single non-optional result remains unadmitted too.
182
+ a `by` block on a list query (or on a non-optional single result).
181
183
  Authorization runs before lookup, ANDed with module/feature gates; policies see
182
184
  only `by`, never filters. Pin denial with `given caller` and `then denied`.
183
185
  Specs pass `by` and filters by name (PLAY0468 for unknown, repeated or missing
@@ -40,7 +40,7 @@ Each binding refusal reports PLAY0268 with its query/filter and reason:
40
40
  | Filter on a single-result query | Equality filters are admitted only for collections |
41
41
  | `scoped to` | The named scope has no portable executable scope contract |
42
42
  | `performer` | Query implementation code is opaque, not a portable declarative lookup |
43
- | Composite `by` block | Multipart lookup admission remains deferred (Screenplay#599) |
43
+ | `by` block on a collection query | A composite lookup is admitted only for an optional single-instance query; narrow a list by composite-keyed read-model parts with equality filters instead |
44
44
  | Filter on a collection/composite property, missing property or mismatched nominal type | The v14 filter contract requires a same-named scalar primitive, concept or enum property with the same type |
45
45
 
46
46
  Keep those intents when the domain needs them; never drop a context source or
@@ -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 and report the capability gap. Read-model
43
- keys do not supply projection routes: align each PDL `from ... key` mapping with
44
- the declared view identity (projection keys are a separate contract).
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
- A scalar query keeps `by name Type` on its own body line. A composite query has a
49
- bare `by` header and at least two distinct `name Type [from source]` children.
50
- Do not combine scalar and block forms. A single-instance lookup must supply every
51
- key part exactly once, with the declared types; collection queries may narrow by
52
- a subset but still have their separate executable-query limitations.
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
- A command or reaction trigger read uses a child `by` block of `part = source`.
55
- Sources are required, noncollection property paths with compatible nominal types,
56
- not literals. Trigger reads map from the trigger's declared values. The historical
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
- This complete authoring-only example declares all lookup parts:
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 ResourceId : Uuid
63
- concept Period : String
64
- module Reporting
65
- feature Months
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
- readmodel ResourceMonth
68
- resourceId ResourceId key
69
- period Period key
70
- hours Decimal
71
- query FindMonth => ResourceMonth optional
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
- resourceId ResourceId
74
- period Period
75
- slice StateChange CloseMonth
76
- command CloseMonth
77
- resourceId ResourceId identifier
78
- period Period
79
- reads ResourceMonth as totals
80
- by
81
- resourceId = resourceId
82
- period = period
83
- produces event MonthClosed
84
- for resourceId
85
- period Period = period
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
- Screen `data ... via query ... by value`, forms and navigation remain scalar
89
- lookups: they cannot supply a composite single-instance key (PLAY0661). Do not
90
- invent UI tuple syntax. Context-derived query parts do not become caller inputs;
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
- A composite absence fixture uses an object with every named part. Query result
97
- assertions may omit keys when arguments already select the instance.
98
-
99
- Composite read-model keys, query `by` blocks and fixtures
100
- over those views remain authoring-only: binding reports PLAY0268 citing
101
- Screenplay#599 (still open). They do not reference-execute or render. This is not
102
- ESM v10 admission; v10 covers reaction identity, production routes and observer
103
- filters. Eligible command reads separately opt into v25 with `command reads protected`;
104
- legacy reads remain PLAY0271, and composite keys are still refused (PLAY0781 ByParts).
105
- See command-surface [protected reads](../../cratis-screenplay-command-surface/references/protected-reads.md).
106
- A single explicit key does bind; Stage admission still depends on the complete
107
- model and projection/query shape, not just the key modifier.
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 FindMonth", "file": "references/named-keys.md" },
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": "remain authoring-only", "file": "references/named-keys.md" },
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" },
@@ -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–v25 (STAGE-ESM-043); the declaration is not external-effect deduplication.
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