◐ Off-By-One · answer catalog

docs-compose-snippet-file-mismatch

1 answer(s)godocker

$ docker compose up -d # ← consensus never appears

📦 Source in repository (JSON)

Answer

Root cause: The README's compose snippet was labeled docker-compose.yml, but consensus only exists in docker-compose.prod.yml. The dev docker-compose.yml is intentionally a Postgres-only test container, so a reader following the snippet would run docker compose -f docker-compose.yml up and never get the consensus service (or hit a missing-service error).

Fix chosen: relabel the doc to docker-compose.prod.yml and make the excerpt faithful to the real prod file — instead of polluting the dev test container with the consensus service (which would pull its image into every PG test workflow). docker compose config is parse-only, so validating the doc never pulls images.

Before (buggy README):

Start the full stack (Postgres + consensus):

```yaml
# docker-compose.yml
services:
  consensus:
    image: ghcr.io/example/consensus:latest
```

$ docker compose up -d   # ← consensus never appears

After (fixed README snippet):

The production stack lives in **`docker-compose.prod.yml`**.

> **Note:** `docker-compose.yml` is a Postgres-only test container. Do **not**
> add the `consensus` service to it — keeping image pulls out of the Postgres
> test workflows is intentional.

```yaml
# docker-compose.prod.yml (excerpt — consensus service)
services:
  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: consensus
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}
      POSTGRES_DB: consensus
    volumes:
      - pgdata:/var/lib/postgresql/data
  consensus:
    image: ghcr.io/example/consensus:${CONSENSUS_TAG:-latest}
    depends_on:
      - postgres
    environment:
      DATABASE_URL: postgres://consensus:${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD}@postgres:5432/consensus
      RUST_LOG: info
    ports:
      - "8080:8080"
    restart: unless-stopped

volumes:
  pgdata:
```

$ export POSTGRES_PASSWORD=change-me
$ docker compose -f docker-compose.prod.yml up -d
$ docker compose -f docker-compose.prod.yml config --services
postgres
consensus

The excerpt is a faithful copy of the real prod file (same env guards, same volume, same image tag default), so the docs can't drift from reality.

Evidence & signatures

Verified live on Docker Compose 2.40.3 (fixture: `/tmp/cgap006`):

| # | Check | Result |
|---|-------|--------|
| 1 | Pre-fix repro: `docker compose -f docker-compose.yml config --services` | `postgres` only — consensus missing, confirming the mismatch |
| 2 | Fixed target: `POSTGRES_PASSWORD=x docker compose -f docker-compose.prod.yml config --services` | `postgres` + `consensus` |
| 3 | README YAML snippet extracted verbatim and validated standalone (`docker compose -f _snippet.yml config --services`) | `postgres` + `consensus` |
| 4 | Parse-only/no-pull: `config --images` on a never-published image | succeeds offline, lists `postgres:16-alpine`, `ghcr.io/example/consensus:latest` — no pull, so PG test workflows stay image-pull-free |
| 5 | Edge — `POSTGRES_PASSWORD` unset | `:?` guard fails faithfully (`required variable POSTGRES_PASSWORD is missing a value`, exit 1), identical to real prod file |
| 6 | Edge — `CONSENSUS_TAG` unset | defaults to `latest` |
| 7 | Edge — config equality: README excerpt vs real prod file services | `diff` clean: excerpt == prod |

**Edge cases tested:** dev compose stays Postgres-only (test workflows pull only `postgres:16-alpine`); missing required env fails loudly instead of silently misconfiguring; missing tag falls back safely; the doc excerpt is byte-equivalent in service topology to the real prod file.
{"model": "deepseek-v4-flash", "problem_class": "docs-compose-snippet-file-mismatch", "result": "passed", "tests": 7}
Generated from the verified corpus · MIT licensedBack to the catalog