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
70 changes: 0 additions & 70 deletions active/release_yml_testpypi_rehearsal_mode.md

This file was deleted.

140 changes: 140 additions & 0 deletions complete/2026/06/build-testpypi-rehearsal-mode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# build-testpypi-rehearsal-mode

- shipped: 2026-06-30
- pr: https://github.com/PyAutoLabs/PyAutoHands/pull/111
- commit: `71936fb47c19fd6ba7b64fa9283bf7231e47b165`
- repos:
- PyAutoHands (the prompt targets "PyAutoBuild", this repo's former name)
- milestone: M1 — prerequisite for the Heart release-validation gate (M2)

## RECORD RECONSTRUCTED AFTER THE FACT (2026-08-08)

This record was **not** written at ship time by `ship_library`. The task shipped
on 2026-06-30 and nothing in the Mind was updated: the prompt stayed in
`active/`, and `planned.md` went on listing it as `status: planned` for six
weeks. It was found during the registry-integrity audit
(`draft/maintenance/pyautomind/registry_integrity_check.md`) and reconstructed
from upstream git evidence, which is why it carries less detail than a record
written by the ship path — there is no contemporaneous trap/finding log.

Everything below is verified against PyAutoHands `main`, not inferred.

## Summary

Added a TestPyPI-only `rehearsal` mode to `release.yml` so the release pipeline
can build and publish the current source to TestPyPI and **stop** — no PyPI
upload, no git tag, no notebook generation, no Colab-URL bumps. That is what
lets the Heart install and validate the actual wheels before any PyPI
promotion, which is the only way packaging-layer bugs (bad `MANIFEST`, missing
data file, direct-URL dependency) get caught.

## Evidence it shipped

In `PyAutoHands/.github/workflows/release.yml` on `main`:

- a `rehearsal` `workflow_dispatch` input, described in-file as "the one mode
switch: false (default) = a full real release";
- a `resolve_mode` job publishing `rehearsal` as a job output — the single
source of truth for rehearsal-vs-live;
- a unique PEP 440 dev segment appended per rehearsal run, so repeated
dispatches never collide, plus `--skip-existing` on the upload;
- the PyPI/tag/notebook jobs gated `if: needs.resolve_mode.outputs.rehearsal != 'true'`.

The merge commit body states the intent directly: *"to unblock the Heart
wheel-based release-validation gate (M2)"*, and notes it was "Validated live on
run #645".

It has been in production use since: the 2026-08-07 release drive ran Stage 2
as rehearsal run 31192317261 → `testpypi 2026.8.7.1.dev70601`.

## Scope delivered beyond the prompt

The same PR carried a dispatch-surface cleanup the prompt did not ask for:
removed the dead `skip_scripts` / `skip_notebooks` knobs, the redundant
`skip_release` dry-run (rehearsal supersedes it) and the defunct
`update_notebook_visualisations` job, leaving the dispatch surface as
`minor_version + rehearsal`. It also added a pre-upload direct-reference-URL
guard — the `[nss]` `git+` footgun named in the prompt's motivation — and
renamed Pulse→Heart, PyAutoAgent→PyAutoBrain.

## The milestone chain this belonged to

M1 of four, all four now shipped and all four discovered stale in `planned.md`
on the same day: M0 `heart-ci-linkage` (PyAutoHeart `heart/checks/ci_status.*`),
M1 this task, M2 `heart-release-validation` (`pyauto-heart validate --ingest`),
M3 `heart-release-profile-wheel-integration` (the named `release` profile in
`heart/validate.py`). The other three had no prompt file to fold and were
removed from `planned.md` rather than recorded.

## Original prompt

# Add a TestPyPI-only "rehearsal" mode to release.yml

Type: feature
Target: PyAutoBuild
Repos:
- PyAutoBuild
Status: planned
Difficulty: too-large
Autonomy: supervised
Priority: normal
Milestone: M1 — prerequisite for `feature/pyautoheart/release_validation.md` (M2)

## Why

The Heart-owned release-validation pipeline (see
`feature/pyautoheart/release_validation.md`) needs to test the organism against
**built wheels**, not source checkouts — that is the only thing that catches
packaging-layer bugs (a bad `MANIFEST`, a missing data file, a too-loose or
direct-URL dependency). Two real incidents in `complete.md` motivate this: the
PyAutoFit `[nss]` `git+` direct URL silently broke every TestPyPI upload for
weeks, and the nufftax/JAX dependency-floor mismatch produced broken installs —
neither was caught by the source-based validation.

`release.yml` already knows how to build and publish to TestPyPI (its
`release_test_pypi` job), but that capability is **coupled to the full
release** (TestPyPI → PyPI → tag → notebook commits in one flow). We need to be
able to build + publish the current source to TestPyPI **and stop**, so Heart
can install and validate those wheels before any PyPI promotion.

## Task

Add a `rehearsal` (TestPyPI-only) execution mode to `release.yml`:

- A new `workflow_dispatch` input (e.g. `rehearsal: true`, or reuse/extend the
existing skip flags) that:
- builds every package from current source and **publishes to TestPyPI**,
- then **STOPS** — no PyPI upload, no git tag, no `tag_and_merge`, no notebook
generation/commit to workspaces, no Colab-URL bumps.
- Emit the resolved TestPyPI version string as a workflow output / artifact so
the caller (Heart / Brain health agent) can install exactly those wheels.
- Keep the existing full-release path untouched and default.

This is intentionally small and isolated — it is the highest-value, lowest-risk
piece and unblocks the rest of the redesign. It does not change the full release
flow; it just exposes "build + TestPyPI, then halt" as a first-class mode.

## Notes / footguns

- Respect the "pure executor" boundary: `release.yml` runs no readiness checks;
it just builds/publishes. The gate lives in Heart.
- Verify the TestPyPI upload step tolerates re-runs of the same version
(TestPyPI rejects duplicate filenames) — the rehearsal will be dispatched
repeatedly. Use a dev/local version suffix or `--skip-existing` semantics as
appropriate.
- Confirm no `git+` direct URLs leak into any uploaded wheel's metadata
(the original `[nss]` failure) — a rehearsal that can't upload is the bug
this whole effort exists to surface early.

## Validation

- Dispatch the rehearsal mode manually; confirm wheels appear on TestPyPI, the
version string is emitted, and the workflow halts before PyPI/tag/notebook
steps.
- `pytest` in PyAutoBuild stays green.

## PR

"PyAutoBuild: TestPyPI-only rehearsal mode in release.yml".

<!-- formalised retroactively by the Intake (Conception) Agent on 2026-07-08 -->
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.

939 records across 7 buckets.
940 records across 7 buckets.

<!-- CURATED:START -->
## Highlights
Expand Down Expand Up @@ -576,6 +576,7 @@ _(curate hard-won records here — survives regeneration.)_
- [autolens-jax-simulator-release-fixes](2026/06/autolens-jax-simulator-release-fixes.md)
- [autolens-results-aggregator-valid-dataset](2026/06/autolens-results-aggregator-valid-dataset.md)
- [bib-duplicate-keys](2026/06/bib-duplicate-keys.md)
- [build-testpypi-rehearsal-mode](2026/06/build-testpypi-rehearsal-mode.md)
- [dark-matter-potentials](2026/06/dark-matter-potentials.md)
- [datacube-delaunay-release-memory](2026/06/datacube-delaunay-release-memory.md)
- [datacube-shared-state](2026/06/datacube-shared-state.md)
Expand Down
90 changes: 90 additions & 0 deletions draft/maintenance/pyautomind/active_prompt_orphan_triage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Triage the 8 orphaned active/ prompts, then make `orphans` a gate

Type: maintenance
Target: PyAutoMind
Repos:
- PyAutoMind
Difficulty: medium
Autonomy: supervised
Priority: normal
Status: formalised

`scripts/lifecycle.py orphans` reports **8 of 10** prompts in `active/` that no
registry entry claims. Each is work whose state nobody is tracking. Triage them,
dispose of each, then flip the reporter into a gate.

## Background

`check` gained registry-integrity validation on 2026-08-08
(`draft/maintenance/pyautomind/registry_integrity_check.md`), covering the
direction **registry → prompt**: every `prompt:` path resolves, exactly, into
the state folder its registry implies. The audit that motivated it found six
`planned.md` entries for work that had already shipped — including the whole
M0–M3 release-validation milestone chain.

`orphans` is the mirror direction, **prompt → registry**, and it was added in
the same pass but deliberately left **report-only**: it exits 0 unless given
`--check`. Wiring it into `check` immediately would have left the tree red with
8 findings, and a red gate nobody can turn green gets ignored or disabled. The
condition is only worth gating once the backlog is at zero.

## The inventory (2026-08-08)

```
active/benchmark_calibration_runs.md
active/ep_optimise_expose_updater_delta.md
active/euclid_eceb_editorial_revision.md
active/fix_workspace_start_here_colab_links.md
active/matplotlib_inline_standalones.md
active/pyautoreduce_slacs1430_acs_comparison.md
active/research_profiling_experiment_in_the_autolens_pr.md
active/workspace_version.md
```

**One is already diagnosed.** `ep_optimise_expose_updater_delta.md` belongs to
the `ep-optimise-updater` entry in `active.md`, which records
`status: COMPLETE 2026-08-08` with both PRs merged (PyAutoFit #1457 →
`3b960609`, autofit_workspace #136 → `cf8b4077`). That is finished work still
sitting in `active.md`, so it wants the normal ship disposal:
`lifecycle.py record ep-optimise-updater --date 2026-08-08 --from-file <body>
--prompt ep_optimise_expose_updater_delta.md --apply`, which writes the record,
folds the prompt and drops the `active.md` section in one step. The entry
already carries enough substance for a rich record. It is an orphan only
because the entry declares no `prompt:` field and the slug does not match the
filename stem.

The remaining seven need the same question answered individually: **shipped,
still in flight, or abandoned?** Answer it against the upstream repo, not from
the prompt's own text — that is the lesson of the M0–M3 chain, where every
prompt still read as pending while the capability was live on `main`.

## Disposal per outcome

- **Shipped** → `lifecycle.py record <slug> --date <YYYY-MM-DD> --from-file
<body> --prompt <name> --apply`. If the record has to be reconstructed after
the fact, say so in it and cite the upstream commit/PR — see
`complete/2026/06/build-testpypi-rehearsal-mode.md` for the shape.
- **In flight** → add the missing `active.md` entry, including a `prompt:`
field so the claim is by path rather than by slug coincidence.
- **Abandoned** → `complete/archive/shelved/`, or `condemned.md` if it is
self-material for the Gut's transit-and-void lifecycle.

## Then close the loop

Once `lifecycle.py orphans` reports none:

1. call `orphan_prompts(ROOT)` from `cmd_check` so the condition becomes drift,
and delete the report-only carve-out documented in `cmd_orphans`;
2. move the three orphan tests in `tests/test_lifecycle_check.py` under the
`check` legs alongside the registry ones;
3. consider requiring a `prompt:` field on every `active.md` entry that has a
prompt file. Slug-matching exists only because entries predate the
convention, and it is the weaker claim — `ep-optimise-updater` shows a real
entry and its real prompt failing to match on name alone.

## Acceptance

- `python3 scripts/lifecycle.py orphans` prints `none`.
- Every disposal is evidenced: a `complete/` record with an upstream
commit/PR, a new `active.md` entry, or an archive/condemned move.
- `orphans` is called from `cmd_check`, and `pytest tests/` is green.
Loading
Loading