@cratis/pi 7.34.1 → 7.36.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 (229) 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/specifications.md +20 -1
  148. package/package/corpus/skills/cratis-chronicle-read-model/SKILL.md +2 -2
  149. package/package/corpus/skills/cratis-chronicle-read-model/references/queries.md +35 -16
  150. package/package/corpus/skills/cratis-chronicle-read-model-specifications/SKILL.md +15 -3
  151. package/package/corpus/skills/cratis-chronicle-reducer/SKILL.md +23 -4
  152. package/package/corpus/skills/cratis-chronicle-web-workbench/SKILL.md +40 -15
  153. package/package/corpus/skills/cratis-cli-terminal-workbench/SKILL.md +20 -6
  154. package/package/corpus/skills/cratis-code-review/SKILL.md +25 -3
  155. package/package/corpus/skills/cratis-components-accessibility/SKILL.md +20 -4
  156. package/package/corpus/skills/cratis-components-schema-editor/SKILL.md +40 -28
  157. package/package/corpus/skills/cratis-components-schema-editor/references/tree-layout.md +62 -0
  158. package/package/corpus/skills/cratis-components-schema-editor/verification.json +14 -0
  159. package/package/corpus/skills/cratis-components-stepper-command-dialog/SKILL.md +16 -8
  160. package/package/corpus/skills/cratis-components-styling/SKILL.md +57 -20
  161. package/package/corpus/skills/cratis-components-styling/verification.json +13 -0
  162. package/package/corpus/skills/cratis-components-toolbar/SKILL.md +37 -7
  163. package/package/corpus/skills/cratis-components-toolbar/verification.json +12 -0
  164. package/package/corpus/skills/cratis-engineering-csharp-conventions/SKILL.md +6 -0
  165. package/package/corpus/skills/cratis-engineering-csharp-conventions/references/exceptions-logging-and-di.md +5 -3
  166. package/package/corpus/skills/cratis-fundamentals-concept/SKILL.md +19 -6
  167. package/package/corpus/skills/cratis-fundamentals-concept/references/typescript-concepts.md +97 -0
  168. package/package/corpus/skills/cratis-fundamentals-concept/verification.json +4 -1
  169. package/package/corpus/skills/cratis-fundamentals-concept-go/SKILL.md +112 -0
  170. package/package/corpus/skills/cratis-fundamentals-type-discovery/SKILL.md +54 -17
  171. package/package/corpus/skills/cratis-fundamentals-type-discovery/verification.json +14 -0
  172. package/package/corpus/skills/cratis-lens-browser-extension/SKILL.md +55 -28
  173. package/package/corpus/skills/cratis-performance-review/SKILL.md +5 -2
  174. package/package/corpus/skills/cratis-release-notes/SKILL.md +3 -1
  175. package/package/corpus/skills/cratis-screenplay-automations-and-translations/SKILL.md +5 -4
  176. package/package/corpus/skills/cratis-screenplay-command-surface/SKILL.md +7 -11
  177. package/package/corpus/skills/cratis-screenplay-command-surface/references/compliance.md +26 -6
  178. package/package/corpus/skills/cratis-screenplay-command-surface/references/enum-numbers.md +4 -2
  179. package/package/corpus/skills/cratis-screenplay-command-surface/references/generated-values-and-responses.md +4 -1
  180. package/package/corpus/skills/cratis-screenplay-command-surface/verification.json +7 -1
  181. package/package/corpus/skills/cratis-screenplay-event-modeling/SKILL.md +3 -2
  182. package/package/corpus/skills/cratis-screenplay-event-modeling/references/parsed-not-runnable.md +6 -2
  183. package/package/corpus/skills/cratis-screenplay-legacy-extraction/SKILL.md +1 -0
  184. package/package/corpus/skills/cratis-screenplay-legacy-extraction/references/generate-notes.md +34 -4
  185. package/package/corpus/skills/cratis-screenplay-model-authoring/SKILL.md +17 -24
  186. package/package/corpus/skills/cratis-screenplay-model-authoring/references/language-reference.md +1 -1
  187. package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-loop.md +19 -2
  188. package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-tools.md +11 -3
  189. package/package/corpus/skills/cratis-screenplay-model-authoring/references/property-links.md +90 -4
  190. package/package/corpus/skills/cratis-screenplay-model-authoring/verification.json +19 -2
  191. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/gap-fill-handoff.md +3 -1
  192. package/package/corpus/skills/cratis-screenplay-scenario-coverage/SKILL.md +3 -1
  193. package/package/corpus/skills/cratis-screenplay-specifications/references/examples-and-routes.md +48 -0
  194. package/package/corpus/skills/cratis-screenplay-specifications/verification.json +3 -1
  195. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/SKILL.md +4 -2
  196. package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/streams-example.md +5 -4
  197. package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +8 -6
  198. package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet-example.md +8 -2
  199. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +4 -2
  200. package/package/corpus/skills/cratis-screenplay-toolchain/references/doc-contradictions.md +7 -1
  201. package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +24 -11
  202. package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +10 -4
  203. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.json +1543 -131
  204. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.version +1 -1
  205. package/package/corpus/skills/cratis-screenplay-toolchain/references/verdicts.md +9 -3
  206. package/package/corpus/skills/cratis-screenplay-toolchain/references/versions.md +23 -7
  207. package/package/corpus/skills/cratis-screenplay-toolchain/verification.json +1 -1
  208. package/package/corpus/skills/cratis-screenplay-ui-composition/SKILL.md +2 -0
  209. package/package/corpus/skills/cratis-screenplay-ui-composition/references/screen-composition-contract.md +27 -9
  210. package/package/corpus/skills/cratis-security-review/SKILL.md +9 -3
  211. package/package/corpus/skills/cratis-security-review/references/arc-boundaries.md +59 -0
  212. package/package/corpus/skills/cratis-specification-by-example/SKILL.md +7 -0
  213. package/package/corpus/skills/cratis-specifications-csharp/SKILL.md +43 -11
  214. package/package/corpus/skills/cratis-specifications-csharp/references/application-scenarios.md +16 -4
  215. package/package/corpus/skills/cratis-specifications-csharp/references/csharp-patterns.md +18 -5
  216. package/package/corpus/skills/cratis-specifications-csharp/references/integration-specs.md +21 -0
  217. package/package/corpus/skills/cratis-specifications-csharp/references/shared-lifecycle.md +34 -0
  218. package/package/corpus/skills/cratis-specifications-csharp/verification.json +13 -0
  219. package/package/corpus/skills/cratis-specifications-typescript/SKILL.md +14 -5
  220. package/package/corpus/skills/cratis-specifications-typescript/verification.json +12 -0
  221. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +8 -2
  222. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +6 -3
  223. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/rendered-application.md +10 -1
  224. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/scene-runtime.md +75 -0
  225. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/verification.json +5 -0
  226. package/package/corpus/skills/cratis-studio-mcp-safety-guidance/SKILL.md +14 -1
  227. package/package/profile-catalog.json +68 -1
  228. package/package.json +1 -1
  229. package/src/index.ts +3 -1
