From 6fbb48c3de9d3bf4ba7584a8f21d3b1e1bd5b366 Mon Sep 17 00:00:00 2001 From: Joel Natividad <1980690+jqnatividad@users.noreply.github.com> Date: Tue, 15 Sep 2026 23:10:37 -0400 Subject: [PATCH] fix(docker): correct site-packages path, and build the image in CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The production stage copied /usr/local/lib/python3.11/site-packages, but #3 bumped both stages to python:3.14-slim, where that path does not exist. Docker fails the instruction rather than skipping it, so every image build has failed since 2026-09-10 — including `docker compose up --build`, the Docker path the README documents. Nothing built the image in CI, which is why it shipped unnoticed for six days. Add a blocking `docker` job that builds it and boots it, asserting /health and /api/v1/health. The build alone is not enough: the production stage copies site-packages and src/ in separate COPY lines, and web.py swallows a failed API router import as a warning rather than a crash, so only booting the container catches those. Verified locally: build succeeds (873MB), image runs Python 3.14.7, deps and data_concierge import, qsv rides along on the /usr/local/bin copy, and both health endpoints return 200 with no restarts. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 41 ++++++++++++++++++++++++++++++++++ .serena/memories/tech_stack.md | 1 + CONTRIBUTING.md | 1 + Dockerfile | 2 +- 4 files changed, 44 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c31f2e9..f1543aa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,6 +73,47 @@ jobs: - name: Check uv.lock matches pyproject.toml run: pip install uv && uv lock --check + docker: + name: docker image + runs-on: ubuntu-latest + timeout-minutes: 20 + # Blocking, because nothing built the image before this job existed and a + # broken build shipped unnoticed for six days: dependabot bumped the base to + # python:3.14-slim (#3) while the production stage still copied + # python3.11/site-packages, so every build — including the documented + # `docker compose up --build` — failed on a path that no longer existed. + + steps: + - uses: actions/checkout@v7 + + - uses: docker/setup-buildx-action@v4 + + - name: Build + uses: docker/build-push-action@v7 + with: + context: . + push: false + load: true + tags: verikan:ci + cache-from: type=gha + cache-to: type=gha,mode=max + + # Building is not enough. The production stage copies site-packages and + # src/ in separate COPY lines, so a wrong path can still produce an image + # that builds and then fails to import. Boot it and require both health + # endpoints — /api/v1/health also proves the API router mounted, which + # web.py swallows as a warning rather than a crash. + - name: Smoke-test + run: | + docker run -d --name verikan-ci -p 8080:8080 verikan:ci + for _ in $(seq 1 60); do + curl -sf localhost:8080/health >/dev/null 2>&1 && break + sleep 2 + done + curl -sf localhost:8080/health || { docker logs verikan-ci; exit 1; } + curl -sf localhost:8080/api/v1/health || { docker logs verikan-ci; exit 1; } + docker rm -f verikan-ci + types: name: types & formatting (advisory) runs-on: ubuntu-latest diff --git a/.serena/memories/tech_stack.md b/.serena/memories/tech_stack.md index e82b134..8e14531 100644 --- a/.serena/memories/tech_stack.md +++ b/.serena/memories/tech_stack.md @@ -3,6 +3,7 @@ - Python `>=3.12`; CI matrix 3.12 + 3.14. `target-version = "py312"`, mypy `python_version = "3.12"`. Do not use 3.13+-only syntax. - **3.11 was dropped deliberately.** `tests/unit/test_query_stream.py::test_cancelled_stream_reader_cancels_worker` deadlocks on 3.11 only: `gateway/query_stream.py::query_events` does `worker.cancel()` then `await worker` inside `anyio.CancelScope(shield=True)` in its `finally`, and on 3.11 that shielded await never completes when the *consumer* task is cancelled. Introduced by `fa50bfb` (PR #7). The suite passes on 3.12 and 3.14. If anyone proposes restoring 3.11, that deadlock is the blocker. - 3.14 is in the matrix because the Dockerfile ships `python:3.14-slim`. Bump the two together or the deployed interpreter goes untested. +- **A blocking `docker` CI job builds the image and boots it** (`/health` + `/api/v1/health`). It exists because nothing built the image before: dependabot bumped the base to `python:3.14-slim` (#3) while `Dockerfile` still copied `python3.11/site-packages`, so every build — including the documented `docker compose up --build` — failed for six days on a path that no longer existed. The production stage copies site-packages and `src/` separately, so the build succeeding is not sufficient; the smoke test is the part that catches a bad copy. - FastAPI + uvicorn + Jinja2 templates; Pydantic v2 (`pydantic-settings` for `core/config.py`). - LangGraph for agent orchestration; `anthropic` SDK directly (no LangChain LLM wrappers). - pandas / numpy for computation; `nbformat` + `nbclient` + `ipykernel` for notebook generation and execution. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c7f23be..8f78fcb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,6 +28,7 @@ boundary, or make it a manual script. | `ruff format --check` | No — advisory | Pre-existing drift across many files | | `mypy src/` | No — advisory | ~90 pre-existing errors, mostly missing annotations | | `uv lock --check` | **Yes** | `uv.lock` must match `pyproject.toml` — no backlog, so it's a gate | +| `docker build` + smoke test | **Yes** | Builds the image and boots it; nothing watched it before, so a base-image bump broke the build for six days | The advisory job reports so the debt stays visible, but it does not block your pull request. Don't add *new* type errors; fixing ones you touch is welcome. **Please don't reformat files diff --git a/Dockerfile b/Dockerfile index 6e49878..b6816f4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -59,7 +59,7 @@ RUN useradd --create-home --shell /bin/bash appuser WORKDIR /app # Copy installed packages from builder -COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages +COPY --from=builder /usr/local/lib/python3.14/site-packages /usr/local/lib/python3.14/site-packages COPY --from=builder /usr/local/bin /usr/local/bin # NOTE: qsv arrives with the /usr/local/bin copy above — a second explicit