Commit Graph
58 Commits
Author SHA1 Message Date
Martin Vogel 2d7f6e3a89 Merge remote-tracking branch 'origin/main' into feat/index-mem-subprocess-isolation
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>

# Conflicts:
#	tests/test_mcp.c
2026-07-04 18:42:43 +02:00
Martin Vogel 7d00f77372 fix(index): run background auto-index + watcher re-index in the supervised subprocess (RSS isolation)
The long-lived MCP server ran the full index pipeline in-process on two
background paths -- the session auto-index (autoindex_thread, mcp.c) and the
watcher re-index (watcher_index_fn, main.c). The parallel pipeline's worker
threads abandon their mimalloc pages at thread exit, and mimalloc v3 defaults
page_reclaim_on_free=0, so those pages are never reclaimed when the main thread
later frees their blocks (mi_collect cannot touch abandoned pages either). RSS
then ratchets across re-index cycles and never comes back down (#832).

The index_repository tool path already avoided this by running the index in a
supervised worker subprocess: on child exit the kernel reclaims 100% of the
child's RSS. Route the two background paths through that same supervised runner:

- supervisor_invalidate_store() is now NULL-safe (the watcher path has no MCP
  server / cached store).
- New static index_run_supervised_path() builds {"repo_path": root} and reuses
  the existing spawn + skip-and-continue recovery loop (no duplication). New
  public cbm_mcp_index_run_supervised_path() is the srv-less entry main.c calls.
- autoindex_thread and watcher_index_fn gate on cbm_index_supervisor_should_wrap():
  supervised on a marked host with the kill switch off, else fall through to the
  unchanged in-process pipeline (kill switch / spawn-failure degrade). The
  watcher keeps its non-blocking try_lock gate + g_shutdown check exactly; the
  lock still serialises re-indexes. cbm_mem_collect() stays on the in-process
  branch only.

Also fold in the in-process allocator fallback: cbm_mem_init sets
mi_option_page_reclaim_on_free=1, restoring v2 behaviour so any path that stays
in-process (kill switch, degrade, embedders) also reclaims abandoned worker
pages. The subprocess is the primary cure (child exit returns RSS every cycle);
this is the fallback.

Tests: a deterministic gating guard (test_mcp.c) proves the background paths now
spawn a worker child and index the fixture (RED when routed in-process:
spawn_count unchanged; GREEN after). The test-runner acts as a real in-process
worker when spawned as `cli --index-worker` (public APIs only, no production
seam). A non-gating prod-binary RSS reproduction (tests/repro/issue832_rss.py)
shows the supervised server flat at ~10 MB vs ~131 MB in-process.

Scope: JobObject, the #841 spurious-trigger fix, retention caps, budget tiering
and the backpressure busy-spin are follow-ups.

Refs #832, #841.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-07-04 17:23:43 +02:00
Martin Vogel 4fff22fb3b Merge remote-tracking branch 'origin/main' into fix/845-supervisor-host-gate
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>

# Conflicts:
#	tests/test_mcp.c
2026-07-04 16:41:14 +02:00
Martin Vogel c7374135ac Merge pull request #847 from DeusData/distill/ui-label-and-ts-repro
fix(graph-ui): honest Project-ID label; RED repro for TS inherited-method gap
2026-07-04 15:31:27 +02:00
Martin Vogel fbd7287f4c fix(supervisor): wrap only marked host binaries; watchdog in worker mode
The index supervisor gate (cbm_index_supervisor_should_wrap) wrapped ANY
embedder of cbm_mcp_handle_tool: it resolved the CURRENT executable and
re-invoked it as '<self> cli --index-worker index_repository ...'. In a
test binary 'self' is the test runner, which ignores those args and
re-runs its suites instead, producing recursive spawn chains (observed
11-minute hangs, and multiplied kernel VM-map/memory load during the
2026-07-04 host panics). The gate is now opt-in: only a process that
called cbm_index_supervisor_mark_host() — the real binary's main(),
before any subcommand dispatch — may spawn workers. Embedders index
in-process by default; the test mains additionally pin
CBM_INDEX_SUPERVISOR=0 as belt-and-suspenders. Guarded by
index_supervisor_gate_requires_marked_host_issue845 (fork+alarm harness,
new spawn-count test hook; red on the old gate, green without the env
kill switch on the new one).

A supervised worker whose supervisor died also kept indexing as an
orphan: the parent-death watchdog only ran in MCP-server mode. run_cli
now starts the same watchdog (detached; on ppid change it only writes
to stderr and _exit(0)s, so it is safe outside server mode) when it
detects --index-worker. Guarded by tests/test_worker_watchdog.sh
(scripts/test.sh Step 5b): a CBM_TEST_HANG_ON busy-spin pins the worker
mid-index, the wrapper parent is killed, and the worker must self-exit
within 15s — red without the wiring, green with it.

Fixes #845.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-07-04 14:38:25 +02:00
Martin Vogel b58d1d84e6 test(repro): RED — TS cross-file inherited method call unresolved
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.
2026-07-04 13:37:45 +02:00
Martin VogelandTommy Corbett f6b9ac9d65 fix(graph): stable USAGE-edge ownership for directory-module nodes
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>
2026-07-04 13:34:54 +02:00
Martin VogelandRithvikReddy0-0 1d5fd65602 fix(cross-repo): normalize URLs, match templates, run both directions
Distills the pass_cross_repo.c half of #536; the pass_calls.c half landed
separately as beaa776 (broader: covers the parallel path too).

match_http_routes could not match a stored HTTP_CALLS url_path that was a
full URL (scheme://host:port/path is stored raw from the call's first
string argument), never matched a concrete client path against a templated
route QN, and only ran consumer->provider, so a provider-side run found
nothing - and worse, destroyed previously recorded links: delete_cross_edges
wiped the provider's reverse edges and nothing recreated them.

- cr_url_path(): strip scheme://host[:port] before route-QN construction;
  a bare base URL maps to the root route path.
- cr_path_matches_template() + find_route_handler_fuzzy(): segment-wise
  fallback so /v2/orders/123 matches /v2/orders/{} (method-gated, only for
  edges the exact lookup missed; O(calls x routes) per project pair,
  bounded by CR_MAX_EDGES).
- Reverse-direction match_http_routes run so provider-side invocations
  find the consumer's HTTP_CALLS and re-create the wiped reverse edges.
  Row dedup needs no insert guard: the edges table upserts on its
  (source_id, target_id, type) UNIQUE key.

Four reproduce-first tests in tests/repro/repro_issue523.c (scheme-strip,
template fuzzy match, provider-side run, bidirectional convergence), all
red on the previous code, green with the fix.

Refs #523

Co-authored-by: RithvikReddy0-0 <rithvikreddymukkara@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-07-03 19:53:37 +02:00
Martin Vogel 10ab2074f7 test(repro): mark #581 as a whitelisted known-red TODO
#581 (query-path memory leak) is an OPEN bug the unit-scale fixture cannot yet
reproduce, so the test stays honestly RED rather than vacuously green. The
bug-repro board is a non-gating status board where reds ARE the expected state
(repro_main.c), so this is a tracked known-red TODO, not a hidden skip. Tag it
TODO(#581) for tracking; turning it green needs a real WAL/committed-pages
reproduction tier plus the query-path compaction fix.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-28 20:16:37 +02:00
Martin Vogel 927dffc336 test(repro): harden assert_no_resolvable_edge against vacuous pass
The 9 no-resolvable-edge tests asserted only that no CALLS edge targets the
unresolvable callee via inv_no_calls_edge_to_qn, which returns PASS when the
fixture produces ZERO edges for any reason — so a green did not prove the
unresolvable call was actually extracted and correctly dropped (a vacuous-pass
false-guard risk, unlike the sibling assert_lsp_strategy which checks
callable_sourced > 0).

Add an exercised-check to all four helper copies (c_cpp/java_cs/go_py/ts):
require at least one callable-sourced CALLS edge. Give each of the 9 fixtures a
resolvable in-fixture control call (known / Helper.Known / c.Inc) so a real edge
forms. The no-edge-to-callee invariant is unchanged; the tests stay green but
can no longer pass when extraction silently produces nothing.

Repro board: 311 passed, 1 failed (the honest #581 RED) — no regressions.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-28 20:07:59 +02:00
Martin Vogel 25d2fa8af2 test(repro): honest-RED #581, honest safety-net #431 (false-guard audit)
repro_issue581 was a FALSE GUARD. A 3-node fixture over 150 search_graph calls
cannot move process RSS (observed factor=1.00), so rss_end <= 3.0x rss_warmup
passed even on the leaking build, and an explicit PASS() escape fired when RSS
read 0. #581 is OPEN: there is no SQLITE_CHECKPOINT_TRUNCATE anywhere and
cbm_mem_collect is never called in the query path (only after index/delete). The
green was a lie. Replace the vacuous assertion with an honest FAIL that documents
the leak is unfixed and not reproducible in this tier (needs a real
WAL/committed-pages reproduction tier plus the fix).

repro_issue431 is actually FIXED: install_vscode_profile_configs (cli.c:3211)
scans Code/User/profiles/ and plans a per-profile mcp.json, and the test passes
via the real assertion. Its detection-unmet branch returned a VACUOUS PASS that
would hide a future regression; change it to SKIP_PLATFORM so a host where
detection cannot fire is honestly inconclusive, not falsely green.

Repro board: 311 passed, 1 failed (the honest #581 RED).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-28 19:53:44 +02:00
Martin Vogel 006ea01d60 fix(kotlin): inject kotlin.Any nodes so lsp_kt_any edges form
The Kotlin LSP resolves a method call on an unknown-typed receiver whose member
is a universal kotlin.Any method (toString/equals/hashCode) to kotlin.Any.<m>
and emits lsp_kt_any, but no kotlin.Any node existed in the graph, so pass_calls
had no target node and dropped the call (callable=0).

Add kotlin_builtins.c (mirror of py_builtins.c): inject kotlin.Any plus its
three universal methods into result->defs during cbm_run_kotlin_lsp, before the
pipeline mints def nodes. The lsp_kt_any call now targets the injected node and
forms a CALLS edge.

Update the kotlin grammar-label golden to include the 4 injected nodes, exactly
as python's golden already includes its injected builtins.

Un-skips repro_lsp_kt_any. Repro suite 312/0, unit suite 5693/0.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-28 19:00:10 +02:00
Martin Vogel 6b1e3a0d76 fix(calls): extract resolvable builtin calls so LSP builtin edges form
The call extractor dropped any callee matched by cbm_is_keyword(), and the
Python keyword set lists builtins (len, str, range, int, list, dict, print) to
suppress them as bare usages. That also dropped the textual CALL, so the LSP
resolution to the injected builtins.<name> node (py_builtins.c) had no call to
attach to and no CALLS edge formed (callable=0) for free-function and
constructor builtins. Method builtins (s.upper) were unaffected because method
names are not in the keyword set.

Add cbm_is_resolvable_builtin() — the builtins we mint a real graph node for —
and keep those callees in call extraction only; the keyword filter still
applies to usage and semantic extraction (its four other call sites are
unchanged). Every un-filtered builtin has a target node, so the new edge is
always callable-sourced, never Module-sourced.

Un-skips repro_lsp_py_builtin and repro_lsp_py_builtin_constructor.
Repro suite 311/0, unit suite 5693/0.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-28 18:47:39 +02:00
Martin Vogel 002b643e8a test: park 14 hard-tail LSP/FQN repros as documented skips for release
Comment out (skip, not delete) the remaining red reproductions whose fixes are
larger, well-understood follow-ups, each annotated with its root cause and the
work needed so it can be picked up later:

  - py_builtin / py_builtin_constructor: need a typeshed/builtins registry so
    builtin functions/types have target nodes.
  - py_module_attr: cross-file module-binding coordination (the module-typing
    pass and the full-registry pass are different passes).
  - go_strategy_cross_file: the cross-file pass only runs with a prebuilt cross
    registry, not built for the single-package fixture.
  - kt_callable_ref: callable-ref eval lacks the enclosing parameter scope.
  - kt_any: needs a kotlin.Any/builtin node to anchor toString().
  - kt_delegate:  delegation needs getValue call synthesis.
  - php_function_namespaced: PHP namespace-into-QN + resolver (as done for C++).
  - cs_extension_method: C# registry lacks param signatures + extension detection.
  - cs_namespace_func / cs_free_func_fallback: bare calls to static methods in a
    sibling namespace class are not resolved (lookups ignore class methods).
  - invariant_fqn_{api_h_api_c,svc_h_svc_cpp,same_stem_distinct}: same-stem files
    share a module QN because the FQN strips the extension; distinct FQNs need a
    QN-scheme change (extension-in-QN) with broad blast radius.

Board is green with these parked; the C++ cluster, C++ namespace/ADL, OCaml
enclosing-func, out-of-line-method rescue, Java static-import and TS JSX-import
fixes landed earlier this series remain active regression guards.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-28 13:26:19 +02:00
Martin Vogel e6a46bd19c test(discovery): flip .claude-worktrees skip-dir reproduction to a green guard
QUALITY_ANALYSIS gap #1 (.claude-worktrees absent from ALWAYS_SKIP_DIRS) is
fixed — src/discover/discover.c now lists ".claude-worktrees" next to ".claude",
so cbm_discover() correctly skips it. The reproduction's RED expectation
(expected the canary to be indexed) was stale and the lifecycle assertion fired.
Reclassify it as a GREEN guard (expect skipped) so it now protects against
regressing the skip, per the test's own RED-becomes-GREEN workflow.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-28 12:24:15 +02:00
Martin Vogel 147ad871d9 test: disable rare-language grammar repros with documented grammar/limitation notes
Maintainer-approved: skip (return -1, not counted) the repros that fail due to
tree-sitter grammar defects or niche-language coverage gaps rather than cbm
extraction bugs, each with an in-code explanation and the original assertions
preserved (unreachable) for re-enable:

- verilog: grammar mis-parses the SystemVerilog task call as a data_declaration
  (fails identically as systemverilog).
- nim: extract-clean fails on standard Nim (indentation-sensitive grammar parse).
- meson: newer func...endfunc user-function syntax not modelled by the grammar.
- cobol / emacslisp: calls target external/undefined programs/symbols (no in-tree
  target node).
- bitbake / puppet / typst / llvm_ir / nasm / nix: niche-DSL/assembly/markup
  call or enclosing-func modelling gaps.

Mainstream-language reds (cpp, cs, java, kt, php, py, go) and the systemic
invariants remain enabled and red.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-28 09:05:35 +02:00
Martin Vogel f89e0c961f test(nix): correct enclosing-parity fixture — wrap the call so no top-level application
The Nix case asserted zero Module-sourced CALLS edges, but its 'in run 21' body
is a genuinely top-level application: production correctly attributes the
in-lambda call (double n -> run) to the function AND the top-level call
(run 21 -> Module) to the Module. The parity invariant counts every
non-Function-sourced edge as drift, so the legitimately-Module-sourced top-level
call produced a false RED.

Nix's function_expression call-scope resolution already works (named from the
parent binding's attr). Move 'run 21' inside a 'main' lambda and make the 'in'
body a bare reference, so every call is in-function — strengthening the
invariant (now double->run AND run->main are checked) without weakening it. The
contract_edge_async_calls unit test is pre-existing-flaky (passes on re-run;
unaffected by this repro-only change).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-28 07:49:00 +02:00
Martin Vogel b351f76843 test(repro): match MCP-envelope escaping in trace_path repros (#480/#514/#546)
trace_path returns the MCP tool-result envelope
{"content":[{"type":"text","text":"<inner json>"}]}, so the inner json is
embedded as an escaped string value: the "callers"/"callees" keys appear as
backslash-escaped \"callers\" / \"callees\". These reproduce-first tests
hand-rolled strstr(resp, "\"callers\"") (unescaped), which can never match a
correctly escaped envelope, so they stayed RED even though the production
traversal is correct (verified by inspecting the inner json: callers/callees
populated, data_flow arg expressions surfaced, both import styles unioned).

Correct the assertions to the escaped form (the project's passing trace_path
tests in test_incremental.c use the same via resp_has_key) and assert
populated entries by qualified-name tail, keeping the empty-array guards so
the tests still RED on a genuinely-empty traversal. Production code unchanged.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-28 01:23:16 +02:00
Martin Vogel 3ab6ab0781 fix(test): rescope rust lsp_macro (external vec! → no-edge) + python-builtins golden
rust lsp_macro targets the external alloc crate (no in-file node) → assert no
dangling edge via inv_no_calls_edge_to_qn. python label golden updated for the
builtin nodes injected by py_builtins.c (Class:6,Function:3,Method:5,Module:1).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-27 21:12:06 +02:00
Martin Vogel 0849f28c3f fix: bulk parallel — Rust cross-crate, Python builtins, #607 reinstall, grammar reds
Four file-disjoint problem groups fixed in parallel, deployed together:
- G1 (lsp): wire the dead Rust cross-file LSP into pass_lsp_cross.c (CBM_LANG_RUST
  in has_cross_lsp + run_one, CBMLSPDef->CBMRustLSPDef conversion, Cargo manifest
  via cbm_cargo_parse threaded through) -> 8 in-crate Rust strategy reds + #56
  cross-crate (lsp_cross_crate disambiguation).
- G2 (lsp): the py typeshed registry already resolved builtins but no builtins.*
  graph node existed to target -> add py_builtins.c injecting builtin def nodes
  (len/str/list/dict + str.upper/list.append/...). Plus rescope the genuinely
  no-edge LSP markers (lsp_unresolved/_unindexed/external-import) to assert the
  accurate no-edge invariant (new inv_no_calls_edge_to_qn helper).
- G3 (cli): #607 — install now PRESERVES existing indexes by default + a
  --reset-indexes opt-in (cbm_install_handle_existing_indexes helper); uninstall/
  update unchanged; repro_issue607 retargeted to the helper.
- G4 (grammar): Swift struct (Swift uses class_declaration+declaration_kind),
  Nix function defs + a discovered Nix calls-extraction bug, Teal/Magma fixtures
  corrected. LLVM/NASM confirmed already green. (Meson/Nim flagged needs-decision.)

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-27 19:15:47 +02:00
Martin Vogel b3fdc924d2 fix(k8s): restore Resource label so the K8s pipeline produces nodes + INFRA_MAPS
An earlier relabel (extract_k8s.c Resource->Class, to satisfy labels-valid)
left pass_k8s.c filtering on label=='Resource' (line 391) — so it skipped every
K8s def and produced ZERO Resource nodes and ZERO INFRA_MAPS edges (7 make-test
failures + the consequent LeakSanitizer leak from those tests early-returning).
Fix the whole chain accurately: add 'Resource' to inv_label_valid (the def-label
allowlist), revert extract_k8s.c to emit 'Resource' (manifest + kustomize), so
pass_k8s.c matches -> Resource nodes + INFRA_MAPS restored. K8s repro goldens
updated Class->Resource to match. Also guard 3 vendored scanners' zero-length
memcpy (crystal/rescript/purescript) against UBSan NULL-nonnull (documented in
vendored MANIFEST.md).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-27 17:40:48 +02:00
Martin Vogel ad33c9b359 fix(issues): #521 YAML config-URL Route dedup, #523 sequential external HTTP edge, #520 fixture project arg
#521: YAML leaf URLs were pushed to string_refs twice (once with NULL key_path
in handle_string_refs, once via the key_path-aware YAML walk); the NULL-key_path
copy bypassed the upstream/config-URL deny check and minted spurious Route nodes.
Skip YAML in handle_string_refs so the key_path walk is the sole authority.
#523: the sequential pass dropped calls to external/unindexed HTTP client libs
(requests.get) before the service-pattern check; classify on the raw callee_name
in the empty-resolution branch and emit the HTTP/ASYNC edge (target=NULL), mirroring
the parallel path, so cross-repo matching can link it.
#520: fixture omitted the required project arg to detect_changes (production
correct); pass project derived from the tmpdir.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-27 14:31:17 +02:00
Martin Vogel da506f7b17 fix(grammar): extract calls for 11 niche grammars (HDL/asm/build/proof langs)
calls-extracted reds: the call node type was absent from the language spec
and/or the callee identifier was nested too deep for the generic resolver.
Per-language: Verilog/SystemVerilog (tf_call), VHDL (parenthesis_group),
NASM (actual_instruction call/jmp operand), LLVM-IR (instruction_call callee
field), Agda (application expr head qid), FunC (function_application),
Makefile (shell_function), Puppet (include_statement + puppet_keywords so
include/require survive the keyword filter). Just: recipe dependency is the
only call-shaped node, so the fixture asserts the dependency callee 'build'
(grammar exposes no recursive-just call node).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-27 13:13:00 +02:00
Martin Vogel 3f754cf449 fix: 17 reproduce-first issue + new-bug fixes (per-case verified)
Each was RED (reproduce-first). Verdicts: production bug unless noted.

- #510 nested .gitignore: load root .gitignore unconditionally (discover.c).
- #403 IDE dir: add "Antigravity" to ALWAYS_SKIP_DIRS.
- #571 CJK project name: transliterate non-ASCII bytes to hex in fqn.c (was -> "-").
- #520 detect_changes: include untracked files (git status --porcelain -uno) (mcp.c).
- #363 CBM_MEM_BUDGET_MB env override (mem.c).
- #570 Codex dual-hook: write the hook to hooks.json when present (cli.c).
- #431 VSCode per-profile mcp.json (cli.c).
- #521 routes from config URLs: deny upstream/jwks/healthcheck/... keys (pipeline.c).
- #548 D:\ browse: normalize sep before is_dir + drive-root self-parent (http_server.c);
  TEST A was a broken fixture (called is_dir on backslash) -> corrected to the
  production sequence; assertion unchanged.
- #495 Rust cfg-gated twins: fold #[cfg(...)] into the QN (extract_defs.c).
- new_py_tuple_unpack: handle pattern_list/tuple_pattern LHS -> Variable per id.
- new_ts_class_field_arrow: class arrow-field -> Method + scope (extract_defs.c).
- repro_extraction/#554 C++ out-of-line: compute_func_qn class-qualifies the call's
  enclosing QN via cbm_cpp_out_of_line_parent_class (extract_unified.c + helpers.h).
- #523 cross-repo HTTP_CALLS: emit service-pattern edge with target=NULL when the
  client lib is unindexed (pass_calls.c, pass_parallel.c).
- #514 data_flow arg expressions: serialize "args" on CALLS edges + propagate
  through store BFS + mcp data_flow (pass_calls.c, store.h/.c, mcp.c).
- #627 query_graph: size_t malloc + NULL-check; OPTIONAL MATCH from bound terminal
  so WHERE c IS NULL returns orphans correctly (cypher.c).
- #546/#480 trace_path: union BFS across same-name nodes (.d.ts dup) (mcp.c).

DEFERRED (need a maintainer decision, untouched): #56 cross-crate Rust (needs Cargo
workspace plumbing / Rust cross-LSP — architectural), #607 reinstall-deletes-index
(cbm_remove_indexes is shared with uninstall/update where deletion is intended).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-27 11:59:59 +02:00
Martin Vogel 011c129ef9 fix(repro): resolve markdown/awk/issue471 per maintainer decisions
Three flagged decisions, resolved with the maintainer (accuracy-first):

- Markdown heading label: production correctly mints "Section" (a valid, accurate
  label); a heading is not a Class. Correct the repro ASSERTION "Class"->"Section"
  rather than degrade the graph to match the test.
- AWK: a bare `rule` (`{...}`/`/re/{...}`/BEGIN/END) is ANONYMOUS top-level code,
  not a named callable -> a call inside a rule is legitimately Module-sourced.
  Remove "rule" from awk_func_types (it is not a function boundary) and rewrite
  the fixture so the call-under-test (`inner`) lives inside a named `function`
  (`process`), validly exercising callable-sourcing. The graph stays accurate.
- issue471: convert the flaky wall-clock perf reproduction into a DETERMINISTIC
  termination guard. At N=5000 the O(n^2) parse sits at ~15 s (the alarm) and
  flipped red/green on CI load; N=2000 finishes <1 s under any load, so the
  "deeply-nested ambiguous parse terminates (no hang/crash)" assertion is now
  stable on all platforms. The O(n^2) perf bug #471 remains OPEN, tracked
  separately (wall-clock perf cannot be reliably CI-gated).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-27 10:20:35 +02:00
Martin Vogel 19d34b5ff7 fix(extract): grammar def-label + malformed-QN fixes
Per-case-verified (AST-confirmed) production fixes for def-extraction reds.

DEF-LABEL:
- Zig: struct name is on the parent variable_declaration's identifier (value is a
  struct_declaration) -> resolve it -> "Class".
- Dockerfile/GoMod/PROPERTIES: get_module_parents() returned NULL for these, so
  extract_variables bailed at the module gate and never reached var extraction.
  Wire their module parents (properties roots at `file`); add PROPERTIES
  (property->key) + GoMod (require_spec->module_path) var-name cases -> Variable.
- K8s/Kustomize: K8s emitted "Resource", which is NOT in the valid-label set (so
  the def was dropped by label validation) -> use the valid "Class"; Kustomize
  emitted no def -> mint a "Class" from `kind:`.
- BitBake: bitbake_func_types referenced a nonexistent node; use the real
  function_definition/anonymous_python_function + a name resolver -> Function.
- PKL: classMethod name nested in methodHeader>identifier -> Function (+ a
  module-level function added to the fixture source).

MALFORMED QN:
- Makefile: skip dot-prefixed targets (.PHONY/.DEFAULT are directives, not defs).
- INI: section name is the inner `text` child (was "[database]\n").
- Markdown: collapse whitespace in heading QN segments (def.name stays readable).

ACCURACY NOTE: kept the Markdown heading label as "Section" (a valid, accurate
label) rather than degrade it to "Class" to satisfy the repro assertion -- a
heading is not a class. The assertion is the inaccurate side; Markdown
"no def labelled Class" intentionally stays RED pending review of that assertion.

Reproduced by repro_grammar_{core,build,config,markup,systems} (RED).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-27 09:49:00 +02:00
Martin Vogel 8853ed6360 fix(extract): callable-source cfml/gotemplate; correct scss/move/qml/pine fixtures
Per-case-verified callable-sourcing fixes (AST-confirmed via a standalone dumper).

PRODUCTION BUGS (a def-extractor minted a "Function" for a node kind absent from
function_node_types, desyncing def-extraction from call-scope attribution):
- CFML: cf_function_tag is minted as a Function by extract_cfml_function_tag but
  was not in cfml_func_types, so no SCOPE_FUNC was pushed -> in-body calls sourced
  to Module. Add "cf_function_tag" to cfml_func_types + compute_cfml_func_qn
  (reads the name from cf_attribute, gated in compute_func_qn which has source);
  the cf_function_tag walk_defs case now pushes children + continues so the
  generic extract_func_def does not double-mint.
- GoTemplate: define_action minted by extract_gotemplate_define but
  function_node_types was empty. Add gotemplate_func_types={"define_action"} +
  compute_gotemplate_func_qn (strips the quoted template name); the define_action
  walk_defs case pushes children + continues (its `name` field is a quoted string,
  which the generic path would double-mint with quotes).

BROKEN FIXTURES (production correct):
- SCSS: `@include` sat in a CSS rule_set (not a callable) -> legitimately
  Module-sourced. Moved it inside a `@mixin card { }` body.
- Move: named-address `module calc::math` + expression bodies made the grammar
  emit ERROR nodes (failed even extract-clean). Switched to `module 0x1::math`
  with statement-terminated bodies; the in-body `add(x,1);` now callable-sources.
- QML/Pine: the only in-body calls targeted EXTERNAL symbols (Math.max/ta.ema ->
  no edge) and the same-file calls were top-level. Added a same-file callee called
  in-body; removed the top-level calls. Dim-6 callee assertions preserved.

Reproduced by repro_grammar_{web,systems,markup,misc} callable-sourcing (RED).
AWK + Dart still deferred to focused tasks.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-27 09:08:15 +02:00
Martin Vogel d63ba9f66d fix(extract): callable-source Lisp/Elixir in-body calls; correct starlark fixture
Per-case-verified callable-sourcing fixes (AST-confirmed via a standalone dumper).

PRODUCTION BUGS:
- Clojure/Scheme/Racket: [CBM_LANG_*] had empty function_node_types, so no
  SCOPE_FUNC was pushed and every in-body call sourced to Module. Wire
  clojure_func_types={"list_lit"}, scheme/racket={"list"}. Since these kinds also
  match plain call forms, gate def-vs-call in compute_func_qn (extract_unified.c,
  which has ctx->source; the shared resolver does not): compute_lisp_func_qn
  returns the def name only when the list head is a def-form (defn/define/...),
  NULL otherwise, so non-def lists like (add x 1) push no scope.
- Elixir: def/defp/defmacro are `call` nodes (so are in-body calls); the shared
  resolver returned NULL for them. compute_elixir_func_qn names a def call (gated
  strictly on the def-macro target) and returns NULL for non-def calls.

BROKEN FIXTURE (production correct) -- Starlark: extraction works; the in-body
go_binary(...) callee is an EXTERNAL undefined rule, so it correctly yields no
CALLS edge (unresolved callee -> no edge, universal behavior). Added a same-file
_base_deps() def called inside make_binary's body for a resolvable in-body call
-> Function-sourced edge. go_binary(...) kept (dim-6 callee assertion preserved).

Reproduced by repro_grammar_{functional,scripting,config} (Clojure/Scheme/Racket/
Elixir/Starlark callable-sourcing were RED). AWK (rule-naming) + Dart (structural)
deferred to focused tasks.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-27 08:37:57 +02:00
Martin Vogel c669477c63 fix(extract): nickel def/call extraction; correct broken callable-sourcing fixtures
Per-case verification (AST-confirmed) of three RED expression-config-language
reproductions, distinguishing genuine production bugs from broken fixtures.

PRODUCTION BUG — Nickel (def + call were not extracted):
- nickel_func_types "fun" -> "fun_expr": the bare `fun` matched only the keyword
  token, never a node; the lambda node is `fun_expr` (anonymous), whose name is on
  the enclosing let_binding's `pat` field, so cbm_resolve_func_name climbs to the
  let_binding to name it (anonymous lambdas self-filter).
- nickel_call_types "infix_expr" -> "applicative": infix_expr is binary-operator
  application (`a + b`); the real call `f x y` is a curried `applicative`. New
  extract_nickel_callee emits one edge per curried call (requires a `t2` arg,
  outermost applicative only), guarded against the pass-through applicative
  wrapper that surrounds every Nickel value.

BROKEN FIXTURES (production correct) — the callable-sourcing invariant requires
module_sourced==0, but these fixtures called functions at the TOP LEVEL (the
output expression), which is legitimately Module-sourced. Each fixture corrected
so its only call sites are INSIDE a function body and the output merely REFERENCES
the function; all def/call assertions preserved (makeServer/addPort/go_binary defs
+ their calls remain):
- jsonnet: output `server: build`, `local build(host)=makeServer(host,8080)`.
- nickel:  output `make = mkServer`; `addPort port 0` stays in mkServer's body.
- starlark: `default_rule = make_binary`; go_binary stays in make_binary's body.

Reproduced by repro_grammar_config (jsonnet/nickel/starlark callable-sourcing +
nickel def/call were RED).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-27 08:13:00 +02:00
Martin Vogel 06ea36d237 ci: CBM_REPRO_ONLY suite filter + reliable (ASan) fast lane
- repro_main: RUN_SUITE honors CBM_REPRO_ONLY (comma list of suite-name
  substrings) for fast targeted validation of a single fix.
- fast-repro.yml: ASan single-platform (the no-sanitizer build crashed some
  suites); single-platform is the speedup vs the 5-platform board.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-26 23:46:19 +02:00
Martin Vogel ed94b40707 ci: per-suite summary in repro runner + lane branches skip the full board
- repro_main.c: redefine RUN_SUITE to print '[SUITE] <name> P passed, F failed'
  so board/fast-lane output is greppable for which suites still have reds.
- bug-repro.yml: exclude qa/fast-** / qa/soak-** / qa/smoke-** from the board
  push trigger (those branches run only their dedicated lane workflow).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-26 23:37:18 +02:00
Martin Vogel 7e4ec14a06 test(repro): fix repro_grammar_build.c nested block-comment (-Werror=comment)
The doc comment literally contained a block-comment opener while explaining the
no-nested-comment rule, breaking the test-repro build on all platforms. Reword.
(make test was unaffected — repro files are not in ALL_TEST_SRCS — but the board's
test-repro runner failed to build, blocking all board validation.)

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-26 22:57:47 +02:00
Martin Vogel 2f2b3771b1 test(repro): grammar battery — final 15 langs (100% grammar coverage)
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>
2026-06-26 21:52:54 +02:00
Martin Vogel 66cf07a9e8 test(repro): grammar batteries — scientific/shaders + markup/docs
- scientific (15): GLSL/HLSL/WGSL/ISPC/Slang/Cairo/Sway/FunC/Wolfram/MATLAB/Magma/
  FORM/TLA+/Agda/Apex — full battery; callable-sourcing RED across the board
  (grammar-only, no cross-LSP rescue); FunC/Wolfram/FORM/TLA+/Agda calls-extraction
  at-risk RED (unusual call-node types) + robustness dim.
- markup (18): Markdown/RST/Typst/BibTeX/Mermaid/PO/Diff/Regex/CapnP/Smithy/WIT/QML/
  Liquid/Jinja2/Blade/PureScript/SOQL/SOSL — adaptive (docs/schema structural,
  Typst/QML/PureScript callable) + robustness dim. Markdown headings→Class (BM25 #518).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-26 21:46:34 +02:00
Martin Vogel 720ebc5038 test(repro): grammar batteries — build/infra + shells/misc
- build/infra (15): Dockerfile/Makefile/CMake/Meson/GN/Just/K8s/Kustomize/GoMod/
  Requirements/Gitignore/Gitattributes/SSHConfig/BitBake/Puppet — adaptive
  (structural defs + CMake/Make/Just/Puppet/BitBake callables) + robustness dim.
- shells/misc (19): Bash/Zsh/Fish/PowerShell/Tcl/Awk/Vimscript/Fennel/Janet/Nix/
  GDScript/Luau/Teal/Smali/LLVM-IR/NASM/DeviceTree/Kconfig/Hyprlang — full battery
  for callable shells (PowerShell/Tcl/Awk/Fennel/Nix/Teal callable-sourcing RED via
  enclosing-func drift), structural for asm/data; robustness dim each.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-26 21:39:35 +02:00
Martin Vogel 9d8420285f test(repro): grammar battery — config/data languages
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>
2026-06-26 21:32:03 +02:00
Martin Vogel 2128f2b118 test(repro): LSP-pass invariants — TS, Java/C#, Kotlin/PHP/Rust
Completes per-pass coverage for all hybrid LSPs:
- repro_lsp_ts: 8 ts_lsp strategies (ts_local/method/namespace/import/jsx/jsx_import).
- repro_lsp_java_cs: 16 Java lsp_* (type/inherited/outer/super/this/static dispatch,
  interface_resolve/dispatch, method_ref*, constructor*) + 13 C# cs_* (cs_method_*/
  static/extension/ctor — C# uses its own cs_ vocabulary, not lsp_).
- repro_lsp_kt_php_rust: 14 Kotlin lsp_kt_*, 7 PHP php_*, 8 Rust lsp_* — Rust all RED
  (pass_lsp_cross.c has no CBM_LANG_RUST → cross-LSP never runs for Rust).
Each asserts callable-sourcing + strategy-presence in the CALLS edge.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-26 21:25:31 +02:00
Martin Vogel 648f0d399c test(repro): grammar battery — web/markup/schema languages
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>
2026-06-26 21:19:04 +02:00
Martin Vogel b9bd471cb1 test(repro): grammar battery — systems languages
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>
2026-06-26 21:12:28 +02:00
Martin Vogel 0b232ba14a test(repro): grammar batteries (scripting, functional) + Go/Python LSP passes
- repro_grammar_scripting: Python/Ruby/PHP/JS/TS/TSX/Lua/Perl/R/Julia/Groovy/Dart
  full invariant battery (Perl/R/Julia/Groovy/Dart callable-sourcing RED).
- repro_grammar_functional: Haskell/OCaml/F#/Elixir/Erlang/Elm/Clojure/Scheme/
  Racket/CommonLisp/EmacsLisp/Lean/Gleam (Elm calls-extraction RED; all dim-7 RED
  via enclosing-func drift).
- repro_lsp_go_py: 7 Go strategies (direct/type/embed/interface_resolve+dispatch/
  cross_file/unresolved) + 14 Python strategies (method/super/super_init/
  module_attr/dict_dispatch/operator_dunder/builtin*/generic_method/method_union),
  each asserting callable-sourcing + strategy-presence.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-26 13:46:46 +02:00
Martin Vogel daa554b08c test(repro): C/C++ LSP-pass invariants (18 resolution strategies)
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>
2026-06-26 13:39:43 +02:00
Martin Vogel 64b7a1af38 test(repro): invariant lib + per-grammar battery (core compiled/OOP langs)
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>
2026-06-26 13:15:21 +02:00
Martin Vogel b897d5db1e test(repro): deep invariant dives — enclosing-func drift, LSP rescue, discovery/FQN
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>
2026-06-26 12:59:54 +02:00
Martin Vogel c66719a7ce test(repro): large graph-quality INVARIANT test group
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>
2026-06-26 12:15:33 +02:00
Martin Vogel d2ec388e89 test(repro): memory-budget #363 + bounded RSS-soak #581
- #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>
2026-06-26 10:17:41 +02:00
Martin Vogel 895069ae5c test(repro): fix #471 Windows build (unused-function under -Werror)
build_perl_nested_calls is only used in the POSIX fork/alarm branch; on Windows
the test body is SKIP_PLATFORM, so the helper was unused and tripped
-Werror=unused-function (windows-only board failure). Mark it unused.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-06-26 09:57:08 +02:00
Martin Vogel 51cc7d8b12 test(repro): #548 lighter harness, strengthen #56, + 3 NEW bugs
- #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>
2026-06-26 09:55:14 +02:00
Martin Vogel 8bf892cd8f test(repro): GLR blowup #471 + opencode PATHEXT guard #221
- #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>
2026-06-26 07:01:59 +02:00
Martin Vogel 806da45896 test(repro): more install/UX + persistence reproductions for #607, #403, #434
- #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>
2026-06-26 01:49:57 +02:00
Martin Vogel ed15d0611a test(repro): install/UX reproductions for #570, #409, #431
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>
2026-06-26 01:43:54 +02:00