Skip to content

fix(readiness): ingest Stage 3's verify_install result into the install-verification leg #76

Description

@Jammy2211

Overview

Heart's release-fidelity Stage 3 (workspace-validation.yml, mode=release) already runs verify_install checks A–E against the TestPyPI wheels and they pass — but the readiness verdict still reports install verification not run. The evidence is produced in CI and then thrown away: heart/validate.py reads the --verify-install sidecar only in the failure direction, and nothing ever writes the verify_install.json sidecar that readiness.py reads. This is one of three legs holding Heart at YELLOW 70. Because the armed nightly release driver's step-5 gate requires GREEN and has deliberately no force input, Heart never reaching GREEN means the nightly can never ship unattended — 2026.7.15.1 shipped only because a human forced it with release --force.

Verified on main at 2026-07-15 (measured, not inherited):

  • pyauto-heart readinessYELLOW score 70, with ? install verification not run.
  • ~/.pyauto-heart/verify_install.json — the file heart/state.py:84 reads — does not exist.
  • ~/.pyauto-heart/validation_report.json from the real 2026-07-15 release run was ingested successfully (integrate stage pass, 543 passed / 0 failed) and contains zero trace of verify_install.

Discard point: heart/validate.py:563-569ready is False force-fails the stage; a PASS contributes nothing.

Plan

  • Record index (testpypi | pypi) in the verify_install.sh JSON sidecar so the result carries its own provenance.
  • Embed the sidecar in the Stage 3 stage report, instead of only consulting it to force a failure.
  • On validate --ingest, persist that embedded result to HEART_STATE_DIR/verify_install.json — the file the readiness leg already reads.
  • Surface the index in the readiness reason line, so a TestPyPI-wheel pass never reads as proof that a PyPI install works.
  • readiness.py needs no logic change: the leg starts receiving evidence through the path it already consumes.

Decided design question (human, 2026-07-15): a TestPyPI-wheel verify_install pass does satisfy this leg — the about-to-ship wheels are the right evidence for a release gate — but provenance is recorded so the verdict claims only what was verified. Precedent: the rehearse stage already records index: "testpypi".

Autonomy note (2026-07-15): launched with --auto, but work-type release caps at human-required (AUTONOMY.md:56), so effective level = human-required and --auto changed nothing. This is the cap working as intended: the change edits what makes Heart GREEN, which is the exact gate guarding the unattended nightly (AUTONOMY.md:85). Plan approved by the human; run ends at PR-open, merge stays human.

Detailed implementation plan

Affected Repositories

  • PyAutoHeart (primary, only)

Branch Survey

Repository Current Branch Dirty?
./PyAutoHeart main clean

Suggested branch: feature/wire-verify-install-leg (no worktree conflict)

Implementation Steps

  1. heart/checks/verify_install.sh — in the --report-json sidecar writer, add "index": "testpypi" when USE_TESTPYPI=1, else "pypi". Pass it through the existing VI_* env-var handoff to the inline python3 writer (alongside VI_READY/VI_VERSION).

  2. heart/validate.pyto_stage_report(...) — add a verify_install: dict | None param. When present, embed a normalized {ts, ready, version, index, checks} block under stage_report["verify_install"]. Keep force_fail/extra_failures behaviour exactly as-is (pure function, no I/O).

  3. heart/validate.py CLI (--verify-install) — keep the force-fail path; additionally pass the parsed sidecar into to_stage_report so a pass survives into the artifact. Update the --verify-install help text, which currently documents only the fail direction.

  4. heart/validate.py ingest (_Accumulator / run) — when an ingested stage report carries a verify_install block, persist it to state.HEART_STATE_DIR / "verify_install.json" via state.atomic_write_json. Idempotent on re-ingest; keep the newest ts. This is the one new write, and it stays inside ~/.pyauto-heart/ — the module boundary (no dispatch, no GitHub, no foreign repo) is preserved.

  5. heart/readiness.py — no gate-logic change. Only extend the existing pass/stale reason strings to name the index (e.g. install verification stale (testpypi, 16d old)), so the provenance decision is visible in the verdict.

  6. Teststests/test_validate.py: sidecar embeds into the stage report on pass; --ingest writes verify_install.json; re-ingest is idempotent; existing force-fail tests still green. tests/test_readiness.py: an ingested testpypi pass flips the leg off the stale tier; reason line carries the index. tests/test_verify_install_script.py: sidecar contains index.

  7. Verification — after ingest of a stage report carrying a pass, pyauto-heart readiness must drop install verification not run, leaving the two known follow-up legs (stale test_run re-run; 58 stale parked no_run scripts). Those are explicitly out of scope per the prompt.

Key Files

  • heart/validate.pyto_stage_report (:395), CLI --verify-install (:541-570), ingest accumulator
  • heart/checks/verify_install.sh — sidecar writer (--report-json block)
  • heart/readiness.py:365-386 — the install-verification leg (consumer; near-untouched)
  • heart/state.py:84verify_install.json → snapshot key
  • .github/workflows/workspace-validation.ymlverify_install_release + emit_release_report (already wired; expected to need no change)

Original Prompt

Click to expand starting prompt

Wire Stage 3's verify_install result into Heart's install-verification readiness leg. Heart's release-fidelity Stage 3 (workspace-validation mode=release) already runs verify_install checks A-E against the TestPyPI wheels and they pass, but the readiness verdict still reports 'install verification not run' because that result is a separate ingest the leg never receives. Evidence is produced and then thrown away. This is one of three legs holding Heart at YELLOW 70; because the armed nightly release driver's step-5 gate requires GREEN and has deliberately no force input, Heart never reaching GREEN means the nightly can never ship unattended - 2026.7.15.1 shipped only because a human forced it with 'release --force'. Fixing this leg is the durable half: the other two are an ops re-run of the weekly mode=smoke workspace-validation to refresh the stale test_run leg (its 3 failures from 2026-07-09 are already disproven by the fresh release run: autolens_test 90p/0f, 543p/0f/0t overall), and hygiene triage of 58 stale parked no_run scripts (all age_days=90, category slow). Those two are follow-ups, not this task.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    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