feat(telemetry): ambient surfacings count, apart — enter_project and the skill sync emit
CI & Build / Python lint (push) Successful in 5s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 16s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Successful in 47s
CI & Build / Build & push image (push) Successful in 25s
CI & Build / Python lint (push) Successful in 5s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 16s
CI & Build / TypeScript typecheck (push) Successful in 32s
CI & Build / Python tests (push) Successful in 47s
CI & Build / Build & push image (push) Successful in 25s
#2477, option (a) as decided, with the readout changed in the same commit. ## The two silent surfaces enter_project returns open tasks + recent notes on every project entry — probably the largest surfacing by volume — and emitted nothing, so the pulls it caused floated unattributed and the surfaced:pulled ratio ran against a denominator missing its biggest contributor. Now source "enter_project". build_process_manifest installs every reachable Process as an auto-surfacing skill on the operator's machine — its own docstring calls it the most consequential passive surface Scribe has — and emitted nothing, so a Process matched on every relevant turn and never opened was indistinguishable from one never installed. Now source "process_skill_sync": the honest event is "installed", which is a surfacing in effect since the description sits in front of the model each session. ## The readout, same commit — the condition option (a) carried Both surfaces are AMBIENT: top-N-by-recency and install-everything are not ranked choices. Pooling them into surfaced_count would make a note's number dominated by "recently updated in a project you opened", and dead-weight detection would read that as popularity — the wrong number read confidently, which is the corrupts-data tier the survey ranked above everything else. So usage_for_notes splits: surfaced_count stays RANKED-ONLY (every existing consumer's reading — "surfaced often, never pulled → dead weight" — keeps meaning what it meant), and ambient_count is new. Classified in SQL via a CASE on AMBIENT_SOURCES so the group count stays three rows per note, not one per distinct source. Pulls stay pooled: "did anyone ever open this?" does not depend on how it was found. #1038 and #2085 read agent pulls and ranked surfacings; both are unaffected by ambient volume, which is the point. Refs #2477
This commit is contained in:
@@ -113,7 +113,13 @@ async def test_usage_for_notes_splits_counts_by_event():
|
||||
from datetime import datetime, timezone
|
||||
|
||||
ts = datetime(2026, 7, 28, tzinfo=timezone.utc)
|
||||
rows = [(3, "surfaced", 9, ts), (3, "pulled", 2, ts)]
|
||||
# Rows are (note_id, event, count, last_at, ambient) since #2477 split the
|
||||
# readout. Ranked and ambient surfacings arrive as separate groups.
|
||||
rows = [
|
||||
(3, "surfaced", 9, ts, False),
|
||||
(3, "surfaced", 40, ts, True),
|
||||
(3, "pulled", 2, ts, False),
|
||||
]
|
||||
session = MagicMock()
|
||||
session.execute = AsyncMock(
|
||||
return_value=MagicMock(all=MagicMock(return_value=rows))
|
||||
@@ -123,7 +129,11 @@ async def test_usage_for_notes_splits_counts_by_event():
|
||||
ctx.__aexit__ = AsyncMock(return_value=False)
|
||||
with patch.object(note_usage, "async_session", return_value=ctx):
|
||||
out = await usage_for_notes([3])
|
||||
# The dead-weight reading ("surfaced often, never pulled") is only valid
|
||||
# over surfacings that were CHOICES. 40 enter_project appearances must not
|
||||
# make a record look popular — they sit in ambient_count (#2477).
|
||||
assert out[3]["surfaced_count"] == 9
|
||||
assert out[3]["ambient_count"] == 40
|
||||
assert out[3]["pull_count"] == 2
|
||||
assert out[3]["last_pulled_at"] == ts.isoformat()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user