Skip to content

prompt: complete covariance-interpolator-rng-seed (PyAutoFit#1451 merged) - #128

Merged
Jammy2211 merged 2 commits into
mainfrom
claude/covariance-interpolator-rng-seed-8zexp3
Aug 6, 2026
Merged

prompt: complete covariance-interpolator-rng-seed (PyAutoFit#1451 merged)#128
Jammy2211 merged 2 commits into
mainfrom
claude/covariance-interpolator-rng-seed-8zexp3

Conversation

@Jammy2211

Copy link
Copy Markdown
Collaborator

Closes out the task now that PyAutoLabs/PyAutoFit#1451 is merged (282d8e1e,
auto-closing PyAutoLabs/PyAutoFit#1450). The Class B release blocker that killed
the 2026.8.2.1 live release is cleared
, green on Python 3.12 and 3.13.

Branch restarted from main — the previous PR (#127) is merged, so this is fresh
work rather than commits stacked on merged history. The force-with-lease that
repointed the branch discarded only e3419110, the commit squash-merged as
acc4a7dd; verified the tree diff against main for every touched path is empty
before pushing.

What changed

All four edits produced by scripts/lifecycle.py record ... --apply — the ship
skills' own primitive, not hand-editing:

  • complete/2026/08/covariance-interpolator-rng-seed.md — new rich completion
    record, with the original prompt folded in under ## Original prompt.
  • active/covariance_interpolator_test_unseeded_rng.md — removed (folded into
    the record).
  • active.mdcovariance-interpolator-rng-seed section removed.
  • complete/index.md — regenerated (890 records).

lifecycle.py check → OK · lifecycle.py index --check → OK.

Why the record leads with the finding, not the fix

The prompt's premise was wrong, and that is the part worth surviving:

  • It blamed the unseeded np.random.random() in the test body and called seeding
    "a one-liner". Seeding only that leaves std at 1.95 of 2.05 — the test still
    fails.
    The dominant source is dynesty's rstate
    (Generator(PCG64(None)), OS entropy, reachable from neither np.random nor a
    local Generator), with the stdlib random module used by initializer.py
    third. All three must be seeded.
  • Measured pre-fix failure rate 1.65% (33/2000, 95% CI 1.18–2.31%) — taken
    before any change, as the prompt's step 2 required.
  • The tolerance is not mis-calibrated. A full untruncated search recovers
    25.0496 ± 0.0039 — 500× tighter — so abs=5.0 is correct and must not be
    loosened. limit_maxcall is what turns the assertion into a coin flip.
  • The sibling was worse. test_single_variable has no random call of its own
    yet was flaking at 3.6%, more than double the test that got blamed.
  • The LinAlgError guards are a separate defect — rank-deficient fixture
    matrix (rank 6 of 9, cond 1.3e17), deterministic input — not the same
    nondeterminism in disguise.

The record also carries the known limitation, so nobody later reads "seeded" as
"the assertion is now meaningful": under maxcall=1 both are frozen-RNG
regression checks, with the measured cost of restoring real convergence.

It also notes this closes the "gate said GREEN, then the live release
contradicted it" question in draft/triage/nightly_release_blocked_eight_nights.md
— the gate's evidence was not stale; the release run drew a different random
sample. That removes the motive for a gate-vs-release redesign this evidence was
about to justify.

Still open

draft/feature/autofit/search_seed_reproducibility.md stays in draft/ — the
real fix. PyAutoFit has no supported way to seed a search, which is why the
merged change must monkeypatch a third-party module from a test, and why users
cannot reproduce a fit.

🤖 Generated with Claude Code

https://claude.ai/code/session_016vdGab4C5rWumTCXkWHPyh


Generated by Claude Code

claude and others added 2 commits August 5, 2026 05:57
…ged)

Advances the task to complete/2026/08/ and removes it from active.md.
PyAutoFit#1451 merged as 282d8e1e, auto-closing issue #1450; the Class B
release blocker that killed 2026.8.2.1 is cleared, green on 3.12 and 3.13.

The record leads with the finding rather than the fix: the prompt's premise
was wrong. The unseeded np.random.random() it blamed is a minor contributor
- seeding only it leaves std at 1.95 of 2.05 and the test still fails. The
dominant source is dynesty's rstate (Generator(PCG64(None)), OS entropy,
reachable from neither np.random nor a local Generator), with the stdlib
random module used by initializer.py third. Measured pre-fix failure rate
1.65% (33/2000, 95% CI 1.18-2.31%).

Also recorded: the tolerance is NOT mis-calibrated (a full search recovers
25.0496 +/- 0.0039, 500x tighter) so abs=5.0 must not be loosened; the
sibling test_single_variable was flaking worse at 3.6% with no random call
of its own; and the LinAlgError guards are a separate defect (rank-deficient
fixture matrix, deterministic input) rather than the same nondeterminism.

The known limitation is recorded so nobody later reads "seeded" as "the
assertion is now meaningful" - under maxcall=1 both are frozen-RNG
regression checks. The real fix stays open as
draft/feature/autofit/search_seed_reproducibility.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016vdGab4C5rWumTCXkWHPyh
…erpolator-rng-seed-8zexp3

# Conflicts:
#	complete/index.md
@Jammy2211
Jammy2211 merged commit b2d203d into main Aug 6, 2026
@Jammy2211
Jammy2211 deleted the claude/covariance-interpolator-rng-seed-8zexp3 branch August 6, 2026 18:36
Jammy2211 pushed a commit that referenced this pull request Aug 16, 2026
…mentation

The clip-count work is written and tested against PyAutoFit 1f4b66a, but push
access to PyAutoFit was denied in this session, so it lands as a patch rather
than a PR. Prompt updated to say so and to carry the verification evidence.

Corrects a wrong premise in the prompt as first filed. It claimed search.summary
had "no search-specific channel at all". That is false: search_summary_from_samples
(text_util.py:115-161) already reads samples.samples_info and already emits
Resurrections, Value-NaN Lane-Steps, Gradient-NaN Lane-Steps and both rates,
key-guarded so other searches are unaffected. I had read search_summary_to_file
and not the function it calls. Left uncorrected it would have sent an
implementer off to build a routing mechanism that already exists.

The real gap is narrow: n_clipped_lane_steps never reaches samples_info, and
n_constrained_lane_steps reaches it but is never emitted — so PyAutoFit#1475's
trapped-lane counter has been invisible in search.summary since it shipped.

As built (tmp/clipper-search-summary.patch, gitignored, 4 files +243/-0):
multistart publishes clipper name + n_clipped_lane_steps into samples_info;
bfgs publishes the clipper name and deliberately no count, since it is
declarative and scipy enforces, so a 0 would read as "never fired" when it
means "cannot know"; text_util grows _clipper_summary_from handling the three
cases plus the owed Constrained Lane-Steps line; 6 new tests.

Verified on 3.13: non_linear + text = 501 passed, 3 skipped, 1 failed, the
failure (nautilus single-core pool) reproduced identically on a stashed clean
tree, as was the astropy collection error — both already recorded under
complete/2026/08/frozen-lane-counter.md. Also verified end-to-end against the
search.summary files four real searches actually wrote, giving
Clipped Lane-Steps = 414 at rate 0.958 on the clipped multistart arm.

Incidental, worth keeping: on that toy 3-parameter Gaussian the unclipped arm
showed Value-NaN Lane-Steps = 378 (94.5%) and the clipped arm 0 — the #128
mechanism reproducing on a model with nothing astrophysical in it, which makes
a far cheaper regression fixture than the imaging/mge cell.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FzF2XmKQaqZRWZfZMxvTNR
Jammy2211 added a commit that referenced this pull request Aug 16, 2026
… what was owed (#190)

* prompt: file the three follow-ups the lane-death investigation left owed

Closes out the Clipper handover. Three findings from autolens_profiling#128
were living only inside other prompt files, where nothing indexes them and
nobody can pick them up. All three are now filed prompts.

Two incidental PyAutoFit bugs, split out of prior_support_clipper.md's
"do not lose these" section, which asked for them to be filed separately
once confirmed. Both confirmed against PyAutoFit main 1f4b66a93:

- save_json_numpy_scalar_typeerror.md — paths/directory.py:80 is a bare
  json.dump with no default= hook, and there is no JSON encoder anywhere in
  autofit/. numpy float32 raises TypeError at the END of a successful run.
  It did not fire while 14/16 lanes were dead, so it fires exactly when lane
  survival improves — any fix to the prior-support problem will surface it.

- crashed_run_poisons_resume.md — the chain, each link read on main:
  directory.py:79 opens "w+" (truncates, no atomic rename), so the crash above
  leaves a partial file; is_complete (directory.py:180) tests only the
  .completed marker, so abstract_search.py:582 dispatches to resume; the
  resume reads the truncated JSON; and JSONDecodeError subclasses ValueError,
  so the guard at multi_start_gradient/search.py:720 catching
  (FileNotFoundError, TypeError, KeyError) does not fall through to the
  fresh-start branch. Result is a zero-step no-op reported as a clean run —
  the phase-2 campaign currently documents this as a trap to work around.

One research task, follow-up (2) owed by active/mge_lane_death.md:

- ell_comps_trapping_unmasked.md — the plateau was masked, not cleared. The
  baseline n_constrained_lane_steps = 0 meant "nothing got that far"; lanes
  died of prior-exit first. Records that the 27.79% came from the
  prior-neutered diagnostic arm and is NOT a citable production number, so
  the task sequences after phase 1 and measures the clipped run instead.

active.md now points at all five filed prompts (these three plus the two
Clipper phases) so the thread is followable from the ledger. dashboard.md
regenerated; lifecycle check OK.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FzF2XmKQaqZRWZfZMxvTNR

* prompt: retire the shipped Clipper phase 1, file the clip-count reporting gap

Phase 1 has landed. PyAutoFit#1477 merged as 1f4b66a — the current tip of
PyAutoFit main — shipping AbstractClipper / ClipperNone / ClipperPriorBox in
autofit/non_linear/clipper.py, wired into both AbstractMultiStartGradient and
AbstractBFGS, opt-in, default ClipperNone, bit-identical under it, 22 tests.

The Mind had not noticed: prior_support_clipper.md was still sitting in
draft/ as a high-priority backlog item on a dashboard people pick work from.
Retired to complete/2026/08/prior-support-clipper.md via lifecycle.py record,
with the original prompt folded in and the findings worth keeping written up
(the inset keyed on bound kind rather than unguarded upper-lower; the
LogGaussianPrior support mismatch; scipy reading a bounds tuple as (min, max)
pairs and silently mis-fitting two-parameter models).

Clip-count reporting, filed as clipper_usage_in_search_summary.md. The
counting half already exists — n_clipped_lane_steps is accumulated per-lane
(not per-coordinate) at multi_start_gradient/search.py:863, written to
search_internal and restored on resume as a lifetime total. The storing half
does not, and the gap is not where it looks:

- search.summary is written by text_util.search_summary_to_file, which only
  ever sees samples and timings. There is no search-specific channel at all,
  for any counter — save_summary never sees search_internal. Routing is the
  work, not the arithmetic, which is why the prompt asks for a general hook
  serving the other multi-start counters rather than one threaded parameter.
- LBFGS produces no count whatsoever. It hands optimize.Bounds to scipy and
  never calls project, so there is no mask to count. Emitting 0 there would
  read as "never fired" when it means "cannot know".

Phase 2 (clipper_validation_campaign.md) marked UNBLOCKED with what phase 1
changed for it: record n_clipped_lane_steps as a fourth counter from
search_internal; a ClipperPriorBox arm reporting zero clips has not exercised
the clipper and its "no change" result is meaningless; the momentum-reset arm
needs writing since nothing yet consumes the mask; and the float32 save_json
crash was NOT fixed by phase 1 (verified at 1f4b66a), so that trap stands and
will start firing precisely because clipping keeps lanes alive.

Repointed all seven references to the moved prompt. lifecycle check + index
check OK; dashboard regenerated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FzF2XmKQaqZRWZfZMxvTNR

* prompt: correct the search.summary premise, record the verified implementation

The clip-count work is written and tested against PyAutoFit 1f4b66a, but push
access to PyAutoFit was denied in this session, so it lands as a patch rather
than a PR. Prompt updated to say so and to carry the verification evidence.

Corrects a wrong premise in the prompt as first filed. It claimed search.summary
had "no search-specific channel at all". That is false: search_summary_from_samples
(text_util.py:115-161) already reads samples.samples_info and already emits
Resurrections, Value-NaN Lane-Steps, Gradient-NaN Lane-Steps and both rates,
key-guarded so other searches are unaffected. I had read search_summary_to_file
and not the function it calls. Left uncorrected it would have sent an
implementer off to build a routing mechanism that already exists.

The real gap is narrow: n_clipped_lane_steps never reaches samples_info, and
n_constrained_lane_steps reaches it but is never emitted — so PyAutoFit#1475's
trapped-lane counter has been invisible in search.summary since it shipped.

As built (tmp/clipper-search-summary.patch, gitignored, 4 files +243/-0):
multistart publishes clipper name + n_clipped_lane_steps into samples_info;
bfgs publishes the clipper name and deliberately no count, since it is
declarative and scipy enforces, so a 0 would read as "never fired" when it
means "cannot know"; text_util grows _clipper_summary_from handling the three
cases plus the owed Constrained Lane-Steps line; 6 new tests.

Verified on 3.13: non_linear + text = 501 passed, 3 skipped, 1 failed, the
failure (nautilus single-core pool) reproduced identically on a stashed clean
tree, as was the astropy collection error — both already recorded under
complete/2026/08/frozen-lane-counter.md. Also verified end-to-end against the
search.summary files four real searches actually wrote, giving
Clipped Lane-Steps = 414 at rate 0.958 on the clipped multistart arm.

Incidental, worth keeping: on that toy 3-parameter Gaussian the unclipped arm
showed Value-NaN Lane-Steps = 378 (94.5%) and the clipped arm 0 — the #128
mechanism reproducing on a model with nothing astrophysical in it, which makes
a far cheaper regression fixture than the imaging/mge cell.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FzF2XmKQaqZRWZfZMxvTNR

* prompt: the search.summary clip-count work is in flight as PyAutoFit#1478

Advance to complete/ on merge.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FzF2XmKQaqZRWZfZMxvTNR

* prompt: both incidental PyAutoFit bugs are in flight (#1479, #1480)

save_json_numpy_scalar_typeerror -> PyAutoFit#1479. Reproduced against the
unfixed tree before fixing. Fixed with a NumpyEncoder wired into BOTH output
writers -- save_json and, which this prompt did not name, Samples.info_to_json.
That second site is the more dangerous: samples_info is a search's own
diagnostic channel, so every counter added to it could reintroduce the crash.

crashed_run_poisons_resume -> PyAutoFit#1480, and carries a CORRECTION. The
prompt claimed the poisoned rerun is "a 4-second no-op that reads as a clean
result". That did not reproduce. What reproduces is a hard JSONDecodeError on
every rerun of the same search name, naming no file and offering no remedy.
The no-op variant presumably needs a surviving search_internal whose restored
total_steps short-circuits the loop; the crash path deletes it first. Same root
cause, fix covers both, but only the crash is evidenced -- recorded so the
unobserved symptom is not cited as fact.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FzF2XmKQaqZRWZfZMxvTNR

---------

Co-authored-by: Claude <noreply@anthropic.com>
Jammy2211 added a commit that referenced this pull request Aug 16, 2026
The cloud session did everything this campaign needs except run it. Adds a
SESSION HANDOVER block to the campaign prompt itself rather than a separate
handover doc, so the context travels with the file a GPU session will actually
open -- the same property #188 was merged to preserve.

What it carries:

- The three PyAutoFit changes that landed AFTER phase 1 (#1478 clip count in
  search.summary, #1479 NumpyEncoder, #1480 atomic writes), and the fact that
  all four are UNRELEASED. The task must run against a checkout at or after
  b6e89cd with autofit.__file__ verified, never a PyPI wheel.
- Which of this prompt's traps are now fixed rather than live -- and why the
  mitigations stay anyway: the step-count assertion catches every no-op cause,
  not only the float32 one.
- That the clip count is now a VALIDITY CHECK, not a statistic. A
  ClipperPriorBox arm reporting zero clips has not exercised the clipper and
  its "no change" result is meaningless -- a broken arm, not a null result.
- A seconds-long smoke test discovered while verifying #1478: the #128
  mechanism reproduces on a toy 3-parameter Gaussian (378 value-NaN lane-steps
  unclipped, 0 clipped, 414 clips at rate 0.958). Cheap way to confirm the
  clipper is wired up and firing before spending GPU time on imaging/mge.
- The mge-lane-death GPU/float64/multi-seed confirmation and the owed
  hazard-index entry, which want the same session and share these arms.
- Sequencing: this campaign, then ell_comps_trapping_unmasked.md on the same
  arms, which must not re-derive 27.79% from the prior-neutered arm.


Claude-Session: https://claude.ai/code/session_01FzF2XmKQaqZRWZfZMxvTNR

Co-authored-by: Claude <noreply@anthropic.com>
Jammy2211 added a commit that referenced this pull request Aug 16, 2026
All three merged today, so they leave draft/. Left in place they would read as
unstarted high-priority backlog on the dashboard people pick work from -- the
exact drift this session opened by finding phase 1 still sitting there after it
had shipped.

- clipper-usage-in-search-summary   PyAutoFit#1478  bbceff6
- save-json-numpy-scalar-typeerror  PyAutoFit#1479  b6e89cd
- crashed-run-poisons-resume        PyAutoFit#1480  5c9244b

Each record carries what implementing it taught, including two corrections to
what the prompts asserted:

- The search.summary prompt claimed there was "no search-specific channel at
  all". False. search_summary_from_samples already read samples_info and
  already emitted the NaN counters; the real gap was two omissions, not a
  missing mechanism. Recorded because it nearly caused a rebuild of something
  that existed.
- The poisoned-resume prompt claimed the rerun was "a zero-step no-op that
  reads as a clean result". That did not reproduce; a hard JSONDecodeError on
  every rerun did. The no-op variant presumably needs a surviving
  search_internal, which the crash path deletes first. Only the crash is
  evidenced, and the record says so.

Also kept: the second unguarded JSON writer the float32 prompt never named
(Samples.info_to_json, the more dangerous one, since samples_info gains a
counter every time a search does); the resume-guard leg found by audit rather
than by the prompt; the test trap where a run short-circuited as
already-complete passes an end-to-end resume test while asserting nothing; and
the toy 3-parameter Gaussian that reproduces the #128 mechanism in seconds,
which is a far cheaper regression fixture than the imaging/mge cell.

active.md updated to shipped state with both corrections. Four dangling
references repointed at the new records. lifecycle check + index check OK;
dashboard regenerated (141 -> 138 drafts).


Claude-Session: https://claude.ai/code/session_01FzF2XmKQaqZRWZfZMxvTNR

Co-authored-by: Claude <noreply@anthropic.com>
Jammy2211 pushed a commit that referenced this pull request Aug 16, 2026
…tart_workspace

Phase 2 of the prior-support work. Absorbs the GPU/float64/multi-seed
confirmation and the hazard-index entry owed from mge-lane-death (#128), which
share this campaign's arms.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRG2X7Af8zdF3vnsWoiK4U
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants