@cratis/pi 7.63.0 → 7.64.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 (20) hide show
  1. package/package/corpus/product-sync.json +3 -3
  2. package/package/corpus/skills/cratis-screenplay-command-surface/SKILL.md +11 -2
  3. package/package/corpus/skills/cratis-screenplay-command-surface/references/date-comparisons.md +100 -0
  4. package/package/corpus/skills/cratis-screenplay-command-surface/references/validate-rules.md +12 -2
  5. package/package/corpus/skills/cratis-screenplay-command-surface/verification.json +3 -0
  6. package/package/corpus/skills/cratis-screenplay-model-authoring/references/language-reference.md +2 -1
  7. package/package/corpus/skills/cratis-screenplay-scenario-coverage/SKILL.md +12 -1
  8. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/berth-reservations.md +4 -4
  9. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/spec-forms-by-mode.md +2 -1
  10. package/package/corpus/skills/cratis-screenplay-specifications/SKILL.md +20 -0
  11. package/package/corpus/skills/cratis-screenplay-specifications/references/outcome-comparison.md +6 -0
  12. package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +4 -2
  13. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +1 -1
  14. package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +20 -4
  15. package/package/corpus/skills/cratis-screenplay-toolchain/references/language-admission.md +16 -1
  16. package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +3 -1
  17. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.json +1429 -25
  18. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.version +1 -1
  19. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +4 -1
  20. package/package.json +1 -1
@@ -171,9 +171,9 @@
171
171
  }
172
172
  ],
173
173
  "synced": {
174
- "version": "4.198.0",
174
+ "version": "4.199.0",
175
175
  "date": "2026-10-16",
176
- "by": "Cratis/AI#576"
176
+ "by": "Cratis/AI#735"
177
177
  },
178
178
  "covers": {
179
179
  "skills": [
@@ -201,7 +201,7 @@
201
201
  ],
202
202
  "rules": []
203
203
  },
204
- "notes": "Standalone 4.198.0 and byte-identical compiler contract pinned. Cratis/AI#576: mechanical compiler catch-up. Language batch #717/#722/#723/#724/#720/#728/#734 teaches atomic reaction batches (v22), described payload handlers (v23), portable linear matching, ordinal text rules (v24), protected command reads (v25), diagnostic arguments and event-source invokes mappings. Facts read at Screenplay v4.198.0 and introducing tags; Stage v4.127.0 admits exact v1-v21 and v23-v25 pairs but refuses v22/v26 and mixed pairs (STAGE-ESM-016), protected reads (044), atomic mode (043) and described handlers (STAGE-IMPL-002), even Stub mode. Stage text rules execute/render; no new renderer/runtime probe or Stage pin uplift. Cratis/AI#706: application navigation regions (module inherit, extend or override), toolbar slice buttons, blueprint template references and sample data packs in cratis-screenplay-ui-composition (references/application-shell.md), with the canonical shell vector and the rejection codes PLAY0710-PLAY0722 and PLAY0740-PLAY0765. Examples moved to the executable-state rules since 4.164: translator reactions in an Automation slice beside the Translate slice (PLAY0694) and the first record of a capture key appended with `when added`. Earlier: Standalone 4.164.0 and byte-identical compiler contract pinned. Cratis/AI#663: one origin per capture (PLAY0687). #668: executable no-event/redelivery v17. #684: concept query-argument validation in every version and query-error assertions v18. #681: executable refusal branches and refusal values v19. #666: proposal summary/severity counts and exact structural source proposals. Generated-concept rules select v20 with PLAY0688/0689 proofs and derived-matches repair; generated secrets and preview strategies remain refused. Release-baseline from-esm admission reads storedName. Standalone binding is not renderer admission: Stage 4.103.0 admits v1-v17 and v19; CLI 3.62.0 bundles Screenplay 4.159.0 / Stage 4.99.0 and renders through v16. Prior evidence remains unless superseded; no new renderer, Docker or browser probe."
204
+ "notes": "Standalone 4.199.0 and byte-identical compiler contract pinned. Cratis/AI#735: chronological Date/DateTime ordering in command conditions and command/property literal validation (ESM v26), UTC tick precision and pre-rule offset validation; then matching remains ordinal. Source-checked Screenplay v4.199.0 commands, diagnostics, interoperability and specifications documentation plus decision 0087. Stage v4.127.1 still refuses v26 with STAGE-ESM-016 (stage-rendering.md and SemanticVersionFeatures.Supports); no render/runtime probe. Cratis/AI#576: prior mechanical compiler catch-up. Language batch #717/#722/#723/#724/#720/#728/#734 teaches atomic reaction batches (v22), described payload handlers (v23), portable linear matching, ordinal text rules (v24), protected command reads (v25), diagnostic arguments and event-source invokes mappings. Facts read at Screenplay v4.198.0 and introducing tags; Stage v4.127.0 admits exact v1-v21 and v23-v25 pairs but refuses v22/v26 and mixed pairs (STAGE-ESM-016), protected reads (044), atomic mode (043) and described handlers (STAGE-IMPL-002), even Stub mode. Stage text rules execute/render; no new renderer/runtime probe or Stage pin uplift. Cratis/AI#706: application navigation regions (module inherit, extend or override), toolbar slice buttons, blueprint template references and sample data packs in cratis-screenplay-ui-composition (references/application-shell.md), with the canonical shell vector and the rejection codes PLAY0710-PLAY0722 and PLAY0740-PLAY0765. Examples moved to the executable-state rules since 4.164: translator reactions in an Automation slice beside the Translate slice (PLAY0694) and the first record of a capture key appended with `when added`. Earlier: Standalone 4.164.0 and byte-identical compiler contract pinned. Cratis/AI#663: one origin per capture (PLAY0687). #668: executable no-event/redelivery v17. #684: concept query-argument validation in every version and query-error assertions v18. #681: executable refusal branches and refusal values v19. #666: proposal summary/severity counts and exact structural source proposals. Generated-concept rules select v20 with PLAY0688/0689 proofs and derived-matches repair; generated secrets and preview strategies remain refused. Release-baseline from-esm admission reads storedName. Standalone binding is not renderer admission: Stage 4.103.0 admits v1-v17 and v19; CLI 3.62.0 bundles Screenplay 4.159.0 / Stage 4.99.0 and renders through v16. Prior evidence remains unless superseded; no new renderer, Docker or browser probe."
205
205
  },
206
206
  {
207
207
  "id": "scene",
@@ -177,11 +177,18 @@ optional `severity`, sharing the condition grammar with `produces … when`:
177
177
  `and` binds tighter than `or`, parentheses group. A conditional rule is an
178
178
  implication: `require isExtension == false or newEndDate > endDate`.
179
179
 
180
+ Requires Screenplay 4.199.0 (ESM v26; `screenplay --version`) for Date/DateTime
181
+ comparisons; older binders report PLAY0268. Read [date comparisons](references/date-comparisons.md)
182
+ when ordering a retention window with `require to >= from`, comparing instants
183
+ across offsets, or rejecting offset-less inputs before rules. It covers admitted
184
+ positions, PLAY0268/0273, ordinal `then` matching and Stage's v26 refusal.
185
+
180
186
  **Rules whose logic is code.** A bare `rule <Name>` has no portable meaning (`PLAY0268`) and a bodied rule binds only as
181
187
  opaque code. Read [references/validate-rules.md](references/validate-rules.md) when a rule's logic must live in a `file`
182
188
  or fenced code body.
183
189
 
184
- **Put format rules on the `concept`, not the command.** A concept carries its own
190
+ **Put format rules on the `concept`, not the command** (except date comparisons,
191
+ which bind only on command properties, not as concept rules). A concept carries its own
185
192
  `validate` block and every use inherits it — that is Screenplay's type system, and
186
193
  a rule that travels is worth more than one that is repeated.
187
194
 
@@ -281,7 +288,9 @@ Four contexts, and **what each omits is load-bearing** — when writing a code b
281
288
  bundle compatibility and execution are separate checks.
282
289
  - [ ] No unintended `PLAY0478` or `PLAY0479` information remains.
283
290
  - [ ] At most one command property carries `identifier`, and no event property does.
284
- - [ ] Format rules live on the `concept`; state-dependent rules are specifications.
291
+ - [ ] Format rules live on the `concept` except command-only date comparisons;
292
+ state-dependent rules are specifications. DateTime comparisons preserve UTC
293
+ ticks; specs include missing-offset Validation rejection.
285
294
  - [ ] Every `authorize` combining policies writes `and`/`or` explicitly.
286
295
  - [ ] Protected reads opt in, meet admission and distinguish reference protection
287
296
  from target realization; legacy reads and `concurrency` imply no protection.
@@ -0,0 +1,100 @@
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
+ # Chronological command date comparisons
5
+
6
+ Requires Screenplay 4.199.0 (ESM v26; `screenplay --version`); older binders refuse date comparisons with PLAY0268. Upgrade the compiler without weakening the rule.
7
+
8
+ Use `==`, `!=`, `>`, `>=`, `<` or `<=` with matching primitives: Date/Date or
9
+ DateTime/DateTime. A concept may type a command property; date rules on the concept
10
+ itself remain refused. These are the admitted positions:
11
+
12
+ | Position | Left | Right |
13
+ | --- | --- | --- |
14
+ | `require`, `produces when` | Required scalar command property | Required scalar command property of the same primitive, or literal |
15
+ | Command/property validation rule | Subject property | Literal only |
16
+
17
+ `Date` orders calendar dates without a time zone. `DateTime` compares UTC instants
18
+ at tick precision (seven fractional digits), including `==`/`!=`: different offsets
19
+ can name equal instants. Literal operands bind to canonical text (`yyyy-MM-dd`, or
20
+ UTC `yyyy-MM-ddTHH:mm:ss.fffffffZ`). An unparsable date literal or an offset-less
21
+ DateTime literal in an admitted position reports PLAY0273.
22
+
23
+ Every participating DateTime input must carry an offset or `Z`. Otherwise input
24
+ validation rejects the command with Validation **before any rule or condition**,
25
+ even if the comparison would short-circuit or its production would be skipped.
26
+ Targets must enforce this before deserialization attaches a local offset, and
27
+ preserve tick precision or refuse the comparison; JavaScript `Date` alone truncates
28
+ precision. Client validators omit date ordering rules. Optional absent values still
29
+ pass validation rules other than `not empty`; optional condition operands refuse.
30
+
31
+ PLAY0268 still refuses mixed Date/DateTime, `$context` operands (including
32
+ `$context.occurred`), `today`, protected read paths, date rules on concepts and
33
+ reaction `where`. A refused whole comparison reports only PLAY0268, without
34
+ validating its literals. A `given clock` does not admit `today` or now.
35
+ Stage refuses v26 with STAGE-ESM-016; standalone binding/reference execution is
36
+ not rendering. Preserve the rule and route delivery to authorized gap-fill.
37
+
38
+ ## Retention window and rejection specifications
39
+
40
+ Two required DateTime inputs express a caller-chosen interval, not the server's
41
+ clock. Keep state-dependent retention-policy reads separately protected; this
42
+ example models only interval ordering. `then` matching remains ordinal, as do
43
+ keys, constraints and freshness: preserve the exact produced payload spelling,
44
+ not a different offset that happens to name the same instant.
45
+
46
+ ```screenplay
47
+ concept WindowId : Uuid
48
+ module Retention
49
+ feature Windows
50
+ slice StateChange KeepWindow
51
+ command KeepWindow
52
+ windowId WindowId identifier
53
+ from DateTime
54
+ to DateTime
55
+ validate
56
+ require to >= from
57
+ message "The window must not end before it starts"
58
+ produces event WindowKept
59
+ from DateTime = from
60
+ to DateTime = to
61
+ specification AcceptingEqualInstantsWithDifferentOffsets
62
+ when KeepWindow
63
+ windowId = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
64
+ from = "2026-10-01T10:00:00+02:00"
65
+ to = "2026-10-01T08:00:00Z"
66
+ then WindowKept
67
+ for "3fa85f64-5717-4562-b3fc-2c963f66afa6"
68
+ from = "2026-10-01T10:00:00+02:00"
69
+ to = "2026-10-01T08:00:00Z"
70
+ specification RejectingAnInvertedWindowByOneTick
71
+ when KeepWindow
72
+ windowId = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
73
+ from = "2026-10-01T08:00:00.0000002Z"
74
+ to = "2026-10-01T08:00:00.0000001Z"
75
+ then error "The window must not end before it starts"
76
+ specification AcceptingAnIncreasingWindow
77
+ when KeepWindow
78
+ windowId = "3fa85f64-5717-4562-b3fc-2c963f66afa6"
79
+ from = "2026-10-01T08:00:00Z"
80
+ to = "2026-10-01T09:00:00Z"
81
+ then WindowKept
82
+ for "3fa85f64-5717-4562-b3fc-2c963f66afa6"
83
+ from = "2026-10-01T08:00:00Z"
84
+ to = "2026-10-01T09:00:00Z"
85
+ ```
86
+
87
+ Extract the complete fence into an ignored `.ai-work/` model folder. Run
88
+ `screenplay <folder> --warnaserror --no-color` (zero errors/warnings), then
89
+ `screenplay test <folder>` (all three specifications passed, none Unsupported).
90
+
91
+ ## Missing-offset input rejection
92
+
93
+ Add a `RejectingAMissingOffset` test at the evaluator-request or target input
94
+ boundary: submit `from = "2026-10-01T08:00:00"` with a valid `to`, then reverse which
95
+ input lacks an offset. Expect Validation before any rule, no facts, and the message
96
+ `DateTime command property 'from' requires an explicit offset or Z.` (or `'to'`).
97
+ Include a skipped-condition case where applicable. A typed `.play` fixture with
98
+ that invalid value refuses binding with PLAY0273; `then error` does not turn it
99
+ into an executed runtime rejection. Record the target test separately, not as a
100
+ passing `.play` specification or a `given clock` workaround.
@@ -23,6 +23,16 @@ modifier generates check digits but does not add validation. Check digits catch
23
23
  typos, not forgery. For generated-concept proof statuses, deterministic regex
24
24
  limits and PLAY0688 repairs, read [generated rules](generated-values-and-responses.md#generated-concept-rules-esm-v20).
25
25
 
26
+ ## Date and DateTime comparisons
27
+
28
+ Requires Screenplay 4.199.0 (ESM v26; `screenplay --version`); older binders refuse
29
+ with PLAY0268. Command/property rules admit `==`, `!=`, `>`, `>=`, `<`, `<=` against
30
+ a same-primitive date literal only, for example `to >= "2026-01-01T00:00:00Z"` on
31
+ DateTime. Property-to-property comparisons instead use `require to >= from`.
32
+ Date rules on concepts remain refused; an absent optional value passes rules
33
+ except `not empty`. Read [date comparisons](date-comparisons.md) for UTC ticks,
34
+ input offsets, refused positions and the complete retention-window specifications.
35
+
26
36
  ## `not empty` means non-blank text
27
37
 
28
38
  On text, `not empty` rejects null, empty text and whitespace-only text; at least
@@ -75,5 +85,5 @@ implementation. Attached command handlers and `file` constraints remain PLAY0268
75
85
  Literal text rules, portable patterns and Studio desugaring: [text and match rules](text-and-match-rules.md).
76
86
  Stage renders pure reducer transitions and opaque policy bodies, but refuses command and
77
87
  concept code validations and rule predicates (STAGE-ESM-005): those are gap-fill code. Prefer a
78
- declarative rule when one can say it. What binds and what the executable model rejects (Date and
79
- DateTime comparisons, nested-path rules): `cratis-screenplay-toolchain` `references/executable-subset.md`.
88
+ declarative rule when one can say it. What binds and what the executable model rejects
89
+ (date comparisons outside command positions, nested-path rules): `cratis-screenplay-toolchain` `references/executable-subset.md`.
@@ -4,6 +4,9 @@
4
4
  "fixtures": [],
5
5
  "assertions": [
6
6
  { "kind": "play-compiles" },
7
+ { "kind": "skill-contains", "value": "require to >= from", "file": "references/date-comparisons.md" },
8
+ { "kind": "skill-contains", "value": "RejectingAMissingOffset", "file": "references/date-comparisons.md" },
9
+ { "kind": "skill-contains", "value": "STAGE-ESM-016", "file": "references/date-comparisons.md" },
7
10
  { "kind": "skill-contains", "value": "Unsupported (`ImplementationBody`)", "file": "references/described-handlers.md" },
8
11
  { "kind": "skill-contains", "value": "including Stub mode", "file": "references/described-handlers.md" },
9
12
  { "kind": "skill-contains", "value": "DecisionStateChanged", "file": "references/protected-reads.md" },
@@ -272,8 +272,9 @@ See read-surface `references/named-keys.md` for the collection-key exclusion alg
272
272
  | Described handlers (ESM v23) | Pending implementation beside unconditional produces; payload-only contract, reached body Unsupported ImplementationBody; Stage STAGE-IMPL-002 even Stub mode |
273
273
  | Ordinal text rules (ESM v24) | contains/not contains/starts with/ends with on scalar non-enum text properties; quoted literals, not conditions; Stage semantic engines execute/render |
274
274
  | Protected command reads (ESM v25) | Root `command reads protected`; eligible read paths in requirements and production mappings, absence Validation, concurrent matching facts Conflict; Stage admits v25 but refuses protected reads STAGE-ESM-044 |
275
+ | Chronological command dates (ESM v26) | Same-primitive Date/DateTime `==`, `!=`, `>`, `>=`, `<`, `<=` in require/produces-when (property or literal RHS) and command/property rules (literal RHS only). DateTime uses UTC ticks, participating offset-less inputs reject Validation before rules; then matching stays ordinal. Requires Screenplay 4.199.0 (`screenplay --version`); older binders refuse PLAY0268. Stage refuses v26 STAGE-ESM-016. Read command-surface `references/date-comparisons.md`. |
275
276
  | Current routing and actor admission | Sources/streams and command/specification routes bind and reference-execute as v8; reaction `runs as system role` supplies the invocation actor as v10. Whole-workspace binding determines executable availability; CLI/Stage realization remains separate |
276
- | Blocks binding (`PLAY0268`) | enum/identity compliance and events combining personal or explicitly subject-scoped secret values with explicit subject marks; a compiler that stops before v13 refuses all `pii`/`secret` concepts ("compliance attributes require portable data-subject semantics"), while v13 binds them and Stage renders protection; attached command `handler` (PLAY0035 beside productions; pending described intent instead binds v23), bare `rule <Name>`, read paths without protected opt-in or in unsupported positions such as `produces when`, dates and `today` in comparisons, `$context.tenant`/claims/roles/causation in `produces`, `$env` conditions, `file` constraints, unquoted `import` of an external contract, a read model with neither explicit `key` nor unambiguous query-based identity as described above (composite keys remain unadmitted), queries with context `from` sources (typed query context is unadmitted), single-result filters (collections only), `scoped to` (opaque scope), `performer` (opaque implementation) or composite `by` blocks; optional keyed and collection queries, including caller-supplied equality filters and observable delivery, bind, `$causedBy` and templates in projections |
277
+ | Blocks binding (`PLAY0268`) | enum/identity compliance and events combining personal or explicitly subject-scoped secret values with explicit subject marks; a compiler that stops before v13 refuses all `pii`/`secret` concepts ("compliance attributes require portable data-subject semantics"), while v13 binds them and Stage renders protection; attached command `handler` (PLAY0035 beside productions; pending described intent instead binds v23), bare `rule <Name>`, read paths without protected opt-in or in unsupported positions such as `produces when`, date comparisons with mixed primitives, optional condition operands, `$context`, protected read paths or `today`, date rules on concepts or reaction `where`, `$context.tenant`/claims/roles/causation in `produces`, `$env` conditions, `file` constraints, unquoted `import` of an external contract, a read model with neither explicit `key` nor unambiguous query-based identity as described above (composite keys remain unadmitted), queries with context `from` sources (typed query context is unadmitted), single-result filters (collections only), `scoped to` (opaque scope), `performer` (opaque implementation) or composite `by` blocks; optional keyed and collection queries, including caller-supplied equality filters and observable delivery, bind, `$causedBy` and templates in projections |
277
278
  | Blocks binding (`PLAY0271`, legacy meaning) | Command reads without protected opt-in and `concurrency`; combined protected reads/concurrency is PLAY0783 |
278
279
  | Deferred (`PLAY0269`, information) | Screens, layouts, templates, forms, contributions, UI profiles, themes, behaviors and `on`/`uses` |
279
280
  | Metadata only (`PLAY0270`, information) | `domain`, `seed`, `persona`, trigger and other descriptions, and `file` provenance on declarations |
@@ -87,6 +87,16 @@ when these inputs are unsettled; skip answered questions.
87
87
  ## Scenario types (decide each per command; detail in `references/scenario-catalogue.md`)
88
88
  Decide each of these per command: happy path; rule rejection (one spec per rule, exact pinned `then error`); denial (`given caller` without the policy, `then denied`, one per gated command and query); state violation; duplicate or retry; competing claim; alternative path; ordering; external failure; compensation; evolution; and the view pass. Read [references/scenario-catalogue.md](references/scenario-catalogue.md) ("Scenario types at a glance") for each type's question and usual shape.
89
89
 
90
+ For command Date/DateTime ordering, cover increasing and inverted intervals,
91
+ equality across offsets, a one-tick boundary and **each participating DateTime
92
+ input without an offset or Z**. That last case rejects with Validation before rules,
93
+ even if a condition short-circuits or a production is skipped. `then` stays ordinal;
94
+ never replace payload text with an equivalent instant. Read the complete
95
+ [retention-window specifications](../cratis-screenplay-command-surface/references/date-comparisons.md)
96
+ for the compiler prerequisite, admitted positions, refused `today` and Stage's v26
97
+ refusal. Missing-offset runtime coverage needs an evaluator-request or target input
98
+ test: a typed `.play` fixture rejects that value at binding with PLAY0273, before runtime.
99
+
90
100
  For recovery, `when redelivered <Event> to <Reaction>` must select one definitely
91
101
  matching effective given and no undecided candidate. It delivers only to the named
92
102
  reaction without re-appending the input; `then no events` explicitly checks no
@@ -126,7 +136,8 @@ proved and keep other guarantees as target requirements; recovery cases are in
126
136
  opaque source text, not the capture's content key.
127
137
  - Format rules belong on a `concept`: give each concept rule representative acceptance,
128
138
  rejection and boundary specs once (through one command that carries it), not on every use;
129
- never `n/a` automatically. Include a whitespace-only rejection for text `not empty`:
139
+ never `n/a` automatically. Date/DateTime comparisons are command-only, not concept rules.
140
+ Include a whitespace-only rejection for text `not empty`:
130
141
  this changes outcomes in every ESM version (Requires Screenplay 4.151.0 or later). Unicode/identity boundaries
131
142
  and evidence: command-surface `references/validate-rules.md`.
132
143
  A business rule gets one rejection spec if an expert could recognize it from its message;
@@ -18,8 +18,8 @@ Complete, compiled design-mode model (marina guest berths) showing a coverage ma
18
18
  // + `require ... message` and marked NOT enforced in the slice descriptions, with their target
19
19
  // named. Binding reports PLAY0271/PLAY0268 for them (expected; Screenplay#129): such a model
20
20
  // is design-complete but not binding-ready, and that is reported, never "fixed" by deleting the
21
- // rules. The past-date rule (`night >= today`) is declarative too: ESM v1 has no runtime date,
22
- // so binding reports PLAY0268 on it (recorded as blocked, not moved into prose); the rule and its rejection
21
+ // rules. The past-date rule (`night >= today`) is declarative too: `today` has no runtime date
22
+ // value, so binding reports PLAY0268 on it (recorded as blocked, not moved into prose); the rule and its rejection
23
23
  // specification stay so the intent executes once a date value exists.
24
24
  // Verified: V1 (warnings as errors). V3 binding is blocked by the stored-state and date rules.
25
25
 
@@ -36,7 +36,7 @@ module Berths
36
36
  authorize IsHarbourOffice
37
37
 
38
38
  slice StateChange ReserveBerth
39
- description "One guest boat per berth per night. OneBoatPerBerthNight declares that two event sources cannot hold the same berth-night; the competing-claim specification pins the loser's rejection after an earlier holder. It neither runs two commands at once nor proves the runtime's index-and-append behaviour under failure: that needs target-level verification. A retried ReserveBerth with the same reservation id is refused by ReserveOnce: the fact occurs once, but the retry is NOT answered with success, so a client that lost the first acknowledgement must treat this rejection as 'already reserved' (idempotent handling is a target decision, recorded as an open question). The night must not be in the past: declared in `validate` (`night >= today`) with its rejection specification. Binding reports PLAY0268 for date comparisons today (ESM v1 has no runtime date value), so this rule is design-complete but blocks V3 until Screenplay supports it."
39
+ description "One guest boat per berth per night. OneBoatPerBerthNight declares that two event sources cannot hold the same berth-night; the competing-claim specification pins the loser's rejection after an earlier holder. It neither runs two commands at once nor proves the runtime's index-and-append behaviour under failure: that needs target-level verification. A retried ReserveBerth with the same reservation id is refused by ReserveOnce: the fact occurs once, but the retry is NOT answered with success, so a client that lost the first acknowledgement must treat this rejection as 'already reserved' (idempotent handling is a target decision, recorded as an open question). The night must not be in the past: declared in `validate` (`night >= today`) with its rejection specification. Binding reports PLAY0268 for the `today` operand, which has no runtime date value (comparisons between Date or DateTime command properties, or against literals, bind), so this rule is design-complete but blocks V3 until Screenplay supports `today`."
40
40
  command ReserveBerth
41
41
  reservationId ReservationId identifier
42
42
  berth BerthCode
@@ -99,7 +99,7 @@ module Berths
99
99
  boatLength = 31
100
100
  then error "Guest berths take boats up to 24 metres"
101
101
 
102
- // Declarative past-date rule; binding is blocked for date comparisons (see header).
102
+ // Declarative past-date rule; binding is blocked for the `today` operand (see header).
103
103
  specification RejectingANightInThePast
104
104
  given caller
105
105
  authenticated
@@ -34,7 +34,8 @@ Typed example/override forms: `cratis-screenplay-specifications`
34
34
  | Refusal branches, `$refusal` | yes | ESM v19; first matching branch wins | Stage supported subset; -039 for unfaithful refusal details/trigger groups, -011 for specification limits |
35
35
  | Query `then error` | yes | ESM v18; one query/one error, no result/denial | requires target v18 admission; a v19-capable renderer does not necessarily admit v18 |
36
36
  | Composite (JSON) values in specs | yes | yes | no |
37
- | Rules over dates or `today`, nested paths | spec them in design | rule does not bind: `recorded` | `recorded` |
37
+ | Same-primitive `Date`/`DateTime` comparisons in `require`, `produces when` and command or property validation rules (v26; Requires Screenplay 4.199.0; see [date comparisons](../../cratis-screenplay-command-surface/references/date-comparisons.md)) | spec them | binds and executes; a `DateTime` input without an offset is a Validation rejection | v26 STAGE-ESM-016: gap-fill |
38
+ | Date rules using `today`, `$context`, mixed `Date`/`DateTime`, concept or reaction-`where` positions; nested paths | spec them in design | rule does not bind: `recorded` | `recorded` |
38
39
  | Bodied rules, code policies | spec them | spec reported **unsupported**, never passed | no |
39
40
  | 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 |
40
41
  | Attached command handlers, `file` constraints, query `performer`s | spec them in design | blocked: PLAY0268 at binding, no spec runs (V3 blocked) | no |
@@ -81,6 +81,21 @@ or target tests; name engine, version and expected/discovered selection.
81
81
  [text and match rules](../cratis-screenplay-command-surface/references/text-and-match-rules.md)
82
82
  for boundary values and PLAY0699/0787. Reference success is not Stage admission.
83
83
 
84
+ ## Chronological command date comparisons
85
+
86
+ Requires Screenplay 4.199.0 (ESM v26; `screenplay --version`); older binders refuse
87
+ these comparisons with PLAY0268. DateTime conditions compare UTC instants at tick
88
+ precision: cover equal instants with different offsets, increasing endpoints,
89
+ an inverted interval and a one-tick boundary. Every participating DateTime input
90
+ without an offset or `Z` rejects with Validation before rules, even when its
91
+ comparison is skipped; add a missing-offset rejection, not a clock fixture workaround.
92
+ `then` matching stays ordinal: expected event values keep the exact produced text,
93
+ not an equivalent offset. Read the complete [retention-window specifications](../cratis-screenplay-command-surface/references/date-comparisons.md)
94
+ for `require to >= from`, PLAY0268/0273 and Stage's v26 refusal. The missing-offset
95
+ runtime case needs an evaluator-request or target input test: putting the invalid
96
+ value in a typed `.play` fixture instead fails binding with PLAY0273; `then error`
97
+ does not exercise runtime validation.
98
+
84
99
  ## Descriptions, persona callers and case tables
85
100
 
86
101
  Use one `description "<rule or behavior>"` (or a fenced `text` description) to
@@ -196,6 +211,9 @@ Whitespace-acceptance specs fail. This applies to every ESM version.
196
211
 
197
212
  Requires Screenplay 4.151.0 or later (`screenplay --version`) for the Unicode `not empty` correction.
198
213
 
214
+ Date/DateTime comparisons are the command-only exception: do not move them onto
215
+ concept rules to follow the general format-rule convention.
216
+
199
217
  ## Application-boundary coverage
200
218
 
201
219
  Every slice should carry at least one specification whose action is what a real
@@ -223,6 +241,8 @@ For command specifications:
223
241
  - [ ] Error cases test business rules; each concept rule has one rejection
224
242
  specification through one command, not one per use.
225
243
  - [ ] A localized rejection is pinned by its quoted `$strings` key.
244
+ - [ ] DateTime comparisons cover offset-less input rejection before rules, equal
245
+ instants across offsets and tick boundaries; `then` keeps ordinal payload values.
226
246
 
227
247
  For view specifications:
228
248
 
@@ -20,6 +20,12 @@ This reference holds the comparison rules for events, read models, query rows an
20
20
  and requires the rejection to carry the string-key marker; it never loads
21
21
  translated text; resolving the key is the realization's job.
22
22
 
23
+ Date/DateTime `then` matching stays ordinal: different offsets naming one instant
24
+ do not match merely because a v26 command comparison considers them equal. Keep
25
+ the exact produced payload text in the expectation. Keys, constraints and freshness
26
+ also retain ordinal equality. For UTC-tick comparisons and pre-rule missing-offset
27
+ Validation rejections, read the [retention-window specifications](../../cratis-screenplay-command-surface/references/date-comparisons.md).
28
+
23
29
  ## Rejections and denials say different things
24
30
 
25
31
  `then error "<message>"` says **rejected, for this reason** — pin it when the
@@ -135,8 +135,10 @@ changes with the root folder name.
135
135
  `references/diagnostics.md` for proof/support failures. Binding is not rendering.
136
136
  Tool/renderer authors: read [references/generation-checks.md](references/generation-checks.md)
137
137
  when discovering strategy options, checking one concept or value, or consuming rule proofs.
138
- - **v22–v25:** read [language admission](references/language-admission.md) for atomic
139
- batches, described handlers, text rules, protected reads and Stage refusals.
138
+ - **v22–v26:** read [language admission](references/language-admission.md) for atomic
139
+ batches, described handlers, text rules, protected reads, chronological command
140
+ Date/DateTime comparisons (Requires Screenplay 4.199.0; `screenplay --version`;
141
+ older binders refuse PLAY0268) and Stage refusals.
140
142
  Read [diagnostic arguments](references/diagnostic-arguments.md) for MCP/JSON subjects:
141
143
  code and typed arguments, never message parsing.
142
144
  - **Caller/compliance metadata:** `$identity` aliases caller built-ins;
@@ -340,7 +340,7 @@ bodies, batches or protected reads (STAGE-ESM-044).
340
340
  | PLAY0268 | construct the ESM cannot represent; read the message for the construct (`executable-subset.md` lists attached handlers, unsupported query shapes, protected enum/identity concepts, read paths without opt-in or in conditions, and older bundled-compiler limits) | stay in design mode, or change the construct if the domain allows; never strip `pii`/authorization |
341
341
  | PLAY0269 / 0270 | UI deferred / authoring metadata (I) | none |
342
342
  | PLAY0271 | legacy `reads` or a `concurrency` block keeps its legacy meaning and cannot bind (error) | opt eligible command reads into v25 with reviewed preamble repair; `concurrency` remains unbound; uniqueness uses a constraint, target realization stays separate |
343
- | PLAY0273 | incoherent: ambiguous `for`, property not on event revision, operand type mismatch, derived `$eventContext` path | fix the reference |
343
+ | PLAY0273 | incoherent: ambiguous `for`, property not on event revision, operand type mismatch, derived `$eventContext` path, unparsable date literal or offset-less DateTime literal in an admitted v26 comparison | fix the reference or literal; DateTime needs offset/Z |
344
344
  | PLAY0350 | `null` in command/event value | Chronicle semantics (nullable event properties are CHR0012; an optional fact is a separate event), not only a binder limitation: specs cannot state an absent command/event value. Omit the value or record a capability gap; whether the optional detail is really a separate fact is a review question, not this code's fix |
345
345
  | PLAY0351 | given/then readmodel lacks the key property | add the keyed query's `by` property |
346
346
  | PLAY0352 | when-less spec asserting an action outcome, except a sole query Validation error (v18) | add an action or assert readmodel/query |
@@ -10,6 +10,7 @@
10
10
  - Time, reactions and captures (ESM v6)
11
11
  - Generated values and responses (ESM v7)
12
12
  - Released public boundaries and observer routes
13
+ - Chronological command date comparisons (ESM v26)
13
14
  - Code attachments (what binds, what never does)
14
15
  - Refused (code, reason): fix, or record as a mode gap
15
16
  - Not refused, but do not rely on it
@@ -40,7 +41,8 @@ Complete examples that bind live in `executable-example.md`, `pdl-example.md` (p
40
41
  `automation-translate-example.md` (ESM v6) and `generated-responses-example.md` (ESM v7).
41
42
 
42
43
  For atomic batches (v22), described handlers (v23), ordinal text rules (v24) and
43
- protected reads (v25), read [language admission](language-admission.md). A later
44
+ protected reads (v25) and chronological command dates (v26), read
45
+ [language admission](language-admission.md). A later
44
46
  version alone does not enable either application opt-in.
45
47
 
46
48
  ## Caller and compliance boundary
@@ -251,12 +253,26 @@ Stage renders v13 concept protection; protected identities/enums still refuse
251
253
 
252
254
  Requires Screenplay 4.117.0 or later (`screenplay --version`) for ESM v9, 4.129.0 or later for production overrides and observer filters (v10), 4.135.0 or later for v11 and 4.139.0 or later for enum numbers (v12).
253
255
 
256
+ ## Chronological command date comparisons (ESM v26)
257
+
258
+ Requires Screenplay 4.199.0 (ESM v26; `screenplay --version`); older binders refuse
259
+ with PLAY0268. `==`, `!=`, `>`, `>=`, `<`, `<=` bind for Date/Date or DateTime/DateTime.
260
+ `require`/`produces when` compare required scalar command properties to properties
261
+ or literals; command/property validation rules accept literal right operands only.
262
+ DateTime compares UTC instants at tick precision, not text. Every participating
263
+ DateTime input needs an offset or `Z`, else Validation rejects before rules, even
264
+ for skipped comparisons. `then` matching stays ordinal. Invalid date literals or
265
+ offset-less DateTime literals in admitted comparisons report PLAY0273. Read
266
+ [date comparisons](../../cratis-screenplay-command-surface/references/date-comparisons.md)
267
+ for the complete window model and retained PLAY0268 refusals. Stage refuses v26
268
+ with STAGE-ESM-016, independently of standalone binding/reference execution.
269
+
254
270
  ## Code attachments (what binds, what never does)
255
271
 
256
272
  Pending `handler implementation` beside unconditional `produces` binds as a described
257
273
  command (v23). Its payload-only body returns Unsupported ImplementationBody when reached;
258
274
  denial/validation specs still run. Read [language admission](language-admission.md) for
259
- v22–v25 and [described handlers](../../cratis-screenplay-command-surface/references/described-handlers.md)
275
+ v22–v26 and [described handlers](../../cratis-screenplay-command-surface/references/described-handlers.md)
260
276
  for the result contract. Attached handlers remain unbound.
261
277
 
262
278
  Inline fences (`csharp`, `typescript`, `react`, `html`, `sql`) and `file <path>` attach
@@ -302,8 +318,8 @@ bodies still leave their owner non-executable.
302
318
  | `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 |
303
319
  | `query` with a composite `by` block, or `by ... from` context-derived arguments | PLAY0268 | composite `by` blocks remain unadmitted. 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 |
304
320
  | 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 |
305
- | `contains` or `starts with` in conditions only | PLAY0268 | `require`/`produces when` conditions admit equality and numeric ordering only; property/concept text rules bind as v24 |
306
- | Date or DateTime comparison, `today` | PLAY0268 | no runtime date value |
321
+ | `contains` or `starts with` in conditions only | PLAY0268 | conditions admit scalar equality and numeric ordering, plus same-primitive command date comparisons from v26; property/concept text rules bind as v24 |
322
+ | 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 |
307
323
  | Rule on a nested path (`lines.qty all > 0`) | PLAY0268 | put the rule on the nested value's concept |
308
324
  | Read paths without protected opt-in, or in `produces when` | PLAY0268 | v25 admits single-level paths only in `require` and produced-event mappings |
309
325
  | Legacy `reads <View> ...` on a command | PLAY0271 (error) | `command reads protected` opts eligible views into v25; see command-surface protected reads |
@@ -1,7 +1,7 @@
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
- # Language admission: batches, described bodies, text and reads
4
+ # Language admission: batches, described bodies, text, reads and dates
5
5
 
6
6
  Select the highest version required by constructs in the model. A newer version
7
7
  alone never opts into either application mode. Consumers must explicitly admit
@@ -13,6 +13,7 @@ exact language/semantic pairs; binding, reference execution and rendering are se
13
13
  | v23 | Pending `handler implementation` beside unconditional `produces` | Payload-only body; PLAY0695 information; reaching body gives Unsupported ImplementationBody | v23 admitted, body refused STAGE-IMPL-002 in renderer/Host/executor, even Stub mode |
14
14
  | v24 | `contains`, `not contains`, `starts with`, `ends with` property/concept rules | Ordinal UTF-16, absent optional passes; not text-condition operators | v24 admitted; semantic Host/executor and generated ordinal comparisons preserve rules |
15
15
  | v25 | Application-root `command reads protected` | Admitted reads in requirements/mappings, absence Validation, matching decide/commit changes Conflict | v25 admitted; protected reads refused STAGE-ESM-044 in renderer/Host/executor |
16
+ | v26 | Chronological command Date/DateTime comparisons | Same-primitive `==`, `!=`, `>`, `>=`, `<`, `<=`; DateTime UTC ticks and pre-rule offset validation | v26 refused STAGE-ESM-016 |
16
17
 
17
18
  Requires Screenplay 4.181.0 or later (`screenplay --version`) for atomic batches; older compilers cannot admit the preamble.
18
19
 
@@ -22,6 +23,8 @@ Requires Screenplay 4.184.0 or later (`screenplay --version`) for literal text r
22
23
 
23
24
  Requires Screenplay 4.193.0 or later (`screenplay --version`) for protected reads; older binders retain PLAY0271/PLAY0268.
24
25
 
26
+ Requires Screenplay 4.199.0 (ESM v26; `screenplay --version`) for date comparisons; older binders report PLAY0268.
27
+
25
28
  Requires Stage 4.124.0 for v24 text-rule admission (`cratis --version` identifies the CLI bundle); older renderers refuse v24 with STAGE-ESM-016. V23 admission alone does not implement described bodies.
26
29
 
27
30
  Requires Stage 4.127.0 for v25 version admission; older renderers refuse v25 with STAGE-ESM-016. Protected reads still refuse STAGE-ESM-044, including on legacy paths; no artifacts are emitted.
@@ -39,6 +42,18 @@ Text comparisons and matching are in [text and match rules](../../cratis-screenp
39
42
  PLAY0699 refuses nonportable constructs, PLAY0367 invalid syntax, PLAY0787 warns
40
43
  on exact Studio text-rule patterns and offers a literal-rule repair.
41
44
 
45
+ For v26, `require`/`produces when` compare a required scalar command property to
46
+ a required same-primitive property or literal. Command/property validation rules
47
+ compare only to literals. Date is a calendar date; DateTime is a UTC instant at
48
+ seven-fractional-digit tick precision. Participating DateTime inputs without an
49
+ offset or `Z` reject with Validation before any rule, even if a comparison is skipped.
50
+ `then` matching, keys, constraints and freshness remain ordinal. PLAY0268 retains
51
+ mixed Date/DateTime, optional condition operands, `$context` (including occurred),
52
+ `today`, protected read paths, concept date rules and reaction `where`. In admitted
53
+ positions, invalid date literals or offset-less DateTime literals use PLAY0273.
54
+ Read [date comparisons](../../cratis-screenplay-command-surface/references/date-comparisons.md)
55
+ for the complete interval example and input/target boundaries.
56
+
42
57
  Stage's semantic engines admit exact v1–v21 and v23–v25 pairs. V22/v26 and mixed
43
58
  pairs refuse STAGE-ESM-016. Admission of v23–v25 is not admission of described bodies,
44
59
  atomic mode or protected reads. A CLI may bundle an older compiler/Stage pair: run no-write render
@@ -22,7 +22,9 @@ and concept compliance (v13) render.
22
22
  ## Current admission
23
23
 
24
24
  Stage admits exact ESM v1–v21 and v23–v25 pairs; v22/v26 and mixed pairs
25
- refuse STAGE-ESM-016. Version admission is separate from construct support.
25
+ refuse STAGE-ESM-016. Chronological command Date/DateTime comparisons select v26:
26
+ standalone binding/reference execution does not make them renderable. Keep the
27
+ rule and use authorized gap-fill. Version admission is separate from construct support.
26
28
  Requires Stage 4.106.0 for v18 admission; older Stage refuses it with `STAGE-ESM-016`.
27
29
  For generated-concept v20/v21 admission and construct prerequisites, read
28
30
  [Stage admission](../../cratis-stage-rendering-and-sandbox/references/admission.md).