@cratis/pi 7.75.0 → 7.76.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/package/corpus/harnesses/copilot/instructions/vertical-slices.instructions.md +6 -4
  2. package/package/corpus/product-sync.json +14 -14
  3. package/package/corpus/rules/vertical-slices.md +6 -4
  4. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/authorization.md +9 -0
  5. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/observable-emission-guards.md +12 -3
  6. package/package/corpus/skills/cratis-arc-command/references/decisions-and-routing.md +11 -0
  7. package/package/corpus/skills/cratis-arc-command-execution/SKILL.md +3 -0
  8. package/package/corpus/skills/cratis-arc-command-execution/references/occurrence-commands.md +78 -0
  9. package/package/corpus/skills/cratis-arc-command-validation/SKILL.md +10 -36
  10. package/package/corpus/skills/cratis-arc-command-validation/references/input-binding.md +49 -0
  11. package/package/corpus/skills/cratis-arc-command-validation/references/read-model-resolution.md +25 -0
  12. package/package/corpus/skills/cratis-arc-command-validation/references/validation-severity.md +21 -0
  13. package/package/corpus/skills/cratis-arc-ef-core-migration/SKILL.md +7 -1
  14. package/package/corpus/skills/cratis-arc-hosting/SKILL.md +3 -0
  15. package/package/corpus/skills/cratis-arc-hosting/references/connection-resolution.md +61 -0
  16. package/package/corpus/skills/cratis-arc-query-paging/SKILL.md +4 -2
  17. package/package/corpus/skills/cratis-arc-react-page/references/queries-and-commands.md +14 -1
  18. package/package/corpus/skills/cratis-chronicle-client-dotnet/SKILL.md +5 -0
  19. package/package/corpus/skills/cratis-chronicle-client-dotnet/references/immediate-append-refusal.md +40 -0
  20. package/package/corpus/skills/cratis-chronicle-client-dotnet/references/lifecycle.md +4 -0
  21. package/package/corpus/skills/cratis-chronicle-client-dotnet/references/occurrences.md +89 -0
  22. package/package/corpus/skills/cratis-chronicle-client-dotnet/references/pinned-generation-delivery.md +33 -3
  23. package/package/corpus/skills/cratis-chronicle-decision-reads/SKILL.md +5 -2
  24. package/package/corpus/skills/cratis-chronicle-decision-reads/references/admission-and-ownership.md +18 -1
  25. package/package/corpus/skills/cratis-chronicle-event-type-migration/references/pinned-generations.md +6 -0
  26. package/package/corpus/skills/cratis-chronicle-hosting/SKILL.md +3 -0
  27. package/package/corpus/skills/cratis-chronicle-hosting/references/operations.md +26 -0
  28. package/package/corpus/skills/cratis-chronicle-hosting/references/storage-resolution.md +55 -0
  29. package/package/corpus/skills/cratis-chronicle-multi-tenancy/SKILL.md +3 -0
  30. package/package/corpus/skills/cratis-chronicle-multi-tenancy/references/remove-namespace.md +38 -0
  31. package/package/corpus/skills/cratis-chronicle-projection/references/definition-changes.md +26 -0
  32. package/package/corpus/skills/cratis-chronicle-projection/references/model-bound-attributes.md +8 -0
  33. package/package/corpus/skills/cratis-chronicle-reactor/SKILL.md +5 -22
  34. package/package/corpus/skills/cratis-chronicle-reactor/references/starting-and-replaying.md +33 -0
  35. package/package/corpus/skills/cratis-chronicle-read-model/SKILL.md +9 -2
  36. package/package/corpus/skills/cratis-chronicle-read-model/references/queries.md +9 -4
  37. package/package/corpus/skills/cratis-chronicle-reducer/SKILL.md +4 -0
  38. package/package/corpus/skills/cratis-multi-service-architecture/SKILL.md +9 -3
  39. package/package/corpus/skills/cratis-performance-review/SKILL.md +4 -1
  40. package/package/corpus/skills/cratis-screenplay-automations-and-translations/SKILL.md +2 -2
  41. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/realization-and-gap-fill.md +10 -2
  42. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/SKILL.md +9 -9
  43. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/atomic-batches-and-source-mappings.md +2 -2
  44. package/package/corpus/skills/cratis-screenplay-model-authoring/SKILL.md +11 -11
  45. package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-tools.md +9 -0
  46. package/package/corpus/skills/cratis-screenplay-model-authoring/references/model-notes.md +41 -23
  47. package/package/corpus/skills/cratis-screenplay-model-authoring/verification.json +8 -3
  48. package/package/corpus/skills/cratis-screenplay-projections/SKILL.md +19 -12
  49. package/package/corpus/skills/cratis-screenplay-projections/references/pdl-grammar.md +37 -2
  50. package/package/corpus/skills/cratis-screenplay-projections/verification.json +11 -0
  51. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/SKILL.md +37 -40
  52. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/gap-fill-handoff.md +3 -2
  53. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/renderability-gate.md +1 -1
  54. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/verification.json +4 -2
  55. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/coverage-matrix.md +9 -0
  56. package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +13 -30
  57. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +39 -6
  58. package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +5 -2
  59. package/package/corpus/skills/cratis-screenplay-toolchain/references/language-admission.md +15 -5
  60. package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +7 -4
  61. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.json +12 -1
  62. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.version +1 -1
  63. package/package/corpus/skills/cratis-screenplay-toolchain/verification.json +9 -2
  64. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +38 -56
  65. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +23 -13
  66. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/date-comparisons.md +44 -0
  67. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/rendered-application.md +8 -2
  68. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/sandbox-and-specrunner.md +59 -8
  69. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/verification.json +7 -3
  70. package/package.json +1 -1
@@ -43,6 +43,18 @@ function**:
43
43
  The underlying hooks live in `@cratis/arc.react/queries` if you need them
44
44
  directly.
45
45
 
46
+ Requires Arc 22.112.1 for optional-argument changes to refetch snapshot queries
47
+ and for concurrent same-key readers to settle together. Requires Arc 22.113.1
48
+ for cancellation/unmount scope cleanup. Requires Arc 22.116.1 for observable
49
+ page/size/sort changes to resubscribe and for query hooks to stop showing the
50
+ previous key's data or status after arguments, paging or sorting change. Check
51
+ `npm ls @cratis/arc.react`; upgrade older clients rather than relying on these
52
+ state transitions.
53
+
54
+ Each key includes arguments, page, size and sorting. A changed key shows that
55
+ key's cached result, or an initial not-ready result, never the old key's rows.
56
+ Two different pages must not share one request or subscription.
57
+
46
58
  ### The result object
47
59
 
48
60
  Every query hook returns a result carrying:
@@ -69,7 +81,8 @@ states separately instead of collapsing them into "loaded or not":
69
81
  | Converged, empty | `hasData` with an empty `data` and no recent command | the designed empty state |
70
82
  | Converged, populated | `hasData` with items | the content |
71
83
  | Failed | `!isSuccess` / `hasExceptions` / `!isAuthorized` | the matching error affordance |
72
- | Stale refresh | `isPerforming` while `data` still holds the previous result | keep the old content, indicate refresh |
84
+ | Same-key refresh | `isPerforming` while `data` still holds that key's previous result | keep that content, indicate refresh |
85
+ | Changed arguments/page/sort | new key's cached result, or initial not-ready state | show only the new key's content or a skeleton |
73
86
 
74
87
  Two consequences. After a create command, take the **window action on the
75
88
  command's success** (close the dialog, navigate to the new id) and let the list
@@ -28,6 +28,11 @@ Source: `Cratis/Chronicle`.
28
28
 
29
29
  Take the version from nuget.org, not the placeholder version in the source.
30
30
 
31
+ Read references/occurrences.md when recording durable triggers, implementing
32
+ occurrence handlers, or choosing startup/shutdown activation and retry semantics.
33
+ Read references/immediate-append-refusal.md when a unit must prevent immediate
34
+ appends from escaping its atomic receipt boundary before transport.
35
+
31
36
  ## Lifecycle
32
37
 
33
38
  Read [references/lifecycle.md](references/lifecycle.md) when waiting for registration (`WaitForRegistration`, not polling `IsConnected`), diagnosing quiet observers (keepalive loss fails silently, not with an exception), or disposing the client.
@@ -0,0 +1,40 @@
1
+ <!-- Copyright (c) Cratis. All rights reserved. -->
2
+ <!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
3
+
4
+ # Refuse immediate appends before transport
5
+
6
+ Requires Chronicle 19.81.0. Check with `dotnet list package`; older clients cannot
7
+ prevent an escaped immediate append with this API. Return events or stage them
8
+ transactionally instead; detecting an immediate append after it committed is
9
+ not a retry-safe boundary.
10
+
11
+ `IUnitOfWork.RefuseImmediateAppends()` returns a disposable frame. While its first
12
+ frame is alive, native immediate append entry points in the current flow throw
13
+ before transport, including captured sequence references and references to a
14
+ different store. Transactional appends still enroll in the unit. This does not
15
+ enable read protection or change read admission.
16
+
17
+ ## Who completes
18
+
19
+ - With no existing completion owner and no enforced read protection, the first
20
+ frame owns completion. Use that frame's asynchronous `Commit` or `Rollback`.
21
+ - Inside an ASP.NET-owned unit, or an enforcing read-protected unit, the frame is
22
+ refusal-only. Its `Commit` and `Rollback` throw
23
+ `ImmediateAppendRefusalRequiresOwner`; completion stays with the existing owner.
24
+ - Nested frames borrow the refusal scope; they do not acquire completion rights.
25
+ Refusal lasts until the first frame is disposed, even if it already committed.
26
+ - Replacing the ambient unit with `Begin` or `SetCurrent` while the frame lives
27
+ is refused. Dispose the frame at the boundary rather than trying to escape it.
28
+
29
+ This prevents immediate Chronicle writes, not external I/O. Use it around a
30
+ custom unit that must commit atomically with a receipt, and handle the ordinary
31
+ commit result. Do not assume Arc's occurrence executor installs this frame.
32
+
33
+ ## Verify
34
+
35
+ In a spec, attempt an immediate append through both the current event log and a
36
+ previously captured reference; assert that neither reaches transport. Assert
37
+ that transactional work commits with its receipt, that an unsupported kernel
38
+ fails closed, and that borrowed frames cannot complete another owner's unit.
39
+ Run `dotnet test` on the owning project. In-process proof is not a substitute for
40
+ integration coverage of the storage provider's transaction boundary.
@@ -31,6 +31,10 @@ This reference holds registration wiring, the registration wait, keepalive and w
31
31
  falls more than 5 seconds behind is treated as a lost connection, with
