8000 Pseudo-attribute metadata depends on plan order · Issue #594 · project-minigraf/minigraf · GitHub
[go: up one dir, main page]

Skip to content

Pseudo-attribute metadata depends on plan order #594

Closed

Description

@adityamukho

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):

[:find ?n ?t :valid-at :any-valid-time
 :where [?e :person/name ?n] [?e :person/age ?a] [?e :db/tx-count ?t]]

?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.

Activity

  1. added this to the v3.0.0 milestone on Oct 14, 2026
  2. added
    bugSomething isn't working
    rustPull requests that update rust code
    on Oct 14, 2026
  3. adityamukho commented on Oct 14, 2026

    @adityamukho
    CollaboratorAuthor

    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.

  4. added 2 commits that reference this issue on Oct 15, 2026
  5. adityamukho commented on Oct 15, 2026

    @adityamukho
    CollaboratorAuthor

    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.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingrustPull requests that update rust code

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      0