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 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:
2026-08-30 13:17:52 -04:00
co-authored by Claude Opus 5
parent efabba58dd
commit 7985f8c7d7
8 changed files with 89 additions and 13 deletions
+6 -1
View File
@@ -604,7 +604,12 @@ async def rule_history(rule_id: int, version_id: int = 0) -> dict:
versions = await rulebooks_svc.list_rule_versions(rule_id, uid)
if versions is None:
raise ValueError(f"rule {rule_id} not found")
rule = await rulebooks_svc.get_rule(rule_id, uid)
# Fail-open, like the deletes: a missing title must not turn a readable
# history into an error.
try:
rule = await rulebooks_svc.get_rule(rule_id, uid)
except Exception:
rule = None
return {
"rule_id": rule_id,
"title": rule.title if rule else "",