Repository navigation
Description
Version
codebase-memory-mcp 0.10.5
Platform
macOS (Apple Silicon)
Install channel
GitHub release archive / install.sh / install.ps1
Binary variant
standard
What happened, and what did you expect?
PHP builtin functions (sprintf, str_replace, exit) are being resolved to unrelated browser-side JavaScript functions in minified libraries, producing fabricated cross-language CALLS edges that violate runtime boundaries:
sprintf(...)in PHP server code → CALLS edge tosprintfinpublic/assets/libs/iCMS/iCMS.jsstr_replace(...)in PHP → CALLS edge tostr_replaceiniCMS.jsexit()in PHP → CALLS edge toexitinpdfmake.min.js
Runtime boundary violation: These edges represent server-side PHP process calling browser-side JavaScript closures — physically impossible at runtime. The only commonality is method name coincidence in compressed assets.
Measured impact (iCMS v8.0.0 project)
| Target | File | False edges |
|---|---|---|
sprintf |
public/assets/libs/iCMS/iCMS.js |
255 |
str_replace |
public/assets/libs/iCMS/iCMS.js |
217 |
exit |
pdfmake.min.js |
154 |
getMessage |
pdfmake.min.js |
53 |
define, trim, pack, ... |
various min.js | 72 |
Total: 751 fabricated PHP→JS edges (100% targeting assets/libs/*/min.js or vendor bundles)
Grep verification:
grep -r "sprintf\|str_replace\|exit" public/assets/libs/iCMS/iCMS.js # finds JS var names
grep -c "iCMS.js" app/ # 0 — server code never imports browser assetsConsequences
- Phantom callers: Browser libraries appear to be called by server code → dead-code analysis reports them as live
- Architecture pollution:
get_architecturehotspots rank browser utility functions as "core server logic" - Blast radius inflation: Impact analysis includes nodes that cannot be affected (server→client boundary crossed)
- Cross-service trace poisoning:
trace_pathreturns impossible call chains (PHP backend → browser frontend)
This is more severe than #2121 (C# BCL) / #2053 (Rust std) — those are same-language stdlib confusion; this is cross-language + runtime boundary violation.
Reproduction
Minimal setup
composer.json:
{
"name": "test/php-js-repro",
"require": {"php": ">=7.4"}
}public/assets/libs/compressed.min.js (browser bundle):
(function(){var sprintf=function(a,b){return a+b};window.util={sprintf:sprintf}})();app/Controller.php (server code):
<?php
namespace App;
class Controller {
public function render($template, $vars) {
// PHP builtin sprintf — server-side only
return sprintf("Template: %s", $template);
}
}Commands
codebase-memory-mcp cli index_repository --repo-path /tmp/php-js-repro --mode full
codebase-memory-mcp cli query_graph --project tmp-php-js-repro \
--query "MATCH (php)-[:CALLS]->(js) WHERE php.file_path ENDS WITH '.php' AND js.file_path ENDS WITH '.js' RETURN php.qualified_name AS caller, js.qualified_name AS callee, js.file_path"Expected vs Actual
Expected: Zero edges (PHP builtin sprintf is not a project symbol; browser compressed.min.js is never imported by server code)
Actual:
app.Controller.render → public.assets.libs.compressed.min.sprintf
Evidence (trace_path --function app.Controller.render --direction outbound):
callees_total: 1
sprintf hop 1 heuristic 0.75
file_path: public/assets/libs/compressed.min.js
Detection heuristic
All 751 false edges in the real repo match this pattern:
MATCH (php)-[:CALLS]->(js)
WHERE php.file_path ENDS WITH '.php'
AND js.file_path ENDS WITH '.js'
AND (js.file_path CONTAINS '/assets/' OR js.file_path CONTAINS '/static/'
OR js.file_path CONTAINS '/libs/' OR js.file_path CONTAINS 'min.js'
OR js.file_path CONTAINS 'vendor')
RETURN COUNT(*) AS false_edge_countResult on iCMS v8.0.0: 751 (100% false positive rate — no legitimate server-side require/import of browser assets)
Root cause hypothesis
- Builtin function blind spot: PHP
sprintf/exit/str_replaceare language builtins (no user-defined node) → indexer falls back to global name search - Cross-language namespace leak: Name resolution doesn't respect runtime boundaries (PHP process vs browser context)
- Confidence inflation: Heuristic edges carry 0.75-0.85 confidence → indistinguishable from real edges
Expected behavior
When the caller language and callee language differ:
- If edge type is
HTTP_CALLSorHANDLES: legitimate cross-language boundary (browser fetch → server route) → keep edge - If edge type is
CALLS: runtime boundary violation → either:- Emit no edge (preferred)
- Emit low-confidence marker edge (
cross_language_unverified) excluded from architecture/hotspot/trace queries by default
For builtin functions (sprintf, exit, define, etc.): should never produce CALLS edges to any project symbol.
Related issues
- BCL/external calls fabricate CALLS edges to unrelated internal classes (phantom callers; e.g. int.TryParse → internal TryParse) #2121: C# BCL → internal class (same-language stdlib confusion)
- Rust: std-typed receivers hijack same-named project methods, fabricating CALLS edges (37.6% of edges stdlib-shaped on 0.10.8) — minimal repro #2053: Rust std → project method (37.6% false edge rate)
- Python stdlib import binds to a same-named TypeScript function (cross-language, strategy=unique_name) — poisons hotspots and Louvain clusters #1572: Cross-language Louvain cluster pollution
This is the first reported instance of cross-language + runtime boundary violation (server→browser).
Project scale
Real repo (iCMS v8.0.0):
- 13,495 nodes / 65,573 edges / ~1,200 PHP files
- 751 false PHP→JS edges (1.1% of total edges)
- 100% targeting
assets/,libs/,vendor/, or*.min.js
Reproduction
Logs
Diagnostics trajectory (memory / performance / leak issues)
Project scale (if relevant)
No response
Confirmations
- I searched existing issues and this is not a duplicate.
- My reproduction uses shareable code (a dummy snippet or a public OSS repository), not proprietary code.
Activity
Carnival-z commentedon Sep 9, 2026
// src/pipeline/registry.c:resolve_name_lookup()
if (!import_vals || import_count == 0) {
return empty_result(); // 拒绝 unique_name / suffix_match
}
maybe can fix this bug
DeusData commentedon Sep 25, 2026
Thank you so much @Carnival-z for such a thorough report. The measured impact table, the minimal three-file repro and the detection query made this quick to confirm.
We reproduced it on current
main: the PHP call binds to the one same-named function in the minified JS bundle withstrategy=unique_name,candidates=1. The resolver sees exactly one symbol with that name in the whole project and accepts it without checking the language. Our cross-language CALLS guard (#1647) already drops the ambiguoussuffix_matchcase but deliberately left this single-candidate case for a follow-up. That follow-up is tracked in #1572 (a Pythonpatchbinding to a TSX function, the same mechanism), and @rudi193-cmd has an open PR, #1702, that extends the guard tounique_namefor every language pair outside a shared family; PHP to JS is covered.So we're closing this as a duplicate of #1572 to keep the work in one place. Your PHP/JS case is a valuable second fixture, and we'll ask for it to be added to #1702's tests. On the suggestion in your comment: returning an empty result whenever a file has no imports would also drop many correct same-language edges, so the fix targets the language boundary rather than import presence. Thanks again, this helps make the graph more trustworthy.