You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix scratchpad asset sweep data loss and hardening from code review
Addresses correctness findings in the file-backed scratchpad assets work:
- Sweep race / clear resurrection (data loss): the orphan sweep keyed its
grace window on file mtime, so a long-referenced image got zero grace the
instant it became unreferenced (e.g. `clear` racing an open tab's pending
autosave), letting the sweep permanently delete a file the surviving
snapshot still pointed at. Anchor the grace to when a file is FIRST observed
unreferenced instead, tracked in-memory. This also subsumes the dedup
mtime-not-refreshed case (mtime no longer factors into the decision).
- `delete`/re-add leaked asset files: `delete` removed only the shape and its
bindings, leaving the asset record to pin its file against the sweep forever
(asymmetric with the `clear` fix). Drop the asset record when the deleted or
replaced shape was its last user (shared assets are preserved).
- Atomic asset writes: write via a temp sibling + rename so a crash or full
disk mid-write can't leave a truncated file at the content-addressed path
that the exists() skip would then serve forever.
- Stored-XSS hardening: serve assets with Content-Disposition: attachment and
X-Content-Type-Options: nosniff so a pasted/uploaded SVG can't execute as
script in the app origin on direct navigation (img/video/fetch ignore these).
- assetStore held in a ref, not useMemo (which React may discard): a fresh
`assets` identity makes <Tldraw> rebuild its store and remount the editor,
dropping unsaved edits and resetting the camera.
- Flag `missing` in `read` for shapes whose asset RECORD is absent, not only
when the file is gone, so the agent isn't handed a healthy-looking image.
- Sync the CLI's read-image extension map with the server (avif/apng/video),
so those assets save with a real extension instead of `.bin`.
- Derive ASSET_FILE_RE and the .bak scanner from one shared pattern so they
can't drift and delete backup-referenced files; add image/apng to MIME_EXT.
Tests updated for the new grace semantics; new regression tests cover the
clear-race data loss and the delete reclaim path.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HCbMMxrNwyPAtJP5qryT6W
0 commit comments