align(4909d): every rule arm that annotates reads one bar, kb_rule_threshold at 0.70
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 13s
CI & Build / TypeScript typecheck (push) Successful in 55s
CI & Build / integration (push) Successful in 1m7s
CI & Build / Python tests (push) Failing after 1m30s
CI & Build / Build & push image (push) Skipped

prompt_rule, pre_tool_rule and write_path_rule now share one settings key,
RULE_FLOOR_KEY = "kb_rule_threshold", default 0.70. The reply backstop keeps
its own 0.80, because there the floor is a stop bar. Moving the shared floor
through tune_retrieval or the Settings form records a tuning event on every
surface that reads it (set_dial, via retrieval_surfaces.sharing_floor), and
the result names the surfaces it carried as `moved_with`. Settings shows one
"Standing-rule confidence threshold" control where it showed three.

Operator ruling (2026-10-05): one shared bar for the rule arms, "especially
since we're only taking the first x number of them" -- the budget limits
what is shown; the bar only decides what is worth ranking. Kept a dial.

Why 0.70, from records read rather than percentiles:
- write_path_rule near-misses at 0.7199-0.72 were all false positives
  (rule 149 against a Lidarr comment, 157 against a retention Svelte file,
  121 against an Archives restore, 164 against a config test, 131 against a
  Go package), so the old 0.72 was not hiding real hits -- but the band does
  noise control on this arm, so dropping 0.02 costs little.
- prompt_rule: the operator set 0.70 by hand on 2026-09-18, after a 0.60
  experiment admitted junk and was reverted. 0.70 is the number with a human
  decision behind it.
- pre_tool_rule lines near 0.68 this session were mostly noise; rising to
  0.70 trims them, and the band still narrows what clears.

Retired keys: kb_promptrule_threshold, kb_toolrule_threshold and
kb_rulehint_threshold are no longer read. Rows an install stored under them
stay in the settings table, inert. On this instance the effective bars move
pre_tool_rule 0.68 -> 0.70, write_path_rule 0.72 -> 0.70, prompt_rule stays
0.70; record_release_defaults writes those per-surface release rows on boot,
so the telemetry shift has an event to explain it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-22 18:32:09 -04:00
co-authored by Claude Opus 5.5
parent f77d18cb63
commit c8ede427ca
10 changed files with 175 additions and 211 deletions
+33 -2
View File
@@ -86,9 +86,9 @@ async def test_a_good_change_writes_the_setting_and_the_event():
setter.assert_awaited_once()
_uid, key, stored = setter.await_args.args
assert key == "kb_promptrule_threshold" and stored == "0.66"
assert key == "kb_rule_threshold" and stored == "0.66"
event = session.add.call_args.args[0]
event = session.add.call_args_list[0].args[0]
assert event.surface == "prompt_rule" and event.dial == "floor"
# The before-value is what makes the history answerable.
assert event.old_value == 0.72 and event.new_value == 0.66
@@ -97,6 +97,37 @@ async def test_a_good_change_writes_the_setting_and_the_event():
assert out["clamped"] is False
@pytest.mark.asyncio
async def test_a_shared_floor_records_the_move_on_every_surface_that_reads_it():
"""One key, one write, an event per surface. A rule arm whose bar moved
with no event of its own would show a telemetry shift nothing explains."""
session, ctx = _patches(floor=0.70)
with ctx[0], patch.object(rt, "set_setting", AsyncMock()) as setter, \
ctx[2], ctx[3]:
out = await rt.set_dial(
1, "pre_tool_rule", "floor", 0.74,
reason="read the 10 highest declines: every one was a real miss",
)
setter.assert_awaited_once()
recorded = {c.args[0].surface for c in session.add.call_args_list}
assert recorded == {"pre_tool_rule", "prompt_rule", "write_path_rule"}
assert sorted(out["moved_with"]) == ["prompt_rule", "write_path_rule"]
@pytest.mark.asyncio
async def test_a_budget_moves_only_its_own_surface():
session, ctx = _patches(budget=3)
with ctx[0], patch.object(rt, "set_setting", AsyncMock()), ctx[2], ctx[3]:
out = await rt.set_dial(
1, "prompt_rule", "budget", 4,
reason="on-point hits sit at ranks 4 and 5 as often as rank 1",
)
assert [c.args[0].surface for c in session.add.call_args_list] == ["prompt_rule"]
assert out["moved_with"] == []
@pytest.mark.asyncio
@pytest.mark.parametrize("dial, sent, applied", [
("floor", 1.4, 1.0),