@cratis/pi 7.128.0 → 7.130.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 (119) hide show
  1. package/package/corpus/agents/coordinator.md +1 -1
  2. package/package/corpus/agents/orchestrator.md +1 -1
  3. package/package/corpus/agents/planner.md +1 -1
  4. package/package/corpus/harnesses/copilot/instructions/csharp.instructions.md +2 -2
  5. package/package/corpus/harnesses/copilot/instructions/framework.instructions.md +1 -1
  6. package/package/corpus/harnesses/copilot/instructions/orleans.instructions.md +2 -1
  7. package/package/corpus/harnesses/copilot/instructions/pull-requests.instructions.md +1 -1
  8. package/package/corpus/harnesses/copilot/instructions/specs.csharp.instructions.md +1 -1
  9. package/package/corpus/harnesses/pi/agents/coordinator.md +1 -1
  10. package/package/corpus/harnesses/pi/agents/orchestrator.md +1 -1
  11. package/package/corpus/harnesses/pi/agents/planner.md +1 -1
  12. package/package/corpus/harnesses/pi/extensions/cratis-hooks/index.ts +1 -1
  13. package/package/corpus/hooks/README.md +17 -5
  14. package/package/corpus/hooks/pre-commit.md +2 -2
  15. package/package/corpus/hooks/scripts/cratis-quality-gate.sh +1 -0
  16. package/package/corpus/hooks/scripts/cratis-run-specs.sh +147 -0
  17. package/package/corpus/hooks/scripts/quality-gates.json +5 -7
  18. package/package/corpus/product-sync.json +4 -4
  19. package/package/corpus/rules/csharp.md +2 -2
  20. package/package/corpus/rules/framework.md +1 -1
  21. package/package/corpus/rules/orleans.md +2 -1
  22. package/package/corpus/rules/pull-requests.md +1 -1
  23. package/package/corpus/rules/specs.csharp.md +1 -1
  24. package/package/corpus/skills/binlog-generation/SKILL.md +1 -1
  25. package/package/corpus/skills/coverage-analysis/references/setup-discovery.md +1 -1
  26. package/package/corpus/skills/cratis-application-slice-conformance/SKILL.md +1 -1
  27. package/package/corpus/skills/cratis-application-slice-specifications/SKILL.md +1 -1
  28. package/package/corpus/skills/cratis-arc-command-execution/references/command-refusals.md +1 -1
  29. package/package/corpus/skills/cratis-arc-command-execution/references/occurrence-commands.md +1 -1
  30. package/package/corpus/skills/cratis-arc-command-operation/references/testing.md +1 -1
  31. package/package/corpus/skills/cratis-arc-command-validation/references/input-binding.md +1 -1
  32. package/package/corpus/skills/cratis-arc-command-validation/references/validation-severity.md +1 -1
  33. package/package/corpus/skills/cratis-arc-react-page/references/from-screenplay.md +5 -5
  34. package/package/corpus/skills/cratis-chronicle-client-dotnet/references/immediate-append-refusal.md +1 -1
  35. package/package/corpus/skills/cratis-chronicle-client-dotnet/references/occurrences.md +1 -1
  36. package/package/corpus/skills/cratis-chronicle-event-constraints/references/storage-uniqueness.md +1 -1
  37. package/package/corpus/skills/cratis-chronicle-event-specifications/SKILL.md +1 -1
  38. package/package/corpus/skills/cratis-chronicle-event-type-migration/references/explicit-migrations.md +1 -1
  39. package/package/corpus/skills/cratis-chronicle-reactor/references/starting-and-replaying.md +1 -1
  40. package/package/corpus/skills/cratis-chronicle-read-model/references/collection-observation.md +1 -1
  41. package/package/corpus/skills/cratis-chronicle-read-model-specifications/SKILL.md +1 -1
  42. package/package/corpus/skills/cratis-ci-pipeline-performance/SKILL.md +1 -1
  43. package/package/corpus/skills/cratis-ci-pipeline-performance/references/build-once-and-shard.md +7 -3
  44. package/package/corpus/skills/cratis-ci-pipeline-performance/references/flaky-and-hung-jobs.md +1 -1
  45. package/package/corpus/skills/cratis-ci-pipeline-performance/references/test-setup-cost.md +1 -1
  46. package/package/corpus/skills/cratis-commits-and-pull-requests/references/pr-labels-and-release.md +1 -1
  47. package/package/corpus/skills/cratis-engineering-ci-gates/SKILL.md +3 -2
  48. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/SKILL.md +5 -1
  49. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/worked-examples.md +17 -8
  50. package/package/corpus/skills/cratis-orchestration-lanes/references/context-handoff.md +1 -1
  51. package/package/corpus/skills/cratis-orchestration-lanes/references/lane-brief.md +2 -2
  52. package/package/corpus/skills/cratis-screenplay-automations-and-translations/SKILL.md +6 -1
  53. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/automation-patterns.md +1 -1
  54. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/cases-to-specify.md +5 -5
  55. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/statemachines-and-workflows.md +164 -0
  56. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/todo-list-example.md +12 -15
  57. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/translate-example.md +10 -4
  58. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/complete-examples.md +2 -2
  59. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/invocation-identity.md +8 -2
  60. package/package/corpus/skills/cratis-screenplay-command-surface/SKILL.md +5 -4
  61. package/package/corpus/skills/cratis-screenplay-command-surface/references/described-handlers.md +12 -8
  62. package/package/corpus/skills/cratis-screenplay-command-surface/references/validate-rules.md +5 -5
  63. package/package/corpus/skills/cratis-screenplay-command-surface/verification.json +1 -1
  64. package/package/corpus/skills/cratis-screenplay-event-modeling/references/nine-steps.md +6 -3
  65. package/package/corpus/skills/cratis-screenplay-legacy-extraction/references/generated-recovery.md +4 -4
  66. package/package/corpus/skills/cratis-screenplay-model-authoring/references/language-reference.md +2 -2
  67. package/package/corpus/skills/cratis-screenplay-read-surface/references/named-keys.md +3 -1
  68. package/package/corpus/skills/cratis-screenplay-read-surface/references/screen-patterns.md +2 -2
  69. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/SKILL.md +4 -4
  70. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/delivery-protocol.md +2 -2
  71. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/renderability-gate.md +6 -5
  72. package/package/corpus/skills/cratis-screenplay-scenario-coverage/SKILL.md +2 -2
  73. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/invoicing-dues-design.md +0 -3
  74. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/invoicing-dues-example.md +8 -3
  75. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/scenario-examples.md +17 -9
  76. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/spec-forms-by-mode.md +4 -3
  77. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/version-skew.md +25 -14
  78. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/view-and-story-specs.md +7 -6
  79. package/package/corpus/skills/cratis-screenplay-scenario-coverage/verification.json +1 -1
  80. package/package/corpus/skills/cratis-screenplay-slice-design/references/read-model-design.md +1 -1
  81. package/package/corpus/skills/cratis-screenplay-slice-design/references/slicing.md +1 -1
  82. package/package/corpus/skills/cratis-screenplay-slice-design/references/worked-example.md +3 -3
  83. package/package/corpus/skills/cratis-screenplay-specifications/SKILL.md +8 -5
  84. package/package/corpus/skills/cratis-screenplay-specifications/references/actions-beyond-commands.md +4 -2
  85. package/package/corpus/skills/cratis-screenplay-specifications/references/child-ordering.md +12 -3
  86. package/package/corpus/skills/cratis-screenplay-specifications/references/reactions-and-cascades.md +70 -21
  87. package/package/corpus/skills/cratis-screenplay-specifications/references/vocabulary.md +3 -2
  88. package/package/corpus/skills/cratis-screenplay-specifications/verification.json +2 -2
  89. package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +3 -3
  90. package/package/corpus/skills/cratis-screenplay-toolchain/references/automation-translate-example.md +5 -8
  91. package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet-example.md +12 -11
  92. package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet.md +1 -1
  93. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostic-arguments.md +1 -1
  94. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +2 -2
  95. package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +10 -7
  96. package/package/corpus/skills/cratis-screenplay-toolchain/references/fast-path.md +1 -1
  97. package/package/corpus/skills/cratis-screenplay-toolchain/references/language-admission.md +4 -1
  98. package/package/corpus/skills/cratis-screenplay-toolchain/references/preferred-syntax.md +4 -1
  99. package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +4 -4
  100. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract-exceptions.json +0 -70
  101. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.json +4743 -623
  102. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.version +1 -1
  103. package/package/corpus/skills/cratis-screenplay-toolchain/references/traps.md +1 -1
  104. package/package/corpus/skills/cratis-screenplay-toolchain/references/verdicts.md +1 -1
  105. package/package/corpus/skills/cratis-screenplay-ui-composition/SKILL.md +6 -0
  106. package/package/corpus/skills/cratis-screenplay-ui-composition/references/action-subjects.md +73 -0
  107. package/package/corpus/skills/cratis-screenplay-ui-composition/references/file-references.md +4 -3
  108. package/package/corpus/skills/cratis-screenplay-ui-composition/references/response-continuations.md +1 -1
  109. package/package/corpus/skills/cratis-screenplay-ui-composition/references/worked-flow.md +1 -1
  110. package/package/corpus/skills/cratis-specifications-csharp/references/running-specs.md +7 -3
  111. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +8 -6
  112. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +8 -5
  113. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/render-example.md +1 -1
  114. package/package/corpus/skills/csharp-refactoring/SKILL.md +2 -2
  115. package/package/corpus/skills/eliminate-redundant-restores/SKILL.md +2 -1
  116. package/package/corpus/skills/filter-syntax/SKILL.md +1 -1
  117. package/package/corpus/skills/msbuild/references/build-perf-baseline.md +4 -1
  118. package/package/corpus/skills/run-tests/SKILL.md +9 -0
  119. package/package.json +1 -1
