fix(query): unify at the binding seam — base engine done, planner + rule heads remain - #927
Draft
whilo wants to merge 1 commit into
Draft
fix(query): unify at the binding seam — base engine done, planner + rule heads remain#927whilo wants to merge 1 commit into
whilo wants to merge 1 commit into
Conversation
…ule heads remain) ONE law: binding a variable that is already bound is UNIFICATION, not assignment. Datomic's semantics, and already datahike's for a variable repeated inside one clause (#912/#913) and for ordinary data patterns. The clause forms that BIND a value each invented their own rule instead. The whole overwrite bug in the base engine is one `zipmap`: `prod-rel` builds its attr map with `(zipmap (concat attrs1 attrs2) (range))`, so a variable present in both relations resolves to the SECOND relation's column — the later binding silently wins. `[?e :name ?v] [(get-else $ ?e :nick "zzz") ?v]` asks for the entities whose nick equals their name; overwriting answers with every entity, asserting a ?v the database never contained. `unify-rel` keeps one column for a shared variable and admits the tuple pair only when the two values agree; it falls through to `prod-rel` when nothing is shared, which is the common case. `bind-by-fn` now uses it. Fixed by this one change, on the base engine: get-else output, tuple bindings, collection bindings, plain function outputs. STILL FAILING, deliberately left visible (5 assertions in query-binding-seam-test) rather than hidden behind a skip: * get-else under the PLANNER, both against a pattern-bound var and against an :in constant — the planner ignores the obligation instead of overwriting it, so it needs its own fix at the fused/optional merge sites; * a variable repeated in a rule HEAD, on BOTH engines, which answers nil in the first position. Those failing tests are the specification for the remaining work. Suite: 861 tests, 7188 assertions, 5 failures — all five are the new law tests above. NO pre-existing test encoded the overwrite behaviour, which is the result that makes this change safe to build on.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft: CI will be red, and that is the point — five assertions fail, all of them new law tests naming work this PR does not yet do. They are left visible rather than skipped, because a skipped test for a known-broken semantic is exactly the silence this whole effort is removing.
The law
Datomic's semantics, and already datahike's for a variable repeated inside one clause (#912/#913) and for ordinary data patterns —
[?e :name ?v] [?e :nick ?v]correctly selects entities whose nick equals their name. It was the clause forms that bind a value which each invented their own rule.The base-engine bug is one
zipmapprod-relbuilds its attr map with(zipmap (concat attrs1 attrs2) (range)). A variable in both relations therefore resolves to the second relation's column — the later binding silently wins:unify-relkeeps one column for a shared variable and admits a tuple pair only when the values agree, falling through toprod-relwhen nothing is shared (the common case).bind-by-fnuses it.What this fixes, and what it doesn't
get-elseoutputget-elsevs an:inconstantRemaining: the planner ignores the obligation rather than overwriting it, so it needs its own fix at the fused/optional merge sites; and a variable repeated in a rule head answers
nilin the first position on both engines.The result that makes this safe to build on
Full suite: 861 tests, 7188 assertions, 5 failures — all five are the new law tests.
unify-relchanges behaviour at every function-binding site in the base engine, and no pre-existing test encoded the overwrite behaviour. Had one done so, that would have been the interesting finding: a test pinning a bug.Why it matters beyond these four bugs
This is the entry that #924's
known-shared-wrongallowlist exists for. When the planner half lands, the:output-var-rebindentry must be deleted — and #924'sknown-shared-wrong-is-still-neededtest fails if it isn't, so the deletion is forced rather than remembered.