Skip to content

ci: production and CI dependency sets are hand-mirrored, and drift is silent #14551

Closed

Description

@mrveiss

Summary

Dependencies are declared twice, in two files that must be kept in sync by hand:

  • autobot-backend/requirements.txt — what production installs
  • requirements-ci/*.txt — what CI installs (setup-python-suite runs pip install -r requirements-ci.txt; it never installs the backend's own requirements file)

A package declared in one and not the other produces no error. Production-only means the tests never exercise it; CI-only means it passes in CI and is missing at runtime.

Evidence

pytesseract was declared in autobot-backend/requirements.txt by #13885 and was still absent from CI when #13896 landed. Every end-to-end OCR test had been skipping the whole time, and the suite was green throughout. The gap surfaced only because #13896 added an explicit provisioning assertion:

AssertionError: OCR toolchain missing on the CI runner: pytesseract is not installed.

The split is deliberate and documented (#1655, role-based grouping to contain version conflicts), and the files themselves show the manual sync:

requirements-ci/ai-ml.txt:9:  # Mirrors autobot-backend/requirements.txt:42.
requirements-ci/utilities.txt:10: apscheduler>=3.11.3,<4.0.0   # production dep (autobot-backend/requirements.txt)

That second comment goes on to describe the same class of latent failure — "Errors nothing today only because lifespan.py imports that module inside a function — same latent shape as croniter (#13351)". So this has bitten before.

What is not being proposed

Merging the two files. The role-based split exists for a reason and CI legitimately omits heavy production deps (torch arrives separately, per #13316). The problem is not that they differ — it is that they differ silently.

Scope

  • A guard that compares the two sets and reports packages present in production but absent from CI
  • An explicit, documented allowlist for the deliberate omissions (torch, GPU-only, anything CI genuinely should not install) — so the diff is expected to be empty and any new entry is a decision, not an oversight
  • Run it in code-quality, where the other convention checks live
  • Seed the allowlist from today's actual diff, only-ever-shrinking, in the style of sys_modules_leak_baseline.txt and extension_import_baseline.txt

Why it is worth the guard

The failure mode is invisible by construction: an optional import degrades to a message at runtime and to a skipif in tests, so the missing package produces a green suite in both places. That is the same blindness behind #13885 and, differently, #14550.

Related

Activity

  1. mrveiss commented on Aug 21, 2026

    @mrveiss
    OwnerAuthor

    Delivered by PR #14578, squash-merged as 1d8352bcd and verified in origin/Dev_new_gui.

    Measured, not estimated: 46/100 packages mirrored — 100 declared in production, 69 in the CI mirror, 55 missing. I re-derived that independently and the checked-in baseline matched my own tree walk exactly.

    Nine baseline rationales were factually wrong, and that mattered more than the count. Each claimed "no CI-scoped test exercises this library" while a live pytest.importorskip/find_spec gate was silently skipping — scikit-learn, ldap3, weasyprint, faiss-cpu, datasketch, tree-sitter-python, trafilatura, yt-dlp, ddgs. Applying the same method to autobot_shared/ surfaced two more: bcrypt and pydantic-settings, both unconditionally imported and never installed by CI. All eleven were mirrored rather than better-justified, taking the baseline 54 → 44 and matching 46/100 → 56/100.

    A rationale that overstates a gap is as misleading as one that hides it, so correcting opencv-python-headless (satisfied under a differently-named package, not missing) was part of the same discipline.

    pytesseract was deliberately not fixed here — it collided with #14510 adding the same package to a different requirements file. Allowlisted with a pointer, self-correcting: the audit forces the entry out once either PR lands it.

    The guard runs --audit inside code-quality, which is required. Both empty-resolution branches now fail loudly rather than reporting clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions