Summary
On the fly target there is no deploy provider that can actually publish: DEPLOY_PROVIDER selection only knows aws and docker, and anything else — including unset, including "fly" — silently falls back to docker. The core runs in a Fly machine whose image ships no docker binary and no daemon (and Fly Machines are Firecracker VMs, so there is no host socket to mount either). Every publish therefore fails with:
deploy run failed: spawn docker ENOENT
This is reproducible with a trivial app (one server.py on $PORT + one index.html) from any scope. Publish on a target: fly + sprites topology has never worked — it is a feature gap, not a regression, but nothing fails loudly at config/doctor/up time, so it presents as a runtime bug.
Evidence
-
Provider selection is a two-way ternary — src/config.ts:636 (current main, checked at 47a6d6c):
const deployProvider: "aws" | "docker" = env.DEPLOY_PROVIDER === "aws" ? "aws" : "docker";
DEPLOY_PROVIDER=fly still selects docker.
-
The docker spawn site is hardcoded and not overridable — src/deploy/docker-deploy-provider.ts:16:
const docker = opts.docker ?? "docker";
Wiring (src/wiring.ts:775-785) passes no opts; there is no DOCKER_BIN-style env override. The child_process error event surfaces as the spawn docker ENOENT message via docker-deploy-provider.ts:76.
-
Live probe of a fly-target core machine: which docker → nothing, /var/run/docker.sock → does not exist, DEPLOY_PROVIDER → unset.
-
The fly publisher is half-landed. The CLI and secret schema already anticipate it — cli/src/backends/fly.ts:957,1435 and src/deployment/secret-schema.ts:48 gate FLY_DEPLOY_API_TOKEN on DEPLOY_PROVIDER === "fly", and .env.example documents the token — but no fly-deploy-provider.ts exists in src/deploy/. The scaffolding shipped; the provider didn't.
Asks
Either (ideally both):
- Implement the fly deploy provider the scaffolding anticipates — the
DeployProvider seam is small (apply / destroy / resolveEndpoint); one Fly app or machine per deployment via the Machines API using the FLY_DEPLOY_API_TOKEN the CLI already verifies and pushes. profile.managedScaleToZero maps naturally onto Fly autostop.
- Fail loudly instead of falling back. When
target: fly (or any config whose resolved provider can't exist in the core's own runtime) resolves to docker, qm check / qm doctor / qm up should error at that point — not let every publish die at spawn time with an ENOENT that reads like a host misconfiguration.
Environment: qm on target: fly, SANDBOX_BACKEND=sprites, core deployed via qm up. Related in spirit to #137 (fly/sprites contracts that configure cleanly but have no implementation behind them).
Summary
On the fly target there is no deploy provider that can actually publish:
DEPLOY_PROVIDERselection only knowsawsanddocker, and anything else — including unset, including"fly"— silently falls back to docker. The core runs in a Fly machine whose image ships no docker binary and no daemon (and Fly Machines are Firecracker VMs, so there is no host socket to mount either). Everypublishtherefore fails with:This is reproducible with a trivial app (one
server.pyon$PORT+ oneindex.html) from any scope. Publish on atarget: fly+ sprites topology has never worked — it is a feature gap, not a regression, but nothing fails loudly at config/doctor/uptime, so it presents as a runtime bug.Evidence
Provider selection is a two-way ternary —
src/config.ts:636(currentmain, checked at47a6d6c):DEPLOY_PROVIDER=flystill selects docker.The docker spawn site is hardcoded and not overridable —
src/deploy/docker-deploy-provider.ts:16:Wiring (
src/wiring.ts:775-785) passes no opts; there is noDOCKER_BIN-style env override. The child_processerrorevent surfaces as thespawn docker ENOENTmessage viadocker-deploy-provider.ts:76.Live probe of a fly-target core machine:
which docker→ nothing,/var/run/docker.sock→ does not exist,DEPLOY_PROVIDER→ unset.The fly publisher is half-landed. The CLI and secret schema already anticipate it —
cli/src/backends/fly.ts:957,1435andsrc/deployment/secret-schema.ts:48gateFLY_DEPLOY_API_TOKENonDEPLOY_PROVIDER === "fly", and.env.exampledocuments the token — but nofly-deploy-provider.tsexists insrc/deploy/. The scaffolding shipped; the provider didn't.Asks
Either (ideally both):
DeployProviderseam is small (apply / destroy / resolveEndpoint); one Fly app or machine per deployment via the Machines API using theFLY_DEPLOY_API_TOKENthe CLI already verifies and pushes.profile.managedScaleToZeromaps naturally onto Fly autostop.target: fly(or any config whose resolved provider can't exist in the core's own runtime) resolves to docker,qm check/qm doctor/qm upshould error at that point — not let every publish die at spawn time with an ENOENT that reads like a host misconfiguration.Environment: qm on
target: fly,SANDBOX_BACKEND=sprites, core deployed viaqm up. Related in spirit to #137 (fly/sprites contracts that configure cleanly but have no implementation behind them).