@modernrelay/orbit-core 0.13.5 → 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.js CHANGED
@@ -1,7 +1,5 @@
1
- import { deriveClusters, resolveClusterCenters, clusterCentroids } from './chunk-XAR262L3.js';
2
- export { DEFAULT_CLUSTER_CENTER_RADIUS, DEFAULT_LAYOUT_SEED, clusterCentroids, deriveClusters, generateClusterCenters, resolveClusterCenters } from './chunk-XAR262L3.js';
3
- import { DIAGNOSTIC_SAMPLE_CAP, encodeStringTable, collectTransfers, EnvelopeSequencer, RequestLedger } from './chunk-NIJX5NVJ.js';
4
- export { DIAGNOSTIC_SAMPLE_CAP, acceptColumnar, collectTransfers, decodeStringTable, encodeStringTable, judgeEpoch } from './chunk-NIJX5NVJ.js';
1
+ import { DIAGNOSTIC_SAMPLE_CAP, encodeStringTable, collectTransfers, deriveClusters, resolveClusterCenters, clusterCentroids, EnvelopeSequencer, RequestLedger } from './chunk-KRCG2JFN.js';
2
+ export { DEFAULT_CLUSTER_CENTER_RADIUS, DEFAULT_LAYOUT_SEED, DIAGNOSTIC_SAMPLE_CAP, acceptColumnar, clusterCentroids, collectTransfers, decodeStringTable, deriveClusters, encodeStringTable, generateClusterCenters, judgeEpoch, resolveClusterCenters } from './chunk-KRCG2JFN.js';
5
3
  import { createStore } from 'zustand/vanilla';
6
4
 
7
5
  // src/errors.ts
@@ -98,6 +96,10 @@ function validateSnapshot(snapshot) {
98
96
  record(invalidNode, `[${i}]`);
99
97
  continue;
100
98
  }
99
+ if (id.includes("\0")) {
100
+ record(invalidNode, `[${i}]`);
101
+ continue;
102
+ }
101
103
  if (nodeIndex.has(id)) {
102
104
  record(duplicateNode, id);
103
105
  continue;
@@ -156,7 +158,7 @@ function validateSnapshot(snapshot) {
156
158
  "invalid-node",
157
159
  "error",
158
160
  invalidNode,
159
- `${invalidNode.count} node row(s) dropped: missing or non-string id`
161
+ `${invalidNode.count} node row(s) dropped: missing, non-string, or NUL-containing id`
160
162
  );
161
163
  pushDiagnostic(
162
164
  diagnostics,
@@ -347,7 +349,7 @@ function validateGroupSpecs(specs, nodeIndex) {
347
349
  severity: "error",
348
350
  count,
349
351
  sampleIds: samples,
350
- message: `groups rejected before scene rewrite (\xA716.3 acyclic/singly-parented): ${kinds} \u2014 the previous group configuration stays active`
352
+ message: `groups rejected before scene rewrite: ${kinds} \u2014 the previous group configuration stays active`
351
353
  }
352
354
  };
353
355
  }
@@ -417,7 +419,7 @@ function validateGroupBySpec(spec) {
417
419
  if (!expandOk) problems.push("semanticZoom.expandAbove must be a finite number");
418
420
  if (collapseOk && expandOk && !(sz.expandAbove > sz.collapseBelow)) {
419
421
  problems.push(
420
- "semanticZoom.expandAbove must be strictly greater than collapseBelow (hysteresis, R-16.3-22)"
422
+ "semanticZoom.expandAbove must be strictly greater than collapseBelow to provide a hysteresis gap"
421
423
  );
422
424
  }
423
425
  }
@@ -427,7 +429,7 @@ function validateGroupBySpec(spec) {
427
429
  severity: "error",
428
430
  count: problems.length,
429
431
  sampleIds: [],
430
- message: `groupBy rejected (\xA716.3/D4): ${problems.join("; ")} \u2014 the previous groupBy configuration stays active`
432
+ message: `groupBy rejected: ${problems.join("; ")} \u2014 the previous groupBy configuration stays active`
431
433
  };
432
434
  }
433
435
  function deriveGroupsByKey(nodes, by, isCollapsedKey) {
@@ -474,7 +476,7 @@ function deriveGroupsByKey(nodes, by, isCollapsedKey) {
474
476
  severity: "warning",
475
477
  count: errorCount,
476
478
  sampleIds: errorSamples,
477
- message: "groupBy.by threw; the affected nodes derived as ungrouped (\xA716.3/\xA78)"
479
+ message: "groupBy.by threw; the affected nodes derived as ungrouped"
478
480
  }
479
481
  };
480
482
  }
@@ -699,27 +701,27 @@ var EMPTY_INDEX = /* @__PURE__ */ new Map();
699
701
  var Reconciler = class {
700
702
  datasetKey = null;
701
703
  hasScene = false;
702
- // Previous scene, kept for the structural diff (§7.2).
704
+ // Previous scene, kept for the structural diff.
703
705
  prevIdByIndex = [];
704
706
  prevIndexById = EMPTY_INDEX;
705
707
  prevEdgeIdByIndex = [];
706
708
  prevLinks = new Uint32Array(0);
707
709
  /**
708
710
  * Declared node.x/y as of the previous reconcile, for nodes that declared
709
- * them. Lets Priority 1 distinguish a CHANGED declaration (caller intent
711
+ * them. Lets Priority 1 distinguish a CHANGED declaration (caller intent
710
712
  * wins over any cache) from an unchanged one (defers to live drift). Fresh
711
713
  * per pass, so departed ids drop and a re-add treats its declaration as new.
712
714
  */
713
715
  prevDeclared = /* @__PURE__ */ new Map();
714
716
  /**
715
- * CPU position mirror for the CURRENT scene, indexed by slot (§7.1 posBuf).
717
+ * CPU position mirror for the CURRENT scene, indexed by slot.
716
718
  * Owned copy — never aliases a published scene's positions array, so
717
719
  * noteEnginePositions never mutates an already-published RenderScene.
718
720
  */
719
721
  livePositions = new Float32Array(0);
720
722
  /**
721
- * Ids removed from the scene → last known finite position (§7.1/§7.3
722
- * leave-and-return guarantee). Map insertion order doubles as LRU order;
723
+ * Ids removed from the scene → last known finite position, preserving the
724
+ * leave-and-return guarantee. Map insertion order doubles as LRU order;
723
725
  * invariant: never overlaps the current scene's id set.
724
726
  */
725
727
  departed = /* @__PURE__ */ new Map();
@@ -833,7 +835,7 @@ var Reconciler = class {
833
835
  }
834
836
  /**
835
837
  * Copy engine-read positions into the live cache for the CURRENT scene's
836
- * slots (§7.1 per-event readback — simulation end, pre-structural-swap).
838
+ * slots.
837
839
  * Extra trailing floats are ignored; a short buffer updates a prefix.
838
840
  */
839
841
  noteEnginePositions(positions) {
@@ -1389,7 +1391,7 @@ function mergeDiagnostics(merge) {
1389
1391
  severity: "info",
1390
1392
  count: merge.shadowedCount,
1391
1393
  sampleIds: merge.shadowedSamples,
1392
- message: `${merge.shadowedCount} overlay node row(s) shadowed by a same-id row admitted earlier (\xA77.5); rows retained`
1394
+ message: `${merge.shadowedCount} overlay node row(s) shadowed by a same-id row admitted earlier; rows retained`
1393
1395
  });
1394
1396
  }
1395
1397
  if (merge.duplicateEdgeCount > 0) {
@@ -1439,7 +1441,7 @@ function sessionCommitDiagnostics(tallies, danglingCount, danglingSamples = [])
1439
1441
  severity: "warning",
1440
1442
  count: danglingCount,
1441
1443
  sampleIds: danglingSamples.slice(0, DIAGNOSTIC_SAMPLE_CAP),
1442
- message: `${danglingCount} ingested edge(s) still awaiting an endpoint at commit (pending-endpoint index; \xA77.5)`
1444
+ message: `${danglingCount} ingested edge(s) still awaiting an endpoint at commit (the endpoint was not ingested before the session committed)`
1443
1445
  });
1444
1446
  }
1445
1447
  return out;
