feat!: make projections and dev runtime recovery-safe - #226
Conversation
Add explicit aggregate_snapshot projection authoring, atomic source fences in memory/SQLite/PostgreSQL, tombstone-aware late confirmation, and adapter regression proofs. BREAKING CHANGE: ProjectionRecordMetadata gains source_snapshot. Existing unversioned read-model rows require an explicit rebuild before opting into source-snapshot semantics. Apply framework migration 0005 before using SQL-backed stores.
Preserve acknowledgement progress and broker tuning when an application changes its registered commands or events. Historical catch-up remains explicit. Refs incidents/nats-durable-subscription-drift
Publish the active process cohort after readiness, retain launch identity across client-only generations, and fence replaced, preparing, and retired instances. Derive GraphQL generation metadata from verified membership and classify pre-dispatch reload rejections without accepting invalid receipts. BREAKING CHANGE: supervised development requires matching CLI and runtime versions with process-instance membership. Upgrade both and restart distributed dev. Tests: 11 lifecycle process tests, 4 native gate tests, 344 JavaScript tests; live application commands across two UI-only activations with unchanged API PID. Public lifecycle e2e proof extended but not executed in this change.
|
Important Review skippedToo many files! This PR contains 124 files, which is 24 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (124)
You can disable this status message by setting the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Update migration-five integration expectations and distinguish eventual projection completion from fresh SSR visibility. Preserve command receipts, process membership, and durable browser proof. Refs: incidents/distributed-pr226-ci
Run the live adapter cases explicitly and retain lifecycle diagnostics. Document the eventual projection barrier used by the browser reload proof. Refs: incidents/distributed-pr226-ci
(cherry picked from commit 97003f3)
(cherry picked from commit d843e82)
(cherry picked from commit d864fa9)
(cherry picked from commit 475f1ba)
(cherry picked from commit ef8b4ff)
Documents the APIs carried from #217 and checks missing and unowned surface commands.
Why
An older aggregate snapshot should not overwrite newer read-model state or resurrect a deleted row. Changing a service's event subscriptions should not reset its acknowledged work. A client-only development rebuild should not leave a healthy, retained API rejecting every command.
This PR brings those recovery guarantees into the framework, including an explicit way to rebuild existing snapshot projections without replaying domain side effects.
What application authors gain
distributed devadmits retained process instances into the active generation. Preparing, replaced and retired instances remain fenced; schema compatibility alone does not authorize a process.Service::application(name, surface)derives modules from command namespaces and validates ownership against the full Surface. Larger applications can export their actual contract: complete manifests allow 4 MiB while individual opaque JSON values remain limited to 1 MiB.Typed application assembly
Use the runtime's complete Surface here; role-selected browser clients remain authorization views of it. Missing Service commands and unowned Surface commands are rejected instead of silently producing an incomplete artifact.
Event-driven policies can continue a causal command chain explicitly before recording downstream events:
Missing incoming causation is an error; this helper does not invent command identity for external events.
Authoring example
The fence compares
(aggregate_sequence, publication_ordinal)within the owning aggregate stream. A stale event confirms the current row revision without inventing a row update. A conflicting equal version or another aggregate attempting to take over the same key is rejected.This mode is for complete replacement snapshots with stable keys—not counters, partial patches, joins, or arbitrary delta reordering. Browser optimism still uses the shared mutation program and committed record revisions for confirmation.
Existing read models
The rebuild API is bus-neutral; the NATS helper reads a stable, gap-free retained stream without consuming or acknowledging it. The caller must still establish historical coverage: a stream starting at sequence one does not prove that all aggregate history was published there.
Rebuilds are bounded offline maintenance for one active local unit-partition binding: up to 10,000 records and 100,000 occurrences / 64 MiB of canonical history. They do not migrate schemas or turn independent projections into one transaction.
Breaking changes and upgrade
0005_projection_source_snapshotsbefore using SQL-backed source fences.ProjectionRecordMetadatagainssource_snapshot.distributed devto establish matching process-instance membership.The original four functional commits are preserved separately. This PR also consolidates all five commits from #217, cherry-picked with source provenance, including its resolved Content-Type review fix. A formatting-only commit reproduces
cargo fmt --allwith the repository configuration. Follow-up test/CI commits cover migration five and the full eventual-command lifecycle.Validation
graphql,sqlite,postgres,nats): 988 passed, 0 failed, 1 explicitly ignored live-NATS test. Environment-gated live cases in that first run are not credited as live evidence.cargo fmt --all --checkandgit diff origin/main --check: pass.graphql,nats) 913 passed, 0 failed, 1 ignored; added missing/unowned Surface rejection assertions also pass. The live NATS custom-content-type round-trip passes.No application-specific project details or fixtures are required to use these APIs.