pen-stack 5.0.0__tar.gz → 5.2.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 (311) hide show
  1. {pen_stack-5.0.0 → pen_stack-5.2.0}/CHANGELOG.md +65 -0
  2. {pen_stack-5.0.0 → pen_stack-5.2.0}/CITATION.cff +2 -2
  3. {pen_stack-5.0.0 → pen_stack-5.2.0}/PKG-INFO +40 -5
  4. {pen_stack-5.0.0 → pen_stack-5.2.0}/README.md +39 -4
  5. pen_stack-5.2.0/configs/delivery_vehicles.yaml +185 -0
  6. pen_stack-5.2.0/configs/genotoxicity_oracle.yaml +48 -0
  7. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/oracles/scope_cards.yaml +13 -0
  8. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/__init__.py +1 -1
  9. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/agent/cite.py +7 -0
  10. pen_stack-5.2.0/pen_stack/planner/delivery_immunology.py +170 -0
  11. pen_stack-5.2.0/pen_stack/planner/genotoxicity_oracle.py +112 -0
  12. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/verify/schema.py +2 -0
  13. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/verify/service.py +16 -1
  14. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack.egg-info/PKG-INFO +40 -5
  15. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack.egg-info/SOURCES.txt +8 -0
  16. pen_stack-5.2.0/prereg/SHA256_LOCK_ws_genotox.json +8 -0
  17. pen_stack-5.2.0/prereg/SHA256_LOCK_ws_immune.json +8 -0
  18. pen_stack-5.2.0/prereg/ws_genotox.yaml +41 -0
  19. pen_stack-5.2.0/prereg/ws_immune.yaml +43 -0
  20. {pen_stack-5.0.0 → pen_stack-5.2.0}/pyproject.toml +1 -1
  21. pen_stack-5.2.0/scripts/p52_build_genotox_oracle.py +112 -0
  22. pen_stack-5.0.0/configs/delivery_vehicles.yaml +0 -105
  23. {pen_stack-5.0.0 → pen_stack-5.2.0}/LICENSE +0 -0
  24. {pen_stack-5.0.0 → pen_stack-5.2.0}/MANIFEST.in +0 -0
  25. {pen_stack-5.0.0 → pen_stack-5.2.0}/bench/run.py +0 -0
  26. {pen_stack-5.0.0 → pen_stack-5.2.0}/benchmarks/genome_writing_bench/LEADERBOARD.md +0 -0
  27. {pen_stack-5.0.0 → pen_stack-5.2.0}/benchmarks/genome_writing_bench/README.md +0 -0
  28. {pen_stack-5.0.0 → pen_stack-5.2.0}/benchmarks/genome_writing_bench/SHA256SUMS +0 -0
  29. {pen_stack-5.0.0 → pen_stack-5.2.0}/benchmarks/genome_writing_bench/SUBMISSIONS.md +0 -0
  30. {pen_stack-5.0.0 → pen_stack-5.2.0}/benchmarks/genome_writing_bench/tasks.yaml +0 -0
  31. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/atlas_families.yaml +0 -0
  32. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/bridge_offtarget_profile.yaml +0 -0
  33. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/cargo_polish.yaml +0 -0
  34. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/cell_types.yaml +0 -0
  35. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/datasets.yaml +0 -0
  36. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/delivery_constraints.yaml +0 -0
  37. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/delivery_rules.yaml +0 -0
  38. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/gates_v3.yaml +0 -0
  39. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/gsh_validated_heldout.yaml +0 -0
  40. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/intent_weights.yaml +0 -0
  41. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/known_unknowns.yaml +0 -0
  42. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/llm.yaml +0 -0
  43. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/monitor_queries.yaml +0 -0
  44. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/rules/delivery.yaml +0 -0
  45. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/rules/fold.yaml +0 -0
  46. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/rules/multiplex.yaml +0 -0
  47. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/rules/payload.yaml +0 -0
  48. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/rules/reachability.yaml +0 -0
  49. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/score_axes.yaml +0 -0
  50. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/target_sites.yaml +0 -0
  51. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/universe_crosswalk.yaml +0 -0
  52. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/write_types.yaml +0 -0
  53. {pen_stack-5.0.0 → pen_stack-5.2.0}/configs/wtkb_curated.yaml +0 -0
  54. {pen_stack-5.0.0 → pen_stack-5.2.0}/data/curated/bridge_offtarget_energetics.json +0 -0
  55. {pen_stack-5.0.0 → pen_stack-5.2.0}/data/curated/bridge_offtarget_profile_measured.parquet +0 -0
  56. {pen_stack-5.0.0 → pen_stack-5.2.0}/data/curated/gene_coords.parquet +0 -0
  57. {pen_stack-5.0.0 → pen_stack-5.2.0}/data/curated/unified_editor_universe.parquet +0 -0
  58. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/BACKLOG.md +0 -0
  59. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/DEPLOY.md +0 -0
  60. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/INFRA.md +0 -0
  61. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/MCP.md +0 -0
  62. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/RELEASING.md +0 -0
  63. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/REPRO.md +0 -0
  64. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/agent.md +0 -0
  65. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/alphagenome_feasibility.md +0 -0
  66. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/benchmark_circularity.md +0 -0
  67. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/cards/atlas.md +0 -0
  68. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/cards/durability.md +0 -0
  69. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/cards/safety.md +0 -0
  70. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/co_scientist.md +0 -0
  71. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/delivery.md +0 -0
  72. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/dissemination.md +0 -0
  73. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/environment.md +0 -0
  74. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/index.md +0 -0
  75. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/mechanistic_constraints.md +0 -0
  76. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/oracles.md +0 -0
  77. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/positioning.md +0 -0
  78. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/private_data_formats.md +0 -0
  79. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/quickstart.md +0 -0
  80. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/rules.md +0 -0
  81. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/scope.md +0 -0
  82. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/scorecard.md +0 -0
  83. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/tutorials/compare-families.md +0 -0
  84. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/tutorials/score-deliverability.md +0 -0
  85. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/tutorials/where-can-i-write.md +0 -0
  86. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/tutorials/which-writer-reaches-locus.md +0 -0
  87. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/uncertainty.md +0 -0
  88. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/verify.md +0 -0
  89. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/world_model.md +0 -0
  90. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/writer_verification.md +0 -0
  91. {pen_stack-5.0.0 → pen_stack-5.2.0}/docs/wtkb.md +0 -0
  92. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/_resources.py +0 -0
  93. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/adapt/__init__.py +0 -0
  94. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/adapt/finetune.py +0 -0
  95. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/adapt/ingest.py +0 -0
  96. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/adapt/pipeline.py +0 -0
  97. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/adapt/recalibrate.py +0 -0
  98. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/adapt/report.py +0 -0
  99. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/agent/__init__.py +0 -0
  100. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/agent/co_scientist.py +0 -0
  101. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/agent/epistemic.py +0 -0
  102. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/agent/guardrails.py +0 -0
  103. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/agent/mcp_server.py +0 -0
  104. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/agent/orchestrator.py +0 -0
  105. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/agent/pen_agent.py +0 -0
  106. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/agent/scope.py +0 -0
  107. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/agent/tools.py +0 -0
  108. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/atlas/__init__.py +0 -0
  109. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/atlas/build_wtkb.py +0 -0
  110. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/atlas/crosslink.py +0 -0
  111. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/atlas/expand.py +0 -0
  112. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/atlas/schema.py +0 -0
  113. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/atlas/scorecard.py +0 -0
  114. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/atlas/universe.py +0 -0
  115. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/atlas/variant_propose.py +0 -0
  116. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/atlas/writer_verify.py +0 -0
  117. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/bridge/__init__.py +0 -0
  118. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/bridge/activity.py +0 -0
  119. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/bridge/cli.py +0 -0
  120. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/bridge/fold_qc.py +0 -0
  121. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/bridge/guide_qc.py +0 -0
  122. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/bridge/ingest.py +0 -0
  123. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/bridge/offtarget.py +0 -0
  124. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/bridge/offtarget_energetics.py +0 -0
  125. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/bridge/ortholog_screen.py +0 -0
  126. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/bridge/pipeline.py +0 -0
  127. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/cli.py +0 -0
  128. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/data/__init__.py +0 -0
  129. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/data/encode.py +0 -0
  130. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/data/genome.py +0 -0
  131. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/data/ingest_chromatin.py +0 -0
  132. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/data/ingest_integration.py +0 -0
  133. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/data/ingest_safety_annot.py +0 -0
  134. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/data/ingest_trip.py +0 -0
  135. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/env/__init__.py +0 -0
  136. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/env/genome_writing_env.py +0 -0
  137. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/env/policies.py +0 -0
  138. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/graph/__init__.py +0 -0
  139. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/graph/build.py +0 -0
  140. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/graph/cell_types.py +0 -0
  141. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/graph/ingest.py +0 -0
  142. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/graph/query.py +0 -0
  143. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/graph/schema.py +0 -0
  144. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/mech/__init__.py +0 -0
  145. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/mech/classify_atlas.py +0 -0
  146. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/mech/whitelist.py +0 -0
  147. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/monitor/__init__.py +0 -0
  148. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/monitor/europepmc.py +0 -0
  149. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/monitor/run.py +0 -0
  150. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/monitor/triage.py +0 -0
  151. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/oracles/__init__.py +0 -0
  152. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/oracles/cache.py +0 -0
  153. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/oracles/energetics.py +0 -0
  154. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/oracles/genome.py +0 -0
  155. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/oracles/protein_design.py +0 -0
  156. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/oracles/rna.py +0 -0
  157. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/oracles/schema.py +0 -0
  158. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/oracles/structure.py +0 -0
  159. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/planner/__init__.py +0 -0
  160. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/planner/cargo.py +0 -0
  161. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/planner/cargo_polish.py +0 -0
  162. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/planner/delivery.py +0 -0
  163. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/planner/delivery_constraints.py +0 -0
  164. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/planner/delivery_vehicles.py +0 -0
  165. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/planner/multiplex.py +0 -0
  166. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/planner/optimize.py +0 -0
  167. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/planner/pipeline.py +0 -0
  168. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/planner/report.py +0 -0
  169. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/planner/router.py +0 -0
  170. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/planner/target_site.py +0 -0
  171. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/rag/__init__.py +0 -0
  172. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/rag/index.py +0 -0
  173. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/rag/llm.py +0 -0
  174. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/rag/qa.py +0 -0
  175. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/rules/__init__.py +0 -0
  176. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/rules/evaluators.py +0 -0
  177. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/rules/loader.py +0 -0
  178. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/rules/schema.py +0 -0
  179. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/rules/solver.py +0 -0
  180. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/score/__init__.py +0 -0
  181. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/score/recalibrate.py +0 -0
  182. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/score/therapeutic.py +0 -0
  183. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/server/__init__.py +0 -0
  184. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/server/api.py +0 -0
  185. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/ui/__init__.py +0 -0
  186. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/ui/app.py +0 -0
  187. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/__init__.py +0 -0
  188. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/adapt_demo.py +0 -0
  189. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/agent_eval.py +0 -0
  190. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/bench_adversarial_tasks.py +0 -0
  191. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/bench_coscientist_tasks.py +0 -0
  192. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/bench_graph_tasks.py +0 -0
  193. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/bench_rule_tasks.py +0 -0
  194. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/bench_trust_tasks.py +0 -0
  195. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/bench_writetype_tasks.py +0 -0
  196. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/blind_gsh_discovery.py +0 -0
  197. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/cargo_directionality.py +0 -0
  198. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/durability_baselines.py +0 -0
  199. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/forward_hypotheses.py +0 -0
  200. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/guide_qc_demo.py +0 -0
  201. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/intent_specification.py +0 -0
  202. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/offtarget_energetics_eval.py +0 -0
  203. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/out_of_scope_refusal.py +0 -0
  204. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/outcome_calibration.py +0 -0
  205. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/paper3_benchmark.py +0 -0
  206. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/paper4_real_validation.py +0 -0
  207. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/paper4_validation.py +0 -0
  208. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/selective_prediction.py +0 -0
  209. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/seq_vs_measured.py +0 -0
  210. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/target_site_controls.py +0 -0
  211. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/uncertainty_eval.py +0 -0
  212. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/ungrounded_baseline.py +0 -0
  213. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/within_locus_ranking.py +0 -0
  214. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/validate/writer_recovery.py +0 -0
  215. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/verify/__init__.py +0 -0
  216. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/wgenome/__init__.py +0 -0
  217. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/wgenome/chromatin_seq.py +0 -0
  218. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/wgenome/durability.py +0 -0
  219. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/wgenome/export_tracks.py +0 -0
  220. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/wgenome/features.py +0 -0
  221. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/wgenome/gsh_baseline.py +0 -0
  222. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/wgenome/mesh_features.py +0 -0
  223. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/wgenome/ood.py +0 -0
  224. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/wgenome/providers.py +0 -0
  225. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/wgenome/safety.py +0 -0
  226. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/wgenome/structure3d.py +0 -0
  227. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/wgenome/uncertainty.py +0 -0
  228. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack/wgenome/writability.py +0 -0
  229. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack.egg-info/dependency_links.txt +0 -0
  230. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack.egg-info/entry_points.txt +0 -0
  231. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack.egg-info/requires.txt +0 -0
  232. {pen_stack-5.0.0 → pen_stack-5.2.0}/pen_stack.egg-info/top_level.txt +0 -0
  233. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_phase0.json +0 -0
  234. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_phase1_5.json +0 -0
  235. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_phase2.json +0 -0
  236. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_phase3.json +0 -0
  237. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_a.json +0 -0
  238. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_atlas.json +0 -0
  239. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_b.json +0 -0
  240. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_ba.json +0 -0
  241. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_ba_v33.json +0 -0
  242. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_ba_v45.json +0 -0
  243. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_bench.json +0 -0
  244. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_c.json +0 -0
  245. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_cal.json +0 -0
  246. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_cite.json +0 -0
  247. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_crit.json +0 -0
  248. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_ct.json +0 -0
  249. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_d.json +0 -0
  250. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_e.json +0 -0
  251. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_env.json +0 -0
  252. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_ep.json +0 -0
  253. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_f.json +0 -0
  254. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_g.json +0 -0
  255. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_graph.json +0 -0
  256. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_h.json +0 -0
  257. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_mc.json +0 -0
  258. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_mon.json +0 -0
  259. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_o.json +0 -0
  260. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_plan.json +0 -0
  261. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_r.json +0 -0
  262. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_route.json +0 -0
  263. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_uq.json +0 -0
  264. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_v.json +0 -0
  265. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/SHA256_LOCK_ws_wv.json +0 -0
  266. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/paper1.yaml +0 -0
  267. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/paper2.yaml +0 -0
  268. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/paper3.yaml +0 -0
  269. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/paper4.yaml +0 -0
  270. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/phase0.yaml +0 -0
  271. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_a.yaml +0 -0
  272. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_atlas.yaml +0 -0
  273. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_b.yaml +0 -0
  274. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_ba.yaml +0 -0
  275. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_ba_v33.yaml +0 -0
  276. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_ba_v45.yaml +0 -0
  277. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_bench.yaml +0 -0
  278. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_c.yaml +0 -0
  279. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_cal.yaml +0 -0
  280. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_cite.yaml +0 -0
  281. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_crit.yaml +0 -0
  282. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_ct.yaml +0 -0
  283. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_d.yaml +0 -0
  284. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_e.yaml +0 -0
  285. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_env.yaml +0 -0
  286. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_ep.yaml +0 -0
  287. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_f.yaml +0 -0
  288. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_g.yaml +0 -0
  289. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_graph.yaml +0 -0
  290. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_h.yaml +0 -0
  291. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_mc.yaml +0 -0
  292. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_mon.yaml +0 -0
  293. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_o.yaml +0 -0
  294. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_plan.yaml +0 -0
  295. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_r.yaml +0 -0
  296. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_route.yaml +0 -0
  297. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_uq.yaml +0 -0
  298. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_v.yaml +0 -0
  299. {pen_stack-5.0.0 → pen_stack-5.2.0}/prereg/ws_wv.yaml +0 -0
  300. {pen_stack-5.0.0 → pen_stack-5.2.0}/scripts/p1_build_atlas.py +0 -0
  301. {pen_stack-5.0.0 → pen_stack-5.2.0}/scripts/p1_build_durability.py +0 -0
  302. {pen_stack-5.0.0 → pen_stack-5.2.0}/scripts/p1_export_tracks.py +0 -0
  303. {pen_stack-5.0.0 → pen_stack-5.2.0}/scripts/p1_safety_concordance.py +0 -0
  304. {pen_stack-5.0.0 → pen_stack-5.2.0}/scripts/p1_train_safety.py +0 -0
  305. {pen_stack-5.0.0 → pen_stack-5.2.0}/scripts/p1_validation_report.py +0 -0
  306. {pen_stack-5.0.0 → pen_stack-5.2.0}/scripts/p2_build_atlas.py +0 -0
  307. {pen_stack-5.0.0 → pen_stack-5.2.0}/scripts/p3_benchmark_report.py +0 -0
  308. {pen_stack-5.0.0 → pen_stack-5.2.0}/scripts/p4_genome_scan.py +0 -0
  309. {pen_stack-5.0.0 → pen_stack-5.2.0}/scripts/ws_b_report.py +0 -0
  310. {pen_stack-5.0.0 → pen_stack-5.2.0}/scripts/ws_c_report.py +0 -0
  311. {pen_stack-5.0.0 → pen_stack-5.2.0}/setup.cfg +0 -0
@@ -3,6 +3,71 @@
3
3
  All notable changes to PEN-STACK are documented here. This file follows
4
4
  [Keep a Changelog](https://keepachangelog.com/) and the program's phase structure.
5
5
 
6
+ ## [5.2.0] - 2026-06-10 - v5.2 release: Computed genotoxicity oracle (data, not a documented tier)
7
+
8
+ The v5.1 genotoxicity axis was a documented ordinal tier; for **integrating** vectors that signal is in fact
9
+ computable from data the stack already holds. v5.2 adds a **computed genotoxicity oracle** — the observed
10
+ enrichment of a vector class's integration sites near COSMIC oncogenes — answering through the v4.0
11
+ OracleResult contract. Workstream WS-GENOTOX, SHA-locked.
12
+
13
+ ### Added
14
+ - **WS-GENOTOX build** — `scripts/p52_build_genotox_oracle.py` (runs on the VM where the data lives) computes,
15
+ per integrating vector class, `P(integration site within 50 kb of a COSMIC Cancer-Gene-Census oncogene)` and
16
+ its enrichment over genome background, from **VISDB** per-virus catalogues × the Phase-1 oncogene annotation
17
+ (**COSMIC CGC v104**). Emits the small, auditable, committed summary `configs/genotoxicity_oracle.yaml` (raw
18
+ catalogues stay on the VM; only the statistics ship → CI-safe).
19
+ - **WS-GENOTOX oracle** — `pen_stack/planner/genotoxicity_oracle.py`: `genotoxicity_oracle(vehicle)` returns an
20
+ `OracleResult` (`output_kind="baseline"`) with `genotox_score = min(1, 1/enrichment)`, native uncertainty
21
+ (CI on the observed fraction), the `delivery_genotoxicity` scope card, and `extrapolating` for small-n
22
+ classes. Non-integrating vehicles → 1.0 by mechanism; no computed class → **abstains** (never fabricates).
23
+ - **Wired into the v5.1 balance** — `safety_efficacy_profile()` now **prefers the computed genotox_score** for
24
+ integrating vectors and falls back to the documented tier otherwise (`genotox_source` records which).
25
+ - **Result (from data):** lentiviral (HIV) integration is **2.08×** enriched near oncogenes (n=88,743, robust)
26
+ vs **5.65×** for gammaretroviral (MLV, the LMO2/SCID-X1 comparator, small-n flagged) — reproducing the
27
+ lentivirus-safer-than-gammaretrovirus ordering **from VISDB×COSMIC**, and the computed lentivirus score
28
+ (0.48) **validates** the v5.1 documented "moderate" tier (0.5). `prereg/ws_genotox.yaml`.
29
+
30
+ ### Changed
31
+ - Version 5.1.0 -> 5.2.0 (minor — additive computed oracle); `cite.curated_dois()` ingests the genotox
32
+ provenance DOIs (VISDB 10.1093/nar/gkz867, COSMIC CGC 10.1038/s41568-018-0060-1, HIV/MLV integration biology).
33
+
34
+ ### Honesty invariant (unchanged)
35
+ - This is a **relative integration-preference** signal. The in-vivo clonal-expansion / leukemogenesis OUTCOME
36
+ in a patient is **not** modelled and stays a known-unknown (`delivery_genotoxicity` scope card); the immune
37
+ MAGNITUDE likewise stays `in_vivo_immunogenicity`. No magnitude is predicted.
38
+
39
+ ## [5.1.0] - 2026-06-10 - v5.1 release: Delivery immunology (the safety↔efficacy balance)
40
+
41
+ The delivery palette gains a **documented, cited, qualitative immune + safety + efficacy profile** per vehicle,
42
+ so the substrate can make the safety↔efficacy tradeoff legible and user-weightable — without ever predicting an
43
+ immune magnitude (that stays a declared known-unknown). Workstream WS-IMMUNE, SHA-locked.
44
+
45
+ ### Added
46
+ - **WS-IMMUNE config** — `configs/delivery_vehicles.yaml` (v1.1): an `immune_safety` block on all 8 vehicles
47
+ (`preexisting_immunity`, `neutralizing_antibody`, `innate_immune`, `adaptive_immune`, `genotoxicity`,
48
+ `efficacy`, `tradeoff`, `immune_dois`) — DOCUMENTED ordinal low/moderate/high priors, every `immune_doi`
49
+ Crossref-verified and in the curated-DOI set (citations resolve by construction).
50
+ - **WS-IMMUNE planner** — `pen_stack/planner/delivery_immunology.py`: `safety_efficacy_profile()` reports two
51
+ **separate** safety sub-axes — `immune_score` (immunogenicity; reversible, eligibility/re-dosing) and
52
+ `genotox_score` (insertional/oncogenic; permanent) — never collapsed, with headline
53
+ `safety_score = min(immune_score, genotox_score)` (precautionary worst-axis). `recommend_delivery(cargo_form,
54
+ cargo_bp, safety_weight, in_vivo)` ranks the eligible palette along the safety↔efficacy frontier by a
55
+ user-supplied weight. Reproduces the stated tradeoff: AAV is dinged on immunogenicity, lentivirus on
56
+ genotoxicity. `prereg/ws_immune.yaml`.
57
+ - **WS-IMMUNE verify** — `Verdict.delivery_profile` + a `delivery_immune_profile` scope flag: `verify()` now
58
+ surfaces the documented profile and tradeoff for a chosen vehicle, always attaching the standing
59
+ `in_vivo_immunogenicity` known-unknown flag — never adding confidence, never predicting a magnitude.
60
+
61
+ ### Changed
62
+ - Version 5.0.0 -> 5.1.0 (minor — additive delivery-immunology layer); `cite.curated_dois()` now also ingests
63
+ the per-vehicle `immune_dois`.
64
+
65
+ ### Honesty invariant (unchanged)
66
+ - The in-vivo immune MAGNITUDE (patient/construct-specific response) remains a declared known-unknown
67
+ (`configs/known_unknowns.yaml: in_vivo_immunogenicity`) and is **never** predicted. v5.1 exposes only
68
+ documented ordinal priors plus a transparent, user-weighted ranking — it makes the boundary legible, it does
69
+ not close it.
70
+
6
71
  ## [5.0.0] - 2026-06-09 - v5.0 release: the Co-Scientist (capstone — smart because it is grounded)
7
72
 
8
73
  The reasoning ceiling rises while the grounding floor stays fixed: a co-scientist that proposes multiple
@@ -1,8 +1,8 @@
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: 5.0.0
5
- date-released: 2026-06-01
4
+ version: 5.2.0
5
+ date-released: 2026-06-10
6
6
  authors:
7
7
  - family-names: "Mahaboob Ali"
8
8
  given-names: "Anees Ahmed"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pen-stack
3
- Version: 5.0.0
3
+ Version: 5.2.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
@@ -77,10 +77,12 @@ Dynamic: license-file
77
77
 
78
78
  # PEN-STACK
79
79
 
80
- ### The Writable Genome - open infrastructure for genome *writing*
80
+ ### The verification & grounding substrate for genome-writing AI — matured into a co-scientist
81
81
 
82
- *Editing tools tell you **how** to change a base. PEN-STACK tells you **where** in the genome you can safely
83
- and durably write new DNA, **which enzyme** can write it there, and **how** to design the write end-to-end.*
82
+ *The foundation models *generate*; PEN-STACK *checks*. It tells you **where** in the genome you can safely and
83
+ durably write, **which enzyme** can write it there, and **how** to design the write end-to-end — then verifies
84
+ every design against rule-grounded mechanism, reports calibrated confidence, cites its reasoning, and says
85
+ "out of scope" rather than guess. Every number comes from a validated tool; nothing is fabricated.*
84
86
 
85
87
  [![PyPI](https://img.shields.io/pypi/v/pen-stack.svg)](https://pypi.org/project/pen-stack/)
86
88
  [![CI](https://github.com/ahmedanees-m/pen-stack/actions/workflows/ci.yml/badge.svg)](https://github.com/ahmedanees-m/pen-stack/actions/workflows/ci.yml)
@@ -89,7 +91,7 @@ and durably write new DNA, **which enzyme** can write it there, and **how** to d
89
91
  [![codecov](https://codecov.io/gh/ahmedanees-m/pen-stack/branch/main/graph/badge.svg)](https://codecov.io/gh/ahmedanees-m/pen-stack)
90
92
  [![License: MIT](https://img.shields.io/badge/License-MIT-informational.svg)](LICENSE)
91
93
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
92
- [![Version](https://img.shields.io/badge/version-5.0.0-blue.svg)](CHANGELOG.md)
94
+ [![Version](https://img.shields.io/badge/version-5.2.0-blue.svg)](CHANGELOG.md)
93
95
  [![Tests](https://img.shields.io/badge/tests-240%20passing-success.svg)](tests/)
94
96
  [![Lint: ruff](https://img.shields.io/badge/lint-ruff-purple.svg)](https://github.com/astral-sh/ruff)
95
97
  [![Runtime: Docker](https://img.shields.io/badge/runtime-docker-2496ED.svg)](docker/)
@@ -133,6 +135,39 @@ Two questions gate every genome-writing project, and before PEN-STACK no resourc
133
135
  Everything is built on bulk-downloadable public data, runs on a single GPU, and is validated **blind** against
134
136
  a pre-registered, honest baseline before release.
135
137
 
138
+ ## What is new in v5.2 — Computed genotoxicity oracle (data, not a documented tier)
139
+
140
+ v5.1 scored genotoxicity as a documented `low/moderate/high` tier. v5.2 makes it **computed from data** for
141
+ integrating vectors: the observed enrichment of a vector class's integration sites near COSMIC oncogenes
142
+ (VISDB integration catalogues × the Phase-1 COSMIC-CGC oncogene annotation), surfaced through the v4.0
143
+ `OracleResult` contract. The in-vivo clonal / leukemogenesis **outcome** stays a known-unknown — this is a
144
+ relative integration-*preference* signal, not a per-patient oncogenesis probability.
145
+
146
+ | Workstream | What it adds | Result |
147
+ |---|---|---|
148
+ | **GENOTOX build** | `scripts/p52_build_genotox_oracle.py` → committed `configs/genotoxicity_oracle.yaml` | per integrating class: `P(site within 50 kb of a COSMIC oncogene)`, enrichment vs background, CI, n — from VISDB × COSMIC CGC v104 (raw data stays on the VM; only the auditable summary ships) |
149
+ | **GENOTOX oracle** | `planner/genotoxicity_oracle.py` (`OracleResult`, `output_kind="baseline"`) | `genotox_score = min(1, 1/enrichment)`; non-integrating → 1.0 by mechanism; **abstains** when it has no computed class (never fabricates); small-n classes flagged `extrapolating` |
150
+ | **wired into v5.1 balance** | `safety_efficacy_profile()` prefers computed genotox, falls back to the documented tier | **lentiviral 2.08×** vs **gammaretroviral 5.65×** oncogene-proximity enrichment — reproduces the lentivirus-safer-than-gammaretrovirus ordering **from data**; computed LV score (0.48) **validates** the v5.1 documented tier (0.5) |
151
+
152
+ See `prereg/ws_genotox.yaml` and the `delivery_genotoxicity` scope card.
153
+
154
+ ## What is new in v5.1 — Delivery immunology (the safety↔efficacy balance)
155
+
156
+ v5.1 makes the delivery palette's **safety↔efficacy tradeoff legible and user-weightable**. Every vehicle now
157
+ carries a documented, cited, qualitative immune + safety + efficacy profile — so you can ask for a *balance*
158
+ (AAV is safe by integration but neutralizing-antibody/pre-existing-immunity limited; lentivirus is a highly
159
+ efficacious integrator but its genotoxicity is the dominant concern). Crucially, the in-vivo immune
160
+ **magnitude** stays a declared known-unknown — v5.1 surfaces documented priors, it does **not** predict a
161
+ patient-specific immune response.
162
+
163
+ | Workstream | What it adds | Result |
164
+ |---|---|---|
165
+ | **IMMUNE config** | `immune_safety` block on all 8 vehicles in `configs/delivery_vehicles.yaml` | documented ordinal (low/moderate/high) priors for pre-existing immunity, neutralizing antibody, innate/adaptive immune, **genotoxicity**, efficacy — every `immune_doi` Crossref-verified and in the curated-DOI set |
166
+ | **IMMUNE planner** | `planner/delivery_immunology.py` — `safety_efficacy_profile()` / `recommend_delivery()` | two **separate** safety sub-axes (`immune_score` reversible vs `genotox_score` permanent), never collapsed; headline `safety_score = min(...)` (worst-axis); ranks the palette along the safety↔efficacy frontier by a **user weight** |
167
+ | **IMMUNE verify** | `Verdict.delivery_profile` + `delivery_immune_profile` scope flag | `verify()` surfaces the documented tradeoff for a chosen vehicle, always attaching the `in_vivo_immunogenicity` known-unknown flag — never adding confidence, never predicting a magnitude |
168
+
169
+ See `prereg/ws_immune.yaml`.
170
+
136
171
  ## What is new in v5.0 — the Co-Scientist (smart because it is grounded)
137
172
 
138
173
  v5.0 matures the reasoning layer on top of everything beneath it. Given a goal and an intent, PEN-STACK
@@ -2,10 +2,12 @@
2
2
 
3
3
  # PEN-STACK
4
4
 
5
- ### The Writable Genome - open infrastructure for genome *writing*
5
+ ### The verification & grounding substrate for genome-writing AI — matured into a co-scientist
6
6
 
7
- *Editing tools tell you **how** to change a base. PEN-STACK tells you **where** in the genome you can safely
8
- and durably write new DNA, **which enzyme** can write it there, and **how** to design the write end-to-end.*
7
+ *The foundation models *generate*; PEN-STACK *checks*. It tells you **where** in the genome you can safely and
8
+ durably write, **which enzyme** can write it there, and **how** to design the write end-to-end — then verifies
9
+ every design against rule-grounded mechanism, reports calibrated confidence, cites its reasoning, and says
10
+ "out of scope" rather than guess. Every number comes from a validated tool; nothing is fabricated.*
9
11
 
10
12
  [![PyPI](https://img.shields.io/pypi/v/pen-stack.svg)](https://pypi.org/project/pen-stack/)
11
13
  [![CI](https://github.com/ahmedanees-m/pen-stack/actions/workflows/ci.yml/badge.svg)](https://github.com/ahmedanees-m/pen-stack/actions/workflows/ci.yml)
@@ -14,7 +16,7 @@ and durably write new DNA, **which enzyme** can write it there, and **how** to d
14
16
  [![codecov](https://codecov.io/gh/ahmedanees-m/pen-stack/branch/main/graph/badge.svg)](https://codecov.io/gh/ahmedanees-m/pen-stack)
15
17
  [![License: MIT](https://img.shields.io/badge/License-MIT-informational.svg)](LICENSE)
16
18
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
17
- [![Version](https://img.shields.io/badge/version-5.0.0-blue.svg)](CHANGELOG.md)
19
+ [![Version](https://img.shields.io/badge/version-5.2.0-blue.svg)](CHANGELOG.md)
18
20
  [![Tests](https://img.shields.io/badge/tests-240%20passing-success.svg)](tests/)
19
21
  [![Lint: ruff](https://img.shields.io/badge/lint-ruff-purple.svg)](https://github.com/astral-sh/ruff)
20
22
  [![Runtime: Docker](https://img.shields.io/badge/runtime-docker-2496ED.svg)](docker/)
@@ -58,6 +60,39 @@ Two questions gate every genome-writing project, and before PEN-STACK no resourc
58
60
  Everything is built on bulk-downloadable public data, runs on a single GPU, and is validated **blind** against
59
61
  a pre-registered, honest baseline before release.
60
62
 
63
+ ## What is new in v5.2 — Computed genotoxicity oracle (data, not a documented tier)
64
+
65
+ v5.1 scored genotoxicity as a documented `low/moderate/high` tier. v5.2 makes it **computed from data** for
66
+ integrating vectors: the observed enrichment of a vector class's integration sites near COSMIC oncogenes
67
+ (VISDB integration catalogues × the Phase-1 COSMIC-CGC oncogene annotation), surfaced through the v4.0
68
+ `OracleResult` contract. The in-vivo clonal / leukemogenesis **outcome** stays a known-unknown — this is a
69
+ relative integration-*preference* signal, not a per-patient oncogenesis probability.
70
+
71
+ | Workstream | What it adds | Result |
72
+ |---|---|---|
73
+ | **GENOTOX build** | `scripts/p52_build_genotox_oracle.py` → committed `configs/genotoxicity_oracle.yaml` | per integrating class: `P(site within 50 kb of a COSMIC oncogene)`, enrichment vs background, CI, n — from VISDB × COSMIC CGC v104 (raw data stays on the VM; only the auditable summary ships) |
74
+ | **GENOTOX oracle** | `planner/genotoxicity_oracle.py` (`OracleResult`, `output_kind="baseline"`) | `genotox_score = min(1, 1/enrichment)`; non-integrating → 1.0 by mechanism; **abstains** when it has no computed class (never fabricates); small-n classes flagged `extrapolating` |
75
+ | **wired into v5.1 balance** | `safety_efficacy_profile()` prefers computed genotox, falls back to the documented tier | **lentiviral 2.08×** vs **gammaretroviral 5.65×** oncogene-proximity enrichment — reproduces the lentivirus-safer-than-gammaretrovirus ordering **from data**; computed LV score (0.48) **validates** the v5.1 documented tier (0.5) |
76
+
77
+ See `prereg/ws_genotox.yaml` and the `delivery_genotoxicity` scope card.
78
+
79
+ ## What is new in v5.1 — Delivery immunology (the safety↔efficacy balance)
80
+
81
+ v5.1 makes the delivery palette's **safety↔efficacy tradeoff legible and user-weightable**. Every vehicle now
82
+ carries a documented, cited, qualitative immune + safety + efficacy profile — so you can ask for a *balance*
83
+ (AAV is safe by integration but neutralizing-antibody/pre-existing-immunity limited; lentivirus is a highly
84
+ efficacious integrator but its genotoxicity is the dominant concern). Crucially, the in-vivo immune
85
+ **magnitude** stays a declared known-unknown — v5.1 surfaces documented priors, it does **not** predict a
86
+ patient-specific immune response.
87
+
88
+ | Workstream | What it adds | Result |
89
+ |---|---|---|
90
+ | **IMMUNE config** | `immune_safety` block on all 8 vehicles in `configs/delivery_vehicles.yaml` | documented ordinal (low/moderate/high) priors for pre-existing immunity, neutralizing antibody, innate/adaptive immune, **genotoxicity**, efficacy — every `immune_doi` Crossref-verified and in the curated-DOI set |
91
+ | **IMMUNE planner** | `planner/delivery_immunology.py` — `safety_efficacy_profile()` / `recommend_delivery()` | two **separate** safety sub-axes (`immune_score` reversible vs `genotox_score` permanent), never collapsed; headline `safety_score = min(...)` (worst-axis); ranks the palette along the safety↔efficacy frontier by a **user weight** |
92
+ | **IMMUNE verify** | `Verdict.delivery_profile` + `delivery_immune_profile` scope flag | `verify()` surfaces the documented tradeoff for a chosen vehicle, always attaching the `in_vivo_immunogenicity` known-unknown flag — never adding confidence, never predicting a magnitude |
93
+
94
+ See `prereg/ws_immune.yaml`.
95
+
61
96
  ## What is new in v5.0 — the Co-Scientist (smart because it is grounded)
62
97
 
63
98
  v5.0 matures the reasoning layer on top of everything beneath it. Given a goal and an intent, PEN-STACK
@@ -0,0 +1,185 @@
1
+ # PEN-STACK v3.3 — Delivery vehicle palette (WS-D / North-Star §4). The substrate must score and constrain
2
+ # the WHOLE delivery palette, not just dual-AAV. Each row: cargo capacity, integration, division dependence,
3
+ # immunogenicity PRIOR (qualitative; MAGNITUDE is a known-unknown — never predicted), re-dosability, tropism,
4
+ # ex/in-vivo, compatible cargo form {DNA, mRNA, RNP}, and >=1 DOI. Values cited to 2026 sources.
5
+ # `constraint_key` maps to configs/delivery_constraints.yaml for the sequence-level scan.
6
+ #
7
+ # v5.1 — `immune_safety`: a DOCUMENTED, CITED, QUALITATIVE (low/moderate/high) immune + safety + efficacy
8
+ # profile per vehicle, for the safety<->efficacy balance (planner/delivery_immunology.py). These are ordinal
9
+ # DOCUMENTED PRIORS from the literature — NOT a predicted, patient- or construct-specific immune magnitude
10
+ # (that stays a known-unknown / scope flag, `in_vivo_immunogenicity`, never predicted). `genotoxicity` = the
11
+ # integration / insertional-mutagenesis risk; `efficacy` = transduction/integration efficiency.
12
+
13
+ version: "1.1"
14
+
15
+ vehicles:
16
+ AAV_single:
17
+ cargo_capacity_bp: 4700
18
+ integrating: false # episomal
19
+ division_dependent: false
20
+ immunogenicity_prior: "moderate-high; pre-existing NAbs exclude 30-60% of patients"
21
+ re_dosable: false
22
+ tropism: "serotype-dependent (liver, muscle, CNS, retina)"
23
+ in_vivo: true
24
+ compatible_cargo_form: [DNA]
25
+ constraint_key: AAV
26
+ dois: ["10.1038/s41573-019-0012-9"]
27
+ immune_safety:
28
+ preexisting_immunity: high # serotype-dependent; seroprevalence ~30-60% of patients
29
+ neutralizing_antibody: high # pre-existing + vector-elicited NAbs; exclude/relapse risk
30
+ innate_immune: low
31
+ adaptive_immune: moderate # capsid-directed CD8 T-cell responses
32
+ genotoxicity: low # episomal, non-integrating
33
+ efficacy: high # efficient in-vivo transduction (cargo-limited ~4.7 kb)
34
+ tradeoff: "safe vector (non-integrating, low genotoxicity) BUT pre-existing/elicited NAbs limit eligibility and prevent re-dosing"
35
+ immune_dois: ["10.1182/blood-2013-01-306647", "10.1089/hum.2009.182", "10.1016/j.ymthe.2019.12.010"]
36
+
37
+ AAV_dual:
38
+ cargo_capacity_bp: 9000 # split across 2 capsids (~9 kb); efficiency drops sharply
39
+ integrating: false
40
+ division_dependent: false
41
+ immunogenicity_prior: "as AAV; split lowers efficiency"
42
+ re_dosable: false
43
+ tropism: "serotype-dependent"
44
+ in_vivo: true
45
+ compatible_cargo_form: [DNA]
46
+ constraint_key: AAV
47
+ dois: ["10.1128/JVI.79.15.9933-9944.2005"] # Grieger & Samulski 2005, AAV packaging capacity
48
+ immune_safety:
49
+ preexisting_immunity: high # same AAV capsid immunology as single
50
+ neutralizing_antibody: high
51
+ innate_immune: low
52
+ adaptive_immune: moderate
53
+ genotoxicity: low # episomal
54
+ efficacy: moderate # split across 2 capsids -> co-transduction needed, efficiency drops
55
+ tradeoff: "as AAV (non-integrating, NAb-limited) AND split-capsid co-transduction lowers efficiency"
56
+ immune_dois: ["10.1182/blood-2013-01-306647", "10.1089/hum.2009.182"]
57
+
58
+ lentivirus:
59
+ cargo_capacity_bp: 8000
60
+ integrating: true # semi-random integration
61
+ division_dependent: false # integrates in non-dividing too; strong in dividing
62
+ immunogenicity_prior: "moderate"
63
+ re_dosable: false
64
+ tropism: "broad (VSV-G pseudotyped)"
65
+ ex_vivo: true
66
+ compatible_cargo_form: [DNA]
67
+ constraint_key: lentiviral
68
+ dois: ["10.1126/science.1233151"]
69
+ immune_safety:
70
+ preexisting_immunity: low # pseudotyped, typically ex-vivo (no host pre-immunity to the vector)
71
+ neutralizing_antibody: low # ex-vivo use avoids humoral neutralisation
72
+ innate_immune: low # ex-vivo
73
+ adaptive_immune: low # ex-vivo
74
+ genotoxicity: moderate # INTEGRATING: insertional-mutagenesis risk; SIN-LTR + gene-body bias reduce but do not eliminate it (gamma-retro LMO2 precedent)
75
+ efficacy: high # efficient, STABLE integration; large-ish cargo (~8 kb); transduces non-dividing cells
76
+ tradeoff: "highly efficacious STABLE integration BUT insertional-mutagenesis / genotoxicity is the dominant safety concern (mitigated by SIN design, not eliminated)"
77
+ immune_dois: ["10.1038/s41375-018-0106-0", "10.1038/nbt1216", "10.1126/science.1088547"]
78
+
79
+ helper_dependent_adenovirus:
80
+ cargo_capacity_bp: 35000 # "gutless" HDAd, up to ~35 kb
81
+ integrating: false
82
+ division_dependent: false
83
+ immunogenicity_prior: "high (innate + adaptive)"
84
+ re_dosable: false
85
+ tropism: "liver and others"
86
+ in_vivo: true
87
+ compatible_cargo_form: [DNA]
88
+ constraint_key: plasmid
89
+ dois: ["10.1128/JVI.72.2.926-933.1998"] # multiply-deleted (gutless-class) adenovirus vectors
90
+ immune_safety:
91
+ preexisting_immunity: high # widespread prior adenovirus exposure in the population
92
+ neutralizing_antibody: high # anti-Ad NAbs common; limit systemic in-vivo dosing
93
+ innate_immune: high # potent acute innate/inflammatory response to the capsid
94
+ adaptive_immune: high # strong anti-vector adaptive response
95
+ genotoxicity: low # non-integrating, episomal "gutless" genome
96
+ efficacy: high # very large cargo (~35 kb), efficient hepatic transduction
97
+ tradeoff: "huge cargo + non-integrating BUT strong innate+adaptive anti-Ad immunity and pre-existing NAbs are the dominant safety limit for systemic use"
98
+ immune_dois: ["10.1089/hum.2004.15.1157"]
99
+
100
+ hsv_amplicon:
101
+ cargo_capacity_bp: 100000 # >100 kb
102
+ integrating: false
103
+ division_dependent: false
104
+ immunogenicity_prior: "high; neurotropic"
105
+ re_dosable: false
106
+ tropism: "neurotropic (CNS)"
107
+ in_vivo: true
108
+ compatible_cargo_form: [DNA]
109
+ constraint_key: plasmid
110
+ dois: ["10.1038/nbt1101-1067"] # Wade-Martins 2001, HSV-1 amplicon (iBAC) large genomic-DNA transfer
111
+ immune_safety:
112
+ preexisting_immunity: moderate # prior HSV exposure common, but helper-free amplicon is gene-free of HSV ORFs
113
+ neutralizing_antibody: moderate # anti-HSV humoral immunity in seropositive hosts
114
+ innate_immune: high # immunogenic / inflammatory in CNS
115
+ adaptive_immune: high
116
+ genotoxicity: low # non-integrating, episomal
117
+ efficacy: moderate # massive cargo (>100 kb) + neurotropism, but transient/variable expression
118
+ tradeoff: "unmatched cargo (>100 kb) and CNS tropism BUT immunogenic/inflammatory and expression is transient"
119
+ immune_dois: ["10.1089/hum.2004.15.1157"]
120
+
121
+ lnp_mrna:
122
+ cargo_capacity_bp: 15000 # large RNA payload (mRNA encoding the writer/RNP)
123
+ integrating: false # transient
124
+ division_dependent: false
125
+ immunogenicity_prior: "low/transient"
126
+ re_dosable: true
127
+ tropism: "liver-tropic by default"
128
+ in_vivo: true
129
+ compatible_cargo_form: [mRNA, RNP]
130
+ constraint_key: lnp_mrna
131
+ dois: ["10.1038/s41578-021-00358-0"]
132
+ immune_safety:
133
+ preexisting_immunity: low # no widespread pre-existing immunity to the LNP (anti-PEG is an emerging exception)
134
+ neutralizing_antibody: low # anti-PEG antibodies emerging; can accelerate clearance on repeat dosing
135
+ innate_immune: moderate # transient innate sensing of mRNA / ionizable lipid (mitigated by mod-nucleosides)
136
+ adaptive_immune: low # no anti-vector adaptive memory to a protein capsid
137
+ genotoxicity: low # NON-integrating, transient (no insertional risk)
138
+ efficacy: moderate # transient expression; potent for hepatic RNP/mRNA but durability is short
139
+ re_dosable: yes # repeatable dosing is the key advantage
140
+ tradeoff: "SAFEST profile (non-integrating, transient, re-dosable, low pre-existing immunity) BUT expression is transient and anti-PEG immunity can blunt repeat doses"
141
+ immune_dois: ["10.1016/j.addr.2020.07.024"]
142
+
143
+ evlp:
144
+ cargo_capacity_bp: null # RNP payload (not a DNA packaging limit)
145
+ integrating: false
146
+ division_dependent: false
147
+ immunogenicity_prior: "low (transient, no DNA)"
148
+ re_dosable: true
149
+ tropism: "engineerable (T cells, retina)"
150
+ in_vivo: true
151
+ ex_vivo: true
152
+ compatible_cargo_form: [RNP]
153
+ constraint_key: evlp
154
+ dois: ["10.1016/j.cell.2022.03.045"]
155
+ immune_safety:
156
+ preexisting_immunity: low # protein/RNP payload, no viral capsid; transient
157
+ neutralizing_antibody: low
158
+ innate_immune: low # no DNA, transient delivery
159
+ adaptive_immune: low
160
+ genotoxicity: low # non-integrating RNP, transient nuclease exposure
161
+ efficacy: moderate # engineerable tropism; emerging modality, in-vivo efficiency still maturing
162
+ re_dosable: yes
163
+ tradeoff: "low-immunogenicity transient RNP delivery with engineerable tropism BUT an emerging modality with still-maturing in-vivo efficiency"
164
+ immune_dois: ["10.1016/j.ymthe.2019.12.010"]
165
+
166
+ electroporation:
167
+ cargo_capacity_bp: null # physical; no packaging limit
168
+ integrating: false # depends on cargo
169
+ division_dependent: false
170
+ immunogenicity_prior: "n/a (ex vivo)"
171
+ re_dosable: false
172
+ tropism: "n/a (ex vivo)"
173
+ ex_vivo: true
174
+ compatible_cargo_form: [DNA, mRNA, RNP]
175
+ constraint_key: electroporation
176
+ dois: ["10.1038/nprot.2014.157"]
177
+ immune_safety:
178
+ preexisting_immunity: low # ex-vivo, physical method; no vector immunology
179
+ neutralizing_antibody: low # ex-vivo (n/a in host)
180
+ innate_immune: low # ex-vivo
181
+ adaptive_immune: low # ex-vivo
182
+ genotoxicity: low # cargo-dependent; RNP/transient cargo carries no insertional risk
183
+ efficacy: high # high ex-vivo delivery efficiency across DNA/mRNA/RNP
184
+ tradeoff: "no vector immunology and high ex-vivo efficiency BUT EX-VIVO ONLY (cell harvest/manufacture required) and cytotoxic at high field strength"
185
+ immune_dois: ["10.1016/j.ymthe.2019.12.010"]
@@ -0,0 +1,48 @@
1
+ version: '1.0'
2
+ built: '2026-06-10'
3
+ description: 'computed integration-site genotoxicity oracle: per vector class, the
4
+ observed enrichment of integration sites within window_bp of a COSMIC oncogene vs
5
+ genome background. genotox_score = min(1, 1/enrichment). In-vivo clonal outcome
6
+ is NOT modelled (stays a known-unknown).'
7
+ window_bp: 50000
8
+ genome_background_frac_oncogene_50kb: 0.02211
9
+ inputs:
10
+ visdb: VISDB per-virus hg38 catalogues
11
+ oncogenes: COSMIC CGC v104 (safety_annot)
12
+ provenance_dois:
13
+ - 10.1093/nar/gkz867
14
+ - 10.1038/s41568-018-0060-1
15
+ - 10.1016/S0092-8674(02)00864-4
16
+ - 10.1126/science.1083413
17
+ robust_min_n: 1000
18
+ classes:
19
+ lentiviral:
20
+ virus: HIV
21
+ n_sites: 88743
22
+ frac_oncogene_50kb: 0.04602
23
+ ci95: 0.00138
24
+ enrichment: 2.081
25
+ frac_genotoxic_cis: 0.000293
26
+ median_dist_oncogene: 2339098
27
+ robust: true
28
+ deltaretroviral:
29
+ virus: HTLV
30
+ n_sites: 51508
31
+ frac_oncogene_50kb: 0.02648
32
+ ci95: 0.00139
33
+ enrichment: 1.198
34
+ frac_genotoxic_cis: 0.000369
35
+ median_dist_oncogene: 3766674
36
+ robust: true
37
+ gammaretroviral:
38
+ virus: MLV
39
+ n_sites: 32
40
+ frac_oncogene_50kb: 0.125
41
+ ci95: 0.11459
42
+ enrichment: 5.653
43
+ frac_genotoxic_cis: 0.0
44
+ median_dist_oncogene: 2871705
45
+ robust: false
46
+ vehicle_class:
47
+ lentiviral:
48
+ - lentivirus
@@ -112,3 +112,16 @@ oracles:
112
112
  not_valid_for: "absolute off-target rates; non-bridge writers; a non-recombining background"
113
113
  generalizes_to_unseen_loci: false
114
114
  license: "open (this work)"
115
+
116
+ delivery_genotoxicity: # v5.2 WS-GENOTOX: computed integration-site oncogene-proximity
117
+ family: genome
118
+ version: "visdb+cgc_v104-2026"
119
+ output_kind: baseline # an observed-data comparator (integration catalogues), not generative
120
+ valid_for: "RELATIVE genotoxicity ordering of INTEGRATING vector classes via the observed enrichment of
121
+ integration sites near COSMIC oncogenes (lentiviral vs gammaretroviral, from VISDB x CGC); reproduces the
122
+ lentivirus-safer-than-gammaretrovirus ordering from data"
123
+ not_valid_for: "the IN-VIVO clonal-expansion / leukemogenesis OUTCOME in a patient (a known-unknown); an
124
+ absolute per-insertion oncogenesis probability; non-integrating vectors (no insertional mechanism);
125
+ classes with too few catalogued sites (flagged extrapolating)"
126
+ generalizes_to_unseen_loci: false
127
+ license: "open (this work; VISDB 10.1093/nar/gkz867, COSMIC CGC 10.1038/s41568-018-0060-1)"
@@ -1,2 +1,2 @@
1
1
  """PEN-STACK v3.0 - open infrastructure for genome writing."""
2
- __version__ = "5.0.0"
2
+ __version__ = "5.2.0"
@@ -28,6 +28,13 @@ def curated_dois() -> frozenset[str]:
28
28
  veh = yaml.safe_load(resource("configs/delivery_vehicles.yaml").read_text(encoding="utf-8"))["vehicles"]
29
29
  for v in veh.values():
30
30
  dois.update(v.get("dois", []) or [])
31
+ dois.update((v.get("immune_safety") or {}).get("immune_dois", []) or []) # v5.1 immune priors
32
+ # v5.2 computed-genotoxicity oracle provenance (VISDB, COSMIC CGC, integration-biology refs)
33
+ try:
34
+ gt = yaml.safe_load(resource("configs/genotoxicity_oracle.yaml").read_text(encoding="utf-8"))
35
+ dois.update(gt.get("provenance_dois", []) or [])
36
+ except FileNotFoundError:
37
+ pass
31
38
  gsh = yaml.safe_load(resource("configs/gsh_validated_heldout.yaml").read_text(encoding="utf-8"))["gsh"]
32
39
  for g in gsh:
33
40
  if g.get("doi"):