omnigraph/docs
devin-ai-integration[bot] 6914e0256e
MR-786: merge-pair truth table with exhaustive op-variant matrix (#81)
* MR-786: merge-pair truth table with exhaustive op-variant matrix

Add crates/omnigraph/tests/merge_truth_table.rs that enumerates every
(left_op, right_op) cell from the operation vocabulary named in the
ticket — {noop, addNode, removeNode, addEdge, removeEdge, setProperty,
dropProperty, addLabel, removeLabel} — and asserts the deterministic
outcome of Omnigraph::branch_merge against a structured oracle.

The matrix is built in a 9x9 match in build_case, so adding a new
OpVariant is a compile-time, fail-on-omission task. Today's mutation
grammar only exposes insert | update set | delete (see
docs/query-language.md), so the 36 cells over the first six ops are
executable and the 45 cells involving dropProperty/addLabel/removeLabel
are recorded as Expected::Unsupported with a note. Each executable cell
spins up a fresh tempdir, applies one mutation per branch, calls
branch_merge, and asserts either:

  * MergeOutcome (AlreadyUpToDate / FastForward / Merged) plus a
    GraphAssert on the affected entities, or
  * an OmniError::MergeConflicts whose entries match the expected
    table_key + MergeConflictKind (row_id is optional because edge
    ULIDs are generated at runtime).

branch_merge is directional, so the (L, R) and (R, L) cells live in
separate entries in the matrix and are run independently — the
op-pair symmetry encoded in build_case serves as the commutativity
oracle without doubling the runtime. End-to-end the suite runs in
~10s on a fresh build, well under the 30s budget asserted at the
bottom of the test.

Also adds a row to docs/testing.md so the test-coverage map points
future agents at this file.

Co-Authored-By: Ragnor Comerford <ragnor.comerford@gmail.com>

* Use one Omnigraph handle for both branches

Self-review caught that the runner was opening two Omnigraph handles
on the same temp dataset (one for main, a second via Omnigraph::open
for feature). tests/branching.rs uses one handle and passes the branch
name to mutate_branch — same pattern works here and avoids any
cache-coherency surprises between the two handles. Also drops the
post-merge reopen, which only existed to give the second handle a
fresh snapshot.

Runtime drops ~10s -> ~9s.

Co-Authored-By: Ragnor Comerford <ragnor.comerford@gmail.com>

* Assert exact conflict count, not subset inclusion

cubic and Devin Review both flagged that check_outcome's
Expected::Conflicts arm only enforces want ⊆ got, so a regression that
produces a spurious extra conflict (e.g. emitting both OrphanEdge and
a stray DivergentInsert) would silently pass the truth-table cell.

For a deterministic oracle that's the wrong direction — the cell pins
the exact conflict-artifact set, not a lower bound. Add an
assert_eq!(got.len(), want.len()) before the existence loop. All 36
executable cells still pass; runtime unchanged.

Co-Authored-By: Ragnor Comerford <ragnor.comerford@gmail.com>

* Subsume 4 conflict tests in branching.rs into truth table

The four `branch_merge_reports_*_conflict` tests
(DivergentUpdate / DivergentInsert / DeleteVsUpdate / OrphanEdge)
were redundant with the deterministic-oracle cells in the new
`merge_truth_table.rs` and only added drift risk.

To preserve the post-conflict invariant that lived in
`branch_merge_reports_divergent_update_conflict` (target unchanged
after a failed merge), the truth-table runner now generalizes it:
on every `Conflicts` cell, main's state is asserted against
`state_after_apply_only(right_op)`. That gives strictly more
coverage than the deleted tests carried, since the invariant now
applies to *all* seven conflict cells, not just one.

The `UniqueViolation` and `CardinalityViolation` cases stay in
`branching.rs` — they're combinatorial (require >1 op per side
with a non-default schema) and out of scope for the pair-wise
truth table.

Co-Authored-By: Ragnor Comerford <ragnor.comerford@gmail.com>

* Fix misleading 'Total edges: 0' comment in (AddEdge, RemoveEdge) cell

Devin Review flagged that the comment said 'Total edges: 0' while the
parenthetical math evaluates to 1 (matching `GraphAssert::base()`).
The assertion is correct; only the leading number in the comment was
wrong. Reworded to 'Net edges: … = 1 (matches base)' so the prose
agrees with both the math and the assertion.

Co-Authored-By: Ragnor Comerford <ragnor.comerford@gmail.com>

---------

Co-authored-by: Ragnor <ragnor@modernrelay.com>
Co-authored-by: Ragnor Comerford <ragnor.comerford@gmail.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-12 22:36:01 +03:00
..
releases docs: expand 0.4.2 release notes 2026-05-10 14:37:58 +00:00
architecture.md docs: PR 2 documentation pass (server / architecture / §VI.23) 2026-05-07 17:09:49 +02:00
audit.md MR-794 step 2: docs — runs/invariants/architecture/execution + cleanup 2026-05-01 10:43:19 +02:00
branches-commits.md recovery: rename composite test, strip ticket references, address review 2026-05-03 13:56:36 +02:00
changes.md Refactor AGENTS.md from encyclopedia to map; move spec into docs/ 2026-04-28 23:31:08 +02:00
ci.md Address reviewer feedback (Cursor + cubic) on PR #60 2026-04-29 00:09:06 +02:00
cli-reference.md Address reviewer feedback (Cursor + cubic) on PR #60 2026-04-29 00:09:06 +02:00
cli.md MR-794 step 2: docs — runs/invariants/architecture/execution + cleanup 2026-05-01 10:43:19 +02:00
constants.md MR-794 step 2: docs — runs/invariants/architecture/execution + cleanup 2026-05-01 10:43:19 +02:00
deployment.md Document AWS build variant and bearer-token sources 2026-04-18 04:04:45 +03:00
embeddings.md Refactor AGENTS.md from encyclopedia to map; move spec into docs/ 2026-04-28 23:31:08 +02:00
errors.md MR-794 step 2: docs — runs/invariants/architecture/execution + cleanup 2026-05-01 10:43:19 +02:00
execution.md MR-794 step 2: docs — runs/invariants/architecture/execution + cleanup 2026-05-01 10:43:19 +02:00
indexes.md Refactor AGENTS.md from encyclopedia to map; move spec into docs/ 2026-04-28 23:31:08 +02:00
install.md Remove stale Homebrew source-build note 2026-04-11 14:12:49 +03:00
invariants.md docs: PR 2 documentation pass (server / architecture / §VI.23) 2026-05-07 17:09:49 +02:00
lance.md lance: confirm MemWAL is opt-in, intra-table, no overlap with MR-847 2026-05-02 19:44:37 +02:00
maintenance.md recovery: refresh-time roll-forward closes the in-process residual + invariants helper 2026-05-05 16:04:48 +02:00
merge.md Refactor AGENTS.md from encyclopedia to map; move spec into docs/ 2026-04-28 23:31:08 +02:00
policy.md Refactor AGENTS.md from encyclopedia to map; move spec into docs/ 2026-04-28 23:31:08 +02:00
query-language.md MR-794 step 2: docs — runs/invariants/architecture/execution + cleanup 2026-05-01 10:43:19 +02:00
runs.md docs/tests: reserve Phase A/B/C/D for the per-writer recovery flow 2026-05-05 22:46:03 +02:00
schema-language.md Address reviewer feedback (Cursor + cubic) on PR #60 2026-04-29 00:09:06 +02:00
server.md docs: fix admission gating description 2026-05-10 14:16:26 +00:00
storage.md recovery: rename composite test, strip ticket references, address review 2026-05-03 13:56:36 +02:00
testing.md MR-786: merge-pair truth table with exhaustive op-variant matrix (#81) 2026-05-12 22:36:01 +03:00
transactions.md docs: add docs/transactions.md — branch-as-transaction explainer (#69) 2026-05-12 22:35:57 +03:00