pen-stack 6.8.0__tar.gz → 6.9.1__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 (490) hide show
  1. {pen_stack-6.8.0 → pen_stack-6.9.1}/CHANGELOG.md +59 -0
  2. {pen_stack-6.8.0 → pen_stack-6.9.1}/CITATION.cff +1 -1
  3. {pen_stack-6.8.0 → pen_stack-6.9.1}/PKG-INFO +28 -2
  4. {pen_stack-6.8.0 → pen_stack-6.9.1}/README.md +27 -1
  5. pen_stack-6.9.1/configs/mhc_epitope_oracle.yaml +239 -0
  6. pen_stack-6.9.1/configs/writer_sequences.fasta +12 -0
  7. pen_stack-6.9.1/docs/immune_profiler.md +61 -0
  8. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/__init__.py +1 -1
  9. pen_stack-6.9.1/pen_stack/planner/ada_risk.py +87 -0
  10. pen_stack-6.9.1/pen_stack/planner/immune_mhc2.py +146 -0
  11. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/immune_profile.py +59 -4
  12. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/immune_calibration.py +10 -0
  13. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack.egg-info/PKG-INFO +28 -2
  14. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack.egg-info/SOURCES.txt +7 -0
  15. pen_stack-6.9.1/prereg/SHA256_LOCK_ws_immune2.json +8 -0
  16. pen_stack-6.9.1/prereg/ws_immune2.yaml +36 -0
  17. {pen_stack-6.8.0 → pen_stack-6.9.1}/pyproject.toml +1 -1
  18. {pen_stack-6.8.0 → pen_stack-6.9.1}/LICENSE +0 -0
  19. {pen_stack-6.8.0 → pen_stack-6.9.1}/MANIFEST.in +0 -0
  20. {pen_stack-6.8.0 → pen_stack-6.9.1}/bench/run.py +0 -0
  21. {pen_stack-6.8.0 → pen_stack-6.9.1}/benchmarks/genome_writing_bench/LEADERBOARD.md +0 -0
  22. {pen_stack-6.8.0 → pen_stack-6.9.1}/benchmarks/genome_writing_bench/README.md +0 -0
  23. {pen_stack-6.8.0 → pen_stack-6.9.1}/benchmarks/genome_writing_bench/SHA256SUMS +0 -0
  24. {pen_stack-6.8.0 → pen_stack-6.9.1}/benchmarks/genome_writing_bench/SUBMISSIONS.md +0 -0
  25. {pen_stack-6.8.0 → pen_stack-6.9.1}/benchmarks/genome_writing_bench/tasks.yaml +0 -0
  26. {pen_stack-6.8.0 → pen_stack-6.9.1}/benchmarks/genome_writing_challenge/README.md +0 -0
  27. {pen_stack-6.8.0 → pen_stack-6.9.1}/benchmarks/genome_writing_challenge/SUBMISSIONS.md +0 -0
  28. {pen_stack-6.8.0 → pen_stack-6.9.1}/benchmarks/position_effect/README.md +0 -0
  29. {pen_stack-6.8.0 → pen_stack-6.9.1}/benchmarks/position_effect/SHA256SUMS +0 -0
  30. {pen_stack-6.8.0 → pen_stack-6.9.1}/benchmarks/writer_efficiency/README.md +0 -0
  31. {pen_stack-6.8.0 → pen_stack-6.9.1}/benchmarks/writer_efficiency/SHA256SUMS +0 -0
  32. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/antipeg.yaml +0 -0
  33. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/atlas_families.yaml +0 -0
  34. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/bridge_offtarget_profile.yaml +0 -0
  35. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/calibration/preexisting_nab_independent.yaml +0 -0
  36. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/capsid_epitope_oracle.yaml +0 -0
  37. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/capsid_sequences.fasta +0 -0
  38. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/cargo_polish.yaml +0 -0
  39. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/cell_types.yaml +0 -0
  40. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/datasets.yaml +0 -0
  41. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/delivery_constraints.yaml +0 -0
  42. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/delivery_rules.yaml +0 -0
  43. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/delivery_vehicles.yaml +0 -0
  44. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/expression/modifiers.yaml +0 -0
  45. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/expression/promoters.yaml +0 -0
  46. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/gates_v3.yaml +0 -0
  47. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/genotoxicity_oracle.yaml +0 -0
  48. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/gsh_validated_heldout.yaml +0 -0
  49. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/intent_weights.yaml +0 -0
  50. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/known_unknowns.yaml +0 -0
  51. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/llm.yaml +0 -0
  52. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/metric_guide.yaml +0 -0
  53. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/monitor_queries.yaml +0 -0
  54. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/oracles/execution.yaml +0 -0
  55. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/oracles/scope_cards.yaml +0 -0
  56. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/rules/delivery.yaml +0 -0
  57. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/rules/fold.yaml +0 -0
  58. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/rules/multiplex.yaml +0 -0
  59. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/rules/payload.yaml +0 -0
  60. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/rules/reachability.yaml +0 -0
  61. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/safety/hazard_registry.yaml +0 -0
  62. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/safety/policy.yaml +0 -0
  63. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/safety/probes.yaml +0 -0
  64. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/score_axes.yaml +0 -0
  65. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/seroprevalence.yaml +0 -0
  66. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/target_sites.yaml +0 -0
  67. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/universe_crosswalk.yaml +0 -0
  68. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/write_types.yaml +0 -0
  69. {pen_stack-6.8.0 → pen_stack-6.9.1}/configs/wtkb_curated.yaml +0 -0
  70. {pen_stack-6.8.0 → pen_stack-6.9.1}/data/curated/bridge_offtarget_energetics.json +0 -0
  71. {pen_stack-6.8.0 → pen_stack-6.9.1}/data/curated/bridge_offtarget_profile_measured.parquet +0 -0
  72. {pen_stack-6.8.0 → pen_stack-6.9.1}/data/curated/gene_coords.parquet +0 -0
  73. {pen_stack-6.8.0 → pen_stack-6.9.1}/data/curated/unified_editor_universe.parquet +0 -0
  74. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/BACKLOG.md +0 -0
  75. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/DEPLOY.md +0 -0
  76. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/INFRA.md +0 -0
  77. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/MCP.md +0 -0
  78. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/RELEASING.md +0 -0
  79. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/REPRO.md +0 -0
  80. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/STABILITY.md +0 -0
  81. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/agent.md +0 -0
  82. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/alphagenome_feasibility.md +0 -0
  83. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/autonomy.md +0 -0
  84. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/benchmark_circularity.md +0 -0
  85. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/biosecurity.md +0 -0
  86. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/build_interface.md +0 -0
  87. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/cards/atlas.md +0 -0
  88. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/cards/durability.md +0 -0
  89. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/cards/position_effect_data.md +0 -0
  90. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/cards/safety.md +0 -0
  91. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/cards/writer_efficiency_data.md +0 -0
  92. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/challenge.md +0 -0
  93. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/closed_loop.md +0 -0
  94. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/co_scientist.md +0 -0
  95. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/co_scientist_loop.md +0 -0
  96. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/delivery.md +0 -0
  97. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/delivery_immunology.md +0 -0
  98. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/digital_twin.md +0 -0
  99. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/dissemination.md +0 -0
  100. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/environment.md +0 -0
  101. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/experiment_design.md +0 -0
  102. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/generative_design.md +0 -0
  103. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/index.md +0 -0
  104. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/integrations.md +0 -0
  105. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/live_oracles.md +0 -0
  106. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/mechanistic_constraints.md +0 -0
  107. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/oracles.md +0 -0
  108. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/position_effect.md +0 -0
  109. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/positioning.md +0 -0
  110. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/private_data_formats.md +0 -0
  111. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/quickstart.md +0 -0
  112. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/responsible_use.md +0 -0
  113. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/rules.md +0 -0
  114. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/scope.md +0 -0
  115. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/scorecard.md +0 -0
  116. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/tpe_bench.md +0 -0
  117. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/tutorials/compare-families.md +0 -0
  118. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/tutorials/score-deliverability.md +0 -0
  119. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/tutorials/where-can-i-write.md +0 -0
  120. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/tutorials/which-writer-reaches-locus.md +0 -0
  121. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/uncertainty.md +0 -0
  122. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/verify.md +0 -0
  123. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/world_model.md +0 -0
  124. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/writer_efficiency.md +0 -0
  125. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/writer_verification.md +0 -0
  126. {pen_stack-6.8.0 → pen_stack-6.9.1}/docs/wtkb.md +0 -0
  127. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/_resources.py +0 -0
  128. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/active/__init__.py +0 -0
  129. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/active/acquire.py +0 -0
  130. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/active/design.py +0 -0
  131. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/active/validate.py +0 -0
  132. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/adapt/__init__.py +0 -0
  133. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/adapt/finetune.py +0 -0
  134. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/adapt/ingest.py +0 -0
  135. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/adapt/pipeline.py +0 -0
  136. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/adapt/recalibrate.py +0 -0
  137. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/adapt/report.py +0 -0
  138. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/agent/__init__.py +0 -0
  139. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/agent/cite.py +0 -0
  140. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/agent/co_scientist.py +0 -0
  141. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/agent/epistemic.py +0 -0
  142. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/agent/guardrails.py +0 -0
  143. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/agent/mcp_server.py +0 -0
  144. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/agent/orchestrator.py +0 -0
  145. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/agent/orchestrator_live.py +0 -0
  146. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/agent/pen_agent.py +0 -0
  147. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/agent/scope.py +0 -0
  148. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/agent/tools.py +0 -0
  149. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/api/__init__.py +0 -0
  150. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/api/manifest.py +0 -0
  151. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/atlas/__init__.py +0 -0
  152. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/atlas/build_wtkb.py +0 -0
  153. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/atlas/crosslink.py +0 -0
  154. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/atlas/expand.py +0 -0
  155. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/atlas/guide_design.py +0 -0
  156. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/atlas/schema.py +0 -0
  157. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/atlas/scorecard.py +0 -0
  158. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/atlas/universe.py +0 -0
  159. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/atlas/variant_propose.py +0 -0
  160. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/atlas/writer_efficiency.py +0 -0
  161. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/atlas/writer_predict.py +0 -0
  162. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/atlas/writer_recommend.py +0 -0
  163. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/atlas/writer_verify.py +0 -0
  164. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/bridge/__init__.py +0 -0
  165. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/bridge/activity.py +0 -0
  166. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/bridge/cli.py +0 -0
  167. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/bridge/fold_qc.py +0 -0
  168. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/bridge/guide_qc.py +0 -0
  169. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/bridge/ingest.py +0 -0
  170. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/bridge/offtarget.py +0 -0
  171. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/bridge/offtarget_energetics.py +0 -0
  172. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/bridge/ortholog_screen.py +0 -0
  173. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/bridge/pipeline.py +0 -0
  174. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/build/__init__.py +0 -0
  175. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/build/ingest.py +0 -0
  176. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/build/protocol.py +0 -0
  177. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/build/simlab.py +0 -0
  178. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/cli.py +0 -0
  179. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/data/__init__.py +0 -0
  180. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/data/encode.py +0 -0
  181. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/data/genome.py +0 -0
  182. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/data/ingest_chromatin.py +0 -0
  183. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/data/ingest_integration.py +0 -0
  184. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/data/ingest_safety_annot.py +0 -0
  185. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/data/ingest_trip.py +0 -0
  186. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/design/__init__.py +0 -0
  187. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/design/generate.py +0 -0
  188. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/design/pareto.py +0 -0
  189. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/design/space.py +0 -0
  190. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/design/writer_variants.py +0 -0
  191. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/env/__init__.py +0 -0
  192. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/env/genome_writing_env.py +0 -0
  193. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/env/policies.py +0 -0
  194. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/graph/__init__.py +0 -0
  195. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/graph/build.py +0 -0
  196. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/graph/cell_types.py +0 -0
  197. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/graph/ingest.py +0 -0
  198. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/graph/query.py +0 -0
  199. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/graph/schema.py +0 -0
  200. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/loop/__init__.py +0 -0
  201. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/loop/continual.py +0 -0
  202. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/loop/cycle.py +0 -0
  203. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/loop/drift.py +0 -0
  204. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/mech/__init__.py +0 -0
  205. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/mech/classify_atlas.py +0 -0
  206. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/mech/whitelist.py +0 -0
  207. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/monitor/__init__.py +0 -0
  208. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/monitor/europepmc.py +0 -0
  209. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/monitor/run.py +0 -0
  210. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/monitor/triage.py +0 -0
  211. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/oracles/__init__.py +0 -0
  212. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/oracles/cache.py +0 -0
  213. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/oracles/energetics.py +0 -0
  214. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/oracles/genome.py +0 -0
  215. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/oracles/protein_design.py +0 -0
  216. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/oracles/rna.py +0 -0
  217. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/oracles/schema.py +0 -0
  218. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/oracles/status.py +0 -0
  219. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/oracles/structure.py +0 -0
  220. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/oracles/vcell.py +0 -0
  221. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/__init__.py +0 -0
  222. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/antipeg_oracle.py +0 -0
  223. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/capsid_epitope_oracle.py +0 -0
  224. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/cargo.py +0 -0
  225. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/cargo_polish.py +0 -0
  226. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/delivery.py +0 -0
  227. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/delivery_constraints.py +0 -0
  228. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/delivery_immunology.py +0 -0
  229. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/delivery_vehicles.py +0 -0
  230. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/genotoxicity_oracle.py +0 -0
  231. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/innate_sensing.py +0 -0
  232. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/multiplex.py +0 -0
  233. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/optimize.py +0 -0
  234. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/pipeline.py +0 -0
  235. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/report.py +0 -0
  236. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/router.py +0 -0
  237. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/seroprevalence_oracle.py +0 -0
  238. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/planner/target_site.py +0 -0
  239. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/rag/__init__.py +0 -0
  240. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/rag/index.py +0 -0
  241. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/rag/llm.py +0 -0
  242. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/rag/qa.py +0 -0
  243. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/rules/__init__.py +0 -0
  244. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/rules/evaluators.py +0 -0
  245. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/rules/loader.py +0 -0
  246. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/rules/schema.py +0 -0
  247. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/rules/solver.py +0 -0
  248. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/safety/__init__.py +0 -0
  249. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/safety/audit.py +0 -0
  250. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/safety/gate.py +0 -0
  251. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/safety/policy.py +0 -0
  252. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/safety/redteam.py +0 -0
  253. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/safety/registry.py +0 -0
  254. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/safety/screen.py +0 -0
  255. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/score/__init__.py +0 -0
  256. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/score/recalibrate.py +0 -0
  257. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/score/therapeutic.py +0 -0
  258. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/server/__init__.py +0 -0
  259. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/server/api.py +0 -0
  260. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/twin/__init__.py +0 -0
  261. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/twin/calibrate.py +0 -0
  262. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/twin/data/__init__.py +0 -0
  263. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/twin/data/position_effect.py +0 -0
  264. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/twin/mechanistic.py +0 -0
  265. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/twin/outcome.py +0 -0
  266. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/twin/position_effect.py +0 -0
  267. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/ui/__init__.py +0 -0
  268. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/ui/app.py +0 -0
  269. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/__init__.py +0 -0
  270. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/adapt_demo.py +0 -0
  271. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/agent_eval.py +0 -0
  272. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/bench_adversarial_tasks.py +0 -0
  273. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/bench_coscientist_tasks.py +0 -0
  274. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/bench_graph_tasks.py +0 -0
  275. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/bench_rule_tasks.py +0 -0
  276. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/bench_trust_tasks.py +0 -0
  277. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/bench_writetype_tasks.py +0 -0
  278. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/blind_gsh_discovery.py +0 -0
  279. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/cargo_directionality.py +0 -0
  280. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/closed_loop.py +0 -0
  281. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/durability_baselines.py +0 -0
  282. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/experiment_design.py +0 -0
  283. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/expr_controls.py +0 -0
  284. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/forward_hypotheses.py +0 -0
  285. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/generative_design.py +0 -0
  286. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/guide_qc_demo.py +0 -0
  287. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/heldout_celltype_expr.py +0 -0
  288. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/intent_specification.py +0 -0
  289. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/known_biology_expr.py +0 -0
  290. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/offtarget_energetics_eval.py +0 -0
  291. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/out_of_scope_refusal.py +0 -0
  292. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/outcome_calibration.py +0 -0
  293. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/outcome_prediction.py +0 -0
  294. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/paper3_benchmark.py +0 -0
  295. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/paper4_real_validation.py +0 -0
  296. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/paper4_validation.py +0 -0
  297. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/protocol_safety.py +0 -0
  298. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/safety_screening.py +0 -0
  299. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/selective_prediction.py +0 -0
  300. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/seq_vs_measured.py +0 -0
  301. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/target_site_controls.py +0 -0
  302. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/uncertainty_eval.py +0 -0
  303. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/ungrounded_baseline.py +0 -0
  304. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/within_locus_ranking.py +0 -0
  305. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/validate/writer_recovery.py +0 -0
  306. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/verify/__init__.py +0 -0
  307. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/verify/schema.py +0 -0
  308. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/verify/service.py +0 -0
  309. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/web/__init__.py +0 -0
  310. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/web/guide.py +0 -0
  311. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/web/llm.py +0 -0
  312. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/web/router.py +0 -0
  313. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/web/server.py +0 -0
  314. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/web/tools.py +0 -0
  315. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/wgenome/__init__.py +0 -0
  316. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/wgenome/chromatin_seq.py +0 -0
  317. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/wgenome/durability.py +0 -0
  318. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/wgenome/export_tracks.py +0 -0
  319. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/wgenome/features.py +0 -0
  320. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/wgenome/gsh_baseline.py +0 -0
  321. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/wgenome/mesh_features.py +0 -0
  322. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/wgenome/ood.py +0 -0
  323. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/wgenome/providers.py +0 -0
  324. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/wgenome/safety.py +0 -0
  325. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/wgenome/structure3d.py +0 -0
  326. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/wgenome/uncertainty.py +0 -0
  327. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack/wgenome/writability.py +0 -0
  328. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack.egg-info/dependency_links.txt +0 -0
  329. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack.egg-info/entry_points.txt +0 -0
  330. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack.egg-info/requires.txt +0 -0
  331. {pen_stack-6.8.0 → pen_stack-6.9.1}/pen_stack.egg-info/top_level.txt +0 -0
  332. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_phase0.json +0 -0
  333. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_phase1_5.json +0 -0
  334. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_phase2.json +0 -0
  335. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_phase3.json +0 -0
  336. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_a.json +0 -0
  337. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_acq.json +0 -0
  338. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_aldesign.json +0 -0
  339. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_alvalidate.json +0 -0
  340. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_atlas.json +0 -0
  341. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_b.json +0 -0
  342. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_ba.json +0 -0
  343. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_ba_v33.json +0 -0
  344. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_ba_v45.json +0 -0
  345. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_bench.json +0 -0
  346. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_c.json +0 -0
  347. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_cal.json +0 -0
  348. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_calib.json +0 -0
  349. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_challenge.json +0 -0
  350. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_chat.json +0 -0
  351. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_cite.json +0 -0
  352. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_continual.json +0 -0
  353. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_cosci2.json +0 -0
  354. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_crit.json +0 -0
  355. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_ct.json +0 -0
  356. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_d.json +0 -0
  357. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_drift.json +0 -0
  358. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_e.json +0 -0
  359. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_env.json +0 -0
  360. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_ep.json +0 -0
  361. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_epitope.json +0 -0
  362. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_expr2.json +0 -0
  363. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_f.json +0 -0
  364. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_frontend.json +0 -0
  365. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_g.json +0 -0
  366. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_gen.json +0 -0
  367. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_genotox.json +0 -0
  368. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_graph.json +0 -0
  369. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_h.json +0 -0
  370. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_hybrid.json +0 -0
  371. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_immune.json +0 -0
  372. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_ingest.json +0 -0
  373. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_innate.json +0 -0
  374. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_loop.json +0 -0
  375. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_manifest.json +0 -0
  376. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_mc.json +0 -0
  377. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_mcp.json +0 -0
  378. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_mech.json +0 -0
  379. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_mon.json +0 -0
  380. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_o.json +0 -0
  381. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_openapi.json +0 -0
  382. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_orch.json +0 -0
  383. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_outcome.json +0 -0
  384. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_pareto.json +0 -0
  385. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_peg.json +0 -0
  386. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_plan.json +0 -0
  387. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_policy.json +0 -0
  388. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_profile.json +0 -0
  389. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_proto.json +0 -0
  390. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_r.json +0 -0
  391. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_redteam.json +0 -0
  392. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_route.json +0 -0
  393. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_screen.json +0 -0
  394. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_seroprev.json +0 -0
  395. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_simlab.json +0 -0
  396. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_twincal.json +0 -0
  397. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_uq.json +0 -0
  398. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_v.json +0 -0
  399. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_vcell.json +0 -0
  400. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_writer.json +0 -0
  401. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/SHA256_LOCK_ws_wv.json +0 -0
  402. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/paper1.yaml +0 -0
  403. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/paper2.yaml +0 -0
  404. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/paper3.yaml +0 -0
  405. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/paper4.yaml +0 -0
  406. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/phase0.yaml +0 -0
  407. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_a.yaml +0 -0
  408. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_acq.yaml +0 -0
  409. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_aldesign.yaml +0 -0
  410. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_alvalidate.yaml +0 -0
  411. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_atlas.yaml +0 -0
  412. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_b.yaml +0 -0
  413. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_ba.yaml +0 -0
  414. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_ba_v33.yaml +0 -0
  415. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_ba_v45.yaml +0 -0
  416. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_bench.yaml +0 -0
  417. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_c.yaml +0 -0
  418. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_cal.yaml +0 -0
  419. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_calib.yaml +0 -0
  420. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_challenge.yaml +0 -0
  421. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_chat.yaml +0 -0
  422. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_cite.yaml +0 -0
  423. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_continual.yaml +0 -0
  424. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_cosci2.yaml +0 -0
  425. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_crit.yaml +0 -0
  426. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_ct.yaml +0 -0
  427. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_d.yaml +0 -0
  428. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_drift.yaml +0 -0
  429. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_e.yaml +0 -0
  430. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_env.yaml +0 -0
  431. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_ep.yaml +0 -0
  432. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_epitope.yaml +0 -0
  433. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_expr2.yaml +0 -0
  434. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_f.yaml +0 -0
  435. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_frontend.yaml +0 -0
  436. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_g.yaml +0 -0
  437. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_gen.yaml +0 -0
  438. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_genotox.yaml +0 -0
  439. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_graph.yaml +0 -0
  440. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_h.yaml +0 -0
  441. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_hybrid.yaml +0 -0
  442. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_immune.yaml +0 -0
  443. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_ingest.yaml +0 -0
  444. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_innate.yaml +0 -0
  445. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_loop.yaml +0 -0
  446. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_manifest.yaml +0 -0
  447. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_mc.yaml +0 -0
  448. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_mcp.yaml +0 -0
  449. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_mech.yaml +0 -0
  450. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_mon.yaml +0 -0
  451. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_o.yaml +0 -0
  452. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_openapi.yaml +0 -0
  453. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_orch.yaml +0 -0
  454. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_outcome.yaml +0 -0
  455. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_pareto.yaml +0 -0
  456. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_peg.yaml +0 -0
  457. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_plan.yaml +0 -0
  458. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_policy.yaml +0 -0
  459. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_profile.yaml +0 -0
  460. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_proto.yaml +0 -0
  461. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_r.yaml +0 -0
  462. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_redteam.yaml +0 -0
  463. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_route.yaml +0 -0
  464. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_screen.yaml +0 -0
  465. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_seroprev.yaml +0 -0
  466. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_simlab.yaml +0 -0
  467. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_twincal.yaml +0 -0
  468. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_uq.yaml +0 -0
  469. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_v.yaml +0 -0
  470. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_vcell.yaml +0 -0
  471. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_writer.yaml +0 -0
  472. {pen_stack-6.8.0 → pen_stack-6.9.1}/prereg/ws_wv.yaml +0 -0
  473. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/calibrate_immune_axes.py +0 -0
  474. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/fetch_licensed_sources.py +0 -0
  475. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/p1_build_atlas.py +0 -0
  476. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/p1_build_durability.py +0 -0
  477. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/p1_build_position_effect.py +0 -0
  478. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/p1_build_writer_eff.py +0 -0
  479. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/p1_export_tracks.py +0 -0
  480. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/p1_safety_concordance.py +0 -0
  481. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/p1_train_safety.py +0 -0
  482. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/p1_validation_report.py +0 -0
  483. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/p2_build_atlas.py +0 -0
  484. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/p3_benchmark_report.py +0 -0
  485. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/p4_genome_scan.py +0 -0
  486. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/p52_build_genotox_oracle.py +0 -0
  487. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/p53_build_epitope_oracle.py +0 -0
  488. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/ws_b_report.py +0 -0
  489. {pen_stack-6.8.0 → pen_stack-6.9.1}/scripts/ws_c_report.py +0 -0
  490. {pen_stack-6.8.0 → pen_stack-6.9.1}/setup.cfg +0 -0
@@ -3,6 +3,65 @@
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.1] - 2026-06-20 - Real NetMHCIIpan-4.0 / NetMHCpan-4.1 MHC epitope load (replaces the v6.9.0 proxy)
7
+
8
+ **PATCH — rigour upgrade.** v6.9.0's MHC-II axis was a documented *heuristic proxy* (P1-anchor density). The
9
+ gold-standard licensed predictors were already on the VM — so v6.9.1 computes the MHC-II epitope load with **real
10
+ NetMHCIIpan-4.0** (and MHC-I with **NetMHCpan-4.1**) over a frequent HLA panel, and re-grounds the axis on the real
11
+ values. Honest: the licensed binaries are **never committed/distributed** — only the **derived fractions** are
12
+ cached (`configs/mhc_epitope_oracle.yaml`), exactly like the v5.3 MHCflurry cache.
13
+
14
+ ### Changed
15
+ - `pen_stack/planner/immune_mhc2.py` — `mhc2_epitope_load(seq, name)` now uses the **real NetMHCIIpan-4.0 EL
16
+ %Rank≤2** cache (over 7 frequent HLA-II alleles) when the antigen is cached; the documented promiscuous-binder
17
+ proxy remains only as the **offline/CI fallback** for uncached sequences. `real_mhc2_load(name)` exposes the cache.
18
+ - `ada_risk` + `immune_profile` (writer-as-antigen) + `benchmarks/immuno` thread the antigen name → real values.
19
+ - `configs/mhc_epitope_oracle.yaml` (committed) — derived epitope fractions for the writer + capsid antigens.
20
+
21
+ ### Result (real tool is more discriminating than the proxy)
22
+ - Real NetMHCIIpan-4.0 strong-binder fraction: SpCas9 **0.153**, Bxb1 **0.152**, ISCro4 **0.112**, AAV2 0.114 vs
23
+ **human albumin (self) 0.066 — the lowest**. The gold-standard tool shows the self protein has a genuinely lower
24
+ MHC-II load and the foreign writers higher — a signal the heuristic proxy flattened (~0.08–0.10 for all). The
25
+ immunogenic-vs-tolerated recovery is unchanged (foreign ≫ self) but now on real predictions.
26
+
27
+ ### How it ran (no host install; per the VM Docker rule)
28
+ - `penmhc:tools` (debian + tcsh + gawk + perl) with `~/netmhc` (the licensed tools) **mounted**, NMHOME fixed at
29
+ runtime; `scratch/v691_mhc_compute.py` runs both predictors and writes the derived cache. The axis stays a 🟡
30
+ population-level proxy (frequent-HLA panel, not a patient-HLA magnitude — a known-unknown).
31
+
32
+ ## [6.9.0] - 2026-06-20 - PEN-IMMUNE: MHC-II/CD4 + ADA + writer-as-antigen
33
+
34
+ **MINOR feature release.** Extends the immune profile from CD8/MHC-I-only to a full T-cell profile — MHC-I +
35
+ **MHC-II/CD4 + ADA risk with self-tolerance filtering** — scored over the **writer enzyme as a distinct antigen**,
36
+ still population-level, OOD-gated, and **never collapsed**. Wraps the v5.6 unified profile. No fabrication: real
37
+ UniProt sequences, grounded documented method, honest 🟡 labels.
38
+
39
+ ### Added — the MHC-II + ADA axes (WS-IMMUNE2: G-WS1, G-WS2)
40
+ - `pen_stack/planner/immune_mhc2.py` — grounded, dependency-free **promiscuous MHC-II binder density** (documented
41
+ P1 hydrophobic anchor, Stern & Wiley 1994; secondary pockets, Southwood 1998) over capsid AND writer sequences +
42
+ the bundled real writer/control FASTA. `configs/writer_sequences.fasta` — real UniProt: SpCas9 (Q99ZW2), ISCro4
43
+ bridge recombinase (D2TGM5), Bxb1 integrase (Q9B086), human albumin self control (P02768).
44
+ - `pen_stack/planner/ada_risk.py` — **ADA-risk = MHC-II epitope density × foreignness** with a JanusMatrix-style
45
+ **self-tolerance filter** (origin authoritative; human-proteome k-mer filter otherwise). Recovers
46
+ immunogenic-vs-tolerated: foreign writers score above the human self control (clean separation).
47
+
48
+ ### Changed — the unified profile (G-WS3)
49
+ - `pen_stack/planner/immune_profile.py` — adds `mhc2_writer` + `ada_writer` axes and a `writer_as_antigen` card
50
+ with `dominant_antigen` + `writer_dominant_risk` (fires for a foreign writer, especially non-viral delivery
51
+ where there is no capsid antigen). `collapsed_score` stays `None` (asserted). `immune_calibration.AXIS_STATUS`
52
+ registers the two new axes as mechanistic/population proxies.
53
+
54
+ ### Added — Immuno-Bench + honest calibration (G-WS4)
55
+ - `benchmarks/immuno/harness.py` — the immunogenic-vs-tolerated recovery track (non-circular: label = protein
56
+ origin) + an honest `calibrate_axis` ADA pass that **stays 🟡** at public-data power (no manufactured ✅).
57
+ - `tests/unit/test_ws_immune2.py` (CI-safe; pure-Python method + committed sequences). `prereg/ws_immune2.yaml`.
58
+
59
+ ### Honesty
60
+ - Every axis is a population-level proxy, never a patient-specific ADA titer / realized CD4 magnitude (known-
61
+ unknowns). The MHC-II method is sequence-intrinsic presentation potential, not a trained allele-specific predictor.
62
+ The self-tolerance k-mer filter is seeded by the bundled human reference (full human proteome substitutable on the
63
+ VM); the authoritative foreignness signal is the protein origin. Axes are a vector, never fused.
64
+
6
65
  ## [6.8.0] - 2026-06-20 - PEN-WRITER: cross-family writer-efficiency engine + Writer-Efficiency Bench
