feat(eventcore-fs): git-mergeable file-based event store backend #390

Merged
jwilger merged 9 commits from feat/eventcore-fs-backend into main 2026-06-12 23:00:23 -07:00
Owner

Summary

Adds eventcore-fs, a file-based event store backend that persists each
append_events transaction as one immutable JSONL file under events/, named
by a transaction UUID7. Because every transaction is a uniquely named file that
is never edited, a git merge of two clones' events/ directories is a pure
additive union with zero textual conflicts — the foundation for offline
collaboration on event-sourced developer tools committed to git.

The work was designed in full before any code (the on-disk format is immutable,
so it had to reserve the merge-mode header fields from the first commit), then
implemented in two layers via outside-in TDD.

Phase 0 — design (ADRs 0038–0046 + blueprint)

  • ADR-0038 file format & atomicity, ADR-0039 read-time linearization,
    ADR-0040 locking & coordination (Layer 1)
  • ADR-0041 causality DAG, ADR-0042 reconciliation API, ADR-0043
    projection-after-merge, ADR-0044 replica identity, ADR-0045 merge
    mode off-trait, ADR-0046 git integration (Layer 2)
  • blueprints/fs-merge-mode.md (incorporating the discovery brief + BDD
    scenarios); store-backends.md updated with the new backend

Layer 1 — single-writer backend (complete)

  • One immutable JSONL file per transaction; atomic tmp→fsync→rename→dir-fsync
    gives all-or-nothing multi-stream writes
  • StreamVersion and global order are computed at read time by linearizing
    a transaction DAG (ADR-0039); single-writer mode is the degenerate
    linear-chain case, so the shared 19-test contract suite passes unchanged
  • In-process append mutex + cross-process .lock + per-subscription fs4
    advisory locks (ADR-0040)
  • FileEventStore, FileCheckpointStore, FileProjectorCoordinator

Layer 2 — merge mode (core complete)

  • Deterministic convergence: linearize breaks ties between concurrent
    transactions by (created_at, replica_id, transaction_id), so any two clones
    holding the same file set compute byte-identical canonical order
  • Fork detection: detect_forks / status report streams with concurrent
    same-base transactions (off-trait API, ADR-0045)
  • Domain-owned reconciliation: reconcile<E, R>(resolver) hands each fork's
    typed divergent branches to the application, which returns resolution events
    (or Unresolvable); the library records an N-parent merge transaction that
    collapses the fork and replicates through git
  • Recursive/self-similar: merge-of-merges is itself a fork and reconciles to
    a single resolved head (termination proven by test)
  • Git metadata: open() writes .gitignore (keeping the replica id, locks,
    index, and tmp out of git — the primary copy-trap defense) and a defensive
    .gitattributes merge=union
  • Projection safety net: topology_generation() lets projections detect
    structural merges and rebuild (ADR-0043)

Quality gates

  • 37 tests in eventcore-fs (19 contract + unit + merge-mode integration);
    full workspace green (postgres excluded — needs a live DB)
  • cargo clippy --all-targets --all-features -D warnings clean
  • cargo fmt clean
  • Zero surviving mutants (cargo mutants)

Scoped follow-ups (each has an ADR; not blocking this PR)

These are the more advanced refinements the ADRs anticipate; the core feature is
complete and shippable without them:

  • ADR-0043 — the per-replica local-ingestion-order cursor so live
    cursor-based projections never rewind after a merge (the topology-generation
    signal is implemented; the cursor is the larger remaining surface)
  • ADR-0044 — working-copy fingerprint binding for the replica id (defense
    in depth against cp -r, beyond the .gitignore already in place) and
    reconcile-time ReplicaIdentityConflict detection
  • ADR-0046 — read-time fsck (content-hash validation) and
    dangling-transaction reporting in status() for partial/aborted git merges

🤖 Generated with Claude Code

## Summary Adds **`eventcore-fs`**, a file-based event store backend that persists each `append_events` transaction as one immutable JSONL file under `events/`, named by a transaction UUID7. Because every transaction is a uniquely named file that is never edited, a `git merge` of two clones' `events/` directories is a pure additive union with **zero textual conflicts** — the foundation for offline collaboration on event-sourced developer tools committed to git. The work was designed in full before any code (the on-disk format is immutable, so it had to reserve the merge-mode header fields from the first commit), then implemented in two layers via outside-in TDD. ## Phase 0 — design (ADRs 0038–0046 + blueprint) - **ADR-0038** file format & atomicity, **ADR-0039** read-time linearization, **ADR-0040** locking & coordination (Layer 1) - **ADR-0041** causality DAG, **ADR-0042** reconciliation API, **ADR-0043** projection-after-merge, **ADR-0044** replica identity, **ADR-0045** merge mode off-trait, **ADR-0046** git integration (Layer 2) - `blueprints/fs-merge-mode.md` (incorporating the discovery brief + BDD scenarios); `store-backends.md` updated with the new backend ## Layer 1 — single-writer backend (complete) - One immutable JSONL file per transaction; atomic tmp→fsync→rename→dir-fsync gives all-or-nothing multi-stream writes - `StreamVersion` and global order are **computed at read time** by linearizing a transaction DAG (ADR-0039); single-writer mode is the degenerate linear-chain case, so the **shared 19-test contract suite passes unchanged** - In-process append mutex + cross-process `.lock` + per-subscription `fs4` advisory locks (ADR-0040) - `FileEventStore`, `FileCheckpointStore`, `FileProjectorCoordinator` ## Layer 2 — merge mode (core complete) - **Deterministic convergence**: `linearize` breaks ties between concurrent transactions by `(created_at, replica_id, transaction_id)`, so any two clones holding the same file set compute byte-identical canonical order - **Fork detection**: `detect_forks` / `status` report streams with concurrent same-base transactions (off-trait API, ADR-0045) - **Domain-owned reconciliation**: `reconcile<E, R>(resolver)` hands each fork's typed divergent branches to the application, which returns resolution events (or `Unresolvable`); the library records an N-parent merge transaction that collapses the fork and replicates through git - **Recursive/self-similar**: merge-of-merges is itself a fork and reconciles to a single resolved head (termination proven by test) - **Git metadata**: `open()` writes `.gitignore` (keeping the replica id, locks, index, and tmp out of git — the primary copy-trap defense) and a defensive `.gitattributes merge=union` - **Projection safety net**: `topology_generation()` lets projections detect structural merges and rebuild (ADR-0043) ## Quality gates - **37 tests** in `eventcore-fs` (19 contract + unit + merge-mode integration); full workspace green (postgres excluded — needs a live DB) - `cargo clippy --all-targets --all-features -D warnings` clean - `cargo fmt` clean - **Zero surviving mutants** (`cargo mutants`) ## Scoped follow-ups (each has an ADR; not blocking this PR) These are the more advanced refinements the ADRs anticipate; the core feature is complete and shippable without them: - **ADR-0043** — the per-replica *local-ingestion-order cursor* so live cursor-based projections never rewind after a merge (the topology-generation signal is implemented; the cursor is the larger remaining surface) - **ADR-0044** — working-copy *fingerprint binding* for the replica id (defense in depth against `cp -r`, beyond the `.gitignore` already in place) and reconcile-time `ReplicaIdentityConflict` detection - **ADR-0046** — read-time *fsck* (content-hash validation) and *dangling-transaction* reporting in `status()` for partial/aborted git merges 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Phase 0 design artifacts for a new file-based event store backend
(eventcore-fs) and its git-merge reconciliation mode. Per the approved
plan, both layers are designed in full before any code, because the
on-disk format is immutable and must reserve the merge-mode header
fields from the first commit.

Layer 1 (single-writer file backend):
- ADR-0038: one immutable JSONL file per transaction, UUID7 filename,
  tmp+fsync+rename atomicity, reserved merge header fields
