Skip to content

Split filtering, add reference-stable index, and reconcile the canvas #1890

Description

@kmcginnes

Task

Split filtering from conversion, add a reusable reference-stable index, and replace the full-replace + structure-version counter with a pure reconciler. This is one behavioral change — the graph stops rebuilding on every update — so the split, the memo, and the reconciler ship together.

Details

Filtering (presence) as its own concept:

  • A hook returning the surviving source Vertex[] (reads node filter state; answers only "is this vertex present?").
  • A hook returning the surviving source Edge[] (reads edge filter state + endpoint existence).

Conversion — pure total functions: Vertex → Canvas Vertex, Edge → Canvas Edge. No branches, no filtering, no volatile fields.

Reference-stable index — reusable util: maps each source item to an output, reusing the previous output when the source reference is unchanged; absent keys are evicted for free. Held in a ref so it persists across renders. Simultaneously the diff mirror, converter cache, and carry-forward index. Used by both the Graph View and Schema View.

Reconciler (internal seams, not exported from the module barrel):

  • Pure diffElements(prev, next) returning { added, removed, updated }, keyed on id presence + reference identity: same id + same ref → skip; same id + different ref → update (remove + add); new id → add; missing id → remove.
  • Thin applyDelta(cy, delta): one batch doing removes, node-adds before edge-adds, updates as remove-then-add. No patching, no data inspection.
  • The element-update hook becomes diff → apply → advance index → return { addedNodeIds, structureRevision }. addedNodeIds = genuinely-new vertices only.

Retire the structure-version counter:

  • Layout reads addedNodeIds; delete its previous-nodes bookkeeping.
  • Visibility, lock, blast-radius, connections-filter depend on the structureRevision token.
  • Delete the phantom counter prop from the selection hook.
  • Delete the deep-clone and full-replace.

Schema View: same three-part shape (presence = existing endpoint-existence check; conversion = vertex-type-config → element; shared reference-stable index).

Acceptance

  • Expanding one neighbor adds one vertex; layout positions only the new vertex; existing positions preserved.
  • diffElements unit tests: add, remove, update (ref change → remove+add), unchanged (same ref → skip), node-before-edge ordering, empty↔populated, no-op → empty delta.
  • applyDelta tests against a headless Cytoscape (or fake): batch add/remove/re-add, never patches.
  • Reference-stable index tests: same ref → same output; changed ref → new output; dropped key → evicted.
  • No deep-clone or full-replace remains; the structure-version counter is gone.
  • pnpm check:types and pnpm test green.

Related Issues

Important

Internal only — this issue is maintained by the core team and is not accepting external contributions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    internalSignals that the team will work on this issue internally.performanceIssues relating to performanceready-for-agentfully specified, ready for an AFK agenttech debtIssues, typically tasks, that are mainly about cleaning up code that is problematic in some way

    Type

    Fields

    No fields configured for Task.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions