pen-stack 6.1.0__tar.gz → 6.2.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 (444) hide show
  1. {pen_stack-6.1.0 → pen_stack-6.2.0}/CHANGELOG.md +37 -0
  2. {pen_stack-6.1.0 → pen_stack-6.2.0}/CITATION.cff +1 -1
  3. {pen_stack-6.1.0 → pen_stack-6.2.0}/PKG-INFO +28 -6
  4. {pen_stack-6.1.0 → pen_stack-6.2.0}/README.md +27 -5
  5. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/__init__.py +1 -1
  6. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/server/api.py +26 -0
  7. pen_stack-6.2.0/pen_stack/web/__init__.py +18 -0
  8. pen_stack-6.2.0/pen_stack/web/llm.py +219 -0
  9. pen_stack-6.2.0/pen_stack/web/server.py +86 -0
  10. pen_stack-6.2.0/pen_stack/web/tools.py +102 -0
  11. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack.egg-info/PKG-INFO +28 -6
  12. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack.egg-info/SOURCES.txt +8 -0
  13. pen_stack-6.2.0/prereg/SHA256_LOCK_ws_chat.json +8 -0
  14. pen_stack-6.2.0/prereg/SHA256_LOCK_ws_frontend.json +8 -0
  15. pen_stack-6.2.0/prereg/ws_chat.yaml +20 -0
  16. pen_stack-6.2.0/prereg/ws_frontend.yaml +21 -0
  17. {pen_stack-6.1.0 → pen_stack-6.2.0}/pyproject.toml +1 -1
  18. {pen_stack-6.1.0 → pen_stack-6.2.0}/LICENSE +0 -0
  19. {pen_stack-6.1.0 → pen_stack-6.2.0}/MANIFEST.in +0 -0
  20. {pen_stack-6.1.0 → pen_stack-6.2.0}/bench/run.py +0 -0
  21. {pen_stack-6.1.0 → pen_stack-6.2.0}/benchmarks/genome_writing_bench/LEADERBOARD.md +0 -0
  22. {pen_stack-6.1.0 → pen_stack-6.2.0}/benchmarks/genome_writing_bench/README.md +0 -0
  23. {pen_stack-6.1.0 → pen_stack-6.2.0}/benchmarks/genome_writing_bench/SHA256SUMS +0 -0
  24. {pen_stack-6.1.0 → pen_stack-6.2.0}/benchmarks/genome_writing_bench/SUBMISSIONS.md +0 -0
  25. {pen_stack-6.1.0 → pen_stack-6.2.0}/benchmarks/genome_writing_bench/tasks.yaml +0 -0
  26. {pen_stack-6.1.0 → pen_stack-6.2.0}/benchmarks/genome_writing_challenge/README.md +0 -0
  27. {pen_stack-6.1.0 → pen_stack-6.2.0}/benchmarks/genome_writing_challenge/SUBMISSIONS.md +0 -0
  28. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/antipeg.yaml +0 -0
  29. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/atlas_families.yaml +0 -0
  30. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/bridge_offtarget_profile.yaml +0 -0
  31. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/capsid_epitope_oracle.yaml +0 -0
  32. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/capsid_sequences.fasta +0 -0
  33. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/cargo_polish.yaml +0 -0
  34. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/cell_types.yaml +0 -0
  35. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/datasets.yaml +0 -0
  36. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/delivery_constraints.yaml +0 -0
  37. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/delivery_rules.yaml +0 -0
  38. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/delivery_vehicles.yaml +0 -0
  39. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/gates_v3.yaml +0 -0
  40. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/genotoxicity_oracle.yaml +0 -0
  41. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/gsh_validated_heldout.yaml +0 -0
  42. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/intent_weights.yaml +0 -0
  43. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/known_unknowns.yaml +0 -0
  44. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/llm.yaml +0 -0
  45. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/monitor_queries.yaml +0 -0
  46. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/oracles/scope_cards.yaml +0 -0
  47. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/rules/delivery.yaml +0 -0
  48. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/rules/fold.yaml +0 -0
  49. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/rules/multiplex.yaml +0 -0
  50. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/rules/payload.yaml +0 -0
  51. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/rules/reachability.yaml +0 -0
  52. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/safety/hazard_registry.yaml +0 -0
  53. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/safety/policy.yaml +0 -0
  54. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/safety/probes.yaml +0 -0
  55. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/score_axes.yaml +0 -0
  56. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/seroprevalence.yaml +0 -0
  57. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/target_sites.yaml +0 -0
  58. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/universe_crosswalk.yaml +0 -0
  59. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/write_types.yaml +0 -0
  60. {pen_stack-6.1.0 → pen_stack-6.2.0}/configs/wtkb_curated.yaml +0 -0
  61. {pen_stack-6.1.0 → pen_stack-6.2.0}/data/curated/bridge_offtarget_energetics.json +0 -0
  62. {pen_stack-6.1.0 → pen_stack-6.2.0}/data/curated/bridge_offtarget_profile_measured.parquet +0 -0
  63. {pen_stack-6.1.0 → pen_stack-6.2.0}/data/curated/gene_coords.parquet +0 -0
  64. {pen_stack-6.1.0 → pen_stack-6.2.0}/data/curated/unified_editor_universe.parquet +0 -0
  65. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/BACKLOG.md +0 -0
  66. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/DEPLOY.md +0 -0
  67. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/INFRA.md +0 -0
  68. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/MCP.md +0 -0
  69. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/RELEASING.md +0 -0
  70. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/REPRO.md +0 -0
  71. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/STABILITY.md +0 -0
  72. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/agent.md +0 -0
  73. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/alphagenome_feasibility.md +0 -0
  74. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/autonomy.md +0 -0
  75. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/benchmark_circularity.md +0 -0
  76. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/biosecurity.md +0 -0
  77. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/build_interface.md +0 -0
  78. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/cards/atlas.md +0 -0
  79. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/cards/durability.md +0 -0
  80. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/cards/safety.md +0 -0
  81. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/challenge.md +0 -0
  82. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/closed_loop.md +0 -0
  83. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/co_scientist.md +0 -0
  84. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/co_scientist_loop.md +0 -0
  85. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/delivery.md +0 -0
  86. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/delivery_immunology.md +0 -0
  87. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/digital_twin.md +0 -0
  88. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/dissemination.md +0 -0
  89. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/environment.md +0 -0
  90. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/experiment_design.md +0 -0
  91. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/generative_design.md +0 -0
  92. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/index.md +0 -0
  93. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/integrations.md +0 -0
  94. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/mechanistic_constraints.md +0 -0
  95. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/oracles.md +0 -0
  96. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/positioning.md +0 -0
  97. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/private_data_formats.md +0 -0
  98. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/quickstart.md +0 -0
  99. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/responsible_use.md +0 -0
  100. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/rules.md +0 -0
  101. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/scope.md +0 -0
  102. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/scorecard.md +0 -0
  103. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/tutorials/compare-families.md +0 -0
  104. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/tutorials/score-deliverability.md +0 -0
  105. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/tutorials/where-can-i-write.md +0 -0
  106. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/tutorials/which-writer-reaches-locus.md +0 -0
  107. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/uncertainty.md +0 -0
  108. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/verify.md +0 -0
  109. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/world_model.md +0 -0
  110. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/writer_verification.md +0 -0
  111. {pen_stack-6.1.0 → pen_stack-6.2.0}/docs/wtkb.md +0 -0
  112. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/_resources.py +0 -0
  113. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/active/__init__.py +0 -0
  114. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/active/acquire.py +0 -0
  115. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/active/design.py +0 -0
  116. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/active/validate.py +0 -0
  117. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/adapt/__init__.py +0 -0
  118. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/adapt/finetune.py +0 -0
  119. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/adapt/ingest.py +0 -0
  120. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/adapt/pipeline.py +0 -0
  121. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/adapt/recalibrate.py +0 -0
  122. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/adapt/report.py +0 -0
  123. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/agent/__init__.py +0 -0
  124. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/agent/cite.py +0 -0
  125. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/agent/co_scientist.py +0 -0
  126. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/agent/epistemic.py +0 -0
  127. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/agent/guardrails.py +0 -0
  128. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/agent/mcp_server.py +0 -0
  129. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/agent/orchestrator.py +0 -0
  130. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/agent/orchestrator_live.py +0 -0
  131. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/agent/pen_agent.py +0 -0
  132. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/agent/scope.py +0 -0
  133. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/agent/tools.py +0 -0
  134. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/api/__init__.py +0 -0
  135. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/api/manifest.py +0 -0
  136. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/atlas/__init__.py +0 -0
  137. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/atlas/build_wtkb.py +0 -0
  138. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/atlas/crosslink.py +0 -0
  139. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/atlas/expand.py +0 -0
  140. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/atlas/schema.py +0 -0
  141. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/atlas/scorecard.py +0 -0
  142. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/atlas/universe.py +0 -0
  143. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/atlas/variant_propose.py +0 -0
  144. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/atlas/writer_verify.py +0 -0
  145. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/bridge/__init__.py +0 -0
  146. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/bridge/activity.py +0 -0
  147. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/bridge/cli.py +0 -0
  148. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/bridge/fold_qc.py +0 -0
  149. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/bridge/guide_qc.py +0 -0
  150. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/bridge/ingest.py +0 -0
  151. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/bridge/offtarget.py +0 -0
  152. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/bridge/offtarget_energetics.py +0 -0
  153. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/bridge/ortholog_screen.py +0 -0
  154. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/bridge/pipeline.py +0 -0
  155. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/build/__init__.py +0 -0
  156. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/build/ingest.py +0 -0
  157. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/build/protocol.py +0 -0
  158. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/build/simlab.py +0 -0
  159. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/cli.py +0 -0
  160. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/data/__init__.py +0 -0
  161. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/data/encode.py +0 -0
  162. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/data/genome.py +0 -0
  163. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/data/ingest_chromatin.py +0 -0
  164. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/data/ingest_integration.py +0 -0
  165. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/data/ingest_safety_annot.py +0 -0
  166. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/data/ingest_trip.py +0 -0
  167. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/design/__init__.py +0 -0
  168. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/design/generate.py +0 -0
  169. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/design/pareto.py +0 -0
  170. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/design/space.py +0 -0
  171. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/env/__init__.py +0 -0
  172. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/env/genome_writing_env.py +0 -0
  173. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/env/policies.py +0 -0
  174. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/graph/__init__.py +0 -0
  175. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/graph/build.py +0 -0
  176. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/graph/cell_types.py +0 -0
  177. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/graph/ingest.py +0 -0
  178. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/graph/query.py +0 -0
  179. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/graph/schema.py +0 -0
  180. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/loop/__init__.py +0 -0
  181. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/loop/continual.py +0 -0
  182. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/loop/cycle.py +0 -0
  183. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/loop/drift.py +0 -0
  184. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/mech/__init__.py +0 -0
  185. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/mech/classify_atlas.py +0 -0
  186. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/mech/whitelist.py +0 -0
  187. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/monitor/__init__.py +0 -0
  188. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/monitor/europepmc.py +0 -0
  189. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/monitor/run.py +0 -0
  190. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/monitor/triage.py +0 -0
  191. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/oracles/__init__.py +0 -0
  192. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/oracles/cache.py +0 -0
  193. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/oracles/energetics.py +0 -0
  194. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/oracles/genome.py +0 -0
  195. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/oracles/protein_design.py +0 -0
  196. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/oracles/rna.py +0 -0
  197. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/oracles/schema.py +0 -0
  198. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/oracles/structure.py +0 -0
  199. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/oracles/vcell.py +0 -0
  200. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/__init__.py +0 -0
  201. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/antipeg_oracle.py +0 -0
  202. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/capsid_epitope_oracle.py +0 -0
  203. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/cargo.py +0 -0
  204. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/cargo_polish.py +0 -0
  205. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/delivery.py +0 -0
  206. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/delivery_constraints.py +0 -0
  207. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/delivery_immunology.py +0 -0
  208. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/delivery_vehicles.py +0 -0
  209. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/genotoxicity_oracle.py +0 -0
  210. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/immune_profile.py +0 -0
  211. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/innate_sensing.py +0 -0
  212. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/multiplex.py +0 -0
  213. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/optimize.py +0 -0
  214. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/pipeline.py +0 -0
  215. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/report.py +0 -0
  216. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/router.py +0 -0
  217. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/seroprevalence_oracle.py +0 -0
  218. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/planner/target_site.py +0 -0
  219. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/rag/__init__.py +0 -0
  220. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/rag/index.py +0 -0
  221. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/rag/llm.py +0 -0
  222. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/rag/qa.py +0 -0
  223. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/rules/__init__.py +0 -0
  224. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/rules/evaluators.py +0 -0
  225. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/rules/loader.py +0 -0
  226. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/rules/schema.py +0 -0
  227. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/rules/solver.py +0 -0
  228. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/safety/__init__.py +0 -0
  229. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/safety/audit.py +0 -0
  230. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/safety/gate.py +0 -0
  231. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/safety/policy.py +0 -0
  232. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/safety/redteam.py +0 -0
  233. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/safety/registry.py +0 -0
  234. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/safety/screen.py +0 -0
  235. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/score/__init__.py +0 -0
  236. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/score/recalibrate.py +0 -0
  237. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/score/therapeutic.py +0 -0
  238. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/server/__init__.py +0 -0
  239. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/twin/__init__.py +0 -0
  240. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/twin/calibrate.py +0 -0
  241. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/twin/mechanistic.py +0 -0
  242. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/twin/outcome.py +0 -0
  243. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/ui/__init__.py +0 -0
  244. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/ui/app.py +0 -0
  245. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/__init__.py +0 -0
  246. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/adapt_demo.py +0 -0
  247. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/agent_eval.py +0 -0
  248. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/bench_adversarial_tasks.py +0 -0
  249. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/bench_coscientist_tasks.py +0 -0
  250. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/bench_graph_tasks.py +0 -0
  251. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/bench_rule_tasks.py +0 -0
  252. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/bench_trust_tasks.py +0 -0
  253. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/bench_writetype_tasks.py +0 -0
  254. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/blind_gsh_discovery.py +0 -0
  255. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/cargo_directionality.py +0 -0
  256. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/closed_loop.py +0 -0
  257. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/durability_baselines.py +0 -0
  258. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/experiment_design.py +0 -0
  259. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/forward_hypotheses.py +0 -0
  260. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/generative_design.py +0 -0
  261. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/guide_qc_demo.py +0 -0
  262. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/immune_calibration.py +0 -0
  263. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/intent_specification.py +0 -0
  264. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/offtarget_energetics_eval.py +0 -0
  265. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/out_of_scope_refusal.py +0 -0
  266. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/outcome_calibration.py +0 -0
  267. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/outcome_prediction.py +0 -0
  268. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/paper3_benchmark.py +0 -0
  269. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/paper4_real_validation.py +0 -0
  270. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/paper4_validation.py +0 -0
  271. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/protocol_safety.py +0 -0
  272. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/safety_screening.py +0 -0
  273. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/selective_prediction.py +0 -0
  274. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/seq_vs_measured.py +0 -0
  275. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/target_site_controls.py +0 -0
  276. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/uncertainty_eval.py +0 -0
  277. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/ungrounded_baseline.py +0 -0
  278. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/within_locus_ranking.py +0 -0
  279. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/validate/writer_recovery.py +0 -0
  280. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/verify/__init__.py +0 -0
  281. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/verify/schema.py +0 -0
  282. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/verify/service.py +0 -0
  283. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/wgenome/__init__.py +0 -0
  284. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/wgenome/chromatin_seq.py +0 -0
  285. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/wgenome/durability.py +0 -0
  286. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/wgenome/export_tracks.py +0 -0
  287. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/wgenome/features.py +0 -0
  288. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/wgenome/gsh_baseline.py +0 -0
  289. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/wgenome/mesh_features.py +0 -0
  290. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/wgenome/ood.py +0 -0
  291. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/wgenome/providers.py +0 -0
  292. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/wgenome/safety.py +0 -0
  293. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/wgenome/structure3d.py +0 -0
  294. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/wgenome/uncertainty.py +0 -0
  295. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack/wgenome/writability.py +0 -0
  296. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack.egg-info/dependency_links.txt +0 -0
  297. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack.egg-info/entry_points.txt +0 -0
  298. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack.egg-info/requires.txt +0 -0
  299. {pen_stack-6.1.0 → pen_stack-6.2.0}/pen_stack.egg-info/top_level.txt +0 -0
  300. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_phase0.json +0 -0
  301. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_phase1_5.json +0 -0
  302. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_phase2.json +0 -0
  303. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_phase3.json +0 -0
  304. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_a.json +0 -0
  305. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_acq.json +0 -0
  306. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_aldesign.json +0 -0
  307. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_alvalidate.json +0 -0
  308. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_atlas.json +0 -0
  309. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_b.json +0 -0
  310. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_ba.json +0 -0
  311. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_ba_v33.json +0 -0
  312. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_ba_v45.json +0 -0
  313. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_bench.json +0 -0
  314. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_c.json +0 -0
  315. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_cal.json +0 -0
  316. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_calib.json +0 -0
  317. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_challenge.json +0 -0
  318. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_cite.json +0 -0
  319. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_continual.json +0 -0
  320. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_cosci2.json +0 -0
  321. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_crit.json +0 -0
  322. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_ct.json +0 -0
  323. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_d.json +0 -0
  324. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_drift.json +0 -0
  325. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_e.json +0 -0
  326. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_env.json +0 -0
  327. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_ep.json +0 -0
  328. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_epitope.json +0 -0
  329. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_f.json +0 -0
  330. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_g.json +0 -0
  331. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_gen.json +0 -0
  332. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_genotox.json +0 -0
  333. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_graph.json +0 -0
  334. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_h.json +0 -0
  335. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_immune.json +0 -0
  336. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_ingest.json +0 -0
  337. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_innate.json +0 -0
  338. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_loop.json +0 -0
  339. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_manifest.json +0 -0
  340. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_mc.json +0 -0
  341. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_mcp.json +0 -0
  342. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_mech.json +0 -0
  343. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_mon.json +0 -0
  344. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_o.json +0 -0
  345. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_openapi.json +0 -0
  346. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_orch.json +0 -0
  347. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_outcome.json +0 -0
  348. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_pareto.json +0 -0
  349. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_peg.json +0 -0
  350. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_plan.json +0 -0
  351. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_policy.json +0 -0
  352. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_profile.json +0 -0
  353. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_proto.json +0 -0
  354. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_r.json +0 -0
  355. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_redteam.json +0 -0
  356. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_route.json +0 -0
  357. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_screen.json +0 -0
  358. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_seroprev.json +0 -0
  359. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_simlab.json +0 -0
  360. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_twincal.json +0 -0
  361. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_uq.json +0 -0
  362. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_v.json +0 -0
  363. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_vcell.json +0 -0
  364. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/SHA256_LOCK_ws_wv.json +0 -0
  365. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/paper1.yaml +0 -0
  366. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/paper2.yaml +0 -0
  367. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/paper3.yaml +0 -0
  368. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/paper4.yaml +0 -0
  369. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/phase0.yaml +0 -0
  370. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_a.yaml +0 -0
  371. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_acq.yaml +0 -0
  372. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_aldesign.yaml +0 -0
  373. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_alvalidate.yaml +0 -0
  374. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_atlas.yaml +0 -0
  375. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_b.yaml +0 -0
  376. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_ba.yaml +0 -0
  377. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_ba_v33.yaml +0 -0
  378. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_ba_v45.yaml +0 -0
  379. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_bench.yaml +0 -0
  380. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_c.yaml +0 -0
  381. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_cal.yaml +0 -0
  382. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_calib.yaml +0 -0
  383. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_challenge.yaml +0 -0
  384. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_cite.yaml +0 -0
  385. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_continual.yaml +0 -0
  386. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_cosci2.yaml +0 -0
  387. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_crit.yaml +0 -0
  388. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_ct.yaml +0 -0
  389. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_d.yaml +0 -0
  390. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_drift.yaml +0 -0
  391. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_e.yaml +0 -0
  392. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_env.yaml +0 -0
  393. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_ep.yaml +0 -0
  394. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_epitope.yaml +0 -0
  395. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_f.yaml +0 -0
  396. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_g.yaml +0 -0
  397. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_gen.yaml +0 -0
  398. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_genotox.yaml +0 -0
  399. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_graph.yaml +0 -0
  400. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_h.yaml +0 -0
  401. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_immune.yaml +0 -0
  402. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_ingest.yaml +0 -0
  403. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_innate.yaml +0 -0
  404. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_loop.yaml +0 -0
  405. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_manifest.yaml +0 -0
  406. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_mc.yaml +0 -0
  407. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_mcp.yaml +0 -0
  408. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_mech.yaml +0 -0
  409. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_mon.yaml +0 -0
  410. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_o.yaml +0 -0
  411. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_openapi.yaml +0 -0
  412. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_orch.yaml +0 -0
  413. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_outcome.yaml +0 -0
  414. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_pareto.yaml +0 -0
  415. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_peg.yaml +0 -0
  416. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_plan.yaml +0 -0
  417. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_policy.yaml +0 -0
  418. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_profile.yaml +0 -0
  419. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_proto.yaml +0 -0
  420. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_r.yaml +0 -0
  421. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_redteam.yaml +0 -0
  422. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_route.yaml +0 -0
  423. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_screen.yaml +0 -0
  424. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_seroprev.yaml +0 -0
  425. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_simlab.yaml +0 -0
  426. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_twincal.yaml +0 -0
  427. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_uq.yaml +0 -0
  428. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_v.yaml +0 -0
  429. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_vcell.yaml +0 -0
  430. {pen_stack-6.1.0 → pen_stack-6.2.0}/prereg/ws_wv.yaml +0 -0
  431. {pen_stack-6.1.0 → pen_stack-6.2.0}/scripts/p1_build_atlas.py +0 -0
  432. {pen_stack-6.1.0 → pen_stack-6.2.0}/scripts/p1_build_durability.py +0 -0
  433. {pen_stack-6.1.0 → pen_stack-6.2.0}/scripts/p1_export_tracks.py +0 -0
  434. {pen_stack-6.1.0 → pen_stack-6.2.0}/scripts/p1_safety_concordance.py +0 -0
  435. {pen_stack-6.1.0 → pen_stack-6.2.0}/scripts/p1_train_safety.py +0 -0
  436. {pen_stack-6.1.0 → pen_stack-6.2.0}/scripts/p1_validation_report.py +0 -0
  437. {pen_stack-6.1.0 → pen_stack-6.2.0}/scripts/p2_build_atlas.py +0 -0
  438. {pen_stack-6.1.0 → pen_stack-6.2.0}/scripts/p3_benchmark_report.py +0 -0
  439. {pen_stack-6.1.0 → pen_stack-6.2.0}/scripts/p4_genome_scan.py +0 -0
  440. {pen_stack-6.1.0 → pen_stack-6.2.0}/scripts/p52_build_genotox_oracle.py +0 -0
  441. {pen_stack-6.1.0 → pen_stack-6.2.0}/scripts/p53_build_epitope_oracle.py +0 -0
  442. {pen_stack-6.1.0 → pen_stack-6.2.0}/scripts/ws_b_report.py +0 -0
  443. {pen_stack-6.1.0 → pen_stack-6.2.0}/scripts/ws_c_report.py +0 -0
  444. {pen_stack-6.1.0 → pen_stack-6.2.0}/setup.cfg +0 -0
