feat(6249): the write-path hint asks whether a new definition copies a close snippet
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 55s
CI & Build / integration (push) Successful in 1m2s
CI & Build / Python tests (push) Successful in 1m56s
CI & Build / Build & push image (push) Successful in 22s
CI & Build / Python lint (push) Successful in 2s
CI & Build / Plugin hooks (push) Successful in 12s
CI & Build / TypeScript typecheck (push) Successful in 55s
CI & Build / integration (push) Successful in 1m2s
CI & Build / Python tests (push) Successful in 1m56s
CI & Build / Build & push image (push) Successful in 22s
The derive check matches by name, so a renamed copy of a recorded snippet passed it and showed only as "similar" prior art. When a write introduces a definition the file does not hold (shape_ledger.new_shapes_at) and an unseen snippet on the menu clears the write-path floor by WRITEPATH_COPY_MARGIN (0.80 at the default floor), the hint now says to reuse it or extract the shared shape before another copy. Names the derive check or the stamping feed already spoke for are left to them. Covers recorded snippets only: the ledger keeps no bodies to compare an unrecorded sibling against. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1580,6 +1580,60 @@ async def test_the_write_time_derive_check_names_a_family_or_a_canon_in_band():
|
||||
assert out["context"] == "" and out["derive"] == []
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_a_new_definition_close_to_a_snippet_is_asked_whether_it_is_a_copy():
|
||||
"""The derive check matches by name, so a renamed copy of a recorded
|
||||
snippet passes it. A new definition whose code resembles an unseen
|
||||
snippet past the copy bar gets the extraction prompt; a shape the file
|
||||
already holds, a weaker hit, a seen hit, or a name the derive check
|
||||
already named does not."""
|
||||
from grimoire.services import plugin_context as pc
|
||||
note = fake_note(id=31, title="debounce — rate-limit a callback", user_id=1,
|
||||
note_type="snippet")
|
||||
|
||||
async def run(score, fresh, *, derive=(), exclude=None):
|
||||
new_at = AsyncMock(return_value=fresh)
|
||||
with patch.multiple(
|
||||
pc, get_writepath_config=AsyncMock(return_value=_cfg()),
|
||||
semantic_search_notes=AsyncMock(return_value=[(score, note)]),
|
||||
record_retrieval=MagicMock(), owner_names_for=AsyncMock(return_value={}),
|
||||
), patch.object(pc.snippets_svc, "list_snippets", AsyncMock(return_value=([], 0))), \
|
||||
patch.object(pc.shape_ledger_svc, "recent_pulls", AsyncMock(return_value={})), \
|
||||
patch.object(pc.shape_ledger_svc, "write_time_divergence", AsyncMock(return_value=[])), \
|
||||
patch.object(pc.shape_ledger_svc, "write_time_derive",
|
||||
AsyncMock(return_value=list(derive))), \
|
||||
patch.object(pc.shape_ledger_svc, "new_shapes_at", new_at):
|
||||
out = await pc.build_write_path_hint(
|
||||
1, "src/x.py", code=REAL_CODE, project_id=24,
|
||||
stamp_shapes=[("sym", "throttle_calls")], exclude_ids=exclude,
|
||||
)
|
||||
return out["context"], new_at
|
||||
|
||||
bar = pc.WRITEPATH_DEFAULT_THRESHOLD + pc.WRITEPATH_COPY_MARGIN
|
||||
ctx, new_at = await run(bar + 0.04, [("sym", "throttle_calls")])
|
||||
new_at.assert_awaited_once_with(24, "src/x.py", [("sym", "throttle_calls")])
|
||||
assert "> `throttle_calls` is new in this file and this code resembles snippet #31 " \
|
||||
"`debounce`" in ctx
|
||||
assert f"(similar {bar + 0.04:.2f}). If it copies that shape, reuse #31" in ctx
|
||||
|
||||
# The file already holds the shape: an edit inside it, not a copy.
|
||||
ctx, _ = await run(bar + 0.04, [])
|
||||
assert "is new in this file" not in ctx
|
||||
# On the menu, but under the copy bar: no ledger read at all.
|
||||
ctx, new_at = await run(bar - 0.04, [("sym", "throttle_calls")])
|
||||
assert "is new in this file" not in ctx and "similar" in ctx
|
||||
new_at.assert_not_awaited()
|
||||
# Shown already this session: the line was said with its first showing.
|
||||
ctx, _ = await run(bar + 0.04, [("sym", "throttle_calls")], exclude=[31])
|
||||
assert "is new in this file" not in ctx
|
||||
# The derive check named the shape: its line is the stronger claim.
|
||||
family = {"symbol": "throttle_calls", "kind": "sym", "key": "dup:1",
|
||||
"family": {"group": "dup:1", "label": "throttle_calls", "identical": True,
|
||||
"files": ["a/y.py"], "file_count": 1, "size": 2}}
|
||||
ctx, _ = await run(bar + 0.04, [("sym", "throttle_calls")], derive=[family])
|
||||
assert "is new in this file" not in ctx
|
||||
|
||||
|
||||
def test_the_hook_keeps_a_derive_channel_and_sends_it_back(tmp_path):
|
||||
"""Derive keys the server returns land in the session's own
|
||||
`.derive.ids` file and go back as `exclude_derive` on the next write —
|
||||
|
||||
Reference in New Issue
Block a user