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