@@ -1569,7 +1571,7 @@ var IncrementalAlphaComposer = class {
1569
1571
  bufB = null;
1570
1572
  staleA = [];
1571
1573
  staleB = [];
1572
- /** Which buffer the NEXT nextBuffer() call returns (0 = A, 1 = B). */
1574
+ /** Which buffer the NEXT nextBuffer call returns (0 = A, 1 = B). */
1573
1575
  next = 0;
1574
1576
  // --- seed key ---
1575
1577
  seededBase = null;
@@ -1672,7 +1674,7 @@ var PressureSampler = class {
1672
1674
  /**
1673
1675
  * Record one onFrame tick. `settled` marks a tick that arrived while the
1674
1676
  * scene was at rest (sim settled, no pending commit work) — the idle-
1675
- * wakeup counter, which reads 0 when the ADR-005 gated clock is honest.
1677
+ * wakeup counter, which reads 0 when the gated activity clock is honest.
1676
1678
  */
1677
1679
  noteFrame(timeMs, settled) {
1678
1680
  this.frames += 1;
@@ -1842,7 +1844,7 @@ var DegradeController = class {
1842
1844
  /**
1843
1845
  * Resource-admission trigger: engage the NEXT not-yet-engaged step in the
1844
1846
  * declared order. Null when the order is exhausted — the caller must then
1845
- * REJECT before allocating (§17: never silently erase semantic styling).
1847
+ * REJECT before allocating.
1846
1848
  */
1847
1849
  engageNextResourceStep(visible) {
1848
1850
  for (const step of this.limits.resourceDegradationOrder) {
@@ -2055,8 +2057,8 @@ var LinkPickIndex = class {
2055
2057
  while (!r.done) r = it.next();
2056
2058
  }
2057
2059
  /**
2058
- * Incremental build: yields whenever `now() − sliceStart ≥ budgetMs` so a
2059
- * scheduler can spread the work across idle frames (§17 long-task budget).
2060
+ * Incremental build: yields whenever `now − sliceStart ≥ budgetMs` so a
2061
+ * scheduler can spread the work across idle frames.
2060
2062
  * Pure generator — no rAF/timers here; the caller owns scheduling.
2061
2063
  *
2062
2064
  * The previous grid stays armed and queryable until the new one commits on
@@ -2220,7 +2222,7 @@ var LinkPickIndex = class {
2220
2222
  * Nearest link within `tolerance` (space units) of the space point
2221
2223
  * `(x, y)`, or null. Scans the candidate cells covering the tolerance
2222
2224
  * disc's bounding box (typically the 3×3 neighborhood; more when the
2223
- * tolerance exceeds the cell size), applies the optional §9.1 visibility
2225
+ * tolerance exceeds the cell size), applies the optional visibility
2224
2226
  * mask per candidate, then runs the exact point→segment distance test.
2225
2227
  * Nearest wins; exact-distance ties break toward the LOWER link index.
2226
2228
  * Returns null while unbuilt/invalidated (picking disarmed).
@@ -2372,7 +2374,7 @@ var EdgePickingFacade = class {
2372
2374
  this.generation++;
2373
2375
  this.index.invalidate();
2374
2376
  }
2375
- /** §9.1 mask pass-through stub: applied per candidate at query time. */
2377
+ /** mask pass-through stub: applied per candidate at query time. */
2376
2378
  setLinkVisibilityMask(mask) {
2377
2379
  this.mask = mask;
2378
2380
  }
@@ -2732,7 +2734,7 @@ function throwAborted2(signal, sourceId, targetId) {
2732
2734
  const reason = signal.reason;
2733
2735
  throw new OrbitOperationError(
2734
2736
  reason === void 0 ? { code: "aborted" } : { code: "aborted", cause: reason },
2735
- `local find('${sourceId}' \u2192 '${targetId}') aborted mid-scan (\xA716.2)`
2737
+ `local find('${sourceId}' \u2192 '${targetId}') aborted mid-scan`
2736
2738
  );
2737
2739
  }
2738
2740
  function createLocalPathService(getBase) {
@@ -2917,7 +2919,7 @@ function throwAborted3(signal, query) {
2917
2919
  const reason = signal.reason;
2918
2920
  throw new OrbitOperationError(
2919
2921
  reason === void 0 ? { code: "aborted" } : { code: "aborted", cause: reason },
2920
- `local search('${query}') aborted mid-scan (\xA716.5)`
2922
+ `local search('${query}') aborted mid-scan`
2921
2923
  );
2922
2924
  }
2923
2925
  function createLocalSearchService(getBase) {
@@ -2972,6 +2974,10 @@ function isColumnarSnapshot(input) {
2972
2974
  }
2973
2975
  var isTypedLength = (arr, n) => arr !== void 0 && arr.length === n;
2974
2976
  function checkStringColumn(col, rows, where, isIds, out) {
2977
+ if (col === null || typeof col !== "object") {
2978
+ out.push({ where, problem: "not-a-string-column", detail: "column missing or not an object" });
2979
+ return;
2980
+ }
2975
2981
  if (col.kind !== "string" || !Array.isArray(col.dictionary) || !(col.codes instanceof Uint32Array)) {
2976
2982
  out.push({ where, problem: "not-a-string-column", detail: 'expected {kind:"string", dictionary, codes}' });
2977
2983
  return;
@@ -3014,6 +3020,10 @@ function checkStringColumn(col, rows, where, isIds, out) {
3014
3020
  }
3015
3021
  }
3016
3022
  function checkColumn(col, rows, where, out) {
3023
+ if (col === null || typeof col !== "object") {
3024
+ out.push({ where, problem: "bad-column-kind", detail: "column missing or not an object" });
3025
+ return;
3026
+ }
3017
3027
  switch (col.kind) {
3018
3028
  case "string":
3019
3029
  checkStringColumn(col, rows, where, false, out);
@@ -3058,6 +3068,14 @@ function validateColumnarStructure(snapshot) {
3058
3068
  issues.push({ where: "edges.length", problem: "bad-length", detail: String(edgeRows) });
3059
3069
  return issues;
3060
3070
  }
3071
+ if (snapshot.nodes === null || typeof snapshot.nodes !== "object") {
3072
+ issues.push({ where: "nodes", problem: "bad-length", detail: "nodes lane missing" });
3073
+ return issues;
3074
+ }
3075
+ if (snapshot.edges === null || typeof snapshot.edges !== "object") {
3076
+ issues.push({ where: "edges", problem: "bad-length", detail: "edges lane missing" });
3077
+ return issues;
3078
+ }
3061
3079
  checkStringColumn(snapshot.nodes.ids, nodeRows, "nodes.ids", true, issues);
3062
3080
  for (const [name, col] of Object.entries(snapshot.nodes.columns ?? {})) {
3063
3081
  checkColumn(col, nodeRows, `nodes.${name}`, issues);
@@ -3273,8 +3291,8 @@ var WorkerLane = class {
3273
3291
  }
3274
3292
  return this.availableState;
3275
3293
  }
3276
- /** Async worker death (P1: a constructed-but-dead worker must strand
3277
- * NOTHING): every pending request rejects as 'worker-failed' so callers
3294
+ /** A constructed-but-dead worker must strand NOTHING: every pending
3295
+ * request rejects as 'worker-failed' so callers
3278
3296
  * run their main-lane fallback, the lane goes permanently unavailable,
3279
3297
  * and the unavailability callback fires (the instance one-shots it). */
3280
3298
  fail(reason) {
@@ -3330,7 +3348,7 @@ var WorkerLane = class {
3330
3348
  }
3331
3349
  /** Abort everything in flight (epoch advance / detach / dataset swap).
3332
3350
  * The ledger's controllers fire each pending promise's abort listener;
3333
- * the sweep below catches anything tracked before a listener attached
3351
+ * the sweep below catches anything tracked before a listener attached
3334
3352
  * rejects stay idempotent through the delete guard. */
3335
3353
  abortAll() {
3336
3354
  this.ledger.abortAll();
@@ -3799,7 +3817,7 @@ var MetricStore = class {
3799
3817
  /** Admitted async columns by metric name; NaN encodes null. */
3800
3818
  columns = /* @__PURE__ */ new Map();
3801
3819
  degreePasses = 0;
3802
- /** §17 telemetry: estimated bytes of metric storage held (S13-T07). */
3820
+ /** telemetry: estimated bytes of metric storage held. */
3803
3821
  estimatedBytes() {
3804
3822
  let bytes = 0;
3805
3823
  for (const col of this.columns.values()) bytes += col.byteLength;
@@ -3830,10 +3848,10 @@ var MetricStore = class {
3830
3848
  }
3831
3849
  }
3832
3850
  /**
3833
- * Joins async metric columns against the accepted model (§12).
3851
+ * Joins async metric columns against the accepted model.
3834
3852
  * Revision-gated PER COLUMN (I1): a column whose issue-time
3835
3853
  * `forModelRevision` stamp differs from `opts.modelRevision` is discarded
3836
- * (info diagnostic — a normal async race outcome, §9.2). A missing or
3854
+ * (info diagnostic — a normal async race outcome). A missing or
3837
3855
  * mismatched stamp is never defaulted to the current revision — that
3838
3856
  * would make the gate self-satisfying.
3839
3857
  * Structural rejections ('index' length mismatch, missing/mismatched ids)
@@ -3851,7 +3869,7 @@ var MetricStore = class {
3851
3869
  "info",
3852
3870
  1,
3853
3871
  [column.metric],
3854
- `metric column '${column.metric}' discarded: computed for model revision ${String(column.forModelRevision)} but the update was issued at revision ${String(opts.modelRevision)} (\xA712/I1 revision-gated admission)`
3872
+ `metric column '${column.metric}' discarded: computed for model revision ${String(column.forModelRevision)} but the update was issued at revision ${String(opts.modelRevision)}`
3855
3873
  )
3856
3874
  );
3857
3875
  continue;
@@ -3961,7 +3979,7 @@ var MetricStore = class {
3961
3979
  }
3962
3980
  /**
3963
3981
  * Raw column in accepted-base order, or null when unavailable. NaN encodes
3964
- * null (§12) — consumers exclude NaN slots from domains. Do NOT mutate:
3982
+ * null — consumers exclude NaN slots from domains. Do NOT mutate:
3965
3983
  * this is the live cache, not a copy.
3966
3984
  */
3967
3985
  metricValues(metric) {
@@ -4007,7 +4025,7 @@ var MetricStore = class {
4007
4025
  };
4008
4026
 
4009
4027
  // src/capabilityPolicy.ts
4010
- var CLUSTER_FORCE_DEGRADATION_REASON = "clusters requested but the engine capability record does not declare clusterForce; the cluster force is inert while membership, cluster labels, and centroids still work (\xA716.3/R-13-39)";
4028
+ var CLUSTER_FORCE_DEGRADATION_REASON = "clusters requested but the engine capability record does not declare clusterForce; the cluster force is inert while membership, cluster labels, and centroids still work";
4011
4029
  function degradation(feature, reason) {
4012
4030
  return Object.freeze({ feature, reason });
4013
4031
  }
@@ -4020,7 +4038,7 @@ function resolveEnginePolicy(capabilities, requested) {
4020
4038
  degradations.push(
4021
4039
  degradation(
4022
4040
  "edgeArrows",
4023
- "edgeArrows requested but the engine capability record does not declare edgeArrows; the prop is inert (\xA716.12)"
4041
+ "edgeArrows requested but the engine capability record does not declare edgeArrows; the prop is inert"
4024
4042
  )
4025
4043
  );
4026
4044
  }
@@ -4028,7 +4046,7 @@ function resolveEnginePolicy(capabilities, requested) {
4028
4046
  degradations.push(
4029
4047
  degradation(
4030
4048
  "images",
4031
- "node images requested but the engine capability record does not declare pointImages; placeholder glyphs render and image refs are retained (\xA78/\xA713)"
4049
+ "node images requested but the engine capability record does not declare pointImages; placeholder glyphs render and image refs are retained"
4032
4050
  )
4033
4051
  );
4034
4052
  }
@@ -4051,14 +4069,14 @@ function assertCapabilityMethodParity(engine) {
4051
4069
  const mismatches = [];
4052
4070
  const capabilities = engine.capabilities;
4053
4071
  if (capabilities === null || typeof capabilities !== "object") {
4054
- mismatches.push("engine.capabilities is missing or not an object (\xA713 static declaration)");
4072
+ mismatches.push("engine.capabilities is missing or not an object");
4055
4073
  return mismatches;
4056
4074
  }
4057
4075
  const caps = capabilities;
4058
4076
  const getPositions = engine.getPositions;
4059
4077
  if (caps.trackedPositions === true && typeof getPositions !== "function") {
4060
4078
  mismatches.push(
4061
- "capabilities.trackedPositions is declared but engine.getPositions is absent (\xA713 tracked readback)"
4079
+ "capabilities.trackedPositions is declared but engine.getPositions is absent"
4062
4080
  );
4063
4081
  }
4064
4082
  return mismatches;
@@ -4145,7 +4163,7 @@ var ImageAtlasPipeline = class {
4145
4163
  generation = null;
4146
4164
  flushScheduled = false;
4147
4165
  disposed = false;
4148
- /** D5/F11-06: evicted-entry bitmaps awaiting close — closed AFTER the
4166
+ /** Evicted-entry bitmaps awaiting close — closed AFTER the
4149
4167
  * flush that carries their removeSlots, so the instance's recovery-replay
4150
4168
  * map (pruned synchronously in the batch callback) can never re-send a
4151
4169
  * closed bitmap. */
@@ -4379,7 +4397,7 @@ var ImageAtlasPipeline = class {
4379
4397
  return index;
4380
4398
  }
4381
4399
  /**
4382
- * I2 (roster-atomic resource mappings, F11-03): the SYNCHRONOUS point→slot
4400
+ * Roster-atomic resource mappings: the SYNCHRONOUS point→slot
4383
4401
  * mapping for the last requested roster — a slot appears only when its ref
4384
4402
  * is resolved AND the engine has already received the bitmap (delivered);
4385
4403
  * pending, failed, evicted, and reused-but-undelivered refs are the −1
@@ -4459,12 +4477,12 @@ var SoftMask = class {
4459
4477
  edgeHideLane;
4460
4478
  edgeDimLane;
4461
4479
  sources = /* @__PURE__ */ new Set();
4462
- /** Dedicated internal source implementing the §9 node→edge cascade. */
4480
+ /** Dedicated internal source implementing the node→edge cascade. */
4463
4481
  cascadeSource = null;
4464
4482
  overflowedFlag = false;
4465
4483
  /** Total memberships currently held across all sources and lanes. */
4466
4484
  totalHeld = 0;
4467
- /** §17 O(Δ) op counters (F10-02 gate instrumentation). */
4485
+ /** O(Δ) op counters. */
4468
4486
  statsBox = {
4469
4487
  slotsVisited: 0,
4470
4488
  zeroCrossings: 0,
@@ -4487,12 +4505,12 @@ var SoftMask = class {
4487
4505
  return this.edgeCap;
4488
4506
  }
4489
4507
  /** One-time latch: some counter hit 0xFFFF and an increment was dropped.
4490
- * Counts may drift afterwards; the caller reports it (§9.1 overflow guard). */
4508
+ * Counts may drift afterwards; the caller reports it. */
4491
4509
  get overflowed() {
4492
4510
  return this.overflowedFlag;
4493
4511
  }
4494
4512
  // Live counter columns (read-only views by convention — do not mutate;
4495
- // references are replaced on grow()).
4513
+ // references are replaced on grow).
4496
4514
  get nodeHideFailures() {
4497
4515
  return this.nodeHideLane.counters;
4498
4516
  }
@@ -4507,7 +4525,7 @@ var SoftMask = class {
4507
4525
  }
4508
4526
  /**
4509
4527
  * Grows capacities for structure changes (existing slot state is
4510
- * preserved; new slots start fully visible). Capacities never shrink
4528
+ * preserved; new slots start fully visible). Capacities never shrink
4511
4529
  * a smaller value is a no-op for that dimension.
4512
4530
  */
4513
4531
  grow(nodeCapacity, edgeCapacity) {
@@ -4532,7 +4550,7 @@ var SoftMask = class {
4532
4550
  this.edgeCap = edgeCapacity;
4533
4551
  }
4534
4552
  }
4535
- /** Registers a new failure source. No cap on source count (§9.1). */
4553
+ /** Registers a new failure source. No cap on source count. */
4536
4554
  acquire(name) {
4537
4555
  const state = {
4538
4556
  name,
@@ -4587,11 +4605,11 @@ var SoftMask = class {
4587
4605
  };
4588
4606
  }
4589
4607
  /**
4590
- * §9 edge cascade over the mask lane: recomputes, from the CURRENT node
4608
+ * edge cascade over the mask lane: recomputes, from the CURRENT node
4591
4609
  * hide lane, the set of edges with at least one hidden endpoint, and feeds
4592
4610
  * it to the dedicated internal cascade source (edge hide lane only).
4593
- * `links` is the flat `[src0, tgt0, src1, tgt1, …]` node-slot pair buffer
4594
- * (§7.1 CSR input shape); edge slot i has endpoints at links[2i]/[2i+1].
4611
+ * `links` is the flat `[src0, tgt0, src1, tgt1, …]` node-slot pair buffer;
4612
+ * edge slot i has endpoints at links[2i]/[2i+1].
4595
4613
  * O(E) scan per call — typically once per drain — but only edges whose
4596
4614
  * cascade state changed produce counter deltas (and thus dirty entries).
4597
4615
  * Edges beyond `links.length / 2` are treated as having no hidden
@@ -4622,11 +4640,11 @@ var SoftMask = class {
4622
4640
  }
4623
4641
  if (hide[source] !== 0 || hide[target] !== 0) failing.push(i);
4624
4642
  }
4625
- this.cascadeSource ??= this.acquire("\xA79.1 node\u2192edge cascade");
4643
+ this.cascadeSource ??= this.acquire("node\u2192edge cascade");
4626
4644
  this.cascadeSource.setEdgeFailures(failing);
4627
4645
  }
4628
4646
  /**
4629
- * O(incident-edges) delta form of the §9.1 cascade (F10-02): for each node
4647
+ * O(incident-edges) delta form of the cascade: for each node
4630
4648
  * whose HIDE visibility crossed zero, recompute only its incident edges'
4631
4649
  * cascade state from the CURRENT node counters and apply the delta through
4632
4650
  * the same internal cascade source the full form uses — the two compose
@@ -4638,7 +4656,7 @@ var SoftMask = class {
4638
4656
  applyNodeCascadeToEdgesDelta(links, incidence, crossedNodes) {
4639
4657
  if (crossedNodes.length === 0) return;
4640
4658
  const hide = this.nodeHideLane.counters;
4641
- this.cascadeSource ??= this.acquire("\xA79.1 node\u2192edge cascade");
4659
+ this.cascadeSource ??= this.acquire("node\u2192edge cascade");
4642
4660
  const nowFailing = [];
4643
4661
  const nowClear = [];
4644
4662
  for (let k = 0; k < crossedNodes.length; k++) {
@@ -4668,7 +4686,7 @@ var SoftMask = class {
4668
4686
  edgeVisibleCount: this.edgeHideLane.zeroCount
4669
4687
  };
4670
4688
  }
4671
- /** §17 telemetry: estimated bytes of mask storage held (S13-T07):
4689
+ /** telemetry: estimated bytes of mask storage held:
4672
4690
  * four counter lanes (+pending trackers) and per-source flag columns. */
4673
4691
  estimatedBytes() {
4674
4692
  let bytes = 0;
@@ -4680,7 +4698,7 @@ var SoftMask = class {
4680
4698
  }
4681
4699
  return bytes;
4682
4700
  }
4683
- /** §17 O(Δ) op counters (live object — snapshot before comparing). */
4701
+ /** O(Δ) op counters (live object — snapshot before comparing). */
4684
4702
  get stats() {
4685
4703
  return this.statsBox;
4686
4704
  }
@@ -4702,7 +4720,7 @@ var SoftMask = class {
4702
4720
  isEdgeVisible(index) {
4703
4721
  return this.edgeHideLane.counters[index] === 0;
4704
4722
  }
4705
- /** Dimmed iff visible AND dimFailures > 0 (§9.1). */
4723
+ /** Dimmed iff visible AND dimFailures > 0. */
4706
4724
  isNodeDimmed(index) {
4707
4725
  return this.isNodeVisible(index) && (this.nodeDimLane.counters[index] ?? 0) > 0;
4708
4726
  }
@@ -4763,7 +4781,7 @@ var SoftMask = class {
4763
4781
  mem.holes = 0;
4764
4782
  }
4765
4783
  /**
4766
- * O(Δ) delta ops on one lane membership (F10-02). Adds and removes are
4784
+ * O(Δ) delta ops on one lane membership. Adds and removes are
4767
4785
  * idempotent per slot (adding a member / removing a non-member is a
4768
4786
  * no-op); removed slots leave HOLES in `list` (compacted past 50%), so
4769
4787
  * replace/clear passes must honor the bit0 guard above. `crossings`, when
@@ -4864,7 +4882,7 @@ var SoftMask = class {
4864
4882
  this.applyMembership(this.edgeDimLane, state.edgeDim, null);
4865
4883
  }
4866
4884
  /** Debug balanced-increment assert: whenever no source holds any
4867
- * membership, every counter must read zero (skipped once overflowed
4885
+ * membership, every counter must read zero (skipped once overflowed
4868
4886
  * clamped increments legitimately drift the books). */
4869
4887
  assertBalancedIfIdle() {
4870
4888
  if (!DEBUG || this.overflowedFlag || this.totalHeld !== 0) return;
@@ -4886,7 +4904,7 @@ var SVG_MAX_ELEMENTS_DEFAULT = 5e4;
4886
4904
  var SvgBudgetError = class extends Error {
4887
4905
  constructor(elementCount, limit) {
4888
4906
  super(
4889
- `SVG export of ${elementCount} elements exceeds the ${limit}-element budget \u2014 filter/isolate first, or use the raster-hybrid fallback (\xA716.14)`
4907
+ `SVG export of ${elementCount} elements exceeds the ${limit}-element budget \u2014 filter/isolate first, or use the raster-hybrid fallback`
4890
4908
  );
4891
4909
  this.elementCount = elementCount;
4892
4910
  this.limit = limit;
@@ -5246,7 +5264,7 @@ function upperBound(values, sorted, target) {
5246
5264
  return lo;
5247
5265
  }
5248
5266
  var TypedColumnCrossfilter = class {
5249
- /** Test instrumentation; see CrossfilterStats. Reset with resetStats(). */
5267
+ /** Test instrumentation; see CrossfilterStats. Reset with resetStats. */
5250
5268
  stats = {
5251
5269
  slotsWalked: 0,
5252
5270
  fullSorts: 0,
@@ -5254,7 +5272,7 @@ var TypedColumnCrossfilter = class {
5254
5272
  binUpdates: 0,
5255
5273
  filteredRecomputes: 0
5256
5274
  };
5257
- /** Count of dims whose filtered layer is live-maintained (F10-02). */
5275
+ /** Count of dims whose filtered layer is live-maintained. */
5258
5276
  liveDims = 0;
5259
5277
  dims = [];
5260
5278
  byKey = /* @__PURE__ */ new Map();
@@ -5280,7 +5298,7 @@ var TypedColumnCrossfilter = class {
5280
5298
  this.stats.binUpdates = 0;
5281
5299
  this.stats.filteredRecomputes = 0;
5282
5300
  }
5283
- /** §17 telemetry: estimated bytes of typed-column storage held (S13-T07).
5301
+ /** telemetry: estimated bytes of typed-column storage held.
5284
5302
  * Documented components: per-dim value/permutation/bin/code/pass arrays,
5285
5303
  * the global failure counter, and the external mask. */
5286
5304
  estimatedBytes() {
@@ -5295,7 +5313,7 @@ var TypedColumnCrossfilter = class {
5295
5313
  }
5296
5314
  return bytes;
5297
5315
  }
5298
- /** F10-02 live-layer bookkeeping — the ONLY writer of `filteredLive`. */
5316
+ /** live-layer bookkeeping — the ONLY writer of `filteredLive`. */
5299
5317
  setFilteredLive(dim, live) {
5300
5318
  if (dim.filteredLive === live) return;
5301
5319
  dim.filteredLive = live;
@@ -5358,8 +5376,8 @@ var TypedColumnCrossfilter = class {
5358
5376
  }
5359
5377
  /**
5360
5378
  * External node-mask predicate for the joint "filtered" second layer (the
5361
- * instance wires the §9.1 filter-prop node mask in). Affects summaries only,
5362
- * never selection visibility. Length must equal rowCount(). Notifies on
5379
+ * instance wires the filter-prop node mask in). Affects summaries only,
5380
+ * never selection visibility. Length must equal rowCount. Notifies on
5363
5381
  * observable change; does NOT advance selectionRevision.
5364
5382
  */
5365
5383
  setExternalMask(passSlots) {
@@ -5384,7 +5402,7 @@ var TypedColumnCrossfilter = class {
5384
5402
  this.notify();
5385
5403
  }
5386
5404
  /**
5387
- * Immutable summary. The filtered layer is recomputed lazily when dirty
5405
+ * Immutable summary. The filtered layer is recomputed lazily when dirty
5388
5406
  * O(rows) per dirty summarize (v0.7 tier; see module doc). Returned objects
5389
5407
  * are frozen and never mutated by later operations.
5390
5408
  */
@@ -5436,7 +5454,7 @@ var TypedColumnCrossfilter = class {
5436
5454
  return Object.freeze(domain !== void 0 ? { ...base, domain } : base);
5437
5455
  }
5438
5456
  /**
5439
- * Incrementally extend columns with new rows (S9-T09 subset): no full
5457
+ * Incrementally extend columns with new rows: no full
5440
5458
  * rebuild, no full re-argsort — the pre-sorted old permutation merges with
5441
5459
  * the sorted new block. Brushes stay by key and are applied to the NEW slots
5442
5460
  * only; the returned delta covers only new slots. Keeps selectionRevision;
@@ -5690,16 +5708,16 @@ var TypedColumnCrossfilter = class {
5690
5708
  }
5691
5709
  }
5692
5710
  /**
5693
- * F10-02 inline maintenance of LIVE filtered layers, dispatched from the
5711
+ * inline maintenance of LIVE filtered layers, dispatched from the
5694
5712
  * one place that knows the failCount transition. `boundary` is the
5695
5713
  * other-failures picture at the interesting side of the flip (after for
5696
5714
  * shown, before for hidden):
5697
- * - 0 → the slot crossed the FULLY-VISIBLE boundary: every other live
5698
- * layer counts it (own layers ignore the own-dim brush, so the brushed
5699
- * dim's layer is provably unchanged by its own flip);
5700
- * - 1 → exactly one OTHER dim still fails the slot: only that dim's
5701
- * what-if-I-cleared-mine layer flips;
5702
- * - ≥2 → no layer can change.
5715
+ * - 0 → the slot crossed the FULLY-VISIBLE boundary: every other live
5716
+ * layer counts it (own layers ignore the own-dim brush, so the brushed
5717
+ * dim's layer is provably unchanged by its own flip);
5718
+ * - 1 → exactly one OTHER dim still fails the slot: only that dim's
5719
+ * what-if-I-cleared-mine layer flips;
5720
+ * - ≥2 → no layer can change.
5703
5721
  * External-mask-excluded and hygiene-invalid slots contribute nothing
5704
5722
  * either way and are skipped.
5705
5723
  */
@@ -6004,7 +6022,7 @@ function assertSerializable(value, slice) {
6004
6022
  switch (typeof v) {
6005
6023
  case "function":
6006
6024
  throw new TypeError(
6007
- `history command for slice "${slice}" carries a function at ${path} \u2014 commands are value diffs, not closures (\xA716.14)`
6025
+ `history command for slice "${slice}" carries a function at ${path} \u2014 commands are value diffs, not closures`
6008
6026
  );
6009
6027
  case "symbol":
6010
6028
  case "bigint":
@@ -6019,7 +6037,7 @@ function assertSerializable(value, slice) {
6019
6037
  if (v === null) return;
6020
6038
  if (v instanceof Map || v instanceof Set) {
6021
6039
  throw new TypeError(
6022
- `history command for slice "${slice}" carries a ${v instanceof Map ? "Map" : "Set"} at ${path} \u2014 convert to arrays/objects before recording (\xA716.14)`
6040
+ `history command for slice "${slice}" carries a ${v instanceof Map ? "Map" : "Set"} at ${path} \u2014 convert to arrays/objects before recording`
6023
6041
  );
6024
6042
  }
6025
6043
  if (seen.has(v)) {
@@ -6041,7 +6059,7 @@ var HistoryKernel = class {
6041
6059
  debug;
6042
6060
  undoStack = [];
6043
6061
  redoStack = [];
6044
- /** Nested begin() joins the outer transaction (depth-counted). */
6062
+ /** Nested begin joins the outer transaction (depth-counted). */
6045
6063
  txDepth = 0;
6046
6064
  txCommands = [];
6047
6065
  txLabel;
@@ -6107,7 +6125,7 @@ var HistoryKernel = class {
6107
6125
  }
6108
6126
  this.pushEntry({ label: void 0, commands: [command] }, null);
6109
6127
  }
6110
- /** Close a transaction; the outermost end() pushes one stack entry. */
6128
+ /** Close a transaction; the outermost end pushes one stack entry. */
6111
6129
  end() {
6112
6130
  if (!this.enabled) return;
6113
6131
  if (this.txDepth === 0) throw new Error("HistoryKernel.end() without a matching begin()");
@@ -6377,7 +6395,7 @@ function createGraphInstance(opts) {
6377
6395
  if (accepted === null) {
6378
6396
  throw new OrbitOperationError(
6379
6397
  { code: "aborted", cause: "no accepted base" },
6380
- "expansion requires an accepted base dataset (\xA79.2)"
6398
+ "expansion requires an accepted base dataset"
6381
6399
  );
6382
6400
  }
6383
6401
  return { accepted, adjacency: acceptedAdjacencyOf() };
@@ -6610,7 +6628,7 @@ function createGraphInstance(opts) {
6610
6628
  severity: "error",
6611
6629
  count: 1,
6612
6630
  sampleIds: [],
6613
- message: "columnar snapshot mutated while worker acceptance was pending \u2014 rejected whole (\xA75: source coordinates are immutable; publish a new sourceRevision)"
6631
+ message: "columnar snapshot mutated while worker acceptance was pending \u2014 rejected whole (source coordinates are immutable; publish a new sourceRevision)"
6614
6632
  }
6615
6633
  ];
6616
6634
  publish({ diagnostics: composeDiagnostics() });
@@ -6637,6 +6655,19 @@ function createGraphInstance(opts) {
6637
6655
  if (message !== "worker-unavailable" && message !== "worker-failed") return;
6638
6656
  acceptanceQueue.admit(() => {
6639
6657
  if (destroyed || token !== pendingDeriveToken) return;
6658
+ if (validateColumnarStructure(columnar).length > 0) {
6659
+ columnarDiags = [
6660
+ {
6661
+ code: "invalid-columnar-snapshot",
6662
+ severity: "error",
6663
+ count: 1,
6664
+ sampleIds: [],
6665
+ message: "columnar snapshot mutated while worker acceptance was pending \u2014 rejected whole (source coordinates are immutable; publish a new sourceRevision)"
6666
+ }
6667
+ ];
6668
+ publish({ diagnostics: composeDiagnostics() });
6669
+ return;
6670
+ }
6640
6671
  applyHostUpdateInner({
6641
6672
  data: materializeColumnarSnapshot(columnar),
6642
6673
  ...deferredMetrics !== void 0 ? { metrics: deferredMetrics } : {}
@@ -6723,7 +6754,7 @@ function createGraphInstance(opts) {
6723
6754
  if (event.engaged && !capLabelsNudged) {
6724
6755
  capLabelsNudged = true;
6725
6756
  console.warn(
6726
- "orbit: cap-dom-labels engaged \u2014 DOM labels are hard-capped at the label budget above limits.domLabelNodes visible nodes (\xA717). A GPU label lane (labelStrategy 'sdf') is the planned scale path (S13-T05, deferred)."
6757
+ "orbit: cap-dom-labels engaged \u2014 DOM labels are hard-capped at the label budget above limits.domLabelNodes visible nodes. A GPU label lane (labelStrategy 'sdf') is the planned scale path."
6727
6758
  );
6728
6759
  }
6729
6760
  scheduleViewportRerank();
@@ -7376,7 +7407,7 @@ function createGraphInstance(opts) {
7376
7407
  severity: "warning",
7377
7408
  count: errorCount,
7378
7409
  sampleIds: samples,
7379
- message: `filter predicate threw for ${errorCount} item(s); failing open \u2014 throwing predicates never hide data (\xA79.1)`
7410
+ message: `filter predicate threw for ${errorCount} item(s); failing open \u2014 throwing predicates never hide data`
7380
7411
  }
7381
7412
  ];
7382
7413
  } else {
@@ -7887,7 +7918,7 @@ function createGraphInstance(opts) {
7887
7918
  }
7888
7919
  function requireCrossfilterEngine() {
7889
7920
  if (crossfilterEngine === null) {
7890
- throw new Error("crossfilter session is not available (set the crossfilter prop first, \xA716.6)");
7921
+ throw new Error("crossfilter session is not available; set the crossfilter prop first");
7891
7922
  }
7892
7923
  return crossfilterEngine;
7893
7924
  }
@@ -7938,13 +7969,13 @@ function createGraphInstance(opts) {
7938
7969
  const eng = crossfilterEngine;
7939
7970
  if (eng === null) {
7940
7971
  throw new TypeError(
7941
- "playTimeline: the crossfilter prop must configure dimensions first (\xA716.6)"
7972
+ "playTimeline: the crossfilter prop must configure dimensions first"
7942
7973
  );
7943
7974
  }
7944
7975
  const summary = eng.summarize(key);
7945
7976
  if (summary.kind === "categorical" || summary.domain === void 0) {
7946
7977
  throw new TypeError(
7947
- `playTimeline: dimension "${key}" must be numeric/temporal with a non-empty domain (\xA716.6)`
7978
+ `playTimeline: dimension "${key}" must be numeric/temporal with a non-empty domain`
7948
7979
  );
7949
7980
  }
7950
7981
  const { min, max } = summary.domain;
@@ -7966,7 +7997,7 @@ function createGraphInstance(opts) {
7966
7997
  );
7967
7998
  }
7968
7999
  if (mode !== "sliding" && mode !== "cumulative") {
7969
- throw new TypeError(`playTimeline: unsupported mode "${String(mode)}" (\xA716.6)`);
8000
+ throw new TypeError(`playTimeline: unsupported mode "${String(mode)}"`);
7970
8001
  }
7971
8002
  stopTimelineTimer();
7972
8003
  timelineSessionSeq += 1;
@@ -8439,7 +8470,7 @@ function createGraphInstance(opts) {
8439
8470
  severity: "warning",
8440
8471
  count: overload,
8441
8472
  sampleIds: [],
8442
- message: `showLabelsFor exceeds tracked-label capacity; ${overload} forced label(s) omitted (\xA714)`
8473
+ message: `showLabelsFor exceeds tracked-label capacity; ${overload} forced label(s) omitted`
8443
8474
  }
8444
8475
  ];
8445
8476
  diagsChanged = true;
@@ -8715,7 +8746,7 @@ function createGraphInstance(opts) {
8715
8746
  severity: "warning",
8716
8747
  count: state.streak,
8717
8748
  sampleIds: [],
8718
- message: `${channel} reprojected on ${state.streak} consecutive commits with identical sampled outputs \u2014 likely an inline lambda prop; hoist or memoize it (\xA78)`
8749
+ message: `${channel} reprojected on ${state.streak} consecutive commits with identical sampled outputs \u2014 likely an inline lambda prop; hoist or memoize it`
8719
8750
  }
8720
8751
  ];
8721
8752
  }
@@ -9117,9 +9148,9 @@ function createGraphInstance(opts) {
9117
9148
  nodeIds: orderByAcceptedBase(full.nodeIds, nodeIndexBase()),
9118
9149
  edgeIds: orderByAcceptedBase(full.edgeIds, edgeIndexById),
9119
9150
  // Group namespace: the raw full-state form stays TOLERANT (deduped,
9120
- // not validated — pinned pre-S12 behavior); ids that stop naming a
9151
+ // not validated — pinned legacy behavior); ids that stop naming a
9121
9152
  // resolved group prune through the ownership path whenever the groups
9122
- // RESOLUTION changes (§16.2/§16.3). selectGroups() is the validating
9153
+ // RESOLUTION changes. selectGroups is the validating
9123
9154
  // mutator.
9124
9155
  groupIds: dedupeFirstOccurrence(full.groupIds)
9125
9156
  });
@@ -9398,7 +9429,7 @@ function createGraphInstance(opts) {
9398
9429
  if (DEV) {
9399
9430
  rejectGroupOp(
9400
9431
  "warning",
9401
- "groupNodes ignored: membership is derived and read-only under groupBy (\xA716.3) \u2014 change the groupBy accessor or remove it",
9432
+ "groupNodes ignored: membership is derived and read-only under groupBy \u2014 change the groupBy accessor or remove it",
9402
9433
  spec.id
9403
9434
  );
9404
9435
  }
@@ -9421,7 +9452,7 @@ function createGraphInstance(opts) {
9421
9452
  if (DEV) {
9422
9453
  rejectGroupOp(
9423
9454
  "warning",
9424
- "ungroup ignored: membership is derived and read-only under groupBy (\xA716.3) \u2014 change the groupBy accessor or remove it",
9455
+ "ungroup ignored: membership is derived and read-only under groupBy \u2014 change the groupBy accessor or remove it",
9425
9456
  groupId
9426
9457
  );
9427
9458
  }
@@ -9446,7 +9477,7 @@ function createGraphInstance(opts) {
9446
9477
  if (DEV) {
9447
9478
  rejectGroupOp(
9448
9479
  "warning",
9449
- "setGroupCollapsed ignored: groups and groupBy are both configured (\xA716.3 config error) \u2014 remove one",
9480
+ "setGroupCollapsed ignored: groups and groupBy are both configured \u2014 remove one",
9450
9481
  groupId
9451
9482
  );
9452
9483
  }
@@ -9457,7 +9488,7 @@ function createGraphInstance(opts) {
9457
9488
  if (DEV) {
9458
9489
  rejectGroupOp(
9459
9490
  "warning",
9460
- `setGroupCollapsed ignored: no derived group '${groupId}' in the current derivation (\xA716.3)`,
9491
+ `setGroupCollapsed ignored: no derived group '${groupId}' in the current derivation`,
9461
9492
  groupId
9462
9493
  );
9463
9494
  }
@@ -9671,7 +9702,7 @@ function createGraphInstance(opts) {
9671
9702
  function invalidateReplaceSessions(owner) {
9672
9703
  for (const s of [...openSessions]) {
9673
9704
  if (s === owner || s.purpose !== "replace") continue;
9674
- abortSessionInternal(s, "stale-base: the model changed outside the session (\xA77.5)", false);
9705
+ abortSessionInternal(s, "stale-base: the model changed outside the session", false);
9675
9706
  }
9676
9707
  }
9677
9708
  function abortAllSessions(except, cause) {
@@ -9740,7 +9771,7 @@ function createGraphInstance(opts) {
9740
9771
  if (expansionHandles.size === 0 && expansionLedger.size === 0) return;
9741
9772
  const err = new OrbitOperationError(
9742
9773
  { code: "aborted", cause: "dataset-changed" },
9743
- "expansion aborted: the datasetKey changed (\xA75/\xA79.2)"
9774
+ "expansion aborted: the datasetKey changed"
9744
9775
  );
9745
9776
  for (const [requestId, handle] of expansionHandles) {
9746
9777
  handle.abort(err);
@@ -9761,7 +9792,7 @@ function createGraphInstance(opts) {
9761
9792
  scopeExtraIds.clear();
9762
9793
  expansionOverlays.clear();
9763
9794
  abortExpansionsForDatasetSwap();
9764
- abortSearchFlight("dataset-changed", "search aborted: the datasetKey changed (\xA75/\xA716.5)");
9795
+ abortSearchFlight("dataset-changed", "search aborted: the datasetKey changed");
9765
9796
  resetMaskState();
9766
9797
  historyKernel.clear();
9767
9798
  stopTimelineTimer();
@@ -9923,7 +9954,7 @@ function createGraphInstance(opts) {
9923
9954
  const labelRerank = recomputeCandidates();
9924
9955
  const patch = {
9925
9956
  revisions,
9926
- // Counts are ACCEPTED-MODEL counts; the scene may be scoped (§9.2).
9957
+ // Counts are ACCEPTED-MODEL counts; the scene may be scoped.
9927
9958
  nodeCount: p.merged.nodes.length,
9928
9959
  edgeCount: p.merged.edges.length,
9929
9960
  diagnostics: composeDiagnostics()
@@ -9983,7 +10014,7 @@ function createGraphInstance(opts) {
9983
10014
  cancelFlushTimer(rec);
9984
10015
  return rejectOperation(
9985
10016
  { code: "overlay-id-conflict", overlayId: id },
9986
- `overlayId '${id}' is already reserved by an open or committed overlay for this dataset (\xA77.5)`
10017
+ `overlayId '${id}' is already reserved by an open or committed overlay for this dataset`
9987
10018
  );
9988
10019
  }
9989
10020
  reservedOverlayIds.set(id, rec);
@@ -10055,14 +10086,14 @@ function createGraphInstance(opts) {
10055
10086
  if (rec.atomic && queuedBytes > rec.maxPendingBytes) {
10056
10087
  return rejectOperation(
10057
10088
  { code: "queue-overflow", queuedBytes, limit: rec.maxPendingBytes },
10058
- `append(): atomic session would queue ${queuedBytes} bytes, exceeding its non-drainable budget of ${rec.maxPendingBytes}; the append was rejected and the session remains open (\xA77.5)`
10089
+ `append(): atomic session would queue ${queuedBytes} bytes, exceeding its non-drainable budget of ${rec.maxPendingBytes}; the append was rejected and the session remains open`
10059
10090
  );
10060
10091
  }
10061
10092
  const overflowLimit = rec.maxPendingBytes * INGEST_OVERFLOW_FACTOR;
10062
10093
  if (bytes > overflowLimit) {
10063
10094
  return rejectOperation(
10064
10095
  { code: "queue-overflow", queuedBytes: bytes, limit: overflowLimit },
10065
- `append(): batch of ${bytes} bytes exceeds the absolute cap of ${overflowLimit} (\xA77.5)`
10096
+ `append(): batch of ${bytes} bytes exceeds the absolute cap of ${overflowLimit}`
10066
10097
  );
10067
10098
  }
10068
10099
  const counts = stageBatch(
@@ -10120,7 +10151,7 @@ function createGraphInstance(opts) {
10120
10151
  };
10121
10152
  }
10122
10153
  const datasetChanged = baseAccepted !== null && baseAccepted.datasetKey !== rec.datasetKey;
10123
- abortAllSessions(rec, "replaced: a replace session committed (\xA77.5)");
10154
+ abortAllSessions(rec, "replaced: a replace session committed");
10124
10155
  const overlaysCleared = clearOverlayState();
10125
10156
  const newBase = baseFromContribution(rec.datasetKey, sourceRevision, c, []);
10126
10157
  const commitDiags = sessionCommitDiagnostics(rec.tallies, newBase.pendingEdges.length);
@@ -10218,7 +10249,7 @@ function createGraphInstance(opts) {
10218
10249
  code: "resource-limit",
10219
10250
  detail: { reason: err instanceof Error ? err.message : String(err) }
10220
10251
  },
10221
- `commit() failed; session rolled back (\xA77.5)`
10252
+ `commit() failed; session rolled back`
10222
10253
  );
10223
10254
  }
10224
10255
  rec.state = "committed";
@@ -10242,16 +10273,16 @@ function createGraphInstance(opts) {
10242
10273
  }
10243
10274
  if (purpose === "replace") {
10244
10275
  if (opts2.sourceRevision === void 0) {
10245
- throw new TypeError("beginIngest: purpose:'replace' requires sourceRevision (\xA77.5)");
10276
+ throw new TypeError("beginIngest: purpose:'replace' requires sourceRevision");
10246
10277
  }
10247
10278
  if (opts2.atomic === false) {
10248
10279
  throw new TypeError(
10249
- "beginIngest: replace sessions are always atomic \u2014 progressive replace frames would expose rows before their sourceRevision existed (\xA77.5)"
10280
+ "beginIngest: replace sessions are always atomic \u2014 progressive replace frames would expose rows before their sourceRevision existed"
10250
10281
  );
10251
10282
  }
10252
10283
  if (baseSource === "declarative") {
10253
10284
  throw new TypeError(
10254
- "beginIngest: purpose:'replace' is unavailable while a declarative data source is active; keep applying snapshots via applyHostUpdate, or use an overlay session (\xA77.5/T16)"
10285
+ "beginIngest: purpose:'replace' is unavailable while a declarative data source is active; keep applying snapshots via applyHostUpdate, or use an overlay session"
10255
10286
  );
10256
10287
  }
10257
10288
  }
@@ -10266,7 +10297,7 @@ function createGraphInstance(opts) {
10266
10297
  if (baseAccepted === null || baseAccepted.datasetKey !== opts2.datasetKey) {
10267
10298
  throw new OrbitOperationError(
10268
10299
  { code: "stale-revision", expected: currentModel, actual: opts2.baseModelRevision },
10269
- baseAccepted === null ? "beginIngest: overlay sessions require an accepted base dataset (\xA77.5 lineage)" : `beginIngest: overlay sessions must name the current datasetKey '${baseAccepted.datasetKey}', got '${opts2.datasetKey}' (\xA77.5 lineage)`
10300
+ baseAccepted === null ? "beginIngest: overlay sessions require an accepted base dataset" : `beginIngest: overlay sessions must name the current datasetKey '${baseAccepted.datasetKey}', got '${opts2.datasetKey}'`
10270
10301
  );
10271
10302
  }
10272
10303
  }
@@ -10275,7 +10306,7 @@ function createGraphInstance(opts) {
10275
10306
  purpose,
10276
10307
  datasetKey: opts2.datasetKey,
10277
10308
  sourceRevision: opts2.sourceRevision ?? null,
10278
- // replace is always atomic; overlays default atomic:true (§7.5).
10309
+ // replace is always atomic; overlays default atomic:true.
10279
10310
  atomic: purpose === "replace" ? true : opts2.atomic ?? true,
10280
10311
  overlayId,
10281
10312
  maxFlushLatencyMs: opts2.maxFlushLatencyMs ?? INGEST_MAX_FLUSH_LATENCY_MS_DEFAULT,
@@ -10388,11 +10419,11 @@ function createGraphInstance(opts) {
10388
10419
  pushServiceDiagnostic(
10389
10420
  "service-aborted",
10390
10421
  "info",
10391
- `expansion result for '${id}' discarded before admission: ${why} (\xA79.2)`
10422
+ `expansion result for '${id}' discarded before admission: ${why}`
10392
10423
  );
10393
10424
  throw new OrbitOperationError(
10394
10425
  { code: "aborted", cause: why },
10395
- `expandNode('${id}') result discarded: ${why} (\xA79.2)`
10426
+ `expandNode('${id}') result discarded: ${why}`
10396
10427
  );
10397
10428
  }
10398
10429
  async function mergeExpansionSession(id, ctx, at, batches, provenance) {
@@ -10613,14 +10644,14 @@ function createGraphInstance(opts) {
10613
10644
  expansionPromises.delete(id);
10614
10645
  const err = new OrbitOperationError(
10615
10646
  { code: "aborted", cause: "collapsed" },
10616
- `expandNode('${id}') aborted by retractExpansion() (\xA79.2/\xA716.3)`
10647
+ `expandNode('${id}') aborted by retractExpansion()`
10617
10648
  );
10618
10649
  expansionHandles.get(requestId)?.abort(err);
10619
10650
  expansionRejectors.get(requestId)?.(err);
10620
10651
  pushServiceDiagnostic(
10621
10652
  "service-aborted",
10622
10653
  "info",
10623
- `pending expansion of '${id}' aborted by retractExpansion() (\xA79.2)`
10654
+ `pending expansion of '${id}' aborted by retractExpansion()`
10624
10655
  );
10625
10656
  publish({ pendingExpansions: expansionLedger.ids() });
10626
10657
  }
@@ -10827,14 +10858,14 @@ function createGraphInstance(opts) {
10827
10858
  if (ctx.signal.aborted) {
10828
10859
  throw new OrbitOperationError(
10829
10860
  { code: "aborted", cause: "superseded" },
10830
- `search('${query}') was superseded before admission (\xA716.5)`
10861
+ `search('${query}') was superseded before admission`
10831
10862
  );
10832
10863
  }
10833
10864
  const denial = acceptanceQueue.admit(() => searchAdmissible(ctx, at));
10834
10865
  if (denial !== null) {
10835
10866
  throw new OrbitOperationError(
10836
10867
  { code: "aborted", cause: denial },
10837
- `search('${query}') result discarded: ${denial} (\xA79.2/\xA716.5)`
10868
+ `search('${query}') result discarded: ${denial}`
10838
10869
  );
10839
10870
  }
10840
10871
  if (accepted === null) return raw;
@@ -10865,7 +10896,7 @@ function createGraphInstance(opts) {
10865
10896
  const at = revisionSnapshot();
10866
10897
  const key = serviceCacheKey({
10867
10898
  serviceId: "search",
10868
- // `fields` is defensive insurance (F12-03): searchIndex is
10899
+ // `fields` is defensive insurance: searchIndex is
10869
10900
  // construction-only (D7) so it cannot legitimately change, but keying
10870
10901
  // it here guarantees a cached result can never outlive the field
10871
10902
  // configuration it was computed under.
@@ -10879,7 +10910,7 @@ function createGraphInstance(opts) {
10879
10910
  searchFlight = null;
10880
10911
  const err = new OrbitOperationError(
10881
10912
  { code: "aborted", cause: "superseded" },
10882
- `search('${query}') superseded the older in-flight query (\xA716.5)`
10913
+ `search('${query}') superseded the older in-flight query`
10883
10914
  );
10884
10915
  flight.handle.abort(err);
10885
10916
  flight.reject(err);
@@ -10945,7 +10976,7 @@ function createGraphInstance(opts) {
10945
10976
  searchFlight = null;
10946
10977
  const err = new OrbitOperationError(
10947
10978
  { code: "aborted", cause: "cleared" },
10948
- "search cleared while in flight (\xA716.5)"
10979
+ "search cleared while in flight"
10949
10980
  );
10950
10981
  flight.handle.abort(err);
10951
10982
  flight.reject(err);
@@ -11012,7 +11043,7 @@ function createGraphInstance(opts) {
11012
11043
  if (denial !== null) {
11013
11044
  throw new OrbitOperationError(
11014
11045
  { code: "aborted", cause: "stale" },
11015
- `findPath('${sourceId}' \u2192 '${targetId}') discarded: ${denial} (\xA79.2)`
11046
+ `findPath('${sourceId}' \u2192 '${targetId}') discarded: ${denial}`
11016
11047
  );
11017
11048
  }
11018
11049
  if (token !== pathSeq || result === null) return result;
@@ -11104,7 +11135,7 @@ function createGraphInstance(opts) {
11104
11135
  findings.push(`mode: unknown filter mode '${String(spec.mode)}'`);
11105
11136
  }
11106
11137
  if (findings.length > 0) {
11107
- throw new TypeError(`applyHostUpdate: invalid filter (\xA79.1): ${findings.join("; ")}`);
11138
+ throw new TypeError(`applyHostUpdate: invalid filter: ${findings.join("; ")}`);
11108
11139
  }
11109
11140
  }
11110
11141
  const prev = store.getState();
@@ -11144,7 +11175,7 @@ function createGraphInstance(opts) {
11144
11175
  severity: "error",
11145
11176
  count: issues.length,
11146
11177
  sampleIds: issues.slice(0, DIAGNOSTIC_SAMPLE_CAP).map((i) => i.where),
11147
- message: `columnar snapshot rejected whole (\xA75.1): ${issues[0].where} \u2014 ${issues[0].detail}`
11178
+ message: `columnar snapshot rejected whole: ${issues[0].where} \u2014 ${issues[0].detail}`
11148
11179
  }
11149
11180
  ];
11150
11181
  columnarRejected = true;
@@ -11165,14 +11196,14 @@ function createGraphInstance(opts) {
11165
11196
  const isReplay = baseAccepted !== null && baseAccepted.datasetKey === data.datasetKey && baseAccepted.sourceRevision === data.sourceRevision;
11166
11197
  if (!isReplay) {
11167
11198
  const nextAccepted = preAccepted ?? validateSnapshot(data);
11168
- abortAllSessions(null, "replaced: a declarative snapshot was applied (\xA77.5)");
11199
+ abortAllSessions(null, "replaced: a declarative snapshot was applied");
11169
11200
  overlayIdsCleared = clearOverlayState();
11170
11201
  datasetKeyChanged = baseAccepted !== null && baseAccepted.datasetKey !== data.datasetKey;
11171
11202
  if (datasetKeyChanged) {
11172
11203
  reconciler = new Reconciler();
11173
11204
  engineDiags = [];
11174
11205
  abortExpansionsForDatasetSwap();
11175
- abortSearchFlight("dataset-changed", "search aborted: the datasetKey changed (\xA75/\xA716.5)");
11206
+ abortSearchFlight("dataset-changed", "search aborted: the datasetKey changed");
11176
11207
  resetMaskState();
11177
11208
  historyKernel.clear();
11178
11209
  stopTimelineTimer();
@@ -11287,7 +11318,7 @@ function createGraphInstance(opts) {
11287
11318
  severity: "error",
11288
11319
  count: 1,
11289
11320
  sampleIds: [],
11290
- message: "groups and groupBy are mutually exclusive (\xA716.3 R-16.3-15): NEITHER applies until the host removes one"
11321
+ message: "groups and groupBy are mutually exclusive: NEITHER applies until the host removes one"
11291
11322
  }
11292
11323
  ];
11293
11324
  groupsDiagsChanged = true;
@@ -11325,7 +11356,7 @@ function createGraphInstance(opts) {
11325
11356
  severity: "warning",
11326
11357
  count: 1,
11327
11358
  sampleIds: [],
11328
- message: "parallelEdgeGrouping is inoperative: the accepted edge list has no same-endpoint-pair parallels (ids synthesized from (type,source,target)-style dedupe already collapse them) \u2014 the toggle changed nothing (\xA716.3 R-16.3-24)"
11359
+ message: "parallelEdgeGrouping is inoperative: the accepted edge list has no same-endpoint-pair parallels (ids synthesized from (type,source,target)-style dedupe already collapse them) \u2014 the toggle changed nothing"
11329
11360
  }
11330
11361
  ];
11331
11362
  parallelRejected = true;
@@ -11405,7 +11436,7 @@ function createGraphInstance(opts) {
11405
11436
  severity: "warning",
11406
11437
  count: update.metrics.length,
11407
11438
  sampleIds: update.metrics.slice(0, DIAGNOSTIC_SAMPLE_CAP).map((c) => c.metric),
11408
- message: "metric columns discarded: no accepted model to join against (\xA712)"
11439
+ message: "metric columns discarded: no accepted model to join against"
11409
11440
  }
11410
11441
  ];
11411
11442
  } else {
@@ -11414,7 +11445,7 @@ function createGraphInstance(opts) {
11414
11445
  count: accepted.nodes.length,
11415
11446
  // I1: columns must be stamped with the revision current at ISSUE
11416
11447
  // time — never the post-update revision (that made the gate
11417
- // self-satisfying, F11-01).
11448
+ // self-satisfying).
11418
11449
  modelRevision: issuedModelSeq
11419
11450
  });
11420
11451
  metricDiags = res.diagnostics;
@@ -11551,7 +11582,7 @@ function createGraphInstance(opts) {
11551
11582
  severity: "warning",
11552
11583
  count: 1,
11553
11584
  sampleIds: [],
11554
- message: "searchIndex is construction-only (\xA716.5/D7): pass it to createGraphInstance options (or key-remount <Graph>) \u2014 this update's searchIndex was ignored"
11585
+ message: "searchIndex is construction-only: pass it to createGraphInstance options (or key-remount <Graph>) \u2014 this update's searchIndex was ignored"
11555
11586
  }
11556
11587
  ];
11557
11588
  searchIndexRejected = true;
@@ -11988,9 +12019,9 @@ function createGraphInstance(opts) {
11988
12019
  applyEmphasis(s.engine, node === null ? null : index);
11989
12020
  emit("nodeHover", { node });
11990
12021
  },
11991
- // §13 native-route edge events (§7.4 mapping). Host onLink* events are
12022
+ // native-route edge events. Host onLink* events are
11992
12023
  // honored regardless of the committed route — an adapter that surfaces
11993
- // them despite declaring linkPicking:false is a harmless pass-through
12024
+ // them despite declaring linkPicking:false is a harmless pass-through
11994
12025
  // but only the 'native' route RELIES on them; the fallback route feeds
11995
12026
  // the same typed events through the pointer samplers.
11996
12027
  onLinkClick(linkIndex) {
@@ -12027,7 +12058,7 @@ function createGraphInstance(opts) {
12027
12058
  const prevented = emit("nodeDragEnd", { node, x, y });
12028
12059
  if (!prevented) writePin(node.id, [x, y]);
12029
12060
  },
12030
- // §14/§15: right-click / long-press → typed 'contextMenu' event. The
12061
+ // Right-click or long-press → typed 'contextMenu' event. The
12031
12062
  // core adds NO built-in follow-up — components own the menu.
12032
12063
  onContextMenu(index, screen) {
12033
12064
  if (!active()) return;
@@ -12041,7 +12072,7 @@ function createGraphInstance(opts) {
12041
12072
  emit("contextMenu", { target: { kind: "node", node }, screen: screenPt });
12042
12073
  },
12043
12074
  /**
12044
- * §13/§17 overlay scheduler tick (adapter activity clock). Per tick:
12075
+ * Overlay scheduler tick (adapter activity clock). Per tick:
12045
12076
  * (1) sim-hot degradation — while the simulation runs, ONE getPositions
12046
12077
  * readback refreshes the CPU cache at a capped >=500ms cadence (M0:
12047
12078
  * tracked readback stalls ~18ms, so the lane NEVER reads back per
@@ -12268,13 +12299,14 @@ function createGraphInstance(opts) {
12268
12299
  route,
12269
12300
  screenToSpace: (p) => eng.screenToSpace?.(p) ?? null,
12270
12301
  medianLinkWidthPx: () => medianLinkWidthPx(lastLinkWidths),
12271
- // S9-T18: the facade's per-candidate visibility mask reads the LIVE
12272
- // §9.1 mask — no re-arm needed on mask changes (§13 grid invariance).
12302
+ // the facade's per-candidate visibility mask reads the LIVE
12303
+ // mask — no re-arm needed on mask changes.
12273
12304
  linkVisible: (linkIndex) => maskEdgeVisibleAt(linkIndex)
12274
12305
  });
12275
12306
  const restartAlpha = layout === "force" ? 1 : null;
12276
12307
  const committed = buildAndCommitFullReplay(s, restartAlpha);
12277
12308
  const restarted = committed && accepted !== null && restartAlpha !== null;
12309
+ if (layout === "fixed") eng.pause();
12278
12310
  publish({
12279
12311
  status: "ready",
12280
12312
  revisions: { ...store.getState().revisions, appliedRender: eng.appliedRevision() },
@@ -12373,7 +12405,7 @@ function createGraphInstance(opts) {
12373
12405
  if (g.requestAnimationFrame === wrapper) g.requestAnimationFrame = native;
12374
12406
  if (registrations > 0 && !destroyed) {
12375
12407
  console.warn(
12376
- `orbit: ${registrations} requestAnimationFrame registration(s) observed over 500ms while this instance is quiescent (\xA717/S13-T06 one-frame-loop). If no app-owned animation is running, a second frame loop is leaking.`
12408
+ `orbit: ${registrations} requestAnimationFrame registration(s) observed over 500ms while this instance is quiescent. If no app-owned animation is running, a second frame loop is leaking.`
12377
12409
  );
12378
12410
  }
12379
12411
  }, 500);
@@ -12448,7 +12480,7 @@ function createGraphInstance(opts) {
12448
12480
  function warnViewStateDrop(channel, why) {
12449
12481
  if (!DEV || viewStateDropWarned.has(channel)) return;
12450
12482
  viewStateDropWarned.add(channel);
12451
- console.warn(`orbit: getViewState omitted ${channel} \u2014 ${why} (\xA716.14)`);
12483
+ console.warn(`orbit: getViewState omitted ${channel} \u2014 ${why}`);
12452
12484
  }
12453
12485
  function serializableScaleOf(channel, value) {
12454
12486
  if (value === void 0) return void 0;
@@ -12565,7 +12597,7 @@ function createGraphInstance(opts) {
12565
12597
  if (visible.length > limit) {
12566
12598
  throw new OrbitOperationError(
12567
12599
  { code: "export-materialization-too-large", rowCount: visible.length, limit },
12568
- `includePositions over ${limit} nodes \u2014 persist the layout through the export lane and reference it from dataRef (\xA716.14)`
12600
+ `includePositions over ${limit} nodes \u2014 persist the layout through the export lane and reference it from dataRef`
12569
12601
  );
12570
12602
  }
12571
12603
  const pos = eng.getPositions();
@@ -12665,7 +12697,7 @@ function createGraphInstance(opts) {
12665
12697
  severity: "error",
12666
12698
  count: verdict.problems.length,
12667
12699
  sampleIds: [],
12668
- message: `setViewState rejected (${verdict.code}): ${verdict.problems.slice(0, 3).join("; ")} \u2014 nothing was applied (\xA716.14)`
12700
+ message: `setViewState rejected (${verdict.code}): ${verdict.problems.slice(0, 3).join("; ")} \u2014 nothing was applied`
12669
12701
  }
12670
12702
  ];
12671
12703
  pendingDiagnosticsRefresh = true;
@@ -12765,6 +12797,9 @@ function createGraphInstance(opts) {
12765
12797
  } else if (wantsManualGroups && !groupsControlled) {
12766
12798
  commitManualGroups(manualGroups.length > 0 ? manualGroups : null);
12767
12799
  }
12800
+ if (state.layout.kind !== layout) {
12801
+ applyHostUpdateInner({ layout: state.layout.kind });
12802
+ }
12768
12803
  if (state.styling !== void 0 && !needsHost) {
12769
12804
  const patch = {};
12770
12805
  if (state.styling.showLinks !== void 0) patch.showLinks = state.styling.showLinks;
@@ -12885,7 +12920,7 @@ function createGraphInstance(opts) {
12885
12920
  if (eng2 === null || eng2.captureScreenshot === void 0) {
12886
12921
  throw new OrbitOperationError(
12887
12922
  { code: "aborted", cause: "no screenshot capability" },
12888
- 'exportImage("png") requires an engine with screenshot capture (\xA716.14)'
12923
+ 'exportImage("png") requires an engine with screenshot capture'
12889
12924
  );
12890
12925
  }
12891
12926
  const blob = await eng2.captureScreenshot();
@@ -12926,7 +12961,7 @@ function createGraphInstance(opts) {
12926
12961
  if (elementCount > limit && opts2?.fallback !== "raster-hybrid") {
12927
12962
  throw new OrbitOperationError(
12928
12963
  { code: "export-too-large", elementCount, limit },
12929
- `SVG export of ${elementCount} elements exceeds ${limit} \u2014 filter/isolate first, or pass { fallback: 'raster-hybrid' } (\xA716.14)`
12964
+ `SVG export of ${elementCount} elements exceeds ${limit} \u2014 filter/isolate first, or pass { fallback: 'raster-hybrid' }`
12930
12965
  );
12931
12966
  }
12932
12967
  let minX = Infinity;
@@ -13027,14 +13062,17 @@ function createGraphInstance(opts) {
13027
13062
  }
13028
13063
  function captureExportPin() {
13029
13064
  if (accepted === null) return null;
13030
- return { accepted, scene, mask: softMask };
13065
+ let visibleIds = null;
13066
+ if (scene !== null) {
13067
+ const slots = visibleSlotsOf(scene, softMask);
13068
+ const ids = /* @__PURE__ */ new Set();
13069
+ for (const i of slots) ids.add(scene.idByIndex[i]);
13070
+ visibleIds = ids;
13071
+ }
13072
+ return { accepted, scene, visibleIds };
13031
13073
  }
13032
13074
  function pinnedVisibleIds(pin) {
13033
- if (pin.scene === null) return null;
13034
- const slots = visibleSlotsOf(pin.scene, pin.mask);
13035
- const ids = /* @__PURE__ */ new Set();
13036
- for (const i of slots) ids.add(pin.scene.idByIndex[i]);
13037
- return ids;
13075
+ return pin.visibleIds;
13038
13076
  }
13039
13077
  function pinnedRowCount(pin, scope) {
13040
13078
  if (scope === "accepted") return pin.accepted.nodes.length + pin.accepted.edges.length;
@@ -13054,7 +13092,7 @@ function createGraphInstance(opts) {
13054
13092
  if (rowCount > limit) {
13055
13093
  throw new OrbitOperationError(
13056
13094
  { code: "export-materialization-too-large", rowCount, limit },
13057
- `exportData would materialize ${rowCount} rows (limit ${limit}) \u2014 use exportDataStream (\xA716.14)`
13095
+ `exportData would materialize ${rowCount} rows (limit ${limit}) \u2014 use exportDataStream`
13058
13096
  );
13059
13097
  }
13060
13098
  if (scope === "accepted") return { nodes: pin.accepted.nodes, edges: pin.accepted.edges };
@@ -13097,7 +13135,7 @@ function createGraphInstance(opts) {
13097
13135
  if (bound > limit) {
13098
13136
  throw new OrbitOperationError(
13099
13137
  { code: "export-materialization-too-large", rowCount: bound, limit },
13100
- `exportLayout would materialize ${bound} rows (limit ${limit}) \u2014 use exportLayoutStream (\xA716.14)`
13138
+ `exportLayout would materialize ${bound} rows (limit ${limit}) \u2014 use exportLayoutStream`
13101
13139
  );
13102
13140
  }
13103
13141
  const out = /* @__PURE__ */ new Map();
@@ -13176,9 +13214,8 @@ function createGraphInstance(opts) {
13176
13214
  visibleNodeCount: st.visible.nodes,
13177
13215
  visibleEdgeCount: st.visible.edges,
13178
13216
  estimatedCpuBytes: estimateCpuBytes(),
13179
- // The acceptance queue is synchronous (depth is 0 outside a job, and a
13180
- // reader inside a job observes 1); async ingestion depth arrives with
13181
- // the worker lane (PR-E).
13217
+ // The acceptance queue is synchronous: depth is 0 outside a job, and a
13218
+ // reader inside a job observes 1.
13182
13219
  queueDepth: acceptanceQueue.active ? 1 : 0,
13183
13220
  modelRevision: st.revisions.model,
13184
13221
  scopeRevision: st.revisions.scope,
@@ -13402,7 +13439,7 @@ var OverviewController = class {
13402
13439
  getScene;
13403
13440
  getVisible;
13404
13441
  size;
13405
- /** Transform of the LAST rasterization; null until rasterize() succeeds. */
13442
+ /** Transform of the LAST rasterization; null until rasterize succeeds. */
13406
13443
  frame = null;
13407
13444
  // --- throttle state (latched by shouldRefresh when it answers true) ---
13408
13445
  lastRefreshMs = null;
@@ -13417,9 +13454,9 @@ var OverviewController = class {
13417
13454
  * when it returns true, so each `true` accounts for exactly one refresh:
13418
13455
  *
13419
13456
  * - hot (`simulationRunning`): time-gated only (≤ 2 Hz) — the epoch is
13420
- * ignored because positions change continuously without epoch advances;
13457
+ * ignored because positions change continuously without epoch advances;
13421
13458
  * - idle: refresh only when the epoch ADVANCED since the last refresh,
13422
- * time-gated at ≤ 1 Hz;
13459
+ * time-gated at ≤ 1 Hz;
13423
13460
  * - idle + unchanged epoch: always false — zero work, forever.
13424
13461
  */
13425
13462
  shouldRefresh(nowMs2, simulationRunning, epoch) {
@@ -13437,7 +13474,7 @@ var OverviewController = class {
13437
13474
  /**
13438
13475
  * Rasterizes the current scene into a fresh `size²` RGBA dot field: 1 px
13439
13476
  * white dots whose alpha ACCUMULATES on overlap (heatmap-ish density),
13440
- * dimmed for mask-hidden points; NaN pairs (§7.3 tombstones) are skipped.
13477
+ * dimmed for mask-hidden points; NaN pairs are skipped.
13441
13478
  * World bounds map into the thumbnail with a 5 % edge padding at a UNIFORM
13442
13479
  * scale (aspect preserved, centered on the short axis) and a downward pixel
13443
13480
  * y (see module header). Returns null when there is no scene or no point.