Split filtering, add reference-stable index, and reconcile the canvas
- Dominant language
- TypeScript
- Stars
- 481
- Forks
- 108
- Avg merge
- 8d 9h
- Merged PRs (30d)
- 7
Description
## 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
- Parent #1887
- Blocked by the decouple task
> [!IMPORTANT]
> Internal only — this issue is maintained by the core team and is not accepting external contributions.
Contributor guide
Assessment
This issue has not been assessed yet.