Skip to content

Index rows decode with no graph: stamp it once at the range-read choke point #2078

Open

Description

@aaj3f

Index rows come back from a range read with g: None: fluree-db-query/src/binary_range.rs builds every index row without a graph, so a caller that reads .g off a range result has to stamp the graph by hand, and the ones that didn't have each been their own named-graph bug. So far: the whole-graph scan, the annotation bundle seal (stamp_graph in stage.rs), the seal scan in #1887, #2022's net-change fold through current_asserted_for_key, and #2008's conflict retractions, which read through CurrentFacts and its stored() stamp. Each is fixed at its own site, or will be once #1887 lands, but the class isn't closed, and one instance is still open on main: push validation's is_currently_asserted (fluree-db-api/src/commit_transfer.rs) skips any range row whose g differs from the target's, so an index row never matches a named-graph target, and a pushed commit that retracts an index-resident named-graph fact is refused ("retract targets non-existent assertion").

  • Stamp the graph once, where every GraphDbRef / range_with_overlay caller already passes: range_with_overlay_tracked and range_bounded_with_overlay in fluree-db-core/src/range.rs, which both have the snapshot and the g_id. That also fixes push validation.
  • Drop the manual stamps that become redundant (stage.rs's stamp_graph, the whole-graph scan's; CurrentFacts's stored() keeps recording the origin).
  • Look at the two decode sites outside that choke point: binary_history.rs (the history API; its output may expose g) and block_fetch.rs (raw block transport, a wire payload, which I'd leave alone).
  • Tests: a range read over an indexed named graph returns stamped rows, and a push that retracts an index-resident named-graph fact is accepted.

On cost: Flake's PartialEq, Hash and comparators exclude g, so stamping only changes code that reads .g, and default-graph reads (g_id 0) don't change. Per row it's one Arc clone. Per named-graph range call it's resolving g_id to a Sid, and GraphRegistry stores IRIs only, so that's an IRI encode per call unless we add a small Sid cache (or callers that already know the graph Sid pass it). One-read-per-slot callers, like a wide named-graph delete, would pay that per slot without the cache, so this wants a before/after on named-graph-heavy shapes (a named-graph delete-all at 20k, SHACL over a named graph) before it lands. The estimate is about 40–60 lines plus the cache.

cc @bplatz, since #2022's fold reads through this path too.

Found while reviewing #2008 (the "index rows carry no graph" class).

Activity

  1. added
    bugSomething isn't working as expected
    P3Backlog: valid, low payoff-per-effort
    area:queryQuery execution, planning, fast paths, overlay, result formatting
    on Oct 12, 2026
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

    P3Backlog: valid, low payoff-per-effortarea:queryQuery execution, planning, fast paths, overlay, result formattingbugSomething isn't working as expected

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions