Skip to content

release/0.2.5793: fuzzy-find exact basename ranking + version sync#364

Merged
justrach merged 10 commits into
mainfrom
release/0.2.5793
May 3, 2026
Merged

release/0.2.5793: fuzzy-find exact basename ranking + version sync#364
justrach merged 10 commits into
mainfrom
release/0.2.5793

Conversation

@justrach

@justrach justrach commented May 3, 2026

Copy link
Copy Markdown
Owner

Summary

All of #363 + phase 1 of #356 — search recall, ranking, query reliability, and ergonomics. Closes #363; closes phase 1 scope of #356 (issue stays open for future phases).

Item Status Commits
#363a literal phrase / identifier search recall ✅ Fixed a6741ef (test) + caaf507 (fix)
#363b fuzzy find ranking ✅ Fixed 82c7598 (test) + 3b0650b (fix)
#363c bundle missing-arg UX ✅ Already shipped in v0.2.5792 (#357 / PR #362)
#356-1 codedb_query partial results ✅ Fixed 3206638 (test) + 615e89b (fix)
#356-2 codedb_outline fuzzy path fallback ✅ Fixed 3206638 (test) + 615e89b (fix)
#356-3 codedb_query received-keys diagnostic ✅ Fixed 3206638 (test) + 615e89b (fix)

Plus stale release_info.zig version sync (e33a90b).

How #363a was found

Sonnet 4.6 sub-agent driving the live MCP reproduced an analogous bug against this codedb repo: codedb_search query="searchContent" regex=false returned doc files but missed src/explore.zig itself. Root cause: Tier 0 of searchContent (explore.zig:1511) iterates word-index hits in posting-list order and saturates result_list with hits from heavily-mentioning files before source files indexed later get reached. Cap-per-file in Tier 0 (max(1, max_results / 5)) restores diversity.

How #363b was found

Direct code review. fuzzyScore at explore.zig:4948 gives lib.rs / main.go / index.ts a +5% special-entry-point bonus regardless of query. Combined with length normalization, this pushed the actual cli.rs exact-basename match below unrelated lib.rs files. Failing test reproduces with user's exact path layout. Fix: 4× multiplier on exact basename match.

#356 phase 1 scope (Agent Context Planner framing dropped)

The issue body was rewritten today to drop the "Agent Context Planner" framing — codedb stays a tool, agents stay in charge of composition. No automatic step composition, no natural-language intent parsing. Just three small reliability improvements:

  • Partial results in codedb_query. Pipeline previously bailed on first error and discarded prior-step output. Now prior-step output is preserved and a structured --- partial --- tail names the failing step + reason.
  • Fuzzy path fallback in codedb_outline. Bare error: file not indexed is now followed by did you mean: with up to 3 fuzzy matches.
  • Received-keys diagnostic for codedb_query missing-arg errors. Mirrors MCP bundle should preserve nested tool arguments for codedb_outline #357's bundle diagnostic. Wired through op-detection, find, search, word, and symbol error paths. Other error sites (transient failures, "needs prior step") keep previous behavior — incremental coverage in follow-up.

Test plan

  • zig build test — 428/428 pass
  • Failing tests for every issue item land before fixes (per CLAUDE.md repo policy)
  • Notarized darwin-arm64 binary built from this branch and installed at /Users/blackfloofie/bin/codedb for live verification
  • Reviewer: spot-check Tier 0 per-file cap doesn't hurt single-file dense matches (mitigated: display layer in mcp.zig:1095 already caps per-file output at 5)
  • Reviewer: spot-check 4× exact-basename multiplier doesn't disrupt other ranking expectations
  • Reviewer: confirm partial-results tail format (--- partial ---\nfailed_at: N\nreason: <text>) is parseable by agent clients

Commits

e33a90b chore: bump version to 0.2.5793 + sync release_info
82c7598 test(issue-363b): failing test for exact-basename ranking in fuzzy find
3b0650b fix(find): exact basename match dominates fuzzy ranking (#363b)
7b95c24 docs: add 0.2.5793 changelog entry
a6741ef test(issue-363a): failing test for word-index quota saturation
caaf507 fix(search): per-file cap in Tier 0 prevents quota saturation (#363a)
7595485 docs: update 0.2.5793 changelog — all of #363 fixed
3206638 test(issue-356): failing tests for query partial results, outline fuzzy fallback, query received-keys
615e89b fix(mcp): codedb_query partial results + outline fuzzy fallback (#356)
8cc9fd7 docs: update 0.2.5793 changelog — #356 phase 1 also fixed

🤖 Generated with Claude Code

justrach and others added 4 commits May 4, 2026 01:36
The previous v0.2.5792 release shipped with src/release_info.zig at
"0.2.579" while build.zig.zon was at "0.2.5792" — so binaries built
from that release self-reported as 0.2.579 even though they were
built from the 0.2.5792 source tree. Fixing both to 0.2.5793 here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reproducer from #363: querying 'cli.rs' against a workspace with
several crates returns unrelated lib.rs files ahead of the actual
crates/forge_main/src/cli.rs. The exact basename match should be
ranked first, not fifth.

Cause (next commit): fuzzyScore in src/explore.zig:4948 gives
'special entry points' (lib.rs, main.go, index.ts) a +5%
multiplicative bonus regardless of whether the query asked for them.
Combined with shorter path normalization, that pushes the actual
cli.rs match below the lib.rs decoys.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Querying 'cli.rs' against a multi-crate workspace returned four
unrelated lib.rs files ahead of the actual cli.rs. Two compounding
factors:

1. fuzzyScore gives lib.rs / main.go / index.ts a +5%
   special-entry-point bonus — applied regardless of whether the
   query asked for those names.
2. Path-length normalization (best_score / sqrt(path.len)) rewards
   shorter paths. lib.rs files with shorter parent paths beat the
   actual cli.rs match on length even when the cli.rs alignment
   was strictly better at the basename level.

Fix: when the query case-insensitively equals the filename, apply
a 4x multiplier so the exact match dominates length normalization
and the special-entry-point bonus on competing files. This mirrors
fzf-style "exact match always wins" behavior.

Companion test in src/tests.zig from the previous commit
(issue-363b: fuzzyFindFiles ranks exact basename match above
unrelated lib.rs) now passes; all 424 tests green.

Closes #363 (item b: fuzzy filename ranking).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Document the version sync fix, #363b basename ranking fix, and
honestly flag #363a as not-reproducible-in-isolation. Note that
#357 (received keys diagnostic, shipped in 0.2.5792) already
addresses #363c.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented May 3, 2026

Copy link
Copy Markdown

Benchmark Regression Report

Thresholds: 10.00% and 50,000 ns absolute delta

NOISE means the percentage threshold was exceeded, but the absolute delta was too small to fail CI.

Tool Base (ns) Head (ns) Delta Abs Delta (ns) Status
codedb_bundle 447560 453437 +1.31% +5877 OK
codedb_changes 47845 50153 +4.82% +2308 OK
codedb_deps 8774 7868 -10.33% -906 OK
codedb_edit 5383 5456 +1.36% +73 OK
codedb_find 54929 55205 +0.50% +276 OK
codedb_hot 84193 88176 +4.73% +3983 OK
codedb_outline 239283 242894 +1.51% +3611 OK
codedb_read 74944 74601 -0.46% -343 OK
codedb_search 152956 145428 -4.92% -7528 OK
codedb_snapshot 234853 239703 +2.07% +4850 OK
codedb_status 90401 77138 -14.67% -13263 OK
codedb_symbol 60137 53123 -11.66% -7014 OK
codedb_tree 38685 46394 +19.93% +7709 NOISE
codedb_word 60778 59650 -1.86% -1128 OK

justrach and others added 3 commits May 4, 2026 02:12
Sonnet 4.6 sub-agent driving the live MCP reproduced the bug
against this codedb repo: searchContent('searchContent') misses
src/explore.zig because doc-file hits saturate Tier 0's
result_list quota before the source-file hits at the end of the
word-index posting list are reached.

Test plants 4 doc files (4 mentions each = 16 hits), then 1
source file (2 hits, total 18). Picks max_results=10 so the
gate `word_hits.len <= max_results * 2` (18 <= 20) holds and
Tier 0 is the active code path. With doc files indexed first,
the source file's hits land at the end of the posting list and
get dropped when result_list fills.

This test fails on main; the fix in the next commit caps Tier 0
hits per file to ensure diversity.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
User reported that codedb_search query='pub struct ForgeApp'
returned only architecture.md, missing the canonical Rust source
file at crates/forge_app/src/app.rs:47 even though the phrase is
a contiguous substring there.

A Sonnet 4.6 agent driving the live MCP narrowed the bug down to
single-token queries against repos where doc files mention the
identifier many times. Tier 0 of searchContent (explore.zig:1511)
iterates word-index hits in posting-list (insertion) order and
appends each (path, line) hit to result_list. When the gate
`word_hits.len <= max_results * 2` holds, Tier 0 runs; once
result_list reaches max_results it returns. Doc files indexed
earlier than source files dominate the posting list, fill the
quota, and source-file hits at the end never make it in.

Fix: in Tier 0, track hits per path and cap them at
max(1, max_results / 5). For the default max_results=50 each file
contributes at most 10 hits, leaving room for at least 5 distinct
files in the result set. For small max_results the cap floors at
1 so diversity is preserved aggressively.

This is a minimal change — Tier 0 still runs first, the gate is
unchanged, and the cap doesn't affect Tier 1+ paths. The display
layer in mcp.zig already caps per-file output at 5 so user-visible
behavior for high-density single-file matches is unchanged.

Companion failing test in src/tests.zig from the previous commit
(issue-363a: searchContent surfaces source-file matches even when
doc files dominate the word index) now passes; all 425 tests green.

Closes #363 (item a: literal search recall).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Promote the release notes from "two fixes + #363a not reproduced"
to "all of #363 resolved" now that the Tier 0 quota saturation
fix landed. Restore the missing 0.2.5792 section header.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented May 3, 2026

Copy link
Copy Markdown

Benchmark Regression Report

Thresholds: 10.00% and 50,000 ns absolute delta

NOISE means the percentage threshold was exceeded, but the absolute delta was too small to fail CI.

Tool Base (ns) Head (ns) Delta Abs Delta (ns) Status
codedb_bundle 564954 554404 -1.87% -10550 OK
codedb_changes 65033 60406 -7.11% -4627 OK
codedb_deps 10100 9927 -1.71% -173 OK
codedb_edit 6007 5645 -6.03% -362 OK
codedb_find 65864 65465 -0.61% -399 OK
codedb_hot 105120 107029 +1.82% +1909 OK
codedb_outline 313713 326065 +3.94% +12352 OK
codedb_read 95341 96652 +1.38% +1311 OK
codedb_search 182388 174817 -4.15% -7571 OK
codedb_snapshot 279400 290287 +3.90% +10887 OK
codedb_status 106888 104722 -2.03% -2166 OK
codedb_symbol 63790 67550 +5.89% +3760 OK
codedb_tree 48792 52701 +8.01% +3909 OK
codedb_word 75685 76328 +0.85% +643 OK

justrach and others added 3 commits May 4, 2026 02:18
fallback, and query received-keys diagnostic

Three reliability improvements landed in this release per the rewritten
#356 scope (Agent Context Planner framing dropped):

  - issue-356-1: codedb_query pipeline currently bails on first error,
    discarding successful prior-step output. Test asserts step 0 output
    survives + a "--- partial ---" tail names the failing step.
  - issue-356-2: codedb_outline returns bare 'file not indexed' when the
    path doesn't index. Test asserts a 'did you mean' hint with the
    closest fuzzy match (src/main.zig for 'src/man.zig').
  - issue-356-3: codedb_query step missing-arg errors should surface
    'received keys: [...]' mirroring the #357 bundle diagnostic.

All three fail on main; fixes in subsequent commits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three reliability improvements landing as the rewritten phase 1 of #356
(Agent Context Planner framing dropped — codedb stays a tool, agent
stays in charge of composition):

1. codedb_query: partial results when a step fails. Pipeline previously
   bailed on the first error and discarded successful prior-step output.
   New behavior: the prior-step output is preserved and a structured
   "--- partial ---" tail names the failing step + reason. Callers can
   recover from a single bad step instead of starting over.

2. codedb_outline: fuzzy path fallback. A non-indexed path used to
   return a bare 'error: file not indexed: <path>'. Now appends up to
   3 fuzzy-matched indexed paths under a 'did you mean:' header, so an
   agent that mistypes a path can self-correct without a separate
   codedb_find round-trip.

3. codedb_query: received-keys diagnostic on missing-arg errors.
   Mirrors the #357 codedb_bundle diagnostic. When a step fails with
   e.g. 'search needs query' but the step actually has a 'q' key
   instead, callers see 'received keys: [op, q]' so they can tell
   whether codedb dropped the field or the client sent it under the
   wrong name.

Implementation:
  - New helper appendFuzzyPathSuggestions in mcp.zig — used in
    handleOutline's "file not indexed" path.
  - New helper finishQueryWithFailure in mcp.zig — emits both the
    received-keys diagnostic and the partial-results tail. Wired
    into the missing-arg error sites for op-detection, find, search,
    word, and symbol pipeline ops.
  - Other error paths in handleQuery (transient OOM, "needs prior
    step" for non-leading ops) keep the previous behavior; they don't
    surface received-keys but they will get partial-results coverage
    in a follow-up.

Tests: src/tests.zig adds three issue-356 cases (one per item) which
fail on main and pass with this commit. All 428 tests green.

Closes parts of #356 (phase 1 reliability scope).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Promote release notes to cover #356 phase 1 reliability work
(partial results, fuzzy path fallback, received-keys diagnostic
for codedb_query) alongside the original #363 fixes. Re-add the
0.2.5792 section header.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@justrach justrach merged commit b3bc56e into main May 3, 2026
1 check passed
@github-actions

github-actions Bot commented May 3, 2026

Copy link
Copy Markdown

Benchmark Regression Report

Thresholds: 10.00% and 50,000 ns absolute delta

NOISE means the percentage threshold was exceeded, but the absolute delta was too small to fail CI.

Tool Base (ns) Head (ns) Delta Abs Delta (ns) Status
codedb_bundle 522866 530419 +1.44% +7553 OK
codedb_changes 55722 72111 +29.41% +16389 NOISE
codedb_deps 8902 10211 +14.70% +1309 NOISE
codedb_edit 6732 6435 -4.41% -297 OK
codedb_find 61741 65311 +5.78% +3570 OK
codedb_hot 103115 97480 -5.46% -5635 OK
codedb_outline 284627 301595 +5.96% +16968 OK
codedb_read 99326 88185 -11.22% -11141 OK
codedb_search 179502 174939 -2.54% -4563 OK
codedb_snapshot 283428 273732 -3.42% -9696 OK
codedb_status 207328 211762 +2.14% +4434 OK
codedb_symbol 64507 58628 -9.11% -5879 OK
codedb_tree 48891 47242 -3.37% -1649 OK
codedb_word 72180 69501 -3.71% -2679 OK

@justrach justrach deleted the release/0.2.5793 branch May 21, 2026 06:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve literal search recall and exact filename ranking

1 participant