Skip to content

GRAPH RAG FUSION: name every row in the Data Plane and drop the surrogate marker and the control-plane translator #428

Closed

Description

@EnRaiha

Version / build tested against

origin/main @ d1e957217 plus the branch of PR #426.

Deployment mode

Origin — single node (local), and a three-node cluster

Engine(s) involved

Graph, Vector, Document

Summary

Follow-up to #424 and PR #426. Not a defect.

After #426, GRAPH RAG FUSION has two mechanisms that name a hit in no edge:

  1. The owner's Data Plane reads the hit's client identity from its stored row (stored_client_identity) and returns it as key in RagVectorHit and RagTextHit. The cluster coordinator renames the marked rows from it (rag_fusion/naming.rs).
  2. The Data Plane sets a surrogate marker on each result that falls back to the surrogate's decimal. A control-plane translator (response_translate/rag_fusion.rs) resolves the marked rows through the answering node's catalog (resolve_surrogate_pk).

The idea: let the Data Plane name every row, then delete the marker, the translator and name_marked_rows. One mechanism, and no deny_unknown_fields coupling between the Data Plane response shape and a control-plane copy of it.

A read of the tree on the branch of PR #426 says this is feasible in part:

Case Today, single node Today, cluster After the change
Row with id, a declared key, or a strict primary key that is not its decimal key, from the catalog key, from the stored row key, from the stored row
Key equals the surrogate's decimal decimal decimal decimal
Row minted with no id decimal decimal decimal
No identity column, and a non-decimal key only in the catalog (native VectorInsert with a document_id, Lite vector sync push) key key on the minting node, decimal elsewhere decimal: a regression on one node
Bitemporal collection key depends on the node decimal, unless stored_client_identity reads the versioned table

The Data Plane never reads the catalog, so it cannot name the catalog-only rows. Net change: about 350 lines out, about 65 in, plus tests.

Proposal

Decide first whether a catalog-only row may answer its surrogate decimal. If yes:

  1. Add a single-node three-source test where a text-only hit in no edge names its key, and an in-process RagStage::Local test for two and three sources.
  2. Name the output rows late: keep the RRF keys as they are, so scores and ranks stay identical.
  3. Read the versioned table in stored_client_identity for a bitemporal collection.
  4. Pin the chosen catalog-only behaviour with a test.

Keying each hit by its stored identity before fusion would drop unbound entirely, but it fuses a bound vector hit with its text hit and changes scores. That needs its own change.

Expected behavior

A fusion row is named by one rule, in one place.

Actual behavior

Two mechanisms, and the second needs a marker field and a translator.

What actually happened? (check all that are true)

  • Acknowledged/committed data was lost, corrupted, or silently wrong
  • The server crashed, hung, or failed to start
  • A security or isolation boundary was crossed
  • Core functionality is broken with no acceptable workaround
  • A workaround exists (rewrite the query, avoid one path, etc.)

None. This is a cleanup proposal.

Proposed severity

SEV-4 — Low: cleanup. The behaviour is correct after #426.

Reproducibility

Not applicable.

Last known-good version / commit (if a regression)

Not applicable.

Environment & logs

Linux x86_64, debug build. No log.

Before submitting

Activity

  1. farhan-syah commented on Oct 20, 2026

    @farhan-syah
    Member

    Settled by #429 in the other direction. Every search response (vector, FTS, hybrid, GRAPH RAG FUSION) names rows after fusion through one Control-Plane resolver, resolve_surrogate_pks. It reads the local catalog in one read transaction, then asks the collection's home leader for the misses in one batched request. Catalog-only keys resolve on every node, so the regression in the table above does not occur. The fusion leg keys are typed (RagKey), so a key "7" never merges with surrogate 7. Closing.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions