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
49 changes: 0 additions & 49 deletions active.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,52 +13,3 @@
- registered: 2026-08-19 by the wake_up session — the issuing session (claude/autofit-priors-messages-audit-ylvenv)
filed the prompt + issue but not this entry, tripping Lifecycle Drift on main.
- repos-none-claimed: this entry claims NO repos — one line deliberately, not 2-space bullets.

## smoke-runner-delegation
- issue: https://github.com/PyAutoLabs/PyAutoHands/issues/260 (issued 2026-08-24)
- issued: 2026-08-24
- prompt: active/run_smoke_copy_drift.md
- status: library-dev
- worktree: ~/Code/PyAutoLabs-wt/smoke-runner-delegation
- decision: the prompt's blocking question is ANSWERED before any repo is touched —
the timeout/kill behaviour was PROMOTED to everyone (PyAutoHands#226/#227 → 52408a84;
all 10 copies import timeout_for + kill_group). Shape chosen: full delegation to a
PyAutoHands-owned runner, staged. Phase 1 = --list allowlist mode + the 4 *_workspace_test
copies; phase 2 = notebook leg + the 3 workspace copies; phase 3 = HowTo, no work.
- measured: 2026-08-24, from every repo's main — 10 copies, 3 variants, ZERO functional
drift inside any variant (workspace 356L byte-identical; workspace_test 198L comment-only;
HowTo 75L differ by PROJECT alone). Prompt steps 1 and 4 verified already done.
- registered: 2026-08-24 by the start_dev session (claude/smoke-copy-drift-ci-docs-ozntvv);
worktree_check_conflict clean (exit 0) for all 8 repos.
- status-detail: HANDS LEGS MERGED, workspace collapses not started. The task stays
active deliberately — issue #260 scopes seven workspace PRs that have zero commits,
so this is not complete and must not be recorded as such.
- library-pr: https://github.com/PyAutoLabs/PyAutoHands/pull/261 MERGED 2026-08-24 → c0e2e53
(both Hands legs: phase 1 `--list` opt-in script lists on run_python.py; phase 2
the matching notebook leg on run.py — `--list`, `--no-write-back`, `--retry-from`).
16 new tests; suite 388 passed / 5 skipped / 0 failed; CI green on all three
matrix legs (3.12/3.13/3.14) plus the tenant-firewall step in each.
- mind-pr: https://github.com/PyAutoLabs/PyAutoMind/pull/280 MERGED 2026-08-24 → 0cd8544a
- phase-2 findings (these changed the plan, recorded so the workspace PRs inherit them):
- run_notebook.py writes executed outputs back IN PLACE. Correct for generation
(the outputs are the product), wrong for a PR gate, which must not dirty the
tree it tests. Hence `--no-write-back`; it supersedes the workspace copy's
staged-copy-at-root trick rather than porting it, since the kernel cwd is
already pinned to the repo root.
- JUPYTER_MISSING_RC did NOT need promoting. It exists because the workspace copy
shelled out to a bare `jupyter`; execute_notebook invokes
`sys.executable run_notebook.py`, so the abort-with-no-summary failure mode is
structurally absent. One promotion item dissolved on inspection.
- remaining: the 7 workspace collapses (4 *_workspace_test 198L → ~75L, then 3 workspace
356L → ~75L), each a one-file PR modelled on HowToLens's delegator. UNBLOCKED as of
2026-08-24 — the library-first gate cleared when PyAutoHands#261 merged. Phase 3
(HowTo ×3) needs no work; it is already the end state.
The delegator invocations these PRs should use:
*_workspace_test: run_python.py <project> scripts --list smoke_tests.txt
--report-dir test-results
workspace: the above, plus run.py <project> notebooks
--list smoke_notebooks.txt --no-write-back --retry-from scripts
`--report-dir` is load-bearing: without it run_python.py never propagates failure
and the gate is vacuously green.
- repos:
- PyAutoHands (branch claude/smoke-copy-drift-ci-docs-ozntvv)
Original file line number Diff line number Diff line change
@@ -1,3 +1,118 @@
Ten repos each carried their own `.github/scripts/run_smoke.py` — the file
PyAutoHeart's reusable `smoke-tests.yml` invokes from inside each workspace, so
one must exist per repo. What was duplicated was not the file's existence but
its **driver loop**: read the allowlist, resolve per-entry env, spawn a
subprocess under the timeout cap, classify PASS/FAIL/TIMEOUT, accumulate, print
the summary, exit non-zero. Seven repos held that loop; the three HowTo repos
were already thin shims.