@@ -83,9 +83,9 @@ module Marina
83
83
  screen BerthListScreen
84
84
  title "Berths"
85
85
  data BerthListView[] via query ListBerths
86
- action BookBerth
86
+ action BookBerth for screen
87
87
  label "Book a berth"
88
- action CancelBerth
88
+ action CancelBerth for item
89
89
  table BerthListView
90
90
  column boatName label "Boat"
91
91
  on row-click navigate to BerthDetailsScreen by berthId
@@ -94,7 +94,7 @@ module Marina
94
94
  data BerthListView via query GetBerth by berthId
95
95
  summary BerthListView
96
96
  field boatName label "Boat"
97
- action CancelBerth
97
+ action CancelBerth for item
98
98
  navigate to BerthListScreen
99
99
 
100
100
  form BookBerthForm for BookBerth
@@ -119,8 +119,8 @@ field because `berthId` is the identifier, not something the user types.
119
119
  | `table BerthListView` with `column boatName label "Boat"` | `<DataPage.Columns><Column field='boatName' header='Boat' /></DataPage.Columns>`; one `Column` per modeled `column`, no extras | Verified |
120
120
  | A second `table` on one screen | `DataTableForQuery` / `DataTableForObservableQuery` ([data-tables.md](data-tables.md)) | Verified |
121
121
  | `summary BerthListView` with `field boatName label "Boat"` | Plain markup in the page or in `detailsComponent` (`{ item }`), one labelled line per modeled `field` | Gap: this skill's verified sources name no summary component |
