8000 fix(query): join answers no longer depend on the plan (#545 PR 1) by adityamukho · Pull Request #592 · project-minigraf/minigraf · GitHub
[go: up one dir, main page]

Skip to content

fix(query): join answers no longer depend on the plan (#545 PR 1) - #592

Merged
adityamukho merged 3 commits into
v3from
feat/545-join-rules
Oct 14, 2026
Merged

adityamukho merged 3 commits into
v3from
feat/545-join-rules

Conversation

@adityamukho
@adityamukho adityamukho commented 8000 Oct 14, 2026
Copy link
Copy Markdown
Collaborator

Part 1 of 3 for #545 (streaming engine 3/9, #473). Plan: docs/superpowers/plans/2026-10-14-545-joins.md.

Before the engine gets its own joins (PR 2), this settles the two cases where today's executor gives a different answer depending on the plan, so the oracle compares against one rule.

Floats. Value's Hash hashed -0.0 and 0.0 differently although == holds for them (a Hash/Eq contract break), so a float join key never paired them. It now hashes -0.0 as 0.0. NaN still equals nothing. Float constants in patterns keep the epsilon match. On top-level joins the nested-loop path never compares a bound float. The epsilon comparison of floats substituted into not bodies is left to #546.

Keyword or ref. A variable bound to a keyword by one pattern and to the ref of the entity the keyword names by another now returns the kind from the first of those patterns in the :where text. Before, the answer came from whichever pattern the planner ran first. Binders (executor) records each variable's binding pattern by text position. PatternMatcher::match_with_hint_seeded takes the variables the pattern replaces: the hash path inserts the pattern's value, and the nested-loop path the fact's value. Expression bindings stay fixed, and pseudo-attribute patterns never replace a value. This covers both executor plan loops (with and without rules); or, not and rule bodies are unchanged.

Decisions settled with the maintainer (plan, "Design decisions"): IEEE == for float joins, :where text order for kinds, IndexNestedLoopJoin on entity probes only (PR 2), and pseudo-attributes reproduced with a follow-up issue (PR 3).

Tests

  • tests/join_rules_test.rs (10): 0.0/-0.0 as the join key and as a shared variable; float constant epsilon; keyword vs ref when plan order ≠ text order, through the attribute position, before and after a rule call, with a repeated pattern; an expression's value kept by a later text-earlier pattern; a pseudo-attribute pattern never replaces a value. Each rule test was checked to fail with its guard removed. They also pass under --features wasm.
  • types.rs unit test: -0.0 and 0.0 hash alike.
  • cargo test: 1,490 passed, 10 ignored; cargo test --features test-oracle: all pass; clippy clean (native, all features, wasm32 browser, wasip1).
  • Codex review: no correctness findings; its three test gaps are covered in 68d66c1.

CHANGELOG (Breaking changes) describes the changed answers.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HyLscCUuJ1GQpdAeX79EdR

adityamukho and others added 3 commits October 14, 2026 18:04
Three PRs: the executor's join rules (floats, keyword or ref), then
IndexNestedLoopJoin/HashJoin and planner v2, then pseudo-attributes
across joins, measurement and docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HyLscCUuJ1GQpdAeX79EdR
Value's Hash now hashes -0.0 as 0.0, as == already treats them, so a
float join key pairs them (it broke the Hash/Eq contract). A variable
bound to a keyword and to the ref of the entity it names takes its kind
from the first binding pattern in :where text order, not from the one
the planner ran first: the executor's plan loops pass the variables a
pattern rebinds to PatternMatcher::match_with_hint_seeded. Expression
bindings stay fixed; pseudo-attribute patterns never rebind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HyLscCUuJ1GQpdAeX79EdR
Review found three gaps: a rule call after the binding pattern, a
repeated pattern, and a pseudo-attribute pattern that must not replace
a value. The matcher's own pseudo-attribute guard duplicated Binders',
so the test could not fail; Binders alone decides now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HyLscCUuJ1GQpdAeX79EdR
@codecov
codecov Bot commented Oct 14, 2026
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.54054% with 7 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/query/datalog/matcher.rs 81.81% 4 Missing ⚠️
src/query/datalog/executor.rs 93.87% 3 Missing ⚠️

📢 Thoughts on this report? Let us know!

@adityamukho
adityamukho merged commit eab15bb into v3 Oct 14, 2026
25 checks passed
@adityamukho
adityamukho deleted the feat/545-join-rules branch October 14, 2026 12:56
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

0