pen-stack 6.8.0__tar.gz → 6.9.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 (489) hide show
  1. {pen_stack-6.8.0 → pen_stack-6.9.0}/CHANGELOG.md +33 -0
  2. {pen_stack-6.8.0 → pen_stack-6.9.0}/CITATION.cff +1 -1
  3. {pen_stack-6.8.0 → pen_stack-6.9.0}/PKG-INFO +25 -2
  4. {pen_stack-6.8.0 → pen_stack-6.9.0}/README.md +24 -1
  5. pen_stack-6.9.0/configs/writer_sequences.fasta +12 -0
  6. pen_stack-6.9.0/docs/immune_profiler.md +53 -0
  7. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/__init__.py +1 -1
  8. pen_stack-6.9.0/pen_stack/planner/ada_risk.py +84 -0
  9. pen_stack-6.9.0/pen_stack/planner/immune_mhc2.py +114 -0
  10. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/immune_profile.py +58 -4
  11. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/immune_calibration.py +10 -0
  12. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack.egg-info/PKG-INFO +25 -2
  13. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack.egg-info/SOURCES.txt +6 -0
  14. pen_stack-6.9.0/prereg/SHA256_LOCK_ws_immune2.json +8 -0
  15. pen_stack-6.9.0/prereg/ws_immune2.yaml +36 -0
  16. {pen_stack-6.8.0 → pen_stack-6.9.0}/pyproject.toml +1 -1
  17. {pen_stack-6.8.0 → pen_stack-6.9.0}/LICENSE +0 -0
  18. {pen_stack-6.8.0 → pen_stack-6.9.0}/MANIFEST.in +0 -0
  19. {pen_stack-6.8.0 → pen_stack-6.9.0}/bench/run.py +0 -0
  20. {pen_stack-6.8.0 → pen_stack-6.9.0}/benchmarks/genome_writing_bench/LEADERBOARD.md +0 -0
  21. {pen_stack-6.8.0 → pen_stack-6.9.0}/benchmarks/genome_writing_bench/README.md +0 -0
  22. {pen_stack-6.8.0 → pen_stack-6.9.0}/benchmarks/genome_writing_bench/SHA256SUMS +0 -0
  23. {pen_stack-6.8.0 → pen_stack-6.9.0}/benchmarks/genome_writing_bench/SUBMISSIONS.md +0 -0
  24. {pen_stack-6.8.0 → pen_stack-6.9.0}/benchmarks/genome_writing_bench/tasks.yaml +0 -0
  25. {pen_stack-6.8.0 → pen_stack-6.9.0}/benchmarks/genome_writing_challenge/README.md +0 -0
  26. {pen_stack-6.8.0 → pen_stack-6.9.0}/benchmarks/genome_writing_challenge/SUBMISSIONS.md +0 -0
  27. {pen_stack-6.8.0 → pen_stack-6.9.0}/benchmarks/position_effect/README.md +0 -0
  28. {pen_stack-6.8.0 → pen_stack-6.9.0}/benchmarks/position_effect/SHA256SUMS +0 -0
  29. {pen_stack-6.8.0 → pen_stack-6.9.0}/benchmarks/writer_efficiency/README.md +0 -0
  30. {pen_stack-6.8.0 → pen_stack-6.9.0}/benchmarks/writer_efficiency/SHA256SUMS +0 -0
  31. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/antipeg.yaml +0 -0
  32. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/atlas_families.yaml +0 -0
  33. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/bridge_offtarget_profile.yaml +0 -0
  34. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/calibration/preexisting_nab_independent.yaml +0 -0
  35. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/capsid_epitope_oracle.yaml +0 -0
  36. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/capsid_sequences.fasta +0 -0
  37. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/cargo_polish.yaml +0 -0
  38. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/cell_types.yaml +0 -0
  39. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/datasets.yaml +0 -0
  40. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/delivery_constraints.yaml +0 -0
  41. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/delivery_rules.yaml +0 -0
  42. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/delivery_vehicles.yaml +0 -0
  43. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/expression/modifiers.yaml +0 -0
  44. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/expression/promoters.yaml +0 -0
  45. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/gates_v3.yaml +0 -0
  46. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/genotoxicity_oracle.yaml +0 -0
  47. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/gsh_validated_heldout.yaml +0 -0
  48. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/intent_weights.yaml +0 -0
  49. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/known_unknowns.yaml +0 -0
  50. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/llm.yaml +0 -0
  51. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/metric_guide.yaml +0 -0
  52. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/monitor_queries.yaml +0 -0
  53. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/oracles/execution.yaml +0 -0
  54. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/oracles/scope_cards.yaml +0 -0
  55. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/rules/delivery.yaml +0 -0
  56. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/rules/fold.yaml +0 -0
  57. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/rules/multiplex.yaml +0 -0
  58. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/rules/payload.yaml +0 -0
  59. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/rules/reachability.yaml +0 -0
  60. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/safety/hazard_registry.yaml +0 -0
  61. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/safety/policy.yaml +0 -0
  62. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/safety/probes.yaml +0 -0
  63. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/score_axes.yaml +0 -0
  64. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/seroprevalence.yaml +0 -0
  65. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/target_sites.yaml +0 -0
  66. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/universe_crosswalk.yaml +0 -0
  67. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/write_types.yaml +0 -0
  68. {pen_stack-6.8.0 → pen_stack-6.9.0}/configs/wtkb_curated.yaml +0 -0
  69. {pen_stack-6.8.0 → pen_stack-6.9.0}/data/curated/bridge_offtarget_energetics.json +0 -0
  70. {pen_stack-6.8.0 → pen_stack-6.9.0}/data/curated/bridge_offtarget_profile_measured.parquet +0 -0
  71. {pen_stack-6.8.0 → pen_stack-6.9.0}/data/curated/gene_coords.parquet +0 -0
  72. {pen_stack-6.8.0 → pen_stack-6.9.0}/data/curated/unified_editor_universe.parquet +0 -0
  73. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/BACKLOG.md +0 -0
  74. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/DEPLOY.md +0 -0
  75. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/INFRA.md +0 -0
  76. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/MCP.md +0 -0
  77. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/RELEASING.md +0 -0
  78. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/REPRO.md +0 -0
  79. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/STABILITY.md +0 -0
  80. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/agent.md +0 -0
  81. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/alphagenome_feasibility.md +0 -0
  82. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/autonomy.md +0 -0
  83. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/benchmark_circularity.md +0 -0
  84. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/biosecurity.md +0 -0
  85. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/build_interface.md +0 -0
  86. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/cards/atlas.md +0 -0
  87. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/cards/durability.md +0 -0
  88. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/cards/position_effect_data.md +0 -0
  89. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/cards/safety.md +0 -0
  90. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/cards/writer_efficiency_data.md +0 -0
  91. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/challenge.md +0 -0
  92. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/closed_loop.md +0 -0
  93. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/co_scientist.md +0 -0
  94. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/co_scientist_loop.md +0 -0
  95. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/delivery.md +0 -0
  96. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/delivery_immunology.md +0 -0
  97. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/digital_twin.md +0 -0
  98. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/dissemination.md +0 -0
  99. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/environment.md +0 -0
  100. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/experiment_design.md +0 -0
  101. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/generative_design.md +0 -0
  102. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/index.md +0 -0
  103. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/integrations.md +0 -0
  104. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/live_oracles.md +0 -0
  105. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/mechanistic_constraints.md +0 -0
  106. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/oracles.md +0 -0
  107. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/position_effect.md +0 -0
  108. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/positioning.md +0 -0
  109. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/private_data_formats.md +0 -0
  110. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/quickstart.md +0 -0
  111. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/responsible_use.md +0 -0
  112. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/rules.md +0 -0
  113. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/scope.md +0 -0
  114. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/scorecard.md +0 -0
  115. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/tpe_bench.md +0 -0
  116. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/tutorials/compare-families.md +0 -0
  117. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/tutorials/score-deliverability.md +0 -0
  118. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/tutorials/where-can-i-write.md +0 -0
  119. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/tutorials/which-writer-reaches-locus.md +0 -0
  120. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/uncertainty.md +0 -0
  121. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/verify.md +0 -0
  122. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/world_model.md +0 -0
  123. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/writer_efficiency.md +0 -0
  124. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/writer_verification.md +0 -0
  125. {pen_stack-6.8.0 → pen_stack-6.9.0}/docs/wtkb.md +0 -0
  126. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/_resources.py +0 -0
  127. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/active/__init__.py +0 -0
  128. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/active/acquire.py +0 -0
  129. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/active/design.py +0 -0
  130. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/active/validate.py +0 -0
  131. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/adapt/__init__.py +0 -0
  132. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/adapt/finetune.py +0 -0
  133. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/adapt/ingest.py +0 -0
  134. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/adapt/pipeline.py +0 -0
  135. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/adapt/recalibrate.py +0 -0
  136. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/adapt/report.py +0 -0
  137. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/agent/__init__.py +0 -0
  138. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/agent/cite.py +0 -0
  139. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/agent/co_scientist.py +0 -0
  140. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/agent/epistemic.py +0 -0
  141. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/agent/guardrails.py +0 -0
  142. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/agent/mcp_server.py +0 -0
  143. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/agent/orchestrator.py +0 -0
  144. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/agent/orchestrator_live.py +0 -0
  145. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/agent/pen_agent.py +0 -0
  146. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/agent/scope.py +0 -0
  147. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/agent/tools.py +0 -0
  148. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/api/__init__.py +0 -0
  149. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/api/manifest.py +0 -0
  150. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/atlas/__init__.py +0 -0
  151. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/atlas/build_wtkb.py +0 -0
  152. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/atlas/crosslink.py +0 -0
  153. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/atlas/expand.py +0 -0
  154. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/atlas/guide_design.py +0 -0
  155. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/atlas/schema.py +0 -0
  156. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/atlas/scorecard.py +0 -0
  157. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/atlas/universe.py +0 -0
  158. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/atlas/variant_propose.py +0 -0
  159. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/atlas/writer_efficiency.py +0 -0
  160. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/atlas/writer_predict.py +0 -0
  161. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/atlas/writer_recommend.py +0 -0
  162. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/atlas/writer_verify.py +0 -0
  163. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/bridge/__init__.py +0 -0
  164. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/bridge/activity.py +0 -0
  165. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/bridge/cli.py +0 -0
  166. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/bridge/fold_qc.py +0 -0
  167. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/bridge/guide_qc.py +0 -0
  168. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/bridge/ingest.py +0 -0
  169. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/bridge/offtarget.py +0 -0
  170. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/bridge/offtarget_energetics.py +0 -0
  171. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/bridge/ortholog_screen.py +0 -0
  172. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/bridge/pipeline.py +0 -0
  173. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/build/__init__.py +0 -0
  174. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/build/ingest.py +0 -0
  175. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/build/protocol.py +0 -0
  176. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/build/simlab.py +0 -0
  177. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/cli.py +0 -0
  178. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/data/__init__.py +0 -0
  179. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/data/encode.py +0 -0
  180. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/data/genome.py +0 -0
  181. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/data/ingest_chromatin.py +0 -0
  182. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/data/ingest_integration.py +0 -0
  183. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/data/ingest_safety_annot.py +0 -0
  184. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/data/ingest_trip.py +0 -0
  185. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/design/__init__.py +0 -0
  186. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/design/generate.py +0 -0
  187. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/design/pareto.py +0 -0
  188. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/design/space.py +0 -0
  189. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/design/writer_variants.py +0 -0
  190. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/env/__init__.py +0 -0
  191. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/env/genome_writing_env.py +0 -0
  192. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/env/policies.py +0 -0
  193. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/graph/__init__.py +0 -0
  194. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/graph/build.py +0 -0
  195. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/graph/cell_types.py +0 -0
  196. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/graph/ingest.py +0 -0
  197. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/graph/query.py +0 -0
  198. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/graph/schema.py +0 -0
  199. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/loop/__init__.py +0 -0
  200. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/loop/continual.py +0 -0
  201. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/loop/cycle.py +0 -0
  202. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/loop/drift.py +0 -0
  203. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/mech/__init__.py +0 -0
  204. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/mech/classify_atlas.py +0 -0
  205. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/mech/whitelist.py +0 -0
  206. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/monitor/__init__.py +0 -0
  207. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/monitor/europepmc.py +0 -0
  208. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/monitor/run.py +0 -0
  209. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/monitor/triage.py +0 -0
  210. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/oracles/__init__.py +0 -0
  211. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/oracles/cache.py +0 -0
  212. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/oracles/energetics.py +0 -0
  213. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/oracles/genome.py +0 -0
  214. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/oracles/protein_design.py +0 -0
  215. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/oracles/rna.py +0 -0
  216. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/oracles/schema.py +0 -0
  217. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/oracles/status.py +0 -0
  218. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/oracles/structure.py +0 -0
  219. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/oracles/vcell.py +0 -0
  220. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/__init__.py +0 -0
  221. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/antipeg_oracle.py +0 -0
  222. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/capsid_epitope_oracle.py +0 -0
  223. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/cargo.py +0 -0
  224. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/cargo_polish.py +0 -0
  225. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/delivery.py +0 -0
  226. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/delivery_constraints.py +0 -0
  227. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/delivery_immunology.py +0 -0
  228. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/delivery_vehicles.py +0 -0
  229. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/genotoxicity_oracle.py +0 -0
  230. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/innate_sensing.py +0 -0
  231. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/multiplex.py +0 -0
  232. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/optimize.py +0 -0
  233. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/pipeline.py +0 -0
  234. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/report.py +0 -0
  235. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/router.py +0 -0
  236. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/seroprevalence_oracle.py +0 -0
  237. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/planner/target_site.py +0 -0
  238. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/rag/__init__.py +0 -0
  239. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/rag/index.py +0 -0
  240. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/rag/llm.py +0 -0
  241. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/rag/qa.py +0 -0
  242. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/rules/__init__.py +0 -0
  243. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/rules/evaluators.py +0 -0
  244. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/rules/loader.py +0 -0
  245. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/rules/schema.py +0 -0
  246. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/rules/solver.py +0 -0
  247. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/safety/__init__.py +0 -0
  248. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/safety/audit.py +0 -0
  249. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/safety/gate.py +0 -0
  250. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/safety/policy.py +0 -0
  251. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/safety/redteam.py +0 -0
  252. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/safety/registry.py +0 -0
  253. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/safety/screen.py +0 -0
  254. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/score/__init__.py +0 -0
  255. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/score/recalibrate.py +0 -0
  256. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/score/therapeutic.py +0 -0
  257. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/server/__init__.py +0 -0
  258. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/server/api.py +0 -0
  259. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/twin/__init__.py +0 -0
  260. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/twin/calibrate.py +0 -0
  261. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/twin/data/__init__.py +0 -0
  262. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/twin/data/position_effect.py +0 -0
  263. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/twin/mechanistic.py +0 -0
  264. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/twin/outcome.py +0 -0
  265. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/twin/position_effect.py +0 -0
  266. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/ui/__init__.py +0 -0
  267. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/ui/app.py +0 -0
  268. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/__init__.py +0 -0
  269. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/adapt_demo.py +0 -0
  270. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/agent_eval.py +0 -0
  271. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/bench_adversarial_tasks.py +0 -0
  272. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/bench_coscientist_tasks.py +0 -0
  273. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/bench_graph_tasks.py +0 -0
  274. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/bench_rule_tasks.py +0 -0
  275. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/bench_trust_tasks.py +0 -0
  276. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/bench_writetype_tasks.py +0 -0
  277. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/blind_gsh_discovery.py +0 -0
  278. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/cargo_directionality.py +0 -0
  279. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/closed_loop.py +0 -0
  280. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/durability_baselines.py +0 -0
  281. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/experiment_design.py +0 -0
  282. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/expr_controls.py +0 -0
  283. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/forward_hypotheses.py +0 -0
  284. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/generative_design.py +0 -0
  285. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/guide_qc_demo.py +0 -0
  286. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/heldout_celltype_expr.py +0 -0
  287. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/intent_specification.py +0 -0
  288. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/known_biology_expr.py +0 -0
  289. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/offtarget_energetics_eval.py +0 -0
  290. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/out_of_scope_refusal.py +0 -0
  291. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/outcome_calibration.py +0 -0
  292. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/outcome_prediction.py +0 -0
  293. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/paper3_benchmark.py +0 -0
  294. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/paper4_real_validation.py +0 -0
  295. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/paper4_validation.py +0 -0
  296. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/protocol_safety.py +0 -0
  297. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/safety_screening.py +0 -0
  298. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/selective_prediction.py +0 -0
  299. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/seq_vs_measured.py +0 -0
  300. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/target_site_controls.py +0 -0
  301. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/uncertainty_eval.py +0 -0
  302. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/ungrounded_baseline.py +0 -0
  303. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/within_locus_ranking.py +0 -0
  304. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/validate/writer_recovery.py +0 -0
  305. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/verify/__init__.py +0 -0
  306. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/verify/schema.py +0 -0
  307. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/verify/service.py +0 -0
  308. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/web/__init__.py +0 -0
  309. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/web/guide.py +0 -0
  310. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/web/llm.py +0 -0
  311. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/web/router.py +0 -0
  312. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/web/server.py +0 -0
  313. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/web/tools.py +0 -0
  314. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/wgenome/__init__.py +0 -0
  315. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/wgenome/chromatin_seq.py +0 -0
  316. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/wgenome/durability.py +0 -0
  317. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/wgenome/export_tracks.py +0 -0
  318. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/wgenome/features.py +0 -0
  319. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/wgenome/gsh_baseline.py +0 -0
  320. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/wgenome/mesh_features.py +0 -0
  321. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/wgenome/ood.py +0 -0
  322. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/wgenome/providers.py +0 -0
  323. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/wgenome/safety.py +0 -0
  324. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/wgenome/structure3d.py +0 -0
  325. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/wgenome/uncertainty.py +0 -0
  326. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack/wgenome/writability.py +0 -0
  327. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack.egg-info/dependency_links.txt +0 -0
  328. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack.egg-info/entry_points.txt +0 -0
  329. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack.egg-info/requires.txt +0 -0
  330. {pen_stack-6.8.0 → pen_stack-6.9.0}/pen_stack.egg-info/top_level.txt +0 -0
  331. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_phase0.json +0 -0
  332. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_phase1_5.json +0 -0
  333. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_phase2.json +0 -0
  334. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_phase3.json +0 -0
  335. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_a.json +0 -0
  336. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_acq.json +0 -0
  337. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_aldesign.json +0 -0
  338. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_alvalidate.json +0 -0
  339. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_atlas.json +0 -0
  340. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_b.json +0 -0
  341. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_ba.json +0 -0
  342. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_ba_v33.json +0 -0
  343. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_ba_v45.json +0 -0
  344. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_bench.json +0 -0
  345. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_c.json +0 -0
  346. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_cal.json +0 -0
  347. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_calib.json +0 -0
  348. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_challenge.json +0 -0
  349. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_chat.json +0 -0
  350. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_cite.json +0 -0
  351. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_continual.json +0 -0
  352. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_cosci2.json +0 -0
  353. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_crit.json +0 -0
  354. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_ct.json +0 -0
  355. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_d.json +0 -0
  356. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_drift.json +0 -0
  357. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_e.json +0 -0
  358. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_env.json +0 -0
  359. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_ep.json +0 -0
  360. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_epitope.json +0 -0
  361. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_expr2.json +0 -0
  362. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_f.json +0 -0
  363. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_frontend.json +0 -0
  364. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_g.json +0 -0
  365. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_gen.json +0 -0
  366. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_genotox.json +0 -0
  367. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_graph.json +0 -0
  368. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_h.json +0 -0
  369. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_hybrid.json +0 -0
  370. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_immune.json +0 -0
  371. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_ingest.json +0 -0
  372. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_innate.json +0 -0
  373. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_loop.json +0 -0
  374. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_manifest.json +0 -0
  375. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_mc.json +0 -0
  376. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_mcp.json +0 -0
  377. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_mech.json +0 -0
  378. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_mon.json +0 -0
  379. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_o.json +0 -0
  380. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_openapi.json +0 -0
  381. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_orch.json +0 -0
  382. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_outcome.json +0 -0
  383. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_pareto.json +0 -0
  384. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_peg.json +0 -0
  385. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_plan.json +0 -0
  386. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_policy.json +0 -0
  387. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_profile.json +0 -0
  388. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_proto.json +0 -0
  389. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_r.json +0 -0
  390. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_redteam.json +0 -0
  391. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_route.json +0 -0
  392. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_screen.json +0 -0
  393. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_seroprev.json +0 -0
  394. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_simlab.json +0 -0
  395. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_twincal.json +0 -0
  396. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_uq.json +0 -0
  397. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_v.json +0 -0
  398. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_vcell.json +0 -0
  399. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_writer.json +0 -0
  400. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/SHA256_LOCK_ws_wv.json +0 -0
  401. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/paper1.yaml +0 -0
  402. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/paper2.yaml +0 -0
  403. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/paper3.yaml +0 -0
  404. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/paper4.yaml +0 -0
  405. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/phase0.yaml +0 -0
  406. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_a.yaml +0 -0
  407. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_acq.yaml +0 -0
  408. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_aldesign.yaml +0 -0
  409. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_alvalidate.yaml +0 -0
  410. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_atlas.yaml +0 -0
  411. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_b.yaml +0 -0
  412. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_ba.yaml +0 -0
  413. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_ba_v33.yaml +0 -0
  414. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_ba_v45.yaml +0 -0
  415. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_bench.yaml +0 -0
  416. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_c.yaml +0 -0
  417. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_cal.yaml +0 -0
  418. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_calib.yaml +0 -0
  419. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_challenge.yaml +0 -0
  420. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_chat.yaml +0 -0
  421. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_cite.yaml +0 -0
  422. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_continual.yaml +0 -0
  423. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_cosci2.yaml +0 -0
  424. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_crit.yaml +0 -0
  425. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_ct.yaml +0 -0
  426. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_d.yaml +0 -0
  427. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_drift.yaml +0 -0
  428. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_e.yaml +0 -0
  429. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_env.yaml +0 -0
  430. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_ep.yaml +0 -0
  431. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_epitope.yaml +0 -0
  432. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_expr2.yaml +0 -0
  433. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_f.yaml +0 -0
  434. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_frontend.yaml +0 -0
  435. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_g.yaml +0 -0
  436. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_gen.yaml +0 -0
  437. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_genotox.yaml +0 -0
  438. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_graph.yaml +0 -0
  439. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_h.yaml +0 -0
  440. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_hybrid.yaml +0 -0
  441. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_immune.yaml +0 -0
  442. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_ingest.yaml +0 -0
  443. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_innate.yaml +0 -0
  444. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_loop.yaml +0 -0
  445. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_manifest.yaml +0 -0
  446. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_mc.yaml +0 -0
  447. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_mcp.yaml +0 -0
  448. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_mech.yaml +0 -0
  449. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_mon.yaml +0 -0
  450. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_o.yaml +0 -0
  451. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_openapi.yaml +0 -0
  452. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_orch.yaml +0 -0
  453. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_outcome.yaml +0 -0
  454. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_pareto.yaml +0 -0
  455. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_peg.yaml +0 -0
  456. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_plan.yaml +0 -0
  457. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_policy.yaml +0 -0
  458. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_profile.yaml +0 -0
  459. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_proto.yaml +0 -0
  460. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_r.yaml +0 -0
  461. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_redteam.yaml +0 -0
  462. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_route.yaml +0 -0
  463. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_screen.yaml +0 -0
  464. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_seroprev.yaml +0 -0
  465. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_simlab.yaml +0 -0
  466. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_twincal.yaml +0 -0
  467. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_uq.yaml +0 -0
  468. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_v.yaml +0 -0
  469. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_vcell.yaml +0 -0
  470. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_writer.yaml +0 -0
  471. {pen_stack-6.8.0 → pen_stack-6.9.0}/prereg/ws_wv.yaml +0 -0
  472. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/calibrate_immune_axes.py +0 -0
  473. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/fetch_licensed_sources.py +0 -0
  474. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/p1_build_atlas.py +0 -0
  475. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/p1_build_durability.py +0 -0
  476. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/p1_build_position_effect.py +0 -0
  477. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/p1_build_writer_eff.py +0 -0
  478. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/p1_export_tracks.py +0 -0
  479. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/p1_safety_concordance.py +0 -0
  480. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/p1_train_safety.py +0 -0
  481. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/p1_validation_report.py +0 -0
  482. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/p2_build_atlas.py +0 -0
  483. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/p3_benchmark_report.py +0 -0
  484. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/p4_genome_scan.py +0 -0
  485. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/p52_build_genotox_oracle.py +0 -0
  486. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/p53_build_epitope_oracle.py +0 -0
  487. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/ws_b_report.py +0 -0
  488. {pen_stack-6.8.0 → pen_stack-6.9.0}/scripts/ws_c_report.py +0 -0
  489. {pen_stack-6.8.0 → pen_stack-6.9.0}/setup.cfg +0 -0
@@ -3,6 +3,39 @@
3
3
  All notable changes to PEN-STACK are documented here. This file follows
4
4
  [Keep a Changelog](https://keepachangelog.com/) and the program's phase structure.
5
5
 
6
+ ## [6.9.0] - 2026-06-20 - PEN-IMMUNE: MHC-II/CD4 + ADA + writer-as-antigen
7
+
8
+ **MINOR feature release.** Extends the immune profile from CD8/MHC-I-only to a full T-cell profile — MHC-I +
9
+ **MHC-II/CD4 + ADA risk with self-tolerance filtering** — scored over the **writer enzyme as a distinct antigen**,
10
+ still population-level, OOD-gated, and **never collapsed**. Wraps the v5.6 unified profile. No fabrication: real
11
+ UniProt sequences, grounded documented method, honest 🟡 labels.
12
+
13
+ ### Added — the MHC-II + ADA axes (WS-IMMUNE2: G-WS1, G-WS2)
14
+ - `pen_stack/planner/immune_mhc2.py` — grounded, dependency-free **promiscuous MHC-II binder density** (documented
15
+ P1 hydrophobic anchor, Stern & Wiley 1994; secondary pockets, Southwood 1998) over capsid AND writer sequences +
16
+ the bundled real writer/control FASTA. `configs/writer_sequences.fasta` — real UniProt: SpCas9 (Q99ZW2), ISCro4
17
+ bridge recombinase (D2TGM5), Bxb1 integrase (Q9B086), human albumin self control (P02768).
18
+ - `pen_stack/planner/ada_risk.py` — **ADA-risk = MHC-II epitope density × foreignness** with a JanusMatrix-style
19
+ **self-tolerance filter** (origin authoritative; human-proteome k-mer filter otherwise). Recovers
20
+ immunogenic-vs-tolerated: foreign writers score above the human self control (clean separation).
21
+
22
+ ### Changed — the unified profile (G-WS3)
23
+ - `pen_stack/planner/immune_profile.py` — adds `mhc2_writer` + `ada_writer` axes and a `writer_as_antigen` card
24
+ with `dominant_antigen` + `writer_dominant_risk` (fires for a foreign writer, especially non-viral delivery
25
+ where there is no capsid antigen). `collapsed_score` stays `None` (asserted). `immune_calibration.AXIS_STATUS`
26
+ registers the two new axes as mechanistic/population proxies.
27
+
28
+ ### Added — Immuno-Bench + honest calibration (G-WS4)
29
+ - `benchmarks/immuno/harness.py` — the immunogenic-vs-tolerated recovery track (non-circular: label = protein
30
+ origin) + an honest `calibrate_axis` ADA pass that **stays 🟡** at public-data power (no manufactured ✅).
31
+ - `tests/unit/test_ws_immune2.py` (CI-safe; pure-Python method + committed sequences). `prereg/ws_immune2.yaml`.
32
+
33
+ ### Honesty
34
+ - Every axis is a population-level proxy, never a patient-specific ADA titer / realized CD4 magnitude (known-
35
+ unknowns). The MHC-II method is sequence-intrinsic presentation potential, not a trained allele-specific predictor.
36
+ The self-tolerance k-mer filter is seeded by the bundled human reference (full human proteome substitutable on the
37
+ VM); the authoritative foreignness signal is the protein origin. Axes are a vector, never fused.
38
+
6
39
  ## [6.8.0] - 2026-06-20 - PEN-WRITER: cross-family writer-efficiency engine + Writer-Efficiency Bench
7
40
 
8
41
  **MINOR feature release.** Upgrades Stage C (pick the writer) from a curated-KB **ranking** to a prediction +
@@ -1,7 +1,7 @@
1
1
  cff-version: 1.2.0
2
2
  message: "If you use PEN-STACK, please cite it as below."
3
3
  title: "PEN-STACK: open infrastructure for genome writing"
4
- version: 6.8.0
4
+ version: 6.9.0
5
5
  date-released: 2026-06-20
6
6
  authors:
7
7
  - family-names: "Mahaboob Ali"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pen-stack
3
- Version: 6.8.0
3
+ Version: 6.9.0
4
4
  Summary: Open infrastructure for genome writing: the Writable Genome atlas, the Writer Atlas, and the Write Planner.
5
5
  Author-email: Anees Ahmed Mahaboob Ali <ahmedaneesm@gmail.com>
6
6
  License: MIT
@@ -90,7 +90,7 @@ every design against rule-grounded mechanism, reports calibrated confidence, cit
90
90
  [![codecov](https://codecov.io/gh/ahmedanees-m/pen-stack/branch/main/graph/badge.svg)](https://codecov.io/gh/ahmedanees-m/pen-stack)
91
91
  [![License: MIT](https://img.shields.io/badge/License-MIT-informational.svg)](LICENSE)
92
92
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
93
- [![Version](https://img.shields.io/badge/version-6.8.0-blue.svg)](CHANGELOG.md)
93
+ [![Version](https://img.shields.io/badge/version-6.9.0-blue.svg)](CHANGELOG.md)
94
94
  [![Status](https://img.shields.io/badge/status-1.0%20First%20Stable-success.svg)](docs/STABILITY.md)
95
95
  [![Tests](https://img.shields.io/badge/tests-378%20passing-success.svg)](tests/)
96
96
  [![Lint: ruff](https://img.shields.io/badge/lint-ruff-purple.svg)](https://github.com/astral-sh/ruff)
@@ -148,6 +148,29 @@ demonstrated (v5.12) and the benchmark went public (v5.13).
148
148
  > unknown funnel remains — made legible (scope flags, known-unknowns, honest baselines, no fabrication), not
149
149
  > hidden.
150
150
 
151
+ ## What is new in v6.9 — PEN-IMMUNE (MHC-II/CD4 + ADA + the writer enzyme as a distinct antigen)
152
+
153
+ The immune profile did **CD8/MHC-I only** (capsid epitope load via MHCflurry) — but the **dominant** immunogenicity
154
+ driver is **MHC-II / CD4 help → anti-drug antibodies (ADA)**, and the **writer enzyme itself is immunogenic**
155
+ (Cas9 elicits MHC-II-presented CD4 responses, Simhadri *Nat Commun* 2021; bridge recombinases / serine integrases
156
+ are bacterial/phage) — yet Stage G scored only the capsid. v6.9 closes that gap, **never collapsing** the axes:
157
+
158
+ - **A CD4/MHC-II epitope-load axis** (`planner/immune_mhc2.py`) — a grounded, dependency-free **promiscuous MHC-II
159
+ binder density** over the documented P1 hydrophobic anchor (Stern & Wiley 1994) + secondary pockets, scored over
160
+ **capsid AND writer** sequences. Population-level proxy (🟡), never a patient-HLA magnitude.
161
+ - **An ADA-risk axis** (`planner/ada_risk.py`) — **ADA-risk = MHC-II epitope density × foreignness**, with a
162
+ **self-tolerance filter** (JanusMatrix-style: self epitopes are tolerated; foreign drive ADA). It **recovers
163
+ immunogenic-vs-tolerated**: the foreign writers (real UniProt SpCas9 / ISCro4 / Bxb1) score **above** the human
164
+ self control (albumin), even without the origin label (the k-mer self-match tolerates the human protein).
165
+ - **The writer as a distinct antigen** — the profile now carries a `writer_as_antigen` card and a
166
+ `writer_dominant_risk` flag: for **non-viral delivery of a bacterial writer there is no capsid antigen, so the
167
+ WRITER is the dominant immunogen** — the insight the capsid-only profile missed.
168
+ - **Immuno-Bench** (`benchmarks/immuno/`) — the immunogenic-vs-tolerated recovery track + an honest `calibrate_axis`
169
+ ADA pass (it stays 🟡 at public-data power — no manufactured ✅, the standing wet-lab bottleneck).
170
+
171
+ Real UniProt sequences only (no fabricated sequence); the axes are reported as a vector with `collapsed_score: None`;
172
+ the realized CD4 response / ADA titer stay known-unknowns. See [docs/immune_profiler.md](docs/immune_profiler.md).
173
+
151
174
  ## What is new in v6.8 — PEN-WRITER (a cross-family writer-efficiency engine + the first writer-efficiency benchmark)
152
175
 
153
176
  Stage C (pick the writer) was **retrieval** — the curated Writer Atlas ranks 8 families but predicts no
@@ -15,7 +15,7 @@ every design against rule-grounded mechanism, reports calibrated confidence, cit
15
15
  [![codecov](https://codecov.io/gh/ahmedanees-m/pen-stack/branch/main/graph/badge.svg)](https://codecov.io/gh/ahmedanees-m/pen-stack)
16
16
  [![License: MIT](https://img.shields.io/badge/License-MIT-informational.svg)](LICENSE)
17
17
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
18
- [![Version](https://img.shields.io/badge/version-6.8.0-blue.svg)](CHANGELOG.md)
18
+ [![Version](https://img.shields.io/badge/version-6.9.0-blue.svg)](CHANGELOG.md)
19
19
  [![Status](https://img.shields.io/badge/status-1.0%20First%20Stable-success.svg)](docs/STABILITY.md)
20
20
  [![Tests](https://img.shields.io/badge/tests-378%20passing-success.svg)](tests/)
21
21
  [![Lint: ruff](https://img.shields.io/badge/lint-ruff-purple.svg)](https://github.com/astral-sh/ruff)
@@ -73,6 +73,29 @@ demonstrated (v5.12) and the benchmark went public (v5.13).
73
73
  > unknown funnel remains — made legible (scope flags, known-unknowns, honest baselines, no fabrication), not
74
74
  > hidden.
75
75
 
76
+ ## What is new in v6.9 — PEN-IMMUNE (MHC-II/CD4 + ADA + the writer enzyme as a distinct antigen)
77
+
78
+ The immune profile did **CD8/MHC-I only** (capsid epitope load via MHCflurry) — but the **dominant** immunogenicity
79
+ driver is **MHC-II / CD4 help → anti-drug antibodies (ADA)**, and the **writer enzyme itself is immunogenic**
80
+ (Cas9 elicits MHC-II-presented CD4 responses, Simhadri *Nat Commun* 2021; bridge recombinases / serine integrases
81
+ are bacterial/phage) — yet Stage G scored only the capsid. v6.9 closes that gap, **never collapsing** the axes:
82
+
83
+ - **A CD4/MHC-II epitope-load axis** (`planner/immune_mhc2.py`) — a grounded, dependency-free **promiscuous MHC-II
84
+ binder density** over the documented P1 hydrophobic anchor (Stern & Wiley 1994) + secondary pockets, scored over
85
+ **capsid AND writer** sequences. Population-level proxy (🟡), never a patient-HLA magnitude.
86
+ - **An ADA-risk axis** (`planner/ada_risk.py`) — **ADA-risk = MHC-II epitope density × foreignness**, with a
87
+ **self-tolerance filter** (JanusMatrix-style: self epitopes are tolerated; foreign drive ADA). It **recovers
88
+ immunogenic-vs-tolerated**: the foreign writers (real UniProt SpCas9 / ISCro4 / Bxb1) score **above** the human
89
+ self control (albumin), even without the origin label (the k-mer self-match tolerates the human protein).
90
+ - **The writer as a distinct antigen** — the profile now carries a `writer_as_antigen` card and a
91
+ `writer_dominant_risk` flag: for **non-viral delivery of a bacterial writer there is no capsid antigen, so the
92
+ WRITER is the dominant immunogen** — the insight the capsid-only profile missed.
93
+ - **Immuno-Bench** (`benchmarks/immuno/`) — the immunogenic-vs-tolerated recovery track + an honest `calibrate_axis`
94
+ ADA pass (it stays 🟡 at public-data power — no manufactured ✅, the standing wet-lab bottleneck).
95
+
96
+ Real UniProt sequences only (no fabricated sequence); the axes are reported as a vector with `collapsed_score: None`;
97
+ the realized CD4 response / ADA titer stay known-unknowns. See [docs/immune_profiler.md](docs/immune_profiler.md).
98
+
76
99
  ## What is new in v6.8 — PEN-WRITER (a cross-family writer-efficiency engine + the first writer-efficiency benchmark)
77
100
 
78
101
  Stage C (pick the writer) was **retrieval** — the curated Writer Atlas ranks 8 families but predicts no
@@ -0,0 +1,12 @@
1
+ # Writer-enzyme + control protein sequences for the v6.9 writer-as-antigen immunogenicity profiler (Stage G).
2
+ # Real UniProt sequences, verbatim, each with its accession + ORIGIN (foreign | self). The writer enzymes are
3
+ # bacterial/phage proteins (FOREIGN -> non-self -> ADA-driving); human albumin is the SELF/tolerated control.
4
+ # Header convention: >NAME|ACCESSION origin=foreign|self family=... (DOIs/provenance in configs/immune_sequences.yaml)
5
+ >SpCas9|Q99ZW2 origin=foreign family=Cas9 organism=S.pyogenes
6
+ MDKKYSIGLDIGTNSVGWAVITDEYKVPSKKFKVLGNTDRHSIKKNLIGALLFDSGETAEATRLKRTARRRYTRRKNRICYLQEIFSNEMAKVDDSFFHRLEESFLVEEDKKHERHPIFGNIVDEVAYHEKYPTIYHLRKKLVDSTDKADLRLIYLALAHMIKFRGHFLIEGDLNPDNSDVDKLFIQLVQTYNQLFEENPINASGVDAKAILSARLSKSRRLENLIAQLPGEKKNGLFGNLIALSLGLTPNFKSNFDLAEDAKLQLSKDTYDDDLDNLLAQIGDQYADLFLAAKNLSDAILLSDILRVNTEITKAPLSASMIKRYDEHHQDLTLLKALVRQQLPEKYKEIFFDQSKNGYAGYIDGGASQEEFYKFIKPILEKMDGTEELLVKLNREDLLRKQRTFDNGSIPHQIHLGELHAILRRQEDFYPFLKDNREKIEKILTFRIPYYVGPLARGNSRFAWMTRKSEETITPWNFEEVVDKGASAQSFIERMTNFDKNLPNEKVLPKHSLLYEYFTVYNELTKVKYVTEGMRKPAFLSGEQKKAIVDLLFKTNRKVTVKQLKEDYFKKIECFDSVEISGVEDRFNASLGTYHDLLKIIKDKDFLDNEENEDILEDIVLTLTLFEDREMIEERLKTYAHLFDDKVMKQLKRRRYTGWGRLSRKLINGIRDKQSGKTILDFLKSDGFANRNFMQLIHDDSLTFKEDIQKAQVSGQGDSLHEHIANLAGSPAIKKGILQTVKVVDELVKVMGRHKPENIVIEMARENQTTQKGQKNSRERMKRIEEGIKELGSQILKEHPVENTQLQNEKLYLYYLQNGRDMYVDQELDINRLSDYDVDHIVPQSFLKDDSIDNKVLTRSDKNRGKSDNVPSEEVVKKMKNYWRQLLNAKLITQRKFDNLTKAERGGLSELDKAGFIKRQLVETRQITKHVAQILDSRMNTKYDENDKLIREVKVITLKSKLVSDFRKDFQFYKVREINNYHHAHDAYLNAVVGTALIKKYPKLESEFVYGDYKVYDVRKMIAKSEQEIGKATAKYFFYSNIMNFFKTEITLANGEIRKRPLIETNGETGEIVWDKGRDFATVRKVLSMPQVNIVKKTEVQTGGFSKESILPKRNSDKLIARKKDWDPKKYGGFDSPTVAYSVLVVAKVEKGKSKKLKSVKELLGITIMERSSFEKNPIDFLEAKGYKEVKKDLIIKLPKYSLFELENGRKRMLASAGELQKGNELALPSKYVNFLYLASHYEKLKGSPEDNEQKQLFVEQHKHYLDEIIEQISEFSKRVILADANLDKVLSAYNKHRDKPIREQAENIIHLFTLTNLGAPAAFKYFDTTIDRKRYTSTKEVLDATLIHQSITGLYETRIDLSQLGGD
7
+ >ISCro4|D2TGM5 origin=foreign family=bridge_IS110 organism=C.rodentium
8
+ MEQELHFIGIDVSKAKLDVDVLRPDGRHRSKKFANTPKGHDELLRWLSGHRVAPAHICMEATSTYMEDVAAHLSDAGYTVSVINPALGKAFAQSEGLRSKTDAVDARMLAEFCRQKRPPAWEAPHPVERALRALVLRHQSLTDMHTQELNRLETAREVQRPSIDAHLLWLHAELKRIEKQIKDLTDDDPDMKHRRKLLESIPGIGEKTSAVLLAYTGLKERFTHARQFAAFAGLTPRRYESGSSVNRASRMSKAGHASLRRALYMPAMVAVSKTEWGRAFRDRLAGNGKKGKVIIGAMMRKLAQVAYGVLKSGVPFDASRHNPVAA
9
+ >Bxb1|Q9B086 origin=foreign family=serine_integrase organism=phage_Bxb1
10
+ MRALVVIRLSRVTDATTSPERQLESCQQLCAQRGWDVVGVAEDLDVSGAVDPFDRKRRPNLARWLAFEEQPFDVIVAYRVDRLTRSIRHLQQLVHWAEDHKKLVVSATEAHFDTTTPFAAVVIALMGTVAQMELEAIKERNRSAAHFNIRAGKYRGSLPPWGYLPTRVDGEWRLVPDPVQRERILEVYHRVVDNHEPLHLVAHDLNRRGVLSPKDYFAQLQGREPQGREWSATALKRSMISEAMLGYATLNGKTVRDDDGAPLVRAEPILTREQLEALRAELVKTSRAKPAVSTPSLLLRVLFCAVCGEPAYKFAGGGRKHPRYRCRSMGFPKHCGNGTVAMAEWDAFCEEQVLDLLGDAAERLEKVWVAGSDSAVELAEVNAELVDLTSLIGSPAYRAGSPQREALDARIAALAARQEELEGLEARPSGWEWRETGQRFGDWWREQDTAAKNTWLRSMNVRLTFDVRGGLTRTIDFGDLQEYEQHLRLGSVVERLHTGMS
11
+ >HumanAlbumin|P02768 origin=self family=human_control organism=H.sapiens
12
+ MKWVTFISLLFLFSSAYSRGVFRRDAHKSEVAHRFKDLGEENFKALVLIAFAQYLQQCPFEDHVKLVNEVTEFAKTCVADESAENCDKSLHTLFGDKLCTVATLRETYGEMADCCAKQEPERNECFLQHKDDNPNLPRLVRPEVDVMCTAFHDNEETFLKKYLYEIARRHPYFYAPELLFFAKRYKAAFTECCQAADKAACLLPKLDELRDEGKASSAKQRLKCASLQKFGERAFKAWAVARLSQRFPKAEFAEVSKLVTDLTKVHTECCHGDLLECADDRADLAKYICENQDSISSKLKECCEKPLLEKSHCIAEVENDEMPADLPSLAADFVESKDVCKNYAEAKDVFLGMFLYEYARRHPDYSVVLLLRLAKTYETTLEKCCAAADPHECYAKVFDEFKPLVEEPQNLIKQNCELFEQLGEYKFQNALLVRYTKKVPQVSTPTLVEVSRNLGKVGSKCCKHPEAKRMPCAEDYLSVVLNQLCVLHEKTPVSDRVTKCCTESLVNRRPCFSALEVDETYVPKEFNAETFTFHADICTLSEKERQIKKQTALVELVKHKPKATKEQLKAVMDDFAAFVEKCCKADDKETCFAEEGKKLVAASQAALGL
@@ -0,0 +1,53 @@
1
+ # Stage G — the immune profiler (v6.9 PEN-IMMUNE)
2
+
3
+ Stage G profiles a design's immunogenicity/toxicity across **separate, never-collapsed axes**. Through v6.8 the
4
+ adaptive axis was **CD8/MHC-I only** (capsid epitope load via MHCflurry). v6.9 adds the **dominant** driver —
5
+ **MHC-II/CD4 → ADA** — and scores the **writer enzyme as a distinct antigen**.
6
+
7
+ ## The MHC-II/CD4 axis (`planner/immune_mhc2.py`)
8
+
9
+ A grounded, dependency-free **promiscuous MHC-II binder density**: MHC-II presents a 9-mer core in an open groove
10
+ whose **P1 pocket is deep and hydrophobic** — the single dominant anchor (M/F/Y/W/L/I/V; Stern & Wiley, *Nature*
11
+ 1994), with secondary pockets at P4/P6/P9. A *promiscuous* epitope (binds many HLA-DR) has a strong P1 anchor +
12
+ favorable secondaries (Southwood 1998). We count promiscuous-binder cores → an epitope-density proxy, computed over
13
+ **capsid AND writer** sequences. It is a **population-level, sequence-intrinsic proxy (🟡)** — not a trained
14
+ allele-specific predictor, not a patient-HLA magnitude (a known-unknown).
15
+
16
+ ## The ADA-risk axis + self-tolerance (`planner/ada_risk.py`)
17
+
18
+ Epitope load is necessary but not sufficient — **self** proteins carry MHC-II epitopes yet are tolerated. So:
19
+
20
+ ```
21
+ ADA-risk = MHC-II epitope density × foreignness
22
+ ```
23
+
24
+ with a **self-tolerance filter** (JanusMatrix-style: an epitope whose core matches the human proteome is
25
+ tolerated). `foreignness` uses the **authoritative protein origin** (self vs bacterial/viral/phage) when known,
26
+ else `1 − self_match_fraction` from a human-proteome k-mer filter. This **recovers immunogenic-vs-tolerated**:
27
+
28
+ | Protein (real UniProt) | origin | ADA-risk |
29
+ |---|---|---|
30
+ | Bxb1 integrase (Q9B086) | foreign | **0.095** |
31
+ | SpCas9 (Q99ZW2) | foreign | **0.093** |
32
+ | ISCro4 bridge recombinase (D2TGM5) | foreign | **0.082** |
33
+ | Human albumin (P02768) | self | **0.0** (tolerated) |
34
+
35
+ The human self control scores 0 **even without the origin label** — the k-mer self-match tolerates it. The foreign
36
+ writers separate cleanly above it.
37
+
38
+ ## The writer as a distinct antigen
39
+
40
+ `immune_profile` now carries a `writer_as_antigen` card and a `writer_dominant_risk` flag. The insight the
41
+ capsid-only profile missed: **for non-viral delivery (LNP/mRNA, eVLP) of a bacterial writer there is no capsid
42
+ antigen — so the WRITER is the dominant immunogen.** The flag fires accordingly; the axes are reported as a vector
43
+ with `collapsed_score: None` (never fused).
44
+
45
+ ## Honest limits
46
+ - Population-level proxies (🟡), never a patient-specific ADA titer / realized CD4 magnitude (known-unknowns).
47
+ - The MHC-II method is presentation potential, not a trained allele-specific predictor.
48
+ - The self-tolerance k-mer filter is seeded by the bundled human reference; the **full human proteome** is
49
+ substitutable on the VM (the authoritative foreignness signal is the protein origin).
50
+ - The ADA axis's `calibrate_axis` pass **stays 🟡** — no public observed-incidence set at N≥6 power (the standing
51
+ wet-lab/clinical-data bottleneck), reported, never manufactured.
52
+
53
+ See `benchmarks/immuno/` (Immuno-Bench) and `prereg/ws_immune2.yaml`.
@@ -1,2 +1,2 @@
1
1
  """PEN-STACK v3.0 - open infrastructure for genome writing."""
2
- __version__ = "6.8.0"
2
+ __version__ = "6.9.0"
@@ -0,0 +1,84 @@
1
+ """ADA-risk + self-tolerance filter (v6.9 PEN-IMMUNE, G-WS2).
2
+
3
+ A protein's MHC-II epitope load (presentation potential) is necessary but not sufficient for anti-drug antibodies
4
+ (ADA): **self** proteins carry MHC-II epitopes too, yet are tolerated (central tolerance deletes self-reactive T
5
+ cells). What drives ADA is **non-self** (foreign) presentable epitopes. So:
6
+
7
+ ADA-risk = MHC-II epitope density x foreignness
8
+
9
+ with a **self-tolerance filter** (JanusMatrix-style: an epitope whose core matches the human proteome is
10
+ tolerated; EpiVax JanusMatrix, De Groot et al.). `foreignness` uses the AUTHORITATIVE protein origin (self vs
11
+ bacterial/viral/phage) when known; otherwise it is `1 - self_match_fraction` from a human-proteome k-mer filter
12
+ (seeded here by the bundled human self-reference; the FULL human proteome is substitutable on the VM via the build
13
+ script). This recovers immunogenic (Cas9, bridge recombinase, serine integrase — all foreign) above tolerated
14
+ (human self) — the immunogenic-vs-tolerated benchmark.
15
+
16
+ Honest: a **population-level proxy (🟡)**, never a patient-specific ADA titer (a known-unknown). The calibration
17
+ attempt against a public ADA set runs through the EXISTING `calibrate_axis` gate; it flips to ✅ only if the gate
18
+ passes (it does not, at the public-data power available — reported, not manufactured).
19
+ """
20
+ from __future__ import annotations
21
+
22
+ from functools import lru_cache
23
+
24
+ from pen_stack.planner.immune_mhc2 import _clean, mhc2_binder_cores, mhc2_epitope_load, writer_sequences
25
+
26
+ ADA_DOIS = ["10.1038/s41467-021-25414-9"] # Cas9 MHC-II CD4 immunogenicity (Simhadri 2021)
27
+
28
+
29
+ @lru_cache(maxsize=1)
30
+ def human_self_kmers(k: int = 9) -> frozenset:
31
+ """9-mer set of the bundled human SELF reference proteins (the self-tolerance reference). On the VM the full
32
+ human proteome is substitutable (scripts/p1_build_immuno.py --human-proteome); here the bundled human
33
+ control(s) seed it, so the AUTHORITATIVE foreignness signal is the protein `origin`."""
34
+ refs = [v["seq"] for v in writer_sequences().values() if v.get("origin") == "self"]
35
+ ks: set = set()
36
+ for s in refs:
37
+ s = _clean(s)
38
+ for i in range(len(s) - k + 1):
39
+ ks.add(s[i:i + k])
40
+ return frozenset(ks)
41
+
42
+
43
+ def self_tolerance(seq: str, human_kmers: frozenset | None = None) -> dict:
44
+ """Fraction of a protein's MHC-II binder cores that match the human self reference (tolerated)."""
45
+ human = human_kmers if human_kmers is not None else human_self_kmers()
46
+ cores = [c for _, c, _ in mhc2_binder_cores(seq)]
47
+ if not cores:
48
+ return {"self_match_fraction": None, "n_binder_cores": 0, "n_self_matched": 0}
49
+ matched = sum(1 for c in cores if c in human)
50
+ return {"self_match_fraction": round(matched / len(cores), 4), "n_binder_cores": len(cores),
51
+ "n_self_matched": matched,
52
+ "reference": "bundled human self proteins (full human proteome substitutable on VM)"}
53
+
54
+
55
+ def ada_risk(seq: str, origin: str | None = None, human_kmers: frozenset | None = None) -> dict:
56
+ """ADA-risk = MHC-II epitope density x foreignness, with the self-tolerance filter. Higher ada_risk_score =
57
+ MORE anti-drug-antibody risk; `ada_immune_score = 1 - ada_risk_score` (higher = safer) for profile parity."""
58
+ el = mhc2_epitope_load(seq)
59
+ st = self_tolerance(seq, human_kmers)
60
+ sm = st["self_match_fraction"] or 0.0
61
+ if origin == "self":
62
+ foreign = 0.0
63
+ else: # foreign or unknown -> use the self-match filter
64
+ foreign = round(1.0 - sm, 4)
65
+ risk = round(el["epitope_density"] * foreign, 4)
66
+ return {
67
+ "ada_risk_score": risk, "ada_immune_score": round(1.0 - risk, 4),
68
+ "epitope_density": el["epitope_density"], "foreignness": foreign, "origin": origin,
69
+ "self_tolerance": st,
70
+ "direction": "ada_risk_score: higher = MORE ADA risk; ada_immune_score: higher = safer",
71
+ "filter": "JanusMatrix-style self-tolerance: foreign non-self MHC-II epitopes drive ADA; self epitopes are "
72
+ "tolerated (central tolerance). Origin is authoritative when known; else the human-proteome "
73
+ "k-mer filter.",
74
+ "status": "population-level proxy (🟡); patient ADA titer / magnitude is a known-unknown",
75
+ "dois": ADA_DOIS,
76
+ }
77
+
78
+
79
+ def ada_risk_named(name: str) -> dict:
80
+ """ADA-risk for a bundled writer/control protein by name (uses its declared origin)."""
81
+ rec = writer_sequences().get(name)
82
+ if not rec:
83
+ return {"available": False, "note": f"no bundled sequence {name!r}"}
84
+ return {"available": True, "name": name, "family": rec.get("family"), **ada_risk(rec["seq"], rec.get("origin"))}
@@ -0,0 +1,114 @@
1
+ """CD4 / MHC-II epitope-load axis for the writer enzyme AND the capsid (v6.9 PEN-IMMUNE, G-WS1).
2
+
3
+ The dominant immunogenicity driver for a protein therapeutic is **MHC-II / CD4 help -> anti-drug antibodies
4
+ (ADA)** — exactly what the v5.x immune profile omitted (it did CD8/MHC-I via MHCflurry only). And the **editor
5
+ protein itself is immunogenic** (Cas9 elicits MHC-II-presented CD4 responses, Simhadri et al., Nat Commun 2021,
6
+ 10.1038/s41467-021-25414-9; bridge recombinases / serine integrases are bacterial/phage) — yet Stage G scored
7
+ only the capsid. v6.9 adds an MHC-II epitope-load axis over the **writer** as a distinct antigen.
8
+
9
+ Method (grounded, dependency-free, allele-agnostic PROMISCUOUS-binder density): MHC-II presents a 9-mer core in an
10
+ open groove; the **P1 pocket is deep and hydrophobic**, the single dominant anchor (M/F/Y/W/L/I/V) (Stern & Wiley,
11
+ Nature 1994; Jardetzky 1996), with secondary pockets at P4/P6/P9. A *promiscuous* epitope (binds many HLA-DR) is
12
+ exactly one with a strong P1 anchor + favorable secondaries (Southwood et al., J Immunol 1998). We count
13
+ promiscuous-binder cores -> an epitope-density proxy. This is a **population-level, sequence-intrinsic PROXY (🟡)**,
14
+ NOT a trained allele-specific predictor and NOT a patient-HLA-specific magnitude (a known-unknown). Whether those
15
+ epitopes drive ADA depends on self-tolerance (foreign vs self) — handled in `ada_risk`.
16
+ """
17
+ from __future__ import annotations
18
+
19
+ from functools import lru_cache
20
+
21
+ from pen_stack._resources import resource
22
+
23
+ _AA = set("ACDEFGHIKLMNPQRSTVWY")
24
+ P1_ANCHOR = set("MFYWLIV") # large hydrophobic — the dominant MHC-II P1 anchor (Stern & Wiley 1994)
25
+ _FAVORABLE = set("AVLIMFYWSTNQGC") # favorable at secondary pockets (hydrophobic / small / polar-uncharged)
26
+ _DISFAVORED = set("DEKRP") # charged / proline disfavored at anchor positions
27
+ MHC2_DOIS = ["10.1038/35030019", "10.1038/s41467-021-25414-9"] # Stern&Wiley groove; Cas9 MHC-II (Simhadri 2021)
28
+
29
+
30
+ def _clean(seq: str) -> str:
31
+ return "".join(c for c in str(seq).upper() if c in _AA)
32
+
33
+
34
+ def _core_is_binder(core: str) -> tuple[bool, float]:
35
+ """A 9-mer core is a promiscuous-binder candidate iff P1 (pos0) is a strong hydrophobic anchor AND >=2 of the
36
+ secondary pockets P4/P6/P9 are favorable with no disfavored residue at an anchor position."""
37
+ if core[0] not in P1_ANCHOR:
38
+ return False, 0.0
39
+ sec = sum(1 for p in (3, 5, 8) if core[p] in _FAVORABLE)
40
+ pen = sum(1 for p in (0, 3, 5, 8) if core[p] in _DISFAVORED)
41
+ score = 1.0 + 0.5 * sec - 0.5 * pen
42
+ return (sec >= 2 and pen == 0), round(score, 3)
43
+
44
+
45
+ def mhc2_binder_cores(seq: str) -> list[tuple[int, str, float]]:
46
+ """All promiscuous-binder 9-mer cores in the sequence: (start_index, core, score)."""
47
+ s = _clean(seq)
48
+ out = []
49
+ for i in range(len(s) - 8):
50
+ ok, sc = _core_is_binder(s[i:i + 9])
51
+ if ok:
52
+ out.append((i, s[i:i + 9], sc))
53
+ return out
54
+
55
+
56
+ def mhc2_epitope_load(seq: str) -> dict:
57
+ """Sequence-intrinsic MHC-II promiscuous-binder density + an immune score (1 = least presentable), 🟡 proxy."""
58
+ s = _clean(seq)
59
+ n_cores = max(0, len(s) - 8)
60
+ binders = mhc2_binder_cores(s)
61
+ density = (len(binders) / n_cores) if n_cores else 0.0
62
+ return {
63
+ "n_residues": len(s), "n_cores": n_cores, "n_promiscuous_binders": len(binders),
64
+ "epitope_density": round(density, 4),
65
+ "mhc2_immune_score": round(1.0 - min(density, 1.0), 4), # 1 = least presentable (MHC-I convention)
66
+ "method": "promiscuous MHC-II binder density (P1 hydrophobic anchor + P4/P6/P9 secondary pockets; "
67
+ "Stern & Wiley 1994; Southwood 1998)",
68
+ "status": "population-level sequence-intrinsic proxy (🟡); NOT a trained allele-specific predictor, NOT a "
69
+ "patient-HLA-specific magnitude (known-unknown)",
70
+ "binder_cores": [c for _, c, _ in binders[:50]],
71
+ }
72
+
73
+
74
+ # ---- bundled writer / control sequences (real UniProt, configs/writer_sequences.fasta) --------
75
+ @lru_cache(maxsize=1)
76
+ def writer_sequences() -> dict:
77
+ """Parse the bundled writer/control FASTA -> {name: {seq, origin, family, accession}}."""
78
+ txt = resource("configs/writer_sequences.fasta").read_text(encoding="utf-8")
79
+ out: dict = {}
80
+ name = seq = origin = family = acc = None
81
+
82
+ def _flush():
83
+ if name:
84
+ out[name] = {"seq": seq, "origin": origin, "family": family, "accession": acc}
85
+ for line in txt.splitlines():
86
+ if line.startswith("#"):
87
+ continue
88
+ if line.startswith(">"):
89
+ _flush()
90
+ head = line[1:].strip()
91
+ tok = head.split()
92
+ name, acc = (tok[0].split("|") + [None])[:2]
93
+ kv = dict(p.split("=", 1) for p in tok[1:] if "=" in p)
94
+ origin, family, seq = kv.get("origin"), kv.get("family"), ""
95
+ else:
96
+ seq = (seq or "") + line.strip()
97
+ _flush()
98
+ return out
99
+
100
+
101
+ def writer_family_to_sequence(writer_family: str) -> dict | None:
102
+ """Map a design's writer family (e.g. 'bridge_IS110', 'serine_integrase', 'Cas9') to a bundled writer
103
+ sequence record, or None when no representative sequence is bundled (then the axis abstains)."""
104
+ fam = (writer_family or "").lower()
105
+ seqs = writer_sequences()
106
+ for name, rec in seqs.items():
107
+ f = (rec.get("family") or "").lower()
108
+ if rec.get("origin") == "self":
109
+ continue
110
+ if fam and (fam in f or f in fam or fam in name.lower()):
111
+ return {"name": name, **rec}
112
+ if "cas9" in fam or "nuclease" in fam:
113
+ return {"name": "SpCas9", **seqs.get("SpCas9", {})} if "SpCas9" in seqs else None
114
+ return None
@@ -12,8 +12,10 @@ not a patient-level prediction.
12
12
  from __future__ import annotations
13
13
 
14
14
  from pen_stack.planner.antipeg_oracle import antipeg_oracle
15
+ from pen_stack.planner.ada_risk import ada_risk
15
16
  from pen_stack.planner.capsid_epitope_oracle import capsid_epitope_oracle
16
17
  from pen_stack.planner.genotoxicity_oracle import genotoxicity_oracle
18
+ from pen_stack.planner.immune_mhc2 import mhc2_epitope_load, writer_family_to_sequence
17
19
  from pen_stack.planner.innate_sensing import innate_sensing
18
20
  from pen_stack.planner.seroprevalence_oracle import seroprevalence_oracle
19
21
  from pen_stack.validate.immune_calibration import axis_label
@@ -67,6 +69,32 @@ def _axis(result, axis: str) -> dict:
67
69
  "note": result.note}
68
70
 
69
71
 
72
+ def _proxy_axis(value, note: str, axis: str = "mhc2_writer") -> dict:
73
+ """An axis record for the v6.9 sequence-intrinsic proxies (MHC-II / ADA). Value None = abstained (no writer
74
+ sequence). Population-level proxy until WS-CALIB validates — never a patient magnitude."""
75
+ return {"value": value, "uncertainty": None, "in_scope": value is not None, "available": value is not None,
76
+ "validation": axis_label(axis), "scope_card": axis, "note": note}
77
+
78
+
79
+ def _writer_antigen_card(design: dict) -> dict | None:
80
+ """The WRITER enzyme as a distinct antigen (v6.9 G-WS3): MHC-II epitope load + ADA-risk over the writer's real
81
+ sequence. Returns None when no representative writer sequence is bundled (axis then abstains)."""
82
+ wf = design.get("writer_family") or design.get("writer")
83
+ rec = writer_family_to_sequence(wf) if wf else None
84
+ if not rec or not rec.get("seq"):
85
+ return None
86
+ el = mhc2_epitope_load(rec["seq"])
87
+ ad = ada_risk(rec["seq"], rec.get("origin"))
88
+ return {"writer_family": wf, "representative": rec.get("name"), "accession": rec.get("accession"),
89
+ "origin": rec.get("origin"), "is_foreign": rec.get("origin") == "foreign",
90
+ "mhc2_immune_score": el["mhc2_immune_score"], "epitope_density": el["epitope_density"],
91
+ "ada_risk_score": ad["ada_risk_score"], "ada_immune_score": ad["ada_immune_score"],
92
+ "self_tolerance": ad["self_tolerance"],
93
+ "note": "the WRITER enzyme scored as a distinct antigen (MHC-II/CD4 + ADA, self-tolerance filtered); "
94
+ "bacterial/phage writers are foreign -> ADA-driving (Cas9 MHC-II: Simhadri 2021). "
95
+ "Population-level proxy (🟡); realized CD4 response / ADA titer is a known-unknown."}
96
+
97
+
70
98
  def immune_profile(design: dict) -> dict:
71
99
  """Per-design immune-risk profile across all axes. ``design`` keys: ``delivery_vehicle`` (or ``vehicle``),
72
100
  ``serotype``, ``cargo_seq``, ``writer_output_form`` (or ``cargo_form``), ``pegylated``.
@@ -79,20 +107,46 @@ def immune_profile(design: dict) -> dict:
79
107
  form = design.get("writer_output_form") or design.get("cargo_form") or ""
80
108
  peg = design.get("pegylated")
81
109
 
110
+ capsid_cd8 = capsid_epitope_oracle(veh)
111
+ writer_card = _writer_antigen_card(design) # v6.9 — the writer enzyme as a distinct antigen
112
+
82
113
  axes = {
83
114
  "genotoxicity": _axis(genotoxicity_oracle(veh), "genotoxicity"),
84
- "cd8_epitope": _axis(capsid_epitope_oracle(veh), "cd8_epitope"),
115
+ "cd8_epitope": _axis(capsid_cd8, "cd8_epitope"), # capsid CD8/MHC-I (v5.3)
85
116
  "innate": _axis(innate_sensing(cargo_seq, form), "innate"),
86
117
  "preexisting_nab": _axis(seroprevalence_oracle(veh, sero), "preexisting_nab"),
87
118
  "anti_peg": _axis(antipeg_oracle(veh, peg), "anti_peg"),
119
+ # v6.9 — CD4/MHC-II + ADA over the WRITER enzyme (the dominant immunogenicity driver, previously omitted)
120
+ "mhc2_writer": _proxy_axis(writer_card["mhc2_immune_score"] if writer_card else None,
121
+ (writer_card or {}).get("note", "no bundled writer sequence -> abstains"),
122
+ "mhc2_writer"),
123
+ "ada_writer": _proxy_axis(writer_card["ada_immune_score"] if writer_card else None,
124
+ "ADA-risk (higher ada_immune_score = safer) over the writer enzyme, self-"
125
+ "tolerance filtered; population proxy" if writer_card else
126
+ "no bundled writer sequence -> abstains", "ada_writer"),
88
127
  }
128
+
129
+ # writer-as-antigen comparison: for non-viral delivery (no foreign capsid) or a foreign writer outscoring the
130
+ # capsid, the WRITER is the dominant antigen — the v6.9 insight, never collapsed into the other axes.
131
+ dominant = None
132
+ writer_dominant_risk = False
133
+ if writer_card:
134
+ capsid_present = bool(capsid_cd8.available and capsid_cd8.value
135
+ and (capsid_cd8.value.get("capsid_immune_score") or 1.0) < 1.0)
136
+ writer_risk = writer_card["ada_risk_score"]
137
+ capsid_risk = (1.0 - (capsid_cd8.value or {}).get("capsid_immune_score", 1.0)) if capsid_present else 0.0
138
+ writer_dominant_risk = bool(writer_card["is_foreign"] and (not capsid_present or writer_risk >= capsid_risk))
139
+ dominant = "writer" if writer_dominant_risk else ("capsid" if capsid_present else "writer")
140
+
89
141
  return {
90
142
  "axes": axes,
91
143
  "collapsed_score": None, # deliberately None — a profile, never a fused number
144
+ "writer_as_antigen": ({**writer_card, "dominant_antigen": dominant,
145
+ "writer_dominant_risk": writer_dominant_risk} if writer_card else None),
92
146
  "route_modifier": _route_modifier(design.get("route")), # v5.6 WS-EXT documented route modifier (or None)
93
147
  "known_unknowns": KNOWN_UNKNOWNS,
94
148
  "no_fabrication": True,
95
- "note": ("relative immune-risk SCREEN across axes; each axis keeps its own value + uncertainty + scope "
96
- "+ validation label; NOT a patient-level prediction. The in-vivo response magnitude and the "
97
- "patient-specific titer are declared known-unknowns."),
149
+ "note": ("relative immune-risk SCREEN across axes (now incl. CD4/MHC-II + ADA over the writer enzyme); each "
150
+ "axis keeps its own value + uncertainty + scope + validation label; NEVER fused. NOT a patient-"
151
+ "level prediction. The realized CD4 response / ADA titer / in-vivo magnitude are known-unknowns."),
98
152
  }
@@ -94,6 +94,16 @@ AXIS_STATUS: dict[str, dict] = {
94
94
  "label": "anti_peg: population proxy — gates re-dosing, not calibrated to re-dosing failure",
95
95
  "reason": "anti-PEG seroprevalence gates re-dosing; not calibrated against observed re-dosing-failure "
96
96
  "rates (and induced post-dose-1 anti-PEG is a separate dynamic)."},
97
+ "mhc2_writer": { # v6.9 G-WS1 — CD4/MHC-II epitope load over the writer enzyme
98
+ "status": "mechanistic_proxy",
99
+ "label": "mhc2_writer: mechanistic/population proxy — NOT outcome-validated",
100
+ "reason": "sequence-intrinsic promiscuous MHC-II binder density (P1-anchor; Stern & Wiley 1994) is a "
101
+ "presentation potential, NOT a trained allele-specific predictor or a patient-HLA magnitude."},
102
+ "ada_writer": { # v6.9 G-WS2 — ADA-risk (MHC-II x foreignness, self-tolerance filtered)
103
+ "status": "mechanistic_proxy",
104
+ "label": "ada_writer: mechanistic/population proxy — NOT outcome-validated",
105
+ "reason": "ADA-risk = MHC-II epitope density x foreignness (self-tolerance filtered) recovers immunogenic-"
106
+ "vs-tolerated, but is not calibrated against observed ADA incidence at public-data power."},
97
107
  }
98
108
 
99
109
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pen-stack
3
- Version: 6.8.0
3
+ Version: 6.9.0
4
4
  Summary: Open infrastructure for genome writing: the Writable Genome atlas, the Writer Atlas, and the Write Planner.
5
5
  Author-email: Anees Ahmed Mahaboob Ali <ahmedaneesm@gmail.com>
6
6
  License: MIT
@@ -90,7 +90,7 @@ every design against rule-grounded mechanism, reports calibrated confidence, cit
90
90
  [![codecov](https://codecov.io/gh/ahmedanees-m/pen-stack/branch/main/graph/badge.svg)](https://codecov.io/gh/ahmedanees-m/pen-stack)
91
91
  [![License: MIT](https://img.shields.io/badge/License-MIT-informational.svg)](LICENSE)
92
92
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
93
- [![Version](https://img.shields.io/badge/version-6.8.0-blue.svg)](CHANGELOG.md)
93
+ [![Version](https://img.shields.io/badge/version-6.9.0-blue.svg)](CHANGELOG.md)
94
94
  [![Status](https://img.shields.io/badge/status-1.0%20First%20Stable-success.svg)](docs/STABILITY.md)
95
95
  [![Tests](https://img.shields.io/badge/tests-378%20passing-success.svg)](tests/)
96
96
  [![Lint: ruff](https://img.shields.io/badge/lint-ruff-purple.svg)](https://github.com/astral-sh/ruff)
@@ -148,6 +148,29 @@ demonstrated (v5.12) and the benchmark went public (v5.13).
148
148
  > unknown funnel remains — made legible (scope flags, known-unknowns, honest baselines, no fabrication), not
149
149
  > hidden.
150
150
 
151
+ ## What is new in v6.9 — PEN-IMMUNE (MHC-II/CD4 + ADA + the writer enzyme as a distinct antigen)
152
+
153
+ The immune profile did **CD8/MHC-I only** (capsid epitope load via MHCflurry) — but the **dominant** immunogenicity
154
+ driver is **MHC-II / CD4 help → anti-drug antibodies (ADA)**, and the **writer enzyme itself is immunogenic**
155
+ (Cas9 elicits MHC-II-presented CD4 responses, Simhadri *Nat Commun* 2021; bridge recombinases / serine integrases
156
+ are bacterial/phage) — yet Stage G scored only the capsid. v6.9 closes that gap, **never collapsing** the axes:
157
+
158
+ - **A CD4/MHC-II epitope-load axis** (`planner/immune_mhc2.py`) — a grounded, dependency-free **promiscuous MHC-II
159
+ binder density** over the documented P1 hydrophobic anchor (Stern & Wiley 1994) + secondary pockets, scored over
160
+ **capsid AND writer** sequences. Population-level proxy (🟡), never a patient-HLA magnitude.
161
+ - **An ADA-risk axis** (`planner/ada_risk.py`) — **ADA-risk = MHC-II epitope density × foreignness**, with a
162
+ **self-tolerance filter** (JanusMatrix-style: self epitopes are tolerated; foreign drive ADA). It **recovers
163
+ immunogenic-vs-tolerated**: the foreign writers (real UniProt SpCas9 / ISCro4 / Bxb1) score **above** the human
164
+ self control (albumin), even without the origin label (the k-mer self-match tolerates the human protein).
165
+ - **The writer as a distinct antigen** — the profile now carries a `writer_as_antigen` card and a
166
+ `writer_dominant_risk` flag: for **non-viral delivery of a bacterial writer there is no capsid antigen, so the
167
+ WRITER is the dominant immunogen** — the insight the capsid-only profile missed.
168
+ - **Immuno-Bench** (`benchmarks/immuno/`) — the immunogenic-vs-tolerated recovery track + an honest `calibrate_axis`
169
+ ADA pass (it stays 🟡 at public-data power — no manufactured ✅, the standing wet-lab bottleneck).
170
+
171
+ Real UniProt sequences only (no fabricated sequence); the axes are reported as a vector with `collapsed_score: None`;
172
+ the realized CD4 response / ADA titer stay known-unknowns. See [docs/immune_profiler.md](docs/immune_profiler.md).
173
+
151
174
  ## What is new in v6.8 — PEN-WRITER (a cross-family writer-efficiency engine + the first writer-efficiency benchmark)
152
175
 
153
176
  Stage C (pick the writer) was **retrieval** — the curated Writer Atlas ranks 8 families but predicts no
@@ -40,6 +40,7 @@ configs/seroprevalence.yaml
40
40
  configs/target_sites.yaml
41
41
  configs/universe_crosswalk.yaml
42
42
  configs/write_types.yaml
43
+ configs/writer_sequences.fasta
43
44
  configs/wtkb_curated.yaml
44
45
  configs/calibration/preexisting_nab_independent.yaml
45
46
  configs/expression/modifiers.yaml
@@ -82,6 +83,7 @@ docs/dissemination.md
82
83
  docs/environment.md
83
84
  docs/experiment_design.md
84
85
  docs/generative_design.md
86
+ docs/immune_profiler.md
85
87
  docs/index.md
86
88
  docs/integrations.md
87
89
  docs/live_oracles.md
@@ -213,6 +215,7 @@ pen_stack/oracles/status.py
213
215
  pen_stack/oracles/structure.py
214
216
  pen_stack/oracles/vcell.py
215
217
  pen_stack/planner/__init__.py
218
+ pen_stack/planner/ada_risk.py
216
219
  pen_stack/planner/antipeg_oracle.py
217
220
  pen_stack/planner/capsid_epitope_oracle.py
218
221
  pen_stack/planner/cargo.py
@@ -222,6 +225,7 @@ pen_stack/planner/delivery_constraints.py
222
225
  pen_stack/planner/delivery_immunology.py
223
226
  pen_stack/planner/delivery_vehicles.py
224
227
  pen_stack/planner/genotoxicity_oracle.py
228
+ pen_stack/planner/immune_mhc2.py
225
229
  pen_stack/planner/immune_profile.py
226
230
  pen_stack/planner/innate_sensing.py
227
231
  pen_stack/planner/multiplex.py
@@ -361,6 +365,7 @@ prereg/SHA256_LOCK_ws_graph.json
361
365
  prereg/SHA256_LOCK_ws_h.json
362
366
  prereg/SHA256_LOCK_ws_hybrid.json
363
367
  prereg/SHA256_LOCK_ws_immune.json
368
+ prereg/SHA256_LOCK_ws_immune2.json
364
369
  prereg/SHA256_LOCK_ws_ingest.json
365
370
  prereg/SHA256_LOCK_ws_innate.json
366
371
  prereg/SHA256_LOCK_ws_loop.json
@@ -432,6 +437,7 @@ prereg/ws_graph.yaml
432
437
  prereg/ws_h.yaml
433
438
  prereg/ws_hybrid.yaml
434
439
  prereg/ws_immune.yaml
440
+ prereg/ws_immune2.yaml
435
441
  prereg/ws_ingest.yaml
436
442
  prereg/ws_innate.yaml
437
443
  prereg/ws_loop.yaml
@@ -0,0 +1,8 @@
1
+ {
2
+ "cycle": "v6.9",
3
+ "workstream": "WS-IMMUNE2",
4
+ "prepared": "2026-06-20",
5
+ "sha256": {
6
+ "prereg/ws_immune2.yaml": "241c052bbd908664b98371a34f319ea08f7ab317693b550874dc28801ee5a5d2"
7
+ }
8
+ }