feat(eventcore-fs): read-time fsck + dangling-transaction handling #402

Merged
jwilger merged 2 commits from feat/393-fsck-dangling into main 2026-06-13 06:53:56 -07:00
Owner

Implements issue #393 / ADR-0046: the remaining git-robustness layers for the file store.

Problem

merge=union keeps a git merge of events/ conflict-free for the additive case, but it can mask an illegal in-place edit of a JSONL file. And a partial or aborted git merge can leave a transaction whose parents did not arrive.

Change

  • Read-time fsck. Transaction headers gain a v2 SHA-256 content_hash anchor over the event payload. On scan, a file whose payload no longer matches its anchor is rejected (excluded from the linearized history) and surfaced via status() as an IntegrityFailure — catching the illegal edit a union merge would otherwise mask. The field is serde-defaulted, so legacy v1 files still load (they skip the check). FORMAT_VERSION is bumped to 2.
  • Dangling-transaction handling. A transaction whose parent_transaction_ids reference files not present (a partial/aborted git merge) is reported as a DanglingTransaction via status(). Linearization already tolerated missing parents; this makes the incomplete state observable — never a crash, never a silent drop.
  • StoreStatus::is_clean() now accounts for forks, dangling transactions, and integrity failures.

Acceptance (ADR-0046)

  • A hand-edited transaction file is rejected at read and reported with a clear integrity error; its events are excluded and reads do not panic (a_hand_edited_transaction_file_is_rejected_by_fsck).
  • A store with a transaction referencing an absent parent opens, status() reports the dangling transaction, and reads do not panic (a_transaction_referencing_an_absent_parent_is_reported_as_dangling).

Notes

  • Adds sha2 (0.10, matching the major already in the workspace lockfile) to eventcore-fs.
  • New git_robustness_test.rs (2 tests). Full crate suite 45 passed; workspace clippy/fmt clean (stable 1.96).
  • Branch includes the merge of main (PRs #391 and #392).

Closes #393

Implements issue #393 / ADR-0046: the remaining git-robustness layers for the file store. ## Problem `merge=union` keeps a `git merge` of `events/` conflict-free for the additive case, but it can *mask* an illegal in-place edit of a JSONL file. And a partial or aborted `git merge` can leave a transaction whose parents did not arrive. ## Change - **Read-time fsck.** Transaction headers gain a v2 SHA-256 `content_hash` anchor over the event payload. On scan, a file whose payload no longer matches its anchor is rejected (excluded from the linearized history) and surfaced via `status()` as an `IntegrityFailure` — catching the illegal edit a union merge would otherwise mask. The field is serde-defaulted, so legacy v1 files still load (they skip the check). `FORMAT_VERSION` is bumped to 2. - **Dangling-transaction handling.** A transaction whose `parent_transaction_ids` reference files not present (a partial/aborted git merge) is reported as a `DanglingTransaction` via `status()`. Linearization already tolerated missing parents; this makes the incomplete state observable — never a crash, never a silent drop. - `StoreStatus::is_clean()` now accounts for forks, dangling transactions, and integrity failures. ## Acceptance (ADR-0046) - A hand-edited transaction file is rejected at read and reported with a clear integrity error; its events are excluded and reads do not panic (`a_hand_edited_transaction_file_is_rejected_by_fsck`). - A store with a transaction referencing an absent parent opens, `status()` reports the dangling transaction, and reads do not panic (`a_transaction_referencing_an_absent_parent_is_reported_as_dangling`). ## Notes - Adds `sha2` (0.10, matching the major already in the workspace lockfile) to `eventcore-fs`. - New `git_robustness_test.rs` (2 tests). Full crate suite 45 passed; workspace clippy/fmt clean (stable 1.96). - Branch includes the merge of `main` (PRs #391 and #392). Closes #393
Add the remaining git-robustness layers from ADR-0046.

- Read-time fsck: transaction headers gain a v2 SHA-256 content_hash anchor
  over the event payload. On scan, a file whose payload no longer matches its
  anchor is rejected (excluded from the linearized history) and surfaced via
  status() as an IntegrityFailure — catching an illegal edit that merge=union
  would otherwise mask. The field is serde-defaulted, so legacy v1 files still
  load (they skip the check). FORMAT_VERSION bumped to 2.
- Dangling-transaction handling: a transaction whose parent_transaction_ids
  reference files not present (a partial/aborted git merge) is reported as a
  DanglingTransaction via status(). Linearization already tolerated missing
  parents; this makes the incomplete state observable, never a crash or a
  silent drop.
- StoreStatus::is_clean() now accounts for forks, dangling, and integrity
  failures.

Closes #393
Merge remote-tracking branch 'origin/main' into feat/393-fsck-dangling
All checks were successful
CI / Detect Changes (pull_request) Successful in 4s
CI / Request auto_review semantic review (pull_request) Successful in 2s
CI / Format (pull_request) Successful in 17s
auto_review auto_review: no findings
CI / Clippy (pull_request) Successful in 1m44s
CI / Security Audit (pull_request) Successful in 23s
CI / Test (pull_request) Successful in 2m37s
CI / Mutation (pull_request) Has been skipped
CI / CI Gate (pull_request) Successful in 2s
a2fea7d2d9
# Conflicts:
#	eventcore-fs/src/merge.rs
auto-review left a comment

The PR introduces a read-time fsck and dangling-transaction handling to improve the robustness of the file store against illegal edits and partial merges. The changes appear well-implemented and safe to merge, with comprehensive tests validating the new functionality.

Walkthrough

  • eventcore-fs/src/format.rs:

    • Introduces content_hash for transaction integrity verification.
    • Implements load_transaction to perform read-time integrity checks.
    • Refactors transaction parsing to support integrity checks.
  • eventcore-fs/src/index.rs:

    • Updates index scanning to handle integrity failures and dangling transactions.
  • eventcore-fs/src/lib.rs:

    • Enhances status() to report integrity failures and dangling transactions.
  • eventcore-fs/src/merge.rs:

    • Adds structures for DanglingTransaction and IntegrityFailure.
    • Updates StoreStatus to include new integrity checks.
  • eventcore-fs/tests/git_robustness_test.rs:

    • Adds tests for integrity failure and dangling transaction scenarios.

LLM usage and cost

The PR introduces a read-time fsck and dangling-transaction handling to improve the robustness of the file store against illegal edits and partial merges. The changes appear well-implemented and safe to merge, with comprehensive tests validating the new functionality. ## Walkthrough - **eventcore-fs/src/format.rs**: - Introduces `content_hash` for transaction integrity verification. - Implements `load_transaction` to perform read-time integrity checks. - Refactors transaction parsing to support integrity checks. - **eventcore-fs/src/index.rs**: - Updates index scanning to handle integrity failures and dangling transactions. - **eventcore-fs/src/lib.rs**: - Enhances `status()` to report integrity failures and dangling transactions. - **eventcore-fs/src/merge.rs**: - Adds structures for `DanglingTransaction` and `IntegrityFailure`. - Updates `StoreStatus` to include new integrity checks. - **eventcore-fs/tests/git_robustness_test.rs**: - Adds tests for integrity failure and dangling transaction scenarios. ## LLM usage and cost - Reasoning (gpt-4o) in=7678 out=431 cost=$0.044855 - Cheap (gpt-4o-mini) in=736 out=45 cost=$0.000137 Estimated total USD: $0.044992 via https://api.openai.com and https://api.openai.com
jwilger deleted branch feat/393-fsck-dangling 2026-06-13 06:53:56 -07:00
jwilger referenced this pull request from a commit 2026-06-13 06:57:41 -07:00
Sign in to join this conversation.
No description provided.