122
- | `action BookBerth` with `label "Book a berth"` | `<MenuItem label='Book a berth' icon={...} command={() => showBookBerth()} />` plus `CommandDialog` and `useDialog` | Verified |
123
- | `action CancelBerth` on a list with a table | `MenuItem` with `disableOnUnselected`; the selected row supplies the identifier | Verified prop |
122
+ | `action BookBerth for screen` with `label "Book a berth"` | `<MenuItem label='Book a berth' icon={...} command={() => showBookBerth()} />` plus `CommandDialog` and `useDialog`; no row fills its inputs | Verified |
123
+ | `action CancelBerth for item` on a list with a table | `MenuItem` with `disableOnUnselected`; the selected row supplies the identifier | Verified prop |
124
124
  | `action` with no `label` | The model gives no text. Use the command name, spaced, and report it | Gap |
125
125
  | `action X` with `navigate to S [by p]` | Navigate to the page for `S` after the command succeeds, in `onSuccess`; pass `p` from the response or the row | Assumption: `screens.md` does not say when it navigates. The form's `on submit` is defined as "after a successful submit"; confirm with the model owner |
126
126
  | `on row-click navigate to S by p` | `DataPage` and `DataTableForQuery` forward no row-click prop (only `DataTableCore` has `onRowClick`, and it takes rows, not a query). Use controlled `selection` and `onSelectionChange` to navigate, or a link in a `Column` `body` | Gap: selection is not a click; report which you chose |
@@ -36,5 +36,5 @@ In a spec, attempt an immediate append through both the current event log and a
36
36
  previously captured reference; assert that neither reaches transport. Assert
37
37
  that transactional work commits with its receipt, that an unsupported kernel
38
38
  fails closed, and that borrowed frames cannot complete another owner's unit.
39
- Run `dotnet test` on the owning project. In-process proof is not a substitute for
39
+ Run the owning project's built spec executable (see [specs.csharp](../../../rules/specs.csharp.md)). In-process proof is not a substitute for
40
40
  integration coverage of the storage provider's transaction boundary.
@@ -81,7 +81,7 @@ a handler through in-process ingress, claims, receipts and completion:
81
81
 
82
82
  There are no background workers, automatic lease renewals or reminders in this
83
83
  scenario; it does not prove behavior in a real multi-node cluster. Run
84
- `dotnet test` on the owning spec project and assert duplicate ingress, redelivery,
84
+ the owning spec project's built executable (see [specs.csharp](../../../rules/specs.csharp.md)) and assert duplicate ingress, redelivery,
85
85
  terminal refusal, lost reply and unsupported-capability paths.
86
86
 
87
87
  Requires Chronicle 19.78.0 for `Defaults` and `EventStoreForTesting` constructors
@@ -22,7 +22,7 @@ complete: the first claimant in event-log order retains the value, later duplica
22
22
  claims are logged and skipped. Reindexing does not retract their stored events.
23
23
  Older kernels can fail the reindex instead.
24
24
 
25
- Run the affected specifications with `dotnet test`, asserting a second source's
25
+ Run the affected specifications with the owning project's built spec executable (see [specs.csharp](../../../rules/specs.csharp.md)), asserting a second source's
26
26
  rejection, unchanged original claim after a failed move, and successful reuse
27
27
  after release. Real SQL integration must prove two competing claims cannot both
28
28
  succeed; an in-memory pass does not prove the SQL index was upgraded.
@@ -229,6 +229,6 @@ assert the value can be claimed again.
229
229
  ## How it is proven
230
230
 
231
231
  `dotnet build` in Debug (which compiles the `#if DEBUG` specification code) and
232
- `dotnet test`, both clean. A constraint specification is only meaningful if it
232
+ the owning project's built spec executable (see [specs.csharp](../../rules/specs.csharp.md)), both clean. A constraint specification is only meaningful if it
233
233
  has been seen to fail: remove the seeding `Given` once and confirm the
234
234
  specification goes red before trusting it green.
@@ -41,6 +41,6 @@ the store-local alias. Custom schema generators resolving explicit compensation
41
41
  targets need the registry-aware overloads or throw
42
42
  `RegistryAwareEventTypeSchemasNotSupported`.
43
43
 
44
- Run `dotnet build -c Debug` and migration specs with `dotnet test`; assert both
44
+ Run `dotnet build -c Debug` and migration spec executables (see [specs.csharp](../../../rules/specs.csharp.md)); assert both
45
45
  directions and real observer delivery where pinning or protected-value release
46
46
  matters. A successful nomination alone does not prove a generation can be read.
@@ -29,5 +29,5 @@ handler is still subscribed to.
29
29
 
30
30
  Verify first registration, restart with an existing position, replay and
31
31
  failed-partition redelivery separately. Assert the external effect count, not
32
- only that the handler was invoked. Run `dotnet test` on the owning spec project;
32
+ only that the handler was invoked. Run the owning spec project's built executable (see [specs.csharp](../../../rules/specs.csharp.md));
33
33
  server-first compatibility and durable positions also need kernel integration.
@@ -41,7 +41,7 @@ pretending observation succeeded.
41
41
 
42
42
  ## Verify
43
43
 
44
- Run `dotnet build -c Debug` and `dotnet test` for the owning query specs. Cover
44
+ Run `dotnet build -c Debug` and the owning query spec executable (see [specs.csharp](../../../rules/specs.csharp.md)). Cover
45
45
  empty, add, update, remove, filter exit and disposal.
46
46
  Requires Arc 22.87.0 for Chronicle observations in `QueryScenario`.
47
47
  Requires Arc 22.91.1 with Chronicle 19.59.1 for default-mode children/joins/reducers. Scenario rebuilds do
@@ -283,6 +283,6 @@ Read `references/view-lifecycle-checks.md` when delivering a read model from a c
283
283
 
284
284
  ## How it is proven
285
285
 
286
- `dotnet build` in Debug and `dotnet test`, both clean. A projection
286
+ `dotnet build` in Debug and the owning project's built spec executable (see [specs.csharp](../../rules/specs.csharp.md)), both clean. A projection
287
287
  specification is only meaningful once it has been seen to fail: drop one seeded
288
288
  event and confirm the assertion goes red before trusting it green.
@@ -75,7 +75,7 @@ named reference before applying one.
75
75
  **Build once, shard the tests.** Fits execution-bound workflows where build and
76
76
  tests run serially or several jobs each rebuild. Default: one job builds in
77
77
  `Release`, uploads the output with `actions/upload-artifact`, and a matrix of shard jobs downloads it and runs
78
- `dotnet test --no-build`. Pitfall: a shard whose filter matches nothing still
78
+ each built spec executable; only VSTest projects use `dotnet test <project> --no-build`. Pitfall: a shard whose filter matches nothing still
79
79
  passes, so assert that every shard ran tests. Read
80
80
  `references/build-once-and-shard.md` when applying or reviewing this.
81
81
 
@@ -75,15 +75,19 @@ jobs:
75
75
  with:
76
76
  name: build-output
77
77
  - run: tar --zstd -xf build-output.tar.zst
78
+ # Example assumes each xUnit v3 mtp-off AssemblyName matches its directory.
79
+ # Use evaluated TargetPath for custom outputs; TUnit/native runners need their own report flags.
80
+ # Only VSTest uses dotnet test <project> --no-build --configuration Release with --logger/--results-directory.
78
81
  - name: Test the shard's projects
79
82
  env:
80
83
  PROJECTS: ${{ matrix.projects }}
81
84
  run: |
82
85
  failed=0
83
86
  for project in $PROJECTS; do
84
- dotnet test "$project" --no-build --configuration Release \
85
- --logger "trx;LogFileName=$(basename "$project").trx" \
86
- --results-directory "$RUNNER_TEMP/test-results" || failed=1
87
+ mkdir -p "$RUNNER_TEMP/test-results"
88
+ # xUnit v3 mtp-off example: resolve each project's actual AssemblyName/TFM.
89
+ "$project/bin/Release/net10.0/$(basename "$project")" \
90
+ -trx "$RUNNER_TEMP/test-results/$(basename "$project").trx" || failed=1
87
91
  done
88
92
  exit "$failed"
89
93
  - name: Verify every project ran tests
@@ -24,7 +24,7 @@ cost runner-minutes and developer trust; diagnose before retrying.
24
24
  ## Find hangs and crashes in .NET
25
25
 
26
26
  ```bash
27
- dotnet test Repo.slnx --configuration Release --no-build \
27
+ dotnet test VSTest.Specs.csproj --configuration Release --no-build \
28
28
  --blame-hang --blame-hang-timeout 5m --blame-hang-dump-type mini \
29
29
  --blame-crash --blame-crash-dump-type mini \
30
30
  --results-directory TestResults
@@ -32,7 +32,7 @@ Measure before guessing, with the language's profiler on the test process:
32
32
 
33
33
  ```bash
34
34
  dotnet tool install --global dotnet-trace
35
- dotnet-trace collect --format speedscope -- dotnet test Project.Specs --no-build --configuration Release
35
+ dotnet-trace collect --format speedscope -- ./<project-dir>/bin/Release/<TFM>/<AssemblyName>
36
36
  ```
37
37
 
38
38
  Read the inclusive time of the setup methods. Pass means the profile names the
@@ -81,7 +81,7 @@ Documentation-only changes use repository-supported non-release intent, ordinari
81
81
  Before marking code/automation work ready, select the affected-project gates that apply from the following list; run wider checks for cross-cutting changes and repository-required merge/release gates:
82
82
 
83
83
  - `dotnet build`: zero errors, zero warnings
84
- - `dotnet test`: all specs pass
84
+ - Built C# spec executables: all specs pass; `dotnet test <project> --no-build` only for VSTest (see specs.csharp)
85
85
  - `yarn lint`: zero errors
86
86
  - `npx tsc -b`: zero TypeScript errors
87
87
  - Code follows all project coding standards and conventions
@@ -81,8 +81,9 @@ a red run to discover the next failure.
81
81
 
82
82
  Several agents, worktrees or builds often share one machine. Keep it responsive:
83
83
 
84
- - Cap parallelism, for example `dotnet build -m:2`, `dotnet test -m:2` with the
85
- spec runner's thread limit, and `vitest run --maxWorkers=2`.
84
+ - Cap parallelism, for example `dotnet build -m:2`, built spec executables with their
85
+ runner-specific thread limit, and `vitest run --maxWorkers=2`. Do not pass MSBuild
86
+ `-m` to executables; `dotnet test <project> --no-build -m:2` is VSTest-only.
86
87
  - Run one heavy phase at a time (build, then specs, then frontend lint and
87
88
  tests), never several at once.
88
89
  - Do not start a heavy phase while another agent's runs in the same machine's
@@ -162,9 +162,13 @@ From the consumer root, with the printed NuGet environment sourced:
162
162
 
163
163
  ```bash
164
164
  dotnet build path/to/consumer.slnx -c Release -warnaserror
165
- dotnet test path/to/Integration.csproj -c Release --no-build --filter '<regression>'
165
+ ./<integration-project-dir>/bin/Release/<TFM>/<AssemblyName> <runner-specific-filter>
166
166
  ```
167
167
 
168
+ Resolve the integration project's actual built spec entrypoint and filter syntax with
169
+ [running-specs](../cratis-specifications-csharp/references/running-specs.md); without
170
+ apphost use `dotnet <TargetPath.dll>`. Only VSTest uses `dotnet test <project> -c Release
171
+ --no-build --filter '<regression>'`. Keep the sourced local NuGet environment.
168
172
  Substitute the repository's actual commands; for frontend fixes run build, lint,
169
173
  specs and the previously broken UI action. Pass: the reproducing spec/action now
170
174
  succeeds, at least one intended filtered spec actually ran, and the consumer's
@@ -50,10 +50,14 @@ step. Apply the entry point's check/restore/cleanup sequence to both repositorie
50
50
  export CHRONICLE_KERNEL_VERSION="$stamp"
51
51
  cd "$consumer"
52
52
  dotnet build path/to/Studio.slnx -c Release -p:StudioFullBuild=true -warnaserror
53
- dotnet test Source/Integrations/Specs/Specs.csproj -c Release --no-build \
54
- --filter '<regression>'
53
+ ./<integration-project-dir>/bin/Release/<TFM>/<AssemblyName> <runner-specific-filter>
55
54
  ```
