Skip to content

Copy FileDef binaries when installing a listing#671

Merged
richardhjtan merged 2 commits into
mainfrom
listing-install-copy-binaries
Jul 23, 2026
Merged

Copy FileDef binaries when installing a listing#671
richardhjtan merged 2 commits into
mainfrom
listing-install-copy-binaries

Conversation

@richardhjtan

Copy link
Copy Markdown
Collaborator

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.

  • The /_atomic endpoint only accepts card and source resource types, and a file-meta resource is a JSON projection with no bytes to write, so the install command dropped file-meta documents from the batch entirely.
  • The copied cards keep their relative links.self (e.g. ../chateau-margaux.jpg), and links.self takes precedence over data.id at 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 ReadBinaryFileCommandWriteBinaryFileCommand (a per-file application/octet-stream POST, the same write path the host upload flow and boxel realm push use 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

  • New fixture: a photo-post listing whose example card has a linksTo(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.
  • Verified end-to-end on a local dev stack: remixed the wine-cellar listing into a scratch workspace; all three label binaries were byte-identical copies in the install directory and the installed cards' relative links resolve to them.
  • Lint and typecheck pass via the monorepo catalog mirror.

🤖 Generated with Claude Code

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>
Copilot AI review requested due to automatic review settings July 23, 2026 11:26
@github-actions

github-actions Bot commented Jul 23, 2026

Copy link
Copy Markdown

Staging Submissions Preview

This PR's content is pushed to the staging submissions realm: https://realms-staging.stack.cards/submissions/

Changed folders:

  • commands/
  • tests/

Updated at 2026-07-23 11:57:18 UTC for commit 22ff059. Shared realm: only this PR's changed files are pushed; files touched by multiple PRs reflect whichever pushed last, and deleted files are not removed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 ListingInstallCommand to copy underlying binary files for file-meta resources using ReadBinaryFileCommandWriteBinaryFileCommand before the atomic batch write.
  • Adds a new photo-post mock listing fixture containing a real PNG referenced via a file-meta relationship.
  • 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(

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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.

Comment on lines +127 to +131
photo: {
links: { self: `${mockCatalogURL}photo-post/photo.png` },
data: {
type: 'file-meta',
id: `${mockCatalogURL}photo-post/photo.png`,

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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>
@richardhjtan
richardhjtan requested a review from a team July 23, 2026 12:33
@richardhjtan
richardhjtan merged commit 897351e into main Jul 23, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants