v3.38.6

ruvnet/ruflov3.38.6Aug 12, 2026by ruvnet

AI Summary

Fixes hanging Codex workers, resolves stale caching of memory content, and restores daemon configuration overrides that were being overwritten by stale state files.

Key Highlights

  • Fixed `codex exec` hanging by closing stdin pipes immediately after spawn
  • Resolved stale content caching when editing MEMORY.md sections with the same ID
  • Fixed `resourceThresholds` overrides being lost to stale daemon state
  • Added retry logic for CI `sharp`/`libvips` failures

Full Release Notes

## Fixes

**#2947 — `DualModeOrchestrator` left every Codex worker's stdin open, causing `codex exec` to hang waiting for EOF.** Both Claude and Codex workers receive their prompt positionally/via a flag — never over stdin — but the pipe was never written to or closed. `claude -p` ignores the unused pipe, but `codex exec` blocks in `resolve_root_prompt` waiting for stdin EOF that never arrives, hanging every real Codex worker until the orchestrator's own multi-minute timeout kills it. Now closes stdin immediately after spawn for both platforms.

**#2920 — Editing a MEMORY.md section's body (same ID, same entry count) served stale cached content instead of refreshing it.** Two related bugs in the intelligence helper's graph/store caching, both keyed on entry *count* instead of *content*: `init()`'s graph-cache-hit gate compared only node count, so a same-ID content edit was invisible to it and `ranked-context.json` never refreshed; `consolidate()`'s persist gate only fired on insight creation or a dedup-driven shrink, so an in-memory content change (e.g. assigning an id to a previously id-less entry) was silently never written back to disk. Added a `storeFingerprint()` helper folding every entry's content into one aggregate value, used to gate the cache hit and to make `consolidate()` always persist.

**#2935 — `.claude-flow/config.json` `resourceThresholds` overrides were silently lost to a stale `daemon-state.json`.** The daemon's stale-state restoration guard only checked the constructor arg (`originalConfig`), not a value set via `config.json` — so an explicit override (e.g. `minFreeMemoryPercent: 0`, a workaround for Darwin's `os.freemem()` undercounting reclaimable memory) kept losing to whatever a `daemon-state.json` from before the override existed had persisted, on every restart. Same bug class as #2661 (`aiWorkersEnabled`), fixed the same way, per-field. Also fixed a secondary diagnostic bug: `readDaemonConfigFromFile()` logged "Daemon config loaded from ..." from inside the constructor before `this.config` existed, so the log call threw inside its own try/catch and never reached `daemon.log` — made "is the config file even being read?" impossible to answer from the log. Does not address this issue's primary Darwin `os.freemem()` memory-gate report — that needs `vm_stat`/`memory_pressure`-based measurement, left for a follow-up.

## CI infrastructure

Fixed a recurring `sharp`/`libvips` "socket hang up" / 503 flake in `npm ci` across CI workflows (confirmed on 8+ unrelated PRs this session) by adding a retry-with-backoff composite action and wiring it into every `npm ci` call site, including the two OS-conditional fallback blocks initially missed.

## Links

- PR: [#2997](https://github.com/ruvnet/ruflo/pull/2997) (#2947)
- PR: [#2998](https://github.com/ruvnet/ruflo/pull/2998) (CI retry infra)
- PR: [#2999](https://github.com/ruvnet/ruflo/pull/2999) (#2920)
- PR: [#3000](https://github.com/ruvnet/ruflo/pull/3000) (#2935)
- PR: [#3001](https://github.com/ruvnet/ruflo/pull/3001) (CI retry follow-up)
- Previous release: [v3.38.5](https://github.com/ruvnet/ruflo/releases/tag/v3.38.5)