56
55
 
56
+ Resolve the actual output and filter for `Source/Integrations/Specs/Specs.csproj`
57
+ via [running-specs](../../cratis-specifications-csharp/references/running-specs.md).
58
+ Without apphost use `dotnet <TargetPath.dll>`; only VSTest uses
59
+ `dotnet test <project> -c Release --no-build --filter '<regression>'`.
60
+ Inspect the current consumer workflow before claiming CI equivalence.
57
61
  Studio defaults kernel selection to the client version when the environment
58
62
  override is absent. Ensure logs show the stamped local image. Local Debug
59
63
  Studio builds skip analyzers; use `-p:StudioFullBuild=true` to match CI analyzer
@@ -83,9 +87,11 @@ bash "$local" use-nuget "$arc" "$stamp"
83
87
  Gates (Arc `dotnet-build.yml`), run in this order after sourcing the printed env:
84
88
  `yarn install --immutable`; in `Source/DotNET/Screenplay.Embedded`: `npm ci --workspaces=false`,
85
89
  `npm run typecheck`, `npm test`, `npm run build`; `dotnet build --configuration Release
86
- -p:CratisSpecsTargetFramework=net10.0`; then `dotnet test <project> --no-build --configuration
87
- Release --framework net10.0` for each project that `python3 scripts/ci-test-shards.py projects
88
- --shard specs-N` prints. Finish by listing Arc's `obj/project.assets.json` files for the stamp.
90
+ -p:CratisSpecsTargetFramework=net10.0`; then each project's evaluated Release/net10.0
91
+ spec executable (or `dotnet <TargetPath.dll>` without apphost) for each project that
92
+ `python3 scripts/ci-test-shards.py projects --shard specs-N` prints. Only identified
93
+ VSTest projects use `dotnet test <project> --no-build --configuration Release --framework
94
+ net10.0`. Inspect the current consumer workflow before claiming equivalence. Finish by listing Arc's `obj/project.assets.json` files for the stamp.
89
95
 
90
96
  - Pass: the Fundamentals IDs in `project.assets.json` are at the stamp, build has 0 warnings and 0 errors, 18 spec projects run and none fail.
91
97
  - Time: pack about 4 min, build about 6 min, the spec projects about 18 min.
@@ -134,9 +140,12 @@ bash "$local" use-nuget "$direct" "$stamp"
134
140
  ```
135
141
 
136
142
  Gates (Direct `build.yml`): `dotnet build Source/Direct/Direct.csproj -c Release
137
- -p:DisableProxyGenerator=true`, the same in Debug with `-warnaserror`, `dotnet test` of that
138
- project with `--no-build`, and `dotnet test Source/Assurance/Assurance.csproj`. Then
139
- check `project.assets.json`. Image-based specs also need the producer image tag.
143
+ -p:DisableProxyGenerator=true`, the same in Debug with `-warnaserror`, then the project's
144
+ verified built Debug spec entrypoint. Build `Source/Assurance/Assurance.csproj` in the
145
+ matching configuration and run its verified spec entrypoint too; do not guess assembly
146
+ names or start an application server. See [running-specs](../../cratis-specifications-csharp/references/running-specs.md);
147
+ only VSTest uses `dotnet test <project> --no-build` in that configuration. Inspect the
148
+ current consumer workflow before claiming equivalence. Then check `project.assets.json`. Image-based specs also need the producer image tag.
140
149
 
141
150
  - Pass for a consumer whose pins lag the producer: every Chronicle ID is in the feed at the
142
151
  stamp, the Release build with the owner's floors passes, and `project.assets.json` shows every
@@ -59,7 +59,7 @@ Cap export retries at five and surface the final failure.
59
59
 
60
60
  ## Verified facts (with evidence)
61
61
  - Cap and spec committed: `git log -1` shows the SHA above.
62
- - Spec project passes: `dotnet test Source/Export.Specs` exit 0 at that SHA.
62
+ - Spec project passes: `./Source/Export.Specs/bin/Debug/net10.0/Export.Specs` exit 0 at that SHA.
63
63
  - Pull request is open: `gh pr list --head export-retry` shows one entry; CI run
64
64
  `1234567890` is in progress.
65
65
 
@@ -60,12 +60,12 @@ C# rules.
60
60
  **Decisions already made:** the cap is five and is a constant, not
61
61
  configuration.
62
62
 
63
- **Gate command:** `dotnet test Source/Export.Specs`.
63
+ **Gate command:** `./Source/Export.Specs/bin/Debug/net10.0/Export.Specs`.
64
64
 
65
65
  **Done =**
66
66
  - [ ] A failing upload stops after five attempts and reports the error
67
67
  - [ ] A spec covers the fifth failure and a success on the third attempt
68
- - [ ] `dotnet test Source/Export.Specs` exits 0
68
+ - [ ] `./Source/Export.Specs/bin/Debug/net10.0/Export.Specs` exits 0
69
69
  - [ ] `git diff --stat` shows only the owned files
70
70
 
71
71
  **Stop and report if:** a public type must change, or another file needs edits.
@@ -95,7 +95,12 @@ another version behaves the same.
95
95
 
96
96
  ## When / when not
97
97
  - Use: "when X happens, then ...", schedules, retries, work queues, notifications, webhooks, APIs,
98
- files or message feeds, events imported from another context, legacy sync.
98
+ files or message feeds, events imported from another context, legacy sync, lifecycles and
99
+ longer processes.
100
+ - A lifecycle (where one thing is and what moves it on) is a `statemachine`; a process that
101
+ sends several commands, waits, asks for approval or gives up after a deadline is a
102
+ `workflow` (ESM v36). Read
103
+ [state machines and workflows](references/statemachines-and-workflows.md) before modeling either.
99
104
  - Not for: reaction, trigger or CDL grammar (`cratis-screenplay-captures-and-reactions`); stream
100
105
  identity and invariants (`cratis-screenplay-streams-and-consistency`); UI interactions such as
101
106
  `on click` (`cratis-screenplay-ui-composition`); hand-written reactors (`cratis-chronicle-reactor`).
@@ -13,7 +13,7 @@
13
13
  - 9. Fan-out
14
14
  - 10. Long-running process shapes
15
15
 
16
- Complete compiled example: `todo-list-example.md` (binds as ESM v6; the list query
16
+ Complete compiled example: `todo-list-example.md` (binds as ESM v34 for `then invokes`; the list query
17
17
  excerpt binds too, and the retry sweep that needs code is shown as a marked excerpt).
18
18
 
19
19
  ## 1. Deciding whether it is an automation
@@ -63,11 +63,11 @@ One spec in the slice does not cover the others.
63
63
  - Current admitted Automation/Translate specifications run through standalone
64
64
  `screenplay test` or MCP `run-specifications`. Validate/render alone is not V4;
65
65
  report unsupported/unbound separately from passing scenarios.
66
- - A command spec lists the cascade (v6 semantics: after
67
- `when <Command>`, `then` lists every new fact, including reaction appends). Only when the V1
68
- tool's compiler stops before v6 does it report a false PLAY0285 on a cascade:
69
- then keep the cascade out of the command spec, specify it in the Automation slice
70
- (`when append <Trigger>`) and record the expectation. See `cratis-screenplay-scenario-coverage`.
66
+ - A specification runs only its own slice (Screenplay decision 0115). A command spec
67
+ states the command's own events; the Automation states what its reaction appends in
68
+ its own `when append <Trigger>` spec, and a command it invokes in another slice with
69
+ `then invokes <Command>` (ESM v34). Another slice's event in a spec is PLAY0285
70
+ (unreachable). See `cratis-screenplay-scenario-coverage`.
71
71
  - `given capture` never persists between specs: state the baseline in each record
72
72
  update spec. First records (root, child, nested) are added only; field-change
73
73
  `and`/`or` and transitions need previous state. Expressions/maps/unguarded record
@@ -0,0 +1,164 @@
1
+ # State machines and workflows (ESM v36)
2
+
3
+ ## Contents
4
+
5
+ - Which construct
6
+ - Complete example
7
+ - Specifications
8
+ - Diagnostics and targets
9
+
10
+ Requires Screenplay 5.1.0 or later (`screenplay --version`). Sources: Screenplay
11
+ `Documentation/screenplay/statemachines.md`, `workflows.md` and decision 0124.
12
+
13
+ ## Which construct
14
+
15
+ | The domain says | Model |
16
+ | --- | --- |
17
+ | "When X happens, do Y", one step | An `Automation` slice with a reaction |
18
+ | Where one thing is in its lifecycle, and what moves it on | A `statemachine` that follows the thing's read model |
19
+ | A longer process: several commands, a choice, a wait for a fact or a person, a deadline, a fan-out | A `workflow` with one run per subject |
20
+
21
+ A state machine never decides on commands: it follows facts that already happened. Entering
22
+ a state may `send` a command or `start` a workflow; both may run again on redelivery, so the
23
+ command or workflow must be safe to repeat. A workflow is how a process waits, retries, asks
24
+ for approval and gives up; do not chain reactions across slices to imitate one.
25
+
26
+ Both are top-level declarations, siblings of `trigger` and `policy`. They name commands,
27
+ events, read models and personas declared in slices of any module. A model that declares one
28
+ selects ESM v36.
29
+
30
+ ## Complete example
31
+
32
+ This model compiles with `--warnaserror` and its three specifications pass with
33
+ `screenplay test`:
34
+
35
+ ```screenplay
36
+ concept InvoiceId : Uuid
37
+ persona FinanceController
38
+ module Billing
39
+ feature Invoices
40
+ slice StateChange SendInvoice
41
+ command SendInvoice
42
+ invoiceId InvoiceId identifier
43
+ produces event InvoiceSent
44
+ slice StateChange MarkOverdue
45
+ command MarkOverdue
46
+ invoiceId InvoiceId identifier
47
+ produces event InvoiceMarkedOverdue
48
+ slice StateChange PayInvoice
49
+ command PayInvoice
50
+ invoiceId InvoiceId identifier
51
+ produces event InvoicePaid
52
+ slice StateChange SendReminder
53
+ command SendReminder
54
+ invoiceId InvoiceId identifier
55
+ produces event ReminderSent
56
+ slice StateChange WriteOffInvoice
57
+ command WriteOffInvoice
58
+ invoiceId InvoiceId identifier
59
+ produces event InvoiceWrittenOff
60
+ slice StateView InvoiceStatus
61
+ readmodel Invoice
62
+ invoiceId InvoiceId key
63
+ status String
64
+ projection Invoices => Invoice
65
+ from InvoiceSent
66
+ invoiceId = $eventSourceId
67
+ status = "sent"
68
+ from InvoiceMarkedOverdue
69
+ status = "overdue"
70
+ from InvoicePaid
71
+ status = "paid"
72
+ query InvoiceById => Invoice optional
73
+ by invoiceId InvoiceId
74
+
75
+ statemachine InvoiceLifecycle
76
+ description "Where an invoice is, from sent to settled"
77
+ follows Invoice
78
+ state Sent initial
79
+ on InvoiceMarkedOverdue -> Overdue
80
+ on InvoicePaid -> Paid
81
+ state Overdue
82
+ entering start CollectOverdue
83
+ on InvoicePaid -> Paid
84
+ on InvoiceWrittenOff -> WrittenOff
85
+ state Paid final
86
+ state WrittenOff final
87
+
88
+ specification GoingOverdueStartsCollection
89
+ given InvoiceSent
90
+ for "9c858901-8a57-4791-81fe-4c455b099bc9"
91
+ when append InvoiceMarkedOverdue
92
+ for "9c858901-8a57-4791-81fe-4c455b099bc9"
93
+ then is Overdue
94
+ then starts CollectOverdue
95
+
96
+ workflow CollectOverdue
97
+ description "Reminds the customer, waits for payment and asks finance before writing off"
98
+ for Invoice
99
+ trigger when InvoiceLifecycle enters Overdue
100
+ -> Remind
101
+ action Remind sends SendReminder
102
+ next -> AwaitPayment
103
+ wait AwaitPayment for InvoicePaid expires after 14 days
104
+ expired -> ApproveWriteOff
105
+ approval ApproveWriteOff by FinanceController expires after 7 days
106
+ approved -> WriteOff
107
+ action WriteOff sends WriteOffInvoice
108
+
109
+ specification AnUnpaidInvoiceIsWrittenOff
110
+ given InvoiceSent
111
+ for "9c858901-8a57-4791-81fe-4c455b099bc9"
112
+ when append InvoiceMarkedOverdue
113
+ for "9c858901-8a57-4791-81fe-4c455b099bc9"
114
+ outcome AwaitPayment expired
115
+ outcome ApproveWriteOff approved
116
+ then sends SendReminder
117
+ then sends WriteOffInvoice
118
+ then completes
119
+
120
+ specification TheRunWaitsForPayment
121
+ given InvoiceSent
122
+ for "9c858901-8a57-4791-81fe-4c455b099bc9"
123
+ when append InvoiceMarkedOverdue
124
+ for "9c858901-8a57-4791-81fe-4c455b099bc9"
125
+ then sends SendReminder
126
+ then waits at AwaitPayment
127
+ ```
128
+
129
+ - `follows Invoice` / `for Invoice`: the read model whose key is one instance (one run per
130
+ invoice). A transition condition (`on E when <condition> -> S`) reads that read model after
131
+ the event; a condition over an optional property is refused at binding.
132
+ - Exactly one `initial` state; a `final` state has no transitions. An event takes the first
133
+ transition on it, in declaration order across the whole machine, whose condition holds and
134
+ whose target the current state allows. Anything else is ignored, not an error.
135
+ - Workflow nodes: `trigger` (`on <Event>`, `when <StateMachine> enters <State>`, `every`,
136
+ `at`, `manual`), `action <Name> sends <Command> [attempts n] [timeout] [retry after]`,
137
+ `decide <Name> when <condition>` with exactly two outlets, `wait` for an event or a
138
+ duration, `approval <Name> by <Persona or Policy>`, `foreach <Name> over <collection>` and
139
+ `join all|any|at least n`. Edges are `<outlet> -> <Node>` under their node.
140
+ - An unconnected negative outlet (`failed`, `rejected`, `expired`) fails the run; an
141
+ unconnected positive outlet ends that branch. Give every event wait and approval an
142
+ `expires after` (PLAY0849 warns otherwise).
143
+
144
+ ## Specifications
145
+
146
+ | Construct | Lines |
147
+ | --- | --- |
148
+ | `statemachine` | `given <Event>`, `when append <Event>`, `then is <State>`, `then sends <Command>`, `then starts <Workflow>` (every command and workflow, in order) |
149
+ | `workflow` | `given <Event>`, `when append <Event>` or `when start <key>`, `outcome <Node> <outlet>`, `then sends <Command>` (every one, in order), `then completes`, `then fails at <Node>`, `then waits at <Node>` |
150
+
151
+ The reference evaluator steps the run deterministically. A wait or approval with no stated
152
+ `outcome` suspends the run (`then waits at`); an action defaults to `next`; a wait for a
153
+ duration resumes at once.
154
+
155
+ ## Diagnostics and targets
156
+
157
+ - State machines: PLAY0834-PLAY0842 (missing or duplicate `initial` is PLAY0835, an
158
+ unreachable state warns PLAY0836, an undeclared reference is PLAY0840).
159
+ - Workflows: PLAY0843-PLAY0851 (no trigger is PLAY0844, a bad outlet PLAY0847, a decision
160
+ without exactly two outlets PLAY0848, an undeclared reference PLAY0851); PLAY0839 and
161
+ PLAY0841 are shared.
162
+ - Stage refuses ESM v36 models with `STAGE-ESM-016`; every other model renders as
163
+ before. The durable engine is Cratis.Orleans; its hosting and adapters are outside this
164
+ reference.
@@ -5,14 +5,15 @@
5
5
  - Design-only additions
6
6
 
7
7
  A complete model: a result opens a work item, a reaction invokes a command, the command's fact
8
- closes the item. It binds as ESM v6 (`executableReady: true`), standalone and through `cratis screenplay mcp`.
9
- Stage renders supported event reactions, but this model's clock/cascade specs remain
10
- refused (`-024`/`-011`); keep them intact. A compiler that stops before v6 rejects the
11
- Automation slice at binding with PLAY0285 or PLAY0268. Versions: `cratis-screenplay-toolchain` `SKILL.md`.
12
-
13
- The first spec lists the whole cascade (`then` names every new fact: `CoursePassed`, and
14
- `CertificateSent` through the reaction), and `given clock` supplies the instant that
15
- `$context.occurred` needs. Both tools accept that cascade when they admit v6; an older compiler reports a false PLAY0285 on it.
8
+ closes the item. `then invokes` selects ESM v34 (`executableReady: true` from Screenplay 4.246.0),
9
+ standalone and through `cratis screenplay mcp`. The Stage spec runner compares `then invokes`, but the
10
+ Cratis renderer refuses models after v33 with `STAGE-ESM-016`; keep the specifications intact. A compiler
11
+ that stops before v34 refuses `then invokes`. Versions: `cratis-screenplay-toolchain` `SKILL.md`.
12
+
13
+ Each specification states only its own slice (Screenplay decision 0115): `RecordingAPass`
14
+ states `CoursePassed`, `SendingAfterAPass` states the hand-over with `then invokes
15
+ SendCertificate` (ESM v34), and `SendingACertificate` states `CertificateSent`. `given clock`
16
+ supplies the instant that `$context.occurred` needs.
16
17
  Current admitted scenarios can be run with
17
18
  standalone `screenplay test` or MCP `run-specifications`.
18
19
 
@@ -58,7 +59,7 @@ module Courses
58
59
  CoursePassed
59
60
  for enrolmentId
60
61
  enrolmentId = enrolmentId // copied on purpose: the reaction selects it as a value
61
- completedAt = $context.occurred // carried on the fact: a projection cannot read $eventContext.occurred
62
+ completedAt = $context.occurred // carried on the fact, so every reader sees the same instant
62
63
  produces when passed == false
63
64
  CourseFailed
64
65
  for enrolmentId
@@ -81,9 +82,6 @@ module Courses
81
82
  for "0d3b9e2a-6c4f-4f1e-8b7a-5e2d1c3b4a01"
82
83
  enrolmentId = "0d3b9e2a-6c4f-4f1e-8b7a-5e2d1c3b4a01"
83
84
  completedAt = "2026-10-05T08:00:00Z"
84
- then CertificateSent
85
- for "0d3b9e2a-6c4f-4f1e-8b7a-5e2d1c3b4a01"
86
- sentAt = "2026-10-05T08:00:00Z"
87
85
  specification RefusingANonCoordinator
88
86
  given caller
89
87
  authenticated
@@ -180,9 +178,8 @@ module Certification
180
178
  for "0d3b9e2a-6c4f-4f1e-8b7a-5e2d1c3b4a01"
181
179
  enrolmentId = "0d3b9e2a-6c4f-4f1e-8b7a-5e2d1c3b4a01"
182
180
  completedAt = "2026-10-05T08:00:00Z"
183
- then CertificateSent
184
- for "0d3b9e2a-6c4f-4f1e-8b7a-5e2d1c3b4a01"
185
- sentAt = "2026-10-05T08:00:00Z"
181
+ then invokes SendCertificate
182
+ enrolmentId = "0d3b9e2a-6c4f-4f1e-8b7a-5e2d1c3b4a01"
186
183
  ```
187
184
 
188
185
  ## Design-only additions
@@ -93,9 +93,6 @@ module Exams
93
93
  for "7e9d1c2b-4a3f-4e5d-8c6b-1a2b3c4d5e06"
94
94
  outcome = "passed"
95
95
  score = 87
96
- then ExamPassed
97
- for "7e9d1c2b-4a3f-4e5d-8c6b-1a2b3c4d5e06"
98
- score = 87
99
96
  slice Automation RecordExamResult
100
97
  reaction PassTranslator
101
98
  when ProctorResultReceived
@@ -115,6 +112,14 @@ module Exams
115
112
  constraint OneResultPerAttempt
116
113
  unique event ExamPassed
117
114
  unique event ExamFailed
115
+ specification RecordingAPass
116
+ when append ProctorResultReceived
117
+ for "7e9d1c2b-4a3f-4e5d-8c6b-1a2b3c4d5e06"
118
+ outcome = "passed"
119
+ score = 87
120
+ then ExamPassed
121
+ for "7e9d1c2b-4a3f-4e5d-8c6b-1a2b3c4d5e06"
122
+ score = 87
118
123
  specification RefusingASecondResult
119
124
  given ExamPassed
120
125
  for "7e9d1c2b-4a3f-4e5d-8c6b-1a2b3c4d5e06"
