pen-stack 6.9.2__tar.gz → 6.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.
Files changed (498) hide show
  1. {pen_stack-6.9.2 → pen_stack-6.10.0}/CHANGELOG.md +33 -0
  2. {pen_stack-6.9.2 → pen_stack-6.10.0}/CITATION.cff +1 -1
  3. {pen_stack-6.9.2 → pen_stack-6.10.0}/PKG-INFO +23 -2
  4. {pen_stack-6.9.2 → pen_stack-6.10.0}/README.md +22 -1
  5. pen_stack-6.10.0/benchmarks/offtarget/SHA256SUMS +4 -0
  6. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/oracles/scope_cards.yaml +17 -0
  7. pen_stack-6.10.0/docs/cards/offtarget_data.md +52 -0
  8. pen_stack-6.10.0/docs/offtarget.md +45 -0
  9. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/__init__.py +1 -1
  10. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/agent/cite.py +13 -0
  11. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/agent/mcp_server.py +12 -0
  12. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/api/manifest.py +6 -0
  13. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/server/api.py +20 -0
  14. pen_stack-6.10.0/pen_stack/wgenome/offtarget_assay.py +55 -0
  15. pen_stack-6.10.0/pen_stack/wgenome/offtarget_data.py +100 -0
  16. pen_stack-6.10.0/pen_stack/wgenome/offtarget_predict.py +177 -0
  17. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack.egg-info/PKG-INFO +23 -2
  18. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack.egg-info/SOURCES.txt +8 -0
  19. pen_stack-6.10.0/prereg/SHA256_LOCK_ws_offtarget.json +8 -0
  20. pen_stack-6.10.0/prereg/ws_offtarget.yaml +42 -0
  21. {pen_stack-6.9.2 → pen_stack-6.10.0}/pyproject.toml +1 -1
  22. {pen_stack-6.9.2 → pen_stack-6.10.0}/LICENSE +0 -0
  23. {pen_stack-6.9.2 → pen_stack-6.10.0}/MANIFEST.in +0 -0
  24. {pen_stack-6.9.2 → pen_stack-6.10.0}/bench/run.py +0 -0
  25. {pen_stack-6.9.2 → pen_stack-6.10.0}/benchmarks/genome_writing_bench/LEADERBOARD.md +0 -0
  26. {pen_stack-6.9.2 → pen_stack-6.10.0}/benchmarks/genome_writing_bench/README.md +0 -0
  27. {pen_stack-6.9.2 → pen_stack-6.10.0}/benchmarks/genome_writing_bench/SHA256SUMS +0 -0
  28. {pen_stack-6.9.2 → pen_stack-6.10.0}/benchmarks/genome_writing_bench/SUBMISSIONS.md +0 -0
  29. {pen_stack-6.9.2 → pen_stack-6.10.0}/benchmarks/genome_writing_bench/tasks.yaml +0 -0
  30. {pen_stack-6.9.2 → pen_stack-6.10.0}/benchmarks/genome_writing_challenge/README.md +0 -0
  31. {pen_stack-6.9.2 → pen_stack-6.10.0}/benchmarks/genome_writing_challenge/SUBMISSIONS.md +0 -0
  32. {pen_stack-6.9.2 → pen_stack-6.10.0}/benchmarks/position_effect/README.md +0 -0
  33. {pen_stack-6.9.2 → pen_stack-6.10.0}/benchmarks/position_effect/SHA256SUMS +0 -0
  34. {pen_stack-6.9.2 → pen_stack-6.10.0}/benchmarks/writer_efficiency/README.md +0 -0
  35. {pen_stack-6.9.2 → pen_stack-6.10.0}/benchmarks/writer_efficiency/SHA256SUMS +0 -0
  36. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/antipeg.yaml +0 -0
  37. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/atlas_families.yaml +0 -0
  38. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/bridge_offtarget_profile.yaml +0 -0
  39. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/calibration/preexisting_nab_independent.yaml +0 -0
  40. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/capsid_epitope_oracle.yaml +0 -0
  41. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/capsid_sequences.fasta +0 -0
  42. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/cargo_polish.yaml +0 -0
  43. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/cell_types.yaml +0 -0
  44. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/datasets.yaml +0 -0
  45. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/delivery_constraints.yaml +0 -0
  46. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/delivery_rules.yaml +0 -0
  47. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/delivery_vehicles.yaml +0 -0
  48. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/expression/modifiers.yaml +0 -0
  49. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/expression/promoters.yaml +0 -0
  50. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/gates_v3.yaml +0 -0
  51. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/genotoxicity_oracle.yaml +0 -0
  52. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/gsh_validated_heldout.yaml +0 -0
  53. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/intent_weights.yaml +0 -0
  54. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/known_unknowns.yaml +0 -0
  55. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/llm.yaml +0 -0
  56. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/metric_guide.yaml +0 -0
  57. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/mhc_epitope_oracle.yaml +0 -0
  58. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/monitor_queries.yaml +0 -0
  59. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/oracles/execution.yaml +0 -0
  60. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/rules/delivery.yaml +0 -0
  61. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/rules/fold.yaml +0 -0
  62. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/rules/multiplex.yaml +0 -0
  63. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/rules/payload.yaml +0 -0
  64. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/rules/reachability.yaml +0 -0
  65. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/safety/hazard_registry.yaml +0 -0
  66. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/safety/policy.yaml +0 -0
  67. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/safety/probes.yaml +0 -0
  68. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/score_axes.yaml +0 -0
  69. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/seroprevalence.yaml +0 -0
  70. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/target_sites.yaml +0 -0
  71. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/universe_crosswalk.yaml +0 -0
  72. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/write_types.yaml +0 -0
  73. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/writer_sequences.fasta +0 -0
  74. {pen_stack-6.9.2 → pen_stack-6.10.0}/configs/wtkb_curated.yaml +0 -0
  75. {pen_stack-6.9.2 → pen_stack-6.10.0}/data/curated/bridge_offtarget_energetics.json +0 -0
  76. {pen_stack-6.9.2 → pen_stack-6.10.0}/data/curated/bridge_offtarget_profile_measured.parquet +0 -0
  77. {pen_stack-6.9.2 → pen_stack-6.10.0}/data/curated/gene_coords.parquet +0 -0
  78. {pen_stack-6.9.2 → pen_stack-6.10.0}/data/curated/unified_editor_universe.parquet +0 -0
  79. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/BACKLOG.md +0 -0
  80. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/DEPLOY.md +0 -0
  81. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/INFRA.md +0 -0
  82. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/MCP.md +0 -0
  83. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/RELEASING.md +0 -0
  84. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/REPRO.md +0 -0
  85. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/STABILITY.md +0 -0
  86. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/agent.md +0 -0
  87. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/alphagenome_feasibility.md +0 -0
  88. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/autonomy.md +0 -0
  89. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/benchmark_circularity.md +0 -0
  90. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/biosecurity.md +0 -0
  91. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/build_interface.md +0 -0
  92. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/cards/atlas.md +0 -0
  93. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/cards/durability.md +0 -0
  94. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/cards/position_effect_data.md +0 -0
  95. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/cards/safety.md +0 -0
  96. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/cards/writer_efficiency_data.md +0 -0
  97. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/challenge.md +0 -0
  98. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/closed_loop.md +0 -0
  99. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/co_scientist.md +0 -0
  100. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/co_scientist_loop.md +0 -0
  101. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/delivery.md +0 -0
  102. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/delivery_immunology.md +0 -0
  103. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/digital_twin.md +0 -0
  104. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/dissemination.md +0 -0
  105. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/environment.md +0 -0
  106. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/experiment_design.md +0 -0
  107. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/generative_design.md +0 -0
  108. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/immune_profiler.md +0 -0
  109. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/index.md +0 -0
  110. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/integrations.md +0 -0
  111. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/live_oracles.md +0 -0
  112. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/mechanistic_constraints.md +0 -0
  113. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/oracles.md +0 -0
  114. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/position_effect.md +0 -0
  115. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/positioning.md +0 -0
  116. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/private_data_formats.md +0 -0
  117. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/quickstart.md +0 -0
  118. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/responsible_use.md +0 -0
  119. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/rules.md +0 -0
  120. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/scope.md +0 -0
  121. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/scorecard.md +0 -0
  122. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/tpe_bench.md +0 -0
  123. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/tutorials/compare-families.md +0 -0
  124. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/tutorials/score-deliverability.md +0 -0
  125. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/tutorials/where-can-i-write.md +0 -0
  126. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/tutorials/which-writer-reaches-locus.md +0 -0
  127. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/uncertainty.md +0 -0
  128. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/verify.md +0 -0
  129. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/world_model.md +0 -0
  130. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/writer_efficiency.md +0 -0
  131. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/writer_verification.md +0 -0
  132. {pen_stack-6.9.2 → pen_stack-6.10.0}/docs/wtkb.md +0 -0
  133. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/_resources.py +0 -0
  134. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/active/__init__.py +0 -0
  135. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/active/acquire.py +0 -0
  136. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/active/design.py +0 -0
  137. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/active/validate.py +0 -0
  138. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/adapt/__init__.py +0 -0
  139. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/adapt/finetune.py +0 -0
  140. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/adapt/ingest.py +0 -0
  141. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/adapt/pipeline.py +0 -0
  142. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/adapt/recalibrate.py +0 -0
  143. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/adapt/report.py +0 -0
  144. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/agent/__init__.py +0 -0
  145. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/agent/co_scientist.py +0 -0
  146. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/agent/epistemic.py +0 -0
  147. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/agent/guardrails.py +0 -0
  148. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/agent/orchestrator.py +0 -0
  149. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/agent/orchestrator_live.py +0 -0
  150. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/agent/pen_agent.py +0 -0
  151. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/agent/scope.py +0 -0
  152. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/agent/tools.py +0 -0
  153. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/api/__init__.py +0 -0
  154. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/atlas/__init__.py +0 -0
  155. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/atlas/build_wtkb.py +0 -0
  156. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/atlas/crosslink.py +0 -0
  157. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/atlas/expand.py +0 -0
  158. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/atlas/guide_design.py +0 -0
  159. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/atlas/schema.py +0 -0
  160. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/atlas/scorecard.py +0 -0
  161. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/atlas/universe.py +0 -0
  162. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/atlas/variant_propose.py +0 -0
  163. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/atlas/writer_efficiency.py +0 -0
  164. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/atlas/writer_predict.py +0 -0
  165. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/atlas/writer_recommend.py +0 -0
  166. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/atlas/writer_verify.py +0 -0
  167. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/bridge/__init__.py +0 -0
  168. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/bridge/activity.py +0 -0
  169. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/bridge/cli.py +0 -0
  170. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/bridge/fold_qc.py +0 -0
  171. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/bridge/guide_qc.py +0 -0
  172. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/bridge/ingest.py +0 -0
  173. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/bridge/offtarget.py +0 -0
  174. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/bridge/offtarget_energetics.py +0 -0
  175. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/bridge/ortholog_screen.py +0 -0
  176. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/bridge/pipeline.py +0 -0
  177. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/build/__init__.py +0 -0
  178. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/build/ingest.py +0 -0
  179. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/build/protocol.py +0 -0
  180. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/build/simlab.py +0 -0
  181. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/cli.py +0 -0
  182. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/data/__init__.py +0 -0
  183. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/data/encode.py +0 -0
  184. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/data/genome.py +0 -0
  185. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/data/ingest_chromatin.py +0 -0
  186. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/data/ingest_integration.py +0 -0
  187. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/data/ingest_safety_annot.py +0 -0
  188. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/data/ingest_trip.py +0 -0
  189. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/design/__init__.py +0 -0
  190. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/design/generate.py +0 -0
  191. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/design/pareto.py +0 -0
  192. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/design/space.py +0 -0
  193. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/design/writer_variants.py +0 -0
  194. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/env/__init__.py +0 -0
  195. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/env/genome_writing_env.py +0 -0
  196. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/env/policies.py +0 -0
  197. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/graph/__init__.py +0 -0
  198. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/graph/build.py +0 -0
  199. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/graph/cell_types.py +0 -0
  200. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/graph/ingest.py +0 -0
  201. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/graph/query.py +0 -0
  202. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/graph/schema.py +0 -0
  203. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/loop/__init__.py +0 -0
  204. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/loop/continual.py +0 -0
  205. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/loop/cycle.py +0 -0
  206. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/loop/drift.py +0 -0
  207. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/mech/__init__.py +0 -0
  208. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/mech/classify_atlas.py +0 -0
  209. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/mech/whitelist.py +0 -0
  210. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/monitor/__init__.py +0 -0
  211. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/monitor/europepmc.py +0 -0
  212. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/monitor/run.py +0 -0
  213. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/monitor/triage.py +0 -0
  214. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/oracles/__init__.py +0 -0
  215. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/oracles/cache.py +0 -0
  216. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/oracles/energetics.py +0 -0
  217. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/oracles/genome.py +0 -0
  218. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/oracles/protein_design.py +0 -0
  219. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/oracles/rna.py +0 -0
  220. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/oracles/schema.py +0 -0
  221. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/oracles/status.py +0 -0
  222. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/oracles/structure.py +0 -0
  223. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/oracles/vcell.py +0 -0
  224. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/__init__.py +0 -0
  225. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/ada_risk.py +0 -0
  226. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/antipeg_oracle.py +0 -0
  227. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/capsid_epitope_oracle.py +0 -0
  228. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/cargo.py +0 -0
  229. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/cargo_polish.py +0 -0
  230. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/delivery.py +0 -0
  231. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/delivery_constraints.py +0 -0
  232. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/delivery_immunology.py +0 -0
  233. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/delivery_vehicles.py +0 -0
  234. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/genotoxicity_oracle.py +0 -0
  235. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/immune_mhc2.py +0 -0
  236. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/immune_profile.py +0 -0
  237. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/innate_sensing.py +0 -0
  238. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/multiplex.py +0 -0
  239. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/optimize.py +0 -0
  240. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/pipeline.py +0 -0
  241. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/report.py +0 -0
  242. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/router.py +0 -0
  243. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/seroprevalence_oracle.py +0 -0
  244. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/planner/target_site.py +0 -0
  245. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/rag/__init__.py +0 -0
  246. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/rag/index.py +0 -0
  247. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/rag/llm.py +0 -0
  248. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/rag/qa.py +0 -0
  249. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/rules/__init__.py +0 -0
  250. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/rules/evaluators.py +0 -0
  251. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/rules/loader.py +0 -0
  252. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/rules/schema.py +0 -0
  253. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/rules/solver.py +0 -0
  254. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/safety/__init__.py +0 -0
  255. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/safety/audit.py +0 -0
  256. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/safety/gate.py +0 -0
  257. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/safety/policy.py +0 -0
  258. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/safety/redteam.py +0 -0
  259. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/safety/registry.py +0 -0
  260. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/safety/screen.py +0 -0
  261. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/score/__init__.py +0 -0
  262. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/score/recalibrate.py +0 -0
  263. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/score/therapeutic.py +0 -0
  264. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/server/__init__.py +0 -0
  265. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/twin/__init__.py +0 -0
  266. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/twin/calibrate.py +0 -0
  267. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/twin/data/__init__.py +0 -0
  268. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/twin/data/position_effect.py +0 -0
  269. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/twin/mechanistic.py +0 -0
  270. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/twin/outcome.py +0 -0
  271. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/twin/position_effect.py +0 -0
  272. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/ui/__init__.py +0 -0
  273. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/ui/app.py +0 -0
  274. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/__init__.py +0 -0
  275. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/adapt_demo.py +0 -0
  276. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/agent_eval.py +0 -0
  277. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/bench_adversarial_tasks.py +0 -0
  278. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/bench_coscientist_tasks.py +0 -0
  279. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/bench_graph_tasks.py +0 -0
  280. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/bench_rule_tasks.py +0 -0
  281. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/bench_trust_tasks.py +0 -0
  282. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/bench_writetype_tasks.py +0 -0
  283. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/blind_gsh_discovery.py +0 -0
  284. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/cargo_directionality.py +0 -0
  285. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/closed_loop.py +0 -0
  286. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/durability_baselines.py +0 -0
  287. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/experiment_design.py +0 -0
  288. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/expr_controls.py +0 -0
  289. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/forward_hypotheses.py +0 -0
  290. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/generative_design.py +0 -0
  291. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/guide_qc_demo.py +0 -0
  292. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/heldout_celltype_expr.py +0 -0
  293. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/immune_calibration.py +0 -0
  294. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/intent_specification.py +0 -0
  295. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/known_biology_expr.py +0 -0
  296. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/offtarget_energetics_eval.py +0 -0
  297. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/out_of_scope_refusal.py +0 -0
  298. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/outcome_calibration.py +0 -0
  299. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/outcome_prediction.py +0 -0
  300. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/paper3_benchmark.py +0 -0
  301. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/paper4_real_validation.py +0 -0
  302. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/paper4_validation.py +0 -0
  303. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/protocol_safety.py +0 -0
  304. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/safety_screening.py +0 -0
  305. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/selective_prediction.py +0 -0
  306. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/seq_vs_measured.py +0 -0
  307. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/target_site_controls.py +0 -0
  308. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/uncertainty_eval.py +0 -0
  309. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/ungrounded_baseline.py +0 -0
  310. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/within_locus_ranking.py +0 -0
  311. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/validate/writer_recovery.py +0 -0
  312. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/verify/__init__.py +0 -0
  313. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/verify/schema.py +0 -0
  314. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/verify/service.py +0 -0
  315. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/web/__init__.py +0 -0
  316. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/web/guide.py +0 -0
  317. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/web/llm.py +0 -0
  318. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/web/router.py +0 -0
  319. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/web/server.py +0 -0
  320. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/web/tools.py +0 -0
  321. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/wgenome/__init__.py +0 -0
  322. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/wgenome/chromatin_seq.py +0 -0
  323. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/wgenome/durability.py +0 -0
  324. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/wgenome/export_tracks.py +0 -0
  325. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/wgenome/features.py +0 -0
  326. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/wgenome/gsh_baseline.py +0 -0
  327. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/wgenome/mesh_features.py +0 -0
  328. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/wgenome/ood.py +0 -0
  329. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/wgenome/providers.py +0 -0
  330. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/wgenome/safety.py +0 -0
  331. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/wgenome/structure3d.py +0 -0
  332. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/wgenome/uncertainty.py +0 -0
  333. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack/wgenome/writability.py +0 -0
  334. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack.egg-info/dependency_links.txt +0 -0
  335. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack.egg-info/entry_points.txt +0 -0
  336. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack.egg-info/requires.txt +0 -0
  337. {pen_stack-6.9.2 → pen_stack-6.10.0}/pen_stack.egg-info/top_level.txt +0 -0
  338. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_phase0.json +0 -0
  339. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_phase1_5.json +0 -0
  340. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_phase2.json +0 -0
  341. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_phase3.json +0 -0
  342. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_a.json +0 -0
  343. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_acq.json +0 -0
  344. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_aldesign.json +0 -0
  345. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_alvalidate.json +0 -0
  346. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_atlas.json +0 -0
  347. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_b.json +0 -0
  348. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_ba.json +0 -0
  349. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_ba_v33.json +0 -0
  350. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_ba_v45.json +0 -0
  351. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_bench.json +0 -0
  352. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_c.json +0 -0
  353. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_cal.json +0 -0
  354. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_calib.json +0 -0
  355. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_challenge.json +0 -0
  356. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_chat.json +0 -0
  357. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_cite.json +0 -0
  358. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_continual.json +0 -0
  359. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_cosci2.json +0 -0
  360. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_crit.json +0 -0
  361. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_ct.json +0 -0
  362. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_d.json +0 -0
  363. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_drift.json +0 -0
  364. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_e.json +0 -0
  365. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_env.json +0 -0
  366. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_ep.json +0 -0
  367. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_epitope.json +0 -0
  368. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_expr2.json +0 -0
  369. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_f.json +0 -0
  370. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_frontend.json +0 -0
  371. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_g.json +0 -0
  372. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_gen.json +0 -0
  373. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_genotox.json +0 -0
  374. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_graph.json +0 -0
  375. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_h.json +0 -0
  376. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_hybrid.json +0 -0
  377. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_immune.json +0 -0
  378. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_immune2.json +0 -0
  379. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_ingest.json +0 -0
  380. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_innate.json +0 -0
  381. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_loop.json +0 -0
  382. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_manifest.json +0 -0
  383. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_mc.json +0 -0
  384. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_mcp.json +0 -0
  385. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_mech.json +0 -0
  386. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_mon.json +0 -0
  387. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_o.json +0 -0
  388. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_openapi.json +0 -0
  389. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_orch.json +0 -0
  390. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_outcome.json +0 -0
  391. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_pareto.json +0 -0
  392. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_peg.json +0 -0
  393. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_plan.json +0 -0
  394. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_policy.json +0 -0
  395. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_profile.json +0 -0
  396. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_proto.json +0 -0
  397. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_r.json +0 -0
  398. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_redteam.json +0 -0
  399. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_route.json +0 -0
  400. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_screen.json +0 -0
  401. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_seroprev.json +0 -0
  402. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_simlab.json +0 -0
  403. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_twincal.json +0 -0
  404. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_uq.json +0 -0
  405. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_v.json +0 -0
  406. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_vcell.json +0 -0
  407. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_writer.json +0 -0
  408. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/SHA256_LOCK_ws_wv.json +0 -0
  409. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/paper1.yaml +0 -0
  410. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/paper2.yaml +0 -0
  411. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/paper3.yaml +0 -0
  412. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/paper4.yaml +0 -0
  413. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/phase0.yaml +0 -0
  414. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_a.yaml +0 -0
  415. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_acq.yaml +0 -0
  416. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_aldesign.yaml +0 -0
  417. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_alvalidate.yaml +0 -0
  418. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_atlas.yaml +0 -0
  419. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_b.yaml +0 -0
  420. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_ba.yaml +0 -0
  421. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_ba_v33.yaml +0 -0
  422. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_ba_v45.yaml +0 -0
  423. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_bench.yaml +0 -0
  424. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_c.yaml +0 -0
  425. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_cal.yaml +0 -0
  426. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_calib.yaml +0 -0
  427. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_challenge.yaml +0 -0
  428. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_chat.yaml +0 -0
  429. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_cite.yaml +0 -0
  430. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_continual.yaml +0 -0
  431. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_cosci2.yaml +0 -0
  432. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_crit.yaml +0 -0
  433. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_ct.yaml +0 -0
  434. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_d.yaml +0 -0
  435. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_drift.yaml +0 -0
  436. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_e.yaml +0 -0
  437. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_env.yaml +0 -0
  438. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_ep.yaml +0 -0
  439. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_epitope.yaml +0 -0
  440. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_expr2.yaml +0 -0
  441. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_f.yaml +0 -0
  442. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_frontend.yaml +0 -0
  443. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_g.yaml +0 -0
  444. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_gen.yaml +0 -0
  445. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_genotox.yaml +0 -0
  446. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_graph.yaml +0 -0
  447. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_h.yaml +0 -0
  448. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_hybrid.yaml +0 -0
  449. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_immune.yaml +0 -0
  450. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_immune2.yaml +0 -0
  451. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_ingest.yaml +0 -0
  452. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_innate.yaml +0 -0
  453. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_loop.yaml +0 -0
  454. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_manifest.yaml +0 -0
  455. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_mc.yaml +0 -0
  456. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_mcp.yaml +0 -0
  457. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_mech.yaml +0 -0
  458. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_mon.yaml +0 -0
  459. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_o.yaml +0 -0
  460. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_openapi.yaml +0 -0
  461. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_orch.yaml +0 -0
  462. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_outcome.yaml +0 -0
  463. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_pareto.yaml +0 -0
  464. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_peg.yaml +0 -0
  465. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_plan.yaml +0 -0
  466. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_policy.yaml +0 -0
  467. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_profile.yaml +0 -0
  468. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_proto.yaml +0 -0
  469. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_r.yaml +0 -0
  470. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_redteam.yaml +0 -0
  471. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_route.yaml +0 -0
  472. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_screen.yaml +0 -0
  473. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_seroprev.yaml +0 -0
  474. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_simlab.yaml +0 -0
  475. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_twincal.yaml +0 -0
  476. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_uq.yaml +0 -0
  477. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_v.yaml +0 -0
  478. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_vcell.yaml +0 -0
  479. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_writer.yaml +0 -0
  480. {pen_stack-6.9.2 → pen_stack-6.10.0}/prereg/ws_wv.yaml +0 -0
  481. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/calibrate_immune_axes.py +0 -0
  482. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/fetch_licensed_sources.py +0 -0
  483. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/p1_build_atlas.py +0 -0
  484. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/p1_build_durability.py +0 -0
  485. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/p1_build_position_effect.py +0 -0
  486. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/p1_build_writer_eff.py +0 -0
  487. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/p1_export_tracks.py +0 -0
  488. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/p1_safety_concordance.py +0 -0
  489. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/p1_train_safety.py +0 -0
  490. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/p1_validation_report.py +0 -0
  491. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/p2_build_atlas.py +0 -0
  492. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/p3_benchmark_report.py +0 -0
  493. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/p4_genome_scan.py +0 -0
  494. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/p52_build_genotox_oracle.py +0 -0
  495. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/p53_build_epitope_oracle.py +0 -0
  496. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/ws_b_report.py +0 -0
  497. {pen_stack-6.9.2 → pen_stack-6.10.0}/scripts/ws_c_report.py +0 -0
  498. {pen_stack-6.9.2 → pen_stack-6.10.0}/setup.cfg +0 -0
@@ -3,6 +3,39 @@
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.0] - 2026-06-20 - WS-OFFTARGET (PEN-OFFTGT: cross-writer-family off-target nomination)
7
+
8
+ **Series III, Stage E.** Off-target moves from a single-family bridge pseudosite scan to a **cross-writer-family,
9
+ chromatin-aware NOMINATION engine** grounded in unbiased genome-wide assays — completing the safety triad
10
+ (site B + writer C + off-target E). Nomination is scrupulously framed as **not a clearance**: every candidate
11
+ ships with the empirical assay that would confirm it.
12
+
13
+ ### Added
14
+ - **Off-Target-Bench** (`benchmarks/offtarget/`) — a real, leakage-controlled nomination benchmark over canonical
15
+ Cas9 guides (EMX1/VEGFA1-3/FANCF/HEK293) with **experimentally validated off-targets** from GUIDE-seq
16
+ (Tsai 2015, `10.1038/nbt.3117`) and CIRCLE-seq (Tsai 2017, `10.1038/nmeth.4278`). Held-out-guide split, per-assay
17
+ provenance, SHA256SUMS. **Gate E-G2 PASSES on real data + real tool:** the licensed **CRISOT-Score** predictor
18
+ (Chen et al., Nat Commun 2023, `10.1038/s41467-023-42695-4`; XGBoost RNA-DNA fingerprint) BEATS the sequence-
19
+ homology baseline — GUIDE-seq AUPRC **0.646 vs 0.467** (gap +0.179, CI [0.015, 0.340]); CIRCLE-seq **0.520 vs
20
+ 0.266** (gap +0.253, CI [0.140, 0.361]); per-guide bootstrap CI excludes 0 on both assays.
21
+ - `pen_stack/wgenome/offtarget_data.py` — validated assay/predictor provenance, a GROUNDED mismatch→active-fraction
22
+ risk calibration (real-data: GUIDE-seq 0-1mm→100% active, 2mm→76%, 3mm→23%, 4mm→3.3%), the bench fixture loader.
23
+ - `pen_stack/wgenome/offtarget_predict.py` — `nominate_offtargets(writer_family, ...)`: **nuclease** (mismatch-
24
+ calibrated risk band + the real cached CRISOT score + a documented chromatin modifier, Lazzarotto 2020);
25
+ **serine integrase** (cryptic **pseudo-attB** scan on the real documented Bxb1 attB core GCGGTCTC/GT);
26
+ **bridge** (delegates to the existing Perry-DMS pseudosite engine). Abstains without inputs; never fabricates sites.
27
+ - `pen_stack/wgenome/offtarget_assay.py` — validation-assay recommender (GUIDE/CHANGE/CIRCLE-seq for nucleases;
28
+ Cryptic-seq/HIDE-seq for integrases; **honest gap** for bridge recombinases — NO published genome-wide unbiased
29
+ off-target assay or predictor exists, verified).
30
+ - **Surfaces:** REST `POST /offtarget` + `GET /offtarget/assay`, MCP `offtarget_scan`, manifest `nominate_offtargets`
31
+ (fabricates=False), an `offtarget_nomination` scope card, and a web **Off-Target** page.
32
+
33
+ ### Honest limits
34
+ - Nomination is NOT a clearance; genome-wide candidate ENUMERATION needs the on-VM Cas-OFFinder/genome scan (this
35
+ engine SCORES + RANKS + risk-bands supplied candidates). The CRISOT predictor is CC-BY-NC — it runs only on the
36
+ VM and its weights are NEVER redistributed; only derived scores are cached (CI-safe). Bridge/integrase off-target
37
+ is data-thin/unmodeled and is flagged extrapolative; IntQuery (Tome Biosciences) is a paper-only reference.
38
+
6
39
  ## [6.9.2] - 2026-06-19 - WS-IMMUNE2 real-tool rigor pass (no proxies / no heuristics across the immune + writer axes)
7
40
 
8
41
  **PATCH — a top-to-bottom audit replacing every remaining proxy/heuristic in the immune & writer-design stack with
@@ -1,7 +1,7 @@
1
1
  cff-version: 1.2.0
2
2
  message: "If you use PEN-STACK, please cite it as below."
3
3
  title: "PEN-STACK: open infrastructure for genome writing"
4
- version: 6.9.2
4
+ version: 6.10.0
5
5
  date-released: 2026-06-20
6
6
  authors:
7
7
  - family-names: "Mahaboob Ali"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pen-stack
3
- Version: 6.9.2
3
+ Version: 6.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,7 +90,7 @@ every design against rule-grounded mechanism, reports calibrated confidence, cit
90
90
  [![codecov](https://codecov.io/gh/ahmedanees-m/pen-stack/branch/main/graph/badge.svg)](https://codecov.io/gh/ahmedanees-m/pen-stack)
91
91
  [![License: MIT](https://img.shields.io/badge/License-MIT-informational.svg)](LICENSE)
92
92
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
93
- [![Version](https://img.shields.io/badge/version-6.9.2-blue.svg)](CHANGELOG.md)
93
+ [![Version](https://img.shields.io/badge/version-6.10.0-blue.svg)](CHANGELOG.md)
94
94
  [![Status](https://img.shields.io/badge/status-1.0%20First%20Stable-success.svg)](docs/STABILITY.md)
95
95
  [![Tests](https://img.shields.io/badge/tests-378%20passing-success.svg)](tests/)
96
96
  [![Lint: ruff](https://img.shields.io/badge/lint-ruff-purple.svg)](https://github.com/astral-sh/ruff)
@@ -148,6 +148,27 @@ demonstrated (v5.12) and the benchmark went public (v5.13).
148
148
  > unknown funnel remains — made legible (scope flags, known-unknowns, honest baselines, no fabrication), not
149
149
  > hidden.
150
150
 
151
+ ## What is new in v6.10 — PEN-OFFTGT (cross-writer-family off-target nomination)
152
+
153
+ Off-target prediction was a single-family bridge pseudosite scan that abstained for nucleases and integrases.
154
+ v6.10 makes it a **cross-writer-family, chromatin-aware NOMINATION engine** — completing the safety triad
155
+ (site + writer + off-target). It is scrupulously honest that **nomination is not a clearance**: every candidate
156
+ ships with the empirical assay that would confirm it.
157
+
158
+ - **A real, validated benchmark** (`benchmarks/offtarget/`) over canonical Cas9 guides with **experimentally
159
+ validated off-targets** from GUIDE-seq (Tsai 2015) and CIRCLE-seq (Tsai 2017). The licensed **CRISOT** predictor
160
+ (Chen et al. *Nat Commun* 2023) **beats the sequence-homology baseline** on held-out guides — GUIDE-seq AUPRC
161
+ **0.65 vs 0.47**, CIRCLE-seq **0.52 vs 0.27**; per-guide bootstrap CI excludes 0 on both. CRISOT is CC-BY-NC and
162
+ runs only on the VM — only derived scores are cached (like the licensed MHC tools).
163
+ - **Grounded, calibrated risk** — the risk band IS the real-data fraction of candidates at *k* mismatches that were
164
+ experimentally validated-active (GUIDE-seq: 0–1 mm → 100%, 2 mm → 76%, 3 mm → 23%, 4 mm → 3.3%), not a guessed curve.
165
+ - **Cross-family** — nucleases (mismatch-calibrated risk + the real CRISOT score), serine integrases (cryptic
166
+ **pseudo-attB** scan on the real documented Bxb1 attB core), bridge recombinases (the existing Perry-DMS engine).
167
+ Bridge/integrase off-target is **honestly flagged data-thin** — there is no published genome-wide unbiased assay
168
+ or predictor for bridge recombinases (verified).
169
+ - **Surfaces** — REST `POST /offtarget`, MCP `offtarget_scan`, manifest `nominate_offtargets`, and an Off-Target
170
+ web page. Abstains without inputs; never fabricates sites.
171
+
151
172
  ## What is new in v6.9 — PEN-IMMUNE (MHC-II/CD4 + ADA + the writer enzyme as a distinct antigen)
152
173
 
153
174
  The immune profile did **CD8/MHC-I only** (capsid epitope load via MHCflurry) — but the **dominant** immunogenicity
@@ -15,7 +15,7 @@ every design against rule-grounded mechanism, reports calibrated confidence, cit
15
15
  [![codecov](https://codecov.io/gh/ahmedanees-m/pen-stack/branch/main/graph/badge.svg)](https://codecov.io/gh/ahmedanees-m/pen-stack)
16
16
  [![License: MIT](https://img.shields.io/badge/License-MIT-informational.svg)](LICENSE)
17
17
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
18
- [![Version](https://img.shields.io/badge/version-6.9.2-blue.svg)](CHANGELOG.md)
18
+ [![Version](https://img.shields.io/badge/version-6.10.0-blue.svg)](CHANGELOG.md)
19
19
  [![Status](https://img.shields.io/badge/status-1.0%20First%20Stable-success.svg)](docs/STABILITY.md)
20
20
  [![Tests](https://img.shields.io/badge/tests-378%20passing-success.svg)](tests/)
21
21
  [![Lint: ruff](https://img.shields.io/badge/lint-ruff-purple.svg)](https://github.com/astral-sh/ruff)
@@ -73,6 +73,27 @@ demonstrated (v5.12) and the benchmark went public (v5.13).
73
73
  > unknown funnel remains — made legible (scope flags, known-unknowns, honest baselines, no fabrication), not
74
74
  > hidden.
75
75
 
76
+ ## What is new in v6.10 — PEN-OFFTGT (cross-writer-family off-target nomination)
77
+
78
+ Off-target prediction was a single-family bridge pseudosite scan that abstained for nucleases and integrases.
79
+ v6.10 makes it a **cross-writer-family, chromatin-aware NOMINATION engine** — completing the safety triad
80
+ (site + writer + off-target). It is scrupulously honest that **nomination is not a clearance**: every candidate
81
+ ships with the empirical assay that would confirm it.
82
+
83
+ - **A real, validated benchmark** (`benchmarks/offtarget/`) over canonical Cas9 guides with **experimentally
84
+ validated off-targets** from GUIDE-seq (Tsai 2015) and CIRCLE-seq (Tsai 2017). The licensed **CRISOT** predictor
85
+ (Chen et al. *Nat Commun* 2023) **beats the sequence-homology baseline** on held-out guides — GUIDE-seq AUPRC
86
+ **0.65 vs 0.47**, CIRCLE-seq **0.52 vs 0.27**; per-guide bootstrap CI excludes 0 on both. CRISOT is CC-BY-NC and
87
+ runs only on the VM — only derived scores are cached (like the licensed MHC tools).
88
+ - **Grounded, calibrated risk** — the risk band IS the real-data fraction of candidates at *k* mismatches that were
89
+ experimentally validated-active (GUIDE-seq: 0–1 mm → 100%, 2 mm → 76%, 3 mm → 23%, 4 mm → 3.3%), not a guessed curve.
90
+ - **Cross-family** — nucleases (mismatch-calibrated risk + the real CRISOT score), serine integrases (cryptic
91
+ **pseudo-attB** scan on the real documented Bxb1 attB core), bridge recombinases (the existing Perry-DMS engine).
92
+ Bridge/integrase off-target is **honestly flagged data-thin** — there is no published genome-wide unbiased assay
93
+ or predictor for bridge recombinases (verified).
94
+ - **Surfaces** — REST `POST /offtarget`, MCP `offtarget_scan`, manifest `nominate_offtargets`, and an Off-Target
95
+ web page. Abstains without inputs; never fabricates sites.
96
+
76
97
  ## What is new in v6.9 — PEN-IMMUNE (MHC-II/CD4 + ADA + the writer enzyme as a distinct antigen)
77
98
 
78
99
  The immune profile did **CD8/MHC-I only** (capsid epitope load via MHCflurry) — but the **dominant** immunogenicity
@@ -0,0 +1,4 @@
1
+ 9a02d9fc0fb4fe305fc87510114df892027ac85f24a495bddccaf1c29e8decf7 split.json
2
+ 006642247dbb3dfe5ebefd0a9f0144e9e9d26b682e7b9173d13e2c4e1252bec8 offtarget_bench_fixture.csv
3
+ 6ec099c0d30f83bd09f7182c4f365ee7b1106e45f4ca80db46f4fdb0df2941ba offtarget_bench_metrics.json
4
+ 626d383ab3a494d6899c1620fa7cb2e6626c055410c1fd57e6b7d57d308523f4 offtarget_calibration.json
@@ -139,6 +139,23 @@ oracles:
139
139
  generalizes_to_unseen_loci: false
140
140
  license: "open (this work; MHCflurry 10.1016/j.cels.2020.06.010, HLA-I supertypes 10.1186/1471-2172-9-1)"
141
141
 
142
+ offtarget_nomination: # v6.10 WS-OFFTARGET: cross-family off-target NOMINATION (not clearance)
143
+ family: genome
144
+ version: "crisot+homology-2026"
145
+ output_kind: baseline # ranks/risk-bands CANDIDATE sites, not generative
146
+ valid_for: "RELATIVE off-target NOMINATION for a writer: rank candidate sites so validated off-targets
147
+ surface first, with a mismatch-CALIBRATED empirical risk band (real GUIDE-seq/CIRCLE-seq active fractions).
148
+ Nucleases use the real CRISOT-Score (beats a homology baseline on held-out guides, CI excludes 0); serine
149
+ integrases use a documented pseudo-attB cryptic scan; bridge recombinases delegate to the Perry-DMS engine"
150
+ not_valid_for: "a safety CLEARANCE (nomination != validation; every result ships with the empirical assay
151
+ that would confirm it); genome-wide candidate ENUMERATION (needs the on-VM Cas-OFFinder/genome scan; this
152
+ engine SCORES supplied candidates); a per-site cleavage/recombination PROBABILITY; bridge-recombinase
153
+ off-target magnitude (NO published genome-wide unbiased assay/predictor exists -> extrapolative/abstains);
154
+ structural variants/translocations beyond nominated sites"
155
+ generalizes_to_unseen_loci: false
156
+ license: "open (this work; GUIDE-seq 10.1038/nbt.3117, CIRCLE-seq 10.1038/nmeth.4278, CHANGE-seq
157
+ 10.1038/s41587-020-0555-7, CRISOT 10.1038/s41467-023-42695-4 CC-BY-NC run on the VM only)"
158
+
142
159
  innate_sensing: # v5.4 WS-INNATE: computed nucleic-acid innate-sensing motif load
143
160
  family: genome
144
161
  version: "cpg-oe+dsrna-2026"
@@ -0,0 +1,52 @@
1
+ # Data card — Off-Target-Bench (v6.10 PEN-OFFTGT)
2
+
3
+ ## Summary
4
+ A real, leakage-controlled benchmark for cross-writer-family off-target **nomination**: given a guide and its
5
+ candidate sites, rank the candidates so the experimentally validated off-targets surface first. Labels are the
6
+ wet-lab assay calls (NON-circular — the label is the experiment, not a predictor).
7
+
8
+ ## Ground truth (independently verified 2026-06-19)
9
+ | Assay | Setting | Citation | DOI |
10
+ |---|---|---|---|
11
+ | GUIDE-seq | cell-based, unbiased, genome-wide | Tsai et al., *Nat Biotechnol* 2015 | `10.1038/nbt.3117` |
12
+ | CIRCLE-seq | in vitro (cell-free), unbiased | Tsai et al., *Nat Methods* 2017 | `10.1038/nmeth.4278` |
13
+
14
+ Canonical Cas9 guides: **EMX1, VEGFA site 1/2/3, FANCF, HEK293 site 2/3/4**. The harmonized candidate/label tables
15
+ are sourced from the CRISOT data release (Zenodo `10.5281/zenodo.8420032`), which redistributes the public assay
16
+ supplements; PEN-STACK cites the **original assay papers** as the ground-truth provenance.
17
+
18
+ ## Learned predictor (real tool, VM-only)
19
+ **CRISOT-Score** — Chen et al., *Nat Commun* 2023, `10.1038/s41467-023-42695-4`; an XGBoost RNA-DNA interaction
20
+ fingerprint. **License: CC-BY-NC** → it runs only on the VM (`crisot:tools` Docker, `xgboost`/`pandas`/`numpy`);
21
+ its weights are NEVER redistributed. Only DERIVED scores are cached/committed (CI-safe), exactly like the licensed
22
+ NetMHC tools.
23
+
24
+ ## Baseline (pre-registered)
25
+ Sequence-homology nomination = ascending **mismatch count** (Hamming over the 20-nt protospacer).
26
+
27
+ ## Result (E-G2, full real data, on the VM)
28
+ | Assay | CRISOT AUPRC | homology AUPRC | gap | 95% CI (held-out-guide bootstrap) | beats homology |
29
+ |---|---|---|---|---|---|
30
+ | GUIDE-seq | 0.646 | 0.467 | +0.179 | [0.015, 0.340] | ✅ |
31
+ | CIRCLE-seq | 0.520 | 0.266 | +0.253 | [0.140, 0.361] | ✅ |
32
+
33
+ The learned predictor beats the homology baseline on both assays (per-guide bootstrap CI excludes 0).
34
+
35
+ ## Risk calibration (grounded)
36
+ The nomination risk band IS the empirical fraction of candidates at *k* mismatches that were validated-active
37
+ (full real data): GUIDE-seq 0–1 mm → 1.00, 2 mm → 0.765, 3 mm → 0.231, 4 mm → 0.033, 5 mm → 0.0028, 6 mm → 0.00014.
38
+ Mismatch counts outside the calibrated range abstain rather than extrapolate.
39
+
40
+ ## Files
41
+ - `benchmarks/offtarget/offtarget_bench_fixture.csv` — real validated off-targets + cached CRISOT scores (CI-safe;
42
+ inactives downsampled with a fixed seed for a small committed file).
43
+ - `benchmarks/offtarget/offtarget_bench_metrics.json` — the AUTHORITATIVE full-data metrics.
44
+ - `benchmarks/offtarget/offtarget_calibration.json` — the full-data mismatch / CRISOT-decile calibration.
45
+ - `benchmarks/offtarget/split.json`, `SHA256SUMS` — split definition + checksums.
46
+
47
+ ## Honest limits
48
+ Nomination is **not** a clearance — every result ships with the empirical assay that would confirm it. Genome-wide
49
+ candidate ENUMERATION needs the on-VM Cas-OFFinder/genome scan; this benchmark covers SCORING + RANKING of supplied
50
+ candidates. Bridge/integrase off-target is data-thin: there is **no published genome-wide unbiased off-target assay
51
+ or predictor for bridge recombinases** (verified), and the large-serine-integrase assays (Cryptic-seq/HIDE-seq) and
52
+ predictor (IntQuery) are recent single-company preprints with no public weights.
@@ -0,0 +1,45 @@
1
+ # Stage E — the off-target nomination engine (v6.10 PEN-OFFTGT)
2
+
3
+ Stage E completes the **safety triad** — site (Stage B) + writer (Stage C) + **off-target** (Stage E) — by turning
4
+ off-target from a single-family bridge pseudosite scan into a **cross-writer-family, chromatin-aware NOMINATION
5
+ engine** with a real-data-calibrated risk band. The cardinal honesty invariant: **nomination is not a clearance.**
6
+ A nominated off-target is a candidate, and every result ships with the empirical assay that would confirm it.
7
+
8
+ ## The engine (`pen_stack/wgenome/offtarget_predict.py`)
9
+
10
+ `nominate_offtargets(writer_family, ...)` dispatches by writer family:
11
+
12
+ - **Nuclease (Cas9):** given a guide + candidate sites (e.g. from a Cas-OFFinder scan), each candidate gets a
13
+ **mismatch-calibrated empirical risk** (the real GUIDE-seq/CIRCLE-seq active fraction at *k* mismatches — not a
14
+ guessed curve), the **real CRISOT-Score** when the (guide, site) is in the cached bench, and a documented
15
+ **chromatin modifier** (open chromatin raises realized off-target activity; Lazzarotto 2020, CHANGE-seq).
16
+ - **Serine integrase (Bxb1):** a cryptic **pseudo-attB** scan that seeds on the *real documented* Bxb1 attB core
17
+ (`GCGGTCTC`, central GT; FlyBase FBto0000359, Ghosh 2003) and reports candidate cryptic sites by arm mismatches.
18
+ - **Bridge recombinase:** delegates to the existing Perry-DMS pseudosite engine (`pen_stack.bridge.offtarget`).
19
+
20
+ The engine **abstains without inputs** (no candidate sites → no fabricated sites) and is explicit that genome-wide
21
+ candidate ENUMERATION needs the on-VM scan; this engine SCORES + RANKS + risk-bands supplied candidates.
22
+
23
+ ## The benchmark (E-G2, real data + real tool)
24
+
25
+ `benchmarks/offtarget/` is a held-out-guide nomination benchmark over canonical Cas9 guides with **experimentally
26
+ validated off-targets** (GUIDE-seq, CIRCLE-seq). The licensed **CRISOT** predictor (CC-BY-NC, run on the VM) beats
27
+ the sequence-homology baseline on both assays — GUIDE-seq AUPRC **0.65 vs 0.47**, CIRCLE-seq **0.52 vs 0.27**, with
28
+ the per-guide bootstrap CI on the gap excluding 0. Only derived CRISOT scores are cached/committed; the weights are
29
+ never redistributed. See `docs/cards/offtarget_data.md` for full provenance.
30
+
31
+ ## Validation-assay recommendation (`pen_stack/wgenome/offtarget_assay.py`)
32
+
33
+ `recommend_assay(writer_family)` maps a writer to the empirical assay(s) that would confirm a nomination —
34
+ GUIDE/CHANGE/CIRCLE-seq for nucleases, Cryptic-seq/HIDE-seq for serine integrases — and is **honest about the gap**
35
+ for bridge recombinases: there is no published genome-wide unbiased off-target assay or predictor for them, so their
36
+ nominations are flagged extrapolative and routed to targeted confirmation, never read as a clearance.
37
+
38
+ ## Surfaces
39
+ REST `POST /offtarget` + `GET /offtarget/assay`, MCP `offtarget_scan`, manifest tool `nominate_offtargets`
40
+ (`fabricates: false`), the `offtarget_nomination` scope card, and the **Off-Target** web page.
41
+
42
+ ## Honest limits
43
+ Nomination ≠ validation. Bridge/integrase off-target is data-thin/unmodeled (verified) and flagged extrapolative.
44
+ Chromatin-awareness depends on target-cell-type data. Translocations/structural variants beyond nominated sites are
45
+ out of scope. The CRISOT learned predictor is CC-BY-NC and runs only on the VM; PEN-STACK ships only derived scores.
@@ -1,2 +1,2 @@
1
1
  """PEN-STACK v3.0 - open infrastructure for genome writing."""
2
- __version__ = "6.9.2"
2
+ __version__ = "6.10.0"
@@ -39,6 +39,19 @@ def curated_dois() -> frozenset[str]:
39
39
  # v5.4 computed innate-sensing provenance (CpG-TLR9 / AAV CpG-depletion / RNA modification)
40
40
  from pen_stack.planner.innate_sensing import PROVENANCE_DOIS as _innate_dois
41
41
  dois.update(_innate_dois)
42
+ # v6.10 off-target nomination provenance (GUIDE/CIRCLE/CHANGE/SITE-seq assays + CRISOT predictor + LSI assays)
43
+ try:
44
+ from pen_stack.wgenome.offtarget_data import (
45
+ ASSAY_PROVENANCE,
46
+ INTEGRASE_ASSAY_PROVENANCE,
47
+ PREDICTOR_PROVENANCE,
48
+ )
49
+ for _src in (ASSAY_PROVENANCE, PREDICTOR_PROVENANCE, INTEGRASE_ASSAY_PROVENANCE):
50
+ for _rec in _src.values():
51
+ if _rec.get("doi"):
52
+ dois.add(_rec["doi"])
53
+ except Exception: # noqa: BLE001
54
+ pass
42
55
  # v5.5 anti-vector seroprevalence provenance (serosurveys)
43
56
  try:
44
57
  sp = yaml.safe_load(resource("configs/seroprevalence.yaml").read_text(encoding="utf-8"))
@@ -91,6 +91,18 @@ def immune_profile(design: dict) -> dict:
91
91
  return _ip(design)
92
92
 
93
93
 
94
+ @mcp.tool()
95
+ def offtarget_scan(writer_family: str, guide: str | None = None, candidate_sites: list | None = None,
96
+ sequence: str | None = None, assay: str = "guideseq") -> dict:
97
+ """v6.10 PEN-OFFTGT cross-family off-target NOMINATION (NOT a clearance). Ranks candidate sites with a
98
+ real-data mismatch-calibrated risk band + the real CRISOT learned score (nuclease), a pseudo-attB scan
99
+ (integrase), or the Perry-DMS pseudosite engine (bridge); ships the validation assay that would confirm
100
+ each candidate. Abstains without inputs; never fabricates sites."""
101
+ from pen_stack.wgenome.offtarget_predict import nominate_offtargets
102
+ return nominate_offtargets(writer_family, guide=guide, candidate_sites=candidate_sites,
103
+ sequence=sequence, assay=assay)
104
+
105
+
94
106
  @mcp.tool()
95
107
  def generate_designs(goal: dict | None = None, candidates: list | None = None, keep: int = 25) -> dict:
96
108
  """v5.8 generative designer (verifier-as-discriminator): hazardous/illegal candidates are DISCARDED;
@@ -46,6 +46,12 @@ _TOOLS = [
46
46
  "efficiency w/ conformal interval + auto-designed guide/att (v6.8 PEN-WRITER)",
47
47
  "input": "write request (write-type, cargo, cell type, optional target/donor seq)", "output": "WriterRanking",
48
48
  "entrypoint": "pen_stack.atlas.writer_recommend.recommend_writers", "fabricates": False},
49
+ {"name": "nominate_offtargets", "summary": "cross-writer-family off-target NOMINATION: rank candidate sites "
50
+ "with a real-data mismatch-calibrated risk band + the real CRISOT learned score (nuclease), pseudo-attB "
51
+ "scan (integrase), Perry-DMS pseudosite engine (bridge); nomination is NOT a clearance (v6.10 PEN-OFFTGT)",
52
+ "input": "writer family + guide/candidate sites (nuclease) or locus sequence (integrase)",
53
+ "output": "ranked off-target candidates + calibrated risk + recommended validation assay",
54
+ "entrypoint": "pen_stack.wgenome.offtarget_predict.nominate_offtargets", "fabricates": False},
49
55
  ]
50
56
 
51
57
  _POLICY = ("outputs outside scope are returned as `out_of_scope` (known-unknown) or `extrapolating` (OOD) and are "
@@ -208,6 +208,26 @@ def immune_endpoint(design: dict):
208
208
  return immune_profile(design)
209
209
 
210
210
 
211
+ @app.post("/offtarget", tags=["v6.10 off-target"])
212
+ def offtarget_endpoint(req: dict):
213
+ """v6.10 PEN-OFFTGT cross-family off-target NOMINATION (NOT a clearance). Body:
214
+ {writer_family, guide?, candidate_sites?, sequence?, accessibility?, assay?}. Returns ranked candidate
215
+ off-targets with a real-data mismatch-calibrated risk band + the recommended validation assay; abstains
216
+ without inputs and never fabricates sites."""
217
+ from pen_stack.wgenome.offtarget_predict import nominate_offtargets
218
+ return nominate_offtargets(
219
+ req.get("writer_family", ""), guide=req.get("guide"), candidate_sites=req.get("candidate_sites"),
220
+ sequence=req.get("sequence"), accessibility=req.get("accessibility"),
221
+ target_core=req.get("target_core"), assay=req.get("assay", "guideseq"))
222
+
223
+
224
+ @app.get("/offtarget/assay", tags=["v6.10 off-target"])
225
+ def offtarget_assay_endpoint(writer_family: str):
226
+ """v6.10 validation-assay recommendation for a writer family (the assay that would confirm a nomination)."""
227
+ from pen_stack.wgenome.offtarget_assay import recommend_assay
228
+ return recommend_assay(writer_family)
229
+
230
+
211
231
  @app.post("/generate", tags=["v6.1 AI surface"])
212
232
  def generate_endpoint(req: dict):
213
233
  """v5.8 generative designer: verifier-as-discriminator. Body: {goal?, candidates?, keep?}. Hazardous/illegal
@@ -0,0 +1,55 @@
1
+ """Validation-assay recommender for off-target nomination (v6.10 PEN-OFFTGT, E-WS3).
2
+
3
+ Nomination is NOT a clearance — it ships with the empirical assay that would CONFIRM the candidates. This maps a
4
+ writer family to the appropriate unbiased genome-wide assay(s) + their documented applicability, grounded in the
5
+ validated assay literature. For families with no published genome-wide off-target assay (bridge recombinases) it
6
+ says so honestly and recommends targeted confirmation, never implying a clearance exists.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ # assay applicability by writer family (validated citations in offtarget_data.ASSAY_PROVENANCE)
11
+ _NUCLEASE_ASSAYS = [
12
+ {"assay": "GUIDE-seq", "setting": "cell-based (in cellulo)", "doi": "10.1038/nbt.3117",
13
+ "use": "captures off-targets in the actual chromatin/cell context (dsODN tag at DSBs)"},
14
+ {"assay": "CHANGE-seq", "setting": "in vitro, high-throughput", "doi": "10.1038/s41587-020-0555-7",
15
+ "use": "most sensitive genome-wide nomination; pair with a cell-based assay to filter chromatin-masked sites"},
16
+ {"assay": "CIRCLE-seq", "setting": "in vitro (cell-free)", "doi": "10.1038/nmeth.4278",
17
+ "use": "highly sensitive in vitro confirmation; over-nominates vs cell context"},
18
+ ]
19
+
20
+
21
+ def recommend_assay(writer_family: str) -> dict:
22
+ """Recommend the empirical validation assay(s) for a writer family + the documented expected sensitivity, or
23
+ an honest 'no genome-wide assay exists' for data-thin families. Always frames nomination as not a clearance."""
24
+ fam = (writer_family or "").lower()
25
+ if "cas9" in fam or "nuclease" in fam or fam in {"spcas9", "sacas9", "cas12a", "ascas12a", "nickase"}:
26
+ return {"family": writer_family, "writer_class": "RNA-guided nuclease (DSB)",
27
+ "recommended": _NUCLEASE_ASSAYS,
28
+ "strategy": "nominate in vitro (CHANGE-/CIRCLE-seq, high sensitivity) THEN confirm the survivors "
29
+ "in the target cell type (GUIDE-seq) — chromatin masks a fraction of in vitro sites",
30
+ "available": True,
31
+ "note": "nomination ranks CANDIDATES; an empirical assay is required for clearance."}
32
+ if "integrase" in fam or "paste" in fam or "passige" in fam or "bxb1" in fam or "phic31" in fam:
33
+ return {"family": writer_family, "writer_class": "large serine integrase",
34
+ "recommended": [{"assay": "Cryptic-seq / HIDE-seq", "setting": "unbiased LSI off-target discovery",
35
+ "doi": "10.1101/2024.08.23.609471",
36
+ "use": "the genome-wide unbiased assay for serine-integrase cryptic attB sites "
37
+ "(Tome Biosciences, 2024 preprint)"}],
38
+ "strategy": "scan cryptic pseudo-attB (this engine) THEN confirm by Cryptic-seq/HIDE-seq; "
39
+ "quantitative prediction (IntQuery) is paper-only (no public weights)",
40
+ "available": True,
41
+ "note": "LSI off-target assays are recent preprints; coverage is single-company / largely Bxb1."}
42
+ if "bridge" in fam or "is110" in fam or "is621" in fam or "seek" in fam or "iscro4" in fam:
43
+ return {"family": writer_family, "writer_class": "bridge recombinase (IS110/IS621 RNA-guided)",
44
+ "recommended": [{"assay": "targeted amplicon / capture sequencing at nominated pseudosites",
45
+ "setting": "targeted", "doi": None,
46
+ "use": "confirm individual nominated pseudosites (no genome-wide unbiased "
47
+ "off-target assay exists for bridge recombinases yet)"}],
48
+ "strategy": "nominate pseudosites with the Perry-DMS engine THEN confirm by targeted sequencing; "
49
+ "an unbiased genome-wide bridge off-target assay is an open need",
50
+ "available": True,
51
+ "note": "HONEST GAP: bridge-recombinase off-target is essentially unmodeled — there is NO "
52
+ "published genome-wide unbiased assay or predictor (verified). Treat nominations as "
53
+ "high-uncertainty / extrapolative; do not read as clearance."}
54
+ return {"family": writer_family, "available": False,
55
+ "note": f"no off-target assay applicability rule for family {writer_family!r}"}
@@ -0,0 +1,100 @@
1
+ """Off-target ground-truth + provenance for the cross-family nomination engine (v6.10 PEN-OFFTGT, E-WS1).
2
+
3
+ The ground truth is harmonized, PUBLISHED, unbiased genome-wide off-target assays over canonical Cas9 guides;
4
+ the derived risk calibration and the Off-Target-Bench headline (the REAL CRISOT predictor vs the homology
5
+ baseline) are embedded in-code so the axis is available everywhere (CI / bare install / live app), while the
6
+ full sealed fixture + per-guide metrics live under ``benchmarks/offtarget/`` for the bench harness.
7
+
8
+ LICENSING / HONESTY: the CRISOT predictor (Chen et al., Nat Commun 2023) is CC-BY-NC and runs ONLY on the VM —
9
+ its binaries/weights are NEVER redistributed; only DERIVED scores are cached (exactly like the licensed MHC
10
+ tools). Off-target SITE sequences are facts from the public assay supplements (cited below). A nominated
11
+ off-target is a CANDIDATE, never a claim.
12
+ """
13
+ from __future__ import annotations
14
+
15
+ from functools import lru_cache
16
+
17
+ # ---- validated assay provenance (independently verified 2026-06-19) -----------------------------
18
+ ASSAY_PROVENANCE = {
19
+ "guideseq": {"name": "GUIDE-seq", "kind": "cell-based, unbiased, genome-wide",
20
+ "citation": "Tsai et al., Nat Biotechnol 2015", "doi": "10.1038/nbt.3117"},
21
+ "circleseq": {"name": "CIRCLE-seq", "kind": "in vitro (cell-free), unbiased, genome-wide",
22
+ "citation": "Tsai et al., Nat Methods 2017", "doi": "10.1038/nmeth.4278"},
23
+ "changeseq": {"name": "CHANGE-seq", "kind": "in vitro, unbiased, high-throughput (110 sgRNAs)",
24
+ "citation": "Lazzarotto et al., Nat Biotechnol 2020", "doi": "10.1038/s41587-020-0555-7"},
25
+ "siteseq": {"name": "SITE-seq", "kind": "in vitro biochemical, unbiased",
26
+ "citation": "Cameron et al., Nat Methods 2017", "doi": "10.1038/nmeth.4284"},
27
+ }
28
+ PREDICTOR_PROVENANCE = {
29
+ "crisot": {"name": "CRISOT-Score", "approach": "XGBoost RNA-DNA interaction fingerprint",
30
+ "citation": "Chen et al., Nat Commun 2023", "doi": "10.1038/s41467-023-42695-4",
31
+ "license": "CC-BY-NC (run on the VM; only derived scores cached, weights never redistributed)"},
32
+ }
33
+ # integrase off-target assays (large serine integrases) — for the assay recommender; data-thin, preprints
34
+ INTEGRASE_ASSAY_PROVENANCE = {
35
+ "cryptic_seq": {"name": "Cryptic-seq / HIDE-seq", "kind": "unbiased LSI off-target discovery",
36
+ "citation": "Hazelbaker et al. (Tome Biosciences), bioRxiv 2024",
37
+ "doi": "10.1101/2024.08.23.609471"},
38
+ "intquery": {"name": "IntQuery", "kind": "LSI off-target deep-learning predictor (paper-only, no public weights)",
39
+ "citation": "Bakalar et al. (Tome Biosciences), bioRxiv 2024", "doi": "10.1101/2024.10.10.617699"},
40
+ }
41
+
42
+ # canonical Cas9 guides present in the bench (20-nt protospacers; Tsai 2015/2017)
43
+ CANONICAL_GUIDES = {
44
+ "EMX1": "GAGTCCGAGCAGAAGAAGAA", "VEGFA_site1": "GGGTGGGGGGAGTTTGCTCC",
45
+ "VEGFA_site2": "GACCCCCTCCACCCCGCCTC", "VEGFA_site3": "GGTGAGTGAGTGTGTGCGTG",
46
+ "FANCF": "GGAATCCCTTCTGCAGCACC", "HEK293_site2": "GAACACAAAGCATAGACTGC",
47
+ "HEK293_site3": "GGCCCAGACTGAGCACGTGA", "HEK293_site4": "GGCACTGCGGCTGGAGGTGG",
48
+ }
49
+
50
+ # ---- DERIVED, real-data risk calibration: empirical active fraction by mismatch count -----------
51
+ # (computed on the VM over ALL canonical-guide candidates; the off-target nomination risk band is grounded
52
+ # in how often a candidate at k mismatches was actually validated-active, not a guessed curve.)
53
+ MISMATCH_ACTIVE_FRACTION = {
54
+ "guideseq": {0: 1.0, 1: 1.0, 2: 0.76471, 3: 0.23129, 4: 0.033, 5: 0.00276, 6: 0.00014},
55
+ "circleseq": {0: 1.0, 1: 1.0, 2: 1.0, 3: 0.67146, 4: 0.26566, 5: 0.05924, 6: 0.00985},
56
+ }
57
+
58
+ # ---- Off-Target-Bench headline (REAL full-data result; per-guide AUPRC, held-out-guide bootstrap CI) -----
59
+ BENCH_SUMMARY = {
60
+ "guideseq": {"n_guides": 8, "crisot_auprc": 0.6458, "homology_auprc": 0.4668,
61
+ "auprc_gap": 0.179, "gap_ci95": [0.0154, 0.3396], "crisot_beats_homology": True},
62
+ "circleseq": {"n_guides": 8, "crisot_auprc": 0.5197, "homology_auprc": 0.2664,
63
+ "auprc_gap": 0.2533, "gap_ci95": [0.1404, 0.3608], "crisot_beats_homology": True},
64
+ "metric": "per-guide AUPRC; baseline = ascending mismatch count; learned = real CRISOT-Score (VM, cached)",
65
+ }
66
+
67
+
68
+ def assay_provenance() -> dict:
69
+ """Validated provenance for every assay + predictor the off-target engine is grounded on."""
70
+ return {"nuclease_assays": ASSAY_PROVENANCE, "nuclease_predictor": PREDICTOR_PROVENANCE,
71
+ "integrase_assays": INTEGRASE_ASSAY_PROVENANCE}
72
+
73
+
74
+ @lru_cache(maxsize=1)
75
+ def bench_records() -> list[dict]:
76
+ """The committed Off-Target-Bench fixture (real validated off-targets + cached CRISOT scores) as a list of
77
+ dicts, or [] when the data tree is absent (bare wheel). Columns: assay, guide, On, Off, mismatch, active,
78
+ crisot_score."""
79
+ try:
80
+ import csv
81
+
82
+ from pen_stack._resources import resource
83
+ path = resource("benchmarks/offtarget/offtarget_bench_fixture.csv")
84
+ with open(path, encoding="utf-8") as fh:
85
+ rows = list(csv.DictReader(fh))
86
+ for r in rows:
87
+ r["mismatch"] = int(r["mismatch"])
88
+ r["active"] = int(r["active"])
89
+ r["crisot_score"] = float(r["crisot_score"])
90
+ return rows
91
+ except Exception: # noqa: BLE001 (bare wheel / no data tree -> the bench harness is checkout-only)
92
+ return []
93
+
94
+
95
+ def calibrated_active_fraction(n_mismatch: int, assay: str = "guideseq") -> float | None:
96
+ """The empirical fraction of candidate sites at ``n_mismatch`` mismatches that were validated-active in the
97
+ named assay (grounded risk). None if the mismatch count is outside the calibrated range (then the axis
98
+ abstains rather than extrapolating)."""
99
+ table = MISMATCH_ACTIVE_FRACTION.get(assay, MISMATCH_ACTIVE_FRACTION["guideseq"])
100
+ return table.get(int(n_mismatch))