Copy FileDef binaries when installing a listing#671
Conversation
Installing a listing whose example cards link FileDef binaries (images, audio) dropped the files: the atomic endpoint only accepts card/source resource types, and file-meta resources carry no bytes to write. The copied cards keep their relative links.self (which wins over data.id at deserialization), so they pointed at paths inside the install directory that were never written — broken images on every remix. The install command now partitions file-meta documents out of the atomic batch into per-file binary copies (ReadBinaryFileCommand → WriteBinaryFileCommand, the same octet-stream write path the host upload flow uses) and writes them before the atomic batch. There is no rollback on atomic failure; orphaned copies in the fresh install directory are harmless. Adds a photo-post fixture (module with a linksTo(ImageDef) field, example card, PNG) and a live test asserting the binary lands in the install directory; the install live-test module remains skipped pending the harness input-construction fix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Staging Submissions PreviewThis PR's content is pushed to the staging submissions realm: https://realms-staging.stack.cards/submissions/ Changed folders:
Updated at 2026-07-23 11:57:18 UTC for commit |
There was a problem hiding this comment.
Pull request overview
Fixes a listing install/remix issue where example cards that link to FileDef binaries (via file-meta) would install without copying the underlying binary bytes into the destination realm, resulting in broken image links.
Changes:
- Updates
ListingInstallCommandto copy underlying binary files forfile-metaresources usingReadBinaryFileCommand→WriteBinaryFileCommandbefore the atomic batch write. - Adds a new
photo-postmock listing fixture containing a real PNG referenced via afile-metarelationship. - Adds an acceptance test asserting that the linked binary is present in the installed listing directory.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
commands/listing-install.ts |
Copies file-meta-backed binaries into the install directory prior to atomic card/source writes. |
tests/helpers/test-fixtures.ts |
Adds a photo-post listing fixture with a PNG and an example card that links to it. |
tests/live/catalog-app/listing-install.test.gts |
Adds a new install test that checks the PNG is written into the destination install folder. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const photoPostListingId = `${mockCatalogURL}Listing/photo-post`; | ||
|
|
||
| export function runTests() { | ||
| module.skip( |
There was a problem hiding this comment.
[Claude Code 🤖] Intentional, unfortunately: the whole listing-install live module is skipped because every test in it fails at command.execute() with a card-api identity error while constructing ListingInstallInput — before any install logic runs. Moving the test to another module doesn't help; no live module can execute an install until that harness issue is fixed. The test is added now so it runs the moment the module is unskipped; the fix itself was verified end-to-end by remixing the wine-cellar listing on a local dev stack and checking the copied binaries byte-for-byte.
| photo: { | ||
| links: { self: `${mockCatalogURL}photo-post/photo.png` }, | ||
| data: { | ||
| type: 'file-meta', | ||
| id: `${mockCatalogURL}photo-post/photo.png`, |
There was a problem hiding this comment.
[Claude Code 🤖] Good catch — changed in 22ff059: the fixture now uses a relative links.self (../photo.png), matching the on-disk shape of catalog content, with data.id kept absolute as the card GET serves it. That's the exact geometry the fix has to satisfy: the relative link must re-resolve inside the install directory after the binary is copied.
Catalog content stores FileDef links relative on disk, and the relative form is what must re-resolve inside the install directory after copying — the fixture now exercises that shape directly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Summary
Installing (or remixing) a listing whose example cards link FileDef binaries produced broken images: the linked files were never copied into the destination realm.
/_atomicendpoint only acceptscardandsourceresource types, and afile-metaresource is a JSON projection with no bytes to write, so the install command dropped file-meta documents from the batch entirely.links.self(e.g.../chateau-margaux.jpg), andlinks.selftakes precedence overdata.idat deserialization — so installed cards pointed at paths inside the install directory that were never written.The install command now partitions file-meta documents out of the atomic batch and copies each underlying binary with
ReadBinaryFileCommand→WriteBinaryFileCommand(a per-fileapplication/octet-streamPOST, the same write path the host upload flow andboxel realm pushuse for binaries). Because install mirrors the source realm's directory layout under the install folder, the cards' relative links resolve to the copies with no relationship rewriting.Binaries are written before the atomic batch so installed cards resolve their file links as soon as they index. There is no rollback: if the atomic batch fails, the copies are left orphaned in the fresh UUID install directory, which is harmless.
This matters most for listings whose content is images — e.g. the AI Image Generator's history of generated PNGs, and the wine-cellar bottle labels.
Testing
photo-postlisting whose example card has alinksTo(ImageDef)field backed by a real PNG, plus a live test asserting the binary lands in the install directory. The listing-install live-test module remains skipped pending the harness input-construction fix, so the test rides that unskip.🤖 Generated with Claude Code