@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.
package/dist/index.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { G as GraphSnapshot, A as AcceptedGraph, R as ResolvedGroup, a as GraphDiagnostic, b as GraphNode, c as AcceptedEdge, N as NodeId, M as MetaEdge, S as SceneFold, d as GroupSpec, e as GroupBySpec, f as SceneGroups, g as RenderScene, h as SceneLinkRef, i as ScenePointRef, j as Accessor, k as RevisionAwareService, l as RequestContext, m as SearchResult, V as ViewportState, n as SelectionState, o as SubgraphSpec, J as JsonValue, E as EngineFactory, p as ExpansionService, P as PathService, q as ScaleLimits, r as GraphTheme, s as GraphStoreState, L as LabelPlacement, t as GraphHostUpdate, B as BeginIngestOptions, I as IngestSession, u as GraphEventName, v as GraphEventMap, w as GraphListenerControl, x as EdgeId, y as GraphPerfSnapshot, z as ResolvedCluster, C as PathOptions, D as PathResult, F as SearchActivation, H as CrossfilterSession, T as TimelinePlayback, K as Scale, O as MetricName, Q as Revisions, U as AccessibilityConfig, W as ThemeInput, X as LabelConfig, Y as IngestBatch, Z as RevisionDimension, _ as FilterSpec, $ as FilterExpr, a0 as DimensionSpec, a1 as BrushState, a2 as DimensionSummary, a3 as DomainPolicy, a4 as EngineBufferChannel, a5 as GraphEngine, a6 as EngineCommit, a7 as EngineCapabilities, a8 as MetricColumn, a9 as ColumnarGraphSnapshot, aa as GraphSnapshotInput } from './index-BoQfS8jd.js';
2
- export { ab as AppendReceipt, ac as CategoryBin, ad as ClusterSpec, ae as Column, af as ColumnChange, ag as DIAGNOSTIC_SAMPLE_CAP, ah as DegradeEvent, ai as DegradeStep, aj as DiagnosticCode, ak as DiagnosticSeverity, al as DimensionKind, am as ErrorPhase, an as ExpansionBatch, ao as ExpansionResponse, ap as FilterMode, aq as FilterValue, ar as GraphEdge, as as GraphError, at as GraphOperationError, au as HistogramBin, av as IngestCommitReceipt, aw as IngestSessionState, ax as InstanceStatus, ay as LayoutKind, az as NodeEventPayload, aA as OrbitOperationError, aB as ResourceAdmissionReport, aC as ResourceDegradeStep, aD as SearchUnavailableReason, aE as SimulationConfig, aF as StringColumn, aG as graphErrorToError, aH as isFatalGraphError, aI as resourceLimitFatal } from './index-BoQfS8jd.js';
3
- import { W as WorkerFactoryOption } from './lane-SZYhcrXT.js';
4
- export { C as ClusterDerivation, D as DEFAULT_CLUSTER_CENTER_RADIUS, a as DEFAULT_LAYOUT_SEED, E as EncodedStringTable, R as RequestClass, b as WorkerEntity, c as WorkerEnvelope, d as WorkerTransport, e as clusterCentroids, f as collectTransfers, g as decodeStringTable, h as deriveClusters, i as encodeStringTable, j as generateClusterCenters, k as judgeEpoch, r as resolveClusterCenters } from './lane-SZYhcrXT.js';
1
+ import { G as GraphSnapshot, A as AcceptedGraph, R as ResolvedGroup, a as GraphDiagnostic, b as GraphNode, c as AcceptedEdge, N as NodeId, M as MetaEdge, S as SceneFold, d as GroupSpec, e as GroupBySpec, f as SceneGroups, g as RenderScene, h as SceneLinkRef, i as ScenePointRef, j as Accessor, k as RevisionAwareService, l as RequestContext, m as SearchResult, V as ViewportState, n as SelectionState, o as SubgraphSpec, J as JsonValue, E as EngineFactory, p as ExpansionService, P as PathService, q as ScaleLimits, r as GraphTheme, s as GraphStoreState, L as LabelPlacement, t as GraphHostUpdate, B as BeginIngestOptions, I as IngestSession, u as GraphEventName, v as GraphEventMap, w as GraphListenerControl, x as EdgeId, y as GraphPerfSnapshot, z as ResolvedCluster, C as PathOptions, D as PathResult, F as SearchActivation, H as CrossfilterSession, T as TimelinePlayback, K as Scale, O as MetricName, Q as Revisions, U as AccessibilityConfig, W as ThemeInput, X as LabelConfig, Y as IngestBatch, Z as RevisionDimension, _ as FilterSpec, $ as FilterExpr, a0 as DimensionSpec, a1 as BrushState, a2 as DimensionSummary, a3 as DomainPolicy, a4 as EngineBufferChannel, a5 as GraphEngine, a6 as EngineCommit, a7 as EngineCapabilities, a8 as MetricColumn, a9 as ColumnarGraphSnapshot, aa as GraphSnapshotInput } from './index-CPRTWpGA.js';
2
+ export { ab as AppendReceipt, ac as CategoryBin, ad as ClusterSpec, ae as Column, af as ColumnChange, ag as DIAGNOSTIC_SAMPLE_CAP, ah as DegradeEvent, ai as DegradeStep, aj as DiagnosticCode, ak as DiagnosticSeverity, al as DimensionKind, am as ErrorPhase, an as ExpansionBatch, ao as ExpansionResponse, ap as FilterMode, aq as FilterValue, ar as GraphEdge, as as GraphError, at as GraphOperationError, au as HistogramBin, av as IngestCommitReceipt, aw as IngestSessionState, ax as InstanceStatus, ay as LayoutKind, az as NodeEventPayload, aA as OrbitOperationError, aB as ResourceAdmissionReport, aC as ResourceDegradeStep, aD as SearchUnavailableReason, aE as SimulationConfig, aF as StringColumn, aG as graphErrorToError, aH as isFatalGraphError, aI as resourceLimitFatal } from './index-CPRTWpGA.js';
3
+ import { W as WorkerFactoryOption } from './lane-_KPQ1deI.js';
4
+ export { C as ClusterDerivation, D as DEFAULT_CLUSTER_CENTER_RADIUS, a as DEFAULT_LAYOUT_SEED, E as EncodedStringTable, R as RequestClass, b as WorkerEntity, c as WorkerEnvelope, d as WorkerTransport, e as clusterCentroids, f as collectTransfers, g as decodeStringTable, h as deriveClusters, i as encodeStringTable, j as generateClusterCenters, k as judgeEpoch, r as resolveClusterCenters } from './lane-_KPQ1deI.js';
5
5
  import { StoreApi } from 'zustand/vanilla';
6
6
 
7
7
  /**
8
- * §5.1 snapshot validation — deterministic malformed-input resolution.
8
+ * snapshot validation — deterministic malformed-input resolution.
9
9
  *
10
10
  * Pure function: same input → structurally identical output; never throws on
11
11
  * malformed input. Diagnostics are batched — at most one GraphDiagnostic per
@@ -16,7 +16,7 @@ import { StoreApi } from 'zustand/vanilla';
16
16
  declare function validateSnapshot<N = Record<string, unknown>, E = Record<string, unknown>>(snapshot: GraphSnapshot<N, E>): AcceptedGraph<N, E>;
17
17
 
18
18
  /**
19
- * §16.3 stage-3 containment rewrite (S12-T01) — pure derivation, no engine,
19
+ * stage-3 containment rewrite — pure derivation, no engine,
20
20
  * no DOM.
21
21
  *
22
22
  * ## The representative forest
@@ -37,35 +37,35 @@ declare function validateSnapshot<N = Record<string, unknown>, E = Record<string
37
37
  * why nesting needs no special case (a fold inside a collapsed group hides
38
38
  * with it, and its members' edges route to the group).
39
39
  *
40
- * Contract summary (spec §16.3/§7.6 stage 3, invariants E5):
40
+ * Contract summary:
41
41
  * - Groups are HIERARCHICAL but singly-parented: a member id may name another
42
- * group (nesting), but no entity has two parents. `validateGroupSpecs`
43
- * rejects a violating array with ONE batched §5.1 'config-error' diagnostic
44
- * BEFORE any scene rewrite — a rejected array changes nothing.
45
- * - `rewriteGroups` runs over the HARD-SCOPED model (§7.6 stage 2 output):
46
- * collapsed representatives replace their in-scope descendants with one row
47
- * (a synthetic super-node, or the fold anchor's existing physical row);
48
- * descendant edges re-route into meta-edge rows carrying the underlying-edge
49
- * count (the badge datum). The post-rewrite graph feeds the EXISTING §7.2
50
- * structural diff, so collapse/expand is a diff, never a reload.
51
- * - Group ids occupy a distinct PUBLIC namespace (§7.4): synthetic rows carry
52
- * INTERNAL scene keys (NUL-prefixed — outside the documented caller id
53
- * contract) that never escape public payloads. A group id equal to a node
54
- * id coexists without collision. A FOLD anchor is a real node, so its
55
- * entity key IS its node id and it needs no synthetic slot at all.
42
+ * group (nesting), but no entity has two parents. `validateGroupSpecs`
43
+ * rejects a violating array with ONE batched 'config-error' diagnostic
44
+ * BEFORE any scene rewrite — a rejected array changes nothing.
45
+ * - `rewriteGroups` runs over the HARD-SCOPED model:
46
+ * collapsed representatives replace their in-scope descendants with one row
47
+ * (a synthetic super-node, or the fold anchor's existing physical row);
48
+ * descendant edges re-route into meta-edge rows carrying the underlying-edge
49
+ * count (the badge datum). The post-rewrite graph feeds the EXISTING
50
+ * structural diff, so collapse/expand is a diff, never a reload.
51
+ * - Group ids occupy a distinct PUBLIC namespace: synthetic rows carry
52
+ * INTERNAL scene keys (NUL-prefixed — outside the documented caller id
53
+ * contract) that never escape public payloads. A group id equal to a node
54
+ * id coexists without collision. A FOLD anchor is a real node, so its
55
+ * entity key IS its node id and it needs no synthetic slot at all.
56
56
  * - Synthetic rows are never cast to N/E: they carry only `id`, and consumers
57
- * identify them by slot position — synthetics are always a CONTIGUOUS
58
- * SUFFIX of the node/edge lists (physical prefix ordering is preserved), so
59
- * `slot >= physicalCount` is the discrimination rule.
57
+ * identify them by slot position — synthetics are always a CONTIGUOUS
58
+ * SUFFIX of the node/edge lists (physical prefix ordering is preserved), so
59
+ * `slot >= physicalCount` is the discrimination rule.
60
60
  */
61
61
 
62
62
  /** Internal scene key of a collapsed group's super-node row. NEVER public. */
63
63
  declare function groupSceneKey(groupId: string): string;
64
64
  /** Internal scene key of a meta-edge row (directed rewritten endpoint pair). */
65
65
  declare function metaEdgeSceneKey(sourceKey: string, targetKey: string): string;
66
- /** §16.3 PUBLIC meta-edge id: the collision-safe ordered endpoint tuple
66
+ /** PUBLIC meta-edge id: the collision-safe ordered endpoint tuple
67
67
  * `JSON.stringify(['meta-edge', source.kind, source.id, target.kind,
68
- * target.id])` — shared with the parallel-edge grouping toggle (R-16.3-24). */
68
+ * target.id])` — shared with the parallel-edge grouping toggle. */
69
69
  declare function metaEdgePublicId(sourceKind: 'node' | 'group', sourceId: string, targetKind: 'node' | 'group', targetId: string): string;
70
70
  /**
71
71
  * Entity key: a physical node id, or a synthetic group scene key. A fold
@@ -102,16 +102,16 @@ interface GroupValidationResult {
102
102
  /**
103
103
  * Validates a manual `groups` array against the FULL accepted model (members
104
104
  * may live outside the current hard scope). Violations, all collected into
105
- * one diagnostic (§5.1 delivery contract — never one event per bad row):
105
+ * one diagnostic:
106
106
  * - duplicate group id in the array;
107
107
  * - self-membership (a group naming its own id — rejected even when a node
108
- * with that id exists: the ambiguity itself is the error);
108
+ * with that id exists: the ambiguity itself is the error);
109
109
  * - duplicate membership (the same node twice in one group);
110
110
  * - overlapping membership (the same node in two groups);
111
111
  * - CYCLIC nesting (groups that contain each other, directly or through a
112
- * chain — the containment forest must stay acyclic);
112
+ * chain — the containment forest must stay acyclic);
113
113
  * - unknown members (ids absent from the accepted model AND not naming
114
- * another group; with no accepted model every non-group member is unknown).
114
+ * another group; with no accepted model every non-group member is unknown).
115
115
  *
116
116
  * NESTING IS LEGAL: a member id naming another group id nests that group.
117
117
  * Containment is a forest, not a partition — but it stays SINGLY PARENTED,
@@ -126,14 +126,14 @@ declare function validateGroupSpecs(specs: readonly GroupSpec[], nodeIndex: Read
126
126
  */
127
127
  declare function resolveManualGroups(specs: readonly GroupSpec[], nodeIndex: ReadonlyMap<NodeId, number>): ResolvedGroup[];
128
128
  /** Canonical structural equality for the groups HOST LANE (GroupSpec is a
129
- * plain descriptor like Scale — equal literals never re-rewrite, §6.1). */
129
+ * plain descriptor like Scale — equal literals never re-rewrite). */
130
130
  declare function sameGroupSpecArrays(a: readonly GroupSpec[] | null, b: readonly GroupSpec[] | null): boolean;
131
131
  /**
132
- * R-16.3-14 collision-safe derived-group id codec: `JSON.stringify(['group',
132
+ * collision-safe derived-group id codec: `JSON.stringify(['group',
133
133
  * key])`. Injective over keys (JSON string encoding), never equal to the raw
134
134
  * key itself (every output starts with `["group",`), and round-trippable via
135
135
  * JSON.parse. Labels stay separate — the derived group's `label` is the raw
136
- * key. Group ids remain a distinct public namespace (§7.4), so a NODE id that
136
+ * key. Group ids remain a distinct public namespace, so a NODE id that
137
137
  * happens to equal a derived id still coexists without collision.
138
138
  */
139
139
  declare function groupByDerivedId(key: string): string;
@@ -142,8 +142,8 @@ declare function groupByDerivedId(key: string): string;
142
142
  declare function sameGroupBySpec<N>(a: GroupBySpec<N> | null, b: GroupBySpec<N> | null): boolean;
143
143
  /**
144
144
  * D4 boundary validation for a groupBy spec: `by` must be a function and
145
- * `semanticZoom.expandAbove` must be STRICTLY greater than `collapseBelow`
146
- * (the §16.3 hysteresis contract T05 builds on). Returns ONE batched
145
+ * `semanticZoom.expandAbove` must be STRICTLY greater than `collapseBelow`.
146
+ * Returns ONE batched
147
147
  * 'config-error' diagnostic (the rejected spec never lands — the previous
148
148
  * groupBy configuration stays active) or null when valid.
149
149
  */
@@ -152,21 +152,21 @@ interface GroupByDerivation {
152
152
  /** One derived group per distinct key, first-encounter order over the
153
153
  * model's node list. `collapsed` comes from the caller's residue lookup. */
154
154
  groups: readonly ResolvedGroup[];
155
- /** Derived PUBLIC id → derived key (the setGroupCollapsed reverse map
156
- * the residue is keyed by KEY, never by id, R-16.3-16). */
155
+ /** Derived PUBLIC id → derived key (the setGroupCollapsed reverse map;
156
+ * the residue is keyed by KEY, never by id). */
157
157
  keyById: ReadonlyMap<string, string>;
158
158
  /** ONE aggregated 'accessor-error' warning when `by` threw (the affected
159
159
  * nodes derive as ungrouped — never silent loss, I3), else null. */
160
160
  diagnostic: GraphDiagnostic | null;
161
161
  }
162
162
  /**
163
- * §16.3 groupBy derivation: one GroupSpec-shaped ResolvedGroup per distinct
164
- * string key returned by `by` (first-encounter order, matching §11
163
+ * groupBy derivation: one GroupSpec-shaped ResolvedGroup per distinct
164
+ * string key returned by `by` (first-encounter order, matching
165
165
  * categorical-domain conventions); `null` — and any non-string value — means
166
166
  * ungrouped. Derived ids use {@link groupByDerivedId}; `label` is the raw
167
167
  * key; `derived: true` marks membership read-only. `collapsed` defaults to
168
168
  * whatever `isCollapsedKey` reports — with an empty residue everything is
169
- * expanded, so adding groupBy alone changes no rendering (R-16.3-13).
169
+ * expanded, so adding groupBy alone changes no rendering.
170
170
  */
171
171
  declare function deriveGroupsByKey<N>(nodes: readonly GraphNode<N>[], by: (node: GraphNode<N>) => string | null, isCollapsedKey: (key: string) => boolean): GroupByDerivation;
172
172
  interface SuperNodeRecord {
@@ -182,15 +182,15 @@ interface SuperNodeRecord {
182
182
  interface MetaEdgeRecord {
183
183
  /** Internal scene key of the meta-edge row (never public). */
184
184
  sceneKey: string;
185
- /** Public record (§7.4 payload surface): endpoints are PUBLIC ids — a
185
+ /** Public record: endpoints are PUBLIC ids — a
186
186
  * group id or a node id — and `count` is the badge datum. */
187
187
  metaEdge: MetaEdge;
188
- /** Indices of the rerouted edges in the PRE-rewrite model's edge list
188
+ /** Indices of the rerouted edges in the PRE-rewrite model's edge list
189
189
  * the stage-5 "any underlying edge passes" rule evaluates these. */
190
190
  underlying: readonly number[];
191
191
  }
192
192
  interface GroupRewrite<N = Record<string, unknown>, E = Record<string, unknown>> {
193
- /** The post-rewrite scene model — what feeds the §7.2 structural diff. */
193
+ /** The post-rewrite scene model — what feeds the structural diff. */
194
194
  graph: AcceptedGraph<N, E>;
195
195
  /** Physical rows (same objects as the input model's, members removed). */
196
196
  physicalNodes: readonly GraphNode<N>[];
@@ -212,7 +212,7 @@ interface GroupRewrite<N = Record<string, unknown>, E = Record<string, unknown>>
212
212
  }
213
213
  /**
214
214
  * Rewrites the collapsed representatives of `forest` over the hard-scoped
215
- * model (§7.6 stage 3). Returns null when nothing collapsed intersects the
215
+ * model. Returns null when nothing collapsed intersects the
216
216
  * model — an uncollapsed group exists only in store.groups and never
217
217
  * rewrites the scene.
218
218
  *
@@ -224,7 +224,7 @@ interface GroupRewrite<N = Record<string, unknown>, E = Record<string, unknown>>
224
224
  * cached by construction: they re-derive from the unchanged accepted model on
225
225
  * expand. Synthetic rows carry no positions; the reconciler's departed cache
226
226
  * restores a re-collapsed super-node (stable scene key) and returning members
227
- * exactly like any other leave-and-return (§7.3).
227
+ * exactly like any other leave-and-return.
228
228
  */
229
229
  declare function rewriteGroups<N, E>(model: AcceptedGraph<N, E>, forest: RepForest): GroupRewrite<N, E> | null;
230
230
  /**
@@ -233,12 +233,12 @@ declare function rewriteGroups<N, E>(model: AcceptedGraph<N, E>, forest: RepFore
233
233
  * groups-empty rewrite when none is active). Returns `base` unchanged when
234
234
  * no pair has multiplicity > 1 — the toggle is then a scene no-op.
235
235
  *
236
- * Meta-edge identity reuses the T01 codecs: public id
237
- * `metaEdgePublicId('node', source, 'node', target)` (the R-16.3-24 tuple),
236
+ * Meta-edge identity reuses the group codecs: public id
237
+ * `metaEdgePublicId('node', source, 'node', target)`,
238
238
  * internal scene key `metaEdgeSceneKey(source, target)`. `count` (the badge
239
- * datum) is the collapsed multiplicity and drives the T01 aggregate width
239
+ * datum) is the collapsed multiplicity and drives the aggregate width
240
240
  * channel; `underlying` indexes the PRE-rewrite model's edge list so the
241
- * stage-5 "any underlying edge passes" mask rule applies unchanged.
241
+ * "any underlying edge passes" mask rule applies unchanged.
242
242
  */
243
243
  declare function collapseParallelEdges<N, E>(model: AcceptedGraph<N, E>, base: GroupRewrite<N, E> | null): GroupRewrite<N, E> | null;
244
244
  /** The RenderScene.groups descriptor for a rewrite. */
@@ -250,9 +250,9 @@ declare function scenePointRefAt(scene: RenderScene, index: number): ScenePointR
250
250
  declare function sceneLinkRefAt(scene: RenderScene, linkIndex: number): SceneLinkRef | null;
251
251
 
252
252
  /**
253
- * §7 reconciler — id↔index model, structural diff, position cache.
253
+ * reconciler — id↔index model, structural diff, position cache.
254
254
  *
255
- * v0.1 implements the 'rebuild' index policy only (§7.3): every reconcile
255
+ * v0.1 implements the 'rebuild' index policy only: every reconcile
256
256
  * rebuilds the flat buffers from scratch in accepted-base order, preserving
257
257
  * positions by id via the live/departed caches. Pure data-structure work: no
258
258
  * DOM, no engine import.
@@ -283,27 +283,27 @@ declare class Reconciler {
283
283
  private prevLinks;
284
284
  /**
285
285
  * Declared node.x/y as of the previous reconcile, for nodes that declared
286
- * them. Lets Priority 1 distinguish a CHANGED declaration (caller intent
286
+ * them. Lets Priority 1 distinguish a CHANGED declaration (caller intent
287
287
  * wins over any cache) from an unchanged one (defers to live drift). Fresh
288
288
  * per pass, so departed ids drop and a re-add treats its declaration as new.
289
289
  */
290
290
  private prevDeclared;
291
291
  /**
292
- * CPU position mirror for the CURRENT scene, indexed by slot (§7.1 posBuf).
292
+ * CPU position mirror for the CURRENT scene, indexed by slot.
293
293
  * Owned copy — never aliases a published scene's positions array, so
294
294
  * noteEnginePositions never mutates an already-published RenderScene.
295
295
  */
296
296
  private livePositions;
297
297
  /**
298
- * Ids removed from the scene → last known finite position (§7.1/§7.3
299
- * leave-and-return guarantee). Map insertion order doubles as LRU order;
298
+ * Ids removed from the scene → last known finite position, preserving the
299
+ * leave-and-return guarantee. Map insertion order doubles as LRU order;
300
300
  * invariant: never overlaps the current scene's id set.
301
301
  */
302
302
  private readonly departed;
303
303
  reconcile<N, E>(accepted: AcceptedGraph<N, E>): ReconcileResult;
304
304
  /**
305
305
  * Copy engine-read positions into the live cache for the CURRENT scene's
306
- * slots (§7.1 per-event readback — simulation end, pre-structural-swap).
306
+ * slots.
307
307
  * Extra trailing floats are ignored; a short buffer updates a prefix.
308
308
  */
309
309
  noteEnginePositions(positions: Float32Array): void;
@@ -311,12 +311,12 @@ declare class Reconciler {
311
311
  }
312
312
 
313
313
  /**
314
- * §8 projection (v0.1 subset): styling accessors → engine-ready typed buffers.
314
+ * projection (v0.1 subset): styling accessors → engine-ready typed buffers.
315
315
  *
316
316
  * Pure and DOM-free. Color parsing covers the CSS subset orbit documents
317
- * (hex, rgb()/rgba(), hsl()/hsla(), small named map); anything else is a
317
+ * (hex, rgb/rgba, hsl/hsla, small named map); anything else is a
318
318
  * caller error surfaced as a batched 'accessor-error' diagnostic, never a
319
- * throw and never a NaN in a GPU buffer (§8 numeric hygiene).
319
+ * throw and never a NaN in a GPU buffer.
320
320
  */
321
321
 
322
322
  type RGBA = [number, number, number, number];
@@ -337,11 +337,11 @@ declare function projectSizes<T>(items: readonly T[], accessor: Accessor<T, numb
337
337
  };
338
338
 
339
339
  /**
340
- * §16.5 search — the SearchService contract plus the built-in LOCAL indexed
341
- * service (S11-T06).
340
+ * search — the SearchService contract plus the built-in LOCAL indexed
341
+ * service.
342
342
  *
343
343
  * The default service is client-side and field-scoped: it indexes the node id
344
- * ALWAYS plus `attrs[field]` (String()-coerced) for each field the host
344
+ * ALWAYS plus `attrs[field]` (String-coerced) for each field the host
345
345
  * declared via `searchIndex` — it never guesses privileged attr names, so a
346
346
  * missing declaration leaves the service id-only. Matching is a
347
347
  * case-insensitive SUBSTRING scan over ONE precomputed lowercase haystack per
@@ -359,25 +359,25 @@ declare function projectSizes<T>(items: readonly T[], accessor: Accessor<T, numb
359
359
  *
360
360
  * `ctx.signal` is honored between scan chunks (an awaited microtask every
361
361
  * {@link SEARCH_SCAN_CHUNK} nodes) — abort is an optimization; the instance's
362
- * admission gate is the correctness gate (§9.2). Nothing here touches the
362
+ * admission gate is the correctness gate. Nothing here touches the
363
363
  * engine, the store, or the DOM.
364
364
  */
365
365
 
366
- /** §16.5 search resolver: custom services plug in server-side search
367
- * (Omnigraph B.7); the instance owns RequestContext creation, revision-keyed
366
+ /** Search resolver: custom services plug in server-side search; the instance
367
+ * owns RequestContext creation, revision-keyed
368
368
  * caching, supersede cancellation, and stale-result rejection at admission. */
369
369
  interface SearchService<N = Record<string, unknown>> extends RevisionAwareService {
370
370
  search(q: string, options: {
371
371
  limit: number;
372
372
  }, ctx: RequestContext): Promise<readonly SearchResult<N>[]>;
373
373
  }
374
- /** Accepted-base view the local service indexes (thunked for lazy wiring
374
+ /** Accepted-base view the local service indexes (thunked for lazy wiring
375
375
  * the instance re-reads it on every call, so the service can be constructed
376
376
  * before any data arrives). */
377
377
  interface LocalSearchBase<N = Record<string, unknown>> {
378
378
  /** Accepted-model nodes in accepted-base order (the tie-break order). */
379
379
  nodes: readonly GraphNode<N>[];
380
- /** §16.5 declared attr fields; undefined = id-only search (the service
380
+ /** declared attr fields; undefined = id-only search (the service
381
381
  * never guesses attr names). */
382
382
  searchIndex: readonly string[] | undefined;
383
383
  }
@@ -393,7 +393,7 @@ declare const SEARCH_SCORE_TOKEN_START_BONUS = 0.25;
393
393
  /** Nodes scanned between cooperative yields (awaited microtask + signal check). */
394
394
  declare const SEARCH_SCAN_CHUNK = 4096;
395
395
  /**
396
- * Creates the §16.5 default indexed search service over the accepted model.
396
+ * Creates the default indexed search service over the accepted model.
397
397
  * Declares `revisionDependencies: ['source', 'model']` — the index keys on
398
398
  * `ctx.modelRevision` (plus the declared field list), so it builds at most
399
399
  * once per model revision and a stale-model result is discarded by the
@@ -403,7 +403,7 @@ declare const SEARCH_SCAN_CHUNK = 4096;
403
403
  declare function createLocalSearchService<N = Record<string, unknown>>(getBase: () => LocalSearchBase<N>): LocalSearchService<N>;
404
404
 
405
405
  /**
406
- * §8 image-atlas pipeline (S10-T09) — pure core side.
406
+ * image-atlas pipeline — pure core side.
407
407
  *
408
408
  * Turns per-point image refs (stable strings from the synchronous `nodeImage`
409
409
  * accessor) into engine-ready atlas resources: resolved ImageBitmaps with
@@ -411,27 +411,27 @@ declare function createLocalSearchService<N = Record<string, unknown>>(getBase:
411
411
  * only ever sees the output shape (`EngineCommit.resources`); everything
412
412
  * async — resolve, fetch, decode, retry, abort — stays here.
413
413
  *
414
- * Invariants (spec §8):
415
- * - Loads are deduplicated by ref: one in-flight resolve per unique ref.
416
- * - Slots are allocated per unique ref from a free-list capped at
417
- * `maxEntries`; over-cap refs stay placeholder and are diagnosed once per
418
- * generation.
419
- * - Results are admission-checked against the current request state before
420
- * atlas admission; the abort signal is an optimization, admission is the
421
- * gate (a resolver that ignores its signal cannot poison a newer
422
- * generation).
423
- * - Transient resolver/fetch failures retry up to `maxRetries`; decode
424
- * failures are final.
425
- * - Failures are cadence-batched: ONE `image-resolve-failed` diagnostic per
426
- * flush with a count and sampled refs, each ref counted once per
427
- * generation. Failures never poison the engine commit.
428
- * - A resolver-returned string is a final URL/data URI fetched + decoded
429
- * exactly once — never recursively passed back to the resolver.
414
+ * Invariants:
415
+ * - Loads are deduplicated by ref: one in-flight resolve per unique ref.
416
+ * - Slots are allocated per unique ref from a free-list capped at
417
+ * `maxEntries`; over-cap refs stay placeholder and are diagnosed once per
418
+ * generation.
419
+ * - Results are admission-checked against the current request state before
420
+ * atlas admission; the abort signal is an optimization, admission is the
421
+ * gate (a resolver that ignores its signal cannot poison a newer
422
+ * generation).
423
+ * - Transient resolver/fetch failures retry up to `maxRetries`; decode
424
+ * failures are final.
425
+ * - Failures are cadence-batched: ONE `image-resolve-failed` diagnostic per
426
+ * flush with a count and sampled refs, each ref counted once per
427
+ * generation. Failures never poison the engine commit.
428
+ * - A resolver-returned string is a final URL/data URI fetched + decoded
429
+ * exactly once — never recursively passed back to the resolver.
430
430
  */
431
431
 
432
432
  /**
433
433
  * Owns authenticated fetch / caching / redirect handling for one ref
434
- * (spec §8, Appendix B.6). Returning a Blob hands the bytes straight to
434
+ * under the public resolver contract. Returning a Blob hands the bytes straight to
435
435
  * decode; returning a string names a FINAL URL or data URI that the pipeline
436
436
  * fetches + decodes once (it is never re-resolved).
437
437
  */
@@ -446,7 +446,7 @@ type FetchLike = (url: string, init: {
446
446
  }>;
447
447
  /** Blob → ImageBitmap. Injectable so Node tests never touch createImageBitmap. */
448
448
  type ImageDecode = (blob: Blob) => Promise<ImageBitmap>;
449
- /** One coalesced flush of atlas work — mirrors `EngineCommit.resources` (§13). */
449
+ /** One coalesced flush of atlas work — mirrors `EngineCommit.resources`. */
450
450
  interface ImageAtlasBatch {
451
451
  /** Newly resolved bitmaps with their slot assignments. */
452
452
  upserts: readonly {
@@ -508,7 +508,7 @@ declare class ImageAtlasPipeline {
508
508
  private generation;
509
509
  private flushScheduled;
510
510
  private disposed;
511
- /** D5/F11-06: evicted-entry bitmaps awaiting close — closed AFTER the
511
+ /** Evicted-entry bitmaps awaiting close — closed AFTER the
512
512
  * flush that carries their removeSlots, so the instance's recovery-replay
513
513
  * map (pruned synchronously in the batch callback) can never re-send a
514
514
  * closed bitmap. */
@@ -542,7 +542,7 @@ declare class ImageAtlasPipeline {
542
542
  /** -1 (placeholder) until the ref's bitmap is delivered or in this batch. */
543
543
  private buildPointIndex;
544
544
  /**
545
- * I2 (roster-atomic resource mappings, F11-03): the SYNCHRONOUS point→slot
545
+ * Roster-atomic resource mappings: the SYNCHRONOUS point→slot
546
546
  * mapping for the last requested roster — a slot appears only when its ref
547
547
  * is resolved AND the engine has already received the bitmap (delivered);
548
548
  * pending, failed, evicted, and reused-but-undelivered refs are the −1
@@ -555,7 +555,7 @@ declare class ImageAtlasPipeline {
555
555
  }
556
556
 
557
557
  /**
558
- * §16.14 view state (S15 view-state lane) — pure module: the serialized
558
+ * View state — pure module: the serialized
559
559
  * schema, the canonical-JSON encoder, the structural validator, and the
560
560
  * version gate. No engine, no DOM, no store access; the instance wires
561
561
  * `getViewState`/`setViewState` on top.
@@ -564,33 +564,33 @@ declare class ImageAtlasPipeline {
564
564
  *
565
565
  * Deep-links outlive library versions, so everything in this file is a
566
566
  * COMMITMENT, not an internal:
567
- * - The v1 wire shape below never changes incompatibly; breaking shape
568
- * changes bump `v` and ship an in-code migration from every prior version
569
- * in the same release (the registry seam is here from day one).
570
- * - Additive fields never bump `v` — an equal-`v` payload with unknown
571
- * fields applies cleanly with the unknowns ignored.
572
- * - A payload with `v` HIGHER than this library knows, or failing structural
573
- * validation (hand-edited URL, truncated paste), is rejected whole: a
574
- * half-restored view misrepresents what the sender saw (§16.14).
567
+ * - The v1 wire shape below never changes incompatibly; breaking shape
568
+ * changes bump `v` and ship an in-code migration from every prior version
569
+ * in the same release (the registry seam is here from day one).
570
+ * - Additive fields never bump `v` — an equal-`v` payload with unknown
571
+ * fields applies cleanly with the unknowns ignored.
572
+ * - A payload with `v` HIGHER than this library knows, or failing structural
573
+ * validation (hand-edited URL, truncated paste), is rejected whole: a
574
+ * half-restored view misrepresents what the sender saw.
575
575
  *
576
576
  * ## v1 shape notes
577
577
  *
578
- * - `folds` extends the spec's v1 schema (amendment logged with this slice):
579
- * §16.3 node folds are exploration state over stable public ids — a
580
- * deep-link that silently dropped them would misrepresent the sender's
581
- * view, the exact failure this feature exists to prevent. Session-local
582
- * expansion records, by contrast, are NEVER serialized (R-16.3-08).
583
- * - Brushes are TAGGED on the wire (`kind`) even though the runtime
584
- * BrushState is untagged: the tag comes from `DimensionSpec.kind` at
585
- * serialize time and lets restore validate shape-vs-dimension without
586
- * consulting the live spec first. Categorical stores EXCLUSIONS, so
587
- * categories that appear after the view was saved stay visible.
588
- * - `layout` is the normalized OBJECT form (`{ kind }`) even though the
589
- * runtime today carries only the bare kind string — the object is what
590
- * makes a future static seed or a layouts package additive.
578
+ * - `folds` extends the v1 schema:
579
+ * node folds are exploration state over stable public ids — a
580
+ * deep-link that silently dropped them would misrepresent the sender's
581
+ * view, the exact failure this feature exists to prevent. Session-local
582
+ * expansion records, by contrast, are NEVER serialized.
583
+ * - Brushes are TAGGED on the wire (`kind`) even though the runtime
584
+ * BrushState is untagged: the tag comes from `DimensionSpec.kind` at
585
+ * serialize time and lets restore validate shape-vs-dimension without
586
+ * consulting the live spec first. Categorical stores EXCLUSIONS, so
587
+ * categories that appear after the view was saved stay visible.
588
+ * - `layout` is the normalized OBJECT form (`{ kind }`) even though the
589
+ * runtime today carries only the bare kind string — the object is what
590
+ * makes a future static seed or a layouts package additive.
591
591
  */
592
592
 
593
- /** Tagged wire form of a crossfilter brush (§16.6 §16.14). */
593
+ /** Tagged wire form of a crossfilter brush for view-state serialization. */
594
594
  type ViewBrushState = {
595
595
  kind: 'numeric' | 'temporal';
596
596
  range: readonly [number, number];
@@ -603,23 +603,31 @@ type ViewBrushState = {
603
603
  interface ViewLayoutSpec {
604
604
  kind: 'force' | 'fixed';
605
605
  }
606
- /** §11 Scale subset that is data by construction (no functions). */
607
- type SerializableScale = {
608
- kind: 'sequential' | 'diverging';
606
+ type SerializableScaleFor<T extends string | number> = {
607
+ kind: 'sequential';
608
+ metric: string;
609
+ range: readonly [T, T];
610
+ domain?: readonly [number, number];
611
+ } | {
612
+ kind: 'diverging';
609
613
  metric: string;
610
- range: readonly string[] | readonly number[];
611
- domain?: readonly number[];
612
- mid?: number;
614
+ range: readonly [T, T, T];
615
+ mid: number;
613
616
  } | {
614
617
  kind: 'categorical';
615
618
  /** Field-descriptor form only — a function `by` is omitted upstream. */
616
619
  by: string;
617
- palette?: readonly string[] | readonly number[];
620
+ palette?: readonly T[];
618
621
  domain?: readonly string[];
619
622
  };
623
+ /** Scale subset that is data by construction (no functions). `T` is bound
624
+ * by the styling channel: CSS strings for nodeColor, finite numbers for
625
+ * nodeSize. Tuple arity mirrors the runtime Scale<T> contract exactly. The
626
+ * conditional preserves homogeneous value collections when `T` is a union. */
627
+ type SerializableScale<T extends string | number = string | number> = T extends unknown ? SerializableScaleFor<T> : never;
620
628
  interface ViewStyling {
621
- nodeColor?: SerializableScale;
622
- nodeSize?: SerializableScale;
629
+ nodeColor?: SerializableScale<string>;
630
+ nodeSize?: SerializableScale<number>;
623
631
  showLinks?: boolean;
624
632
  edgeArrows?: boolean;
625
633
  /** Named themes only; a custom GraphTheme object is omitted upstream. */
@@ -630,16 +638,16 @@ interface GraphViewState {
630
638
  camera: ViewportState | null;
631
639
  selection: SelectionState;
632
640
  hiddenNodeIds: readonly NodeId[];
633
- /** §9.2 isolation; null = full scope. */
641
+ /** isolation; null = full scope. */
634
642
  subgraph: SubgraphSpec | null;
635
643
  /** Manual groups verbatim, or — under `groupBy` — `{key, collapsed}` pairs
636
- * only (membership recomputes from current data on restore, R-16.3-16). */
644
+ * only (membership recomputes from current data on restore). */
637
645
  groups: readonly GroupSpec[] | ReadonlyArray<{
638
646
  key: string;
639
647
  collapsed: boolean;
640
648
  }>;
641
649
  pinnedNodeIds: readonly NodeId[];
642
- /** §16.3 node folds: anchor → declared members (v1 extension, see header). */
650
+ /** node folds: anchor → declared members (v1 extension, see header). */
643
651
  folds?: ReadonlyArray<readonly [NodeId, readonly NodeId[]]>;
644
652
  layout: ViewLayoutSpec;
645
653
  /** Declaration order; a key absent here has no brush. */
@@ -653,7 +661,7 @@ interface GraphViewState {
653
661
  positions?: ReadonlyArray<readonly [string, number, number]>;
654
662
  styling?: ViewStyling;
655
663
  /** Host-owned durable source coordinate — stored verbatim, NEVER
656
- * interpreted; compared canonically on restore (§16.14). */
664
+ * interpreted; compared canonically on restore. */
657
665
  dataRef?: JsonValue;
658
666
  }
659
667
  declare const VIEW_STATE_VERSION: 1;
@@ -664,8 +672,8 @@ declare const VIEW_STATE_VERSION: 1;
664
672
  * their canonical strings are identical.
665
673
  */
666
674
  declare function canonicalJson(value: JsonValue | undefined): string | undefined;
667
- /** Canonical equality for dataRef values (§16.14): key order never matters.
668
- * A non-JSON value (cycles included) is never equal to anything — the §5
675
+ /** Canonical equality for dataRef values: key order never matters.
676
+ * A non-JSON value (cycles included) is never equal to anything — the
669
677
  * "compared, never interpreted" rule extended to malformed input. */
670
678
  declare function sameDataRef(a: JsonValue | undefined, b: JsonValue | undefined): boolean;
671
679
  type ViewStateVerdict = {
@@ -677,7 +685,7 @@ type ViewStateVerdict = {
677
685
  problems: readonly string[];
678
686
  };
679
687
  /**
680
- * Full structural validation + version gate. Order per §16.14: version first
688
+ * Full structural validation + version gate. Order per version first
681
689
  * (higher-than-known and non-numeric reject as `unsupported-version` /
682
690
  * `invalid-view-state` BEFORE field checks), then per-field structure. Lower
683
691
  * versions run the migration registry, then re-validate at the current shape.
@@ -693,7 +701,7 @@ type SetViewStateResult = {
693
701
  } | {
694
702
  status: 'rejected';
695
703
  code: 'invalid-view-state' | 'unsupported-version'
696
- /** The state touches a §6.4 controlled slice or carries styling the
704
+ /** The state touches a controlled slice or carries styling the
697
705
  * host must reflect, and no aggregate restore callback exists. */
698
706
  | 'missing-restore-callback'
699
707
  /** Another restore/history transaction is awaiting acknowledgement. */
@@ -706,28 +714,28 @@ type SetViewStateResult = {
706
714
  };
707
715
 
708
716
  /**
709
- * §6 GraphInstance — the public headless core instance (v0.3 subset).
717
+ * GraphInstance — the public headless core instance (v0.3 subset).
710
718
  *
711
719
  * One `applyHostUpdate` call is the atomic host boundary: it validates,
712
720
  * reconciles, re-projects only dirty channels, and publishes EXACTLY ONE store
713
- * `set()` and AT MOST ONE engine commit, so a simultaneous data + style +
714
- * controlled-state change can never tear across frames (§6).
721
+ * `set` and AT MOST ONE engine commit, so a simultaneous data + style +
722
+ * controlled-state change can never tear across frames.
715
723
  *
716
- * Vanilla zustand only — no React, no DOM access at module scope (§18).
724
+ * Vanilla zustand only — no React, no DOM access at module scope.
717
725
  */
718
726
 
719
- /** §8 dark base theme (the default when no base is named). */
727
+ /** dark base theme (the default when no base is named). */
720
728
  declare const GRAPH_THEME_DARK: GraphTheme;
721
- /** §8 light base theme. */
729
+ /** light base theme. */
722
730
  declare const GRAPH_THEME_LIGHT: GraphTheme;
723
731
  /**
724
- * Resolve a ThemeInput to a full GraphTheme (§8): pick the named base
732
+ * Resolve a ThemeInput to a full GraphTheme: pick the named base
725
733
  * (default dark), then merge every defined token over it. A full GraphTheme
726
734
  * input resolves to exactly its own tokens; `undefined` resolves to the dark
727
735
  * base; the v0.1 `{background}` compat shorthand merges as a partial.
728
736
  */
729
737
  declare function resolveTheme(input?: ThemeInput): GraphTheme;
730
- /** One categorical legend row (§11): declared-domain rows first (including
738
+ /** One categorical legend row: declared-domain rows first (including
731
739
  * currently-empty categories), then extra seen values sorted. */
732
740
  interface ScaleInfoRow {
733
741
  value: string;
@@ -745,50 +753,50 @@ interface ScaleChannelInfo<N = Record<string, unknown>> {
745
753
  /** Categorical rows; omitted for sequential/diverging scales. */
746
754
  rows?: readonly ScaleInfoRow[];
747
755
  }
748
- /** §9.2 revision-aware service seam (expansion since v0.5, search since S11). */
756
+ /** Revision-aware service seam for expansion and search. */
749
757
  interface GraphServices<N = Record<string, unknown>, E = Record<string, unknown>> {
750
758
  /**
751
759
  * Ego-expansion resolver for `expandNode` / `SubgraphSpec.hops`. Default:
752
- * the built-in LOCAL service — it walks the core's §7.1 adjacency over the
760
+ * the built-in LOCAL service — it walks the core's adjacency over the
753
761
  * accepted model, INCLUDING currently out-of-scope nodes (zero config,
754
762
  * zero network; the core still never fetches).
755
763
  */
756
764
  expansion?: ExpansionService<N, E>;
757
765
  /**
758
- * §16.2 path resolver for `findPath`. Default: the built-in LOCAL
766
+ * path resolver for `findPath`. Default: the built-in LOCAL
759
767
  * unweighted BFS over the loaded VISIBLE edge list, respecting
760
768
  * PathOptions.direction. Revision-aware: a result arriving after a
761
- * dataset replacement is discarded at admission (S12-T08).
769
+ * dataset replacement is discarded at admission.
762
770
  */
763
771
  path?: PathService;
764
772
  /**
765
- * §16.5 search resolver for `instance.search`. Default: the built-in LOCAL
773
+ * search resolver for `instance.search`. Default: the built-in LOCAL
766
774
  * indexed service over the accepted model plus the host's declared
767
775
  * `searchIndex` fields (id-only when never declared — it never guesses
768
776
  * attr names; zero config, zero network). Custom services plug in
769
- * server-side search (Omnigraph B.7) with the same instance-side
770
- * correctness: RequestContext, revision-keyed caching, supersede
777
+ * server-side search (such as Omnigraph stored queries) with the same
778
+ * instance-side correctness: RequestContext, revision-keyed caching, supersede
771
779
  * cancellation, stale rejection at admission.
772
780
  */
773
781
  search?: SearchService<N>;
774
782
  }
775
783
  interface CreateGraphInstanceOptions<N = Record<string, unknown>, E = Record<string, unknown>> {
776
- /** Called once per mount; a re-attach constructs a fresh engine (§6). */
784
+ /** Called once per mount; a re-attach constructs a fresh engine. */
777
785
  engine: EngineFactory;
778
786
  /** Fit the camera once when the first data-bearing commit reaches a fresh engine. Default true. */
779
787
  fitViewOnFirstData?: boolean;
780
- /** §9.2 revision-aware services (expansion + §16.5 search). */
788
+ /** revision-aware services (expansion + search). */
781
789
  services?: GraphServices<N, E>;
782
790
  /**
783
- * §16.5 node attr fields the DEFAULT search service indexes (ids always;
791
+ * node attr fields the DEFAULT search service indexes (ids always;
784
792
  * absent = id-only — the service never guesses attr names). CONSTRUCTION-
785
- * ONLY per the spec's host construction options (D7): read once here;
793
+ * ONLY as a host construction option: read once here;
786
794
  * changing it requires a keyed remount / replacement instance. A runtime
787
795
  * `applyHostUpdate` attempt is ignored with a one-shot warning.
788
796
  */
789
797
  searchIndex?: readonly string[];
790
798
  /**
791
- * §16.14 undo/redo (S9-T20). Default true. `false` makes the history
799
+ * undo/redo. Default true. `false` makes the history
792
800
  * surface inert (record/undo/redo no-ops, depths stay 0); an object sets
793
801
  * the stack bound (default {@link HISTORY_LIMIT_DEFAULT} entries).
794
802
  */
@@ -796,42 +804,42 @@ interface CreateGraphInstanceOptions<N = Record<string, unknown>, E = Record<str
796
804
  limit?: number;
797
805
  };
798
806
  /**
799
- * §17/§6.1 degradation-ladder thresholds (S13-T08). CONSTRUCTION-ONLY
800
- * (D7): read once; invalid fields fall back to the spec defaults with ONE
807
+ * Degradation-ladder thresholds. CONSTRUCTION-ONLY: read once; invalid
808
+ * fields fall back to the defaults with ONE
801
809
  * config warning diagnostic. A runtime change requires a keyed remount.
802
810
  */
803
811
  limits?: Partial<ScaleLimits>;
804
812
  /**
805
- * §8 image-atlas resolver seam (S10): owns authenticated fetch/caching for
813
+ * Image-atlas resolver seam: owns authenticated fetch/caching for
806
814
  * one `nodeImage` ref. Default: plain `fetch(ref)` for public URLs.
807
815
  * Injectable for tests and authenticated hosts.
808
816
  */
809
817
  imageResolver?: ImageResolver;
810
818
  /**
811
- * §6.1/§17 execution mode (ADR-006 D1; CONSTRUCTION-ONLY, D7). Current
812
- * worker cargo: columnar ACCEPTANCE (validate + dedupe + link resolution
813
- * off-thread; §7.5-style async admission). 'main' (default) keeps every
819
+ * Execution mode. Current worker cargo is columnar ACCEPTANCE: validation,
820
+ * deduplication, and link resolution run off-thread, then land through
821
+ * revision-gated async admission. 'main' (default) keeps every
814
822
  * columnar ingest synchronous; 'auto' and 'worker' route columnar data
815
823
  * through the worker lane when it boots — an unavailable lane degrades
816
824
  * to 'main' with one `worker-unavailable` info diagnostic under 'auto'
817
- * and an ERROR diagnostic under 'worker' (which never silently falls
818
- * back on channel work, but acceptance has no worker-REQUIRED semantics
819
- * yet channel projection cargo is the registered follow-up).
825
+ * and an ERROR diagnostic under 'worker'. Columnar acceptance may still
826
+ * fall back because it has no worker-required mode; channel projection
827
+ * remains on the main thread.
820
828
  */
821
829
  execution?: 'auto' | 'main' | 'worker';
822
- /** ADR-006 D5 worker construction tri-option (URL / factory / inline
830
+ /** Worker construction tri-option (URL / factory / inline
823
831
  * default). Testing seam: `transport` on the lane via this factory. */
824
832
  workerFactory?: WorkerFactoryOption;
825
833
  }
826
834
  /**
827
- * `expandNode` outcome (§9.2/§16.3):
828
- * - `{ added }` — the admitted result merged; `added` counts the nodes it
829
- * made newly visible in the current scope.
830
- * - `{ noop: true }` — every returned neighbor was already visible in the
831
- * current scope (T17); no session was opened, nothing changed.
832
- * - `{ coalesced: true }` — reserved. v0.5 same-id coalescing hands the
833
- * SECOND caller the IDENTICAL in-flight promise, so both callers observe
834
- * the primary call's `{added}`/`{noop}` result instead of this marker.
835
+ * `expandNode` outcome:
836
+ * - `{ added }` — the admitted result merged; `added` counts the nodes it
837
+ * made newly visible in the current scope.
838
+ * - `{ noop: true }` — every returned neighbor was already visible in the
839
+ * current scope; no session was opened and nothing changed.
840
+ * - `{ coalesced: true }` — reserved. v0.5 same-id coalescing hands the
841
+ * SECOND caller the IDENTICAL in-flight promise, so both callers observe
842
+ * the primary call's `{added}`/`{noop}` result instead of this marker.
835
843
  */
836
844
  type ExpandNodeResult = {
837
845
  added: number;
@@ -841,7 +849,7 @@ type ExpandNodeResult = {
841
849
  noop: true;
842
850
  };
843
851
  /**
844
- * §9.2 expansion bookkeeping: one committed expansion overlay. Data-merging
852
+ * expansion bookkeeping: one committed expansion overlay. Data-merging
845
853
  * batches carry the request id (overlayId + batch ids) and provenance into
846
854
  * ingestion so abort, rollback, and removeOverlay remove the exact
847
855
  * contribution they own.
@@ -855,11 +863,11 @@ interface ExpansionOverlayRecord {
855
863
  provenance?: unknown;
856
864
  }
857
865
  /**
858
- * §14 overlay label lane subscriptions. Two channels with distinct cadences:
859
- * - `subscribeCandidates` fires ONLY when the candidate SET (ids/text/forced)
860
- * changes — the throttled re-rank. React re-renders label content here.
861
- * - `subscribePositions` fires on scheduler ticks (host `onFrame`) with fresh
862
- * x/y for the SAME set — imperative transform writes, NO React re-render.
866
+ * overlay label lane subscriptions. Two channels with distinct cadences:
867
+ * - `subscribeCandidates` fires ONLY when the candidate SET (ids/text/forced)
868
+ * changes — the throttled re-rank. React re-renders label content here.
869
+ * - `subscribePositions` fires on scheduler ticks (host `onFrame`) with fresh
870
+ * x/y for the SAME set — imperative transform writes, NO React re-render.
863
871
  * Both replay the current state synchronously on subscribe. The emitted array
864
872
  * and its placement objects are REUSED across position ticks — copy if you
865
873
  * need a snapshot.
@@ -869,20 +877,20 @@ interface LabelSubscriptions {
869
877
  subscribePositions(cb: (list: readonly LabelPlacement[]) => void): () => void;
870
878
  }
871
879
  interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>> {
872
- /** Vanilla zustand store — the single observable state surface (§6.3). */
880
+ /** Vanilla zustand store — the single observable state surface. */
873
881
  readonly store: StoreApi<GraphStoreState>;
874
- /** §14 DOM label lane (overlay scheduler output). */
882
+ /** DOM label lane (overlay scheduler output). */
875
883
  readonly labels: LabelSubscriptions;
876
- /** Atomic host transaction: one store publication, at most one engine commit (§6). */
884
+ /** Atomic host transaction: one store publication, at most one engine commit. */
877
885
  applyHostUpdate(update: GraphHostUpdate<N, E>): void;
878
886
  /**
879
- * §7.5 revisioned ingestion: begin a bounded, cancellable session against an
887
+ * revisioned ingestion: begin a bounded, cancellable session against an
880
888
  * explicit `datasetKey` and `baseModelRevision` (compare-and-set; mismatch
881
889
  * throws 'stale-revision'). Overlay sessions must name the CURRENT
882
890
  * datasetKey; replace sessions may establish a new one and are always
883
891
  * atomic.
884
892
  *
885
- * T16 rule: while a declarative data source is actively driving (a snapshot
893
+ * While a declarative data source is actively driving (a snapshot
886
894
  * was applied through `applyHostUpdate` and has not been superseded by a
887
895
  * committed replace session), `purpose:'replace'` is rejected at begin with
888
896
  * a TypeError — two writers may not race for the base. Overlay ingestion
@@ -890,11 +898,11 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
890
898
  *
891
899
  * Every session admission/publication is serialized through the
892
900
  * instance-local acceptance queue; arrival there is the global admission
893
- * order (§7.5).
901
+ * order.
894
902
  */
895
903
  beginIngest(opts: BeginIngestOptions): IngestSession<N, E>;
896
904
  /**
897
- * §7.5: atomically remove exactly one committed overlay — re-runs collision
905
+ * atomically remove exactly one committed overlay — re-runs collision
898
906
  * and endpoint resolution, promotes formerly shadowed rows from surviving
899
907
  * overlays, advances model/render revisions, and releases the overlayId for
900
908
  * deliberate reuse. Unknown ids are an idempotent `{ removed: false }`.
@@ -902,14 +910,14 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
902
910
  removeOverlay(overlayId: string): {
903
911
  removed: boolean;
904
912
  };
905
- /** Committed overlay ids for the current dataset (§7.5). */
913
+ /** Committed overlay ids for the current dataset. */
906
914
  getOverlayIds(): readonly string[];
907
915
  attach(container: HTMLElement): Promise<void>;
908
916
  detach(): void;
909
917
  destroy(): void;
910
918
  /**
911
- * §15 typed events: listeners run SYNCHRONOUSLY in registration order; the
912
- * control's preventDefault() cancels ONLY the built-in follow-up (click
919
+ * typed events: listeners run SYNCHRONOUSLY in registration order; the
920
+ * control's preventDefault cancels ONLY the built-in follow-up (click
913
921
  * selection, drag pin), never other listeners.
914
922
  */
915
923
  on<K extends GraphEventName>(name: K, cb: (payload: GraphEventMap<N, E>[K], control: GraphListenerControl) => void): () => void;
@@ -918,51 +926,51 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
918
926
  zoomOut(): void;
919
927
  setViewport(v: Partial<ViewportState>): void;
920
928
  /**
921
- * §16 focus neighborhood (T10): keep the v0.1 camera behavior
929
+ * Focus neighborhood: keep the v0.1 camera behavior
922
930
  * (setFocusedIndex + zoomToIndex) and RETURN the 1-hop neighbor ids
923
931
  * (engine adjacency when available, else the core CSR adjacency).
924
932
  *
925
- * Documented compromise: the engine exposes ONE highlight channel until S10
926
- * styling lands, so the neighbor ring is pushed through setSelectedIndices
933
+ * Documented compromise: the engine exposes ONE highlight channel, so the
934
+ * neighbor ring is pushed through setSelectedIndices
927
935
  * ONLY when that cannot lie about real selection state — selection empty
928
936
  * and uncontrolled. The ring is a visual, never a store write; the next
929
937
  * selection push overwrites it. Opt out via `highlightNeighbors: false`.
930
- * `hops` is reserved at 1 until multi-hop lands.
938
+ * Only `hops: 1` is currently supported.
931
939
  */
932
940
  focusNode(id: NodeId, opts?: {
933
941
  highlightNeighbors?: boolean;
934
942
  hops?: 1;
935
943
  }): readonly NodeId[];
936
944
  /**
937
- * §13 emphasis ring WITHOUT the camera: ring `id` (null clears). The light
945
+ * emphasis ring WITHOUT the camera: ring `id` (null clears). The light
938
946
  * op keyboard navigation needs — arrowing a list must not fly the camera on
939
947
  * every keystroke (`focusNode` stays ring + zoom + neighbors). Unknown ids
940
948
  * are a silent no-op (a stale row racing a model swap is data, not an
941
949
  * error); `emphasisRing: false` suppresses it entirely. The target is
942
950
  * STICKY: it survives structural commits and context recovery until it is
943
951
  * cleared, its id departs the model, or pointer hover supersedes it
944
- * (emphasis belongs to the latest action — the §16.2 rule).
952
+ * (emphasis belongs to the latest action — the rule).
945
953
  */
946
954
  emphasizeNode(id: NodeId | null): void;
947
955
  /**
948
- * §14/§15 typed context-menu channel, opened from a DOM presenter. Label
956
+ * Typed context-menu channel, opened from a DOM presenter. Label
949
957
  * divs are `pointerEvents: 'auto'` by design (click-to-focus), so a
950
958
  * right-click on one never reaches the engine canvas — without this seam
951
959
  * the nodes prominent enough to carry labels are exactly the ones whose
952
960
  * right-click falls through to the browser's native menu. Emits the SAME
953
961
  * 'contextMenu' event the canvas gesture produces; `screen` is
954
- * container-relative CSS px (the §15 payload contract). Unknown ids are a
962
+ * container-relative CSS px. Unknown ids are a
955
963
  * silent no-op (a stale label racing a model swap is data, not an error).
956
964
  */
957
965
  requestNodeContextMenu(id: NodeId, screen: readonly [number, number]): void;
958
966
  setSelection(ids: readonly NodeId[] | SelectionState): void;
959
967
  selectNodes(ids: readonly NodeId[]): void;
960
968
  selectEdges(ids: readonly EdgeId[]): void;
961
- /** §16.2 group namespace (S12-T02): validate against the CURRENT resolved
969
+ /** group namespace: validate against the CURRENT resolved
962
970
  * groups (unknown ids dropped, duplicates collapse) and store in
963
971
  * groups-array order — the group analog of accepted-base ordering. Never
964
972
  * touches the node/edge namespaces; the group namespace is always
965
- * instance-owned (§6.4 controlled selection covers nodes only). */
973
+ * instance-owned. */
966
974
  selectGroups(ids: readonly string[]): void;
967
975
  /** Expand to the 1-hop neighborhood of `id` (or of the current selection). */
968
976
  selectNeighbors(id?: NodeId): void;
@@ -970,9 +978,9 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
970
978
  invertSelection(): void;
971
979
  clearSelection(): void;
972
980
  /**
973
- * §16.2 lasso (S6-T05): resolve the SCREEN-coordinate polygon to node ids
981
+ * lasso: resolve the SCREEN-coordinate polygon to node ids
974
982
  * via `engine.pointsInPolygon`, drop hidden ids, then replace (default) or
975
- * union (`additive`) the node selection through the same §6.4 ownership
983
+ * union (`additive`) the node selection through the same ownership
976
984
  * path as every other mutator (controlled → intent only). Returns the
977
985
  * resolved lasso ids (accepted-base order) regardless of ownership; empty
978
986
  * when the engine is not ready or lacks `pointsInPolygon`.
@@ -992,19 +1000,19 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
992
1000
  * tolerance. No-op (null) on the native route. */
993
1001
  sampleEdgeClick(screen: readonly [number, number]): AcceptedEdge<E> | null;
994
1002
  /**
995
- * @internal §15/§17 shared hit-test/overlay cadence: the count of engine
1003
+ * @internal Shared hit-test/overlay cadence: the count of engine
996
1004
  * onFrame ticks this session. THE one clock every sampling route throttles
997
1005
  * against (node hover and link picking share it by construction — there is
998
- * no second cadence timer anywhere; the S13-T06 lint rule enforces it).
999
- * The S13 ladder's defer-link-picking arms/disarms against this counter;
1000
- * §17 telemetry reads it for idle-wakeup accounting.
1006
+ * no second cadence timer anywhere; the lint rule enforces it).
1007
+ * The degradation ladder's defer-link-picking step arms/disarms against this counter;
1008
+ * telemetry reads it for idle-wakeup accounting.
1001
1009
  */
1002
1010
  getFrameCadence(): number;
1003
1011
  /**
1004
- * @internal F10-02 op counters (live object — snapshot before comparing):
1005
- * the perf-gate-delta suite proves the brush fast path does O(Δ) work
1006
- * zero full recomposes/refreshes/cascades across a scrub. §17 telemetry
1007
- * (S13-T07) will fold these into `lastCommitMs`-adjacent accounting.
1012
+ * @internal op counters (live object — snapshot before comparing):
1013
+ * the perf-gate-delta suite proves the brush fast path does O(Δ) work
1014
+ * zero full recomposes/refreshes/cascades across a scrub. telemetry
1015
+ * will fold these into `lastCommitMs`-adjacent accounting.
1008
1016
  */
1009
1017
  getPerfCounters(): Readonly<{
1010
1018
  brushSlotsTranslated: number;
@@ -1014,12 +1022,12 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1014
1022
  fullEdgeRecomposes: number;
1015
1023
  }>;
1016
1024
  /**
1017
- * §17 telemetry snapshot (S13-T07): counts, byte estimates, queue depth,
1025
+ * telemetry snapshot: counts, byte estimates, queue depth,
1018
1026
  * revisions, last-commit phase decomposition, active ladder steps,
1019
1027
  * execution lane, range availability, and the pressure mirror — never raw
1020
1028
  * attrs or ids. Synchronous in every lifecycle state (pre-scene fields
1021
1029
  * read zero/absent). `validate` is folded into `derive` until the
1022
- * columnar lane splits acceptance from derivation (PR-E).
1030
+ * columnar lane splits acceptance from derivation.
1023
1031
  */
1024
1032
  getPerfSnapshot(): GraphPerfSnapshot;
1025
1033
  hideNodes(ids: readonly NodeId[]): void;
@@ -1028,24 +1036,24 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1028
1036
  pinNode(id: NodeId, xy?: readonly [number, number]): void;
1029
1037
  unpinNode(id: NodeId): void;
1030
1038
  clearPins(): void;
1031
- /** §16.3 PERSISTENT pins (S12-T09): pin ids AT THEIR CURRENT POSITION via
1039
+ /** PERSISTENT pins: pin ids AT THEIR CURRENT POSITION via
1032
1040
  * engine.setPinnedIndices — no position payload in v0.10. Independent of
1033
1041
  * transient drag pinning (`pins`): the engine receives the UNION of both
1034
- * slices, so releasing a drag pin leaves a persistent pin held. §6.4
1042
+ * slices, so releasing a drag pin leaves a persistent pin held.
1035
1043
  * ownership mirrors groups: once the host supplies `pinnedNodeIds` (null
1036
1044
  * included) the ops fire the 'pinnedChange' intent instead of writing.
1037
1045
  * Unknown ids drop; departed ids prune through the ownership path on
1038
- * model changes (R-16.3-25). */
1046
+ * model changes. */
1039
1047
  pinNodes(ids: readonly NodeId[]): void;
1040
1048
  /** Release persistent pins (see {@link pinNodes}); unpinned ids no-op. */
1041
1049
  unpinNodes(ids: readonly NodeId[]): void;
1042
- /** Add one group definition (same §16.3 acyclic/singly-parented validation as the
1050
+ /** Add one group definition (same acyclic/singly-parented validation as the
1043
1051
  * `groups` prop — a violating spec is ONE 'config-error' and a no-op). */
1044
1052
  groupNodes(spec: GroupSpec): void;
1045
1053
  /** Remove one group definition; its id prunes from SelectionState.groupIds
1046
1054
  * through the ownership path. Unknown ids no-op (dev-mode warning). */
1047
1055
  ungroup(groupId: string): void;
1048
- /** Collapse/expand one group as a §7.2 structural diff. Works on manual
1056
+ /** Collapse/expand one group as a structural diff. Works on manual
1049
1057
  * groups AND groupBy-derived groups (the residue toggle). Same-value
1050
1058
  * calls are exact no-ops (zero publishes, zero commits). */
1051
1059
  setGroupCollapsed(groupId: string, collapsed: boolean): void;
@@ -1059,12 +1067,12 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1059
1067
  * rejected, since that would close a containment cycle).
1060
1068
  *
1061
1069
  * One publish and at most one structural commit (E1). A no-member fold is
1062
- * an exact no-op. Records a §16.14 'folds' history step.
1070
+ * an exact no-op. Records a 'folds' history step.
1063
1071
  */
1064
1072
  foldNode(id: NodeId, opts?: {
1065
1073
  memberIds?: readonly NodeId[];
1066
1074
  }): void;
1067
- /** Unfolds `id`, returning its members to the scene as a §7.2 structural
1075
+ /** Unfolds `id`, returning its members to the scene as a structural
1068
1076
  * diff. Unknown or unfolded ids are exact no-ops. */
1069
1077
  unfoldNode(id: NodeId): void;
1070
1078
  /** The members `id` currently stands for, or null when it is not folded.
@@ -1075,30 +1083,30 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1075
1083
  } | null;
1076
1084
  /** Current stage-4 clusters over the physical scene: ordered keys, member
1077
1085
  * ids, the force center labels anchor to while hot, and the settled
1078
- * centroid (null until a §7.1 readback or a fixed-layout commit). Empty
1086
+ * centroid (null until a readback or a fixed-layout commit). Empty
1079
1087
  * when no `clusters` spec is active. Clusters synthesize nothing — the
1080
- * scene is byte-identical with and without a spec (R-16.3-17/19). */
1088
+ * scene is byte-identical with and without a spec. */
1081
1089
  getClusters(): readonly ResolvedCluster[];
1082
- /** R-16.3-18: resolve a cluster (by key) to its MEMBER node ids and write
1083
- * them into SelectionState.nodeIds through the standard §6.4 ownership
1090
+ /** resolve a cluster (by key) to its MEMBER node ids and write
1091
+ * them into SelectionState.nodeIds through the standard ownership
1084
1092
  * path — clusters have no id namespace of their own in selection.
1085
1093
  * `additive` unions with the current node selection. Unknown keys no-op. */
1086
1094
  selectCluster(key: string, opts?: {
1087
1095
  additive?: boolean;
1088
1096
  }): void;
1089
1097
  /**
1090
- * §9.2 isolate: hard-scope the graph to the CURRENT node selection
1098
+ * isolate: hard-scope the graph to the CURRENT node selection
1091
1099
  * `subgraph: { seedIds: selection.nodeIds }` through the SAME path as the
1092
1100
  * host-update prop. No-op when nothing is selected. Ownership note (v0.5):
1093
1101
  * `subgraph` is UNCONTROLLED-ONLY — always instance-owned; the prop and
1094
1102
  * this method write the same state, last writer wins.
1095
1103
  */
1096
1104
  isolateSelection(): void;
1097
- /** §9.2: clear the hard scope (`subgraph: null`) — the full accepted model
1098
- * returns with cached positions (§9.4-style identity for kept ids). */
1105
+ /** clear the hard scope (`subgraph: null`) — the full accepted model
1106
+ * returns with cached positions. */
1099
1107
  resetIsolation(): void;
1100
1108
  /**
1101
- * §9.2/§16.3 ego-expansion of `id` (default 1 hop) through the configured
1109
+ * Ego-expansion of `id` (default 1 hop) through the configured
1102
1110
  * ExpansionService. The result is gated by admission (declared revision
1103
1111
  * dependencies + dataset lineage + seed existence — abort is only an
1104
1112
  * optimization) and merges through ONE awaited atomic overlay
@@ -1117,8 +1125,8 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1117
1125
  * Undoes `id`'s own expansions — the navigation Back button, NOT a
1118
1126
  * containment operation. Aborts `id`'s pending expansion AND explicitly
1119
1127
  * removes the overlays its past expansions committed (plus their scope
1120
- * accretion). Committed overlay DATA otherwise persists per §7.5 until
1121
- * removeOverlay / a replacing snapshot; this IS that explicit removal for
1128
+ * accretion). Committed overlay DATA otherwise persists until
1129
+ * `removeOverlay()` or a replacing snapshot; this IS that explicit removal for
1122
1130
  * expansion overlays.
1123
1131
  *
1124
1132
  * On a node that was never expanded from, this does nothing — there is no
@@ -1127,7 +1135,7 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1127
1135
  * different word for navigation history.
1128
1136
  */
1129
1137
  retractExpansion(id: NodeId): void;
1130
- /** §9.2 expansion bookkeeping for `id`: committed overlay records with
1138
+ /** expansion bookkeeping for `id`: committed overlay records with
1131
1139
  * request id, provenance, and the ids each expansion revealed. */
1132
1140
  getExpansionOverlays(id: NodeId): readonly ExpansionOverlayRecord[];
1133
1141
  /**
@@ -1136,21 +1144,21 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1136
1144
  * `serviceCacheKey` over EXACTLY the service's declared revision
1137
1145
  * dimensions ({@link SEARCH_CACHE_LIMIT}-entry LRU; a second call with an
1138
1146
  * equal key while one is in flight coalesces onto the same service call),
1139
- * cancels superseded work (a NEWER query aborts the older in-flight call
1147
+ * cancels superseded work (a NEWER query aborts the older in-flight call
1140
1148
  * the older promise rejects `OrbitOperationError {code:'aborted'}`), and
1141
1149
  * rejects stale results at admission (declared revision drift or dataset
1142
1150
  * lineage change → the same typed 'aborted' rejection with a distinct
1143
1151
  * staleness message; the store is untouched). A successful search
1144
1152
  * publishes `store.search = {query, results}` — `node` populated for
1145
1153
  * in-model ids — in ONE store publication. Search NEVER changes
1146
- * scope/filter semantics and never fetches graph data (§16.5).
1154
+ * scope/filter semantics and never fetches graph data.
1147
1155
  */
1148
1156
  search(query: string, opts?: {
1149
1157
  limit?: number;
1150
1158
  }): Promise<readonly SearchResult<N>[]>;
1151
1159
  /** Clear `store.search` to null (e.g. the <GraphSearch> input emptied). */
1152
1160
  clearSearch(): void;
1153
- /** §16.2 path query + atomic emphasis (S12-T08): resolves via the path
1161
+ /** path query + atomic emphasis: resolves via the path
1154
1162
  * service (local BFS default); null = unreachable (a RESULT). Emphasis is
1155
1163
  * session-local — released by clearPath, any selection mutation, undo/
1156
1164
  * redo, or a scene rebuild; never a history step; never serialized. */
@@ -1158,21 +1166,21 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1158
1166
  clearPath(): void;
1159
1167
  getActivePath(): PathResult | null;
1160
1168
  /**
1161
- * §16.5 result contract (T07): a result id in the current rendered scene
1162
- * AND §9.1 mask-visible is focused (`focusNode`) → `{status:'focused'}`.
1169
+ * Result contract: a result id in the current rendered scene
1170
+ * AND mask-visible is focused (`focusNode`) → `{status:'focused'}`.
1163
1171
  * Otherwise classification ONLY — 'not-loaded' (absent from the accepted
1164
1172
  * model), 'out-of-scope' (in the model but outside the hard scope),
1165
1173
  * 'filtered' (in the scene but mask-hidden). Never mutates scope or
1166
- * filters — the host reacts explicitly (§16.5).
1174
+ * filters — the host reacts explicitly.
1167
1175
  */
1168
1176
  activateSearchResult(result: SearchResult<N>): SearchActivation;
1169
1177
  pauseSimulation(): void;
1170
1178
  resumeSimulation(): void;
1171
1179
  isSimulationRunning(): boolean;
1172
- /** §16.1 screenshot: delegates to the engine; null when unsupported/not ready. */
1180
+ /** screenshot: delegates to the engine; null when unsupported/not ready. */
1173
1181
  captureScreenshot(): Promise<Blob | null>;
1174
1182
  /**
1175
- * §15.1 binding-detected reduced-motion media preference. The EFFECTIVE
1183
+ * binding-detected reduced-motion media preference. The EFFECTIVE
1176
1184
  * value is `accessibility.reducedMotion ?? v` — when reduced, camera
1177
1185
  * durations (fitView/setViewport/focusNode) coerce to 0.
1178
1186
  */
@@ -1180,7 +1188,7 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1180
1188
  /**
1181
1189
  * The crossfilter session facade, or null until the `crossfilter` prop has
1182
1190
  * configured dimensions over an accepted base. Delegates to the
1183
- * typed-column engine; `setBrush` routes visibility deltas into the §9.1
1191
+ * typed-column engine; `setBrush` routes visibility deltas into the
1184
1192
  * soft mask (buffers-only commit, zero relayout) and resolves after the
1185
1193
  * publish. Brush slot deltas are BASE indices; under a hard scope
1186
1194
  * out-of-scope rows have no scene slot and simply do not mask anything.
@@ -1200,12 +1208,12 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1200
1208
  /** Re-apply the most recently undone entry. False when nothing to redo. */
1201
1209
  redo(): boolean;
1202
1210
  /**
1203
- * Serialize the exploration state (§16.14): camera, selection, hidden ids,
1211
+ * Serialize the exploration state: camera, selection, hidden ids,
1204
1212
  * isolation, groups (manual specs verbatim; under `groupBy` only collapsed
1205
1213
  * `{key, collapsed}` pairs — membership recomputes on restore), pins,
1206
1214
  * folds, layout, crossfilter brushes in declaration order, the Scale-valued
1207
1215
  * styling subset, and the host's `dataRef` verbatim. The predicate `filter`
1208
- * and §16.3 expansion records are never serialized. The sync form carries
1216
+ * and expansion records are never serialized. The sync form carries
1209
1217
  * no positions: reproduction is best-effort via the layout descriptor.
1210
1218
  */
1211
1219
  getViewState(opts?: {
@@ -1213,7 +1221,7 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1213
1221
  }): GraphViewState;
1214
1222
  /**
1215
1223
  * Async form: additionally embeds quantized coordinates for the VISIBLE
1216
- * (post-mask) set, read once from the engine (per-event readback, ADR-001).
1224
+ * (post-mask) set, read once from the engine as event-time readback.
1217
1225
  * Restores as a frozen fixed-equivalent — pixel-faithful regardless of
1218
1226
  * engine nondeterminism. Past `maxPositions` (default 100 000) the call
1219
1227
  * rejects `export-materialization-too-large`; persist the layout through
@@ -1224,7 +1232,7 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1224
1232
  maxPositions?: number;
1225
1233
  }): Promise<GraphViewState>;
1226
1234
  /**
1227
- * Atomically restore a serialized view (§16.14). NEVER partially applies:
1235
+ * Atomically restore a serialized view. NEVER partially applies:
1228
1236
  * structural validation and the version gate run first (reject whole with
1229
1237
  * one 'invalid-view-state' diagnostic); then the dataRef canonical
1230
1238
  * comparison — a mismatch fires the 'viewStateMismatch' event INSTEAD of
@@ -1233,7 +1241,7 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1233
1241
  * undo/redo uses, so a restore is itself undoable. Embedded positions
1234
1242
  * apply as a frozen fixed-equivalent (one replay-style commit, then the
1235
1243
  * simulation pauses — a later explicit layout change or reheat unfreezes).
1236
- * A state touching a §6.4 controlled slice (or styling, once a restore
1244
+ * A state touching a controlled slice (or styling, once a restore
1237
1245
  * callback exists) resolves 'missing-restore-callback' until the aggregate
1238
1246
  * protocol is registered.
1239
1247
  */
@@ -1272,14 +1280,14 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1272
1280
  * entity over ONE pinned revision — a mid-stream commit never mixes
1273
1281
  * epochs. Closing the generator releases the pin. */
1274
1282
  exportDataStream(scope?: 'visible' | 'accepted'): AsyncGenerator<string, void, undefined>;
1275
- /** Bounded id → [x, y] map from one position readback (§7.1 per-event). */
1283
+ /** Bounded id → [x, y] map from one position readback. */
1276
1284
  exportLayout(opts?: {
1277
1285
  limit?: number;
1278
1286
  }): Promise<ReadonlyMap<NodeId, readonly [number, number]>>;
1279
1287
  /** Memory-bounded `{"id","x","y"}` JSONL over one pinned readback. */
1280
1288
  exportLayoutStream(): AsyncGenerator<string, void, undefined>;
1281
1289
  /**
1282
- * §11 legend surface: the active Scale on a styling channel plus its
1290
+ * legend surface: the active Scale on a styling channel plus its
1283
1291
  * resolved domain (sequential/diverging — resolved through the SAME frozen
1284
1292
  * DomainStore coordinate the projection uses) or categorical legend rows
1285
1293
  * (declared-domain order first including empty categories, then extra seen
@@ -1288,9 +1296,9 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1288
1296
  */
1289
1297
  getScaleInfo(channel: 'nodeColor' | 'nodeSize'): ScaleChannelInfo<N> | null;
1290
1298
  /**
1291
- * §12 metric read for one node id via the core id→index map (never a
1292
- * public million-entry Map). Null for unknown ids/metrics and §8-null
1293
- * values; lazily computes the degree family on first use.
1299
+ * metric read for one node id via the core id→index map (never a
1300
+ * public million-entry Map). Null for unknown ids, unknown metrics, and
1301
+ * null values; lazily computes the degree family on first use.
1294
1302
  */
1295
1303
  getMetricValue(metric: MetricName, id: NodeId): number | null;
1296
1304
  getRevisions(): Revisions;
@@ -1300,54 +1308,54 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1300
1308
  * way a hover/selection consumer resolves `store.hover.edgeId` or
1301
1309
  * `selection.edgeIds` to real records. Undefined for unknown ids. */
1302
1310
  getEdge(id: EdgeId): AcceptedEdge<E> | undefined;
1303
- /** Scene ids that are §9.1 mask-visible (scope ∧ mask), scene order. */
1311
+ /** Scene ids that are mask-visible (scope ∧ mask), scene order. */
1304
1312
  getVisibleNodeIds(): readonly NodeId[];
1305
- /** Scene roster: scope applied, mask NOT applied — the §15.1 navigator's
1313
+ /** Scene roster: scope applied, mask NOT applied — the navigator's
1306
1314
  * entry list, which must still LIST masked/hidden nodes and expose their
1307
1315
  * state in text rather than dropping them. */
1308
1316
  getSceneNodeIds(): readonly NodeId[];
1309
- /** §15.1 accessibility config stash (navigator/live-region consumers). */
1317
+ /** accessibility config stash (navigator/live-region consumers). */
1310
1318
  getAccessibility(): AccessibilityConfig<N> | undefined;
1311
1319
  }
1312
- /** §16.14: consecutive same-dimension brush moves within this window merge
1320
+ /** consecutive same-dimension brush moves within this window merge
1313
1321
  * into one history entry (scrub/drag coalescing). */
1314
1322
  declare const BRUSH_HISTORY_COALESCE_MS = 500;
1315
- /** §16.6 timeline defaults (S9-T10). */
1323
+ /** timeline defaults. */
1316
1324
  declare const TIMELINE_TICK_MS_DEFAULT = 100;
1317
1325
  declare const TIMELINE_STEP_DEFAULT = 0.01;
1318
- /** §16.5 search defaults (S11-T06). */
1326
+ /** search defaults. */
1319
1327
  declare const SEARCH_LIMIT_DEFAULT = 20;
1320
1328
  declare const SEARCH_CACHE_LIMIT = 32;
1321
1329
  declare function createGraphInstance<N = Record<string, unknown>, E = Record<string, unknown>>(opts: CreateGraphInstanceOptions<N, E>): GraphInstance<N, E>;
1322
1330
 
1323
1331
  /**
1324
- * §14 DOM label lane — pure candidate selection (S7-T01/T16).
1332
+ * DOM label lane — pure candidate selection.
1325
1333
  *
1326
1334
  * `selectLabelCandidates` is a pure, deterministic ranking function: no engine,
1327
1335
  * no DOM, no store. The instance-side overlay scheduler calls it on THROTTLED
1328
- * re-rank triggers only (viewport idle, model change, config change, settle)
1336
+ * re-rank triggers only (viewport idle, model change, config change, settle)
1329
1337
  * NEVER per frame. Positions are the reconciler's CPU cache (space coords);
1330
1338
  * per-frame work elsewhere is a pure O(k) projection of the winners.
1331
1339
  *
1332
- * Selection rules (§14):
1333
- * - Zoom-LOD: below `minZoom` the lane is empty EXCEPT `showFor` ids, which
1334
- * bypass the zoom gate but stay viewport-culled.
1335
- * - `showFor` claims capacity FIRST in accepted-base order. When the
1336
- * in-viewport `showFor` set alone exceeds capacity k, accepted-base order
1337
- * wins deterministically and `overloadCount` reports the omissions (one
1338
- * `label-overload` diagnostic upstream — no winner churn).
1339
- * - Remaining capacity fills with viewport-visible nodes ranked by
1340
- * `getWeight` (else degree), ties broken by accepted-base order.
1341
- * - Visibility comes from the engine's `pointsInRect` when available, else a
1342
- * CPU cull of cached positions through the viewport transform. Nodes with
1343
- * unknown (NaN) cached positions are unplaceable on the CPU path.
1340
+ * Selection rules:
1341
+ * - Zoom-LOD: below `minZoom` the lane is empty EXCEPT `showFor` ids, which
1342
+ * bypass the zoom gate but stay viewport-culled.
1343
+ * - `showFor` claims capacity FIRST in accepted-base order. When the
1344
+ * in-viewport `showFor` set alone exceeds capacity k, accepted-base order
1345
+ * wins deterministically and `overloadCount` reports the omissions (one
1346
+ * `label-overload` diagnostic upstream — no winner churn).
1347
+ * - Remaining capacity fills with viewport-visible nodes ranked by
1348
+ * `getWeight` (else degree), ties broken by accepted-base order.
1349
+ * - Visibility comes from the engine's `pointsInRect` when available, else a
1350
+ * CPU cull of cached positions through the viewport transform. Nodes with
1351
+ * unknown (NaN) cached positions are unplaceable on the CPU path.
1344
1352
  */
1345
1353
 
1346
1354
  /** A capacity winner before per-frame projection assigns screen coordinates. */
1347
1355
  type LabelCandidate = Omit<LabelPlacement, 'x' | 'y'>;
1348
- /** §14 default ranked-candidate cap. */
1356
+ /** default ranked-candidate cap. */
1349
1357
  declare const LABEL_MAX_VISIBLE_DEFAULT = 64;
1350
- /** §14 policy maximum for `maxVisible`. */
1358
+ /** policy maximum for `maxVisible`. */
1351
1359
  declare const LABEL_MAX_VISIBLE_CAP = 1024;
1352
1360
  interface LabelCandidateViewport {
1353
1361
  zoom: number;
@@ -1360,7 +1368,7 @@ interface SelectLabelCandidatesArgs<N = Record<string, unknown>> {
1360
1368
  scene: RenderScene;
1361
1369
  /**
1362
1370
  * Accepted nodes in accepted-base order. Under the 'rebuild' index policy
1363
- * (§7.3) scene index i IS accepted-base position i, so `nodes[i]` is the
1371
+ * scene index i IS accepted-base position i, so `nodes[i]` is the
1364
1372
  * node behind `scene.idByIndex[i]`.
1365
1373
  */
1366
1374
  nodes: readonly GraphNode<N>[];
@@ -1385,11 +1393,11 @@ interface LabelCandidateResult {
1385
1393
  declare function selectLabelCandidates<N = Record<string, unknown>>(args: SelectLabelCandidatesArgs<N>): LabelCandidateResult;
1386
1394
 
1387
1395
  /**
1388
- * §7.1/§13 CSR adjacency over columnar link buffers.
1396
+ * CSR adjacency over columnar link buffers.
1389
1397
  *
1390
- * Pure, engine-free helpers shared by local expansion (§9.2), incident-edge
1391
- * dirtying (§9.1), and the engine-facing `neighborIndices` interaction helper
1392
- * (§13). Build is O(L) via two counting passes over the flat
1398
+ * Pure, engine-free helpers shared by local expansion, incident-edge
1399
+ * dirtying, and the engine-facing `neighborIndices` interaction helper.
1400
+ * Build is O(L) via two counting passes over the flat
1393
1401
  * `[src0, tgt0, src1, tgt1, …]` link buffer — no comparison sort and no
1394
1402
  * per-link allocation (the only allocations are the CSR arrays plus one
1395
1403
  * point-sized cursor array).
@@ -1420,9 +1428,9 @@ declare function buildAdjacency(links: Uint32Array, pointCount: number): Adjacen
1420
1428
  */
1421
1429
  declare function neighborsOf(adj: Adjacency, index: number): Uint32Array;
1422
1430
  /**
1423
- * CSR INCIDENCE: point → incident EDGE SLOTS (F10-02). The plain Adjacency
1431
+ * CSR INCIDENCE: point → incident EDGE SLOTS. The plain Adjacency
1424
1432
  * stores neighbor points, which cannot drive incident-edge dirtying — the
1425
- * §9.1 delta cascade needs the edge slots themselves. Same two counting
1433
+ * delta cascade needs the edge slots themselves. Same two counting
1426
1434
  * passes and the same conventions: undirected (each edge listed under both
1427
1435
  * endpoints), parallel edges repeat, and a self-loop lists its edge slot
1428
1436
  * twice under its point — consumers' per-edge operations are idempotent, so
@@ -1437,26 +1445,26 @@ interface Incidence {
1437
1445
  }
1438
1446
 
1439
1447
  /**
1440
- * §13/§15 CPU link-pick fallback: a uniform grid over ALL links in SPACE
1448
+ * CPU link-pick fallback: a uniform grid over ALL links in SPACE
1441
1449
  * coordinates (cell ≈ median link length), used when the engine lacks native
1442
1450
  * `linkAt` (`capabilities.linkPicking === false`). Backs
1443
- * `onEdgeClick`/`onEdgeHover` via the §7.4 index→edge mapping.
1451
+ * `onEdgeClick`/`onEdgeHover` via the index→edge mapping.
1444
1452
  *
1445
1453
  * Coordinate contract: everything here is SPACE coordinates. Callers invert
1446
1454
  * the affine `Viewport` (space = (screen − center)/zoom + [x, y]) and pass a
1447
1455
  * space-unit tolerance (`tolerancePx / zoom`).
1448
1456
  *
1449
1457
  * Invalidation contract (normative — wave 2 enforces arming):
1450
- * - The grid indexes a POSITION SNAPSHOT (the §7.1 `posBuf` CPU mirror as of
1451
- * the build call). It NEVER observes live simulation positions: while the
1452
- * simulation is hot (alpha above threshold) or an animated `setLayout()`
1453
- * transition runs, picking is DISARMED by the caller; on settle one
1454
- * per-event `getPositions` refreshes the mirror and the grid is rebuilt.
1458
+ * - The grid indexes a POSITION SNAPSHOT (the `posBuf` CPU mirror as of
1459
+ * the build call). It NEVER observes live simulation positions: while the
1460
+ * simulation is hot (alpha above threshold) or an animated `setLayout`
1461
+ * transition runs, picking is DISARMED by the caller; on settle one
1462
+ * per-event `getPositions` refreshes the mirror and the grid is rebuilt.
1455
1463
  * - Rebuild ONLY on structural change (link buffer changed) or position
1456
- * sync. The grid is invariant under camera moves and visibility-mask
1457
- * changes: the §9.1 mask is applied per candidate at QUERY time via the
1458
- * optional `visible` callback (pure pass-through until S9 wires the real
1459
- * mask through it).
1464
+ * sync. The grid is invariant under camera moves and visibility-mask
1465
+ * changes: the mask is applied per candidate at QUERY time via the
1466
+ * optional `visible` callback (pure pass-through until mask wiring supplies the real
1467
+ * mask through it).
1460
1468
  *
1461
1469
  * Build uses two counting-sort passes into CSR grid arrays (`cellOffsets`,
1462
1470
  * `cellLinkIds`). Each segment is inserted with a supercover grid traversal,
@@ -1464,11 +1472,11 @@ interface Incidence {
1464
1472
  * every cell in its O(cols * rows) axis-aligned bounding box. There is no
1465
1473
  * comparison sort or per-link allocation beyond the CSR arrays (plus
1466
1474
  * O(cells) cursor and O(links) query stamps). Links with a non-finite endpoint
1467
- * (NaN-tombstoned points, §13) are excluded and can never be returned. A hard
1475
+ * (NaN-tombstoned points) are excluded and can never be returned. A hard
1468
1476
  * CSR-entry cap deterministically degrades pathological builds to exact O(L)
1469
1477
  * query scans with no cell-link payload.
1470
1478
  */
1471
- /** §9.1 visibility mask applied per candidate at query time. */
1479
+ /** visibility mask applied per candidate at query time. */
1472
1480
  type LinkVisibilityMask = (linkIndex: number) => boolean;
1473
1481
  /**
1474
1482
  * Read-only view of the built grid (diagnostics/tests). The typed arrays are
@@ -1514,8 +1522,8 @@ declare class LinkPickIndex {
1514
1522
  */
1515
1523
  build(positions: Float32Array, links: Uint32Array): void;
1516
1524
  /**
1517
- * Incremental build: yields whenever `now() − sliceStart ≥ budgetMs` so a
1518
- * scheduler can spread the work across idle frames (§17 long-task budget).
1525
+ * Incremental build: yields whenever `now − sliceStart ≥ budgetMs` so a
1526
+ * scheduler can spread the work across idle frames.
1519
1527
  * Pure generator — no rAF/timers here; the caller owns scheduling.
1520
1528
  *
1521
1529
  * The previous grid stays armed and queryable until the new one commits on
@@ -1528,7 +1536,7 @@ declare class LinkPickIndex {
1528
1536
  * Nearest link within `tolerance` (space units) of the space point
1529
1537
  * `(x, y)`, or null. Scans the candidate cells covering the tolerance
1530
1538
  * disc's bounding box (typically the 3×3 neighborhood; more when the
1531
- * tolerance exceeds the cell size), applies the optional §9.1 visibility
1539
+ * tolerance exceeds the cell size), applies the optional visibility
1532
1540
  * mask per candidate, then runs the exact point→segment distance test.
1533
1541
  * Nearest wins; exact-distance ties break toward the LOWER link index.
1534
1542
  * Returns null while unbuilt/invalidated (picking disarmed).
@@ -1537,45 +1545,45 @@ declare class LinkPickIndex {
1537
1545
  }
1538
1546
 
1539
1547
  /**
1540
- * §13/§15 edge-picking facade (S6-T07).
1548
+ * Edge-picking facade.
1541
1549
  *
1542
1550
  * The core commits to ONE route per mount session, read from
1543
1551
  * `engine.capabilities.linkPicking` at engine-ready time — never method
1544
1552
  * sniffing, and never re-evaluated (a capability record mutated after ready
1545
1553
  * changes nothing):
1546
1554
  *
1547
- * - 'native': the adapter delivers `onLinkClick`/`onLinkHover` host events
1548
- * itself; the facade is inert (arm/disarm/queries no-op and
1549
- * `pickLinkAt` returns null) and the instance maps link indices
1550
- * to typed edges straight off the host events.
1551
- * - 'fallback': the instance samples the pointer on the shared §15 throttle
1552
- * cadence and resolves hits through a `LinkPickIndex` uniform
1553
- * grid that is armed ONLY while the simulation is settled.
1554
- *
1555
- * Arming protocol (fallback route; §13):
1556
- * - `arm(positions, links)` runs on simulation settle (fed by one per-event
1557
- * `getPositions` readback) and on structural commits that do NOT restart
1558
- * the simulation (fixed layout). The grid builds CHUNKED via
1559
- * `LinkPickIndex.buildChunked` under a per-slice time budget so large link
1560
- * sets never block (§17); small builds complete synchronously in the first
1561
- * slice. While an initial build is in flight queries return null; a
1562
- * position-sync REBUILD keeps answering from the previous grid until the
1563
- * new one commits.
1564
- * - `disarm()` runs on any commit that restarts the simulation: targets are
1565
- * moving and the position mirror is stale, so queries return null until
1566
- * the next settle re-arms.
1567
- * - Rebuilds happen ONLY on structural change or position sync — the grid is
1568
- * invariant under camera moves and mask changes (the §9.1 visibility mask
1569
- * is applied per candidate at query time; pass-through stub until S9).
1570
- *
1571
- * Tolerance (§13): a query converts screen px to space units via
1555
+ * - 'native': the adapter delivers `onLinkClick`/`onLinkHover` host events
1556
+ * itself; the facade is inert (arm/disarm/queries no-op and
1557
+ * `pickLinkAt` returns null) and the instance maps link indices
1558
+ * to typed edges straight off the host events.
1559
+ * - 'fallback': the instance samples the pointer on the shared throttle
1560
+ * cadence and resolves hits through a `LinkPickIndex` uniform
1561
+ * grid that is armed ONLY while the simulation is settled.
1562
+ *
1563
+ * Arming protocol for the fallback route:
1564
+ * - `arm(positions, links)` runs on simulation settle (fed by one per-event
1565
+ * `getPositions` readback) and on structural commits that do NOT restart
1566
+ * the simulation (fixed layout). The grid builds CHUNKED via
1567
+ * `LinkPickIndex.buildChunked` under a per-slice time budget so large link
1568
+ * sets never block; small builds complete synchronously in the first
1569
+ * slice. While an initial build is in flight queries return null; a
1570
+ * position-sync REBUILD keeps answering from the previous grid until the
1571
+ * new one commits.
1572
+ * - `disarm` runs on any commit that restarts the simulation: targets are
1573
+ * moving and the position mirror is stale, so queries return null until
1574
+ * the next settle re-arms.
1575
+ * - Rebuilds happen ONLY on structural change or position sync — the grid is
1576
+ * invariant under camera moves and mask changes (the visibility mask
1577
+ * is applied per candidate at query time; initially a pass-through stub).
1578
+ *
1579
+ * Tolerance: a query converts screen px to space units via
1572
1580
  * `screenToSpace` of two points `EDGE_PICK_TOLERANCE_PX` apart, then uses
1573
1581
  * `max(4px, half the median link width)` scaled by that factor.
1574
1582
  */
1575
1583
 
1576
1584
  type EdgePickRoute = 'native' | 'fallback';
1577
1585
  /** Screen-space pick tolerance floor, and the probe distance used to measure
1578
- * the screen→space scale (§13). */
1586
+ * the screen→space scale. */
1579
1587
  declare const EDGE_PICK_TOLERANCE_PX = 4;
1580
1588
  /**
1581
1589
  * Median link width in px from a projected linkWidth buffer (deterministic
@@ -1588,9 +1596,9 @@ interface EdgePickingFacadeOptions {
1588
1596
  route: EdgePickRoute;
1589
1597
  /** Affine screen→space conversion; null = conversion unavailable. */
1590
1598
  screenToSpace: (p: readonly [number, number]) => readonly [number, number] | null;
1591
- /** Median link width in px for the tolerance floor; default () => 0. */
1599
+ /** Median link width in px for the tolerance floor; default => 0. */
1592
1600
  medianLinkWidthPx?: () => number;
1593
- /** §9.1 visibility mask pass-through stub (mutable via the setter). */
1601
+ /** visibility mask pass-through stub (mutable via the setter). */
1594
1602
  linkVisible?: LinkVisibilityMask;
1595
1603
  /** Chunked-build slice budget in ms. */
1596
1604
  buildBudgetMs?: number;
@@ -1622,7 +1630,7 @@ declare class EdgePickingFacade {
1622
1630
  arm(positions: Float32Array, links: Uint32Array): void;
1623
1631
  /** Simulation went hot: drop the grid; queries null until the next settle. */
1624
1632
  disarm(): void;
1625
- /** §9.1 mask pass-through stub: applied per candidate at query time. */
1633
+ /** mask pass-through stub: applied per candidate at query time. */
1626
1634
  setLinkVisibilityMask(mask: LinkVisibilityMask | null): void;
1627
1635
  /**
1628
1636
  * Nearest link index within tolerance of a SCREEN point, or null when: on
@@ -1646,8 +1654,8 @@ declare class EdgePickingFacade {
1646
1654
  type EdgePairCounters = Map<NodeId, Map<NodeId, number>>;
1647
1655
 
1648
1656
  /**
1649
- * §7.5 revisioned ingestion — pure session/overlay bookkeeping plus the
1650
- * instance-local acceptance queue (S8-T01..T07).
1657
+ * revisioned ingestion — pure session/overlay bookkeeping plus the
1658
+ * instance-local acceptance queue.
1651
1659
  *
1652
1660
  * Everything here is data-structure work: no store, no engine, no DOM. The
1653
1661
  * GraphInstance wires these helpers into its publication path (instance.ts).
@@ -1655,7 +1663,7 @@ type EdgePairCounters = Map<NodeId, Map<NodeId, number>>;
1655
1663
  * Ordering model: every admission takes a monotonically increasing ticket from
1656
1664
  * the instance's AcceptanceQueue. Overlay rows are stamped with their
1657
1665
  * admission ticket, and the merge folds base + overlays strictly in ticket
1658
- * order — arrival at the queue IS the global admission order (§7.5).
1666
+ * order — arrival at the queue IS the global admission order.
1659
1667
  */
1660
1668
 
1661
1669
  /** Byte backpressure budget default: 8 MiB of admitted-but-unflushed payload. */
@@ -1687,7 +1695,7 @@ interface RowTally {
1687
1695
  count: number;
1688
1696
  samples: string[];
1689
1697
  }
1690
- /** Per-session staging tallies; surfaced as diagnostics ONLY at commit (§7.5). */
1698
+ /** Per-session staging tallies; surfaced as diagnostics ONLY at commit. */
1691
1699
  interface StagingTallies {
1692
1700
  invalidNodes: RowTally;
1693
1701
  duplicateNodes: RowTally;
@@ -1712,11 +1720,11 @@ interface SessionContribution<N = Record<string, unknown>, E = Record<string, un
1712
1720
  readonly edges: StampedEdge<E>[];
1713
1721
  readonly nodeIds: Set<NodeId>;
1714
1722
  readonly edgeIds: Set<string>;
1715
- /** Exact ordered endpoint tuple → next synthesized-parallel-edge k (§5). */
1723
+ /** Exact ordered endpoint tuple → next synthesized-parallel-edge k. */
1716
1724
  readonly pairCounters: EdgePairCounters;
1717
1725
  /** Public prefix lengths: rows before these counts have been published
1718
1726
  * (progressive flush / commit); appends only grow the arrays, so a prefix
1719
- * is sufficient. Atomic sessions stay at 0 until commit (§7.5). */
1727
+ * is sufficient. Atomic sessions stay at 0 until commit. */
1720
1728
  publicNodeCount: number;
1721
1729
  publicEdgeCount: number;
1722
1730
  }
@@ -1728,8 +1736,8 @@ interface StageResult {
1728
1736
  /**
1729
1737
  * Validate and stage one batch's rows into a session contribution.
1730
1738
  *
1731
- * §5.1-equivalent row validation WITHOUT endpoint checks — edges may arrive
1732
- * before nodes (§7.5): they occupy their eventual edge records here; endpoint
1739
+ * Object-lane-equivalent row validation WITHOUT endpoint checks — edges may arrive
1740
+ * before nodes: they occupy their eventual edge records here; endpoint
1733
1741
  * resolution happens at merge. Within a session, duplicate ids are
1734
1742
  * first-wins-dropped (tallied for commit diagnostics); cross-session
1735
1743
  * collisions are the merge's shadowing concern, not staging's.
@@ -1745,7 +1753,7 @@ interface MergeBase<N = Record<string, unknown>, E = Record<string, unknown>> {
1745
1753
  /** Endpoint-resolved base edges. */
1746
1754
  edges: readonly AcceptedEdge<E>[];
1747
1755
  /** Replace-session bases retain edge records whose endpoints were missing
1748
- * at commit; a later overlay node can still resolve them (§7.5). */
1756
+ * at commit; a later overlay node can still resolve them. */
1749
1757
  pendingEdges: readonly StampedEdge<E>[];
1750
1758
  diagnostics: readonly GraphDiagnostic[];
1751
1759
  }
@@ -1761,7 +1769,7 @@ interface MergeResult<N = Record<string, unknown>, E = Record<string, unknown>>
1761
1769
  duplicateEdgeSamples: readonly string[];
1762
1770
  /** overlayId (or BASE_PENDING_KEY) → edges still awaiting an endpoint. The
1763
1771
  * pending-endpoint index: these occupy edge records but never enter the
1764
- * engine link buffer (§7.5). */
1772
+ * engine link buffer. */
1765
1773
  pendingBySource: ReadonlyMap<string, number>;
1766
1774
  pendingEdgeCount: number;
1767
1775
  }
@@ -1776,15 +1784,15 @@ declare function baseFromContribution<N, E>(datasetKey: string, sourceRevision:
1776
1784
  * Merge the accepted base with every overlay contribution's PUBLIC rows.
1777
1785
  *
1778
1786
  * - Node collisions: earliest admission (ticket order; base first) wins.
1779
- * Later rows stay retained-but-shadowed in their contribution and are
1780
- * tallied for the single count-aggregated 'overlay-node-shadowed' info
1781
- * diagnostic (§7.5).
1787
+ * Later rows stay retained-but-shadowed in their contribution and are
1788
+ * tallied for the single count-aggregated 'overlay-node-shadowed' info
1789
+ * diagnostic.
1782
1790
  * - Edge ids: first admission wins; later same-id records are dropped
1783
- * (tallied). An edge whose endpoints are not all present in the merged
1784
- * node set is pending — it occupies its record and the pending-endpoint
1785
- * accounting but is excluded from `accepted.edges` (and therefore from the
1786
- * engine link buffer). Endpoints arriving later resolve it on the next
1787
- * merge (same or different batch/overlay).
1791
+ * (tallied). An edge whose endpoints are not all present in the merged
1792
+ * node set is pending — it occupies its record and the pending-endpoint
1793
+ * accounting but is excluded from `accepted.edges` (and therefore from the
1794
+ * engine link buffer). Endpoints arriving later resolve it on the next
1795
+ * merge (same or different batch/overlay).
1788
1796
  *
1789
1797
  * Deterministic: output depends only on the base and the stamped rows.
1790
1798
  */
@@ -1793,20 +1801,20 @@ declare function mergeModel<N, E>(base: MergeBase<N, E>, overlays: readonly Sess
1793
1801
  declare function mergeDiagnostics(merge: MergeResult<unknown, unknown>): GraphDiagnostic[];
1794
1802
  /**
1795
1803
  * Commit-time diagnostics for one session: staging tallies plus the dangling
1796
- * (still-pending-endpoint) count — emitted ONLY at session commit (§7.5).
1804
+ * (still-pending-endpoint) count — emitted ONLY at session commit.
1797
1805
  */
1798
1806
  declare function sessionCommitDiagnostics(tallies: StagingTallies, danglingCount: number, danglingSamples?: readonly string[]): GraphDiagnostic[];
1799
1807
 
1800
1808
  /**
1801
- * §9.2 hard subgraph scope — pure resolution over the accepted base.
1809
+ * hard subgraph scope — pure resolution over the accepted base.
1802
1810
  *
1803
1811
  * `resolveScope` turns a `SubgraphSpec` into the exact node/edge subset the
1804
1812
  * reconciler should be fed: seeds validated against the accepted base
1805
1813
  * (unknown ids dropped, duplicates collapsed), optional `hops` expansion via
1806
- * BFS over the §7.1 CSR adjacency of the ACCEPTED BASE (not the scene — the
1807
- * default expansion service walks this same index, §9.2), and edges cascaded
1808
- * through `cascadeEdges`, the single §9 edge-survival primitive (an edge
1809
- * survives iff BOTH endpoints survive) that S9's soft masks reuse.
1814
+ * BFS over the CSR adjacency of the ACCEPTED BASE (not the scene — the
1815
+ * default expansion service walks this same index), and edges cascaded
1816
+ * through `cascadeEdges`, the single edge-survival primitive (an edge
1817
+ * survives iff BOTH endpoints survive) that soft masks reuse.
1810
1818
  *
1811
1819
  * Everything here is synchronous and engine-free. The async
1812
1820
  * `ExpansionService` seam (./services) exists for `expandNode`; `hops`
@@ -1814,21 +1822,21 @@ declare function sessionCommitDiagnostics(tallies: StagingTallies, danglingCount
1814
1822
  */
1815
1823
 
1816
1824
  /**
1817
- * THE edge-cascade primitive (§9): an edge survives iff BOTH of its
1825
+ * THE edge-cascade primitive: an edge survives iff BOTH of its
1818
1826
  * endpoints survive. O(E); the only allocation is the output array, which
1819
1827
  * holds references to the input edge objects (never copies).
1820
1828
  *
1821
- * Exported for reuse by §9.1 soft masks (S9) and any other subset producer.
1829
+ * Exported for reuse by soft masks and any other subset producer.
1822
1830
  */
1823
1831
  declare function cascadeEdges<E>(edges: readonly AcceptedEdge<E>[], survives: (id: NodeId) => boolean): AcceptedEdge<E>[];
1824
1832
  /**
1825
- * Builds the §7.1 CSR adjacency of an accepted base: endpoints are positions
1833
+ * Builds the CSR adjacency of an accepted base: endpoints are positions
1826
1834
  * in `accepted.nodes` (accepted-base order). Every accepted edge has resolved
1827
- * endpoints by contract (§5.1 drops dangling edges), so this cannot throw on
1835
+ * endpoints by contract, so this cannot throw on
1828
1836
  * a well-formed `AcceptedGraph`.
1829
1837
  */
1830
1838
  declare function buildAcceptedAdjacency(accepted: AcceptedGraph<unknown, unknown>): Adjacency;
1831
- /** Output of `resolveScope`: the exact subset to feed the reconciler (§9.2). */
1839
+ /** Output of `resolveScope`: the exact subset to feed the reconciler. */
1832
1840
  interface ResolvedScope<N = Record<string, unknown>, E = Record<string, unknown>> {
1833
1841
  /** Surviving node ids (seeds + hop expansion), membership-query form. */
1834
1842
  nodeIds: ReadonlySet<NodeId>;
@@ -1838,31 +1846,31 @@ interface ResolvedScope<N = Record<string, unknown>, E = Record<string, unknown>
1838
1846
  edges: readonly AcceptedEdge<E>[];
1839
1847
  }
1840
1848
  /**
1841
- * Resolves a hard-scope spec against the accepted base (§9.2).
1849
+ * Resolves a hard-scope spec against the accepted base.
1842
1850
  *
1843
1851
  * - `spec.seedIds` are validated against `accepted.nodeIndex`: ids unknown to
1844
- * the accepted base are dropped, duplicates collapse to one seed.
1852
+ * the accepted base are dropped, duplicates collapse to one seed.
1845
1853
  * - `spec.hops` (default 0; negative/non-finite values clamp to 0, fractions
1846
- * floor) expands the survivor set by BFS over the accepted-base adjacency.
1847
- * This is the synchronous local path — the §9.2 default `ExpansionService`
1848
- * walks the same index for `expandNode`.
1854
+ * floor) expands the survivor set by BFS over the accepted-base adjacency.
1855
+ * This is the synchronous local path — the default `ExpansionService`
1856
+ * walks the same index for `expandNode`.
1849
1857
  * - `adjacency` may be a caller-cached `buildAcceptedAdjacency(accepted)`
1850
- * result; pass `null` to have one built on demand (only when `hops > 0`
1851
- * and there are surviving seeds — hop-0 resolution never builds it).
1858
+ * result; pass `null` to have one built on demand (only when `hops > 0`
1859
+ * and there are surviving seeds — hop-0 resolution never builds it).
1852
1860
  * - Output preserves accepted-base order for both nodes and edges; edges are
1853
- * cascaded through {@link cascadeEdges}.
1861
+ * cascaded through {@link cascadeEdges}.
1854
1862
  */
1855
1863
  declare function resolveScope<N, E>(accepted: AcceptedGraph<N, E>, spec: SubgraphSpec, adjacency: Adjacency | null): ResolvedScope<N, E>;
1856
1864
 
1857
1865
  /**
1858
- * §9.2 revision-aware services — pure sequencing/admission/caching helpers
1866
+ * revision-aware services — pure sequencing/admission/caching helpers
1859
1867
  * plus the built-in local expansion service.
1860
1868
  *
1861
1869
  * The correctness gate is `admitServiceResult`: a result is admitted only if
1862
1870
  * every revision dimension the service DECLARED is unchanged since the call
1863
1871
  * was issued; undeclared dimensions never invalidate (so e.g. the local
1864
1872
  * expansion service, declaring only 'source', survives unrelated model/scope
1865
- * advances from other overlay publications). Abort is an optimization
1873
+ * advances from other overlay publications). Abort is an optimization
1866
1874
  * admission is the gate.
1867
1875
  *
1868
1876
  * Cache keys include service identity, canonical-JSON request parameters,
@@ -1872,7 +1880,7 @@ declare function resolveScope<N, E>(accepted: AcceptedGraph<N, E>, spec: Subgrap
1872
1880
  * these primitives to its acceptance queue.
1873
1881
  */
1874
1882
 
1875
- /** Current value of each §9.2 revision dimension (a Revisions subset). */
1883
+ /** Current value of each revision dimension (a Revisions subset). */
1876
1884
  interface RevisionSnapshot {
1877
1885
  source: number | string | null;
1878
1886
  model: number;
@@ -1896,13 +1904,13 @@ interface RequestContextHandle {
1896
1904
  abort(reason?: unknown): void;
1897
1905
  }
1898
1906
  /**
1899
- * Builds the `RequestContext` a service call receives (§9.2): dataset,
1907
+ * Builds the `RequestContext` a service call receives: dataset,
1900
1908
  * the three revision dimensions at issue time, a request id, and a
1901
1909
  * cancellation signal owned by the returned controller.
1902
1910
  */
1903
1911
  declare function createRequestContext(args: CreateRequestContextArgs): RequestContextHandle;
1904
1912
  interface AdmitServiceResultArgs {
1905
- /** The service's `revisionDependencies` (§9.2). */
1913
+ /** The service's `revisionDependencies`. */
1906
1914
  declared: readonly RevisionDimension[];
1907
1915
  /** Revision values when the request was issued. */
1908
1916
  at: RevisionSnapshot;
@@ -1910,7 +1918,7 @@ interface AdmitServiceResultArgs {
1910
1918
  now: RevisionSnapshot;
1911
1919
  }
1912
1920
  /**
1913
- * §9.2 stale-result rule: admit a service result iff EVERY declared revision
1921
+ * stale-result rule: admit a service result iff EVERY declared revision
1914
1922
  * dimension is unchanged between issue and admission. Undeclared dimensions
1915
1923
  * never invalidate. Declaring nothing means the result is admissible under
1916
1924
  * any drift; declaring all three restores strict point-in-model semantics.
@@ -1921,13 +1929,13 @@ interface ServiceCacheKeyArgs {
1921
1929
  /** Request parameters (JSON-shaped); key order is canonicalized away. */
1922
1930
  params: unknown;
1923
1931
  datasetKey: string;
1924
- /** The service's declared revision dependencies (§9.2). */
1932
+ /** The service's declared revision dependencies. */
1925
1933
  declared: readonly RevisionDimension[];
1926
1934
  /** Current revision values; only declared dimensions enter the key. */
1927
1935
  revisions: RevisionSnapshot;
1928
1936
  }
1929
1937
  /**
1930
- * §9.2 cache-key rule: service identity + canonical-JSON params +
1938
+ * cache-key rule: service identity + canonical-JSON params +
1931
1939
  * `datasetKey` + EXACTLY the declared revision dimensions' current values.
1932
1940
  * Declaration-list order and params key order do not affect the key;
1933
1941
  * undeclared revision drift never changes it.
@@ -1936,11 +1944,11 @@ declare function serviceCacheKey(args: ServiceCacheKeyArgs): string;
1936
1944
  /** Accepted-base view the local service walks (thunked for lazy wiring). */
1937
1945
  interface LocalExpansionBase<N = Record<string, unknown>, E = Record<string, unknown>> {
1938
1946
  accepted: AcceptedGraph<N, E>;
1939
- /** The §7.1 CSR adjacency of `accepted` (see buildAcceptedAdjacency). */
1947
+ /** The CSR adjacency of `accepted` (see buildAcceptedAdjacency). */
1940
1948
  adjacency: Adjacency;
1941
1949
  }
1942
1950
  /**
1943
- * The built-in §9.2 expansion service: walks the core's accepted-base
1951
+ * The built-in expansion service: walks the core's accepted-base
1944
1952
  * adjacency — INCLUDING currently out-of-scope nodes (it reads the base, not
1945
1953
  * the scene) — with zero config and zero network. Declares
1946
1954
  * `revisionDependencies: ['source']`, so unrelated model/scope advances
@@ -1954,7 +1962,7 @@ interface LocalExpansionBase<N = Record<string, unknown>, E = Record<string, unk
1954
1962
  * admission gate is authoritative).
1955
1963
  *
1956
1964
  * The response is the CLOSED N-hop neighborhood (seeds included, plus every
1957
- * edge between returned nodes); per §9.2 the overlay merger dedupes rows
1965
+ * edge between returned nodes); the overlay merger dedupes rows
1958
1966
  * that already exist, so returning already-known seeds is correct.
1959
1967
  */
1960
1968
  declare function createLocalExpansionService<N = Record<string, unknown>, E = Record<string, unknown>>(getBase: () => LocalExpansionBase<N, E>): ExpansionService<N, E>;
@@ -1967,7 +1975,7 @@ type RegisterExpansionResult = {
1967
1975
  onto: string;
1968
1976
  };
1969
1977
  /**
1970
- * Pure in-flight-expansion ledger (§9.2): within one valid scope revision a
1978
+ * Pure in-flight-expansion ledger: within one valid scope revision a
1971
1979
  * second `expandNode(id)` while one is in flight coalesces into the pending
1972
1980
  * call; expansions of DISTINCT ids run (and complete) concurrently and
1973
1981
  * independently. `retractExpansion(id)` uses `abort(id)` to drop that id's
@@ -2005,14 +2013,15 @@ declare class PendingExpansions {
2005
2013
  }
2006
2014
 
2007
2015
  /**
2008
- * §16.14 history command-stack kernel (S9-T20; pulled forward from M7).
2016
+ * history command-stack kernel.
2009
2017
  *
2010
2018
  * v0.7 implements the KERNEL only: value-diff commands, transactions,
2011
2019
  * coalescing, and a bounded stack. The kernel never touches stores — it is a
2012
- * pure application seam: `undo()`/`redo()` return the command list to apply
2020
+ * pure application seam: `undo`/`redo` return the command list to apply
2013
2021
  * (already inverted, in application order) and move the cursor; the instance
2014
- * (wired in S15) applies commands to its slices and publishes.
2015
- * Ownership-mode acknowledgement walks and view-state integration are S15.
2022
+ * applies commands to its slices and publishes.
2023
+ * Ownership-mode acknowledgement walks and view-state integration remain
2024
+ * instance-level concerns.
2016
2025
  *
2017
2026
  * Commands are `{ slice, before, after }` value diffs — never closures — so
2018
2027
  * they are serializable and invert by swapping. The kernel freezes and stores
@@ -2032,7 +2041,7 @@ interface HistoryDepths {
2032
2041
  readonly redoDepth: number;
2033
2042
  }
2034
2043
  interface HistoryKernelOptions {
2035
- /** Stack bound; oldest entry evicted past it (§16.14; default 50). */
2044
+ /** Stack bound; oldest entry evicted past it. */
2036
2045
  limit?: number;
2037
2046
  /** `false` = the `history: false` prop: everything is a no-op, depths stay 0. */
2038
2047
  enabled?: boolean;
@@ -2050,7 +2059,7 @@ declare class HistoryKernel {
2050
2059
  private readonly debug;
2051
2060
  private readonly undoStack;
2052
2061
  private readonly redoStack;
2053
- /** Nested begin() joins the outer transaction (depth-counted). */
2062
+ /** Nested begin joins the outer transaction (depth-counted). */
2054
2063
  private txDepth;
2055
2064
  private txCommands;
2056
2065
  private txLabel;
@@ -2080,7 +2089,7 @@ declare class HistoryKernel {
2080
2089
  * transaction. The kernel freezes and stores what it is given.
2081
2090
  */
2082
2091
  record(slice: string, before: unknown, after: unknown): void;
2083
- /** Close a transaction; the outermost end() pushes one stack entry. */
2092
+ /** Close a transaction; the outermost end pushes one stack entry. */
2084
2093
  end(): void;
2085
2094
  /**
2086
2095
  * Move the cursor back one entry and return its commands, already inverted
@@ -2110,28 +2119,28 @@ declare class HistoryKernel {
2110
2119
  }
2111
2120
 
2112
2121
  /**
2113
- * §9.1 soft filtering (S9-T01) — pure, engine-free expr evaluation,
2122
+ * soft filtering — pure, engine-free expr evaluation,
2114
2123
  * validation, compilation, and canonical keying. The instance feeds compiled
2115
2124
  * filters into the SoftMask kernel (./mask); nothing here touches the store.
2116
2125
  *
2117
- * Semantics (orbit-spec.md §9.1):
2126
+ * Semantics:
2118
2127
  * - `field` addresses `attrs[field]`; the literal field 'id' addresses the
2119
- * entity id (it wins even when `attrs.id` exists).
2120
- * - The serializable expr path NEVER throws: junk shapes and §8-hygiene
2121
- * failures (non-numeric / non-finite values under 'range') simply fail the
2122
- * item. `validateFilterExpr` is the reporting channel — the instance turns
2123
- * its findings into validation errors at applyHostUpdate.
2128
+ * entity id (it wins even when `attrs.id` exists).
2129
+ * - The serializable expr path NEVER throws: junk shapes and numeric-hygiene
2130
+ * failures (non-numeric / non-finite values under 'range') simply fail the
2131
+ * item. `validateFilterExpr` is the reporting channel — the instance turns
2132
+ * its findings into validation errors at applyHostUpdate.
2124
2133
  * - eq/neq/in compare numbers with Object.is semantics EXCEPT that NaN is
2125
- * never equal to anything (so ±0 are distinct and NaN ≠ NaN); everything
2126
- * else compares with plain ===. No coercion, ever ('5' never equals 5).
2134
+ * never equal to anything (so ±0 are distinct and NaN ≠ NaN); everything
2135
+ * else compares with plain ===. No coercion, ever ('5' never equals 5).
2127
2136
  * - Function predicates are black boxes: throws are caught and aggregated
2128
- * into ONE {count, samples} result the caller converts to a single
2129
- * 'filter-error' diagnostic (§5.1 batching — O(categories), never O(bad
2130
- * rows)). A throwing predicate FAILS OPEN: the item stays visible, so a
2131
- * buggy predicate can never blank the graph.
2137
+ * into ONE {count, samples} result the caller converts to a single
2138
+ * 'filter-error' diagnostic (batching — O(categories), never O(bad
2139
+ * rows)). A throwing predicate FAILS OPEN: the item stays visible, so a
2140
+ * buggy predicate can never blank the graph.
2132
2141
  * - Structural specs compare by canonical key (`canonicalFilterKey`) so
2133
- * identity churn with equal structure never re-evaluates; function
2134
- * predicates key by reference identity via a WeakMap-issued token.
2142
+ * identity churn with equal structure never re-evaluates; function
2143
+ * predicates key by reference identity via a WeakMap-issued token.
2135
2144
  */
2136
2145
 
2137
2146
  /**
@@ -2141,7 +2150,7 @@ declare class HistoryKernel {
2141
2150
  declare function resolveFilterField(item: GraphNode<unknown> | AcceptedEdge<unknown>, field: string): unknown;
2142
2151
  /**
2143
2152
  * Evaluates one expr for one item via a field resolver. NEVER throws:
2144
- * malformed shapes and §8-hygiene failures fail the item (return false);
2153
+ * malformed shapes and numeric-hygiene failures fail the item (return false);
2145
2154
  * a malformed operand under 'not' also fails (junk never passes by double
2146
2155
  * negation). `range` requires a finite number value; missing bounds are
2147
2156
  * unbounded; includeMin/includeMax default true. `is-null` matches null OR
@@ -2151,7 +2160,7 @@ declare function evaluateFilterExpr(expr: FilterExpr, resolve: (field: string) =
2151
2160
  /**
2152
2161
  * Structural checker for serializable exprs: unknown ops and malformed
2153
2162
  * shapes are reported as `$`-rooted path strings ([] = valid). The instance
2154
- * converts findings into validation errors at applyHostUpdate (§9.1) —
2163
+ * converts findings into validation errors at applyHostUpdate
2155
2164
  * evaluation itself never throws on the same junk, it just fails the item.
2156
2165
  */
2157
2166
  declare function validateFilterExpr(expr: FilterExpr): string[];
@@ -2178,7 +2187,7 @@ declare function compileEdgeFilter<N = Record<string, unknown>, E = Record<strin
2178
2187
  * Canonical structural key for a FilterSpec or FilterExpr: object keys are
2179
2188
  * sorted, arrays preserve order, undefined-valued keys are omitted, and
2180
2189
  * function predicates map to a unique reference-identity token. Two inputs
2181
- * with equal keys are §9.1-equivalent — the instance skips re-evaluation
2190
+ * with equal keys are semantically equivalent — the instance skips re-evaluation
2182
2191
  * when the key of an incoming filter matches the active one (identity churn
2183
2192
  * with equal structure never re-evaluates; swapping a function reference
2184
2193
  * always does).
@@ -2186,14 +2195,14 @@ declare function compileEdgeFilter<N = Record<string, unknown>, E = Record<strin
2186
2195
  declare function canonicalFilterKey(specOrExpr: unknown): string;
2187
2196
 
2188
2197
  /**
2189
- * §9.1 soft-mask kernel (S9-T02/T03) — failure COUNTERS, never Sets and
2198
+ * soft-mask kernel — failure COUNTERS, never Sets and
2190
2199
  * never per-source bit positions (so there is no 32-dimension cap).
2191
2200
  *
2192
2201
  * The mask owns four Uint16 counter lanes: hideFailures and dimFailures for
2193
2202
  * nodes AND edges. Every acquired {@link MaskSource} contributes +1 to a
2194
2203
  * lane counter for each slot it currently fails and -1 when that slot
2195
2204
  * re-enters. A slot is visible iff hideFailures === 0 and dimmed iff visible
2196
- * AND dimFailures > 0 (spec §9.1 mask mechanics).
2205
+ * AND dimFailures > 0.
2197
2206
  *
2198
2207
  * Delta discipline: each source keeps its previous failing membership as
2199
2208
  * per-source Uint8 flag columns plus a dense slot list, so replacing a
@@ -2203,9 +2212,9 @@ declare function canonicalFilterKey(specOrExpr: unknown): string;
2203
2212
  * compares against the state at the previous drain, so a fail-then-restore
2204
2213
  * inside one drain period nets to no emission.
2205
2214
  *
2206
- * {@link SoftMask.applyNodeCascadeToEdges} implements §9's SINGLE edge-
2215
+ * {@link SoftMask.applyNodeCascadeToEdges} implements SINGLE edge-
2207
2216
  * survival rule over the mask lane: an edge hide-fails iff EITHER endpoint
2208
- * hide-fails (equivalently: survives iff BOTH endpoints survive
2217
+ * hide-fails (equivalently: survives iff BOTH endpoints survive
2209
2218
  * scope.ts `cascadeEdges` is the hard-scope variant of the same rule). It is
2210
2219
  * fed through one dedicated internal cascade source from the node hide lane:
2211
2220
  * O(E) recompute per call, but only edges whose state changed produce
@@ -2213,12 +2222,12 @@ declare function canonicalFilterKey(specOrExpr: unknown): string;
2213
2222
  *
2214
2223
  * Overflow guard: increments clamp at 0xFFFF and latch a one-time
2215
2224
  * {@link SoftMask.overflowed} flag the caller reports (an implementation may
2216
- * widen to Uint32 without changing semantics, §9.1). Debug builds assert
2217
- * balanced increments/decrements whenever a clear()/release() leaves zero
2225
+ * widen to Uint32 without changing semantics). Debug builds assert
2226
+ * balanced increments/decrements whenever a clear/release leaves zero
2218
2227
  * held memberships.
2219
2228
  */
2220
2229
 
2221
- /** Default muted alpha for dimmed entities (§9.1 'dim' mode). */
2230
+ /** Default muted alpha for dimmed entities. */
2222
2231
  declare const DIM_ALPHA_DEFAULT = 0.15;
2223
2232
  /**
2224
2233
  * A handle contributing failure memberships to the mask. Setting a lane
@@ -2231,7 +2240,7 @@ interface MaskSource {
2231
2240
  setNodeFailures(hideIdx: Iterable<number> | null, dimIdx?: Iterable<number> | null): void;
2232
2241
  setEdgeFailures(hideIdx: Iterable<number> | null, dimIdx?: Iterable<number> | null): void;
2233
2242
  /**
2234
- * O(Δ) delta form of the HIDE lane (F10-02): adds/removes individual slots
2243
+ * O(Δ) delta form of the HIDE lane: adds/removes individual slots
2235
2244
  * from this source's membership without replaying the full set. Freely
2236
2245
  * composable with the replace form — a later setNodeFailures re-baselines.
2237
2246
  * `crossings`, when supplied, receives the slots whose hide counter
@@ -2242,8 +2251,8 @@ interface MaskSource {
2242
2251
  updateEdgeFailures(addHide: ArrayLike<number> | null, removeHide: ArrayLike<number> | null): void;
2243
2252
  /** Empties all four lane memberships (the source stays usable). */
2244
2253
  clear(): void;
2245
- /** clear() + permanently retires the handle (further set/clear throws;
2246
- * release() itself is idempotent). */
2254
+ /** clear + permanently retires the handle (further set/clear throws;
2255
+ * release itself is idempotent). */
2247
2256
  release(): void;
2248
2257
  }
2249
2258
  /** Per-CALL zero-crossings reported by the delta ops (reused, callee-cleared). */
@@ -2253,7 +2262,7 @@ interface MaskCrossings {
2253
2262
  /** Slots whose hide counter went nonzero → 0 in this call. */
2254
2263
  becameClear: number[];
2255
2264
  }
2256
- /** §17 O(Δ) operation counters (see resetStats/stats on SoftMask). */
2265
+ /** O(Δ) operation counters (see resetStats/stats on SoftMask). */
2257
2266
  interface MaskStats {
2258
2267
  /** Slots visited by delta membership ops (add + remove attempts). */
2259
2268
  slotsVisited: number;
@@ -2264,7 +2273,7 @@ interface MaskStats {
2264
2273
  }
2265
2274
  /**
2266
2275
  * One drain payload. The four index arrays are REUSED across drains — copy
2267
- * before the next drainDirty() call if you need to keep them.
2276
+ * before the next drainDirty call if you need to keep them.
2268
2277
  */
2269
2278
  interface MaskDrain {
2270
2279
  /** Node slots whose hide-visibility (hideFailures 0 ↔ nonzero) flipped
@@ -2289,18 +2298,18 @@ declare class SoftMask {
2289
2298
  private readonly edgeHideLane;
2290
2299
  private readonly edgeDimLane;
2291
2300
  private readonly sources;
2292
- /** Dedicated internal source implementing the §9 node→edge cascade. */
2301
+ /** Dedicated internal source implementing the node→edge cascade. */
2293
2302
  private cascadeSource;
2294
2303
  private overflowedFlag;
2295
2304
  /** Total memberships currently held across all sources and lanes. */
2296
2305
  private totalHeld;
2297
- /** §17 O(Δ) op counters (F10-02 gate instrumentation). */
2306
+ /** O(Δ) op counters. */
2298
2307
  private readonly statsBox;
2299
2308
  constructor(nodeCapacity: number, edgeCapacity: number);
2300
2309
  get nodeCapacity(): number;
2301
2310
  get edgeCapacity(): number;
2302
2311
  /** One-time latch: some counter hit 0xFFFF and an increment was dropped.
2303
- * Counts may drift afterwards; the caller reports it (§9.1 overflow guard). */
2312
+ * Counts may drift afterwards; the caller reports it. */
2304
2313
  get overflowed(): boolean;
2305
2314
  get nodeHideFailures(): Uint16Array;
2306
2315
  get nodeDimFailures(): Uint16Array;
@@ -2308,18 +2317,18 @@ declare class SoftMask {
2308
2317
  get edgeDimFailures(): Uint16Array;
2309
2318
  /**
2310
2319
  * Grows capacities for structure changes (existing slot state is
2311
- * preserved; new slots start fully visible). Capacities never shrink
2320
+ * preserved; new slots start fully visible). Capacities never shrink
2312
2321
  * a smaller value is a no-op for that dimension.
2313
2322
  */
2314
2323
  grow(nodeCapacity: number, edgeCapacity: number): void;
2315
- /** Registers a new failure source. No cap on source count (§9.1). */
2324
+ /** Registers a new failure source. No cap on source count. */
2316
2325
  acquire(name: string): MaskSource;
2317
2326
  /**
2318
- * §9 edge cascade over the mask lane: recomputes, from the CURRENT node
2327
+ * edge cascade over the mask lane: recomputes, from the CURRENT node
2319
2328
  * hide lane, the set of edges with at least one hidden endpoint, and feeds
2320
2329
  * it to the dedicated internal cascade source (edge hide lane only).
2321
- * `links` is the flat `[src0, tgt0, src1, tgt1, …]` node-slot pair buffer
2322
- * (§7.1 CSR input shape); edge slot i has endpoints at links[2i]/[2i+1].
2330
+ * `links` is the flat `[src0, tgt0, src1, tgt1, …]` node-slot pair buffer;
2331
+ * edge slot i has endpoints at links[2i]/[2i+1].
2323
2332
  * O(E) scan per call — typically once per drain — but only edges whose
2324
2333
  * cascade state changed produce counter deltas (and thus dirty entries).
2325
2334
  * Edges beyond `links.length / 2` are treated as having no hidden
@@ -2327,7 +2336,7 @@ declare class SoftMask {
2327
2336
  */
2328
2337
  applyNodeCascadeToEdges(links: Uint32Array): void;
2329
2338
  /**
2330
- * O(incident-edges) delta form of the §9.1 cascade (F10-02): for each node
2339
+ * O(incident-edges) delta form of the cascade: for each node
2331
2340
  * whose HIDE visibility crossed zero, recompute only its incident edges'
2332
2341
  * cascade state from the CURRENT node counters and apply the delta through
2333
2342
  * the same internal cascade source the full form uses — the two compose
@@ -2343,10 +2352,10 @@ declare class SoftMask {
2343
2352
  * drain). The returned index arrays are reused by the next drain.
2344
2353
  */
2345
2354
  drainDirty(): MaskDrain;
2346
- /** §17 telemetry: estimated bytes of mask storage held (S13-T07):
2355
+ /** telemetry: estimated bytes of mask storage held:
2347
2356
  * four counter lanes (+pending trackers) and per-source flag columns. */
2348
2357
  estimatedBytes(): number;
2349
- /** §17 O(Δ) op counters (live object — snapshot before comparing). */
2358
+ /** O(Δ) op counters (live object — snapshot before comparing). */
2350
2359
  get stats(): Readonly<MaskStats>;
2351
2360
  resetStats(): void;
2352
2361
  visibleNodeCount(): number;
@@ -2354,7 +2363,7 @@ declare class SoftMask {
2354
2363
  /** Visible iff hideFailures === 0 (out-of-range slots read not-visible). */
2355
2364
  isNodeVisible(index: number): boolean;
2356
2365
  isEdgeVisible(index: number): boolean;
2357
- /** Dimmed iff visible AND dimFailures > 0 (§9.1). */
2366
+ /** Dimmed iff visible AND dimFailures > 0. */
2358
2367
  isNodeDimmed(index: number): boolean;
2359
2368
  isEdgeDimmed(index: number): boolean;
2360
2369
  /** 1 (fully visible) | dimAlpha (dimmed) | 0 (hidden). */
@@ -2368,7 +2377,7 @@ declare class SoftMask {
2368
2377
  */
2369
2378
  private applyMembership;
2370
2379
  /**
2371
- * O(Δ) delta ops on one lane membership (F10-02). Adds and removes are
2380
+ * O(Δ) delta ops on one lane membership. Adds and removes are
2372
2381
  * idempotent per slot (adding a member / removing a non-member is a
2373
2382
  * no-op); removed slots leave HOLES in `list` (compacted past 50%), so
2374
2383
  * replace/clear passes must honor the bit0 guard above. `crossings`, when
@@ -2383,65 +2392,65 @@ declare class SoftMask {
2383
2392
  private drainLane;
2384
2393
  private clearSource;
2385
2394
  /** Debug balanced-increment assert: whenever no source holds any
2386
- * membership, every counter must read zero (skipped once overflowed
2395
+ * membership, every counter must read zero (skipped once overflowed
2387
2396
  * clamped increments legitimately drift the books). */
2388
2397
  private assertBalancedIfIdle;
2389
2398
  }
2390
2399
 
2391
2400
  /**
2392
- * §16.6 crossfilter — typed-column engine (v0.7 node-dimension subset).
2401
+ * crossfilter — typed-column engine (v0.7 node-dimension subset).
2393
2402
  *
2394
2403
  * `TypedColumnCrossfilter` is the columnar backend the instance wraps into the
2395
2404
  * public `CrossfilterSession`. Design (crossfilter.js lineage):
2396
2405
  *
2397
- * - **Parse once.** `build()` extracts every dimension exactly once into typed
2398
- * columns (numeric/temporal → `Float64Array` epoch-ms/values, categorical →
2399
- * dictionary codes). §8 hygiene: non-finite numerics, unparseable temporals,
2400
- * and non-string/non-finite categorical values are excluded from the
2401
- * dimension (tracked per dimension in `excludedRows`; the slot is marked
2402
- * invalid). Temporal parsing: numbers are epoch ms verbatim; strings go
2403
- * through `Date.parse` (ES2022 parses `'YYYY-MM-DD'` as UTC midnight);
2404
- * `Date` instances use `getTime()`.
2406
+ * - **Parse once.** `build` extracts every dimension exactly once into typed
2407
+ * columns (numeric/temporal → `Float64Array` epoch-ms/values, categorical →
2408
+ * dictionary codes). hygiene: non-finite numerics, unparseable temporals,
2409
+ * and non-string/non-finite categorical values are excluded from the
2410
+ * dimension (tracked per dimension in `excludedRows`; the slot is marked
2411
+ * invalid). Temporal parsing: numbers are epoch ms verbatim; strings go
2412
+ * through `Date.parse` (ES2022 parses `'YYYY-MM-DD'` as UTC midnight);
2413
+ * `Date` instances use `getTime`.
2405
2414
  * - **O(Δ) brushes.** Each range dimension keeps a one-time argsorted
2406
- * permutation. A brush move performs two binary searches and walks ONLY the
2407
- * symmetric difference between the old and new in-range windows; categorical
2408
- * brushes walk only the per-code slot lists whose excluded flag changed. The
2409
- * brush path never re-sorts. A per-slot, per-dimension pass flag plus a
2410
- * global per-slot failure counter make a row selection-visible iff it fails
2411
- * zero dimensions. Hygiene-excluded rows fail any non-null brush on that
2412
- * dimension (they cannot be in range / in a category) and pass a null brush.
2415
+ * permutation. A brush move performs two binary searches and walks ONLY the
2416
+ * symmetric difference between the old and new in-range windows; categorical
2417
+ * brushes walk only the per-code slot lists whose excluded flag changed. The
2418
+ * brush path never re-sorts. A per-slot, per-dimension pass flag plus a
2419
+ * global per-slot failure counter make a row selection-visible iff it fails
2420
+ * zero dimensions. Hygiene-excluded rows fail any non-null brush on that
2421
+ * dimension (they cannot be in range / in a category) and pass a null brush.
2413
2422
  * - **Deltas out.** `setBrush` returns the slots whose overall visibility
2414
- * flipped (`hidden`/`shown`) for the instance's mask source.
2415
- * - **Lazy dual layer.** `summarize()` returns immutable summaries whose
2416
- * `filtered` layer counts rows passing every OTHER dimension's brush plus an
2417
- * external node-mask predicate (`setExternalMask`). v0.7 recomputes a dirty
2418
- * dimension's filtered layer lazily per `summarize()` call — O(rows) per
2419
- * dirty summarize, documented and acceptable at this tier (§17 fixtures own
2420
- * the perf claims; the O(Δ) guarantee covers the brush/visibility path).
2423
+ * flipped (`hidden`/`shown`) for the instance's mask source.
2424
+ * - **Lazy dual layer.** `summarize` returns immutable summaries whose
2425
+ * `filtered` layer counts rows passing every OTHER dimension's brush plus an
2426
+ * external node-mask predicate (`setExternalMask`). v0.7 recomputes a dirty
2427
+ * dimension's filtered layer lazily per `summarize` call — O(rows) per
2428
+ * dirty summarize, documented and acceptable at this tier (fixtures own
2429
+ * the perf claims; the O(Δ) guarantee covers the brush/visibility path).
2421
2430
  * - **Revisions & notify.** `selectionRevision` starts at 0 and advances
2422
- * exactly once per observable `setBrush` (a brush state change is observable
2423
- * via `getBrush` even when no row flips). v0.7 is synchronous, so
2424
- * latest-call-wins degenerates to "every call applies immediately in call
2425
- * order". Subscribers fire once per observable change after state is
2426
- * consistent; synchronous re-entrancy (a subscriber mutating the engine) is
2427
- * coalesced into one trailing notification pass. Model updates
2428
- * (`appendRows`/`replaceAll`) keep the current `selectionRevision` (§16.6)
2429
- * but do notify. External-mask changes notify (summaries changed) without
2430
- * advancing the selection revision.
2431
+ * exactly once per observable `setBrush` (a brush state change is observable
2432
+ * via `getBrush` even when no row flips). v0.7 is synchronous, so
2433
+ * latest-call-wins degenerates to "every call applies immediately in call
2434
+ * order". Subscribers fire once per observable change after state is
2435
+ * consistent; synchronous re-entrancy (a subscriber mutating the engine) is
2436
+ * coalesced into one trailing notification pass. Model updates
2437
+ * (`appendRows`/`replaceAll`) keep the current `selectionRevision`
2438
+ * but do notify. External-mask changes notify (summaries changed) without
2439
+ * advancing the selection revision.
2431
2440
  * - **Incremental append.** `appendRows` extends columns/codes in place and
2432
- * merges the pre-sorted old permutation with the sorted new block
2433
- * (permutation merge — never a full re-argsort); bins extend incrementally
2434
- * unless the domain grew (then a re-bin, still sort-free). Brushes persist
2435
- * by key and are re-applied to the NEW slots only; the returned delta covers
2436
- * only new slots (`shown` = new passing, `hidden` = new failing).
2437
- * `replaceAll` rebuilds columns but preserves brushes by dimension key,
2438
- * re-applying them as one combined delta against an all-visible baseline of
2439
- * the new roster (`shown` is always empty). `replaceAll` clears the external
2440
- * mask (slot indices changed meaning); `appendRows` keeps it and treats new
2441
- * slots as passing until the instance re-supplies it.
2441
+ * merges the pre-sorted old permutation with the sorted new block
2442
+ * (permutation merge — never a full re-argsort); bins extend incrementally
2443
+ * unless the domain grew (then a re-bin, still sort-free). Brushes persist
2444
+ * by key and are re-applied to the NEW slots only; the returned delta covers
2445
+ * only new slots (`shown` = new passing, `hidden` = new failing).
2446
+ * `replaceAll` rebuilds columns but preserves brushes by dimension key,
2447
+ * re-applying them as one combined delta against an all-visible baseline of
2448
+ * the new roster (`shown` is always empty). `replaceAll` clears the external
2449
+ * mask (slot indices changed meaning); `appendRows` keeps it and treats new
2450
+ * slots as passing until the instance re-supplies it.
2442
2451
  */
2443
2452
 
2444
- /** Default histogram bin count for numeric/temporal dimensions (§16.6). */
2453
+ /** Default histogram bin count for numeric/temporal dimensions. */
2445
2454
  declare const DEFAULT_BIN_COUNT = 24;
2446
2455
  /** Slots whose overall selection-visibility flipped in one operation. */
2447
2456
  interface BrushDelta {
@@ -2458,15 +2467,15 @@ interface CrossfilterStats {
2458
2467
  fullSorts: number;
2459
2468
  /** Permutation merges performed by appendRows. */
2460
2469
  permutationMerges: number;
2461
- /** Incremental filtered-layer bin adjustments (F10-02: O(Δ·D)). */
2470
+ /** Incremental filtered-layer bin adjustments (O(Δ·D)). */
2462
2471
  binUpdates: number;
2463
2472
  /** Full O(rows) filtered-layer recomputes (materialization/oracle only). */
2464
2473
  filteredRecomputes: number;
2465
2474
  }
2466
2475
  declare class TypedColumnCrossfilter<N = Record<string, unknown>> {
2467
- /** Test instrumentation; see CrossfilterStats. Reset with resetStats(). */
2476
+ /** Test instrumentation; see CrossfilterStats. Reset with resetStats. */
2468
2477
  readonly stats: CrossfilterStats;
2469
- /** Count of dims whose filtered layer is live-maintained (F10-02). */
2478
+ /** Count of dims whose filtered layer is live-maintained. */
2470
2479
  private liveDims;
2471
2480
  private dims;
2472
2481
  private byKey;
@@ -2484,11 +2493,11 @@ declare class TypedColumnCrossfilter<N = Record<string, unknown>> {
2484
2493
  /** Monotonic from 0; advances exactly once per observable setBrush change. */
2485
2494
  get selectionRevision(): number;
2486
2495
  resetStats(): void;
2487
- /** §17 telemetry: estimated bytes of typed-column storage held (S13-T07).
2496
+ /** telemetry: estimated bytes of typed-column storage held.
2488
2497
  * Documented components: per-dim value/permutation/bin/code/pass arrays,
2489
2498
  * the global failure counter, and the external mask. */
2490
2499
  estimatedBytes(): number;
2491
- /** F10-02 live-layer bookkeeping — the ONLY writer of `filteredLive`. */
2500
+ /** live-layer bookkeeping — the ONLY writer of `filteredLive`. */
2492
2501
  private setFilteredLive;
2493
2502
  /**
2494
2503
  * (Re)initialize columns from scratch. Clears all brushes and the external
@@ -2510,19 +2519,19 @@ declare class TypedColumnCrossfilter<N = Record<string, unknown>> {
2510
2519
  setBrush(key: string, brush: BrushState): BrushDelta;
2511
2520
  /**
2512
2521
  * External node-mask predicate for the joint "filtered" second layer (the
2513
- * instance wires the §9.1 filter-prop node mask in). Affects summaries only,
2514
- * never selection visibility. Length must equal rowCount(). Notifies on
2522
+ * instance wires the filter-prop node mask in). Affects summaries only,
2523
+ * never selection visibility. Length must equal rowCount. Notifies on
2515
2524
  * observable change; does NOT advance selectionRevision.
2516
2525
  */
2517
2526
  setExternalMask(passSlots: Uint8Array | null): void;
2518
2527
  /**
2519
- * Immutable summary. The filtered layer is recomputed lazily when dirty
2528
+ * Immutable summary. The filtered layer is recomputed lazily when dirty
2520
2529
  * O(rows) per dirty summarize (v0.7 tier; see module doc). Returned objects
2521
2530
  * are frozen and never mutated by later operations.
2522
2531
  */
2523
2532
  summarize(key: string): DimensionSummary;
2524
2533
  /**
2525
- * Incrementally extend columns with new rows (S9-T09 subset): no full
2534
+ * Incrementally extend columns with new rows: no full
2526
2535
  * rebuild, no full re-argsort — the pre-sorted old permutation merges with
2527
2536
  * the sorted new block. Brushes stay by key and are applied to the NEW slots
2528
2537
  * only; the returned delta covers only new slots. Keeps selectionRevision;
@@ -2551,16 +2560,16 @@ declare class TypedColumnCrossfilter<N = Record<string, unknown>> {
2551
2560
  private binIndex;
2552
2561
  private flip;
2553
2562
  /**
2554
- * F10-02 inline maintenance of LIVE filtered layers, dispatched from the
2563
+ * inline maintenance of LIVE filtered layers, dispatched from the
2555
2564
  * one place that knows the failCount transition. `boundary` is the
2556
2565
  * other-failures picture at the interesting side of the flip (after for
2557
2566
  * shown, before for hidden):
2558
- * - 0 → the slot crossed the FULLY-VISIBLE boundary: every other live
2559
- * layer counts it (own layers ignore the own-dim brush, so the brushed
2560
- * dim's layer is provably unchanged by its own flip);
2561
- * - 1 → exactly one OTHER dim still fails the slot: only that dim's
2562
- * what-if-I-cleared-mine layer flips;
2563
- * - ≥2 → no layer can change.
2567
+ * - 0 → the slot crossed the FULLY-VISIBLE boundary: every other live
2568
+ * layer counts it (own layers ignore the own-dim brush, so the brushed
2569
+ * dim's layer is provably unchanged by its own flip);
2570
+ * - 1 → exactly one OTHER dim still fails the slot: only that dim's
2571
+ * what-if-I-cleared-mine layer flips;
2572
+ * - ≥2 → no layer can change.
2564
2573
  * External-mask-excluded and hygiene-invalid slots contribute nothing
2565
2574
  * either way and are skipped.
2566
2575
  */
@@ -2578,27 +2587,27 @@ declare class TypedColumnCrossfilter<N = Record<string, unknown>> {
2578
2587
  }
2579
2588
 
2580
2589
  /**
2581
- * §11 scales & domains (S10-T01/T07) — canonical scale keying, default
2590
+ * scales & domains — canonical scale keying, default
2582
2591
  * palettes, sRGB color interpolation, domain-state machinery, and stable
2583
2592
  * categorical assignment. Pure and engine-free; the instance/projection
2584
2593
  * layers consume these primitives when a styling channel carries a `Scale`.
2585
2594
  *
2586
- * Semantics (orbit-spec.md §8/§11):
2587
- * - Scales are plain descriptors compared by CANONICAL STRUCTURAL VALUE
2588
- * equal inline literals produce equal keys and never reproject. A function
2589
- * `by` keys by reference identity (WeakMap token), never by source text.
2595
+ * Semantics:
2596
+ * - Scales are plain descriptors compared by CANONICAL STRUCTURAL VALUE
2597
+ * equal inline literals produce equal keys and never reproject. A function
2598
+ * `by` keys by reference identity (WeakMap token), never by source text.
2590
2599
  * - Domains default to the whole dataset revision and stay FROZEN across
2591
- * masking/brushing/isolation ('dataset' scope): the same metric value never
2592
- * changes visual meaning because a user brushed. 'hard-scope'/'visible' are
2593
- * explicit opt-ins that recompute when the caller's scope generation bumps;
2594
- * streaming 'expand' permits monotonic domain growth on recompute.
2600
+ * masking/brushing/isolation ('dataset' scope): the same metric value never
2601
+ * changes visual meaning because a user brushed. 'hard-scope'/'visible' are
2602
+ * explicit opt-ins that recompute when the caller's scope generation bumps;
2603
+ * streaming 'expand' permits monotonic domain growth on recompute.
2595
2604
  * - Explicit numeric domains always win verbatim (never computed, cached, or
2596
- * unioned).
2605
+ * unioned).
2597
2606
  * - Categorical values declared in `domain` take their declared position;
2598
- * out-of-domain values take a stable fnv-1a hash slot — NEVER first-seen
2599
- * order, so arrival order can never recolor a category.
2600
- * - §8 numeric hygiene: null/non-finite metric values resolve to `null`
2601
- * (caller falls back to the default style) and are excluded from domains.
2607
+ * out-of-domain values take a stable fnv-1a hash slot — NEVER first-seen
2608
+ * order, so arrival order can never recolor a category.
2609
+ * - numeric hygiene: null/non-finite metric values resolve to `null`
2610
+ * (caller falls back to the default style) and are excluded from domains.
2602
2611
  */
2603
2612
 
2604
2613
  type SequentialScale<T, N = Record<string, unknown>> = Extract<Scale<T, N>, {
@@ -2615,7 +2624,7 @@ type DivergingScale<T, N = Record<string, unknown>> = Extract<Scale<T, N>, {
2615
2624
  * order preserved, undefined-valued keys omitted, and a function `by` mapped
2616
2625
  * to a unique reference-identity token (same WeakMap approach — and canonical
2617
2626
  * grammar — as `canonicalFilterKey`). Two scales with equal keys are
2618
- * §11-equivalent: equal inline literals MUST and DO produce equal keys, so
2627
+ * structurally equivalent: equal inline literals MUST and DO produce equal keys, so
2619
2628
  * identity churn never reprojects; swapping a function reference always does.
2620
2629
  */
2621
2630
  declare function canonicalScaleKey<T, N>(scale: Scale<T, N>): string;
@@ -2634,7 +2643,7 @@ declare const DIVERGING_RANGE_DEFAULT: readonly [string, string, string];
2634
2643
  declare function interpolateColor(a: string, b: string, t: number): string;
2635
2644
  /**
2636
2645
  * Sequential color: maps `value` across `domain` onto the two-stop ramp.
2637
- * Returns null (caller renders the default style, §8 hygiene) when the value
2646
+ * Returns null (caller renders the default style, hygiene) when the value
2638
2647
  * is null/non-finite or the domain is null.
2639
2648
  */
2640
2649
  declare function sequentialColor<N = Record<string, unknown>>(scale: SequentialScale<string, N>, value: number | null, domain: readonly [number, number] | null): string | null;
@@ -2649,11 +2658,11 @@ declare function divergingColor<N = Record<string, unknown>>(scale: DivergingSca
2649
2658
  * Sequential size: linear map of `value` across `domain` onto [lo,hi],
2650
2659
  * clamped at the range endpoints. Degenerate domains yield the range
2651
2660
  * midpoint; null/non-finite values and null domains yield null (default
2652
- * style — NaN is never handed to a size buffer, §8).
2661
+ * style — NaN is never handed to a size buffer).
2653
2662
  */
2654
2663
  declare function sequentialSize(range: readonly [number, number], value: number | null, domain: readonly [number, number] | null): number | null;
2655
2664
  /**
2656
- * [min,max] over the finite numbers in `values` (§8 hygiene: null and
2665
+ * [min,max] over the finite numbers in `values` (hygiene: null and
2657
2666
  * non-finite entries are excluded), or null when nothing qualifies. A single
2658
2667
  * qualifying value yields a degenerate [v,v] domain.
2659
2668
  */
@@ -2663,7 +2672,7 @@ interface ResolveDomainArgs {
2663
2672
  * descriptor, so the key already discriminates by metric). Opaque here. */
2664
2673
  key: string;
2665
2674
  /** Explicit caller domain — returned VERBATIM; never computed, cached, or
2666
- * expand-unioned (§11: explicit always wins). */
2675
+ * expand-unioned. */
2667
2676
  explicit?: readonly [number, number] | undefined;
2668
2677
  /** Defaults: scope 'dataset', streaming 'freeze-per-revision'. */
2669
2678
  policy?: DomainPolicy | undefined;
@@ -2673,7 +2682,7 @@ interface ResolveDomainArgs {
2673
2682
  * (bump = recompute). IGNORED under 'dataset' scope — masking/brushing
2674
2683
  * must never change what a color means. */
2675
2684
  scopeGeneration?: number | undefined;
2676
- /** Source lineage this resolve belongs to (F11-02: datasetKey + source
2685
+ /** Source lineage this resolve belongs to (dataset key + source
2677
2686
  * revision). `streaming: 'expand'` unions only WITHIN one lineage — a
2678
2687
  * source replacement starts fresh instead of unioning dead extrema.
2679
2688
  * Callers that omit it keep the legacy always-union behavior. */
@@ -2683,7 +2692,7 @@ interface ResolveDomainArgs {
2683
2692
  compute: () => readonly [number, number] | null;
2684
2693
  }
2685
2694
  /**
2686
- * Per-instance domain freezer keyed by canonical scale key (§11).
2695
+ * Per-instance domain freezer keyed by canonical scale key.
2687
2696
  *
2688
2697
  * FREEZE-PER-REVISION: under scope 'dataset' the domain is computed ONCE per
2689
2698
  * {key, datasetRevision} — repeat resolves return the frozen value without
@@ -2722,24 +2731,24 @@ declare function categoricalIndex(domain: readonly string[] | undefined, palette
2722
2731
  declare function categoricalRows(domain: readonly string[] | undefined, seen: Iterable<string>): string[];
2723
2732
 
2724
2733
  /**
2725
- * DEF2 capability-policy module (spec §13; plan S1-T08/S4-T05).
2734
+ * capability-policy module.
2726
2735
  *
2727
- * §13 (normative): for capabilities where the core owns a fallback path, the
2736
+ * (normative): for capabilities where the core owns a fallback path, the
2728
2737
  * core selects native-vs-fallback ONCE at mount from the engine's declared
2729
2738
  * `capabilities` record — never by sniffing method presence — and unsupported
2730
- * *requested* props degrade loudly (a §5.1 diagnostic), never as silent no-ops.
2739
+ * *requested* props degrade loudly (a diagnostic), never as silent no-ops.
2731
2740
  *
2732
2741
  * This module is the single place those decisions are made:
2733
- * - {@link resolveEnginePolicy} turns the capability record + the host's
2734
- * requested features into one frozen {@link EnginePolicy} at mount.
2735
- * - {@link assertCapabilityMethodParity} is the mount-time dev-mode record
2736
- * vs. method-surface assertion, restricted to honestly checkable pairs.
2737
- * - {@link normalizeCommitForCapabilities} strips commit payload an engine
2738
- * declared it cannot honor, so incapable adapters never see it.
2742
+ * - {@link resolveEnginePolicy} turns the capability record + the host's
2743
+ * requested features into one frozen {@link EnginePolicy} at mount.
2744
+ * - {@link assertCapabilityMethodParity} is the mount-time dev-mode record
2745
+ * vs. method-surface assertion, restricted to honestly checkable pairs.
2746
+ * - {@link normalizeCommitForCapabilities} strips commit payload an engine
2747
+ * declared it cannot honor, so incapable adapters never see it.
2739
2748
  */
2740
2749
 
2741
2750
  /** One loud degradation: a feature the host requested that the mounted engine
2742
- * does not declare. Feeds the §5.1 dev diagnostic at mount. */
2751
+ * does not declare. Feeds the dev diagnostic at mount. */
2743
2752
  interface EnginePolicyDegradation {
2744
2753
  readonly feature: string;
2745
2754
  readonly reason: string;
@@ -2749,29 +2758,29 @@ interface EnginePolicyDegradation {
2749
2758
  interface RequestedEngineFeatures {
2750
2759
  edgeArrows?: boolean;
2751
2760
  images?: boolean;
2752
- /** §16.3 stage-4: a `clusters` spec is active this session. */
2761
+ /** stage-4: a `clusters` spec is active this session. */
2753
2762
  clusters?: boolean;
2754
2763
  }
2755
2764
  /**
2756
- * The frozen mount-time native-vs-fallback record (§13). Evaluated exactly
2765
+ * The frozen mount-time native-vs-fallback record. Evaluated exactly
2757
2766
  * once per mount from `EngineCapabilities` and never revisited — capability
2758
2767
  * records are static declarations fixed at engine construction, so the policy
2759
2768
  * must not drift even if a caller mutates the input record afterwards.
2760
2769
  */
2761
2770
  interface EnginePolicy {
2762
- /** §16.12 arrowheads: engine-drawn, or the prop is inert (+ dev warning). */
2771
+ /** arrowheads: engine-drawn, or the prop is inert (+ dev warning). */
2763
2772
  readonly edgeArrows: 'native' | 'inert';
2764
- /** §8 image sprites: atlas-backed, or the placeholder glyph with refs
2773
+ /** image sprites: atlas-backed, or the placeholder glyph with refs
2765
2774
  * retained for a future compatible engine. */
2766
2775
  readonly images: 'native' | 'placeholder';
2767
- /** §13 link hover/click: engine events, or the core's CPU grid fallback. */
2776
+ /** link hover/click: engine events, or the core's CPU grid fallback. */
2768
2777
  readonly linkPicking: 'native' | 'cpu-fallback';
2769
- /** §16.3 stage-4 cluster force: engine-applied, or inert (membership,
2778
+ /** stage-4 cluster force: engine-applied, or inert (membership,
2770
2779
  * labels, and centroids are core-owned and unaffected). */
2771
2780
  readonly clusterForce: 'native' | 'inert';
2772
2781
  /** Channels eligible for ranged (partial) uploads; empty = full replaces. */
2773
2782
  readonly rangedChannels: ReadonlySet<EngineBufferChannel>;
2774
- /** §17 stop-at-rest: 'stops' when the engine declares idleFrames:'stops'.
2783
+ /** stop-at-rest: 'stops' when the engine declares idleFrames:'stops'.
2775
2784
  * Observability only (telemetry/harness read it) — an idle-spinning engine
2776
2785
  * is a documented state, never a degradation entry: nothing was
2777
2786
  * host-REQUESTED, so there is nothing to warn about. */
@@ -2784,7 +2793,7 @@ interface EnginePolicy {
2784
2793
  * Resolve the mount-time engine policy from the declared capability record.
2785
2794
  *
2786
2795
  * Decisions come from `capabilities` ONLY — method sniffing is forbidden by
2787
- * §13. The result is deep-frozen and holds a defensive copy of
2796
+ * The result is deep-frozen and holds a defensive copy of
2788
2797
  * `rangeUpdates`, so mutating the input record afterwards changes nothing.
2789
2798
  * A degradation entry exists only for features the host actually requested
2790
2799
  * that the engine does not declare; unrequested gaps stay silent.
@@ -2795,25 +2804,25 @@ declare function resolveEnginePolicy(capabilities: EngineCapabilities, requested
2795
2804
  * with the engine's method surface? Returns a list of human-readable
2796
2805
  * mismatches (empty = consistent).
2797
2806
  *
2798
- * Why so few checks? §13's illustrative parity assertion
2807
+ * Why so few checks? An illustrative parity assertion
2799
2808
  * (`capabilities.linkPicking === (typeof engine.linkAt === 'function')`)
2800
- * presumes the spec's full method surface; the v0.1 adapter contract
2809
+ * presumes a broader method surface; the v0.1 adapter contract
2801
2810
  * deliberately narrows it, leaving most capabilities with NO honestly
2802
- * checkable method pair. Those defer to the §19 conformance suite, which
2803
- * validates declared records against observed behavior:
2804
- *
2805
- * - `linkPicking`: native picking arrives through mount-time host events
2806
- * (`onLinkClick`/`onLinkHover`), not a probeable `linkAt` method — there
2807
- * is nothing on the engine object to compare the record against.
2808
- * - `edgeArrows` / `pointImages` / `rangeUpdates`: honored inside
2809
- * `commit()` payload handling (`config.linkArrows`, `resources`, ranged
2810
- * uploads) with no distinguishing method; only behavior can validate them.
2811
- * - `simulation`: `start()`/`pause()` are mandatory on every engine (static
2812
- * engines no-op them), so method presence carries no signal either way.
2813
- * - `pointsInPolygon`-family (`pointsInRect`, `captureScreenshot`,
2814
- * `neighborIndices`, `screenToSpace`/`spaceToScreen`, `setPinnedIndices`,
2815
- * `zoomToIndex`): optional-by-contract with no declaring capability bit —
2816
- * absence is legitimate, so no check is fabricated for them.
2811
+ * checkable method pair. Those are instead covered by engine probes that
2812
+ * validate declared records against observed behavior:
2813
+ *
2814
+ * - `linkPicking`: native picking arrives through mount-time host events
2815
+ * (`onLinkClick`/`onLinkHover`), not a probeable `linkAt` method — there
2816
+ * is nothing on the engine object to compare the record against.
2817
+ * - `edgeArrows` / `pointImages` / `rangeUpdates`: honored inside
2818
+ * `commit()` payload handling (`config.linkArrows`, `resources`, ranged
2819
+ * uploads) with no distinguishing method; only behavior can validate them.
2820
+ * - `simulation`: `start()`/`pause()` are mandatory on every engine (static
2821
+ * engines no-op them), so method presence carries no signal either way.
2822
+ * - `pointsInPolygon`-family (`pointsInRect`, `captureScreenshot`,
2823
+ * `neighborIndices`, `screenToSpace`/`spaceToScreen`, `setPinnedIndices`,
2824
+ * `zoomToIndex`): optional-by-contract with no declaring capability bit —
2825
+ * absence is legitimate, so no check is fabricated for them.
2817
2826
  *
2818
2827
  * The one honest pair on this surface: `trackedPositions` declares position
2819
2828
  * readback works, so `getPositions` must actually be present.
@@ -2821,10 +2830,10 @@ declare function resolveEnginePolicy(capabilities: EngineCapabilities, requested
2821
2830
  declare function assertCapabilityMethodParity(engine: GraphEngine): string[];
2822
2831
  /**
2823
2832
  * Strip commit payload the engine's capability record says it cannot honor:
2824
- * - `resources` (image atlas + per-point image index) unless `pointImages`;
2825
- * - `config.linkArrows` unless `edgeArrows`;
2826
- * - `config.cluster` unless `clusterForce` (§16.3 stage 4 — the core keeps
2827
- * membership, labels, and centroids; only the FORCE is engine-side).
2833
+ * - `resources` (image atlas + per-point image index) unless `pointImages`;
2834
+ * - `config.linkArrows` unless `edgeArrows`;
2835
+ * - `config.cluster` unless `clusterForce` (stage 4 — the core keeps
2836
+ * membership, labels, and centroids; only the FORCE is engine-side).
2828
2837
  * A `config` left empty by the strip is dropped entirely.
2829
2838
  *
2830
2839
  * IDENTITY-PRESERVING: when nothing needs stripping the SAME commit object
@@ -2837,15 +2846,15 @@ declare function normalizeCommitForCapabilities(commit: EngineCommit, capabiliti
2837
2846
  };
2838
2847
 
2839
2848
  /**
2840
- * §8 shared numeric hygiene (R-19-10) — THE single coercion layer for every
2849
+ * shared numeric hygiene — THE single coercion layer for every
2841
2850
  * numeric consumer in orbit-core.
2842
2851
  *
2843
2852
  * Wherever a caller-supplied value feeds a numeric sink — size/width
2844
- * projection buffers (§8), scale domains (§11), metric columns (§12),
2845
- * crossfilter bins (§16.6), table lanes — the value is REQUIRED to route
2853
+ * projection buffers, scale domains, metric columns,
2854
+ * crossfilter bins, table lanes — the value is REQUIRED to route
2846
2855
  * through `coerceNumeric` / `coerceNumericInto`. Non-numeric and non-finite
2847
2856
  * inputs (including the string sentinels `"NaN"` / `"Infinity"` /
2848
- * `"-Infinity"` that JSON transports smuggle through, §5) coerce to `null`:
2857
+ * `"-Infinity"` that JSON transports smuggle through) coerce to `null`:
2849
2858
  * the row falls back to the default style and is excluded from domain
2850
2859
  * computation. NaN NEVER escapes this module — not as a return value and not
2851
2860
  * into a GPU buffer.
@@ -2853,16 +2862,15 @@ declare function normalizeCommitForCapabilities(commit: EngineCommit, capabiliti
2853
2862
  * Coercion rules:
2854
2863
  * - numbers pass iff `Number.isFinite` (NaN / ±Infinity → null);
2855
2864
  * - strings are trimmed; empty → null; the case-insensitive sentinels
2856
- * 'NaN' / 'Infinity' / '-Infinity' / '+Infinity' → null; anything else
2857
- * parses via `Number(...)` and passes iff finite (so '1e3' → 1000 but
2858
- * '12px' → null — `Number`, not `parseFloat`, so no partial prefixes);
2865
+ * 'NaN' / 'Infinity' / '-Infinity' / '+Infinity' → null; anything else
2866
+ * parses via `Number(...)` and passes iff finite (so '1e3' → 1000 but
2867
+ * '12px' → null — `Number`, not `parseFloat`, so no partial prefixes);
2859
2868
  * - booleans, objects, arrays, functions, symbols, bigints, null, and
2860
- * undefined → null (no `valueOf`/`toString` coercion side channels).
2869
+ * undefined → null (no `valueOf`/`toString` coercion side channels).
2861
2870
  *
2862
- * FOLLOW-UP (do not fix here): `crossfilter.ts` predates this module and
2863
- * carries its own inline finite checks; migrating it to route through
2864
- * `coerceNumeric` is a tracked S10 follow-up so the sentinel-string rules
2865
- * stay defined in exactly one place.
2871
+ * `crossfilter.ts` predates this module and retains its own inline finite
2872
+ * checks. Any consolidation must route through `coerceNumeric` so the
2873
+ * sentinel-string rules stay defined in exactly one place.
2866
2874
  */
2867
2875
  declare function coerceNumeric(value: unknown): number | null;
2868
2876
  /**
@@ -2877,31 +2885,31 @@ declare function coerceNumeric(value: unknown): number | null;
2877
2885
  declare function coerceNumericInto(target: Float32Array, index: number, value: unknown, fallback: number): boolean;
2878
2886
 
2879
2887
  /**
2880
- * §12 metrics (v0.8 subset): lazy degree-family primitives over the
2888
+ * metrics (v0.8 subset): lazy degree-family primitives over the
2881
2889
  * maintained topology plus revision-gated admission of async metric columns.
2882
2890
  *
2883
2891
  * - The degree family (degree / inDegree / outDegree) is computed LAZILY on
2884
- * first request per model revision, in ONE combined O(n + L) pass, and
2885
- * cached as Float64Arrays until the model revision changes.
2892
+ * first request per model revision, in ONE combined O(n + L) pass, and
2893
+ * cached as Float64Arrays until the model revision changes.
2886
2894
  * - SELF-LOOP SEMANTICS: a self-loop (a, a) contributes exactly 1 to each of
2887
- * degree, inDegree, and outDegree of `a`. The CSR adjacency lists a
2888
- * self-loop twice under its point (once per endpoint slot, see
2889
- * adjacency.ts), so degree = CSR row length MINUS the point's self-loop
2890
- * count; in/out come from a directed pass over the flat link pairs.
2891
- * - Async columns join once against the accepted model (§12): 'index' align
2892
- * is positional over accepted-base order; 'ids' align joins by id with
2893
- * unknown ids counted+sampled, duplicate ids counted (last occurrence
2894
- * wins), and absent rows null. Every value routes through `coerceNumeric`
2895
- * (§8 hygiene, R-19-10). A column computed for a stale model revision is
2896
- * DISCARDED with a diagnostic — admission is the correctness gate, abort
2897
- * is only an optimization (§9.2).
2895
+ * degree, inDegree, and outDegree of `a`. The CSR adjacency lists a
2896
+ * self-loop twice under its point (once per endpoint slot, see
2897
+ * adjacency.ts), so degree = CSR row length MINUS the point's self-loop
2898
+ * count; in/out come from a directed pass over the flat link pairs.
2899
+ * - Async columns join once against the accepted model: 'index' align
2900
+ * is positional over accepted-base order; 'ids' align joins by id with
2901
+ * unknown ids counted+sampled, duplicate ids counted (last occurrence
2902
+ * wins), and absent rows null. Every value routes through `coerceNumeric`.
2903
+ * A column computed for a stale model revision is
2904
+ * DISCARDED with a diagnostic — admission is the correctness gate, abort
2905
+ * is only an optimization.
2898
2906
  * - Storage encodes null as NaN inside Float64Arrays; `getMetricValue`
2899
- * converts back at the boundary so NaN never escapes to callers.
2907
+ * converts back at the boundary so NaN never escapes to callers.
2900
2908
  * - Admitted columns SHADOW the built-in degree family under the same name
2901
- * (a precomputed/server 'degree' column wins; §12 precomputed path).
2909
+ * (a precomputed/server 'degree' column wins; precomputed path).
2902
2910
  */
2903
2911
 
2904
- /** Topology snapshot the degree family is computed from (§12). */
2912
+ /** Topology snapshot the degree family is computed from. */
2905
2913
  interface MetricModelInput<N = Record<string, unknown>> {
2906
2914
  /** Accepted nodes in accepted-base order (index i ↔ point i). */
2907
2915
  nodes: readonly GraphNode<N>[];
@@ -2933,7 +2941,7 @@ declare class MetricStore<N = Record<string, unknown>> {
2933
2941
  /** Admitted async columns by metric name; NaN encodes null. */
2934
2942
  private readonly columns;
2935
2943
  private degreePasses;
2936
- /** §17 telemetry: estimated bytes of metric storage held (S13-T07). */
2944
+ /** telemetry: estimated bytes of metric storage held. */
2937
2945
  estimatedBytes(): number;
2938
2946
  /** Number of combined degree-family compute passes (test observability). */
2939
2947
  get degreeComputePasses(): number;
@@ -2946,10 +2954,10 @@ declare class MetricStore<N = Record<string, unknown>> {
2946
2954
  */
2947
2955
  setModel(model: MetricModelInput<N>): void;
2948
2956
  /**
2949
- * Joins async metric columns against the accepted model (§12).
2957
+ * Joins async metric columns against the accepted model.
2950
2958
  * Revision-gated PER COLUMN (I1): a column whose issue-time
2951
2959
  * `forModelRevision` stamp differs from `opts.modelRevision` is discarded
2952
- * (info diagnostic — a normal async race outcome, §9.2). A missing or
2960
+ * (info diagnostic — a normal async race outcome). A missing or
2953
2961
  * mismatched stamp is never defaulted to the current revision — that
2954
2962
  * would make the gate self-satisfying.
2955
2963
  * Structural rejections ('index' length mismatch, missing/mismatched ids)
@@ -2966,7 +2974,7 @@ declare class MetricStore<N = Record<string, unknown>> {
2966
2974
  getMetricValue(metric: MetricName, index: number): number | null;
2967
2975
  /**
2968
2976
  * Raw column in accepted-base order, or null when unavailable. NaN encodes
2969
- * null (§12) — consumers exclude NaN slots from domains. Do NOT mutate:
2977
+ * null — consumers exclude NaN slots from domains. Do NOT mutate:
2970
2978
  * this is the live cache, not a copy.
2971
2979
  */
2972
2980
  metricValues(metric: MetricName): Float64Array | null;
@@ -2978,22 +2986,22 @@ declare class MetricStore<N = Record<string, unknown>> {
2978
2986
  }
2979
2987
 
2980
2988
  /**
2981
- * §16.8 minimap / overview — CPU fallback lane (S11-T09/T10).
2989
+ * minimap / overview — CPU fallback lane.
2982
2990
  *
2983
2991
  * v0.9 trim: no engine exposes `capabilities.overviewPass` yet (cosmos has no
2984
- * second draw pass — M0 matrix), so this controller IS the minimap thumbnail
2985
- * path: an O(n) CPU rasterization of the §7.1 position mirror into a small
2992
+ * second draw pass — matrix), so this controller IS the minimap thumbnail
2993
+ * path: an O(n) CPU rasterization of the position mirror into a small
2986
2994
  * RGBA dot field. It is a pure controller — no DOM, no canvas — the React
2987
2995
  * component blits the returned `Uint8ClampedArray` into an `ImageData`/canvas
2988
- * and draws the viewport rectangle on top (O(1) from `getViewport()`, fully
2996
+ * and draws the viewport rectangle on top (O(1) from `getViewport`, fully
2989
2997
  * decoupled from thumbnail refresh cadence).
2990
2998
  *
2991
- * Refresh cadence (spec §16.8): ≤ 2 Hz while the simulation is hot (positions
2999
+ * Refresh cadence: ≤ 2 Hz while the simulation is hot (positions
2992
3000
  * change continuously on the GPU, so the epoch is ignored), ≤ 1 Hz after a
2993
3001
  * change while idle, and ZERO work while idle with an unchanged positions
2994
3002
  * epoch — `shouldRefresh` is the single throttle gate and latches its clock /
2995
3003
  * epoch only when it answers true (a `true` must be followed by one
2996
- * `rasterize()`).
3004
+ * `rasterize`).
2997
3005
  *
2998
3006
  * Orientation: minimap pixel y grows DOWNWARD while world (space) y grows
2999
3007
  * upward — the same flip cosmos applies in its space→screen scale (dist
@@ -3032,7 +3040,7 @@ interface OverviewRaster {
3032
3040
  bitmap: Uint8ClampedArray;
3033
3041
  bounds: OverviewBounds;
3034
3042
  }
3035
- /** Spec §16.8: the CPU fallback rasterizes into a 256² target. */
3043
+ /** Spec the CPU fallback rasterizes into a 256² target. */
3036
3044
  declare const OVERVIEW_SIZE_DEFAULT = 256;
3037
3045
  /** Hot-simulation refresh floor: ≤ 2 Hz. */
3038
3046
  declare const OVERVIEW_HOT_INTERVAL_MS = 500;
@@ -3042,7 +3050,7 @@ declare class OverviewController {
3042
3050
  private readonly getScene;
3043
3051
  private readonly getVisible;
3044
3052
  readonly size: number;
3045
- /** Transform of the LAST rasterization; null until rasterize() succeeds. */
3053
+ /** Transform of the LAST rasterization; null until rasterize succeeds. */
3046
3054
  private frame;
3047
3055
  private lastRefreshMs;
3048
3056
  private lastEpoch;
@@ -3052,16 +3060,16 @@ declare class OverviewController {
3052
3060
  * when it returns true, so each `true` accounts for exactly one refresh:
3053
3061
  *
3054
3062
  * - hot (`simulationRunning`): time-gated only (≤ 2 Hz) — the epoch is
3055
- * ignored because positions change continuously without epoch advances;
3063
+ * ignored because positions change continuously without epoch advances;
3056
3064
  * - idle: refresh only when the epoch ADVANCED since the last refresh,
3057
- * time-gated at ≤ 1 Hz;
3065
+ * time-gated at ≤ 1 Hz;
3058
3066
  * - idle + unchanged epoch: always false — zero work, forever.
3059
3067
  */
3060
3068
  shouldRefresh(nowMs: number, simulationRunning: boolean, epoch: number): boolean;
3061
3069
  /**
3062
3070
  * Rasterizes the current scene into a fresh `size²` RGBA dot field: 1 px
3063
3071
  * white dots whose alpha ACCUMULATES on overlap (heatmap-ish density),
3064
- * dimmed for mask-hidden points; NaN pairs (§7.3 tombstones) are skipped.
3072
+ * dimmed for mask-hidden points; NaN pairs are skipped.
3065
3073
  * World bounds map into the thumbnail with a 5 % edge padding at a UNIFORM
3066
3074
  * scale (aspect preserved, centered on the short axis) and a downward pixel
3067
3075
  * y (see module header). Returns null when there is no scene or no point.
@@ -3077,34 +3085,34 @@ declare class OverviewController {
3077
3085
  }
3078
3086
 
3079
3087
  /**
3080
- * §16.14 SVG export (S15 export lane) — the M7 pure module.
3088
+ * SVG export — the engine-free pure module.
3081
3089
  *
3082
3090
  * ENGINE-INDEPENDENT BY CONSTRUCTION, not by discipline: positions and
3083
3091
  * projected styles come IN as a plain descriptor, vector markup goes OUT as a
3084
3092
  * string. No engine, no instance, no DOM — the post-v1 server snapshot path
3085
- * (spec §13, R-13-53) reuses this verbatim under plain Node, and the test
3093
+ * reuses this verbatim under plain Node, and the test
3086
3094
  * suite runs it exactly that way. Keeping it engine-free is an M7
3087
3095
  * requirement, which is why it is a standalone module rather than instance
3088
3096
  * code that might one day be extracted.
3089
3097
  *
3090
- * Output discipline (§16.14):
3091
- * - One element per node/edge/label, assembled OFF-DOM by chunked
3092
- * array-join — O(elements), never a live DOM node per element.
3093
- * - Every label and attribute string is XML-escaped (§14's untrusted-content
3094
- * rule in its XML form): a hostile label renders as literal text in every
3095
- * downstream vector tool, never as markup.
3096
- * - Bounded: above `maxElements` (default 50 000 — the practical ceiling for
3097
- * downstream vector editors) rendering THROWS before assembling anything;
3098
- * the instance wraps that into the typed `export-too-large` rejection, and
3099
- * the raster-hybrid form (a PNG base layer plus a small vector overlay) is
3100
- * the sanctioned way past it.
3098
+ * Output discipline:
3099
+ * - One element per node/edge/label, assembled OFF-DOM by chunked
3100
+ * array-join — O(elements), never a live DOM node per element.
3101
+ * - Every label and attribute string is XML-escaped (untrusted-content
3102
+ * rule in its XML form): a hostile label renders as literal text in every
3103
+ * downstream vector tool, never as markup.
3104
+ * - Bounded: above `maxElements` (default 50 000 — the practical ceiling for
3105
+ * downstream vector editors) rendering THROWS before assembling anything;
3106
+ * the instance wraps that into the typed `export-too-large` rejection, and
3107
+ * the raster-hybrid form (a PNG base layer plus a small vector overlay) is
3108
+ * the sanctioned way past it.
3101
3109
  */
3102
3110
  interface SvgSceneNode {
3103
3111
  x: number;
3104
3112
  y: number;
3105
3113
  /** Radius in output px (the caller halves its size-buffer diameter). */
3106
3114
  r: number;
3107
- /** Any CSS color string (the caller projects RGBA buffers to rgba()). */
3115
+ /** Any CSS color string (the caller projects RGBA buffers to rgba). */
3108
3116
  color: string;
3109
3117
  }
3110
3118
  interface SvgSceneEdge {
@@ -3162,21 +3170,23 @@ declare function escapeXml(text: string): string;
3162
3170
  declare function renderSvg(scene: SvgScene, opts?: RenderSvgOptions): string;
3163
3171
 
3164
3172
  /**
3165
- * §5.1 columnar-NATIVE acceptance rules (PR-F wave 1, ADR-006) the column
3166
- * -domain twin of validate.ts, built to run INSIDE the worker over typed
3173
+ * Columnar-native acceptance rules the column-oriented twin of validate.ts,
3174
+ * built to run INSIDE the worker over typed
3167
3175
  * columns without materializing a single row object.
3168
3176
  *
3169
3177
  * Semantics mirror the object lane EXACTLY (the equivalence oracle pins
3170
3178
  * rosters AND diagnostics, message strings included):
3171
- * - duplicate node ids drop, first occurrence wins ('duplicate-node-id',
3172
- * warning) — and edges addressing a dropped duplicate ROW remap to the
3173
- * surviving occurrence, because the object lane resolves endpoints by ID
3174
- * STRING, which survives.
3175
- * - duplicate edge ids drop, first wins ('duplicate-edge-id', warning).
3176
- * - self-loops are RETAINED with 'self-loop-retained' (info).
3177
- * - invalid-node / invalid-edge / dangling-edge cannot occur here: ids come
3178
- * from a structurally validated dictionary column and endpoints are
3179
- * in-bounds indices by prior validation (validateColumnarStructure).
3179
+ * - duplicate node ids drop, first occurrence wins ('duplicate-node-id',
3180
+ * warning) — and edges addressing a dropped duplicate ROW remap to the
3181
+ * surviving occurrence, because the object lane resolves endpoints by ID
3182
+ * STRING, which survives.
3183
+ * - duplicate edge ids drop, first wins ('duplicate-edge-id', warning).
3184
+ * - self-loops are RETAINED with 'self-loop-retained' (info).
3185
+ * - invalid-node / invalid-edge rows with NUL-reserved ids drop here;
3186
+ * dangling edges can then arise when an endpoint names a dropped invalid
3187
+ * node. Other structural corruption cannot occur because ids come from a
3188
+ * structurally validated dictionary column and endpoints are in-bounds
3189
+ * indices by prior validation (validateColumnarStructure).
3180
3190
  *
3181
3191
  * Duplicates hide in TWO encodings: two rows sharing a code, and two
3182
3192
  * DISTINCT dictionary entries holding equal strings. Both are handled by
@@ -3211,21 +3221,21 @@ interface ColumnarAcceptance {
3211
3221
  declare function acceptColumnar(snapshot: ColumnarGraphSnapshot<unknown, unknown>): ColumnarAcceptance;
3212
3222
 
3213
3223
  /**
3214
- * §5 columnar snapshot lane (S13-T01, ADR-006) — structural validation and
3224
+ * columnar snapshot lane — structural validation and
3215
3225
  * the materialization bridge.
3216
3226
  *
3217
3227
  * Validation is O(number of columns + rows) and runs BEFORE transfer or
3218
3228
  * admission. Columnar structural corruption is intentionally not repaired
3219
- * row by row — offset/index misalignment can reinterpret every later row
3229
+ * row by row — offset/index misalignment can reinterpret every later row
3220
3230
  * so any structural issue rejects the WHOLE snapshot, the prior scene stays
3221
- * intact, and nothing throws from a React render (spec §5.1).
3231
+ * intact, and nothing throws from a React render.
3222
3232
  *
3223
3233
  * The bridge materializes a VALID columnar snapshot into the object form and
3224
3234
  * feeds the existing pipeline, so duplicate-id / dangling-edge / self-loop
3225
3235
  * resolution stays in exactly one place (validate.ts) and the columnar lane
3226
- * inherits every object-lane rule by construction (ADR-006: T01 lands
3227
- * behind `execution: 'main'` with zero behavior change). The
3228
- * zero-materialization path arrives with the worker waves.
3236
+ * inherits every object-lane rule by construction. Under `execution: 'main'`
3237
+ * materialization remains synchronous; the worker lane can perform acceptance
3238
+ * off-thread before the same shared pipeline runs.
3229
3239
  *
3230
3240
  * Null semantics: `nulls` is one byte per row, nonzero = null. Null attr
3231
3241
  * values materialize as `null` (JSON-ish; every numeric/temporal consumer
@@ -3242,7 +3252,7 @@ interface ColumnarIssue {
3242
3252
  }
3243
3253
  /**
3244
3254
  * O(columns + rows) structural validation. Empty array ⇒ structurally sound
3245
- * (duplicate ids, self-loops, and parallel-edge rules are NOT checked here
3255
+ * (duplicate ids, self-loops, and parallel-edge rules are NOT checked here
3246
3256
  * they are shared object-lane semantics applied after materialization).
3247
3257
  */
3248
3258
  declare function validateColumnarStructure(snapshot: ColumnarGraphSnapshot<unknown, unknown>): ColumnarIssue[];
@@ -3266,7 +3276,7 @@ declare function buildAcceptedFromColumnar<N, E>(snapshot: ColumnarGraphSnapshot
3266
3276
  declare function columnarArrayBuffers(snapshot: ColumnarGraphSnapshot<unknown, unknown>): ArrayBuffer[];
3267
3277
  /**
3268
3278
  * `bufferOwnership: 'transfer'` — detach every underlying ArrayBuffer.
3269
- * Called ONLY after validation and admission both succeeded (ADR-006 D4:
3279
+ * Called ONLY after validation and admission both succeeded:
3270
3280
  * reject-before-allocation extends to reject-before-detach). Returns the
3271
3281
  * number of buffers detached. SharedArrayBuffer-backed views are skipped
3272
3282
  * (they cannot detach and remain shared by contract).
@@ -3274,8 +3284,8 @@ declare function columnarArrayBuffers(snapshot: ColumnarGraphSnapshot<unknown, u
3274
3284
  declare function detachColumnarBuffers(snapshot: ColumnarGraphSnapshot<unknown, unknown>): number;
3275
3285
 
3276
3286
  /**
3277
- * §17 serializable field descriptors (S13-T01, ADR-006 D1) — the worker-lane
3278
- * accessor forms: `FieldAccessor` + `SerializableTransform` + the `field()`
3287
+ * serializable field descriptors — the worker-lane
3288
+ * accessor forms: `FieldAccessor` + `SerializableTransform` + the `field`
3279
3289
  * manual-schema helper. Descriptors are DATA, never code: they cross the
3280
3290
  * worker boundary by structured clone, compare by canonical structural
3281
3291
  * value, and unknown transform ops are validation errors (spec: "descriptors
@@ -3293,14 +3303,14 @@ declare function detachColumnarBuffers(snapshot: ColumnarGraphSnapshot<unknown,
3293
3303
  * projection ever runs.
3294
3304
  */
3295
3305
 
3296
- /** Branded attr path — `field<A,T>()` is a manual-schema ASSERTION (compile
3297
- * -time narrowing for codegen/schema packages), not runtime validation. */
3306
+ /** Branded attr path — `field<A,T>` is a manual-schema ASSERTION for
3307
+ * compile-time narrowing in codegen/schema packages, not runtime validation. */
3298
3308
  type TypedFieldPath<A, T> = string & {
3299
3309
  readonly __attrs?: A;
3300
3310
  readonly __value?: T;
3301
3311
  };
3302
3312
  declare function field<A, T>(path: string): TypedFieldPath<A, T>;
3303
- /** §17 transform whitelist. Closed set — extending it is a spec amendment. */
3313
+ /** transform whitelist. Closed set — extending it is a spec amendment. */
3304
3314
  type SerializableTransform = {
3305
3315
  op: 'identity';
3306
3316
  } | {
@@ -3347,7 +3357,7 @@ declare function isFieldAccessor(value: unknown): value is FieldAccessor<unknown
3347
3357
  declare function descriptorKey(accessor: FieldAccessor<unknown, unknown>): string;
3348
3358
  /**
3349
3359
  * Evaluate a descriptor against an entity's `(id, attrs)` — the pure
3350
- * function both lanes share (ADR-006 D2: byte-exact parity starts with ONE
3360
+ * function both lanes share (byte-exact parity starts with ONE
3351
3361
  * evaluation implementation, imported by both threads, never duplicated).
3352
3362
  */
3353
3363
  declare function evaluateFieldAccessor(accessor: FieldAccessor<unknown, unknown>, id: string, attrs: Readonly<Record<string, unknown>> | undefined): unknown;