pen-stack 6.1.0__tar.gz → 6.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pen_stack-6.1.0 → pen_stack-6.2.1}/CHANGELOG.md +49 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/CITATION.cff +1 -1
- {pen_stack-6.1.0 → pen_stack-6.2.1}/PKG-INFO +28 -6
- {pen_stack-6.1.0 → pen_stack-6.2.1}/README.md +27 -5
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/__init__.py +1 -1
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/server/api.py +36 -3
- pen_stack-6.2.1/pen_stack/web/__init__.py +18 -0
- pen_stack-6.2.1/pen_stack/web/llm.py +219 -0
- pen_stack-6.2.1/pen_stack/web/server.py +93 -0
- pen_stack-6.2.1/pen_stack/web/tools.py +105 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack.egg-info/PKG-INFO +28 -6
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack.egg-info/SOURCES.txt +8 -0
- pen_stack-6.2.1/prereg/SHA256_LOCK_ws_chat.json +8 -0
- pen_stack-6.2.1/prereg/SHA256_LOCK_ws_frontend.json +8 -0
- pen_stack-6.2.1/prereg/ws_chat.yaml +20 -0
- pen_stack-6.2.1/prereg/ws_frontend.yaml +21 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pyproject.toml +1 -1
- {pen_stack-6.1.0 → pen_stack-6.2.1}/LICENSE +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/MANIFEST.in +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/bench/run.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/benchmarks/genome_writing_bench/LEADERBOARD.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/benchmarks/genome_writing_bench/README.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/benchmarks/genome_writing_bench/SHA256SUMS +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/benchmarks/genome_writing_bench/SUBMISSIONS.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/benchmarks/genome_writing_bench/tasks.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/benchmarks/genome_writing_challenge/README.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/benchmarks/genome_writing_challenge/SUBMISSIONS.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/antipeg.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/atlas_families.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/bridge_offtarget_profile.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/capsid_epitope_oracle.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/capsid_sequences.fasta +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/cargo_polish.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/cell_types.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/datasets.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/delivery_constraints.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/delivery_rules.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/delivery_vehicles.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/gates_v3.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/genotoxicity_oracle.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/gsh_validated_heldout.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/intent_weights.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/known_unknowns.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/llm.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/monitor_queries.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/oracles/scope_cards.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/rules/delivery.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/rules/fold.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/rules/multiplex.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/rules/payload.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/rules/reachability.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/safety/hazard_registry.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/safety/policy.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/safety/probes.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/score_axes.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/seroprevalence.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/target_sites.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/universe_crosswalk.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/write_types.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/configs/wtkb_curated.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/data/curated/bridge_offtarget_energetics.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/data/curated/bridge_offtarget_profile_measured.parquet +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/data/curated/gene_coords.parquet +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/data/curated/unified_editor_universe.parquet +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/BACKLOG.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/DEPLOY.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/INFRA.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/MCP.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/RELEASING.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/REPRO.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/STABILITY.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/agent.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/alphagenome_feasibility.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/autonomy.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/benchmark_circularity.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/biosecurity.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/build_interface.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/cards/atlas.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/cards/durability.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/cards/safety.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/challenge.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/closed_loop.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/co_scientist.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/co_scientist_loop.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/delivery.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/delivery_immunology.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/digital_twin.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/dissemination.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/environment.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/experiment_design.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/generative_design.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/index.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/integrations.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/mechanistic_constraints.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/oracles.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/positioning.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/private_data_formats.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/quickstart.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/responsible_use.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/rules.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/scope.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/scorecard.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/tutorials/compare-families.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/tutorials/score-deliverability.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/tutorials/where-can-i-write.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/tutorials/which-writer-reaches-locus.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/uncertainty.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/verify.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/world_model.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/writer_verification.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/docs/wtkb.md +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/_resources.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/active/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/active/acquire.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/active/design.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/active/validate.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/adapt/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/adapt/finetune.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/adapt/ingest.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/adapt/pipeline.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/adapt/recalibrate.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/adapt/report.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/agent/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/agent/cite.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/agent/co_scientist.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/agent/epistemic.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/agent/guardrails.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/agent/mcp_server.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/agent/orchestrator.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/agent/orchestrator_live.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/agent/pen_agent.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/agent/scope.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/agent/tools.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/api/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/api/manifest.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/atlas/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/atlas/build_wtkb.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/atlas/crosslink.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/atlas/expand.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/atlas/schema.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/atlas/scorecard.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/atlas/universe.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/atlas/variant_propose.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/atlas/writer_verify.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/bridge/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/bridge/activity.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/bridge/cli.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/bridge/fold_qc.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/bridge/guide_qc.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/bridge/ingest.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/bridge/offtarget.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/bridge/offtarget_energetics.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/bridge/ortholog_screen.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/bridge/pipeline.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/build/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/build/ingest.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/build/protocol.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/build/simlab.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/cli.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/data/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/data/encode.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/data/genome.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/data/ingest_chromatin.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/data/ingest_integration.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/data/ingest_safety_annot.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/data/ingest_trip.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/design/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/design/generate.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/design/pareto.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/design/space.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/env/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/env/genome_writing_env.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/env/policies.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/graph/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/graph/build.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/graph/cell_types.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/graph/ingest.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/graph/query.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/graph/schema.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/loop/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/loop/continual.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/loop/cycle.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/loop/drift.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/mech/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/mech/classify_atlas.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/mech/whitelist.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/monitor/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/monitor/europepmc.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/monitor/run.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/monitor/triage.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/oracles/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/oracles/cache.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/oracles/energetics.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/oracles/genome.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/oracles/protein_design.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/oracles/rna.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/oracles/schema.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/oracles/structure.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/oracles/vcell.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/antipeg_oracle.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/capsid_epitope_oracle.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/cargo.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/cargo_polish.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/delivery.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/delivery_constraints.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/delivery_immunology.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/delivery_vehicles.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/genotoxicity_oracle.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/immune_profile.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/innate_sensing.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/multiplex.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/optimize.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/pipeline.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/report.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/router.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/seroprevalence_oracle.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/planner/target_site.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/rag/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/rag/index.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/rag/llm.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/rag/qa.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/rules/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/rules/evaluators.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/rules/loader.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/rules/schema.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/rules/solver.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/safety/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/safety/audit.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/safety/gate.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/safety/policy.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/safety/redteam.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/safety/registry.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/safety/screen.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/score/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/score/recalibrate.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/score/therapeutic.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/server/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/twin/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/twin/calibrate.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/twin/mechanistic.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/twin/outcome.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/ui/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/ui/app.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/adapt_demo.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/agent_eval.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/bench_adversarial_tasks.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/bench_coscientist_tasks.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/bench_graph_tasks.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/bench_rule_tasks.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/bench_trust_tasks.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/bench_writetype_tasks.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/blind_gsh_discovery.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/cargo_directionality.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/closed_loop.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/durability_baselines.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/experiment_design.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/forward_hypotheses.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/generative_design.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/guide_qc_demo.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/immune_calibration.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/intent_specification.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/offtarget_energetics_eval.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/out_of_scope_refusal.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/outcome_calibration.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/outcome_prediction.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/paper3_benchmark.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/paper4_real_validation.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/paper4_validation.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/protocol_safety.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/safety_screening.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/selective_prediction.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/seq_vs_measured.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/target_site_controls.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/uncertainty_eval.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/ungrounded_baseline.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/within_locus_ranking.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/validate/writer_recovery.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/verify/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/verify/schema.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/verify/service.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/wgenome/__init__.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/wgenome/chromatin_seq.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/wgenome/durability.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/wgenome/export_tracks.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/wgenome/features.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/wgenome/gsh_baseline.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/wgenome/mesh_features.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/wgenome/ood.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/wgenome/providers.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/wgenome/safety.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/wgenome/structure3d.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/wgenome/uncertainty.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack/wgenome/writability.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack.egg-info/dependency_links.txt +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack.egg-info/entry_points.txt +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack.egg-info/requires.txt +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/pen_stack.egg-info/top_level.txt +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_phase0.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_phase1_5.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_phase2.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_phase3.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_a.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_acq.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_aldesign.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_alvalidate.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_atlas.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_b.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_ba.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_ba_v33.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_ba_v45.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_bench.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_c.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_cal.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_calib.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_challenge.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_cite.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_continual.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_cosci2.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_crit.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_ct.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_d.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_drift.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_e.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_env.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_ep.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_epitope.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_f.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_g.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_gen.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_genotox.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_graph.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_h.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_immune.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_ingest.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_innate.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_loop.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_manifest.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_mc.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_mcp.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_mech.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_mon.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_o.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_openapi.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_orch.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_outcome.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_pareto.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_peg.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_plan.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_policy.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_profile.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_proto.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_r.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_redteam.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_route.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_screen.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_seroprev.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_simlab.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_twincal.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_uq.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_v.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_vcell.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/SHA256_LOCK_ws_wv.json +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/paper1.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/paper2.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/paper3.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/paper4.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/phase0.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_a.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_acq.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_aldesign.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_alvalidate.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_atlas.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_b.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_ba.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_ba_v33.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_ba_v45.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_bench.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_c.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_cal.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_calib.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_challenge.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_cite.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_continual.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_cosci2.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_crit.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_ct.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_d.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_drift.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_e.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_env.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_ep.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_epitope.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_f.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_g.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_gen.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_genotox.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_graph.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_h.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_immune.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_ingest.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_innate.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_loop.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_manifest.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_mc.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_mcp.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_mech.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_mon.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_o.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_openapi.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_orch.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_outcome.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_pareto.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_peg.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_plan.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_policy.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_profile.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_proto.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_r.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_redteam.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_route.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_screen.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_seroprev.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_simlab.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_twincal.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_uq.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_v.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_vcell.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/prereg/ws_wv.yaml +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/scripts/p1_build_atlas.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/scripts/p1_build_durability.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/scripts/p1_export_tracks.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/scripts/p1_safety_concordance.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/scripts/p1_train_safety.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/scripts/p1_validation_report.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/scripts/p2_build_atlas.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/scripts/p3_benchmark_report.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/scripts/p4_genome_scan.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/scripts/p52_build_genotox_oracle.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/scripts/p53_build_epitope_oracle.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/scripts/ws_b_report.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/scripts/ws_c_report.py +0 -0
- {pen_stack-6.1.0 → pen_stack-6.2.1}/setup.cfg +0 -0
|
@@ -3,6 +3,55 @@
|
|
|
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.1] - 2026-06-12 - v6.2.1: JSON-safe atlas/crosslink endpoints (patch)
|
|
7
|
+
|
|
8
|
+
**Bug fix.** The `/atlas`, `/writable`, and `/crosslink/loci` endpoints returned raw DataFrame records, which
|
|
9
|
+
leak non-finite floats (`NaN`/`inf`) present in `atlas.parquet`; the JSON encoder rejects these
|
|
10
|
+
(`ValueError: Out of range float values are not JSON compliant` → HTTP 500). Surfaced on the v6.2 Web Platform's
|
|
11
|
+
Writer Atlas and Site Finder pages.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
- `pen_stack/server/api.py`: a `_records()` helper serializes DataFrame rows JSON-safely (via pandas `to_json`,
|
|
15
|
+
so `NaN`/`inf` → `null` and numpy scalars → native), applied to `/atlas`, `/writable`, `/crosslink/loci`.
|
|
16
|
+
Regression test `tests/unit/test_ws_api.py::test_records_helper_is_json_safe_with_non_finite_floats`.
|
|
17
|
+
|
|
18
|
+
## [6.2.0] - 2026-06-11 - v6.2: The Web Platform (the human surface)
|
|
19
|
+
|
|
20
|
+
**Post-1.0 adoption surface for bench scientists.** A complete, friendly web application — a grounded co-scientist
|
|
21
|
+
chat plus structured feature pages — over the same typed v6.1 API the AI surface uses. The LLM **narrates and
|
|
22
|
+
routes but never sources a number**; every quantitative answer renders with its confidence band, provenance, and
|
|
23
|
+
an explicit ledger of what PEN-STACK can't tell you. MINOR release on the stable 6.0 API. Workstreams
|
|
24
|
+
WS-{BACKEND,CHAT,FRONTEND,PAGES,DEPLOY}, SHA-locked.
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
- **WS-BACKEND** — `pen_stack/web/server.py`: one FastAPI gateway that **mounts the v6.1 engine surface** under
|
|
28
|
+
`/api` (so the frontend has one base URL / one OpenAPI) and adds the grounded `/chat` (+ SSE `/chat/stream`),
|
|
29
|
+
CORS, and static serving of the built frontend (`web/dist`). A `/health` for the live grounded indicator.
|
|
30
|
+
- **WS-CHAT** *(the hard gate)* — `pen_stack/web/tools.py` (the deterministic engine tool-runner: parse a goal →
|
|
31
|
+
run `verify`/`safety`/`immune_profile`/scope → a grounded dossier; `extract_grounded_numbers` = the allow-list)
|
|
32
|
+
and `pen_stack/web/llm.py` (the grounded co-scientist: **Ollama → Nemotron → deterministic narrator**, with
|
|
33
|
+
`_enforce_grounding` striking any numeric token the model can't trace to a tool result). A reply's numbers are
|
|
34
|
+
always engine-sourced; `tests/unit/test_ws_chat.py` asserts **no number in a reply is absent from the tool
|
|
35
|
+
results**, and that the deterministic narrator works with both LLMs offline.
|
|
36
|
+
- **WS-FRONTEND** — `web/` (React/Vite + Tailwind): the **honest-UX component library** — `ConfidenceBand`,
|
|
37
|
+
`ProvenanceChip`, `ScopeLedger`, `SafetyBadge`, `ImmuneProfileCard` — so a number is never shown without its
|
|
38
|
+
uncertainty + provenance, and the scope ledger appears on every answer.
|
|
39
|
+
- **WS-PAGES** — 11 feature pages over the typed API: Co-Scientist · Site Finder · Writer Atlas · Designer ·
|
|
40
|
+
Verify · Delivery & Immunity · Digital Twin · Guardian · Experiments · Challenge · Scope & About. Each renders
|
|
41
|
+
through the honest-UX library and degrades gracefully when the LLM is offline.
|
|
42
|
+
- **WS-DEPLOY** — `docker/web.Dockerfile` (multi-stage: a **node:20** stage builds the frontend, a slim Python
|
|
43
|
+
serves UI + API from one origin) + a `web` service in `docker-compose.yml`: **one-command self-host**
|
|
44
|
+
(`docker compose up web ollama`, open `http://localhost:8000`). `web/.env.example`, `web/README.md` quickstart.
|
|
45
|
+
- Read-only Challenge surface for the web page: `GET /api/challenge/{tasks,leaderboard}` (public tasks + the
|
|
46
|
+
PEN-STACK reference leaderboard; submissions are still scored offline, never accepted over HTTP).
|
|
47
|
+
- prereg `ws_{chat,frontend}` + SHA locks; deposit `phase_6.2/`.
|
|
48
|
+
|
|
49
|
+
### Notes
|
|
50
|
+
- **The LLM never sources a number.** It explains, compares, and routes over the engine's tool outputs; the
|
|
51
|
+
grounding guard strips any value it can't trace, and the app runs in a deterministic, no-LLM mode (the science
|
|
52
|
+
lives in the engine, not the model). This cycle improves **usability/adoption**, not validation — a real-data
|
|
53
|
+
result and a first lab user remain the standing bottleneck. No new science; contracts under the 1.0 commitment.
|
|
54
|
+
|
|
6
55
|
## [6.1.0] - 2026-06-11 - v6.1: The AI Integration Surface
|
|
7
56
|
|
|
8
57
|
**Post-1.0 adoption surface for AI builders.** Not new capability — the *introspectable, documented, dependable*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pen-stack
|
|
3
|
-
Version: 6.1
|
|
3
|
+
Version: 6.2.1
|
|
4
4
|
Summary: Open infrastructure for genome writing: the Writable Genome atlas, the Writer Atlas, and the Write Planner.
|
|
5
5
|
Author-email: Anees Ahmed Mahaboob Ali <ahmedaneesm@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -90,9 +90,9 @@ every design against rule-grounded mechanism, reports calibrated confidence, cit
|
|
|
90
90
|
[](https://codecov.io/gh/ahmedanees-m/pen-stack)
|
|
91
91
|
[](LICENSE)
|
|
92
92
|
[](https://www.python.org/)
|
|
93
|
-
[](CHANGELOG.md)
|
|
94
94
|
[](docs/STABILITY.md)
|
|
95
|
-
[](tests/)
|
|
96
96
|
[](https://github.com/astral-sh/ruff)
|
|
97
97
|
[](docker/)
|
|
98
98
|
[](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
|
-
│ ├──
|
|
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
|
[](https://codecov.io/gh/ahmedanees-m/pen-stack)
|
|
16
16
|
[](LICENSE)
|
|
17
17
|
[](https://www.python.org/)
|
|
18
|
-
[](CHANGELOG.md)
|
|
19
19
|
[](docs/STABILITY.md)
|
|
20
|
-
[](tests/)
|
|
21
21
|
[](https://github.com/astral-sh/ruff)
|
|
22
22
|
[](docker/)
|
|
23
23
|
[](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
|
-
│ ├──
|
|
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
|
|
2
|
+
__version__ = "6.2.1"
|
|
@@ -8,6 +8,7 @@ Run: ``uvicorn pen_stack.server.api:app --host 0.0.0.0 --port 8000`` (needs the
|
|
|
8
8
|
"""
|
|
9
9
|
from __future__ import annotations
|
|
10
10
|
|
|
11
|
+
import json
|
|
11
12
|
from pathlib import Path
|
|
12
13
|
|
|
13
14
|
import pandas as pd
|
|
@@ -34,6 +35,12 @@ def _atlas_df() -> pd.DataFrame:
|
|
|
34
35
|
return pd.read_parquet(_ATLAS)
|
|
35
36
|
|
|
36
37
|
|
|
38
|
+
def _records(df: pd.DataFrame) -> list[dict]:
|
|
39
|
+
"""JSON-safe records from a DataFrame: NaN/inf -> null and numpy scalars -> native (pandas `to_json`
|
|
40
|
+
handles both). Raw `to_dict('records')` leaks non-finite floats, which the JSON encoder rejects (500)."""
|
|
41
|
+
return json.loads(df.to_json(orient="records"))
|
|
42
|
+
|
|
43
|
+
|
|
37
44
|
@app.get("/health")
|
|
38
45
|
def health():
|
|
39
46
|
return {"status": "ok", "version": __version__, "atlas_present": _ATLAS.exists()}
|
|
@@ -60,7 +67,7 @@ def atlas(family: str | None = None, limit: int = Query(50, le=500)):
|
|
|
60
67
|
cols = [c for c in ["representative_system", "family", "confidence", "mechanism_bucket",
|
|
61
68
|
"deliv_class", "readiness", "cargo_capacity_bp", "reachability_tier",
|
|
62
69
|
"human_cell_activity"] if c in df.columns]
|
|
63
|
-
return {"n": int(len(df)), "rows": df[cols].head(limit)
|
|
70
|
+
return {"n": int(len(df)), "rows": _records(df[cols].head(limit)), "disclaimer": _DISCLAIMER}
|
|
64
71
|
|
|
65
72
|
|
|
66
73
|
@app.get("/crosslink/writers")
|
|
@@ -86,7 +93,7 @@ def crosslink_loci(family: str, ct: str = "k562", top: int = Query(20, le=200)):
|
|
|
86
93
|
loci = cl.loci_for_writer(family, ct, top=top)
|
|
87
94
|
except FileNotFoundError as e:
|
|
88
95
|
raise HTTPException(503, str(e)) from e
|
|
89
|
-
return {"family": family, "ct": ct, "loci": loci
|
|
96
|
+
return {"family": family, "ct": ct, "loci": _records(loci), "disclaimer": _DISCLAIMER}
|
|
90
97
|
|
|
91
98
|
|
|
92
99
|
@app.get("/writable")
|
|
@@ -99,7 +106,7 @@ def writable(gene: str, ct: str = "k562", top: int = Query(20, le=200)):
|
|
|
99
106
|
if g.empty:
|
|
100
107
|
return {"gene": gene, "ct": ct, "loci": [], "disclaimer": _DISCLAIMER}
|
|
101
108
|
cols = ["chrom", "bin", "safety", "p_durable", "writability"]
|
|
102
|
-
return {"gene": gene, "ct": ct, "loci": g[cols].head(top)
|
|
109
|
+
return {"gene": gene, "ct": ct, "loci": _records(g[cols].head(top)), "disclaimer": _DISCLAIMER}
|
|
103
110
|
|
|
104
111
|
|
|
105
112
|
@app.get("/bridge/design")
|
|
@@ -223,3 +230,29 @@ def session_endpoint(req: dict):
|
|
|
223
230
|
predicted outcomes + per-axis immune profiles + suggested experiments + citations + scope ledger + safety."""
|
|
224
231
|
from pen_stack.agent.co_scientist import co_scientist_session
|
|
225
232
|
return co_scientist_session(req["goal"], req.get("cell_state", "k562"), candidates=req.get("candidates"))
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
# ======================================================================================
|
|
236
|
+
# v5.13 — The Genome-Writing Challenge (read-only surface for the web Challenge page).
|
|
237
|
+
# Public tasks (NO labels) + the PEN-STACK reference submission that anchors the leaderboard. Submissions
|
|
238
|
+
# are Python `predict_fn`s scored offline (`benchmarks/genome_writing_challenge/run.py`) — never accepted
|
|
239
|
+
# over HTTP — so these routes only EXPOSE the held-out round and the anchor score.
|
|
240
|
+
# ======================================================================================
|
|
241
|
+
@app.get("/challenge/tasks", tags=["challenge"])
|
|
242
|
+
def challenge_tasks(round_id: str = "2026R1"):
|
|
243
|
+
"""The public inputs of the current held-out round (family + design + instructions; NEVER the label)."""
|
|
244
|
+
from benchmarks.genome_writing_challenge.harness import _round_tasks
|
|
245
|
+
tasks = _round_tasks(round_id)
|
|
246
|
+
return {"round": round_id, "n_tasks": len(tasks),
|
|
247
|
+
"tasks": [{"id": t.id, "family": t.family, "public_input": t.public_input} for t in tasks]}
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
@app.get("/challenge/leaderboard", tags=["challenge"])
|
|
251
|
+
def challenge_leaderboard(round_id: str = "2026R1"):
|
|
252
|
+
"""The leaderboard anchored by the PEN-STACK reference submission (deterministic, non-circular labels,
|
|
253
|
+
no-fabrication audited). External submissions are scored offline and appended here after a round."""
|
|
254
|
+
from benchmarks.genome_writing_challenge.harness import evaluate, reference_submission
|
|
255
|
+
ref = evaluate(reference_submission(), round_id)
|
|
256
|
+
return {"round": round_id, "leaderboard": [ref],
|
|
257
|
+
"rules": {"no_circular_labels": ref["no_circular_labels"],
|
|
258
|
+
"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"}
|