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.
Files changed (469) hide show
  1. agentinputlab/__init__.py +28 -0
  2. agentinputlab/algorithms/__init__.py +6 -0
  3. agentinputlab/algorithms/acquire/__init__.py +145 -0
  4. agentinputlab/algorithms/acquire/adaptive_rag/__init__.py +43 -0
  5. agentinputlab/algorithms/acquire/adaptive_rag/replay.py +367 -0
  6. agentinputlab/algorithms/acquire/adaptive_rag/runtime.py +1202 -0
  7. agentinputlab/algorithms/acquire/adaptive_rag_common_support.py +542 -0
  8. agentinputlab/algorithms/acquire/hyde.py +296 -0
  9. agentinputlab/algorithms/acquire/hyde_controlled.py +200 -0
  10. agentinputlab/algorithms/acquire/hyde_external.py +148 -0
  11. agentinputlab/algorithms/acquire/ircot.py +28 -0
  12. agentinputlab/algorithms/acquire/ircot_common_support.py +478 -0
  13. agentinputlab/algorithms/acquire/ircot_native.py +355 -0
  14. agentinputlab/algorithms/acquire/ircot_replay.py +327 -0
  15. agentinputlab/algorithms/acquire/qrag/__init__.py +79 -0
  16. agentinputlab/algorithms/acquire/qrag/bridge.py +828 -0
  17. agentinputlab/algorithms/acquire/qrag/common_support.py +891 -0
  18. agentinputlab/algorithms/acquire/qrag/native_axis.py +71 -0
  19. agentinputlab/algorithms/acquire/qrag/reader_adapter.py +139 -0
  20. agentinputlab/algorithms/acquire/r2ag/__init__.py +57 -0
  21. agentinputlab/algorithms/acquire/r2ag/bridge.py +1312 -0
  22. agentinputlab/algorithms/acquire/r2ag/common_support.py +1029 -0
  23. agentinputlab/algorithms/acquire/r2ag/socket_runtime.py +255 -0
  24. agentinputlab/algorithms/clarify/__init__.py +61 -0
  25. agentinputlab/algorithms/clarify/_structured.py +64 -0
  26. agentinputlab/algorithms/clarify/active_task_disambiguation.py +371 -0
  27. agentinputlab/algorithms/clarify/ask_or_assume/__init__.py +17 -0
  28. agentinputlab/algorithms/clarify/ask_or_assume/monitor.py +410 -0
  29. agentinputlab/algorithms/clarify/future_turns.py +379 -0
  30. agentinputlab/algorithms/clarify/udcs.py +255 -0
  31. agentinputlab/algorithms/clarify/udcs_deterministic.py +196 -0
  32. agentinputlab/algorithms/curate/__init__.py +65 -0
  33. agentinputlab/algorithms/curate/acon/__init__.py +27 -0
  34. agentinputlab/algorithms/curate/acon/common.py +284 -0
  35. agentinputlab/algorithms/curate/acon/common_support.py +136 -0
  36. agentinputlab/algorithms/curate/acon/history_bridge.py +309 -0
  37. agentinputlab/algorithms/curate/acon/observation_bridge.py +290 -0
  38. agentinputlab/algorithms/curate/llmlingua/__init__.py +30 -0
  39. agentinputlab/algorithms/curate/llmlingua/adapters.py +537 -0
  40. agentinputlab/algorithms/curate/llmlingua/budget.py +48 -0
  41. agentinputlab/algorithms/curate/llmlingua/controlled.py +175 -0
  42. agentinputlab/algorithms/curate/llmlingua/multilingual.py +105 -0
  43. agentinputlab/algorithms/curate/llmlingua/span_map.py +167 -0
  44. agentinputlab/algorithms/curate/recomp/__init__.py +47 -0
  45. agentinputlab/algorithms/curate/recomp/external.py +1129 -0
  46. agentinputlab/algorithms/curate/recomp/selective.py +304 -0
  47. agentinputlab/algorithms/decompose/__init__.py +107 -0
  48. agentinputlab/algorithms/decompose/decomp/__init__.py +53 -0
  49. agentinputlab/algorithms/decompose/decomp/common_support.py +478 -0
  50. agentinputlab/algorithms/decompose/decomp/planner_component.py +199 -0
  51. agentinputlab/algorithms/decompose/decomp/worker_bridge.py +416 -0
  52. agentinputlab/algorithms/decompose/llm_compiler/__init__.py +35 -0
  53. agentinputlab/algorithms/decompose/llm_compiler/bridge.py +520 -0
  54. agentinputlab/algorithms/decompose/llm_compiler/common_support.py +504 -0
  55. agentinputlab/algorithms/decompose/plan_and_budget/__init__.py +43 -0
  56. agentinputlab/algorithms/decompose/plan_and_budget/cached_soft_budget.py +362 -0
  57. agentinputlab/algorithms/decompose/plan_and_budget/decomposer_component.py +107 -0
  58. agentinputlab/algorithms/decompose/plan_and_budget/full.py +205 -0
  59. agentinputlab/algorithms/decompose/plan_and_budget/hard_cap.py +246 -0
  60. agentinputlab/algorithms/decompose/plan_and_budget/regenerated_soft_budget.py +448 -0
  61. agentinputlab/algorithms/decompose/plan_and_solve/__init__.py +33 -0
  62. agentinputlab/algorithms/decompose/plan_and_solve/plan_component.py +192 -0
  63. agentinputlab/algorithms/decompose/plan_and_solve/ps_prompt.py +127 -0
  64. agentinputlab/algorithms/decompose/self_ask/__init__.py +27 -0
  65. agentinputlab/algorithms/decompose/self_ask/loop.py +362 -0
  66. agentinputlab/algorithms/decompose/self_ask/planner_component.py +117 -0
  67. agentinputlab/algorithms/reformulate/__init__.py +85 -0
  68. agentinputlab/algorithms/reformulate/infocqr/__init__.py +40 -0
  69. agentinputlab/algorithms/reformulate/infocqr/cache_replay.py +362 -0
  70. agentinputlab/algorithms/reformulate/infocqr/external.py +675 -0
  71. agentinputlab/algorithms/reformulate/infocqr/student.py +189 -0
  72. agentinputlab/algorithms/reformulate/query2doc/__init__.py +42 -0
  73. agentinputlab/algorithms/reformulate/query2doc/controlled_live.py +190 -0
  74. agentinputlab/algorithms/reformulate/query2doc/models.py +95 -0
  75. agentinputlab/algorithms/reformulate/query2doc/official_cached.py +335 -0
  76. agentinputlab/algorithms/reformulate/query2doc/querygym_bridge.py +223 -0
  77. agentinputlab/algorithms/reformulate/query2doc/querygym_runtime.py +326 -0
  78. agentinputlab/algorithms/reformulate/reformer/__init__.py +23 -0
  79. agentinputlab/algorithms/reformulate/reformer/external.py +417 -0
  80. agentinputlab/algorithms/reformulate/rrr.py +696 -0
  81. agentinputlab/annotation/__init__.py +5 -0
  82. agentinputlab/annotation/independent.py +428 -0
  83. agentinputlab/annotation/server.py +233 -0
  84. agentinputlab/annotation/static/app.js +121 -0
  85. agentinputlab/annotation/static/index.html +60 -0
  86. agentinputlab/annotation/static/review.css +2 -0
  87. agentinputlab/annotation/static/review.html +10 -0
  88. agentinputlab/annotation/static/review.js +11 -0
  89. agentinputlab/annotation/static/styles.css +55 -0
  90. agentinputlab/annotation/store.py +444 -0
  91. agentinputlab/api.py +368 -0
  92. agentinputlab/artifacts/__init__.py +15 -0
  93. agentinputlab/artifacts/json_file.py +104 -0
  94. agentinputlab/artifacts/manifest.py +98 -0
  95. agentinputlab/artifacts/store.py +157 -0
  96. agentinputlab/backends/__init__.py +98 -0
  97. agentinputlab/backends/embedding/__init__.py +25 -0
  98. agentinputlab/backends/embedding/base.py +145 -0
  99. agentinputlab/backends/embedding/callable.py +75 -0
  100. agentinputlab/backends/embedding/replay.py +129 -0
  101. agentinputlab/backends/llm/__init__.py +31 -0
  102. agentinputlab/backends/llm/base.py +149 -0
  103. agentinputlab/backends/llm/callable.py +108 -0
  104. agentinputlab/backends/llm/decomp_completion.py +88 -0
  105. agentinputlab/backends/llm/final_content_stop.py +72 -0
  106. agentinputlab/backends/llm/gpt_oss_final_channel.py +84 -0
  107. agentinputlab/backends/llm/openai_compatible.py +332 -0
  108. agentinputlab/backends/llm/transformers.py +171 -0
  109. agentinputlab/backends/retrieval/__init__.py +35 -0
  110. agentinputlab/backends/retrieval/base.py +50 -0
  111. agentinputlab/backends/retrieval/dense.py +777 -0
  112. agentinputlab/backends/retrieval/memory.py +119 -0
  113. agentinputlab/backends/retrieval/sqlite_fts.py +155 -0
  114. agentinputlab/backends/user/__init__.py +15 -0
  115. agentinputlab/backends/user/base.py +66 -0
  116. agentinputlab/backends/user/callable.py +54 -0
  117. agentinputlab/backends/user/replay.py +89 -0
  118. agentinputlab/backends/vector.py +38 -0
  119. agentinputlab/benchmarks/__init__.py +246 -0
  120. agentinputlab/benchmarks/acquisition.py +106 -0
  121. agentinputlab/benchmarks/ale.py +540 -0
  122. agentinputlab/benchmarks/appworld_ul.py +669 -0
  123. agentinputlab/benchmarks/assets.py +226 -0
  124. agentinputlab/benchmarks/base.py +68 -0
  125. agentinputlab/benchmarks/beir_archive.py +235 -0
  126. agentinputlab/benchmarks/beir_sample.py +269 -0
  127. agentinputlab/benchmarks/bfcl_native.py +245 -0
  128. agentinputlab/benchmarks/bfcl_v3.py +607 -0
  129. agentinputlab/benchmarks/cache.py +218 -0
  130. agentinputlab/benchmarks/clariq.py +203 -0
  131. agentinputlab/benchmarks/data/registry.json +321 -0
  132. agentinputlab/benchmarks/data/smoke_assets.json +511 -0
  133. agentinputlab/benchmarks/data/statebench_v0_8_1_task_ids.json +475 -0
  134. agentinputlab/benchmarks/data/toolsandbox_165848b_scenario_names.json +1 -0
  135. agentinputlab/benchmarks/execution.py +1111 -0
  136. agentinputlab/benchmarks/interactive.py +257 -0
  137. agentinputlab/benchmarks/ir_query.py +204 -0
  138. agentinputlab/benchmarks/longbench.py +203 -0
  139. agentinputlab/benchmarks/paired_replay.py +479 -0
  140. agentinputlab/benchmarks/preprocess.py +2313 -0
  141. agentinputlab/benchmarks/production.py +236 -0
  142. agentinputlab/benchmarks/qa.py +963 -0
  143. agentinputlab/benchmarks/registry.py +110 -0
  144. agentinputlab/benchmarks/retrieval.py +459 -0
  145. agentinputlab/benchmarks/runtime.py +509 -0
  146. agentinputlab/benchmarks/statebench.py +938 -0
  147. agentinputlab/benchmarks/tau3.py +725 -0
  148. agentinputlab/benchmarks/toolsandbox.py +626 -0
  149. agentinputlab/benchmarks/trec_dl_sample.py +263 -0
  150. agentinputlab/campaign.py +654 -0
  151. agentinputlab/campaign_runner.py +953 -0
  152. agentinputlab/cli/__init__.py +6 -0
  153. agentinputlab/cli/main.py +933 -0
  154. agentinputlab/connectors/__init__.py +46 -0
  155. agentinputlab/connectors/knowledge/__init__.py +4 -0
  156. agentinputlab/connectors/tools/__init__.py +30 -0
  157. agentinputlab/connectors/tools/base.py +57 -0
  158. agentinputlab/connectors/tools/mcp.py +222 -0
  159. agentinputlab/connectors/tools/memory.py +41 -0
  160. agentinputlab/connectors/tools/openapi.py +695 -0
  161. agentinputlab/connectors/tools/schema.py +102 -0
  162. agentinputlab/contracts/__init__.py +91 -0
  163. agentinputlab/contracts/availability.py +24 -0
  164. agentinputlab/contracts/dependency.py +58 -0
  165. agentinputlab/contracts/enums.py +82 -0
  166. agentinputlab/contracts/errors.py +63 -0
  167. agentinputlab/contracts/evidence.py +43 -0
  168. agentinputlab/contracts/intent.py +110 -0
  169. agentinputlab/contracts/lifecycle.py +164 -0
  170. agentinputlab/contracts/patch.py +167 -0
  171. agentinputlab/contracts/serialization.py +93 -0
  172. agentinputlab/contracts/state.py +127 -0
  173. agentinputlab/contracts/trace.py +59 -0
  174. agentinputlab/contracts/worker.py +42 -0
  175. agentinputlab/core/__init__.py +7 -0
  176. agentinputlab/data/__init__.py +32 -0
  177. agentinputlab/data/checksums.py +9 -0
  178. agentinputlab/data/downloader.py +235 -0
  179. agentinputlab/data/http.py +171 -0
  180. agentinputlab/data/index.py +21 -0
  181. agentinputlab/data/overlap.py +28 -0
  182. agentinputlab/data/preprocess.py +32 -0
  183. agentinputlab/data/storage.py +57 -0
  184. agentinputlab/data/trec_sample.py +427 -0
  185. agentinputlab/evaluation/__init__.py +5 -0
  186. agentinputlab/evaluation/outcomes.py +32 -0
  187. agentinputlab/experiments/__init__.py +278 -0
  188. agentinputlab/experiments/analysis.py +981 -0
  189. agentinputlab/experiments/artifacts.py +687 -0
  190. agentinputlab/experiments/automatic_measurement.py +678 -0
  191. agentinputlab/experiments/auxiliary_matrix.py +203 -0
  192. agentinputlab/experiments/bindings.py +430 -0
  193. agentinputlab/experiments/blueprints.py +147 -0
  194. agentinputlab/experiments/builders/__init__.py +45 -0
  195. agentinputlab/experiments/builders/executable_external_payload.py +423 -0
  196. agentinputlab/experiments/builders/external_process_arena.py +1018 -0
  197. agentinputlab/experiments/builders/registry_intervention.py +463 -0
  198. agentinputlab/experiments/cli.py +158 -0
  199. agentinputlab/experiments/controls.py +340 -0
  200. agentinputlab/experiments/driver_guard.py +205 -0
  201. agentinputlab/experiments/drivers/__init__.py +89 -0
  202. agentinputlab/experiments/drivers/external_arena.py +2908 -0
  203. agentinputlab/experiments/drivers/method_process.py +662 -0
  204. agentinputlab/experiments/drivers/parity_process.py +1484 -0
  205. agentinputlab/experiments/drivers/static_production.py +1574 -0
  206. agentinputlab/experiments/executor.py +448 -0
  207. agentinputlab/experiments/loader.py +605 -0
  208. agentinputlab/experiments/measurement.py +675 -0
  209. agentinputlab/experiments/paper_analysis.py +1818 -0
  210. agentinputlab/experiments/parity_identity.py +605 -0
  211. agentinputlab/experiments/plan.py +277 -0
  212. agentinputlab/experiments/production_builders.py +3739 -0
  213. agentinputlab/experiments/readiness.py +432 -0
  214. agentinputlab/experiments/schema.py +514 -0
  215. agentinputlab/experiments/secrets.py +177 -0
  216. agentinputlab/experiments/stateful_analysis.py +1738 -0
  217. agentinputlab/experiments/transfer_analysis.py +1316 -0
  218. agentinputlab/experiments/unseen_analysis.py +1025 -0
  219. agentinputlab/integrations/__init__.py +1 -0
  220. agentinputlab/integrations/action_space/__init__.py +1 -0
  221. agentinputlab/integrations/external_workers/__init__.py +76 -0
  222. agentinputlab/integrations/external_workers/ace.py +431 -0
  223. agentinputlab/integrations/external_workers/base.py +181 -0
  224. agentinputlab/integrations/external_workers/decomp_live.py +249 -0
  225. agentinputlab/integrations/external_workers/decomp_planner.py +30 -0
  226. agentinputlab/integrations/external_workers/infocqr_student.py +280 -0
  227. agentinputlab/integrations/external_workers/ircot.py +576 -0
  228. agentinputlab/integrations/external_workers/llmcompiler_live.py +360 -0
  229. agentinputlab/integrations/external_workers/longllmlingua.py +162 -0
  230. agentinputlab/integrations/external_workers/method.py +314 -0
  231. agentinputlab/integrations/external_workers/process.py +678 -0
  232. agentinputlab/integrations/external_workers/supervisor.py +1071 -0
  233. agentinputlab/integrations/full_architecture/__init__.py +1 -0
  234. agentinputlab/integrations/full_architecture/hyde.py +212 -0
  235. agentinputlab/integrations/full_architecture/plan_and_budget.py +188 -0
  236. agentinputlab/integrations/live_history.py +222 -0
  237. agentinputlab/integrations/prompt_optimization/__init__.py +1 -0
  238. agentinputlab/integrations/training/__init__.py +1 -0
  239. agentinputlab/metrics/__init__.py +50 -0
  240. agentinputlab/metrics/catalog.py +313 -0
  241. agentinputlab/metrics/harm.py +95 -0
  242. agentinputlab/metrics/paired.py +40 -0
  243. agentinputlab/metrics/qa.py +76 -0
  244. agentinputlab/metrics/text.py +33 -0
  245. agentinputlab/metrics/third_party.py +161 -0
  246. agentinputlab/models/__init__.py +4 -0
  247. agentinputlab/observability/__init__.py +56 -0
  248. agentinputlab/observability/budget.py +316 -0
  249. agentinputlab/observability/instrumentation.py +754 -0
  250. agentinputlab/observability/models.py +403 -0
  251. agentinputlab/observability/monitor.py +380 -0
  252. agentinputlab/optimizers/__init__.py +1 -0
  253. agentinputlab/optimizers/clarify/__init__.py +12 -0
  254. agentinputlab/optimizers/context/__init__.py +22 -0
  255. agentinputlab/optimizers/decompose/__init__.py +64 -0
  256. agentinputlab/optimizers/evidence/__init__.py +22 -0
  257. agentinputlab/optimizers/rewrite/__init__.py +30 -0
  258. agentinputlab/parity/__init__.py +5 -0
  259. agentinputlab/parity/base.py +206 -0
  260. agentinputlab/production_campaign.py +763 -0
  261. agentinputlab/py.typed +1 -0
  262. agentinputlab/recipes/__init__.py +333 -0
  263. agentinputlab/recipes/ace.py +418 -0
  264. agentinputlab/recipes/ace_bfcl.py +273 -0
  265. agentinputlab/recipes/ace_common_support.py +169 -0
  266. agentinputlab/recipes/ace_native_plan.py +322 -0
  267. agentinputlab/recipes/ace_online.py +711 -0
  268. agentinputlab/recipes/ace_retrieval.py +330 -0
  269. agentinputlab/recipes/ace_statebench.py +382 -0
  270. agentinputlab/recipes/ace_tau.py +463 -0
  271. agentinputlab/recipes/ace_toolsandbox.py +432 -0
  272. agentinputlab/recipes/acon_guideline.py +22 -0
  273. agentinputlab/recipes/adaptive_rag.py +822 -0
  274. agentinputlab/recipes/llmlingua2_inference.py +146 -0
  275. agentinputlab/recipes/llmlingua2_training.py +796 -0
  276. agentinputlab/recipes/mce.py +1486 -0
  277. agentinputlab/recipes/mce_final.py +335 -0
  278. agentinputlab/recipes/mce_text_fit.py +499 -0
  279. agentinputlab/recipes/mce_text_only.py +298 -0
  280. agentinputlab/recipes/qrag.py +729 -0
  281. agentinputlab/recipes/qrag_inference.py +364 -0
  282. agentinputlab/recipes/r2ag_features.py +236 -0
  283. agentinputlab/recipes/r2ag_inference.py +503 -0
  284. agentinputlab/recipes/r2ag_training.py +948 -0
  285. agentinputlab/recipes/recomp_abstractive.py +592 -0
  286. agentinputlab/recipes/recomp_extractive.py +525 -0
  287. agentinputlab/recipes/reformer.py +17 -0
  288. agentinputlab/recipes/rqrag.py +1516 -0
  289. agentinputlab/recipes/rqrag_common_support.py +193 -0
  290. agentinputlab/recipes/rqrag_completion.py +147 -0
  291. agentinputlab/recipes/skillopt.py +462 -0
  292. agentinputlab/recipes/skillopt_common_support.py +154 -0
  293. agentinputlab/recipes/skillopt_environment.py +165 -0
  294. agentinputlab/recipes/skillopt_environment_cli.py +5 -0
  295. agentinputlab/recipes/skillopt_retrieval.py +188 -0
  296. agentinputlab/recipes/smartsearch.py +897 -0
  297. agentinputlab/recipes/smartsearch_curriculum.py +283 -0
  298. agentinputlab/recipes/smartsearch_grpo_contracts.py +58 -0
  299. agentinputlab/recipes/smartsearch_grpo_data.py +314 -0
  300. agentinputlab/recipes/smartsearch_grpo_meter.py +324 -0
  301. agentinputlab/recipes/smartsearch_grpo_prefix.py +144 -0
  302. agentinputlab/recipes/smartsearch_grpo_rollout.py +119 -0
  303. agentinputlab/recipes/smartsearch_grpo_tools.py +364 -0
  304. agentinputlab/recipes/smartsearch_grpo_training.py +305 -0
  305. agentinputlab/recipes/smartsearch_grpo_transport.py +248 -0
  306. agentinputlab/recipes/smartsearch_grpo_worker.py +364 -0
  307. agentinputlab/recipes/smartsearch_inference.py +524 -0
  308. agentinputlab/recipes/smartsearch_native_data.py +172 -0
  309. agentinputlab/recipes/smartsearch_policy.py +616 -0
  310. agentinputlab/recipes/smartsearch_policy_worker.py +9 -0
  311. agentinputlab/recipes/smartsearch_sampling.py +232 -0
  312. agentinputlab/recipes/smartsearch_teacher.py +203 -0
  313. agentinputlab/recipes/smartsearch_training.py +265 -0
  314. agentinputlab/registry/__init__.py +46 -0
  315. agentinputlab/registry/beta.py +727 -0
  316. agentinputlab/registry/data/algorithms.json +1959 -0
  317. agentinputlab/registry/data/auxiliary_method_profiles.json +34 -0
  318. agentinputlab/registry/loader.py +100 -0
  319. agentinputlab/registry/result_manifest.py +184 -0
  320. agentinputlab/registry/runtime.py +195 -0
  321. agentinputlab/registry/schema.py +449 -0
  322. agentinputlab/runner/__init__.py +30 -0
  323. agentinputlab/runner/balance.py +248 -0
  324. agentinputlab/runner/cache.py +135 -0
  325. agentinputlab/runner/composite.py +130 -0
  326. agentinputlab/runner/engine.py +285 -0
  327. agentinputlab/runner/runtime_guard.py +268 -0
  328. agentinputlab/runner/worker.py +80 -0
  329. agentinputlab/runtime_bootstrap.py +288 -0
  330. agentinputlab/selectors/__init__.py +196 -0
  331. agentinputlab/selectors/advanced.py +1514 -0
  332. agentinputlab/selectors/artifacts.py +1087 -0
  333. agentinputlab/selectors/base.py +112 -0
  334. agentinputlab/selectors/campaigns.py +1893 -0
  335. agentinputlab/selectors/catalog.py +86 -0
  336. agentinputlab/selectors/discovery.py +1860 -0
  337. agentinputlab/selectors/evaluation.py +1348 -0
  338. agentinputlab/selectors/features.py +383 -0
  339. agentinputlab/selectors/learned.py +502 -0
  340. agentinputlab/selectors/no_op.py +28 -0
  341. agentinputlab/selectors/outcome_table.py +475 -0
  342. agentinputlab/selectors/producer.py +853 -0
  343. agentinputlab/selectors/rules.py +109 -0
  344. agentinputlab/selectors/runtime.py +420 -0
  345. agentinputlab/studies/__init__.py +16 -0
  346. agentinputlab/studies/design.py +165 -0
  347. agentinputlab/studies/paired.py +322 -0
  348. agentinputlab/studio/__init__.py +6 -0
  349. agentinputlab/studio/campaigns.py +819 -0
  350. agentinputlab/studio/engine.py +1408 -0
  351. agentinputlab/studio/model_backends.py +425 -0
  352. agentinputlab/studio/prepared.py +410 -0
  353. agentinputlab/studio/server.py +613 -0
  354. agentinputlab/studio/static/app.js +397 -0
  355. agentinputlab/studio/static/campaigns.html +175 -0
  356. agentinputlab/studio/static/campaigns.js +426 -0
  357. agentinputlab/studio/static/index.html +192 -0
  358. agentinputlab/studio/static/result.html +103 -0
  359. agentinputlab/studio/static/result.js +273 -0
  360. agentinputlab/studio/static/styles.css +467 -0
  361. agentinputlab-0.1.0a1.data/data/share/agentinputlab/CITATION.cff +22 -0
  362. agentinputlab-0.1.0a1.dist-info/METADATA +392 -0
  363. agentinputlab-0.1.0a1.dist-info/RECORD +469 -0
  364. agentinputlab-0.1.0a1.dist-info/WHEEL +5 -0
  365. agentinputlab-0.1.0a1.dist-info/entry_points.txt +6 -0
  366. agentinputlab-0.1.0a1.dist-info/licenses/LICENSE +21 -0
  367. agentinputlab-0.1.0a1.dist-info/licenses/NOTICE +31 -0
  368. agentinputlab-0.1.0a1.dist-info/licenses/THIRD_PARTY_NOTICES.md +94 -0
  369. agentinputlab-0.1.0a1.dist-info/top_level.txt +2 -0
  370. workers/README.md +94 -0
  371. workers/ace/README.md +261 -0
  372. workers/ace/__init__.py +1 -0
  373. workers/ace/compatibility_manifest.json +39 -0
  374. workers/ace/driver.py +1682 -0
  375. workers/acon/README.md +215 -0
  376. workers/acon/__init__.py +5 -0
  377. workers/acon/compatibility_manifest.json +93 -0
  378. workers/acon/driver.py +1859 -0
  379. workers/acon/fitted.py +395 -0
  380. workers/acon/guideline.py +470 -0
  381. workers/acon/guideline_source_manifest.json +20 -0
  382. workers/adaptive_rag/README.md +96 -0
  383. workers/adaptive_rag/__init__.py +15 -0
  384. workers/adaptive_rag/compatibility_manifest.json +61 -0
  385. workers/adaptive_rag/driver.py +1470 -0
  386. workers/adaptive_rag/fixture_runtime.py +163 -0
  387. workers/adaptive_rag/runtime.py +252 -0
  388. workers/ask_or_assume/README.md +124 -0
  389. workers/ask_or_assume/__init__.py +1 -0
  390. workers/ask_or_assume/compatibility_manifest.json +36 -0
  391. workers/ask_or_assume/driver.py +1227 -0
  392. workers/decomp/README.md +133 -0
  393. workers/decomp/UPSTREAM_LICENSE.Apache-2.0.txt +201 -0
  394. workers/decomp/__init__.py +5 -0
  395. workers/decomp/compatibility_manifest.json +205 -0
  396. workers/decomp/driver.py +1015 -0
  397. workers/decomp/live.py +137 -0
  398. workers/decomp/runtime.py +231 -0
  399. workers/infocqr/README.md +106 -0
  400. workers/infocqr/__init__.py +1 -0
  401. workers/infocqr/compatibility_manifest.json +84 -0
  402. workers/infocqr/driver.py +1766 -0
  403. workers/ircot/README.md +167 -0
  404. workers/ircot/__init__.py +7 -0
  405. workers/ircot/compatibility_manifest.json +121 -0
  406. workers/ircot/controlled.py +457 -0
  407. workers/ircot/driver.py +1373 -0
  408. workers/ircot/fixture_bindings.json +39 -0
  409. workers/ircot/fixture_config.json +48 -0
  410. workers/ircot/fixture_prompt.txt +2 -0
  411. workers/ircot/native_qa.py +398 -0
  412. workers/ircot/qa_compatibility_manifest.json +57 -0
  413. workers/ircot/runtime.py +97 -0
  414. workers/llmcompiler/README.md +160 -0
  415. workers/llmcompiler/__init__.py +1 -0
  416. workers/llmcompiler/compatibility_manifest.json +45 -0
  417. workers/llmcompiler/driver.py +1514 -0
  418. workers/llmcompiler/export_prompts.py +74 -0
  419. workers/llmcompiler/live.py +174 -0
  420. workers/llmcompiler/patch_manifest.json +147 -0
  421. workers/mce/README.md +198 -0
  422. workers/mce/__init__.py +29 -0
  423. workers/mce/compatibility_manifest.json +115 -0
  424. workers/mce/driver.py +2585 -0
  425. workers/mce/final_eval.py +173 -0
  426. workers/official_arenas/README.md +25 -0
  427. workers/official_arenas/__init__.py +1 -0
  428. workers/official_arenas/capture_records.py +110 -0
  429. workers/official_arenas/driver.py +619 -0
  430. workers/official_arenas/protocol.py +334 -0
  431. workers/official_arenas/providers/__init__.py +1 -0
  432. workers/official_arenas/providers/_live_history.py +228 -0
  433. workers/official_arenas/providers/_message_compat.py +77 -0
  434. workers/official_arenas/providers/appworld_ul.py +196 -0
  435. workers/official_arenas/providers/fixture.py +112 -0
  436. workers/official_arenas/providers/statebench.py +960 -0
  437. workers/official_arenas/providers/tau3.py +1672 -0
  438. workers/official_arenas/providers/tau_retail.py +586 -0
  439. workers/official_arenas/providers/toolsandbox.py +1321 -0
  440. workers/official_arenas/providers/tooltalk.py +699 -0
  441. workers/official_arenas/retail_capture.py +188 -0
  442. workers/official_arenas/retail_driver.py +275 -0
  443. workers/qrag/README.md +172 -0
  444. workers/qrag/__init__.py +1 -0
  445. workers/qrag/compatibility_manifest.json +64 -0
  446. workers/qrag/driver.py +673 -0
  447. workers/r2ag/README.md +154 -0
  448. workers/r2ag/__init__.py +5 -0
  449. workers/r2ag/compatibility_manifest.json +55 -0
  450. workers/r2ag/driver.py +1287 -0
  451. workers/r2ag/feature_schema.json +8 -0
  452. workers/r2ag/runtime.py +589 -0
  453. workers/recomp/README.md +120 -0
  454. workers/recomp/__init__.py +1 -0
  455. workers/recomp/compatibility_manifest.json +43 -0
  456. workers/recomp/driver.py +1653 -0
  457. workers/reformer/README.md +125 -0
  458. workers/reformer/__init__.py +1 -0
  459. workers/reformer/compatibility_manifest.json +68 -0
  460. workers/reformer/driver.py +1459 -0
  461. workers/reformer/induction.py +457 -0
  462. workers/rrr/README.md +126 -0
  463. workers/rrr/__init__.py +1 -0
  464. workers/rrr/compatibility_manifest.json +57 -0
  465. workers/rrr/driver.py +1133 -0
  466. workers/smartsearch/README.md +331 -0
  467. workers/smartsearch/__init__.py +1 -0
  468. workers/smartsearch/compatibility_manifest.json +41 -0
  469. workers/smartsearch/driver.py +1643 -0
@@ -0,0 +1,1025 @@
1
+ """Fail-closed analysis for the stratified unseen-:math:`\\tau^3` transfer.
2
+
3
+ The unseen transfer is not an all-actions benchmark. Each frozen stratum
4
+ contains ``NO_OP`` plus only the families that were declared eligible before
5
+ outcomes existed. This module therefore reports family effects only on their
6
+ observed legal support. It never fabricates missing counterfactuals or pools
7
+ them into an all-family ranking.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import random
13
+ import re
14
+ from collections.abc import Mapping, Sequence
15
+ from dataclasses import dataclass
16
+ from pathlib import Path
17
+ from statistics import fmean
18
+ from types import MappingProxyType
19
+ from typing import Any
20
+
21
+ from agentinputlab.benchmarks import ATOMIC_EXTERNAL_PAIR_CONTRACT
22
+ from agentinputlab.contracts.enums import ProfileKind, SemanticFamily
23
+ from agentinputlab.contracts.errors import ArtifactError, ValidationError
24
+ from agentinputlab.contracts.serialization import content_hash, freeze_mapping
25
+
26
+ from .analysis import (
27
+ _arm_metrics,
28
+ _cluster_bootstrap_interval,
29
+ _validate_resample_arguments,
30
+ load_verified_cell_results,
31
+ )
32
+ from .artifacts import verify_experiment_run_directory
33
+ from .loader import load_experiment_manifest
34
+ from .schema import ExperimentManifest, ExperimentStage
35
+ from .stateful_analysis import validate_external_arena_record_receipts
36
+
37
+ PAPER_UNSEEN_TAU3_PROTOCOL = "paper-unseen-tau3-transfer-v1"
38
+ UNSEEN_TAU3_ELIGIBILITY_PROTOCOL = "agentinputlab.unseen-tau3-eligibility.v1"
39
+ UNSEEN_TAU3_SELECTOR_DECISIONS_ARTIFACT = "agentinputlab.unseen_tau3_selector_decisions"
40
+
41
+ _TAU3_REVISION = "cf71a8070269883e38a365ffa85f78f46844c1f4"
42
+ _SHA256 = re.compile(r"^[0-9a-f]{64}$")
43
+ _GROUP_SHA256 = re.compile(r"^group_[0-9a-f]{64}$")
44
+ _IDENTIFIER = re.compile(r"^[a-z0-9][a-z0-9_.:-]*$")
45
+ _ENVIRONMENT_NAME = re.compile(r"^[A-Z_][A-Z0-9_]*$")
46
+ _CORE_FAMILIES = (
47
+ SemanticFamily.REFORMULATE,
48
+ SemanticFamily.DECOMPOSE,
49
+ SemanticFamily.ACQUIRE,
50
+ SemanticFamily.CLARIFY,
51
+ SemanticFamily.CURATE,
52
+ )
53
+ _VALID_SUCCESS = "valid_success"
54
+
55
+
56
+ @dataclass(frozen=True, slots=True)
57
+ class _UnseenRun:
58
+ root: Path
59
+ manifest: ExperimentManifest
60
+ records: tuple[Mapping[str, Any], ...]
61
+ stratum_id: str
62
+ eligible_families: tuple[SemanticFamily, ...]
63
+ group_count: int
64
+ expected_episodes: int
65
+ run_identity_hash: str
66
+ manifest_hash: str
67
+ plan_hash: str
68
+
69
+
70
+ def validate_unseen_tau3_analysis_plan(
71
+ value: Mapping[str, Any],
72
+ ) -> Mapping[str, Any]:
73
+ """Validate the exact outcome-blind 200-group eligibility plan."""
74
+
75
+ if not isinstance(value, Mapping):
76
+ raise ValidationError("unseen tau3 eligibility plan must be an object")
77
+ raw = dict(value)
78
+ supplied_hash = raw.pop("plan_hash", None)
79
+ expected_keys = {
80
+ "schema_version",
81
+ "protocol",
82
+ "source_revision",
83
+ "total_groups",
84
+ "model_slot",
85
+ "seed",
86
+ "strata",
87
+ }
88
+ if (
89
+ set(raw) != expected_keys
90
+ or raw.get("schema_version") != 1
91
+ or raw.get("protocol") != UNSEEN_TAU3_ELIGIBILITY_PROTOCOL
92
+ or raw.get("source_revision") != _TAU3_REVISION
93
+ or raw.get("total_groups") != 200
94
+ ):
95
+ raise ValidationError("unseen tau3 eligibility plan identity or census is invalid")
96
+ model_slot = _identifier(raw["model_slot"], label="unseen tau3 model slot")
97
+ seed = _nonnegative_integer(raw["seed"], label="unseen tau3 seed")
98
+ raw_strata = _sequence(raw["strata"], label="unseen tau3 strata")
99
+ if not raw_strata:
100
+ raise ValidationError("unseen tau3 eligibility plan requires strata")
101
+ family_order = {family.value: index for index, family in enumerate(_CORE_FAMILIES)}
102
+ strata: list[dict[str, Any]] = []
103
+ seen: set[str] = set()
104
+ total_groups = 0
105
+ total_episodes = 0
106
+ for index, item in enumerate(raw_strata):
107
+ if not isinstance(item, Mapping) or set(item) != {
108
+ "stratum_id",
109
+ "eligible_families",
110
+ "group_count",
111
+ "unit_inventory_env",
112
+ "unit_inventory_sha256_env",
113
+ }:
114
+ raise ValidationError(f"unseen tau3 stratum {index} fields are invalid")
115
+ stratum_id = _identifier(
116
+ item["stratum_id"],
117
+ label=f"unseen tau3 stratum {index} ID",
118
+ )
119
+ if stratum_id in seen:
120
+ raise ValidationError("unseen tau3 stratum IDs must be unique")
121
+ seen.add(stratum_id)
122
+ families_raw = _sequence(
123
+ item["eligible_families"],
124
+ label=f"unseen tau3 stratum {stratum_id} families",
125
+ )
126
+ try:
127
+ families = tuple(SemanticFamily(family) for family in families_raw)
128
+ except (TypeError, ValueError) as exc:
129
+ raise ValidationError("unseen tau3 eligibility contains an unknown family") from exc
130
+ if (
131
+ not families
132
+ or len(families) != len(set(families))
133
+ or any(family not in _CORE_FAMILIES for family in families)
134
+ or list(families_raw) != sorted(families_raw, key=lambda family: family_order[family])
135
+ ):
136
+ raise ValidationError(
137
+ "unseen tau3 eligible families must be canonical unique core families"
138
+ )
139
+ group_count = _positive_integer(
140
+ item["group_count"],
141
+ label=f"unseen tau3 stratum {stratum_id} group count",
142
+ )
143
+ if group_count < 2:
144
+ raise ValidationError(
145
+ "unseen tau3 strata require at least two independent groups "
146
+ "for a stratum-level uncertainty interval"
147
+ )
148
+ for field in ("unit_inventory_env", "unit_inventory_sha256_env"):
149
+ text = item[field]
150
+ if not isinstance(text, str) or _ENVIRONMENT_NAME.fullmatch(text) is None:
151
+ raise ValidationError(f"unseen tau3 {field} is invalid")
152
+ total_groups += group_count
153
+ total_episodes += group_count * (1 + len(families))
154
+ strata.append(
155
+ {
156
+ "stratum_id": stratum_id,
157
+ "eligible_families": [family.value for family in families],
158
+ "group_count": group_count,
159
+ "unit_inventory_env": item["unit_inventory_env"],
160
+ "unit_inventory_sha256_env": item["unit_inventory_sha256_env"],
161
+ }
162
+ )
163
+ if total_groups != 200:
164
+ raise ValidationError("unseen tau3 strata must contain exactly 200 groups")
165
+ if total_episodes > 1_200:
166
+ raise ValidationError("unseen tau3 plan exceeds the 1,200-episode ceiling")
167
+ base = {
168
+ "schema_version": 1,
169
+ "protocol": UNSEEN_TAU3_ELIGIBILITY_PROTOCOL,
170
+ "source_revision": _TAU3_REVISION,
171
+ "total_groups": 200,
172
+ "model_slot": model_slot,
173
+ "seed": seed,
174
+ "strata": strata,
175
+ }
176
+ plan_hash = content_hash(base)
177
+ if supplied_hash is not None and supplied_hash != plan_hash:
178
+ raise ValidationError("unseen tau3 eligibility plan hash differs from its content")
179
+ return freeze_mapping(
180
+ {
181
+ **base,
182
+ "planned_agent_episodes": total_episodes,
183
+ "maximum_agent_episodes": 1_200,
184
+ "plan_hash": plan_hash,
185
+ }
186
+ )
187
+
188
+
189
+ def validate_unseen_tau3_selector_decisions(
190
+ value: Mapping[str, Any],
191
+ *,
192
+ eligibility_plan_hash: str,
193
+ representative_manifest_hash: str,
194
+ ) -> Mapping[str, Any]:
195
+ """Validate an optional outcome-blind one-action-per-group policy artifact."""
196
+
197
+ expected_keys = {
198
+ "schema_version",
199
+ "artifact",
200
+ "stage",
201
+ "selector_id",
202
+ "selector_revision",
203
+ "selector_artifact_sha256",
204
+ "eligibility_plan_hash",
205
+ "representative_manifest_hash",
206
+ "records",
207
+ "outcomes_accessed",
208
+ "other_arm_outcomes_accessed",
209
+ "experiments_executed",
210
+ "decision_hash",
211
+ }
212
+ if not isinstance(value, Mapping) or set(value) != expected_keys:
213
+ raise ValidationError("unseen tau3 selector decision schema is invalid")
214
+ data = dict(value)
215
+ if (
216
+ data["schema_version"] != 1
217
+ or data["artifact"] != UNSEEN_TAU3_SELECTOR_DECISIONS_ARTIFACT
218
+ or data["stage"] != "frozen_before_outcomes"
219
+ or data["outcomes_accessed"] is not False
220
+ or data["other_arm_outcomes_accessed"] is not False
221
+ or data["experiments_executed"] is not False
222
+ or data["eligibility_plan_hash"] != eligibility_plan_hash
223
+ or data["representative_manifest_hash"] != representative_manifest_hash
224
+ ):
225
+ raise ValidationError(
226
+ "unseen tau3 selector decisions violate their frozen outcome-blind binding"
227
+ )
228
+ _identifier(data["selector_id"], label="unseen tau3 selector ID")
229
+ _identifier(data["selector_revision"], label="unseen tau3 selector revision")
230
+ _sha256(
231
+ data["selector_artifact_sha256"],
232
+ label="unseen tau3 selector artifact",
233
+ )
234
+ records: list[dict[str, str]] = []
235
+ seen: set[str] = set()
236
+ for index, item in enumerate(_sequence(data["records"], label="unseen tau3 selector records")):
237
+ if not isinstance(item, Mapping) or set(item) != {
238
+ "group_sha256",
239
+ "selected_family",
240
+ "selected_release_id",
241
+ }:
242
+ raise ValidationError(f"unseen tau3 selector decision {index} fields are invalid")
243
+ group_id = item["group_sha256"]
244
+ if (
245
+ not isinstance(group_id, str)
246
+ or _GROUP_SHA256.fullmatch(group_id) is None
247
+ or group_id in seen
248
+ ):
249
+ raise ValidationError("unseen tau3 selector decisions require unique anonymized groups")
250
+ seen.add(group_id)
251
+ try:
252
+ family = SemanticFamily(item["selected_family"])
253
+ except (TypeError, ValueError) as exc:
254
+ raise ValidationError("unseen tau3 selector selected an unknown family") from exc
255
+ if family not in {*_CORE_FAMILIES, SemanticFamily.NO_OP}:
256
+ raise ValidationError("unseen tau3 selector selected an unsupported family")
257
+ release_id = _identifier(
258
+ item["selected_release_id"],
259
+ label="unseen tau3 selector release",
260
+ )
261
+ records.append(
262
+ {
263
+ "group_sha256": group_id,
264
+ "selected_family": family.value,
265
+ "selected_release_id": release_id,
266
+ }
267
+ )
268
+ if len(records) != 200:
269
+ raise ValidationError("unseen tau3 selector decisions require exactly 200 groups")
270
+ _sha256(data["decision_hash"], label="unseen tau3 selector decision hash")
271
+ if (
272
+ content_hash({key: item for key, item in data.items() if key != "decision_hash"})
273
+ != data["decision_hash"]
274
+ ):
275
+ raise ValidationError("unseen tau3 selector decision hash differs from content")
276
+ return freeze_mapping({**data, "records": tuple(records)})
277
+
278
+
279
+ def analyze_unseen_tau3_transfer(
280
+ run_dirs: Sequence[str | Path],
281
+ *,
282
+ eligibility_plan: Mapping[str, Any],
283
+ representatives: Mapping[str, Any],
284
+ selector_decisions: Mapping[str, Any] | None = None,
285
+ metric: str = _VALID_SUCCESS,
286
+ algorithm_failure_value: float | None = None,
287
+ bootstrap_samples: int = 2_000,
288
+ random_seed: int = 2027,
289
+ ) -> Mapping[str, Any]:
290
+ """Analyze exact legal support without imputing unavailable family outcomes."""
291
+
292
+ _validate_resample_arguments(
293
+ bootstrap_samples=bootstrap_samples,
294
+ permutation_samples=1,
295
+ random_seed=random_seed,
296
+ )
297
+ if metric != _VALID_SUCCESS:
298
+ raise ValidationError(
299
+ "paper unseen tau3 transfer fixes the comparable metric to valid_success"
300
+ )
301
+ plan = validate_unseen_tau3_analysis_plan(eligibility_plan)
302
+ representative_hash, releases = _validated_representatives(representatives)
303
+ roots = tuple(Path(path).expanduser().resolve() for path in run_dirs)
304
+ if len(roots) != len(plan["strata"]) or len(set(roots)) != len(roots):
305
+ raise ValidationError(
306
+ "unseen tau3 transfer requires exactly one unique run per frozen stratum"
307
+ )
308
+ runs = tuple(
309
+ _load_unseen_run(
310
+ root,
311
+ plan=plan,
312
+ representative_manifest_hash=representative_hash,
313
+ releases=releases,
314
+ )
315
+ for root in roots
316
+ )
317
+ by_stratum: dict[str, _UnseenRun] = {}
318
+ for run in runs:
319
+ if run.stratum_id in by_stratum:
320
+ raise ArtifactError("unseen tau3 transfer contains a duplicate stratum run")
321
+ by_stratum[run.stratum_id] = run
322
+ expected_strata = {stratum["stratum_id"] for stratum in plan["strata"]}
323
+ if set(by_stratum) != expected_strata:
324
+ raise ArtifactError("unseen tau3 transfer does not cover the frozen strata")
325
+
326
+ group_rows: dict[str, dict[str, Any]] = {}
327
+ dependency_identity: Mapping[str, str] | None = None
328
+ scorer_identity: tuple[str, str, str] | None = None
329
+ total_episodes = 0
330
+ for stratum in plan["strata"]:
331
+ run = by_stratum[stratum["stratum_id"]]
332
+ baseline_id, family_arms = _unseen_arm_contract(
333
+ run.manifest,
334
+ expected_families=run.eligible_families,
335
+ representative_manifest_hash=representative_hash,
336
+ releases=releases,
337
+ )
338
+ for record in run.records:
339
+ receipt = _validate_unseen_external_receipts(
340
+ run.manifest,
341
+ record,
342
+ baseline_arm_id=baseline_id,
343
+ family_arms=family_arms,
344
+ metric=metric,
345
+ )
346
+ if dependency_identity is None:
347
+ dependency_identity = receipt["dependencies"]
348
+ elif receipt["dependencies"] != dependency_identity:
349
+ raise ArtifactError("unseen tau3 dependencies differ across groups or strata")
350
+ current_scorer = (
351
+ receipt["scorer_id"],
352
+ receipt["scorer_revision"],
353
+ receipt["outcome_contract_sha256"],
354
+ )
355
+ if scorer_identity is None:
356
+ scorer_identity = current_scorer
357
+ elif current_scorer != scorer_identity:
358
+ raise ArtifactError(
359
+ "unseen tau3 scorer or valid-success contract differs across strata"
360
+ )
361
+ group_id = receipt["group_sha256"]
362
+ if group_id in group_rows:
363
+ raise ArtifactError("unseen tau3 groups overlap across frozen eligibility strata")
364
+ values = _arm_metrics(
365
+ record,
366
+ metric=metric,
367
+ algorithm_failure_value=algorithm_failure_value,
368
+ )
369
+ if values is None: # pragma: no cover - verified run invariant
370
+ raise ArtifactError("unseen tau3 result cell is incomplete")
371
+ baseline = values[baseline_id]
372
+ group_rows[group_id] = {
373
+ "group_sha256": group_id,
374
+ "stratum_id": run.stratum_id,
375
+ "eligible_families": tuple(family.value for family in run.eligible_families),
376
+ "values": {
377
+ SemanticFamily.NO_OP.value: baseline,
378
+ **{family.value: values[arm_id] for family, arm_id in family_arms.items()},
379
+ },
380
+ "release_by_family": {
381
+ SemanticFamily.NO_OP.value: "baseline.no_op",
382
+ **{family.value: releases[family] for family in run.eligible_families},
383
+ },
384
+ }
385
+ total_episodes += len(run.manifest.arms)
386
+ if len(group_rows) != 200:
387
+ raise ArtifactError("unseen tau3 transfer requires exactly 200 independent groups")
388
+ if total_episodes != plan["planned_agent_episodes"] or total_episodes > 1_200:
389
+ raise ArtifactError("unseen tau3 realized episode census differs from the frozen plan")
390
+
391
+ rng = random.Random(random_seed)
392
+ family_outputs: dict[str, Any] = {}
393
+ for family in _CORE_FAMILIES:
394
+ supported = [row for row in group_rows.values() if family.value in row["eligible_families"]]
395
+ if not supported:
396
+ continue
397
+ effects = [
398
+ row["values"][family.value] - row["values"][SemanticFamily.NO_OP.value]
399
+ for row in supported
400
+ ]
401
+ strata_outputs: dict[str, Any] = {}
402
+ for stratum_id in sorted({row["stratum_id"] for row in supported}):
403
+ values = [
404
+ row["values"][family.value] - row["values"][SemanticFamily.NO_OP.value]
405
+ for row in supported
406
+ if row["stratum_id"] == stratum_id
407
+ ]
408
+ strata_outputs[stratum_id] = {
409
+ "support_groups": len(values),
410
+ "mean_effect_vs_no_op": fmean(values),
411
+ "cluster_bootstrap_95ci": list(
412
+ _cluster_bootstrap_interval(
413
+ values,
414
+ samples=bootstrap_samples,
415
+ rng=rng,
416
+ )
417
+ ),
418
+ }
419
+ worst = min(
420
+ strata_outputs.items(),
421
+ key=lambda item: (
422
+ float(item[1]["mean_effect_vs_no_op"]),
423
+ item[0],
424
+ ),
425
+ )
426
+ family_outputs[family.value] = {
427
+ "support_groups": len(supported),
428
+ "eligibility_coverage": len(supported) / 200.0,
429
+ "mean_effect_vs_no_op_on_legal_support": fmean(effects),
430
+ "cluster_bootstrap_95ci": list(
431
+ _cluster_bootstrap_interval(
432
+ effects,
433
+ samples=bootstrap_samples,
434
+ rng=rng,
435
+ )
436
+ ),
437
+ "strata": strata_outputs,
438
+ "worst_supported_stratum": {
439
+ "stratum_id": worst[0],
440
+ **worst[1],
441
+ },
442
+ "missing_counterfactuals_imputed": False,
443
+ }
444
+
445
+ selector_output: Mapping[str, Any]
446
+ if selector_decisions is None:
447
+ selector_output = {
448
+ "evaluated": False,
449
+ "analysis_scope": "family_transfer_only",
450
+ "reason": (
451
+ "No frozen unseen-group selector decision artifact was supplied; "
452
+ "family effects are not selector-transfer evidence."
453
+ ),
454
+ }
455
+ else:
456
+ frozen_decisions = validate_unseen_tau3_selector_decisions(
457
+ selector_decisions,
458
+ eligibility_plan_hash=plan["plan_hash"],
459
+ representative_manifest_hash=representative_hash,
460
+ )
461
+ selector_output = _evaluate_unseen_selector(
462
+ frozen_decisions,
463
+ group_rows=group_rows,
464
+ releases=releases,
465
+ bootstrap_samples=bootstrap_samples,
466
+ rng=rng,
467
+ )
468
+ assert dependency_identity is not None
469
+ assert scorer_identity is not None
470
+ return freeze_mapping(
471
+ {
472
+ "schema_version": 1,
473
+ "analysis": "paper_unseen_tau3_stratified_transfer",
474
+ "analysis_protocol": PAPER_UNSEEN_TAU3_PROTOCOL,
475
+ "metric": metric,
476
+ "eligibility_plan_hash": plan["plan_hash"],
477
+ "representative_manifest_hash": representative_hash,
478
+ "run_count": len(runs),
479
+ "independent_groups": 200,
480
+ "verified_agent_episodes": total_episodes,
481
+ "maximum_agent_episodes": 1_200,
482
+ "source_revision": _TAU3_REVISION,
483
+ "model_slot": plan["model_slot"],
484
+ "seed": plan["seed"],
485
+ "family_effects": family_outputs,
486
+ "selector_transfer": selector_output,
487
+ "dependency_identity_sha256": content_hash(dependency_identity),
488
+ "scorer_identity": {
489
+ "scorer_id": scorer_identity[0],
490
+ "scorer_revision": scorer_identity[1],
491
+ "outcome_contract_sha256": scorer_identity[2],
492
+ },
493
+ "support_rule": (
494
+ "Each family is estimated only on groups where that family was "
495
+ "frozen as eligible; unavailable actions are never imputed."
496
+ ),
497
+ "bootstrap_samples": bootstrap_samples,
498
+ "random_seed": random_seed,
499
+ "algorithm_failure_value": algorithm_failure_value,
500
+ "source_runs": tuple(
501
+ {
502
+ "study_id": run.manifest.study_id,
503
+ "stratum_id": run.stratum_id,
504
+ "run_identity_hash": run.run_identity_hash,
505
+ "manifest_hash": run.manifest_hash,
506
+ "plan_hash": run.plan_hash,
507
+ }
508
+ for run in sorted(runs, key=lambda item: item.stratum_id)
509
+ ),
510
+ "experiments_executed_by_analysis": False,
511
+ "paper_claim_authorized": False,
512
+ }
513
+ )
514
+
515
+
516
+ def _load_unseen_run(
517
+ root: Path,
518
+ *,
519
+ plan: Mapping[str, Any],
520
+ representative_manifest_hash: str,
521
+ releases: Mapping[SemanticFamily, str],
522
+ ) -> _UnseenRun:
523
+ verification = verify_experiment_run_directory(root)
524
+ if not verification["complete"] or not verification["all_succeeded"]:
525
+ raise ArtifactError("unseen tau3 analysis requires complete all-succeeded verified runs")
526
+ manifest = load_experiment_manifest(root / "manifest.json")
527
+ if (
528
+ manifest.stage is not ExperimentStage.TRANSFER
529
+ or manifest.estimand_profile_kind is not ProfileKind.CONTROLLED_ADAPTER
530
+ or not manifest.study_id.startswith("robustness.unseen_tau3.")
531
+ or manifest.driver_entrypoint != "agentinputlab.experiments.drivers.external_arena:factory"
532
+ or len(manifest.benchmarks) != 1
533
+ or manifest.benchmarks[0].cell_id != "tau3.banking_knowledge"
534
+ or manifest.benchmarks[0].source_revision != _TAU3_REVISION
535
+ or manifest.metadata.get("requires_atomic_external_replay") is not True
536
+ or manifest.metadata.get("fit_or_calibrate_allowed") is not False
537
+ or manifest.metadata.get("eligibility_plan_hash") != plan["plan_hash"]
538
+ or manifest.metadata.get("eligibility_plan_total_groups") != 200
539
+ or manifest.metadata.get("campaign_maximum_agent_episodes") != 1_200
540
+ or manifest.metadata.get("campaign_expected_agent_episodes")
541
+ != plan["planned_agent_episodes"]
542
+ or manifest.metadata.get("representative_manifest_hash") != representative_manifest_hash
543
+ or manifest.model_slots != (plan["model_slot"],)
544
+ or manifest.seeds != (plan["seed"],)
545
+ ):
546
+ raise ArtifactError("unseen tau3 run differs from the frozen transfer protocol")
547
+ stratum_id = manifest.metadata.get("eligibility_stratum")
548
+ candidates = [stratum for stratum in plan["strata"] if stratum["stratum_id"] == stratum_id]
549
+ if len(candidates) != 1:
550
+ raise ArtifactError("unseen tau3 run references an unknown eligibility stratum")
551
+ stratum = candidates[0]
552
+ families = tuple(SemanticFamily(value) for value in stratum["eligible_families"])
553
+ if (
554
+ manifest.metadata.get("eligible_families") != list(stratum["eligible_families"])
555
+ or manifest.benchmarks[0].split != f"unseen_transfer.{stratum_id}"
556
+ ):
557
+ raise ArtifactError("unseen tau3 run eligibility or split differs from its stratum")
558
+ _unseen_arm_contract(
559
+ manifest,
560
+ expected_families=families,
561
+ representative_manifest_hash=representative_manifest_hash,
562
+ releases=releases,
563
+ )
564
+ census = manifest.metadata.get("experiment_census")
565
+ group_count = int(stratum["group_count"])
566
+ expected_episodes = group_count * len(manifest.arms)
567
+ if (
568
+ not isinstance(census, Mapping)
569
+ or census.get("protocol") != "agentinputlab.experiment_census.v1"
570
+ or census.get("campaign_kind") != "unseen_tau3_transfer_stratum"
571
+ or census.get("independent_group_target") != group_count
572
+ or census.get("expected_plan_cells") != group_count
573
+ or census.get("expected_agent_episodes") != expected_episodes
574
+ or tuple(census.get("expected_arm_ids", ())) != tuple(arm.arm_id for arm in manifest.arms)
575
+ or tuple(census.get("expected_model_slots", ())) != manifest.model_slots
576
+ or tuple(census.get("expected_seeds", ())) != manifest.seeds
577
+ ):
578
+ raise ArtifactError("unseen tau3 run census differs from the frozen stratum")
579
+ records = load_verified_cell_results(root)
580
+ if len(records) != group_count:
581
+ raise ArtifactError("unseen tau3 run record count differs from its group census")
582
+ for record in records:
583
+ cell = record.get("cell")
584
+ if (
585
+ not isinstance(cell, Mapping)
586
+ or cell.get("benchmark_id") != "tau3.banking_knowledge"
587
+ or cell.get("split") != f"unseen_transfer.{stratum_id}"
588
+ or cell.get("model_slot") != plan["model_slot"]
589
+ or cell.get("seed") != plan["seed"]
590
+ or tuple(cell.get("arm_ids", ())) != tuple(arm.arm_id for arm in manifest.arms)
591
+ ):
592
+ raise ArtifactError("unseen tau3 result cell differs from its frozen manifest")
593
+ return _UnseenRun(
594
+ root=root,
595
+ manifest=manifest,
596
+ records=records,
597
+ stratum_id=str(stratum_id),
598
+ eligible_families=families,
599
+ group_count=group_count,
600
+ expected_episodes=expected_episodes,
601
+ run_identity_hash=_sha256(
602
+ verification["identity_hash"],
603
+ label="unseen tau3 run identity",
604
+ ),
605
+ manifest_hash=_sha256(
606
+ verification["manifest_hash"],
607
+ label="unseen tau3 manifest hash",
608
+ ),
609
+ plan_hash=_sha256(
610
+ verification["plan_hash"],
611
+ label="unseen tau3 run plan hash",
612
+ ),
613
+ )
614
+
615
+
616
+ def _unseen_arm_contract(
617
+ manifest: ExperimentManifest,
618
+ *,
619
+ expected_families: Sequence[SemanticFamily],
620
+ representative_manifest_hash: str,
621
+ releases: Mapping[SemanticFamily, str],
622
+ ) -> tuple[str, Mapping[SemanticFamily, str]]:
623
+ baselines = [arm for arm in manifest.arms if arm.family is SemanticFamily.NO_OP]
624
+ interventions = [arm for arm in manifest.arms if arm.family is not SemanticFamily.NO_OP]
625
+ if (
626
+ len(baselines) != 1
627
+ or baselines[0].release_id != "baseline.no_op"
628
+ or tuple(arm.family for arm in interventions) != tuple(expected_families)
629
+ or len({arm.family for arm in interventions}) != len(interventions)
630
+ ):
631
+ raise ArtifactError("unseen tau3 arm inventory differs from legal family support")
632
+ family_arms: dict[SemanticFamily, str] = {}
633
+ for arm in interventions:
634
+ if (
635
+ arm.release_id != releases.get(arm.family)
636
+ or arm.parameters.get("representative_rank") != 1
637
+ or arm.parameters.get("representative_manifest_hash") != representative_manifest_hash
638
+ ):
639
+ raise ArtifactError("unseen tau3 arm differs from the frozen rank-1 representative")
640
+ family_arms[arm.family] = arm.arm_id
641
+ return baselines[0].arm_id, MappingProxyType(family_arms)
642
+
643
+
644
+ def _validate_unseen_external_receipts(
645
+ manifest: ExperimentManifest,
646
+ record: Mapping[str, Any],
647
+ *,
648
+ baseline_arm_id: str,
649
+ family_arms: Mapping[SemanticFamily, str],
650
+ metric: str,
651
+ ) -> Mapping[str, Any]:
652
+ normalized = validate_external_arena_record_receipts(
653
+ manifest,
654
+ record,
655
+ metric=metric,
656
+ )
657
+ expected_arm_ids = {baseline_arm_id, *family_arms.values()}
658
+ if (
659
+ normalized["suite_id"] != "tau3.banking_knowledge"
660
+ or normalized["source_revision"] != _TAU3_REVISION
661
+ or normalized["baseline_arm_id"] != baseline_arm_id
662
+ or set(normalized["arms"]) != expected_arm_ids
663
+ or any(
664
+ normalized["arms"][arm_id]["family"] != family.value
665
+ for family, arm_id in family_arms.items()
666
+ )
667
+ ):
668
+ raise ArtifactError(
669
+ "unseen tau3 normalized atomic receipt differs from legal family support"
670
+ )
671
+ cell = record.get("cell")
672
+ result = record.get("result")
673
+ payload = result.get("payload") if isinstance(result, Mapping) else None
674
+ if not isinstance(cell, Mapping) or not isinstance(payload, Mapping):
675
+ raise ArtifactError("unseen tau3 result lacks cell or payload")
676
+ if (
677
+ payload.get("atomic_replay_contract") != ATOMIC_EXTERNAL_PAIR_CONTRACT
678
+ or payload.get("benchmark_id") != cell.get("benchmark_id")
679
+ or payload.get("split") != cell.get("split")
680
+ or payload.get("unit_id") != cell.get("unit_id")
681
+ or payload.get("model_slot") != cell.get("model_slot")
682
+ or payload.get("seed") != cell.get("seed")
683
+ or payload.get("baseline_arm_id") != baseline_arm_id
684
+ or tuple(payload.get("planned_arm_ids", ())) != tuple(cell.get("arm_ids", ()))
685
+ or payload.get("target_source_revision") != _TAU3_REVISION
686
+ ):
687
+ raise ArtifactError("unseen tau3 atomic payload identity is invalid")
688
+ checkpoint = payload.get("checkpoint_identity")
689
+ if not isinstance(checkpoint, Mapping):
690
+ raise ArtifactError("unseen tau3 payload lacks checkpoint identity")
691
+ group_id = checkpoint.get("group_sha256")
692
+ if (
693
+ not isinstance(group_id, str)
694
+ or _GROUP_SHA256.fullmatch(group_id) is None
695
+ or checkpoint.get("source_revision") != _TAU3_REVISION
696
+ ):
697
+ raise ArtifactError("unseen tau3 checkpoint group or source identity is invalid")
698
+ for field in (
699
+ "identity_sha256",
700
+ "visible_state_sha256",
701
+ "origin_state_sha256",
702
+ "replay_identity_sha256",
703
+ ):
704
+ _sha256(checkpoint.get(field), label=f"unseen tau3 checkpoint {field}")
705
+ dependencies = _dependency_hashes(
706
+ payload.get("observed_dependency_hashes"),
707
+ label="unseen tau3 observed dependencies",
708
+ )
709
+ baseline_consistency = _sha256(
710
+ payload.get("baseline_consistency_sha256"),
711
+ label="unseen tau3 baseline consistency",
712
+ )
713
+ pairs = _sequence(payload.get("atomic_pairs"), label="unseen tau3 atomic pairs")
714
+ expected_treatments = set(family_arms.values())
715
+ if len(pairs) != len(expected_treatments):
716
+ raise ArtifactError("unseen tau3 atomic pair inventory is incomplete")
717
+ receipt_hash_by_arm: dict[str, str] = {}
718
+ scorer: tuple[str, str] | None = None
719
+ for pair in pairs:
720
+ if not isinstance(pair, Mapping):
721
+ raise ArtifactError("unseen tau3 atomic pair receipt must be an object")
722
+ treatment_id = pair.get("treatment_arm_id")
723
+ if (
724
+ treatment_id not in expected_treatments
725
+ or treatment_id in receipt_hash_by_arm
726
+ or pair.get("baseline_consistency_sha256") != baseline_consistency
727
+ ):
728
+ raise ArtifactError("unseen tau3 atomic pair treatment identity is invalid")
729
+ _sha256(pair.get("request_sha256"), label="unseen tau3 atomic request")
730
+ receipt = pair.get("receipt")
731
+ if not isinstance(receipt, Mapping):
732
+ raise ArtifactError("unseen tau3 atomic pair lacks a typed receipt")
733
+ receipt_hash = _sha256(
734
+ pair.get("receipt_sha256"),
735
+ label="unseen tau3 atomic receipt",
736
+ )
737
+ if content_hash(receipt) != receipt_hash:
738
+ raise ArtifactError("unseen tau3 atomic receipt hash differs from content")
739
+ if (
740
+ receipt.get("benchmark_id") != "tau3.banking_knowledge"
741
+ or receipt.get("checkpoint_id") != cell.get("unit_id")
742
+ or receipt.get("source_revision") != _TAU3_REVISION
743
+ or receipt.get("origin_state_hash") != checkpoint["origin_state_sha256"]
744
+ or receipt.get("replay_identity") != checkpoint["replay_identity_sha256"]
745
+ or receipt.get("seed") != cell.get("seed")
746
+ or receipt.get("locked_dependency_hashes") != dependencies
747
+ ):
748
+ raise ArtifactError("unseen tau3 atomic receipt differs from frozen replay identity")
749
+ scorer_id = _nonempty_text(
750
+ receipt.get("scorer_id"),
751
+ label="unseen tau3 scorer ID",
752
+ )
753
+ scorer_revision = _sha256(
754
+ receipt.get("scorer_revision"),
755
+ label="unseen tau3 scorer revision",
756
+ )
757
+ current_scorer = (scorer_id, scorer_revision)
758
+ if scorer is None:
759
+ scorer = current_scorer
760
+ elif current_scorer != scorer:
761
+ raise ArtifactError("unseen tau3 atomic pairs use different official scorers")
762
+ arms = _sequence(
763
+ receipt.get("arms"),
764
+ label="unseen tau3 atomic receipt arms",
765
+ )
766
+ by_role: dict[str, Mapping[str, Any]] = {}
767
+ for arm in arms:
768
+ if not isinstance(arm, Mapping) or arm.get("role") not in {
769
+ "baseline",
770
+ "treatment",
771
+ }:
772
+ raise ArtifactError("unseen tau3 atomic arm receipt is invalid")
773
+ role = str(arm["role"])
774
+ if role in by_role:
775
+ raise ArtifactError("unseen tau3 atomic receipt duplicates an arm role")
776
+ by_role[role] = arm
777
+ if set(by_role) != {"baseline", "treatment"}:
778
+ raise ArtifactError("unseen tau3 atomic receipt lacks both arm roles")
779
+ if (
780
+ by_role["baseline"].get("arm_id") != baseline_arm_id
781
+ or by_role["treatment"].get("arm_id") != treatment_id
782
+ or len(
783
+ {
784
+ by_role["baseline"].get("runtime_instance_id"),
785
+ by_role["treatment"].get("runtime_instance_id"),
786
+ }
787
+ )
788
+ != 2
789
+ ):
790
+ raise ArtifactError("unseen tau3 atomic arm roles or runtime instances are invalid")
791
+ for arm in by_role.values():
792
+ if (
793
+ arm.get("completed") is not True
794
+ or arm.get("origin_state_hash") != checkpoint["origin_state_sha256"]
795
+ or arm.get("replay_identity") != checkpoint["replay_identity_sha256"]
796
+ or arm.get("seed") != cell.get("seed")
797
+ or arm.get("locked_dependency_hashes") != dependencies
798
+ ):
799
+ raise ArtifactError(
800
+ "unseen tau3 atomic arm receipt differs from shared replay identity"
801
+ )
802
+ _sha256(
803
+ arm.get("runtime_instance_id"),
804
+ label="unseen tau3 runtime instance",
805
+ )
806
+ receipt_hash_by_arm[str(treatment_id)] = receipt_hash
807
+ if set(receipt_hash_by_arm) != expected_treatments or scorer is None:
808
+ raise ArtifactError("unseen tau3 atomic pair receipt coverage is incomplete")
809
+
810
+ raw_arms = _sequence(payload.get("arms"), label="unseen tau3 arm outcomes")
811
+ outcomes: dict[str, Mapping[str, Any]] = {}
812
+ for arm in raw_arms:
813
+ if not isinstance(arm, Mapping) or not isinstance(arm.get("arm_id"), str):
814
+ raise ArtifactError("unseen tau3 arm outcome is invalid")
815
+ arm_id = str(arm["arm_id"])
816
+ if arm_id in outcomes:
817
+ raise ArtifactError("unseen tau3 arm outcomes contain duplicates")
818
+ outcomes[arm_id] = arm
819
+ expected_arm_ids = {baseline_arm_id, *expected_treatments}
820
+ if set(outcomes) != expected_arm_ids:
821
+ raise ArtifactError("unseen tau3 arm outcomes differ from the legal arm inventory")
822
+ baseline_hashes = tuple(outcomes[baseline_arm_id].get("atomic_pair_receipt_sha256s", ()))
823
+ if set(baseline_hashes) != set(receipt_hash_by_arm.values()):
824
+ raise ArtifactError("unseen tau3 NO_OP outcome is not bound to every atomic pair")
825
+ contract_hash: str | None = None
826
+ for arm_id, outcome in outcomes.items():
827
+ if outcome.get("status") != "succeeded":
828
+ raise ArtifactError("unseen tau3 paper analysis requires succeeded arm outcomes")
829
+ if arm_id != baseline_arm_id and (
830
+ outcome.get("atomic_pair_receipt_sha256") != receipt_hash_by_arm[arm_id]
831
+ ):
832
+ raise ArtifactError("unseen tau3 treatment outcome is bound to another atomic pair")
833
+ composition = outcome.get("valid_success_composition")
834
+ metrics = outcome.get("metrics")
835
+ if not isinstance(composition, Mapping) or not isinstance(metrics, Mapping):
836
+ raise ArtifactError("unseen tau3 outcome lacks official score composition")
837
+ if (
838
+ composition.get("benchmark_id") != "tau3.banking_knowledge"
839
+ or composition.get("arm_id") != arm_id
840
+ or composition.get("scorer_id") != scorer[0]
841
+ or composition.get("scorer_revision") != scorer[1]
842
+ or composition.get("trace_hash") != outcome.get("trace_hash")
843
+ or composition.get(metric) != metrics.get(metric)
844
+ ):
845
+ raise ArtifactError("unseen tau3 valid-success composition is inconsistent")
846
+ composition_hash = _sha256(
847
+ composition.get("composition_receipt_sha256"),
848
+ label="unseen tau3 valid-success composition",
849
+ )
850
+ if (
851
+ content_hash(
852
+ {
853
+ key: item
854
+ for key, item in composition.items()
855
+ if key != "composition_receipt_sha256"
856
+ }
857
+ )
858
+ != composition_hash
859
+ ):
860
+ raise ArtifactError("unseen tau3 valid-success receipt hash differs from content")
861
+ current_contract = _sha256(
862
+ composition.get("outcome_contract_sha256"),
863
+ label="unseen tau3 outcome contract",
864
+ )
865
+ if contract_hash is None:
866
+ contract_hash = current_contract
867
+ elif current_contract != contract_hash:
868
+ raise ArtifactError("unseen tau3 arms use different valid-success contracts")
869
+ assert contract_hash is not None
870
+ if (
871
+ normalized["group_id"] != group_id
872
+ or normalized["dependency_identity"] != dependencies
873
+ or normalized["scorer_identity"]
874
+ != {
875
+ "scorer_id": scorer[0],
876
+ "scorer_revision": scorer[1],
877
+ }
878
+ or normalized["outcome_contract_sha256"] != contract_hash
879
+ ):
880
+ raise ArtifactError("unseen tau3 specialized receipts differ from shared arena validation")
881
+ return freeze_mapping(
882
+ {
883
+ "group_sha256": group_id,
884
+ "dependencies": dependencies,
885
+ "scorer_id": scorer[0],
886
+ "scorer_revision": scorer[1],
887
+ "outcome_contract_sha256": contract_hash,
888
+ }
889
+ )
890
+
891
+
892
+ def _evaluate_unseen_selector(
893
+ decisions: Mapping[str, Any],
894
+ *,
895
+ group_rows: Mapping[str, Mapping[str, Any]],
896
+ releases: Mapping[SemanticFamily, str],
897
+ bootstrap_samples: int,
898
+ rng: random.Random,
899
+ ) -> Mapping[str, Any]:
900
+ decision_rows = {row["group_sha256"]: row for row in decisions["records"]}
901
+ if set(decision_rows) != set(group_rows):
902
+ raise ValidationError(
903
+ "unseen tau3 selector decisions differ from the verified transfer groups"
904
+ )
905
+ values: list[float] = []
906
+ baseline_values: list[float] = []
907
+ effects: list[float] = []
908
+ intervention_coverage: list[float] = []
909
+ for group_id in sorted(group_rows):
910
+ group = group_rows[group_id]
911
+ decision = decision_rows[group_id]
912
+ family = SemanticFamily(decision["selected_family"])
913
+ if family is SemanticFamily.NO_OP:
914
+ expected_release = "baseline.no_op"
915
+ else:
916
+ if family.value not in group["eligible_families"]:
917
+ raise ValidationError(
918
+ "unseen tau3 selector chose a family outside frozen eligibility"
919
+ )
920
+ expected_release = releases[family]
921
+ if decision["selected_release_id"] != expected_release:
922
+ raise ValidationError("unseen tau3 selector changed the frozen representative release")
923
+ baseline = float(group["values"][SemanticFamily.NO_OP.value])
924
+ selected = float(group["values"][family.value])
925
+ values.append(selected)
926
+ baseline_values.append(baseline)
927
+ effects.append(selected - baseline)
928
+ intervention_coverage.append(0.0 if family is SemanticFamily.NO_OP else 1.0)
929
+ return {
930
+ "evaluated": True,
931
+ "analysis_scope": "frozen_unseen_group_selector_transfer",
932
+ "selector_id": decisions["selector_id"],
933
+ "selector_revision": decisions["selector_revision"],
934
+ "selector_artifact_sha256": decisions["selector_artifact_sha256"],
935
+ "decision_hash": decisions["decision_hash"],
936
+ "independent_groups": 200,
937
+ "mean_policy_value": fmean(values),
938
+ "mean_no_op_value": fmean(baseline_values),
939
+ "mean_effect_vs_no_op": fmean(effects),
940
+ "cluster_bootstrap_95ci": list(
941
+ _cluster_bootstrap_interval(
942
+ effects,
943
+ samples=bootstrap_samples,
944
+ rng=rng,
945
+ )
946
+ ),
947
+ "intervention_coverage": fmean(intervention_coverage),
948
+ "missing_counterfactuals_imputed": False,
949
+ "paper_claim_authorized": False,
950
+ }
951
+
952
+
953
+ def _validated_representatives(
954
+ value: Mapping[str, Any],
955
+ ) -> tuple[str, Mapping[SemanticFamily, str]]:
956
+ # Local import avoids a package-import cycle: selector campaigns use the
957
+ # experiment schema, while this analysis is exported by experiments.
958
+ from agentinputlab.selectors.campaigns import validate_representative_manifest
959
+
960
+ frozen = validate_representative_manifest(value)
961
+ releases = {
962
+ SemanticFamily(row["family"]): row["release_id"]
963
+ for row in frozen["selections"]
964
+ if row["rank"] == 1
965
+ }
966
+ if set(releases) != set(_CORE_FAMILIES):
967
+ raise ValidationError("unseen tau3 transfer requires one frozen rank-1 release per family")
968
+ return frozen["manifest_hash"], MappingProxyType(releases)
969
+
970
+
971
+ def _dependency_hashes(value: Any, *, label: str) -> Mapping[str, str]:
972
+ if not isinstance(value, Mapping) or not value:
973
+ raise ArtifactError(f"{label} must be a non-empty object")
974
+ parsed: dict[str, str] = {}
975
+ for slot, digest in value.items():
976
+ if not isinstance(slot, str) or not slot:
977
+ raise ArtifactError(f"{label} contains an invalid slot")
978
+ parsed[slot] = _sha256(digest, label=f"{label}.{slot}")
979
+ return freeze_mapping(parsed)
980
+
981
+
982
+ def _sha256(value: Any, *, label: str) -> str:
983
+ if not isinstance(value, str) or _SHA256.fullmatch(value) is None:
984
+ raise ArtifactError(f"{label} must be a lowercase SHA-256")
985
+ return value
986
+
987
+
988
+ def _identifier(value: Any, *, label: str) -> str:
989
+ if not isinstance(value, str) or _IDENTIFIER.fullmatch(value) is None:
990
+ raise ValidationError(f"{label} must be a lowercase identifier")
991
+ return value
992
+
993
+
994
+ def _nonempty_text(value: Any, *, label: str) -> str:
995
+ if not isinstance(value, str) or not value.strip():
996
+ raise ValidationError(f"{label} must be non-empty text")
997
+ return value
998
+
999
+
1000
+ def _sequence(value: Any, *, label: str) -> tuple[Any, ...]:
1001
+ if isinstance(value, str | bytes) or not isinstance(value, Sequence):
1002
+ raise ValidationError(f"{label} must be an array")
1003
+ return tuple(value)
1004
+
1005
+
1006
+ def _nonnegative_integer(value: Any, *, label: str) -> int:
1007
+ if isinstance(value, bool) or not isinstance(value, int) or value < 0:
1008
+ raise ValidationError(f"{label} must be a non-negative integer")
1009
+ return value
1010
+
1011
+
1012
+ def _positive_integer(value: Any, *, label: str) -> int:
1013
+ result = _nonnegative_integer(value, label=label)
1014
+ if result < 1:
1015
+ raise ValidationError(f"{label} must be positive")
1016
+ return result
1017
+
1018
+
1019
+ __all__ = [
1020
+ "PAPER_UNSEEN_TAU3_PROTOCOL",
1021
+ "UNSEEN_TAU3_SELECTOR_DECISIONS_ARTIFACT",
1022
+ "analyze_unseen_tau3_transfer",
1023
+ "validate_unseen_tau3_analysis_plan",
1024
+ "validate_unseen_tau3_selector_decisions",
1025
+ ]