From 35a40933421e07f9c3e2b6fb657a41e953dda4b7 Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Sat, 5 Sep 2026 22:16:33 +0200 Subject: [PATCH 1/3] deps: track stable internal releases and verify supported Python Co-authored-by: Koru Agent --- .github/dependabot.yml | 31 ++++++++++ .github/internal-dependencies.json | 35 ++++++++++++ .../internal-dependency-freshness.yml | 36 ++++++++++++ .github/workflows/test-locked.yml | 30 ++++++++++ README.md | 4 ++ docs/dependencies.md | 28 ++++++++++ imgl/capture.py | 4 +- imgl/export/vql_adapter.py | 4 +- pyproject.toml | 11 +++- uv.lock | 56 ++++++++++--------- 10 files changed, 209 insertions(+), 30 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/internal-dependencies.json create mode 100644 .github/workflows/internal-dependency-freshness.yml create mode 100644 .github/workflows/test-locked.yml create mode 100644 docs/dependencies.md diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..755c1bf --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,31 @@ +version: 2 +updates: +- package-ecosystem: uv + directory: / + schedule: + interval: cron + cronjob: 42 4 * * * + timezone: Europe/Warsaw + open-pull-requests-limit: 1 + versioning-strategy: increase-if-necessary + allow: + - dependency-name: costs + dependency-type: all + - dependency-name: goal + dependency-type: all + - dependency-name: pfix + dependency-type: all + - dependency-name: clickmd + dependency-type: all + - dependency-name: code2llm + dependency-type: all + groups: + internal-packages: + patterns: + - costs + - goal + - pfix + - clickmd + - code2llm + commit-message: + prefix: deps diff --git a/.github/internal-dependencies.json b/.github/internal-dependencies.json new file mode 100644 index 0000000..ce582b0 --- /dev/null +++ b/.github/internal-dependencies.json @@ -0,0 +1,35 @@ +{ + "schema": "goal.internal-dependencies/v1", + "packages": [ + { + "name": "costs", + "repository": "semcod/costs", + "registry": "pypi", + "versioning": "semver" + }, + { + "name": "goal", + "repository": "semcod/goal", + "registry": "pypi", + "versioning": "semver" + }, + { + "name": "pfix", + "repository": "semcod/pfix", + "registry": "pypi", + "versioning": "semver" + }, + { + "name": "clickmd", + "repository": "semcod/clickmd", + "registry": "pypi", + "versioning": "semver" + }, + { + "name": "code2llm", + "repository": "semcod/code2llm", + "registry": "pypi", + "versioning": "semver" + } + ] +} diff --git a/.github/workflows/internal-dependency-freshness.yml b/.github/workflows/internal-dependency-freshness.yml new file mode 100644 index 0000000..d64bfc8 --- /dev/null +++ b/.github/workflows/internal-dependency-freshness.yml @@ -0,0 +1,36 @@ +name: Internal dependency freshness + +on: + schedule: + - cron: "47 5 * * *" + workflow_dispatch: + pull_request: + paths: + - pyproject.toml + - uv.lock + - .github/internal-dependencies.json + - .github/workflows/internal-dependency-freshness.yml + +permissions: + contents: read + +jobs: + freshness: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 + with: + python-version: "3.12" + - name: Install released checker + run: python -m pip install "goal==2.2.0" + - name: Verify published stable targets + run: goal dependencies --catalog .github/internal-dependencies.json --check > dependency-freshness.json + - name: Retain freshness evidence + if: always() + uses: actions/upload-artifact@v4 + with: + name: dependency-freshness + path: dependency-freshness.json + if-no-files-found: ignore diff --git a/.github/workflows/test-locked.yml b/.github/workflows/test-locked.yml new file mode 100644 index 0000000..b1ca5ad --- /dev/null +++ b/.github/workflows/test-locked.yml @@ -0,0 +1,30 @@ +name: Locked tests + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + +jobs: + test: + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + python-version: ["3.10", "3.13"] + steps: + - uses: actions/checkout@v7 + - uses: actions/setup-python@v7 + with: + python-version: ${{ matrix.python-version }} + - run: python -m pip install uv + - name: Install locked test dependencies + run: uv sync --locked --extra dev --extra web --extra diagnose --python "${{ matrix.python-version }}" + - name: Test supported Python versions + run: uv run --no-sync python -m pytest -q diff --git a/README.md b/README.md index 04fd9e1..9991d77 100644 --- a/README.md +++ b/README.md @@ -362,3 +362,7 @@ Zobacz [TODO.md](TODO.md). ## License Licensed under Apache-2.0. + +## Dependency maintenance + +See [dependency updates and Python tool groups](docs/dependencies.md) for locked tests, daily updates and freshness checks. diff --git a/docs/dependencies.md b/docs/dependencies.md new file mode 100644 index 0000000..8de956b --- /dev/null +++ b/docs/dependencies.md @@ -0,0 +1,28 @@ +# Internal dependency updates + +This repository owns its dependency configuration and this guide. The shared checker is maintained in [semcod/goal](https://github.com/semcod/goal/blob/84f18540d14c24cc8ff5b7f202d2874344779ecc/docs/internal-dependencies.md). Documentation follows the repository ownership principle in [wellmanifest/docs](https://github.com/wellmanifest/docs/blob/f64de5806577769672ebc1730d2e144b4c7671ec/README.md). + +## Python support and tools + +Application Python support remains `>=3.10,<3.14`. Goal is used as a development/release tool; source inspection found no Goal imports or executable invocation in the application Python code. Its old declarations (dev) moved to an `automation` dependency group requiring Python >=3.12. The normal dev/test installation remains usable on the application's minimum Python version. + +```sh +uv sync --locked --extra dev +uv sync --locked --group automation --python 3.12 +``` + +The second command selects an automation environment; use a separate UV_PROJECT_ENVIRONMENT when keeping application and tool environments side by side. `imgl` itself is excluded from the registry catalog when it is the local editable package. + +## Daily updates and verification + +[Dependabot configuration](../.github/dependabot.yml) checks the explicit internal package allowlist daily, including weekends, and groups updates in one PR. It includes transitive dependencies and may widen a manifest constraint when needed. Local or Git sources require separate review. + +[Freshness CI](../.github/workflows/internal-dependency-freshness.yml) compares uv.lock with the highest published stable three-part versions using Goal 2.2.0. It runs daily, manually and on dependency PRs, has read-only repository permissions and retains JSON evidence. Resolver failures and mismatched targets stay visible. A successful audit says nothing about an already installed development or production environment. + +[Locked tests](../.github/workflows/test-locked.yml) run on Python 3.10 and 3.13 before merge. Update creation does not grant merge approval. The `>=` declarations alone do not refresh uv.lock; environments must be synchronized after a tested update is merged. + +## Delivery record + +This change updates the internal packages to the registry targets observed on 2026-09-05, preserves application Python support and adds the scheduled checks above. Test and publication results are recorded in this repository's PR and Actions checks. The ecosystem rollout history is maintained in [costs documentation](https://github.com/semcod/costs/tree/main/docs/dependencies). + +The test configuration exposes the repository-owned MCP adapter source for its execution-permission test. Optional control packages remain optional. Timestamp generation uses `timezone.utc`, which supports the declared Python 3.10 minimum. diff --git a/imgl/capture.py b/imgl/capture.py index f88bd69..411768a 100644 --- a/imgl/capture.py +++ b/imgl/capture.py @@ -6,7 +6,7 @@ import os import shutil import subprocess -from datetime import UTC, datetime +from datetime import datetime, timezone from pathlib import Path @@ -77,7 +77,7 @@ def default_capture_path(out: str | Path | None = None) -> Path: path = Path(out).expanduser() path.parent.mkdir(parents=True, exist_ok=True) return path - ts = datetime.now(UTC).strftime("%Y%m%d_%H%M%S") + ts = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S") path = Path.home() / ".imgl" / "captures" / f"screen_{ts}.png" path.parent.mkdir(parents=True, exist_ok=True) return path diff --git a/imgl/export/vql_adapter.py b/imgl/export/vql_adapter.py index a386704..31d5d77 100644 --- a/imgl/export/vql_adapter.py +++ b/imgl/export/vql_adapter.py @@ -5,7 +5,7 @@ import json import os import sys -from datetime import UTC, datetime +from datetime import datetime, timezone from pathlib import Path from typing import Any @@ -83,7 +83,7 @@ def scene_to_vql( "detect_source": scene.metadata.get("detect_source", ""), "ocr_backend": scene.metadata.get("ocr_backend", ""), "lang": scene.metadata.get("lang", ""), - "analyzed_at": datetime.now(UTC).isoformat(), + "analyzed_at": datetime.now(timezone.utc).isoformat(), } capture = scene.metadata.get("capture") if isinstance(capture, dict) and capture: diff --git a/pyproject.toml b/pyproject.toml index 8cb587b..ba2cca3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,7 +57,6 @@ full = [ ] dev = [ "pytest>=8.0", - "goal>=2.1.0", "costs>=0.1.20", "pfix>=0.1.60", # dev environments should exercise the OCR path @@ -107,3 +106,13 @@ max_commits = 500 # Cost thresholds for badge colors (USD) badge_color_thresholds = { low = 1.0, medium = 5.0, high = 10.0, critical = 50.0 } + +[tool.uv.dependency-groups] +automation = {requires-python = ">=3.12"} + +[dependency-groups] +automation = ["goal>=2.2.0"] + +[tool.pytest.ini_options] +# Test the repository-owned MCP adapter without installing the optional control stack. +pythonpath = ["packages/mcp2imgl/src"] diff --git a/uv.lock b/uv.lock index 690d7b9..a3c9e9b 100644 --- a/uv.lock +++ b/uv.lock @@ -269,7 +269,7 @@ name = "cffi" version = "2.0.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pycparser", marker = "implementation_name != 'PyPy'" }, + { name = "pycparser" }, ] sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } wheels = [ @@ -411,16 +411,16 @@ wheels = [ [[package]] name = "clickmd" -version = "1.1.14" +version = "1.1.15" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "costs" }, { name = "goal" }, { name = "pfix" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/0e/1b/84df87d056991c2fb0789ae47b49d5afb8496f2c45541760e81553d00b43/clickmd-1.1.14.tar.gz", hash = "sha256:a3625777736ba5d3d43f7de8ff81bc01d2a4d77f6c252ce6ea7d55b860279f43", size = 41134, upload-time = "2026-04-08T09:11:28.657Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/12/82b3b80bb2751e0d6c120c1beb11116527cca9322202b5a1924811b58376/clickmd-1.1.15.tar.gz", hash = "sha256:0a2971b952e471c4726bc2f88ed397abd395283c79e4885e435921426493d01c", size = 41145, upload-time = "2026-06-29T07:35:58.128Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/89/29/625bc2004029ce7297d0709e6486447c4a0f0d832c2ddd962cada14d32c7/clickmd-1.1.14-py3-none-any.whl", hash = "sha256:005bbc7cd97d8a58ba25b4fc0018b7970e37b57ee50d53aa33df5f445b4ff46b", size = 45540, upload-time = "2026-04-08T09:11:27.228Z" }, + { url = "https://files.pythonhosted.org/packages/d7/5c/398fafad25e456d86fe8fe7bf9a3873f2077564d42dcdd1426b76d01e915/clickmd-1.1.15-py3-none-any.whl", hash = "sha256:b191c0c26be5ef009ea27a3e88c1c7d633d95a6da2fc737f04f6727481bfeb5e", size = 45514, upload-time = "2026-06-29T07:35:56.53Z" }, ] [[package]] @@ -434,7 +434,7 @@ wheels = [ [[package]] name = "costs" -version = "0.1.51" +version = "0.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anthropic" }, @@ -446,11 +446,12 @@ dependencies = [ { name = "pandas", version = "3.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "python-dotenv" }, { name = "tiktoken" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, { name = "typer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/92/2c/d9f9a9c0acd33bc40788aaeef792fe045efd42368cde2ad00a0e15eeb625/costs-0.1.51.tar.gz", hash = "sha256:727f5f14874c41731e2485cc309ec4cc87c447288c8be4c0ddb38f72391d49cc", size = 30777, upload-time = "2026-05-12T08:33:20.439Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/6f/7f3c72d6d4b5264bd5a3447e18a3b5184bffee143f72c8d023bb759afd1a/costs-0.2.0.tar.gz", hash = "sha256:3782bae859725dae30f697b5f3e5aa5d84e06feadebc5782ae706e21d46437af", size = 44606, upload-time = "2026-09-05T15:49:55.524Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/81/15/4490e3afc8e0e903a984582db06a34ec9feeddf52ef99902d456a2e15da5/costs-0.1.51-py3-none-any.whl", hash = "sha256:15e2ebf518fec04e5883612d96dd2673f56cbeaf58408e448eb0837c01a2dc85", size = 35771, upload-time = "2026-05-12T08:33:19.271Z" }, + { url = "https://files.pythonhosted.org/packages/1d/7e/fc91d9fdc7a1ceb9116daffab27124a54f6e8887c9d59d906df43dcbfa6a/costs-0.2.0-py3-none-any.whl", hash = "sha256:4798b8535cbbcbb354e440ebce91365f17c910414bf5831a0610998ae6e679af", size = 48625, upload-time = "2026-09-05T15:49:54.054Z" }, ] [[package]] @@ -500,7 +501,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -726,7 +727,7 @@ wheels = [ [[package]] name = "goal" -version = "2.1.261" +version = "2.2.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, @@ -736,9 +737,9 @@ dependencies = [ { name = "tomlkit" }, { name = "typer" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/de/27/27f2b2c453b3c0c77d3b3b37f2d5a2a9dfaaec2eee1f90b4fc53b2c7c7d5/goal-2.1.261.tar.gz", hash = "sha256:cc72d7ae9c2f8b6fc86b0aba10c4f723df3d167117b252c23019f5f25d6e9a8d", size = 302506, upload-time = "2026-06-22T13:53:34.882Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/9c/135e3f67a7324c3c49ef4246f5518b59ad90226e62c3d30ae20cba005c1d/goal-2.2.0.tar.gz", hash = "sha256:e9e2c1ac9493dae3b887b16d503f7c1f83d02ddcbdd3c5cf58d44a458bb2662f", size = 399786, upload-time = "2026-09-05T19:41:55.329Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/12/66/a2823f9a67f8ccda8e416991b56a88354f7223eba4943b5f34198de5dbca/goal-2.1.261-py3-none-any.whl", hash = "sha256:75f67d1e502eda2a092c5926448b2c32895525a94e9eec62f12a156e892225d7", size = 290072, upload-time = "2026-06-22T13:53:32.983Z" }, + { url = "https://files.pythonhosted.org/packages/24/69/8a4cf5710683bb777f1f6e4cd44dd3907befe97b94c6ea6e97d4305b4e44/goal-2.2.0-py3-none-any.whl", hash = "sha256:0d8f93aa317ac92a66b64b797e210a5d66044ce8db2cb05b012b03d42aced95e", size = 349709, upload-time = "2026-09-05T19:41:53.615Z" }, ] [[package]] @@ -882,7 +883,6 @@ capture = [ ] dev = [ { name = "costs" }, - { name = "goal" }, { name = "pfix" }, { name = "pytesseract" }, { name = "pytest" }, @@ -895,7 +895,6 @@ diagnose = [ full = [ { name = "costs" }, { name = "fastapi" }, - { name = "goal" }, { name = "litellm" }, { name = "mss" }, { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, @@ -919,11 +918,15 @@ web = [ { name = "uvicorn", extra = ["standard"] }, ] +[package.dev-dependencies] +automation = [ + { name = "goal", marker = "python_full_version >= '3.12'" }, +] + [package.metadata] requires-dist = [ { name = "costs", marker = "extra == 'dev'", specifier = ">=0.1.20" }, { name = "fastapi", marker = "extra == 'web'", specifier = ">=0.110" }, - { name = "goal", marker = "extra == 'dev'", specifier = ">=2.1.0" }, { name = "imgl", extras = ["capture", "diagnose", "dev", "llm", "ocr", "web"], marker = "extra == 'full'" }, { name = "imgl", extras = ["ocr"], marker = "extra == 'dev'" }, { name = "litellm", marker = "extra == 'llm'", specifier = ">=1.30" }, @@ -939,6 +942,9 @@ requires-dist = [ ] provides-extras = ["capture", "ocr", "diagnose", "llm", "web", "full", "dev"] +[package.metadata.requires-dev] +automation = [{ name = "goal", marker = "python_full_version >= '3.12'", specifier = ">=2.2.0" }] + [[package]] name = "importlib-metadata" version = "8.9.0" @@ -1646,10 +1652,10 @@ resolution-markers = [ "python_full_version < '3.11'", ] dependencies = [ - { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "python-dateutil", marker = "python_full_version < '3.11'" }, - { name = "pytz", marker = "python_full_version < '3.11'" }, - { name = "tzdata", marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } }, + { name = "python-dateutil" }, + { name = "pytz" }, + { name = "tzdata" }, ] sdist = { url = "https://files.pythonhosted.org/packages/33/01/d40b85317f86cf08d853a4f495195c73815fdf205eef3993821720274518/pandas-2.3.3.tar.gz", hash = "sha256:e05e1af93b977f7eafa636d043f9f94c7ee3ac81af99c13508215942e64c993b", size = 4495223, upload-time = "2025-09-29T23:34:51.853Z" } wheels = [ @@ -1702,10 +1708,10 @@ resolution-markers = [ "python_full_version == '3.11.*' and sys_platform != 'emscripten' and sys_platform != 'win32'", ] dependencies = [ - { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, { name = "numpy", version = "2.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "python-dateutil", marker = "python_full_version >= '3.11'" }, - { name = "tzdata", marker = "(python_full_version >= '3.11' and sys_platform == 'emscripten') or (python_full_version >= '3.11' and sys_platform == 'win32')" }, + { name = "python-dateutil" }, + { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f8/87/4341c6252d1c47b08768c3d25ac487362bf403f0313ddae4a2a26c9b1b4c/pandas-3.0.3.tar.gz", hash = "sha256:696a4a00a2a2a35d4e5deb3fc946641b96c944f02230e4f76137fe35d806c4fc", size = 4651414, upload-time = "2026-05-11T18:54:29.21Z" } wheels = [ @@ -1774,7 +1780,7 @@ name = "pexpect" version = "4.9.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "ptyprocess", marker = "python_full_version < '3.11' or sys_platform != 'win32'" }, + { name = "ptyprocess" }, ] sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } wheels = [ @@ -1783,7 +1789,7 @@ wheels = [ [[package]] name = "pfix" -version = "0.1.73" +version = "0.1.79" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "litellm" }, @@ -1792,9 +1798,9 @@ dependencies = [ { name = "python-dotenv" }, { name = "rich" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/04/76/982888ddbfd8398ac2c1a04bfe16caddfa4091f84af347ee878cdb5e5cf9/pfix-0.1.73.tar.gz", hash = "sha256:f1c55a01b738b5c6465815ad9d61371d6e2a1a6074199fa0174309996de7310c", size = 2837935, upload-time = "2026-05-12T08:34:08.486Z" } +sdist = { url = "https://files.pythonhosted.org/packages/ae/7e/252be5e1d55321b947013010f45b02d781de87e25b9a524c0ee72c1ad3c0/pfix-0.1.79.tar.gz", hash = "sha256:6bc4c572e22e0f0d952bc5e2df78f52f8f999cab64e22138b097b2eab4d83092", size = 2845663, upload-time = "2026-07-05T17:00:57.331Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/4f/abe3e6992a7df0237fc75d000ad950da8cf20d1c767415e4605b31fa143a/pfix-0.1.73-py3-none-any.whl", hash = "sha256:0e0f022c0277b8c9633a2be2d2def366c856170953d2f9ff9acf4a473c1c6bf2", size = 149278, upload-time = "2026-05-12T08:34:04.109Z" }, + { url = "https://files.pythonhosted.org/packages/39/bf/548982294e795d79003680b2214c7f5dd00ca4b0ea856064bf9cb6869ba7/pfix-0.1.79-py3-none-any.whl", hash = "sha256:bb7ab83b99c0bfbaae5e6e95cb801a27d4fd68749485600fdfe49dad00607461", size = 151754, upload-time = "2026-07-05T17:00:52.816Z" }, ] [[package]] From 913723129e080213926ca35a8f00848a3a6fe1db Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Sat, 5 Sep 2026 22:19:49 +0200 Subject: [PATCH 2/3] ci: install Tesseract for OCR integration tests Co-authored-by: Koru Agent --- .github/workflows/test-locked.yml | 4 ++++ docs/dependencies.md | 2 ++ 2 files changed, 6 insertions(+) diff --git a/.github/workflows/test-locked.yml b/.github/workflows/test-locked.yml index b1ca5ad..573f244 100644 --- a/.github/workflows/test-locked.yml +++ b/.github/workflows/test-locked.yml @@ -24,6 +24,10 @@ jobs: with: python-version: ${{ matrix.python-version }} - run: python -m pip install uv + - name: Install OCR runtime for integration tests + run: | + sudo apt-get update + sudo apt-get install --no-install-recommends -y tesseract-ocr tesseract-ocr-eng tesseract-ocr-pol - name: Install locked test dependencies run: uv sync --locked --extra dev --extra web --extra diagnose --python "${{ matrix.python-version }}" - name: Test supported Python versions diff --git a/docs/dependencies.md b/docs/dependencies.md index 8de956b..5f9fdb9 100644 --- a/docs/dependencies.md +++ b/docs/dependencies.md @@ -26,3 +26,5 @@ The second command selects an automation environment; use a separate UV_PROJECT_ This change updates the internal packages to the registry targets observed on 2026-09-05, preserves application Python support and adds the scheduled checks above. Test and publication results are recorded in this repository's PR and Actions checks. The ecosystem rollout history is maintained in [costs documentation](https://github.com/semcod/costs/tree/main/docs/dependencies). The test configuration exposes the repository-owned MCP adapter source for its execution-permission test. Optional control packages remain optional. Timestamp generation uses `timezone.utc`, which supports the declared Python 3.10 minimum. + +The test runner installs the system Tesseract executable and English/Polish language data before the OCR/web integration tests. The Python `ocr` extra supplies the wrapper only. On Debian/Ubuntu, install `tesseract-ocr tesseract-ocr-eng tesseract-ocr-pol` before running this suite locally. From 52248a1c0b22620cec812a709b67a96bbf17bf08 Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Sat, 5 Sep 2026 22:22:09 +0200 Subject: [PATCH 3/3] ci: expose the required test gate for the Python matrix Co-authored-by: Koru Agent --- .github/workflows/test-locked.yml | 15 ++++++++++++++- docs/dependencies.md | 2 ++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-locked.yml b/.github/workflows/test-locked.yml index 573f244..8d9b300 100644 --- a/.github/workflows/test-locked.yml +++ b/.github/workflows/test-locked.yml @@ -11,7 +11,8 @@ permissions: contents: read jobs: - test: + supported_python: + name: test (${{ matrix.python-version }}) runs-on: ubuntu-latest timeout-minutes: 15 strategy: @@ -32,3 +33,15 @@ jobs: run: uv sync --locked --extra dev --extra web --extra diagnose --python "${{ matrix.python-version }}" - name: Test supported Python versions run: uv run --no-sync python -m pytest -q + + test: + name: test + needs: supported_python + if: always() + runs-on: ubuntu-latest + timeout-minutes: 2 + steps: + - name: Require every supported Python job to pass + env: + MATRIX_RESULT: ${{ needs.supported_python.result }} + run: test "$MATRIX_RESULT" = success diff --git a/docs/dependencies.md b/docs/dependencies.md index 5f9fdb9..e984849 100644 --- a/docs/dependencies.md +++ b/docs/dependencies.md @@ -28,3 +28,5 @@ This change updates the internal packages to the registry targets observed on 20 The test configuration exposes the repository-owned MCP adapter source for its execution-permission test. Optional control packages remain optional. Timestamp generation uses `timezone.utc`, which supports the declared Python 3.10 minimum. The test runner installs the system Tesseract executable and English/Polish language data before the OCR/web integration tests. The Python `ocr` extra supplies the wrapper only. On Debian/Ubuntu, install `tesseract-ocr tesseract-ocr-eng tesseract-ocr-pol` before running this suite locally. + +The `main-supervised-autonomy` GitHub ruleset requires a successful `test` check and an independent approval of the latest push. The aggregate `test` job fails unless every Python matrix job succeeds. Merge uses the repository-required merge commit method after review.