fix(server): don't disable embeddings when macOS misreports 0 MB free#14
Merged
Conversation
…lable (#13) MemoryManager::initialize gates the ONNX model load on available memory to avoid OOM-killing the process. sysinfo's available_memory() returns 0 on some macOS versions (reclaimable memory is parked in inactive/speculative/purgeable pages that aren't counted as free), so healthy Macs with 16 GB RAM had every embedding-dependent tool (index_markdown, memory_*, semantic search) silently disabled with no override. - Extract evaluate_memory_gate() as a pure, unit-tested policy: a 0 reading is a detection failure (a running process always holds memory) -> proceed with the load rather than hard-disabling on a number we don't trust; a genuine low-but-nonzero reading still skips to graph-only. - Add CODEGRAPH_SKIP_MEMORY_CHECK=1 (also true/yes) to bypass the gate entirely, in both MCP and one-shot --run-tool modes. - Log/error messages now name the override; README documents it. - 5 unit tests cover load / skip / zero-proceed / bypass / boundary. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
🔍 CodeGraph PR Review5 files changed (+202/−23, 18 functions) · Risk: 🔴 high Blast radius48 direct callers affected across
|
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.
Intent
The developer asked the agent to investigate a user-reported GitHub issue (#13) on the CodeGraph repo where the server disabled embeddings/model loading because macOS misreported 0 MB of available memory via sysinfo's available_memory(). They wanted the gate fixed so a 0 MB reading is treated as a detection failure that proceeds with the model load, plus a CODEGRAPH_SKIP_MEMORY_CHECK environment-variable escape hatch, with unit tests covering the load/skip/zero/bypass/boundary cases. They explicitly asked to document CODEGRAPH_SKIP_MEMORY_CHECK in the README. Finally, they instructed the agent to post the drafted resolution comment on issue #13 and push the fix/macos-memory-detection branch (through the no-mistakes validation gate rather than directly to origin), noting the fix would need to be folded into the latest code currently in testing. This work sat alongside broader session efforts (VS Code extension funnel/CodeLens features, vsix packaging, and userbase-growth planning) but the commit itself was the isolated macOS memory-detection fix off main.
What Changed
evaluate_memory_gatepolicy incrates/codegraph-server/src/memory.rs: a 0-byteavailable_memory()reading is now treated as a detection failure (common on macOS, issue macOS: available memory misdetected as 0 MB — embedding model never loads, markdown/memory tools unusable #13) and the ONNX embedding model loads anyway, instead of hard-disabling semantic search; genuinely low readings still skip the model with a graph-only fallback.CODEGRAPH_SKIP_MEMORY_CHECKenv-var escape hatch to bypass the gate entirely, referenced in the skip-path log/error messages and documented in both the main README and the npmmcp-packageREADME.mcp/engine.rs) and taught the embed-loop RAM backpressure (ai_query/engine.rs) to ignore 0 MB readings, so misreporting machines no longer fall back to per-workspace model loads or permanently ratchet batch size down to the minimum. Covered by new gate/backpressure unit tests plus e2e runs against a fake vm_stats shim exercising the zero, low, and bypass paths (all passing in the pipeline).Risk Assessment
✅ Low: Well-bounded fix with the gate policy extracted into a pure, unit-tested helper, both previously flagged inconsistent call sites (socket-engine gate and embed backpressure) now correctly reusing it, no remaining raw memory checks, and README documentation matching actual behavior.
Testing
Ran all 8 new unit tests (gate policy load/skip/zero/bypass/boundary plus embed-backpressure zero-reading cases; all pass), then exercised the fix end-to-end by running the real codegraph-server binary with a DYLD interpose shim that reproduces sysinfo's macOS 0 MB misreport: the 0 MB case now proceeds to load the embedding model (one-shot and --serve engine paths), genuinely low memory still skips with the new override hint, and CODEGRAPH_SKIP_MEMORY_CHECK=1 bypasses the gate live; log transcripts and the shim source are saved as evidence. No UI surface is involved, so log transcripts are the reviewer-visible artifact.
Evidence: Memory-gate e2e log transcript (baseline / 0 MB repro / low-skip / bypass / socket engine)
Evidence: DYLD interpose shim used to reproduce the macOS 0 MB sysinfo misreport
Interposes host_statistics64 and inflates compressor_page_count so sysinfo's (free+inactive+purgeable - compressor) saturating subtraction yields 0 — the exact issue-13 failure mode; FAKE_VM_MODE=low fakes ~500 MB for the skip/bypass paths.Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 2 issues found → auto-fixed ✅
crates/codegraph-server/src/mcp/engine.rs:222- The socket-engine shared-model gate still uses the rawsys.available_memory() < 1_500_000_000check with no zero-reading (detection-failure) handling and no CODEGRAPH_SKIP_MEMORY_CHECK support, despite its comment saying it gates 'the same way the per-workspace path does'. On a macOS machine misreporting 0 MB (issue macOS: available memory misdetected as 0 MB — embedding model never loads, markdown/memory tools unusable #13), the shared model is skipped and every workspace falls back to loading its own ONNX model via the now-fixed per-workspace gate - multiplying memory usage on exactly the machines flagged as constrained, and making the README claim that the env var works in MCP mode only accidentally true. Fix by reusing evaluate_memory_gate, memory_check_bypassed, and MODEL_MIN_FREE_BYTES here (they are already pub(crate)).crates/codegraph-server/src/ai_query/engine.rs:401- The embed-loop RAM backpressure (also at line 550) treats a 0 MB available_memory reading as genuine pressure: on the same misreporting macOS machines, every poll ofavailable_memory_mb() < EMBED_LOW_MEM_MBis true, so the ONNX batch size ratchets down to the minimum of 4 and a checkpoint is forced on every poll, permanently degrading embedding throughput during first index. Apply the same '0 is an untrusted reading, not real state' rule introduced by this commit (e.g.avail_mb > 0 && avail_mb < EMBED_LOW_MEM_MB).🔧 Fix: apply shared memory gate to socket engine and embed backpressure
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
cargo test -p codegraph-server --lib gate_ (5 MemoryGate policy tests: ample/boundary/low-skip/zero/bypass — all pass)cargo test -p codegraph-server --lib embed_memory_pressured (3 embed-backpressure tests incl. zero-reading-not-pressure — all pass)cargo test -p codegraph-server --lib memory:: (full memory module suite — 26 pass, 1 ignored needing model files)Baseline e2e: RUST_LOG=info ./target/debug/codegraph-server --workspace <tmp> --run-tool codegraph_get_symbol_info — 6951 MB read, model loads normallyIssue #13 e2e repro: same command under DYLD_INSERT_LIBRARIES=fake_vm_stats.dylib FAKE_VM_MODE=zero — sysinfo reads 0 MB, server logs detection-failure warning and still loads the embedding modelSkip-path e2e: FAKE_VM_MODE=low (499 MB) — model skipped, graph-only, log and error now carry the CODEGRAPH_SKIP_MEMORY_CHECK=1 override hintBypass e2e: FAKE_VM_MODE=low CODEGRAPH_SKIP_MEMORY_CHECK=1 — model loads despite 499 MB readingSocket-engine e2e: ./target/debug/codegraph-server --serve under FAKE_VM_MODE=zero — 'Engine:' detection-failure warning logged and shared embedding model loadedConfirmed README diff documents CODEGRAPH_SKIP_MEMORY_CHECK and worktree left clean after testing✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.