CI image PYTHONPATH shadows rev-pinned pre-commit hook clones #970

Closed
opened 2026-08-07 20:03:17 +00:00 by coilyco-ops · 1 comment
Member

Summary

The agentic-os:release runner image sets PYTHONPATH=/opt/agentic-os/python. That entry precedes a virtualenv's site-packages on sys.path, so every language: python hook from this repo imports the image's agentic_os, not the rev-pinned clone pre-commit installed into the hook venv.

The effect: a consumer repo's rev: pin in .pre-commit-config.yaml is silently ignored inside CI. Consumers run whatever validator version the image happens to carry.

Evidence

Inside forgejo.coilysiren.me/coilyco-flight-deck/agentic-os:release:

PYTHONPATH=/opt/agentic-os/python
sys.path[:3] == ['', '/opt/agentic-os/python', '/usr/lib/python312.zip']

Reproduced against coilyco-bridge/agentic-os-xxx, which pins rev: v0.206.0.

  • The pinned clone pre-commit created (HEAD 156ddbab, tag v0.206.0) defines TRIFECTA_PATHS = frozenset({"docs/FEATURES.md"}), so docs/FEATURES.md rides TRIFECTA_MAX_CHARS = 12_500.
  • /opt/agentic-os/python/agentic_os/pre_commit/check_documentation_layout.py has no TRIFECTA_PATHS and instead applies FEATURES_MAX_LINES = 80 / FEATURES_MAX_CHARS = 4_000.
  • The hook failed in CI with docs/FEATURES.md: 4320 chars exceeds the 4000-char cap. Only the /opt copy produces that number, which is what proves the shadowing rather than merely suggesting it.

The same run passed on a developer laptop with a warm pre-commit cache, because there no PYTHONPATH shadows the pinned clone. So the two surfaces disagree about which validator version is authoritative, and the laptop is the one honoring the pin.

Why it matters

  • A pinned rev: is the consumer's contract with this repo. Right now that contract holds locally and breaks in CI.
  • Local-passes / CI-fails is exactly the split this suite exists to prevent, and it is hard to diagnose from CI output alone: the failing message cites a cap that does not exist in the pinned source.
  • Tightening a cap on main immediately breaks every consumer's CI regardless of their pin, with no upgrade step on their side.

Suggested direction

Scope PYTHONPATH to the surfaces that need the baked agentic_os (the aos CLI entry points) rather than exporting it image-wide, or strip it for hook execution so the venv's installed copy wins. Not proposing a specific patch here since the image graph is owned by this repo.

Notes

Unrelated but found while chasing CI logs for the same investigation: aosguard ops actions logs targets Forgejo 16 routes (/actions/runs/{id}/jobs, /actions/jobs/{id}/logs). The server runs Forgejo 15.0.2+gitea-1.22.0, whose swagger exposes neither, so the verb returns missing_run: HTTP 404 for every repo. ops actions runs and ops actions tasks work, since /actions/runs and /actions/tasks do exist. Job logs are currently unreachable via the API. Worth its own issue if that surface is expected to work.

Context

Surfaced from coilyco-bridge/agentic-os-xxx, red on every push since 66fc73d. That repo is now green via da6c9db, which trims docs/FEATURES.md to 3891 chars so it satisfies both the pinned and the shipped caps. That is a workaround at the consumer, not a fix for the shadowing.

## Summary The `agentic-os:release` runner image sets `PYTHONPATH=/opt/agentic-os/python`. That entry precedes a virtualenv's `site-packages` on `sys.path`, so every `language: python` hook from this repo imports the **image's** `agentic_os`, not the rev-pinned clone pre-commit installed into the hook venv. The effect: a consumer repo's `rev:` pin in `.pre-commit-config.yaml` is silently ignored inside CI. Consumers run whatever validator version the image happens to carry. ## Evidence Inside `forgejo.coilysiren.me/coilyco-flight-deck/agentic-os:release`: ``` PYTHONPATH=/opt/agentic-os/python sys.path[:3] == ['', '/opt/agentic-os/python', '/usr/lib/python312.zip'] ``` Reproduced against `coilyco-bridge/agentic-os-xxx`, which pins `rev: v0.206.0`. * The pinned clone pre-commit created (`HEAD 156ddbab`, tag `v0.206.0`) defines `TRIFECTA_PATHS = frozenset({"docs/FEATURES.md"})`, so `docs/FEATURES.md` rides `TRIFECTA_MAX_CHARS = 12_500`. * `/opt/agentic-os/python/agentic_os/pre_commit/check_documentation_layout.py` has no `TRIFECTA_PATHS` and instead applies `FEATURES_MAX_LINES = 80` / `FEATURES_MAX_CHARS = 4_000`. * The hook failed in CI with `docs/FEATURES.md: 4320 chars exceeds the 4000-char cap`. Only the `/opt` copy produces that number, which is what proves the shadowing rather than merely suggesting it. The same run passed on a developer laptop with a warm pre-commit cache, because there no `PYTHONPATH` shadows the pinned clone. So the two surfaces disagree about which validator version is authoritative, and the laptop is the one honoring the pin. ## Why it matters * A pinned `rev:` is the consumer's contract with this repo. Right now that contract holds locally and breaks in CI. * Local-passes / CI-fails is exactly the split this suite exists to prevent, and it is hard to diagnose from CI output alone: the failing message cites a cap that does not exist in the pinned source. * Tightening a cap on `main` immediately breaks every consumer's CI regardless of their pin, with no upgrade step on their side. ## Suggested direction Scope `PYTHONPATH` to the surfaces that need the baked `agentic_os` (the `aos` CLI entry points) rather than exporting it image-wide, or strip it for hook execution so the venv's installed copy wins. Not proposing a specific patch here since the image graph is owned by this repo. ## Notes Unrelated but found while chasing CI logs for the same investigation: `aosguard ops actions logs` targets Forgejo 16 routes (`/actions/runs/{id}/jobs`, `/actions/jobs/{id}/logs`). The server runs Forgejo `15.0.2+gitea-1.22.0`, whose swagger exposes neither, so the verb returns `missing_run: HTTP 404` for every repo. `ops actions runs` and `ops actions tasks` work, since `/actions/runs` and `/actions/tasks` do exist. Job logs are currently unreachable via the API. Worth its own issue if that surface is expected to work. ## Context Surfaced from `coilyco-bridge/agentic-os-xxx`, red on every push since `66fc73d`. That repo is now green via `da6c9db`, which trims `docs/FEATURES.md` to 3891 chars so it satisfies both the pinned and the shipped caps. That is a workaround at the consumer, not a fix for the shadowing.
Author
Member

Closed by 479924cf, which fixes the shared root cause. The full writeup, including the behavior regression and the open verification step, is on #771.

Closed by `479924cf`, which fixes the shared root cause. The full writeup, including the behavior regression and the open verification step, is on #771.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-flight-deck/agentic-os#970
No description provided.