-
Notifications
You must be signed in to change notification settings - Fork 3
State Modeling & Signal Processing
react-state-basis models React state updates as a discrete-time signal. This page covers the data structures and mathematical heuristics used to sample, store, and compare these signals.
To understand how Basis goes from identifying correlations (v0.5) to identifying root causes (v0.6), you need to know about the two mathematical spaces the engine works in at the same time. We don't throw away the signal data when we add the graph layer. We stack the topological view on top of it.
- Definition: The history of a single variable over time.
-
Dimensions: Time (
$N=50$ ticks). -
Math:
$v_{user} = [0, 1, 0, 0, 1 \dots]$ - Operation: Cosine Similarity (Dot Product).
- Purpose: Finds Relationships ("Does A move when B moves?"). This is what detects Boolean Explosion and Redundancy.
- Definition: The authority of the entire system at a specific moment.
-
Dimensions: Complexity (
$N=$ Total Nodes in Graph). - Math: v_system = [Score_event, Score_user, Score_effect, ...]
- Operation: Eigenvector Centrality (Power Iteration).
- Purpose: Finds Hierarchy ("Who triggered the chain reaction?"). This is what detects Prime Movers.
How they connect: The engine uses the Micro-Vectors (Ring Buffers) to detect causal edges. Those edges then form the Matrix that the Macro-Vector (Eigenvector) is calculated from.
Every instrumented hook (useState, useReducer, etc.) is represented as a binary vector in {0, 1}⁵⁰.
-
Dimension (
$N=50$ ): The engine keeps a sliding window of the last 50 browser frames. -
Logical High (
$1$ ): At least one state update was recorded for that variable during the frame. -
Logical Low (
$0$ ): No updates were recorded for that variable during the frame.
By focusing on the timing of transitions rather than the actual state values, the engine can spot architectural relationships with minimal CPU and memory cost.
To do mathematical correlation, async updates need to be quantized into discrete temporal buckets.
-
Heartbeat: The engine uses
requestAnimationFrame(rAF) as the sampling clock. This ties the sampling frequency to the hardware refresh rate (60Hz-144Hz) and eliminates temporal aliasing. - Quantization: One engine "Tick" = one browser paint frame.
-
Batching: Multiple updates to the same variable within a single frame get collapsed into a single pulse (
$1$ ). The engine sees the same rhythm the user sees on screen.
Basis uses a static memory model to avoid GC pressure and keep writes at
-
Storage:
Uint8Array(50). Each signal gets a pre-allocated contiguous memory block. -
Update Mechanism: A Ring Buffer with a rotating
headpointer. New data overwrites the oldest entry. -
O(1) Precise Density: Pulse density is tracked with bit-flip delta logic (
meta.density += newValue - oldValue). This avoids mathematical drift over long sessions and keeps the density calculation constant-time regardless of buffer size.
Starting in v0.5.0, signals are no longer treated as a flat list. Every signal gets an Algebraic Role so the engine can do a structural audit of the state space.
-
Local Basis (
$U$ ): Signals from local hooks (useState,useReducer). -
Global Subspace (
$W$ ): Signals from context anchors (createContext). -
The Direct Sum Model: The engine checks whether
$V \approx U \oplus W$ . This only holds if the intersection is zero:$U \cap W = {0}$ . -
What it catches: If a Local Basis vector (
$U$ ) is found inside the span of a Global Subspace ($W$ ), it gets flagged as Context Mirroring. That means you have local state shadowing a context value.
The interception logic is designed to stay invisible to the main thread during user interactions.
- Snapshot Isolation: Before an analysis pass starts, the engine does an Atomic Swap. It snapshots the "dirty" signal set and clears the live registry right away. This prevents race conditions and makes sure pulses that happen during the math pass get captured for the next frame.
-
Async Heuristics: The
$O(D \times N)$ pairwise analysis is scheduled viarequestIdleCallback. The math only runs when the browser is idle, so the frame budget stays reserved for your UI.
The engine identifies relationships by calculating Cosine Similarity across three temporal planes (
- Amortized Modulo Math: The circular offset is normalized once outside the hot loop. The inner loop then runs with just a single branch check, keeping execution typically under <1ms.
-
Synchronous Plane (
$\tau=0$ ): Detects Redundancy (updates firing in the same frame). -
Lead-Lag Planes (
$\tau=\pm 1$ ): Detects Causal Sync Leaks (one update triggering another in the next frame).
Vector analysis finds correlation. v0.6 adds Graph Theory to find causality. The engine builds a Directed Adjacency Matrix
-
Nodes (
$V$ ): State Variables, Effects, and Implicit Events. -
Edges (
$E$ ): Causal links where$u \to v$ means "u triggered v". -
Implicit Event Detection: When multiple variables update without an Effect as the source, the engine creates a virtual node (
Event_Tick_...) to represent the external trigger. This lets the graph group "Sibling" updates correctly instead of falsely flagging them as causal leaks.
To prioritize what to fix first, the engine calculates Eigenvector Centrality on the causal graph.
- Power Iteration: An iterative approximation ($O(k \cdot E)$) that calculates the "Authority Score" of every node.
- The Prime Mover: The node with the highest spectral score is the root cause of the largest cascade. This is what lets the Health Report rank issues by actual systemic impact instead of just listing them flat.
- Volatility Guard: Variables that pulse in >50% of the window (e.g. 60FPS animations) are classified as Streams. The engine suppresses causal alerts for these automatically to avoid noise.
- Conditional Independence: The topology engine filters out "Sibling Noise" ($P(A, B | Event)$). If two variables are driven by the same Global Event, they get marked as independent siblings. This prevents false "Double Render" alerts.
-
Graph Pruning: Event nodes older than the active interaction window (
$\approx 10s$ ) are garbage collected during idle ticks to prevent memory leaks in the adjacency matrix.