Skip to content

Accept relations the DD session did not start with - #19

Merged
ajwdev merged 1 commit into
mainfrom
ajw-dd-new-relation-inputs
Oct 2, 2026
Merged

ajwdev merged 1 commit into
mainfrom
ajw-dd-new-relation-inputs

Conversation

@ajwdev

@ajwdev ajwdev commented Oct 2, 2026

Copy link
Copy Markdown
Owner

Summary

Make the DD session accept facts for relations it did not start with,
and treat declared-but-empty relations as inputs, instead of silently
dropping facts or failing with "not found in rels".

Problem

The DD worker only creates input handles for relations known at spawn.
Command::Insert/Remove do if let Some(h) = handles.get_mut(&rel),
so facts for any other relation vanish. Separately, a relation that is
declared but never derived or populated is not an input at all.

Reproduced on upstream/main with --backend dd against testdata/:

$ printf '%s\n' '+ brand_new("x").' 'brand_new(X)' '::quit' | pallograph ... --backend dd
Asserted.
No entries for 'brand_new'.

$ printf '%s\n' '?- nodepool_taint(A,B,C,D)' '::quit' | pallograph ... --backend dd
Error: dd backend cannot evaluate this rule:
rule for `_0`: relation `nodepool_taint` not found in rels

The interpreter backend returns brand_new("x") for the first and
No results. for the second.

Fix

  • DdSession records the relations it has an input handle for
    (inputs) and exposes has_input(&self, rel) -> bool.
  • Engine::add_fact: when a session is live and the relation has no
    input handle, push the fact to the EDB and rebuild the session
    (via a small private rebuild_session, which reports errors on
    stderr) rather than dropping it.
  • build_strata: relations that are Decl-ed, not derived by any rule,
    and not already extensional are also session inputs.

After the fix, both cases match the interpreter:

Asserted.
  brand_new("x")
Found 1 entries:

No results.

Known limitation

Adding a rule over a relation that was created after the session
started (for example ?- brand_new(X) right after + brand_new("x").)
still fails on DD with "not found in rels". That goes through
add_rule / add_idb, not add_fact, and is left for a follow-up.

Testing

  • engine::tests::dd_add_fact_new_relation_is_visible: add_fact on a
    brand-new relation is visible via query_live and evaluate, and
    matches the interpreter. Fails without the has_input/rebuild change.
  • engine::tests::dd_declared_but_empty_relation_is_queryable: a rule
    over a declared-but-empty relation compiles on DD and yields no rows.
    Fails without the build_strata change (relation lonely not found in rels).
  • cargo fmt --check, cargo clippy --all-targets --locked -- -D warnings
    and cargo test --all-targets --locked all pass on stable.

🤖 Generated with Claude Code

The DD worker only creates input handles for relations known when it
is spawned, and silently drops inserts for any other relation. Two
cases hit this:

- Engine::add_fact on a brand-new relation lost the fact, so a later
  query on the DD backend returned nothing while the interpreter
  returned the row.
- A relation that is declared but never derived or populated was not
  an input, so rules referencing it failed with "relation not found
  in rels".

DdSession now records its input relations and exposes has_input.
add_fact pushes a fact for an unknown relation to the EDB and
rebuilds the session. build_strata also treats declared relations
that no rule derives as inputs.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@ajwdev
ajwdev merged commit fb29088 into main Oct 2, 2026
2 checks passed
@ajwdev
ajwdev deleted the ajw-dd-new-relation-inputs branch October 2, 2026 18:00
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.

1 participant