pen-stack 7.1.2__tar.gz → 7.1.3__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 (566) hide show
  1. {pen_stack-7.1.2 → pen_stack-7.1.3}/CHANGELOG.md +46 -0
  2. {pen_stack-7.1.2 → pen_stack-7.1.3}/CITATION.cff +2 -2
  3. {pen_stack-7.1.2 → pen_stack-7.1.3}/PKG-INFO +17 -14
  4. {pen_stack-7.1.2 → pen_stack-7.1.3}/README.md +16 -13
  5. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/safety/hazard_registry.yaml +63 -0
  6. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/__init__.py +1 -1
  7. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/design/generate.py +14 -3
  8. pen_stack-7.1.3/pen_stack/design/space.py +136 -0
  9. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/safety/registry.py +68 -3
  10. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/safety/screen.py +2 -1
  11. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/server/api.py +22 -3
  12. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack.egg-info/PKG-INFO +17 -14
  13. {pen_stack-7.1.2 → pen_stack-7.1.3}/pyproject.toml +1 -1
  14. pen_stack-7.1.2/pen_stack/design/space.py +0 -85
  15. {pen_stack-7.1.2 → pen_stack-7.1.3}/LICENSE +0 -0
  16. {pen_stack-7.1.2 → pen_stack-7.1.3}/MANIFEST.in +0 -0
  17. {pen_stack-7.1.2 → pen_stack-7.1.3}/bench/run.py +0 -0
  18. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/chat_grounding/README.md +0 -0
  19. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/chat_grounding/SHA256SUMS +0 -0
  20. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/chat_headtohead/README.md +0 -0
  21. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/chat_routing/README.md +0 -0
  22. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/chat_routing/SHA256SUMS +0 -0
  23. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/chat_safety/README.md +0 -0
  24. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/chat_safety/SHA256SUMS +0 -0
  25. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/delivery/SHA256SUMS +0 -0
  26. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/genome_writing_bench/LEADERBOARD.md +0 -0
  27. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/genome_writing_bench/README.md +0 -0
  28. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/genome_writing_bench/SHA256SUMS +0 -0
  29. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/genome_writing_bench/SUBMISSIONS.md +0 -0
  30. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/genome_writing_bench/tasks.yaml +0 -0
  31. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/genome_writing_challenge/README.md +0 -0
  32. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/genome_writing_challenge/SUBMISSIONS.md +0 -0
  33. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/loop/SHA256SUMS +0 -0
  34. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/offtarget/SHA256SUMS +0 -0
  35. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/oracle/SHA256SUMS +0 -0
  36. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/position_effect/README.md +0 -0
  37. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/position_effect/SHA256SUMS +0 -0
  38. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/verify/SHA256SUMS +0 -0
  39. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/writer_efficiency/README.md +0 -0
  40. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/writer_efficiency/SHA256SUMS +0 -0
  41. {pen_stack-7.1.2 → pen_stack-7.1.3}/benchmarks/writespec/SHA256SUMS +0 -0
  42. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/aav_serotype_tropism.yaml +0 -0
  43. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/antipeg.yaml +0 -0
  44. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/atlas_families.yaml +0 -0
  45. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/bridge_offtarget_profile.yaml +0 -0
  46. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/calibration/preexisting_nab_independent.yaml +0 -0
  47. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/capsid_epitope_oracle.yaml +0 -0
  48. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/capsid_sequences.fasta +0 -0
  49. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/cargo_polish.yaml +0 -0
  50. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/cell_types.yaml +0 -0
  51. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/datasets.yaml +0 -0
  52. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/delivery_constraints.yaml +0 -0
  53. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/delivery_rules.yaml +0 -0
  54. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/delivery_vehicles.yaml +0 -0
  55. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/expression/modifiers.yaml +0 -0
  56. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/expression/promoters.yaml +0 -0
  57. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/gates_v3.yaml +0 -0
  58. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/genotoxicity_oracle.yaml +0 -0
  59. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/gsh_validated_heldout.yaml +0 -0
  60. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/intent_weights.yaml +0 -0
  61. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/known_unknowns.yaml +0 -0
  62. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/llm.yaml +0 -0
  63. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/metric_guide.yaml +0 -0
  64. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/mhc_epitope_oracle.yaml +0 -0
  65. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/monitor_queries.yaml +0 -0
  66. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/oracles/execution.yaml +0 -0
  67. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/oracles/reliability.yaml +0 -0
  68. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/oracles/scope_cards.yaml +0 -0
  69. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/rules/delivery.yaml +0 -0
  70. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/rules/fold.yaml +0 -0
  71. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/rules/multiplex.yaml +0 -0
  72. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/rules/payload.yaml +0 -0
  73. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/rules/reachability.yaml +0 -0
  74. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/safety/policy.yaml +0 -0
  75. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/safety/probes.yaml +0 -0
  76. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/score_axes.yaml +0 -0
  77. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/seroprevalence.yaml +0 -0
  78. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/target_sites.yaml +0 -0
  79. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/universe_crosswalk.yaml +0 -0
  80. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/write_types.yaml +0 -0
  81. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/writer_sequences.fasta +0 -0
  82. {pen_stack-7.1.2 → pen_stack-7.1.3}/configs/wtkb_curated.yaml +0 -0
  83. {pen_stack-7.1.2 → pen_stack-7.1.3}/data/curated/bridge_offtarget_energetics.json +0 -0
  84. {pen_stack-7.1.2 → pen_stack-7.1.3}/data/curated/bridge_offtarget_profile_measured.parquet +0 -0
  85. {pen_stack-7.1.2 → pen_stack-7.1.3}/data/curated/gene_coords.parquet +0 -0
  86. {pen_stack-7.1.2 → pen_stack-7.1.3}/data/curated/unified_editor_universe.parquet +0 -0
  87. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/BACKLOG.md +0 -0
  88. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/DEPLOY.md +0 -0
  89. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/INFRA.md +0 -0
  90. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/MCP.md +0 -0
  91. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/RELEASING.md +0 -0
  92. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/REPRO.md +0 -0
  93. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/STABILITY.md +0 -0
  94. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/agent.md +0 -0
  95. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/alphagenome_feasibility.md +0 -0
  96. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/autonomy.md +0 -0
  97. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/benchmark_circularity.md +0 -0
  98. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/biosecurity.md +0 -0
  99. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/build_interface.md +0 -0
  100. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/cards/atlas.md +0 -0
  101. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/cards/durability.md +0 -0
  102. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/cards/offtarget_data.md +0 -0
  103. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/cards/position_effect_data.md +0 -0
  104. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/cards/safety.md +0 -0
  105. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/cards/writer_efficiency_data.md +0 -0
  106. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/challenge.md +0 -0
  107. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/closed_loop.md +0 -0
  108. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/co_scientist.md +0 -0
  109. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/co_scientist_loop.md +0 -0
  110. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/delivery.md +0 -0
  111. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/delivery_immunology.md +0 -0
  112. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/delivery_recommender.md +0 -0
  113. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/digital_twin.md +0 -0
  114. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/dissemination.md +0 -0
  115. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/environment.md +0 -0
  116. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/experiment_design.md +0 -0
  117. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/generative_design.md +0 -0
  118. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/immune_profiler.md +0 -0
  119. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/index.md +0 -0
  120. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/integrations.md +0 -0
  121. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/live_oracles.md +0 -0
  122. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/mechanistic_constraints.md +0 -0
  123. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/offtarget.md +0 -0
  124. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/oracle_mesh.md +0 -0
  125. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/oracles.md +0 -0
  126. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/position_effect.md +0 -0
  127. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/positioning.md +0 -0
  128. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/private_data_formats.md +0 -0
  129. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/quickstart.md +0 -0
  130. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/responsible_use.md +0 -0
  131. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/rule_spec.md +0 -0
  132. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/rules.md +0 -0
  133. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/scope.md +0 -0
  134. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/scorecard.md +0 -0
  135. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/tpe_bench.md +0 -0
  136. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/tutorials/compare-families.md +0 -0
  137. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/tutorials/score-deliverability.md +0 -0
  138. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/tutorials/where-can-i-write.md +0 -0
  139. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/tutorials/which-writer-reaches-locus.md +0 -0
  140. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/uncertainty.md +0 -0
  141. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/verify.md +0 -0
  142. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/verify_service.md +0 -0
  143. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/world_model.md +0 -0
  144. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/writer_efficiency.md +0 -0
  145. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/writer_verification.md +0 -0
  146. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/writespec_bench.md +0 -0
  147. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/writespec_profile.md +0 -0
  148. {pen_stack-7.1.2 → pen_stack-7.1.3}/docs/wtkb.md +0 -0
  149. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/_resources.py +0 -0
  150. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/active/__init__.py +0 -0
  151. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/active/acquire.py +0 -0
  152. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/active/brains.py +0 -0
  153. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/active/campaign.py +0 -0
  154. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/active/design.py +0 -0
  155. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/active/validate.py +0 -0
  156. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/adapt/__init__.py +0 -0
  157. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/adapt/finetune.py +0 -0
  158. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/adapt/ingest.py +0 -0
  159. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/adapt/pipeline.py +0 -0
  160. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/adapt/recalibrate.py +0 -0
  161. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/adapt/report.py +0 -0
  162. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/agent/__init__.py +0 -0
  163. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/agent/cite.py +0 -0
  164. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/agent/co_scientist.py +0 -0
  165. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/agent/epistemic.py +0 -0
  166. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/agent/guardrails.py +0 -0
  167. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/agent/mcp_server.py +0 -0
  168. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/agent/orchestrator.py +0 -0
  169. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/agent/orchestrator_live.py +0 -0
  170. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/agent/pen_agent.py +0 -0
  171. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/agent/scope.py +0 -0
  172. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/agent/tools.py +0 -0
  173. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/api/__init__.py +0 -0
  174. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/api/manifest.py +0 -0
  175. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/atlas/__init__.py +0 -0
  176. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/atlas/build_wtkb.py +0 -0
  177. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/atlas/crosslink.py +0 -0
  178. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/atlas/expand.py +0 -0
  179. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/atlas/guide_design.py +0 -0
  180. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/atlas/schema.py +0 -0
  181. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/atlas/scorecard.py +0 -0
  182. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/atlas/universe.py +0 -0
  183. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/atlas/variant_propose.py +0 -0
  184. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/atlas/writer_efficiency.py +0 -0
  185. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/atlas/writer_predict.py +0 -0
  186. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/atlas/writer_recommend.py +0 -0
  187. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/atlas/writer_verify.py +0 -0
  188. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/bridge/__init__.py +0 -0
  189. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/bridge/activity.py +0 -0
  190. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/bridge/cli.py +0 -0
  191. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/bridge/fold_qc.py +0 -0
  192. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/bridge/guide_qc.py +0 -0
  193. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/bridge/ingest.py +0 -0
  194. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/bridge/offtarget.py +0 -0
  195. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/bridge/offtarget_energetics.py +0 -0
  196. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/bridge/ortholog_screen.py +0 -0
  197. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/bridge/pipeline.py +0 -0
  198. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/build/__init__.py +0 -0
  199. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/build/cloudlab.py +0 -0
  200. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/build/ingest.py +0 -0
  201. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/build/protocol.py +0 -0
  202. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/build/simlab.py +0 -0
  203. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/cli.py +0 -0
  204. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/data/__init__.py +0 -0
  205. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/data/encode.py +0 -0
  206. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/data/genome.py +0 -0
  207. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/data/ingest_chromatin.py +0 -0
  208. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/data/ingest_integration.py +0 -0
  209. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/data/ingest_safety_annot.py +0 -0
  210. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/data/ingest_trip.py +0 -0
  211. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/design/__init__.py +0 -0
  212. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/design/capsid_generate.py +0 -0
  213. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/design/pareto.py +0 -0
  214. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/design/writer_variants.py +0 -0
  215. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/env/__init__.py +0 -0
  216. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/env/genome_writing_env.py +0 -0
  217. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/env/policies.py +0 -0
  218. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/graph/__init__.py +0 -0
  219. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/graph/build.py +0 -0
  220. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/graph/cell_types.py +0 -0
  221. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/graph/ingest.py +0 -0
  222. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/graph/query.py +0 -0
  223. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/graph/schema.py +0 -0
  224. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/loop/__init__.py +0 -0
  225. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/loop/continual.py +0 -0
  226. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/loop/cycle.py +0 -0
  227. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/loop/drift.py +0 -0
  228. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/mech/__init__.py +0 -0
  229. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/mech/classify_atlas.py +0 -0
  230. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/mech/whitelist.py +0 -0
  231. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/monitor/__init__.py +0 -0
  232. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/monitor/europepmc.py +0 -0
  233. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/monitor/run.py +0 -0
  234. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/monitor/triage.py +0 -0
  235. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/oracles/__init__.py +0 -0
  236. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/oracles/affinity.py +0 -0
  237. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/oracles/cache.py +0 -0
  238. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/oracles/energetics.py +0 -0
  239. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/oracles/genome.py +0 -0
  240. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/oracles/protein_design.py +0 -0
  241. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/oracles/reliability.py +0 -0
  242. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/oracles/rna.py +0 -0
  243. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/oracles/schema.py +0 -0
  244. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/oracles/status.py +0 -0
  245. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/oracles/structure.py +0 -0
  246. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/oracles/structure_run.py +0 -0
  247. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/oracles/vcell.py +0 -0
  248. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/__init__.py +0 -0
  249. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/ada_risk.py +0 -0
  250. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/antipeg_oracle.py +0 -0
  251. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/capsid_epitope_oracle.py +0 -0
  252. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/cargo.py +0 -0
  253. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/cargo_polish.py +0 -0
  254. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/delivery.py +0 -0
  255. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/delivery_constraints.py +0 -0
  256. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/delivery_immune.py +0 -0
  257. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/delivery_immunology.py +0 -0
  258. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/delivery_predict.py +0 -0
  259. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/delivery_vehicles.py +0 -0
  260. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/genotoxicity_oracle.py +0 -0
  261. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/immune_mhc2.py +0 -0
  262. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/immune_profile.py +0 -0
  263. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/innate_sensing.py +0 -0
  264. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/multiplex.py +0 -0
  265. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/optimize.py +0 -0
  266. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/pipeline.py +0 -0
  267. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/report.py +0 -0
  268. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/router.py +0 -0
  269. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/seroprevalence_oracle.py +0 -0
  270. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/planner/target_site.py +0 -0
  271. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/rag/__init__.py +0 -0
  272. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/rag/corpus.py +0 -0
  273. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/rag/embed.py +0 -0
  274. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/rag/ground.py +0 -0
  275. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/rag/index.py +0 -0
  276. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/rag/llm.py +0 -0
  277. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/rag/qa.py +0 -0
  278. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/rag/retrieve.py +0 -0
  279. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/rules/__init__.py +0 -0
  280. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/rules/evaluators.py +0 -0
  281. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/rules/loader.py +0 -0
  282. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/rules/schema.py +0 -0
  283. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/rules/solver.py +0 -0
  284. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/rules/spec.py +0 -0
  285. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/safety/__init__.py +0 -0
  286. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/safety/audit.py +0 -0
  287. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/safety/gate.py +0 -0
  288. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/safety/policy.py +0 -0
  289. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/safety/redteam.py +0 -0
  290. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/safety/standards.py +0 -0
  291. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/score/__init__.py +0 -0
  292. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/score/recalibrate.py +0 -0
  293. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/score/therapeutic.py +0 -0
  294. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/server/__init__.py +0 -0
  295. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/spec/__init__.py +0 -0
  296. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/spec/clarify.py +0 -0
  297. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/spec/extract.py +0 -0
  298. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/spec/resolvers/__init__.py +0 -0
  299. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/spec/resolvers/cell.py +0 -0
  300. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/spec/resolvers/chem.py +0 -0
  301. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/spec/resolvers/feature.py +0 -0
  302. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/spec/resolvers/gene.py +0 -0
  303. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/spec/resolvers/locus.py +0 -0
  304. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/spec/resolvers/phenotype.py +0 -0
  305. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/spec/satisfy.py +0 -0
  306. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/spec/service.py +0 -0
  307. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/spec/writespec.py +0 -0
  308. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/twin/__init__.py +0 -0
  309. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/twin/calibrate.py +0 -0
  310. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/twin/data/__init__.py +0 -0
  311. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/twin/data/position_effect.py +0 -0
  312. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/twin/mechanistic.py +0 -0
  313. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/twin/outcome.py +0 -0
  314. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/twin/position_effect.py +0 -0
  315. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/ui/__init__.py +0 -0
  316. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/ui/app.py +0 -0
  317. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/__init__.py +0 -0
  318. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/adapt_demo.py +0 -0
  319. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/agent_eval.py +0 -0
  320. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/bench_adversarial_tasks.py +0 -0
  321. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/bench_coscientist_tasks.py +0 -0
  322. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/bench_graph_tasks.py +0 -0
  323. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/bench_rule_tasks.py +0 -0
  324. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/bench_trust_tasks.py +0 -0
  325. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/bench_writetype_tasks.py +0 -0
  326. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/blind_gsh_discovery.py +0 -0
  327. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/cargo_directionality.py +0 -0
  328. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/closed_loop.py +0 -0
  329. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/durability_baselines.py +0 -0
  330. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/experiment_design.py +0 -0
  331. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/expr_controls.py +0 -0
  332. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/forward_hypotheses.py +0 -0
  333. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/generative_design.py +0 -0
  334. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/guide_qc_demo.py +0 -0
  335. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/heldout_celltype_expr.py +0 -0
  336. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/immune_calibration.py +0 -0
  337. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/intent_specification.py +0 -0
  338. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/known_biology_expr.py +0 -0
  339. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/offtarget_energetics_eval.py +0 -0
  340. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/out_of_scope_refusal.py +0 -0
  341. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/outcome_calibration.py +0 -0
  342. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/outcome_prediction.py +0 -0
  343. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/paper3_benchmark.py +0 -0
  344. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/paper4_real_validation.py +0 -0
  345. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/paper4_validation.py +0 -0
  346. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/protocol_safety.py +0 -0
  347. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/safety_screening.py +0 -0
  348. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/selective_prediction.py +0 -0
  349. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/seq_vs_measured.py +0 -0
  350. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/target_site_controls.py +0 -0
  351. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/uncertainty_eval.py +0 -0
  352. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/ungrounded_baseline.py +0 -0
  353. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/within_locus_ranking.py +0 -0
  354. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/validate/writer_recovery.py +0 -0
  355. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/verify/__init__.py +0 -0
  356. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/verify/proof.py +0 -0
  357. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/verify/schema.py +0 -0
  358. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/verify/service.py +0 -0
  359. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/web/__init__.py +0 -0
  360. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/web/guide.py +0 -0
  361. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/web/llm.py +0 -0
  362. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/web/llm_provider.py +0 -0
  363. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/web/router.py +0 -0
  364. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/web/server.py +0 -0
  365. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/web/tools.py +0 -0
  366. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/__init__.py +0 -0
  367. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/chromatin_seq.py +0 -0
  368. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/durability.py +0 -0
  369. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/export_tracks.py +0 -0
  370. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/features.py +0 -0
  371. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/gsh_baseline.py +0 -0
  372. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/mesh_features.py +0 -0
  373. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/offtarget_assay.py +0 -0
  374. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/offtarget_data.py +0 -0
  375. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/offtarget_predict.py +0 -0
  376. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/ood.py +0 -0
  377. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/providers.py +0 -0
  378. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/safety.py +0 -0
  379. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/structure3d.py +0 -0
  380. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/uncertainty.py +0 -0
  381. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack/wgenome/writability.py +0 -0
  382. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack.egg-info/SOURCES.txt +0 -0
  383. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack.egg-info/dependency_links.txt +0 -0
  384. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack.egg-info/entry_points.txt +0 -0
  385. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack.egg-info/requires.txt +0 -0
  386. {pen_stack-7.1.2 → pen_stack-7.1.3}/pen_stack.egg-info/top_level.txt +0 -0
  387. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_phase0.json +0 -0
  388. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_phase1_5.json +0 -0
  389. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_phase2.json +0 -0
  390. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_phase3.json +0 -0
  391. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_a.json +0 -0
  392. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_acq.json +0 -0
  393. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_aldesign.json +0 -0
  394. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_alvalidate.json +0 -0
  395. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_atlas.json +0 -0
  396. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_b.json +0 -0
  397. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_ba.json +0 -0
  398. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_ba_v33.json +0 -0
  399. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_ba_v45.json +0 -0
  400. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_bench.json +0 -0
  401. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_c.json +0 -0
  402. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_cal.json +0 -0
  403. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_calib.json +0 -0
  404. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_challenge.json +0 -0
  405. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_chat.json +0 -0
  406. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_cite.json +0 -0
  407. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_closedloop.json +0 -0
  408. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_continual.json +0 -0
  409. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_cosci2.json +0 -0
  410. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_crit.json +0 -0
  411. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_ct.json +0 -0
  412. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_d.json +0 -0
  413. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_delivery.json +0 -0
  414. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_drift.json +0 -0
  415. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_e.json +0 -0
  416. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_env.json +0 -0
  417. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_ep.json +0 -0
  418. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_epitope.json +0 -0
  419. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_expr2.json +0 -0
  420. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_f.json +0 -0
  421. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_frontend.json +0 -0
  422. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_g.json +0 -0
  423. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_gen.json +0 -0
  424. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_genotox.json +0 -0
  425. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_graph.json +0 -0
  426. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_h.json +0 -0
  427. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_hybrid.json +0 -0
  428. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_immune.json +0 -0
  429. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_immune2.json +0 -0
  430. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_ingest.json +0 -0
  431. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_innate.json +0 -0
  432. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_loop.json +0 -0
  433. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_manifest.json +0 -0
  434. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_mc.json +0 -0
  435. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_mcp.json +0 -0
  436. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_mech.json +0 -0
  437. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_mon.json +0 -0
  438. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_o.json +0 -0
  439. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_offtarget.json +0 -0
  440. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_openapi.json +0 -0
  441. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_oracle.json +0 -0
  442. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_orch.json +0 -0
  443. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_outcome.json +0 -0
  444. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_pareto.json +0 -0
  445. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_peg.json +0 -0
  446. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_penchat.json +0 -0
  447. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_plan.json +0 -0
  448. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_policy.json +0 -0
  449. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_profile.json +0 -0
  450. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_proto.json +0 -0
  451. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_r.json +0 -0
  452. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_redteam.json +0 -0
  453. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_route.json +0 -0
  454. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_screen.json +0 -0
  455. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_seroprev.json +0 -0
  456. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_simlab.json +0 -0
  457. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_twincal.json +0 -0
  458. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_uq.json +0 -0
  459. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_v.json +0 -0
  460. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_vcell.json +0 -0
  461. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_verify.json +0 -0
  462. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_writer.json +0 -0
  463. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_writespec.json +0 -0
  464. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/SHA256_LOCK_ws_wv.json +0 -0
  465. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/paper1.yaml +0 -0
  466. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/paper2.yaml +0 -0
  467. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/paper3.yaml +0 -0
  468. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/paper4.yaml +0 -0
  469. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/phase0.yaml +0 -0
  470. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_a.yaml +0 -0
  471. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_acq.yaml +0 -0
  472. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_aldesign.yaml +0 -0
  473. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_alvalidate.yaml +0 -0
  474. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_atlas.yaml +0 -0
  475. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_b.yaml +0 -0
  476. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_ba.yaml +0 -0
  477. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_ba_v33.yaml +0 -0
  478. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_ba_v45.yaml +0 -0
  479. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_bench.yaml +0 -0
  480. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_c.yaml +0 -0
  481. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_cal.yaml +0 -0
  482. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_calib.yaml +0 -0
  483. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_challenge.yaml +0 -0
  484. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_chat.yaml +0 -0
  485. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_cite.yaml +0 -0
  486. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_closedloop.yaml +0 -0
  487. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_continual.yaml +0 -0
  488. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_cosci2.yaml +0 -0
  489. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_crit.yaml +0 -0
  490. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_ct.yaml +0 -0
  491. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_d.yaml +0 -0
  492. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_delivery.yaml +0 -0
  493. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_drift.yaml +0 -0
  494. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_e.yaml +0 -0
  495. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_env.yaml +0 -0
  496. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_ep.yaml +0 -0
  497. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_epitope.yaml +0 -0
  498. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_expr2.yaml +0 -0
  499. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_f.yaml +0 -0
  500. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_frontend.yaml +0 -0
  501. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_g.yaml +0 -0
  502. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_gen.yaml +0 -0
  503. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_genotox.yaml +0 -0
  504. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_graph.yaml +0 -0
  505. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_h.yaml +0 -0
  506. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_hybrid.yaml +0 -0
  507. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_immune.yaml +0 -0
  508. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_immune2.yaml +0 -0
  509. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_ingest.yaml +0 -0
  510. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_innate.yaml +0 -0
  511. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_loop.yaml +0 -0
  512. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_manifest.yaml +0 -0
  513. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_mc.yaml +0 -0
  514. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_mcp.yaml +0 -0
  515. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_mech.yaml +0 -0
  516. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_mon.yaml +0 -0
  517. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_o.yaml +0 -0
  518. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_offtarget.yaml +0 -0
  519. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_openapi.yaml +0 -0
  520. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_oracle.yaml +0 -0
  521. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_orch.yaml +0 -0
  522. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_outcome.yaml +0 -0
  523. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_pareto.yaml +0 -0
  524. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_peg.yaml +0 -0
  525. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_penchat.yaml +0 -0
  526. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_plan.yaml +0 -0
  527. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_policy.yaml +0 -0
  528. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_profile.yaml +0 -0
  529. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_proto.yaml +0 -0
  530. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_r.yaml +0 -0
  531. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_redteam.yaml +0 -0
  532. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_route.yaml +0 -0
  533. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_screen.yaml +0 -0
  534. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_seroprev.yaml +0 -0
  535. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_simlab.yaml +0 -0
  536. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_twincal.yaml +0 -0
  537. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_uq.yaml +0 -0
  538. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_v.yaml +0 -0
  539. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_vcell.yaml +0 -0
  540. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_verify.yaml +0 -0
  541. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_writer.yaml +0 -0
  542. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_writespec.yaml +0 -0
  543. {pen_stack-7.1.2 → pen_stack-7.1.3}/prereg/ws_wv.yaml +0 -0
  544. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/build_capsid_fitness.py +0 -0
  545. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/build_rag_corpus.py +0 -0
  546. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/calibrate_immune_axes.py +0 -0
  547. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/fetch_licensed_sources.py +0 -0
  548. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/offtarget_chromatin_incremental.py +0 -0
  549. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/offtarget_chromatin_matched.py +0 -0
  550. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/offtarget_chromatin_validation.py +0 -0
  551. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/p1_build_atlas.py +0 -0
  552. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/p1_build_durability.py +0 -0
  553. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/p1_build_position_effect.py +0 -0
  554. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/p1_build_writer_eff.py +0 -0
  555. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/p1_export_tracks.py +0 -0
  556. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/p1_safety_concordance.py +0 -0
  557. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/p1_train_safety.py +0 -0
  558. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/p1_validation_report.py +0 -0
  559. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/p2_build_atlas.py +0 -0
  560. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/p3_benchmark_report.py +0 -0
  561. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/p4_genome_scan.py +0 -0
  562. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/p52_build_genotox_oracle.py +0 -0
  563. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/p53_build_epitope_oracle.py +0 -0
  564. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/ws_b_report.py +0 -0
  565. {pen_stack-7.1.2 → pen_stack-7.1.3}/scripts/ws_c_report.py +0 -0
  566. {pen_stack-7.1.2 → pen_stack-7.1.3}/setup.cfg +0 -0
@@ -3,6 +3,52 @@
3
3
  All notable changes to PEN-STACK are documented here. This file follows
4
4
  [Keep a Changelog](https://keepachangelog.com/).
5
5
 
6
+ ## [7.1.3] - 2026-06-26 - Designer correctness: Guardian biosecurity + calibrated confidence
7
+
8
+ ### Fixed
9
+ - **CRITICAL (Designer / Guardian biosecurity):** Hazardous cargo functions (e.g. furin-cleavage viral
10
+ tropism-enhancement, dominant-negative tumor-suppressor ablation) passed the Designer as "Safety: Clear" with
11
+ full survivor tables. Several root causes, all fixed:
12
+ - The hazard registry (`configs/safety/hazard_registry.yaml`) had **no signatures** for engineered viral tropism
13
+ enhancement or oncogenic tumor-suppressor ablation. Added `FUNC-VIRAL-TROPISM-ENHANCE` (furin cleavage /
14
+ receptor-binding / tropism, high severity) and `FUNC-ONCOGENIC-SUPPRESSOR` (dominant-negative TP53 / RB / PTEN,
15
+ apoptosis-checkpoint ablation, high severity), both DURC / HHS-P3CO categories.
16
+ - **Oncogenic-manipulation PATTERN screen** (`oncogenic_manipulation` in the registry +
17
+ `HazardRegistry.oncogenic_flags`): a flat keyword list is brittle to paraphrase — a red-team pass found the
18
+ Guardian caught only **1/8** mechanism/synonym phrasings ("R175H p53 abolishing transactivation", "PTEN
19
+ knockout", "RAS G12D constitutive activation", "hTERT immortalization", "APC frameshift", "EGFR
20
+ ligand-independent activation", "NF1+BAX/BAK knockout"). The pattern screen flags the *combination*
21
+ `(tumor-suppressor + disruptive verb)` OR `(oncogene + activating signature)` OR `immortalization`, which
22
+ catches **8/8** while the deliberate asymmetry spares therapy with **no allow-list** — restoring a suppressor or
23
+ silencing an oncogene matches neither, so "p53 correction to restore apoptosis", "TRAC/CCR5 knockout",
24
+ "knock-down of mutant KRAS" stay clear (**11/11** benign). Disposition is escalate (dual-use → human review).
25
+ - **Keyword matcher hardened** (`_kw_match`): a plain substring test made the ricin abbreviation `"rip"` fire
26
+ inside **"transc-rip-tion"** (a word in almost every editing design → benign cassettes false-refused as ricin),
27
+ and let a hyphenated `"furin-cleavage"` slip past the space-form keyword. Matching is now separator-insensitive
28
+ (`-`/`_`/space unified) and word-boundary anchored, fixing both the false positive and the evasion.
29
+ - The goal-based candidate path (`pen_stack/design/space.py::candidate_space`) **dropped** the goal's
30
+ `cargo_function`, so the Guardian in `verify()` screened nothing. It is now propagated onto every swept
31
+ candidate. The `/generate` endpoint additionally screens the goal's cargo function FIRST and returns an explicit
32
+ biosecurity refusal (`refused: true` + the safety verdict) so an empty table is correctly attributed to a
33
+ refusal, not a silent "no candidates".
34
+ - **CRITICAL (Designer / calibration):** Confidence was a constant `1.00 · [0.56, 0.71]` for every input because the
35
+ page hardcoded fake planner scores (0.7 / 0.6 / 0.5) on each candidate. The page now submits the design GOAL and
36
+ the engine plans real writable sites with grounded per-locus safety / durability / writer-activity, so the
37
+ confidence band is genuinely calibrated (it differs by locus/vehicle, e.g. F9 → `[0.866, 0.972]`, and is absent
38
+ for a refused design). `web/src/pages/Designer.jsx` rewritten to send a goal and render the refused / empty /
39
+ survivor states distinctly.
40
+ - **Designer (cell types without a measured atlas):** a goal in a cell type with no writability atlas (cd8_t /
41
+ pbmc / h1_hesc / ipsc) returned an empty table, because the planner-backed `candidate_space` needs `plan_write`.
42
+ `generate_designs` now falls back to `space.vehicle_sweep(goal)`: it sweeps the capacity-compatible vehicles,
43
+ carries `cargo_function` (the Guardian still screens), runs full legality + biosecurity discrimination, and
44
+ ABSTAINS on the calibrated confidence (no fabricated band) — surfaced as "abstained, no measured atlas for this
45
+ cell type". `candidate_space` still returns `[]` without the atlas; `generate_designs(candidates=[])` still
46
+ returns `[]`.
47
+ - **Designer (administration context):** the vehicle sweep now filters by the goal's `in_vivo` flag using the
48
+ curated `in_vivo` / `ex_vivo` route flags in `configs/delivery_vehicles.yaml` (an ex-vivo goal keeps
49
+ lentivirus / electroporation / eVLP; an in-vivo goal keeps AAV / LNP / HDAd / HSV / eVLP). Grounded from the
50
+ curated palette, not a clinical claim; `in_vivo=None` keeps all (existing callers/tests unchanged).
51
+
6
52
  ## [7.1.2] - 2026-06-25 - PEN-CHAT: chat-response latency fix
7
53
 
8
54
  ### Fixed
@@ -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: 7.1.2
5
- date-released: 2026-06-25
4
+ version: 7.1.3
5
+ date-released: 2026-06-26
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: 7.1.2
3
+ Version: 7.1.3
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
@@ -162,9 +162,10 @@ flowchart TB
162
162
  | Generative designer | `pen_stack.design` | Proposes candidate writing systems and keeps only those that pass safety, legality, and calibration, returning a Pareto frontier. |
163
163
  | Digital twin | `pen_stack.twin` | Calibrated, out-of-distribution-gated outcome prediction, bounded at phenotype. |
164
164
  | Experiment designer | `pen_stack.active` | Active learning by expected information gain, with a retrospective active-versus-random evaluation. |
165
- | Build interface | `pen_stack.build` | Safety-gated protocol export (draft only, never auto-run) and gated ingestion of results. |
166
- | Closed loop | `pen_stack.loop` | A gated design, build, test, learn loop with drift detection and versioned, reversible recalibration. |
167
- | Agent and co-scientist | `pen_stack.agent` | Goal to cited, auditable plan; MCP server; the co-scientist that drives the loop. |
165
+ | Build interface | `pen_stack.build` | Safety-gated protocol export (draft only, never auto-run) and gated ingestion of results, with a cloud-lab connector that runs the biosecurity gate before any submission. |
166
+ | Closed loop | `pen_stack.loop`, `pen_stack.active` | A gated design, build, test, learn loop with drift detection and versioned, reversible recalibration; an SDL-brain benchmark and a validation-campaign engine that orders the most-informative next measurements by expected information gain. |
167
+ | Write intent (WriteSpec) | `pen_stack.spec` | A typed, ontology-backed `WriteRequest` (an SBOL3 profile) with a grounded extractor that resolves free text to verified ontology ids, asks clarifying questions on ambiguity, and runs a SAT feasibility check. |
168
+ | Agent, co-scientist, and chat | `pen_stack.agent`, `pen_stack.web`, `pen_stack.rag` | Goal to cited, auditable plan; MCP server; the co-scientist that drives the loop; and the grounded conversational chat (four lanes: design, explain, meta, general; provenance-tagged retrieval; a swappable LLM provider). |
168
169
  | Bridge off-target engine | `pen_stack.bridge` | Off-target nomination and guide QC for bridge recombinases. |
169
170
  | Interfaces | `pen_stack.server`, `pen_stack.web`, `pen_stack.ui`, `pen_stack.cli` | REST API, web application, and command-line tools. |
170
171
 
@@ -249,20 +250,22 @@ A single assembly path (`pen_stack/atlas/universe.py`) feeds the classifier, the
249
250
  ```
250
251
  pen-stack/
251
252
  pen_stack/ the installable package
252
- wgenome/ Writable Genome: features, safety, durability, writability, uncertainty, structure3d
253
- atlas/ Writer Atlas, knowledge base, cross-link, variant proposal, canonical universe
253
+ spec/ WriteSpec: typed SBOL3-profile intent layer, grounded extractor, ontology resolvers, SAT feasibility
254
+ wgenome/ Writable Genome: features, safety, durability, writability, uncertainty, structure3d, off-target nomination
255
+ atlas/ Writer Atlas, knowledge base, cross-link, variant proposal, canonical universe, writer-efficiency predictor
254
256
  mech/ score/ mechanism classification at scale; re-grounded therapeutic-readiness axes
255
- planner/ Write Planner: optimisation, cargo, routing, delivery palette, delivery immunology
257
+ planner/ Write Planner: optimisation, cargo, routing, delivery palette, delivery immunology, capsid fitness
256
258
  bridge/ bridge off-target engine and guide QC
257
- oracles/ oracle mesh: the OracleResult contract and adapters over the foundation models
259
+ oracles/ oracle mesh: the OracleResult contract and adapters over the foundation models, with binding-affinity and per-oracle reliability
258
260
  graph/ living world-model knowledge graph (gated, propose-only)
259
- rules/ verify/ machine-readable rule base and the verify(design) service
260
- safety/ the biosecurity and dual-use gate
261
- design/ twin/ generative designer; calibrated digital twin
262
- active/ build/ experiment designer; safety-gated build interface
261
+ rules/ verify/ machine-readable rule base, the verify(design) service, and the proof-object with repair hints
262
+ safety/ the biosecurity and dual-use gate, with standards concordance
263
+ design/ twin/ generative designer; calibrated digital twin with a learned position-effect model
264
+ active/ build/ experiment designer with the SDL-brain benchmark and validation-campaign engine; safety-gated build interface and cloud-lab connector
263
265
  loop/ the gated design-build-test-learn loop
266
+ rag/ PEN-CHAT: provenance-tagged retrieval corpus, embedder, and four-branch ground router (social, cited, general, abstained)
264
267
  agent/ agent platform, co-scientist, MCP server
265
- api/ web/ server/ ui/ cli.py AI integration surface, web platform, REST API, CLI
268
+ api/ web/ server/ ui/ cli.py AI integration surface, web platform with the grounded chat and swappable LLM provider, REST API, CLI
266
269
  benchmarks/ Genome-Writing Bench and the public Genome-Writing Challenge
267
270
  scripts/ reproducible pipeline drivers
268
271
  configs/ pinned datasets, thresholds, and curation (YAML)
@@ -296,7 +299,7 @@ All public: hg38 (UCSC); ENCODE and Roadmap chromatin (ATAC/DNase and histone ma
296
299
  author = {Mahaboob Ali, Anees Ahmed},
297
300
  title = {PEN-STACK: open infrastructure for genome writing (The Writable Genome)},
298
301
  year = {2026},
299
- version = {6.11.0},
302
+ version = {7.1.2},
300
303
  url = {https://github.com/ahmedanees-m/pen-stack}
301
304
  }
302
305
  ```
@@ -85,9 +85,10 @@ flowchart TB
85
85
  | Generative designer | `pen_stack.design` | Proposes candidate writing systems and keeps only those that pass safety, legality, and calibration, returning a Pareto frontier. |
86
86
  | Digital twin | `pen_stack.twin` | Calibrated, out-of-distribution-gated outcome prediction, bounded at phenotype. |
87
87
  | Experiment designer | `pen_stack.active` | Active learning by expected information gain, with a retrospective active-versus-random evaluation. |
88
- | Build interface | `pen_stack.build` | Safety-gated protocol export (draft only, never auto-run) and gated ingestion of results. |
89
- | Closed loop | `pen_stack.loop` | A gated design, build, test, learn loop with drift detection and versioned, reversible recalibration. |
90
- | Agent and co-scientist | `pen_stack.agent` | Goal to cited, auditable plan; MCP server; the co-scientist that drives the loop. |
88
+ | Build interface | `pen_stack.build` | Safety-gated protocol export (draft only, never auto-run) and gated ingestion of results, with a cloud-lab connector that runs the biosecurity gate before any submission. |
89
+ | Closed loop | `pen_stack.loop`, `pen_stack.active` | A gated design, build, test, learn loop with drift detection and versioned, reversible recalibration; an SDL-brain benchmark and a validation-campaign engine that orders the most-informative next measurements by expected information gain. |
90
+ | Write intent (WriteSpec) | `pen_stack.spec` | A typed, ontology-backed `WriteRequest` (an SBOL3 profile) with a grounded extractor that resolves free text to verified ontology ids, asks clarifying questions on ambiguity, and runs a SAT feasibility check. |
91
+ | Agent, co-scientist, and chat | `pen_stack.agent`, `pen_stack.web`, `pen_stack.rag` | Goal to cited, auditable plan; MCP server; the co-scientist that drives the loop; and the grounded conversational chat (four lanes: design, explain, meta, general; provenance-tagged retrieval; a swappable LLM provider). |
91
92
  | Bridge off-target engine | `pen_stack.bridge` | Off-target nomination and guide QC for bridge recombinases. |
92
93
  | Interfaces | `pen_stack.server`, `pen_stack.web`, `pen_stack.ui`, `pen_stack.cli` | REST API, web application, and command-line tools. |
93
94
 
@@ -172,20 +173,22 @@ A single assembly path (`pen_stack/atlas/universe.py`) feeds the classifier, the
172
173
  ```
173
174
  pen-stack/
174
175
  pen_stack/ the installable package
175
- wgenome/ Writable Genome: features, safety, durability, writability, uncertainty, structure3d
176
- atlas/ Writer Atlas, knowledge base, cross-link, variant proposal, canonical universe
176
+ spec/ WriteSpec: typed SBOL3-profile intent layer, grounded extractor, ontology resolvers, SAT feasibility
177
+ wgenome/ Writable Genome: features, safety, durability, writability, uncertainty, structure3d, off-target nomination
178
+ atlas/ Writer Atlas, knowledge base, cross-link, variant proposal, canonical universe, writer-efficiency predictor
177
179
  mech/ score/ mechanism classification at scale; re-grounded therapeutic-readiness axes
178
- planner/ Write Planner: optimisation, cargo, routing, delivery palette, delivery immunology
180
+ planner/ Write Planner: optimisation, cargo, routing, delivery palette, delivery immunology, capsid fitness
179
181
  bridge/ bridge off-target engine and guide QC
180
- oracles/ oracle mesh: the OracleResult contract and adapters over the foundation models
182
+ oracles/ oracle mesh: the OracleResult contract and adapters over the foundation models, with binding-affinity and per-oracle reliability
181
183
  graph/ living world-model knowledge graph (gated, propose-only)
182
- rules/ verify/ machine-readable rule base and the verify(design) service
183
- safety/ the biosecurity and dual-use gate
184
- design/ twin/ generative designer; calibrated digital twin
185
- active/ build/ experiment designer; safety-gated build interface
184
+ rules/ verify/ machine-readable rule base, the verify(design) service, and the proof-object with repair hints
185
+ safety/ the biosecurity and dual-use gate, with standards concordance
186
+ design/ twin/ generative designer; calibrated digital twin with a learned position-effect model
187
+ active/ build/ experiment designer with the SDL-brain benchmark and validation-campaign engine; safety-gated build interface and cloud-lab connector
186
188
  loop/ the gated design-build-test-learn loop
189
+ rag/ PEN-CHAT: provenance-tagged retrieval corpus, embedder, and four-branch ground router (social, cited, general, abstained)
187
190
  agent/ agent platform, co-scientist, MCP server
188
- api/ web/ server/ ui/ cli.py AI integration surface, web platform, REST API, CLI
191
+ api/ web/ server/ ui/ cli.py AI integration surface, web platform with the grounded chat and swappable LLM provider, REST API, CLI
189
192
  benchmarks/ Genome-Writing Bench and the public Genome-Writing Challenge
190
193
  scripts/ reproducible pipeline drivers
191
194
  configs/ pinned datasets, thresholds, and curation (YAML)
@@ -219,7 +222,7 @@ All public: hg38 (UCSC); ENCODE and Roadmap chromatin (ATAC/DNase and histone ma
219
222
  author = {Mahaboob Ali, Anees Ahmed},
220
223
  title = {PEN-STACK: open infrastructure for genome writing (The Writable Genome)},
221
224
  year = {2026},
222
- version = {6.11.0},
225
+ version = {7.1.2},
223
226
  url = {https://github.com/ahmedanees-m/pen-stack}
224
227
  }
225
228
  ```
@@ -133,6 +133,69 @@ controlled_functions:
133
133
  keywords: ["pathogen_essential", "virulence_factor", "pathogen essential"]
134
134
  control_ref: "DURC policy"
135
135
  severity: medium
136
+ - id: FUNC-VIRAL-TROPISM-ENHANCE
137
+ # v7.1.2 CRITICAL: Added to catch furin-cleavage and other viral enhancement modifications.
138
+ # Furin is a ubiquitous human protease; inserting furin cleavage sites increases proteolytic
139
+ # activation of viral glycoproteins, broadening cell tropism and transmissibility (GOF concern).
140
+ name: "engineered enhancement of viral cell tropism / proteolytic activation (furin cleavage, PRRA inserts)"
141
+ keywords: ["furin cleavage", "furin_cleavage", "protease activation", "receptor binding enhancement",
142
+ "tropism enhancement", "tropism_expansion", "virulence enhancement"]
143
+ control_ref: "DURC policy (GOF concern, HHS P3CO oversight)"
144
+ severity: high
145
+ - id: FUNC-ONCOGENIC-SUPPRESSOR
146
+ # v7.1.2 CRITICAL: Added to catch dominant-negative tumor suppressors and oncogenic manipulations.
147
+ # Deleting or inhibiting tumor suppressors (TP53, RB, PTEN) ablates apoptosis/cell-cycle checkpoints,
148
+ # enabling unrestricted proliferation and malignant transformation (oncogenic context).
149
+ name: "dominant-negative / ablation of tumor-suppressor checkpoints (TP53, RB, PTEN, APC)"
150
+ keywords: ["dominant-negative", "dominant negative", "tp53_suppressor", "p53_ablation", "rb_suppressor",
151
+ "pten_suppressor", "apc_suppressor", "apoptosis_checkpoint_ablation", "cell_cycle_checkpoint_ablation",
152
+ "tumor_suppressor_knockout", "unrestricted_proliferation", "apoptosis_evasion"]
153
+ control_ref: "DURC policy (oncogenic context, malignant transformation risk)"
154
+ severity: high
155
+
156
+ # --- Oncogenic-manipulation PATTERN screen (v7.1.2). -----------------------------------
157
+ # A flat keyword list (FUNC-ONCOGENIC-SUPPRESSOR above) catches only literal phrasings; an adversary (or an
158
+ # honest user) describing the same edit by MECHANISM or SYNONYM evades it ("R175H p53 that abolishes
159
+ # transactivation", "PTEN knockout", "RAS G12D constitutive activation", "hTERT immortalization"). This pattern
160
+ # screen flags the COMBINATION rather than a fixed phrase:
161
+ # (tumor-suppressor gene token + a disruptive verb) -> losing a growth/apoptosis brake
162
+ # (oncogene token + an activating signature) -> flooring a growth accelerator
163
+ # (an immortalization signature) -> bypassing replicative senescence
164
+ # The asymmetry is deliberate and is what spares legitimate therapy WITHOUT an explicit allow-list: RESTORING a
165
+ # suppressor or SILENCING/knocking-down an oncogene does not match (restoration verbs are not disruptive; silencing
166
+ # is not an activating signature), so "wild-type p53 correction to restore apoptosis" or "knock down mutant KRAS"
167
+ # stay clear. Disposition is ESCALATE (medium): deliberate oncogenic transformation is dual-use, but cancer-model
168
+ # research is legitimate and has an IBC/oversight path, so it routes to human review rather than a blanket refuse;
169
+ # the blatant dominant-negative phrasings still REFUSE via FUNC-ONCOGENIC-SUPPRESSOR. Tokens are public gene
170
+ # symbols / standard molecular-biology verbs - no exploit detail.
171
+ oncogenic_manipulation:
172
+ id: FUNC-ONCOGENIC-PATTERN
173
+ name: "engineered oncogenic transformation (tumor-suppressor disruption / oncogene activation / immortalization)"
174
+ control_ref: "DURC policy (oncogenic transformation); cancer-model research has a legitimate IBC/oversight path"
175
+ severity: medium
176
+ tumor_suppressors: ["tp53", "trp53", " p53", "rb1", "retinoblastoma protein", "pten", " apc ", "cdkn2a",
177
+ "ink4a", " p16", " arf ", " nf1", "neurofibromin", "brca1", "brca2", " vhl", "smad4",
178
+ "stk11", " lkb1", " bax", " bak", "pro-apoptotic", "tumor suppressor", "tumour suppressor"]
179
+ oncogenes: ["kras", "nras", "hras", "k-ras", "n-ras", "h-ras", " ras ", " myc", "c-myc", "mycn", "braf",
180
+ "egfr", "erbb2", " her2", "pik3ca", " akt ", " alk ", " met ", " ret ", "bcr-abl", "ccnd1",
181
+ "cyclin d", " mdm2", "ezh2", "beta-catenin", "wnt-target", "mapk flux", "pi3k/akt"]
182
+ disrupt_verbs: ["knockout", "knock out", "knock-out", "knocked out", "disrupt", "ablat", "dominant-negative",
183
+ "dominant negative", "frameshift", "inactivat", "abolish", "sequester", "loss-of-function",
184
+ "loss of function", "null allele", "truncat", "silence the suppressor", "remove the",
185
+ "release the", "derepress", "lipid-phosphatase brake"]
186
+ activate_signatures: ["constitutive activ", "constitutively active", "gain-of-function", "gain of function",
187
+ "activating mutation", "oncogenic mutation", "ligand-independent", "ligand independent",
188
+ "autoinhibition", "g12d", "g12v", "g12c", "g13d", "q61", "v600e", "gtp-bound active",
189
+ "switch in its gtp", "constitutive mapk", "constitutive wnt", "constitutive signaling",
190
+ "constitutive survival", "hyperactivat", "independent of ligand", "sustain constitutive"]
191
+ immortalization: ["immortaliz", "telomerase", "htert", "unlimited replicative", "unlimited proliferat",
192
+ "unrestricted proliferat", "indefinite proliferat", "replicative lifespan", "bypass senescence",
193
+ "evade senescence", "escape senescence"]
194
+ # restoration verbs that, when no disruptive/activating/immortalization signal is present, keep a suppressor /
195
+ # oncogene mention CLEAR (therapeutic gene correction). Belt-and-braces on top of the asymmetric logic.
196
+ therapy_context: ["restore", "restoration", "correct the", "gene correction", "wild-type replacement",
197
+ "replace the defective", "reconstitute the wild-type", "functional copy", "supplementation",
198
+ "wild-type p53 gene correction"]
136
199
 
137
200
  # --- Chimera / context rules: hazardous ASSEMBLY of individually-benign parts. ---------
138
201
  chimera_rules:
@@ -1,2 +1,2 @@
1
1
  """PEN-STACK v3.0 - open infrastructure for genome writing."""
2
- __version__ = "7.1.2"
2
+ __version__ = "7.1.3"
@@ -10,7 +10,7 @@ from __future__ import annotations
10
10
 
11
11
  from typing import Any
12
12
 
13
- from pen_stack.design.space import candidate_space
13
+ from pen_stack.design.space import candidate_space, vehicle_sweep
14
14
  from pen_stack.verify import verify
15
15
 
16
16
  # a survivor must be legal AND safe (cleared or low-severity advisory); refuse/escalate are discarded.
@@ -29,8 +29,19 @@ def generate_designs(goal: dict | None = None, *, candidates: list[dict] | None
29
29
  by confidence. Hazardous (refuse/escalate) or illegal proposals are discarded, never returned.
30
30
 
31
31
  Pass an explicit ``candidates`` list to discriminate a known pool (atlas-independent); otherwise candidates
32
- are enumerated from ``goal`` via the planner-backed candidate space."""
33
- pool = candidates if candidates is not None else candidate_space(goal or {}, n=n)
32
+ are enumerated from ``goal`` via the planner-backed candidate space.
33
+
34
+ v7.1.2: when the goal's cell type has NO measured writability atlas (so the planner-backed candidate_space
35
+ yields nothing), fall back to an atlas-free vehicle sweep so the legality + biosecurity discrimination still
36
+ runs; those survivors carry no calibrated confidence (it abstains honestly, surfaced in the UI) rather than
37
+ the page showing an empty table for a perfectly legal, screened design. The explicit-``candidates`` path is
38
+ untouched (``generate_designs(candidates=[])`` still returns [])."""
39
+ if candidates is not None:
40
+ pool = candidates
41
+ else:
42
+ pool = candidate_space(goal or {}, n=n)
43
+ if not pool and goal: # atlas absent for this cell type -> atlas-free sweep (confidence will abstain)
44
+ pool = vehicle_sweep(goal, n=n)
34
45
  survivors: list[dict] = []
35
46
  for d in pool:
36
47
  v = verify(dict(d), actor=actor)
@@ -0,0 +1,136 @@
1
+ """Candidate-space generation for the generative designer (v5.8, WS-GEN support).
2
+
3
+ `candidate_space(goal)` enumerates candidate end-to-end writing systems, writer x site x cargo x delivery,
4
+ by wrapping the validated Phase-3 inverse-design planner (`plan_write`) for the site x writer x scores, then
5
+ pairing each with every *compatible* delivery vehicle from the curated palette (cargo fits the vehicle
6
+ capacity). Every candidate carries the planner's grounded scores (safety / p_durable / writer_activity) so the
7
+ verifier-as-discriminator can compute a calibrated confidence and the v5.6 immune profile downstream.
8
+
9
+ Atlas-dependent: when the Phase-1 writability atlas is absent (e.g. a bare laptop checkout), `plan_write`
10
+ yields nothing and `candidate_space` returns []. The discriminator/Pareto logic is independent of the atlas and
11
+ is exercised on explicit candidates (tests/bench fixtures); the atlas path runs on the VM/with data.
12
+ """
13
+ from __future__ import annotations
14
+
15
+ from typing import Any
16
+
17
+ from pen_stack.planner.delivery_vehicles import names as _vehicle_names
18
+ from pen_stack.planner.delivery_vehicles import vehicle as _vehicle
19
+
20
+ # edit-intent -> write_type (the router/verifier dispatches on write_type)
21
+ _INTENT_WRITE_TYPE = {
22
+ "safe_harbour_insertion": "insertion",
23
+ "high_durability_insertion": "insertion",
24
+ "knock_in_with_disruption": "insertion",
25
+ "landing_pad_insertion": "landing_pad",
26
+ "regulatory_element_excision": "excision",
27
+ "repeat_excision": "excision",
28
+ "regulatory_rewrite": "regulatory_rewrite",
29
+ }
30
+
31
+
32
+ def _compatible_vehicles(cargo_bp: int, in_vivo: bool | None = None) -> list[str]:
33
+ """Vehicles whose curated cargo capacity fits the cargo (capacity None = no DNA-packaging limit).
34
+
35
+ v7.1.2: when an administration ``in_vivo`` context is given, also filter by the vehicle's curated route
36
+ (the `in_vivo` / `ex_vivo` flags in configs/delivery_vehicles.yaml) - an in-vivo goal keeps the in-vivo-capable
37
+ vehicles, an ex-vivo goal keeps the ex-vivo-capable ones (e.g. lentivirus / electroporation / eVLP). This is a
38
+ grounded compatibility filter from the curated palette, not a clinical claim. ``in_vivo=None`` keeps all."""
39
+ out = []
40
+ for n in _vehicle_names():
41
+ v = _vehicle(n) or {}
42
+ cap = v.get("cargo_capacity_bp")
43
+ if cap is not None and cargo_bp > cap:
44
+ continue
45
+ if in_vivo is True and not v.get("in_vivo"):
46
+ continue
47
+ if in_vivo is False and not v.get("ex_vivo"):
48
+ continue
49
+ out.append(n)
50
+ return out
51
+
52
+
53
+ def deliverability_score(vehicle_name: str, cargo_bp: int) -> float:
54
+ """Grounded deliverability proxy: capacity headroom (more spare capacity = more deliverable),
55
+ clipped to [0,1]. Vehicles with no packaging limit score 1.0. NOT a clinical claim."""
56
+ cap = (_vehicle(vehicle_name) or {}).get("cargo_capacity_bp")
57
+ if cap is None:
58
+ return 1.0
59
+ if cargo_bp > cap:
60
+ return 0.0
61
+ return max(0.0, min(1.0, (cap - cargo_bp) / cap))
62
+
63
+
64
+ def candidate_space(goal: dict, *, n: int = 200, k: int = 8) -> list[dict[str, Any]]:
65
+ """Enumerate candidate designs for a goal {gene, intent, cargo_bp, cell_type, cargo_function?}. Each candidate
66
+ is a plain dict consumable by `verify()` and carries the planner's grounded scores. Returns [] if the atlas is
67
+ absent.
68
+
69
+ v7.1.2: the goal's screening-relevant fields (cargo_function, cargo_seq, in_vivo, delivery_tropism,
70
+ replication_competent) are PROPAGATED onto every candidate so the Guardian biosecurity gate in verify() screens
71
+ the cargo function for each swept vehicle. Previously these were dropped here, so a hazardous cargo function
72
+ reached NO screen on the goal-based path."""
73
+ gene = goal["gene"]
74
+ intent = goal.get("intent") or goal.get("edit_intent") or "safe_harbour_insertion"
75
+ cargo_bp = int(goal.get("cargo_bp") or goal.get("payload_bp") or 3000)
76
+ ct = goal.get("cell_type") or goal.get("ct") or "k562"
77
+ write_type = _INTENT_WRITE_TYPE.get(intent, "insertion")
78
+ # screening-relevant goal fields propagated onto every candidate (the Guardian reads cargo_function).
79
+ screen_extra = {f: goal[f] for f in ("cargo_function", "cargo_seq", "in_vivo", "delivery_tropism",
80
+ "replication_competent") if goal.get(f) is not None}
81
+
82
+ from pen_stack.planner.pipeline import plan_write
83
+ try:
84
+ plans = plan_write(gene, intent, cargo_bp, ct, k=k)
85
+ except Exception: # atlas/data absent -> no candidates (discriminator/Pareto unaffected)
86
+ return []
87
+
88
+ vehicles = _compatible_vehicles(cargo_bp, in_vivo=goal.get("in_vivo"))
89
+ cands: list[dict] = []
90
+ for p in plans:
91
+ for veh in vehicles:
92
+ cands.append({
93
+ **screen_extra, # v7.1.2: cargo_function et al. so the Guardian screens this candidate
94
+ "write_type": write_type, "gene": gene, "chrom": p["site"]["chrom"],
95
+ "edit_intent": intent, "writer_family": p["writer"], "cargo_bp": cargo_bp,
96
+ "cell_type": ct, "delivery_vehicle": veh,
97
+ # grounded planner scores (model_extra) -> verify() calibrated confidence + downstream:
98
+ "safety": p["safety"], "p_durable": p["durability"], "writer_activity": p["writer_activity"],
99
+ "on_target": p["on_target"], "reachability_tier": p.get("reachability_tier"),
100
+ "deliverability": deliverability_score(veh, cargo_bp),
101
+ "_planner_score": p["score"],
102
+ "provenance": {**p.get("provenance", {}), "candidate_space": "v5.8 plan_write x delivery palette"},
103
+ })
104
+ if len(cands) >= n:
105
+ return cands
106
+ return cands
107
+
108
+
109
+ def vehicle_sweep(goal: dict, *, n: int = 200) -> list[dict[str, Any]]:
110
+ """Atlas-FREE candidate enumeration: sweep the compatible delivery vehicles for the goal WITHOUT planner
111
+ scores. Used when the writability atlas has no coverage for the requested cell type (e.g. cd8_t / pbmc /
112
+ h1_hesc), so `candidate_space` (which needs `plan_write`) yields nothing.
113
+
114
+ Each candidate carries the goal's cargo_function (so the Guardian still screens it), the cargo size (so the
115
+ capacity rules still filter oversize vehicles), and NO safety/p_durable/writer_activity (so verify() honestly
116
+ ABSTAINS on the calibrated confidence rather than inventing one). The legality + biosecurity discrimination is
117
+ fully exercised; only the calibrated-confidence column is left uncomputed (and labelled as such in the UI)."""
118
+ intent = goal.get("intent") or goal.get("edit_intent") or "safe_harbour_insertion"
119
+ cargo_bp = int(goal.get("cargo_bp") or goal.get("payload_bp") or 3000)
120
+ ct = goal.get("cell_type") or goal.get("ct") or "k562"
121
+ write_type = _INTENT_WRITE_TYPE.get(intent, "insertion")
122
+ screen_extra = {f: goal[f] for f in ("cargo_function", "cargo_seq", "in_vivo", "delivery_tropism",
123
+ "replication_competent") if goal.get(f) is not None}
124
+ cands: list[dict] = []
125
+ for veh in _compatible_vehicles(cargo_bp, in_vivo=goal.get("in_vivo")):
126
+ cands.append({
127
+ **screen_extra,
128
+ "write_type": write_type, "gene": goal.get("gene"), "chrom": goal.get("chrom"),
129
+ "edit_intent": intent, "cargo_bp": cargo_bp, "cell_type": ct, "delivery_vehicle": veh,
130
+ "deliverability": deliverability_score(veh, cargo_bp),
131
+ "provenance": {"candidate_space": "v7.1.2 atlas-free vehicle sweep "
132
+ "(no measured writability atlas for this cell type; confidence abstains)"},
133
+ })
134
+ if len(cands) >= n:
135
+ break
136
+ return cands
@@ -12,6 +12,7 @@ sequence still carries a hazardous FUNCTION annotation, and function, not homolo
12
12
  """
13
13
  from __future__ import annotations
14
14
 
15
+ import re
15
16
  from dataclasses import dataclass, field
16
17
  from typing import Any, Callable
17
18
 
@@ -27,6 +28,26 @@ def _norm(s: Any) -> str:
27
28
  return str(s or "").strip().lower()
28
29
 
29
30
 
31
+ def _sep_norm(s: Any) -> str:
32
+ """Lowercase and collapse separator runs (whitespace / hyphen / underscore) to a single space, so
33
+ "furin-cleavage", "furin_cleavage" and "furin cleavage" are one token. Keeps the matcher robust to the
34
+ hyphen/space/underscore variation that is ubiquitous in free-text function descriptions."""
35
+ return re.sub(r"[\s_\-]+", " ", _norm(s)).strip()
36
+
37
+
38
+ def _kw_match(kw: str, text: str) -> bool:
39
+ """Separator-insensitive, word-boundary keyword match (v7.1.2). Two failure modes of a plain substring test:
40
+ (1) over-broad - the short ricin keyword "rip" matches inside "transc-RIP-tion", a word in almost every
41
+ genome-editing design, so a benign promoter cassette would false-refuse as ricin; (2) too-narrow - a
42
+ hyphenated "furin-cleavage" would slip past the space-form keyword "furin cleavage". Normalising separators
43
+ then matching on alphanumeric boundaries fixes both: "rip" matches "RIP" standalone but not inside a longer
44
+ word, and "furin cleavage" / "furin-cleavage" / "furin_cleavage" all match."""
45
+ k = _sep_norm(kw)
46
+ if not k:
47
+ return False
48
+ return re.search(r"(?<![a-z0-9])" + re.escape(k) + r"(?![a-z0-9])", _sep_norm(text)) is not None
49
+
50
+
30
51
  def _design_function_tokens(design: dict) -> set[str]:
31
52
  """Normalised function annotations declared on a design (NOT free-text justification)."""
32
53
  toks: set[str] = set()
@@ -57,6 +78,7 @@ class HazardRegistry:
57
78
  regulated_taxa: list[dict] = field(default_factory=list)
58
79
  controlled_functions: list[dict] = field(default_factory=list)
59
80
  chimera_rules: list[dict] = field(default_factory=list)
81
+ oncogenic_manipulation: dict = field(default_factory=dict)
60
82
  external_enabled: bool = False
61
83
  external_hook: Callable[[str], list[ScreenHit]] | None = None
62
84
 
@@ -71,6 +93,7 @@ class HazardRegistry:
71
93
  regulated_taxa=raw.get("regulated_taxa", []),
72
94
  controlled_functions=raw.get("controlled_functions", []),
73
95
  chimera_rules=raw.get("chimera_rules", []),
96
+ oncogenic_manipulation=raw.get("oncogenic_manipulation", {}),
74
97
  external_enabled=external_hook is not None,
75
98
  external_hook=external_hook,
76
99
  )
@@ -88,7 +111,7 @@ class HazardRegistry:
88
111
  pfam = _design_pfam(design)
89
112
  for entry in self.toxin_functions + self.controlled_functions:
90
113
  by_pfam = pfam & {_norm(p) for p in entry.get("pfam", [])}
91
- by_kw = {kw for kw in (entry.get("keywords") or []) if any(_norm(kw) in t or t == _norm(kw) for t in toks)}
114
+ by_kw = {kw for kw in (entry.get("keywords") or []) if any(_kw_match(kw, t) for t in toks)}
92
115
  if by_pfam or by_kw:
93
116
  ev = {}
94
117
  if by_pfam:
@@ -100,6 +123,47 @@ class HazardRegistry:
100
123
  provenance=self._prov(entry), evidence=ev))
101
124
  return hits
102
125
 
126
+ def oncogenic_flags(self, design: dict) -> list[ScreenHit]:
127
+ """Oncogenic-manipulation PATTERN screen (v7.1.2). Flags the COMBINATION that a flat keyword list misses:
128
+ a tumor-suppressor gene with a disruptive verb, an oncogene with an activating signature, or an
129
+ immortalization signature. The asymmetry spares therapy without an allow-list (restoring a suppressor /
130
+ silencing an oncogene matches neither). Escalates to human review (dual-use, legitimate cancer-model path)."""
131
+ cfg = self.oncogenic_manipulation
132
+ if not cfg:
133
+ return []
134
+ # screen the declared function annotations only (the artifact, not any free-text justification)
135
+ text = " " + " | ".join(sorted(_design_function_tokens(design))) + " "
136
+ if not text.strip(" |"):
137
+ return []
138
+
139
+ def has(keys: list[str]) -> list[str]:
140
+ return [k for k in (keys or []) if _norm(k) in text]
141
+
142
+ supp = has(cfg.get("tumor_suppressors"))
143
+ onco = has(cfg.get("oncogenes"))
144
+ disrupt = has(cfg.get("disrupt_verbs"))
145
+ activate = has(cfg.get("activate_signatures"))
146
+ immortal = has(cfg.get("immortalization"))
147
+ therapy = has(cfg.get("therapy_context"))
148
+
149
+ reasons = []
150
+ if supp and disrupt:
151
+ reasons.append(f"tumor-suppressor disruption ({supp[0]} + {disrupt[0]})")
152
+ if onco and activate:
153
+ reasons.append(f"oncogene activation ({onco[0]} + {activate[0]})")
154
+ if immortal:
155
+ reasons.append(f"immortalization signature ({immortal[0]})")
156
+ if not reasons:
157
+ return []
158
+ # therapeutic restoration / supplementation with NO disruptive/activating/immortalization signal -> clear.
159
+ if therapy and not (disrupt or activate or immortal):
160
+ return []
161
+ return [ScreenHit(kind="oncogenic_flag", detail=cfg.get("name", "oncogenic manipulation"),
162
+ severity=cfg.get("severity", "medium"), provenance=self._prov(cfg),
163
+ evidence={"patterns": reasons,
164
+ "suppressor": supp[:2], "oncogene": onco[:2], "disrupt": disrupt[:2],
165
+ "activate": activate[:2], "immortalization": immortal[:2]})]
166
+
103
167
  def taxon_flags(self, design: dict) -> list[ScreenHit]:
104
168
  """Regulated-pathogen-TAXON screen (Select Agent / Australia Group membership by declared source)."""
105
169
  hits: list[ScreenHit] = []
@@ -121,8 +185,9 @@ class HazardRegistry:
121
185
  hits: list[ScreenHit] = []
122
186
  rules = {r["id"]: r for r in self.chimera_rules}
123
187
 
124
- has_toxin = bool(self.function_flags(design)) or _norm(design.get("cargo_function")) and any(
125
- _norm(kw) in _norm(design.get("cargo_function")) for e in self.toxin_functions for kw in (e.get("keywords") or []))
188
+ cf = _norm(design.get("cargo_function"))
189
+ has_toxin = bool(self.function_flags(design)) or bool(cf) and any(
190
+ _kw_match(kw, cf) for e in self.toxin_functions for kw in (e.get("keywords") or []))
126
191
  broad = _norm(design.get("delivery_tropism")) in {"broad", "broad_systemic", "systemic"} or \
127
192
  _norm(design.get("delivery_vehicle")) in {"aav9", "aavrh10"}
128
193
  replicating = bool(design.get("replication_competent"))
@@ -15,7 +15,7 @@ from typing import Literal
15
15
 
16
16
  from pydantic import BaseModel, Field
17
17
 
18
- ScreenKind = Literal["sequence_homology", "function_flag", "taxon_flag", "chimera_context"]
18
+ ScreenKind = Literal["sequence_homology", "function_flag", "taxon_flag", "chimera_context", "oncogenic_flag"]
19
19
  Severity = Literal["low", "medium", "high"]
20
20
 
21
21
 
@@ -43,6 +43,7 @@ def screen_design(design: dict, registry=None) -> list[ScreenHit]:
43
43
  design = dict(design)
44
44
  hits: list[ScreenHit] = []
45
45
  hits += reg.function_flags(design) # toxin / pathogen-essential function domains
46
+ hits += reg.oncogenic_flags(design) # v7.1.2 oncogenic-manipulation pattern (mechanism/synonym-robust)
46
47
  hits += reg.taxon_flags(design) # regulated pathogen taxa
47
48
  hits += reg.chimera_context(design) # hazardous assembly of benign parts
48
49
  seq = _assemble_cargo(design)
@@ -440,11 +440,30 @@ def delivery_tropism_endpoint(target_tissue: str):
440
440
  @app.post("/generate", tags=["v6.1 AI surface"])
441
441
  def generate_endpoint(req: dict):
442
442
  """v5.8 generative designer: verifier-as-discriminator. Body: {goal?, candidates?, keep?}. Hazardous/illegal
443
- candidates are discarded; survivors are calibrated + immune-profiled candidates (never asserted to work)."""
443
+ candidates are discarded; survivors are calibrated + immune-profiled candidates (never asserted to work).
444
+
445
+ v7.1.2: the GOAL'S cargo function is screened by the Guardian FIRST, before the vehicle x cargo sweep. A
446
+ hazardous goal (e.g. a furin-cleavage tropism-enhancement or a dominant-negative tumor-suppressor ablation) is
447
+ REFUSED up front and the response carries the explicit safety verdict, so an empty result is correctly
448
+ attributed to a biosecurity refusal (not a silent 'no candidates'). The per-candidate Guardian still runs in
449
+ verify() as defence in depth."""
444
450
  from pen_stack.design import generate_designs
445
- return {"survivors": generate_designs(req.get("goal"), candidates=req.get("candidates"),
451
+ goal = req.get("goal")
452
+ # Guardian pre-screen on the goal's declared cargo function (the artifact, not any free-text justification).
453
+ if isinstance(goal, dict) and any(goal.get(f) for f in ("cargo_function", "cargo_seq")):
454
+ from pen_stack.safety.gate import safety_gate
455
+ screen = {f: goal[f] for f in ("cargo_function", "cargo_seq", "gene", "delivery_vehicle", "in_vivo",
456
+ "delivery_tropism", "replication_competent") if goal.get(f) is not None}
457
+ gv = safety_gate(screen, actor=str(req.get("actor", "api")))
458
+ if gv.decision in ("refuse", "escalate"):
459
+ return {"survivors": [], "refused": True,
460
+ "safety": {"decision": gv.decision, "reason": gv.reason,
461
+ "hits": [{"detail": h.detail, "severity": h.severity, "kind": h.kind}
462
+ for h in gv.hits]},
463
+ "disclaimer": _DISCLAIMER}
464
+ return {"survivors": generate_designs(goal, candidates=req.get("candidates"),
446
465
  keep=int(req.get("keep", 25)), actor=str(req.get("actor", "api"))),
447
- "disclaimer": _DISCLAIMER}
466
+ "refused": False, "disclaimer": _DISCLAIMER}
448
467
 
449
468
 
450
469
  @app.post("/predict", tags=["v6.1 AI surface"])