@cratis/pi 2.22.0 → 2.23.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/backend-developer.md +6 -5
- package/package/corpus/agents/code-reviewer.md +7 -7
- package/package/corpus/agents/coordinator.md +5 -4
- package/package/corpus/agents/frontend-developer.md +34 -40
- package/package/corpus/agents/orchestrator.md +5 -4
- package/package/corpus/agents/performance-reviewer.md +5 -4
- package/package/corpus/agents/planner.md +5 -4
- package/package/corpus/agents/repository-investigation-reviewer.md +2 -1
- package/package/corpus/agents/repository-investigator.md +2 -1
- package/package/corpus/agents/security-reviewer.md +5 -4
- package/package/corpus/agents/slice-implementer.md +8 -2
- package/package/corpus/agents/spec-writer.md +6 -4
- package/package/corpus/harnesses/pi/extensions/subagent/agents.ts +52 -7
- package/package/corpus/harnesses/pi/extensions/subagent/index.ts +14 -0
- package/package/corpus/hooks/README.md +29 -27
- package/package/corpus/hooks/agent-stop.md +1 -5
- package/package/corpus/hooks/scripts/cratis-patterns.json +1 -1
- package/package/corpus/hooks/scripts/validate-package-subpaths.sh +1 -2
- package/package/corpus/prompts/verify-ai-setup.prompt.md +17 -7
- package/package/corpus/rules/ai-distribution.md +58 -0
- package/package/corpus/rules/components.md +77 -44
- package/package/corpus/rules/dialogs.md +24 -20
- package/package/corpus/rules/efcore.md +35 -187
- package/package/corpus/rules/framework.md +1 -1
- package/package/corpus/rules/frontend-quality.md +1 -1
- package/package/corpus/rules/frontend-testing.md +4 -4
- package/package/corpus/rules/general.md +29 -105
- package/package/corpus/rules/new-repository-intake.md +34 -0
- package/package/corpus/rules/orleans.md +13 -27
- package/package/corpus/rules/react.md +12 -12
- package/package/corpus/rules/reactors.md +28 -5
- package/package/corpus/rules/specs.scenarios.csharp.md +18 -3
- package/package/corpus/rules/specs.typescript.md +1 -1
- package/package/corpus/rules/storybook.md +2 -2
- package/package/corpus/rules/typescript.md +1 -0
- package/package/corpus/rules/vertical-slices.md +20 -15
- package/package/corpus/rules/writing-correct-examples.md +1 -0
- package/package/corpus/skills/cratis-application-react-specifications/SKILL.md +4 -4
- package/package/corpus/skills/cratis-application-slice-specifications/SKILL.md +16 -8
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/SKILL.md +6 -4
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/authentication.md +1 -1
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/authorization.md +1 -1
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/frontend.md +1 -1
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/local-development.md +1 -1
- package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/tenancy.md +7 -4
- package/package/corpus/skills/cratis-arc-command/SKILL.md +9 -7
- package/package/corpus/skills/cratis-arc-command/references/command-result.md +1 -1
- package/package/corpus/skills/cratis-arc-command/references/handler-shapes.md +2 -2
- package/package/corpus/skills/cratis-arc-command/references/proxy-generation.md +6 -3
- package/package/corpus/skills/cratis-arc-command/references/read-model-injection.md +1 -1
- package/package/corpus/skills/cratis-arc-command-execution/SKILL.md +12 -2
- package/package/corpus/skills/cratis-arc-command-validation/SKILL.md +5 -3
- package/package/corpus/skills/cratis-arc-ef-core-migration/SKILL.md +7 -4
- package/package/corpus/skills/cratis-arc-observable-query-http/SKILL.md +10 -3
- package/package/corpus/skills/cratis-arc-query-paging/SKILL.md +13 -8
- package/package/corpus/skills/cratis-arc-react-page/SKILL.md +27 -24
- package/package/corpus/skills/cratis-arc-react-page/references/data-page.md +15 -11
- package/package/corpus/skills/cratis-arc-react-page/references/data-tables.md +9 -2
- package/package/corpus/skills/cratis-arc-react-page/references/dialogs.md +11 -9
- package/package/corpus/skills/cratis-arc-react-page/references/queries-and-commands.md +26 -2
- package/package/corpus/skills/cratis-chronicle-cli-operations/SKILL.md +19 -13
- package/package/corpus/skills/cratis-chronicle-client-dotnet/SKILL.md +17 -15
- package/package/corpus/skills/cratis-chronicle-client-elixir/SKILL.md +24 -20
- package/package/corpus/skills/cratis-chronicle-client-kotlin/SKILL.md +26 -15
- package/package/corpus/skills/cratis-chronicle-client-typescript/SKILL.md +15 -11
- package/package/corpus/skills/cratis-chronicle-compliance/SKILL.md +14 -3
- package/package/corpus/skills/cratis-chronicle-event-constraints/SKILL.md +13 -6
- package/package/corpus/skills/cratis-chronicle-event-modeling/SKILL.md +2 -2
- package/package/corpus/skills/cratis-chronicle-event-specifications/SKILL.md +11 -5
- package/package/corpus/skills/cratis-chronicle-event-type-migration/SKILL.md +2 -2
- package/package/corpus/skills/cratis-chronicle-multi-tenancy/SKILL.md +2 -2
- package/package/corpus/skills/cratis-chronicle-projection/SKILL.md +23 -4
- package/package/corpus/skills/cratis-chronicle-projection/references/fluent-builder.md +1 -1
- package/package/corpus/skills/cratis-chronicle-projection/references/model-bound-attributes.md +2 -2
- package/package/corpus/skills/cratis-chronicle-reactor/SKILL.md +22 -8
- package/package/corpus/skills/cratis-chronicle-read-model/SKILL.md +1 -1
- package/package/corpus/skills/cratis-chronicle-read-model/references/queries.md +1 -1
- package/package/corpus/skills/cratis-chronicle-read-model-specifications/SKILL.md +3 -1
- package/package/corpus/skills/cratis-chronicle-reducer/SKILL.md +1 -1
- package/package/corpus/skills/cratis-chronicle-web-workbench/SKILL.md +19 -11
- package/package/corpus/skills/cratis-cli-terminal-workbench/SKILL.md +11 -6
- package/package/corpus/skills/cratis-code-review/SKILL.md +8 -6
- package/package/corpus/skills/cratis-components-accessibility/SKILL.md +112 -82
- package/package/corpus/skills/cratis-components-schema-editor/SKILL.md +12 -10
- package/package/corpus/skills/cratis-components-stepper-command-dialog/SKILL.md +11 -12
- package/package/corpus/skills/cratis-components-styling/SKILL.md +204 -170
- package/package/corpus/skills/cratis-components-toolbar/SKILL.md +32 -26
- package/package/corpus/skills/cratis-event-model-diagram/SKILL.md +1 -1
- package/package/corpus/skills/cratis-fundamentals-concept/SKILL.md +2 -2
- package/package/corpus/skills/cratis-fundamentals-type-discovery/SKILL.md +2 -2
- package/package/corpus/skills/cratis-lens-browser-extension/SKILL.md +4 -2
- package/package/corpus/skills/cratis-performance-review/SKILL.md +4 -2
- package/package/corpus/skills/cratis-screenplay-model-authoring/SKILL.md +15 -5
- package/package/corpus/skills/cratis-security-review/SKILL.md +20 -3
- package/package/corpus/skills/cratis-specifications-csharp/SKILL.md +3 -3
- package/package/corpus/skills/cratis-specifications-csharp/references/application-scenarios.md +12 -8
- package/package/corpus/skills/cratis-specifications-csharp/references/csharp-patterns.md +1 -1
- package/package/corpus/skills/cratis-specifications-csharp/references/integration-specs.md +7 -3
- package/package/corpus/skills/cratis-specifications-typescript/SKILL.md +6 -3
- package/package/corpus/skills/cratis-specifications-typescript/references/typescript-patterns.md +21 -4
- package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +29 -17
- package/package.json +1 -1
|
@@ -16,8 +16,10 @@ This skill is verified against these exact sources:
|
|
|
16
16
|
|
|
17
17
|
| Package | Version | Purpose |
|
|
18
18
|
| --- | --- | --- |
|
|
19
|
-
| `Cratis.Cli` | `2.
|
|
20
|
-
|
|
19
|
+
| `Cratis.Cli` | `3.2.0` | the `cratis` command, its contexts, output formats, and command tree |
|
|
20
|
+
|
|
21
|
+
> Re-verified at `Cratis/cli` **v3.2.0** (originally written against 2.4.0): every command, branch, flag and output format this skill names exists there; the 2.x→3.x change is the Chronicle 17/18 wire migration plus new branches (`ai`, `arc`, `screenplay`, `prologue`, `llm`) this skill does not cover.
|
|
22
|
+
| `Cratis.Chronicle` | `18.3.0` | the observer, partition, sequence, and job concepts the CLI reads |
|
|
21
23
|
|
|
22
24
|
The CLI ships a **versioned machine-readable catalog of its own surface**, and
|
|
23
25
|
that catalog is the authority for exact command names on the installed version:
|
|
@@ -110,7 +112,7 @@ error.
|
|
|
110
112
|
| Is the server healthy at all? | `cratis chronicle diagnose` (exit code 3 when unhealthy) |
|
|
111
113
|
| Why has this read model stopped updating? | `chronicle failed-partitions list --observer <id>` — the error is on the partition, not in the log |
|
|
112
114
|
| An observer is quarantined — why? | `chronicle failed-partitions show <observer> <partition> --detailed`, with attempt history |
|
|
113
|
-
| Did this event actually get appended? | `chronicle events get --event-type <type> --event-source-id <id
|
|
115
|
+
| Did this event actually get appended? | `chronicle events get --event-type <type> --event-source-id <id>` (`events tail` returns only the highest sequence number — not a count, not the events) |
|
|
114
116
|
| What is this event's shape in the store? | `chronicle event-types list`, then `chronicle event-types show <type>` |
|
|
115
117
|
| Is this projection registered? | `chronicle projections list`, then `chronicle projections show <id>` |
|
|
116
118
|
| What does the read model actually hold? | `chronicle read-models get <read-model> <key>`, or `read-models instances` |
|
|
@@ -165,16 +167,20 @@ Before any of them:
|
|
|
165
167
|
|
|
166
168
|
### Two confirmation traps
|
|
167
169
|
|
|
168
|
-
**
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
170
|
+
**Destructive commands fail closed outside a terminal.** Every command with a
|
|
171
|
+
confirmation prompt — `observers replay`, `observers replay-partition`,
|
|
172
|
+
`observers retry-partition`, `observers clear-quarantine`, `jobs stop`,
|
|
173
|
+
`jobs resume`, `recommendations perform`, `recommendations ignore`,
|
|
174
|
+
`users remove`, `applications remove`, `subscriptions remove` — asks
|
|
175
|
+
interactively, and when the session is **not** interactive (a script, a
|
|
176
|
+
pipeline, an agent harness) it does *not* proceed: it writes
|
|
177
|
+
"Re-run the command with --yes to confirm the operation" and exits with the
|
|
178
|
+
validation error code. `--yes` is therefore the only way a non-interactive run
|
|
179
|
+
performs one of these, which makes `--yes` the authorization boundary. Declining
|
|
180
|
+
the interactive prompt exits successfully having done nothing.
|
|
181
|
+
|
|
182
|
+
**Additive commands do not prompt.** `users add`, `applications add` and
|
|
183
|
+
`subscriptions add` run without confirmation in every mode.
|
|
178
184
|
|
|
179
185
|
Reaching for `--yes` to silence a prompt you have not read is how the wrong
|
|
180
186
|
store gets replayed. A failed partition you have not yet explained is not a
|
|
@@ -17,16 +17,18 @@ There is no host requirement and no application architecture imposed.
|
|
|
17
17
|
## Verified product sources
|
|
18
18
|
|
|
19
19
|
This skill is verified against the `Cratis/Chronicle` repository at tag
|
|
20
|
-
`
|
|
21
|
-
|
|
20
|
+
`v18.3.0`. Its client sources are unchanged in public shape since `v17.0.1`
|
|
21
|
+
(the 17→18 client diff is converters, options and doc comments), and `v17.0.1`
|
|
22
|
+
was byte-identical to `16.45.2` for every public type cited here except the
|
|
23
|
+
compatibility check noted below.
|
|
22
24
|
|
|
23
25
|
| Package | Line | Purpose |
|
|
24
26
|
| --- | --- | --- |
|
|
25
|
-
| `Cratis.Chronicle` | `
|
|
26
|
-
| `Cratis.Chronicle.Connections` | `
|
|
27
|
-
| `Cratis.Chronicle.AspNetCore` | `
|
|
28
|
-
| `Cratis.Chronicle.Testing` | `
|
|
29
|
-
| `Cratis.Chronicle.CodeAnalysis` | `
|
|
27
|
+
| `Cratis.Chronicle` | `18.3.0` | `ChronicleClient`, `IEventStore`, `[EventType]`, observers |
|
|
28
|
+
| `Cratis.Chronicle.Connections` | `18.3.0` | `ChronicleConnectionString`, connection lifecycle |
|
|
29
|
+
| `Cratis.Chronicle.AspNetCore` | `18.3.0` | ASP.NET Core wiring, header/subdomain namespace resolvers |
|
|
30
|
+
| `Cratis.Chronicle.Testing` | `18.3.0` | in-process scenarios |
|
|
31
|
+
| `Cratis.Chronicle.CodeAnalysis` | `18.3.0` | the analyzers, a **separate opt-in** package |
|
|
30
32
|
|
|
31
33
|
Take the exact version from nuget.org. The version in source is a `1.0.0`
|
|
32
34
|
placeholder injected at pack time (`Source/Directory.Build.props`), so the
|
|
@@ -182,23 +184,23 @@ and an optional `EventStoreNamespaceResolverType`.
|
|
|
182
184
|
Since Chronicle 17 the compatibility check is a server-side RPC, and **the client
|
|
183
185
|
runs it automatically inside `Connect()`** —
|
|
184
186
|
`Source/Clients/Connections/ChronicleConnection.cs:310` calls
|
|
185
|
-
`CheckCompatibility` (`:
|
|
186
|
-
version, and the descriptor set its contracts package was built with (`:
|
|
187
|
-
The rationale is at `:
|
|
187
|
+
`CheckCompatibility` (`:414`), sending the client type, client version, protocol
|
|
188
|
+
version, and the descriptor set its contracts package was built with (`:420-426`).
|
|
189
|
+
The rationale is at `:409-413`: Chronicle has clients in four languages and only
|
|
188
190
|
some can build a descriptor set at runtime, so each ships the one it was built
|
|
189
191
|
with and the server does the single comparison.
|
|
190
192
|
|
|
191
193
|
Behavior you can rely on:
|
|
192
194
|
|
|
193
195
|
- A server too old to have the RPC answers `Unimplemented`, and the client falls
|
|
194
|
-
back to the previous client-side exchange (`:
|
|
196
|
+
back to the previous client-side exchange (`:428-434`) — upgrading the client
|
|
195
197
|
does not silently drop the check.
|
|
196
|
-
- Any other transport error is **logged and ignored** (`:
|
|
198
|
+
- Any other transport error is **logged and ignored** (`:435-441`), on the stated
|
|
197
199
|
reasoning that failing to ask says nothing about whether the two sides agree.
|
|
198
200
|
- A genuine mismatch throws `IncompatibleServerException`
|
|
199
201
|
(`Source/Clients/Connections/IncompatibleServerException.cs:10`) whose message
|
|
200
202
|
names the server address, its version, its protocol version, and the specific
|
|
201
|
-
incompatibilities (`:
|
|
203
|
+
incompatibilities (`:443-449`).
|
|
202
204
|
|
|
203
205
|
The client identifies itself as `".NET"`
|
|
204
206
|
(`Source/Clients/Connections/ChronicleClientIdentity.cs:22`) with its assembly
|
|
@@ -333,8 +335,8 @@ Read models are queried through `eventStore.ReadModels`
|
|
|
333
335
|
Artifacts are found by **assembly scanning**, with no registration call and no DI
|
|
334
336
|
container required. `DefaultClientArtifactsProvider.Default` composes the
|
|
335
337
|
project-referenced and package-referenced assemblies
|
|
336
|
-
(`Source/Clients/DotNET/DefaultClientArtifactsProvider.cs:
|
|
337
|
-
predicates are exactly (`:
|
|
338
|
+
(`Source/Clients/DotNET/DefaultClientArtifactsProvider.cs:37`), and the
|
|
339
|
+
predicates are exactly (`:242-251`):
|
|
338
340
|
|
|
339
341
|
| Kind | Predicate |
|
|
340
342
|
| --- | --- |
|
|
@@ -12,33 +12,37 @@ to yours, and everything after that is ordinary OTP.
|
|
|
12
12
|
|
|
13
13
|
## Verified product sources
|
|
14
14
|
|
|
15
|
-
This skill
|
|
16
|
-
|
|
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.
|
|
17
20
|
|
|
18
21
|
| Fact | Value | Source |
|
|
19
22
|
| --- | --- | --- |
|
|
20
23
|
| OTP app / Hex package | `:cratis_chronicle` | `Source/chronicle/mix.exs:14` |
|
|
21
|
-
| Published
|
|
22
|
-
| Elixir requirement | `~> 1.14` | `Source/chronicle/mix.exs
|
|
23
|
-
| Contracts dependency | `cratis_chronicle_contracts` resolved to `16.13.4` | `Source/chronicle/mix.lock` |
|
|
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` |
|
|
24
27
|
|
|
25
28
|
> **The `v2.3.0` git tag was never published to Hex.** `mix deps.get` cannot
|
|
26
|
-
> fetch it.
|
|
27
|
-
>
|
|
29
|
+
> fetch it. What it introduced — notably the `Chronicle.Concept` macro
|
|
30
|
+
> (`use Chronicle.Concept, type: :string`, a single-value concept that carries its
|
|
31
|
+
> `pii` classification once, mirroring `ConceptAs<T>`) — **is published from
|
|
32
|
+
> `3.0.0`**. On `2.2.0` it does not exist; on `3.x` it is the preferred way to
|
|
33
|
+
> classify a personal value.
|
|
28
34
|
|
|
29
35
|
> **The repository's `VERSION` file says `0.0.5` and is a build-time
|
|
30
36
|
> placeholder** overwritten by the publish workflow. Never quote it.
|
|
31
37
|
|
|
32
|
-
> **
|
|
33
|
-
>
|
|
34
|
-
> `
|
|
35
|
-
> `
|
|
36
|
-
>
|
|
37
|
-
> `
|
|
38
|
-
> `Chronicle.Seeding.Seeder`. **Copy from `Documentation/client-snippets/`
|
|
39
|
-
> instead** — those are CI-validated and correct at every version.
|
|
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
44
|
|
|
41
|
-
> `Documentation/get-started.md:
|
|
45
|
+
> `Documentation/get-started.md:13` pins `{:cratis_chronicle, "~> 0.1"}`, which
|
|
42
46
|
> does not match the published `2.2.0`. Use a `2.x` requirement.
|
|
43
47
|
|
|
44
48
|
## Adding it
|
|
@@ -211,7 +215,7 @@ the outcome.
|
|
|
211
215
|
| `get_from_sequence_number/2` | | `:369` |
|
|
212
216
|
| `get_tail_sequence_number/2` | | `:408` |
|
|
213
217
|
|
|
214
|
-
Append options (`event_log.ex:79-94`): `:client`, `:namespace`,
|
|
218
|
+
Append options (`event_log.ex:79-94`, plus `:occurred` read at `:720`): `:client`, `:namespace`,
|
|
215
219
|
`:event_sequence_id` (default `"event-log"`), `:event_source_type` (default
|
|
216
220
|
`"Default"`), `:event_stream_type` (default **`"All"`**), `:event_stream_id`
|
|
217
221
|
(default `"Default"`), `:tags`, `:subject`, `:correlation_id`, `:identity`,
|
|
@@ -398,9 +402,9 @@ attempt.
|
|
|
398
402
|
|
|
399
403
|
| Pitfall | Why it bites |
|
|
400
404
|
| --- | --- |
|
|
401
|
-
| Copying the root `README.md` | Its module names do not exist
|
|
402
|
-
| Using `Chronicle.Concept` | It
|
|
403
|
-
|
|
|
405
|
+
| Copying the `v2.2.0` root `README.md` | Its module names do not exist; the `3.x` README is correct |
|
|
406
|
+
| Using `Chronicle.Concept` on `2.2.0` | It ships from `3.0.0`; on `2.2.0` annotate fields with `pii/1,2` instead |
|
|
407
|
+
| Copying the dependency line from the README | It lags the published version; take the version from hex.pm |
|
|
404
408
|
| Quoting the `VERSION` file | It is a `0.0.5` build-time placeholder |
|
|
405
409
|
| Putting configuration in `config.exs` | The client reads no application env; options are child-spec keywords |
|
|
406
410
|
| Omitting `:otp_app` | Discovery falls back to scanning every loaded module |
|
|
@@ -13,14 +13,20 @@ you construct a client, ask it for an event store, and append or observe.
|
|
|
13
13
|
|
|
14
14
|
## Verified product sources
|
|
15
15
|
|
|
16
|
-
This skill
|
|
16
|
+
This skill was written against `Chronicle.Kotlin` at tag `v4.0.0` (commit
|
|
17
|
+
`63ff629`) and re-verified at **`v5.1.0`**: every class, function, option and
|
|
18
|
+
Spring bean this skill names exists there. The `4→5` major is the Chronicle 17/18
|
|
19
|
+
wire migration (gRPC request/response shapes and `ensureSuccess` result
|
|
20
|
+
envelopes — internal to the client); `5.0.0` also adds a `ChronicleCommandRejected`
|
|
21
|
+
exception for a rejected server-side command. The `file:line` citations below
|
|
22
|
+
were taken at `v4.0.0` and may have shifted.
|
|
17
23
|
|
|
18
24
|
| Artifact | Version | Verified from |
|
|
19
25
|
| --- | --- | --- |
|
|
20
|
-
| `io.cratis:chronicle` | `
|
|
21
|
-
| `io.cratis:chronicle-spring-boot-starter` | `
|
|
22
|
-
| `io.cratis:chronicle-testing` | `
|
|
23
|
-
| `io.cratis:chronicle-contracts` | `
|
|
26
|
+
| `io.cratis:chronicle` | `5.1.0` | `Chronicle.Kotlin` at tag `v5.1.0` |
|
|
27
|
+
| `io.cratis:chronicle-spring-boot-starter` | `5.1.0` | same tag, `Integrations/SpringBoot` |
|
|
28
|
+
| `io.cratis:chronicle-testing` | `5.1.0` | same tag, `Testing` |
|
|
29
|
+
| `io.cratis:chronicle-contracts` | `18.2.0` | `Source/build.gradle.kts` (`chronicleContractsVersion`) |
|
|
24
30
|
|
|
25
31
|
All three artifacts are published to Maven Central under `io.cratis`
|
|
26
32
|
(`Source/build.gradle.kts:54`, `Testing/build.gradle.kts:32`,
|
|
@@ -35,9 +41,10 @@ All three artifacts are published to Maven Central under `io.cratis`
|
|
|
35
41
|
> the checked-in source never carries the real number. Take it from Maven
|
|
36
42
|
> Central.
|
|
37
43
|
|
|
38
|
-
> **The client and the kernel version independently.** Client `
|
|
39
|
-
> against `chronicle-contracts` `
|
|
40
|
-
>
|
|
44
|
+
> **The client and the kernel version independently.** Client `5.1.0` is built
|
|
45
|
+
> against `chronicle-contracts` `18.2.0` (the `4.x` line was built against
|
|
46
|
+
> `16.44.1` and does not speak the 17/18 wire shapes); the Chronicle server is
|
|
47
|
+
> on `18.x`. Confirm the client/server pair you intend to run is
|
|
41
48
|
> supported before relying on it — do not infer compatibility from the fact that
|
|
42
49
|
> both are "latest".
|
|
43
50
|
|
|
@@ -82,11 +89,11 @@ fun main() = runBlocking {
|
|
|
82
89
|
| `fun evictEventStores()` | `:36` | drops the local cache, keeps the client |
|
|
83
90
|
| `fun dispose()` | `:39` | `IChronicleClient : AutoCloseable`, `close()` delegates to it (`:41`) |
|
|
84
91
|
|
|
85
|
-
**The client connects in its constructor.** `ChronicleClient.kt:
|
|
92
|
+
**The client connects in its constructor.** `ChronicleClient.kt:12` is
|
|
86
93
|
`ChronicleConnection(options.connectionString).also { it.connect() }` — there is
|
|
87
94
|
no separate `connect()` step to call, and constructing the client is the
|
|
88
95
|
connecting act. Event stores are cached per `"$name/$namespace"`
|
|
89
|
-
(`ChronicleClient.kt:
|
|
96
|
+
(`ChronicleClient.kt:21`), so repeated `getEventStore` calls return the same
|
|
90
97
|
instance.
|
|
91
98
|
|
|
92
99
|
The default namespace is the literal `"Default"` —
|
|
@@ -355,13 +362,15 @@ A model-bound projection puts the projection on the read model with `@FromEvent`
|
|
|
355
362
|
(`projections/SetFrom.kt:22`); the full family also includes `SetValue`,
|
|
356
363
|
`SetFromContext`, `AddFrom`, `SubtractFrom`, `Increment`, `Decrement`, `Count`,
|
|
357
364
|
`Join`, `RemovedWith`, `RemovedWithJoin`, `ChildrenFrom`, `ClearWith`,
|
|
358
|
-
`FromAll`, `FromEvery`, `
|
|
365
|
+
`FromAll`, `FromEvery`, `FromEventSourceId`, `CountFromAll`, `IncrementFromAll`,
|
|
366
|
+
`DecrementFromAll`, `Nested`, `NoAutoMap`, `NoAutoMapProperties`,
|
|
367
|
+
`NotRewindable`. The declarative
|
|
359
368
|
alternative is a class implementing `IProjectionFor<TReadModel>`.
|
|
360
369
|
|
|
361
370
|
## Discovery and registration
|
|
362
371
|
|
|
363
372
|
`ClientArtifacts` scans the classpath with ClassGraph
|
|
364
|
-
(`artifacts/ClientArtifacts.kt:
|
|
373
|
+
(`artifacts/ClientArtifacts.kt:66-98`), and `ClientArtifacts.default` is a
|
|
365
374
|
process-wide lazy singleton (`:156`). What it looks for (`:66-98`):
|
|
366
375
|
|
|
367
376
|
| Kind | Rule |
|
|
@@ -377,6 +386,8 @@ process-wide lazy singleton (`:156`). What it looks for (`:66-98`):
|
|
|
377
386
|
| seeders | implements `ICanSeedEvents` |
|
|
378
387
|
| webhooks | implements `IWebhookDefiner` |
|
|
379
388
|
| captures | implements `ICapture` |
|
|
389
|
+
| reactor middlewares | implements `IReactorMiddleware` or `BlockingReactorMiddleware` |
|
|
390
|
+
| reactor argument resolvers | implements `IReactorMethodArgumentResolver` or `BlockingReactorMethodArgumentResolver` |
|
|
380
391
|
|
|
381
392
|
> The `FromEvent$Container` entry is not incidental: Kotlin's `@Repeatable`
|
|
382
393
|
> replaces repeated annotations with a synthetic container, so a class carrying
|
|
@@ -464,7 +475,7 @@ In Spring Boot, Java injects the `Chronicle` bean instead — it already takes
|
|
|
464
475
|
folds a reducer through the same handler-shape rules as production
|
|
465
476
|
(`ReadModelScenario.kt:139-150`). Its scope is small — appends and reducer folds
|
|
466
477
|
only; there is no in-process reactor, projection, or constraint scenario
|
|
467
|
-
(`Testing/api/Testing.api` is
|
|
478
|
+
(`Testing/api/Testing.api` is 57 lines).
|
|
468
479
|
|
|
469
480
|
## Common pitfalls
|
|
470
481
|
|
|
@@ -474,9 +485,9 @@ only; there is no in-process reactor, projection, or constraint scenario
|
|
|
474
485
|
| Two `@EventType` classes sharing a simple name | The id defaults to the simple name, so they collide on the wire (`EventTypesService.kt:67`) |
|
|
475
486
|
| Shipping the default connection string to production | `skipTlsValidation` defaults to **true**; certificate validation is off (`ChronicleConnectionString.kt:28`) |
|
|
476
487
|
| Copying a version from the README or docs | Both are stale at `v4.0.0`; the real version comes from the release, not the source |
|
|
477
|
-
| Expecting `getEventStore` to suspend | It does not — the client already connected in its constructor (`ChronicleClient.kt:
|
|
488
|
+
| Expecting `getEventStore` to suspend | It does not — the client already connected in its constructor (`ChronicleClient.kt:12`) |
|
|
478
489
|
| Expecting `awaitRegistration()` to mean "registered" | It completes in a `finally`, so it also returns after a failed pass (`ArtifactRegistrations.kt:47-57`) |
|
|
479
|
-
| Expecting a registration failure to throw | Failures are printed to `System.err`, not raised (`EventStore.kt:
|
|
490
|
+
| Expecting a registration failure to throw | Failures are printed to `System.err`, not raised (`EventStore.kt:244`) |
|
|
480
491
|
| Expecting read model reactors to be discovered | `IReadModelReactor` is absent from the scan and from `IEventStore`; construct `ReadModelReactors(...)` yourself |
|
|
481
492
|
| Leaving the default classpath scan on in a large app | Use `withArtifactsFrom(...)` or `artifact-packages` to narrow it (`ChronicleOptions.kt:58`) |
|
|
482
493
|
| Expecting WebFlux support from the starter | The web auto-configuration is `SERVLET`-only (`ChronicleWebAutoConfiguration.kt:29`) |
|
|
@@ -13,13 +13,17 @@ HTTP and never sees this package.
|
|
|
13
13
|
|
|
14
14
|
## Verified product sources
|
|
15
15
|
|
|
16
|
-
This skill
|
|
17
|
-
(commit `bed0b86`)
|
|
16
|
+
This skill was written against `Cratis/Chronicle.TypeScript` at tag `v4.0.0`
|
|
17
|
+
(commit `bed0b86`) and re-verified at **`v5.1.0`** (published on npm as
|
|
18
|
+
`5.1.0`): every class, function and option this skill names exists there. The
|
|
19
|
+
`4→5` major is the Chronicle 17/18 wire migration (internal gRPC shapes; it adds
|
|
20
|
+
`ensureCommandResponse` for server-side command results). The `file:line`
|
|
21
|
+
citations below were taken at `v4.0.0` and may have shifted.
|
|
18
22
|
|
|
19
23
|
| Package | Version | Where |
|
|
20
24
|
| --- | --- | --- |
|
|
21
|
-
| `@cratis/chronicle` | `
|
|
22
|
-
| `@cratis/chronicle.contracts` | `
|
|
25
|
+
| `@cratis/chronicle` | `5.1.0` | npm; `Source/package.json` carries a `1.0.0` placeholder |
|
|
26
|
+
| `@cratis/chronicle.contracts` | `18.2.0` | `Source/package.json` dependency at `v5.1.0` |
|
|
23
27
|
| `@cratis/fundamentals` | `^7.14.0` | **peer dependency** — you install it |
|
|
24
28
|
|
|
25
29
|
> **Do not read the version out of the repository.** `Source/package.json` says
|
|
@@ -75,7 +79,7 @@ try {
|
|
|
75
79
|
}
|
|
76
80
|
```
|
|
77
81
|
|
|
78
|
-
`IChronicleClient` is
|
|
82
|
+
`IChronicleClient` is four members — `Source/IChronicleClient.ts:16-39`:
|
|
79
83
|
|
|
80
84
|
| Member | Line |
|
|
81
85
|
| --- | --- |
|
|
@@ -125,7 +129,7 @@ Two facts to carry into production guidance:
|
|
|
125
129
|
is not validated, because a development kernel serves a self-signed
|
|
126
130
|
certificate. Set `?skipTlsValidation=false` against a real server.
|
|
127
131
|
- **A connection string with no credentials silently falls back to the
|
|
128
|
-
development client credentials** (`Source/connection/ChronicleConnection.ts`).
|
|
132
|
+
development client credentials** (`Source/connection/ChronicleConnection.ts:319-326`; the constants live in `ChronicleConnectionString.ts:453-454`).
|
|
129
133
|
An anonymous-looking connection string is not anonymous; it is
|
|
130
134
|
`chronicle-dev-client`.
|
|
131
135
|
|
|
@@ -208,13 +212,13 @@ if (!result.isSuccess) {
|
|
|
208
212
|
`EventContext.sequenceNumber` is a `bigint` too.
|
|
209
213
|
- `AppendOptions` — `Source/eventSequences/AppendOptions.ts`: `correlationId?`,
|
|
210
214
|
`eventSourceId?`, `concurrencyScope?`, `concurrencyScopes?`, and **`tags?`**
|
|
211
|
-
(`:22-29`,
|
|
215
|
+
(`:22-29`, since `4.0.0`; unchanged at `5.1.0`).
|
|
212
216
|
|
|
213
217
|
> **Single `append()` cannot target a stream or a subject.** It hardcodes
|
|
214
218
|
> `EventSourceType: 'Default'`, `EventStreamType: 'Default'`,
|
|
215
219
|
> `EventStreamId: eventSourceId`, and `Subject: eventSourceId`
|
|
216
|
-
> (`Source/eventSequences/EventSequence.ts:100-
|
|
217
|
-
> option in `4.0.0` (`:
|
|
220
|
+
> (`Source/eventSequences/EventSequence.ts:100-120`). Only `tags` became a real
|
|
221
|
+
> option in `4.0.0` (`:118`). To target a different stream or subject, use the
|
|
218
222
|
> `EventForEventSourceId[]` overload, whose entries carry `eventStreamType`,
|
|
219
223
|
> `eventStreamId`, `eventSourceType`, `subject`, and `tags`.
|
|
220
224
|
|
|
@@ -252,7 +256,7 @@ Reducers do the same (`Source/reducers/Reducers.ts:454-460`). A handler whose
|
|
|
252
256
|
method name does not match is simply never called — **there is no error**.
|
|
253
257
|
|
|
254
258
|
> The docstring at `Source/reactors/reactor.ts:28-29` claims dispatch is by the
|
|
255
|
-
> first parameter's type. **It is wrong**, and it is still wrong at `
|
|
259
|
+
> first parameter's type. **It is wrong**, and it is still wrong at `5.1.0`. The
|
|
256
260
|
> code is the authority; so are the client snippets under `Documentation/`, which
|
|
257
261
|
> state the name rule explicitly.
|
|
258
262
|
|
|
@@ -281,7 +285,7 @@ a failed side-effect append fails the partition.
|
|
|
281
285
|
|
|
282
286
|
`@reducer(id?, eventSequenceId?, readModel?, isActive?)` —
|
|
283
287
|
`Source/reducers/reducer.ts:58`. Passing `readModel` also registers that type as a
|
|
284
|
-
read model. **The reducer handler takes three arguments
|
|
288
|
+
read model. **The reducer handler takes three arguments (`4.0.0` through `5.1.0`)** —
|
|
285
289
|
`reducerInstance[methodName](content, currentState, context)`
|
|
286
290
|
(`Source/reducers/Reducers.ts:400`). The third is optional by arity, and a handler
|
|
287
291
|
may be sync or async.
|
|
@@ -17,8 +17,8 @@ This skill is verified against this exact public release:
|
|
|
17
17
|
|
|
18
18
|
| Package | Version | Purpose |
|
|
19
19
|
| --- | --- | --- |
|
|
20
|
-
| `Cratis.Chronicle` | `
|
|
21
|
-
| `Cratis.Chronicle.CodeAnalysis` | `
|
|
20
|
+
| `Cratis.Chronicle` | `18.3.0` | `Cratis.Chronicle.Compliance.GDPR`, `Cratis.Chronicle.SubjectAttribute`, `IEventSequence.Redact`, `IReadModels.Release` |
|
|
21
|
+
| `Cratis.Chronicle.CodeAnalysis` | `18.3.0` | `CHR0026`, `CHR0034`, `CHR0035`, `CHR0043`, `CHR0046` |
|
|
22
22
|
|
|
23
23
|
Reverify product sources before claiming support for another version.
|
|
24
24
|
|
|
@@ -224,7 +224,18 @@ storage, configured under `Cratis:Chronicle:Compliance:Encryption`.
|
|
|
224
224
|
noise: which person owns the resulting document?
|
|
225
225
|
- Bearer tokens, magic links, and signed URLs are secrets, not durable facts.
|
|
226
226
|
Store a keyed hash or an opaque reference. Chronicle has no attribute that
|
|
227
|
-
withholds a secret from the log
|
|
227
|
+
withholds a secret from the log (Arc's `[NotAudited]` keeps a *command
|
|
228
|
+
property* out of the causation chain — see **cratis-arc-command** — but a
|
|
229
|
+
secret placed in an event payload is in the log for good).
|
|
230
|
+
- **Erasure is wider than the event log.** Crypto-shredding removes readability
|
|
231
|
+
of `[PII]` values in events and read models. It does nothing for a copy that
|
|
232
|
+
left Chronicle: an exported CSV, a generated PDF, a search index, an email
|
|
233
|
+
body, a blob the command uploaded, a database backup, or a restored
|
|
234
|
+
encryption-key backup that makes shredded ciphertext readable again. Model the
|
|
235
|
+
erasure request as a flow that covers those destinations too — and decide,
|
|
236
|
+
with the product owner, what happens when a backup is restored (re-erase on
|
|
237
|
+
restore, or a fence that refuses to restore keys). Those are product and legal
|
|
238
|
+
decisions; this skill only insists they are made, not left implicit.
|
|
228
239
|
- If a subject boundary cannot be made person-level without changing product
|
|
229
240
|
behavior, stop and surface the trade-off before implementing.
|
|
230
241
|
|
|
@@ -17,9 +17,11 @@ Constraints are discovered automatically. There is no registration call.
|
|
|
17
17
|
|
|
18
18
|
| Package | Version | Purpose |
|
|
19
19
|
| --- | --- | --- |
|
|
20
|
-
| `Cratis.Chronicle` (client) | `
|
|
21
|
-
| `Cratis.Chronicle` code analysis | `
|
|
22
|
-
| `Cratis.Chronicle.Testing` | `
|
|
20
|
+
| `Cratis.Chronicle` (client) | `18.3.0` | `[Unique]`, `[RemoveConstraint]`, `IConstraint`, `IConstraintBuilder`, `IUniqueConstraintBuilder`, `ConstraintViolation`, `IAppendResult` |
|
|
21
|
+
| `Cratis.Chronicle` code analysis | `18.3.0` | `CHR0017`, `CHR0018`, `CHR0020` |
|
|
22
|
+
| `Cratis.Chronicle.Testing` | `18.3.0` | `EventScenario` and the `IAppendResult` `Should*` assertions |
|
|
23
|
+
|
|
24
|
+
> Re-verified at the versions above by **symbol and signature**: every type, attribute and member this skill names exists at that tag, and the public surface it describes is unchanged since the previous verification (Chronicle 16.45.x / Arc 22.10.4 — the Chronicle 16→18 client diff is converters, options and doc comments; no type was removed or renamed). Behavior claims were verified at the earlier tag unless a section says otherwise.
|
|
23
25
|
|
|
24
26
|
Reverify against the Chronicle repository before claiming support for another
|
|
25
27
|
version. Never translate an attribute argument order or an assertion name from
|
|
@@ -150,9 +152,14 @@ Note the asymmetry: `AppendResult` exposes a singular nullable
|
|
|
150
152
|
`ConcurrencyViolations`. Only the `HasConcurrencyViolations` flag is on the
|
|
151
153
|
interface.
|
|
152
154
|
|
|
153
|
-
⚠️
|
|
154
|
-
|
|
155
|
-
|
|
155
|
+
⚠️ Constraints are evaluated and indexed against the **plaintext** of a `[PII]`
|
|
156
|
+
property, not its ciphertext — PII encryption is non-deterministic (a fresh key
|
|
157
|
+
and nonce per value), so hashing the encrypted form would never detect a
|
|
158
|
+
collision. The kernel builds a plaintext copy for the constraint check and
|
|
159
|
+
persists only the encrypted event; on reindex it releases (decrypts) stored
|
|
160
|
+
content to recompute the hashes, and skips subjects whose key has been erased so
|
|
161
|
+
they do not all collide on the hash of an empty value. The index therefore holds
|
|
162
|
+
plaintext-derived hashes, not the personal value itself.
|
|
156
163
|
|
|
157
164
|
## Step 6 — Specify the violation
|
|
158
165
|
|
|
@@ -25,8 +25,8 @@ This skill is verified against these exact sources:
|
|
|
25
25
|
|
|
26
26
|
| Package | Version | Purpose |
|
|
27
27
|
| --- | --- | --- |
|
|
28
|
-
| `Cratis.Chronicle` | `
|
|
29
|
-
| `Cratis.Chronicle.CodeAnalysis` | `
|
|
28
|
+
| `Cratis.Chronicle` | `18.3.0` | event types, event-source identities, subjects, `[PII]` |
|
|
29
|
+
| `Cratis.Chronicle.CodeAnalysis` | `18.3.0` | `CHR0012`, `CHR0026`, `CHR0034`, `CHR0035` |
|
|
30
30
|
|
|
31
31
|
Reverify product sources before claiming support for another version.
|
|
32
32
|
|
|
@@ -14,8 +14,10 @@ application's constraints discovered and active.
|
|
|
14
14
|
|
|
15
15
|
| Package | Version | Purpose |
|
|
16
16
|
| --- | --- | --- |
|
|
17
|
-
| `Cratis.Chronicle.Testing` | `
|
|
18
|
-
| `Cratis.Chronicle` | `
|
|
17
|
+
| `Cratis.Chronicle.Testing` | `18.3.0` | `EventScenario`, its `Given`/`When` builders, the `IAppendResult` `Should*` assertions |
|
|
18
|
+
| `Cratis.Chronicle` | `18.3.0` | `IEventSequence.Append`/`AppendMany`, `IAppendResult`, `ConstraintViolation` |
|
|
19
|
+
|
|
20
|
+
> Re-verified at the versions above by **symbol and signature**: every type, attribute and member this skill names exists at that tag, and the public surface it describes is unchanged since the previous verification (Chronicle 16.45.x / Arc 22.10.4 — the Chronicle 16→18 client diff is converters, options and doc comments; no type was removed or renamed). Behavior claims were verified at the earlier tag unless a section says otherwise.
|
|
19
21
|
|
|
20
22
|
```bash
|
|
21
23
|
dotnet add package Cratis.Chronicle.Testing
|
|
@@ -43,9 +45,13 @@ version. Never translate an assertion name from memory.
|
|
|
43
45
|
|
|
44
46
|
## When you do not
|
|
45
47
|
|
|
46
|
-
- **Concurrency violations
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
- **Concurrency violations are not what the scenario's defaults exercise.**
|
|
49
|
+
`EventScenario` wires a strategy that always answers `ConcurrencyScope.None`,
|
|
50
|
+
which the validator skips, so an append that lets the strategy pick the scope
|
|
51
|
+
(`When`, or `EventLog.Append` without a `concurrencyScope`) can never report
|
|
52
|
+
`HasConcurrencyViolations`. Only an append that passes an explicit scope on
|
|
53
|
+
`scenario.EventLog.Append(...)` reaches the in-process validator at all — and
|
|
54
|
+
that is a spec of the scope you hand-built, not of the application's strategy. Specify concurrency against
|
|
49
55
|
the real kernel with an out-of-process integration specification, and do not
|
|
50
56
|
write a scenario specification that looks like it covers it — it would pass
|
|
51
57
|
vacuously, which is worse than not having one.
|
|
@@ -22,8 +22,8 @@ This skill is verified against these exact sources:
|
|
|
22
22
|
|
|
23
23
|
| Package | Version | Purpose |
|
|
24
24
|
| --- | --- | --- |
|
|
25
|
-
| `Cratis.Chronicle` | `
|
|
26
|
-
| `Cratis.Chronicle.CodeAnalysis` | `
|
|
25
|
+
| `Cratis.Chronicle` | `18.3.0` | `Cratis.Chronicle.Events` and `Cratis.Chronicle.Events.Migrations` |
|
|
26
|
+
| `Cratis.Chronicle.CodeAnalysis` | `18.3.0` | `CHR0012`, `CHR0037`, `CHR0049`, `CHR0050` |
|
|
27
27
|
|
|
28
28
|
Reverify product sources before claiming support for another version.
|
|
29
29
|
|
|
@@ -23,8 +23,8 @@ This skill is verified against this exact source:
|
|
|
23
23
|
|
|
24
24
|
| Package | Version | Purpose |
|
|
25
25
|
| --- | --- | --- |
|
|
26
|
-
| `Cratis.Chronicle` | `
|
|
27
|
-
| `Cratis.Chronicle.AspNetCore` | `
|
|
26
|
+
| `Cratis.Chronicle` | `18.3.0` | `EventStoreNamespaceName`, `IEventStoreNamespaceResolver`, `IChronicleClient.GetEventStore` |
|
|
27
|
+
| `Cratis.Chronicle.AspNetCore` | `18.3.0` | the header and subdomain namespace resolvers |
|
|
28
28
|
|
|
29
29
|
Reverify product sources before claiming support for another version.
|
|
30
30
|
|
|
@@ -17,7 +17,7 @@ This skill is verified against this exact source:
|
|
|
17
17
|
|
|
18
18
|
| Package | Version | Purpose |
|
|
19
19
|
| --- | --- | --- |
|
|
20
|
-
| `Cratis.Chronicle` | `
|
|
20
|
+
| `Cratis.Chronicle` | `18.3.0` | `Cratis.Chronicle.Projections`, `Cratis.Chronicle.Projections.ModelBound`, `Cratis.Chronicle.Keys`, `Cratis.Chronicle.EventSequences` |
|
|
21
21
|
|
|
22
22
|
Reverify product sources before claiming support for another version.
|
|
23
23
|
|
|
@@ -90,6 +90,20 @@ a read model type is not supported and is not what the API means. If a read mode
|
|
|
90
90
|
needs a field that only another read model has, the model is missing an event —
|
|
91
91
|
fix the event model rather than cross-reading at runtime.
|
|
92
92
|
|
|
93
|
+
### A joined property always wins — do not latch on it
|
|
94
|
+
|
|
95
|
+
A projection re-resolves its joins every time it handles one of the read model's
|
|
96
|
+
own events and applies the joined values **after** the local mappings, so a
|
|
97
|
+
property written both by a `From`/`[SetFrom]` and by a `Join` ends up with the
|
|
98
|
+
joined value regardless of the order the events arrived. A local write can
|
|
99
|
+
therefore never reset or clear a joined property. The natural latch shape — a
|
|
100
|
+
local event sets `IsBlocked = false`, a joined event sets it `true` — compiles,
|
|
101
|
+
reads correctly and silently sticks on the joined value. Give each fact its own
|
|
102
|
+
property (`BlockedAt`, `UnblockedAt`) and derive the outcome from both at the
|
|
103
|
+
query edge. Chronicle's analyzer **`CHR0042` (`JoinOverridesLocalWrite`)** reports
|
|
104
|
+
the overlap; suppress it only when the join is deliberately keeping that property
|
|
105
|
+
fresh.
|
|
106
|
+
|
|
93
107
|
## Selecting the source
|
|
94
108
|
|
|
95
109
|
Class-level `[EventSequence("<name>")]`, `[EventLog]`, or `[EventStore("<name>")]`
|
|
@@ -121,9 +135,14 @@ or a reactor rather than annotating the projection.
|
|
|
121
135
|
`key:` on **both** a parent and a nested or child type for the **same** event
|
|
122
136
|
throws a duplicate-key exception at startup. Keep `[FromEvent<T>]` on the
|
|
123
137
|
nested type only, or switch the nested type to property-level `[SetFrom<T>]`.
|
|
124
|
-
- **
|
|
125
|
-
|
|
126
|
-
|
|
138
|
+
- **Setting the same read-model property twice for one event.** The per-event
|
|
139
|
+
builder refuses a second `Set`/`Increment`/`Decrement`/`Add`/`Subtract` on a
|
|
140
|
+
property it already wrote for that event (`DuplicatePropertyInProjection`,
|
|
141
|
+
thrown while the projection is built at startup). Model-bound, that is two
|
|
142
|
+
attributes for the same `<TEvent>` on one property that both target it — for
|
|
143
|
+
example `[SetFrom<E>]` and `[Count<E>]` together. Several `[SetFromContext<E>]`
|
|
144
|
+
on one member is a different case: it is accepted and **all but the last are
|
|
145
|
+
discarded** — analyzer `CHR0040` reports it.
|
|
127
146
|
- **Chaining after `AutoMap()`/`NoAutoMap()`.** Those two return the base builder
|
|
128
147
|
interface, so `.NotRewindable()`, `.Passive()`, `.ContainerName()`, and
|
|
129
148
|
`.FromEventSequence()` will not compile after them. Put them last.
|
package/package/corpus/skills/cratis-chronicle-projection/references/model-bound-attributes.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Model-bound projection attributes
|
|
2
2
|
|
|
3
|
-
Verified against `Cratis.Chronicle` `
|
|
3
|
+
Verified against `Cratis.Chronicle` `18.3.0`.
|
|
4
4
|
|
|
5
5
|
Unless noted, every attribute below lives in
|
|
6
6
|
`Cratis.Chronicle.Projections.ModelBound`. Generic arity is stated exactly:
|
|
@@ -27,7 +27,7 @@ attribute takes no generic parameter at all.
|
|
|
27
27
|
| --- | --- | --- | --- |
|
|
28
28
|
| `[FromEvent<T>]` | `<T>` | `(string? key = default, string? parentKey = default)`, plus `ConstantKey { get; init; }` | class, struct; repeatable |
|
|
29
29
|
| `[RemovedWith<T>]` | `<T>` | `(string? key = default, string? parentKey = default)` | class, struct, property, parameter; repeatable |
|
|
30
|
-
| `[RemovedWithJoin<T>]` | `<T>` | `(string? key = default)` | property, parameter; repeatable |
|
|
30
|
+
| `[RemovedWithJoin<T>]` | `<T>` | `(string? key = default)` | class, struct, property, parameter; repeatable |
|
|
31
31
|
| `[Nested]` | non-generic | none | property, parameter; single |
|
|
32
32
|
| `[FromAll]` | non-generic | `(string? contextProperty = default, string? property = default)` | **property only**; single |
|
|
33
33
|
| `[FromEvery]` | non-generic | `(string? property = default, string? contextProperty = default)` | property, parameter; single |
|