From bc4eba636d7c2ec20891fb9cab5aeb29b81d1ec7 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 31 Aug 2026 16:55:43 -0400 Subject: [PATCH] fix: the documented install path pulled :dev, not :latest (#3270) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit docker-compose.yml pinned :dev on all five app services — web, worker, scheduler, maintenance-long, ml-worker. The README documents `docker compose -f docker-compose.yml up -d` as the production path, and -f means "use only this file", skipping the override and its build: directives. So Compose pulled image:, and image: was the rolling development channel. The documented way to install this product shipped development builds. It went unnoticed for a structural reason rather than a careless one: nobody who works on the project takes that path. The operator deploys from a swarm stack file; contributors get docker-compose.override.yml, which sets build: for all five services, and build: wins over image:. The broken path is reachable only by a stranger following the README — which is exactly the audience that did not exist until now. :latest, per rule 147: main IS production. It is also what the agent stack (agent/docker-compose.yml) already pinned, so this makes the two stacks agree rather than introducing a new convention. Both paths verified with `docker compose config`, which merges and prints without starting anything: dev path — build: present on all five, image: not pulled -f production — 0 build: directives, five :latest images resolved Also checked the base file for anything a stranger could not satisfy: no host-absolute volume paths, no operator-specific port bindings, no device mappings. The tag was the only defect in the consumer path. The comment on web.image is deliberately long (rule 32). A line reading :latest inside a file a developer is debugging with is exactly the line someone flips back to :dev to test something and then commits, and the consequence — strangers silently installing bleeding edge — is invisible to everyone who works here. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_017QHszn9H8VBvx5Ke8x1hvw --- README.md | 12 +++++++++++- docker-compose.yml | 28 +++++++++++++++++++++++----- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index cd9c1fe..efeff23 100644 --- a/README.md +++ b/README.md @@ -69,9 +69,19 @@ or a `.env` file (see `.env.example` for the variable names) and use: ```bash docker compose -f docker-compose.yml up -d -# (skips the override so containers pull registry images) +# (skips the dev override, so containers pull published :latest images) ``` +`-f` is doing real work there: it tells Compose to use *only* that file, which +skips `docker-compose.override.yml` and its local builds. What you get is the +`:latest` images — the stable channel, built from `main`. This is the install +path, and it is the one to use if you are running FabledCurator rather than +working on it. + +`:dev` is the other channel: rebuilt from the `dev` branch several times a day, +bleeding edge, no stability promise. Nothing in this repo points an installer at +it, and nothing should. + The GPU agent is deployed separately, on the machine with the card — `agent/docker-compose.yml`, not this stack. diff --git a/docker-compose.yml b/docker-compose.yml index 1fb24d6..59b4503 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -74,7 +74,25 @@ services: retries: 5 web: - image: git.fabledsword.com/bvandeusen/fabledcurator:dev + # :latest, NOT :dev — this file IS the install path. + # + # `docker compose up -d` merges docker-compose.override.yml, which sets + # build: for all five app services, and a build: wins over image:. So a + # contributor never pulls this tag and is unaffected by what it says. + # + # The tag is consulted only on `docker compose -f docker-compose.yml up -d` + # — the documented production path, which skips the override. That is a + # stranger installing the product, and they must land on the stable channel. + # + # :latest is main, which IS production (rule 147). :dev is the rolling + # bleeding-edge channel we work out of, republished several times a day with + # no stability promise. This file pinned :dev on all five services until + # 2026-08-31 (#3270), so the documented install shipped development builds. + # It went unnoticed because nobody who works on the project takes this path: + # the operator deploys from a swarm stack file, contributors get the + # override. Do not "fix" this back to :dev while debugging — use the + # override, or -f with an explicit tag on the command line. + image: git.fabledsword.com/bvandeusen/fabledcurator:latest command: ["web"] # Graceful shutdown: give the container time to drain in-flight work on a # deploy (docker SIGTERMs, then SIGKILLs after this window — default is only @@ -122,7 +140,7 @@ services: redis: { condition: service_healthy } worker: - image: git.fabledsword.com/bvandeusen/fabledcurator:dev + image: git.fabledsword.com/bvandeusen/fabledcurator:latest command: ["worker"] # Drain in-flight import/thumbnail/download tasks before SIGKILL on deploy. stop_grace_period: 90s @@ -142,7 +160,7 @@ services: redis: { condition: service_healthy } scheduler: - image: git.fabledsword.com/bvandeusen/fabledcurator:dev + image: git.fabledsword.com/bvandeusen/fabledcurator:latest command: ["scheduler"] # Quick maintenance/scan lane + beat — short tasks, modest drain window. stop_grace_period: 60s @@ -163,7 +181,7 @@ services: # 30-min backup or a multi-chunk audit can never starve the 5-min recovery # sweeps / vacuum (operator-flagged 2026-06-07). One slot — these are heavy. maintenance-long: - image: git.fabledsword.com/bvandeusen/fabledcurator:dev + image: git.fabledsword.com/bvandeusen/fabledcurator:latest command: ["worker"] # Longest lane (DB backups, library audits, translation backfill) — give it # the most room to finish a chunk gracefully. Chunked + idempotent, so a job @@ -184,7 +202,7 @@ services: redis: { condition: service_healthy } ml-worker: - image: git.fabledsword.com/bvandeusen/fabledcurator-ml:dev + image: git.fabledsword.com/bvandeusen/fabledcurator-ml:latest command: ["ml-worker"] # A single GPU inference pass can run tens of seconds — let it finish. stop_grace_period: 120s