fix(backend): make document replication atomic, honest, and safely worded

↗ view on GitHub · Amal · 2026-08-12 · feb2e55f

WHY THIS MATTERS
replicate_document inserted library rows with status "ready" BEFORE
uploading any bytes. A failed upload left user-visible broken documents
(rows with no version) in Library Files; a failed current_version_id update
was silently swallowed (Supabase builders return errors in-band - they do
not reject) while the tool still reported ok:true. The repo's own
persistGeneratedFile does it right: bytes first, rows last, so the worst
failure is an invisible orphaned blob, never a broken row the user can see.

WHAT IS UPLOAD-FIRST ORDERING?
When an operation spans storage and database, order the writes so each
partial-failure state is harmless: pre-generate the document UUIDs, upload
all bytes under those ids, then insert documents + versions, then link
current_version_id checking every in-band error. Copies whose linking fails
are rolled back (best-effort row delete) and reported in a new
failed_copies array; if every copy fails the result is ok:false.

ALSO IN THIS COMMIT (same pipeline, same files)
- Raw Postgres/S3 error text no longer reaches the model/user event stream:
  the three fail() sites now wrap errors with safeErrorMessage, matching
  the streaming path's convention (secrets/endpoints stay out of chat).
- Within-turn workflow reference handles use the full workflow id instead
  of id.slice(0,8) - every "builtin-*" id shared that prefix, so two system
  workflows' assets could silently rebind each other's doc handles.
- Dead DocStore.source_id field removed (written once, read nowhere).
- The prompt mandated replicate → edit_document for ALL templates, but
  edit_document only supports .docx; a PDF template boxed the model in with
  no permitted fallback. The instruction is now scoped to .docx copies,
  with explicit guidance for other types, and the per-file notices match
  the prompt's "will be edited or filled in" scope so purely-informational
  reference files no longer trigger spurious library copies.
- Tests now pin the contract: uploads are asserted to happen before any
  documents insert (call-order log), with the exact storage key and bytes,
  plus a failure path proving no "ready" row survives a failed upload.

Found by review of PR #309.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E4PXCdenNH5Mqhm5Sre9Zs
Repository open-legal-products/mike
Author Amal <mamalanand3@gmail.com>
Authored
Committed
Parents 5ed658b4
Stats 5 files changed , +230 , -88
Part of Refactor workflows into defaults, add-ons, and quick actions

Capture this commit into my fork

Download a Markdown prompt that tells Claude how to port this exact commit into your working tree. Run it via claude -p < capture-commit-feb2e55f.md from inside the repo you want the change in.

⬇ Download capture-commit-feb2e55f.md