-
Notifications
You must be signed in to change notification settings - Fork 0
fix(runtime): reconcile autonomous executor and confidence repairs #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,7 +24,7 @@ const DEFAULT_CONFIG = { | |
|
|
||
| class AdaptiveCpuAlerts { | ||
| constructor(options = {}) { | ||
| this.lane = options.lane || 'archivist'; | ||
| this.lane = options.lane || 'swarmmind'; | ||
| this.stateDir = options.stateDir; | ||
| this.config = Object.assign({}, DEFAULT_CONFIG, options.config || {}); | ||
| this.statePath = path.join(this.stateDir, 'adaptive-alert-state.json'); | ||
|
|
@@ -144,48 +144,83 @@ class AdaptiveCpuAlerts { | |
|
|
||
| let deltaCpuUsec; | ||
| let wallSeconds; | ||
| const isFirstSample = this._prevCpu === null || this._prevWallMs === null; | ||
|
|
||
| if (this._prevCpu !== null && this._prevWallMs !== null) { | ||
| if (!isFirstSample) { | ||
| deltaCpuUsec = Math.max(0, cpuTotalUsec - this._prevCpu); | ||
| wallSeconds = _wallSecondsOverride != null | ||
| ? _wallSecondsOverride | ||
| : (now - this._prevWallMs) / 1000; | ||
| } else { | ||
| // First sample: initialize state but do not evaluate CPU thresholds | ||
| // Memory threshold still evaluated on first sample | ||
| this._state.consecutiveHighCpu = 0; | ||
| this._state.consecutiveCriticalCpu = 0; | ||
| this._state.consecutiveEmergencyCpu = 0; | ||
| deltaCpuUsec = cpuTotalUsec; | ||
| wallSeconds = _wallSecondsOverride != null | ||
| ? _wallSecondsOverride | ||
| : Math.max(this.config.sample_window_seconds, process.uptime()); | ||
| } | ||
|
|
||
| const cpuPct = this._normalizeCpuPct(deltaCpuUsec, wallSeconds); | ||
|
|
||
| this._prevWallMs = now; | ||
| this._prevCpu = cpuTotalUsec; | ||
|
|
||
| const thresholds = this._getAdaptiveThresholds(); | ||
| const result = this._checkThresholds(cpuPct, memRss, thresholds); | ||
|
|
||
| if (cpuPct < thresholds.warningPct) { | ||
| this._state.samples.push({ | ||
| timestamp: new Date().toISOString(), | ||
| cpuPct: Math.round(cpuPct * 1000) / 1000, | ||
| cpuDeltaUsec: deltaCpuUsec, | ||
| cpuTotalUsec, | ||
| wallSeconds: Math.round(wallSeconds * 10) / 10, | ||
| }); | ||
| } | ||
| // Skip CPU threshold evaluation on first sample | ||
| if (isFirstSample) { | ||
| // Still check memory threshold | ||
| const memAlerts = this._checkMemoryThreshold(memRss); | ||
| this.saveState(); | ||
| return memAlerts.length > 0 ? { | ||
| shouldAlert: true, | ||
| severity: memAlerts[0].severity, | ||
| alerts: memAlerts, | ||
| cpuPct: 0, | ||
| thresholds: this._getAdaptiveThresholds(), | ||
| escalate: memAlerts.some(a => a.severity === 'CRITICAL'), | ||
| } : null; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For a normal first sample this now returns Useful? React with 👍 / 👎. |
||
| } | ||
|
|
||
| const cpuPct = this._normalizeCpuPct(deltaCpuUsec, wallSeconds); | ||
|
|
||
| const maxSamples = this.config.baseline_window_samples * 2; | ||
| if (this._state.samples.length > maxSamples) { | ||
| this._state.samples = this._state.samples.slice(-this.config.baseline_window_samples); | ||
| } | ||
| const thresholds = this._getAdaptiveThresholds(); | ||
| const result = this._checkThresholds(cpuPct, memRss, thresholds); | ||
|
|
||
| if (cpuPct < thresholds.warningPct) { | ||
| this._state.samples.push({ | ||
| timestamp: new Date().toISOString(), | ||
| cpuPct: Math.round(cpuPct * 1000) / 1000, | ||
| cpuDeltaUsec: deltaCpuUsec, | ||
| cpuTotalUsec, | ||
| wallSeconds: Math.round(wallSeconds * 10) / 10, | ||
| }); | ||
| } | ||
|
|
||
| this.saveState(); | ||
| return result; | ||
| } | ||
| const maxSamples = this.config.baseline_window_samples * 2; | ||
| if (this._state.samples.length > maxSamples) { | ||
| this._state.samples = this._state.samples.slice(-this.config.baseline_window_samples); | ||
| } | ||
|
|
||
| this.saveState(); | ||
| return result.shouldAlert ? result : null; | ||
| } | ||
|
|
||
| _checkMemoryThreshold(memRss) { | ||
| const alerts = []; | ||
| if (memRss > this.config.mem_threshold_bytes) { | ||
| const key = `mem-warning-${this.lane}`; | ||
| if (!this._isCooldownActive(key)) { | ||
| const memPct = (memRss / this.config.mem_threshold_bytes) * 100; | ||
| alerts.push({ | ||
| severity: memPct > 200 ? 'CRITICAL' : 'WARNING', | ||
| metric: 'memory', | ||
| value: memRss, | ||
| threshold: this.config.mem_threshold_bytes, | ||
| thresholdType: 'static', | ||
| mode: 'static', | ||
| message: `Memory RSS at ${(memRss / 1024 / 1024).toFixed(1)}MB exceeds threshold ${(this.config.mem_threshold_bytes / 1024 / 1024).toFixed(0)}MB`, | ||
| }); | ||
| this._setCooldown(key, this.config.mem_cooldown_seconds); | ||
| } | ||
| } | ||
| return alerts; | ||
| } | ||
|
|
||
| _checkThresholds(cpuPct, memRss, thresholds) { | ||
| const alerts = []; | ||
|
|
@@ -258,44 +293,45 @@ class AdaptiveCpuAlerts { | |
| this._state.consecutiveHighCpu = 0; | ||
| } | ||
| } | ||
| } else { | ||
| this._state.consecutiveHighCpu = 0; | ||
| this._state.consecutiveCriticalCpu = 0; | ||
| this._state.consecutiveEmergencyCpu = 0; | ||
| } | ||
|
|
||
| if (memRss > this.config.mem_threshold_bytes) { | ||
| const key = `mem-warning-${this.lane}`; | ||
| if (!this._isCooldownActive(key)) { | ||
| const memPct = (memRss / this.config.mem_threshold_bytes) * 100; | ||
| alerts.push({ | ||
| severity: memPct > 200 ? 'CRITICAL' : 'WARNING', | ||
| metric: 'memory', | ||
| value: memRss, | ||
| threshold: this.config.mem_threshold_bytes, | ||
| thresholdType: 'static', | ||
| mode: 'static', | ||
| message: `Memory RSS at ${(memRss / 1024 / 1024).toFixed(1)}MB exceeds threshold ${(this.config.mem_threshold_bytes / 1024 / 1024).toFixed(0)}MB`, | ||
| }); | ||
| this._setCooldown(key, this.config.mem_cooldown_seconds); | ||
| } | ||
| } | ||
| } else { | ||
| this._state.consecutiveHighCpu = 0; | ||
| this._state.consecutiveCriticalCpu = 0; | ||
| this._state.consecutiveEmergencyCpu = 0; | ||
| } | ||
|
|
||
| const escalate = alerts.some(a => a.severity === 'CRITICAL'); | ||
| const maxAlert = alerts.length > 0 ? alerts.reduce((a, b) => { | ||
| const rank = { CRITICAL: 3, WARNING: 2, INFO: 1 }; | ||
| return (rank[a.severity] || 0) >= (rank[b.severity] || 0) ? a : b; | ||
| }) : null; | ||
| // Memory threshold check (always evaluated, not just first sample) | ||
| if (memRss > this.config.mem_threshold_bytes) { | ||
| const key = `mem-warning-${this.lane}`; | ||
| if (!this._isCooldownActive(key)) { | ||
| const memPct = (memRss / this.config.mem_threshold_bytes) * 100; | ||
| alerts.push({ | ||
| severity: memPct > 200 ? 'CRITICAL' : 'WARNING', | ||
| metric: 'memory', | ||
| value: memRss, | ||
| threshold: this.config.mem_threshold_bytes, | ||
| thresholdType: 'static', | ||
| mode: 'static', | ||
| message: `Memory RSS at ${(memRss / 1024 / 1024).toFixed(1)}MB exceeds threshold ${(this.config.mem_threshold_bytes / 1024 / 1024).toFixed(0)}MB`, | ||
| }); | ||
| this._setCooldown(key, this.config.mem_cooldown_seconds); | ||
| } | ||
| } | ||
|
|
||
| return { | ||
| shouldAlert: alerts.length > 0, | ||
| severity: maxAlert ? maxAlert.severity : null, | ||
| alerts, | ||
| cpuPct, | ||
| thresholds, | ||
| escalate, | ||
| }; | ||
| } | ||
| const escalate = alerts.some(a => a.severity === 'CRITICAL'); | ||
| const maxAlert = alerts.length > 0 ? alerts.reduce((a, b) => { | ||
| const rank = { CRITICAL: 3, WARNING: 2, INFO: 1 }; | ||
| return (rank[a.severity] || 0) >= (rank[b.severity] || 0) ? a : b; | ||
| }) : null; | ||
|
|
||
| return { | ||
| shouldAlert: alerts.length > 0, | ||
| severity: maxAlert ? maxAlert.severity : null, | ||
| alerts, | ||
| cpuPct, | ||
| thresholds, | ||
| escalate, | ||
| }; | ||
| } | ||
|
|
||
| getStatus() { | ||
| this.loadState(); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: vortsghost2025/Archivist-Agent
Length of output: 22398
🏁 Script executed:
Repository: vortsghost2025/Archivist-Agent
Length of output: 12528
Make
evaluatereturn a non-alert result object when memory is normal.AdaptiveCpuAlertsreturnsnullon normal memory usage, butscripts/test-lane-worker-adaptive-alerts.jsasserts thatevaluatereturns a result withshouldAlert. Replace the first-samplenullreturn with{ shouldAlert: false, ... }, and align similarnullreturns with the same result contract.🤖 Prompt for AI Agents