Files
T
q792602257andClaude Opus 4.6 fa10cccf71 chore(openspec): archive downgrade-python-3-13-paddleocr
Change is complete (19/19 tasks) and its delta spec has been synced
into a new main spec openspec/specs/python-runtime-baseline/spec.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-07-14 21:18:57 +08:00

55 lines
8.4 KiB
Markdown

## Context
The workspace root and all three `uv` workspace members (`apps/device-host-agent`, `apps/cloud-api`, `packages/cloud-platform`) pin `requires-python = ">=3.14"`. `Dockerfile` and `Jenkinsfile` both build on `astral-sh/uv:python3.14-bookworm-slim`. `paddleocr>=3.0.0` is a hard dependency of the root `device-agent-runtime` project (`pyproject.toml:13`), and `perception/ocr.py::PaddleOCREngine._load()` requires the separate `paddlepaddle` package at runtime to actually run inference — but `paddlepaddle` has no `cp314` wheel on PyPI (verified against the PyPI project page and `PaddlePaddle/PaddleOCR#17370`), so no Python-3.14 environment in this project can ever install it. This has already caused a production task failure on a real host-agent device. `docs/MACOS_IPHONE_SETUP.md:156-158` already flagged this exact tension and required it be resolved as a deliberate, validated workspace-wide change rather than an ad hoc per-host downgrade — this design is that change.
## Goals / Non-Goals
**Goals:**
- Make `paddlepaddle` installable (and therefore OCR functional) on every environment that follows this project's documented setup, by moving the supported Python version to one PaddlePaddle actually ships wheels for.
- Keep the four workspace `pyproject.toml` files, `uv.lock`, `Dockerfile`, and `Jenkinsfile` mutually consistent on Python 3.13.
- Preserve all existing runtime behavior — this is a toolchain change, not a feature change. No application code logic should need to change to satisfy this proposal (only the interpreter/dependency-resolution target).
**Non-Goals:**
- Not declaring `paddlepaddle` as a project dependency in `pyproject.toml`/`uv.lock`. Per the earlier decision in this incident, installing `paddlepaddle` itself remains a manual, per-host operational step (`uv pip install paddlepaddle`), independent of this change. This proposal only removes the upstream blocker that made that manual install impossible; it does not automate the install.
- Not hardening `perception/ocr.py::run_ocr()` to catch `RuntimeError` from the OCR engine. That was raised and explicitly declined as a separate concern during incident triage — a task can still fail today if `paddlepaddle` is missing on a 3.13 host, just for a legitimate reason (nobody installed it) rather than an impossible one (no wheel exists).
- Not adding a Python version support matrix / CI test matrix across multiple Python versions. This project has always targeted a single pinned version; this change moves that single pin from 3.14 to 3.13, it does not introduce multi-version support.
- Not touching any application-level requirement/behavior — no `openspec/specs/*` capability changes accompany this change (see proposal.md Capabilities section).
## Decisions
**D1: Target `>=3.13,<3.14` (not a bare `>=3.13`).**
An open-ended `>=3.13` would silently re-admit 3.14 (and any future 3.15+) the moment a contributor's local `uv` picks a newer interpreter, reintroducing this exact bug with no warning. Pinning `<3.14` forces `uv sync`/`uv lock` to fail loudly if someone's environment tries to resolve against an unsupported interpreter, and makes the reason (paddlepaddle wheel availability) discoverable by grepping for the upper bound. When PaddlePaddle eventually ships `cp314` wheels, lifting this bound is a deliberate, reviewable one-line change rather than an implicit drift.
**D2: Change all four `pyproject.toml` files together, in one change.**
`uv` workspaces require a single resolved environment shared across all members (one `uv.lock`, one `.venv`) — `apps/cloud-api`, `apps/device-host-agent`, and `packages/cloud-platform` cannot each pin a different Python floor without breaking `uv sync --all-packages`. Alternatives considered: downgrading only `apps/device-host-agent` (the only member that actually touches OCR) — rejected, because `uv` workspace resolution is root-driven and per-member `requires-python` values are intersected, not independently honored; leaving the others at `>=3.14` while the root moves to `<3.14` would make the workspace intersection empty and `uv sync` would fail outright.
**D3: Re-run `uv lock` from scratch against Python 3.13 rather than hand-editing `uv.lock`.**
`uv.lock` embeds resolution metadata (wheel tags, hashes) tied to the target Python version; hand-editing it to swap version markers risks producing an internally inconsistent lockfile that `uv sync --locked` would reject or, worse, silently misresolve. A clean `uv lock` re-resolution is the only way to get a trustworthy lockfile, and lets the resolver naturally surface any dependency that (unlike `paddleocr`) turns out to have its own 3.13-vs-3.14 constraint conflicts.
**D4: Treat the Python-3.14-only-syntax audit as a verification task, not a design-time judgment call.**
A preliminary grep for known 3.14-only constructs (PEP 750 t-strings, `annotationlib`, `compression.zstd`) found no usage — but the only reliable check is actually running the full non-integration test suite under a real 3.13 interpreter, since static grepping cannot catch every possible 3.14-only stdlib call. `tasks.md` makes this an explicit, checked step rather than assuming the grep was sufficient.
**D5: No `openspec/specs/*` capability delta.**
This change alters the supported Python interpreter version and dependency resolution, not any capability's observable request/response behavior, protocol, or user-facing requirement. Every existing capability spec (`host-agent-protocol`, `perception-provider`, etc.) continues to describe the system correctly after this change. Consistent with treating this as a pure infrastructure/toolchain change (see proposal.md Capabilities section, which lists none).
## Risks / Trade-offs
- **[Risk] Some other pinned dependency in `uv.lock` might not have resolved the same way (or at all) for cp313 as it did for cp314** → Mitigation: `uv lock` will surface any resolution failure explicitly at lock time (task 2), and the full non-integration test suite must pass against the regenerated lock before this change is considered complete (task 5).
- **[Risk] Any contributor or deployment target still holding a Python 3.14 interpreter/venv will have builds/CI break the moment this merges** → Mitigation: this is the intended, accepted breaking change (called out as **BREAKING** in proposal.md); `docs/MACOS_IPHONE_SETUP.md` is updated in the same change to tell operators to install Python 3.13 instead, and the Docker/Jenkins base images are updated in lockstep so CI and containerized deployments do not need a separate manual step.
- **[Risk] Undiscovered 3.14-only syntax somewhere in the ~200+ Python files** → Mitigation: D4 — full test suite run under 3.13 is a required, verified task, not an assumption.
- **[Trade-off] This still does not make OCR work out of the box** — `paddlepaddle` remains an unlisted, manual dependency per the prior decision (Non-Goals). Every host still needs a manual `uv pip install paddlepaddle` after this change, and that install will still be wiped by a future `uv sync --locked` (a previously accepted and documented risk, now finally actionable since a compatible wheel will exist). This trade-off was deliberately kept out of scope to keep this change focused on the single blocking issue (wheel availability), not dependency-declaration policy.
## Migration Plan
1. Update `requires-python` in all four `pyproject.toml` files to `>=3.13,<3.14`.
2. Update `Dockerfile` and `Jenkinsfile` base images to `astral-sh/uv:python3.13-bookworm-slim`.
3. `uv python install 3.13`, then `uv lock` to regenerate `uv.lock` against the new interpreter.
4. `uv sync --locked --all-packages` to provision a 3.13 `.venv` from the new lock.
5. Run the full non-integration test suite (`uv run --all-packages pytest -m "not integration"`) and fix any failures caused by the interpreter change (expected: none, per D4).
6. Update `docs/MACOS_IPHONE_SETUP.md` to reflect the new 3.13 baseline and remove the now-obsolete "do not downgrade" warning.
7. No code rollback path is meaningfully separate from a `git revert` of this change — reverting restores the 3.14 pin and the pre-existing (already-broken) OCR situation, which is a safe rollback target since it is today's status quo.
## Open Questions
- None blocking. If PaddlePaddle later ships a `cp314` wheel, lifting the `<3.14` bound (D1) is a natural, separately-reviewable follow-up, not something this change needs to anticipate further than the explicit upper bound already makes discoverable.