omnigraph/crates
Ragnor Comerford 26b4c61d44
recovery: address PR #72 round-2 review findings
Bot reviewers (cubic + cursor) flagged 5 follow-on issues after the
first fix push. Three are real bugs in the Phase 6-8 ensure_indices
sidecar wiring; two are AI-slop flags on shallow tests. One cursor
finding is a false positive on intentional node/edge index asymmetry.

Real bugs fixed:

- needs_index_work_node and needs_index_work_edge now skip empty
  tables (count_rows == 0). The ensure_indices_for_branch loop has
  `if row_count > 0 { build_indices(...) }`, so empty tables produce
  zero commit_staged calls. Pinning them in the sidecar would force
  NoMovement classification on recovery and trigger the all-or-nothing
  rollback of any sibling table's legitimate index work (cubic #1).

- needs_index_work_node and needs_index_work_edge now respect the
  table_branch parameter from the snapshot entry, instead of always
  passing None (== main). For branch writes, opening the wrong HEAD
  could miss recoverable Phase B commits (cubic #2).

- needs_index_work_edge documented as intentionally BTree-only (mirrors
  the build_indices_on_dataset_for_catalog edge branch which only
  builds id/src/dst BTrees). Cursor flagged FTS/vector omission as
  inconsistency with the node helper; confirmed intentional via
  inline comment so future readers know the asymmetry is on purpose
  (cursor finding, false positive marked).

Test improvements:

- recovery_multi_sidecar_requires_fresh_snapshot_for_correctness — new
  integration test that uses TWO sidecars on the SAME table where
  sidecar B's expected_version equals sidecar A's post_commit_pin.
  Sidecar B's classification only succeeds if the recovery sweep
  refreshes the snapshot between iterations to see A's manifest
  update. Without the refresh fix from the prior commit, B would be
  classified against stale pins (cubic #4 follow-up).

- recovery_ensure_indices_handles_empty_tables — new integration test
  that runs ensure_indices on an all-empty repo. With the round-2 fix,
  both initial and steady-state runs leave no sidecar (zero pins ⇒
  zero sidecar I/O). Without the empty-table fix, the sidecar would
  pin Company (zero rows but missing indices) and force a NoMovement
  rollback (cubic #1 verification).

- ensure_indices_phase_b_failure_does_not_leak_sidecar_when_no_work_needed —
  renamed/rewrote the prior `_recovered_on_next_open` test to assert
  the post-fix invariant: when load_jsonl auto-built every catalog
  index via prepare_updates_for_commit, ensure_indices's needs_work
  helpers correctly report zero pins and produce no sidecar. The old
  assertion ("exactly one sidecar must persist") was wrong for the
  scoped behavior.

Test surface (post-round-2):
- 25 unit tests in db::manifest::recovery (BranchMerge classifier,
  sort order, primitives — unchanged).
- 12 integration tests in tests/recovery.rs (+2 from this commit).
- 11 failpoint tests including the four per-writer Phase B → recovery
  tests (one renamed to reflect the scoped behavior).
- ~672 workspace tests pass with --features failpoints.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 12:50:33 +02:00
..
omnigraph recovery: address PR #72 round-2 review findings 2026-05-03 12:50:33 +02:00
omnigraph-cli release: bump version to 0.4.1 2026-05-02 23:20:50 +02:00
omnigraph-compiler release: bump version to 0.4.1 2026-05-02 23:20:50 +02:00
omnigraph-server release: bump version to 0.4.1 2026-05-02 23:20:50 +02:00