Skip to content

xlog-relcomp-probe: XLOG recursion on DR64, and XLOG × egglog over one relation - #1896

Merged
AdaWorldAPI merged 11 commits into
mainfrom
ccr-85acaff0-oszq40-reason
Oct 31, 2026
Merged

AdaWorldAPI merged 11 commits into
mainfrom
ccr-85acaff0-oszq40-reason

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

This is stage 1 of D-REASONING-CODEGRAPH-0: XLOG and egglog reasoning over the same stored relation. It lives in the existing xlog-relcomp-probe, as #1888's handoff asks. There is no new crate, engine or store.

XLOG recursion on the CPU kernel (src/recursive.rs)

  • admit_closure accepts XLOG's compiled recursive SCC for linear transitive closure, and nothing else. That shape is a base Scan edge plus a ChainJoin of path and edge on path.1 = edge.0, with an agreeing fallback.
  • Non-linear and mutual recursion are refused, each with its own reason.
  • closure binds edge under the sealed frame, types edge ∘ edge with the existing chain typing, and evaluates semi-naively with the existing relcomp::compose.
  • support(x, y) gives the facts some derivation of path(x, y) can use, and affected(u, v) the answers a fact can feed. Both are masks computed from the closure on demand; derivations are not stored.

tests/recursive.rs, 9 tests:

  • the closure matches BFS over the tuples and a naive fixpoint walk of XLOG's own compiled bodies;
  • a 200-case differential against BFS passes;
  • cycles terminate;
  • semi-naive work is exactly one row OR per derived pair;
  • support covers both diamond branches and excludes off-route facts;
  • the refusals hold, and a stale frame is refused.

egglog on the same register (tests/shared_relation.rs, 6 tests)

egglog derives equality from (rule ((edge a b)) ((union a b))), with proofs from prove.

  • egglog's a = b equals XLOG's closure of E ∪ Eᵀ on every pair of a two-component graph.
  • Every directed path is an egglog equality; the converse fails.
  • Every fact in an egglog proof is a bit of the shared register. For a directed answer, every such fact also lies in XLOG's support mask.
  • When a fact is removed and the frame advances, XLOG's bind refuses the old frame. The removed fact is found in the old egglog proof by its address, without re-running egglog.

The one conversion is register bits to egglog fact text: 114 B for 6 edges. egglog's tables and union-find are untouched.

Disable runs. Five guards were disabled one at a time, each turning its test red: the support filter, the reflexive closure in affected, the non-linear guard, the mutual-recursion guard, and semi-naive deltas. Three of these tests first stayed green and were tightened until they discriminated.

Not done:

  • timing;
  • the MLIR/DialEgg, SQL and Java legs;
  • egglog proofs of a directed relation;
  • recursion shapes beyond one linear closure.

cargo test --release passes and clippy -D warnings is clean.


Generated by Claude Code

…i-naively on DR64

admit_closure accepts exactly one linear recursive SCC (base Scan edge, step
ChainJoin path.1 = edge.0 projecting 0 and 3, fallback agreeing) and refuses
non-linear and mutual recursion. closure binds edge under the sealed frame and
runs semi-naive rounds over the existing relcomp::compose. support and
affected read derivations back from the closure as masks on demand.

Tests: BFS and a fixpoint walk of XLOG's own plan as references, a 200-case
differential, cycle termination, both diamond alternatives in support, the
affected set of one fact, refusals, and a stale frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMNZqKXSaeb9g2ypywF
One edge register under a sealed frame is read by XLOG's compiled closure
(directed reachability) and by egglog (equality with proofs, via
(rule ((edge a b)) ((union a b)))). Tests: egglog equality equals the
closure of E u E^T on all pairs; every directed path is an equality; an
egglog proof rests only on bits of the shared register, and on a directed
answer every proof fact lies in XLOG's support mask; a removed fact
invalidates the XLOG bind and is found in the old proof by address.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMNZqKXSaeb9g2ypywF
…ation stage

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMNZqKXSaeb9g2ypywF
@coderabbitai

coderabbitai Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7f2a7d54-ba8d-47f3-8c1d-b9f861b1b657
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

Share

trace(edge, valid, x, y) replays closure's semi-naive rounds and returns the
derivation evaluation performed: from the round path(x, y) first appeared,
back through the previous round's delta and edge, smallest intermediate first.
tests/trace.rs checks it against BFS shortest paths, the register, and support.

tests/provenance.rs: provenance is source root + frame version + program hash
+ CE64 declared reading (XLOG only). The root is an observer and its sorted,
deduplicated facts, so re-serializing a report is never new evidence; the
program hash covers the program, never the facts. Derivation multiplicity is
counted separately from independent roots, and two consumers of one root are
one observation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMNZqKXSaeb9g2ypywF
…, not lineage

derivation_multiplicity_is_not_independent_evidence counted the union of
roots over all derivations (lineage) and called it independent evidence.
With A reporting 1->2->4->5 and B only 1->3->4, the derivations rest on {A}
and {A, B}; absorption leaves {A}, so there is one independent support, not
two. The test now computes the ATMS label (PosBool provenance over source
roots) and pins three cases: one observer, B dependent on A, and B
independent of A. Lineage stays as a separate count and cannot tell the last
two apart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMNZqKXSaeb9g2ypywF
…ment label

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMNZqKXSaeb9g2ypywF
@AdaWorldAPI
AdaWorldAPI marked this pull request as ready for review October 31, 2026 19:01
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-31T19:02:39.828444Z 2678550 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@AdaWorldAPI
AdaWorldAPI merged commit 3927001 into main Oct 31, 2026
11 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2678550a73

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +170 to +171
for (p, w) in path.iter_mut().zip(e.rows) {
*p = w & valid;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Mask unassigned source rows when initializing the closure

When the register contains stale bits in an unassigned row, valid only masks destination columns, so those bits become answers even though their source slot is outside the domain. For example, with valid = 0b11 and only edge[63] = 1, closure returns rows[63] = 1; trace(edge, valid, 63, 0) likewise returns a base-fact witness for that unassigned source. Because the relation uses the same axis on both sides, zero rows whose index is not in valid, and apply the same initialization in trace, so the domain mask excludes invalid endpoints consistently.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants