Skip to content

Regenerate the retracted figures, and the v1.1 material that followed - #23

Open
aurascoper wants to merge 101 commits into
fix/ledger-guard-document-scopefrom
fix/figure-artifacts-and-v11
Open

Regenerate the retracted figures, and the v1.1 material that followed#23
aurascoper wants to merge 101 commits into
fix/ledger-guard-document-scopefrom
fix/figure-artifacts-and-v11

Conversation

@aurascoper

@aurascoper aurascoper commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Stacked on #20. Seven commits, in the order they happened.

The defect

fig2_melanin_accumulation.pdf said, inside the image, "C. neoformans, C. sphaerospermum are radiotrophic (melanin-mediated energy gain)" — under a caption disowning "radiation-derived energy production" and against §2.6, "Radiotrophy is not established for any of the seven species modelled." fig1 said "radiotrophic niche", on the wrong side of the plot.

None of it was unnoticed, which is the part worth recording. The generator was corrected on 2026-08-14 (d53f236, 01b0f4d) and the verdict was written down three times — RM-G08-01, RM-G10-01, PP-65-08 ("deliberately not regenerated"). The verdict was reached, the source was fixed, and the only artifact anyone opens went on carrying the claim, because nothing could fail: the claims guard read one .tex, and tests/runtests.jl splits the monolith above # 13. Figure export, so the Julia suite cannot reach export_figures at all.

Regenerating from HEAD alone would have retired one contradiction and shipped four — only two of six in-plot strings had been fixed, and one "fix" asserted drift toward the source while §6.3 reports the ordering running the opposite way, within 1.4 SE of the seeding null.

The guard, three tiers, each with a control

  • sha256 per PDF, stdlib only. Without it, regenerating a figure and forgetting its sidecar leaves the suite green on stale-but-clean text while the PDF still carries the claim — the artifact-versus-source split reproduced inside the guard written to close it.
  • The phrase guard reads <figure>.txt as the document a row names.
  • A vocabulary floor for labels under MIN_WORDS. Neither figure row is reachable by the phrase guard — "radiotrophic niche" is two words — and that limit is asserted rather than left to look like coverage.

The pinned-SHA control idiom is retired here. It was used three times, each time noting that a squash-merge degrades the control into a skip, and each time proceeding. All four controls are now committed files under calibration/tests/fixtures/.

Also declares GENERATED_ARTIFACTS: artifacts/ is gitignored and nothing under it is tracked, so two document-resolution tests were passing on untracked local state and would have failed on any clean checkout.

v1.1 and after

  • §7.3 — the facility regime, argued from the manuscript's own ten-orders-of-magnitude dose-rate gap rather than pitched. Three references, each verified at source; the brief they came from was wrong on three counts.
  • Ethics — the AM7 taxonomy (NCBI taxid 94625, CDC 2022-12-19). Rule 6: the record and the handling instruction, no containment determination.
  • A deletion. v1.0 said "None of those numbers appears in this manuscript." The v1.1 correction is in this manuscript. AGENTS.md step 5 says delete rather than reword.
  • preprint/hoffman_memo.tex — four pages. The last is questions, because an earlier draft asserted MURR's capabilities back to a MURR scientist from a brief whose beamline inventory was single-sourced to a seminar abstract. HOFFMAN-11 records the one claim dropped for want of a readable source, in three parts: identified, inaccessible (HTTP 403, not absent), attribution unconfirmed.
  • The coinage at scan levelradiodialysis appeared ten times and its disclaimer covered one. Fixed positionally, which makes it two lines and makes it checkable. The suggestion to give §3.11 the "specification, not method" paragraph was refused: §3.2/3.4/3.12 carry it over code that does not exist, and §3.11's equations run.

§6.2, Table 4 — what decided each accepted move

compute_delta_H computed four terms and discarded the decomposition on its return line. Split out (not retyped — three callers want the scalar, one is the JACC cross-implementation check), the counterfactual runs on the variate the acceptance test already drew.

Removing the direct radiation term reverses sixteen of 206,042 accepted moves; it is the sole decisive term in one. Four, three and nine by seed at 400 MCS. Fifteen of the sixteen carry an adhesion or volume term that is independently decisive as well, so decisive_label returns multiple and the rad row reads 0.00% while the term was in fact capable of deciding sixteen moves — absorption, not absence, which is the point of reporting the count. The corrected bound predicts it: summing 1 - exp(rad/T_cpm) over drawn-branch accepted moves with rad < 0 gives 16.67 against the sixteen measured. PP-62-04, PP-62-10.

Corrected 2026-09-01. This description previously reported that the term reversed none of the 206,042, with a bound argument to match; both were withdrawn at manuscript v1.2. ΔH_rad is signed by role as well as by β_ioncompute_delta_H_terms adds +β_ion[source] when the source gains a site and subtracts β_ion[target] when the target loses one — so the reach is max|β_ion|, not min. The withdrawn argument was wrong by three orders of magnitude and predicted 0.26 reversals against the sixteen observed. PP-62-04 carries the history. The PR description was a dependent that the correction's audit step missed, the same way the Wan note was — second instance, and the reason that step now names artifacts outside the repository.

66–77% of accepted moves are reversed by removing no single term. No spatial map: median 3 accepted moves per touched voxel across seven categories. PP-62-07 records that refusal and the two alternatives also refused.

Two guard findings

  • The byte contract has a detection floor. 0.5 → 0.5000001 in the melanin coefficient leaves contract_csv.jl byte-identical; 0.5 → 50.0 fails it. Conditionally green with the condition unstated — a third kind of check-that-cannot-fail. Documented in validate_serial.jl, paired with an exact === check whose control is that summation order is observable on 15.7% of moves.
  • A test that passed over dead surface. The first decomposition test saw ΔH_mel = 0.0 on all 21,492 sampled moves, because melanin only grows through update_melanin!, which the harness never called. State is stepped before sampling now, and all four branches are asserted nonzero.

Suites

calibration 371, contract 7, coupling 313 passed / 6 skipped, Julia 20,171 across seven testsets.

Not a clean run. checkpoint_io_tests.jl and test_julia_interop fail for want of HDF5 in this worktree's unresolved depot; they pass in the main checkout and nothing here introduced them. Six coupling skips are openmc.

Note for reviewers: the venv's editable install points at the main checkout, so coupling must be run with PYTHONPATH set to this tree or it measures the wrong package.

🤖 Generated with Claude Code

https://claude.ai/code/session_01F4m1NqS1u9tuDRaqmNoQap

aurascoper and others added 20 commits August 26, 2026 17:50
…ation

Adds the World Resources Institute Global Power Plant Database v1.3.0 (34,936
plants, CC BY 4.0) as an immutable reference snapshot, together with a
provenance declaration carrying publisher, version, licence, attribution,
canonical source and the SHA-256 of the committed bytes. A test in a later
commit checks that hash against the file, because a provenance file that can
drift from what it describes turns "unknown" into "confidently wrong".

The dataset is pinned `-text` in .gitattributes. The repository normalises line
endings via `* text=auto`, which makes a content hash unreproducible by
construction -- git stores LF, checks out LF on macOS and Linux and CRLF on
Windows, so the same commit yields different bytes per platform. The first
declaration was written against a CRLF working copy (11,973,385 bytes) while
git had stored LF (11,938,448); every clone would have failed the check.
Pinning the dataset as binary makes the declared hash mean one thing everywhere.

At 11.4 MiB the file sits far below GitHub's 50 MiB warning, so ordinary Git is
its right home. LFS would add a client and quota dependency to solve a problem
this repository does not have, and fetching on clone would trade exact
reproducible bytes for the hope that an upstream URL still means the same thing.

This is a snapshot, not a cache: adopting a future WRI release is a new explicit
dataset-version commit, never a silent replacement.

THIRD_PARTY_NOTICES.md records the shader source vendored from
github.com/bilawalsidhu/gods-eye-view (MIT) and the licence boundaries of every
dataset used. No upstream dataset from that project is copied; those carry
CC BY-NC-SA and ODbL terms.

The commits that follow decompose the geolocator by concern rather than
replaying its development. They are a presentational series: the module graph
is only complete at the last one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ULbfnMy6CKDWWD9aQdYY2
Two questions that look alike and are not. A stat fingerprint
(st_mtime_ns + st_size + st_ino) decides WHEN TO REREAD a file; a timestamp
inside the data decides whether it is CURRENT. Touching a file must reload it
and leave its status exactly where it was, because touching a file does not make
the world newer.

Sources declare a class that determines where their authority comes from:

  live       expects continuous updates, measured against a clock
  reference  a versioned dataset with a declared vintage -- never stale by
             clock, since 34,936 power plants retrieved on a date are not wrong
             a week later
  authored   hand-maintained, carrying no semantic timestamp at all; reports
             FALLBACK forever and labels the mtime as what it is

That last case is the honest one: absence of an authority is a state to report,
not a gap to paper over. A reference layer's authority is a DECLARED VINTAGE,
which is frequently not a date -- "1.3.0", "2004" -- so requiring a parseable
timestamp is what pushes such a layer into borrowing a retrieval date and
presenting transport metadata as an epistemic fact.

st_ino is in the fingerprint because the upstream lattice writes atomically,
temp-then-rename, and a rename can land in the same nanosecond bucket as the
previous write while changing the inode.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ULbfnMy6CKDWWD9aQdYY2
The upstream is a loopback-only service holding private state. It offers a
redacted mode and this module asks for it, but does not trust it: that mode is a
property the upstream establishes and is free to redefine without telling us,
and this process binds 0.0.0.0 with CORS "*" and no auth.

So nothing is forwarded. A new document is built key by key from an allowlist --
no dict(upstream), no spread, no update() -- and unknown keys are dropped by
construction rather than by filtering. Values are coerced to scalars, because a
key allowlist with unbounded values is not a boundary: an allowlisted key could
otherwise carry an arbitrary nested object. Free text is length-capped, which
bounds the blast radius without pretending to sanitise meaning. The upstream
view parameter is a server constant, never read from the client.

Financial-state fields are absent, and per-symbol position presence is withheld
unless explicitly enabled by environment variable, since presence alone reveals
which instruments are held.

The tests are adversarial by design. The mocked upstream ships fields that must
never appear, including ones nobody has written yet, and asserts on forbidden
key names and secret values separately -- conflating those produces a false
positive the moment an allowlisted free-text value contains a forbidden word.
Fixture values are deliberately synthetic; a test that proves a boundary hides
private state must not itself contain any.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ULbfnMy6CKDWWD9aQdYY2
Base imagery from NASA GIBS, registered as a layer rather than set as a globe
material, because it arrives with a provider, a dataset vintage, a licence and a
required credit exactly like every other source. Special-casing it into the
sphere would put the one dataset with a legal attribution obligation outside the
model that tracks obligations.

The separation the layer exists to demonstrate:

    datasetVintage = 2004     epistemic. What the pixels depict.
    retrievedAt    = today    transport. When the bytes arrived.

Neither is staleness. Blue Marble Next Generation is twenty-two years old and
NOMINAL, because a reference dataset has a vintage rather than an age. Provider
unreachable with no cache is UNAVAILABLE, never STALE -- not having the bytes is
a different failure from having old ones.

The GetMap request is a server constant. No parameter on any route can steer the
URL, layer, projection or dimensions; an /api/imagery?url=... shape would be an
open proxy, and a parameterised test throws metadata-service and file:// URLs at
the route to prove the descriptor and content hash never move. Responses are
validated by content-type before the bytes are trusted, since GIBS reports
errors as XML with HTTP 200, and bounded by size.

The raster is cached outside version control and re-fetchable. Imagery is
optional by contract: with none available the globe keeps its graticule and the
layer reports UNAVAILABLE.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ULbfnMy6CKDWWD9aQdYY2
Completes the module graph: the FastAPI service, its six site layers and
epistemic band system, and the browser client that renders them.

The server resolves layers through the freshness model, so /api/health reports a
class, an authority and a status per source. Unknown layer ids now 404 instead
of returning an empty FeatureCollection, which had made a typo indistinguishable
from no data. Caching policy is stated once as a table: no-store for /api/*,
no-cache for /app/* and HTML, with public imagery excepted to no-cache. Nothing
here is content-hashed, so nothing claims max-age -- a versionless ES-module
graph served without revalidation lets a browser reuse one module while its
siblings update, and the resulting mixed old/new graph presents as an
application bug rather than a stale asset.

The client is three.js r0.147 with no build step. Layers register against a
contract with a six-state feed model, so a source's provenance and freshness are
visible in the UI rather than implied. GLSL sensor styles are vendored verbatim
from God's Eye View and translated for three.js at runtime by a small adapter,
which keeps the shader bodies diffable against upstream. They are labelled NVG
SIM and FLIR SIM under a SENSOR VIEW header: they are visual transforms of a
true-colour raster, not measurements, and nothing here observes infrared or
intensified light.

The correlation bands keep a coordinate frame on each endpoint, and the frame
for a price correlation carries no geometry at all -- anchoring a statistic to a
place invents geography the statistic does not have. The trading lattice follows
the same rule: it has no coordinates, so it renders beside the globe rather than
on it.

The detection overlay is bounded by construction, not optimised later: pooled
DOM nodes, frustum-culled, at most 100 targets, on a 10 Hz timer. Marker
geometries and materials are disposed on layer toggle.

Publication note: the source explains that a local lattice source exists, that
it is loopback-only, and that financial state is redacted, because without that
the security model is unauditable. It deliberately does not narrate the private
system behind it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ULbfnMy6CKDWWD9aQdYY2
…bsent

The measured correlation band needs a price source, and a price source is
operator plumbing: venue API access plus a symbol universe. It is therefore an
optional adapter rather than core code, and this deployment ships without one.

Until now that absence was swallowed. `_build_links` caught ImportError and
carried on, so a missing producer and a producer that ran and found nothing
were indistinguishable from outside -- which is precisely the conflation this
codebase refuses everywhere else. An uninstalled adapter must not read as "no
correlations found".

/api/health and /api/links now report market_correlation explicitly:

    status:    unavailable
    installed: false
    reason:    optional local market adapter not installed (geolocator.market)
    contract:  module exposing fuel_correlations() -> list[dict]

The contract is published so a future user can supply their own producer
without editing api.py, and the state distinguishes three cases that were
previously one: adapter absent, adapter present with an empty bar cache, and
adapter present and current. The layer tooltip surfaces the reason, so the UI
says why the band is missing rather than just omitting it.

The ImportError is still swallowed, deliberately -- a failing adapter must not
take the structural and speculative bands with it -- but the absence is now
stated rather than implied.

104 tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ULbfnMy6CKDWWD9aQdYY2
… simulation

Supersedes #13, which described the geolocator as a Tableau workbook and
justified documenting it on the grounds that the .twb and .mp4 were "already
committed and unreferenced". Both halves of that are now historically wrong:
geolocator/ is a published FastAPI and three.js subsystem over a vendored WRI
snapshot, and those artifacts are no longer unreferenced because a running
service reads the same dataset. Refreshing #13 would have meant rewriting its
purpose rather than updating it.

#13 also placed the section as "### 4 ·" at the end of ## Simulations, which
lists a thing explicitly labelled "not a model" as the fourth simulation --
precisely the inference its own disclaimer warns against. This version is a
top-level section in the end matter, so the structure carries the boundary
rather than relying on a sentence to undo it.

Kept from #13, because it remains the strongest sentence in it:

    This supports no claim in this repository.

Changed is the rationale. Not "unreferenced artifacts need explaining" but: a
named, maintained subtree invites an inference of coupling just as a stray file
does, so the boundary is stated explicitly -- no gate reads it, no figure
depends on it.

Also corrects the now-stale claim under ## Selected structure that the root
carries only unsorted artifacts "not part of the framework and not listed
here". One of them is now named and maintained, and is still outside the
framework.

Carries no new quantitative claim, addressing the second review thread on #13.
The only numerals are the identifiers SHA-256, v1.3.0 and CC BY 4.0; the GIF's
pixel dimensions, frame rate and palette size are deliberately omitted -- they
created ledger overhead without explaining the architecture. The first thread on
#13, about the workbook's missing data dependency, is resolved by #14 vendoring
the dataset with a hash-checked declaration.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ULbfnMy6CKDWWD9aQdYY2
The isolation fix in this branch is right, but it inherited a toothless
assertion from the version it replaced. Demonstrated by widening MISSION_FIELDS
to admit "equity" -- a genuine breach of the boundary -- and re-running: the
adversarial suite in test_lattice_boundary.py correctly fails two tests, while
test_lattice_boundary_is_untouched_by_imagery passes. Its mocked upstream
carried nothing sensitive, so `assert "equity" not in ...` could not fail
whatever the boundary did.

That was not introduced here. The previous version was equally unable to fail,
for a different reason: it hit the live board, whose stream mode already strips
equity upstream, so there was never anything present for the boundary to have
leaked. Determinism was the improvement; teeth are still missing.

The upstream fixture now carries the fields the boundary must drop -- equity and
margin_used in the mission, has_position and position_size on a cell -- and the
assertion covers the whole set rather than one field. With MISSION_FIELDS
widened the test now fails as it should, and passes on the real code with the
lattice board up or down.

Also restores the trailing newline this file lost.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ULbfnMy6CKDWWD9aQdYY2
The geolocator has had no CI coverage since it landed. coupling-tests runs
pytest against contract/, coupling/ and calibration/; model-contracts is
path-scoped to analysis/, R, Julia and preprint material. Neither reaches
geolocator/**, so the green badges on #14, #15 and #16 were silent about the
code those PRs changed, and the only real gate was someone remembering to run
the suite by hand.

Adds a geolocator-tests job on geolocator/**, the vendored dataset, and
.gitattributes. It installs only what the subsystem needs -- fastapi, httpx,
pytest -- deliberately not `-e .`, since the geolocator does not participate in
the contract/coupling package graph.

Two tiers, kept apart on purpose. "Our contracts hold" and "NASA's endpoint
answered this runner" are different claims, and letting the second gate a PR
would make a provider outage look like a defect here.

  geolocator-tests       blocking, deterministic, no network
  gibs-interoperability  schedule + manual only, continue-on-error

Making the blocking tier honest required one test change: an autouse fixture in
conftest.py isolates the imagery cache to tmp_path and stubs the provider. It
is installed at the urlopen seam rather than by replacing imagery._fetch, so the
real validation path still runs -- content-type, JPEG magic bytes, MAX_BYTES
ceiling -- and the two tests that install their own urlopen stub simply override
it. GEOLOCATOR_LIVE_GIBS=1 runs the identical suite against the real endpoint,
which is what the non-blocking tier does.

The fixture belongs in conftest rather than test_imagery.py because
test_api_routes.py and test_provenance.py reach imagery.state() through
/api/health. Scoped to one module it left the blocking tier provider-dependent
and wrote a cache into the working tree -- observed, not theorised.

The job also re-checks the vendored CSV's SHA-256 against its declaration before
running pytest. .gitattributes pins that file `-text` precisely so the hash
holds on every runner; if line-ending normalisation creeps back the declaration
silently stops meaning anything, and this fails loudly instead.

Verified: 104 passed with the network proxied to a dead port and LATTICE_URL
unreachable, leaving no cache in the working tree; 20 passed against the real
GIBS endpoint with the cache cleared; the boundary negative control still fails
when MISSION_FIELDS is widened; the dataset check passes clean and fails on a
one-byte corruption.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ULbfnMy6CKDWWD9aQdYY2
The new CI job failed on its first run, which is the argument for having it.

`worldgrid` loads from the lattice board's energy_world.json, a path OUTSIDE
this repository. A public clone legitimately does not have it, so the layer
correctly reports `unavailable` -- while two provenance tests asserted `nominal`
unconditionally. Every local run passed because the authoring machine happens to
hold that file.

That is the same failure mode as the line-ending hash: a test that only passes
in the environment that wrote it. It survived a fresh-clone gate because the
fresh clone still ran on a machine with the file at the absolute path the
default points to.

Both tests now treat absence as a correct answer. Present, the layer must report
the declared release; absent, `unavailable` with no vintage and no retrieval
date -- there is nothing to confuse with a vintage when nothing was retrieved.
Only the cross-repo source is permitted to be missing; `power` reads a vendored
file and must always resolve.

`pytest -rs` in the workflow keeps the skip visible rather than silent.

Verified both ways: 104 passed with the file present, 103 passed and 1 skipped
with ENERGY_WORLD_JSON pointed at a nonexistent path.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ULbfnMy6CKDWWD9aQdYY2
The portability allowance added in the previous commit was too wide. It treated
any UNAVAILABLE worldgrid as acceptable, but TrackedSource reaches that status
two ways: the file is absent, or the file exists and its loader threw. The first
is a fact about a public clone. The second is a parsing regression, and
accepting both would have made this allowance conceal exactly the class of bug
the suite exists to catch -- the inverse of the environment dependency it was
written to fix.

The two branches now require the missing-file cause specifically, which
freshness.py distinguishes by error prefix: `missing: <path>` when the stat
fingerprint is None, `<ExceptionType>: <message>` when the loader raised.

Three states, verified:

  file present    104 passed
  file absent     103 passed, 1 skipped
  file malformed  2 failed  <- previously would have passed

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ULbfnMy6CKDWWD9aQdYY2
`fig2_melanin_accumulation.pdf` said, inside the image, "C. neoformans,
C. sphaerospermum are radiotrophic (melanin-mediated energy gain)" — under a
caption disowning "radiation-derived energy production" and against §2.6,
"Radiotrophy is not established for any of the seven species modelled."
`fig1` said "radiotrophic niche".

Neither was unnoticed, which is the part worth recording. The generator was
corrected on 2026-08-14 (d53f236, 01b0f4d) and the verdict was written down
three times — RM-G08-01 "regenerate the committed PNGs", RM-G10-01 "drop
'radiotrophic'", PP-65-08 "the committed PNGs still carry the old reversed zone
labels ... deliberately not regenerated". The verdict was reached, the source
was fixed, and the only artifact anyone opens went on carrying the retracted
claim, because nothing could fail: the claims guard read one .tex file, and
tests/runtests.jl splits the monolith above `#  13. Figure export`, so the Julia
suite cannot reach export_figures at all.

Regenerating from HEAD alone would have retired one contradiction and shipped
four. Only two of six in-plot claim strings had been fixed:

  - "Radial stratification — ..." as a title, against L976 "not evidence of
    established stratification"
  - "Melanin accumulation — radiation-driven production", against the caption
  - "Melanin producers (★ radiotropic)", a phenotype attribution for what
    RM-G10-01 records as a model input
  - "★ ... drift toward the source (radiotropic)", which asserts as fact what
    the run's own output contradicts (L966-967, "their observed ordering is in
    the opposite direction", within 1.4 SE of the seeding null at L972).
    Replaced, not reworded: there is no true version of that sentence.
  - "(% depleted)" on fig 4, the artifact half of RM-KR-06

Figures 1 and 2 reproduce the manuscript's numbers exactly — mean_r 13.10 /
11.55 / 9.94 against the captions' 13.1 / 11.5 / 9.9, and M=1.4372 against
M=1.44 — so no caption moves. They came from main_coupled(), which now refuses
to run (RADIODIALYSIS: BLOCKED at a coupled X_total). That refusal is correct
and is untouched: figs 1-2 read only snapshot mean_r and mean_melanin, and
neither the Hamiltonian nor update_melanin! reads state.nutrient, which is the
only channel by which radiodialysis reaches the CPM state. Figures 3 and 4 are
NOT regenerated and are named as such by FIG-03.

The guard, three tiers, each with a control:

  - sha256 per PDF, pinned in stdlib. Without it, regenerating a figure and
    forgetting its sidecar leaves the suite green on stale-but-clean text while
    the PDF still carries the claim — the artifact-versus-source split
    reproduced inside the guard written to close it.
  - the phrase guard reads `<figure>.txt` as the document a row names
  - a vocabulary floor for labels under MIN_WORDS. NEITHER figure row is
    reachable by the phrase guard: "radiotrophic niche" is two words, and fig
    2's annotation splits on its comma and parens into runs of 2, 4 and 3. That
    limit is asserted rather than left to look like coverage.

The pinned-SHA control idiom is retired here. It was used three times —
5980dc5, 9319d43, and a third that would have been e24dbec — each time noting
that a squash-merge makes the commit unreachable and degrades the control into
a skip, and each time proceeding. All four controls are now committed files
under calibration/tests/fixtures/.

Also declares GENERATED_ARTIFACTS. `artifacts/` is gitignored and nothing under
it is tracked, so two document-resolution tests were passing on untracked local
state and would have failed on CI or any clean checkout — found by building
this branch in a fresh worktree.

367 passed (was 362).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F4m1NqS1u9tuDRaqmNoQap
Three additions to the manuscript, one new document, and one deletion.

SECTION 7.3 — the use-case gap, argued from the model's own constraint rather
than pitched. The manuscript already puts reactor irradiation (~Gy/min) and its
cited environmental motivation (~mGy/yr) ten orders of magnitude apart and says
a constant calibrated in one does not transfer to the other. Engineered
facilities sit between them, and that is where the offline counterfactual's
inputs — bounded geometry, characterised source, measurable metal inventory —
are obtainable rather than assumed. Written to satisfy PP-8-04, which ruled
against the deployment register: this predicts nothing and proposes nothing, and
says in as many words that the model is unchanged and only the setting differs.

Three references, each verified at source before it entered the file:
  - Sarro 2007 (PMID 17426994) — the brief this came from said "34 months" and
    named Cofrentes. The abstract says neither, only "a Spanish nuclear power
    plant". Both details dropped rather than carried.
  - Karley 2018 (PMID 29063404) — D10 248 Gy to 2 kGy and 3.8 ug/mg both
    verbatim in the abstract. The brief attributed the 3.8 figure to the 2023
    paper and the authorship to Shukla; both wrong.
  - Karley 2023 (PMID 37209244) — dead biomass removes Co and Ni, which is what
    sorption predicts. Its "4e-4 to 1e-5 g/mg" is dimensionally odd and two
    orders off the same isolates' 2018 figure, so it is quoted nowhere.

ETHICS — the AM7 taxonomy, which the manuscript had never carried. NCBI serves
taxid 94625 as Brucella intermedia with Ochrobactrum intermedium as a synonym;
CDC's 2022-12-19 lab update directs Class II BSC handling and state-lab referral
for anything identified as Brucella. Verified directly against the NCBI record
and the CDC notice. An initially guessed DOI for Oren & Garrity resolved to an
unrelated paper on Raineyella fluvialis and was discarded.

Rule 6 governs what this may say. The research brief behind it concluded BSL-2
and non-select-agent for the SPECIES; biosafety follows strains, so the section
records the taxonomy and the handling instruction and declares no containment
level, no select-agent status, and nothing touching D-APPROVAL.

THE DELETION — v1.0 said "None of those numbers appears in this manuscript."
The v1.1 figure correction is in this manuscript, which disproves it. AGENTS.md
step 5 says delete rather than reword, because a paraphrase is the same claim
and this repository has corrected its own corrections twice by making it. The
sentence is gone; what moved is stated instead.

preprint/hoffman_memo.tex — three pages. Page 3 ASKS what the facility can
supply rather than stating it. The draft it replaced asserted MURR's
capabilities back to a MURR scientist from a secondhand brief whose beamline
inventory was single-sourced to a seminar abstract — the same inference class
this repository exists to refuse, and checkable by its reader in a minute.

docs/correspondence/wan_v11_note.md — unsent draft.

Nine ledger rows. 367 passed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F4m1NqS1u9tuDRaqmNoQap
…nobody ran

Three analyses arrived with the Hoffman thread. Two had premises that did not
survive contact with the source, and both were caught before anything shipped.

THE COINAGE. The suggestion was to give section 3.11 the "This subsection is
specification, not method" paragraph that 3.2, 3.4 and 3.12 carry. That would
have been false in the opposite direction: those three stand over code that does
not exist -- "No program in this work integrates Eq. 2", "no simulation reported
here holds an independently-integrated momentum state" -- while 3.11's equations
run in biofilms_radiodialysis.R and in Julia, with results in 6.5.

The real defect was narrower and is the figure defect's shape. 3.11 already
disowns the term in a full paragraph, names the established descriptors, and
Figure 3's caption already says the two curves are not a closed feedback law.
The term then appeared ten times and the disclaimer covered one; the abstract
said "a radial radiodialysis solver" with no signal the word was coined here.
Caveat in the body, claim in the part people scan.

Fixed positionally rather than editorially, which makes it two lines and makes
it checkable: the term must not appear before the paragraph that disowns it.
Abstract now reads "a radial membrane-transport solver"; the heading is
"Membrane Transport Under Radiation-Driven Permeability Change". Nine uses
remain, all introduced. No version bump and no correction entry -- v1.1 has been
sent to nobody, and a correction paragraph is for a claim that reached a reader.

THE MEMO. The corrosion framing is right and one adjustment matters enough to
state in the memo: MIC is a chemical attack that happens to occur in a radiation
field, and every one of its mechanisms works at background dose. Radiation
selects which organisms are present. The opposite reading is a radiation-driven
metabolism claim of exactly the class section 2.6 retracts, and it would have
entered through the framing rather than through a sentence.

Hoffman's papers were verified before anything was attributed to him, and the
identity check was not a formality: his Scholar profile is filed under Catalyst
Science Solutions, the 2024 Materialia paper lists him at GE Research, and a
Florida seminar listing is what joins those to MURR. His envelope -- steam,
hydrothermal chemistry, hydrogen-isotope permeation -- comes from three papers
that are his and are readable.

DROPPED: the used-fuel-pool pitting-resistance claim, which would have carried
the argument the whole distance. NACE-2019-12944 returns HTTP 403 and the
surrounding literature points to Rebak. Recorded as a refusal in three parts,
because claim-identified, source-inaccessible and attribution-unconfirmed are
three different states and only the middle one is recoverable by a reader with
access. HOFFMAN-06 makes the same point without it.

The geometry caveat is the sentence that keeps page 3 honest -- cylinder in
water, Robin boundary, no metal and no interface -- and it is also the sentence
that reads like a hedge and goes first when someone tightens the page. It is now
a ledger row with a test behind it. Four pages, not three: the argument is a
page and letting LaTeX orphan a header to hide that was not an option.

THE GUARD GAINS ITS MIRROR. Every document test here asserts ABSENCE, because
`delete` is the verdict where absence is the criterion. That left the opposite
failure uncovered: a deliberately-carried sentence quietly trimmed, with nothing
able to notice. LOAD_BEARING is the mirror, on the RETRACTED_IN_FIGURES idiom --
an explicit tuple rather than a new verdict or column, since most `keep` rows
are not quotable prose. Both new tests have controls, and both were proved
against the real files: planting a bare term above the disclaimer and striking
the geometry sentence failed those two tests and no others.

THE SURROGATE AXIS. NEWS-AUD-03 and two sibling audits searched for real
biofilms pairing wet mass, dry mass, blanks and a calibrated hydrated volume,
and each says the search was sampled and not exhausted. None searched for a
surrogate; "phantom" appears in this repository only as the A0 water geometry.
Recorded as an axis, which is true independent of what any source contains.

Hellriegel 2014 resolved on the full text: it is a surrogate, not a fit -- a
growth-independent gellan imitate, 2 mL cast in a 40 x 2 mm mould at 0.33-1.17%
w/v, whose stated purpose is testing characterization tools before they meet a
real biofilm. It reports no density, no water content and no masses, which turns
out not to matter: a cast specimen's true values are set by the recipe. It
CANNOT clear D-RHOWET and SURR-01 says so -- a gellan gel at one percent solids
has water's density and bounds nothing about a biofilm's dry fraction. What it
bounds is the protocol.

Also found while searching it: PMC8579398 pairs wet mass, dry mass, water
content and matched agar blanks on E. coli biofilms, and has no hydrated volume
at all -- thickness only. The closest near-miss located so far, failing on the
same single term as every other. density_g_cm3 stays blank.

The dataset schema refused three invented enum values on first write. They were
mapped onto the existing vocabulary rather than the vocabulary widened.

371 passed (was 367). Julia interop fails in this worktree for want of HDF5 in
a depot with no Manifest; no Julia code is touched here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F4m1NqS1u9tuDRaqmNoQap
`compute_delta_H` computed ΔH_adh, ΔH_vol, ΔH_rad and ΔH_mel as four separate
locals and threw the decomposition away on its return line. §6.2 reports the
melanin term biasing acceptance by 15.5% against the direct radiation term's one
part in 1e5 -- a ratio of about 1.5e4 -- and says in its last sentence that
hand-specified adhesion differences are larger than both. That is a spatial fact
reported as a table row, and the numbers to draw it were being computed 6.4M
times a run and discarded.

SPLIT, NOT RETYPED. compute_delta_H_terms is the old body with the sum removed;
compute_delta_H adds the fields back in the same order. Three callers outside
this file want the scalar and one of them is biofilms_potts_jacc.jl's
cross-implementation check against the parallel port. Changing what that reads,
to make a rendering change easier, would trade a real guard for a picture.

THE BYTE CONTRACT HAS A FLOOR, MEASURED RATHER THAN ASSUMED. Perturbing the
melanin coefficient from 0.5 to 0.5000001 leaves contract_csv.jl's output
byte-identical; 0.5 to 50.0 fails it. A 2e-7 shift moves exp(-ΔH/T) by ~4e-8 and
has to straddle one of ~6.4M uniform draws to appear at all, so the contract
guards the trajectory and does not certify bit-exactness against small numerical
change. Green there was necessary and not sufficient.

tests/delta_h_decomposition.jl is the exact check: the four terms sum to the
scalar under `===` on every sampled move. Its control is that SUMMATION ORDER IS
OBSERVABLE -- reordering the same four terms differs on 3367 of 21492 sampled
moves, 15.7%, because adhesion and volume are O(1), radiation is O(1e-5) and
melanin is O(0.5), so the small terms vanish or survive depending where they
land. Without that, "same operands, same order" would be describing an
associativity that holds anyway and the file would assert a tautology.

It also requires all four branches to be nonzero. The first version of this test
saw ΔH_mel = 0.0 on all 21492 moves and passed: melanin starts at zero and only
grows through update_melanin!, which the harness never called, so the melanin
branch was dead surface a green test walked over. The state is now stepped
before sampling.

PROVED BY MUTATION, not by reading: planting a reordered sum in compute_delta_H
fails the exactness assertion and the control both, and nothing else.

Julia: 162 passed across five testsets. checkpoint_io_tests.jl still errors on
`Package HDF5 ... is required but does not seem to be installed` -- this worktree
has no Manifest.toml, the main checkout does and resolves HDF5 there, so it is
environmental and predates this change. NOT A CLEAN RUN.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F4m1NqS1u9tuDRaqmNoQap
…ng anything

The counterfactual, on the uniform that was actually drawn, never on a new one:
drawing again advances the stream and the byte contract catches it, a second
generator makes the answer stochastic and adds a seed to declare, a probability
threshold invents a constant. All three fabricate.

THE TWO ACCEPTANCE BRANCHES TURN OUT TO PRODUCE DISJOINT LABEL SETS, which is
what makes `contingent` a category and not a patch over an awkward case:

  ΔH <= 0  no draw was taken, u is NaN. Removing a term can push ΔH above zero,
           and what would have happened then needs a number nobody drew. No term
           can be shown to flip the move to REJECT here -- only to remove its
           certainty. Yields `none` or `contingent`, never a named term.
  ΔH > 0   a draw exists, every counterfactual is decidable, nothing is
           contingent. And only a term that HELPED can be decisive: removing one
           that hurt lowers ΔH and the move stays accepted. Yields `none`, one
           of the four, or `multiple`.

Asserted over 20,000 random term vectors rather than remarked on, because if
`contingent` ever appeared in the drawn branch the label would be answering two
questions under one name and the colour key would mean nothing.

INERT: `u = ΔH <= 0 ? NaN : rand(rng)` evaluates only its taken branch, so the
generator is consulted on exactly the moves it was before. Byte contract green,
plus a direct lattice-and-melanin comparison with and without the tally attached
and a different-seed control proving that comparison can fail.

THE MEASUREMENT, RUN BEFORE ANY COLORMAP, ON THE FIGURE CONFIG
(N=40, 6 cells/species, seed 42):

    100 MCS, 16037 accepted        400 MCS, 53603 accepted
      none        38.6%              none        66.0%
      contingent  49.4%              contingent  23.7%
      adh          7.5%              adh          6.2%
      vol          4.4%              vol          4.0%
      mel          0.01%             mel          0.04%
      rad          0.00%             rad          0.00%
      multiple     0.09%             multiple     0.13%

THE DIRECT RADIATION TERM DECIDED ZERO OF 53,603 ACCEPTED MOVES, and that is
structural rather than under-sampling. Only a helping term can be decisive, and
β_ion is negative for exactly two of seven species at -5e-5, so a radiation
contribution that helps is of order 5e-5 and flipping a draw needs u within
~1e-5 of the threshold. Expected flips over 53,603 moves: about 0.5. This is
section 6.2's "one part in 1e5" as a count instead of a ratio.

The melanin term -- the one section 6.2 calls dominant over radiation -- decided
23. Which is section 6.2's own last sentence, "hand-specified adhesion
differences remain larger than both", arriving as a measurement.

AND THE MEASUREMENT ARGUES AGAINST THE LAYER IT WAS TAKEN FOR. n_accepted has a
median of 3 per touched voxel and a 25th percentile of 2, over 6157 of 64000
voxels. A modal label over three samples across seven categories is noise, and
no opacity rule repairs that -- binding the qualification to the picture was the
plan, and the honest reading is that the qualification defeats the picture
rather than annotating it. Two labels are also 90% of the moves. No bundle layer
and no colormap are written here.

What the run does support is the histogram, which is a result: 10% of accepted
moves have any single decisive term at all, and the two radiation-linked terms
account for 0.04% of them.

Julia: 20,171 passed across seven testsets. checkpoint_io_tests.jl still errors
for want of HDF5 in this worktree's unresolved depot. NOT A CLEAN RUN.

Also documents the byte contract's detection floor in validate_serial.jl, where
the next reader will meet it: it is conditionally green with the condition
unstated, which is a third kind of check that cannot fail, and it is not
redundant with the exact check beside it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F4m1NqS1u9tuDRaqmNoQap
… map

Section 6.2 ranks the two radiation-derived terms at a single move and closes by
noting hand-specified adhesion differences are larger than both. The same
comparison over a run: for each ACCEPTED move, would removing one term have
reversed it. Table 4 is that count.

    term removed        100 MCS      400 MCS
    none (the sum)       38.56%       65.99%
    adh                   7.53%        6.15%
    vol                   4.43%        3.97%
    rad                   0.00%        0.00%
    mel                   0.01%        0.04%
    >1 term               0.09%        0.13%
    contingent           49.39%       23.72%

THE DIRECT RADIATION TERM REVERSED NONE OF 206,042 ACCEPTED MOVES across seeds
42, 43 and 44. That is not under-sampling and the section says why: only a term
that LOWERED Delta H can be decisive for an accepted move, beta_ion is negative
for two of seven species at -5e-5, and reversing would need the drawn variate
within ~1e-5 of the threshold -- about 0.5 expected reversals in 53,603. Zero is
the expected observation. It is Table 3's one-part-in-1e5 as a count instead of
a ratio, and it follows from Table 3 rather than adding to it.

Melanin reversed 23 of 53,603. Both restate the closing sentence that was
already there.

THE COMPLEMENT IS THE RESULT. Between 66% and 77% of accepted moves are reversed
by removing no single term, so the dynamics are carried by the sum and not owned
by a component.

NO SPATIAL MAP, AND THE ROW SAYS SO RATHER THAN THE MAP BEING QUIETLY ABSENT.
The per-voxel tally and the modal-label reduction exist and are tested; the
measurement they were built for is what argued against drawing them. At 400 MCS,
6157 of 64000 voxels received any accepted move, median 3 and p25 2, across
seven categories. A mode over three samples is noise and an opacity rule bound
to the count would annotate the noise rather than remove it. Two further options
were refused and PP-62-07 records both: a map restricted to the ~10% of moves
with a named decisive term would filter out the 90% where the sum carried the
move and show a model looking more term-driven than it is; reporting nothing
would have discarded a real corroboration of Table 3. The distribution is
reported, the crop is not.

NO NULL PANEL, AND NOT BECAUSE IT WAS FORGOTTEN. Section 6.3's null is a SEEDING
null -- mean radial position has a value at MCS 0 from placement alone, so "what
would this look like without dynamics" is well posed there. Decisiveness is a
property of accepted moves, which do not exist at seeding, and zeroing terms
gives a different model rather than a null. What is well posed is seed
robustness, and that is what the three-seed figure above is.

The histogram also lands in a register the figure guard can actually read. A
raster render carries almost no extractable text, so RETRACTED_IN_FIGURES would
have gone silent on it and only the sha256 tier would have bitten. A table is
prose in the .tex and the ordinary phrase guard covers it.

Five ledger rows. 371 calibration, 313 coupling, 7 contract. Coupling's one
failure and one error are the pre-existing HDF5 gap in this worktree's
unresolved depot; the six skips are openmc. Suites now run with PYTHONPATH set
to this worktree -- the venv's editable install points at the main checkout, so
earlier coupling counts in this branch measured the wrong tree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F4m1NqS1u9tuDRaqmNoQap
The draft described a three-page memo. It is four pages: the corrosion argument
went in between the empirical fact and the questions. A letter that miscounts
its own attachment is the same class of defect as a figure the prose retracts.

Adds the Section 6.2 table and the terminology tightening as brief additions
rather than a changelog, and makes the figure claim specific now that it has
been checked against the committed sidecars: five in-plot strings across the two
images -- both plot titles, Figure 1's two band labels, and Figure 2's
annotation. Figure 1's bands were reversed as well as mislabelled, which the
note already said and the diff confirms.

Still unsent.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F4m1NqS1u9tuDRaqmNoQap

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 77125683db

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread preprint/modeling_radioresistance_and_radiotropic_fitness.tex Outdated
Comment thread coupling/biofilm_openmc/observer.py Outdated
aurascoper and others added 5 commits August 29, 2026 17:12
… misreport it

The 8-colour sweep can carry one defect of its own -- a parity-correlated bias in
accepted moves -- and NOTHING IN THE REPOSITORY WOULD HAVE REPORTED IT.
jacc_port_tests.jl compares kernels on identical inputs, so it passes whenever
BOTH kernels carry the artifact, and tests/fixtures/serial_seed42.csv pins the
serial stream, which has no sublattices at all. The port was byte-identical on
both branches and had no acceptance instrumentation of any kind.

NO SPATIAL MAP, AND FOR d404438'S REASON RATHER THAN A NEW ONE. That commit
refused a per-voxel map for the decisive-label tally at 6157 of 64000 voxels
touched, median 3 -- a mode over three samples is noise. The argument carries,
and the conclusion here is stronger: a parity bias is a GLOBAL count comparison,
so the map was never the instrument for it. cpm_color! gains two write-only
per-site arrays, reduced every sweep and never drawn.

FOUR CHOICES THAT EACH AVOID A FALSE FAILURE ON THE FIRST RUN.

  `st` IS A DISCRIMINATOR, NOT A SENTINEL. 0 never proposed, 1
  evaluated-rejected, 2 evaluated-accepted. A NaN inside `dh` would have been
  indistinguishable from a site never proposed, shrinking the denominator of
  every acceptance rate and raising it silently. The spatial class is NOT
  stored -- it is derived from (tx,ty,tz), which is what keeps it spatial when
  the pass order is permuted.

  THE TABLE IS CONDITIONED ON OPPORTUNITY. The early returns -- wall, same-sigma,
  medium-into-medium, out-of-bounds -- are geometry-dependent, so a uniform null
  over eight classes would report the shape of the domain as a decomposition
  artifact. The 2x8 accepted/rejected table asks about the acceptance RATE.

  THE THRESHOLDS ARE EFFECT SIZES. n is 1.3e5 to 3.1e5 evaluated proposals per
  run and the cells are not independent -- an accepted move changes the lattice
  for every later pass -- so chi-square over-disperses from autocorrelation
  alone. At N=40 it ran 8.3 to 59.8 against a df=7 critical value of 18.475
  while Cramer's V never exceeded 0.014. V and the max per-class rate deviation
  are asserted; chi-square and n are reported beside them, never alone.

  color_order SEPARATES THE DECOMPOSITION FROM THE vols STALENESS. The colour
  loop is sequential and vols accumulates across passes (delta_H reads it at
  :167 while cpm_color! mutates it at :208), so the first pass evaluates against
  sweep-start volumes and the last against volumes moved by seven passes -- a
  deterministic, parity-correlated difference with nothing to do with the
  checkerboard, and `c` indexes both spatial class and sequence position.
  REVERSAL WAS REFUSED: position(c) = 7-c separates a monotonic position effect
  and is invariant to any effect symmetric about the midpoint, so one
  transformation leaves one blind spot. The RNG step key stays mcs*8 + c, keyed
  to the colour and not its position, so permuting changes the pass order and
  nothing else.

THE RESULT IS THE THIRD DISPOSITION, AND IT IS REPORTED AS SUCH. V 0.0050-0.0111
and max rate deviation 0.017-0.049 over three seeds x three orderings: no
decomposition artifact, and the residual tracks NEITHER spatial class NOR pass
position. The permuted run is a different trajectory rather than the same system
observed differently, so that outcome was reachable and the tier asserts the
bound and prints both rate vectors rather than claiming an attribution.

VERIFIED CROSS-VERSION, BECAUSE IT IS A CROSS-VERSION CLAIM. Comparing
on_sweep=nothing against an instrumented run at one commit compares the new code
to itself: the writes are unconditional, so both paths are identical kernel code
and the assertion is vacuous. The check that means something ran the port at
7712568 and after -- threads backend, 1 thread, seed 42 lattice sha256
3f528fab5b725dfd both sides (4884 occupied), seed 43 a4a8972857d9a893 (4883).

AND ITS POSITIVE CONTROL. Two agreeing runs cannot establish determinism on a
bounded race; it may simply not have manifested. The same seed at 4 threads gave
three different lattices in three runs (42a1815c, f42c3bf4, a824b7ef), so the
race is real, manifests, and the check detects it. The port is NOT reproducible
across thread counts and no lattice fixture is committed: it would sit in a
compare-never-regenerate directory while being thread-count-dependent.

The guard's own control is synthetic and in-file: one class held 20 percent low
must clear both thresholds. A threshold nobody has seen fail is not a guard.

fig5 carries the regime diagnostic the lattice picture cannot give -- acceptance
rate per sweep and the pooled Delta H distribution, both distributions, neither
a map. Pooled rate 0.062 at N=40; the per-sweep maximum of 0.414 is an
initialization transient, which is why the tier compares first half against
second before believing any pooled number. The provenance line names the run in
the .txt sidecar the phrase guard reads, since the test spans three seeds and
three orderings and would otherwise be about a different thing.

Six ledger rows, two census entries. Julia suite green including the byte-level
serial contract; calibration 371, contract 7.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJu1d4TFhowR3GUtH2MdoG
…an find it

Two annotations printed on top of each other and neither was readable. THAT WAS
ARITHMETIC, NOT A RENDERING FLUKE, WHICH IS WHY IT RECURRED ON EVERY
REGENERATION: both were placed at x = 0.55*t_end from FINAL values --
m_final + 0.05 = 0.829 on the left axis, Peff_final * 0.88 = 2.385 on the right
-- and those two independent numbers on two independently autoscaled axes both
mapped to 79 percent of plot height. The fix separates them HORIZONTALLY, at
0.35 and 0.80 of the run, and anchors each to its own curve at its own x. A
vertical nudge would have fixed this dataset and left the coincidence in place.

THE ARTIFACT COULD NOT BE REBUILT, WHICH IS WHY IT WAS ALSO STALE. `julia
--project=. biofilms_potts.jl` runs main_coupled(), which hits RADIODIALYSIS:
BLOCKED -- the coupled loop reconstructs X_total from occupancy. FIG-03 already
records that blocker, and states it of figs 3 AND 4. It is true of one.

  fig3 plots m(t) and P_eff/P0. dm/dt = -k_dam*Ddot_R*m and
  P_eff = P0*exp(alpha_P*Ddot_R*t). Neither reads X_total or X_red.
  fig4 plots c_wall, c_mean, s_mean. The gated basis enters at exactly one
  place, uptake = k_ads*X_total + k_red*X_red, which drives c and s only.

regenerate_fig3.jl renders into a temp directory and copies one file across.
IT PROVES THE EXEMPTION RATHER THAN ASSERTING IT, and the control bites in both
directions so it cannot pass by measuring nothing: at 10x the uptake constants
fig3's two series must come back identical AND fig4's c_wall must move, and the
copy is refused if either half fails. Both held. fig4 is untouched and FIG-03
stands. It is committed rather than left in a scratch directory because a
generator nobody can run is the liability 1b51126 was written about.

AND THE REBUILD RETIRED A CLAIM THAT HAD SURVIVED FIFTEEN DAYS. d53f236
(2026-08-14) dropped "(50 Gy cumulative)" from the generator and RM-KR-01
already carried the verdict -- never print Gy there, since D_cum = Ddot_R*t is
dimensionless model time and no calibration converts it. The PDF went on
printing it because nothing could rebuild it: 1b51126 retired the same defect in
figs 1-2 through main()'s --no-radiolysis path and could only add .sha256/.txt
sidecars over a fig3 it had no way to regenerate. m = 0.779 stays -- that value
is arithmetically exact and RM-KR-02 keeps it. Only the Gy gloss is retracted.

NO GUARD COULD HAVE FOUND IT, AND THE FIRST FIX MADE THAT WORSE. Three words, so
MIN_WORDS=5 puts it out of the phrase guard's reach; no "radiotroph", so
RETRACTED_IN_FIGURES missed it too. FIG-05 was covered by NOTHING. The first
version of that row wrote the claim as "(50 Gy cumulative), printed beside
m = 0.779" -- five words of my own prose, which distinguishing_phrase duly
extracted, so the phrase guard would have searched the sidecar for a run that
was never in the figure and passed. Manufactured coverage, caught by
test_the_figure_rows_are_honest_about_being_vocabulary_only, which exists for
exactly that. The row is now the in-plot string alone. Filing FIG-05 in that
test's vocabulary-only list without more would have been the same lie one level
up: a list named for rows the word list covers, holding a row it does not.

So the word list covers it now. "gy cumulative" is a UNITS term in a tuple
otherwise about a phenotype, which the note says out loud, and
fig3_membrane_transport_prefix.{pdf,txt} from e24dbec is the committed
known-bad input that proves it bites -- mutating the tuple back to
("radiotroph",) drops fig3 from the hits and the control fails. Committed, not
recovered with `git show`, for the reason the fixtures README already gives.

The stale print at test_claims_ledger.py:366 still enumerated "FIG-01, FIG-02"
one screen from the list it contradicts. Fixed in the same pass.

The generator edit is below the `#  13. Figure export` split marker, so
validate_serial.jl, runtests.jl and import_dose_field.jl cannot reach it and the
byte-pinned serial stream is untouchable by it. Confirmed green regardless.

Three ledger rows, one census entry. Julia suite green including the serial
contract; calibration 371, contract 7.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJu1d4TFhowR3GUtH2MdoG
Codex P1 on #23, reproduced and confirmed. `plot_panels` imported pyvista above
its own argument check, so in any environment without the `viewer` extra --
which is every environment the suite actually runs in -- `plot_panels([], ...)`
raised ModuleNotFoundError and never reached the ValueError it promises. The
import now sits below the check.

`test_plot_panels_refuses_an_empty_panel_list` was unskipped and asserting that
ValueError, and it PASSED THROUGHOUT, because a tier that has pyvista installed
reaches the check no matter which line comes first. It could not fail for the
defect it was written for. Rule 2 in the shape rule 2 warns about: the skip was
the coverage, and removing the skip did not add any.

So the control blocks the module itself rather than trusting the runner, and
bites on both tiers. Two details in it are load-bearing:

  IT ASSERTS THE BLOCK IS IN FORCE BEFORE TESTING ANYTHING. My first attempt at
  this reproduction used a `find_module` hook, which modern Python never calls,
  so the block silently did nothing and `plot_panels([], ...)` returned a clean
  ValueError -- a false negative that would have had me dismiss a valid P1 as
  unreproducible. A meta-path hook that does nothing looks exactly like a fix.

  IT RESTORES sys.modules AND sys.meta_path IN A finally. Leaving pyvista
  blocked would skip or fail the eight viewer-gated tests downstream of it and
  the cause would not be local to anything.

Verified by mutation: restoring the import above the check fails exactly this
new test and nothing else -- 1 failed, 51 passed -- while the original empty-list
test stays green, which is the whole point. Coupling suite 316 passed, 6 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJu1d4TFhowR3GUtH2MdoG
…e next one

Codex P1 on #23, reproduced and confirmed, and it reaches further than the
sentence it names.

THE BOUND. Section 6.2 asserted that beta_ion being negative for two of seven
species at -5e-5 made that "the largest radiation contribution that could favour
an accepted move". Delta H_rad is signed by ROLE as well as by the coefficient:
compute_delta_H_terms adds +beta_ion[source]*I when the source gains a site and
SUBTRACTS beta_ion[target]*I when the target loses one, so a POSITIVELY signed
species vacating a site favours acceptance exactly as much as a negatively
signed one occupying it. The bound is max|beta_ion| = 7.5e-2, not min. Wrong by
1.5e3. Measured over 192996 evaluated proposals from the seed-42 state at 100
MCS, 29.8 percent carry Delta H_rad < -5e-5 and the extreme is -0.0671. Table 3
gains the row whose absence made the error possible -- the same coefficient in
the other role, at -7.5e-2 and an acceptance bias of 1.0151 rather than 0.985.

THE COUNT MOVES TOO, AND THAT IS NOT WHAT CODEX ASKED ABOUT. PP-62-04 published
"zero of 206042". Re-measured, it is ONE of 206042: none under seeds 42 and 43,
one under seed 44. The denominator is exactly right.

FINDING THE RUN TOOK TWO ATTEMPTS AND IS ITS OWN DEFECT. run_simulation and
run_simulation_coupled both seed MersenneTwister and give 14281 accepted moves
at 100 MCS; Table 4 says 16037. That is reproduced only by the idiom in
tests/delta_h_decomposition.jl -- mcs_step! driven by hand with
Random.Xoshiro(seed) and update_melanin! each sweep. Neither b39fb8a nor d404438
committed a harness and nothing records the configuration, so the published
table describes a trajectory no shipped entry point produces. Ledgered as
PP-62-11. With it identified, EVERY cell of Table 4 reproduces exactly, along
with PP-62-05's 23 of 53603 and PP-62-06's per-seed contingent shares -- which
is what makes the rad row's disagreement a finding rather than a different run.

THE REAL RESULT IS ABSORPTION, NOT ABSENCE. Removing Delta H_rad alone reverses
16 accepted moves (4/3/9 by seed). Fifteen of them also carry an independently
decisive adhesion or volume term, so decisive_label returns `multiple` and the
`rad` row reads 0.00 percent while the term was in fact capable of deciding
sixteen. The corrected arithmetic predicts 16.67 and the withdrawn one predicts
0.26; 16 were measured. That agreement is the evidence the arithmetic is now
right, and an earlier estimate of mine put it at 58-76 by assuming most accepted
moves sit in the drawn branch -- only 11 to 16 percent do.

A CORRECTION THAT ONLY CHANGES THE NUMBER TEACHES NOBODY WHY IT WAS WRONG, so
tests/prose_bounds.jl reads max|beta_ion|*I0 off CPMParams and the stated bound
off the .tex and fails when they disagree. Nothing could have done that before:
contract_csv.jl guards the trajectory, delta_h_decomposition.jl guards that the
terms sum to the scalar, test_claims_ledger.py guards retracted PHRASES. None
reads a NUMBER out of the prose. Verified by mutation -- reverting the .tex to
5e-5 fails with isapprox(5.0e-5, 0.075). Its control asserts the withdrawn
sentence yields NO bound rather than a wrong one, explicitly, because otherwise
"no bound stated" and "the right bound stated" are indistinguishable, which is
the shape of gap that let this through. SCOPE STATED IN THE FILE: it gates one
number, not prose against code in general.

Version 1.2 correction block names both moved numbers and scopes its own
reassurance to the entries actually re-measured. It also fixes a sentence my own
fbb264b invalidated: the v1.1 block said figures 3 AND 4 carry a "per cent
depleted" label; only figure 4 does, and figure 3 has since been rebuilt.

PP-62-04 restated; PP-62-09, -10, -11 added. Julia suite green including the
byte-level serial contract; calibration 371, contract 7.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJu1d4TFhowR3GUtH2MdoG
PP-62-11's required_to_fix, both halves. The table was published from a run
NOTHING SHIPPED COULD RE-EXECUTE: run_simulation and run_simulation_coupled both
seed MersenneTwister and give 14281 accepted moves at 100 MCS against the
table's 16037, and the run that produces 16037 is the idiom in
tests/delta_h_decomposition.jl -- mcs_step! driven by hand with
Random.Xoshiro(seed) and update_melanin! each sweep. Neither b39fb8a nor d404438
committed a harness and no file recorded the parameters, so for two weeks the
published table could not be checked against anything.

decided_moves.jl reproduces it exactly: both columns in 8 s, all three seeds at
400 MCS in 13 s. The Table 4 caption now names the generator and the
Xoshiro/MersenneTwister distinction, so the configuration is recorded beside the
number as well as executable.

IT USES ONLY THE SHIPPED API. mcs_step! already takes `driver` and DriverCounts
already accumulates the labels, so decisive_label is called by the model rather
than reimplemented in the harness and the table cannot drift from the rule that
produces it. No radiodialysis, so no basis gate acknowledgement and no new
census site -- the CPM trajectory never reads the nutrient field, which is also
why the coupled and uncoupled paths give identical accepted counts.

IT STATES WHAT IT MUST REPRODUCE. The published counts are in the file and the
script exits nonzero on mismatch, rather than printing numbers with nothing to
check them against -- which is the condition the table was in.

tests/decided_moves_tests.jl makes that automatic instead of something someone
has to remember to run, and READS ITS EXPECTED COUNTS OUT OF THE SCRIPT'S OWN
TABLE rather than restating them: a second copy would let script and suite drift
and each look green. It pins the two numbers version 1.2 moved -- the 206042
denominator and rad == 1, not zero -- and its control steps the same run under
MersenneTwister and requires the totals to DISAGREE, which is the arm that
proves the comparison can fail.

One correction to my own hand: the caption first read 14037 where the measured
MersenneTwister count is 14281. A wrong number inside a correction about a wrong
number. Fixed, and re-verified against the code rather than against my memory
of it.

Julia suite green, +10 assertions; calibration 371, contract 7.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJu1d4TFhowR3GUtH2MdoG
@aurascoper

Copy link
Copy Markdown
Owner Author

@codex review

Re-review request: your last review covered 7712568, head is now 3267cdd (five commits). Both P1s from that review are fixed and resolved:

  • Empty panels before PyVista (observer.py) — reproduced and fixed in 8a7c28f. The pre-existing test could never have caught it, so it ships with a control that blocks the module itself; mutation-checked.
  • Target-cell losses in the radiation bound (§6.2) — reproduced and fixed in 5788db5. Confirmed, and it went further than the sentence: PP-62-04's "zero of 206042" is one of 206042. Bound wrong by 1.5e3, count wrong by one, corrected arithmetic now predicts 16.67 against 16 measured.

New since 7712568, and the parts most worth adversarial attention:

commit what to doubt
37c0b33 JACC checkerboard parity measurement. Thresholds are observed, not derived (Cramér's V < 0.025, maxdev < 0.12) from 3 seeds × 3 orderings at N=20/50 MCS. The color_order permutation is meant to separate a decomposition artifact from the documented vols cross-pass staleness — please check that separation actually holds.
fbb264b regenerate_fig3.jl opens basis_gate_ack on the claim that fig3's m(t)/P_eff never read the gated basis. Control is a 10× uptake perturbation that must move fig4 and not fig3.
5788db5 tests/prose_bounds.jl gates one number and says so. Manuscript at version 1.2.
3267cdd decided_moves.jl reproduces Table 4 exactly — its configuration matched no shipped entry point until now (PP-62-11).

Suites: Julia green incl. the byte-level serial contract, calibration 371, contract 7, coupling 316/6 skipped. preflight_merge.sh 23 refuses on STALE REVIEW only, which is what this comment is for.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3267cddc22

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/correspondence/wan_v11_note.md Outdated
Comment thread tests/prose_bounds.jl Outdated
…ited

Codex raised two findings on 3267cdd and both reproduce.

P1, docs/correspondence/wan_v11_note.md. The draft still told Caixia Wan that
the direct radiation term "reversed none of 206,042 moves". That is the version
1.1 count the version 1.2 correction withdrew. The note is unsent so nothing has
gone out, but it also said "nothing that changes a result" and offered to attach
the paper: it would have arrived carrying the withdrawn number alongside a
correction block stating that two published numbers moved. Step 4 of the
correction protocol is audit dependents, and it ran over the manuscript and the
ledger and not over correspondence.

P2, tests/prose_bounds.jl -- the guard written to stop exactly this class of
defect -- computed max|beta_ion| = 7.5e-2. For a copy between two OCCUPIED
parcels Delta H_rad is (beta_source - beta_target)*I, so the acceptance-favouring
reach is an extremum over PAIRINGS and not over species:
max(0, max beta) + max(0, -min beta) = 7.505e-2. The guard did not merely miss
the larger value. It asserted equality at rtol 1e-6 and would have REJECTED the
correct one.

ATTAINED, NOT ONLY DERIVED. A C. sphaerospermum source (-5e-5) copying into an
S. oneidensis target (7.5e-2) reaches -0.07505, four times in 1298668 evaluated
proposals at N=20, seed 42, 400 MCS. The three N=40 runs of Table 4 do not reach
it, which is why the single-role figure went unchallenged by the measurement
that accompanied it.

AND A THIRD, FOUND BY MEASURING THE SECOND. Section 6.2 said "measured over the
run, 29.8% of evaluated proposals carry Delta H_rad < -5e-5". No run was named
and none reproduces it. The fraction is configuration-dependent -- 0.1442 at
N=20/400 MCS, 0.2960 at N=40/60 MCS -- so naming the run is not a formality.
Restated as 26.7% over 3968838 evaluated proposals across seeds 42, 43 and 44 at
400 MCS, N=40: the Table 4 runs, now named in the sentence itself. This is
PP-62-11's own defect committed inside the fix for PP-62-04.

The instrumentation is an in-memory source rewrite that never edits the repo,
proved inert by lattice hash against the pristine module with a different-seed
control.

THE GATE IS MUTATION-CHECKED. Reverting the .tex to 7.5e-2 fails it at the
isapprox assertion; the file was restored byte-identical afterwards. The
extractor now refuses the max_s |beta| SHAPE whatever number it carries, because
a sentence bounding one role at a time is not a bound on Delta H_rad and reading
a number out of it would launder that.

Ledger: PP-62-09 to restate (0.075 -> 0.07505), PP-62-12 added for the
percentage, PP-62-04's notes record that its own evidence line came from an
unnamed run. My first draft of those rows used status "restated", which is not
in the verdict vocabulary, and put the corrected value in claim_text where the
row records the claim as published; test_every_row_has_an_id_and_a_verdict
caught both.

Julia suites green including prose bounds 18/18 and Table 4 10/10; calibration
371, contract 7, coupling 316 passed / 6 skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WJu1d4TFhowR3GUtH2MdoG
@aurascoper

aurascoper commented Aug 30, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Re-review request: your last review covered 3267cdd, head is now c38c2a3.

Both findings from that pass confirmed and fixed in one commit. What to doubt in it:

The bound itself tests/prose_bounds.jl now computes max(0, max β) + max(0, -min β), not (max β - min β). The claim behind that shape is that an absent parcel contributes nothing to the sum, so a coefficient vector of one sign would take its reach from one role alone. If that reasoning is wrong the two forms differ only for coefficients this repo does not ship, which is exactly the kind of guard that looks fine until it isn't.
Attainability I assert the pairwise extremum is reached, on evidence: a CS source (-5e-5) into an SO target (7.5e-2) gives -0.07505, four times in 1298668 evaluated proposals at N=20, seed 42, 400 MCS. Measured by in-memory source rewrite, proved inert by lattice hash with a different-seed control. The test itself only asserts argmax(β_ion) != argmin(β_ion), which is necessary and not sufficient.
The percentage I restated Measuring your P2 turned up a third error that was mine, not in your report: §6.2 said 29.8% of proposals carry ΔH_rad < -5e-5, "measured over the run", naming no run, and nothing reproduces it. Now 26.7% over 3968838 proposals across seeds 42/43/44 at 400 MCS, N=40, with the configuration in the sentence. Worth checking that the number and the named run actually correspond, since the previous version of this sentence is the reason to doubt it.
The Wan note Corrected count, marked rather than swapped. The reassurance sentences that became false are removed or scoped. Please check I did not leave a third one.

Two things you did not ask about that changed anyway. The built preprint PDF on my machine was still a version 1.1 build carrying the withdrawn count, which is the file that note offers to attach; rebuilt from source, still untracked per 1c43802. And my first draft of the ledger rows used a status outside the verdict vocabulary and put corrected values where the row records the claim as published — test_every_row_has_an_id_and_a_verdict caught it, which is the guard doing its job rather than me noticing.

The gate is mutation-checked: reverting the .tex to 7.5e-2 fails it at the isapprox line.

aurascoper and others added 5 commits September 1, 2026 10:56
…ound two instances a reader had not

FOUR ITEMS, ONE THREAD. omega_s (Table 2), Gamma_s (§2.3), the NAME H_kNN (§3.8) and
blasius1999 (uncited) are the same machinery seen from four places. Deciding them
separately would have meant reading the same evidence four times.

A. THE omega_s ROW IS DELETED ON AN INTERNAL CONTRADICTION, not a retention-class
judgement. §4 states that EVERY parameter in Table 2 is a literature-anchored prior;
omega_s is not one -- PP-T2-25 records its citations as theory sources for the model,
and the range was built to bracket a period no organism here is claimed to have. The
row and that sentence could not both stand, and that is decidable without reading §4's
intent. Corroborating only: §4 retains the alpha_M and K_s rows as MEASURED values
blocked by a cells-per-parcel conversion, a class omega_s is not in. The SYMBOL stays;
deleting a parameter claim is not deleting an equation.

THERE IS NO CONTROL FOR A REMOVAL and constructing one would be theatre. What was
checked is the side effects: kuramoto1984 and acebron2005 remain cited, no new orphan
appeared, §4's sentence became true.

B, C. §2.3's Gamma_s claim corrected and blasius1999 cited there. The bibitem was read
back against CROSSREF before use, not reconstructed from the key: 10.1038/20676 returns
Blasius, Huppert & Stone (1999), Nature 399, 354-359, matching on title, all three
authors, container, year, volume and pages. The key could as easily have been the
Blasius boundary layer.

AND WIDENING THE GUARD FOUND TWO THINGS NO READER HAD. The guard from 567b135 matched
H_kNN alone, so it could not see §2.2's "Our PSDE framework extends these precedents by
incorporating ... phase-locking dynamics that couple species interactions" -- a fourth
instance of the family PP-25-01 records -- nor §3.7, the one subsection naming this
machinery with no status statement at all, while PP-T2-25's notes had said "Section 3.7
is unimplemented" since the ledger was written. §3.7's disclaimer is scoped to the TERM,
not the subsection, because update_nutrient! does integrate a nutrient field every step
(biofilms_potts.jl:918, called at :1239) -- a blanket marker would have been false.

F. THE NAME H_kNN ASSERTS MACHINERY THE EQUATION DOES NOT CONTAIN. kNN is defined by a
distance metric, a ranking and a cutoff k; Eq. knn has none of the three and aggregates
across j=1..n under P_sj. It is a single product with no split, so "Decision Tree" names
nothing either. F_j is the fitness field §3.2 reports absent from the sources. Same class
as radiotrophy, which is what §1 was written for -- BUT §1'S RULE COVERS THE FIVE
PHENOMENON NAMES AS WRITTEN, so a reader applying it literally would not catch a METHOD
name doing the identical thing. RM-B02-01 is the sibling and prescribes the COMPLEMENTARY
subset, because reactor_decision_tree.R genuinely calls class::knn(k=3). Repaired on
§3.11's own coinage template rather than by renaming; rename stays available separately.

TWO ERRORS I MADE AND CAUGHT, BOTH WORTH RECORDING.
(1) Rewriting to satisfy the absence gate, I wrote "a single product term gives it the
branch structure a decision tree would need" -- the exact inverse of the claim. Dodging a
checker can invert a statement, and the checker will not notice.
(2) The guard's status vocabulary was three regex literals joined by `*`. Julia's Regex
`*` CONCATENATES: r"a|b" * r"c|d" is (?:a|b)(?:c|d), requiring both in sequence. It
matched almost nothing and reported four subsections as undisclaimed when one was. It
failed loudly but as a FALSE POSITIVE, which is the direction that gets a guard weakened
rather than fixed.

The guard now masks equations and table rows, maps each prose hit to its OWNING
SUBSECTION, and uses a vocabulary DISCOVERED by reading the subsections that already
disclaim correctly rather than invented. Subsection granularity is itself a correction:
paragraph level produced two false positives on correct prose.

@test_broken isempty(unused) IS NOW @test, AND THE TWO ARE NOT THE SAME CLAIM. The broken
form said "we expect orphans and want to be told when there are none". The strict form
says "an uncited bibitem is a failure", and its cost is real: the natural workflow is
add-the-entry-then-cite-it, and that intermediate state is now red. Accepted deliberately;
the classification sets make a future exception a recorded decision.

UNCITED BIBITEMS: ZERO. Nine on 2026-08-31, one this morning, none now.

Ledger: PP-T2-25 applied on the deletion branch; PP-23-01, PP-38-01, PP-37-01 added.
Renumbering cascade followed, not worked around: §3.4 anchor 585-598 -> 592-605, guide
citations :753 -> :780 and :1005 -> :1031, re-rendered with 19 citations verified.
absence_gate 133 -> 136; the three new flags are the house "specification, not method"
marker and two negations scoped to Eq.~\ref{eq:knn} by name.

425 pytest passed, Julia Manuscript claims 90 passed, 0 failed, 0 broken.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H2EuPqyhPoZoLE9SpxGorE
…f fixed

THE BRANCH ITS required_to_fix NAMED WAS NOT THE BRANCH THAT WAS AVAILABLE. The row
says "Delete or replace the references; the source files do not exist", and its
notes describe four PHANTOM figures in §§6.1-6.4 aliasing onto the four real ones --
"Figure 1 in section 6.1 RESOLVES TO THE CPM RADIAL-STRATIFICATION PLOT". Section 6
now contains ZERO literal figure references. The phantoms were removed in earlier
work and this row was never updated, so its location pointed at §§6.1-6.4 where
nothing remained, and "the source files do not exist" was true of the phantoms and
false of everything that was left.

A DEFECT RECORD GOING STALE WHEN THE DEFECT PARTLY CLOSES is the absence-record
family one verb over, and it is why the template is read-the-row-then-check-the-
branch rather than read-the-row-then-apply-it.

What actually remained were SIX literals, all in §8's version-correction passage and
all naming REAL figures. EACH WAS VERIFIED AGAINST THE FIGURE'S CAPTION AND FILENAME
BEFORE CONVERSION, not against its position, because this row's own history is that
these numbers once aliased onto the wrong plots: Figure 1 = fig:radial =
fig1_radial_stratification; 2 = fig:melanin; 3 = fig:membrane, whose caption reads
"membrane integrity $m(t)$" against prose saying "plots $m(t)$ and $P_{eff}/P_0$";
4 = fig:contaminant, matching FIG-03's "per cent depleted". None sat in a caption,
so no label-ordering subtlety arose -- checked rather than assumed.

FIGURES FLOAT, AND THAT MAKES THIS A STRONGER FIX THAN THE SECTION NUMERALS WERE.
A section number is one the author controls; a figure number is wherever LaTeX placed
the float, so the prose can become wrong with nothing moving in the source. Recorded
in the row and in the guard.

The guard now covers Figure~ as well as Section~. It excluded figures until today
with a reason and an owner -- PP-FIG-01, verdict unapplied -- and THAT EXCLUSION
EXPIRED WHEN THE ROW CLOSED, so the comment is rewritten rather than left standing.
An exclusion outliving its reason is how the __pycache__ skip went wrong.

Literal Section~N: 0. Literal Figure~N: 0. Dangling \ref: none.
absence_gate on the .tex: 136 before, 136 after.
425 pytest passed, Julia Manuscript claims 94 passed, 0 failed, 0 broken.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H2EuPqyhPoZoLE9SpxGorE
…thout its derivation

MOST OF THIS ANALYSIS WAS ALREADY IN THE TREE, and checking that first is what left
two items instead of six. §6.6 already says "This validates the implementation path,
not the physical target"; §3.12 already has the not-one-signed argument; §7.4 already
says the threshold must be declared prospectively AND that the same six measurements
permit both the resolution study and the offline test -- so there is no separate
uncertainty-reduction project, and that point needed no restating. SYN-E2E-01 already
records the one-way implementation claim as supported.

A. THE ONLY CLAIM FALSIFIABLE ABOUT THE WORLD HAD NO LEDGER ROW. Seven rows carry
§7.3 and none of them is the offline counterfactual. PP-CF-01 adds it,
needs_verification: well-posed and unrun.

It is kept apart from the implementation claim on purpose. SYN-E2E-01 is falsified by
an axis flip, a conservation violation or a mass-normalisation error -- what the
orientation probes and test_csg_mass.py's 4/pi exist for. PP-CF-01 is falsified by
physics: the dose-field difference between the current biomass configuration and a
plausibly perturbed one falling INSIDE the combined transport-statistical and
calibration uncertainty, at which point d(mu)/d(c) ~ 0 stops being a declared
simplification and becomes an empirically adequate one.

A NULL RETIRES THE TWO-WAY LOOP, NOT THE WORK, and the row says so in terms. The
one-way path stays supported, the manuscript stays publishable, and the null is itself
the reportable result -- retiring the loop on evidence rather than on cost. Written
loosely this row reads like a project-termination condition and makes running the test
look risky. It is the opposite, and a row nobody wants to run is a row that never gets
run.

B. §3.12 SAID "a reasonable simplification only while the sorbate is dilute and low-Z"
AND NEVER SAID WHY. Compton, photoelectric-as-mechanism, electron density and
"indistinguishable" appeared NOWHERE in the .tex -- searched, not assumed. That is this
repository's own "state the derivation, not the result" rule pointed at itself: a
reader could not check the condition and a future author could not locate its boundary.

The mechanism is now stated, and so is the boundary, because the two have DIFFERENT
EVIDENTIARY STATUS and only one waits on measurement. Compton dominance over C/H/N/O
means attenuation tracks electron density rather than atomic number, and hydrogen
sharpens rather than softens it -- highest electron count per unit mass of any element,
so a hydrated organic phase and water converge instead of separating. The boundary is
checkable with no measurement of this system at all: photoelectric returns below
roughly a few tens of keV for light elements. THE MAGNITUDE IS DECLINED EXPLICITLY --
the biomass/medium contrast needs the water fraction and closed hydrated composition
§7.4 lists as missing, and materials.py works in mass and volume with no composition or
Z/A handling. Asserting a number there would invent what the bench work exists to
supply.

FOUND BY A PREMISE CHECK, AND THE SHAPE DIFFERS FROM THE OTHER FOUR TODAY. Those were
claims about documents nobody had read. This was a document read CORRECTLY with the
reasoning underneath supplied silently -- the conclusion was right and its derivation
was imported from outside the text. Nothing in the manuscript was wrong, which is what
makes it hard to catch. Guarded now: the condition and its mechanism must coexist, with
a control asserting the bare condition alone fails.

Renumbering cascade was smaller than predicted and was checked rather than assumed:
only the guide citation AFTER §3.12 moved, :1031 -> :1044, re-rendered with 19
citations verified. The §3.4 anchor and the :780 citation are upstream of the insertion.

absence_gate on the .tex: 136 before, 136 after. PP-CF-01 is absent from the ENFORCED
NOWHERE report because its document is `preprint`, not because it has a guard.

425 pytest passed, Julia Manuscript claims 103 passed, 0 failed, 0 broken.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H2EuPqyhPoZoLE9SpxGorE
Distinguish the existence screen from design authorization in D3. A usable neutron weight now requires either direct target and spectrum relevance or explicit organism- and spectrum-transfer arguments, and the DTIC, Hoffman, NASBEE, search, author-outreach, and revisit paths carry the same condition.

Copy link
Copy Markdown
Owner Author

@codex review

Please review current head f2474a1d2734f1eab439858d00eb90ad266ba44b. All prior review threads have commit-specific replies and are resolved; merge-result CI on 87a1b6f0681232b6fdd6eab2dff956b476ddac97 is green.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f2474a1d27

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread calibration/tests/test_claims_ledger.py Outdated
Comment thread tests/jacc_parity_tests.jl Outdated
Comment thread coupling/tests/test_observer.py Outdated

Copy link
Copy Markdown
Owner Author

@codex review

Please review the current head 4dcc98fdef19562a6a0fad3cb6a0294bf4a26385. The three findings from the f2474a1 review were fixed in this commit, verified on synthetic merge 3457a896c66814430800da7c6b31467eac2a981e, answered with commit-specific evidence, and resolved.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

Copy link
Copy Markdown
Owner Author

@codex review

Please review current head 70039166e4a98037185af34b2b49cbc6a4b22510. It adds explicit mutation-control liveness and the narrow Julia-driver rule after the three f2474a1 findings. Synthetic merge f518111e3e97b7e375c723c39e27b0d713c5b079 is green: model-contracts run 126, coupling-tests run 223, manuscript 36 pages, calibration 428/5 expected skips, Python 7 plus coupling 316/6 expected skips, and Julia 20,488/20,488 including JACC parity 65/65. There are zero unresolved review threads.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

Copy link
Copy Markdown
Owner Author

@codex review

Retrying the current-head review request after the prior request remained unanswered for more than one hour. Review exact head 70039166e4a98037185af34b2b49cbc6a4b22510; synthetic merge f518111e3e97b7e375c723c39e27b0d713c5b079 remains green and there are zero unresolved threads.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Hooray!

Reviewed commit: 70039166e4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

aurascoper and others added 5 commits September 5, 2026 01:05
…, and the equation's symbols get a guard

PP-T2-25 deleted Table 2's omega_s row on 2026-09-01 and kept the symbol in
Eq. eq:adaptive, correctly: deleting a parameter claim is not deleting an
equation. But that row was the symbol's only description anywhere in the
manuscript. Table 1 lists the equation's other symbols, theta_s and gamma_s,
and did not list omega_s, so a reader of section 3.7 met a symbol defined
nowhere. This is the deletion's side effect that the row said could be
checked, found by a reader on 2026-09-05, not by a guard: the \ref guard
cannot see a math symbol.

The row added to Table 1 names omega_s as the phase frequency in phi_s and
says no value is assigned, since the adaptive term is unexercised. No
parameter value is claimed, so section 4's statement that every Table 2
parameter is literature-anchored is untouched, and the phase-locking status
guard masks table rows, so it does not fire on the new one.

The guard checks every symbol of eq:adaptive and its where-sentence against
Table 1 or an inline definition. Its controls run in both directions: the
precondition (the detector found the equation's symbols) is asserted
separately from the outcome (none missing), inline definitions are shown to
be recognised so phi_s and A_s are not false positives, and the omega_s row
is selected from the artifact, removed, the mutation asserted to have applied
in the table and not in the equation, and the check must then name exactly
that one symbol. A detector that flagged every symbol would pass "fires" and
fail that last assertion.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
…ds where the v1.2 text actually is

The tracked note was written for v1.1 and its own header said it had been superseded
twice. A tracked, complete, unsent note in a correspondence directory is exactly the
artifact someone later reads as cleared to send, so the file now carries the v1.2 text
that was gated and drafted in Gmail on 2026-09-05, its draft id, the artifact it attaches,
and what was verified against the manuscript diff before any of it was written. The
earlier draft stays below as the record of what changed, marked not to send.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
…atches up, and one caption points at the right table

A reader following the manuscript's repository link landed on master, which is
version 1.0, and the paragraph beside it said this revision was prepared against
4d8a5f8, ten commits behind the text it sat in. The link now names the tag
preprint-v1.2, to be placed on the commit whose CI build is verified, and the
revision line names 8754762, the parent of this commit, as the paragraph's own
rule requires. The version line moves from August to September 2026.

Table 3's caption said the pairwise reach was given beneath the table; it is given
in the prose beneath Table 4, and the caption now says so with a reference.

README's archiving line names preprint-v1.2 as the tag to archive and records
that preprint-v1 marks version 1.0 at 5ccadac, so the two tags are not confused
later. The Wan correspondence note records the build she holds, the working tree
of d404438 built 29 August 08:40, and drops the mailbox identifiers and address
that do not belong in a public repository.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
…manuscript line below 465 by one

26b3a14 inserted one row into Table 1 and shifted the manuscript by a line from
there down. Two calibration guards pin manuscript line numbers on purpose, so
that a move is noticed rather than absorbed, and both fired on CI while the
manuscript suite stayed green: the overdamped-regime paragraph is now lines
593 to 606, and the calculus guide's two citations into the manuscript point at
781 and 1045. Each target was re-read before renumbering, as the guard's own
message requires: line 781 still reads "Zero-flux symmetry is imposed at r = 0"
and line 1045 still carries "represented explicitly in the semi-discrete
operator". The guide's .tex was renumbered to match its .md, and the .pdf and
.md.sha256 were regenerated by tools/render_guide.py, which verified all 19
citations in the rendered text before recording the hash.

Locally: calibration suite 433 passed, 0 failed, from this worktree with
python -m pytest. The manuscript itself is unchanged in this commit.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
…seeds behind 206 042, and the abstract's bias

Five defects found by reading the version 1.2 PDF as a forwarded copy, none of
them a published number moving.

The byline asserted a degree in progress as a post-nominal; it now carries only
the conferred one. Section 6.2 pointed by name at a "Data and Code Availability"
section that does not exist; the section is Software and Data Availability.
Table 4's caption printed the reproduction command with the two-dash option
ligated into one glyph, so the command as printed could not be pasted; the
dashes are now protected. The 206 042 denominator is the sum of accepted moves
over seeds 42, 43 and 44 at 400 MCS, of which Table 4 shows only seed 42, and
the per-seed counts differ by more than half (53 603, 68 465, 83 974, from
decided_moves.jl's published table); the sentence now names all three and says
which one the table shows, and the two "three runs of Table 4" phrasings say
the same. The abstract read as if 7.505e-2 were the acceptance bias; it is the
reach in Delta H, and the bias it produces is 1.5 percent, which the sentence
now says.

Three Frontiers entries carried no DOI; the article-number DOIs were read back
from Crossref (titles match) before being added. The Introduction's sentence on
"reasoning" drops its "including as metaphor" clause. Two Julia guards that pin
the abstract and the "three runs" sentence by string are updated to the new
wording, and the version line, the repository link and the parent revision
move to 1.2.1, tree/preprint-v1.2.1 and 4bf1ba9. The tag preprint-v1.2 stays
where it is.

Locally, from this worktree: manuscript guards 70/70, prose_bounds 39/39,
rad_proposals 26/26, calibration 433 passed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
…gitignore hunks

master's thirteen geolocator and worldgrid commits were not in this lineage.
The one conflict was .gitignore, resolved exactly as in 1ddde52 on
feat/evidence-vocabulary: master's geolocator cache block and this lineage's
built-preprint block both stay. PR #23's head moves to this commit, so the
review gate sits at the head that would merge.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
aurascoper added a commit that referenced this pull request Sep 6, 2026
…ocabulary

The two merges of master resolved .gitignore identically, so this is a
history-only merge: it makes da5286a the shared ancestor of #23's head and this
branch, and #24's diff against fix/figure-artifacts-and-v11 is the bridge.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
…t on 2026-09-06

Checked against the mailbox: nothing to Caixia Wan has been sent since the
October 2024 thread, and the Gmail draft carries the v1.2.1 subject and the
copydesk-gated text, not the v1.2 text this note had filed as final. That
earlier text moves to the superseded section with the eight review findings
that retired it. No mailbox identifiers or addresses are recorded.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
aurascoper added a commit that referenced this pull request Sep 7, 2026
…vocabulary

Keeps #23's head as the shared ancestor so #24 stays the bridge alone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
…they made

The correction email went on 2026-09-05 at 3:33 PM CDT with the v1.2 build
(4bf1ba9, 36 pages) attached, from a mailbox the connected tools do not see,
so the 09-06 block saying "still drafted" was wrong. A follow-up with the
v1.2.1 build (3081a58, 37 pages) went on the same thread on 2026-09-06, and
the note now quotes both texts as sent, lists what v1.2.1 contains against
the build she holds, and states that "none to the numbers" is true of it.

WAN-EMAIL-01 in data/claims_ledger.csv names the sends as a claim sink
outside the repository (AGENTS.md, "Correcting a published number"): any
later correction of 1 500 times, one of 206 042, sixteen would reverse, or
9.6 in Delta H has to reach the recipient, and the row is how a query finds
that. No address or mailbox identifier is recorded in either file.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
aurascoper added a commit that referenced this pull request Sep 7, 2026
…-vocabulary

Keeps #23's head as the shared ancestor so #24 stays the bridge alone.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
aurascoper and others added 2 commits September 7, 2026 07:22
render_figure_svg.py no longer carries one workstation's interpreter
path: the cairosvg fallback runs in the interpreter executing the script,
after checking cairosvg imports there, and sidecars() refuses by name
when pdftotext is absent, since the .txt it writes is what the figure
phrase guard scans. subvoxel_refinement.py parses ratios in one function
that checks its two requirements by name, every ratio at least 1 and 1
present, so "0,1,2" is refused for the zero and not for a missing 1; five
cases cover both messages and the accepted ladder.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
Preserve the existing downstream claims guard byte for byte; it already includes the generated-artifact repair. Carry forward only the six regression cases from the backport. Validation: 46 ledger and generated-artifact tests passed on macOS arm64.
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.

1 participant