- ADR-0039: read-time linearization; StreamVersion is a projection over
  a transaction DAG, not a stored value; single-writer mode is the
  degenerate linear-chain case that passes the contract suite unchanged
- ADR-0040: in-process append mutex, cross-process store lock, and
  fs4 OS advisory locks for projector coordination

Layer 2 (merge mode):
- ADR-0041: causality via a transaction DAG + per-stream base versions
- ADR-0042: domain-owned ForkResolver returning a command; library
  records an N-parent merge transaction
- ADR-0043: projection-after-merge policy
- ADR-0044: machine-local replica identity with copy-trap defenses
- ADR-0045: merge mode lives outside the EventStore trait
- ADR-0046: git integration contract

Also adds blueprints/fs-merge-mode.md (incorporating the Layer 2
discovery brief and BDD scenarios) and registers the backend in
blueprints/store-backends.md.
Implements Layer 1 of the eventcore-fs backend: a single-writer store
that persists each append_events transaction as one immutable JSONL file
under events/, named by a transaction UUID7. Passes the shared 19-test
backend contract suite unchanged.

- One immutable JSONL file per transaction; atomic tmp+fsync+rename write
  gives all-or-nothing multi-stream semantics (ADR-0038)
- StreamVersion and global order are computed at read time by linearizing
  a transaction DAG built from recorded parent pointers (ADR-0039);
  single-writer mode is the degenerate linear-chain case
- Reserved merge-mode header fields (replica_id, parent_transaction_ids,
  stream_bases, created_at) are written from the first commit since the
  format is immutable; parent pointers are read by the linearizer today
- In-process append mutex + cross-process .lock + per-subscription fs4
  advisory locks for projector coordination (ADR-0040)
- FileEventStore, FileCheckpointStore, FileProjectorCoordinator

Contract suite green; unit tests cover on-disk format, the linearizer,
index rebuild on reopen, the store lock, and crash-safe scans. Zero
surviving mutants.
Implements the core of Layer 2 (merge mode): the deterministic
linearization and fork-detection that let clones reconcile histories
combined via git merge.

- linearize() now breaks ties between concurrent transactions by
  (created_at, replica_id, transaction_id) — all immutable recorded
  values — so every clone holding the same file set computes the
  identical canonical order (ADR-0039 convergence). Single-writer
  chains have unique depths, so the tiebreak is inert and the contract
  suite is unaffected.
- detect_forks() / status() report streams where two or more concurrent
  transactions extended the same base version (ADR-0041), exposed as
  file-store-specific API outside the EventStore trait (ADR-0045).
- New public types: TransactionId (nutype), Fork, StoreStatus.

Integration tests prove two clones that union each other's transaction
files converge to byte-identical canonical order regardless of merge
direction, and that forks are detected while linear histories stay
clean. Zero surviving mutants.
Adds the reconcile API (ADR-0042): the application supplies a resolver
that inspects each fork's divergent branches (typed events) and returns
either resolution events or Unresolvable. Resolution events are recorded
as an N-parent merge transaction listing the fork heads as parents, so
detect_forks thereafter reports the fork as resolved, and the merge file
replicates through git like any other transaction.

- reconcile<E, R>(resolver) drives every unresolved fork
- ForkContext / BranchView expose the typed divergent events
- ResolutionOutcome::{Resolve, Unresolvable}; ReconcileReport summary
- detect_forks now filters resolved forks (a transaction descending from
  all heads), via re-introduced ancestor reachability
- the per-event version arithmetic is factored into one build_envelopes
  helper shared by the append and merge paths

Integration tests prove a fork collapses into a merge that both clones
converge on, that the resolver sees both branches' events, and that a
declined fork stays unresolved. Zero surviving mutants.
- open() writes .gitignore and .gitattributes (idempotently, preserving
  any existing files). The .gitignore keeps the replica id, locks, index,
  checkpoints, tmp, and .lock out of git, leaving events/ as the only
  committed source of truth — the primary defense against the copy trap
  (ADR-0044/0046). .gitattributes sets events/** merge=union defensively.
- A regression test proves merge-of-merges: when two clones reconcile the
  same fork independently, the two merge nodes are themselves a fork, and
  reconciling recursively terminates at a single resolved head on which
  both clones converge (ADR-0042 self-similarity/termination).

Zero surviving mutants.
feat(eventcore-fs): topology-generation signal for projections
All checks were successful
CI / Detect Changes (pull_request) Successful in 3s
CI / Request auto_review semantic review (pull_request) Successful in 2s
CI / Format (pull_request) Successful in 15s
CI / Clippy (pull_request) Successful in 1m54s
CI / Security Audit (pull_request) Successful in 25s
CI / Test (pull_request) Successful in 2m49s
CI / Mutation (pull_request) Has been skipped
CI / CI Gate (pull_request) Successful in 1s
auto_review auto_review: no findings
9719f46c4e
Adds FileEventStore::topology_generation(), which counts the structural
merges (N-parent merge transactions) in the history. It increases when a
git merge or a reconcile records a merge transaction — i.e. whenever
events may have been inserted behind a projection's cursor. Projections
that cannot guarantee idempotent resolution events can compare it between
polls and rebuild when it changes (ADR-0043 safety net).

Zero surviving mutants.
auto-review requested changes 2026-06-12 21:18:09 -07:00
Dismissed
auto-review left a comment

This PR introduces eventcore-fs, a file-based event store backend designed for offline collaboration via git merges. The implementation appears robust, with a focus on deterministic linearization and domain-owned reconciliation. The changes seem safe to merge, but adding CI checks for testing and linting would enhance reliability.

Walkthrough

  • New Backend Addition: The eventcore-fs backend is added, allowing event histories to be stored as immutable JSONL files. This enables offline collaboration by leveraging git's merge capabilities.
  • Deterministic Linearization: The backend computes stream versions and global order at read time, ensuring deterministic convergence across replicas.
  • Merge Mode: Introduces a mechanism for detecting and reconciling forks in event histories, allowing domain-specific resolution strategies.
  • Locking and Coordination: Implements in-process and cross-process locking to ensure data integrity and correct projector coordination.
  • CI Recommendations: Suggests adding CI checks for running tests and linting to catch issues early.

LLM usage and cost

Pre-merge checks

  • PR metadata quality: failed
  • Rationale: PR title exceeds the 72 character limit.
  • Offending text: feat(eventcore-fs): file-based event store backend with git-merge reconciliation
This PR introduces `eventcore-fs`, a file-based event store backend designed for offline collaboration via git merges. The implementation appears robust, with a focus on deterministic linearization and domain-owned reconciliation. The changes seem safe to merge, but adding CI checks for testing and linting would enhance reliability. ## Walkthrough - **New Backend Addition**: The `eventcore-fs` backend is added, allowing event histories to be stored as immutable JSONL files. This enables offline collaboration by leveraging git's merge capabilities. - **Deterministic Linearization**: The backend computes stream versions and global order at read time, ensuring deterministic convergence across replicas. - **Merge Mode**: Introduces a mechanism for detecting and reconciling forks in event histories, allowing domain-specific resolution strategies. - **Locking and Coordination**: Implements in-process and cross-process locking to ensure data integrity and correct projector coordination. - **CI Recommendations**: Suggests adding CI checks for running tests and linting to catch issues early. ## LLM usage and cost - Reasoning (gpt-4o) in=23531 out=354 cost=$0.122965 - Cheap (gpt-4o-mini) in=9926 out=35 cost=$0.001510 Estimated total USD: $0.124475 via https://api.openai.com and https://api.openai.com ## Pre-merge checks - PR metadata quality: failed - Rationale: PR title exceeds the 72 character limit. - Offending text: feat(eventcore-fs): file-based event store backend with git-merge reconciliation
jwilger changed title from feat(eventcore-fs): file-based event store backend with git-merge reconciliation to feat(eventcore-fs): git-mergeable file-based event store backend 2026-06-12 21:36:34 -07:00
Author
Owner

Addressed the pre-merge metadata check: shortened the PR title from 80 to 64 characters, now under the 72-char conventional-commit header limit.

Re the CI suggestion in the review: the repository CI already runs Test, Clippy, Mutation, Format, and Security Audit jobs on every PR (see the checks on this PR), so no additional CI for tests/linting is needed.

@auto-review re-review

Addressed the pre-merge metadata check: shortened the PR title from 80 to 64 characters, now under the 72-char conventional-commit header limit. Re the CI suggestion in the review: the repository CI already runs Test, Clippy, Mutation, Format, and Security Audit jobs on every PR (see the checks on this PR), so no additional CI for tests/linting is needed. @auto-review re-review
Owner

Queued a forced review at 9719f46c4e. This intentionally bypasses CI gating; watch the commit-status badge for progress.

Queued a forced review at 9719f46c4ea364d0c6bc882ffe0c7cc9c1200e4b. This intentionally bypasses CI gating; watch the commit-status badge for progress.
auto-review approved these changes 2026-06-12 21:36:56 -07:00
Dismissed
auto-review left a comment

This PR introduces a new file-based event store backend, eventcore-fs, which allows for git-mergeable offline collaboration by storing each transaction as an immutable JSONL file. The implementation appears robust, with comprehensive testing and documentation. It is safe to merge.

Walkthrough

  • Cargo.lock and Cargo.toml: Added eventcore-fs as a new package and included necessary dependencies like fs4 for file locking.
  • Blueprints and ADRs: Extensive documentation added, detailing the design and implementation of the file-based backend, including merge mode and locking mechanisms.
  • eventcore-fs: Implemented the core functionality for the file-based event store, ensuring atomic writes and deterministic linearization of events.
  • Tests: A contract suite test is included to ensure the new backend adheres to the existing event store contract, verifying its correctness and compatibility.

LLM usage and cost

This PR introduces a new file-based event store backend, `eventcore-fs`, which allows for git-mergeable offline collaboration by storing each transaction as an immutable JSONL file. The implementation appears robust, with comprehensive testing and documentation. It is safe to merge. ## Walkthrough - **Cargo.lock and Cargo.toml**: Added `eventcore-fs` as a new package and included necessary dependencies like `fs4` for file locking. - **Blueprints and ADRs**: Extensive documentation added, detailing the design and implementation of the file-based backend, including merge mode and locking mechanisms. - **eventcore-fs**: Implemented the core functionality for the file-based event store, ensuring atomic writes and deterministic linearization of events. - **Tests**: A contract suite test is included to ensure the new backend adheres to the existing event store contract, verifying its correctness and compatibility. ## LLM usage and cost - Reasoning (gpt-4o) in=23699 out=377 cost=$0.124150 - Cheap (gpt-4o-mini) in=1278 out=45 cost=$0.000219 Estimated total USD: $0.124369 via https://api.openai.com and https://api.openai.com
docs(eventcore-fs): mark ADRs 0038-0046 as Accepted
All checks were successful
CI / Detect Changes (pull_request) Successful in 3s
CI / Request auto_review semantic review (pull_request) Successful in 2s
auto_review auto_review: no findings
CI / Format (pull_request) Successful in 15s
CI / CI Gate (pull_request) Successful in 2s
CI / Clippy (pull_request) Successful in 1m52s
CI / Security Audit (pull_request) Successful in 25s
CI / Test (pull_request) Successful in 2m50s
CI / Mutation (pull_request) Has been skipped
7940ae18f9
Merging this PR ratifies the file-backend and merge-mode decisions, so
the ADRs move from Proposed to Accepted. Decisions whose implementation
is partially deferred to follow-up issues (#391 ADR-0043, #392 ADR-0044,
#393 ADR-0046) are still accepted as architectural direction; the issues
track remaining implementation, not the decision.
jwilger dismissed auto-review's review 2026-06-12 21:43:17 -07:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

auto-review approved these changes 2026-06-12 21:43:25 -07:00
Dismissed
auto-review left a comment

The PR updates the status of several ADR documents from 'Proposed' to 'Accepted', indicating that the design decisions have been finalized and approved. This change is straightforward and does not introduce any code changes, making it safe to merge.

LLM usage and cost

The PR updates the status of several ADR documents from 'Proposed' to 'Accepted', indicating that the design decisions have been finalized and approved. This change is straightforward and does not introduce any code changes, making it safe to merge. ## LLM usage and cost - Reasoning (gpt-4o) in=3072 out=62 cost=$0.016290 - Cheap (gpt-4o-mini) in=1278 out=45 cost=$0.000219 Estimated total USD: $0.016509 via https://api.openai.com and https://api.openai.com
@ -0,0 +10,4 @@
workspace = true
[dependencies]
eventcore-types = { version = "0.8.0", path = "../eventcore-types" }
Author
Owner

Won't this version constraint be problematic when the version numbers are bumped with the next release? How can we make it reference "whatever version is published along with this" (i.e. the workspace version)?

Won't this version constraint be problematic when the version numbers are bumped with the next release? How can we make it reference "whatever version is published along with this" (i.e. the workspace version)?
@ -0,0 +20,4 @@
uuid = { version = "1.23.1", features = ["v7", "serde"] }
fs4 = { version = "1.1.0", default-features = false, features = ["sync"] }
nutype = { version = "0.7.0", features = ["serde"] }
Author
Owner

Let's also ensure that the versions for all of the other dependencies are up to date with the latest versions and also match the versions used for other crates in eventcore that use the same dependencies. Can that be enforced such that these version numbers are always shared between the crates? Does that even matter in Rust? Or could each of our crates depend on a different version of X and the whole thing would still work after all transitive dependencies are resolved?

Let's also ensure that the versions for all of the other dependencies are up to date with the latest versions and also match the versions used for other crates in eventcore that use the same dependencies. Can that be enforced such that these version numbers are always shared between the crates? Does that even matter in Rust? Or could each of our crates depend on a different version of X and the whole thing would still work after all transitive dependencies are resolved?
@ -0,0 +1602,4 @@
"existing git metadata is preserved, not overwritten"
);
}
}
Author
Owner

This file is huge. Wouldn't it be better if we could break this down into modules? Is there a sensible way to do so that isn't just random? I think smaller files are easier to deal with in agentic development harnesses, aren't they?

This file is huge. Wouldn't it be better if we could break this down into modules? Is there a sensible way to do so that isn't just random? I think smaller files are easier to deal with in agentic development harnesses, aren't they?
refactor(eventcore-fs): split lib.rs into focused modules
All checks were successful
CI / Detect Changes (pull_request) Successful in 3s
CI / Request auto_review semantic review (pull_request) Successful in 2s
auto_review auto_review: no findings
CI / Format (pull_request) Successful in 15s
CI / Clippy (pull_request) Successful in 1m54s
CI / Security Audit (pull_request) Successful in 24s
CI / Test (pull_request) Successful in 2m51s
CI / Mutation (pull_request) Has been skipped
CI / CI Gate (pull_request) Successful in 2s
8494efe276
Addresses PR review feedback. The single ~1600-line lib.rs is split by
responsibility into modules, so each file is small enough to work with
comfortably:

- error    — the crate's error types
- config   — store configuration and on-disk directory layout
- format   — the immutable JSONL transaction-file format (ADR-0038)
- index    — the in-memory read model and linearization engine (ADR-0039)
- merge    — fork detection and reconciliation types (ADR-0041/0042)
- coordination — locking, checkpoints, projector coordination (ADR-0040)
- lib      — the FileEventStore facade, trait impls, and re-exports

Pure refactor: public API unchanged (all types re-exported), all 37
tests pass, clippy/fmt clean, zero surviving mutants. Also aligns the
chrono version requirement (0.4.42) with the eventcore crate.
jwilger dismissed auto-review's review 2026-06-12 22:11:20 -07:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

auto-review approved these changes 2026-06-12 22:11:32 -07:00
Dismissed
auto-review left a comment

This PR introduces a new file-based event store backend, eventcore-fs, which allows for git-mergeable event storage. The changes appear well-structured and modular, with clear separation of concerns across different files. The update to the chrono dependency version should be verified for compatibility.

Walkthrough

Δ since 7940ae1:

  • Dependency Update:

    • Cargo.toml: Updated chrono dependency to version 0.4.42.
  • New Modules:

    • config.rs: Handles store configuration and directory layout.
    • coordination.rs: Manages locking and coordination for the event store.
    • error.rs: Defines error types for the file backend.
    • format.rs: Specifies the on-disk transaction file format.
    • index.rs: Implements the in-memory linearized read model.
    • merge.rs: Provides fork detection and reconciliation API types.
  • Refactoring:

    • lib.rs: Refactored to use new modules, improving code organization and readability.

LLM usage and cost

This PR introduces a new file-based event store backend, `eventcore-fs`, which allows for git-mergeable event storage. The changes appear well-structured and modular, with clear separation of concerns across different files. The update to the `chrono` dependency version should be verified for compatibility. ## Walkthrough ### Δ since 7940ae1: - **Dependency Update**: - `Cargo.toml`: Updated `chrono` dependency to version `0.4.42`. - **New Modules**: - `config.rs`: Handles store configuration and directory layout. - `coordination.rs`: Manages locking and coordination for the event store. - `error.rs`: Defines error types for the file backend. - `format.rs`: Specifies the on-disk transaction file format. - `index.rs`: Implements the in-memory linearized read model. - `merge.rs`: Provides fork detection and reconciliation API types. - **Refactoring**: - `lib.rs`: Refactored to use new modules, improving code organization and readability. ## LLM usage and cost - Reasoning (gpt-4o) in=19599 out=308 cost=$0.102615 - Cheap (gpt-4o-mini) in=1278 out=45 cost=$0.000219 Estimated total USD: $0.102834 via https://api.openai.com and https://api.openai.com
Author
Owner

Thanks for the review — addressed all three:

1. eventcore-types = { version = "0.8.0", path = ... } drifting on release bumps.
This matches every sibling backend crate (eventcore-memory, -sqlite, -postgres all hardcode the same version = "0.8.0"). The version is required for a path dependency that is also published to crates.io, and release-plz bumps all of them in lockstep on each release per ADR-025 (every crate uses version.workspace = true, so they always move together). So it does not drift in practice — itʼs the same mechanism the rest of the workspace already relies on.

2. Dependency versions: up to date, matching siblings, and enforcement.
Aligned chrono to 0.4.42 (matching the eventcore crate); the rest already match the sibling crates. On enforcement: in Rust this matters less than it looks — Cargoʼs resolver unifies SemVer-compatible requirements via the lockfile, so e.g. serde "1.0" and serde "1.0.228" resolve to a single compiled copy. Divergent major versions would coexist (multiple copies compiled — wasteful but still correct). The idiomatic way to enforce shared versions is [workspace.dependencies] + dep.workspace = true. This workspace does not use that today (there is no [workspace.dependencies] section), so adopting it is a workspace-wide change touching every crate — I would recommend doing that as its own PR rather than bundling it here. I am also adding a generation guardrail so new crates match sibling versions from the start (separate guardrails PR, below).

3. lib.rs is huge → modularize.
Done in 8494efe. Split by responsibility into error, config, format, index, merge, and coordination modules; lib.rs dropped from ~1605 to 754 lines (~400 non-test — the FileEventStore facade, trait impls, and re-exports). Pure refactor: public API unchanged, all 37 tests pass, clippy/fmt clean, zero surviving mutants.

Per our review-feedback protocol, the giant-file and dependency-consistency lessons are getting generation guardrails in a separate chore/guardrail-update-* PR so future agents avoid these in the first place (cheaper than catching them in review).

Thanks for the review — addressed all three: **1. `eventcore-types = { version = "0.8.0", path = ... }` drifting on release bumps.** This matches every sibling backend crate (`eventcore-memory`, `-sqlite`, `-postgres` all hardcode the same `version = "0.8.0"`). The version is *required* for a path dependency that is also published to crates.io, and release-plz bumps all of them in lockstep on each release per ADR-025 (every crate uses `version.workspace = true`, so they always move together). So it does not drift in practice — itʼs the same mechanism the rest of the workspace already relies on. **2. Dependency versions: up to date, matching siblings, and enforcement.** Aligned `chrono` to `0.4.42` (matching the `eventcore` crate); the rest already match the sibling crates. On *enforcement*: in Rust this matters less than it looks — Cargoʼs resolver unifies SemVer-compatible requirements via the lockfile, so e.g. `serde "1.0"` and `serde "1.0.228"` resolve to a single compiled copy. Divergent *major* versions would coexist (multiple copies compiled — wasteful but still correct). The idiomatic way to *enforce* shared versions is `[workspace.dependencies]` + `dep.workspace = true`. This workspace does not use that today (there is no `[workspace.dependencies]` section), so adopting it is a workspace-wide change touching every crate — I would recommend doing that as its own PR rather than bundling it here. I am also adding a generation guardrail so new crates match sibling versions from the start (separate guardrails PR, below). **3. `lib.rs` is huge → modularize.** Done in 8494efe. Split by responsibility into `error`, `config`, `format`, `index`, `merge`, and `coordination` modules; `lib.rs` dropped from ~1605 to 754 lines (~400 non-test — the `FileEventStore` facade, trait impls, and re-exports). Pure refactor: public API unchanged, all 37 tests pass, clippy/fmt clean, zero surviving mutants. Per our review-feedback protocol, the giant-file and dependency-consistency lessons are getting **generation guardrails** in a separate `chore/guardrail-update-*` PR so future agents avoid these in the first place (cheaper than catching them in review).
Merge branch 'main' into feat/eventcore-fs-backend
All checks were successful
CI / Detect Changes (pull_request) Successful in 3s
CI / Format (pull_request) Successful in 21s
CI / Request auto_review semantic review (pull_request) Successful in 3s
auto_review auto_review: no findings
CI / Test (pull_request) Successful in 3m25s
CI / Security Audit (pull_request) Successful in 27s
CI / Mutation (pull_request) Has been skipped
CI / Clippy (pull_request) Successful in 1m13s
CI / CI Gate (pull_request) Successful in 1s
4a37ba3447
auto-review left a comment

This PR introduces new guidelines for maintaining version consistency across crates and organizing modules by responsibility. These changes aim to improve dependency management and code modularity.

LLM usage and cost

This PR introduces new guidelines for maintaining version consistency across crates and organizing modules by responsibility. These changes aim to improve dependency management and code modularity. ## LLM usage and cost - Reasoning (gpt-4o) in=3740 out=177 cost=$0.021355 - Cheap (gpt-4o-mini) in=1278 out=45 cost=$0.000219 Estimated total USD: $0.021574 via https://api.openai.com and https://api.openai.com
jwilger scheduled this pull request to auto merge when all checks succeed 2026-06-12 22:57:50 -07:00
jwilger deleted branch feat/eventcore-fs-backend 2026-06-12 23:00:23 -07:00
jwilger referenced this pull request from a commit 2026-06-13 05:24:48 -07:00
Sign in to join this conversation.
No description provided.