Materials Chemistry Closed-Loop Lab-Safety Replay
The materials chemistry lab-safety replay validates metadata-only simulator-only closed-loop rows before any materials-lab or discovery language is allowed.
The write-up
"Closed-loop materials lab" is easy language to overclaim. A fixture can look like an autonomous discovery loop while carrying nothing that should be spoken aloud: wetlab steps, reagent quantities, a controlled or bioactive target, robot commands, or a bare assertion that some material was found. "Closed-loop materials lab" is easy language to overclaim. A fixture can look like an autonomous discovery loop while carrying nothing that should be spoken aloud: wetlab steps, reagent quantities, a controlled or bioactive target, robot commands, or a bare assertion that some material was found. This component sits in front of that language and answers one question. Is a closed-loop-lab-shaped fixture safe and grounded enough to be talked about at all, in a simulator-only frame, before any lab claim is allowed?
Its stable id is materials_chemistry_closed_loop_lab_safety_replay, and its public surface name (PUBLIC_SURFACE_NAME) is materials_chemistry_artifact_safety_refusal_validator. Its stable id is materials_chemistry_closed_loop_lab_safety_replay, and its public surface name (PUBLIC_SURFACE_NAME) is materials_chemistry_artifact_safety_refusal_validator. The promise-sounding "closed-loop replay" name was reframed on purpose: nothing here executes a wetlab loop or commands a robot. The component reads public simulator rows, recomputes a winner, checks refusals, and writes a metadata-only result record. It emits a verdict of either public_safe_simulator_replay_accepted or blocked_public_safety_boundary, plus the findings that produced it.
The part worth naming is that the component does not trust the fixture's own conclusion. A plain replay would read a declared "selected candidate" label and report it. The part worth naming is that the component does not trust the fixture's own conclusion. A plain replay would read a declared "selected candidate" label and report it. This one recomputes the winner from public numbers and treats a mismatch with the declared label as a failure, not a footnote.
Purpose
A loose reader of a lab fixture accepts a declared winner and a "safe" flag at face value. A loose reader of a lab fixture accepts a declared winner and a "safe" flag at face value. That fails two ways. A stale or flattering label passes even when the numbers no longer support it, and dangerous content slips through because nothing is watching for it. This component closes both gaps. It rederives the selection from score-backed rows, and it treats eight named categories of dangerous or overclaiming content as things to refuse rather than ignore. The result is fixture-bound evidence that the loop's structure is inspectable on a simulator, with no real lab, chemicals, or robot involved.
How it works
There are two entrypoints. run validates a first-wave fixture directory with negative cases included. There are two entrypoints. run validates a first-wave fixture directory with negative cases included. run_lab_bundle validates an exported bundle with include_negative=False and requires a copied source-module manifest. Both call _build_result to compute the payload, attach _freshness_basis, and write the result record. run_lab_bundle can reuse a still-fresh prior record through _fresh_lab_bundle_receipt when the input digests are unchanged.
_build_result runs in this order.
| Function | Role |
|---|---|
_load_payloads | Reads the six positive inputs (protocol, policy, candidates, experiment DAG, assays, decisions) and, in fixture mode, the eight forbidden negative inputs |
_candidate_findings, _experiment_findings, _assay_findings, _decision_findings | Check required fields, cross-references, and safety flags on each row; each missing field or bad link becomes one finding |
_numeric_replay_result | Recomputes the selected candidate from public scores; the core check |
_source_module_manifest_result | Verifies copied source-module bodies by digest without putting body text into the record; required only in bundle mode |
scan_paths, _secret_exclusion_scan | scan_paths sweeps the input set against the forbidden-class list and reports blocking hits; _secret_exclusion_scan drops body text from that scan record so it stays metadata-only |
build_materials_lab_evolve_replay | Builds the Lab/Evolve replay graph from the same payloads and findings |
The numeric recompute is the heart. _numeric_replay_result reads public_safety_gate_score from each candidate, public_assay_proxy_value from each assay, and public_active_learning_score from each decision. The numeric recompute is the heart. _numeric_replay_result reads public_safety_gate_score from each candidate, public_assay_proxy_value from each assay, and public_active_learning_score from each decision. _numeric_value accepts a number only when it is finite and in [0, 1]; anything else yields MATERIALS_NUMERIC_REPLAY_SCORE_OUT_OF_RANGE or MATERIALS_NUMERIC_REPLAY_SCORE_REQUIRED. When no score field is present at all, the run blocks with MATERIALS_NUMERIC_REPLAY_POLICY_REQUIRES_SCORE_BACKED_ROWS (policy active) or MATERIALS_NUMERIC_REPLAY_REQUIRED. Scores are joined by candidate id. A candidate missing one of its three scores gives MATERIALS_NUMERIC_REPLAY_LINKAGE_REQUIRED. A safety gate below NUMERIC_REPLAY_MIN_SAFETY_GATE (0.70) gives MATERIALS_NUMERIC_REPLAY_SAFETY_GATE_FAILED.
The weighted candidate score
For each linked candidate the weighted score is 0.45 * assay_proxy + 0.35 * active_learning + 0.20 * safety_gate. For each linked candidate the weighted score is 0.45 * assay_proxy + 0.35 * active_learning + 0.20 * safety_gate. The winner is the maximum by score, ties broken by id. Only after that pick is computed does the component compare it to the policy's declared expected label. A mismatch is MATERIALS_NUMERIC_REPLAY_EXPECTED_LABEL_STALE. Numeric replay reports pass only when there are no findings and at least one verified row.
The baseline fixture holds four candidates.
| Candidate | Safety gate | Assay proxy | Active-learning | Weighted score | Decision / action |
|---|---|---|---|---|---|
mat_polymer_membrane_001 | 0.94 | 0.92 | 0.90 | 0.917 | decision_membrane_001 / simulate_assay |
mat_solid_electrolyte_002 | 0.91 | 0.84 | 0.81 | 0.8435 | decision_electrolyte_002 / update_surrogate_model |
mat_catalyst_support_003 | 0.85 | 0.78 | 0.74 | 0.780 | decision_support_003 / choose_next_simulation |
mat_sorbent_surface_004 | 0.88 | 0.70 | 0.66 | 0.722 | decision_sorbent_004 / screen_candidate |
The recompute selects mat_polymer_membrane_001 at 0.917, which matches the policy's expected_selected_candidate_material_id. The recompute selects mat_polymer_membrane_001 at 0.917, which matches the policy's expected_selected_candidate_material_id. The policy declares minimum_safety_gate_score 0.70 and the selection rule max_weighted_public_assay_active_learning_and_safety_gate_score.
_build_result folds every check into one policy_passed gate: the four row sets are non-empty, no positive finding fired, no forbidden content leaked into the encoded rows, no expected negative case is missing, every row is simulator_only, every hazard flag is false, and numeric replay passed. _build_result folds every check into one policy_passed gate: the four row sets are non-empty, no positive finding fired, no forbidden content leaked into the encoded rows, no expected negative case is missing, every row is simulator_only, every hazard flag is false, and numeric replay passed. The overall status is a pass only when policy_passed holds, the secret scan passed, the replay graph passed, and, in bundle mode, the source-module manifest passed. The verdict string follows that status.
Diagram source & refs
flowchart TD inputs["six public inputs protocol, policy, candidates, experiments, assays, decisions"] rows["per-row field + link checks"] numeric["numeric recompute 0.45 assay + 0.35 active + 0.20 gate"] labelcheck["recomputed pick vs declared label gate >= 0.70"] negatives["eight forbidden fixtures"] refuse["any MATERIALS_*_FORBIDDEN observed"] manifest["source-module manifest digest check (bundle mode)"] scan["secret exclusion scan"] status["status + safety verdict"] accepted["public_safe_simulator_replay_accepted"] blocked["blocked_public_safety_boundary"] inputs --> rows inputs --> numeric numeric --> labelcheck labelcheck --> blocked labelcheck --> status negatives --> refuse refuse --> blocked refuse --> status manifest --> status scan --> status rows --> status status --> accepted status --> blockedNegative cases
EXPECTED_NEGATIVE_CASES names eight forbidden fixtures, each with the code the component must raise when it observes one. EXPECTED_NEGATIVE_CASES names eight forbidden fixtures, each with the code the component must raise when it observes one. A run that fails to refuse any of them lists the case under expected_missing and blocks.
| Forbidden fixture | Code |
|---|---|
wetlab_protocol_steps | MATERIALS_WETLAB_PROTOCOL_FORBIDDEN |
hazardous_synthesis_steps | MATERIALS_HAZARDOUS_SYNTHESIS_FORBIDDEN |
reagent_amounts | MATERIALS_REAGENT_AMOUNT_FORBIDDEN |
controlled_or_bioactive_target | MATERIALS_CONTROLLED_OR_BIOACTIVE_TARGET_FORBIDDEN |
| live lab account secrets | MATERIALS LIVE LAB account secret FORBIDDEN |
robot_command_execution | MATERIALS_ROBOT_COMMAND_FORBIDDEN |
private_lab_notebook_export | MATERIALS_PRIVATE_LAB_NOTEBOOK_FORBIDDEN |
discovery_claim | MATERIALS_DISCOVERY_CLAIM_FORBIDDEN |
The numeric perturbations are covered too. Lowering the membrane gate to 0.52 moves the pick to mat_solid_electrolyte_002 and blocks with a safety-gate failure. The numeric perturbations are covered too. Lowering the membrane gate to 0.52 moves the pick to mat_solid_electrolyte_002 and blocks with a safety-gate failure. Declaring a stale expected label while the numbers select a different candidate raises the stale-label code. Removing score rows while the policy is active raises the score-backed-rows code with verified_numeric_row_count at 0.
Prior Art Grounding
Self-driving-lab structure under fixture evidence
The shape borrowed here is the self-driving laboratory, where a propose-run-measure loop is paired with safety interlocks that can refuse an unsafe experiment. The shape borrowed here is the self-driving laboratory, where a propose-run-measure loop is paired with safety interlocks that can refuse an unsafe experiment. This component keeps the loop-plus-safety-gate structure but runs it over a simulator fixture and adds a numeric recompute so the declared winner is checked rather than trusted. The engineering lineage is ordinary refusal-first input validation applied to a lab-shaped record. It is not a real laboratory controller, a chemical-safety authority, or a discovery benchmark.
Validation Result record Path
Run the first-wave fixture proof from the Microcosm root:
Exported source-body bundle inspection
Inspect the exported source-body bundle. Until the exported fixture is refreshed with score-backed numeric rows, this command can return a blocked numeric verdict while still proving the manifest and body-floor boundary: Inspect the exported source-body bundle. Until the exported fixture is refreshed with score-backed numeric rows, this command can return a blocked numeric verdict while still proving the manifest and body-floor boundary:
cd microcosm-substrate
PYTHONPATH=src ../repo-python -m microcosm_core.organs.materials_chemistry_closed_loop_lab_safety_replay run-lab-bundle --input examples/materials_chemistry_closed_loop_lab_safety_replay/exported_materials_lab_safety_bundle --out /tmp/microcosm_materials_chemistry_lab_safety_bundle
Run the focused regression suite:
cd microcosm-substrate
PYTHONPATH=src ../repo-pytest tests/test_materials_chemistry_closed_loop_lab_safety_replay.py -q
cd microcosm-substrate
PYTHONPATH=src ../repo-python scripts/build_doctrine_projection.py --check-paper-module-corpus
A pass means the runtime recomputed the winner from public numbers, matched the declared label, refused all eight forbidden cases, kept the result record metadata-only, and stayed inside the simulator-only ceiling. A pass means the runtime recomputed the winner from public numbers, matched the declared label, refused all eight forbidden cases, kept the result record metadata-only, and stayed inside the simulator-only ceiling. The validation result records named here are the authority for a current run; older archived records predate the numeric rows and are not the numeric proof.
Scope boundary
Scope limit
The bounded winner-recomputation claim
The strongest claim the evidence supports is narrow: over public synthetic inputs, this component recomputes a lab-shaped fixture's selected candidate from score-backed rows, refuses eight named dangerous or overclaiming classes, verifies copied source-module bodies by digest, and writes a metadata-only result record, all reproducible with the commands above. The strongest claim the evidence supports is narrow: over public synthetic inputs, this component recomputes a lab-shaped fixture's selected candidate from score-backed rows, refuses eight named dangerous or overclaiming classes, verifies copied source-module bodies by digest, and writes a metadata-only result record, all reproducible with the commands above. That is the proof boundary. Fixture numbers are public replay coordinates for a safety-gated contract, not experimental measurements.
Claims outside the public fixture
It refuses to claim more. This is not a laboratory. It refuses to claim more. This is not a laboratory. It does not synthesize materials, give wetlab or hazardous-synthesis instructions, state reagent quantities, target controlled or bioactive compounds, control a robot, export a private lab notebook, use live account secrets, validate live assay data, rank real compounds, call a provider, assert a discovery, or post a benchmark claims. Its scope limit is the bundle ceiling: copied public source-module bodies, metadata-only simulator-only records, and artifact safety and refusal validation only. It cannot prove chemical safety, regulatory suitability, lab readiness, launch-scope decision, or public sharing.
Context & evidence
In short Materials Chemistry Closed-Loop Lab-Safety Replay is the public lab-safety claim boundary for Microcosm. It checks candidate material refs, safety-screen refs, simulator-only assay refs, active-learning decisions, failure taxonomy refs, cold replay refs, source bundle hashes, Lab/Evolve replay graph evidence, copied source/control/result record/standard bodies, metadata-only result record policy, and eight lab-safety overclaim negative cases while keeping wetlab protocols, hazardous synthesis steps, reagent quantities, controlled or bioactive targets, live lab account secrets, robot commands, private lab notebook bodies, live assay data, discovery claims, benchmark claims, model-output data, source notes, and launch-scope decision out of result records.
Scope limit Copied public Lab/Evolve source/control/result record/standard bodies, metadata-only simulator-only fixture result records, runtime bundle result records, and artifact safety/refusal validation only; no wetlab execution, hazardous synthesis guidance, reagent quantity, controlled or bioactive target, live assay, robot command, private lab notebook, external model access, discovery claim, benchmark claims, launch-scope decision, publishing-scope decision, or product-progress evidence.
Covers Materials Lab-Safety Refusal Replay
Source
Source Source module: src/microcosm_core/organs/materials_chemistry_closed_loop_lab_safety_replay.py · Design note · Source registry