fix(api): mutations answer ok; route helpers flush and leave the commit to the handler

Two rows of the canonical-patterns table had drifted, found while closing the roadmap audit:

- 63 mutation responses carried no `ok` — `{"unsubscribed": true}`, `{"status": "ok"}`,
  `{"added": 3, …}` and so on. Each now leads with `"ok": true` (additive: every field a client
  reads is still there).
- Twelve route helpers committed on their own. Six were just the end of their handler's work and now
  flush: the playlist item add/remove and Watch later get-or-create, the Plex series/season bulk
  mark, and the invite decision + account activation — which an approval used to land in separate
  transactions. The other six commit on purpose (a token durable before its link is mailed, a
  single-use token burned as its own unit, the Google callback's tail, a background registration
  with its own session, the staged search ingest around YouTube calls), each listed with its reason.

`tests/test_route_conventions.py` holds both rules in code; CLAUDE.md's two rows point at it.
This commit is contained in:
2026-09-19 18:21:06 +02:00
parent 30fbdc52b2
commit 99df44d7fb
26 changed files with 170 additions and 71 deletions
+9 -7
View File
@@ -424,6 +424,7 @@ def explore_channel(
except YouTubeError as exc:
raise youtube_refusal(exc)
return {
"ok": True,
"channel_id": channel_id,
"ingested": result["ingested"],
"next_page_token": result["next_page_token"],
@@ -505,6 +506,7 @@ def update_channel(
background.add_task(backfill_channel_now, channel_id, user.id)
return {
"ok": True,
"id": channel_id,
"priority": sub.priority,
"hidden": sub.hidden,
@@ -539,7 +541,7 @@ def reset_backfill(
db.commit()
with quota.attribute(user.id, quota.QuotaAction.VIDEOS_BACKFILL_RECENT):
run_recent_backfill(db, [channel], max_channels=1)
return {"id": channel_id, "reset": True}
return {"ok": True, "id": channel_id, "reset": True}
@router.post("/{channel_id}/subscribe")
@@ -618,7 +620,7 @@ def subscribe(
.values(via_explore=False)
)
db.commit()
return {"subscribed": channel_id}
return {"ok": True, "subscribed": channel_id}
@router.delete("/{channel_id}/subscription")
@@ -645,7 +647,7 @@ def unsubscribe(
raise youtube_refusal(exc)
db.delete(sub)
db.commit()
return {"unsubscribed": channel_id}
return {"ok": True, "unsubscribed": channel_id}
@router.get("/blocked/list")
@@ -686,7 +688,7 @@ def block_channel(
)
)
db.commit()
return {"blocked": channel_id}
return {"ok": True, "blocked": channel_id}
@router.delete("/{channel_id}/block")
@@ -701,7 +703,7 @@ def unblock_channel(
)
)
db.commit()
return {"unblocked": channel_id}
return {"ok": True, "unblocked": channel_id}
class AttachTagIn(BaseModel):
@@ -736,7 +738,7 @@ def attach_tag(
)
)
db.commit()
return {"channel_id": channel_id, "tag_id": body.tag_id}
return {"ok": True, "channel_id": channel_id, "tag_id": body.tag_id}
@router.delete("/{channel_id}/tags/{tag_id}")
@@ -756,4 +758,4 @@ def detach_tag(
if row is not None:
db.delete(row)
db.commit()
return {"channel_id": channel_id, "tag_id": tag_id}
return {"ok": True, "channel_id": channel_id, "tag_id": tag_id}