# Ralph Tracker Phase 1 Implementation Plan ## Overview This plan details how to enhance the existing RalphTracker with RALPH_STATUS block parsing, circuit breaker pattern, and dual-condition exit gate. --- ## 1. Current State Analysis ### What RalphTracker Already Does Well - **Todo Detection**: Supports 5 formats (checkboxes, indicators, status in parentheses, native TodoWrite, checkmark-based) - **Completion Phrases**: Detects `PHRASE` with occurrence-based logic (1st = store, 2nd = complete) - **Loop State Tracking**: Tracks active/inactive, iteration counts, max iterations, elapsed hours, cycle counts - **Auto-Enable**: Disabled by default, auto-enables when Ralph patterns detected - **Event System**: Emits `loopUpdate`, `todoUpdate`, `completionDetected`, `enabled` events - **SSE Integration**: Events forwarded via `session:ralphLoopUpdate`, `session:ralphTodoUpdate`, `session:ralphCompletionDetected` - **Debouncing**: EVENT_DEBOUNCE_MS (50ms) for rapid updates to prevent UI jitter - **Cleanup**: MAX_TODO_ITEMS (50), TODO_EXPIRY_MS (1 hour), throttled cleanup ### Current Limitations | Feature | Status | |---------|--------| | RALPH_STATUS block parsing | Missing | | Circuit breaker pattern | Missing | | Priority-based todos (P0/P1/P2) | Missing | | Dual-condition exit gate | Missing | | Files modified tracking | Missing | | Tests status tracking | Missing | | Work type classification | Missing | --- ## 2. New Type Definitions (types.ts) ```typescript // ========== RALPH_STATUS Block Types ========== export type RalphStatusValue = 'IN_PROGRESS' | 'COMPLETE' | 'BLOCKED'; export type RalphTestsStatus = 'PASSING' | 'FAILING' | 'NOT_RUN'; export type RalphWorkType = 'IMPLEMENTATION' | 'TESTING' | 'DOCUMENTATION' | 'REFACTORING'; /** * Parsed RALPH_STATUS block from Claude output. */ export interface RalphStatusBlock { status: RalphStatusValue; tasksCompletedThisLoop: number; filesModified: number; testsStatus: RalphTestsStatus; workType: RalphWorkType; exitSignal: boolean; recommendation: string; parsedAt: number; } // ========== Circuit Breaker Types ========== export type CircuitBreakerState = 'CLOSED' | 'HALF_OPEN' | 'OPEN'; export type CircuitBreakerReason = | 'normal_operation' | 'no_progress_warning' | 'no_progress_open' | 'same_error_repeated' | 'tests_failing_too_long' | 'progress_detected' | 'manual_reset'; export interface CircuitBreakerStatus { state: CircuitBreakerState; consecutiveNoProgress: number; consecutiveSameError: number; consecutiveTestsFailure: number; lastProgressIteration: number; reason: string; reasonCode: CircuitBreakerReason; lastTransitionAt: number; lastErrorMessage: string | null; } // ========== Priority Todo Types ========== export type RalphTodoPriority = 'P0' | 'P1' | 'P2' | null; // ========== Helper Functions ========== export function createInitialCircuitBreakerStatus(): CircuitBreakerStatus { return { state: 'CLOSED', consecutiveNoProgress: 0, consecutiveSameError: 0, consecutiveTestsFailure: 0, lastProgressIteration: 0, reason: 'Initial state', reasonCode: 'normal_operation', lastTransitionAt: Date.now(), lastErrorMessage: null, }; } ``` --- ## 3. New Regex Patterns (ralph-tracker.ts) ```typescript // ---------- RALPH_STATUS Block Patterns ---------- const RALPH_STATUS_START_PATTERN = /^---RALPH_STATUS---\s*$/; const RALPH_STATUS_END_PATTERN = /^---END_RALPH_STATUS---\s*$/; const RALPH_STATUS_FIELD_PATTERN = /^STATUS:\s*(IN_PROGRESS|COMPLETE|BLOCKED)\s*$/i; const RALPH_TASKS_COMPLETED_PATTERN = /^TASKS_COMPLETED_THIS_LOOP:\s*(\d+)\s*$/i; const RALPH_FILES_MODIFIED_PATTERN = /^FILES_MODIFIED:\s*(\d+)\s*$/i; const RALPH_TESTS_STATUS_PATTERN = /^TESTS_STATUS:\s*(PASSING|FAILING|NOT_RUN)\s*$/i; const RALPH_WORK_TYPE_PATTERN = /^WORK_TYPE:\s*(IMPLEMENTATION|TESTING|DOCUMENTATION|REFACTORING)\s*$/i; const RALPH_EXIT_SIGNAL_PATTERN = /^EXIT_SIGNAL:\s*(true|false)\s*$/i; const RALPH_RECOMMENDATION_PATTERN = /^RECOMMENDATION:\s*(.+)$/i; // ---------- Completion Indicator Patterns ---------- const COMPLETION_INDICATOR_PATTERNS = [ /all\s+(?:tasks?|items?|work)\s+(?:are\s+)?(?:completed?|done|finished)/i, /(?:completed?|finished)\s+all\s+(?:tasks?|items?|work)/i, /nothing\s+(?:left|remaining)\s+to\s+do/i, /no\s+more\s+(?:tasks?|items?|work)/i, /everything\s+(?:is\s+)?(?:completed?|done)/i, ]; // ---------- Priority Pattern ---------- const TODO_PRIORITY_PATTERN = /^\s*(?:\[.\])?\s*(?:Critical:|Blocker:|Feature:|Improvement:)?\s*\(?(P[012])\)?:?\s*/i; ``` --- ## 4. New State Properties (ralph-tracker.ts) ```typescript // Add to RalphTracker class // Circuit breaker state tracking private _circuitBreaker: CircuitBreakerStatus; // RALPH_STATUS block parsing state private _statusBlockBuffer: string[] = []; private _inStatusBlock: boolean = false; private _lastStatusBlock: RalphStatusBlock | null = null; // Dual-condition exit tracking private _completionIndicators: number = 0; private _exitGateMet: boolean = false; // Cumulative tracking private _totalFilesModified: number = 0; private _totalTasksCompleted: number = 0; ``` --- ## 5. New Methods to Implement ### 5.1 RALPH_STATUS Block Parsing ```typescript private processStatusBlockLine(line: string): void { const trimmed = line.trim(); if (RALPH_STATUS_START_PATTERN.test(trimmed)) { this._inStatusBlock = true; this._statusBlockBuffer = []; return; } if (this._inStatusBlock && RALPH_STATUS_END_PATTERN.test(trimmed)) { this._inStatusBlock = false; this.parseStatusBlock(this._statusBlockBuffer); this._statusBlockBuffer = []; return; } if (this._inStatusBlock) { this._statusBlockBuffer.push(trimmed); } } private parseStatusBlock(lines: string[]): void { const block: Partial = { parsedAt: Date.now() }; for (const line of lines) { // Parse each field... } if (block.status !== undefined) { this._lastStatusBlock = fullBlock; this.handleStatusBlock(fullBlock); } } private handleStatusBlock(block: RalphStatusBlock): void { this._totalFilesModified += block.filesModified; this._totalTasksCompleted += block.tasksCompletedThisLoop; const hasProgress = block.filesModified > 0 || block.tasksCompletedThisLoop > 0; this.updateCircuitBreaker(hasProgress, block.testsStatus, block.status); if (block.status === 'COMPLETE') { this._completionIndicators++; } if (block.exitSignal && this._completionIndicators >= 2) { this._exitGateMet = true; this.emit('exitGateMet', { completionIndicators: this._completionIndicators, exitSignal: true }); } this.emit('statusBlockDetected', block); } ``` ### 5.2 Circuit Breaker Logic ```typescript private updateCircuitBreaker( hasProgress: boolean, testsStatus: RalphTestsStatus, status: RalphStatusValue ): void { const prevState = this._circuitBreaker.state; if (hasProgress) { this._circuitBreaker.consecutiveNoProgress = 0; this._circuitBreaker.lastProgressIteration = this._loopState.cycleCount; if (this._circuitBreaker.state === 'HALF_OPEN') { this._circuitBreaker.state = 'CLOSED'; this._circuitBreaker.reasonCode = 'progress_detected'; } } else { this._circuitBreaker.consecutiveNoProgress++; if (this._circuitBreaker.state === 'CLOSED') { if (this._circuitBreaker.consecutiveNoProgress >= 3) { this._circuitBreaker.state = 'OPEN'; this._circuitBreaker.reasonCode = 'no_progress_open'; } else if (this._circuitBreaker.consecutiveNoProgress >= 2) { this._circuitBreaker.state = 'HALF_OPEN'; this._circuitBreaker.reasonCode = 'no_progress_warning'; } } } if (prevState !== this._circuitBreaker.state) { this._circuitBreaker.lastTransitionAt = Date.now(); this.emit('circuitBreakerUpdate', { ...this._circuitBreaker }); } } resetCircuitBreaker(): void { this._circuitBreaker = createInitialCircuitBreakerStatus(); this._circuitBreaker.reasonCode = 'manual_reset'; this.emit('circuitBreakerUpdate', { ...this._circuitBreaker }); } ``` ### 5.3 Update processLine Method ```typescript private processLine(line: string): void { const trimmed = line.trim(); if (!trimmed) return; // NEW: Check for RALPH_STATUS block this.processStatusBlockLine(trimmed); // NEW: Check for completion indicators this.detectCompletionIndicators(trimmed); // EXISTING: Rest of the detection methods... this.detectCompletionPhrase(trimmed); this.detectAllTasksComplete(trimmed); this.detectTaskCompletion(trimmed); this.detectLoopStatus(trimmed); this.detectTodoItems(trimmed); } ``` --- ## 6. New Events to Add ```typescript export interface RalphTrackerEvents { // Existing events loopUpdate: (state: RalphTrackerState) => void; todoUpdate: (todos: RalphTodoItem[]) => void; completionDetected: (phrase: string) => void; enabled: () => void; // New events statusBlockDetected: (block: RalphStatusBlock) => void; circuitBreakerUpdate: (status: CircuitBreakerStatus) => void; exitGateMet: (data: { completionIndicators: number; exitSignal: boolean }) => void; } ``` --- ## 7. Server Integration (server.ts) ```typescript // Add new SSE event handlers in setupSessionListeners() session.on('ralphStatusBlockDetected', (block: RalphStatusBlock) => { this.broadcast('session:ralphStatusUpdate', { sessionId: session.id, block }); }); session.on('ralphCircuitBreakerUpdate', (status: CircuitBreakerStatus) => { this.broadcast('session:circuitBreakerUpdate', { sessionId: session.id, status }); }); session.on('ralphExitGateMet', (data) => { this.broadcast('session:exitGateMet', { sessionId: session.id, ...data }); }); // Add API endpoint for circuit breaker reset this.app.post('/api/sessions/:id/ralph-circuit-breaker/reset', async (req) => { const session = this.sessions.get(req.params.id); if (!session) return { success: false, error: 'Session not found' }; session.ralphTracker?.resetCircuitBreaker(); return { success: true }; }); ``` --- ## 8. Frontend Changes (app.js) ### New SSE Event Listeners ```javascript this.eventSource.addEventListener('session:ralphStatusUpdate', (e) => { const data = JSON.parse(e.data); this.updateRalphStatusBlock(data.sessionId, data.block); }); this.eventSource.addEventListener('session:circuitBreakerUpdate', (e) => { const data = JSON.parse(e.data); this.updateCircuitBreaker(data.sessionId, data.status); }); ``` ### New Rendering Methods ```javascript updateRalphStatusBlock(sessionId, block) { // Store and render status block } renderRalphStatusBlock(block) { // Render STATUS, WORK_TYPE, TESTS_STATUS, RECOMMENDATION } updateCircuitBreaker(sessionId, status) { // Store and render circuit breaker state } renderCircuitBreaker(status) { // Render badge: green (CLOSED), yellow (HALF_OPEN), red (OPEN) } ``` --- ## 9. Implementation Order | Step | Task | Time | |------|------|------| | 1 | Add type definitions to `types.ts` | 30 min | | 2 | Add regex patterns to `ralph-tracker.ts` | 30 min | | 3 | Add state properties to RalphTracker class | 15 min | | 4 | Implement RALPH_STATUS parsing methods | 1.5 hr | | 5 | Implement circuit breaker logic | 1 hr | | 6 | Implement completion indicators | 30 min | | 7 | Update events interface | 15 min | | 8 | Add server SSE handlers and API endpoint | 45 min | | 9 | Add frontend event listeners and rendering | 1 hr | | 10 | Add CSS styles | 30 min | | 11 | Update HTML structure | 15 min | | 12 | Write unit tests | 1.5 hr | **Total: ~8 hours** --- ## 10. Files to Modify | File | Changes | |------|---------| | `src/types.ts` | Add RalphStatusBlock, CircuitBreakerStatus, helper functions | | `src/ralph-tracker.ts` | Add patterns, state, parsing methods, circuit breaker | | `src/web/server.ts` | Add SSE handlers, circuit breaker reset endpoint | | `src/web/public/app.js` | Add event listeners, rendering methods | | `src/web/public/styles.css` | Add status block and circuit breaker styles | | `src/web/public/index.html` | Add UI elements to Ralph panel | | `test/ralph-tracker.test.ts` | Add tests for new functionality | --- ## 11. Test Cases to Add 1. **RALPH_STATUS Parsing** - Parse valid status block with all fields - Parse block with missing optional fields - Ignore malformed blocks - Handle multiple blocks in sequence 2. **Circuit Breaker State Transitions** - CLOSED → HALF_OPEN on 2 no-progress - HALF_OPEN → OPEN on 3 no-progress - HALF_OPEN → CLOSED on progress - Manual reset from OPEN 3. **Dual-Condition Exit Gate** - Exit when indicators >= 2 AND exitSignal = true - No exit when indicators >= 2 but exitSignal = false - No exit when exitSignal = true but indicators < 2 4. **Integration Tests** - SSE events broadcast correctly - UI updates on status block detection - Circuit breaker badge updates