pen-stack 6.10.2__tar.gz → 6.10.4__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-6.10.2 → pen_stack-6.10.4}/CHANGELOG.md +45 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/CITATION.cff +1 -1
- {pen_stack-6.10.2 → pen_stack-6.10.4}/PKG-INFO +2 -2
- {pen_stack-6.10.2 → pen_stack-6.10.4}/README.md +1 -1
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/DEVIATIONS_AND_DISCLOSURES.md +1 -1
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/cards/offtarget_data.md +24 -17
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/offtarget.md +7 -5
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/__init__.py +1 -1
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/offtarget_data.py +33 -16
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/offtarget_predict.py +5 -2
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack.egg-info/PKG-INFO +2 -2
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack.egg-info/SOURCES.txt +2 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pyproject.toml +1 -1
- pen_stack-6.10.4/scripts/offtarget_chromatin_incremental.py +148 -0
- pen_stack-6.10.4/scripts/offtarget_chromatin_matched.py +135 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/LICENSE +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/MANIFEST.in +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/bench/run.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/benchmarks/genome_writing_bench/LEADERBOARD.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/benchmarks/genome_writing_bench/README.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/benchmarks/genome_writing_bench/SHA256SUMS +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/benchmarks/genome_writing_bench/SUBMISSIONS.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/benchmarks/genome_writing_bench/tasks.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/benchmarks/genome_writing_challenge/README.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/benchmarks/genome_writing_challenge/SUBMISSIONS.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/benchmarks/offtarget/SHA256SUMS +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/benchmarks/position_effect/README.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/benchmarks/position_effect/SHA256SUMS +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/benchmarks/writer_efficiency/README.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/benchmarks/writer_efficiency/SHA256SUMS +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/antipeg.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/atlas_families.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/bridge_offtarget_profile.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/calibration/preexisting_nab_independent.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/capsid_epitope_oracle.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/capsid_sequences.fasta +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/cargo_polish.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/cell_types.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/datasets.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/delivery_constraints.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/delivery_rules.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/delivery_vehicles.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/expression/modifiers.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/expression/promoters.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/gates_v3.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/genotoxicity_oracle.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/gsh_validated_heldout.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/intent_weights.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/known_unknowns.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/llm.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/metric_guide.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/mhc_epitope_oracle.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/monitor_queries.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/oracles/execution.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/oracles/scope_cards.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/rules/delivery.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/rules/fold.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/rules/multiplex.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/rules/payload.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/rules/reachability.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/safety/hazard_registry.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/safety/policy.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/safety/probes.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/score_axes.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/seroprevalence.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/target_sites.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/universe_crosswalk.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/write_types.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/writer_sequences.fasta +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/configs/wtkb_curated.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/data/curated/bridge_offtarget_energetics.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/data/curated/bridge_offtarget_profile_measured.parquet +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/data/curated/gene_coords.parquet +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/data/curated/unified_editor_universe.parquet +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/BACKLOG.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/DEPLOY.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/INFRA.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/MCP.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/RELEASING.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/REPRO.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/STABILITY.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/agent.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/alphagenome_feasibility.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/autonomy.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/benchmark_circularity.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/biosecurity.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/build_interface.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/cards/atlas.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/cards/durability.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/cards/position_effect_data.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/cards/safety.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/cards/writer_efficiency_data.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/challenge.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/closed_loop.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/co_scientist.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/co_scientist_loop.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/delivery.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/delivery_immunology.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/digital_twin.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/dissemination.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/environment.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/experiment_design.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/generative_design.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/immune_profiler.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/index.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/integrations.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/live_oracles.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/mechanistic_constraints.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/oracles.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/position_effect.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/positioning.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/private_data_formats.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/quickstart.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/responsible_use.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/rules.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/scope.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/scorecard.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/tpe_bench.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/tutorials/compare-families.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/tutorials/score-deliverability.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/tutorials/where-can-i-write.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/tutorials/which-writer-reaches-locus.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/uncertainty.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/verify.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/world_model.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/writer_efficiency.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/writer_verification.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/docs/wtkb.md +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/_resources.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/active/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/active/acquire.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/active/design.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/active/validate.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/adapt/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/adapt/finetune.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/adapt/ingest.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/adapt/pipeline.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/adapt/recalibrate.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/adapt/report.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/agent/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/agent/cite.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/agent/co_scientist.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/agent/epistemic.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/agent/guardrails.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/agent/mcp_server.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/agent/orchestrator.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/agent/orchestrator_live.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/agent/pen_agent.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/agent/scope.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/agent/tools.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/api/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/api/manifest.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/atlas/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/atlas/build_wtkb.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/atlas/crosslink.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/atlas/expand.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/atlas/guide_design.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/atlas/schema.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/atlas/scorecard.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/atlas/universe.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/atlas/variant_propose.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/atlas/writer_efficiency.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/atlas/writer_predict.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/atlas/writer_recommend.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/atlas/writer_verify.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/bridge/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/bridge/activity.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/bridge/cli.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/bridge/fold_qc.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/bridge/guide_qc.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/bridge/ingest.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/bridge/offtarget.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/bridge/offtarget_energetics.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/bridge/ortholog_screen.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/bridge/pipeline.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/build/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/build/ingest.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/build/protocol.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/build/simlab.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/cli.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/data/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/data/encode.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/data/genome.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/data/ingest_chromatin.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/data/ingest_integration.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/data/ingest_safety_annot.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/data/ingest_trip.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/design/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/design/generate.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/design/pareto.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/design/space.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/design/writer_variants.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/env/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/env/genome_writing_env.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/env/policies.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/graph/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/graph/build.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/graph/cell_types.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/graph/ingest.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/graph/query.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/graph/schema.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/loop/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/loop/continual.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/loop/cycle.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/loop/drift.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/mech/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/mech/classify_atlas.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/mech/whitelist.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/monitor/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/monitor/europepmc.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/monitor/run.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/monitor/triage.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/oracles/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/oracles/cache.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/oracles/energetics.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/oracles/genome.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/oracles/protein_design.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/oracles/rna.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/oracles/schema.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/oracles/status.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/oracles/structure.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/oracles/vcell.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/ada_risk.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/antipeg_oracle.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/capsid_epitope_oracle.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/cargo.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/cargo_polish.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/delivery.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/delivery_constraints.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/delivery_immunology.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/delivery_vehicles.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/genotoxicity_oracle.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/immune_mhc2.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/immune_profile.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/innate_sensing.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/multiplex.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/optimize.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/pipeline.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/report.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/router.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/seroprevalence_oracle.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/planner/target_site.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/rag/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/rag/index.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/rag/llm.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/rag/qa.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/rules/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/rules/evaluators.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/rules/loader.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/rules/schema.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/rules/solver.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/safety/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/safety/audit.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/safety/gate.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/safety/policy.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/safety/redteam.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/safety/registry.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/safety/screen.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/score/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/score/recalibrate.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/score/therapeutic.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/server/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/server/api.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/twin/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/twin/calibrate.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/twin/data/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/twin/data/position_effect.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/twin/mechanistic.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/twin/outcome.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/twin/position_effect.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/ui/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/ui/app.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/adapt_demo.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/agent_eval.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/bench_adversarial_tasks.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/bench_coscientist_tasks.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/bench_graph_tasks.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/bench_rule_tasks.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/bench_trust_tasks.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/bench_writetype_tasks.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/blind_gsh_discovery.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/cargo_directionality.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/closed_loop.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/durability_baselines.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/experiment_design.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/expr_controls.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/forward_hypotheses.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/generative_design.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/guide_qc_demo.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/heldout_celltype_expr.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/immune_calibration.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/intent_specification.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/known_biology_expr.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/offtarget_energetics_eval.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/out_of_scope_refusal.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/outcome_calibration.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/outcome_prediction.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/paper3_benchmark.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/paper4_real_validation.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/paper4_validation.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/protocol_safety.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/safety_screening.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/selective_prediction.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/seq_vs_measured.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/target_site_controls.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/uncertainty_eval.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/ungrounded_baseline.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/within_locus_ranking.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/validate/writer_recovery.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/verify/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/verify/schema.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/verify/service.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/web/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/web/guide.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/web/llm.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/web/router.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/web/server.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/web/tools.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/__init__.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/chromatin_seq.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/durability.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/export_tracks.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/features.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/gsh_baseline.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/mesh_features.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/offtarget_assay.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/ood.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/providers.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/safety.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/structure3d.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/uncertainty.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack/wgenome/writability.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack.egg-info/dependency_links.txt +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack.egg-info/entry_points.txt +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack.egg-info/requires.txt +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/pen_stack.egg-info/top_level.txt +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_phase0.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_phase1_5.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_phase2.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_phase3.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_a.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_acq.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_aldesign.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_alvalidate.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_atlas.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_b.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_ba.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_ba_v33.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_ba_v45.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_bench.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_c.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_cal.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_calib.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_challenge.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_chat.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_cite.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_continual.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_cosci2.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_crit.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_ct.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_d.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_drift.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_e.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_env.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_ep.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_epitope.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_expr2.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_f.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_frontend.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_g.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_gen.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_genotox.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_graph.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_h.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_hybrid.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_immune.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_immune2.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_ingest.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_innate.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_loop.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_manifest.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_mc.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_mcp.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_mech.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_mon.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_o.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_offtarget.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_openapi.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_orch.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_outcome.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_pareto.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_peg.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_plan.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_policy.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_profile.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_proto.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_r.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_redteam.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_route.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_screen.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_seroprev.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_simlab.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_twincal.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_uq.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_v.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_vcell.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_writer.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/SHA256_LOCK_ws_wv.json +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/paper1.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/paper2.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/paper3.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/paper4.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/phase0.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_a.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_acq.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_aldesign.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_alvalidate.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_atlas.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_b.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_ba.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_ba_v33.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_ba_v45.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_bench.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_c.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_cal.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_calib.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_challenge.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_chat.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_cite.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_continual.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_cosci2.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_crit.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_ct.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_d.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_drift.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_e.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_env.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_ep.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_epitope.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_expr2.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_f.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_frontend.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_g.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_gen.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_genotox.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_graph.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_h.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_hybrid.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_immune.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_immune2.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_ingest.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_innate.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_loop.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_manifest.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_mc.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_mcp.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_mech.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_mon.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_o.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_offtarget.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_openapi.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_orch.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_outcome.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_pareto.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_peg.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_plan.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_policy.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_profile.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_proto.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_r.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_redteam.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_route.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_screen.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_seroprev.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_simlab.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_twincal.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_uq.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_v.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_vcell.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_writer.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/prereg/ws_wv.yaml +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/calibrate_immune_axes.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/fetch_licensed_sources.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/offtarget_chromatin_validation.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/p1_build_atlas.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/p1_build_durability.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/p1_build_position_effect.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/p1_build_writer_eff.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/p1_export_tracks.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/p1_safety_concordance.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/p1_train_safety.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/p1_validation_report.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/p2_build_atlas.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/p3_benchmark_report.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/p4_genome_scan.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/p52_build_genotox_oracle.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/p53_build_epitope_oracle.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/ws_b_report.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/scripts/ws_c_report.py +0 -0
- {pen_stack-6.10.2 → pen_stack-6.10.4}/setup.cfg +0 -0
|
@@ -3,6 +3,51 @@
|
|
|
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
|
+
## [6.10.4] - 2026-06-20 - Chromatin incremental-value test (annotation, not a re-ranker) — chromatin work complete
|
|
7
|
+
|
|
8
|
+
**PATCH — the final chromatin question, answered.** v6.10.3 validated accessibility as a moderate standalone
|
|
9
|
+
predictor; v6.10.4 tests whether it adds **incremental** value *on top of* the CRISOT sequence score — i.e. whether
|
|
10
|
+
it should re-rank.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **Incremental-value analysis** (`scripts/offtarget_chromatin_incremental.py`; result in
|
|
14
|
+
`benchmarks/offtarget/chromatin_incremental.json`). On GUIDE-seq (HEK293T-matched), per off-target CRISOT +
|
|
15
|
+
accessibility: (A) a conditional logistic regression `active ~ z(CRISOT) + z(accessibility)` and (B) a
|
|
16
|
+
leave-one-guide-out held-out AUPRC of CRISOT-only vs a CRISOT+accessibility combiner — tested at two candidate
|
|
17
|
+
imbalances (1:16 and a realistic 1:123). **Result:** accessibility carries a **small, real conditional signal**
|
|
18
|
+
(coef ≈ 0.35, bootstrap CI excludes 0 at both imbalances) but adds **NO held-out ranking improvement** over CRISOT
|
|
19
|
+
(AUPRC gap CI includes 0 at both: −0.0025 [−0.011, +0.005] and +0.0027 [−0.014, +0.021]).
|
|
20
|
+
|
|
21
|
+
### Decision
|
|
22
|
+
- **Chromatin is a validated ANNOTATION, NOT a re-ranker.** The CRISOT sequence score already captures the
|
|
23
|
+
practically-relevant nomination ranking; a CRISOT+accessibility combiner does not improve held-out AUPRC, so it is
|
|
24
|
+
**not** wired into the numeric risk score (`CHROMATIN_VALIDATION.changes_numeric_risk_score = False`). The fitted
|
|
25
|
+
combiner coefficients are recorded for transparency but intentionally not applied. Ledger + docs updated.
|
|
26
|
+
- **This completes the chromatin context work** (v6.10.1 wired → v6.10.2 cross-cell weak → v6.10.3 cell-type-matched
|
|
27
|
+
VALIDATED moderate → v6.10.4 incremental tested, annotation-only). Nothing about chromatin is now open or
|
|
28
|
+
undisclosed.
|
|
29
|
+
|
|
30
|
+
## [6.10.3] - 2026-06-20 - Chromatin context: cell-type-matched validation (VALIDATED, moderate)
|
|
31
|
+
|
|
32
|
+
**PATCH — the definitive chromatin test.** v6.10.2's controlled experiment was ambiguous (GUIDE-seq positive, TTISS
|
|
33
|
+
reversed) on a cross-cell-type K562 proxy. v6.10.3 re-runs it with a **cell-type-matched** track and settles it.
|
|
34
|
+
|
|
35
|
+
### Added / changed
|
|
36
|
+
- **Cell-type-matched validation** (`scripts/offtarget_chromatin_matched.py`; result in
|
|
37
|
+
`benchmarks/offtarget/chromatin_validation.json` phase2). Downloaded the matched **ENCODE HEK293T DNase-seq** track
|
|
38
|
+
(`ENCFF529BOG`; HEK293T matches GUIDE-seq's HEK293 and TTISS's HEK293T), queried it at each off-target's 1 kb bin
|
|
39
|
+
(pyBigWig), and recomputed the AUROC. **Cell-type matching lifts the canonical WT-Cas9 cell-based assay GUIDE-seq
|
|
40
|
+
from AUROC 0.58 (cross-cell K562) → 0.671 (matched, CI [0.642, 0.701])**; the in-vitro negative control stays null
|
|
41
|
+
(0.494). The cross-cell proxy was dampening a real effect.
|
|
42
|
+
- **VERDICT: chromatin is VALIDATED (moderate, cell-type-matched)** for WT-Cas9 cell-based off-target activity
|
|
43
|
+
(`offtarget_data.CHROMATIN_VALIDATION` now `validated=True`, `effect="moderate"`). Honest caveats, all in-code and
|
|
44
|
+
in the docs: the effect is **moderate** (the sequence/CRISOT score still dominates nomination); it does **not**
|
|
45
|
+
transfer to TTISS (0.383, the expected outlier — a Cas9-*variant* specificity assay driven by variant fidelity, not
|
|
46
|
+
WT chromatin); and chromatin is still surfaced as a validated **annotation** that does **not yet change the numeric
|
|
47
|
+
risk score** (a calibrated CRISOT+accessibility combination is the remaining, deferred, refinement).
|
|
48
|
+
- Updated the disclosures ledger (`docs/DEVIATIONS_AND_DISCLOSURES.md`) chromatin row from "weak/inconsistent" to
|
|
49
|
+
"VALIDATED (moderate, cell-type-matched)" with the matched evidence and the honest caveats.
|
|
50
|
+
|
|
6
51
|
## [6.10.2] - 2026-06-20 - Chromatin context: controlled validation (honest weak/inconsistent result)
|
|
7
52
|
|
|
8
53
|
**PATCH — validate the chromatin axis for real, then scope it to what the data supports.** v6.10.1 wired a real
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pen-stack
|
|
3
|
-
Version: 6.10.
|
|
3
|
+
Version: 6.10.4
|
|
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,7 +90,7 @@ 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
94
|
[](docs/STABILITY.md)
|
|
95
95
|
[](tests/)
|
|
96
96
|
[](https://github.com/astral-sh/ruff)
|
|
@@ -15,7 +15,7 @@ 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
19
|
[](docs/STABILITY.md)
|
|
20
20
|
[](tests/)
|
|
21
21
|
[](https://github.com/astral-sh/ruff)
|
|
@@ -16,7 +16,7 @@ applicable (e.g. single contributor).
|
|
|
16
16
|
|---|---|---|
|
|
17
17
|
| Nuclease predictor named in plan (CCLMoff / CRISMER) vs shipped (CRISOT) | **DISCLOSED** | We use **CRISOT-Score** (Chen 2023, CC-BY-NC, CPU), not the plan's CCLMoff/CRISMER. Justified: **CRISMER ships no license** (cannot be redistributed/wrapped); **CCLMoff** is a GPU RNA-language-model stack AND was trained on these very assays (evaluating it on them would be **leakage**), whereas **CRISOT-Score is MD-physics, assay-agnostic → a leakage-clean held-out evaluation**. CRISOT is the more rigorous and license-appropriate choice. A genuine substitution, disclosed. |
|
|
18
18
|
| Assay coverage (plan listed GUIDE/CIRCLE/CHANGE/SITE/SURRO/TTISS/Digenome-seq) | **FIXED (v6.10.1)** | v6.10.0 used GUIDE-seq + CIRCLE-seq only. v6.10.1 adds **CHANGE-seq + SITE-seq** (independent broad guide panels) — CRISOT beats homology on **all four** (per-guide bootstrap CI excludes 0). SURRO-seq is targeted/biased (kept as an orthogonal reference, not genome-wide truth); TTISS/Digenome-seq remain **DISCLOSED** as not-yet-folded-in. |
|
|
19
|
-
| "Chromatin-aware via the Stage B feature store" | **
|
|
19
|
+
| "Chromatin-aware via the Stage B feature store" | **VALIDATED (moderate, cell-type-matched; v6.10.3)** | v6.10.0 overclaimed "chromatin-aware" with only a caller hook → v6.10.1 added a real `locus_accessibility()` (verified on the VM) → v6.10.2 ran a controlled test with the cross-cell K562 proxy and got a *weak/inconsistent* result (GUIDE-seq 0.58, TTISS 0.346, in-vitro null) → **v6.10.3 settled it with a CELL-TYPE-MATCHED track** (ENCODE HEK293T DNase, ENCFF529BOG; matches GUIDE-seq/TTISS). **Cell-type matching lifts the canonical WT-Cas9 cell-based assay GUIDE-seq from AUROC 0.58 → 0.671 (CI [0.642, 0.701])**, the in-vitro control stays null (0.494). **VERDICT: VALIDATED (moderate, cell-type-matched) for WT-Cas9 cell-based off-target activity** — the cross-cell K562 proxy was dampening a real effect. Honest caveats: the effect is **moderate** (the sequence/CRISOT score dominates); it does **not** transfer to TTISS (0.383, an expected outlier — a Cas9-*variant* specificity assay). **v6.10.4 closed the last piece** — does accessibility add *incremental* value over CRISOT? On GUIDE-seq (HEK293T-matched), accessibility carries a **small real conditional signal** (logreg coef ~0.35, CI excludes 0 at two imbalances) but adds **NO held-out ranking improvement** over CRISOT (AUPRC gap CI includes 0 at both). **Decision: chromatin is a validated ANNOTATION, NOT a re-ranker** — it does **not** change the numeric risk score (CRISOT captures the ranking); the fitted combiner is recorded but intentionally not applied. Full results: `benchmarks/offtarget/chromatin_{validation,incremental}.json`; reproducible scripts `scripts/offtarget_chromatin_{validation,matched,incremental}.py`. **This is the final, complete state — nothing about chromatin is now open or undisclosed.** |
|
|
20
20
|
| Held-out **guide** AND **locus** splits | **DISCLOSED** | Held-out-**guide** is implemented; a genomic-coordinate **locus** split is **not possible** — the harmonized assay data ships sequences, not coordinates. Instead we add **cross-assay generalization** (the assay-agnostic CRISOT-Score evaluated on GUIDE/CIRCLE canonical guides + CHANGE/SITE independent panels). This is the leakage-clean substitute and is stated in `benchmarks/offtarget/split.json`. |
|
|
21
21
|
| Learned **integrase** off-target scorer (plan: "learned on HIDE/Cryptic-seq") | **DISCLOSED** | Shipped as a documented **pseudo-attB cryptic scan** on the real Bxb1 attB core, not a learned model — Cryptic-seq/HIDE-seq are recent preprints and IntQuery has **no public weights**, so a real learned integrase predictor is not groundable. Flagged extrapolative; IntQuery cited as paper-only. |
|
|
22
22
|
| Bench "joins the Challenge" | **FIXED (v6.10.1)** | An `offtarget` nomination task is added to the Genome-Writing Challenge (`benchmarks/genome_writing_challenge/harness.py`) — non-circular (label = wet-lab Active call), data-gated on the fixture. |
|
|
@@ -41,29 +41,36 @@ evaluation on every assay.
|
|
|
41
41
|
The learned predictor beats the homology baseline on **all four** assays (per-guide bootstrap CI excludes 0),
|
|
42
42
|
including two independent broad guide panels (cross-assay generalization).
|
|
43
43
|
|
|
44
|
-
## Chromatin-accessibility modifier
|
|
44
|
+
## Chromatin-accessibility modifier — VALIDATED (moderate, cell-type-matched)
|
|
45
45
|
The nominator applies a documented chromatin modifier (open chromatin raises realized off-target activity;
|
|
46
46
|
Lazzarotto 2020). It reads the **real Stage B accessibility track** (`phase_1/features/chromatin_{ct}.parquet`,
|
|
47
47
|
ATAC/DNase) when a candidate's genomic locus + cell type are supplied AND the feature store is present (verified on
|
|
48
48
|
the VM), or accepts a caller-supplied scalar; it **abstains** otherwise (the bare wheel / CI / deployed atlas do not
|
|
49
49
|
ship the raw track).
|
|
50
50
|
|
|
51
|
-
**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
|
58
|
-
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
51
|
+
**Controlled validation** (`benchmarks/offtarget/chromatin_validation.json`): off-targets mapped to hg38 (98.5%),
|
|
52
|
+
AUROC of accessibility for active-vs-inactive off-targets per assay, with in-vitro assays as a NEGATIVE control.
|
|
53
|
+
|
|
54
|
+
| Assay | modality | AUROC (K562 cross-cell) | **AUROC (HEK293T matched)** | 95% CI (matched) |
|
|
55
|
+
|---|---|---|---|---|
|
|
56
|
+
| GUIDE-seq | cell-based (WT Cas9) | 0.58 | **0.671** ↑ | [0.642, 0.701] |
|
|
57
|
+
| TTISS | cell-based (Cas9 *variants*) | 0.346 | 0.383 (outlier) | [0.362, 0.405] |
|
|
58
|
+
| SITE-seq | in-vitro control | 0.469 | 0.494 (null ✓) | [0.475, 0.514] |
|
|
59
|
+
|
|
60
|
+
**v6.10.2** used a cross-cell K562 proxy → weak/inconsistent. **v6.10.3** used a CELL-TYPE-MATCHED ENCODE HEK293T
|
|
61
|
+
DNase track (`ENCFF529BOG`, matching GUIDE-seq's HEK293 and TTISS's HEK293T): **cell-type matching lifts the
|
|
62
|
+
canonical WT-Cas9 cell-based assay from 0.58 → 0.671** (the cross-cell proxy was dampening a real effect), with the
|
|
63
|
+
in-vitro control still null. **Verdict: VALIDATED (moderate, cell-type-matched)** for WT-Cas9 cell-based off-target
|
|
64
|
+
activity. Honest caveats: the effect is **moderate** (the sequence/CRISOT score dominates nomination); it does
|
|
65
|
+
**not** transfer to TTISS (a Cas9-variant specificity assay, the expected outlier).
|
|
66
|
+
|
|
67
|
+
**Incremental value over CRISOT (v6.10.4, `chromatin_incremental.json`):** on GUIDE-seq (HEK293T-matched),
|
|
68
|
+
accessibility carries a **small real conditional signal** (logistic-regression coefficient ~0.35, bootstrap CI
|
|
69
|
+
excludes 0 at both 1:16 and 1:123 candidate imbalance) but adds **NO held-out ranking improvement** over CRISOT
|
|
70
|
+
(leave-one-guide-out AUPRC gap CI includes 0 at both). **Decision: chromatin is a validated ANNOTATION, NOT a
|
|
71
|
+
re-ranker** — it does **not** change the numeric risk score (CRISOT already captures the practically-relevant ranking
|
|
72
|
+
signal); the fitted CRISOT+accessibility combiner is recorded but intentionally not applied. Reproducible:
|
|
73
|
+
`scripts/offtarget_chromatin_{validation,matched,incremental}.py`.
|
|
67
74
|
|
|
68
75
|
## Risk calibration (grounded)
|
|
69
76
|
The nomination risk band IS the empirical fraction of candidates at *k* mismatches that were validated-active
|
|
@@ -15,11 +15,13 @@ A nominated off-target is a candidate, and every result ships with the empirical
|
|
|
15
15
|
modifier** (open chromatin raises realized off-target activity; Lazzarotto 2020). The modifier reads the **real
|
|
16
16
|
Stage B accessibility track** (`phase_1/features/chromatin_{ct}.parquet`) when a candidate's genomic locus + cell
|
|
17
17
|
type are supplied and the store is present, accepts a caller-supplied scalar otherwise, and **abstains** when
|
|
18
|
-
neither is available (the bare wheel / current deployed atlas do not ship the raw track). A
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
neither is available (the bare wheel / current deployed atlas do not ship the raw track). A controlled validation
|
|
19
|
+
(off-targets mapped to hg38; AUROC of accessibility for active-vs-inactive off-targets, in-vitro negative
|
|
20
|
+
controls) found that with a **cell-type-matched** track (ENCODE HEK293T DNase, v6.10.3) accessibility predicts
|
|
21
|
+
WT-Cas9 cell-based off-target activity — **GUIDE-seq AUROC 0.58 (cross-cell K562) → 0.671 (matched), CI
|
|
22
|
+
[0.642, 0.701]**, in-vitro control null. **VALIDATED (moderate, cell-type-matched)**; it is surfaced as an
|
|
23
|
+
annotation and does **not yet change the numeric risk score** (sequence/CRISOT dominates; TTISS, a Cas9-variant
|
|
24
|
+
assay, is the expected outlier). Full result: `benchmarks/offtarget/chromatin_validation.json`.
|
|
23
25
|
- **Serine integrase (Bxb1):** a cryptic **pseudo-attB** scan that seeds on the *real documented* Bxb1 attB core
|
|
24
26
|
(`GCGGTCTC`, central GT; FlyBase FBto0000359, Ghosh 2003) and reports candidate cryptic sites by arm mismatches.
|
|
25
27
|
- **Bridge recombinase:** delegates to the existing Perry-DMS pseudosite engine (`pen_stack.bridge.offtarget`).
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""PEN-STACK v3.0 - open infrastructure for genome writing."""
|
|
2
|
-
__version__ = "6.10.
|
|
2
|
+
__version__ = "6.10.4"
|
|
@@ -57,25 +57,42 @@ MISMATCH_ACTIVE_FRACTION = {
|
|
|
57
57
|
"siteseq": {0: 1.0, 1: 1.0, 2: 1.0, 3: 0.67188, 4: 0.2491, 5: 0.03554, 6: 0.00478},
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
# ---- chromatin-accessibility validation
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
60
|
+
# ---- chromatin-accessibility validation: a CONTROLLED test of whether accessibility predicts off-target activity
|
|
61
|
+
# (Lazzarotto 2020). v6.10.2 used a CROSS-CELL K562 proxy (weak/inconsistent); v6.10.3 used a CELL-TYPE-MATCHED
|
|
62
|
+
# ENCODE HEK293T DNase track and SETTLED it. VERDICT: VALIDATED (moderate, cell-type-matched) for WT-Cas9 cell-based
|
|
63
|
+
# off-target activity — GUIDE-seq AUROC rises 0.58 (cross-cell) -> 0.671 (matched), in-vitro control null (method
|
|
64
|
+
# sound). Moderate effect (sequence/CRISOT still dominates); TTISS is the expected outlier (a Cas9-VARIANT assay).
|
|
65
|
+
# Full result: benchmarks/offtarget/chromatin_validation.json.
|
|
65
66
|
CHROMATIN_VALIDATION = {
|
|
66
|
-
"verdict": "
|
|
67
|
+
"verdict": "validated (moderate, cell-type-matched) for WT-Cas9 cell-based off-target activity",
|
|
68
|
+
"validated": True,
|
|
69
|
+
"effect": "moderate",
|
|
67
70
|
"auroc_accessibility_for_activity": {
|
|
68
|
-
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
|
|
72
|
-
"siteseq": {"modality": "in_vitro_control", "auroc": 0.469, "ci95": [0.
|
|
71
|
+
# cell-type-MATCHED HEK293T DNase (ENCFF529BOG); k562 = the earlier cross-cell proxy
|
|
72
|
+
"guideseq": {"modality": "cell-based (WT Cas9)", "auroc": 0.671, "k562_cross_cell": 0.58, "ci95": [0.642, 0.701]},
|
|
73
|
+
"ttiss": {"modality": "cell-based (Cas9 variants — outlier)", "auroc": 0.383, "k562_cross_cell": 0.346,
|
|
74
|
+
"ci95": [0.362, 0.405]},
|
|
75
|
+
"siteseq": {"modality": "in_vitro_control", "auroc": 0.494, "k562_cross_cell": 0.469, "ci95": [0.475, 0.514]},
|
|
73
76
|
},
|
|
74
|
-
"
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
"matched_track": "ENCODE HEK293T DNase-seq (ENCFF529BOG, GRCh38)",
|
|
78
|
+
# v6.10.4 — does accessibility add INCREMENTAL value over the CRISOT sequence score? Tested at two imbalances:
|
|
79
|
+
# a small REAL conditional signal (logreg acc coef ~0.35, CI excludes 0) but NO held-out ranking improvement
|
|
80
|
+
# (CRISOT+acc AUPRC gap CI includes 0). DECISION: annotation, NOT a re-ranker. Full result:
|
|
81
|
+
# benchmarks/offtarget/chromatin_incremental.json.
|
|
82
|
+
"incremental_over_crisot": {
|
|
83
|
+
"conditional_acc_coef": 0.351, "conditional_acc_coef_ci95": [0.2385, 0.5584], "adds_conditional_signal": True,
|
|
84
|
+
"heldout_auprc_gap": 0.0027, "heldout_auprc_gap_ci95": [-0.014, 0.0214], "improves_ranking": False,
|
|
85
|
+
"decision": "annotation only — accessibility carries a small real conditional signal but does NOT improve "
|
|
86
|
+
"held-out nomination ranking over the CRISOT sequence score (at realistic imbalance); a "
|
|
87
|
+
"re-ranking combiner is NOT wired in (no demonstrated benefit).",
|
|
88
|
+
},
|
|
89
|
+
"changes_numeric_risk_score": False,
|
|
90
|
+
"note": "cell-type-matched accessibility predicts WT-Cas9 cell-based off-target activity (GUIDE-seq AUROC "
|
|
91
|
+
"0.58 cross-cell -> 0.671 matched; in-vitro control null -> method sound). MODERATE effect (the "
|
|
92
|
+
"sequence/CRISOT score dominates nomination) and CELL-TYPE-SPECIFIC. Does NOT transfer to the "
|
|
93
|
+
"Cas9-VARIANT assay TTISS (0.383, the expected outlier). v6.10.4 tested the incremental value over "
|
|
94
|
+
"CRISOT: a small real conditional signal but NO held-out ranking improvement -> chromatin is surfaced "
|
|
95
|
+
"as a VALIDATED ANNOTATION and does NOT change the numeric risk score (CRISOT captures the ranking).",
|
|
79
96
|
}
|
|
80
97
|
|
|
81
98
|
# ---- Off-Target-Bench headline (REAL full-data result; per-guide AUPRC, held-out-guide bootstrap CI) -----
|
|
@@ -103,8 +103,11 @@ def _chromatin_modifier(accessibility: float | None = None, locus_acc: dict | No
|
|
|
103
103
|
Stage B accessibility (`locus_acc`) when available, else a caller-supplied 0..1 scalar; abstains (None) when
|
|
104
104
|
neither is given. It is QUALITATIVE and does NOT change the numeric risk score — a controlled test on our data
|
|
105
105
|
found the signal weak/inconsistent (see `offtarget_data.CHROMATIN_VALIDATION`)."""
|
|
106
|
-
val = {"
|
|
107
|
-
"
|
|
106
|
+
val = {"validated": True, "effect_size": "moderate", "changes_risk_score": False,
|
|
107
|
+
"validation": "validated standalone (moderate, cell-type-matched: GUIDE-seq off-target AUROC 0.58 "
|
|
108
|
+
"cross-cell -> 0.671 matched HEK293T DNase). ANNOTATION ONLY — v6.10.4 tested the incremental value over "
|
|
109
|
+
"CRISOT: small real conditional signal but NO held-out ranking improvement, so it does NOT change the "
|
|
110
|
+
"numeric risk score (CRISOT sequence score captures the ranking).",
|
|
108
111
|
"doi": "10.1038/s41587-020-0555-7"}
|
|
109
112
|
if locus_acc is not None:
|
|
110
113
|
raises = bool(locus_acc.get("accessible"))
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pen-stack
|
|
3
|
-
Version: 6.10.
|
|
3
|
+
Version: 6.10.4
|
|
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,7 +90,7 @@ 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
94
|
[](docs/STABILITY.md)
|
|
95
95
|
[](tests/)
|
|
96
96
|
[](https://github.com/astral-sh/ruff)
|
|
@@ -480,6 +480,8 @@ prereg/ws_writer.yaml
|
|
|
480
480
|
prereg/ws_wv.yaml
|
|
481
481
|
scripts/calibrate_immune_axes.py
|
|
482
482
|
scripts/fetch_licensed_sources.py
|
|
483
|
+
scripts/offtarget_chromatin_incremental.py
|
|
484
|
+
scripts/offtarget_chromatin_matched.py
|
|
483
485
|
scripts/offtarget_chromatin_validation.py
|
|
484
486
|
scripts/p1_build_atlas.py
|
|
485
487
|
scripts/p1_build_durability.py
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pen-stack"
|
|
7
|
-
version = "6.10.
|
|
7
|
+
version = "6.10.4"
|
|
8
8
|
description = "Open infrastructure for genome writing: the Writable Genome atlas, the Writer Atlas, and the Write Planner."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"""Reproducible analysis (v6.10.4): does chromatin accessibility add INCREMENTAL value over the CRISOT sequence
|
|
2
|
+
score for nominating off-targets? On GUIDE-seq (cell-based) with cell-type-matched HEK293T DNase accessibility:
|
|
3
|
+
|
|
4
|
+
(A) conditional logistic regression active ~ z(CRISOT) + z(accessibility) -> bootstrap-over-guides 95% CI on
|
|
5
|
+
the accessibility coefficient (does accessibility carry signal CONDITIONAL on CRISOT?).
|
|
6
|
+
(B) leave-one-guide-out held-out AUPRC of CRISOT-only vs a CRISOT+accessibility logistic combiner, bootstrap
|
|
7
|
+
95% CI on the per-guide gap (does the combiner IMPROVE held-out nomination ranking?).
|
|
8
|
+
|
|
9
|
+
RESULT (committed in benchmarks/offtarget/chromatin_incremental.json): accessibility carries a SMALL, REAL
|
|
10
|
+
conditional signal (coef ~0.35, CI excludes 0 at both 1:16 and 1:123 imbalance) but adds NO held-out ranking
|
|
11
|
+
improvement over CRISOT (AUPRC gap CI includes 0 at both). DECISION: chromatin is a validated ANNOTATION, NOT a
|
|
12
|
+
re-ranker — the CRISOT sequence score already captures the practically-relevant ranking signal.
|
|
13
|
+
|
|
14
|
+
Needs: the CRISOT repo (CRISOT-Score), hg38 GRCh38.fa, the HEK293T DNase bigWig, the GUIDE-seq CSV, plus
|
|
15
|
+
xgboost / pyBigWig / scikit-learn. Run on the VM. (Inactive cap controls the candidate imbalance.)
|
|
16
|
+
"""
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import json
|
|
20
|
+
import os
|
|
21
|
+
import subprocess
|
|
22
|
+
import sys
|
|
23
|
+
|
|
24
|
+
import numpy as np
|
|
25
|
+
import pandas as pd
|
|
26
|
+
import pyBigWig
|
|
27
|
+
from sklearn.linear_model import LogisticRegression
|
|
28
|
+
from sklearn.metrics import average_precision_score
|
|
29
|
+
|
|
30
|
+
sys.path.insert(0, os.environ.get("CRISOT", "/crisot"))
|
|
31
|
+
from crisot_modules import CRISOT # noqa: E402
|
|
32
|
+
from utils import load_pkl # noqa: E402
|
|
33
|
+
|
|
34
|
+
FA = os.environ.get("FA", "/ref/GRCh38.fa")
|
|
35
|
+
BW = os.environ.get("BW", "/ref/hek293t_dnase.bigWig")
|
|
36
|
+
DS = os.environ.get("DS", "/d")
|
|
37
|
+
INACT_CAP = int(os.environ.get("INACT_CAP", "4000")) # 4000/guide ~ realistic imbalance
|
|
38
|
+
COMP = str.maketrans("ACGT", "TGCA")
|
|
39
|
+
VALID = {f"chr{i}" for i in list(range(1, 23)) + ["X", "Y"]}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def rc(s: str) -> str:
|
|
43
|
+
return s.translate(COMP)[::-1]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def main() -> dict:
|
|
47
|
+
rng = np.random.RandomState(7)
|
|
48
|
+
pr, _ab, _bins, _w = load_pkl(os.environ.get("CRISOT", "/crisot") + "/models/crisot_score_param.pkl")
|
|
49
|
+
model = CRISOT(param=pr, ref_genome=os.environ.get("CRISOT", "/crisot") + "/script/hg38.na")
|
|
50
|
+
df = pd.read_csv(f"{DS}/guideseq.csv")
|
|
51
|
+
df["On20"] = df["On"].str[:20]
|
|
52
|
+
g = df.groupby("On20")["Active"].sum()
|
|
53
|
+
df = df[df["On20"].isin(list(g[g >= 5].index))].copy()
|
|
54
|
+
parts = []
|
|
55
|
+
for _gd, sub in df.groupby("On20"):
|
|
56
|
+
inact = sub[sub.Active == 0]
|
|
57
|
+
parts.append(pd.concat([sub[sub.Active == 1], inact.sample(n=min(INACT_CAP, len(inact)), random_state=rng)]))
|
|
58
|
+
d = pd.concat(parts).reset_index(drop=True)
|
|
59
|
+
d["crisot"] = model.score(data_df=d, On="On", Off="Off")
|
|
60
|
+
d["off23"] = d["Off"].str[:23]
|
|
61
|
+
pat = {}
|
|
62
|
+
for off in d["off23"].unique():
|
|
63
|
+
if len(off) == 23 and set(off) <= set("ACGT"):
|
|
64
|
+
pat[off] = off
|
|
65
|
+
pat[rc(off)] = off
|
|
66
|
+
open("/tmp/pats.txt", "w").write("\n".join(pat) + "\n")
|
|
67
|
+
hits: dict = {}
|
|
68
|
+
cur, buf = None, []
|
|
69
|
+
|
|
70
|
+
def flush(chrom, seq):
|
|
71
|
+
c = chrom if chrom and chrom.startswith("chr") else f"chr{chrom}"
|
|
72
|
+
if not seq or c not in VALID:
|
|
73
|
+
return
|
|
74
|
+
open("/tmp/chr.txt", "w").write(seq)
|
|
75
|
+
p = subprocess.run(["grep", "-boFf", "/tmp/pats.txt", "/tmp/chr.txt"], capture_output=True, text=True)
|
|
76
|
+
for ln in p.stdout.splitlines():
|
|
77
|
+
ob, _, m = ln.partition(":")
|
|
78
|
+
if pat.get(m):
|
|
79
|
+
hits.setdefault(pat[m], []).append((c, int(ob)))
|
|
80
|
+
with open(FA) as fh:
|
|
81
|
+
for line in fh:
|
|
82
|
+
if line.startswith(">"):
|
|
83
|
+
if cur:
|
|
84
|
+
flush(cur, "".join(buf))
|
|
85
|
+
cur, buf = line[1:].split()[0], []
|
|
86
|
+
else:
|
|
87
|
+
buf.append(line.strip().upper())
|
|
88
|
+
if cur:
|
|
89
|
+
flush(cur, "".join(buf))
|
|
90
|
+
bw = pyBigWig.open(BW)
|
|
91
|
+
bwc = set(bw.chroms().keys())
|
|
92
|
+
cache: dict = {}
|
|
93
|
+
|
|
94
|
+
def acc(off):
|
|
95
|
+
vals = []
|
|
96
|
+
for c, p in hits.get(off, []):
|
|
97
|
+
bc = c if c in bwc else (c[3:] if c[3:] in bwc else None)
|
|
98
|
+
if bc is None:
|
|
99
|
+
continue
|
|
100
|
+
b0 = (p // 1000) * 1000
|
|
101
|
+
if (bc, b0) not in cache:
|
|
102
|
+
try:
|
|
103
|
+
v = bw.stats(bc, b0, min(b0 + 1000, bw.chroms(bc)), type="mean")[0]
|
|
104
|
+
cache[(bc, b0)] = float(v) if v is not None else None
|
|
105
|
+
except Exception: # noqa: BLE001
|
|
106
|
+
cache[(bc, b0)] = None
|
|
107
|
+
if cache[(bc, b0)] is not None:
|
|
108
|
+
vals.append(cache[(bc, b0)])
|
|
109
|
+
return max(vals) if vals else None
|
|
110
|
+
d["acc"] = d["off23"].map(acc)
|
|
111
|
+
d = d.dropna(subset=["acc"]).reset_index(drop=True)
|
|
112
|
+
d["zc"] = (d.crisot - d.crisot.mean()) / d.crisot.std()
|
|
113
|
+
d["za"] = (d.acc - d.acc.mean()) / d.acc.std()
|
|
114
|
+
guides = sorted(d.On20.unique())
|
|
115
|
+
|
|
116
|
+
def fit(dd):
|
|
117
|
+
lr = LogisticRegression(max_iter=2000, class_weight="balanced").fit(dd[["zc", "za"]], dd.Active)
|
|
118
|
+
return lr.coef_[0], lr.intercept_[0]
|
|
119
|
+
(cc, ca), _b = fit(d)
|
|
120
|
+
accb = []
|
|
121
|
+
for _ in range(1000):
|
|
122
|
+
gs = rng.choice(guides, len(guides), replace=True)
|
|
123
|
+
try:
|
|
124
|
+
accb.append(fit(pd.concat([d[d.On20 == x] for x in gs]))[0][1])
|
|
125
|
+
except Exception: # noqa: BLE001
|
|
126
|
+
pass
|
|
127
|
+
acc_ci = [round(float(np.percentile(accb, 2.5)), 4), round(float(np.percentile(accb, 97.5)), 4)]
|
|
128
|
+
cris_ap, comb_ap = [], []
|
|
129
|
+
for held in guides:
|
|
130
|
+
tr, te = d[d.On20 != held], d[d.On20 == held]
|
|
131
|
+
if te.Active.sum() == 0 or len(te) < 5:
|
|
132
|
+
continue
|
|
133
|
+
lr = LogisticRegression(max_iter=2000, class_weight="balanced").fit(tr[["zc", "za"]], tr.Active)
|
|
134
|
+
comb_ap.append(average_precision_score(te.Active, lr.predict_proba(te[["zc", "za"]])[:, 1]))
|
|
135
|
+
cris_ap.append(average_precision_score(te.Active, te.zc.values))
|
|
136
|
+
gap = np.array(comb_ap) - np.array(cris_ap)
|
|
137
|
+
gb = [float(np.mean(gap[rng.randint(0, len(gap), len(gap))])) for _ in range(1000)]
|
|
138
|
+
out = {"n_offtargets": int(len(d)), "n_actives": int(d.Active.sum()), "n_guides": len(guides),
|
|
139
|
+
"conditional_acc_coef": round(float(ca), 4), "acc_coef_ci95": acc_ci,
|
|
140
|
+
"mean_crisot_only_auprc": round(float(np.mean(cris_ap)), 4),
|
|
141
|
+
"mean_crisot_plus_acc_auprc": round(float(np.mean(comb_ap)), 4),
|
|
142
|
+
"auprc_gap_ci95": [round(float(np.percentile(gb, 2.5)), 4), round(float(np.percentile(gb, 97.5)), 4)]}
|
|
143
|
+
print(json.dumps(out, indent=2))
|
|
144
|
+
return out
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
if __name__ == "__main__":
|
|
148
|
+
main()
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""Reproducible analysis (v6.10.3): the CELL-TYPE-MATCHED chromatin test that settled v6.10.2's ambiguous result.
|
|
2
|
+
|
|
3
|
+
Re-runs the accessibility-vs-off-target-activity AUROC with a cell-type-MATCHED ENCODE HEK293T DNase-seq track
|
|
4
|
+
(ENCFF529BOG) instead of the cross-cell K562 proxy. HEK293T matches GUIDE-seq (HEK293) and TTISS (HEK293T). Maps
|
|
5
|
+
off-targets to hg38 (grep -F, both strands), queries the HEK293T DNase signal at each off-target's 1 kb bin
|
|
6
|
+
(pyBigWig mean), AUROC of accessibility for active-vs-inactive off-targets per assay. Needs hg38 GRCh38.fa, the
|
|
7
|
+
HEK293T DNase bigWig, the harmonized assay CSVs, and pyBigWig.
|
|
8
|
+
|
|
9
|
+
RESULT (committed in benchmarks/offtarget/chromatin_validation.json, phase2): cell-type matching LIFTS the canonical
|
|
10
|
+
WT-Cas9 cell-based assay GUIDE-seq from AUROC 0.58 (cross-cell K562) to 0.671 (matched HEK293T, CI [0.642, 0.701]);
|
|
11
|
+
the in-vitro control stays null (0.494). VERDICT: VALIDATED (moderate, cell-type-matched). TTISS stays an outlier
|
|
12
|
+
(0.383) — it is a Cas9-VARIANT specificity assay, driven by variant fidelity rather than WT chromatin.
|
|
13
|
+
|
|
14
|
+
Usage (on the VM, container with pandas+numpy+pyBigWig):
|
|
15
|
+
FA=GRCh38.fa BW=hek293t_dnase.bigWig DS=datasets python offtarget_chromatin_matched.py
|
|
16
|
+
"""
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import collections
|
|
20
|
+
import json
|
|
21
|
+
import os
|
|
22
|
+
import subprocess
|
|
23
|
+
|
|
24
|
+
import numpy as np
|
|
25
|
+
import pandas as pd
|
|
26
|
+
import pyBigWig
|
|
27
|
+
|
|
28
|
+
FA = os.environ.get("FA", "/ref/GRCh38.fa")
|
|
29
|
+
BW = os.environ.get("BW", "/ref/hek293t_dnase.bigWig")
|
|
30
|
+
DS = os.environ.get("DS", "/d")
|
|
31
|
+
COMP = str.maketrans("ACGT", "TGCA")
|
|
32
|
+
# cell-based assays (matched by HEK293T) + one small in-vitro control; the big in-vitro sets are dropped for speed
|
|
33
|
+
ASSAYS = {"guideseq": "cell-based (WT Cas9)", "ttiss": "cell-based (Cas9 variants)", "siteseq": "in_vitro_control"}
|
|
34
|
+
VALID = {f"chr{i}" for i in list(range(1, 23)) + ["X", "Y"]}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def rc(s: str) -> str:
|
|
38
|
+
return s.translate(COMP)[::-1]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def auroc(y, s):
|
|
42
|
+
y = np.asarray(y)
|
|
43
|
+
s = np.asarray(s, float)
|
|
44
|
+
n1, n0 = int(y.sum()), int((1 - y).sum())
|
|
45
|
+
if n1 == 0 or n0 == 0:
|
|
46
|
+
return None
|
|
47
|
+
order = np.argsort(s)
|
|
48
|
+
ranks = np.empty(len(s))
|
|
49
|
+
ranks[order] = np.arange(1, len(s) + 1)
|
|
50
|
+
d = collections.defaultdict(list)
|
|
51
|
+
for i, v in enumerate(s):
|
|
52
|
+
d[v].append(i)
|
|
53
|
+
for _v, idxs in d.items():
|
|
54
|
+
rr = np.mean([ranks[i] for i in idxs])
|
|
55
|
+
for i in idxs:
|
|
56
|
+
ranks[i] = rr
|
|
57
|
+
return float((ranks[y == 1].sum() - n1 * (n1 + 1) / 2) / (n1 * n0))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def main() -> dict:
|
|
61
|
+
rng = np.random.RandomState(7)
|
|
62
|
+
bw = pyBigWig.open(BW)
|
|
63
|
+
bwchroms = set(bw.chroms().keys())
|
|
64
|
+
frames = []
|
|
65
|
+
for tag in ASSAYS:
|
|
66
|
+
df = pd.read_csv(f"{DS}/{tag}.csv")
|
|
67
|
+
df["assay"] = tag
|
|
68
|
+
inact = df[df["Active"] == 0]
|
|
69
|
+
frames.append(pd.concat([df[df["Active"] == 1], inact.sample(n=min(1500, len(inact)), random_state=rng)]))
|
|
70
|
+
sub = pd.concat(frames).reset_index(drop=True)
|
|
71
|
+
sub["off23"] = sub["Off"].str[:23]
|
|
72
|
+
pat_map = {}
|
|
73
|
+
for off in sub["off23"].unique():
|
|
74
|
+
if len(off) == 23 and set(off) <= set("ACGT"):
|
|
75
|
+
pat_map[off] = off
|
|
76
|
+
pat_map[rc(off)] = off
|
|
77
|
+
open("/tmp/pats.txt", "w").write("\n".join(pat_map) + "\n")
|
|
78
|
+
hits: dict = {}
|
|
79
|
+
cur, buf = None, []
|
|
80
|
+
|
|
81
|
+
def flush(chrom, seq):
|
|
82
|
+
c = chrom if chrom and chrom.startswith("chr") else f"chr{chrom}"
|
|
83
|
+
if not seq or c not in VALID:
|
|
84
|
+
return
|
|
85
|
+
open("/tmp/chr.txt", "w").write(seq)
|
|
86
|
+
p = subprocess.run(["grep", "-boFf", "/tmp/pats.txt", "/tmp/chr.txt"], capture_output=True, text=True)
|
|
87
|
+
for ln in p.stdout.splitlines():
|
|
88
|
+
off_b, _, matched = ln.partition(":")
|
|
89
|
+
fwd = pat_map.get(matched)
|
|
90
|
+
if fwd:
|
|
91
|
+
hits.setdefault(fwd, []).append((c, int(off_b)))
|
|
92
|
+
with open(FA) as fh:
|
|
93
|
+
for line in fh:
|
|
94
|
+
if line.startswith(">"):
|
|
95
|
+
if cur:
|
|
96
|
+
flush(cur, "".join(buf))
|
|
97
|
+
cur, buf = line[1:].split()[0], []
|
|
98
|
+
else:
|
|
99
|
+
buf.append(line.strip().upper())
|
|
100
|
+
if cur:
|
|
101
|
+
flush(cur, "".join(buf))
|
|
102
|
+
cache: dict = {}
|
|
103
|
+
|
|
104
|
+
def binsig(bc, b0):
|
|
105
|
+
if (bc, b0) not in cache:
|
|
106
|
+
try:
|
|
107
|
+
v = bw.stats(bc, b0, min(b0 + 1000, bw.chroms(bc)), type="mean")[0]
|
|
108
|
+
cache[(bc, b0)] = float(v) if v is not None else None
|
|
109
|
+
except Exception: # noqa: BLE001
|
|
110
|
+
cache[(bc, b0)] = None
|
|
111
|
+
return cache[(bc, b0)]
|
|
112
|
+
|
|
113
|
+
def acc(off):
|
|
114
|
+
vals = []
|
|
115
|
+
for c, p in hits.get(off, []):
|
|
116
|
+
bc = c if c in bwchroms else (c[3:] if c[3:] in bwchroms else None)
|
|
117
|
+
if bc is None:
|
|
118
|
+
continue
|
|
119
|
+
s = binsig(bc, (p // 1000) * 1000)
|
|
120
|
+
if s is not None:
|
|
121
|
+
vals.append(s)
|
|
122
|
+
return max(vals) if vals else None
|
|
123
|
+
sub["acc"] = sub["off23"].map(acc)
|
|
124
|
+
mp = sub.dropna(subset=["acc"])
|
|
125
|
+
out = {}
|
|
126
|
+
for tag in ASSAYS:
|
|
127
|
+
a = mp[mp["assay"] == tag]
|
|
128
|
+
out[tag] = {"modality": ASSAYS[tag], "auroc": round(auroc(a["Active"].values, a["acc"].values), 3),
|
|
129
|
+
"actives": int(a["Active"].sum()), "n": int(len(a))}
|
|
130
|
+
print(json.dumps(out, indent=2))
|
|
131
|
+
return out
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
if __name__ == "__main__":
|
|
135
|
+
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|