Skip to content

feat(heart): Colab gate — prove the --no-deps bootstrap can import what the libraries import #227

Description

@Jammy2211

Overview

autonerves.setup_colab installs the PyAuto stack on Colab with --no-deps, so every dependency Colab does not preinstall must be hand-listed in _SHARED_EXTRAS. On 2026-09-15 corner — a base autofit dependency imported lazily inside corner_cornerpy — was missing, and HowToFit tutorial 5 died mid-workshop after its emcee run. Nothing caught it: workspace smoke runs at PYAUTO_TEST_MODE=2 (samplers never constructed), and Heart check F emulates Colab by pip install autolens jax with dependencies, so its venv already contains everything the --no-deps path would miss. This task makes check F a faithful Colab gate: seed the venv from Google's published Colab manifest, run the real --no-deps bootstrap, then prove every module the libraries import is importable. Check F FAIL already maps to readiness RED, so the gate blocks release.

Scoping decision (time vs robustness): rung 2 — import probe after a faithful bootstrap, ~5 min, inside the existing release-only verify_install_release lane. Rung 1 (static scan) is an input, not a gate; rung 3/4 (notebooks end to end at real settings, tens of minutes to hours) test a different bug class and are declined for this gate (HowTo repos have no release profile; tutorial 5 cannot complete at real sampling today, PyAutoFit#1454).

Plan

  • Ground the Colab emulation on Google's live manifest (googlecolab/backend-info pip-freeze.txt), with cache + vendored snapshot fallback, and say which source was used.
  • Seed the sim venv with only the manifest packages the stack needs (dry-run resolve ∩ manifest), never with the stack's own dependencies.
  • Run the injected setup cell verbatim (real --no-deps install + workspace clone), as today.
  • Walk declared requirements against what is installed / what Colab ships; AST-scan the installed libraries for every third-party import (module- and function-level, guarded or not) and import each one; construct the tutorial searches.
  • Verdict: unguarded import that fails on Colab → FAIL (RED); guarded misses, version conflicts, never-imported declared deps → WARN. No allowlist shipped; an empty accepted_missing config exists for the human.
  • Rewrite the stale check-F docs; unit-test the gate offline; run the witness locally (PyPI as-is → FAIL naming corner; Nerves#167 branch → PASS).
Detailed implementation plan

Affected Repositories

  • PyAutoHeart (primary, only)

PyAutoNerves and the HowTo repos are listed in the prompt but need no edit: the gate reads released wheels and Google's manifest. All four are claimed by in-flight tasks (colab-bootstrap-lazy-deps, colab-workshop-dep-stopgap, howtofit-mode).

Branch Survey

Repository Current Branch Dirty?
./PyAutoHeart main clean (1 behind origin)

Suggested branch: feature/colab-notebook-release-gate
Worktree: ~/Code/PyAutoLabs-wt/colab-notebook-release-gate/

Implementation Steps

  1. New heart/checks/colab_gate.py (stdlib + packaging; run with the sim venv's interpreter so importlib.metadata sees the venv). JSON report via --report-json; exit 0 pass / 1 fail / 2 tool error.

    • seed: load manifest (fetch https://raw.githubusercontent.com/googlecolab/backend-info/main/pip-freeze.txt → fallback $HEART_STATE_DIR/colab_pip_freeze.txt → vendored heart/checks/colab_pip_freeze.snapshot.txt, dated; record source; cache live copy). pip install --dry-run --report - <f_targets> jax (same targets + PIP_INDEX_ARGS check F uses) for the with-deps closure; intersect PEP 503-normalised names with the manifest, drop PyAuto packages, pip install --no-deps name==<colab version> for the intersection.
    • verify (after the setup cell): (a) requirement walk from the installed PyAuto dists over requires_dist (markers evaluated, extras empty): unmet + in manifest → install Colab's version --no-deps, continue; unmet + not in manifest → missing_declared; installed but outside specifier → version_conflict. (b) AST-scan every .py of installed autonerves/autofit/autoarray/autogalaxy/autolens for all imports, keep third-party top-level names (not sys.stdlib_module_names, not PyAuto), flag whether the site is inside a try: catching ImportError/ModuleNotFoundError/Exception; import each name in a subprocess. Unguarded failure → FAIL with file:line; guarded-only → WARN. (c) instantiate af.Emcee, af.DynestyStatic, af.Nautilus, af.LBFGS with defaults; exception → FAIL. (d) Verdict: FAIL on any unguarded import failure, constructor failure, or missing_declared that is imported anywhere; everything else WARN. Optional heart/config/colab_gate.yaml accepted_missing: (name + reason) downgrades a named FAIL to WARN — ships empty.
  2. Rework check_f() in heart/checks/verify_install.sh (lines 685-812): venv on python3.12 (Colab's interpreter; missing interpreter is FAIL like B/E); replace pip install ${f_targets[*]} jax with pip install packaging + colab_gate.py seed; keep the fake google.colab stub, the verbatim setup-cell driver and the al.Imaging.from_fits cell; insert colab_gate.py verify between the setup cell and the notebook cell; result line F|FAIL|colab gate: unguarded imports missing on Colab: corner (autofit/non_linear/plot/samples_plotters.py:95), … / F|PASS|Colab manifest <date/source>; N Colab-provided, M extras, K probed imports; fold the gate JSON into the --report-json sidecar under checks.F.colab_gate. Dev flag COLAB_GATE_AUTONERVES_SRC=<path>: after the cell's pip install autonerves --no-deps, pip install --no-deps <path> so the gate can run against an unreleased setup_colab.

  3. Tests — new tests/test_colab_gate.py (manifest parsing + fallback order; requirement walk on fabricated requires_dist; AST scanner guarded/unguarded/stdlib/PyAuto exclusion; verdict rules incl. accepted_missing); extend tests/test_verify_install_script.py (check_f calls seed and verify, uses python3.12, no with-deps stack install). No network, no venv in unit CI.

  4. Docs — skills/verify_install/verify_install.md row F (still says autoconf, dataset/imaging/simple); health_agent/capabilities.yaml verify_install.measures; docs/release_validation.md F description. State what the simulation does (Colab's package set, Python 3.12) and does not (GPU, OS, 1–2 day manifest lag) cover.

  5. Ship via ship_workspace. PR body must flag: the first release-integrate run after merge will be RED until the autonerves that ships PyAutoNerves#167 is on PyPI (today's PyPI autonerves lacks corner/optax/xxhash/blackjax). That is the gate working.

Verification (the witness)

  1. heart/checks/verify_install.sh check F against PyPI as-is → F|FAIL naming corner — the 2026-09-15 failure that 18/18 smoke missed.
  2. Same with COLAB_GATE_AUTONERVES_SRC=~/Code/PyAutoLabs-wt/colab-bootstrap-lazy-deps/PyAutoNerves → F|PASS (or WARNs only).
  3. python3 -m pytest -q -n auto PyAutoHeart/tests green; pyauto-heart readiness reads the new sidecar.
    Paste both F result lines and wall time into the PR.

Key Files

  • heart/checks/verify_install.sh — check F (check_f(), lines 685-812), dispatch at 830, verdict roll-up 843-871, sidecar 868-919
  • heart/checks/colab_gate.py — new
  • heart/checks/colab_pip_freeze.snapshot.txt — new, dated vendored fallback
  • heart/config/colab_gate.yaml — new, empty accepted_missing:
  • heart/readiness.py:511-542 — consumes verify_install.json (ready:false → RED)
  • .github/workflows/workspace-validation.yml:649-686 — verify_install_release job (release mode only)
  • tests/test_verify_install_script.py, tests/test_colab_gate.py
  • skills/verify_install/verify_install.md, health_agent/capabilities.yaml, docs/release_validation.md

Cadence / follow-ups (not this task)

  • Runs every nightly release (release-integrate → verify_install_release) and on demand via pyauto-heart verify_install.
  • Follow-up prompts to offer: PR-time trigger in PyAutoNerves when setup_colab.py changes; a HowTo real-settings nightly (rung 3) once PyAutoFit#1454 is fixed.

Original Prompt

Click to expand starting prompt

Release-time gate that proves the Colab notebooks actually run

Type: feature
Target: PyAutoHeart
Repos:

  • PyAutoHeart
  • PyAutoNerves
  • HowToFit
  • HowToGalaxy
  • HowToLens
    Difficulty: medium
    Autonomy: safe
    Priority: high
    Status: formalised
    Consequence: glance
    Witness: with corner deleted from _SHARED_EXTRAS, the new gate reports RED, where today's workspace smoke reports 18/18 green — i.e. the gate catches the 2026-09-15 tutorial-5 failure that every existing gate missed.
    Review-minutes: 3
    Unattended: ready

Filed: 2026-09-15

Raw request from the user, verbatim:

can we /intake something that checks colab notebooks run during release? IU guess
that could be slow but the intake can scope out the best way to do that and balance
time versus robustness

Why now

autonerves/setup_colab.py bootstraps Colab with pip install *packages --no-deps,
so every dependency Colab does not itself preinstall must be named by hand in
_SHARED_EXTRAS or it never lands. On 2026-09-15 HowToFit chapter 1 tutorial 5 died
on Colab with ModuleNotFoundError: No module named 'corner' — after a 2000-step
emcee search had already completed, in the results update that follows it. A workshop
was running that day.

The reason nothing caught it is the part that should shape the scoping:

  • corner is imported INSIDE corner_cornerpy
    (autofit/non_linear/plot/samples_plotters.py:95), not at module scope. So
    import autofit succeeds, the model builds, the search runs to completion, and
    only the post-fit plot raises.
  • Workspace smoke runs at PYAUTO_TEST_MODE=2 (config/build/profile_smoke.yaml),
    which bypasses the sampler entirely — the searches are never constructed and the
    lazy imports never execute. Scripts pass green while being unrunnable by a reader.
  • config/build/no_run.yaml already documents this same blind spot for
    tutorial_5_expectation_propagation.

Third instance of the class: 8336939 (PyAutoNerves#166) closed it for emcee and
dynesty; a HowToFit prompt had it open for blackjax; PyAutoNerves#167 closes corner,
optax, xxhash and blackjax at once. Each fix needs its own PyPI release to reach a
single user, and the list is being patched one user report at a time.

What already exists (build on, do not duplicate)

  • PyAutoHeart verify_install check F already simulates the Colab bootstrap. That is
    the right place; the open question is what it should execute once bootstrapped.
  • PyAutoNerves#167 adds a test deriving _SHARED_EXTRAS specifiers from PyAutoFit's
    pyproject.toml. That closes the DRIFT class statically. It does not prove a
    notebook runs.
  • 100 notebooks carry the Colab setup cell: HowToFit 18, HowToGalaxy 32, HowToLens 50,
    plus the three workspace repos.

The tradeoff to scope — time versus robustness

This is explicitly what the task is for. Weigh these rungs and recommend one; do not
merely list them.

  1. STATIC — AST-scan the libraries for function-level third-party imports, cross-check
    against _SHARED_EXTRAS and what Colab preinstalls. Seconds. Catches exactly this
    class; proves nothing about runtime.
  2. IMPORT PROBE — after a real Colab bootstrap, import every lazily-imported module and
    construct every af.<Search> class the scripts instantiate. Minutes. Catches missing
    deps and bad pins without running a fit.
  3. ONE REPRESENTATIVE NOTEBOOK per chapter, end to end at REAL settings — not
    PYAUTO_TEST_MODE=2, since that mode is the blindness. Tens of minutes.
  4. EVERY notebook end to end. Hours; probably too slow for a release gate, but worth
    pricing so the decision is informed.

Also in scope for the scoping

  • Where it runs. A real Colab runtime is not reachable from CI, so check F's simulation
    is an approximation — and Colab's exact preinstalled package set is precisely the
    thing being approximated. Getting that wrong IS the bug. Say what the approximation
    does and does not cover.
  • Whether the gate blocks a release or merely reports. A missing dependency makes
    notebooks unrunnable for every user, so blocking is arguable.
  • Cadence: per-release, nightly, or only when _SHARED_EXTRAS or a pyproject.toml
    changes.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions