ControlledGraph API

Core controlled-graph attachment, canonical snapshots, change requests, and diagnostics.

attachControlledGraph(engine, callbacks) declares “controlled” authority, installs the line reconciler, and returns the handle the application pushes canonical snapshots through:

Handle memberMeaning
setCanonicalGraph(snapshot)Cache the latest CanonicalGraphSnapshot ({ lines: LineRecord[] }) and schedule one coalesced reconciliation pass — the only inbound canonical channel
flush()Run any pending reconciliation synchronously (vanilla apps and tests)
dispose()Detach the reconciler

A LineRecord is { id, fromConnectorId, toConnectorId, payload? } with application-owned stable ids. Node and connector existence stays framework-mount-led; the snapshot carries only line records.

Change requests

callbacks.onLineChangeRequest(request) receives one atomic LineChangeRequest per gesture: an intent ("connect" | "disconnect" | "replace" | "reconnect") plus add (ProposedLine[] with SnapLine-minted ids), remove (LineId[]), update (LineEndpointUpdate[]), and the originalEvent. Apply the proposal to your records and push them back through setCanonicalGraph — adopting a proposed id settles the staged line in place; pushing unchanged records rejects it.

Diagnostics

callbacks.onDiagnosticsChanged(diagnostics) and query(engine).diagnostics() expose the current ReconciliationError[]. code is one of:

CodeMeaning
"duplicate-id"A record id appears more than once in the snapshot; the first record wins
"capacity-exceeded"A record violates a connector’s maxIncoming
"connection-rejected"An endpoint’s isValidConnection vetoed the record

Reconciliation never rewrites, reorders, or deletes canonical records: a record the mirror cannot represent stays latent (endpoints not mounted; silent) or errored (rules violation; structured diagnostic) and is retried when relevant state changes.