@cratis/pi 7.74.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 (75) hide show
  1. package/package/corpus/harnesses/copilot/instructions/vertical-slices.instructions.md +6 -4
  2. package/package/corpus/harnesses/pi/extensions/cratis-hooks/index.ts +5 -2
  3. package/package/corpus/hooks/README.md +27 -3
  4. package/package/corpus/hooks/scripts/cratis-quality-gate.sh +67 -4
  5. package/package/corpus/hooks/scripts/quality-gates.json +7 -1
  6. package/package/corpus/product-sync.json +14 -14
  7. package/package/corpus/rules/general.md +1 -0
  8. package/package/corpus/rules/vertical-slices.md +6 -4
  9. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/authorization.md +9 -0
  10. package/package/corpus/skills/cratis-arc-authentication-authorization-and-identity/references/observable-emission-guards.md +12 -3
  11. package/package/corpus/skills/cratis-arc-command/references/decisions-and-routing.md +11 -0
  12. package/package/corpus/skills/cratis-arc-command-execution/SKILL.md +3 -0
  13. package/package/corpus/skills/cratis-arc-command-execution/references/occurrence-commands.md +78 -0
  14. package/package/corpus/skills/cratis-arc-command-validation/SKILL.md +10 -36
  15. package/package/corpus/skills/cratis-arc-command-validation/references/input-binding.md +49 -0
  16. package/package/corpus/skills/cratis-arc-command-validation/references/read-model-resolution.md +25 -0
  17. package/package/corpus/skills/cratis-arc-command-validation/references/validation-severity.md +21 -0
  18. package/package/corpus/skills/cratis-arc-ef-core-migration/SKILL.md +7 -1
  19. package/package/corpus/skills/cratis-arc-hosting/SKILL.md +3 -0
  20. package/package/corpus/skills/cratis-arc-hosting/references/connection-resolution.md +61 -0
  21. package/package/corpus/skills/cratis-arc-query-paging/SKILL.md +4 -2
  22. package/package/corpus/skills/cratis-arc-react-page/references/queries-and-commands.md +14 -1
  23. package/package/corpus/skills/cratis-chronicle-client-dotnet/SKILL.md +5 -0
  24. package/package/corpus/skills/cratis-chronicle-client-dotnet/references/immediate-append-refusal.md +40 -0
  25. package/package/corpus/skills/cratis-chronicle-client-dotnet/references/lifecycle.md +4 -0
  26. package/package/corpus/skills/cratis-chronicle-client-dotnet/references/occurrences.md +89 -0
  27. package/package/corpus/skills/cratis-chronicle-client-dotnet/references/pinned-generation-delivery.md +33 -3
  28. package/package/corpus/skills/cratis-chronicle-decision-reads/SKILL.md +5 -2
  29. package/package/corpus/skills/cratis-chronicle-decision-reads/references/admission-and-ownership.md +18 -1
  30. package/package/corpus/skills/cratis-chronicle-event-type-migration/references/pinned-generations.md +6 -0
  31. package/package/corpus/skills/cratis-chronicle-hosting/SKILL.md +3 -0
  32. package/package/corpus/skills/cratis-chronicle-hosting/references/operations.md +26 -0
  33. package/package/corpus/skills/cratis-chronicle-hosting/references/storage-resolution.md +55 -0
  34. package/package/corpus/skills/cratis-chronicle-multi-tenancy/SKILL.md +3 -0
  35. package/package/corpus/skills/cratis-chronicle-multi-tenancy/references/remove-namespace.md +38 -0
  36. package/package/corpus/skills/cratis-chronicle-projection/references/definition-changes.md +26 -0
  37. package/package/corpus/skills/cratis-chronicle-projection/references/model-bound-attributes.md +8 -0
  38. package/package/corpus/skills/cratis-chronicle-reactor/SKILL.md +5 -22
  39. package/package/corpus/skills/cratis-chronicle-reactor/references/starting-and-replaying.md +33 -0
  40. package/package/corpus/skills/cratis-chronicle-read-model/SKILL.md +9 -2
  41. package/package/corpus/skills/cratis-chronicle-read-model/references/queries.md +9 -4
  42. package/package/corpus/skills/cratis-chronicle-reducer/SKILL.md +4 -0
  43. package/package/corpus/skills/cratis-multi-service-architecture/SKILL.md +9 -3
  44. package/package/corpus/skills/cratis-performance-review/SKILL.md +4 -1
  45. package/package/corpus/skills/cratis-screenplay-automations-and-translations/SKILL.md +2 -2
  46. package/package/corpus/skills/cratis-screenplay-automations-and-translations/references/realization-and-gap-fill.md +10 -2
  47. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/SKILL.md +9 -9
  48. package/package/corpus/skills/cratis-screenplay-captures-and-reactions/references/atomic-batches-and-source-mappings.md +2 -2
  49. package/package/corpus/skills/cratis-screenplay-model-authoring/SKILL.md +11 -11
  50. package/package/corpus/skills/cratis-screenplay-model-authoring/references/mcp-tools.md +9 -0
  51. package/package/corpus/skills/cratis-screenplay-model-authoring/references/model-notes.md +41 -23
  52. package/package/corpus/skills/cratis-screenplay-model-authoring/verification.json +8 -3
  53. package/package/corpus/skills/cratis-screenplay-projections/SKILL.md +19 -12
  54. package/package/corpus/skills/cratis-screenplay-projections/references/pdl-grammar.md +37 -2
  55. package/package/corpus/skills/cratis-screenplay-projections/verification.json +11 -0
  56. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/SKILL.md +37 -40
  57. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/gap-fill-handoff.md +3 -2
  58. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/references/renderability-gate.md +1 -1
  59. package/package/corpus/skills/cratis-screenplay-render-and-gap-fill/verification.json +4 -2
  60. package/package/corpus/skills/cratis-screenplay-scenario-coverage/references/coverage-matrix.md +9 -0
  61. package/package/corpus/skills/cratis-screenplay-toolchain/SKILL.md +13 -30
  62. package/package/corpus/skills/cratis-screenplay-toolchain/references/diagnostics.md +39 -6
  63. package/package/corpus/skills/cratis-screenplay-toolchain/references/executable-subset.md +5 -2
  64. package/package/corpus/skills/cratis-screenplay-toolchain/references/language-admission.md +15 -5
  65. package/package/corpus/skills/cratis-screenplay-toolchain/references/renderable-subset.md +7 -4
  66. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.json +12 -1
  67. package/package/corpus/skills/cratis-screenplay-toolchain/references/screenplay-contract.version +1 -1
  68. package/package/corpus/skills/cratis-screenplay-toolchain/verification.json +9 -2
  69. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/SKILL.md +38 -56
  70. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/admission.md +23 -13
  71. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/date-comparisons.md +44 -0
  72. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/rendered-application.md +8 -2
  73. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/references/sandbox-and-specrunner.md +59 -8
  74. package/package/corpus/skills/cratis-stage-rendering-and-sandbox/verification.json +7 -3
  75. package/package.json +1 -1
