Index Java and Kotlin definitions with an internal <jvm-default-package> key in src/pipeline/pass_lsp_cross.c so cbm_pxc_filter_defs_for_file() retains sibling-file declarations when no package header exists. The hash table rejects empty keys, which previously removed Algo.kt::maxOf before cross-file resolution.
Initialize cbm_run_kotlin_lsp_cross() with the file module QN so default-package caller identities match extracted graph QNs such as <project>.Main.run. In pxc_append_results(), index resolutions by caller and callee short name and let an equal-confidence project-wide result replace the earlier per-file guess; this changes kotlin.comparisons.maxOf to <project>.Algo.maxOf without adding O(n^2) scans.
ASan/UBSan validation: lsp_resolution_probe passed 83/83, kotlin_lsp passed 79/79, java_lsp passed 379/379, and parallel passed 36/36. The focused lrp_kotlin_s7_generic debug run resolved one CALLS edge from <project>.Main.run to <project>.Algo.maxOf. git diff --check passed.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Make tests/test_parallel.c::extraction_errors_are_nonfatal_in_parallel_and_sequential_paths enforce the skip-and-report contract used by cbm_parallel_extract() and cbm_pipeline_pass_definitions(): unsupported-language files return success, leave result_cache empty, and do not mutate the graph. Run-level allocator, worker, merge, and OOM failures remain fatal in src/pipeline/pass_parallel.c and src/pipeline/pass_definitions.c.
Prevent src/pipeline/pass_httplinks.c::discover_node_routes() from rescanning decorators when definition extraction already stored route_path. This removes the unprefixed /orders and /orders/{id} clones beside /api/orders and /internal/v1/api/orders while retaining decorator discovery for legacy nodes without route_path.
ASan/UBSan validation: CBM_ONLY_SUITE=parallel build/c/test-runner passed 36/36; CBM_ONLY_SUITE=edge_types_probe build/c/test-runner passed 55/55, including handles_spring_java and handles_spring_kotlin exact-route assertions. make -f Makefile.cbm lint-source-safety and git diff --check passed.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Route filesystem project arguments through get_store_project_arg() so resolve_project_store() can auto-index paths without breaking #1025 unique-tail slug resolution or manage_adr path normalization. Append one-shot _context data to TOON search responses and keep query_graph compatible with in-memory stores.
Publish subprocess child PIDs atomically, migrate UI indexing to cbm_subprocess_run(), enforce spawned-process ownership on process-kill, use per-slot log files, and defer MCP store invalidation to the request thread. Replace signal-handler fclose(stdin) with atomic stop plus close(0), and give autoindex_thread its own store handle.
Treat recorded oversized-file skips as nonfatal while preserving OOM failures; clamp finish_data_flow_props() snprintf offsets; align TOON tests with explicit format=json assertions; use cbm_resolve_cache_dir() in index resilience tests.
Validated: ASan/UBSan MCP 216/216, input_validation 45/45, tool_consolidation 100/100, token_reduction 50/50, depindex 35/35; pipeline and subprocess suites passed; make -f Makefile.cbm cbm built and signed; lint-source-safety and source-safety-test passed.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Merge upstream/main at 2469ecc3 into integrate-upstream-split-search-tools while retaining branch-specific incremental indexing, MCP API consolidation, and graph extraction behavior.
The staged tree adds upstream's Mojo and Perl grammar support, issue reproduction suites, Graph UI changes, Windows smoke coverage, TOON graph output, subprocess supervision, and Laravel facade route handling. Conflict resolutions in src/pipeline/httplink.c and pass_httplinks.c retain dynamic growth and IMPORTS edge identity; scripts/smoke-test.sh and scripts/soak-test.sh retain hermetic cache isolation.
Validation against the merge plus the follow-up working-tree reconciliation: ASan/UBSan MCP suite 216/216 passed. Follow-up semantic and concurrency fixes remain intentionally unstaged for the next focused commit.
Measure idle CPU from process CPU-time deltas instead of the lifetime average reported by ps. Expose user and system CPU counters in diagnostics, validate configurable idle and response limits, and fail closed when the server or its protocol pipe exits.
Disable session-CWD auto-indexing inside the explicit-index soak harness so unrelated repository work cannot contend for the pipeline lock, inflate cache/RSS results, or masquerade as idle CPU. Preserve crash/restart coverage and exact cleanup of harness-owned resources.
Validated with the ASan/UBSan MCP suite (171 tests), a bounded 30-second idle soak with crash recovery (0.0% idle CPU, 197 MiB RSS, stable cache/FDs), shell syntax and ShellCheck, source-safety lint, clang-format diff, configuration rejection cases, and diff hygiene.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
The watchdog test killed its wrapper as soon as the child PID file appeared. That could race main startup, let the child capture an already-reparented PID 1, and intentionally disable parent-death detection.
Wait for the configured info-level memory initialization marker emitted after watchdog creation before killing the wrapper. Name the startup and exit polling bounds so the lifecycle contract is explicit and repeated runs are deterministic.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Prevent both overlay producer opportunities from publishing file-scoped rows when a changed file introduces a parent Folder that does not exist canonically. Such overlays cannot represent the shared structural context and previously produced an active graph with one missing folder node.
Check each normalized changed-path ancestor through the existing indexed node-by-file-path store query. Root files require no lookup, returned node arrays are released immediately, existing-folder edits remain overlay-eligible, and missing, invalid, or failed lookups fall through to the proven canonical exact publisher.
Enable the registered small-delta overlay policy in the new-folder parity regression and require canonical exact publication plus fresh-rebuild equality. Validate complete native and ASan/UBSan pipeline suites (354/354 each) and eight current CLI matrix routes with exact canonical or active-overlay graph gates and owned-root cleanup.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Generalize the existing fresh FAST rebuild comparator with an explicit index mode while retaining the FAST wrapper for all existing callers. Use contextual snapshot and error names so the helper describes its canonical graph role.
Require FULL incremental indexing to match a fresh FULL rebuild, and require a changed FULL-to-FAST additive transition to match the same fresh FULL oracle. Select eager derived refresh through the registered config policy while preserving assertions for skipped-file and sibling-project persistence.
Validate the complete pipeline suite under native and ASan/UBSan runners (354/354 each) with no canonical diff or sanitizer diagnostic. Changed-line formatting, diff hygiene, and source-safety checks pass.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Replace the database-loss recovery node-count tolerance with the shared canonical graph oracle. The test selects eager derived refresh through the registered incremental configuration policy so its incremental baseline and clean recovery rebuild have equivalent semantics.
Prune nested Folder nodes that lose their last contained file or child folder before graph-wide incremental post-passes. Run the scan only when classification reports deleted files, allocate temporary path storage to the exact folder count, free it on every exit path, and fail closed on graph errors.
Add focused nested-folder lifecycle coverage and validate the complete ordered incremental suite under native and ASan/UBSan runners (161/161 each), with no canonical drift or sanitizer diagnostic. Changed-line formatting, diff hygiene, and source-safety checks also pass.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Replace the formatter tolerance with a canonical incremental-versus-clean graph comparison and preserve mismatch artifacts for diagnosis.
Preseed containment increments with the repository package map, suppress ambiguous Python super constructor suffix matches consistently across sequential and parallel resolution, and restore captured inbound edges before graph-wide semantic derivation.
Keep the package map and edge snapshot lifecycles bounded, use the integrated derived-refresh configuration, and cover the false clean-reference call with a focused regression.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
The complete TSan gate applied native LSP timing ceilings because the benchmark harness only recognized AddressSanitizer. That produced a false C# benchmark failure after 6,443 otherwise passing tests, even though no data race was reported.
Add portable shared detection for GCC and Clang address/thread sanitizer builds. Keep native and instrumented timing policies as explicit, benchmark-specific named constants, and apply the same logic to the C# and Python LSP benchmarks.
Validated focused C# and Python benchmarks under TSan, ASan/UBSan, and no-sanitizer builds. Native ceilings remain unchanged.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Treat an unindexed project-qualified LSP target as an internal declaration rather than an external symbol. This lets the registry select the canonical cross-file definition while retaining weak-match suppression for unqualified third-party and explicit external targets.
Align the parallel call resolver with the sequential route by consulting the registry after an LSP graph miss and applying the same containment guard. Add a regression for the C/C++ forward-declaration shape while preserving the existing external and Python super-init false-positive tests.
Validated with no-sanitizer pipeline (353/353), parallel (31/31), edge-structural (32/32), and LSP-resolution-probe (83/83) suites. Repeated the affected matrices under ASan/UBSan and TSan; all passed with no sanitizer report. Changed lines pass the configured clang-format check and git diff --check.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Expose extraction deadlines through the existing configuration registry with a documented default and explicit lower and upper bounds. Propagate the selected deadline through sequential, parallel, incremental, semantic, usage, call, and infrastructure extraction paths so every route applies the same policy.
Keep sanitizer-specific test headroom in test configuration rather than production constants, and verify default registration plus both clamps. Extraction failures continue to fail closed, preserving the previously published database instead of persisting partial graphs.
Validated with the 352-test pipeline suite, 161-test incremental suite including exact 15,956-node/55,790-edge equality, 31-test parallel suite, focused TSan worker-pool and parallel suites, and a complete TSan run with no race report. The complete runner reached 6,418 passes and 25 pre-existing red graph-capability failures, which remain the next tracked blocker.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Treat parser, allocator, and unsupported-language errors as failed indexing operations in both sequential and parallel extraction paths instead of publishing file hashes with missing semantic nodes. Preserve valid zero-byte files, aggregate worker errors independently of local graph allocation, and keep cleanup ownership balanced on every failure path.\n\nAdd a regression covering empty-file success and fail-closed behavior across both extraction modes. The FastAPI incremental/full oracle now matches exactly at 15,956 nodes and 55,907 edges, the full incremental ASan/UBSan suite passes 161 tests, and the complete parallel and pipeline suites pass. Instrumented RSS remains diagnostic while the production ceiling stays enforced on comparable builds.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Preserve caller-owned package maps on exact and overlay routes while making ordinary parallel extraction explicitly own map replacement. Release the published map before the successful incremental early return so it cannot become process-global unreachable state.\n\nAdd a 64-file module-backed incremental regression that exercises the parallel route and asserts the global package map is cleared. The focused macOS native leak check now reports zero leaks, and the complete ASan/UBSan pipeline suite passes.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Make the C runner own its default isolated cache lifecycle. Remove the exact runner-created root before a green summary, preserve failed and crashed runs for diagnosis, and fail closed when cache setup or cleanup cannot complete.
Retain an atexit fallback for early returns without allowing forked _exit children to delete the parent cache. Add a test-only cleanup failure injection so lifecycle error propagation is reproducible.
Validated with a rebuilt ASan/UBSan runner: green runs removed every owned cache, an ordinary red test retained its root and exited 1, and injected cleanup failure retained its root, incremented the failure count, and exited 1. Exact retained roots and obsolete rollback artifacts were removed after verification.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Route default full reindexes through the existing transactional project-replacement path when the database is structurally valid or has only cosmetic path metadata defects. This preserves SQLite ADRs and sibling dependency projects while retaining atomic rewrite for unreadable or structurally corrupt stores.
Report ADR presence from the canonical SQLite backend in index and graph-schema responses, with legacy-file fallback for unmigrated installations.
Validated with rebuilt production and ASan/UBSan binaries, 171/171 MCP tests, 350/350 pipeline tests, exact ADR and sibling-project regression coverage, a real default-policy reindex round trip, signature verification, formatting, diff hygiene, and source-safety checks.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Encode nonstandard ASCII control bytes as complete \u00XX sequences instead of silently dropping them. Preserve the existing truncate-before-partial-escape behavior for bounded destination buffers.
Add regression coverage for mixed control characters and exact output length. Validated with the rebuilt ASan/UBSan runner (66/66 str_util tests), strict compilation, changed-hunk formatting, diff hygiene, and source-safety checks.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Restore the upstream query-only leak workflow and timeout budgets so multi-hour jobs are neither dormant nor truncated. Preserve mixed-workload behavior while adding a dedicated read-only mode across Linux, macOS, and Windows.
Run every soak in an isolated project/cache/FIFO root, clean owned servers and diagnostics on normal or abnormal exit, and convert MSYS paths before placing them in JSON or environment variables. Validate initialize and tool responses, retain failure state across crash recovery, inject the crash before waiting for an index response, and require a checked post-restart reindex.
Record cache, database, and WAL sizes alongside RSS and FD metrics. Use post-index peak/final ratios and long-run slope as the portable default memory gates; keep an explicit CBM_SOAK_RSS_MAX_MB override for measured platform budgets instead of the obsolete universal 200 MB ceiling.
Validation:
- bash -n scripts/soak-test.sh
- shellcheck -x scripts/soak-test.sh
- actionlint on soak workflows
- source-safety and diff hygiene
- zero-minute product lifecycle smoke: passed
- asynchronous crash/restart/reindex smoke: passed
- one-minute query-leak run: 106 RPCs, zero failures
- invalid config and failed-server cleanup paths: rejected and cleaned
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Make install.ps1 preserve an existing executable before replacement, treat nonzero native --version status as verification failure, and restore the prior binary when copy or verification fails. Abort safely if the existing executable cannot be preserved instead of risking an unrollbackable overwrite.
Remove the rename-aside backup only after the new binary verifies and place the complete download/extract/install flow under a finally cleanup so temporary cbm-install directories are removed on success, explicit exits, and unexpected errors.
Strengthen the existing Windows smoke path to seed an installed binary, fail on installer errors, and reject an orphaned .old backup after successful replacement.
Validation: bash syntax; source-safety and protocol stdout checks; isolated install security audit; repository PowerShell grammar parse with zero extraction errors; diff hygiene. Native PowerShell replacement execution remains covered by the Windows CI smoke job because PowerShell is unavailable on this host.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Preserve whether a full publication was reached through an attempted incremental route and expose that provenance in index_repository responses. Map those safe replacement fallbacks to a distinct rank-refresh event without changing the canonical publish_kind=full contract.
Under the default stale_on_incremental policy, defer synchronous PageRank, LinkRank, and degree recomputation only when replacement metadata has already marked all rank views stale and no dependencies were reindexed. Eager and stale_on_exact policies still recompute; search, trace, and architecture surfaces omit stale rank values and emit freshness warnings until a later refresh.
This adds no background worker or retained resource. Pipeline provenance resets on every run, callers copy it before freeing the pipeline, and existing store/query lifecycle rules own stale-ledger cleanup and subsequent refresh.
Measured on the canonical route-handler self-dogfood scenario: rank refresh fell from 7,669 ms to 0.02 ms and the observed fresh-over-incremental speedup was 7.37x, with canonical graph equality, stale-warning oracles, and temporary worktree/database cleanup all green. End-to-end timing remains resource-sensitive.
Validation: signed product build; sanitizer test build; PageRank suite (59 passed); MCP suite (171 passed); pipeline suite (349 passed); C full-fallback canonical canaries (2 passed); source-safety check; route-handler canonical self-dogfood.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Replace per-node SQLite upserts during graph-buffer publication with a set-oriented temporary-table batch and deterministic ID remapping. Keep the batch inside the caller-owned replacement transaction so sibling projects remain intact and every failure rolls back the full project replacement.
Finalize all temporary statements, clear connection-scoped staging state before reuse, free node and ID arrays on every success and failure path, and reject invalid temporary IDs before map access. Add transaction rollback coverage and strengthen graph-buffer persistence assertions.
Measured the targeted span at 89 ms for 13,455 nodes in the canonical route-handler self-dogfood scenario. The scenario remained canonically equivalent with cleanup green; synchronous rank refresh remains the dominant end-to-end blocker.
Validation: product build; sanitizer build; source-safety check; store node suite (114 passed); graph-buffer suite (67 passed); pipeline suite (349 passed); focused C source-frontier canonical canaries (2 passed); route-handler canonical self-dogfood.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Strengthen the default-cap overflow canary with a graph-changing C source mutation so the full-rebuild safety route proves canonical parity for changed definitions and calls.
Add configured-cap coverage showing that the same mutation can publish an exact delta and remain canonical when its complete inbound frontier fits within a cap of 16.
Keep the conservative default cap unchanged. Existing real-repository evidence shows that cap inflation alone increases work, often still overflows, and can become slower or non-canonical for broad frontiers.
Validated with the sanitizer test-runner build, both C source frontier policy canaries, source-safety checks, and git diff validation.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
Route oversized C-family source frontiers to a full rebuild so stale cross-file call edges cannot survive containment fallback.
Refresh the watcher baseline before releasing the pipeline lock after explicit indexing, closing the race that could launch a redundant full-mode reindex over a fresh FAST database.
Align the sequential/parallel environment-edge oracle with function-owned graph edges and add canonical-equality coverage for C source fallback.
Validated with product and sanitizer builds, source-safety checks, 171 MCP tests, 348 pipeline tests, focused watcher and fallback canaries, and a five-scenario self-dogfood matrix with canonical equality and cleanup in every case.
Signed-off-by: Andrew Hundt <ATHundt@gmail.com>
The previous commit's clang-format -i rewrote all of
test_edge_types_probe.c (+732/-358 for a 48-line test addition) - my
local formatter's whole-file drift, not real non-conformance (lint-ci
passes on the restored file). Restore the file to main's formatting
with only the two #952 tests added.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Real Laravel apps register routes through the Illuminate facade, whose
class lives in vendor/ and is never indexed - and for that style the
graph minted ZERO Route nodes, flat or grouped. Three stacked defects:
1. The callee of Route::get(...) (scoped_call_expression) was
extracted as bare 'get' via generic field resolution, so the
empty-resolution route fallback ('::get' suffix table) could never
engage. The extractor now emits the qualified 'Route::get' form,
gated to the literal Route scope AND a route-method table match so
Cache::get / Config::get keep bare names and can never mint junk
(guarded by an inverse test; the path gate additionally requires a
leading '/').
2. The sequential pass had no ROUTE_REG empty-resolution fallback at
all (its comment claimed parity with the parallel path, which has
one) - unresolvable route registrations were dropped entirely.
Added, mirroring the parallel callee_suffix fallback.
3. Nothing composed enclosing prefix()->group() chains (same class as
Spring's #734). At extraction - the only place the AST still exists
- each route call inside group closures now walks its ancestors:
every enclosing closure that is the argument of ->group(...)
contributes the prefix('...') found on that group call's receiver
chain, outer-to-inner for nested groups; middleware/name/domain
chain links are skipped.
The existing handles_laravel_php test kept passing throughout because
its fixture defines an in-tree Route class, resolving by QN - which is
exactly how this class stayed unseen.
Closes#952
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Layer 2 of #996, forced by the new guard going RED on the Windows CI
leg with the writer fix alone: _environ holds ANSI-code-page bytes,
not UTF-8, so a non-ASCII USERPROFILE or CBM_CACHE_DIR arrives either
mojibake'd or with unrepresentable characters replaced by '?' - which
is invalid in Windows paths, so every downstream wide-safe file API
fails no matter how correct it is. cbm_safe_getenv now reads the value
via GetEnvironmentVariableW and converts to genuine UTF-8
(cbm_wide_to_utf8), matching the UTF-8-path convention the rest of the
codebase assumes; missing variables honor the fallback as before, and
conversion trouble falls back to the ANSI scan rather than failing.
POSIX untouched.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The 8e gate compared uname -s to the bare literal MINGW64_NT, which
never matches the real value (MINGW64_NT-10.0-...), so the POSIX
branch silently ran on Windows and looked for the extensionless shim
that #929 no longer installs. Branch by platform prefix: Windows
expects the .cmd shim and the absence of the legacy extensionless
twin; POSIX unchanged. Content checks (never blocks, delegates to
hook-augment) now run on both.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
cbm_writer_open used a raw ANSI-CP fopen for the hand-rolled SQLite
writer - the one file-creating call on the dump chain without a
UTF-8-to-wide conversion. On a non-ASCII Windows profile
(C:\Users\Kovacs Janos) extract and resolve succeeded but the dump
failed with pipeline.err phase=dump: fopen could not create graph.db
under the profile-derived cache dir while cbm_mkdir_p (already wide)
had happily created the directory around it. Routed through cbm_fopen,
matching #700 (pass readers) and #973 (canonicalization); POSIX is
byte-transparent.
New Windows guard test_non_ascii_cache_dump.py indexes an ASCII repo
into a non-ASCII CBM_CACHE_DIR and requires a query_graph readback
with Function count > 0 - proving the DB was written to and reopened
from the non-ASCII cache, not merely that no error surfaced. The
existing non-ASCII guard only varied the repo path against an ASCII
cache, which is why this class went unseen.
The USERPROFILE-sourced env encoding question (Layer 2 - _environ is
ANSI-CP, not UTF-8) is deliberately not bundled; it needs verification
on a real Windows box and will be filed separately if the guard alone
does not settle it.
Closes#996
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Extensionless bash shims under %USERPROFILE%\.claude\hooks triggered
the Windows 'How do you want to open this file?' dialog whenever an
editor (Cursor) scanned the hooks dir, and could not execute without
bash anyway. All three Claude hook scripts (discovery gate, session
reminder, subagent reminder) now install as .cmd files with cmd syntax
on Windows - @echo off bodies, caret-escaped pipes in the reminder
text, 2>/dev/null redirects - and the install removes the pre-existing
extensionless twin so upgrades stop triggering the dialog. The
settings.json command paths follow automatically since they are built
from the same script-name macros. POSIX behavior is byte-identical and
guarded (no .cmd twin).
Closes#929
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
ha_deadline_ms was defined unconditionally but only used by the POSIX
ha_arm_deadline - unused-function under -Werror broke every Windows
leg. The knob, its constants and the doc comment now live inside the
same #ifndef _WIN32 block as the deadline machinery they configure;
Windows continues to rely solely on the settings.json hook timeout.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Aider has no MCP support - it reads CONVENTIONS.md but can only run
shell commands. The installer wrote the shared MCP-tool-centric
instructions there, telling the model to call search_graph(...) etc.,
tools Aider cannot invoke; a reporter reasonably asked how that was
ever supposed to work (#1032).
Aider now gets a dedicated variant: the same discovery priority
expressed as runnable codebase-memory-mcp cli commands (usable via
/run), including first-index and list_projects bootstrapping, with the
no-MCP constraint stated explicitly.
Closes#1032
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The 300ms in-process SIGALRM budget in hook-augment self-terminated
with a silent _exit(0) on real cold starts (SQLite/mmap open under
load), so PreToolUse augmentation never appeared in real sessions
(reporter: 0/24 observed) while warm manual invocations worked - and a
fired deadline was indistinguishable from a legitimate no-match run.
Default budget is now 2000ms (the settings.json hook timeout stays the
outer backstop), overridable via CBM_HOOK_DEADLINE_MS (clamped
50..10000). When the deadline fires, the handler write()s a
pre-formatted breadcrumb (deadline, pid, the env knob to raise) to
~/.cache/codebase-memory-mcp/logs/hook-augment-timeouts.log before
exiting - fd and message are prepared at arm time so the handler stays
async-signal-safe; CBM_HOOK_TIMEOUT_LOG overrides the path for tests.
Windows keeps relying on the settings.json timeout (unchanged no-op).
Deterministic reproduction: stdin is a pipe whose writer never sends,
so the read blocks past a 60ms deadline - the timer must fire, exit 0
(fail-open), and leave the breadcrumb. RED before (no breadcrumb),
GREEN after.
Closes#858
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Agents naturally pass the repo folder name (codebase-memory-mcp), but
indexed project names derive from the full path (E:\project\graph\x
-> E-project-graph-x), so every graph tool answered 'project not found
or not indexed' while list_projects clearly showed the project.
get_project_arg now falls back to a cache-dir filename scan when no
<project>.db exists: a passed name matching exactly ONE indexed
project as a segment-aligned tail (-<name>.db) adopts that project's
full name (logged); zero or several matches keep the original name so
the existing not-found error with the candidate list fires. Exact
names never enter the scan, and internal-name drift stays #704's
fallback in resolve_store.
Closes#1025
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
cbm_pipeline_fqn_compute strips the file extension, so a C/C++ header
and its same-stem source collide on both the module QN and the File
QN. Node upserts match by QN, so the header's File node is merged into
the source's - the header has no node of its own and can never receive
an inbound IMPORTS edge; the reporter's zero-inbound query flags 194
of 214 files.
The module-QN unification is (at least partly) load-bearing for C/C++
declaration/definition call joins, and the File-node creation sites
overlap PR #995's pending fix for #994, so the fix is deferred to land
on top of that. This RED reproduction (non-gating repro tier) keeps
the bug tracked until then. Refs #964
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A function whose body braces are split across #ifdef/#else branches
(one open brace per branch, a single shared close) parses with an
ERROR region on the raw source - both branches are present at once, so
the braces are unbalanced - and the defs walk silently dropped it
while its callers stayed as unresolved names (cbm_path_within_root,
handle_process_kill).
The preprocessed second pass (simplecpp) already exists for macro-
hidden CALLS; it evaluates the conditionals, so one branch is chosen
and the expanded tree parses clean, with same-file token lines aligned
to the original. Recover definitions from it, adopting only defs that
(a) intersect a raw-tree ERROR region, (b) have their name visible on
the corresponding original source line (rejects header-inlined defs
whose physical expanded lines alias unrelated raw lines when
compile_commands include paths resolve), and (c) are absent by
qualified name from the raw pass.
Verified on the real instances: handle_process_kill (580-647) and
cbm_path_within_root (5070-5085) both index with correct line ranges.
Closes#961
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The #599 receiver-aware narrowing (87091ed) shipped without coverage
for the delegation/store bucket reported in #876: same-named calls
whose receiver is a call result (_get_store().get inside get), a
module singleton (_default.check inside check), or a loop-local cursor
(cur.execute inside execute). All three are clean on current main;
this guard pins the bucket so it cannot regress. Refs #876
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
cbm_store_find_node_by_id heap-allocates the node's string fields;
the #871 helper left them unfreed, tripping LSan on the Linux legs.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A persistently dirty or untracked worktree re-triggered a full reindex
(and its DB/artifact rewrite) on every poll cycle - git_is_dirty()
answered 'is the tree dirty' where the watcher needs 'did the tree
CHANGE'. Idle repos with one uncommitted file produced sustained disk
write amplification (reported at 1 TB/day across several repos).
The watcher now tracks a dirty-state signature: FNV-1a over the
entries of git status --porcelain -uall -z plus each listed path's
(size, mtime_ns). Same signature -> no reindex; editing a dirty file,
adding/removing one, or reverting the tree to clean each produce a new
signature and trigger exactly one reindex. Submodule status is folded
in on POSIX, mirroring the old submodule dirty probe. 0 is reserved
for a clean tree; a dirty-at-baseline tree still reindexes once (the
watcher cannot know whether that state reached the DB, e.g. after a
server restart with a stale artifact).
Baselines (HEAD and signature) are now committed only after a
SUCCESSFUL reindex: check_changes stages observations in pending_*
fields, and busy-skips (index_fn > 0, e.g. pipeline lock held) or
failed runs leave the baselines untouched so the change is retried on
the next poll instead of being recorded as seen and silently lost -
the old code stored the new HEAD at check time, dropping any commit
that arrived while the pipeline was busy.
Closes#937
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>