You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Pseudo-attribute metadata depends on plan order #594
Found while planning #545 (decision 4 of docs/superpowers/plans/2026-10-14-545-joins.md).
What happens
:db/valid-from, :db/valid-to, :db/tx-count and :db/tx-id read the fact of the last pattern with a stored attribute, in optimizer::plan order, that matched the same entity. The executor keeps per-entity hidden bindings (__fvf_<uuid> …) and each pattern match over
8000
writes them. So the answer depends on the join order, which differs between native and wasm (no reordering there):
?t is the tx-count of the :person/age fact or of the :person/name fact, whichever pattern ran last. With the two patterns at the same selectivity, source order decides; change one constant and the order (and the answer) changes.
The fallback is also row-dependent: when no earlier pattern matched the entity on that row, the pseudo-attribute pattern matches every visible fact of the entity (one row each), e.g.
[?e :person/friend ?f] [?f :db/tx-count ?t]
returns one row per fact of ?f, except on rows where ?f = ?e, where it returns the :person/friend fact's tx-count.
Where it stands
#545 PR 3 makes the streaming engine reproduce the executor exactly for the shapes where the source pattern is fixed or chosen by entity equality per row; the row-dependent fallback shapes (pseudo-attribute on an entity no earlier pattern binds as its entity, _ entities) stay on the executor.
To decide
A rule that does not depend on plan order, for example:
a pseudo-attribute pattern reads the fact of the nearest pattern before it in :where text order with the same entity term, and is an error (PRS-*) without one; or
a pseudo-attribute is a property of a pattern, written on it (e.g. a 4th/5th tuple position or a :meta binding form), not a separate pattern.
Either is a breaking change to queries; it belongs in v3.0.0 with the other #545 join rules (CHANGELOG Breaking changes) if it lands before the cut.
Rule settled with the maintainer (2026-10-14). Every plan must return the same rows the same number of times; only the order of rows may differ, and only when the query sets none. Today native and wasm (which keeps source order) disagree here. With :name and :age asserted in separate transactions, [?e :name ?n] [?e :age 30] [?e :db/tx-count ?t] gives ?t = 1 natively and ?t = 2 under --features wasm.
New rule: a per-fact pseudo-attribute pattern (:db/valid-from, :db/valid-to, :db/tx-count, :db/tx-id) reads the fact of the nearest pattern before it in :where text order whose entity term is the same. Without one, the query is a parse error (a new PRS-* code). This is a breaking change for v3.0.0 (CHANGELOG, Breaking changes). Still open for the spec: entity terms that differ but name the same entity (a keyword and a UUID constant for one entity), :db/valid-at (not per-fact, unchanged), and rule, or and not bodies.
Fixed on v3 by #602 (759cadf): a per-fact pseudo-attribute reads its source, the nearest earlier pattern in the :where text with the same entity term (lexical scope; not-join/or-join only for listed variables; closed rule bodies), resolved at parse time; PRS-081 when there is none. Docs: project-minigraf/minigraf-docs#19. Ships in v3.0.0.
Activity
adityamukho commentedon Oct 14, 2026
Rule settled with the maintainer (2026-10-14). Every plan must return the same rows the same number of times; only the order of rows may differ, and only when the query sets none. Today native and wasm (which keeps source order) disagree here. With
:nameand:ageasserted in separate transactions,[?e :name ?n] [?e :age 30] [?e :db/tx-count ?t]gives?t = 1natively and?t = 2under--features wasm.New rule: a per-fact pseudo-attribute pattern (
:db/valid-from,:db/valid-to,:db/tx-count,:db/tx-id) reads the fact of the nearest pattern before it in:wheretext order whose entity term is the same. Without one, the query is a parse error (a newPRS-*code). This is a breaking change for v3.0.0 (CHANGELOG, Breaking changes). Still open for the spec: entity terms that differ but name the same entity (a keyword and a UUID constant for one entity),:db/valid-at(not per-fact, unchanged), and rule,orandnotbodies.Merge pull request #598 from project-minigraf/docs/594-596-spec
Merge pull request #602 from project-minigraf/feat/594-pseudo-sources
adityamukho commentedon Oct 15, 2026
Fixed on
v3by #602 (759cadf): a per-fact pseudo-attribute reads its source, the nearest earlier pattern in the:wheretext with the same entity term (lexical scope;not-join/or-joinonly for listed variables; closed rule bodies), resolved at parse time; PRS-081 when there is none. Docs: project-minigraf/minigraf-docs#19. Ships in v3.0.0.