Skip to content

chore: reconcile the production Python runtime to a single 3.10 floor (closes #197)#198

Merged
cofade merged 1 commit into
mainfrom
chore/197-reconcile-python-version
Jun 29, 2026
Merged

chore: reconcile the production Python runtime to a single 3.10 floor (closes #197)#198
cofade merged 1 commit into
mainfrom
chore/197-reconcile-python-version

Conversation

@cofade

@cofade cofade commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Problem

The repo named its Python runtime three disagreeing ways — container python:3.12-slim, deploy-docs prose 3.11, bare-metal PM2 host 3.10. That drift is the documented root cause of incident #180 (a 3.11-only from datetime import UTC reached main and crashed both Python services at import time, because CI/containers ran a different interpreter than the host). The 3.10–3.14 CI matrix from #195 / ADR-029 mitigated the symptom but deliberately left the runtime-naming drift open. This PR is for #197 — it closes that gap.

Approach

Adopt 3.10 as the authoritative floor and make it enforced, not hand-maintained.

  • /.python-version (=3.10) — the single source of truth.
  • scripts/check-python-version.sh — a drift guard that asserts both Dockerfile.dev FROM lines, the image-service ruff floor (py310), and each CI matrix's version-aware minimum all match the anchor. Wired into make check-python-version, the husky pre-push hook, and a new python-version-consistency CI job (the tenth). Mirrors the existing check-citations house style.
  • Both Python images python:3.12-slimpython:3.10-slim, so the container path mirrors the live 3.10 PM2 host — eliminating the test-vs-ship divergence behind feat: live structured server-log console (closes #178) #180. The matrix stays 3.10–3.14: 3.10 is the floor we ship, not a cap on what the code must tolerate.
  • Prose reconciled to 3.10 across constraints, building-block view, docker-compose doc, CLAUDE.md, CONTRIBUTING, runbook, production-deployment, and the PR/issue templates; the now-ten CI job count is corrected everywhere it was stated (CONTRIBUTING was also stale at "eight" and missing ui-playwright).
  • Reconciliation recorded in ADR-029 and the chapter-11 lesson. The historical "named three ways" narrative is left intact — the guard scopes to machine-readable surfaces, so a literal-version grep can't self-trip on the lesson that explains the fix.

requirements*.txt are untouched: the floated bounds (numpy>=2.0.0, onnxruntime>=1.23.2, pydantic>=2.12.5) already resolve real wheels on 3.10 (ADR-029 chose each floor for exactly that). duckdb-service intentionally keeps no ruff config (ADR-029 documents why).

Verification (all run locally, green)

  • Real Docker builds on python:3.10-slim — both images build and import the native stack: image-service → py 3.10.20, cv2 4.10.0, onnxruntime 1.23.2; duckdb-service → duckdb 1.4.4, pydantic 2.13.4. The onnxruntime 1.23.2 resolution is exactly what ADR-029 predicts for a 3.10 interpreter.
  • Guard, both directions — passes on the real tree; correctly fails when a Dockerfile is reverted to 3.12 or a matrix minimum is lowered to 3.9; correctly passes on a reordered matrix and a trailing same-line comment.
  • Pre-push hook ran the full check suite (incl. the new guard) on push — all OK.
  • make check-citations clean; cross-surface grep shows no stray service-runtime version mention.
  • Two independent senior-reviewer passes; all P0/P1 resolved (incl. a P1 where adding the tenth job had stranded "nine jobs" claims).

Reviewer note

PR #196 (unmerged) also touches the runbook's Python section, so expect a trivial both-say-3.10 merge conflict there. No behavioral change — same code, and the 3.10 cell is already green in the existing matrix.

🤖 Generated with Claude Code

…closes #197)

The repo named its Python runtime three disagreeing ways — container
python:3.12-slim, deploy-docs prose 3.11, bare-metal PM2 host 3.10 — the
documented root cause behind incident #180 (a 3.11-only datetime.UTC that
crashed both Python services on deploy because CI/containers ran a different
version than the host). The 3.10-3.14 CI matrix from #195 (ADR-029) mitigated
the symptom but left the runtime-naming drift open; this closes it.

Adopt 3.10 as the authoritative floor and make it enforced, not hand-kept:

- Add /.python-version (=3.10) as the single source of truth.
- Add scripts/check-python-version.sh: asserts both Dockerfile.dev FROM lines,
  the image-service ruff floor (py310), and each CI matrix's version-aware
  minimum all match the anchor. Wired into make check-python-version, the
  husky pre-push hook, and a new python-version-consistency CI job.
- Pin both Python service images python:3.12-slim -> python:3.10-slim, so the
  container path mirrors the live 3.10 PM2 host (verified: both images build
  and import the native stack on 3.10 — onnxruntime resolves its 3.10 wheel,
  1.23.2, exactly as ADR-029 predicts).
- Reconcile every prose surface to 3.10 (constraints, building-block view,
  docker-compose doc, CLAUDE.md, CONTRIBUTING, runbook, production-deployment,
  PR/issue templates) and correct the now-ten CI job count across the docs.
- Record the reconciliation as done in ADR-029 and the chapter-11 lesson; the
  historical "named three ways" narrative is left intact (the guard scopes to
  machine-readable surfaces, so a literal-version grep can't self-trip on it).

The matrix stays 3.10-3.14: 3.10 is the floor we ship, not a cap on what the
code must tolerate. Requirements pins are untouched — the floated bounds
already resolve real wheels on 3.10. See ADR-029 for the floor rationale.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@cofade cofade merged commit 4d503dc into main Jun 29, 2026
18 checks passed
@cofade cofade deleted the chore/197-reconcile-python-version branch June 29, 2026 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant