@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/{chunk-NIJX5NVJ.js → chunk-KRCG2JFN.js} +169 -3
- package/dist/chunk-KRCG2JFN.js.map +1 -0
- package/dist/engine.d.ts +1 -1
- package/dist/{index-CFZMson3.d.ts → index-CPRTWpGA.d.ts} +176 -176
- package/dist/index.d.ts +611 -611
- package/dist/index.js +191 -154
- package/dist/index.js.map +1 -1
- package/dist/{lane-CHHLuxgq.d.ts → lane-_KPQ1deI.d.ts} +43 -43
- package/dist/testing.d.ts +22 -22
- package/dist/testing.js +99 -16
- package/dist/testing.js.map +1 -1
- package/dist/worker/entry.js +259 -2
- package/dist/worker/entry.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-GUXIITKK.js +0 -89
- package/dist/chunk-GUXIITKK.js.map +0 -1
- package/dist/chunk-NIJX5NVJ.js.map +0 -1
- package/dist/chunk-XAR262L3.js +0 -140
- package/dist/chunk-XAR262L3.js.map +0 -1
- package/dist/worker/entry.d.ts +0 -2
package/dist/index.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { deriveClusters, resolveClusterCenters, clusterCentroids } from './chunk-
|
|
2
|
-
export { DEFAULT_CLUSTER_CENTER_RADIUS, DEFAULT_LAYOUT_SEED, clusterCentroids, deriveClusters, generateClusterCenters, resolveClusterCenters } from './chunk-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
722
|
-
* leave-and-return guarantee
|
|
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
|
|
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
|
|
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 (
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2059
|
-
* scheduler can spread the work across idle frames
|
|
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
|
|
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
|
-
/**
|
|
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
|
|
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
|
|
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
|
-
/**
|
|
3277
|
-
*
|
|
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
|
-
/**
|
|
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
|
|
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
|
|
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)}
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
/**
|
|
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
|
-
*
|
|
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
|
|
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
|
-
/**
|
|
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
|
|
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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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("
|
|
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
|
|
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("
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
/**
|
|
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
|
-
/**
|
|
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
|
|
5362
|
-
* never selection visibility. Length must equal rowCount
|
|
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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
5698
|
-
*
|
|
5699
|
-
*
|
|
5700
|
-
*
|
|
5701
|
-
*
|
|
5702
|
-
*
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 (
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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)}"
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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}
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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}
|
|
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}
|
|
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()
|
|
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()
|
|
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
|
|
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}
|
|
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
|
|
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
|
|
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
|
|
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}
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
-
*
|
|
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
|
-
//
|
|
12272
|
-
//
|
|
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
|
|
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}
|
|
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
|
|
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
|
|
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
|
|
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' }
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
13180
|
-
// reader inside a job observes 1
|
|
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
|
|
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
|
-
*
|
|
13457
|
+
* ignored because positions change continuously without epoch advances;
|
|
13421
13458
|
* - idle: refresh only when the epoch ADVANCED since the last refresh,
|
|
13422
|
-
*
|
|
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
|
|
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.
|