State Absorber: The Key Component
The State Absorber overwrites instead of queues. This single design choice guarantees both memory stability and temporal consistency.Position in Pipeline
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ STATE ABSORBER: THE BRIDGE ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ PTY Daemon ──▶ Actor ──▶ GridWorker ──▶ [State Absorber] ║
║ │ ║
║ ▼ ║
║ ACK Gate ──▶ Frontend ║
║ ║
║ ───────────────────────────────────────────────────────────────── ║
║ ║
║ ABSORBER ROLE: ║
║ ║
║ • Receives ALL data (every PTY update) ║
║ • Stores CURRENT state only ║
║ • Never blocks upstream ║
║ • Fixed memory footprint ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
Without vs With State Absorber
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ WITHOUT STATE ABSORBER ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ PTY (1000/sec) ──▶ Actor ──▶ Queue ──▶ ACK (60/sec) ──▶ Frontend ║
║ │ ║
║ └── Queue grows: 940 items/sec ║
║ Memory grows indefinitely ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
╔═════════════════════════════════════════════════════════════════════╗
║ WITH STATE ABSORBER ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ PTY (1000/sec) ──▶ Actor ──▶ Absorber ──▶ ACK (60/sec) ║
║ │ ║
║ └── Always ONE state, overwrites ║
║ Memory fixed ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
Overwrite vs Queue
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ QUEUE APPROACH (Traditional) ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ Input: S1 ──▶ S2 ──▶ S3 ──▶ S4 ──▶ S5 ──▶ ... ──▶ S10 ║
║ ║
║ Queue: [S1][S2][S3][S4][S5]...[S10] ◀── ALL states kept ║
║ ║
║ Output: S1 ──▶ S2 ──▶ S3 ──▶ ... (one at a time) ║
║ ║
║ Memory: Grows with queue depth (unbounded) ║
║ Time: User sees OLD states (queue backlog) ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
╔═════════════════════════════════════════════════════════════════════╗
║ OVERWRITE APPROACH (State Absorber) ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ Input: S1 ──▶ S2 ──▶ S3 ──▶ S4 ──▶ S5 ──▶ ... ──▶ S10 ║
║ │ │ │ │ │ │ ║
║ ▼ ▼ ▼ ▼ ▼ ▼ ║
║ ║
║ State: [S1] ║
║ [S2] ◀── overwrites S1 ║
║ [S3] ◀── overwrites S2 ║
║ ... ║
║ [S10] ◀── only CURRENT state exists ║
║ ║
║ Output: S10 (when ACK allows) ║
║ ║
║ Memory: Fixed (viewport size only) ║
║ Time: User sees CURRENT state (no backlog) ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
Key Difference
| Approach | Philosophy |
|---|---|
| Queue | ”Remember everything, show in order” |
| Overwrite | ”Remember current, show current” |
Memory Comparison
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ MEMORY USAGE: QUEUE vs ABSORBER ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ Typical Terminal: 120 cols x 40 rows = 4,800 cells ║
║ Cell size: ~17 bytes (char + colors + flags) ║
║ Viewport memory: 4,800 x 17 = ~80KB ║
║ ║
║ ───────────────────────────────────────────────────────────────── ║
║ ║
║ Queue-Based (1 minute of AI output): ║
║ • 1000 states/sec x 60 sec = 60,000 states queued ║
║ • 60,000 x 80KB = 4.8GB memory ║
║ ║
║ State Absorber (same scenario): ║
║ • 1 state (current) ║
║ • 1 x 80KB = 80KB memory ║
║ ║
║ Difference: 60,000x less memory ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
Memory Control Across Pipeline
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ WHERE MEMORY IS CONTROLLED ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ LAYER 1: PTY DAEMON ║
║ ───────────────────────────────────────────────────────────────── ║
║ Memory Control: Unix Socket backpressure ║
║ • Kernel ~208KB limit ║
║ • When socket full, write() blocks ║
║ • Rarely triggered (Tauri keeps reading) ║
║ Growth: Theoretically yes, practically no ║
║ ║
║ LAYER 2: TAURI BACKEND ║
║ ───────────────────────────────────────────────────────────────── ║
║ Memory Control: State Absorber OVERWRITE ║
║ • Grid: Fixed (rows x cols x cell_size) ║
║ • New data overwrites old ║
║ • No accumulation possible ║
║ Growth: IMPOSSIBLE ║
║ ║
║ LAYER 3: FRONTEND ║
║ ───────────────────────────────────────────────────────────────── ║
║ Memory Control: ACK rate limiting ║
║ • Receives max 60 states/sec (ACK-gated) ║
║ • Each state overwrites in xterm.js ║
║ • No event queue buildup ║
║ Growth: IMPOSSIBLE (ACK prevents overflow) ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
Pipeline Never Blocks
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ SCENARIO: Renderer is slow (waiting for ACK) ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ T=0ms PTY: output "Line 1" ║
║ Actor: process ──▶ GridWorker ║
║ State Absorber: store "Line 1" ║
║ ACK: waiting_ack=false ──▶ emit, waiting_ack=true ║
║ ║
║ T=5ms PTY: output "Line 2" ║
║ Actor: process ──▶ GridWorker ║
║ State Absorber: OVERWRITE with "Line 1 + Line 2" ║
║ ACK: waiting_ack=true ──▶ NO emit (absorbed) ║
║ ║
║ T=10ms PTY: output "Line 3" ║
║ Actor: process ──▶ GridWorker ║
║ State Absorber: OVERWRITE with all 3 lines ║
║ ACK: waiting_ack=true ──▶ NO emit (absorbed) ║
║ ║
║ ...PTY keeps outputting, State Absorber keeps absorbing... ║
║ ║
║ T=16ms Frontend: finished render, invoke("grid_ack") ║
║ ACK: waiting_ack=false ║
║ State Absorber: has latest state ready ║
║ ACK: emit(latest), waiting_ack=true ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
Key Observation
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ DECOUPLED PROCESSING AND RENDERING ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ • PTY NEVER waits for renderer ║
║ • Actor NEVER waits for ACK ║
║ • State Absorber ALWAYS accepts new data ║
║ • ACK ONLY controls emission, not processing ║
║ ║
║ The pipeline is DECOUPLED: ║
║ ║
║ [PTY ──▶ Actor ──▶ Absorber] ◀──▶ [ACK ──▶ Frontend] ║
║ PROCESSING RENDERING ║
║ (always fast) (may be slow) ║
║ ║
║ State Absorber is the decoupling point. ║
║ Unlike a queue, it does not grow. ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
State Coalescing (Not Data Loss)
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ IMPORTANT DISTINCTION ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ DATA LOSS: ║
║ Input bytes are dropped, never processed ║
║ Result: Missing content, corrupted output ║
║ ║
║ STATE COALESCING: ║
║ All bytes processed, intermediate STATES discarded ║
║ Result: Final content preserved, intermediate views skipped ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
Example
PTY Output: “H” -> “He” -> “Hel” -> “Hell” -> “Hello”Copy
╔═════════════════════════════════════════════════════════════════════╗
║ DATA LOSS (BAD) ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ • Process: "H", drop "e", drop "l", process "l", process "o" ║
║ • Final: "Hlo" ◀── WRONG, content corrupted ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
╔═════════════════════════════════════════════════════════════════════╗
║ STATE COALESCING (State Absorber) ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ • Process ALL: "H" ──▶ "He" ──▶ "Hel" ──▶ "Hell" ──▶ "Hello" ║
║ • Store: each state overwrites previous ║
║ • Emit: only "Hello" (when ACK allows) ║
║ • Final: "Hello" ◀── CORRECT, content preserved ║
║ ║
║ User did not see "H", "He", "Hel", "Hell" but WHO CARES? ║
║ They see "Hello" which is what matters. ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
Data Flow Verification
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ NO DATA LOSS AT ANY POINT ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ PTY bytes ──▶ Alacritty VTE Parser ──▶ Grid cells ──▶ Absorber ║
║ │ │ ║
║ │ │ ║
║ ALL bytes parsed State overwrite ║
║ (escape sequences, (only latest ║
║ UTF-8, control codes) kept) ║
║ ║
║ No data loss at any point. Only STATE coalescing. ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
The Dual Guarantee
ONE mechanism (overwrite) provides TWO guarantees:Copy
╔═════════════════════════════════════════════════════════════════════╗
║ 1. MEMORY STABILITY ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ Queue: [S1][S2][S3]...[S1000] ──▶ Memory grows ║
║ Overwrite: [S1000] ──▶ Memory fixed ║
║ ║
║ Do not accumulate ──▶ Memory does not grow ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
╔═════════════════════════════════════════════════════════════════════╗
║ 2. TEMPORAL CONSISTENCY ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ Queue: User sees S1, S2, S3... (past states) ║
║ Overwrite: User sees S1000 (current state) ║
║ ║
║ Do not accumulate ──▶ User sees present, not past ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
Visual: Memory + Time Over Duration
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ MEMORY & FRAME CONTENT ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ Scenario: 10,000 state updates, renderer at its pace ║
║ ║
║ MEMORY USAGE FRAME CONTENT ║
║ │ ║
║ │ Queue / Queue Frame: ║
║ │ / ┌─────┬─────┬─────┬─────┐ ║
║ │ / │ T=0 │ T=1 │ T=2 │ T=3 │ ║
║ │ / ├─────┼─────┼─────┼─────┤ ║
║ │ / │ S0 │ S50 │S100 │S150 │ past ║
║ │ / └─────┴─────┴─────┴─────┘ ║
║ │/ (showing old from queue) ║
║ │ ║
║ │══════════ Absorber Absorber Frame: ║
║ │ ┌─────┬─────┬─────┬─────┐ ║
║ │ │ T=0 │ T=1 │ T=2 │ T=3 │ ║
║ │ ├─────┼─────┼─────┼─────┤ ║
║ │ │ now │ now │ now │ now │ curr ║
║ └────────────────▶ Time └─────┴─────┴─────┴─────┘ ║
║ (always showing current) ║
║ ║
║ QUEUE: Memory grows + Frame shows past ║
║ ABSORBER: Memory flat + Frame shows now ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
AI-Human Concurrency
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ WHY STATE ABSORBER MATTERS FOR AI ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ Human types "ls" while AI generates output ║
║ ║
║ QUEUE (Problem): ║
║ ───────────────────────────────────────────────────────────────── ║
║ T=1s: shows AI line 50 (queue: 950 pending) ║
║ Human input: in queue! ║
║ ║
║ T=5s: shows AI line 250 (queue: 4750 pending) ║
║ Human input: still waiting! ║
║ ║
║ ──▶ User sees PAST, input feedback delayed ║
║ ║
║ ───────────────────────────────────────────────────────────────── ║
║ ║
║ ABSORBER (MonoTerm): ║
║ ───────────────────────────────────────────────────────────────── ║
║ T=1s: shows current (all coalesced) ║
║ Human input: visible! ║
║ ║
║ T=5s: shows current (still synchronized) ║
║ Human input: still visible! ║
║ ║
║ ──▶ User sees NOW, input feedback immediate ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝
Summary
Copy
╔═════════════════════════════════════════════════════════════════════╗
║ STATE ABSORBER: KEY TAKEAWAYS ║
╠═════════════════════════════════════════════════════════════════════╣
║ ║
║ 1. State Absorber OVERWRITES instead of QUEUES ║
║ 2. All data is PROCESSED, only intermediate STATES discarded ║
║ 3. Memory is FIXED regardless of output volume ║
║ 4. User always sees CURRENT state, not past ║
║ 5. Pipeline NEVER blocks (decouples processing from rendering) ║
║ ║
║ ───────────────────────────────────────────────────────────────── ║
║ ║
║ State Absorber is the KEY component: ║
║ ║
║ • Without it: Actor + ACK would need queue ──▶ memory growth ║
║ • With it: Actor processes fast, ACK controls, memory fixed ║
║ ║
║ TWO GUARANTEES from ONE mechanism: ║
║ • Memory Stability ║
║ • Temporal Consistency ║
║ ║
╚═════════════════════════════════════════════════════════════════════╝