Commit Graph
3346 Commits
Author SHA1 Message Date
Martin Vogel bedbc0ac00 Merge pull request #2345 from DeusData/fix/issue-2127
fix(pipeline): never bind an external Python import to a same-named project symbol (#2127)
2026-10-01 22:38:18 +02:00
Martin Vogel 7d4a12cb0a Merge pull request #2350 from DeusData/docs/cli-daemon-behavior
docs: one-shot cli commands use the shared daemon
2026-10-01 22:02:55 +02:00
Martin Vogel c61b3806bf Merge pull request #2449 from DeusData/fix/build-seams-and-cx-tmp
fix(build): make prod objects follow TEST_SEAMS; stop cx tmp leak
2026-10-01 19:19:26 +02:00
Martin Vogel 0bed0d372d Merge pull request #2327 from DeusData/fix/issue-1736
fix(grammar): accept a lone '&' in JSX strings and text (#1736)
2026-10-01 19:19:16 +02:00
Martin Vogel 28e24c6e51 Merge pull request #2324 from DeusData/fix/issue-1720
fix(install): adopt the Codex MCP table after Codex rewrites it (#1720)
2026-10-01 19:19:10 +02:00
Martin Vogel f67243ff0e Merge pull request #2320 from DeusData/fix/issue-1428
fix(extract): form Route nodes from NestJS @Controller/@Get decorators (#1428)
2026-10-01 19:19:04 +02:00
Martin Vogel ea7e01e91e Merge pull request #2445 from DeusData/fix/cypher-optional-join-overflow
fix(cypher): grow the OPTIONAL fallback buffer in the rel cross-join
2026-10-01 19:18:59 +02:00
Martin Vogel 77ea3bb95c Merge pull request #2407 from DeusData/fix/issue-1354
fix(ts-lsp): type imported class receivers for cross-file method calls (#1354)
2026-10-01 19:09:53 +02:00
Martin Vogel 3f0f49cd6c Merge pull request #2344 from DeusData/fix/issue-2134
fix(mcp): reuse the project that owns a root on unnamed re-index (#2134)
2026-10-01 19:09:46 +02:00
Martin Vogel 0be78a53a5 Merge pull request #2451 from DeusData/fix/pypi-publish-urllib3-2.8.0
build(pypi): bump urllib3 to 2.8.0 in the publish toolchain pins
2026-10-01 19:09:39 +02:00
Martin Vogel 41b1aeacfe fix(mcp): resolve the root owner for unnamed index status polls
With #2134, an unnamed index_repository of a root that another indexed
project already owns adopts that owner's name, and the daemon keys the
job by it (application_index_project_key reads the forwarded "name").
The unnamed status poll that the #2144 async reply asks for ("the same
repo_path and status: true") still derived its key from the path alone
in index_status_project_key. For an owned root it never found the job
it had just started and answered "no index job or index is known for
project '<path-derived>'"; an ambiguous root got that same misleading
answer instead of the loud error the start returns.

index_status_project_key now runs the start path's
index_root_owner_resolve on the same canonical repo_path: an explicit
name still wins, a single other owner is the key, several owners fail
with the same error naming them, otherwise the path-derived key stays.
The status error buffer grows to hold that owner list.

The daemon's other readers of the key (job dedupe in
application_job_subscribe_locked, the synchronous cut-short marker set
and taken around application_index_run_sync) derive it from the
forwarded args, which already carry the owner name, so they agree with
the start; status was the only reader that diverged.

Refs #2134, #2144

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-01 00:30:20 +02:00
Martin Vogel 492ae13557 chore(lint): release the #2127 import-filter strings through safe_free
The memory-core ratchet flagged src/pipeline/pass_pkgmap.c growing by 2 raw
allocator sites (82 -> 84). Both are frees of strings returned by
cbm_pipeline_fqn_compute and cbm_pipeline_resolve_module, which the core
never counted, so they now go through safe_free as the rest of the codebase
does rather than raw free or cbm_free. Behaviour is unchanged;
pass_pkgmap.c is back at its baseline of 82.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-30 23:41:55 +02:00
Martin Vogel 5acd91a39e fix(pipeline): never bind an external Python import to a same-named project symbol (#2127)
`from unittest.mock import patch` names a module outside the project.
Strategy 1 of cbm_pipeline_resolve_import_node cannot resolve it, so the
Strategy-3 symbol-name fallback bound the import to the only project
definition whose leaf is `patch` -- a REST view's PkgConfigView.patch --
and every `patch(...)` call became an import_map CALLS edge at confidence
0.95. Once that IMPORTS edge is gone the same call falls through to the
weak short-name strategies (unique_name 0.75, suffix_match), which bind it
again; `mock.patch(...)`, `json.loads(...)`, `os.path.join(...)` reached
project methods the same way, because the member guard exempts
import-rooted receivers.

Two per-language (Python-only) rules, both keyed on the import's module
chain rather than on any spelling list:

- Import side (pass_pkgmap.c, shared by both drivers): for an import
  whose module is not in the project, a Strategy-3 hit must spell the
  import's module chain as an ordered subsequence of its QN (a sys.path
  root or src/ layout the resolver missed still qualifies), and whatever
  names a module (an enclosing path segment, any segment of a plain
  `import x`) may only bind a Module/File node. Imports of project
  modules are unchanged (they may re-export from anywhere).
- Call side (pass_calls.c + pass_parallel.c, identical gates): a call
  whose root identifier is bound by an external import (no IMPORTS edge
  materialized it) and whose weak-strategy target contradicts that
  import's chain is not emitted as a plain CALLS edge. import_map /
  same_module / lsp_* edges are never touched.

django/django (parallel pipeline): CALLS 62,430 -> 60,123, TESTS
29,872 -> 28,571, IMPORTS 16,068 -> 15,491. Removed CALLS are
member calls through stdlib imports (1,900: os.path.join ->
defaultfilters.join, json.loads -> signing.loads, mock.patch ->
RedirectView.patch) and bare calls of stdlib names (398: date ->
defaultfilters.date, urlsplit -> MultiPartParser.parse); a random
25-edge sample was 25/25 false. Six IMPORTS are re-targeted to the real
definition (template_tests.utils.setup, multiple_database TestRouter,
pr_quality errors.Message).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-30 23:41:55 +02:00
Martin Vogel 3984795769 fix(ts-lsp): type imported class receivers for cross-file method calls (#1354)
A method call on an instance of a class defined in another file produced
no CALLS edge, while the identical code in the class's own file resolved
via lsp_ts_method. The type-aware tier typed the receiver wrongly in two
places, so the method lookup in the shared TS registry missed and the
call fell to method_not_in_registry:

1. `new C()` always qualified a bare constructor name against the
   CURRENT module. `const t = new ImportedClass(); t.m()` and
   `new ImportedClass().m()` were typed as a phantom
   `<this module>.ImportedClass`. The constructor type now follows TS
   scoping: a class declared in this module, else the class an
   unambiguous import binding names, else the old spelling.

2. ts_import_symbol_qn (and the copy of its heuristic in
   resolve_type_with_imports) treated an import value ending in
   ".<name>" as an already-qualified symbol QN. For the dominant TS
   convention of a file named after its class (`Foo.ts` exports
   `class Foo`, module `x.Foo`, class `x.Foo.Foo`), the receiver was
   typed as the MODULE, for `new`, annotations and parameters alike.
   The registry now decides the ambiguous case: a registered
   `module.name` wins, else the value is the symbol QN as before.

Both are resolved through the existing shared cross-file registry; no
name-based fallback is reintroduced. Cost is one or two hashed lookups
on the finalized overlay / sealed shared registry, per `new` expression
or per ambiguous import spelling during the walk; nothing is looked up
during registration and nothing is written to the shared registry.

typeorm (3,593 .ts files, shallow f279fd13): lsp_ts_method 2,551 ->
3,130, all 579 new edges cross-file (cross-file lsp_ts_method 696 ->
1,275), 0 edges lost, other strategies unchanged, index time
unchanged. 20 sampled new edges checked against source: 20 true
positives.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-30 23:06:27 +02:00
Martin Vogel c86be38954 docs: correct CLI-mode claim that one-shot commands never touch the daemon (#2183, #2167)
README.md:132, README.md:633, README.md:761, and docs/CONFIGURATION.md:203
said one-shot `cli` commands "never start or connect to the coordination
daemon" / read "their own environment without starting the daemon". That
was already contradicted a few lines above it (README.md:126 lists
one-shot CLI commands among the processes that "share a crash-safe OS
admission barrier" with the daemon) and by the code:
main_local_cli_daemon_execute() (src/main.c) bootstraps a client
connection to the shared per-user coordination daemon via
main_client_bootstrap_with_upgrade(), spawning one (bootstrap.daemon_spawned)
when none is running, before dispatching the tool call.

Verified live: `cli --verbose list_projects` against an isolated
HOME/CBM_CACHE_DIR/CBM_RUNTIME_DIR printed "hint: this command started a
temporary CBM daemon", and its cbm-daemon.log showed
daemon.start -> daemon.runtime_stopping (reason=last_committed_client_disconnected)
-> daemon.lifetime_end, i.e. the daemon it spawned exited again once the
CLI command's own connection closed. bootstrap_production_spawn() passes
the calling process's `environ` straight to posix_spawn(), so a CLI
invocation that starts the daemon also seeds that daemon's captured
daemon-owned environment (CBM_DIAGNOSTICS, CBM_LOG_LEVEL, etc.) - it does
not read "its own environment" independently as the docs claimed.

Corrected all four passages to state the real behavior: CLI commands
connect to the shared daemon (starting one if none is running) for the
same admission barrier and per-project locks, hold a `cli_session` that
is never registered with the background watcher, and - if their own
connection is what started the daemon - that daemon exits again once the
command's connection closes and no other session is attached. No opt-out
env var or flag for an in-process/no-daemon CLI mode exists (grepped the
whole tree), so none is documented.

This is a pure documentation fix; no production behavior changed. Kept
clear of PR #2348 (fix/issue-2167), which separately rewrites the
watcher-scope paragraph at README.md:152/237/672 and
docs/CONFIGURATION.md:88 for issue #2167's auto-sync-scope correction -
none of the lines here overlap with that diff.

Refs #2183, #2167

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-30 23:05:04 +02:00
Martin Vogel 3f99b2ddd3 build(pypi): bump urllib3 to 2.8.0 in the publish toolchain pins
urllib3 2.7.0, pinned in pkg/pypi/requirements-publish.txt for the
PyPI publish step, is affected by three advisories published on
2026-09-30, all fixed in 2.8.0:
- GHSA-8988-9cw3-xx77 (high): HTTPS proxy TLS configuration may be
  ignored or overridden
- GHSA-vxq7-64xx-v4gw (high): unbounded chunk-size line buffering in
  HTTPResponse.stream() / read_chunked()
- GHSA-gh4c-6fx4-qh6g (medium): chunked deflate streaming can loop
  forever

OSSF Scorecard reports them as code-scanning alert #33
(VulnerabilitiesID), which the CodeQL gate counts as an open alert,
so every PR's gate is blocked until the pin moves.

Only urllib3 changes. The file was regenerated with the documented
recipe (pip-compile 7.5.1 on a linux/amd64 python:3.12 image) in
upgrade-only mode (--upgrade-package urllib3==2.8.0), so every other
pin and hash is byte-identical. Both new hashes match PyPI's published
digests for urllib3-2.8.0-py3-none-any.whl and urllib3-2.8.0.tar.gz.

Proof: `pip install --require-hashes --no-deps -r
requirements-publish.txt` on linux/amd64 python:3.12 installs the full
set with every hash verified, imports urllib3 2.8.0, twine and build,
and `pip check` reports no broken requirements.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-30 22:55:43 +02:00
Martin Vogel e81fd499f8 fix(install): adopt the Codex MCP table after Codex rewrites it (#1720)
Codex rewrites its [mcp_servers] tables whenever it edits MCP servers
itself (`codex mcp add`, its MCP settings, wrappers such as Orca that
drive it) and drops comment decor on the way. From our managed block it
keeps the table but loses the begin marker, omits `args = []`, and leaves
the end marker as an orphan below whichever table follows. Reproduced
with codex-cli 0.153.4: after `codex mcp add orca -- /bin/echo hi` the
file holds an unmarked

  [mcp_servers.codebase-memory-mcp]
  command = ".../codebase-memory-mcp"
  env_vars = ["CBM_CACHE_DIR", "CBM_RUNTIME_DIR"]

and a stray `# <<< codebase-memory-mcp MCP <<<` under [mcp_servers.orca].

Every later install then failed with op=mcp_install on a table cbm itself
had written, twice over: cbm_toml_remove_legacy_table refused the orphan
marker as malformed, and its owned-shape check predated env_vars (#1562,
#1664), so even without the orphan the table counted as foreign.

cbm_toml_remove_legacy_table now drops a lone orphaned marker line in the
same atomic write (we are the only author of those markers, #1558; only
that line is removed, nothing is guessed) and treats env_vars naming only
CBM_CACHE_DIR / CBM_RUNTIME_DIR as part of the owned shape. A table with
any other key or forwarded name is still foreign and left byte-identical,
and a foreign table keeps the file untouched, orphan included. The scan is
split into toml_strip_legacy_table + toml_legacy_classify_assignment so
the entry point reads the file, heals, strips and writes once.

The same helper backs the Grok Build install, which gains the same
self-heal.

Tests: cli_upsert_codex_mcp_adopts_codex_rewritten_table uses the exact
bytes Codex produced; config_toml_legacy_remove_adopts_owned_env_vars_only
pins the env_vars boundary (owned names adopted, any other name foreign).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-30 22:27:19 +02:00
Martin Vogel 364dd6a99b test(mcp): compare the #2134 root with forward slashes on Windows
tool_index_repository_reuses_existing_project_for_root_issue2134 counts
how often the canonical repo root occurs in list_projects. On Windows,
cbm_canonical_path returns "C:\Users\...", while the stored root_path is
"C:/Users/...", so the count was 0 and the test failed on the CLANG64
leg (test_mcp.c:8448: owners == 0, expected 1).

Normalize the expected root with cbm_normalize_path_sep, a no-op on
POSIX, before counting.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-30 22:26:34 +02:00
Martin Vogel 1f0daaa915 fix(mcp): keep #2134 root-owner reuse out of cross-repo mode; portable test path
Linux, MSan, TSan and diag CI failed in mcp_mutation_guard:
tool_cross_repo_missing_inputs_fail_without_creating_ghost_databases
ASSERT(source_failed). handle_index_repository resolved the root owner
before dispatching cross-repo-intelligence mode. That test registers its
named target with the source's own root, so the unindexed source adopted
existing-cross-target as its project (log: index.root_owner_reused
project=existing-cross-target), and the missing source was no longer
reported. Cross-repo mode reads an existing source index and never writes
one, so the #2134 reuse now runs only on the re-index path, after that
dispatch. macOS CI stayed green because cbm_tmpdir() is /tmp, a symlink
to /private/tmp there, so the canonical repo_path never equalled the
fixture's stored root; with the fixture path canonicalized, the failure
reproduced 3/3 on macOS and passes 3/3 with this change.

The #2134 test itself called realpath() into a 1 KiB buffer. glibc's
FORTIFY check aborts on that ("buffer overflow detected", a SIGABRT of the
mcp suite on the ubuntu 2/3 shards), and MinGW has no realpath at all
(Windows compile error). It now uses cbm_canonical_path with a 4 KiB
buffer, the same canonicalizer production uses.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-30 22:26:34 +02:00
Martin Vogel b94afb4421 chore(lint): route the #2134 root-owner scratch through the memory core
The memory-core ratchet flagged src/mcp/mcp.c growing by 10 raw allocator
sites (784 -> 794) from index_root_owner_resolve and its caller. The owner
list buffer, which this code allocates and frees itself, now uses
cbm_realloc/cbm_free (class other). Strings handed over by other APIs
(cbm_project_name_from_path, heap_strdup, the index argument strings) are
released through safe_free, as elsewhere in the file, so no memory the core
never counted reaches cbm_free. Behaviour is unchanged; mcp.c is back at its
baseline of 784.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-30 22:26:15 +02:00
Martin Vogel 155d147e78 fix(mcp): reuse the project that owns a root on unnamed re-index (#2134)
index_repository without `name` derived the project key from the path
alone. When the root had first been indexed under an explicit name, a
later unnamed re-index forked a second index (same root_path,
path-derived name) and left the original untouched, so the stale index
kept being served while the call reported success.

Resolve the key from the indexes on disk before any work starts:
- the path-derived project exists -> keep it (unchanged behavior);
- exactly one other project owns the canonical root -> adopt its name
  and update it in place, so existing indexes are never orphaned;
- several projects own the root -> fail loudly, name them and ask for
  `name` instead of guessing or forking again;
- none -> first index under the derived name, as before.

The resolved name is written into the args handed to the daemon job
coordinator and the supervised worker, so the project lease key and the
index actually written stay the same project.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-09-30 22:26:15 +02:00
Martin Vogel 0f52d30c29 Merge pull request #2412 from DeusData/fix/activation-unknown-daemon-is-foreign
fix(cli): never stop a daemon whose cache is not confirmed as ours
2026-09-30 22:21:59 +02:00
Martin Vogel 878379a8af Merge pull request #2411 from DeusData/fix/harness-timeout-race-deterministic
test(harness): hold the scheduler contract's fixtures by construction
2026-09-30 22:21:53 +02:00
Martin Vogel f4ff01b10b Merge pull request #2410 from DeusData/fix/test-runner-isolate-runtime-dir
fix(test): isolate the C test runners' daemon runtime
2026-09-30 22:21:48 +02:00
Martin Vogel 8b8cafb616 Merge pull request #2409 from DeusData/test/daemon-ipc-startup-gate-no-timeout
test(daemon-ipc): wait for the startup gate event, not an attempt budget
2026-09-30 22:21:43 +02:00
Martin Vogel 218f0e5b78 Merge pull request #2408 from DeusData/test/watcher-poll-only-watched-deflake
test(watcher): poll-only-watched-projects waits for the watched reindex, not one poll
2026-09-30 22:21:35 +02:00
Martin Vogel 0bee4c1b79 Merge pull request #2406 from DeusData/fix/spill-test-disk-determinism
test(spill): make spill test verdicts independent of host free disk
2026-09-30 22:21:17 +02:00
Martin Vogel 48acb559e6 Merge pull request #2405 from DeusData/fix/internal-db-enumeration
fix(cli): never treat internal cache stores as project indexes
2026-09-30 22:21:11 +02:00
Martin Vogel 083bc99d80 Merge pull request #2404 from DeusData/fix/issue-2118
fix(mcp): annotate get_file_outline and ingest_traces as read-only (#2118)
2026-09-30 22:21:06 +02:00
Martin Vogel 39da5de00c Merge pull request #2403 from DeusData/fix/issue-1297
docs(readme): semantic_query is a search_graph parameter; team artifact is opt-in (#1297)
2026-09-30 22:21:00 +02:00
Martin Vogel d0ec2313d9 Merge pull request #2394 from DeusData/fix/issue-2184-post-extraction-budget
fix(pipeline): spill before the post-extraction phases when they would cross the budget (#2184)
2026-09-30 22:20:56 +02:00
Martin Vogel 6d19350e37 Merge pull request #2358 from DeusData/fix/issue-2311
docs(pipeline): CBM_EXTRACT_BUDGET is a CPU-time parse budget, not bytes (#2311)
2026-09-30 22:20:51 +02:00
Martin Vogel cb251ed472 Merge pull request #2357 from DeusData/fix/issue-2144
feat(mcp): opt-in async index_repository with status polling (#2144)
2026-09-30 22:20:46 +02:00
Martin Vogel 029919c660 Merge pull request #2355 from DeusData/fix/issue-2209
fix(install): Hermes hook edit no longer refuses unrelated YAML sections (#2209)
2026-09-30 22:20:30 +02:00
Martin Vogel 1ff6299976 Merge pull request #2354 from DeusData/fix/issue-2235
fix(extract): read the url of a JS/TS request-config object (#2235)
2026-09-30 22:20:23 +02:00
Martin Vogel 368f33f9e0 Merge pull request #2353 from DeusData/fix/issue-2200
test(cli): pin that update -y never deletes project indexes (#2200)
2026-09-30 22:20:18 +02:00
Martin Vogel 372aff2b5c Merge pull request #2351 from DeusData/fix/issue-2208
fix(cypher): carry the real node through WITH, not a name-only stub (#2208)
2026-09-30 22:20:14 +02:00
Martin Vogel 6746f43549 Merge pull request #2343 from DeusData/fix/issue-2133
fix(cross-repo): a pre-#768 store no longer aborts ["*"] or wipes edges (#2133)
2026-09-30 22:19:37 +02:00
Martin Vogel 94097f0727 Merge pull request #2341 from DeusData/fix/git-spawn-local-env
fix(git): clear git's repository-local env for cbm's own git children (#2003)
2026-09-30 22:19:32 +02:00
Martin Vogel 9df483f0af Merge pull request #2338 from DeusData/fix/issue-2044
fix(install): accept a Codex hook binary path that contains a space (#2044)
2026-09-30 22:19:27 +02:00
Martin Vogel 30a410b398 Merge pull request #2335 from DeusData/fix/issue-1955
fix(daemon): hash a verified peer image copy once, not on every HELLO (#1955)
2026-09-30 22:19:22 +02:00
Martin Vogel 78795ad76a Merge pull request #2339 from DeusData/fix/issue-2053
fix(rust): never let a std-typed receiver bind a same-named project method (#2053)
2026-09-30 22:19:17 +02:00
Martin Vogel 5910c47a97 Merge pull request #2332 from DeusData/fix/issue-1916
fix(pipeline): compose axios.create baseURL into HTTP_CALLS (#1916)
2026-09-30 22:19:12 +02:00
Martin Vogel e2f9fcc399 Merge pull request #2334 from DeusData/fix/issue-1951
fix(mcp): translate Git-root paths for subdirectory projects in detect_changes (#1951)
2026-09-30 22:19:07 +02:00
Martin Vogel 7821a1babb Merge pull request #2331 from DeusData/fix/issue-1827
fix(mcp): resolve projects by their non-ASCII folder name (#1827)
2026-09-30 22:19:02 +02:00
Martin Vogel 6bce86383e Merge pull request #2330 from DeusData/fix/issue-1783
fix(sqlite-writer): never end a B-tree level with a zero-cell interior page (#1783)
2026-09-30 22:18:48 +02:00
Martin Vogel 09819ba144 Merge pull request #2328 from DeusData/fix/issue-1743
fix(lsp): bound structured-binding field reads and TS method heritage walk (#1743)
2026-09-30 22:18:43 +02:00
Martin Vogel 0cff5dbe7c Merge pull request #2325 from DeusData/fix/issue-1735
fix(discover): skip Laravel's compiled Blade view cache by default (#1735)
2026-09-30 22:18:38 +02:00
Martin Vogel e9a3d18fbd Merge pull request #2322 from DeusData/fix/issue-1687
fix(daemon): name the WSL DrvFs remedy when a /mnt/<drive> cache is refused (#1687)
2026-09-30 22:18:33 +02:00
Martin Vogel f5ecb5f739 Merge pull request #2321 from DeusData/fix/issue-1457
fix(dart): index extension declarations and their members (#1457)
2026-09-30 22:18:27 +02:00