fix(daemon): platform-aware resource thresholds for macOS#1173
Open
ahmedibrahim085 wants to merge 3 commits intoruvnet:mainfrom
Open
fix(daemon): platform-aware resource thresholds for macOS#1173ahmedibrahim085 wants to merge 3 commits intoruvnet:mainfrom
ahmedibrahim085 wants to merge 3 commits intoruvnet:mainfrom
Conversation
…port
The `os` module was imported dynamically via `await import('os')` inside
the async `canRunWorker()` method. Since `os` is a Node.js built-in that
is always available and never changes at runtime, this dynamic import
adds unnecessary overhead on every resource check call.
Move to a standard top-level ESM import. This also enables synchronous
access to `os` APIs (like `os.cpus()`) in non-async contexts such as
the constructor, which the next commit requires for platform-aware
threshold computation.
…tead of hardcoded values Daemon workers (audit, optimize, testgaps) never execute on macOS because the hardcoded resource thresholds are incompatible with how macOS reports system metrics. CPU: os.loadavg() returns aggregate load across all cores. A 16-core Mac at modest utilization reports loadavg ~3-5, permanently exceeding the hardcoded maxCpuLoad of 2.0. Workers are blocked even when the system is effectively idle. Memory: macOS uses available RAM as filesystem cache. os.freemem() reports only truly unused memory (typically 5-8%), not reclaimable cache. The 20% minFreeMemoryPercent threshold is unreachable under normal macOS operation. Extract threshold computation into getDefaultResourceThresholds() that scales CPU threshold by core count (cores × 3) and uses a 1% free memory floor on Darwin. Linux gets a 5% floor since its memory reporting is more conservative. Both remain overridable via config parameter. Fixes ruvnet#1077
When debugging why workers are blocked, the first question is "what thresholds is the daemon using?" Currently this requires reading the daemon-state.json file after startup. Add a single log line at daemon start that shows the active maxCpuLoad, core count, minFreeMemoryPercent, and platform. This makes threshold misconfiguration immediately visible in daemon logs without additional tooling.
mixingchex
suggested changes
Feb 25, 2026
mixingchex
left a comment
There was a problem hiding this comment.
REQUEST_CHANGES — Reviewed via hive-mind swarm analysis.
The fix correctly diagnoses the macOS issue — os.loadavg() scaling and macOS memory reporting make hardcoded thresholds permanently block all workers. The memory thresholds (1% Darwin, 5% Linux) are sound.
Required change:
The CPU multiplier cpuCount * 3 is too aggressive — on a 16-core Mac it sets maxCpuLoad = 48, effectively disabling the resource gate entirely.
| System | Cores | Current (2.0) | Proposed (x3) | Recommended (x1.0) |
|---|---|---|---|---|
| 1-core | 1 | 2.0 | 3.0 | 2.0 (floor) |
| 4-core | 4 | 2.0 | 12.0 | 4.0 |
| 8-core | 8 | 2.0 | 24.0 | 8.0 |
| 16-core | 16 | 2.0 | 48.0 | 16.0 |
Recommended fix:
maxCpuLoad: Math.max(cpuCount * 1.0, 2.0),This means "allow workers when load < 100% per core, with a minimum of 2.0 for small machines."
Everything else (static import, startup logging, config override preservation) is clean.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
os.loadavg()on any multi-core Mac at idle (reports aggregate load, not per-core)os.freemem()reports only truly unused RAM, not reclaimable cache (macOS typically shows 5-8% "free")Problem
All daemon workers with resource checks fail with:
On a 16-core Mac at idle. Workers have 0% success rate (0 runs out of hundreds of scheduler cycles).
Root cause:
os.loadavg()[0]returns aggregate load (not per-core), andos.freemem()excludes reclaimable cache on macOS. The hardcoded thresholds assume Linux-like reporting semantics.Approach
import os from 'os'— Use top-level ESM import instead ofawait import('os')in async method. Built-in modules don't need dynamic import, and this enables synchronous access in the constructor.getDefaultResourceThresholds()— Extract threshold computation into a pure function that:maxCpuLoadby core count (os.cpus().length × 3), so a 16-core Mac allows load up to 48 instead of 2minFreeMemoryPercentto 1% on Darwin (reflects actual memory pressure, not cache usage) and 5% on LinuxStartup logging — Log computed thresholds (values, core count, platform) at daemon start for debuggability.
Test plan
daemon statusshows 100% success rate for audit, optimize, testgaps (were 0% before)daemon trigger --worker auditcompletes in <1msFixes #1077