fix(agent-tooling): search order, --lite umbrella breakage, Rust test false-positives, export-snapshot (closes #218) - #234
Conversation
The --help epilog and module docstring showed `codelens search . "query"` (workspace first), the opposite of the actual argparse signature (pattern first, workspace second) — every other umbrella command takes workspace first, so this is an easy trap. Following the wrong example does not error: the workspace path silently becomes the search pattern and returns an empty "ok" result with zero indication anything went wrong. Found while exercising search end-to-end across a polyglot workspace (rs/ts/tsx/js/css/html).
`graph` mode's `truncated` field was set to True whenever the query merely contained a LIMIT clause, regardless of whether any rows were actually cut off — a `LIMIT 50` query matching 1 row reported `truncated: true`, misleading callers into thinking more results existed. Now computed from the real row count vs. limit. Added a regression test covering the under-filled-LIMIT case, which the existing test_truncated_flag test never exercised (it only tested LIMIT-with-enough-matches and no-LIMIT-at-all).
Rust unit tests live inline in the same file as production code inside
`#[cfg(test)] mod tests { #[test] fn ... }`, unlike JS/Python where
tests sit in a separate tests/ directory (already exempted by the
existing test-path patterns). Without this, every Rust test function
and every `mod tests` module false-positives as dead code, since the
test harness invokes them via attribute discovery, not a CALLS edge.
Measured on a real 192-file Rust workspace: this was 56%+ of all
Rust registry_dead findings in the top-100 window (100->69 after the
fix, with `mod tests` blocks also newly exempted). Detects #[test],
#[tokio::test], #[async_std::test] and other `#[x::test]` attribute
variants by checking the source lines immediately above the flagged
symbol.
…snapshot (closes #218) export-snapshot was dropped entirely in the #195 umbrella consolidation with no replacement, so import-snapshot could never find a snapshot file to load ("Snapshot file not found" on every run) — the underlying build_snapshot()/write_snapshot() logic in snapshot_io.py was never deleted, just orphaned with no CLI entry point. Added `deps --check export-snapshot` as a new sub-mode (mirroring import-snapshot's own structure), and verified a full export->import round trip preserves node/edge counts. Also excluded both import-snapshot and export-snapshot from the bare `codelens deps <workspace>` default: they are side-effecting/opt-in actions that always failed with no --input/--output given, so every default `deps` run showed a spurious unrelated error entry. See docs/design/0218-export-snapshot.md for the full design rationale.
Two related bugs found while exercising every umbrella command's --lite output on a real 425-file polyglot workspace: 1. _apply_lite's reducer dispatch table predates the #195 umbrella consolidation and keyed off the OLD leaf command names (smell, dead-code, query, ...). Since umbrella commands always pass their own name (context, audit, security, deps, ...), no branch ever matched, and every umbrella's --lite output silently collapsed to `{"status": "ok"}` with all data dropped. Fixed by unwrapping the `{"s","st","r":[{"_check":name,...}]}` envelope, applying the existing per-check reducers keyed by each item's own `_check` name, then re-wrapping. 2. summary/history are not umbrella-wrapped, so they hit the generic fallback instead — which doesn't know their real field names. summary's own job is "anti-overload prioritized findings" per its --help text, but --lite returned the same multi-thousand-token payload as non-lite (nested top_items/flow_chain per finding were never trimmed). history --lite collapsed to just `{"status", "workspace"}`, dropping snapshots/latest/trends/deltas entirely. Added dedicated reducers for both. Also: _force_utf8_stdio() (the issue #179 Unicode-crash fix) rewraps stdout/stderr with TextIOWrapper(encoding='utf-8') but never set newline='', so every '\n' written on Windows silently became '\r\n' (Python's default write-side os.linesep translation) — affecting every line CodeLens prints on Windows. Fixed by adding newline=''. Caught by an existing test that was failing before this fix.
Result of exercising every umbrella command (search/context/audit/ security/deps/impact/api-map/summary/history/doctor/graph) end-to-end against a real 425-file polyglot workspace (Rust/TS/TSX/JS/CSS/HTML Tauri+React app) plus CodeLens's own Python codebase. Documents: the search pattern/workspace argument-order trap, which command to use for which "replace grep" question, --lite reducer coverage per command, per-language verified coverage (including the confirmed gap: no Rust taint analysis), and a changelog of the 6 fixes made this session with before/after verification evidence.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
|
CI failures on this PR (`quality-gate` x4, `Test Suite`) are pre-existing on `main`, not caused by these changes — verified by checking `gh run list --branch main`: the merge commit for PR #233 (last merge before this PR) already shows both jobs failing. Root causes filed separately as #235:
Locally verified (Windows, excluding the two known-flaky/segfaulting test files per the documented baseline methodology): all directly-touched test files pass — `test_export_snapshot.py` (new, 7/7), `test_query_graph.py`, `test_deadcode_engine.py`, `test_command_registry.py`, `test_codelens.py` (81/81), `test_issue195_consolidation.py`. Full command outputs and before/after CLI verification for every fix are in the commit messages and `docs/agent-usage-guide.md`. |



Summary
Direct verification pass driven by the goal "make CodeLens genuinely usable as an agent's primary tool, replacing manual grep, across js/css/html/react/py/rs/ts" — exercised every umbrella command end-to-end against a real 425-file polyglot workspace (Rust/TS/TSX/JS/CSS/HTML Tauri+React app) and CodeLens's own Python codebase, fixed everything broken directly (no worker per explicit directive), with before/after verification for each fix.
Fixes
search --helpexample order was backwards — docs showedworkspacebeforepattern, opposite of the real signature. Following it silently returns an empty result.graphmodetruncatedflag was meaningless — alwaysTruewhenever a query had aLIMIT, regardless of whether results were cut off.--litewas completely broken for all 12 umbrella commands — reducer dispatch predates the refactor(commands): consolidate 78 commands → 12 focused commands #195 consolidation, keyed off old leaf command names that never match the new umbrella names. Every umbrella's--litesilently returned{"status": "ok"}with all data dropped.#[test]functions false-flagged as dead code — measured 56%+ of all Rustregistry_deadfindings on a real workspace before the fix.deps --check import-snapshotpermanently broken (closes chore(deps): import-snapshot permanently broken since export-snapshot was dropped #218) —export-snapshotwas dropped in refactor(commands): consolidate 78 commands → 12 focused commands #195 with no replacement; restored asdeps --check export-snapshot, verified full round trip.summary/history--litestill returned bloated/empty output even after fix refactor: backend-focused cleanup — remove hardcoded paths, garbage files, frontend deps #3 (they're not umbrella-enveloped, hit the generic fallback which doesn't know their field names)._force_utf8_stdio()never setnewline='', silently turning every\ninto\r\non Windows.Test plan
pytest tests/— all directly-touched test files pass (search, query_graph, deadcode_engine, export_snapshot [new], command_registry, codelens)codelens scan .unrelated to these changes), documented indocs/agent-usage-guide.mddocs/agent-usage-guide.md"Fixed this session" sectionsync_command_count.py --apply— docs stay in sync, count unchanged (export-snapshot is adepssub-check, not a new top-level command)🤖 Generated with Claude Code — direct fix session (no worker), full details in docs/agent-usage-guide.md