@modernrelay/orbit-core 0.13.6 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Typed error taxonomy (spec §6.5, v0.2 subset of call sites).
2
+ * Typed error taxonomy for public operation failures.
3
3
  *
4
4
  * Structural fatality rule: a *transient* context loss never mints a
5
5
  * GraphError — it is a status transition ('lost') plus a 'context-lost'
@@ -7,7 +7,7 @@
7
7
  * code 'context-lost' is constructed ONLY on terminal recovery failure, where
8
8
  * it is always fatal. This keeps fatality structural rather than conditional.
9
9
  */
10
- /** Placeholder until resource admission control lands (plan S4-T06). */
10
+ /** Reserved for resource admission-control failures. */
11
11
  interface ResourceAdmissionReport {
12
12
  reason: string;
13
13
  estimatedBytes?: number;
@@ -31,8 +31,8 @@ type GraphError = {
31
31
  cause: unknown;
32
32
  };
33
33
  /**
34
- * Operation-scoped failures (spec §6.5): rejected promises / thrown calls.
35
- * All ten codes are typed now even where their subsystems are post-v0.2
34
+ * Operation-scoped failures: rejected promises / thrown calls.
35
+ * All ten codes are typed now even where their subsystems are post-v0.2
36
36
  * the union is the public contract, the wiring arrives with each subsystem.
37
37
  */
38
38
  type GraphOperationError = {
@@ -73,10 +73,10 @@ type GraphOperationError = {
73
73
  };
74
74
  /** Lifecycle phase an instance-level error occurred in. */
75
75
  type ErrorPhase = 'mount' | 'running' | 'recovery';
76
- /** Spec §6.5 fatality matrix as a pure decision function. */
76
+ /** Spec fatality matrix as a pure decision function. */
77
77
  declare function isFatalGraphError(error: GraphError, phase: ErrorPhase): boolean;
78
78
  /**
79
- * Spec §6.5 rule for a resource-limit producer deciding `fatal`: rejection is
79
+ * Spec rule for a resource-limit producer deciding `fatal`: rejection is
80
80
  * fatal before the first accepted scene or during terminal recovery; a later
81
81
  * inadmissible declarative update keeps the previous scene (non-fatal).
82
82
  */
@@ -91,25 +91,25 @@ declare class OrbitOperationError extends Error {
91
91
  declare function graphErrorToError(graphError: GraphError, cause?: Error): Error;
92
92
 
93
93
  /**
94
- * orbit-core public data model (spec §5, v0.1 subset).
94
+ * orbit-core public data model.
95
95
  *
96
96
  * The public model is object-based, id-keyed, and generic over caller attribute
97
97
  * types. A `GraphSnapshot` is the declarative source of truth; the core keeps a
98
- * derived index model and drives the engine imperatively (§4).
98
+ * derived index model and drives the engine imperatively.
99
99
  */
100
100
 
101
101
  type NodeId = string;
102
102
  type EdgeId = string;
103
103
  /** Plain JSON value — the shape `dataRef` and other verbatim host payloads
104
- * must fit (§16.14: stored, round-tripped, compared canonically, NEVER
105
- * interpreted). */
104
+ * must fit. Values are stored, round-tripped, compared canonically, and NEVER
105
+ * interpreted. */
106
106
  type JsonValue = null | boolean | number | string | JsonValue[] | {
107
107
  [key: string]: JsonValue;
108
108
  };
109
109
  interface GraphNode<N = Record<string, unknown>> {
110
110
  id: NodeId;
111
111
  attrs?: N;
112
- /** Optional fixed/persisted position (layout 'fixed' honors these; §10). */
112
+ /** Optional fixed/persisted position honored by the fixed layout. */
113
113
  x?: number;
114
114
  y?: number;
115
115
  }
@@ -118,7 +118,7 @@ interface GraphEdge<E = Record<string, unknown>> {
118
118
  * Optional stable id. When absent, the core synthesizes a deterministic id
119
119
  * `${escapedSource}→${escapedTarget}#${k}` where `\\`, `→`, and `#` are
120
120
  * backslash-escaped inside endpoint ids, and k disambiguates parallel edges
121
- * in first-occurrence order (§5). Simple endpoint ids retain the familiar
121
+ * in first-occurrence order. Simple endpoint ids retain the familiar
122
122
  * `${source}→${target}#${k}` form.
123
123
  */
124
124
  id?: EdgeId;
@@ -126,51 +126,51 @@ interface GraphEdge<E = Record<string, unknown>> {
126
126
  target: NodeId;
127
127
  attrs?: E;
128
128
  }
129
- /** Versioned snapshot — the declarative source of truth (§4, §5). */
129
+ /** Versioned snapshot — the declarative source of truth. */
130
130
  interface GraphSnapshot<N = Record<string, unknown>, E = Record<string, unknown>> {
131
- /** Identity of the dataset; changing it clears all per-dataset state (§5). */
131
+ /** Identity of the dataset; changing it clears all per-dataset state. */
132
132
  datasetKey: string;
133
- /** Caller-owned revision; same {datasetKey, sourceRevision} replays are idempotent (§5). */
133
+ /** Caller-owned revision; same {datasetKey, sourceRevision} replays are idempotent. */
134
134
  sourceRevision: number | string;
135
135
  nodes: readonly GraphNode<N>[];
136
136
  edges: readonly GraphEdge<E>[];
137
137
  }
138
138
  type DiagnosticSeverity = 'info' | 'warning' | 'error';
139
139
  type DiagnosticCode = 'duplicate-node-id' | 'duplicate-edge-id' | 'dangling-edge-endpoint' | 'invalid-node' | 'invalid-edge' | 'self-loop-retained'
140
- /** A filter predicate threw or an expr referenced bad data; aggregated (§9.1). */
140
+ /** A filter predicate threw or an expr referenced bad data; aggregated. */
141
141
  | 'filter-error'
142
- /** Async metric column rejected (misaligned/duplicate/unknown ids; §12). */
142
+ /** Async metric column rejected due to misalignment, duplicates, or unknown ids. */
143
143
  | 'metric-column-error'
144
- /** A channel reprojected repeatedly with identical outputs (§8 dev). */
144
+ /** A channel reprojected repeatedly with identical outputs. */
145
145
  | 'accessor-churn'
146
- /** Image atlas resolve/decoding failures, cadence-batched (§8). */
146
+ /** Image atlas resolve/decoding failures, cadence-batched. */
147
147
  | 'image-resolve-failed' | 'source-revision-reused'
148
- /** §5.1 columnar lane: invalid structure (length mismatch, detached
148
+ /** columnar lane: invalid structure (length mismatch, detached
149
149
  * buffer, out-of-range dictionary or endpoint index) — the WHOLE snapshot
150
150
  * is rejected before derivation; the previous accepted scene stays. */
151
151
  | 'invalid-columnar-snapshot'
152
- /** ADR-006 D5: the worker lane could not boot — columnar acceptance runs
152
+ /** The worker lane could not boot — columnar acceptance runs
153
153
  * on the main lane instead (info under execution:'auto', error under
154
154
  * 'worker'). One-shot per instance. */
155
155
  | 'worker-unavailable'
156
- /** A host config lane was rejected at the boundary (§5.1/§16.3 — e.g. a
156
+ /** A host config lane was rejected at the boundary — e.g. a
157
157
  * groups array whose containment is cyclic or multiply parented); the
158
158
  * previous config stays live. */
159
159
  | 'config-error'
160
- /** §16.14: a setViewState payload failed structural validation or carries
160
+ /** a setViewState payload failed structural validation or carries
161
161
  * a version newer than this library; NOTHING was applied. */
162
162
  | 'invalid-view-state' | 'engine-error' | 'accessor-error'
163
- /** A user event listener threw; isolated per §15 (the chain continues). */
163
+ /** A user event listener threw; isolated so the listener chain continues. */
164
164
  | 'listener-error'
165
- /** showLabelsFor exceeded tracked-label capacity; omissions counted (§14). */
165
+ /** showLabelsFor exceeded tracked-label capacity; omissions counted. */
166
166
  | 'label-overload'
167
- /** A same-id row from an earlier overlay won in admission order (§7.5). */
167
+ /** A same-id row from an earlier overlay won in admission order. */
168
168
  | 'overlay-node-shadowed'
169
- /** A service call was aborted/discarded before admission (§9.2; info). */
169
+ /** A service call was aborted/discarded before admission. */
170
170
  | 'service-aborted'
171
- /** A service call failed (§9.2; error). */
171
+ /** A service call failed. */
172
172
  | 'service-error' | 'context-lost' | 'operation-rejected'
173
- /** Adapter-defined codes are namespaced (spec §6.5 routing note). */
173
+ /** Adapter-defined codes are namespaced. */
174
174
  | `engine:${string}`;
175
175
  declare const DIAGNOSTIC_SAMPLE_CAP = 10;
176
176
  interface GraphDiagnostic {
@@ -187,10 +187,10 @@ interface Revisions {
187
187
  source: number | string | null;
188
188
  /** Monotonic counter advanced on every accepted model change. */
189
189
  model: number;
190
- /** Filtering/subgraph scope revision (§9). Advances with every accepted
190
+ /** Filtering/subgraph scope revision. Advances with every accepted
191
191
  * model change AND on every hard-scope (subgraph) change; a SCOPE-ONLY
192
192
  * change advances `scope` and `render` but NOT `model` — the first genuine
193
- * scope/model split (v0.5, §9.2). */
193
+ * scope/model split. */
194
194
  scope: number;
195
195
  /** Monotonic counter advanced on every desired-render publication. */
196
196
  render: number;
@@ -203,7 +203,7 @@ interface AcceptedEdge<E = Record<string, unknown>> extends GraphEdge<E> {
203
203
  interface AcceptedGraph<N = Record<string, unknown>, E = Record<string, unknown>> {
204
204
  datasetKey: string;
205
205
  sourceRevision: number | string;
206
- /** Deduplicated (first-wins), in accepted-base order (§5.1, §16.2). */
206
+ /** Deduplicated (first-wins), in accepted-base order. */
207
207
  nodes: readonly GraphNode<N>[];
208
208
  /** Dangling endpoints dropped; ids present (synthesized when needed). */
209
209
  edges: readonly AcceptedEdge<E>[];
@@ -222,23 +222,23 @@ interface RenderScene {
222
222
  edgeIdByIndex: readonly EdgeId[];
223
223
  /**
224
224
  * 2*count floats. NaN pairs mean "no known position" — the engine seeds
225
- * them (§7.3); known positions come from the position cache.
225
+ * them; known positions come from the position cache.
226
226
  */
227
227
  positions: Float32Array;
228
228
  /** 2*linkCount uint32 endpoint indices into the point set. */
229
229
  links: Uint32Array;
230
230
  /**
231
- * §16.3 stage-3 synthetic suffix (S12). Present iff the scene was rewritten
231
+ * Synthetic suffix. Present iff the scene was rewritten
232
232
  * by collapsed groups: point slots >= physicalPointCount are super-nodes
233
233
  * and link slots >= physicalLinkCount are meta-edges (synthetics are always
234
234
  * a contiguous suffix). For those slots, idByIndex/edgeIdByIndex hold
235
- * INTERNAL scene keys that never escape public payloads (§7.4) — consumers
235
+ * INTERNAL scene keys that never escape public payloads — consumers
236
236
  * resolve slots through the discriminated ScenePointRef/SceneLinkRef
237
237
  * helpers instead.
238
238
  */
239
239
  groups?: SceneGroups;
240
240
  }
241
- /** §16.3 compact synthetic-suffix descriptor attached to a rewritten scene. */
241
+ /** compact synthetic-suffix descriptor attached to a rewritten scene. */
242
242
  interface SceneGroups {
243
243
  physicalPointCount: number;
244
244
  physicalLinkCount: number;
@@ -247,9 +247,9 @@ interface SceneGroups {
247
247
  /** Aligned to link slots physicalLinkCount..linkCount-1. */
248
248
  metaEdges: readonly MetaEdge[];
249
249
  /**
250
- * §16.3 node folds: representatives that are REAL nodes, so they carry no
250
+ * node folds: representatives that are REAL nodes, so they carry no
251
251
  * synthetic slot and never appear in `superNodes`. A folded anchor keeps
252
- * its physical row (and its own caller-driven styling, R-6.1-14) — this
252
+ * its physical row (and its own caller-driven styling) — this
253
253
  * list only reports how many descendants it currently stands for, for
254
254
  * badge rendering. Empty when nothing is folded.
255
255
  */
@@ -260,7 +260,7 @@ interface SceneFold {
260
260
  anchorId: NodeId;
261
261
  hiddenCount: number;
262
262
  }
263
- /** §7.4 discriminated point ref: a physical node id or a resolved group
263
+ /** discriminated point ref: a physical node id or a resolved group
264
264
  * public namespaces only, never internal scene keys. */
265
265
  type ScenePointRef = {
266
266
  kind: 'node';
@@ -269,7 +269,7 @@ type ScenePointRef = {
269
269
  kind: 'group';
270
270
  group: ResolvedGroup;
271
271
  };
272
- /** §7.4 discriminated link ref: a physical edge id or a meta-edge record. */
272
+ /** discriminated link ref: a physical edge id or a meta-edge record. */
273
273
  type SceneLinkRef = {
274
274
  kind: 'edge';
275
275
  id: EdgeId;
@@ -280,8 +280,8 @@ type SceneLinkRef = {
280
280
  type Accessor<T, V> = V | ((item: T) => V);
281
281
  type LayoutKind = 'force' | 'fixed';
282
282
  /**
283
- * §10 force tunables under stable, engine-neutral names — orbit maps them onto
284
- * the active engine's parameters through atomic config-only commits (§13), so
283
+ * force tunables under stable, engine-neutral names — orbit maps them onto
284
+ * the active engine's parameters through atomic config-only commits, so
285
285
  * a value here never resets positions or restarts the layout.
286
286
  *
287
287
  * Every field is optional and OMISSION MEANS "leave the engine's default
@@ -373,7 +373,7 @@ interface ColumnarGraphSnapshot<N = Record<string, unknown>, E = Record<string,
373
373
  datasetKey: string;
374
374
  sourceRevision: string | number;
375
375
  /** Default 'borrowed'. 'transfer' detaches the supplied ArrayBuffers ONLY
376
- * after structural validation AND admission succeed (ADR-006 D4); the
376
+ * after structural validation AND admission succeed; the
377
377
  * snapshot object is then single-use. */
378
378
  bufferOwnership?: 'borrowed' | 'transfer';
379
379
  nodes: {
@@ -404,65 +404,65 @@ interface GraphHostUpdate<N = Record<string, unknown>, E = Record<string, unknow
404
404
  nodeSize?: Accessor<GraphNode<N>, number> | Scale<number, N>;
405
405
  linkColor?: Accessor<AcceptedEdge<E>, string>;
406
406
  linkWidth?: Accessor<AcceptedEdge<E>, number>;
407
- /** §12 async metric columns, joined once with revision-gated admission. */
407
+ /** async metric columns, joined once with revision-gated admission. */
408
408
  metrics?: readonly MetricColumn[];
409
409
  /**
410
- * §8 image sprites: synchronous, string-valued ref accessor (URL/blob
410
+ * image sprites: synchronous, string-valued ref accessor (URL/blob
411
411
  * ref/cache key — opaque to orbit). Refs feed the image-atlas pipeline when
412
412
  * the engine declares `pointImages`; otherwise refs are retained and the
413
- * placeholder shape renders (§13 capability policy).
413
+ * placeholder shape renders.
414
414
  */
415
- /** §8 image refs; `null` CLEARS the accessor and evicts the atlas back to
415
+ /** image refs; `null` CLEARS the accessor and evicts the atlas back to
416
416
  * placeholders (D2 explicit reset — omission stays "no change"). */
417
417
  nodeImage?: ((node: GraphNode<N>) => string | null) | null;
418
- /** §16.12 instanced arrowheads (capability-gated; inert when unsupported). */
418
+ /** instanced arrowheads (capability-gated; inert when unsupported). */
419
419
  edgeArrows?: boolean;
420
- /** §16.14 durable source coordinate for view states — stored VERBATIM,
420
+ /** durable source coordinate for view states — stored VERBATIM,
421
421
  * never interpreted; serialized by getViewState and canonically compared
422
422
  * on setViewState. Stash-only lane: no publish, no commit. Omission means
423
423
  * no change (there is no clear form in v1 — set `{}` for emptiness). */
424
424
  dataRef?: JsonValue;
425
- /** §16.13 runtime toggles — atomic config-only commits, no reprojection. */
425
+ /** runtime toggles — atomic config-only commits, no reprojection. */
426
426
  showLinks?: boolean;
427
- /** §13 emphasis-ring toggle (default TRUE — the ring predates its name: it
427
+ /** emphasis-ring toggle (default TRUE — the ring predates its name: it
428
428
  * has followed hover since v0.1). False clears the engine ring once and
429
429
  * suppresses every driver (hover, focusNode, emphasizeNode). */
430
430
  emphasisRing?: boolean;
431
431
  layout?: LayoutKind;
432
432
  simulation?: SimulationConfig;
433
- /** Controlled selection (uncontrolled when never provided; §6.4 subset). */
433
+ /** Controlled selection (uncontrolled when never provided; subset). */
434
434
  selection?: readonly NodeId[];
435
435
  theme?: ThemeInput;
436
- /** DOM label lane configuration (§14; strategy 'dom' only in v0.4). */
436
+ /** DOM label lane configuration; strategy 'dom' only in v0.4. */
437
437
  labels?: LabelConfig<N>;
438
- /** §15.1 accessibility runtime options. */
438
+ /** accessibility runtime options. */
439
439
  accessibility?: AccessibilityConfig<N>;
440
- /** §9.2 hard scope: feed ONLY the resolved subset through the reconciler;
440
+ /** hard scope: feed ONLY the resolved subset through the reconciler;
441
441
  * null restores full scope. Positions come from the cache; reflow default
442
442
  * true restarts the layout around the remainder. */
443
443
  subgraph?: SubgraphSpec | null;
444
- /** §9.1 soft filter: mask (hide/dim) with ZERO relayout; null clears. */
444
+ /** soft filter: mask (hide/dim) with ZERO relayout; null clears. */
445
445
  filter?: FilterSpec<N, E> | null;
446
- /** §16.6 crossfilter dimensions (declarative; brushes live on the session). */
446
+ /** crossfilter dimensions (declarative; brushes live on the session). */
447
447
  crossfilter?: readonly DimensionSpec<N>[];
448
- /** §16.3 manual groups; null clears (D2). Config-error with groupBy. */
448
+ /** manual groups; null clears (D2). Config-error with groupBy. */
449
449
  groups?: readonly GroupSpec[] | null;
450
- /** §16.3 derived grouping; null clears (D2). Config-error with groups. */
450
+ /** derived grouping; null clears (D2). Config-error with groups. */
451
451
  groupBy?: GroupBySpec<N> | null;
452
- /** §16.3 stage-4 non-collapsing layout clusters; null clears (D2). Clusters
452
+ /** stage-4 non-collapsing layout clusters; null clears (D2). Clusters
453
453
  * COEXIST with groups — they preserve every node and edge. */
454
454
  clusters?: ClusterSpec<N> | null;
455
- /** §16.3 persistent pins (independent of transient drag pinning); null
455
+ /** persistent pins (independent of transient drag pinning); null
456
456
  * clears (D2). Departed ids prune through ownership. */
457
457
  pinnedNodeIds?: readonly NodeId[] | null;
458
- /** §16.3 parallel-edge grouping toggle: same-pair edges collapse into one
458
+ /** parallel-edge grouping toggle: same-pair edges collapse into one
459
459
  * count-weighted meta-edge. */
460
460
  parallelEdgeGrouping?: boolean;
461
461
  }
462
462
  /** Built-in synchronous metrics plus caller-supplied async column names. */
463
463
  type MetricName = 'degree' | 'inDegree' | 'outDegree' | (string & {});
464
464
  interface DomainPolicy {
465
- /** Domain population. Default 'dataset' (frozen per dataset revision
465
+ /** Domain population. Default 'dataset' (frozen per dataset revision
466
466
  * masking/isolation never change what a color means). */
467
467
  scope?: 'dataset' | 'hard-scope' | 'visible';
468
468
  /** Streaming behavior. Default 'freeze-per-revision'; 'expand' permits
@@ -488,7 +488,7 @@ type Scale<T, N = Record<string, unknown>> = {
488
488
  mid: number;
489
489
  range: readonly [T, T, T];
490
490
  };
491
- /** Async metric column joined against the accepted model (§12). */
491
+ /** Async metric column joined against the accepted model. */
492
492
  interface MetricColumn {
493
493
  metric: string;
494
494
  /** 'ids' joins by the ids array; 'index' is accepted-base positional. */
@@ -496,7 +496,7 @@ interface MetricColumn {
496
496
  values: readonly (number | null)[];
497
497
  ids?: readonly NodeId[];
498
498
  /**
499
- * §12/I1 issue-time stamp: the `getRevisions().model` value CURRENT WHEN
499
+ * Issue-time stamp: the `getRevisions().model` value CURRENT WHEN
500
500
  * THE UPDATE CARRYING THIS COLUMN WAS BUILT. Capture it before starting an
501
501
  * async computation and deliver it with the result — admission rejects the
502
502
  * column (info diagnostic) when the model has moved since, so stale async
@@ -514,7 +514,7 @@ interface GraphTheme {
514
514
  labelFg: string;
515
515
  accent: string;
516
516
  mutedAlpha: number;
517
- /** §13 emphasis-ring color (pointer hover, `focusNode`, `emphasizeNode`).
517
+ /** emphasis-ring color (pointer hover, `focusNode`, `emphasizeNode`).
518
518
  * Distinct from `accent` on purpose: accent is the SELECTION highlight, and
519
519
  * an emphasized node must not read as selected. */
520
520
  emphasisRing: string;
@@ -562,7 +562,7 @@ interface DimensionSpec<N = Record<string, unknown>> {
562
562
  /** Stable dimension key (brushes rebase by this key across data updates). */
563
563
  key: string;
564
564
  kind: DimensionKind;
565
- /** Raw value accessor; §8 hygiene applies (non-finite → excluded from bins).
565
+ /** Raw value accessor; hygiene applies (non-finite → excluded from bins).
566
566
  * Temporal accepts epoch-ms numbers, ISO strings, or 'YYYY-MM-DD'. */
567
567
  get: (node: GraphNode<N>) => unknown;
568
568
  /** Histogram bin count for numeric/temporal (default 24). */
@@ -582,7 +582,7 @@ interface HistogramBin {
582
582
  /** Rows in this bin regardless of any mask. */
583
583
  total: number;
584
584
  /** Rows in this bin passing every OTHER dimension's brush + the filter
585
- * prop's node mask (the §16.6 joint "filtered" second layer). */
585
+ * prop's node mask (the joint "filtered" second layer). */
586
586
  filtered: number;
587
587
  }
588
588
  interface CategoryBin {
@@ -601,7 +601,7 @@ interface DimensionSummary {
601
601
  };
602
602
  bins: readonly HistogramBin[];
603
603
  categories: readonly CategoryBin[];
604
- /** Rows excluded by §8 hygiene (non-finite / unparseable). */
604
+ /** Rows excluded by hygiene (non-finite / unparseable). */
605
605
  excludedRows: number;
606
606
  }
607
607
  interface CrossfilterSession {
@@ -638,7 +638,7 @@ interface SearchResult<N = Record<string, unknown>> {
638
638
  label?: string;
639
639
  node?: GraphNode<N>;
640
640
  }
641
- /** Why an activated result could not be focused (§16.5 result contract). */
641
+ /** Why an activated result could not be focused. */
642
642
  type SearchUnavailableReason = 'not-loaded' | 'out-of-scope' | 'filtered';
643
643
  type SearchActivation = {
644
644
  status: 'focused';
@@ -648,7 +648,7 @@ type SearchActivation = {
648
648
  reason: SearchUnavailableReason;
649
649
  result: SearchResult;
650
650
  };
651
- /** Context every async service call receives (§9.2 sequencing rule). */
651
+ /** Context every async service call receives. */
652
652
  interface RequestContext {
653
653
  datasetKey: string;
654
654
  sourceRevision: number | string | null;
@@ -659,7 +659,7 @@ interface RequestContext {
659
659
  signal: AbortSignal;
660
660
  }
661
661
  type RevisionDimension = 'source' | 'model' | 'scope';
662
- /** A service declares exactly the revision dimensions it consumes (§9.2). */
662
+ /** A service declares exactly the revision dimensions it consumes. */
663
663
  interface RevisionAwareService {
664
664
  readonly revisionDependencies: readonly RevisionDimension[];
665
665
  }
@@ -674,9 +674,9 @@ type ExpansionResponse<N = Record<string, unknown>, E = Record<string, unknown>>
674
674
  provenance?: unknown;
675
675
  };
676
676
  /**
677
- * §16.2 path resolver seam (S12-T08). `find` resolves the node/edge id path
677
+ * path resolver seam. `find` resolves the node/edge id path
678
678
  * between two loaded nodes or null when unreachable (null is a RESULT, not
679
- * an error). Extends the §9.2 revision-aware contract: abort is advisory,
679
+ * an error). Extends the revision-aware contract: abort is advisory,
680
680
  * revision admission at delivery is authoritative.
681
681
  */
682
682
  interface PathService extends RevisionAwareService {
@@ -687,7 +687,7 @@ interface ExpansionService<N = Record<string, unknown>, E = Record<string, unkno
687
687
  }
688
688
  interface BeginIngestOptions {
689
689
  /** 'replace' commits a new source coordinate atomically; 'overlay' advances
690
- * only modelRevision and may be progressive (§7.5). */
690
+ * only modelRevision and may be progressive. */
691
691
  purpose: 'replace' | 'overlay';
692
692
  datasetKey: string;
693
693
  /** Required for 'replace': the source coordinate the commit establishes. */
@@ -707,7 +707,7 @@ interface BeginIngestOptions {
707
707
  maxPendingBytes?: number;
708
708
  }
709
709
  interface IngestBatch<N = Record<string, unknown>, E = Record<string, unknown>> {
710
- /** Consecutive, strictly monotonic from zero (§7.5). */
710
+ /** Consecutive, strictly monotonic from zero. */
711
711
  sequence: number;
712
712
  /** Idempotency key: an admitted {sequence, batchId} replay returns its
713
713
  * original receipt; same sequence + different batchId rejects. */
@@ -734,7 +734,7 @@ interface IngestCommitReceipt {
734
734
  sourceRevision?: number | string;
735
735
  admittedNodes: number;
736
736
  admittedEdges: number;
737
- /** Dangling edges dropped at commit (diagnostics emitted only then; §7.5). */
737
+ /** Dangling edges dropped at commit; diagnostics are emitted only then. */
738
738
  danglingEdges: number;
739
739
  }
740
740
  type IngestSessionState = 'open' | 'committing' | 'committed' | 'aborted';
@@ -745,14 +745,14 @@ interface IngestSession<N = Record<string, unknown>, E = Record<string, unknown>
745
745
  commit(): Promise<IngestCommitReceipt>;
746
746
  abort(reason?: unknown): Promise<void>;
747
747
  }
748
- /** §14 label lane configuration (zoom-LOD, ranking, forced ids). */
748
+ /** label lane configuration (zoom-LOD, ranking, forced ids). */
749
749
  interface LabelConfig<N = Record<string, unknown>> {
750
750
  enabled?: boolean;
751
751
  /** Labels appear only at/above this zoom (LOD threshold). Default 1. */
752
752
  minZoom?: number;
753
753
  /**
754
- * §16.3 cluster-label LOD ceiling. At or BELOW this zoom the active
755
- * `clusters` spec's labels render and NODE labels are suppressed; above it
754
+ * cluster-label LOD ceiling. At or BELOW this zoom the active
755
+ * cluster labels render and NODE labels are suppressed; above it
756
756
  * cluster labels stop and node-label LOD (`minZoom`) takes over. Absent ⇒
757
757
  * no LOD hand-off: cluster labels (when a spec is active) and node labels
758
758
  * coexist, each on its own gate.
@@ -760,14 +760,14 @@ interface LabelConfig<N = Record<string, unknown>> {
760
760
  maxZoom?: number;
761
761
  /** Ranked-candidate cap k (viewport-culled). Default 64, policy max 1024. */
762
762
  maxVisible?: number;
763
- /** Ids that claim capacity FIRST, bypassing ranking (§14 showLabelsFor). */
763
+ /** Ids that claim capacity FIRST, bypassing ranking. */
764
764
  showFor?: readonly NodeId[];
765
- /** Label text; default attrs.label ?? id. Rendered as a TEXT NODE (§14). */
765
+ /** Label text; default attrs.label ?? id. Rendered as a TEXT NODE. */
766
766
  getText?: (node: GraphNode<N>) => string;
767
767
  /** Ranking weight; default nodeSize result order, else degree. */
768
768
  getWeight?: (node: GraphNode<N>) => number;
769
769
  }
770
- /** §15.1 accessibility runtime options. */
770
+ /** accessibility runtime options. */
771
771
  interface AccessibilityConfig<N = Record<string, unknown>> {
772
772
  /** Canvas aria-label. Default 'Graph visualization'. */
773
773
  label?: string;
@@ -780,13 +780,13 @@ interface AccessibilityConfig<N = Record<string, unknown>> {
780
780
  getAccessibleLabel?: (node: GraphNode<N>) => string;
781
781
  /**
782
782
  * Reduced-motion override: true forces reduced, false forces full motion,
783
- * undefined follows the host binding's media-query detection (§15.1).
783
+ * undefined follows the host binding's media-query detection.
784
784
  */
785
785
  reducedMotion?: boolean;
786
786
  }
787
- /** One positioned label emitted to the overlay lane per scheduler tick (§14). */
787
+ /** One positioned label emitted to the overlay lane per scheduler tick. */
788
788
  interface LabelPlacement {
789
- /** Node id — or, for `kind: 'cluster'`, the §16.3 CLUSTER KEY. */
789
+ /** Node id — or, for `kind: 'cluster'`, the CLUSTER KEY. */
790
790
  id: NodeId;
791
791
  text: string;
792
792
  /** Screen coordinates (CSS px, container-relative). */
@@ -794,10 +794,10 @@ interface LabelPlacement {
794
794
  y: number;
795
795
  forced: boolean;
796
796
  /**
797
- * §16.3 placement kind. 'node' (default) anchors to the node's cached
797
+ * placement kind. 'node' (default) anchors to the node's cached
798
798
  * position; 'cluster' anchors to the cluster's force center while the
799
799
  * simulation is hot and to its settled centroid afterwards, and selects its
800
- * MEMBER node ids when activated (R-16.3-18/21). Ids are drawn from
800
+ * MEMBER node ids when activated. Ids are drawn from
801
801
  * different namespaces, so consumers must key on `(kind, id)`.
802
802
  */
803
803
  kind?: 'node' | 'cluster';
@@ -808,22 +808,22 @@ interface ViewportState {
808
808
  zoom: number;
809
809
  }
810
810
  type InstanceStatus = 'idle' | 'mounting' | 'ready'
811
- /** WebGL context lost; engine frozen, CPU model stays live (§13.1). */
811
+ /** WebGL context lost; engine frozen, CPU model stays live. */
812
812
  | 'lost'
813
- /** Context restored; the full-scene replay commit is in flight (§13.1). */
813
+ /** Context restored; the full-scene replay commit is in flight. */
814
814
  | 'recovering' | 'destroyed' | 'error';
815
815
  /**
816
- * Namespaced selection (§16.2). Namespaces are independent: node-set algebra
817
- * never mutates edge selection. `groupIds` is reserved (populated from S12).
816
+ * Namespaced selection. Namespaces are independent: node-set algebra
817
+ * never mutates edge selection. `groupIds` is populated by group operations.
818
818
  */
819
819
  interface SelectionState {
820
820
  nodeIds: readonly NodeId[];
821
821
  edgeIds: readonly EdgeId[];
822
822
  groupIds: readonly string[];
823
823
  }
824
- /** §16.3 manual group definition. Flat and disjoint: membership may not
824
+ /** manual group definition. Flat and disjoint: membership may not
825
825
  * nest, overlap, duplicate, self-reference, or name unknown ids — violations
826
- * are §5.1 config-error diagnostics BEFORE any scene rewrite. */
826
+ * are config-error diagnostics BEFORE any scene rewrite. */
827
827
  interface GroupSpec {
828
828
  /** Public group id — its own namespace, never colliding with node ids. */
829
829
  id: string;
@@ -833,7 +833,7 @@ interface GroupSpec {
833
833
  collapsed?: boolean;
834
834
  color?: string;
835
835
  }
836
- /** §16.3 derived grouping: one group per distinct accessor key (null =
836
+ /** derived grouping: one group per distinct accessor key (null =
837
837
  * ungrouped). Membership is derived and READ-ONLY; collapsed defaults false
838
838
  * so adding groupBy alone changes no rendering. */
839
839
  interface GroupBySpec<N = Record<string, unknown>> {
@@ -848,10 +848,10 @@ interface GroupBySpec<N = Record<string, unknown>> {
848
848
  };
849
849
  }
850
850
  /**
851
- * §16.3 stage-4 non-collapsing layout clusters: a categorical `by` accessor
851
+ * stage-4 non-collapsing layout clusters: a categorical `by` accessor
852
852
  * partitions the PHYSICAL scene (`null` ⇒ unclustered) into force-clustered,
853
853
  * centroid-labelled sets. Clusters preserve every node and edge and therefore
854
- * NEVER synthesize super-nodes or meta-edges (R-16.3-17/19); they coexist with
854
+ * NEVER synthesize super-nodes or meta-edges; they coexist with
855
855
  * groups and re-derive over the post-group-rewrite physical scene.
856
856
  */
857
857
  interface ClusterSpec<N = Record<string, unknown>> {
@@ -860,11 +860,11 @@ interface ClusterSpec<N = Record<string, unknown>> {
860
860
  by: (node: GraphNode<N>) => string | null;
861
861
  /** Cluster-force strength handed to the engine. Inert (with ONE loud
862
862
  * degradation diagnostic) on engines that do not declare `clusterForce`;
863
- * membership, labels, and centroids still work (R-13-39). */
863
+ * membership, labels, and centroids still work. */
864
864
  strength?: number;
865
865
  /** Explicit force centers per key, in SPACE coordinates. Keys omitted here
866
- * generate deterministically from the ordered keys + layout seed
867
- * (R-16.3-20 — see `resolveClusterCenters`). */
866
+ * generate deterministically from the ordered keys + layout seed; see
867
+ * `resolveClusterCenters`. */
868
868
  centers?: ReadonlyMap<string, readonly [number, number]>;
869
869
  }
870
870
  /** Resolved cluster surface for overlays/selection (public ids only). */
@@ -875,7 +875,7 @@ interface ResolvedCluster {
875
875
  memberIds: readonly NodeId[];
876
876
  /** The force center labels anchor to while the simulation is HOT. */
877
877
  forceCenter: readonly [number, number];
878
- /** Settled centroid from the last permitted §7.1 readback (or the commit
878
+ /** Settled centroid from the last permitted readback (or the commit
879
879
  * under a fixed layout); null until one has landed. */
880
880
  centroid: readonly [number, number] | null;
881
881
  }
@@ -889,8 +889,8 @@ interface ResolvedGroup {
889
889
  derived: boolean;
890
890
  color?: string;
891
891
  }
892
- /** §16.3 rerouted member edge on a collapsed group (stage 3), or a grouped
893
- * parallel-edge bundle (§16.3 R-24). Count is the badge datum. */
892
+ /** rerouted member edge on a collapsed group (stage 3), or a grouped
893
+ * parallel-edge bundle. Count is the badge datum. */
894
894
  interface MetaEdge {
895
895
  id: string;
896
896
  /** Node id OR group id endpoint (public namespaces). */
@@ -899,7 +899,7 @@ interface MetaEdge {
899
899
  /** Underlying (rerouted / collapsed-parallel) edge count. */
900
900
  count: number;
901
901
  }
902
- /** §16.2 path query options (PathService). */
902
+ /** path query options (PathService). */
903
903
  interface PathOptions {
904
904
  /** Edge-direction rule for traversal. Default 'outgoing'. */
905
905
  direction?: 'outgoing' | 'incoming' | 'either';
@@ -919,68 +919,68 @@ interface GraphStoreState {
919
919
  nodeId: NodeId | null;
920
920
  edgeId: EdgeId | null;
921
921
  };
922
- /** id → pinned space position (§16.3 pin slice; drag-pinning writes here). */
922
+ /** id → pinned space position. */
923
923
  pins: ReadonlyMap<NodeId, readonly [number, number]>;
924
- /** §16.3 PERSISTENT pins (S12-T09): ids held at their CURRENT position via
924
+ /** PERSISTENT pins: ids held at their CURRENT position via
925
925
  * engine.setPinnedIndices. Independent lifecycle from the transient
926
926
  * drag-pin `pins` slice — the engine receives the UNION; releasing a drag
927
927
  * pin on a persistently-pinned node leaves it pinned. No position payload
928
928
  * in v0.10: a persistent pin freezes the node wherever it currently is. */
929
929
  pinnedNodeIds: ReadonlySet<NodeId>;
930
930
  hiddenNodeIds: ReadonlySet<NodeId>;
931
- /** Active hard scope (§9.2); null = full scope. */
931
+ /** Active hard scope; null = full scope. */
932
932
  scope: SubgraphSpec | null;
933
- /** Soft-mask visibility counts (§9.1): RENDERED SCENE entities with zero
934
- * hide-failures — the §16.3 synthetic suffix INCLUDED, so a collapsed
933
+ /** Soft-mask visibility counts: RENDERED SCENE entities with zero
934
+ * hide-failures — the synthetic suffix INCLUDED, so a collapsed
935
935
  * group contributes its one drawn super-node. Equals nodeCount/edgeCount
936
936
  * when nothing masks, scopes, or groups.
937
937
  *
938
938
  * NOT the same question as `getVisibleNodeIds()`, which lists PUBLIC
939
- * physical ids only (§7.4). Pair a count with that list via
939
+ * physical ids only. Pair a count with that list via
940
940
  * `getVisibleNodeIds().length`; use `visible` for "how much is on screen". */
941
941
  visible: {
942
942
  nodes: number;
943
943
  edges: number;
944
944
  };
945
- /** Timeline playback state (§16.6): at most one playing dimension. */
945
+ /** Timeline playback state: at most one playing dimension. */
946
946
  timeline: {
947
947
  playingKey: string | null;
948
948
  };
949
- /** §16.14 history kernel depths (S9-T20; full walk semantics in S15). */
949
+ /** history kernel depths. */
950
950
  history: {
951
951
  undoDepth: number;
952
952
  redoDepth: number;
953
953
  };
954
- /** Node ids with an expansion in flight (§9.2 loading affordance). */
954
+ /** Node ids with an expansion in flight. */
955
955
  pendingExpansions: ReadonlySet<NodeId>;
956
956
  /**
957
- * §16.3 node folds: anchor id → how many members it stands for. Empty when
957
+ * node folds: anchor id → how many members it stands for. Empty when
958
958
  * nothing is folded.
959
959
  *
960
960
  * Published so folds are OBSERVABLE. A fold changes neither an anchor's id
961
- * nor its label text, so the §14 label lane — which re-renders content only
961
+ * nor its label text, so the label lane — which re-renders content only
962
962
  * when the candidate SET changes — would otherwise never re-render a badge
963
963
  * that depends on fold state. Subscribing to this slice is how a host keeps
964
964
  * fold-derived chrome (badges, affordances) in step.
965
965
  */
966
966
  folds: ReadonlyMap<NodeId, number>;
967
- /** Committed overlay ids for the current dataset (§7.5). */
967
+ /** Committed overlay ids for the current dataset. */
968
968
  overlayIds: readonly string[];
969
- /** §16.3 resolved groups (manual or groupBy-derived); [] when ungrouped.
969
+ /** resolved groups (manual or groupBy-derived); [] when ungrouped.
970
970
  * Path highlight is deliberately NOT here: session-local, never
971
- * serialized (§16.2). */
971
+ * serialized. */
972
972
  groups: readonly ResolvedGroup[];
973
- /** Last completed search (§16.5): feeds <GraphSearch> and the §15.1
973
+ /** Last completed search: feeds <GraphSearch> and the
974
974
  * navigator's search-results section. Cleared on datasetKey change. */
975
975
  search: {
976
976
  query: string;
977
977
  results: readonly SearchResult[];
978
978
  } | null;
979
979
  viewport: ViewportState | null;
980
- /** §14/§16.1: live force-simulation activity — true after a commit with
981
- * restart or resumeSimulation(); false on settle or pauseSimulation(). */
980
+ /** Live force-simulation activity — true after a commit with
981
+ * restart or resumeSimulation; false on settle or pauseSimulation. */
982
982
  simulationRunning: boolean;
983
- /** §8 resolved theme tokens (S10): the merged GraphTheme currently driving
983
+ /** Resolved theme tokens: the merged GraphTheme currently driving
984
984
  * engine config, projection fallbacks, and mask dim alpha. Published on
985
985
  * change; defaults to the dark base. */
986
986
  theme: GraphTheme;
@@ -992,10 +992,10 @@ interface GraphListenerControl {
992
992
  interface NodeEventPayload<N = Record<string, unknown>> {
993
993
  node: GraphNode<N>;
994
994
  }
995
- /** §13 engine buffer channels. Canonical home (engine/index.ts re-exports
995
+ /** engine buffer channels. Canonical home (engine/index.ts re-exports
996
996
  * the engine seam imports from types, never the reverse). */
997
997
  type EngineBufferChannel = 'pointPosition' | 'link' | 'pointColor' | 'pointSize' | 'linkColor' | 'linkWidth';
998
- /** §17 performance snapshot — NEVER carries raw attrs or ids (§17). */
998
+ /** performance snapshot — NEVER carries raw attrs or ids. */
999
999
  interface GraphPerfSnapshot {
1000
1000
  at: number;
1001
1001
  nodeCount: number;
@@ -1026,16 +1026,16 @@ interface GraphPerfSnapshot {
1026
1026
  activeDegradations: readonly DegradeStep[];
1027
1027
  execution: 'main' | 'worker';
1028
1028
  rangeUpdates: readonly EngineBufferChannel[];
1029
- /** §17 pressure-sampler mirror (S13-T07): EWMA of per-window mean frame
1030
- * deltas, dropped-frame count, and idle wakeups since the last sample
1031
- * 0 idle wakeups is the healthy reading under the ADR-005 gated clock. */
1029
+ /** pressure-sampler mirror: EWMA of per-window mean frame
1030
+ * deltas, dropped-frame count, and idle wakeups since the last sample.
1031
+ * Zero idle wakeups is the healthy reading under the gated activity clock. */
1032
1032
  pressure: {
1033
1033
  frameEwmaMs: number;
1034
1034
  droppedFrames: number;
1035
1035
  idleWakeups: number;
1036
1036
  };
1037
1037
  }
1038
- /** §17/§6.1 `limits` — construction-time thresholds for the ladder (D7:
1038
+ /** `limits` — construction-time thresholds for the ladder (construction-only:
1039
1039
  * read once; a runtime change warns and is ignored). */
1040
1040
  interface ScaleLimits {
1041
1041
  /** Default 100_000. */
@@ -1050,7 +1050,7 @@ interface ScaleLimits {
1050
1050
  minimumDwellMs: number;
1051
1051
  /** Resource steps in engagement order. `uniform-link-style` participates
1052
1052
  * ONLY when explicitly listed — it can erase data-encoded styling, so
1053
- * omission means resource admission rejects instead (§17). */
1053
+ * omission means resource admission rejects instead. */
1054
1054
  resourceDegradationOrder: readonly ResourceDegradeStep[];
1055
1055
  }
1056
1056
  type ResourceDegradeStep = 'disable-transitions' | 'defer-images' | 'uniform-link-style';
@@ -1065,10 +1065,10 @@ interface DegradeEvent {
1065
1065
  };
1066
1066
  }
1067
1067
  interface GraphEventMap<N = Record<string, unknown>, E = Record<string, unknown>> {
1068
- /** §17 throttled telemetry sample — never per frame (S13-T07). */
1068
+ /** throttled telemetry sample — never per frame. */
1069
1069
  perfSample: GraphPerfSnapshot;
1070
- /** §17 ladder step engagement/disengagement (S13-T08). Notification
1071
- * pattern, not §6.4-controlled. */
1070
+ /** Ladder step engagement/disengagement. This is a notification pattern,
1071
+ * not a controlled state lane. */
1072
1072
  degrade: DegradeEvent;
1073
1073
  nodeClick: NodeEventPayload<N> & {
1074
1074
  metaKey?: boolean;
@@ -1090,14 +1090,14 @@ interface GraphEventMap<N = Record<string, unknown>, E = Record<string, unknown>
1090
1090
  x: number;
1091
1091
  y: number;
1092
1092
  };
1093
- /** §16.14: a setViewState dataRef mismatch — fired INSTEAD of applying.
1093
+ /** a setViewState dataRef mismatch — fired INSTEAD of applying.
1094
1094
  * Restoration proceeds only when the caller re-invokes with the opt-in. */
1095
1095
  viewStateMismatch: {
1096
1096
  stored: JsonValue | undefined;
1097
1097
  current: JsonValue | undefined;
1098
1098
  };
1099
- /** §16.14 aggregate restore intent: fired ONCE per restore/history
1100
- * transaction touching any §6.4 controlled slice or serialized styling
1099
+ /** aggregate restore intent: fired ONCE per restore/history
1100
+ * transaction touching any controlled slice or serialized styling
1101
1101
  * never fanned out per lane. The host reflects every participating prop in
1102
1102
  * one commit; the transaction commits when the reflected values match, and
1103
1103
  * times out / diverges / supersedes as typed results otherwise. `next` is
@@ -1120,7 +1120,7 @@ interface GraphEventMap<N = Record<string, unknown>, E = Record<string, unknown>
1120
1120
  };
1121
1121
  viewportChange: ViewportState;
1122
1122
  selectionChange: SelectionState;
1123
- /** §16.3/§7.4 (R-16.3-12): a super-node hit carries the resolved GROUP
1123
+ /** A super-node hit carries the resolved GROUP
1124
1124
  * never a GraphNode, never an internal scene key. Built-in follow-up
1125
1125
  * selects the group id into SelectionState.groupIds (preventDefault
1126
1126
  * cancels it, mirroring nodeClick). */
@@ -1128,31 +1128,31 @@ interface GraphEventMap<N = Record<string, unknown>, E = Record<string, unknown>
1128
1128
  group: ResolvedGroup;
1129
1129
  metaKey?: boolean;
1130
1130
  };
1131
- /** §16.3/§7.4: a meta-edge hit carries the MetaEdge record (public
1131
+ /** A meta-edge hit carries the MetaEdge record (public
1132
1132
  * endpoint ids + the underlying count badge datum). No built-in follow-up. */
1133
1133
  metaEdgeClick: {
1134
1134
  metaEdge: MetaEdge;
1135
1135
  };
1136
- /** §6.4 groups slice change: op results (uncontrolled), op intents
1136
+ /** groups slice change: op results (uncontrolled), op intents
1137
1137
  * (controlled — the host reflects the array back through the `groups`
1138
1138
  * prop), and groupBy re-derivations (notification; groupBy is always
1139
- * instance-derived, R-16.3-16). Host `groups` prop writes and manual
1139
+ * instance-derived). Host `groups` prop writes and manual
1140
1140
  * model-drift re-resolutions are store-only and do NOT fire this. */
1141
1141
  groupsChange: {
1142
1142
  groups: readonly ResolvedGroup[];
1143
1143
  };
1144
- /** §6.4 persistent-pin slice change (S12-T09), the groups-latch mirror:
1144
+ /** persistent-pin slice change, the groups-latch mirror:
1145
1145
  * op results (uncontrolled) and op INTENTS (controlled — the host
1146
1146
  * reflects the array back through the `pinnedNodeIds` prop). Host prop
1147
1147
  * writes and model-drift prunes are store-only and do NOT fire this. */
1148
1148
  pinnedChange: {
1149
1149
  pinnedNodeIds: readonly NodeId[];
1150
1150
  };
1151
- /** §16.3 effective-set reporting seam (S12-T03): retractExpansion fires this
1151
+ /** effective-set reporting seam: retractExpansion fires this
1152
1152
  * with the NEXT effective set as a SubgraphSpec whenever a collapse
1153
1153
  * changed what is displayed. v0.10 keeps `subgraph` UNCONTROLLED-ONLY, so
1154
1154
  * this is a notification today; a future controlled subgraph mode turns
1155
- * it into the §6.4 intent without changing the payload shape. */
1155
+ * it into the intent without changing the payload shape. */
1156
1156
  subgraphChange: {
1157
1157
  subgraph: SubgraphSpec;
1158
1158
  };
@@ -1166,19 +1166,19 @@ interface GraphEventMap<N = Record<string, unknown>, E = Record<string, unknown>
1166
1166
  type GraphEventName = keyof GraphEventMap;
1167
1167
 
1168
1168
  /**
1169
- * GraphEngine adapter contract (spec §13, v0.1 subset).
1169
+ * GraphEngine adapter contract.
1170
1170
  *
1171
1171
  * The core drives any engine exclusively through this interface; cosmos.gl is
1172
1172
  * the first implementation and lives in @modernrelay/orbit-engine-cosmos — the
1173
- * only package allowed to import it. FakeEngine (core /testing) implements the
1173
+ * only package allowed to import it. FakeEngine from the core testing entry implements the
1174
1174
  * same contract headlessly.
1175
1175
  *
1176
1176
  * v0.1 subset decisions:
1177
- * - Buffer updates are full-channel replaces, or RANGED patches for the
1178
- * channels an engine declares in `capabilities.rangeUpdates` (S13-T04).
1179
- * - One visibly atomic update per EngineCommit (§13): the adapter applies all
1180
- * channels/config of a commit before the next drawn frame.
1181
- * - Position readback (`getPositions`) is per-event only, never per-tick (§7.1/§17).
1177
+ * - Buffer updates are full-channel replaces, or RANGED patches for the
1178
+ * channels an engine declares in `capabilities.rangeUpdates`.
1179
+ * - One visibly atomic update per EngineCommit: the adapter applies all
1180
+ * channels/config of a commit before the next drawn frame.
1181
+ * - Position readback (`getPositions`) is per-event only, never per-tick.
1182
1182
  */
1183
1183
 
1184
1184
  interface EngineCapabilities {
@@ -1186,30 +1186,30 @@ interface EngineCapabilities {
1186
1186
  linkPicking: boolean;
1187
1187
  /** Channels supporting ranged (partial) updates. Empty in v0.1 for cosmos. */
1188
1188
  rangeUpdates: readonly EngineBufferChannel[];
1189
- /** O(k) tracked-subset position readback per frame (§13). */
1189
+ /** O(k) tracked-subset position readback per frame. */
1190
1190
  trackedPositions: boolean;
1191
1191
  /** Engine runs a live GPU force simulation. */
1192
1192
  simulation: boolean;
1193
- /** Instanced directional arrowheads on links (§16.12). */
1193
+ /** Instanced directional arrowheads on links. */
1194
1194
  edgeArrows?: boolean;
1195
- /** Per-point image sprites via a texture atlas (§8). */
1195
+ /** Per-point image sprites via a texture atlas. */
1196
1196
  pointImages?: boolean;
1197
- /** §16.3 cluster force: per-point cluster assignment with optional
1198
- * strength/centers (S12). Engines without it degrade loudly — membership,
1199
- * labels, and centroids still work (R-13-39). */
1197
+ /** cluster force: per-point cluster assignment with optional
1198
+ * strength/centers. Engines without it degrade loudly — membership,
1199
+ * labels, and centroids still work. */
1200
1200
  clusterForce?: boolean;
1201
- /** §17 frame-loop idle behavior: 'stops' = zero rAF at rest (quiescent,
1201
+ /** frame-loop idle behavior: 'stops' = zero rAF at rest (quiescent,
1202
1202
  * the stop-at-rest target); 'free-running' = the engine burns rAF while
1203
1203
  * idle — a documented degradation, not a violation. Absent reads as
1204
1204
  * 'free-running' (conservative). */
1205
1205
  idleFrames?: 'stops' | 'free-running';
1206
- /** §13/§17 onFrame phase: true = exact post-draw; false/absent = an
1207
- * activity clock (overlays may lag one sample — ADR-002). This field
1206
+ /** onFrame phase: true = exact post-draw; false/absent = an
1207
+ * activity clock (overlays may lag one sample). This field
1208
1208
  * makes the previously prose-only declaration real. */
1209
1209
  postDrawFrames?: boolean;
1210
1210
  }
1211
1211
  interface EngineConfigUpdate {
1212
- /** §16.3 stage-4 cluster force (capability `clusterForce`; inert
1212
+ /** stage-4 cluster force (capability `clusterForce`; inert
1213
1213
  * otherwise). null clears. `pointClusters` maps point index → cluster
1214
1214
  * ordinal (aligned to `centers` pairs). */
1215
1215
  cluster?: {
@@ -1221,18 +1221,18 @@ interface EngineConfigUpdate {
1221
1221
  simulation?: SimulationConfig;
1222
1222
  /** Space-coordinate defaults used when seeding unknown (NaN) positions. */
1223
1223
  seedRadius?: number;
1224
- /** §16.12 arrowheads on/off (capability edgeArrows; inert otherwise). */
1224
+ /** arrowheads on/off (capability edgeArrows; inert otherwise). */
1225
1225
  linkArrows?: boolean;
1226
- /** §16.13 link visibility toggle — config-only, never a buffer rebuild. */
1226
+ /** link visibility toggle — config-only, never a buffer rebuild. */
1227
1227
  renderLinks?: boolean;
1228
- /** Engine-relevant §8 theme tokens beyond background. */
1228
+ /** Engine-relevant theme tokens beyond background. */
1229
1229
  defaultPointColor?: string;
1230
1230
  defaultLinkColor?: string;
1231
- /** §13 emphasis-ring color (cosmos: `focusedPointRingColor`). No capability
1231
+ /** emphasis-ring color (cosmos: `focusedPointRingColor`). No capability
1232
1232
  * gate: `setFocusedIndex` is a required engine member, so every engine has
1233
1233
  * the mechanism — one that ignores the COLOR degrades to its own default. */
1234
1234
  emphasisRingColor?: string;
1235
- /** §17 disable-transitions ladder step (S13-T09): 0 = atomic jumps;
1235
+ /** disable-transitions ladder step: 0 = atomic jumps;
1236
1236
  * null = restore the engine's own default duration. Engines without
1237
1237
  * transitions ignore it. */
1238
1238
  transitionDurationMs?: number | null;
@@ -1269,12 +1269,12 @@ interface EngineCommit {
1269
1269
  linkWidth: Float32Array;
1270
1270
  }>;
1271
1271
  /**
1272
- * S13-T04 ranged channel updates — ONLY for channels the engine declared
1272
+ * ranged channel updates — ONLY for channels the engine declared
1273
1273
  * in `capabilities.rangeUpdates`, and only AFTER that channel has been
1274
1274
  * seeded by at least one full-buffer commit. A channel appears in
1275
1275
  * `buffers` OR here in one commit, never both. `start` is in ELEMENT
1276
1276
  * units of the channel's layout (RGBA floats for color channels). Patch
1277
- * `data` views are valid only during `commit()` — same lifetime contract
1277
+ * `data` views are valid only during `commit` — same lifetime contract
1278
1278
  * as full buffers.
1279
1279
  */
1280
1280
  bufferPatches?: Partial<{
@@ -1284,7 +1284,7 @@ interface EngineCommit {
1284
1284
  linkWidth: readonly BufferPatch[];
1285
1285
  }>;
1286
1286
  config?: EngineConfigUpdate;
1287
- /** §8 image-atlas resource updates (capability pointImages); applied
1287
+ /** image-atlas resource updates (capability pointImages); applied
1288
1288
  * atomically with the same commit's buffers. */
1289
1289
  resources?: {
1290
1290
  imageAtlas?: {
@@ -1303,7 +1303,7 @@ interface EngineCommit {
1303
1303
  } | false;
1304
1304
  }
1305
1305
  /**
1306
- * WebGL context lifecycle events (§13.1). `restored` means the adapter has a
1306
+ * WebGL context lifecycle events. `restored` means the adapter has a
1307
1307
  * fresh, empty, commit-ready GL machine in the same container — the core then
1308
1308
  * re-commits the scene. `failed` is terminal reinitialization failure.
1309
1309
  */
@@ -1315,14 +1315,14 @@ type EngineContextEvent = {
1315
1315
  type: 'failed';
1316
1316
  error: Error;
1317
1317
  };
1318
- /** Adapter observability channel; codes are namespaced `engine:*` (§6.5). */
1318
+ /** Adapter observability channel; codes are namespaced `engine:*`. */
1319
1319
  interface EngineDiagnostic {
1320
1320
  code: `engine:${string}`;
1321
1321
  severity: DiagnosticSeverity;
1322
1322
  message: string;
1323
1323
  }
1324
- /** Events the engine reports up to the core (indices are engine-local; the
1325
- * core maps them back to typed objects — §7.4). */
1324
+ /** Events the engine reports to core. Indices are engine-local; core maps
1325
+ * them back to typed objects. */
1326
1326
  interface EngineHostEvents {
1327
1327
  onPointClick?(index: number | null, modifiers?: {
1328
1328
  metaKey: boolean;
@@ -1332,13 +1332,13 @@ interface EngineHostEvents {
1332
1332
  /** Native link picking (capability `linkPicking`); indices are link-local. */
1333
1333
  onLinkClick?(linkIndex: number): void;
1334
1334
  onLinkHover?(linkIndex: number | null): void;
1335
- /** Native point drag (space coords). The core owns pin semantics (§16.3). */
1335
+ /** Native point drag (space coords). The core owns pin semantics. */
1336
1336
  onDragStart?(index: number): void;
1337
1337
  onDragEnd?(index: number, x: number, y: number): void;
1338
1338
  /** Context-menu gesture (right-click / touch long-press); null = background. */
1339
1339
  onContextMenu?(index: number | null, screen: readonly [number, number]): void;
1340
1340
  /**
1341
- * Overlay/activity clock (§13/§17): the adapter's per-frame callback for the
1341
+ * Overlay/activity clock: the adapter's per-frame callback for the
1342
1342
  * core scheduler's fan-out (DOM labels, tooltips). Under
1343
1343
  * `postDrawFrames:false` engines this is an activity clock — overlays may
1344
1344
  * lag the canvas by one sample; the adapter reports that degradation once.
@@ -1358,7 +1358,7 @@ interface GraphEngine {
1358
1358
  readonly capabilities: EngineCapabilities;
1359
1359
  /** Mount into a container. Resolve when the first frame can be produced. */
1360
1360
  mount(container: HTMLElement, events: EngineHostEvents): Promise<void>;
1361
- /** Apply one atomic update (§13). Throws only on programmer error. */
1361
+ /** Apply one atomic update. Throws only on programmer error. */
1362
1362
  commit(update: EngineCommit): void;
1363
1363
  /** Highest commit revision that is visibly applied. */
1364
1364
  appliedRevision(): number | null;
@@ -1378,7 +1378,7 @@ interface GraphEngine {
1378
1378
  pointsInPolygon?(screenPolygon: readonly [number, number][]): number[];
1379
1379
  /** Point indices inside a SCREEN-coordinate rect [x0,y0,x1,y1] (label cull). */
1380
1380
  pointsInRect?(screenRect: readonly [number, number, number, number]): number[];
1381
- /** Capture the current frame as an image (toolbar screenshot; §16.1). */
1381
+ /** Capture the current frame as an image for toolbar screenshots and exports. */
1382
1382
  captureScreenshot?(): Promise<Blob | null>;
1383
1383
  /** 1-hop neighbor point indices (engine adjacency, if available). */
1384
1384
  neighborIndices?(index: number): number[];