Regenerate the retracted figures, and the v1.1 material that followed - #23
Regenerate the retracted figures, and the v1.1 material that followed#23aurascoper wants to merge 101 commits into
Conversation
…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
There was a problem hiding this comment.
💡 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".
… 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
|
@codex review Re-review request: your last review covered
New since
Suites: Julia green incl. the byte-level serial contract, calibration 371, contract 7, coupling 316/6 skipped. |
There was a problem hiding this comment.
💡 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".
…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
|
@codex review Re-review request: your last review covered Both findings from that pass confirmed and fixed in one commit. What to doubt in it:
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 The gate is mutation-checked: reverting the .tex to 7.5e-2 fails it at the |
…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.
|
@codex review Please review current head |
There was a problem hiding this comment.
💡 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".
|
@codex review Please review the current head |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
@codex review Please review current head |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
@codex review Retrying the current-head review request after the prior request remained unanswered for more than one hour. Review exact head |
|
Codex Review: Didn't find any major issues. Hooray! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
…, 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
…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
…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
…-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
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.
Stacked on #20. Seven commits, in the order they happened.
The defect
fig2_melanin_accumulation.pdfsaid, 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."fig1said "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, andtests/runtests.jlsplits the monolith above# 13. Figure export, so the Julia suite cannot reachexport_figuresat 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
<figure>.txtas the document a row names.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
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-11records the one claim dropped for want of a readable source, in three parts: identified, inaccessible (HTTP 403, not absent), attribution unconfirmed.radiodialysisappeared 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_Hcomputed 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_labelreturnsmultipleand theradrow 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: summing1 - exp(rad/T_cpm)over drawn-branch accepted moves withrad < 0gives 16.67 against the sixteen measured.PP-62-04,PP-62-10.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-07records that refusal and the two alternatives also refused.Two guard findings
0.5 → 0.5000001in the melanin coefficient leavescontract_csv.jlbyte-identical;0.5 → 50.0fails it. Conditionally green with the condition unstated — a third kind of check-that-cannot-fail. Documented invalidate_serial.jl, paired with an exact===check whose control is that summation order is observable on 15.7% of moves.ΔH_mel = 0.0on all 21,492 sampled moves, because melanin only grows throughupdate_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.jlandtest_julia_interopfail 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
PYTHONPATHset to this tree or it measures the wrong package.🤖 Generated with Claude Code
https://claude.ai/code/session_01F4m1NqS1u9tuDRaqmNoQap