diff --git a/complete/2026/08/version-skew-yank-awareness.md b/complete/2026/08/version-skew-yank-awareness.md
new file mode 100644
index 00000000..8e01c35c
--- /dev/null
+++ b/complete/2026/08/version-skew-yank-awareness.md
@@ -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.
diff --git a/complete/index.md b/complete/index.md
index a202c88e..2159725e 100644
--- a/complete/index.md
+++ b/complete/index.md
@@ -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.
## Highlights
@@ -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)
diff --git a/dashboard.md b/dashboard.md
index 00e22817..37d23bfb 100644
--- a/dashboard.md
+++ b/dashboard.md
@@ -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)
@@ -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).
bug — 35
@@ -123,7 +123,7 @@ Scoped but not started; some are not yet prompt files. Full detail in [`planned.
-feature — 27
+feature — 26
- [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
@@ -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
diff --git a/draft/feature/pyautoheart/version_skew_yank_awareness.md b/draft/feature/pyautoheart/version_skew_yank_awareness.md
deleted file mode 100644
index e09296e3..00000000
--- a/draft/feature/pyautoheart/version_skew_yank_awareness.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# 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.