react-state-basis 0.6.4 → 0.6.6
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/README.md +59 -1
- package/dist/{chunk-6GBZSOB3.mjs → chunk-WMHY2C6D.mjs} +300 -86
- package/dist/chunk-WMHY2C6D.mjs.map +1 -0
- package/dist/index.d.mts +37 -2
- package/dist/index.d.ts +37 -2
- package/dist/index.js +300 -84
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -1
- package/dist/index.mjs.map +1 -1
- package/dist/integrations/zustand.js +296 -84
- package/dist/integrations/zustand.js.map +1 -1
- package/dist/integrations/zustand.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-6GBZSOB3.mjs.map +0 -1
|
@@ -24,33 +24,92 @@ __export(zustand_exports, {
|
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(zustand_exports);
|
|
26
26
|
|
|
27
|
+
// src/core/constants.ts
|
|
28
|
+
var WINDOW_SIZE = 50;
|
|
29
|
+
var PAIR_RARITY_TARGET = 0.01;
|
|
30
|
+
var RELATIVE_OVERLAP_FLOOR = 0.65;
|
|
31
|
+
var LOOP_THRESHOLD = 150;
|
|
32
|
+
var VOLATILITY_THRESHOLD = 25;
|
|
33
|
+
var INSTANCE_SEP = "##";
|
|
34
|
+
|
|
27
35
|
// src/core/math.ts
|
|
28
|
-
var
|
|
36
|
+
var choose = (n, k) => {
|
|
37
|
+
if (k < 0 || k > n) return 0;
|
|
38
|
+
k = Math.min(k, n - k);
|
|
39
|
+
let result = 1;
|
|
40
|
+
for (let i = 0; i < k; i++) {
|
|
41
|
+
result = result * (n - i) / (i + 1);
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
var hypergeomPMF = (k, n1, m1, N) => {
|
|
46
|
+
const total = choose(N, n1);
|
|
47
|
+
if (total === 0) return 0;
|
|
48
|
+
return choose(m1, k) * choose(N - m1, n1 - k) / total;
|
|
49
|
+
};
|
|
50
|
+
var hypergeomUpperTailP = (kStart, n1, m1, N) => {
|
|
51
|
+
const kMax = Math.min(n1, m1);
|
|
52
|
+
let p = 0;
|
|
53
|
+
for (let k = Math.max(0, kStart); k <= kMax; k++) {
|
|
54
|
+
p += hypergeomPMF(k, n1, m1, N);
|
|
55
|
+
}
|
|
56
|
+
return p;
|
|
57
|
+
};
|
|
58
|
+
var minOverlapForRarity = (n1, m1, N, targetP) => {
|
|
59
|
+
const kMax = Math.min(n1, m1);
|
|
60
|
+
for (let k = 0; k <= kMax; k++) {
|
|
61
|
+
if (hypergeomUpperTailP(k, n1, m1, N) <= targetP) return k;
|
|
62
|
+
}
|
|
63
|
+
return kMax + 1;
|
|
64
|
+
};
|
|
65
|
+
var overlapThresholdCache = /* @__PURE__ */ new Map();
|
|
66
|
+
var getMinOverlap = (densityA, densityB, windowSize) => {
|
|
67
|
+
const lo = Math.min(densityA, densityB) | 0;
|
|
68
|
+
const hi = Math.max(densityA, densityB) | 0;
|
|
69
|
+
const key = `${lo}_${hi}_${windowSize}`;
|
|
70
|
+
let cached = overlapThresholdCache.get(key);
|
|
71
|
+
if (cached === void 0) {
|
|
72
|
+
const rare = minOverlapForRarity(lo, hi, windowSize, PAIR_RARITY_TARGET);
|
|
73
|
+
const floor = Math.ceil(RELATIVE_OVERLAP_FLOOR * lo);
|
|
74
|
+
cached = Math.max(rare, floor);
|
|
75
|
+
overlapThresholdCache.set(key, cached);
|
|
76
|
+
}
|
|
77
|
+
return cached;
|
|
78
|
+
};
|
|
79
|
+
var isSignificantOverlap = (overlap, densityA, densityB, windowSize) => {
|
|
80
|
+
if (densityA < 2 || densityB < 2) return false;
|
|
81
|
+
return overlap >= getMinOverlap(densityA, densityB, windowSize);
|
|
82
|
+
};
|
|
83
|
+
var countOverlapsCircular = (bufferA, headA, bufferB, headB) => {
|
|
29
84
|
const L = bufferA.length;
|
|
30
|
-
|
|
31
|
-
const
|
|
85
|
+
const offSync = ((headB - headA) % L + L) % L;
|
|
86
|
+
const offALeadsB = ((headB - headA + 1) % L + L) % L;
|
|
87
|
+
const offBLeadsA = ((headB - headA - 1) % L + L) % L;
|
|
88
|
+
let kSync = 0;
|
|
89
|
+
let kALeadsB = 0;
|
|
90
|
+
let kBLeadsA = 0;
|
|
91
|
+
let densityA = 0;
|
|
92
|
+
let densityB = 0;
|
|
32
93
|
for (let i = 0; i < L; i++) {
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
94
|
+
const a = bufferA[i] ? 1 : 0;
|
|
95
|
+
const b = bufferB[i] ? 1 : 0;
|
|
96
|
+
densityA += a;
|
|
97
|
+
densityB += b;
|
|
98
|
+
let iSync = i + offSync;
|
|
99
|
+
if (iSync >= L) iSync -= L;
|
|
100
|
+
let iALeadsB = i + offALeadsB;
|
|
101
|
+
if (iALeadsB >= L) iALeadsB -= L;
|
|
102
|
+
let iBLeadsA = i + offBLeadsA;
|
|
103
|
+
if (iBLeadsA >= L) iBLeadsA -= L;
|
|
104
|
+
if (a && bufferB[iSync]) kSync++;
|
|
105
|
+
if (a && bufferB[iALeadsB]) kALeadsB++;
|
|
106
|
+
if (a && bufferB[iBLeadsA]) kBLeadsA++;
|
|
42
107
|
}
|
|
43
|
-
|
|
44
|
-
return dot / (Math.sqrt(magA) * Math.sqrt(magB));
|
|
108
|
+
return { kSync, kALeadsB, kBLeadsA, densityA, densityB };
|
|
45
109
|
};
|
|
46
|
-
var
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
dot += A[i] * B[i];
|
|
50
|
-
magA += A[i] * A[i];
|
|
51
|
-
magB += B[i] * B[i];
|
|
52
|
-
}
|
|
53
|
-
return magA === 0 || magB === 0 ? 0 : dot / (Math.sqrt(magA) * Math.sqrt(magB));
|
|
110
|
+
var cosineFromOverlap = (overlap, densityA, densityB) => {
|
|
111
|
+
if (densityA <= 0 || densityB <= 0) return 0;
|
|
112
|
+
return overlap / Math.sqrt(densityA * densityB);
|
|
54
113
|
};
|
|
55
114
|
|
|
56
115
|
// src/core/graph.ts
|
|
@@ -87,13 +146,27 @@ var calculateSpectralInfluence = (graph, maxIterations = 20, tolerance = 1e-3) =
|
|
|
87
146
|
}
|
|
88
147
|
return scores;
|
|
89
148
|
};
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
149
|
+
var groupEventSources = (nodes, edges) => {
|
|
150
|
+
const outgoing = /* @__PURE__ */ new Map();
|
|
151
|
+
edges.forEach((e) => {
|
|
152
|
+
if (!outgoing.has(e.source)) outgoing.set(e.source, []);
|
|
153
|
+
outgoing.get(e.source).push(e);
|
|
154
|
+
});
|
|
155
|
+
const eventSourceIds = nodes.filter((n) => n.role === "event").map((n) => n.id);
|
|
156
|
+
const signatureOf = (sourceEdges) => sourceEdges.map((e) => `${e.target}@${e.weight}`).sort().join("|");
|
|
157
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
158
|
+
eventSourceIds.forEach((id) => {
|
|
159
|
+
const sig = signatureOf(outgoing.get(id) || []);
|
|
160
|
+
if (!buckets.has(sig)) buckets.set(sig, []);
|
|
161
|
+
buckets.get(sig).push(id);
|
|
162
|
+
});
|
|
163
|
+
const groups = Array.from(buckets.values()).map((sourceIds) => ({
|
|
164
|
+
sourceIds,
|
|
165
|
+
occurrences: sourceIds.length,
|
|
166
|
+
edges: (outgoing.get(sourceIds[0]) || []).slice()
|
|
167
|
+
}));
|
|
168
|
+
return groups.sort((a, b) => b.edges.length - a.edges.length || b.occurrences - a.occurrences);
|
|
169
|
+
};
|
|
97
170
|
|
|
98
171
|
// src/core/label.ts
|
|
99
172
|
var stripInstance = (label) => {
|
|
@@ -106,6 +179,7 @@ var parseLabel = (label) => {
|
|
|
106
179
|
return { file: parts[0] || "Unknown", name: parts[1] || base };
|
|
107
180
|
};
|
|
108
181
|
var isSameField = (labelA, labelB) => stripInstance(labelA) === stripInstance(labelB);
|
|
182
|
+
var isEffectLabel = (name) => /^effect_L\d+(:\d+)?$/.test(name) || name === "anonymous_effect" || name === "anonymous_layout_effect";
|
|
109
183
|
|
|
110
184
|
// src/core/ranker.ts
|
|
111
185
|
var identifyTopIssues = (graph, history2, redundantLabels2, violationMap) => {
|
|
@@ -207,32 +281,22 @@ var LAST_LOG_TIMES = /* @__PURE__ */ new Map();
|
|
|
207
281
|
var LOG_COOLDOWN = 3e3;
|
|
208
282
|
var THEME = {
|
|
209
283
|
identity: "#6C5CE7",
|
|
210
|
-
// Purple (Brand)
|
|
211
284
|
problem: "#D63031",
|
|
212
|
-
// Red (Bugs)
|
|
213
285
|
solution: "#FBC531",
|
|
214
|
-
// Yellow (Fixes)
|
|
215
286
|
context: "#0984E3",
|
|
216
|
-
// Blue (Locations)
|
|
217
287
|
muted: "#9AA0A6",
|
|
218
|
-
// Gray (Metadata)
|
|
219
288
|
border: "#2E2E35",
|
|
220
289
|
success: "#00b894"
|
|
221
|
-
// Green (Good Score)
|
|
222
290
|
};
|
|
223
291
|
var STYLES = {
|
|
224
|
-
// Structure
|
|
225
292
|
basis: `background: ${THEME.identity}; color: white; font-weight: bold; padding: 2px 6px; border-radius: 3px;`,
|
|
226
293
|
headerIdentity: `background: ${THEME.identity}; color: white; font-weight: bold; padding: 4px 8px; border-radius: 4px;`,
|
|
227
294
|
headerProblem: `background: ${THEME.problem}; color: white; font-weight: bold; padding: 4px 8px; border-radius: 4px;`,
|
|
228
295
|
version: `background: #a29bfe; color: #2d3436; padding: 2px 6px; border-radius: 3px; margin-left: -4px;`,
|
|
229
|
-
// Actions
|
|
230
296
|
actionLabel: `color: ${THEME.solution}; font-weight: bold;`,
|
|
231
297
|
actionPill: `color: ${THEME.solution}; font-weight: bold; border: 1px solid ${THEME.solution}; padding: 0 4px; border-radius: 3px;`,
|
|
232
|
-
// Context
|
|
233
298
|
impactLabel: `color: ${THEME.context}; font-weight: bold;`,
|
|
234
299
|
location: `color: ${THEME.context}; font-family: monospace; font-weight: bold;`,
|
|
235
|
-
// Text
|
|
236
300
|
subText: `color: ${THEME.muted}; font-size: 11px;`,
|
|
237
301
|
bold: "font-weight: bold;",
|
|
238
302
|
label: "background: #dfe6e9; color: #2d3436; padding: 0 4px; border-radius: 3px; font-family: monospace; font-weight: bold; border: 1px solid #b2bec3;"
|
|
@@ -247,6 +311,15 @@ var shouldLog = (key) => {
|
|
|
247
311
|
return false;
|
|
248
312
|
};
|
|
249
313
|
var isBooleanLike = (name) => /^(is|has|can|should|did|will|show|hide)(?=[A-Z_])/.test(name);
|
|
314
|
+
var areSyncSignificant = (metaA, metaB) => {
|
|
315
|
+
const { kSync, densityA, densityB } = countOverlapsCircular(
|
|
316
|
+
metaA.buffer,
|
|
317
|
+
metaA.head,
|
|
318
|
+
metaB.buffer,
|
|
319
|
+
metaB.head
|
|
320
|
+
);
|
|
321
|
+
return isSignificantOverlap(kSync, densityA, densityB, metaA.buffer.length);
|
|
322
|
+
};
|
|
250
323
|
var getSuggestedFix = (issue, info) => {
|
|
251
324
|
if (issue.label.includes("Global Event")) {
|
|
252
325
|
return `These variables update together but live in different hooks/files. Consolidate them into a single %cuseReducer%c or atomic store update.`;
|
|
@@ -276,7 +349,7 @@ var getSuggestedFix = (issue, info) => {
|
|
|
276
349
|
}
|
|
277
350
|
return `Check the dependency chain of ${info.name}.`;
|
|
278
351
|
};
|
|
279
|
-
var displayHealthReport = (history2,
|
|
352
|
+
var displayHealthReport = (history2, violationMap) => {
|
|
280
353
|
if (!isWeb) return;
|
|
281
354
|
const entries = Array.from(history2.entries());
|
|
282
355
|
if (entries.length === 0) return;
|
|
@@ -352,11 +425,10 @@ var displayHealthReport = (history2, threshold, violationMap) => {
|
|
|
352
425
|
processed.add(labelA);
|
|
353
426
|
entries.forEach(([labelB, metaB]) => {
|
|
354
427
|
if (labelA === labelB || processed.has(labelB)) return;
|
|
355
|
-
if (
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
}
|
|
428
|
+
if (!areSyncSignificant(metaA, metaB)) return;
|
|
429
|
+
if (metaA.role === "context" /* CONTEXT */ && metaB.role === "context" /* CONTEXT */) return;
|
|
430
|
+
currentCluster.push(labelB);
|
|
431
|
+
processed.add(labelB);
|
|
360
432
|
});
|
|
361
433
|
if (currentCluster.length > 1) clusters.push(currentCluster);
|
|
362
434
|
else independentCount++;
|
|
@@ -432,7 +504,7 @@ var displayRedundancyAlert = (labelA, metaA, labelB, metaB, sim) => {
|
|
|
432
504
|
const alertType = isContextMirror ? "CONTEXT MIRRORING" : isStoreMirror ? "STORE MIRRORING" : "DUPLICATE STATE";
|
|
433
505
|
console.group(`%c \u264A BASIS | ${alertType} `, STYLES.headerProblem);
|
|
434
506
|
console.log(`%c\u{1F4CD} Location: %c${infoA.file}`, STYLES.bold, STYLES.location);
|
|
435
|
-
console.log(`%cIssue:%c ${infoA.name} and ${infoB.name}
|
|
507
|
+
console.log(`%cIssue:%c ${infoA.name} and ${infoB.name} overlapped on ${(sim * 100).toFixed(0)}% of aligned updates.`, STYLES.bold, "");
|
|
436
508
|
if (isContextMirror || isStoreMirror) {
|
|
437
509
|
const sourceType = isStoreMirror ? "External Store" : "Global Context";
|
|
438
510
|
console.log(
|
|
@@ -501,6 +573,99 @@ var displayCausalHint = (targetLabel, targetMeta, sourceLabel, sourceMeta) => {
|
|
|
501
573
|
}
|
|
502
574
|
console.groupEnd();
|
|
503
575
|
};
|
|
576
|
+
var splitHookLine = (raw) => {
|
|
577
|
+
const m = raw.match(/^(.*):(\d+)$/);
|
|
578
|
+
if (!m) return { hook: raw };
|
|
579
|
+
return { hook: m[1], line: Number(m[2]) };
|
|
580
|
+
};
|
|
581
|
+
var formatHook = (raw) => {
|
|
582
|
+
const { hook } = splitHookLine(raw);
|
|
583
|
+
if (!isEffectLabel(hook)) return hook;
|
|
584
|
+
const lineMatch = hook.match(/L(\d+)$/);
|
|
585
|
+
return lineMatch ? `effect @ L${lineMatch[1]}` : "effect (anonymous)";
|
|
586
|
+
};
|
|
587
|
+
var formatNode = (node, fallbackId = "?") => {
|
|
588
|
+
if (!node) return fallbackId;
|
|
589
|
+
if (node.role === "event") return "Event";
|
|
590
|
+
const hook = formatHook(node.name || node.id);
|
|
591
|
+
if (node.file && hook) return `${node.file} \u2192 ${hook}`;
|
|
592
|
+
return hook || node.id;
|
|
593
|
+
};
|
|
594
|
+
var displayGraphReport = (graph) => {
|
|
595
|
+
if (!isWeb) return;
|
|
596
|
+
if (graph.nodes.length === 0) {
|
|
597
|
+
console.log(
|
|
598
|
+
`%c \u{1F4CA} BASIS | CAUSAL GRAPH %c(no data yet)`,
|
|
599
|
+
STYLES.headerIdentity,
|
|
600
|
+
`color: ${THEME.muted}; font-style: italic;`
|
|
601
|
+
);
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
const nodeById = new Map(graph.nodes.map((n) => [n.id, n]));
|
|
605
|
+
const outgoing = /* @__PURE__ */ new Map();
|
|
606
|
+
graph.edges.forEach((e) => {
|
|
607
|
+
if (!outgoing.has(e.source)) outgoing.set(e.source, []);
|
|
608
|
+
outgoing.get(e.source).push(e);
|
|
609
|
+
});
|
|
610
|
+
const eventGroups = graph.eventGroups.map((g) => ({
|
|
611
|
+
sourceIds: g.sourceIds,
|
|
612
|
+
sourceNode: nodeById.get(g.sourceIds[0]),
|
|
613
|
+
edges: g.edges,
|
|
614
|
+
occurrences: g.occurrences
|
|
615
|
+
}));
|
|
616
|
+
const groupedSourceIds = new Set(graph.eventGroups.flatMap((g) => g.sourceIds));
|
|
617
|
+
const nonEventGroups = Array.from(outgoing.keys()).filter((id) => !groupedSourceIds.has(id)).map((id) => ({ sourceIds: [id], sourceNode: nodeById.get(id), edges: outgoing.get(id), occurrences: 1 }));
|
|
618
|
+
const groups = [...eventGroups, ...nonEventGroups].sort(
|
|
619
|
+
(a, b) => b.edges.length - a.edges.length || b.occurrences - a.occurrences
|
|
620
|
+
);
|
|
621
|
+
console.group(
|
|
622
|
+
`%c \u{1F4CA} BASIS | CAUSAL GRAPH %c${graph.nodes.length} nodes \xB7 ${graph.edges.length} edges \xB7 ${groups.length} sources \xB7 buffer window ${graph.bufferWindowSize}`,
|
|
623
|
+
STYLES.headerIdentity,
|
|
624
|
+
`color: ${THEME.muted}; font-weight: normal; font-style: italic;`
|
|
625
|
+
);
|
|
626
|
+
console.log(
|
|
627
|
+
`%cparent \u2192 child = observed cause \u2192 update. (\xD7N) = times in this window. Event groups with the same fan-out are collapsed.`,
|
|
628
|
+
STYLES.subText
|
|
629
|
+
);
|
|
630
|
+
groups.forEach((group) => {
|
|
631
|
+
const isEvent = group.sourceNode?.role === "event";
|
|
632
|
+
const isCtx = group.sourceNode?.role === "context" /* CONTEXT */;
|
|
633
|
+
const isFx = group.sourceNode?.role === "effect";
|
|
634
|
+
const isUnknown = group.sourceNode?.role === "unknown";
|
|
635
|
+
const icon = isEvent ? "\u26A1" : isCtx ? "\u03A9" : isFx ? "\u21AF" : isUnknown ? "?" : "\u25CF";
|
|
636
|
+
const color = isEvent ? THEME.solution : isCtx ? THEME.context : THEME.identity;
|
|
637
|
+
const fanout = group.edges.length;
|
|
638
|
+
const hits = group.occurrences;
|
|
639
|
+
const hitLabel = hits > 1 ? ` \xB7 \xD7${hits}` : "";
|
|
640
|
+
const title = isEvent ? `Event \xB7 ${fanout} target${fanout === 1 ? "" : "s"}${hitLabel}` : formatNode(group.sourceNode, group.sourceIds[0]);
|
|
641
|
+
console.groupCollapsed(
|
|
642
|
+
`%c${icon} %c${title}`,
|
|
643
|
+
`color: ${color};`,
|
|
644
|
+
"font-family: monospace; font-weight: 600;"
|
|
645
|
+
);
|
|
646
|
+
group.edges.slice().sort((a, b) => b.weight - a.weight).forEach((edge) => {
|
|
647
|
+
const target = nodeById.get(edge.target);
|
|
648
|
+
const label = formatNode(target, edge.target);
|
|
649
|
+
const weight = edge.weight > 1 ? ` (\xD7${edge.weight})` : "";
|
|
650
|
+
if (target?.redundant) {
|
|
651
|
+
console.log(
|
|
652
|
+
`%c ${label}%c${weight} %credundant`,
|
|
653
|
+
`color: ${THEME.muted}; font-family: monospace;`,
|
|
654
|
+
`color: ${THEME.muted}; font-style: italic;`,
|
|
655
|
+
`color: ${THEME.problem}; font-weight: bold;`
|
|
656
|
+
);
|
|
657
|
+
} else {
|
|
658
|
+
console.log(
|
|
659
|
+
`%c ${label}%c${weight}`,
|
|
660
|
+
`color: ${THEME.muted}; font-family: monospace;`,
|
|
661
|
+
`color: ${THEME.muted}; font-style: italic;`
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
});
|
|
665
|
+
console.groupEnd();
|
|
666
|
+
});
|
|
667
|
+
console.groupEnd();
|
|
668
|
+
};
|
|
504
669
|
var displayViolentBreaker = (label, count, threshold) => {
|
|
505
670
|
if (!isWeb) return;
|
|
506
671
|
const { name } = parseLabel(label);
|
|
@@ -513,7 +678,6 @@ Frequency: ${count} updates/sec`);
|
|
|
513
678
|
};
|
|
514
679
|
|
|
515
680
|
// src/core/analysis.ts
|
|
516
|
-
var CAUSAL_MARGIN = 0.05;
|
|
517
681
|
var isEventDriven = (label, graph) => {
|
|
518
682
|
for (const [parent, targets] of graph.entries()) {
|
|
519
683
|
if (parent.startsWith("Event_Tick_") && targets.has(label)) {
|
|
@@ -523,28 +687,33 @@ var isEventDriven = (label, graph) => {
|
|
|
523
687
|
return false;
|
|
524
688
|
};
|
|
525
689
|
var calculateAllSimilarities = (entryA, entryB) => {
|
|
526
|
-
const
|
|
527
|
-
entryA.meta.buffer,
|
|
528
|
-
entryA.meta.head,
|
|
529
|
-
entryB.meta.buffer,
|
|
530
|
-
entryB.meta.head,
|
|
531
|
-
0
|
|
532
|
-
);
|
|
533
|
-
const bA = calculateSimilarityCircular(
|
|
690
|
+
const { kSync, kALeadsB, kBLeadsA, densityA, densityB } = countOverlapsCircular(
|
|
534
691
|
entryA.meta.buffer,
|
|
535
692
|
entryA.meta.head,
|
|
536
693
|
entryB.meta.buffer,
|
|
537
|
-
entryB.meta.head
|
|
538
|
-
1
|
|
694
|
+
entryB.meta.head
|
|
539
695
|
);
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
);
|
|
547
|
-
|
|
696
|
+
const sync = cosineFromOverlap(kSync, densityA, densityB);
|
|
697
|
+
const bA = cosineFromOverlap(kALeadsB, densityA, densityB);
|
|
698
|
+
const aB = cosineFromOverlap(kBLeadsA, densityA, densityB);
|
|
699
|
+
const max = Math.max(sync, bA, aB);
|
|
700
|
+
const windowSize = entryA.meta.buffer.length;
|
|
701
|
+
const significantSync = isSignificantOverlap(kSync, densityA, densityB, windowSize);
|
|
702
|
+
const kLead = Math.max(kALeadsB, kBLeadsA);
|
|
703
|
+
const significantLead = isSignificantOverlap(kLead, densityA, densityB, windowSize) && kLead >= kSync + 1;
|
|
704
|
+
return {
|
|
705
|
+
sync,
|
|
706
|
+
bA,
|
|
707
|
+
aB,
|
|
708
|
+
max,
|
|
709
|
+
kSync,
|
|
710
|
+
kALeadsB,
|
|
711
|
+
kBLeadsA,
|
|
712
|
+
densityA,
|
|
713
|
+
densityB,
|
|
714
|
+
significantSync,
|
|
715
|
+
significantLead
|
|
716
|
+
};
|
|
548
717
|
};
|
|
549
718
|
var shouldSkipComparison = (entryA, entryB, dirtyLabels2) => {
|
|
550
719
|
if (entryA.label === entryB.label) return true;
|
|
@@ -569,52 +738,51 @@ var detectRedundancy = (entryA, entryB, similarities, redundantSet, violationMap
|
|
|
569
738
|
const roleA = entryA.meta.role;
|
|
570
739
|
const roleB = entryB.meta.role;
|
|
571
740
|
if (isGlobalSource(roleA) && isGlobalSource(roleB)) return;
|
|
572
|
-
if (
|
|
741
|
+
if (similarities.densityA < 2 || similarities.densityB < 2) return;
|
|
742
|
+
const score = similarities.sync;
|
|
573
743
|
if (roleA === "local" /* LOCAL */ && isGlobalSource(roleB)) {
|
|
574
744
|
redundantSet.add(entryA.label);
|
|
575
|
-
pushViolation(violationMap, entryB.label, { type: "context_mirror", target: entryA.label, similarity:
|
|
576
|
-
displayRedundancyAlert(entryA.label, entryA.meta, entryB.label, entryB.meta,
|
|
745
|
+
pushViolation(violationMap, entryB.label, { type: "context_mirror", target: entryA.label, similarity: score });
|
|
746
|
+
displayRedundancyAlert(entryA.label, entryA.meta, entryB.label, entryB.meta, score);
|
|
577
747
|
} else if (isGlobalSource(roleA) && roleB === "local" /* LOCAL */) {
|
|
578
748
|
redundantSet.add(entryB.label);
|
|
579
|
-
pushViolation(violationMap, entryA.label, { type: "context_mirror", target: entryB.label, similarity:
|
|
580
|
-
displayRedundancyAlert(entryB.label, entryB.meta, entryA.label, entryA.meta,
|
|
749
|
+
pushViolation(violationMap, entryA.label, { type: "context_mirror", target: entryB.label, similarity: score });
|
|
750
|
+
displayRedundancyAlert(entryB.label, entryB.meta, entryA.label, entryA.meta, score);
|
|
581
751
|
} else if (roleA === "local" /* LOCAL */ && roleB === "local" /* LOCAL */) {
|
|
582
752
|
redundantSet.add(entryA.label);
|
|
583
753
|
redundantSet.add(entryB.label);
|
|
584
|
-
pushViolation(violationMap, entryA.label, { type: "duplicate_state", target: entryB.label, similarity:
|
|
585
|
-
pushViolation(violationMap, entryB.label, { type: "duplicate_state", target: entryA.label, similarity:
|
|
586
|
-
displayRedundancyAlert(entryA.label, entryA.meta, entryB.label, entryB.meta,
|
|
754
|
+
pushViolation(violationMap, entryA.label, { type: "duplicate_state", target: entryB.label, similarity: score });
|
|
755
|
+
pushViolation(violationMap, entryB.label, { type: "duplicate_state", target: entryA.label, similarity: score });
|
|
756
|
+
displayRedundancyAlert(entryA.label, entryA.meta, entryB.label, entryB.meta, score);
|
|
587
757
|
}
|
|
588
758
|
};
|
|
589
759
|
var detectCausalLeak = (entryA, entryB, similarities, violationMap, graph) => {
|
|
590
760
|
if (entryA.isVolatile || entryB.isVolatile) return;
|
|
591
|
-
if (similarities.max - similarities.sync < CAUSAL_MARGIN) return;
|
|
592
761
|
const addLeak = (source, target) => {
|
|
593
762
|
if (isEventDriven(target, graph)) return;
|
|
594
|
-
|
|
595
|
-
violationMap.set(source, []);
|
|
596
|
-
}
|
|
597
|
-
violationMap.get(source).push({ type: "causal_leak", target });
|
|
763
|
+
pushViolation(violationMap, source, { type: "causal_leak", target });
|
|
598
764
|
const sourceEntry = source === entryA.label ? entryA : entryB;
|
|
599
765
|
const targetEntry = source === entryA.label ? entryB : entryA;
|
|
600
766
|
displayCausalHint(target, targetEntry.meta, source, sourceEntry.meta);
|
|
601
767
|
};
|
|
602
|
-
if (similarities.
|
|
768
|
+
if (similarities.kALeadsB >= similarities.kBLeadsA) {
|
|
603
769
|
addLeak(entryA.label, entryB.label);
|
|
604
|
-
} else
|
|
770
|
+
} else {
|
|
605
771
|
addLeak(entryB.label, entryA.label);
|
|
606
772
|
}
|
|
607
773
|
};
|
|
608
774
|
var detectSubspaceOverlap = (dirtyEntries, allEntries, redundantSet, dirtyLabels2, graph) => {
|
|
609
|
-
let compCount = 0;
|
|
610
775
|
const violationMap = /* @__PURE__ */ new Map();
|
|
776
|
+
let compCount = 0;
|
|
611
777
|
for (const entryA of dirtyEntries) {
|
|
612
778
|
for (const entryB of allEntries) {
|
|
613
779
|
if (shouldSkipComparison(entryA, entryB, dirtyLabels2)) continue;
|
|
614
780
|
compCount++;
|
|
615
781
|
const similarities = calculateAllSimilarities(entryA, entryB);
|
|
616
|
-
if (similarities.
|
|
782
|
+
if (similarities.significantSync) {
|
|
617
783
|
detectRedundancy(entryA, entryB, similarities, redundantSet, violationMap);
|
|
784
|
+
}
|
|
785
|
+
if (similarities.significantLead) {
|
|
618
786
|
detectCausalLeak(entryA, entryB, similarities, violationMap, graph);
|
|
619
787
|
}
|
|
620
788
|
}
|
|
@@ -847,9 +1015,9 @@ var registerVariable = (l, o = {}) => {
|
|
|
847
1015
|
});
|
|
848
1016
|
}
|
|
849
1017
|
};
|
|
850
|
-
var printBasisHealthReport = (
|
|
1018
|
+
var printBasisHealthReport = () => {
|
|
851
1019
|
if (!instance.config.debug) return;
|
|
852
|
-
displayHealthReport(instance.history,
|
|
1020
|
+
displayHealthReport(instance.history, instance.violationMap);
|
|
853
1021
|
};
|
|
854
1022
|
var getBasisMetrics = () => ({
|
|
855
1023
|
engine: "v0.6.x",
|
|
@@ -857,9 +1025,53 @@ var getBasisMetrics = () => ({
|
|
|
857
1025
|
analysis_ms: instance.metrics.lastAnalysisTimeMs.toFixed(3),
|
|
858
1026
|
entropy: instance.metrics.systemEntropy.toFixed(3)
|
|
859
1027
|
});
|
|
1028
|
+
var getBasisGraph = () => {
|
|
1029
|
+
const nodeIds = /* @__PURE__ */ new Set();
|
|
1030
|
+
const edges = [];
|
|
1031
|
+
instance.graph.forEach((targets, source) => {
|
|
1032
|
+
nodeIds.add(source);
|
|
1033
|
+
targets.forEach((weight, target) => {
|
|
1034
|
+
nodeIds.add(target);
|
|
1035
|
+
edges.push({ source, target, weight });
|
|
1036
|
+
});
|
|
1037
|
+
});
|
|
1038
|
+
const nodes = Array.from(nodeIds).map((id) => {
|
|
1039
|
+
if (id.startsWith("Event_Tick_")) {
|
|
1040
|
+
return { id, name: "Event", file: "(shared trigger)", role: "event", density: null, redundant: false };
|
|
1041
|
+
}
|
|
1042
|
+
const meta = instance.history.get(id);
|
|
1043
|
+
const { file, name } = parseLabel(id);
|
|
1044
|
+
if (!meta) {
|
|
1045
|
+
const role = isEffectLabel(name) ? "effect" : "unknown";
|
|
1046
|
+
return { id, name, file, role, density: null, redundant: false };
|
|
1047
|
+
}
|
|
1048
|
+
return {
|
|
1049
|
+
id,
|
|
1050
|
+
name,
|
|
1051
|
+
file,
|
|
1052
|
+
role: meta.role,
|
|
1053
|
+
density: meta.density,
|
|
1054
|
+
redundant: instance.redundantLabels.has(id)
|
|
1055
|
+
};
|
|
1056
|
+
});
|
|
1057
|
+
return {
|
|
1058
|
+
generatedAt: Date.now(),
|
|
1059
|
+
bufferWindowSize: WINDOW_SIZE,
|
|
1060
|
+
eventTtlMs: EVENT_TTL,
|
|
1061
|
+
nodes,
|
|
1062
|
+
edges,
|
|
1063
|
+
eventGroups: groupEventSources(nodes, edges)
|
|
1064
|
+
};
|
|
1065
|
+
};
|
|
1066
|
+
var printBasisGraph = () => {
|
|
1067
|
+
if (!instance.config.debug) return;
|
|
1068
|
+
displayGraphReport(getBasisGraph());
|
|
1069
|
+
};
|
|
860
1070
|
if (typeof window !== "undefined") {
|
|
861
1071
|
window.printBasisReport = printBasisHealthReport;
|
|
862
1072
|
window.getBasisMetrics = getBasisMetrics;
|
|
1073
|
+
window.getBasisGraph = getBasisGraph;
|
|
1074
|
+
window.printBasisGraph = printBasisGraph;
|
|
863
1075
|
}
|
|
864
1076
|
|
|
865
1077
|
// src/integrations/zustand.ts
|