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>
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-07-14
|
||||
@@ -0,0 +1,54 @@
|
||||
## 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.
|
||||
@@ -0,0 +1,29 @@
|
||||
## Why
|
||||
|
||||
PaddlePaddle has not published a Python 3.14 (`cp314`) wheel on PyPI (confirmed against PyPI project page and `PaddlePaddle/PaddleOCR#17370`, upstream tracking issue, no ETA). `perception/ocr.py::PaddleOCREngine` requires `paddlepaddle` at runtime to actually run inference, and `paddleocr>=3.0.0` is a hard dependency in `pyproject.toml`. Because the workspace pins `requires-python = ">=3.14"`, any host running this project on Python 3.14 can install `paddleocr` (pure-Python wheel) but can never install `paddlepaddle` — OCR will always fail with `RuntimeError: Engine 'paddle_static' is unavailable because dependency 'paddlepaddle' is not installed.` regardless of how the package is installed.
|
||||
|
||||
This has already caused a production task failure (`assignment ec036... attempt 1 on device-8967d09f0d5f4cf49f7361a9f0dcb0ce: failed`). `docs/MACOS_IPHONE_SETUP.md` already anticipated this class of problem and explicitly told operators not to downgrade to Python 3.13 ad hoc — it requires this to be done as a reviewed, workspace-wide compatibility change first. This proposal is that change.
|
||||
|
||||
## What Changes
|
||||
|
||||
- Lower the workspace's minimum/target Python version from `3.14` to `3.13` so `paddlepaddle` (and therefore working OCR) can actually be installed. **BREAKING**: any environment currently pinned to Python 3.14 must reinstall its toolchain with Python 3.13; `uv.lock` will be regenerated against the new interpreter and is not compatible with a 3.14-only environment.
|
||||
- Update `requires-python` in all four workspace `pyproject.toml` files (root, `apps/device-host-agent`, `apps/cloud-api`, `packages/cloud-platform`) from `>=3.14` to `>=3.13,<3.14`.
|
||||
- Update the Docker/CI base image from `astral-sh/uv:python3.14-bookworm-slim` to `astral-sh/uv:python3.13-bookworm-slim` in `Dockerfile` and `Jenkinsfile`.
|
||||
- Regenerate `uv.lock` against Python 3.13, which is expected to newly resolve a `paddlepaddle` wheel as installable (it is not added as a declared dependency by this change — see Non-Goals in design.md).
|
||||
- Audit the codebase for any Python-3.14-only syntax/stdlib usage that would break under 3.13, and fix or confirm none exists.
|
||||
- Update `docs/MACOS_IPHONE_SETUP.md` to remove/replace the now-obsolete "do not downgrade to 3.13 ad hoc" warning with guidance matching the new baseline.
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
- `python-runtime-baseline`: declares and enforces the workspace's supported Python interpreter version (3.13) consistently across all `pyproject.toml` files, `uv.lock`, the Docker image, and the CI pipeline.
|
||||
|
||||
### Modified Capabilities
|
||||
(none — no *existing* capability's observable requirements change; `perception-provider` and `host-agent-protocol` behavior are unaffected, only the Python interpreter version and dependency resolution change)
|
||||
|
||||
## Impact
|
||||
|
||||
- **Affected files**: `pyproject.toml`, `apps/device-host-agent/pyproject.toml`, `apps/cloud-api/pyproject.toml`, `packages/cloud-platform/pyproject.toml`, `uv.lock`, `Dockerfile`, `Jenkinsfile`, `docs/MACOS_IPHONE_SETUP.md`.
|
||||
- **Affected systems**: local dev environments, CI (Jenkins), production Docker images/deployment — all must move to Python 3.13.
|
||||
- **Dependencies**: full `uv lock` re-resolution against 3.13; no dependency version pins in `pyproject.toml` are expected to need changes, but the lock will reflect whatever the resolver picks for 3.13.
|
||||
- **Out of scope**: actually declaring `paddlepaddle` as a project dependency (remains a manual per-host install, per prior decision) and hardening `perception/ocr.py::run_ocr()` to catch `RuntimeError` (previously declined by the user as a separate concern).
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Workspace-wide supported Python version
|
||||
The system SHALL declare a single, consistent supported Python interpreter version range across the `uv` workspace root and every workspace member (`apps/device-host-agent`, `apps/cloud-api`, `packages/cloud-platform`), such that the range admits Python 3.13 and excludes Python 3.14, so that `paddlepaddle` (which has no Python 3.14 wheel available on PyPI) can be installed in every environment that follows the project's documented setup.
|
||||
|
||||
#### Scenario: Workspace resolves and syncs on Python 3.13
|
||||
- **WHEN** an operator runs `uv python install 3.13` followed by `uv sync --locked --all-packages` in the repository root
|
||||
- **THEN** the sync succeeds and provisions a `.venv` using a Python 3.13 interpreter, with `uv.lock` resolved against that interpreter
|
||||
|
||||
#### Scenario: A Python 3.14 interpreter is rejected
|
||||
- **WHEN** `uv` attempts to resolve or sync the workspace against a Python 3.14 interpreter
|
||||
- **THEN** `uv` reports the interpreter as incompatible with the declared `requires-python` range, rather than silently proceeding
|
||||
|
||||
### Requirement: Container and CI images match the declared Python baseline
|
||||
The system SHALL build its Docker image and Jenkins CI pipeline using a base image whose Python version matches the workspace's declared `requires-python` range, so that containerized and CI environments never diverge from what local development targets.
|
||||
|
||||
#### Scenario: Docker image build uses the supported Python version
|
||||
- **WHEN** the project's `Dockerfile` is built
|
||||
- **THEN** the resulting image's base image is `astral-sh/uv:python3.13-bookworm-slim`
|
||||
|
||||
#### Scenario: CI pipeline uses the supported Python version
|
||||
- **WHEN** the Jenkins pipeline defined in `Jenkinsfile` executes
|
||||
- **THEN** it runs inside the `astral-sh/uv:python3.13-bookworm-slim` image
|
||||
@@ -0,0 +1,36 @@
|
||||
## 1. Update Python version pins
|
||||
|
||||
- [x] 1.1 Update `requires-python` in root `pyproject.toml` from `>=3.14` to `>=3.13,<3.14`
|
||||
- [x] 1.2 Update `requires-python` in `apps/device-host-agent/pyproject.toml` to `>=3.13,<3.14`
|
||||
- [x] 1.3 Update `requires-python` in `apps/cloud-api/pyproject.toml` to `>=3.13,<3.14`
|
||||
- [x] 1.4 Update `requires-python` in `packages/cloud-platform/pyproject.toml` to `>=3.13,<3.14`
|
||||
|
||||
## 2. Update container/CI base images
|
||||
|
||||
- [x] 2.1 Update `Dockerfile:26` base image from `astral-sh/uv:python3.14-bookworm-slim` to `astral-sh/uv:python3.13-bookworm-slim`
|
||||
- [x] 2.2 Update `Jenkinsfile:58` image reference from `astral-sh/uv:python3.14-bookworm-slim` to `astral-sh/uv:python3.13-bookworm-slim`
|
||||
- [x] 2.3 Grep the repo for any other `python3.14`/`3.14` references tied to the toolchain (excluding this change's own `openspec/changes/` artifacts and historical `openspec/changes/archive/` records) and update or confirm each is out of scope
|
||||
|
||||
## 3. Regenerate the lockfile and provision the environment
|
||||
|
||||
- [x] 3.1 `uv python install 3.13`
|
||||
- [x] 3.2 `uv lock` to regenerate `uv.lock` against Python 3.13; confirm the resolution completes without conflict errors
|
||||
- [x] 3.3 `uv sync --locked --all-packages` to provision a fresh `.venv`; confirm it uses the 3.13 interpreter (`uv run --package device-agent-runtime python --version`)
|
||||
- [x] 3.4 Confirm `paddlepaddle` is now installable against the regenerated lock/environment (`uv pip install paddlepaddle` succeeds and `python -c "import paddle"` works) — manual, not added to `pyproject.toml`/`uv.lock`, per design.md Non-Goals
|
||||
|
||||
## 4. Verify no Python-3.14-only usage breaks under 3.13
|
||||
|
||||
- [x] 4.1 Run the full non-integration suite against the 3.13 environment: `uv run --all-packages pytest -m "not integration"`; fix any failures caused by the interpreter downgrade (none expected per design.md D4) — 543 passed. Note: collection was initially blocked by pre-existing Python-2-style `except X, Y:` syntax errors (7 occurrences across `runtime/task.py`, `packages/cloud-platform/cloud/sql_repository.py`, `packages/cloud-platform/cloud/internal_api/api.py`), introduced by commit `22d37ca9` (2026-07-13) unrelated to this change's scope. Fixed as a drive-by (parenthesized the tuples) per user direction, since they blocked verification on any Python version.
|
||||
- [x] 4.2 Run `uv run --all-packages python -m compileall .` (or equivalent) across the workspace to catch any syntax-level incompatibility beyond what pytest collection would exercise — clean, no errors (scoped to project source dirs, excluding `.venv`)
|
||||
- [x] 4.3 Ruff check/format on any files touched by this change — `uvx ruff check` all checks passed; `uvx ruff format --check` 3 files already formatted (ruff isn't a project dependency, run ephemerally via `uvx`)
|
||||
|
||||
## 5. Update documentation
|
||||
|
||||
- [x] 5.1 Update `docs/MACOS_IPHONE_SETUP.md` §4.2 to reflect the Python 3.13 baseline and remove/replace the now-obsolete "do not downgrade to 3.13 ad hoc" warning (lines ~156-158) with guidance that 3.13 is now the supported version
|
||||
- [x] 5.2 Sweep `docs/MACOS_IPHONE_SETUP.md` and any other docs for stray `3.14` references introduced when the project originally targeted 3.14, and correct them to `3.13` — only remaining `3.14` mentions are the intentional upper-bound pin and the paddlepaddle-wheel-availability explanation
|
||||
|
||||
## 6. Final validation
|
||||
|
||||
- [x] 6.1 `git diff --check` (no whitespace errors) across all changed files — clean
|
||||
- [x] 6.2 `openspec validate downgrade-python-3-13-paddleocr --strict` — valid
|
||||
- [x] 6.3 Confirm all four `pyproject.toml` files and `Dockerfile`/`Jenkinsfile` agree on the same Python version, and `uv.lock` is committed alongside them — all agree on 3.13
|
||||
Reference in New Issue
Block a user