Files
pad/internal
xarmian 60dd3e1a37 feat(store): add attachment resolution planner for cross-workspace copy (TASK-2354)
Implements PLAN-2357 DR-11 / DR-11a. PlanAttachmentCopy takes the copied
content plus the FINAL destination fields and returns the old->new
attachment UUID map, the rows to create (originals followed by their
variants, parent_id remapped), the byte total, and the unresolvable-ref
list. It writes nothing, takes no *sql.Tx, and is shared by the copy
orchestration and the dry-run endpoint so their numbers cannot drift.

DR-11a: every resolution is scoped to workspace_id = A AND deleted_at IS
NULL, and the parent/variant traversal carries the identical scope. The
reference set comes from user-controlled content, so an unscoped lookup
would let a user clone another workspace's blob into a workspace they
control, bypassing the download handler's workspace check. Refs that
resolve to nothing under that scope -- dangling, soft-deleted, or foreign
-- are never cloned and never fatal: they get no map entry, so the
rewrite preserves the literal text and the copy renders exactly as broken
as the source did.

A cross-backend row emits an empty storage_key with the source key in
SourceStorageKey, so the plan never contains a key the target backend
cannot resolve. CreateAttachment now rejects an empty storage_key, which
turns that contract into an enforced invariant: an orchestration that
skips the Get/Put byte transfer fails at insert rather than creating a
live attachment that 404s on download.

Claude-Session: https://claude.ai/code/session_01E2fRi12n8rARczvdEa2LYT
2026-07-30 14:37:51 +00:00
..
2026-03-26 01:52:36 +00:00