@@ -1,9 +1,12 @@
1
1
  ---
2
2
  name: cratis-chronicle-client-elixir
3
- description: Talk to a Chronicle server from an Elixir application with the cratis_chronicle Hex package - putting Chronicle.Client in a supervision tree, connection strings, use Chronicle.Events.EventType structs, Chronicle.append returning ok or error tuples, reactors with the @handles attribute and a handle/2 callback, model-bound and declarative read models/projections, variant_of/enters_on/GlobalHandler for an entity with mutually exclusive lifecycle shapes, and the connection lifecycle phases and keepalive. Use when an OTP application appends to or observes a Chronicle event store. Do not use for the .NET, TypeScript, or Kotlin clients.
3
+ description: Talk to a Chronicle server from an Elixir application with the cratis_chronicle Hex package - Chronicle.Client supervision and connection lifecycle, EventType structs, append errors, event sources and streams, Chronicle.Concept, PII and encrypted secrets, reactors, read models/projections with composite keys, variants and GlobalHandler, and observer inspection. Use when an OTP application appends to or observes a Chronicle event store. Do not use for the .NET, TypeScript, or Kotlin clients.
4
4
  license: MIT
5
5
  ---
6
6
 
7
+ <!-- Copyright (c) Cratis. All rights reserved. -->
8
+ <!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
9
+
7
10
  # The Chronicle client for Elixir
8
11
 
9
12
  `cratis_chronicle` is a **standalone client SDK**. It is a library, not a
@@ -12,18 +15,17 @@ to yours, and everything after that is ordinary OTP.
12
15
 
13
16
  ## Verified product sources
14
17
 
15
- This skill was written against `Cratis/Chronicle.Elixir` at tag **`v2.2.0`** and
16
- re-verified at **`v3.1.0`** (published on Hex as `3.1.0`; `3.0.0` is the
17
- Chronicle 17/18 wire migration — gRPC request/response shapes, no public API
18
- removed). Every module, function and option this skill names exists at `v3.1.0`;
19
- the `file:line` citations below were taken at `v2.2.0` and may have shifted.
18
+ Re-verified against `Cratis/Chronicle.Elixir` tag **`v3.10.2`** (Hex `3.10.2`).
19
+ Source paths below are relative to `Source/chronicle/` at that tag.
20
+
21
+ Read [references/upgrading.md](references/upgrading.md) when upgrading from 2.x or earlier 3.x releases; wire compatibility and corrected behavior both matter.
20
22
 
21
23
  | Fact | Value | Source |
22
24
  | --- | --- | --- |
23
25
  | OTP app / Hex package | `:cratis_chronicle` | `Source/chronicle/mix.exs:14` |
24
- | Published versions | `3.1.0`, `3.0.0`, `2.2.0`, `2.1.x`, `2.0.0`, `1.0.x`, `0.x` — **no `2.3.0`** | hex.pm |
25
- | Elixir requirement | `~> 1.14` | `Source/chronicle/mix.exs` |
26
- | Contracts dependency | `cratis_chronicle_contracts` resolved to `18.2.0` at `v3.1.0` (`16.13.4` at `v2.2.0`) | `Source/chronicle/mix.lock` |
26
+ | Published versions | `3.10.2`, earlier `3.x`, `3.0.0`, `2.2.0`, `2.1.x`, `2.0.0`, `1.0.x`, `0.x` — **no `2.3.0`** | hex.pm |
27
+ | Elixir requirement | `~> 1.18` | `Source/chronicle/mix.exs` |
28
+ | Contracts dependency | `cratis_chronicle_contracts` resolved to `19.30.0` (`18.2.0` at `v3.1.0`, `16.13.4` at `v2.2.0`); pair it with a compatible kernel | `Source/chronicle/mix.lock` |
27
29
 
28
30
  > **The `v2.3.0` git tag was never published to Hex.** `mix deps.get` cannot
29
31
  > fetch it. What it introduced — notably the `Chronicle.Concept` macro
@@ -35,15 +37,12 @@ the `file:line` citations below were taken at `v2.2.0` and may have shifted.
35
37
  > **The repository's `VERSION` file says `0.0.5` and is a build-time
36
38
  > placeholder** overwritten by the publish workflow. Never quote it.
37
39
 
38
- > **The real modules are namespaced** — `Chronicle.Events.EventType`,
39
- > `Chronicle.ReadModels.ReadModel`, `Chronicle.Reactors.Reactor`,
40
- > `Chronicle.Reducers.Reducer`, `Chronicle.Seeding.Seeder`. The `v2.2.0` root
41
- > `README.md` used unnamespaced names that do not exist (`use Chronicle.EventType`,
42
- > …); the `3.x` README is correct. When in doubt, copy from
43
- > `Documentation/client-snippets/` — those are CI-validated at every version.
40
+ > Use namespaced modules (`Chronicle.Events.EventType`, not `Chronicle.EventType`).
41
+ > The `v2.2.0` README got this wrong; the `3.x` README is correct. Maintained
42
+ > snippets live in `Documentation/client-snippets/`.
44
43
 
45
- > `Documentation/get-started.md:13` pins `{:cratis_chronicle, "~> 0.1"}`, which
46
- > does not match the published `2.2.0`. Use a `2.x` requirement.
44
+ The current README and get-started guide use `~> 3.5`; select the intended
45
+ published version from hex.pm rather than treating a guide's range as a pin.
47
46
 
48
47
  ## Adding it
49
48
 
@@ -51,7 +50,7 @@ the `file:line` citations below were taken at `v2.2.0` and may have shifted.
51
50
  # mix.exs
52
51
  defp deps do
53
52
  [
54
- {:cratis_chronicle, "~> 2.2"}
53
+ {:cratis_chronicle, "~> 3.10"}
55
54
  ]
56
55
  end
57
56
  ```
@@ -62,8 +61,8 @@ The library declares `extra_applications: [:logger, :inets, :ssl]` and **no
62
61
 
63
62
  ## Starting the client
64
63
 
65
- `Chronicle.Client` is a `Supervisor` (`lib/chronicle/client.ex:129`) with
66
- `start_link(opts \\ [])` (`:139`). Put it in your application's tree — this is
64
+ `Chronicle.Client` is a `Supervisor` (`lib/chronicle/client.ex:135`) with
65
+ `start_link(opts \\ [])` (`:145`). Put it in your application's tree — this is
67
66
  the CI-validated snippet from
68
67
  `Documentation/client-snippets/get-started/console/connect.md`:
69
68
 
@@ -75,7 +74,7 @@ defmodule MyApp.Application do
75
74
  def start(_type, _args) do
76
75
  children = [
77
76
  {Chronicle.Client,
78
- connection_string: "chronicle://localhost:35000",
77
+ connection_string: Chronicle.Connections.ConnectionString.development(),
79
78
  event_store: "quickstart",
80
79
  otp_app: :my_app}
81
80
  ]
@@ -87,38 +86,38 @@ end
87
86
 
88
87
  ### Options
89
88
 
90
- All configuration is **child-spec keyword options**. There is no
91
- `Application.get_env` anywhere in the library and no `config/` directory —
92
- `config.exs` does nothing for this client. Read the options at
93
- `lib/chronicle/client.ex`:
89
+ Pass **child-spec keyword options**. The client reads no application env;
90
+ your app must read its own configuration and pass it in (`lib/chronicle/client.ex`).
94
91
 
95
92
  | Option | Default | Line |
96
93
  | --- | --- | --- |
97
- | `:name` | `Chronicle.Client` | `:140` |
94
+ | `:name` | `Chronicle.Client` | `:146` |
98
95
  | `:connection_string` | `ConnectionString.default/0` | — |
99
- | `:event_store` | `"default"` | `:159` |
100
- | `:namespace` | `"Default"` — capital D | `:160` |
101
- | `:discover` | `true` | `:161` |
102
- | `:otp_app` | none; falls back to scanning loaded modules | `:168` |
103
- | `:event_types`, `:migrations`, `:reactors`, `:reducers`, `:read_models`, `:projections`, `:seeders`, `:webhooks`, `:event_store_subscriptions`, `:global_handlers` | `[]`, merged with discovered | `:186-197` |
104
- | `:skip_tls_validation`, `:load_balancer`, `:grpc_options`, `:retry_attempts`, `:reconnect_base_delay`, `:reconnect_max_delay` | forwarded to the connection | — |
96
+ | `:event_store` | `"default"` | `:165` |
97
+ | `:namespace` | `"Default"` — capital D | `:166` |
98
+ | `:discover` | `true` | `:167` |
99
+ | `:otp_app` | none; falls back to scanning loaded modules | `:174` |
100
+ | `:event_types`, `:event_sources`, `:migrations`, `:reactors`, `:reducers`, `:read_models`, `:projections`, `:seeders`, `:webhooks`, `:event_store_subscriptions`, `:global_handlers` | `[]`, merged with discovered | `:194-214` |
101
+ | `:default_sink_type_id` | `:mongodb`; accepts `:mongodb`, `:sql`, `:in_memory`, `:none` or a raw string | `:169-170` |
102
+ | `:server_address` | alternative `"host:port"` address | connection option |
103
+ | `:skip_tls_validation`, `:load_balancer`, `:grpc_options`, `:reconnect_base_delay`, `:reconnect_max_delay` | forwarded to the connection | — |
104
+ | `:retry_attempts` | accepted for compatibility, **ignored** | `connections/connection.ex:48-49` |
105
105
 
106
106
  > The moduledoc at `client.ex:81` says the namespace defaults to `"default"`.
107
- > The code at `:160` uses `"Default"`. **Trust the code.**
107
+ > The code at `:166` uses `"Default"`. **Trust the code.**
108
108
 
109
109
  **Set `:otp_app`.** With it, discovery is scoped to your application's modules;
110
110
  without it the client falls back to scanning every loaded module.
111
111
 
112
112
  Configuration is stashed in `:persistent_term` and read back with
113
- `Chronicle.Client.config/1` (`client.ex:150`). Note it stores only a subset —
114
- `read_models`, `projections`, and `migrations` are not retrievable at runtime.
113
+ `Chronicle.Client.config/1` (`client.ex:156`). Its subset includes `event_sources`,
114
+ but not `read_models`, `projections`, or `migrations` (`:218-228`).
115
115
 
116
116
  ### The supervision tree
117
117
 
118
- `Supervisor.init(children, strategy: :rest_for_one)` — `client.ex:308`. The
119
- strategy is deliberate: the children are ordered connection → session →
120
- registration → observers, so restarting the connection restarts everything that
121
- depends on it, and nothing is left holding a dead channel.
118
+ `Supervisor.init(children, strategy: :rest_for_one)` — `client.ex:328`.
119
+ The lifecycle hub is the root dependency; restarting it restarts its subscribers.
120
+ The connection, session and registration precede observers.
122
121
 
123
122
  ### Multiple clients
124
123
 
@@ -134,7 +133,7 @@ broadcasts `{:chronicle_lifecycle, phase, connection_id}` with three phases
134
133
  | Phase | Meaning |
135
134
  | --- | --- |
136
135
  | `:disconnected` | no live session with the kernel |
137
- | `:connected` | the session handshake completed |
136
+ | `:connected` | the kernel acknowledged the connection id with its first keepalive |
138
137
  | `:registered` | the registration coordinator registered the base artifacts |
139
138
 
140
139
  **Wait for `:registered`, never merely `:connected`** — the module's own docs say
@@ -142,90 +141,78 @@ so at `:27-29`, because reducers and reactors are not attached until registratio
142
141
  finishes.
143
142
 
144
143
  ```elixir
145
- config = Chronicle.Client.config()
144
+ alias Chronicle.Connections.Lifecycle
146
145
 
147
- case Chronicle.Connections.Lifecycle.wait_until(config.lifecycle, :registered, 30_000) do
148
- :ok -> :ok
149
- {:error, :timeout} -> # decide what a not-yet-registered client means for you
146
+ case Lifecycle.wait_until(Lifecycle.name_for(Chronicle.Client), :registered, 30_000) do
147
+ :ok -> :ready
148
+ {:error, :timeout} -> :not_ready
150
149
  end
151
150
  ```
152
151
 
153
152
  `wait_until(lifecycle, target_phase, timeout \\ 30_000)` is at `:141`.
154
- `subscribe/1` (`:90`) returns the current phase **and** sends it as a message,
153
+ `subscribe/1` (`:90`) returns `{:ok, phase, connection_id}` **and** sends it as a message,
155
154
  which closes the subscribe-after-transition race; `phase/1` (`:98`) is the plain
156
155
  read.
157
156
 
158
- ## Keepalive — the failure mode is silence
159
-
160
- The contract is spelled out in `lib/chronicle/connections/keep_alive.ex:7-17`:
161
- the kernel pushes a `ConnectionKeepAlive` down the `Connect` server stream once
162
- per second, and for each one **the client must call back the separate unary
163
- `ConnectionKeepAlive` RPC** (`answer/2` at `:56`). A client that only consumes the
164
- stream is evicted once the kernel's `LastSeen` falls more than five seconds
165
- behind, and the kernel then unsubscribes its observers.
166
-
167
- The consequence is stated in that same comment and is worth carrying into any
168
- diagnosis: **reactors and reducers go quiet while the `Connect` stream stays open
169
- and every append keeps working.** Nothing raises. If observers stop firing but
170
- appends succeed, look at the connection before you look at the observer.
171
-
172
- Reconnect is exponential backoff — `:retry_attempts` 5, `:reconnect_base_delay`
173
- 1000 ms, `:reconnect_max_delay` 10000 ms — re-resolving addresses on every
174
- attempt.
157
+ Reconnect never gives up: exponential backoff starts at 1000 ms and caps at
158
+ 10000 ms, re-resolving addresses each time. `:retry_attempts` is ignored.
159
+ Registration failures leave the client in `:connected`, log
160
+ `Chronicle registration failed`, and retry every five seconds. Appends before a
161
+ channel exists return `{:error, :not_connected}`; read model queries wait up to
162
+ 30 seconds for `:registered`.
175
163
 
176
- ## Connection strings
164
+ ## Authentication and TLS
177
165
 
178
- `Chronicle.Connections.ConnectionString` accepts `chronicle://` and
179
- `chronicle+srv://` (`lib/chronicle/connections/connection_string.ex:8`,
180
- validated at `:342`). Default port is `35_000` (`:83`).
166
+ Use `ConnectionString.development()` locally: `default()` supplies **no
167
+ credentials**, so an authentication-required development kernel never lets it
168
+ reach `:registered`. Production uses URL userinfo `client-id:secret@host` or
169
+ `?apiKey=...` (the API key wins when both are given). Load real credentials from
170
+ the application's approved secret mechanism; never log the connection string.
181
171
 
182
- | Function | Line |
183
- | --- | --- |
184
- | `default/0` — `chronicle://localhost:35000` | `:144` |
185
- | `development/0` — adds the dev client credentials | `:154` |
186
- | `parse/1` | `:186` |
187
-
188
- Query parameters include `apiKey`, `disableTls`, `skipTlsValidation`,
189
- `certificatePath`, `certificatePassword`, `authPort`, `loadBalancer`,
190
- `srvNameServer`. A `chronicle+srv://` string accepts only one host and raises
191
- otherwise (`:197-198`).
172
+ **`skip_tls_validation` defaults to `true`.** Production must set
173
+ `skipTlsValidation=false`; a client certificate does not establish server trust.
192
174
 
193
- > **`skip_tls_validation` defaults to `true`** — the struct default at `:112` and
194
- > the query parse at `:214`. TLS is on but the certificate chain is not checked,
195
- > because a development kernel serves a self-signed certificate. **A production
196
- > connection string must carry `?skipTlsValidation=false`.**
175
+ Read [references/connections.md](references/connections.md) when configuring connection strings, mTLS, grpc/Mint options or credential-safe logging, or diagnosing keepalive and quiet observers.
197
176
 
198
177
  ## Defining event types
199
178
 
200
179
  ```elixir
201
- defmodule MyApp.Events.<EventName> do
202
- @moduledoc "<What happened, in the past tense.>"
180
+ # Copyright (c) Cratis. All rights reserved.
181
+ # Licensed under the MIT license. See LICENSE file in the project root for full license information.
182
+
183
+ defmodule MyApp.Events.FundsDeposited do
184
+ @moduledoc "Funds were deposited into an account."
203
185
 
204
- use Chronicle.Events.EventType, id: "<event-name>"
186
+ use Chronicle.Events.EventType, id: "funds-deposited"
205
187
 
206
- defstruct [:<field>, :<other_field>]
188
+ defstruct amount: 0, active: false, title: ""
207
189
  end
208
190
  ```
209
191
 
210
192
  `use Chronicle.Events.EventType` takes `:id` through `Keyword.fetch!`
211
- (`lib/chronicle/events/event_type.ex:68`) — **the id is required**, unlike the
193
+ (`lib/chronicle/events/event_type.ex:71`) — **the id is required**, unlike the
212
194
  .NET, Kotlin, and TypeScript clients where it defaults to the type name. Give it
213
195
  a stable, kebab-case string and never change it. `:generation` defaults to `1`
214
- (`:69`).
196
+ (`:72`).
215
197
 
216
- The macro imports constraint macros into your module (`:79-86`):
198
+ **Use typed defaults on events and read models.** Schemas come from struct
199
+ defaults: `nil` registers as string, numbers as number, booleans as boolean;
200
+ list element schemas use the first default element. Nested structs and concepts
201
+ are descended into (`schemas/json_schema_generator.ex:159-201`).
202
+
203
+ The macro imports constraint macros into your module (`:83-93`):
217
204
  `unique/1`, `unique/2`, `unique_event_type/0`, `unique_event_type/1`,
218
- `remove_constraint/1`, plus `Chronicle.Compliance.pii/1,2` (`:88`). The
205
+ `remove_constraint/1`, plus `Chronicle.Compliance.pii/1,2` and
206
+ `Chronicle.Confidentiality.encrypted/1,2,3`. The
219
207
  equivalent accumulating module attributes `@unique`, `@unique_event_type`,
220
208
  `@remove_constraint` also work.
221
209
 
222
- **Struct fields are sent as camelCase.** `encode_event/1` converts snake_case to
223
- camelCase and `Jason.encode!`s the result
224
- (`lib/chronicle/event_sequences/event_log.ex`).
210
+ **Only top-level event keys are camelCased.** `encode_event/1` transforms them
211
+ before `Jason.encode!` (`event_sequences/event_log.ex:927-933`); nested keys are
212
+ not transformed. Event structs get no `Jason.Encoder` implementation;
213
+ `Chronicle.Concept` does, encoding its wrapped value rather than a wrapper.
225
214
 
226
- > The moduledoc claims Chronicle generates a `Jason.Encoder` implementation
227
- > automatically. There is no `defimpl Jason.Encoder` in the macro — encoding
228
- > happens in `encode_event/1`. Do not rely on the claim.
215
+ Read [references/compliance.md](references/compliance.md) when defining personal data, data subjects, concepts or encrypted operational secrets. `pii` and `encrypted` are not interchangeable and cannot mark the same leaf.
229
216
 
230
217
  Schema evolution is
231
218
  `use Chronicle.Events.Migration, from: {Mod, generation: n}, to: {Mod, generation: n + 1}`
@@ -235,10 +222,11 @@ raises at compile time.
235
222
  ## Appending
236
223
 
237
224
  ```elixir
238
- :ok =
239
- Chronicle.append(book_id, %MyApp.Events.<EventName>{
240
- <field>: "<value>"
241
- })
225
+ case Chronicle.append("account-1", %MyApp.Events.FundsDeposited{amount: 50}) do
226
+ :ok -> :ok
227
+ {:error, {:constraint_violations, violations}} -> {:rejected, violations}
228
+ {:error, reason} -> {:error, reason}
229
+ end
242
230
  ```
243
231
 
244
232
  `Chronicle.append/3` delegates to `Chronicle.EventSequences.EventLog`
@@ -253,46 +241,49 @@ raises at compile time.
253
241
  sequence number, and `append_and_wait_for_completion/3` exists for when you need
254
242
  the outcome.
255
243
 
256
- The other append functions (`append_many/3`, `append_many_for_event_sources/2`, `append_and_wait_for_completion/3`, the `get_*` readers) and the full option list are in the reference.
257
244
  Read [references/append-api.md](references/append-api.md) when you need an append variant, a read-back function, or an append option such as `:event_stream_type`, `:concurrency_scope` or `:tags`.
258
245
 
259
- Errors are normalized to one of two shapes:
260
-
261
- ```elixir
262
- {:error, {:constraint_violations, violations}}
263
- {:error, {:append_errors, errors}}
264
- ```
246
+ Failed appends return `{:error, reason}` (before 3.2.0 rejection could incorrectly
247
+ return `:ok`). Reasons include `{:constraint_violations, violations}`,
248
+ `{:concurrency_violations, violations}`, `{:append_errors, errors}`,
249
+ `:not_connected`, and `{:incompatible_server, response}` from the first append's
250
+ compatibility preflight per channel. Pair the kernel and installed contracts;
251
+ do not blindly retry a timed-out write.
265
252
 
266
253
  **Match on them.** A bare `:ok = Chronicle.append(...)` raises a `MatchError` on
267
254
  a constraint violation, which is a fine choice in a script and the wrong one in a
268
255
  GenServer.
269
256
 
257
+ Read [references/event-sources.md](references/event-sources.md) when declaring named event sources/streams, deriving concurrency scopes or routing mixed-source batches; definitions require Chronicle 19.30.0+.
258
+
270
259
  A unit of work is a process: `Chronicle.begin_unit_of_work/1` starts an `Agent`,
271
260
  and while one is current for the calling process `append`/`append_many` buffer
272
261
  instead of sending, until `UnitOfWork.commit/1` or `rollback/1`.
262
+ `commit/1` returns `:ok | {:error, reason}`. `Chronicle.with_unit_of_work(fun, opts)`
263
+ passes the unit to an arity-one function, commits on return, and raises on commit
264
+ failure. Source/stream options apply to buffered appends too.
273
265
 
274
266
  ## Observing
275
267
 
276
268
  ### Reactors
277
269
 
278
270
  ```elixir
279
- defmodule MyApp.Reactors.<ReactorName> do
271
+ defmodule MyApp.Reactors.DepositLogger do
280
272
  use Chronicle.Reactors.Reactor
273
+ require Logger
281
274
 
282
- alias MyApp.Events.<EventName>
283
-
284
- @handles <EventName>
275
+ alias MyApp.Events.FundsDeposited
276
+ @handles FundsDeposited
285
277
 
286
278
  @impl true
287
- def handle(%<EventName>{}, %{event_source_id: <id>}) do
288
- # side effect here
279
+ def handle(%FundsDeposited{}, %{sequence_number: number}) do
280
+ Logger.info("Deposit observed", sequence_number: number)
289
281
  :ok
290
282
  end
291
283
  end
292
284
  ```
293
285
 
294
- That is the CI-validated snippet
295
- (`Documentation/client-snippets/get-started/common/reactor.md`).
286
+ This follows `Documentation/client-snippets/get-started/common/reactor.md`.
296
287
 
297
288
  - **`@handles` is an accumulating module attribute** declaring the subscription;
298
289
  dispatch is then ordinary Elixir pattern matching in `handle/2`. This is the
@@ -307,36 +298,38 @@ That is the CI-validated snippet
307
298
  - Optional replay callbacks: `on_replay_begin/0`, `on_replay_end/0`,
308
299
  `on_partition_replay_begin/1`, `on_partition_replay_end/1`.
309
300
 
310
- **The context map has exactly five keys** —
311
- `%{event_source_id, sequence_number, occurred, event_store, namespace}`
312
- (`lib/chronicle/reactors/handler.ex:393-397`). The reactor moduledoc also
313
- mentions `:correlation_id`; **it is not in the map**.
301
+ **The reactor context has six keys**: `event_source_id`, `sequence_number`,
302
+ `occurred`, `event_source`, `event_store`, `namespace`
303
+ (`lib/chronicle/reactors/handler.ex:421-428`). `event_source` is the registered
304
+ source name or `nil` for legacy appends. The moduledoc mentions `:correlation_id`,
305
+ but **it is not in the map**. Reducer context differs: `event_source_id`,
306
+ `sequence_number`, `occurred`, `event_source`, `observation_state`
307
+ (`reducers/handler.ex:381-386`).
314
308
 
315
309
  ### Read models and projections
316
310
 
317
311
  ```elixir
318
- defmodule MyApp.ReadModels.<ReadModelName> do
312
+ defmodule MyApp.ReadModels.AccountBalance do
319
313
  use Chronicle.ReadModels.ReadModel
314
+ defstruct id: "", balance: 0
320
315
 
321
- defstruct id: nil, <field>: nil, <flag>: false
322
-
323
- from MyApp.Events.<EventName>,
324
- set: [id: :event_source_id, <field>: :<event_field>]
325
-
326
- from MyApp.Events.<OtherEvent>,
327
- set: [<flag>: true]
316
+ from(MyApp.Events.FundsDeposited,
317
+ set: [id: :event_source_id],
318
+ add: [balance: :amount]
319
+ )
328
320
  end
329
321
  ```
330
322
 
331
- That shape is the CI-validated snippet
332
- (`Documentation/client-snippets/get-started/common/book-read-model.md`).
323
+ This is the model-bound shape; use typed defaults for its registered schema.
333
324
 
334
325
  The DSL macros are `from/1`, `from/2`, `join/2`, `removed_with/2`, `from_every/1`.
335
326
  `from/2` options: `:key` (defaults to `"$eventSourceId"`), `:parent_key`, `:set`,
336
- `:add`, `:subtract`, `:count`.
327
+ `:add`, `:subtract`, `:count`. `join/2` requires `:on`.
328
+
329
+ Read [references/projections.md](references/projections.md) when choosing `passive`, `not_rewindable`, `event_sequence`, `no_auto_map`, composite/event-context keys or dictionary counters. Snake_case field atoms now map correctly; no camelCase-string workaround is needed.
337
330
 
338
331
  > **The read model id sent to the kernel is the last module segment** —
339
- > `Module.split() |> List.last()` at `lib/chronicle/read_models/read_model.ex:148`.
332
+ > `Module.split() |> List.last()` at `lib/chronicle/read_models/read_model.ex:197`.
340
333
  > `MyApp.ReadModels.Account` registers as `"Account"`, so two read models with the
341
334
  > same final segment collide. Pass `id:` to disambiguate.
342
335
 
@@ -348,28 +341,45 @@ process**, so the reduction is Elixir code you own.
348
341
 
349
342
  #### Variants — mutually exclusive read models for one entity's lifecycle
350
343
 
351
- Requires `cratis_chronicle` `3.4.0` or later (newer than this skill's `3.1.0` baseline). `variant_of/2` requires `:key`; a variant with no `enters_on` raises `Chronicle.Projections.VariantMustDeclareEntersOnEvent` at registration.
344
+ Requires `cratis_chronicle` `3.4.0` or later; verified at `3.10.2`. `variant_of/2` requires `:key`; a variant with no `enters_on` raises `Chronicle.Projections.VariantMustDeclareEntersOnEvent` at registration.
352
345
 
353
346
  Read [references/variants.md](references/variants.md) when an entity has mutually exclusive lifecycle shapes (for example a backlog entry that becomes a pull request) and you need variant read models or a `GlobalHandler`.
354
347
 
355
348
  Querying (`lib/chronicle/read_models.ex`):
356
349
 
357
350
  ```elixir
358
- {:ok, books} = Chronicle.all(MyApp.ReadModels.<ReadModelName>)
359
- {:ok, book} = Chronicle.read_model(MyApp.ReadModels.<ReadModelName>, book_id)
351
+ {:ok, accounts} = Chronicle.all(MyApp.ReadModels.AccountBalance)
352
+ {:ok, account} = Chronicle.read_model(MyApp.ReadModels.AccountBalance, "account-1")
360
353
  ```
361
354
 
362
355
  `Chronicle.read_model/3` delegates to `ReadModels.get/3` (`lib/chronicle.ex:211`,
363
- `read_models.ex:245-246`), returning `{:ok, struct() | nil} | {:error, term()}`.
364
- `Chronicle.all/2` delegates to `ReadModels.get_instances/2`
365
- (`lib/chronicle.ex:219`, `read_models.ex:314-315`).
356
+ `read_models.ex:251-252`), returning `{:ok, struct() | nil} | {:error, term()}`.
357
+ `Chronicle.all/2` delegates to `ReadModels.all/2`
358
+ (`lib/chronicle.ex:219`, `read_models.ex:320-330`).
359
+
360
+ Use `Chronicle.ReadModels.query(MyApp.ReadModels.AccountBalance, page: 0)` for paging:
361
+ `:page` is zero-based (default `0`), `:page_size` defaults to `50`, and
362
+ `:occurrence` selects a replay container. Before 3.5.1, page 0 was rejected and
363
+ the default was 1; **page 1 now means the second page**. `ReadModels.snapshots/3`,
364
+ `occurrences/2`, and `definitions/1` expose history, replay containers, and
365
+ registered definitions.
366
366
 
367
367
  **Live updates arrive as messages, not as a stream.** `ReadModels.watch/2`
368
- (`read_models.ex:593`) sends
368
+ (`read_models.ex:608`) sends
369
369
  `{:chronicle_read_model_changed, module, %Changeset{}}` and
370
- `{:chronicle_read_model_watch_error, module, reason}` to the calling process. This
371
- is the Elixir analogue of the other clients' observable APIs, and it means the
372
- receiving process must have a `handle_info` for both.
370
+ `{:chronicle_read_model_watch_error, module, reason}` to the calling process. The receiving process needs a `handle_info` for both.
371
+
372
+ ## Operational inspection
373
+
374
+ `Chronicle.Observers.get_all/1` lists namespace observers; `remove/2` removes an
375
+ orphaned observer across the store, refuses running/subscribed observers in any
376
+ namespace, and leaves read model data intact (`observers.ex:84,120`). Obtain
377
+ explicit authority before removal and inspect `RemovalResult.outcome` —
378
+ `{:ok, result}` alone does not mean removed. `Chronicle.FailedPartitions` and
379
+ `Chronicle.Jobs` provide failure/job inspection; `Jobs.get/2` lists then finds
380
+ client-side. Observer types include `:reactor`, `:projection`, `:reducer`,
381
+ `:external`; states include `:active`, `:suspended`, `:replaying`, `:disconnected`,
382
+ `:quarantined` and `:unknown`.
373
383
 
