mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
fix(ci): reorder Dockerfile so wheel installs before headroom-ai
PR #350 CI: docker-native-e2e's wheel install succeeded but the build-stage verify (`from headroom._core import hello`) failed with `ModuleNotFoundError: No module named 'headroom._core'`. Same failure mode the customer hit in production (Finding #2) — but in CI we have the full layer trace. Root cause: the headroom-core-py wheel claims ownership of both `headroom/__init__.py` (stub from maturin's python-source layout) AND `headroom/_core.cpython-*.so`. The previous Dockerfile installed headroom-ai FIRST (which laid down the real `headroom/` tree), then the wheel SECOND with `--force-reinstall`. pip's --force-reinstall uninstalls the wheel's previously installed files before reinstalling — but the wheel's stub `__init__.py` had already overwritten headroom-ai's at first install. Net result: pip deleted `headroom/__init__.py` and `headroom/_core.so` ownership records got into a state where the .so wasn't present after the install. Fix: swap the order. Install the wheel first (lays down stub `__init__.py` + `_core.so`), then install headroom-ai (overwrites the stub with the real `__init__.py` and adds the rest of the `headroom/` tree). `_core.so` survives because headroom-ai doesn't claim ownership of it. Drop `--force-reinstall` from the wheel step since nothing is installing the wheel before it. This is the exact failure A0 was designed to catch — a deployment that ships without `_core` working. CI is now serving as a regression gate for the production install path. The remaining 3 PR check failures (validate × 3 / Dev Containers) are environmental: the runner's PyPI mirror (`pypi.netflix.net`) times out fetching `cuda-bindings==12.9.4` / `nvidia-cuda-cupti-cu12==12.8.90` / `safetensors==0.7.0`. These come from `headroom-ai[dev]` → `sentence-transformers` → `torch` → CUDA deps. Not caused by the realignment branch; the post-create script needs a `--extra dev-light` profile or the mirror needs the packages cached. Tracking separately.
This commit is contained in:
parent
55dfc19e1d
commit
f1aa12cebf
1 changed files with 31 additions and 8 deletions
39
Dockerfile
39
Dockerfile
|
|
@ -55,13 +55,28 @@ ARG HEADROOM_EXTRAS=proxy,code
|
|||
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||
uv pip install --system ".[${HEADROOM_EXTRAS}]"
|
||||
|
||||
# Layer 2: copy real source, reinstall only headroom-ai (no deps)
|
||||
COPY headroom/ headroom/
|
||||
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||
uv pip install --system --no-deps --reinstall-package headroom-ai .
|
||||
|
||||
# Layer 3 (Hotfix-A0): build and install the Rust extension wheel. uv
|
||||
# already installed `maturin` as a transitive of the [proxy]/[code]
|
||||
# Layer 2 (Hotfix-A0): build and install the Rust extension wheel
|
||||
# BEFORE installing headroom-ai source. Why this order:
|
||||
#
|
||||
# * The headroom-core-py wheel includes a stub `headroom/__init__.py`
|
||||
# plus `headroom/_core.cpython-*.so` (maturin's `python-source`
|
||||
# layout — see `crates/headroom-py/pyproject.toml`).
|
||||
# * The headroom-ai install also writes files under `headroom/`.
|
||||
# * If headroom-ai is installed FIRST and the wheel goes second with
|
||||
# `--force-reinstall`, pip uninstalls the wheel's previously
|
||||
# installed files, deleting `headroom/__init__.py` (which the wheel
|
||||
# also claims). headroom-ai's __init__.py was already overwritten
|
||||
# by the wheel's empty stub at install-time, so the deletion leaves
|
||||
# no `__init__.py` at all — `from headroom._core import hello`
|
||||
# then fails with `ModuleNotFoundError: No module named
|
||||
# 'headroom._core'`. Observed in PR #350 CI before this reorder.
|
||||
# * Installing the wheel FIRST means: wheel lays down stub
|
||||
# `__init__.py` + `_core.so`. Then headroom-ai install OVERWRITES
|
||||
# `__init__.py` with the real one and adds the rest of the
|
||||
# `headroom/` tree. `_core.so` survives because headroom-ai
|
||||
# doesn't claim ownership of it.
|
||||
#
|
||||
# uv already installed `maturin` as a transitive of the [proxy]/[code]
|
||||
# extras; if it didn't, install it explicitly here so the build never
|
||||
# silently skips.
|
||||
COPY crates/ crates/
|
||||
|
|
@ -71,7 +86,15 @@ RUN --mount=type=cache,target=/root/.cache/uv \
|
|||
--mount=type=cache,target=/build/target \
|
||||
uv pip install --system maturin \
|
||||
&& maturin build --release -m crates/headroom-py/Cargo.toml --out /build/wheels \
|
||||
&& uv pip install --system --force-reinstall --no-deps /build/wheels/headroom_core_py-*.whl
|
||||
&& uv pip install --system --no-deps /build/wheels/headroom_core_py-*.whl
|
||||
|
||||
# Layer 3: copy real source, install headroom-ai (no deps). This
|
||||
# overwrites the wheel's stub `headroom/__init__.py` with the real one
|
||||
# and adds the full `headroom/` tree alongside the surviving
|
||||
# `_core.so` from Layer 2.
|
||||
COPY headroom/ headroom/
|
||||
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||
uv pip install --system --no-deps --reinstall-package headroom-ai .
|
||||
|
||||
# Layer 4 (Hotfix-A0): verify the extension actually loads end-to-end
|
||||
# inside the build image. If this fails, the runtime image would fail
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue