@cratis/pi 7.128.0 → 7.129.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 (61) hide show
  1. package/package/corpus/product-sync.json +4 -4
  2. package/package/corpus/skills/cratis-application-slice-conformance/SKILL.md +1 -1
  3. package/package/corpus/skills/cratis-arc-react-page/references/from-screenplay.md +5 -5
  4. package/package/corpus/skills/cratis-screenplay-automations-and-translations/SKILL.md +6 -1
  5. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/automation-patterns.md +1 -1
  6. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/cases-to-specify.md +5 -5
  7. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/statemachines-and-workflows.md +164 -0
  8. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/todo-list-example.md +12 -15
  9. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/translate-example.md +10 -4
  10. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/complete-examples.md +2 -2
  11. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/invocation-identity.md +8 -2
  12. package/package/corpus/skills/cratis-screenplay-command-surface/SKILL.md +5 -4
  13. package/package/corpus/skills/cratis-screenplay-command-surface/references/described-handlers.md +12 -8
  14. package/package/corpus/skills/cratis-screenplay-command-surface/references/validate-rules.md +5 -5
  15. package/package/corpus/skills/cratis-screenplay-command-surface/verification.json +1 -1
  16. package/package/corpus/skills/cratis-screenplay-event-modeling/references/nine-steps.md +6 -3
  17. package/package/corpus/skills/cratis-screenplay-legacy-extraction/references/generated-recovery.md +4 -4
  18. package/package/corpus/skills/cratis-screenplay-model-authoring/references/language-reference.md +2 -2
  19. package/package/corpus/skills/cratis-screenplay-read-surface/references/named-keys.md +3 -1
  20. package/package/corpus/skills/cratis-screenplay-read-surface/references/screen-patterns.md +2 -2
  21. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/SKILL.md +4 -4
  22. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/renderability-gate.md +6 -5
  23. package/package/corpus/skills/cratis-screenplay-scenario-coverage/SKILL.md +2 -2
  24. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/invoicing-dues-design.md +0 -3
  25. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/invoicing-dues-example.md +8 -3
  26. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/scenario-examples.md +17 -9
  27. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/spec-forms-by-mode.md +4 -3
  28. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/version-skew.md +25 -14
  29. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/view-and-story-specs.md +7 -6
  30. package/package/corpus/skills/cratis-screenplay-scenario-coverage/verification.json +1 -1
  31. package/package/corpus/skills/cratis-screenplay-slice-design/references/read-model-design.md +1 -1
  32. package/package/corpus/skills/cratis-screenplay-slice-design/references/slicing.md +1 -1
  33. package/package/corpus/skills/cratis-screenplay-slice-design/references/worked-example.md +3 -3
  34. package/package/corpus/skills/cratis-screenplay-specifications/SKILL.md +4 -2
  35. package/package/corpus/skills/cratis-screenplay-specifications/references/actions-beyond-commands.md +4 -2
  36. package/package/corpus/skills/cratis-screenplay-specifications/references/child-ordering.md +12 -3
  37. package/package/corpus/skills/cratis-screenplay-specifications/references/reactions-and-cascades.md +70 -21
  38. package/package/corpus/skills/cratis-screenplay-specifications/references/vocabulary.md +3 -2
  39. package/package/corpus/skills/cratis-screenplay-specifications/verification.json +2 -2
  40. package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +3 -3
  41. package/package/corpus/skills/cratis-screenplay-toolchain/references/automation-translate-example.md +5 -8
  42. package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet-example.md +12 -11
  43. package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet.md +1 -1
  44. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostic-arguments.md +1 -1
  45. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +2 -2
  46. package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +10 -7
  47. package/package/corpus/skills/cratis-screenplay-toolchain/references/language-admission.md +4 -1
  48. package/package/corpus/skills/cratis-screenplay-toolchain/references/preferred-syntax.md +4 -1
  49. package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +4 -4
  50. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract-exceptions.json +0 -70
  51. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.json +4743 -623
  52. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.version +1 -1
  53. package/package/corpus/skills/cratis-screenplay-toolchain/references/traps.md +1 -1
  54. package/package/corpus/skills/cratis-screenplay-ui-composition/SKILL.md +6 -0
  55. package/package/corpus/skills/cratis-screenplay-ui-composition/references/action-subjects.md +73 -0
  56. package/package/corpus/skills/cratis-screenplay-ui-composition/references/file-references.md +4 -3
  57. package/package/corpus/skills/cratis-screenplay-ui-composition/references/response-continuations.md +1 -1
  58. package/package/corpus/skills/cratis-screenplay-ui-composition/references/worked-flow.md +1 -1
  59. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +6 -5
  60. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +8 -5
  61. package/package.json +1 -1
@@ -171,9 +171,9 @@
171
171
  }
172
172
  ],
173
173
  "synced": {
174
- "version": "4.245.0",
175
- "date": "2026-10-25",
176
- "by": "Cratis/AI#820"
174
+ "version": "5.1.0",
175
+ "date": "2026-11-02",
176
+ "by": "Cratis/AI#975"
177
177
  },
178
178
  "covers": {
179
179
  "skills": [
@@ -201,7 +201,7 @@
201
201
  ],
202
202
  "rules": []
203
203
  },
204
- "notes": "Cratis/AI#820: reviewed v4.245.0 release; protected-read constraint precedence preserved. Review correction: removed unsupported parser-repair and inbound-public refusal release attributions and the incorrect PLAY0136 event-key claim, restoring prior teaching. Published contract asset is byte-identical to the previous snapshot; pin and compatibility entry advanced together. Prior: Cratis/AI#779: reference-runner capability refusals taught as scoped per specification (introduced in v4.213.2, Cratis/Screenplay#897) from the v4.216.0 tool and MCP documentation and plan source: an unadmitted projection (UnsupportedEventContext, UnsupportedProjectionBlock) marks unsupported only the specifications that reach it or its read model, the others run and planIssues lists deferred issues; application-level issues still block every selected specification; no new render/runtime probe. Prior: Cratis/AI#776: PLAY0802 ReservedStoredName (introduced in v4.213.3, Cratis/Screenplay#893) taught from the v4.216.0 compilers and documentation: stored event source `Default` and stored event stream `All` (ordinal, name or `id` pin) refused at authoring time, a pin away from the reserved name valid, PLAY0273 kept as the binding backstop; no new render/runtime probe. Prior: Cratis/AI#784: standalone Screenplay 4.216.0 pinned; compiler contract replaced by the v4.216.0 release asset (adds the propose-repair destinationIntent v1 schema and PLAY0802 ReservedStoredName). Source-checked decision 0096 and the MCP reference for the explicit author-intent PLAY0470 repair: repair-intents discovery, intentActions feature detection, complete per-production selections, retained production-destination report and identity views, explicit apply and refusals. No new render/runtime probe. Prior: Cratis/AI#771: standalone Screenplay 4.213.0 pinned; regenerated compiler contract is byte-identical to the v4.213.0 release asset and unchanged from 4.212.4. Reviewed the full v4.212.4-v4.213.0 delta against tagged decision 0093 and MCP reference: pre-binding container identities and stable binding/migration continuity, own-slice member substitutions, containerIdentities completeness/ambiguity/collision refusals, retained ambiguous notes, explicit semanticRenames/retirements, binding fixes through MCP, exact reopen exception, notes/identity rollback and exact-ID re-add anchoring. No grammar, binder, ESM or diagnostic-code changes; no new render/runtime probe. Prior: Cratis/AI#772: standalone Screenplay 4.212.4 pinned; regenerated compiler contract is byte-identical to the v4.212.4 release asset. Source-checked joined-event automap/no automap overrides and level fallback in executable binding; PLAY0380 covers only all inside children/nested. No new render/runtime probe. Prior: Cratis/AI#769: standalone Screenplay 4.212.3 pinned; regenerated compiler contract is byte-identical to the v4.212.3 release asset. Source-checked both compilers and projection documentation for PLAY0801 DuplicateEventInProjectionScope: shared from/removal/clear set, separate join set, fresh sets per children/nested/variant level, and no two-row update through repeated from blocks with different keys. No new render/runtime probe. Prior: Cratis/AI#768: standalone Screenplay 4.212.2 pinned; regenerated compiler contract is byte-identical to the v4.212.2 release asset (unchanged from the previous contract). Source-checked v4.212.0 split-model dotted note targets, open-workspace applicationIdentity and complete add/reanchor substitutions; unbound container identities are not claimed. v4.212.1 aligns PLAY0535 collection fields, optional parameters and single-result identity inference. v4.212.2 counts read-only query denials for SPEC004, not SPEC006. No new render/runtime probe. Prior: Cratis/AI#762 and #761: source-checked v4.210.0 and v4.211.0 contracts for PLAY0800 CommandHandlerRequiresAttachment (required typed subject, permanent code-attachment requirement, other PLAY0268 families unchanged), independent reference remove/add batches, located same-text ambiguity conflicts and string MCP conflict/move-report document fields. v4.211.1 mapping changes inspected but excluded from this guidance update at the user's request; no typed PLAY0273 property/type arguments are claimed. Standalone Screenplay 4.211.1 and its compiler contract pinned; the contract is a byte-identical copy of the v4.211.1 release asset. No new render/runtime probe. Prior: Standalone 4.205.0 and byte-identical compiler contract pinned. Cratis/AI#746: Uuid ==/!= in command require and produces when (ESM v28): same-concept rule, bare Uuid against a concept, canonical literals, protected read paths in require only; PLAY0268 (different concepts, ordering, Uuid validation and concept rules, read paths in produces when) and PLAY0273 (non-canonical literal) checked against the 4.205.0 compiler, v28 selection read from the MCP executable-model view; Stage admits exact v1-v21 and v23-v26 pairs so v28 is refused STAGE-ESM-016, not probed against a Stage image; CLI 3.74.0 renders through v26. Prior: Standalone 4.204.0 and byte-identical compiler contract pinned. Cratis/AI#702 and #691: PLAY0690 reducer identity (Screenplay 4.170.0, native compiler only) and the screenplay.json validation gate (Screenplay 4.165.0; cratis screenplay validate reads it from CLI 3.65.0) are taught and probed against the 4.204.0 compiler. 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."
204
+ "notes": "Cratis/AI#975: reviewed every release v4.246.0 through v5.1.0. Standalone 5.1.0 and its byte-identical contract pinned; the onboarding/environment contract exceptions are gone. v5.0.0: objects and lists are indented blocks (`member = value`, `item`, `none`, `empty`), inline JSON is PLAY0833, and every skill example uses the block form. v4.246.0 (decision 0115): a specification runs only its own slice; command specifications state their own events, automations state cross-slice hand-overs with `then invokes` (ESM v34), and every cross-slice expectation in the examples moved to the producing slice. v4.248.0: action subjects `for item`/`for screen` with PLAY0817-PLAY0821; every example action states its subject by intent. v4.250.0 (decision 0117): attached handlers beside unconditional produces with a resolved body bind as the v23 result contract; PLAY0800 only for the remaining shapes; PLAY0035 retired. v4.254.0: `$eventContext.occurred` runs in scoped projections for facts appended under `given clock` (probed on the 5.1.0 tool; a `given` fact carries none). v4.257.0: PLAY0824/PLAY0825 preferred-syntax rows. v5.1.0: `statemachine` and `workflow` (ESM v36) taught with a compiled, passing example; Stage 4.214.0 refuses v36. Cratis.Orleans engine hosting remains Cratis/AI#972. Editor-only, host-provider and board releases need no teaching change. Prior: Cratis/AI#820: reviewed v4.245.0 release; protected-read constraint precedence preserved. Review correction: removed unsupported parser-repair and inbound-public refusal release attributions and the incorrect PLAY0136 event-key claim, restoring prior teaching. Published contract asset is byte-identical to the previous snapshot; pin and compatibility entry advanced together. Prior: Cratis/AI#779: reference-runner capability refusals taught as scoped per specification (introduced in v4.213.2, Cratis/Screenplay#897) from the v4.216.0 tool and MCP documentation and plan source: an unadmitted projection (UnsupportedEventContext, UnsupportedProjectionBlock) marks unsupported only the specifications that reach it or its read model, the others run and planIssues lists deferred issues; application-level issues still block every selected specification; no new render/runtime probe. Prior: Cratis/AI#776: PLAY0802 ReservedStoredName (introduced in v4.213.3, Cratis/Screenplay#893) taught from the v4.216.0 compilers and documentation: stored event source `Default` and stored event stream `All` (ordinal, name or `id` pin) refused at authoring time, a pin away from the reserved name valid, PLAY0273 kept as the binding backstop; no new render/runtime probe. Prior: Cratis/AI#784: standalone Screenplay 4.216.0 pinned; compiler contract replaced by the v4.216.0 release asset (adds the propose-repair destinationIntent v1 schema and PLAY0802 ReservedStoredName). Source-checked decision 0096 and the MCP reference for the explicit author-intent PLAY0470 repair: repair-intents discovery, intentActions feature detection, complete per-production selections, retained production-destination report and identity views, explicit apply and refusals. No new render/runtime probe. Prior: Cratis/AI#771: standalone Screenplay 4.213.0 pinned; regenerated compiler contract is byte-identical to the v4.213.0 release asset and unchanged from 4.212.4. Reviewed the full v4.212.4-v4.213.0 delta against tagged decision 0093 and MCP reference: pre-binding container identities and stable binding/migration continuity, own-slice member substitutions, containerIdentities completeness/ambiguity/collision refusals, retained ambiguous notes, explicit semanticRenames/retirements, binding fixes through MCP, exact reopen exception, notes/identity rollback and exact-ID re-add anchoring. No grammar, binder, ESM or diagnostic-code changes; no new render/runtime probe. Prior: Cratis/AI#772: standalone Screenplay 4.212.4 pinned; regenerated compiler contract is byte-identical to the v4.212.4 release asset. Source-checked joined-event automap/no automap overrides and level fallback in executable binding; PLAY0380 covers only all inside children/nested. No new render/runtime probe. Prior: Cratis/AI#769: standalone Screenplay 4.212.3 pinned; regenerated compiler contract is byte-identical to the v4.212.3 release asset. Source-checked both compilers and projection documentation for PLAY0801 DuplicateEventInProjectionScope: shared from/removal/clear set, separate join set, fresh sets per children/nested/variant level, and no two-row update through repeated from blocks with different keys. No new render/runtime probe. Prior: Cratis/AI#768: standalone Screenplay 4.212.2 pinned; regenerated compiler contract is byte-identical to the v4.212.2 release asset (unchanged from the previous contract). Source-checked v4.212.0 split-model dotted note targets, open-workspace applicationIdentity and complete add/reanchor substitutions; unbound container identities are not claimed. v4.212.1 aligns PLAY0535 collection fields, optional parameters and single-result identity inference. v4.212.2 counts read-only query denials for SPEC004, not SPEC006. No new render/runtime probe. Prior: Cratis/AI#762 and #761: source-checked v4.210.0 and v4.211.0 contracts for PLAY0800 CommandHandlerRequiresAttachment (required typed subject, permanent code-attachment requirement, other PLAY0268 families unchanged), independent reference remove/add batches, located same-text ambiguity conflicts and string MCP conflict/move-report document fields. v4.211.1 mapping changes inspected but excluded from this guidance update at the user's request; no typed PLAY0273 property/type arguments are claimed. Standalone Screenplay 4.211.1 and its compiler contract pinned; the contract is a byte-identical copy of the v4.211.1 release asset. No new render/runtime probe. Prior: Standalone 4.205.0 and byte-identical compiler contract pinned. Cratis/AI#746: Uuid ==/!= in command require and produces when (ESM v28): same-concept rule, bare Uuid against a concept, canonical literals, protected read paths in require only; PLAY0268 (different concepts, ordering, Uuid validation and concept rules, read paths in produces when) and PLAY0273 (non-canonical literal) checked against the 4.205.0 compiler, v28 selection read from the MCP executable-model view; Stage admits exact v1-v21 and v23-v26 pairs so v28 is refused STAGE-ESM-016, not probed against a Stage image; CLI 3.74.0 renders through v26. Prior: Standalone 4.204.0 and byte-identical compiler contract pinned. Cratis/AI#702 and #691: PLAY0690 reducer identity (Screenplay 4.170.0, native compiler only) and the screenplay.json validation gate (Screenplay 4.165.0; cratis screenplay validate reads it from CLI 3.65.0) are taught and probed against the 4.204.0 compiler. 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",
@@ -44,7 +44,7 @@ This skill is a method: it names no API of its own. When the Screenplay skills a
44
44
  | --- | --- |
45
45
  | Where each rule lives (validator, `Provide()`, handler result, constraint, exception) | `rules/vertical-slices.md` "The decision matrix" |
46
46
  | A customization never makes a rejected model renderable; managed output is never hand-edited | Stage (`Customizations/` is the unmanaged seam; managed output is regenerated) |
47
- | Attached file or inline command handlers are refused with PLAY0800, a permanent requirement for a code implementation attachment (Requires Screenplay 4.210.0; older binders report PLAY0268); pending handlers with unconditional productions bind v23 as described commands, but reached bodies are Unsupported ImplementationBody and Stage refuses STAGE-IMPL-002 even in Stub mode | Screenplay and Stage; use the model as the gap-fill contract |
47
+ | Attached file or inline command handlers bind beside unconditional `produces` with a resolved body (Screenplay 4.250.0) and are otherwise refused with PLAY0800 (4.210.0 to 4.249.x refuse every attached handler; older binders report PLAY0268); pending handlers with unconditional productions bind v23 as described commands, but reached bodies are Unsupported ImplementationBody and Stage refuses STAGE-IMPL-002 even in Stub mode | Screenplay and Stage; use the model as the gap-fill contract |
48
48
 
49
49
  ## Procedure
50
50
 
@@ -83,9 +83,9 @@ module Marina
83
83
  screen BerthListScreen
84
84
  title "Berths"
85
85
  data BerthListView[] via query ListBerths
86
- action BookBerth
86
+ action BookBerth for screen
87
87
  label "Book a berth"
88
- action CancelBerth
88
+ action CancelBerth for item
89
89
  table BerthListView
90
90
  column boatName label "Boat"
91
91
  on row-click navigate to BerthDetailsScreen by berthId
@@ -94,7 +94,7 @@ module Marina
94
94
  data BerthListView via query GetBerth by berthId
95
95
  summary BerthListView
96
96
  field boatName label "Boat"
97
- action CancelBerth
97
+ action CancelBerth for item
98
98
  navigate to BerthListScreen
99
99
 
100
100
  form BookBerthForm for BookBerth
@@ -119,8 +119,8 @@ field because `berthId` is the identifier, not something the user types.
119
119
  | `table BerthListView` with `column boatName label "Boat"` | `<DataPage.Columns><Column field='boatName' header='Boat' /></DataPage.Columns>`; one `Column` per modeled `column`, no extras | Verified |
120
120
  | A second `table` on one screen | `DataTableForQuery` / `DataTableForObservableQuery` ([data-tables.md](data-tables.md)) | Verified |
121
121
  | `summary BerthListView` with `field boatName label "Boat"` | Plain markup in the page or in `detailsComponent` (`{ item }`), one labelled line per modeled `field` | Gap: this skill's verified sources name no summary component |
122
- | `action BookBerth` with `label "Book a berth"` | `<MenuItem label='Book a berth' icon={...} command={() => showBookBerth()} />` plus `CommandDialog` and `useDialog` | Verified |
123
- | `action CancelBerth` on a list with a table | `MenuItem` with `disableOnUnselected`; the selected row supplies the identifier | Verified prop |
122
+ | `action BookBerth for screen` with `label "Book a berth"` | `<MenuItem label='Book a berth' icon={...} command={() => showBookBerth()} />` plus `CommandDialog` and `useDialog`; no row fills its inputs | Verified |
123
+ | `action CancelBerth for item` on a list with a table | `MenuItem` with `disableOnUnselected`; the selected row supplies the identifier | Verified prop |
124
124
  | `action` with no `label` | The model gives no text. Use the command name, spaced, and report it | Gap |
125
125
  | `action X` with `navigate to S [by p]` | Navigate to the page for `S` after the command succeeds, in `onSuccess`; pass `p` from the response or the row | Assumption: `screens.md` does not say when it navigates. The form's `on submit` is defined as "after a successful submit"; confirm with the model owner |
126
126
  | `on row-click navigate to S by p` | `DataPage` and `DataTableForQuery` forward no row-click prop (only `DataTableCore` has `onRowClick`, and it takes rows, not a query). Use controlled `selection` and `onSelectionChange` to navigate, or a link in a `Column` `body` | Gap: selection is not a click; report which you chose |
@@ -95,7 +95,12 @@ another version behaves the same.
95
95
 
96
96
  ## When / when not
97
97
  - Use: "when X happens, then ...", schedules, retries, work queues, notifications, webhooks, APIs,
98
- files or message feeds, events imported from another context, legacy sync.
98
+ files or message feeds, events imported from another context, legacy sync, lifecycles and
99
+ longer processes.
100
+ - A lifecycle (where one thing is and what moves it on) is a `statemachine`; a process that
101
+ sends several commands, waits, asks for approval or gives up after a deadline is a
102
+ `workflow` (ESM v36). Read
103
+ [state machines and workflows](references/statemachines-and-workflows.md) before modeling either.
99
104
  - Not for: reaction, trigger or CDL grammar (`cratis-screenplay-captures-and-reactions`); stream
100
105
  identity and invariants (`cratis-screenplay-streams-and-consistency`); UI interactions such as
101
106
  `on click` (`cratis-screenplay-ui-composition`); hand-written reactors (`cratis-chronicle-reactor`).
@@ -13,7 +13,7 @@
13
13
  - 9. Fan-out
14
14
  - 10. Long-running process shapes
15
15
 
16
- Complete compiled example: `todo-list-example.md` (binds as ESM v6; the list query
16
+ Complete compiled example: `todo-list-example.md` (binds as ESM v34 for `then invokes`; the list query
17
17
  excerpt binds too, and the retry sweep that needs code is shown as a marked excerpt).
18
18
 
19
19
  ## 1. Deciding whether it is an automation
@@ -63,11 +63,11 @@ One spec in the slice does not cover the others.
63
63
  - Current admitted Automation/Translate specifications run through standalone
64
64
  `screenplay test` or MCP `run-specifications`. Validate/render alone is not V4;
65
65
  report unsupported/unbound separately from passing scenarios.
66
- - A command spec lists the cascade (v6 semantics: after
67
- `when <Command>`, `then` lists every new fact, including reaction appends). Only when the V1
68
- tool's compiler stops before v6 does it report a false PLAY0285 on a cascade:
69
- then keep the cascade out of the command spec, specify it in the Automation slice
70
- (`when append <Trigger>`) and record the expectation. See `cratis-screenplay-scenario-coverage`.
66
+ - A specification runs only its own slice (Screenplay decision 0115). A command spec
67
+ states the command's own events; the Automation states what its reaction appends in
68
+ its own `when append <Trigger>` spec, and a command it invokes in another slice with
69
+ `then invokes <Command>` (ESM v34). Another slice's event in a spec is PLAY0285
70
+ (unreachable). See `cratis-screenplay-scenario-coverage`.
71
71
  - `given capture` never persists between specs: state the baseline in each record
72
72
  update spec. First records (root, child, nested) are added only; field-change
73
73
  `and`/`or` and transitions need previous state. Expressions/maps/unguarded record
@@ -0,0 +1,164 @@
1
+ # State machines and workflows (ESM v36)
2
+
3
+ ## Contents
4
+
5
+ - Which construct
6
+ - Complete example
7
+ - Specifications
8
+ - Diagnostics and targets
9
+
10
+ Requires Screenplay 5.1.0 or later (`screenplay --version`). Sources: Screenplay
11
+ `Documentation/screenplay/statemachines.md`, `workflows.md` and decision 0124.
12
+
13
+ ## Which construct
14
+
15
+ | The domain says | Model |
16
+ | --- | --- |
17
+ | "When X happens, do Y", one step | An `Automation` slice with a reaction |
18
+ | Where one thing is in its lifecycle, and what moves it on | A `statemachine` that follows the thing's read model |
19
+ | A longer process: several commands, a choice, a wait for a fact or a person, a deadline, a fan-out | A `workflow` with one run per subject |
20
+
21
+ A state machine never decides on commands: it follows facts that already happened. Entering
22
+ a state may `send` a command or `start` a workflow; both may run again on redelivery, so the
23
+ command or workflow must be safe to repeat. A workflow is how a process waits, retries, asks
24
+ for approval and gives up; do not chain reactions across slices to imitate one.
25
+
26
+ Both are top-level declarations, siblings of `trigger` and `policy`. They name commands,
27
+ events, read models and personas declared in slices of any module. A model that declares one
28
+ selects ESM v36.
29
+
30
+ ## Complete example
31
+
32
+ This model compiles with `--warnaserror` and its three specifications pass with
33
+ `screenplay test`:
34
+
35
+ ```screenplay
36
+ concept InvoiceId : Uuid
37
+ persona FinanceController
38
+ module Billing
39
+ feature Invoices
40
+ slice StateChange SendInvoice
41
+ command SendInvoice
42
+ invoiceId InvoiceId identifier
43
+ produces event InvoiceSent
44
+ slice StateChange MarkOverdue
45
+ command MarkOverdue
46
+ invoiceId InvoiceId identifier
47
+ produces event InvoiceMarkedOverdue
48
+ slice StateChange PayInvoice
49
+ command PayInvoice
50
+ invoiceId InvoiceId identifier
51
+ produces event InvoicePaid
52
+ slice StateChange SendReminder
53
+ command SendReminder
54
+ invoiceId InvoiceId identifier
55
+ produces event ReminderSent
56
+ slice StateChange WriteOffInvoice
57
+ command WriteOffInvoice
58
+ invoiceId InvoiceId identifier
59
+ produces event InvoiceWrittenOff
60
+ slice StateView InvoiceStatus
61
+ readmodel Invoice
62
+ invoiceId InvoiceId key
63
+ status String
64
+ projection Invoices => Invoice
65
+ from InvoiceSent
66
+ invoiceId = $eventSourceId
67
+ status = "sent"
68
+ from InvoiceMarkedOverdue
69
+ status = "overdue"
70
+ from InvoicePaid
71
+ status = "paid"
72
+ query InvoiceById => Invoice optional
73
+ by invoiceId InvoiceId
74
+
75
+ statemachine InvoiceLifecycle
76
+ description "Where an invoice is, from sent to settled"
77
+ follows Invoice
78
+ state Sent initial
79
+ on InvoiceMarkedOverdue -> Overdue
80
+ on InvoicePaid -> Paid
81
+ state Overdue
82
+ entering start CollectOverdue
83
+ on InvoicePaid -> Paid
84
+ on InvoiceWrittenOff -> WrittenOff
85
+ state Paid final
86
+ state WrittenOff final
87
+
88
+ specification GoingOverdueStartsCollection
89
+ given InvoiceSent
90
+ for "9c858901-8a57-4791-81fe-4c455b099bc9"
91
+ when append InvoiceMarkedOverdue
92
+ for "9c858901-8a57-4791-81fe-4c455b099bc9"
93
+ then is Overdue
94
+ then starts CollectOverdue
95
+
96
+ workflow CollectOverdue
97
+ description "Reminds the customer, waits for payment and asks finance before writing off"
98
+ for Invoice
99
+ trigger when InvoiceLifecycle enters Overdue
100
+ -> Remind
101
+ action Remind sends SendReminder
102
+ next -> AwaitPayment
103
+ wait AwaitPayment for InvoicePaid expires after 14 days
104
+ expired -> ApproveWriteOff
105
+ approval ApproveWriteOff by FinanceController expires after 7 days
106
+ approved -> WriteOff
107
+ action WriteOff sends WriteOffInvoice
108
+
109
+ specification AnUnpaidInvoiceIsWrittenOff
110
+ given InvoiceSent
111
+ for "9c858901-8a57-4791-81fe-4c455b099bc9"
112
+ when append InvoiceMarkedOverdue
113
+ for "9c858901-8a57-4791-81fe-4c455b099bc9"
114
+ outcome AwaitPayment expired
115
+ outcome ApproveWriteOff approved
116
+ then sends SendReminder
117
+ then sends WriteOffInvoice
118
+ then completes
119
+
120
+ specification TheRunWaitsForPayment
121
+ given InvoiceSent
122
+ for "9c858901-8a57-4791-81fe-4c455b099bc9"
123
+ when append InvoiceMarkedOverdue
124
+ for "9c858901-8a57-4791-81fe-4c455b099bc9"
125
+ then sends SendReminder
126
+ then waits at AwaitPayment
127
+ ```
128
+
129
+ - `follows Invoice` / `for Invoice`: the read model whose key is one instance (one run per
130
+ invoice). A transition condition (`on E when <condition> -> S`) reads that read model after
131
+ the event; a condition over an optional property is refused at binding.
132
+ - Exactly one `initial` state; a `final` state has no transitions. An event takes the first
133
+ transition on it, in declaration order across the whole machine, whose condition holds and
134
+ whose target the current state allows. Anything else is ignored, not an error.
135
+ - Workflow nodes: `trigger` (`on <Event>`, `when <StateMachine> enters <State>`, `every`,
136
+ `at`, `manual`), `action <Name> sends <Command> [attempts n] [timeout] [retry after]`,
137
+ `decide <Name> when <condition>` with exactly two outlets, `wait` for an event or a
138
+ duration, `approval <Name> by <Persona or Policy>`, `foreach <Name> over <collection>` and
139
+ `join all|any|at least n`. Edges are `<outlet> -> <Node>` under their node.
140
+ - An unconnected negative outlet (`failed`, `rejected`, `expired`) fails the run; an
141
+ unconnected positive outlet ends that branch. Give every event wait and approval an
142
+ `expires after` (PLAY0849 warns otherwise).
143
+
144
+ ## Specifications
145
+
146
+ | Construct | Lines |
147
+ | --- | --- |
148
+ | `statemachine` | `given <Event>`, `when append <Event>`, `then is <State>`, `then sends <Command>`, `then starts <Workflow>` (every command and workflow, in order) |
149
+ | `workflow` | `given <Event>`, `when append <Event>` or `when start <key>`, `outcome <Node> <outlet>`, `then sends <Command>` (every one, in order), `then completes`, `then fails at <Node>`, `then waits at <Node>` |
150
+
151
+ The reference evaluator steps the run deterministically. A wait or approval with no stated
152
+ `outcome` suspends the run (`then waits at`); an action defaults to `next`; a wait for a
153
+ duration resumes at once.
154
+
155
+ ## Diagnostics and targets
156
+
157
+ - State machines: PLAY0834-PLAY0842 (missing or duplicate `initial` is PLAY0835, an
158
+ unreachable state warns PLAY0836, an undeclared reference is PLAY0840).
159
+ - Workflows: PLAY0843-PLAY0851 (no trigger is PLAY0844, a bad outlet PLAY0847, a decision
160
+ without exactly two outlets PLAY0848, an undeclared reference PLAY0851); PLAY0839 and
161
+ PLAY0841 are shared.
162
+ - Stage refuses ESM v36 models with `STAGE-ESM-016`; every other model renders as
163
+ before. The durable engine is Cratis.Orleans; its hosting and adapters are outside this
164
+ reference.
@@ -5,14 +5,15 @@
5
5
  - Design-only additions
6
6
 
7
7
  A complete model: a result opens a work item, a reaction invokes a command, the command's fact
8
- closes the item. It binds as ESM v6 (`executableReady: true`), standalone and through `cratis screenplay mcp`.
9
- Stage renders supported event reactions, but this model's clock/cascade specs remain
10
- refused (`-024`/`-011`); keep them intact. A compiler that stops before v6 rejects the
11
- Automation slice at binding with PLAY0285 or PLAY0268. Versions: `cratis-screenplay-toolchain` `SKILL.md`.
12
-
13
- The first spec lists the whole cascade (`then` names every new fact: `CoursePassed`, and
14
- `CertificateSent` through the reaction), and `given clock` supplies the instant that
15
- `$context.occurred` needs. Both tools accept that cascade when they admit v6; an older compiler reports a false PLAY0285 on it.
8
+ closes the item. `then invokes` selects ESM v34 (`executableReady: true` from Screenplay 4.246.0),
9
+ standalone and through `cratis screenplay mcp`. The Stage spec runner compares `then invokes`, but the
10
+ Cratis renderer refuses models after v33 with `STAGE-ESM-016`; keep the specifications intact. A compiler
11
+ that stops before v34 refuses `then invokes`. Versions: `cratis-screenplay-toolchain` `SKILL.md`.
12
+
13
+ Each specification states only its own slice (Screenplay decision 0115): `RecordingAPass`
14
+ states `CoursePassed`, `SendingAfterAPass` states the hand-over with `then invokes
15
+ SendCertificate` (ESM v34), and `SendingACertificate` states `CertificateSent`. `given clock`
16
+ supplies the instant that `$context.occurred` needs.
16
17
  Current admitted scenarios can be run with
17
18
  standalone `screenplay test` or MCP `run-specifications`.
18
19
 
@@ -58,7 +59,7 @@ module Courses
58
59
  CoursePassed
59
60
  for enrolmentId
60
61
  enrolmentId = enrolmentId // copied on purpose: the reaction selects it as a value
61
- completedAt = $context.occurred // carried on the fact: a projection cannot read $eventContext.occurred
62
+ completedAt = $context.occurred // carried on the fact, so every reader sees the same instant
62
63
  produces when passed == false
63
64
  CourseFailed
64
65
  for enrolmentId
@@ -81,9 +82,6 @@ module Courses
81
82
  for "0d3b9e2a-6c4f-4f1e-8b7a-5e2d1c3b4a01"
82
83
  enrolmentId = "0d3b9e2a-6c4f-4f1e-8b7a-5e2d1c3b4a01"
83
84
  completedAt = "2026-10-05T08:00:00Z"
84
- then CertificateSent
85
- for "0d3b9e2a-6c4f-4f1e-8b7a-5e2d1c3b4a01"
86
- sentAt = "2026-10-05T08:00:00Z"
87
85
  specification RefusingANonCoordinator
88
86
  given caller
89
87
  authenticated
@@ -180,9 +178,8 @@ module Certification
180
178
  for "0d3b9e2a-6c4f-4f1e-8b7a-5e2d1c3b4a01"
181
179
  enrolmentId = "0d3b9e2a-6c4f-4f1e-8b7a-5e2d1c3b4a01"
182
180
  completedAt = "2026-10-05T08:00:00Z"
183
- then CertificateSent
184
- for "0d3b9e2a-6c4f-4f1e-8b7a-5e2d1c3b4a01"
185
- sentAt = "2026-10-05T08:00:00Z"
181
+ then invokes SendCertificate
182
+ enrolmentId = "0d3b9e2a-6c4f-4f1e-8b7a-5e2d1c3b4a01"
186
183
  ```
187
184
 
188
185
  ## Design-only additions
@@ -93,9 +93,6 @@ module Exams
93
93
  for "7e9d1c2b-4a3f-4e5d-8c6b-1a2b3c4d5e06"
94
94
  outcome = "passed"
95
95
  score = 87
96
- then ExamPassed
97
- for "7e9d1c2b-4a3f-4e5d-8c6b-1a2b3c4d5e06"
98
- score = 87
99
96
  slice Automation RecordExamResult
100
97
  reaction PassTranslator
101
98
  when ProctorResultReceived
@@ -115,6 +112,14 @@ module Exams
115
112
  constraint OneResultPerAttempt
116
113
  unique event ExamPassed
117
114
  unique event ExamFailed
115
+ specification RecordingAPass
116
+ when append ProctorResultReceived
117
+ for "7e9d1c2b-4a3f-4e5d-8c6b-1a2b3c4d5e06"
118
+ outcome = "passed"
119
+ score = 87
120
+ then ExamPassed
121
+ for "7e9d1c2b-4a3f-4e5d-8c6b-1a2b3c4d5e06"
122
+ score = 87
118
123
  specification RefusingASecondResult
119
124
  given ExamPassed
120
125
  for "7e9d1c2b-4a3f-4e5d-8c6b-1a2b3c4d5e06"
@@ -131,7 +136,8 @@ module Exams
131
136
  - Keep the capture and its appended event in Translate; put reactions to that local
132
137
  event in a separate Automation. Co-location in a directionless Translate warns
133
138
  PLAY0694 and fails `--warnaserror`; explicit inbound refuses it with PLAY0616.
134
- `then` lists every new fact, so `TranslatingAPass` includes the Automation result.
139
+ A specification runs only its own slice (Screenplay decision 0115), so `TranslatingAPass`
140
+ states the Translate slice's fact and `RecordingAPass` states the Automation's result.
135
141
  - `when added` records first sight; the separate `when outcome` append handles
136
142
  later changes. For an update spec, seed the same reference with `given capture`.
137
143
  Requires Screenplay 4.175.0 or later (`screenplay --version`); older evaluators
@@ -289,8 +289,8 @@ module Collections
289
289
  when trigger PaymentFileArrived
290
290
  invoiceId = "9c858901-8a57-4791-81fe-4c455b099bc9"
291
291
  amount = 120
292
- then InvoiceClosed
293
- for "9c858901-8a57-4791-81fe-4c455b099bc9"
292
+ then invokes CloseInvoice
293
+ invoiceId = "9c858901-8a57-4791-81fe-4c455b099bc9"
294
294
  reason = "paid"
295
295
  specification IssuingTheWeeklyDigest
296
296
  given clock "2026-10-05T07:00:00Z"
@@ -54,10 +54,16 @@ module Work
54
54
  specification ProcessingRequestedWork
55
55
  when append WorkRequested
56
56
  workId = "work-1"
57
- then WorkRecorded
58
- for "work-1"
57
+ then invokes RecordWork
58
+ workId = "work-1"
59
59
  ```
60
60
 
61
+ The automation states the hand-over with `then invokes` (ESM v34). `RecordWork` is
62
+ decided under the declared system identity, so a denial would reach the reaction's
63
+ refusal branches, but `WorkRecorded` belongs to the `RecordWork` slice and is not kept
64
+ in this specification (Screenplay decision 0115). `RecordWork`'s own slice proves the
65
+ event with a `when RecordWork` specification.
66
+
61
67
  ## Diagnostics and target boundaries
62
68
 
63
69
  - PLAY0647: malformed, repeated or misplaced identity, including duplicate/empty roles.
@@ -105,11 +105,12 @@ fix to migrate. `--warnaserror` does not reject information diagnostics.
105
105
  properties, `reads`, `authorize`, `validate`, `produces`/`handler`, `concurrency`.
106
106
  Keep to it.
107
107
 
108
- A file/code `handler` cannot coexist with `produces` and fails binding
109
- with PLAY0800 (`CommandHandlerRequiresAttachment`): gap-fill the slice in code
110
- with a constrained implementation attachment, not by waiting for a new ESM version.
108
+ A file/code `handler` beside unconditional `produces`, with a resolved nonempty body,
109
+ binds as the v23 result contract: `produces` fixes the
110
+ events and the body owns their property values. Without `produces`, with `produces ... when`,
111
+ or with an unresolved body it fails binding with PLAY0800 (`CommandHandlerRequiresAttachment`).
111
112
  Read the required typed `subject` argument for the command, never parse the message.
112
- Requires Screenplay 4.210.0 (`screenplay --version`) for PLAY0800; older binders use PLAY0268 for this refusal. A pending `handler implementation` beside unconditional `produces`
113
+ Requires Screenplay 4.250.0 (`screenplay --version`); 4.210.0 to 4.249.x refuse every attached handler with PLAY0800 and older binders use PLAY0268. A pending `handler implementation` beside unconditional `produces`
113
114
  is a described command (ESM v23): the body owns payload values only. Prefer plain
114
115
  `produces` for declarative logic. Read [described handlers](references/described-handlers.md)
115
116
  when logic needs prose, for the result contract, PLAY0695–0698, Unsupported
@@ -32,13 +32,17 @@ module Invoices
32
32
 
33
33
  A pending `implementation` has no `file` or fence. Bare `implementation` is valid;
34
34
  optional `hint` lines are ordered, nonblank quoted strings, decoded without trimming.
35
- One wrapper and at most one payload are permitted. Attaching a file or fence stops
36
- being a described command: attached handlers fail binding with PLAY0800
37
- (`CommandHandlerRequiresAttachment`) and cannot coexist with `produces`.
38
- This permanent limitation requires a constrained implementation attachment:
39
- gap-fill the slice in code, not by waiting for a supported ESM version.
40
-
41
- Requires Screenplay 4.210.0 (`screenplay --version`) for PLAY0800 and its required typed `subject` declaration argument naming the command; older binders use PLAY0268. Hosts switch on the code and read `arguments.subject`, never parse the message.
35
+ One wrapper and at most one payload are permitted. Attaching a file or fence makes it
36
+ an attached handler. Beside unconditional `produces`, with a resolved, nonempty,
37
+ language-tagged body, it binds with the same v23 result contract (Screenplay 4.250.0,
38
+ decision 0117): the productions fix event types, count, order and destinations, and
39
+ the body owns property values. Reaching the body in reference execution is Unsupported
40
+ (`ImplementationBody`) and appends nothing. An attached handler with no `produces`,
41
+ with `produces ... when`, or with an empty or unresolved body fails binding with PLAY0800
42
+ (`CommandHandlerRequiresAttachment`): declare unconditional `produces`, split variable
43
+ outcomes into separate commands, or attach a resolved body.
44
+
45
+ Requires Screenplay 4.250.0 (`screenplay --version`) for attached handlers beside `produces` to bind; 4.210.0 to 4.249.x refuse every attached handler with PLAY0800, and older binders use PLAY0268. Hosts switch on the code and read `arguments.subject`, never parse the message.
42
46
 
43
47
  ## Result contract v1
44
48
 
@@ -61,7 +65,7 @@ explicitly admit this version, never silently drop the body.
61
65
 
62
66
  | Diagnostic | Meaning and action |
63
67
  | --- | --- |
64
- | PLAY0800 (error) | File/inline handler requires a constrained implementation attachment; `subject` identifies the command to gap-fill |
68
+ | PLAY0800 (error) | File/inline handler without unconditional `produces` or a resolved, nonempty body; `subject` identifies the command |
65
69
  | PLAY0695 (information) | Described command admitted; command and RequirementId name the missing body |
66
70
  | PLAY0696 (error) | No productions, including response-only; add unconditional productions |
67
71
  | PLAY0697 (error) | Conditional productions; result v1 needs unconditional events |
@@ -98,11 +98,11 @@ validate
98
98
 
99
99
  A bodied rule or fenced block on a validation, rule or policy binds as opaque code
100
100
  (ESM v3): the reference runner reports it unsupported, and a target must supply the
101
- implementation. Attached command handlers refuse PLAY0800 and require constrained
102
- implementation attachments; `file` constraints retain PLAY0268 (only `unique`
103
- constraints bind). Requires Screenplay 4.210.0 (`screenplay --version`) for the
104
- handler's PLAY0800; older binders use PLAY0268. Pending command handlers beside unconditional
105
- `produces` instead bind as described commands; see [described handlers](described-handlers.md).
101
+ implementation. Attached command handlers bind beside unconditional `produces` with a
102
+ resolved body (Screenplay 4.250.0) and otherwise refuse PLAY0800; `file` constraints
103
+ retain PLAY0268 (only `unique` constraints bind). Pending and attached command handlers
104
+ beside unconditional `produces` share the v23 result contract; see
105
+ [described handlers](described-handlers.md).
106
106
  Literal text rules, portable patterns and Studio desugaring: [text and match rules](text-and-match-rules.md).
107
107
  Stage renders pure reducer transitions and opaque policy bodies, but refuses command and
108
108
  concept code validations and rule predicates (STAGE-ESM-005): those are gap-fill code. Prefer a
@@ -52,7 +52,7 @@
52
52
  },
53
53
  {
54
54
  "kind": "skill-contains",
55
- "value": "A file/code `handler` cannot coexist with `produces`"
55
+ "value": "A file/code `handler` beside unconditional `produces`, with a resolved nonempty body,"
56
56
  },
57
57
  {
58
58
  "kind": "skill-contains",
@@ -274,11 +274,14 @@ module Invoicing
274
274
  specification IssuingOnMonday
275
275
  given clock "2026-10-05T07:00:00Z"
276
276
  when clock "2026-10-05T07:30:00Z"
277
- then CollectionsDigestIssued
278
- for "weekly"
279
- issuedAt = "2026-10-05T07:30:00Z"
277
+ then invokes IssueCollectionsDigest
278
+ period = "weekly"
280
279
  ```
281
280
 
281
+ Each slice proves its own link (Screenplay decision 0115): the automation states the
282
+ command it invokes with `then invokes` (ESM v34), and `IssuingTheDigest` in the command's
283
+ slice states `CollectionsDigestIssued`.
284
+
282
285
  At the example's verified Screenplay version, iterating the overdue items needs code (a clock trigger reads the whole view and takes
283
286
  no `by`); see `cratis-screenplay-automations-and-translations`. A reaction that `produces`
284
287
  directly while it `reads` fails binding (`PLAY0268`): decide in a command instead.
@@ -178,9 +178,9 @@ resolved adapter version, diagnostic, retained/withheld form and open question:
178
178
  `MaximumExecutableModelVersion` below v15 withholds non-default concept generation
179
179
  with SP0073 and dependent values/responses/mappings with SP0052; pins against them
180
180
  withhold scenarios with SP0039. Below v7 responses/return expectations are withheld.
181
- A cap describes less behavior, not an equivalent implementation. Handler references
182
- compile but refuse executable binding (PLAY0800 for file/inline command handlers);
183
- record that verdict separately and gap-fill the slice with a constrained implementation
184
- attachment, not by waiting for ESM admission.
181
+ A cap describes less behavior, not an equivalent implementation. A file/inline command
182
+ handler binds only beside unconditional `produces` with a resolved body (Screenplay
183
+ 4.250.0); otherwise it refuses executable binding with PLAY0800. Record that verdict
184
+ separately and gap-fill the slice in code.
185
185
  Requires Screenplay 4.210.0 (`screenplay --version`); older binders use PLAY0268 for these handlers.
186
186
  Never remove protection, required payloads or loss rows to obtain a green result.
@@ -257,7 +257,7 @@ See read-surface `references/named-keys.md` for the collection-key exclusion alg
257
257
  | Disposition | Constructs |
258
258
  | --- | --- |
259
259
  | 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` |
260
- | 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) |
260
+ | 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 and occurrence time in a projection mapping or key, such as `$eventContext.sequenceNumber` or `$eventContext.causedBy.subject` (`$eventSourceId` and `$eventContext.eventSourceId` run; `$eventContext.occurred` runs in `from`, `every` and `children` blocks for facts appended during the run under `given clock`, while a `given` fact carries no occurrence time and reports Unsupported) |
261
261
  | Binds as ESM v6 (`PLAY0268` on a compiler that stops before v6) | `Automation` and `Translate` slices, reactions that produce or invoke, captures, top-level `trigger`, clock, trigger and capture specifications. The standalone `screenplay test`/MCP reference route evaluates admitted v6 actions; Stage renders supported event-triggered Automation, with remaining refusals in the Stage skill's `references/admission.md` |
262
262
  | Reaction with trigger `reads` | Direct-producing (or code-bodied) reaction with `reads`: `PLAY0268` ("ESM v6 cannot protect that decision dependency"), non-executable. Invokes-only reaction with `reads`: information only; the invoked command must declare and protect its own decision reads. Keep the `reads`; never remove them to obtain binding |
263
263
  | Binds as opaque code (v3); reference runner reports unsupported | Bodied reducers, bodied named rules, fenced `validate` blocks, code or file policies. A pure reducer body is the only attachment Stage admits |
@@ -279,7 +279,7 @@ See read-surface `references/named-keys.md` for the collection-key exclusion alg
279
279
  | 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`. |
280
280
  | 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 |
281
281
  | 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; 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) or a `by` block on a list query or non-optional single result (a `performer` query is not refused: it is an opaque read, PLAY0270, left out of the executable model; [version gate](../../cratis-screenplay-toolchain/references/executable-subset.md#code-attachments-what-binds-what-never-does)); optional keyed and collection queries, including caller-supplied equality filters and observable delivery, bind, `$causedBy` and templates in projections |
282
- | Blocks binding (`PLAY0800`, permanent attachment requirement) | Attached file/inline command `handler`: gap-fill the slice with a constrained implementation attachment, not by waiting for ESM admission. PLAY0035 beside productions; pending described intent instead binds v23. Read required typed `arguments.subject` for the command, never parse the message. Compiler prerequisite and older PLAY0268 attribution: [diagnostic arguments](../../cratis-screenplay-toolchain/references/diagnostic-arguments.md) |
282
+ | Blocks binding (`PLAY0800`) | Attached file/inline command `handler` with no unconditional `produces`, with `produces ... when`, or with an unresolved body. Beside unconditional `produces` with a resolved body it binds as the v23 result contract, and pending described intent also binds v23 (command-surface `references/described-handlers.md` has the compiler gate). Read required typed `arguments.subject` for the command, never parse the message. Compiler prerequisite and older PLAY0268 attribution: [diagnostic arguments](../../cratis-screenplay-toolchain/references/diagnostic-arguments.md) |
283
283
  | Blocks binding (`PLAY0271`, legacy meaning) | Command reads without protected opt-in and `concurrency`; combined protected reads/concurrency is PLAY0783 |
284
284
  | Deferred (`PLAY0269`, information) | Screens, layouts, templates, forms, contributions, UI profiles, themes, behaviors and `on`/`uses` |
285
285
  | Metadata only (`PLAY0270`, information) | `domain`, `seed`, `persona`, trigger and other descriptions, and `file` provenance on declarations |
@@ -183,7 +183,9 @@ module Billing
183
183
  when append PaymentRemoved
184
184
  invoice = "INV-1"
185
185
  method = "card"
186
- then no readmodel PaymentTotals for {"invoiceId":"INV-1","method":"card"}
186
+ then no readmodel PaymentTotals for
187
+ invoiceId = "INV-1"
188
+ method = "card"
187
189
  then readmodel PaymentTotals
188
190
  invoiceId = "INV-1"
189
191
  method = "cash"
@@ -83,7 +83,7 @@ module Berths
83
83
  berth BerthName = berth
84
84
  screen BookBerthScreen
85
85
  title "Book a berth"
86
- action BookBerth
86
+ action BookBerth for screen
87
87
  navigate to OpenBookingsScreen
88
88
  specification BookingABerth
89
89
  given caller
@@ -115,7 +115,7 @@ module Berths
115
115
  screen OpenBookingsScreen
116
116
  title "Open bookings"
117
117
  data OpenBooking[] via query ListOpenBookings
118
- action BookBerth
118
+ action BookBerth for screen
119
119
  ```
120
120
 
121
121
  ## What a screen pattern is not