374
384
  ## Idioms worth knowing
375
385
 
@@ -382,8 +392,8 @@ receiving process must have a `handle_info` for both.
382
392
  - **Discovery is compile-time reflection.** The `use` macros generate
383
393
  `__chronicle_*__/1` functions via `__before_compile__`, and discovery is
384
394
  `function_exported?/3` over the application's modules — not runtime scanning.
385
- - **No telemetry.** The client emits no `:telemetry` events; `telemetry` appears
386
- only as a transitive dependency of `grpc`. Logging is plain `Logger`.
395
+ - **No client-owned telemetry events.** `telemetry` is a direct dependency;
396
+ transport failure detection subscribes to grpc events. Logging is `Logger`.
387
397
  - **No formatter export.** `.formatter.exs` declares no `locals_without_parens`
388
398
  for `from`, `join`, `removed_with`, `from_every`, `pii`, `subject`, `unique`, or
389
399
  `unique_event_type`, and there is no `import_deps: [:cratis_chronicle]` to
@@ -393,28 +403,13 @@ receiving process must have a `handle_info` for both.
393
403
 
394
404
  ## Common pitfalls
395
405
 
396
- | Pitfall | Why it bites |
397
- | --- | --- |
398
- | Copying the `v2.2.0` root `README.md` | Its module names do not exist; the `3.x` README is correct |
399
- | Using `Chronicle.Concept` on `2.2.0` | It ships from `3.0.0`; on `2.2.0` annotate fields with `pii/1,2` instead |
400
- | Copying the dependency line from the README | It lags the published version; take the version from hex.pm |
401
- | Quoting the `VERSION` file | It is a `0.0.5` build-time placeholder |
402
- | Putting configuration in `config.exs` | The client reads no application env; options are child-spec keywords |
403
- | Omitting `:otp_app` | Discovery falls back to scanning every loaded module |
404
- | Assuming the namespace default is `"default"` | It is `"Default"`; the moduledoc is wrong |
405
- | `:ok = Chronicle.append(...)` in a server | A constraint violation returns `{:error, _}` and raises `MatchError` |
406
- | Waiting for `:connected` | Observers attach at `:registered` |
407
- | Reading `:correlation_id` from a reactor context | The map has five keys and that is not one |
408
- | Two read models with the same final module segment | The id is the last segment only |
409
- | Appending from a `Task` and expecting the correlation id | Ambient context is per process |
410
- | Treating quiet observers as "no events" | Keepalive eviction silences observers while appends still succeed |
411
- | Shipping the default TLS behavior | `skip_tls_validation` defaults to `true` |
412
- | Forgetting `global_handlers:` or `:otp_app` discovery | A `GlobalHandler` module is never merged into its variants unless registered one way or the other |
413
- | A shared handler mapping a field one variant lacks | `GlobalHandlerPropertyNotOnVariant` at registration, not a silently skipped mapping |
406
+ Read [references/pitfalls.md](references/pitfalls.md) when troubleshooting discovery, defaults, process context, variant registration or older-version examples.
414
407
 
415
408
  ## Verify
416
409
 
417
- - `mix deps.get` resolves `cratis_chronicle` to the `2.x` version you intended.
410
+ - Elixir 1.18+ and `mix deps.get` resolve the intended `3.x` client; contracts
411
+ and kernel are compatible (event source definitions need kernel 19.30.0+).
412
+ - Local development uses `ConnectionString.development()` or explicit credentials.
418
413
  - `Chronicle.Client` is in the supervision tree with an explicit `:otp_app`, and
419
414
  the tree starts clean.
420
415
  - The lifecycle reaches `:registered` before the application claims readiness.
@@ -425,6 +420,7 @@ receiving process must have a `handle_info` for both.
425
420
  - Read model module names have distinct final segments, or explicit ids.
426
421
  - Every variant group has at least one `enters_on` per variant, and every
427
422
  `GlobalHandler` member exists on every variant it targets.
428
- - Every code example was copied from `Documentation/client-snippets/`, not from
429
- the README.
423
+ - Production logging filters credential-bearing gRPC/Mint crash reports; see
424
+ the connections reference for limits.
425
+ - Examples match the APIs and schema defaults at the installed tag.
430
426
  - `mix compile --warnings-as-errors` and `mix test` are clean.
@@ -1,19 +1,40 @@
1
+ <!-- Copyright (c) Cratis. All rights reserved. -->
2
+ <!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
3
+
1
4
  # Append API
2
5
 
3
- ## Append functions and options
6
+ Verified at `Cratis/Chronicle.Elixir v3.10.2`; paths below are under `Source/chronicle/lib/chronicle/`.
7
+
8
+ ## Append functions and readers
4
9
 
5
- | Function | Arity | Line in `event_log.ex` |
10
+ | Function on `Chronicle.EventSequences.EventLog` | Arguments / result | Line in `event_log.ex` |
6
11
  | --- | --- | --- |
