Skip to content

ci: enforce stub freshness in CI, fix existing stub drift#2912

Merged
michaeldwan merged 5 commits intomainfrom
md/ci-stub-check
Apr 8, 2026
Merged

ci: enforce stub freshness in CI, fix existing stub drift#2912
michaeldwan merged 5 commits intomainfrom
md/ci-stub-check

Conversation

@michaeldwan
Copy link
Copy Markdown
Member

@michaeldwan michaeldwan commented Apr 7, 2026

Coglet's Python type stubs (.pyi files generated by pyo3-stub-gen from Rust source) can drift when someone changes Rust structs or docstrings and forgets to run mise run generate:stubs. The stub:check mise task already existed for local use but wasn't enforced in CI -- so the stubs have been quietly out of date since #2829.

This PR does two things: prevents future drift and fixes the existing drift.

Preventing drift: Adds a check-stubs CI job that regenerates stubs and diffs against HEAD, same pattern as check-llm-docs and docs:cli:check. Uses mise run --force to bypass the sources/outputs mtime freshness check, which would otherwise skip regeneration in CI's fresh checkout where all files share the same timestamp.

Fixing existing drift:

The generate:stubs mise task and stub:check already exist but weren't
enforced in CI, so .pyi stubs could drift when Rust source changed.

Adds a check-stubs job that runs `mise run --force stub:check` on Rust
changes, using --force to bypass sources/outputs mtime freshness (which
would skip regeneration in CI's fresh checkout).
Stubs drifted after the BuildInfo.dirty field was added in #2829 and
docstring updates in recent PRs. Regenerated with `mise run generate:stubs`.
@michaeldwan michaeldwan requested a review from a team as a code owner April 7, 2026 17:41
Copy link
Copy Markdown

@ask-bonk ask-bonk bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One issue found: a type annotation regression in the regenerated stubs.

@property
def metrics(self) -> MetricRecorder:
r"""
The metric recorder for this prediction.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type annotation regression: context was previously dict[builtins.str, builtins.str] but is now just dict. This reduces type safety and may break downstream type checking.\n\nsuggestion\n @property\n def context(self) -> dict[builtins.str, builtins.str]:\n

@ask-bonk
Copy link
Copy Markdown

ask-bonk bot commented Apr 7, 2026

Posted a review on PR #2912 identifying a type annotation regression where context property changed from dict[builtins.str, builtins.str] to dict in the regenerated stubs.

github run

stub_gen is a PyO3 binary that dynamically links libpython. setup-uv
installs Python to a non-standard path, so the shared library isn't on
LD_LIBRARY_PATH by default. Query sysconfig for the correct LIBDIR.
Copy link
Copy Markdown

@ask-bonk ask-bonk bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR adds valuable CI enforcement for stub freshness. The check-stubs job implementation follows the established patterns used by check-llm-docs and docs:cli:check.

However, there's one issue:

Type annotation regression in generated stubs

The context property in Scope class has lost its generic type parameters. The regenerated stub shows -> dict but the docstring (and previous version) specifies dict[str, str]. This reduces type safety for downstream users.

This appears to be a limitation of pyo3-stub-gen 0.20, which doesn't preserve generic parameters for Py<PyDict>. Consider:

  1. Investigating if newer pyo3-stub-gen versions handle this better
  2. Adding post-processing in stub_gen.rs to fix specific regressions
  3. Accepting this as a known limitation for now (the docstring is correct)

@ask-bonk
Copy link
Copy Markdown

ask-bonk bot commented Apr 7, 2026

I've reviewed PR #2912 and posted my feedback. The PR adds valuable CI enforcement for Python stub freshness, but there's a type annotation regression in the regenerated stubs where context property lost its generic type parameters (dict[builtins.str, builtins.str]dict). This appears to be a pyo3-stub-gen limitation rather than a bug in the PR itself.

github run

Regression from #2853: the context property returns Py<PyDict> which
pyo3-stub-gen infers as bare `dict`. Add an override_return_type
annotation so the generated stub preserves the intended dict[str, str]
contract.
@ask-bonk
Copy link
Copy Markdown

ask-bonk bot commented Apr 7, 2026

All files look correct. The type annotation regression has been properly fixed using the #[gen_stub(override_return_type(...))] attribute on line 240 of metric_scope.rs. The CI workflow is properly configured following established patterns.

LGTM

github run

@michaeldwan michaeldwan changed the title ci: enforce stub freshness in CI ci: enforce stub freshness in CI, fix existing stub drift Apr 7, 2026
stub_gen needs libpython3.x.so at runtime (PyO3 auto-initialize).
setup-uv's python-build-standalone is statically linked and doesn't
ship the .so, causing 'cannot open shared object file' at runtime.
@ask-bonk
Copy link
Copy Markdown

ask-bonk bot commented Apr 7, 2026

LGTM

github run

@michaeldwan michaeldwan enabled auto-merge April 7, 2026 20:48
@michaeldwan michaeldwan added this pull request to the merge queue Apr 8, 2026
Merged via the queue into main with commit 93c5569 Apr 8, 2026
74 of 76 checks passed
@michaeldwan michaeldwan deleted the md/ci-stub-check branch April 8, 2026 16:16
markphelps added a commit that referenced this pull request Apr 8, 2026
…icate/cog into mphelps/push-phase-progress

* 'mphelps/push-phase-progress' of https://github.com/replicate/cog: (95 commits)
  feat: add metric name validation (#2911)
  Rename `cog run` to `cog exec` (#2916)
  chore(deps): bump github.com/google/go-containerregistry (#2884)
  fix: replace removed libgl1-mesa-glx in tensorflow integration test (#2914)
  ci: enforce stub freshness in CI, fix existing stub drift (#2912)
  feat: add schema-compare command to test harness (#2891)
  chore(deps): bump uuid from 1.22.0 to 1.23.0 in /crates (#2887)
  chore(deps): bump github.com/hashicorp/go-version from 1.7.0 to 1.9.0 (#2909)
  chore(deps): bump insta from 1.46.3 to 1.47.2 in /crates (#2908)
  fix: support list[X] | None inputs + integration tests for PEP 604 union File/Path coercion (#2882)
  ci: exclude Dependabot PRs from auto-code review (#2910)
  chore(deps): bump actions/checkout from 4 to 6 (#2904)
  chore(deps): bump github.com/testcontainers/testcontainers-go/modules/registry (#2886)
  fix: metrics bugs in coglet prediction server (#2896)
  Bump version to 0.17.2 (#2903)
  fix(coglet): propagate metric scope to async event loop thread (#2902)
  chore: remove unnecessary nolint directive in test (#2803)
  feat(coglet): add Sentry error reporting for infrastructure errors (#2865)
  fix: homebrew cask postflight xattr references wrong binary name (#2899)
  fix: include custom metrics in cog predict --json output (#2897)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants