react-state-basis 0.4.1 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -20,6 +20,36 @@ import {
20
20
  use as reactUse
21
21
  } from "react";
22
22
 
23
+ // src/core/math.ts
24
+ var calculateSimilarityCircular = (bufferA, headA, bufferB, headB, offset) => {
25
+ const L = bufferA.length;
26
+ let dot = 0;
27
+ let magA = 0;
28
+ let magB = 0;
29
+ const headOffset = headB - headA + offset;
30
+ for (let i = 0; i < L; i++) {
31
+ const valA = bufferA[i];
32
+ let iB = i + headOffset;
33
+ if (iB < 0) iB += L;
34
+ else if (iB >= L) iB -= L;
35
+ const valB = bufferB[iB];
36
+ dot += valA * valB;
37
+ magA += valA * valA;
38
+ magB += valB * valB;
39
+ }
40
+ if (magA === 0 || magB === 0) return 0;
41
+ return dot / (Math.sqrt(magA) * Math.sqrt(magB));
42
+ };
43
+ var calculateCosineSimilarity = (A, B) => {
44
+ let dot = 0, magA = 0, magB = 0;
45
+ for (let i = 0; i < A.length; i++) {
46
+ dot += A[i] * B[i];
47
+ magA += A[i] * A[i];
48
+ magB += B[i] * B[i];
49
+ }
50
+ return magA === 0 || magB === 0 ? 0 : dot / (Math.sqrt(magA) * Math.sqrt(magB));
51
+ };
52
+
23
53
  // src/core/logger.ts
24
54
  var isWeb = typeof window !== "undefined" && typeof window.document !== "undefined";
25
55
  var LAST_LOG_TIMES = /* @__PURE__ */ new Map();
@@ -32,9 +62,11 @@ var STYLES = {
32
62
  headerGreen: "background: #00b894; color: white; font-weight: bold; padding: 4px 8px; border-radius: 4px;",
33
63
  label: "background: #dfe6e9; color: #2d3436; padding: 0 4px; border-radius: 3px; font-family: monospace; font-weight: bold; border: 1px solid #b2bec3;",
34
64
  location: "color: #0984e3; font-family: monospace; font-weight: bold;",
35
- codeBlock: "background: #1e1e1e; color: #9cdcfe; padding: 8px 12px; display: block; margin: 4px 0; border-left: 3px solid #00b894; font-family: monospace; line-height: 1.4; border-radius: 0 3px 3px 0;",
65
+ impact: "background: #f1f2f6; color: #2f3542; padding: 0 4px; border-radius: 3px; font-weight: bold;",
36
66
  subText: "color: #636e72; font-size: 11px;",
37
- bold: "font-weight: bold;"
67
+ bold: "font-weight: bold;",
68
+ actionMemo: "color: #00b894; font-weight: bold; border: 1px solid #00b894; padding: 0 4px; border-radius: 3px;",
69
+ actionDelete: "color: #d63031; font-weight: bold; border: 1px solid #d63031; padding: 0 4px; border-radius: 3px;"
38
70
  };
39
71
  var parseLabel = (label) => {
40
72
  const parts = label.split(" -> ");
@@ -68,11 +100,11 @@ var displayRedundancyAlert = (labelA, labelB, sim) => {
68
100
  if (!isWeb || !shouldLog(`redundant-${labelA}-${labelB}`)) return;
69
101
  const infoA = parseLabel(labelA);
70
102
  const infoB = parseLabel(labelB);
71
- console.group(`%c \u{1F4D0} BASIS | REDUNDANT PATTERN `, STYLES.headerRed);
103
+ console.group(`%c \u264A BASIS | TWIN STATE DETECTED `, STYLES.headerRed);
72
104
  console.log(`%c\u{1F4CD} Location: %c${infoA.file}`, STYLES.bold, STYLES.location);
73
105
  console.log(
74
- `%cObservation:%c %c${infoA.name}%c and %c${infoB.name}%c move together.
75
- %cOne is likely a direct mirror of the other. Confidence: ${(sim * 100).toFixed(0)}%`,
106
+ `%cThe Rhythm:%c %c${infoA.name}%c and %c${infoB.name}%c are moving in perfect sync.
107
+ %cThis indicates that one is a redundant shadow of the other. Confidence: ${(sim * 100).toFixed(0)}%`,
76
108
  STYLES.bold,
77
109
  "",
78
110
  STYLES.label,
@@ -82,10 +114,12 @@ var displayRedundancyAlert = (labelA, labelB, sim) => {
82
114
  STYLES.subText
83
115
  );
84
116
  console.log(
85
- `%cAction:%c Refactor %c${infoB.name}%c to useMemo.`,
86
- "color: #00b894; font-weight: bold;",
117
+ `%cRecommended Fix:%c Derive %c${infoB.name}%c from %c${infoA.name}%c during the render pass.`,
118
+ STYLES.bold,
119
+ "",
120
+ STYLES.actionMemo,
87
121
  "",
88
- "color: #e84393; font-weight: bold;",
122
+ STYLES.bold,
89
123
  ""
90
124
  );
91
125
  console.groupEnd();
@@ -96,12 +130,12 @@ var displayCausalHint = (targetLabel, sourceLabel, method = "math") => {
96
130
  const target = parseLabel(targetLabel);
97
131
  const source = parseLabel(sourceLabel);
98
132
  console.groupCollapsed(
99
- `%c \u{1F4A1} BASIS | ${method === "math" ? "DETECTED" : "TRACKED"} SYNC LEAK `,
133
+ `%c \u26A1 BASIS | DOUBLE RENDER CYCLE `,
100
134
  STYLES.headerBlue
101
135
  );
102
136
  console.log(`%c\u{1F4CD} Location: %c${target.file}`, STYLES.bold, STYLES.location);
103
137
  console.log(
104
- `%cFlow:%c %c${source.name}%c \u2794 Effect \u2794 %c${target.name}%c`,
138
+ `%cThe Rhythm:%c %c${source.name}%c pulses, then %c${target.name}%c pulses one frame later.`,
105
139
  STYLES.bold,
106
140
  "",
107
141
  STYLES.label,
@@ -110,78 +144,112 @@ var displayCausalHint = (targetLabel, sourceLabel, method = "math") => {
110
144
  ""
111
145
  );
112
146
  console.log(
113
- `%cContext:%c ${method === "math" ? "The engine detected a consistent 20ms lag between these updates." : "This was caught during React effect execution."}
114
- %cResult:%c This creates a %cDouble Render Cycle%c.`,
147
+ `%cThe Impact:%c You are forcing %c2 render passes%c for a single logical change.`,
115
148
  STYLES.bold,
116
149
  "",
150
+ STYLES.impact,
151
+ ""
152
+ );
153
+ console.log(
154
+ `%cRecommended Fix:%c Remove the useEffect. Calculate %c${target.name}%c as a derived value or projection.`,
117
155
  STYLES.bold,
118
156
  "",
119
- "color: #d63031; font-weight: bold;",
157
+ STYLES.actionDelete,
120
158
  ""
121
159
  );
122
160
  console.groupEnd();
123
161
  };
124
- var displayInfiniteLoop = (label) => {
162
+ var displayViolentBreaker = (label, count, threshold) => {
125
163
  if (!isWeb) return;
126
- const info = parseLabel(label);
127
- console.group(`%c \u{1F6D1} BASIS CRITICAL | CIRCUIT BREAKER `, STYLES.headerRed);
128
- console.error(`Infinite oscillation on: %c${info.name}%c`, "color: white; background: #d63031; padding: 2px 4px;", "");
164
+ const parts = label.split(" -> ");
165
+ console.group(
166
+ `%c \u26A0\uFE0F CRITICAL SYSTEM ALERT | BASIS ENGINE `,
167
+ "background: #dc2626; color: white; font-weight: bold; padding: 8px 16px; font-size: 14px;"
168
+ );
169
+ console.error(
170
+ `%c\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`,
171
+ "color: #dc2626; font-weight: bold;"
172
+ );
173
+ console.error(
174
+ `%cINFINITE LOOP DETECTED
175
+
176
+ %cVariable: %c${parts[1] || label}
177
+ %cUpdate Frequency: %c${count} updates/sec
178
+ %cExpected Maximum: %c${threshold} updates
179
+
180
+ %c\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501`,
181
+ "color: #dc2626; font-size: 16px; font-weight: bold;",
182
+ "color: #71717a; font-weight: bold;",
183
+ `color: white; background: #dc2626; padding: 2px 8px;`,
184
+ "color: #71717a; font-weight: bold;",
185
+ `color: #fbbf24; font-weight: bold;`,
186
+ "color: #71717a; font-weight: bold;",
187
+ `color: #fbbf24; font-weight: bold;`,
188
+ "color: #dc2626; font-weight: bold;"
189
+ );
190
+ console.log(
191
+ `%cDIAGNOSTICS:
192
+ 1. Check for setState inside the render body.
193
+ 2. Verify useEffect dependencies (missing or unstable refs).
194
+ 3. Look for circular chains (State A -> B -> A).
195
+
196
+ %cSYSTEM ACTION: Update BLOCKED. Fix your code to resume monitoring.`,
197
+ "color: #71717a;",
198
+ "color: #dc2626; font-weight: bold;"
199
+ );
129
200
  console.groupEnd();
130
201
  };
131
- var displayHealthReport = (history2, similarityFn, threshold) => {
202
+ var displayHealthReport = (history2, threshold) => {
132
203
  const entries = Array.from(history2.entries());
133
204
  const totalVars = entries.length;
134
205
  if (totalVars === 0) return;
135
206
  const clusters = [];
136
207
  const processed = /* @__PURE__ */ new Set();
137
208
  let independentCount = 0;
138
- entries.forEach(([labelA, vecA]) => {
209
+ entries.forEach(([labelA, metaA]) => {
139
210
  if (processed.has(labelA)) return;
140
211
  const currentCluster = [labelA];
141
212
  processed.add(labelA);
142
- entries.forEach(([labelB, vecB]) => {
213
+ entries.forEach(([labelB, metaB]) => {
143
214
  if (labelA === labelB || processed.has(labelB)) return;
144
- const sim = similarityFn(vecA, vecB);
215
+ const sim = calculateCosineSimilarity(metaA.buffer, metaB.buffer);
145
216
  if (sim > threshold) {
146
217
  currentCluster.push(labelB);
147
218
  processed.add(labelB);
148
219
  }
149
220
  });
150
- if (currentCluster.length > 1) {
151
- clusters.push(currentCluster);
152
- } else {
153
- independentCount++;
154
- }
221
+ if (currentCluster.length > 1) clusters.push(currentCluster);
222
+ else independentCount++;
155
223
  });
156
224
  const systemRank = independentCount + clusters.length;
157
225
  const healthScore = systemRank / totalVars * 100;
158
226
  if (isWeb) {
159
227
  console.group(`%c \u{1F4CA} BASIS | ARCHITECTURAL HEALTH REPORT `, STYLES.headerGreen);
160
228
  console.log(
161
- `%cArchitectural Health Score: %c${healthScore.toFixed(1)}% %c(State Distribution: ${systemRank}/${totalVars})`,
229
+ `%cSystem Efficiency: %c${healthScore.toFixed(1)}% %c(Basis Vectors: ${systemRank} / Total Hooks: ${totalVars})`,
162
230
  STYLES.bold,
163
231
  `color: ${healthScore > 85 ? "#00b894" : "#d63031"}; font-size: 16px; font-weight: bold;`,
164
232
  "color: #636e72; font-style: italic;"
165
233
  );
166
234
  if (clusters.length > 0) {
167
- console.log(`%cDetected ${clusters.length} Synchronized Update Clusters:`, "font-weight: bold; color: #e17055; margin-top: 10px;");
235
+ console.log(`%cDetected ${clusters.length} Entangled Clusters:`, "font-weight: bold; color: #e17055; margin-top: 10px;");
168
236
  clusters.forEach((cluster, idx) => {
169
237
  const names = cluster.map((l) => parseLabel(l).name).join(" \u27F7 ");
170
238
  console.log(` %c${idx + 1}%c ${names}`, "background: #e17055; color: white; border-radius: 50%; padding: 0 5px;", "font-family: monospace;");
171
239
  });
172
- console.log("%c\u{1F4A1} Action: Variables in a cluster move together. Try refactoring them into a single state object or use useMemo for derived values.", STYLES.subText);
240
+ console.log("%c\u{1F4A1} Analysis: These variables are mirrored. Storing them separately creates unnecessary work for React.", STYLES.subText);
173
241
  } else {
174
- console.log("%c\u2728 All state variables have optimal distribution. Your Basis is healthy.", "color: #00b894; font-weight: bold; margin-top: 10px;");
242
+ console.log("%c\u2728 All state variables are independent. Your architectural Basis is healthy.", "color: #00b894; font-weight: bold; margin-top: 10px;");
175
243
  }
176
- if (totalVars > 0 && totalVars < 15) {
244
+ if (totalVars > 0 && totalVars < 20) {
177
245
  console.groupCollapsed("%cView Full Correlation Matrix", "color: #636e72; font-size: 11px;");
178
246
  const matrix = {};
179
- entries.forEach(([labelA]) => {
247
+ entries.forEach(([labelA, metaA]) => {
180
248
  const nameA = parseLabel(labelA).name;
181
249
  matrix[nameA] = {};
182
- entries.forEach(([labelB]) => {
250
+ entries.forEach(([labelB, metaB]) => {
183
251
  const nameB = parseLabel(labelB).name;
184
- const sim = similarityFn(history2.get(labelA), history2.get(labelB));
252
+ const sim = calculateCosineSimilarity(metaA.buffer, metaB.buffer);
185
253
  matrix[nameA][nameB] = sim > threshold ? `\u274C ${(sim * 100).toFixed(0)}%` : `\u2705`;
186
254
  });
187
255
  });
@@ -189,183 +257,185 @@ var displayHealthReport = (history2, similarityFn, threshold) => {
189
257
  console.groupEnd();
190
258
  }
191
259
  console.groupEnd();
192
- } else {
193
- console.log(`[BASIS HEALTH] Score: ${healthScore.toFixed(1)}% (State Distribution: ${systemRank}/${totalVars})`);
194
260
  }
195
261
  };
196
262
 
197
- // src/core/math.ts
198
- var calculateSimilarityWithOffset = (A, B, offsetA, offsetB, length) => {
199
- let dot = 0;
200
- let magA = 0;
201
- let magB = 0;
202
- for (let i = 0; i < length; i++) {
203
- const valA = A[i + offsetA];
204
- const valB = B[i + offsetB];
205
- dot += valA * valB;
206
- magA += valA * valA;
207
- magB += valB * valB;
208
- }
209
- if (magA === 0 || magB === 0) return 0;
210
- return dot / (Math.sqrt(magA) * Math.sqrt(magB));
211
- };
212
- var calculateCosineSimilarity = (A, B) => {
213
- return calculateSimilarityWithOffset(A, B, 0, 0, A.length);
214
- };
215
-
216
263
  // src/core/constants.ts
217
264
  var WINDOW_SIZE = 50;
218
265
  var SIMILARITY_THRESHOLD = 0.88;
219
266
  var LOOP_THRESHOLD = 150;
220
- var LOOP_WINDOW_MS = 1e3;
221
267
  var ANALYSIS_INTERVAL = 5;
222
268
  var VOLATILITY_THRESHOLD = 25;
223
269
 
224
270
  // src/engine.ts
225
- var GLOBAL_KEY = "__BASIS_ENGINE_INSTANCE__";
271
+ var BASIS_INSTANCE_KEY = /* @__PURE__ */ Symbol.for("__basis_engine_instance__");
226
272
  var getGlobalInstance = () => {
227
- const g = typeof window !== "undefined" ? window : global;
228
- if (!g[GLOBAL_KEY]) {
229
- g[GLOBAL_KEY] = {
273
+ const root = globalThis;
274
+ if (!root[BASIS_INSTANCE_KEY]) {
275
+ root[BASIS_INSTANCE_KEY] = {
230
276
  config: { debug: false },
231
277
  history: /* @__PURE__ */ new Map(),
232
278
  currentTickBatch: /* @__PURE__ */ new Set(),
233
279
  redundantLabels: /* @__PURE__ */ new Set(),
234
280
  booted: false,
235
- updateLog: [],
236
281
  tick: 0,
237
282
  isBatching: false,
238
- currentEffectSource: null
283
+ currentEffectSource: null,
284
+ pausedVariables: /* @__PURE__ */ new Set(),
285
+ metrics: { lastAnalysisTimeMs: 0, comparisonCount: 0, lastAnalysisTimestamp: 0 },
286
+ alertCount: 0,
287
+ loopCounters: /* @__PURE__ */ new Map(),
288
+ lastCleanup: Date.now()
239
289
  };
240
290
  }
241
- return g[GLOBAL_KEY];
291
+ return root[BASIS_INSTANCE_KEY];
242
292
  };
243
293
  var instance = getGlobalInstance();
244
- var config = instance.config;
245
- var history = instance.history;
246
- var currentTickBatch = instance.currentTickBatch;
247
- var redundantLabels = instance.redundantLabels;
248
- var configureBasis = (newConfig) => {
249
- Object.assign(instance.config, newConfig);
250
- if (instance.config.debug && !instance.booted) {
251
- displayBootLog(WINDOW_SIZE);
252
- instance.booted = true;
253
- }
254
- };
255
- var getTemporalSimilarity = (vecA, vecB) => {
256
- const L = vecA.length;
257
- const sync = calculateSimilarityWithOffset(vecA, vecB, 0, 0, L);
258
- const bFollowsA = calculateSimilarityWithOffset(vecA, vecB, 0, 1, L - 1);
259
- const aFollowsB = calculateSimilarityWithOffset(vecA, vecB, 1, 0, L - 1);
260
- return { sync, bFollowsA, aFollowsB };
261
- };
262
- var getPulseDensity = (vec) => {
263
- let sum = 0;
264
- for (let i = 0; i < vec.length; i++) sum += vec[i];
265
- return sum;
266
- };
294
+ var { config, history, redundantLabels, currentTickBatch } = instance;
295
+ var currentTickRegistry = {};
296
+ var dirtyLabels = /* @__PURE__ */ new Set();
267
297
  var analyzeBasis = () => {
268
298
  if (!instance.config.debug) {
269
299
  instance.redundantLabels.clear();
270
300
  return;
271
301
  }
272
- const entries = Array.from(instance.history.entries()).map(([label, vec]) => ({
273
- label,
274
- vec,
275
- density: getPulseDensity(vec)
276
- })).filter((e) => e.density >= 2);
277
- if (entries.length < 2) return;
278
- const newRedundant = /* @__PURE__ */ new Set();
279
- for (let i = 0; i < entries.length; i++) {
280
- for (let j = i + 1; j < entries.length; j++) {
281
- const entryA = entries[i];
282
- const entryB = entries[j];
283
- const { sync, bFollowsA, aFollowsB } = getTemporalSimilarity(entryA.vec, entryB.vec);
284
- const maxSim = Math.max(sync, bFollowsA, aFollowsB);
285
- if (maxSim > SIMILARITY_THRESHOLD) {
286
- const isBothVolatile = entryA.density > VOLATILITY_THRESHOLD && entryB.density > VOLATILITY_THRESHOLD;
287
- if (sync === maxSim) {
288
- if (!isBothVolatile) {
289
- newRedundant.add(entryA.label);
290
- newRedundant.add(entryB.label);
291
- displayRedundancyAlert(entryA.label, entryB.label, sync);
292
- }
293
- } else if (bFollowsA === maxSim) {
294
- displayCausalHint(entryB.label, entryA.label, "math");
295
- } else if (aFollowsB === maxSim) {
296
- displayCausalHint(entryA.label, entryB.label, "math");
302
+ const scheduler = globalThis.requestIdleCallback || ((cb) => setTimeout(cb, 1));
303
+ scheduler(() => {
304
+ const analysisStart = performance.now();
305
+ if (dirtyLabels.size === 0) return;
306
+ const allEntries = [];
307
+ const dirtyEntries = [];
308
+ instance.history.forEach((meta, label) => {
309
+ if (meta.options.suppressAll) return;
310
+ let density = 0;
311
+ for (let k = 0; k < meta.buffer.length; k++) density += meta.buffer[k];
312
+ if (density >= 2) {
313
+ const entry = { label, meta, density };
314
+ allEntries.push(entry);
315
+ if (dirtyLabels.has(label)) dirtyEntries.push(entry);
316
+ }
317
+ });
318
+ if (dirtyEntries.length === 0 || allEntries.length < 2) {
319
+ dirtyLabels.clear();
320
+ return;
321
+ }
322
+ const nextRedundant = /* @__PURE__ */ new Set();
323
+ let compCount = 0;
324
+ instance.redundantLabels.forEach((l) => {
325
+ if (!dirtyLabels.has(l)) nextRedundant.add(l);
326
+ });
327
+ for (const dirtyEntry of dirtyEntries) {
328
+ for (const otherEntry of allEntries) {
329
+ if (dirtyEntry.label === otherEntry.label) continue;
330
+ if (dirtyLabels.has(otherEntry.label) && dirtyEntry.label > otherEntry.label) continue;
331
+ compCount++;
332
+ const sync = calculateSimilarityCircular(dirtyEntry.meta.buffer, dirtyEntry.meta.head, otherEntry.meta.buffer, otherEntry.meta.head, 0);
333
+ const bA = calculateSimilarityCircular(dirtyEntry.meta.buffer, dirtyEntry.meta.head, otherEntry.meta.buffer, otherEntry.meta.head, 1);
334
+ const aB = calculateSimilarityCircular(dirtyEntry.meta.buffer, dirtyEntry.meta.head, otherEntry.meta.buffer, otherEntry.meta.head, -1);
335
+ const maxSim = Math.max(sync, bA, aB);
336
+ if (maxSim > SIMILARITY_THRESHOLD) {
337
+ const bothVolatile = dirtyEntry.density > VOLATILITY_THRESHOLD && otherEntry.density > VOLATILITY_THRESHOLD;
338
+ if (sync === maxSim && !bothVolatile) {
339
+ nextRedundant.add(dirtyEntry.label);
340
+ nextRedundant.add(otherEntry.label);
341
+ displayRedundancyAlert(dirtyEntry.label, otherEntry.label, sync);
342
+ } else if (bA === maxSim) displayCausalHint(otherEntry.label, dirtyEntry.label, "math");
343
+ else if (aB === maxSim) displayCausalHint(dirtyEntry.label, otherEntry.label, "math");
297
344
  }
298
345
  }
299
346
  }
300
- }
301
- instance.redundantLabels.clear();
302
- newRedundant.forEach((label) => instance.redundantLabels.add(label));
347
+ dirtyLabels.clear();
348
+ instance.redundantLabels.clear();
349
+ nextRedundant.forEach((l) => instance.redundantLabels.add(l));
350
+ instance.metrics.lastAnalysisTimeMs = performance.now() - analysisStart;
351
+ instance.metrics.comparisonCount = compCount;
352
+ instance.metrics.lastAnalysisTimestamp = Date.now();
353
+ });
354
+ };
355
+ var processHeartbeat = () => {
356
+ instance.tick++;
357
+ instance.history.forEach((meta, label) => {
358
+ meta.buffer[meta.head] = instance.currentTickBatch.has(label) ? 1 : 0;
359
+ meta.head = (meta.head + 1) % WINDOW_SIZE;
360
+ });
361
+ instance.currentTickBatch.clear();
362
+ currentTickRegistry = {};
363
+ instance.isBatching = false;
364
+ if (instance.tick % ANALYSIS_INTERVAL === 0) analyzeBasis();
303
365
  };
304
366
  var recordUpdate = (label) => {
305
367
  if (!instance.config.debug) return true;
368
+ if (instance.pausedVariables.has(label)) return false;
306
369
  const now = Date.now();
307
- instance.updateLog.push({ label, ts: now });
308
- if (instance.updateLog.length > 200) {
309
- instance.updateLog = instance.updateLog.filter((e) => now - e.ts < LOOP_WINDOW_MS);
370
+ if (now - instance.lastCleanup > 1e3) {
371
+ instance.loopCounters.clear();
372
+ instance.lastCleanup = now;
310
373
  }
311
- const updateCount = instance.updateLog.filter((e) => e.label === label).length;
312
- if (updateCount > LOOP_THRESHOLD) {
313
- displayInfiniteLoop(label);
374
+ const count = (instance.loopCounters.get(label) || 0) + 1;
375
+ instance.loopCounters.set(label, count);
376
+ if (count > LOOP_THRESHOLD) {
377
+ displayViolentBreaker(label, count, LOOP_THRESHOLD);
378
+ instance.pausedVariables.add(label);
314
379
  return false;
315
380
  }
316
381
  if (instance.currentEffectSource && instance.currentEffectSource !== label) {
317
382
  displayCausalHint(label, instance.currentEffectSource, "tracking");
318
383
  }
384
+ if (currentTickRegistry[label]) return true;
385
+ currentTickRegistry[label] = true;
319
386
  instance.currentTickBatch.add(label);
387
+ dirtyLabels.add(label);
320
388
  if (!instance.isBatching) {
321
389
  instance.isBatching = true;
322
- setTimeout(() => {
323
- instance.tick++;
324
- instance.history.forEach((vec, l) => {
325
- vec.shift();
326
- vec.push(instance.currentTickBatch.has(l) ? 1 : 0);
327
- });
328
- instance.currentTickBatch.clear();
329
- instance.isBatching = false;
330
- if (instance.tick % ANALYSIS_INTERVAL === 0) {
331
- analyzeBasis();
332
- }
333
- }, 20);
390
+ requestAnimationFrame(processHeartbeat);
334
391
  }
335
392
  return true;
336
393
  };
337
- var beginEffectTracking = (label) => {
338
- if (instance.config.debug) instance.currentEffectSource = label;
339
- };
340
- var endEffectTracking = () => {
341
- instance.currentEffectSource = null;
394
+ var configureBasis = (c) => {
395
+ Object.assign(instance.config, c);
396
+ if (instance.config.debug && !instance.booted) {
397
+ displayBootLog(WINDOW_SIZE);
398
+ instance.booted = true;
399
+ }
342
400
  };
343
- var registerVariable = (label) => {
344
- if (!instance.config.debug) return;
345
- if (!instance.history.has(label)) {
346
- instance.history.set(label, new Array(WINDOW_SIZE).fill(0));
401
+ var registerVariable = (l, o = {}) => {
402
+ if (!instance.config.debug || o.suppressAll) return;
403
+ if (!instance.history.has(l)) {
404
+ instance.history.set(l, { buffer: new Uint8Array(WINDOW_SIZE), head: 0, options: o });
347
405
  }
348
406
  };
349
- var unregisterVariable = (label) => {
350
- instance.history.delete(label);
407
+ var unregisterVariable = (l) => {
408
+ instance.history.delete(l);
409
+ };
410
+ var beginEffectTracking = (l) => {
411
+ if (instance.config.debug) instance.currentEffectSource = l;
412
+ };
413
+ var endEffectTracking = () => {
414
+ instance.currentEffectSource = null;
351
415
  };
352
416
  var printBasisHealthReport = (threshold = 0.5) => {
353
417
  if (!instance.config.debug) {
354
418
  console.warn("[Basis] Cannot generate report. Debug mode is OFF.");
355
419
  return;
356
420
  }
357
- displayHealthReport(instance.history, calculateCosineSimilarity, threshold);
421
+ displayHealthReport(instance.history, threshold);
358
422
  };
423
+ var getBasisMetrics = () => ({
424
+ engine: "v0.4.2 (Ring Buffer)",
425
+ hooks: instance.history.size,
426
+ load: instance.metrics.comparisonCount,
427
+ analysis_ms: instance.metrics.lastAnalysisTimeMs.toFixed(3)
428
+ });
359
429
  if (typeof window !== "undefined") {
360
430
  window.printBasisReport = printBasisHealthReport;
431
+ window.getBasisMetrics = getBasisMetrics;
361
432
  }
362
433
  var __testEngine__ = {
363
434
  instance,
364
- config: instance.config,
365
435
  history: instance.history,
366
- currentTickBatch: instance.currentTickBatch,
367
436
  configureBasis,
368
437
  registerVariable,
438
+ unregisterVariable,
369
439
  recordUpdate,
370
440
  printBasisHealthReport,
371
441
  beginEffectTracking,
@@ -380,7 +450,9 @@ function useState(initialState, label) {
380
450
  const effectiveLabel = reactUseRef(label || getFallbackLabel("state")).current;
381
451
  reactUseEffect(() => {
382
452
  registerVariable(effectiveLabel);
383
- return () => unregisterVariable(effectiveLabel);
453
+ return () => {
454
+ unregisterVariable(effectiveLabel);
455
+ };
384
456
  }, [effectiveLabel]);
385
457
  const setter = reactUseCallback((newValue) => {
386
458
  if (recordUpdate(effectiveLabel)) {
@@ -403,7 +475,9 @@ function useReducer(reducer, initialArg, init, label) {
403
475
  );
404
476
  reactUseEffect(() => {
405
477
  registerVariable(effectiveLabel);
406
- return () => unregisterVariable(effectiveLabel);
478
+ return () => {
479
+ unregisterVariable(effectiveLabel);
480
+ };
407
481
  }, [effectiveLabel]);
408
482
  const basisDispatch = reactUseCallback((action) => {
409
483
  if (recordUpdate(effectiveLabel)) {
@@ -475,7 +549,9 @@ function useOptimistic2(passthrough, reducer, label) {
475
549
  const effectiveLabel = label || "anonymous_optimistic";
476
550
  reactUseEffect(() => {
477
551
  registerVariable(effectiveLabel);
478
- return () => unregisterVariable(effectiveLabel);
552
+ return () => {
553
+ unregisterVariable(effectiveLabel);
554
+ };
479
555
  }, [effectiveLabel]);
480
556
  const [state, reactAddOptimistic] = React.useOptimistic(passthrough, reducer);
481
557
  const addOptimistic = reactUseCallback((payload) => {
@@ -496,7 +572,9 @@ function useActionState2(action, initialState, permalink, label) {
496
572
  );
497
573
  reactUseEffect(() => {
498
574
  registerVariable(effectiveLabel);
499
- return () => unregisterVariable(effectiveLabel);
575
+ return () => {
576
+ unregisterVariable(effectiveLabel);
577
+ };
500
578
  }, [effectiveLabel]);
501
579
  const basisDispatch = reactUseCallback((payload) => {
502
580
  if (recordUpdate(effectiveLabel)) {
@@ -557,7 +635,9 @@ var BasisHUD = () => {
557
635
  useEffect2(() => {
558
636
  if (!isExpanded) return;
559
637
  let animationFrame;
638
+ let isMounted = true;
560
639
  const draw = () => {
640
+ if (!isMounted) return;
561
641
  const canvas = canvasRef.current;
562
642
  if (!canvas) return;
563
643
  const ctx = canvas.getContext("2d");
@@ -579,7 +659,10 @@ var BasisHUD = () => {
579
659
  animationFrame = requestAnimationFrame(draw);
580
660
  };
581
661
  draw();
582
- return () => cancelAnimationFrame(animationFrame);
662
+ return () => {
663
+ isMounted = false;
664
+ cancelAnimationFrame(animationFrame);
665
+ };
583
666
  }, [isExpanded]);
584
667
  return /* @__PURE__ */ jsxs("div", { style: getHUDContainerStyle(isExpanded), onClick: () => setIsExpanded(!isExpanded), children: [
585
668
  /* @__PURE__ */ jsx(HUDHeader, { isExpanded }),
@@ -605,63 +688,87 @@ function renderEmptyState(ctx) {
605
688
  ctx.fillText("Waiting for state transitions...", HUD_DIMENSIONS.PADDING, 30);
606
689
  }
607
690
  function renderMatrix(ctx, entries) {
608
- entries.forEach(([label, vector], rowIndex) => {
609
- const y = rowIndex * HUD_DIMENSIONS.ROW_HEIGHT + HUD_DIMENSIONS.PADDING;
610
- const stateName = label.split(" -> ")[1] || label;
611
- const density = vector.reduce((acc, bit) => acc + bit, 0);
612
- const isVolatile = density > 25;
691
+ const L = HUD_DIMENSIONS.WINDOW_SIZE;
692
+ const colW = HUD_DIMENSIONS.COL_WIDTH;
693
+ const rowH = HUD_DIMENSIONS.ROW_HEIGHT;
694
+ const pad = HUD_DIMENSIONS.PADDING;
695
+ const cellW = colW - 1.5;
696
+ const cellH = rowH - 4;
697
+ const gridPath = new Path2D();
698
+ const successPath = new Path2D();
699
+ const errorPath = new Path2D();
700
+ ctx.font = "11px Inter, Menlo, monospace";
701
+ let rowIndex = 0;
702
+ for (const [label, meta] of entries) {
703
+ const y = rowIndex * rowH + pad;
613
704
  const isRedundant = redundantLabels.has(label);
614
- vector.forEach((bit, colIndex) => {
615
- const x = colIndex * HUD_DIMENSIONS.COL_WIDTH + HUD_DIMENSIONS.PADDING;
616
- ctx.fillStyle = bit === 1 ? isRedundant ? HUD_THEME.error : HUD_THEME.success : HUD_THEME.grid;
617
- const w = HUD_DIMENSIONS.COL_WIDTH - 1.5;
618
- const h = HUD_DIMENSIONS.ROW_HEIGHT - 4;
619
- if (ctx.roundRect) {
620
- ctx.beginPath();
621
- ctx.roundRect(x, y, w, h, HUD_DIMENSIONS.RADIUS);
622
- ctx.fill();
705
+ const { buffer, head } = meta;
706
+ let uiPos = 0;
707
+ const addToPath = (val, xIdx) => {
708
+ const x = xIdx * colW + pad;
709
+ if (val === 1) {
710
+ (isRedundant ? errorPath : successPath).rect(x, y, cellW, cellH);
623
711
  } else {
624
- ctx.fillRect(x, y, w, h);
712
+ gridPath.rect(x, y, cellW, cellH);
625
713
  }
626
- });
627
- const textX = HUD_DIMENSIONS.WINDOW_SIZE * HUD_DIMENSIONS.COL_WIDTH + HUD_DIMENSIONS.PADDING + 10;
714
+ };
715
+ for (let i = head; i < L; i++) addToPath(buffer[i], uiPos++);
716
+ for (let i = 0; i < head; i++) addToPath(buffer[i], uiPos++);
717
+ const stateName = label.split(" -> ")[1] || label;
718
+ const textX = L * colW + pad + 10;
719
+ let density = 0;
720
+ for (let i = 0; i < L; i++) density += buffer[i];
721
+ const isVolatile = density > 25;
628
722
  ctx.fillStyle = isRedundant ? HUD_THEME.error : isVolatile ? HUD_THEME.success : HUD_THEME.text;
629
- ctx.font = `${isRedundant || isVolatile ? "600" : "400"} 11px Inter, Menlo, monospace`;
630
- let prefix = "";
631
- if (isRedundant) prefix = "! ";
632
- else if (isVolatile) prefix = "~ ";
633
- const cleanName = prefix + stateName;
634
- const truncatedName = cleanName.length > 18 ? cleanName.substring(0, 16) + ".." : cleanName;
635
- ctx.fillText(truncatedName, textX, y + 9);
636
- });
723
+ ctx.fillText((isRedundant ? "! " : isVolatile ? "~ " : "") + stateName, textX, y + 9);
724
+ rowIndex++;
725
+ }
726
+ ctx.fillStyle = HUD_THEME.grid;
727
+ ctx.fill(gridPath);
728
+ ctx.fillStyle = HUD_THEME.success;
729
+ ctx.fill(successPath);
730
+ ctx.fillStyle = HUD_THEME.error;
731
+ ctx.fill(errorPath);
637
732
  }
638
- var HUDHeader = ({ isExpanded }) => /* @__PURE__ */ jsxs("div", { style: {
639
- padding: "10px 14px",
640
- backgroundColor: isExpanded ? HUD_THEME.header : "transparent",
641
- color: isExpanded ? "white" : HUD_THEME.header,
642
- fontWeight: 600,
643
- fontSize: "11px",
644
- letterSpacing: "0.05em",
645
- display: "flex",
646
- justifyContent: "space-between",
647
- alignItems: "center",
648
- transition: "background 0.3s"
649
- }, children: [
650
- /* @__PURE__ */ jsx("span", { children: isExpanded ? "STATE BASIS MATRIX" : "\u{1F4D0} BASIS ACTIVE" }),
651
- isExpanded && /* @__PURE__ */ jsx("span", { style: { opacity: 0.8, fontSize: "9px" }, children: "R50" })
652
- ] });
653
- var HUDFooter = () => /* @__PURE__ */ jsxs("div", { style: {
654
- marginTop: "12px",
655
- paddingTop: "8px",
656
- borderTop: `1px solid ${HUD_THEME.grid}`,
657
- color: HUD_THEME.textDim,
658
- fontSize: "9px",
659
- display: "flex",
660
- justifyContent: "space-between"
661
- }, children: [
662
- /* @__PURE__ */ jsx("span", { children: "LINEAR DEPENDENCY AUDIT" }),
663
- /* @__PURE__ */ jsx("span", { children: "THRESHOLD 0.88" })
664
- ] });
733
+ var HUDHeader = ({ isExpanded }) => /* @__PURE__ */ jsxs(
734
+ "div",
735
+ {
736
+ style: {
737
+ padding: "10px 14px",
738
+ backgroundColor: isExpanded ? HUD_THEME.header : "transparent",
739
+ color: isExpanded ? "white" : HUD_THEME.header,
740
+ fontWeight: 600,
741
+ fontSize: "11px",
742
+ letterSpacing: "0.05em",
743
+ display: "flex",
744
+ justifyContent: "space-between",
745
+ alignItems: "center",
746
+ transition: "background 0.3s"
747
+ },
748
+ children: [
749
+ /* @__PURE__ */ jsx("span", { children: isExpanded ? "STATE BASIS MATRIX" : "\u{1F4D0} BASIS ACTIVE" }),
750
+ isExpanded && /* @__PURE__ */ jsx("span", { style: { opacity: 0.8, fontSize: "9px" }, children: "v0.4.2" })
751
+ ]
752
+ }
753
+ );
754
+ var HUDFooter = () => /* @__PURE__ */ jsxs(
755
+ "div",
756
+ {
757
+ style: {
758
+ marginTop: "12px",
759
+ paddingTop: "8px",
760
+ borderTop: `1px solid ${HUD_THEME.grid}`,
761
+ color: HUD_THEME.textDim,
762
+ fontSize: "9px",
763
+ display: "flex",
764
+ justifyContent: "space-between"
765
+ },
766
+ children: [
767
+ /* @__PURE__ */ jsx("span", { children: "RING BUFFER ENGINE" }),
768
+ /* @__PURE__ */ jsx("span", { children: "ZERO ALLOC" })
769
+ ]
770
+ }
771
+ );
665
772
 
666
773
  // src/context.tsx
667
774
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
@@ -684,6 +791,7 @@ export {
684
791
  BasisProvider,
685
792
  basis,
686
793
  configureBasis,
794
+ getBasisMetrics,
687
795
  printBasisHealthReport,
688
796
  use,
689
797
  useActionState2 as useActionState,