7
66
 
8
67
  **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.1
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.1
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.1-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,32 @@ 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`) — **v6.9.1 computes it with the real, licensed
159
+ NetMHCIIpan-4.0** (EL %Rank≤2 over a frequent HLA-II panel; MHC-I via NetMHCpan-4.1), scored over **capsid AND
160
+ writer** sequences; only the derived fractions are cached (`configs/mhc_epitope_oracle.yaml`, the binaries are
161
+ never distributed), with a documented promiscuous-binder proxy as the offline/CI fallback. Population-level proxy
162
+ (🟡), never a patient-HLA magnitude. *(v6.9.0 used the heuristic proxy; the real tool is more discriminating —
163
+ human-self albumin 0.066 vs foreign writers 0.11–0.15.)*
164
+ - **An ADA-risk axis** (`planner/ada_risk.py`) — **ADA-risk = MHC-II epitope density × foreignness**, with a
165
+ **self-tolerance filter** (JanusMatrix-style: self epitopes are tolerated; foreign drive ADA). It **recovers
166
+ immunogenic-vs-tolerated**: the foreign writers (real UniProt SpCas9 / ISCro4 / Bxb1) score **above** the human
167
+ self control (albumin), even without the origin label (the k-mer self-match tolerates the human protein).
168
+ - **The writer as a distinct antigen** — the profile now carries a `writer_as_antigen` card and a
169
+ `writer_dominant_risk` flag: for **non-viral delivery of a bacterial writer there is no capsid antigen, so the
170
+ WRITER is the dominant immunogen** — the insight the capsid-only profile missed.
171
+ - **Immuno-Bench** (`benchmarks/immuno/`) — the immunogenic-vs-tolerated recovery track + an honest `calibrate_axis`
172
+ ADA pass (it stays 🟡 at public-data power — no manufactured ✅, the standing wet-lab bottleneck).
173
+
174
+ Real UniProt sequences only (no fabricated sequence); the axes are reported as a vector with `collapsed_score: None`;
175
+ the realized CD4 response / ADA titer stay known-unknowns. See [docs/immune_profiler.md](docs/immune_profiler.md).
176
+
151
177
  ## What is new in v6.8 — PEN-WRITER (a cross-family writer-efficiency engine + the first writer-efficiency benchmark)
152
178
 
153
179
  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.1-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,32 @@ 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`) — **v6.9.1 computes it with the real, licensed
