Skip to content

feat: make CLI and MCP output lean by default - #1597

Open
DeusData wants to merge 30 commits into
mainfrom
feat/lean-output-contract
Open

feat: make CLI and MCP output lean by default#1597
DeusData wants to merge 30 commits into
mainfrom
feat/lean-output-contract

Conversation

@DeusData

Copy link
Copy Markdown
Owner

What does this PR do?

Makes CLI and MCP responses lean by default while preserving the graph answer itself.

  • keeps core graph rows, exact totals, truncation state, and continuation cursors in the default response
  • moves diagnostics, evidence, progress, and other operational detail behind explicit flags/parameters
  • adds semantic-boundary output budgets and lossless, snapshot-bound pagination instead of byte-slicing answers
  • adds response-local directory-prefix dictionaries only when the serialized and token-shape estimates show a material win
  • keeps JSON as an explicit opt-in and adds a quiet CLI mode
  • preserves invalid UTF-8/reversible identities instead of replacing bytes
  • scopes code search to canonical indexed files and keeps scoped file globs portable to BusyBox/Alpine
  • documents the lean/default versus detailed contracts and adds regression/size contracts

Measured output reduction

On the same serialized MCP tools/list fixture:

  • bytes: 23,075 -> 15,071 (-34.7%)
  • cl100k tokens: 5,068 -> 3,478 (-31.4%)
  • o200k tokens: 5,151 -> 3,570 (-30.7%)

For repeated-path result tables, response-local directory compression reduced token-shaped output by 38.3% on Unix paths and 44.5% on Windows paths. Scattered/token-hostile inputs remain uncompressed, so the optimization does not make those responses larger.

Output contract

  • defaults are compact, but not lossy: graph identities/rows, exact counts, safety signals, and continuations remain present
  • max_output_tokens is enforced as a deterministic model-neutral byte ceiling at whole semantic units
  • omissions are explicit and independently pageable
  • cursors are bound to query arguments, result state, and index generation; stale cursors fail closed
  • directory prefixes are response-local, non-recursive, and emitted only above exact savings thresholds

Validation

Final commit:

  • env CBM_NO_CCACHE=1 scripts/test.sh --suites mcp: 253 passed, 2 expected skips, no sanitizer findings

Completed before the final two-file BusyBox portability follow-up:

  • macOS full sanitizer suite: 7,537 passed, 4 expected skips
  • Linux arm64 sanitizer suite: 7,375 passed, 4 expected skips
  • container lint/static-format gate: passed
  • deliberate RED-on-revert checks bound the CLI quiet/runtime, MCP output, search completeness, and watchdog-isolation regressions

The wider final rerun and native Windows completion were stopped to publish the PR; hosted CI is expected to validate the final merge tree. The prior Windows attempt failed in test infrastructure before product tests because a concurrent VM cleanup removed its live temp root; the affected infrastructure files are unchanged by this branch.

Checklist

  • Every commit is signed off
  • Focused tests pass locally on the final commit
  • New behavior is covered by regression and output-size contracts
  • Documentation is updated

@DeusData DeusData added enhancement New feature or request maintainer-notes Internal observations and improvement notes priority/high Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker. labels Aug 18, 2026
@DeusData
DeusData force-pushed the feat/lean-output-contract branch 2 times, most recently from b900338 to 10d05b3 Compare September 5, 2026 03:29
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>

# Conflicts:
#	tests/test_cli.c
Tool definitions no longer carry a separate title (the name is the MCP
display fallback), so the accessor main added for the pi adapter has no
field to read. The adapter already used the name when no title existed.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Fix-forward after rebasing onto main (545 commits, 26 conflicted-file
resolutions). Where main had shipped a behaviour in the meantime, main
wins; the PR keeps its output contract on top of it:

- search_code: the scan runs under main's supervised, deadline- and
  output-bounded runner and feeds the branch's streaming classifier from
  the runner's output file; the POSIX wrappers map grep's no-match to 0,
  so every non-zero exit fails closed (no exit-1 special case).
- trace_path: strategy/confidence precede args in header and rows (#1542),
  in both the tree table and the json legs.
- cypher: relationship expansion is never capped (a cap falsified
  aggregates) and unlabeled MATCH scans every candidate; `truncated` is
  raised only by a real ceiling — a clamped hop range is probed one hop
  beyond the cap and reports truncated only when a candidate exists there.
  The plain BFS and the trail BFS both probe one row past max_results so
  saturation is observable instead of silent.
- search_code full mode and the final json use main's U+FFFD sanitizer
  instead of '?' replacement.
- search_graph json keeps an empty `groups` array for semantic-only calls;
  list_projects json echoes offset/limit next to next_offset and accepts
  main's include_details spelling for the stats projection.
- discovery budget: main added get_file_outline, compare_graphs, manage_adr
  set_sections and the debug/include_details parameters; their descriptions
  are trimmed to the lean style and the ceiling moves from 15 to 18 KiB.

Tests that asserted a JSON default now request format:"json"; the
fail-closed search test uses an unreadable regular file (a missing or
non-regular indexed path is deliberately not a scan operand on main); the
non-regular fixture gives its real sources File nodes, as every indexed
project has; list_projects total counts listable projects (the 0-byte
ghost is never a row, so it is not a page either).

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- test_daemon_lifecycle.py: daemon coordination is account-wide and
  CBM_CACHE_DIR does not move the rendezvous (main's CBM_RUNTIME_DIR
  relocation), so a private CBM_RUNTIME_DIR per cache is what makes the
  --verbose call cold and lets it observe the spawn hint.
- test_hook_augment.py: the CLI answers in the lean tree form by default;
  the guard parses the JSON projection, so it asks for it.
- test_mcp.c: the fail-closed search test skipped on Windows past the
  teardown that names its POSIX-only response.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The hint moved into a structured info record when one-shot CLI output
went quiet by default. Structured values escape spaces, so the record
read `daemon_start` and a person (and the Windows lifecycle guard) could
not find `daemon start` in it. Keep the quiet default and, when --verbose
or CBM_LOG_LEVEL=info opts in, print the same plain stderr hint the CLI
printed before.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The unreadable-operand scenario used mode-0 permission bits, which
Windows cannot express and root ignores (the Colima legs run as root), so
the test skipped on both — and bare SKIP() is forbidden. The scoped file
list deliberately drops every missing or non-regular indexed path before
grep sees it, so a refusal can only come from the scan itself. The scan
seam now delivers one plausible hit and then grep's error status, on every
platform, and the test asserts that neither that hit nor zero matches is
ever reported as a complete page.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
@DeusData
DeusData force-pushed the feat/lean-output-contract branch from 10d05b3 to a15d99e Compare September 5, 2026 04:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request maintainer-notes Internal observations and improvement notes priority/high Needs near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant