|
2 | 2 |
|
3 | 3 | All notable changes to jcodemunch-mcp are documented here. |
4 | 4 |
|
| 5 | +## [1.108.186] - 2026-07-26 - the ledger stops claiming a channel that never ran |
| 6 | + |
| 7 | +### Fixed |
| 8 | + |
| 9 | +- ⚠ **`get_ranked_context`'s fusion exit recorded `semantic_used=True` on every |
| 10 | + ranking-ledger row while building no similarity channel.** That exit builds |
| 11 | + lexical, identity and structural — its own `_meta.channels` lists the three, and |
| 12 | + since v1.108.185 its verdict reports `channels.semantic: "off"` — so the response |
| 13 | + and the ledger disagreed about the same call, and the ledger was the one that was |
| 14 | + wrong. Disclosed as deliberately deferred in v1.108.185 because the column feeds a |
| 15 | + learned parameter; this is the follow-through. |
| 16 | + |
| 17 | + The flag is now derived from the channels actually built |
| 18 | + (`any(ch.name == "similarity" for ch in channels)`) rather than hardcoded to |
| 19 | + `False`, so adding a similarity channel there picks it up with no second edit — |
| 20 | + the same shape `search_symbols_fusion` already had. The verdict's |
| 21 | + `semantic_channel` now comes off the same derivation, so the two cannot diverge |
| 22 | + again. |
| 23 | + |
| 24 | +- ⚠ **Flipping the flag was necessary and not sufficient: the ledger is |
| 25 | + append-only.** `WeightTuner` learns a per-repo `semantic_weight` by splitting rows |
| 26 | + on that column and comparing mean confidence between the groups, so pre-fix rows |
| 27 | + keep steering it for the whole 90-day recency window. **Reproduced before fixing: |
| 28 | + 30 honest lexical rows at 0.80 confidence plus 30 mislabelled fusion rows at 0.40 |
| 29 | + walked `semantic_weight` from 0.5 to 0.45, on a ledger whose honest labels decline |
| 30 | + to move it at all.** |
| 31 | + |
| 32 | + New `retrieval/ledger_trust.py` holds the one rule that says which labels are not |
| 33 | + evidence, shared by all three consumers rather than copied into each. **The rows |
| 34 | + are exactly identifiable with no heuristic:** they carry |
| 35 | + `tool = "get_ranked_context_fusion"`, a value no other producer writes, so a |
| 36 | + pre-fix row is precisely that tool with `semantic_used = 1` and a post-fix row is |
| 37 | + the same tool with `0`. A tool-only rule would have discarded the fix's own honest |
| 38 | + rows. |
| 39 | + |
| 40 | +- ⚠ **`suggest_corrections` was reporting a vocabulary gap on calls where identity |
| 41 | + matching ran.** Regret's `vocabulary_gap` signal is the conjunction |
| 42 | + `not identity_hit and semantic_used`, and that exit hardcoded the semantic flag |
| 43 | + AND passed no ledger features at all — so `identity_hit` defaulted to 0 while the |
| 44 | + identity channel was one of the three it built. Every confident fusion call was a |
| 45 | + textbook match for "the agent's term doesn't match a symbol name", and those |
| 46 | + clusters become config patches shown to the user. Untrusted rows are dropped from |
| 47 | + that signal. |
| 48 | + |
| 49 | +### Changed |
| 50 | + |
| 51 | +- **The historical rows are excluded, disclosed, and neither rewritten nor counted |
| 52 | + as semantic-off.** Three options were weighed. A one-time corrective `UPDATE` was |
| 53 | + rejected on charter grounds, not convenience: the tuner has only ever written the |
| 54 | + `tuning.jsonc` sidecar and `suggest_corrections` is read-only by charter, so |
| 55 | + rewriting a user's telemetry rows is a charter change. Letting the 90-day window |
| 56 | + age them out was also rejected — that is learning from a corpus we know is |
| 57 | + mislabelled. **Unknown is a third answer, not a vote for `semantic_used=0`:** |
| 58 | + folding those rows into the OFF group would be the same error mirrored, and it |
| 59 | + would move the weight just as far. Every consumer that reads the column now |
| 60 | + discloses the count — `events_semantic_label_unknown` on the tuner's signals and |
| 61 | + on `analyze_regret`, `semantic_label_unknown` per repo in `analyze_perf --ledger`. |
| 62 | + |
| 63 | +- ⚠ **The exclusion expires, and a drift guard says when.** It is only honest while |
| 64 | + that exit builds no similarity channel; if one is added, its `semantic_used=1` |
| 65 | + rows become real evidence and the rule would start discarding good data. A test |
| 66 | + fails if the exit grows a similarity channel while the rule is still |
| 67 | + unconditional. |
| 68 | + |
| 69 | +### Notes |
| 70 | + |
| 71 | +- **Real blast radius is small and worth stating plainly.** The ledger is opt-in |
| 72 | + (`perf_telemetry_enabled`, default `False`), so most installs hold no rows at all |
| 73 | + and were never affected. Installs that enabled telemetry and used |
| 74 | + `get_ranked_context(fusion=True)` have mislabelled rows, and for them the learned |
| 75 | + weight and the correction suggestions were both reading a lie. |
| 76 | +- Compatibility is pinned rather than asserted: a pre-fix ledger stays readable and |
| 77 | + unrewritten, and the new disclosure keys are absent — not zero — for a caller |
| 78 | + whose ledger holds no mislabelled row. |
| 79 | +- New `tests/test_v1_108_186.py` (22), including the real-route ledger check, a |
| 80 | + non-vacuity test for the derivation (patch a channel to be named `similarity` and |
| 81 | + both the ledger and the verdict must follow), non-vacuity tests that show the same |
| 82 | + ledger moving the weight and raising the cluster with the guard disabled, and the |
| 83 | + drift guard. No tool-count change, no `INDEX_VERSION` change, no schema change. |
| 84 | +- Found on the way and deliberately NOT folded in: `get_ranked_context`'s fusion |
| 85 | + exit passes no `extract_ledger_features` payload, so `top1_score`, `top2_score` |
| 86 | + and `identity_hit` are defaults rather than measurements on every row it writes; |
| 87 | + and `token_tracker._ensure_loaded(None)` on the first savings write repins the |
| 88 | + perf db to `~/.code-index` even when a tool was given a `storage_path`. |
| 89 | + |
5 | 90 | ## [1.108.185] - 2026-07-26 - fusion gets a verdict, and fusion can prove absence |
6 | 91 |
|
7 | 92 | ### Fixed |
|
0 commit comments