@cratis/pi 7.91.0 → 7.93.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 (35) hide show
  1. package/package/corpus/product-sync.json +2 -2
  2. package/package/corpus/skills/cratis-screenplay-command-surface/references/inline-events.md +4 -1
  3. package/package/corpus/skills/cratis-screenplay-command-surface/references/text-and-match-rules.md +17 -0
  4. package/package/corpus/skills/cratis-screenplay-model-authoring/SKILL.md +1 -1
  5. package/package/corpus/skills/cratis-screenplay-model-authoring/references/language-reference.md +1 -1
  6. package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-tools.md +21 -6
  7. package/package/corpus/skills/cratis-screenplay-model-authoring/references/property-links.md +22 -1
  8. package/package/corpus/skills/cratis-screenplay-model-authoring/references/repairs.md +5 -2
  9. package/package/corpus/skills/cratis-screenplay-model-review/SKILL.md +6 -3
  10. package/package/corpus/skills/cratis-screenplay-model-review/references/checklist.md +4 -4
  11. package/package/corpus/skills/cratis-screenplay-model-review/references/model-inventory-report.md +2 -1
  12. package/package/corpus/skills/cratis-screenplay-model-review/references/verified-sources.md +1 -1
  13. package/package/corpus/skills/cratis-screenplay-read-surface/SKILL.md +9 -4
  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 +1 -1
  16. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/renderability-gate.md +1 -1
  17. package/package/corpus/skills/cratis-screenplay-scenario-coverage/SKILL.md +8 -2
  18. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/scenario-examples.md +2 -2
  19. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/spec-forms-by-mode.md +4 -3
  20. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/view-and-story-specs.md +1 -1
  21. package/package/corpus/skills/cratis-screenplay-slice-design/SKILL.md +1 -1
  22. package/package/corpus/skills/cratis-screenplay-slice-design/references/read-model-design.md +3 -2
  23. package/package/corpus/skills/cratis-screenplay-specifications/SKILL.md +6 -2
  24. package/package/corpus/skills/cratis-screenplay-specifications/references/examples-and-routes.md +19 -0
  25. package/package/corpus/skills/cratis-screenplay-specifications/references/vocabulary.md +4 -0
  26. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/SKILL.md +3 -1
  27. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/stream-id-rules.md +4 -0
  28. package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +1 -1
  29. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +9 -0
  30. package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +10 -8
  31. package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +2 -2
  32. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.version +1 -1
  33. package/package/corpus/skills/cratis-screenplay-toolchain/references/traps.md +1 -1
  34. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +1 -1
  35. package/package.json +1 -1
@@ -171,9 +171,9 @@
171
171
  }
172
172
  ],
173
173
  "synced": {
174
- "version": "4.231.0",
174
+ "version": "4.232.0",
175
175
  "date": "2026-10-19",
176
- "by": "Cratis/AI#808"
176
+ "by": "Cratis/AI#823"
177
177
  },
178
178
  "covers": {
179
179
  "skills": [
@@ -80,6 +80,9 @@ MCP can declare a missing produced event (`PLAY0166`), add explicit routing
80
80
  (`PLAY0478`), remove a redundant pin (`PLAY0471`), or remove an inline identifier
81
81
  copy (`PLAY0469`). The last **changes the event contract**, retires a property,
82
82
  refuses affected consumers/opaque implementations and is not fix-all. It does
83
- not establish that stored data is safe to migrate. Use
83
+ not establish that stored data is safe to migrate; for a contract that may have been
84
+ stored, `propose-property` `remove` with `newGeneration: true` extracts the event and
85
+ drafts a new generation (a source draft, never deployment ready; requires Screenplay
86
+ 4.232.0, `screenplay --version`). Use
84
87
  `cratis-screenplay-model-authoring` for discovery, preview, extraction and rename.
85
88
 
@@ -63,6 +63,23 @@ settings. Syntax remains `matches "^INV-[0-9]{6}$"` or `matches email`.
63
63
 
64
64
  `\s` includes U+00A0, U+FEFF and Unicode line/paragraph separators; it excludes
65
65
  U+0085. Dot excludes LF, CR, U+2028 and U+2029. `\w` excludes U+0130.
66
+ ### Write unambiguous patterns (PLAY0803)
67
+
68
+ Requires Screenplay 4.218.2 or later (`screenplay --version`); older compilers do not warn.
69
+
70
+ Generated clients run the pattern in a browser's backtracking engine, so an exponentially
71
+ ambiguous pattern can hang a tab on a crafted value even though Screenplay's own automaton
72
+ stays linear. The warning `PLAY0803` (`AmbiguousMatchPattern`) names the ambiguous
73
+ subexpression and a simpler rewrite where one exists; C#, TypeScript, Monaco and VS Code
74
+ report it identically. Very large patterns are not analyzed, so keep them small anyway.
75
+
76
+ | Ambiguous | Write instead |
77
+ | --- | --- |
78
+ | `(a+)+$`, `(a*)*` | `a+`, `a*` (never quantify a group whose body already repeats) |
79
+ | `(a\|a)*` | `a*` (alternatives must not match the same text) |
80
+
81
+ Prefer a character class such as `[ab]*` over alternatives that overlap. Fix the pattern rather than suppressing the warning; validate with `--warnings-as-errors`.
82
+
66
83
  `matches email` is conservative, not RFC 5322: one `@`, nonempty local part without
67
84
  whitespace/`@`, and at least two nonempty domain parts without whitespace/`@`.
68
85
  A no-break space therefore fails email validation. Other bare names report PLAY0366.
@@ -175,7 +175,7 @@ Choose formatting and disclose dropped comments before apply:
175
175
 
176
176
  ## Repair or extract before rewriting
177
177
 
178
- Read `read-workspace` with `view: "repairs"` at the same revision as diagnostics and pass the repair to `propose-repair`; use `propose-extract-inline-event` before adding generations. `PLAY0469` changes the event contract, so ask about stored contracts first. No automatic generation-evolution repair ships. `PLAY0479`: migrate optionality spelling with `PreserveTrivia`. `eventNeverPersisted: true` cannot unfreeze admitted revisions. Differing event pins carry `storedName` in ESM v16, shared by all generations and unique (PLAY0472). Read [references/repairs.md](references/repairs.md) when fixing `PLAY0166`, `PLAY0478`, `PLAY0516` or `PLAY0683`, or admitting a [release baseline](references/release-baseline.md). Read [references/destination-intent-repair.md](references/destination-intent-repair.md) when `PLAY0470` needs a repair.
178
+ Read `read-workspace` with `view: "repairs"` at the same revision as diagnostics and pass the repair to `propose-repair`; use `propose-extract-inline-event` before adding generations, or let a `remove` with `newGeneration: true` extract the inline event itself, as [property links](references/property-links.md) describes. `PLAY0469` changes the event contract, so ask about stored contracts first. No automatic generation-evolution repair ships. `PLAY0479`: migrate optionality spelling with `PreserveTrivia`. `eventNeverPersisted: true` cannot unfreeze admitted revisions. Differing event pins carry `storedName` in ESM v16, shared by all generations and unique (PLAY0472). Read [references/repairs.md](references/repairs.md) when fixing `PLAY0166`, `PLAY0478`, `PLAY0516` or `PLAY0683`, or admitting a [release baseline](references/release-baseline.md). Read [references/destination-intent-repair.md](references/destination-intent-repair.md) when `PLAY0470` needs a repair.
179
179
 
180
180
  ## Choose a readable layout
181
181
 
@@ -278,7 +278,7 @@ See read-surface `references/named-keys.md` for the collection-key exclusion alg
278
278
  | 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 and, in a new enough bundle, renders protected reads as Arc read protection, refusing unpreservable shapes and every older bundle with STAGE-ESM-044; semantic Host/executor execute admitted reads with non-Error protected requirements refused STAGE-ESM-045 |
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
- | 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), `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 |
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
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) |
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` |
@@ -319,7 +319,7 @@ with `view: "diagnostics"`, then `view: "repairs"` at the current revision.
319
319
  | `PLAY0166` | Declare a missing command-produced event in its slice. Infer known command-path types (retaining concepts) or `$context.occurred` as `DateTime`; refuse uncertain/conflicting shapes, imports, existing declarations, cross-file producers and parser-invalid workspaces. |
320
320
  | `PLAY0478` | Add `for <identifier>` to a plain production. Both models must be executable; refuse a version change or retargeting another production. This changes routing: accept only if the identifier, not allocation, is intended; `canFixAll: false`. |
321
321
  | `PLAY0471` | Remove a redundant event id only with unchanged executable model, catalog and comments. |
322
- | `PLAY0469` | Remove an inline same-source identifier property and mapping, retiring its semantic address. This changes the contract; `canFixAll` is false. Refuse other consumers, opaque impact, changed routing or comment loss. Plain contracts get guidance only. |
322
+ | `PLAY0469` | Remove an inline same-source identifier property and mapping, retiring its semantic address. This changes the contract; `canFixAll` is false. Refuse other consumers, opaque impact, changed routing or comment loss. Plain contracts get guidance only. For a contract that may have been stored, use `propose-property` `remove` with `newGeneration: true` instead. |
323
323
  | `PLAY0479` | Migrate one optional type spelling, or all in a document, preserving syntax and trivia. Exclude `query Q => observable?`. |
324
324
  | `PLAY0563/0564` | Expand a one-line interaction alternative / turn a strict item `where` into one block-form `when`. Individual review, canonical formatting, no pinned evidence; refuse comment loss. Opaque non-item-condition text has no PLAY0564 repair. |
325
325
  | `PLAY0614` | Declare Translate direction only when exactly one inbound/outbound interpretation fits public metadata; never change event visibility to make a repair fit. |
@@ -362,9 +362,12 @@ Requires Screenplay 4.228.0 (`screenplay --version`) for `propose-inline-event`.
362
362
  `propose-inline-event` is the inverse: it folds a slice-level event with exactly one
363
363
  production into an inline event on that production, takes the same `subject`,
364
364
  revisions and `formatting: "CanonicalizeTouchedDocuments"`, and preserves executable
365
- bytes and identities. It refuses when the fold could change meaning (a conditional
366
- production, public or external event, cross-slice use, handlers, lost comments or any
367
- other reference to the event).
365
+ bytes and identities. Use it to undo an extraction when the event has one producer and
366
+ no other consumer. It refuses when the fold could change meaning: a conditional
367
+ production (`when`), incomplete mappings, generations, an external origin or public
368
+ event, cross-slice or cross-document use, opaque or handler text, comments that would
369
+ be lost, or any reference other than the single production. Read the refusal and
370
+ leave the event standalone; never work around it with text edits.
368
371
 
369
372
  Requires Screenplay 4.223.0 (`screenplay --version`) for `trace-lineage`.
370
373
 
@@ -448,7 +451,14 @@ correctness repair; PLAY0667–0670 require an author decision, with no automati
448
451
 
449
452
  Sources/streams and command/specification routes bind as ESM v8 and have
450
453
  catalog identities; `executionAvailable` still requires whole-workspace binding.
451
- Source/stream `propose-rename` repairs bound route references. Operations and
454
+ Source/stream `propose-rename` repairs bound route references. `propose-rename` also
455
+ renames a composite stream-id part: it rewrites the part declaration and every
456
+ `part = ...` mapping in command routes, specification routes, examples and redelivery
457
+ locators, keeps part order and stored stream ids, and is refused
458
+ when the new name collides with another part of the same stream. Use it instead of a
459
+ hand-written `propose-ast` batch.
460
+ Requires Screenplay 4.220.0 (`screenplay --version`) for part renames; older servers
461
+ cannot rename a part through `propose-rename`. Operations and
452
462
  exact numeric mode remain unadmitted. Check installed schemas, especially when
453
463
  the CLI bundle predates the standalone tool.
454
464
 
@@ -623,7 +633,12 @@ Upgrade before treating those rows as a coverage gate.
623
633
  `find-modeling-smells` asks information-level questions, never changes compilation
624
634
  or `--warnaserror`: SMELL001 generic event endings, SMELL002 generic command verbs,
625
635
  SMELL003 duplicate nonempty event shapes from different commands, SMELL004 event
626
- fan-out, SMELL005 read-model property fan-in. Optional scope/document and
636
+ fan-out, SMELL005 read-model property fan-in (counts only the events that actually
637
+ feed the property, not every known event through a projection `all` block), SMELL006
638
+ an event property that no mapping, AutoMap, reaction, condition or specification
639
+ reads (worded as a question: dead data or a missing reader?).
640
+ Requires Screenplay 4.221.0 (`screenplay --version`) for SMELL006 and the corrected
641
+ SMELL005 count; older servers over-report SMELL005 and never report SMELL006. Optional scope/document and
627
642
  `eventFanOutThreshold`/`propertyFanInThreshold` (default 5, integers 1–200) bound
628
643
  selection; equal to threshold is not flagged. Similar shape does not establish
629
644
  similar meaning: report a defect only with a domain consequence. No per-declaration
@@ -8,6 +8,7 @@
8
8
  - Address and query
9
9
  - Read evidence, not just a count
10
10
  - Propose a property change
11
+ - Remove from an inline event
11
12
  - Add with explicit sources and fixtures
12
13
 
13
14
  Property-path evidence in `find-references` and `dependencies` is read-only inspection.
@@ -140,8 +141,10 @@ with `expectedRevision`, `expectedCatalogRevision`, `action: "rename"|"remove"`,
140
141
  or `alsoRemove` entries are `{ "target": <handle>, "expectedName": <name> }`.
141
142
  Select only intended command, current-event and non-key read-model properties:
142
143
  chain membership establishes eligibility, not permission to edit every field.
143
- Off-chain selections refuse atomically (`HopNotOnChain`). Historical generations, inline events,
144
+ Off-chain selections refuse atomically (`HopNotOnChain`). Historical generations,
144
145
  keys, opaque or incomplete links and unsupported spans refuse rather than guess.
146
+ Inline events refuse `InlineEventRequiresExtraction` unless the action is `remove`
147
+ with `newGeneration: true` (see [inline events](#remove-from-an-inline-event)).
145
148
 
146
149
  Rename repairs proven references and fixtures. Renaming only a command input
147
150
  keeps the event payload name; broken AutoMap links become explicit mappings.
@@ -175,6 +178,24 @@ have equal revisions. `[]` means no accepted planned event edits, not success;
175
178
  there is no singular `property.generation`. `deployableWithoutTransformation`
176
179
  and `esmVersionKnown` are independent of authoring acceptance.
177
180
 
181
+ ## Remove from an inline event
182
+
183
+ Requires Screenplay 4.232.0 (`screenplay --version`) for inline-event removal;
184
+ older releases refuse inline events.
185
+
186
+ `action: "remove"` with `newGeneration: true` on an inline event extracts it to its
187
+ owning slice in the same proposal (explicit `CanonicalizeTouchedDocuments` consent
188
+ required) and drafts generation N+1 without the member and its mappings. Generation N
189
+ keeps the member; the contract identity and property identities stay. This is how to
190
+ retire a command identifier copied into a stored event payload (`PLAY0469`).
191
+ Without `newGeneration`, an inline event still refuses `InlineEventRequiresExtraction`:
192
+ extract it first with `propose-extract-inline-event`.
193
+
194
+ The report adds `evolutionDraft` (true when any selected event uses `newGeneration`)
195
+ and `extractedInlineEvents` (always an array). An evolution draft is source only: no
196
+ migrator is declared and `deployableWithoutTransformation` stays false. Never present
197
+ it as migration, deployment or replay ready; Chronicle still needs a transformation.
198
+
178
199
  ## Add with explicit sources and fixtures
179
200
 
180
201
  Read the declaration's original `read-ast` handle. Send `action: "add"`, both
@@ -19,8 +19,11 @@ from silently changing the reviewed candidate.
19
19
  new timeline findings; evidence pinning is unsupported for this repair.
20
20
  - `PLAY0469` removes an inline identifier payload copy: it **changes the event
21
21
  contract**, refuses consumer/opaque impact, has no fix-all, and the catalog does
22
- not prove events were persisted, so ask about stored contracts first.
23
- No automatic generation-evolution repair ships.
22
+ not prove events were persisted, so ask about stored contracts first. For a
23
+ contract that may have been stored, use `propose-property` `remove` with
24
+ `newGeneration: true` instead: it drafts a new generation (see
25
+ [property planning](property-links.md#remove-from-an-inline-event)).
26
+ The repair itself never drafts a generation.
24
27
  - `PLAY0479`: migrate optionality spelling with `PreserveTrivia`; document scope
25
28
  migrates all occurrences together. Keep the `query Q => observable?` exception.
26
29
  - `PLAY0470` is repaired only from an author-supplied destination intent, never
@@ -53,8 +53,8 @@ model's behalf.
53
53
 
54
54
  3. **Element sweep** (phase 1, mechanical, before any judgement). One line per gated element, event,
55
55
  name, command, event property and slice; `references/checklist.md` S1-S7 gives each line's
56
- format. Scoped `find-modeling-smells` supplies advisory generic-name, duplicate-shape
57
- and wide-flow questions, never compiler defects or a substitute for the sweep. Each `NONE` and each form name is its own finding naming that element. A repeated
56
+ format. Scoped `find-modeling-smells` supplies advisory generic-name, duplicate-shape,
57
+ wide-flow and unread-event-property questions, never compiler defects or a substitute for the sweep. Each `NONE` and each form name is its own finding naming that element. A repeated
58
58
  payload or generic verb is a signal to investigate: report it only when the name or payload
59
59
  hides the business reason or a consequence is shown (distinct facts that share a shape and
60
60
  earlier generations are not findings). A description, comment or spec name never excuses a flagged line.
@@ -63,7 +63,10 @@ model's behalf.
63
63
  refused change needs a `then error` spec; each command missing from the table is investigated.
64
64
  5. **Lineage and completeness** (phase 3). Backward: every read-model field to an event field,
65
65
  `$eventSourceId`, literal or documented derivation, to a command input, `$context`, capture field
66
- or literal, to the screen, reaction or integration that supplies it. AutoMap fills same-named
66
+ or literal, to the screen, reaction or integration that supplies it. Trace a field with the
67
+ `screenplay` MCP server's `trace-lineage` tool (paged tree, breaks, branches and opaque hops
68
+ are reported) rather than stitching `dependencies` calls; confirm each hop in the model.
69
+ Requires Screenplay 4.223.0 (`screenplay --version`); on older releases use `dependencies`. AutoMap fills same-named
67
70
  fields silently: count them. Forward: every event to a consumer or a terminal reason; every
68
71
  command input to an event field or a rule. Before calling data missing, search the model.
69
72
  6. **Phased checklist** (phases 4-10): ownership, event quality, events versus views, rules and
@@ -52,8 +52,8 @@ not why: a signal, so confirm the hidden reason before reporting. The fix names
52
52
  change (`BerthReassigned`, `BerthLengthLimitRaised`), one event per reason, each with its own
53
53
  rules and consumers. A shared payload shape alone is not a defect: full generations repeat the
54
54
  prior shape on purpose and different facts may look alike. Screenplay 4.127.0 MCP
55
- `find-modeling-smells` reports advisory questions (SMELL001–SMELL005) for generic
56
- names, duplicate shapes and wide flows. It supplements the sweep, never changes
55
+ `find-modeling-smells` reports advisory questions (SMELL001–SMELL005; SMELL006 needs a newer server, see [MCP tools](../../cratis-screenplay-model-authoring/references/mcp-tools.md)) for generic
56
+ names, duplicate shapes, wide flows and event properties nothing reads. It supplements the sweep, never changes
57
57
  a compiler verdict or proves a domain defect.
58
58
 
59
59
  ## Phase 2. Entity walk (5 checks, T1-T5; feeds F1-F3 and scenario coverage)
@@ -173,14 +173,14 @@ Nebulit (`provenance.md`).
173
173
  | G4 | A command invoked by a reaction is not gated by a caller policy, unless a trusted-path decision is recorded | reactions, `authorize` | D (silent = major) |
174
174
  | G5 | Row scoping (whose data) is part of the view, not a filter the caller supplies | queries | D |
175
175
  | G6 | Every persona Cannot line resolves to an executable gate (`authorize` policy, or ownership `claim "x" matches subject\|<command property>`, or a Uuid `require <command property> == <protected read path>`) and a `then denied` spec whose caller is synthesized with `given caller as <Persona>` or explicitly carries the effective-gate roles/claims; otherwise recorded as a gap. Persona text is intent only | personas, policies, specs | D |
176
- | G7 | Every command and query under an inherited module/feature `authorize` has its own `then denied` spec; authorization shared by a feature is declared at feature/module level so new paths inherit it | policies, specs | D |
176
+ | G7 | Every command and query under an inherited module/feature `authorize` has its own `then denied` spec; authorization shared by a feature is declared at feature/module level so new paths inherit it. `require anonymous` is flagged on anything the business did not name public; it must be the whole authorization, preferably in a separate public module, and is not the same as omitting `authorize` | policies, specs | D (major when it exposes another person's data) |
177
177
  | G8 | Ownership/claim targets are a supported scalar (text, Uuid, Date or DateTime render; a numeric or Boolean target is always denied; other shapes and a command without exactly one identifier are STAGE-ESM-015): noted | policies | C (renderable mode) |
178
178
 
179
179
  ## Phase 10. Views, queries and screens (4 checks, H1-H4)
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 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) |
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` and a list-query `by` block remain PLAY0268; a `performer` query 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)). 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
 
@@ -32,7 +32,8 @@ the Screenplay MCP views.
32
32
  for obligations with no matching specification. These read authored examples, not executed
33
33
  coverage (`../../cratis-screenplay-model-authoring/references/mcp-tools.md`).
34
34
  5. Gaps and orphans: `find-references` and `dependencies` for declarations referenced by nothing;
35
- `find-modeling-smells` for the candidate shapes.
35
+ `find-modeling-smells` for the candidate shapes; SMELL006 names event properties no
36
+ mapping, reaction, condition or specification reads, a question to answer, not a defect.
36
37
 
37
38
  ## Report
38
39
  Asked conversationally, give the summary and the most important gap and offer the full lists on request.
@@ -9,7 +9,7 @@ reference execution.
9
9
  |---|---|
10
10
  | The MCP tool catalog (`describe-application`, `search-declarations`, `dependency-graph`, `find-assertion-gaps`, `read-workspace`, `declaration-details`) | `Screenplay`: `Source/DotNET/Screenplay.Mcp/McpToolCatalog.cs`, `Documentation/screenplay/mcp/reference.md` |
11
11
  | Diagnostics PLAY0029, PLAY0191, PLAY0268, PLAY0271, PLAY0350, PLAY0381, PLAY0469; one data subject per event | `Screenplay`: `Source/DotNET/Screenplay/Diagnostics/DiagnosticCodes.cs`, the decision record on data subjects |
12
- | `find-specification-obligations` (SPEC001 to SPEC008, authored presence) and `find-modeling-smells` (SMELL001 to SMELL005, advisory questions); neither proves executed behavior or complete lineage | `Screenplay`: `Documentation/screenplay/mcp/reference.md` |
12
+ | `find-specification-obligations` (SPEC001 to SPEC008, authored presence) and `find-modeling-smells` (SMELL001 to SMELL006, advisory questions); neither proves executed behavior or complete lineage | `Screenplay`: `Documentation/screenplay/mcp/reference.md` |
13
13
  | `semantic-diff` source objects and revision-pinned pages | `Screenplay`: `Source/DotNET/Screenplay.Mcp/` (`McpRevisionDiff`, `McpWorkspaces.Comparison`), `Documentation/screenplay/mcp/reference.md` |
14
14
  | Model notes: anchors, kinds, the committed sidecar, the open-question gate | `Screenplay`: `Documentation/screenplay/model-notes.md`; notes tools in model-authoring `references/model-notes.md` |
15
15
  | Property links and their roles for lineage and journey tracing | `Screenplay`: `Documentation/screenplay/mcp/reference.md`; model-authoring `references/property-links.md` |
@@ -77,10 +77,15 @@ query ListInvoices => InvoiceListReadModel[]
77
77
  authorize IsAuthenticated
78
78
  ```
79
79
 
80
+ A deliberately public query (no identity needed) uses a policy with `require anonymous`
81
+ as its whole authorization, ideally in a separate public module; leaving `authorize` off
82
+ is not the same thing. Rules and diagnostics:
83
+ [anonymous policy](../cratis-screenplay-command-surface/references/policy-persona-seed.md#anonymous-policy).
84
+
80
85
  **Name the compiler and renderer.** Optional keyed queries and collection queries
81
86
  bind, including `observable`. Caller-supplied equality
82
87
  filters on collections bind as ESM v14; `from`, single-result filters, `scoped to`,
83
- `performer` and a `by` block on a list query (or on a non-optional single result) remain PLAY0268, each with its reason. Read
88
+ and a `by` block on a list query (or on a non-optional single result) remain PLAY0268, each with its reason. A `performer` query is not refused: it is an opaque read (PLAY0270 information) left out of the executable model ([version gate](../cratis-screenplay-toolchain/references/executable-subset.md#code-attachments-what-binds-what-never-does)). Read
84
89
  [equality filters](references/equality-filters.md) for the admitted shape, a complete
85
90
  compiled specification model and the Stage/CLI ceilings. Keep a list the domain needs.
86
91
 
@@ -161,7 +166,7 @@ precondition. It takes a `file` reference or an inline block in a tagged fence
161
166
  (` ```csharp `, ` ```sql `), and is the query's counterpart to a command's
162
167
  `handler`. The parser accepts any registered inline language and does not reject
163
168
  a nonsensical one, so the choice is yours to get right. Performer code is opaque:
164
- Screenplay never runs it.
169
+ Screenplay never runs it. It is reported as information `PLAY0270` and left out of the executable model; a specification that reads it is left out while every other specification still runs. Older compilers refuse it with PLAY0268: see the [version gate](../cratis-screenplay-toolchain/references/executable-subset.md#code-attachments-what-binds-what-never-does).
165
170
 
166
171
  A read model a performer composes needs no projection, and no event builds it.
167
172
  Specify it from state with `given readmodel`, then `when query <Query>` with the
@@ -178,7 +183,7 @@ Caller-supplied equality filters on collections select ESM v14 (Requires Screenp
178
183
  primitive/concept/enum properties, same nominal type ignoring optionality, no
179
184
  `from`, distinct names not repeating `by`. `by` and supplied filters AND together;
180
185
  optional filters may be omitted, but supplied null is refused. PLAY0268 still
181
- rejects context sources, single-result filters, opaque scope/performer and
186
+ rejects context sources, single-result filters, opaque scope and
182
187
  a `by` block on a list query (or on a non-optional single result).
183
188
  Authorization runs before lookup, ANDed with module/feature gates; policies see
184
189
  only `by`, never filters. Pin denial with `given caller` and `then denied`.
@@ -305,7 +310,7 @@ binding failures are errors.
305
310
  - [ ] `observable` is present exactly where the caller should see changes without
306
311
  asking again.
307
312
  - [ ] Every authorized query has a specification with `given caller`, including a
308
- `then denied` case.
313
+ `then denied` case (a query authorized only by an anonymous policy may omit `given caller`).
309
314
  - [ ] Each read model has exactly one builder and every field traces to an event.
310
315
  - [ ] A reducer-built view's `by` type matches its events' event-source identity (`PLAY0690`).
311
316
  - [ ] No screen reference is left ambiguous or unresolved.
@@ -39,7 +39,7 @@ Each binding refusal reports PLAY0268 with its query/filter and reason:
39
39
  | `filter ... from ...` or context-derived `by` | Typed query context sources are not admitted; a caller argument must not stand in for trusted context |
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
- | `performer` | Query implementation code is opaque, not a portable declarative lookup |
42
+ | `performer` | Query implementation code is opaque. Requires Screenplay 4.220.1 (`screenplay --version`) for it to be an opaque read (PLAY0270 information) left out of the executable model; older compilers refuse it with PLAY0268 and leave the model unbound |
43
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
 
@@ -25,7 +25,7 @@ selection is:
25
25
  (case-sensitive). It first excludes collection-query `by` properties: if exactly
26
26
  one candidate remains, that is the identifier; otherwise it uses all `*Id`
27
27
  candidates and requires exactly one. An admitted list query here is a collection
28
- query without context-derived `by`, filters, scope or performer.
28
+ query without context-derived `by`, filters or scope.
29
29
 
30
30
  A projection-only/queryless read model needs an explicit `key`: a lone `*Id`
31
31
  property alone does not infer identity. Never use the command's `identifier`
@@ -35,7 +35,7 @@ ESM). Only the probe answers renderability. `PLAY0270` entries are information,
35
35
  | Class | Meaning | Typical examples (each verified in `admission.md`) | Action |
36
36
  | --- | --- | --- | --- |
37
37
  | **Model fix (in mode)** | the model is in, or the user chose, renderable mode and breaks its own subset in a way that has a renderable equivalent with the same meaning | a `produces` whose `for` is not the command identifier; two projections for one read model (`-007`); a policy Stage cannot express portably (`-015`; role-only and opaque pure policies render) | edit request to the modeler session with address, change and rationale |
38
- | **Capability gap** | the intended meaning needs a construct Stage does not render yet | DateTime equality filters and required parameters after optional filters (`-010`); context/single-result filters, opaque `scoped to`/`performer` and a list-query `by` block remain PLAY0268; a read model with several key parts or a projection keyed by parts (v27) refuses `STAGE-ESM-048` and a single-instance query by parts `STAGE-ESM-047` (Chronicle#4265); Translate, clocks, captures, non-event triggers and opaque reaction bodies (`-024`); claim-reading/opaque `runs as` gates (`-034`), legacy `from` (`-035`), mixed effects in one handler (`-037`, retries can duplicate events; keep it whole), unsupported reaction mappings (`-039`); unsupported generated types/result combinations (`-028`/`-038`); `then no readmodel` (`-027`); evolved events (`STAGE-ESM-026`); unsupported expression/enum production conditions (`-006`; supported conditional productions render); legacy reads (`PLAY0271`), protected reads the renderer cannot preserve, or any protected read in an older CLI bundle (STAGE-ESM-044 despite v25 admission; semantic Host/executor support is separate); code validation (`-005`); protected identities/enums (`-040`) or unadmitted explicit subject lineage (`PLAY0268`); described handlers (v23, STAGE-IMPL-002 even Stub mode), atomic mode (STAGE-ESM-043; v22 admission Requires Stage 4.139.0, older Stage reports -016) | keep the model; fallback record entry; options a to c in `SKILL.md`; link the Stage issue |
38
+ | **Capability gap** | the intended meaning needs a construct Stage does not render yet | DateTime equality filters and required parameters after optional filters (`-010`); context/single-result filters, opaque `scoped to` and a list-query `by` block remain PLAY0268; a query `performer` (opaque read, PLAY0270) is left out of the model so render emits nothing for it: write the code the model needs by hand as a gap-fill item; a read model with several key parts or a projection keyed by parts (v27) refuses `STAGE-ESM-048` and a single-instance query by parts `STAGE-ESM-047` (Chronicle#4265); Translate, clocks, captures, non-event triggers and opaque reaction bodies (`-024`); claim-reading/opaque `runs as` gates (`-034`), legacy `from` (`-035`), mixed effects in one handler (`-037`, retries can duplicate events; keep it whole), unsupported reaction mappings (`-039`); unsupported generated types/result combinations (`-028`/`-038`); `then no readmodel` (`-027`); evolved events (`STAGE-ESM-026`); unsupported expression/enum production conditions (`-006`; supported conditional productions render); legacy reads (`PLAY0271`), protected reads the renderer cannot preserve, or any protected read in an older CLI bundle (STAGE-ESM-044 despite v25 admission; semantic Host/executor support is separate); code validation (`-005`); protected identities/enums (`-040`) or unadmitted explicit subject lineage (`PLAY0268`); described handlers (v23, STAGE-IMPL-002 even Stub mode), atomic mode (STAGE-ESM-043; v22 admission Requires Stage 4.139.0, older Stage reports -016) | keep the model; fallback record entry; options a to c in `SKILL.md`; link the Stage issue |
39
39
  | **Implementation attachment** | a permanent limitation, not future ESM admission | file/inline command handlers (PLAY0800; typed `subject` names the command) | keep the model contract and gap-fill the slice in code with a constrained implementation attachment; do not wait for a new ESM version |
40
40
  | **Tool skew** | the bundled compiler disagrees with documented semantics | the false `PLAY0285` on reaction cascades from an older bundle; codes the standalone compiler does not raise | record in the session state and the fallback record; never "fix" a correct model |
41
41
  | **Environment** | not the model | restore failures, missing SDK, a destination that is not writable | fix the environment or report blocked |
@@ -131,7 +131,11 @@ proved and keep other guarantees as target requirements; recovery cases are in
131
131
  - One behaviour per spec; names read as sentences: `Reserving...`, `Rejecting...`, `Refusing...`
132
132
  (denial), `<View>LifecycleN<State>` for families.
133
133
  - `for` on every given, appended and expected event (plain `produces <Name>` too; inline `produces event` omits it), and on the `when` command where the
134
- destination matters. A competing-claim given needs a *different* `for`.
134
+ destination matters. A competing-claim given needs a *different* `for`. A given without `for`
135
+ belongs to the event source the specification acts on; state `for` when the command appends to
136
+ several event sources or an assertion depends on the given's source, and never assert
137
+ `$eventSourceId` of a sourceless given. Read
138
+ [examples and routes](../cratis-screenplay-specifications/references/examples-and-routes.md#givens-without-an-event-source).
135
139
  Foreign event fixtures feeding a capture may omit `for`; supplied `for` is
136
140
  opaque source text, not the capture's content key.
137
141
  - Format rules belong on a `concept`: give each concept rule representative acceptance,
@@ -147,7 +151,9 @@ proved and keep other guarantees as target requirements; recovery cases are in
147
151
  - Descriptions are not rendered: a rule only in prose is unenforced; make it a rule layer, a
148
152
  spec or a recorded target requirement.
149
153
  - Prove projections with events (`given`/`when append`), not `given readmodel`; seed read models
150
- only for performer-backed views or commands that decide on view state.
154
+ only for performer-backed views or commands that decide on view state. A query `performer` is an opaque read
155
+ (information `PLAY0270`, not `PLAY0268`): it is left out of the executable model, a spec that reads it is
156
+ left out too and the other specs still run, so mark it `gap` for the executable modes ([version gate](../cratis-screenplay-toolchain/references/executable-subset.md#code-attachments-what-binds-what-never-does)).
151
157
  - No contradiction between a family and single-transition specs of the same view.
152
158
 
153
159
  ### Quality checklist (adapted from the TrogonStack scenario checklist; `references/provenance.md`)
@@ -219,6 +219,6 @@ empty-list intent is a separate claim from a keyed row being absent (`view-and-s
219
219
  queries are executable too (`ListOpenInvoices` in the backing example); caller-supplied equality filters on collections bind as ESM v14.
220
220
  Pass `by` and filters in query arguments; PLAY0468 reports unknown, repeated or
221
221
  missing required arguments. Optional filters may be omitted, supplied null is refused.
222
- Context-sourced/single-result filters, opaque `scoped to`/`performer`, and a list-query
223
- `by` block remain PLAY0268. Compiled coverage and renderer ceilings:
222
+ Context-sourced/single-result filters, opaque `scoped to`, and a list-query
223
+ `by` block remain PLAY0268; a `performer` query is an opaque read left out of the model (PLAY0270; [version gate](../../cratis-screenplay-toolchain/references/executable-subset.md#code-attachments-what-binds-what-never-does)). Compiled coverage and renderer ceilings:
224
224
  read-surface [equality filters](../../cratis-screenplay-read-surface/references/equality-filters.md).
@@ -24,7 +24,7 @@ Typed example/override forms: `cratis-screenplay-specifications`
24
24
  | `then readmodel` / `then query` (keyed `ById`, `arguments`, `result`) | yes | yes | yes |
25
25
  | `then query` on an unfiltered list or a list narrowed by one `by` key (observable too) | yes | yes: no `arguments` for an unkeyed list, one `result` per row stating the read-model identifier, no `result` = empty list | snapshot and observable lists render |
26
26
  | Collection query with caller-supplied equality `filter`, including observable | yes | yes, ESM v14: same-named scalar property/type, AND with `by`; optional omission allowed, supplied null refused; PLAY0468 checks arguments; row order does not matter | yes on supported snapshot/observable collections; DateTime/filter parameter order refuse -010; independent Stage executor still refuses filtered assertions (-010) |
27
- | Context `from`, single-result filters, `scoped to`, `performer` or a list-query `by` block | yes | PLAY0268: query context, collection-only filtering, opaque scope/implementation or a multipart list lookup are unadmitted | no |
27
+ | Context `from`, single-result filters, `scoped to` or a list-query `by` block | yes | PLAY0268: query context, collection-only filtering, opaque scope or a multipart list lookup are unadmitted | no |
28
28
  | `then no readmodel <RM> for "<key>"` | yes | yes | no |
29
29
  | `when query` -> `then result` / `then no result` | yes | yes | same as `then query`: only the query-only cases below |
30
30
  | `given clock` / `when clock`, `when trigger`, record-source `given`/`when capture` | yes | yes (standalone and any cratis whose compiler admits v6; an older bundle does not, see toolchain `references/executable-subset.md`) | no |
@@ -45,7 +45,8 @@ Typed example/override forms: `cratis-screenplay-specifications`
45
45
  | Bodied rules, code policies | spec them | spec reported **unsupported**, never passed | no |
46
46
  | Pending described command handlers (v23) | specify intent | binds; denial/validation execute, body-reaching specs Unsupported ImplementationBody; all-Unsupported is not green | STAGE-IMPL-002 even Stub mode |
47
47
  | Attached command handlers | spec them in design | blocked: PLAY0800, no spec runs (V3 blocked); permanent constrained-attachment requirement, gap-fill in code | no |
48
- | `file` constraints, query `performer`s | spec them in design | blocked: PLAY0268 at binding, no spec runs (V3 blocked) | no |
48
+ | `file` constraints | spec them in design | blocked: PLAY0268 at binding, no spec runs (V3 blocked) | no |
49
+ | Query `performer`s | spec them in design | opaque read: PLAY0270 information, left out of the executable model; a spec that reads it is left out, every other spec still runs ([version gate](../../cratis-screenplay-toolchain/references/executable-subset.md#code-attachments-what-binds-what-never-does); older compilers report PLAY0268) | no |
49
50
  | Atomic reaction mode (v22) | declare for new models | failed batch adds no facts or view changes; earlier batches/commands remain; `then error` alone is insufficient | v22 STAGE-ESM-016; mode in admitted v23–v27 STAGE-ESM-043 |
50
51
  | Protected command reads (v25) | declare opt-in for eligible reads | absence Validation; matching intervening facts Conflict; race vectors are not a new spec construct | Cratis C# rendering in a new enough bundle (STAGE-ESM-044 before, or for unpreservable shapes); semantic Host/executor execute admitted reads, non-Error protected requirements STAGE-ESM-045; v25 pair admitted |
51
52
 
@@ -58,7 +59,7 @@ Requires Stage 4.90.0 for snapshot/live lists, 4.101.0 for no-event specificatio
58
59
 
59
60
  ## Design mode
60
61
  Write the full intended behaviour, including scenarios the executable subset cannot run
61
- (filtered, scoped and performer-backed views; clock, trigger and capture scenarios when only a
62
+ (filtered, scoped and performer-backed views, the last left out of the executable model rather than refused; clock, trigger and capture scenarios when only a
62
63
  older cratis bundle is available). Mark each such spec in the coverage matrix as
63
64
  `gap: <reason>` for the narrower modes so the verification and render phases know what will not execute.
64
65
 
@@ -61,7 +61,7 @@ own full givens. The excerpt is copied from `invoicing-dues-example.md`; the las
61
61
  both that the stored row is gone and that the keyed query returns nothing. The whole-list query
62
62
  (no key) is executable too (Requires Screenplay 4.105.0 or later): `invoicing-dues-example.md` adds
63
63
  `ListOpenInvoices => OpenInvoice[]` with one spec that expects one `result` row and one that
64
- expects the empty list after `PaymentReceived`. Only `filter`, `scoped to` and `performer` queries stay design-mode.
64
+ expects the empty list after `PaymentReceived`. Only `filter`, `scoped to` and `performer` queries stay design-mode (a performer query is left out of the executable model, not refused).
65
65
  The source document also asserts the other terminal outcomes (`InvoiceVoided`, `InvoiceSettled`) the same way; they are not copied here.
66
66
  ```screenplay excerpt parent=references/invoicing-dues-example.md#1
67
67
  specification OpenInvoicesLifecycle1Empty
@@ -120,7 +120,7 @@ Ask the batch below only for what the request leaves open: (1) origin of each ac
120
120
 
121
121
  - At most one `identifier` per command; never on an event property or read-model property (use `key`). At most one builder per read model (`PLAY0191`). Read `references/read-model-design.md` ("Identifier and key contract") for the exact rules.
122
122
 
123
- - A query's `by` goes on its own body line; `from`, single-result filters, scope, performer and a list-query `by` block remain `PLAY0268`; equality filters on collections bind as ESM v14. Read `references/read-model-design.md` ("Query binding") for the binding rules.
123
+ - A query's `by` goes on its own body line; `from`, single-result filters, scope and a list-query `by` block remain `PLAY0268` (a `performer` query is an opaque read left out of the executable model, [version gate](../cratis-screenplay-toolchain/references/executable-subset.md#code-attachments-what-binds-what-never-does)); equality filters on collections bind as ESM v14. Read `references/read-model-design.md` ("Query binding") for the binding rules.
124
124
 
125
125
  - A `unique` constraint names a property the event declares directly; the constraint name is
126
126
  its identity (renaming starts an empty index).
@@ -330,8 +330,9 @@ module Berths
330
330
  - A query's `by` goes on its own body line. Optional keyed and collection queries
331
331
  bind, including observable delivery. Caller-supplied equality filters on collections
332
332
  bind as ESM v14; `by` ANDs with supplied filters. `from`, single-result
333
- filters, scope, performer and a `by` block on a list query remain PLAY0268 for their
334
- respective context/cardinality/opaque/multipart gaps. A composite-keyed optional
333
+ filters, scope and a `by` block on a list query remain PLAY0268 for their
334
+ respective context/cardinality/opaque/multipart gaps. A `performer` query is an opaque read left
335
+ out of the executable model, not PLAY0268 ([version gate](../../cratis-screenplay-toolchain/references/executable-subset.md#code-attachments-what-binds-what-never-does)). A composite-keyed optional
335
336
  single-instance query takes a `by` block naming every part (ESM v27). Read read-surface
336
337
  [equality filters](../../cratis-screenplay-read-surface/references/equality-filters.md).
337
338
 
@@ -238,7 +238,10 @@ For command specifications:
238
238
  - [ ] `given caller` is present whenever the command is authorized, with a
239
239
  `then denied` case for a caller who must be refused.
240
240
  - [ ] `then` contains **either** events **or** an error, never both.
241
- - [ ] A collision between two event sources uses `for` on the `given` event.
241
+ - [ ] A collision between two event sources uses `for` on the `given` event. A `given` without
242
+ `for` belongs to the event source the specification acts on; state `for` when the command
243
+ appends to several event sources or an assertion depends on it (see
244
+ [examples and routes](references/examples-and-routes.md#givens-without-an-event-source)).
242
245
  - [ ] Error cases test business rules; each concept rule has one rejection
243
246
  specification through one command, not one per use.
244
247
  - [ ] A localized rejection is pinned by its quoted `$strings` key.
@@ -248,7 +251,8 @@ For command specifications:
248
251
  For view specifications:
249
252
 
250
253
  - [ ] A view a `performer` composes is specified with `given readmodel`,
251
- `when query` and `then result` or `then no result`.
254
+ `when query` and `then result` or `then no result`; the reference runner leaves such a
255
+ spec out (`PLAY0270` information), so it is design intent, not executed proof.
252
256
  - [ ] `given readmodel` is a complete instance with its identifier.
253
257
  - [ ] `then readmodel` states the identifier and the properties that matter; add
254
258
  `exactly` only when extra properties must fail the assertion.
@@ -11,6 +11,7 @@
11
11
  - Event routes
12
12
  - Redelivery locators
13
13
  - Operation and recovery intent
14
+ - Givens without an event source
14
15
 
15
16
  ## Typed examples
16
17
 
@@ -223,3 +224,21 @@ future external-work behavior. Use `then no events` to assert explicitly that th
223
224
  action and cascade produced no new facts; after append it excludes the input fact.
224
225
  It may accompany view/query/response assertions, not events, event-order assertions,
225
226
  errors or denial (PLAY0545). An omitted event list is not this explicit assertion.
227
+
228
+ ## Givens without an event source
229
+
230
+ A `given` event with no `for` belongs to the event source the specification acts on: the
231
+ event source each fact the command appends goes to, or the `for` of `when append`.
232
+
233
+ - A unique-event constraint counts a sourceless given as already on that event source. A
234
+ unique-value constraint treats its value as the action's own claim.
235
+ - When a projection needs the given's event-source identity, the reference evaluator reports
236
+ `Unsupported` (Projection) and does not invent one. This holds whatever the action,
237
+ because givens are projected before it runs.
238
+ - Runners that append to real event streams, such as Stage, append sourceless givens to the
239
+ action's event source.
240
+ - State `for` when the command appends to more than one event source, or when an assertion
241
+ depends on the given's event source. Never assert `$eventSourceId` of a sourceless given.
242
+
243
+ Requires Screenplay 4.229.0 (`screenplay --version`) for the documented, vector-pinned
244
+ placement; older versions leave a sourceless given's placement unspecified.
@@ -54,6 +54,10 @@ The complete model with these specifications is in read-surface `references/name
54
54
 
55
55
  ## Parse and binding diagnostics
56
56
 
57
+ A command or query authorized only by an anonymous policy may omit `given caller`;
58
+ every other authorized specification needs one (PLAY0389). See
59
+ [anonymous policy](../../cratis-screenplay-command-surface/references/policy-persona-seed.md#anonymous-policy).
60
+
57
61
  PLAY0358 is a syntax error; PLAY0388 also occurs at parse time for extra text
58
62
  after `then denied`. PLAY0350, PLAY0352, PLAY0388 for mixed outcomes, PLAY0389 and
59
63
  the one-rejection rule PLAY0273 occur only at binding. Source validation alone
@@ -100,7 +100,9 @@ Unattended work takes the conservative option and marks it `ASSUMED` in model
100
100
  ## Rules
101
101
  **Compiler contracts** (diagnostics; capability per tool in the toolchain `references/executable-subset.md`)
102
102
  - `identifier` on an event property is PLAY0019; the source id is never payload by declaration.
103
- Copying it as a payload value is PLAY0469 (information, warning for inline events).
103
+ Copying it as a payload value is PLAY0469 (information, warning for inline events);
104
+ for a possibly stored contract, retire it as an evolution draft with `propose-property`
105
+ `remove` + `newGeneration: true`, not by editing the event in place (model-authoring [property planning](../cratis-screenplay-model-authoring/references/property-links.md#remove-from-an-inline-event)).
104
106
  - In the executable model a production's `for` must resolve to the command's scalar identifier:
105
107
  one command writes one stream declaratively; described handlers bind v23 but
106
108
  their payload-only contract does not grant arbitrary destinations.
@@ -13,4 +13,8 @@ Rules for stream-id literals, composite ids and the reserved `All` stream name.
13
13
  PLAY0273 as a backstop. Streams `all`, `ALL` and `Default`
14
14
  remain valid. Rename via `propose-rename`; a pin retaining `All` cannot fix it.
15
15
  Existing `All` history reads as source-only appends, not the renamed stream.
16
+ Rename a composite part with `propose-rename` too: it rewrites the part and every
17
+ `part = ...` mapping together and refuses a name that collides with another part;
18
+ never hand-write a `propose-ast` batch for it (needs a server that supports part
19
+ renames, see model-authoring `references/mcp-tools.md`).
16
20
  Source evidence and migration limits are in that reference.
@@ -103,7 +103,7 @@ not the source identity.
103
103
  - **Executable** (binds, V3): `references/executable-subset.md`. Optional keyed lookups, unfiltered
104
104
  lists and lists narrowed by one `by` key (observable too) bind; caller-supplied equality
105
105
  filters on collections bind as ESM v14. Context `from`, single-result
106
- filters, opaque `scoped to`/`performer` and a `by` block on a list query remain PLAY0268. Read
106
+ filters, opaque `scoped to` and a `by` block on a list query remain PLAY0268; a `performer` query is an opaque read left out of the executable model (PLAY0270; [version gate](references/executable-subset.md#code-attachments-what-binds-what-never-does)). Read
107
107
  read-surface [equality filters](../cratis-screenplay-read-surface/references/equality-filters.md).
108
108
  Pending handlers beside unconditional productions bind as described commands (v23),
109
109
  but reached bodies are Unsupported; attached file/inline handlers refuse PLAY0800
@@ -8,6 +8,7 @@
8
8
  - Explicit enum member numbers
9
9
  - Reserved stored names and event pins
10
10
  - Named keys, production routes and observer filters
11
+ - Ambiguous match patterns (PLAY0803)
11
12
  - Projection event scope (PLAY0801)
12
13
  - Reducer instance identity (PLAY0690)
13
14
  - Caller identity, compliance and routes
@@ -149,6 +150,14 @@ Overrides/filters select released ESM v10; malformed routes also use PLAY0504.
149
150
  Read read-surface `references/named-keys.md` and
150
151
  [production routes and filters](production-routes-and-filters.md).
151
152
 
153
+ ## Ambiguous match patterns (PLAY0803)
154
+
155
+ Requires Screenplay 4.218.2 (`screenplay --version`); older compilers do not report it.
156
+
157
+ | Code | Severity | Meaning / fix |
158
+ | --- | --- | --- |
159
+ | PLAY0803 | W | `AmbiguousMatchPattern`: a `matches` pattern in the portable dialect, such as `(a+)+$`, `(a\|a)*` or `(a*)*`, can backtrack exponentially in a browser engine. Reported by both compilers and editors with the ambiguous subexpression; very large patterns are not analyzed. Rewrite it unambiguously (`a+`, `[ab]*`); see command-surface `text-and-match-rules.md`. |
160
+
152
161
  ## Projection event scope (PLAY0801)
153
162
 
154
163
  Requires Screenplay 4.212.3 (`screenplay --version`) for this ordinary compilation
@@ -91,7 +91,7 @@ Requires Screenplay 4.141.0 or later (`screenplay --version`) to bind concept co
91
91
  equivalent inferred ESM bytes. Flat composite read-model keys bind as v27
92
92
  (see below). Collections and observable delivery bind.
93
93
  Caller-supplied equality filters on collections also bind as ESM v14; context
94
- sources, single-result filters, scope, performer and a list-query `by` block remain blocked.
94
+ sources, single-result filters, scope and a list-query `by` block remain blocked; a `performer` query is an opaque read left out of the executable model.
95
95
  - One projection per read model: `from`, `every`, `all` (one block per level), `join`,
96
96
  `children`, `nested`, `remove with`, `remove via join` (binds; blocks the execution plan at the projection level, see below), `clear with`, counters, `add`,
97
97
  `subtract`, `set`, `clear`, variants, and the identifier mapped from the projection's key (`xId = $eventSourceId` only for an event-source key).
@@ -316,11 +316,13 @@ v22–v28 and [described handlers](../../cratis-screenplay-command-surface/refer
316
316
  for the result contract. Attached handlers remain unbound.
317
317
 
318
318
  Inline fences (`csharp`, `typescript`, `react`, `html`, `sql`) and `file <path>` attach
319
- code to an owner. Three kinds block binding (V3 blocked, no specification runs):
320
- the attached command `handler` (PLAY0800), the `file` constraint (PLAY0268, see below)
321
- and a query `performer` (PLAY0268)
322
- ("uses delivery, filtering, scope, or implementation behavior outside the first ESM v1
323
- vertical"). Everything else binds as an **opaque requirement** that needs a target to
319
+ code to an owner. Two kinds block binding (V3 blocked, no specification runs):
320
+ the attached command `handler` (PLAY0800) and the `file` constraint (PLAY0268, see below).
321
+ A query `performer` does not block: it is an opaque read, reported as information
322
+ `PLAY0270` and left out of the executable model; a specification that reads it is left
323
+ out, and every other specification still runs with `screenplay test`.
324
+ Requires Screenplay 4.220.1 (`screenplay --version`); older versions refuse a performer
325
+ query with PLAY0268 and leave the whole model unbound. Everything else binds as an **opaque requirement** that needs a target to
324
326
  execute: reducer transitions, rule predicates, command and concept code validation, policy
325
327
  predicates and reaction effects. Reaction effects bind only when the trigger has no
326
328
  `reads`; a trigger with `reads` plus a `file` or inline effect fails binding. Reaction
@@ -350,7 +352,7 @@ bodies still leave their owner non-executable.
350
352
  code validation is refused (STAGE-ESM-005). Opaque pure policies render.
351
353
  - The reference runner returns Unsupported for the opaque bodies that do bind (rule and
352
354
  policy predicates, code validation, reducer transitions); a specification that needs one
353
- never passes. Attached handlers, file constraints and query performers (and reaction effects on a trigger with
355
+ never passes. Attached handlers and file constraints (and reaction effects on a trigger with
354
356
  `reads`) are different: they leave the whole model unbound, so no specification runs at
355
357
  all.
356
358
 
@@ -362,7 +364,7 @@ bodies still leave their owner non-executable.
362
364
  | Unquoted `import Other.Contract` | PLAY0268 | external contract import is not bound |
363
365
  | `pii` or `secret` on a concept | PLAY0268 | Older compilers refuse it outright. Current compilers admit v13 except enum/identity compliance and events mixing personal or explicitly subject-scoped secret values with explicit subject marks; see `compliance.md` in command-surface references |
364
366
  | `query` with a `by` block over a list, or `by ... from` context-derived arguments | PLAY0268 | a `by` block binds only on an optional single-instance query (v27). An optional scalar snapshot lookup, an unfiltered list (`RM[]`) and a list narrowed by one caller-supplied `by` key bind, in their `observable` form too |
365
- | Context `from`, single-result filters, `scoped to`, `performer` queries | PLAY0268 | Typed query context, filtering of single results, opaque scope and query implementation remain unadmitted; each refusal names its reason. Caller-supplied collection equality filters bind as v14. `observable` goes in the return position (`=> observable RM[]`); as a body line it is PLAY0048 |
367
+ | Context `from`, single-result filters, `scoped to` | PLAY0268 | Typed query context, filtering of single results and opaque scope remain unadmitted; a `performer` query is not refused (PLAY0270 information, left out of the executable model); each refusal names its reason. Caller-supplied collection equality filters bind as v14. `observable` goes in the return position (`=> observable RM[]`); as a body line it is PLAY0048 |
366
368
  | `contains` or `starts with` in conditions only | PLAY0268 | conditions admit scalar equality (Uuid from v28) and numeric ordering, plus same-primitive command date comparisons from v26; property/concept text rules bind as v24 |
367
369
  | Date comparisons with mixed primitives, `$context` (including occurred), `today`, protected read paths, optional condition operands, concept rules or reaction `where` | PLAY0268 | v26 admits only command conditions and command/property literal validation rules |
368
370
  | Rule on a nested path (`lines.qty all > 0`) | PLAY0268 | put the rule on the nested value's concept |
@@ -53,7 +53,7 @@ This table is a reading of the renderer's admission, not a render result: run th
53
53
  | Area | Renders | Refused (code) |
54
54
  | --- | --- | --- |
55
55
  | Slice kinds | `StateChange`, `StateView`, supported event-triggered `Automation` with Chronicle reactors | Translate, captures, non-event triggers, opaque bodies, clock/trigger/capture specs (`-024`); claim-reading/opaque `runs as` gates (`-034`), mixed effects from one handler (`-037`, redelivery can duplicate events), unsupported conditions/destinations/mappings (`-039`). Keep refused reactions whole |
56
- | Queries | optional keyed snapshot lookups; snapshot or observable collections, keyed or unkeyed, with v14 equality filters | context/single-result filters, opaque `scoped to`/`performer` and a list-query `by` block: PLAY0268; v27 composite-key lookups by parts: STAGE-ESM-047, read models and projections keyed by parts: STAGE-ESM-048. DateTime filters and required parameters after optional filters refuse `-010`; filter-name collisions refuse `-012`; concept arguments retain Arc validation, including nested members/elements; nullable keys or optional concept filters with `not empty` refuse `-010` rather than changing null behavior |
56
+ | Queries | optional keyed snapshot lookups; snapshot or observable collections, keyed or unkeyed, with v14 equality filters | context/single-result filters, opaque `scoped to` and a list-query `by` block: PLAY0268; a `performer` query is an opaque read (PLAY0270) left out of the model ([version gate](executable-subset.md#code-attachments-what-binds-what-never-does)); v27 composite-key lookups by parts: STAGE-ESM-047, read models and projections keyed by parts: STAGE-ESM-048. DateTime filters and required parameters after optional filters refuse `-010`; filter-name collisions refuse `-012`; concept arguments retain Arc validation, including nested members/elements; nullable keys or optional concept filters with `not empty` refuse `-010` rather than changing null behavior |
57
57
  | Authorization | role-only, authenticated, opaque pure policies, claim conditions with Uuid, Date, DateTime or text targets (numeric and Boolean claim matches render as always false), `not`/and/or; roles read through the identity's `RoleClaimType` | role-claim URIs, nested opaque policies, unresolved or non-portable policies, no single identifier, opaque-policy subjects that are not text, Uuid, Date or DateTime (`STAGE-ESM-015`, a restriction separate from declarative claim targets) |
58
58
  | Event sources, streams, routes (ESM v8) | rendered, including routed read-model/query companion replay | reserved stored names, unformattable routed fixtures (`STAGE-ESM-030`) |
59
59
  | Numbers, case tables | whole numbers as `long` from ESM v8; case tables | out-of-`int` literals below v8 (`STAGE-ESM-031`) |
@@ -99,7 +99,7 @@ ids into routing to fit a renderer (PLAY0515).
99
99
  observable collections, including supported equality filters;
100
100
  Requires Stage 4.90.0 for snapshot lists and live `IReadModels.Observe` streams;
101
101
  older renderers refuse snapshot lists with STAGE-ESM-010.
102
- context/single-result filters, opaque `scoped to` and `performer` block binding. Keep a list the domain needs and report
102
+ context/single-result filters, and opaque `scoped to` block binding; a `performer` query is left out of the executable model ([version gate](executable-subset.md#code-attachments-what-binds-what-never-does)). Keep a list the domain needs and report
103
103
  the capability gap; marking it `observable` or keying it is a modeling decision for the user.
104
104
  - Attached file/inline handlers refuse PLAY0800 and require constrained implementation
105
105
  attachments: gap-fill in code, not by waiting for ESM admission.
@@ -3,7 +3,7 @@
3
3
  Compiler syntax: `cheat-sheet.md`. Negative capability claims depend on the tool you ran; name it in every verdict.
4
4
 
5
5
  1. Clean V1 is not executable: binding errors appear through MCP (V2), `render` or `cratis screenplay validate --executable` (bundled compiler, writes nothing). Neither `screenplay <folder>` nor plain `cratis screenplay validate` binds.
6
- 2. The Screenplay samples validate clean but are not all executable; copying their idioms (context-filtered queries, enum/identity compliance, `today`, `reads`, `$causedBy`, templates, performers) can block V3. Caller-supplied collection equality filters bind; read read-surface `references/equality-filters.md`.
6
+ 2. The Screenplay samples validate clean but are not all executable; copying their idioms (context-filtered queries, enum/identity compliance, `today`, `reads`, `$causedBy`, templates) can block V3. Caller-supplied collection equality filters bind; read read-surface `references/equality-filters.md`.
7
7
  3. Know the target mode (design/executable/renderable) before writing; state it.
8
8
  4. Plain `produces` without `for` means allocation in the ESM but "the identifier" in rendered code. Always write `for <identifier>` on a plain `produces <Name>`; inline `produces event <Name>` omits `for` and defaults to the identifier (PLAY0478).
9
9
  5. PLAY0029 is a warning: a misspelled keyword (or `type` inside a slice) drops the construct silently. Use `--warnings-as-errors`.
@@ -157,7 +157,7 @@ Requires Stage 4.90.0 for snapshot/live lists, 4.96.0 for non-text secrets and 4
157
157
  | `STAGE-ESM-005` | Code validation or rule predicate bodies; or a command beyond the first capability (optional event property, event revision other than the first, validation or requirement that cannot be rendered, neither `produces` nor a response) | Use declarative validation; non-initial event generations are not rendered |
158
158
  | `STAGE-ESM-006` | `produces` that cannot render without changing its destination or mappings (expression/enum conditions, literal or computed mappings, `for` not a command identifier, mappings not one-to-one with event properties, duplicate tags) | Map properties one to one; supported conditional productions render as guarded events, not separate commands |
159
159
  | `STAGE-ESM-007`, `-008`, `-009` | Projection count per read model (exactly one projection or reducer each); unresolvable properties or no single read-model transition (**flat** projections only); affected instance not one, not keyed by an event property, or not the event-source identity (flat projections only) | One projection per read model; see "Projections" below |
160
- | `STAGE-ESM-010` | A query is neither an optional snapshot lookup by the read-model identifier nor a supported snapshot/observable collection query; each query is checked on its own. Both collection modes render. Concept-typed keys and filters retain Arc validation, including composite members and collection elements; nullable concept keys or optional concept filters with `not empty` cannot preserve null semantics | Keyed `XById => X optional` queries or snapshot/observable lists. Equality filters render on both collections; DateTime filters, required filters after optional ones and unsupported null-validation shapes refuse 010. Filter-name collisions refuse 012. Context/single-result filters, opaque scope/performer and a list-query `by` block remain PLAY0268; a read model with several key parts (v27) refuses `STAGE-ESM-048` |
160
+ | `STAGE-ESM-010` | A query is neither an optional snapshot lookup by the read-model identifier nor a supported snapshot/observable collection query; each query is checked on its own. Both collection modes render. Concept-typed keys and filters retain Arc validation, including composite members and collection elements; nullable concept keys or optional concept filters with `not empty` cannot preserve null semantics | Keyed `XById => X optional` queries or snapshot/observable lists. Equality filters render on both collections; DateTime filters, required filters after optional ones and unsupported null-validation shapes refuse 010. Filter-name collisions refuse 012. Context/single-result filters, opaque scope and a list-query `by` block remain PLAY0268; a performer query is left out of the model (PLAY0270, Requires Screenplay 4.220.1), so render emits nothing for it and it is a gap-fill item; a read model with several key parts (v27) refuses `STAGE-ESM-048` |
161
161
  | `STAGE-ESM-011` | A specification cannot render (see the rules below) | Reshape it only if the assertion keeps its meaning; otherwise keep the specification, record the gap, and gap-fill with the specification as the oracle. Never weaken or delete it to get a render |
162
162
  | `STAGE-ESM-012` | Generated C# names collide (properties, types, namespaces, constraints) | Rename |
163
163
  | `STAGE-ESM-013` | An event-context value other than `$context.occurred` mapped in `produces` | Map a command property when that preserves the meaning; otherwise gap-fill |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cratis/pi",
3
- "version": "7.91.0",
3
+ "version": "7.93.0",
4
4
  "description": "Configuration-aware Cratis AI integration for Pi",
5
5
  "type": "module",
6
6
  "files": [