7
- | `append/3` | `(event_source_id, event, opts)` | `:99` |
8
- | `append_many/3` | `(event_source_id, events, opts)` | `:120` |
9
- | `append_many_for_event_sources/2` | `(events, opts)` | `:155` |
10
- | `append_and_wait_for_completion/3` | returns `{:ok, %{success: _, failed_partitions: _}}` | `:215` |
11
- | `get_for_event_source/2` | | `:326` |
12
- | `get_from_sequence_number/2` | | `:369` |
13
- | `get_tail_sequence_number/2` | | `:408` |
14
-
15
- Append options (`event_log.ex:79-94`, plus `:occurred` read at `:720`): `:client`, `:namespace`,
16
- `:event_sequence_id` (default `"event-log"`), `:event_source_type` (default
17
- `"Default"`), `:event_stream_type` (default **`"All"`**), `:event_stream_id`
18
- (default `"Default"`), `:tags`, `:subject`, `:correlation_id`, `:identity`,
19
- `:causation`, `:concurrency_scope`, `:occurred`.
12
+ | `append/3` | `(event_source_id, event, opts)` → `:ok \| {:error, reason}` | `:126` |
13
+ | `append_many/3` | `(event_source_id, events, opts)` → `:ok \| {:error, reason}` | `:147` |
14
+ | `append_many_for_event_sources/2` | `(EventForEventSourceId entries, opts)` → `:ok \| {:error, reason}` | `:184` |
15
+ | `append_and_wait_for_completion/3` | `(event_source_id, event, opts)` → `{:ok, %{success: _, failed_partitions: _}} \| {:error, reason}` | `:264` |
16
+ | `get_for_event_source/2` | `(event_source_id, opts)` | `:402` |
17
+ | `get_from_sequence_number/2` | `(sequence_number, opts)` | `:445` |
18
+ | `get_tail_sequence_number/2` | `(event_source_id_or_nil, opts)` | `:484` |
19
+ | `get_next_sequence_number/2` | `(event_source_id_or_nil, opts)` | `:502` |
20
+ | `get_tail_sequence_number_for_observer/2` | `(observer_module, opts)` | `:523` |
21
+ | `complete_stream/3` | `(event_stream_type, event_stream_id, opts)` | `:548` |
22
+ | `redact/3` | `(sequence_number, reason, opts)` | `:587` |
23
+ | `redact_for_event_source/4` | `(event_source_id, reason, event_types, opts)` | `:622` |
24
+ | `has_events_for?/2` | `(event_source_id, opts)` | `:658` |
25
+
26
+ Read operations observe state; completion and redaction mutate it and require authority for the specific target. `append_many` variants are atomic batches. The cross-source variant uses entries for per-event routing/metadata and accepts batch `:client`, `:namespace`, `:event_sequence_id` and source/stream defaults.
27
+
28
+ ## Options
29
+
30
+ Append options (`event_log.ex:79-113`): `:client`, `:namespace`, `:event_sequence_id` (default `"event-log"`), `:event_source_type`, `:event_stream_type`, `:event_stream_id`, `:event_source`, `:event_stream`, `:tags`, `:subject`, `:correlation_id`, `:identity`, `:causation`, `:concurrency_scope`, `:occurred`.
31
+
32
+ Omitted, `nil`, or empty routing types/ids travel as empty strings; the **kernel**, not client-side defaults, resolves them to `"Default"` / `"All"` / `"Default"`. Nonempty values are exact. Concurrency filters remain independent of routing.
33
+
34
+ Read [event-sources.md](event-sources.md) for definitions, stream routing and derived guards. Definition concurrency applies only without an explicit scope. Incompatible derived guards for one id fail with `{:error, {:incompatible_concurrency_scopes, id, guards}}` before sending.
35
+
36
+ ## Errors and completion
37
+
38
+ `append_response.ex:65-83` returns `{:error, {:constraint_violations, violations}}`, `{:error, {:concurrency_violations, violations}}` or `{:error, {:append_errors, errors}}` on rejection. Channel/preflight errors include `{:error, :not_connected}` and `{:error, {:incompatible_server, response}}`. A transport timeout does not prove that no event was stored.
39
+
40
+ `append_and_wait_for_completion/3` has **no many-event variant**. `{:ok, result}` does not imply every observer succeeded: inspect `result.success` and `failed_partitions`. Its wait happens **after** the append (`event_log.ex:267-275`), so `{:error, reason}` can follow a stored event if waiting fails. Do not retry the write blindly; reconcile the stored outcome first.
@@ -0,0 +1,32 @@
1
+ <!-- Copyright (c) Cratis. All rights reserved. -->
2
+ <!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
3
+
4
+ # Personal data, concepts and operational secrets
5
+
6
+ Verified at `Cratis/Chronicle.Elixir v3.10.2`: `Source/chronicle/lib/chronicle/{concept,compliance,confidentiality}.ex`, `events/event_type.ex:92-93`, and `read_models/read_model.ex`.
7
+
8
+ `pii/1,2` marks personal data for compliance encryption and right-to-erasure. `encrypted/1,2,3` (since 3.5.0) marks non-personal operational secrets for separate confidentiality encryption with no compliance erasure operation. Its scopes are `:subject` (default), `:namespace`, `:global`. They are not interchangeable.
9
+
10
+ ```elixir
11
+ # Copyright (c) Cratis. All rights reserved.
12
+ # Licensed under the MIT license. See LICENSE file in the project root for full license information.
13
+
14
+ defmodule MyApp.PersonName do
15
+ use Chronicle.Concept, type: :string
16
+ pii("Legal name of the data subject")
17
+ end
18
+
19
+ defmodule MyApp.Events.PartnerIntegrationConfigured do
20
+ use Chronicle.Events.EventType, id: "partner-integration-configured"
21
+ defstruct contact_name: %MyApp.PersonName{}, email: "", api_key: ""
22
+
23
+ pii(:email, "Partner contact's email address")
24
+ encrypted(:api_key, :subject, "Partner API key")
25
+ end
26
+ ```
27
+
28
+ `Chronicle.Concept` ships on Hex from **3.0.0**, not 2.2.0 (the 2.3.0 tag was unpublished). `type:` is required: `:string`, `:integer`, `:float`, `:boolean`, `:uuid`. Typed concept defaults let the schema generator carry the wrapped type and classification onto every leaf that uses it. The concept's `Jason.Encoder` serializes only its wrapped value.
29
+
30
+ On a concept use `pii/0,1` to classify its sole value, not the field-oriented `Chronicle.Compliance.pii/1,2`. Concept `encrypted/0,1,2` similarly marks that value. Neither classification is allowed on a concept with `event_source_id: true`; use a non-sensitive surrogate stream identity instead. Both classifications on one schema leaf raise `Chronicle.Confidentiality.PiiAndEncryptedCombinedNotSupported`.
31
+
32
+ For a read model whose subject is not its `:id`, declare `subject(:customer_id)` in the module using `Chronicle.ReadModels.ReadModel`. It identifies the natural person for PII release; there is only one subject declaration per module. `subject/1` is not imported by `EventType`; append-time `:subject` is an append option, not this read-model macro.