104c1d6f378eca8e5b0e4c384b114b30058b5c6b
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
def144df06 |
fix(tests): a Result's .all() is sync, and the module has a fourth tool (#4104)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / integration (push) Successful in 42s
CI & Build / TypeScript typecheck (push) Successful in 56s
CI & Build / Build & push image (push) Canceled after 0s
CI & Build / Python tests (push) Canceled after 1m37s
Two failures in the tests added with the step, both mine. `make_mock_session` is an AsyncMock and every child of an AsyncMock is one too, so leaving `.all` as it came handed `migrate_floor` a coroutine where it reads a list — the same trap the helper's own docstring already flags for `add`. And the registration test enumerated three tools by name, which is exactly what it is for: `migrate_retrieval_floor` made it four. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy |
||
|
|
381c90ca7e |
feat(retrieval): the wide net becomes a pull — fifty candidates, no bar (#4103)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / integration (push) Successful in 54s
CI & Build / Python tests (push) Failing after 1m8s
CI & Build / Build & push image (push) Skipped
Milestone 416 step 5. The operator's compromise — "if you're worried about excluding potentially important data let limit it to 50 entries" — moved to the surface where it is safe. Fifty in the push would be milestone 394 with extra steps; fifty in a pull crowds nothing out. `what_might_apply(query)` returns ranked rule candidates with NO threshold. The moment it serves is the one where the caller does not trust a bar to decide for them, so it does not have one — every row carries its score and the reader judges. WHY IT IS NOT A BIGGER `limit` ON `search` `_search_rules` returns statement, why and how_to_apply in full, on the stated reasoning that a caller who went looking deserves the whole record. That is the DEEP pull and should stay that way. This is the SHALLOW one — many candidates, each just enough to decide whether to open it. Opposite trade-offs, so it is a second tool. THE PREMISE THE STEP GOT WRONG The task said fifty "costs nothing". `_rule_hint_line` had already measured otherwise: ~143 tokens per line once the trigger is rendered, and #3855 tripled trigger lengths across the corpus. Fifty is ~7,000 tokens — cheap next to an arm firing before every Bash call, but not free, and a tool promising a free wide net gets reached for casually and then regretted. So it reuses the graduated shape #3851 measured for the push: the top few carry their trigger whole, the rest carry a cut of it. TRUNCATED, never dropped — the trigger is what lets a reader judge without opening, and a teaser without one is just an id. The cut borrows `_goal_line`'s technique including the fallback that matters (#4036): `textwrap.shorten` returns a bare "…" for one unbroken word. TELEMETRY Logged under its own pull source, asserted absent from both the tunable push registry and AMBIENT_SOURCES. That guard is load-bearing right now: the push arms' near-miss distributions are the evidence #4121 argues from, and a pull folded into them would move those numbers. INSTRUCTION SURFACES The using-scribe reflex and the MCP instructions both pointed at `search(content_type="rule")` for the consequential moment — the deep tool, at the moment you want breadth. They now point here, and keep `search` for reading a rule you already suspect. Written as a practice rather than a prohibition (rule 165). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy |
||
|
|
ca49a46c23 |
feat(retrieval): the model moves its own floors, and says why (#4102)
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 43s
CI & Build / TypeScript typecheck (push) Successful in 56s
CI & Build / Python tests (push) Failing after 1m5s
CI & Build / Build & push image (push) Skipped
Milestone 416 step 4's write half. `retrieval_surfaces.py` made the six
push arms describe their `{floor, budget}` the same way; this adds the
three MCP tools that let the model READ that and change it, and the
backup sections that carry the reasons.
The operator's decision, which this implements:
"the floor should be chosen and adjusted by the model using it… the
user should be able to touch it but the model should be the thing
handling it 9 times out of 10."
WHY A REASON IS REQUIRED, AND WHY THE TOOL ARGUES AGAINST PERCENTILES
The milestone originally listed self-tuning as a non-goal on one
measured case, and that case is now the tool's docstring rather than a
prohibition: `report_preference` logged 69 consecutive declines with
the refused record 0.0006 under the bar, and every percentile said
"lower it". The refused record was rule 77 "Extract intent from loose
phrasing" matched against a query about report layout — a false
positive. Lowering would have attached that rule to every completion
report ever written.
What separated the statistic from the correct action was OPENING the
record. So `tune_retrieval` refuses a blank or perfunctory reason,
tells the caller to read `retrieval_telemetry(near_miss_samples=5)`
and the record ids it names, and carries that 69-decline example — an
abstract warning loses to a number. The non-goal that survives is
*statistical* auto-tuning; nothing here reads a percentile and picks a
value.
BACKUP (v16), which is what CI caught
`retrieval_tuning_events` was neither backed up nor excluded, and
#2293's guard said so. It is backed up: `settings` already carried the
numbers, so dropping this would restore an install with six moved
dials and no argument for any of them — precisely the state the table
exists to prevent, and worse now that the model is the one moving
them. One `_retrieval_tuning_event_rows` builder called from both
exporters (snippet #2851); `user_id` travels because a restore has to
remap it, which is why the row builder is not the model's `to_dict()`.
`surface` is a registry name rather than a foreign key, so the history
survives a restore into an install whose ids all differ.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
|