pen-stack 5.3.0__tar.gz → 5.5.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 (323) hide show
  1. {pen_stack-5.3.0 → pen_stack-5.5.0}/CHANGELOG.md +61 -0
  2. {pen_stack-5.3.0 → pen_stack-5.5.0}/CITATION.cff +1 -1
  3. {pen_stack-5.3.0 → pen_stack-5.5.0}/PKG-INFO +43 -2
  4. {pen_stack-5.3.0 → pen_stack-5.5.0}/README.md +42 -1
  5. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/oracles/scope_cards.yaml +28 -0
  6. pen_stack-5.5.0/configs/seroprevalence.yaml +64 -0
  7. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/__init__.py +1 -1
  8. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/agent/cite.py +10 -0
  9. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/planner/delivery_immunology.py +14 -0
  10. pen_stack-5.5.0/pen_stack/planner/innate_sensing.py +135 -0
  11. pen_stack-5.5.0/pen_stack/planner/seroprevalence_oracle.py +92 -0
  12. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/verify/service.py +21 -0
  13. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack.egg-info/PKG-INFO +43 -2
  14. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack.egg-info/SOURCES.txt +7 -0
  15. pen_stack-5.5.0/prereg/SHA256_LOCK_ws_innate.json +8 -0
  16. pen_stack-5.5.0/prereg/SHA256_LOCK_ws_seroprev.json +8 -0
  17. pen_stack-5.5.0/prereg/ws_innate.yaml +39 -0
  18. pen_stack-5.5.0/prereg/ws_seroprev.yaml +40 -0
  19. {pen_stack-5.3.0 → pen_stack-5.5.0}/pyproject.toml +1 -1
  20. {pen_stack-5.3.0 → pen_stack-5.5.0}/LICENSE +0 -0
  21. {pen_stack-5.3.0 → pen_stack-5.5.0}/MANIFEST.in +0 -0
  22. {pen_stack-5.3.0 → pen_stack-5.5.0}/bench/run.py +0 -0
  23. {pen_stack-5.3.0 → pen_stack-5.5.0}/benchmarks/genome_writing_bench/LEADERBOARD.md +0 -0
  24. {pen_stack-5.3.0 → pen_stack-5.5.0}/benchmarks/genome_writing_bench/README.md +0 -0
  25. {pen_stack-5.3.0 → pen_stack-5.5.0}/benchmarks/genome_writing_bench/SHA256SUMS +0 -0
  26. {pen_stack-5.3.0 → pen_stack-5.5.0}/benchmarks/genome_writing_bench/SUBMISSIONS.md +0 -0
  27. {pen_stack-5.3.0 → pen_stack-5.5.0}/benchmarks/genome_writing_bench/tasks.yaml +0 -0
  28. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/atlas_families.yaml +0 -0
  29. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/bridge_offtarget_profile.yaml +0 -0
  30. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/capsid_epitope_oracle.yaml +0 -0
  31. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/capsid_sequences.fasta +0 -0
  32. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/cargo_polish.yaml +0 -0
  33. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/cell_types.yaml +0 -0
  34. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/datasets.yaml +0 -0
  35. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/delivery_constraints.yaml +0 -0
  36. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/delivery_rules.yaml +0 -0
  37. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/delivery_vehicles.yaml +0 -0
  38. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/gates_v3.yaml +0 -0
  39. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/genotoxicity_oracle.yaml +0 -0
  40. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/gsh_validated_heldout.yaml +0 -0
  41. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/intent_weights.yaml +0 -0
  42. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/known_unknowns.yaml +0 -0
  43. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/llm.yaml +0 -0
  44. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/monitor_queries.yaml +0 -0
  45. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/rules/delivery.yaml +0 -0
  46. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/rules/fold.yaml +0 -0
  47. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/rules/multiplex.yaml +0 -0
  48. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/rules/payload.yaml +0 -0
  49. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/rules/reachability.yaml +0 -0
  50. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/score_axes.yaml +0 -0
  51. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/target_sites.yaml +0 -0
  52. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/universe_crosswalk.yaml +0 -0
  53. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/write_types.yaml +0 -0
  54. {pen_stack-5.3.0 → pen_stack-5.5.0}/configs/wtkb_curated.yaml +0 -0
  55. {pen_stack-5.3.0 → pen_stack-5.5.0}/data/curated/bridge_offtarget_energetics.json +0 -0
  56. {pen_stack-5.3.0 → pen_stack-5.5.0}/data/curated/bridge_offtarget_profile_measured.parquet +0 -0
  57. {pen_stack-5.3.0 → pen_stack-5.5.0}/data/curated/gene_coords.parquet +0 -0
  58. {pen_stack-5.3.0 → pen_stack-5.5.0}/data/curated/unified_editor_universe.parquet +0 -0
  59. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/BACKLOG.md +0 -0
  60. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/DEPLOY.md +0 -0
  61. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/INFRA.md +0 -0
  62. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/MCP.md +0 -0
  63. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/RELEASING.md +0 -0
  64. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/REPRO.md +0 -0
  65. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/agent.md +0 -0
  66. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/alphagenome_feasibility.md +0 -0
  67. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/benchmark_circularity.md +0 -0
  68. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/cards/atlas.md +0 -0
  69. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/cards/durability.md +0 -0
  70. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/cards/safety.md +0 -0
  71. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/co_scientist.md +0 -0
  72. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/delivery.md +0 -0
  73. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/dissemination.md +0 -0
  74. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/environment.md +0 -0
  75. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/index.md +0 -0
  76. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/mechanistic_constraints.md +0 -0
  77. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/oracles.md +0 -0
  78. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/positioning.md +0 -0
  79. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/private_data_formats.md +0 -0
  80. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/quickstart.md +0 -0
  81. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/rules.md +0 -0
  82. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/scope.md +0 -0
  83. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/scorecard.md +0 -0
  84. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/tutorials/compare-families.md +0 -0
  85. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/tutorials/score-deliverability.md +0 -0
  86. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/tutorials/where-can-i-write.md +0 -0
  87. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/tutorials/which-writer-reaches-locus.md +0 -0
  88. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/uncertainty.md +0 -0
  89. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/verify.md +0 -0
  90. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/world_model.md +0 -0
  91. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/writer_verification.md +0 -0
  92. {pen_stack-5.3.0 → pen_stack-5.5.0}/docs/wtkb.md +0 -0
  93. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/_resources.py +0 -0
  94. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/adapt/__init__.py +0 -0
  95. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/adapt/finetune.py +0 -0
  96. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/adapt/ingest.py +0 -0
  97. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/adapt/pipeline.py +0 -0
  98. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/adapt/recalibrate.py +0 -0
  99. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/adapt/report.py +0 -0
  100. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/agent/__init__.py +0 -0
  101. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/agent/co_scientist.py +0 -0
  102. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/agent/epistemic.py +0 -0
  103. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/agent/guardrails.py +0 -0
  104. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/agent/mcp_server.py +0 -0
  105. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/agent/orchestrator.py +0 -0
  106. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/agent/pen_agent.py +0 -0
  107. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/agent/scope.py +0 -0
  108. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/agent/tools.py +0 -0
  109. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/atlas/__init__.py +0 -0
  110. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/atlas/build_wtkb.py +0 -0
  111. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/atlas/crosslink.py +0 -0
  112. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/atlas/expand.py +0 -0
  113. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/atlas/schema.py +0 -0
  114. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/atlas/scorecard.py +0 -0
  115. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/atlas/universe.py +0 -0
  116. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/atlas/variant_propose.py +0 -0
  117. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/atlas/writer_verify.py +0 -0
  118. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/bridge/__init__.py +0 -0
  119. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/bridge/activity.py +0 -0
  120. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/bridge/cli.py +0 -0
  121. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/bridge/fold_qc.py +0 -0
  122. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/bridge/guide_qc.py +0 -0
  123. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/bridge/ingest.py +0 -0
  124. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/bridge/offtarget.py +0 -0
  125. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/bridge/offtarget_energetics.py +0 -0
  126. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/bridge/ortholog_screen.py +0 -0
  127. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/bridge/pipeline.py +0 -0
  128. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/cli.py +0 -0
  129. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/data/__init__.py +0 -0
  130. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/data/encode.py +0 -0
  131. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/data/genome.py +0 -0
  132. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/data/ingest_chromatin.py +0 -0
  133. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/data/ingest_integration.py +0 -0
  134. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/data/ingest_safety_annot.py +0 -0
  135. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/data/ingest_trip.py +0 -0
  136. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/env/__init__.py +0 -0
  137. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/env/genome_writing_env.py +0 -0
  138. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/env/policies.py +0 -0
  139. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/graph/__init__.py +0 -0
  140. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/graph/build.py +0 -0
  141. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/graph/cell_types.py +0 -0
  142. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/graph/ingest.py +0 -0
  143. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/graph/query.py +0 -0
  144. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/graph/schema.py +0 -0
  145. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/mech/__init__.py +0 -0
  146. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/mech/classify_atlas.py +0 -0
  147. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/mech/whitelist.py +0 -0
  148. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/monitor/__init__.py +0 -0
  149. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/monitor/europepmc.py +0 -0
  150. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/monitor/run.py +0 -0
  151. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/monitor/triage.py +0 -0
  152. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/oracles/__init__.py +0 -0
  153. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/oracles/cache.py +0 -0
  154. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/oracles/energetics.py +0 -0
  155. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/oracles/genome.py +0 -0
  156. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/oracles/protein_design.py +0 -0
  157. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/oracles/rna.py +0 -0
  158. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/oracles/schema.py +0 -0
  159. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/oracles/structure.py +0 -0
  160. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/planner/__init__.py +0 -0
  161. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/planner/capsid_epitope_oracle.py +0 -0
  162. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/planner/cargo.py +0 -0
  163. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/planner/cargo_polish.py +0 -0
  164. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/planner/delivery.py +0 -0
  165. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/planner/delivery_constraints.py +0 -0
  166. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/planner/delivery_vehicles.py +0 -0
  167. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/planner/genotoxicity_oracle.py +0 -0
  168. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/planner/multiplex.py +0 -0
  169. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/planner/optimize.py +0 -0
  170. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/planner/pipeline.py +0 -0
  171. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/planner/report.py +0 -0
  172. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/planner/router.py +0 -0
  173. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/planner/target_site.py +0 -0
  174. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/rag/__init__.py +0 -0
  175. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/rag/index.py +0 -0
  176. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/rag/llm.py +0 -0
  177. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/rag/qa.py +0 -0
  178. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/rules/__init__.py +0 -0
  179. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/rules/evaluators.py +0 -0
  180. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/rules/loader.py +0 -0
  181. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/rules/schema.py +0 -0
  182. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/rules/solver.py +0 -0
  183. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/score/__init__.py +0 -0
  184. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/score/recalibrate.py +0 -0
  185. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/score/therapeutic.py +0 -0
  186. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/server/__init__.py +0 -0
  187. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/server/api.py +0 -0
  188. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/ui/__init__.py +0 -0
  189. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/ui/app.py +0 -0
  190. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/__init__.py +0 -0
  191. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/adapt_demo.py +0 -0
  192. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/agent_eval.py +0 -0
  193. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/bench_adversarial_tasks.py +0 -0
  194. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/bench_coscientist_tasks.py +0 -0
  195. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/bench_graph_tasks.py +0 -0
  196. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/bench_rule_tasks.py +0 -0
  197. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/bench_trust_tasks.py +0 -0
  198. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/bench_writetype_tasks.py +0 -0
  199. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/blind_gsh_discovery.py +0 -0
  200. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/cargo_directionality.py +0 -0
  201. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/durability_baselines.py +0 -0
  202. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/forward_hypotheses.py +0 -0
  203. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/guide_qc_demo.py +0 -0
  204. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/intent_specification.py +0 -0
  205. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/offtarget_energetics_eval.py +0 -0
  206. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/out_of_scope_refusal.py +0 -0
  207. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/outcome_calibration.py +0 -0
  208. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/paper3_benchmark.py +0 -0
  209. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/paper4_real_validation.py +0 -0
  210. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/paper4_validation.py +0 -0
  211. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/selective_prediction.py +0 -0
  212. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/seq_vs_measured.py +0 -0
  213. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/target_site_controls.py +0 -0
  214. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/uncertainty_eval.py +0 -0
  215. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/ungrounded_baseline.py +0 -0
  216. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/within_locus_ranking.py +0 -0
  217. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/validate/writer_recovery.py +0 -0
  218. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/verify/__init__.py +0 -0
  219. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/verify/schema.py +0 -0
  220. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/wgenome/__init__.py +0 -0
  221. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/wgenome/chromatin_seq.py +0 -0
  222. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/wgenome/durability.py +0 -0
  223. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/wgenome/export_tracks.py +0 -0
  224. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/wgenome/features.py +0 -0
  225. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/wgenome/gsh_baseline.py +0 -0
  226. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/wgenome/mesh_features.py +0 -0
  227. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/wgenome/ood.py +0 -0
  228. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/wgenome/providers.py +0 -0
  229. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/wgenome/safety.py +0 -0
  230. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/wgenome/structure3d.py +0 -0
  231. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/wgenome/uncertainty.py +0 -0
  232. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack/wgenome/writability.py +0 -0
  233. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack.egg-info/dependency_links.txt +0 -0
  234. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack.egg-info/entry_points.txt +0 -0
  235. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack.egg-info/requires.txt +0 -0
  236. {pen_stack-5.3.0 → pen_stack-5.5.0}/pen_stack.egg-info/top_level.txt +0 -0
  237. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_phase0.json +0 -0
  238. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_phase1_5.json +0 -0
  239. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_phase2.json +0 -0
  240. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_phase3.json +0 -0
  241. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_a.json +0 -0
  242. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_atlas.json +0 -0
  243. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_b.json +0 -0
  244. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_ba.json +0 -0
  245. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_ba_v33.json +0 -0
  246. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_ba_v45.json +0 -0
  247. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_bench.json +0 -0
  248. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_c.json +0 -0
  249. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_cal.json +0 -0
  250. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_cite.json +0 -0
  251. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_crit.json +0 -0
  252. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_ct.json +0 -0
  253. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_d.json +0 -0
  254. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_e.json +0 -0
  255. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_env.json +0 -0
  256. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_ep.json +0 -0
  257. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_epitope.json +0 -0
  258. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_f.json +0 -0
  259. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_g.json +0 -0
  260. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_genotox.json +0 -0
  261. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_graph.json +0 -0
  262. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_h.json +0 -0
  263. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_immune.json +0 -0
  264. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_mc.json +0 -0
  265. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_mon.json +0 -0
  266. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_o.json +0 -0
  267. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_plan.json +0 -0
  268. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_r.json +0 -0
  269. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_route.json +0 -0
  270. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_uq.json +0 -0
  271. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_v.json +0 -0
  272. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/SHA256_LOCK_ws_wv.json +0 -0
  273. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/paper1.yaml +0 -0
  274. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/paper2.yaml +0 -0
  275. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/paper3.yaml +0 -0
  276. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/paper4.yaml +0 -0
  277. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/phase0.yaml +0 -0
  278. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_a.yaml +0 -0
  279. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_atlas.yaml +0 -0
  280. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_b.yaml +0 -0
  281. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_ba.yaml +0 -0
  282. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_ba_v33.yaml +0 -0
  283. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_ba_v45.yaml +0 -0
  284. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_bench.yaml +0 -0
  285. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_c.yaml +0 -0
  286. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_cal.yaml +0 -0
  287. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_cite.yaml +0 -0
  288. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_crit.yaml +0 -0
  289. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_ct.yaml +0 -0
  290. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_d.yaml +0 -0
  291. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_e.yaml +0 -0
  292. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_env.yaml +0 -0
  293. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_ep.yaml +0 -0
  294. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_epitope.yaml +0 -0
  295. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_f.yaml +0 -0
  296. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_g.yaml +0 -0
  297. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_genotox.yaml +0 -0
  298. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_graph.yaml +0 -0
  299. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_h.yaml +0 -0
  300. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_immune.yaml +0 -0
  301. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_mc.yaml +0 -0
  302. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_mon.yaml +0 -0
  303. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_o.yaml +0 -0
  304. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_plan.yaml +0 -0
  305. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_r.yaml +0 -0
  306. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_route.yaml +0 -0
  307. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_uq.yaml +0 -0
  308. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_v.yaml +0 -0
  309. {pen_stack-5.3.0 → pen_stack-5.5.0}/prereg/ws_wv.yaml +0 -0
  310. {pen_stack-5.3.0 → pen_stack-5.5.0}/scripts/p1_build_atlas.py +0 -0
  311. {pen_stack-5.3.0 → pen_stack-5.5.0}/scripts/p1_build_durability.py +0 -0
  312. {pen_stack-5.3.0 → pen_stack-5.5.0}/scripts/p1_export_tracks.py +0 -0
  313. {pen_stack-5.3.0 → pen_stack-5.5.0}/scripts/p1_safety_concordance.py +0 -0
  314. {pen_stack-5.3.0 → pen_stack-5.5.0}/scripts/p1_train_safety.py +0 -0
  315. {pen_stack-5.3.0 → pen_stack-5.5.0}/scripts/p1_validation_report.py +0 -0
  316. {pen_stack-5.3.0 → pen_stack-5.5.0}/scripts/p2_build_atlas.py +0 -0
  317. {pen_stack-5.3.0 → pen_stack-5.5.0}/scripts/p3_benchmark_report.py +0 -0
  318. {pen_stack-5.3.0 → pen_stack-5.5.0}/scripts/p4_genome_scan.py +0 -0
  319. {pen_stack-5.3.0 → pen_stack-5.5.0}/scripts/p52_build_genotox_oracle.py +0 -0
  320. {pen_stack-5.3.0 → pen_stack-5.5.0}/scripts/p53_build_epitope_oracle.py +0 -0
  321. {pen_stack-5.3.0 → pen_stack-5.5.0}/scripts/ws_b_report.py +0 -0
  322. {pen_stack-5.3.0 → pen_stack-5.5.0}/scripts/ws_c_report.py +0 -0
  323. {pen_stack-5.3.0 → pen_stack-5.5.0}/setup.cfg +0 -0
@@ -3,6 +3,67 @@
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.5.0] - 2026-06-10 - v5.5 release: Anti-vector seroprevalence oracle (the last immune axis, from data)
7
+
8
+ Completes the computable delivery-immunology axes. **Pre-existing humoral immunity** (B-cell / neutralizing
9
+ antibody) to a viral capsid is the one immune axis that *cannot* be computed from sequence — it is a population
10
+ prevalence from natural exposure. v5.5 grounds it in published **serosurvey data**. Workstream WS-SEROPREV,
11
+ SHA-locked.
12
+
13
+ ### Added
14
+ - **WS-SEROPREV table** — `configs/seroprevalence.yaml`: curated population NAb/IgG seroprevalence per serotype
15
+ as **ranges** (region/age/assay variation) with DOIs — AAV (Calcedo 2009, Boutin 2010), adenovirus type 5
16
+ (Mast 2010), HSV-1 (Looker 2015), VSV (negligible).
17
+ - **WS-SEROPREV oracle** — `pen_stack/planner/seroprevalence_oracle.py`: `seroprevalence_oracle(vehicle,
18
+ serotype=None)` → `OracleResult`. `preexisting_score = 1 − midpoint(seroprevalence)/100`; the range width is
19
+ surfaced as `native_uncertainty`. Non-viral → 1.0 by mechanism; unknown → **abstains**.
20
+ - **Wired into the pre-existing axis** — `safety_efficacy_profile()` folds the computed seroprevalence score
21
+ into the `preexisting_immunity` sub-axis **only for in-vivo vehicles** (serum NAb neutralises the vector in
22
+ vivo; ex-vivo transduction in a dish is not reached by host antibody → reported but muted). `seroprevalence_score`
23
+ surfaces the raw value.
24
+ - **Result (from data):** adenovirus has the highest pre-existing seroprevalence (40–90%, score 0.35), AAV
25
+ intermediate (30–60%, 0.55), VSV/lentivirus negligible (0–5%, 0.975) — the documented ordering quantified
26
+ from serosurveys. `prereg/ws_seroprev.yaml`.
27
+
28
+ ### Changed
29
+ - Version 5.4.0 -> 5.5.0 (minor — additive data-grounded oracle); `cite.curated_dois()` ingests the
30
+ seroprevalence DOIs.
31
+
32
+ ### Honesty invariant (unchanged)
33
+ - A **population** prevalence (a range; region/age/assay-dependent), **not** a given **patient's** NAb titer /
34
+ sero-status (a clinical test, patient-specific → a known-unknown); the **humoral (B-cell)** axis only,
35
+ distinct from the v5.3 T-cell epitope load. No patient-specific magnitude predicted.
36
+
37
+ ## [5.4.0] - 2026-06-10 - v5.4 release: Computed innate-sensing scorer (completes the computable immune axes)
38
+
39
+ The third computed delivery-immunology signal, after v5.2 genotoxicity and v5.3 capsid epitope load. Innate
40
+ sensing of a delivered nucleic acid is computed directly from the **cargo sequence** — CpG O/E for DNA (TLR9),
41
+ U-richness + dsRNA for mRNA (TLR7/RIG-I) — covering every cargo form. Workstream WS-INNATE, SHA-locked.
42
+
43
+ ### Added
44
+ - **WS-INNATE scorer** — `pen_stack/planner/innate_sensing.py`: `cpg_observed_expected()` (Gardiner-Garden &
45
+ Frommer) + `innate_sensing(seq, cargo_form)` → `OracleResult`. **DNA** → CpG O/E (vertebrate genome ~0.2
46
+ tolerated; non-depleted DNA → 1 TLR9-stimulatory), `innate_score = max(0, 1 − CpG_O/E)`. **mRNA** → uridine
47
+ fraction + ViennaRNA dsRNA pairing (graceful when ViennaRNA absent), flagged **partial/`extrapolating`**.
48
+ **RNP** → minimal/transient. Abstains on empty / unrecognised input (never fabricates). Pure sequence
49
+ computation — no external data, runs in CI.
50
+ - **Surfaced in `verify()`** — when a design supplies `cargo_seq`, the computed innate load is attached as a
51
+ `cargo_innate_sensing` scope flag (cargo form from the writer output form, else the vehicle's first
52
+ compatible form) and added to `delivery_profile.cargo_innate`. No confidence added; the realized in-vivo
53
+ innate response stays a known-unknown.
54
+ - Scope card `innate_sensing`; `prereg/ws_innate.yaml`. `cite.curated_dois()` ingests the innate provenance
55
+ DOIs (CpG-TLR9 10.1073/pnas.161293498, CpG-depleted AAV 10.1172/JCI68205, RNA modification
56
+ 10.1016/j.immuni.2005.06.008, + Krieg 1995 / Hornung 2006).
57
+
58
+ ### Changed
59
+ - Version 5.3.0 -> 5.4.0 (minor — additive computed scorer).
60
+
61
+ ### Honesty invariant (unchanged)
62
+ - Sequence-intrinsic motif-**load** signal. The realized **in-vivo innate response** magnitude in a patient is
63
+ **not** modelled (known-unknown); the mRNA score is **partial** because the dominant evasion lever —
64
+ **nucleoside modification** (m1-pseudouridine) — is a manufacturing choice not derivable from sequence; DNA
65
+ methylation state is likewise out of scope. No magnitude predicted.
66
+
6
67
  ## [5.3.0] - 2026-06-10 - v5.3 release: Computed capsid epitope-load oracle (covers all vectors)
7
68
 
8
69
  v5.2 computed genotoxicity only meaningfully touches integrating vectors. v5.3 brings the **NetMHC-style
@@ -1,7 +1,7 @@
1
1
  cff-version: 1.2.0
2
2
  message: "If you use PEN-STACK, please cite it as below."
3
3
  title: "PEN-STACK: open infrastructure for genome writing"
4
- version: 5.3.0
4
+ version: 5.5.0
5
5
  date-released: 2026-06-10
6
6
  authors:
7
7
  - family-names: "Mahaboob Ali"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pen-stack
3
- Version: 5.3.0
3
+ Version: 5.5.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
@@ -91,7 +91,7 @@ every design against rule-grounded mechanism, reports calibrated confidence, cit
91
91
  [![codecov](https://codecov.io/gh/ahmedanees-m/pen-stack/branch/main/graph/badge.svg)](https://codecov.io/gh/ahmedanees-m/pen-stack)
92
92
  [![License: MIT](https://img.shields.io/badge/License-MIT-informational.svg)](LICENSE)
93
93
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
94
- [![Version](https://img.shields.io/badge/version-5.3.0-blue.svg)](CHANGELOG.md)
94
+ [![Version](https://img.shields.io/badge/version-5.5.0-blue.svg)](CHANGELOG.md)
95
95
  [![Tests](https://img.shields.io/badge/tests-240%20passing-success.svg)](tests/)
96
96
  [![Lint: ruff](https://img.shields.io/badge/lint-ruff-purple.svg)](https://github.com/astral-sh/ruff)
97
97
  [![Runtime: Docker](https://img.shields.io/badge/runtime-docker-2496ED.svg)](docker/)
@@ -135,6 +135,47 @@ Two questions gate every genome-writing project, and before PEN-STACK no resourc
135
135
  Everything is built on bulk-downloadable public data, runs on a single GPU, and is validated **blind** against
136
136
  a pre-registered, honest baseline before release.
137
137
 
138
+ ## What is new in v5.5 — Anti-vector seroprevalence oracle (the last immune axis, from data)
139
+
140
+ This completes the computable delivery-immunology axes. **Pre-existing humoral immunity** (B-cell / NAb) to a
141
+ viral capsid is the one axis that *cannot* be computed from sequence — it is a population prevalence from
142
+ natural exposure — so v5.5 grounds it in published **serosurvey data** (AAV: Calcedo 2009 / Boutin 2010;
143
+ adenovirus: Mast 2010; HSV-1: Looker 2015). `preexisting_score = 1 − midpoint(seroprevalence)/100`, with the
144
+ literature range surfaced as native uncertainty.
145
+
146
+ | serotype (vehicle) | NAb seroprevalence | pre-existing score |
147
+ |---|---|---|
148
+ | Ad5 → HDAd | 40–90% | 0.35 |
149
+ | AAV (aggregate) → AAV | 30–60% | 0.55 |
150
+ | HSV-1 → HSV | 50–70% | 0.40 |
151
+ | VSV → lentivirus | 0–5% | 0.975 |
152
+
153
+ Folded into the pre-existing axis for **in-vivo** vehicles (muted for ex-vivo, where serum NAb can't reach
154
+ ex-vivo cells); non-viral → 1.0 by mechanism. It is a **population** prevalence — **not** a given patient's NAb
155
+ titer (a known-unknown). See `pen_stack/planner/seroprevalence_oracle.py`, `configs/seroprevalence.yaml`,
156
+ `prereg/ws_seroprev.yaml`, and the `seroprevalence` scope card.
157
+
158
+ **With v5.5, four of the five delivery-immunology axes are grounded in data or sequence** — genotoxicity
159
+ (VISDB×COSMIC), adaptive/CD8 (MHCflurry), innate (CpG/dsRNA), pre-existing/NAb (serosurveys) — each abstaining
160
+ rather than fabricating, with the in-vivo *magnitude* always a declared known-unknown.
161
+
162
+ ## What is new in v5.4 — Computed innate-sensing scorer (completes the computable immune axes)
163
+
164
+ The third computed delivery-immunology signal (after v5.2 genotoxicity and v5.3 capsid epitope load). Innate
165
+ sensing of a delivered nucleic acid is computed directly from the **cargo sequence**, covering every cargo
166
+ form. It is a sequence-intrinsic motif-*load* signal; the realized in-vivo innate response stays a
167
+ known-unknown, and the mRNA score is honestly *partial* (the dominant lever — nucleoside modification — isn't
168
+ derivable from sequence).
169
+
170
+ | Cargo form | Pathway | Computed from sequence | Score |
171
+ |---|---|---|---|
172
+ | **DNA** (AAV / HDAd / HSV / plasmid) | TLR9 / cGAS | CpG observed/expected ratio | `max(0, 1 − CpG_O/E)` — vertebrate genome ~0.2 tolerated, non-depleted DNA → 1 stimulatory |
173
+ | **mRNA** (LNP-mRNA / electroporation) | TLR7/8 + RIG-I/MDA5/PKR | U-fraction + ViennaRNA dsRNA pairing | partial / `extrapolating` (nucleoside modification out of scope) |
174
+ | **RNP** (eVLP / electroporation) | minimal (transient gRNA) | — | ~0.9 by mechanism |
175
+
176
+ `verify()` surfaces it as a `cargo_innate_sensing` flag whenever a `cargo_seq` is supplied. See
177
+ `pen_stack/planner/innate_sensing.py`, `prereg/ws_innate.yaml`, and the `innate_sensing` scope card.
178
+
138
179
  ## What is new in v5.3 — Computed capsid epitope-load oracle (covers all vectors)
139
180
 
140
181
  v5.2 computed genotoxicity only touches integrating vectors. v5.3 brings the **NetMHC-style calculation** to the
@@ -16,7 +16,7 @@ every design against rule-grounded mechanism, reports calibrated confidence, cit
16
16
  [![codecov](https://codecov.io/gh/ahmedanees-m/pen-stack/branch/main/graph/badge.svg)](https://codecov.io/gh/ahmedanees-m/pen-stack)
17
17
  [![License: MIT](https://img.shields.io/badge/License-MIT-informational.svg)](LICENSE)
18
18
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
19
- [![Version](https://img.shields.io/badge/version-5.3.0-blue.svg)](CHANGELOG.md)
19
+ [![Version](https://img.shields.io/badge/version-5.5.0-blue.svg)](CHANGELOG.md)
20
20
  [![Tests](https://img.shields.io/badge/tests-240%20passing-success.svg)](tests/)
21
21
  [![Lint: ruff](https://img.shields.io/badge/lint-ruff-purple.svg)](https://github.com/astral-sh/ruff)
22
22
  [![Runtime: Docker](https://img.shields.io/badge/runtime-docker-2496ED.svg)](docker/)
@@ -60,6 +60,47 @@ Two questions gate every genome-writing project, and before PEN-STACK no resourc
60
60
  Everything is built on bulk-downloadable public data, runs on a single GPU, and is validated **blind** against
61
61
  a pre-registered, honest baseline before release.
62
62
 
63
+ ## What is new in v5.5 — Anti-vector seroprevalence oracle (the last immune axis, from data)
64
+
65
+ This completes the computable delivery-immunology axes. **Pre-existing humoral immunity** (B-cell / NAb) to a
66
+ viral capsid is the one axis that *cannot* be computed from sequence — it is a population prevalence from
67
+ natural exposure — so v5.5 grounds it in published **serosurvey data** (AAV: Calcedo 2009 / Boutin 2010;
68
+ adenovirus: Mast 2010; HSV-1: Looker 2015). `preexisting_score = 1 − midpoint(seroprevalence)/100`, with the
69
+ literature range surfaced as native uncertainty.
70
+
71
+ | serotype (vehicle) | NAb seroprevalence | pre-existing score |
72
+ |---|---|---|
73
+ | Ad5 → HDAd | 40–90% | 0.35 |
74
+ | AAV (aggregate) → AAV | 30–60% | 0.55 |
75
+ | HSV-1 → HSV | 50–70% | 0.40 |
76
+ | VSV → lentivirus | 0–5% | 0.975 |
77
+
78
+ Folded into the pre-existing axis for **in-vivo** vehicles (muted for ex-vivo, where serum NAb can't reach
79
+ ex-vivo cells); non-viral → 1.0 by mechanism. It is a **population** prevalence — **not** a given patient's NAb
80
+ titer (a known-unknown). See `pen_stack/planner/seroprevalence_oracle.py`, `configs/seroprevalence.yaml`,
81
+ `prereg/ws_seroprev.yaml`, and the `seroprevalence` scope card.
82
+
83
+ **With v5.5, four of the five delivery-immunology axes are grounded in data or sequence** — genotoxicity
84
+ (VISDB×COSMIC), adaptive/CD8 (MHCflurry), innate (CpG/dsRNA), pre-existing/NAb (serosurveys) — each abstaining
85
+ rather than fabricating, with the in-vivo *magnitude* always a declared known-unknown.
86
+
87
+ ## What is new in v5.4 — Computed innate-sensing scorer (completes the computable immune axes)
88
+
89
+ The third computed delivery-immunology signal (after v5.2 genotoxicity and v5.3 capsid epitope load). Innate
90
+ sensing of a delivered nucleic acid is computed directly from the **cargo sequence**, covering every cargo
91
+ form. It is a sequence-intrinsic motif-*load* signal; the realized in-vivo innate response stays a
92
+ known-unknown, and the mRNA score is honestly *partial* (the dominant lever — nucleoside modification — isn't
93
+ derivable from sequence).
94
+
95
+ | Cargo form | Pathway | Computed from sequence | Score |
96
+ |---|---|---|---|
97
+ | **DNA** (AAV / HDAd / HSV / plasmid) | TLR9 / cGAS | CpG observed/expected ratio | `max(0, 1 − CpG_O/E)` — vertebrate genome ~0.2 tolerated, non-depleted DNA → 1 stimulatory |
98
+ | **mRNA** (LNP-mRNA / electroporation) | TLR7/8 + RIG-I/MDA5/PKR | U-fraction + ViennaRNA dsRNA pairing | partial / `extrapolating` (nucleoside modification out of scope) |
99
+ | **RNP** (eVLP / electroporation) | minimal (transient gRNA) | — | ~0.9 by mechanism |
100
+
101
+ `verify()` surfaces it as a `cargo_innate_sensing` flag whenever a `cargo_seq` is supplied. See
102
+ `pen_stack/planner/innate_sensing.py`, `prereg/ws_innate.yaml`, and the `innate_sensing` scope card.
103
+
63
104
  ## What is new in v5.3 — Computed capsid epitope-load oracle (covers all vectors)
64
105
 
65
106
  v5.2 computed genotoxicity only touches integrating vectors. v5.3 brings the **NetMHC-style calculation** to the
@@ -138,3 +138,31 @@ oracles:
138
138
  a viral vehicle whose antigen sequence is not committed (abstains)"
139
139
  generalizes_to_unseen_loci: false
140
140
  license: "open (this work; MHCflurry 10.1016/j.cels.2020.06.010, HLA-I supertypes 10.1186/1471-2172-9-1)"
141
+
142
+ innate_sensing: # v5.4 WS-INNATE: computed nucleic-acid innate-sensing motif load
143
+ family: genome
144
+ version: "cpg-oe+dsrna-2026"
145
+ output_kind: baseline # deterministic sequence statistic, not generative
146
+ valid_for: "sequence-intrinsic innate-sensing LOAD of a cargo sequence: CpG observed/expected (DNA ->
147
+ TLR9/cGAS; CpG-depleted DNA is tolerated, non-depleted is stimulatory) and U-richness + dsRNA pairing
148
+ (mRNA -> TLR7/8 + RIG-I/MDA5/PKR); a relative, computable proxy"
149
+ not_valid_for: "the realized IN-VIVO innate RESPONSE magnitude in a patient (a known-unknown); RNA
150
+ NUCLEOSIDE MODIFICATION (m1-pseudouridine), the dominant mRNA evasion lever - NOT sequence-derivable
151
+ (the mRNA score is PARTIAL / extrapolating); DNA methylation state of the delivered cargo"
152
+ generalizes_to_unseen_loci: false
153
+ license: "open (this work; CpG-TLR9 10.1073/pnas.161293498, CpG-depleted AAV 10.1172/JCI68205,
154
+ RNA modification 10.1016/j.immuni.2005.06.008)"
155
+
156
+ seroprevalence: # v5.5 WS-SEROPREV: anti-vector NAb seroprevalence from serosurvey data
157
+ family: genome
158
+ version: "serosurvey-2026"
159
+ output_kind: baseline # curated empirical population data, not a model
160
+ valid_for: "POPULATION pre-existing neutralizing-antibody seroprevalence per capsid serotype, from published
161
+ serosurveys (AAV Calcedo/Boutin, Ad5 Mast, HSV-1 Looker); preexisting_score = 1 - midpoint/100. The one
162
+ immune axis that is empirical, not sequence-computable"
163
+ not_valid_for: "a given PATIENT's NAb titer / sero-status (a clinical test, patient-specific -> a
164
+ known-unknown); precise region/age/assay-specific values (a range, not a point); functional-NAb vs
165
+ IgG-binding distinctions; T-cell immunity (that is the capsid_epitope oracle); anti-PEG immunity"
166
+ generalizes_to_unseen_loci: false
167
+ license: "open (this work; Calcedo 10.1086/595830, Boutin 10.1089/hum.2009.182, Mast
168
+ 10.1016/j.vaccine.2009.10.145, Looker 10.1371/journal.pone.0140765)"
@@ -0,0 +1,64 @@
1
+ # PEN-STACK v5.5 - anti-vector neutralizing-antibody SEROPREVALENCE (WS-SEROPREV).
2
+ #
3
+ # Pre-existing humoral immunity to a viral capsid is the one immune axis that CANNOT be computed from sequence:
4
+ # it is the prevalence, in a population, of people who already carry neutralizing antibodies against the vector
5
+ # from natural exposure. The only honest grounding is published serosurvey DATA. This table curates the
6
+ # population NAb/IgG seroprevalence per serotype from canonical serosurveys, as RANGES (the literature varies by
7
+ # region, age, and assay - IgG-binding vs functional-NAb), each with >=1 DOI.
8
+ #
9
+ # preexisting_score = 1 - midpoint(seroprevalence_pct)/100 (1 = fewest patients excluded by pre-existing NAb).
10
+ #
11
+ # HONESTY (scope card `seroprevalence`): this is a POPULATION prevalence, NOT a given patient's NAb titer (that
12
+ # is a clinical test, patient-specific -> a known-unknown); it is region/age/assay-dependent (ranges, not point
13
+ # values); and it is the pre-existing HUMORAL axis only (B-cell / antibody), distinct from the T-cell epitope
14
+ # load computed in v5.3.
15
+
16
+ version: "1.0"
17
+
18
+ serotypes:
19
+ AAV_aggregate: # serotype-agnostic AAV (AAV_single / AAV_dual): across common serotypes
20
+ nab_seroprevalence_pct: [30, 60]
21
+ note: "serotype- and region-dependent; AAV2 highest, AAV8/9 lower"
22
+ dois: ["10.1086/595830", "10.1089/hum.2009.182"]
23
+ AAV2:
24
+ nab_seroprevalence_pct: [50, 72]
25
+ note: "highest of the common serotypes (Calcedo ~72%, Boutin IgG ~67%)"
26
+ dois: ["10.1086/595830", "10.1089/hum.2009.182"]
27
+ AAV1:
28
+ nab_seroprevalence_pct: [50, 67]
29
+ dois: ["10.1089/hum.2009.182"]
30
+ AAV5:
31
+ nab_seroprevalence_pct: [30, 40]
32
+ dois: ["10.1089/hum.2009.182", "10.1086/595830"]
33
+ AAV6:
34
+ nab_seroprevalence_pct: [30, 46]
35
+ dois: ["10.1089/hum.2009.182"]
36
+ AAV8:
37
+ nab_seroprevalence_pct: [20, 40]
38
+ note: "lower pre-existing immunity (Calcedo ~38%)"
39
+ dois: ["10.1086/595830", "10.1089/hum.2009.182"]
40
+ AAV9:
41
+ nab_seroprevalence_pct: [30, 50]
42
+ dois: ["10.1086/595830"]
43
+ Ad5:
44
+ nab_seroprevalence_pct: [40, 90]
45
+ note: "very high and strongly region-dependent (highest in sub-Saharan Africa); Mast 2010"
46
+ dois: ["10.1016/j.vaccine.2009.10.145"]
47
+ HSV1:
48
+ nab_seroprevalence_pct: [50, 70]
49
+ note: "global adult HSV-1 seroprevalence (Looker 2015, ages 0-49 ~67%)"
50
+ dois: ["10.1371/journal.pone.0140765"]
51
+ VSV:
52
+ nab_seroprevalence_pct: [0, 5]
53
+ note: "VSV is not endemic in humans -> negligible pre-existing immunity to VSV-G-pseudotyped lentivirus"
54
+ dois: ["10.1038/mt.2011.287"]
55
+
56
+ # which serotype grounds each vehicle's pre-existing-immunity axis. Non-viral vehicles carry no foreign capsid
57
+ # -> no pre-existing ANTI-VECTOR humoral immunity (anti-PEG for LNP is an emerging, separate exception).
58
+ vehicle_serotype:
59
+ AAV_single: AAV_aggregate
60
+ AAV_dual: AAV_aggregate
61
+ helper_dependent_adenovirus: Ad5
62
+ hsv_amplicon: HSV1
63
+ lentivirus: VSV
64
+ non_viral: [lnp_mrna, evlp, electroporation]
@@ -1,2 +1,2 @@
1
1
  """PEN-STACK v3.0 - open infrastructure for genome writing."""
2
- __version__ = "5.3.0"
2
+ __version__ = "5.5.0"
@@ -36,6 +36,16 @@ def curated_dois() -> frozenset[str]:
36
36
  dois.update(a.get("provenance_dois", []) or [])
37
37
  except FileNotFoundError:
38
38
  pass
39
+ # v5.4 computed innate-sensing provenance (CpG-TLR9 / AAV CpG-depletion / RNA modification)
40
+ from pen_stack.planner.innate_sensing import PROVENANCE_DOIS as _innate_dois
41
+ dois.update(_innate_dois)
42
+ # v5.5 anti-vector seroprevalence provenance (serosurveys)
43
+ try:
44
+ sp = yaml.safe_load(resource("configs/seroprevalence.yaml").read_text(encoding="utf-8"))
45
+ for _rec in (sp.get("serotypes") or {}).values():
46
+ dois.update(_rec.get("dois", []) or [])
47
+ except FileNotFoundError:
48
+ pass
39
49
  gsh = yaml.safe_load(resource("configs/gsh_validated_heldout.yaml").read_text(encoding="utf-8"))["gsh"]
40
50
  for g in gsh:
41
51
  if g.get("doi"):
@@ -78,6 +78,17 @@ def safety_efficacy_profile(name: str) -> dict | None:
78
78
  adaptive_source = "computed"
79
79
  elif cap_score is not None and not in_vivo:
80
80
  adaptive_source = "computed_ex_vivo_muted" # reported, but ex-vivo mutes the realized response
81
+ # PRE-EXISTING immunity (B-cell / NAb): grounded in published serosurvey data (v5.5 WS-SEROPREV). Folded
82
+ # only for IN-VIVO vehicles (serum NAb neutralises the vector in vivo; ex-vivo transduction in a dish is
83
+ # not reached by host antibody, so for ex-vivo vehicles it is reported but muted).
84
+ from pen_stack.planner.seroprevalence_oracle import computed_preexisting_score
85
+ pre_score, pre_oracle = computed_preexisting_score(name)
86
+ preexisting_source = "documented"
87
+ if pre_score is not None and in_vivo:
88
+ axis_scores["preexisting_immunity"] = pre_score
89
+ preexisting_source = "computed"
90
+ elif pre_score is not None and not in_vivo:
91
+ preexisting_source = "computed_ex_vivo_muted"
81
92
  immune_present = [s for s in axis_scores.values() if s is not None]
82
93
  immune_score = (sum(immune_present) / len(immune_present)) if immune_present else None
83
94
  # genotoxicity: prefer the COMPUTED oracle (v5.2 WS-GENOTOX: integration-site x COSMIC-oncogene
@@ -102,6 +113,9 @@ def safety_efficacy_profile(name: str) -> dict | None:
102
113
  "adaptive_source": adaptive_source, # computed | computed_ex_vivo_muted | documented
103
114
  "capsid_presentability_score": _r(cap_score), # computed intrinsic capsid CD8 presentability (or None)
104
115
  "adaptive_provenance": (cap_oracle.note if cap_score is not None else None),
116
+ "preexisting_source": preexisting_source, # computed | computed_ex_vivo_muted | documented
117
+ "seroprevalence_score": _r(pre_score), # computed pre-existing-NAb score (or None)
118
+ "preexisting_provenance": (pre_oracle.note if pre_score is not None else None),
105
119
  "genotox_score": _r(genotox_score),
106
120
  "genotox_source": genotox_source, # "computed" (VISDBxCOSMIC oracle) | "documented" (ordinal tier)
107
121
  "genotox_provenance": (gtox_oracle.note if genotox_source == "computed" else None),
@@ -0,0 +1,135 @@
1
+ """Computed innate-immune-sensing scorer for nucleic-acid cargo (v5.4, WS-INNATE).
2
+
3
+ Innate sensing of a delivered nucleic acid is a property of the CARGO SEQUENCE (and its form), computed here
4
+ directly from sequence - the third computed delivery-immunology signal (after v5.2 genotoxicity and v5.3 capsid
5
+ epitope load). It covers every cargo form the palette carries:
6
+
7
+ * DNA (AAV / HDAd / HSV / electroporated plasmid) -> TLR9 / cGAS sensing of unmethylated CpG. The standard
8
+ sequence statistic is the CpG observed/expected ratio (Gardiner-Garden & Frommer): vertebrate genomes are
9
+ CpG-DEPLETED (O/E ~ 0.2) and tolerated, while non-depleted plasmid/viral DNA (O/E -> 1) is TLR9-stimulatory;
10
+ CpG-DEPLETED vectors evade detection. innate_score = max(0, 1 - CpG_O/E).
11
+ * mRNA (LNP-mRNA / electroporated mRNA) -> TLR7/8 (U-rich ssRNA) + RIG-I / MDA5 / PKR (dsRNA). Computed from
12
+ uridine fraction + ViennaRNA base-pairing. This signal is PARTIAL and flagged `extrapolating`: the dominant
13
+ innate-evasion lever for mRNA is NUCLEOSIDE MODIFICATION (m1-pseudouridine), which is NOT derivable from the
14
+ nucleotide sequence (a manufacturing choice) - a stated known-limitation.
15
+ * RNP / protein -> minimal, transient nucleic-acid exposure (no DNA; short-lived gRNA): score ~ high.
16
+
17
+ Answers through the v4.0 OracleResult contract (output_kind="baseline"). HONESTY: this is a sequence-intrinsic
18
+ motif-LOAD signal; the realized in-vivo innate RESPONSE magnitude in a patient is NOT modelled and stays a
19
+ known-unknown; DNA methylation state and RNA nucleoside modification are out of sequence scope.
20
+ """
21
+ from __future__ import annotations
22
+
23
+ from pen_stack.oracles.schema import OracleResult, Provenance
24
+
25
+ _SCOPE_CARD = "innate_sensing"
26
+ _DNA = set("ACGT")
27
+ _RNA = set("ACGU")
28
+ # CpG-TLR9 (Krieg 1995 / Bauer 2001), CpG-depleted AAV evasion (Faust 2013), RNA nucleoside modification
29
+ # (Kariko 2005), 5'ppp dsRNA RIG-I (Hornung 2006).
30
+ PROVENANCE_DOIS = ["10.1038/374546a0", "10.1073/pnas.161293498", "10.1172/JCI68205",
31
+ "10.1016/j.immuni.2005.06.008", "10.1126/science.1132505"]
32
+
33
+
34
+ def _clean(seq: str) -> str:
35
+ return "".join(c for c in (seq or "").upper() if c.isalpha())
36
+
37
+
38
+ def cpg_observed_expected(dna: str) -> dict:
39
+ """CpG observed/expected ratio (Gardiner-Garden & Frommer): (n_CpG / (n_C * n_G)) * length. Vertebrate
40
+ genome ~0.2 (depleted); non-depleted plasmid/viral DNA approaches 1; engineered CpG-free -> 0."""
41
+ s = _clean(dna).replace("U", "T")
42
+ L = len(s)
43
+ nC, nG = s.count("C"), s.count("G")
44
+ n_cpg = s.count("CG")
45
+ oe = (n_cpg / (nC * nG) * L) if (nC and nG) else 0.0
46
+ gc = (nC + nG) / L if L else 0.0
47
+ return {"length": L, "cpg_count": n_cpg, "cpg_oe": round(oe, 4), "gc": round(gc, 4)}
48
+
49
+
50
+ def _dsrna_paired_fraction(rna: str) -> float | None:
51
+ """Fraction of bases paired in the ViennaRNA MFE structure (dsRNA -> RIG-I/MDA5/PKR). None if ViennaRNA
52
+ absent (graceful degradation, as in bridge/fold_qc.py)."""
53
+ try:
54
+ import RNA
55
+ except Exception: # noqa: BLE001
56
+ return None
57
+ s = _clean(rna).replace("T", "U")
58
+ if not s:
59
+ return None
60
+ struct, _ = RNA.fold_compound(s).mfe()
61
+ paired = sum(1 for c in struct if c in "()")
62
+ return round(paired / len(struct), 4) if struct else None
63
+
64
+
65
+ def _prov() -> Provenance:
66
+ return Provenance(model="cargo_innate_sensing", version="1.0", source="adapter",
67
+ extra={"provenance_dois": PROVENANCE_DOIS})
68
+
69
+
70
+ def innate_sensing(seq: str, cargo_form: str) -> OracleResult:
71
+ """Computed innate-sensing score for a cargo sequence + form, as an OracleResult (v4.0 contract).
72
+
73
+ `cargo_form` in {DNA, mRNA, RNP}. Returns innate_score in [0,1] (1 = least innate-stimulatory). Abstains
74
+ (available=False) on an empty sequence or an unrecognised/uncomputable form. Never fabricates."""
75
+ s = _clean(seq)
76
+ form = (cargo_form or "").strip()
77
+ if not s:
78
+ return OracleResult(oracle="genome", value=None, provenance=_prov(), scope_card=_SCOPE_CARD,
79
+ in_scope=False, available=False, output_kind="baseline",
80
+ note="no cargo sequence supplied")
81
+
82
+ if form == "DNA":
83
+ c = cpg_observed_expected(s)
84
+ score = max(0.0, min(1.0, 1.0 - c["cpg_oe"]))
85
+ return OracleResult(
86
+ oracle="genome",
87
+ value={"innate_score": round(score, 3), "pathway": "TLR9/cGAS (unmethylated CpG)",
88
+ "cpg_oe": c["cpg_oe"], "cpg_count": c["cpg_count"], "gc": c["gc"], "length": c["length"]},
89
+ provenance=_prov(), native_uncertainty=None, scope_card=_SCOPE_CARD, in_scope=True,
90
+ extrapolating=False, output_kind="baseline", available=True,
91
+ note=(f"CpG O/E={c['cpg_oe']} ({c['cpg_count']} CpG, {c['length']} bp); innate_score=max(0,1-O/E). "
92
+ "Vertebrate genome O/E~0.2 (tolerated), non-depleted DNA ->1 (TLR9-stimulatory). DNA "
93
+ "methylation state and the realized in-vivo innate RESPONSE are known-unknowns (not modelled)."))
94
+
95
+ if form == "mRNA":
96
+ u_frac = s.replace("T", "U").count("U") / len(s)
97
+ paired = _dsrna_paired_fraction(s)
98
+ # partial sequence-only signal: U-richness (TLR7/8) + dsRNA pairing (RIG-I/PKR). The dominant evasion
99
+ # lever (nucleoside modification, m1-pseudouridine) is NOT sequence-derivable -> flagged extrapolating.
100
+ if paired is None:
101
+ score = max(0.0, min(1.0, 1.0 - u_frac))
102
+ note_ds = "ViennaRNA absent: dsRNA term omitted; score from U-fraction only."
103
+ else:
104
+ score = max(0.0, min(1.0, 1.0 - 0.5 * u_frac - 0.5 * paired))
105
+ note_ds = f"dsRNA paired_fraction={paired} (RIG-I/MDA5/PKR)."
106
+ return OracleResult(
107
+ oracle="rna",
108
+ value={"innate_score": round(score, 3), "pathway": "TLR7/8 (U-rich ssRNA) + RIG-I/MDA5/PKR (dsRNA)",
109
+ "u_fraction": round(u_frac, 4), "dsrna_paired_fraction": paired, "length": len(s)},
110
+ provenance=_prov(), native_uncertainty=None, scope_card=_SCOPE_CARD, in_scope=True,
111
+ extrapolating=True, output_kind="baseline", available=True,
112
+ note=("PARTIAL sequence-only signal. " + note_ds + " The dominant mRNA innate-evasion lever - "
113
+ "NUCLEOSIDE MODIFICATION (m1-pseudouridine) - is NOT sequence-derivable and is out of scope; "
114
+ "the realized in-vivo innate response is a known-unknown."))
115
+
116
+ if form == "RNP":
117
+ return OracleResult(
118
+ oracle="rna",
119
+ value={"innate_score": 0.9, "pathway": "minimal (transient gRNA; no DNA)", "length": len(s)},
120
+ provenance=_prov(), native_uncertainty=None, scope_card=_SCOPE_CARD, in_scope=True,
121
+ extrapolating=True, output_kind="baseline", available=True,
122
+ note=("RNP cargo: transient, no DNA -> minimal nucleic-acid innate sensing (synthetic gRNA may "
123
+ "trigger RIG-I via 5'-triphosphate; modification mitigates - not sequence-derivable). "
124
+ "Realized response is a known-unknown."))
125
+
126
+ return OracleResult(oracle="genome", value=None, provenance=_prov(), scope_card=_SCOPE_CARD,
127
+ in_scope=False, available=False, output_kind="baseline",
128
+ note=f"unrecognised cargo_form {cargo_form!r} (expected DNA / mRNA / RNP)")
129
+
130
+
131
+ def computed_innate_score(seq: str, cargo_form: str) -> tuple[float | None, OracleResult]:
132
+ """Convenience: (innate_score or None, full OracleResult). None when the scorer abstains. Never fabricates."""
133
+ r = innate_sensing(seq, cargo_form)
134
+ val = (r.value or {}).get("innate_score") if (r.available and r.value) else None
135
+ return val, r
@@ -0,0 +1,92 @@
1
+ """Anti-vector neutralizing-antibody seroprevalence oracle (v5.5, WS-SEROPREV).
2
+
3
+ The last computable delivery-immunology axis: PRE-EXISTING humoral immunity (B-cell / neutralizing antibody)
4
+ to a viral capsid. Unlike genotoxicity (v5.2), capsid T-cell epitope load (v5.3) and innate sensing (v5.4),
5
+ this CANNOT be computed from sequence - it is the prevalence, in a population, of people who already carry
6
+ NAbs against the vector from natural exposure. The honest grounding is published serosurvey DATA
7
+ (configs/seroprevalence.yaml), curated as ranges with provenance.
8
+
9
+ preexisting_score = 1 - midpoint(seroprevalence_pct) / 100 # 1 = fewest patients excluded by NAb
10
+
11
+ Answers through the v4.0 OracleResult contract (output_kind="baseline"). Non-viral vehicles carry no foreign
12
+ capsid -> no pre-existing ANTI-VECTOR humoral immunity (score 1.0 by mechanism). HONESTY: a POPULATION
13
+ prevalence, NOT a given patient's NAb titer (a known-unknown); region/age/assay-dependent (a range, surfaced);
14
+ the humoral (B-cell) axis only - distinct from the T-cell epitope load of v5.3.
15
+ """
16
+ from __future__ import annotations
17
+
18
+ from functools import lru_cache
19
+
20
+ import yaml
21
+
22
+ from pen_stack._resources import resource
23
+ from pen_stack.oracles.schema import OracleResult, Provenance
24
+
25
+ _SCOPE_CARD = "seroprevalence"
26
+
27
+
28
+ @lru_cache(maxsize=1)
29
+ def _table() -> dict:
30
+ return yaml.safe_load(resource("configs/seroprevalence.yaml").read_text(encoding="utf-8"))
31
+
32
+
33
+ def _all_dois() -> list[str]:
34
+ dois: set[str] = set()
35
+ for rec in (_table().get("serotypes") or {}).values():
36
+ dois.update(rec.get("dois", []) or [])
37
+ return sorted(dois)
38
+
39
+
40
+ def _prov(**extra) -> Provenance:
41
+ return Provenance(model="anti_vector_seroprevalence", version=str(_table().get("version", "1.0")),
42
+ source="cache", extra=extra)
43
+
44
+
45
+ def seroprevalence_oracle(vehicle_name: str, serotype: str | None = None) -> OracleResult:
46
+ """Pre-existing anti-vector NAb seroprevalence for a vehicle (or an explicit serotype), as an OracleResult.
47
+
48
+ - viral vehicle (or serotype) with curated data -> preexisting_score = 1 - midpoint(seroprevalence)/100.
49
+ - non-viral vehicle -> 1.0 by mechanism (no foreign capsid).
50
+ - unknown vehicle / no curated serotype -> available=False (caller falls back to the documented tier).
51
+ Never fabricates a number."""
52
+ t = _table()
53
+ sero = t.get("serotypes") or {}
54
+ key = serotype or (t.get("vehicle_serotype") or {}).get(vehicle_name)
55
+
56
+ if key and key in sero:
57
+ rec = sero[key]
58
+ lo, hi = rec["nab_seroprevalence_pct"]
59
+ mid = (lo + hi) / 2.0
60
+ score = max(0.0, min(1.0, 1.0 - mid / 100.0))
61
+ return OracleResult(
62
+ oracle="genome",
63
+ value={"preexisting_score": round(score, 3), "serotype": key,
64
+ "nab_seroprevalence_pct": [lo, hi], "midpoint_pct": mid, "dois": rec.get("dois", [])},
65
+ provenance=_prov(serotype=key, dois=rec.get("dois", [])), native_uncertainty=round((hi - lo) / 200.0, 4),
66
+ scope_card=_SCOPE_CARD, in_scope=True, extrapolating=False, output_kind="baseline", available=True,
67
+ note=(f"{key}: documented NAb seroprevalence {lo}-{hi}% (population); preexisting_score="
68
+ f"1-midpoint/100={score:.3f}. " + (rec.get("note", "") + " " if rec.get("note") else "")
69
+ + "A POPULATION prevalence, region/age/assay-dependent - NOT a given patient's NAb titer "
70
+ "(a known-unknown)."))
71
+
72
+ if vehicle_name in (t.get("non_viral") or []):
73
+ return OracleResult(
74
+ oracle="genome",
75
+ value={"preexisting_score": 1.0, "serotype": None, "mechanism": "non-viral"},
76
+ provenance=_prov(), native_uncertainty=0.0, scope_card=_SCOPE_CARD, in_scope=True,
77
+ extrapolating=False, output_kind="baseline", available=True,
78
+ note="non-viral vehicle: no foreign capsid -> no pre-existing ANTI-VECTOR humoral immunity (1.0). "
79
+ "Anti-PEG immunity for LNP is an emerging, separate exception (not a vector seroprevalence).")
80
+
81
+ return OracleResult(oracle="genome", value=None, provenance=_prov(), scope_card=_SCOPE_CARD,
82
+ in_scope=False, available=False, output_kind="baseline",
83
+ note=f"no curated seroprevalence for {vehicle_name!r}; fall back to the documented "
84
+ "preexisting_immunity tier.")
85
+
86
+
87
+ def computed_preexisting_score(vehicle_name: str, serotype: str | None = None) -> tuple[float | None, OracleResult]:
88
+ """Convenience: (preexisting_score or None, full OracleResult). None when the oracle abstains. Never
89
+ fabricates."""
90
+ r = seroprevalence_oracle(vehicle_name, serotype)
91
+ val = (r.value or {}).get("preexisting_score") if (r.available and r.value) else None
92
+ return val, r
@@ -107,6 +107,27 @@ def verify(design: Design | dict, question: str | None = None) -> Verdict:
107
107
  "reason": "documented ordinal immune/safety priors surfaced; the in-vivo immune "
108
108
  "MAGNITUDE remains a known-unknown (not predicted)"})
109
109
 
110
+ # v5.4 WS-INNATE: if a cargo SEQUENCE is supplied, compute its innate-sensing load from sequence
111
+ # (CpG/TLR9 for DNA, U/dsRNA for mRNA). Surfaced as a scope flag; the realized innate RESPONSE magnitude
112
+ # is a known-unknown. Cargo form = the writer output form, else the vehicle's first compatible form.
113
+ if design.cargo_seq:
114
+ form = design.writer_output_form
115
+ if not form and design.delivery_vehicle:
116
+ from pen_stack.planner.delivery_vehicles import vehicle as _veh
117
+ forms = (_veh(design.delivery_vehicle) or {}).get("compatible_cargo_form") or []
118
+ form = forms[0] if forms else None
119
+ if form:
120
+ from pen_stack.planner.innate_sensing import innate_sensing
121
+ inr = innate_sensing(design.cargo_seq, form)
122
+ if inr.available:
123
+ scope_flags.append({"kind": "cargo_innate_sensing", "cargo_form": form,
124
+ "innate_score": inr.value["innate_score"], "pathway": inr.value["pathway"],
125
+ "reason": "computed sequence-intrinsic innate-sensing load; the realized "
126
+ "in-vivo innate RESPONSE magnitude is a known-unknown"})
127
+ if delivery_profile is not None:
128
+ delivery_profile = dict(delivery_profile)
129
+ delivery_profile["cargo_innate"] = inr.value
130
+
110
131
  return Verdict(
111
132
  legal=routed["legal"], deferred=False, write_type=design.write_type, routing=routing,
112
133
  rule_results=results,