agentinputlab 0.1.0a1__py3-none-any.whl
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.
- agentinputlab/__init__.py +28 -0
- agentinputlab/algorithms/__init__.py +6 -0
- agentinputlab/algorithms/acquire/__init__.py +145 -0
- agentinputlab/algorithms/acquire/adaptive_rag/__init__.py +43 -0
- agentinputlab/algorithms/acquire/adaptive_rag/replay.py +367 -0
- agentinputlab/algorithms/acquire/adaptive_rag/runtime.py +1202 -0
- agentinputlab/algorithms/acquire/adaptive_rag_common_support.py +542 -0
- agentinputlab/algorithms/acquire/hyde.py +296 -0
- agentinputlab/algorithms/acquire/hyde_controlled.py +200 -0
- agentinputlab/algorithms/acquire/hyde_external.py +148 -0
- agentinputlab/algorithms/acquire/ircot.py +28 -0
- agentinputlab/algorithms/acquire/ircot_common_support.py +478 -0
- agentinputlab/algorithms/acquire/ircot_native.py +355 -0
- agentinputlab/algorithms/acquire/ircot_replay.py +327 -0
- agentinputlab/algorithms/acquire/qrag/__init__.py +79 -0
- agentinputlab/algorithms/acquire/qrag/bridge.py +828 -0
- agentinputlab/algorithms/acquire/qrag/common_support.py +891 -0
- agentinputlab/algorithms/acquire/qrag/native_axis.py +71 -0
- agentinputlab/algorithms/acquire/qrag/reader_adapter.py +139 -0
- agentinputlab/algorithms/acquire/r2ag/__init__.py +57 -0
- agentinputlab/algorithms/acquire/r2ag/bridge.py +1312 -0
- agentinputlab/algorithms/acquire/r2ag/common_support.py +1029 -0
- agentinputlab/algorithms/acquire/r2ag/socket_runtime.py +255 -0
- agentinputlab/algorithms/clarify/__init__.py +61 -0
- agentinputlab/algorithms/clarify/_structured.py +64 -0
- agentinputlab/algorithms/clarify/active_task_disambiguation.py +371 -0
- agentinputlab/algorithms/clarify/ask_or_assume/__init__.py +17 -0
- agentinputlab/algorithms/clarify/ask_or_assume/monitor.py +410 -0
- agentinputlab/algorithms/clarify/future_turns.py +379 -0
- agentinputlab/algorithms/clarify/udcs.py +255 -0
- agentinputlab/algorithms/clarify/udcs_deterministic.py +196 -0
- agentinputlab/algorithms/curate/__init__.py +65 -0
- agentinputlab/algorithms/curate/acon/__init__.py +27 -0
- agentinputlab/algorithms/curate/acon/common.py +284 -0
- agentinputlab/algorithms/curate/acon/common_support.py +136 -0
- agentinputlab/algorithms/curate/acon/history_bridge.py +309 -0
- agentinputlab/algorithms/curate/acon/observation_bridge.py +290 -0
- agentinputlab/algorithms/curate/llmlingua/__init__.py +30 -0
- agentinputlab/algorithms/curate/llmlingua/adapters.py +537 -0
- agentinputlab/algorithms/curate/llmlingua/budget.py +48 -0
- agentinputlab/algorithms/curate/llmlingua/controlled.py +175 -0
- agentinputlab/algorithms/curate/llmlingua/multilingual.py +105 -0
- agentinputlab/algorithms/curate/llmlingua/span_map.py +167 -0
- agentinputlab/algorithms/curate/recomp/__init__.py +47 -0
- agentinputlab/algorithms/curate/recomp/external.py +1129 -0
- agentinputlab/algorithms/curate/recomp/selective.py +304 -0
- agentinputlab/algorithms/decompose/__init__.py +107 -0
- agentinputlab/algorithms/decompose/decomp/__init__.py +53 -0
- agentinputlab/algorithms/decompose/decomp/common_support.py +478 -0
- agentinputlab/algorithms/decompose/decomp/planner_component.py +199 -0
- agentinputlab/algorithms/decompose/decomp/worker_bridge.py +416 -0
- agentinputlab/algorithms/decompose/llm_compiler/__init__.py +35 -0
- agentinputlab/algorithms/decompose/llm_compiler/bridge.py +520 -0
- agentinputlab/algorithms/decompose/llm_compiler/common_support.py +504 -0
- agentinputlab/algorithms/decompose/plan_and_budget/__init__.py +43 -0
- agentinputlab/algorithms/decompose/plan_and_budget/cached_soft_budget.py +362 -0
- agentinputlab/algorithms/decompose/plan_and_budget/decomposer_component.py +107 -0
- agentinputlab/algorithms/decompose/plan_and_budget/full.py +205 -0
- agentinputlab/algorithms/decompose/plan_and_budget/hard_cap.py +246 -0
- agentinputlab/algorithms/decompose/plan_and_budget/regenerated_soft_budget.py +448 -0
- agentinputlab/algorithms/decompose/plan_and_solve/__init__.py +33 -0
- agentinputlab/algorithms/decompose/plan_and_solve/plan_component.py +192 -0
- agentinputlab/algorithms/decompose/plan_and_solve/ps_prompt.py +127 -0
- agentinputlab/algorithms/decompose/self_ask/__init__.py +27 -0
- agentinputlab/algorithms/decompose/self_ask/loop.py +362 -0
- agentinputlab/algorithms/decompose/self_ask/planner_component.py +117 -0
- agentinputlab/algorithms/reformulate/__init__.py +85 -0
- agentinputlab/algorithms/reformulate/infocqr/__init__.py +40 -0
- agentinputlab/algorithms/reformulate/infocqr/cache_replay.py +362 -0
- agentinputlab/algorithms/reformulate/infocqr/external.py +675 -0
- agentinputlab/algorithms/reformulate/infocqr/student.py +189 -0
- agentinputlab/algorithms/reformulate/query2doc/__init__.py +42 -0
- agentinputlab/algorithms/reformulate/query2doc/controlled_live.py +190 -0
- agentinputlab/algorithms/reformulate/query2doc/models.py +95 -0
- agentinputlab/algorithms/reformulate/query2doc/official_cached.py +335 -0
- agentinputlab/algorithms/reformulate/query2doc/querygym_bridge.py +223 -0
- agentinputlab/algorithms/reformulate/query2doc/querygym_runtime.py +326 -0
- agentinputlab/algorithms/reformulate/reformer/__init__.py +23 -0
- agentinputlab/algorithms/reformulate/reformer/external.py +417 -0
- agentinputlab/algorithms/reformulate/rrr.py +696 -0
- agentinputlab/annotation/__init__.py +5 -0
- agentinputlab/annotation/independent.py +428 -0
- agentinputlab/annotation/server.py +233 -0
- agentinputlab/annotation/static/app.js +121 -0
- agentinputlab/annotation/static/index.html +60 -0
- agentinputlab/annotation/static/review.css +2 -0
- agentinputlab/annotation/static/review.html +10 -0
- agentinputlab/annotation/static/review.js +11 -0
- agentinputlab/annotation/static/styles.css +55 -0
- agentinputlab/annotation/store.py +444 -0
- agentinputlab/api.py +368 -0
- agentinputlab/artifacts/__init__.py +15 -0
- agentinputlab/artifacts/json_file.py +104 -0
- agentinputlab/artifacts/manifest.py +98 -0
- agentinputlab/artifacts/store.py +157 -0
- agentinputlab/backends/__init__.py +98 -0
- agentinputlab/backends/embedding/__init__.py +25 -0
- agentinputlab/backends/embedding/base.py +145 -0
- agentinputlab/backends/embedding/callable.py +75 -0
- agentinputlab/backends/embedding/replay.py +129 -0
- agentinputlab/backends/llm/__init__.py +31 -0
- agentinputlab/backends/llm/base.py +149 -0
- agentinputlab/backends/llm/callable.py +108 -0
- agentinputlab/backends/llm/decomp_completion.py +88 -0
- agentinputlab/backends/llm/final_content_stop.py +72 -0
- agentinputlab/backends/llm/gpt_oss_final_channel.py +84 -0
- agentinputlab/backends/llm/openai_compatible.py +332 -0
- agentinputlab/backends/llm/transformers.py +171 -0
- agentinputlab/backends/retrieval/__init__.py +35 -0
- agentinputlab/backends/retrieval/base.py +50 -0
- agentinputlab/backends/retrieval/dense.py +777 -0
- agentinputlab/backends/retrieval/memory.py +119 -0
- agentinputlab/backends/retrieval/sqlite_fts.py +155 -0
- agentinputlab/backends/user/__init__.py +15 -0
- agentinputlab/backends/user/base.py +66 -0
- agentinputlab/backends/user/callable.py +54 -0
- agentinputlab/backends/user/replay.py +89 -0
- agentinputlab/backends/vector.py +38 -0
- agentinputlab/benchmarks/__init__.py +246 -0
- agentinputlab/benchmarks/acquisition.py +106 -0
- agentinputlab/benchmarks/ale.py +540 -0
- agentinputlab/benchmarks/appworld_ul.py +669 -0
- agentinputlab/benchmarks/assets.py +226 -0
- agentinputlab/benchmarks/base.py +68 -0
- agentinputlab/benchmarks/beir_archive.py +235 -0
- agentinputlab/benchmarks/beir_sample.py +269 -0
- agentinputlab/benchmarks/bfcl_native.py +245 -0
- agentinputlab/benchmarks/bfcl_v3.py +607 -0
- agentinputlab/benchmarks/cache.py +218 -0
- agentinputlab/benchmarks/clariq.py +203 -0
- agentinputlab/benchmarks/data/registry.json +321 -0
- agentinputlab/benchmarks/data/smoke_assets.json +511 -0
- agentinputlab/benchmarks/data/statebench_v0_8_1_task_ids.json +475 -0
- agentinputlab/benchmarks/data/toolsandbox_165848b_scenario_names.json +1 -0
- agentinputlab/benchmarks/execution.py +1111 -0
- agentinputlab/benchmarks/interactive.py +257 -0
- agentinputlab/benchmarks/ir_query.py +204 -0
- agentinputlab/benchmarks/longbench.py +203 -0
- agentinputlab/benchmarks/paired_replay.py +479 -0
- agentinputlab/benchmarks/preprocess.py +2313 -0
- agentinputlab/benchmarks/production.py +236 -0
- agentinputlab/benchmarks/qa.py +963 -0
- agentinputlab/benchmarks/registry.py +110 -0
- agentinputlab/benchmarks/retrieval.py +459 -0
- agentinputlab/benchmarks/runtime.py +509 -0
- agentinputlab/benchmarks/statebench.py +938 -0
- agentinputlab/benchmarks/tau3.py +725 -0
- agentinputlab/benchmarks/toolsandbox.py +626 -0
- agentinputlab/benchmarks/trec_dl_sample.py +263 -0
- agentinputlab/campaign.py +654 -0
- agentinputlab/campaign_runner.py +953 -0
- agentinputlab/cli/__init__.py +6 -0
- agentinputlab/cli/main.py +933 -0
- agentinputlab/connectors/__init__.py +46 -0
- agentinputlab/connectors/knowledge/__init__.py +4 -0
- agentinputlab/connectors/tools/__init__.py +30 -0
- agentinputlab/connectors/tools/base.py +57 -0
- agentinputlab/connectors/tools/mcp.py +222 -0
- agentinputlab/connectors/tools/memory.py +41 -0
- agentinputlab/connectors/tools/openapi.py +695 -0
- agentinputlab/connectors/tools/schema.py +102 -0
- agentinputlab/contracts/__init__.py +91 -0
- agentinputlab/contracts/availability.py +24 -0
- agentinputlab/contracts/dependency.py +58 -0
- agentinputlab/contracts/enums.py +82 -0
- agentinputlab/contracts/errors.py +63 -0
- agentinputlab/contracts/evidence.py +43 -0
- agentinputlab/contracts/intent.py +110 -0
- agentinputlab/contracts/lifecycle.py +164 -0
- agentinputlab/contracts/patch.py +167 -0
- agentinputlab/contracts/serialization.py +93 -0
- agentinputlab/contracts/state.py +127 -0
- agentinputlab/contracts/trace.py +59 -0
- agentinputlab/contracts/worker.py +42 -0
- agentinputlab/core/__init__.py +7 -0
- agentinputlab/data/__init__.py +32 -0
- agentinputlab/data/checksums.py +9 -0
- agentinputlab/data/downloader.py +235 -0
- agentinputlab/data/http.py +171 -0
- agentinputlab/data/index.py +21 -0
- agentinputlab/data/overlap.py +28 -0
- agentinputlab/data/preprocess.py +32 -0
- agentinputlab/data/storage.py +57 -0
- agentinputlab/data/trec_sample.py +427 -0
- agentinputlab/evaluation/__init__.py +5 -0
- agentinputlab/evaluation/outcomes.py +32 -0
- agentinputlab/experiments/__init__.py +278 -0
- agentinputlab/experiments/analysis.py +981 -0
- agentinputlab/experiments/artifacts.py +687 -0
- agentinputlab/experiments/automatic_measurement.py +678 -0
- agentinputlab/experiments/auxiliary_matrix.py +203 -0
- agentinputlab/experiments/bindings.py +430 -0
- agentinputlab/experiments/blueprints.py +147 -0
- agentinputlab/experiments/builders/__init__.py +45 -0
- agentinputlab/experiments/builders/executable_external_payload.py +423 -0
- agentinputlab/experiments/builders/external_process_arena.py +1018 -0
- agentinputlab/experiments/builders/registry_intervention.py +463 -0
- agentinputlab/experiments/cli.py +158 -0
- agentinputlab/experiments/controls.py +340 -0
- agentinputlab/experiments/driver_guard.py +205 -0
- agentinputlab/experiments/drivers/__init__.py +89 -0
- agentinputlab/experiments/drivers/external_arena.py +2908 -0
- agentinputlab/experiments/drivers/method_process.py +662 -0
- agentinputlab/experiments/drivers/parity_process.py +1484 -0
- agentinputlab/experiments/drivers/static_production.py +1574 -0
- agentinputlab/experiments/executor.py +448 -0
- agentinputlab/experiments/loader.py +605 -0
- agentinputlab/experiments/measurement.py +675 -0
- agentinputlab/experiments/paper_analysis.py +1818 -0
- agentinputlab/experiments/parity_identity.py +605 -0
- agentinputlab/experiments/plan.py +277 -0
- agentinputlab/experiments/production_builders.py +3739 -0
- agentinputlab/experiments/readiness.py +432 -0
- agentinputlab/experiments/schema.py +514 -0
- agentinputlab/experiments/secrets.py +177 -0
- agentinputlab/experiments/stateful_analysis.py +1738 -0
- agentinputlab/experiments/transfer_analysis.py +1316 -0
- agentinputlab/experiments/unseen_analysis.py +1025 -0
- agentinputlab/integrations/__init__.py +1 -0
- agentinputlab/integrations/action_space/__init__.py +1 -0
- agentinputlab/integrations/external_workers/__init__.py +76 -0
- agentinputlab/integrations/external_workers/ace.py +431 -0
- agentinputlab/integrations/external_workers/base.py +181 -0
- agentinputlab/integrations/external_workers/decomp_live.py +249 -0
- agentinputlab/integrations/external_workers/decomp_planner.py +30 -0
- agentinputlab/integrations/external_workers/infocqr_student.py +280 -0
- agentinputlab/integrations/external_workers/ircot.py +576 -0
- agentinputlab/integrations/external_workers/llmcompiler_live.py +360 -0
- agentinputlab/integrations/external_workers/longllmlingua.py +162 -0
- agentinputlab/integrations/external_workers/method.py +314 -0
- agentinputlab/integrations/external_workers/process.py +678 -0
- agentinputlab/integrations/external_workers/supervisor.py +1071 -0
- agentinputlab/integrations/full_architecture/__init__.py +1 -0
- agentinputlab/integrations/full_architecture/hyde.py +212 -0
- agentinputlab/integrations/full_architecture/plan_and_budget.py +188 -0
- agentinputlab/integrations/live_history.py +222 -0
- agentinputlab/integrations/prompt_optimization/__init__.py +1 -0
- agentinputlab/integrations/training/__init__.py +1 -0
- agentinputlab/metrics/__init__.py +50 -0
- agentinputlab/metrics/catalog.py +313 -0
- agentinputlab/metrics/harm.py +95 -0
- agentinputlab/metrics/paired.py +40 -0
- agentinputlab/metrics/qa.py +76 -0
- agentinputlab/metrics/text.py +33 -0
- agentinputlab/metrics/third_party.py +161 -0
- agentinputlab/models/__init__.py +4 -0
- agentinputlab/observability/__init__.py +56 -0
- agentinputlab/observability/budget.py +316 -0
- agentinputlab/observability/instrumentation.py +754 -0
- agentinputlab/observability/models.py +403 -0
- agentinputlab/observability/monitor.py +380 -0
- agentinputlab/optimizers/__init__.py +1 -0
- agentinputlab/optimizers/clarify/__init__.py +12 -0
- agentinputlab/optimizers/context/__init__.py +22 -0
- agentinputlab/optimizers/decompose/__init__.py +64 -0
- agentinputlab/optimizers/evidence/__init__.py +22 -0
- agentinputlab/optimizers/rewrite/__init__.py +30 -0
- agentinputlab/parity/__init__.py +5 -0
- agentinputlab/parity/base.py +206 -0
- agentinputlab/production_campaign.py +763 -0
- agentinputlab/py.typed +1 -0
- agentinputlab/recipes/__init__.py +333 -0
- agentinputlab/recipes/ace.py +418 -0
- agentinputlab/recipes/ace_bfcl.py +273 -0
- agentinputlab/recipes/ace_common_support.py +169 -0
- agentinputlab/recipes/ace_native_plan.py +322 -0
- agentinputlab/recipes/ace_online.py +711 -0
- agentinputlab/recipes/ace_retrieval.py +330 -0
- agentinputlab/recipes/ace_statebench.py +382 -0
- agentinputlab/recipes/ace_tau.py +463 -0
- agentinputlab/recipes/ace_toolsandbox.py +432 -0
- agentinputlab/recipes/acon_guideline.py +22 -0
- agentinputlab/recipes/adaptive_rag.py +822 -0
- agentinputlab/recipes/llmlingua2_inference.py +146 -0
- agentinputlab/recipes/llmlingua2_training.py +796 -0
- agentinputlab/recipes/mce.py +1486 -0
- agentinputlab/recipes/mce_final.py +335 -0
- agentinputlab/recipes/mce_text_fit.py +499 -0
- agentinputlab/recipes/mce_text_only.py +298 -0
- agentinputlab/recipes/qrag.py +729 -0
- agentinputlab/recipes/qrag_inference.py +364 -0
- agentinputlab/recipes/r2ag_features.py +236 -0
- agentinputlab/recipes/r2ag_inference.py +503 -0
- agentinputlab/recipes/r2ag_training.py +948 -0
- agentinputlab/recipes/recomp_abstractive.py +592 -0
- agentinputlab/recipes/recomp_extractive.py +525 -0
- agentinputlab/recipes/reformer.py +17 -0
- agentinputlab/recipes/rqrag.py +1516 -0
- agentinputlab/recipes/rqrag_common_support.py +193 -0
- agentinputlab/recipes/rqrag_completion.py +147 -0
- agentinputlab/recipes/skillopt.py +462 -0
- agentinputlab/recipes/skillopt_common_support.py +154 -0
- agentinputlab/recipes/skillopt_environment.py +165 -0
- agentinputlab/recipes/skillopt_environment_cli.py +5 -0
- agentinputlab/recipes/skillopt_retrieval.py +188 -0
- agentinputlab/recipes/smartsearch.py +897 -0
- agentinputlab/recipes/smartsearch_curriculum.py +283 -0
- agentinputlab/recipes/smartsearch_grpo_contracts.py +58 -0
- agentinputlab/recipes/smartsearch_grpo_data.py +314 -0
- agentinputlab/recipes/smartsearch_grpo_meter.py +324 -0
- agentinputlab/recipes/smartsearch_grpo_prefix.py +144 -0
- agentinputlab/recipes/smartsearch_grpo_rollout.py +119 -0
- agentinputlab/recipes/smartsearch_grpo_tools.py +364 -0
- agentinputlab/recipes/smartsearch_grpo_training.py +305 -0
- agentinputlab/recipes/smartsearch_grpo_transport.py +248 -0
- agentinputlab/recipes/smartsearch_grpo_worker.py +364 -0
- agentinputlab/recipes/smartsearch_inference.py +524 -0
- agentinputlab/recipes/smartsearch_native_data.py +172 -0
- agentinputlab/recipes/smartsearch_policy.py +616 -0
- agentinputlab/recipes/smartsearch_policy_worker.py +9 -0
- agentinputlab/recipes/smartsearch_sampling.py +232 -0
- agentinputlab/recipes/smartsearch_teacher.py +203 -0
- agentinputlab/recipes/smartsearch_training.py +265 -0
- agentinputlab/registry/__init__.py +46 -0
- agentinputlab/registry/beta.py +727 -0
- agentinputlab/registry/data/algorithms.json +1959 -0
- agentinputlab/registry/data/auxiliary_method_profiles.json +34 -0
- agentinputlab/registry/loader.py +100 -0
- agentinputlab/registry/result_manifest.py +184 -0
- agentinputlab/registry/runtime.py +195 -0
- agentinputlab/registry/schema.py +449 -0
- agentinputlab/runner/__init__.py +30 -0
- agentinputlab/runner/balance.py +248 -0
- agentinputlab/runner/cache.py +135 -0
- agentinputlab/runner/composite.py +130 -0
- agentinputlab/runner/engine.py +285 -0
- agentinputlab/runner/runtime_guard.py +268 -0
- agentinputlab/runner/worker.py +80 -0
- agentinputlab/runtime_bootstrap.py +288 -0
- agentinputlab/selectors/__init__.py +196 -0
- agentinputlab/selectors/advanced.py +1514 -0
- agentinputlab/selectors/artifacts.py +1087 -0
- agentinputlab/selectors/base.py +112 -0
- agentinputlab/selectors/campaigns.py +1893 -0
- agentinputlab/selectors/catalog.py +86 -0
- agentinputlab/selectors/discovery.py +1860 -0
- agentinputlab/selectors/evaluation.py +1348 -0
- agentinputlab/selectors/features.py +383 -0
- agentinputlab/selectors/learned.py +502 -0
- agentinputlab/selectors/no_op.py +28 -0
- agentinputlab/selectors/outcome_table.py +475 -0
- agentinputlab/selectors/producer.py +853 -0
- agentinputlab/selectors/rules.py +109 -0
- agentinputlab/selectors/runtime.py +420 -0
- agentinputlab/studies/__init__.py +16 -0
- agentinputlab/studies/design.py +165 -0
- agentinputlab/studies/paired.py +322 -0
- agentinputlab/studio/__init__.py +6 -0
- agentinputlab/studio/campaigns.py +819 -0
- agentinputlab/studio/engine.py +1408 -0
- agentinputlab/studio/model_backends.py +425 -0
- agentinputlab/studio/prepared.py +410 -0
- agentinputlab/studio/server.py +613 -0
- agentinputlab/studio/static/app.js +397 -0
- agentinputlab/studio/static/campaigns.html +175 -0
- agentinputlab/studio/static/campaigns.js +426 -0
- agentinputlab/studio/static/index.html +192 -0
- agentinputlab/studio/static/result.html +103 -0
- agentinputlab/studio/static/result.js +273 -0
- agentinputlab/studio/static/styles.css +467 -0
- agentinputlab-0.1.0a1.data/data/share/agentinputlab/CITATION.cff +22 -0
- agentinputlab-0.1.0a1.dist-info/METADATA +392 -0
- agentinputlab-0.1.0a1.dist-info/RECORD +469 -0
- agentinputlab-0.1.0a1.dist-info/WHEEL +5 -0
- agentinputlab-0.1.0a1.dist-info/entry_points.txt +6 -0
- agentinputlab-0.1.0a1.dist-info/licenses/LICENSE +21 -0
- agentinputlab-0.1.0a1.dist-info/licenses/NOTICE +31 -0
- agentinputlab-0.1.0a1.dist-info/licenses/THIRD_PARTY_NOTICES.md +94 -0
- agentinputlab-0.1.0a1.dist-info/top_level.txt +2 -0
- workers/README.md +94 -0
- workers/ace/README.md +261 -0
- workers/ace/__init__.py +1 -0
- workers/ace/compatibility_manifest.json +39 -0
- workers/ace/driver.py +1682 -0
- workers/acon/README.md +215 -0
- workers/acon/__init__.py +5 -0
- workers/acon/compatibility_manifest.json +93 -0
- workers/acon/driver.py +1859 -0
- workers/acon/fitted.py +395 -0
- workers/acon/guideline.py +470 -0
- workers/acon/guideline_source_manifest.json +20 -0
- workers/adaptive_rag/README.md +96 -0
- workers/adaptive_rag/__init__.py +15 -0
- workers/adaptive_rag/compatibility_manifest.json +61 -0
- workers/adaptive_rag/driver.py +1470 -0
- workers/adaptive_rag/fixture_runtime.py +163 -0
- workers/adaptive_rag/runtime.py +252 -0
- workers/ask_or_assume/README.md +124 -0
- workers/ask_or_assume/__init__.py +1 -0
- workers/ask_or_assume/compatibility_manifest.json +36 -0
- workers/ask_or_assume/driver.py +1227 -0
- workers/decomp/README.md +133 -0
- workers/decomp/UPSTREAM_LICENSE.Apache-2.0.txt +201 -0
- workers/decomp/__init__.py +5 -0
- workers/decomp/compatibility_manifest.json +205 -0
- workers/decomp/driver.py +1015 -0
- workers/decomp/live.py +137 -0
- workers/decomp/runtime.py +231 -0
- workers/infocqr/README.md +106 -0
- workers/infocqr/__init__.py +1 -0
- workers/infocqr/compatibility_manifest.json +84 -0
- workers/infocqr/driver.py +1766 -0
- workers/ircot/README.md +167 -0
- workers/ircot/__init__.py +7 -0
- workers/ircot/compatibility_manifest.json +121 -0
- workers/ircot/controlled.py +457 -0
- workers/ircot/driver.py +1373 -0
- workers/ircot/fixture_bindings.json +39 -0
- workers/ircot/fixture_config.json +48 -0
- workers/ircot/fixture_prompt.txt +2 -0
- workers/ircot/native_qa.py +398 -0
- workers/ircot/qa_compatibility_manifest.json +57 -0
- workers/ircot/runtime.py +97 -0
- workers/llmcompiler/README.md +160 -0
- workers/llmcompiler/__init__.py +1 -0
- workers/llmcompiler/compatibility_manifest.json +45 -0
- workers/llmcompiler/driver.py +1514 -0
- workers/llmcompiler/export_prompts.py +74 -0
- workers/llmcompiler/live.py +174 -0
- workers/llmcompiler/patch_manifest.json +147 -0
- workers/mce/README.md +198 -0
- workers/mce/__init__.py +29 -0
- workers/mce/compatibility_manifest.json +115 -0
- workers/mce/driver.py +2585 -0
- workers/mce/final_eval.py +173 -0
- workers/official_arenas/README.md +25 -0
- workers/official_arenas/__init__.py +1 -0
- workers/official_arenas/capture_records.py +110 -0
- workers/official_arenas/driver.py +619 -0
- workers/official_arenas/protocol.py +334 -0
- workers/official_arenas/providers/__init__.py +1 -0
- workers/official_arenas/providers/_live_history.py +228 -0
- workers/official_arenas/providers/_message_compat.py +77 -0
- workers/official_arenas/providers/appworld_ul.py +196 -0
- workers/official_arenas/providers/fixture.py +112 -0
- workers/official_arenas/providers/statebench.py +960 -0
- workers/official_arenas/providers/tau3.py +1672 -0
- workers/official_arenas/providers/tau_retail.py +586 -0
- workers/official_arenas/providers/toolsandbox.py +1321 -0
- workers/official_arenas/providers/tooltalk.py +699 -0
- workers/official_arenas/retail_capture.py +188 -0
- workers/official_arenas/retail_driver.py +275 -0
- workers/qrag/README.md +172 -0
- workers/qrag/__init__.py +1 -0
- workers/qrag/compatibility_manifest.json +64 -0
- workers/qrag/driver.py +673 -0
- workers/r2ag/README.md +154 -0
- workers/r2ag/__init__.py +5 -0
- workers/r2ag/compatibility_manifest.json +55 -0
- workers/r2ag/driver.py +1287 -0
- workers/r2ag/feature_schema.json +8 -0
- workers/r2ag/runtime.py +589 -0
- workers/recomp/README.md +120 -0
- workers/recomp/__init__.py +1 -0
- workers/recomp/compatibility_manifest.json +43 -0
- workers/recomp/driver.py +1653 -0
- workers/reformer/README.md +125 -0
- workers/reformer/__init__.py +1 -0
- workers/reformer/compatibility_manifest.json +68 -0
- workers/reformer/driver.py +1459 -0
- workers/reformer/induction.py +457 -0
- workers/rrr/README.md +126 -0
- workers/rrr/__init__.py +1 -0
- workers/rrr/compatibility_manifest.json +57 -0
- workers/rrr/driver.py +1133 -0
- workers/smartsearch/README.md +331 -0
- workers/smartsearch/__init__.py +1 -0
- workers/smartsearch/compatibility_manifest.json +41 -0
- workers/smartsearch/driver.py +1643 -0
|
@@ -0,0 +1,1893 @@
|
|
|
1
|
+
"""Frozen selector-study manifests and full-information policy analysis.
|
|
2
|
+
|
|
3
|
+
The campaign layer is deliberately execution neutral. It binds preregistered
|
|
4
|
+
selection rules, frozen policy artifacts, evaluation support, and diagnostic
|
|
5
|
+
roles without calling a model or benchmark. Real outcomes enter only through
|
|
6
|
+
an explicitly verified, non-synthetic result artifact.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import hashlib
|
|
12
|
+
import json
|
|
13
|
+
import math
|
|
14
|
+
import random
|
|
15
|
+
import re
|
|
16
|
+
from collections import defaultdict
|
|
17
|
+
from collections.abc import Mapping, Sequence
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from statistics import fmean
|
|
20
|
+
from typing import Any
|
|
21
|
+
|
|
22
|
+
from agentinputlab.contracts.enums import SemanticFamily
|
|
23
|
+
from agentinputlab.contracts.errors import ArtifactError, ValidationError
|
|
24
|
+
from agentinputlab.contracts.serialization import content_hash, freeze_mapping
|
|
25
|
+
|
|
26
|
+
_SHA256 = re.compile(r"^[0-9a-f]{64}$")
|
|
27
|
+
_IDENTIFIER = re.compile(r"^[a-z0-9][a-z0-9_.:-]*$")
|
|
28
|
+
_GROUP_ID = re.compile(r"^group_[0-9a-f]{64}$")
|
|
29
|
+
_CORE_FAMILIES = (
|
|
30
|
+
SemanticFamily.REFORMULATE,
|
|
31
|
+
SemanticFamily.DECOMPOSE,
|
|
32
|
+
SemanticFamily.ACQUIRE,
|
|
33
|
+
SemanticFamily.CLARIFY,
|
|
34
|
+
SemanticFamily.CURATE,
|
|
35
|
+
)
|
|
36
|
+
_REPRESENTATIVE_ARTIFACT = "agentinputlab.selector_representative_manifest"
|
|
37
|
+
_CAMPAIGN_ARTIFACT = "agentinputlab.selector_campaign_manifest"
|
|
38
|
+
_RESULT_ARTIFACT = "agentinputlab.selector_campaign_results"
|
|
39
|
+
_LOSO_ARTIFACT = "agentinputlab.selector_loso_manifest"
|
|
40
|
+
_DISCOVERY_SUMMARY_ARTIFACT = "agentinputlab.selector_discovery_summary"
|
|
41
|
+
_RULE_ARTIFACT = "agentinputlab.selector_pareto_rule"
|
|
42
|
+
_DESIGN_ARTIFACT = "agentinputlab.selector_campaign_design"
|
|
43
|
+
_BINDINGS_ARTIFACT = "agentinputlab.selector_campaign_bindings"
|
|
44
|
+
_ABLATION_BINDINGS_ARTIFACT = "agentinputlab.selector_ablation_bindings"
|
|
45
|
+
_ABLATION_MATRIX_ARTIFACT = "agentinputlab.selector_ablation_matrix"
|
|
46
|
+
_LOSO_DESIGN_ARTIFACT = "agentinputlab.selector_loso_design"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def freeze_pareto_representatives(
|
|
50
|
+
summary: Mapping[str, Any],
|
|
51
|
+
rule: Mapping[str, Any],
|
|
52
|
+
*,
|
|
53
|
+
source_file_sha256: str | None = None,
|
|
54
|
+
) -> Mapping[str, Any]:
|
|
55
|
+
"""Select two deterministic representatives per family from verified discovery.
|
|
56
|
+
|
|
57
|
+
Candidates are first filtered by the frozen support/safety rule, then
|
|
58
|
+
ordered by successive Pareto fronts over benefit (higher), hard harm
|
|
59
|
+
(lower), and normalized cost (lower). The preregistered utility score and
|
|
60
|
+
a stable release-ID tie break order candidates within a front.
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
parsed_summary = _validated_discovery_summary(summary)
|
|
64
|
+
parsed_rule = _validated_pareto_rule(rule)
|
|
65
|
+
if source_file_sha256 is not None:
|
|
66
|
+
_require_sha256(source_file_sha256, label="discovery summary file SHA-256")
|
|
67
|
+
candidates = parsed_summary["candidates"]
|
|
68
|
+
by_family: dict[SemanticFamily, list[dict[str, Any]]] = defaultdict(list)
|
|
69
|
+
for candidate in candidates:
|
|
70
|
+
by_family[candidate["family"]].append(candidate)
|
|
71
|
+
|
|
72
|
+
selected_rows: list[dict[str, Any]] = []
|
|
73
|
+
rejected_rows: list[dict[str, Any]] = []
|
|
74
|
+
count = parsed_rule["representatives_per_family"]
|
|
75
|
+
for family in _CORE_FAMILIES:
|
|
76
|
+
family_rows = by_family.get(family, [])
|
|
77
|
+
if not family_rows:
|
|
78
|
+
raise ValidationError(f"discovery summary has no candidates for {family.value}")
|
|
79
|
+
eligible: list[dict[str, Any]] = []
|
|
80
|
+
for candidate in family_rows:
|
|
81
|
+
reasons: list[str] = []
|
|
82
|
+
if candidate["independent_groups"] < parsed_rule["minimum_independent_groups"]:
|
|
83
|
+
reasons.append("insufficient_independent_groups")
|
|
84
|
+
if candidate["support_fraction"] < parsed_rule["minimum_support_fraction"]:
|
|
85
|
+
reasons.append("insufficient_support")
|
|
86
|
+
if candidate["hard_harm_rate"] > parsed_rule["maximum_hard_harm_rate"]:
|
|
87
|
+
reasons.append("hard_harm_gate")
|
|
88
|
+
if candidate["mean_valid_success_gain"] < parsed_rule["minimum_valid_success_gain"]:
|
|
89
|
+
reasons.append("minimum_gain_gate")
|
|
90
|
+
if reasons:
|
|
91
|
+
rejected_rows.append(
|
|
92
|
+
{
|
|
93
|
+
"family": family.value,
|
|
94
|
+
"release_id": candidate["release_id"],
|
|
95
|
+
"reason_codes": sorted(reasons),
|
|
96
|
+
}
|
|
97
|
+
)
|
|
98
|
+
else:
|
|
99
|
+
eligible.append(candidate)
|
|
100
|
+
if len(eligible) < count:
|
|
101
|
+
raise ValidationError(
|
|
102
|
+
f"Pareto freeze requires at least {count} eligible candidates for "
|
|
103
|
+
f"{family.value}; found {len(eligible)}"
|
|
104
|
+
)
|
|
105
|
+
ranked = _pareto_ranked(eligible, parsed_rule)
|
|
106
|
+
for rank, row in enumerate(ranked[:count], start=1):
|
|
107
|
+
selected_rows.append(
|
|
108
|
+
{
|
|
109
|
+
"family": family.value,
|
|
110
|
+
"rank": rank,
|
|
111
|
+
"release_id": row["release_id"],
|
|
112
|
+
"pareto_layer": row["pareto_layer"],
|
|
113
|
+
"utility_score": row["utility_score"],
|
|
114
|
+
"mean_valid_success_gain": row["mean_valid_success_gain"],
|
|
115
|
+
"hard_harm_rate": row["hard_harm_rate"],
|
|
116
|
+
"normalized_cost": row["normalized_cost"],
|
|
117
|
+
"independent_groups": row["independent_groups"],
|
|
118
|
+
"support_fraction": row["support_fraction"],
|
|
119
|
+
"source_run_identity_hash": row["source_run_identity_hash"],
|
|
120
|
+
}
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
semantic_summary_hash = content_hash(_summary_for_hash(parsed_summary))
|
|
124
|
+
base = {
|
|
125
|
+
"schema_version": 1,
|
|
126
|
+
"artifact": _REPRESENTATIVE_ARTIFACT,
|
|
127
|
+
"stage": "frozen",
|
|
128
|
+
"selection_scope": "two_per_core_family",
|
|
129
|
+
"source_summary": {
|
|
130
|
+
"revision": parsed_summary["revision"],
|
|
131
|
+
"semantic_sha256": semantic_summary_hash,
|
|
132
|
+
"file_sha256": source_file_sha256,
|
|
133
|
+
"profile_kind": "controlled_adapter",
|
|
134
|
+
"source_run_identity_hashes": sorted(
|
|
135
|
+
item["run_identity_hash"] for item in parsed_summary["source_runs"]
|
|
136
|
+
),
|
|
137
|
+
},
|
|
138
|
+
"rule": {
|
|
139
|
+
**{key: value for key, value in parsed_rule.items() if key != "rule_hash"},
|
|
140
|
+
"rule_hash": parsed_rule["rule_hash"],
|
|
141
|
+
},
|
|
142
|
+
"selections": selected_rows,
|
|
143
|
+
"rejections": sorted(
|
|
144
|
+
rejected_rows,
|
|
145
|
+
key=lambda item: (item["family"], item["release_id"]),
|
|
146
|
+
),
|
|
147
|
+
"experiments_executed": False,
|
|
148
|
+
}
|
|
149
|
+
return freeze_mapping({**base, "manifest_hash": content_hash(base)})
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def validate_representative_manifest(value: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
153
|
+
"""Validate and freeze one representative-selection artifact."""
|
|
154
|
+
|
|
155
|
+
data = _strict_mapping(
|
|
156
|
+
value,
|
|
157
|
+
label="representative manifest",
|
|
158
|
+
keys={
|
|
159
|
+
"schema_version",
|
|
160
|
+
"artifact",
|
|
161
|
+
"stage",
|
|
162
|
+
"selection_scope",
|
|
163
|
+
"source_summary",
|
|
164
|
+
"rule",
|
|
165
|
+
"selections",
|
|
166
|
+
"rejections",
|
|
167
|
+
"experiments_executed",
|
|
168
|
+
"manifest_hash",
|
|
169
|
+
},
|
|
170
|
+
)
|
|
171
|
+
if (
|
|
172
|
+
data["schema_version"] != 1
|
|
173
|
+
or data["artifact"] != _REPRESENTATIVE_ARTIFACT
|
|
174
|
+
or data["stage"] != "frozen"
|
|
175
|
+
or data["selection_scope"] != "two_per_core_family"
|
|
176
|
+
or data["experiments_executed"] is not False
|
|
177
|
+
):
|
|
178
|
+
raise ValidationError("representative manifest identity or stage is invalid")
|
|
179
|
+
expected_hash = data["manifest_hash"]
|
|
180
|
+
_require_sha256(expected_hash, label="representative manifest hash")
|
|
181
|
+
if content_hash({key: item for key, item in data.items() if key != "manifest_hash"}) != (
|
|
182
|
+
expected_hash
|
|
183
|
+
):
|
|
184
|
+
raise ValidationError("representative manifest hash differs from its content")
|
|
185
|
+
source = _strict_mapping(
|
|
186
|
+
data["source_summary"],
|
|
187
|
+
label="representative source summary",
|
|
188
|
+
keys={
|
|
189
|
+
"revision",
|
|
190
|
+
"semantic_sha256",
|
|
191
|
+
"file_sha256",
|
|
192
|
+
"profile_kind",
|
|
193
|
+
"source_run_identity_hashes",
|
|
194
|
+
},
|
|
195
|
+
)
|
|
196
|
+
_require_text(source["revision"], label="representative source revision")
|
|
197
|
+
_require_sha256(source["semantic_sha256"], label="representative source semantic hash")
|
|
198
|
+
if source["file_sha256"] is not None:
|
|
199
|
+
_require_sha256(source["file_sha256"], label="representative source file hash")
|
|
200
|
+
if source["profile_kind"] != "controlled_adapter":
|
|
201
|
+
raise ValidationError("selector representatives require controlled discovery outcomes")
|
|
202
|
+
identities = _string_sequence(
|
|
203
|
+
source["source_run_identity_hashes"],
|
|
204
|
+
label="representative source run identities",
|
|
205
|
+
)
|
|
206
|
+
if not identities or identities != tuple(sorted(set(identities))):
|
|
207
|
+
raise ValidationError("representative source run identities must be sorted unique")
|
|
208
|
+
for identity in identities:
|
|
209
|
+
_require_sha256(identity, label="representative source run identity")
|
|
210
|
+
rule = _strict_mapping(
|
|
211
|
+
data["rule"],
|
|
212
|
+
label="representative rule",
|
|
213
|
+
keys={
|
|
214
|
+
"schema_version",
|
|
215
|
+
"artifact",
|
|
216
|
+
"stage",
|
|
217
|
+
"representatives_per_family",
|
|
218
|
+
"minimum_independent_groups",
|
|
219
|
+
"minimum_support_fraction",
|
|
220
|
+
"maximum_hard_harm_rate",
|
|
221
|
+
"minimum_valid_success_gain",
|
|
222
|
+
"benefit_weight",
|
|
223
|
+
"harm_penalty",
|
|
224
|
+
"cost_penalty",
|
|
225
|
+
"tie_break",
|
|
226
|
+
"rule_hash",
|
|
227
|
+
},
|
|
228
|
+
)
|
|
229
|
+
_validated_pareto_rule({key: item for key, item in rule.items() if key != "rule_hash"})
|
|
230
|
+
_require_sha256(rule["rule_hash"], label="representative rule hash")
|
|
231
|
+
if (
|
|
232
|
+
content_hash({key: item for key, item in rule.items() if key != "rule_hash"})
|
|
233
|
+
!= rule["rule_hash"]
|
|
234
|
+
):
|
|
235
|
+
raise ValidationError("representative rule hash differs from its content")
|
|
236
|
+
selections = _sequence(data["selections"], label="representative selections")
|
|
237
|
+
expected_pairs = {(family.value, rank) for family in _CORE_FAMILIES for rank in (1, 2)}
|
|
238
|
+
observed_pairs: set[tuple[str, int]] = set()
|
|
239
|
+
releases: set[str] = set()
|
|
240
|
+
for index, raw in enumerate(selections):
|
|
241
|
+
row = _strict_mapping(
|
|
242
|
+
raw,
|
|
243
|
+
label=f"representative selection {index}",
|
|
244
|
+
keys={
|
|
245
|
+
"family",
|
|
246
|
+
"rank",
|
|
247
|
+
"release_id",
|
|
248
|
+
"pareto_layer",
|
|
249
|
+
"utility_score",
|
|
250
|
+
"mean_valid_success_gain",
|
|
251
|
+
"hard_harm_rate",
|
|
252
|
+
"normalized_cost",
|
|
253
|
+
"independent_groups",
|
|
254
|
+
"support_fraction",
|
|
255
|
+
"source_run_identity_hash",
|
|
256
|
+
},
|
|
257
|
+
)
|
|
258
|
+
family = _core_family(row["family"], label=f"selection {index} family")
|
|
259
|
+
rank = _positive_integer(row["rank"], label=f"selection {index} rank")
|
|
260
|
+
observed_pairs.add((family.value, rank))
|
|
261
|
+
release_id = _identifier(row["release_id"], label=f"selection {index} release")
|
|
262
|
+
if release_id in releases:
|
|
263
|
+
raise ValidationError("representative releases must be unique across families")
|
|
264
|
+
releases.add(release_id)
|
|
265
|
+
_nonnegative_integer(row["pareto_layer"], label=f"selection {index} Pareto layer")
|
|
266
|
+
_finite(row["utility_score"], label=f"selection {index} utility score")
|
|
267
|
+
_bounded(row["mean_valid_success_gain"], -1.0, 1.0, label="selection gain")
|
|
268
|
+
_bounded(row["hard_harm_rate"], 0.0, 1.0, label="selection hard harm")
|
|
269
|
+
_bounded(row["normalized_cost"], 0.0, 1.0, label="selection normalized cost")
|
|
270
|
+
_positive_integer(row["independent_groups"], label="selection independent groups")
|
|
271
|
+
_bounded(row["support_fraction"], 0.0, 1.0, label="selection support")
|
|
272
|
+
_require_sha256(
|
|
273
|
+
row["source_run_identity_hash"],
|
|
274
|
+
label="selection source run identity",
|
|
275
|
+
)
|
|
276
|
+
if row["source_run_identity_hash"] not in identities:
|
|
277
|
+
raise ValidationError(
|
|
278
|
+
"representative selection source is absent from the source summary"
|
|
279
|
+
)
|
|
280
|
+
if observed_pairs != expected_pairs or len(selections) != 10:
|
|
281
|
+
raise ValidationError("representative manifest requires exact ranks 1 and 2 per family")
|
|
282
|
+
_sequence(data["rejections"], label="representative rejections")
|
|
283
|
+
return freeze_mapping(data)
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def build_selector_baseline_campaign(
|
|
287
|
+
representatives: Mapping[str, Any],
|
|
288
|
+
bindings: Mapping[str, Any],
|
|
289
|
+
design: Mapping[str, Any],
|
|
290
|
+
) -> Mapping[str, Any]:
|
|
291
|
+
"""Build the frozen multi-policy baseline campaign."""
|
|
292
|
+
|
|
293
|
+
reps = validate_representative_manifest(representatives)
|
|
294
|
+
parsed_bindings = _validated_campaign_bindings(bindings)
|
|
295
|
+
parsed_design = _validated_campaign_design(design)
|
|
296
|
+
if parsed_bindings["representative_manifest_hash"] != reps["manifest_hash"]:
|
|
297
|
+
raise ValidationError("selector campaign bindings differ from the representative manifest")
|
|
298
|
+
selected = _selected_releases(reps)
|
|
299
|
+
best = parsed_bindings["best_fixed_global"]
|
|
300
|
+
if best["selected_release_id"] != selected[best["selected_family"]][0]:
|
|
301
|
+
raise ValidationError("best-fixed release is not the rank-1 selector representative")
|
|
302
|
+
|
|
303
|
+
policies: list[dict[str, Any]] = [
|
|
304
|
+
_policy(
|
|
305
|
+
"no_op",
|
|
306
|
+
kind="no_op",
|
|
307
|
+
role="fixed_baseline",
|
|
308
|
+
formal_inference=True,
|
|
309
|
+
diagnostic_only=False,
|
|
310
|
+
parameters={"release_id": "baseline.no_op"},
|
|
311
|
+
),
|
|
312
|
+
_policy(
|
|
313
|
+
"random_eligible",
|
|
314
|
+
kind="random_eligible",
|
|
315
|
+
role="frequency_control",
|
|
316
|
+
formal_inference=True,
|
|
317
|
+
diagnostic_only=False,
|
|
318
|
+
parameters={"random_seed": parsed_design["random_seed"]},
|
|
319
|
+
),
|
|
320
|
+
]
|
|
321
|
+
for family in _CORE_FAMILIES:
|
|
322
|
+
policies.append(
|
|
323
|
+
_policy(
|
|
324
|
+
f"fixed_{family.value}",
|
|
325
|
+
kind="fixed_family",
|
|
326
|
+
role="family_fixed_baseline",
|
|
327
|
+
formal_inference=True,
|
|
328
|
+
diagnostic_only=False,
|
|
329
|
+
parameters={
|
|
330
|
+
"family": family.value,
|
|
331
|
+
"release_id": selected[family][0],
|
|
332
|
+
"representative_rank": 1,
|
|
333
|
+
},
|
|
334
|
+
)
|
|
335
|
+
)
|
|
336
|
+
policies.extend(
|
|
337
|
+
(
|
|
338
|
+
_policy(
|
|
339
|
+
"best_fixed_global",
|
|
340
|
+
kind="best_fixed_global",
|
|
341
|
+
role="calibration_frozen_baseline",
|
|
342
|
+
formal_inference=True,
|
|
343
|
+
diagnostic_only=False,
|
|
344
|
+
parameters={
|
|
345
|
+
"selected_family": best["selected_family"].value,
|
|
346
|
+
"selected_release_id": best["selected_release_id"],
|
|
347
|
+
"policy_manifest_sha256": best["policy_manifest_sha256"],
|
|
348
|
+
},
|
|
349
|
+
),
|
|
350
|
+
_artifact_policy(
|
|
351
|
+
"defect_rule",
|
|
352
|
+
parsed_bindings["selectors"]["defect_rule"],
|
|
353
|
+
role="interpretable_baseline",
|
|
354
|
+
formal_inference=True,
|
|
355
|
+
),
|
|
356
|
+
_artifact_policy(
|
|
357
|
+
"zero_shot_router",
|
|
358
|
+
parsed_bindings["selectors"]["zero_shot_router"],
|
|
359
|
+
role="generic_router_comparator",
|
|
360
|
+
formal_inference=True,
|
|
361
|
+
),
|
|
362
|
+
_artifact_policy(
|
|
363
|
+
"penalized_t_learner",
|
|
364
|
+
parsed_bindings["selectors"]["penalized_t_learner"],
|
|
365
|
+
role="confirmatory_learned_policy",
|
|
366
|
+
formal_inference=True,
|
|
367
|
+
),
|
|
368
|
+
_artifact_policy(
|
|
369
|
+
"gbdt_t_learner",
|
|
370
|
+
parsed_bindings["selectors"]["gbdt_t_learner"],
|
|
371
|
+
role="exploratory_nonlinear_policy",
|
|
372
|
+
formal_inference=False,
|
|
373
|
+
),
|
|
374
|
+
_artifact_policy(
|
|
375
|
+
"eligibility_aware_selector",
|
|
376
|
+
parsed_bindings["selectors"]["eligibility_aware_selector"],
|
|
377
|
+
role="locked_primary_selector",
|
|
378
|
+
formal_inference=True,
|
|
379
|
+
),
|
|
380
|
+
_policy(
|
|
381
|
+
"observed_action_oracle",
|
|
382
|
+
kind="observed_action_oracle",
|
|
383
|
+
role="descriptive_upper_bound",
|
|
384
|
+
formal_inference=False,
|
|
385
|
+
diagnostic_only=True,
|
|
386
|
+
parameters={
|
|
387
|
+
"outcome_access": "post_outcome_only",
|
|
388
|
+
"may_select_or_train": False,
|
|
389
|
+
},
|
|
390
|
+
),
|
|
391
|
+
)
|
|
392
|
+
)
|
|
393
|
+
metadata = {
|
|
394
|
+
"suite_ids": list(parsed_design["suite_ids"]),
|
|
395
|
+
"required_independent_groups": parsed_design["required_independent_groups"],
|
|
396
|
+
"minimum_common_support_groups": parsed_design["minimum_common_support_groups"],
|
|
397
|
+
"random_seed": parsed_design["random_seed"],
|
|
398
|
+
"selector_representative_rank": parsed_bindings["representative_rank"],
|
|
399
|
+
"oracle_policy_id": "observed_action_oracle",
|
|
400
|
+
"oracle_diagnostic_only": True,
|
|
401
|
+
"fit_or_calibrate_allowed": False,
|
|
402
|
+
"preflight_first": True,
|
|
403
|
+
}
|
|
404
|
+
return _campaign(
|
|
405
|
+
campaign_id=parsed_design["campaign_id"],
|
|
406
|
+
campaign_kind="baseline",
|
|
407
|
+
primary_metric=parsed_design["primary_metric"],
|
|
408
|
+
evaluation_split=parsed_design["evaluation_split"],
|
|
409
|
+
representative_manifest_hash=reps["manifest_hash"],
|
|
410
|
+
policies=policies,
|
|
411
|
+
metadata=metadata,
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def build_selector_ablation_campaign(
|
|
416
|
+
baseline_campaign: Mapping[str, Any],
|
|
417
|
+
bindings: Mapping[str, Any],
|
|
418
|
+
matrix: Mapping[str, Any],
|
|
419
|
+
*,
|
|
420
|
+
campaign_id: str,
|
|
421
|
+
) -> Mapping[str, Any]:
|
|
422
|
+
"""Build refit-required feature and guardrail ablations."""
|
|
423
|
+
|
|
424
|
+
baseline = validate_selector_campaign_manifest(baseline_campaign)
|
|
425
|
+
if baseline["campaign_kind"] != "baseline":
|
|
426
|
+
raise ValidationError("selector ablations require a baseline campaign")
|
|
427
|
+
_identifier(campaign_id, label="selector ablation campaign ID")
|
|
428
|
+
parsed = _validated_ablation_bindings(bindings)
|
|
429
|
+
if parsed["baseline_campaign_hash"] != baseline["campaign_hash"]:
|
|
430
|
+
raise ValidationError("selector ablation bindings differ from the baseline campaign")
|
|
431
|
+
entries = _validated_ablation_matrix(matrix)
|
|
432
|
+
policies: list[dict[str, Any]] = []
|
|
433
|
+
no_op = next(item for item in baseline["policies"] if item["policy_id"] == "no_op")
|
|
434
|
+
policies.append(dict(no_op))
|
|
435
|
+
primary = next(
|
|
436
|
+
item for item in baseline["policies"] if item["policy_id"] == "eligibility_aware_selector"
|
|
437
|
+
)
|
|
438
|
+
policies.append(
|
|
439
|
+
{
|
|
440
|
+
**dict(primary),
|
|
441
|
+
"policy_id": "full_selector",
|
|
442
|
+
"role": "ablation_reference",
|
|
443
|
+
"formal_inference": False,
|
|
444
|
+
}
|
|
445
|
+
)
|
|
446
|
+
unsafe = {entry["policy_id"] for entry in entries if entry["diagnostic_only"]}
|
|
447
|
+
for entry in entries:
|
|
448
|
+
policy_id = entry["policy_id"]
|
|
449
|
+
artifact = parsed["artifacts"][policy_id]
|
|
450
|
+
policies.append(
|
|
451
|
+
_policy(
|
|
452
|
+
policy_id,
|
|
453
|
+
kind="frozen_ablation",
|
|
454
|
+
role="prespecified_ablation",
|
|
455
|
+
formal_inference=False,
|
|
456
|
+
diagnostic_only=entry["diagnostic_only"],
|
|
457
|
+
parameters={
|
|
458
|
+
"changed_component": entry["changed_component"],
|
|
459
|
+
"requires_independent_refit": entry["requires_independent_refit"],
|
|
460
|
+
"artifact_binding": artifact,
|
|
461
|
+
},
|
|
462
|
+
)
|
|
463
|
+
)
|
|
464
|
+
metadata = {
|
|
465
|
+
**dict(baseline["metadata"]),
|
|
466
|
+
"baseline_campaign_hash": baseline["campaign_hash"],
|
|
467
|
+
"unsafe_ablation_policy_ids": sorted(unsafe),
|
|
468
|
+
"ablation_results_are_secondary": True,
|
|
469
|
+
"fit_or_calibrate_allowed_during_evaluation": False,
|
|
470
|
+
}
|
|
471
|
+
return _campaign(
|
|
472
|
+
campaign_id=campaign_id,
|
|
473
|
+
campaign_kind="ablation",
|
|
474
|
+
primary_metric=baseline["primary_metric"],
|
|
475
|
+
evaluation_split=baseline["evaluation_split"],
|
|
476
|
+
representative_manifest_hash=baseline["representative_manifest_hash"],
|
|
477
|
+
policies=policies,
|
|
478
|
+
metadata=metadata,
|
|
479
|
+
)
|
|
480
|
+
|
|
481
|
+
|
|
482
|
+
def build_selector_loso_manifest(design: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
483
|
+
"""Generate leave-one-suite-out refit/freeze instructions."""
|
|
484
|
+
|
|
485
|
+
data = _strict_mapping(
|
|
486
|
+
design,
|
|
487
|
+
label="selector LOSO design",
|
|
488
|
+
keys={
|
|
489
|
+
"schema_version",
|
|
490
|
+
"artifact",
|
|
491
|
+
"stage",
|
|
492
|
+
"campaign_id",
|
|
493
|
+
"suite_ids",
|
|
494
|
+
"selector_kind",
|
|
495
|
+
"fit_config_sha256",
|
|
496
|
+
"calibration_config_sha256",
|
|
497
|
+
"representative_manifest_hash",
|
|
498
|
+
"revision_prefix",
|
|
499
|
+
"minimum_train_suites",
|
|
500
|
+
},
|
|
501
|
+
)
|
|
502
|
+
if (
|
|
503
|
+
data["schema_version"] != 1
|
|
504
|
+
or data["artifact"] != _LOSO_DESIGN_ARTIFACT
|
|
505
|
+
or data["stage"] != "frozen"
|
|
506
|
+
):
|
|
507
|
+
raise ValidationError("selector LOSO design identity or stage is invalid")
|
|
508
|
+
campaign_id = _identifier(data["campaign_id"], label="selector LOSO campaign ID")
|
|
509
|
+
suites = _identifier_sequence(data["suite_ids"], label="selector LOSO suites")
|
|
510
|
+
minimum = _positive_integer(
|
|
511
|
+
data["minimum_train_suites"],
|
|
512
|
+
label="selector LOSO minimum train suites",
|
|
513
|
+
)
|
|
514
|
+
if len(suites) < minimum + 1:
|
|
515
|
+
raise ValidationError("selector LOSO design has too few suites for its training floor")
|
|
516
|
+
selector_kind = _identifier(data["selector_kind"], label="selector LOSO kind")
|
|
517
|
+
for label in (
|
|
518
|
+
"fit_config_sha256",
|
|
519
|
+
"calibration_config_sha256",
|
|
520
|
+
"representative_manifest_hash",
|
|
521
|
+
):
|
|
522
|
+
_require_sha256(data[label], label=f"selector LOSO {label}")
|
|
523
|
+
prefix = _identifier(data["revision_prefix"], label="selector LOSO revision prefix")
|
|
524
|
+
folds = []
|
|
525
|
+
for held_out in suites:
|
|
526
|
+
training = tuple(item for item in suites if item != held_out)
|
|
527
|
+
folds.append(
|
|
528
|
+
{
|
|
529
|
+
"fold_id": f"holdout.{held_out}",
|
|
530
|
+
"held_out_suite": held_out,
|
|
531
|
+
"training_suites": list(training),
|
|
532
|
+
"calibration_source": "training_suites_group_disjoint",
|
|
533
|
+
"evaluation_split": "untouched_held_out_suite",
|
|
534
|
+
"selector_kind": selector_kind,
|
|
535
|
+
"fit_config_sha256": data["fit_config_sha256"],
|
|
536
|
+
"calibration_config_sha256": data["calibration_config_sha256"],
|
|
537
|
+
"output_revision": f"{prefix}.{held_out}",
|
|
538
|
+
"requires_fresh_fit": True,
|
|
539
|
+
"test_outcomes_visible_during_fit": False,
|
|
540
|
+
"test_outcomes_visible_during_calibration": False,
|
|
541
|
+
}
|
|
542
|
+
)
|
|
543
|
+
base = {
|
|
544
|
+
"schema_version": 1,
|
|
545
|
+
"artifact": _LOSO_ARTIFACT,
|
|
546
|
+
"stage": "frozen",
|
|
547
|
+
"campaign_id": campaign_id,
|
|
548
|
+
"representative_manifest_hash": data["representative_manifest_hash"],
|
|
549
|
+
"minimum_train_suites": minimum,
|
|
550
|
+
"folds": folds,
|
|
551
|
+
"preflight_first": True,
|
|
552
|
+
"experiments_executed": False,
|
|
553
|
+
}
|
|
554
|
+
return freeze_mapping({**base, "manifest_hash": content_hash(base)})
|
|
555
|
+
|
|
556
|
+
|
|
557
|
+
def validate_selector_loso_manifest(value: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
558
|
+
"""Validate a generated LOSO artifact and its disjoint folds."""
|
|
559
|
+
|
|
560
|
+
data = _strict_mapping(
|
|
561
|
+
value,
|
|
562
|
+
label="selector LOSO manifest",
|
|
563
|
+
keys={
|
|
564
|
+
"schema_version",
|
|
565
|
+
"artifact",
|
|
566
|
+
"stage",
|
|
567
|
+
"campaign_id",
|
|
568
|
+
"representative_manifest_hash",
|
|
569
|
+
"minimum_train_suites",
|
|
570
|
+
"folds",
|
|
571
|
+
"preflight_first",
|
|
572
|
+
"experiments_executed",
|
|
573
|
+
"manifest_hash",
|
|
574
|
+
},
|
|
575
|
+
)
|
|
576
|
+
if (
|
|
577
|
+
data["schema_version"] != 1
|
|
578
|
+
or data["artifact"] != _LOSO_ARTIFACT
|
|
579
|
+
or data["stage"] != "frozen"
|
|
580
|
+
or data["preflight_first"] is not True
|
|
581
|
+
or data["experiments_executed"] is not False
|
|
582
|
+
):
|
|
583
|
+
raise ValidationError("selector LOSO manifest identity or stage is invalid")
|
|
584
|
+
_identifier(data["campaign_id"], label="selector LOSO campaign ID")
|
|
585
|
+
_require_sha256(
|
|
586
|
+
data["representative_manifest_hash"],
|
|
587
|
+
label="selector LOSO representative hash",
|
|
588
|
+
)
|
|
589
|
+
minimum = _positive_integer(
|
|
590
|
+
data["minimum_train_suites"],
|
|
591
|
+
label="selector LOSO minimum train suites",
|
|
592
|
+
)
|
|
593
|
+
folds = _sequence(data["folds"], label="selector LOSO folds")
|
|
594
|
+
if len(folds) < minimum + 1:
|
|
595
|
+
raise ValidationError("selector LOSO manifest has too few folds")
|
|
596
|
+
held_out: set[str] = set()
|
|
597
|
+
all_suites: set[str] = set()
|
|
598
|
+
for index, raw in enumerate(folds):
|
|
599
|
+
fold = _strict_mapping(
|
|
600
|
+
raw,
|
|
601
|
+
label=f"selector LOSO fold {index}",
|
|
602
|
+
keys={
|
|
603
|
+
"fold_id",
|
|
604
|
+
"held_out_suite",
|
|
605
|
+
"training_suites",
|
|
606
|
+
"calibration_source",
|
|
607
|
+
"evaluation_split",
|
|
608
|
+
"selector_kind",
|
|
609
|
+
"fit_config_sha256",
|
|
610
|
+
"calibration_config_sha256",
|
|
611
|
+
"output_revision",
|
|
612
|
+
"requires_fresh_fit",
|
|
613
|
+
"test_outcomes_visible_during_fit",
|
|
614
|
+
"test_outcomes_visible_during_calibration",
|
|
615
|
+
},
|
|
616
|
+
)
|
|
617
|
+
_identifier(fold["fold_id"], label=f"selector LOSO fold {index} ID")
|
|
618
|
+
held = _identifier(fold["held_out_suite"], label=f"selector LOSO fold {index} holdout")
|
|
619
|
+
training = set(
|
|
620
|
+
_identifier_sequence(
|
|
621
|
+
fold["training_suites"],
|
|
622
|
+
label=f"selector LOSO fold {index} training suites",
|
|
623
|
+
)
|
|
624
|
+
)
|
|
625
|
+
if held in training or len(training) < minimum:
|
|
626
|
+
raise ValidationError("selector LOSO fold violates its suite separation")
|
|
627
|
+
if held in held_out:
|
|
628
|
+
raise ValidationError("selector LOSO holdout suites must be unique")
|
|
629
|
+
held_out.add(held)
|
|
630
|
+
all_suites.update(training)
|
|
631
|
+
all_suites.add(held)
|
|
632
|
+
if (
|
|
633
|
+
fold["calibration_source"] != "training_suites_group_disjoint"
|
|
634
|
+
or fold["evaluation_split"] != "untouched_held_out_suite"
|
|
635
|
+
or fold["requires_fresh_fit"] is not True
|
|
636
|
+
or fold["test_outcomes_visible_during_fit"] is not False
|
|
637
|
+
or fold["test_outcomes_visible_during_calibration"] is not False
|
|
638
|
+
):
|
|
639
|
+
raise ValidationError("selector LOSO fold permits held-out leakage")
|
|
640
|
+
_identifier(fold["selector_kind"], label="selector LOSO selector kind")
|
|
641
|
+
_identifier(fold["output_revision"], label="selector LOSO output revision")
|
|
642
|
+
_require_sha256(fold["fit_config_sha256"], label="selector LOSO fit config hash")
|
|
643
|
+
_require_sha256(
|
|
644
|
+
fold["calibration_config_sha256"],
|
|
645
|
+
label="selector LOSO calibration config hash",
|
|
646
|
+
)
|
|
647
|
+
if held_out != all_suites:
|
|
648
|
+
raise ValidationError("selector LOSO folds do not hold out every declared suite")
|
|
649
|
+
_require_sha256(data["manifest_hash"], label="selector LOSO manifest hash")
|
|
650
|
+
if (
|
|
651
|
+
content_hash({key: item for key, item in data.items() if key != "manifest_hash"})
|
|
652
|
+
!= data["manifest_hash"]
|
|
653
|
+
):
|
|
654
|
+
raise ValidationError("selector LOSO manifest hash differs from its content")
|
|
655
|
+
return freeze_mapping(data)
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
def validate_selector_campaign_manifest(value: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
659
|
+
"""Validate a frozen baseline or ablation campaign."""
|
|
660
|
+
|
|
661
|
+
data = _strict_mapping(
|
|
662
|
+
value,
|
|
663
|
+
label="selector campaign manifest",
|
|
664
|
+
keys={
|
|
665
|
+
"schema_version",
|
|
666
|
+
"artifact",
|
|
667
|
+
"stage",
|
|
668
|
+
"campaign_id",
|
|
669
|
+
"campaign_kind",
|
|
670
|
+
"primary_metric",
|
|
671
|
+
"evaluation_split",
|
|
672
|
+
"representative_manifest_hash",
|
|
673
|
+
"policies",
|
|
674
|
+
"metadata",
|
|
675
|
+
"experiments_executed",
|
|
676
|
+
"campaign_hash",
|
|
677
|
+
},
|
|
678
|
+
)
|
|
679
|
+
if (
|
|
680
|
+
data["schema_version"] != 1
|
|
681
|
+
or data["artifact"] != _CAMPAIGN_ARTIFACT
|
|
682
|
+
or data["stage"] != "frozen"
|
|
683
|
+
or data["campaign_kind"] not in {"baseline", "ablation"}
|
|
684
|
+
or data["experiments_executed"] is not False
|
|
685
|
+
):
|
|
686
|
+
raise ValidationError("selector campaign identity or stage is invalid")
|
|
687
|
+
_identifier(data["campaign_id"], label="selector campaign ID")
|
|
688
|
+
_identifier(data["primary_metric"], label="selector campaign primary metric")
|
|
689
|
+
_identifier(data["evaluation_split"], label="selector campaign evaluation split")
|
|
690
|
+
_require_sha256(
|
|
691
|
+
data["representative_manifest_hash"],
|
|
692
|
+
label="selector campaign representative hash",
|
|
693
|
+
)
|
|
694
|
+
policies = _sequence(data["policies"], label="selector campaign policies")
|
|
695
|
+
if len(policies) < 3:
|
|
696
|
+
raise ValidationError("selector campaign requires at least three policies")
|
|
697
|
+
policy_ids: set[str] = set()
|
|
698
|
+
oracle_count = 0
|
|
699
|
+
no_op_count = 0
|
|
700
|
+
for index, raw in enumerate(policies):
|
|
701
|
+
policy = _validated_policy(raw, label=f"selector campaign policy {index}")
|
|
702
|
+
if policy["policy_id"] in policy_ids:
|
|
703
|
+
raise ValidationError("selector campaign policy IDs must be unique")
|
|
704
|
+
policy_ids.add(policy["policy_id"])
|
|
705
|
+
no_op_count += policy["policy_id"] == "no_op"
|
|
706
|
+
if policy["kind"] == "observed_action_oracle":
|
|
707
|
+
oracle_count += 1
|
|
708
|
+
if (
|
|
709
|
+
policy["diagnostic_only"] is not True
|
|
710
|
+
or policy["formal_inference"] is not False
|
|
711
|
+
or policy["parameters"].get("outcome_access") != "post_outcome_only"
|
|
712
|
+
):
|
|
713
|
+
raise ValidationError("observed-action oracle must remain diagnostic-only")
|
|
714
|
+
if no_op_count != 1:
|
|
715
|
+
raise ValidationError("selector campaign requires exactly one NO_OP policy")
|
|
716
|
+
if data["campaign_kind"] == "baseline" and oracle_count != 1:
|
|
717
|
+
raise ValidationError("baseline campaign requires one diagnostic observed-action oracle")
|
|
718
|
+
if data["campaign_kind"] == "ablation" and oracle_count:
|
|
719
|
+
raise ValidationError("ablation campaign must not introduce an outcome oracle")
|
|
720
|
+
metadata = _mapping(data["metadata"], label="selector campaign metadata")
|
|
721
|
+
_positive_integer(
|
|
722
|
+
metadata.get("required_independent_groups"),
|
|
723
|
+
label="selector campaign required independent groups",
|
|
724
|
+
)
|
|
725
|
+
minimum = _positive_integer(
|
|
726
|
+
metadata.get("minimum_common_support_groups"),
|
|
727
|
+
label="selector campaign minimum common-support groups",
|
|
728
|
+
)
|
|
729
|
+
if minimum > metadata["required_independent_groups"]:
|
|
730
|
+
raise ValidationError("selector campaign common-support floor exceeds total groups")
|
|
731
|
+
suites = _identifier_sequence(metadata.get("suite_ids"), label="selector campaign suites")
|
|
732
|
+
if not suites:
|
|
733
|
+
raise ValidationError("selector campaign requires suite IDs")
|
|
734
|
+
if metadata.get("preflight_first") is not True:
|
|
735
|
+
raise ValidationError("selector campaign must remain preflight-first")
|
|
736
|
+
_require_sha256(data["campaign_hash"], label="selector campaign hash")
|
|
737
|
+
if (
|
|
738
|
+
content_hash({key: item for key, item in data.items() if key != "campaign_hash"})
|
|
739
|
+
!= data["campaign_hash"]
|
|
740
|
+
):
|
|
741
|
+
raise ValidationError("selector campaign hash differs from its content")
|
|
742
|
+
return freeze_mapping(data)
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
def validate_selector_campaign_design(value: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
746
|
+
"""Validate the outcome-blind design used before policy artifacts exist."""
|
|
747
|
+
|
|
748
|
+
return freeze_mapping(_validated_campaign_design(value))
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
def validate_selector_campaign_results(
|
|
752
|
+
campaign: Mapping[str, Any],
|
|
753
|
+
results: Mapping[str, Any],
|
|
754
|
+
) -> Mapping[str, Any]:
|
|
755
|
+
"""Validate complete, verified, non-synthetic multi-policy outcomes."""
|
|
756
|
+
|
|
757
|
+
manifest = validate_selector_campaign_manifest(campaign)
|
|
758
|
+
data = _strict_mapping(
|
|
759
|
+
results,
|
|
760
|
+
label="selector campaign results",
|
|
761
|
+
keys={
|
|
762
|
+
"schema_version",
|
|
763
|
+
"artifact",
|
|
764
|
+
"stage",
|
|
765
|
+
"data_status",
|
|
766
|
+
"is_synthetic",
|
|
767
|
+
"campaign_manifest_hash",
|
|
768
|
+
"source_runs",
|
|
769
|
+
"records",
|
|
770
|
+
},
|
|
771
|
+
)
|
|
772
|
+
if (
|
|
773
|
+
data["schema_version"] != 1
|
|
774
|
+
or data["artifact"] != _RESULT_ARTIFACT
|
|
775
|
+
or data["stage"] != "verified"
|
|
776
|
+
or data["data_status"] != "VERIFIED_REAL_RESULTS"
|
|
777
|
+
or data["is_synthetic"] is not False
|
|
778
|
+
):
|
|
779
|
+
raise ValidationError("selector results are not verified real outcomes")
|
|
780
|
+
if data["campaign_manifest_hash"] != manifest["campaign_hash"]:
|
|
781
|
+
raise ValidationError("selector result campaign hash differs from the manifest")
|
|
782
|
+
source_runs = _validated_source_runs(data["source_runs"])
|
|
783
|
+
if not source_runs:
|
|
784
|
+
raise ValidationError("selector campaign results require verified source runs")
|
|
785
|
+
policies = {
|
|
786
|
+
item["policy_id"]: item
|
|
787
|
+
for item in (
|
|
788
|
+
_validated_policy(raw, label="selector result policy") for raw in manifest["policies"]
|
|
789
|
+
)
|
|
790
|
+
}
|
|
791
|
+
records = _sequence(data["records"], label="selector campaign records")
|
|
792
|
+
by_group: dict[str, dict[str, dict[str, Any]]] = defaultdict(dict)
|
|
793
|
+
suites = set(manifest["metadata"]["suite_ids"])
|
|
794
|
+
common_groups: set[str] = set()
|
|
795
|
+
for index, raw in enumerate(records):
|
|
796
|
+
record = _validated_result_record(
|
|
797
|
+
raw,
|
|
798
|
+
label=f"selector result record {index}",
|
|
799
|
+
)
|
|
800
|
+
if record["suite_id"] not in suites:
|
|
801
|
+
raise ValidationError("selector result references an undeclared suite")
|
|
802
|
+
try:
|
|
803
|
+
policy = policies[record["policy_id"]]
|
|
804
|
+
except KeyError as exc:
|
|
805
|
+
raise ValidationError("selector result references an undeclared policy") from exc
|
|
806
|
+
if record["diagnostic_only"] is not policy["diagnostic_only"]:
|
|
807
|
+
raise ValidationError("selector result diagnostic role differs from its policy")
|
|
808
|
+
if record["policy_id"] in by_group[record["group_id"]]:
|
|
809
|
+
raise ValidationError("selector results contain duplicate group-policy rows")
|
|
810
|
+
if (
|
|
811
|
+
not record["selection_eligible"]
|
|
812
|
+
and record["intervened"]
|
|
813
|
+
and not policy["diagnostic_only"]
|
|
814
|
+
):
|
|
815
|
+
raise ValidationError("release policy selected a structurally ineligible action")
|
|
816
|
+
by_group[record["group_id"]][record["policy_id"]] = record
|
|
817
|
+
if record["common_support"]:
|
|
818
|
+
common_groups.add(record["group_id"])
|
|
819
|
+
|
|
820
|
+
required_groups = manifest["metadata"]["required_independent_groups"]
|
|
821
|
+
if len(by_group) != required_groups:
|
|
822
|
+
raise ValidationError(
|
|
823
|
+
f"selector result group count is {len(by_group)}, expected {required_groups}"
|
|
824
|
+
)
|
|
825
|
+
if len(common_groups) < manifest["metadata"]["minimum_common_support_groups"]:
|
|
826
|
+
raise ValidationError("selector results miss the frozen common-support floor")
|
|
827
|
+
expected_policies = set(policies)
|
|
828
|
+
fixed_policy_ids = {"no_op", *(f"fixed_{family.value}" for family in _CORE_FAMILIES)}
|
|
829
|
+
for group_id, group_rows in by_group.items():
|
|
830
|
+
if set(group_rows) != expected_policies:
|
|
831
|
+
raise ValidationError(f"selector group {group_id} lacks the complete policy set")
|
|
832
|
+
support_values = {row["common_support"] for row in group_rows.values()}
|
|
833
|
+
suite_values = {row["suite_id"] for row in group_rows.values()}
|
|
834
|
+
baseline_values = {row["no_op_value"] for row in group_rows.values()}
|
|
835
|
+
if len(support_values) != 1 or len(suite_values) != 1 or len(baseline_values) != 1:
|
|
836
|
+
raise ValidationError("selector group has inconsistent support, suite, or baseline")
|
|
837
|
+
no_op = group_rows["no_op"]
|
|
838
|
+
if (
|
|
839
|
+
no_op["selected_family"] != SemanticFamily.NO_OP.value
|
|
840
|
+
or no_op["selected_release_id"] != "baseline.no_op"
|
|
841
|
+
or no_op["intervened"]
|
|
842
|
+
or not no_op["selection_eligible"]
|
|
843
|
+
or no_op["value"] != no_op["no_op_value"]
|
|
844
|
+
or no_op["hard_harm"]
|
|
845
|
+
):
|
|
846
|
+
raise ValidationError("selector NO_OP result violates the identity policy")
|
|
847
|
+
if "observed_action_oracle" in group_rows:
|
|
848
|
+
if not fixed_policy_ids.issubset(group_rows):
|
|
849
|
+
raise ValidationError("oracle validation requires NO_OP and five fixed policies")
|
|
850
|
+
fixed_values = [group_rows[policy_id]["value"] for policy_id in fixed_policy_ids]
|
|
851
|
+
oracle = group_rows["observed_action_oracle"]
|
|
852
|
+
maximum = max(fixed_values)
|
|
853
|
+
if not math.isclose(oracle["value"], maximum, abs_tol=1e-12):
|
|
854
|
+
raise ValidationError("observed-action oracle differs from fixed-action headroom")
|
|
855
|
+
maximizing_actions = {
|
|
856
|
+
(
|
|
857
|
+
group_rows[policy_id]["selected_family"],
|
|
858
|
+
group_rows[policy_id]["selected_release_id"],
|
|
859
|
+
)
|
|
860
|
+
for policy_id in fixed_policy_ids
|
|
861
|
+
if math.isclose(group_rows[policy_id]["value"], maximum, abs_tol=1e-12)
|
|
862
|
+
}
|
|
863
|
+
if (
|
|
864
|
+
oracle["selected_family"],
|
|
865
|
+
oracle["selected_release_id"],
|
|
866
|
+
) not in maximizing_actions:
|
|
867
|
+
raise ValidationError(
|
|
868
|
+
"observed-action oracle action differs from the maximizing fixed action"
|
|
869
|
+
)
|
|
870
|
+
return freeze_mapping(
|
|
871
|
+
{
|
|
872
|
+
**data,
|
|
873
|
+
"source_runs": source_runs,
|
|
874
|
+
"records": tuple(
|
|
875
|
+
row
|
|
876
|
+
for group_id in sorted(by_group)
|
|
877
|
+
for _policy_id, row in sorted(by_group[group_id].items())
|
|
878
|
+
),
|
|
879
|
+
}
|
|
880
|
+
)
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
def analyze_selector_campaign_results(
|
|
884
|
+
campaign: Mapping[str, Any],
|
|
885
|
+
results: Mapping[str, Any],
|
|
886
|
+
*,
|
|
887
|
+
bootstrap_samples: int = 2_000,
|
|
888
|
+
random_seed: int = 2027,
|
|
889
|
+
) -> Mapping[str, Any]:
|
|
890
|
+
"""Summarize multi-policy value, harm, cost, eligibility, and coverage."""
|
|
891
|
+
|
|
892
|
+
if (
|
|
893
|
+
isinstance(bootstrap_samples, bool)
|
|
894
|
+
or not isinstance(bootstrap_samples, int)
|
|
895
|
+
or bootstrap_samples < 100
|
|
896
|
+
):
|
|
897
|
+
raise ValidationError("selector campaign bootstrap_samples must be an integer >= 100")
|
|
898
|
+
if isinstance(random_seed, bool) or not isinstance(random_seed, int) or random_seed < 0:
|
|
899
|
+
raise ValidationError("selector campaign random_seed must be non-negative")
|
|
900
|
+
manifest = validate_selector_campaign_manifest(campaign)
|
|
901
|
+
verified = validate_selector_campaign_results(manifest, results)
|
|
902
|
+
policy_specs = {item["policy_id"]: item for item in manifest["policies"]}
|
|
903
|
+
rows_by_policy: dict[str, list[Mapping[str, Any]]] = defaultdict(list)
|
|
904
|
+
for record in verified["records"]:
|
|
905
|
+
rows_by_policy[record["policy_id"]].append(record)
|
|
906
|
+
rng = random.Random(random_seed)
|
|
907
|
+
summaries: dict[str, Any] = {}
|
|
908
|
+
for policy_id in sorted(rows_by_policy):
|
|
909
|
+
rows = rows_by_policy[policy_id]
|
|
910
|
+
effects = [row["value"] - row["no_op_value"] for row in rows]
|
|
911
|
+
summaries[policy_id] = {
|
|
912
|
+
"independent_groups": len(rows),
|
|
913
|
+
"mean_value": fmean(row["value"] for row in rows),
|
|
914
|
+
"mean_no_op_value": fmean(row["no_op_value"] for row in rows),
|
|
915
|
+
"mean_gain_vs_no_op": fmean(effects),
|
|
916
|
+
"gain_interval": _bootstrap_mean_interval(
|
|
917
|
+
effects,
|
|
918
|
+
samples=bootstrap_samples,
|
|
919
|
+
rng=rng,
|
|
920
|
+
),
|
|
921
|
+
"intervention_coverage": fmean(1.0 if row["intervened"] else 0.0 for row in rows),
|
|
922
|
+
"hard_harm_rate": fmean(1.0 if row["hard_harm"] else 0.0 for row in rows),
|
|
923
|
+
"ineligible_selection_rate": fmean(
|
|
924
|
+
1.0 if row["intervened"] and not row["selection_eligible"] else 0.0 for row in rows
|
|
925
|
+
),
|
|
926
|
+
"mean_cost": fmean(row["cost"] for row in rows),
|
|
927
|
+
"diagnostic_only": policy_specs[policy_id]["diagnostic_only"],
|
|
928
|
+
"formal_inference": policy_specs[policy_id]["formal_inference"],
|
|
929
|
+
}
|
|
930
|
+
formal = sorted(
|
|
931
|
+
policy_id
|
|
932
|
+
for policy_id, policy in policy_specs.items()
|
|
933
|
+
if policy["formal_inference"] and not policy["diagnostic_only"]
|
|
934
|
+
)
|
|
935
|
+
diagnostic = sorted(
|
|
936
|
+
policy_id for policy_id, policy in policy_specs.items() if policy["diagnostic_only"]
|
|
937
|
+
)
|
|
938
|
+
return freeze_mapping(
|
|
939
|
+
{
|
|
940
|
+
"schema_version": 1,
|
|
941
|
+
"analysis": "selector_multi_policy_campaign",
|
|
942
|
+
"campaign_id": manifest["campaign_id"],
|
|
943
|
+
"campaign_hash": manifest["campaign_hash"],
|
|
944
|
+
"primary_metric": manifest["primary_metric"],
|
|
945
|
+
"evaluation_split": manifest["evaluation_split"],
|
|
946
|
+
"independent_groups": manifest["metadata"]["required_independent_groups"],
|
|
947
|
+
"common_support_groups": len(
|
|
948
|
+
{row["group_id"] for row in verified["records"] if row["common_support"]}
|
|
949
|
+
),
|
|
950
|
+
"policy_summaries": summaries,
|
|
951
|
+
"formal_inference_policy_ids": formal,
|
|
952
|
+
"diagnostic_policy_ids": diagnostic,
|
|
953
|
+
"observed_action_oracle_used_for_training": False,
|
|
954
|
+
"observed_action_oracle_used_for_inference": False,
|
|
955
|
+
"bootstrap_samples": bootstrap_samples,
|
|
956
|
+
"random_seed": random_seed,
|
|
957
|
+
"paper_claim_authorized": False,
|
|
958
|
+
}
|
|
959
|
+
)
|
|
960
|
+
|
|
961
|
+
|
|
962
|
+
def load_json_mapping(path: str | Path, *, label: str) -> tuple[Mapping[str, Any], str]:
|
|
963
|
+
"""Read one bounded JSON object and return its exact file digest."""
|
|
964
|
+
|
|
965
|
+
source = Path(path).expanduser().resolve()
|
|
966
|
+
try:
|
|
967
|
+
content = source.read_bytes()
|
|
968
|
+
except OSError as exc:
|
|
969
|
+
raise ArtifactError(f"cannot read {label}: {source}") from exc
|
|
970
|
+
if len(content) > 16 * 1024 * 1024:
|
|
971
|
+
raise ArtifactError(f"{label} exceeds the 16 MiB JSON limit")
|
|
972
|
+
try:
|
|
973
|
+
value = json.loads(content.decode("utf-8"))
|
|
974
|
+
except (UnicodeError, json.JSONDecodeError) as exc:
|
|
975
|
+
raise ArtifactError(f"{label} is not valid UTF-8 JSON") from exc
|
|
976
|
+
if not isinstance(value, Mapping):
|
|
977
|
+
raise ValidationError(f"{label} must be a JSON object")
|
|
978
|
+
return value, hashlib.sha256(content).hexdigest()
|
|
979
|
+
|
|
980
|
+
|
|
981
|
+
def _validated_discovery_summary(value: Mapping[str, Any]) -> dict[str, Any]:
|
|
982
|
+
data = _strict_mapping(
|
|
983
|
+
value,
|
|
984
|
+
label="selector discovery summary",
|
|
985
|
+
keys={
|
|
986
|
+
"schema_version",
|
|
987
|
+
"artifact",
|
|
988
|
+
"stage",
|
|
989
|
+
"revision",
|
|
990
|
+
"data_status",
|
|
991
|
+
"observed",
|
|
992
|
+
"is_synthetic",
|
|
993
|
+
"profile_kind",
|
|
994
|
+
"source_runs",
|
|
995
|
+
"candidates",
|
|
996
|
+
},
|
|
997
|
+
)
|
|
998
|
+
if (
|
|
999
|
+
data["schema_version"] != 1
|
|
1000
|
+
or data["artifact"] != _DISCOVERY_SUMMARY_ARTIFACT
|
|
1001
|
+
or data["stage"] != "verified"
|
|
1002
|
+
or data["data_status"] != "VERIFIED_REAL_RESULTS"
|
|
1003
|
+
or data["observed"] is not True
|
|
1004
|
+
or data["is_synthetic"] is not False
|
|
1005
|
+
or data["profile_kind"] != "controlled_adapter"
|
|
1006
|
+
):
|
|
1007
|
+
raise ValidationError("representative selection requires verified real controlled results")
|
|
1008
|
+
revision = _identifier(data["revision"], label="selector discovery summary revision")
|
|
1009
|
+
source_runs = _validated_source_runs(data["source_runs"])
|
|
1010
|
+
source_identities = {item["run_identity_hash"] for item in source_runs}
|
|
1011
|
+
candidates: list[dict[str, Any]] = []
|
|
1012
|
+
seen: set[tuple[SemanticFamily, str]] = set()
|
|
1013
|
+
for index, raw in enumerate(_sequence(data["candidates"], label="discovery candidates")):
|
|
1014
|
+
row = _strict_mapping(
|
|
1015
|
+
raw,
|
|
1016
|
+
label=f"discovery candidate {index}",
|
|
1017
|
+
keys={
|
|
1018
|
+
"family",
|
|
1019
|
+
"release_id",
|
|
1020
|
+
"mean_valid_success_gain",
|
|
1021
|
+
"hard_harm_rate",
|
|
1022
|
+
"normalized_cost",
|
|
1023
|
+
"independent_groups",
|
|
1024
|
+
"support_fraction",
|
|
1025
|
+
"source_run_identity_hash",
|
|
1026
|
+
},
|
|
1027
|
+
)
|
|
1028
|
+
family = _core_family(row["family"], label=f"discovery candidate {index} family")
|
|
1029
|
+
release = _identifier(
|
|
1030
|
+
row["release_id"],
|
|
1031
|
+
label=f"discovery candidate {index} release",
|
|
1032
|
+
)
|
|
1033
|
+
key = (family, release)
|
|
1034
|
+
if key in seen:
|
|
1035
|
+
raise ValidationError("selector discovery candidates must be unique by family/release")
|
|
1036
|
+
seen.add(key)
|
|
1037
|
+
source_identity = row["source_run_identity_hash"]
|
|
1038
|
+
_require_sha256(source_identity, label="candidate source run identity")
|
|
1039
|
+
if source_identity not in source_identities:
|
|
1040
|
+
raise ValidationError("candidate source identity is absent from verified source runs")
|
|
1041
|
+
candidates.append(
|
|
1042
|
+
{
|
|
1043
|
+
"family": family,
|
|
1044
|
+
"release_id": release,
|
|
1045
|
+
"mean_valid_success_gain": _bounded(
|
|
1046
|
+
row["mean_valid_success_gain"],
|
|
1047
|
+
-1.0,
|
|
1048
|
+
1.0,
|
|
1049
|
+
label="candidate mean valid-success gain",
|
|
1050
|
+
),
|
|
1051
|
+
"hard_harm_rate": _bounded(
|
|
1052
|
+
row["hard_harm_rate"],
|
|
1053
|
+
0.0,
|
|
1054
|
+
1.0,
|
|
1055
|
+
label="candidate hard-harm rate",
|
|
1056
|
+
),
|
|
1057
|
+
"normalized_cost": _bounded(
|
|
1058
|
+
row["normalized_cost"],
|
|
1059
|
+
0.0,
|
|
1060
|
+
1.0,
|
|
1061
|
+
label="candidate normalized cost",
|
|
1062
|
+
),
|
|
1063
|
+
"independent_groups": _positive_integer(
|
|
1064
|
+
row["independent_groups"],
|
|
1065
|
+
label="candidate independent groups",
|
|
1066
|
+
),
|
|
1067
|
+
"support_fraction": _bounded(
|
|
1068
|
+
row["support_fraction"],
|
|
1069
|
+
0.0,
|
|
1070
|
+
1.0,
|
|
1071
|
+
label="candidate support fraction",
|
|
1072
|
+
),
|
|
1073
|
+
"source_run_identity_hash": source_identity,
|
|
1074
|
+
}
|
|
1075
|
+
)
|
|
1076
|
+
if not candidates:
|
|
1077
|
+
raise ValidationError("selector discovery summary has no candidates")
|
|
1078
|
+
return {
|
|
1079
|
+
**data,
|
|
1080
|
+
"revision": revision,
|
|
1081
|
+
"source_runs": source_runs,
|
|
1082
|
+
"candidates": candidates,
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
|
|
1086
|
+
def _validated_pareto_rule(value: Mapping[str, Any]) -> dict[str, Any]:
|
|
1087
|
+
data = _strict_mapping(
|
|
1088
|
+
value,
|
|
1089
|
+
label="selector Pareto rule",
|
|
1090
|
+
keys={
|
|
1091
|
+
"schema_version",
|
|
1092
|
+
"artifact",
|
|
1093
|
+
"stage",
|
|
1094
|
+
"representatives_per_family",
|
|
1095
|
+
"minimum_independent_groups",
|
|
1096
|
+
"minimum_support_fraction",
|
|
1097
|
+
"maximum_hard_harm_rate",
|
|
1098
|
+
"minimum_valid_success_gain",
|
|
1099
|
+
"benefit_weight",
|
|
1100
|
+
"harm_penalty",
|
|
1101
|
+
"cost_penalty",
|
|
1102
|
+
"tie_break",
|
|
1103
|
+
},
|
|
1104
|
+
)
|
|
1105
|
+
if (
|
|
1106
|
+
data["schema_version"] != 1
|
|
1107
|
+
or data["artifact"] != _RULE_ARTIFACT
|
|
1108
|
+
or data["stage"] != "frozen"
|
|
1109
|
+
):
|
|
1110
|
+
raise ValidationError("selector Pareto rule must use frozen schema v1")
|
|
1111
|
+
count = _positive_integer(
|
|
1112
|
+
data["representatives_per_family"],
|
|
1113
|
+
label="representatives per family",
|
|
1114
|
+
)
|
|
1115
|
+
if count != 2:
|
|
1116
|
+
raise ValidationError("current selector protocol requires exactly two per family")
|
|
1117
|
+
parsed = {
|
|
1118
|
+
**data,
|
|
1119
|
+
"representatives_per_family": count,
|
|
1120
|
+
"minimum_independent_groups": _positive_integer(
|
|
1121
|
+
data["minimum_independent_groups"],
|
|
1122
|
+
label="Pareto minimum independent groups",
|
|
1123
|
+
),
|
|
1124
|
+
"minimum_support_fraction": _bounded(
|
|
1125
|
+
data["minimum_support_fraction"],
|
|
1126
|
+
0.0,
|
|
1127
|
+
1.0,
|
|
1128
|
+
label="Pareto minimum support",
|
|
1129
|
+
),
|
|
1130
|
+
"maximum_hard_harm_rate": _bounded(
|
|
1131
|
+
data["maximum_hard_harm_rate"],
|
|
1132
|
+
0.0,
|
|
1133
|
+
1.0,
|
|
1134
|
+
label="Pareto maximum hard harm",
|
|
1135
|
+
),
|
|
1136
|
+
"minimum_valid_success_gain": _bounded(
|
|
1137
|
+
data["minimum_valid_success_gain"],
|
|
1138
|
+
-1.0,
|
|
1139
|
+
1.0,
|
|
1140
|
+
label="Pareto minimum gain",
|
|
1141
|
+
),
|
|
1142
|
+
"benefit_weight": _positive_number(
|
|
1143
|
+
data["benefit_weight"],
|
|
1144
|
+
label="Pareto benefit weight",
|
|
1145
|
+
),
|
|
1146
|
+
"harm_penalty": _nonnegative_number(
|
|
1147
|
+
data["harm_penalty"],
|
|
1148
|
+
label="Pareto harm penalty",
|
|
1149
|
+
),
|
|
1150
|
+
"cost_penalty": _nonnegative_number(
|
|
1151
|
+
data["cost_penalty"],
|
|
1152
|
+
label="Pareto cost penalty",
|
|
1153
|
+
),
|
|
1154
|
+
}
|
|
1155
|
+
if data["tie_break"] != "pareto_layer,-utility,-benefit,harm,cost,-support,release_id":
|
|
1156
|
+
raise ValidationError("unsupported selector Pareto tie-break")
|
|
1157
|
+
parsed["rule_hash"] = content_hash(parsed)
|
|
1158
|
+
return parsed
|
|
1159
|
+
|
|
1160
|
+
|
|
1161
|
+
def _pareto_ranked(
|
|
1162
|
+
candidates: Sequence[Mapping[str, Any]],
|
|
1163
|
+
rule: Mapping[str, Any],
|
|
1164
|
+
) -> list[dict[str, Any]]:
|
|
1165
|
+
remaining = [dict(item) for item in candidates]
|
|
1166
|
+
ranked: list[dict[str, Any]] = []
|
|
1167
|
+
layer = 0
|
|
1168
|
+
while remaining:
|
|
1169
|
+
front = [
|
|
1170
|
+
candidate
|
|
1171
|
+
for candidate in remaining
|
|
1172
|
+
if not any(
|
|
1173
|
+
_dominates(other, candidate) for other in remaining if other is not candidate
|
|
1174
|
+
)
|
|
1175
|
+
]
|
|
1176
|
+
if not front: # pragma: no cover - finite partial order always has a front
|
|
1177
|
+
raise AssertionError("Pareto ordering produced no front")
|
|
1178
|
+
for candidate in front:
|
|
1179
|
+
candidate["pareto_layer"] = layer
|
|
1180
|
+
candidate["utility_score"] = (
|
|
1181
|
+
rule["benefit_weight"] * candidate["mean_valid_success_gain"]
|
|
1182
|
+
- rule["harm_penalty"] * candidate["hard_harm_rate"]
|
|
1183
|
+
- rule["cost_penalty"] * candidate["normalized_cost"]
|
|
1184
|
+
)
|
|
1185
|
+
front.sort(
|
|
1186
|
+
key=lambda item: (
|
|
1187
|
+
-item["utility_score"],
|
|
1188
|
+
-item["mean_valid_success_gain"],
|
|
1189
|
+
item["hard_harm_rate"],
|
|
1190
|
+
item["normalized_cost"],
|
|
1191
|
+
-item["support_fraction"],
|
|
1192
|
+
item["release_id"],
|
|
1193
|
+
)
|
|
1194
|
+
)
|
|
1195
|
+
ranked.extend(front)
|
|
1196
|
+
front_ids = {id(item) for item in front}
|
|
1197
|
+
remaining = [item for item in remaining if id(item) not in front_ids]
|
|
1198
|
+
layer += 1
|
|
1199
|
+
return ranked
|
|
1200
|
+
|
|
1201
|
+
|
|
1202
|
+
def _dominates(left: Mapping[str, Any], right: Mapping[str, Any]) -> bool:
|
|
1203
|
+
no_worse = (
|
|
1204
|
+
left["mean_valid_success_gain"] >= right["mean_valid_success_gain"]
|
|
1205
|
+
and left["hard_harm_rate"] <= right["hard_harm_rate"]
|
|
1206
|
+
and left["normalized_cost"] <= right["normalized_cost"]
|
|
1207
|
+
)
|
|
1208
|
+
strict = (
|
|
1209
|
+
left["mean_valid_success_gain"] > right["mean_valid_success_gain"]
|
|
1210
|
+
or left["hard_harm_rate"] < right["hard_harm_rate"]
|
|
1211
|
+
or left["normalized_cost"] < right["normalized_cost"]
|
|
1212
|
+
)
|
|
1213
|
+
return no_worse and strict
|
|
1214
|
+
|
|
1215
|
+
|
|
1216
|
+
def _summary_for_hash(summary: Mapping[str, Any]) -> Mapping[str, Any]:
|
|
1217
|
+
return {
|
|
1218
|
+
**{key: item for key, item in summary.items() if key != "candidates"},
|
|
1219
|
+
"candidates": [
|
|
1220
|
+
{
|
|
1221
|
+
**candidate,
|
|
1222
|
+
"family": candidate["family"].value,
|
|
1223
|
+
}
|
|
1224
|
+
for candidate in summary["candidates"]
|
|
1225
|
+
],
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
|
|
1229
|
+
def _validated_campaign_design(value: Mapping[str, Any]) -> dict[str, Any]:
|
|
1230
|
+
data = _strict_mapping(
|
|
1231
|
+
value,
|
|
1232
|
+
label="selector campaign design",
|
|
1233
|
+
keys={
|
|
1234
|
+
"schema_version",
|
|
1235
|
+
"artifact",
|
|
1236
|
+
"stage",
|
|
1237
|
+
"campaign_id",
|
|
1238
|
+
"primary_metric",
|
|
1239
|
+
"evaluation_split",
|
|
1240
|
+
"suite_ids",
|
|
1241
|
+
"required_independent_groups",
|
|
1242
|
+
"minimum_common_support_groups",
|
|
1243
|
+
"random_seed",
|
|
1244
|
+
},
|
|
1245
|
+
)
|
|
1246
|
+
if (
|
|
1247
|
+
data["schema_version"] != 1
|
|
1248
|
+
or data["artifact"] != _DESIGN_ARTIFACT
|
|
1249
|
+
or data["stage"] != "frozen"
|
|
1250
|
+
):
|
|
1251
|
+
raise ValidationError("selector campaign design must use frozen schema v1")
|
|
1252
|
+
parsed = {
|
|
1253
|
+
**data,
|
|
1254
|
+
"campaign_id": _identifier(data["campaign_id"], label="selector campaign ID"),
|
|
1255
|
+
"primary_metric": _identifier(
|
|
1256
|
+
data["primary_metric"],
|
|
1257
|
+
label="selector campaign primary metric",
|
|
1258
|
+
),
|
|
1259
|
+
"evaluation_split": _identifier(
|
|
1260
|
+
data["evaluation_split"],
|
|
1261
|
+
label="selector campaign evaluation split",
|
|
1262
|
+
),
|
|
1263
|
+
"suite_ids": _identifier_sequence(
|
|
1264
|
+
data["suite_ids"],
|
|
1265
|
+
label="selector campaign suites",
|
|
1266
|
+
),
|
|
1267
|
+
"required_independent_groups": _positive_integer(
|
|
1268
|
+
data["required_independent_groups"],
|
|
1269
|
+
label="selector campaign required independent groups",
|
|
1270
|
+
),
|
|
1271
|
+
"minimum_common_support_groups": _positive_integer(
|
|
1272
|
+
data["minimum_common_support_groups"],
|
|
1273
|
+
label="selector campaign minimum common-support groups",
|
|
1274
|
+
),
|
|
1275
|
+
"random_seed": _nonnegative_integer(
|
|
1276
|
+
data["random_seed"],
|
|
1277
|
+
label="selector campaign random seed",
|
|
1278
|
+
),
|
|
1279
|
+
}
|
|
1280
|
+
if (
|
|
1281
|
+
not parsed["suite_ids"]
|
|
1282
|
+
or parsed["minimum_common_support_groups"] > parsed["required_independent_groups"]
|
|
1283
|
+
):
|
|
1284
|
+
raise ValidationError("selector campaign support design is invalid")
|
|
1285
|
+
return parsed
|
|
1286
|
+
|
|
1287
|
+
|
|
1288
|
+
def _validated_campaign_bindings(value: Mapping[str, Any]) -> dict[str, Any]:
|
|
1289
|
+
data = _strict_mapping(
|
|
1290
|
+
value,
|
|
1291
|
+
label="selector campaign bindings",
|
|
1292
|
+
keys={
|
|
1293
|
+
"schema_version",
|
|
1294
|
+
"artifact",
|
|
1295
|
+
"stage",
|
|
1296
|
+
"representative_manifest_hash",
|
|
1297
|
+
"representative_rank",
|
|
1298
|
+
"best_fixed_global",
|
|
1299
|
+
"selectors",
|
|
1300
|
+
},
|
|
1301
|
+
)
|
|
1302
|
+
if (
|
|
1303
|
+
data["schema_version"] != 1
|
|
1304
|
+
or data["artifact"] != _BINDINGS_ARTIFACT
|
|
1305
|
+
or data["stage"] != "frozen"
|
|
1306
|
+
):
|
|
1307
|
+
raise ValidationError("selector campaign bindings must use frozen schema v1")
|
|
1308
|
+
representative_manifest_hash = _sha256_value(
|
|
1309
|
+
data["representative_manifest_hash"],
|
|
1310
|
+
label="selector campaign representative manifest",
|
|
1311
|
+
)
|
|
1312
|
+
representative_rank = _positive_integer(
|
|
1313
|
+
data["representative_rank"],
|
|
1314
|
+
label="selector campaign representative rank",
|
|
1315
|
+
)
|
|
1316
|
+
if representative_rank != 1:
|
|
1317
|
+
raise ValidationError("selector campaign currently requires rank-1 family policies")
|
|
1318
|
+
best = _strict_mapping(
|
|
1319
|
+
data["best_fixed_global"],
|
|
1320
|
+
label="selector best-fixed binding",
|
|
1321
|
+
keys={
|
|
1322
|
+
"selected_family",
|
|
1323
|
+
"selected_release_id",
|
|
1324
|
+
"policy_manifest_sha256",
|
|
1325
|
+
},
|
|
1326
|
+
)
|
|
1327
|
+
parsed_best = {
|
|
1328
|
+
"selected_family": _core_family(
|
|
1329
|
+
best["selected_family"],
|
|
1330
|
+
label="selector best-fixed family",
|
|
1331
|
+
),
|
|
1332
|
+
"selected_release_id": _identifier(
|
|
1333
|
+
best["selected_release_id"],
|
|
1334
|
+
label="selector best-fixed release",
|
|
1335
|
+
),
|
|
1336
|
+
"policy_manifest_sha256": _sha256_value(
|
|
1337
|
+
best["policy_manifest_sha256"],
|
|
1338
|
+
label="selector best-fixed policy manifest",
|
|
1339
|
+
),
|
|
1340
|
+
}
|
|
1341
|
+
raw_selectors = _strict_mapping(
|
|
1342
|
+
data["selectors"],
|
|
1343
|
+
label="selector artifact bindings",
|
|
1344
|
+
keys={
|
|
1345
|
+
"defect_rule",
|
|
1346
|
+
"zero_shot_router",
|
|
1347
|
+
"penalized_t_learner",
|
|
1348
|
+
"gbdt_t_learner",
|
|
1349
|
+
"eligibility_aware_selector",
|
|
1350
|
+
},
|
|
1351
|
+
)
|
|
1352
|
+
selectors = {
|
|
1353
|
+
policy_id: _validated_artifact_binding(
|
|
1354
|
+
raw,
|
|
1355
|
+
label=f"selector artifact binding {policy_id}",
|
|
1356
|
+
)
|
|
1357
|
+
for policy_id, raw in raw_selectors.items()
|
|
1358
|
+
}
|
|
1359
|
+
expected_kinds = {
|
|
1360
|
+
"defect_rule": {"rule"},
|
|
1361
|
+
"zero_shot_router": {"zero_shot_router"},
|
|
1362
|
+
"penalized_t_learner": {"ridge_t_learner", "logistic_t_learner"},
|
|
1363
|
+
"gbdt_t_learner": {"gbdt_t_learner"},
|
|
1364
|
+
"eligibility_aware_selector": {
|
|
1365
|
+
"ridge_utility",
|
|
1366
|
+
"ridge_t_learner",
|
|
1367
|
+
"logistic_t_learner",
|
|
1368
|
+
"gbdt_t_learner",
|
|
1369
|
+
"knn_utility",
|
|
1370
|
+
"cost_risk_guardrail",
|
|
1371
|
+
},
|
|
1372
|
+
}
|
|
1373
|
+
for policy_id, allowed in expected_kinds.items():
|
|
1374
|
+
if selectors[policy_id]["selector_kind"] not in allowed:
|
|
1375
|
+
raise ValidationError(f"{policy_id} binding has an incompatible selector kind")
|
|
1376
|
+
return {
|
|
1377
|
+
**data,
|
|
1378
|
+
"representative_manifest_hash": representative_manifest_hash,
|
|
1379
|
+
"representative_rank": representative_rank,
|
|
1380
|
+
"best_fixed_global": parsed_best,
|
|
1381
|
+
"selectors": selectors,
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
|
|
1385
|
+
def _validated_ablation_bindings(value: Mapping[str, Any]) -> dict[str, Any]:
|
|
1386
|
+
data = _strict_mapping(
|
|
1387
|
+
value,
|
|
1388
|
+
label="selector ablation bindings",
|
|
1389
|
+
keys={
|
|
1390
|
+
"schema_version",
|
|
1391
|
+
"artifact",
|
|
1392
|
+
"stage",
|
|
1393
|
+
"baseline_campaign_hash",
|
|
1394
|
+
"artifacts",
|
|
1395
|
+
},
|
|
1396
|
+
)
|
|
1397
|
+
if (
|
|
1398
|
+
data["schema_version"] != 1
|
|
1399
|
+
or data["artifact"] != _ABLATION_BINDINGS_ARTIFACT
|
|
1400
|
+
or data["stage"] != "frozen"
|
|
1401
|
+
):
|
|
1402
|
+
raise ValidationError("selector ablation bindings must use frozen schema v1")
|
|
1403
|
+
baseline_campaign_hash = _sha256_value(
|
|
1404
|
+
data["baseline_campaign_hash"],
|
|
1405
|
+
label="selector ablation baseline campaign",
|
|
1406
|
+
)
|
|
1407
|
+
artifacts = _strict_mapping(
|
|
1408
|
+
data["artifacts"],
|
|
1409
|
+
label="selector ablation artifacts",
|
|
1410
|
+
keys={
|
|
1411
|
+
"drop_ambiguity_features",
|
|
1412
|
+
"drop_multistep_features",
|
|
1413
|
+
"drop_retrieval_features",
|
|
1414
|
+
"drop_context_features",
|
|
1415
|
+
"drop_reformulation_features",
|
|
1416
|
+
"without_eligibility_mask",
|
|
1417
|
+
"without_cost_gate",
|
|
1418
|
+
"without_harm_calibration",
|
|
1419
|
+
},
|
|
1420
|
+
)
|
|
1421
|
+
return {
|
|
1422
|
+
**data,
|
|
1423
|
+
"baseline_campaign_hash": baseline_campaign_hash,
|
|
1424
|
+
"artifacts": {
|
|
1425
|
+
policy_id: _validated_artifact_binding(
|
|
1426
|
+
raw,
|
|
1427
|
+
label=f"selector ablation artifact {policy_id}",
|
|
1428
|
+
)
|
|
1429
|
+
for policy_id, raw in artifacts.items()
|
|
1430
|
+
},
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
|
|
1434
|
+
def _validated_ablation_matrix(value: Mapping[str, Any]) -> tuple[dict[str, Any], ...]:
|
|
1435
|
+
data = _strict_mapping(
|
|
1436
|
+
value,
|
|
1437
|
+
label="selector ablation matrix",
|
|
1438
|
+
keys={"schema_version", "artifact", "stage", "entries"},
|
|
1439
|
+
)
|
|
1440
|
+
if (
|
|
1441
|
+
data["schema_version"] != 1
|
|
1442
|
+
or data["artifact"] != _ABLATION_MATRIX_ARTIFACT
|
|
1443
|
+
or data["stage"] != "frozen"
|
|
1444
|
+
):
|
|
1445
|
+
raise ValidationError("selector ablation matrix must use frozen schema v1")
|
|
1446
|
+
expected = {
|
|
1447
|
+
"drop_ambiguity_features": ("feature_group.ambiguity", True, False),
|
|
1448
|
+
"drop_multistep_features": ("feature_group.multi_step", True, False),
|
|
1449
|
+
"drop_retrieval_features": ("feature_group.retrieval_need", True, False),
|
|
1450
|
+
"drop_context_features": ("feature_group.context_pressure", True, False),
|
|
1451
|
+
"drop_reformulation_features": (
|
|
1452
|
+
"feature_group.reformulation_need",
|
|
1453
|
+
True,
|
|
1454
|
+
False,
|
|
1455
|
+
),
|
|
1456
|
+
"without_eligibility_mask": ("eligibility_mask", False, True),
|
|
1457
|
+
"without_cost_gate": ("cost_gate", False, False),
|
|
1458
|
+
"without_harm_calibration": ("harm_calibration", False, True),
|
|
1459
|
+
}
|
|
1460
|
+
parsed: dict[str, dict[str, Any]] = {}
|
|
1461
|
+
for index, raw in enumerate(_sequence(data["entries"], label="selector ablation entries")):
|
|
1462
|
+
row = _strict_mapping(
|
|
1463
|
+
raw,
|
|
1464
|
+
label=f"selector ablation entry {index}",
|
|
1465
|
+
keys={
|
|
1466
|
+
"policy_id",
|
|
1467
|
+
"changed_component",
|
|
1468
|
+
"requires_independent_refit",
|
|
1469
|
+
"diagnostic_only",
|
|
1470
|
+
},
|
|
1471
|
+
)
|
|
1472
|
+
policy_id = _identifier(row["policy_id"], label="selector ablation policy ID")
|
|
1473
|
+
if policy_id in parsed:
|
|
1474
|
+
raise ValidationError("selector ablation policy IDs must be unique")
|
|
1475
|
+
parsed[policy_id] = {
|
|
1476
|
+
"policy_id": policy_id,
|
|
1477
|
+
"changed_component": _identifier(
|
|
1478
|
+
row["changed_component"],
|
|
1479
|
+
label="selector ablation changed component",
|
|
1480
|
+
),
|
|
1481
|
+
"requires_independent_refit": _boolean(
|
|
1482
|
+
row["requires_independent_refit"],
|
|
1483
|
+
label="selector ablation refit flag",
|
|
1484
|
+
),
|
|
1485
|
+
"diagnostic_only": _boolean(
|
|
1486
|
+
row["diagnostic_only"],
|
|
1487
|
+
label="selector ablation diagnostic flag",
|
|
1488
|
+
),
|
|
1489
|
+
}
|
|
1490
|
+
if set(parsed) != set(expected):
|
|
1491
|
+
raise ValidationError("selector ablation matrix differs from the frozen protocol")
|
|
1492
|
+
for policy_id, values in expected.items():
|
|
1493
|
+
row = parsed[policy_id]
|
|
1494
|
+
if (
|
|
1495
|
+
row["changed_component"],
|
|
1496
|
+
row["requires_independent_refit"],
|
|
1497
|
+
row["diagnostic_only"],
|
|
1498
|
+
) != values:
|
|
1499
|
+
raise ValidationError(f"selector ablation entry {policy_id} differs from protocol")
|
|
1500
|
+
return tuple(parsed[policy_id] for policy_id in expected)
|
|
1501
|
+
|
|
1502
|
+
|
|
1503
|
+
def _validated_artifact_binding(value: Any, *, label: str) -> dict[str, Any]:
|
|
1504
|
+
data = _strict_mapping(
|
|
1505
|
+
value,
|
|
1506
|
+
label=label,
|
|
1507
|
+
keys={"stage", "selector_kind", "selector_id", "revision", "sha256"},
|
|
1508
|
+
)
|
|
1509
|
+
if data["stage"] != "frozen":
|
|
1510
|
+
raise ValidationError(f"{label} must bind a frozen artifact")
|
|
1511
|
+
return {
|
|
1512
|
+
"stage": "frozen",
|
|
1513
|
+
"selector_kind": _identifier(data["selector_kind"], label=f"{label} kind"),
|
|
1514
|
+
"selector_id": _identifier(data["selector_id"], label=f"{label} ID"),
|
|
1515
|
+
"revision": _identifier(data["revision"], label=f"{label} revision"),
|
|
1516
|
+
"sha256": _sha256_value(data["sha256"], label=f"{label} SHA-256"),
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
|
|
1520
|
+
def _selected_releases(
|
|
1521
|
+
representatives: Mapping[str, Any],
|
|
1522
|
+
) -> dict[SemanticFamily, tuple[str, str]]:
|
|
1523
|
+
selected: dict[SemanticFamily, list[tuple[int, str]]] = defaultdict(list)
|
|
1524
|
+
for row in representatives["selections"]:
|
|
1525
|
+
selected[SemanticFamily(row["family"])].append((row["rank"], row["release_id"]))
|
|
1526
|
+
return {
|
|
1527
|
+
family: tuple(release for _rank, release in sorted(rows))
|
|
1528
|
+
for family, rows in selected.items()
|
|
1529
|
+
}
|
|
1530
|
+
|
|
1531
|
+
|
|
1532
|
+
def _campaign(
|
|
1533
|
+
*,
|
|
1534
|
+
campaign_id: str,
|
|
1535
|
+
campaign_kind: str,
|
|
1536
|
+
primary_metric: str,
|
|
1537
|
+
evaluation_split: str,
|
|
1538
|
+
representative_manifest_hash: str,
|
|
1539
|
+
policies: Sequence[Mapping[str, Any]],
|
|
1540
|
+
metadata: Mapping[str, Any],
|
|
1541
|
+
) -> Mapping[str, Any]:
|
|
1542
|
+
base = {
|
|
1543
|
+
"schema_version": 1,
|
|
1544
|
+
"artifact": _CAMPAIGN_ARTIFACT,
|
|
1545
|
+
"stage": "frozen",
|
|
1546
|
+
"campaign_id": campaign_id,
|
|
1547
|
+
"campaign_kind": campaign_kind,
|
|
1548
|
+
"primary_metric": primary_metric,
|
|
1549
|
+
"evaluation_split": evaluation_split,
|
|
1550
|
+
"representative_manifest_hash": representative_manifest_hash,
|
|
1551
|
+
"policies": list(policies),
|
|
1552
|
+
"metadata": dict(metadata),
|
|
1553
|
+
"experiments_executed": False,
|
|
1554
|
+
}
|
|
1555
|
+
result = freeze_mapping({**base, "campaign_hash": content_hash(base)})
|
|
1556
|
+
return validate_selector_campaign_manifest(result)
|
|
1557
|
+
|
|
1558
|
+
|
|
1559
|
+
def _policy(
|
|
1560
|
+
policy_id: str,
|
|
1561
|
+
*,
|
|
1562
|
+
kind: str,
|
|
1563
|
+
role: str,
|
|
1564
|
+
formal_inference: bool,
|
|
1565
|
+
diagnostic_only: bool,
|
|
1566
|
+
parameters: Mapping[str, Any],
|
|
1567
|
+
) -> dict[str, Any]:
|
|
1568
|
+
return {
|
|
1569
|
+
"policy_id": policy_id,
|
|
1570
|
+
"kind": kind,
|
|
1571
|
+
"role": role,
|
|
1572
|
+
"formal_inference": formal_inference,
|
|
1573
|
+
"diagnostic_only": diagnostic_only,
|
|
1574
|
+
"parameters": dict(parameters),
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
|
|
1578
|
+
def _artifact_policy(
|
|
1579
|
+
policy_id: str,
|
|
1580
|
+
binding: Mapping[str, Any],
|
|
1581
|
+
*,
|
|
1582
|
+
role: str,
|
|
1583
|
+
formal_inference: bool,
|
|
1584
|
+
) -> dict[str, Any]:
|
|
1585
|
+
return _policy(
|
|
1586
|
+
policy_id,
|
|
1587
|
+
kind="frozen_artifact_policy",
|
|
1588
|
+
role=role,
|
|
1589
|
+
formal_inference=formal_inference,
|
|
1590
|
+
diagnostic_only=False,
|
|
1591
|
+
parameters={"artifact_binding": dict(binding)},
|
|
1592
|
+
)
|
|
1593
|
+
|
|
1594
|
+
|
|
1595
|
+
def _validated_policy(value: Any, *, label: str) -> dict[str, Any]:
|
|
1596
|
+
data = _strict_mapping(
|
|
1597
|
+
value,
|
|
1598
|
+
label=label,
|
|
1599
|
+
keys={
|
|
1600
|
+
"policy_id",
|
|
1601
|
+
"kind",
|
|
1602
|
+
"role",
|
|
1603
|
+
"formal_inference",
|
|
1604
|
+
"diagnostic_only",
|
|
1605
|
+
"parameters",
|
|
1606
|
+
},
|
|
1607
|
+
)
|
|
1608
|
+
policy_id = _identifier(data["policy_id"], label=f"{label} ID")
|
|
1609
|
+
kind = _identifier(data["kind"], label=f"{label} kind")
|
|
1610
|
+
role = _identifier(data["role"], label=f"{label} role")
|
|
1611
|
+
formal = _boolean(data["formal_inference"], label=f"{label} formal inference")
|
|
1612
|
+
diagnostic = _boolean(data["diagnostic_only"], label=f"{label} diagnostic flag")
|
|
1613
|
+
if formal and diagnostic:
|
|
1614
|
+
raise ValidationError(f"{label} cannot be both formal and diagnostic-only")
|
|
1615
|
+
return {
|
|
1616
|
+
"policy_id": policy_id,
|
|
1617
|
+
"kind": kind,
|
|
1618
|
+
"role": role,
|
|
1619
|
+
"formal_inference": formal,
|
|
1620
|
+
"diagnostic_only": diagnostic,
|
|
1621
|
+
"parameters": freeze_mapping(_mapping(data["parameters"], label=f"{label} parameters")),
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
|
|
1625
|
+
def _validated_result_record(value: Any, *, label: str) -> dict[str, Any]:
|
|
1626
|
+
data = _strict_mapping(
|
|
1627
|
+
value,
|
|
1628
|
+
label=label,
|
|
1629
|
+
keys={
|
|
1630
|
+
"group_id",
|
|
1631
|
+
"suite_id",
|
|
1632
|
+
"policy_id",
|
|
1633
|
+
"selected_family",
|
|
1634
|
+
"selected_release_id",
|
|
1635
|
+
"value",
|
|
1636
|
+
"no_op_value",
|
|
1637
|
+
"hard_harm",
|
|
1638
|
+
"cost",
|
|
1639
|
+
"intervened",
|
|
1640
|
+
"selection_eligible",
|
|
1641
|
+
"common_support",
|
|
1642
|
+
"diagnostic_only",
|
|
1643
|
+
},
|
|
1644
|
+
)
|
|
1645
|
+
group_id = _require_text(data["group_id"], label=f"{label} group ID")
|
|
1646
|
+
if _GROUP_ID.fullmatch(group_id) is None:
|
|
1647
|
+
raise ValidationError(f"{label} group ID must be a privacy-safe hash")
|
|
1648
|
+
family = _family(data["selected_family"], label=f"{label} selected family")
|
|
1649
|
+
release = _require_text(data["selected_release_id"], label=f"{label} selected release")
|
|
1650
|
+
if family is SemanticFamily.NO_OP and release != "baseline.no_op":
|
|
1651
|
+
raise ValidationError(f"{label} NO_OP selection requires baseline.no_op")
|
|
1652
|
+
if family is not SemanticFamily.NO_OP and release == "baseline.no_op":
|
|
1653
|
+
raise ValidationError(f"{label} intervention selection cannot use baseline.no_op")
|
|
1654
|
+
intervened = _boolean(data["intervened"], label=f"{label} intervened")
|
|
1655
|
+
if intervened is (family is SemanticFamily.NO_OP):
|
|
1656
|
+
raise ValidationError(f"{label} intervention flag differs from its selected family")
|
|
1657
|
+
return {
|
|
1658
|
+
"group_id": group_id,
|
|
1659
|
+
"suite_id": _identifier(data["suite_id"], label=f"{label} suite"),
|
|
1660
|
+
"policy_id": _identifier(data["policy_id"], label=f"{label} policy"),
|
|
1661
|
+
"selected_family": family.value,
|
|
1662
|
+
"selected_release_id": release,
|
|
1663
|
+
"value": _bounded(data["value"], 0.0, 1.0, label=f"{label} value"),
|
|
1664
|
+
"no_op_value": _bounded(
|
|
1665
|
+
data["no_op_value"],
|
|
1666
|
+
0.0,
|
|
1667
|
+
1.0,
|
|
1668
|
+
label=f"{label} NO_OP value",
|
|
1669
|
+
),
|
|
1670
|
+
"hard_harm": _boolean(data["hard_harm"], label=f"{label} hard harm"),
|
|
1671
|
+
"cost": _nonnegative_number(data["cost"], label=f"{label} cost"),
|
|
1672
|
+
"intervened": intervened,
|
|
1673
|
+
"selection_eligible": _boolean(
|
|
1674
|
+
data["selection_eligible"],
|
|
1675
|
+
label=f"{label} selection eligibility",
|
|
1676
|
+
),
|
|
1677
|
+
"common_support": _boolean(
|
|
1678
|
+
data["common_support"],
|
|
1679
|
+
label=f"{label} common support",
|
|
1680
|
+
),
|
|
1681
|
+
"diagnostic_only": _boolean(
|
|
1682
|
+
data["diagnostic_only"],
|
|
1683
|
+
label=f"{label} diagnostic flag",
|
|
1684
|
+
),
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
|
|
1688
|
+
def _validated_source_runs(value: Any) -> tuple[dict[str, str], ...]:
|
|
1689
|
+
rows = _sequence(value, label="selector verified source runs")
|
|
1690
|
+
parsed: list[dict[str, str]] = []
|
|
1691
|
+
identities: set[str] = set()
|
|
1692
|
+
for index, raw in enumerate(rows):
|
|
1693
|
+
row = _strict_mapping(
|
|
1694
|
+
raw,
|
|
1695
|
+
label=f"selector source run {index}",
|
|
1696
|
+
keys={
|
|
1697
|
+
"study_id",
|
|
1698
|
+
"run_identity_hash",
|
|
1699
|
+
"manifest_hash",
|
|
1700
|
+
"plan_hash",
|
|
1701
|
+
"result_set_hash",
|
|
1702
|
+
},
|
|
1703
|
+
)
|
|
1704
|
+
parsed_row = {
|
|
1705
|
+
"study_id": _identifier(row["study_id"], label="selector source study ID"),
|
|
1706
|
+
"run_identity_hash": _sha256_value(
|
|
1707
|
+
row["run_identity_hash"],
|
|
1708
|
+
label="selector run identity",
|
|
1709
|
+
),
|
|
1710
|
+
"manifest_hash": _sha256_value(
|
|
1711
|
+
row["manifest_hash"],
|
|
1712
|
+
label="selector source manifest",
|
|
1713
|
+
),
|
|
1714
|
+
"plan_hash": _sha256_value(row["plan_hash"], label="selector source plan"),
|
|
1715
|
+
"result_set_hash": _sha256_value(
|
|
1716
|
+
row["result_set_hash"],
|
|
1717
|
+
label="selector result set",
|
|
1718
|
+
),
|
|
1719
|
+
}
|
|
1720
|
+
if parsed_row["run_identity_hash"] in identities:
|
|
1721
|
+
raise ValidationError("selector source run identities must be unique")
|
|
1722
|
+
identities.add(parsed_row["run_identity_hash"])
|
|
1723
|
+
parsed.append(parsed_row)
|
|
1724
|
+
return tuple(sorted(parsed, key=lambda item: item["run_identity_hash"]))
|
|
1725
|
+
|
|
1726
|
+
|
|
1727
|
+
def _bootstrap_mean_interval(
|
|
1728
|
+
values: Sequence[float],
|
|
1729
|
+
*,
|
|
1730
|
+
samples: int,
|
|
1731
|
+
rng: random.Random,
|
|
1732
|
+
) -> Mapping[str, float]:
|
|
1733
|
+
if not values:
|
|
1734
|
+
raise ValidationError("selector bootstrap requires values")
|
|
1735
|
+
estimates = sorted(
|
|
1736
|
+
fmean(values[rng.randrange(len(values))] for _ in values) for _ in range(samples)
|
|
1737
|
+
)
|
|
1738
|
+
return {
|
|
1739
|
+
"estimate": fmean(values),
|
|
1740
|
+
"low": _quantile(estimates, 0.025),
|
|
1741
|
+
"high": _quantile(estimates, 0.975),
|
|
1742
|
+
"method": "independent_group_bootstrap",
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
|
|
1746
|
+
def _quantile(values: Sequence[float], probability: float) -> float:
|
|
1747
|
+
index = (len(values) - 1) * probability
|
|
1748
|
+
lower = math.floor(index)
|
|
1749
|
+
upper = math.ceil(index)
|
|
1750
|
+
if lower == upper:
|
|
1751
|
+
return values[lower]
|
|
1752
|
+
weight = index - lower
|
|
1753
|
+
return values[lower] * (1.0 - weight) + values[upper] * weight
|
|
1754
|
+
|
|
1755
|
+
|
|
1756
|
+
def _strict_mapping(
|
|
1757
|
+
value: Any,
|
|
1758
|
+
*,
|
|
1759
|
+
label: str,
|
|
1760
|
+
keys: set[str],
|
|
1761
|
+
) -> dict[str, Any]:
|
|
1762
|
+
if not isinstance(value, Mapping) or any(not isinstance(key, str) for key in value):
|
|
1763
|
+
raise ValidationError(f"{label} must be an object")
|
|
1764
|
+
data = dict(value)
|
|
1765
|
+
if set(data) != keys:
|
|
1766
|
+
raise ValidationError(
|
|
1767
|
+
f"{label} fields differ: expected {sorted(keys)!r}, got {sorted(data)!r}"
|
|
1768
|
+
)
|
|
1769
|
+
return data
|
|
1770
|
+
|
|
1771
|
+
|
|
1772
|
+
def _mapping(value: Any, *, label: str) -> dict[str, Any]:
|
|
1773
|
+
if not isinstance(value, Mapping) or any(not isinstance(key, str) for key in value):
|
|
1774
|
+
raise ValidationError(f"{label} must be an object")
|
|
1775
|
+
return dict(value)
|
|
1776
|
+
|
|
1777
|
+
|
|
1778
|
+
def _sequence(value: Any, *, label: str) -> tuple[Any, ...]:
|
|
1779
|
+
if isinstance(value, (str, bytes)) or not isinstance(value, Sequence):
|
|
1780
|
+
raise ValidationError(f"{label} must be an array")
|
|
1781
|
+
return tuple(value)
|
|
1782
|
+
|
|
1783
|
+
|
|
1784
|
+
def _string_sequence(value: Any, *, label: str) -> tuple[str, ...]:
|
|
1785
|
+
rows = _sequence(value, label=label)
|
|
1786
|
+
if any(not isinstance(item, str) or not item.strip() for item in rows):
|
|
1787
|
+
raise ValidationError(f"{label} must contain non-empty strings")
|
|
1788
|
+
return tuple(rows)
|
|
1789
|
+
|
|
1790
|
+
|
|
1791
|
+
def _identifier_sequence(value: Any, *, label: str) -> tuple[str, ...]:
|
|
1792
|
+
rows = tuple(_identifier(item, label=f"{label} item") for item in _sequence(value, label=label))
|
|
1793
|
+
if len(rows) != len(set(rows)):
|
|
1794
|
+
raise ValidationError(f"{label} must be unique")
|
|
1795
|
+
return rows
|
|
1796
|
+
|
|
1797
|
+
|
|
1798
|
+
def _identifier(value: Any, *, label: str) -> str:
|
|
1799
|
+
text = _require_text(value, label=label)
|
|
1800
|
+
if _IDENTIFIER.fullmatch(text) is None:
|
|
1801
|
+
raise ValidationError(f"{label} must be a lowercase stable identifier")
|
|
1802
|
+
return text
|
|
1803
|
+
|
|
1804
|
+
|
|
1805
|
+
def _require_text(value: Any, *, label: str) -> str:
|
|
1806
|
+
if not isinstance(value, str) or not value.strip() or value != value.strip():
|
|
1807
|
+
raise ValidationError(f"{label} must be a trimmed non-empty string")
|
|
1808
|
+
return value
|
|
1809
|
+
|
|
1810
|
+
|
|
1811
|
+
def _sha256_value(value: Any, *, label: str) -> str:
|
|
1812
|
+
_require_sha256(value, label=label)
|
|
1813
|
+
return value
|
|
1814
|
+
|
|
1815
|
+
|
|
1816
|
+
def _require_sha256(value: Any, *, label: str) -> None:
|
|
1817
|
+
if not isinstance(value, str) or _SHA256.fullmatch(value) is None:
|
|
1818
|
+
raise ValidationError(f"{label} must be a lowercase SHA-256")
|
|
1819
|
+
|
|
1820
|
+
|
|
1821
|
+
def _core_family(value: Any, *, label: str) -> SemanticFamily:
|
|
1822
|
+
family = _family(value, label=label)
|
|
1823
|
+
if family not in _CORE_FAMILIES:
|
|
1824
|
+
raise ValidationError(f"{label} must be a core intervention family")
|
|
1825
|
+
return family
|
|
1826
|
+
|
|
1827
|
+
|
|
1828
|
+
def _family(value: Any, *, label: str) -> SemanticFamily:
|
|
1829
|
+
try:
|
|
1830
|
+
return SemanticFamily(value)
|
|
1831
|
+
except (TypeError, ValueError) as exc:
|
|
1832
|
+
raise ValidationError(f"{label} must be a semantic family") from exc
|
|
1833
|
+
|
|
1834
|
+
|
|
1835
|
+
def _boolean(value: Any, *, label: str) -> bool:
|
|
1836
|
+
if not isinstance(value, bool):
|
|
1837
|
+
raise ValidationError(f"{label} must be boolean")
|
|
1838
|
+
return value
|
|
1839
|
+
|
|
1840
|
+
|
|
1841
|
+
def _positive_integer(value: Any, *, label: str) -> int:
|
|
1842
|
+
result = _nonnegative_integer(value, label=label)
|
|
1843
|
+
if result < 1:
|
|
1844
|
+
raise ValidationError(f"{label} must be positive")
|
|
1845
|
+
return result
|
|
1846
|
+
|
|
1847
|
+
|
|
1848
|
+
def _nonnegative_integer(value: Any, *, label: str) -> int:
|
|
1849
|
+
if isinstance(value, bool) or not isinstance(value, int) or value < 0:
|
|
1850
|
+
raise ValidationError(f"{label} must be a non-negative integer")
|
|
1851
|
+
return value
|
|
1852
|
+
|
|
1853
|
+
|
|
1854
|
+
def _finite(value: Any, *, label: str) -> float:
|
|
1855
|
+
if isinstance(value, bool) or not isinstance(value, (int, float)) or not math.isfinite(value):
|
|
1856
|
+
raise ValidationError(f"{label} must be finite")
|
|
1857
|
+
return float(value)
|
|
1858
|
+
|
|
1859
|
+
|
|
1860
|
+
def _bounded(value: Any, lower: float, upper: float, *, label: str) -> float:
|
|
1861
|
+
result = _finite(value, label=label)
|
|
1862
|
+
if not lower <= result <= upper:
|
|
1863
|
+
raise ValidationError(f"{label} must be in [{lower:g}, {upper:g}]")
|
|
1864
|
+
return result
|
|
1865
|
+
|
|
1866
|
+
|
|
1867
|
+
def _positive_number(value: Any, *, label: str) -> float:
|
|
1868
|
+
result = _finite(value, label=label)
|
|
1869
|
+
if result <= 0:
|
|
1870
|
+
raise ValidationError(f"{label} must be positive")
|
|
1871
|
+
return result
|
|
1872
|
+
|
|
1873
|
+
|
|
1874
|
+
def _nonnegative_number(value: Any, *, label: str) -> float:
|
|
1875
|
+
result = _finite(value, label=label)
|
|
1876
|
+
if result < 0:
|
|
1877
|
+
raise ValidationError(f"{label} must be non-negative")
|
|
1878
|
+
return result
|
|
1879
|
+
|
|
1880
|
+
|
|
1881
|
+
__all__ = [
|
|
1882
|
+
"analyze_selector_campaign_results",
|
|
1883
|
+
"build_selector_ablation_campaign",
|
|
1884
|
+
"build_selector_baseline_campaign",
|
|
1885
|
+
"build_selector_loso_manifest",
|
|
1886
|
+
"freeze_pareto_representatives",
|
|
1887
|
+
"load_json_mapping",
|
|
1888
|
+
"validate_representative_manifest",
|
|
1889
|
+
"validate_selector_campaign_design",
|
|
1890
|
+
"validate_selector_campaign_manifest",
|
|
1891
|
+
"validate_selector_campaign_results",
|
|
1892
|
+
"validate_selector_loso_manifest",
|
|
1893
|
+
]
|