@@ -3,6 +3,43 @@
3
3
  All notable changes to PEN-STACK are documented here. This file follows
4
4
  [Keep a Changelog](https://keepachangelog.com/) and the program's phase structure.
5
5
 
6
+ ## [6.2.0] - 2026-06-11 - v6.2: The Web Platform (the human surface)
7
+
8
+ **Post-1.0 adoption surface for bench scientists.** A complete, friendly web application — a grounded co-scientist
9
+ chat plus structured feature pages — over the same typed v6.1 API the AI surface uses. The LLM **narrates and
10
+ routes but never sources a number**; every quantitative answer renders with its confidence band, provenance, and
11
+ an explicit ledger of what PEN-STACK can't tell you. MINOR release on the stable 6.0 API. Workstreams
12
+ WS-{BACKEND,CHAT,FRONTEND,PAGES,DEPLOY}, SHA-locked.
13
+
14
+ ### Added
15
+ - **WS-BACKEND** — `pen_stack/web/server.py`: one FastAPI gateway that **mounts the v6.1 engine surface** under
16
+ `/api` (so the frontend has one base URL / one OpenAPI) and adds the grounded `/chat` (+ SSE `/chat/stream`),
17
+ CORS, and static serving of the built frontend (`web/dist`). A `/health` for the live grounded indicator.
18
+ - **WS-CHAT** *(the hard gate)* — `pen_stack/web/tools.py` (the deterministic engine tool-runner: parse a goal →
19
+ run `verify`/`safety`/`immune_profile`/scope → a grounded dossier; `extract_grounded_numbers` = the allow-list)
20
+ and `pen_stack/web/llm.py` (the grounded co-scientist: **Ollama → Nemotron → deterministic narrator**, with
21
+ `_enforce_grounding` striking any numeric token the model can't trace to a tool result). A reply's numbers are
22
+ always engine-sourced; `tests/unit/test_ws_chat.py` asserts **no number in a reply is absent from the tool
23
+ results**, and that the deterministic narrator works with both LLMs offline.
24
+ - **WS-FRONTEND** — `web/` (React/Vite + Tailwind): the **honest-UX component library** — `ConfidenceBand`,
25
+ `ProvenanceChip`, `ScopeLedger`, `SafetyBadge`, `ImmuneProfileCard` — so a number is never shown without its
26
+ uncertainty + provenance, and the scope ledger appears on every answer.
27
+ - **WS-PAGES** — 11 feature pages over the typed API: Co-Scientist · Site Finder · Writer Atlas · Designer ·
28
+ Verify · Delivery & Immunity · Digital Twin · Guardian · Experiments · Challenge · Scope & About. Each renders
29
+ through the honest-UX library and degrades gracefully when the LLM is offline.
30
+ - **WS-DEPLOY** — `docker/web.Dockerfile` (multi-stage: a **node:20** stage builds the frontend, a slim Python
31
+ serves UI + API from one origin) + a `web` service in `docker-compose.yml`: **one-command self-host**
32
+ (`docker compose up web ollama`, open `http://localhost:8000`). `web/.env.example`, `web/README.md` quickstart.
33
+ - Read-only Challenge surface for the web page: `GET /api/challenge/{tasks,leaderboard}` (public tasks + the
34
+ PEN-STACK reference leaderboard; submissions are still scored offline, never accepted over HTTP).
35
+ - prereg `ws_{chat,frontend}` + SHA locks; deposit `phase_6.2/`.
36
+
37
+ ### Notes
38
+ - **The LLM never sources a number.** It explains, compares, and routes over the engine's tool outputs; the
39
+ grounding guard strips any value it can't trace, and the app runs in a deterministic, no-LLM mode (the science
40
+ lives in the engine, not the model). This cycle improves **usability/adoption**, not validation — a real-data
41
+ result and a first lab user remain the standing bottleneck. No new science; contracts under the 1.0 commitment.
42
+
6
43
  ## [6.1.0] - 2026-06-11 - v6.1: The AI Integration Surface
7
44
 
8
45
  **Post-1.0 adoption surface for AI builders.** Not new capability — the *introspectable, documented, dependable*
@@ -1,7 +1,7 @@
1
1
  cff-version: 1.2.0
2
2
  message: "If you use PEN-STACK, please cite it as below."
3
3
  title: "PEN-STACK: open infrastructure for genome writing"
4
- version: 6.1.0
4
+ version: 6.2.0
5
5
  date-released: 2026-06-11
6
6
  authors:
7
7
  - family-names: "Mahaboob Ali"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pen-stack
3
- Version: 6.1.0
3
+ Version: 6.2.0
4
4
  Summary: Open infrastructure for genome writing: the Writable Genome atlas, the Writer Atlas, and the Write Planner.
5
5
  Author-email: Anees Ahmed Mahaboob Ali <ahmedaneesm@gmail.com>
6
6
  License: MIT
@@ -90,9 +90,9 @@ every design against rule-grounded mechanism, reports calibrated confidence, cit
90
90
  [![codecov](https://codecov.io/gh/ahmedanees-m/pen-stack/branch/main/graph/badge.svg)](https://codecov.io/gh/ahmedanees-m/pen-stack)
91
91
  [![License: MIT](https://img.shields.io/badge/License-MIT-informational.svg)](LICENSE)
92
92
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
93
- [![Version](https://img.shields.io/badge/version-6.1.0-blue.svg)](CHANGELOG.md)
93
+ [![Version](https://img.shields.io/badge/version-6.2.0-blue.svg)](CHANGELOG.md)
94
94
  [![Status](https://img.shields.io/badge/status-1.0%20First%20Stable-success.svg)](docs/STABILITY.md)
95
- [![Tests](https://img.shields.io/badge/tests-360%20passing-success.svg)](tests/)
95
+ [![Tests](https://img.shields.io/badge/tests-368%20passing-success.svg)](tests/)
96
96
  [![Lint: ruff](https://img.shields.io/badge/lint-ruff-purple.svg)](https://github.com/astral-sh/ruff)
97
97
  [![Runtime: Docker](https://img.shields.io/badge/runtime-docker-2496ED.svg)](docker/)
98
98
  [![Validation: pre-registered](https://img.shields.io/badge/validation-pre--registered-critical.svg)](prereg/)
@@ -148,6 +148,26 @@ demonstrated (v5.12) and the benchmark went public (v5.13).
148
148
  > unknown funnel remains — made legible (scope flags, known-unknowns, honest baselines, no fabrication), not
149
149
  > hidden.
150
150
 
151
+ ## What is new in v6.2 — The Web Platform (the human surface)
152
+
153
+ Post-1.0, the adoption surface for **bench scientists**: a complete, friendly **web application** — a grounded
154
+ co-scientist chat plus structured feature pages — over the same typed v6.1 API the AI surface uses. The LLM
155
+ **narrates and routes but never sources a number**; every quantitative answer renders with its confidence band,
156
+ its provenance, and an explicit ledger of what PEN-STACK *can't* tell you.
157
+
158
+ | Workstream | What it adds | Result |
159
+ |---|---|---|
160
+ | **BACKEND** | `pen_stack/web/server.py` | one FastAPI gateway that mounts the v6.1 engine surface (under `/api`) + adds the grounded `/chat` (+ SSE `/chat/stream`) + CORS + serves the built frontend |
161
+ | **CHAT** *(the hard gate)* | `pen_stack/web/{tools,llm}.py` | the grounded co-scientist: the **engine** computes every number (`run_tools`), the LLM narrates over the tool results (**Ollama → Nemotron → deterministic**), and a **grounding guard strikes any number the model can't trace to a tool result** (asserted in `tests/unit/test_ws_chat.py`) |
162
+ | **FRONTEND** | `web/` (React/Vite + Tailwind) | the **honest-UX library** — `ConfidenceBand · ProvenanceChip · ScopeLedger · SafetyBadge · ImmuneProfileCard` — so a number is never shown without its uncertainty + provenance |
163
+ | **PAGES** | 11 feature pages | Co-Scientist · Site Finder · Writer Atlas · Designer · Verify · Delivery & Immunity · Digital Twin · Guardian · Experiments · Challenge · Scope & About |
164
+ | **DEPLOY** | `docker/web.Dockerfile` + compose | **one-command self-host**: a `node:20` stage builds the frontend, a slim Python serves UI + API from one origin — `docker compose up web ollama`, open `http://localhost:8000` |
165
+
166
+ **The LLM never sources a number** — it explains, compares, and routes over the engine's tool outputs, and the
167
+ science runs (deterministic mode) with no LLM at all. See [`web/README.md`](web/README.md) and
168
+ `prereg/ws_{chat,frontend}.yaml`. (Lowers the usability barrier; a real-data validation + a first lab user remain
169
+ the standing bottleneck — no new science.)
170
+
151
171
  ## What is new in v6.1 — The AI Integration Surface
152
172
 
153
173
  Post-1.0, the adoption surface for **AI builders**: PEN-STACK is now **self-describing** — an external agent can
@@ -780,13 +800,15 @@ pen-stack/
780
800
  │ │ v5.12 closed_loop (loop-integrity hard-gate: gated end-to-end run · Level-3 human-in-control · drift detection · versioned/reversible continual learning)
781
801
  │ ├── data/ ingestion (genome, chromatin, integration, TRIP, safety annotations)
782
802
  │ ├── api/ v6.1 AI integration surface: manifest (capability_manifest + scope_manifest = machine-readable known-unknowns + oracle scope cards)
783
- │ ├── server/api.py FastAPI REST (atlas, crosslink, writable, plan, bridge, ask; v3.3 verify; v6.1 /capabilities /scope /safety /immune /generate /predict /suggest /session + openapi.json 3.1)
803
+ │ ├── web/ v6.2 Web Platform backend: tools (deterministic engine dossier) / llm (grounded co-scientist: Ollama→Nemotron→deterministic + grounding-guard hard gate) / server (FastAPI gateway mounting the v6.1 surface + /chat + SSE + static frontend)
804
+ │ ├── server/api.py FastAPI REST (atlas, crosslink, writable, plan, bridge, ask; v3.3 verify; v6.1 /capabilities /scope /safety /immune /generate /predict /suggest /session + openapi.json 3.1; v5.13 /challenge/{tasks,leaderboard})
784
805
  │ ├── ui/app.py Streamlit web app (16 pages; v3.2 PEN-Agent shows confidence + epistemic status)
785
806
  │ └── cli.py unified CLI
786
807
  ├── benchmarks/genome_writing_bench/ Genome-Writing Bench v0.3.8 (T1-T16 + co_scientist + safety_screening + generative_design + outcome_prediction + experiment_design + protocol_safety + closed_loop; tasks / harness / solvers / LEADERBOARD / SHAs)
787
808
  ├── benchmarks/genome_writing_challenge/ v5.13 the public Genome-Writing Challenge (held-out rounds + immune-risk task + submission API; harness / run / README / SUBMISSIONS)
788
809
  ├── bench/run.py one-command bench entrypoint (--agent, --verify)
789
810
  ├── examples/ v6.1 runnable golden path: external_agent.py (REST) / mcp_client.py (MCP) / agent_tools.py (framework-agnostic tool specs from the live manifest + dispatcher)
811
+ ├── web/ v6.2 the Web Platform frontend (React/Vite + Tailwind): honest-UX library (ConfidenceBand/ProvenanceChip/ScopeLedger/SafetyBadge/ImmuneProfileCard) + 11 feature pages + the grounded co-scientist chat; built by docker/web.Dockerfile (node:20 stage)
790
812
  ├── scripts/ reproducible pipeline drivers (p1_*, p2_*, p4_*, p52/p53 delivery-immunology oracle builds, ws_*_report)
791
813
  ├── configs/ pinned datasets + thresholds + curation (YAML); v3.2 known_unknowns /
792
814
  │ target_sites / delivery_constraints; v5.1-5.6 delivery_vehicles immune_safety /
@@ -799,7 +821,7 @@ pen-stack/
799
821
  │ genotox,epitope,innate,seroprev,peg,calib,profile,screen,policy,redteam,
800
822
  │ gen,pareto,orch,vcell,mech,outcome,twincal,acq,aldesign,alvalidate,
801
823
  │ proto,ingest,simlab,loop,continual,drift,challenge,cosci2,
802
- │ manifest,openapi,mcp} + SHA256 locks)
824
+ │ manifest,openapi,mcp,chat,frontend} + SHA256 locks)
803
825
  ├── data/curated/ small committed tables (universe, gene coords, measured bridge profile,
804
826
  │ v3.2 bridge_offtarget_energetics.json)
805
827
  ├── data/llm_bench_cache/ 28 cached ungrounded-LLM transcripts (T7, offline/CI replay)
@@ -813,7 +835,7 @@ pen-stack/
813
835
  │ generative_design.md / digital_twin.md / experiment_design.md /
814
836
  │ build_interface.md / closed_loop.md / autonomy.md / challenge.md /
815
837
  │ co_scientist_loop.md / integrations.md / STABILITY.md (1.0 API freeze)
816
- ├── docker/ CUDA image + UI image + pinned requirements
838
+ ├── docker/ CUDA image + UI image + v6.2 web.Dockerfile (multi-stage: node:20 frontend build → slim Python gateway) + pinned requirements
817
839
  ├── tools/penctl.py laptop<->VM orchestrator (paramiko SSH/SFTP, Docker-only)
818
840
  ├── docker-compose.yml one-command self-hostable platform
819
841
  └── pyproject.toml CITATION.cff CHANGELOG.md LICENSE
@@ -15,9 +15,9 @@ every design against rule-grounded mechanism, reports calibrated confidence, cit
15
15
  [![codecov](https://codecov.io/gh/ahmedanees-m/pen-stack/branch/main/graph/badge.svg)](https://codecov.io/gh/ahmedanees-m/pen-stack)
16
16
  [![License: MIT](https://img.shields.io/badge/License-MIT-informational.svg)](LICENSE)
17
17
  [![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
18
- [![Version](https://img.shields.io/badge/version-6.1.0-blue.svg)](CHANGELOG.md)
18
+ [![Version](https://img.shields.io/badge/version-6.2.0-blue.svg)](CHANGELOG.md)
19
19
  [![Status](https://img.shields.io/badge/status-1.0%20First%20Stable-success.svg)](docs/STABILITY.md)
20
- [![Tests](https://img.shields.io/badge/tests-360%20passing-success.svg)](tests/)
20
+ [![Tests](https://img.shields.io/badge/tests-368%20passing-success.svg)](tests/)
21
21
  [![Lint: ruff](https://img.shields.io/badge/lint-ruff-purple.svg)](https://github.com/astral-sh/ruff)
22
22
  [![Runtime: Docker](https://img.shields.io/badge/runtime-docker-2496ED.svg)](docker/)
23
23
  [![Validation: pre-registered](https://img.shields.io/badge/validation-pre--registered-critical.svg)](prereg/)
@@ -73,6 +73,26 @@ demonstrated (v5.12) and the benchmark went public (v5.13).
73
73
  > unknown funnel remains — made legible (scope flags, known-unknowns, honest baselines, no fabrication), not
74
74
  > hidden.
75
75
 
76
+ ## What is new in v6.2 — The Web Platform (the human surface)
77
+
78
+ Post-1.0, the adoption surface for **bench scientists**: a complete, friendly **web application** — a grounded
79
+ co-scientist chat plus structured feature pages — over the same typed v6.1 API the AI surface uses. The LLM
80
+ **narrates and routes but never sources a number**; every quantitative answer renders with its confidence band,
81
+ its provenance, and an explicit ledger of what PEN-STACK *can't* tell you.
82
+
83
+ | Workstream | What it adds | Result |
84
+ |---|---|---|
85
+ | **BACKEND** | `pen_stack/web/server.py` | one FastAPI gateway that mounts the v6.1 engine surface (under `/api`) + adds the grounded `/chat` (+ SSE `/chat/stream`) + CORS + serves the built frontend |
86
+ | **CHAT** *(the hard gate)* | `pen_stack/web/{tools,llm}.py` | the grounded co-scientist: the **engine** computes every number (`run_tools`), the LLM narrates over the tool results (**Ollama → Nemotron → deterministic**), and a **grounding guard strikes any number the model can't trace to a tool result** (asserted in `tests/unit/test_ws_chat.py`) |
87
+ | **FRONTEND** | `web/` (React/Vite + Tailwind) | the **honest-UX library** — `ConfidenceBand · ProvenanceChip · ScopeLedger · SafetyBadge · ImmuneProfileCard` — so a number is never shown without its uncertainty + provenance |
88
+ | **PAGES** | 11 feature pages | Co-Scientist · Site Finder · Writer Atlas · Designer · Verify · Delivery & Immunity · Digital Twin · Guardian · Experiments · Challenge · Scope & About |
89
+ | **DEPLOY** | `docker/web.Dockerfile` + compose | **one-command self-host**: a `node:20` stage builds the frontend, a slim Python serves UI + API from one origin — `docker compose up web ollama`, open `http://localhost:8000` |
90
+
91
+ **The LLM never sources a number** — it explains, compares, and routes over the engine's tool outputs, and the
92
+ science runs (deterministic mode) with no LLM at all. See [`web/README.md`](web/README.md) and
93
+ `prereg/ws_{chat,frontend}.yaml`. (Lowers the usability barrier; a real-data validation + a first lab user remain
94
+ the standing bottleneck — no new science.)
95
+
76
96
  ## What is new in v6.1 — The AI Integration Surface
77
97
 
78
98
  Post-1.0, the adoption surface for **AI builders**: PEN-STACK is now **self-describing** — an external agent can
@@ -705,13 +725,15 @@ pen-stack/
705
725
  │ │ v5.12 closed_loop (loop-integrity hard-gate: gated end-to-end run · Level-3 human-in-control · drift detection · versioned/reversible continual learning)
706
726
  │ ├── data/ ingestion (genome, chromatin, integration, TRIP, safety annotations)
707
727
  │ ├── api/ v6.1 AI integration surface: manifest (capability_manifest + scope_manifest = machine-readable known-unknowns + oracle scope cards)
708
- │ ├── server/api.py FastAPI REST (atlas, crosslink, writable, plan, bridge, ask; v3.3 verify; v6.1 /capabilities /scope /safety /immune /generate /predict /suggest /session + openapi.json 3.1)
728
+ │ ├── web/ v6.2 Web Platform backend: tools (deterministic engine dossier) / llm (grounded co-scientist: Ollama→Nemotron→deterministic + grounding-guard hard gate) / server (FastAPI gateway mounting the v6.1 surface + /chat + SSE + static frontend)
729
+ │ ├── server/api.py FastAPI REST (atlas, crosslink, writable, plan, bridge, ask; v3.3 verify; v6.1 /capabilities /scope /safety /immune /generate /predict /suggest /session + openapi.json 3.1; v5.13 /challenge/{tasks,leaderboard})
709
730
  │ ├── ui/app.py Streamlit web app (16 pages; v3.2 PEN-Agent shows confidence + epistemic status)
710
731
  │ └── cli.py unified CLI
711
732
  ├── benchmarks/genome_writing_bench/ Genome-Writing Bench v0.3.8 (T1-T16 + co_scientist + safety_screening + generative_design + outcome_prediction + experiment_design + protocol_safety + closed_loop; tasks / harness / solvers / LEADERBOARD / SHAs)
712
733
  ├── benchmarks/genome_writing_challenge/ v5.13 the public Genome-Writing Challenge (held-out rounds + immune-risk task + submission API; harness / run / README / SUBMISSIONS)
713
734
  ├── bench/run.py one-command bench entrypoint (--agent, --verify)
714
735
  ├── examples/ v6.1 runnable golden path: external_agent.py (REST) / mcp_client.py (MCP) / agent_tools.py (framework-agnostic tool specs from the live manifest + dispatcher)
736
+ ├── web/ v6.2 the Web Platform frontend (React/Vite + Tailwind): honest-UX library (ConfidenceBand/ProvenanceChip/ScopeLedger/SafetyBadge/ImmuneProfileCard) + 11 feature pages + the grounded co-scientist chat; built by docker/web.Dockerfile (node:20 stage)
715
737
  ├── scripts/ reproducible pipeline drivers (p1_*, p2_*, p4_*, p52/p53 delivery-immunology oracle builds, ws_*_report)
716
738
  ├── configs/ pinned datasets + thresholds + curation (YAML); v3.2 known_unknowns /
717
739
  │ target_sites / delivery_constraints; v5.1-5.6 delivery_vehicles immune_safety /
@@ -724,7 +746,7 @@ pen-stack/
724
746
  │ genotox,epitope,innate,seroprev,peg,calib,profile,screen,policy,redteam,
725
747
  │ gen,pareto,orch,vcell,mech,outcome,twincal,acq,aldesign,alvalidate,
726
748
  │ proto,ingest,simlab,loop,continual,drift,challenge,cosci2,
727
- │ manifest,openapi,mcp} + SHA256 locks)
749
+ │ manifest,openapi,mcp,chat,frontend} + SHA256 locks)
728
750
  ├── data/curated/ small committed tables (universe, gene coords, measured bridge profile,
729
751
  │ v3.2 bridge_offtarget_energetics.json)
730
752
  ├── data/llm_bench_cache/ 28 cached ungrounded-LLM transcripts (T7, offline/CI replay)
@@ -738,7 +760,7 @@ pen-stack/
738
760
  │ generative_design.md / digital_twin.md / experiment_design.md /
739
761
  │ build_interface.md / closed_loop.md / autonomy.md / challenge.md /
740
762
  │ co_scientist_loop.md / integrations.md / STABILITY.md (1.0 API freeze)
741
- ├── docker/ CUDA image + UI image + pinned requirements
763
+ ├── docker/ CUDA image + UI image + v6.2 web.Dockerfile (multi-stage: node:20 frontend build → slim Python gateway) + pinned requirements
742
764
  ├── tools/penctl.py laptop<->VM orchestrator (paramiko SSH/SFTP, Docker-only)
743
765
  ├── docker-compose.yml one-command self-hostable platform
744
766
  └── pyproject.toml CITATION.cff CHANGELOG.md LICENSE
@@ -1,2 +1,2 @@
1
1
  """PEN-STACK v3.0 - open infrastructure for genome writing."""
2
- __version__ = "6.1.0"
2
+ __version__ = "6.2.0"
@@ -223,3 +223,29 @@ def session_endpoint(req: dict):
223
223
  predicted outcomes + per-axis immune profiles + suggested experiments + citations + scope ledger + safety."""
224
224
  from pen_stack.agent.co_scientist import co_scientist_session
225
225
  return co_scientist_session(req["goal"], req.get("cell_state", "k562"), candidates=req.get("candidates"))
226
+
227
+
228
+ # ======================================================================================
229
+ # v5.13 — The Genome-Writing Challenge (read-only surface for the web Challenge page).
230
+ # Public tasks (NO labels) + the PEN-STACK reference submission that anchors the leaderboard. Submissions
231
+ # are Python `predict_fn`s scored offline (`benchmarks/genome_writing_challenge/run.py`) — never accepted
232
+ # over HTTP — so these routes only EXPOSE the held-out round and the anchor score.
233
+ # ======================================================================================
234
+ @app.get("/challenge/tasks", tags=["challenge"])
235
+ def challenge_tasks(round_id: str = "2026R1"):
236
+ """The public inputs of the current held-out round (family + design + instructions; NEVER the label)."""
237
+ from benchmarks.genome_writing_challenge.harness import _round_tasks
238
+ tasks = _round_tasks(round_id)
239
+ return {"round": round_id, "n_tasks": len(tasks),
240
+ "tasks": [{"id": t.id, "family": t.family, "public_input": t.public_input} for t in tasks]}
241
+
242
+
243
+ @app.get("/challenge/leaderboard", tags=["challenge"])
244
+ def challenge_leaderboard(round_id: str = "2026R1"):
245
+ """The leaderboard anchored by the PEN-STACK reference submission (deterministic, non-circular labels,
246
+ no-fabrication audited). External submissions are scored offline and appended here after a round."""
247
+ from benchmarks.genome_writing_challenge.harness import evaluate, reference_submission
248
+ ref = evaluate(reference_submission(), round_id)
249
+ return {"round": round_id, "leaderboard": [ref],
250
+ "rules": {"no_circular_labels": ref["no_circular_labels"],
251
+ "no_fabrication_audited": True, "labels": "validated PEN-STACK verifier / oracles"}}
@@ -0,0 +1,18 @@
1
+ """PEN-STACK Web Platform (v6.2) — the human surface.
2
+
3
+ A grounded co-scientist chat + every engine feature behind one typed gateway, with honest UX. The LLM narrates
4
+ and routes; the engine sources every number. Submodules:
5
+
6
+ * ``tools`` — the deterministic engine tool-runner (parse a goal, run verify/safety/immune/scope, return a
7
+ grounded dossier) and the grounding allow-list.
8
+ * ``llm`` — the grounded co-scientist (Ollama → Nemotron → deterministic) with the grounding-guard hard gate.
9
+ * ``server`` — the FastAPI gateway (mounts the v6.1 engine surface + ``/chat``); needs the ``server`` extra.
10
+
11
+ ``server`` is imported lazily (it requires FastAPI) so ``import pen_stack.web`` works on a bare install.
12
+ """
13
+ from __future__ import annotations
14
+
15
+ from pen_stack.web.llm import grounded_reply
16
+ from pen_stack.web.tools import extract_grounded_numbers, parse_goal, run_tools
17
+
18
+ __all__ = ["grounded_reply", "run_tools", "parse_goal", "extract_grounded_numbers"]
@@ -0,0 +1,219 @@
1
+ """Grounded co-scientist for the web chat (PEN-STACK v6.2, WS-CHAT).
2
+
3
+ The conversational layer that is helpful **and** cannot fabricate. The flow is always:
4
+
5
+ run_tools(message) -> the ENGINE computes every number (verify / safety / immune / scope)
6
+ extract_grounded_numbers(tool_results) -> the allow-list of values the model may cite
7
+ LLM narrates over the tool results -> Ollama (local, free) → Nemotron (hosted free tier) → deterministic
8
+ _enforce_grounding(text, allow_list) -> HARD GATE: any number not traceable to a tool result is struck
9
+
10
+ The LLM *routes, explains, and compares*; it never sources a number. If both LLMs are unavailable the
11
+ deterministic narrator composes the reply directly from the tool results — so the science never depends on the
12
+ model. The grounding guard is the invariant: a numeric claim absent from the tool results cannot survive into a
13
+ reply (it is replaced with the marker ``[unverified]``). This is asserted by ``tests/unit/test_ws_chat.py``.
14
+ """
15
+ from __future__ import annotations
16
+
17
+ import os
18
+ import re
19
+ from pathlib import Path
20
+ from typing import Any
21
+
22
+ from pen_stack.web.tools import extract_grounded_numbers, run_tools
23
+
24
+ SYSTEM = (
25
+ "You are PEN-STACK's co-scientist for genome writing. You may explain, compare, and route between the "
26
+ "engine's tools, but you MUST NOT state any number, score, probability, titer, or confidence that is not "
27
+ "present verbatim in the TOOL RESULTS provided to you. If a value is not in the tool results, say it is "
28
+ "out of scope or unknown — never invent it. Never invent a citation. Always surface uncertainty and the "
29
+ "scope ledger ('what I can't tell you'). Be concise, friendly, and honest. This is decision-support, not a "
30
+ "clinical directive."
31
+ )
32
+
33
+ # the number marker the guard substitutes for any ungrounded numeric token the model emits.
34
+ _UNVERIFIED = "[unverified]"
35
+ # a numeric token in model prose: optional sign, digits, optional decimal, optional % (e.g. 0.28, 28%, 4500)
36
+ _TOKEN_RE = re.compile(r"(?<![\w.])-?\d+(?:\.\d+)?%?")
37
+
38
+
39
+ # --------------------------------------------------------------------------------------
40
+ # the grounding guard (the hard gate)
41
+ # --------------------------------------------------------------------------------------
42
+ def _is_grounded(token: str, grounded: set[str]) -> bool:
43
+ """A numeric token is grounded iff it (or a normalised form) appears in the engine's allow-list."""
44
+ raw = token.strip()
45
+ pct = raw.endswith("%")
46
+ body = raw[:-1] if pct else raw
47
+ if body in grounded:
48
+ return True
49
+ try:
50
+ f = float(body)
51
+ except ValueError:
52
+ return False
53
+ forms = {body, str(int(f)) if f.is_integer() else str(f), f"{f:.2f}"}
54
+ if pct: # "28%" matches a grounded 0.28 score or a grounded 28
55
+ forms.add(str(f / 100))
56
+ forms.add(f"{f / 100:.2f}")
57
+ return bool(forms & grounded)
58
+
59
+
60
+ def _enforce_grounding(text: str, grounded: set[str]) -> str:
61
+ """Strike every numeric token in `text` that is not traceable to the engine's tool results. The result is
62
+ a reply in which **no number is absent from the tool results** — the invariant the chat is built on."""
63
+ return _TOKEN_RE.sub(lambda m: m.group(0) if _is_grounded(m.group(0), grounded) else _UNVERIFIED, text)
64
+
65
+
66
+ def ungrounded_numbers(text: str, grounded: set[str]) -> list[str]:
67
+ """Diagnostic: the numeric tokens in `text` that are NOT in the allow-list (empty after enforcement)."""
68
+ return [m.group(0) for m in _TOKEN_RE.finditer(text) if not _is_grounded(m.group(0), grounded)]
69
+
70
+
71
+ # --------------------------------------------------------------------------------------
72
+ # the deterministic narrator (no-LLM fallback; numbers grounded by construction)
73
+ # --------------------------------------------------------------------------------------
74
+ def _fmt(x: Any) -> str:
75
+ if isinstance(x, float):
76
+ return f"{x:.2f}".rstrip("0").rstrip(".") if x != int(x) else str(int(x))
77
+ return str(x)
78
+
79
+
80
+ def _deterministic_narrate(tr: dict) -> str:
81
+ """Compose a clear English reply directly from the engine's tool results. Every number here comes straight
82
+ from `tr`, so the reply is grounded by construction (this is the LLM-offline path)."""
83
+ d = tr["parsed_design"]
84
+ v = tr["verdict"]
85
+ lines: list[str] = []
86
+ lines.append(
87
+ f"I read your goal as: a **{d['edit_intent'].replace('_', ' ')}** of **{d['gene']}** "
88
+ f"(~{d['cargo_bp']} bp cargo) delivered by **{d['delivery_vehicle'].replace('_', ' ')}** "
89
+ f"in **{d['cell_type']}**. Here is what the engine computes — every number below is tool-sourced.")
90
+
91
+ legal = "legal" if v["legal"] else ("deferred" if v["legal"] is None else "ILLEGAL")
92
+ line = f"**Verification.** The design is **{legal}** ({v['epistemic_status']})."
93
+ if v["violations"]:
94
+ line += " Violations: " + ", ".join(str(x) for x in v["violations"]) + "."
95
+ if v["confidence"] is not None:
96
+ band = f" [{v['interval'][0]:.2f}–{v['interval'][1]:.2f}]" if v.get("interval") else ""
97
+ line += f" Calibrated confidence on the soft components: **{v['confidence']:.2f}**{band}."
98
+ else:
99
+ line += " (Confidence abstained — no calibrated soft-component score for this design.)"
100
+ lines.append(line)
101
+
102
+ s = tr["safety"]
103
+ if s.get("decision"):
104
+ lines.append(f"**Safety (Guardian).** Decision: **{s['decision']}** — {s.get('reason', 'n/a')}.")
105
+
106
+ imm = tr["immune_profile"]
107
+ axes = imm.get("axes") or {}
108
+ if axes:
109
+ lines.append("**Immune-risk profile** (per-axis — never collapsed into one number):")
110
+ for name, a in axes.items():
111
+ val = _fmt(a["value"]) if a.get("value") is not None else "n/a"
112
+ unc = a.get("uncertainty")
113
+ unc_s = f" ±{_fmt(unc)}" if unc is not None else ""
114
+ lab = a.get("validation", "")
115
+ lines.append(f" • {name.replace('_', ' ')}: **{val}**{unc_s} — {lab}")
116
+ if imm.get("collapsed_score") is None:
117
+ lines.append(" (No single fused immune score is asserted — that would overstate certainty.)")
118
+
119
+ sc = tr["scope"]
120
+ if sc.get("out_of_scope"):
121
+ lines.append(f"**Out of scope.** {sc.get('why') or sc.get('title')} PEN-STACK will not guess a value here.")
122
+ ku = imm.get("known_unknowns") or []
123
+ if ku:
124
+ lines.append("**What I can't tell you** (known-unknowns): " + ", ".join(str(x) for x in ku) + ".")
125
+
126
+ lines.append(f"_{tr['disclaimer']}_")
127
+ return "\n".join(lines)
128
+
129
+
130
+ # --------------------------------------------------------------------------------------
131
+ # LLM backends (free-tier first; both optional)
132
+ # --------------------------------------------------------------------------------------
133
+ def _ollama_base() -> str:
134
+ return os.getenv("OLLAMA_HOST", "http://localhost:11434").rstrip("/")
135
+
136
+
137
+ def _llm_timeout() -> float:
138
+ # generous by default: a 7B model narrating a full dossier on a single GPU can take ~60-90s; too short a
139
+ # timeout would silently fall back to the deterministic narrator on every real query.
140
+ return float(os.getenv("PEN_STACK_LLM_TIMEOUT", "150"))
141
+
142
+
143
+ def _call_ollama(prompt: str) -> str:
144
+ """Primary: local Ollama (free). Default model qwen2.5:7b-instruct (override via OLLAMA_MODEL). Generation is
145
+ bounded (num_predict) so a reply returns promptly; the science is in the engine, the LLM only narrates."""
146
+ import requests
147
+
148
+ r = requests.post(
149
+ f"{_ollama_base()}/api/generate",
150
+ json={"model": os.getenv("OLLAMA_MODEL", "qwen2.5:7b-instruct"),
151
+ "prompt": prompt, "system": SYSTEM, "stream": False,
152
+ "options": {"temperature": 0.2,
153
+ "num_predict": int(os.getenv("OLLAMA_NUM_PREDICT", "450"))}},
154
+ timeout=_llm_timeout())
155
+ r.raise_for_status()
156
+ return r.json()["response"]
157
+
158
+
159
+ def _nvidia_key() -> str | None:
160
+ key = os.getenv("NVIDIA_API_KEY")
161
+ if key:
162
+ return key.strip()
163
+ f = Path(__file__).resolve().parents[2] / "configs" / "nvidia_api_key.txt"
164
+ return f.read_text(encoding="utf-8").strip() if f.exists() else None
165
+
166
+
167
+ def _call_nemotron(prompt: str) -> str:
168
+ """Fallback: NVIDIA-hosted Nemotron (free tier). Needs NVIDIA_API_KEY (or configs/nvidia_api_key.txt)."""
169
+ import requests
170
+
171
+ key = _nvidia_key()
172
+ if not key:
173
+ raise RuntimeError("no NVIDIA_API_KEY")
174
+ r = requests.post(
175
+ "https://integrate.api.nvidia.com/v1/chat/completions",
176
+ headers={"Authorization": f"Bearer {key}"},
177
+ json={"model": os.getenv("NEMOTRON_MODEL", "nvidia/llama-3.1-nemotron-70b-instruct"),
178
+ "messages": [{"role": "system", "content": SYSTEM}, {"role": "user", "content": prompt}],
179
+ "temperature": 0.2, "max_tokens": 900},
180
+ timeout=_llm_timeout())
181
+ r.raise_for_status()
182
+ return r.json()["choices"][0]["message"]["content"]
183
+
184
+
185
+ def _prompt(message: str, tool_results: dict, history: list | None) -> str:
186
+ import json
187
+
188
+ convo = ""
189
+ for turn in (history or [])[-6:]:
190
+ role = turn.get("role", "user")
191
+ convo += f"{role.upper()}: {turn.get('content', '')}\n"
192
+ return (f"{SYSTEM}\n\nTOOL RESULTS (the ONLY source of numbers — cite nothing else):\n"
193
+ f"{json.dumps(tool_results, default=str, separators=(',', ':'))}\n\n{convo}USER: {message}\n\n"
194
+ f"Compose a concise, friendly reply (a short paragraph) that explains the engine's findings, surfaces "
195
+ f"the uncertainty and the scope ledger, and uses ONLY numbers present in the tool results.")
196
+
197
+
198
+ # --------------------------------------------------------------------------------------
199
+ # the public entry point
200
+ # --------------------------------------------------------------------------------------
201
+ def grounded_reply(message: str, history: list | None = None, *, allow_llm: bool = True) -> dict:
202
+ """The grounded co-scientist. Runs the engine, then narrates over its results with the grounding guard
203
+ enforced. Returns {reply, tool_results, grounded, backend}. `grounded` is always True: the reply is either
204
+ composed deterministically from the tool results, or passed through `_enforce_grounding`."""
205
+ tool_results = run_tools(message, history) # ENGINE computes every number
206
+ grounded = extract_grounded_numbers(tool_results) # the allow-list
207
+ prompt = _prompt(message, tool_results, history)
208
+
209
+ if allow_llm and os.getenv("PEN_STACK_NO_LLM") != "1":
210
+ for backend in (_call_ollama, _call_nemotron):
211
+ try:
212
+ text = _enforce_grounding(backend(prompt), grounded) # HARD GATE
213
+ return {"reply": text, "tool_results": tool_results, "grounded": True,
214
+ "backend": backend.__name__.removeprefix("_call_")}
215
+ except Exception: # any backend failure → next, then deterministic
216
+ continue
217
+
218
+ return {"reply": _deterministic_narrate(tool_results), "tool_results": tool_results,
219
+ "grounded": True, "backend": "deterministic"}
@@ -0,0 +1,86 @@
1
+ """The PEN-STACK web gateway (v6.2, WS-BACKEND) — one typed HTTP surface over the engine + the grounded chat.
2
+
3
+ This is a *gateway, not a rewrite*. It mounts the v6.1 AI-surface app (``/verify``, ``/safety``, ``/immune``,
4
+ ``/generate``, ``/predict``, ``/suggest``, ``/session``, ``/capabilities``, ``/scope`` + the atlas/crosslink
5
+ routes) and adds the human-facing pieces: the grounded ``/chat`` (and a streaming ``/chat/stream``), CORS for
6
+ the React frontend, and static serving of the built frontend when present. Every quantity still comes from the
7
+ engine; the chat's LLM only narrates (see ``pen_stack.web.llm``).
8
+
9
+ Run: ``uvicorn pen_stack.web.server:app --host 0.0.0.0 --port 8000`` (needs the ``server`` extra).
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import json
14
+ from pathlib import Path
15
+
16
+ try:
17
+ from fastapi import FastAPI
18
+ from fastapi.middleware.cors import CORSMiddleware
19
+ from fastapi.responses import StreamingResponse
20
+ except ImportError as e: # pragma: no cover - server extra optional
21
+ raise ImportError("FastAPI not installed: pip install 'pen-stack[server]'") from e
22
+
23
+ from pen_stack import __version__
24
+ from pen_stack.server.api import app as _engine_app # the v6.1 typed engine surface (reused verbatim)
25
+
26
+ app = FastAPI(
27
+ title="PEN-STACK — Web Platform",
28
+ version=__version__,
29
+ description=("The human surface for genome writing: a grounded co-scientist chat + every engine feature, "
30
+ "with honest UX (confidence bands, provenance, scope ledger, safety badges). The LLM narrates "
31
+ "and routes but never sources a number."),
32
+ )
33
+
34
+ # CORS — the Vite dev server (5173) and the bundled static frontend both talk to this gateway.
35
+ app.add_middleware(
36
+ CORSMiddleware,
37
+ allow_origins=["*"], # self-hosted, single-tenant; tighten via PEN_STACK_CORS if deployed
38
+ allow_methods=["*"],
39
+ allow_headers=["*"],
40
+ )
41
+
42
+ # Mount the entire v6.1 engine surface under the same app so the frontend has ONE base URL/one OpenAPI.
43
+ app.mount("/api", _engine_app)
44
+
45
+
46
+ @app.get("/health")
47
+ def health() -> dict:
48
+ return {"status": "ok", "version": __version__, "surface": "web"}
49
+
50
+
51
+ @app.post("/chat", tags=["v6.2 co-scientist"])
52
+ def chat_route(req: dict) -> dict:
53
+ """The grounded co-scientist: the LLM narrates over ENGINE tool outputs; every number comes from the tools
54
+ and the grounding guard strikes any the model invents. Body: {message, history?}. Returns
55
+ {reply, tool_results, grounded, backend}."""
56
+ from pen_stack.web.llm import grounded_reply
57
+
58
+ return grounded_reply(req["message"], history=req.get("history", []),
59
+ allow_llm=bool(req.get("allow_llm", True)))
60
+
61
+
62
+ @app.post("/chat/stream", tags=["v6.2 co-scientist"])
63
+ def chat_stream_route(req: dict) -> StreamingResponse:
64
+ """Same grounded reply, streamed as Server-Sent Events. The reply is computed grounded first (guard already
65
+ applied), then emitted word-by-word so the UI can render progressively; a final event carries the dossier."""
66
+ from pen_stack.web.llm import grounded_reply
67
+
68
+ result = grounded_reply(req["message"], history=req.get("history", []),
69
+ allow_llm=bool(req.get("allow_llm", True)))
70
+
71
+ def _events():
72
+ for word in result["reply"].split(" "):
73
+ yield f"data: {json.dumps({'token': word + ' '})}\n\n"
74
+ yield ("event: done\ndata: " + json.dumps(
75
+ {"tool_results": result["tool_results"], "backend": result["backend"],
76
+ "grounded": result["grounded"]}, default=str) + "\n\n")
77
+
78
+ return StreamingResponse(_events(), media_type="text/event-stream")
79
+
80
+
81
+ # Serve the built React frontend (web/dist) when present — one-command self-host serves UI + API together.
82
+ _DIST = Path(__file__).resolve().parents[2] / "web" / "dist"
83
+ if _DIST.exists(): # pragma: no cover - only when the frontend has been built
84
+ from fastapi.staticfiles import StaticFiles
85
+
86
+ app.mount("/", StaticFiles(directory=str(_DIST), html=True), name="frontend")