Skip to content

Commit 38b28f9

Browse files
jgravelleclaude
andcommitted
release: v1.108.187 — both fusion exits record the features they measured
get_ranked_context's fusion exit passed no extract_ledger_features payload at all, so top1_score, top2_score and identity_hit were recorded as defaults on every ranking-ledger row it wrote. Three of regret's six signals read those columns. search_symbols' fusion exit had the narrower half of the same defect: it passed the features but built their input with no identity key, so identity_hit was False there too regardless of what the identity channel found. Both are fixed together; shipping one honest and one false would have guaranteed a third release on the same column. A failing test found the part that mattered: compute_confidence sniffs the same identity key when no has_identity_match is passed, so feeding identity through the shared input would have moved the confidence of every fusion search (0.742 to 0.783 on one fixture). The ledger input is now separate from the confidence input, pinned behaviourally. New ledger_trust.identity_label_is_trustworthy, with a deliberately weaker discriminator than the semantic one: identity_hit has no value a pre-fix row alone can carry, so the rule matches a row that returned symbols while recording no top1_score. search_symbols_fusion's history is not separable and no heuristic is used for it. Also removed an unreachable identity guard on regret's vocabulary_gap, and stopped a pre-fix single-result row being clustered as thin_result on the strength of a default. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 2fd7db5 commit 38b28f9

9 files changed

Lines changed: 582 additions & 12 deletions

File tree

CHANGELOG.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,84 @@
22

33
All notable changes to jcodemunch-mcp are documented here.
44

5+
## [1.108.187] - 2026-07-26 - both fusion exits record the features they measured
6+
7+
### Fixed
8+
9+
- ⚠ **`get_ranked_context`'s fusion exit passed no `extract_ledger_features` payload
10+
at all**, so `top1_score`, `top2_score` and `identity_hit` were recorded as their
11+
defaults on every ranking-ledger row it ever wrote. Three of regret's six signals
12+
read those columns, and a default is indistinguishable from a measurement once it
13+
is in the ledger. Reported as an adjacent finding in 1.108.186 rather than folded
14+
in; this is the follow-through.
15+
16+
Identity comes from the identity channel's own `raw_scores` rather than being left
17+
to default. That exit BUILDS the identity channel, so unlike its sibling it knows
18+
per symbol whether identity matched, and `build_identity_channel` admits only
19+
symbols scoring above zero.
20+
21+
- ⚠ **`search_symbols`' fusion exit had the narrower half of the same defect.** It
22+
passed the features but built their input as `{"score": s}` with no `identity` key,
23+
so `identity_hit` was recorded False on every fusion row regardless of what the
24+
identity channel found. Both fusion producers are fixed together: shipping one
25+
honest and one false would have guaranteed a third release on the same column.
26+
27+
- ⚠ **A pre-fix single-result row was clustered as `thin_result` on the strength of a
28+
default.** That detector treats `top1_score is None` as thin, which reads a MISSING
29+
measurement as a weak one — correct where the score was genuinely absent, wrong for
30+
rows that recorded no features at all. Only those rows are skipped; every other
31+
producer's behaviour is unchanged, pinned by tests for the empty-result,
32+
weak-score and other-tool cases.
33+
34+
### Changed
35+
36+
- **The ledger input is now SEPARATE from the confidence input, and a failing test is
37+
what found this.** `compute_confidence` sniffs the same `identity` key when no
38+
`has_identity_match` is passed, scoring it 1.0 known-true / 0.7 unknown / 0.6
39+
known-false — so feeding identity through the shared input would have moved the
40+
confidence of every fusion search (measured: 0.742 -> 0.783 on one fixture). That
41+
is a ranking-adjacent change with its own justification, not a side effect of
42+
recording a column, so the confidence call keeps the input it has always had. The
43+
separation is pinned behaviourally: `attach_confidence` must receive rows without
44+
an identity key on the same call where the ledger features receive rows with one.
45+
46+
- **`ledger_trust.identity_label_is_trustworthy`, and its discriminator is weaker
47+
than the semantic one on purpose.** `identity_hit` has no value a pre-fix row alone
48+
can carry — pre-fix is always `0`, and `0` is also an honest post-fix answer, so
49+
matching on the column would discard good evidence forever. What IS exact: a row
50+
that returned symbols while recording no `top1_score` can only have come from the
51+
exit that passed no features. Post-fix a non-empty result always carries a fused
52+
score, and an empty result carries no `returned_ids` to match on.
53+
54+
- ⚠ **`search_symbols_fusion`'s history is NOT separable, and no heuristic is used.**
55+
It always recorded top scores and only omitted the `identity` key, so its pre-fix
56+
rows are indistinguishable from honest post-fix rows that had no identity match.
57+
There is no version or timestamp column to bound it by. The recency window is the
58+
only remedy and that is stated rather than papered over.
59+
60+
- ⚠ **An identity guard on regret's `vocabulary_gap` was UNREACHABLE and was
61+
removed** — found by a failing non-vacuity test, not by reading. That signal
62+
requires `semantic_used`, and a `get_ranked_context_fusion` row with
63+
`semantic_used=1` is already refused by the v1.108.186 rule, so the rows are
64+
suppressed either way. An unreachable guard reads like protection and is not.
65+
66+
- Disclosure follows the 1.108.186 pattern: `events_without_ledger_features` on
67+
`analyze_regret`, `no_ledger_features` per repo in `analyze_perf --ledger`, and
68+
`identity_hits` no longer counts a default as a miss. Both keys are absent — not
69+
zero — for a caller whose ledger holds no such row.
70+
71+
### Notes
72+
73+
- New `tests/test_v1_108_187.py` (24). Non-vacuity shown on both exits: reverting
74+
either producer fails four tests. Compatibility pinned — a pre-fix ledger stays
75+
readable and unrewritten.
76+
- No tool-count change, no `INDEX_VERSION` change, no schema change. Replay gate
77+
green (mrr/ndcg/recall 1.0), which matters here because the confidence separation
78+
is the thing that kept ranking output still.
79+
- Still open from the 1.108.186 findings: `token_tracker._ensure_loaded(None)` on the
80+
first savings write repins the perf db to `~/.code-index` even when a tool was
81+
handed a `storage_path`.
82+
583
## [1.108.186] - 2026-07-26 - the ledger stops claiming a channel that never ran
684

785
### Fixed

0 commit comments

Comments
 (0)