feat(retrieval): a review pass judges whether injected lines related — menus_to_review, judge_menu and a judged readout (#4772)
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m1s
CI & Build / Python tests (push) Successful in 1m55s
CI & Build / Build & push image (push) Successful in 44s
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m1s
CI & Build / Python tests (push) Successful in 1m55s
CI & Build / Build & push image (push) Successful in 44s
An open rate cannot say whether a menu line related: every line carries its matched passage (#4364), so "not opened" covers unrelated, enough as shown, and already in context. #4772 "Injected notes are never judged". - retrieval_judgments (0115): a reviewer verdict per line of a logged call, on_point / adjacent / unrelated, with its reason, rank, budget side and whether the agent opened it within the hour. - menus_to_review re-runs a random sample of unjudged auto_inject calls with the arm's own parameters, past its budget, passage on every line. judge_menu records verdicts, re-deriving rank from a fresh re-run. - retrieval_telemetry gains a judged block (by rank, within/beyond budget, on_point_unopened). surfaced_never_pulled stops blaming titles. - missed-retrieval guidance names the review before a budget move. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,7 @@ from scribe.models.system_usage import SURFACED as SYSTEM_SURFACED
|
||||
from scribe.models.system_usage import SystemUsageEvent
|
||||
from scribe.services.rule_usage import is_ambient
|
||||
from scribe.models.retrieval_log import RetrievalLog
|
||||
from scribe.services.retrieval_review import judged_block
|
||||
from scribe.services.retrieval_registry import (
|
||||
POINTS, UNBIDDEN, get_point, is_registered, sources_expected_to_emit,
|
||||
)
|
||||
@@ -745,9 +746,11 @@ def _compute_warnings(sources: dict, usage: dict, rule_usage: dict,
|
||||
# ── Surfaced and never pulled, for each corpus ───────────────────────
|
||||
#
|
||||
# The one corpus-level check, and the only number here that judges the
|
||||
# RECORDS rather than the arms. A record shown repeatedly and never opened
|
||||
# is either badly titled or genuinely irrelevant, and both are actionable
|
||||
# in a way "pull-through is 0.15" is not.
|
||||
# RECORDS rather than the arms. It used to say a record shown repeatedly
|
||||
# and never opened is "badly titled or genuinely irrelevant" — true when a
|
||||
# line was a title, and not since it carries the passage (#4364): the
|
||||
# record may have done its job unopened. So it now points at the judged
|
||||
# sample rather than at a cause (#4772).
|
||||
#
|
||||
# Distinct records, not events: a note surfaced forty times and never
|
||||
# opened is one problem, not forty.
|
||||
@@ -764,9 +767,11 @@ def _compute_warnings(sources: dict, usage: dict, rule_usage: dict,
|
||||
out.append(_warn(
|
||||
"surfaced_never_pulled",
|
||||
f"{never} of {shown} distinct {label} were surfaced in this "
|
||||
f"window and never opened. Read the titles before the "
|
||||
f"threshold: a record nobody opens is usually one whose title "
|
||||
f"does not say when it matters.",
|
||||
f"window and never opened. That is not a verdict on them: a "
|
||||
f"line carries its matched passage, so an unopened record may "
|
||||
f"have been unrelated, enough as shown, or already in context. "
|
||||
f"Before acting on it — a title, a floor, a budget — judge a "
|
||||
f"sample with `menus_to_review` and read the `judged` block.",
|
||||
source=None, corpus=label,
|
||||
surfaced=int(shown), pulled=int(pulled or 0), never_pulled=never,
|
||||
))
|
||||
@@ -995,6 +1000,7 @@ async def retrieval_summary(
|
||||
"usage": {},
|
||||
"rule_usage": {},
|
||||
"system_usage": {},
|
||||
"judged": {},
|
||||
"read_failed": False,
|
||||
}
|
||||
|
||||
@@ -1554,6 +1560,18 @@ async def retrieval_summary(
|
||||
out["rule_usage"] = rule_usage
|
||||
out["system_usage"] = await _system_usage(user_id, since)
|
||||
|
||||
# ── Judged lines (#4772) ─────────────────────────────────────────────
|
||||
#
|
||||
# The relevance readout the usage blocks cannot be: a reviewer's verdict
|
||||
# on each line of a sample of logged menus, by rank. Its own guard, for
|
||||
# `_system_usage`'s reason — a failure flags itself rather than printing
|
||||
# an empty block, which reads as "nothing judged" (#2663).
|
||||
try:
|
||||
out["judged"] = await judged_block(user_id, since)
|
||||
except Exception:
|
||||
logger.warning("judged block read failed", exc_info=True)
|
||||
out["judged"] = {"judged_failed": True}
|
||||
|
||||
# ── What is wrong (#3431) ────────────────────────────────────────────
|
||||
#
|
||||
# Computed LAST, over the blocks above rather than over the database, so
|
||||
|
||||
Reference in New Issue
Block a user