84
+ NetMHCIIpan-4.0** (EL %Rank≤2 over a frequent HLA-II panel; MHC-I via NetMHCpan-4.1), scored over **capsid AND
85
+ writer** sequences; only the derived fractions are cached (`configs/mhc_epitope_oracle.yaml`, the binaries are
86
+ never distributed), with a documented promiscuous-binder proxy as the offline/CI fallback. Population-level proxy
87
+ (🟡), never a patient-HLA magnitude. *(v6.9.0 used the heuristic proxy; the real tool is more discriminating —
88
+ human-self albumin 0.066 vs foreign writers 0.11–0.15.)*
89
+ - **An ADA-risk axis** (`planner/ada_risk.py`) — **ADA-risk = MHC-II epitope density × foreignness**, with a
90
+ **self-tolerance filter** (JanusMatrix-style: self epitopes are tolerated; foreign drive ADA). It **recovers
91
+ immunogenic-vs-tolerated**: the foreign writers (real UniProt SpCas9 / ISCro4 / Bxb1) score **above** the human
92
+ self control (albumin), even without the origin label (the k-mer self-match tolerates the human protein).
93
+ - **The writer as a distinct antigen** — the profile now carries a `writer_as_antigen` card and a
94
+ `writer_dominant_risk` flag: for **non-viral delivery of a bacterial writer there is no capsid antigen, so the
95
+ WRITER is the dominant immunogen** — the insight the capsid-only profile missed.
96
+ - **Immuno-Bench** (`benchmarks/immuno/`) — the immunogenic-vs-tolerated recovery track + an honest `calibrate_axis`
97
+ ADA pass (it stays 🟡 at public-data power — no manufactured ✅, the standing wet-lab bottleneck).
98
+
99
+ Real UniProt sequences only (no fabricated sequence); the axes are reported as a vector with `collapsed_score: None`;
100
+ the realized CD4 response / ADA titer stay known-unknowns. See [docs/immune_profiler.md](docs/immune_profiler.md).
101
+
76
102
  ## What is new in v6.8 — PEN-WRITER (a cross-family writer-efficiency engine + the first writer-efficiency benchmark)
77
103
 
78
104
  Stage C (pick the writer) was **retrieval** — the curated Writer Atlas ranks 8 families but predicts no
@@ -0,0 +1,239 @@
1
+ version: 6.9.1
2
+ method:
3
+ mhc2: NetMHCIIpan-4.0 EL %Rank<=2
4
+ mhc1: NetMHCpan-4.1 %Rank<=0.5
5
+ hla2_panel:
6
+ - DRB1_0101
7
+ - DRB1_0301
8
+ - DRB1_0401
9
+ - DRB1_0701
10
+ - DRB1_1101
11
+ - DRB1_1301
12
+ - DRB1_1501
13
+ hla1_panel:
14
+ - HLA-A01:01
15
+ - HLA-A02:01
16
+ - HLA-A03:01
17
+ - HLA-A11:01
18
+ - HLA-A24:02
19
+ - HLA-A26:01
20
+ - HLA-B07:02
21
+ - HLA-B08:01
22
+ - HLA-B15:01
23
+ - HLA-B27:05
24
+ - HLA-B40:01
25
+ - HLA-B58:01
26
+ provenance_dois:
27
+ - 10.1093/nar/gkac1029
28
+ - 10.1093/nar/gkaa379
29
+ note: population-level epitope load over a frequent HLA panel (NOT patient-HLA-specific);
30
+ licensed NetMHC binaries run locally, only derived fractions cached.
31
+ mhc2:
32
+ SpCas9:
33
+ epitope_fraction_strong: 0.1529
34
+ immune_score: 0.8471
35
+ n_windows: 1354
36
+ n_strong: 207
37
+ alleles_used:
38
+ - DRB1_0101
39
+ - DRB1_0301
40
+ - DRB1_0401
41
+ - DRB1_0701
42
+ - DRB1_1101
43
+ - DRB1_1301
44
+ - DRB1_1501
45
+ ISCro4:
46
+ epitope_fraction_strong: 0.1122
47
+ immune_score: 0.8878
48
+ n_windows: 312
49
+ n_strong: 35
50
+ alleles_used:
51
+ - DRB1_0101
52
+ - DRB1_0301
53
+ - DRB1_0401
54
+ - DRB1_0701
55
+ - DRB1_1101
56
+ - DRB1_1301
57
+ - DRB1_1501
58
+ Bxb1:
59
+ epitope_fraction_strong: 0.152
60
+ immune_score: 0.848
61
+ n_windows: 487
62
+ n_strong: 74
63
+ alleles_used:
64
+ - DRB1_0101
65
+ - DRB1_0301
66
+ - DRB1_0401
67
+ - DRB1_0701
68
+ - DRB1_1101
69
+ - DRB1_1301
70
+ - DRB1_1501
71
+ HumanAlbumin:
72
+ epitope_fraction_strong: 0.0655
73
+ immune_score: 0.9345
74
+ n_windows: 595
75
+ n_strong: 39
76
+ alleles_used:
77
+ - DRB1_0101
78
+ - DRB1_0301
79
+ - DRB1_0401
80
+ - DRB1_0701
81
+ - DRB1_1101
82
+ - DRB1_1301
83
+ - DRB1_1501
84
+ AAV2_VP1:
85
+ epitope_fraction_strong: 0.1137
86
+ immune_score: 0.8863
87
+ n_windows: 721
88
+ n_strong: 82
89
+ alleles_used:
90
+ - DRB1_0101
91
+ - DRB1_0301
92
+ - DRB1_0401
93
+ - DRB1_0701
94
+ - DRB1_1101
95
+ - DRB1_1301
96
+ - DRB1_1501
97
+ Ad5_hexon:
98
+ epitope_fraction_strong: 0.1471
99
+ immune_score: 0.8529
100
+ n_windows: 938
101
+ n_strong: 138
102
+ alleles_used:
103
+ - DRB1_0101
104
+ - DRB1_0301
105
+ - DRB1_0401
106
+ - DRB1_0701
107
+ - DRB1_1101
108
+ - DRB1_1301
109
+ - DRB1_1501
110
+ VSVg_Indiana:
111
+ epitope_fraction_strong: 0.0684
112
+ immune_score: 0.9316
113
+ n_windows: 497
114
+ n_strong: 34
115
+ alleles_used:
116
+ - DRB1_0101
117
+ - DRB1_0301
118
+ - DRB1_0401
119
+ - DRB1_0701
120
+ - DRB1_1101
121
+ - DRB1_1301
122
+ - DRB1_1501
123
+ HSV1_gD:
124
+ epitope_fraction_strong: 0.1184
125
+ immune_score: 0.8816
126
+ n_windows: 380
127
+ n_strong: 45
128
+ alleles_used:
129
+ - DRB1_0101
130
+ - DRB1_0301
131
+ - DRB1_0401
132
+ - DRB1_0701
133
+ - DRB1_1101
134
+ - DRB1_1301
135
+ - DRB1_1501
136
+ HSV1_gB:
137
+ epitope_fraction_strong: 0.1067
138
+ immune_score: 0.8933
139
+ n_windows: 890
140
+ n_strong: 95
141
+ alleles_used:
142
+ - DRB1_0101
143
+ - DRB1_0301
144
+ - DRB1_0401
145
+ - DRB1_0701
146
+ - DRB1_1101
147
+ - DRB1_1301
148
+ - DRB1_1501
149
+ mhc1:
150
+ AAV2_VP1:
151
+ epitope_fraction_strong: 0.0935
152
+ immune_score: 0.9065
153
+ n_windows: 727
154
+ n_strong: 68
155
+ alleles_used:
156
+ - HLA-A01:01
157
+ - HLA-A02:01
158
+ - HLA-A03:01
159
+ - HLA-A11:01
160
+ - HLA-A24:02
161
+ - HLA-A26:01
162
+ - HLA-B07:02
163
+ - HLA-B08:01
164
+ - HLA-B15:01
165
+ - HLA-B27:05
166
+ - HLA-B40:01
167
+ - HLA-B58:01
168
+ Ad5_hexon:
169
+ epitope_fraction_strong: 0.1367
170
+ immune_score: 0.8633
171
+ n_windows: 944
172
+ n_strong: 129
173
+ alleles_used:
174
+ - HLA-A01:01
175
+ - HLA-A02:01
176
+ - HLA-A03:01
177
+ - HLA-A11:01
178
+ - HLA-A24:02
179
+ - HLA-A26:01
180
+ - HLA-B07:02
181
+ - HLA-B08:01
182
+ - HLA-B15:01
183
+ - HLA-B27:05
184
+ - HLA-B40:01
185
+ - HLA-B58:01
186
+ VSVg_Indiana:
187
+ epitope_fraction_strong: 0.1074
188
+ immune_score: 0.8926
189
+ n_windows: 503
190
+ n_strong: 54
191
+ alleles_used:
192
+ - HLA-A01:01
193
+ - HLA-A02:01
194
+ - HLA-A03:01
195
+ - HLA-A11:01
196
+ - HLA-A24:02
197
+ - HLA-A26:01
198
+ - HLA-B07:02
199
+ - HLA-B08:01
200
+ - HLA-B15:01
201
+ - HLA-B27:05
202
+ - HLA-B40:01
203
+ - HLA-B58:01
204
+ HSV1_gD:
205
+ epitope_fraction_strong: 0.1218
206
+ immune_score: 0.8782
207
+ n_windows: 386
208
+ n_strong: 47
209
+ alleles_used:
210
+ - HLA-A01:01
211
+ - HLA-A02:01
212
+ - HLA-A03:01
213
+ - HLA-A11:01
214
+ - HLA-A24:02
215
+ - HLA-A26:01
216
+ - HLA-B07:02
217
+ - HLA-B08:01
218
+ - HLA-B15:01
219
+ - HLA-B27:05
220
+ - HLA-B40:01
221
+ - HLA-B58:01
222
+ HSV1_gB:
223
+ epitope_fraction_strong: 0.115
224
+ immune_score: 0.885
225
+ n_windows: 896
226
+ n_strong: 103
227
+ alleles_used:
228
+ - HLA-A01:01
229
+ - HLA-A02:01
230
+ - HLA-A03:01
231
+ - HLA-A11:01
232
+ - HLA-A24:02
233
+ - HLA-A26:01
234
+ - HLA-B07:02
235
+ - HLA-B08:01
236
+ - HLA-B15:01
237
+ - HLA-B27:05
238
+ - HLA-B40:01
239
+ - HLA-B58:01
@@ -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,61 @@
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
+ > **v6.9.1 — real predictor.** The MHC-II epitope load is computed with the **licensed NetMHCIIpan-4.0** (EL
10
+ > %Rank≤2 over a frequent HLA-II panel; MHC-I via **NetMHCpan-4.1**), run inside `penmhc:tools` Docker on the VM
11
+ > with the licensed tools **mounted** (never committed). Only the **derived fractions** are cached
12
+ > (`configs/mhc_epitope_oracle.yaml`), exactly like the v5.3 MHCflurry cache. The documented proxy below remains as
13
+ > the offline/CI fallback for sequences not in the cache. Real result: human-self albumin **0.066** vs foreign
14
+ > writers **0.11–0.15** (the gold-standard tool discriminates self from foreign — the v6.9.0 proxy gave ~0.08–0.10
15
+ > for all). Still a 🟡 population-level proxy (frequent-HLA panel, not a patient-HLA magnitude).
16
+
17
+ A grounded, dependency-free **promiscuous MHC-II binder density** (the offline/CI fallback): MHC-II presents a 9-mer core in an open groove
18
+ whose **P1 pocket is deep and hydrophobic** — the single dominant anchor (M/F/Y/W/L/I/V; Stern & Wiley, *Nature*
19
+ 1994), with secondary pockets at P4/P6/P9. A *promiscuous* epitope (binds many HLA-DR) has a strong P1 anchor +
20
+ favorable secondaries (Southwood 1998). We count promiscuous-binder cores → an epitope-density proxy, computed over
21
+ **capsid AND writer** sequences. It is a **population-level, sequence-intrinsic proxy (🟡)** — not a trained
22
+ allele-specific predictor, not a patient-HLA magnitude (a known-unknown).
23
+
24
+ ## The ADA-risk axis + self-tolerance (`planner/ada_risk.py`)
25
+
26
+ Epitope load is necessary but not sufficient — **self** proteins carry MHC-II epitopes yet are tolerated. So:
27
+
28
+ ```
29
+ ADA-risk = MHC-II epitope density × foreignness
30
+ ```
31
+
32
+ with a **self-tolerance filter** (JanusMatrix-style: an epitope whose core matches the human proteome is
33
+ tolerated). `foreignness` uses the **authoritative protein origin** (self vs bacterial/viral/phage) when known,
34
+ else `1 − self_match_fraction` from a human-proteome k-mer filter. This **recovers immunogenic-vs-tolerated**:
35
+
36
+ | Protein (real UniProt) | origin | ADA-risk |
37
+ |---|---|---|
38
+ | Bxb1 integrase (Q9B086) | foreign | **0.095** |
39
+ | SpCas9 (Q99ZW2) | foreign | **0.093** |
40
+ | ISCro4 bridge recombinase (D2TGM5) | foreign | **0.082** |
41
+ | Human albumin (P02768) | self | **0.0** (tolerated) |
42
+
43
+ The human self control scores 0 **even without the origin label** — the k-mer self-match tolerates it. The foreign
44
+ writers separate cleanly above it.
45
+
46
+ ## The writer as a distinct antigen
47
+
48
+ `immune_profile` now carries a `writer_as_antigen` card and a `writer_dominant_risk` flag. The insight the
49
+ capsid-only profile missed: **for non-viral delivery (LNP/mRNA, eVLP) of a bacterial writer there is no capsid
50
+ antigen — so the WRITER is the dominant immunogen.** The flag fires accordingly; the axes are reported as a vector
51
+ with `collapsed_score: None` (never fused).
52
+
53
+ ## Honest limits
54
+ - Population-level proxies (🟡), never a patient-specific ADA titer / realized CD4 magnitude (known-unknowns).
55
+ - The MHC-II method is presentation potential, not a trained allele-specific predictor.
56
+ - The self-tolerance k-mer filter is seeded by the bundled human reference; the **full human proteome** is
57
+ substitutable on the VM (the authoritative foreignness signal is the protein origin).
58
+ - The ADA axis's `calibrate_axis` pass **stays 🟡** — no public observed-incidence set at N≥6 power (the standing
59
+ wet-lab/clinical-data bottleneck), reported, never manufactured.
60
+
61
+ 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.1"
@@ -0,0 +1,87 @@
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,
56
+ name: str | None = None) -> dict:
57
+ """ADA-risk = MHC-II epitope density x foreignness, with the self-tolerance filter. Uses the REAL NetMHCIIpan-4.0
58
+ epitope density when the antigen `name` is cached (else the documented proxy). Higher ada_risk_score = MORE
59
+ anti-drug-antibody risk; `ada_immune_score = 1 - ada_risk_score` (higher = safer) for profile parity."""
60
+ el = mhc2_epitope_load(seq, name)
61
+ st = self_tolerance(seq, human_kmers)
62
+ sm = st["self_match_fraction"] or 0.0
63
+ if origin == "self":
64
+ foreign = 0.0
65
+ else: # foreign or unknown -> use the self-match filter
66
+ foreign = round(1.0 - sm, 4)
67
+ risk = round(el["epitope_density"] * foreign, 4)
68
+ return {
69
+ "ada_risk_score": risk, "ada_immune_score": round(1.0 - risk, 4),
70
+ "epitope_density": el["epitope_density"], "foreignness": foreign, "origin": origin,
71
+ "self_tolerance": st,
72
+ "direction": "ada_risk_score: higher = MORE ADA risk; ada_immune_score: higher = safer",
73
+ "filter": "JanusMatrix-style self-tolerance: foreign non-self MHC-II epitopes drive ADA; self epitopes are "
74
+ "tolerated (central tolerance). Origin is authoritative when known; else the human-proteome "
75
+ "k-mer filter.",
76
+ "status": "population-level proxy (🟡); patient ADA titer / magnitude is a known-unknown",
77
+ "dois": ADA_DOIS,
78
+ }
79
+
80
+
81
+ def ada_risk_named(name: str) -> dict:
82
+ """ADA-risk for a bundled writer/control protein by name (uses its declared origin)."""
83
+ rec = writer_sequences().get(name)
84
+ if not rec:
85
+ return {"available": False, "note": f"no bundled sequence {name!r}"}
86
+ return {"available": True, "name": name, "family": rec.get("family"),
87
+ **ada_risk(rec["seq"], rec.get("origin"), name=name)}