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
123 changes: 123 additions & 0 deletions complete/2026/07/version-drift-stamp-consistency.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
- issue: none (the prompt was never issued — the fix shipped inside a `/wake_up` session's branch)
- delivered-by: **PyAutoBrain#144** — commit `e26ab17` *"fix: version_drift checks stamp consistency, not equality-to-release-tag"* (2026-07-19, branch `claude/wake-up-u53v8z`)
- classification: library (PyAutoBrain) — bug
- LEDGER BACKFILL, not new work: this record was written 2026-08-08 when the prompt was
picked up for development and found already delivered. No code was written for it.
PyAutoBrain#144 had **no** completion record until this one, so the ledger carried a gap.
- prompt Status was stale: it read `fix-implemented-on-branch (claude/wake-up-u53v8z) —
pending review/merge`. That branch merged 2026-07-19; the status was never advanced,
which is what made the prompt look open.

## What was wrong

`bin/version_drift.sh` compared each library/workspace's committed source version stamp
(`*/__init__.py` `__version__`, workspace `version.txt`) against the latest PyAutoLens
**release tag** and flagged any mismatch as drift. The release design deliberately
abandoned that invariant: `release.yml` stamps `__version__` into the wheel build tree
only and does **not** commit it back, because daily "Update version to X" commits to
every library main were the noise engine behind the June/July 2026 accidental-release
cascade (PyAutoBuild#118 / #120). pip users get the version from the stamped wheel;
source checkouts stay frozen.

So the check reported drift after **every** release, indefinitely — pure `/wake_up`
noise, and misleading, since it read as a release defect when the release was fine.

## What shipped

**Option 2 of the three the prompt offered** — honour the freeze, flag only
*non-uniform* stamps:

- The invariant is now "every coupled repo carries the SAME stamp as its siblings";
a repo out of step with the consensus is flagged. The latest release tag is shown
for context only, with a consensus trailing the tag reported as the expected freeze
rather than drift.
- `gh` became optional — the reference tag is informational, so the consensus check
runs on local stamps without it, which is what makes the script usable in web/CI
sessions.
- Fixed a stale stamp path left by the organ rename: `PyAutoConf/autoconf` →
`PyAutoNerves/autonerves`.
- Both documentation updates the prompt required: the `version_drift.sh` header comment
(which still described the tag-equality model) and the `/wake_up` skill step-5 wording.

Verified in that PR: uniform frozen stamps read clean; a single out-of-step stamp is
still flagged — i.e. the reframe did not simply disable the check.

## Verification done before retiring the prompt (2026-08-08)

- `git merge-base --is-ancestor e26ab17 origin/main` → true, so the fix is on main.
- Read the shipped `bin/version_drift.sh`: header now documents the freeze and the
consensus invariant; no `== latest release tag` comparison survives.
- Read `skills/wake_up/wake_up.md` step 5: reworded to "version-stamp *consistency
across the coupled libs + workspaces* … the latest release tag is shown for context
only". Both doc requirements satisfied.

## Note

Option 3 (retire the script in favour of Heart's `version_skew` check) was not taken
and remains a live option — `version_drift.sh` still exists. Nothing depends on
revisiting it; recorded only so a future reader knows it was considered and left open
rather than overlooked.

## Original prompt

# version_drift.sh reports permanent false drift — asserts an abandoned invariant

Type: bug
Target: pyautobrain
Repos:
- PyAutoBrain
Difficulty: small
Autonomy: safe
Priority: normal
Status: fix-implemented-on-branch (claude/wake-up-u53v8z, PyAutoBrain) — pending review/merge

`PyAutoBrain/bin/version_drift.sh` compares each library/workspace's committed
source version stamp (`*/__init__.py` `__version__`, workspace `version.txt`)
against the latest PyAutoLens **release tag**, and flags any mismatch as drift.
That invariant (committed source stamp == latest release tag) was **deliberately
abandoned** by the release design.

Evidence (2026-07-19 wake-up): reference tag `2026.7.19.1` (published 13:52),
but every stamp — PyAutoNerves / PyAutoArray / PyAutoFit / PyAutoGalaxy /
PyAutoLens and the autofit/autogalaxy/autolens workspace `version.txt` — reads
`2026.7.9.1`. Verified against GitHub `main` **and** the `2026.7.19.1` tag
commit (identical blob SHA `19b7d518`): the source stamp is frozen there too, so
this is not container/mirror staleness — the stamp genuinely is not bumped on
release.

Root cause (working as intended, NOT a release bug): `PyAutoHands/.github/
workflows/release.yml` (step "Stamp version in build tree", ~L394-403) seds
`__version__` into the **wheel build tree only** and does not commit it back.
The inline comment is explicit: *"the stamp is NOT committed back to the library
repo. Daily 'Update version to X' commits to every library main were the
stale-CI/noise engine behind the June/July 2026 accidental-release cascade
(PyAutoBuild#118 / #120); pip users get __version__ from the stamped wheel,
source checkouts use PYAUTO_SKIP_WORKSPACE_VERSION_CHECK."* So PyPI wheels are
correctly versioned; the committed source stamp is intentionally frozen.

Consequently `version_drift.sh` will report drift after **every** release,
indefinitely (the source stamp is never advanced again) — pure noise in the
`/wake_up` digest, and misleading: it reads as a release defect when the release
is fine.

Fix options (pick during triage):
1. **Re-point the reference to what pip users actually get** — compare the
published PyPI / wheel version per package against the latest release tag
(the meaningful post-cascade invariant), not the deliberately-frozen source
stamp.
2. **Honor the documented skip semantics** — treat a uniformly-frozen source
stamp as expected (mirror `PYAUTO_SKIP_WORKSPACE_VERSION_CHECK`), only
flagging *non-uniform* stamps (one repo out of step with the others), which
is the real drift worth catching.
3. **Retire the script** if Heart's `version_skew` check (pinned-dep skew,
already green) covers the remaining need.

Whichever is chosen, update the `version_drift.sh` header comment (it still
describes the tag-equality model) and the `/wake_up` skill step 5 wording.

Note: this is the same class of defect as the origin drift-check false-positive
fixed on the `claude/wake-up-u53v8z` branch (repos_sync.py `normalize_remote`
made host-agnostic) — a wake-up check encoding an invariant that reality no
longer holds. Found during the 2026-07-19 `/wake_up` version-pin investigation.

<!-- formalised from a /wake_up investigation, 2026-07-19 -->
138 changes: 138 additions & 0 deletions complete/2026/08/hygiene-gone-ref-counter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
- issue: none (the prompt was never issued — the defects were fixed under other issues, see below)
- delivered-by: **PyAutoBrain#205** (squashed `7ad1e43`, 2026-08-07) and **PyAutoBrain#200** (squashed `5cb1c73`, 2026-08-05, issue PyAutoBrain#197)
- classification: library (PyAutoBrain) — bug, infrastructure
- LEDGER BACKFILL, not new work: this record was written 2026-08-08 when the prompt
was picked up for development and found already delivered. No code was written for
it. Defect 2's delivery is separately recorded in
`complete/2026/08/hygiene-coverage-drift.md`; Defect 1 (#205) had **no** record
until this one, so the ledger carried a gap.

## What the prompt claimed

`hygiene tidy` under-reported git debris by roughly an order of magnitude — it
reported "12 stale branches across 9 repos, 0 stashes, 0 [gone] refs, 0 dirty
checkouts" when the real state was 91 branches across 28 repos, 4 stashes, dozens of
`[gone]` refs and 3 dirty checkouts. Two independent defects.

## Both defects were already fixed

**Defect 1 — the `[gone]` counter could never be non-zero.** `prescan_tidy` counted
with `git branch -vv | grep -c '\[gone\]'`, but porcelain prints the upstream as
`[origin/<branch>: gone]`, never the bare `[gone]`, so the pattern matched nothing in
every repo, always. Fixed by **PyAutoBrain#205** (2026-08-07), which switched to
`for-each-ref --format='%(upstream:track)'` — the idiom
`enumerate_condemn_candidates` and `repo_cleanup` already used — and added a
regression test building a fixture with a genuinely gone upstream, verified to fail on
the unfixed counter.

**Defect 2 — the scan covered 9 repos, not the organism.** `prescan_tidy` iterated
hardcoded `LIB_REPOS` + `ORG_REPOS` literals, so PyAutoCTI, PyAutoReduce, PyAutoMemory,
every workspace, every HowTo and every assistant were invisible; the "0 stashes" and
"0 dirty checkouts" figures were scope artifacts, not detector bugs. Fixed by
**PyAutoBrain#200** (2026-08-05): `LIB_REPOS`/`ORG_REPOS`/`WS_REPOS` are now derived
from the body map via `_hygiene_repos.py` reading `repos.yaml`, with a
`repos_sync.py` coverage check that fails if they drift from the map or if a repo name
is written back into an array literal. That is exactly the resolution the prompt asked
someone to decide on, and it names the same `_hygiene_extras.py`/PR#193 precedent.

## Verification done before retiring the prompt (2026-08-08)

The prompt specified its own control: *"Before the fix, `prescan_tidy` must reproduce
`0 [gone] refs` on a checkout known to have some. After, the count must be non-zero on
that same tree. A green run on a tree with zero `[gone]` refs proves nothing — pick the
tree first."* That control was run rather than assumed:

- Built a throwaway repo with a real bare remote, pushed a branch, deleted it on the
remote, and `fetch --prune`d so the checkout genuinely carried a `[gone]` ref.
- On that same tree: the old form `git branch -vv | grep -c '\[gone\]'` → **0**;
the shipped form `for-each-ref '%(upstream:track)' | grep -c '\[gone\]'` → **1**.
- Confirmed no repo-name array literal survives anywhere in `hygiene.sh` — every loop
runs over the derived `CODE_REPOS`/`SCAN_REPOS`, including `run_tidy` and
`enumerate_condemn_candidates`, the two the prompt named as sharing the limitation.

## Trap worth keeping

Establishing "already fixed" required deepening the clone. Cloud-session checkouts are
**shallow** (`git rev-parse --is-shallow-repository` → true), and a shallow PyAutoBrain
makes `git diff origin/main...<branch>` fail with `no merge base` and makes
`git log origin/main..<branch>` list commits that ARE on main. Both look like evidence
of divergence and are artifacts of the graft boundary. `git fetch --deepen=500` first,
then test ancestry with `git merge-base --is-ancestor`.

## Original prompt

# The hygiene tidy pre-scan reports 0 [gone] refs unconditionally, and scans only 9 of ~28 repos

Type: bug
Target: PyAutoBrain
Repos:
- PyAutoBrain
Difficulty: small
Autonomy: supervised
Priority: normal
Status: formalised

Found during a `/repo_cleanup` sweep on 2026-08-04. `hygiene tidy` reported
"12 stale branches across 9 repos, 0 stashes, 0 [gone] refs, 0 dirty checkouts".
The real state at that moment was 91 branches across 28 repos, 4 stashes,
dozens of [gone] refs and 3 dirty checkouts.

Two independent defects produce that gap.

## Defect 1 — the `[gone]` counter can never be non-zero

`agents/conductors/hygiene/hygiene.sh:129`:

g=$(git -C "$dir" branch -vv 2>/dev/null | grep -c '\[gone\]' || true)

`git branch -vv` prints the upstream as `[origin/<branch>: gone]`, never the
bare `[gone]`. The pattern matches nothing, in every repo, always. Proof on
PyAutoHands, which had three at the time:

git branch -vv | grep -c '\[gone\]' -> 0
for-each-ref --format='%(upstream:track)' refs/heads -> [gone] x3

`prescan_tidy` then folds `gone` into the `total` at line 133-134, so the
conductor's prioritisable count for `tidy` is systematically understated and
`tidy` under-ranks itself against the other hygiene modes.

Fix: count via `for-each-ref '%(upstream:track)'` (already the idiom used in
`repo_cleanup`'s own audit), or match `: gone]`.

Note `enumerate_condemn_candidates` at line 419 does NOT share this bug — it
uses `for-each-ref` correctly.

## Defect 2 — the scan covers 9 repos, not the organism

`prescan_tidy` (line 121) iterates `LIB_REPOS` + `ORG_REPOS` only:

LIB_REPOS=(PyAutoNerves PyAutoFit PyAutoArray PyAutoGalaxy PyAutoLens)
ORG_REPOS=(PyAutoBrain PyAutoHands PyAutoHeart PyAutoMind)

That is the "9 repos" in the summary line. Invisible to it: PyAutoCTI,
PyAutoReduce, PyAutoMemory, PyAutoGut, PyAutoScientist, every workspace, every
HowTo, every assistant, autolens_profiling, admin_jammy. Both the "0 stashes"
and "0 dirty checkouts" figures were scope artifacts, not detector bugs — all 4
stashes and all 3 dirty trees lived in repos it never looks at.

Decide whether the fix is to derive the repo set from `PyAutoMind/repos.yaml`
(the body map) rather than re-listing it, which is the same hard-coding problem
`_hygiene_extras.py` was just refactored to remove in PR #193. `run_tidy` /
`enumerate_condemn_candidates` share the same two lists and the same limitation.

## Why it matters

`hygiene tidy` is the advertised front door for git debris and the thing a
human reads before deciding whether a cleanup is worth running. Under-reporting
by roughly an order of magnitude makes it read as "nothing much to do" when
there is. A wrong-but-quiet number is worse than no number.

## Control

Before the fix, `prescan_tidy` must reproduce `0 [gone] refs` on a checkout
known to have some (any repo with a merged-and-deleted upstream). After, the
count must be non-zero on that same tree and match
`for-each-ref | grep -c '\[gone\]'`. A green run on a tree with zero [gone] refs
proves nothing — pick the tree first.

<!-- raised from a /repo_cleanup sweep, 2026-08-04 -->
4 changes: 3 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.

935 records across 7 buckets.
937 records across 7 buckets.

<!-- CURATED:START -->
## Highlights
Expand Down Expand Up @@ -34,6 +34,7 @@ _(curate hard-won records here — survives regeneration.)_
- [hst-dq-bits-dial](2026/08/hst-dq-bits-dial.md)
- [hygiene-coverage-drift](2026/08/hygiene-coverage-drift.md)
- [hygiene-detail-flag](2026/08/hygiene-detail-flag.md)
- [hygiene-gone-ref-counter](2026/08/hygiene-gone-ref-counter.md) — the prompt was never issued — the defects were fixed under other issues, see below
- [hygiene-howto-refs-docstrings](2026/08/hygiene-howto-refs-docstrings.md)
- [interferometer-delaunay-flaky-fitexception](2026/08/interferometer-delaunay-flaky-fitexception.md)
- [interferometer-start-here-integrate-oom](2026/08/interferometer-start-here-integrate-oom.md)
Expand Down Expand Up @@ -545,6 +546,7 @@ _(curate hard-won records here — survives regeneration.)_
- [validation-searches-env-optax](2026/07/validation-searches-env-optax.md)
- [verify-install-check-f-autosimulate-and-dep-pin](2026/07/verify-install-check-f-autosimulate-and-dep-pin.md)
- [version-check-compat-floor](2026/07/version-check-compat-floor.md)
- [version-drift-stamp-consistency](2026/07/version-drift-stamp-consistency.md) — the prompt was never issued — the fix shipped inside a `/wake_up` session's branch
- [version-pinning-design-review](2026/07/version-pinning-design-review.md)
- [viz-refactor-asserts-1280](2026/07/viz-refactor-asserts-1280.md) — Two visualization sweep-assert failures, both diagnosed as env-config (NOT code bugs); workspace-only, no libr…
- [viz-render-gallery](2026/07/viz-render-gallery.md) — Eyes agent Phase 1
Expand Down
75 changes: 0 additions & 75 deletions draft/bug/pyautobrain/hygiene_gone_ref_counter_always_zero.md

This file was deleted.

Loading
Loading