@@ -131,7 +136,8 @@ module Exams
131
136
  - Keep the capture and its appended event in Translate; put reactions to that local
132
137
  event in a separate Automation. Co-location in a directionless Translate warns
133
138
  PLAY0694 and fails `--warnaserror`; explicit inbound refuses it with PLAY0616.
134
- `then` lists every new fact, so `TranslatingAPass` includes the Automation result.
139
+ A specification runs only its own slice (Screenplay decision 0115), so `TranslatingAPass`
140
+ states the Translate slice's fact and `RecordingAPass` states the Automation's result.
135
141
  - `when added` records first sight; the separate `when outcome` append handles
136
142
  later changes. For an update spec, seed the same reference with `given capture`.
137
143
  Requires Screenplay 4.175.0 or later (`screenplay --version`); older evaluators
@@ -289,8 +289,8 @@ module Collections
289
289
  when trigger PaymentFileArrived
290
290
  invoiceId = "9c858901-8a57-4791-81fe-4c455b099bc9"
291
291
  amount = 120
292
- then InvoiceClosed
293
- for "9c858901-8a57-4791-81fe-4c455b099bc9"
292
+ then invokes CloseInvoice
293
+ invoiceId = "9c858901-8a57-4791-81fe-4c455b099bc9"
294
294
  reason = "paid"
295
295
  specification IssuingTheWeeklyDigest
296
296
  given clock "2026-10-05T07:00:00Z"
@@ -54,10 +54,16 @@ module Work
54
54
  specification ProcessingRequestedWork
55
55
  when append WorkRequested
56
56
  workId = "work-1"
57
- then WorkRecorded
58
- for "work-1"
57
+ then invokes RecordWork
58
+ workId = "work-1"
59
59
  ```
60
60
 
61
+ The automation states the hand-over with `then invokes` (ESM v34). `RecordWork` is
62
+ decided under the declared system identity, so a denial would reach the reaction's
63
+ refusal branches, but `WorkRecorded` belongs to the `RecordWork` slice and is not kept
64
+ in this specification (Screenplay decision 0115). `RecordWork`'s own slice proves the
65
+ event with a `when RecordWork` specification.
66
+
61
67
  ## Diagnostics and target boundaries
62
68
 
63
69
  - PLAY0647: malformed, repeated or misplaced identity, including duplicate/empty roles.