pen-stack 6.10.4__tar.gz → 6.12.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 (534) hide show
  1. pen_stack-6.12.0/CHANGELOG.md +1582 -0
  2. {pen_stack-6.10.4 → pen_stack-6.12.0}/CITATION.cff +1 -1
  3. pen_stack-6.12.0/PKG-INFO +304 -0
  4. pen_stack-6.12.0/README.md +229 -0
  5. {pen_stack-6.10.4 → pen_stack-6.12.0}/bench/run.py +15 -15
  6. pen_stack-6.12.0/benchmarks/delivery/SHA256SUMS +2 -0
  7. {pen_stack-6.10.4 → pen_stack-6.12.0}/benchmarks/genome_writing_bench/LEADERBOARD.md +5 -5
  8. {pen_stack-6.10.4 → pen_stack-6.12.0}/benchmarks/genome_writing_bench/README.md +13 -13
  9. {pen_stack-6.10.4 → pen_stack-6.12.0}/benchmarks/genome_writing_bench/tasks.yaml +17 -17
  10. {pen_stack-6.10.4 → pen_stack-6.12.0}/benchmarks/genome_writing_challenge/README.md +3 -3
  11. {pen_stack-6.10.4 → pen_stack-6.12.0}/benchmarks/genome_writing_challenge/SUBMISSIONS.md +3 -3
  12. {pen_stack-6.10.4 → pen_stack-6.12.0}/benchmarks/position_effect/README.md +10 -10
  13. pen_stack-6.12.0/benchmarks/verify/SHA256SUMS +2 -0
  14. {pen_stack-6.10.4 → pen_stack-6.12.0}/benchmarks/writer_efficiency/README.md +8 -8
  15. pen_stack-6.12.0/configs/aav_serotype_tropism.yaml +81 -0
  16. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/antipeg.yaml +8 -8
  17. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/atlas_families.yaml +10 -10
  18. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/bridge_offtarget_profile.yaml +18 -18
  19. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/calibration/preexisting_nab_independent.yaml +3 -3
  20. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/cargo_polish.yaml +10 -10
  21. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/cell_types.yaml +7 -7
  22. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/datasets.yaml +18 -18
  23. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/delivery_constraints.yaml +10 -10
  24. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/delivery_rules.yaml +1 -1
  25. pen_stack-6.12.0/configs/delivery_vehicles.yaml +185 -0
  26. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/expression/modifiers.yaml +12 -12
  27. pen_stack-6.12.0/configs/expression/promoters.yaml +52 -0
  28. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/gates_v3.yaml +3 -3
  29. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/gsh_validated_heldout.yaml +26 -26
  30. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/intent_weights.yaml +10 -10
  31. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/known_unknowns.yaml +8 -8
  32. pen_stack-6.12.0/configs/llm.yaml +59 -0
  33. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/metric_guide.yaml +34 -34
  34. pen_stack-6.12.0/configs/oracles/execution.yaml +87 -0
  35. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/oracles/scope_cards.yaml +36 -20
  36. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/rules/fold.yaml +1 -1
  37. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/rules/reachability.yaml +1 -1
  38. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/safety/hazard_registry.yaml +19 -19
  39. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/safety/policy.yaml +7 -7
  40. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/safety/probes.yaml +4 -4
  41. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/score_axes.yaml +14 -14
  42. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/seroprevalence.yaml +2 -2
  43. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/target_sites.yaml +15 -15
  44. pen_stack-6.12.0/configs/universe_crosswalk.yaml +36 -0
  45. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/write_types.yaml +2 -2
  46. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/wtkb_curated.yaml +2 -2
  47. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/BACKLOG.md +6 -6
  48. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/STABILITY.md +9 -9
  49. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/agent.md +10 -10
  50. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/alphagenome_feasibility.md +8 -8
  51. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/autonomy.md +10 -10
  52. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/benchmark_circularity.md +11 -11
  53. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/biosecurity.md +10 -10
  54. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/build_interface.md +7 -7
  55. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/cards/durability.md +3 -3
  56. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/cards/offtarget_data.md +21 -21
  57. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/cards/position_effect_data.md +7 -7
  58. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/cards/writer_efficiency_data.md +5 -5
  59. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/challenge.md +8 -8
  60. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/closed_loop.md +14 -14
  61. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/co_scientist.md +7 -7
  62. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/co_scientist_loop.md +3 -3
  63. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/delivery.md +4 -4
  64. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/delivery_immunology.md +41 -41
  65. pen_stack-6.12.0/docs/delivery_recommender.md +54 -0
  66. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/digital_twin.md +11 -11
  67. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/dissemination.md +2 -2
  68. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/environment.md +2 -2
  69. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/experiment_design.md +10 -10
  70. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/generative_design.md +10 -10
  71. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/immune_profiler.md +21 -21
  72. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/index.md +1 -1
  73. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/integrations.md +14 -14
  74. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/live_oracles.md +13 -13
  75. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/mechanistic_constraints.md +14 -14
  76. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/offtarget.md +14 -15
  77. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/oracles.md +6 -6
  78. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/position_effect.md +19 -19
  79. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/positioning.md +2 -2
  80. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/private_data_formats.md +2 -2
  81. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/responsible_use.md +19 -19
  82. pen_stack-6.12.0/docs/rule_spec.md +18 -0
  83. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/rules.md +3 -3
  84. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/scope.md +11 -11
  85. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/tpe_bench.md +7 -7
  86. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/tutorials/which-writer-reaches-locus.md +1 -1
  87. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/uncertainty.md +30 -30
  88. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/verify.md +4 -4
  89. pen_stack-6.12.0/docs/verify_service.md +52 -0
  90. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/world_model.md +7 -7
  91. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/writer_efficiency.md +15 -15
  92. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/writer_verification.md +11 -11
  93. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/__init__.py +1 -1
  94. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/_resources.py +2 -2
  95. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/active/__init__.py +3 -3
  96. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/active/acquire.py +4 -4
  97. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/active/design.py +1 -1
  98. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/active/validate.py +7 -7
  99. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/adapt/ingest.py +1 -1
  100. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/adapt/pipeline.py +1 -1
  101. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/adapt/recalibrate.py +1 -1
  102. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/adapt/report.py +1 -1
  103. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/agent/cite.py +23 -6
  104. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/agent/co_scientist.py +22 -22
  105. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/agent/epistemic.py +11 -11
  106. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/agent/guardrails.py +2 -2
  107. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/agent/mcp_server.py +26 -5
  108. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/agent/orchestrator.py +3 -3
  109. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/agent/orchestrator_live.py +1 -1
  110. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/agent/pen_agent.py +12 -12
  111. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/agent/scope.py +1 -1
  112. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/api/__init__.py +4 -4
  113. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/api/manifest.py +18 -3
  114. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/atlas/build_wtkb.py +1 -1
  115. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/atlas/crosslink.py +7 -7
  116. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/atlas/expand.py +3 -3
  117. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/atlas/guide_design.py +23 -23
  118. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/atlas/schema.py +10 -10
  119. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/atlas/scorecard.py +3 -3
  120. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/atlas/variant_propose.py +4 -4
  121. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/atlas/writer_efficiency.py +11 -11
  122. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/atlas/writer_predict.py +10 -10
  123. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/atlas/writer_recommend.py +9 -9
  124. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/atlas/writer_verify.py +27 -27
  125. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/bridge/cli.py +4 -4
  126. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/bridge/fold_qc.py +1 -1
  127. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/bridge/guide_qc.py +1 -1
  128. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/bridge/ingest.py +4 -4
  129. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/bridge/offtarget.py +9 -9
  130. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/bridge/offtarget_energetics.py +9 -9
  131. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/bridge/ortholog_screen.py +2 -2
  132. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/bridge/pipeline.py +2 -2
  133. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/build/__init__.py +2 -2
  134. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/build/ingest.py +3 -3
  135. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/build/protocol.py +9 -9
  136. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/build/simlab.py +2 -2
  137. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/cli.py +1 -1
  138. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/data/encode.py +2 -2
  139. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/data/genome.py +1 -1
  140. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/data/ingest_chromatin.py +2 -2
  141. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/data/ingest_integration.py +1 -1
  142. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/data/ingest_safety_annot.py +5 -5
  143. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/data/ingest_trip.py +3 -3
  144. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/design/__init__.py +2 -2
  145. pen_stack-6.12.0/pen_stack/design/capsid_generate.py +62 -0
  146. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/design/generate.py +6 -6
  147. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/design/pareto.py +2 -2
  148. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/design/space.py +2 -2
  149. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/design/writer_variants.py +28 -28
  150. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/env/genome_writing_env.py +21 -21
  151. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/env/policies.py +9 -9
  152. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/graph/build.py +5 -5
  153. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/graph/cell_types.py +2 -2
  154. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/graph/ingest.py +8 -8
  155. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/graph/query.py +3 -3
  156. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/graph/schema.py +8 -8
  157. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/loop/__init__.py +2 -2
  158. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/loop/continual.py +4 -4
  159. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/loop/cycle.py +9 -9
  160. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/loop/drift.py +2 -2
  161. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/mech/classify_atlas.py +2 -2
  162. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/mech/whitelist.py +4 -4
  163. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/monitor/europepmc.py +1 -1
  164. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/monitor/run.py +1 -1
  165. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/monitor/triage.py +3 -3
  166. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/oracles/__init__.py +2 -2
  167. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/oracles/cache.py +1 -1
  168. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/oracles/energetics.py +2 -2
  169. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/oracles/genome.py +16 -16
  170. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/oracles/protein_design.py +15 -15
  171. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/oracles/rna.py +2 -2
  172. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/oracles/schema.py +15 -15
  173. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/oracles/status.py +6 -6
  174. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/oracles/structure.py +2 -2
  175. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/oracles/vcell.py +5 -5
  176. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/ada_risk.py +8 -8
  177. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/antipeg_oracle.py +3 -3
  178. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/capsid_epitope_oracle.py +6 -6
  179. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/cargo.py +3 -3
  180. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/cargo_polish.py +2 -2
  181. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/delivery.py +1 -1
  182. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/delivery_constraints.py +1 -1
  183. pen_stack-6.12.0/pen_stack/planner/delivery_immune.py +60 -0
  184. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/delivery_immunology.py +19 -19
  185. pen_stack-6.12.0/pen_stack/planner/delivery_predict.py +136 -0
  186. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/genotoxicity_oracle.py +4 -4
  187. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/immune_mhc2.py +15 -15
  188. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/immune_profile.py +19 -19
  189. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/innate_sensing.py +3 -3
  190. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/multiplex.py +3 -3
  191. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/optimize.py +3 -3
  192. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/pipeline.py +1 -1
  193. pen_stack-6.12.0/pen_stack/planner/report.py +26 -0
  194. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/router.py +3 -3
  195. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/seroprevalence_oracle.py +3 -3
  196. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/target_site.py +11 -11
  197. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/rag/llm.py +4 -4
  198. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/rag/qa.py +2 -2
  199. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/rules/__init__.py +1 -1
  200. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/rules/evaluators.py +14 -9
  201. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/rules/schema.py +14 -14
  202. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/rules/solver.py +2 -2
  203. pen_stack-6.12.0/pen_stack/rules/spec.py +78 -0
  204. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/safety/__init__.py +1 -1
  205. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/safety/audit.py +2 -2
  206. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/safety/gate.py +2 -2
  207. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/safety/policy.py +4 -4
  208. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/safety/redteam.py +3 -3
  209. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/safety/registry.py +5 -5
  210. pen_stack-6.12.0/pen_stack/safety/screen.py +51 -0
  211. pen_stack-6.12.0/pen_stack/safety/standards.py +141 -0
  212. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/score/therapeutic.py +2 -2
  213. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/server/api.py +43 -7
  214. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/twin/__init__.py +3 -3
  215. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/twin/calibrate.py +5 -5
  216. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/twin/data/__init__.py +1 -1
  217. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/twin/data/position_effect.py +12 -12
  218. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/twin/mechanistic.py +11 -11
  219. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/twin/outcome.py +7 -7
  220. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/twin/position_effect.py +22 -22
  221. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/ui/app.py +15 -15
  222. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/adapt_demo.py +5 -5
  223. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/agent_eval.py +3 -3
  224. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/bench_adversarial_tasks.py +8 -8
  225. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/bench_coscientist_tasks.py +2 -2
  226. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/bench_graph_tasks.py +3 -3
  227. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/bench_rule_tasks.py +3 -3
  228. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/bench_trust_tasks.py +9 -9
  229. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/bench_writetype_tasks.py +3 -3
  230. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/blind_gsh_discovery.py +8 -8
  231. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/cargo_directionality.py +5 -5
  232. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/closed_loop.py +4 -4
  233. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/durability_baselines.py +5 -5
  234. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/experiment_design.py +4 -4
  235. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/expr_controls.py +1 -1
  236. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/forward_hypotheses.py +2 -2
  237. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/generative_design.py +3 -3
  238. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/guide_qc_demo.py +8 -8
  239. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/heldout_celltype_expr.py +4 -4
  240. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/immune_calibration.py +27 -27
  241. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/intent_specification.py +1 -1
  242. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/offtarget_energetics_eval.py +12 -12
  243. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/out_of_scope_refusal.py +5 -5
  244. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/outcome_calibration.py +11 -11
  245. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/outcome_prediction.py +6 -6
  246. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/paper3_benchmark.py +5 -5
  247. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/paper4_real_validation.py +9 -9
  248. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/paper4_validation.py +1 -1
  249. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/protocol_safety.py +2 -2
  250. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/safety_screening.py +2 -2
  251. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/selective_prediction.py +2 -2
  252. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/seq_vs_measured.py +4 -4
  253. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/target_site_controls.py +6 -6
  254. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/uncertainty_eval.py +8 -8
  255. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/ungrounded_baseline.py +15 -15
  256. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/within_locus_ranking.py +8 -8
  257. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/writer_recovery.py +2 -2
  258. pen_stack-6.12.0/pen_stack/verify/proof.py +169 -0
  259. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/verify/schema.py +9 -9
  260. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/verify/service.py +5 -5
  261. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/web/__init__.py +5 -5
  262. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/web/guide.py +10 -10
  263. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/web/llm.py +39 -39
  264. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/web/router.py +6 -6
  265. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/web/server.py +9 -9
  266. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/web/tools.py +21 -21
  267. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/chromatin_seq.py +2 -2
  268. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/durability.py +1 -1
  269. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/features.py +2 -2
  270. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/gsh_baseline.py +2 -2
  271. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/mesh_features.py +9 -9
  272. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/offtarget_assay.py +5 -5
  273. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/offtarget_data.py +7 -7
  274. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/offtarget_predict.py +15 -15
  275. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/ood.py +10 -10
  276. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/providers.py +10 -10
  277. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/safety.py +3 -3
  278. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/structure3d.py +18 -18
  279. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/uncertainty.py +6 -6
  280. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/writability.py +6 -6
  281. pen_stack-6.12.0/pen_stack.egg-info/PKG-INFO +304 -0
  282. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack.egg-info/SOURCES.txt +17 -1
  283. pen_stack-6.12.0/prereg/SHA256_LOCK_ws_delivery.json +8 -0
  284. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_hybrid.json +1 -1
  285. pen_stack-6.12.0/prereg/SHA256_LOCK_ws_immune2.json +8 -0
  286. pen_stack-6.12.0/prereg/SHA256_LOCK_ws_offtarget.json +8 -0
  287. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_r.json +1 -1
  288. pen_stack-6.12.0/prereg/SHA256_LOCK_ws_verify.json +8 -0
  289. pen_stack-6.12.0/prereg/SHA256_LOCK_ws_writer.json +8 -0
  290. pen_stack-6.12.0/prereg/ws_delivery.yaml +39 -0
  291. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_hybrid.yaml +1 -1
  292. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_immune2.yaml +8 -8
  293. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_offtarget.yaml +1 -1
  294. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_r.yaml +2 -2
  295. pen_stack-6.12.0/prereg/ws_verify.yaml +45 -0
  296. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_writer.yaml +4 -4
  297. {pen_stack-6.10.4 → pen_stack-6.12.0}/pyproject.toml +23 -23
  298. pen_stack-6.12.0/scripts/build_capsid_fitness.py +93 -0
  299. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/calibrate_immune_axes.py +34 -34
  300. pen_stack-6.12.0/scripts/fetch_licensed_sources.py +57 -0
  301. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/offtarget_chromatin_incremental.py +7 -7
  302. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/offtarget_chromatin_matched.py +2 -2
  303. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/offtarget_chromatin_validation.py +1 -1
  304. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/p1_build_atlas.py +4 -4
  305. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/p1_build_durability.py +3 -3
  306. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/p1_build_position_effect.py +15 -15
  307. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/p1_build_writer_eff.py +8 -8
  308. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/p1_export_tracks.py +1 -1
  309. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/p1_safety_concordance.py +2 -2
  310. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/p1_train_safety.py +3 -3
  311. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/p1_validation_report.py +4 -4
  312. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/p2_build_atlas.py +5 -5
  313. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/p3_benchmark_report.py +1 -1
  314. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/p4_genome_scan.py +1 -1
  315. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/p52_build_genotox_oracle.py +10 -10
  316. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/p53_build_epitope_oracle.py +6 -6
  317. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/ws_b_report.py +5 -5
  318. pen_stack-6.10.4/CHANGELOG.md +0 -1533
  319. pen_stack-6.10.4/PKG-INFO +0 -1111
  320. pen_stack-6.10.4/README.md +0 -1036
  321. pen_stack-6.10.4/configs/delivery_vehicles.yaml +0 -185
  322. pen_stack-6.10.4/configs/expression/promoters.yaml +0 -52
  323. pen_stack-6.10.4/configs/llm.yaml +0 -59
  324. pen_stack-6.10.4/configs/oracles/execution.yaml +0 -87
  325. pen_stack-6.10.4/configs/universe_crosswalk.yaml +0 -36
  326. pen_stack-6.10.4/docs/DEVIATIONS_AND_DISCLOSURES.md +0 -57
  327. pen_stack-6.10.4/pen_stack/planner/report.py +0 -26
  328. pen_stack-6.10.4/pen_stack/safety/screen.py +0 -51
  329. pen_stack-6.10.4/pen_stack.egg-info/PKG-INFO +0 -1111
  330. pen_stack-6.10.4/prereg/SHA256_LOCK_ws_immune2.json +0 -8
  331. pen_stack-6.10.4/prereg/SHA256_LOCK_ws_offtarget.json +0 -8
  332. pen_stack-6.10.4/prereg/SHA256_LOCK_ws_writer.json +0 -8
  333. pen_stack-6.10.4/scripts/fetch_licensed_sources.py +0 -57
  334. {pen_stack-6.10.4 → pen_stack-6.12.0}/LICENSE +0 -0
  335. {pen_stack-6.10.4 → pen_stack-6.12.0}/MANIFEST.in +0 -0
  336. {pen_stack-6.10.4 → pen_stack-6.12.0}/benchmarks/genome_writing_bench/SHA256SUMS +0 -0
  337. {pen_stack-6.10.4 → pen_stack-6.12.0}/benchmarks/genome_writing_bench/SUBMISSIONS.md +0 -0
  338. {pen_stack-6.10.4 → pen_stack-6.12.0}/benchmarks/offtarget/SHA256SUMS +0 -0
  339. {pen_stack-6.10.4 → pen_stack-6.12.0}/benchmarks/position_effect/SHA256SUMS +0 -0
  340. {pen_stack-6.10.4 → pen_stack-6.12.0}/benchmarks/writer_efficiency/SHA256SUMS +0 -0
  341. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/capsid_epitope_oracle.yaml +0 -0
  342. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/capsid_sequences.fasta +0 -0
  343. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/genotoxicity_oracle.yaml +0 -0
  344. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/mhc_epitope_oracle.yaml +0 -0
  345. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/monitor_queries.yaml +0 -0
  346. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/rules/delivery.yaml +0 -0
  347. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/rules/multiplex.yaml +0 -0
  348. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/rules/payload.yaml +0 -0
  349. {pen_stack-6.10.4 → pen_stack-6.12.0}/configs/writer_sequences.fasta +0 -0
  350. {pen_stack-6.10.4 → pen_stack-6.12.0}/data/curated/bridge_offtarget_energetics.json +0 -0
  351. {pen_stack-6.10.4 → pen_stack-6.12.0}/data/curated/bridge_offtarget_profile_measured.parquet +0 -0
  352. {pen_stack-6.10.4 → pen_stack-6.12.0}/data/curated/gene_coords.parquet +0 -0
  353. {pen_stack-6.10.4 → pen_stack-6.12.0}/data/curated/unified_editor_universe.parquet +0 -0
  354. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/DEPLOY.md +0 -0
  355. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/INFRA.md +0 -0
  356. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/MCP.md +0 -0
  357. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/RELEASING.md +0 -0
  358. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/REPRO.md +0 -0
  359. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/cards/atlas.md +0 -0
  360. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/cards/safety.md +0 -0
  361. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/quickstart.md +0 -0
  362. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/scorecard.md +0 -0
  363. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/tutorials/compare-families.md +0 -0
  364. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/tutorials/score-deliverability.md +0 -0
  365. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/tutorials/where-can-i-write.md +0 -0
  366. {pen_stack-6.10.4 → pen_stack-6.12.0}/docs/wtkb.md +0 -0
  367. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/adapt/__init__.py +0 -0
  368. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/adapt/finetune.py +0 -0
  369. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/agent/__init__.py +0 -0
  370. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/agent/tools.py +0 -0
  371. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/atlas/__init__.py +0 -0
  372. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/atlas/universe.py +0 -0
  373. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/bridge/__init__.py +0 -0
  374. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/bridge/activity.py +0 -0
  375. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/data/__init__.py +0 -0
  376. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/env/__init__.py +0 -0
  377. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/graph/__init__.py +0 -0
  378. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/mech/__init__.py +0 -0
  379. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/monitor/__init__.py +0 -0
  380. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/__init__.py +0 -0
  381. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/planner/delivery_vehicles.py +0 -0
  382. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/rag/__init__.py +0 -0
  383. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/rag/index.py +0 -0
  384. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/rules/loader.py +0 -0
  385. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/score/__init__.py +0 -0
  386. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/score/recalibrate.py +0 -0
  387. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/server/__init__.py +0 -0
  388. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/ui/__init__.py +0 -0
  389. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/__init__.py +0 -0
  390. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/validate/known_biology_expr.py +0 -0
  391. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/verify/__init__.py +0 -0
  392. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/__init__.py +0 -0
  393. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack/wgenome/export_tracks.py +0 -0
  394. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack.egg-info/dependency_links.txt +0 -0
  395. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack.egg-info/entry_points.txt +0 -0
  396. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack.egg-info/requires.txt +0 -0
  397. {pen_stack-6.10.4 → pen_stack-6.12.0}/pen_stack.egg-info/top_level.txt +0 -0
  398. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_phase0.json +0 -0
  399. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_phase1_5.json +0 -0
  400. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_phase2.json +0 -0
  401. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_phase3.json +0 -0
  402. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_a.json +0 -0
  403. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_acq.json +0 -0
  404. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_aldesign.json +0 -0
  405. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_alvalidate.json +0 -0
  406. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_atlas.json +0 -0
  407. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_b.json +0 -0
  408. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_ba.json +0 -0
  409. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_ba_v33.json +0 -0
  410. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_ba_v45.json +0 -0
  411. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_bench.json +0 -0
  412. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_c.json +0 -0
  413. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_cal.json +0 -0
  414. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_calib.json +0 -0
  415. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_challenge.json +0 -0
  416. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_chat.json +0 -0
  417. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_cite.json +0 -0
  418. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_continual.json +0 -0
  419. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_cosci2.json +0 -0
  420. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_crit.json +0 -0
  421. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_ct.json +0 -0
  422. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_d.json +0 -0
  423. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_drift.json +0 -0
  424. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_e.json +0 -0
  425. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_env.json +0 -0
  426. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_ep.json +0 -0
  427. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_epitope.json +0 -0
  428. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_expr2.json +0 -0
  429. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_f.json +0 -0
  430. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_frontend.json +0 -0
  431. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_g.json +0 -0
  432. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_gen.json +0 -0
  433. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_genotox.json +0 -0
  434. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_graph.json +0 -0
  435. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_h.json +0 -0
  436. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_immune.json +0 -0
  437. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_ingest.json +0 -0
  438. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_innate.json +0 -0
  439. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_loop.json +0 -0
  440. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_manifest.json +0 -0
  441. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_mc.json +0 -0
  442. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_mcp.json +0 -0
  443. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_mech.json +0 -0
  444. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_mon.json +0 -0
  445. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_o.json +0 -0
  446. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_openapi.json +0 -0
  447. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_orch.json +0 -0
  448. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_outcome.json +0 -0
  449. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_pareto.json +0 -0
  450. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_peg.json +0 -0
  451. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_plan.json +0 -0
  452. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_policy.json +0 -0
  453. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_profile.json +0 -0
  454. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_proto.json +0 -0
  455. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_redteam.json +0 -0
  456. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_route.json +0 -0
  457. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_screen.json +0 -0
  458. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_seroprev.json +0 -0
  459. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_simlab.json +0 -0
  460. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_twincal.json +0 -0
  461. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_uq.json +0 -0
  462. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_v.json +0 -0
  463. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_vcell.json +0 -0
  464. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/SHA256_LOCK_ws_wv.json +0 -0
  465. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/paper1.yaml +0 -0
  466. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/paper2.yaml +0 -0
  467. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/paper3.yaml +0 -0
  468. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/paper4.yaml +0 -0
  469. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/phase0.yaml +0 -0
  470. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_a.yaml +0 -0
  471. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_acq.yaml +0 -0
  472. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_aldesign.yaml +0 -0
  473. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_alvalidate.yaml +0 -0
  474. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_atlas.yaml +0 -0
  475. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_b.yaml +0 -0
  476. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_ba.yaml +0 -0
  477. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_ba_v33.yaml +0 -0
  478. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_ba_v45.yaml +0 -0
  479. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_bench.yaml +0 -0
  480. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_c.yaml +0 -0
  481. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_cal.yaml +0 -0
  482. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_calib.yaml +0 -0
  483. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_challenge.yaml +0 -0
  484. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_chat.yaml +0 -0
  485. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_cite.yaml +0 -0
  486. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_continual.yaml +0 -0
  487. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_cosci2.yaml +0 -0
  488. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_crit.yaml +0 -0
  489. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_ct.yaml +0 -0
  490. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_d.yaml +0 -0
  491. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_drift.yaml +0 -0
  492. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_e.yaml +0 -0
  493. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_env.yaml +0 -0
  494. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_ep.yaml +0 -0
  495. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_epitope.yaml +0 -0
  496. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_expr2.yaml +0 -0
  497. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_f.yaml +0 -0
  498. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_frontend.yaml +0 -0
  499. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_g.yaml +0 -0
  500. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_gen.yaml +0 -0
  501. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_genotox.yaml +0 -0
  502. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_graph.yaml +0 -0
  503. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_h.yaml +0 -0
  504. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_immune.yaml +0 -0
  505. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_ingest.yaml +0 -0
  506. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_innate.yaml +0 -0
  507. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_loop.yaml +0 -0
  508. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_manifest.yaml +0 -0
  509. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_mc.yaml +0 -0
  510. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_mcp.yaml +0 -0
  511. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_mech.yaml +0 -0
  512. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_mon.yaml +0 -0
  513. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_o.yaml +0 -0
  514. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_openapi.yaml +0 -0
  515. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_orch.yaml +0 -0
  516. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_outcome.yaml +0 -0
  517. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_pareto.yaml +0 -0
  518. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_peg.yaml +0 -0
  519. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_plan.yaml +0 -0
  520. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_policy.yaml +0 -0
  521. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_profile.yaml +0 -0
  522. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_proto.yaml +0 -0
  523. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_redteam.yaml +0 -0
  524. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_route.yaml +0 -0
  525. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_screen.yaml +0 -0
  526. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_seroprev.yaml +0 -0
  527. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_simlab.yaml +0 -0
  528. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_twincal.yaml +0 -0
  529. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_uq.yaml +0 -0
  530. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_v.yaml +0 -0
  531. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_vcell.yaml +0 -0
  532. {pen_stack-6.10.4 → pen_stack-6.12.0}/prereg/ws_wv.yaml +0 -0
  533. {pen_stack-6.10.4 → pen_stack-6.12.0}/scripts/ws_c_report.py +0 -0
  534. {pen_stack-6.10.4 → pen_stack-6.12.0}/setup.cfg +0 -0
@@ -0,0 +1,1582 @@
1
+ # Changelog
2
+
3
+ All notable changes to PEN-STACK are documented here. This file follows
4
+ [Keep a Changelog](https://keepachangelog.com/).
5
+
6
+ ## [6.12.0] - 2026-06-21 - Verification service: published rule spec, proof object, standards-aligned biosecurity
7
+
8
+ Hardens `verify(design)` into a formal verification service. The rule base becomes a published, citable spec;
9
+ `verify_proof()` returns a repair-oriented proof object an agent can fix a failed design from; and the
10
+ biosecurity gate is mapped to the community synthesis-screening standards.
11
+
12
+ ### Added
13
+ - **Published rule spec** (`pen_stack/rules/spec.py`, `benchmarks/verify/rule_spec.json`, `docs/rule_spec.md`).
14
+ The rule base exports as a machine-readable, citable document. A parity check confirms the exported spec
15
+ round-trips to the exact ruleset the solver loads (0 mismatches), every rule names a registered evaluator,
16
+ and every rule carries a DOI or a note.
17
+ - **Repair-oriented proof object** (`pen_stack/verify/proof.py`). `verify_proof(design)` returns three axes,
18
+ legality, confidence and biosecurity, reported separately, each with a status, the rule or signature that
19
+ fired, evidence, and a repair hint; the collapsed verdict is `None`. `repair_from_proof` fixes a
20
+ failed-on-legality design using only the proof object and re-verifies it. Biosecurity hazards are
21
+ acknowledged and routed to human review, never auto-repaired.
22
+ - **Biosecurity standards alignment** (`pen_stack/safety/standards.py`). Maps the Guardian screen kinds and
23
+ decisions onto the IBBIS Common Mechanism categories and `ScreenStatus` (Pass / Warning / Flag) and onto
24
+ SecureDNA's pass/deny outcome, with a concordance report (8/8 concordant on the labelled probe set).
25
+ References: Common Mechanism (Wheeler et al. 2024, `10.1089/apb.2023.0034`); SecureDNA (`arXiv:2403.14023`).
26
+ - **Verify-Bench** (`benchmarks/verify/`) reporting the three gates, and surfaces: REST `POST /api/verify/proof`,
27
+ MCP `verify_proof`, manifest tool `verify_proof`, and `docs/verify_service.md`.
28
+
29
+ ### Notes
30
+ - The verdict covers legality, feasibility and biosecurity, not efficacy (efficacy stays a downstream
31
+ prediction with its own uncertainty). The biosecurity hook is the in-design gate; the full sequence-screening
32
+ pipeline is BioFirewall, and the standard alignment is a concordance, not a certification.
33
+ - The plan paired this with a Stage A WriteSpec / SAT repair loop. Stage A is not yet built, so the proof-object
34
+ repair loop here is self-contained; the WriteSpec coupling is a documented future integration.
35
+
36
+ ## [6.11.0] - 2026-06-20 - Cross-modality deliverability and a learned capsid-fitness model
37
+
38
+ Delivery moves from an 8-vehicle rule palette to a cross-modality recommender. It adds a learned,
39
+ benchmarked AAV capsid-fitness model, a serotype-to-tissue tropism prior grounded in approved therapies, and an
40
+ immune-coupled dose tradeoff, without fabricating tropism. All datasets were independently verified.
41
+
42
+ ### Added
43
+ - **Learned AAV capsid-fitness on FLIP-AAV** (`pen_stack/planner/delivery_predict.py`, `scripts/build_capsid_fitness.py`,
44
+ `benchmarks/delivery/`). Trained on the FLIP-AAV benchmark (Dallago 2021; Bryant 2021 packaging fitness,
45
+ `10.1038/s41587-020-00793-4`; Ogden 2019 `10.1126/science.aaw2900`). It beats a mutation-burden baseline on
46
+ both held-out splits: `sampled` Spearman 0.920 vs 0.522 (CI [0.387, 0.411]); `mut_des`
47
+ (mutant to designed) 0.814 vs 0.752 (CI [0.061, 0.064]). The 217 MB/split FLIP data stays on the VM; the derived
48
+ metrics and the reproducible build script are committed. The ~3 MB model itself is gitignored, regenerated via
49
+ `scripts/build_capsid_fitness.py` and mounted into the deployed app (like `position_effect.pkl`); the axis abstains
50
+ gracefully when absent. Predicted fitness is a candidate for the measured packaging axis, not in-vivo tropism.
51
+ - **Serotype-to-tissue tropism priors** (`configs/aav_serotype_tropism.yaml`) from approved AAV therapies (AAV9 to CNS,
52
+ AAVrh74 to skeletal muscle vs AAVRh74var to liver: different capsids, kept separate; AAV5 to liver; AAV2 to retina/
53
+ putamen via local injection). This is a grounded prior for an approved serotype and a known-unknown (abstain) for a novel
54
+ capsid. Casgevy/Lyfgenia carry no serotype prior (not-AAV controls).
55
+ - **Immune-coupled dose tradeoff** (`pen_stack/planner/delivery_immune.py`) fuses deliverability with the Stage G
56
+ immune profile and surfaces dose vs immunogenicity per vehicle as a vector (`collapsed_score=None`, never fused).
57
+ - **Verify-gated generative capsids** (`pen_stack/design/capsid_generate.py`): fitness-filtered VP1 variants,
58
+ candidates only; abstains without the model.
59
+ - **Surfaces:** REST `POST /delivery`, `POST /capsid_fitness`, and `GET /delivery/tropism`; MCP `delivery_recommend`;
60
+ manifest `recommend_delivery` and `capsid_fitness`; a `capsid_fitness` scope card; a `delivery` Challenge task
61
+ (serotype to tissue); preregistration `ws_delivery.yaml`.
62
+
63
+ ### Limitations
64
+ - The capsid-fitness model is a one-hot gradient-boosting model, not a protein-LM (it passes the gate; a protein-LM is
65
+ the upgrade path). Capsid-fitness covers AAV only (VLP/LNP data is thinner). In-vivo human tropism is
66
+ a known-unknown except for the approved-therapy priors; novel capsids abstain on tropism. alpha-retro-VLP is exploratory.
67
+
68
+ ## [6.10.4] - 2026-06-20 - Chromatin incremental-value test (annotation, not a re-ranker)
69
+
70
+ This patch closes out the chromatin work. v6.10.3 validated accessibility as a moderate standalone
71
+ predictor; v6.10.4 tests whether it adds incremental value on top of the CRISOT sequence score, i.e. whether
72
+ it should re-rank.
73
+
74
+ ### Added
75
+ - **Incremental-value analysis** (`scripts/offtarget_chromatin_incremental.py`; result in
76
+ `benchmarks/offtarget/chromatin_incremental.json`). On GUIDE-seq (HEK293T-matched), per off-target CRISOT plus
77
+ accessibility: (A) a conditional logistic regression `active ~ z(CRISOT) + z(accessibility)` and (B) a
78
+ leave-one-guide-out held-out AUPRC of CRISOT-only vs a CRISOT+accessibility combiner, tested at two candidate
79
+ imbalances (1:16 and a realistic 1:123). Result: accessibility carries a small, real conditional signal
80
+ (coef ~0.35, bootstrap CI excludes 0 at both imbalances) but adds no held-out ranking improvement over CRISOT
81
+ (AUPRC gap CI includes 0 at both: -0.0025 [-0.011, +0.005] and +0.0027 [-0.014, +0.021]).
82
+
83
+ ### Decision
84
+ - Chromatin is a validated annotation, not a re-ranker. The CRISOT sequence score already captures the
85
+ practically-relevant nomination ranking; a CRISOT+accessibility combiner does not improve held-out AUPRC, so it is
86
+ not wired into the numeric risk score (`CHROMATIN_VALIDATION.changes_numeric_risk_score = False`). The fitted
87
+ combiner coefficients are recorded but intentionally not applied. Ledger and docs updated.
88
+ - This completes the chromatin context work (v6.10.1 wired it, v6.10.2 cross-cell weak, v6.10.3 cell-type-matched
89
+ validated moderate, v6.10.4 incremental tested, annotation-only). Nothing about chromatin remains open or
90
+ undisclosed.
91
+
92
+ ## [6.10.3] - 2026-06-20 - Chromatin context: cell-type-matched validation (validated, moderate)
93
+
94
+ This patch settles the chromatin test. v6.10.2's controlled experiment was ambiguous (GUIDE-seq positive, TTISS
95
+ reversed) on a cross-cell-type K562 proxy; v6.10.3 re-runs it with a cell-type-matched track.
96
+
97
+ ### Added / changed
98
+ - **Cell-type-matched validation** (`scripts/offtarget_chromatin_matched.py`; result in
99
+ `benchmarks/offtarget/chromatin_validation.json` phase2). Downloaded the matched ENCODE HEK293T DNase-seq track
100
+ (`ENCFF529BOG`; HEK293T matches GUIDE-seq's HEK293 and TTISS's HEK293T), queried it at each off-target's 1 kb bin
101
+ (pyBigWig), and recomputed the AUROC. Cell-type matching lifts the canonical WT-Cas9 cell-based assay GUIDE-seq
102
+ from AUROC 0.58 (cross-cell K562) to 0.671 (matched, CI [0.642, 0.701]); the in-vitro negative control stays null
103
+ (0.494). The cross-cell proxy was dampening a real effect.
104
+ - Verdict: chromatin is validated (moderate, cell-type-matched) for WT-Cas9 cell-based off-target activity
105
+ (`offtarget_data.CHROMATIN_VALIDATION` now `validated=True`, `effect="moderate"`). The caveats, all in-code and
106
+ in the docs: the effect is moderate (the sequence/CRISOT score still dominates nomination); it does not
107
+ transfer to TTISS (0.383, the expected outlier, a Cas9-variant specificity assay driven by variant fidelity, not
108
+ WT chromatin); and chromatin is still surfaced as a validated annotation that does not yet change the numeric
109
+ risk score (a calibrated CRISOT+accessibility combination is the remaining, deferred refinement).
110
+ - Reclassified the chromatin axis from "weak/inconsistent" to "validated (moderate, cell-type-matched)" with the
111
+ matched evidence and the caveats.
112
+
113
+ ## [6.10.2] - 2026-06-20 - Chromatin context: controlled validation (weak/inconsistent result)
114
+
115
+ This patch validates the chromatin axis, then scopes it to what the data supports. v6.10.1 wired a real
116
+ Stage B accessibility read but had not demonstrated it carries signal. v6.10.2 runs a controlled experiment and
117
+ reports the result: it is not a clean win.
118
+
119
+ ### Added
120
+ - **A controlled chromatin validation** (`benchmarks/offtarget/chromatin_validation.json`,
121
+ `scripts/offtarget_chromatin_validation.py`). Off-target protospacers mapped to hg38 (GRCh38.fa, exact match both
122
+ strands, 98.5% mapped); AUROC of the Stage B K562 ATAC/DNase accessibility for active-vs-inactive off-targets per
123
+ assay, with in-vitro assays as a negative control (cell-free, so no chromatin). Result: the in-vitro controls hug
124
+ 0.5 (method sound, no spurious signal); the canonical cell-based assay GUIDE-seq is a textbook modest positive
125
+ (AUROC 0.58, CI [0.550, 0.613]) even with a cross-cell-type K562 proxy; but the second cell-based assay TTISS
126
+ reverses (0.346). Verdict: weak and inconsistent, chromatin is not a validated quantitative axis on this data
127
+ (the cross-cell-type proxy is the likely cause; a cell-type-matched accessibility track would settle it, deferred).
128
+
129
+ ### Changed
130
+ - The chromatin-accessibility modifier is now an explicit annotation only, labelled `validated=false`: it reads
131
+ the real Stage B track (or a caller-supplied scalar) and notes the qualitative Lazzarotto-2020 direction, but it
132
+ does not change the numeric off-target risk score. `offtarget_data.CHROMATIN_VALIDATION` carries the result.
133
+ - Corrected the v6.10.1 entry that had marked chromatin "FIXED"; that was too strong. It is now recorded as
134
+ tested, weak/inconsistent, documented annotation, not a validated axis.
135
+
136
+ This is a negative result reported in full.
137
+
138
+ ## [6.10.1] - 2026-06-20 - Off-target rigor pass and retroactive audit (v6.7-v6.9)
139
+
140
+ This patch completes the Stage E plan and documents every remaining deviation. It closes the v6.10.0 gaps and
141
+ re-audits v6.7/v6.8/v6.9 (plan vs shipped vs code) and corrects the findings. No item is reported complete if it
142
+ is a silent substitution, partial, or deferral.
143
+
144
+ ### Added / changed (Stage E completion)
145
+ - **Off-Target-Bench expanded to four unbiased assays.** Added CHANGE-seq (Lazzarotto 2020, `10.1038/s41587-020-0555-7`)
146
+ and SITE-seq (Cameron 2017, `10.1038/nmeth.4284`) on independent broad guide panels (20 and 11 guides). The real
147
+ CRISOT-Score (MD-physics, assay-agnostic so leakage-clean) beats the homology baseline on all four:
148
+ AUPRC 0.646/0.520/0.541/0.521 vs 0.467/0.266/0.249/0.233; per-guide bootstrap CI excludes 0 on each.
149
+ - **Chromatin wired to the real Stage B track and relabelled.** `locus_accessibility(chrom, bin, ct)` reads
150
+ `phase_1/features/chromatin_{ct}.parquet` (ATAC/DNase) when present and abstains otherwise; the docs now say
151
+ "chromatin-accessibility modifier" (not "chromatin-aware engine"), since the bare wheel and the deployed atlas do not ship the
152
+ raw track, so the modifier is inactive there.
153
+ - **Off-target task added to the Genome-Writing Challenge** (`benchmarks/genome_writing_challenge/harness.py`):
154
+ non-circular (label = wet-lab Active call), data-gated on the fixture; the reference solver nominates correctly.
155
+ - **Substitutions:** CRISOT is used instead of the plan-named CCLMoff/CRISMER (CRISMER ships no license;
156
+ CCLMoff is GPU and trained on these assays, so it leaks; CRISOT is the leakage-clean, license-clean, CPU choice). A
157
+ genomic-coordinate locus split is not possible (harmonized data is coordinate-free), so held-out-guide and cross-assay are used.
158
+
159
+ ### Fixed (retroactive audit)
160
+ - **v6.9:** dropped the inaccurate "OOD-gated" claim in the MHC-II axis status (it is coverage-gated, abstains
161
+ when uncached, with no distributional OOD gate); corrected the stale `AXIS_STATUS["mhc2_writer"].reason` and the
162
+ `immune_mhc2.py` module docstring (they still described the dropped v6.9.0 P1-anchor proxy as "the method"; the
163
+ production axis is the real NetMHCIIpan-4.0). The plan-named MHC-II tool ensemble and the IEDB/ImmunoSeq/FVIII
164
+ ADA datasets were not used (single-tool NetMHCIIpan-4.0; the recovery bench is a 4-protein sanity check, not an
165
+ IEDB held-out leaderboard); the 6.9.1 to 6.9.2 MHC-II metric changed from peptide-fraction to residue-coverage.
166
+ - **v6.8:** v6.8.0's attB was a poly-G/C schematic (replaced with the real Bxb1 attB in v6.9.2);
167
+ inter-curator agreement is N/A (single contributor); "at least 1 external submission" is unmet (forward-looking).
168
+ - **v6.7:** corrected the "chromosome-Mondrian" served-interval wording (per-chromosome Mondrian qhats are computed,
169
+ but the global qhat is served, which is correct since a query has no chromosome at serve time); recorded the prereg
170
+ consolidation and the deferred HEK293T-OOD demo / scope-manifest entry.
171
+
172
+ ## [6.10.0] - 2026-06-20 - Cross-writer-family off-target nomination
173
+
174
+ Off-target moves from a single-family bridge pseudosite scan to a cross-writer-family,
175
+ chromatin-aware nomination engine grounded in unbiased genome-wide assays, completing the safety triad
176
+ (site B, writer C, off-target E). Nomination is framed as not a clearance: every candidate
177
+ ships with the empirical assay that would confirm it.
178
+
179
+ ### Added
180
+ - **Off-Target-Bench** (`benchmarks/offtarget/`): a real, leakage-controlled nomination benchmark over canonical
181
+ Cas9 guides (EMX1/VEGFA1-3/FANCF/HEK293) with experimentally validated off-targets from GUIDE-seq
182
+ (Tsai 2015, `10.1038/nbt.3117`) and CIRCLE-seq (Tsai 2017, `10.1038/nmeth.4278`). Held-out-guide split, per-assay
183
+ provenance, SHA256SUMS. On real data with a real tool, the licensed CRISOT-Score predictor
184
+ (Chen et al., Nat Commun 2023, `10.1038/s41467-023-42695-4`; XGBoost RNA-DNA fingerprint) beats the sequence-
185
+ homology baseline: GUIDE-seq AUPRC 0.646 vs 0.467 (gap +0.179, CI [0.015, 0.340]); CIRCLE-seq 0.520 vs
186
+ 0.266 (gap +0.253, CI [0.140, 0.361]); per-guide bootstrap CI excludes 0 on both assays.
187
+ - `pen_stack/wgenome/offtarget_data.py`: validated assay/predictor provenance, a grounded mismatch-to-active-fraction
188
+ risk calibration (real-data: GUIDE-seq 0-1mm to 100% active, 2mm to 76%, 3mm to 23%, 4mm to 3.3%), the bench fixture loader.
189
+ - `pen_stack/wgenome/offtarget_predict.py`: `nominate_offtargets(writer_family, ...)`. Nuclease (mismatch-
190
+ calibrated risk band plus the real cached CRISOT score plus a documented chromatin modifier, Lazzarotto 2020);
191
+ serine integrase (cryptic pseudo-attB scan on the real documented Bxb1 attB core GCGGTCTC/GT);
192
+ bridge (delegates to the existing Perry-DMS pseudosite engine). Abstains without inputs; never fabricates sites.
193
+ - `pen_stack/wgenome/offtarget_assay.py`: validation-assay recommender (GUIDE/CHANGE/CIRCLE-seq for nucleases;
194
+ Cryptic-seq/HIDE-seq for integrases; a documented gap for bridge recombinases, since no published genome-wide
195
+ unbiased off-target assay or predictor exists, verified).
196
+ - **Surfaces:** REST `POST /offtarget` and `GET /offtarget/assay`; MCP `offtarget_scan`; manifest `nominate_offtargets`
197
+ (fabricates=False); an `offtarget_nomination` scope card; and a web Off-Target page.
198
+
199
+ ### Limitations
200
+ - Nomination is not a clearance; genome-wide candidate enumeration needs the on-VM Cas-OFFinder/genome scan (this
201
+ engine scores, ranks, and risk-bands supplied candidates). The CRISOT predictor is CC-BY-NC: it runs only on the
202
+ VM and its weights are never redistributed; only derived scores are cached (CI-safe). Bridge/integrase off-target
203
+ is data-thin and unmodeled and is flagged extrapolative; IntQuery (Tome Biosciences) is a paper-only reference.
204
+
205
+ ## [6.9.2] - 2026-06-19 - Real-tool rigor pass across the immune and writer axes (no proxies, no heuristics)
206
+
207
+ A top-to-bottom audit replaces every remaining proxy/heuristic in the immune and writer-design stack with
208
+ the real on-VM tool (gold-standard, licensed) or an abstention. No silent fallbacks. All licensed binaries stay on
209
+ the VM; only derived numbers are cached.
210
+
211
+ ### Changed
212
+ - **MHC-I capsid axis re-grounded on NetMHCpan-4.1** (`pen_stack/planner/capsid_epitope_oracle.py`). The primary
213
+ capsid CD8 predictor is now the gold-standard licensed NetMHCpan-4.1 (%Rank_EL<=0.5, residue coverage, 12-allele
214
+ panel; `configs/mhc_epitope_oracle.yaml` `mhc1`); the v5.3 MHCflurry value is kept as an explicit, reported
215
+ cross-check (never silently substituted). Both agree AAV is the least CD8-immunogenic capsid
216
+ (AAV `capsid_immune_score` 0.4585 NetMHCpan / 0.2803 MHCflurry; the predictor disagreement is surfaced, not hidden).
217
+ - **ADA-risk re-grounded** (`pen_stack/planner/ada_risk.py`). `ada_risk = real NetMHCIIpan-4.0 density x foreignness`,
218
+ where foreignness is the protein origin (the authoritative central-tolerance signal). Unknown origin or uncached
219
+ density now abstains (no k-mer guess, no heuristic), replacing the v6.9.0 albumin-only self-tolerance
220
+ heuristic. The real human-proteome 9-mer self-match (computed on the VM over the full UniProt reference
221
+ proteome, 20,431 proteins / 10.4 M 9-mers) is reported as a cross-check: human albumin 1.0 (self), the
222
+ foreign writers (SpCas9/ISCro4/Bxb1) and capsids 0.0 (non-self), a clean self/non-self separation.
223
+ - **MHC-II axis no longer falls back to a production proxy** (`pen_stack/planner/immune_mhc2.py`). `mhc2_epitope_load`
224
+ uses the real NetMHCIIpan-4.0 cache by antigen name and otherwise abstains; the documented promiscuous-binder
225
+ estimate is retained as `mhc2_proxy_estimate` for offline triage only (explicitly labelled, not the production axis).
226
+ - **Real Bxb1 attB written** (`pen_stack/atlas/guide_design.py`). The PASTE/PASSIGE pegRNA 3' extension now writes the
227
+ real documented Bxb1 minimal attB verbatim (FlyBase FBto0000359; Ghosh, Kim & Hatfull, Mol Cell 2003;
228
+ 8-bp common core GCGGTCTC around the central GT crossover) instead of the schematic poly-G/poly-C arms. Integrases
229
+ without a bundled documented site expose only the central core (never a fabricated full sequence).
230
+ - `pen_stack/planner/immune_profile.py`: the writer-as-antigen card surfaces `foreignness`, the real
231
+ `self_match_human_proteome` cross-check, and the MHC-II/ADA backends (this replaces the removed `self_tolerance` field).
232
+
233
+ ### Deviations from the v6.9 pre-registration (`prereg/ws_immune2.yaml`)
234
+ - The pre-registered "1 - self_match_fraction from a human-proteome k-mer filter" foreignness fallback is
235
+ dropped: foreignness is the authoritative origin, and an unknown origin abstains rather than imputing from a
236
+ k-mer match (the real self-match is reported only as a cross-check). This is a stricter rule.
237
+
238
+ ### Data / tests
239
+ - `configs/mhc_epitope_oracle.yaml`: corrected `self_match` (the v6.9.x cache had a FASTA-keying bug that collapsed
240
+ the 20,431-protein proteome to 1 protein, zeroing every self-match including albumin); recomputed correctly on the VM.
241
+ - `tests/unit/{test_ws_immune2,test_ws_epitope,test_ws_writer,test_ws_rel}.py` updated for the abstain semantics,
242
+ the NetMHCpan-4.1 primary capsid value plus MHCflurry cross-check, the real attB, and the 6.9.2 version pins.
243
+
244
+ ## [6.9.1] - 2026-06-20 - Real NetMHCIIpan-4.0 / NetMHCpan-4.1 MHC epitope load (replaces the v6.9.0 proxy)
245
+
246
+ This patch is a rigour upgrade. v6.9.0's MHC-II axis was a documented heuristic proxy (P1-anchor density). The
247
+ gold-standard licensed predictors were already on the VM, so v6.9.1 computes the MHC-II epitope load with real
248
+ NetMHCIIpan-4.0 (and MHC-I with NetMHCpan-4.1) over a frequent HLA panel, and re-grounds the axis on the real
249
+ values. The licensed binaries are never committed or distributed; only the derived fractions are
250
+ cached (`configs/mhc_epitope_oracle.yaml`), exactly like the v5.3 MHCflurry cache.
251
+
252
+ ### Changed
253
+ - `pen_stack/planner/immune_mhc2.py`: `mhc2_epitope_load(seq, name)` now uses the real NetMHCIIpan-4.0 EL
254
+ %Rank<=2 cache (over 7 frequent HLA-II alleles) when the antigen is cached; the documented promiscuous-binder
255
+ proxy remains only as the offline/CI fallback for uncached sequences. `real_mhc2_load(name)` exposes the cache.
256
+ - `ada_risk`, `immune_profile` (writer-as-antigen), and `benchmarks/immuno` thread the antigen name to real values.
257
+ - `configs/mhc_epitope_oracle.yaml` (committed): derived epitope fractions for the writer and capsid antigens.
258
+
259
+ ### Result (the real tool is more discriminating than the proxy)
260
+ - Real NetMHCIIpan-4.0 strong-binder fraction: SpCas9 0.153, Bxb1 0.152, ISCro4 0.112, AAV2 0.114 vs
261
+ human albumin (self) 0.066, the lowest. The gold-standard tool shows the self protein has a genuinely lower
262
+ MHC-II load and the foreign writers higher, a signal the heuristic proxy flattened (~0.08-0.10 for all). The
263
+ immunogenic-vs-tolerated recovery is unchanged (foreign well above self) but now on real predictions.
264
+
265
+ ### How it ran (no host install; per the VM Docker rule)
266
+ - `penmhc:tools` (debian + tcsh + gawk + perl) with `~/netmhc` (the licensed tools) mounted, NMHOME fixed at
267
+ runtime; `scratch/v691_mhc_compute.py` runs both predictors and writes the derived cache. The axis stays a
268
+ population-level proxy (frequent-HLA panel, not a patient-HLA magnitude, a known-unknown).
269
+
270
+ ## [6.9.0] - 2026-06-20 - Immune profile: MHC-II/CD4, ADA, and writer-as-antigen
271
+
272
+ This minor feature release extends the immune profile from CD8/MHC-I-only to a full T-cell profile: MHC-I plus
273
+ MHC-II/CD4 plus ADA risk with self-tolerance filtering, scored over the writer enzyme as a distinct antigen,
274
+ still population-level, OOD-gated, and never collapsed. It wraps the v5.6 unified profile. No fabrication: real
275
+ UniProt sequences, a grounded documented method, proxy-labelled axes.
276
+
277
+ ### Added: the MHC-II and ADA axes
278
+ - `pen_stack/planner/immune_mhc2.py`: a grounded, dependency-free promiscuous MHC-II binder density (documented
279
+ P1 hydrophobic anchor, Stern & Wiley 1994; secondary pockets, Southwood 1998) over capsid and writer sequences plus
280
+ the bundled real writer/control FASTA. `configs/writer_sequences.fasta`: real UniProt for SpCas9 (Q99ZW2), ISCro4
281
+ bridge recombinase (D2TGM5), Bxb1 integrase (Q9B086), human albumin self control (P02768).
282
+ - `pen_stack/planner/ada_risk.py`: ADA-risk = MHC-II epitope density x foreignness with a JanusMatrix-style
283
+ self-tolerance filter (origin authoritative; human-proteome k-mer filter otherwise). It recovers
284
+ immunogenic-vs-tolerated: foreign writers score above the human self control (clean separation).
285
+
286
+ ### Changed: the unified profile
287
+ - `pen_stack/planner/immune_profile.py`: adds `mhc2_writer` and `ada_writer` axes and a `writer_as_antigen` card
288
+ with `dominant_antigen` and `writer_dominant_risk` (which fires for a foreign writer, especially non-viral delivery
289
+ where there is no capsid antigen). `collapsed_score` stays `None` (asserted). `immune_calibration.AXIS_STATUS`
290
+ registers the two new axes as mechanistic/population proxies.
291
+
292
+ ### Added: Immuno-Bench and calibration
293
+ - `benchmarks/immuno/harness.py`: the immunogenic-vs-tolerated recovery track (non-circular: label = protein
294
+ origin) plus a `calibrate_axis` ADA pass that remains a proxy at public-data power (no manufactured validation).
295
+ - `tests/unit/test_ws_immune2.py` (CI-safe; pure-Python method plus committed sequences). `prereg/ws_immune2.yaml`.
296
+
297
+ ### Limitations
298
+ - Every axis is a population-level proxy, never a patient-specific ADA titer or realized CD4 magnitude (known-
299
+ unknowns). The MHC-II method is sequence-intrinsic presentation potential, not a trained allele-specific predictor.
300
+ The self-tolerance k-mer filter is seeded by the bundled human reference (the full human proteome is substitutable on the
301
+ VM); the authoritative foreignness signal is the protein origin. Axes are a vector, never fused.
302
+
303
+ ## [6.8.0] - 2026-06-20 - Cross-family writer-efficiency engine and Writer-Efficiency Bench
304
+
305
+ This minor feature release upgrades Stage C (pick the writer) from a curated-KB ranking to a prediction plus
306
+ design layer: the first curated writer-efficiency benchmark, a learned cross-family efficiency predictor,
307
+ integrated guide/att design, and serine-integrase variant critique. It wraps the Writer Atlas and v4.0 writer-verification.
308
+ No fabrication: every efficiency is a real published number with a DOI and a verbatim quote.
309
+
310
+ ### Added: the curated dataset and benchmark
311
+ - `pen_stack/atlas/writer_efficiency.py` plus `data/writer_efficiency.parquet` (SHA-locked): ~45 records / 9 DOIs /
312
+ 4 families, each row with a DOI, a verbatim quote, and a source-access grade (39 pmc_verbatim, 1 abstract, 5 secondary).
313
+ Sources: PASTE (Yarnall *Nat Biotechnol* 2023), (ee)PASSIGE (Pandey/Liu *Nat Biomed Eng* 2025), hyperactive
314
+ integrases (Hew *Nucleic Acids Res* 2024 e64), evoCAST (*Science* 2025), ShCAST (*Science* 2019), enIS621
315
+ (*Nat Commun* 2026), ISCro4 (*Science*).
316
+ - `benchmarks/writer_efficiency/`: the Writer-Efficiency Bench, a sealed, SHA-locked held-out-family plus
317
+ held-out-locus track set plus a baseline leaderboard plus a submission harness. `docs/cards/writer_efficiency_data.md`.
318
+
319
+ ### Added: the learned predictor and the gate
320
+ - `pen_stack/atlas/writer_predict.py`: interpretable-feature HistGradientBoosting plus a family-blocked split-conformal
321
+ interval, candidate-flagged. The pre-registered gate: it beats the KB family-mean baseline on held-out
322
+ locus (MAE 11.7 vs 15.2, paired-bootstrap CI excludes 0; rho +0.38 vs -0.26) and ranks families better on
323
+ held-out family (rho +0.52 vs -0.20), but the held-out-family MAE gain is not significant at N=42/4-families, so
324
+ the KB ranking is retained as primary, the predictor ships candidate-flagged, and the dataset plus bench are the
325
+ contribution. The negative is reported.
326
+
327
+ ### Added: guide design and variant critique
328
+ - `pen_stack/atlas/guide_design.py`: bridge-RNA TBL/DBL loops (Durrant 2024), pegRNA+attB (Yarnall 2023; Bxb1
329
+ core GT), orthogonal att-pair selection (Roelle 2023 GA/GT), with round-trip and invariant recovery tests.
330
+ - `pen_stack/design/writer_variants.py`: extends v4.0 writer-verification to serine-integrase hyperactive mutants
331
+ (Hew 2024 / Keravala 2009); recovers Bxb1 `c22` and PhiC31 P2/P3 retrospectively; defers the
332
+ LM-vs-conservation blind claim (LM naturalness is not engineered hyperactivity).
333
+
334
+ ### Added: the recommender surface
335
+ - `pen_stack/atlas/writer_recommend.py` plus manifest tool `recommend_writers`: ranks families (KB-grounded primary)
336
+ plus candidate predicted efficiency with a conformal interval plus an auto-designed guide. Efficiency is never extrapolated
337
+ to a family absent from the dataset (KB-only there).
338
+
339
+ ### Limitations
340
+ - Predicted efficiencies are candidates with intervals, never asserted activity. 4 families is the binding
341
+ statistical limit, reported. Range efficiencies stored as midpoints (raw string retained);
342
+ secondary-source rows flagged and droppable (strict subset).
343
+
344
+ ## [6.7.0] - 2026-06-19 - Learned, trained-conformal Stage H and TPE-Bench
345
+
346
+ This minor feature release upgrades the digital twin's Stage H expression/outcome layer from a validation-failing
347
+ closed-form heuristic to a learned, trained-conformal, decomposable position-effect model, and ships the
348
+ held-out benchmark the expression capability never had. Wrap, don't rebuild: it extends `twin`, `wgenome.uncertainty`,
349
+ `wgenome.ood`, and `benchmarks`. No fabrication: every metric is from a real CV run on real TRIP supervision, and
350
+ the cross-cell-type transfer claim is data-gated, never faked.
351
+
352
+ ### Added: the learned model and trained conformal
353
+ - `pen_stack/twin/data/position_effect.py`: a unified position-effect schema plus a dataset registry with verified
354
+ accessions/DOIs (TRIP live; PatchMPRA/MPIRE/lentiMPRA/Leemans registered and recorded `available=False` until
355
+ fetched), z-normalization within (dataset x cassette), domain-blocked plus held-out-cell-type splits, a leakage check.
356
+ - `pen_stack/twin/position_effect.py`: `PositionEffectModel` (factored `f_cassette` plus `g_context`, LightGBM),
357
+ `evaluate()` (chromosome-blocked CV vs the v3.x durability head plus cassette-only, paired-bootstrap CIs,
358
+ separability), split-conformal calibration (`ConformalRegressor`, chromosome-Mondrian, OOD-widened),
359
+ `predict_stage_h()` serving seam. Result (real TRIP): expression rho 0.428 to 0.469 (CI excludes 0);
360
+ held-out conformal coverage 0.885 vs 0.90 nominal.
361
+ - `configs/twin/position_effect_conformal.json`: the shipped calibration (qhat plus N plus held-out coverage).
362
+ - `scripts/p1_build_position_effect.py`: regenerates the model plus conformal artifacts (real CV report).
363
+
364
+ ### Changed: Stage H integration
365
+ - `pen_stack/twin/outcome.py`: when a chromatin context is supplied and the artifact is present, `predict_outcome`
366
+ serves the learned trained-conformal interval plus `p_silenced` plus an OOD tier (`position_effect` block,
367
+ `stage_h_mode`); with no context/artifact it falls back to the heuristic band, backward compatible (the
368
+ v5.9 relative-scale contract is intact).
369
+
370
+ ### Added: TPE-Bench and controls
371
+ - `benchmarks/position_effect/`: TPE-Bench, a sealed, SHA-locked held-out-chromosome track plus a baseline
372
+ leaderboard (cassette-only / durability head / factored). The leave-one-cell-type-out
373
+ transfer track is scaffolded and data-gated (no fabricated transfer number).
374
+ - `pen_stack/validate/{expr_controls,known_biology_expr,heldout_celltype_expr}.py`: a label-shuffle-to-chance control,
375
+ an H3K9me3-heterochromatin-to-silencing recovery, and the data-gated transfer harness.
376
+ - `tests/unit/test_ws_pe.py`: CI-safe (synthetic planted signal); the real-TRIP claim runs on a checkout, skips in CI.
377
+
378
+ ### Limitations
379
+ - Public data cannot flip expression to outcome-validated (the v6.5 wall); v6.7 ships the learned and calibrated
380
+ upgrade plus the benchmark plus the data-gating, not a manufactured result. Cross-cell-type transfer needs the additional
381
+ human datasets (a data-acquisition step), reported as such. Wet-lab validation omitted by scope.
382
+
383
+ ## [6.6.0] - 2026-06-16 - License-clean provenance (COSMIC to CancerMine)
384
+
385
+ This minor release is a provenance refactor: no new science, no capability lost. The shipped artifact now sources the
386
+ oncogene/TSG/driver list from CancerMine (CC0) instead of COSMIC Cancer Gene Census (free for academia but
387
+ no-redistribution). Copyright protects the compiled database, not the fact that a gene is an oncogene, so
388
+ sourcing the list from a CC0 compilation removes all licensing doubt while keeping the same capability. This is prep for
389
+ the BioFirewall release, whose open repo vendors PEN-STACK's hazard data.
390
+
391
+ ### Changed
392
+ - `pen_stack/data/ingest_safety_annot.py`: `load_cancermine()` (CC0) is the default oncogene/TSG source
393
+ (HUGO to coords via GENCODE, `--min-citations` precision knob); `load_cosmic()` stays available but off by
394
+ default (bring-your-own-license, local enrichment only).
395
+ - `configs/genotoxicity_oracle.yaml`: regenerated from CancerMine; provenance and DOIs updated (CancerMine
396
+ 10.1038/s41592-019-0422-y). `safety_{ct}.pkl` plus the Writable-Genome atlas regenerated on CancerMine features
397
+ (re-deposited on Zenodo, superseding the COSMIC-derived deposit).
398
+
399
+ ### Added
400
+ - **`DATA_LICENSES.md`**: every source by license by redistribution-status by where-used.
401
+ - `tests/unit/test_data_licenses.py`: a CI license gate that fails if a restricted source (COSMIC/OncoKB) is the
402
+ shipped derived-data source or a raw restricted gene-list is committed; CancerMine is the default.
403
+ - `scripts/fetch_licensed_sources.py`: a bring-your-own-license fetcher for COSMIC/OncoKB (local-only, validation).
404
+
405
+ ### Notes
406
+ - Metrics may shift (CancerMine has broader coverage than CGC), reported. The genotoxicity axis is a
407
+ mechanism-grounded proxy (not outcome-validated) before and after; the swap changes only the source.
408
+
409
+ ## [6.5.0] - 2026-06-15 - Comprehensive expression model and proxy-validation pass
410
+
411
+ This minor feature release has two threads, one principle (no fabrication):
412
+
413
+ ### Added: a comprehensive, literature-cited expression model
414
+ - `configs/expression/promoters.yaml`: the twin's promoter palette expands from 5 to 31 promoters (constitutive plus
415
+ tissue-specific: liver TBG/LP1/hAAT, neuron hSyn/CaMKIIa, muscle MHCK7/MCK/CK8, astrocyte GfaABC1D, SFFV/MND/
416
+ MSCV/RSV, and more). Each entry carries `strength` plus context plus assay plus citation plus confidence, because promoter
417
+ strength has no universal scalar (it depends on cell type by vector by readout), so a single number is encoded
418
+ with its context, never as a universal truth.
419
+ - `configs/expression/modifiers.yaml`: a modifier layer (WPRE, intron, polyA, Kozak, codon-optimization/CAI,
420
+ CpG-silencing) as literature priors/ranges, applied as a bounded uplift range (never a point multiplier, since
421
+ the chimeric intron is ~20x for one transgene, ~3x for another). `twin/mechanistic.py` consumes both.
422
+
423
+ ### Added: a proxy-to-outcome validation harness
424
+ - `scripts/calibrate_immune_axes.py` plus `configs/calibration/preexisting_nab_independent.yaml`: runs the existing
425
+ `calibrate_axis` gate (N>=6 AND bootstrap Spearman CI excludes 0) against independent measured data.
426
+
427
+ ### Result (the deliverable)
428
+ - No immune or expression axis flips to outcome-validated. Pre-existing NAb tested vs an independent cohort
429
+ (Navarro-Oliveros 2024, Basque): rho=0.12, CI includes 0, geography-dependent. Relative-expression tested vs an
430
+ independent promoter study (Damdindorj 2014): rho=0.12, CI includes 0, promoter strength is context-dependent
431
+ (Damdindorj found CMV strongest; Qin found the opposite). Genotoxicity (3 vectors), CD8 (5 capsids), anti-PEG
432
+ (1), and innate (0 fixed) are structurally below the N>=6 gate. The labels stay proxy with empirical backing;
433
+ flipping them would require measured-outcome data at a statistical power the public literature does not provide.
434
+
435
+ ### Tests
436
+ - `tests/unit/test_ws_express.py`: the palette is comprehensive and cited; context is encoded; the modifier profile is a
437
+ bounded range; the proxy does not falsely claim cross-study validation (the no-fabrication gate holds).
438
+
439
+ ## [6.4.3] - 2026-06-12 - Chat vehicle-parse fix (AAVS1 no longer hijacks the vehicle)
440
+
441
+ This patch fixes a parsing bug. `web/tools.py::parse_goal` matched the delivery vehicle by substring, so the safe-harbour nickname
442
+ AAVS1 (which contains "aav") wrongly selected the AAV vehicle even when the user said lentivirus or
443
+ LNP, producing the wrong immune profile (e.g. genotoxicity 1.0 instead of lentivirus's 0.481). Fix: strip the
444
+ safe-harbour nicknames (AAVS1/H11/HIPP11/ROSA26) from the vehicle-search text before matching, so the user's
445
+ stated vehicle wins. Explicit "AAV" still selects AAV. A new test locks all three cases.
446
+
447
+ ## [6.4.2] - 2026-06-12 - Co-Scientist chat: real writer recommendations and self-explanatory values
448
+
449
+ This patch fixes a stale/confusing chat experience reported from the live app. Three problems, three fixes:
450
+
451
+ 1. **The chat dossier was generic and barely changed per query.** `web/tools.py::parse_goal` hardcoded
452
+ `chrom="chr19"` (so a goal about ITGB2, chr21, was mis-located) and `run_tools` never called the planner,
453
+ so a "which writer can integrate N kb in GENE" question got a vehicle-keyed immune profile but no named
454
+ writer. Fix: `parse_goal` now resolves the gene's real chromosome (`planner.gene_region`, atlas-gated,
455
+ falls back offline), and `run_tools` runs the planner and attaches a `plan` block: the recommended writer
456
+ family, top site, safety/durability/score, cargo-capacity fit, and delivery, all engine-computed. It says so
457
+ when the gene isn't in the atlas ("not found, check the HGNC symbol"); never fabricated.
458
+ 2. **The LLM narration produced `[unverified]` spam.** With no writer in the tool results, the model invented
459
+ one (`AAV9-CRISPR` plus made-up numbers) and the grounding guard struck them all. Fix: the system prompt now
460
+ forbids inventing a writer/vehicle/table/number, and if the guard still strikes 2 or more numbers the reply falls
461
+ back to the fully-grounded deterministic narration, so the spam never reaches the user.
462
+ 3. **Values and the "extrapolating" badge weren't self-explanatory.** Each immune axis now carries a
463
+ plain-language `meaning` ("0.55 on a 0-1 scale, moderate; higher = fewer patients excluded; this is a
464
+ proxy, not validated against a measured outcome"), the deterministic narration uses it, and
465
+ `ImmuneProfileCard` renders it plus a one-line legend explaining that "extrapolating" means a proxy estimate.
466
+
467
+ ### Added
468
+ - `tests/unit/test_ws_chat.py`: chrom resolution, axis-meaning, real writer plan, and the no-`[unverified]`-spam
469
+ fallback are locked by new tests.
470
+
471
+ ## [6.4.1] - 2026-06-12 - Defence-in-depth: pre-route safety screen
472
+
473
+ This patch closes a screening gap. The grounded co-scientist chat ran the Guardian (biosecurity gate) only in the design lane (via
474
+ `run_tools`); a hazardous request with no design signal (no vehicle/locus) routed to `general`/`explain`/`meta`
475
+ and was never screened. Fix: `pen_stack/web/llm.py::_pre_route_safety` runs the Guardian, framing-stripped, the
476
+ authority on the decision, at the top of `grounded_reply()`, before lane routing. A `refuse`/`escalate`
477
+ verdict short-circuits to a clear decline (`mode="safety"`, with the decision in `tool_results`). Benign
478
+ hazard-adjacent biology (vaccines, generic pathogen questions) is not blocked: the Guardian clears it and
479
+ routing continues. A broad regex only decides whether to invoke the Guardian; a false trigger is harmless.
480
+
481
+ ### Added
482
+ - `tests/unit/test_ws_chat.py`: `test_pre_route_safety_screens_a_hazardous_general_query` and
483
+ `test_pre_route_safety_does_not_over_refuse_benign_questions` lock both sides of the screen.
484
+
485
+ ## [6.4.0] - 2026-06-12 - Live Oracles (the foundation models actually execute)
486
+
487
+ The oracle mesh goes live. The foundation-model adapters that were deferred contracts now run real backends,
488
+ without touching the no-fabrication invariant (generated outputs stay candidates, OOD inputs are flagged, a down
489
+ backend defers). Live execution is opt-in via `PEN_STACK_ORACLE_NET=1`; with the flag unset (CI/offline) every
490
+ oracle behaves exactly as before. This is a minor feature release on the stable 6.x API.
491
+
492
+ ### Added: live oracles
493
+ - **Evo2-40B (hosted):** `oracles/genome.py::generate_dna` calls NVIDIA's hosted Evo2-40B (real generated DNA plus
494
+ per-token probability). ~1-3 s.
495
+ - **AlphaGenome (hosted):** `oracles/genome.py::variant_effect` connected to the existing v3.1
496
+ `wgenome.AlphaGenomeProvider` (added `score_variant`; no duplicate client), a real regulatory variant-effect
497
+ magnitude. ~2-10 s. (AlphaGenome already ran live in v3.1 for expression/tracks/contact, 416 cached predictions.)
498
+ - **ProteinMPNN / ESM3-open / RFdiffusion (local GPU):** `model_servers/{proteinmpnn,esm3,rfdiffusion}` small
499
+ FastAPI servers on the VM GPU (reuse `penstack:phase1.5` / `rfdiffusion:base`); `oracles/protein_design.py`
500
+ HTTP-calls them. ProteinMPNN ~1-9 s, ESM3 ~1-2 s warm, RFdiffusion ~1-2 min. `docker-compose.models.yml` starts
501
+ them on demand.
502
+ - **Execution and latency surface:** `configs/oracles/execution.yaml` plus `oracles/status.py` (`oracle_status`,
503
+ `summary`) plus `GET /oracles` plus the chat meta facts: per-oracle execution, latency class
504
+ (instant/seconds/slow/long_job), and live status, so the assistant states the cost before running anything.
505
+
506
+ ### Held / deferred
507
+ - **AlphaFold3, Boltz-2, Chai-1, Protenix:** held, they need a rented A100/H100 (24-80 GB; AF3 also ~1 TB
508
+ databases). They run separately on cloud, never on the 16 GB VM and never in the request path.
509
+ - **Arc STATE / scGPT:** the package is verified installable (`pip install arc-state`; SE-600M embeds cells), but a
510
+ trustworthy perturbation outcome needs the State-Transition model plus a reference scRNA pipeline, and even
511
+ SOTA doesn't beat naive baselines (Arc VCC), so the magnitude stays a known-unknown, deferred
512
+ (a uniform gated hook is added via `PEN_STACK_VCELL_URL` for when an ST server is stood up).
513
+
514
+ ### Verified on the VM (RTX A4000)
515
+ Evo2-40B generation ~1.2 s; AlphaGenome variant score `chr22:36201698 A>C` max|effect| 3.15 over 14,652 tracks
516
+ in 3.6 s; ProteinMPNN designed real ubiquitin-fold sequences (global_score ~0.80) in ~9 s; ESM3-open completed the
517
+ ubiquitin sequence from a partial prompt in 1.4 s warm; RFdiffusion diffused a real 60-residue backbone in ~105 s.
518
+ All generated outputs remain candidates (`as_claim()` raises).
519
+
520
+ ## [6.3.1] - 2026-06-12 - Router fix: general "how does it work" no longer misrouted to the meta lane
521
+
522
+ This patch corrects routing. It was found by a full-stack test pass (every oracle plus every endpoint plus the 4
523
+ chat lanes plus general/biological-intelligence questions).
524
+
525
+ ### Fixed
526
+ - **Router meta-lane over-capture.** A general-biology question phrased "and how does it work / cut DNA?"
527
+ (e.g. *"what is CRISPR-Cas9 and how does it cut DNA?"*) matched the meta pattern `how (do|does) (you|it|this|pen)`
528
+ and was answered from PEN-STACK capability facts instead of general knowledge. Narrowed the bare-pronoun meta
529
+ trigger to `how (do|does) (you|pen)` so a general "how does it ..." routes to the general lane (labelled,
530
+ with an engine pointer); a pen-stack-scoped "how do you compute X" stays meta (the verb-qualified pattern is
531
+ unchanged). Regression cases added to `tests/unit/test_ws_chat.py::test_router_classifies_the_four_lanes`.
532
+
533
+ ### Verified (v6.3 test pass)
534
+ - **Oracle mesh (42/42, engine-direct):** ViennaRNA computes a real MFE fold (-38.3 kcal/mol); AlphaGenome,
535
+ Evo2, vcell (Arc-STATE), AF3/Boltz/Chai/Protenix, and RFdiffusion/ProteinMPNN/ESM3 either compute or defer
536
+ with the OOD gate plus provenance intact, never fabricate; the generative-candidate `as_claim()` guard
537
+ raises. Computed immune layers reproduce orderings from data: genotoxicity LV 0.481 < gammaretro 0.177
538
+ (LMO2/SCID-X1), capsid AAV 0.28 > Ad 0.18, CpG O/E rich > poor, seroprevalence AAV 0.55 / Ad5 0.35, anti-PEG
539
+ 0.515; full `verify()` clears a clean design, rejects a 7 kb single-AAV (alt lentivirus legal), refuses ricin,
540
+ rejects an RNP-over-AAV, and flags multiplex translocation risk 0.95.
541
+ - **App surface (live, LLM on):** every endpoint 200 plus a grounded shape; the 4 chat lanes route correctly with the
542
+ grounding guard clean on the grounded lanes (0 ungrounded numbers, Nemotron backend).
543
+
544
+ ## [6.3.0] - 2026-06-12 - The Hybrid Co-Scientist (grounded engine plus general intelligence)
545
+
546
+ The chat gains general and biological intelligence without loosening the no-fabrication core. A 4-lane router
547
+ keeps grounded engine output and general trained-knowledge in separate, explicitly-labelled lanes, so a
548
+ general-knowledge fact can never be mistaken for a PEN-STACK result. Numbers now come with their meaning,
549
+ reference range, and how they were computed; the conversation has memory. This is a minor feature release on the stable
550
+ 6.x API, SHA-locked.
551
+
552
+ ### Added
553
+ - A deterministic 4-lane chat surface: `pen_stack/web/router.py` (classifier: `design` / `explain` / `meta` /
554
+ `general`, biased to the engine whenever a design signal is present) plus `pen_stack/web/guide.py`
555
+ (`metric_guide()` interpretation cards plus `pen_stack_facts()` assembled from live engine data) plus a rewritten
556
+ `pen_stack/web/llm.py::grounded_reply` that dispatches per lane and returns `{mode, provenance, grounded, ...}`.
557
+ - **`configs/metric_guide.yaml`:** grounded interpretation for every engine number (genotoxicity, CD8 epitope,
558
+ innate, pre-existing NAb, anti-PEG, confidence, relative expression, and the safety decisions): what it means, the
559
+ scale plus direction, reference bands, how it is computed, and its validation status. The chat now explains a value
560
+ (scale / what's good-or-bad / reference range / method), not just prints it.
561
+ - **Lanes and provenance:** `design`/`explain`/`meta` are engine-grounded (the grounding guard runs over the tool
562
+ results, the metric guide, or the live facts); `general` answers from the LLM's trained knowledge, is labelled
563
+ "General knowledge, not PEN-STACK-verified", attributes no number to PEN-STACK, and points to the engine
564
+ wherever PEN-STACK could compute a concrete answer (`pen_stack_angles`).
565
+ - **Conversation memory:** the last turns are passed to every lane so follow-ups ("what does that 0.55 mean?")
566
+ resolve against the prior dossier; the frontend keeps history in-session until refresh and renders a per-message
567
+ provenance badge (grounded vs general) plus the "PEN-STACK can compute this" pointers.
568
+ - Tests: `tests/unit/test_ws_chat.py` covers the 4-lane router, the general lane labelled/unattributed/pointered, the
569
+ meta lane grounded in live facts, the explain lane interpreting prior values without a fresh design, the metric
570
+ guide complete. Preregistration `ws_hybrid` plus SHA lock; deposit `phase_6.3/`.
571
+
572
+ ### Notes
573
+ - The core is untouched. The guard still runs on every PEN-STACK-attributed number; we added a general lane,
574
+ we did not loosen the grounded lane. The cost is that general-lane answers carry the LLM's fallibility,
575
+ made safe by the explicit label and by redirecting to the engine for anything computable.
576
+
577
+ ## [6.2.4] - 2026-06-12 - Faster grounded narration (LLM backends) (patch)
578
+
579
+ Performance plus a real fix, from benchmarking the narration backends on the deployment GPU (RTX A4000). The
580
+ LLM only narrates over engine tool results (the grounding guard runs regardless), so latency is the thing to
581
+ tune. Measured (real grounded prompt): Ollama qwen2.5:7b = ~50s warm / 120s cold (3.4 tok/s, a workstation
582
+ GPU is slow for an LLM); qwen2.5:3b = ~27s; llama3.2:3b = ~17s; hosted Nemotron-49B = ~5s. All keep the
583
+ grounding guard clean (0 ungrounded). The old Nemotron fallback model (`llama-3.1-nemotron-70b-instruct`) now
584
+ 404s, i.e. the fallback was silently broken.
585
+
586
+ ### Fixed / changed (`pen_stack/web/llm.py`)
587
+ - **Nemotron model corrected** to `nvidia/llama-3.3-nemotron-super-49b-v1` (the 70B name was retired, so the
588
+ fallback 404'd). Restores a working, ~5s hosted backend.
589
+ - **Default local model qwen2.5:7b to qwen2.5:3b-instruct** (~2x faster narration, grounding unchanged).
590
+ - **`keep_alive` (default 30m)** so the model stays resident on the GPU and idle calls don't pay the cold start.
591
+ - **Configurable backend order** `PEN_STACK_LLM_ORDER` (default `ollama,nemotron` = local/private-first;
592
+ `nemotron,ollama` = speed-first ~5s). `web/.env.example` documents all knobs.
593
+
594
+ ## [6.2.3] - 2026-06-12 - Scope matcher covers functional titer and durability (patch)
595
+
596
+ A coverage fix (from the 20-query acceptance suite, `phase_6.2/PEN-STACK_ACCEPTANCE_TESTS.md`). The
597
+ known-unknowns matcher (`configs/known_unknowns.yaml`) had no entry for functional titer / absolute in-vivo
598
+ expression magnitude and its durability terms were too narrow ("how long will it last in a patient"), so
599
+ common measured-endpoint questions ("what functional titer (% of normal)?", "how long will episomal AAV
600
+ expression last?") were not explicitly deferred. The no-fabrication spine already held (no titer/half-life was
601
+ ever emitted, and the immune profile lists `patient_specific_titer`), but the matcher should flag these
602
+ proactively.
603
+
604
+ ### Added / Fixed
605
+ - `configs/known_unknowns.yaml`: a new known-unknown `in_vivo_expression_magnitude` (functional titer / % of normal
606
+ / absolute expression, a measured clinical endpoint, never predicted; PEN-STACK gives the relative mechanistic
607
+ proxy plus immune context); broadened `long_term_clinical_durability` match-terms/patterns to catch "how long will
608
+ ... last/persist", "durability", "half-life". Regression test
609
+ `tests/unit/test_ws_api.py::test_scope_defers_titer_and_durability_questions`.
610
+
611
+ ### Acceptance suite result
612
+ - 20/20 behave as specified at the engine level: grounded where earned, refusing where unsafe (ricin/botulinum),
613
+ abstaining/deferring where appropriate (titer, durability, phenotype), no fabricated number. T10 (RNP/AAV) and T12
614
+ (multiplex translocation) are enforced via `delivery.cargo_form_compatible` and `multiplex.translocation_risk`
615
+ on the structured design fields (`writer_output_form`, `edits`).
616
+
617
+ ## [6.2.2] - 2026-06-12 - Safe-harbour locus-nickname resolution (patch)
618
+
619
+ A usability fix. Site Finder / `/plan` / `/writable` returned 0 plans for `AAVS1` because it is a genomic
620
+ safe-harbour locus nickname, not an HGNC gene symbol, so the gene-to-coordinate lookup (`gene_coords`, 60,888
621
+ symbols) could not resolve it: an empty result, but unhelpful for the most-typed safe harbour. (The cell-type
622
+ atlases are complete; real symbols like `PCSK9`/`HBB`/`CCR5`/`CLYBL` resolved fine.)
623
+
624
+ ### Fixed
625
+ - `pen_stack/planner/optimize.py`: `resolve_gene()` maps well-documented safe-harbour nicknames to their host
626
+ gene (`AAVS1` to `PPP1R12C` 19q13.42; `H11`/`Hipp11` to `EIF4ENIF1` 22q12) at every gene-to-coordinate lookup
627
+ (`gene_region`, `plan`, `crosslink.loci_for_gene`); real symbols pass through unchanged. Regression test
628
+ `tests/unit/test_ws_api.py::test_safe_harbour_nickname_resolves_to_host_gene`.
629
+
630
+ ## [6.2.1] - 2026-06-12 - JSON-safe atlas/crosslink endpoints (patch)
631
+
632
+ A bug fix. The `/atlas`, `/writable`, and `/crosslink/loci` endpoints returned raw DataFrame records, which
633
+ leak non-finite floats (`NaN`/`inf`) present in `atlas.parquet`; the JSON encoder rejects these
634
+ (`ValueError: Out of range float values are not JSON compliant`, so HTTP 500). Surfaced on the v6.2 Web Platform's
635
+ Writer Atlas and Site Finder pages.
636
+
637
+ ### Fixed
638
+ - `pen_stack/server/api.py`: a `_records()` helper serializes DataFrame rows JSON-safely (via pandas `to_json`,
639
+ so `NaN`/`inf` become `null` and numpy scalars become native), applied to `/atlas`, `/writable`, `/crosslink/loci`.
640
+ Regression test `tests/unit/test_ws_api.py::test_records_helper_is_json_safe_with_non_finite_floats`.
641
+
642
+ ## [6.2.0] - 2026-06-11 - The Web Platform (the human surface)
643
+
644
+ A post-1.0 adoption surface for bench scientists. A complete, friendly web application: a grounded co-scientist
645
+ chat plus structured feature pages, over the same typed v6.1 API the AI surface uses. The LLM narrates and
646
+ routes but never sources a number; every quantitative answer renders with its confidence band, provenance, and
647
+ an explicit ledger of what PEN-STACK can't tell you. This is a minor release on the stable 6.0 API, SHA-locked.
648
+
649
+ ### Added
650
+ - **Backend:** `pen_stack/web/server.py`, one FastAPI gateway that mounts the v6.1 engine surface under
651
+ `/api` (so the frontend has one base URL and one OpenAPI) and adds the grounded `/chat` (plus SSE `/chat/stream`),
652
+ CORS, and static serving of the built frontend (`web/dist`). A `/health` for the live grounded indicator.
653
+ - **Chat (the hard gate):** `pen_stack/web/tools.py` (the deterministic engine tool-runner: parse a goal,
654
+ run `verify`/`safety`/`immune_profile`/scope, return a grounded dossier; `extract_grounded_numbers` is the allow-list)
655
+ and `pen_stack/web/llm.py` (the grounded co-scientist: Ollama, then Nemotron, then deterministic narrator, with
656
+ `_enforce_grounding` striking any numeric token the model can't trace to a tool result). A reply's numbers are
657
+ always engine-sourced; `tests/unit/test_ws_chat.py` asserts no number in a reply is absent from the tool
658
+ results, and that the deterministic narrator works with both LLMs offline.
659
+ - **Frontend:** `web/` (React/Vite plus Tailwind): the UX component library (`ConfidenceBand`,
660
+ `ProvenanceChip`, `ScopeLedger`, `SafetyBadge`, `ImmuneProfileCard`), so a number is never shown without its
661
+ uncertainty plus provenance, and the scope ledger appears on every answer.
662
+ - **Pages:** 11 feature pages over the typed API: Co-Scientist, Site Finder, Writer Atlas, Designer,
663
+ Verify, Delivery & Immunity, Digital Twin, Guardian, Experiments, Challenge, Scope & About. Each renders
664
+ through the UX library and degrades gracefully when the LLM is offline.
665
+ - **Deploy:** `docker/web.Dockerfile` (multi-stage: a node:20 stage builds the frontend, a slim Python
666
+ serves UI plus API from one origin) plus a `web` service in `docker-compose.yml`: one-command self-host
667
+ (`docker compose up web ollama`, open `http://localhost:8000`). `web/.env.example`, `web/README.md` quickstart.
668
+ - Read-only Challenge surface for the web page: `GET /api/challenge/{tasks,leaderboard}` (public tasks plus the
669
+ PEN-STACK reference leaderboard; submissions are still scored offline, never accepted over HTTP).
670
+ - Preregistration `ws_{chat,frontend}` plus SHA locks; deposit `phase_6.2/`.
671
+
672
+ ### Notes
673
+ - The LLM never sources a number. It explains, compares, and routes over the engine's tool outputs; the
674
+ grounding guard strips any value it can't trace, and the app runs in a deterministic, no-LLM mode (the science
675
+ lives in the engine, not the model). This cycle improves usability/adoption, not validation; a real-data
676
+ result and a first lab user remain the standing bottleneck. No new science; contracts under the 1.0 commitment.
677
+
678
+ ## [6.1.0] - 2026-06-11 - The AI Integration Surface
679
+
680
+ A post-1.0 adoption surface for AI builders. Not new capability: the introspectable, documented, dependable
681
+ contract that lets an external agent discover what PEN-STACK offers and what it refuses to answer. This is a minor
682
+ release on the stable 6.0 API, SHA-locked.
683
+
684
+ ### Added
685
+ - **Capability and scope manifests (the differentiator):** `pen_stack/api/manifest.py`: `capability_manifest()`
686
+ (machine-readable: the stable tools, inputs/outputs, all `fabricates=False`, guarantees, stability) and `scope_manifest()`
687
+ (machine-readable: the known-unknowns registry plus every oracle scope card, i.e. what PEN-STACK refuses to
688
+ answer). Generated from the live registry/scope cards (never hand-written); internal matcher fields not leaked.
689
+ - **OpenAPI:** `pen_stack/server/api.py`: `GET /capabilities` plus `GET /scope` plus `POST /verify /safety /immune
690
+ /generate /predict /suggest /session`; FastAPI auto-generates the OpenAPI 3.1 spec at `/openapi.json`.
691
+ - **MCP:** `pen_stack/agent/mcp_server.py`: the self-describing resources `pen-stack://capabilities` plus
692
+ `pen-stack://scope`, plus the engine tools (`safety_screen`, `immune_profile`, `generate_designs`,
693
+ `predict_outcome`, `suggest_experiment`, `co_scientist_session`). A hazardous design returns a structured
694
+ refusal an agent branches on.
695
+ - **Examples:** a runnable golden path: `examples/external_agent.py` (REST: discover scope, submit, branch on
696
+ safety/legality), `examples/mcp_client.py` (MCP), `examples/agent_tools.py` (framework-agnostic tool specs built
697
+ from the live manifest plus an in-process dispatcher to the validated engine).
698
+ - Docs: `docs/integrations.md` rewritten as "Integrate PEN-STACK in your AI" (the four guarantees plus the scope
699
+ contract plus REST/MCP/framework quickstarts); preregistration `ws_{manifest,openapi,mcp}` plus SHA locks; deposit `phase_6.1/`.
700
+
701
+ ### Notes
702
+ - Scope is data, not a disclaimer. The scope manifest makes the scope machinery itself an API, the thing
703
+ that makes trustworthy autonomy something another system can build on. This cycle lowers the barrier to
704
+ adoption; it does not, by itself, create it: outreach plus a real result remain the standing bottleneck. No new
705
+ science or validation; contracts versioned plus deprecation-policed under the 1.0 commitment.
706
+
707
+ ## [6.0.0] - 2026-06-11 - 1.0, First Stable (the graduation)
708
+
709
+ The Closed-Loop arc is complete (7/7), and PEN-STACK graduates to "1.0, First Stable." The public API,
710
+ exercised across every surface (verify, safety, generative design, twin, experiment design, build interface,
711
+ closed loop, co-scientist, and the Genome-Writing Challenge), is documented and frozen with a deprecation
712
+ policy. "First Stable" is earned, not declared: it is cut only after the closed loop is demonstrated (v5.12),
713
+ the benchmark is public (v5.13), and the integration surface ships.
714
+
715
+ ### Changed
716
+ - **`Development Status :: 5 - Production/Stable`** (was Beta). Version 6.0.0 (MAJOR).
717
+ - The public API is documented and frozen with a deprecation policy: **`docs/STABILITY.md`** (semver from 6.0.0;
718
+ deprecations warn at least 1 MINOR before removal in a MAJOR; the `OracleResult`/`Verdict`/`SafetyVerdict`/immune-profile
719
+ contracts and invariants, including `collapsed_score is None` and the no-fabrication guard, are stable across 6.x).
720
+ - The Genome-Writing Challenge is public.
721
+
722
+ ### Notes
723
+ - "1.0, First Stable" is a commitment to API stability, not a claim of solving genetic engineering. The
724
+ unknown funnel remains, made legible (scope flags, known-unknowns, baselines, no fabrication), not
725
+ hidden. The high version numbers of the program's fast youth finally meet a real stability commitment.
726
+
727
+ ## [5.13.0] - 2026-06-11 - The Standard (Genome-Writing Challenge plus Co-Scientist II)
728
+
729
+ This cycle aims to make PEN-STACK the field's reference: an open, recurring, held-out benchmark
730
+ others build to, and to give scientists a co-scientist that drives the whole loop with immune-risk first-class.
731
+ SHA-locked. (The v6.0.0 "1.0, First Stable" graduation follows.)
732
+
733
+ ### Added
734
+ - **The Genome-Writing Challenge** (`benchmarks/genome_writing_challenge/`): an open,
735
+ recurring, held-out leaderboard (the CASP / Virtual-Cell-Challenge model). `evaluate(Submission, round_id)`
736
+ scores an external `predict_fn(public_input) -> answer` on a held-out round whose labels it never sees; labels
737
+ are computed by the validated PEN-STACK layers (rules / v5.7 Guardian / v5.6 immune profile) so no task uses a
738
+ circular label; a no-fabrication audit runs on every submission; task families include an immune-risk
739
+ task grounded in the v5.6 oracles. A one-command runner (`run.py`); a reference submission anchors the leaderboard.
740
+ - **The matured co-scientist** (`pen_stack/agent/co_scientist.py::co_scientist_session(goal, cell_state)`)
741
+ drives the whole loop: safe, legal, calibrated designs, then predicted outcomes, then suggested
742
+ experiments, then exportable protocols, returning the Pareto strategies, calibrated `predicted_outcomes`,
743
+ per-axis immune profiles (first-class), `suggested_experiments`, citations (resolve by construction),
744
+ a complete scope ledger, and the per-design safety decision. The scientist/lab decides; the co-scientist
745
+ drives. No number is fabricated; hazardous candidates are discarded.
746
+ - **The integration surface:** MCP server tools, the Challenge submission API, and a worked reference
747
+ example (`docs/integrations.md`). The standing adoption criterion (at least 1 external integration plus at least 1 external
748
+ submission) depends on outreach, the non-code bottleneck flagged since v3.1; the surface is shipped.
749
+ - Docs: `docs/{challenge,co_scientist_loop,integrations}.md`; preregistration `ws_{challenge,cosci2}` plus SHA locks; deposit
750
+ `phase_5.13/`.
751
+
752
+ ### Notes
753
+ - A standard requires a community: PEN-STACK provides the open, reproducible, held-out benchmark and the
754
+ integration surface; adoption depends on outreach. The co-scientist drives and presents (including the
755
+ immune-risk profile with its known-unknowns); the scientist and lab decide.
756
+
757
+ ## [5.12.0] - 2026-06-11 - The Closed Loop (autonomy Level 3)
758
+
759
+ This release integrates everything into one continual design/build/test/learn cycle,
760
+ humans/lab in control, no fabrication, drift-aware. It reaches autonomy Level 3 (the program's ceiling).
761
+ SHA-locked.
762
+
763
+ ### Added
764
+ - **The loop** (`pen_stack/loop/cycle.py`): `run_loop(goal, cell_state, ...)` orchestrates every prior cycle each
765
+ round: generate (v5.8), decide/batch (v5.10), safety-gated export (v5.7 plus v5.11), run (sim-lab v5.11 /
766
+ real lab), ingest (v4.5 gate), drift (v5.12), continual learn (v5.12). Gated: safety, build, and
767
+ belief-admission each await the `approver`. Returns `autonomy_level=3`, `human_in_control=True`,
768
+ `no_fabrication=True`. A hazardous candidate is discarded by the safety-gated pipeline before it is ever run.
769
+ - **Drift** (`pen_stack/loop/drift.py`): `detect_drift(designs, results)` compares the v5.9 twin's predictions
770
+ vs observed readouts; growing miscalibration leads to `severity:"high"` and `inflate_intervals` (widen, don't over-trust).
771
+ - **Continual learning** (`pen_stack/loop/continual.py`): `continual_update(...)` recalibrates trust plus twin plus immune
772
+ proxies on admitted outcomes only; each update is versioned and reversible (`rollback_to`); high drift
773
+ widens intervals; an admitted immune measurement with a CI can graduate a v5.6 proxy to outcome-validated.
774
+ This is recalibration, not foundation-model retraining.
775
+ - **Demo and autonomy criteria:** `loop_converges_faster_than_random` reports the active-vs-random convergence with a
776
+ bootstrap CI (retrospective/simulated, reported either way); `docs/autonomy.md` asserts the Level-3 criteria
777
+ (closed loop, human in control at every gate, anomaly flagging, no fabrication) and that Levels 4/5 are
778
+ not claimed.
779
+ - **Bench v0.3.8:** a new `closed_loop` hard-gate task. The gate is the loop's integrity (gated
780
+ end-to-end run plus no-fabrication plus Level-3 human-in-control plus drift detection plus versioned/reversible continual
781
+ learning); an ungated autopilot fails by construction. Convergence reported informationally.
782
+ - Docs: `docs/{closed_loop,autonomy}.md`; preregistration `ws_{loop,continual,drift}` plus SHA locks; deposit `phase_5.12/`.
783
+
784
+ ### Notes
785
+ - The loop is Level 3: closed, but with humans/lab in control at every gate, not autonomous. It runs in
786
+ silico via the sim-lab (a real lab attaches at the same interface); continual learning recalibrates rather than
787
+ retrains; drift covers calibration/residual shift, not all failures; the convergence demo is retrospective/
788
+ simulated, reported with CIs.
789
+
790
+ ## [5.11.0] - 2026-06-11 - The Build Interface (digital-to-physical bridge)
791
+
792
+ This release makes designs executable and results ingestible: loop-ready, lab-optional,
793
+ safety-gated, with the immune-risk profile attached as protocol metadata. SHA-locked.
794
+
795
+ ### Added
796
+ - **Protocol export** (`pen_stack/build/protocol.py`): `export_protocol(design, experiment, target, actor)` for
797
+ Opentrons / PyLabRobot / cloud-lab. It runs `verify()` first: a safety-`refuse` or illegal design raises
798
+ `ProtocolExportError` (no export path for a flagged design); a cleared design is emitted as a DRAFT
799
+ ("human/lab review required") carrying the v5.6 immune profile plus provenance in its metadata. Never auto-run.
800
+ - **Ingest** (`pen_stack/build/ingest.py`): `ingest_result(result, ...)` validates a result (assay / readout /
801
+ provenance) and turns it into a quarantined measured edge Candidate; the only path into the curated
802
+ world-model is the v4.5 gate (`gate_admit`): automated checks AND explicit human approval. No auto-edit
803
+ (Principle 1). Immune measurements can begin validating the v5.6 proxies on a later pass.
804
+ - **Sim-lab** (`pen_stack/build/simlab.py`): `run_simulated(protocol_ir, design, cell_state)` executes a
805
+ protocol in silico (samples from the v5.9 twin plus measurement noise), labelled `SIMULATED`, so the closed
806
+ loop (v5.12) runs end-to-end (export, sim, ingest) without hardware; it never enters the world-model as
807
+ measured truth.
808
+ - **Bench v0.3.7:** a new `protocol_safety` hard-gate task (`pen_stack/validate/protocol_safety.py`):
809
+ a cleared design exports with immune metadata, a safety-refused/illegal design is blocked, and the simulated
810
+ loop completes with quarantined SIMULATED results; an ungated exporter (which would emit the hazardous protocol)
811
+ fails by construction.
812
+ - Docs: `docs/build_interface.md`; preregistration `ws_{proto,ingest,simlab}` plus SHA locks; deposit `phase_5.11/`.
813
+
814
+ ### Notes
815
+ - PEN-STACK emits protocols and ingests results; it does not run experiments. Protocols are drafts requiring
816
+ human/lab review, results enter only through the gate, and the simulated lab is for development / loop-validation,
817
+ never a substitute for real data. Export is hard-blocked for anything the safety gate flags.
818
+
819
+ ## [5.10.0] - 2026-06-11 - The Experiment Designer (active learning / EIG)
820
+
821
+ The "Learn" brain of a self-driving lab: turn "I'm uncertain" into "run
822
+ this experiment next." It reads the calibrated v5.9 twin's uncertainty plus the v5.6 immune labels, scores each
823
+ candidate experiment by expected information gain, assembles a diverse batch, and proves on held-out data, with
824
+ CIs, that this learns faster than random/greedy (reporting plainly when it does not). SHA-locked.
825
+
826
+ ### Added
827
+ - **Acquisition** (`pen_stack/active/acquire.py`): `expected_information_gain` (reducible uncertainty from the twin's
828
+ predictive distribution; `>= 0`, monotone in uncertainty), `predictive_entropy` (from the twin's interval width),
829
+ and `immune_voi` (value of information for validating an immune proxy axis, v5.6): an experiment that
830
+ would measure a still-proxy axis is high-VOI (it turns proxy to outcome-validated). `acquisition_score` is fully
831
+ traceable to twin quantities plus v5.6 labels; deterministic; no fabricated values.
832
+ - **Batch design** (`pen_stack/active/design.py`): `select_batch` greedily maximises acquisition minus a
833
+ redundancy penalty (shared design facets), giving a diverse batch (not k copies of the most-uncertain point);
834
+ each experiment carries its expected info gain.
835
+ - **Validation** (`pen_stack/active/validate.py`): `retrospective_active_learning` simulates active vs random vs
836
+ greedy campaigns on a held-out split, reports mean±CI learning curves and a bootstrap CI on the curve-area
837
+ gap; `active_beats_random` only when the CI excludes zero, else the not-yet-useful negative is reported.
838
+ - **Bench v0.3.6:** a new `experiment_design` hard-gate task. The gate is the Learn engine's
839
+ properties (twin-sourced EIG monotone in uncertainty plus immune-VOI for proxy validation plus a diverse
840
+ batch plus retrospective active-vs-random with reps and CI); a random selector fails by construction. Active-beats-
841
+ random is reported informationally.
842
+ - Docs: `docs/experiment_design.md`; preregistration `ws_{acq,aldesign,alvalidate}` plus SHA locks; deposit `phase_5.10/`.
843
+
844
+ ### Notes
845
+ - The experiment designer is only as good as the v5.9 twin plus the v5.6 labels it queries; its advantage is validated
846
+ retrospectively with CIs and reported plainly when absent. It chooses informative experiments but does
847
+ not run them; prospective benefit awaits a lab partner (v5.11+). No autonomy claim.
848
+
849
+ ## [5.9.0] - 2026-06-11 - The Digital Twin (calibrated outcome prediction)
850
+
851
+ The missing layer: what does the cell do after the write? Predicted with
852
+ calibrated uncertainty. The twin computes what mechanism allows, adds an in-distribution virtual-cell estimate
853
+ (OOD-gated), screens immune outcome from the v5.6 profile, and is explicit about its boundary at phenotype.
854
+ SHA-locked.
855
+
856
+ ### Added
857
+ - **Virtual cell** (`pen_stack/oracles/vcell.py` plus scope cards `state`/`scgpt`): `predict_response(cell_state,
858
+ perturbation, model)` wraps Arc STATE / scGPT under the v4.0 `OracleResult` contract. A
859
+ perturbation-response prediction is a candidate, OOD-gated (a context outside the documented envelope is marked
860
+ `extrapolating`), cached/deferred (value `None` when absent, never fabricated). It encodes the field's own result
861
+ (Arc Virtual Cell Challenge): perturbation models don't yet consistently beat naive baselines.
862
+ - **Mechanism** (`pen_stack/twin/mechanistic.py`): `cassette_expression` = `promoter_strength x copy_number x
863
+ accessibility` (closed-form steady state); assumptions plus scope flags attached; physics where computable, not
864
+ a phenotype.
865
+ - **Outcome** (`pen_stack/twin/outcome.py`): `predict_outcome(design, cell_state)` fuses mechanism plus an
866
+ in-distribution virtual-cell response plus the v5.6 immune profile into one prediction with an interval that
867
+ widens under OOD, an immune-outcome dimension, and an explicit phenotype / in-vivo-magnitude boundary.
868
+ In-vivo durability may be conditioned on the grounded pre-existing-NAb axis (no invented immune numbers);
869
+ `output_kind="candidate"`.
870
+ - **Calibration** (`pen_stack/twin/calibrate.py`): `calibrate_outcome(...)` reports calibration two-sided: interval
871
+ coverage plus a bootstrap CI on the MAE gap vs a naive mean baseline; the twin "beats" naive only when the CI
872
+ excludes zero, else the negative is reported verbatim; it abstains at `N < 3`.
873
+ - **Bench v0.3.5:** a new `outcome_prediction` hard-gate task (`pen_stack/validate/outcome_prediction.py`):
874
+ the gate is the twin's calibration properties (two-sided calibration plus OOD widening plus immune dimension plus
875
+ phenotype out-of-scope), which an overconfident predictor fails by construction; twin-vs-naive skill is reported
876
+ informationally on a labelled synthetic stream (no public perturbation-outcome calibration set exists).
877
+ - Docs: `docs/digital_twin.md`; preregistration `ws_{vcell,mech,outcome,twincal}` plus SHA locks; deposit `phase_5.9/`.
878
+
879
+ ### Notes
880
+ - The twin is a hypothesis engine, not an oracle of truth: predictions are candidates with intervals;
881
+ phenotype, in-vivo behaviour, immunogenicity magnitude, and durability beyond the computable stay
882
+ scope-flagged. The interval is a heuristic band, not a trained conformal interval (no public outcome
883
+ calibration set). Immune-outcome is sourced from v5.6, never invented.
884
+
885
+ ## [5.8.0] - 2026-06-11 - The Live Agent and Generative Designer
886
+
887
+ PEN-STACK turns from a checker into a grounded designer: it generates
888
+ candidate end-to-end writing systems, keeps only those that pass safety plus legality plus calibration
889
+ (verifier-as-discriminator), and returns the Pareto frontier of real tradeoffs, in which immunogenicity-risk
890
+ is, for the first time, a grounded axis sourced from the v5.6 profile rather than a placeholder. SHA-locked.
891
+
892
+ ### Added
893
+ - **Generation** (`pen_stack/design/{space,generate}.py`): `generate_designs(goal|candidates)` proposes candidates
894
+ (`candidate_space` = the validated Phase-3 planner by the compatible delivery palette) and the v3.3 `verify()`,
895
+ now safety-gated (v5.7) plus legality plus calibration plus immune-profiled, disposes. A candidate survives only
896
+ if legal AND safe (`clear`/`flag`); hazardous (`refuse`/`escalate`) and illegal proposals are discarded,
897
+ never returned (the `as_claim()` guard generalised to whole designs). Survivors carry calibrated confidence,
898
+ the v5.6 immune profile, the safety decision, and `output_kind="candidate"`, never asserted to work.
899
+ - **Pareto** (`pen_stack/design/pareto.py`): `pareto_front(designs)` over `(efficiency, durability, safety,
900
+ deliverability, neg_immune_risk, neg_cost)`. `neg_immune_risk` is grounded by the v5.6 profile: the
901
+ worst-case per-axis in-scope score with the per-axis uncertainty carried as a band; the profile is never
902
+ collapsed into one number and the in-vivo magnitude stays scope-flagged (`in_vivo_magnitude_unknown`).
903
+ - **Orchestration** (`pen_stack/agent/orchestrator_live.py`): `orchestrate(goal)`: plan, generate, call an oracle
904
+ (cache-first/replayable) for a critique signal, dispose via `verify()`, refine. Every number is tool-sourced;
905
+ a seed-locked replay reproduces the trace (replay is the CI default); no fabrication.
906
+ - **Bench v0.3.4:** a new `generative_design` hard-gate task (`pen_stack/validate/generative_design.py`):
907
+ on a frozen mixed pool (benign plus a hazardous ricin payload plus illegal oversize/mRNA-incompatible), the grounded
908
+ designer returns only legal, safe, calibrated, immune-profiled survivors on a grounded-immune-axis Pareto frontier,
909
+ while an ungrounded generator ships hazardous/illegal designs and fails by construction.
910
+ - Docs: `docs/generative_design.md`; preregistration `ws_{gen,pareto,orch}` plus SHA locks; deposit `phase_5.8/`.
911
+
912
+ ### Notes
913
+ - A generated output is a candidate, never a claim; novelty is bounded by the oracles' validity and the
914
+ rules' legality, and never asserted to work. The immune-risk Pareto axis is a worst-case screen; the
915
+ per-axis v5.6 profile (with its validation labels) remains authoritative; in-vivo magnitude is a known-unknown.
916
+
917
+ ## [5.7.0] - 2026-06-11 - The Guardian (biosecurity / dual-use safety gate)
918
+
919
+ This release makes PEN-STACK safe by
920
+ construction before it moves toward "build": every design submitted to `verify()` first passes a biosecurity / dual-use screening gate that
921
+ refuses or escalates select-agent, pandemic-pathogen, and controlled-toxin signatures, with function-based and
922
+ chimera checks that catch AI-designed homologs that homology alone would miss, while legitimate therapeutic designs
923
+ pass untouched. It is orthogonal to (and complementary with) the v5.1-v5.6 immune-risk profile. SHA-locked.
924
+
925
+ ### Added
926
+ - **Screens** (`pen_stack/safety/{registry,screen}.py` plus `configs/safety/hazard_registry.yaml`): a curated,
927
+ version-pinned `HazardRegistry` (`registry_version`) and three or more screens returning typed, provenanced
928
+ `ScreenHit`s: `function_flag` (toxin / pathogen-essential functions, the screen that catches AI-homologs
929
+ at low identity), `taxon_flag` (regulated-pathogen taxa), `chimera_context` (hazardous assembly of benign
930
+ parts plus split-hazard), and `sequence_homology` (delegated to a wrappable external screener: IBBIS Common
931
+ Mechanism / SecureDNA-style; the in-repo baseline is a no-op). Signatures are function/family/taxon-level
932
+ only (public Pfam accessions plus public control-list references: 42 CFR 73 / 7 CFR 331 / 9 CFR 121 / Australia
933
+ Group / HHS P3CO/DURC), no hazard sequences, no synthesis/enhancement detail. All 14+ Pfam accessions were
934
+ independently verified against EBI InterPro before reliance; one error (PF01375, mislabeled anthrax, which is
935
+ heat-labile/cholera enterotoxin) was caught and corrected; anthrax PA was re-sourced from UniProt P13423.
936
+ - **Policy** (`pen_stack/safety/{policy,gate,audit}.py` plus `configs/safety/policy.yaml`): `SafetyVerdict`
937
+ {clear, flag, refuse, escalate}; `safety_gate(design, actor=...)` = strip-framing, screen, decide, audit;
938
+ ambiguous dual-use (gain-of-function) escalates to human review (HHS P3CO/DURC), not auto-refuse; an
939
+ append-only, hash-chained, tamper-evident `audit_log` (plus `verify_chain`) storing a design digest, not the
940
+ design. Re-framing as "defensive research" cannot flip refuse to clear (the artifact decides, not the wording).
941
+ - **Integration:** `Verdict.safety: SafetyVerdict`; `verify(design, actor=...)` runs the gate first and a
942
+ `refuse` short-circuits (the design is returned un-evaluated, not scored/critiqued). No-fabrication holds:
943
+ hits come only from the versioned registry.
944
+ - **Red team** (`pen_stack/safety/redteam.py`): an adversarial harness (AI-homolog, split-hazard, reframing,
945
+ chimera) plus reframing-stability pairs; reports set size plus caught count.
946
+ - **Bench v0.3.3:** a new `safety_screening` hard-gate task (`pen_stack/validate/safety_screening.py`):
947
+ benign therapeutics 0 false refusals, hazards refused/escalated at correct severity, evasions never `clear`;
948
+ beats a no-safety baseline (1.0 vs 0.33) by construction. Frozen probes/registry/policy SHA-locked into the
949
+ bench. The bench is now 17/17 available, planner beats naive on 13/13.
950
+ - Docs: `docs/responsible_use.md` plus `docs/biosecurity.md`; preregistration `ws_{screen,policy,redteam}` plus SHA locks;
951
+ deposit `phase_5.7/` (execution summary plus an independent data/ID verification record).
952
+
953
+ ### Notes
954
+ - The safety gate is a defensive safeguard, not a guarantee, and not a substitute for institutional
955
+ biosafety / IBC review; signatures are versioned and exploit detail is intentionally not published.
956
+ - It is orthogonal to the immune-risk profile: the Guardian asks "is this design hazardous/dual-use?"; the immune
957
+ profile asks "will the patient react?". Both attach to every `Verdict`; neither subsumes the other.
958
+
959
+ ## [5.6.0] - 2026-06-11 - Immunology completion and calibration (anti-PEG, proxy labels, unified profile)
960
+
961
+ This release finishes the delivery-immunology arc (v5.1-v5.5): it adds the missing anti-PEG axis, calibrates the
962
+ proxies, and exposes a unified per-design immune-risk profile that never collapses into one number.
963
+ SHA-locked.
964
+
965
+ ### Added
966
+ - **Anti-PEG** (`pen_stack/planner/antipeg_oracle.py` plus `configs/antipeg.yaml`): pre-existing/induced anti-PEG
967
+ antibodies gate re-dosing of PEGylated LNP. Population prevalence range (25-72%) gives
968
+ `preexisting_antipeg_score = 1 - midpoint/100`, range surfaced as `native_uncertainty`; abstains for
969
+ non-PEGylated vehicles. Serosurvey DOIs Crossref-verified (Chen 2016 `10.1021/acs.analchem.6b03109`, Yang &
970
+ Lai `10.1002/wnan.1339`, Armstrong `10.1002/cncr.22739`, Kozma `10.1016/j.addr.2020.07.024`). Scope card `antipeg`.
971
+ - **Calibration** (`pen_stack/validate/immune_calibration.py`): `calibrate_axis()` (Spearman rho plus percentile
972
+ bootstrap CI) labels an axis outcome-validated only when the CI excludes zero, else `weak_proxy`, and
973
+ `mechanistic_proxy` when N < 6. With no sufficient public paired (proxy, observed) dataset, every axis is
974
+ labelled a mechanistic/population proxy; the label travels with the profile. (No fabricated
975
+ outcome data; the machinery is proven on synthetic input.)
976
+ - **Profile** (`pen_stack/planner/immune_profile.py` plus `Verdict.immune_profile`): a per-design vector
977
+ of all axes (genotoxicity, CD8 epitope, innate, pre-existing NAb, anti-PEG), each with its own value plus
978
+ uncertainty plus scope plus validation label. `collapsed_score is None` (never fused, asserted); known-unknowns
979
+ listed; abstaining axes report `None`.
980
+ - **Extras:** a documented qualitative route/immune-privilege modifier (eye/CNS lower realized
981
+ immunogenicity vs systemic; Streilein 2003 `10.1038/nri1224`; no fabricated magnitude); CD4/MHC-II helper
982
+ epitopes, pre-existing capsid-specific T-cell immunity, and complement/CARPA registered as
983
+ known-unknowns. `prereg/ws_{peg,calib,profile}.yaml` plus SHA locks.
984
+
985
+ ### Changed
986
+ - Version 5.5.0 to 5.6.0 (minor, additive); `cite.curated_dois()` ingests the anti-PEG plus immune-privilege DOIs.
987
+
988
+ ### Scope invariant (unchanged)
989
+ - Every axis is a relative-risk screen (sequence/mechanistic or population proxy), labelled as such until
990
+ outcome-validated; the profile is never collapsed into one number; patient-specific titer, post-dose-1
991
+ induced immunity, and exact in-vivo magnitude stay known-unknowns.
992
+
993
+ ## [5.5.0] - 2026-06-10 - Anti-vector seroprevalence oracle (the last immune axis, from data)
994
+
995
+ This release completes the computable delivery-immunology axes. Pre-existing humoral immunity (B-cell /
996
+ neutralizing antibody) to a viral capsid is the one immune axis that cannot be computed from sequence: it is a population
997
+ prevalence from natural exposure. v5.5 grounds it in published serosurvey data. SHA-locked.
998
+
999
+ ### Added
1000
+ - **Seroprevalence table** (`configs/seroprevalence.yaml`): curated population NAb/IgG seroprevalence per serotype
1001
+ as ranges (region/age/assay variation) with DOIs: AAV (Calcedo 2009, Boutin 2010), adenovirus type 5
1002
+ (Mast 2010), HSV-1 (Looker 2015), VSV (negligible).
1003
+ - **Seroprevalence oracle** (`pen_stack/planner/seroprevalence_oracle.py`): `seroprevalence_oracle(vehicle,
1004
+ serotype=None)` returns an `OracleResult`. `preexisting_score = 1 - midpoint(seroprevalence)/100`; the range width is
1005
+ surfaced as `native_uncertainty`. Non-viral becomes 1.0 by mechanism; unknown abstains.
1006
+ - **Wired into the pre-existing axis:** `safety_efficacy_profile()` folds the computed seroprevalence score
1007
+ into the `preexisting_immunity` sub-axis only for in-vivo vehicles (serum NAb neutralises the vector in
1008
+ vivo; ex-vivo transduction in a dish is not reached by host antibody, so it is reported but muted). `seroprevalence_score`
1009
+ surfaces the raw value.
1010
+ - **Result (from data):** adenovirus has the highest pre-existing seroprevalence (40-90%, score 0.35), AAV
1011
+ intermediate (30-60%, 0.55), VSV/lentivirus negligible (0-5%, 0.975), the documented ordering quantified
1012
+ from serosurveys. `prereg/ws_seroprev.yaml`.
1013
+
1014
+ ### Changed
1015
+ - Version 5.4.0 to 5.5.0 (minor, additive data-grounded oracle); `cite.curated_dois()` ingests the
1016
+ seroprevalence DOIs.
1017
+
1018
+ ### Scope invariant (unchanged)
1019
+ - This is a population prevalence (a range; region/age/assay-dependent), not a given patient's NAb titer /
1020
+ sero-status (a clinical test, patient-specific, a known-unknown); the humoral (B-cell) axis only,
1021
+ distinct from the v5.3 T-cell epitope load. No patient-specific magnitude predicted.
1022
+
1023
+ ## [5.4.0] - 2026-06-10 - Computed innate-sensing scorer (completes the computable immune axes)
1024
+
1025
+ The third computed delivery-immunology signal, after v5.2 genotoxicity and v5.3 capsid epitope load. Innate
1026
+ sensing of a delivered nucleic acid is computed directly from the cargo sequence: CpG O/E for DNA (TLR9),
1027
+ U-richness plus dsRNA for mRNA (TLR7/RIG-I), covering every cargo form. SHA-locked.
1028
+
1029
+ ### Added
1030
+ - **Innate scorer** (`pen_stack/planner/innate_sensing.py`): `cpg_observed_expected()` (Gardiner-Garden &
1031
+ Frommer) plus `innate_sensing(seq, cargo_form)` returning an `OracleResult`. DNA gives CpG O/E (vertebrate genome ~0.2
1032
+ tolerated; non-depleted DNA is TLR9-stimulatory), `innate_score = max(0, 1 - CpG_O/E)`. mRNA gives uridine
1033
+ fraction plus ViennaRNA dsRNA pairing (graceful when ViennaRNA absent), flagged partial/`extrapolating`.
1034
+ RNP is minimal/transient. Abstains on empty / unrecognised input (never fabricates). Pure sequence
1035
+ computation, no external data, runs in CI.
1036
+ - **Surfaced in `verify()`:** when a design supplies `cargo_seq`, the computed innate load is attached as a
1037
+ `cargo_innate_sensing` scope flag (cargo form from the writer output form, else the vehicle's first
1038
+ compatible form) and added to `delivery_profile.cargo_innate`. No confidence added; the realized in-vivo
1039
+ innate response stays a known-unknown.
1040
+ - Scope card `innate_sensing`; `prereg/ws_innate.yaml`. `cite.curated_dois()` ingests the innate provenance
1041
+ DOIs (CpG-TLR9 10.1073/pnas.161293498, CpG-depleted AAV 10.1172/JCI68205, RNA modification
1042
+ 10.1016/j.immuni.2005.06.008, plus Krieg 1995 / Hornung 2006).
1043
+
1044
+ ### Changed
1045
+ - Version 5.3.0 to 5.4.0 (minor, additive computed scorer).
1046
+
1047
+ ### Scope invariant (unchanged)
1048
+ - This is a sequence-intrinsic motif-load signal. The realized in-vivo innate response magnitude in a patient is
1049
+ not modelled (known-unknown); the mRNA score is partial because the dominant evasion lever,
1050
+ nucleoside modification (m1-pseudouridine), is a manufacturing choice not derivable from sequence; DNA
1051
+ methylation state is likewise out of scope. No magnitude predicted.
1052
+
1053
+ ## [5.3.0] - 2026-06-10 - Computed capsid epitope-load oracle (covers all vectors)
1054
+
1055
+ v5.2 computed genotoxicity only meaningfully touches integrating vectors. v5.3 brings the NetMHC-style
1056
+ calculation to the adaptive (CD8 T-cell) axis: the fraction of a viral vector's capsid/envelope that is
1057
+ presentable across a frequent HLA-I panel (MHCflurry), so the computed immune signal covers all 8 vehicles
1058
+ (5 viral computed, 3 non-viral by mechanism). SHA-locked.
1059
+
1060
+ ### Added
1061
+ - **Build** (`scripts/p53_build_epitope_oracle.py`, runs in a dedicated `penstack:mhcflurry` image):
1062
+ slides 9-mers across each capsid/envelope antigen and predicts MHCflurry 2.0 affinity %rank per allele across
1063
+ 12 frequent HLA-I alleles; `epitope_fraction_strong` = residues covered by a strong binder (%rank <= 0.5);
1064
+ `capsid_immune_score = 1 - epitope_fraction_strong`. Sequences UniProt-verified and committed
1065
+ (`configs/capsid_sequences.fasta`): AAV2 VP1 P03135, Ad5 hexon P04133, VSV-G P03522, HSV-1 gD P57083 plus gB
1066
+ P06437. Emits the small committed summary `configs/capsid_epitope_oracle.yaml` (MHCflurry plus raw sequences stay
1067
+ on the VM, CI-safe).
1068
+ - **Oracle** (`pen_stack/planner/capsid_epitope_oracle.py`): `capsid_epitope_oracle(vehicle)` returns
1069
+ an `OracleResult` (`output_kind="baseline"`, scope card `capsid_epitope`). Non-viral vehicles become 1.0 by
1070
+ mechanism; unknown / sequence-less abstains.
1071
+ - **Wired into the adaptive axis:** `safety_efficacy_profile()` folds the computed capsid score into the
1072
+ adaptive (CD8) sub-axis only for in-vivo vehicles. The computed score is intrinsic antigen
1073
+ presentability; for ex-vivo lentivirus (whose VSV-G envelope is intrinsically epitope-dense but barely
1074
+ seen by the host ex vivo) it is reported but not folded (`adaptive_source = computed_ex_vivo_muted`), the
1075
+ documented tier kept. `capsid_presentability_score` surfaces the raw computed value.
1076
+ - **Result:** the AAV2 capsid is the least epitope-dense (0.72) and Ad5 hexon among the most (0.82); HDAd's in-vivo
1077
+ immune score drops accordingly, the documented adaptive ordering reproduced from sequence. `prereg/ws_epitope.yaml`.
1078
+
1079
+ ### Changed
1080
+ - Version 5.2.0 to 5.3.0 (minor, additive computed oracle); `cite.curated_dois()` ingests the epitope
1081
+ provenance DOIs (MHCflurry 10.1016/j.cels.2020.06.010, HLA-I supertypes 10.1186/1471-2172-9-1).
1082
+
1083
+ ### Scope invariant (unchanged)
1084
+ - This is a population-level, sequence-intrinsic presentation signal (does the capsid contain HLA binders), not
1085
+ the realized in-vivo / patient-HLA-specific T-cell response (a known-unknown), and CD8/MHC-I only (not
1086
+ antibody / neutralizing-antibody). No magnitude predicted.
1087
+
1088
+ ## [5.2.0] - 2026-06-10 - Computed genotoxicity oracle (data, not a documented tier)
1089
+
1090
+ The v5.1 genotoxicity axis was a documented ordinal tier; for integrating vectors that signal is in fact
1091
+ computable from data the stack already holds. v5.2 adds a computed genotoxicity oracle: the observed
1092
+ enrichment of a vector class's integration sites near COSMIC oncogenes, answering through the v4.0
1093
+ OracleResult contract. SHA-locked.
1094
+
1095
+ ### Added
1096
+ - **Build** (`scripts/p52_build_genotox_oracle.py`, runs on the VM where the data lives): computes,
1097
+ per integrating vector class, `P(integration site within 50 kb of a COSMIC Cancer-Gene-Census oncogene)` and
1098
+ its enrichment over genome background, from VISDB per-virus catalogues by the Phase-1 oncogene annotation
1099
+ (COSMIC CGC v104). Emits the small, auditable, committed summary `configs/genotoxicity_oracle.yaml` (raw
1100
+ catalogues stay on the VM; only the statistics ship, CI-safe).
1101
+ - **Oracle** (`pen_stack/planner/genotoxicity_oracle.py`): `genotoxicity_oracle(vehicle)` returns an
1102
+ `OracleResult` (`output_kind="baseline"`) with `genotox_score = min(1, 1/enrichment)`, native uncertainty
1103
+ (CI on the observed fraction), the `delivery_genotoxicity` scope card, and `extrapolating` for small-n
1104
+ classes. Non-integrating vehicles become 1.0 by mechanism; no computed class abstains (never fabricates).
1105
+ - **Wired into the v5.1 balance:** `safety_efficacy_profile()` now prefers the computed genotox_score for
1106
+ integrating vectors and falls back to the documented tier otherwise (`genotox_source` records which).
1107
+ - **Result (from data):** lentiviral (HIV) integration is 2.08x enriched near oncogenes (n=88,743, robust)
1108
+ vs 5.65x for gammaretroviral (MLV, the LMO2/SCID-X1 comparator, small-n flagged), reproducing the
1109
+ lentivirus-safer-than-gammaretrovirus ordering from VISDB by COSMIC, and the computed lentivirus score
1110
+ (0.48) validates the v5.1 documented "moderate" tier (0.5). `prereg/ws_genotox.yaml`.
1111
+
1112
+ ### Changed
1113
+ - Version 5.1.0 to 5.2.0 (minor, additive computed oracle); `cite.curated_dois()` ingests the genotox
1114
+ provenance DOIs (VISDB 10.1093/nar/gkz867, COSMIC CGC 10.1038/s41568-018-0060-1, HIV/MLV integration biology).
1115
+
1116
+ ### Scope invariant (unchanged)
1117
+ - This is a relative integration-preference signal. The in-vivo clonal-expansion / leukemogenesis outcome
1118
+ in a patient is not modelled and stays a known-unknown (`delivery_genotoxicity` scope card); the immune
1119
+ magnitude likewise stays `in_vivo_immunogenicity`. No magnitude is predicted.
1120
+
1121
+ ## [5.1.0] - 2026-06-10 - Delivery immunology (the safety/efficacy balance)
1122
+
1123
+ The delivery palette gains a documented, cited, qualitative immune plus safety plus efficacy profile per vehicle,
1124
+ so the substrate can make the safety/efficacy tradeoff legible and user-weightable, without ever predicting an
1125
+ immune magnitude (that stays a declared known-unknown). SHA-locked.
1126
+
1127
+ ### Added
1128
+ - **Config** (`configs/delivery_vehicles.yaml` v1.1): an `immune_safety` block on all 8 vehicles
1129
+ (`preexisting_immunity`, `neutralizing_antibody`, `innate_immune`, `adaptive_immune`, `genotoxicity`,
1130
+ `efficacy`, `tradeoff`, `immune_dois`): documented ordinal low/moderate/high priors, every `immune_doi`
1131
+ Crossref-verified and in the curated-DOI set (citations resolve by construction).
1132
+ - **Planner** (`pen_stack/planner/delivery_immunology.py`): `safety_efficacy_profile()` reports two
1133
+ separate safety sub-axes: `immune_score` (immunogenicity; reversible, eligibility/re-dosing) and
1134
+ `genotox_score` (insertional/oncogenic; permanent), never collapsed, with a top-line
1135
+ `safety_score = min(immune_score, genotox_score)` (precautionary worst-axis). `recommend_delivery(cargo_form,
1136
+ cargo_bp, safety_weight, in_vivo)` ranks the eligible palette along the safety/efficacy frontier by a
1137
+ user-supplied weight. It reproduces the stated tradeoff: AAV is dinged on immunogenicity, lentivirus on
1138
+ genotoxicity. `prereg/ws_immune.yaml`.
1139
+ - **Verify** (`Verdict.delivery_profile` plus a `delivery_immune_profile` scope flag): `verify()` now
1140
+ surfaces the documented profile and tradeoff for a chosen vehicle, always attaching the standing
1141
+ `in_vivo_immunogenicity` known-unknown flag, never adding confidence, never predicting a magnitude.
1142
+
1143
+ ### Changed
1144
+ - Version 5.0.0 to 5.1.0 (minor, additive delivery-immunology layer); `cite.curated_dois()` now also ingests
1145
+ the per-vehicle `immune_dois`.
1146
+
1147
+ ### Scope invariant (unchanged)
1148
+ - The in-vivo immune magnitude (patient/construct-specific response) remains a declared known-unknown
1149
+ (`configs/known_unknowns.yaml: in_vivo_immunogenicity`) and is never predicted. v5.1 exposes only
1150
+ documented ordinal priors plus a transparent, user-weighted ranking; it makes the boundary legible, it does
1151
+ not close it.
1152
+
1153
+ ## [5.0.0] - 2026-06-09 - The Co-Scientist (capstone)
1154
+
1155
+ The reasoning ceiling rises while the grounding floor stays fixed: a co-scientist that proposes multiple
1156
+ distinct strategies, critiques and revises its own plans, cites its reasoning, and itemises what it cannot
1157
+ assess, with no-fabrication holding across the full reasoning stack (the central gate). Each component is SHA-locked.
1158
+
1159
+ ### Added
1160
+ - **Planning and multi-strategy** (`pen_stack/agent/co_scientist.py`): `propose_strategies()` returns 2-3 materially
1161
+ distinct strategies (at least 2 design axes differ, measured by `distinctness()`, not reworded), each
1162
+ independently legal plus confidence-tagged; `deliberate()` benchmarks the deliberative planner vs the
1163
+ deterministic baseline. `prereg/ws_plan.yaml`.
1164
+ - **Critique and scope:** `critique()` / `critique_and_revise()` (the critic only flags plus swaps a design
1165
+ choice, never invents a number; revisions re-verified) plus `critique_falsifiability()` (improves flawed plans
1166
+ illegal to legal, 0 spurious revisions on clean) plus `scope_ledger()` (per-recommendation: what was/wasn't
1167
+ assessed, the known-unknowns itemised). `prereg/ws_crit.yaml`.
1168
+ - **Citation and generalisation** (`pen_stack/agent/cite.py`): `cited_rationale()` (citations drawn from the curated
1169
+ world-model, resolve by construction) plus `citations_grounded()` guard (rejects any DOI not in the curated
1170
+ set) plus `generalise()` (adjacent tasks grounded-or-refused). `prereg/ws_cite.yaml`.
1171
+ - **Bench v0.3.2:** a `co_scientist_grounded` reference-solver task: grounded rate 1.0 vs ungrounded 0.0;
1172
+ no-fabrication across the full stack. `docs/co_scientist.md`.
1173
+
1174
+ ### Changed
1175
+ - Version 4.5.1 to 5.0.0 (major, the substrate matured into a grounded co-scientist); bench 0.3.1 to 0.3.2.
1176
+
1177
+ ## [4.5.1] - 2026-06-09 - ID-correctness patch: cell-type ontology IDs
1178
+
1179
+ ### Fixed
1180
+ Two of the three new v4.5 Tier-A cell-type ontology IDs in `configs/cell_types.yaml` were wrong (verified via
1181
+ EBI-OLS): `EFO:0002322` resolved to the RPMI8226 myeloma line (not a T cell) and `EFO:0004146` to an
1182
+ obsolete myopathy term (not hepatocyte). Corrected to the canonical, non-obsolete Cell Ontology terms:
1183
+ primary_T_cell to `CL:0000084` (T cell), hepatocyte to `CL:0000182` (hepatocyte). iPSC (`EFO:0004905`),
1184
+ K562 (`EFO:0002067`), HepG2 (`EFO:0001187`) verified correct, as was the ISPpu10 back-test record (Europe PMC
1185
+ PPR1218813, "ISPpu10 is a structure-gated bridge RNA recombinase..."). No result/test change (the IDs are
1186
+ coverage-card metadata; `cell_types.py` reads coverage, not the ontology id).
1187
+
1188
+ ## [4.5.0] - 2026-06-09 - The Living World-Model (knowledge graph plus gated living loop)
1189
+
1190
+ v4.5 promotes the flat tables into a queryable knowledge graph that keeps itself current. Each component is
1191
+ SHA-locked. The agent proposes; a gate disposes, so no process auto-edits curated truth.
1192
+
1193
+ ### Added
1194
+ - **Knowledge graph.** `pen_stack/graph/{schema,build,query}.py`: typed nodes
1195
+ (writer/locus/cargo/vehicle/cell_type/write_type/outcome) plus typed edges
1196
+ (reaches/deliverable_by/performs/durable_in/carries/used_writer/observed_at), each carrying evidence kind
1197
+ (measured > curated > predicted) plus confidence plus scope plus provenance. Built deterministically from the v4.0
1198
+ curated tables (94 nodes / 288 edges), a pure-Python JSON store. Multi-hop queries return provenanced paths;
1199
+ `deliverable_by` reproduces the v3.3 verifier (0 parity mismatches). REST `POST /graph/query` plus MCP
1200
+ `graph_query`. `docs/world_model.md`; `prereg/ws_graph.yaml`.
1201
+ - **Gated living loop.** `pen_stack/graph/ingest.py`: Candidate plus Quarantine (propose never mutates
1202
+ a graph), `automated_checks` plus `gate_admit(approved, admitted_by)` as the sole admission path with versioned
1203
+ records; the back-test surfaces ISPpu10 (Europe PMC PPR1218813). No auto-edit path (asserted). `prereg/ws_mon.yaml`.
1204
+ - **Cell-type expansion.** `configs/cell_types.yaml` Tier-A (iPSC/ESC, primary T cells, hepatocytes)
1205
+ with coverage cards plus a Tier-B roadmap; `pen_stack/graph/cell_types.py` graceful degradation (partial coverage
1206
+ caps confidence) plus cross-cell-type OOD labelling. `prereg/ws_ct.yaml`.
1207
+ - **Graph reasoning bench.** `graph_multihop_reasoning` (bench v0.3.1): graph reasoning accuracy 1.0
1208
+ vs ungrounded 0.0, every answer a provenanced path. `prereg/ws_ba_v45.yaml`.
1209
+
1210
+ ### Changed
1211
+ - Version 4.0.3 to 4.5.0; bench 0.3 to 0.3.1; README updated for v4.5; M1/M2 plus world-model note updates.
1212
+
1213
+ ## [4.0.3] - 2026-06-09 - ID-correctness patch: UniProt plus Pfam plus ontology audit
1214
+
1215
+ ### Fixed
1216
+ A whole-repo audit of structured IDs (verified against InterPro, UniProt, EBI-OLS, mygene):
1217
+ - **`pen_stack/mech/pfam_whitelist.yaml` (v1.2.1 to v1.2.2):** the 26 Pfam accessions were all correct, but
1218
+ 13 of 22 `example_uniprot` proteins did not actually contain their claimed domain (membership checked
1219
+ against each protein's UniProt Pfam cross-references), including a marine-worm Histone H3 (PF13586), a
1220
+ mouse mannosyltransferase (PF05621/TniB), I-AniI (a LAGLIDADG enzyme) mislabelled HNH (PF01844), a
1221
+ glycine-betaine transporter and a Tn3 transposase mis-filed as rve, and an obsolete 404 accession
1222
+ (PF08721), despite the header claiming a spot-check. All corrected to reviewed/curated proteins whose
1223
+ UniProt entry genuinely carries the domain (e.g. ISCro4 `D2TGM5`, Tn5 `Q46731`, Tn7-TnsA `P13988`, Bxb1
1224
+ integrase `Q9B086`, McrA `P24200`); the audit-status header was corrected to stop over-claiming.
1225
+ - **`configs/atlas_families.yaml`** (drives family expansion in `expand.py`): IS621 `A0A0F6B5L8` (a
1226
+ betaine transporter) to `A0A2X3M8B0` (IS621 transposase); phiC31 `Q9T2A6` (a plant NAD(P)H
1227
+ oxidoreductase) to `Q9T221` (phiC31 integrase). The Pfam-query signatures and discovery DOIs were
1228
+ already correct.
1229
+
1230
+ ### Verified clean
1231
+ The 4 EFO cell-type IDs map correctly (EFO:0002067=K562, EFO:0001187=HepG2, EFO:0002784=GM12878,
1232
+ EFO:0005483=ES-Bruce4); all GSH gene symbols are valid HGNC symbols; all 26 Pfam accessions resolve with the
1233
+ correct domain name.
1234
+
1235
+ ## [4.0.2] - 2026-06-09 - Citation-correctness patch: full-repo DOI audit
1236
+
1237
+ ### Fixed
1238
+ A full sweep of all 56 DOIs in the repo (verified via Crossref plus doi.org) found six incorrect or
1239
+ non-existent citations, all now corrected to verified, topically-correct references:
1240
+ - `configs/gsh_validated_heldout.yaml` H11 locus: `10.1371/journal.pone.0113481` (resolved to an unrelated
1241
+ cardiology paper) to `10.1093/nar/gkt1290` (Zhu et al. 2014, *DICE*, NAR 42:e34, the paper that
1242
+ characterized human H11 on chr22q12.2 between DRG1 and EIF4ENIF1).
1243
+ - `configs/delivery_vehicles.yaml` plus `configs/rules/{delivery,payload}.yaml`: `10.1089/hum.2017.084`
1244
+ (non-existent), `10.1089/hum.2009.213` (non-existent), `10.1038/sj.gt.3302529` (unrelated erratum) to
1245
+ `10.1128/JVI.79.15.9933-9944.2005` (Grieger & Samulski, AAV packaging capacity),
1246
+ `10.1128/JVI.72.2.926-933.1998` (multiply-deleted adenovirus vectors), `10.1038/nbt1101-1067`
1247
+ (Wade-Martins, HSV-1 amplicon large-capacity).
1248
+ - `pen_stack/validate/bench_writetype_tasks.py` provenance: `10.1038/s41586-023-06756-4` (diabetes program)
1249
+ and `10.1126/science.abm1123` (freshwater fish) to `10.1016/j.cell.2022.03.045` and
1250
+ `10.1128/JVI.79.15.9933-9944.2005`.
1251
+
1252
+ The remaining 50 DOIs resolve correctly; three legacy DOIs in `mech/pfam_whitelist.yaml` (Rice 1995 Cell,
1253
+ Kholodii 1997 Res Microbiol, Prudhomme 2002 J Bacteriol) carry full author/year/journal references and are
1254
+ real classic papers whose pre-modern DOIs do not resolve at doi.org, left unchanged (a registration artifact,
1255
+ not an error).
1256
+
1257
+ ## [4.0.1] - 2026-06-09 - Data-correctness patch: writer-verification panel verified against Perry 2025
1258
+
1259
+ ### Fixed
1260
+ - **The frozen writer-verification panel is now verbatim from the measured Perry 2025 ISCro4 DMS.** The offline-fallback panel
1261
+ in `atlas/writer_verify.py` previously used illustrative Z-scores (2.6/2.1/1.7) and invented control
1262
+ variants (G15D/P88R/L120E), and `_CORE_RESIDUES` used illustrative arginines. Replaced with the real values
1263
+ from `science.adz0276` Table S3: the top-3 enhancers N322P (Z 0.754), H50K (0.742), R278M (0.709), real
1264
+ near-neutral variants (V21R, S312Q, G286T), the most-deleterious variants (R132E -5.40, R137E -5.12,
1265
+ R195D -4.98), and the documented catalytic residues D11/E60/D102/D105/S241 ("Residue Groups" sheet). The
1266
+ real-DMS path (on the VM/Drive) was already correct; only the offline fallback constants were illustrative.
1267
+ Added `test_ws_wv.py::test_frozen_panel_matches_real_perry_dms_table_s3` to guard against drift.
1268
+
1269
+ ## [4.0.0] - 2026-06-09 - The Oracle Mesh (on top of the foundation models) plus writer verification
1270
+
1271
+ A major bump: the substrate now composes the biomolecular foundation models under one contract and verifies
1272
+ the writer enzyme itself. Each component is SHA-locked. No de-novo writer invention: score
1273
+ and critique only (the pen-assemble lesson).
1274
+
1275
+ ### Added
1276
+ - **The oracle mesh.** `pen_stack/oracles/` with `OracleResult{value, provenance(model+version),
1277
+ native_uncertainty, scope_card, in_scope, extrapolating, output_kind, available, cached}`. Adapters:
1278
+ `genome.py` (AlphaGenome OOD-gated; Evo2 likelihood=claim / generation=candidate; ChromBPNet/Borzoi
1279
+ baseline), `structure.py` (AlphaFold3/Boltz-2/Chai-1/Protenix plus `consensus()` that widens the interval on
1280
+ cross-oracle disagreement), `protein_design.py` (RFdiffusion/ProteinMPNN/ESM3, all candidates), `rna.py`
1281
+ (ViennaRNA, real, hard fold-legality), `energetics.py` (bridge off-target, MC3 gate >=0.77).
1282
+ `configs/oracles/scope_cards.yaml` (11 models); deterministic version-pinned `oracle_cache/`. Guard:
1283
+ the generative candidate `as_claim()` raises. `docs/oracles.md`; `prereg/ws_o.yaml`.
1284
+ - **Writer verification.** `pen_stack/atlas/writer_verify.py`: DMS- and structure-grounded variant
1285
+ scoring (measured=claimable, unmeasured=not), `blind_recovery` recovers N322P/H50K/R278M above
1286
+ measured-worse controls, and `critique_candidate` (fold/active-site/deliverable/reachable) wired into
1287
+ `verify()` as `Verdict.writer_critique`, always `no_claim=True`. `docs/writer_verification.md`;
1288
+ `prereg/ws_wv.yaml`.
1289
+ - **Mesh upgrade plus delivery oracle.** `wgenome/mesh_features.py` (OOD-gated feature hook plus blind
1290
+ re-validation reporting parity vs v3.x when oracles are deferred) plus a computable
1291
+ `delivery.aav_packaging_margin` soft rule (titre drops near the AAV capsid limit). `prereg/ws_atlas.yaml`.
1292
+
1293
+ ### Changed
1294
+ - Version 3.4.0 to 4.0.0; `Verdict` gains `writer_critique`; M1 plus writer-verification note plus M2 updates.
1295
+
1296
+ ## [3.4.0] - 2026-06-09 - The Environment (train/eval surface plus bench v0.3 plus outcome-calibration)
1297
+
1298
+ v3.4 turns the thin Gym interface into a full environment an AI agent can be trained and graded in, ships
1299
+ Genome-Writing Bench v0.3 (multi-write-type plus adversarial robustness), and tests whether plan-confidence
1300
+ actually predicts documented outcomes. Each component is SHA-locked. The environment is an
1301
+ interface plus an evaluation harness (a near-one-shot decision), no RL-superiority claim.
1302
+
1303
+ ### Added
1304
+ - **The genome-writing environment.** `pen_stack/env/genome_writing_env.py` upgraded to a full
1305
+ `gymnasium.Env`: a 5-stage MDP (write_type, site, writer, cargo, delivery) whose step validity comes
1306
+ from the v3.3 verifier and whose reward is the legality gate times the L4 calibrated plan confidence, with a
1307
+ reserved abstain action for a justified refusal. `pen_stack/env/policies.py` (random plus greedy-planner).
1308
+ Passes `gymnasium.utils.env_checker.check_env`; greedy(planner) >= random and greedy-legal on the frozen
1309
+ seed set. `docs/environment.md`; `prereg/ws_env.yaml` plus lock.
1310
+ - **Genome-Writing Bench v0.3.** `multi_write_type_legality` routes plus judges legality across all 6
1311
+ non-insertion write types (accuracy 1.0, ungrounded 0.0); `adversarial_robustness` probes T13-T16
1312
+ (out-of-scope-in-disguise, contradictory constraints, prompt-injection, distribution-shift): the
1313
+ verifier-backed agent passes 4/4 vs an over-confident baseline 0/4, no-fabrication holds including under
1314
+ injection. Leaderboard v0.3 robustness contrast. `prereg/ws_bench.yaml` plus lock.
1315
+ - **Plan-confidence calibrated against documented outcomes.** `pen_stack/validate/outcome_calibration.py`:
1316
+ a plan-level reliability diagram plus ECE plus bootstrap-CI selective prediction on the DOI writer panel. The
1317
+ result: useful for ranking (high-confidence 0.30 vs low-confidence 0.0 documented-choice recovery, gap
1318
+ CI95 [0.17, 0.43], monotone) but poorly calibrated in absolute terms (ECE 0.71). Feeds M-UQ.
1319
+ `prereg/ws_cal.yaml` plus lock.
1320
+
1321
+ ### Changed
1322
+ - Version 3.3.0 to 3.4.0; bench 0.2.1 to 0.3; README updated for v3.4; M2/M-UQ manuscript updates.
1323
+
1324
+ ## [3.3.0] - 2026-06-09 - The Verifier (a type checker for genome writes)
1325
+
1326
+ v3.3 lifts the laws of genome writing into a versioned, machine-readable rule base and exposes a single
1327
+ `verify(design) -> Verdict` call (legal/illegal plus named rule plus calibrated confidence plus scope) over Python,
1328
+ REST, and MCP. Each component is SHA-locked.
1329
+
1330
+ ### Added
1331
+ - **Rule base plus solver.** `pen_stack/rules/{schema,evaluators,loader,solver}.py` plus `configs/rules/*.yaml`
1332
+ (9 rules across reachability/fold/payload/multiplex/delivery), each id/kind/mechanism/param/provenance(DOI)/
1333
+ test. Evaluators delegate to the existing validated functions; a parity test proves no decision changed.
1334
+ Legality and confidence are kept as distinct axes.
1335
+ - **Delivery palette.** `configs/delivery_vehicles.yaml` plus `planner/delivery_vehicles.py`: 8 vehicles
1336
+ (AAV single/dual, lentivirus, HDAd, HSV amplicon, LNP-mRNA, eVLP, electroporation) with capacity/integration/
1337
+ cargo-form/DOIs; delivery rules (hard rejects plus soft penalties plus an immunogenicity-magnitude scope flag).
1338
+ - **Write-type router.** `planner/router.py` plus `configs/write_types.yaml`: dispatches insertion/
1339
+ excision/inversion/replacement/regulatory_rewrite/landing_pad_install/multiplex; unsupported types defer.
1340
+ - **Verification service.** `pen_stack/verify/{service,schema}.py`: `verify(design) -> Verdict`; `POST
1341
+ /verify` plus MCP `verify_write`; `docs/verify.md`. No fabrication (every number tool-sourced).
1342
+ - **Bench v0.2.1 plus agent.** T12 rule-grounded legality-with-explanation (verifier reason accuracy 1.0
1343
+ vs ungrounded 0.0); the agent submits its plan to the verifier. Bench 12/12 available, planner beats baseline
1344
+ 8/8.
1345
+ - **Docs:** `docs/verify.md`, `docs/rules.md`, `docs/delivery.md`.
1346
+
1347
+ ### Changed
1348
+ - Version 3.2.0 to 3.3.0 (pyproject, `__init__`, CITATION.cff). README updated for v3.3; bench badge v0.2.1.
1349
+
1350
+ ## [3.2.0] - 2026-06-08 - A calibrated, self-aware co-scientist
1351
+
1352
+ The v3.2 cycle makes the genome-writing funnel trustworthy: every value carries a calibrated confidence,
1353
+ an extrapolation flag, and, where the biology is beyond any tool here, an explicit out-of-scope deferral.
1354
+ Each workstream is pre-registered (`prereg/ws_{uq,ep,mc,ba}.yaml`, SHA-locked) and reports its
1355
+ negatives. The Genome-Writing Bench bumps to v0.2.
1356
+
1357
+ ### Added
1358
+ - **Calibrated uncertainty plus OOD.** Conformal prediction intervals (durability expression) and APS /
1359
+ Mondrian prediction sets (safety, silenced) wrapping the existing heads with no retraining
1360
+ (`pen_stack.wgenome.uncertainty`); an OOD detector that widens intervals out-of-distribution
1361
+ (`pen_stack.wgenome.ood`); selective prediction plus plan-level confidence
1362
+ (`pen_stack.validate.selective_prediction`). Held-out coverage 0.895 vs 0.90 nominal; risk-coverage accuracy
1363
+ 0.739 to 0.930 under abstention. OOD across human cell types is weak (0.65-0.73), reported as a heuristic.
1364
+ - **Epistemic scoping.** A three-tier status (grounded-confident / grounded-extrapolating /
1365
+ not-computable) on every agent output (`pen_stack.agent.epistemic`); a known-unknowns registry plus a scope
1366
+ matcher (`configs/known_unknowns.yaml`, `pen_stack.agent.scope`, `docs/scope.md`) that defers out-of-scope
1367
+ questions (deferral 1.0, false-defer 0.0); abstention in the agent. The no-fabrication gate is intact.
1368
+ - **Mechanistic filters.** A hard target-site/PAM/att-site reachability reject
1369
+ (`pen_stack.planner.target_site`, `configs/target_sites.yaml`; controls 9/9); vehicle-specific
1370
+ delivery-sequence penalties (`pen_stack.planner.delivery_constraints`); and an off-target energetics
1371
+ model (`pen_stack.bridge.offtarget_energetics`) that beats the 0.77 baseline at held-out AUROC 0.88 on the
1372
+ comparable (core-disrupted) construction and ships as the default ranker. A reviewer-driven re-run
1373
+ (`by_negative_construction`) shows that gap is mostly the core-penalisation artifact; with the core held
1374
+ matched the non-core substitution-identity gain is real but modest (delta ~0.04, 0.687 vs 0.646). Both AUROCs
1375
+ carry a favourable-negative-set caveat (decoys derived from real off-targets; no non-recombining background).
1376
+ - **Bench v0.2 plus uncertainty-aware agent.** Four trust tasks (T8 calibration, T9 selective prediction,
1377
+ T10 OOD honesty, T11 out-of-scope refusal) contrasting the uncertainty-aware agent with an over-confident
1378
+ baseline (4/4); PEN-Agent emits confidence plus epistemic status plus abstains; UI surfaces them. Bench re-SHA-locked.
1379
+ - **Gymnasium interface (optional).** A thin `gymnasium.Env` over the planner (`pen_stack.env`,
1380
+ `[env]` extra) for agent-developer interoperability, interface only, no RL superiority claimed.
1381
+ - **Docs:** `docs/uncertainty.md`, `docs/scope.md`, `docs/mechanistic_constraints.md`; M-UQ methods note plus
1382
+ M1/M2 manuscript updates. The Opentrons workstream is deferred to `docs/BACKLOG.md`.
1383
+
1384
+ ### Changed
1385
+ - Version 3.1.0 to 3.2.0 (pyproject, `__init__`, CITATION.cff). README updated for v3.2; badges plus bench
1386
+ v0.2. The bridge off-target default ranker is now the energetics model when its penalty table is present.
1387
+
1388
+ ## [3.1.0] - 2026-06-04 - Publishable contributions plus an adopted benchmark
1389
+
1390
+ The v3.1 cycle completes (workstreams A-H). It hardens the planning benchmark, surrounds the
1391
+ models with strong baselines, adds a predicted-structure safety axis, and ships the first benchmark and
1392
+ grounded agent for the genome-writing side. Every workstream is pre-registered (`prereg/ws_*.yaml`,
1393
+ SHA-locked) and reports its negatives.
1394
+
1395
+ ### Added
1396
+ - **Strong baselines plus safety primary-metric switch.** An endogenous-expression baseline (TRIP-trained
1397
+ Spearman 0.51 vs AlphaGenome ES-Bruce4 proxy 0.43), a multi-mark ablation (all-marks >= best single), and a
1398
+ published GSH rule-set: safe-harbour discrimination (learned 0.92, 95% CI [0.82, 0.98] vs distance-rule
1399
+ 0.38, delta CI excludes zero) is now the primary safety metric; the circular `genotoxic_cis` AUROC is a
1400
+ labeled diagnostic. (`pen_stack.wgenome.gsh_baseline`, `pen_stack.validate.durability_baselines`.)
1401
+ - **AlphaGenome integration.** A hosted-API provider with an offline cache; predicted-vs-measured track
1402
+ validation (HepG2 ATAC Pearson 0.85) with a score-level low-confidence flag; a 3D structural-risk
1403
+ axis from contact-map deltas (`pen_stack.wgenome.{providers,chromatin_seq,structure3d}`,
1404
+ `pen_stack.validate.seq_vs_measured`).
1405
+ - **Cargo Polish.** A cargo-sequence silencing-risk scan (`pen_stack.planner.cargo_polish`).
1406
+ - **Genome-Writing Bench v0.1 plus PEN-Agent.** The first writing-side benchmark (`benchmarks/`,
1407
+ `bench/run.py`) with deterministic scorers, a leaderboard, and a real LLM-agent baseline; a grounded
1408
+ write-planning state machine with a no-fabrication hard gate (`pen_stack.agent.pen_agent`).
1409
+ - **Local recalibration / private-data adaptation.** Gated recalibration / fine-tuning on private
1410
+ data, in-container; the adapted model activates only if it beats the released model AND a no-skill
1411
+ baseline; the released model is provably unchanged (`pen_stack.adapt`).
1412
+ - **Multiplex plus guide QC.** A pairwise translocation-risk screen (`pen_stack.planner.multiplex`,
1413
+ surfaced in PEN-Agent) and a bridge-RNA guide ranker (`pen_stack.bridge.guide_qc`).
1414
+ - **Release plus dissemination.** README/badges updated for v3.1, `docs/quickstart.md`,
1415
+ `docs/positioning.md`, the leaderboard submission guide, the dissemination log, and version 3.1.0.
1416
+
1417
+ ### Changed
1418
+ - The planning benchmark's `recovery_at_k` ranking is now deterministic (stable sort plus tie-breakers).
1419
+ - The LLM stack defaults to the local Ollama model on the compute tier with an automatic hosted-Nemotron
1420
+ fallback, a cooldown cache, and bounded timeouts (no more multi-minute stalls when a provider is absent).
1421
+
1422
+ ## [3.1.0a0] - 2026-06-04 - De-circularize the planning benchmark (gate)
1423
+
1424
+ The v3.1 cycle (publishable contributions plus an adopted benchmark) opens with its gate: de-circularizing the
1425
+ Phase-3 planning benchmark before anything builds on it.
1426
+
1427
+ ### Changed
1428
+ - **The Phase-3 "discriminating-stratum recovery@10 = 1.00 vs 0.00 (McNemar p, CI)" is now labeled
1429
+ definitional, not predictive,** everywhere (README, manuscript abstract, `prereg/paper3.yaml`,
1430
+ `validate/paper3_benchmark.py` docstring). An on-target identity term dominates the score, so the planner
1431
+ ranks the goal's own gene first by construction. Documented in `docs/benchmark_circularity.md`.
1432
+ - The intent result is reframed as a specification-compliance correctness table (`validate/intent_specification.py`,
1433
+ 7/7), with no recovery/p-value/CI language.
1434
+
1435
+ ### Added (the non-circular replacements)
1436
+ - **Blind safe-harbour site discovery (the new lead result):** `validate/blind_gsh_discovery.py` plus
1437
+ `configs/gsh_validated_heldout.yaml` (5 DOI-validated held-out GSH, gene-anchored to hg38) plus a
1438
+ frozen/SHA-locked `data/gsh_matched_controls.parquet`. Run genome-wide (no on-target term), the planner's
1439
+ writability separates validated GSH from matched-context controls at AUROC 0.92 (safety-only 0.50).
1440
+ - **Diversified writer-family recovery:** `validate/writer_recovery.py` plus `data/writer_panel.csv` (8 writes,
1441
+ 4 families, DOIs). recovery@1 = 1.0 vs prevalence 0.25 (smallest-capacity DSB-free writer that fits
1442
+ the cargo).
1443
+ - **Within-locus ranking** (descriptive): `validate/within_locus_ranking.py`, AAVS1 documented bin at the
1444
+ 93rd within-locus percentile (top quartile); CLYBL at the 34th (a negative result).
1445
+ - **Consolidated report** `scripts/p3_benchmark_report.py` to `out/ws_a_report.md`; `prereg/ws_a.yaml` plus
1446
+ SHA lock. Gate G-A is met: blind AUROC reported, no circular claims remain.
1447
+
1448
+ ## [Unreleased] - 2026-06-03 - Reframing, repository polish, coverage, hybrid LLM
1449
+
1450
+ ### Added
1451
+ - **Hybrid LLM backend** (`pen_stack/rag/llm.py`, `configs/llm.yaml`): a strong hosted model for
1452
+ reasoning/agent/Q&A (NVIDIA Nemotron, OpenAI-compatible, free) with automatic fallback to the local
1453
+ Ollama model, then to the deterministic no-LLM path. One `provider` switch. The agent and RAG were
1454
+ refactored onto a single provider-agnostic `chat()` (NVIDIA tool-call IDs and Ollama native message
1455
+ threading both handled). The LLM stays non-load-bearing (every number/citation still comes from
1456
+ validated tools), so the model choice does not affect scientific reproducibility; it only improves
1457
+ orchestration (Nemotron planned a goal in 2 tool calls vs the local 7B's 8-call loop). Core scientific
1458
+ compute stays local/VM and uses no LLM. API keys are read from an env var or a gitignored file and
1459
+ are never committed.
1460
+
1461
+ ### Changed
1462
+ - **Paper 4 reframed to its scope.** `pen-bridge` is positioned as the first measured-data-validated
1463
+ tool that nominates and ranks candidate off-target locations for bridge recombinases, a
1464
+ screening tool, not a quantitative safety calculator. The AUROC 0.77 vs 0.62 result is stated with
1465
+ its caveat (favourable negative set; mostly tests core integrity), and the magnitude limitation
1466
+ (sequence-risk does not rank recombination amount, rho ~0.30) is named as the single most important
1467
+ limitation. Application-Note tier, first-of-its-kind for an unoccupied gap; the Writable Genome remains
1468
+ the flagship. Manuscript plus `prereg/paper4.yaml` plus summaries updated.
1469
+ - **Variant-effect reframed:** the DMS recovers KNOWN enhancers (a catalogue feature), it is not a novel
1470
+ variant-design method; EVOLVEpro is the engine to wrap when generating new variants.
1471
+ - **Repository made clean ASCII:** removed all decorative emojis and em/en dashes and other non-ASCII
1472
+ punctuation across code, docs, configs, and manuscripts (box-drawing tree characters kept).
1473
+
1474
+ ### Added
1475
+ - 72-system ortholog characterisation (`bridge/ortholog_screen.py`), explicitly descriptive (Table S1 has
1476
+ no activity label): sequence-similarity organisation vs the validated standout ISCro4 (IS621 ranks most
1477
+ similar, a sanity check). Exploratory secondary result, N ~72.
1478
+ - Coverage: CI runs `pytest --cov`, uploads to Codecov, and publishes a self-hosted coverage badge
1479
+ (`tools/make_coverage_badge.py` to `.github/badges/coverage.svg`). Unit-test coverage of the core logic
1480
+ is 69% (integration-only modules that need GPU/VM/network/LLM are excluded via `[tool.coverage.run]`).
1481
+ - Professional, emoji-free README with connected-repo badges (genome-atlas / mech-class / pen-score /
1482
+ pen-assemble / pen-compare), an architecture diagram, and the problem/gaps explanation.
1483
+
1484
+ ## [3.0.0a5] - 2026-06-02 - Phase 1.5 (Bridge-recombinase off-target engine, Paper 4)
1485
+
1486
+ The first public instrument: a bridge-recombinase off-target screening tool.
1487
+
1488
+ ### Added
1489
+ - **Off-target engine** (`pen_stack/bridge/offtarget.py` plus `configs/bridge_offtarget_profile.yaml`):
1490
+ a genome-wide hg38 pseudosite scan (CT-core seed, per-chromosome, memory-bounded) plus a position-weight
1491
+ risk model grounded in the published mechanism. Beats naive Hamming: AUROC 1.00 vs 0.59 at
1492
+ separating core-preserving (real-risk) from core-disrupting (abolished) sites. Exposes
1493
+ `predict_offtargets(family, site)`, completing the Phase-3 Planner cargo hook.
1494
+ - **Fold / cross-loop QC** (`bridge/fold_qc.py`): a ViennaRNA fold (verified MFE on a 190-nt design) plus
1495
+ TBL/DBL cross-loop complementarity.
1496
+ - **Activity framework** (`bridge/activity.py`): an exploratory DMS plus 72-system trainer (deferred; data paywalled).
1497
+ - **`pen-bridge`** (`bridge/pipeline.py`, `bridge/cli.py`, `/bridge/design` API): wraps the Arc
1498
+ BridgeRNADesigner (verified) and adds the off-target plus QC layer.
1499
+ - `validate/paper4_validation.py` plus `scripts/p4_genome_scan.py`; `prereg/paper4.yaml` plus SHA lock.
1500
+
1501
+ ### Notes
1502
+ - **Phase 1.5 complete.** The pre-registered criteria were met (or gated): the off-target engine,
1503
+ the ViennaRNA fold, and the designer wrap are verified on the VM (real hg38 scan: chr22 in ~21 s). The blind
1504
+ recall of Perry 2025's measured off-targets and the DMS/activity model are gated on the paywalled
1505
+ Perry 2025 supplementary (drop in via `ingest.load_offtarget_profile`). This completes the deferred Phase-2
1506
+ Section 2.4 and Phase-3 Section 3.2 hooks. 68 tests green; ruff clean. All program phases (0, 1, 1.5, 2, 3) now done.
1507
+
1508
+ ## [3.0.0a4] - 2026-06-02 - Phase 3 (The Write Planner plus agentic platform, Paper 3)
1509
+
1510
+ Inverse design plus the paper-defining recovery@k benchmark plus the agentic platform.
1511
+
1512
+ ### Added
1513
+ - **Inverse-design optimiser** (`pen_stack/planner/optimize.py`, `configs/intent_weights.yaml`): an
1514
+ `edit_intent`-conditioned objective whose `target_gene_sign` flips whether hitting the target gene is
1515
+ penalised or rewarded, so the same TRAC site ranks #1 (knock-in) vs #101 (safe-harbour).
1516
+ - **Cargo/delivery** (`planner/cargo.py`, `planner/delivery.py`): a donor spec plus size check plus a delivery rule
1517
+ table; bridge/seek off-target via an optional Phase-1.5 hook (pending until 1.5).
1518
+ - **End-to-end Planner** (`planner/pipeline.py`, `report.py`, `/plan` API, `pen-stack plan` CLI): ranked,
1519
+ fully traceable plans with per-field provenance.
1520
+ - **Two-stratum recovery@k benchmark** (`validate/paper3_benchmark.py`, `data/benchmark_panel.csv`,
1521
+ `prereg/paper3.yaml`): discriminating stratum planner 1.00 vs baseline 0.00, McNemar p=0.0156, gap CI
1522
+ [1.0,1.0] excludes zero; control tie 0.67=0.67. The panel is cited to Europe-PMC-verified sources.
1523
+ - **Forward hypotheses** (`validate/forward_hypotheses.py`): date-stamped novel F8/SERPINA1/CISH/HBA1
1524
+ proposals plus a grounded cited ranking.
1525
+ - **Agentic platform:** `agent/tools.py` plus `agent/orchestrator.py` (Ollama tool-calling, an auditable trace,
1526
+ no-fabrication, refusals), `agent/mcp_server.py` (fastmcp), `docker-compose.yml` plus `docker/ui.Dockerfile`
1527
+ plus a Streamlit Agent page plus `docs/DEPLOY.md`/`docs/MCP.md`, `validate/agent_eval.py`.
1528
+ - Shipped `data/curated/gene_coords.parquet` (GENCODE-derived) so tools work in any container.
1529
+
1530
+ ### Notes
1531
+ - **Phase 3 complete.** The pre-registered criteria were met (`prereg/paper3.yaml` plus `SHA256_LOCK_phase3.json`).
1532
+ The agent is verified on the VM in LLM mode (no-fabrication plus plan-equivalence plus refusals all pass). 63 tests
1533
+ green; ruff clean. Wet-lab (3.7) skipped, non-gating. The bridge off-target hook completes with Phase 1.5.
1534
+
1535
+ ## [3.0.0a3] - 2026-06-02 - Phase 2 (Writer Atlas plus Unified Stack, Paper 2)
1536
+
1537
+ The broad, cross-family Writer Atlas, the writer-to-locus cross-link, and the installable platform.
1538
+
1539
+ ### Added
1540
+ - **Writer Atlas** (`pen_stack/atlas/expand.py`, `atlas.parquet`): 33,370 systems across 8 families
1541
+ (31,885 IS110/IS1111 orthologs plus curated cores/reps), every row confidence-tagged plus at least 1 source DOI,
1542
+ targeting metadata inherited from the WT-KB. `configs/atlas_families.yaml` drives the UniProt queries.
1543
+ - **Mechanism at scale** (`pen_stack/mech/`): ported the audited 18-family Pfam whitelist v1.2.1; composite
1544
+ co-occurrence rules; core agreement 1.00 vs audited labels; conflicting calls go to a review queue.
1545
+ - **Therapeutic readiness** (`pen_stack/score/therapeutic.py`): deliverability/cargo/human-cell axes,
1546
+ components retained (ISCro4 326aa to AAV).
1547
+ - **Cross-link** (`pen_stack/atlas/crosslink.py`): bidirectional writer-to-locus queries; AAVS1 held-out
1548
+ check passes (0.90 writability plus bridge-reachable). Per-family caches for k562/hepg2/hspc.
1549
+ - **Variant proposal** (`pen_stack/atlas/variant_propose.py`): a point-mutation framework plus a retrospective
1550
+ harness, no chimeras; DMS model pluggable (Phase 1.5).
1551
+ - **PEN-MONITOR** (`pen_stack/monitor/`): a Europe PMC living-database engine; the back-test surfaces ISPpu10;
1552
+ never auto-edits the atlas; every candidate cited.
1553
+ - **Grounded RAG** (`pen_stack/rag/`, `pen_stack/agent/guardrails.py`): numbers from tool calls, claims
1554
+ cited, clinical directives refused; an optional Ollama/Qwen phrasing layer (presentation only).
1555
+ - **Stack:** unified CLI subcommands, a FastAPI server (`pen_stack/server/api.py`), a Streamlit platform UI
1556
+ (Writer Atlas plus Ask pages), an mkdocs site plus 4 use-case tutorials. 46 tests green; ruff clean.
1557
+
1558
+ ### Notes
1559
+ - **Phase 2 complete.** The pre-registered criteria were met (`prereg/paper2.yaml` plus `SHA256_LOCK_phase2.json`);
1560
+ the atlas Zenodo DOI is pending author upload. Verified on the VM (Docker): API, UI (:8501), RAG with Qwen.
1561
+
1562
+ ## [3.0.0a0] - 2026-06-01 - Phase 0 (in progress)
1563
+
1564
+ A fresh v3.0 monorepo. It supersedes the v1.0 platform repository (archived) and consolidates the five prior
1565
+ repositories (`genome-atlas`, `mech-class`, `pen-score`, `pen-assemble`, `pen-compare`) as provenance.
1566
+
1567
+ ### Added
1568
+ - A monorepo scaffold: 13 modules (`atlas`, `mech`, `score`, `wgenome`, `planner`, `bridge`, `monitor`,
1569
+ `rag`, `agent`, `ui`, `data`, `validate`, `server`), `pyproject.toml`, a Docker image spec, the `penctl`
1570
+ laptop-to-VM orchestrator, CI, `configs/`, `prereg/`.
1571
+ - `docs/INFRA.md`: the three-tier (laptop / VM / Drive) Docker-only, SFTP-only workflow.
1572
+ - `configs/llm.yaml`: a single LLM switch (Ollama plus Qwen2.5-7B-Instruct, Apache-2.0).
1573
+ - `configs/datasets.yaml`: pinned dataset accessions plus verified IDs (see VERIFICATION_REPORT_v3.0).
1574
+ - **WT-KB** (`pen_stack/atlas/`): 8 fully-sourced writer families with reachability tiers; the schema enforces the at-least-1-DOI sourcing rule.
1575
+ - **Re-grounded axes** (`pen_stack/score/recalibrate.py`, `configs/score_axes.yaml`): `S_Cargo` from measured bp, `S_Prog` from targeting modality, `length_aa` backfilled, no per-enzyme overrides.
1576
+ - **Canonical universe** (`pen_stack/atlas/universe.py::assemble`): one path joining the 1,058-entity universe plus WT-KB plus crosswalk; a cross-module consistency test.
1577
+ - **Descriptive scorecard** (`pen_stack/atlas/scorecard.py`): reframed from the circular certification; blind concordance recovers ISCro4 as the bridge standout without naming it. 21 tests green.
1578
+
1579
+ ### Notes
1580
+ - Independent verification of all datasets/IDs/DOIs/tools completed: no critical errors in the v3.0 plan
1581
+ (full report in `Final_Part_v3.0/VERIFICATION_REPORT_v3.0.md`).
1582
+ - **Phase 0 complete.** All pre-registered success criteria were met (`prereg/phase0.yaml` plus SHA lock).