Ontology bridge: evidence relations, units with dimensions, the lattice system, and the prior-versus-shipped coefficients - #24
Conversation
…e for claims A ledger value and a manuscript claim are backed by different kinds of thing, and the repository held four disagreeing copies of "the" evidence vocabulary: the parameter-ledger test (8 values), the calibration schema (8, with a status misfiled as a basis), the claims ledger's header (5) and its data (12 in use, 90 rows outside the header's own list). Both sets now live in physical_contract and the consumers read them as one object. The claims ledger stored provenance SOURCES (simulation_output, code, code_inspection, repository_policy) in its evidence column, plus two spellings (literature, none). Its convention is additive, and evidence_basis has never been edited in place, so the 173 rows keep their stored values: a canonicaliser reads them as (basis, source), and an allowlist keyed by (claim_id, stored_value) is asserted equal to the ledger's legacy rows in both directions, so it may shrink and may not grow. A new row must write the canonical form. `derived` stays in both sets but is documented as a source with an unresolved basis under the manuscript's weakest-input rule, and must get no external evidence class. The species table, which had zero consumers, is now read. Controls: planted rows in each direction; the live-data relation check fails on zero hits rather than on "no violation found". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
…the package CI's shared-contract tier installs contract and coupling only, so the test asserting biofilm_calibration.schema.EVIDENCE_BASIS is the contract object raised ModuleNotFoundError there. It now lives in calibration/tests, where the package exists and a planted copy fails it. Local runs had masked this with a PYTHONPATH covering all three packages. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
…ord has an IRI row data/ontology_bridge.csv maps 85 terms: the five phenomenon words, both evidence vocabularies, the source axis, the two nulls, 26 unit strings and 21 quantity kinds. 55 rows mirror external terms, each re-verified today (OBO labels through the OLS4 API, units and kinds against QUDT v3.5.1); 28 are minted under the project namespace with a mirrored nearest parent; `derived` is unmapped on both basis axes by rule. Units carry SI base exponents and name their quantity kind, and the test checks the two agree by arithmetic, so the phase-locking rad/hr (an angle rate, T^-1) and the manuscript's R/h (an exposure rate, M^-1 I) both fail if mapped to the absorbed-dose rate rather than by string. Counts are dimensionless and keep what they count in count_of. The test is offline: both directions between the contract sets and the file, every unit string in the four unit-carrying ledgers has a row, namespaces are disjoint by prefix, every phenomenon row states its endpoint, and blank verified_on rows must equal an exception list that is empty. The claims ledger's reported_unit column is a free-text register (87 strings, among them "sliders" and "TCP port") and is not a unit vocabulary; it is out of scope. Findings while verifying: QUDT v3.5.1 has no MicroM2-PER-SEC, PER-GRAY or R-PER-HR (all minted); MicroM-PER-SEC exists and is verified; OBI:0000011 is obsolete and is not used. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
… definitions Twenty-nine rows: seven model terms (the two isotherms, the Robin condition, Donnan dialysis, radiolysis of water with hydroxyl as a cross-reference, biosorption, bioreduction) whose parents are IAO information content entity or BFO process; twenty-one quantity kinds for the coefficients and groups, including the sheet's four diffusivities D_N,bio, D_C,bio, D_C,app and D_C,disp as distinct rows under one dimension; and four new mirrored anchors (CHEBI hydroxyl, QUDT SecondOrderReactionRateConstant, SoilAdsorptionCoefficient, VolumeFraction) verified today. Three columns. parent_relation says whether a minted term's parent is same_dimension (exponents checked by arithmetic) or semantic, so the Velocity parent of membrane permeability and k_L reads as a dimension statement and not a meaning claim. definition is required on every model term, every minted kind and every dimensionless kind, because the Thiele modulus, effectiveness factor and Fourier number all carry seven zeros; the definitions are the sheet's (phi_0 = L sqrt(k_0/(D N_w)), eta = min(1, sqrt2/phi_0), Fo = Dt/L^2). xref must name a mirrored row and is never a parent. Out of scope, named: k_0, the nutrient constants and D_N,bio's value are in lattice units and wait for step 4's second unit system; k_m is in neither the repository nor the sheet's table; the G-value is not used by any source file. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
CI on 4c85ea6 failed julia-tests: the manuscript guard enumerates every file carrying X_max, q_max or Langmuir and requires each to be on a declared list, and the bridge's step 3 rows name all three as terms. The local run before that push covered the contract suite only; the Julia manuscript suite, run here from the omega worktree against the Biofilms-v11 project, is 4/4 on the guard with the bridge declared. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
Eleven lattice unit rows over the bases latt, MCS and H, the CPM's own length, clock and energy, keeping the SI exponent pattern (a lattice diffusivity is still L^2 T^-1) with an H column for the Hamiltonian base, so the unit-equals-kind arithmetic holds within a system. D_C and D_M live in latt^2 per field step, D_s in latt^2 per MCS, kappa per latt, the uptake rates per field step, T_cpm and Delta H in H; I0, C_wall and c_ext are normalised. Three conversion rows. latt->m and MCS->s are blocked on D-PITCH and D-TIMESERIES in reference_d_requirements.csv, and the test requires a blocked row's requirement to still be awaiting_measurement, so when the pitch is measured the bridge goes red until the factor is filled. MCS->s depends on latt->m and cannot be ready first. The synthetic reference's 1.2 cm dosimetry pitch has its own row and system, basis synthetic, so it can never be read as the biological factor. The coupled diagnostic's Ddot_R is a unit row named placeholder with no quantity kind, and the test refuses to let it acquire one: the '50 Gy cumulative' defect e4021c0 removed, pinned at the data layer. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
…nguished by a test beta_s,ion and alpha_M each exist twice: the Table 2 literature prior in Gy^-1 or ug cell^-1 Gy^-1, and the coefficient CPMParams ships in the lattice system (H for beta_ion, per field step for alpha_M_species), the same midpoint number used as-is. Five coefficient rows pair them through substitution_of and a relation: declared_substitution for the two pairs the manuscript declares in sec:params, and hard_coded_replacement for the 0.5 melanin coupling that stands where alpha_M would enter the acceptance term (PP-T2-29, cpm.melanin_coupling), the coefficient through which radiation actually reaches the dynamics. The tests read the source: CPMParams' two commented vectors are parsed by species tag, and every shipped value must lie inside the Table 2 range for that species, with a value for a species that has no row required to be zero (OI's beta is the one commented exception). The shipped row must sit in a different unit system from its prior, its declared_in label must exist in the .tex, its ledger rows must resolve, and the 0.5 literal must still appear exactly twice in compute_delta_H_terms. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
🟡 Changes recommended
tools/render_figure_svg.py hard-codes a developer-specific Python path and should be made portable (and fail with clearer prerequisites) before merge.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR extends the repository’s “contract-first” discipline by wiring more scientific/operational semantics (evidence-basis relations, gated radiodialysis basis provenance, lattice/time unit systems, coefficient provenance) into enforced vocabularies, guards, and reproducible producers, while also tightening CI so previously-skipped surfaces become exercised.
Changes:
- Adds/extends multiple offline contract guards and negative controls (evidence-basis relations, basis-gate acknowledgements, refusal ordering, single-draw synthetic gate refusal, rasterization ladder non-tiling pitch refusal).
- Introduces reproducible producers for manuscript-reported numbers/figures (e.g., Table 4/§6.2 producers, acceptance-regime figure generation) and adds/updates committed figure sidecars/hashes.
- Consolidates environment specification and CI setup to reduce drift and eliminate silent skips (micromamba environment.yml, xvfb/poppler-utils installation, merge gate job).
File summaries
| File | Description |
|---|---|
| validate_serial.jl | Documents serial CSV check detection floor; explicitly acks gated radiodialysis basis. |
| tools/render_guide.py | Renders guide TeX with tectonic, validates citation anchors in PDF text, records source hash. |
| tools/render_figure_svg.py | Renders SVG→PDF and writes joint source/output digests plus required PDF sidecars. |
| tests/runtests.jl | Expands Julia test entrypoint to include new guard/provenance/report suites. |
| tests/rad_proposals_tests.jl | Pins §6.2 proposal statistics producer and proves on_proposal hook inertness. |
| tests/genealogy_tests.jl | Adds basis_gate_ack for tests that must step a gated radiodialysis basis. |
| tests/decided_moves_tests.jl | Ensures Table 4 is reproducible from a shipped entry point and can fail under MT RNG. |
| tests/console_report_tests.jl | Guards against fabricated physical units in console reports and scans all producers. |
| tests/checkpoint_io_tests.jl | Adds HDF5 export provenance fields for gated basis and asserts both directions. |
| scripts/assert_numpy_receipt.py | Verifies numpy “receipt” structure/content with self-test and pinned expected cases/checks. |
| regenerate_fig3.jl | Provides a runnable, controlled fig3-only regeneration path under basis gating. |
| rad_proposals.jl | Shipped producer for per-proposal ΔH_rad stats reported in §6.2. |
| Project.toml | Adds CairoMakie dependency for figure generation. |
| preprint/figures/phase2_diffusion_cell.txt | Adds committed text sidecar for a figure/diagram extraction path. |
| preprint/figures/phase2_diffusion_cell.svg.sha256 | Adds framed source/pdf/pair digest for the SVG/PDF pair. |
| preprint/figures/phase2_diffusion_cell.sha256 | Adds bare PDF sha256 sidecar. |
| preprint/figures/fig5_acceptance_regime.txt | Adds pdftotext sidecar for Fig 5 acceptance regime. |
| preprint/figures/fig5_acceptance_regime.sha256 | Adds bare PDF sha256 sidecar for Fig 5. |
| preprint/figures/fig4_contaminant_penetration.txt | Adds pdftotext sidecar for Fig 4. |
| preprint/figures/fig4_contaminant_penetration.sha256 | Adds bare PDF sha256 sidecar for Fig 4. |
| preprint/figures/fig3_membrane_transport.txt | Adds pdftotext sidecar for Fig 3. |
| preprint/figures/fig3_membrane_transport.sha256 | Adds bare PDF sha256 sidecar for Fig 3. |
| preprint/figures/fig2_melanin_accumulation.txt | Adds pdftotext sidecar for Fig 2. |
| preprint/figures/fig2_melanin_accumulation.sha256 | Adds bare PDF sha256 sidecar for Fig 2. |
| preprint/figures/fig1_radial_stratification.txt | Adds pdftotext sidecar for Fig 1. |
| preprint/figures/fig1_radial_stratification.sha256 | Adds bare PDF sha256 sidecar for Fig 1. |
| jacc_acceptance_figure.jl | Adds Fig 5 generator (acceptance rates + ΔH distribution) with printed provenance. |
| export_checkpoint.jl | Exports/restores sticky gated-basis provenance into restart checkpoints; acks basis gate for CLI export. |
| environment.yml | Adds a single pinned transport environment spec consumed by workflows/docs. |
| docs/research/radiotrophic_compatibility_audit.md | Adds detailed read-in of Robertson 2012 and clarifies melanin dependence limits. |
| docs/research/murr_facility_candidate.md | Adds explicitly-unsourced forward-looking facility candidate note with stop conditions. |
| docs/preprint_revision_plan.md | Marks document as SUPERSEDED and corrects/updates provenance/status notes. |
| docs/openmc_stack.md | Switches environment instructions to environment.yml and documents golden-tally fixture regen path. |
| docs/jacc_coupling_port.md | Documents new decomposition measurement and clarifies reproducibility limits. |
| docs/guides/calculus_in_this_code.md.sha256 | Adds recorded md hash sidecar for guide rendering provenance. |
| docs/exchange_schema.md | Clarifies two distinct grid transforms and points to new co-registration coverage. |
| docs/correspondence/deng_tracer_note.md | Adds held draft correspondence note with explicit release conditions. |
| docs/calibration/sop/matched_blank.md | Adds SOP defining matched blank requirements and disposition. |
| docs/calibration/sop/imaging_segmentation.md | Adds SOP for voxel calibration + declared segmentation basis constraints. |
| docs/calibration/sop/harvest_dewatering.md | Adds SOP for wet/dry mass procedure with gating preconditions and declared variance measurement. |
| docs/calibration/reference_d_measurement_protocol.md | Clarifies per-strain biosafety mapping is keyed by verbatim strain identifiers. |
| docs/calibration/openmc_nested_pilot_report.md | Adds publication-block rule for gate/significance disagreement and raises minimum outer draws. |
| docs/calibration/morphology_rasterization_ladder.md | Withdraws contaminated non-tiling pitch row and corrects dependent findings/ranges. |
| docs/calibration/integration_contract.md | Corrects β_ion reach explanation (role-signed reach vs one-role magnitude). |
| decided_moves.jl | Adds shipped producer for Table 4 decisive-label counts under the correct stepping idiom. |
| data/uncertainty/feedback_parameter_distributions.csv | Corrects melanin-coupling magnitude comparison text to reflect corrected reach. |
| data/species_parameter_provenance.csv | Adds reshaped Table 2 provenance table for queryable weak-prior classification. |
| data/parameter_provenance.csv | Corrects melanin_coupling note to reflect β_ion reach; updates magnitude comparison. |
| data/calibration/suspended_isotherm_proposal.csv | Adds non-authoritative planning worksheet with explicit non-gate semantics. |
| data/calibration/spatial/sources.csv | Adds several “identified via web search” sources explicitly flagged as not read in full. |
| data/calibration/spatial/dataset_candidates.csv | Adds surrogate/phantom search axis entries and a diagnostic-only surrogate candidate. |
| data/calibration/reference_d_requirements.csv | Fixes status vocabulary documentation to match loader-accepted values and adds drift test rationale. |
| coupling/tests/test_viewer_bundle.py | Declares background=0 for cell_id labels in viewer bundle tests. |
| coupling/tests/test_synthetic_gate_fixtures.py | Adds test refusing single-draw runs even with large apparent effect. |
| coupling/tests/test_provenance_ledger.py | Unifies evidence vocabulary with calibration via shared contract object. |
| coupling/tests/test_mesh.py | Adds control ensuring scan() refuses before invoking runner (no histories spent). |
| coupling/tests/fixtures/pilot_verdict_significance.json | Adds committed reduced verdict fixture for publication_block testing. |
| coupling/scripts/synthetic_e2e.py | Writes a multi-grid viewer bundle so bundle_problems co-registration checks apply to this path. |
| coupling/scripts/subvoxel_refinement.py | Refuses non-divisor ratios early; clarifies occupancy/background semantics in bundle layers. |
| coupling/pyproject.toml | Adds pyvista/pyyaml into dev extras to eliminate silent skips and brittle transitive deps. |
| coupling/biofilm_openmc/synthetic_gate.py | Refuses draws.size<2 with explicit degrees-of-freedom rationale. |
| coupling/biofilm_openmc/drivers.py | Ensures scan() calls mass_of up-front so unsupported configs refuse before transport. |
| contract/tests/test_evidence_basis.py | Adds evidence-basis relation tests, canonicaliser + allowlist enforcement with planted controls. |
| contract/tests/fixtures/claims_ledger_legacy_evidence.csv | Adds pinned allowlist of legacy evidence_basis spellings that may shrink but not grow. |
| CLAUDE.md | Adds repository standards pointer to AGENTS.md for Claude Code workflows. |
| calibration/tests/test_rasterization_ladder.py | Splits slab vs sphere pitch ladders, adds non-tiling refusal controls and skip-tail invariants. |
| calibration/tests/test_evidence_vocabulary.py | Ensures calibration schema uses the contract evidence-basis object identity (not a copy). |
| calibration/tests/test_approval.py | Tightens per-strain biosafety mapping binding and adds multiple negative controls. |
| calibration/tests/fixtures/README.md | Documents committed negative-control fixtures and why they must not be regenerated. |
| calibration/tests/fixtures/phase2_diffusion_cell_prefix.txt | Adds known-bad extraction fixture for FIG-09/10 reachability failure mode. |
| calibration/tests/fixtures/fig3_membrane_transport_prefix.txt | Adds known-bad text fixture for fig3 prior claim detection. |
| calibration/tests/fixtures/fig2_melanin_accumulation_prefix.txt | Adds known-bad text fixture for fig2 prior claim detection. |
| calibration/tests/fixtures/fig1_radial_stratification_prefix.txt | Adds known-bad text fixture for fig1 prior claim detection. |
| calibration/scripts/reference_d_status.py | Switches authorization criteria mapping to structured subjects (no prose parsing) and loads sources registry. |
| calibration/scripts/rasterization_ladder.py | Refuses non-tiling pitches (named skip rows) and prevents skipped rungs from breaking convergence tails. |
| calibration/biofilm_calibration/spatial/synthetic.py | Refuses non-tiling pitches via NonTilingPitchError instead of rounding voxel counts. |
| calibration/biofilm_calibration/schema.py | Replaces local evidence-basis set with shared contract object and removes “unresolved” basis drift. |
| calibration/biofilm_calibration/acquisition.py | Documents biosafety mapping keyed by exact strain IDs; disallows ambiguous abbreviations. |
| .gitignore | Ignores built preprint PDFs (treating them as build artifacts). |
| .github/workflows/coupling-tests.yml | Uses environment.yml for micromamba, installs xvfb/poppler-utils, runs merge-gate negative controls. |
Review details
- Files reviewed: 105/146 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…gnore hunks master's thirteen geolocator and worldgrid commits were not in this stack. The one conflict was .gitignore: master appended a geolocator cache block and the stack appended the built-preprint block at the same place. Both stay. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7
There was a problem hiding this comment.
🟡 Changes recommended
The review found portability/robustness issues in new tooling (hard-coded interpreter path, missing dependency preflight, and a ratios-validation edge case) that should be fixed before merge.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 105/146 changed files
- Comments generated: 1
- Review effort level: Lite
The five coefficient rows now carry a basis, and the test requires it to agree with the evidence_basis of every ledger row the coefficient names: derived for the six beta_s,ion priors, declared for the alpha_M priors, the two normalization scales and the 0.5 coupling. A hard_coded_replacement row may have no basis but declared, so a citation on the 0.5 fails twice, once against the rule and once against PP-T2-29. 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
There was a problem hiding this comment.
🔵 Needs a closer look
The new render_figure_svg and assert_numpy_receipt utilities have portability/robustness issues (hard-coded interpreter path, missing dependency checks, and schema-type crash paths) that should be fixed before approval.
Review details
- Files reviewed: 10/10 changed files
- Comments generated: 0 new
- Review effort level: Lite
…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
…-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
…and advection errors D_C_bio no longer enters the Tier 0 reactor model: it is the slab preset's molecular D_eff (slab_parms), and the reactor slot is D_C_disp alone. D_C_disp is a dispersion coefficient of a diffusion-reaction model; the code has no advection term, and tracer tests are what will pin it, not what has. The seven notes that named the internal sheet as their source now say only that downstream renderings read the row: the bridge is upstream of the sheet from here, and a public file need not name a gated consumer. 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
…t/evidence-vocabulary
What this is
The repository's controlled vocabularies, unit strings and phenomenon words, mapped to external IRIs or minted under a project namespace, with the repo's typed contract and an offline test suite as the checker. Five steps, eight commits, each with a green
coupling-testsrun on the commit that stands.Stacked on #23; merges after it. The base is
fix/figure-artifacts-and-v11. #23's gate, a Codex review at the head that merges, is unchanged. Master was merged into both branches with the same.gitignoreresolution (da5286a on #23's branch, 1ddde52 here, joined by 1deec76), so this PR's diff is the bridge and nothing else: ten files.The steps
data/ontology_bridge.csv: phenomena, both evidence vocabularies, sources, nulls, 26 unit strings, 21 quantity kinds; SI exponents so rad/hr and R/h fail by arithmetic if mapped to a dose rate.parent_relation,definition,xref.latt->mandMCS->sblocked on D-PITCH and D-TIMESERIES so the bridge goes red when either flips; the synthetic 1.2 cm pitch in its own system; the dose-rate placeholder pinned to no quantity kind.declared_substitutionorhard_coded_replacement; the test parsesCPMParamsand requires every shipped value inside its Table 2 range.basismust agree with every ledger row it names; a hard-coded literal may only bedeclared.Merge commits: 1ddde52 (master into this branch), 1deec76 (#23's branch, with master, into this branch).
Shape at the tip
135 rows over eleven axes: 60 mirrored (OBO labels re-verified through the OLS4 API, units and kinds against QUDT v3.5.1 on 2026-09-06), 73 minted with a mirrored nearest parent and a stated parent relation,
derivedunmapped on both basis axes by rule. Contract tests: 30, all offline.Controls
41 planted failures across the five steps, each applied to the real file, confirmed at the level the assertion reads, seen red, restored green. Four mutants survived on first application and all four were bad mutations, not gaps (a column-blind replace, a frozenset identity, a restore on uncommitted state twice); the harness now refuses to plant on a file that differs from HEAD.
Out of scope, named
reported_unitcolumn: 87 free-text strings, not a unit vocabulary; mapping it needs a unit key column across 356 rows.🤖 Generated with Claude Code
https://claude.ai/code/session_01UR6L4KXRqhcHQkDdq5kbX7