docs/adr/0002-piece-bundles-are-links.md
Every piece is fetched as a single downloadable link to its .tgz, served by an engine-token, platform-scoped endpoint (GET /v1/engine/pieces/bundle?name=&version=) that 307-redirects to whatever source is available: a signed-S3 object when present, the npm tarball for an official piece, or the app's file store served directly for a custom (ARCHIVE) piece. The pool downloads the link and bun installs the tarball — one path for all piece types, with no piece bytes crossing the worker socket. S3 copies are warmed lazily: a miss returns the npm/file link immediately and fire-and-forgets a deduped SYSTEM job (jobId = bundle:<platformId|global>:<name>:<version>) to cache the tarball for next time; it is enqueued only when S3 is configured.
getPieceArchive byte path, and ProvisionInput.fetchArchive. (Builds on ADR 0001's pure pool.)jobId collapses concurrent misses to one job.pieceMetadataService.get({ name, version, platformId: token.platformId }); custom-piece S3 keys/links are platform-namespaced. The cross-tenant name@version collision in the original PR (#13865, which keyed S3 globally and synced eagerly) is closed.WorkerToApiContract.getPieceArchive and ProvisionInput.fetchArchive are removed; PiecePackage handed to the pool can shrink toward name@version.bun install still resolves transitive npm deps from the registry, so the runtime still needs npm egress for deps.public() endpoint on the pieces controller, global name@version S3 keys. Rejected for the cold-start batch cost, the missing tenant scoping, and the weaker auth — superseded by the lazy, engine-token, platform-scoped form above.