@cratis/pi 7.34.0 → 7.35.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 (241) hide show
  1. package/package/corpus/agents/security-reviewer.md +1 -0
  2. package/package/corpus/agents/spec-writer.md +1 -1
  3. package/package/corpus/harnesses/pi/extensions/shared/rules.ts +3 -1
  4. package/package/corpus/hooks/scripts/cratis-nuget-pins.txt +7 -6
  5. package/package/corpus/hooks/scripts/cratis-release-notes-reviewed.cjs +7 -6
  6. package/package/corpus/hooks/scripts/cratis-store-mutations.json +7 -3
  7. package/package/corpus/product-sync.json +896 -0
  8. package/package/corpus/prompts/add-business-rule.prompt.md +1 -1
  9. package/package/corpus/prompts/ship-changes.prompt.md +2 -2
  10. package/package/corpus/rules/ai-distribution.md +31 -3
  11. package/package/corpus/rules/application-profile.md +2 -1
  12. package/package/corpus/rules/components.md +66 -7
  13. package/package/corpus/rules/concepts.md +11 -3
  14. package/package/corpus/rules/csharp.md +3 -1
  15. package/package/corpus/rules/dialogs.md +9 -0
  16. package/package/corpus/rules/efcore.md +1 -1
  17. package/package/corpus/rules/elixir.md +49 -0
  18. package/package/corpus/rules/framework.md +5 -3
  19. package/package/corpus/rules/general.md +1 -0
  20. package/package/corpus/rules/glossary.md +4 -4
  21. package/package/corpus/rules/go-engineering.md +60 -0
  22. package/package/corpus/rules/go.md +115 -0
  23. package/package/corpus/rules/java.md +5 -2
  24. package/package/corpus/rules/kotlin.md +7 -5
  25. package/package/corpus/rules/orleans.md +65 -9
  26. package/package/corpus/rules/profiles.md +43 -6
  27. package/package/corpus/rules/pull-requests.md +3 -3
  28. package/package/corpus/rules/react.md +8 -1
  29. package/package/corpus/rules/reactors.md +27 -3
  30. package/package/corpus/rules/specs.csharp.md +11 -4
  31. package/package/corpus/rules/specs.scenarios.csharp.md +35 -4
  32. package/package/corpus/rules/specs.typescript.md +2 -1
  33. package/package/corpus/rules/storybook.md +1 -1
  34. package/package/corpus/rules/typescript.md +1 -1
  35. package/package/corpus/rules/vertical-slices.md +37 -5
  36. package/package/corpus/skills/cratis-application-react-specifications/SKILL.md +4 -2
  37. package/package/corpus/skills/cratis-application-slice-specifications/SKILL.md +18 -8
  38. package/package/corpus/skills/cratis-application-slice-specifications/references/query-and-decision-scenarios.md +65 -0
  39. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/SKILL.md +53 -57
  40. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/authentication.md +38 -42
  41. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/authorization.md +18 -7
  42. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/authproxy.md +30 -0
  43. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/frontend.md +12 -9
  44. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/local-development.md +9 -9
  45. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/observable-emission-guards.md +8 -5
  46. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/tenancy.md +20 -4
  47. package/package/corpus/skills/cratis-arc-command/SKILL.md +32 -10
  48. package/package/corpus/skills/cratis-arc-command/references/command-result.md +12 -5
  49. package/package/corpus/skills/cratis-arc-command/references/decisions-and-routing.md +95 -0
  50. package/package/corpus/skills/cratis-arc-command/references/generated-values.md +3 -2
  51. package/package/corpus/skills/cratis-arc-command/references/handler-shapes.md +8 -8
  52. package/package/corpus/skills/cratis-arc-command/references/proxy-generation.md +22 -3
  53. package/package/corpus/skills/cratis-arc-command/references/read-model-injection.md +13 -1
  54. package/package/corpus/skills/cratis-arc-command-execution/SKILL.md +19 -9
  55. package/package/corpus/skills/cratis-arc-command-kotlin/SKILL.md +44 -18
  56. package/package/corpus/skills/cratis-arc-command-kotlin/references/read-model-naming.md +29 -0
  57. package/package/corpus/skills/cratis-arc-command-operation/SKILL.md +10 -9
  58. package/package/corpus/skills/cratis-arc-command-operation/references/execution-and-recovery.md +2 -2
  59. package/package/corpus/skills/cratis-arc-command-operation/references/testing.md +4 -3
  60. package/package/corpus/skills/cratis-arc-command-typescript/SKILL.md +42 -22
  61. package/package/corpus/skills/cratis-arc-command-typescript/references/chronicle-events.md +36 -5
  62. package/package/corpus/skills/cratis-arc-command-typescript/references/command-operations.md +114 -0
  63. package/package/corpus/skills/cratis-arc-command-typescript/references/hosting-and-storage.md +37 -16
  64. package/package/corpus/skills/cratis-arc-command-typescript/references/identity-and-introspection.md +88 -0
  65. package/package/corpus/skills/cratis-arc-command-typescript/references/observability-and-host-scopes.md +25 -0
  66. package/package/corpus/skills/cratis-arc-command-typescript/references/proxy-generation.md +35 -4
  67. package/package/corpus/skills/cratis-arc-command-typescript/references/slice-layout.md +11 -0
  68. package/package/corpus/skills/cratis-arc-command-typescript/verification.json +8 -1
  69. package/package/corpus/skills/cratis-arc-command-validation/SKILL.md +49 -19
  70. package/package/corpus/skills/cratis-arc-ef-core-migration/SKILL.md +12 -6
  71. package/package/corpus/skills/cratis-arc-go/SKILL.md +148 -0
  72. package/package/corpus/skills/cratis-arc-go/references/queries.md +80 -0
  73. package/package/corpus/skills/cratis-arc-hosting/SKILL.md +96 -0
  74. package/package/corpus/skills/cratis-arc-hosting/references/integrations-and-publish.md +80 -0
  75. package/package/corpus/skills/cratis-arc-identity-and-tenancy-kotlin/SKILL.md +137 -0
  76. package/package/corpus/skills/cratis-arc-observable-query-http/SKILL.md +20 -2
  77. package/package/corpus/skills/cratis-arc-query-kotlin/SKILL.md +26 -6
  78. package/package/corpus/skills/cratis-arc-query-paging/SKILL.md +25 -20
  79. package/package/corpus/skills/cratis-arc-query-typescript/SKILL.md +32 -6
  80. package/package/corpus/skills/cratis-arc-query-typescript/references/storage-observation-and-compliance.md +66 -0
  81. package/package/corpus/skills/cratis-arc-query-typescript/verification.json +5 -1
  82. package/package/corpus/skills/cratis-arc-react-page/SKILL.md +24 -13
  83. package/package/corpus/skills/cratis-arc-react-page/references/data-page.md +20 -10
  84. package/package/corpus/skills/cratis-arc-react-page/references/data-tables.md +17 -3
  85. package/package/corpus/skills/cratis-arc-react-page/references/dialogs.md +14 -3
  86. package/package/corpus/skills/cratis-arc-react-page/references/from-screenplay.md +6 -1
  87. package/package/corpus/skills/cratis-arc-react-page/references/provenance.md +1 -1
  88. package/package/corpus/skills/cratis-arc-react-page/references/queries-and-commands.md +11 -1
  89. package/package/corpus/skills/cratis-arc-react-page/verification.json +6 -1
  90. package/package/corpus/skills/cratis-arc-spring-data-kotlin/SKILL.md +163 -0
  91. package/package/corpus/skills/cratis-arc-testing-kotlin/SKILL.md +131 -0
  92. package/package/corpus/skills/cratis-arc-validation-kotlin/SKILL.md +44 -11
  93. package/package/corpus/skills/cratis-arc-validation-typescript/SKILL.md +5 -3
  94. package/package/corpus/skills/cratis-chronicle-cli-operations/SKILL.md +79 -25
  95. package/package/corpus/skills/cratis-chronicle-cli-operations/references/command-effects.md +57 -0
  96. package/package/corpus/skills/cratis-chronicle-client-dotnet/SKILL.md +87 -99
  97. package/package/corpus/skills/cratis-chronicle-client-dotnet/references/additional-surfaces.md +65 -0
  98. package/package/corpus/skills/cratis-chronicle-client-dotnet/references/client-construction.md +42 -0
  99. package/package/corpus/skills/cratis-chronicle-client-dotnet/references/compatibility-check.md +12 -0
  100. package/package/corpus/skills/cratis-chronicle-client-dotnet/references/discovery.md +43 -19
  101. package/package/corpus/skills/cratis-chronicle-client-dotnet/references/hosting.md +29 -1
  102. package/package/corpus/skills/cratis-chronicle-client-elixir/SKILL.md +158 -162
  103. package/package/corpus/skills/cratis-chronicle-client-elixir/references/append-api.md +36 -15
  104. package/package/corpus/skills/cratis-chronicle-client-elixir/references/compliance.md +32 -0
  105. package/package/corpus/skills/cratis-chronicle-client-elixir/references/connections.md +56 -0
  106. package/package/corpus/skills/cratis-chronicle-client-elixir/references/event-sources.md +64 -0
  107. package/package/corpus/skills/cratis-chronicle-client-elixir/references/pitfalls.md +25 -0
  108. package/package/corpus/skills/cratis-chronicle-client-elixir/references/projections.md +48 -0
  109. package/package/corpus/skills/cratis-chronicle-client-elixir/references/upgrading.md +34 -0
  110. package/package/corpus/skills/cratis-chronicle-client-elixir/references/variants.md +13 -5
  111. package/package/corpus/skills/cratis-chronicle-client-elixir/verification.json +23 -0
  112. package/package/corpus/skills/cratis-chronicle-client-go/SKILL.md +162 -0
  113. package/package/corpus/skills/cratis-chronicle-client-go/references/projections.md +73 -0
  114. package/package/corpus/skills/cratis-chronicle-client-kotlin/SKILL.md +87 -88
  115. package/package/corpus/skills/cratis-chronicle-client-kotlin/references/connection-lifecycle.md +13 -0
  116. package/package/corpus/skills/cratis-chronicle-client-kotlin/references/discovery-and-registration.md +14 -4
  117. package/package/corpus/skills/cratis-chronicle-client-kotlin/references/event-sources.md +65 -0
  118. package/package/corpus/skills/cratis-chronicle-client-kotlin/references/options.md +29 -0
  119. package/package/corpus/skills/cratis-chronicle-client-kotlin/references/spring-boot.md +13 -0
  120. package/package/corpus/skills/cratis-chronicle-client-kotlin/references/variants.md +5 -4
  121. package/package/corpus/skills/cratis-chronicle-client-typescript/SKILL.md +165 -156
  122. package/package/corpus/skills/cratis-chronicle-client-typescript/references/read-models-and-projections.md +54 -11
  123. package/package/corpus/skills/cratis-chronicle-client-typescript/references/testing.md +126 -0
  124. package/package/corpus/skills/cratis-chronicle-client-typescript/references/variants.md +3 -5
  125. package/package/corpus/skills/cratis-chronicle-client-typescript/verification.json +19 -0
  126. package/package/corpus/skills/cratis-chronicle-compliance/SKILL.md +36 -13
  127. package/package/corpus/skills/cratis-chronicle-decision-reads/SKILL.md +110 -0
  128. package/package/corpus/skills/cratis-chronicle-decision-reads/references/admission-and-ownership.md +57 -0
  129. package/package/corpus/skills/cratis-chronicle-decision-reads/verification.json +12 -0
  130. package/package/corpus/skills/cratis-chronicle-event-constraints/SKILL.md +58 -19
  131. package/package/corpus/skills/cratis-chronicle-event-constraints/references/closing-streams.md +73 -0
  132. package/package/corpus/skills/cratis-chronicle-event-modeling/SKILL.md +32 -3
  133. package/package/corpus/skills/cratis-chronicle-event-specifications/SKILL.md +18 -5
  134. package/package/corpus/skills/cratis-chronicle-event-type-migration/SKILL.md +32 -2
  135. package/package/corpus/skills/cratis-chronicle-hosting/SKILL.md +134 -0
  136. package/package/corpus/skills/cratis-chronicle-hosting/references/operations.md +89 -0
  137. package/package/corpus/skills/cratis-chronicle-hosting/verification.json +14 -0
  138. package/package/corpus/skills/cratis-chronicle-mcp-inspection/SKILL.md +93 -66
  139. package/package/corpus/skills/cratis-chronicle-mcp-inspection/references/blocked-tools.md +21 -7
  140. package/package/corpus/skills/cratis-chronicle-mcp-inspection/references/deployment.md +77 -0
  141. package/package/corpus/skills/cratis-chronicle-mcp-inspection/references/observational-tools.md +46 -4
  142. package/package/corpus/skills/cratis-chronicle-multi-tenancy/SKILL.md +15 -1
  143. package/package/corpus/skills/cratis-chronicle-projection/SKILL.md +44 -10
  144. package/package/corpus/skills/cratis-chronicle-projection/references/fluent-builder.md +7 -1
  145. package/package/corpus/skills/cratis-chronicle-projection/references/model-bound-attributes.md +8 -0
  146. package/package/corpus/skills/cratis-chronicle-reactor/SKILL.md +85 -105
  147. package/package/corpus/skills/cratis-chronicle-reactor/references/slice-delivery-checklist.md +1 -1
  148. package/package/corpus/skills/cratis-chronicle-reactor/references/specifications.md +20 -1
  149. package/package/corpus/skills/cratis-chronicle-read-model/SKILL.md +2 -2
  150. package/package/corpus/skills/cratis-chronicle-read-model/references/queries.md +35 -16
  151. package/package/corpus/skills/cratis-chronicle-read-model-specifications/SKILL.md +15 -3
  152. package/package/corpus/skills/cratis-chronicle-reducer/SKILL.md +23 -4
  153. package/package/corpus/skills/cratis-chronicle-web-workbench/SKILL.md +40 -15
  154. package/package/corpus/skills/cratis-cli-terminal-workbench/SKILL.md +20 -6
  155. package/package/corpus/skills/cratis-code-review/SKILL.md +25 -3
  156. package/package/corpus/skills/cratis-components-accessibility/SKILL.md +20 -4
  157. package/package/corpus/skills/cratis-components-schema-editor/SKILL.md +40 -28
  158. package/package/corpus/skills/cratis-components-schema-editor/references/tree-layout.md +62 -0
  159. package/package/corpus/skills/cratis-components-schema-editor/verification.json +14 -0
  160. package/package/corpus/skills/cratis-components-stepper-command-dialog/SKILL.md +16 -8
  161. package/package/corpus/skills/cratis-components-styling/SKILL.md +57 -20
  162. package/package/corpus/skills/cratis-components-styling/verification.json +13 -0
  163. package/package/corpus/skills/cratis-components-toolbar/SKILL.md +37 -7
  164. package/package/corpus/skills/cratis-components-toolbar/verification.json +12 -0
  165. package/package/corpus/skills/cratis-engineering-csharp-conventions/SKILL.md +6 -0
  166. package/package/corpus/skills/cratis-engineering-csharp-conventions/references/exceptions-logging-and-di.md +5 -3
  167. package/package/corpus/skills/cratis-fundamentals-concept/SKILL.md +19 -6
  168. package/package/corpus/skills/cratis-fundamentals-concept/references/typescript-concepts.md +97 -0
  169. package/package/corpus/skills/cratis-fundamentals-concept/verification.json +4 -1
  170. package/package/corpus/skills/cratis-fundamentals-concept-go/SKILL.md +112 -0
  171. package/package/corpus/skills/cratis-fundamentals-type-discovery/SKILL.md +54 -17
  172. package/package/corpus/skills/cratis-fundamentals-type-discovery/verification.json +14 -0
  173. package/package/corpus/skills/cratis-lens-browser-extension/SKILL.md +55 -28
  174. package/package/corpus/skills/cratis-performance-review/SKILL.md +5 -2
  175. package/package/corpus/skills/cratis-release-notes/SKILL.md +3 -1
  176. package/package/corpus/skills/cratis-screenplay-automations-and-translations/SKILL.md +5 -4
  177. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/realization-and-gap-fill.md +1 -1
  178. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/SKILL.md +1 -1
  179. package/package/corpus/skills/cratis-screenplay-command-surface/SKILL.md +5 -6
  180. package/package/corpus/skills/cratis-screenplay-command-surface/references/compliance.md +25 -7
  181. package/package/corpus/skills/cratis-screenplay-command-surface/references/enum-numbers.md +4 -2
  182. package/package/corpus/skills/cratis-screenplay-command-surface/references/generated-values-and-responses.md +4 -1
  183. package/package/corpus/skills/cratis-screenplay-event-modeling/SKILL.md +4 -3
  184. package/package/corpus/skills/cratis-screenplay-event-modeling/references/nine-steps.md +1 -1
  185. package/package/corpus/skills/cratis-screenplay-event-modeling/references/parsed-not-runnable.md +2 -2
  186. package/package/corpus/skills/cratis-screenplay-legacy-extraction/SKILL.md +3 -2
  187. package/package/corpus/skills/cratis-screenplay-legacy-extraction/references/generate-notes.md +34 -4
  188. package/package/corpus/skills/cratis-screenplay-model-authoring/SKILL.md +5 -3
  189. package/package/corpus/skills/cratis-screenplay-model-authoring/references/language-reference.md +1 -1
  190. package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-tools.md +4 -2
  191. package/package/corpus/skills/cratis-screenplay-model-authoring/references/property-links.md +42 -3
  192. package/package/corpus/skills/cratis-screenplay-model-authoring/verification.json +3 -1
  193. package/package/corpus/skills/cratis-screenplay-modeling-lifecycle/references/vocabulary-map.md +2 -2
  194. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/SKILL.md +6 -6
  195. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/drift-and-ledger.md +1 -1
  196. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/gap-fill-handoff.md +6 -4
  197. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/renderability-gate.md +1 -1
  198. package/package/corpus/skills/cratis-screenplay-scenario-coverage/SKILL.md +3 -1
  199. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/invoicing-dues-design.md +1 -1
  200. package/package/corpus/skills/cratis-screenplay-slice-design/SKILL.md +1 -1
  201. package/package/corpus/skills/cratis-screenplay-slice-design/references/rule-layers.md +2 -2
  202. package/package/corpus/skills/cratis-screenplay-slice-design/references/worked-example.md +1 -1
  203. package/package/corpus/skills/cratis-screenplay-specifications/references/examples-and-routes.md +48 -0
  204. package/package/corpus/skills/cratis-screenplay-specifications/verification.json +3 -1
  205. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/SKILL.md +7 -5
  206. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/chronicle-boundaries.md +2 -2
  207. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/consistency-and-concurrency.md +2 -2
  208. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/streams-example.md +5 -4
  209. package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +8 -6
  210. package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet-example.md +2 -2
  211. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +4 -2
  212. package/package/corpus/skills/cratis-screenplay-toolchain/references/doc-contradictions.md +1 -1
  213. package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +16 -11
  214. package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +8 -5
  215. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.json +1329 -32
  216. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.version +1 -1
  217. package/package/corpus/skills/cratis-screenplay-toolchain/references/verdicts.md +2 -2
  218. package/package/corpus/skills/cratis-screenplay-toolchain/references/versions.md +23 -7
  219. package/package/corpus/skills/cratis-screenplay-toolchain/verification.json +1 -1
  220. package/package/corpus/skills/cratis-screenplay-ui-composition/SKILL.md +2 -0
  221. package/package/corpus/skills/cratis-screenplay-ui-composition/references/screen-composition-contract.md +27 -9
  222. package/package/corpus/skills/cratis-security-review/SKILL.md +9 -3
  223. package/package/corpus/skills/cratis-security-review/references/arc-boundaries.md +59 -0
  224. package/package/corpus/skills/cratis-specification-by-example/SKILL.md +7 -0
  225. package/package/corpus/skills/cratis-specifications-csharp/SKILL.md +43 -11
  226. package/package/corpus/skills/cratis-specifications-csharp/references/application-scenarios.md +16 -4
  227. package/package/corpus/skills/cratis-specifications-csharp/references/csharp-patterns.md +18 -5
  228. package/package/corpus/skills/cratis-specifications-csharp/references/integration-specs.md +21 -0
  229. package/package/corpus/skills/cratis-specifications-csharp/references/shared-lifecycle.md +34 -0
  230. package/package/corpus/skills/cratis-specifications-csharp/verification.json +13 -0
  231. package/package/corpus/skills/cratis-specifications-typescript/SKILL.md +14 -5
  232. package/package/corpus/skills/cratis-specifications-typescript/verification.json +12 -0
  233. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +11 -5
  234. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +7 -4
  235. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/rendered-application.md +10 -1
  236. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/scene-runtime.md +75 -0
  237. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/verification.json +6 -1
  238. package/package/corpus/skills/cratis-studio-mcp-safety-guidance/SKILL.md +14 -1
  239. package/package/profile-catalog.json +68 -1
  240. package/package.json +1 -1
  241. package/src/index.ts +3 -1
@@ -19,10 +19,6 @@ effects. If the answer is "populate a queryable model", it is not a reactor.
19
19
  | record data from an outside system or service as our own facts | an adapter at the boundary, often a reactor (**translation**) |
20
20
  | both a model and an effect | one projection *and* one reactor |
21
21
 
22
- A reactor is an **automation** when it answers one of our own events, whatever it
23
- causes. It is the adapter side of a **translation** only when its input is
24
- outside data that becomes our own facts.
25
-
26
22
  > **Model first.** If an accepted model under the model root covers this scope, or
27
23
  > the repository is opted in (the root, the folder holding the project's `.play` files, holds a
28
24
  > committed `.play` file (`git ls-tree -r --name-only HEAD` lists a `.play` file there, narrowed to `-- <root>` when a root is configured), or the project explicitly set `mcpServers.screenplay.root` in
@@ -42,20 +38,16 @@ This skill is verified against these exact sources:
42
38
 
43
39
  | Package | Version | Purpose |
44
40
  | --- | --- | --- |
45
- | `Cratis.Chronicle` | `18.3.0` | `Cratis.Chronicle.Reactors`, `Cratis.Chronicle.Reactors.SideEffects`, `Cratis.Chronicle.EventSequences`, `Cratis.Chronicle.Events` |
46
- | `Cratis.Chronicle.CodeAnalysis` | `18.3.0` | `CHR0004`, `CHR0005`, `CHR0008`, `CHR0013`, `CHR0022`, `CHR0031`, `CHR0032` |
41
+ | `Cratis.Chronicle` | `19.50.1` | `Cratis.Chronicle.Reactors`, `Cratis.Chronicle.Reactors.SideEffects`, `Cratis.Chronicle.EventSequences`, `Cratis.Chronicle.Events` |
42
+ | `Cratis.Chronicle.CodeAnalysis` | `19.50.1` | handler, side-effect and filter diagnostics, including CHR0054–CHR0056 |
47
43
 
48
- Scenario read-model seeding/absence, synchronous handler exception propagation,
49
- and the `EventContext.From` UTC default are verified separately at **Chronicle
50
- 19.46.0**; they require **19.46.0+**. See the source paths in
51
- [references/specifications.md](references/specifications.md).
44
+ Scenario guards began in **19.46.0**, reverified at **19.50.0**;
45
+ see [specifications](references/specifications.md).
52
46
 
53
47
  Reverify product sources before claiming support for another version.
54
48
 
55
- > **There is no `ReactorSideEffect` type.** It does not exist in Chronicle, in
56
- > any version. The real return types are listed below; the per-event metadata
57
- > control it was imagined to provide is what `EventForEventSourceId` actually
58
- > gives you. Never write it into code or an example.
49
+ > **There is no `ReactorSideEffect` type.** Use the supported return types below;
50
+ > `EventForEventSourceId` supplies per-event metadata.
59
51
 
60
52
  ## Write the reactor
61
53
 
@@ -85,8 +77,7 @@ and plays no part. When two methods claim the same event type, the winner is
85
77
  chosen by public before non-public, then more parameters before fewer, then
86
78
  ordinal name order — so do not rely on it; write one handler per event type.
87
79
 
88
- A handler takes **at least one** parameter. There is no upper limit. Everything
89
- after the first is resolved by type, position-independently:
80
+ A handler takes at least one parameter. Further parameters resolve by type:
90
81
 
91
82
  | Parameter type | Resolved as |
92
83
  | --- | --- |
@@ -95,13 +86,10 @@ after the first is resolved by type, position-independently:
95
86
  | a type that has a projection or a reducer | that **read model**, materialized for this event |
96
87
  | anything else | from the service provider |
97
88
 
98
- An unresolvable parameter throws at invocation, and analyzer **CHR0004**
99
- (warning) flags it at build time: after the event, a reactor method may take the
100
- event context, a read model, or a service — not a primitive, a value type, or a
101
- string.
89
+ An unresolvable parameter throws. CHR0004 warns against primitive, value-type
90
+ or string dependencies after the event: use context, a read model or a service.
102
91
 
103
- The first parameter's type must carry `[EventType]`, or analyzer **CHR0005**
104
- (error) rejects it.
92
+ The first parameter must carry `[EventType]` (CHR0005 error).
105
93
 
106
94
  ### Injecting a read model
107
95
 
@@ -121,17 +109,13 @@ public class <ReactorName> : IReactor, ICanResolveReadModelKey
121
109
  }
122
110
  ```
123
111
 
124
- The resolved key applies to every read-model parameter across all of the
125
- reactor's handlers.
112
+ The resolved key applies to every read-model parameter on the reactor.
126
113
 
127
- A **materialized** read model is read from its sink, so it is eventually
128
- consistent — as current as its own observer. Mark the read model `[Passive]` when
129
- the reactor needs it strongly consistent: a passive model has no sink and is
130
- computed on demand at the point the reactor runs.
114
+ Materialized models are as current as their observer. `[Passive]` computes
115
+ on demand without a sink when the reactor needs a current read.
131
116
 
132
- Prefer the event's own data. Analyzer **CHR0032** (warning) rejects injecting a
133
- storage primitive such as `IMongoCollection<T>` directly — read keyed state
134
- through a read-model parameter or `IReadModels.GetInstanceById` instead.
117
+ Prefer the event's own data. CHR0032 warns against injected storage primitives such as `IMongoCollection<T>`;
118
+ read keyed state through read-model parameters or `IReadModels.GetInstanceById`.
135
119
 
136
120
  ## Return types
137
121
 
@@ -147,15 +131,18 @@ through a read-model parameter or `IReadModels.GetInstanceById` instead.
147
131
  A collection may **mix** bare events and `EventForEventSourceId` items; each is
148
132
  appended with its own metadata, all in one transaction.
149
133
 
150
- A custom side-effect type handled by your own `IReactorSideEffectHandler` is
151
- only recognised when returned as `Task<T>`.
134
+ Arrays and lists of registered events or `EventForEventSourceId` are also valid
135
+ synchronous returns. Custom `IReactorSideEffectHandler` implementations can
136
+ claim synchronous types through `CanHandleReturnType(Type)`; they are not
137
+ restricted to `Task<T>`. An unclaimed return value **fails the partition** with
138
+ `UnhandledReactorReturnValue`, naming its type. CHR0054 flags an unsupported
139
+ return type at build time. Source at v19.50.0: `Reactors/EventHandlerMethods.cs`,
140
+ `Reactors/SideEffects/IReactorSideEffectHandler.cs`, `Reactors/UnhandledReactorReturnValue.cs`.
152
141
 
153
142
  ### Returning events instead of injecting `IEventLog`
154
143
 
155
- Return the events. Do not inject `Cratis.Chronicle.EventSequences.IEventLog` into
156
- a reactor. **This is a convention, not a framework contract** — no analyzer
157
- enforces it — but returning the events keeps the reactor free of the event store
158
- and keeps the append inside Chronicle's own transaction.
144
+ Return events rather than inject `IEventLog`: **a convention, not an analyzer
145
+ contract**. Returned appends stay inside Chronicle's transaction.
159
146
 
160
147
  ```csharp
