PR #840 flips the lrp_ts_s6_inherited_method probe from a fragile
false-green (a unique_name short-name registry guess that happened to
bind the right node in a 2-file fixture) to asserting the weak edge is
suppressed. That flip is correct, but it leaves the underlying gap —
ts_lsp cross-file INHERITED method call resolution — with no red
reproduction anywhere.
Add tests/repro/repro_ts_inherited_method.c to the non-gating repro
suite: base.ts defines Base.greet, derived.ts has Derived extends Base
and a typed call site d.greet(). A GREEN precondition test proves both
files extract cleanly, the Base.greet Method def exists and the call
site is extracted; the RED pipeline test additionally verifies the
callee node and the INHERITS edge are in the graph, then asserts the
correct outcome: a CALLS edge callSite -> *.Base.greet carrying an
lsp_ts_* strategy on that same edge. The pre-#840 lucky unique_name
fallback edge does not satisfy it (verified: the run dumps that exact
edge, strategy unique_name, confidence 0.75), and post-#840 suppression
yields no edge at all — so the test stays RED until ts_lsp genuinely
resolves cross-file inheritance. Guards the gap left visible after
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
#840's probe flip; see the test header for the root-cause pointer.
Since #667 every file in a Java/Go package shares a directory-based module
QN that collides with the pipeline's Folder/Project node. Class-level
references resolved their enclosing scope to that shared node, whose
file_path was clobbered by each file's always-emitted Module def — last
writer wins (sequential upsert) or last-merged worker wins (parallel merge)
— so USAGE-edge sources conflated across same-package files and varied run
to run.
Three coordinated changes:
- cbm_gbuf_upsert_node: a Module def colliding with a Project/Folder node
no longer updates ANY field (the #667 guard only protected the label).
- merge_update_existing: same guard on the parallel worker-gbuf merge path;
the ID remap stays outside the guard so worker edges still redirect onto
the canonical node.
- Source-node finders (pass_usages, pass_parallel, pass_calls) treat a
lookup landing on a Folder/Project container as a miss and fall back to
the per-file File node (new cbm_pipeline_node_is_dir_container helper).
Adds tests/repro/repro_issue787.c: exact-source-set, 5-run stability, and
>50-file parallel-path guards (red on the unfixed code in both sequential
and parallel flavors).
Distilled from #828: the author's commits lacked DCO sign-off trailers and
could not be cherry-picked; content applied verbatim plus one clang-format
fix in graph_buffer.c.
Closes#787.
Co-authored-by: Tommy Corbett <spde89@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A single pathological file that hard-crashes the native indexer (SIGSEGV / stack
overflow / abort / tree-sitter assertion) previously took down the whole MCP
server or CLI (issue #668). index_repository now runs in a worker subprocess: the
parent reaps it, and a crash is contained — the parent survives and reports it
instead of dying.
- src/mcp/index_supervisor.{h,c}: worker-role state + cbm_index_spawn_worker(),
which spawns `<self> cli --index-worker index_repository <json> --response-out
<tmp>` via the subprocess primitive, reaps, and classifies. fork+exec only;
recursion is prevented by the --index-worker argv flag, never an ambient env
var (which could misfire and silently run unprotected in-process).
- src/mcp/mcp.c: a supervisor gate at the top of handle_index_repository wraps the
run unless this process is the worker or CBM_INDEX_SUPERVISOR=0 (kill switch).
Clean exit passes the worker's response through; a crash/hang returns a
contained-failure response; a spawn failure degrades to the in-process path.
- src/main.c: parse --index-worker / --response-out; the worker writes its result
to the response file for the parent to read back.
- src/ui/http_server.c: its existing index spawn now passes --index-worker so it
does not re-supervise (one isolation layer, no redundant process nesting).
- src/foundation/subprocess.c: the forked child redirects output with open()+dup2()
instead of freopen() — async-signal-safe, no malloc between fork and exec, since
the parent may be multithreaded (server threads + mimalloc/sqlite/libgit2 state).
- internal/cbm/cbm.c: CBM_TEST_CRASH_ON / CBM_TEST_HANG_ON deterministic fault
injectors (test-only, env-gated) so the guard is honest — green iff a real fault
is genuinely contained, not a fixture that may stop faulting.
- scripts/smoke-invariants.sh: inv_crasher_contained_cli asserts the crash escapes
as a signal without the supervisor (rc>=128) and is contained + reported with it
(rc<128, outcome=crash).
Precise skip-and-continue (quarantine the culprit file, index the rest) is layered
on in a follow-up; this change contains the crash and keeps the process alive.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
New src/foundation/subprocess.{h,c}: spawn a child, tail its output, and
classify how it ended — clean / exit-nonzero / crash / hang / killed — from
POSIX WIFSIGNALED/WTERMSIG and the Windows NTSTATUS exception exit codes
(0xC0000005 access violation, 0xC00000FD stack overflow). Adds an EINTR-safe
reap loop, a quiet-timeout that kills and reports a hung child (no new output
within the window), and partial-line-safe log tailing.
Generalized from the ad-hoc index spawn in src/ui/http_server.c so the
crash/hang supervisor can reuse one primitive across platforms. The exit-code
to outcome mapping lives in a pure cbm_proc_classify() so the Windows
crash-code path is unit-tested on every platform, not just an untested
Windows branch.
tests/test_subprocess.c: 13 tests — the classifier on all platforms plus real
POSIX spawn/reap of clean, non-zero, SIGSEGV-crash and hang children. Green
under ASan/UBSan.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
index_repository silently dropped files that failed to index: CBMFileResult.has_error
was set but never read, oversized files (>100 MB) were dropped with no signal, and
read/extract failures only bumped a logged-only counter — a file that couldn't be
indexed just vanished from the graph.
Collect and surface them:
- New retained {path, reason, phase} error list on struct cbm_pipeline (mirrors the
excluded_dirs pattern) + accessor + a back-pointer on cbm_pipeline_ctx_t so both
extraction paths can append. Wired in BOTH the sequential (pass_definitions) and
parallel (per-worker, merged lock-free) paths — small repos take the sequential
path, so wiring only one would leave the guard vacuous.
- Feeds: read-fail, extract-fail, the newly-CONSUMED has_error (parse timeout /
parse failed, with error_msg), and oversized. The cross_lsp phase is reserved for
the crash supervisor (Track C) and not fed here (the cross-LSP passes are
best-effort with no failure return; feeding the no-source case would be false
positives).
- MCP/CLI response gains top-level "skipped_count" (0 on clean) and, when >0, a
capped "skipped":{files[<=50],count,truncated} + "logfile". Status stays "indexed"
— a reported skip is the expected, handled outcome, not a degradation.
- Per-run logfile (full uncapped list) written ONLY when >=1 file is skipped:
$CBM_INDEX_LOG override else <cache_dir>/logs/<project>-<epoch>.log.
- Generous env-configurable caps (src/foundation/limits.c): CBM_MAX_FILE_BYTES,
default raised 100 MB -> 512 MiB; over-cap files are REPORTED (phase oversized) +
WARNed, never silently dropped.
Reproduce-first: tests/test_index_resilience.c (gating) — an oversized file (cap
lowered via env) must appear in skipped[] with the 2 good files still indexed and a
logfile written; a clean run has skipped_count 0 and no logfile. Genuine guard:
no-op'ing the recorder makes the oversized file silently vanish (RED). Full suite
5750/0, no ASan/UBSan.
Part of the resilient-indexing effort (Track B surfacing layer). Refs #668.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
detect_changes returned an empty impacted_symbols set for projects indexed
inside a git worktree or from a repo subdirectory (#659): canonical_root was
computed wrong. `git rev-parse --git-common-dir` emits a path relative to the
directory passed via -C (input_path), NOT to worktree_root, and the "/.git"
suffix was stripped textually without resolving ".." components. So e.g.
"../.git" joined against worktree_root, or "/ws/scripts/../.git" strip, left an
unresolved ".." and never matched the project's stored root path.
Fix (src/git/git_context.c): join the relative --git-common-dir against
input_path (the -C dir) instead of worktree_root, and realpath()/_fullpath()-
normalize the result BEFORE stripping "/.git" (the .git dir always exists for a
valid repo, so resolution succeeds). This is consistent with the existing
realpath'd root_path used for prefix matching (mcp.c).
Reproduce-first: tests/test_git_context.c. The subdirectory case is the genuine
guard — a repo indexed from a subdir yields a *relative* --git-common-dir, so the
unfixed code leaves an un-normalized "<root>/subdir/.." (verified RED; GREEN after
the realpath fix). The linked-worktree case is a supporting invariant, not the
#659 reproducer: git that emits an *absolute* worktree --git-common-dir (e.g.
2.48.x) doesn't manifest the bug, so it passes either way; it still enforces the
worktree->main-root invariant. All three git-based tests SKIP_PLATFORM on Windows
(the CI shell there cannot init a repo via system()).
Distilled from #672 (thanks @anivaryam); that PR's production fix is taken
verbatim. Its repo_root/subdir tests ran git unconditionally and failed the
Windows CI leg ("failed to init git repo"); here all three git-based tests are
Windows-skipped so ci-ok is green cross-platform. Supersedes #696, which only
realpath'd after the strip without changing the join base and so still yielded
the workspace parent for the subdirectory case.
Closes#659
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Co-Authored-By: anivaryam <anivaryam.dev@gmail.com>
verify_compiler() in scripts/env.sh ran `file` on the clang path and
grepped for arm64/universal. Nix's clang is a bash wrapper script, so
`file` reports "ASCII text executable" and the check falsely concluded
"x86_64 only", aborting before any compile. Replace it with a capability
probe: compile + link a trivial program for the target -arch and trust
the result — correct for wrapper scripts (Nix, ccache) and cross-compilers.
Make arch targeting explicit and toolchain-agnostic: export
ARCHFLAGS="-arch <arch>" from env.sh and fold it into CC/CXX in
Makefile.cbm via `override`, so it reaches every compile and link
(including the vendored objects) and survives a command-line CC=
override. This replaces the `arch -<arch> make` prefix, which cannot
work with Nix's fixed-target clang. Drop the now-redundant ARCH_PREFIX
from build/test/lint/repro.
Refs #705.
Signed-off-by: Kris Williams <115474+kriswill@users.noreply.github.com>
lsp_all.o is a unity object that #includes every lsp/*.c resolver; those include
cbm.h, and CBMCall is copied BY VALUE across the lsp->pipeline boundary
(cbm_calls_push). Its Make rule depended only on lsp_all.c, not on the headers it
pulls in. So after CBMCall gained a field (is_method, #477) an incremental build
kept a stale lsp_all.o with the old struct layout while the rest of the tree
recompiled against the new one -- an ODR mismatch ASan flags as a
stack-buffer-underflow in cbm_calls_push (the by-value copy under-reads the
shorter stale struct). Clean builds (CI) always match, so it only bites
incremental developer builds.
Add an LSP_UNITY_DEPS prerequisite (lsp/*.c + lsp/*.h + lsp/generated/*.c +
internal/cbm/*.h) to lsp_all.o and prod_lsp_all.o so the object rebuilds when any
included header or unity source changes. Wildcard-based, so new LSP resolvers are
covered automatically; explicit because this Makefile has no -MMD auto-deps.
Verified: touching internal/cbm/cbm.h now rebuilds lsp_all.o (was stale before);
clean build + full ASan suite green, rustlsp_dbg_macro_inner_call no longer aborts.
Signed-off-by: Kris Kersey <kris@kerseyfabrications.com>
ASSEMBLY/BEANCOUNT/BICEP/CFML/CFSCRIPT/LINKERSCRIPT/PINE/RESCRIPT/SQL/SQUIRREL/
SYSTEMVERILOG/TABLEGEN/TEMPL/VERILOG/VHDL. Completes per-grammar invariant
coverage for ALL 159 vendored grammars. Callable langs (verilog/vhdl/systemverilog/
cfml/cfscript/rescript/squirrel/pine/templ/sql) full battery (callable-sourcing RED
via enclosing-func drift); asm/linker/tablegen/bicep/beancount structural + a
robustness dim (malformed input must not crash) on every language.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
JSON/JSON5/YAML/TOML/INI/HCL/XML/CSV/PROPERTIES/DOTENV/KDL/RON/PKL/NICKEL/JSONNET/
STARLARK. Adaptive battery (most are structural-only: extract-clean + valid
labels/FQNs/ranges + defs-present), plus HCL/Nickel/Jsonnet/Starlark callable +
callable-sourcing, plus a robustness dim: malformed/truncated input must RETURN
(no crash) on every config language.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
HTML/CSS/SCSS/Vue/Svelte/Astro/GraphQL/Protobuf/Thrift/Prisma/GoTemplate/JSDoc.
Adaptive battery: structural-only langs assert extract-clean + valid labels/FQNs/
ranges + defs-present; SCSS/GoTemplate also assert calls + callable-sourcing
(both RED — enclosing-func gap / no Function node to source the call).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Zig/Nim/Crystal/Hare/Odin/Pony/Ada/Fortran/COBOL/Pascal/Solidity/Move full
invariant battery. Zig/Hare/Solidity callable-sourcing GREEN guards; the rest RED
via enclosing-func drift (func_kinds_for_lang only covers Zig); Nim RED (no spec/
grammar — zero defs/calls, asserted as the documented gap).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Per-pass resolution contract for the C/C++ hybrid LSP: one fixture per lsp_*
strategy c_lsp.c emits (lsp_direct, implicit_this, scoped, type/virtual/base/
smart_ptr dispatch, template[_instantiation], func_ptr, dll_resolve, operator,
constructor/destructor/copy_constructor, conversion, adl, unresolved). Each
asserts the inner call is callable-sourced AND properties_json carries that
strategy. Ties to repro_invariant_lsp_rescue (the exact-QN join can suppress a
correctly-emitted strategy).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Foundation for the exhaustive all-grammar/all-LSP invariant suite:
- repro_invariant_lib.h: shared invariant helpers (extract-clean, label-valid,
fqn-wellformed, range-valid, callable-sourcing split, dangling-edge count,
lsp-strategy presence, target-QN-suffix).
- repro_grammar_core.c: full invariant battery for C/C++/CUDA/Rust/Go/Java/C#/
Kotlin/Scala/Swift/ObjC/D — one TEST per language asserting extract-clean +
valid labels/FQNs/ranges + defs-present + calls-extracted + callable-sourcing
(Module-sourced==0) + no-dangling. Callable-sourcing reds are the known gap.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Comprehensively reproduce the remaining QUALITY_ANALYSIS gaps:
- repro_invariant_enclosing_parity (gap #3): cbm_find_enclosing_func's hardcoded
func_kinds_for_lang switch has drifted from lang_specs.function_node_types.
Languages absent from the switch whose function nodes aren't in func_kinds_generic
silently attribute every in-function call to Module. Full drift table +
per-language reproductions (fortran/scss/sql/verilog/julia/nix RED via Module
source; commonlisp/emacslisp/dart/cobol RED, some compounded by a callee-
extraction gap).
- repro_invariant_lsp_rescue (gap #5/#5a): cbm_pipeline_find_lsp_resolution
(lsp_resolve.h:65) joins LSP results to tree-sitter calls by EXACT
caller_qn==enclosing_func_qn; when tree-sitter says Module, the LSP rescue is
discarded. C++ out-of-line fixture asserts the edge is LSP-callable-sourced AND
that properties_json preserves the lsp_* strategy/confidence (both RED today).
- repro_invariant_discovery_fqn (gaps #1,#4): comprehensive 50+ skip-dir table
(.claude-worktrees RED, the rest GREEN guards) + 6 FQN same-stem collision cases
(api.h/api.c + svc.h/svc.cpp RED; cross-dir/.d.ts/cross-package GREEN guards).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A systemic-invariant suite derived from the prior QUALITY_ANALYSIS (only 3.69% of
real-repo CALLS edges are Function/Method-sourced; the rest fall back to Module):
- repro_invariant_calls: source-position-aware CALLS attribution per language —
a call inside a function body must be sourced at Function/Method, never Module.
C/C++/Rust/Java/C# RED (Module fallback + LSP-rescue join too strict); Go/Python
GREEN guards.
- repro_invariant_graph: discovery hygiene (.claude-worktrees must be skipped —
RED), FQN same-stem distinctness (api.h vs api.c collide via strip_ext — RED),
no-dangling-edges (GREEN integrity guard), Perl enclosing-func parity
(func_kinds_for_lang lacks subroutine_declaration_statement — RED).
- repro_invariant_breadth: 26-language table asserting in-body calls are
callable-sourced (~12 RED incl. r/julia + the known-gap langs, ~14 GREEN guards).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- #363: the cgroup CPU axis was fixed in v0.8.0 (detect_system_linux reads
cpu.max/cfs_quota), but there is no user-controllable memory ceiling —
cbm_mem_init derives the budget from host/cgroup RAM with no override. Test
sets CBM_MEM_BUDGET_MB and asserts cbm_mem_budget honors it; RED because that
env knob is not read (mirrors the open ask from the issue thread; note this is
the memory-override remainder, adjacent to enhancement #580).
- #581: bounded RSS-growth reproduction for the long-running leak — repeats a
query op ~150x and asserts current RSS (cbm_mem_rss / /proc/self/statm) stays
within 3x of the warmup baseline. Documents flakiness + that a slow per-op leak
may not trip the bounded threshold (then a true multi-hour soak is needed).
#513 (Windows stdio handshake hang) is NOT reproducible in the unit-test runner:
it is Windows-only WaitForSingleObject code in cbm_mcp_server_run. It needs the
prod cbm binary built on windows-latest + a stdio-driver test that sends an
initialize request, keeps stdin open, and asserts a response before EOF. Deferred
as a board extension (documented in private/BUG_REPRO_PLAN.md).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- #548: reworked off the live-HTTP-server draft — calls cbm_is_dir (the exact
function handle_browse gates on) with a backslash path + the drive-root parent
strrchr logic; no sockets/threads. RED on current code.
- #56: was a false-pass (bare-name resolver routed crate_a::helper to the only
'helper' candidate). Added a second local helper to force ambiguity and now
assert a CALLS edge whose target QN is in crate_a's namespace. Genuinely RED.
NEW bugs found by the discovery sweep (each a RED reproduction, root-cause traced):
- repro_new_ts_class_field_arrow: TS class-field arrow methods (handler = () => {})
are never emitted as Method defs and inner calls mis-attribute to the class QN
(extract_class_methods + resolve_toplevel_arrow_name ignore public_field_definition).
- repro_new_py_tuple_unpack: 'x, y = f()' yields no Variable defs — extract_vars
only handles an identifier 'left', not pattern_list.
- repro_new_cypher_limit_zero: 'LIMIT 0' returns ALL rows — limit==0 is used as
both the unset sentinel and a valid value; three guards check limit>0.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- #471 (RED): deeply-nested ambiguous Perl call chain f(f(f(...))) makes the GLR
stack-merge O(n^2) (stack_node_add_link recurses over all shared heads; the
#461 recursion-depth cap bounds stack depth, not total iterations). Reproduced
in a forked child with alarm(15) at depth 5000; asserts the child is not
signal-killed (RED when the quadratic blowup blows the time budget).
- #221 (GREEN guard): cbm_find_cli now probes Windows PATHEXT (.exe/.cmd/.bat/.ps1,
commit 0485d3f), so opencode is resolvable. Guards that fix on a fake
opencode shim placed on PATH. Candidate to close after reporter retest.
(#548 held: its agent draft spins up a live HTTP server in a thread to exercise
handle_browse; reworking to a lighter harness before adding.)
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- #607 (RED, DATA LOSS): cbm_cmd_install prints 'must be rebuilt' then calls
cbm_remove_indexes() which unlink()s every .db in the cache and never rebuilds
— re-running install destroys the user's index. Asserts the DB survives.
- #403 (RED): cbm_should_skip_dir excludes neither Antigravity / Programs /
AppData, and the .gitignore path is git-gated, so an IDE install tree is fully
indexed. Asserts a sentinel under the install dir is not discovered.
- #434 (RED): the incremental dump_and_persist only re-exports the artifact when
one already exists and never receives the persistence flag, so persistence=true
is silently dropped on first index. Asserts the artifact exists after one
index_repository with persistence=true.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
In-process via cli.h + a temp HOME + the cbm_build_install_plan_json dry-run
oracle (no real filesystem mutation of the user's config):
- #570 (RED): install_cli_agent_configs hardcodes the Codex hook target to
~/.codex/config.toml and never checks for ~/.codex/hooks.json, so the hook is
planned into config.toml even when hooks.json is in use (dual registration).
- #409 (GREEN guard): the legacy blocking PreToolUse gate regression is already
fixed (cbm_install_hook_gate_script writes the non-blocking hook-augment shim);
this guards the upgrade/overwrite scenario no existing test covered. Issue is a
candidate to close after reporter retest.
- #431 (RED): the VSCode install path computes only Code/User/mcp.json and has no
profile-aware API, so Code/User/profiles/<id>/mcp.json is never written; the
plan omits the profile path entirely.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
push_nested_class_nodes (extract_defs.c) re-queues only class-like/field/decl
children of a trait body — never function_item / function_signature_item — so
abstract + default trait methods are dropped from the graph (a major source of
the shallow-Rust-index degradation). impl-block methods (separate code path) are
extracted, serving as the positive control. Asserts all three trait-body methods
appear as defs; RED on current code.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- #557 (DATA LOSS): resolve_store() in mcp.c unlink()s the user's DB (+wal/+shm)
with no backup when cbm_store_check_integrity() returns false — e.g. a project
row whose root_path fails the path-shape SQL check. The test plants root_path
"826" (from the issue evidence) under a CBM_CACHE_DIR temp dir, calls a tool
that routes through resolve_store, and asserts the DB still exists OR a backup
was made (RED: it is silently deleted).
- #520: detect_changes runs 'git diff', which never lists UNTRACKED new files, so
a newly-created file is invisible until a manual re-index. Indexes a git repo,
creates an untracked file, calls detect_changes, asserts the new file appears.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- #627: query_graph crash — integer overflow in cypher.c cross_join_with_rels
(node_count^2 * growth overflows int -> tiny malloc -> OOB write) on an
OPTIONAL MATCH with an already-bound terminal node. Reproduced in a FORKED
child (crash must not kill the runner); asserts the child is not signalled.
- #514: trace_path data_flow mode drops argument expressions — cbm_edge_info_t
carries no properties_json, so the CALLS-edge arg text never reaches the MCP
JSON. Asserts the arg expression appears in the data_flow response.
- #510: non-root .gitignore ignored — try_load_nested_gitignore() bails when the
walk frame prefix is empty, so a directory's own .gitignore is never loaded
when indexing a non-git-root subtree. Drives cbm_discover() directly and
asserts an explicitly-ignored file is excluded.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Build fixes (wave 2 broke on all platforms):
- repro_harness.h: include <pipeline/pipeline.h> for cbm_project_name_from_path
(-Werror=implicit-function-declaration).
- repro_issue408.c: the doc comment contained '["packages/*"]' whose '/*' opened
a nested block comment (-Werror=comment); reworded.
New reproductions:
- #571: cbm_project_name_from_path strips CJK (per-byte [A-Za-z0-9._-] filter
rewrites every UTF-8 continuation byte to '-'); a purely-CJK trailing path
segment vanishes. Asserts the name is not the ASCII-only truncation.
- #523: cross-repo HTTP_CALLS — unindexed-lib guard in pass_calls.c drops the
client call before the HTTP_CALLS edge is emitted, so cbm_cross_repo_match
returns http_edges==0 for a byte-identical call/route. Asserts >=1.
- #546: trace_path splits a symbol duplicated by an ambient .d.ts into two nodes;
inbound traversal walks only one, dropping callers by import style. Asserts
BOTH the relative-import and alias-import callers appear.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
First users of the shared repro_harness.h (validates the multi-file + MCP-tool
harness end to end):
- #408: STRONGER than the existing weak test_lang_contract.c guard (which any
IMPORTS edge satisfies) — fixture has zero relative imports + no dependencies
field, so the only possible IMPORTS edge is the workspace cross-package one
packages/b -> @org/a; asserts >=1.
- #56: Rust multi-crate workspace; crate_b::run calls crate_a::helper; asserts
CALLS >= 2 so an intra-crate edge can't mask the missing cross-crate edge.
- #480: precondition asserts CALLS>0 (edges exist), then drives the trace_path
MCP tool and asserts the caller appears + the result is not the empty
"callers":[] shape — isolating it as a traversal bug, not extraction.
All assert correct behaviour; RED on current code (board verifies).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- Makefile: add -Itests to the test-repro-runner compile so repro files in the
tests/repro/ subdir resolve "test_framework.h" (they sit one dir deeper than
the existing tests/*.c, which find it relative to their own directory).
- #495: cfg-gated twin functions collapse — two mutually-exclusive #[cfg] Rust
fns get identical qualified_name and the UNIQUE(project,qualified_name) upsert
overwrites one; asserts the twins get distinct QNs.
- #521: Route nodes minted from URL string literals in infra/config files
(try_upsert_infra_route has no source-vs-config guard); indexes a YAML-only
fixture and asserts zero Route nodes.
- #382: Java class-level + marker_annotation decorators dropped; asserts @Entity/
@RestController on the class and @Override on the method (strengthens the weak
existing #382 method-only test).
All three assert correct behaviour and are RED on current code.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Stand up a separate, non-gating reproduce-first suite that holds one RED case
per open bug issue (the redness is the deliverable + the regression guard):
- tests/repro/ + repro_main.c -> `make test-repro` (its own runner with its own
main + counters; deliberately EXCLUDED from ALL_TEST_SRCS so the gating
`make test` / ci-ok required check stays green and PRs are not wedged)
- repro_extraction.c: first reproduction, #554 -- a C++ out-of-line method's
inner CALLS edge must attribute to the class-qualified Method QN, not the
Module; ties the call's enclosing_func_qn to the method definition's own
qualified_name so a class-qualifier drop (the live root cause) fails it
- scripts/repro.sh: build+run the board; a build/link failure fails the job,
while expected test redness is reported as the board state (job stays green)
- .github/workflows/bug-repro.yml: workflow_dispatch (platform filter) + qa/**
push; runs the board on linux x2 / macos x2 / windows so many bug vectors can
be reproduced on many platforms at once
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Route QNs (__route__METHOD__/path) are the rendezvous key for joining a client
HTTP_CALLS to the server handler that serves it, but they were built from the raw
path. Frameworks write path parameters with different placeholder syntaxes
(":id" Express/clients, "{id}" Axum/Spring/OpenAPI, "<id>" Flask/Rocket), so a
client call and its handler produced different QNs and never joined. Static
routes joined; parameterized routes (most of a REST surface) did not.
Add cbm_route_canon_path() which collapses each parameter token (":name",
"{name}", "<name>", "${...}") to a single "{}" token, and apply it to the path
at every HTTP-route QN construction site (pass_route_nodes, pass_parallel,
pass_calls, pass_cross_repo). Broker/async/infra QNs are left untouched. Only the
QN (identity/dedup key) is canonicalized; the Route node display name keeps the
original path. Parameter names are intentionally discarded so the same logical
endpoint matches across services that name the variable differently.
Adds tests/test_route_canon.c (11 cases). Fixes#505.
Signed-off-by: imateusdev <imateusdev@gmail.com>
Compare persisted SQLite node counts to in-memory dump counts after
index_repository completes so partial WAL/durability loss surfaces as
status:"degraded" instead of silent indexed.
Signed-off-by: Sam Li <yangsec888@gmail.com>
The web server behind the graph UI is now a purpose-built in-house
module (src/ui/httpd.c): localhost-only listener, strict HTTP/1.1
parsing with fixed request caps, a per-connection receive deadline,
and Connection: close semantics. http_server.c keeps the routing and
handlers, rewritten against the new transport API; the public server
API and main.c are unchanged. The previously vendored third-party
server is removed entirely.
Comes with a new 28-test transport + routing suite (tests/test_httpd.c)
covering parsing edge cases (strict CRLF, Content-Length limits, raw
path matching, percent-decode rules) and live-socket behavior (CORS
policy, RPC dispatch, receive deadline, clean shutdown). The security
audit scripts now check the new file layout and treat any network call
in vendored code as a failure.
mimalloc bumped to v3.3.2 (MI_MALLOC_VERSION 30302), which adds static-CRT malloc override on Windows. Makefile: define the real MI_MALLOC_OVERRIDE=1 ONLY on MinGW (enables the static-CRT override entry points — the generic Windows fix for #424); on Unix keep static-link-order override (defining MI_MALLOC_OVERRIDE there compiles alloc-override.c's forwarding defs and crashes macOS with 'mi_free: invalid pointer' since system libs keep the system allocator). The old -DMI_OVERRIDE=1 was never read by mimalloc source — kept as a prod marker. smoke-test.sh: hard-fail on any 'mimalloc: error' in stderr. Regenerated scripts/vendored-checksums.txt for the new tree (security-vendored.sh passes; no dangerous calls in vendored mimalloc).
Root cause (corrected from the report): not a tree-sitter null-subtree sentinel — 0xffffffffffffffff is a freed/heap-corrupted pointer. The vendored ts runtime allocates via its overridable ts_current_malloc/free; under the prod build's MI_OVERRIDE=1, the Windows static-MinGW link (--allow-multiple-definition) resolves ts_malloc to mimalloc but ts_free can resolve to the CRT free (or vice-versa), corrupting the heap freelist and crashing mid-parse on large templated C++ headers (scales with parse churn, not syntax). cbm_init now calls ts_set_allocator(mi_malloc, mi_calloc, mi_realloc, mi_free) so ts allocate+free go through one allocator on every platform. Guarded to CFLAGS_PROD (MI_OVERRIDE=1); the test build stays CRT+ASan to avoid an alloc/free mismatch there. Tests in test_stack_overflow.c: allocator-binding mechanism + large-templated-C++ extraction guard (the C++ gap noted in #424).
Final 4 probe suites (grammar_probe_d/e/f/g, 250 cases) bring node/edge-creation coverage to all 159 grammars. Triage fixed 4 fixture mislabels (objc Method label, smithy $version order, json non-ignored filename, sql DDL-only Variables) and confirmed ~46 real reds. Findings map to known classes 2/3 (import/include-edge resolution missing for ~34 grammars: agda/bicep/elm/func/move/nasm/pony/purescript/qml/smali/tlaplus/vhdl/protobuf/thrift/capnp/wit/smithy/astro/nix/nickel/pkl/jsonnet/hyprlang/devicetree/cmake/makefile/meson/gn/just/bitbake/kconfig/html/css/scss), 16 (node-extraction incompleteness: wolfram multi-def/set_top, wit world funcs, bicep resource, just recipe), plus infra gaps (INFRA_MAPS hcl/k8s only from YAML topic bindings; DEPENDS_ON only from Helm Chart.yaml — go.mod/requirements produce none). NEW class 17 = file-index routing gap: .env/.gitignore/.gitattributes/.re have no EXT_TABLE/FILENAME_TABLE entry in discover/language.c so index_repository never indexes them (direct extraction works). Vue/Svelte/Astro component imports: extraction works but JS/TS path resolver doesn't handle those extensions. All 159 grammars now have reproduce-first guards.
Extends the node/edge-creation hunt to ~35 grammar-only code languages (129 graph/extraction cases, 73 green guards / 56 real RED reproductions; triage confirmed 0 fixture errors — all reds are genuine product gaps). Findings map to: class 2 import-EXTRACTION missing (cbm_extract_imports dispatch in extract_imports.c covers only ~38 langs + default:break, so ~25 grammar-only langs' configured *_import_types are never consumed → 0 imports); class 1 INHERITS missing (crystal/julia/pascal/powershell/squirrel/solidity); and NEW class 16 = per-grammar NODE-extraction incompleteness (class_types configured + grammar node present, but extract_defs.c emits 0 type nodes for D struct/class, F# record/union, Gleam type, Julia/Odin struct, Pascal record, PowerShell class, Hare struct, ReScript type, squirrel class, sway struct/abi, tcl namespace, wgsl struct). Affected-grammar matrix in the suite comments. Brings code-grammar coverage to ~61 of 66.