Closes milestone 416 at 9/9. CI 6999 green on 104c1d6.
Why this merge
The route only reaches a session when the plugin ships from main. Two of step 9's conditions are behavioural — a session reading the refused records unasked, and tune_retrieval-first reading as the wrong move — and neither is observable until this lands.
What it is
The tuning loop shipped in steps 4 and 6 and logged zero events in its lifetime. tune_retrieval, retrieval_telemetry and retrieval_surfaces appeared on no instruction surface at all, so the decision that "the model should be the thing handling it 9 times out of 10" could not begin to happen.
What was missing was not an auditor but a route. using-scribe now carries it, ordered:
Read the refused records — retrieval_telemetry(near_miss_samples=5) names them by id.
Fix the trigger — update_rule(when_to_apply=...), then re-check where it ranks.
Only then the dial — tune_retrieval, with what was read in the required reason.
The order is the content. A rule's when_to_apply IS the text its score is computed against, so a miss is evidence about that text first. Rewording one trigger changes one rule's reach; moving a floor changes what every record on the surface does, and cannot tell a badly-worded trigger from a genuinely distant one.
The create path also gets a precondition: before writing a new record, what_might_apply asks what already covers that moment — fifty candidates, no bar, because a bar is what lets the existing record hide.
_INSTRUCTIONS gets one index line, not the route: 1,986 of 2,000 characters (#2562 cuts the rest mid-word).
Evidence the ordering is right
Rule 1 dev is home scored 0.6515 and ranked 5th for the moment it governed, behind three rules that restrained the same act. Every percentile said "lower the floor"; at 0.60 the arm delivered those three restraints and still not rule 1. Rewriting the trigger to lead with the symptom put it 1st at 0.7130.
The route has since been run twice more on live data, both times fixing a record rather than a dial:
Rule 168 was firing on sed, grep, cat and git push — 0.7084 on a plain repo grep, against 0.7159 on a genuine infrastructure query, i.e. 0.0075 of separation. Trigger rewritten; the false positives now score 0.6772 and 0.6475 (below the 0.68 floor, no longer firing) and the true positive rose to 0.7644. Separation 0.0075 → 0.0872.
report_preference was fixed earlier by writing the missing record, not by lowering its bar.
Tests
tests/test_retrieval_miss_route.py, six tests. The load-bearing one is positional — a reordering preserves every substring a presence check would look for, and in the wrong order the route stops being a route and becomes a menu.
Plugin version 2026.09.18.0436; the executing cache refreshes on the manifest bump (#2209).
Closes milestone 416 at 9/9. CI 6999 green on `104c1d6`.
## Why this merge
The route only reaches a session when the plugin ships from `main`. Two of step 9's conditions are behavioural — a session reading the refused records unasked, and `tune_retrieval`-first reading as the wrong move — and neither is observable until this lands.
## What it is
The tuning loop shipped in steps 4 and 6 and logged **zero events** in its lifetime. `tune_retrieval`, `retrieval_telemetry` and `retrieval_surfaces` appeared on no instruction surface at all, so the decision that *"the model should be the thing handling it 9 times out of 10"* could not begin to happen.
What was missing was not an auditor but a route. `using-scribe` now carries it, ordered:
1. Read the refused records — `retrieval_telemetry(near_miss_samples=5)` names them by id.
2. Fix the trigger — `update_rule(when_to_apply=...)`, then re-check where it ranks.
3. Only then the dial — `tune_retrieval`, with what was read in the required `reason`.
**The order is the content.** A rule's `when_to_apply` IS the text its score is computed against, so a miss is evidence about that text first. Rewording one trigger changes one rule's reach; moving a floor changes what every record on the surface does, and cannot tell a badly-worded trigger from a genuinely distant one.
The create path also gets a precondition: before writing a new record, `what_might_apply` asks what already covers that moment — fifty candidates, no bar, because a bar is what lets the existing record hide.
`_INSTRUCTIONS` gets one index line, not the route: 1,986 of 2,000 characters (#2562 cuts the rest mid-word).
## Evidence the ordering is right
Rule 1 `dev is home` scored 0.6515 and ranked **5th** for the moment it governed, behind three rules that *restrained* the same act. Every percentile said "lower the floor"; at 0.60 the arm delivered those three restraints and still not rule 1. Rewriting the trigger to lead with the symptom put it **1st at 0.7130**.
The route has since been run twice more on live data, both times fixing a record rather than a dial:
- **Rule 168** was firing on `sed`, `grep`, `cat` and `git push` — 0.7084 on a plain repo `grep`, against 0.7159 on a genuine infrastructure query, i.e. 0.0075 of separation. Trigger rewritten; the false positives now score 0.6772 and 0.6475 (below the 0.68 floor, no longer firing) and the true positive rose to 0.7644. **Separation 0.0075 → 0.0872.**
- **`report_preference`** was fixed earlier by writing the missing record, not by lowering its bar.
## Tests
`tests/test_retrieval_miss_route.py`, six tests. The load-bearing one is **positional** — a reordering preserves every substring a presence check would look for, and in the wrong order the route stops being a route and becomes a menu.
Plugin version `2026.09.18.0436`; the executing cache refreshes on the manifest bump (#2209).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
The tuning loop shipped in steps 4 and 6 and logged zero events in its
lifetime. `tune_retrieval`, `retrieval_telemetry` and `retrieval_surfaces`
appeared on no instruction surface at all — not the skills, not the hooks,
not the MCP instructions — so the decision that "the model should be the
thing handling it 9 times out of 10" could not begin to happen.
What was missing was not an auditor but a route. `using-scribe` now carries
it, ordered: read the refused records, fix the trigger, and only then
consider the dial. The order is the content. A rule's `when_to_apply` IS
the text its score is computed against, so a miss is evidence about that
text first; rewording one trigger changes one rule's reach, while moving a
floor changes what every record on the surface does and cannot tell a
badly-worded trigger from a genuinely distant one.
Measured, and the reason the order is asserted rather than suggested: rule
1 scored 0.6515 and ranked 5th for the moment it governed, behind three
rules that restrained the same act. Every percentile said "lower the
floor"; at 0.60 the arm delivered those three restraints and still not rule
1. Rewriting the trigger to lead with the symptom put it 1st at 0.7130.
Also: the create path gets a precondition. A new record is itself a
retrieval-affecting act, so before writing one, what_might_apply asks what
already covers that moment — fifty candidates and no bar, because a bar is
what lets the existing record hide.
`_INSTRUCTIONS` gets one index line, not the route: 1,986 of 2,000
characters, since Claude Code cuts the rest mid-word (#2562).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes milestone 416 at 9/9. CI 6999 green on
104c1d6.Why this merge
The route only reaches a session when the plugin ships from
main. Two of step 9's conditions are behavioural — a session reading the refused records unasked, andtune_retrieval-first reading as the wrong move — and neither is observable until this lands.What it is
The tuning loop shipped in steps 4 and 6 and logged zero events in its lifetime.
tune_retrieval,retrieval_telemetryandretrieval_surfacesappeared on no instruction surface at all, so the decision that "the model should be the thing handling it 9 times out of 10" could not begin to happen.What was missing was not an auditor but a route.
using-scribenow carries it, ordered:retrieval_telemetry(near_miss_samples=5)names them by id.update_rule(when_to_apply=...), then re-check where it ranks.tune_retrieval, with what was read in the requiredreason.The order is the content. A rule's
when_to_applyIS the text its score is computed against, so a miss is evidence about that text first. Rewording one trigger changes one rule's reach; moving a floor changes what every record on the surface does, and cannot tell a badly-worded trigger from a genuinely distant one.The create path also gets a precondition: before writing a new record,
what_might_applyasks what already covers that moment — fifty candidates, no bar, because a bar is what lets the existing record hide._INSTRUCTIONSgets one index line, not the route: 1,986 of 2,000 characters (#2562 cuts the rest mid-word).Evidence the ordering is right
Rule 1
dev is homescored 0.6515 and ranked 5th for the moment it governed, behind three rules that restrained the same act. Every percentile said "lower the floor"; at 0.60 the arm delivered those three restraints and still not rule 1. Rewriting the trigger to lead with the symptom put it 1st at 0.7130.The route has since been run twice more on live data, both times fixing a record rather than a dial:
sed,grep,catandgit push— 0.7084 on a plain repogrep, against 0.7159 on a genuine infrastructure query, i.e. 0.0075 of separation. Trigger rewritten; the false positives now score 0.6772 and 0.6475 (below the 0.68 floor, no longer firing) and the true positive rose to 0.7644. Separation 0.0075 → 0.0872.report_preferencewas fixed earlier by writing the missing record, not by lowering its bar.Tests
tests/test_retrieval_miss_route.py, six tests. The load-bearing one is positional — a reordering preserves every substring a presence check would look for, and in the wrong order the route stops being a route and becomes a menu.Plugin version
2026.09.18.0436; the executing cache refreshes on the manifest bump (#2209).🤖 Generated with Claude Code
https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy