Skip to content

fix(ci): restore green CI — enlace floor 0.1.21 + install the dev extra - #1

Merged
thorwhalen merged 4 commits into
mainfrom
claude/rollout-ci-fix
Aug 4, 2026
Merged

fix(ci): restore green CI — enlace floor 0.1.21 + install the dev extra#1
thorwhalen merged 4 commits into
mainfrom
claude/rollout-ci-fix

Conversation

@thorwhalen

Copy link
Copy Markdown
Member

Gets ci.yml green again. It had been red on main since 2026-05-28, and the newest commit on main is a CI push-back carrying a workflow-skip marker, so no newer run had fired to reveal that a second, independent breakage had since landed on top of the first.

Root cause — two independent failures, both in the Run Tests step

1. Dependency floor one release too low (the original 2026-05-28 red)

Run 26588121918, job ci / Validation (3.12), step Run Tests:

FAILED enlace_docker/tests/test_diagnose.py::test_runs_via_diagnose_app_entry_point
E   AssertionError: assert 'docker_missing_dockerfile' in
        {<Category.MISSING_ENTRY_POINT: 'missing_entry_point'>}
1 failed, 52 passed, 2 skipped

That job resolved enlace==0.1.20. The enlace.diagnosers extension point this package registers against — enlace.diagnose.iter_diagnosers, which diagnose_app calls — first shipped in enlace 0.1.21 (enlace commit 191b00b, "Phase 3 extension points — port-allocation flag + diagnoser hook"; the 0.1.20 version bump 2eb2d0b precedes it, and enlace/diagnose.py at 0.1.20 contains zero references to the hook). The declared floor here was enlace>=0.1.20, so a clean resolve could legitimately pick a release in which the registered diagnoser is never invoked. Developer machines masked this because they carry a newer enlace.

Reproduced in a clean venv: with enlace==0.1.201 failed, 52 passed, 2 skipped; with enlace==0.1.2153 passed, 2 skipped.

Today's resolver picks 0.1.27, so this specific assertion would no longer fire — but the declared floor was still wrong, and a wrong floor is a real, reproducible packaging bug for anyone installing from PyPI with an older enlace pinned.

2. dev extra no longer installed by CI (what was actually red today)

The first branch push exposed this. Run 30858824314, jobs Validation (3.10) and Windows Tests:

plugins: anyio-4.14.2                       <- pytest-asyncio absent
PytestConfigWarning: Unknown config option: asyncio_mode
Failed: async def functions are not natively supported.
11 failed, 42 passed, 2 skipped

and in the install step:

if [ -n "" ]; then uv pip install -e ".[]"; else uv pip install -e .; fi

wads' reusable workflow now feeds the install step from [tool.wads.ci.install].extras, whose default is "". Older runs of this repo got the dev extra only by accident, from the install-deps-uv action's own default: "dev", which the workflow now always overrides with the resolved (empty) config value — compare the 2026-05-28 log, which shows if [ -n "dev" ]. pytest-asyncio is declared only in the dev extra and asyncio_mode = "auto" depends on it, so every async def test failed.

The sibling enlace and enlace_auth repos already carry the [tool.wads.ci.install] extras = "dev" line for exactly this reason.

What changed

Commit Change
56526da enlace>=0.1.20enlace>=0.1.21, with a comment recording why, plus one stale in-file version reference
e98f0fc testpaths ["enlace_docker/tests"]["enlace_docker"]
16b50ca SPDX license = "Apache-2.0", trove classifiers, .editorconfig
ca9586e [tool.wads.ci.install] extras = "dev"

Notes on the two non-root-cause commits:

  • testpaths. wads CI runs pytest --doctest-modules with no path argument, so collection roots come entirely from testpaths. Pointed at enlace_docker/tests, the --doctest-modules flag was inert — no module docstring in the package could ever be collected, and CI reported green regardless. Pointing it at the package keeps every existing test (they live under enlace_docker/tests) and makes future doctests actually run. Collected counts are unchanged (53 passed, 2 skipped) because no module currently has doctest examples.
  • Metadata. No behaviour change. The [project.license] table form is deprecated under PEP 639; the built wheel now carries License-Expression: Apache-2.0 plus an auto-included License-File. Verified uv build produces both sdist and wheel, twine check PASSED on both, and the wheel's entry_points.txt still carries all four enlace.backend_strategies entries plus the enlace.diagnosers one.

No package behaviour and no test assertion was changed to make CI pass.

Verification

Local dependents gate (priv test-dependents enlace-docker):

  • baseline, before any change: enlace-docker pass 1.3s — 1 suites: 1 pass, 0 fail, 0 no-tests
  • final, on this branch: enlace-docker pass 1.2s — 1 suites: 1 pass, 0 fail, 0 no-tests

Branch CI: run 30859243465 — success.

ci / Read Configuration   :: success
ci / Validation (3.10)    :: success   53 passed, 2 skipped
ci / Validation (3.12)    :: success   53 passed, 2 skipped
ci / Windows Tests        :: success   53 passed, 2 skipped
ci / Publish              :: skipped   (branch push — publish is gated on main)
ci / Publish GitHub Pages :: skipped

All three test jobs show pytest-asyncio==1.4.0 installed, plugins: anyio, asyncio-1.4.0, and enlace==0.1.27.

Left undone

  • The repo's GitHub description is longer and more informative than the pyproject description, so the audit reports a mismatch. Left as-is deliberately rather than truncating the GitHub side; worth a decision on which is canonical.
  • No agent skills directory (skills/) — out of scope for a CI fix.
  • The two Docker-requiring integration tests still skip in CI (they gate on DOCKER_AVAILABLE). That is by design, but it does mean the real-docker paths are exercised only locally.

⚠️ Merging this PR publishes a release

ci.yml publishes to PyPI on push to main, so merging will cut and publish a new enlace_docker release (version auto-bumped from 0.0.4). Left open for you to merge when you want that.

The `enlace.diagnosers` entry-point group this package registers against
(and `enlace.diagnose.iter_diagnosers`, which `diagnose_app` calls) first
shipped in enlace 0.1.21. The declared floor was `enlace>=0.1.20`, one
release too low, so a clean resolve could legitimately install 0.1.20 —
where `diagnose_app` never invokes plugin diagnosers.

That is exactly what happened in CI: the Validation (3.12) job resolved
`enlace==0.1.20` and `test_runs_via_diagnose_app_entry_point` failed with

    AssertionError: assert 'docker_missing_dockerfile' in
        {<Category.MISSING_ENTRY_POINT: 'missing_entry_point'>}

Reproduced locally in a clean venv: pinning enlace==0.1.20 fails that test
(1 failed, 52 passed, 2 skipped); enlace==0.1.21 passes (53 passed,
2 skipped). Developer machines masked it because they carry a newer enlace.

Claude-Session: https://claude.ai/code/session_01VipiLaG4xy7WctqY9w2475
…lected

wads CI runs `pytest --doctest-modules` with no path argument, so pytest's
collection roots come entirely from `testpaths`. With
`testpaths = ["enlace_docker/tests"]` the `--doctest-modules` flag was inert:
no module docstring in the package could ever be collected, and CI reported
green regardless.

Pointing testpaths at the package directory keeps the existing test files
(they live under enlace_docker/tests) and additionally exposes module
docstrings to doctest collection. Verified in a clean venv with the exact CI
command: 53 passed, 2 skipped -- unchanged, since no module currently has
doctest examples. This is about future ones being honoured.

Claude-Session: https://claude.ai/code/session_01VipiLaG4xy7WctqY9w2475
Packaging metadata alignment with the rest of the ecosystem, no behaviour
change:

- `[project.license] text = "Apache-2.0"` -> `license = "Apache-2.0"`. The
  table form is deprecated under PEP 639; the built wheel now carries
  `License-Expression: Apache-2.0` plus an auto-included `License-File`.
- Added the standard trove classifiers (the package previously published
  none).
- Added the ecosystem-standard .editorconfig.

Verified: `uv build` produces both sdist and wheel, `twine check` PASSED on
both, and the wheel's entry_points.txt still carries all four
`enlace.backend_strategies` entries plus the `enlace.diagnosers` one.

Claude-Session: https://claude.ai/code/session_01VipiLaG4xy7WctqY9w2475
wads' reusable workflow now feeds the install step from
`[tool.wads.ci.install].extras`, which defaults to "" — so CI installed the
package with core dependencies only. Older runs got the `dev` extra by
accident, from the install-deps-uv action's own `default: "dev"`, which the
workflow now always overrides with the (empty) resolved config value.

pytest-asyncio is declared only in the `dev` extra, and `asyncio_mode =
"auto"` needs it, so every `async def` test failed:

    Failed: async def functions are not natively supported.
    PytestConfigWarning: Unknown config option: asyncio_mode

Reproduced locally in a clean 3.10 venv (package + bare pytest, no extra):
11 failed, 42 passed, 2 skipped. Adding the `dev` extra to that same venv:
53 passed, 2 skipped. `CIConfig.from_file` now reports install_extras='dev'.

Same fix already carried by the sibling enlace and enlace_auth repos.

Claude-Session: https://claude.ai/code/session_01VipiLaG4xy7WctqY9w2475
@thorwhalen
thorwhalen merged commit 8d2410a into main Aug 4, 2026
12 checks passed
@thorwhalen
thorwhalen deleted the claude/rollout-ci-fix branch August 4, 2026 13:38
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.

1 participant