Skip to content

fix(daemon): platform-aware resource thresholds for macOS#1173

Closed
ahmedibrahim085 wants to merge 5926 commits intoruvnet:mainfrom
ahmedibrahim085:fix/platform-aware-resource-thresholds
Closed

fix(daemon): platform-aware resource thresholds for macOS#1173
ahmedibrahim085 wants to merge 5926 commits intoruvnet:mainfrom
ahmedibrahim085:fix/platform-aware-resource-thresholds

Conversation

@ahmedibrahim085
Copy link
Copy Markdown

Summary

  • Daemon workers (audit, optimize, testgaps) permanently blocked on macOS due to hardcoded resource thresholds that are incompatible with macOS system metric reporting
  • CPU threshold of 2.0 is exceeded by os.loadavg() on any multi-core Mac at idle (reports aggregate load, not per-core)
  • Memory threshold of 20% is unreachable because os.freemem() reports only truly unused RAM, not reclaimable cache (macOS typically shows 5-8% "free")
  • Compute thresholds from system capabilities: CPU cores × 3 for load, 1% free memory on Darwin (5% on Linux)
  • Thresholds remain overridable via config parameter — zero breaking change

Problem

All daemon workers with resource checks fail with:

CPU load too high: 3.80
Memory too low: 7.6% free

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), and os.freemem() excludes reclaimable cache on macOS. The hardcoded thresholds assume Linux-like reporting semantics.

Approach

  1. import os from 'os' — Use top-level ESM import instead of await import('os') in async method. Built-in modules don't need dynamic import, and this enables synchronous access in the constructor.

  2. getDefaultResourceThresholds() — Extract threshold computation into a pure function that:

  3. Startup logging — Log computed thresholds (values, core count, platform) at daemon start for debuggability.

Test plan

  • Verified on 16-core macOS: all 5 workers execute successfully after patch
  • daemon status shows 100% success rate for audit, optimize, testgaps (were 0% before)
  • daemon trigger --worker audit completes in <1ms
  • Config override still works (config parameter takes precedence over computed defaults)
  • Verify Linux behavior unchanged (same function, higher thresholds: cores×3 for CPU, 5% for memory)

Fixes #1077

ruvnet and others added 30 commits February 8, 2026 17:28
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T17:28:41Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T17:28:42Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T17:28:49Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T17:31:20Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T17:35:33Z
- Changes: 5 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T17:52:17Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T17:52:29Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T17:52:38Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T17:53:15Z
- Changes: 2 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T20:39:45Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T20:39:54Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T20:40:34Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T20:40:39Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T20:41:40Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T20:41:52Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T20:42:38Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T21:20:16Z
- Changes: 6 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T21:20:20Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T21:20:27Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T21:20:35Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T21:20:45Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T21:20:58Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T21:21:06Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T21:21:10Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T21:21:15Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T21:21:20Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T21:26:02Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T21:26:33Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T21:26:41Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-08T21:27:23Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
ruvnet and others added 24 commits February 11, 2026 22:50
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-11T22:50:47Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-11T22:50:57Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-11T22:51:03Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-11T22:52:01Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Automatic checkpoint created by Claude Code
- Branch: rebrand/ruvflow-umbrella
- Timestamp: 2026-02-11T22:52:39Z
- Changes: 1 file(s)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove sqlite3 and bcrypt from dependency chain (closes ruvnet#1091)
  - Eliminates 10 HIGH severity vulnerabilities (tar@6.2.1 CVEs)
  - Removes 73+ packages from install footprint
  - Pin agentdb@2.0.0-alpha.3.5 in memory and umbrella packages

- Add backward compatibility for older settings.json configs
  - Default --success to true in post-edit, post-command, post-task
  - Default --file to 'unknown' in pre-edit, post-edit
  - Old hook configs no longer error with "Required option missing"

- Add Agent Teams hooks to init settings generator
  - TeammateIdle: auto-assign pending tasks to idle teammates
  - TaskCompleted: train patterns and record completion

- Rename helpers from .js to .cjs for ESM compatibility
  - Root package.json has "type": "module", .js files parse as ESM
  - .cjs extension ensures CommonJS require() works correctly

Published: @claude-flow/cli@3.1.0-alpha.34, claude-flow@3.1.0-alpha.34,
@claude-flow/memory@3.0.0-alpha.9

Co-Authored-By: claude-flow <ruv@ruv.net>
Regenerate package-lock.json and pnpm-lock.yaml to match
updated agentdb dependency. Fixes CI failures where npm ci
and pnpm --frozen-lockfile rejected the version mismatch.

Co-Authored-By: claude-flow <ruv@ruv.net>
- @claude-flow/shared: Add helmet, express, cors, ws as devDeps
  (needed for pnpm strict hoisting in CI). Remove obsolete
  @types/helmet (helmet v7+ ships own types)

- @claude-flow/integration: Fix TS2339 for agentic-flow VERSION
  export removed upstream. Use bracket notation to bypass
  compile-time check (runtime already handled gracefully)

- @claude-flow/testing: Add explicit Mock type annotations to
  vi.fn() fields to fix TS2742 portable type inference errors

All 20 V3 packages now build clean with pnpm -r build.

Co-Authored-By: claude-flow <ruv@ruv.net>
agentdb@2.0.0-alpha.3.6 includes:
- CLI Commander parsing fix (resolves "unknown command 'node'" error)
- LLM Router (FastGRNN-based intelligent model selection)
- Hyperbolic geometry (Poincare ball operations)
- Curriculum learning (hard negative mining, contrastive loss)

Published: claude-flow@3.1.0-alpha.35, @claude-flow/cli@3.1.0-alpha.35,
@claude-flow/memory@3.0.0-alpha.10

Co-Authored-By: claude-flow <ruv@ruv.net>
The command parser enforces `required: true` on option specs BEFORE
the action function runs, so defaulting values in the action was
insufficient. Changed 5 option specs from required to optional:
- pre-edit: --file (defaults to 'unknown')
- post-edit: --file (defaults to 'unknown'), --success (defaults to true)
- post-command: --success (defaults to true)
- post-task: --success (defaults to true)

This enables Claude Code hooks to call these commands without explicit
flags, matching the PostToolUse convention where success is implied.

Published as @claude-flow/cli@3.1.0-alpha.36 and claude-flow@3.1.0-alpha.36.

Co-Authored-By: claude-flow <ruv@ruv.net>
Co-Authored-By: claude-flow <ruv@ruv.net>
- Remove unpublished optional deps from gastown-bridge (gastown-formula-wasm,
  ruvector-gnn-wasm) that caused npm 11 to crash with "Invalid Version:"
- Bump agentdb 2.0.0-alpha.3.6 -> 3.7 (pins @ruvector/gnn@0.1.23 with all
  platform binaries published)
- Bump agentic-flow ^2.0.1-alpha.80 -> ^2.0.7 (pins @ruvector/tiny-dancer@0.1.17
  with linux-arm64-gnu stub published)
- Bump gastown-bridge ^0.1.2 -> ^0.1.3
- Version bump to 3.1.0-alpha.39

Published packages: gastown-bridge@0.1.3, agentdb@2.0.0-alpha.3.7,
agentic-flow@2.0.7, @ruvector/gnn platform stubs @0.1.22+0.1.23,
@ruvector/tiny-dancer-linux-arm64-gnu@0.1.16+0.1.17,
@claude-flow/cli@3.1.0-alpha.39, claude-flow@3.1.0-alpha.39

Co-Authored-By: claude-flow <ruv@ruv.net>
V3 Security, Backward Compat & Agent Teams Hooks
…e Day

- Switch download badges from ruflo to claude-flow npm package
- Add GitHub Project of the Day badge above existing badges
- Bump version to 3.1.0-alpha.40 and publish to npm

Co-Authored-By: claude-flow <ruv@ruv.net>
- Fix ruflo bin to walk node_modules tree instead of using require.resolve
  (blocked by @claude-flow/cli strict exports map)
- Use git rev-parse --show-toplevel for all hook paths in settings.json
  so hooks work from any subdirectory
- Update CLAUDE.md publishing rules to include ruflo as third package
- Bump ruflo to 3.1.0-alpha.16

Co-Authored-By: claude-flow <ruv@ruv.net>
Resolves "Invalid Version:" crash on npm 11.10.0+ caused by
@ruvector/gnn caret-range dedup triggering arborist bug with
corrupted npx cache entries. agentdb 3.7 uses exact gnn@0.1.23.

Co-Authored-By: claude-flow <ruv@ruv.net>
…uvnet#1161)

The PreToolUse:Task hook used $TOOL_INPUT_prompt which expands to the
full agent prompt (thousands of characters), overflowing the shell's
argument length limit. Switched to $TOOL_INPUT_description (the short
3-5 word field) and truncated to 200 chars.

Fixes ruvnet#1160
Co-Authored-By: claude-flow <ruv@ruv.net>
…#1163)

ruflo.js now imports CLI class directly and passes ruflo branding
(name, description) instead of re-importing cli.js with defaults.
Also fixed two hardcoded 'claude-flow' strings in index.ts help text
to use this.name for proper branding in both packages.

Fixes ruvnet#1162
Co-Authored-By: claude-flow <ruv@ruv.net>
On Windows, import() requires file:// URLs, not bare C:\ paths.
Added pathToFileURL() wrapper for all dynamic imports in ruflo.js.

Fixes ruvnet#1164
…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.
Copy link
Copy Markdown

@mixingchex mixingchex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@ruvnet ruvnet closed this Mar 5, 2026
ruvnet added a commit that referenced this pull request Mar 17, 2026
….0 (WIP)

Fixes #1077 — daemon workers never execute due to unrealistic resource thresholds.

WorkerDaemon hardcoded `maxCpuLoad: 2.0` which blocked all background workers
on any multi-core machine with moderate load. A 12-core machine at 18% CPU
utilization (loadavg ~2.2) would have ALL workers permanently deferred.

Three community PRs attempted fixes but were closed without merge:
- PR #1078: Used `cpuCount * 3` (too permissive, no config reading, removed
  spawn safeguards, no tests)
- PR #1173: Used `cpuCount * 3` with platform detection (too permissive, no
  config reading, removed timer .unref(), no tests)
- PR #1052: Fixed busy-wait loop symptom but not root threshold cause (no tests)

- Smart CPU-proportional default: `Math.max(cpuCount * 0.8, 2.0)`
  - 0.8 ratio aligns with K8s HPA batch workload standard (80%)
  - Floor of 2.0 prevents blocking on single-CPU machines
  - Fallback `cpus().length || 1` for containers with restricted cgroups
- 3-layer config priority: constructor arg > config.json > smart default
- New `readDaemonConfigFromFile()` reads `.claude-flow/config.json`
  - Supports flat dot-notation keys and `scopes.project` nesting
  - Runtime type validation (rejects non-numeric, negative, out-of-range)
- State restoration from `daemon-state.json` with range validation
- ESM-safe: replaced `require('os')` and `require('fs')` with static imports
- Added `appendFileSync` to top-level import (was inline `require('fs')`)

- [ ] Incorporate busy-wait loop fix from PR #1052 (break on deferred worker)
- [ ] Add startup logging of computed thresholds (from PR #1173)
- [ ] Platform-aware `minFreeMemoryPercent` (macOS reports only truly free RAM)
- [ ] Container-aware CPU detection via cgroup v1/v2 reading
- [ ] CLI flags `--max-cpu-load` and `--min-free-memory` for daemon start
- [ ] Display resource thresholds in `daemon status` output

- [x] 17 unit tests covering defaults, resource gating (allow + block CPU +
  block memory), config reading (flat + scoped + malformed), priority chain,
  state persistence, input validation
- [x] 1617 tests pass across 24 suites (0 failures, 0 regressions)
- [x] Verified on 12-core Linux (maxCpuLoad: 9.6, workers executing)
- [x] Verified in devcontainer (Node 20, pnpm 8)
- [x] Verified via global npm install in external project

Co-Authored-By: claude-flow <ruv@ruv.net>
ruvnet added a commit that referenced this pull request Mar 17, 2026
…Wave 1)

Follow-up to the CPU-proportional maxCpuLoad fix. Incorporates improvements
from community PRs #1052, #1173, and #1078 analysis.

## Changes

### WI-1: Busy-wait loop prevention (from PR #1052 analysis)
- processPendingWorkers() now breaks when a worker is deferred (returns null)
- Adds 30s backoff retry when no running workers exist to drain the queue
- Prevents the positive feedback loop: high CPU -> defer -> tight retry -> higher CPU

### WI-2: Startup logging of computed thresholds (from PR #1173)
- Daemon logs PID, CPU count, maxCpuLoad, and minFreeMemoryPercent on start
- Critical for diagnosing threshold issues in production

### WI-3: Platform-aware minFreeMemoryPercent
- macOS: 5% default (os.freemem() excludes reclaimable file cache)
- Linux: 10% default (os.freemem() includes reclaimable memory)
- Previous 20% was too aggressive for macOS (PR #1078 used 1%, too low)

## Test plan

- [x] 21 unit tests (4 new: platform memory, 3 busy-wait prevention)
- [x] 1621 tests pass across 24 suites (0 failures, 0 regressions)

Co-Authored-By: claude-flow <ruv@ruv.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Daemon workers never execute on macOS due to unrealistic resource thresholds

3 participants