You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Version: codebase-memory-mcp v0.9.0 (macOS arm64, release binary) Language: PHP Mode: reproduces in fast and moderate.
Summary
On large PHP codebases, extraction and the definitions pass complete normally, then pass=lsp_cross → parallel.resolve.start ... workers=15 never finishes. With the supervisor on it is reaped as outcome=hang signal=9; with it off it runs indefinitely.
It is not a clean deadlock and not steady progress — a livelock with unbounded memory churn: an initial ~99% CPU burst spikes RSS to multiple GB, then CPU collapses to ~10–18% while RSS thrashes up and down for the rest of the run, making no forward progress. Only CBM_DISABLE_LSP_CROSS=1 avoids it.
Result — hangs. Extraction fine (parallel.extract.done nodes=171136), then parallel.resolve.start files=19483 workers=15 and no parallel.resolve.done. Worker sampled during resolve:
Counter-check — same repo with CBM_DISABLE_LSP_CROSS=1 completes cleanly:status=indexed, 160,945 nodes / 530,740 edges. So the hang is isolated to the cross-file resolution pass.
(Independently reproduced on a private Symfony 5.4 / API Platform 2.6 app, ~3,700 files, identical signature — and on a framework-free php-only src/ copy with no vendor/config present, so it is not a vendor/framework artifact.)
It scales with cross-module reference density, not one bad file
Delta-debugging the private app (clean folders, php-only, fast): no single top-level directory hangs, and neither half of the source tree hangs — only the whole tree does. The pathology forms across the module graph and needs the full cross-reference density, consistent with a cyclic/superlinear type-resolution walk rather than a single pathological construct. (This is also why splitting a repo to minimize it makes the hang vanish.)
Root-cause signal: the PHP resolver has no step/parse budget
The C, TS, and Python resolvers self-limit and log it — [clsp] expression eval step budget exhausted, [tslsp] type-text parse budget exhausted, env CBM_TS_TYPE_BUDGET — and this exact pass's deadlocks were already fixed for those languages:
There is no equivalent [php_lsp] budget, and CBM_LSP_MAX_WALK_DEPTH=3 does not help — so the PHP path appears never to have received the step/recursion budget the other resolvers got.
Supervisor gap — a hang in the lsp_crosspass (not per-file extraction) has no file to quarantine, so CBM_INDEX_SUPERVISOR just SIGKILLs and restart-loops through CBM_INDEX_MAX_RESTARTS with zero forward progress. A pass-level timeout that skips/degrades cross-resolution would fail gracefully. (Relatedly, CBM_MEM_BUDGET_MB is not enforced as a hard cap here — RSS ran well past it.)
Version: codebase-memory-mcp v0.9.0 (macOS arm64, release binary)
Language: PHP
Mode: reproduces in
fastandmoderate.Summary
On large PHP codebases, extraction and the
definitionspass complete normally, thenpass=lsp_cross→parallel.resolve.start ... workers=15never finishes. With the supervisor on it is reaped asoutcome=hang signal=9; with it off it runs indefinitely.It is not a clean deadlock and not steady progress — a livelock with unbounded memory churn: an initial ~99% CPU burst spikes RSS to multiple GB, then CPU collapses to ~10–18% while RSS thrashes up and down for the rest of the run, making no forward progress. Only
CBM_DISABLE_LSP_CROSS=1avoids it.Public reproduction (Shopware)
Result — hangs. Extraction fine (
parallel.extract.done nodes=171136), thenparallel.resolve.start files=19483 workers=15and noparallel.resolve.done. Worker sampled during resolve:Counter-check — same repo with
CBM_DISABLE_LSP_CROSS=1completes cleanly:status=indexed, 160,945 nodes / 530,740 edges. So the hang is isolated to the cross-file resolution pass.(Independently reproduced on a private Symfony 5.4 / API Platform 2.6 app, ~3,700 files, identical signature — and on a framework-free php-only
src/copy with no vendor/config present, so it is not a vendor/framework artifact.)It scales with cross-module reference density, not one bad file
Delta-debugging the private app (clean folders, php-only,
fast): no single top-level directory hangs, and neither half of the source tree hangs — only the whole tree does. The pathology forms across the module graph and needs the full cross-reference density, consistent with a cyclic/superlinear type-resolution walk rather than a single pathological construct. (This is also why splitting a repo to minimize it makes the hang vanish.)Root-cause signal: the PHP resolver has no step/parse budget
The C, TS, and Python resolvers self-limit and log it —
[clsp] expression eval step budget exhausted,[tslsp] type-text parse budget exhausted, envCBM_TS_TYPE_BUDGET— and this exact pass's deadlocks were already fixed for those languages:cbm_pipeline_pass_lsp_crossdeadlocks on a specific.tsfile (no progress, ~3 CPU-s, indefinite) — fixed for TypeScript.py_eval_expr_typeinfinite recursion, fixed with a depth guard; Python parser hangs on deeply chained method calls during definitions pass #710 (closed) — Python parser hangs on deeply chained method calls — both Python hang fixes in the same resolution machinery.There is no equivalent
[php_lsp]budget, andCBM_LSP_MAX_WALK_DEPTH=3does not help — so the PHP path appears never to have received the step/recursion budget the other resolvers got.Two issues
lsp_crosslivelock / unbounded RAM — port the step/recursion/cycle budget from the TS (cbm_pipeline_pass_lsp_cross deadlocks on a specific .ts file (no progress, ~3 CPU-s, indefinite) #370) and Python (py_lsp: py_eval_expr_type infinite recursion — Python missed in 9f981a1 depth-guard fix #720/Python parser hangs on deeply chained method calls during definitions pass #710) fixes to the PHP type resolver, so cross-module resolution degrades (drop the edge / mark unresolved) instead of churning forever.lsp_crosspass (not per-file extraction) has no file to quarantine, soCBM_INDEX_SUPERVISORjust SIGKILLs and restart-loops throughCBM_INDEX_MAX_RESTARTSwith zero forward progress. A pass-level timeout that skips/degrades cross-resolution would fail gracefully. (Relatedly,CBM_MEM_BUDGET_MBis not enforced as a hard cap here — RSS ran well past it.)