161
148
  // One event, on the triggering event's own event source.
@@ -169,20 +156,12 @@ public Task<IEnumerable<object>> <MethodName>(<EventName> @event, EventContext c
169
156
 
170
157
  ### Targeting another event source
171
158
 
172
- `Cratis.Chronicle.EventSequences.EventForEventSourceId` is the cross-stream
173
- wrapper:
174
-
175
- ```csharp
176
- public record EventForEventSourceId(EventSourceId EventSourceId, object Event, Causation? Causation = default)
177
- {
178
- public Subject? Subject { get; init; }
179
- public EventStreamType EventStreamType { get; init; }
180
- public EventStreamId EventStreamId { get; init; }
181
- public EventSourceType EventSourceType { get; init; }
182
- public DateTimeOffset? Occurred { get; init; }
183
- public IEnumerable<string> Tags { get; init; }
184
- }
185
- ```
159
+ `Cratis.Chronicle.EventSequences.EventForEventSourceId(eventSourceId, @event,
160
+ causation)` is the cross-stream wrapper. Its init members include `Subject`,
161
+ `Occurred`, `Tags`, `EventSource` (`Type?`) and `EventStream` (`string?`). Routing
162
+ defaults are `EventStreamType.All`, `EventStreamId.Default` and
163
+ `EventSourceType.Default`. Source: `EventSequences/EventForEventSourceId.cs`
164
+ at v19.50.0.
186
165
 
187
166
  ```csharp
188
167
  public Task<IEnumerable<EventForEventSourceId>> <MethodName>(<EventName> @event, EventContext context) =>
@@ -193,8 +172,9 @@ public Task<IEnumerable<EventForEventSourceId>> <MethodName>(<EventName> @event,
193
172
  ]);
194
173
  ```
195
174
 
196
- It does **not** carry an event sequence id; side effects are appended to the
197
- event log.
175
+ It also carries `IEnumerable<NamedTag> NamedTags` (snapshotted on assignment).
176
+ It does **not** carry an
177
+ event sequence id; side effects are appended to the event log.
198
178
 
199
179
  ### Where the metadata for a bare event comes from
200
180
 
@@ -223,8 +203,8 @@ a method** and means **replay exclusion**:
223
203
  **`[OnceOnly]` is not per-event-source deduplication.** There is no ledger of
224
204
  which events a handler has already seen. Recovering a failed partition
225
205
  re-delivers the event as an ordinary observation, and a `[OnceOnly]` handler runs
226
- again. Design the side effect to be idempotent regardless — an external
227
- idempotency key, an upsert, a conditional write.
206
+ again. Catch-up and crash redelivery are not replay either; every ordinary
207
+ matching event can run, even on the same source. Keep effects idempotent.
228
208
 
229
209
  Analyzer **CHR0022** (warning) requires `[OnceOnly]` on a handler that returns
230
210
  event side effects, because a replay would otherwise append duplicates.
@@ -255,6 +235,16 @@ public sealed class ReactorAttribute(string id = "", string? eventSequence = def
255
235
  **There is no `isActive` argument** — that belongs to `[Reducer]`. Without an
256
236
  explicit `id`, the reactor's identity is its full type name.
257
237
 
238
+ Give side-effecting reactors a **stable explicit id**. Since 19.47.0 discovery
239
+ warns on likely renames/moves: a new id catches up from the start and repeats
240
+ side effects; `[OnceOnly]` does not prevent that. `ArtifactIdentityDrift = Fail`
241
+ rejects Warning-level reactor/event-type findings with
242
+ `ArtifactIdentityDriftDetected`; projection/reducer drift is Information.
243
+ Inspect `RegistrationOutcome.IdentityDrift`. After stopping all subscriptions,
244
+ `IEventStore.Observers.Remove` can remove an orphaned observer; it refuses while
245
+ running or subscribed anywhere. This is an authorized operator action, not a
246
+ rename cleanup to perform automatically.
247
+
258
248
  The source sequence resolves in this order: an `[EventStore]` attribute (which
259
249
  selects the inbox for that store), then `[EventSequence]`/`[EventLog]`, then
260
250
  `Reactor(eventSequence: ...)`, then the event store inferred from the handled
@@ -282,10 +272,16 @@ event there originates from one service.
282
272
  | `[FilterEventsByTag("<tag>")]` | **filters** by appended tag; repeatable, and any one match admits the event |
283
273
  | `[EventSourceType("<value>")]` | **filters** by the appended event source type |
284
274
  | `[EventStreamType("<value>")]` | **filters** by the appended event stream type |
275
+ | `[FromEventSource<TSource>("<stream>")]` | **filters** by a declared event source and stream (`Cratis.Chronicle.EventSources`) |
285
276
  | `[EventStreamId("<value>")]` | **does not filter**; it is append metadata for side effects |
286
277
  | `[Tag]`, `[Tags]` | **label** the reactor; they never filter |
287
278
 
288
279
  Filter categories combine with AND; tags within the tag category combine with OR.
280
+ Typed source filters work on reactors and reducers, not projections (CHR0041).
281
+ CHR0055 flags unknown streams; CHR0056 flags routing that contradicts the filter.
282
+ Filters survive catch-up, replay and failed-partition recovery.
283
+ `WaitForCompletion` excludes nonmatching observers when the .NET client supplies
284
+ its first appended sequence number.
289
285
  These correspond to metadata supplied at append time:
290
286
 
291
287
  ```csharp
@@ -302,38 +298,15 @@ selection, a reactor or a reducer is where it happens.
302
298
 
303
299
  ## Invoking a command from a reactor
304
300
 
305
- An automation that turns one area's events into another area's intent runs a
306
- command rather than appending directly (Screenplay `invokes`). With the Arc Chronicle integration the handler
307
- **returns** the command — the same shape as returning an event — and Arc executes
308
- it through validation and authorization; a denied, invalid or throwing result is a
309
- side-effect failure that fails the partition rather than being dropped:
310
-
311
- ```csharp
312
- using Cratis.Arc.Chronicle.Reactors;
313
-
314
- [ExecuteCommandsAsSystem("<role the command requires>")] // only when the command is [Roles]/[Authorize]-gated
315
- public class <ReactorName> : IReactor
316
- {
317
- [OnceOnly]
318
- public Task<<CommandName>> <MethodName>(<EventName> @event, EventContext context) =>
319
- Task.FromResult(new <CommandName>(@event.<Property>));
320
- }
321
- ```
322
-
323
- A reactor runs with **no principal**; `[ExecuteCommandsAsSystem]` (class-level,
324
- `Cratis.Arc.Chronicle.Reactors`) supplies one for the **returned** commands only.
325
- A collection return is executed as commands when every element is a command. A stable collection mixing registered events and commands (Arc 22.72.0+; Arc 22.68.0's handler needs every element to be a command) appends the events
326
- first as one batch, then runs the commands in order, with no transaction across them; a retry can
327
- repeat both. `[ExecuteCommandsAsSystem]` covers only the commands.
328
- A reactor retry can execute the command's operations again; inline operations
329
- are not a substitute for reactor/outbox durability (see
330
- `cratis-arc-command-operation`, verified at Arc v22.48.1).
331
-
332
- The imperative form — inject `ICommandPipeline` (`Cratis.Arc.Commands`) and call
333
- `Execute(command)` — is still supported and is the subject of the
334
- **cratis-arc-command-execution** skill. It needs `[OnceOnly]` as well (`ARCCHR0006`
335
- warns), the `CommandResult` must be inspected, and `[ExecuteCommandsAsSystem]`
336
- does not cover it.
301
+ An automation that turns another area's facts into intent runs a command
302
+ (Screenplay `invokes`). For the Arc integration's return shapes, execution
303
+ identity and imperative pipeline alternative, use **cratis-arc-command-execution**
304
+ and **cratis-arc-command** rather than reimplementing command dispatch here.
305
+ A reactor has no caller principal: choose the authorized identity explicitly.
306
+ Keep `[OnceOnly]` and idempotency; a failed command must remain a visible
307
+ partition failure. Inline operations can run again on reactor retry and do not
308
+ replace durable delivery; see **cratis-arc-command-operation**.
309
+ Mixed event-and-command returns and their ordering are owned by the Arc skills.
337
310
 
338
311
  ## Failure behavior
339
312
 
@@ -344,7 +317,10 @@ can **quarantine** the observer, which stops retries and suppresses automatic
344
317
  recovery. **A quarantine ends when an operator clears it
345
318
  (`ClearObserverQuarantine()`), or when the observer is subscribed again** — for an
346
319
  application observer that is when the client connects again, for example after a
347
- redeploy; Kernel-owned observers are subscribed again when the Kernel starts.
320
+ redeploy; Kernel-owned reactors subscribe again at startup; automatic event-store
321
+ subscription reconciliation does not end quarantine. Read
322
+ [recovery](../cratis-chronicle-hosting/references/operations.md) for the
323
+ v19.50.1 fail-closed lookup and observer-kind-specific quarantine rules.
348
324
 
349
325
  Do not throw to reject a malformed inbound event. A reactor is not a data-quality
350
326
  gate; invalid payloads belong at the command or append site. When a malformed
@@ -353,34 +329,38 @@ surface it through the operational failure path, and skip the partial side
353
329
  effect. Throwing just to reject it pauses the partition and can quarantine the
354
330
  whole observer.
355
331
 
332
+ `RetryFailedPartitionFor<TReactor>(partition)` returns a bounded
333
+ `ReactorPartitionRetryOutcome`. `ClearFailedPartitionQuarantineFor<TReactor>(partition,
334
+ retryImmediately)` clears **one partition**, preserves attempt history and starts
335
+ a fresh retry budget (`maxRetryAttempts`). Observer clear is not partition clear.
336
+ Quarantine survives deactivation; watchdog ticks and replay/catch-up completion
337
+ do not end it. Only an operator clear or fresh subscription does. Kernel alert
338
+ incidents surface repeated failures; see **cratis-chronicle-hosting**.
339
+
340
+ A returned append into a closed scope fails with `StreamClosed`, so the reactor
341
+ must not blindly retry it forever. Model an authorized alternate fact/route or
342
+ operator recovery; see **cratis-chronicle-event-constraints**.
343
+
356
344
  ### Domain failures must leave a visible state
357
345
 
358
- A recorded failure fact is not complete handling while the user-facing workflow still looks running. Give each terminal failure a reliable owner that moves the workflow to an explicit failed or retryable state; do not add a failure reactor when a state machine already owns the transition.
346
+ A terminal failure needs an owner that moves the workflow out of "running".
347
+ Do not add a failure reactor when a state machine already owns that transition.
359
348
 
360
349
  Read [references/domain-failures.md](references/domain-failures.md) when handling a domain failure event or deciding whether a failure needs its own reactor or watchdog.
361
350
 
362
351
  ## Keep the reactor stateless
363
352
 
364
- Inject collaborators through the primary constructor; hold no mutable state on
365
- the class. Analyzer **CHR0031** (warning) flags mutable reactor state. Keep each
366
- reactor focused on one automation concern; several handlers in one class are fine
367
- when they serve that concern.
353
+ Inject through the primary constructor; hold no mutable state (CHR0031 warning).
354
+ Keep one automation concern per reactor; several related handlers are fine.
368
355
 
369
356
  ## Specifications
370
357
 
371
358
  Start with `Specification` plus a direct call for pure reactor decisions; add `ReactorScenario<TReactor>` only where invocation, dependency wiring or side effects contribute proof. Specify the contract, not only the happy path: field lineage, contract-authorized filtering, repeated delivery, and unrelated events.
372
359
 
373
- In Chronicle **19.46.0+**, a handler's unseeded read-model parameter throws
374
- `ReadModelNotSeededForReactorScenario`, even if nullable. Seed it through
375
- `Given.ForEventSourceId(id).ReadModel(instance)`, or declare intentional absence
376
- with `.NoReadModel<T>()`. Use the resolved read-model key; `Given` events do not
377
- build read models, including passive ones. A synchronous handler throw surfaces
378
- the handler's exception rather than a reflection wrapper, and the scenario's
379
- `EventContext.Occurred` defaults to UTC.
380
-
381
- Read [references/specifications.md](references/specifications.md) before writing
382
- or reviewing reactor specifications; it shows both setup alternatives and the
383
- scope of these scenario-only guards.
360
+ Read [specifications](references/specifications.md) before writing scenario
361
+ specs: explicit read-model seeding/absence, stream-filtered seeds, produced-event
362
+ destinations, per-run discovery and disposal. `Given` never builds read models,
363
+ including passive ones; nullable parameters still need explicit absence.
384
364
 
385
365
  ## Verify
386
366
 
@@ -405,7 +385,7 @@ scope of these scenario-only guards.
405
385
  - No filter attribute is placed where it is inert.
406
386
  - The reactor holds no mutable state and injects no storage primitive.
407
387
  - The build is clean with no `CHR0004`, `CHR0005`, `CHR0008`, `CHR0013`,
408
- `CHR0022`, `CHR0031`, or `CHR0032` outstanding, and the reactor
388
+ `CHR0022`, `CHR0031`, `CHR0032`, `CHR0054`, `CHR0055`, or `CHR0056` outstanding, and the reactor
409
389
  specifications pass.
410
390
 
411
391
  ## Lineage
@@ -56,7 +56,7 @@ give the reactor `[ExecuteCommandsAsSystem]` naming that role.
56
56
  |---|---|
57
57
  | One trigger event, one command | One handler whose first parameter is the trigger event, returning the command built from the trigger's fields. Add `[ExecuteCommandsAsSystem]` only when the command is gated, and `[OnceOnly]` |
58
58
  | One trigger event, several commands | Return the commands as a collection: Arc runs them in order, with no transaction across them, and a retry can repeat them (see "Invoking a command from a reactor") |
59
- | One trigger, events and commands | Return one stable collection mixing registered events and commands (Arc 22.72.0 or later): the events are appended first as one batch, then the commands run in order, with no transaction across them. Add `[OnceOnly]` where a replay must not repeat it. The Stage 4.73.1 scaffold pins Arc 22.68.0, so this needs a proven dependency override; never split the modeled reaction |
59
+ | One trigger, events and commands | Return one stable collection mixing registered events and commands (Arc 22.72.0 or later): the events are appended first as one batch, then the commands run in order, with no transaction across them. Add `[OnceOnly]` where a replay must not repeat it. The Stage scaffold pins an older Arc (see `cratis-stage-rendering-and-sandbox` `references/rendered-application.md`), so this needs a proven dependency override; never split the modeled reaction |
60
60
  | One trigger event, events produced directly | Return the event or events; `[OnceOnly]` applies (`CHR0022`) |
61
61
  | A condition narrows the trigger | Realize exactly the stated `where`. Show it with one specification where it skips and one for the neighboring case where it acts |
62
62
  | A fact on another event source | `EventForEventSourceId` with the stated target id |
@@ -3,6 +3,7 @@
3
3
  ## Contents
4
4
 
5
5
  - Specifications
6
+ - Routing and produced events — Chronicle 19.50.0 verification
6
7
  - Read-model setup — Chronicle 19.46.0+
7
8
  - Exceptions and occurrence time — Chronicle 19.46.0+
8
9
  - Contract coverage
@@ -18,6 +19,24 @@ non-event side effects; for handlers that return events, assert the resulting
18
19
  appends through the scenario's event store. Cover the replay path separately
19
20
  when the reactor has `[OnceOnly]` or `[Replay]` handlers.
20
21
 
22
+ ## Routing and produced events — Chronicle 19.50.0 verification
23
+
24
+ Scenarios implement `IDisposable`; dispose in `Destroy()`.
25
+ `Given.ForEventSource(id).OnStream(eventSourceType, eventStreamType, eventStreamId).Events(...)`
26
+ seeds routing for class-based and fluent reactors. Source/stream/typed definition
27
+ filters are honored: unqualified seeds do not reach a handler filtered to a
28
+ specific stream. Specify both a matching event and an excluded event.
29
+
30
+ `ProducedEvents` records each `ProducedEvent` **with its destination**.
31
+ `ShouldHaveProduced<TEvent>(eventSourceId)` checks routing; the
32
+ `ShouldHaveProduced<TEvent>((produced, @event) => ...)` overload checks metadata
33
+ and payload together. Do not assert only the payload when a cross-stream target
34
+ is part of the contract. Per-run `Defaults(clientArtifactsProvider, serviceProvider,
35
+ options)` supports `InMemoryClientArtifactsProvider` and `ExplicitArtifacts`;
36
+ non-generic `ReactorScenario(reactorId, defaults)` exercises a runtime/fluent reactor.
37
+ Sources: `Source/Clients/Testing/Reactors/` and `Source/Clients/Testing/Defaults.cs`
38
+ at **v19.50.0**.
39
+
21
40
  ## Read-model setup — Chronicle 19.46.0+
22
41
 
23
42
  Class-based `ReactorScenario<TReactor>` does not build read models from `Given`
@@ -78,7 +97,7 @@ their supplied offset; the positional constructor does not default `Occurred`.
78
97
  For deterministic time-dependent plain-call specs, supply a fixed occurrence
79
98
  time rather than asserting an exact current instant.
80
99
 
81
- Verified against **Chronicle tag `v19.46.0`**:
100
+ Reverified against **Chronicle tag `v19.50.0`** (the guards began in 19.46.0):
82
101
 
83
102
  - `Source/Clients/Testing/Reactors/ReactorSourceGivenBuilder.cs` and
84
103
  `ReactorScenarioGivenBuilder.cs`: seeding, absence and builder signatures.
@@ -24,8 +24,8 @@ This skill is verified against these exact sources:
24
24
  | Package | Version | Purpose |
25
25
  | --- | --- | --- |
26
26
  | `Cratis.Chronicle` | `18.3.0` | `Cratis.Chronicle.Events`, `Cratis.Chronicle.Keys`, `Cratis.Chronicle.ReadModels` |
27
- | `Cratis.Arc.Core` | `22.16.0` | `Cratis.Arc.Queries.ModelBound.ReadModelAttribute` and `PathAttribute` |
28
- | `Cratis.Arc.MongoDB` | `22.16.0` | the `Observe` family of `IMongoCollection<T>` extensions |
27
+ | `Cratis.Arc.Core` | `22.75.0` | `Cratis.Arc.Queries.ModelBound.ReadModelAttribute` and `PathAttribute` |
28
+ | `Cratis.Arc.MongoDB` | `22.75.0` | the `Observe` family of `IMongoCollection<T>` extensions |
29
29
 
30
30
  Reverify product sources before claiming support for another version. Confirm
31
31
  the exact Arc package version in the consuming project before citing one.
@@ -11,9 +11,8 @@
11
11
  - Custom routes
12
12
  - Reading without a query surface
13
13
 
14
- Verified against `Cratis.Arc.Core` and `Cratis.Arc.MongoDB` as checked out
15
- alongside `Cratis.Chronicle` `18.3.0`. Confirm the exact Arc package version in
16
- the consuming project before citing one.
14
+ Verified against `Cratis.Arc.Core` and `Cratis.Arc.MongoDB` **v22.75.0**.
15
+ Chronicle projection behavior is owned by the Chronicle guidance.
17
16
 
18
17
  ## Where the pieces live
19
18
 
@@ -23,7 +22,8 @@ the consuming project before citing one.
23
22
  | `PathAttribute` (`[Path]`) | `Cratis.Arc.Queries.ModelBound` | `Cratis.Arc.Core` |
24
23
  | the `Observe` extensions | `MongoDB.Driver` | `Cratis.Arc.MongoDB` |
25
24
 
26
- `[ReadModel]` is a bare marker with **no constructor parameters**. `[Path]` takes
25
+ `[ReadModel]` has no constructor parameters; its `RequireQueryAttribute = true`
26
+ property opts into explicit endpoint discovery. `[Path]` takes
27
27
  one `string path` and targets a class or a method.
28
28
 
29
29
  The `Observe` extensions are deliberately declared in the `MongoDB.Driver`
@@ -32,8 +32,17 @@ Chronicle extensions — Chronicle declares no `Observe` on `IMongoCollection<T>
32
32
 
33
33
  ## Discovery rules
34
34
 
35
- Arc scans the read-model type for **static** methods, public and non-public
36
- alike. Instance methods are never discovered.
35
+ Arc discovers **public static** methods; private and compiler-generated methods
36
+ are never queries. Use `[ReadModel(RequireQueryAttribute = true)]` and `[Query]`
37
+ on intended endpoints when the type also has folds (`Create`/`Reduce`) or public
38
+ helpers. `[Query]` alone does not hide siblings. ARC0026 checks invalid/ambiguous
39
+ query declarations; ARCCHR0019 warns about fold-like statics exposed by convention.
40
+ A `CancellationToken` parameter is supplied by Arc, not a query argument/proxy
41
+ input. Concept parameters are always caller-supplied, never DI. Invalid bool,
42
+ overflow, concept or collection-element GET/QUERY arguments return HTTP 400.
43
+ Minimal-API concepts serialize as primitives since 22.26.0.
44
+ Sources at Arc v22.75.0: `Arc.Core/Queries/ModelBound/ReadModelAttribute.cs`,
45
+ `QueryAttribute.cs`, and `Documentation/backend/csharp/chronicle/code-analysis/ARCCHR0019.md`.
37
46
 
38
47
  The declared return type is validated after unwrapping at most one `Task<>`:
39
48
 
@@ -94,27 +103,32 @@ Return `ISubject<...>` directly. Do **not** return `Task<ISubject<...>>`.
94
103
  ISubject<IEnumerable<TDocument>> Observe<TDocument>(
95
104
  this IMongoCollection<TDocument> collection,
96
105
  Expression<Func<TDocument, bool>>? filter,
97
- FindOptions? options = null);
106
+ FindOptions? options = null,
107
+ bool ignoreQueryContext = false);
98
108
 
99
109
  ISubject<IEnumerable<TDocument>> Observe<TDocument>(
100
110
  this IMongoCollection<TDocument> collection,
101
111
  FilterDefinition<TDocument>? filter = null,
102
- FindOptions? options = null);
112
+ FindOptions? options = null,
113
+ bool ignoreQueryContext = false);
103
114
 
104
115
  // single-valued
105
116
  ISubject<TDocument> ObserveSingle<TDocument>(
106
117
  this IMongoCollection<TDocument> collection,
107
118
  Expression<Func<TDocument, bool>>? filter,
108
- FindOptions? options = null);
119
+ FindOptions? options = null,
120
+ bool ignoreQueryContext = false);
109
121
 
110
122
  ISubject<TDocument> ObserveSingle<TDocument>(
111
123
  this IMongoCollection<TDocument> collection,
112
124
  FilterDefinition<TDocument>? filter = null,
113
- FindOptions? options = null);
125
+ FindOptions? options = null,
126
+ bool ignoreQueryContext = false);
114
127
 
115
128
  ISubject<TDocument> ObserveById<TDocument, TId>(
116
129
  this IMongoCollection<TDocument> collection,
117
- TId id);
130
+ TId id,
131
+ bool ignoreQueryContext = false);
118
132
  ```
119
133
 
120
134
  Two details that catch people out:
@@ -129,17 +143,22 @@ Two details that catch people out:
129
143
  Also available in the same place: `FindById<T, TId>` and
130
144
  `FindByIdAsync<T, TId>`.
131
145
 
146
+ Single-instance `ObserveSingle`/`ObserveById` (MongoDB and EF) emit `default`
147
+ when absent, deleted or outside the filter, without ending the subscription.
148
+ Guard React `result.hasData` and `result.isReady` before dereferencing data.
149
+
132
150
  ## Cost and composition
133
151
 
134
- The behavior below was checked against **Arc v22.49.0**
135
- ([collection observation](https://github.com/Cratis/Arc/blob/v22.49.0/Documentation/backend/csharp/mongodb/observing-collections.md),
136
- [implementation](https://github.com/Cratis/Arc/blob/v22.49.0/Source/DotNET/MongoDB/MongoCollectionExtensions.cs)).
152
+ The behavior below was checked against **Arc v22.75.0**
153
+ ([collection observation](https://github.com/Cratis/Arc/blob/v22.75.0/Documentation/backend/csharp/mongodb/observing-collections.md),
154
+ [implementation](https://github.com/Cratis/Arc/blob/v22.75.0/Source/DotNET/MongoDB/MongoCollectionExtensions.cs)).
137
155
  Do not generalize it to every provider or custom observable.
138
156
 
139
157
  - Per-collection `Observe` reads an initial filtered set, retains it in memory,
140
158
  and applies change-stream updates. It does **not** re-query the entire
141
159
  collection for every event. Updates/replacements perform a keyed membership
142
- lookup; paged removals can query to refill the page.
160
+ lookup for unpaged observations. Paged observations re-read the page and total
161
+ on every change; sort ties and unsorted pages use `_id`.
143
162
  - Collection emissions still construct a snapshot of the retained set. In-memory
144
163
  joins, sorting, mapping, and serialization downstream can be expensive even
145
164
  without a full database re-query. Measure retained rows, payload size, change
@@ -158,7 +177,7 @@ Do not generalize it to every provider or custom observable.
158
177
  - Prefer a purpose-built projected summary for frequently recomputed joins.
159
178
  Query-time composition is supported, not forbidden. Bound each input and define
160
179
  count, paging, missing-related-data, and subscription-disposal behavior.
161
- In v22.49.0 auxiliary observations can use `ignoreQueryContext: true` so client
180
+ At v22.75.0 MongoDB and EF auxiliary observations can use `ignoreQueryContext: true` so client
162
181
  paging/counts belong to the primary source. That option reads **all matching
163
182
  auxiliary rows**; it is not a performance limit. Confirm version support before
164
183
  using it, and keep an explicit narrow filter.
@@ -22,10 +22,10 @@ is no separate `When`: seeding the events is what makes the projection run.
22
22
 
23
23
  | Package | Version | Purpose |
24
24
  | --- | --- | --- |
25
- | `Cratis.Chronicle.Testing` | `18.3.0` | `ReadModelScenario<TReadModel>` and its `Given` builder |
25
+ | `Cratis.Chronicle.Testing` | `19.50.1` | `ReadModelScenario<TReadModel>` and its `Given` builder |
26
26
  | `Cratis.Specifications.XUnit` | `4.x` | The `Specification` base and the `ShouldXxx` assertions |
27
27
 
28
- > Re-verified at the versions above by **symbol and signature**: every type, attribute and member this skill names exists at that tag, and the public surface it describes is unchanged since the previous verification (Chronicle 16.45.x / Arc 22.10.4 — the Chronicle 16→18 client diff is converters, options and doc comments; no type was removed or renamed). Behavior claims were verified at the earlier tag unless a section says otherwise.
28
+ Source: `Source/Clients/Testing/ReadModels/` at **Cratis/Chronicle v19.50.0**.
29
29
 
30
30
  ```bash
31
31
  dotnet add package Cratis.Chronicle.Testing
@@ -82,6 +82,12 @@ var scenario = new ReadModelScenario<CartSummary>(new CartSummary { ItemCount =
82
82
  Further constructors take a service provider, a `Defaults`, or both, alongside
83
83
  the initial state. Use the named-parameter form when you need only one of them:
84
84
  `new ReadModelScenario<T>(initialState: null, serviceProvider: services)`.
85
+ Scenarios implement `IDisposable`; call `_scenario.Dispose()` in `Destroy()`.
86
+ `WithProjection(Action<IProjectionBuilderFor<T>>)` supplies an inline projection
87
+ and wins over discovery, **including a discovered reducer**. Per-run `Defaults`
88
+ can take a client artifacts provider, service provider and options;
89
+ `InMemoryClientArtifactsProvider` and `ChronicleOptions.ExplicitArtifacts` let a
90
+ specification isolate registrations without global discovery.
85
91
 
86
92
  ## Step 2 — Seed the events
87
93
 
@@ -103,6 +109,12 @@ await scenario.Given.ForEventSource(anotherOrderId).Events(new OrderCreated("ord
103
109
  offers `.ReadModel(instance)` to pin a materialized instance for code that calls
104
110
  `IReadModels.GetInstanceById` rather than deriving it from events.
105
111
 
112
+ For a filtered reducer, seed the routing metadata as well:
113
+ `Given.ForEventSource(id).OnStream(eventSourceType, eventStreamType, eventStreamId).Events(...)`.
114
+ `[EventSourceType]`, `[EventStreamType]` and `[FromEventSource<T>]` filters are honored;
115
+ unrouted seeds no longer reach a handler for another stream. Child-before-parent
116
+ writes are retried when the parent later arrives; decimal seeds retain exact values.
117
+
106
118
  Events are processed in the order supplied. Seed before asserting, and do not
107
119
  try to separate a "setup" `Given` from an "act" `Given` — for a read model they
108
120
  are the same phase.
@@ -131,7 +143,7 @@ specific reason in the skip message.
131
143
 
132
144
  ## Step 4 — Know what the scenario picked
133
145
 
134
- The scenario finds a handler for `TReadModel` in this order:
146
+ Without an explicit `WithProjection`, the scenario finds a handler for `TReadModel` in this order:
135
147
 
136
148
  1. A **reducer** — a class implementing `IReducerFor<TReadModel>`.
137
149
  2. A **fluent projection** — a class implementing `IProjectionFor<TReadModel>`.
@@ -17,7 +17,7 @@ This skill is verified against this exact source:
17
17
 
18
18
  | Package | Version | Purpose |
19
19
  | --- | --- | --- |
20
- | `Cratis.Chronicle` | `18.3.0` | `Cratis.Chronicle.Reducers`, `Cratis.Chronicle.ReadModels`, `Cratis.Chronicle.Events` |
20
+ | `Cratis.Chronicle` | `19.50.1` | `Cratis.Chronicle.Reducers`, `Cratis.Chronicle.ReadModels`, `Cratis.Chronicle.Events` |
21
21
 
22
22
  Reverify product sources before claiming support for another version.
23
23
 
@@ -98,6 +98,9 @@ The rules the invoker enforces:
98
98
  per event type** — do not write two handlers for the same event.
99
99
  - Return the complete next state. Never mutate `current` in place; use `with { }`.
100
100
  - The reducer must be **stateless**. Do not hold mutable state on the class.
101
+ - A reducer with no dispatchable methods is not registered. Logs name skipped
102
+ reducer-like methods; CHR0006/CHR0007 flag them. CHR0051 checks nullable current
103
+ state, and CHR0057 rejects multiple `IReducerFor<T>` targets on one class.
101
104
 
102
105
  ### Returning null deletes the instance
103
106
 
@@ -136,14 +139,14 @@ read.
136
139
 
137
140
  ## Filtering which events reach the reducer
138
141
 
139
- Three attributes genuinely filter a reducer's input, and they correspond to
140
- metadata supplied at append time:
142
+ These attributes genuinely filter a reducer's input, matching append metadata:
141
143
 
142
144
  | Attribute | Filters on |
143
145
  | --- | --- |
144
146
  | `[FilterEventsByTag("<tag>")]` | an appended tag; repeatable, and any one match admits the event |
145
147
  | `[EventSourceType("<value>")]` | the appended event source type |
146
148
  | `[EventStreamType("<value>")]` | the appended event stream type |
149
+ | `[FromEventSource<TSource>("<stream>")]` | the source definition and declared stream (`Cratis.Chronicle.EventSources`) |
147
150
 
148
151
  `[Tag]` and `[Tags]` **label** the artifact; they do not filter. Note also that a
149
152
  **projection cannot be filtered at all** — its definition has no field for it.
@@ -163,6 +166,20 @@ await eventStore.EventLog.Append(
163
166
 
164
167
  Mind the parameter order on `Append`: `eventStreamType` comes before
165
168
  `eventStreamId`, which comes before `eventSourceType`.
169
+ CHR0055 flags an unknown typed stream and CHR0056 contradictory routing.
170
+ Filters remain effective during catch-up, replay and failed-partition recovery.
171
+
172
+ ## Definition changes replay
173
+
174
+ The kernel classifies new definitions under `observers.definitionEvolution`:
175
+ `Automatic` (default), `PartialOnly`, or `Manual`. Reducer method fingerprints
176
+ make code changes visible even without subscription changes; assembly versions
177
+ are ignored since 19.29.4 (that upgrade replays each reducer once). Changed
178
+ implementation, keys or filters require full replay; adding event types permits
179
+ partial replay only when history proves they follow all previously consumed
180
+ events per source. Interleaved history requires full replay. Manual policies
181
+ leave recommendations; they do not silently rebuild. Source at v19.50.0:
182
+ `Documentation/hosting/configuration/observers.md`.
166
183
 
167
184
  ## Specifications
168
185
 
@@ -194,7 +211,9 @@ assert on the resulting instance there. Cover, at minimum:
194
211
 
195
212
  - The admission test is satisfied and the justification names the specific
196
213
  limitation.
197
- - The current-state parameter is nullable on every handler method.
214
+ - The current-state parameter is nullable on every handler method (CHR0051).
215
+ - Logs contain no skipped reducer-like method warning (CHR0006/CHR0007);
216
+ CHR0055–CHR0057 are clean.
198
217
  - No handler method has more than three parameters, and any third is
199
218
  `EventContext`.
200
219
  - Exactly one handler exists per event type.