All ten are now shims. 2085 lines became 1127, and 1127 is mostly prose: of
`autolens_workspace_test`'s 77 lines, 32 are the docstring explaining why it
delegates.

## The argument, which was not "they have drifted"

The prompt was filed on a drift finding. Re-measured 2026-08-24 from every
repo's `main`, there was **zero functional drift inside any variant** — the
three workspace copies byte-identical, the four `_test` copies differing in two
docstring lines, the three HowTo copies in `PROJECT` alone.

That is not evidence the design was safe. It is the receipt for three manual
N-repo sweeps that had been paid to restore it: the env-resolver fork (#185),
the per-script timeout and process-group kill (#226/#227), and the jupyter
guard. The HowTo tier needed **none** of the three, precisely because it holds
no logic. The case for collapsing is maintenance cost, not drift.

The prompt's blocking question — "does autolens_workspace_test's timeout/kill
get promoted, or keep a documented divergence?" — was already answered by
promotion in #226/#227. All ten copies imported `timeout_for` and `kill_group`
before this task started; `_kill_group` existed in zero.

## The real obstacle was discovery model, not behaviour

The shared runners were opt-out (recursive discovery minus `no_run.yaml`); the
seven logic-bearing copies are opt-in allowlists (`smoke_tests.txt`,
`smoke_notebooks.txt`). That mismatch is why they could not delegate. So each
phase was a PyAutoHands feature first and per-repo edits second.

## Two bugs found by measuring before writing

**1. The `no_run`-wins rule would have deleted 13 scripts from smoke coverage
(#262).** #261 shipped "an explicit exclusion is the more specific intent, so
`no_run` wins over the allowlist". Measured against the real repos, that rule
would have silently skipped 9 scripts in autogalaxy_workspace_test, 2 in
autolens_workspace_test, 1 in autofit_workspace and 1 in autolens_workspace —
every one of which runs in smoke today, since the vendored runners never opened
`no_run.yaml` at all.

The rule was wrong because it conflated two policies for two different runs:
`no_run.yaml` governs the release mega-run and notebook generation, the
allowlist governs the PR gate, and a script legitimately appears in both. The
failure mode is the dangerous kind — **CI would have stayed green**, because a
skipped script is not a failure. Corrected to allowlist-authoritative before any
workspace was touched, and confirmed in production afterwards: autogalaxy's nine
all ran and passed, as did autolens's two and autofit's `searches/mcmc` in both
its script and notebook forms.

Same PR fixed a second blocker: `autocti_workspace_test` is the only workspace
with no `config/build/no_run.yaml`, and the autohands-level fallback path does
not exist either, so both runners crashed with `FileNotFoundError` before
running anything.

**2. `regenerate_notebook` resolved the source by bare filename (#263).** It
looked up `scripts_dir / nb_path.name`, dropping the subdirectory, so
`notebooks/imaging/model_fit.ipynb` searched for `scripts/model_fit.py`. Every
workspace notebook is in a subdirectory, so the stale-notebook recovery was dead
on arrival — and a bare filename can find the *wrong* source when two topics
share a name. The existing tests missed it because their fixture was **flat**,
which is the one layout where the bug is invisible. The replacement tests use a
nested notebook plus a decoy script at the scripts root, and were negative-tested
against the old resolution.

## What was proven rather than assumed

- **Env resolution is identical.** The old runners passed a *relative* script
path to `build_env_for_script`; the shared runners pass an *absolute* one. All
128 listed scripts across all seven repos were resolved both ways and diffed:
0 differences, in env and in args. Pattern matching is substring/stem based so
path form is irrelevant, and no profile pattern collides with the absolute
prefix.
- No profile sets per-script `args`, so the shared runners' extra-args support
changes nothing.
- Every allowlist entry resolves to a real file, and every listed notebook's
source script exists for the retry path.
- The two-leg exit code is the worst of both, verified in all three
pass/fail combinations — a failing notebook cannot be masked by passing
scripts.
- **Every merge was verified from the CI log, not the green tick**, because a
coverage regression here is indistinguishable from a pass. Each repo's
"Running N listed scripts/notebooks" was checked against its allowlist:
11/11, 22/22, 35/35, 3/3, 8/8+2/2, 14/14+2/2, 35/35+2/2.

## Traps for anyone touching this again

- `--report-dir` is load-bearing. `run_python.py` only propagates failure when a
report was built; without it the gate runs to completion and always exits 0.
- `run_notebook.py` writes executed outputs back **in place**. Correct for
generation, where the outputs are the product; wrong for a PR gate, which must
not dirty the tree it tests. Hence `--no-write-back`.
- `JUPYTER_MISSING_RC` did **not** need promoting. It existed because the
workspace copies shelled out to a bare `jupyter`; the shared runner invokes
`sys.executable run_notebook.py`, so the abort-with-no-summary mode is
structurally absent. One planned promotion item dissolved on inspection.
- A bare `off`/`on`/`yes` entry in `no_run.yaml` parses as a YAML **boolean** and
crashes `should_skip` with `TypeError: argument of type 'bool' is not
iterable`. Hit while building a fixture; not fixed, no repo currently has such
a script name.

## Still open

The merged `claude/smoke-copy-drift-ci-docs-ozntvv` branches across nine repos
were not deleted — this session's git proxy refuses delete refspecs
(`send-pack: unexpected disconnect`). They are all proven merged into `main`.

## Original prompt

# run_smoke.py: three runner variants across 10 repos, no sync mechanism

Type: maintenance
Expand Down
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.

1093 records across 7 buckets.
1094 records across 7 buckets.

<!-- CURATED:START -->
## Highlights
Expand Down Expand Up @@ -194,6 +194,7 @@ _(curate hard-won records here — survives regeneration.)_
- [small-datasets-loader-pixel-scales](2026/08/small-datasets-loader-pixel-scales.md)
- [small-datasets-regime-stamp](2026/08/small-datasets-regime-stamp.md)
- [small-datasets-rmtree-committed-data](2026/08/small-datasets-rmtree-committed-data.md)
- [smoke-runner-delegation](2026/08/smoke-runner-delegation.md)
- [smoke-runner-jupyter-guard](2026/08/smoke-runner-jupyter-guard.md)
- [spawn-autonomy-log-generated](2026/08/spawn-autonomy-log-generated.md)
- [spawn-drift-self-heal](2026/08/spawn-drift-self-heal.md)
Expand Down
17 changes: 8 additions & 9 deletions dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@
</head>
<body>
<header class="hero"><span class="orb">📋</span><h1>PyAuto<b>Mind</b><span class="kind">Dashboard</span></h1><p class="tag">Intent. Priority. Flow.</p></header><p class="lede">Every task the Mind is holding. Tap a task's 📋 and its <code>/start_dev</code> command is on your clipboard — paste it into a Claude Code chat to route Claude straight to that task. <a href="#recent">Recent</a> is the same work by date — what has been happening rather than what to do next.</p>
<ul class="stats"><li><b>2</b><span>In flight</span></li><li><b>3</b><span>Parked</span></li><li><b>6</b><span>Planned</span></li><li><b>155</b><span>Backlog</span></li></ul>
<ul class="stats"><li><b>1</b><span>In flight</span></li><li><b>3</b><span>Parked</span></li><li><b>6</b><span>Planned</span></li><li><b>155</b><span>Backlog</span></li></ul>
<p class="muted mdsrc"><a href="https://github.com/PyAutoLabs/PyAutoMind/blob/main/dashboard.md">markdown version</a></p>
<h2>Start here</h2>
<h3>Highest priority <span class="facets">(filed as high) — showing 12 of 17</span></h3>
Expand All @@ -145,7 +145,6 @@ <h3>Quick wins <span class="facets">(small enough, and safe enough to run unatte
<h2>In flight <a class="mdsrc" href="https://github.com/PyAutoLabs/PyAutoMind/blob/main/active.md">markdown version</a></h2>
<p class="muted">Issued — each has an open GitHub issue and usually a branch.</p>
<div class="task"><button class="copy" data-cmd="/start_dev active/16_transformed_message_factor_gradient_unpack.md" aria-label="Copy the Claude command">📋</button><p><a href="https://github.com/PyAutoLabs/PyAutoMind/blob/main/active/16_transformed_message_factor_gradient_unpack.md"><code>@PyAutoFit</code> <code>TransformedMessage.factor_gradient</code> crashes on first call</a> — <a href="https://github.com/PyAutoLabs/PyAutoFit/issues/1501">issue #1501</a><span class="facets"> — issued 2026-08-19</span> — <span class="facets">HOLD — do not start dev. Fix-or-delete hangs off the PyAutoFit#1498 logpdf-contract</span></p></div>
<div class="task"><button class="copy" data-cmd="/start_dev active/run_smoke_copy_drift.md" aria-label="Copy the Claude command">📋</button><p><a href="https://github.com/PyAutoLabs/PyAutoMind/blob/main/active/run_smoke_copy_drift.md">run_smoke.py: three runner variants across 10 repos, no sync mechanism</a> — <a href="https://github.com/PyAutoLabs/PyAutoHands/issues/260">issue #260</a><span class="facets"> — issued 2026-08-24</span> — <span class="facets">library-dev</span></p></div>
<h2>Parked <a class="mdsrc" href="https://github.com/PyAutoLabs/PyAutoMind/blob/main/parked.md">markdown version</a></h2>
<details>
<summary>3 task(s)</summary>
Expand Down Expand Up @@ -326,12 +325,6 @@ <h2>Backlog <a class="mdsrc" href="https://github.com/PyAutoLabs/PyAutoMind/tree
<p class="muted">The 50 newest things to happen to the work in hand, newest first — issued, parked, filed. Every other section on this page is laid out by state, which is exactly why none of them can answer “what has been happening?”. Shipped work is not here: it is read from <code>complete/index.md</code>, and a thousand records deep it would crowd out everything anyone can still act on. Showing the newest 10; … opens the next 10.</p>
<table class="recent">
<tr>
<td class="when">2026-08-24</td>
<td class="what">issued</td>
<td><a href="https://github.com/PyAutoLabs/PyAutoMind/blob/main/active/run_smoke_copy_drift.md">run_smoke.py: three runner variants across 10 repos, no sync mechanism</a></td>
<td class="pick"><button class="copy" data-cmd="/start_dev active/run_smoke_copy_drift.md" aria-label="Copy the Claude command">📋</button></td>
</tr>
<tr>
<td class="when">2026-08-23</td>
<td class="what">filed</td>
<td><a href="https://github.com/PyAutoLabs/PyAutoMind/blob/main/draft/maintenance/workspaces/pynufft_removal_downstream_residue.md">pynufft removal: unswept downstream residue (1 hard break + stale…</a></td>
Expand Down Expand Up @@ -385,7 +378,7 @@ <h2>Backlog <a class="mdsrc" href="https://github.com/PyAutoLabs/PyAutoMind/tree
<td><a href="https://github.com/PyAutoLabs/PyAutoMind/blob/main/draft/maintenance/libraries/remove_pynufft_legacy_transformer.md">Remove pynufft + legacy TransformerNUFFTPyNUFFT</a></td>
<td class="pick"><button class="copy" data-cmd="/start_dev draft/maintenance/libraries/remove_pynufft_legacy_transformer.md" aria-label="Copy the Claude command">📋</button></td>
</tr>
<tr hidden>
<tr>
<td class="when">2026-08-22</td>
<td class="what">filed</td>
<td><a href="https://github.com/PyAutoLabs/PyAutoMind/blob/main/draft/bug/pyautolens/point_source_json_datasets_record_no_regime.md">Point-source JSON datasets record no resolution regime</a></td>
Expand Down Expand Up @@ -625,6 +618,12 @@ <h2>Backlog <a class="mdsrc" href="https://github.com/PyAutoLabs/PyAutoMind/tree
<td><a href="https://github.com/PyAutoLabs/PyAutoMind/blob/main/draft/maintenance/autolens_workspace_developer/stale_api_rot_audit.md">autolens_workspace_developer: broad stale-API rot (56 symbols, no CI)</a></td>
<td class="pick"><button class="copy" data-cmd="/start_dev draft/maintenance/autolens_workspace_developer/stale_api_rot_audit.md" aria-label="Copy the Claude command">📋</button></td>
</tr>
<tr hidden>
<td class="when">2026-08-04</td>
<td class="what">filed</td>
<td><a href="https://github.com/PyAutoLabs/PyAutoMind/blob/main/draft/bug/workspaces/aplt_output_drift_remaining_repos.md"><code>aplt.Output</code> stale-API drift in the remaining workspace repos</a></td>
<td class="pick"><button class="copy" data-cmd="/start_dev draft/bug/workspaces/aplt_output_drift_remaining_repos.md" aria-label="Copy the Claude command">📋</button></td>
</tr>
</table>
<button class="more" data-page="10">… 10 more (40 left)</button>
<h2>Epics <a class="mdsrc" href="https://github.com/PyAutoLabs/PyAutoMind/blob/main/epics.md">markdown version</a></h2>
Expand Down
Loading
Loading