fix(ui): history_diff 500s when a note's file vanished, not 404

svc.get_note(note_id) sat outside the try in history_diff, so a note
with history but no current file (unlinked without hard_delete) raised
an uncaught NotFound and returned 500 instead of 404. Moved it inside
the same try/except as the history-revision lookup. Audited the other
note_id routes: they already wrap their get_note/get calls in
try/except MdmemError, so this was the only route with the gap.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0139vHnNpS2sLNELjrAHX5Cu
This commit is contained in:
MarkusandClaude Opus 5 committed 2026-09-12 18:33:47 +00:00
1 parent 59958f83ea
commit 4cb99c0347
2 files changed
+22 -1

No files matched your search

+4 -1
View File
@@ -322,9 +322,12 @@ def build_ui_app(svc: MemoryService) -> FastAPI: # noqa: C901 - one place, many
async def history_diff(request: Request, note_id: str, stamp: str) -> Response:
try:
old = svc.vault.read_history(note_id, stamp)
current = svc.get_note(note_id).to_text()
except Exception as exc:
# A note can have history but no current file (unlinked outside
# hard_delete); svc.get_note then raises NotFound after the path
# validation above has already passed, so both must 404 here.
return PlainTextResponse(str(exc), status_code=404)
current = svc.get_note(note_id).to_text()
return templates.TemplateResponse(
request,
"partial_diff.html",
+18
View File
@@ -124,6 +124,24 @@ async def test_note_page_shows_links_backlinks_and_history(ui):
assert "llama-swap" in back.text
async def test_history_diff_for_a_note_whose_file_vanished_returns_404(ui):
"""A note can have history but no current file if it was unlinked outside of
hard_delete (e.g. by hand, or a bug elsewhere). svc.get_note then raises
NotFound — the route must turn that into 404, not an uncaught 500 (§10)."""
client, svc = ui
res = await svc.write_note(title="Verschwunden", body="v1", type="note")
await svc.edit(res["id"], body="v2", expected_version=svc.get_note(res["id"]).file_hash)
stamps = svc.vault.history(res["id"])
assert stamps, "editing an existing note must snapshot the previous version"
path = svc.vault.find(res["id"])
assert path is not None
path.unlink()
r = await client.get(f"/ui/n/{res['id']}/history/{stamps[0]}")
assert r.status_code == 404
async def test_edit_conflict_shows_a_diff_and_keeps_both_versions(ui):
client, svc = ui
res = await svc.write_note(title="Konflikt", body="original", type="note")