fix(platform): make the 0.5 fresh deploy reach a working stack - #3108
Merged
Conversation
v0.5.0 cannot deploy itself on a clean host — five independent defects,
found by walking the released artifacts through the documented fresh-deploy
journey:
- tale deploy derived its pull list mechanically as tale-${service},
inventing tale-backend-api / tale-backend-worker images that were never
built (the backend tier runs the platform image). Service → image now
goes through imageRef/imageRepoForService, shared by the compose
creators and the pull list, with THIRD_PARTY_IMAGES carrying the minio
pin.
- The generated backend services lacked DATABASE_URL, so both roles
crash-looped on the env schema. Mirrors compose.yml, failing closed on
a missing DB_PASSWORD.
- object-store was in the stateful compose but in NO deploy tier, so the
explicit 'up -d <services…>' never started the blob store (uploads
dead, worker ENOTFOUND at boot). It joins STATEFUL + STOP_GATED, which
also makes status/reset see it; the backend tier now depends_on it.
- waitForHealthy only accepted 'healthy', so backend-worker — whose
healthcheck is deliberately disabled (no HTTP surface) — burned the
full 300s timeout on every deploy. Running + no configured healthcheck
now passes.
- The proxy entrypoint kept the whole 0.5 lane block (auth/app routes,
/events, machine doors, /<bucket>/*) behind the cutover's
BACKEND_UPSTREAM reversibility switch; with Convex gone, unset no
longer means 0.4 lanes — it means uploads, live updates and every
machine door 404. The lanes inject unconditionally now, the variable
stays as an override.
The platform image also lost the shipped config catalogs the retired
convex image used to bake (/app/system, /app/builtin — every provider
read 500'd, orgs seeded nothing) and never owned /app/data, so the
backend roles hit EACCES on the root-owned org-config volume. The
Dockerfile bakes both catalogs and owns the mount point; the entrypoint
re-asserts ownership for volumes a v0.5.0 image already booted against.
Guards: compose-parity locks service→image to release.yml's build
matrix, backend env keys to compose.yml, the minio pin to one value, and
the proxy entrypoint to unconditional lanes; container-image-test now
fails any platform image missing the catalogs or an app-owned /app/data.
Also corrects the 0.4-era guard texts (--accept-data-loss help, the
run-deploy comment, and the docblock promising a container-side backstop
that retired with the Convex runtime).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What broke
v0.5.0 cannot deploy itself on a clean host. Walking the released artifacts through the documented fresh-deploy journey (
tale init→tale deploy→ onboarding → provider → chat → upload) hit five independent defects — the first one fatal at the very first step:deploy.tsderived image names mechanically astale-${service}, so the new backend tier producedtale-backend-api:0.5.0/tale-backend-worker:0.5.0, which the release pipeline never builds (the tier runs the platform image withTALE_ROLEdispatch). Every fresh deploy dies at "Failed to pull image".DATABASE_URLon the backend services (compose.yml does); both roles crash-looped on the env schema.object-storewas in the stateful compose but in no deploy tier, and the deployup -dnames services explicitly: no store container, uploads dead, workerENOTFOUND object-storeat boot.waitForHealthyonly acceptedhealthy;backend-workerdeliberately has no healthcheck (no HTTP surface) and can never report it. Every deploy burned the full 300 s and aborted./events(SSE), both machine doors, control drain, SSO/SCIM and/<bucket>/*behind the cutover'sBACKEND_UPSTREAMreversibility switch.tale deploynever sets it, and with the Convex runtime gone "unset" no longer means 0.4 lanes — it means uploads, live updates and every machine door 404. (Chat only worked because the base Caddyfile's/api/*carries its own default.)Two more live in the platform image itself, inherited from the teardown — the retired convex image used to carry them:
/app/system+/app/builtin(the shipped config catalogs) are baked nowhere: every provider read 500s (missing shipped config directory) and org scaffolding has no seed catalog. Neithertale deploynor plaindocker compose upworks around it./app/data(org-config volume mount point) is never owned: the volume initializes root-owned while every role runs asapp— the backend's object-store bootstrap dies onEACCESwriting the default connection.The fix
imageRef/imageRepoForService/THIRD_PARTY_IMAGESintools/cli/src/lib/compose/types.ts) used by both the compose creators and the deploy pull list (deduped), so they cannot drift again.DATABASE_URL(fail-closed on a missingDB_PASSWORD, mirroring the object-store key) anddepends_on: object-store.object-storejoinsSTATEFUL_SERVICES+STOP_GATED_SERVICES— started on first deploy, recreated only under--stop, and now visible tostatus/reset/-s.waitForHealthytreats running with no configured healthcheck as success.BACKEND_UPSTREAM=backend-api:3005; the variable remains an override for split deployments.configs/platform/system → /app/systemandconfigs/platform/custom → /app/builtin(the dockerignore already strips**/*.secrets.jsonfrom the context) and owns/app/data; the entrypoint's root phase re-asserts ownership for volumes a v0.5.0 image already booted against.--accept-data-losshelp, run-deploy comment, and the guard docblock that promised a container-side backstop which retired with the Convex runtime).Guards added
compose-parity.test.ts: every generated tale image must equalimageReffor its service; every image repo must exist in release.yml's build matrix (the cross-artifact fact defect 1 violated); backend env keys must cover compose.yml's (defect 2); the minio pin is a single shared value; the proxy entrypoint must inject the lanes unconditionally (defect 5).container-image-test.ts(runs in the release container gate): fails any platform image missing/app/system/providers,/app/builtin, or an app-owned/app/data(defects 6–7 — this is the check that would have stopped v0.5.0 from shipping).Verified
On this machine, against the released ghcr 0.5.0 images with the fixed CLI (built from this branch, stamped 0.5.0):
Deployment complete!, all 10 containers healthy in one pass;/events+/tale-blobs/*with noBACKEND_UPSTREAMset;tscclean fortools/cliandservices/platform,oxlintclean,bash -non both entrypoints.Not in this PR (follow-ups)
tale update --version X(space form) is silently eaten by the root--versionflag on every CLI line — real parser bug, needs its own change (the=form works; notes/doc snippets avoid the broken form).upgrades.mdstill lists aconvextier and aTALE_ACCEPT_DATA_LOSScontainer backstop that no longer exists;overview/container-architecture/ compose-reference pages still describe the 0.4 topology (needs the en/de/fr sweep).CONVEX_URL/SANDBOX_STORAGE_INTERNAL_BASE_URL=http://convex:3210residues (unused by the verified lanes; sandbox lanes not exercised in this pass)./api/auth/convex/token(404, cosmetic) — belongs to the http-api residues branch.