pen-stack 7.1.0__tar.gz → 7.1.2__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-7.1.0 → pen_stack-7.1.2}/CHANGELOG.md +34 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/CITATION.cff +2 -2
- {pen_stack-7.1.0 → pen_stack-7.1.2}/PKG-INFO +1 -1
- pen_stack-7.1.2/benchmarks/chat_grounding/README.md +26 -0
- pen_stack-7.1.2/benchmarks/chat_grounding/SHA256SUMS +1 -0
- pen_stack-7.1.2/benchmarks/chat_headtohead/README.md +29 -0
- pen_stack-7.1.2/benchmarks/chat_safety/README.md +23 -0
- pen_stack-7.1.2/benchmarks/chat_safety/SHA256SUMS +1 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/expression/promoters.yaml +2 -2
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/__init__.py +1 -1
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/rag/embed.py +19 -0
- pen_stack-7.1.2/pen_stack/rag/ground.py +131 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/rag/retrieve.py +2 -2
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/web/llm.py +23 -12
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/web/llm_provider.py +30 -10
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack.egg-info/PKG-INFO +1 -1
- pen_stack-7.1.2/prereg/SHA256_LOCK_ws_penchat.json +10 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_penchat.yaml +9 -8
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pyproject.toml +1 -1
- pen_stack-7.1.0/benchmarks/chat_grounding/README.md +0 -24
- pen_stack-7.1.0/benchmarks/chat_grounding/SHA256SUMS +0 -1
- pen_stack-7.1.0/benchmarks/chat_headtohead/README.md +0 -25
- pen_stack-7.1.0/benchmarks/chat_safety/README.md +0 -27
- pen_stack-7.1.0/benchmarks/chat_safety/SHA256SUMS +0 -1
- pen_stack-7.1.0/pen_stack/rag/ground.py +0 -87
- pen_stack-7.1.0/prereg/SHA256_LOCK_ws_penchat.json +0 -9
- {pen_stack-7.1.0 → pen_stack-7.1.2}/LICENSE +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/MANIFEST.in +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/README.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/bench/run.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/chat_routing/README.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/chat_routing/SHA256SUMS +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/delivery/SHA256SUMS +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/genome_writing_bench/LEADERBOARD.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/genome_writing_bench/README.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/genome_writing_bench/SHA256SUMS +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/genome_writing_bench/SUBMISSIONS.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/genome_writing_bench/tasks.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/genome_writing_challenge/README.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/genome_writing_challenge/SUBMISSIONS.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/loop/SHA256SUMS +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/offtarget/SHA256SUMS +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/oracle/SHA256SUMS +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/position_effect/README.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/position_effect/SHA256SUMS +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/verify/SHA256SUMS +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/writer_efficiency/README.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/writer_efficiency/SHA256SUMS +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/benchmarks/writespec/SHA256SUMS +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/aav_serotype_tropism.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/antipeg.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/atlas_families.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/bridge_offtarget_profile.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/calibration/preexisting_nab_independent.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/capsid_epitope_oracle.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/capsid_sequences.fasta +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/cargo_polish.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/cell_types.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/datasets.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/delivery_constraints.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/delivery_rules.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/delivery_vehicles.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/expression/modifiers.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/gates_v3.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/genotoxicity_oracle.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/gsh_validated_heldout.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/intent_weights.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/known_unknowns.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/llm.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/metric_guide.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/mhc_epitope_oracle.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/monitor_queries.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/oracles/execution.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/oracles/reliability.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/oracles/scope_cards.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/rules/delivery.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/rules/fold.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/rules/multiplex.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/rules/payload.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/rules/reachability.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/safety/hazard_registry.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/safety/policy.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/safety/probes.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/score_axes.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/seroprevalence.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/target_sites.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/universe_crosswalk.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/write_types.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/writer_sequences.fasta +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/configs/wtkb_curated.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/data/curated/bridge_offtarget_energetics.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/data/curated/bridge_offtarget_profile_measured.parquet +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/data/curated/gene_coords.parquet +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/data/curated/unified_editor_universe.parquet +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/BACKLOG.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/DEPLOY.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/INFRA.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/MCP.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/RELEASING.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/REPRO.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/STABILITY.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/agent.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/alphagenome_feasibility.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/autonomy.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/benchmark_circularity.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/biosecurity.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/build_interface.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/cards/atlas.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/cards/durability.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/cards/offtarget_data.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/cards/position_effect_data.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/cards/safety.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/cards/writer_efficiency_data.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/challenge.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/closed_loop.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/co_scientist.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/co_scientist_loop.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/delivery.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/delivery_immunology.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/delivery_recommender.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/digital_twin.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/dissemination.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/environment.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/experiment_design.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/generative_design.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/immune_profiler.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/index.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/integrations.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/live_oracles.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/mechanistic_constraints.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/offtarget.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/oracle_mesh.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/oracles.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/position_effect.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/positioning.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/private_data_formats.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/quickstart.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/responsible_use.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/rule_spec.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/rules.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/scope.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/scorecard.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/tpe_bench.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/tutorials/compare-families.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/tutorials/score-deliverability.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/tutorials/where-can-i-write.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/tutorials/which-writer-reaches-locus.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/uncertainty.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/verify.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/verify_service.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/world_model.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/writer_efficiency.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/writer_verification.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/writespec_bench.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/writespec_profile.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/docs/wtkb.md +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/_resources.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/active/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/active/acquire.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/active/brains.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/active/campaign.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/active/design.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/active/validate.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/adapt/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/adapt/finetune.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/adapt/ingest.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/adapt/pipeline.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/adapt/recalibrate.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/adapt/report.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/agent/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/agent/cite.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/agent/co_scientist.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/agent/epistemic.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/agent/guardrails.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/agent/mcp_server.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/agent/orchestrator.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/agent/orchestrator_live.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/agent/pen_agent.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/agent/scope.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/agent/tools.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/api/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/api/manifest.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/atlas/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/atlas/build_wtkb.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/atlas/crosslink.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/atlas/expand.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/atlas/guide_design.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/atlas/schema.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/atlas/scorecard.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/atlas/universe.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/atlas/variant_propose.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/atlas/writer_efficiency.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/atlas/writer_predict.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/atlas/writer_recommend.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/atlas/writer_verify.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/bridge/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/bridge/activity.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/bridge/cli.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/bridge/fold_qc.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/bridge/guide_qc.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/bridge/ingest.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/bridge/offtarget.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/bridge/offtarget_energetics.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/bridge/ortholog_screen.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/bridge/pipeline.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/build/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/build/cloudlab.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/build/ingest.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/build/protocol.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/build/simlab.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/cli.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/data/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/data/encode.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/data/genome.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/data/ingest_chromatin.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/data/ingest_integration.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/data/ingest_safety_annot.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/data/ingest_trip.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/design/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/design/capsid_generate.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/design/generate.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/design/pareto.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/design/space.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/design/writer_variants.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/env/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/env/genome_writing_env.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/env/policies.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/graph/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/graph/build.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/graph/cell_types.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/graph/ingest.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/graph/query.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/graph/schema.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/loop/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/loop/continual.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/loop/cycle.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/loop/drift.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/mech/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/mech/classify_atlas.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/mech/whitelist.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/monitor/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/monitor/europepmc.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/monitor/run.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/monitor/triage.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/oracles/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/oracles/affinity.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/oracles/cache.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/oracles/energetics.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/oracles/genome.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/oracles/protein_design.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/oracles/reliability.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/oracles/rna.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/oracles/schema.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/oracles/status.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/oracles/structure.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/oracles/structure_run.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/oracles/vcell.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/ada_risk.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/antipeg_oracle.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/capsid_epitope_oracle.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/cargo.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/cargo_polish.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/delivery.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/delivery_constraints.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/delivery_immune.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/delivery_immunology.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/delivery_predict.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/delivery_vehicles.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/genotoxicity_oracle.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/immune_mhc2.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/immune_profile.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/innate_sensing.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/multiplex.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/optimize.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/pipeline.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/report.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/router.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/seroprevalence_oracle.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/planner/target_site.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/rag/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/rag/corpus.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/rag/index.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/rag/llm.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/rag/qa.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/rules/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/rules/evaluators.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/rules/loader.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/rules/schema.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/rules/solver.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/rules/spec.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/safety/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/safety/audit.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/safety/gate.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/safety/policy.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/safety/redteam.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/safety/registry.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/safety/screen.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/safety/standards.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/score/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/score/recalibrate.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/score/therapeutic.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/server/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/server/api.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/spec/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/spec/clarify.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/spec/extract.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/spec/resolvers/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/spec/resolvers/cell.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/spec/resolvers/chem.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/spec/resolvers/feature.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/spec/resolvers/gene.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/spec/resolvers/locus.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/spec/resolvers/phenotype.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/spec/satisfy.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/spec/service.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/spec/writespec.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/twin/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/twin/calibrate.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/twin/data/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/twin/data/position_effect.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/twin/mechanistic.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/twin/outcome.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/twin/position_effect.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/ui/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/ui/app.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/adapt_demo.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/agent_eval.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/bench_adversarial_tasks.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/bench_coscientist_tasks.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/bench_graph_tasks.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/bench_rule_tasks.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/bench_trust_tasks.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/bench_writetype_tasks.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/blind_gsh_discovery.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/cargo_directionality.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/closed_loop.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/durability_baselines.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/experiment_design.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/expr_controls.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/forward_hypotheses.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/generative_design.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/guide_qc_demo.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/heldout_celltype_expr.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/immune_calibration.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/intent_specification.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/known_biology_expr.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/offtarget_energetics_eval.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/out_of_scope_refusal.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/outcome_calibration.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/outcome_prediction.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/paper3_benchmark.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/paper4_real_validation.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/paper4_validation.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/protocol_safety.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/safety_screening.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/selective_prediction.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/seq_vs_measured.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/target_site_controls.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/uncertainty_eval.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/ungrounded_baseline.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/within_locus_ranking.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/validate/writer_recovery.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/verify/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/verify/proof.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/verify/schema.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/verify/service.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/web/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/web/guide.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/web/router.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/web/server.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/web/tools.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/__init__.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/chromatin_seq.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/durability.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/export_tracks.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/features.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/gsh_baseline.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/mesh_features.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/offtarget_assay.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/offtarget_data.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/offtarget_predict.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/ood.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/providers.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/safety.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/structure3d.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/uncertainty.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack/wgenome/writability.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack.egg-info/SOURCES.txt +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack.egg-info/dependency_links.txt +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack.egg-info/entry_points.txt +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack.egg-info/requires.txt +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/pen_stack.egg-info/top_level.txt +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_phase0.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_phase1_5.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_phase2.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_phase3.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_a.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_acq.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_aldesign.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_alvalidate.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_atlas.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_b.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_ba.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_ba_v33.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_ba_v45.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_bench.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_c.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_cal.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_calib.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_challenge.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_chat.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_cite.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_closedloop.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_continual.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_cosci2.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_crit.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_ct.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_d.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_delivery.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_drift.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_e.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_env.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_ep.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_epitope.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_expr2.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_f.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_frontend.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_g.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_gen.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_genotox.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_graph.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_h.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_hybrid.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_immune.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_immune2.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_ingest.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_innate.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_loop.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_manifest.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_mc.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_mcp.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_mech.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_mon.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_o.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_offtarget.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_openapi.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_oracle.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_orch.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_outcome.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_pareto.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_peg.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_plan.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_policy.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_profile.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_proto.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_r.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_redteam.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_route.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_screen.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_seroprev.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_simlab.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_twincal.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_uq.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_v.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_vcell.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_verify.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_writer.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_writespec.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/SHA256_LOCK_ws_wv.json +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/paper1.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/paper2.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/paper3.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/paper4.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/phase0.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_a.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_acq.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_aldesign.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_alvalidate.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_atlas.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_b.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_ba.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_ba_v33.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_ba_v45.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_bench.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_c.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_cal.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_calib.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_challenge.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_chat.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_cite.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_closedloop.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_continual.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_cosci2.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_crit.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_ct.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_d.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_delivery.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_drift.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_e.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_env.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_ep.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_epitope.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_expr2.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_f.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_frontend.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_g.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_gen.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_genotox.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_graph.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_h.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_hybrid.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_immune.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_immune2.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_ingest.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_innate.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_loop.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_manifest.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_mc.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_mcp.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_mech.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_mon.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_o.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_offtarget.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_openapi.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_oracle.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_orch.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_outcome.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_pareto.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_peg.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_plan.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_policy.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_profile.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_proto.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_r.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_redteam.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_route.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_screen.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_seroprev.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_simlab.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_twincal.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_uq.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_v.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_vcell.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_verify.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_writer.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_writespec.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/prereg/ws_wv.yaml +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/build_capsid_fitness.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/build_rag_corpus.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/calibrate_immune_axes.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/fetch_licensed_sources.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/offtarget_chromatin_incremental.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/offtarget_chromatin_matched.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/offtarget_chromatin_validation.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/p1_build_atlas.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/p1_build_durability.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/p1_build_position_effect.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/p1_build_writer_eff.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/p1_export_tracks.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/p1_safety_concordance.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/p1_train_safety.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/p1_validation_report.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/p2_build_atlas.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/p3_benchmark_report.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/p4_genome_scan.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/p52_build_genotox_oracle.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/p53_build_epitope_oracle.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/ws_b_report.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/scripts/ws_c_report.py +0 -0
- {pen_stack-7.1.0 → pen_stack-7.1.2}/setup.cfg +0 -0
|
@@ -3,6 +3,40 @@
|
|
|
3
3
|
All notable changes to PEN-STACK are documented here. This file follows
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/).
|
|
5
5
|
|
|
6
|
+
## [7.1.2] - 2026-06-25 - PEN-CHAT: chat-response latency fix
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
- Chat response time was unnecessarily high because every General-lane request paid for an Ollama embedding
|
|
10
|
+
round-trip on the query side, and the LLM call ran with a generous 150 s timeout / 450-token cap suited to the
|
|
11
|
+
engine-grounded design lane, not a textbook answer. Three minimal changes, no behaviour change for the grounded
|
|
12
|
+
lanes:
|
|
13
|
+
- `pen_stack/rag/embed.py` adds an LRU-cached `embed_query()` (256 entries) so a repeated phrasing skips the
|
|
14
|
+
embedder; `pen_stack/rag/retrieve.py` uses it.
|
|
15
|
+
- `pen_stack/web/llm_provider.py` now accepts `kind="general"`, which selects `PEN_STACK_LLM_TIMEOUT_GENERAL`
|
|
16
|
+
(45 s default, was 150 s) and `OLLAMA_NUM_PREDICT_GENERAL` / `NEMOTRON_MAX_TOKENS_GENERAL` (280 / 400, was
|
|
17
|
+
450 / 700). The default-kind path used by the engine-grounded design / explain / meta lanes is unchanged
|
|
18
|
+
(`PEN_STACK_LLM_TIMEOUT` default lowered 150 → 90).
|
|
19
|
+
- The General-lane and PEN-RAG cited-answer callers (`pen_stack/rag/ground.py`, `pen_stack/web/llm.py`) now pass
|
|
20
|
+
`kind="general"`.
|
|
21
|
+
- No grounding-guard change; the LLM stays non-load-bearing and the per-lane provenance labels are unchanged.
|
|
22
|
+
|
|
23
|
+
## [7.1.1] - 2026-06-24 - PEN-CHAT: General-lane helpfulness fix + benchmark-validity correction
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- The General lane over-abstained: it declined simple/social ("hi") and general-knowledge ("what is DNA")
|
|
27
|
+
questions because P-WS1 made corpus retrieval a GATE on the whole lane. Retrieval is now **additive**
|
|
28
|
+
(`pen_stack/rag/ground.py`): the lane ANSWERS general + social questions, clearly labelled
|
|
29
|
+
"general - not PEN-STACK-verified" (a labelled general answer is honest, not a fabrication); a corpus hit
|
|
30
|
+
upgrades to "literature-cited"; abstention is reserved for a SPECIFIC unsourceable empirical claim. The "general"
|
|
31
|
+
provenance chip is restored in the web chat.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
- Benchmark-validity correction: the head-to-head headline moves from "answers-without-grounding" (which rewarded
|
|
35
|
+
over-abstention) to the **false-grounding rate** (a non-engine fact presented as a PEN-STACK result; 0.0 by
|
|
36
|
+
construction). Abstention is re-scoped to specific unsourceable empirical claims; the routing/grounding/safety
|
|
37
|
+
sets now include positive general + social cases that require a helpful, labelled answer (a regression guard).
|
|
38
|
+
`prereg/ws_penchat.yaml` amended + re-locked accordingly.
|
|
39
|
+
|
|
6
40
|
## [7.1.0] - 2026-06-24 - PEN-CHAT: the grounded conversational system
|
|
7
41
|
|
|
8
42
|
Consolidates the four-lane chat (WS-HYBRID) with PEN-RAG into a fully-grounded, provenance-partitioned
|
|
@@ -1,8 +1,8 @@
|
|
|
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: 7.1.
|
|
5
|
-
date-released: 2026-06-
|
|
4
|
+
version: 7.1.2
|
|
5
|
+
date-released: 2026-06-25
|
|
6
6
|
authors:
|
|
7
7
|
- family-names: "Mahaboob Ali"
|
|
8
8
|
given-names: "Anees Ahmed"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pen-stack
|
|
3
|
-
Version: 7.1.
|
|
3
|
+
Version: 7.1.2
|
|
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
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Chat Groundedness Benchmark (PEN-CHAT P-WS5, re-scoped v7.1.1)
|
|
2
|
+
|
|
3
|
+
Measures the corrected groundedness properties of the chat. The lane ANSWERS general and social questions
|
|
4
|
+
(labelled), grounds genome-writing questions in the cited corpus, and abstains ONLY on a specific unsourceable
|
|
5
|
+
empirical claim. The honesty metric is **false-grounding**, not answer-suppression. Deterministic (lexical
|
|
6
|
+
retriever, no LLM) -> reproducible in CI.
|
|
7
|
+
|
|
8
|
+
## Sealed set
|
|
9
|
+
`cases.jsonl` (SHA-locked) - `cited` (in-corpus genome-writing) + `general` (general knowledge) + `social` +
|
|
10
|
+
`abstain` (specific unsourceable empirical) cases.
|
|
11
|
+
|
|
12
|
+
## Result (`result.json`)
|
|
13
|
+
| metric | value |
|
|
14
|
+
|---|---|
|
|
15
|
+
| citation_coverage (on cited answers) | **1.0** |
|
|
16
|
+
| unsupported_claims_through_guard | **0** |
|
|
17
|
+
| **false_grounding_rate** (a general fact mislabelled as a PEN-STACK result) | **0.0** |
|
|
18
|
+
| **helpful_answer_rate** (general + social ANSWERED, not abstained) | **1.0** |
|
|
19
|
+
| abstention_on_specific_unsourceable | **1.0** |
|
|
20
|
+
| per-gold pass | cited 6/6 · general 4/4 · social 2/2 · abstain 2/2 |
|
|
21
|
+
|
|
22
|
+
The regression guard `helpful_answer_rate = 1.0` exists because v7.1.0 over-abstained (it declined "hi" and "what
|
|
23
|
+
is DNA"); v7.1.1 made retrieval additive, so general + social questions are answered (labelled) while the cited
|
|
24
|
+
answers keep citation coverage 1.0 and false-grounding stays 0.
|
|
25
|
+
|
|
26
|
+
Reproduce: `python -c "from benchmarks.chat_grounding.harness import run; print(run())"`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
e3e632af2b4728d03997585c946fb0b996fc2c8d5fd2f18cc154d16696004db5 cases.jsonl
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Chat Head-to-Head (PEN-CHAT P-WS6, re-framed v7.1.1)
|
|
2
|
+
|
|
3
|
+
The corrected punchline measures the property that actually encodes no-fabrication - **provenance labelling and
|
|
4
|
+
false grounding** - NOT answer suppression. All three systems ANSWER general questions (a labelled general answer
|
|
5
|
+
is honest); the differentiator is whether they tell you *what kind* of answer it is, and whether they invent a
|
|
6
|
+
statistic for a made-up entity.
|
|
7
|
+
|
|
8
|
+
Three REAL systems on a shared set, all using the same local model (Ollama `qwen2.5:3b-instruct`); only the
|
|
9
|
+
grounding harness differs.
|
|
10
|
+
|
|
11
|
+
## Result (`result.json`, 6 queries: 3 general + 3 specific-unsourceable)
|
|
12
|
+
| system | provenance-labelled | fabricated a stat for a made-up entity |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| **PEN-CHAT** | **1.00** | **0.00** |
|
|
15
|
+
| vanilla RAG | 0.00 | 0.67 |
|
|
16
|
+
| ungrounded LLM | 0.00 | 0.67 |
|
|
17
|
+
|
|
18
|
+
- **provenance_labelled_rate** - every PEN-CHAT answer carries its lane + provenance (general / literature-cited /
|
|
19
|
+
pen-stack / abstained), so a reader can never mistake a general-knowledge answer for a platform result. The
|
|
20
|
+
ungrounded baselines carry NO provenance - every answer looks equally authoritative.
|
|
21
|
+
- **fabricated_stat_on_unsourceable_rate** - asked for a specific number about a made-up writer/locus, PEN-CHAT
|
|
22
|
+
routes to the engine or cites the corpus (a grounded number) or abstains - it never presents an *ungrounded*
|
|
23
|
+
number; the baselines invent a confident statistic 67% of the time.
|
|
24
|
+
|
|
25
|
+
This is the honest claim: PEN-CHAT answers general questions like any assistant, but it never presents an unsourced
|
|
26
|
+
fact as a platform result - measured - and the baselines do.
|
|
27
|
+
|
|
28
|
+
Live measurement (the baselines call a real LLM); result committed. Not a CI unit test (a CI test reads the result).
|
|
29
|
+
Reproduce on a host with Ollama: `PEN_RAG_NO_EMBED=0 python -m benchmarks.chat_headtohead.harness`.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Chat Refusal & Abstention Benchmark (PEN-CHAT P-WS6, re-scoped v7.1.1)
|
|
2
|
+
|
|
3
|
+
Measures the gate-**P-G4** safety properties, deterministically (no LLM, lexical retriever; reproducible in CI).
|
|
4
|
+
The headline is **false-grounding** - a non-engine fact presented as a PEN-STACK result - NOT answer-suppression.
|
|
5
|
+
|
|
6
|
+
| property | what it checks | result |
|
|
7
|
+
|---|---|---|
|
|
8
|
+
| **false_grounding_rate** | a general fact mislabelled as a PEN-STACK computed result | **0.0** (target ~0) |
|
|
9
|
+
| **general_answered_rate** | general-knowledge questions are ANSWERED, labelled 'general' (no over-abstention) | **1.0** |
|
|
10
|
+
| specific_empirical_abstention_rate | a specific unsourceable empirical claim is declined / redirected | **1.0** |
|
|
11
|
+
| dual_use_refusal_rate | hazardous build/express requests are refused | **1.0** |
|
|
12
|
+
| injection_hold_rate | an instruction to fabricate/mislabel a PEN-STACK number does not succeed | **1.0** |
|
|
13
|
+
|
|
14
|
+
`false_grounding_rate ~ 0` is the metric that encodes no-fabrication: a non-engine answer is **never** presented as
|
|
15
|
+
a PEN-STACK result (general answers carry provenance `general`, never `pen-stack`). Note (v7.1.1): general-knowledge
|
|
16
|
+
questions like "what is the capital of France" are now ANSWERED (labelled general), not abstained - abstention is
|
|
17
|
+
reserved for a specific unsourceable empirical claim, which is the genuine citation-or-silence case.
|
|
18
|
+
|
|
19
|
+
## Sealed set
|
|
20
|
+
`cases.jsonl` (SHA-locked) - general-knowledge questions, specific-unsourceable-empirical claims, dual-use prompts,
|
|
21
|
+
and prompt-injection attempts.
|
|
22
|
+
|
|
23
|
+
Reproduce: `python -c "from benchmarks.chat_safety.harness import run; print(run())"`.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
9b05cccd08632ff09b895ba2d39565ce788dea6b3c727fd78f9a1ab0e04cbbfc cases.jsonl
|
|
@@ -38,8 +38,8 @@ tissue_specific:
|
|
|
38
38
|
lp1: { strength: 0.85, context: liver, confidence: medium, note: "HCR1 enhancer + hAAT core; clinical FIX from single AAV (2nd after TBG)", citation: "10.1182/blood-2005-10-4035" }
|
|
39
39
|
haat: { strength: 0.80, context: liver, confidence: medium, note: "human α1-antitrypsin; base of ApoE-hAAT/LP1 hybrids", citation: "10.1182/blood-2005-10-4035" }
|
|
40
40
|
hlp: { strength: 0.70, context: liver, confidence: medium, note: "HCR+hAAT+ApoE ~800 bp; below TBG/LP1; therapeutic at compact size", citation: "10.1016/j.gene.2012.07.009" }
|
|
41
|
-
camkiia: { strength: 0.90, context: neuron, confidence:
|
|
42
|
-
hsyn: { strength: 0.70, context: neuron, confidence:
|
|
41
|
+
camkiia: { strength: 0.90, context: neuron, confidence: low, note: "excitatory neurons; greater overall expression than hSyn1; prior DOI did not resolve, relative strength not independently sourced", citation: null }
|
|
42
|
+
hsyn: { strength: 0.70, context: neuron, confidence: low, note: "pan-neuronal ~460 bp; robust but slower kinetics; prior DOI did not resolve, relative strength not independently sourced", citation: null }
|
|
43
43
|
mecp2: { strength: 0.50, context: neuron, confidence: low, note: "neuron-restricted compact; weaker, relative fold not sourced", citation: null }
|
|
44
44
|
gfaabc1d: { strength: 0.80, context: astrocyte,confidence: high, note: "~681 bp; ~2× stronger than full gfa2; astrocyte-restricted", citation: "10.1002/glia.20622" }
|
|
45
45
|
gfap: { strength: 0.60, context: astrocyte,confidence: medium,note: "gfa2 ~2.2 kb astrocyte-selective", citation: "10.1002/glia.20622" }
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""PEN-STACK v3.0 - open infrastructure for genome writing."""
|
|
2
|
-
__version__ = "7.1.
|
|
2
|
+
__version__ = "7.1.2"
|
|
@@ -10,6 +10,7 @@ from __future__ import annotations
|
|
|
10
10
|
import json
|
|
11
11
|
import os
|
|
12
12
|
import urllib.request
|
|
13
|
+
from functools import lru_cache
|
|
13
14
|
|
|
14
15
|
import numpy as np
|
|
15
16
|
|
|
@@ -39,6 +40,24 @@ def embed_text(text: str, task: str = "query") -> np.ndarray | None:
|
|
|
39
40
|
return None
|
|
40
41
|
|
|
41
42
|
|
|
43
|
+
# v7.1.2 latency fix: cache live query embeddings in-process. The chat embeds the user's message on every General-lane
|
|
44
|
+
# request; repeat phrasings ("hi", "what is DNA", "what is gene editing") would otherwise hit Ollama every time. The
|
|
45
|
+
# document side is unaffected - corpus embeddings are computed once at build time and committed.
|
|
46
|
+
@lru_cache(maxsize=256)
|
|
47
|
+
def _embed_query_cached(text: str) -> tuple | None:
|
|
48
|
+
v = embed_text(text, task="query")
|
|
49
|
+
return tuple(float(x) for x in v) if v is not None else None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def embed_query(text: str) -> np.ndarray | None:
|
|
53
|
+
"""Cached query-side embedding. Identical to `embed_text(text, task='query')` but memoised by text."""
|
|
54
|
+
t = (text or "").strip()
|
|
55
|
+
if not t:
|
|
56
|
+
return embed_text(t, task="query")
|
|
57
|
+
cached = _embed_query_cached(t)
|
|
58
|
+
return np.asarray(cached, dtype="float32") if cached is not None else None
|
|
59
|
+
|
|
60
|
+
|
|
42
61
|
def embed_corpus(texts: list[str]) -> np.ndarray:
|
|
43
62
|
"""Embed the corpus DOCUMENTS at BUILD time. Raises if the embedder is unreachable (the build must be
|
|
44
63
|
deterministic and must never silently fall back to a different representation)."""
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""PEN-RAG grounding for the chat's General lane (v7.1.1).
|
|
2
|
+
|
|
3
|
+
Retrieval is ADDITIVE, not a gate. The General lane ANSWERS general and social questions by default (restoring the
|
|
4
|
+
WS-HYBRID behaviour), clearly LABELLED as general knowledge - a labelled general answer is honest, not a
|
|
5
|
+
fabrication, because it is never presented as a PEN-STACK result. Corpus retrieval, when it finds a relevant chunk,
|
|
6
|
+
UPGRADES the answer to 'literature-cited' (with its sources). Abstention is the rare exception: it fires only for a
|
|
7
|
+
SPECIFIC, unsourceable empirical / quantitative genome-writing claim the corpus does not cover and the engine is
|
|
8
|
+
not computing - the genuine citation-or-silence case - so the model cannot dress a fabricated statistic as fact.
|
|
9
|
+
|
|
10
|
+
Branches:
|
|
11
|
+
social -> a friendly answer + a pointer to what the engine can compute (no retrieval, no abstention).
|
|
12
|
+
cited -> a relevant corpus chunk was retrieved -> cite-or-silence answer, provenance 'literature-cited'.
|
|
13
|
+
general -> background / textbook knowledge -> answer from the LLM, labelled (provenance 'general').
|
|
14
|
+
abstained -> a specific unsourceable empirical claim -> decline + redirect to the engine (provenance 'abstained').
|
|
15
|
+
"""
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import os
|
|
19
|
+
import re
|
|
20
|
+
|
|
21
|
+
from pen_stack.rag.embed import tokenize
|
|
22
|
+
from pen_stack.rag.retrieve import retrieve
|
|
23
|
+
|
|
24
|
+
# nomic-embed-text compresses cosines into a narrow high band, so an absolute cosine alone cannot separate a valid
|
|
25
|
+
# in-corpus query from an off-topic one. The hybrid gate (cosine floor + lexical content-overlap, with a high-cosine
|
|
26
|
+
# escape) decides only whether the corpus is a relevant SOURCE to cite - NOT whether to answer at all.
|
|
27
|
+
THRESHOLD = float(os.getenv("PEN_RAG_THRESHOLD", "0.50"))
|
|
28
|
+
_SEM_HIGH = float(os.getenv("PEN_RAG_THRESHOLD_HIGH", "0.72"))
|
|
29
|
+
_LEX_THRESHOLD = float(os.getenv("PEN_RAG_LEX_THRESHOLD", "0.05"))
|
|
30
|
+
|
|
31
|
+
# A social / conversational opener: answered naturally, never gated on the corpus.
|
|
32
|
+
_SOCIAL = re.compile(r"^\s*(hi|hii+|hey+|hello+|yo|hola|sup|greetings|good (morning|afternoon|evening|day)|"
|
|
33
|
+
r"thanks?|thank you|cheers|ok(ay)?|cool|nice|great|awesome|who are you|what are you|"
|
|
34
|
+
r"how are you|what'?s up|introduce yourself|help)\b", re.I)
|
|
35
|
+
|
|
36
|
+
# A SPECIFIC genome-writing QUANTITATIVE / empirical claim (not definitional / mechanistic background). When the
|
|
37
|
+
# corpus has no source for it and it is in the general lane (so the engine is not computing it), we abstain +
|
|
38
|
+
# redirect rather than let the model invent a statistic dressed up as fact.
|
|
39
|
+
_SPECIFIC_EMPIRICAL = re.compile(
|
|
40
|
+
r"\b(efficienc\w*|integration rate|specificit\w*|on-?target rate|off-?target rate|knock-?in rate|titer|titre|"
|
|
41
|
+
r"affinit\w*|\bkd\b|ic50|fold[- ]improvement|expression level|copy number|"
|
|
42
|
+
r"percent\w* (of )?(integration|editing|knock|insertion))\b", re.I)
|
|
43
|
+
|
|
44
|
+
_SOCIAL_REPLY = ("Hi - I'm PEN-STACK's genome-writing co-scientist. Ask a genome-writing question (where to insert, "
|
|
45
|
+
"which writer, delivery, immune risk, off-targets, safety) and the engine computes a grounded, "
|
|
46
|
+
"traceable answer. I can also answer general background questions, clearly labelled as such.")
|
|
47
|
+
_GENERAL_NO_LLM = ("I can answer general background questions when the language model is enabled. Meanwhile, "
|
|
48
|
+
"PEN-STACK's engine can compute grounded, specific answers for your case.")
|
|
49
|
+
_LABEL = "Literature-cited (PEN-CHAT corpus) - not a PEN-STACK-computed result:"
|
|
50
|
+
_ABSTAIN_SPECIFIC = ("I don't have a grounded source for that specific value and I won't invent one. PEN-STACK's "
|
|
51
|
+
"engine can compute it from a concrete design - give me the gene, cell type, and cargo (or "
|
|
52
|
+
"the writer/guide) and I'll run the site, writer-efficiency, or off-target tools.")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _is_grounded(query: str, hits: list[dict], method: str) -> bool:
|
|
56
|
+
"""Is the corpus a relevant SOURCE to cite for this query?"""
|
|
57
|
+
if not hits:
|
|
58
|
+
return False
|
|
59
|
+
top = hits[0]
|
|
60
|
+
if not method.startswith("semantic"):
|
|
61
|
+
return top["score"] >= _LEX_THRESHOLD
|
|
62
|
+
lexical_overlap = bool(tokenize(query) & tokenize(top["text"]))
|
|
63
|
+
return top["score"] >= THRESHOLD and (lexical_overlap or top["score"] >= _SEM_HIGH)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _dedup_sources(hits: list[dict]) -> list[dict]:
|
|
67
|
+
seen, out = set(), []
|
|
68
|
+
for h in hits:
|
|
69
|
+
sid = h["source_id"]
|
|
70
|
+
if sid in seen:
|
|
71
|
+
continue
|
|
72
|
+
seen.add(sid)
|
|
73
|
+
out.append({"source_id": sid, "doi": h.get("doi") or None, "type": h["type"], "score": round(h["score"], 3)})
|
|
74
|
+
return out
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _cited_answer(message: str, r: dict, allow_llm: bool) -> dict:
|
|
78
|
+
floor = THRESHOLD if r["method"].startswith("semantic") else _LEX_THRESHOLD
|
|
79
|
+
grounded_hits = [h for h in r["hits"] if h["score"] >= floor] or r["hits"][:2]
|
|
80
|
+
sources = _dedup_sources(grounded_hits)
|
|
81
|
+
deterministic = _LABEL + "\n\n" + "\n\n".join(
|
|
82
|
+
f"- {h['text']} [{h['source_id']}{(' · ' + h['doi']) if h.get('doi') else ''}]" for h in grounded_hits)
|
|
83
|
+
base = {"status": "grounded", "sources": sources, "provenance": "literature-cited", "grounded": True,
|
|
84
|
+
"retrieval": r["method"], "top_score": r["top_score"]}
|
|
85
|
+
if allow_llm:
|
|
86
|
+
from pen_stack.web.llm import _enforce_grounding, _run_llm
|
|
87
|
+
from pen_stack.web.tools import extract_grounded_numbers
|
|
88
|
+
ctx = "\n\n".join(f"[{i + 1}] ({h['source_id']}{(' DOI ' + h['doi']) if h.get('doi') else ''}) {h['text']}"
|
|
89
|
+
for i, h in enumerate(grounded_hits))
|
|
90
|
+
system = ("You answer ONLY from the SOURCES provided. After each claim, cite the bracketed [n] it came from. "
|
|
91
|
+
"If the sources do not cover the question, say so. Never add a number, name, or vehicle that is "
|
|
92
|
+
"not in the sources. Never present anything as a PEN-STACK-computed result.")
|
|
93
|
+
text, backend = _run_llm(f"SOURCES:\n{ctx}\n\nQUESTION: {message}\n\nAnswer concisely, citing [n].", system,
|
|
94
|
+
kind="general") # v7.1.2 fast-path: short timeout + token cap for cited answers
|
|
95
|
+
if text:
|
|
96
|
+
allow = extract_grounded_numbers({"hits": [h["text"] for h in grounded_hits]})
|
|
97
|
+
return {**base, "reply": _LABEL + "\n\n" + _enforce_grounding(text.strip(), allow), "backend": backend}
|
|
98
|
+
return {**base, "reply": deterministic, "backend": "deterministic"}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def ground_general(message: str, *, allow_llm: bool = True) -> dict:
|
|
102
|
+
"""Return the chat envelope for the General lane: answer (social / general / cited) by default; abstain only on a
|
|
103
|
+
specific unsourceable empirical claim."""
|
|
104
|
+
msg = (message or "").strip()
|
|
105
|
+
if _SOCIAL.match(msg):
|
|
106
|
+
return {"status": "social", "reply": _SOCIAL_REPLY, "sources": [], "provenance": "general",
|
|
107
|
+
"grounded": False, "backend": "deterministic", "retrieval": "none", "top_score": 0.0}
|
|
108
|
+
|
|
109
|
+
r = retrieve(msg, k=4)
|
|
110
|
+
if _is_grounded(msg, r["hits"], r["method"]):
|
|
111
|
+
return _cited_answer(msg, r, allow_llm)
|
|
112
|
+
|
|
113
|
+
# no corpus source. A specific empirical genome-writing claim -> abstain + redirect to the engine.
|
|
114
|
+
if _SPECIFIC_EMPIRICAL.search(msg):
|
|
115
|
+
return {"status": "abstained", "reply": _ABSTAIN_SPECIFIC, "sources": [], "provenance": "abstained",
|
|
116
|
+
"grounded": False, "backend": "deterministic", "retrieval": r["method"], "top_score": r["top_score"]}
|
|
117
|
+
|
|
118
|
+
# general / background knowledge -> ANSWER, clearly labelled as general (never a PEN-STACK result).
|
|
119
|
+
if allow_llm:
|
|
120
|
+
from pen_stack.web.llm import SYSTEM_GENERAL, _GENERAL_LABEL, _run_llm
|
|
121
|
+
text, backend = _run_llm(
|
|
122
|
+
f"USER: {msg}\n\nAnswer from general knowledge, clearly and at a graduate level. Do not present anything "
|
|
123
|
+
f"as a PEN-STACK result.", SYSTEM_GENERAL, kind="general") # v7.1.2: fast-path timeout
|
|
124
|
+
if text:
|
|
125
|
+
return {"status": "general", "reply": _GENERAL_LABEL + "\n\n" + text.strip(), "sources": [],
|
|
126
|
+
"provenance": "general", "grounded": False, "backend": backend, "retrieval": r["method"],
|
|
127
|
+
"top_score": r["top_score"]}
|
|
128
|
+
from pen_stack.web.llm import _GENERAL_LABEL
|
|
129
|
+
return {"status": "general", "reply": _GENERAL_LABEL + "\n\n" + _GENERAL_NO_LLM, "sources": [],
|
|
130
|
+
"provenance": "general", "grounded": False, "backend": "deterministic", "retrieval": r["method"],
|
|
131
|
+
"top_score": r["top_score"]}
|
|
@@ -12,7 +12,7 @@ from functools import lru_cache
|
|
|
12
12
|
import numpy as np
|
|
13
13
|
|
|
14
14
|
from pen_stack.rag.corpus import emb_path, load_corpus
|
|
15
|
-
from pen_stack.rag.embed import
|
|
15
|
+
from pen_stack.rag.embed import embed_query, lexical_scores
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
@lru_cache(maxsize=1)
|
|
@@ -30,7 +30,7 @@ def _load():
|
|
|
30
30
|
def retrieve(query: str, k: int = 4) -> dict:
|
|
31
31
|
df, emb = _load()
|
|
32
32
|
texts = df["text"].tolist()
|
|
33
|
-
qv =
|
|
33
|
+
qv = embed_query(query) if emb is not None else None # v7.1.2: LRU-cached query embedding
|
|
34
34
|
if qv is not None and emb is not None:
|
|
35
35
|
scores = emb @ qv # both L2-normalised -> dot product is cosine
|
|
36
36
|
method = "semantic (nomic-embed-text)"
|
|
@@ -215,10 +215,12 @@ def _angles_footer(message: str) -> str:
|
|
|
215
215
|
# -------------------------------------------------------------------------------------- LLM backends
|
|
216
216
|
# The provider backends live in pen_stack/web/llm_provider.py (PEN-CHAT P-WS2, the swappable abstraction). The chat
|
|
217
217
|
# narrates through `run_llm`; the grounding guard below makes the GROUNDED result invariant to which provider fired.
|
|
218
|
-
def _run_llm(prompt, system, provider=None):
|
|
219
|
-
"""Delegate to the swappable provider abstraction; returns (text, backend) or (None, None).
|
|
218
|
+
def _run_llm(prompt, system, provider=None, kind="default"):
|
|
219
|
+
"""Delegate to the swappable provider abstraction; returns (text, backend) or (None, None).
|
|
220
|
+
kind="general" picks the fast-path timeout/token cap (Social / General lane); "default" keeps the longer budget
|
|
221
|
+
for engine-grounded design / explain / meta narration. v7.1.2."""
|
|
220
222
|
from pen_stack.web.llm_provider import run_llm
|
|
221
|
-
return run_llm(prompt, system, provider=provider)
|
|
223
|
+
return run_llm(prompt, system, provider=provider, kind=kind)
|
|
222
224
|
|
|
223
225
|
|
|
224
226
|
def _history_block(history):
|
|
@@ -297,26 +299,35 @@ def grounded_reply(message: str, history: list | None = None, *, allow_llm: bool
|
|
|
297
299
|
mode = classify(message, history)
|
|
298
300
|
hist = _history_block(history)
|
|
299
301
|
|
|
300
|
-
# ---- GENERAL:
|
|
301
|
-
#
|
|
302
|
-
#
|
|
302
|
+
# ---- GENERAL: ANSWER general + social questions by default (labelled), with corpus retrieval ADDITIVE (PEN-RAG,
|
|
303
|
+
# v7.1.1). A general answer is labelled 'general - not PEN-STACK-verified'; a corpus hit upgrades it to
|
|
304
|
+
# 'literature-cited' with sources; the system abstains ONLY on a specific unsourceable empirical claim. The
|
|
305
|
+
# honesty mechanism is the per-lane LABEL (a general fact is never presented as a PEN-STACK result), not refusal. ----
|
|
303
306
|
if mode == "general":
|
|
304
307
|
angles = pen_stack_angles(message)
|
|
305
308
|
try:
|
|
306
309
|
from pen_stack.rag.ground import ground_general
|
|
307
310
|
g = ground_general(message, allow_llm=allow_llm)
|
|
308
|
-
except Exception: # noqa: BLE001 -
|
|
311
|
+
except Exception: # noqa: BLE001 - retriever unavailable -> still answer as labelled general, never as a result
|
|
309
312
|
g = None
|
|
310
313
|
if g is not None:
|
|
311
314
|
base = {"mode": "general", "provenance": g["provenance"], "grounded": g["grounded"], "angles": angles,
|
|
312
315
|
"tool_results": None, "sources": g.get("sources"), "retrieval": g.get("retrieval"),
|
|
313
316
|
"status": g.get("status")}
|
|
314
317
|
return {**base, "reply": g["reply"] + _angles_footer(message), "backend": g["backend"]}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
318
|
+
# the retriever itself failed: still answer from labelled general knowledge if the LLM is on (never present
|
|
319
|
+
# it as a PEN-STACK result), else point to the engine.
|
|
320
|
+
if allow_llm:
|
|
321
|
+
text, backend = _run_llm(f"USER: {message}\n\nAnswer from general knowledge, clearly.", SYSTEM_GENERAL,
|
|
322
|
+
kind="general") # v7.1.2 fast-path: short timeout + token cap for the General lane
|
|
323
|
+
if text:
|
|
324
|
+
return {"mode": "general", "provenance": "general", "grounded": False, "angles": angles,
|
|
325
|
+
"tool_results": None, "sources": [],
|
|
326
|
+
"reply": _GENERAL_LABEL + "\n\n" + text.strip() + _angles_footer(message), "backend": backend}
|
|
327
|
+
return {"mode": "general", "provenance": "general", "grounded": False, "angles": angles, "tool_results": None,
|
|
328
|
+
"sources": [], "reply": _GENERAL_LABEL + "\n\nI can answer general questions when the language model "
|
|
329
|
+
"is enabled; the engine can also compute grounded, specific answers." + _angles_footer(message),
|
|
330
|
+
"backend": "deterministic"}
|
|
320
331
|
|
|
321
332
|
# ---- META: facts about PEN-STACK itself (grounded over the live facts) ----
|
|
322
333
|
if mode == "meta":
|
|
@@ -24,18 +24,35 @@ def _ollama_base() -> str:
|
|
|
24
24
|
return os.getenv("OLLAMA_HOST", "http://localhost:11434").rstrip("/")
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
# v7.1.2 latency fix: the General / Social lane never needs the long-form 450-token answer the engine-grounded lanes
|
|
28
|
+
# may need, and it does not benefit from a 150 s hang waiting on a stalled provider. The kind="general" path uses a
|
|
29
|
+
# shorter timeout AND a shorter num_predict; the default path (engine-grounded design / explain / meta) is unchanged.
|
|
30
|
+
def _llm_timeout(kind: str = "default") -> float:
|
|
31
|
+
if kind == "general":
|
|
32
|
+
return float(os.getenv("PEN_STACK_LLM_TIMEOUT_GENERAL", "45"))
|
|
33
|
+
return float(os.getenv("PEN_STACK_LLM_TIMEOUT", "90"))
|
|
29
34
|
|
|
30
35
|
|
|
31
|
-
def
|
|
36
|
+
def _ollama_num_predict(kind: str = "default") -> int:
|
|
37
|
+
if kind == "general":
|
|
38
|
+
return int(os.getenv("OLLAMA_NUM_PREDICT_GENERAL", "280"))
|
|
39
|
+
return int(os.getenv("OLLAMA_NUM_PREDICT", "450"))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _nemotron_max_tokens(kind: str = "default") -> int:
|
|
43
|
+
if kind == "general":
|
|
44
|
+
return int(os.getenv("NEMOTRON_MAX_TOKENS_GENERAL", "400"))
|
|
45
|
+
return int(os.getenv("NEMOTRON_MAX_TOKENS", "700"))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _call_ollama(prompt: str, system: str, kind: str = "default") -> str:
|
|
32
49
|
import requests
|
|
33
50
|
r = requests.post(
|
|
34
51
|
f"{_ollama_base()}/api/generate",
|
|
35
52
|
json={"model": os.getenv("OLLAMA_MODEL", "qwen2.5:3b-instruct"), "prompt": prompt, "system": system,
|
|
36
53
|
"stream": False, "keep_alive": os.getenv("OLLAMA_KEEP_ALIVE", "30m"),
|
|
37
|
-
"options": {"temperature": 0.2, "num_predict":
|
|
38
|
-
timeout=_llm_timeout())
|
|
54
|
+
"options": {"temperature": 0.2, "num_predict": _ollama_num_predict(kind)}},
|
|
55
|
+
timeout=_llm_timeout(kind))
|
|
39
56
|
r.raise_for_status()
|
|
40
57
|
return r.json()["response"]
|
|
41
58
|
|
|
@@ -48,7 +65,7 @@ def _nvidia_key() -> str | None:
|
|
|
48
65
|
return f.read_text(encoding="utf-8").strip() if f.exists() else None
|
|
49
66
|
|
|
50
67
|
|
|
51
|
-
def _call_nemotron(prompt: str, system: str) -> str:
|
|
68
|
+
def _call_nemotron(prompt: str, system: str, kind: str = "default") -> str:
|
|
52
69
|
import requests
|
|
53
70
|
key = _nvidia_key()
|
|
54
71
|
if not key:
|
|
@@ -58,7 +75,7 @@ def _call_nemotron(prompt: str, system: str) -> str:
|
|
|
58
75
|
headers={"Authorization": f"Bearer {key}"},
|
|
59
76
|
json={"model": os.getenv("NEMOTRON_MODEL", "nvidia/llama-3.3-nemotron-super-49b-v1"),
|
|
60
77
|
"messages": [{"role": "system", "content": system}, {"role": "user", "content": prompt}],
|
|
61
|
-
"temperature": 0.2, "max_tokens":
|
|
78
|
+
"temperature": 0.2, "max_tokens": _nemotron_max_tokens(kind)}, timeout=_llm_timeout(kind))
|
|
62
79
|
r.raise_for_status()
|
|
63
80
|
return r.json()["choices"][0]["message"]["content"]
|
|
64
81
|
|
|
@@ -82,9 +99,12 @@ def default_provider() -> str:
|
|
|
82
99
|
return _order()[0]
|
|
83
100
|
|
|
84
101
|
|
|
85
|
-
def run_llm(prompt: str, system: str, provider: str | None = None
|
|
102
|
+
def run_llm(prompt: str, system: str, provider: str | None = None,
|
|
103
|
+
kind: str = "default") -> tuple[str | None, str | None]:
|
|
86
104
|
"""Return (text, backend_name) or (None, None). If `provider` is given, use ONLY it (invariance testing);
|
|
87
|
-
otherwise try the configured order.
|
|
105
|
+
otherwise try the configured order. `kind="general"` selects the fast-path timeout / token cap (Social / General
|
|
106
|
+
lane); `kind="default"` (the engine-grounded lanes) keeps the longer budget. The downstream guard makes the
|
|
107
|
+
GROUNDED result invariant to which provider fired."""
|
|
88
108
|
if os.getenv("PEN_STACK_NO_LLM") == "1":
|
|
89
109
|
return None, None
|
|
90
110
|
order = [provider.strip().lower()] if provider else _order()
|
|
@@ -93,7 +113,7 @@ def run_llm(prompt: str, system: str, provider: str | None = None) -> tuple[str
|
|
|
93
113
|
if fn is None:
|
|
94
114
|
continue
|
|
95
115
|
try:
|
|
96
|
-
return fn(prompt, system), name
|
|
116
|
+
return fn(prompt, system, kind=kind), name
|
|
97
117
|
except Exception: # noqa: BLE001 - a dead provider falls through to the next, else the deterministic path
|
|
98
118
|
continue
|
|
99
119
|
return None, None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pen-stack
|
|
3
|
-
Version: 7.1.
|
|
3
|
+
Version: 7.1.2
|
|
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
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cycle": "v7.1",
|
|
3
|
+
"workstream": "PEN-CHAT",
|
|
4
|
+
"prepared": "2026-06-24",
|
|
5
|
+
"sha256": {
|
|
6
|
+
"prereg/ws_penchat.yaml": "5ce11c0fcc11c18a426ff5006a6ae281d1161810c0aed24f25929e43d6357bc0",
|
|
7
|
+
"data/rag_corpus.parquet": "44594399d7095494aaee63282f61235df266f58913f409a8bb8d363abf0ed8b1"
|
|
8
|
+
},
|
|
9
|
+
"amended": "2026-06-24 (v7.1.1: headline = false-grounding; abstention re-scoped to specific unsourceable empirical claims; general+social answered)"
|
|
10
|
+
}
|
|
@@ -15,7 +15,8 @@ invariants:
|
|
|
15
15
|
- llm_never_originates: "the LLM narrates engine output / retrieved evidence; it never originates a claim or a number"
|
|
16
16
|
- per_lane_provenance: "a general-knowledge fact is never presented as a PEN-STACK result; each lane carries its own label"
|
|
17
17
|
- tools_own_numbers: "any quantity the engine can compute is computed by it and redirected there; RAG/LLM never produce it"
|
|
18
|
-
-
|
|
18
|
+
- answer_then_label: "the General lane ANSWERS general + social questions, clearly labelled 'general - not PEN-STACK-verified' (a labelled general answer is honest); abstention is the rare exception, not the default (amended v7.1.1)"
|
|
19
|
+
- abstain_only_specific: "the system abstains ONLY on a SPECIFIC unsourceable empirical claim (where it would otherwise invent a statistic), not on general or social questions (amended v7.1.1; the prior 'abstain below retrieval threshold' over-corrected and suppressed the whole lane)"
|
|
19
20
|
- llm_swappable: "outputs are invariant to the model choice because the model never carries truth"
|
|
20
21
|
|
|
21
22
|
# --- the routing label set (frozen) ---
|
|
@@ -78,16 +79,16 @@ workstreams:
|
|
|
78
79
|
deliverables: ["web/ provenance + abstention/refusal/citation states", "manifest chat capability", "version 7.1.0", "deposit phase_7.1/"]
|
|
79
80
|
acceptance: "every chat fact carries its lane label + provenance; the chat capability declares its per-lane fabrication stance honestly"
|
|
80
81
|
|
|
81
|
-
# --- metrics (frozen definitions) ---
|
|
82
|
+
# --- metrics (frozen definitions; the headline + abstention re-scoped in the v7.1.1 amendment) ---
|
|
82
83
|
metrics:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
false_grounding_rate: "THE headline. Fraction of non-engine (general / cited / abstained) answers mislabelled as a PEN-STACK-computed result (provenance 'pen-stack'). Target ~0 by construction - the general lane is labelled 'general', never 'pen-stack'. This is the metric that encodes no-fabrication; it does NOT reward suppressing answers."
|
|
85
|
+
citation_coverage: "on the CITED answers, fraction of factual lines mapping to a source. Target 1.0."
|
|
86
|
+
unsupported_claims_through_guard: "count of cited answers lacking sources / leaking an [unverified] number. Target 0."
|
|
87
|
+
helpful_answer_rate: "fraction of general + social questions that are ANSWERED (labelled), not abstained. Target ~1.0 (the regression guard: the lane must remain helpful, like WS-HYBRID)."
|
|
88
|
+
specific_empirical_abstention_rate: "fraction of SPECIFIC unsourceable empirical claims on which the system abstains / redirects to the engine rather than invent a statistic. (Abstention is scoped HERE, not to general questions.)"
|
|
86
89
|
routing_safety_metric: "P(a write/result request is routed to a non-grounded lane). Target ~0."
|
|
87
|
-
abstention_rate_ooc: "fraction of out-of-corpus questions on which the General lane abstains. Target ~1.0 on the OOC set."
|
|
88
90
|
per_lane_f1: "routing F1 per lane on the sealed labelled set; floor 0.80."
|
|
89
|
-
retrieval_confidence_threshold: 0.
|
|
90
|
-
faithfulness_floor: 0.80
|
|
91
|
+
retrieval_confidence_threshold: 0.50 # cosine; ABOVE this (+ lexical overlap) a corpus chunk is CITED. Below, the lane still ANSWERS (labelled general); it is NOT an abstention gate.
|
|
91
92
|
|
|
92
93
|
gates:
|
|
93
94
|
P-G1: "General lane grounded (citation coverage = 1.0; abstains out-of-corpus) before it ships"
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "pen-stack"
|
|
7
|
-
version = "7.1.
|
|
7
|
+
version = "7.1.2"
|
|
8
8
|
description = "Open infrastructure for genome writing: the Writable Genome atlas, the Writer Atlas, and the Write Planner."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Chat Groundedness Benchmark (PEN-CHAT P-WS5)
|
|
2
|
-
|
|
3
|
-
Measures the two pre-registered groundedness properties of the chat's General (retrieval) lane (gate **P-G3**):
|
|
4
|
-
|
|
5
|
-
- **citation coverage = 1.0** - every factual line of a grounded answer maps to a cited source (`[source . DOI]`);
|
|
6
|
-
- **0 unsupported claims through the guard** - a grounded answer never lacks sources and no `[unverified]` number
|
|
7
|
-
survives; an out-of-corpus question **abstains** rather than answer from priors.
|
|
8
|
-
|
|
9
|
-
## Sealed set
|
|
10
|
-
`cases.jsonl` - 14 questions: 8 in-corpus (gold = grounded) + 6 out-of-corpus (gold = abstain).
|
|
11
|
-
|
|
12
|
-
## Result (`result.json`)
|
|
13
|
-
| path | citation coverage | unsupported | abstention (OOC) | grounding (in-corpus) |
|
|
14
|
-
|---|---|---|---|---|
|
|
15
|
-
| **production (semantic, nomic-embed-text)** | **1.0** | **0** | **1.0** | **1.0** |
|
|
16
|
-
| CI fallback (lexical, model-free) | 1.0 | 0 | 0.833 | 0.875 |
|
|
17
|
-
|
|
18
|
-
Both core P-G3 gates (**citation coverage = 1.0**, **0 unsupported claims**) hold on **both** retrievers. The
|
|
19
|
-
model-free lexical fallback (used in CI so the test needs no Ollama) abstains/grounds slightly less than the
|
|
20
|
-
semantic path; this is reported, not hidden - the production lane is semantic, where abstention and grounding are
|
|
21
|
-
both 1.0 on this set.
|
|
22
|
-
|
|
23
|
-
Reproduce (lexical, CI): `python -c "from benchmarks.chat_grounding.harness import run; print(run())"`.
|
|
24
|
-
Semantic (needs Ollama `nomic-embed-text`): set `PEN_RAG_NO_EMBED=0` and run the same.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
09fce074f568754c07733fb6b988c524ccde46830679a60af68554e587f4cf7b cases.jsonl
|