@@ -0,0 +1,49 @@
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
+ # Command input binding and member paths
5
+
6
+ ## Explicit offsets
7
+
8
+ Requires Arc 22.110.0. Check with `dotnet list package`; older Arc has no
9
+ `[ExplicitOffset]` binding contract. Require an explicit offset at the input
10
+ boundary instead of accepting a server-local interpretation.
11
+
12
+ Use `[property: ExplicitOffset]` on a `DateTimeOffset` or `DateTime` command
13
+ property, nullable or not. It refuses date-time text without an offset or `Z`
14
+ with `DateTime command property '<member>' requires an explicit offset or Z.`
15
+ `DateTimeOffset` retains the input offset; `DateTime` becomes UTC. The attribute
16
+ is in `Cratis.Arc.Commands`.
17
+
18
+ ## Malformed bodies still authorize
19
+
20
+ Requires Arc 22.110.0 for authorization-before-binding-failure handling on
21
+ execute and `/validate`. An unauthorized caller gets 403 even if the body is
22
+ malformed; an authorized caller gets a `malformedRequest` validation result.
23
+ Its message is generic, and its member is a normalized field path such as
24
+ `from` or `items[2].when`, not parser or CLR type details.
25
+
26
+ A resource-dependent policy cannot run without a bound command; those policies
27
+ still produce a binding validation failure for an unbindable body. Requirements
28
+ that never read the resource may implement
29
+ `Cratis.Arc.Authorization.IResourceFreeRequirement` so their
30
+ policies can run; built-in role, claim, name and authenticated-user requirements
31
+ are already resource-free. Do not mark a requirement resource-free if it reads
32
+ the command.
33
+
34
+ ## Validation members are field paths
35
+
36
+ Requires Arc 22.115.0 for **all** `ValidationResult.Members` paths to be
37
+ camelCase, including data annotations and errors returned by `Provide()` or
38
+ `Handle()`. Use `name`, `address.street` and `items[0].name` in server assertions,
39
+ not `nameof(Property)` or PascalCase paths. Authors may still construct a result
40
+ with `[nameof(Property)]`; Arc normalizes it before clients receive it. Older
41
+ Arc can fail to bind such results to the matching form field.
42
+
43
+ ## Verify
44
+
45
+ Add specs for offset-less rejection, an accepted offset, malformed input under
46
+ both authorized and denied callers, and nested/indexed member paths. Assert
47
+ server `Members` using camelCase and run `dotnet test` on the owning spec project.
48
+ For form behavior, assert the rejection appears on its intended field, not only
49
+ in a command-wide error list.
@@ -0,0 +1,25 @@
1
+ <!-- Copyright (c) Cratis. All rights reserved. -->
2
+ <!-- Licensed under the MIT license. See LICENSE file in the project root for full license information. -->
3
+
4
+ # Read-model resolution for validation
5
+
6
+ Resolution does not key off `[ReadModel]`: a model becomes injectable because a
7
+ Chronicle projection or reducer, an EF Core `DbSet<T>`, or a MongoDB collection
8
+ backs it. Registration is global by type; keeping a model in the slice is a
9
+ convention, not a resolver restriction.
10
+
11
+ The default lookup uses the command's resolved event-source id. It does not
12
+ infer a key from the read-model type or an arbitrary similarly named property.
13
+ Use `[LookUpBy(nameof(Command.Property))]` for a command-property key; for a
14
+ computed key use `IDecisionReads.Get` in `Provide()` under read protection `On`.
15
+ An ordinary `IReadModels.GetInstanceById` there is refused under `On`; outside
16
+ protected work it is an advisory read, not a consistency guard.
17
+
18
+ A missing instance resolves to `null`, not a default object. A nullable parameter
19
+ receives that null; a non-nullable one produces a validation failure (400).
20
+ `ARC0006` warns on a non-nullable command-scoped read-model parameter. Reject a
21
+ missing nullable model through a validator, `Provide()` or
22
+ `Result<TEvent, ValidationResult>`; do not return a nullable event.
23
+
24
+ Read **cratis-arc-command** for the full resolution and nullability reference,
25
+ including passive projections where absence is not null.
@@ -0,0 +1,21 @@
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
+ # Choose which severities block
5
+
6
+ Model-bound commands accept `X-Allowed-Severity` (`allowedSeverity`). Under
7
+ read protection `Off` and `Measure`, a caller sending `3` (Error) removes Error
8
+ results from validators, command filters and `Provide()`, so `Handle()` runs
9
+ and a validator's state rule can be skipped unless the command declares
10
+ `[BlockOnValidationSeverity(ValidationResultSeverity.Error)]`
11
+ (`Cratis.Arc.Commands.ModelBound`). Severity is not authorization.
12
+
13
+ Requires Arc 22.108.0 for the `On` floor: a command declared `On` blocks `Error`
14
+ and `Unknown` whatever the caller sends; the caller can relax only `Warning`
15
+ and `Information`. Lowering `ReadProtection:MaximumMode` at runtime does not
16
+ remove the floor, and an explicit attribute wins. Check with
17
+ `dotnet list package`; on older Arc declare the blocking severity explicitly.
18
+
19
+ Specify both the default refusal and a caller sending a permissive severity.
20
+ Assert the command did not write events; a displayed message alone is not proof
21
+ that validation blocked execution. Run `dotnet test` on the owning spec project.
@@ -70,7 +70,13 @@ observation services and then, **only when `AutoDiscoverDbContexts` is true and
70
70
  the connection string is non-empty**, discovers and registers every public
71
71
  `BaseDbContext` subtype that is not marked `[IgnoreAutoRegistration]`.
72
72
 
73
- ⚠️ `WithEntityFrameworkCore()` with no arguments discovers **nothing**.
73
+ Requires Arc 22.109.0 for options bound from `Cratis:EntityFrameworkCore` before
74
+ `configureOptions` runs; that callback wins over configuration. Read
75
+ ../cratis-arc-hosting/references/connection-resolution.md when resolving tenant or schema-purpose
76
+ connections, including pooled contexts.
77
+
78
+ ⚠️ Without a connection string from configuration or the callback,
79
+ `WithEntityFrameworkCore()` discovers **nothing**.
74
80
  `EntityFrameworkCoreOptions.ConnectionString` defaults to the empty string, and
75
81
  both discovery gates test it. A setup that looks wired and registers no context
76
82
  is almost always this.
@@ -13,6 +13,9 @@ Choose the host and integrations before copying a bootstrap. Arc is standalone
13
13
  CQRS; Chronicle is optional and its client connects to a separate event store.
14
14
  Nothing in `AddCratis()` runs the Chronicle engine in your application.
15
15
 
16
+ Read references/connection-resolution.md when MongoDB or EF Core connections
17
+ must resolve per tenant or use separate runtime and schema identities.
18
+
16
19
  ## Verified product sources
17
20
 
18
21
  | Package | Purpose |
@@ -0,0 +1,61 @@
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 application storage connections
5
+
6
+ Requires Arc 22.109.0. Check with `dotnet list package`; older Arc has no shared
7
+ connection resolver. Tenant resolution alone does not change the database.
8
+
9
+ ## Select the resolution
10
+
11
+ `ArcOptions.ConnectionResolution`, bound under `Cratis:Arc:ConnectionResolution`,
12
+ is the shared default for MongoDB and Entity Framework Core. An integration's
13
+ own `ConnectionResolution` replaces that entire default for that integration;
14
+ it is not merged field by field.
15
+
16
+ Resolution has two slots, `Connection` then `Identity`, using the same shape.
17
+ Choose `Default` for configured values, `Template` for scope-derived values,
18
+ `Http` for a trusted platform endpoint, or `Custom` for `IConnectionResolver`.
19
+ `ConnectionRequest`, `ResolvedConnection`, `ConnectionIdentity` and
20
+ `ConnectionPurpose` live in `Cratis.Arc.Connections`. A result can supply only
21
+ the connection string, database, schema or identity it owns; fields are optional.
22
+
23
+ Results are cached in memory per request key, honor `expiresAt`, and are
24
+ invalidated on login failure. This is credential resolution, not permission to
25
+ move data. Changing the resolved destination does not migrate an existing database.
26
+ Keep resolver endpoints and templates within the approved tenant/storage boundary;
27
+ never log resolved passwords or tokens.
28
+
29
+ ## MongoDB
30
+
31
+ `MongoDBOptions.ConnectionResolution` can be bound from
32
+ `Cratis:MongoDB:ConnectionResolution`. A resolved username/password becomes a
33
+ SCRAM credential. An access token becomes a MONGODB-OIDC credential refreshed
34
+ through the resolver. Clients on the same server with different credentials
35
+ are not shared as one identity.
36
+
37
+ ## Entity Framework Core
38
+
39
+ `EntityFrameworkCoreOptions` binds `ConnectionString`, `AutoDiscoverDbContexts`
40
+ and `ConnectionResolution` from `Cratis:EntityFrameworkCore`; the options callback
41
+ runs afterward and wins. Automatic discovery still needs a nonempty configured
42
+ connection string to select the provider, even if the resolver supplies a tenant
43
+ destination later.
44
+
45
+ Arc-registered contexts resolve for the current tenant and purpose whenever a
46
+ connection opens, including pooled contexts. A SQL Server access token becomes
47
+ `SqlConnection.AccessToken`; PostgreSQL uses it as the password. Do not capture
48
+ one tenant's resolved connection into singleton options or manually reuse it
49
+ across tenants.
50
+
51
+ `ConnectionPurposeScope.Begin(ConnectionPurpose.Schema)` selects schema-purpose
52
+ resolution for migrations; runtime data access uses `Runtime`. Dispose the scope
53
+ after the schema operation. Different purposes may use different identities,
54
+ but they must resolve the intended destination consistently.
55
+
56
+ ## Verify
57
+
58
+ Run the application's database integration specs. Open connections for two
59
+ tenants through the same pool and assert each reaches only its own database;
60
+ exercise a schema-purpose open, credential expiry and login-failure invalidation.
61
+ Compilation alone cannot prove tenant isolation or resolver authorization.
@@ -56,8 +56,10 @@ Sources: `Arc.Core/Queries/QueryStringQueryRequestReader.cs`,
56
56
 
57
57
  ## Which return shapes page
58
58
 
59
- A query is a public static method on the `[ReadModel]` type, discovered by its
60
- return type.
59
+ A query is an eligible public or internal static method on the `[ReadModel]`
60
+ type, discovered by its return type. Internal visibility does not hide an
61
+ endpoint; keep helpers outside that type. Read **cratis-chronicle-read-model**'s
62
+ query reference for explicit `[Query]` discovery and older-version limits.
61
63
 
62
64
  | Return | Paged? | How |
63
65
  | --- | --- | --- |
@@ -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 |