fix(6247): a getter is seen by its pulls, so the silent list stops naming every pull door
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 53s
CI & Build / integration (push) Successful in 1m5s
CI & Build / Python tests (push) Successful in 1m56s
CI & Build / Build & push image (push) Successful in 22s

usage and rule_usage gain pulled_by_source, read from the per-source rows
the readout already had, and _silent_surfaces counts those doors as having
emitted. The rules-listing points were seen as of the previous commit,
through rule_usage.by_source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-22 19:28:29 -04:00
co-authored by Claude Opus 5.5
parent d05d4f3632
commit 1fa9245bbf
3 changed files with 59 additions and 0 deletions
@@ -803,6 +803,9 @@ def _silent_surfaces(sources: dict, usage: dict, rule_usage: dict,
return []
seen = set(sources) | set((usage.get("by_source") or {}))
seen |= set((rule_usage.get("by_source") or {}))
# A getter shows nothing, so it is seen only by its pulls.
seen |= set((usage.get("pulled_by_source") or {}))
seen |= set((rule_usage.get("pulled_by_source") or {}))
seen |= set(((system_usage or {}).get("by_source") or {}))
return [
{"source": s, "kind": POINTS[s].kind, "what": POINTS[s].what}
@@ -1486,6 +1489,9 @@ async def retrieval_summary(
"distinct_notes_surfaced": int(distinct_surfaced or 0),
"distinct_notes_pulled": int(distinct_pulled or 0),
}
# Pulls per door. `by_source` is keyed by the surface that showed a record
# and leaves pulls out, so this is what says each getter is recording.
pulled_by_source: dict[str, int] = {}
for event, source, n in urows:
n = int(n)
if event == SURFACED:
@@ -1495,6 +1501,7 @@ async def retrieval_summary(
usage["surfaced"] += n
elif event == PULLED:
usage["pulled"] += n
pulled_by_source[source] = pulled_by_source.get(source, 0) + n
# The mcp_/rest_ split is load-bearing (see NoteUsageEvent's own
# comment). "Is
# this record dead weight?" is answered by ANY pull; "was that
@@ -1513,6 +1520,7 @@ async def retrieval_summary(
round(usage["pulled_by_agent"] / usage["surfaced"], 4)
if usage["surfaced"] else None
)
usage["pulled_by_source"] = pulled_by_source
# The same question, per surface — which is the one the top-level ratio
# cannot answer. A corpus average of 0.05 is compatible with one surface
@@ -1585,6 +1593,8 @@ async def retrieval_summary(
"applied": 0,
"departed": 0,
"distinct_rules_acted": int(distinct_rules_acted or 0),
# Pulls per door, as on the note block.
"pulled_by_source": {},
}
if rule_rows is None:
# The FLAG is added, the shape is kept — matching `by_source_failed`
@@ -1607,6 +1617,8 @@ async def retrieval_summary(
rule_usage["surfaced"] += n
elif event == RULE_PULLED:
rule_usage["pulled"] += n
pulled = rule_usage["pulled_by_source"]
pulled[source] = pulled.get(source, 0) + n
# Same split, and it carries MORE weight here than for notes.
# The arm's whole claim is "this rule may apply to what you are
# writing", and only an agent opening it says the claim landed.