feat(prior-art): edit-time record-sync nudge — the sync class (#2708)
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / TypeScript typecheck (push) Successful in 24s
CI & Build / integration (push) Successful in 26s
CI & Build / Python tests (push) Successful in 56s
CI & Build / Build & push image (push) Successful in 43s
CI & Build / Python lint (push) Successful in 3s
CI & Build / Plugin hooks (push) Successful in 11s
CI & Build / TypeScript typecheck (push) Successful in 24s
CI & Build / integration (push) Successful in 26s
CI & Build / Python tests (push) Successful in 56s
CI & Build / Build & push image (push) Successful in 43s
A snippet recorded AT the exact file being edited is not a reuse suggestion — it IS the record of the file being changed. The write-path hint now renders those as their own SYNC class: 'snippet #N records this file — updating the record is part of the edit (update_snippet / verify_snippet)'. Nearby and semantic hits stay the reuse menu. The two classes dedup on separate per-session channels (exclude_ids vs exclude_sync_ids, .ids vs .sync.ids in the hook), so a reuse hint shown early in a session can no longer silence the record-sync nudge when the recorded file itself is edited later. Sync surfacing is measured under its own note_usage source (write_path_sync) — its pull-through rate is the scoreboard for whether edit-time sync actually happens, per decision #2707 (no forge connection; records stay current in the session that has the context). Plugin 0.1.31. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -156,16 +156,25 @@ async def test_no_ids_short_circuits_without_a_query():
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"marker, expected_source",
|
||||
[("here", "write_path_place"), ("nearby", "write_path_place")],
|
||||
"lookups, expected_source",
|
||||
[
|
||||
# A hit AT the exact file is the sync class (#2708); 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"),
|
||||
([(1, "empty"), (2, "hit")], "write_path_place"),
|
||||
],
|
||||
ids=["at-the-file", "nearby"],
|
||||
)
|
||||
async def test_write_path_place_arm_is_recorded(marker, expected_source):
|
||||
"""The place arm carries no score, so it has no home in retrieval_logs — it
|
||||
surfaced snippets while leaving no trace anywhere. That was the blocker
|
||||
#2082 recorded against this task; this is the assertion that it's closed."""
|
||||
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."""
|
||||
from scribe.services import plugin_context
|
||||
|
||||
here = [{"id": 42, "title": "helper", "user_id": 1, "note_type": "snippet"}]
|
||||
responses = [(here, 1) if kind == "hit" else ([], 0) for _n, kind in lookups]
|
||||
with (
|
||||
patch.object(
|
||||
plugin_context,
|
||||
@@ -175,7 +184,7 @@ async def test_write_path_place_arm_is_recorded(marker, expected_source):
|
||||
patch.object(
|
||||
plugin_context.snippets_svc,
|
||||
"list_snippets",
|
||||
AsyncMock(side_effect=[(here, 1), ([], 0)]),
|
||||
AsyncMock(side_effect=responses),
|
||||
),
|
||||
patch.object(
|
||||
plugin_context, "semantic_search_notes", AsyncMock(return_value=[])
|
||||
|
||||
Reference in New Issue
Block a user