docs(6209): twelve more test files say which behaviour they pin
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / integration (push) Successful in 1m12s
CI & Build / Python tests (push) Successful in 1m53s
CI & Build / Build & push image (push) Successful in 12s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 14s
CI & Build / TypeScript typecheck (push) Successful in 52s
CI & Build / integration (push) Successful in 1m12s
CI & Build / Python tests (push) Successful in 1m53s
CI & Build / Build & push image (push) Successful in 12s
shape ledger, MCP projects/search/rulebooks tools, backup, chunking, plugin context, derived mirror, rule band, shape form gate, plugin version mint and note usage tests drop issue, milestone and rule numbers, dates and one-install figures from docstrings, comments and messages. Three shape-form-gate test names that told the discovery story now name the property: a registry module's helpers are not service functions, the divergence gate silences only a family contradiction, and callable helpers beside a callable canon still prompt. The rulebook tool-count comment that logged each milestone's additions is replaced by the reason it is a count. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+19
-23
@@ -1,4 +1,4 @@
|
||||
"""Tests for the usage signal (#2085) — was a surfaced record ever pulled?
|
||||
"""Tests for the usage signal — was a surfaced record ever pulled?
|
||||
|
||||
Covers the payload shaping and the two contracts that make this safe to leave in
|
||||
the hot path: telemetry never raises, and telemetry never blocks. Plus the thing
|
||||
@@ -90,8 +90,8 @@ async def test_usage_for_notes_splits_counts_by_event():
|
||||
from datetime import datetime, timezone
|
||||
|
||||
ts = datetime(2026, 7, 28, tzinfo=timezone.utc)
|
||||
# Rows are (note_id, event, count, last_at, ambient) since #2477 split the
|
||||
# readout. Ranked and ambient surfacings arrive as separate groups.
|
||||
# Rows are (note_id, event, count, last_at, ambient): ranked and ambient
|
||||
# surfacings arrive as separate groups.
|
||||
rows = [
|
||||
(3, "surfaced", 9, ts, False),
|
||||
(3, "surfaced", 40, ts, True),
|
||||
@@ -111,7 +111,7 @@ async def test_usage_for_notes_splits_counts_by_event():
|
||||
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).
|
||||
# make a record look popular — they sit in ambient_count.
|
||||
assert out[3]["surfaced_count"] == 9
|
||||
assert out[3]["ambient_count"] == 40
|
||||
assert out[3]["pull_count"] == 2
|
||||
@@ -120,7 +120,7 @@ async def test_usage_for_notes_splits_counts_by_event():
|
||||
|
||||
async def test_usage_for_notes_counts_what_happened_away_from_home():
|
||||
"""Surfaced or opened on a project other than the record's own is the
|
||||
evidence a record transferred (#3735). It is a SUBSET of the totals, read
|
||||
evidence a record transferred. It is a SUBSET of the totals, read
|
||||
from the second aggregate, and it must land on the right counter."""
|
||||
from datetime import datetime, timezone
|
||||
|
||||
@@ -167,7 +167,7 @@ async def test_no_ids_short_circuits_without_a_query():
|
||||
@pytest.mark.parametrize(
|
||||
"lookups, expected_source",
|
||||
[
|
||||
# A hit AT the exact file is the sync class (#2708); a hit from the
|
||||
# A hit AT the exact file is the sync class; a hit from the
|
||||
# directory query is the reuse-shaped place arm. Both are un-scored,
|
||||
# and both must leave a usage trace under their own name.
|
||||
([(1, "hit"), (2, "empty")], "write_path_sync"),
|
||||
@@ -177,9 +177,8 @@ async def test_no_ids_short_circuits_without_a_query():
|
||||
)
|
||||
async def test_unscored_location_arms_are_recorded(lookups, expected_source):
|
||||
"""The location arms carry no score, so they have no home in retrieval_logs
|
||||
— they surfaced snippets while leaving no trace anywhere. That was the
|
||||
blocker #2082 recorded against this task; this is the assertion that it's
|
||||
closed, per class."""
|
||||
— without a usage row they would surface snippets while leaving no trace
|
||||
anywhere. Asserted per class."""
|
||||
from scribe.services import plugin_context
|
||||
|
||||
here = [{"id": 42, "title": "helper", "user_id": 1, "note_type": "snippet"}]
|
||||
@@ -237,15 +236,13 @@ async def test_auto_inject_records_what_survived_the_margin_gate():
|
||||
|
||||
|
||||
def test_every_getter_that_can_be_surfaced_also_records_a_pull():
|
||||
"""Rule #33 contract check — and the one that would have caught #2245.
|
||||
"""A contract check between the two halves of the usage pair.
|
||||
|
||||
`surfaced` and `pulled` only mean something as a PAIR: the rate between them
|
||||
is what #1038 and #2085 gate on. That pair is only closed if the tool which
|
||||
OPENS a record reports it. `get_note` did, `get_snippet` did, `get_task` did
|
||||
NOT — and auto-inject ranks kind-blind over a corpus that is overwhelmingly
|
||||
tasks and issues, so the gap sat exactly where the volume is: every surfaced
|
||||
task counted as never-pulled, dragging measured pull-through toward zero for
|
||||
the menu's own dominant kind.
|
||||
is what pull-through is read from. That pair is only closed if every tool
|
||||
which OPENS a record reports it — and auto-inject ranks kind-blind over a
|
||||
corpus that is mostly tasks and issues, so one getter that does not report
|
||||
counts the menu's dominant kind as never-pulled.
|
||||
|
||||
Asserted by source inspection rather than by calling the tools, because the
|
||||
failure is a MISSING call — which no behavioural test of the tool's return
|
||||
@@ -272,12 +269,11 @@ def test_every_getter_that_can_be_surfaced_also_records_a_pull():
|
||||
|
||||
# --- persistence (integration) --------------------------------------------
|
||||
# Everything above mocks _schedule or the session — deliberately, for the hot
|
||||
# path. But that left the two functions that actually touch the database
|
||||
# (_insert_events and usage_for_notes' real SQL) running against real Postgres
|
||||
# nowhere, which is how the deployed instance reported zero for every counter
|
||||
# while surfacing demonstrably fired (#2663): all-green mocked units over a
|
||||
# dead real path, the #2109 shape. These two run in the CI integration lane
|
||||
# and split the chain so a failure names its half.
|
||||
# path. Without these, the two functions that actually touch the database
|
||||
# (_insert_events and usage_for_notes' real SQL) would run against real
|
||||
# Postgres nowhere — all-green mocked units over a dead real path. These two
|
||||
# run in the CI integration lane and split the chain so a failure names its
|
||||
# half.
|
||||
|
||||
|
||||
async def _purge(note_id: int) -> None:
|
||||
@@ -309,7 +305,7 @@ async def test_insert_and_readout_roundtrip_on_real_postgres(_dispose_engine):
|
||||
"source": "mcp_get_snippet"},
|
||||
])
|
||||
out = await usage_for_notes([nid])
|
||||
# write_path_place is a ranked choice; enter_project is ambient (#2477).
|
||||
# write_path_place is a ranked choice; enter_project is ambient.
|
||||
assert out[nid]["surfaced_count"] == 1
|
||||
assert out[nid]["ambient_count"] == 1
|
||||
assert out[nid]["pull_count"] == 1
|
||||
|
||||
Reference in New Issue
Block a user