Skip to content

End-user runtime installs use floor pins while CI uses exact pins (dev/CI/prod drift) #59

@ar7casper

Description

@ar7casper

Problem

The runtime installOpenant in apps/openant-cli/internal/python/runtime.go runs:

exec.Command(pythonPath, "-m", "pip", "install", "-e", corePath)

That resolves dependencies from pyproject.toml's [project.dependencies], which uses floor pins (anthropic>=0.40.0, pydantic>=2.0.0, etc.). pip will pull whatever the latest version on PyPI is that satisfies the floor.

CI (.github/workflows/test.yaml) runs a different command:

pip install -r requirements.txt && pip install ".[dev]"

Where libs/openant-core/requirements.txt has exact pins (anthropic==0.75.0, pydantic==2.12.5, etc.).

What this means in practice

  • A contributor running tests locally or in CI uses anthropic==0.75.0.
  • An end user who runs openant scan today might get anthropic==0.78.0 — whatever PyPI currently serves as the latest matching >=0.40.0.
  • Three months from now, a fresh openant scan could pull anthropic==1.2.0 if upstream has had releases.

This is a recipe for "works on my machine" / "works in CI" / "breaks for users" gaps that are hard to reproduce. SDK constructor changes (cf. the AuthenticationError(message=, response=, body=) shift in #56), default-model swaps, response-shape changes — any of these can land for end users without ever being exercised in CI.

Where this came up

While reviewing #36 (auto-detect dep changes and reinstall), the question came up of whether the staleness check should also hash requirements.txt. The answer was no — installOpenant doesn't read requirements.txt, so hashing it would trigger reinstalls that don't actually apply the new pins, making the UX worse. PR #36's pyproject.toml-only scope is correct given today's installOpenant behavior. The divergence itself is a separate, pre-existing problem.

Proposed fix

Make installOpenant mirror what CI does:

  1. pip install -r requirements.txt first (apply exact pins).
  2. Then pip install -e . (install the package itself).
  3. Have feat: auto-detect dependency changes and reinstall openant #36's CheckDepsStale hash both files so a change to either triggers reinstall.

That makes end-user installs deterministic and matches what's exercised in CI.

Open questions

  • Keep the dual-file system (pyproject.toml floor + requirements.txt lock), or move to a single source of truth (e.g., generate requirements.txt from pyproject.toml via pip-compile or uv lock)?
  • The .[dev] extras (pytest, etc.) in CI — survive into end-user installs, or stay CI-only?

Why this isn't in #36

PR #36's scope was "auto-detect dep changes". Changing how installOpenant behaves is a behavior change that deserves its own review. Filing this so it doesn't get lost.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestpythonPull requests that update python code

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions