@cratis/pi 7.62.0 → 7.63.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 (103) hide show
  1. package/package/corpus/product-sync.json +9 -9
  2. package/package/corpus/skills/cratis-application-slice-conformance/SKILL.md +1 -1
  3. package/package/corpus/skills/cratis-arc-command/references/generated-values.md +27 -12
  4. package/package/corpus/skills/cratis-arc-command/references/shop-generation.md +17 -6
  5. package/package/corpus/skills/cratis-fundamentals-concept/SKILL.md +10 -2
  6. package/package/corpus/skills/cratis-fundamentals-concept/references/shop-generation.md +49 -6
  7. package/package/corpus/skills/cratis-screenplay-automations-and-translations/SKILL.md +43 -41
  8. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/cases-to-specify.md +11 -2
  9. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/integration-interview.md +24 -0
  10. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/public-events-and-direction.md +76 -10
  11. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/realization-and-gap-fill.md +5 -0
  12. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/todo-list-example.md +1 -1
  13. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/translate-example.md +39 -23
  14. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/translation-patterns.md +35 -12
  15. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/SKILL.md +51 -81
  16. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/atomic-batches-and-source-mappings.md +83 -0
  17. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/capture-map-and-example.md +14 -4
  18. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/reaction-forms.md +59 -0
  19. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/record-capture-specifications.md +60 -0
  20. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/specifying-triggers-and-clock.md +5 -1
  21. package/package/corpus/skills/cratis-screenplay-command-surface/SKILL.md +26 -28
  22. package/package/corpus/skills/cratis-screenplay-command-surface/references/described-handlers.md +82 -0
  23. package/package/corpus/skills/cratis-screenplay-command-surface/references/generated-values-and-responses.md +82 -28
  24. package/package/corpus/skills/cratis-screenplay-command-surface/references/protected-reads.md +113 -0
  25. package/package/corpus/skills/cratis-screenplay-command-surface/references/shop-generation.md +45 -12
  26. package/package/corpus/skills/cratis-screenplay-command-surface/references/text-and-match-rules.md +119 -0
  27. package/package/corpus/skills/cratis-screenplay-command-surface/references/validate-rules.md +14 -4
  28. package/package/corpus/skills/cratis-screenplay-command-surface/verification.json +10 -3
  29. package/package/corpus/skills/cratis-screenplay-event-modeling/SKILL.md +12 -12
  30. package/package/corpus/skills/cratis-screenplay-event-modeling/references/parsed-not-runnable.md +5 -3
  31. package/package/corpus/skills/cratis-screenplay-event-modeling/verification.json +5 -1
  32. package/package/corpus/skills/cratis-screenplay-legacy-extraction/SKILL.md +2 -2
  33. package/package/corpus/skills/cratis-screenplay-legacy-extraction/references/evidence-table-template.md +1 -1
  34. package/package/corpus/skills/cratis-screenplay-legacy-extraction/references/generated-recovery.md +51 -14
  35. package/package/corpus/skills/cratis-screenplay-legacy-extraction/references/intent-example.md +5 -0
  36. package/package/corpus/skills/cratis-screenplay-legacy-extraction/references/loss-report-template.md +2 -1
  37. package/package/corpus/skills/cratis-screenplay-legacy-extraction/references/rule-modeling.md +6 -3
  38. package/package/corpus/skills/cratis-screenplay-legacy-extraction/references/signal-to-intent.md +1 -1
  39. package/package/corpus/skills/cratis-screenplay-model-authoring/SKILL.md +22 -28
  40. package/package/corpus/skills/cratis-screenplay-model-authoring/references/choosing-generation.md +20 -7
  41. package/package/corpus/skills/cratis-screenplay-model-authoring/references/language-reference.md +12 -6
  42. package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-loop.md +9 -1
  43. package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-tools.md +58 -10
  44. package/package/corpus/skills/cratis-screenplay-model-authoring/verification.json +4 -2
  45. package/package/corpus/skills/cratis-screenplay-model-review/SKILL.md +2 -5
  46. package/package/corpus/skills/cratis-screenplay-model-review/references/anti-patterns.md +2 -2
  47. package/package/corpus/skills/cratis-screenplay-model-review/references/checklist.md +2 -2
  48. package/package/corpus/skills/cratis-screenplay-model-review/references/quick-self-check.md +2 -1
  49. package/package/corpus/skills/cratis-screenplay-model-review/references/review-questions.md +3 -2
  50. package/package/corpus/skills/cratis-screenplay-modeling-lifecycle/references/principles.md +1 -1
  51. package/package/corpus/skills/cratis-screenplay-modeling-lifecycle/references/vocabulary-map.md +1 -1
  52. package/package/corpus/skills/cratis-screenplay-read-surface/SKILL.md +2 -3
  53. package/package/corpus/skills/cratis-screenplay-read-surface/references/named-keys.md +3 -1
  54. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/SKILL.md +8 -3
  55. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/gap-fill-handoff.md +8 -0
  56. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/renderability-gate.md +6 -4
  57. package/package/corpus/skills/cratis-screenplay-scenario-coverage/SKILL.md +36 -29
  58. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/berth-reservations.md +6 -0
  59. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/invoicing-dues-design.md +15 -4
  60. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/invoicing-dues-example.md +25 -20
  61. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/public-event-coverage.md +14 -3
  62. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/scenario-examples.md +9 -3
  63. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/spec-forms-by-mode.md +7 -3
  64. package/package/corpus/skills/cratis-screenplay-slice-design/SKILL.md +3 -1
  65. package/package/corpus/skills/cratis-screenplay-slice-design/references/command-inventory.md +4 -4
  66. package/package/corpus/skills/cratis-screenplay-slice-design/references/rule-layers.md +4 -2
  67. package/package/corpus/skills/cratis-screenplay-slice-design/references/slicing.md +4 -3
  68. package/package/corpus/skills/cratis-screenplay-slice-design/references/worked-example.md +8 -8
  69. package/package/corpus/skills/cratis-screenplay-specifications/SKILL.md +49 -47
  70. package/package/corpus/skills/cratis-screenplay-specifications/references/actions-beyond-commands.md +11 -1
  71. package/package/corpus/skills/cratis-screenplay-specifications/references/generated-fixtures.md +48 -17
  72. package/package/corpus/skills/cratis-screenplay-specifications/references/vocabulary.md +14 -1
  73. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/SKILL.md +25 -21
  74. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/boundaries.md +2 -2
  75. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/consistency-and-concurrency.md +9 -3
  76. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/multi-service-models.md +4 -3
  77. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/streams-example.md +7 -0
  78. package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +30 -22
  79. package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet-example.md +3 -1
  80. package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet.md +47 -2
  81. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostic-arguments.md +60 -0
  82. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +65 -5
  83. package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +50 -22
  84. package/package/corpus/skills/cratis-screenplay-toolchain/references/generation-checks.md +93 -0
  85. package/package/corpus/skills/cratis-screenplay-toolchain/references/generation-strategies-example.md +117 -35
  86. package/package/corpus/skills/cratis-screenplay-toolchain/references/language-admission.md +46 -0
  87. package/package/corpus/skills/cratis-screenplay-toolchain/references/preferred-syntax.md +3 -1
  88. package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +25 -10
  89. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.json +1800 -50
  90. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.version +1 -1
  91. package/package/corpus/skills/cratis-screenplay-toolchain/references/traps.md +5 -3
  92. package/package/corpus/skills/cratis-screenplay-toolchain/verification.json +6 -1
  93. package/package/corpus/skills/cratis-screenplay-ui-composition/SKILL.md +8 -53
  94. package/package/corpus/skills/cratis-screenplay-ui-composition/references/file-references.md +2 -2
  95. package/package/corpus/skills/cratis-screenplay-ui-composition/references/interaction-example.md +54 -0
  96. package/package/corpus/skills/cratis-screenplay-ui-composition/verification.json +6 -3
  97. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +30 -29
  98. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +36 -9
  99. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/choosing-generation.md +28 -8
  100. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/publication-and-recovery.md +31 -0
  101. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/sandbox-and-specrunner.md +8 -0
  102. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/verification.json +4 -1
  103. package/package.json +1 -1
@@ -1,22 +1,30 @@
1
1
  <!-- Copyright (c) Cratis. All rights reserved. -->
2
2
  <!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
3
3
 
4
- # The shop in Screenplay: keep the release boundary
4
+ # The shop in Screenplay: generated values
5
+
6
+ ## Contents
7
+
8
+ - Choosing a strategy
9
+ - When not to generate
10
+ - Sources
5
11
 
6
12
  ## Choosing a strategy
7
13
 
8
14
  Use the same vocabulary as the [Fundamentals/Arc shop](../../cratis-fundamentals-concept/references/shop-generation.md),
9
15
  but only the released language realization: CustomerId is `cus_` + uppercase
10
- ULID, OrderId is `typeid "order"`, and InviteCode is NanoID. Their strategies
16
+ ULID, OrderId is `typeid "order"`, and InviteCode is NanoID. InvoiceNumber uses
17
+ a readable date/checksum pattern; TicketNumber is an Int pickup-ticket value. Their strategies
11
18
  belong to concepts; command properties only say `generated`/`generated identifier`.
12
19
  The existing [strategy reference](generated-values-and-responses.md) owns exact
13
20
  encodings, entropy, MCP edits, fixtures and freshness.
14
21
 
15
- **Context-dependent generation is not released in Screenplay.** The OrderId below
16
- is time-ordered TypeID, not Arc's received-time/tenant factory contract; Stage
17
- emits a wall-clock `New()`. Passed-through GenerationContext in Arc source
18
- recovery describes that strategy shape, not equivalent clock/tenant semantics.
19
- Context-member/rule recovery stays in code.
22
+ Requires Screenplay 4.172.0 or later (`screenplay --version`) for pattern/random/rule
23
+ and checksum validation (ESM v21); older compilers refuse them with PLAY0268.
24
+ `generate rule Name` can attach code with Now/Tenant context, but the reference
25
+ runner never executes it: pin the whole String result. TypeID itself has no
26
+ tenant slot. Context-member factory recovery still stays in code. Stage's
27
+ time-ordered factories use the command receipt, not an invented wall-clock value.
20
28
 
21
29
  The shop's ApiKey remains a **secret**. In .NET its factory is `Bytes(32)` and its
22
30
  concept is `[NotAudited]`. It is never an identifier (event-source IDs are plaintext
@@ -35,6 +43,11 @@ concept OrderId : String
35
43
  concept InviteCode : String
36
44
  generate nanoid
37
45
  concept ApiKey : String secret
46
+ concept InvoiceNumber : String
47
+ generate pattern "INV-{yyyy}{MM}-#{7}" checksum luhn
48
+ validate checksum luhn
49
+ concept TicketNumber : Int
50
+ generate random 100000..999999
38
51
  module Shop
39
52
  feature Customers
40
53
  slice StateChange Register
@@ -58,22 +71,39 @@ module Shop
58
71
  inviteCode = "abcdefghijklmnopqrstu"
59
72
  feature Orders
60
73
  slice StateChange Place
74
+ constraint UniqueInvoiceNumber
75
+ unique invoiceNumber on OrderPlaced
76
+ constraint UniquePickupTicket
77
+ unique pickupTicket on OrderPlaced
61
78
  command PlaceOrder
62
79
  orderId OrderId generated identifier
80
+ invoiceNumber InvoiceNumber generated
81
+ pickupTicket TicketNumber generated
63
82
  produces event OrderPlaced
83
+ invoiceNumber InvoiceNumber = invoiceNumber
84
+ pickupTicket TicketNumber = pickupTicket
64
85
  returns orderId
65
86
  specification PlacesWithPinnedValue
87
+ given clock "2026-10-02T09:00:00Z"
66
88
  when PlaceOrder
67
89
  for "order_0000000000e008000000000000"
90
+ generated invoiceNumber = "INV-202610-00000004"
91
+ generated pickupTicket = 123456
68
92
  then OrderPlaced
69
93
  for "order_0000000000e008000000000000"
94
+ invoiceNumber = "INV-202610-00000004"
95
+ pickupTicket = 123456
70
96
  then returns "order_0000000000e008000000000000"
71
97
  ```
72
98
 
73
99
  Each property is server-owned, not a client-minted input. The ApiKey declaration
74
100
  is not permission to replace its secret contract with an ordinary random String.
75
- No `given clock` is used: pin the whole value. A seed/clock does not draw a
76
- portable ULID or TypeID fixture. A v15 duplicate-source specification should
101
+ The invoice date segments use the pinned UTC clock; it does not draw a portable
102
+ ULID or TypeID fixture. Checksum validation is authored separately from generation.
103
+ Dates/check digits add no entropy. The short invoice and ticket values use
104
+ single-property unique constraints; neither is a generated identifier. Whole-source
105
+ freshness protects the OrderId destination, not every generated payload value.
106
+ A duplicate-source specification should
77
107
  expect Concurrency with no new facts or response, not a regenerated ID.
78
108
 
79
109
  ## When not to generate
@@ -83,10 +113,13 @@ idempotency keys, authorization, gapless invoice numbers or proof of projection
83
113
  readiness. A reference InviteCode is not automatically a credential; if possession
84
114
  confers access, protect it as a secret and do not claim this generated String
85
115
  example realizes that credential behavior. Never drop ApiKey's secret marker to
86
- make its generation bind/render. Pattern/random/rule execution, context rules,
87
- sequence allocation and secret generation stay explicit upstream gaps.
116
+ make its generation bind/render. A pattern is not gapless/sequential numbering;
117
+ check digits catch typos, not forgery. ESM v21 binds and reference-executes with
118
+ pins. Requires Stage 4.118.0 for checksum validation and 4.119.0 for pattern/random
119
+ rendering; older renderers refuse those constructs. `generate rule` still refuses
120
+ STAGE-ESM-028. Sequence allocation and secret generation stay explicit gaps.
88
121
 
89
- ## Tagged evidence
122
+ ## Sources
90
123
 
91
124
  Screenplay `Documentation/screenplay/generated-values/choosing.md`,
92
125
  `Documentation/screenplay/generated-values.md`,
@@ -0,0 +1,119 @@
1
+ <!-- Copyright (c) Cratis. All rights reserved. -->
2
+ <!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
3
+
4
+ # Literal text rules and portable matching
5
+
6
+ ## Contents
7
+
8
+ - Literal text rules
9
+ - Portable `matches`
10
+ - Studio replacements and public check APIs
11
+
12
+ ## Literal text rules
13
+
14
+ Requires Screenplay 4.184.0 or later (`screenplay --version`) for literal text rules and pattern admission checks; older compilers do not admit these rule forms.
15
+
16
+ Prefer a literal rule over a regex when the requirement is plain text. Complete example:
17
+
18
+ ```screenplay
19
+ concept InvoiceReference : String
20
+ validate
21
+ contains "-"
22
+ not contains " "
23
+ starts with "INV-"
24
+ ends with "-NOK"
25
+ ```
26
+
27
+ These concept/command-property rules select ESM v24. They compare UTF-16 code units
28
+ ordinally, without case folding or normalization. Use one non-enum text value and a
29
+ quoted literal operand, not a property, collection or regex. An absent optional
30
+ value passes; add `not empty` to require presence. An empty operand makes `contains`,
31
+ `starts with` and `ends with` pass, and `not contains` fail for present text.
32
+ Equality and inequality remain `== "x"` and `!= "x"`.
33
+
34
+ This is not condition grammar: `contains`/`starts with` in `require`, `produces when`
35
+ or reaction `where` remain PLAY0268. Those conditions admit scalar equality and
36
+ numeric ordering, not the property text rules.
37
+
38
+ Requires Stage 4.124.0 for v24 text-rule admission (`cratis --version` identifies the CLI bundle); older renderers refuse v24 with STAGE-ESM-016.
39
+
40
+ Stage admits v24 and executes these four rules on its Host and specification
41
+ executor, rendering ordinal UTF-16 comparisons without regex or a Screenplay
42
+ runtime dependency. The legacy EventModel syntax engine drops these rules; use
43
+ semantic admission, never infer support from that engine's output.
44
+
45
+ ## Portable `matches`
46
+
47
+ Requires Screenplay 4.183.0 or later (`screenplay --version`); older compilers use platform matching and may accept nonportable constructs.
48
+
49
+ A quoted pattern is a flagless JavaScript expression restricted to a portable linear
50
+ dialect, not arbitrary ECMAScript or .NET regex. It searches any substring unless
51
+ anchored. Screenplay uses its own Thompson automaton, without timeout or host-engine
52
+ settings. Syntax remains `matches "^INV-[0-9]{6}$"` or `matches email`.
53
+
54
+ | Admitted | Meaning |
55
+ | --- | --- |
56
+ | Literals, `.`, `^`, `$`, alternation | `$` is strict end of input, not before a final newline |
57
+ | `(…)`, `(?:…)`, `(?<name>…)` | ASCII names `[A-Za-z_][A-Za-z0-9_]*`; duplicate names only in disjoint alternatives; names that can match together report PLAY0367 |
58
+ | Classes, negation, single-character ranges | Unions/complements use set semantics |
59
+ | `\d \D \w \W \s \S` | `\d` is ASCII digits, `\w` ASCII letters/digits/underscore |
60
+ | `\t \n \r \f \v`, `\0` not before a digit, `\xHH`, `\uHHHH` | UTF-16 code-unit escapes |
61
+ | Escaped syntax characters and `\/` | `\-` also inside a class |
62
+ | `* + ? {n} {n,} {n,m}` and lazy forms | No stacked quantifiers |
63
+
64
+ `\s` includes U+00A0, U+FEFF and Unicode line/paragraph separators; it excludes
65
+ U+0085. Dot excludes LF, CR, U+2028 and U+2029. `\w` excludes U+0130.
66
+ `matches email` is conservative, not RFC 5322: one `@`, nonempty local part without
67
+ whitespace/`@`, and at least two nonempty domain parts without whitespace/`@`.
68
+ A no-break space therefore fails email validation. Other bare names report PLAY0366.
69
+
70
+ PLAY0367 means invalid syntax, including stacked quantifiers. PLAY0699 means a
71
+ construct outside the dialect: lookarounds, backreferences, word boundaries,
72
+ Unicode properties, code-point escapes, control/octal/identity escapes, .NET-only
73
+ anchors/options/class subtraction, empty classes, stray brackets, class escapes as
74
+ range endpoints, or non-ASCII group names. Use explicit classes, UTF-16/hex escapes,
75
+ `^`/`$`, or a literal text rule where equivalent. A length-only lookahead can become
76
+ an anchored counted repeat; there is no general lookaround replacement.
77
+
78
+ Limits are 1,000 decoded UTF-16 code units and 3,000 expanded nodes. Literals,
79
+ classes, anchors and each optional/loop/alternative choice point count one. Counted
80
+ repeats multiply their body by the upper bound (unbounded: lower bound plus one),
81
+ adding optional/loop choices. `x{1500}` counts 1,500; `a{0,1500}` and `(a*){1500}`
82
+ count 3,000. Exceeding either limit reports PLAY0699 before automaton construction.
83
+
84
+ Older serialized ESM retains authored pattern bytes and loads, but invalid/refused
85
+ patterns plan as UnsupportedValidation and generation checks report Unproven;
86
+ re-authoring reports PLAY0367/PLAY0699.
87
+ Browser matching remains advisory: JavaScript may backtrack even on admitted
88
+ `(a+)+$`. The server-side linear check is authoritative.
89
+
90
+ ## Studio replacements and public check APIs
91
+
92
+ Only exact escaped-literal Studio shapes desugar with warning PLAY0787, not PLAY0699:
93
+
94
+ | Decoded pattern (`L` is an escaped literal) | Replacement |
95
+ | --- | --- |
96
+ | `^(?![\s\S]*L)` | `not contains "literal"` |
97
+ | `L(?![\s\S])` | `ends with "literal"` |
98
+ | `^L(?![\s\S])` | `== "literal"` |
99
+ | `^(?!L$)` or `^(?!L(?![\s\S]))` | `!= "literal"` |
100
+
101
+ Recognition requires a lossless escape/decode round trip: Studio v1 uses
102
+ .NET Regex.Escape; v2 escapes `\ ^ $ . | ? * + ( ) [ ] { } /`. Other lookarounds
103
+ remain refused. Plain `L`, `^L`, `^L$` and `L$` are unchanged. Syntax retains the
104
+ original text, while binding stores the ordinal rule. Old ESM evaluates these exact
105
+ patterns as replacements without changing bytes. The editor quick fix and MCP
106
+ `propose-repair` migrate to literal rules preserving message/severity; preview the
107
+ revision-bound canonical-formatting proposal before explicit apply.
108
+
109
+ C#: `Cratis.Screenplay.Semantics.PortableMatchPattern.Check(pattern)`.
110
+ TypeScript: import `checkPortableMatchPattern` from `@cratis/screenplay-compiler`.
111
+ Both return PortableMatchCheck: status, code, construct, UTF-16 offset in the decoded
112
+ pattern, suggestion, description and optional replacement `{ kind, value }`.
113
+ Statuses are Admitted, Deprecated, Refused, Invalid (lowercase strings in TypeScript).
114
+ Admitted has no code; Deprecated is PLAY0787, Refused PLAY0699, Invalid PLAY0367.
115
+ Replacement kinds are Equal, NotEqual, Contains, NotContains, StartsWith, EndsWith.
116
+ Checking never executes a pattern or constructs a platform regex.
117
+
118
+ Validate with `screenplay <root> --warnaserror`, then execute acceptance/refusal
119
+ examples through `screenplay test <root>`; source validation alone is not a rule test.
@@ -10,9 +10,18 @@
10
10
  | `== <v>` / `!= <v>` | `currency == "NOK"`, `status != draft` |
11
11
  | `length == <n>` | `currency length == 3` |
12
12
  | `matches email` | the only named pattern; any other name is `PLAY0366` |
13
- | `matches "<regex>"` | ECMAScript; matches **any substring** unless anchored with `^…$`; an invalid pattern is `PLAY0367` |
13
+ | `matches "<regex>"` | Portable linear dialect; any substring unless anchored `^…$`; invalid syntax PLAY0367, refused constructs PLAY0699 |
14
+ | `contains "<text>"` / `not contains "<text>"` | Ordinal substring presence/absence on scalar non-enum text |
15
+ | `starts with "<text>"` / `ends with "<text>"` | Ordinal prefix/suffix; quoted literal operands, not conditions |
14
16
  | `all > <v>` / `all >= <v>` | `lines.quantity all > 0` |
15
17
  | `rule <Name>` | `orgNumber rule BeAValidOrganizationNumber` |
18
+ | `checksum luhn|mod11|mod97` | String concept `validate checksum luhn`; validates supplied/stored values too |
19
+
20
+ Requires Screenplay 4.172.0 or later (`screenplay --version`) for checksum rules
21
+ (ESM v21); older compilers refuse them with PLAY0268. A pattern's `checksum`
22
+ modifier generates check digits but does not add validation. Check digits catch
23
+ typos, not forgery. For generated-concept proof statuses, deterministic regex
24
+ limits and PLAY0688 repairs, read [generated rules](generated-values-and-responses.md#generated-concept-rules-esm-v20).
16
25
 
17
26
  ## `not empty` means non-blank text
18
27
 
@@ -60,9 +69,10 @@ validate
60
69
 
61
70
  A bodied rule or fenced block on a validation, rule or policy binds as opaque code
62
71
  (ESM v3): the reference runner reports it unsupported, and a target must supply the
63
- implementation. Two exceptions never bind: the command `handler`, and a `file`
64
- constraint (the binder records the requirement, then rejects it with `PLAY0268`;
65
- only `unique` constraints bind).
72
+ implementation. Attached command handlers and `file` constraints remain PLAY0268
73
+ (only `unique` constraints bind). Pending command handlers beside unconditional
74
+ `produces` instead bind as described commands; see [described handlers](described-handlers.md).
75
+ Literal text rules, portable patterns and Studio desugaring: [text and match rules](text-and-match-rules.md).
66
76
  Stage renders pure reducer transitions and opaque policy bodies, but refuses command and
67
77
  concept code validations and rule predicates (STAGE-ESM-005): those are gap-fill code. Prefer a
68
78
  declarative rule when one can say it. What binds and what the executable model rejects (Date and
@@ -4,6 +4,11 @@
4
4
  "fixtures": [],
5
5
  "assertions": [
6
6
  { "kind": "play-compiles" },
7
+ { "kind": "skill-contains", "value": "Unsupported (`ImplementationBody`)", "file": "references/described-handlers.md" },
8
+ { "kind": "skill-contains", "value": "including Stub mode", "file": "references/described-handlers.md" },
9
+ { "kind": "skill-contains", "value": "DecisionStateChanged", "file": "references/protected-reads.md" },
10
+ { "kind": "skill-contains", "value": "checkPortableMatchPattern", "file": "references/text-and-match-rules.md" },
11
+ { "kind": "skill-contains", "value": "U+00A0", "file": "references/text-and-match-rules.md" },
7
12
  { "kind": "skill-contains", "value": "screenplay_declaration_details", "file": "references/generated-values-and-responses.md" },
8
13
  { "kind": "skill-contains", "value": "do not hand-edit the text", "file": "references/generated-values-and-responses.md" },
9
14
  { "kind": "skill-contains", "value": "A CLI-bundled MCP can lack this summary", "file": "references/generated-values-and-responses.md" },
@@ -42,7 +47,7 @@
42
47
  },
43
48
  {
44
49
  "kind": "skill-contains",
45
- "value": "`produces` and `handler` are mutually exclusive"
50
+ "value": "A file/code `handler` cannot coexist with `produces`"
46
51
  },
47
52
  {
48
53
  "kind": "skill-contains",
@@ -54,11 +59,11 @@
54
59
  },
55
60
  {
56
61
  "kind": "skill-contains",
57
- "value": "`reads` is not a protected read"
62
+ "value": "command reads protected"
58
63
  },
59
64
  {
60
65
  "kind": "skill-contains",
61
- "value": "Adding a\n`concurrency` block does not fix this"
66
+ "value": "reads/concurrency cannot combine (PLAY0783)"
62
67
  },
63
68
  {
64
69
  "kind": "skill-contains",
@@ -93,6 +98,8 @@
93
98
  "value": "Generated identifiers need Uuid or String backing and at least 64 random bits.", "file": "references/generated-values-and-responses.md"
94
99
  },
95
100
  { "kind": "skill-contains", "value": "Generated values and responses (ESM v7 and v15)" },
101
+ { "kind": "skill-contains", "value": "names that can match together report PLAY0367", "file": "references/text-and-match-rules.md" },
102
+ { "kind": "skill-contains", "value": "or reaction `where` remain PLAY0268", "file": "references/text-and-match-rules.md" },
96
103
  { "kind": "skill-contains", "value": "Generated values are not request inputs", "file": "references/generated-values-and-responses.md" },
97
104
  { "kind": "skill-contains", "value": "Generated-concept validation rules select ESM v20", "file": "references/generated-values-and-responses.md" },
98
105
  { "kind": "skill-contains", "value": "PLAY0688 and a violating example", "file": "references/generated-values-and-responses.md" },
@@ -108,7 +108,7 @@ The independent verdicts V1 to V5 that report them are in
108
108
  `cratis-screenplay-modeling-lifecycle`.
109
109
 
110
110
  What binds depends on **which tool** you ask, so name the tool and its version:
111
- Read [references/parsed-not-runnable.md](references/parsed-not-runnable.md) (section "What binds depends on which tool") when stating what a tool binds or renders (`reads`/`concurrency` fail with `PLAY0271`; `persona` declarations are report-only; an older bundle reports *Slice '<name>' of type '<type>' is not admitted by ESM v1.*).
111
+ Read [references/parsed-not-runnable.md](references/parsed-not-runnable.md) (section "What binds depends on which tool") when stating what a tool binds or renders (legacy reads and `concurrency` fail with `PLAY0271`; protected command reads opt into v25; `persona` declarations are report-only; an older bundle reports *Slice '<name>' of type '<type>' is not admitted by ESM v1.*).
112
112
 
113
113
  The ESM versions, the full disposition table and the Step 7 clock example's binding
114
114
  result are in [references/parsed-not-runnable.md](references/parsed-not-runnable.md)
@@ -169,19 +169,19 @@ compile or will not be safe. Both are deliberate.
169
169
 
170
170
  - **A command may read state.** The generic method forbids `ReadModel -> Command`
171
171
  edges. Screenplay ships `reads <ReadModel> [as <alias>] [by <property>]` so the
172
- model shows what a state-dependent decision consulted. **It is not a protected
173
- (open limitation):** nothing checks at append time that the state is still current,
174
- the executable model rejects `reads` and `concurrency` (`PLAY0271`), and adding
175
- `concurrency` does not make the decision safe .
176
- Write a state-dependent rule as `reads <View>` plus `require <expr> message "..."`
177
- and mark it in the slice `description` as **not enforced in the model today**,
178
- naming the target that must enforce it (Arc `[ProtectedDecision]` with
179
- `DecisionRead<T>`, Chronicle's dynamic consistency boundary, or a constraint where
180
- one fits). Model uniqueness as a `unique` constraint. Never copy state into a
172
+ model shows what a state-dependent decision consulted. Application-root
173
+ `command reads protected` admits eligible command reads as v25: absent state
174
+ rejects and matching decide/commit changes conflict. Read
175
+ [protected reads](../cratis-screenplay-command-surface/references/protected-reads.md)
176
+ for the strict shape and paths. Legacy reads remain PLAY0271; `concurrency` is
177
+ not protection and cannot combine with protected reads. Stage refuses protected reads
178
+ (STAGE-ESM-044), not v25 itself: name target enforcement separately rather than claiming a render.
179
+ Write state-dependent rules as `reads` plus `require` with an indented message;
180
+ mark refused shapes as unenforced and name the intended target mechanism. Model uniqueness as a `unique` constraint. Never copy state into a
181
181
  command input, add an attestation flag, or hide the rule in `handler` prose. Do not
182
182
  use `reads` to fetch data the command could carry as input. A reaction trigger
183
- declares the views an automation decides from with the same `reads`, and the same
184
- caveat applies.
183
+ declares consulted views with `reads`, but trigger reads remain unprotected;
184
+ decide in an invoked command instead.
185
185
  - **Some validation *does* belong in the model.** The generic method routes format
186
186
  rules to the type system. Screenplay's type system *is* the `concept`, and a
187
187
  concept carries its own `validate` block - so a format rule lives on the concept
@@ -34,7 +34,7 @@ Tool versions and consumer boundaries: toolchain `SKILL.md`.
34
34
  | Compliance concepts | Bare `pii`/`personal` and `secret`, qualifiers and scope bind as v13; enum/identity compliance and events combining personal or explicitly subject-scoped secret values with an explicit `subject` mark refuse PLAY0268 at binding only. A CLI bundle that admits v13 binds markers; Stage renders v13 protection, not protected identities/enums or subject lineage. Never remove protection |
35
35
  | Identity details / processing purposes / event subject | Report-only metadata; executable detail reads refuse PLAY0268, not source declaration errors |
36
36
  | Composite stream ids | v8 routing; complete named parts/canonical comparisons, PLAY0515 refuses protected keys/sources; not a legacy text split |
37
- | Command reads/concurrency | Legacy unprotected decisions, PLAY0271 |
37
+ | Command reads/concurrency | Eligible reads opt into v25 with `command reads protected`; legacy reads/concurrency retain PLAY0271; Stage refuses protected reads (STAGE-ESM-044), not the v25 pair |
38
38
  | Invokes-only trigger reads | Report-only, not protected state; direct production with reads refuses |
39
39
  | Generated values/responses | v7 binding/reference execution; v15 strategies/strict fixtures/freshness. Stage renders supported UUID/String strategies, responses and fixtures; unsupported types/combinations remain -028/-038 |
40
40
  | Sources/streams and command/specification routes | v8 binding/reference execution; the CLI (toolchain `references/renderable-subset.md`) reaches Stage checks through its bundled ceiling (v16 without v17 support) |
@@ -70,8 +70,10 @@ accepted proposal or parsed node with a running application.
70
70
  - `Automation` and `Translate` slices, reactions, captures and triggers bind (ESM v6) on the
71
71
  standalone tool and a CLI bundle that admits v6. (An older bundle
72
72
  reports *Slice '<name>' of type '<type>' is not admitted by ESM v1.*) Stage renders supported event-triggered Automation, not Translate/captures or non-event triggers.
73
- - `reads` and `concurrency` on a command do not bind (`PLAY0271`), so no decision is
74
- protected against stale state. A reaction trigger's `reads` that only `invokes` is
73
+ - Eligible command reads bind/reference-execute with `command reads protected`
74
+ (v25); legacy reads and `concurrency` remain PLAY0271. Read command-surface
75
+ [protected reads](../../cratis-screenplay-command-surface/references/protected-reads.md)
76
+ for admission, absence/conflicts and Stage refusal. A reaction trigger's `reads` that only `invokes` is
75
77
  report-only intent (`PLAY0270`); one that `produces` directly fails binding (`PLAY0268`).
76
78
  - `persona` declarations are report-only and never block; bare `pii` and `secret`
77
79
  concepts bind as ESM v13 (Requires Screenplay 4.141.0 or later); Stage renders admitted v13 protection.
@@ -45,7 +45,11 @@
45
45
  },
46
46
  {
47
47
  "kind": "skill-contains",
48
- "value": "It is not a protected"
48
+ "value": "command reads protected"
49
+ },
50
+ {
51
+ "kind": "skill-contains",
52
+ "value": "Legacy reads remain PLAY0271"
49
53
  },
50
54
  {
51
55
  "kind": "skill-contains",
@@ -137,8 +137,8 @@ chain per slice before handoff (`references/evidence-table-template.md`, "Tracea
137
137
  - one StateChange per decision a person or system makes; events are facts experts recognise;
138
138
  consequences (counters, denormalised copies) become projections; an automation only when
139
139
  evidence shows a separate decision; no generic names (`Update/Edit/Save<Noun>`, `<Noun>Updated`): split by intent;
140
- - refusals, state-dependent rules (`reads` + `require`, marked **NOT enforced in the model
141
- today** with the target named), unique indexes and preserved `pii` / `secret` protection:
140
+ - refusals, state-dependent rules (`reads` + `require` with eligible protected-read
141
+ opt-in; legacy/refused shapes marked unenforced and target realization named), unique indexes and preserved `pii` / `secret` protection:
142
142
  `references/rule-modeling.md`. Every role gate has `authorize` plus a `then denied` spec,
143
143
  else a recorded gap; rules you cannot express truthfully are recorded one by one, never
144
144
  fabricated.
@@ -57,7 +57,7 @@ Example rows:
57
57
  | id | source | locator | observed fact | technical shape | strength | classification | gen. disposition | candidate | decision | decided by | verdict |
58
58
  |---|---|---|---|---|---|---|---|---|---|---|---|
59
59
  | E1 | dynamic | capture 0007, `POST /api/checkins` | taking in a coat writes two tables | insert `Checkins`; update `Hooks(occupied)`; 201 x41, 409 x3 | Observed | intent (take in) + consequence (hook) | n/a | `TakeInCoat` -> `CoatTakenIn`; occupancy via projection | change | proposed | not asked |
60
- | E2 | code | `CheckinService.cs` | 409 when the hook is already free, message "That coat is not on a hook" | throws `ConflictException` | Read | intent (rule) | n/a | `reads CoatStatus` + `require`, NOT enforced today (target: protected decision or Chronicle `concurrency` scope); no executable error spec, recorded in LOSS.md | keep | proposed | not asked |
60
+ | E2 | code | `CheckinService.cs` | 409 when the hook is already free, message "That coat is not on a hook" | throws `ConflictException` | Read | intent (rule) | n/a | legacy control: `reads CoatStatus` + `require` without protected opt-in; inspect v25 admission, record refused shape/Stage target gap in LOSS.md | keep | proposed | not asked |
61
61
  | E3 | static | `static.play`, SP0016 at `CheckinValidator` | validation rule held to a condition is emitted unconditionally; the condition is lost | `When(x => x.IsVip)` | Exact (loss) | unknown | Lowered without its condition (semantic mismatch, reported by SP0016) | none yet | undecided | - | question Q4: when does the rule really apply? read `CheckinValidator` and ask an expert |
62
62
  | E4 | dynamic | uncorrelated txn, `Hooks` nightly 02:00 | hook flags reset without a command | update `Hooks(*)` daily | Observed | unexplained | n/a | none | undecided | - | question Q5 |
63
63
 
@@ -24,6 +24,20 @@ Each recovery below has its own gate; use the adapter that has the one you rely
24
24
 
25
25
  - Requires Arc.Screenplay 22.78.0 or later for `[GeneratedValue]` Handle parameters whose `New()` is a UUID v4 form, for the `generated identifier` and response they produce, and for scenario pins (`for` / `generated`). Before it none of this is recovered. From 22.78.0 until 22.86.0 any other strategy keeps its source form and reports SP0073.
26
26
  - Requires Arc.Screenplay 22.86.0 or later to recover UUIDv7, ULID, TypeID, NanoID, `Bytes` and hex strategies as concept `generate` lines (ESM v15) and a passed-through `GenerationContext`.
27
+ - Requires Arc.Screenplay 22.101.0 for generated-concept validator recovery (ESM
28
+ v20); check `dotnet list package --include-transitive`. Older adapters withhold
29
+ generation on rule-bearing concepts. Recovery covers only a fully recovered,
30
+ non-opaque default validator: Proven rules emit, Unproven rules remain with
31
+ SP0078, Refuted rules withhold generation with SP0073 and a counterexample.
32
+ Generation is also withheld with SP0073 (rules kept) when the validator is
33
+ unreadable, conditional or names a predicate (`rule <Name>`), when a UUID
34
+ concept has any validator, when the concept carries `pii` or `secret`, and
35
+ below a v20 cap.
36
+ - Requires Arc.Screenplay 22.107.0 for pattern/random, checksum validation and
37
+ self-contained String generation-rule recovery (ESM v21); older adapters leave
38
+ those factories in code with SP0073. A v20-or-lower cap withholds generation
39
+ and dependent values/mappings/responses/destinations/scenarios, preserving
40
+ checksum validation as a source attachment rather than dropping it.
27
41
 
28
42
  Tagged evidence:
29
43
 
@@ -38,24 +52,30 @@ Tagged evidence:
38
52
  Use the [same shop vocabulary](../../cratis-screenplay-command-surface/references/shop-generation.md):
39
53
  CustomerId (`cus_` + ULID), OrderId (TypeID), InviteCode (NanoID), ApiKey (secret
40
54
  Bytes(32) with .NET `[NotAudited]`). Do not claim exact recovery of every factory:
41
- the custom `cus_` interpolation is not a recognized single factory call;
42
- TypeID can recover a passed-through context's strategy, not equivalent receipt-time/
43
- tenant behavior. Context-member bodies and generated secrets remain unreleased
44
- Screenplay scope. Preserve ApiKey's protection and source code, not an unprotected
55
+ a custom `cus_` interpolation may recover as a self-contained String rule, not as
56
+ an inferred built-in prefix strategy. TypeID recovers a passed-through context's
57
+ strategy, not proof of equivalent receipt-time/tenant behavior. Context-member
58
+ String bodies can recover under the v21 gate; generated secrets stay in code.
59
+ Recovered rule fixtures supply a String result without reference execution of the body. Preserve ApiKey's protection and source code, not an unprotected
45
60
  replacement String. The intentional candidate can author the released customer
46
61
  prefix strategy with an explicit target decision, separate from as-is proof.
47
62
 
48
63
  Recover the strategy the source proves; do not choose a replacement because a
49
64
  factory is named `New()`. Use the existing [strategy reference](../../cratis-screenplay-command-surface/references/generated-values-and-responses.md)
50
- for meaning and shapes, then the forms below for parameter factories, literal pins
65
+ for meaning and shapes (including readable InvoiceNumber patterns and random Int
66
+ TicketNumber values), then the forms below for parameter factories, literal pins
51
67
  and retained source pointers.
52
68
 
53
69
  ## When not to
54
70
 
55
71
  Do not infer generation for client-supplied IDs, deduplication keys or gapless
56
72
  invoice numbers, or turn an observed secret into a random String. Preserve
57
- protection and unrecovered code; rule/context-member bodies are not executable
58
- strategies. Report missing pins, withheld productions/scenarios and version caps
73
+ protection and unrecovered code. A pattern is not a gapless/sequential allocator
74
+ or secret; check digits detect typos, not forgery. Low-entropy payload codes need
75
+ uniqueness separate from source freshness. Arc recovery does not imply rendering:
76
+ Requires Stage 4.118.0 for checksum validation and 4.119.0 for pattern/random;
77
+ older renderers refuse them. `generate rule` still refuses STAGE-ESM-028.
78
+ Report missing pins, withheld productions/scenarios and version caps
59
79
  as losses, not successful recovery. Sources: Arc
60
80
  `Documentation/backend/csharp/generating-a-screenplay.md`;
61
81
  Screenplay `Documentation/screenplay/generated-values/choosing.md`.
@@ -65,8 +85,8 @@ Screenplay `Documentation/screenplay/generated-values/choosing.md`.
65
85
  The UUID v4 forms, pins and the identifier/response rules in this section need Arc.Screenplay 22.78.0 or later; the other strategies in the list below need 22.86.0 or later.
66
86
 
67
87
  A `[GeneratedValue]` Handle parameter becomes a generated command property only
68
- for a required scalar Uuid/String concept with a proven strategy and no validator,
69
- validation rules or compliance markers. Its explicit attribute name, otherwise
88
+ for a required scalar Uuid/String or signed Int32/Int64 random concept with a proven strategy and no compliance
89
+ markers. Validator rules recover under the v20 gate above, not by deleting them. Its explicit attribute name, otherwise
70
90
  parameter name, becomes the property name. A directly returned event-source
71
91
  identity (alone or beside an event) adds `generated identifier` and a response;
72
92
  a direct `EventForEventSourceId(parameter, event)` target adds the identifier
@@ -85,10 +105,26 @@ Constructors/conversions must forward the primitive unchanged. Recoverable calls
85
105
  - `RandomNumberGenerator.GetHexString(...)` → hex bytes only with an even literal
86
106
  character count; preserve its requested casing.
87
107
 
88
- A passed-through `GenerationContext` parameter is readable for UUIDv7/ULID/TypeID;
89
- reading `context.Now` or `context.Tenant` is not. Helper calls, multi-statement
90
- bodies, computed/invalid arguments and rule/pattern/random execution stay in code
91
- with SP0073. Never invent a rule body or implementation-file reference.
108
+ Under the v21 recovery gate, literal `GenerateValue.Pattern(pattern[, checksum])`
109
+ and its passed-through context overload recover `generate pattern`; dated patterns
110
+ require that context overload. `GenerateValue.Integer(min, max)` recovers inclusive
111
+ signed Int64 `random`; an Int32 concept needs exactly one `(int)` cast with both
112
+ bounds inside Int32. Invalid/computed arguments, unsigned backing and extra casts
113
+ stay in code with SP0073. Screenplay checks pattern support, proofs and entropy.
114
+
115
+ An unconditional default validator's `Must(v => GenerateValue.HasValidChecksum(v,
116
+ Checksum.Luhn))` recovers `validate checksum luhn` (also Mod11/Mod97). None,
117
+ conditional predicates and arbitrary helper predicates are not checksum rules.
118
+
119
+ A self-contained String factory can instead recover `generate rule <Concept>New`
120
+ with an inline `csharp` body, stripping only proven forwarding constructions.
121
+ Literal/primitive locals, `context.Now`, `context.Tenant`, string, Math, Convert,
122
+ Guid, RandomNumberGenerator and GenerateValue are allowlisted; multi-statement
123
+ bodies can qualify. Compound time-based calls must pass the captured context.
124
+ Private helpers, fields, DI, aliases/static imports, ambient time, raw Default
125
+ comparisons and external dependencies remain SP0073; no file fallback is invented.
126
+ This is the Cratis C# binding to Fundamentals' GenerationContext, not a universal
127
+ runtime type. Opaque entropy is unknown, so a rule cannot supply an identifier.
92
128
  The concept owns `generate`; each command property only marks generation.
93
129
  Use the shared [strategy reference](../../cratis-screenplay-command-surface/references/generated-values-and-responses.md)
94
130
  for exact encodings, ranges, entropy and admission, rather than duplicating them.
@@ -119,7 +155,8 @@ resolved adapter version, diagnostic, retained/withheld form and open question:
119
155
 
120
156
  | Diagnostic | Loss to reconcile |
121
157
  | --- | --- |
122
- | SP0073 | Unproven strategy/body/arguments, or non-default strategy above the ESM cap; no replacement strategy inferred. |
158
+ | SP0073 | Unproven strategy/body/arguments, refuted generated-concept rule with witness, or generation above the ESM cap; no replacement strategy inferred. |
159
+ | SP0078 | Generated-concept rule proof is Unproven; preserve the rule and reason, not a claim of Proven generation. |
123
160
  | SP0052 | Unadmitted generated value, dependent response or pre-generation protection stays in code; local-generation fallback is not parameter recovery. |
124
161
  | SP0012 | A required payload mapping or condition needs an unavailable value/read: withhold the whole production, never prune it into an incomplete fact. An optional blocked mapping can be omitted alone. |
125
162
  | SP0039 | Missing/unreadable pins, unrecoverable source identities or outcomes withhold the whole scenario. Name what was lost. |
@@ -1,5 +1,10 @@
1
1
  # Intentional candidate example
2
2
 
3
+ Legacy control: this candidate deliberately omits `command reads protected`, so its
4
+ unenforced markers are about this source. Eligible command reads can instead opt
5
+ into v25; inspect all reads before migration and keep target realization separate.
6
+ Read [protected reads](../../cratis-screenplay-command-surface/references/protected-reads.md).
7
+
3
8
  A complete, compiling example of what extraction produces: one legacy write that touched two
4
9
  tables (`Checkins`, `Hooks`) is re-sliced into a single decision event plus a projection. The
5
10
  numbers in the slice descriptions (`E1`, `E6`, `Q3`) are evidence ids and open questions from
@@ -35,7 +35,8 @@ and the question raised.
35
35
  ## Rules not enforced or not expressible today
36
36
  One line per rule, named individually (never one generic platform caveat): the rule, its
37
37
  evidence row, the invariant and consistency risk, and the target enforcement. State-dependent
38
- checks are written as `reads` + `require` and marked NOT enforced in the slice description;
38
+ checks use `reads` + `require`: eligible reads opt into v25 protection, while legacy/refused
39
+ shapes are marked unenforced and Stage realization remains a separate gap;
39
40
  date rules and opaque policies that no declaration can state stay in the slice `documentation` and here.
40
41
 
41
42
  ## Unknowns and undecided target decisions
@@ -12,9 +12,12 @@
12
12
 
13
13
  ## State-dependent rules
14
14
  A rule that depends on stored state (current status, existing records, balances) is written
15
- as `reads <View>` + `require <expr> message "…"` and the slice description says it is **NOT
16
- enforced in the model today** (PLAY0268/0271 at binding are expected in design mode).
17
- Name the invariant, the race it leaves open, and the target:
15
+ as `reads <View>` plus `require` with an indented message. Opt eligible views into
16
+ application-root `command reads protected` (v25); test present/absent state and rule
17
+ refusal, and matching decide/commit conflicts. Read
18
+ [protected reads](../../cratis-screenplay-command-surface/references/protected-reads.md)
19
+ for admission and Stage's refusal. For legacy/refused shapes, mark the rule unenforced.
20
+ Name the invariant, the race it leaves open and the target realization:
18
21
  `[ProtectedDecision]` + `DecisionRead<T>` (Arc 22.39.0 and later; available to gap-fill
19
22
  in Stage's rendered package set, not automatically emitted), or a Chronicle
20
23
  `concurrency` scope on the event source or stream, or a constraint where one fits. Forbidden: caller-supplied copies of state
@@ -71,7 +71,7 @@ files on it. Each hop has a typical yield:
71
71
 
72
72
  | Path | Hops | What to take from it |
73
73
  |---|---|---|
74
- | Write | entry point (route, handler, form action), input model and validation, service, entity, repository, schema or migration, response and error mapping | the command name and inputs; `validate` rules with their exact messages; state-dependent checks (`reads` plus `require`, NOT enforced); unique indexes; the error mapping gives the `then error` text and the legacy HTTP code for the slice `documentation` |
74
+ | Write | entry point (route, handler, form action), input model and validation, service, entity, repository, schema or migration, response and error mapping | the command name and inputs; `validate` rules with their exact messages; state-dependent checks (`reads` plus `require`, eligible protected opt-in or recorded legacy/refused shape and target gap); unique indexes; the error mapping gives the `then error` text and the legacy HTTP code for the slice `documentation` |
75
75
  | Read | entry point, query or repository, response model, paging and filter conventions | the read-model shape and query arguments (`by`, `filter`); which caller may narrow what |
76
76
  | Background | listeners, after-commit hooks, message consumers, schedulers, outbox relays | reaction or translation candidates; say "none found" when there is none |
77
77