Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 107 additions & 0 deletions complete/2026/08/version-skew-yank-awareness.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# version-skew-yank-awareness

**Completed:** 2026-08-18
**Type:** feature · **Target:** PyAutoHeart · **PR:** PyAutoHeart#148 (merged,
`7659f153`; branch `feature/version-skew-yank-awareness`)

## Summary

Closed the yank gap the `version_skew` Heart leg acknowledged in its own
docstring: the tick check compares floors against **local git tags**, so it
could not see the other way a floor goes bad — the release it names being
**yanked on PyPI** afterwards (the 2026-07 incident shape, where every floor
named the yanked `2026.7.6.649`). Filed as the surviving loose end when the
Phase 4 tracker retired ([[release-version-sync-back-to-main]]); shipped the
same day.

## What shipped

`python -m heart.checks.version_skew --pypi` — a deep, on-demand leg that asks
the PyPI JSON API whether each workspace floor still names an installable
(non-yanked) release and whether *any* installable release satisfies it.

- **Statuses → readiness:** `UNSATISFIABLE` (nothing installable ≥ floor —
every candidate yanked; same defect class as the tag leg) → **RED**;
`FLOOR_YANKED` (floor itself yanked/absent but newer installable releases
satisfy it — floors are `>=` bounds so installs still resolve) → **YELLOW**
"bump the floor"; `UNKNOWN` (PyPI unreachable) → **STALE**, never a false
block; `OK`/`BAD` as in the tag leg.
- **Tick untouched:** network-bound, so never run from `tick.sh` — on-demand /
nightly only, behind the explicit `--pypi` flag.
- **Sidecar state** (`version_skew_pypi.json`): the tick's `version_skew.json`
rewrite can never clobber on-demand PyPI evidence, and vice versa. An absent
slice is no signal in readiness and the dashboard.
- `run_pypi()` side-effect-free like `run()` (persistence in `main()` only);
one PyPI fetch per distinct package, not per workspace. Wired through
`state.py` snapshot, readiness legs + score weights, and a "Version skew
(PyPI)" dashboard section.
- **Validated:** 484 tests pass (15 new); live probe against real PyPI
(`autolens`, 421 releases): `2026.7.9.1 → OK`, the incident release
`2026.7.6.649 → FLOOR_YANKED`, `2099.1.1.1 → UNSATISFIABLE`,
`garbage → BAD`.

## Key findings / traps

- **Tenant firewall caught a real leak on the first CI round:** the
one-fetch-per-package test named `HowToLens` — a *new* instance fact in
organ code (`repos_sync.py --check --only "tenant firewall (organ code)"`).
Fixed by using `autolens_assistant` (an already-present fact in that file,
same `autolens` package mapping). When testing organ code, pick instance
names the file already carries; the firewall treats new ones as drift even
in tests.
- **Verdict-shape reasoning recorded in the check itself:** a yanked floor
with newer installable releases is deliberately YELLOW, not RED — `>=`
semantics mean installs still resolve; only "nothing installable ≥ floor"
blocks. Offline degrades to UNKNOWN/STALE so an offline dev box can never
produce a false RED.
- Fork (b) of the version model stands: this reads state only — no
commit-back behaviour was added anywhere.

## Original prompt

# version_skew: flag a floor that names a PyPI-yanked release

Type: feature
Target: PyAutoHeart
Repos:
- PyAutoHeart
Difficulty: small
Autonomy: supervised
Priority: low
Status: formalised

## Why

The `version_skew` Heart leg (reworked under build-chain #155 Phase 4 task 2,
PyAutoHeart#96) enforces "a floor must name an *installable* release" only
against **local git tags**: UNSATISFIABLE fires when
`version.minimum_library_version` exceeds the newest `YYYY.M.D.B` release tag.
It cannot see the other way a floor goes bad — the release it names being
**yanked on PyPI afterwards** (as `2026.7.6.649` was; that yank is what
originally exposed the "floors named a yanked release" bug that this check now
half-guards). The gap is acknowledged in the check itself
(`heart/checks/version_skew.py:33`: "a release that was later *yanked* on PyPI —
that needs the PyPI API, not git tags") and was left unowned when the Phase 4
tracker (`complete/2026/08/release-version-sync-back-to-main.md`) retired.

## Scope

- Extend `version_skew` (or add a sibling non-tick check, if network access
disqualifies it from the tick path — the current check is deliberately
local-tags-only, no import/network) to query the PyPI JSON API for the
floor's version and flag `yanked: true` per package.
- Verdict shape should mirror the existing one: a yanked floor is the same
class of defect as UNSATISFIABLE (no installable version satisfies "exactly
this floor"), but the floor semantics (>=) mean a yanked floor with newer
non-yanked releases still resolves — decide whether that is RED, YELLOW, or
informational, and record the reasoning.
- Offline/API-failure behaviour must be UNKNOWN/STALE, never a false RED —
match how the tag-based check treats unresolvable repos.

## Constraints

- Do not slow the readiness tick: if the PyPI call cannot be cached or made
optional, keep it out of the tick path (nightly / on-demand only).
- Fork (b) of the version model stands (mains authoritative, floors + tags +
wheels as the live signals — see the retired tracker). This check reads
state; it must not resurrect any commit-back behaviour.
3 changes: 2 additions & 1 deletion complete/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Token-light navigation over the finished-work records (schema:
only then grep a dated bucket. Curators: edit the band between the CURATED
markers; everything below GENERATED is rebuilt.

1022 records across 7 buckets.
1023 records across 7 buckets.

<!-- CURATED:START -->
## Highlights
Expand Down Expand Up @@ -145,6 +145,7 @@ _(curate hard-won records here — survives regeneration.)_
- [test-mode-fit-exception-finalization](2026/08/test-mode-fit-exception-finalization.md) — `PYAUTO_TEST_MODE=1` no longer finalizes a model point whose reconstruction raises `FitException`; it substitu…
- [test-mode-samples-info-hook-contract](2026/08/test-mode-samples-info-hook-contract.md) — `NonLinearSearch._test_mode_samples_info()`'s docstring told subclasses
- [uniform-prior-bounds-numpy-path](2026/08/uniform-prior-bounds-numpy-path.md) — auto-closed by the merge's `Closes` line
- [version-skew-yank-awareness](2026/08/version-skew-yank-awareness.md)
- [wiki-provenance-restamp](2026/08/wiki-provenance-restamp.md)
- [worktree-claim-parser-forms](2026/08/worktree-claim-parser-forms.md) — CLOSED completed
- [yang24-sidm-gravothermal-profile](2026/08/yang24-sidm-gravothermal-profile.md)
Expand Down
7 changes: 3 additions & 4 deletions dashboard.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Tasks only — the organism's health lives with the Heart (`/health`), not here.
| [In flight](#in-flight) (`active/`) | 3 |
| [Parked](#parked) (`parked.md`) | 1 |
| [Planned](#planned) (`planned.md`) | 7 |
| [Backlog](#backlog) (`draft/`) | 128 |
| [Backlog](#backlog) (`draft/`) | 127 |

Live on GitHub: [open issues](https://github.com/search?q=org%3APyAutoLabs+is%3Aissue+is%3Aopen&type=issues) · [open pull requests](https://github.com/search?q=org%3APyAutoLabs+is%3Apr+is%3Aopen&type=prs)

Expand Down Expand Up @@ -79,7 +79,7 @@ Scoped but not started; some are not yet prompt files. Full detail in [`planned.

## Backlog

**128** filed prompts, not started. Each section is sorted most-pickable first (priority, then size).
**127** filed prompts, not started. Each section is sorted most-pickable first (priority, then size).

<details>
<summary><b>bug</b> — 35</summary>
Expand Down Expand Up @@ -123,7 +123,7 @@ Scoped but not started; some are not yet prompt files. Full detail in [`planned.
</details>

<details>
<summary><b>feature</b> — 27</summary>
<summary><b>feature</b> — 26</summary>

- [Decide whether the clipper belongs in the search identifier](draft/feature/autofit/clipper_in_search_identifier.md) — autofit · medium · human-required · high
- [Profile and speed up JAX likelihood-function compile times (all use](draft/feature/autolens_profiling/jax_compile_time_profiling.md) — autolens_profiling · large · supervised · high
Expand All @@ -148,7 +148,6 @@ Scoped but not started; some are not yet prompt files. Full detail in [`planned.
- [Context: PyAutoLens issue #542 follow-up (Gap 2, deferred during the](draft/feature/jax_substructure/6_deflection_equivalence_test.md) — jax_substructure · too-large · supervised · normal
- [Once https://github.com/PyAutoLabs/PyAutoLens/issues/480 is fixed (PointSolver](draft/feature/workspaces/restore_multiple_sources_lensing_of_lens.md) — workspaces · too-large · supervised · normal
- [dPIE: optional central-dispersion (sigma_0) parameterization](draft/feature/autogalaxy/dpie_sigma0_parameterization.md) — autogalaxy · small · supervised · low
- [version_skew: flag a floor that names a PyPI-yanked release](draft/feature/pyautoheart/version_skew_yank_awareness.md) — pyautoheart · small · supervised · low
- [Gallery runner: add visualization_upper + decide the modeling_visualization_jit tier](draft/feature/workspaces/gallery_runner_missing_tiers.md) — workspaces · small · supervised · low
- [Scheduled runs — overnight queue passes with a morning report](draft/feature/autonomy/10_scheduled_runs.md) — autonomy · medium · supervised · low
- [Teach repos_sync --write to stamp organ config surfaces](draft/feature/pyautomind/repos-sync-config-stamper.md) — pyautomind · hard · supervised · low
Expand Down
46 changes: 0 additions & 46 deletions draft/feature/pyautoheart/version_skew_yank_awareness.md

This file was deleted.

Loading