@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.
- package/package/corpus/agents/security-reviewer.md +1 -0
- package/package/corpus/agents/spec-writer.md +1 -1
- package/package/corpus/harnesses/pi/extensions/shared/rules.ts +3 -1
- package/package/corpus/hooks/scripts/cratis-nuget-pins.txt +7 -6
- package/package/corpus/hooks/scripts/cratis-release-notes-reviewed.cjs +7 -6
- package/package/corpus/hooks/scripts/cratis-store-mutations.json +7 -3
- package/package/corpus/product-sync.json +896 -0
- package/package/corpus/prompts/add-business-rule.prompt.md +1 -1
- package/package/corpus/prompts/ship-changes.prompt.md +2 -2
- package/package/corpus/rules/ai-distribution.md +31 -3
- package/package/corpus/rules/application-profile.md +2 -1
- package/package/corpus/rules/components.md +66 -7
- package/package/corpus/rules/concepts.md +11 -3
- package/package/corpus/rules/csharp.md +3 -1
- package/package/corpus/rules/dialogs.md +9 -0
- package/package/corpus/rules/efcore.md +1 -1
- package/package/corpus/rules/elixir.md +49 -0
- package/package/corpus/rules/framework.md +5 -3
- package/package/corpus/rules/general.md +1 -0
- package/package/corpus/rules/glossary.md +4 -4
- package/package/corpus/rules/go-engineering.md +60 -0
- package/package/corpus/rules/go.md +115 -0
- package/package/corpus/rules/java.md +5 -2
- package/package/corpus/rules/kotlin.md +7 -5
- package/package/corpus/rules/orleans.md +65 -9
- package/package/corpus/rules/profiles.md +43 -6
- package/package/corpus/rules/pull-requests.md +3 -3
- package/package/corpus/rules/react.md +8 -1
- package/package/corpus/rules/reactors.md +27 -3
- package/package/corpus/rules/specs.csharp.md +11 -4
- package/package/corpus/rules/specs.scenarios.csharp.md +35 -4
- package/package/corpus/rules/specs.typescript.md +2 -1
- package/package/corpus/rules/storybook.md +1 -1
- package/package/corpus/rules/typescript.md +1 -1
- package/package/corpus/rules/vertical-slices.md +37 -5
- package/package/corpus/skills/cratis-application-react-specifications/SKILL.md +4 -2
- package/package/corpus/skills/cratis-application-slice-specifications/SKILL.md +18 -8
- package/package/corpus/skills/cratis-application-slice-specifications/references/query-and-decision-scenarios.md +65 -0
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/SKILL.md +53 -57
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/authentication.md +38 -42
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/authorization.md +18 -7
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/authproxy.md +30 -0
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/frontend.md +12 -9
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/local-development.md +9 -9
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/observable-emission-guards.md +8 -5
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/tenancy.md +20 -4
- package/package/corpus/skills/cratis-arc-command/SKILL.md +32 -10
- package/package/corpus/skills/cratis-arc-command/references/command-result.md +12 -5
- package/package/corpus/skills/cratis-arc-command/references/decisions-and-routing.md +95 -0
- package/package/corpus/skills/cratis-arc-command/references/generated-values.md +3 -2
- package/package/corpus/skills/cratis-arc-command/references/handler-shapes.md +8 -8
- package/package/corpus/skills/cratis-arc-command/references/proxy-generation.md +22 -3
- package/package/corpus/skills/cratis-arc-command/references/read-model-injection.md +13 -1
- package/package/corpus/skills/cratis-arc-command-execution/SKILL.md +19 -9
- package/package/corpus/skills/cratis-arc-command-kotlin/SKILL.md +44 -18
- package/package/corpus/skills/cratis-arc-command-kotlin/references/read-model-naming.md +29 -0
- package/package/corpus/skills/cratis-arc-command-operation/SKILL.md +10 -9
- package/package/corpus/skills/cratis-arc-command-operation/references/execution-and-recovery.md +2 -2
- package/package/corpus/skills/cratis-arc-command-operation/references/testing.md +4 -3
- package/package/corpus/skills/cratis-arc-command-typescript/SKILL.md +42 -22
- package/package/corpus/skills/cratis-arc-command-typescript/references/chronicle-events.md +36 -5
- package/package/corpus/skills/cratis-arc-command-typescript/references/command-operations.md +114 -0
- package/package/corpus/skills/cratis-arc-command-typescript/references/hosting-and-storage.md +37 -16
- package/package/corpus/skills/cratis-arc-command-typescript/references/identity-and-introspection.md +88 -0
- package/package/corpus/skills/cratis-arc-command-typescript/references/observability-and-host-scopes.md +25 -0
- package/package/corpus/skills/cratis-arc-command-typescript/references/proxy-generation.md +35 -4
- package/package/corpus/skills/cratis-arc-command-typescript/references/slice-layout.md +11 -0
- package/package/corpus/skills/cratis-arc-command-typescript/verification.json +8 -1
- package/package/corpus/skills/cratis-arc-command-validation/SKILL.md +49 -19
- package/package/corpus/skills/cratis-arc-ef-core-migration/SKILL.md +12 -6
- package/package/corpus/skills/cratis-arc-go/SKILL.md +148 -0
- package/package/corpus/skills/cratis-arc-go/references/queries.md +80 -0
- package/package/corpus/skills/cratis-arc-hosting/SKILL.md +96 -0
- package/package/corpus/skills/cratis-arc-hosting/references/integrations-and-publish.md +80 -0
- package/package/corpus/skills/cratis-arc-identity-and-tenancy-kotlin/SKILL.md +137 -0
- package/package/corpus/skills/cratis-arc-observable-query-http/SKILL.md +20 -2
- package/package/corpus/skills/cratis-arc-query-kotlin/SKILL.md +26 -6
- package/package/corpus/skills/cratis-arc-query-paging/SKILL.md +25 -20
- package/package/corpus/skills/cratis-arc-query-typescript/SKILL.md +32 -6
- package/package/corpus/skills/cratis-arc-query-typescript/references/storage-observation-and-compliance.md +66 -0
- package/package/corpus/skills/cratis-arc-query-typescript/verification.json +5 -1
- package/package/corpus/skills/cratis-arc-react-page/SKILL.md +24 -13
- package/package/corpus/skills/cratis-arc-react-page/references/data-page.md +20 -10
- package/package/corpus/skills/cratis-arc-react-page/references/data-tables.md +17 -3
- package/package/corpus/skills/cratis-arc-react-page/references/dialogs.md +14 -3
- package/package/corpus/skills/cratis-arc-react-page/references/from-screenplay.md +6 -1
- package/package/corpus/skills/cratis-arc-react-page/references/provenance.md +1 -1
- package/package/corpus/skills/cratis-arc-react-page/references/queries-and-commands.md +11 -1
- package/package/corpus/skills/cratis-arc-react-page/verification.json +6 -1
- package/package/corpus/skills/cratis-arc-spring-data-kotlin/SKILL.md +163 -0
- package/package/corpus/skills/cratis-arc-testing-kotlin/SKILL.md +131 -0
- package/package/corpus/skills/cratis-arc-validation-kotlin/SKILL.md +44 -11
- package/package/corpus/skills/cratis-arc-validation-typescript/SKILL.md +5 -3
- package/package/corpus/skills/cratis-chronicle-cli-operations/SKILL.md +79 -25
- package/package/corpus/skills/cratis-chronicle-cli-operations/references/command-effects.md +57 -0
- package/package/corpus/skills/cratis-chronicle-client-dotnet/SKILL.md +87 -99
- package/package/corpus/skills/cratis-chronicle-client-dotnet/references/additional-surfaces.md +65 -0
- package/package/corpus/skills/cratis-chronicle-client-dotnet/references/client-construction.md +42 -0
- package/package/corpus/skills/cratis-chronicle-client-dotnet/references/compatibility-check.md +12 -0
- package/package/corpus/skills/cratis-chronicle-client-dotnet/references/discovery.md +43 -19
- package/package/corpus/skills/cratis-chronicle-client-dotnet/references/hosting.md +29 -1
- package/package/corpus/skills/cratis-chronicle-client-elixir/SKILL.md +158 -162
- package/package/corpus/skills/cratis-chronicle-client-elixir/references/append-api.md +36 -15
- package/package/corpus/skills/cratis-chronicle-client-elixir/references/compliance.md +32 -0
- package/package/corpus/skills/cratis-chronicle-client-elixir/references/connections.md +56 -0
- package/package/corpus/skills/cratis-chronicle-client-elixir/references/event-sources.md +64 -0
- package/package/corpus/skills/cratis-chronicle-client-elixir/references/pitfalls.md +25 -0
- package/package/corpus/skills/cratis-chronicle-client-elixir/references/projections.md +48 -0
- package/package/corpus/skills/cratis-chronicle-client-elixir/references/upgrading.md +34 -0
- package/package/corpus/skills/cratis-chronicle-client-elixir/references/variants.md +13 -5
- package/package/corpus/skills/cratis-chronicle-client-elixir/verification.json +23 -0
- package/package/corpus/skills/cratis-chronicle-client-go/SKILL.md +162 -0
- package/package/corpus/skills/cratis-chronicle-client-go/references/projections.md +73 -0
- package/package/corpus/skills/cratis-chronicle-client-kotlin/SKILL.md +87 -88
- package/package/corpus/skills/cratis-chronicle-client-kotlin/references/connection-lifecycle.md +13 -0
- package/package/corpus/skills/cratis-chronicle-client-kotlin/references/discovery-and-registration.md +14 -4
- package/package/corpus/skills/cratis-chronicle-client-kotlin/references/event-sources.md +65 -0
- package/package/corpus/skills/cratis-chronicle-client-kotlin/references/options.md +29 -0
- package/package/corpus/skills/cratis-chronicle-client-kotlin/references/spring-boot.md +13 -0
- package/package/corpus/skills/cratis-chronicle-client-kotlin/references/variants.md +5 -4
- package/package/corpus/skills/cratis-chronicle-client-typescript/SKILL.md +165 -156
- package/package/corpus/skills/cratis-chronicle-client-typescript/references/read-models-and-projections.md +54 -11
- package/package/corpus/skills/cratis-chronicle-client-typescript/references/testing.md +126 -0
- package/package/corpus/skills/cratis-chronicle-client-typescript/references/variants.md +3 -5
- package/package/corpus/skills/cratis-chronicle-client-typescript/verification.json +19 -0
- package/package/corpus/skills/cratis-chronicle-compliance/SKILL.md +36 -13
- package/package/corpus/skills/cratis-chronicle-decision-reads/SKILL.md +110 -0
- package/package/corpus/skills/cratis-chronicle-decision-reads/references/admission-and-ownership.md +57 -0
- package/package/corpus/skills/cratis-chronicle-decision-reads/verification.json +12 -0
- package/package/corpus/skills/cratis-chronicle-event-constraints/SKILL.md +58 -19
- package/package/corpus/skills/cratis-chronicle-event-constraints/references/closing-streams.md +73 -0
- package/package/corpus/skills/cratis-chronicle-event-modeling/SKILL.md +32 -3
- package/package/corpus/skills/cratis-chronicle-event-specifications/SKILL.md +18 -5
- package/package/corpus/skills/cratis-chronicle-event-type-migration/SKILL.md +32 -2
- package/package/corpus/skills/cratis-chronicle-hosting/SKILL.md +134 -0
- package/package/corpus/skills/cratis-chronicle-hosting/references/operations.md +89 -0
- package/package/corpus/skills/cratis-chronicle-hosting/verification.json +14 -0
- package/package/corpus/skills/cratis-chronicle-mcp-inspection/SKILL.md +93 -66
- package/package/corpus/skills/cratis-chronicle-mcp-inspection/references/blocked-tools.md +21 -7
- package/package/corpus/skills/cratis-chronicle-mcp-inspection/references/deployment.md +77 -0
- package/package/corpus/skills/cratis-chronicle-mcp-inspection/references/observational-tools.md +46 -4
- package/package/corpus/skills/cratis-chronicle-multi-tenancy/SKILL.md +15 -1
- package/package/corpus/skills/cratis-chronicle-projection/SKILL.md +44 -10
- package/package/corpus/skills/cratis-chronicle-projection/references/fluent-builder.md +7 -1
- package/package/corpus/skills/cratis-chronicle-projection/references/model-bound-attributes.md +8 -0
- package/package/corpus/skills/cratis-chronicle-reactor/SKILL.md +85 -105
- package/package/corpus/skills/cratis-chronicle-reactor/references/specifications.md +20 -1
- package/package/corpus/skills/cratis-chronicle-read-model/SKILL.md +2 -2
- package/package/corpus/skills/cratis-chronicle-read-model/references/queries.md +35 -16
- package/package/corpus/skills/cratis-chronicle-read-model-specifications/SKILL.md +15 -3
- package/package/corpus/skills/cratis-chronicle-reducer/SKILL.md +23 -4
- package/package/corpus/skills/cratis-chronicle-web-workbench/SKILL.md +40 -15
- package/package/corpus/skills/cratis-cli-terminal-workbench/SKILL.md +20 -6
- package/package/corpus/skills/cratis-code-review/SKILL.md +25 -3
- package/package/corpus/skills/cratis-components-accessibility/SKILL.md +20 -4
- package/package/corpus/skills/cratis-components-schema-editor/SKILL.md +40 -28
- package/package/corpus/skills/cratis-components-schema-editor/references/tree-layout.md +62 -0
- package/package/corpus/skills/cratis-components-schema-editor/verification.json +14 -0
- package/package/corpus/skills/cratis-components-stepper-command-dialog/SKILL.md +16 -8
- package/package/corpus/skills/cratis-components-styling/SKILL.md +57 -20
- package/package/corpus/skills/cratis-components-styling/verification.json +13 -0
- package/package/corpus/skills/cratis-components-toolbar/SKILL.md +37 -7
- package/package/corpus/skills/cratis-components-toolbar/verification.json +12 -0
- package/package/corpus/skills/cratis-engineering-csharp-conventions/SKILL.md +6 -0
- package/package/corpus/skills/cratis-engineering-csharp-conventions/references/exceptions-logging-and-di.md +5 -3
- package/package/corpus/skills/cratis-fundamentals-concept/SKILL.md +19 -6
- package/package/corpus/skills/cratis-fundamentals-concept/references/typescript-concepts.md +97 -0
- package/package/corpus/skills/cratis-fundamentals-concept/verification.json +4 -1
- package/package/corpus/skills/cratis-fundamentals-concept-go/SKILL.md +112 -0
- package/package/corpus/skills/cratis-fundamentals-type-discovery/SKILL.md +54 -17
- package/package/corpus/skills/cratis-fundamentals-type-discovery/verification.json +14 -0
- package/package/corpus/skills/cratis-lens-browser-extension/SKILL.md +55 -28
- package/package/corpus/skills/cratis-performance-review/SKILL.md +5 -2
- package/package/corpus/skills/cratis-release-notes/SKILL.md +3 -1
- package/package/corpus/skills/cratis-screenplay-automations-and-translations/SKILL.md +5 -4
- package/package/corpus/skills/cratis-screenplay-command-surface/SKILL.md +7 -11
- package/package/corpus/skills/cratis-screenplay-command-surface/references/compliance.md +26 -6
- package/package/corpus/skills/cratis-screenplay-command-surface/references/enum-numbers.md +4 -2
- package/package/corpus/skills/cratis-screenplay-command-surface/references/generated-values-and-responses.md +4 -1
- package/package/corpus/skills/cratis-screenplay-command-surface/verification.json +7 -1
- package/package/corpus/skills/cratis-screenplay-event-modeling/SKILL.md +3 -2
- package/package/corpus/skills/cratis-screenplay-event-modeling/references/parsed-not-runnable.md +6 -2
- package/package/corpus/skills/cratis-screenplay-legacy-extraction/SKILL.md +1 -0
- package/package/corpus/skills/cratis-screenplay-legacy-extraction/references/generate-notes.md +34 -4
- package/package/corpus/skills/cratis-screenplay-model-authoring/SKILL.md +17 -24
- package/package/corpus/skills/cratis-screenplay-model-authoring/references/language-reference.md +1 -1
- package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-loop.md +19 -2
- package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-tools.md +11 -3
- package/package/corpus/skills/cratis-screenplay-model-authoring/references/property-links.md +90 -4
- package/package/corpus/skills/cratis-screenplay-model-authoring/verification.json +19 -2
- package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/gap-fill-handoff.md +3 -1
- package/package/corpus/skills/cratis-screenplay-scenario-coverage/SKILL.md +3 -1
- package/package/corpus/skills/cratis-screenplay-specifications/references/examples-and-routes.md +48 -0
- package/package/corpus/skills/cratis-screenplay-specifications/verification.json +3 -1
- package/package/corpus/skills/cratis-screenplay-streams-and-consistency/SKILL.md +4 -2
- package/package/corpus/skills/cratis-screenplay-streams-and-consistency/references/streams-example.md +5 -4
- package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +8 -6
- package/package/corpus/skills/cratis-screenplay-toolchain/references/cheat-sheet-example.md +8 -2
- package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +4 -2
- package/package/corpus/skills/cratis-screenplay-toolchain/references/doc-contradictions.md +7 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +24 -11
- package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +10 -4
- package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.json +1543 -131
- package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.version +1 -1
- package/package/corpus/skills/cratis-screenplay-toolchain/references/verdicts.md +9 -3
- package/package/corpus/skills/cratis-screenplay-toolchain/references/versions.md +23 -7
- package/package/corpus/skills/cratis-screenplay-toolchain/verification.json +1 -1
- package/package/corpus/skills/cratis-screenplay-ui-composition/SKILL.md +2 -0
- package/package/corpus/skills/cratis-screenplay-ui-composition/references/screen-composition-contract.md +27 -9
- package/package/corpus/skills/cratis-security-review/SKILL.md +9 -3
- package/package/corpus/skills/cratis-security-review/references/arc-boundaries.md +59 -0
- package/package/corpus/skills/cratis-specification-by-example/SKILL.md +7 -0
- package/package/corpus/skills/cratis-specifications-csharp/SKILL.md +43 -11
- package/package/corpus/skills/cratis-specifications-csharp/references/application-scenarios.md +16 -4
- package/package/corpus/skills/cratis-specifications-csharp/references/csharp-patterns.md +18 -5
- package/package/corpus/skills/cratis-specifications-csharp/references/integration-specs.md +21 -0
- package/package/corpus/skills/cratis-specifications-csharp/references/shared-lifecycle.md +34 -0
- package/package/corpus/skills/cratis-specifications-csharp/verification.json +13 -0
- package/package/corpus/skills/cratis-specifications-typescript/SKILL.md +14 -5
- package/package/corpus/skills/cratis-specifications-typescript/verification.json +12 -0
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +8 -2
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +6 -3
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/rendered-application.md +10 -1
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/scene-runtime.md +75 -0
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/verification.json +5 -0
- package/package/corpus/skills/cratis-studio-mcp-safety-guidance/SKILL.md +14 -1
- package/package/profile-catalog.json +68 -1
- package/package.json +1 -1
- package/src/index.ts +3 -1
|
@@ -0,0 +1,56 @@
|
|
|
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
|
+
# Connections, trust and resilience
|
|
5
|
+
|
|
6
|
+
Verified at `Cratis/Chronicle.Elixir v3.10.2`: `Source/chronicle/lib/chronicle/connections/{connection_string,connection,keep_alive,client_certificate,transport}.ex`, `registration/coordinator.ex`, and `Documentation/connections/{connection-strings,resilience,crash-reports}.md`.
|
|
7
|
+
|
|
8
|
+
## Connection strings and authentication
|
|
9
|
+
|
|
10
|
+
`Chronicle.Connections.ConnectionString` accepts `chronicle://` and `chronicle+srv://`; the default port is `35000`. Multiple comma-separated hosts are resolved again on reconnect; SRV accepts only one host (`connection_string.ex:198-199`).
|
|
11
|
+
|
|
12
|
+
| Function | Line in `connection_string.ex` |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| `default/0` — localhost, **no credentials** | `:145` |
|
|
15
|
+
| `development/0` — well-known local development credentials | `:155` |
|
|
16
|
+
| `parse/1` | `:187` |
|
|
17
|
+
|
|
18
|
+
Use `development/0` only for a local kernel configured to accept the well-known credentials, never for a shared or production kernel. A bare default connection does not substitute credentials; an authentication-required development kernel drops its session (`:stream_ended`) and it never registers.
|
|
19
|
+
|
|
20
|
+
Production authentication is URL userinfo `client-id:client-secret@host` (OAuth token exchange and refresh) or the `apiKey` query parameter (an `api-key` header). The API key wins when both are present. URL-encode reserved characters; write literal `+` as `%2B` because userinfo uses form decoding. Obtain values from the application's approved secret mechanism.
|
|
21
|
+
|
|
22
|
+
Query parameters: `apiKey`, `disableTls`, `skipTlsValidation`, `certificatePath`, `certificatePassword`, `authPort`, `loadBalancer`, `srvNameServer`. `loadBalancer` accepts `least-connections`, `round-robin`, `random`.
|
|
23
|
+
|
|
24
|
+
## Server trust and client certificates
|
|
25
|
+
|
|
26
|
+
`skip_tls_validation` defaults to **true** in both the struct and parser (`connection_string.ex:113,215`). TLS encrypts traffic but does not authenticate the server with that default. Set `skipTlsValidation=false` outside local development. `disableTls` is only for a TLS-terminating proxy; the kernel itself serves TLS.
|
|
27
|
+
|
|
28
|
+
Since 3.7.0, `certificatePath` accepts PKCS#12 (`.p12`/`.pfx`) or PEM containing a certificate and matching private key. `certificatePassword` unlocks protected files. The identity is presented to both gRPC and the OAuth token endpoint; invalid files, wrong passwords or mismatched keys fail startup. PKCS#12 loading needs `openssl`. Client certificates cannot be combined with `disableTls=true`.
|
|
29
|
+
|
|
30
|
+
**A client certificate does not trust the server.** With a client certificate, put custom server-verification options on `GRPC.Credential` passed as `:cred` through `:grpc_options`, not in adapter-level `:transport_opts`. For example, this option excerpt assumes `trusted_der` is an approved DER-encoded CA certificate:
|
|
31
|
+
|
|
32
|
+
```elixir
|
|
33
|
+
grpc_options: [
|
|
34
|
+
cred: GRPC.Credential.new(ssl: [verify: :verify_peer, cacerts: [trusted_der]])
|
|
35
|
+
]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This credential configures the **gRPC channel only**; OAuth server verification still follows `skipTlsValidation` and the system trust store. Install the CA in that trust store when client credentials need it. Conflicting identity or adapter-level verification overrides are rejected at startup.
|
|
39
|
+
|
|
40
|
+
Since 3.8.0 the client uses grpc 1.x and Mint 1.11+, owns its transport, and needs no `GRPC.Client.Supervisor`. If the application calls `GRPC.Stub.connect/2` independently, specify `adapter: GRPC.Client.Adapters.Mint` there too (or explicitly depend on Gun). Application-level Mint `client_settings` must retain `enable_push: false`; grpc replaces rather than merges those settings and the client rejects unsafe overrides.
|
|
41
|
+
|
|
42
|
+
## Credential-safe logging is still necessary
|
|
43
|
+
|
|
44
|
+
Chronicle's own process status redacts credentials, but dependency crash reports can expose gRPC headers, bearer tokens, API keys and Mint HPACK tables. Before starting the client, install the primary Logger filter from the versioned [client crash-report guide](https://github.com/Cratis/Chronicle.Elixir/blob/v3.10.2/Documentation/connections/crash-reports.md). It matches `Elixir.GRPC.Client`, `Elixir.GRPC.Channel`, and `Elixir.Mint.` report content and replaces reports with a notice.
|
|
45
|
+
|
|
46
|
+
Keep `handle_sasl_reports: false`. This is a safety net, not a guarantee: plain warning strings carrying exit reasons are not covered, and filters do not survive a Logger restart. Restrict production log access and rotate any credential already exposed. Never log connection strings.
|
|
47
|
+
|
|
48
|
+
## Keepalive and readiness
|
|
49
|
+
|
|
50
|
+
The kernel sends keepalive once a second; the client answers via a separate unary RPC (`keep_alive.ex:7-17,56`). Merely consuming the stream is insufficient. Kernel eviction after five seconds without an answer can silence reactors/reducers while appends continue working. Diagnose the connection when observers go quiet rather than assuming there are no events.
|
|
51
|
+
|
|
52
|
+
`:connected` means the first keepalive acknowledged the connection id, not that artifacts registered. Failed registration logs `Chronicle registration failed`, stays `:connected`, and retries every five seconds. Wait for `:registered` before claiming readiness.
|
|
53
|
+
|
|
54
|
+
Reconnect uses exponential backoff (1000 ms base, 10000 ms cap); `:retry_attempts` is accepted but ignored. Appends do not wait or queue during an outage: before a channel exists they return `{:error, :not_connected}`. Read model queries wait up to 30 seconds for registration. Transport failures return `{:error, %GRPC.RPCError{}}`; a timeout does not prove a write was not stored.
|
|
55
|
+
|
|
56
|
+
Seeders run after `:registered`, again on reconnect, and skip an event source with existing events (`seeding/runner.ex`, `seeding.ex`). Since 3.5.1 this avoids startup duplicates; it does not remove duplicates already stored by 3.5.0.
|
|
@@ -0,0 +1,64 @@
|
|
|
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
|
+
# Event sources and streams
|
|
5
|
+
|
|
6
|
+
Verified at `Cratis/Chronicle.Elixir v3.10.2`: `Source/chronicle/lib/chronicle/event_sources/event_source.ex`, `event_sources/routing.ex`, `event_sequences/definition_routing.ex`, and `Documentation/event-sources.md`. Definitions require **Chronicle 19.30.0+**.
|
|
7
|
+
|
|
8
|
+
An event source definition gives appends a stable name, optional streams and default concurrency dimensions. It belongs to the append, not the event type; the same event type can go through different definitions. Appends without a definition keep their existing routing and have no registered-source metadata.
|
|
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.AccountEventSource do
|
|
15
|
+
use Chronicle.EventSources.EventSource,
|
|
16
|
+
name: "Account",
|
|
17
|
+
description: "A bank account",
|
|
18
|
+
concurrency: [:event_source_id]
|
|
19
|
+
|
|
20
|
+
stream("Transactions",
|
|
21
|
+
description: "Money movements",
|
|
22
|
+
concurrency: [:event_source_id, :event_stream_id]
|
|
23
|
+
)
|
|
24
|
+
end
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`:name` defaults to the last module segment without a trailing `EventSource`. Dimensions are `:event_source_id`, `:event_source_type`, `:event_stream_type`, `:event_stream_id`. A stream with no dimensions inherits its source's dimensions. Duplicate stream names fail compilation; duplicate source names raise `Chronicle.EventSources.DuplicateEventSourceName` at client startup.
|
|
28
|
+
|
|
29
|
+
## Register and append
|
|
30
|
+
|
|
31
|
+
Set `otp_app:` so discovery finds the definition, or pass `event_sources: [MyApp.AccountEventSource]` to `Chronicle.Client`. Definitions register after event types and before observers on every reconnect. Registration is an upsert; omitting a definition later does not delete it from the kernel.
|
|
32
|
+
|
|
33
|
+
With the client registered and the `MyApp.Events.FundsDeposited` event from the skill declared:
|
|
34
|
+
|
|
35
|
+
```elixir
|
|
36
|
+
case Chronicle.append("account-1", %MyApp.Events.FundsDeposited{amount: 50},
|
|
37
|
+
event_source: MyApp.AccountEventSource,
|
|
38
|
+
event_stream: "Transactions",
|
|
39
|
+
event_stream_id: "2024-05"
|
|
40
|
+
) do
|
|
41
|
+
:ok -> :ok
|
|
42
|
+
{:error, reason} -> {:error, reason}
|
|
43
|
+
end
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The source name becomes the event source type and event `EventSource` metadata; the stream name becomes the event stream type. Sources can be modules or names. Without `:event_stream`, the stream type is `"All"`. `append_many/3` and units of work accept the same source/stream options.
|
|
47
|
+
|
|
48
|
+
Each `Chronicle.EventSequences.EventForEventSourceId` can carry `event_source` and `event_stream`. In `append_many_for_event_sources/2`, entry-level routing wins; batch defaults fill only entries with no source. A routing rejection prevents the whole batch from being sent.
|
|
49
|
+
|
|
50
|
+
| Reason inside `{:error, reason}` | Cause |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `{:unknown_event_source, source}` | Source not registered with this client |
|
|
53
|
+
| `{:event_stream_does_not_belong_to_event_source, source, stream}` | Stream not declared by that source |
|
|
54
|
+
| `{:event_routing_contradicts_event_source, source, dimension, expected, actual}` | Explicit source/stream type contradicts the definition |
|
|
55
|
+
| `{:event_stream_without_event_source, stream}` | Stream given without a source |
|
|
56
|
+
| `{:incompatible_concurrency_scopes, id, guards}` | Derived guards disagree for one event source id in a batch |
|
|
57
|
+
|
|
58
|
+
## Default concurrency is not an explicit decision guard
|
|
59
|
+
|
|
60
|
+
Without an explicit `:concurrency_scope`, the client reads the tail narrowed by the effective definition dimensions and uses that sequence number as a scope. With no dimensions, it sends no scope. Explicit scopes, including `Chronicle.Events.ConcurrencyScope.none()`, win and avoid that read. Do not disable a guard just to silence a rejection; choose a scope that protects the business decision's reads.
|
|
61
|
+
|
|
62
|
+
The wire carries one scope per event source id. Guarded entries of that id must agree on dimensions and selected source type, stream type and stream id. Unguarded entries never suppress a later guarded entry. Incompatible derived guards fail before any tail read or append; use separate batches, or deliberately supply one explicit scope on an entry for that id.
|
|
63
|
+
|
|
64
|
+
Reactor and reducer contexts expose `:event_source` as the registered name, or `nil` for events appended without a definition. Their other context keys differ; do not assume the reactor context shape for a reducer.
|
|
@@ -0,0 +1,25 @@
|
|
|
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
|
+
# Common pitfalls
|
|
5
|
+
|
|
6
|
+
Verified at `Cratis/Chronicle.Elixir v3.10.2`; historical qualifications are intentional.
|
|
7
|
+
|
|
8
|
+
| Pitfall | Why it bites |
|
|
9
|
+
| --- | --- |
|
|
10
|
+
| Copying the `v2.2.0` root README | Its module names do not exist; the `3.x` README is correct |
|
|
11
|
+
| Using `Chronicle.Concept` on `2.2.0` | It ships from `3.0.0`; on `2.2.0` annotate fields with `pii/1,2` instead |
|
|
12
|
+
| Combining `pii` and `encrypted` | The same leaf raises `PiiAndEncryptedCombinedNotSupported`; neither is allowed on an `event_source_id: true` concept |
|
|
13
|
+
| Quoting the `VERSION` file | It is a `0.0.5` build-time placeholder |
|
|
14
|
+
| Putting options only in `config.exs` | The client reads no application env; your app must pass child-spec keyword options |
|
|
15
|
+
| Omitting `:otp_app` | Discovery falls back to scanning every loaded module |
|
|
16
|
+
| Assuming the namespace default is `"default"` | It is `"Default"`; the moduledoc is wrong |
|
|
17
|
+
| `:ok = Chronicle.append(...)` in a server | A constraint violation returns `{:error, _}` and raises `MatchError` |
|
|
18
|
+
| Waiting for `:connected` | Observers attach at `:registered` |
|
|
19
|
+
| Reading `:correlation_id` from a reactor context | The map has six keys and that is not one |
|
|
20
|
+
| Two read models with the same final module segment | The default id is the last segment only |
|
|
21
|
+
| Appending from a `Task` and expecting the correlation id | Ambient context is per process |
|
|
22
|
+
| Treating quiet observers as "no events" | Keepalive eviction can silence observers while appends still succeed |
|
|
23
|
+
| Shipping the default TLS behavior | `skip_tls_validation` defaults to `true` |
|
|
24
|
+
| Forgetting `global_handlers:` or `:otp_app` discovery | Shared mappings are not merged into variants unless registered |
|
|
25
|
+
| A shared handler mapping a field one variant lacks | `GlobalHandlerPropertyNotOnVariant` at registration, not a silently skipped mapping |
|
|
@@ -0,0 +1,48 @@
|
|
|
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
|
+
# Projection options and keys
|
|
5
|
+
|
|
6
|
+
Verified at `Cratis/Chronicle.Elixir v3.10.2`: `Source/chronicle/lib/chronicle/read_models/read_model.ex:35-120,183-212,230-332`, `projections/projection.ex`, and `registration/coordinator.ex:735-746`.
|
|
7
|
+
|
|
8
|
+
`use Chronicle.ReadModels.ReadModel` accepts `id:`, `passive: true`, `not_rewindable: true`, and `event_sequence: "sequence-name"`. Defaults are the last module segment as id, active, rewindable, and `"event-log"`. Standalone `Chronicle.Projections.Projection` also accepts sequence/rewindability options and requires `model:`.
|
|
9
|
+
|
|
10
|
+
AutoMap maps matching event/model properties by default. `no_auto_map()` disables it for the whole projection; `no_auto_map([:balance, :status])` excludes only those properties so explicit mappings can own them.
|
|
11
|
+
|
|
12
|
+
Since 3.5.1, multi-word atom references are encoded as camelCase correctly: `set: [owner_name: :owner_name]` is the supported shape. AutoMap also handles shared multi-word names; boolean/float constants work without a string workaround. `join/2` requires `:on`. `:count` increments the named field once per occurrence.
|
|
13
|
+
|
|
14
|
+
## Composite keys and event context (since 3.9.0)
|
|
15
|
+
|
|
16
|
+
This module excerpt assumes a registered `MyApp.Events.AccountOpened` event. The key names and part order are preserved:
|
|
17
|
+
|
|
18
|
+
```elixir
|
|
19
|
+
# Copyright (c) Cratis. All rights reserved.
|
|
20
|
+
# Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
21
|
+
|
|
22
|
+
defmodule MyApp.ReadModels.WeeklyAccountOpenings do
|
|
23
|
+
use Chronicle.ReadModels.ReadModel
|
|
24
|
+
defstruct transaction_count: 0
|
|
25
|
+
|
|
26
|
+
from(MyApp.Events.AccountOpened,
|
|
27
|
+
key: {:composite, [
|
|
28
|
+
{"Year", {:event_context, "Occurred.Year"}},
|
|
29
|
+
{"Week", {:event_context, "Occurred.Week"}}
|
|
30
|
+
]},
|
|
31
|
+
count: :transaction_count
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Composite parts accept event-field atoms, explicit expression strings and literals. They must form a nonempty ordered list of `{name, expression}` pairs; nested composites are not supported. Event-context paths contain letters, dots and parentheses and are passed unchanged. Keys also apply to `join` and `removed_with`.
|
|
37
|
+
|
|
38
|
+
**`Occurred.Year` is the calendar year, not the ISO week-year.** Do not assume that pairing it with `Occurred.Week` gives an ISO week identity at a year boundary; settle the required business key first.
|
|
39
|
+
|
|
40
|
+
## Dictionary counters (since 3.1.0)
|
|
41
|
+
|
|
42
|
+
On a read model with `defstruct event_counts: %{}`, this excerpt increments one entry per event type:
|
|
43
|
+
|
|
44
|
+
```elixir
|
|
45
|
+
from_every(increment: [event_counts: {:event_context, :type}])
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`decrement:` supports the corresponding dictionary operation. Use typed defaults for numeric and boolean fields on every model: schemas are generated from those defaults, not static Elixir types.
|
|
@@ -0,0 +1,34 @@
|
|
|
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
|
+
# Upgrading 2.x to 3.x
|
|
5
|
+
|
|
6
|
+
Verified at `Cratis/Chronicle.Elixir v3.10.2`: `Source/chronicle/mix.exs`, `mix.lock`, `lib/chronicle/wire_result.ex`, `jobs.ex`, `event_sequences/event_log.ex`, `read_models.ex`, `seeding.ex`, and the release notes for 3.0.0, 3.2.0, 3.5.1 and 3.8.0.
|
|
7
|
+
|
|
8
|
+
## Dependencies and wire compatibility
|
|
9
|
+
|
|
10
|
+
3.0.0 migrated the wire contracts to Chronicle 17/18, renaming RPCs and unwrapping response envelopes. It removed no public Elixir API, but unauthorized/excepted command responses now return `{:error, reason}` rather than looking successful. `Jobs.get/2` lists jobs then finds the id client-side; `append_many_for_event_sources/2` uses its dedicated RPC rather than the single-source path.
|
|
11
|
+
|
|
12
|
+
For **3.10.2**:
|
|
13
|
+
|
|
14
|
+
- Use `{:cratis_chronicle, "~> 3.10"}` and Elixir **1.18+** (`mix.exs` requires `~> 1.18`).
|
|
15
|
+
- grpc **1.x** and Mint **1.11+** are direct dependencies; do not carry a mandatory `GRPC.Client.Supervisor` child forward from an older grpc setup.
|
|
16
|
+
- Contracts resolve to **19.30.0** in this tag's lockfile. Pair the kernel with the installed contracts descriptor; named event source definitions require **Chronicle 19.30.0+**.
|
|
17
|
+
- The first append on each channel runs a compatibility check, shared until reconnect. `{:error, {:incompatible_server, response}}` is a version/descriptor problem, not a transient append rejection. Update kernel and contracts as a compatible pair; do not bypass the preflight. Failed transport calls return `{:error, %GRPC.RPCError{}}`.
|
|
18
|
+
|
|
19
|
+
## Corrected behavior requires application review
|
|
20
|
+
|
|
21
|
+
3.5.1 fixed behavior that older applications may have unintentionally relied on:
|
|
22
|
+
|
|
23
|
+
| Change | Review before rollout |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| Reducers register successfully and process from the log start | Old events now reach reducers that previously failed registration |
|
|
26
|
+
| Multi-word projection fields and AutoMap now populate | Remove camelCase-string workarounds; inspect fields that were formerly empty |
|
|
27
|
+
| `unique(:owner_email)` and `remove_constraint` registration work | Uniqueness is now enforced and release events can remove constraints |
|
|
28
|
+
| `ReadModels.query/2` is zero-based, default page 0 | Change first-page callers to `page: 0`; `page: 1` is now the second page |
|
|
29
|
+
| Seeding skips an event source with existing events | 3.5.0 re-appended on every start; already-stored duplicates are not removed |
|
|
30
|
+
| Tail/next sequence lookups no longer narrow implicitly to `"Default"` | Audit callers that depended on implicit routing narrowing |
|
|
31
|
+
|
|
32
|
+
Since 3.2.0, rejected appends (including concurrency/constraint failures) return `{:error, reason}` instead of potentially returning `:ok`; batch append metadata survives the rich append RPC. Handle errors on single, batch and transactional paths.
|
|
33
|
+
|
|
34
|
+
3.10.2 preserves declared `unique(..., message: ...)` violation messages on single, batch and transactional appends. Retain the constraint name and diagnostics when handling violations rather than assuming every message came from the kernel.
|
|
@@ -1,10 +1,18 @@
|
|
|
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
|
# Variants
|
|
2
5
|
|
|
3
6
|
## Variants — mutually exclusive read models for one entity's lifecycle
|
|
4
7
|
|
|
5
|
-
> Requires `cratis_chronicle` `3.4.0` or later
|
|
6
|
-
> `
|
|
7
|
-
>
|
|
8
|
+
> Requires `cratis_chronicle` `3.4.0` or later. Verified at
|
|
9
|
+
> `Cratis/Chronicle.Elixir v3.10.2` (`Source/chronicle/lib/chronicle/read_models/read_model.ex:280-300`,
|
|
10
|
+
> `projections/global_handler.ex`, `projections/variant_reclassifier.ex`).
|
|
11
|
+
>
|
|
12
|
+
> The 3.4.0 release reported a kernel `$eventSourceId` property-mapping limitation
|
|
13
|
+
> (Cratis/Chronicle#3924). This client-source verification does not establish
|
|
14
|
+
> whether kernel 19.x fixed it; verify the full variant transition against your
|
|
15
|
+
> kernel before claiming end-to-end support.
|
|
8
16
|
|
|
9
17
|
Some entities do not have one shape for their whole lifetime — a work item is a
|
|
10
18
|
backlog entry until a pull request exists for it, then it is a pull request
|
|
@@ -19,7 +27,7 @@ end
|
|
|
19
27
|
|
|
20
28
|
defmodule MyApp.ReadModels.BacklogItem do
|
|
21
29
|
use Chronicle.ReadModels.ReadModel
|
|
22
|
-
defstruct id:
|
|
30
|
+
defstruct id: "", title: ""
|
|
23
31
|
|
|
24
32
|
variant_of MyApp.ReadModels.WorkItem, key: :id
|
|
25
33
|
enters_on MyApp.Events.IssueCreated
|
|
@@ -29,7 +37,7 @@ end
|
|
|
29
37
|
|
|
30
38
|
defmodule MyApp.ReadModels.PullRequestItem do
|
|
31
39
|
use Chronicle.ReadModels.ReadModel
|
|
32
|
-
defstruct id:
|
|
40
|
+
defstruct id: "", title: "", pull_request_url: "", build_status: ""
|
|
33
41
|
|
|
34
42
|
variant_of MyApp.ReadModels.WorkItem, key: :id
|
|
35
43
|
enters_on MyApp.Events.PullRequestCreated
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skill": "cratis-chronicle-client-elixir",
|
|
3
|
+
"input": "Connect an Elixir application, append through a registered event source, and query the first page of its read model.",
|
|
4
|
+
"fixtures": [],
|
|
5
|
+
"assertions": [
|
|
6
|
+
{ "kind": "skill-contains", "value": "**`v3.10.2`**" },
|
|
7
|
+
{ "kind": "skill-contains", "value": "{:cratis_chronicle, \"~> 3.10\"}" },
|
|
8
|
+
{ "kind": "skill-contains", "value": "ConnectionString.development()" },
|
|
9
|
+
{ "kind": "skill-contains", "value": "`~> 1.18`" },
|
|
10
|
+
{ "kind": "skill-contains", "value": "`nil` registers as string" },
|
|
11
|
+
{ "kind": "skill-contains", "value": "**The reactor context has six keys**" },
|
|
12
|
+
{ "kind": "skill-contains", "value": "`sequence_number`, `occurred`, `event_source`, `observation_state`" },
|
|
13
|
+
{ "kind": "skill-contains", "value": "**page 1 now means the second page**" },
|
|
14
|
+
{ "kind": "skill-contains", "value": "`:retry_attempts` is accepted but ignored", "file": "references/connections.md" },
|
|
15
|
+
{ "kind": "skill-contains", "value": "Client certificates cannot be combined with `disableTls=true`", "file": "references/connections.md" },
|
|
16
|
+
{ "kind": "skill-contains", "value": "registered-source metadata", "file": "references/event-sources.md" },
|
|
17
|
+
{ "kind": "skill-contains", "value": "`{:incompatible_concurrency_scopes, id, guards}`", "file": "references/event-sources.md" },
|
|
18
|
+
{ "kind": "skill-contains", "value": "`Chronicle.Events.ConcurrencyScope.none()`", "file": "references/event-sources.md" },
|
|
19
|
+
{ "kind": "skill-contains", "value": "**no many-event variant**", "file": "references/append-api.md" },
|
|
20
|
+
{ "kind": "skill-contains", "value": "`subject/1` is not imported by `EventType`", "file": "references/compliance.md" },
|
|
21
|
+
{ "kind": "skill-contains", "value": "calendar year, not the ISO week-year", "file": "references/projections.md" }
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cratis-chronicle-client-go
|
|
3
|
+
description: Connect a standalone Go application to Chronicle, register events and observers, append with explicit outcomes, and materialize read models. Use for Chronicle.Go client setup, projections, reactors, gRPC ownership and safe retry decisions. Do not use for Arc HTTP commands or Chronicle kernel implementation.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Go 1.26 or later; Chronicle.Go v0.9.1 with the Chronicle 19.32.3 kernel profile.
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<!-- Copyright (c) Cratis. All rights reserved. -->
|
|
9
|
+
<!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
|
|
10
|
+
|
|
11
|
+
# Chronicle from Go
|
|
12
|
+
|
|
13
|
+
> **Experimental v0:** Chronicle.Go **v0.9.1**, verified kernel profile
|
|
14
|
+
> **Chronicle 19.32.3**. Companion guidance targets Arc.Go **v0.1.1** and
|
|
15
|
+
> Fundamentals.Go **v0.3.2**. Minor releases may break APIs.
|
|
16
|
+
|
|
17
|
+
This is a standalone event-store client, not an Arc HTTP framework. Use explicit
|
|
18
|
+
registration rather than C# attributes or assembly discovery. Events are immutable
|
|
19
|
+
facts represented by named structs; event-source identity is append metadata,
|
|
20
|
+
not an event payload property.
|
|
21
|
+
|
|
22
|
+
## Verified product sources
|
|
23
|
+
|
|
24
|
+
| Product | Tag | Source checked |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| Chronicle.Go (`github.com/cratis/chronicle.go`) | `v0.9.1` | `client.go`, `options.go`, `options_transport.go`, `registry.go`, `registry_projections.go`, `registry_readmodels.go`, `registry_reactors.go`, `eventsequences/sequence.go`, `internal/decision/decision.go`, `captures/service.go`, `captures/redaction.go`, `examples/getting-started/main.go`, `examples/projections/main.go` |
|
|
27
|
+
|
|
28
|
+
[Source at v0.9.1](https://github.com/Cratis/Chronicle.Go/tree/v0.9.1)
|
|
29
|
+
and its [parity ledger](https://github.com/Cratis/Chronicle.Go/blob/v0.9.1/Documentation/parity.md)
|
|
30
|
+
qualify supported behavior. The README's older statement that observers,
|
|
31
|
+
projections and automatic lifecycle recovery are absent is stale; those surfaces
|
|
32
|
+
exist, but that does **not** mean whole-product parity.
|
|
33
|
+
|
|
34
|
+
## Register and append
|
|
35
|
+
|
|
36
|
+
Install `github.com/cratis/chronicle.go@v0.9.1` in a consumer module. This complete
|
|
37
|
+
package appends one event using **local development** defaults:
|
|
38
|
+
|
|
39
|
+
```go
|
|
40
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
41
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
42
|
+
|
|
43
|
+
package customers
|
|
44
|
+
|
|
45
|
+
import (
|
|
46
|
+
"context"
|
|
47
|
+
"errors"
|
|
48
|
+
|
|
49
|
+
chronicle "github.com/cratis/chronicle.go"
|
|
50
|
+
"github.com/cratis/chronicle.go/events"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
// CustomerRegistered records a customer's display name.
|
|
54
|
+
type CustomerRegistered struct {
|
|
55
|
+
Name string `json:"name"`
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// AppendCustomer uses a caller-bounded context and closes its owned client.
|
|
59
|
+
func AppendCustomer(ctx context.Context) (err error) {
|
|
60
|
+
registry := chronicle.NewRegistry()
|
|
61
|
+
if _, err = chronicle.RegisterEvent[CustomerRegistered](registry,
|
|
62
|
+
events.WithID("customer-registered")); err != nil {
|
|
63
|
+
return err
|
|
64
|
+
}
|
|
65
|
+
client, err := chronicle.NewClient(
|
|
66
|
+
chronicle.WithDevelopmentDefaults(), chronicle.WithRegistry(registry))
|
|
67
|
+
if err != nil {
|
|
68
|
+
return err
|
|
69
|
+
}
|
|
70
|
+
defer func() { err = errors.Join(err, client.Close()) }()
|
|
71
|
+
store, err := client.EventStore(ctx, "customers")
|
|
72
|
+
if err != nil {
|
|
73
|
+
return err
|
|
74
|
+
}
|
|
75
|
+
result, err := store.EventLog().Append(ctx, "customer-42",
|
|
76
|
+
CustomerRegistered{Name: "Ada"})
|
|
77
|
+
if err != nil {
|
|
78
|
+
return err // The write may have committed. Do not blindly retry.
|
|
79
|
+
}
|
|
80
|
+
return result.Err()
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Registration errors and append outcomes are not optional checks. `Append` returns
|
|
85
|
+
both a transport error and a result; after transport success, `result.Err()` can
|
|
86
|
+
still report a rejection. A timeout/disconnect may hide a commit. Choose explicit
|
|
87
|
+
concurrency/idempotency semantics before retrying, never a generic write retry.
|
|
88
|
+
Use stable persisted event IDs and explicit `json` names for cross-language data.
|
|
89
|
+
|
|
90
|
+
For a runnable program and its observable append position, use the tagged
|
|
91
|
+
[getting-started example](https://github.com/Cratis/Chronicle.Go/blob/v0.9.1/examples/getting-started/main.go).
|
|
92
|
+
This compileable package does not itself start a kernel or prove a successful append.
|
|
93
|
+
|
|
94
|
+
## Connection and gRPC ownership
|
|
95
|
+
|
|
96
|
+
- `NewClient` validates and freezes declarations without network I/O; it does
|
|
97
|
+
not prove readiness. `Dial(ctx, options...)` also connects. Complete all
|
|
98
|
+
registrations before construction; later changes do not mutate that client.
|
|
99
|
+
- `WithDevelopmentDefaults` relaxes TLS certificate verification for development;
|
|
100
|
+
it is not a certificate whitelist. Production needs validated TLS and explicit
|
|
101
|
+
production credentials. `WithTLS` accepts TLS configuration; never use dev
|
|
102
|
+
defaults as a production fix for a failed certificate.
|
|
103
|
+
- `WithGRPCConnection` borrows a `grpc.ClientConn`; the caller owns and closes it.
|
|
104
|
+
Follow the option's explicit-authentication requirement. Close the Chronicle
|
|
105
|
+
client before its borrowed collaborators. Owned connections belong to the client.
|
|
106
|
+
- `Close` cancels and joins owned work. Handlers must honor cancellation;
|
|
107
|
+
a bounded `CloseContext` timeout means cleanup is incomplete, not successful.
|
|
108
|
+
Keep short unary deadlines separate from long-lived subscriptions.
|
|
109
|
+
- `WithOnConnected`, `WithOnDisconnected` and `WithLoadBalancer` are explicit
|
|
110
|
+
lifecycle customization points. `WithGRPCStatsHandler` borrows concurrent-safe,
|
|
111
|
+
promptly returning callbacks for owned connections; it conflicts with a borrowed
|
|
112
|
+
connection and does not authorize interceptors or retries.
|
|
113
|
+
- For SDK contributors, generate protobuf contracts only from the authoritative
|
|
114
|
+
inputs using the repository's pinned Buf recipe. Preserve metadata, field numbers,
|
|
115
|
+
deadlines and checkpoint boundaries; never hand-edit generated contracts.
|
|
116
|
+
|
|
117
|
+
## Read models and side effects
|
|
118
|
+
|
|
119
|
+
Read [projection registration](references/projections.md) when populating a read
|
|
120
|
+
model. Start with model-bound tags; use the fluent builder when that cannot express
|
|
121
|
+
it, then a reducer for genuinely procedural state decisions. Do not mix model-bound
|
|
122
|
+
mapping tags and fluent mappings for the same declaration.
|
|
123
|
+
|
|
124
|
+
`RegisterReactorHandler(registry, id, func(context.Context, E) error)` registers a
|
|
125
|
+
typed closure for a registered event. `RegisterReactor` explicitly registers a type;
|
|
126
|
+
its exported methods select events by parameter type, not by handler name. Optional
|
|
127
|
+
leading context and `reactors.Delivery` parameters carry cancellation and delivery
|
|
128
|
+
identity. `delivery.ID()` can key an external idempotency record; it is not an
|
|
129
|
+
exactly-once guarantee. Return supported follow-up events rather than manually
|
|
130
|
+
recreating effect dispatch; use projections for materialization, reactors for effects.
|
|
131
|
+
|
|
132
|
+
`reactors.OnceOnly` excludes replay; it does **not** deduplicate failed-partition
|
|
133
|
+
recovery. Effects may repeat after errors, cleanup failures or reconnect. Keep them
|
|
134
|
+
idempotent. The kernel owns recovery/quarantine and progress; do not invent resume
|
|
135
|
+
positions or acknowledge before successful processing and cleanup. Read the tagged
|
|
136
|
+
[reactor guide](https://github.com/Cratis/Chronicle.Go/blob/v0.9.1/Documentation/reactors.md)
|
|
137
|
+
for exact effect, replay and registration-readiness limits.
|
|
138
|
+
|
|
139
|
+
## Unsupported does not mean success
|
|
140
|
+
|
|
141
|
+
Decision guards require the verified 19.32.3 profile and compatibility preflight;
|
|
142
|
+
unsupported kernels return `ErrUnsupported`. Protected operations have their own
|
|
143
|
+
19.32.x capability gates; this release supports qualified protected revisions and
|
|
144
|
+
classified read-model replay routes, not every protected watch/profile.
|
|
145
|
+
Do not use the deprecated `readmodels.DecisionProtectedModel` or
|
|
146
|
+
`DecisionProtectionMetadata` compatibility hooks for new work.
|
|
147
|
+
|
|
148
|
+
Webhook source authorization cannot travel through the CDL-only capture transport.
|
|
149
|
+
`Save`/`Validate` refuse it with `ErrUnsupported` before dispatch. Capture credential
|
|
150
|
+
JSON import/export is also refused. Never serialize or log webhook credentials or
|
|
151
|
+
pretend a rejected configuration was applied.
|
|
152
|
+
|
|
153
|
+
## Verify
|
|
154
|
+
|
|
155
|
+
- Compile against the released module without workspace/local replacements.
|
|
156
|
+
- Test rejection separately from transport error and ambiguous commit recovery.
|
|
157
|
+
- Use `chronicletest` scenarios for event/read-model contracts within their supported
|
|
158
|
+
profiles; pure decisions can use standard `testing` directly.
|
|
159
|
+
- Exercise registration, cancellation, reconnect, borrowed connections and joined
|
|
160
|
+
cleanup against the pinned kernel before claiming runtime parity.
|
|
161
|
+
- Chronicle.Go v0.9.1 requires Fundamentals.Go v0.1.0; the separate concepts skill's
|
|
162
|
+
v0.3.2 pin is not a required dependency upgrade.
|
|
@@ -0,0 +1,73 @@
|
|
|
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
|
+
# Model-bound Go projections
|
|
5
|
+
|
|
6
|
+
Verified at Chronicle.Go **v0.9.1** in `registry_readmodels.go`,
|
|
7
|
+
`registry_projections.go`, `projections/declaration.go` and the
|
|
8
|
+
[tagged projection example](https://github.com/Cratis/Chronicle.Go/blob/v0.9.1/examples/projections/main.go).
|
|
9
|
+
This complete package declares a projection; it does not connect or append:
|
|
10
|
+
|
|
11
|
+
```go
|
|
12
|
+
// Copyright (c) Cratis. All rights reserved.
|
|
13
|
+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
14
|
+
|
|
15
|
+
package inventory
|
|
16
|
+
|
|
17
|
+
import (
|
|
18
|
+
"time"
|
|
19
|
+
|
|
20
|
+
chronicle "github.com/cratis/chronicle.go"
|
|
21
|
+
"github.com/cratis/chronicle.go/events"
|
|
22
|
+
"github.com/cratis/chronicle.go/projections"
|
|
23
|
+
"github.com/cratis/chronicle.go/readmodels"
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
// ProductRegistered records a new product's description.
|
|
27
|
+
type ProductRegistered struct {
|
|
28
|
+
ProductName string `json:"productName"`
|
|
29
|
+
Description string `json:"description"`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Inventory is materialized by the kernel from registered events.
|
|
33
|
+
type Inventory struct {
|
|
34
|
+
ID string `json:"id" chronicle:"key"`
|
|
35
|
+
ProductName string `json:"productName"`
|
|
36
|
+
Description string `json:"description" chronicle:"set(@registered)"`
|
|
37
|
+
State string `json:"state" chronicle:"value(@registered,value=\"available\")"`
|
|
38
|
+
Registered time.Time `json:"registered" chronicle:"context(@registered,from=occurred)"`
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Declarations returns the registry and typed read-model handle.
|
|
42
|
+
func Declarations() (*chronicle.Registry, readmodels.Model[Inventory], error) {
|
|
43
|
+
registry := chronicle.NewRegistry()
|
|
44
|
+
registered, err := chronicle.RegisterEvent[ProductRegistered](registry,
|
|
45
|
+
events.WithID("product-registered"))
|
|
46
|
+
if err != nil {
|
|
47
|
+
return nil, readmodels.Model[Inventory]{}, err
|
|
48
|
+
}
|
|
49
|
+
model, err := chronicle.RegisterReadModel[Inventory](registry)
|
|
50
|
+
if err != nil {
|
|
51
|
+
return nil, model, err
|
|
52
|
+
}
|
|
53
|
+
projection := projections.ModelBound(model,
|
|
54
|
+
projections.BindEvent("registered", registered),
|
|
55
|
+
projections.FromEvent(registered))
|
|
56
|
+
return registry, model, registry.AddProjection(projection)
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`chronicle:"key"` binds event-source identity. `FromEvent` enables AutoMap by
|
|
61
|
+
default (`ProductName` maps by name); `BindEvent` gives mapping tags a local
|
|
62
|
+
alias. `set` copies a property, `value` sets a constant, and `context` selects
|
|
63
|
+
metadata. Registration checks errors before client construction.
|
|
64
|
+
|
|
65
|
+
Pass the registry to `WithRegistry`. Use the typed handle with
|
|
66
|
+
`readmodels.For(store.ReadModels(), model)` and `Get(ctx, id)`; inspect both the
|
|
67
|
+
error and `instance.Exists`, not a zero value as proof of presence. Materialization
|
|
68
|
+
is eventually consistent. The tagged example includes a bounded read wait and
|
|
69
|
+
prints the materialized state. Do not infer catch-up from registration alone.
|
|
70
|
+
|
|
71
|
+
For shapes tags cannot express, define a separate untagged model and use
|
|
72
|
+
`projections.NewBuilder`/typed mapping helpers. A reducer is the procedural escape
|
|
73
|
+
hatch, not the first choice for event-to-property mapping.
|