mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-07 07:59:42 +02:00
Split 3 large files into 11 focused sub-modules via composition: ralph-tracker.ts (3,868 → ~2,400 LOC): - ralph-plan-tracker.ts: plan task tracking, checkpoints, history - ralph-fix-plan-watcher.ts: @fix_plan.md file watching - ralph-stall-detector.ts: iteration stall detection - ralph-status-parser.ts: RALPH_STATUS block parsing, circuit breaker respawn-controller.ts (3,611 → ~3,200 LOC): - respawn-patterns.ts: pure pattern detection functions - respawn-adaptive-timing.ts: adaptive timing with percentile calc - respawn-metrics.ts: cycle metrics tracking + aggregation - respawn-health.ts: pure health scoring functions session.ts (2,418 → ~1,800 LOC): - session-cli-builder.ts: CLI argument construction - session-auto-ops.ts: auto-compact/clear automation - session-task-cache.ts: task description LRU cache All external APIs preserved via delegation. Events forwarded through parent classes. Zero behavioral changes — all 436 tests pass. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
167 lines
4.7 KiB
TypeScript
167 lines
4.7 KiB
TypeScript
/**
|
|
* @fileoverview RalphStallDetector - Iteration stall detection
|
|
*
|
|
* Monitors iteration progress and emits warnings when the loop
|
|
* appears to be stalled (no iteration changes for extended periods).
|
|
*
|
|
* Extracted from ralph-tracker.ts as part of domain splitting.
|
|
*
|
|
* @module ralph-stall-detector
|
|
*/
|
|
|
|
import { EventEmitter } from 'node:events';
|
|
|
|
/**
|
|
* RalphStallDetector - Detects iteration stalls in the Ralph loop.
|
|
*
|
|
* Events emitted:
|
|
* - `iterationStallWarning` - When iteration hasn't changed for warning threshold
|
|
* - `iterationStallCritical` - When iteration hasn't changed for critical threshold
|
|
*/
|
|
export class RalphStallDetector extends EventEmitter {
|
|
/** Timestamp when iteration count last changed */
|
|
private _lastIterationChangeTime: number = 0;
|
|
|
|
/** Last observed iteration count for stall detection */
|
|
private _lastObservedIteration: number = 0;
|
|
|
|
/** Timer for iteration stall detection */
|
|
private _iterationStallTimer: NodeJS.Timeout | null = null;
|
|
|
|
/** Iteration stall warning threshold (ms) - default 10 minutes */
|
|
private _iterationStallWarningMs: number = 10 * 60 * 1000;
|
|
|
|
/** Iteration stall critical threshold (ms) - default 20 minutes */
|
|
private _iterationStallCriticalMs: number = 20 * 60 * 1000;
|
|
|
|
/** Whether stall warning has been emitted */
|
|
private _iterationStallWarned: boolean = false;
|
|
|
|
/** Whether the loop is currently active */
|
|
private _loopActive: boolean = false;
|
|
|
|
constructor() {
|
|
super();
|
|
this._lastIterationChangeTime = Date.now();
|
|
}
|
|
|
|
/**
|
|
* Start iteration stall detection timer.
|
|
* Should be called when the loop becomes active.
|
|
*/
|
|
startIterationStallDetection(): void {
|
|
this.stopIterationStallDetection();
|
|
this._lastIterationChangeTime = Date.now();
|
|
this._iterationStallWarned = false;
|
|
|
|
// Check every minute
|
|
this._iterationStallTimer = setInterval(() => {
|
|
this.checkIterationStall();
|
|
}, 60 * 1000);
|
|
}
|
|
|
|
/**
|
|
* Stop iteration stall detection timer.
|
|
*/
|
|
stopIterationStallDetection(): void {
|
|
if (this._iterationStallTimer) {
|
|
clearInterval(this._iterationStallTimer);
|
|
this._iterationStallTimer = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Notify the detector that the iteration has changed.
|
|
* Resets stall tracking state.
|
|
*/
|
|
notifyIterationChanged(iteration: number): void {
|
|
this._lastIterationChangeTime = Date.now();
|
|
this._lastObservedIteration = iteration;
|
|
this._iterationStallWarned = false;
|
|
}
|
|
|
|
/**
|
|
* Set whether the loop is currently active.
|
|
* Stall detection only fires when loop is active.
|
|
*/
|
|
setLoopActive(active: boolean): void {
|
|
this._loopActive = active;
|
|
}
|
|
|
|
/**
|
|
* Check for iteration stall and emit appropriate events.
|
|
*/
|
|
private checkIterationStall(): void {
|
|
if (!this._loopActive) return;
|
|
|
|
const stallDurationMs = Date.now() - this._lastIterationChangeTime;
|
|
|
|
// Critical stall (longer duration)
|
|
if (stallDurationMs >= this._iterationStallCriticalMs) {
|
|
this.emit('iterationStallCritical', {
|
|
iteration: this._lastObservedIteration,
|
|
stallDurationMs,
|
|
});
|
|
return;
|
|
}
|
|
|
|
// Warning stall
|
|
if (stallDurationMs >= this._iterationStallWarningMs && !this._iterationStallWarned) {
|
|
this._iterationStallWarned = true;
|
|
this.emit('iterationStallWarning', {
|
|
iteration: this._lastObservedIteration,
|
|
stallDurationMs,
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get iteration stall metrics for monitoring.
|
|
*/
|
|
getIterationStallMetrics(): {
|
|
lastIterationChangeTime: number;
|
|
stallDurationMs: number;
|
|
warningThresholdMs: number;
|
|
criticalThresholdMs: number;
|
|
isWarned: boolean;
|
|
currentIteration: number;
|
|
} {
|
|
return {
|
|
lastIterationChangeTime: this._lastIterationChangeTime,
|
|
stallDurationMs: Date.now() - this._lastIterationChangeTime,
|
|
warningThresholdMs: this._iterationStallWarningMs,
|
|
criticalThresholdMs: this._iterationStallCriticalMs,
|
|
isWarned: this._iterationStallWarned,
|
|
currentIteration: this._lastObservedIteration,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Configure iteration stall thresholds.
|
|
* @param warningMs - Warning threshold in milliseconds
|
|
* @param criticalMs - Critical threshold in milliseconds
|
|
*/
|
|
configureIterationStallThresholds(warningMs: number, criticalMs: number): void {
|
|
this._iterationStallWarningMs = warningMs;
|
|
this._iterationStallCriticalMs = criticalMs;
|
|
}
|
|
|
|
/**
|
|
* Reset stall detector state.
|
|
*/
|
|
reset(): void {
|
|
this._lastIterationChangeTime = Date.now();
|
|
this._lastObservedIteration = 0;
|
|
this._iterationStallWarned = false;
|
|
this._loopActive = false;
|
|
}
|
|
|
|
/**
|
|
* Clean up all resources.
|
|
*/
|
|
destroy(): void {
|
|
this.stopIterationStallDetection();
|
|
this.removeAllListeners();
|
|
}
|
|
}
|