pen-stack 5.8.0__tar.gz → 5.10.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pen_stack-5.8.0 → pen_stack-5.10.0}/CHANGELOG.md +67 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/CITATION.cff +1 -1
- {pen_stack-5.8.0 → pen_stack-5.10.0}/PKG-INFO +50 -9
- {pen_stack-5.8.0 → pen_stack-5.10.0}/README.md +49 -8
- {pen_stack-5.8.0 → pen_stack-5.10.0}/benchmarks/genome_writing_bench/SHA256SUMS +1 -1
- {pen_stack-5.8.0 → pen_stack-5.10.0}/benchmarks/genome_writing_bench/tasks.yaml +38 -1
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/oracles/scope_cards.yaml +23 -0
- pen_stack-5.10.0/docs/digital_twin.md +55 -0
- pen_stack-5.10.0/docs/experiment_design.md +44 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/__init__.py +1 -1
- pen_stack-5.10.0/pen_stack/active/__init__.py +20 -0
- pen_stack-5.10.0/pen_stack/active/acquire.py +73 -0
- pen_stack-5.10.0/pen_stack/active/design.py +51 -0
- pen_stack-5.10.0/pen_stack/active/validate.py +104 -0
- pen_stack-5.10.0/pen_stack/oracles/vcell.py +51 -0
- pen_stack-5.10.0/pen_stack/twin/__init__.py +14 -0
- pen_stack-5.10.0/pen_stack/twin/calibrate.py +61 -0
- pen_stack-5.10.0/pen_stack/twin/mechanistic.py +37 -0
- pen_stack-5.10.0/pen_stack/twin/outcome.py +84 -0
- pen_stack-5.10.0/pen_stack/validate/experiment_design.py +65 -0
- pen_stack-5.10.0/pen_stack/validate/outcome_prediction.py +76 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack.egg-info/PKG-INFO +50 -9
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack.egg-info/SOURCES.txt +27 -0
- pen_stack-5.10.0/prereg/SHA256_LOCK_ws_acq.json +8 -0
- pen_stack-5.10.0/prereg/SHA256_LOCK_ws_aldesign.json +8 -0
- pen_stack-5.10.0/prereg/SHA256_LOCK_ws_alvalidate.json +8 -0
- pen_stack-5.10.0/prereg/SHA256_LOCK_ws_mech.json +8 -0
- pen_stack-5.10.0/prereg/SHA256_LOCK_ws_outcome.json +8 -0
- pen_stack-5.10.0/prereg/SHA256_LOCK_ws_twincal.json +8 -0
- pen_stack-5.10.0/prereg/SHA256_LOCK_ws_vcell.json +8 -0
- pen_stack-5.10.0/prereg/ws_acq.yaml +19 -0
- pen_stack-5.10.0/prereg/ws_aldesign.yaml +15 -0
- pen_stack-5.10.0/prereg/ws_alvalidate.yaml +19 -0
- pen_stack-5.10.0/prereg/ws_mech.yaml +16 -0
- pen_stack-5.10.0/prereg/ws_outcome.yaml +19 -0
- pen_stack-5.10.0/prereg/ws_twincal.yaml +20 -0
- pen_stack-5.10.0/prereg/ws_vcell.yaml +20 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pyproject.toml +1 -1
- {pen_stack-5.8.0 → pen_stack-5.10.0}/LICENSE +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/MANIFEST.in +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/bench/run.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/benchmarks/genome_writing_bench/LEADERBOARD.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/benchmarks/genome_writing_bench/README.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/benchmarks/genome_writing_bench/SUBMISSIONS.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/antipeg.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/atlas_families.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/bridge_offtarget_profile.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/capsid_epitope_oracle.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/capsid_sequences.fasta +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/cargo_polish.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/cell_types.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/datasets.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/delivery_constraints.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/delivery_rules.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/delivery_vehicles.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/gates_v3.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/genotoxicity_oracle.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/gsh_validated_heldout.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/intent_weights.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/known_unknowns.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/llm.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/monitor_queries.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/rules/delivery.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/rules/fold.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/rules/multiplex.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/rules/payload.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/rules/reachability.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/safety/hazard_registry.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/safety/policy.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/safety/probes.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/score_axes.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/seroprevalence.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/target_sites.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/universe_crosswalk.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/write_types.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/configs/wtkb_curated.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/data/curated/bridge_offtarget_energetics.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/data/curated/bridge_offtarget_profile_measured.parquet +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/data/curated/gene_coords.parquet +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/data/curated/unified_editor_universe.parquet +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/BACKLOG.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/DEPLOY.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/INFRA.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/MCP.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/RELEASING.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/REPRO.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/agent.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/alphagenome_feasibility.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/benchmark_circularity.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/biosecurity.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/cards/atlas.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/cards/durability.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/cards/safety.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/co_scientist.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/delivery.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/delivery_immunology.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/dissemination.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/environment.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/generative_design.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/index.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/mechanistic_constraints.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/oracles.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/positioning.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/private_data_formats.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/quickstart.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/responsible_use.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/rules.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/scope.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/scorecard.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/tutorials/compare-families.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/tutorials/score-deliverability.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/tutorials/where-can-i-write.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/tutorials/which-writer-reaches-locus.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/uncertainty.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/verify.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/world_model.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/writer_verification.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/docs/wtkb.md +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/_resources.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/adapt/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/adapt/finetune.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/adapt/ingest.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/adapt/pipeline.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/adapt/recalibrate.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/adapt/report.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/agent/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/agent/cite.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/agent/co_scientist.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/agent/epistemic.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/agent/guardrails.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/agent/mcp_server.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/agent/orchestrator.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/agent/orchestrator_live.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/agent/pen_agent.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/agent/scope.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/agent/tools.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/atlas/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/atlas/build_wtkb.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/atlas/crosslink.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/atlas/expand.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/atlas/schema.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/atlas/scorecard.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/atlas/universe.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/atlas/variant_propose.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/atlas/writer_verify.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/bridge/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/bridge/activity.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/bridge/cli.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/bridge/fold_qc.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/bridge/guide_qc.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/bridge/ingest.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/bridge/offtarget.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/bridge/offtarget_energetics.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/bridge/ortholog_screen.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/bridge/pipeline.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/cli.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/data/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/data/encode.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/data/genome.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/data/ingest_chromatin.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/data/ingest_integration.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/data/ingest_safety_annot.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/data/ingest_trip.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/design/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/design/generate.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/design/pareto.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/design/space.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/env/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/env/genome_writing_env.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/env/policies.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/graph/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/graph/build.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/graph/cell_types.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/graph/ingest.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/graph/query.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/graph/schema.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/mech/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/mech/classify_atlas.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/mech/whitelist.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/monitor/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/monitor/europepmc.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/monitor/run.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/monitor/triage.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/oracles/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/oracles/cache.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/oracles/energetics.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/oracles/genome.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/oracles/protein_design.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/oracles/rna.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/oracles/schema.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/oracles/structure.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/antipeg_oracle.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/capsid_epitope_oracle.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/cargo.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/cargo_polish.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/delivery.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/delivery_constraints.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/delivery_immunology.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/delivery_vehicles.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/genotoxicity_oracle.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/immune_profile.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/innate_sensing.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/multiplex.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/optimize.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/pipeline.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/report.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/router.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/seroprevalence_oracle.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/planner/target_site.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/rag/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/rag/index.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/rag/llm.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/rag/qa.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/rules/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/rules/evaluators.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/rules/loader.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/rules/schema.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/rules/solver.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/safety/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/safety/audit.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/safety/gate.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/safety/policy.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/safety/redteam.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/safety/registry.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/safety/screen.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/score/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/score/recalibrate.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/score/therapeutic.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/server/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/server/api.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/ui/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/ui/app.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/adapt_demo.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/agent_eval.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/bench_adversarial_tasks.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/bench_coscientist_tasks.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/bench_graph_tasks.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/bench_rule_tasks.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/bench_trust_tasks.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/bench_writetype_tasks.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/blind_gsh_discovery.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/cargo_directionality.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/durability_baselines.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/forward_hypotheses.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/generative_design.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/guide_qc_demo.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/immune_calibration.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/intent_specification.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/offtarget_energetics_eval.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/out_of_scope_refusal.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/outcome_calibration.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/paper3_benchmark.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/paper4_real_validation.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/paper4_validation.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/safety_screening.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/selective_prediction.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/seq_vs_measured.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/target_site_controls.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/uncertainty_eval.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/ungrounded_baseline.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/within_locus_ranking.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/validate/writer_recovery.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/verify/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/verify/schema.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/verify/service.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/wgenome/__init__.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/wgenome/chromatin_seq.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/wgenome/durability.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/wgenome/export_tracks.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/wgenome/features.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/wgenome/gsh_baseline.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/wgenome/mesh_features.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/wgenome/ood.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/wgenome/providers.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/wgenome/safety.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/wgenome/structure3d.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/wgenome/uncertainty.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack/wgenome/writability.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack.egg-info/dependency_links.txt +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack.egg-info/entry_points.txt +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack.egg-info/requires.txt +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/pen_stack.egg-info/top_level.txt +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_phase0.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_phase1_5.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_phase2.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_phase3.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_a.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_atlas.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_b.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_ba.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_ba_v33.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_ba_v45.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_bench.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_c.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_cal.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_calib.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_cite.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_crit.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_ct.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_d.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_e.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_env.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_ep.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_epitope.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_f.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_g.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_gen.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_genotox.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_graph.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_h.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_immune.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_innate.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_mc.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_mon.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_o.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_orch.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_pareto.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_peg.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_plan.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_policy.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_profile.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_r.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_redteam.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_route.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_screen.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_seroprev.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_uq.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_v.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/SHA256_LOCK_ws_wv.json +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/paper1.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/paper2.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/paper3.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/paper4.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/phase0.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_a.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_atlas.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_b.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_ba.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_ba_v33.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_ba_v45.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_bench.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_c.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_cal.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_calib.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_cite.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_crit.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_ct.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_d.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_e.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_env.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_ep.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_epitope.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_f.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_g.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_gen.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_genotox.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_graph.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_h.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_immune.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_innate.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_mc.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_mon.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_o.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_orch.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_pareto.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_peg.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_plan.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_policy.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_profile.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_r.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_redteam.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_route.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_screen.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_seroprev.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_uq.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_v.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/prereg/ws_wv.yaml +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/scripts/p1_build_atlas.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/scripts/p1_build_durability.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/scripts/p1_export_tracks.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/scripts/p1_safety_concordance.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/scripts/p1_train_safety.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/scripts/p1_validation_report.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/scripts/p2_build_atlas.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/scripts/p3_benchmark_report.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/scripts/p4_genome_scan.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/scripts/p52_build_genotox_oracle.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/scripts/p53_build_epitope_oracle.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/scripts/ws_b_report.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/scripts/ws_c_report.py +0 -0
- {pen_stack-5.8.0 → pen_stack-5.10.0}/setup.cfg +0 -0
|
@@ -3,6 +3,73 @@
|
|
|
3
3
|
All notable changes to PEN-STACK are documented here. This file follows
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/) and the program's phase structure.
|
|
5
5
|
|
|
6
|
+
## [5.10.0] - 2026-06-11 - v5.10 release: The Experiment Designer (active learning / EIG)
|
|
7
|
+
|
|
8
|
+
**Closed-Loop arc, Cycle 4 of 7.** The "Learn" brain of a self-driving lab: turn *"I'm uncertain"* into *"run
|
|
9
|
+
this experiment next."* Reads the calibrated v5.9 twin's uncertainty + the v5.6 immune labels, scores each
|
|
10
|
+
candidate experiment by expected information gain, assembles a diverse batch, and proves on held-out data — with
|
|
11
|
+
CIs — that this learns faster than random/greedy (reporting honestly when it does not). Workstreams
|
|
12
|
+
WS-{ACQ,DESIGN,VALIDATE}, SHA-locked.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
- **WS-ACQ** — `pen_stack/active/acquire.py`: `expected_information_gain` (reducible uncertainty from the twin's
|
|
16
|
+
predictive distribution; `≥ 0`, monotone in uncertainty), `predictive_entropy` (from the twin's interval width),
|
|
17
|
+
and **`immune_voi`** — value of information for **validating an immune PROXY axis** (v5.6): an experiment that
|
|
18
|
+
would measure a still-proxy axis is high-VOI (turns proxy → outcome-validated). `acquisition_score` is fully
|
|
19
|
+
traceable to twin quantities + v5.6 labels; deterministic; no fabricated values.
|
|
20
|
+
- **WS-DESIGN** — `pen_stack/active/design.py`: `select_batch` greedily maximises acquisition **minus a
|
|
21
|
+
redundancy penalty** (shared design facets) → a **diverse** batch (not k copies of the most-uncertain point);
|
|
22
|
+
each experiment carries its expected info gain.
|
|
23
|
+
- **WS-VALIDATE** — `pen_stack/active/validate.py`: `retrospective_active_learning` simulates active vs random vs
|
|
24
|
+
greedy campaigns on a held-out split, reports mean±CI learning curves and a **bootstrap CI on the curve-area
|
|
25
|
+
gap**; `active_beats_random` only when the CI excludes zero — else the not-yet-useful negative is reported.
|
|
26
|
+
- **WS-BENCH** — bench **v0.3.6**: new `experiment_design` hard-gate task — the gate is the Learn engine's
|
|
27
|
+
honesty + falsifiability (twin-sourced EIG monotone in uncertainty + immune-VOI for proxy validation + diverse
|
|
28
|
+
batch + retrospective active-vs-random with reps+CI); a random selector fails by construction. Active-beats-
|
|
29
|
+
random is reported informationally.
|
|
30
|
+
- Docs: `docs/experiment_design.md`; prereg `ws_{acq,aldesign,alvalidate}` + SHA locks; deposit `phase_5.10/`.
|
|
31
|
+
|
|
32
|
+
### Notes
|
|
33
|
+
- The experiment designer is only as good as the v5.9 twin + v5.6 labels it queries; its advantage is validated
|
|
34
|
+
**retrospectively** with CIs and reported honestly when absent. It chooses informative experiments but **does
|
|
35
|
+
not run them** — prospective benefit awaits a lab partner (v5.11+). No autonomy claim.
|
|
36
|
+
|
|
37
|
+
## [5.9.0] - 2026-06-11 - v5.9 release: The Digital Twin (calibrated outcome prediction)
|
|
38
|
+
|
|
39
|
+
**Closed-Loop arc, Cycle 3 of 7.** The missing layer: *what does the cell do after the write?* — predicted with
|
|
40
|
+
calibrated honesty. The twin computes what mechanism allows, adds an in-distribution virtual-cell estimate
|
|
41
|
+
(OOD-gated), screens immune outcome from the v5.6 profile, and is explicit about its boundary at phenotype.
|
|
42
|
+
Workstreams WS-{VCELL,MECH,OUTCOME,CAL}, SHA-locked.
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
- **WS-VCELL** — `pen_stack/oracles/vcell.py` + scope cards `state`/`scgpt`: `predict_response(cell_state,
|
|
46
|
+
perturbation, model)` wraps **Arc STATE** / **scGPT** under the v4.0 `OracleResult` contract. A
|
|
47
|
+
perturbation-response prediction is a **candidate**, OOD-gated (a context outside the documented envelope →
|
|
48
|
+
`extrapolating`), cached/deferred (value `None` when absent — never fabricated). Encodes the field's own result
|
|
49
|
+
(Arc Virtual Cell Challenge): perturbation models don't yet consistently beat naive baselines.
|
|
50
|
+
- **WS-MECH** — `pen_stack/twin/mechanistic.py`: `cassette_expression` = `promoter_strength × copy_number ×
|
|
51
|
+
accessibility` (closed-form steady state); assumptions + scope flags attached; **physics where computable, NOT
|
|
52
|
+
a phenotype**.
|
|
53
|
+
- **WS-OUTCOME** — `pen_stack/twin/outcome.py`: `predict_outcome(design, cell_state)` fuses mechanism +
|
|
54
|
+
in-distribution virtual-cell response + the v5.6 immune profile into one prediction with an interval that
|
|
55
|
+
**widens under OOD**, an immune-outcome dimension, and an explicit **phenotype / in-vivo-magnitude boundary**.
|
|
56
|
+
In-vivo durability may be **conditioned on the grounded pre-existing-NAb axis** (no invented immune numbers);
|
|
57
|
+
`output_kind="candidate"`.
|
|
58
|
+
- **WS-CAL** — `pen_stack/twin/calibrate.py`: `calibrate_outcome(...)` reports calibration **two-sided** — interval
|
|
59
|
+
coverage + a bootstrap CI on the MAE gap vs a naive mean baseline; the twin "beats" naive **only when the CI
|
|
60
|
+
excludes zero**, else the negative is reported verbatim; abstains at `N < 3`.
|
|
61
|
+
- **WS-BENCH** — bench **v0.3.5**: new `outcome_prediction` hard-gate task (`pen_stack/validate/outcome_prediction.py`)
|
|
62
|
+
— the gate is the twin's **honesty properties** (two-sided calibration + OOD widening + immune dimension +
|
|
63
|
+
phenotype out-of-scope), which an overconfident predictor fails by construction; twin-vs-naive skill is reported
|
|
64
|
+
informationally on a labelled synthetic stream (no public perturbation-outcome calibration set exists).
|
|
65
|
+
- Docs: `docs/digital_twin.md`; prereg `ws_{vcell,mech,outcome,twincal}` + SHA locks; deposit `phase_5.9/`.
|
|
66
|
+
|
|
67
|
+
### Notes
|
|
68
|
+
- The twin is a **hypothesis engine, not an oracle of truth**: predictions are candidates with intervals;
|
|
69
|
+
phenotype, in-vivo behaviour, immunogenicity *magnitude*, and durability beyond the computable stay
|
|
70
|
+
scope-flagged. The interval is a heuristic band, **not** a trained conformal interval (no public outcome
|
|
71
|
+
calibration set). Immune-outcome is sourced from v5.6, never invented.
|
|
72
|
+
|
|
6
73
|
## [5.8.0] - 2026-06-11 - v5.8 release: The Live Agent & Generative Designer
|
|
7
74
|
|
|
8
75
|
**Closed-Loop arc, Cycle 2 of 7.** PEN-STACK turns from a *checker* into a grounded *designer*: it generates
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pen-stack
|
|
3
|
-
Version: 5.
|
|
3
|
+
Version: 5.10.0
|
|
4
4
|
Summary: Open infrastructure for genome writing: the Writable Genome atlas, the Writer Atlas, and the Write Planner.
|
|
5
5
|
Author-email: Anees Ahmed Mahaboob Ali <ahmedaneesm@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -90,12 +90,12 @@ every design against rule-grounded mechanism, reports calibrated confidence, cit
|
|
|
90
90
|
[](https://codecov.io/gh/ahmedanees-m/pen-stack)
|
|
91
91
|
[](LICENSE)
|
|
92
92
|
[](https://www.python.org/)
|
|
93
|
-
[](CHANGELOG.md)
|
|
94
|
+
[](tests/)
|
|
95
95
|
[](https://github.com/astral-sh/ruff)
|
|
96
96
|
[](docker/)
|
|
97
97
|
[](prereg/)
|
|
98
|
-
[](benchmarks/genome_writing_bench/)
|
|
99
99
|
|
|
100
100
|
**Built on five prior, separately published repositories:**
|
|
101
101
|
|
|
@@ -134,6 +134,43 @@ Two questions gate every genome-writing project, and before PEN-STACK no resourc
|
|
|
134
134
|
Everything is built on bulk-downloadable public data, runs on a single GPU, and is validated **blind** against
|
|
135
135
|
a pre-registered, honest baseline before release.
|
|
136
136
|
|
|
137
|
+
## What is new in v5.10 — The Experiment Designer (active learning / EIG)
|
|
138
|
+
|
|
139
|
+
v5.10 (**Closed-Loop arc, Cycle 4 of 7**) is the **Learn** brain of a self-driving lab: it turns *"I'm
|
|
140
|
+
uncertain"* into *"run **this** experiment next."* It reads the calibrated v5.9 twin's uncertainty and the v5.6
|
|
141
|
+
immune labels, scores each candidate experiment by the information it is expected to yield, assembles a diverse
|
|
142
|
+
batch, and proves on held-out data — with confidence intervals — that this learns faster than random/greedy.
|
|
143
|
+
|
|
144
|
+
| Workstream | What it adds | Result |
|
|
145
|
+
|---|---|---|
|
|
146
|
+
| **ACQ** | `active/acquire.py` | EIG from the twin (≥0, monotone in uncertainty); **immune-VOI** rewards experiments that would validate a v5.6 **proxy** axis; deterministic, traceable |
|
|
147
|
+
| **DESIGN** | `active/design.py` | `select_batch` — diverse batch (acquisition − redundancy penalty), not k copies of the most-uncertain point; each carries expected info gain |
|
|
148
|
+
| **VALIDATE** | `active/validate.py` | retrospective active vs random/greedy learning curves with reps + **bootstrap CI** on the curve-area gap; beats random **only if CI excludes 0**, else reports not-yet-useful |
|
|
149
|
+
| **BENCH** | bench **v0.3.6** `experiment_design` hard gate | gate = the Learn engine's honesty + falsifiability; a random selector (no acquisition, no falsifiable curve) fails by construction |
|
|
150
|
+
|
|
151
|
+
Falsifiable by construction and **lab-optional** — it chooses informative experiments but does not run them
|
|
152
|
+
(prospective benefit awaits a lab; no autonomy claim). See [`docs/experiment_design.md`](docs/experiment_design.md)
|
|
153
|
+
and `prereg/ws_{acq,aldesign,alvalidate}.yaml`.
|
|
154
|
+
|
|
155
|
+
## What is new in v5.9 — The Digital Twin (calibrated outcome prediction)
|
|
156
|
+
|
|
157
|
+
v5.9 (**Closed-Loop arc, Cycle 3 of 7**) adds the missing layer — *what does the cell do after the write?* —
|
|
158
|
+
predicted with calibrated honesty. The twin computes what mechanism allows, adds an in-distribution virtual-cell
|
|
159
|
+
estimate (OOD-gated), screens immune outcome from the v5.6 profile, and is explicit about its boundary at
|
|
160
|
+
phenotype. A **hypothesis engine, not an oracle of truth**.
|
|
161
|
+
|
|
162
|
+
| Workstream | What it adds | Result |
|
|
163
|
+
|---|---|---|
|
|
164
|
+
| **VCELL** | `oracles/vcell.py` + scope cards `state`/`scgpt` | Arc STATE / scGPT under the OracleResult contract; perturbation prediction is a **candidate**, **OOD-gated**, deferred value never fabricated |
|
|
165
|
+
| **MECH** | `twin/mechanistic.py` | `cassette_expression` = promoter × copy × accessibility (closed form); **physics where computable, NOT a phenotype** |
|
|
166
|
+
| **OUTCOME** | `twin/outcome.py` | fuses mechanism + in-dist VC + v5.6 immune; interval **widens under OOD**; in-vivo durability conditioned on the **grounded NAb axis**; phenotype/in-vivo-magnitude scope-flagged |
|
|
167
|
+
| **CAL** | `twin/calibrate.py` | calibration reported **two-sided** (coverage + MAE-gap-vs-naive bootstrap CI); beats naive **only if CI excludes 0**, else the negative is reported |
|
|
168
|
+
| **BENCH** | bench **v0.3.5** `outcome_prediction` hard gate | gate = the twin's honesty properties (two-sided cal + OOD widening + immune dim + phenotype out-of-scope); an overconfident predictor fails by construction |
|
|
169
|
+
|
|
170
|
+
The interval is a **heuristic band, not a trained conformal interval** (no public perturbation-outcome calibration
|
|
171
|
+
set; Arc's Virtual Cell Challenge shows models don't yet consistently beat naive baselines). See
|
|
172
|
+
[`docs/digital_twin.md`](docs/digital_twin.md) and `prereg/ws_{vcell,mech,outcome,twincal}.yaml`.
|
|
173
|
+
|
|
137
174
|
## What is new in v5.8 — The Live Agent & Generative Designer
|
|
138
175
|
|
|
139
176
|
v5.8 (**Closed-Loop arc, Cycle 2 of 7**) turns PEN-STACK from a *checker* into a grounded *designer*: it
|
|
@@ -599,11 +636,13 @@ pen-stack/
|
|
|
599
636
|
│ ├── agent/ agentic platform: tools / orchestrator / pen_agent / mcp_server / guardrails; v5.0 co_scientist + cite (multi-strategy, self-critique, cited rationale, scope ledger); v5.8 orchestrator_live (live, cache-replayable, generate→oracle→verify→refine)
|
|
600
637
|
│ │ + v3.2 epistemic (3-tier status) / scope (known-unknowns matcher)
|
|
601
638
|
│ ├── graph/ v4.5 living world-model knowledge graph (schema/build/query/ingest/cell_types); typed provenanced edges; gated living loop (propose-only)
|
|
602
|
-
│ ├── oracles/ v4.0 L1 oracle mesh: OracleResult contract + adapters (genome/structure/protein_design/rna/energetics) over the foundation models; version-pinned cache; v5.2-5.6 delivery-immunology scope cards (delivery_genotoxicity/capsid_epitope/innate_sensing/seroprevalence/antipeg)
|
|
639
|
+
│ ├── oracles/ v4.0 L1 oracle mesh: OracleResult contract + adapters (genome/structure/protein_design/rna/energetics) over the foundation models; version-pinned cache; v5.2-5.6 delivery-immunology scope cards (delivery_genotoxicity/capsid_epitope/innate_sensing/seroprevalence/antipeg); v5.9 vcell (Arc STATE/scGPT, OOD-gated, output_kind=candidate)
|
|
603
640
|
│ ├── rules/ v3.3 machine-readable rules engine (schema/evaluators/loader/solver) over configs/rules/*.yaml
|
|
604
641
|
│ ├── verify/ v3.3 verification service: verify(design) -> Verdict (legal+reasons+confidence+scope; v4.0 writer_critique; v5.1 delivery_profile; v5.6 immune_profile per-axis vector; v5.7 safety SafetyVerdict)
|
|
605
642
|
│ ├── safety/ v5.7 the Guardian: biosecurity/dual-use gate (registry/screen/policy/gate/audit/redteam); runs first in verify(); refuse short-circuits; tamper-evident audit
|
|
606
643
|
│ ├── design/ v5.8 generative designer: space (candidate_space) / generate (verifier-as-discriminator; hazardous+illegal discarded) / pareto (frontier w/ grounded v5.6 immune axis)
|
|
644
|
+
│ ├── twin/ v5.9 digital twin: mechanistic (cassette expression, closed-form) / outcome (fuse mech+vcell+v5.6 immune; OOD widens interval; phenotype-bounded) / calibrate (honest two-sided)
|
|
645
|
+
│ ├── active/ v5.10 experiment designer: acquire (EIG/immune-VOI over the v5.9 twin) / design (diverse batch) / validate (retrospective active-vs-random, reps+CI, falsifiable)
|
|
607
646
|
│ ├── adapt/ local recalibration / private-data adaptation behind a gate (v3.1, WS-F)
|
|
608
647
|
│ ├── env/ v3.4 full Gymnasium environment over router+verifier (genome_writing_env + policies; [env] extra)
|
|
609
648
|
│ ├── monitor/ PEN-MONITOR living database (Europe PMC)
|
|
@@ -615,12 +654,14 @@ pen-stack/
|
|
|
615
654
|
│ │ v3.3 bench_rule_tasks (T12) / v3.4 bench_writetype_tasks + bench_adversarial_tasks (T13-16) + outcome_calibration /
|
|
616
655
|
│ │ v5.6 immune_calibration (proxy-vs-observed; labels each axis validated-or-proxy, two-sided) /
|
|
617
656
|
│ │ v5.7 safety_screening (the Guardian hard-gate: benign 0-false-refusal · hazards refused/escalated · evasions never clear) /
|
|
618
|
-
│ │ v5.8 generative_design (verifier-as-discriminator hard-gate: hazardous+illegal discarded; survivors calibrated+immune; grounded-immune Pareto)
|
|
657
|
+
│ │ v5.8 generative_design (verifier-as-discriminator hard-gate: hazardous+illegal discarded; survivors calibrated+immune; grounded-immune Pareto) /
|
|
658
|
+
│ │ v5.9 outcome_prediction (digital-twin hard-gate: two-sided calibration + OOD widening + immune dim + phenotype out-of-scope) /
|
|
659
|
+
│ │ v5.10 experiment_design (active-learning hard-gate: EIG monotone + immune-VOI + diverse batch + retrospective active-vs-random reps+CI)
|
|
619
660
|
│ ├── data/ ingestion (genome, chromatin, integration, TRIP, safety annotations)
|
|
620
661
|
│ ├── server/api.py FastAPI REST (atlas, crosslink, writable, plan, bridge, ask)
|
|
621
662
|
│ ├── ui/app.py Streamlit web app (16 pages; v3.2 PEN-Agent shows confidence + epistemic status)
|
|
622
663
|
│ └── cli.py unified CLI
|
|
623
|
-
├── benchmarks/genome_writing_bench/ Genome-Writing Bench v0.3.
|
|
664
|
+
├── benchmarks/genome_writing_bench/ Genome-Writing Bench v0.3.6 (T1-T16 + co_scientist + safety_screening + generative_design + outcome_prediction + experiment_design; tasks / harness / solvers / LEADERBOARD / SHAs)
|
|
624
665
|
├── bench/run.py one-command bench entrypoint (--agent, --verify)
|
|
625
666
|
├── scripts/ reproducible pipeline drivers (p1_*, p2_*, p4_*, p52/p53 delivery-immunology oracle builds, ws_*_report)
|
|
626
667
|
├── configs/ pinned datasets + thresholds + curation (YAML); v3.2 known_unknowns /
|
|
@@ -629,10 +670,10 @@ pen-stack/
|
|
|
629
670
|
│ seroprevalence / antipeg + oracles/scope_cards (+ v5.6 known_unknowns:
|
|
630
671
|
│ cd4_mhcii_help / preexisting_capsid_tcell / complement_carpa);
|
|
631
672
|
│ v5.7 safety/{hazard_registry,policy,probes} (Guardian; function/family/taxon-level only)
|
|
632
|
-
├── prereg/ SHA-locked success criteria (paper1..4 + ws_a..ws_h + v3.2-v5.
|
|
673
|
+
├── prereg/ SHA-locked success criteria (paper1..4 + ws_a..ws_h + v3.2-v5.9 ws_{uq,ep,mc,ba,
|
|
633
674
|
│ r,v,route,env,bench,cal,o,wv,atlas,graph,mon,ct,plan,crit,cite,immune,
|
|
634
675
|
│ genotox,epitope,innate,seroprev,peg,calib,profile,screen,policy,redteam,
|
|
635
|
-
│ gen,pareto,orch} + SHA256 locks)
|
|
676
|
+
│ gen,pareto,orch,vcell,mech,outcome,twincal,acq,aldesign,alvalidate} + SHA256 locks)
|
|
636
677
|
├── data/curated/ small committed tables (universe, gene coords, measured bridge profile,
|
|
637
678
|
│ v3.2 bridge_offtarget_energetics.json)
|
|
638
679
|
├── data/llm_bench_cache/ 28 cached ungrounded-LLM transcripts (T7, offline/CI replay)
|
|
@@ -15,12 +15,12 @@ every design against rule-grounded mechanism, reports calibrated confidence, cit
|
|
|
15
15
|
[](https://codecov.io/gh/ahmedanees-m/pen-stack)
|
|
16
16
|
[](LICENSE)
|
|
17
17
|
[](https://www.python.org/)
|
|
18
|
-
[](CHANGELOG.md)
|
|
19
|
+
[](tests/)
|
|
20
20
|
[](https://github.com/astral-sh/ruff)
|
|
21
21
|
[](docker/)
|
|
22
22
|
[](prereg/)
|
|
23
|
-
[](benchmarks/genome_writing_bench/)
|
|
24
24
|
|
|
25
25
|
**Built on five prior, separately published repositories:**
|
|
26
26
|
|
|
@@ -59,6 +59,43 @@ Two questions gate every genome-writing project, and before PEN-STACK no resourc
|
|
|
59
59
|
Everything is built on bulk-downloadable public data, runs on a single GPU, and is validated **blind** against
|
|
60
60
|
a pre-registered, honest baseline before release.
|
|
61
61
|
|
|
62
|
+
## What is new in v5.10 — The Experiment Designer (active learning / EIG)
|
|
63
|
+
|
|
64
|
+
v5.10 (**Closed-Loop arc, Cycle 4 of 7**) is the **Learn** brain of a self-driving lab: it turns *"I'm
|
|
65
|
+
uncertain"* into *"run **this** experiment next."* It reads the calibrated v5.9 twin's uncertainty and the v5.6
|
|
66
|
+
immune labels, scores each candidate experiment by the information it is expected to yield, assembles a diverse
|
|
67
|
+
batch, and proves on held-out data — with confidence intervals — that this learns faster than random/greedy.
|
|
68
|
+
|
|
69
|
+
| Workstream | What it adds | Result |
|
|
70
|
+
|---|---|---|
|
|
71
|
+
| **ACQ** | `active/acquire.py` | EIG from the twin (≥0, monotone in uncertainty); **immune-VOI** rewards experiments that would validate a v5.6 **proxy** axis; deterministic, traceable |
|
|
72
|
+
| **DESIGN** | `active/design.py` | `select_batch` — diverse batch (acquisition − redundancy penalty), not k copies of the most-uncertain point; each carries expected info gain |
|
|
73
|
+
| **VALIDATE** | `active/validate.py` | retrospective active vs random/greedy learning curves with reps + **bootstrap CI** on the curve-area gap; beats random **only if CI excludes 0**, else reports not-yet-useful |
|
|
74
|
+
| **BENCH** | bench **v0.3.6** `experiment_design` hard gate | gate = the Learn engine's honesty + falsifiability; a random selector (no acquisition, no falsifiable curve) fails by construction |
|
|
75
|
+
|
|
76
|
+
Falsifiable by construction and **lab-optional** — it chooses informative experiments but does not run them
|
|
77
|
+
(prospective benefit awaits a lab; no autonomy claim). See [`docs/experiment_design.md`](docs/experiment_design.md)
|
|
78
|
+
and `prereg/ws_{acq,aldesign,alvalidate}.yaml`.
|
|
79
|
+
|
|
80
|
+
## What is new in v5.9 — The Digital Twin (calibrated outcome prediction)
|
|
81
|
+
|
|
82
|
+
v5.9 (**Closed-Loop arc, Cycle 3 of 7**) adds the missing layer — *what does the cell do after the write?* —
|
|
83
|
+
predicted with calibrated honesty. The twin computes what mechanism allows, adds an in-distribution virtual-cell
|
|
84
|
+
estimate (OOD-gated), screens immune outcome from the v5.6 profile, and is explicit about its boundary at
|
|
85
|
+
phenotype. A **hypothesis engine, not an oracle of truth**.
|
|
86
|
+
|
|
87
|
+
| Workstream | What it adds | Result |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| **VCELL** | `oracles/vcell.py` + scope cards `state`/`scgpt` | Arc STATE / scGPT under the OracleResult contract; perturbation prediction is a **candidate**, **OOD-gated**, deferred value never fabricated |
|
|
90
|
+
| **MECH** | `twin/mechanistic.py` | `cassette_expression` = promoter × copy × accessibility (closed form); **physics where computable, NOT a phenotype** |
|
|
91
|
+
| **OUTCOME** | `twin/outcome.py` | fuses mechanism + in-dist VC + v5.6 immune; interval **widens under OOD**; in-vivo durability conditioned on the **grounded NAb axis**; phenotype/in-vivo-magnitude scope-flagged |
|
|
92
|
+
| **CAL** | `twin/calibrate.py` | calibration reported **two-sided** (coverage + MAE-gap-vs-naive bootstrap CI); beats naive **only if CI excludes 0**, else the negative is reported |
|
|
93
|
+
| **BENCH** | bench **v0.3.5** `outcome_prediction` hard gate | gate = the twin's honesty properties (two-sided cal + OOD widening + immune dim + phenotype out-of-scope); an overconfident predictor fails by construction |
|
|
94
|
+
|
|
95
|
+
The interval is a **heuristic band, not a trained conformal interval** (no public perturbation-outcome calibration
|
|
96
|
+
set; Arc's Virtual Cell Challenge shows models don't yet consistently beat naive baselines). See
|
|
97
|
+
[`docs/digital_twin.md`](docs/digital_twin.md) and `prereg/ws_{vcell,mech,outcome,twincal}.yaml`.
|
|
98
|
+
|
|
62
99
|
## What is new in v5.8 — The Live Agent & Generative Designer
|
|
63
100
|
|
|
64
101
|
v5.8 (**Closed-Loop arc, Cycle 2 of 7**) turns PEN-STACK from a *checker* into a grounded *designer*: it
|
|
@@ -524,11 +561,13 @@ pen-stack/
|
|
|
524
561
|
│ ├── agent/ agentic platform: tools / orchestrator / pen_agent / mcp_server / guardrails; v5.0 co_scientist + cite (multi-strategy, self-critique, cited rationale, scope ledger); v5.8 orchestrator_live (live, cache-replayable, generate→oracle→verify→refine)
|
|
525
562
|
│ │ + v3.2 epistemic (3-tier status) / scope (known-unknowns matcher)
|
|
526
563
|
│ ├── graph/ v4.5 living world-model knowledge graph (schema/build/query/ingest/cell_types); typed provenanced edges; gated living loop (propose-only)
|
|
527
|
-
│ ├── oracles/ v4.0 L1 oracle mesh: OracleResult contract + adapters (genome/structure/protein_design/rna/energetics) over the foundation models; version-pinned cache; v5.2-5.6 delivery-immunology scope cards (delivery_genotoxicity/capsid_epitope/innate_sensing/seroprevalence/antipeg)
|
|
564
|
+
│ ├── oracles/ v4.0 L1 oracle mesh: OracleResult contract + adapters (genome/structure/protein_design/rna/energetics) over the foundation models; version-pinned cache; v5.2-5.6 delivery-immunology scope cards (delivery_genotoxicity/capsid_epitope/innate_sensing/seroprevalence/antipeg); v5.9 vcell (Arc STATE/scGPT, OOD-gated, output_kind=candidate)
|
|
528
565
|
│ ├── rules/ v3.3 machine-readable rules engine (schema/evaluators/loader/solver) over configs/rules/*.yaml
|
|
529
566
|
│ ├── verify/ v3.3 verification service: verify(design) -> Verdict (legal+reasons+confidence+scope; v4.0 writer_critique; v5.1 delivery_profile; v5.6 immune_profile per-axis vector; v5.7 safety SafetyVerdict)
|
|
530
567
|
│ ├── safety/ v5.7 the Guardian: biosecurity/dual-use gate (registry/screen/policy/gate/audit/redteam); runs first in verify(); refuse short-circuits; tamper-evident audit
|
|
531
568
|
│ ├── design/ v5.8 generative designer: space (candidate_space) / generate (verifier-as-discriminator; hazardous+illegal discarded) / pareto (frontier w/ grounded v5.6 immune axis)
|
|
569
|
+
│ ├── twin/ v5.9 digital twin: mechanistic (cassette expression, closed-form) / outcome (fuse mech+vcell+v5.6 immune; OOD widens interval; phenotype-bounded) / calibrate (honest two-sided)
|
|
570
|
+
│ ├── active/ v5.10 experiment designer: acquire (EIG/immune-VOI over the v5.9 twin) / design (diverse batch) / validate (retrospective active-vs-random, reps+CI, falsifiable)
|
|
532
571
|
│ ├── adapt/ local recalibration / private-data adaptation behind a gate (v3.1, WS-F)
|
|
533
572
|
│ ├── env/ v3.4 full Gymnasium environment over router+verifier (genome_writing_env + policies; [env] extra)
|
|
534
573
|
│ ├── monitor/ PEN-MONITOR living database (Europe PMC)
|
|
@@ -540,12 +579,14 @@ pen-stack/
|
|
|
540
579
|
│ │ v3.3 bench_rule_tasks (T12) / v3.4 bench_writetype_tasks + bench_adversarial_tasks (T13-16) + outcome_calibration /
|
|
541
580
|
│ │ v5.6 immune_calibration (proxy-vs-observed; labels each axis validated-or-proxy, two-sided) /
|
|
542
581
|
│ │ v5.7 safety_screening (the Guardian hard-gate: benign 0-false-refusal · hazards refused/escalated · evasions never clear) /
|
|
543
|
-
│ │ v5.8 generative_design (verifier-as-discriminator hard-gate: hazardous+illegal discarded; survivors calibrated+immune; grounded-immune Pareto)
|
|
582
|
+
│ │ v5.8 generative_design (verifier-as-discriminator hard-gate: hazardous+illegal discarded; survivors calibrated+immune; grounded-immune Pareto) /
|
|
583
|
+
│ │ v5.9 outcome_prediction (digital-twin hard-gate: two-sided calibration + OOD widening + immune dim + phenotype out-of-scope) /
|
|
584
|
+
│ │ v5.10 experiment_design (active-learning hard-gate: EIG monotone + immune-VOI + diverse batch + retrospective active-vs-random reps+CI)
|
|
544
585
|
│ ├── data/ ingestion (genome, chromatin, integration, TRIP, safety annotations)
|
|
545
586
|
│ ├── server/api.py FastAPI REST (atlas, crosslink, writable, plan, bridge, ask)
|
|
546
587
|
│ ├── ui/app.py Streamlit web app (16 pages; v3.2 PEN-Agent shows confidence + epistemic status)
|
|
547
588
|
│ └── cli.py unified CLI
|
|
548
|
-
├── benchmarks/genome_writing_bench/ Genome-Writing Bench v0.3.
|
|
589
|
+
├── benchmarks/genome_writing_bench/ Genome-Writing Bench v0.3.6 (T1-T16 + co_scientist + safety_screening + generative_design + outcome_prediction + experiment_design; tasks / harness / solvers / LEADERBOARD / SHAs)
|
|
549
590
|
├── bench/run.py one-command bench entrypoint (--agent, --verify)
|
|
550
591
|
├── scripts/ reproducible pipeline drivers (p1_*, p2_*, p4_*, p52/p53 delivery-immunology oracle builds, ws_*_report)
|
|
551
592
|
├── configs/ pinned datasets + thresholds + curation (YAML); v3.2 known_unknowns /
|
|
@@ -554,10 +595,10 @@ pen-stack/
|
|
|
554
595
|
│ seroprevalence / antipeg + oracles/scope_cards (+ v5.6 known_unknowns:
|
|
555
596
|
│ cd4_mhcii_help / preexisting_capsid_tcell / complement_carpa);
|
|
556
597
|
│ v5.7 safety/{hazard_registry,policy,probes} (Guardian; function/family/taxon-level only)
|
|
557
|
-
├── prereg/ SHA-locked success criteria (paper1..4 + ws_a..ws_h + v3.2-v5.
|
|
598
|
+
├── prereg/ SHA-locked success criteria (paper1..4 + ws_a..ws_h + v3.2-v5.9 ws_{uq,ep,mc,ba,
|
|
558
599
|
│ r,v,route,env,bench,cal,o,wv,atlas,graph,mon,ct,plan,crit,cite,immune,
|
|
559
600
|
│ genotox,epitope,innate,seroprev,peg,calib,profile,screen,policy,redteam,
|
|
560
|
-
│ gen,pareto,orch} + SHA256 locks)
|
|
601
|
+
│ gen,pareto,orch,vcell,mech,outcome,twincal,acq,aldesign,alvalidate} + SHA256 locks)
|
|
561
602
|
├── data/curated/ small committed tables (universe, gene coords, measured bridge profile,
|
|
562
603
|
│ v3.2 bridge_offtarget_energetics.json)
|
|
563
604
|
├── data/llm_bench_cache/ 28 cached ungrounded-LLM transcripts (T7, offline/CI replay)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
e00a8a901015eac185ac75366cf1ce5b0783451c9bc862d27d745b7d038887a8 benchmarks/genome_writing_bench/tasks.yaml
|
|
2
2
|
5ca511c6763b4e3703e8009031ff8dc385c2a99540e2731d875a9fbbb16f5ecd configs/gsh_validated_heldout.yaml
|
|
3
3
|
758817c1e46c7db10f7f942316663367c5f297cac0cf2f59947a90638a256718 data/writer_panel.csv
|
|
4
4
|
865b18ff23d140c3df6f3b5f25398581ebdfe3534e1cecf6f512afb540ab5ede data/gsh_matched_controls.parquet
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
# A task names a `scorer` (module.function in pen_stack.validate / pen_stack.bridge) and a `metric` key to
|
|
9
9
|
# read from its report. Solvers (deterministic planner, naive baseline, LLM agent) are compared on the same
|
|
10
10
|
# tasks; a solver that cannot ground a number must refuse, not invent (no-fabrication is a hard gate).
|
|
11
|
-
version: "0.3.
|
|
11
|
+
version: "0.3.6"
|
|
12
12
|
prepared: "2026-06-11"
|
|
13
13
|
|
|
14
14
|
taxonomy:
|
|
@@ -41,6 +41,10 @@ taxonomy:
|
|
|
41
41
|
SF_safety_screening: "screen a design for select-agent / pandemic-pathogen / controlled-toxin signatures: benign therapeutics pass (0 false refusals), hazards refused/escalated, AI-homolog + chimera + reframing evasions never `clear` (vs a no-safety baseline that clears everything)"
|
|
42
42
|
# v0.3.4 (v5.8): the generative designer - verifier-as-discriminator over a mixed candidate pool.
|
|
43
43
|
GD_generative_design: "generate candidate writing systems and keep ONLY legal+safe+calibrated+immune-profiled survivors (hazardous toxin payload + illegal oversize/form-incompatible designs DISCARDED), returning a Pareto frontier with a grounded immune-risk axis (vs an ungrounded generator that ships hazardous/illegal designs)"
|
|
44
|
+
# v0.3.5 (v5.9): the digital twin - calibrated, OOD-aware, immune-aware, phenotype-bounded outcome prediction.
|
|
45
|
+
OP_outcome_prediction: "predict a write's computable outcome with HONEST calibration (two-sided MAE-vs-naive with bootstrap CI), an interval that WIDENS under OOD, an immune-outcome dimension from v5.6, and phenotype out of scope (vs an overconfident predictor with a fixed narrow interval and no scope awareness)"
|
|
46
|
+
# v0.3.6 (v5.10): the experiment designer - active learning / EIG, falsifiable vs random/greedy.
|
|
47
|
+
ED_experiment_design: "choose the experiment(s) that most reduce model uncertainty: EIG from the calibrated twin (monotone in uncertainty), immune-VOI rewarding proxy-validating experiments, a diverse batch, and a RETROSPECTIVE active-vs-random validation with reps + bootstrap CI (vs a random selector with no acquisition signal and no falsifiable curve)"
|
|
44
48
|
|
|
45
49
|
tasks:
|
|
46
50
|
- id: site_selection_blind_gsh
|
|
@@ -261,3 +265,36 @@ tasks:
|
|
|
261
265
|
note: "v5.8 verifier-as-discriminator: the ungrounded generator returns the raw pool (ships hazardous +
|
|
262
266
|
illegal designs) and fails by construction; the grounded designer discards them and returns calibrated,
|
|
263
267
|
immune-profiled candidates on a Pareto frontier with a grounded immune-risk axis."
|
|
268
|
+
|
|
269
|
+
- id: outcome_prediction
|
|
270
|
+
family: OP_outcome_prediction
|
|
271
|
+
scorer: "pen_stack.validate.outcome_prediction:run"
|
|
272
|
+
metric: "twin_honest_and_calibrated"
|
|
273
|
+
baseline_metric: "overconfident_predictor_honest"
|
|
274
|
+
higher_is_better: true
|
|
275
|
+
hard_gate: true
|
|
276
|
+
gate_rule: "twin_honest_and_calibrated == True (calibration two-sided w/ CI AND OOD widens interval AND immune-outcome present AND phenotype out-of-scope)"
|
|
277
|
+
ground_truth: "structural honesty properties of the outcome prediction (two-sided calibration + OOD widening +
|
|
278
|
+
immune dimension from v5.6 + phenotype out-of-scope), NOT a beat-the-world claim - non-circular; twin-vs-naive
|
|
279
|
+
skill is reported informationally on a labelled synthetic stream because no public perturbation-outcome
|
|
280
|
+
calibration set exists (Arc Virtual Cell Challenge: models do not yet consistently beat naive baselines)"
|
|
281
|
+
circular: false
|
|
282
|
+
note: "v5.9 the digital twin: a trustworthy predictor is calibrated + OOD-aware + immune-aware + phenotype-
|
|
283
|
+
bounded; an overconfident predictor (fixed narrow interval, no OOD/scope awareness) fails the gate by
|
|
284
|
+
construction. Honest about what the field cannot yet do."
|
|
285
|
+
|
|
286
|
+
- id: experiment_design
|
|
287
|
+
family: ED_experiment_design
|
|
288
|
+
scorer: "pen_stack.validate.experiment_design:run"
|
|
289
|
+
metric: "experiment_designer_honest"
|
|
290
|
+
baseline_metric: "random_selector_honest"
|
|
291
|
+
higher_is_better: true
|
|
292
|
+
hard_gate: true
|
|
293
|
+
gate_rule: "experiment_designer_honest == True (EIG monotone in uncertainty AND immune-VOI rewards proxy validation AND batch diverse AND retrospective active-vs-random reported with reps+CI)"
|
|
294
|
+
ground_truth: "structural honesty + falsifiability properties of the Learn engine (twin-sourced EIG, immune-VOI,
|
|
295
|
+
diverse batch, retrospective active-vs-random with reps + bootstrap CI), NOT a beat-the-world claim -
|
|
296
|
+
non-circular; the active-beats-random outcome is reported either way (not-yet-useful is a valid result)"
|
|
297
|
+
circular: false
|
|
298
|
+
note: "v5.10 the experiment designer: a trustworthy Learn engine computes acquisition from the calibrated twin,
|
|
299
|
+
rewards proxy-validating experiments, selects a diverse batch, and validates active-vs-random retrospectively
|
|
300
|
+
with CIs; a random selector has no acquisition signal and no falsifiable curve and fails by construction."
|
|
@@ -179,3 +179,26 @@ oracles:
|
|
|
179
179
|
generalizes_to_unseen_loci: false
|
|
180
180
|
license: "open (this work; Chen 10.1021/acs.analchem.6b03109, Yang&Lai 10.1002/wnan.1339,
|
|
181
181
|
Armstrong 10.1002/cncr.22739, Kozma 10.1016/j.addr.2020.07.024)"
|
|
182
|
+
|
|
183
|
+
state: # v5.9 WS-VCELL: Arc STATE virtual-cell perturbation-response model
|
|
184
|
+
family: vcell
|
|
185
|
+
version: "state-2025"
|
|
186
|
+
output_kind: candidate # a perturbation-response PREDICTION is a candidate/hypothesis, never a claim
|
|
187
|
+
valid_for: "IN-DISTRIBUTION single-gene / chemical / cytokine perturbation transcriptional-response estimates
|
|
188
|
+
in TRAINED human cell contexts (Arc STATE; ~70 contexts, 167M+100M cells)"
|
|
189
|
+
not_valid_for: "OUT-OF-DISTRIBUTION cell types / perturbations (Arc's own Virtual Cell Challenge result:
|
|
190
|
+
perturbation models do NOT yet consistently beat naive baselines -> OOD sets extrapolating=True); phenotype;
|
|
191
|
+
in-vivo behaviour; clinical endpoints"
|
|
192
|
+
generalizes_to_unseen_loci: false
|
|
193
|
+
license: "Arc Institute (github.com/ArcInstitute/state)"
|
|
194
|
+
|
|
195
|
+
scgpt: # v5.9 WS-VCELL: scGPT single-cell foundation model (perturbation prediction)
|
|
196
|
+
family: vcell
|
|
197
|
+
version: "scgpt-2024"
|
|
198
|
+
output_kind: candidate
|
|
199
|
+
valid_for: "IN-DISTRIBUTION genetic-perturbation transcriptional-response estimates within trained single-cell
|
|
200
|
+
contexts (scGPT; >33M cells)"
|
|
201
|
+
not_valid_for: "OOD cell types / perturbations (does not consistently beat naive baselines); phenotype; in-vivo;
|
|
202
|
+
absolute expression"
|
|
203
|
+
generalizes_to_unseen_loci: false
|
|
204
|
+
license: "MIT (github.com/bowang-lab/scGPT; Nature Methods 10.1038/s41592-024-02201-0)"
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# The digital twin (v5.9)
|
|
2
|
+
|
|
3
|
+
From v5.9, PEN-STACK can predict *what the cell does after the write* — calibrated, OOD-gated, and scope-bounded.
|
|
4
|
+
It computes what mechanism allows, adds an in-distribution virtual-cell estimate, screens immune outcome from the
|
|
5
|
+
v5.6 profile, and is honest about its boundary at phenotype. The twin is a **hypothesis engine, not an oracle of
|
|
6
|
+
truth**.
|
|
7
|
+
|
|
8
|
+
```python
|
|
9
|
+
from pen_stack.twin import predict_outcome
|
|
10
|
+
o = predict_outcome(design, cell_state="k562")
|
|
11
|
+
o["predicted_outcome"] # {relative_expression, vcell_response, units}
|
|
12
|
+
o["interval"] # heuristic band; WIDENS under OOD
|
|
13
|
+
o["immune_outcome"] # the v5.6 per-axis profile (sourced, not invented)
|
|
14
|
+
o["scope_flags"] # phenotype_not_modeled, in_vivo_magnitude_unknown, (vcell_OOD if extrapolating)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Mechanism where computable (`pen_stack/twin/mechanistic.py`)
|
|
18
|
+
|
|
19
|
+
`cassette_expression(design, chromatin_ctx)` = `promoter_strength × copy_number × accessibility` — a closed-form
|
|
20
|
+
steady-state estimate. Assumptions (steady-state, no silencing, linear copy scaling) and scope flags
|
|
21
|
+
(`episomal_durability_unknown`, `phenotype_not_modeled`) travel with the output. It is **physics where
|
|
22
|
+
computable, never a phenotype**.
|
|
23
|
+
|
|
24
|
+
## Virtual-cell oracle, OOD-gated (`pen_stack/oracles/vcell.py`)
|
|
25
|
+
|
|
26
|
+
`predict_response(cell_state, perturbation, model="state")` wraps Arc **STATE** / **scGPT** under the v4.0
|
|
27
|
+
`OracleResult` contract. A perturbation-response prediction is a **candidate**, never a claim; a cell context or
|
|
28
|
+
perturbation outside the documented validity envelope sets `extrapolating=True` / `in_scope=False`. The backend is
|
|
29
|
+
deferred/cache-replayed (value `None` when absent — never fabricated). This encodes the field's own result (Arc's
|
|
30
|
+
Virtual Cell Challenge): **perturbation models do not yet consistently beat naive baselines** and do not
|
|
31
|
+
generalize to unseen contexts.
|
|
32
|
+
|
|
33
|
+
## Fused outcome (`pen_stack/twin/outcome.py`)
|
|
34
|
+
|
|
35
|
+
`predict_outcome(design, cell_state)` fuses the computable mechanistic estimate (backbone) + an in-distribution
|
|
36
|
+
virtual-cell response (when available) + the v5.6 immune profile. The interval **widens under OOD** rather than
|
|
37
|
+
over-trusting an extrapolating model. For in-vivo vehicles, durability **may be conditioned on the grounded
|
|
38
|
+
pre-existing-NAb axis** (no invented immune numbers). Phenotype and in-vivo magnitude stay scope-flagged.
|
|
39
|
+
|
|
40
|
+
> The interval is a heuristic band, **not** a trained conformal interval — there is no public
|
|
41
|
+
> perturbation-outcome calibration set. The twin says so.
|
|
42
|
+
|
|
43
|
+
## Honest calibration (`pen_stack/twin/calibrate.py`)
|
|
44
|
+
|
|
45
|
+
`calibrate_outcome(predictions, observations, intervals=…)` reports calibration **two-sided, whatever the shape**:
|
|
46
|
+
interval coverage vs nominal, and a skill comparison against a naive mean baseline with a **bootstrap CI on the
|
|
47
|
+
MAE gap**. The twin "beats" the baseline **only when the CI excludes zero** — otherwise the negative is reported
|
|
48
|
+
verbatim. At `N < 3` it abstains honestly.
|
|
49
|
+
|
|
50
|
+
## Honest scope
|
|
51
|
+
|
|
52
|
+
The twin predicts what mechanism computes, what an in-distribution virtual-cell model supports, and what the v5.6
|
|
53
|
+
immune profile screens — with calibrated intervals. It does **not** predict phenotype, in-vivo behaviour,
|
|
54
|
+
immunogenicity *magnitude*, or durability beyond the computable; these stay scope-flagged. Perturbation prediction
|
|
55
|
+
is an open problem; the twin is a calibrated hypothesis engine, honest where it is weak.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# The experiment designer (v5.10)
|
|
2
|
+
|
|
3
|
+
From v5.10, PEN-STACK turns *"I'm uncertain"* into *"run **this** experiment next."* It reads the calibrated v5.9
|
|
4
|
+
twin's uncertainty and the v5.6 immune-risk labels, scores each candidate experiment by the information it is
|
|
5
|
+
expected to yield, assembles a diverse batch, and proves on held-out data — with confidence intervals — that this
|
|
6
|
+
learns faster than random or greedy, reporting honestly when it does not. The **Learn** brain of a self-driving
|
|
7
|
+
lab: lab-optional and falsifiable by construction.
|
|
8
|
+
|
|
9
|
+
## Acquisition (`pen_stack/active/acquire.py`)
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
from pen_stack.active import acquisition_score, expected_information_gain, immune_voi
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
- **`predictive_entropy(outcome)`** — the twin's current uncertainty, from its interval width (Gaussian
|
|
16
|
+
differential entropy).
|
|
17
|
+
- **`expected_information_gain(candidate, cell_state)`** — reducible uncertainty: `entropy now − expected
|
|
18
|
+
posterior entropy` (a measurement collapses the predictive sd toward a noise floor); `≥ 0`. Monotone in the
|
|
19
|
+
twin's uncertainty (an OOD candidate yields more EIG).
|
|
20
|
+
- **`immune_voi(candidate)`** — value of information for **validating an immune PROXY axis** (v5.6): an axis still
|
|
21
|
+
labelled a proxy that this experiment would measure is high-VOI (it would turn proxy → outcome-validated).
|
|
22
|
+
- **`acquisition_score`** = `w_eig·EIG + w_unc·entropy + w_imm·immune_voi`. Fully traceable to twin quantities +
|
|
23
|
+
v5.6 labels; deterministic given inputs (no fabricated values).
|
|
24
|
+
|
|
25
|
+
## Diverse batch (`pen_stack/active/design.py`)
|
|
26
|
+
|
|
27
|
+
`select_batch(candidates, cell_state, k)` greedily maximises summed acquisition **minus a redundancy penalty**
|
|
28
|
+
(shared design facets) against the already-chosen set — so a batch is a *diverse* set of informative experiments,
|
|
29
|
+
not k copies of the single most-uncertain point. Each chosen experiment carries its `expected_info_gain`.
|
|
30
|
+
|
|
31
|
+
## Retrospective falsifiability (`pen_stack/active/validate.py`)
|
|
32
|
+
|
|
33
|
+
`retrospective_active_learning(dataset, strategies=("active","random","greedy"))` simulates campaigns per
|
|
34
|
+
strategy on a held-out split, records the held-out-MAE learning curve per round, and over repetitions reports
|
|
35
|
+
mean±CI curves and a **bootstrap CI on the curve-area gap** (`random_area − active_area`). The active learner
|
|
36
|
+
"beats" random **only when the CI excludes zero**; otherwise the not-yet-useful negative is reported verbatim — a
|
|
37
|
+
valid, published outcome.
|
|
38
|
+
|
|
39
|
+
## Honest scope
|
|
40
|
+
|
|
41
|
+
The experiment designer is only as good as the v5.9 twin and the v5.6 labels it queries. Its advantage is
|
|
42
|
+
validated **retrospectively** on existing data with confidence intervals, and reported honestly when absent. It
|
|
43
|
+
chooses informative experiments — including ones that would validate an immune proxy — but it **does not run
|
|
44
|
+
them**; prospective benefit awaits a lab partner (v5.11+).
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""PEN-STACK v3.0 - open infrastructure for genome writing."""
|
|
2
|
-
__version__ = "5.
|
|
2
|
+
__version__ = "5.10.0"
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""pen_stack.active — the experiment designer / the "Learn" brain of a self-driving lab (v5.10).
|
|
2
|
+
|
|
3
|
+
Turn "I'm uncertain" into "run THIS experiment next": score each candidate experiment by the information it is
|
|
4
|
+
expected to yield (from the calibrated v5.9 twin), reward experiments that would validate an immune PROXY axis
|
|
5
|
+
(v5.6), assemble a diverse batch, and prove on held-out data — with confidence intervals — that this learns
|
|
6
|
+
faster than random or greedy, reporting honestly when it does not. Lab-optional, falsifiable by construction.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pen_stack.active.acquire import (
|
|
11
|
+
acquisition_score,
|
|
12
|
+
expected_information_gain,
|
|
13
|
+
immune_voi,
|
|
14
|
+
predictive_entropy,
|
|
15
|
+
)
|
|
16
|
+
from pen_stack.active.design import batch_diversity, select_batch
|
|
17
|
+
from pen_stack.active.validate import retrospective_active_learning
|
|
18
|
+
|
|
19
|
+
__all__ = ["expected_information_gain", "immune_voi", "predictive_entropy", "acquisition_score",
|
|
20
|
+
"select_batch", "batch_diversity", "retrospective_active_learning"]
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Acquisition functions for the experiment designer (v5.10, WS-ACQ).
|
|
2
|
+
|
|
3
|
+
Score each candidate experiment by the information it is expected to yield — computed from the calibrated v5.9
|
|
4
|
+
twin's predictive uncertainty (never fabricated). Three signals:
|
|
5
|
+
* expected_information_gain — reducible predictive uncertainty (entropy now - expected posterior entropy),
|
|
6
|
+
* predictive_entropy — the twin's current uncertainty (from its interval width),
|
|
7
|
+
* immune_voi — value of information for VALIDATING an immune PROXY axis (turns proxy -> validated).
|
|
8
|
+
The acquisition is only as good as the v5.9 twin and the v5.6 labels it queries; it chooses informative
|
|
9
|
+
experiments, it does not run them.
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import math
|
|
14
|
+
|
|
15
|
+
# a measurement does not resolve uncertainty perfectly: a noise floor on the post-experiment entropy.
|
|
16
|
+
_MEASUREMENT_NOISE_SD = 0.05
|
|
17
|
+
_TWO_PI_E = 2.0 * math.pi * math.e
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _interval_sd(outcome: dict) -> float:
|
|
21
|
+
"""Std-dev implied by the twin's (approx 95%) interval: sd ~ width / (2 * 1.96)."""
|
|
22
|
+
lo, hi = outcome.get("interval", [0.0, 0.0])
|
|
23
|
+
return max(1e-6, (float(hi) - float(lo)) / (2.0 * 1.96))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _gaussian_entropy(sd: float) -> float:
|
|
27
|
+
return 0.5 * math.log(_TWO_PI_E * sd * sd)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def predictive_entropy(outcome: dict) -> float:
|
|
31
|
+
"""Differential entropy of the twin's predictive distribution, from its interval width."""
|
|
32
|
+
return _gaussian_entropy(_interval_sd(outcome))
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _expected_posterior_entropy(outcome: dict) -> float:
|
|
36
|
+
"""Entropy expected AFTER running the experiment: the measurement collapses predictive sd toward the
|
|
37
|
+
measurement noise floor (cannot go below it)."""
|
|
38
|
+
post_sd = max(_MEASUREMENT_NOISE_SD, min(_interval_sd(outcome), _MEASUREMENT_NOISE_SD * 2))
|
|
39
|
+
return _gaussian_entropy(post_sd)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def expected_information_gain(candidate: dict, cell_state: str, model_ctx: dict | None = None) -> float:
|
|
43
|
+
"""EIG ~ reducible uncertainty = predictive entropy now - expected posterior entropy. Computed from the
|
|
44
|
+
calibrated twin's predictive distribution; >= 0 (a measurement never increases expected uncertainty)."""
|
|
45
|
+
from pen_stack.twin.outcome import predict_outcome
|
|
46
|
+
o = predict_outcome(candidate, cell_state or candidate.get("cell_state", ""))
|
|
47
|
+
return max(0.0, predictive_entropy(o) - _expected_posterior_entropy(o))
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def immune_voi(candidate: dict, cell_state: str = "") -> float:
|
|
51
|
+
"""Value of information for validating an immune PROXY axis (v5.6): an axis still labelled a proxy that this
|
|
52
|
+
experiment would MEASURE is high-VOI (turns proxy -> outcome-validated). Reads the v5.6 validation labels."""
|
|
53
|
+
from pen_stack.twin.outcome import predict_outcome
|
|
54
|
+
prof = predict_outcome(candidate, cell_state or candidate.get("cell_state", "")).get("immune_outcome") or {}
|
|
55
|
+
measures = {str(a).strip().lower() for a in (candidate.get("measures_immune_axes") or [])}
|
|
56
|
+
voi = 0.0
|
|
57
|
+
for axis, rec in prof.get("axes", {}).items():
|
|
58
|
+
label = (rec.get("validation") or "").lower()
|
|
59
|
+
is_proxy = "proxy" in label and "not outcome-validated" in label
|
|
60
|
+
if is_proxy and (not measures or axis.lower() in measures):
|
|
61
|
+
voi += 1.0
|
|
62
|
+
return voi
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def acquisition_score(candidate: dict, cell_state: str, model_ctx: dict | None = None,
|
|
66
|
+
*, w_eig: float = 1.0, w_unc: float = 0.3, w_imm: float = 0.4) -> float:
|
|
67
|
+
"""Weighted acquisition: information gain + raw uncertainty + immune value-of-information. Fully traceable
|
|
68
|
+
to twin quantities + v5.6 labels (no fabricated values); deterministic given the inputs."""
|
|
69
|
+
from pen_stack.twin.outcome import predict_outcome
|
|
70
|
+
o = predict_outcome(candidate, cell_state or candidate.get("cell_state", ""))
|
|
71
|
+
eig = expected_information_gain(candidate, cell_state, model_ctx)
|
|
72
|
+
unc = predictive_entropy(o)
|
|
73
|
+
return w_eig * eig + w_unc * unc + w_imm * immune_voi(candidate, cell_state)
|