@modernrelay/orbit-core 0.13.6 → 0.14.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,7 +603,7 @@ type ViewBrushState = {
603
603
  interface ViewLayoutSpec {
604
604
  kind: 'force' | 'fixed';
605
605
  }
606
- /** §11 Scale subset that is data by construction (no functions). */
606
+ /** Scale subset that is data by construction (no functions). */
607
607
  type SerializableScale = {
608
608
  kind: 'sequential' | 'diverging';
609
609
  metric: string;
@@ -630,16 +630,16 @@ interface GraphViewState {
630
630
  camera: ViewportState | null;
631
631
  selection: SelectionState;
632
632
  hiddenNodeIds: readonly NodeId[];
633
- /** §9.2 isolation; null = full scope. */
633
+ /** isolation; null = full scope. */
634
634
  subgraph: SubgraphSpec | null;
635
635
  /** Manual groups verbatim, or — under `groupBy` — `{key, collapsed}` pairs
636
- * only (membership recomputes from current data on restore, R-16.3-16). */
636
+ * only (membership recomputes from current data on restore). */
637
637
  groups: readonly GroupSpec[] | ReadonlyArray<{
638
638
  key: string;
639
639
  collapsed: boolean;
640
640
  }>;
641
641
  pinnedNodeIds: readonly NodeId[];
642
- /** §16.3 node folds: anchor → declared members (v1 extension, see header). */
642
+ /** node folds: anchor → declared members (v1 extension, see header). */
643
643
  folds?: ReadonlyArray<readonly [NodeId, readonly NodeId[]]>;
644
644
  layout: ViewLayoutSpec;
645
645
  /** Declaration order; a key absent here has no brush. */
@@ -653,7 +653,7 @@ interface GraphViewState {
653
653
  positions?: ReadonlyArray<readonly [string, number, number]>;
654
654
  styling?: ViewStyling;
655
655
  /** Host-owned durable source coordinate — stored verbatim, NEVER
656
- * interpreted; compared canonically on restore (§16.14). */
656
+ * interpreted; compared canonically on restore. */
657
657
  dataRef?: JsonValue;
658
658
  }
659
659
  declare const VIEW_STATE_VERSION: 1;
@@ -664,8 +664,8 @@ declare const VIEW_STATE_VERSION: 1;
664
664
  * their canonical strings are identical.
665
665
  */
666
666
  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
667
+ /** Canonical equality for dataRef values: key order never matters.
668
+ * A non-JSON value (cycles included) is never equal to anything — the
669
669
  * "compared, never interpreted" rule extended to malformed input. */
670
670
  declare function sameDataRef(a: JsonValue | undefined, b: JsonValue | undefined): boolean;
671
671
  type ViewStateVerdict = {
@@ -677,7 +677,7 @@ type ViewStateVerdict = {
677
677
  problems: readonly string[];
678
678
  };
679
679
  /**
680
- * Full structural validation + version gate. Order per §16.14: version first
680
+ * Full structural validation + version gate. Order per version first
681
681
  * (higher-than-known and non-numeric reject as `unsupported-version` /
682
682
  * `invalid-view-state` BEFORE field checks), then per-field structure. Lower
683
683
  * versions run the migration registry, then re-validate at the current shape.
@@ -693,7 +693,7 @@ type SetViewStateResult = {
693
693
  } | {
694
694
  status: 'rejected';
695
695
  code: 'invalid-view-state' | 'unsupported-version'
696
- /** The state touches a §6.4 controlled slice or carries styling the
696
+ /** The state touches a controlled slice or carries styling the
697
697
  * host must reflect, and no aggregate restore callback exists. */
698
698
  | 'missing-restore-callback'
699
699
  /** Another restore/history transaction is awaiting acknowledgement. */
@@ -706,28 +706,28 @@ type SetViewStateResult = {
706
706
  };
707
707
 
708
708
  /**
709
- * §6 GraphInstance — the public headless core instance (v0.3 subset).
709
+ * GraphInstance — the public headless core instance (v0.3 subset).
710
710
  *
711
711
  * One `applyHostUpdate` call is the atomic host boundary: it validates,
712
712
  * 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).
713
+ * `set` and AT MOST ONE engine commit, so a simultaneous data + style +
714
+ * controlled-state change can never tear across frames.
715
715
  *
716
- * Vanilla zustand only — no React, no DOM access at module scope (§18).
716
+ * Vanilla zustand only — no React, no DOM access at module scope.
717
717
  */
718
718
 
719
- /** §8 dark base theme (the default when no base is named). */
719
+ /** dark base theme (the default when no base is named). */
720
720
  declare const GRAPH_THEME_DARK: GraphTheme;
721
- /** §8 light base theme. */
721
+ /** light base theme. */
722
722
  declare const GRAPH_THEME_LIGHT: GraphTheme;
723
723
  /**
724
- * Resolve a ThemeInput to a full GraphTheme (§8): pick the named base
724
+ * Resolve a ThemeInput to a full GraphTheme: pick the named base
725
725
  * (default dark), then merge every defined token over it. A full GraphTheme
726
726
  * input resolves to exactly its own tokens; `undefined` resolves to the dark
727
727
  * base; the v0.1 `{background}` compat shorthand merges as a partial.
728
728
  */
729
729
  declare function resolveTheme(input?: ThemeInput): GraphTheme;
730
- /** One categorical legend row (§11): declared-domain rows first (including
730
+ /** One categorical legend row: declared-domain rows first (including
731
731
  * currently-empty categories), then extra seen values sorted. */
732
732
  interface ScaleInfoRow {
733
733
  value: string;
@@ -745,50 +745,50 @@ interface ScaleChannelInfo<N = Record<string, unknown>> {
745
745
  /** Categorical rows; omitted for sequential/diverging scales. */
746
746
  rows?: readonly ScaleInfoRow[];
747
747
  }
748
- /** §9.2 revision-aware service seam (expansion since v0.5, search since S11). */
748
+ /** Revision-aware service seam for expansion and search. */
749
749
  interface GraphServices<N = Record<string, unknown>, E = Record<string, unknown>> {
750
750
  /**
751
751
  * Ego-expansion resolver for `expandNode` / `SubgraphSpec.hops`. Default:
752
- * the built-in LOCAL service — it walks the core's §7.1 adjacency over the
752
+ * the built-in LOCAL service — it walks the core's adjacency over the
753
753
  * accepted model, INCLUDING currently out-of-scope nodes (zero config,
754
754
  * zero network; the core still never fetches).
755
755
  */
756
756
  expansion?: ExpansionService<N, E>;
757
757
  /**
758
- * §16.2 path resolver for `findPath`. Default: the built-in LOCAL
758
+ * path resolver for `findPath`. Default: the built-in LOCAL
759
759
  * unweighted BFS over the loaded VISIBLE edge list, respecting
760
760
  * PathOptions.direction. Revision-aware: a result arriving after a
761
- * dataset replacement is discarded at admission (S12-T08).
761
+ * dataset replacement is discarded at admission.
762
762
  */
763
763
  path?: PathService;
764
764
  /**
765
- * §16.5 search resolver for `instance.search`. Default: the built-in LOCAL
765
+ * search resolver for `instance.search`. Default: the built-in LOCAL
766
766
  * indexed service over the accepted model plus the host's declared
767
767
  * `searchIndex` fields (id-only when never declared — it never guesses
768
768
  * 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
769
+ * server-side search (such as Omnigraph stored queries) with the same
770
+ * instance-side correctness: RequestContext, revision-keyed caching, supersede
771
771
  * cancellation, stale rejection at admission.
772
772
  */
773
773
  search?: SearchService<N>;
774
774
  }
775
775
  interface CreateGraphInstanceOptions<N = Record<string, unknown>, E = Record<string, unknown>> {
776
- /** Called once per mount; a re-attach constructs a fresh engine (§6). */
776
+ /** Called once per mount; a re-attach constructs a fresh engine. */
777
777
  engine: EngineFactory;
778
778
  /** Fit the camera once when the first data-bearing commit reaches a fresh engine. Default true. */
779
779
  fitViewOnFirstData?: boolean;
780
- /** §9.2 revision-aware services (expansion + §16.5 search). */
780
+ /** revision-aware services (expansion + search). */
781
781
  services?: GraphServices<N, E>;
782
782
  /**
783
- * §16.5 node attr fields the DEFAULT search service indexes (ids always;
783
+ * node attr fields the DEFAULT search service indexes (ids always;
784
784
  * absent = id-only — the service never guesses attr names). CONSTRUCTION-
785
- * ONLY per the spec's host construction options (D7): read once here;
785
+ * ONLY as a host construction option: read once here;
786
786
  * changing it requires a keyed remount / replacement instance. A runtime
787
787
  * `applyHostUpdate` attempt is ignored with a one-shot warning.
788
788
  */
789
789
  searchIndex?: readonly string[];
790
790
  /**
791
- * §16.14 undo/redo (S9-T20). Default true. `false` makes the history
791
+ * undo/redo. Default true. `false` makes the history
792
792
  * surface inert (record/undo/redo no-ops, depths stay 0); an object sets
793
793
  * the stack bound (default {@link HISTORY_LIMIT_DEFAULT} entries).
794
794
  */
@@ -796,42 +796,42 @@ interface CreateGraphInstanceOptions<N = Record<string, unknown>, E = Record<str
796
796
  limit?: number;
797
797
  };
798
798
  /**
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
799
+ * Degradation-ladder thresholds. CONSTRUCTION-ONLY: read once; invalid
800
+ * fields fall back to the defaults with ONE
801
801
  * config warning diagnostic. A runtime change requires a keyed remount.
802
802
  */
803
803
  limits?: Partial<ScaleLimits>;
804
804
  /**
805
- * §8 image-atlas resolver seam (S10): owns authenticated fetch/caching for
805
+ * Image-atlas resolver seam: owns authenticated fetch/caching for
806
806
  * one `nodeImage` ref. Default: plain `fetch(ref)` for public URLs.
807
807
  * Injectable for tests and authenticated hosts.
808
808
  */
809
809
  imageResolver?: ImageResolver;
810
810
  /**
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
811
+ * Execution mode. Current worker cargo is columnar ACCEPTANCE: validation,
812
+ * deduplication, and link resolution run off-thread, then land through
813
+ * revision-gated async admission. 'main' (default) keeps every
814
814
  * columnar ingest synchronous; 'auto' and 'worker' route columnar data
815
815
  * through the worker lane when it boots — an unavailable lane degrades
816
816
  * 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).
817
+ * and an ERROR diagnostic under 'worker'. Columnar acceptance may still
818
+ * fall back because it has no worker-required mode; channel projection
819
+ * remains on the main thread.
820
820
  */
821
821
  execution?: 'auto' | 'main' | 'worker';
822
- /** ADR-006 D5 worker construction tri-option (URL / factory / inline
822
+ /** Worker construction tri-option (URL / factory / inline
823
823
  * default). Testing seam: `transport` on the lane via this factory. */
824
824
  workerFactory?: WorkerFactoryOption;
825
825
  }
826
826
  /**
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.
827
+ * `expandNode` outcome:
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; no session was opened and 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
835
  */
836
836
  type ExpandNodeResult = {
837
837
  added: number;
@@ -841,7 +841,7 @@ type ExpandNodeResult = {
841
841
  noop: true;
842
842
  };
843
843
  /**
844
- * §9.2 expansion bookkeeping: one committed expansion overlay. Data-merging
844
+ * expansion bookkeeping: one committed expansion overlay. Data-merging
845
845
  * batches carry the request id (overlayId + batch ids) and provenance into
846
846
  * ingestion so abort, rollback, and removeOverlay remove the exact
847
847
  * contribution they own.
@@ -855,11 +855,11 @@ interface ExpansionOverlayRecord {
855
855
  provenance?: unknown;
856
856
  }
857
857
  /**
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.
858
+ * 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.
863
863
  * Both replay the current state synchronously on subscribe. The emitted array
864
864
  * and its placement objects are REUSED across position ticks — copy if you
865
865
  * need a snapshot.
@@ -869,20 +869,20 @@ interface LabelSubscriptions {
869
869
  subscribePositions(cb: (list: readonly LabelPlacement[]) => void): () => void;
870
870
  }
871
871
  interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>> {
872
- /** Vanilla zustand store — the single observable state surface (§6.3). */
872
+ /** Vanilla zustand store — the single observable state surface. */
873
873
  readonly store: StoreApi<GraphStoreState>;
874
- /** §14 DOM label lane (overlay scheduler output). */
874
+ /** DOM label lane (overlay scheduler output). */
875
875
  readonly labels: LabelSubscriptions;
876
- /** Atomic host transaction: one store publication, at most one engine commit (§6). */
876
+ /** Atomic host transaction: one store publication, at most one engine commit. */
877
877
  applyHostUpdate(update: GraphHostUpdate<N, E>): void;
878
878
  /**
879
- * §7.5 revisioned ingestion: begin a bounded, cancellable session against an
879
+ * revisioned ingestion: begin a bounded, cancellable session against an
880
880
  * explicit `datasetKey` and `baseModelRevision` (compare-and-set; mismatch
881
881
  * throws 'stale-revision'). Overlay sessions must name the CURRENT
882
882
  * datasetKey; replace sessions may establish a new one and are always
883
883
  * atomic.
884
884
  *
885
- * T16 rule: while a declarative data source is actively driving (a snapshot
885
+ * While a declarative data source is actively driving (a snapshot
886
886
  * was applied through `applyHostUpdate` and has not been superseded by a
887
887
  * committed replace session), `purpose:'replace'` is rejected at begin with
888
888
  * a TypeError — two writers may not race for the base. Overlay ingestion
@@ -890,11 +890,11 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
890
890
  *
891
891
  * Every session admission/publication is serialized through the
892
892
  * instance-local acceptance queue; arrival there is the global admission
893
- * order (§7.5).
893
+ * order.
894
894
  */
895
895
  beginIngest(opts: BeginIngestOptions): IngestSession<N, E>;
896
896
  /**
897
- * §7.5: atomically remove exactly one committed overlay — re-runs collision
897
+ * atomically remove exactly one committed overlay — re-runs collision
898
898
  * and endpoint resolution, promotes formerly shadowed rows from surviving
899
899
  * overlays, advances model/render revisions, and releases the overlayId for
900
900
  * deliberate reuse. Unknown ids are an idempotent `{ removed: false }`.
@@ -902,14 +902,14 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
902
902
  removeOverlay(overlayId: string): {
903
903
  removed: boolean;
904
904
  };
905
- /** Committed overlay ids for the current dataset (§7.5). */
905
+ /** Committed overlay ids for the current dataset. */
906
906
  getOverlayIds(): readonly string[];
907
907
  attach(container: HTMLElement): Promise<void>;
908
908
  detach(): void;
909
909
  destroy(): void;
910
910
  /**
911
- * §15 typed events: listeners run SYNCHRONOUSLY in registration order; the
912
- * control's preventDefault() cancels ONLY the built-in follow-up (click
911
+ * typed events: listeners run SYNCHRONOUSLY in registration order; the
912
+ * control's preventDefault cancels ONLY the built-in follow-up (click
913
913
  * selection, drag pin), never other listeners.
914
914
  */
915
915
  on<K extends GraphEventName>(name: K, cb: (payload: GraphEventMap<N, E>[K], control: GraphListenerControl) => void): () => void;
@@ -918,51 +918,51 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
918
918
  zoomOut(): void;
919
919
  setViewport(v: Partial<ViewportState>): void;
920
920
  /**
921
- * §16 focus neighborhood (T10): keep the v0.1 camera behavior
921
+ * Focus neighborhood: keep the v0.1 camera behavior
922
922
  * (setFocusedIndex + zoomToIndex) and RETURN the 1-hop neighbor ids
923
923
  * (engine adjacency when available, else the core CSR adjacency).
924
924
  *
925
- * Documented compromise: the engine exposes ONE highlight channel until S10
926
- * styling lands, so the neighbor ring is pushed through setSelectedIndices
925
+ * Documented compromise: the engine exposes ONE highlight channel, so the
926
+ * neighbor ring is pushed through setSelectedIndices
927
927
  * ONLY when that cannot lie about real selection state — selection empty
928
928
  * and uncontrolled. The ring is a visual, never a store write; the next
929
929
  * selection push overwrites it. Opt out via `highlightNeighbors: false`.
930
- * `hops` is reserved at 1 until multi-hop lands.
930
+ * Only `hops: 1` is currently supported.
931
931
  */
932
932
  focusNode(id: NodeId, opts?: {
933
933
  highlightNeighbors?: boolean;
934
934
  hops?: 1;
935
935
  }): readonly NodeId[];
936
936
  /**
937
- * §13 emphasis ring WITHOUT the camera: ring `id` (null clears). The light
937
+ * emphasis ring WITHOUT the camera: ring `id` (null clears). The light
938
938
  * op keyboard navigation needs — arrowing a list must not fly the camera on
939
939
  * every keystroke (`focusNode` stays ring + zoom + neighbors). Unknown ids
940
940
  * are a silent no-op (a stale row racing a model swap is data, not an
941
941
  * error); `emphasisRing: false` suppresses it entirely. The target is
942
942
  * STICKY: it survives structural commits and context recovery until it is
943
943
  * cleared, its id departs the model, or pointer hover supersedes it
944
- * (emphasis belongs to the latest action — the §16.2 rule).
944
+ * (emphasis belongs to the latest action — the rule).
945
945
  */
946
946
  emphasizeNode(id: NodeId | null): void;
947
947
  /**
948
- * §14/§15 typed context-menu channel, opened from a DOM presenter. Label
948
+ * Typed context-menu channel, opened from a DOM presenter. Label
949
949
  * divs are `pointerEvents: 'auto'` by design (click-to-focus), so a
950
950
  * right-click on one never reaches the engine canvas — without this seam
951
951
  * the nodes prominent enough to carry labels are exactly the ones whose
952
952
  * right-click falls through to the browser's native menu. Emits the SAME
953
953
  * 'contextMenu' event the canvas gesture produces; `screen` is
954
- * container-relative CSS px (the §15 payload contract). Unknown ids are a
954
+ * container-relative CSS px. Unknown ids are a
955
955
  * silent no-op (a stale label racing a model swap is data, not an error).
956
956
  */
957
957
  requestNodeContextMenu(id: NodeId, screen: readonly [number, number]): void;
958
958
  setSelection(ids: readonly NodeId[] | SelectionState): void;
959
959
  selectNodes(ids: readonly NodeId[]): void;
960
960
  selectEdges(ids: readonly EdgeId[]): void;
961
- /** §16.2 group namespace (S12-T02): validate against the CURRENT resolved
961
+ /** group namespace: validate against the CURRENT resolved
962
962
  * groups (unknown ids dropped, duplicates collapse) and store in
963
963
  * groups-array order — the group analog of accepted-base ordering. Never
964
964
  * touches the node/edge namespaces; the group namespace is always
965
- * instance-owned (§6.4 controlled selection covers nodes only). */
965
+ * instance-owned. */
966
966
  selectGroups(ids: readonly string[]): void;
967
967
  /** Expand to the 1-hop neighborhood of `id` (or of the current selection). */
968
968
  selectNeighbors(id?: NodeId): void;
@@ -970,9 +970,9 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
970
970
  invertSelection(): void;
971
971
  clearSelection(): void;
972
972
  /**
973
- * §16.2 lasso (S6-T05): resolve the SCREEN-coordinate polygon to node ids
973
+ * lasso: resolve the SCREEN-coordinate polygon to node ids
974
974
  * via `engine.pointsInPolygon`, drop hidden ids, then replace (default) or
975
- * union (`additive`) the node selection through the same §6.4 ownership
975
+ * union (`additive`) the node selection through the same ownership
976
976
  * path as every other mutator (controlled → intent only). Returns the
977
977
  * resolved lasso ids (accepted-base order) regardless of ownership; empty
978
978
  * when the engine is not ready or lacks `pointsInPolygon`.
@@ -992,19 +992,19 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
992
992
  * tolerance. No-op (null) on the native route. */
993
993
  sampleEdgeClick(screen: readonly [number, number]): AcceptedEdge<E> | null;
994
994
  /**
995
- * @internal §15/§17 shared hit-test/overlay cadence: the count of engine
995
+ * @internal Shared hit-test/overlay cadence: the count of engine
996
996
  * onFrame ticks this session. THE one clock every sampling route throttles
997
997
  * 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.
998
+ * no second cadence timer anywhere; the lint rule enforces it).
999
+ * The degradation ladder's defer-link-picking step arms/disarms against this counter;
1000
+ * telemetry reads it for idle-wakeup accounting.
1001
1001
  */
1002
1002
  getFrameCadence(): number;
1003
1003
  /**
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.
1004
+ * @internal 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. telemetry
1007
+ * will fold these into `lastCommitMs`-adjacent accounting.
1008
1008
  */
1009
1009
  getPerfCounters(): Readonly<{
1010
1010
  brushSlotsTranslated: number;
@@ -1014,12 +1014,12 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1014
1014
  fullEdgeRecomposes: number;
1015
1015
  }>;
1016
1016
  /**
1017
- * §17 telemetry snapshot (S13-T07): counts, byte estimates, queue depth,
1017
+ * telemetry snapshot: counts, byte estimates, queue depth,
1018
1018
  * revisions, last-commit phase decomposition, active ladder steps,
1019
1019
  * execution lane, range availability, and the pressure mirror — never raw
1020
1020
  * attrs or ids. Synchronous in every lifecycle state (pre-scene fields
1021
1021
  * read zero/absent). `validate` is folded into `derive` until the
1022
- * columnar lane splits acceptance from derivation (PR-E).
1022
+ * columnar lane splits acceptance from derivation.
1023
1023
  */
1024
1024
  getPerfSnapshot(): GraphPerfSnapshot;
1025
1025
  hideNodes(ids: readonly NodeId[]): void;
@@ -1028,24 +1028,24 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1028
1028
  pinNode(id: NodeId, xy?: readonly [number, number]): void;
1029
1029
  unpinNode(id: NodeId): void;
1030
1030
  clearPins(): void;
1031
- /** §16.3 PERSISTENT pins (S12-T09): pin ids AT THEIR CURRENT POSITION via
1031
+ /** PERSISTENT pins: pin ids AT THEIR CURRENT POSITION via
1032
1032
  * engine.setPinnedIndices — no position payload in v0.10. Independent of
1033
1033
  * 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
1034
+ * slices, so releasing a drag pin leaves a persistent pin held.
1035
1035
  * ownership mirrors groups: once the host supplies `pinnedNodeIds` (null
1036
1036
  * included) the ops fire the 'pinnedChange' intent instead of writing.
1037
1037
  * Unknown ids drop; departed ids prune through the ownership path on
1038
- * model changes (R-16.3-25). */
1038
+ * model changes. */
1039
1039
  pinNodes(ids: readonly NodeId[]): void;
1040
1040
  /** Release persistent pins (see {@link pinNodes}); unpinned ids no-op. */
1041
1041
  unpinNodes(ids: readonly NodeId[]): void;
1042
- /** Add one group definition (same §16.3 acyclic/singly-parented validation as the
1042
+ /** Add one group definition (same acyclic/singly-parented validation as the
1043
1043
  * `groups` prop — a violating spec is ONE 'config-error' and a no-op). */
1044
1044
  groupNodes(spec: GroupSpec): void;
1045
1045
  /** Remove one group definition; its id prunes from SelectionState.groupIds
1046
1046
  * through the ownership path. Unknown ids no-op (dev-mode warning). */
1047
1047
  ungroup(groupId: string): void;
1048
- /** Collapse/expand one group as a §7.2 structural diff. Works on manual
1048
+ /** Collapse/expand one group as a structural diff. Works on manual
1049
1049
  * groups AND groupBy-derived groups (the residue toggle). Same-value
1050
1050
  * calls are exact no-ops (zero publishes, zero commits). */
1051
1051
  setGroupCollapsed(groupId: string, collapsed: boolean): void;
@@ -1059,12 +1059,12 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1059
1059
  * rejected, since that would close a containment cycle).
1060
1060
  *
1061
1061
  * 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.
1062
+ * an exact no-op. Records a 'folds' history step.
1063
1063
  */
1064
1064
  foldNode(id: NodeId, opts?: {
1065
1065
  memberIds?: readonly NodeId[];
1066
1066
  }): void;
1067
- /** Unfolds `id`, returning its members to the scene as a §7.2 structural
1067
+ /** Unfolds `id`, returning its members to the scene as a structural
1068
1068
  * diff. Unknown or unfolded ids are exact no-ops. */
1069
1069
  unfoldNode(id: NodeId): void;
1070
1070
  /** The members `id` currently stands for, or null when it is not folded.
@@ -1075,30 +1075,30 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1075
1075
  } | null;
1076
1076
  /** Current stage-4 clusters over the physical scene: ordered keys, member
1077
1077
  * 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
1078
+ * centroid (null until a readback or a fixed-layout commit). Empty
1079
1079
  * 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). */
1080
+ * scene is byte-identical with and without a spec. */
1081
1081
  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
1082
+ /** resolve a cluster (by key) to its MEMBER node ids and write
1083
+ * them into SelectionState.nodeIds through the standard ownership
1084
1084
  * path — clusters have no id namespace of their own in selection.
1085
1085
  * `additive` unions with the current node selection. Unknown keys no-op. */
1086
1086
  selectCluster(key: string, opts?: {
1087
1087
  additive?: boolean;
1088
1088
  }): void;
1089
1089
  /**
1090
- * §9.2 isolate: hard-scope the graph to the CURRENT node selection
1090
+ * isolate: hard-scope the graph to the CURRENT node selection
1091
1091
  * `subgraph: { seedIds: selection.nodeIds }` through the SAME path as the
1092
1092
  * host-update prop. No-op when nothing is selected. Ownership note (v0.5):
1093
1093
  * `subgraph` is UNCONTROLLED-ONLY — always instance-owned; the prop and
1094
1094
  * this method write the same state, last writer wins.
1095
1095
  */
1096
1096
  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). */
1097
+ /** clear the hard scope (`subgraph: null`) — the full accepted model
1098
+ * returns with cached positions. */
1099
1099
  resetIsolation(): void;
1100
1100
  /**
1101
- * §9.2/§16.3 ego-expansion of `id` (default 1 hop) through the configured
1101
+ * Ego-expansion of `id` (default 1 hop) through the configured
1102
1102
  * ExpansionService. The result is gated by admission (declared revision
1103
1103
  * dependencies + dataset lineage + seed existence — abort is only an
1104
1104
  * optimization) and merges through ONE awaited atomic overlay
@@ -1117,8 +1117,8 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1117
1117
  * Undoes `id`'s own expansions — the navigation Back button, NOT a
1118
1118
  * containment operation. Aborts `id`'s pending expansion AND explicitly
1119
1119
  * 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
1120
+ * accretion). Committed overlay DATA otherwise persists until
1121
+ * `removeOverlay()` or a replacing snapshot; this IS that explicit removal for
1122
1122
  * expansion overlays.
1123
1123
  *
1124
1124
  * On a node that was never expanded from, this does nothing — there is no
@@ -1127,7 +1127,7 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1127
1127
  * different word for navigation history.
1128
1128
  */
1129
1129
  retractExpansion(id: NodeId): void;
1130
- /** §9.2 expansion bookkeeping for `id`: committed overlay records with
1130
+ /** expansion bookkeeping for `id`: committed overlay records with
1131
1131
  * request id, provenance, and the ids each expansion revealed. */
1132
1132
  getExpansionOverlays(id: NodeId): readonly ExpansionOverlayRecord[];
1133
1133
  /**
@@ -1136,21 +1136,21 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1136
1136
  * `serviceCacheKey` over EXACTLY the service's declared revision
1137
1137
  * dimensions ({@link SEARCH_CACHE_LIMIT}-entry LRU; a second call with an
1138
1138
  * 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
1139
+ * cancels superseded work (a NEWER query aborts the older in-flight call
1140
1140
  * the older promise rejects `OrbitOperationError {code:'aborted'}`), and
1141
1141
  * rejects stale results at admission (declared revision drift or dataset
1142
1142
  * lineage change → the same typed 'aborted' rejection with a distinct
1143
1143
  * staleness message; the store is untouched). A successful search
1144
1144
  * publishes `store.search = {query, results}` — `node` populated for
1145
1145
  * in-model ids — in ONE store publication. Search NEVER changes
1146
- * scope/filter semantics and never fetches graph data (§16.5).
1146
+ * scope/filter semantics and never fetches graph data.
1147
1147
  */
1148
1148
  search(query: string, opts?: {
1149
1149
  limit?: number;
1150
1150
  }): Promise<readonly SearchResult<N>[]>;
1151
1151
  /** Clear `store.search` to null (e.g. the <GraphSearch> input emptied). */
1152
1152
  clearSearch(): void;
1153
- /** §16.2 path query + atomic emphasis (S12-T08): resolves via the path
1153
+ /** path query + atomic emphasis: resolves via the path
1154
1154
  * service (local BFS default); null = unreachable (a RESULT). Emphasis is
1155
1155
  * session-local — released by clearPath, any selection mutation, undo/
1156
1156
  * redo, or a scene rebuild; never a history step; never serialized. */
@@ -1158,21 +1158,21 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1158
1158
  clearPath(): void;
1159
1159
  getActivePath(): PathResult | null;
1160
1160
  /**
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'}`.
1161
+ * Result contract: a result id in the current rendered scene
1162
+ * AND mask-visible is focused (`focusNode`) → `{status:'focused'}`.
1163
1163
  * Otherwise classification ONLY — 'not-loaded' (absent from the accepted
1164
1164
  * model), 'out-of-scope' (in the model but outside the hard scope),
1165
1165
  * 'filtered' (in the scene but mask-hidden). Never mutates scope or
1166
- * filters — the host reacts explicitly (§16.5).
1166
+ * filters — the host reacts explicitly.
1167
1167
  */
1168
1168
  activateSearchResult(result: SearchResult<N>): SearchActivation;
1169
1169
  pauseSimulation(): void;
1170
1170
  resumeSimulation(): void;
1171
1171
  isSimulationRunning(): boolean;
1172
- /** §16.1 screenshot: delegates to the engine; null when unsupported/not ready. */
1172
+ /** screenshot: delegates to the engine; null when unsupported/not ready. */
1173
1173
  captureScreenshot(): Promise<Blob | null>;
1174
1174
  /**
1175
- * §15.1 binding-detected reduced-motion media preference. The EFFECTIVE
1175
+ * binding-detected reduced-motion media preference. The EFFECTIVE
1176
1176
  * value is `accessibility.reducedMotion ?? v` — when reduced, camera
1177
1177
  * durations (fitView/setViewport/focusNode) coerce to 0.
1178
1178
  */
@@ -1180,7 +1180,7 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1180
1180
  /**
1181
1181
  * The crossfilter session facade, or null until the `crossfilter` prop has
1182
1182
  * configured dimensions over an accepted base. Delegates to the
1183
- * typed-column engine; `setBrush` routes visibility deltas into the §9.1
1183
+ * typed-column engine; `setBrush` routes visibility deltas into the
1184
1184
  * soft mask (buffers-only commit, zero relayout) and resolves after the
1185
1185
  * publish. Brush slot deltas are BASE indices; under a hard scope
1186
1186
  * out-of-scope rows have no scene slot and simply do not mask anything.
@@ -1200,12 +1200,12 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1200
1200
  /** Re-apply the most recently undone entry. False when nothing to redo. */
1201
1201
  redo(): boolean;
1202
1202
  /**
1203
- * Serialize the exploration state (§16.14): camera, selection, hidden ids,
1203
+ * Serialize the exploration state: camera, selection, hidden ids,
1204
1204
  * isolation, groups (manual specs verbatim; under `groupBy` only collapsed
1205
1205
  * `{key, collapsed}` pairs — membership recomputes on restore), pins,
1206
1206
  * folds, layout, crossfilter brushes in declaration order, the Scale-valued
1207
1207
  * styling subset, and the host's `dataRef` verbatim. The predicate `filter`
1208
- * and §16.3 expansion records are never serialized. The sync form carries
1208
+ * and expansion records are never serialized. The sync form carries
1209
1209
  * no positions: reproduction is best-effort via the layout descriptor.
1210
1210
  */
1211
1211
  getViewState(opts?: {
@@ -1213,7 +1213,7 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1213
1213
  }): GraphViewState;
1214
1214
  /**
1215
1215
  * Async form: additionally embeds quantized coordinates for the VISIBLE
1216
- * (post-mask) set, read once from the engine (per-event readback, ADR-001).
1216
+ * (post-mask) set, read once from the engine as event-time readback.
1217
1217
  * Restores as a frozen fixed-equivalent — pixel-faithful regardless of
1218
1218
  * engine nondeterminism. Past `maxPositions` (default 100 000) the call
1219
1219
  * rejects `export-materialization-too-large`; persist the layout through
@@ -1224,7 +1224,7 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1224
1224
  maxPositions?: number;
1225
1225
  }): Promise<GraphViewState>;
1226
1226
  /**
1227
- * Atomically restore a serialized view (§16.14). NEVER partially applies:
1227
+ * Atomically restore a serialized view. NEVER partially applies:
1228
1228
  * structural validation and the version gate run first (reject whole with
1229
1229
  * one 'invalid-view-state' diagnostic); then the dataRef canonical
1230
1230
  * comparison — a mismatch fires the 'viewStateMismatch' event INSTEAD of
@@ -1233,7 +1233,7 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1233
1233
  * undo/redo uses, so a restore is itself undoable. Embedded positions
1234
1234
  * apply as a frozen fixed-equivalent (one replay-style commit, then the
1235
1235
  * simulation pauses — a later explicit layout change or reheat unfreezes).
1236
- * A state touching a §6.4 controlled slice (or styling, once a restore
1236
+ * A state touching a controlled slice (or styling, once a restore
1237
1237
  * callback exists) resolves 'missing-restore-callback' until the aggregate
1238
1238
  * protocol is registered.
1239
1239
  */
@@ -1272,14 +1272,14 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1272
1272
  * entity over ONE pinned revision — a mid-stream commit never mixes
1273
1273
  * epochs. Closing the generator releases the pin. */
1274
1274
  exportDataStream(scope?: 'visible' | 'accepted'): AsyncGenerator<string, void, undefined>;
1275
- /** Bounded id → [x, y] map from one position readback (§7.1 per-event). */
1275
+ /** Bounded id → [x, y] map from one position readback. */
1276
1276
  exportLayout(opts?: {
1277
1277
  limit?: number;
1278
1278
  }): Promise<ReadonlyMap<NodeId, readonly [number, number]>>;
1279
1279
  /** Memory-bounded `{"id","x","y"}` JSONL over one pinned readback. */
1280
1280
  exportLayoutStream(): AsyncGenerator<string, void, undefined>;
1281
1281
  /**
1282
- * §11 legend surface: the active Scale on a styling channel plus its
1282
+ * legend surface: the active Scale on a styling channel plus its
1283
1283
  * resolved domain (sequential/diverging — resolved through the SAME frozen
1284
1284
  * DomainStore coordinate the projection uses) or categorical legend rows
1285
1285
  * (declared-domain order first including empty categories, then extra seen
@@ -1288,9 +1288,9 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1288
1288
  */
1289
1289
  getScaleInfo(channel: 'nodeColor' | 'nodeSize'): ScaleChannelInfo<N> | null;
1290
1290
  /**
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.
1291
+ * metric read for one node id via the core id→index map (never a
1292
+ * public million-entry Map). Null for unknown ids, unknown metrics, and
1293
+ * null values; lazily computes the degree family on first use.
1294
1294
  */
1295
1295
  getMetricValue(metric: MetricName, id: NodeId): number | null;
1296
1296
  getRevisions(): Revisions;
@@ -1300,54 +1300,54 @@ interface GraphInstance<N = Record<string, unknown>, E = Record<string, unknown>
1300
1300
  * way a hover/selection consumer resolves `store.hover.edgeId` or
1301
1301
  * `selection.edgeIds` to real records. Undefined for unknown ids. */
1302
1302
  getEdge(id: EdgeId): AcceptedEdge<E> | undefined;
1303
- /** Scene ids that are §9.1 mask-visible (scope ∧ mask), scene order. */
1303
+ /** Scene ids that are mask-visible (scope ∧ mask), scene order. */
1304
1304
  getVisibleNodeIds(): readonly NodeId[];
1305
- /** Scene roster: scope applied, mask NOT applied — the §15.1 navigator's
1305
+ /** Scene roster: scope applied, mask NOT applied — the navigator's
1306
1306
  * entry list, which must still LIST masked/hidden nodes and expose their
1307
1307
  * state in text rather than dropping them. */
1308
1308
  getSceneNodeIds(): readonly NodeId[];
1309
- /** §15.1 accessibility config stash (navigator/live-region consumers). */
1309
+ /** accessibility config stash (navigator/live-region consumers). */
1310
1310
  getAccessibility(): AccessibilityConfig<N> | undefined;
1311
1311
  }
1312
- /** §16.14: consecutive same-dimension brush moves within this window merge
1312
+ /** consecutive same-dimension brush moves within this window merge
1313
1313
  * into one history entry (scrub/drag coalescing). */
1314
1314
  declare const BRUSH_HISTORY_COALESCE_MS = 500;
1315
- /** §16.6 timeline defaults (S9-T10). */
1315
+ /** timeline defaults. */
1316
1316
  declare const TIMELINE_TICK_MS_DEFAULT = 100;
1317
1317
  declare const TIMELINE_STEP_DEFAULT = 0.01;
1318
- /** §16.5 search defaults (S11-T06). */
1318
+ /** search defaults. */
1319
1319
  declare const SEARCH_LIMIT_DEFAULT = 20;
1320
1320
  declare const SEARCH_CACHE_LIMIT = 32;
1321
1321
  declare function createGraphInstance<N = Record<string, unknown>, E = Record<string, unknown>>(opts: CreateGraphInstanceOptions<N, E>): GraphInstance<N, E>;
1322
1322
 
1323
1323
  /**
1324
- * §14 DOM label lane — pure candidate selection (S7-T01/T16).
1324
+ * DOM label lane — pure candidate selection.
1325
1325
  *
1326
1326
  * `selectLabelCandidates` is a pure, deterministic ranking function: no engine,
1327
1327
  * 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)
1328
+ * re-rank triggers only (viewport idle, model change, config change, settle)
1329
1329
  * NEVER per frame. Positions are the reconciler's CPU cache (space coords);
1330
1330
  * per-frame work elsewhere is a pure O(k) projection of the winners.
1331
1331
  *
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.
1332
+ * Selection rules:
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.
1344
1344
  */
1345
1345
 
1346
1346
  /** A capacity winner before per-frame projection assigns screen coordinates. */
1347
1347
  type LabelCandidate = Omit<LabelPlacement, 'x' | 'y'>;
1348
- /** §14 default ranked-candidate cap. */
1348
+ /** default ranked-candidate cap. */
1349
1349
  declare const LABEL_MAX_VISIBLE_DEFAULT = 64;
1350
- /** §14 policy maximum for `maxVisible`. */
1350
+ /** policy maximum for `maxVisible`. */
1351
1351
  declare const LABEL_MAX_VISIBLE_CAP = 1024;
1352
1352
  interface LabelCandidateViewport {
1353
1353
  zoom: number;
@@ -1360,7 +1360,7 @@ interface SelectLabelCandidatesArgs<N = Record<string, unknown>> {
1360
1360
  scene: RenderScene;
1361
1361
  /**
1362
1362
  * 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
1363
+ * scene index i IS accepted-base position i, so `nodes[i]` is the
1364
1364
  * node behind `scene.idByIndex[i]`.
1365
1365
  */
1366
1366
  nodes: readonly GraphNode<N>[];
@@ -1385,11 +1385,11 @@ interface LabelCandidateResult {
1385
1385
  declare function selectLabelCandidates<N = Record<string, unknown>>(args: SelectLabelCandidatesArgs<N>): LabelCandidateResult;
1386
1386
 
1387
1387
  /**
1388
- * §7.1/§13 CSR adjacency over columnar link buffers.
1388
+ * CSR adjacency over columnar link buffers.
1389
1389
  *
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
1390
+ * Pure, engine-free helpers shared by local expansion, incident-edge
1391
+ * dirtying, and the engine-facing `neighborIndices` interaction helper.
1392
+ * Build is O(L) via two counting passes over the flat
1393
1393
  * `[src0, tgt0, src1, tgt1, …]` link buffer — no comparison sort and no
1394
1394
  * per-link allocation (the only allocations are the CSR arrays plus one
1395
1395
  * point-sized cursor array).
@@ -1420,9 +1420,9 @@ declare function buildAdjacency(links: Uint32Array, pointCount: number): Adjacen
1420
1420
  */
1421
1421
  declare function neighborsOf(adj: Adjacency, index: number): Uint32Array;
1422
1422
  /**
1423
- * CSR INCIDENCE: point → incident EDGE SLOTS (F10-02). The plain Adjacency
1423
+ * CSR INCIDENCE: point → incident EDGE SLOTS. The plain Adjacency
1424
1424
  * stores neighbor points, which cannot drive incident-edge dirtying — the
1425
- * §9.1 delta cascade needs the edge slots themselves. Same two counting
1425
+ * delta cascade needs the edge slots themselves. Same two counting
1426
1426
  * passes and the same conventions: undirected (each edge listed under both
1427
1427
  * endpoints), parallel edges repeat, and a self-loop lists its edge slot
1428
1428
  * twice under its point — consumers' per-edge operations are idempotent, so
@@ -1437,26 +1437,26 @@ interface Incidence {
1437
1437
  }
1438
1438
 
1439
1439
  /**
1440
- * §13/§15 CPU link-pick fallback: a uniform grid over ALL links in SPACE
1440
+ * CPU link-pick fallback: a uniform grid over ALL links in SPACE
1441
1441
  * coordinates (cell ≈ median link length), used when the engine lacks native
1442
1442
  * `linkAt` (`capabilities.linkPicking === false`). Backs
1443
- * `onEdgeClick`/`onEdgeHover` via the §7.4 index→edge mapping.
1443
+ * `onEdgeClick`/`onEdgeHover` via the index→edge mapping.
1444
1444
  *
1445
1445
  * Coordinate contract: everything here is SPACE coordinates. Callers invert
1446
1446
  * the affine `Viewport` (space = (screen − center)/zoom + [x, y]) and pass a
1447
1447
  * space-unit tolerance (`tolerancePx / zoom`).
1448
1448
  *
1449
1449
  * 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.
1450
+ * - The grid indexes a POSITION SNAPSHOT (the `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.
1455
1455
  * - 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).
1456
+ * sync. The grid is invariant under camera moves and visibility-mask
1457
+ * changes: the mask is applied per candidate at QUERY time via the
1458
+ * optional `visible` callback (pure pass-through until mask wiring supplies the real
1459
+ * mask through it).
1460
1460
  *
1461
1461
  * Build uses two counting-sort passes into CSR grid arrays (`cellOffsets`,
1462
1462
  * `cellLinkIds`). Each segment is inserted with a supercover grid traversal,
@@ -1464,11 +1464,11 @@ interface Incidence {
1464
1464
  * every cell in its O(cols * rows) axis-aligned bounding box. There is no
1465
1465
  * comparison sort or per-link allocation beyond the CSR arrays (plus
1466
1466
  * 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
1467
+ * (NaN-tombstoned points) are excluded and can never be returned. A hard
1468
1468
  * CSR-entry cap deterministically degrades pathological builds to exact O(L)
1469
1469
  * query scans with no cell-link payload.
1470
1470
  */
1471
- /** §9.1 visibility mask applied per candidate at query time. */
1471
+ /** visibility mask applied per candidate at query time. */
1472
1472
  type LinkVisibilityMask = (linkIndex: number) => boolean;
1473
1473
  /**
1474
1474
  * Read-only view of the built grid (diagnostics/tests). The typed arrays are
@@ -1514,8 +1514,8 @@ declare class LinkPickIndex {
1514
1514
  */
1515
1515
  build(positions: Float32Array, links: Uint32Array): void;
1516
1516
  /**
1517
- * Incremental build: yields whenever `now() − sliceStart ≥ budgetMs` so a
1518
- * scheduler can spread the work across idle frames (§17 long-task budget).
1517
+ * Incremental build: yields whenever `now − sliceStart ≥ budgetMs` so a
1518
+ * scheduler can spread the work across idle frames.
1519
1519
  * Pure generator — no rAF/timers here; the caller owns scheduling.
1520
1520
  *
1521
1521
  * The previous grid stays armed and queryable until the new one commits on
@@ -1528,7 +1528,7 @@ declare class LinkPickIndex {
1528
1528
  * Nearest link within `tolerance` (space units) of the space point
1529
1529
  * `(x, y)`, or null. Scans the candidate cells covering the tolerance
1530
1530
  * disc's bounding box (typically the 3×3 neighborhood; more when the
1531
- * tolerance exceeds the cell size), applies the optional §9.1 visibility
1531
+ * tolerance exceeds the cell size), applies the optional visibility
1532
1532
  * mask per candidate, then runs the exact point→segment distance test.
1533
1533
  * Nearest wins; exact-distance ties break toward the LOWER link index.
1534
1534
  * Returns null while unbuilt/invalidated (picking disarmed).
@@ -1537,45 +1537,45 @@ declare class LinkPickIndex {
1537
1537
  }
1538
1538
 
1539
1539
  /**
1540
- * §13/§15 edge-picking facade (S6-T07).
1540
+ * Edge-picking facade.
1541
1541
  *
1542
1542
  * The core commits to ONE route per mount session, read from
1543
1543
  * `engine.capabilities.linkPicking` at engine-ready time — never method
1544
1544
  * sniffing, and never re-evaluated (a capability record mutated after ready
1545
1545
  * changes nothing):
1546
1546
  *
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
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 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 for the fallback route:
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; 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 visibility mask
1569
+ * is applied per candidate at query time; initially a pass-through stub).
1570
+ *
1571
+ * Tolerance: a query converts screen px to space units via
1572
1572
  * `screenToSpace` of two points `EDGE_PICK_TOLERANCE_PX` apart, then uses
1573
1573
  * `max(4px, half the median link width)` scaled by that factor.
1574
1574
  */
1575
1575
 
1576
1576
  type EdgePickRoute = 'native' | 'fallback';
1577
1577
  /** Screen-space pick tolerance floor, and the probe distance used to measure
1578
- * the screen→space scale (§13). */
1578
+ * the screen→space scale. */
1579
1579
  declare const EDGE_PICK_TOLERANCE_PX = 4;
1580
1580
  /**
1581
1581
  * Median link width in px from a projected linkWidth buffer (deterministic
@@ -1588,9 +1588,9 @@ interface EdgePickingFacadeOptions {
1588
1588
  route: EdgePickRoute;
1589
1589
  /** Affine screen→space conversion; null = conversion unavailable. */
1590
1590
  screenToSpace: (p: readonly [number, number]) => readonly [number, number] | null;
1591
- /** Median link width in px for the tolerance floor; default () => 0. */
1591
+ /** Median link width in px for the tolerance floor; default => 0. */
1592
1592
  medianLinkWidthPx?: () => number;
1593
- /** §9.1 visibility mask pass-through stub (mutable via the setter). */
1593
+ /** visibility mask pass-through stub (mutable via the setter). */
1594
1594
  linkVisible?: LinkVisibilityMask;
1595
1595
  /** Chunked-build slice budget in ms. */
1596
1596
  buildBudgetMs?: number;
@@ -1622,7 +1622,7 @@ declare class EdgePickingFacade {
1622
1622
  arm(positions: Float32Array, links: Uint32Array): void;
1623
1623
  /** Simulation went hot: drop the grid; queries null until the next settle. */
1624
1624
  disarm(): void;
1625
- /** §9.1 mask pass-through stub: applied per candidate at query time. */
1625
+ /** mask pass-through stub: applied per candidate at query time. */
1626
1626
  setLinkVisibilityMask(mask: LinkVisibilityMask | null): void;
1627
1627
  /**
1628
1628
  * Nearest link index within tolerance of a SCREEN point, or null when: on
@@ -1646,8 +1646,8 @@ declare class EdgePickingFacade {
1646
1646
  type EdgePairCounters = Map<NodeId, Map<NodeId, number>>;
1647
1647
 
1648
1648
  /**
1649
- * §7.5 revisioned ingestion — pure session/overlay bookkeeping plus the
1650
- * instance-local acceptance queue (S8-T01..T07).
1649
+ * revisioned ingestion — pure session/overlay bookkeeping plus the
1650
+ * instance-local acceptance queue.
1651
1651
  *
1652
1652
  * Everything here is data-structure work: no store, no engine, no DOM. The
1653
1653
  * GraphInstance wires these helpers into its publication path (instance.ts).
@@ -1655,7 +1655,7 @@ type EdgePairCounters = Map<NodeId, Map<NodeId, number>>;
1655
1655
  * Ordering model: every admission takes a monotonically increasing ticket from
1656
1656
  * the instance's AcceptanceQueue. Overlay rows are stamped with their
1657
1657
  * admission ticket, and the merge folds base + overlays strictly in ticket
1658
- * order — arrival at the queue IS the global admission order (§7.5).
1658
+ * order — arrival at the queue IS the global admission order.
1659
1659
  */
1660
1660
 
1661
1661
  /** Byte backpressure budget default: 8 MiB of admitted-but-unflushed payload. */
@@ -1687,7 +1687,7 @@ interface RowTally {
1687
1687
  count: number;
1688
1688
  samples: string[];
1689
1689
  }
1690
- /** Per-session staging tallies; surfaced as diagnostics ONLY at commit (§7.5). */
1690
+ /** Per-session staging tallies; surfaced as diagnostics ONLY at commit. */
1691
1691
  interface StagingTallies {
1692
1692
  invalidNodes: RowTally;
1693
1693
  duplicateNodes: RowTally;
@@ -1712,11 +1712,11 @@ interface SessionContribution<N = Record<string, unknown>, E = Record<string, un
1712
1712
  readonly edges: StampedEdge<E>[];
1713
1713
  readonly nodeIds: Set<NodeId>;
1714
1714
  readonly edgeIds: Set<string>;
1715
- /** Exact ordered endpoint tuple → next synthesized-parallel-edge k (§5). */
1715
+ /** Exact ordered endpoint tuple → next synthesized-parallel-edge k. */
1716
1716
  readonly pairCounters: EdgePairCounters;
1717
1717
  /** Public prefix lengths: rows before these counts have been published
1718
1718
  * (progressive flush / commit); appends only grow the arrays, so a prefix
1719
- * is sufficient. Atomic sessions stay at 0 until commit (§7.5). */
1719
+ * is sufficient. Atomic sessions stay at 0 until commit. */
1720
1720
  publicNodeCount: number;
1721
1721
  publicEdgeCount: number;
1722
1722
  }
@@ -1728,8 +1728,8 @@ interface StageResult {
1728
1728
  /**
1729
1729
  * Validate and stage one batch's rows into a session contribution.
1730
1730
  *
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
1731
+ * Object-lane-equivalent row validation WITHOUT endpoint checks — edges may arrive
1732
+ * before nodes: they occupy their eventual edge records here; endpoint
1733
1733
  * resolution happens at merge. Within a session, duplicate ids are
1734
1734
  * first-wins-dropped (tallied for commit diagnostics); cross-session
1735
1735
  * collisions are the merge's shadowing concern, not staging's.
@@ -1745,7 +1745,7 @@ interface MergeBase<N = Record<string, unknown>, E = Record<string, unknown>> {
1745
1745
  /** Endpoint-resolved base edges. */
1746
1746
  edges: readonly AcceptedEdge<E>[];
1747
1747
  /** Replace-session bases retain edge records whose endpoints were missing
1748
- * at commit; a later overlay node can still resolve them (§7.5). */
1748
+ * at commit; a later overlay node can still resolve them. */
1749
1749
  pendingEdges: readonly StampedEdge<E>[];
1750
1750
  diagnostics: readonly GraphDiagnostic[];
1751
1751
  }
@@ -1761,7 +1761,7 @@ interface MergeResult<N = Record<string, unknown>, E = Record<string, unknown>>
1761
1761
  duplicateEdgeSamples: readonly string[];
1762
1762
  /** overlayId (or BASE_PENDING_KEY) → edges still awaiting an endpoint. The
1763
1763
  * pending-endpoint index: these occupy edge records but never enter the
1764
- * engine link buffer (§7.5). */
1764
+ * engine link buffer. */
1765
1765
  pendingBySource: ReadonlyMap<string, number>;
1766
1766
  pendingEdgeCount: number;
1767
1767
  }
@@ -1776,15 +1776,15 @@ declare function baseFromContribution<N, E>(datasetKey: string, sourceRevision:
1776
1776
  * Merge the accepted base with every overlay contribution's PUBLIC rows.
1777
1777
  *
1778
1778
  * - 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).
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.
1782
1782
  * - 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).
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).
1788
1788
  *
1789
1789
  * Deterministic: output depends only on the base and the stamped rows.
1790
1790
  */
@@ -1793,20 +1793,20 @@ declare function mergeModel<N, E>(base: MergeBase<N, E>, overlays: readonly Sess
1793
1793
  declare function mergeDiagnostics(merge: MergeResult<unknown, unknown>): GraphDiagnostic[];
1794
1794
  /**
1795
1795
  * Commit-time diagnostics for one session: staging tallies plus the dangling
1796
- * (still-pending-endpoint) count — emitted ONLY at session commit (§7.5).
1796
+ * (still-pending-endpoint) count — emitted ONLY at session commit.
1797
1797
  */
1798
1798
  declare function sessionCommitDiagnostics(tallies: StagingTallies, danglingCount: number, danglingSamples?: readonly string[]): GraphDiagnostic[];
1799
1799
 
1800
1800
  /**
1801
- * §9.2 hard subgraph scope — pure resolution over the accepted base.
1801
+ * hard subgraph scope — pure resolution over the accepted base.
1802
1802
  *
1803
1803
  * `resolveScope` turns a `SubgraphSpec` into the exact node/edge subset the
1804
1804
  * reconciler should be fed: seeds validated against the accepted base
1805
1805
  * (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.
1806
+ * BFS over the CSR adjacency of the ACCEPTED BASE (not the scene — the
1807
+ * default expansion service walks this same index), and edges cascaded
1808
+ * through `cascadeEdges`, the single edge-survival primitive (an edge
1809
+ * survives iff BOTH endpoints survive) that soft masks reuse.
1810
1810
  *
1811
1811
  * Everything here is synchronous and engine-free. The async
1812
1812
  * `ExpansionService` seam (./services) exists for `expandNode`; `hops`
@@ -1814,21 +1814,21 @@ declare function sessionCommitDiagnostics(tallies: StagingTallies, danglingCount
1814
1814
  */
1815
1815
 
1816
1816
  /**
1817
- * THE edge-cascade primitive (§9): an edge survives iff BOTH of its
1817
+ * THE edge-cascade primitive: an edge survives iff BOTH of its
1818
1818
  * endpoints survive. O(E); the only allocation is the output array, which
1819
1819
  * holds references to the input edge objects (never copies).
1820
1820
  *
1821
- * Exported for reuse by §9.1 soft masks (S9) and any other subset producer.
1821
+ * Exported for reuse by soft masks and any other subset producer.
1822
1822
  */
1823
1823
  declare function cascadeEdges<E>(edges: readonly AcceptedEdge<E>[], survives: (id: NodeId) => boolean): AcceptedEdge<E>[];
1824
1824
  /**
1825
- * Builds the §7.1 CSR adjacency of an accepted base: endpoints are positions
1825
+ * Builds the CSR adjacency of an accepted base: endpoints are positions
1826
1826
  * 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
1827
+ * endpoints by contract, so this cannot throw on
1828
1828
  * a well-formed `AcceptedGraph`.
1829
1829
  */
1830
1830
  declare function buildAcceptedAdjacency(accepted: AcceptedGraph<unknown, unknown>): Adjacency;
1831
- /** Output of `resolveScope`: the exact subset to feed the reconciler (§9.2). */
1831
+ /** Output of `resolveScope`: the exact subset to feed the reconciler. */
1832
1832
  interface ResolvedScope<N = Record<string, unknown>, E = Record<string, unknown>> {
1833
1833
  /** Surviving node ids (seeds + hop expansion), membership-query form. */
1834
1834
  nodeIds: ReadonlySet<NodeId>;
@@ -1838,31 +1838,31 @@ interface ResolvedScope<N = Record<string, unknown>, E = Record<string, unknown>
1838
1838
  edges: readonly AcceptedEdge<E>[];
1839
1839
  }
1840
1840
  /**
1841
- * Resolves a hard-scope spec against the accepted base (§9.2).
1841
+ * Resolves a hard-scope spec against the accepted base.
1842
1842
  *
1843
1843
  * - `spec.seedIds` are validated against `accepted.nodeIndex`: ids unknown to
1844
- * the accepted base are dropped, duplicates collapse to one seed.
1844
+ * the accepted base are dropped, duplicates collapse to one seed.
1845
1845
  * - `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`.
1846
+ * floor) expands the survivor set by BFS over the accepted-base adjacency.
1847
+ * This is the synchronous local path — the default `ExpansionService`
1848
+ * walks the same index for `expandNode`.
1849
1849
  * - `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).
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).
1852
1852
  * - Output preserves accepted-base order for both nodes and edges; edges are
1853
- * cascaded through {@link cascadeEdges}.
1853
+ * cascaded through {@link cascadeEdges}.
1854
1854
  */
1855
1855
  declare function resolveScope<N, E>(accepted: AcceptedGraph<N, E>, spec: SubgraphSpec, adjacency: Adjacency | null): ResolvedScope<N, E>;
1856
1856
 
1857
1857
  /**
1858
- * §9.2 revision-aware services — pure sequencing/admission/caching helpers
1858
+ * revision-aware services — pure sequencing/admission/caching helpers
1859
1859
  * plus the built-in local expansion service.
1860
1860
  *
1861
1861
  * The correctness gate is `admitServiceResult`: a result is admitted only if
1862
1862
  * every revision dimension the service DECLARED is unchanged since the call
1863
1863
  * was issued; undeclared dimensions never invalidate (so e.g. the local
1864
1864
  * expansion service, declaring only 'source', survives unrelated model/scope
1865
- * advances from other overlay publications). Abort is an optimization
1865
+ * advances from other overlay publications). Abort is an optimization
1866
1866
  * admission is the gate.
1867
1867
  *
1868
1868
  * Cache keys include service identity, canonical-JSON request parameters,
@@ -1872,7 +1872,7 @@ declare function resolveScope<N, E>(accepted: AcceptedGraph<N, E>, spec: Subgrap
1872
1872
  * these primitives to its acceptance queue.
1873
1873
  */
1874
1874
 
1875
- /** Current value of each §9.2 revision dimension (a Revisions subset). */
1875
+ /** Current value of each revision dimension (a Revisions subset). */
1876
1876
  interface RevisionSnapshot {
1877
1877
  source: number | string | null;
1878
1878
  model: number;
@@ -1896,13 +1896,13 @@ interface RequestContextHandle {
1896
1896
  abort(reason?: unknown): void;
1897
1897
  }
1898
1898
  /**
1899
- * Builds the `RequestContext` a service call receives (§9.2): dataset,
1899
+ * Builds the `RequestContext` a service call receives: dataset,
1900
1900
  * the three revision dimensions at issue time, a request id, and a
1901
1901
  * cancellation signal owned by the returned controller.
1902
1902
  */
1903
1903
  declare function createRequestContext(args: CreateRequestContextArgs): RequestContextHandle;
1904
1904
  interface AdmitServiceResultArgs {
1905
- /** The service's `revisionDependencies` (§9.2). */
1905
+ /** The service's `revisionDependencies`. */
1906
1906
  declared: readonly RevisionDimension[];
1907
1907
  /** Revision values when the request was issued. */
1908
1908
  at: RevisionSnapshot;
@@ -1910,7 +1910,7 @@ interface AdmitServiceResultArgs {
1910
1910
  now: RevisionSnapshot;
1911
1911
  }
1912
1912
  /**
1913
- * §9.2 stale-result rule: admit a service result iff EVERY declared revision
1913
+ * stale-result rule: admit a service result iff EVERY declared revision
1914
1914
  * dimension is unchanged between issue and admission. Undeclared dimensions
1915
1915
  * never invalidate. Declaring nothing means the result is admissible under
1916
1916
  * any drift; declaring all three restores strict point-in-model semantics.
@@ -1921,13 +1921,13 @@ interface ServiceCacheKeyArgs {
1921
1921
  /** Request parameters (JSON-shaped); key order is canonicalized away. */
1922
1922
  params: unknown;
1923
1923
  datasetKey: string;
1924
- /** The service's declared revision dependencies (§9.2). */
1924
+ /** The service's declared revision dependencies. */
1925
1925
  declared: readonly RevisionDimension[];
1926
1926
  /** Current revision values; only declared dimensions enter the key. */
1927
1927
  revisions: RevisionSnapshot;
1928
1928
  }
1929
1929
  /**
1930
- * §9.2 cache-key rule: service identity + canonical-JSON params +
1930
+ * cache-key rule: service identity + canonical-JSON params +
1931
1931
  * `datasetKey` + EXACTLY the declared revision dimensions' current values.
1932
1932
  * Declaration-list order and params key order do not affect the key;
1933
1933
  * undeclared revision drift never changes it.
@@ -1936,11 +1936,11 @@ declare function serviceCacheKey(args: ServiceCacheKeyArgs): string;
1936
1936
  /** Accepted-base view the local service walks (thunked for lazy wiring). */
1937
1937
  interface LocalExpansionBase<N = Record<string, unknown>, E = Record<string, unknown>> {
1938
1938
  accepted: AcceptedGraph<N, E>;
1939
- /** The §7.1 CSR adjacency of `accepted` (see buildAcceptedAdjacency). */
1939
+ /** The CSR adjacency of `accepted` (see buildAcceptedAdjacency). */
1940
1940
  adjacency: Adjacency;
1941
1941
  }
1942
1942
  /**
1943
- * The built-in §9.2 expansion service: walks the core's accepted-base
1943
+ * The built-in expansion service: walks the core's accepted-base
1944
1944
  * adjacency — INCLUDING currently out-of-scope nodes (it reads the base, not
1945
1945
  * the scene) — with zero config and zero network. Declares
1946
1946
  * `revisionDependencies: ['source']`, so unrelated model/scope advances
@@ -1954,7 +1954,7 @@ interface LocalExpansionBase<N = Record<string, unknown>, E = Record<string, unk
1954
1954
  * admission gate is authoritative).
1955
1955
  *
1956
1956
  * 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
1957
+ * edge between returned nodes); the overlay merger dedupes rows
1958
1958
  * that already exist, so returning already-known seeds is correct.
1959
1959
  */
1960
1960
  declare function createLocalExpansionService<N = Record<string, unknown>, E = Record<string, unknown>>(getBase: () => LocalExpansionBase<N, E>): ExpansionService<N, E>;
@@ -1967,7 +1967,7 @@ type RegisterExpansionResult = {
1967
1967
  onto: string;
1968
1968
  };
1969
1969
  /**
1970
- * Pure in-flight-expansion ledger (§9.2): within one valid scope revision a
1970
+ * Pure in-flight-expansion ledger: within one valid scope revision a
1971
1971
  * second `expandNode(id)` while one is in flight coalesces into the pending
1972
1972
  * call; expansions of DISTINCT ids run (and complete) concurrently and
1973
1973
  * independently. `retractExpansion(id)` uses `abort(id)` to drop that id's
@@ -2005,14 +2005,15 @@ declare class PendingExpansions {
2005
2005
  }
2006
2006
 
2007
2007
  /**
2008
- * §16.14 history command-stack kernel (S9-T20; pulled forward from M7).
2008
+ * history command-stack kernel.
2009
2009
  *
2010
2010
  * v0.7 implements the KERNEL only: value-diff commands, transactions,
2011
2011
  * 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
2012
+ * pure application seam: `undo`/`redo` return the command list to apply
2013
2013
  * (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.
2014
+ * applies commands to its slices and publishes.
2015
+ * Ownership-mode acknowledgement walks and view-state integration remain
2016
+ * instance-level concerns.
2016
2017
  *
2017
2018
  * Commands are `{ slice, before, after }` value diffs — never closures — so
2018
2019
  * they are serializable and invert by swapping. The kernel freezes and stores
@@ -2032,7 +2033,7 @@ interface HistoryDepths {
2032
2033
  readonly redoDepth: number;
2033
2034
  }
2034
2035
  interface HistoryKernelOptions {
2035
- /** Stack bound; oldest entry evicted past it (§16.14; default 50). */
2036
+ /** Stack bound; oldest entry evicted past it. */
2036
2037
  limit?: number;
2037
2038
  /** `false` = the `history: false` prop: everything is a no-op, depths stay 0. */
2038
2039
  enabled?: boolean;
@@ -2050,7 +2051,7 @@ declare class HistoryKernel {
2050
2051
  private readonly debug;
2051
2052
  private readonly undoStack;
2052
2053
  private readonly redoStack;
2053
- /** Nested begin() joins the outer transaction (depth-counted). */
2054
+ /** Nested begin joins the outer transaction (depth-counted). */
2054
2055
  private txDepth;
2055
2056
  private txCommands;
2056
2057
  private txLabel;
@@ -2080,7 +2081,7 @@ declare class HistoryKernel {
2080
2081
  * transaction. The kernel freezes and stores what it is given.
2081
2082
  */
2082
2083
  record(slice: string, before: unknown, after: unknown): void;
2083
- /** Close a transaction; the outermost end() pushes one stack entry. */
2084
+ /** Close a transaction; the outermost end pushes one stack entry. */
2084
2085
  end(): void;
2085
2086
  /**
2086
2087
  * Move the cursor back one entry and return its commands, already inverted
@@ -2110,28 +2111,28 @@ declare class HistoryKernel {
2110
2111
  }
2111
2112
 
2112
2113
  /**
2113
- * §9.1 soft filtering (S9-T01) — pure, engine-free expr evaluation,
2114
+ * soft filtering — pure, engine-free expr evaluation,
2114
2115
  * validation, compilation, and canonical keying. The instance feeds compiled
2115
2116
  * filters into the SoftMask kernel (./mask); nothing here touches the store.
2116
2117
  *
2117
- * Semantics (orbit-spec.md §9.1):
2118
+ * Semantics:
2118
2119
  * - `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.
2120
+ * entity id (it wins even when `attrs.id` exists).
2121
+ * - The serializable expr path NEVER throws: junk shapes and numeric-hygiene
2122
+ * failures (non-numeric / non-finite values under 'range') simply fail the
2123
+ * item. `validateFilterExpr` is the reporting channel — the instance turns
2124
+ * its findings into validation errors at applyHostUpdate.
2124
2125
  * - 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).
2126
+ * never equal to anything (so ±0 are distinct and NaN ≠ NaN); everything
2127
+ * else compares with plain ===. No coercion, ever ('5' never equals 5).
2127
2128
  * - 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.
2129
+ * into ONE {count, samples} result the caller converts to a single
2130
+ * 'filter-error' diagnostic (batching — O(categories), never O(bad
2131
+ * rows)). A throwing predicate FAILS OPEN: the item stays visible, so a
2132
+ * buggy predicate can never blank the graph.
2132
2133
  * - 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.
2134
+ * identity churn with equal structure never re-evaluates; function
2135
+ * predicates key by reference identity via a WeakMap-issued token.
2135
2136
  */
2136
2137
 
2137
2138
  /**
@@ -2141,7 +2142,7 @@ declare class HistoryKernel {
2141
2142
  declare function resolveFilterField(item: GraphNode<unknown> | AcceptedEdge<unknown>, field: string): unknown;
2142
2143
  /**
2143
2144
  * Evaluates one expr for one item via a field resolver. NEVER throws:
2144
- * malformed shapes and §8-hygiene failures fail the item (return false);
2145
+ * malformed shapes and numeric-hygiene failures fail the item (return false);
2145
2146
  * a malformed operand under 'not' also fails (junk never passes by double
2146
2147
  * negation). `range` requires a finite number value; missing bounds are
2147
2148
  * unbounded; includeMin/includeMax default true. `is-null` matches null OR
@@ -2151,7 +2152,7 @@ declare function evaluateFilterExpr(expr: FilterExpr, resolve: (field: string) =
2151
2152
  /**
2152
2153
  * Structural checker for serializable exprs: unknown ops and malformed
2153
2154
  * shapes are reported as `$`-rooted path strings ([] = valid). The instance
2154
- * converts findings into validation errors at applyHostUpdate (§9.1) —
2155
+ * converts findings into validation errors at applyHostUpdate
2155
2156
  * evaluation itself never throws on the same junk, it just fails the item.
2156
2157
  */
2157
2158
  declare function validateFilterExpr(expr: FilterExpr): string[];
@@ -2178,7 +2179,7 @@ declare function compileEdgeFilter<N = Record<string, unknown>, E = Record<strin
2178
2179
  * Canonical structural key for a FilterSpec or FilterExpr: object keys are
2179
2180
  * sorted, arrays preserve order, undefined-valued keys are omitted, and
2180
2181
  * function predicates map to a unique reference-identity token. Two inputs
2181
- * with equal keys are §9.1-equivalent — the instance skips re-evaluation
2182
+ * with equal keys are semantically equivalent — the instance skips re-evaluation
2182
2183
  * when the key of an incoming filter matches the active one (identity churn
2183
2184
  * with equal structure never re-evaluates; swapping a function reference
2184
2185
  * always does).
@@ -2186,14 +2187,14 @@ declare function compileEdgeFilter<N = Record<string, unknown>, E = Record<strin
2186
2187
  declare function canonicalFilterKey(specOrExpr: unknown): string;
2187
2188
 
2188
2189
  /**
2189
- * §9.1 soft-mask kernel (S9-T02/T03) — failure COUNTERS, never Sets and
2190
+ * soft-mask kernel — failure COUNTERS, never Sets and
2190
2191
  * never per-source bit positions (so there is no 32-dimension cap).
2191
2192
  *
2192
2193
  * The mask owns four Uint16 counter lanes: hideFailures and dimFailures for
2193
2194
  * nodes AND edges. Every acquired {@link MaskSource} contributes +1 to a
2194
2195
  * lane counter for each slot it currently fails and -1 when that slot
2195
2196
  * re-enters. A slot is visible iff hideFailures === 0 and dimmed iff visible
2196
- * AND dimFailures > 0 (spec §9.1 mask mechanics).
2197
+ * AND dimFailures > 0.
2197
2198
  *
2198
2199
  * Delta discipline: each source keeps its previous failing membership as
2199
2200
  * per-source Uint8 flag columns plus a dense slot list, so replacing a
@@ -2203,9 +2204,9 @@ declare function canonicalFilterKey(specOrExpr: unknown): string;
2203
2204
  * compares against the state at the previous drain, so a fail-then-restore
2204
2205
  * inside one drain period nets to no emission.
2205
2206
  *
2206
- * {@link SoftMask.applyNodeCascadeToEdges} implements §9's SINGLE edge-
2207
+ * {@link SoftMask.applyNodeCascadeToEdges} implements SINGLE edge-
2207
2208
  * survival rule over the mask lane: an edge hide-fails iff EITHER endpoint
2208
- * hide-fails (equivalently: survives iff BOTH endpoints survive
2209
+ * hide-fails (equivalently: survives iff BOTH endpoints survive
2209
2210
  * scope.ts `cascadeEdges` is the hard-scope variant of the same rule). It is
2210
2211
  * fed through one dedicated internal cascade source from the node hide lane:
2211
2212
  * O(E) recompute per call, but only edges whose state changed produce
@@ -2213,12 +2214,12 @@ declare function canonicalFilterKey(specOrExpr: unknown): string;
2213
2214
  *
2214
2215
  * Overflow guard: increments clamp at 0xFFFF and latch a one-time
2215
2216
  * {@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
2217
+ * widen to Uint32 without changing semantics). Debug builds assert
2218
+ * balanced increments/decrements whenever a clear/release leaves zero
2218
2219
  * held memberships.
2219
2220
  */
2220
2221
 
2221
- /** Default muted alpha for dimmed entities (§9.1 'dim' mode). */
2222
+ /** Default muted alpha for dimmed entities. */
2222
2223
  declare const DIM_ALPHA_DEFAULT = 0.15;
2223
2224
  /**
2224
2225
  * A handle contributing failure memberships to the mask. Setting a lane
@@ -2231,7 +2232,7 @@ interface MaskSource {
2231
2232
  setNodeFailures(hideIdx: Iterable<number> | null, dimIdx?: Iterable<number> | null): void;
2232
2233
  setEdgeFailures(hideIdx: Iterable<number> | null, dimIdx?: Iterable<number> | null): void;
2233
2234
  /**
2234
- * O(Δ) delta form of the HIDE lane (F10-02): adds/removes individual slots
2235
+ * O(Δ) delta form of the HIDE lane: adds/removes individual slots
2235
2236
  * from this source's membership without replaying the full set. Freely
2236
2237
  * composable with the replace form — a later setNodeFailures re-baselines.
2237
2238
  * `crossings`, when supplied, receives the slots whose hide counter
@@ -2242,8 +2243,8 @@ interface MaskSource {
2242
2243
  updateEdgeFailures(addHide: ArrayLike<number> | null, removeHide: ArrayLike<number> | null): void;
2243
2244
  /** Empties all four lane memberships (the source stays usable). */
2244
2245
  clear(): void;
2245
- /** clear() + permanently retires the handle (further set/clear throws;
2246
- * release() itself is idempotent). */
2246
+ /** clear + permanently retires the handle (further set/clear throws;
2247
+ * release itself is idempotent). */
2247
2248
  release(): void;
2248
2249
  }
2249
2250
  /** Per-CALL zero-crossings reported by the delta ops (reused, callee-cleared). */
@@ -2253,7 +2254,7 @@ interface MaskCrossings {
2253
2254
  /** Slots whose hide counter went nonzero → 0 in this call. */
2254
2255
  becameClear: number[];
2255
2256
  }
2256
- /** §17 O(Δ) operation counters (see resetStats/stats on SoftMask). */
2257
+ /** O(Δ) operation counters (see resetStats/stats on SoftMask). */
2257
2258
  interface MaskStats {
2258
2259
  /** Slots visited by delta membership ops (add + remove attempts). */
2259
2260
  slotsVisited: number;
@@ -2264,7 +2265,7 @@ interface MaskStats {
2264
2265
  }
2265
2266
  /**
2266
2267
  * One drain payload. The four index arrays are REUSED across drains — copy
2267
- * before the next drainDirty() call if you need to keep them.
2268
+ * before the next drainDirty call if you need to keep them.
2268
2269
  */
2269
2270
  interface MaskDrain {
2270
2271
  /** Node slots whose hide-visibility (hideFailures 0 ↔ nonzero) flipped
@@ -2289,18 +2290,18 @@ declare class SoftMask {
2289
2290
  private readonly edgeHideLane;
2290
2291
  private readonly edgeDimLane;
2291
2292
  private readonly sources;
2292
- /** Dedicated internal source implementing the §9 node→edge cascade. */
2293
+ /** Dedicated internal source implementing the node→edge cascade. */
2293
2294
  private cascadeSource;
2294
2295
  private overflowedFlag;
2295
2296
  /** Total memberships currently held across all sources and lanes. */
2296
2297
  private totalHeld;
2297
- /** §17 O(Δ) op counters (F10-02 gate instrumentation). */
2298
+ /** O(Δ) op counters. */
2298
2299
  private readonly statsBox;
2299
2300
  constructor(nodeCapacity: number, edgeCapacity: number);
2300
2301
  get nodeCapacity(): number;
2301
2302
  get edgeCapacity(): number;
2302
2303
  /** 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). */
2304
+ * Counts may drift afterwards; the caller reports it. */
2304
2305
  get overflowed(): boolean;
2305
2306
  get nodeHideFailures(): Uint16Array;
2306
2307
  get nodeDimFailures(): Uint16Array;
@@ -2308,18 +2309,18 @@ declare class SoftMask {
2308
2309
  get edgeDimFailures(): Uint16Array;
2309
2310
  /**
2310
2311
  * Grows capacities for structure changes (existing slot state is
2311
- * preserved; new slots start fully visible). Capacities never shrink
2312
+ * preserved; new slots start fully visible). Capacities never shrink
2312
2313
  * a smaller value is a no-op for that dimension.
2313
2314
  */
2314
2315
  grow(nodeCapacity: number, edgeCapacity: number): void;
2315
- /** Registers a new failure source. No cap on source count (§9.1). */
2316
+ /** Registers a new failure source. No cap on source count. */
2316
2317
  acquire(name: string): MaskSource;
2317
2318
  /**
2318
- * §9 edge cascade over the mask lane: recomputes, from the CURRENT node
2319
+ * edge cascade over the mask lane: recomputes, from the CURRENT node
2319
2320
  * hide lane, the set of edges with at least one hidden endpoint, and feeds
2320
2321
  * 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].
2322
+ * `links` is the flat `[src0, tgt0, src1, tgt1, …]` node-slot pair buffer;
2323
+ * edge slot i has endpoints at links[2i]/[2i+1].
2323
2324
  * O(E) scan per call — typically once per drain — but only edges whose
2324
2325
  * cascade state changed produce counter deltas (and thus dirty entries).
2325
2326
  * Edges beyond `links.length / 2` are treated as having no hidden
@@ -2327,7 +2328,7 @@ declare class SoftMask {
2327
2328
  */
2328
2329
  applyNodeCascadeToEdges(links: Uint32Array): void;
2329
2330
  /**
2330
- * O(incident-edges) delta form of the §9.1 cascade (F10-02): for each node
2331
+ * O(incident-edges) delta form of the cascade: for each node
2331
2332
  * whose HIDE visibility crossed zero, recompute only its incident edges'
2332
2333
  * cascade state from the CURRENT node counters and apply the delta through
2333
2334
  * the same internal cascade source the full form uses — the two compose
@@ -2343,10 +2344,10 @@ declare class SoftMask {
2343
2344
  * drain). The returned index arrays are reused by the next drain.
2344
2345
  */
2345
2346
  drainDirty(): MaskDrain;
2346
- /** §17 telemetry: estimated bytes of mask storage held (S13-T07):
2347
+ /** telemetry: estimated bytes of mask storage held:
2347
2348
  * four counter lanes (+pending trackers) and per-source flag columns. */
2348
2349
  estimatedBytes(): number;
2349
- /** §17 O(Δ) op counters (live object — snapshot before comparing). */
2350
+ /** O(Δ) op counters (live object — snapshot before comparing). */
2350
2351
  get stats(): Readonly<MaskStats>;
2351
2352
  resetStats(): void;
2352
2353
  visibleNodeCount(): number;
@@ -2354,7 +2355,7 @@ declare class SoftMask {
2354
2355
  /** Visible iff hideFailures === 0 (out-of-range slots read not-visible). */
2355
2356
  isNodeVisible(index: number): boolean;
2356
2357
  isEdgeVisible(index: number): boolean;
2357
- /** Dimmed iff visible AND dimFailures > 0 (§9.1). */
2358
+ /** Dimmed iff visible AND dimFailures > 0. */
2358
2359
  isNodeDimmed(index: number): boolean;
2359
2360
  isEdgeDimmed(index: number): boolean;
2360
2361
  /** 1 (fully visible) | dimAlpha (dimmed) | 0 (hidden). */
@@ -2368,7 +2369,7 @@ declare class SoftMask {
2368
2369
  */
2369
2370
  private applyMembership;
2370
2371
  /**
2371
- * O(Δ) delta ops on one lane membership (F10-02). Adds and removes are
2372
+ * O(Δ) delta ops on one lane membership. Adds and removes are
2372
2373
  * idempotent per slot (adding a member / removing a non-member is a
2373
2374
  * no-op); removed slots leave HOLES in `list` (compacted past 50%), so
2374
2375
  * replace/clear passes must honor the bit0 guard above. `crossings`, when
@@ -2383,65 +2384,65 @@ declare class SoftMask {
2383
2384
  private drainLane;
2384
2385
  private clearSource;
2385
2386
  /** Debug balanced-increment assert: whenever no source holds any
2386
- * membership, every counter must read zero (skipped once overflowed
2387
+ * membership, every counter must read zero (skipped once overflowed
2387
2388
  * clamped increments legitimately drift the books). */
2388
2389
  private assertBalancedIfIdle;
2389
2390
  }
2390
2391
 
2391
2392
  /**
2392
- * §16.6 crossfilter — typed-column engine (v0.7 node-dimension subset).
2393
+ * crossfilter — typed-column engine (v0.7 node-dimension subset).
2393
2394
  *
2394
2395
  * `TypedColumnCrossfilter` is the columnar backend the instance wraps into the
2395
2396
  * public `CrossfilterSession`. Design (crossfilter.js lineage):
2396
2397
  *
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()`.
2398
+ * - **Parse once.** `build` extracts every dimension exactly once into typed
2399
+ * columns (numeric/temporal → `Float64Array` epoch-ms/values, categorical →
2400
+ * dictionary codes). hygiene: non-finite numerics, unparseable temporals,
2401
+ * and non-string/non-finite categorical values are excluded from the
2402
+ * dimension (tracked per dimension in `excludedRows`; the slot is marked
2403
+ * invalid). Temporal parsing: numbers are epoch ms verbatim; strings go
2404
+ * through `Date.parse` (ES2022 parses `'YYYY-MM-DD'` as UTC midnight);
2405
+ * `Date` instances use `getTime`.
2405
2406
  * - **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.
2407
+ * permutation. A brush move performs two binary searches and walks ONLY the
2408
+ * symmetric difference between the old and new in-range windows; categorical
2409
+ * brushes walk only the per-code slot lists whose excluded flag changed. The
2410
+ * brush path never re-sorts. A per-slot, per-dimension pass flag plus a
2411
+ * global per-slot failure counter make a row selection-visible iff it fails
2412
+ * zero dimensions. Hygiene-excluded rows fail any non-null brush on that
2413
+ * dimension (they cannot be in range / in a category) and pass a null brush.
2413
2414
  * - **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).
2415
+ * flipped (`hidden`/`shown`) for the instance's mask source.
2416
+ * - **Lazy dual layer.** `summarize` returns immutable summaries whose
2417
+ * `filtered` layer counts rows passing every OTHER dimension's brush plus an
2418
+ * external node-mask predicate (`setExternalMask`). v0.7 recomputes a dirty
2419
+ * dimension's filtered layer lazily per `summarize` call — O(rows) per
2420
+ * dirty summarize, documented and acceptable at this tier (fixtures own
2421
+ * the perf claims; the O(Δ) guarantee covers the brush/visibility path).
2421
2422
  * - **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.
2423
+ * exactly once per observable `setBrush` (a brush state change is observable
2424
+ * via `getBrush` even when no row flips). v0.7 is synchronous, so
2425
+ * latest-call-wins degenerates to "every call applies immediately in call
2426
+ * order". Subscribers fire once per observable change after state is
2427
+ * consistent; synchronous re-entrancy (a subscriber mutating the engine) is
2428
+ * coalesced into one trailing notification pass. Model updates
2429
+ * (`appendRows`/`replaceAll`) keep the current `selectionRevision`
2430
+ * but do notify. External-mask changes notify (summaries changed) without
2431
+ * advancing the selection revision.
2431
2432
  * - **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.
2433
+ * merges the pre-sorted old permutation with the sorted new block
2434
+ * (permutation merge — never a full re-argsort); bins extend incrementally
2435
+ * unless the domain grew (then a re-bin, still sort-free). Brushes persist
2436
+ * by key and are re-applied to the NEW slots only; the returned delta covers
2437
+ * only new slots (`shown` = new passing, `hidden` = new failing).
2438
+ * `replaceAll` rebuilds columns but preserves brushes by dimension key,
2439
+ * re-applying them as one combined delta against an all-visible baseline of
2440
+ * the new roster (`shown` is always empty). `replaceAll` clears the external
2441
+ * mask (slot indices changed meaning); `appendRows` keeps it and treats new
2442
+ * slots as passing until the instance re-supplies it.
2442
2443
  */
2443
2444
 
2444
- /** Default histogram bin count for numeric/temporal dimensions (§16.6). */
2445
+ /** Default histogram bin count for numeric/temporal dimensions. */
2445
2446
  declare const DEFAULT_BIN_COUNT = 24;
2446
2447
  /** Slots whose overall selection-visibility flipped in one operation. */
2447
2448
  interface BrushDelta {
@@ -2458,15 +2459,15 @@ interface CrossfilterStats {
2458
2459
  fullSorts: number;
2459
2460
  /** Permutation merges performed by appendRows. */
2460
2461
  permutationMerges: number;
2461
- /** Incremental filtered-layer bin adjustments (F10-02: O(Δ·D)). */
2462
+ /** Incremental filtered-layer bin adjustments (O(Δ·D)). */
2462
2463
  binUpdates: number;
2463
2464
  /** Full O(rows) filtered-layer recomputes (materialization/oracle only). */
2464
2465
  filteredRecomputes: number;
2465
2466
  }
2466
2467
  declare class TypedColumnCrossfilter<N = Record<string, unknown>> {
2467
- /** Test instrumentation; see CrossfilterStats. Reset with resetStats(). */
2468
+ /** Test instrumentation; see CrossfilterStats. Reset with resetStats. */
2468
2469
  readonly stats: CrossfilterStats;
2469
- /** Count of dims whose filtered layer is live-maintained (F10-02). */
2470
+ /** Count of dims whose filtered layer is live-maintained. */
2470
2471
  private liveDims;
2471
2472
  private dims;
2472
2473
  private byKey;
@@ -2484,11 +2485,11 @@ declare class TypedColumnCrossfilter<N = Record<string, unknown>> {
2484
2485
  /** Monotonic from 0; advances exactly once per observable setBrush change. */
2485
2486
  get selectionRevision(): number;
2486
2487
  resetStats(): void;
2487
- /** §17 telemetry: estimated bytes of typed-column storage held (S13-T07).
2488
+ /** telemetry: estimated bytes of typed-column storage held.
2488
2489
  * Documented components: per-dim value/permutation/bin/code/pass arrays,
2489
2490
  * the global failure counter, and the external mask. */
2490
2491
  estimatedBytes(): number;
2491
- /** F10-02 live-layer bookkeeping — the ONLY writer of `filteredLive`. */
2492
+ /** live-layer bookkeeping — the ONLY writer of `filteredLive`. */
2492
2493
  private setFilteredLive;
2493
2494
  /**
2494
2495
  * (Re)initialize columns from scratch. Clears all brushes and the external
@@ -2510,19 +2511,19 @@ declare class TypedColumnCrossfilter<N = Record<string, unknown>> {
2510
2511
  setBrush(key: string, brush: BrushState): BrushDelta;
2511
2512
  /**
2512
2513
  * 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
2514
+ * instance wires the filter-prop node mask in). Affects summaries only,
2515
+ * never selection visibility. Length must equal rowCount. Notifies on
2515
2516
  * observable change; does NOT advance selectionRevision.
2516
2517
  */
2517
2518
  setExternalMask(passSlots: Uint8Array | null): void;
2518
2519
  /**
2519
- * Immutable summary. The filtered layer is recomputed lazily when dirty
2520
+ * Immutable summary. The filtered layer is recomputed lazily when dirty
2520
2521
  * O(rows) per dirty summarize (v0.7 tier; see module doc). Returned objects
2521
2522
  * are frozen and never mutated by later operations.
2522
2523
  */
2523
2524
  summarize(key: string): DimensionSummary;
2524
2525
  /**
2525
- * Incrementally extend columns with new rows (S9-T09 subset): no full
2526
+ * Incrementally extend columns with new rows: no full
2526
2527
  * rebuild, no full re-argsort — the pre-sorted old permutation merges with
2527
2528
  * the sorted new block. Brushes stay by key and are applied to the NEW slots
2528
2529
  * only; the returned delta covers only new slots. Keeps selectionRevision;
@@ -2551,16 +2552,16 @@ declare class TypedColumnCrossfilter<N = Record<string, unknown>> {
2551
2552
  private binIndex;
2552
2553
  private flip;
2553
2554
  /**
2554
- * F10-02 inline maintenance of LIVE filtered layers, dispatched from the
2555
+ * inline maintenance of LIVE filtered layers, dispatched from the
2555
2556
  * one place that knows the failCount transition. `boundary` is the
2556
2557
  * other-failures picture at the interesting side of the flip (after for
2557
2558
  * 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.
2559
+ * - 0 → the slot crossed the FULLY-VISIBLE boundary: every other live
2560
+ * layer counts it (own layers ignore the own-dim brush, so the brushed
2561
+ * dim's layer is provably unchanged by its own flip);
2562
+ * - 1 → exactly one OTHER dim still fails the slot: only that dim's
2563
+ * what-if-I-cleared-mine layer flips;
2564
+ * - ≥2 → no layer can change.
2564
2565
  * External-mask-excluded and hygiene-invalid slots contribute nothing
2565
2566
  * either way and are skipped.
2566
2567
  */
@@ -2578,27 +2579,27 @@ declare class TypedColumnCrossfilter<N = Record<string, unknown>> {
2578
2579
  }
2579
2580
 
2580
2581
  /**
2581
- * §11 scales & domains (S10-T01/T07) — canonical scale keying, default
2582
+ * scales & domains — canonical scale keying, default
2582
2583
  * palettes, sRGB color interpolation, domain-state machinery, and stable
2583
2584
  * categorical assignment. Pure and engine-free; the instance/projection
2584
2585
  * layers consume these primitives when a styling channel carries a `Scale`.
2585
2586
  *
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.
2587
+ * Semantics:
2588
+ * - Scales are plain descriptors compared by CANONICAL STRUCTURAL VALUE
2589
+ * equal inline literals produce equal keys and never reproject. A function
2590
+ * `by` keys by reference identity (WeakMap token), never by source text.
2590
2591
  * - 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.
2592
+ * masking/brushing/isolation ('dataset' scope): the same metric value never
2593
+ * changes visual meaning because a user brushed. 'hard-scope'/'visible' are
2594
+ * explicit opt-ins that recompute when the caller's scope generation bumps;
2595
+ * streaming 'expand' permits monotonic domain growth on recompute.
2595
2596
  * - Explicit numeric domains always win verbatim (never computed, cached, or
2596
- * unioned).
2597
+ * unioned).
2597
2598
  * - 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.
2599
+ * out-of-domain values take a stable fnv-1a hash slot — NEVER first-seen
2600
+ * order, so arrival order can never recolor a category.
2601
+ * - numeric hygiene: null/non-finite metric values resolve to `null`
2602
+ * (caller falls back to the default style) and are excluded from domains.
2602
2603
  */
2603
2604
 
2604
2605
  type SequentialScale<T, N = Record<string, unknown>> = Extract<Scale<T, N>, {
@@ -2615,7 +2616,7 @@ type DivergingScale<T, N = Record<string, unknown>> = Extract<Scale<T, N>, {
2615
2616
  * order preserved, undefined-valued keys omitted, and a function `by` mapped
2616
2617
  * to a unique reference-identity token (same WeakMap approach — and canonical
2617
2618
  * grammar — as `canonicalFilterKey`). Two scales with equal keys are
2618
- * §11-equivalent: equal inline literals MUST and DO produce equal keys, so
2619
+ * structurally equivalent: equal inline literals MUST and DO produce equal keys, so
2619
2620
  * identity churn never reprojects; swapping a function reference always does.
2620
2621
  */
2621
2622
  declare function canonicalScaleKey<T, N>(scale: Scale<T, N>): string;
@@ -2634,7 +2635,7 @@ declare const DIVERGING_RANGE_DEFAULT: readonly [string, string, string];
2634
2635
  declare function interpolateColor(a: string, b: string, t: number): string;
2635
2636
  /**
2636
2637
  * Sequential color: maps `value` across `domain` onto the two-stop ramp.
2637
- * Returns null (caller renders the default style, §8 hygiene) when the value
2638
+ * Returns null (caller renders the default style, hygiene) when the value
2638
2639
  * is null/non-finite or the domain is null.
2639
2640
  */
2640
2641
  declare function sequentialColor<N = Record<string, unknown>>(scale: SequentialScale<string, N>, value: number | null, domain: readonly [number, number] | null): string | null;
@@ -2649,11 +2650,11 @@ declare function divergingColor<N = Record<string, unknown>>(scale: DivergingSca
2649
2650
  * Sequential size: linear map of `value` across `domain` onto [lo,hi],
2650
2651
  * clamped at the range endpoints. Degenerate domains yield the range
2651
2652
  * midpoint; null/non-finite values and null domains yield null (default
2652
- * style — NaN is never handed to a size buffer, §8).
2653
+ * style — NaN is never handed to a size buffer).
2653
2654
  */
2654
2655
  declare function sequentialSize(range: readonly [number, number], value: number | null, domain: readonly [number, number] | null): number | null;
2655
2656
  /**
2656
- * [min,max] over the finite numbers in `values` (§8 hygiene: null and
2657
+ * [min,max] over the finite numbers in `values` (hygiene: null and
2657
2658
  * non-finite entries are excluded), or null when nothing qualifies. A single
2658
2659
  * qualifying value yields a degenerate [v,v] domain.
2659
2660
  */
@@ -2663,7 +2664,7 @@ interface ResolveDomainArgs {
2663
2664
  * descriptor, so the key already discriminates by metric). Opaque here. */
2664
2665
  key: string;
2665
2666
  /** Explicit caller domain — returned VERBATIM; never computed, cached, or
2666
- * expand-unioned (§11: explicit always wins). */
2667
+ * expand-unioned. */
2667
2668
  explicit?: readonly [number, number] | undefined;
2668
2669
  /** Defaults: scope 'dataset', streaming 'freeze-per-revision'. */
2669
2670
  policy?: DomainPolicy | undefined;
@@ -2673,7 +2674,7 @@ interface ResolveDomainArgs {
2673
2674
  * (bump = recompute). IGNORED under 'dataset' scope — masking/brushing
2674
2675
  * must never change what a color means. */
2675
2676
  scopeGeneration?: number | undefined;
2676
- /** Source lineage this resolve belongs to (F11-02: datasetKey + source
2677
+ /** Source lineage this resolve belongs to (dataset key + source
2677
2678
  * revision). `streaming: 'expand'` unions only WITHIN one lineage — a
2678
2679
  * source replacement starts fresh instead of unioning dead extrema.
2679
2680
  * Callers that omit it keep the legacy always-union behavior. */
@@ -2683,7 +2684,7 @@ interface ResolveDomainArgs {
2683
2684
  compute: () => readonly [number, number] | null;
2684
2685
  }
2685
2686
  /**
2686
- * Per-instance domain freezer keyed by canonical scale key (§11).
2687
+ * Per-instance domain freezer keyed by canonical scale key.
2687
2688
  *
2688
2689
  * FREEZE-PER-REVISION: under scope 'dataset' the domain is computed ONCE per
2689
2690
  * {key, datasetRevision} — repeat resolves return the frozen value without
@@ -2722,24 +2723,24 @@ declare function categoricalIndex(domain: readonly string[] | undefined, palette
2722
2723
  declare function categoricalRows(domain: readonly string[] | undefined, seen: Iterable<string>): string[];
2723
2724
 
2724
2725
  /**
2725
- * DEF2 capability-policy module (spec §13; plan S1-T08/S4-T05).
2726
+ * capability-policy module.
2726
2727
  *
2727
- * §13 (normative): for capabilities where the core owns a fallback path, the
2728
+ * (normative): for capabilities where the core owns a fallback path, the
2728
2729
  * core selects native-vs-fallback ONCE at mount from the engine's declared
2729
2730
  * `capabilities` record — never by sniffing method presence — and unsupported
2730
- * *requested* props degrade loudly (a §5.1 diagnostic), never as silent no-ops.
2731
+ * *requested* props degrade loudly (a diagnostic), never as silent no-ops.
2731
2732
  *
2732
2733
  * 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.
2734
+ * - {@link resolveEnginePolicy} turns the capability record + the host's
2735
+ * requested features into one frozen {@link EnginePolicy} at mount.
2736
+ * - {@link assertCapabilityMethodParity} is the mount-time dev-mode record
2737
+ * vs. method-surface assertion, restricted to honestly checkable pairs.
2738
+ * - {@link normalizeCommitForCapabilities} strips commit payload an engine
2739
+ * declared it cannot honor, so incapable adapters never see it.
2739
2740
  */
2740
2741
 
2741
2742
  /** One loud degradation: a feature the host requested that the mounted engine
2742
- * does not declare. Feeds the §5.1 dev diagnostic at mount. */
2743
+ * does not declare. Feeds the dev diagnostic at mount. */
2743
2744
  interface EnginePolicyDegradation {
2744
2745
  readonly feature: string;
2745
2746
  readonly reason: string;
@@ -2749,29 +2750,29 @@ interface EnginePolicyDegradation {
2749
2750
  interface RequestedEngineFeatures {
2750
2751
  edgeArrows?: boolean;
2751
2752
  images?: boolean;
2752
- /** §16.3 stage-4: a `clusters` spec is active this session. */
2753
+ /** stage-4: a `clusters` spec is active this session. */
2753
2754
  clusters?: boolean;
2754
2755
  }
2755
2756
  /**
2756
- * The frozen mount-time native-vs-fallback record (§13). Evaluated exactly
2757
+ * The frozen mount-time native-vs-fallback record. Evaluated exactly
2757
2758
  * once per mount from `EngineCapabilities` and never revisited — capability
2758
2759
  * records are static declarations fixed at engine construction, so the policy
2759
2760
  * must not drift even if a caller mutates the input record afterwards.
2760
2761
  */
2761
2762
  interface EnginePolicy {
2762
- /** §16.12 arrowheads: engine-drawn, or the prop is inert (+ dev warning). */
2763
+ /** arrowheads: engine-drawn, or the prop is inert (+ dev warning). */
2763
2764
  readonly edgeArrows: 'native' | 'inert';
2764
- /** §8 image sprites: atlas-backed, or the placeholder glyph with refs
2765
+ /** image sprites: atlas-backed, or the placeholder glyph with refs
2765
2766
  * retained for a future compatible engine. */
2766
2767
  readonly images: 'native' | 'placeholder';
2767
- /** §13 link hover/click: engine events, or the core's CPU grid fallback. */
2768
+ /** link hover/click: engine events, or the core's CPU grid fallback. */
2768
2769
  readonly linkPicking: 'native' | 'cpu-fallback';
2769
- /** §16.3 stage-4 cluster force: engine-applied, or inert (membership,
2770
+ /** stage-4 cluster force: engine-applied, or inert (membership,
2770
2771
  * labels, and centroids are core-owned and unaffected). */
2771
2772
  readonly clusterForce: 'native' | 'inert';
2772
2773
  /** Channels eligible for ranged (partial) uploads; empty = full replaces. */
2773
2774
  readonly rangedChannels: ReadonlySet<EngineBufferChannel>;
2774
- /** §17 stop-at-rest: 'stops' when the engine declares idleFrames:'stops'.
2775
+ /** stop-at-rest: 'stops' when the engine declares idleFrames:'stops'.
2775
2776
  * Observability only (telemetry/harness read it) — an idle-spinning engine
2776
2777
  * is a documented state, never a degradation entry: nothing was
2777
2778
  * host-REQUESTED, so there is nothing to warn about. */
@@ -2784,7 +2785,7 @@ interface EnginePolicy {
2784
2785
  * Resolve the mount-time engine policy from the declared capability record.
2785
2786
  *
2786
2787
  * Decisions come from `capabilities` ONLY — method sniffing is forbidden by
2787
- * §13. The result is deep-frozen and holds a defensive copy of
2788
+ * The result is deep-frozen and holds a defensive copy of
2788
2789
  * `rangeUpdates`, so mutating the input record afterwards changes nothing.
2789
2790
  * A degradation entry exists only for features the host actually requested
2790
2791
  * that the engine does not declare; unrequested gaps stay silent.
@@ -2795,25 +2796,25 @@ declare function resolveEnginePolicy(capabilities: EngineCapabilities, requested
2795
2796
  * with the engine's method surface? Returns a list of human-readable
2796
2797
  * mismatches (empty = consistent).
2797
2798
  *
2798
- * Why so few checks? §13's illustrative parity assertion
2799
+ * Why so few checks? An illustrative parity assertion
2799
2800
  * (`capabilities.linkPicking === (typeof engine.linkAt === 'function')`)
2800
- * presumes the spec's full method surface; the v0.1 adapter contract
2801
+ * presumes a broader method surface; the v0.1 adapter contract
2801
2802
  * 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.
2803
+ * checkable method pair. Those are instead covered by engine probes that
2804
+ * validate declared records against observed behavior:
2805
+ *
2806
+ * - `linkPicking`: native picking arrives through mount-time host events
2807
+ * (`onLinkClick`/`onLinkHover`), not a probeable `linkAt` method — there
2808
+ * is nothing on the engine object to compare the record against.
2809
+ * - `edgeArrows` / `pointImages` / `rangeUpdates`: honored inside
2810
+ * `commit()` payload handling (`config.linkArrows`, `resources`, ranged
2811
+ * uploads) with no distinguishing method; only behavior can validate them.
2812
+ * - `simulation`: `start()`/`pause()` are mandatory on every engine (static
2813
+ * engines no-op them), so method presence carries no signal either way.
2814
+ * - `pointsInPolygon`-family (`pointsInRect`, `captureScreenshot`,
2815
+ * `neighborIndices`, `screenToSpace`/`spaceToScreen`, `setPinnedIndices`,
2816
+ * `zoomToIndex`): optional-by-contract with no declaring capability bit —
2817
+ * absence is legitimate, so no check is fabricated for them.
2817
2818
  *
2818
2819
  * The one honest pair on this surface: `trackedPositions` declares position
2819
2820
  * readback works, so `getPositions` must actually be present.
@@ -2821,10 +2822,10 @@ declare function resolveEnginePolicy(capabilities: EngineCapabilities, requested
2821
2822
  declare function assertCapabilityMethodParity(engine: GraphEngine): string[];
2822
2823
  /**
2823
2824
  * 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).
2825
+ * - `resources` (image atlas + per-point image index) unless `pointImages`;
2826
+ * - `config.linkArrows` unless `edgeArrows`;
2827
+ * - `config.cluster` unless `clusterForce` (stage 4 — the core keeps
2828
+ * membership, labels, and centroids; only the FORCE is engine-side).
2828
2829
  * A `config` left empty by the strip is dropped entirely.
2829
2830
  *
2830
2831
  * IDENTITY-PRESERVING: when nothing needs stripping the SAME commit object
@@ -2837,15 +2838,15 @@ declare function normalizeCommitForCapabilities(commit: EngineCommit, capabiliti
2837
2838
  };
2838
2839
 
2839
2840
  /**
2840
- * §8 shared numeric hygiene (R-19-10) — THE single coercion layer for every
2841
+ * shared numeric hygiene — THE single coercion layer for every
2841
2842
  * numeric consumer in orbit-core.
2842
2843
  *
2843
2844
  * 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
2845
+ * projection buffers, scale domains, metric columns,
2846
+ * crossfilter bins, table lanes — the value is REQUIRED to route
2846
2847
  * through `coerceNumeric` / `coerceNumericInto`. Non-numeric and non-finite
2847
2848
  * inputs (including the string sentinels `"NaN"` / `"Infinity"` /
2848
- * `"-Infinity"` that JSON transports smuggle through, §5) coerce to `null`:
2849
+ * `"-Infinity"` that JSON transports smuggle through) coerce to `null`:
2849
2850
  * the row falls back to the default style and is excluded from domain
2850
2851
  * computation. NaN NEVER escapes this module — not as a return value and not
2851
2852
  * into a GPU buffer.
@@ -2853,16 +2854,15 @@ declare function normalizeCommitForCapabilities(commit: EngineCommit, capabiliti
2853
2854
  * Coercion rules:
2854
2855
  * - numbers pass iff `Number.isFinite` (NaN / ±Infinity → null);
2855
2856
  * - 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);
2857
+ * 'NaN' / 'Infinity' / '-Infinity' / '+Infinity' → null; anything else
2858
+ * parses via `Number(...)` and passes iff finite (so '1e3' → 1000 but
2859
+ * '12px' → null — `Number`, not `parseFloat`, so no partial prefixes);
2859
2860
  * - booleans, objects, arrays, functions, symbols, bigints, null, and
2860
- * undefined → null (no `valueOf`/`toString` coercion side channels).
2861
+ * undefined → null (no `valueOf`/`toString` coercion side channels).
2861
2862
  *
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.
2863
+ * `crossfilter.ts` predates this module and retains its own inline finite
2864
+ * checks. Any consolidation must route through `coerceNumeric` so the
2865
+ * sentinel-string rules stay defined in exactly one place.
2866
2866
  */
2867
2867
  declare function coerceNumeric(value: unknown): number | null;
2868
2868
  /**
@@ -2877,31 +2877,31 @@ declare function coerceNumeric(value: unknown): number | null;
2877
2877
  declare function coerceNumericInto(target: Float32Array, index: number, value: unknown, fallback: number): boolean;
2878
2878
 
2879
2879
  /**
2880
- * §12 metrics (v0.8 subset): lazy degree-family primitives over the
2880
+ * metrics (v0.8 subset): lazy degree-family primitives over the
2881
2881
  * maintained topology plus revision-gated admission of async metric columns.
2882
2882
  *
2883
2883
  * - 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.
2884
+ * first request per model revision, in ONE combined O(n + L) pass, and
2885
+ * cached as Float64Arrays until the model revision changes.
2886
2886
  * - 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).
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: '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
+ * 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.
2898
2898
  * - Storage encodes null as NaN inside Float64Arrays; `getMetricValue`
2899
- * converts back at the boundary so NaN never escapes to callers.
2899
+ * converts back at the boundary so NaN never escapes to callers.
2900
2900
  * - Admitted columns SHADOW the built-in degree family under the same name
2901
- * (a precomputed/server 'degree' column wins; §12 precomputed path).
2901
+ * (a precomputed/server 'degree' column wins; precomputed path).
2902
2902
  */
2903
2903
 
2904
- /** Topology snapshot the degree family is computed from (§12). */
2904
+ /** Topology snapshot the degree family is computed from. */
2905
2905
  interface MetricModelInput<N = Record<string, unknown>> {
2906
2906
  /** Accepted nodes in accepted-base order (index i ↔ point i). */
2907
2907
  nodes: readonly GraphNode<N>[];
@@ -2933,7 +2933,7 @@ declare class MetricStore<N = Record<string, unknown>> {
2933
2933
  /** Admitted async columns by metric name; NaN encodes null. */
2934
2934
  private readonly columns;
2935
2935
  private degreePasses;
2936
- /** §17 telemetry: estimated bytes of metric storage held (S13-T07). */
2936
+ /** telemetry: estimated bytes of metric storage held. */
2937
2937
  estimatedBytes(): number;
2938
2938
  /** Number of combined degree-family compute passes (test observability). */
2939
2939
  get degreeComputePasses(): number;
@@ -2946,10 +2946,10 @@ declare class MetricStore<N = Record<string, unknown>> {
2946
2946
  */
2947
2947
  setModel(model: MetricModelInput<N>): void;
2948
2948
  /**
2949
- * Joins async metric columns against the accepted model (§12).
2949
+ * Joins async metric columns against the accepted model.
2950
2950
  * Revision-gated PER COLUMN (I1): a column whose issue-time
2951
2951
  * `forModelRevision` stamp differs from `opts.modelRevision` is discarded
2952
- * (info diagnostic — a normal async race outcome, §9.2). A missing or
2952
+ * (info diagnostic — a normal async race outcome). A missing or
2953
2953
  * mismatched stamp is never defaulted to the current revision — that
2954
2954
  * would make the gate self-satisfying.
2955
2955
  * Structural rejections ('index' length mismatch, missing/mismatched ids)
@@ -2966,7 +2966,7 @@ declare class MetricStore<N = Record<string, unknown>> {
2966
2966
  getMetricValue(metric: MetricName, index: number): number | null;
2967
2967
  /**
2968
2968
  * Raw column in accepted-base order, or null when unavailable. NaN encodes
2969
- * null (§12) — consumers exclude NaN slots from domains. Do NOT mutate:
2969
+ * null — consumers exclude NaN slots from domains. Do NOT mutate:
2970
2970
  * this is the live cache, not a copy.
2971
2971
  */
2972
2972
  metricValues(metric: MetricName): Float64Array | null;
@@ -2978,22 +2978,22 @@ declare class MetricStore<N = Record<string, unknown>> {
2978
2978
  }
2979
2979
 
2980
2980
  /**
2981
- * §16.8 minimap / overview — CPU fallback lane (S11-T09/T10).
2981
+ * minimap / overview — CPU fallback lane.
2982
2982
  *
2983
2983
  * 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
2984
+ * second draw pass — matrix), so this controller IS the minimap thumbnail
2985
+ * path: an O(n) CPU rasterization of the position mirror into a small
2986
2986
  * RGBA dot field. It is a pure controller — no DOM, no canvas — the React
2987
2987
  * component blits the returned `Uint8ClampedArray` into an `ImageData`/canvas
2988
- * and draws the viewport rectangle on top (O(1) from `getViewport()`, fully
2988
+ * and draws the viewport rectangle on top (O(1) from `getViewport`, fully
2989
2989
  * decoupled from thumbnail refresh cadence).
2990
2990
  *
2991
- * Refresh cadence (spec §16.8): ≤ 2 Hz while the simulation is hot (positions
2991
+ * Refresh cadence: ≤ 2 Hz while the simulation is hot (positions
2992
2992
  * change continuously on the GPU, so the epoch is ignored), ≤ 1 Hz after a
2993
2993
  * change while idle, and ZERO work while idle with an unchanged positions
2994
2994
  * epoch — `shouldRefresh` is the single throttle gate and latches its clock /
2995
2995
  * epoch only when it answers true (a `true` must be followed by one
2996
- * `rasterize()`).
2996
+ * `rasterize`).
2997
2997
  *
2998
2998
  * Orientation: minimap pixel y grows DOWNWARD while world (space) y grows
2999
2999
  * upward — the same flip cosmos applies in its space→screen scale (dist
@@ -3032,7 +3032,7 @@ interface OverviewRaster {
3032
3032
  bitmap: Uint8ClampedArray;
3033
3033
  bounds: OverviewBounds;
3034
3034
  }
3035
- /** Spec §16.8: the CPU fallback rasterizes into a 256² target. */
3035
+ /** Spec the CPU fallback rasterizes into a 256² target. */
3036
3036
  declare const OVERVIEW_SIZE_DEFAULT = 256;
3037
3037
  /** Hot-simulation refresh floor: ≤ 2 Hz. */
3038
3038
  declare const OVERVIEW_HOT_INTERVAL_MS = 500;
@@ -3042,7 +3042,7 @@ declare class OverviewController {
3042
3042
  private readonly getScene;
3043
3043
  private readonly getVisible;
3044
3044
  readonly size: number;
3045
- /** Transform of the LAST rasterization; null until rasterize() succeeds. */
3045
+ /** Transform of the LAST rasterization; null until rasterize succeeds. */
3046
3046
  private frame;
3047
3047
  private lastRefreshMs;
3048
3048
  private lastEpoch;
@@ -3052,16 +3052,16 @@ declare class OverviewController {
3052
3052
  * when it returns true, so each `true` accounts for exactly one refresh:
3053
3053
  *
3054
3054
  * - hot (`simulationRunning`): time-gated only (≤ 2 Hz) — the epoch is
3055
- * ignored because positions change continuously without epoch advances;
3055
+ * ignored because positions change continuously without epoch advances;
3056
3056
  * - idle: refresh only when the epoch ADVANCED since the last refresh,
3057
- * time-gated at ≤ 1 Hz;
3057
+ * time-gated at ≤ 1 Hz;
3058
3058
  * - idle + unchanged epoch: always false — zero work, forever.
3059
3059
  */
3060
3060
  shouldRefresh(nowMs: number, simulationRunning: boolean, epoch: number): boolean;
3061
3061
  /**
3062
3062
  * Rasterizes the current scene into a fresh `size²` RGBA dot field: 1 px
3063
3063
  * white dots whose alpha ACCUMULATES on overlap (heatmap-ish density),
3064
- * dimmed for mask-hidden points; NaN pairs (§7.3 tombstones) are skipped.
3064
+ * dimmed for mask-hidden points; NaN pairs are skipped.
3065
3065
  * World bounds map into the thumbnail with a 5 % edge padding at a UNIFORM
3066
3066
  * scale (aspect preserved, centered on the short axis) and a downward pixel
3067
3067
  * y (see module header). Returns null when there is no scene or no point.
@@ -3077,34 +3077,34 @@ declare class OverviewController {
3077
3077
  }
3078
3078
 
3079
3079
  /**
3080
- * §16.14 SVG export (S15 export lane) — the M7 pure module.
3080
+ * SVG export — the engine-free pure module.
3081
3081
  *
3082
3082
  * ENGINE-INDEPENDENT BY CONSTRUCTION, not by discipline: positions and
3083
3083
  * projected styles come IN as a plain descriptor, vector markup goes OUT as a
3084
3084
  * 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
3085
+ * reuses this verbatim under plain Node, and the test
3086
3086
  * suite runs it exactly that way. Keeping it engine-free is an M7
3087
3087
  * requirement, which is why it is a standalone module rather than instance
3088
3088
  * code that might one day be extracted.
3089
3089
  *
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.
3090
+ * Output discipline:
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 (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.
3101
3101
  */
3102
3102
  interface SvgSceneNode {
3103
3103
  x: number;
3104
3104
  y: number;
3105
3105
  /** Radius in output px (the caller halves its size-buffer diameter). */
3106
3106
  r: number;
3107
- /** Any CSS color string (the caller projects RGBA buffers to rgba()). */
3107
+ /** Any CSS color string (the caller projects RGBA buffers to rgba). */
3108
3108
  color: string;
3109
3109
  }
3110
3110
  interface SvgSceneEdge {
@@ -3162,21 +3162,21 @@ declare function escapeXml(text: string): string;
3162
3162
  declare function renderSvg(scene: SvgScene, opts?: RenderSvgOptions): string;
3163
3163
 
3164
3164
  /**
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
3165
+ * Columnar-native acceptance rules the column-oriented twin of validate.ts,
3166
+ * built to run INSIDE the worker over typed
3167
3167
  * columns without materializing a single row object.
3168
3168
  *
3169
3169
  * Semantics mirror the object lane EXACTLY (the equivalence oracle pins
3170
3170
  * 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).
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).
3180
3180
  *
3181
3181
  * Duplicates hide in TWO encodings: two rows sharing a code, and two
3182
3182
  * DISTINCT dictionary entries holding equal strings. Both are handled by
@@ -3211,21 +3211,21 @@ interface ColumnarAcceptance {
3211
3211
  declare function acceptColumnar(snapshot: ColumnarGraphSnapshot<unknown, unknown>): ColumnarAcceptance;
3212
3212
 
3213
3213
  /**
3214
- * §5 columnar snapshot lane (S13-T01, ADR-006) — structural validation and
3214
+ * columnar snapshot lane — structural validation and
3215
3215
  * the materialization bridge.
3216
3216
  *
3217
3217
  * Validation is O(number of columns + rows) and runs BEFORE transfer or
3218
3218
  * admission. Columnar structural corruption is intentionally not repaired
3219
- * row by row — offset/index misalignment can reinterpret every later row
3219
+ * row by row — offset/index misalignment can reinterpret every later row
3220
3220
  * so any structural issue rejects the WHOLE snapshot, the prior scene stays
3221
- * intact, and nothing throws from a React render (spec §5.1).
3221
+ * intact, and nothing throws from a React render.
3222
3222
  *
3223
3223
  * The bridge materializes a VALID columnar snapshot into the object form and
3224
3224
  * feeds the existing pipeline, so duplicate-id / dangling-edge / self-loop
3225
3225
  * 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.
3226
+ * inherits every object-lane rule by construction. Under `execution: 'main'`
3227
+ * materialization remains synchronous; the worker lane can perform acceptance
3228
+ * off-thread before the same shared pipeline runs.
3229
3229
  *
3230
3230
  * Null semantics: `nulls` is one byte per row, nonzero = null. Null attr
3231
3231
  * values materialize as `null` (JSON-ish; every numeric/temporal consumer
@@ -3242,7 +3242,7 @@ interface ColumnarIssue {
3242
3242
  }
3243
3243
  /**
3244
3244
  * O(columns + rows) structural validation. Empty array ⇒ structurally sound
3245
- * (duplicate ids, self-loops, and parallel-edge rules are NOT checked here
3245
+ * (duplicate ids, self-loops, and parallel-edge rules are NOT checked here
3246
3246
  * they are shared object-lane semantics applied after materialization).
3247
3247
  */
3248
3248
  declare function validateColumnarStructure(snapshot: ColumnarGraphSnapshot<unknown, unknown>): ColumnarIssue[];
@@ -3266,7 +3266,7 @@ declare function buildAcceptedFromColumnar<N, E>(snapshot: ColumnarGraphSnapshot
3266
3266
  declare function columnarArrayBuffers(snapshot: ColumnarGraphSnapshot<unknown, unknown>): ArrayBuffer[];
3267
3267
  /**
3268
3268
  * `bufferOwnership: 'transfer'` — detach every underlying ArrayBuffer.
3269
- * Called ONLY after validation and admission both succeeded (ADR-006 D4:
3269
+ * Called ONLY after validation and admission both succeeded:
3270
3270
  * reject-before-allocation extends to reject-before-detach). Returns the
3271
3271
  * number of buffers detached. SharedArrayBuffer-backed views are skipped
3272
3272
  * (they cannot detach and remain shared by contract).
@@ -3274,8 +3274,8 @@ declare function columnarArrayBuffers(snapshot: ColumnarGraphSnapshot<unknown, u
3274
3274
  declare function detachColumnarBuffers(snapshot: ColumnarGraphSnapshot<unknown, unknown>): number;
3275
3275
 
3276
3276
  /**
3277
- * §17 serializable field descriptors (S13-T01, ADR-006 D1) — the worker-lane
3278
- * accessor forms: `FieldAccessor` + `SerializableTransform` + the `field()`
3277
+ * serializable field descriptors — the worker-lane
3278
+ * accessor forms: `FieldAccessor` + `SerializableTransform` + the `field`
3279
3279
  * manual-schema helper. Descriptors are DATA, never code: they cross the
3280
3280
  * worker boundary by structured clone, compare by canonical structural
3281
3281
  * value, and unknown transform ops are validation errors (spec: "descriptors
@@ -3293,14 +3293,14 @@ declare function detachColumnarBuffers(snapshot: ColumnarGraphSnapshot<unknown,
3293
3293
  * projection ever runs.
3294
3294
  */
3295
3295
 
3296
- /** Branded attr path — `field<A,T>()` is a manual-schema ASSERTION (compile
3297
- * -time narrowing for codegen/schema packages), not runtime validation. */
3296
+ /** Branded attr path — `field<A,T>` is a manual-schema ASSERTION for
3297
+ * compile-time narrowing in codegen/schema packages, not runtime validation. */
3298
3298
  type TypedFieldPath<A, T> = string & {
3299
3299
  readonly __attrs?: A;
3300
3300
  readonly __value?: T;
3301
3301
  };
3302
3302
  declare function field<A, T>(path: string): TypedFieldPath<A, T>;
3303
- /** §17 transform whitelist. Closed set — extending it is a spec amendment. */
3303
+ /** transform whitelist. Closed set — extending it is a spec amendment. */
3304
3304
  type SerializableTransform = {
3305
3305
  op: 'identity';
3306
3306
  } | {
@@ -3347,7 +3347,7 @@ declare function isFieldAccessor(value: unknown): value is FieldAccessor<unknown
3347
3347
  declare function descriptorKey(accessor: FieldAccessor<unknown, unknown>): string;
3348
3348
  /**
3349
3349
  * 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
3350
+ * function both lanes share (byte-exact parity starts with ONE
3351
3351
  * evaluation implementation, imported by both threads, never duplicated).
3352
3352
  */
3353
3353
  declare function evaluateFieldAccessor(accessor: FieldAccessor<unknown, unknown>, id: string, attrs: Readonly<Record<string, unknown>> | undefined): unknown;