32
32
  reconnect backoff capped at 30 seconds. **The failure mode is silence, not an
33
33
  exception** — appends keep working while observers go quiet.
34
+ - Requires Chronicle 19.72.1 for reactor/reducer `ClientIsNotConnected` stream
35
+ failures to reconnect the whole client with a fresh connection id and register
36
+ all observers again. Older clients can retry a stale registration indefinitely;
37
+ check `dotnet list package` before diagnosing that as a quiet handler.
34
38
  - `Dispose()` disposes read model reactors for created stores, cancels the owned
35
39
  connection, and disposes the connection
36
40
  (`Source/Clients/DotNET/ChronicleClient.cs`, `Dispose`).
@@ -0,0 +1,89 @@
1
+ <!-- Copyright (c) Cratis. All rights reserved. -->
2
+ <!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
3
+
4
+ # Durable application occurrences
5
+
6
+ Requires Chronicle 19.77.0 for the .NET occurrence client and testing surface.
7
+ Check with `dotnet list package`; older clients need an upgrade, not an event
8
+ appended just to wake a reactor. The kernel must advertise `occurrences` and,
9
+ for receipted effects, `effect-receipts`; absent or unknown support fails closed.
10
+
11
+ ## Record and handle
12
+
13
+ Occurrences are a durable work queue, not domain events or a compliance store.
14
+ Trigger payloads are plaintext: never put personal data or operational secrets
15
+ in them. Compliance-marked trigger schemas are refused. Keep a stable reference
16
+ and resolve protected information through its owning service instead.
17
+
18
+ ```csharp
19
+ using Cratis.Chronicle.Occurrences;
20
+
21
+ [Trigger("refresh-catalog")]
22
+ public record RefreshCatalog(string Catalog);
23
+ ```
24
+
25
+ Implement `IOccurrenceHandler<RefreshCatalog>` with the signature
26
+ `Task Handle(RefreshCatalog trigger, OccurrenceContext context,
27
+ CancellationToken cancellationToken)`. Handlers are discovered like reactors. Record
28
+ with `eventStore.Occurrences.Record(trigger, idempotencyId)` using a stable
29
+ idempotency id. Inspect `Recorded`, `AlreadyRecorded`, `OccurrenceIdConflict`
30
+ and `OccurrencePayloadInvalid`; a reused id with different content is not a
31
+ successful retry.
32
+
33
+ The client claims due work and renews its fenced lease while the handler runs.
34
+ Failure backs off and eventually quarantines that occurrence without blocking
35
+ later work. A stale lease epoch cannot renew, complete or fail another worker's
36
+ lease. Delivery can repeat after a crash: a lease is not exactly-once execution.
37
+
38
+ ## Receipt boundary
39
+
40
+ Use `context.EffectKey(effectName)` for one stable effect name within an
41
+ occurrence. `IUnitOfWork.UseEffectReceipt(key, response)` commits the receipt
42
+ atomically with transactional events. Zero-event units can also be receipted;
43
+ protected reads still have to validate. A repeated effect returns its stored
44
+ outcome instead of appending again. Unknown commit results are settled by receipt
45
+ lookup, or fail retryably rather than inventing success.
46
+
47
+ Do not put secrets in a receipt response: it is stored data. An external system
48
+ must accept the effect key as its own idempotency key if its effect must survive
49
+ redelivery. A Chronicle receipt cannot make arbitrary network I/O atomic.
50
+
51
+ Read references/immediate-append-refusal.md when a custom receipt boundary must
52
+ prevent immediate appends before transport. In Arc, use the
53
+ **cratis-arc-command-execution** occurrence executor instead of hand-building the
54
+ command's authorization and receipt boundary.
55
+
56
+ ## Startup and shutdown
57
+
58
+ `Startup` and `Shutdown` are built-in triggers. Set `ChronicleOptions.ActivationId`
59
+ to the stable logical deployment activation, not a random id on every restart.
60
+ `ActivationScope.PerProcess` instead selects one activation per process.
61
+ `LifecycleScope.Application` is the default; `AllNamespaces` durably fans out
62
+ over a fixed namespace snapshot, so a crash resumes that fan-out without duplicates.
63
+
64
+ A logical shutdown is recorded by `IOccurrences.EndActivation(id)`; stopping one
65
+ pod is not a logical activation ending. Per-process host shutdown is bounded,
66
+ not guaranteed to run during a kill or crash. ASP.NET Core and generic hosts wire
67
+ the lifecycle service automatically; standalone clients own their lifecycle.
68
+
69
+ ## Specify retries explicitly
70
+
71
+ `OccurrenceScenario<THandler>` in `Cratis.Chronicle.Testing.Occurrences` drives
72
+ a handler through in-process ingress, claims, receipts and completion:
73
+
74
+ - `Record(trigger, idempotencyId)` records without delivering.
75
+ - `DeliverNext()` claims and invokes; advancing `Time` alone delivers nothing.
76
+ - `DeliverWithoutCompleting()` simulates loss after work but before acknowledgement.
77
+ - `Replies` can drop a committed append's reply; `Capabilities` on the testing
78
+ store can model current, old or unknown kernel support.
79
+ - Register real constructor dependencies in `Services` before the first operation.
80
+ Assert durable events and receipts as well as the delivery outcome.
81
+
82
+ There are no background workers, automatic lease renewals or reminders in this
83
+ scenario; it does not prove behavior in a real multi-node cluster. Run
84
+ `dotnet test` on the owning spec project and assert duplicate ingress, redelivery,
85
+ terminal refusal, lost reply and unsupported-capability paths.
86
+
87
+ Requires Chronicle 19.78.0 for `Defaults` and `EventStoreForTesting` constructors
88
+ accepting an `EventStoreName` and `EventStoreNamespaceName`. Scenarios built from
89
+ such defaults inherit that identity; old constructors retain `testing`/`default`.
@@ -3,6 +3,14 @@
3
3
 
4
4
  # Pin event generations before connecting
5
5
 
6
+ ## Contents
7
+
8
+ - Standalone client
9
+ - Host integration
10
+ - Scope and registration
11
+ - Event-store subscription pins
12
+ - Product sources
13
+
6
14
  Requires Chronicle **19.41.0+** for client reactors/reducers and **19.48.0+** for
7
15
  typed materialized projections. Upgrade every kernel silo before enabling the
8
16
  option. `Compatibility` remains the default; adding a generation alone does not
@@ -72,13 +80,35 @@ builder.AddCratisChronicle(options =>
72
80
  submitted as both wildcard and `Pinned` is unsupported and rejected by the
73
81
  kernel with `EventGenerationDeliveryNotSupported`; the option does not make
74
82
  wildcard pinning work.
75
- - Ad-hoc queries/event reads are not opted in. Neither are webhooks, captures,
76
- or event-store subscriptions. Do not generalize this option to every read
77
- path, or to unreleased generation-delivery work.
83
+ - Ad-hoc queries/event reads, webhooks and captures are not opted in. Event-store
84
+ subscriptions have their own builder opt-in below; the client-wide setting
85
+ does not enable it.
78
86
 
79
87
  For delivery-time migration, persisted PDL pins, and testing limits, read
80
88
  [the migration reference](../../cratis-chronicle-event-type-migration/references/pinned-generations.md).
81
89
 
90
+ ## Event-store subscription pins
91
+
92
+ Requires Chronicle 19.66.0 on client and kernel. Check `dotnet list package`
93
+ and the deployed kernel tag; older builders may throw
94
+ `EventStoreSubscriptionGenerationDeliveryNotSupported`. Compatibility remains
95
+ the default.
96
+
97
+ On `eventStore.Subscriptions.Subscribe(id, sourceStore, configure)`, configure
98
+ `WithGenerationDelivery(EventGenerationDelivery.Pinned)` and either
99
+ `WithEventType<TEvent>()` for that CLR type's declared generation or
100
+ `WithEventType(eventTypeId, generation)` for an explicit pin. This selects the
101
+ generation forwarded into the target inbox during live delivery, catch-up,
102
+ replay and partition retries; it is separate from the inbox observer's own pin.
103
+
104
+ Both stores must register the generation. Registration refuses a missing
105
+ source/target generation or two generations of the same identifier. If the
106
+ target loses its pin at forwarding time, the failing batch appends nothing and
107
+ does not advance past the failing event; earlier acknowledged events stay
108
+ acknowledged. Changing only a pin or delivery mode rebinds the subscription in
109
+ place, without an unsubscribe. Verify migration and protected-value release
110
+ through real-client integration, not just a handler fed the desired CLR type.
111
+
82
112
  ## Product sources
83
113
 
84
114
  Source: `Cratis/Chronicle`:
@@ -143,8 +143,11 @@ command protection, caching and enrollment; older Arc refuses them.
143
143
  Enroll the read **before** staging its decision's events through
144
144
  `EventLog.Transactional` and let the owning unit of work commit. Inspect
145
145
  `IsSuccess`, append errors/constraint violations/concurrency violations and
146
- `GetDecisionConflicts()`; the latter reports decision conflicts without exposing
147
- sequence numbers. On a kernel whose append validators accept an empty batch
146
+ `GetDecisionConflicts()`. Requires Chronicle 19.76.0 for the nullable
147
+ `ConflictingEventTypeId` and `ConflictingEventSequenceNumber` on decision conflicts
148
+ and concurrency violations. They name the first event matching the failed guard;
149
+ older kernels leave both null. Conflict JSON contains the read-model identifier,
150
+ not its CLR type. Check with `dotnet list package` before asserting these fields. On a kernel whose append validators accept an empty batch
148
151
  (a kernel that does so when a scope carries an actual boundary or expects no matching event), a checked empty
149
152
  append validates its scope and writes nothing; a kernel that rejects it surfaces
150
153
  `DecisionReadValidateOnlyNotSupported`, which fails closed. Do not mistake "no
@@ -21,7 +21,7 @@ an adapter for arbitrary read-model storage:
21
21
  | OpenEndedEventTypes / Derivatives / FromEventProperty | all-events, FromEvery, or event-property routing |
22
22
  | NotEventSourceKeyed / KeyConversion | keys not convertible to the admitted raw source key |
23
23
  | NoEventTypes / UnsupportedEventTypeId | no finite guarded type set or unsupported encoded type ids |
24
- | InvalidKey / FoldIncomplete / DefinitionMismatch | runtime key, fold or client/kernel definition disagreement |
24
+ | InvalidKey / FoldIncomplete / DefinitionMissing / DefinitionMismatch | runtime key, fold, missing kernel definition or client/kernel definition disagreement |
25
25
  | StreamKeyRequiresStreamScope | stream-keyed model read without a stream scope |
26
26
  | StreamScopeNotSupported / AllStreamsNotSupported / StreamKeyRequiresExplicitStreamId | unsupported stream reader or incomplete stream selection |
27
27
 
@@ -35,6 +35,12 @@ Do not silently replace a refused decision read with a materialized sink read.
35
35
  Redesign the decision model as a focused admitted projection only when the
36
36
  contract permits it, or surface the missing capability.
37
37
 
38
+ Requires Chronicle 19.75.0 for `DefinitionMissing` to be distinct from
39
+ `DefinitionMismatch`. Refusals are not cached, a read checks definitions once
40
+ more before refusing, and agreement is invalidated on connect/disconnect. A
41
+ matching definition can therefore recover after restart without restarting the
42
+ application. Check `dotnet list package`; older clients can retain a refusal.
43
+
38
44
  ## Completion is owned
39
45
 
40
46
  `IUnitOfWork.HasEnrolledDecisionReads` is sticky: it remains true after commit,
@@ -53,6 +59,17 @@ all late staging. Protected work and owner completion checks remain enforced;
53
59
  `UnitOfWorkIsCompleting` must not be caught and interpreted as success. An
54
60
  in-flight commit cannot be undone by a competing rollback.
55
61
 
62
+ Requires Chronicle 19.76.0 for `IUnitOfWork.SuspendReadRegions()`: nested hosts
63
+ can suspend inherited regions and restore them by disposing the scope. This is
64
+ not permission to bypass a guarded decision. Arc uses it from 22.113.0;
65
+ read-model injection outside the command decision under `On` is refused unless
66
+ the model is deliberately `[Unprotected("why")]`.
67
+
68
+ Requires Chronicle 19.81.0 for `RefuseImmediateAppends()`, which changes immediate
69
+ write admission, not read admission. Read
70
+ **cratis-chronicle-client-dotnet**'s immediate-append refusal reference before
71
+ claiming completion rights for its returned frame.
72
+
56
73
  Keep read, decision, enrollment and completion inside one ambient async context.
57
74
  If a commit rejects the read, start a new read/decision attempt rather than
58
75
  reusing the stale protected instance or appending its events without the guard.
@@ -51,6 +51,12 @@ client and kernel registration exception names. Changing a reactor/reducer's
51
51
  pin or delivery mode does not itself trigger replay; request replay when prior
52
52
  state needs rebuilding.
53
53
 
54
+ Requires Chronicle 19.66.0 for generation-pinned event-store subscriptions.
55
+ Their builder opts in separately with `WithGenerationDelivery(Pinned)` and
56
+ explicit or typed event pins; the global observer option does not opt them in.
57
+ Both source and target stores must register the generation. Read the client
58
+ reference above for registration and forwarding failure behavior.
59
+
54
60
  ## PDL pins are resolved once, when saved
55
61
 
56
62
  For a PDL definition saved with `GenerationDelivery = Pinned`, a bare reference
@@ -48,6 +48,9 @@ operator/kernel surface, not an application-profile layout rule.
48
48
  development database ports on loopback only; a host application needing MongoDB
49
49
  must be able to reach port 27017. Do not expose unauthenticated MongoDB.
50
50
 
51
+ Read references/storage-resolution.md when choosing per-namespace destinations,
52
+ separate schema/runtime identities, SQL schemas, or disabling automatic creation.
53
+
51
54
  ## Supply certificates before starting production
52
55
 
53
56
  Default TLS needs a PFX certificate with a private key:
@@ -65,6 +65,32 @@ on every silo and resume from the last durable position after a failed window.
65
65
  Check the kernel version and shutdown logs; neither guarantee makes an interrupted
66
66
  external effect exactly once.
67
67
 
68
+ Requires Chronicle 19.77.4 for an observer replaced by a newer connected client
69
+ to hand over to a still-connected older client when the newer one disconnects.
70
+ The newest registration wins while both are connected; the older handler does
71
+ not receive event types only the departed client handled. Check the kernel tag;
72
+ older kernels can leave that observer stopped.
73
+
74
+ ### Job acceptance and bounded recovery
75
+
76
+ Requires Chronicle 19.80.0 for `IJobs.Stop` and `IJobs.Resume` to return
77
+ `JobCommandResult` with `Accepted` and a refusal reason. A completed RPC is not
78
+ an accepted operation: inspect the result. `RetryFailedPartitions` retries
79
+ partitions through bounded per-partition jobs without reopening a concluded
80
+ replay. Do not invent a CLI flag for this contract operation.
81
+
82
+ Timed-out job steps retry up to five attempts. Replay work has at most 16
83
+ partition steps active, but projection replay/catch-up still use the single
84
+ ordered step above; do not generalize partition parallelism to projections.
85
+ Running jobs whose steps concluded over two minutes ago are reconciled, and
86
+ replay-complete notifications retry. These recovery paths do not clear quarantine or
87
+ prove historical completeness. Check the kernel/client version before relying
88
+ on acceptance results; older clients do not expose them.
89
+
90
+ Requires Chronicle 19.77.2 for stopped/deactivated catch-up and replay steps to
91
+ drain within the job-step stop timeout and resume from their durable checkpoint.
92
+ This does not make external effects exactly once.
93
+
68
94
  ### Next-event lookup failures
69
95
 
70
96
  Routing keeps the saved position and defers observation when
@@ -0,0 +1,55 @@
1
+ <!-- Copyright (c) Cratis. All rights reserved. -->
2
+ <!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
3
+
4
+ # Resolve kernel storage destinations and identities
5
+
6
+ Requires Chronicle 19.74.0 for storage connection resolution.
7
+ Requires Chronicle 19.74.2 for the kernel startup fix; the first two patches
8
+ of this feature fail startup. Check the deployed image tag before changing configuration. Without resolution, configured storage
9
+ behavior stays unchanged.
10
+
11
+ ## Scope and purpose
12
+
13
+ `storage.connectionResolution` uses Arc's connection contract with `Connection`
14
+ then `Identity` slots. Choose `Default`, `Template`, `Http`, or `Custom` for an
15
+ in-process kernel. The HTTP request scope includes `kind`, `eventStore` and
16
+ `namespace`. A resolver may supply connection string, database, schema or
17
+ identity independently. Supply credentials through approved configuration or
18
+ the trusted resolver, never source files or logs.
19
+
20
+ Resolution covers event-store, namespace and read-model databases on SQL and
21
+ MongoDB. A resolved connection string or database is used as given, without
22
+ name derivation or a `DatabaseNames` binding. Moving the resolved destination
23
+ is not a data migration. Existing data, schema and permissions must be prepared
24
+ at the intended location before traffic is moved.
25
+
26
+ The cluster database's location stays on `storage.connectionDetails`; its
27
+ identity can resolve for `Schema` work. Schema creation, migrations, table
28
+ migrations and replay swaps use `Schema`; data access uses `Runtime`. Do not
29
+ assume namespace job storage and cluster storage use the same purpose or scope.
30
+
31
+ ## Schema and provisioning
32
+
33
+ `storage.createIfMissing = false` makes a missing database or schema fail with
34
+ `DatabaseDoesNotExist` or `SchemaDoesNotExist` instead of creating it.
35
+ `storage.schema` selects Chronicle's SQL schema. PostgreSQL puts it first on
36
+ the search path; SQL Server requires the database user's default schema to
37
+ match or migration fails with `DefaultSchemaMismatch`. Schema discovery only
38
+ considers that schema, not a same-named table elsewhere in a shared database.
39
+
40
+ ## Identity rotation
41
+
42
+ SQL resolves identities each time a connection opens, including refreshed
43
+ passwords or tokens. A failed login drops the cached resolution before retry.
44
+ MongoDB separates clients with different credentials and supports MONGODB-OIDC
45
+ access tokens refreshed through resolution. Password-based MongoDB clients do
46
+ not acquire a new password merely because configuration changes; restart them
47
+ when rotating that credential.
48
+
49
+ ## Verify
50
+
51
+ Use the real target provider in integration specs: resolve two namespace
52
+ destinations, verify data isolation, run schema-purpose migration with its own
53
+ identity, and assert missing schema/database failure when creation is disabled.
54
+ Exercise expiry and failed-login invalidation without printing the resolved
55
+ credentials. A healthy process alone does not prove the selected destination.
@@ -28,6 +28,9 @@ Sources:
28
28
 
29
29
  Reverify product sources before claiming support for another version.
30
30
 
31
+ Read references/remove-namespace.md when removing a tenant: provider-owned data,
32
+ application read models, reminders and reconnect behavior have different boundaries.
33
+
31
34
  ## The concept
32
35
 
33
36
  | Term | Meaning |
@@ -0,0 +1,38 @@
1
+ <!-- Copyright (c) Cratis. All rights reserved. -->
2
+ <!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
3
+
4
+ # Remove a namespace
5
+
6
+ Requires Chronicle 19.73.0 for `IEventStore.RemoveNamespace`.
7
+ Requires Chronicle 19.75.1 for reminder cleanup.
8
+ Requires Chronicle 19.76.1 for concurrent re-subscription recovery.
9
+ Requires client 19.77.1 for forgetting a removed namespace on reconnect. Check
10
+ with `dotnet list package` and the kernel image tag; older pairs can recreate
11
+ an apparently removed namespace.
12
+
13
+ This is destructive tenant removal, not a way to hide a tenant in the UI.
14
+ Before calling it, confirm the named event store and namespace, the authorized
15
+ scope, backups and application-owned storage disposition. Never target the
16
+ default namespace: its removal is refused. Removing an unknown namespace is a
17
+ no-op, and an interrupted removal can be repeated.
18
+
19
+ Removal first stops listing the namespace, unsubscribes and removes its
20
+ observers and their persistent reminders, then drops provider-owned namespace
21
+ storage and forgets the namespace. Forwarding and pattern observers with no
22
+ saved state are included through their reminders. Re-subscriptions already in
23
+ flight are handled by bounded unsubscribe/remove retries.
24
+
25
+ MongoDB drops its namespace database. SQL and in-memory providers retain their
26
+ namespace data; do not claim removal is erasure in those providers. Application
27
+ read-model databases are not dropped: the application owns that data and its
28
+ separately authorized cleanup.
29
+
30
+ On reconnect a non-default store asks whether its namespace still exists. If
31
+ absent, it releases that store instead of re-registering it; if the kernel
32
+ cannot answer, registration follows the older behavior. Explicitly using the
33
+ namespace again can create it anew. Stop or reroute writers when removal must
34
+ remain final.
35
+
36
+ Verify removal with a matching kernel and provider, including restart and
37
+ reconnect, and separately inspect the disposition of application-owned data.
38
+ Do not create or delete a live tenant merely to test this workflow.
@@ -23,5 +23,31 @@ history. Sources: `Documentation/projections/registration-lifecycle.md`,
23
23
  `Documentation/concepts/observers.mdx`, `Observation/Jobs/{CatchUpObserver,ReplayObserver}.cs`
24
24
  and `Observation/States/Routing.cs` (under `Source/Kernel/Core/`).
25
25
 
26
+ ## Rolling deployment versions
27
+
28
+ Requires Chronicle 19.79.0 on client and kernel for projection registration's
29
+ `ChronicleOptions.SoftwareVersion`. It defaults to the entry assembly's informational version;
30
+ `Cratis:Chronicle:SoftwareVersion` overrides it, and startup warns on `1.0.0`.
31
+ Check `dotnet list package` and the kernel image tag; older kernels ignore it.
32
+
33
+ The kernel compares semantic-version precedence, including prerelease labels.
34
+ An older definition cannot overwrite a newer stored version, and an older
35
+ full-set registration cannot retire newer projections. Equal, missing or
36
+ unparseable versions retain ordinary registration behavior. An intentional
37
+ rollback must give the older code a software version higher than the stored
38
+ one. Changing only software version does not request a replay; definition
39
+ evolution policy still determines that.
40
+
41
+ ## Namespace reconciliation
42
+
43
+ Requires Chronicle 19.81.1 for projections and captures to reconcile subscriptions
44
+ in every namespace, including runtime-created namespaces. Explicit ensure waits
45
+ for healthy subscriptions; implicit first-append creation is reconciled within
46
+ a watchdog interval. A broken definition does not block healthy ones or creation.
47
+ A lost subscription is repaired, but reconciliation never lifts quarantine,
48
+ revives a retired observer, or restarts a stopped/deleted capture. A kernel
49
+ restart or a newly added namespace still ends projection quarantine through a
50
+ fresh subscription; do not interpret ordinary watchdog repair as operator clear.
51
+
26
52
  Closing a stream does not erase its events or prevent a projection replay.
27
53
  Keep the closing fact as history; see **cratis-chronicle-event-constraints**.
@@ -59,6 +59,14 @@ pair it with `[NotRewindable]`. `[NotProjected]` excludes a query-assembled memb
59
59
  from AutoMap and CHR0024. Sources: `Projections/ModelBound/NotProjectedAttribute.cs`,
60
60
  `Projections/FromEveryBuilder.cs`, and `Documentation/projections/model-bound/`.
61
61
 
62
+ Requires Chronicle 19.78.1 for `[FromAll]`/`[FromEvery]` properties under
63
+ `[ChildrenFrom<T>]` or `[Nested]` to be declared on the child itself, including
64
+ the event creating it. Parent all-event mappings are not copied into children.
65
+ Older client definitions with root-declared child mappings work only when the
66
+ root has no property with the same name; otherwise the mapping stays on the
67
+ root until the client is upgraded. Check client/kernel versions and replay
68
+ affected projections to rebuild already materialized child values.
69
+
62
70
  ## Setting values
63
71
 
64
72
  | Attribute | Arity | Parameters | Targets |
@@ -133,32 +133,15 @@ re-delivers the event as an ordinary observation, and a `[OnceOnly]` handler run
133
133
  again. Catch-up and crash redelivery are not replay either; every ordinary
134
134
  matching event can run, even on the same source. Keep effects idempotent.
135
135
 
136
- **A reactor new to a store catches up the whole history on first registration, and
137
- `[OnceOnly]` does not cover that.** For a side-effect reactor (jobs, AI or external
138
- calls), start the observer at the tail or have the handler ignore facts that
139
- predate its registration, and specify that history causes nothing. A
140
- reconciliation sweep that decides from a read model must not run while that model's
141
- observer is replaying or behind: a rebuilding model looks like "never processed".
142
- Decide from the events or a `[Passive]` model, and specify the replaying case.
136
+ **A new reactor catches up history; `[OnceOnly]` does not stop that.**
137
+ Requires Chronicle 19.70.0 for `[StartAtTail]` to start only its first registration
138
+ at the tail; existing positions remain. Upgrade the server first: older kernels
139
+ ignore it. Read references/starting-and-replaying.md when avoiding pre-registration
140
+ side effects or choosing alternate replay behavior.
143
141
 
144
142
  Analyzer **CHR0022** (warning) requires `[OnceOnly]` on a handler that returns
145
143
  event side effects, because a replay would otherwise append duplicates.
146
144
 
147
- `Cratis.Chronicle.Reactors.ReplayAttribute` (`[Replay]`) is the other half, and
148
- targets a method only. Mark a **second** handler for the same event type with it
149
- when replay needs to do something *different* rather than nothing:
150
-
151
- ```csharp
152
- public Task <MethodName>(<EventName> @event) => <serviceName>.<Operation>(@event.<Property>);
153
-
154
- [Replay]
155
- public Task <MethodName>DuringReplay(<EventName> @event) => Task.CompletedTask;
156
- ```
157
-
158
- With a `[Replay]` handler present, only it runs during replay. Without one, the
159
- ordinary handler runs during replay as before. An event type handled *only* by a
160
- `[Replay]` handler is still subscribed to.
161
-
162
145
  ## Identity and event sequence
163
146
 
164
147
  `Cratis.Chronicle.Reactors.ReactorAttribute` takes two optional arguments:
@@ -0,0 +1,33 @@
1
+ <!-- Copyright (c) Cratis. All rights reserved. -->
2
+ <!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
3
+
4
+ # Start at the tail and distinguish replay
5
+
6
+ Requires Chronicle 19.70.0 for `[StartAtTail]` in
7
+ `Cratis.Chronicle.Reactors`. Upgrade the server before the client: an older
8
+ server ignores the field and catches up from the beginning. Check with
9
+ `dotnet list package` and the kernel image tag.
10
+
11
+ Put `[StartAtTail]` on a side-effect reactor that should observe only future
12
+ events. It changes the **first registration**: an observer already holding a
13
+ position keeps it. Leaving the attribute in place is safe, but adding it is not
14
+ a command to fast-forward an existing observer. Specify that historical facts
15
+ cause no effect on first registration.
16
+
17
+ `[OnceOnly]` excludes replay, not initial catch-up, failed-partition recovery
18
+ or crash redelivery. Keep side effects idempotent. A reconciliation sweep must
19
+ not decide from a model that is replaying or behind: rebuilding state can look
20
+ like "never processed". Decide from events or a passive model and cover that case.
21
+
22
+ ## Alternate replay behavior
23
+
24
+ `Cratis.Chronicle.Reactors.ReplayAttribute` targets a method. Mark a second
25
+ handler for the same event type when replay must do different work. With that
26
+ handler present only it runs during replay; without one, the ordinary handler
27
+ runs unless excluded by `[OnceOnly]`. An event type handled only by a `[Replay]`
28
+ handler is still subscribed to.
29
+
30
+ Verify first registration, restart with an existing position, replay and
31
+ failed-partition redelivery separately. Assert the external effect count, not
32
+ only that the handler was invoked. Run `dotnet test` on the owning spec project;
33
+ server-first compatibility and durable positions also need kernel integration.
@@ -215,8 +215,8 @@ current rather than eventually consistent.
215
215
  **Passive is fresher, not safer.** A materialized read may lag the log; a passive
216
216
  read is current when read. Neither captures a position or enrolls a guard, so
217
217
  neither makes a rule hold when two requests race. To guard a decision use a decision
218
- read over a flat, event-source-keyed projection with an `Id` property (reducers and
219
- self-reducing models are refused), a constraint for uniqueness, or an aggregate;
218
+ read over an admitted projection or unfiltered dependency-free reducer, a
219
+ constraint for uniqueness, or an aggregate;
220
220
  see [choosing how a rule holds](../cratis-chronicle-decision-reads/references/choosing-how-a-rule-holds.md).
221
221
 
222
222
  **`IMongoCollection<T>` reads only the sink.** It cannot compute passive state:
@@ -227,6 +227,13 @@ read-model parameter injection) when you need its computed state. Do not remove
227
227
  Keep secret-bearing state on the protected access path; project only safe
228
228
  metadata into a separate list/search model.
229
229
 
230
+ Requires Chronicle 19.77.3 for strongly consistent per-key projections to fold
231
+ from the start on every read: passive, stream-scoped, wildcard-key and session
232
+ reads immediately reflect revisions, redactions and joined-subject erasure.
233
+ Earlier warm reads can retain old content. Each read costs O(key history), not
234
+ an incremental suffix; prefer materialization for frequent long-history reads.
235
+ Check the deployed kernel tag before relying on this freshness.
236
+
230
237
  The number of passive types is not itself a performance smell. Review event
231
238
  history length, invocation frequency, and the consistency/security requirement;
232
239
  repeated reconstruction of large histories on a hot path is the concern.
@@ -32,10 +32,15 @@ Chronicle extensions — Chronicle declares no `Observe` on `IMongoCollection<T>
32
32
 
33
33
  ## Discovery rules
34
34
 
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
35
+ Arc discovers eligible **public and internal static** methods on `[ReadModel]`
36
+ types. Internal visibility is not an endpoint privacy boundary. Keep helpers
37
+ outside the read model, regardless of their visibility. Use
38
+ `[ReadModel(RequireQueryAttribute = true)]` and `[Query]` on intended endpoints
39
+ when the type also has folds (`Create`/`Reduce`); `[Query]` alone does not hide
40
+ siblings. Requires Arc 22.27.1 for exclusion of private, protected, special-name
41
+ and compiler-generated methods; older versions can expose private statics too.
42
+ Check with `dotnet list package`; on older versions move helpers out rather
43
+ than relying on visibility. ARC0026 checks invalid/ambiguous
39
44
  query declarations; ARCCHR0019 warns about fold-like statics exposed by convention.
40
45
  Requires Arc 22.90.0 for automatic exclusion of methods taking the model itself,
41
46
  including `Reduce(event, current)`; `[Query]` cannot force such a method into an