fix(scribe): a delete must not depend on the lookup that names it (#3273)
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 29s
CI & Build / TypeScript typecheck (push) Successful in 38s
CI & Build / Python tests (push) Successful in 1m15s
CI & Build / Build & push image (push) Successful in 36s
CI & Build / Python lint (push) Successful in 4s
CI & Build / Plugin hooks (push) Successful in 8s
CI & Build / integration (push) Successful in 29s
CI & Build / TypeScript typecheck (push) Successful in 38s
CI & Build / Python tests (push) Successful in 1m15s
CI & Build / Build & push image (push) Successful in 36s
CI caught the naming work reaching for Postgres from the unit lane, and the connection error was the symptom of a real design fault rather than a test gap: reading the title BEFORE the delete put a live query on the delete path, so a lookup that failed would have stopped the delete happening. That is a decoration breaking its payload — the same mistake just fixed in rules_etag, made again two commits later. Every title lookup now fails open: delete_task, delete_note, delete_milestone, delete_snippet and rule_history lose the name, never the operation. The five unit tests mock the lookup rather than reaching for a database, and delete_note gains one asserting the delete still happens when the lookup raises — the behaviour, not just the absence of a crash. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -138,9 +138,18 @@ async def test_merge_snippets_read_only_target_says_why():
|
||||
@pytest.mark.asyncio
|
||||
async def test_delete_snippet_retires_or_raises():
|
||||
from scribe.mcp.tools.snippets import delete_snippet
|
||||
with patch("scribe.services.snippets.delete_snippet", AsyncMock(return_value=True)):
|
||||
assert await delete_snippet(1) == {"deleted": True, "id": 1}
|
||||
with patch("scribe.services.snippets.delete_snippet", AsyncMock(return_value=False)):
|
||||
|
||||
doomed = MagicMock()
|
||||
doomed.title = "debounce helper"
|
||||
# The confirmation names what went (#3273) — after the delete there is
|
||||
# nothing left to look the title up from.
|
||||
with patch("scribe.services.snippets.delete_snippet", AsyncMock(return_value=True)), \
|
||||
patch("scribe.services.snippets.get_snippet", AsyncMock(return_value=doomed)):
|
||||
assert await delete_snippet(1) == {
|
||||
"deleted": True, "id": 1, "title": "debounce helper",
|
||||
}
|
||||
with patch("scribe.services.snippets.delete_snippet", AsyncMock(return_value=False)), \
|
||||
patch("scribe.services.snippets.get_snippet", AsyncMock(return_value=None)):
|
||||
with pytest.raises(ValueError):
|
||||
await delete_snippet(404)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user