agentevolve-optimizer 0.5.0__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 (414) hide show
  1. agent_evolve/__init__.py +722 -0
  2. agent_evolve/agentic.py +2800 -0
  3. agent_evolve/api.py +767 -0
  4. agent_evolve/application/__init__.py +1580 -0
  5. agent_evolve/application/action_allocation.py +744 -0
  6. agent_evolve/application/action_allocation_frame.py +347 -0
  7. agent_evolve/application/action_allocation_frame_commit.py +185 -0
  8. agent_evolve/application/action_allocation_frame_commit_v3.py +184 -0
  9. agent_evolve/application/action_allocation_frame_v3.py +338 -0
  10. agent_evolve/application/action_archive_value.py +497 -0
  11. agent_evolve/application/action_evidence_consistency.py +455 -0
  12. agent_evolve/application/action_forecast_partitioning.py +1471 -0
  13. agent_evolve/application/action_metric_projection.py +211 -0
  14. agent_evolve/application/action_role_value.py +680 -0
  15. agent_evolve/application/action_score_authorities.py +363 -0
  16. agent_evolve/application/action_structural_signature.py +116 -0
  17. agent_evolve/application/action_target_realization.py +402 -0
  18. agent_evolve/application/agentic_evolution.py +7734 -0
  19. agent_evolve/application/agentic_portfolio_residual_expert.py +835 -0
  20. agent_evolve/application/anchor_residual_identification.py +463 -0
  21. agent_evolve/application/archive_conditioned_action_target.py +208 -0
  22. agent_evolve/application/artifact_journal.py +246 -0
  23. agent_evolve/application/artifact_replay.py +347 -0
  24. agent_evolve/application/budgeted_optimizer.py +1828 -0
  25. agent_evolve/application/calibrated_campaign.py +485 -0
  26. agent_evolve/application/calibrated_current_prefix_forecast_opportunity.py +322 -0
  27. agent_evolve/application/calibrated_positive_gain_opportunity.py +1581 -0
  28. agent_evolve/application/campaign_capacity_recourse.py +254 -0
  29. agent_evolve/application/campaign_contextual_outcomes.py +119 -0
  30. agent_evolve/application/campaign_diagnostic_blocks.py +930 -0
  31. agent_evolve/application/campaign_evidence_registry.py +262 -0
  32. agent_evolve/application/campaign_execution.py +2537 -0
  33. agent_evolve/application/campaign_generation_audit.py +942 -0
  34. agent_evolve/application/campaign_learning.py +1812 -0
  35. agent_evolve/application/campaign_learning_runtime.py +1977 -0
  36. agent_evolve/application/campaign_search_phase.py +227 -0
  37. agent_evolve/application/campaign_selector_context_extension.py +220 -0
  38. agent_evolve/application/campaign_variation_envelope.py +649 -0
  39. agent_evolve/application/campaign_variation_trace.py +451 -0
  40. agent_evolve/application/candidate_archive_consequence.py +128 -0
  41. agent_evolve/application/causal_opportunity_portfolio_gate.py +385 -0
  42. agent_evolve/application/composite_outcome_updater.py +145 -0
  43. agent_evolve/application/composition_portfolio_selection.py +363 -0
  44. agent_evolve/application/concurrent_stage.py +144 -0
  45. agent_evolve/application/contextual_action_allocation.py +181 -0
  46. agent_evolve/application/contextual_campaign_outcomes.py +267 -0
  47. agent_evolve/application/contextual_campaign_planning.py +1366 -0
  48. agent_evolve/application/contextual_delayed_credit.py +651 -0
  49. agent_evolve/application/contextual_search_controller.py +2374 -0
  50. agent_evolve/application/current_prefix_forecast_opportunity.py +714 -0
  51. agent_evolve/application/decision_metric_projection.py +112 -0
  52. agent_evolve/application/derived_action_semantics.py +129 -0
  53. agent_evolve/application/detailed_evaluation.py +449 -0
  54. agent_evolve/application/earned_lineage.py +1011 -0
  55. agent_evolve/application/effective_choice_audit.py +484 -0
  56. agent_evolve/application/empirical_consequence_calibration.py +908 -0
  57. agent_evolve/application/evaluation_accounting.py +325 -0
  58. agent_evolve/application/evaluation_cache.py +199 -0
  59. agent_evolve/application/evaluation_escrow.py +547 -0
  60. agent_evolve/application/evaluation_recourse.py +253 -0
  61. agent_evolve/application/event_recorder.py +151 -0
  62. agent_evolve/application/evolution_campaign.py +1840 -0
  63. agent_evolve/application/executable_hypothesis.py +323 -0
  64. agent_evolve/application/factorial_branch_pilot.py +772 -0
  65. agent_evolve/application/finite_acquisition_capacity_recourse.py +672 -0
  66. agent_evolve/application/finite_acquisition_residual_expert.py +373 -0
  67. agent_evolve/application/finite_acquisition_variation_envelope.py +802 -0
  68. agent_evolve/application/finite_action_hypothesis_semantics.py +446 -0
  69. agent_evolve/application/finite_action_selection.py +188 -0
  70. agent_evolve/application/finite_action_set.py +306 -0
  71. agent_evolve/application/finite_action_transition.py +537 -0
  72. agent_evolve/application/finite_variation_eligibility.py +296 -0
  73. agent_evolve/application/forecast_geometry_portfolio.py +799 -0
  74. agent_evolve/application/forecast_opportunity_shadow_calibration.py +316 -0
  75. agent_evolve/application/front_proximity_admission.py +311 -0
  76. agent_evolve/application/front_proximity_parent_basis.py +458 -0
  77. agent_evolve/application/frozen_hurdle_score.py +659 -0
  78. agent_evolve/application/g3_causal_screen.py +2257 -0
  79. agent_evolve/application/g3_causal_validation.py +1046 -0
  80. agent_evolve/application/g3_postseal_curation.py +818 -0
  81. agent_evolve/application/gated_agentic_generator.py +205 -0
  82. agent_evolve/application/generation_feedback.py +293 -0
  83. agent_evolve/application/generative_proposal_journal.py +185 -0
  84. agent_evolve/application/geometry_conditional_elasticity.py +453 -0
  85. agent_evolve/application/global_wave_action_allocation.py +1151 -0
  86. agent_evolve/application/head_mass_conditional_seat.py +268 -0
  87. agent_evolve/application/identifiable_reflection_evidence.py +1147 -0
  88. agent_evolve/application/identifiable_reflection_learning.py +395 -0
  89. agent_evolve/application/identifiable_reflection_request.py +364 -0
  90. agent_evolve/application/in_memory_residual_archive.py +341 -0
  91. agent_evolve/application/insight_memory.py +1804 -0
  92. agent_evolve/application/live_runtime_manifest.py +758 -0
  93. agent_evolve/application/llm_task_queue.py +769 -0
  94. agent_evolve/application/matched_finite_action_block.py +409 -0
  95. agent_evolve/application/materialized_action_broker.py +2328 -0
  96. agent_evolve/application/materialized_action_constraints.py +83 -0
  97. agent_evolve/application/materialized_variation.py +211 -0
  98. agent_evolve/application/multi_option_evolution.py +1536 -0
  99. agent_evolve/application/outcome_adaptive_action_racing.py +2827 -0
  100. agent_evolve/application/outcome_adaptive_residual_campaign_runtime.py +580 -0
  101. agent_evolve/application/outcome_adaptive_residual_portfolio_evolution.py +3671 -0
  102. agent_evolve/application/outcome_conditioned_portfolio_selection.py +1374 -0
  103. agent_evolve/application/outcome_relation.py +193 -0
  104. agent_evolve/application/paired_allocation_comparison.py +241 -0
  105. agent_evolve/application/paired_block_schedule.py +127 -0
  106. agent_evolve/application/parent_measurement.py +226 -0
  107. agent_evolve/application/pareto_archive.py +811 -0
  108. agent_evolve/application/portfolio_campaign_runtime.py +4739 -0
  109. agent_evolve/application/portfolio_evolution.py +2950 -0
  110. agent_evolve/application/portfolio_hypothesis_observations.py +814 -0
  111. agent_evolve/application/portfolio_memory_attribution.py +581 -0
  112. agent_evolve/application/portfolio_memory_dose.py +788 -0
  113. agent_evolve/application/portfolio_memory_matched_control.py +938 -0
  114. agent_evolve/application/portfolio_memory_transfer.py +297 -0
  115. agent_evolve/application/portfolio_optimization_memory.py +363 -0
  116. agent_evolve/application/portfolio_outcome_feedback.py +1613 -0
  117. agent_evolve/application/portfolio_projection.py +335 -0
  118. agent_evolve/application/portfolio_recombination.py +2032 -0
  119. agent_evolve/application/post_evolution_reflection.py +834 -0
  120. agent_evolve/application/postcommit_rank_authority.py +245 -0
  121. agent_evolve/application/precommitted_portfolio_racing.py +2762 -0
  122. agent_evolve/application/prequential_archive_opportunity_calibration.py +1154 -0
  123. agent_evolve/application/prequential_residual_exploration.py +343 -0
  124. agent_evolve/application/prequential_score_portfolio.py +954 -0
  125. agent_evolve/application/projections.py +292 -0
  126. agent_evolve/application/protected_action_committee.py +1027 -0
  127. agent_evolve/application/protected_branch_pilot.py +376 -0
  128. agent_evolve/application/protected_current_prefix_forecast_opportunity.py +552 -0
  129. agent_evolve/application/provider_replay.py +910 -0
  130. agent_evolve/application/rank_balanced_causal_pilot.py +1372 -0
  131. agent_evolve/application/recombination_residual_expert.py +403 -0
  132. agent_evolve/application/reflection_workflow.py +571 -0
  133. agent_evolve/application/region_conditional_credit.py +911 -0
  134. agent_evolve/application/residual_campaign_runtime.py +531 -0
  135. agent_evolve/application/residual_headroom_campaign_runtime.py +459 -0
  136. agent_evolve/application/residual_headroom_ledger.py +1544 -0
  137. agent_evolve/application/residual_learning_transaction.py +396 -0
  138. agent_evolve/application/residual_portfolio_evolution.py +1228 -0
  139. agent_evolve/application/residual_reachability.py +749 -0
  140. agent_evolve/application/residual_stage_credit.py +499 -0
  141. agent_evolve/application/same_prefix_paired_audit.py +1580 -0
  142. agent_evolve/application/semantic_coverage_score_portfolio.py +838 -0
  143. agent_evolve/application/sequential_lineage_allocation.py +1017 -0
  144. agent_evolve/application/sequential_market_replay.py +1395 -0
  145. agent_evolve/application/sequential_residual_campaign_runtime.py +305 -0
  146. agent_evolve/application/sequential_residual_portfolio_evolution.py +940 -0
  147. agent_evolve/application/single_score_action_allocation.py +299 -0
  148. agent_evolve/application/source_exposure_allocation.py +906 -0
  149. agent_evolve/application/staged_memory.py +210 -0
  150. agent_evolve/application/stratified_cold_start_allocation.py +732 -0
  151. agent_evolve/application/support_guarded_hurdle_score.py +549 -0
  152. agent_evolve/application/target_conditioned_action_forecast.py +595 -0
  153. agent_evolve/application/target_conditioned_campaign.py +566 -0
  154. agent_evolve/application/treatment_assignment.py +201 -0
  155. agent_evolve/application/trusted_objective_evidence.py +217 -0
  156. agent_evolve/application/two_stage_action_evolution.py +1131 -0
  157. agent_evolve/application/v8lite_allocation_policy.py +1083 -0
  158. agent_evolve/application/v9_candidate_policy.py +1303 -0
  159. agent_evolve/bootstrap.py +108 -0
  160. agent_evolve/campaign_presets.py +517 -0
  161. agent_evolve/campaign_profiles.py +452 -0
  162. agent_evolve/campaign_variation_topology.py +288 -0
  163. agent_evolve/campaign_workload.py +950 -0
  164. agent_evolve/cli.py +797 -0
  165. agent_evolve/contract.py +241 -0
  166. agent_evolve/core/__init__.py +91 -0
  167. agent_evolve/core/action_semantics.py +411 -0
  168. agent_evolve/core/authored.py +105 -0
  169. agent_evolve/core/formatting.py +286 -0
  170. agent_evolve/core/optimization_semantics.py +324 -0
  171. agent_evolve/core/problem.py +167 -0
  172. agent_evolve/core/results.py +323 -0
  173. agent_evolve/core/stats.py +70 -0
  174. agent_evolve/core/telemetry.py +100 -0
  175. agent_evolve/domain/__init__.py +89 -0
  176. agent_evolve/domain/artifact.py +162 -0
  177. agent_evolve/domain/durable_text.py +68 -0
  178. agent_evolve/domain/event.py +1454 -0
  179. agent_evolve/domain/finite_action_set.py +426 -0
  180. agent_evolve/domain/finite_variation.py +526 -0
  181. agent_evolve/domain/generative_emission.py +559 -0
  182. agent_evolve/domain/ids.py +163 -0
  183. agent_evolve/domain/inline_text.py +106 -0
  184. agent_evolve/domain/insight.py +27 -0
  185. agent_evolve/domain/lineage.py +737 -0
  186. agent_evolve/domain/llm_task_queue.py +960 -0
  187. agent_evolve/domain/outcome.py +96 -0
  188. agent_evolve/domain/patch.py +854 -0
  189. agent_evolve/domain/typed_json.py +542 -0
  190. agent_evolve/domain/variation_space.py +158 -0
  191. agent_evolve/driver.py +1014 -0
  192. agent_evolve/harness/__init__.py +29 -0
  193. agent_evolve/harness/base.py +242 -0
  194. agent_evolve/harness/directives.py +163 -0
  195. agent_evolve/harness/generative_seal.py +479 -0
  196. agent_evolve/harness/registry.py +41 -0
  197. agent_evolve/infrastructure/__init__.py +39 -0
  198. agent_evolve/infrastructure/artifacts/__init__.py +6 -0
  199. agent_evolve/infrastructure/artifacts/_verification.py +67 -0
  200. agent_evolve/infrastructure/artifacts/filesystem.py +343 -0
  201. agent_evolve/infrastructure/artifacts/in_memory.py +73 -0
  202. agent_evolve/infrastructure/asyncio_runtime.py +109 -0
  203. agent_evolve/infrastructure/authored_runtime.py +188 -0
  204. agent_evolve/infrastructure/authored_worker.py +171 -0
  205. agent_evolve/infrastructure/clock.py +53 -0
  206. agent_evolve/infrastructure/events/__init__.py +6 -0
  207. agent_evolve/infrastructure/events/_validation.py +89 -0
  208. agent_evolve/infrastructure/events/in_memory.py +56 -0
  209. agent_evolve/infrastructure/events/jsonl.py +193 -0
  210. agent_evolve/infrastructure/exception_provenance.py +215 -0
  211. agent_evolve/infrastructure/ids.py +118 -0
  212. agent_evolve/infrastructure/lineage_codec.py +1836 -0
  213. agent_evolve/infrastructure/outcome_adaptive_phase_journal.py +170 -0
  214. agent_evolve/infrastructure/residual_headroom_journal.py +221 -0
  215. agent_evolve/infrastructure/resource_lease.py +370 -0
  216. agent_evolve/infrastructure/sanitization/__init__.py +8 -0
  217. agent_evolve/infrastructure/sanitization/strict_json.py +484 -0
  218. agent_evolve/infrastructure/sequential_phase_journal.py +170 -0
  219. agent_evolve/infrastructure/stream_liveness.py +383 -0
  220. agent_evolve/infrastructure/subprocess_boundary.py +136 -0
  221. agent_evolve/integrations/__init__.py +1 -0
  222. agent_evolve/integrations/botorch/__init__.py +28 -0
  223. agent_evolve/integrations/botorch/finite_qlognehvi.py +190 -0
  224. agent_evolve/integrations/botorch/finite_qlognehvi_batch.py +155 -0
  225. agent_evolve/integrations/botorch/finite_qlognehvi_batch_identity.py +20 -0
  226. agent_evolve/integrations/botorch/finite_qlognehvi_batch_worker.py +55 -0
  227. agent_evolve/integrations/botorch/finite_qlognehvi_identity.py +22 -0
  228. agent_evolve/integrations/botorch/finite_qlognehvi_worker.py +55 -0
  229. agent_evolve/integrations/botorch/subprocess_qlognehvi.py +261 -0
  230. agent_evolve/integrations/botorch/subprocess_qlognehvi_batch.py +273 -0
  231. agent_evolve/integrations/completion.py +242 -0
  232. agent_evolve/integrations/pydantic_ai/__init__.py +441 -0
  233. agent_evolve/integrations/pydantic_ai/action_forecast.py +1068 -0
  234. agent_evolve/integrations/pydantic_ai/agentic_generator.py +2308 -0
  235. agent_evolve/integrations/pydantic_ai/async_generator.py +1604 -0
  236. agent_evolve/integrations/pydantic_ai/boundary_codec.py +1526 -0
  237. agent_evolve/integrations/pydantic_ai/calibrated_portfolio_campaign.py +756 -0
  238. agent_evolve/integrations/pydantic_ai/calibrated_portfolio_selection.py +7537 -0
  239. agent_evolve/integrations/pydantic_ai/campaign_acquisition.py +609 -0
  240. agent_evolve/integrations/pydantic_ai/execution_binding.py +138 -0
  241. agent_evolve/integrations/pydantic_ai/forecast_geometry_action_committee.py +217 -0
  242. agent_evolve/integrations/pydantic_ai/harness.py +159 -0
  243. agent_evolve/integrations/pydantic_ai/heterogeneous_model_execution.py +306 -0
  244. agent_evolve/integrations/pydantic_ai/hierarchical_residual_adaptive_semantic_view.py +179 -0
  245. agent_evolve/integrations/pydantic_ai/json_schema_dialect.py +108 -0
  246. agent_evolve/integrations/pydantic_ai/materialized_hierarchical_residual_expert.py +952 -0
  247. agent_evolve/integrations/pydantic_ai/materialized_portfolio_judge.py +520 -0
  248. agent_evolve/integrations/pydantic_ai/model_execution_profile.py +659 -0
  249. agent_evolve/integrations/pydantic_ai/outbound_request_manifest.py +1170 -0
  250. agent_evolve/integrations/pydantic_ai/portable_residual_consequence_features.py +575 -0
  251. agent_evolve/integrations/pydantic_ai/portfolio_selection.py +422 -0
  252. agent_evolve/integrations/pydantic_ai/progress_aware_openrouter.py +416 -0
  253. agent_evolve/integrations/pydantic_ai/provider_attempt_join.py +1523 -0
  254. agent_evolve/integrations/pydantic_ai/provider_free_calibrated_runner.py +607 -0
  255. agent_evolve/integrations/pydantic_ai/queued_runner.py +2634 -0
  256. agent_evolve/integrations/pydantic_ai/reconciled_residual_reachability.py +1417 -0
  257. agent_evolve/integrations/pydantic_ai/residual_forecast_geometry.py +445 -0
  258. agent_evolve/integrations/pydantic_ai/residual_reachability.py +674 -0
  259. agent_evolve/integrations/pydantic_ai/residual_semantic_cells.py +239 -0
  260. agent_evolve/integrations/pydantic_ai/sealed_output_replay.py +1068 -0
  261. agent_evolve/integrations/pydantic_ai/semantic_coverage_residual_portfolio.py +770 -0
  262. agent_evolve/integrations/pydantic_ai/semantic_decision_replay.py +383 -0
  263. agent_evolve/integrations/pydantic_ai/support_adaptive_residual_portfolio.py +135 -0
  264. agent_evolve/integrations/pydantic_ai/trusted_residual_prompt_context.py +143 -0
  265. agent_evolve/integrations/pydantic_ai/validated_openrouter_model.py +107 -0
  266. agent_evolve/integrations/pymoo_adapter.py +242 -0
  267. agent_evolve/policies/__init__.py +17 -0
  268. agent_evolve/policies/check.py +469 -0
  269. agent_evolve/policies/emit_scaffold.py +451 -0
  270. agent_evolve/policies/feedback/__init__.py +37 -0
  271. agent_evolve/policies/feedback/held_out_asn.py +1325 -0
  272. agent_evolve/policies/genetic.py +607 -0
  273. agent_evolve/policies/llm_backoff.py +183 -0
  274. agent_evolve/policies/llm_chooser.py +226 -0
  275. agent_evolve/policies/llm_generator.py +1760 -0
  276. agent_evolve/policies/llm_init.py +267 -0
  277. agent_evolve/policies/llm_operator.py +109 -0
  278. agent_evolve/policies/llm_prior.py +194 -0
  279. agent_evolve/policies/llm_surrogate.py +334 -0
  280. agent_evolve/policies/measurement_evidence.py +704 -0
  281. agent_evolve/policies/memory/__init__.py +223 -0
  282. agent_evolve/policies/memory/balanced_subset_blocks.py +707 -0
  283. agent_evolve/policies/memory/compatibility_matching.py +593 -0
  284. agent_evolve/policies/memory/global_falsification.py +1841 -0
  285. agent_evolve/policies/memory/prompt_shape.py +503 -0
  286. agent_evolve/policies/memory/randomized_subset.py +714 -0
  287. agent_evolve/policies/memory/staged_causal.py +1270 -0
  288. agent_evolve/policies/memory/treatment_compliance.py +759 -0
  289. agent_evolve/policies/objective_resolution/__init__.py +17 -0
  290. agent_evolve/policies/objective_resolution/fixed_grid.py +364 -0
  291. agent_evolve/policies/operator_portfolio.py +407 -0
  292. agent_evolve/policies/reguidance.py +1133 -0
  293. agent_evolve/policies/reward/__init__.py +83 -0
  294. agent_evolve/policies/reward/affine_candidate_consequence.py +156 -0
  295. agent_evolve/policies/reward/affine_candidate_consequence_3d.py +159 -0
  296. agent_evolve/policies/reward/affine_hypervolume.py +490 -0
  297. agent_evolve/policies/reward/affine_hypervolume_3d.py +567 -0
  298. agent_evolve/policies/reward/contextual_marginal_utility.py +318 -0
  299. agent_evolve/policies/reward/frozen_archive.py +360 -0
  300. agent_evolve/policies/reward/frozen_wave_archive.py +368 -0
  301. agent_evolve/policies/search_state.py +208 -0
  302. agent_evolve/policies/selection/__init__.py +345 -0
  303. agent_evolve/policies/selection/acquisition_certified_slate.py +684 -0
  304. agent_evolve/policies/selection/affine_frontier_context.py +330 -0
  305. agent_evolve/policies/selection/affine_frontier_target.py +473 -0
  306. agent_evolve/policies/selection/archive_elite.py +1346 -0
  307. agent_evolve/policies/selection/calibrated_portfolio_binding.py +640 -0
  308. agent_evolve/policies/selection/calibrated_slate.py +1394 -0
  309. agent_evolve/policies/selection/calibrated_slate_codec.py +579 -0
  310. agent_evolve/policies/selection/common_candidate_pool.py +685 -0
  311. agent_evolve/policies/selection/diagnostic_sampling.py +319 -0
  312. agent_evolve/policies/selection/disjoint_pairs.py +479 -0
  313. agent_evolve/policies/selection/elite_explorer.py +719 -0
  314. agent_evolve/policies/selection/finite_action.py +187 -0
  315. agent_evolve/policies/selection/finite_option_prompt_projection.py +377 -0
  316. agent_evolve/policies/selection/finite_palette_evidence.py +247 -0
  317. agent_evolve/policies/selection/forecast_calibration.py +922 -0
  318. agent_evolve/policies/selection/frontier_probe_slate.py +814 -0
  319. agent_evolve/policies/selection/frozen_archive_pairs.py +762 -0
  320. agent_evolve/policies/selection/full_support_slate.py +91 -0
  321. agent_evolve/policies/selection/meaningful_direction.py +240 -0
  322. agent_evolve/policies/selection/memory_dose_feasibility.py +259 -0
  323. agent_evolve/policies/selection/model_anchored_slate.py +826 -0
  324. agent_evolve/policies/selection/phenotype_recourse.py +979 -0
  325. agent_evolve/policies/selection/proposal_support.py +368 -0
  326. agent_evolve/policies/selection/random_portfolio.py +254 -0
  327. agent_evolve/policies/selection/regret_bounded_slate.py +1084 -0
  328. agent_evolve/policies/selection/residual_frontier.py +463 -0
  329. agent_evolve/policies/selection/residual_frontier_target.py +605 -0
  330. agent_evolve/policies/selection/structural_posterior_slate.py +1571 -0
  331. agent_evolve/policies/selection/target_conditioned_allocator.py +648 -0
  332. agent_evolve/policies/selection/target_conditioned_features.py +812 -0
  333. agent_evolve/policies/selection/target_conditioned_prequential.py +1527 -0
  334. agent_evolve/policies/selection/task_keyed_palette.py +906 -0
  335. agent_evolve/policies/semantics.py +147 -0
  336. agent_evolve/policies/structure.py +362 -0
  337. agent_evolve/policies/structured_output_budget.py +62 -0
  338. agent_evolve/policies/surrogate.py +696 -0
  339. agent_evolve/policies/variation/__init__.py +1 -0
  340. agent_evolve/policies/variation/compositional_finite_catalog.py +426 -0
  341. agent_evolve/policies/variation/crossover_inheritance.py +575 -0
  342. agent_evolve/policies/variation/disjoint_recombination.py +611 -0
  343. agent_evolve/policies/variation/exact_composition_capacity.py +214 -0
  344. agent_evolve/policies/variation/exact_parent_crossover.py +950 -0
  345. agent_evolve/policies/variation/multiscale_restart_catalog.py +372 -0
  346. agent_evolve/policies/variation/source_union_finite_catalog.py +403 -0
  347. agent_evolve/policies/variation/typed_patch.py +1981 -0
  348. agent_evolve/policies/weighted_prior.py +394 -0
  349. agent_evolve/ports/__init__.py +383 -0
  350. agent_evolve/ports/action_allocation.py +733 -0
  351. agent_evolve/ports/action_allocation_frame.py +1153 -0
  352. agent_evolve/ports/action_allocation_frame_commit.py +294 -0
  353. agent_evolve/ports/action_allocation_frame_commit_v3.py +432 -0
  354. agent_evolve/ports/action_allocation_frame_v3.py +995 -0
  355. agent_evolve/ports/action_forecast.py +1568 -0
  356. agent_evolve/ports/action_metric_projection.py +165 -0
  357. agent_evolve/ports/agentic_generator.py +1561 -0
  358. agent_evolve/ports/archive_context.py +136 -0
  359. agent_evolve/ports/artifact_sanitizer.py +44 -0
  360. agent_evolve/ports/artifact_store.py +225 -0
  361. agent_evolve/ports/clock.py +13 -0
  362. agent_evolve/ports/contextual_search_allocation.py +827 -0
  363. agent_evolve/ports/decision_metric_projection.py +258 -0
  364. agent_evolve/ports/event_store.py +55 -0
  365. agent_evolve/ports/executable_hypothesis.py +557 -0
  366. agent_evolve/ports/finite_acquisition.py +377 -0
  367. agent_evolve/ports/finite_acquisition_batch.py +296 -0
  368. agent_evolve/ports/finite_acquisition_batch_json.py +164 -0
  369. agent_evolve/ports/finite_acquisition_json.py +247 -0
  370. agent_evolve/ports/finite_acquisition_space.py +168 -0
  371. agent_evolve/ports/finite_action_selection.py +348 -0
  372. agent_evolve/ports/finite_action_set.py +256 -0
  373. agent_evolve/ports/frontier_target.py +396 -0
  374. agent_evolve/ports/generation_failure.py +43 -0
  375. agent_evolve/ports/hard_feasibility.py +233 -0
  376. agent_evolve/ports/id_factory.py +34 -0
  377. agent_evolve/ports/llm_task_queue.py +93 -0
  378. agent_evolve/ports/objective_resolution.py +419 -0
  379. agent_evolve/ports/paired_allocation_comparison.py +401 -0
  380. agent_evolve/ports/paired_block_schedule.py +475 -0
  381. agent_evolve/ports/parent_measurement.py +336 -0
  382. agent_evolve/ports/portfolio_memory_dose.py +643 -0
  383. agent_evolve/ports/portfolio_selection.py +3169 -0
  384. agent_evolve/ports/postcommit_rank_authority.py +467 -0
  385. agent_evolve/ports/presented_action_evidence.py +794 -0
  386. agent_evolve/ports/resource_lease.py +162 -0
  387. agent_evolve/ports/structured_generator.py +734 -0
  388. agent_evolve/ports/structured_output_budget.py +120 -0
  389. agent_evolve/ports/subprocess_boundary.py +138 -0
  390. agent_evolve/ports/treatment_assignment.py +466 -0
  391. agent_evolve/ports/variation_catalog.py +76 -0
  392. agent_evolve/ports/variation_source.py +226 -0
  393. agent_evolve/proposal_mode.py +157 -0
  394. agent_evolve/proposers/__init__.py +10 -0
  395. agent_evolve/proposers/random_proposer.py +188 -0
  396. agent_evolve/provider_accounting.py +163 -0
  397. agent_evolve/py.typed +0 -0
  398. agent_evolve/reference_method.py +1570 -0
  399. agent_evolve/session/__init__.py +11 -0
  400. agent_evolve/session/authorship.py +864 -0
  401. agent_evolve/session/evaluate.py +236 -0
  402. agent_evolve/session/fidelity.py +237 -0
  403. agent_evolve/session/genetic_loop.py +742 -0
  404. agent_evolve/session/loop.py +803 -0
  405. agent_evolve/session/screening.py +671 -0
  406. agent_evolve/settings.py +376 -0
  407. agent_evolve/workload_kit.py +368 -0
  408. agent_evolve/workload_prompt.py +398 -0
  409. agentevolve_optimizer-0.5.0.dist-info/METADATA +599 -0
  410. agentevolve_optimizer-0.5.0.dist-info/RECORD +414 -0
  411. agentevolve_optimizer-0.5.0.dist-info/WHEEL +5 -0
  412. agentevolve_optimizer-0.5.0.dist-info/entry_points.txt +2 -0
  413. agentevolve_optimizer-0.5.0.dist-info/licenses/LICENSE +21 -0
  414. agentevolve_optimizer-0.5.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,3671 @@
1
+ """Durable outcome-adaptive evolution over one sealed proposal market.
2
+
3
+ This application service turns outcome-adaptive action racing into an honest
4
+ live protocol. Proposal experts materialize every action before a current
5
+ outcome exists. A diagnostic subset is evaluated first, and each subsequent
6
+ action is selected only from outcomes that have crossed a durable interception
7
+ boundary.
8
+
9
+ The service is workload-, objective-, model-, provider-, prompt-, and
10
+ configuration-schema blind. Workloads remain behind the existing proposal,
11
+ evaluation, archive-utility, slate-value, and slate-feasibility ports.
12
+ """
13
+
14
+ from __future__ import annotations
15
+
16
+ import asyncio
17
+ import hashlib
18
+ import json
19
+ import math
20
+ import re
21
+ from dataclasses import dataclass, field
22
+ from enum import Enum
23
+ from typing import Protocol, runtime_checkable
24
+
25
+ from agent_evolve.application.agentic_evolution import EvolutionCandidate
26
+ from agent_evolve.application.candidate_archive_consequence import (
27
+ CandidateArchivePortfolioConsequenceUtilityPort,
28
+ validate_candidate_archive_portfolio_consequence_utility,
29
+ )
30
+ from agent_evolve.application.forecast_opportunity_shadow_calibration import (
31
+ ForecastOpportunityShadowCalibrationProjector,
32
+ )
33
+ from agent_evolve.application.materialized_action_broker import (
34
+ BrokerActionScore,
35
+ MaterializedActionAllocationRequirement,
36
+ MaterializedActionBrokerDecision,
37
+ MaterializedActionBrokerRequest,
38
+ MaterializedActionDescriptor,
39
+ MaterializedSlateFeasibilityPort,
40
+ MaterializedSlateValuePort,
41
+ RegretBrokeredMaterializedActionPolicy,
42
+ )
43
+ from agent_evolve.application.outcome_adaptive_action_racing import (
44
+ AdaptiveActionAllocationDirective,
45
+ AdaptiveActionDescriptor,
46
+ AdaptiveActionFactorCell,
47
+ AdaptiveActionOutcome,
48
+ AdaptiveActionRacingDecision,
49
+ AdaptiveActionSetOutcome,
50
+ AdaptiveActionWave,
51
+ OUTCOME_ADAPTIVE_ACTION_RACING_CAUSAL_SET_POLICY_VERSION,
52
+ OUTCOME_ADAPTIVE_ACTION_RACING_RISK_CONTROLLED_POLICY_VERSION,
53
+ OUTCOME_ADAPTIVE_ACTION_RACING_STRATIFIED_AUDIT_POLICY_VERSION,
54
+ OutcomeAdaptiveActionRacingPolicy,
55
+ )
56
+ from agent_evolve.application.prequential_score_portfolio import (
57
+ MaterializedActionScoreBatch,
58
+ MaterializedActionScorePort,
59
+ )
60
+ from agent_evolve.application.prequential_archive_opportunity_calibration import (
61
+ ArchiveOpportunityCalibrationObservation,
62
+ )
63
+ from agent_evolve.application.protected_current_prefix_forecast_opportunity import (
64
+ ProtectedCurrentPrefixForecastOpportunityChallenger,
65
+ )
66
+ from agent_evolve.application.residual_portfolio_evolution import (
67
+ DISJOINT_ACTION_EVALUATION_WAVES_V1,
68
+ MaterializedActionAllocationPolicyPort,
69
+ MaterializedActionEvaluation,
70
+ MaterializedActionEvaluationBatch,
71
+ MaterializedActionProposalBatch,
72
+ MaterializedActionProposalExpertPort,
73
+ ResidualPortfolioDecisionRequest,
74
+ ResidualPortfolioEvolutionResult,
75
+ evaluate_materialized_action_counterfactual_subset,
76
+ evaluate_materialized_action_subset,
77
+ propose_materialized_action_batches,
78
+ )
79
+ from agent_evolve.application.same_prefix_paired_audit import (
80
+ FORECAST_OPPORTUNITY_SAME_PREFIX_AUDIT_DESIGNER_IDS,
81
+ FORECAST_OPPORTUNITY_SAME_PREFIX_SHADOW_DESIGNER_ID,
82
+ FORECAST_STRATIFIED_SAME_PREFIX_AUDIT_DESIGNER_ID,
83
+ ForecastOpportunitySamePrefixShadowDesignerPort,
84
+ SamePrefixPairedAuditAdjudicator,
85
+ SamePrefixPairedAuditArm,
86
+ SamePrefixPairedAuditDesignerPort,
87
+ SamePrefixPairedAuditObservation,
88
+ SamePrefixPairedAuditPlan,
89
+ )
90
+ from agent_evolve.domain.ids import CandidateId
91
+ from agent_evolve.domain.patch import require_sha256
92
+ from agent_evolve.domain.typed_json import (
93
+ FrozenJsonObject,
94
+ freeze_json,
95
+ thaw_json,
96
+ typed_json_sha256,
97
+ )
98
+
99
+
100
+ OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_ID = (
101
+ "outcome_adaptive_residual_portfolio_evolution"
102
+ )
103
+ OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_VERSION = 5
104
+ OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_DEFINITION_SHA256 = hashlib.sha256(
105
+ b"agent-evolve:outcome-adaptive-residual-portfolio-evolution:v5;"
106
+ b"proposal-market=sealed-once-before-current-outcomes;"
107
+ b"prior-authority=materialized-action-broker-selection-index;"
108
+ b"diagnostic-allocation=optional-outcome-blind-required-action-policy;"
109
+ b"diagnostic=portable-constrained-lane-head-design;"
110
+ b"continuation=one-real-outcome-then-one-action;"
111
+ b"causal-outcomes=fixed-set-and-prior-conditioned-set-lift;"
112
+ b"policy-use-of-causal-set-outcomes=version-gated;"
113
+ b"v4=conditional-opportunity-saturation-and-uniform-audit;"
114
+ b"v5=seed-invariant-directed-selection-and-epsilon-greedy-risk-audit;"
115
+ b"randomized-audit=logged-propensity;"
116
+ b"durability=market-diagnostic-each-adaptive-step-final;"
117
+ b"exactly-once=disjoint-action-evaluation-waves;"
118
+ b"archive-publication=combined-final-slate-only;"
119
+ b"workload-objective-model-provider-prompt-config-branches=false"
120
+ ).hexdigest()
121
+ OUTCOME_ADAPTIVE_RESIDUAL_PAIRED_AUDIT_EVOLUTION_VERSION = 6
122
+ OUTCOME_ADAPTIVE_RESIDUAL_PAIRED_AUDIT_EVOLUTION_DEFINITION_SHA256 = (
123
+ hashlib.sha256(
124
+ b"agent-evolve:outcome-adaptive-residual-portfolio-evolution:v6;"
125
+ b"base-definition="
126
+ + OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_DEFINITION_SHA256.encode(
127
+ "ascii"
128
+ )
129
+ + b";paired-audit=optional-same-prefix-distinct-arm-assay;"
130
+ b"paired-audit-plan=durable-before-either-arm-evaluation;"
131
+ b"paired-audit-publication=authoritative-arm-only;"
132
+ b"physical-budget=one-extra-real-evaluation-per-assayed-stage;"
133
+ b"workload-objective-model-provider-prompt-config-branches=false"
134
+ ).hexdigest()
135
+ )
136
+ OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_OPPORTUNITY_EVOLUTION_VERSION = 7
137
+ OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_OPPORTUNITY_EVOLUTION_DEFINITION_SHA256 = (
138
+ hashlib.sha256(
139
+ b"agent-evolve:outcome-adaptive-residual-portfolio-evolution:v7;"
140
+ b"base-definition="
141
+ + OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_DEFINITION_SHA256.encode(
142
+ "ascii"
143
+ )
144
+ + b";continuation=protected-current-prefix-forecast-opportunity;"
145
+ b"forecast-geometry=frozen-before-diagnostic-outcomes;"
146
+ b"fallback=complete-incumbent-racing-decision;"
147
+ b"abstention=preserve-fallback;"
148
+ b"candidate-outcomes=observed-prefix-only;"
149
+ b"eligible-candidate-outcomes=false;"
150
+ b"workload-objective-model-provider-prompt-config-branches=false"
151
+ ).hexdigest()
152
+ )
153
+ _FORECAST_OPPORTUNITY_DEFINITION_SHA256 = (
154
+ OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_OPPORTUNITY_EVOLUTION_DEFINITION_SHA256
155
+ )
156
+ _PAIRED_AUDIT_DEFINITION_SHA256 = (
157
+ OUTCOME_ADAPTIVE_RESIDUAL_PAIRED_AUDIT_EVOLUTION_DEFINITION_SHA256
158
+ )
159
+ OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_SHADOW_EVOLUTION_VERSION = 8
160
+ OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_SHADOW_EVOLUTION_DEFINITION_SHA256 = (
161
+ hashlib.sha256(
162
+ b"agent-evolve:outcome-adaptive-residual-portfolio-evolution:v8;"
163
+ b"base-definition="
164
+ + _FORECAST_OPPORTUNITY_DEFINITION_SHA256.encode("ascii")
165
+ + b";shadow=optional-same-prefix-challenger-vs-fallback-assay;"
166
+ b"shadow-plan=durable-before-either-arm-evaluation;"
167
+ b"shadow-schedule=final-continuation-only;"
168
+ b"shadow-publication=authoritative-challenger-only;"
169
+ b"physical-budget=one-extra-real-evaluation-per-assayed-stage;"
170
+ b"workload-objective-model-provider-prompt-config-branches=false"
171
+ ).hexdigest()
172
+ )
173
+ OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_STRATIFIED_AUDIT_EVOLUTION_VERSION = 9
174
+ OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_STRATIFIED_AUDIT_EVOLUTION_DEFINITION_SHA256 = (
175
+ hashlib.sha256(
176
+ b"agent-evolve:outcome-adaptive-residual-portfolio-evolution:v9;"
177
+ b"base-definition="
178
+ + _FORECAST_OPPORTUNITY_DEFINITION_SHA256.encode("ascii")
179
+ + b";audit=one-hash-rotated-same-prefix-forecast-stratum-assay;"
180
+ b"audit-plan=durable-before-either-arm-evaluation;"
181
+ b"abstention-authoritative-arm=protected-fallback;"
182
+ b"intervention-authoritative-arm=forecast-challenger;"
183
+ b"counterfactual-action=quarantined-from-later-authoritative-selection;"
184
+ b"sampling=uniform-nonempty-stratum-then-uniform-action;"
185
+ b"calibration=paired-role-and-propensity-authenticated;"
186
+ b"audit-publication=authoritative-arm-only;"
187
+ b"physical-budget=at-most-one-extra-real-evaluation-per-assayed-stage;"
188
+ b"workload-objective-model-provider-prompt-config-branches=false"
189
+ ).hexdigest()
190
+ )
191
+
192
+ PORTABLE_ADAPTIVE_MARKET_PROJECTOR_ID = (
193
+ "portable_materialized_adaptive_market_projector"
194
+ )
195
+ PORTABLE_ADAPTIVE_MARKET_PROJECTOR_VERSION = 1
196
+ PORTABLE_ADAPTIVE_MARKET_PROJECTOR_DEFINITION_SHA256 = hashlib.sha256(
197
+ b"agent-evolve:portable-materialized-adaptive-market-projector:v1;"
198
+ b"deduplicate=required-first-then-prior-score-native-rank-action-hash;"
199
+ b"lane=expert;operator=operator-id;"
200
+ b"prior=broker-selection-index;"
201
+ b"lineage=current-run-parent-membership;"
202
+ b"semantics=generic-materialized-action-context-only;"
203
+ b"workload-objective-model-provider-prompt-config-fields=false"
204
+ ).hexdigest()
205
+ PORTABLE_ADAPTIVE_SEMANTIC_VIEW_ID = (
206
+ "portable_materialized_adaptive_semantic_view"
207
+ )
208
+ PORTABLE_ADAPTIVE_SEMANTIC_VIEW_VERSION = 1
209
+ PORTABLE_ADAPTIVE_SEMANTIC_VIEW_DEFINITION_SHA256 = hashlib.sha256(
210
+ b"agent-evolve:portable-materialized-adaptive-semantic-view:v1;"
211
+ b"inputs=generic-materialized-action-context-lineage-and-role;"
212
+ b"workload-objective-model-provider-prompt-config-fields=false"
213
+ ).hexdigest()
214
+
215
+ CANDIDATE_ARCHIVE_ADAPTIVE_OUTCOME_PROJECTOR_ID = (
216
+ "candidate_archive_adaptive_action_outcome_projector"
217
+ )
218
+ CANDIDATE_ARCHIVE_ADAPTIVE_OUTCOME_PROJECTOR_VERSION = 2
219
+
220
+ _TOKEN = re.compile(r"^[a-z][a-z0-9_.:-]{0,255}$")
221
+ _MARKET_STATE_DOMAIN = b"agent-evolve:adaptive-market-state:v1\x00"
222
+ _SCORE_ENSEMBLE_PROJECTOR_DEFINITION_DOMAIN = (
223
+ b"agent-evolve:score-ensemble-adaptive-market-projector:v1\x00"
224
+ )
225
+ _FACTOR_STRATIFIED_PROJECTOR_DEFINITION_DOMAIN = (
226
+ b"agent-evolve:factor-stratified-adaptive-market-projector:v1\x00"
227
+ )
228
+ _OUTCOME_PROJECTOR_DEFINITION_DOMAIN = (
229
+ b"agent-evolve:adaptive-outcome-projector-definition:v2\x00"
230
+ )
231
+ _PHASE_RECEIPT_DOMAIN = (
232
+ b"agent-evolve:outcome-adaptive-phase-receipt:v1\x00"
233
+ )
234
+ _PHASE_ACK_DOMAIN = b"agent-evolve:outcome-adaptive-phase-ack:v1\x00"
235
+ _PAIRED_AUDIT_EXECUTION_DOMAIN = (
236
+ b"agent-evolve:outcome-adaptive-paired-audit-execution:v1\x00"
237
+ )
238
+ _RESULT_DOMAIN = b"agent-evolve:outcome-adaptive-result:v5\x00"
239
+ _PAIRED_AUDIT_RESULT_DOMAIN = (
240
+ b"agent-evolve:outcome-adaptive-result:v6\x00"
241
+ )
242
+ _FORECAST_OPPORTUNITY_RESULT_DOMAIN = (
243
+ b"agent-evolve:outcome-adaptive-result:v7\x00"
244
+ )
245
+ _FORECAST_SHADOW_RESULT_DOMAIN = (
246
+ b"agent-evolve:outcome-adaptive-result:v8\x00"
247
+ )
248
+ _FORECAST_STRATIFIED_AUDIT_RESULT_DOMAIN = (
249
+ b"agent-evolve:outcome-adaptive-result:v9\x00"
250
+ )
251
+
252
+
253
+ def _canonical_json(value: object) -> bytes:
254
+ return json.dumps(
255
+ value,
256
+ allow_nan=False,
257
+ ensure_ascii=True,
258
+ separators=(",", ":"),
259
+ sort_keys=True,
260
+ ).encode("ascii", errors="strict")
261
+
262
+
263
+ def _hash(domain: bytes, value: object) -> str:
264
+ return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
265
+
266
+
267
+ def _require_token(value: str, *, name: str) -> None:
268
+ if type(value) is not str or _TOKEN.fullmatch(value) is None:
269
+ raise ValueError(f"{name} must use the closed token grammar")
270
+
271
+
272
+ def _candidate_id_tuple(
273
+ values: tuple[CandidateId, ...],
274
+ ) -> tuple[str, ...]:
275
+ if type(values) is not tuple:
276
+ raise TypeError("current_run_parent_ids must be an exact tuple")
277
+ result: list[str] = []
278
+ for value in values:
279
+ if type(value) is not CandidateId:
280
+ raise TypeError("current_run_parent_ids must contain exact IDs")
281
+ CandidateId.__post_init__(value)
282
+ result.append(value.value)
283
+ if result != sorted(set(result)):
284
+ raise ValueError(
285
+ "current_run_parent_ids must be unique and canonical"
286
+ )
287
+ return tuple(result)
288
+
289
+
290
+ @dataclass(frozen=True, slots=True)
291
+ class AdaptiveActionSemanticView:
292
+ """Portable operator grouping and semantic cells for one action."""
293
+
294
+ operator_id: str
295
+ semantic_cell_ids: tuple[str, ...]
296
+
297
+ def __post_init__(self) -> None:
298
+ _require_token(self.operator_id, name="operator_id")
299
+ if (
300
+ type(self.semantic_cell_ids) is not tuple
301
+ or self.semantic_cell_ids
302
+ != tuple(sorted(set(self.semantic_cell_ids)))
303
+ ):
304
+ raise ValueError(
305
+ "semantic_cell_ids must be unique and canonical"
306
+ )
307
+ for value in self.semantic_cell_ids:
308
+ _require_token(value, name="semantic_cell_id")
309
+
310
+
311
+ @runtime_checkable
312
+ class AdaptiveActionSemanticViewPort(Protocol):
313
+ """Optional pre-evaluation semantic view; never sees candidate outcomes."""
314
+
315
+ projection_id: str
316
+ projection_version: int
317
+ definition_sha256: str
318
+
319
+ def view(
320
+ self,
321
+ action: MaterializedActionDescriptor,
322
+ ) -> AdaptiveActionSemanticView: ...
323
+
324
+
325
+ @dataclass(frozen=True, slots=True)
326
+ class PortableMaterializedAdaptiveSemanticView:
327
+ """Default view requiring no workload-specific integration."""
328
+
329
+ projection_id: str = PORTABLE_ADAPTIVE_SEMANTIC_VIEW_ID
330
+ projection_version: int = PORTABLE_ADAPTIVE_SEMANTIC_VIEW_VERSION
331
+ definition_sha256: str = (
332
+ PORTABLE_ADAPTIVE_SEMANTIC_VIEW_DEFINITION_SHA256
333
+ )
334
+
335
+ def view(
336
+ self,
337
+ action: MaterializedActionDescriptor,
338
+ ) -> AdaptiveActionSemanticView:
339
+ if type(action) is not MaterializedActionDescriptor:
340
+ raise TypeError("action must be exact")
341
+ action.__post_init__()
342
+ context = action.context
343
+ return AdaptiveActionSemanticView(
344
+ operator_id=action.operator_id,
345
+ semantic_cell_ids=tuple(
346
+ sorted(
347
+ {
348
+ f"role:{action.role_id}",
349
+ f"residual:{context.residual_frontier_cell}",
350
+ (
351
+ "parent_position:"
352
+ f"{context.parent_position_cell}"
353
+ ),
354
+ (
355
+ "archive_relation:"
356
+ f"{context.archive_relation_cell}"
357
+ ),
358
+ f"patch:{context.patch_compatibility_cell}",
359
+ (
360
+ "calibration:"
361
+ f"{context.forecast_calibration_cell}"
362
+ ),
363
+ f"phase:{context.phase.value}",
364
+ f"arity:{len(action.parent_ids)}",
365
+ f"reference:{int(action.reference_action)}",
366
+ (
367
+ "source_distance:"
368
+ f"{context.source_distance_bin}"
369
+ ),
370
+ f"memory_dose:{context.memory_dose_bin}",
371
+ "structure:"
372
+ + context.structural_signature_sha256[:16],
373
+ }
374
+ )
375
+ ),
376
+ )
377
+
378
+
379
+ @runtime_checkable
380
+ class AdaptiveActionMarketProjectorPort(Protocol):
381
+ """Project materialized actions into a portable outcome-blind market."""
382
+
383
+ projector_id: str
384
+ projector_version: int
385
+ definition_sha256: str
386
+ state_sha256: str
387
+
388
+ async def project(
389
+ self,
390
+ request: ResidualPortfolioDecisionRequest,
391
+ proposals: tuple[MaterializedActionProposalBatch, ...],
392
+ actions: tuple[MaterializedActionDescriptor, ...],
393
+ scores: tuple[BrokerActionScore, ...],
394
+ required_action_sha256s: tuple[str, ...],
395
+ ) -> tuple[AdaptiveActionDescriptor, ...]: ...
396
+
397
+
398
+ @dataclass(frozen=True, slots=True)
399
+ class PortableMaterializedAdaptiveMarketProjector:
400
+ """Default zero-workload-knowledge projection for adaptive racing."""
401
+
402
+ current_run_parent_ids: tuple[CandidateId, ...] = ()
403
+ semantic_view: AdaptiveActionSemanticViewPort = field(
404
+ default_factory=PortableMaterializedAdaptiveSemanticView,
405
+ repr=False,
406
+ compare=False,
407
+ )
408
+ projector_id: str = PORTABLE_ADAPTIVE_MARKET_PROJECTOR_ID
409
+ projector_version: int = PORTABLE_ADAPTIVE_MARKET_PROJECTOR_VERSION
410
+ definition_sha256: str = (
411
+ PORTABLE_ADAPTIVE_MARKET_PROJECTOR_DEFINITION_SHA256
412
+ )
413
+ state_sha256: str = field(init=False)
414
+
415
+ def __post_init__(self) -> None:
416
+ ids = _candidate_id_tuple(self.current_run_parent_ids)
417
+ if self.projector_id != PORTABLE_ADAPTIVE_MARKET_PROJECTOR_ID:
418
+ raise ValueError("projector_id is immutable")
419
+ if (
420
+ self.projector_version
421
+ != PORTABLE_ADAPTIVE_MARKET_PROJECTOR_VERSION
422
+ ):
423
+ raise ValueError("projector_version is immutable")
424
+ if (
425
+ self.definition_sha256
426
+ != PORTABLE_ADAPTIVE_MARKET_PROJECTOR_DEFINITION_SHA256
427
+ ):
428
+ raise ValueError("projector definition is immutable")
429
+ if not isinstance(
430
+ self.semantic_view,
431
+ AdaptiveActionSemanticViewPort,
432
+ ):
433
+ raise TypeError("semantic_view must implement its port")
434
+ _require_token(
435
+ self.semantic_view.projection_id,
436
+ name="semantic projection_id",
437
+ )
438
+ if (
439
+ type(self.semantic_view.projection_version) is not int
440
+ or self.semantic_view.projection_version <= 0
441
+ ):
442
+ raise ValueError("semantic projection_version must be positive")
443
+ require_sha256(
444
+ self.semantic_view.definition_sha256,
445
+ "semantic view definition",
446
+ )
447
+ object.__setattr__(
448
+ self,
449
+ "state_sha256",
450
+ _hash(
451
+ _MARKET_STATE_DOMAIN,
452
+ {
453
+ "schema_version": 1,
454
+ "current_run_parent_ids": list(ids),
455
+ "semantic_view_definition_sha256": (
456
+ self.semantic_view.definition_sha256
457
+ ),
458
+ },
459
+ ),
460
+ )
461
+
462
+ async def project(
463
+ self,
464
+ request: ResidualPortfolioDecisionRequest,
465
+ proposals: tuple[MaterializedActionProposalBatch, ...],
466
+ actions: tuple[MaterializedActionDescriptor, ...],
467
+ scores: tuple[BrokerActionScore, ...],
468
+ required_action_sha256s: tuple[str, ...],
469
+ ) -> tuple[AdaptiveActionDescriptor, ...]:
470
+ del request, proposals
471
+ self.__post_init__()
472
+ if type(actions) is not tuple or not actions:
473
+ raise ValueError("actions must be a non-empty exact tuple")
474
+ action_by_sha: dict[str, MaterializedActionDescriptor] = {}
475
+ for action in actions:
476
+ if type(action) is not MaterializedActionDescriptor:
477
+ raise TypeError("actions must contain exact descriptors")
478
+ action.__post_init__()
479
+ if action.action_sha256 in action_by_sha:
480
+ raise ValueError("actions repeat an identity")
481
+ action_by_sha[action.action_sha256] = action
482
+ if (
483
+ type(scores) is not tuple
484
+ or any(type(value) is not BrokerActionScore for value in scores)
485
+ ):
486
+ raise TypeError("scores must contain exact broker scores")
487
+ score_by_action = {value.action_sha256: value for value in scores}
488
+ for value in scores:
489
+ value.__post_init__()
490
+ if set(score_by_action) != set(action_by_sha):
491
+ raise ValueError("broker scores do not exactly cover actions")
492
+ if (
493
+ type(required_action_sha256s) is not tuple
494
+ or required_action_sha256s
495
+ != tuple(sorted(set(required_action_sha256s)))
496
+ or not set(required_action_sha256s).issubset(action_by_sha)
497
+ ):
498
+ raise ValueError(
499
+ "required action hashes must be canonical and in-market"
500
+ )
501
+ return self._project_with_prior(
502
+ actions=actions,
503
+ prior_score_by_action={
504
+ value.action_sha256: value.selection_index
505
+ for value in scores
506
+ },
507
+ required_action_sha256s=required_action_sha256s,
508
+ )
509
+
510
+ def _project_with_prior(
511
+ self,
512
+ *,
513
+ actions: tuple[MaterializedActionDescriptor, ...],
514
+ prior_score_by_action: dict[str, float],
515
+ required_action_sha256s: tuple[str, ...],
516
+ ) -> tuple[AdaptiveActionDescriptor, ...]:
517
+ action_by_sha = {
518
+ value.action_sha256: value for value in actions
519
+ }
520
+ if set(prior_score_by_action) != set(action_by_sha):
521
+ raise ValueError("prior scores do not exactly cover actions")
522
+ for value in prior_score_by_action.values():
523
+ if (
524
+ type(value) is not float
525
+ or not math.isfinite(value)
526
+ or not 0.0 <= value <= 1.0
527
+ ):
528
+ raise ValueError("prior scores must be finite probabilities")
529
+ required = set(required_action_sha256s)
530
+ by_phenotype: dict[str, list[MaterializedActionDescriptor]] = {}
531
+ for action in actions:
532
+ by_phenotype.setdefault(
533
+ action.phenotype_identity_sha256,
534
+ [],
535
+ ).append(action)
536
+ representatives: list[MaterializedActionDescriptor] = []
537
+ for rows in by_phenotype.values():
538
+ required_rows = [
539
+ value
540
+ for value in rows
541
+ if value.action_sha256 in required
542
+ ]
543
+ if len(required_rows) > 1:
544
+ raise ValueError(
545
+ "fixed constraints repeat one phenotype"
546
+ )
547
+ representatives.append(
548
+ (
549
+ required_rows[0]
550
+ if required_rows
551
+ else max(
552
+ rows,
553
+ key=lambda value: (
554
+ prior_score_by_action[
555
+ value.action_sha256
556
+ ],
557
+ -value.native_rank,
558
+ value.action_sha256,
559
+ ),
560
+ )
561
+ )
562
+ )
563
+ if not required.issubset(
564
+ {value.action_sha256 for value in representatives}
565
+ ):
566
+ raise ValueError(
567
+ "phenotype projection displaced a fixed constraint"
568
+ )
569
+ by_lane: dict[str, list[MaterializedActionDescriptor]] = {}
570
+ for action in representatives:
571
+ by_lane.setdefault(action.expert_id, []).append(action)
572
+ canonical_rank: dict[str, int] = {}
573
+ for rows in by_lane.values():
574
+ for ordinal, action in enumerate(
575
+ sorted(
576
+ rows,
577
+ key=lambda value: (
578
+ value.native_rank,
579
+ value.action_sha256,
580
+ ),
581
+ ),
582
+ start=1,
583
+ ):
584
+ canonical_rank[action.action_sha256] = ordinal
585
+ current_ids = set(self.current_run_parent_ids)
586
+ result: list[AdaptiveActionDescriptor] = []
587
+ for action in sorted(
588
+ representatives,
589
+ key=lambda value: value.action_sha256,
590
+ ):
591
+ semantic = self.semantic_view.view(action)
592
+ if type(semantic) is not AdaptiveActionSemanticView:
593
+ raise TypeError("semantic_view returned a foreign value")
594
+ semantic.__post_init__()
595
+ generated_parent = any(
596
+ value in current_ids for value in action.parent_ids
597
+ )
598
+ result.append(
599
+ AdaptiveActionDescriptor(
600
+ action_sha256=action.action_sha256,
601
+ phenotype_sha256=action.phenotype_identity_sha256,
602
+ lane_id=action.expert_id,
603
+ operator_id=semantic.operator_id,
604
+ native_rank=canonical_rank[action.action_sha256],
605
+ lane_size=len(by_lane[action.expert_id]),
606
+ prior_score=float(
607
+ prior_score_by_action[action.action_sha256]
608
+ ),
609
+ parent_generated_in_current_run=generated_parent,
610
+ semantic_cell_ids=tuple(
611
+ sorted(
612
+ {
613
+ *semantic.semantic_cell_ids,
614
+ (
615
+ "parent:generated"
616
+ if generated_parent
617
+ else "parent:archive"
618
+ ),
619
+ }
620
+ )
621
+ ),
622
+ )
623
+ )
624
+ return tuple(result)
625
+
626
+
627
+ @dataclass(frozen=True, slots=True)
628
+ class ScoreEnsembleMaterializedAdaptiveMarketProjector:
629
+ """Combine opaque pre-evaluation authorities by within-market rank."""
630
+
631
+ scorers: tuple[MaterializedActionScorePort, ...] = field(
632
+ repr=False,
633
+ compare=False,
634
+ )
635
+ scorer_weights: tuple[tuple[str, float], ...]
636
+ current_run_parent_ids: tuple[CandidateId, ...] = ()
637
+ semantic_view: AdaptiveActionSemanticViewPort = field(
638
+ default_factory=PortableMaterializedAdaptiveSemanticView,
639
+ repr=False,
640
+ compare=False,
641
+ )
642
+ projector_id: str = (
643
+ "score_ensemble_materialized_adaptive_market_projector"
644
+ )
645
+ projector_version: int = 1
646
+ definition_sha256: str = field(init=False)
647
+ state_sha256: str = field(init=False)
648
+
649
+ def __post_init__(self) -> None:
650
+ ids = _candidate_id_tuple(self.current_run_parent_ids)
651
+ if type(self.scorers) is not tuple or not self.scorers:
652
+ raise ValueError("scorers must be a non-empty exact tuple")
653
+ identities: list[tuple[str, int, str]] = []
654
+ for scorer in self.scorers:
655
+ if not isinstance(scorer, MaterializedActionScorePort):
656
+ raise TypeError("scorer must implement its port")
657
+ scorer_id = getattr(scorer, "scorer_id", None)
658
+ scorer_version = getattr(scorer, "scorer_version", None)
659
+ definition_sha256 = getattr(
660
+ scorer,
661
+ "definition_sha256",
662
+ None,
663
+ )
664
+ _require_token(scorer_id, name="scorer_id")
665
+ if type(scorer_version) is not int or scorer_version <= 0:
666
+ raise ValueError("scorer_version must be positive")
667
+ require_sha256(
668
+ definition_sha256,
669
+ "scorer definition_sha256",
670
+ )
671
+ identities.append(
672
+ (scorer_id, scorer_version, definition_sha256)
673
+ )
674
+ scorer_ids = tuple(value[0] for value in identities)
675
+ if scorer_ids != tuple(sorted(set(scorer_ids))):
676
+ raise ValueError("scorers must be unique and ID-canonical")
677
+ if (
678
+ type(self.scorer_weights) is not tuple
679
+ or tuple(value[0] for value in self.scorer_weights)
680
+ != scorer_ids
681
+ ):
682
+ raise ValueError("scorer_weights must exactly cover scorers")
683
+ total_weight = 0.0
684
+ for scorer_id, weight in self.scorer_weights:
685
+ _require_token(scorer_id, name="weight scorer_id")
686
+ if (
687
+ type(weight) is not float
688
+ or not math.isfinite(weight)
689
+ or weight <= 0.0
690
+ ):
691
+ raise ValueError("scorer weights must be positive")
692
+ total_weight += weight
693
+ if not isinstance(
694
+ self.semantic_view,
695
+ AdaptiveActionSemanticViewPort,
696
+ ):
697
+ raise TypeError("semantic_view must implement its port")
698
+ require_sha256(
699
+ self.semantic_view.definition_sha256,
700
+ "semantic view definition",
701
+ )
702
+ _require_token(self.projector_id, name="projector_id")
703
+ if type(self.projector_version) is not int or self.projector_version <= 0:
704
+ raise ValueError("projector_version must be positive")
705
+ object.__setattr__(
706
+ self,
707
+ "definition_sha256",
708
+ _hash(
709
+ _SCORE_ENSEMBLE_PROJECTOR_DEFINITION_DOMAIN,
710
+ {
711
+ "schema_version": 1,
712
+ "projector_id": self.projector_id,
713
+ "projector_version": self.projector_version,
714
+ "scorers": [
715
+ {
716
+ "scorer_id": scorer_id,
717
+ "scorer_version": scorer_version,
718
+ "definition_sha256": definition_sha256,
719
+ "weight_hex": dict(
720
+ self.scorer_weights
721
+ )[scorer_id].hex(),
722
+ }
723
+ for scorer_id, scorer_version, definition_sha256
724
+ in identities
725
+ ],
726
+ "normalization": (
727
+ "within-sealed-market-rank-percentile"
728
+ ),
729
+ "aggregation": "normalized-positive-weighted-mean",
730
+ "semantic_view_definition_sha256": (
731
+ self.semantic_view.definition_sha256
732
+ ),
733
+ "candidate_outcomes_observed": False,
734
+ "workload_model_provider_prompt_config_branches": False,
735
+ },
736
+ ),
737
+ )
738
+ object.__setattr__(
739
+ self,
740
+ "state_sha256",
741
+ _hash(
742
+ _MARKET_STATE_DOMAIN,
743
+ {
744
+ "schema_version": 1,
745
+ "projector_definition_sha256": (
746
+ self.definition_sha256
747
+ ),
748
+ "current_run_parent_ids": list(ids),
749
+ },
750
+ ),
751
+ )
752
+
753
+ @staticmethod
754
+ def _rank_percentiles(
755
+ actions: tuple[MaterializedActionDescriptor, ...],
756
+ values: dict[str, float],
757
+ ) -> dict[str, float]:
758
+ ordered = sorted(
759
+ actions,
760
+ key=lambda action: (
761
+ values[action.action_sha256],
762
+ -action.native_rank,
763
+ action.action_sha256,
764
+ ),
765
+ )
766
+ if len(ordered) == 1:
767
+ return {ordered[0].action_sha256: 1.0}
768
+ return {
769
+ action.action_sha256: index / (len(ordered) - 1)
770
+ for index, action in enumerate(ordered)
771
+ }
772
+
773
+ async def project(
774
+ self,
775
+ request: ResidualPortfolioDecisionRequest,
776
+ proposals: tuple[MaterializedActionProposalBatch, ...],
777
+ actions: tuple[MaterializedActionDescriptor, ...],
778
+ scores: tuple[BrokerActionScore, ...],
779
+ required_action_sha256s: tuple[str, ...],
780
+ ) -> tuple[AdaptiveActionDescriptor, ...]:
781
+ del scores
782
+ self.__post_init__()
783
+ raw = await asyncio.gather(
784
+ *(
785
+ scorer.score(request, proposals)
786
+ for scorer in self.scorers
787
+ )
788
+ )
789
+ batches = tuple(raw)
790
+ proposal_sha256s = tuple(
791
+ sorted(value.proposal_sha256 for value in proposals)
792
+ )
793
+ action_sha256s = {
794
+ value.action_sha256 for value in actions
795
+ }
796
+ percentiles: dict[str, dict[str, float]] = {}
797
+ for scorer, batch in zip(
798
+ self.scorers,
799
+ batches,
800
+ strict=True,
801
+ ):
802
+ if type(batch) is not MaterializedActionScoreBatch:
803
+ raise TypeError("scorer returned a foreign batch")
804
+ batch.__post_init__()
805
+ if (
806
+ batch.scorer_id != scorer.scorer_id
807
+ or batch.scorer_version != scorer.scorer_version
808
+ or batch.scorer_definition_sha256
809
+ != scorer.definition_sha256
810
+ or batch.residual_request_sha256
811
+ != request.request_sha256
812
+ or batch.proposal_sha256s != proposal_sha256s
813
+ ):
814
+ raise ValueError("score batch differs from its authority")
815
+ values = {
816
+ value.action_sha256: value.value
817
+ for value in batch.scores
818
+ }
819
+ if set(values) != action_sha256s:
820
+ raise ValueError("score batch does not cover the market")
821
+ percentiles[batch.scorer_id] = self._rank_percentiles(
822
+ actions,
823
+ values,
824
+ )
825
+ weights = dict(self.scorer_weights)
826
+ total_weight = math.fsum(weights.values())
827
+ combined = {
828
+ action.action_sha256: float(
829
+ math.fsum(
830
+ weights[scorer_id]
831
+ * percentiles[scorer_id][
832
+ action.action_sha256
833
+ ]
834
+ for scorer_id in weights
835
+ )
836
+ / total_weight
837
+ )
838
+ for action in actions
839
+ }
840
+ base = PortableMaterializedAdaptiveMarketProjector(
841
+ current_run_parent_ids=self.current_run_parent_ids,
842
+ semantic_view=self.semantic_view,
843
+ )
844
+ return base._project_with_prior(
845
+ actions=actions,
846
+ prior_score_by_action=combined,
847
+ required_action_sha256s=required_action_sha256s,
848
+ )
849
+
850
+
851
+ @dataclass(frozen=True, slots=True)
852
+ class FactorStratifiedAdaptiveMarketProjector:
853
+ """Add opaque branch/role/rank factor cells to any market projector.
854
+
855
+ The wrapper is an integration-layer adapter. It never parses expert IDs,
856
+ model names, prompts, configurations, objectives, or outcomes. A
857
+ composition root explicitly binds each proposal expert to an opaque source
858
+ branch; the remaining factors are framework-native action role and
859
+ materialized within-lane rank quantile.
860
+ """
861
+
862
+ delegate: AdaptiveActionMarketProjectorPort = field(
863
+ repr=False,
864
+ compare=False,
865
+ )
866
+ source_branch_by_expert: tuple[tuple[str, str], ...]
867
+ rank_layer_count: int = 3
868
+ projector_id: str = "factor_stratified_adaptive_market_projector"
869
+ projector_version: int = 1
870
+ definition_sha256: str = field(init=False)
871
+ state_sha256: str = field(init=False)
872
+
873
+ def __post_init__(self) -> None:
874
+ if not isinstance(self.delegate, AdaptiveActionMarketProjectorPort):
875
+ raise TypeError("delegate must implement the adaptive market port")
876
+ _require_token(self.delegate.projector_id, name="delegate projector_id")
877
+ if (
878
+ type(self.delegate.projector_version) is not int
879
+ or self.delegate.projector_version <= 0
880
+ ):
881
+ raise ValueError("delegate projector_version must be positive")
882
+ require_sha256(
883
+ self.delegate.definition_sha256,
884
+ "delegate definition_sha256",
885
+ )
886
+ require_sha256(self.delegate.state_sha256, "delegate state_sha256")
887
+ if (
888
+ type(self.source_branch_by_expert) is not tuple
889
+ or not self.source_branch_by_expert
890
+ or self.source_branch_by_expert
891
+ != tuple(sorted(self.source_branch_by_expert))
892
+ ):
893
+ raise ValueError(
894
+ "source_branch_by_expert must be non-empty and canonical"
895
+ )
896
+ experts: list[str] = []
897
+ for value in self.source_branch_by_expert:
898
+ if type(value) is not tuple or len(value) != 2:
899
+ raise TypeError(
900
+ "source_branch_by_expert must contain exact pairs"
901
+ )
902
+ expert_id, branch_id = value
903
+ _require_token(expert_id, name="source expert_id")
904
+ _require_token(branch_id, name="source branch_id")
905
+ experts.append(expert_id)
906
+ if len(experts) != len(set(experts)):
907
+ raise ValueError("source_branch_by_expert repeats an expert")
908
+ if (
909
+ type(self.rank_layer_count) is not int
910
+ or self.rank_layer_count < 2
911
+ or self.rank_layer_count > 16
912
+ ):
913
+ raise ValueError("rank_layer_count must be an integer in [2, 16]")
914
+ _require_token(self.projector_id, name="projector_id")
915
+ if self.projector_version != 1:
916
+ raise ValueError("projector_version is immutable")
917
+ object.__setattr__(
918
+ self,
919
+ "definition_sha256",
920
+ _hash(
921
+ _FACTOR_STRATIFIED_PROJECTOR_DEFINITION_DOMAIN,
922
+ {
923
+ "schema_version": 1,
924
+ "projector_id": self.projector_id,
925
+ "projector_version": self.projector_version,
926
+ "delegate_definition_sha256": (
927
+ self.delegate.definition_sha256
928
+ ),
929
+ "rank_layer_count": self.rank_layer_count,
930
+ "factor_families": [
931
+ "evolutionary_role",
932
+ "materialized_rank_layer",
933
+ "source_branch",
934
+ "source_branch_role",
935
+ ],
936
+ "source_branch_semantics": (
937
+ "opaque_explicit_composition_root_binding"
938
+ ),
939
+ "candidate_outcomes_observed": False,
940
+ "workload_objective_model_provider_prompt_config": False,
941
+ },
942
+ ),
943
+ )
944
+ object.__setattr__(
945
+ self,
946
+ "state_sha256",
947
+ _hash(
948
+ _MARKET_STATE_DOMAIN,
949
+ {
950
+ "schema_version": 2,
951
+ "projector_definition_sha256": self.definition_sha256,
952
+ "delegate_state_sha256": self.delegate.state_sha256,
953
+ "source_branch_by_expert": [
954
+ {
955
+ "expert_id": expert_id,
956
+ "source_branch_id": branch_id,
957
+ }
958
+ for expert_id, branch_id in (
959
+ self.source_branch_by_expert
960
+ )
961
+ ],
962
+ },
963
+ ),
964
+ )
965
+
966
+ async def project(
967
+ self,
968
+ request: ResidualPortfolioDecisionRequest,
969
+ proposals: tuple[MaterializedActionProposalBatch, ...],
970
+ actions: tuple[MaterializedActionDescriptor, ...],
971
+ scores: tuple[BrokerActionScore, ...],
972
+ required_action_sha256s: tuple[str, ...],
973
+ ) -> tuple[AdaptiveActionDescriptor, ...]:
974
+ self.__post_init__()
975
+ projected = await self.delegate.project(
976
+ request,
977
+ proposals,
978
+ actions,
979
+ scores,
980
+ required_action_sha256s,
981
+ )
982
+ action_by_sha = {
983
+ value.action_sha256: value for value in actions
984
+ }
985
+ if len(action_by_sha) != len(actions):
986
+ raise ValueError("materialized actions repeat an identity")
987
+ branch_by_expert = dict(self.source_branch_by_expert)
988
+ observed_experts = {value.lane_id for value in projected}
989
+ if not observed_experts.issubset(branch_by_expert):
990
+ raise ValueError(
991
+ "source branch binding must cover every projected expert"
992
+ )
993
+ result = []
994
+ for value in projected:
995
+ raw = action_by_sha.get(value.action_sha256)
996
+ if raw is None:
997
+ raise ValueError("projected action is absent materialized input")
998
+ branch_id = branch_by_expert[value.lane_id]
999
+ role_id = raw.role_id
1000
+ layer = min(
1001
+ self.rank_layer_count - 1,
1002
+ (
1003
+ (value.native_rank - 1) * self.rank_layer_count
1004
+ )
1005
+ // value.lane_size,
1006
+ )
1007
+ added = (
1008
+ AdaptiveActionFactorCell(
1009
+ family_id="evolutionary_role",
1010
+ level_id=role_id,
1011
+ ),
1012
+ AdaptiveActionFactorCell(
1013
+ family_id="materialized_rank_layer",
1014
+ level_id=f"layer{layer}",
1015
+ ),
1016
+ AdaptiveActionFactorCell(
1017
+ family_id="source_branch",
1018
+ level_id=branch_id,
1019
+ ),
1020
+ AdaptiveActionFactorCell(
1021
+ family_id="source_branch_role",
1022
+ level_id=(
1023
+ "cell:"
1024
+ + _hash(
1025
+ _FACTOR_STRATIFIED_PROJECTOR_DEFINITION_DOMAIN,
1026
+ {
1027
+ "source_branch_id": branch_id,
1028
+ "evolutionary_role_id": role_id,
1029
+ },
1030
+ )
1031
+ ),
1032
+ ),
1033
+ )
1034
+ combined = tuple(sorted((*value.factor_cells, *added)))
1035
+ if len({cell.family_id for cell in combined}) != len(combined):
1036
+ raise ValueError(
1037
+ "delegate and stratifier repeat a factor family"
1038
+ )
1039
+ result.append(
1040
+ AdaptiveActionDescriptor(
1041
+ action_sha256=value.action_sha256,
1042
+ phenotype_sha256=value.phenotype_sha256,
1043
+ lane_id=value.lane_id,
1044
+ operator_id=value.operator_id,
1045
+ native_rank=value.native_rank,
1046
+ lane_size=value.lane_size,
1047
+ prior_score=value.prior_score,
1048
+ parent_generated_in_current_run=(
1049
+ value.parent_generated_in_current_run
1050
+ ),
1051
+ semantic_cell_ids=value.semantic_cell_ids,
1052
+ factor_cells=combined,
1053
+ )
1054
+ )
1055
+ return tuple(result)
1056
+
1057
+
1058
+ @runtime_checkable
1059
+ class AdaptiveActionOutcomeProjectorPort(Protocol):
1060
+ """Project real candidate evaluations into portable archive gain."""
1061
+
1062
+ projector_id: str
1063
+ projector_version: int
1064
+ definition_sha256: str
1065
+
1066
+ def project(
1067
+ self,
1068
+ evaluations: tuple[MaterializedActionEvaluation, ...],
1069
+ ) -> tuple[AdaptiveActionOutcome, ...]: ...
1070
+
1071
+ def joint_gain(
1072
+ self,
1073
+ evaluations: tuple[MaterializedActionEvaluation, ...],
1074
+ ) -> float: ...
1075
+
1076
+ def project_set_outcome(
1077
+ self,
1078
+ prior_evaluations: tuple[MaterializedActionEvaluation, ...],
1079
+ evaluations: tuple[MaterializedActionEvaluation, ...],
1080
+ ) -> AdaptiveActionSetOutcome: ...
1081
+
1082
+
1083
+ @dataclass(frozen=True, slots=True)
1084
+ class CandidateArchiveAdaptiveActionOutcomeProjector:
1085
+ """Use an injected workload utility without exposing objective semantics."""
1086
+
1087
+ prior_candidates: tuple[EvolutionCandidate, ...]
1088
+ utility: CandidateArchivePortfolioConsequenceUtilityPort = field(
1089
+ repr=False,
1090
+ compare=False,
1091
+ )
1092
+ projector_id: str = CANDIDATE_ARCHIVE_ADAPTIVE_OUTCOME_PROJECTOR_ID
1093
+ projector_version: int = (
1094
+ CANDIDATE_ARCHIVE_ADAPTIVE_OUTCOME_PROJECTOR_VERSION
1095
+ )
1096
+ definition_sha256: str = field(init=False)
1097
+
1098
+ def __post_init__(self) -> None:
1099
+ if (
1100
+ type(self.prior_candidates) is not tuple
1101
+ or any(
1102
+ type(value) is not EvolutionCandidate
1103
+ for value in self.prior_candidates
1104
+ )
1105
+ ):
1106
+ raise TypeError("prior_candidates must be an exact tuple")
1107
+ for value in self.prior_candidates:
1108
+ value.__post_init__()
1109
+ utility_identity = (
1110
+ validate_candidate_archive_portfolio_consequence_utility(
1111
+ self.utility
1112
+ )
1113
+ )
1114
+ if (
1115
+ self.projector_id
1116
+ != CANDIDATE_ARCHIVE_ADAPTIVE_OUTCOME_PROJECTOR_ID
1117
+ ):
1118
+ raise ValueError("projector_id is immutable")
1119
+ if (
1120
+ self.projector_version
1121
+ != CANDIDATE_ARCHIVE_ADAPTIVE_OUTCOME_PROJECTOR_VERSION
1122
+ ):
1123
+ raise ValueError("projector_version is immutable")
1124
+ object.__setattr__(
1125
+ self,
1126
+ "definition_sha256",
1127
+ _hash(
1128
+ _OUTCOME_PROJECTOR_DEFINITION_DOMAIN,
1129
+ {
1130
+ "schema_version": 1,
1131
+ "projector_id": self.projector_id,
1132
+ "projector_version": self.projector_version,
1133
+ "utility": {
1134
+ "utility_id": utility_identity[0],
1135
+ "utility_version": utility_identity[1],
1136
+ "definition_sha256": utility_identity[2],
1137
+ },
1138
+ "prior_candidate_ids": [
1139
+ value.candidate_id.value
1140
+ for value in self.prior_candidates
1141
+ ],
1142
+ "admission": (
1143
+ "valid_and_operator_and_evidence_compliant"
1144
+ ),
1145
+ "currency": (
1146
+ "individual_fixed_joint_and_conditioned_set_utility"
1147
+ ),
1148
+ "set_observation_policy_role": "observational_only",
1149
+ },
1150
+ ),
1151
+ )
1152
+
1153
+ @staticmethod
1154
+ def _validate_evaluations(
1155
+ evaluations: tuple[MaterializedActionEvaluation, ...],
1156
+ *,
1157
+ allow_empty: bool = False,
1158
+ ) -> None:
1159
+ if (
1160
+ type(evaluations) is not tuple
1161
+ or (not allow_empty and not evaluations)
1162
+ or any(
1163
+ type(value) is not MaterializedActionEvaluation
1164
+ for value in evaluations
1165
+ )
1166
+ ):
1167
+ raise ValueError("evaluations must be a non-empty exact tuple")
1168
+ action_ids: list[str] = []
1169
+ for value in evaluations:
1170
+ value.__post_init__()
1171
+ action_ids.append(value.action.action_sha256)
1172
+ if len(action_ids) != len(set(action_ids)):
1173
+ raise ValueError("evaluations repeat an action")
1174
+
1175
+ @staticmethod
1176
+ def _feasible(evaluation: MaterializedActionEvaluation) -> bool:
1177
+ candidate = evaluation.candidate
1178
+ return bool(
1179
+ candidate.valid
1180
+ and candidate.operator_compliant
1181
+ and candidate.evidence_compliant
1182
+ )
1183
+
1184
+ @staticmethod
1185
+ def _bindings(
1186
+ evaluations: tuple[MaterializedActionEvaluation, ...],
1187
+ ) -> tuple[tuple[str, str], ...]:
1188
+ return tuple(
1189
+ sorted(
1190
+ (
1191
+ value.action.action_sha256,
1192
+ value.evaluation_sha256,
1193
+ )
1194
+ for value in evaluations
1195
+ )
1196
+ )
1197
+
1198
+ def _portfolio_gain(
1199
+ self,
1200
+ evaluations: tuple[MaterializedActionEvaluation, ...],
1201
+ ) -> float:
1202
+ self._validate_evaluations(evaluations, allow_empty=True)
1203
+ points = tuple(
1204
+ value.candidate.objective_map
1205
+ for value in sorted(
1206
+ evaluations,
1207
+ key=lambda item: item.action.action_sha256,
1208
+ )
1209
+ if self._feasible(value)
1210
+ )
1211
+ gain = (
1212
+ 0.0
1213
+ if not points
1214
+ else self.utility.portfolio_marginal_utility(
1215
+ self.prior_candidates,
1216
+ points,
1217
+ )
1218
+ )
1219
+ if (
1220
+ type(gain) is not float
1221
+ or not math.isfinite(gain)
1222
+ or gain < 0.0
1223
+ ):
1224
+ raise ValueError("archive utility returned invalid joint gain")
1225
+ return float(gain)
1226
+
1227
+ def project(
1228
+ self,
1229
+ evaluations: tuple[MaterializedActionEvaluation, ...],
1230
+ ) -> tuple[AdaptiveActionOutcome, ...]:
1231
+ self.__post_init__()
1232
+ self._validate_evaluations(evaluations)
1233
+ outcomes: list[AdaptiveActionOutcome] = []
1234
+ for evaluation in sorted(
1235
+ evaluations,
1236
+ key=lambda value: value.action.action_sha256,
1237
+ ):
1238
+ feasible = self._feasible(evaluation)
1239
+ gain = (
1240
+ 0.0
1241
+ if not feasible
1242
+ else self.utility.marginal_utility(
1243
+ self.prior_candidates,
1244
+ evaluation.candidate.objective_map,
1245
+ )
1246
+ )
1247
+ if (
1248
+ type(gain) is not float
1249
+ or not math.isfinite(gain)
1250
+ or gain < 0.0
1251
+ ):
1252
+ raise ValueError(
1253
+ "archive utility returned invalid individual gain"
1254
+ )
1255
+ outcomes.append(
1256
+ AdaptiveActionOutcome(
1257
+ action_sha256=evaluation.action.action_sha256,
1258
+ evaluation_sha256=evaluation.evaluation_sha256,
1259
+ feasible=feasible,
1260
+ marginal_archive_gain=float(gain),
1261
+ )
1262
+ )
1263
+ return tuple(outcomes)
1264
+
1265
+ def joint_gain(
1266
+ self,
1267
+ evaluations: tuple[MaterializedActionEvaluation, ...],
1268
+ ) -> float:
1269
+ self.__post_init__()
1270
+ self._validate_evaluations(evaluations)
1271
+ return self._portfolio_gain(evaluations)
1272
+
1273
+ def project_set_outcome(
1274
+ self,
1275
+ prior_evaluations: tuple[MaterializedActionEvaluation, ...],
1276
+ evaluations: tuple[MaterializedActionEvaluation, ...],
1277
+ ) -> AdaptiveActionSetOutcome:
1278
+ """Measure fixed opportunity and causal lift at one wave boundary."""
1279
+
1280
+ self.__post_init__()
1281
+ self._validate_evaluations(
1282
+ prior_evaluations,
1283
+ allow_empty=True,
1284
+ )
1285
+ self._validate_evaluations(evaluations)
1286
+ prior_actions = {
1287
+ value.action.action_sha256 for value in prior_evaluations
1288
+ }
1289
+ current_actions = {
1290
+ value.action.action_sha256 for value in evaluations
1291
+ }
1292
+ if prior_actions & current_actions:
1293
+ raise ValueError(
1294
+ "prior and current evaluations repeat an action"
1295
+ )
1296
+ prior_receipts = {
1297
+ value.evaluation_sha256 for value in prior_evaluations
1298
+ }
1299
+ current_receipts = {
1300
+ value.evaluation_sha256 for value in evaluations
1301
+ }
1302
+ if prior_receipts & current_receipts:
1303
+ raise ValueError(
1304
+ "prior and current evaluations repeat a receipt"
1305
+ )
1306
+ prior_gain = self._portfolio_gain(prior_evaluations)
1307
+ fixed_gain = self._portfolio_gain(evaluations)
1308
+ augmented = self._portfolio_gain(
1309
+ tuple(
1310
+ sorted(
1311
+ (*prior_evaluations, *evaluations),
1312
+ key=lambda value: value.action.action_sha256,
1313
+ )
1314
+ )
1315
+ )
1316
+ conditional = augmented - prior_gain
1317
+ numerical_tolerance = 1e-12 * max(
1318
+ 1.0,
1319
+ abs(prior_gain),
1320
+ abs(augmented),
1321
+ )
1322
+ if conditional < -numerical_tolerance:
1323
+ raise ValueError(
1324
+ "archive utility is non-monotone across selected sets"
1325
+ )
1326
+ if conditional < 0.0:
1327
+ conditional = 0.0
1328
+ return AdaptiveActionSetOutcome(
1329
+ prior_action_evaluation_bindings=self._bindings(
1330
+ prior_evaluations
1331
+ ),
1332
+ current_action_evaluation_bindings=self._bindings(
1333
+ evaluations
1334
+ ),
1335
+ prior_selected_set_gain=float(prior_gain),
1336
+ current_wave_fixed_set_gain=float(fixed_gain),
1337
+ augmented_selected_set_gain=float(augmented),
1338
+ conditional_set_gain=float(conditional),
1339
+ )
1340
+
1341
+
1342
+ class OutcomeAdaptiveResidualPhase(str, Enum):
1343
+ MARKET_FROZEN = "market_frozen"
1344
+ DIAGNOSTIC_EVALUATED = "diagnostic_evaluated"
1345
+ PAIRED_AUDIT_FROZEN = "paired_audit_frozen"
1346
+ ADAPTIVE_STEP_EVALUATED = "adaptive_step_evaluated"
1347
+ FINALIZED = "finalized"
1348
+
1349
+
1350
+ @dataclass(frozen=True, slots=True)
1351
+ class OutcomeAdaptiveResidualPhaseReceipt:
1352
+ """One causal interception boundary in an adaptive stage."""
1353
+
1354
+ phase: OutcomeAdaptiveResidualPhase
1355
+ phase_ordinal: int
1356
+ residual_request_sha256: str
1357
+ diagnostic_decision_sha256: str
1358
+ product_sha256s: tuple[str, ...]
1359
+ evidence: FrozenJsonObject
1360
+ receipt_sha256: str = field(init=False)
1361
+
1362
+ def __post_init__(self) -> None:
1363
+ if type(self.phase) is not OutcomeAdaptiveResidualPhase:
1364
+ raise TypeError("phase must be exact")
1365
+ if type(self.phase_ordinal) is not int or self.phase_ordinal <= 0:
1366
+ raise ValueError("phase_ordinal must be positive")
1367
+ require_sha256(
1368
+ self.residual_request_sha256,
1369
+ "residual_request_sha256",
1370
+ )
1371
+ require_sha256(
1372
+ self.diagnostic_decision_sha256,
1373
+ "diagnostic_decision_sha256",
1374
+ )
1375
+ if (
1376
+ type(self.product_sha256s) is not tuple
1377
+ or not self.product_sha256s
1378
+ ):
1379
+ raise ValueError("product_sha256s must be a non-empty tuple")
1380
+ for value in self.product_sha256s:
1381
+ require_sha256(value, "product_sha256")
1382
+ if (
1383
+ type(self.evidence) is not FrozenJsonObject
1384
+ or freeze_json(self.evidence) is not self.evidence
1385
+ ):
1386
+ raise TypeError("phase evidence must be an exact frozen object")
1387
+ object.__setattr__(
1388
+ self,
1389
+ "receipt_sha256",
1390
+ _hash(_PHASE_RECEIPT_DOMAIN, self._unsigned_record()),
1391
+ )
1392
+
1393
+ def _unsigned_record(self) -> dict[str, object]:
1394
+ return {
1395
+ "schema_version": 1,
1396
+ "phase": self.phase.value,
1397
+ "phase_ordinal": self.phase_ordinal,
1398
+ "residual_request_sha256": self.residual_request_sha256,
1399
+ "diagnostic_decision_sha256": (
1400
+ self.diagnostic_decision_sha256
1401
+ ),
1402
+ "product_sha256s": list(self.product_sha256s),
1403
+ "evidence_sha256": typed_json_sha256(self.evidence),
1404
+ }
1405
+
1406
+ def to_record(self, *, include_evidence: bool = False) -> dict[str, object]:
1407
+ self.__post_init__()
1408
+ record = {
1409
+ **self._unsigned_record(),
1410
+ "receipt_sha256": self.receipt_sha256,
1411
+ }
1412
+ if include_evidence:
1413
+ record["evidence"] = thaw_json(self.evidence)
1414
+ return record
1415
+
1416
+
1417
+ @dataclass(frozen=True, slots=True)
1418
+ class OutcomeAdaptiveResidualPhaseCommitAck:
1419
+ committer_id: str
1420
+ committer_version: int
1421
+ committer_definition_sha256: str
1422
+ phase_receipt_sha256: str
1423
+ durable: bool
1424
+ evidence: FrozenJsonObject
1425
+ ack_sha256: str = field(init=False)
1426
+
1427
+ def __post_init__(self) -> None:
1428
+ _require_token(self.committer_id, name="committer_id")
1429
+ if type(self.committer_version) is not int or self.committer_version <= 0:
1430
+ raise ValueError("committer_version must be positive")
1431
+ require_sha256(
1432
+ self.committer_definition_sha256,
1433
+ "committer_definition_sha256",
1434
+ )
1435
+ require_sha256(
1436
+ self.phase_receipt_sha256,
1437
+ "phase_receipt_sha256",
1438
+ )
1439
+ if type(self.durable) is not bool:
1440
+ raise TypeError("durable must be exact")
1441
+ if (
1442
+ type(self.evidence) is not FrozenJsonObject
1443
+ or freeze_json(self.evidence) is not self.evidence
1444
+ ):
1445
+ raise TypeError("commit evidence must be an exact frozen object")
1446
+ object.__setattr__(
1447
+ self,
1448
+ "ack_sha256",
1449
+ _hash(_PHASE_ACK_DOMAIN, self._unsigned_record()),
1450
+ )
1451
+
1452
+ def _unsigned_record(self) -> dict[str, object]:
1453
+ return {
1454
+ "schema_version": 1,
1455
+ "committer": {
1456
+ "committer_id": self.committer_id,
1457
+ "committer_version": self.committer_version,
1458
+ "definition_sha256": self.committer_definition_sha256,
1459
+ },
1460
+ "phase_receipt_sha256": self.phase_receipt_sha256,
1461
+ "durable": self.durable,
1462
+ "evidence_sha256": typed_json_sha256(self.evidence),
1463
+ }
1464
+
1465
+ def to_record(self, *, include_evidence: bool = False) -> dict[str, object]:
1466
+ self.__post_init__()
1467
+ record = {**self._unsigned_record(), "ack_sha256": self.ack_sha256}
1468
+ if include_evidence:
1469
+ record["evidence"] = thaw_json(self.evidence)
1470
+ return record
1471
+
1472
+
1473
+ @runtime_checkable
1474
+ class OutcomeAdaptiveResidualPhaseCommitPort(Protocol):
1475
+ committer_id: str
1476
+ committer_version: int
1477
+ definition_sha256: str
1478
+
1479
+ async def commit(
1480
+ self,
1481
+ receipt: OutcomeAdaptiveResidualPhaseReceipt,
1482
+ ) -> OutcomeAdaptiveResidualPhaseCommitAck: ...
1483
+
1484
+
1485
+ def _flatten(
1486
+ batches: tuple[MaterializedActionEvaluationBatch, ...],
1487
+ ) -> tuple[MaterializedActionEvaluation, ...]:
1488
+ by_action = {
1489
+ value.action.action_sha256: value
1490
+ for batch in batches
1491
+ for value in batch.evaluations
1492
+ }
1493
+ return tuple(by_action[value] for value in sorted(by_action))
1494
+
1495
+
1496
+ def _merge_waves(
1497
+ proposals: tuple[MaterializedActionProposalBatch, ...],
1498
+ waves: tuple[tuple[MaterializedActionEvaluationBatch, ...], ...],
1499
+ ) -> tuple[MaterializedActionEvaluationBatch, ...]:
1500
+ proposal_by_expert = {value.expert_id: value for value in proposals}
1501
+ source_by_expert: dict[str, list[MaterializedActionEvaluationBatch]] = {}
1502
+ for wave in waves:
1503
+ for batch in wave:
1504
+ source_by_expert.setdefault(batch.expert_id, []).append(batch)
1505
+ merged: list[MaterializedActionEvaluationBatch] = []
1506
+ for expert_id in sorted(source_by_expert):
1507
+ source = source_by_expert[expert_id]
1508
+ proposal = proposal_by_expert[expert_id]
1509
+ evaluations = tuple(
1510
+ sorted(
1511
+ (
1512
+ value
1513
+ for batch in source
1514
+ for value in batch.evaluations
1515
+ ),
1516
+ key=lambda value: value.action.action_sha256,
1517
+ )
1518
+ )
1519
+ action_ids = tuple(
1520
+ value.action.action_sha256 for value in evaluations
1521
+ )
1522
+ if len(action_ids) != len(set(action_ids)):
1523
+ raise ValueError("adaptive waves repeat an evaluation")
1524
+ merged.append(
1525
+ MaterializedActionEvaluationBatch(
1526
+ proposal_sha256=proposal.proposal_sha256,
1527
+ expert_id=proposal.expert_id,
1528
+ expert_version=proposal.expert_version,
1529
+ expert_definition_sha256=(
1530
+ proposal.expert_definition_sha256
1531
+ ),
1532
+ selected_action_sha256s=action_ids,
1533
+ evaluations=evaluations,
1534
+ evidence=freeze_json(
1535
+ {
1536
+ "adaptive_wave_batch_sha256s": [
1537
+ value.batch_sha256 for value in source
1538
+ ],
1539
+ "candidate_outcomes_reused": False,
1540
+ "disjoint_action_waves": True,
1541
+ }
1542
+ ),
1543
+ )
1544
+ )
1545
+ return tuple(merged)
1546
+
1547
+
1548
+ @dataclass(frozen=True, slots=True)
1549
+ class OutcomeAdaptivePairedAuditExecution:
1550
+ """One extra real arm excluded from the authoritative K-budget archive."""
1551
+
1552
+ plan: SamePrefixPairedAuditPlan
1553
+ observation: SamePrefixPairedAuditObservation
1554
+ counterfactual_evaluation_batches: tuple[
1555
+ MaterializedActionEvaluationBatch, ...
1556
+ ]
1557
+ plan_receipt_sha256: str
1558
+ execution_sha256: str = field(init=False)
1559
+
1560
+ def __post_init__(self) -> None:
1561
+ if type(self.plan) is not SamePrefixPairedAuditPlan:
1562
+ raise TypeError("plan must be exact")
1563
+ self.plan.__post_init__()
1564
+ if type(self.observation) is not SamePrefixPairedAuditObservation:
1565
+ raise TypeError("observation must be exact")
1566
+ self.observation.__post_init__()
1567
+ if self.observation.plan != self.plan:
1568
+ raise ValueError("paired audit observation changed its frozen plan")
1569
+ if (
1570
+ type(self.counterfactual_evaluation_batches) is not tuple
1571
+ or not self.counterfactual_evaluation_batches
1572
+ ):
1573
+ raise ValueError(
1574
+ "counterfactual_evaluation_batches must be non-empty"
1575
+ )
1576
+ evaluations: list[MaterializedActionEvaluation] = []
1577
+ for value in self.counterfactual_evaluation_batches:
1578
+ if type(value) is not MaterializedActionEvaluationBatch:
1579
+ raise TypeError(
1580
+ "counterfactual evaluation batches must be exact"
1581
+ )
1582
+ value.__post_init__()
1583
+ evaluations.extend(value.evaluations)
1584
+ if len(evaluations) != 1:
1585
+ raise ValueError("paired audit must buy exactly one extra action")
1586
+ expected_action_sha256 = (
1587
+ self.plan.exploration_action_sha256
1588
+ if self.plan.authoritative_arm
1589
+ is SamePrefixPairedAuditArm.LEGACY
1590
+ else self.plan.legacy_action_sha256
1591
+ )
1592
+ evaluation = evaluations[0]
1593
+ if evaluation.action.action_sha256 != expected_action_sha256:
1594
+ raise ValueError(
1595
+ "counterfactual evaluation differs from the unselected arm"
1596
+ )
1597
+ expected_outcome = (
1598
+ self.observation.exploration_outcome
1599
+ if self.plan.authoritative_arm
1600
+ is SamePrefixPairedAuditArm.LEGACY
1601
+ else self.observation.legacy_outcome
1602
+ )
1603
+ if expected_outcome.evaluation_sha256 != evaluation.evaluation_sha256:
1604
+ raise ValueError(
1605
+ "counterfactual outcome does not join its real evaluation"
1606
+ )
1607
+ require_sha256(
1608
+ self.plan_receipt_sha256,
1609
+ "plan_receipt_sha256",
1610
+ )
1611
+ object.__setattr__(
1612
+ self,
1613
+ "execution_sha256",
1614
+ _hash(
1615
+ _PAIRED_AUDIT_EXECUTION_DOMAIN,
1616
+ self._unsigned_record(),
1617
+ ),
1618
+ )
1619
+
1620
+ @property
1621
+ def counterfactual_action_sha256(self) -> str:
1622
+ if self.plan.authoritative_arm is SamePrefixPairedAuditArm.LEGACY:
1623
+ return self.plan.exploration_action_sha256
1624
+ return self.plan.legacy_action_sha256
1625
+
1626
+ def _unsigned_record(self) -> dict[str, object]:
1627
+ return {
1628
+ "schema_version": 1,
1629
+ "plan_sha256": self.plan.plan_sha256,
1630
+ "observation_sha256": self.observation.observation_sha256,
1631
+ "counterfactual_evaluation_batch_sha256s": [
1632
+ value.batch_sha256
1633
+ for value in self.counterfactual_evaluation_batches
1634
+ ],
1635
+ "counterfactual_action_sha256": (
1636
+ self.counterfactual_action_sha256
1637
+ ),
1638
+ "plan_receipt_sha256": self.plan_receipt_sha256,
1639
+ "physical_extra_real_evaluation_count": 1,
1640
+ "assay_union_admitted_to_authoritative_archive": False,
1641
+ }
1642
+
1643
+ def to_record(self, *, include_evidence: bool = False) -> dict[str, object]:
1644
+ self.__post_init__()
1645
+ return {
1646
+ **self._unsigned_record(),
1647
+ "plan": self.plan.to_record(include_evidence=include_evidence),
1648
+ "observation": self.observation.to_record(
1649
+ include_evidence=include_evidence
1650
+ ),
1651
+ "counterfactual_evaluation_batches": [
1652
+ value.to_record(include_evidence=include_evidence)
1653
+ for value in self.counterfactual_evaluation_batches
1654
+ ],
1655
+ "execution_sha256": self.execution_sha256,
1656
+ }
1657
+
1658
+
1659
+ @dataclass(frozen=True, slots=True)
1660
+ class OutcomeAdaptiveResidualPortfolioEvolutionResult:
1661
+ """Complete causal trace plus the standard downstream result."""
1662
+
1663
+ result: ResidualPortfolioEvolutionResult
1664
+ prior_broker_decision: MaterializedActionBrokerDecision
1665
+ adaptive_actions: tuple[AdaptiveActionDescriptor, ...]
1666
+ diagnostic_decision: AdaptiveActionRacingDecision
1667
+ continuation_decisions: tuple[AdaptiveActionRacingDecision, ...]
1668
+ evaluation_waves: tuple[
1669
+ tuple[MaterializedActionEvaluationBatch, ...], ...
1670
+ ]
1671
+ outcomes: tuple[AdaptiveActionOutcome, ...]
1672
+ set_outcomes: tuple[AdaptiveActionSetOutcome, ...]
1673
+ diagnostic_joint_gain: float
1674
+ allocation_directive: AdaptiveActionAllocationDirective
1675
+ phase_receipts: tuple[OutcomeAdaptiveResidualPhaseReceipt, ...]
1676
+ phase_commit_acks: tuple[
1677
+ OutcomeAdaptiveResidualPhaseCommitAck, ...
1678
+ ]
1679
+ market_projector_definition_sha256: str
1680
+ market_projector_state_sha256: str
1681
+ outcome_projector_definition_sha256: str
1682
+ forecast_opportunity_challenger_definition_sha256: str | None = None
1683
+ paired_audit_executions: tuple[
1684
+ OutcomeAdaptivePairedAuditExecution, ...
1685
+ ] = ()
1686
+ forecast_opportunity_calibration_observations: tuple[
1687
+ ArchiveOpportunityCalibrationObservation, ...
1688
+ ] = ()
1689
+ method_definition_sha256: str = (
1690
+ OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_DEFINITION_SHA256
1691
+ )
1692
+ adaptive_result_sha256: str = field(init=False)
1693
+
1694
+ def __post_init__(self) -> None:
1695
+ if type(self.result) is not ResidualPortfolioEvolutionResult:
1696
+ raise TypeError("result must be exact")
1697
+ self.result.__post_init__()
1698
+ if (
1699
+ type(self.prior_broker_decision)
1700
+ is not MaterializedActionBrokerDecision
1701
+ ):
1702
+ raise TypeError("prior_broker_decision must be exact")
1703
+ self.prior_broker_decision.__post_init__()
1704
+ if (
1705
+ type(self.adaptive_actions) is not tuple
1706
+ or not self.adaptive_actions
1707
+ ):
1708
+ raise ValueError("adaptive_actions must be non-empty")
1709
+ action_by_sha: dict[str, AdaptiveActionDescriptor] = {}
1710
+ for value in self.adaptive_actions:
1711
+ if type(value) is not AdaptiveActionDescriptor:
1712
+ raise TypeError("adaptive_actions must be exact")
1713
+ value.__post_init__()
1714
+ action_by_sha[value.action_sha256] = value
1715
+ if len(action_by_sha) != len(self.adaptive_actions):
1716
+ raise ValueError("adaptive_actions repeat an identity")
1717
+ if type(self.diagnostic_decision) is not AdaptiveActionRacingDecision:
1718
+ raise TypeError("diagnostic_decision must be exact")
1719
+ self.diagnostic_decision.__post_init__()
1720
+ if self.diagnostic_decision.wave is not AdaptiveActionWave.DIAGNOSTIC:
1721
+ raise ValueError("first decision must be diagnostic")
1722
+ if type(self.continuation_decisions) is not tuple:
1723
+ raise TypeError("continuation_decisions must be a tuple")
1724
+ for value in self.continuation_decisions:
1725
+ if type(value) is not AdaptiveActionRacingDecision:
1726
+ raise TypeError("continuation decisions must be exact")
1727
+ value.__post_init__()
1728
+ if value.wave is AdaptiveActionWave.DIAGNOSTIC:
1729
+ raise ValueError("continuation cannot be diagnostic")
1730
+ if (
1731
+ type(self.evaluation_waves) is not tuple
1732
+ or len(self.evaluation_waves)
1733
+ != 1 + len(self.continuation_decisions)
1734
+ ):
1735
+ raise ValueError(
1736
+ "evaluation waves must cover diagnostic and continuations"
1737
+ )
1738
+ evaluation_by_action: dict[str, MaterializedActionEvaluation] = {}
1739
+ for wave in self.evaluation_waves:
1740
+ if type(wave) is not tuple or not wave:
1741
+ raise ValueError("each evaluation wave must be non-empty")
1742
+ for batch in wave:
1743
+ if type(batch) is not MaterializedActionEvaluationBatch:
1744
+ raise TypeError("evaluation waves must contain exact batches")
1745
+ batch.__post_init__()
1746
+ for evaluation in batch.evaluations:
1747
+ action_sha = evaluation.action.action_sha256
1748
+ if action_sha in evaluation_by_action:
1749
+ raise ValueError("evaluation waves repeat an action")
1750
+ evaluation_by_action[action_sha] = evaluation
1751
+ if type(self.outcomes) is not tuple:
1752
+ raise TypeError("outcomes must be a tuple")
1753
+ outcome_by_action: dict[str, AdaptiveActionOutcome] = {}
1754
+ for value in self.outcomes:
1755
+ if type(value) is not AdaptiveActionOutcome:
1756
+ raise TypeError("outcomes must be exact")
1757
+ value.__post_init__()
1758
+ if value.action_sha256 in outcome_by_action:
1759
+ raise ValueError("outcomes repeat an action")
1760
+ evaluation = evaluation_by_action.get(value.action_sha256)
1761
+ if (
1762
+ evaluation is None
1763
+ or value.evaluation_sha256
1764
+ != evaluation.evaluation_sha256
1765
+ ):
1766
+ raise ValueError("outcome does not join its real evaluation")
1767
+ outcome_by_action[value.action_sha256] = value
1768
+ if (
1769
+ type(self.set_outcomes) is not tuple
1770
+ or len(self.set_outcomes) != len(self.evaluation_waves)
1771
+ ):
1772
+ raise ValueError(
1773
+ "set outcomes must cover every causal evaluation wave"
1774
+ )
1775
+ for value in self.set_outcomes:
1776
+ if type(value) is not AdaptiveActionSetOutcome:
1777
+ raise TypeError("set outcomes must be exact")
1778
+ value.__post_init__()
1779
+ selected = set(self.diagnostic_decision.selected_action_sha256s)
1780
+ diagnostic_evaluated = {
1781
+ value.action.action_sha256
1782
+ for value in _flatten(self.evaluation_waves[0])
1783
+ }
1784
+ if diagnostic_evaluated != selected:
1785
+ raise ValueError("diagnostic evaluations differ from decision")
1786
+ if not selected.issubset(outcome_by_action):
1787
+ raise ValueError("diagnostic outcomes are incomplete")
1788
+ for ordinal, decision in enumerate(
1789
+ self.continuation_decisions,
1790
+ start=1,
1791
+ ):
1792
+ if decision.prior_selected_action_sha256s != tuple(
1793
+ sorted(selected)
1794
+ ):
1795
+ raise ValueError("continuation decision skips causal prefix")
1796
+ expected_outcomes = tuple(
1797
+ sorted(
1798
+ outcome_by_action[value].outcome_sha256
1799
+ for value in selected
1800
+ )
1801
+ )
1802
+ if decision.observed_outcome_sha256s != expected_outcomes:
1803
+ raise ValueError(
1804
+ "continuation decision observed a foreign outcome cutoff"
1805
+ )
1806
+ expected_set_outcomes = tuple(
1807
+ sorted(
1808
+ value.set_outcome_sha256
1809
+ for value in self.set_outcomes[:ordinal]
1810
+ )
1811
+ )
1812
+ if (
1813
+ decision.observed_set_outcome_sha256s
1814
+ != expected_set_outcomes
1815
+ ):
1816
+ raise ValueError(
1817
+ "continuation decision observed a foreign set cutoff"
1818
+ )
1819
+ evaluated = {
1820
+ value.action.action_sha256
1821
+ for value in _flatten(self.evaluation_waves[ordinal])
1822
+ }
1823
+ if evaluated != set(decision.selected_action_sha256s):
1824
+ raise ValueError("continuation wave differs from decision")
1825
+ selected.update(decision.selected_action_sha256s)
1826
+ if selected != set(outcome_by_action):
1827
+ raise ValueError("outcome set differs from selected causal chain")
1828
+ if type(self.paired_audit_executions) is not tuple:
1829
+ raise TypeError("paired_audit_executions must be a tuple")
1830
+ if self.forecast_opportunity_challenger_definition_sha256 is not None:
1831
+ require_sha256(
1832
+ self.forecast_opportunity_challenger_definition_sha256,
1833
+ "forecast_opportunity_challenger_definition_sha256",
1834
+ )
1835
+ continuation_by_sha256 = {
1836
+ value.decision_sha256: value
1837
+ for value in self.continuation_decisions
1838
+ }
1839
+ paired_execution_by_decision: dict[
1840
+ str, OutcomeAdaptivePairedAuditExecution
1841
+ ] = {}
1842
+ for value in self.paired_audit_executions:
1843
+ if type(value) is not OutcomeAdaptivePairedAuditExecution:
1844
+ raise TypeError("paired audit executions must be exact")
1845
+ value.__post_init__()
1846
+ decision_sha256 = value.plan.racing_decision_sha256
1847
+ if decision_sha256 in paired_execution_by_decision:
1848
+ raise ValueError(
1849
+ "paired audit executions repeat a racing decision"
1850
+ )
1851
+ decision = continuation_by_sha256.get(decision_sha256)
1852
+ is_forecast_audit = (
1853
+ value.plan.designer_id
1854
+ in FORECAST_OPPORTUNITY_SAME_PREFIX_AUDIT_DESIGNER_IDS
1855
+ )
1856
+ if (
1857
+ decision is None
1858
+ or (
1859
+ not is_forecast_audit
1860
+ and decision.wave
1861
+ is not AdaptiveActionWave.RANDOMIZED_AUDIT
1862
+ )
1863
+ or decision.selected_action_sha256s
1864
+ != (value.plan.authoritative_action_sha256,)
1865
+ or decision.prior_selected_action_sha256s
1866
+ != value.plan.common_prefix_action_sha256s
1867
+ ):
1868
+ raise ValueError(
1869
+ "paired audit execution does not join its racing decision"
1870
+ )
1871
+ if is_forecast_audit != (
1872
+ self.forecast_opportunity_challenger_definition_sha256
1873
+ is not None
1874
+ ):
1875
+ raise ValueError(
1876
+ "paired assay role differs from the method execution mode"
1877
+ )
1878
+ authoritative_evaluation = evaluation_by_action.get(
1879
+ value.plan.authoritative_action_sha256
1880
+ )
1881
+ authoritative_outcome = (
1882
+ value.observation.legacy_outcome
1883
+ if value.plan.authoritative_arm
1884
+ is SamePrefixPairedAuditArm.LEGACY
1885
+ else value.observation.exploration_outcome
1886
+ )
1887
+ if (
1888
+ authoritative_evaluation is None
1889
+ or authoritative_outcome.evaluation_sha256
1890
+ != authoritative_evaluation.evaluation_sha256
1891
+ ):
1892
+ raise ValueError(
1893
+ "paired audit authoritative arm is not the selected "
1894
+ "real evaluation"
1895
+ )
1896
+ if value.counterfactual_action_sha256 in evaluation_by_action:
1897
+ raise ValueError(
1898
+ "paired audit counterfactual entered the authoritative "
1899
+ "evaluation waves"
1900
+ )
1901
+ paired_execution_by_decision[decision_sha256] = value
1902
+ if (
1903
+ type(self.forecast_opportunity_calibration_observations)
1904
+ is not tuple
1905
+ ):
1906
+ raise TypeError(
1907
+ "forecast opportunity calibration observations must be a tuple"
1908
+ )
1909
+ expected_calibration_observations: list[
1910
+ ArchiveOpportunityCalibrationObservation
1911
+ ] = []
1912
+ calibration_projector = (
1913
+ ForecastOpportunityShadowCalibrationProjector()
1914
+ )
1915
+ for execution in self.paired_audit_executions:
1916
+ if (
1917
+ execution.plan.designer_id
1918
+ not in FORECAST_OPPORTUNITY_SAME_PREFIX_AUDIT_DESIGNER_IDS
1919
+ ):
1920
+ continue
1921
+ decision = continuation_by_sha256[
1922
+ execution.plan.racing_decision_sha256
1923
+ ]
1924
+ expected_calibration_observations.append(
1925
+ calibration_projector.project(
1926
+ decision_index=self.result.request.decision_index,
1927
+ evidence_cutoff_ordinal=(
1928
+ self.result.request.decision_index
1929
+ ),
1930
+ decision=decision,
1931
+ action=action_by_sha[
1932
+ execution.plan.exploration_action_sha256
1933
+ ],
1934
+ observation=execution.observation,
1935
+ )
1936
+ )
1937
+ for value in self.forecast_opportunity_calibration_observations:
1938
+ if type(value) is not ArchiveOpportunityCalibrationObservation:
1939
+ raise TypeError(
1940
+ "forecast opportunity calibration observations must "
1941
+ "be exact"
1942
+ )
1943
+ value.__post_init__()
1944
+ if self.forecast_opportunity_calibration_observations != tuple(
1945
+ expected_calibration_observations
1946
+ ):
1947
+ raise ValueError(
1948
+ "forecast calibration observations do not close shadow assays"
1949
+ )
1950
+ prior_bindings: list[tuple[str, str]] = []
1951
+ prior_augmented_gain = 0.0
1952
+ for ordinal, (wave, set_outcome) in enumerate(
1953
+ zip(self.evaluation_waves, self.set_outcomes, strict=True)
1954
+ ):
1955
+ expected_current_bindings = tuple(
1956
+ sorted(
1957
+ (
1958
+ value.action.action_sha256,
1959
+ value.evaluation_sha256,
1960
+ )
1961
+ for value in _flatten(wave)
1962
+ )
1963
+ )
1964
+ if (
1965
+ set_outcome.prior_action_evaluation_bindings
1966
+ != tuple(sorted(prior_bindings))
1967
+ or set_outcome.current_action_evaluation_bindings
1968
+ != expected_current_bindings
1969
+ ):
1970
+ raise ValueError(
1971
+ "set outcome does not join its causal evaluation prefix"
1972
+ )
1973
+ if not math.isclose(
1974
+ set_outcome.prior_selected_set_gain,
1975
+ prior_augmented_gain,
1976
+ rel_tol=1e-12,
1977
+ abs_tol=1e-15,
1978
+ ):
1979
+ raise ValueError(
1980
+ "set outcome utility chain is not causally contiguous"
1981
+ )
1982
+ if ordinal == 0 and (
1983
+ set_outcome.prior_action_evaluation_bindings
1984
+ or not math.isclose(
1985
+ set_outcome.conditional_set_gain,
1986
+ set_outcome.current_wave_fixed_set_gain,
1987
+ rel_tol=1e-12,
1988
+ abs_tol=1e-15,
1989
+ )
1990
+ ):
1991
+ raise ValueError(
1992
+ "diagnostic set outcome must start from an empty prefix"
1993
+ )
1994
+ prior_bindings.extend(expected_current_bindings)
1995
+ prior_augmented_gain = (
1996
+ set_outcome.augmented_selected_set_gain
1997
+ )
1998
+ if (
1999
+ type(self.diagnostic_joint_gain) is not float
2000
+ or not math.isfinite(self.diagnostic_joint_gain)
2001
+ or self.diagnostic_joint_gain < 0.0
2002
+ ):
2003
+ raise ValueError("diagnostic_joint_gain must be non-negative")
2004
+ if not math.isclose(
2005
+ self.diagnostic_joint_gain,
2006
+ self.set_outcomes[0].current_wave_fixed_set_gain,
2007
+ rel_tol=1e-12,
2008
+ abs_tol=1e-15,
2009
+ ):
2010
+ raise ValueError(
2011
+ "diagnostic joint gain differs from its set observation"
2012
+ )
2013
+ if (
2014
+ type(self.allocation_directive)
2015
+ is not AdaptiveActionAllocationDirective
2016
+ ):
2017
+ raise TypeError("allocation_directive must be exact")
2018
+ self.allocation_directive.__post_init__()
2019
+ if (
2020
+ self.allocation_directive.diagnostic_decision_sha256
2021
+ != self.diagnostic_decision.decision_sha256
2022
+ or self.allocation_directive.continuation_decision_sha256s
2023
+ != tuple(
2024
+ sorted(
2025
+ value.decision_sha256
2026
+ for value in self.continuation_decisions
2027
+ )
2028
+ )
2029
+ or self.allocation_directive.observed_outcome_sha256s
2030
+ != tuple(
2031
+ sorted(value.outcome_sha256 for value in self.outcomes)
2032
+ )
2033
+ or self.allocation_directive.observed_set_outcome_sha256s
2034
+ != tuple(
2035
+ sorted(
2036
+ value.set_outcome_sha256
2037
+ for value in self.set_outcomes
2038
+ )
2039
+ )
2040
+ or set(self.allocation_directive.required_action_sha256s)
2041
+ != selected
2042
+ ):
2043
+ raise ValueError("allocation directive does not close causal trace")
2044
+ if self.forecast_opportunity_challenger_definition_sha256 is not None:
2045
+ if (
2046
+ self.allocation_directive.policy_definition_sha256
2047
+ != self.forecast_opportunity_challenger_definition_sha256
2048
+ or any(
2049
+ value.policy_definition_sha256
2050
+ != self.forecast_opportunity_challenger_definition_sha256
2051
+ for value in self.continuation_decisions
2052
+ )
2053
+ ):
2054
+ raise ValueError(
2055
+ "forecast challenger identity does not cover every "
2056
+ "continuation"
2057
+ )
2058
+ if (
2059
+ self.result.broker_decision.allocation_requirement
2060
+ != self.allocation_directive
2061
+ or {
2062
+ value.action_sha256
2063
+ for value in self.result.broker_decision.selected_actions
2064
+ }
2065
+ != selected
2066
+ ):
2067
+ raise ValueError("final broker result differs from directive")
2068
+ if (
2069
+ type(self.phase_receipts) is not tuple
2070
+ or len(self.phase_receipts)
2071
+ != (
2072
+ 3
2073
+ + len(self.continuation_decisions)
2074
+ + len(self.paired_audit_executions)
2075
+ )
2076
+ ):
2077
+ raise ValueError("phase receipts do not cover causal execution")
2078
+ expected_phase_values = [
2079
+ OutcomeAdaptiveResidualPhase.MARKET_FROZEN,
2080
+ OutcomeAdaptiveResidualPhase.DIAGNOSTIC_EVALUATED,
2081
+ ]
2082
+ for decision in self.continuation_decisions:
2083
+ if decision.decision_sha256 in paired_execution_by_decision:
2084
+ expected_phase_values.append(
2085
+ OutcomeAdaptiveResidualPhase.PAIRED_AUDIT_FROZEN
2086
+ )
2087
+ expected_phase_values.append(
2088
+ OutcomeAdaptiveResidualPhase.ADAPTIVE_STEP_EVALUATED
2089
+ )
2090
+ expected_phase_values.append(
2091
+ OutcomeAdaptiveResidualPhase.FINALIZED
2092
+ )
2093
+ expected_phases = tuple(expected_phase_values)
2094
+ if tuple(value.phase for value in self.phase_receipts) != expected_phases:
2095
+ raise ValueError("phase receipts are out of causal order")
2096
+ if tuple(
2097
+ value.phase_ordinal for value in self.phase_receipts
2098
+ ) != tuple(range(1, len(self.phase_receipts) + 1)):
2099
+ raise ValueError("phase receipt ordinals are not contiguous")
2100
+ for value in self.phase_receipts:
2101
+ value.__post_init__()
2102
+ if (
2103
+ value.residual_request_sha256
2104
+ != self.result.request.request_sha256
2105
+ or value.diagnostic_decision_sha256
2106
+ != self.diagnostic_decision.decision_sha256
2107
+ ):
2108
+ raise ValueError("phase receipt names another execution")
2109
+ receipt_by_sha256 = {
2110
+ value.receipt_sha256: value for value in self.phase_receipts
2111
+ }
2112
+ for execution in self.paired_audit_executions:
2113
+ receipt = receipt_by_sha256.get(execution.plan_receipt_sha256)
2114
+ if (
2115
+ receipt is None
2116
+ or receipt.phase
2117
+ is not OutcomeAdaptiveResidualPhase.PAIRED_AUDIT_FROZEN
2118
+ or thaw_json(receipt.evidence).get("plan_sha256")
2119
+ != execution.plan.plan_sha256
2120
+ ):
2121
+ raise ValueError(
2122
+ "paired audit plan lacks its pre-evaluation freeze receipt"
2123
+ )
2124
+ if type(self.phase_commit_acks) is not tuple:
2125
+ raise TypeError("phase_commit_acks must be a tuple")
2126
+ for value in self.phase_commit_acks:
2127
+ value.__post_init__()
2128
+ if self.phase_commit_acks and tuple(
2129
+ value.phase_receipt_sha256
2130
+ for value in self.phase_commit_acks
2131
+ ) != tuple(
2132
+ value.receipt_sha256 for value in self.phase_receipts
2133
+ ):
2134
+ raise ValueError("phase commit acknowledgements do not close")
2135
+ for name in (
2136
+ "market_projector_definition_sha256",
2137
+ "market_projector_state_sha256",
2138
+ "outcome_projector_definition_sha256",
2139
+ "method_definition_sha256",
2140
+ ):
2141
+ require_sha256(getattr(self, name), name)
2142
+ has_forecast = (
2143
+ self.forecast_opportunity_challenger_definition_sha256
2144
+ is not None
2145
+ )
2146
+ has_paired_assay = bool(self.paired_audit_executions)
2147
+ has_forecast_stratified_audit = any(
2148
+ value.plan.designer_id
2149
+ == FORECAST_STRATIFIED_SAME_PREFIX_AUDIT_DESIGNER_ID
2150
+ for value in self.paired_audit_executions
2151
+ )
2152
+ expected_method_definition_sha256 = (
2153
+ OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_STRATIFIED_AUDIT_EVOLUTION_DEFINITION_SHA256
2154
+ if has_forecast_stratified_audit
2155
+ else (
2156
+ OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_SHADOW_EVOLUTION_DEFINITION_SHA256
2157
+ if has_forecast and has_paired_assay
2158
+ else (
2159
+ _FORECAST_OPPORTUNITY_DEFINITION_SHA256
2160
+ if has_forecast
2161
+ else (
2162
+ _PAIRED_AUDIT_DEFINITION_SHA256
2163
+ if has_paired_assay
2164
+ else OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_DEFINITION_SHA256
2165
+ )
2166
+ )
2167
+ )
2168
+ )
2169
+ if (
2170
+ self.method_definition_sha256
2171
+ != expected_method_definition_sha256
2172
+ ):
2173
+ raise ValueError(
2174
+ "method definition does not match paired-audit execution mode"
2175
+ )
2176
+ object.__setattr__(
2177
+ self,
2178
+ "adaptive_result_sha256",
2179
+ _hash(
2180
+ (
2181
+ _FORECAST_STRATIFIED_AUDIT_RESULT_DOMAIN
2182
+ if has_forecast_stratified_audit
2183
+ else (
2184
+ _FORECAST_SHADOW_RESULT_DOMAIN
2185
+ if has_forecast and has_paired_assay
2186
+ else (
2187
+ _FORECAST_OPPORTUNITY_RESULT_DOMAIN
2188
+ if has_forecast
2189
+ else (
2190
+ _PAIRED_AUDIT_RESULT_DOMAIN
2191
+ if has_paired_assay
2192
+ else _RESULT_DOMAIN
2193
+ )
2194
+ )
2195
+ )
2196
+ ),
2197
+ self._unsigned_record(),
2198
+ ),
2199
+ )
2200
+
2201
+ def _unsigned_record(self) -> dict[str, object]:
2202
+ has_forecast = (
2203
+ self.forecast_opportunity_challenger_definition_sha256
2204
+ is not None
2205
+ )
2206
+ has_paired_assay = bool(self.paired_audit_executions)
2207
+ has_forecast_stratified_audit = any(
2208
+ value.plan.designer_id
2209
+ == FORECAST_STRATIFIED_SAME_PREFIX_AUDIT_DESIGNER_ID
2210
+ for value in self.paired_audit_executions
2211
+ )
2212
+ record: dict[str, object] = {
2213
+ "schema_version": (
2214
+ 8
2215
+ if has_forecast_stratified_audit
2216
+ else (
2217
+ 7
2218
+ if has_forecast and has_paired_assay
2219
+ else (
2220
+ 6
2221
+ if has_forecast
2222
+ else (5 if has_paired_assay else 4)
2223
+ )
2224
+ )
2225
+ ),
2226
+ "method": {
2227
+ "method_id": OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_ID,
2228
+ "method_version": (
2229
+ OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_STRATIFIED_AUDIT_EVOLUTION_VERSION
2230
+ if has_forecast_stratified_audit
2231
+ else (
2232
+ OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_SHADOW_EVOLUTION_VERSION
2233
+ if has_forecast and has_paired_assay
2234
+ else (
2235
+ OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_OPPORTUNITY_EVOLUTION_VERSION
2236
+ if has_forecast
2237
+ else (
2238
+ OUTCOME_ADAPTIVE_RESIDUAL_PAIRED_AUDIT_EVOLUTION_VERSION
2239
+ if has_paired_assay
2240
+ else OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_VERSION
2241
+ )
2242
+ )
2243
+ )
2244
+ ),
2245
+ "definition_sha256": self.method_definition_sha256,
2246
+ },
2247
+ "combined_result_sha256": self.result.result_sha256,
2248
+ "prior_broker_decision_sha256": (
2249
+ self.prior_broker_decision.decision_sha256
2250
+ ),
2251
+ "adaptive_action_sha256s": [
2252
+ value.action_sha256 for value in self.adaptive_actions
2253
+ ],
2254
+ "diagnostic_decision_sha256": (
2255
+ self.diagnostic_decision.decision_sha256
2256
+ ),
2257
+ "continuation_decision_sha256s": [
2258
+ value.decision_sha256
2259
+ for value in self.continuation_decisions
2260
+ ],
2261
+ "evaluation_wave_batch_sha256s": [
2262
+ [value.batch_sha256 for value in wave]
2263
+ for wave in self.evaluation_waves
2264
+ ],
2265
+ "outcome_sha256s": [
2266
+ value.outcome_sha256 for value in self.outcomes
2267
+ ],
2268
+ "set_outcome_sha256s": [
2269
+ value.set_outcome_sha256 for value in self.set_outcomes
2270
+ ],
2271
+ "diagnostic_joint_gain_hex": self.diagnostic_joint_gain.hex(),
2272
+ "allocation_directive_sha256": (
2273
+ self.allocation_directive.directive_sha256
2274
+ ),
2275
+ "phase_receipt_sha256s": [
2276
+ value.receipt_sha256 for value in self.phase_receipts
2277
+ ],
2278
+ "phase_commit_ack_sha256s": [
2279
+ value.ack_sha256 for value in self.phase_commit_acks
2280
+ ],
2281
+ "market_projector_definition_sha256": (
2282
+ self.market_projector_definition_sha256
2283
+ ),
2284
+ "market_projector_state_sha256": (
2285
+ self.market_projector_state_sha256
2286
+ ),
2287
+ "outcome_projector_definition_sha256": (
2288
+ self.outcome_projector_definition_sha256
2289
+ ),
2290
+ "current_outcomes_used_only_after_interception": True,
2291
+ "workload_objective_model_provider_prompt_config_branches": False,
2292
+ }
2293
+ if self.paired_audit_executions:
2294
+ record.update(
2295
+ {
2296
+ "paired_audit_execution_sha256s": [
2297
+ value.execution_sha256
2298
+ for value in self.paired_audit_executions
2299
+ ],
2300
+ "paired_audit_physical_extra_real_evaluation_count": len(
2301
+ self.paired_audit_executions
2302
+ ),
2303
+ "paired_audit_union_admitted_to_authoritative_archive": (
2304
+ False
2305
+ ),
2306
+ }
2307
+ )
2308
+ if has_forecast_stratified_audit:
2309
+ record.update(
2310
+ {
2311
+ "forecast_stratified_same_prefix_audit": True,
2312
+ "counterfactual_action_quarantine_enforced": True,
2313
+ "counterfactual_quarantined_action_sha256s": sorted(
2314
+ value.counterfactual_action_sha256
2315
+ for value in self.paired_audit_executions
2316
+ if value.plan.designer_id
2317
+ == FORECAST_STRATIFIED_SAME_PREFIX_AUDIT_DESIGNER_ID
2318
+ ),
2319
+ "audit_position_schedule": (
2320
+ "one-hash-uniform-continuation-position-per-request"
2321
+ ),
2322
+ }
2323
+ )
2324
+ if self.forecast_opportunity_calibration_observations:
2325
+ record[
2326
+ "forecast_opportunity_calibration_observation_sha256s"
2327
+ ] = [
2328
+ value.observation_sha256
2329
+ for value in (
2330
+ self.forecast_opportunity_calibration_observations
2331
+ )
2332
+ ]
2333
+ if self.forecast_opportunity_challenger_definition_sha256 is not None:
2334
+ record.update(
2335
+ {
2336
+ "forecast_opportunity_challenger_definition_sha256": (
2337
+ self.forecast_opportunity_challenger_definition_sha256
2338
+ ),
2339
+ "forecast_geometry_frozen_before_diagnostic_outcomes": True,
2340
+ "current_prefix_candidate_outcomes_used_for_selection": True,
2341
+ "eligible_candidate_outcomes_observed": False,
2342
+ "fallback_preserved_on_abstention": True,
2343
+ }
2344
+ )
2345
+ return record
2346
+
2347
+ def to_record(self, *, include_evidence: bool = False) -> dict[str, object]:
2348
+ self.__post_init__()
2349
+ record = {
2350
+ **self._unsigned_record(),
2351
+ "adaptive_actions": [
2352
+ value.to_record() for value in self.adaptive_actions
2353
+ ],
2354
+ "diagnostic_decision": self.diagnostic_decision.to_record(
2355
+ include_evidence=include_evidence
2356
+ ),
2357
+ "continuation_decisions": [
2358
+ value.to_record(include_evidence=include_evidence)
2359
+ for value in self.continuation_decisions
2360
+ ],
2361
+ "evaluation_waves": [
2362
+ [
2363
+ value.to_record(include_evidence=include_evidence)
2364
+ for value in wave
2365
+ ]
2366
+ for wave in self.evaluation_waves
2367
+ ],
2368
+ "outcomes": [value.to_record() for value in self.outcomes],
2369
+ "set_outcomes": [
2370
+ value.to_record() for value in self.set_outcomes
2371
+ ],
2372
+ "allocation_directive": self.allocation_directive.to_record(
2373
+ include_evidence=include_evidence
2374
+ ),
2375
+ "phase_receipts": [
2376
+ value.to_record(include_evidence=include_evidence)
2377
+ for value in self.phase_receipts
2378
+ ],
2379
+ "phase_commit_acks": [
2380
+ value.to_record(include_evidence=include_evidence)
2381
+ for value in self.phase_commit_acks
2382
+ ],
2383
+ "combined_result": self.result.to_record(
2384
+ include_allocation_evidence=include_evidence
2385
+ ),
2386
+ "adaptive_result_sha256": self.adaptive_result_sha256,
2387
+ }
2388
+ if self.paired_audit_executions:
2389
+ record["paired_audit_executions"] = [
2390
+ value.to_record(include_evidence=include_evidence)
2391
+ for value in self.paired_audit_executions
2392
+ ]
2393
+ if self.forecast_opportunity_calibration_observations:
2394
+ record["forecast_opportunity_calibration_observations"] = [
2395
+ value.to_record()
2396
+ for value in (
2397
+ self.forecast_opportunity_calibration_observations
2398
+ )
2399
+ ]
2400
+ return record
2401
+
2402
+
2403
+ @dataclass(frozen=True, slots=True)
2404
+ class OutcomeAdaptiveResidualPortfolioEvolution:
2405
+ """Execute diagnostic and sequential actions from one sealed market."""
2406
+
2407
+ experts: tuple[MaterializedActionProposalExpertPort, ...]
2408
+ broker: RegretBrokeredMaterializedActionPolicy
2409
+ racing_policy: OutcomeAdaptiveActionRacingPolicy
2410
+ market_projector: AdaptiveActionMarketProjectorPort = field(
2411
+ repr=False,
2412
+ compare=False,
2413
+ )
2414
+ outcome_projector: AdaptiveActionOutcomeProjectorPort = field(
2415
+ repr=False,
2416
+ compare=False,
2417
+ )
2418
+ slate_value: MaterializedSlateValuePort = field(
2419
+ repr=False,
2420
+ compare=False,
2421
+ )
2422
+ slate_feasibility: MaterializedSlateFeasibilityPort = field(
2423
+ repr=False,
2424
+ compare=False,
2425
+ )
2426
+ diagnostic_allocation_policy: (
2427
+ MaterializedActionAllocationPolicyPort | None
2428
+ ) = field(
2429
+ default=None,
2430
+ repr=False,
2431
+ compare=False,
2432
+ )
2433
+ phase_committer: OutcomeAdaptiveResidualPhaseCommitPort | None = field(
2434
+ default=None,
2435
+ repr=False,
2436
+ compare=False,
2437
+ )
2438
+ paired_audit_designer: SamePrefixPairedAuditDesignerPort | None = field(
2439
+ default=None,
2440
+ repr=False,
2441
+ compare=False,
2442
+ )
2443
+ forecast_opportunity_challenger: (
2444
+ ProtectedCurrentPrefixForecastOpportunityChallenger | None
2445
+ ) = field(
2446
+ default=None,
2447
+ repr=False,
2448
+ compare=False,
2449
+ )
2450
+ forecast_opportunity_shadow_designer: (
2451
+ ForecastOpportunitySamePrefixShadowDesignerPort | None
2452
+ ) = field(
2453
+ default=None,
2454
+ repr=False,
2455
+ compare=False,
2456
+ )
2457
+ require_durable_phase_commits: bool = False
2458
+
2459
+ def __post_init__(self) -> None:
2460
+ if type(self.experts) is not tuple or not self.experts:
2461
+ raise ValueError("experts must be a non-empty exact tuple")
2462
+ if any(
2463
+ getattr(value, "evaluation_wave_semantics", None)
2464
+ != DISJOINT_ACTION_EVALUATION_WAVES_V1
2465
+ for value in self.experts
2466
+ ):
2467
+ raise ValueError(
2468
+ "adaptive experts must support disjoint action waves"
2469
+ )
2470
+ if type(self.broker) is not RegretBrokeredMaterializedActionPolicy:
2471
+ raise TypeError("broker must be an exact regret-broker policy")
2472
+ self.broker.__post_init__()
2473
+ if type(self.racing_policy) is not OutcomeAdaptiveActionRacingPolicy:
2474
+ # Structural admission for injected allocation controllers:
2475
+ # the policy must expose the exact racing surface (identity
2476
+ # triple plus both decision methods). Version-gated
2477
+ # features (causal set outcomes, paired audits) still key
2478
+ # off policy_version, so a foreign controller only reaches
2479
+ # the plain observational path.
2480
+ required_attributes = (
2481
+ "policy_id",
2482
+ "policy_version",
2483
+ "definition_sha256",
2484
+ "design_diagnostic_pilot",
2485
+ "select_next",
2486
+ "__post_init__",
2487
+ )
2488
+ missing = tuple(
2489
+ name
2490
+ for name in required_attributes
2491
+ if not hasattr(self.racing_policy, name)
2492
+ )
2493
+ if missing:
2494
+ raise TypeError(
2495
+ "racing_policy must be the exact racing policy or "
2496
+ "implement its surface; missing: "
2497
+ + ",".join(missing)
2498
+ )
2499
+ self.racing_policy.__post_init__()
2500
+ if not isinstance(
2501
+ self.market_projector,
2502
+ AdaptiveActionMarketProjectorPort,
2503
+ ):
2504
+ raise TypeError("market_projector must implement its port")
2505
+ _require_token(
2506
+ self.market_projector.projector_id,
2507
+ name="market projector_id",
2508
+ )
2509
+ if (
2510
+ type(self.market_projector.projector_version) is not int
2511
+ or self.market_projector.projector_version <= 0
2512
+ ):
2513
+ raise ValueError("market projector_version must be positive")
2514
+ require_sha256(
2515
+ self.market_projector.definition_sha256,
2516
+ "market projector definition",
2517
+ )
2518
+ require_sha256(
2519
+ self.market_projector.state_sha256,
2520
+ "market projector state",
2521
+ )
2522
+ if not isinstance(
2523
+ self.outcome_projector,
2524
+ AdaptiveActionOutcomeProjectorPort,
2525
+ ):
2526
+ raise TypeError("outcome_projector must implement its port")
2527
+ _require_token(
2528
+ self.outcome_projector.projector_id,
2529
+ name="outcome projector_id",
2530
+ )
2531
+ if (
2532
+ type(self.outcome_projector.projector_version) is not int
2533
+ or self.outcome_projector.projector_version <= 0
2534
+ ):
2535
+ raise ValueError("outcome projector_version must be positive")
2536
+ require_sha256(
2537
+ self.outcome_projector.definition_sha256,
2538
+ "outcome projector definition",
2539
+ )
2540
+ if not isinstance(self.slate_value, MaterializedSlateValuePort):
2541
+ raise TypeError("slate_value must implement its port")
2542
+ if not isinstance(
2543
+ self.slate_feasibility,
2544
+ MaterializedSlateFeasibilityPort,
2545
+ ):
2546
+ raise TypeError("slate_feasibility must implement its port")
2547
+ require_sha256(
2548
+ self.slate_value.definition_sha256,
2549
+ "slate value definition",
2550
+ )
2551
+ require_sha256(
2552
+ self.slate_feasibility.definition_sha256,
2553
+ "slate feasibility definition",
2554
+ )
2555
+ if self.diagnostic_allocation_policy is not None:
2556
+ if not isinstance(
2557
+ self.diagnostic_allocation_policy,
2558
+ MaterializedActionAllocationPolicyPort,
2559
+ ):
2560
+ raise TypeError(
2561
+ "diagnostic_allocation_policy must implement its port"
2562
+ )
2563
+ _require_token(
2564
+ self.diagnostic_allocation_policy.policy_id,
2565
+ name="diagnostic allocation policy_id",
2566
+ )
2567
+ if (
2568
+ type(self.diagnostic_allocation_policy.policy_version)
2569
+ is not int
2570
+ or self.diagnostic_allocation_policy.policy_version <= 0
2571
+ ):
2572
+ raise ValueError(
2573
+ "diagnostic allocation policy_version must be positive"
2574
+ )
2575
+ require_sha256(
2576
+ self.diagnostic_allocation_policy.definition_sha256,
2577
+ "diagnostic allocation policy definition",
2578
+ )
2579
+ if self.phase_committer is not None:
2580
+ if not isinstance(
2581
+ self.phase_committer,
2582
+ OutcomeAdaptiveResidualPhaseCommitPort,
2583
+ ):
2584
+ raise TypeError("phase_committer must implement its port")
2585
+ _require_token(
2586
+ self.phase_committer.committer_id,
2587
+ name="committer_id",
2588
+ )
2589
+ if (
2590
+ type(self.phase_committer.committer_version) is not int
2591
+ or self.phase_committer.committer_version <= 0
2592
+ ):
2593
+ raise ValueError("committer_version must be positive")
2594
+ require_sha256(
2595
+ self.phase_committer.definition_sha256,
2596
+ "committer definition",
2597
+ )
2598
+ if self.paired_audit_designer is not None:
2599
+ if not isinstance(
2600
+ self.paired_audit_designer,
2601
+ SamePrefixPairedAuditDesignerPort,
2602
+ ):
2603
+ raise TypeError(
2604
+ "paired_audit_designer must implement its port"
2605
+ )
2606
+ _require_token(
2607
+ self.paired_audit_designer.designer_id,
2608
+ name="paired audit designer_id",
2609
+ )
2610
+ if (
2611
+ type(self.paired_audit_designer.designer_version) is not int
2612
+ or self.paired_audit_designer.designer_version <= 0
2613
+ ):
2614
+ raise ValueError(
2615
+ "paired audit designer_version must be positive"
2616
+ )
2617
+ require_sha256(
2618
+ self.paired_audit_designer.definition_sha256,
2619
+ "paired audit designer definition",
2620
+ )
2621
+ if (
2622
+ self.racing_policy.policy_version
2623
+ != (
2624
+ OUTCOME_ADAPTIVE_ACTION_RACING_STRATIFIED_AUDIT_POLICY_VERSION
2625
+ )
2626
+ ):
2627
+ raise ValueError(
2628
+ "paired audit interception requires racing policy v6"
2629
+ )
2630
+ if self.forecast_opportunity_challenger is not None:
2631
+ if (
2632
+ type(self.forecast_opportunity_challenger)
2633
+ is not ProtectedCurrentPrefixForecastOpportunityChallenger
2634
+ ):
2635
+ raise TypeError(
2636
+ "forecast_opportunity_challenger must be exact"
2637
+ )
2638
+ self.forecast_opportunity_challenger.__post_init__()
2639
+ if self.paired_audit_designer is not None:
2640
+ raise ValueError(
2641
+ "forecast challenger and paired audit cannot share one "
2642
+ "authoritative execution"
2643
+ )
2644
+ if (
2645
+ self.forecast_opportunity_challenger.fallback_policy_id
2646
+ != self.racing_policy.policy_id
2647
+ or self.forecast_opportunity_challenger
2648
+ .fallback_policy_version
2649
+ != self.racing_policy.policy_version
2650
+ or self.forecast_opportunity_challenger
2651
+ .fallback_policy_definition_sha256
2652
+ != self.racing_policy.definition_sha256
2653
+ ):
2654
+ raise ValueError(
2655
+ "forecast challenger fallback differs from racing policy"
2656
+ )
2657
+ if self.forecast_opportunity_shadow_designer is not None:
2658
+ if self.forecast_opportunity_challenger is None:
2659
+ raise ValueError(
2660
+ "forecast shadow designer requires a forecast challenger"
2661
+ )
2662
+ if self.paired_audit_designer is not None:
2663
+ raise ValueError(
2664
+ "forecast shadow and stratified audit designers are "
2665
+ "mutually exclusive"
2666
+ )
2667
+ if not isinstance(
2668
+ self.forecast_opportunity_shadow_designer,
2669
+ ForecastOpportunitySamePrefixShadowDesignerPort,
2670
+ ):
2671
+ raise TypeError(
2672
+ "forecast_opportunity_shadow_designer must implement "
2673
+ "its port"
2674
+ )
2675
+ _require_token(
2676
+ self.forecast_opportunity_shadow_designer.designer_id,
2677
+ name="forecast shadow designer_id",
2678
+ )
2679
+ if (
2680
+ type(
2681
+ self.forecast_opportunity_shadow_designer.designer_version
2682
+ )
2683
+ is not int
2684
+ or (
2685
+ self.forecast_opportunity_shadow_designer.designer_version
2686
+ <= 0
2687
+ )
2688
+ ):
2689
+ raise ValueError(
2690
+ "forecast shadow designer_version must be positive"
2691
+ )
2692
+ require_sha256(
2693
+ self.forecast_opportunity_shadow_designer.definition_sha256,
2694
+ "forecast shadow designer definition",
2695
+ )
2696
+ if type(self.require_durable_phase_commits) is not bool:
2697
+ raise TypeError("require_durable_phase_commits must be exact")
2698
+ if (
2699
+ self.require_durable_phase_commits
2700
+ and self.phase_committer is None
2701
+ ):
2702
+ raise ValueError(
2703
+ "required durable phase commits need a committer"
2704
+ )
2705
+
2706
+ async def _commit(
2707
+ self,
2708
+ receipt: OutcomeAdaptiveResidualPhaseReceipt,
2709
+ ) -> OutcomeAdaptiveResidualPhaseCommitAck | None:
2710
+ if self.phase_committer is None:
2711
+ return None
2712
+ ack = await self.phase_committer.commit(receipt)
2713
+ if type(ack) is not OutcomeAdaptiveResidualPhaseCommitAck:
2714
+ raise TypeError("phase committer returned a foreign ack")
2715
+ ack.__post_init__()
2716
+ if (
2717
+ ack.committer_id != self.phase_committer.committer_id
2718
+ or ack.committer_version
2719
+ != self.phase_committer.committer_version
2720
+ or ack.committer_definition_sha256
2721
+ != self.phase_committer.definition_sha256
2722
+ or ack.phase_receipt_sha256 != receipt.receipt_sha256
2723
+ ):
2724
+ raise ValueError("phase commit ack differs from request")
2725
+ if self.require_durable_phase_commits and not ack.durable:
2726
+ raise ValueError("required phase commit was not durable")
2727
+ return ack
2728
+
2729
+ async def run(
2730
+ self,
2731
+ request: ResidualPortfolioDecisionRequest,
2732
+ ) -> OutcomeAdaptiveResidualPortfolioEvolutionResult:
2733
+ self.__post_init__()
2734
+ if type(request) is not ResidualPortfolioDecisionRequest:
2735
+ raise TypeError("request must be exact")
2736
+ request.__post_init__()
2737
+ uses_causal_set_outcomes = (
2738
+ self.racing_policy.policy_version
2739
+ in {
2740
+ OUTCOME_ADAPTIVE_ACTION_RACING_CAUSAL_SET_POLICY_VERSION,
2741
+ OUTCOME_ADAPTIVE_ACTION_RACING_RISK_CONTROLLED_POLICY_VERSION,
2742
+ }
2743
+ )
2744
+ proposals = await propose_materialized_action_batches(
2745
+ experts=self.experts,
2746
+ request=request,
2747
+ )
2748
+ forecast_geometry = (
2749
+ None
2750
+ if self.forecast_opportunity_challenger is None
2751
+ else await self.forecast_opportunity_challenger.freeze_geometry(
2752
+ request=request,
2753
+ proposals=proposals,
2754
+ )
2755
+ )
2756
+ actions = tuple(
2757
+ action
2758
+ for proposal in proposals
2759
+ for action in proposal.actions
2760
+ )
2761
+ diagnostic_requirement = None
2762
+ if self.diagnostic_allocation_policy is not None:
2763
+ diagnostic_requirement = (
2764
+ await self.diagnostic_allocation_policy.require(
2765
+ request,
2766
+ proposals,
2767
+ )
2768
+ )
2769
+ if (
2770
+ type(diagnostic_requirement)
2771
+ is not MaterializedActionAllocationRequirement
2772
+ ):
2773
+ raise TypeError(
2774
+ "diagnostic allocation policy returned a foreign "
2775
+ "requirement"
2776
+ )
2777
+ diagnostic_requirement.__post_init__()
2778
+ if (
2779
+ diagnostic_requirement.policy_id,
2780
+ diagnostic_requirement.policy_version,
2781
+ diagnostic_requirement.policy_definition_sha256,
2782
+ ) != (
2783
+ self.diagnostic_allocation_policy.policy_id,
2784
+ self.diagnostic_allocation_policy.policy_version,
2785
+ self.diagnostic_allocation_policy.definition_sha256,
2786
+ ):
2787
+ raise ValueError(
2788
+ "diagnostic allocation requirement changed policy identity"
2789
+ )
2790
+ proposal_sha256s = tuple(
2791
+ sorted(value.proposal_sha256 for value in proposals)
2792
+ )
2793
+ if (
2794
+ diagnostic_requirement.residual_request_sha256
2795
+ != request.request_sha256
2796
+ or diagnostic_requirement.proposal_sha256s
2797
+ != proposal_sha256s
2798
+ ):
2799
+ raise ValueError(
2800
+ "diagnostic allocation requirement changed its "
2801
+ "sealed cutoff"
2802
+ )
2803
+ if not set(
2804
+ diagnostic_requirement.required_action_sha256s
2805
+ ).issubset({value.action_sha256 for value in actions}):
2806
+ raise ValueError(
2807
+ "diagnostic allocation selected outside the market"
2808
+ )
2809
+ prior_decision = self.broker.select(
2810
+ MaterializedActionBrokerRequest(
2811
+ actions=actions,
2812
+ evaluation_slots=request.evaluation_slots,
2813
+ slate_value=self.slate_value,
2814
+ slate_feasibility=self.slate_feasibility,
2815
+ reference_escrow_slots=request.reference_escrow_slots,
2816
+ allocation_requirement=diagnostic_requirement,
2817
+ )
2818
+ )
2819
+ fixed_actions = tuple(
2820
+ sorted(
2821
+ set(prior_decision.required_reference_action_sha256s)
2822
+ | (
2823
+ set()
2824
+ if diagnostic_requirement is None
2825
+ else set(
2826
+ diagnostic_requirement.required_action_sha256s
2827
+ )
2828
+ )
2829
+ | (
2830
+ set()
2831
+ if prior_decision.exploration_requirement is None
2832
+ else set(
2833
+ prior_decision.exploration_requirement
2834
+ .required_action_sha256s
2835
+ )
2836
+ )
2837
+ )
2838
+ )
2839
+ adaptive_actions = await self.market_projector.project(
2840
+ request,
2841
+ proposals,
2842
+ actions,
2843
+ prior_decision.scores,
2844
+ fixed_actions,
2845
+ )
2846
+ if len(adaptive_actions) < request.evaluation_slots:
2847
+ raise ValueError(
2848
+ "phenotype-unique adaptive market cannot fill capacity"
2849
+ )
2850
+ adaptive_action_by_sha256 = {
2851
+ value.action_sha256: value for value in adaptive_actions
2852
+ }
2853
+ diagnostic = self.racing_policy.design_diagnostic_pilot(
2854
+ residual_request_sha256=request.request_sha256,
2855
+ actions=adaptive_actions,
2856
+ evaluation_slots=request.evaluation_slots,
2857
+ required_action_sha256s=fixed_actions,
2858
+ )
2859
+ proposal_sha256s = tuple(
2860
+ sorted(value.proposal_sha256 for value in proposals)
2861
+ )
2862
+ receipts: list[OutcomeAdaptiveResidualPhaseReceipt] = []
2863
+ acks: list[OutcomeAdaptiveResidualPhaseCommitAck] = []
2864
+
2865
+ market_receipt = OutcomeAdaptiveResidualPhaseReceipt(
2866
+ phase=OutcomeAdaptiveResidualPhase.MARKET_FROZEN,
2867
+ phase_ordinal=1,
2868
+ residual_request_sha256=request.request_sha256,
2869
+ diagnostic_decision_sha256=diagnostic.decision_sha256,
2870
+ product_sha256s=(
2871
+ *proposal_sha256s,
2872
+ prior_decision.decision_sha256,
2873
+ diagnostic.decision_sha256,
2874
+ *(
2875
+ ()
2876
+ if forecast_geometry is None
2877
+ else (forecast_geometry.batch_sha256,)
2878
+ ),
2879
+ ),
2880
+ evidence=freeze_json(
2881
+ {
2882
+ "proposal_sha256s": list(proposal_sha256s),
2883
+ "proposal_action_count": len(actions),
2884
+ "adaptive_market_action_count": len(
2885
+ adaptive_actions
2886
+ ),
2887
+ "fixed_action_sha256s": list(fixed_actions),
2888
+ "prior_broker_decision": (
2889
+ prior_decision.to_record(
2890
+ include_allocation_evidence=True
2891
+ )
2892
+ ),
2893
+ "adaptive_actions": [
2894
+ value.to_record()
2895
+ for value in adaptive_actions
2896
+ ],
2897
+ "diagnostic_decision": diagnostic.to_record(
2898
+ include_evidence=True
2899
+ ),
2900
+ "market_projector": {
2901
+ "projector_id": (
2902
+ self.market_projector.projector_id
2903
+ ),
2904
+ "projector_version": (
2905
+ self.market_projector.projector_version
2906
+ ),
2907
+ "definition_sha256": (
2908
+ self.market_projector.definition_sha256
2909
+ ),
2910
+ "state_sha256": (
2911
+ self.market_projector.state_sha256
2912
+ ),
2913
+ },
2914
+ **(
2915
+ {}
2916
+ if forecast_geometry is None
2917
+ else {
2918
+ "forecast_opportunity_challenger": {
2919
+ "challenger_id": (
2920
+ self.forecast_opportunity_challenger
2921
+ .challenger_id
2922
+ ),
2923
+ "challenger_version": (
2924
+ self.forecast_opportunity_challenger
2925
+ .challenger_version
2926
+ ),
2927
+ "definition_sha256": (
2928
+ self.forecast_opportunity_challenger
2929
+ .definition_sha256
2930
+ ),
2931
+ },
2932
+ "forecast_geometry": (
2933
+ forecast_geometry.to_record(
2934
+ include_evidence=True
2935
+ )
2936
+ ),
2937
+ "forecast_geometry_frozen_before_"
2938
+ "diagnostic_outcomes": True,
2939
+ }
2940
+ ),
2941
+ "current_candidate_outcomes_observed": False,
2942
+ "all_actions_materialized": True,
2943
+ }
2944
+ ),
2945
+ )
2946
+ receipts.append(market_receipt)
2947
+ ack = await self._commit(market_receipt)
2948
+ if ack is not None:
2949
+ acks.append(ack)
2950
+
2951
+ diagnostic_batches = await evaluate_materialized_action_subset(
2952
+ experts=self.experts,
2953
+ proposals=proposals,
2954
+ selected_action_sha256s=(
2955
+ diagnostic.selected_action_sha256s
2956
+ ),
2957
+ )
2958
+ diagnostic_evaluations = _flatten(diagnostic_batches)
2959
+ outcomes = list(
2960
+ self.outcome_projector.project(
2961
+ diagnostic_evaluations
2962
+ )
2963
+ )
2964
+ diagnostic_joint_gain = self.outcome_projector.joint_gain(
2965
+ diagnostic_evaluations
2966
+ )
2967
+ diagnostic_set_outcome = (
2968
+ self.outcome_projector.project_set_outcome(
2969
+ (),
2970
+ diagnostic_evaluations,
2971
+ )
2972
+ )
2973
+ if not math.isclose(
2974
+ diagnostic_joint_gain,
2975
+ diagnostic_set_outcome.current_wave_fixed_set_gain,
2976
+ rel_tol=1e-12,
2977
+ abs_tol=1e-15,
2978
+ ):
2979
+ raise ValueError(
2980
+ "diagnostic joint utility projections disagree"
2981
+ )
2982
+ set_outcomes = [diagnostic_set_outcome]
2983
+ selected_evaluations = list(diagnostic_evaluations)
2984
+ waves = [diagnostic_batches]
2985
+ diagnostic_receipt = OutcomeAdaptiveResidualPhaseReceipt(
2986
+ phase=OutcomeAdaptiveResidualPhase.DIAGNOSTIC_EVALUATED,
2987
+ phase_ordinal=2,
2988
+ residual_request_sha256=request.request_sha256,
2989
+ diagnostic_decision_sha256=diagnostic.decision_sha256,
2990
+ product_sha256s=(
2991
+ *(
2992
+ value.batch_sha256
2993
+ for value in diagnostic_batches
2994
+ ),
2995
+ *(value.outcome_sha256 for value in outcomes),
2996
+ diagnostic_set_outcome.set_outcome_sha256,
2997
+ ),
2998
+ evidence=freeze_json(
2999
+ {
3000
+ "diagnostic_evaluation_batches": [
3001
+ value.to_record(include_evidence=True)
3002
+ for value in diagnostic_batches
3003
+ ],
3004
+ "diagnostic_outcomes": [
3005
+ value.to_record() for value in outcomes
3006
+ ],
3007
+ "diagnostic_joint_gain_hex": (
3008
+ diagnostic_joint_gain.hex()
3009
+ ),
3010
+ "diagnostic_set_outcome": (
3011
+ diagnostic_set_outcome.to_record()
3012
+ ),
3013
+ "causal_set_outcome_policy_role": (
3014
+ "selection_input"
3015
+ if uses_causal_set_outcomes
3016
+ else "observational_only"
3017
+ ),
3018
+ "current_prefix_candidate_outcomes_policy_role": (
3019
+ "selection_input"
3020
+ if self.forecast_opportunity_challenger
3021
+ is not None
3022
+ else "observational_only"
3023
+ ),
3024
+ "later_candidate_outcomes_observed": False,
3025
+ "next_adaptive_decision_exists": False,
3026
+ }
3027
+ ),
3028
+ )
3029
+ receipts.append(diagnostic_receipt)
3030
+ ack = await self._commit(diagnostic_receipt)
3031
+ if ack is not None:
3032
+ acks.append(ack)
3033
+
3034
+ selected = set(diagnostic.selected_action_sha256s)
3035
+ continuation_decisions: list[AdaptiveActionRacingDecision] = []
3036
+ paired_audit_executions: list[
3037
+ OutcomeAdaptivePairedAuditExecution
3038
+ ] = []
3039
+ forecast_calibration_observations: list[
3040
+ ArchiveOpportunityCalibrationObservation
3041
+ ] = []
3042
+ counterfactual_quarantined_action_sha256s: set[str] = set()
3043
+ paired_audit_adjudicator = (
3044
+ None
3045
+ if (
3046
+ self.paired_audit_designer is None
3047
+ and self.forecast_opportunity_shadow_designer is None
3048
+ )
3049
+ else SamePrefixPairedAuditAdjudicator()
3050
+ )
3051
+ while len(selected) < request.evaluation_slots:
3052
+ excluded_action_sha256s = tuple(
3053
+ sorted(counterfactual_quarantined_action_sha256s)
3054
+ )
3055
+ fallback_decision = self.racing_policy.select_next(
3056
+ residual_request_sha256=request.request_sha256,
3057
+ actions=adaptive_actions,
3058
+ evaluation_slots=request.evaluation_slots,
3059
+ diagnostic_action_sha256s=(
3060
+ diagnostic.selected_action_sha256s
3061
+ ),
3062
+ diagnostic_joint_gain=diagnostic_joint_gain,
3063
+ selected_action_sha256s=tuple(sorted(selected)),
3064
+ outcomes=tuple(outcomes),
3065
+ set_outcomes=tuple(set_outcomes),
3066
+ excluded_action_sha256s=excluded_action_sha256s,
3067
+ )
3068
+ decision = (
3069
+ fallback_decision
3070
+ if self.forecast_opportunity_challenger is None
3071
+ else self.forecast_opportunity_challenger.challenge(
3072
+ fallback=fallback_decision,
3073
+ geometry=forecast_geometry,
3074
+ adaptive_actions=adaptive_actions,
3075
+ selected_evaluations=tuple(
3076
+ selected_evaluations
3077
+ ),
3078
+ excluded_action_sha256s=(
3079
+ excluded_action_sha256s
3080
+ ),
3081
+ )
3082
+ )
3083
+ continuation_decisions.append(decision)
3084
+ paired_plan: SamePrefixPairedAuditPlan | None = None
3085
+ paired_plan_receipt: (
3086
+ OutcomeAdaptiveResidualPhaseReceipt | None
3087
+ ) = None
3088
+ if (
3089
+ self.paired_audit_designer is not None
3090
+ and decision.wave is AdaptiveActionWave.RANDOMIZED_AUDIT
3091
+ ):
3092
+ paired_plan = self.paired_audit_designer.design(
3093
+ decision=decision,
3094
+ actions=adaptive_actions,
3095
+ )
3096
+ elif self.forecast_opportunity_shadow_designer is not None:
3097
+ paired_plan = (
3098
+ self.forecast_opportunity_shadow_designer.design(
3099
+ adaptive_step=len(continuation_decisions),
3100
+ remaining_authoritative_slots_after_decision=(
3101
+ request.evaluation_slots
3102
+ - len(selected)
3103
+ - len(decision.selected_action_sha256s)
3104
+ ),
3105
+ decision=decision,
3106
+ fallback=fallback_decision,
3107
+ actions=adaptive_actions,
3108
+ )
3109
+ )
3110
+ if paired_plan is not None:
3111
+ paired_plan_receipt = OutcomeAdaptiveResidualPhaseReceipt(
3112
+ phase=(
3113
+ OutcomeAdaptiveResidualPhase.PAIRED_AUDIT_FROZEN
3114
+ ),
3115
+ phase_ordinal=len(receipts) + 1,
3116
+ residual_request_sha256=request.request_sha256,
3117
+ diagnostic_decision_sha256=(
3118
+ diagnostic.decision_sha256
3119
+ ),
3120
+ product_sha256s=(
3121
+ decision.decision_sha256,
3122
+ paired_plan.plan_sha256,
3123
+ ),
3124
+ evidence=freeze_json(
3125
+ {
3126
+ "adaptive_step": len(
3127
+ continuation_decisions
3128
+ ),
3129
+ "racing_decision_sha256": (
3130
+ decision.decision_sha256
3131
+ ),
3132
+ "plan_sha256": paired_plan.plan_sha256,
3133
+ "plan": paired_plan.to_record(
3134
+ include_evidence=True
3135
+ ),
3136
+ "current_arm_outcomes_observed": False,
3137
+ "plan_frozen_before_arm_evaluation": True,
3138
+ "durable_commit_required": (
3139
+ self.require_durable_phase_commits
3140
+ ),
3141
+ "assay_union_may_enter_authoritative_archive": (
3142
+ False
3143
+ ),
3144
+ }
3145
+ ),
3146
+ )
3147
+ receipts.append(paired_plan_receipt)
3148
+ ack = await self._commit(paired_plan_receipt)
3149
+ if ack is not None:
3150
+ acks.append(ack)
3151
+ step_batches = await evaluate_materialized_action_subset(
3152
+ experts=self.experts,
3153
+ proposals=proposals,
3154
+ selected_action_sha256s=(
3155
+ decision.selected_action_sha256s
3156
+ ),
3157
+ )
3158
+ step_evaluations = _flatten(step_batches)
3159
+ step_outcomes = self.outcome_projector.project(
3160
+ step_evaluations
3161
+ )
3162
+ step_set_outcome = (
3163
+ self.outcome_projector.project_set_outcome(
3164
+ tuple(selected_evaluations),
3165
+ step_evaluations,
3166
+ )
3167
+ )
3168
+ paired_execution: OutcomeAdaptivePairedAuditExecution | None = None
3169
+ forecast_calibration_observation: (
3170
+ ArchiveOpportunityCalibrationObservation | None
3171
+ ) = None
3172
+ if paired_plan is not None:
3173
+ if (
3174
+ paired_plan_receipt is None
3175
+ or paired_audit_adjudicator is None
3176
+ ):
3177
+ raise RuntimeError(
3178
+ "paired audit plan lacks its frozen execution context"
3179
+ )
3180
+ counterfactual_action_sha256 = (
3181
+ paired_plan.exploration_action_sha256
3182
+ if paired_plan.authoritative_arm
3183
+ is SamePrefixPairedAuditArm.LEGACY
3184
+ else paired_plan.legacy_action_sha256
3185
+ )
3186
+ counterfactual_batches = (
3187
+ await evaluate_materialized_action_counterfactual_subset(
3188
+ experts=self.experts,
3189
+ proposals=proposals,
3190
+ selected_action_sha256s=(
3191
+ counterfactual_action_sha256,
3192
+ ),
3193
+ )
3194
+ )
3195
+ counterfactual_evaluations = _flatten(
3196
+ counterfactual_batches
3197
+ )
3198
+ counterfactual_outcomes = (
3199
+ self.outcome_projector.project(
3200
+ counterfactual_evaluations
3201
+ )
3202
+ )
3203
+ counterfactual_set_outcome = (
3204
+ self.outcome_projector.project_set_outcome(
3205
+ tuple(selected_evaluations),
3206
+ counterfactual_evaluations,
3207
+ )
3208
+ )
3209
+ if (
3210
+ len(step_outcomes) != 1
3211
+ or len(counterfactual_outcomes) != 1
3212
+ ):
3213
+ raise ValueError(
3214
+ "paired audit arms must each contain one action"
3215
+ )
3216
+ authoritative_outcome = step_outcomes[0]
3217
+ counterfactual_outcome = counterfactual_outcomes[0]
3218
+ if (
3219
+ paired_plan.authoritative_arm
3220
+ is SamePrefixPairedAuditArm.LEGACY
3221
+ ):
3222
+ legacy_outcome = authoritative_outcome
3223
+ legacy_set_outcome = step_set_outcome
3224
+ exploration_outcome = counterfactual_outcome
3225
+ exploration_set_outcome = (
3226
+ counterfactual_set_outcome
3227
+ )
3228
+ else:
3229
+ legacy_outcome = counterfactual_outcome
3230
+ legacy_set_outcome = counterfactual_set_outcome
3231
+ exploration_outcome = authoritative_outcome
3232
+ exploration_set_outcome = step_set_outcome
3233
+ paired_observation = (
3234
+ paired_audit_adjudicator.adjudicate(
3235
+ plan=paired_plan,
3236
+ legacy_outcome=legacy_outcome,
3237
+ exploration_outcome=exploration_outcome,
3238
+ legacy_set_outcome=legacy_set_outcome,
3239
+ exploration_set_outcome=(
3240
+ exploration_set_outcome
3241
+ ),
3242
+ )
3243
+ )
3244
+ paired_execution = OutcomeAdaptivePairedAuditExecution(
3245
+ plan=paired_plan,
3246
+ observation=paired_observation,
3247
+ counterfactual_evaluation_batches=(
3248
+ counterfactual_batches
3249
+ ),
3250
+ plan_receipt_sha256=(
3251
+ paired_plan_receipt.receipt_sha256
3252
+ ),
3253
+ )
3254
+ paired_audit_executions.append(paired_execution)
3255
+ counterfactual_quarantined_action_sha256s.add(
3256
+ paired_execution.counterfactual_action_sha256
3257
+ )
3258
+ if (
3259
+ paired_plan.designer_id
3260
+ in FORECAST_OPPORTUNITY_SAME_PREFIX_AUDIT_DESIGNER_IDS
3261
+ ):
3262
+ forecast_calibration_observation = (
3263
+ ForecastOpportunityShadowCalibrationProjector().project(
3264
+ decision_index=request.decision_index,
3265
+ evidence_cutoff_ordinal=request.decision_index,
3266
+ decision=decision,
3267
+ action=adaptive_action_by_sha256[
3268
+ paired_plan.exploration_action_sha256
3269
+ ],
3270
+ observation=paired_observation,
3271
+ )
3272
+ )
3273
+ forecast_calibration_observations.append(
3274
+ forecast_calibration_observation
3275
+ )
3276
+ outcomes.extend(step_outcomes)
3277
+ set_outcomes.append(step_set_outcome)
3278
+ selected_evaluations.extend(step_evaluations)
3279
+ waves.append(step_batches)
3280
+ selected.update(decision.selected_action_sha256s)
3281
+ step_receipt = OutcomeAdaptiveResidualPhaseReceipt(
3282
+ phase=(
3283
+ OutcomeAdaptiveResidualPhase
3284
+ .ADAPTIVE_STEP_EVALUATED
3285
+ ),
3286
+ phase_ordinal=len(receipts) + 1,
3287
+ residual_request_sha256=request.request_sha256,
3288
+ diagnostic_decision_sha256=(
3289
+ diagnostic.decision_sha256
3290
+ ),
3291
+ product_sha256s=(
3292
+ decision.decision_sha256,
3293
+ *(value.batch_sha256 for value in step_batches),
3294
+ *(
3295
+ value.outcome_sha256
3296
+ for value in step_outcomes
3297
+ ),
3298
+ step_set_outcome.set_outcome_sha256,
3299
+ *(
3300
+ ()
3301
+ if paired_execution is None
3302
+ else (
3303
+ paired_execution.execution_sha256,
3304
+ paired_execution.observation.observation_sha256,
3305
+ *(
3306
+ ()
3307
+ if forecast_calibration_observation is None
3308
+ else (
3309
+ forecast_calibration_observation
3310
+ .observation_sha256,
3311
+ )
3312
+ ),
3313
+ *(
3314
+ value.batch_sha256
3315
+ for value in (
3316
+ paired_execution
3317
+ .counterfactual_evaluation_batches
3318
+ )
3319
+ ),
3320
+ )
3321
+ ),
3322
+ ),
3323
+ evidence=freeze_json(
3324
+ {
3325
+ "adaptive_step": len(
3326
+ continuation_decisions
3327
+ ),
3328
+ "decision": decision.to_record(
3329
+ include_evidence=True
3330
+ ),
3331
+ "evaluation_batches": [
3332
+ value.to_record(include_evidence=True)
3333
+ for value in step_batches
3334
+ ],
3335
+ "outcomes": [
3336
+ value.to_record()
3337
+ for value in step_outcomes
3338
+ ],
3339
+ "set_outcome": (
3340
+ step_set_outcome.to_record()
3341
+ ),
3342
+ **(
3343
+ {}
3344
+ if paired_execution is None
3345
+ else {
3346
+ "paired_audit_execution": (
3347
+ paired_execution.to_record(
3348
+ include_evidence=True
3349
+ )
3350
+ ),
3351
+ "paired_audit_counterfactual_excluded_from_"
3352
+ "authoritative_archive": True,
3353
+ **(
3354
+ {}
3355
+ if forecast_calibration_observation is None
3356
+ else {
3357
+ "forecast_opportunity_calibration_"
3358
+ "observation": (
3359
+ forecast_calibration_observation
3360
+ .to_record()
3361
+ )
3362
+ }
3363
+ ),
3364
+ }
3365
+ ),
3366
+ "causal_set_outcome_policy_role": (
3367
+ "selection_input"
3368
+ if uses_causal_set_outcomes
3369
+ else "observational_only"
3370
+ ),
3371
+ "current_prefix_candidate_outcomes_policy_role": (
3372
+ "selection_input"
3373
+ if self.forecast_opportunity_challenger
3374
+ is not None
3375
+ else "observational_only"
3376
+ ),
3377
+ "selected_action_count_after_step": len(
3378
+ selected
3379
+ ),
3380
+ "unobserved_candidate_outcomes_available": (
3381
+ False
3382
+ ),
3383
+ "next_adaptive_decision_exists": False,
3384
+ }
3385
+ ),
3386
+ )
3387
+ receipts.append(step_receipt)
3388
+ ack = await self._commit(step_receipt)
3389
+ if ack is not None:
3390
+ acks.append(ack)
3391
+
3392
+ directive = AdaptiveActionAllocationDirective(
3393
+ policy_id=(
3394
+ self.racing_policy.policy_id
3395
+ if self.forecast_opportunity_challenger is None
3396
+ else self.forecast_opportunity_challenger.challenger_id
3397
+ ),
3398
+ policy_version=(
3399
+ self.racing_policy.policy_version
3400
+ if self.forecast_opportunity_challenger is None
3401
+ else self.forecast_opportunity_challenger
3402
+ .challenger_version
3403
+ ),
3404
+ policy_definition_sha256=(
3405
+ self.racing_policy.definition_sha256
3406
+ if self.forecast_opportunity_challenger is None
3407
+ else self.forecast_opportunity_challenger
3408
+ .definition_sha256
3409
+ ),
3410
+ residual_request_sha256=request.request_sha256,
3411
+ proposal_sha256s=proposal_sha256s,
3412
+ required_action_sha256s=tuple(sorted(selected)),
3413
+ diagnostic_decision_sha256=diagnostic.decision_sha256,
3414
+ continuation_decision_sha256s=tuple(
3415
+ sorted(
3416
+ value.decision_sha256
3417
+ for value in continuation_decisions
3418
+ )
3419
+ ),
3420
+ observed_outcome_sha256s=tuple(
3421
+ sorted(value.outcome_sha256 for value in outcomes)
3422
+ ),
3423
+ observed_set_outcome_sha256s=tuple(
3424
+ sorted(
3425
+ value.set_outcome_sha256
3426
+ for value in set_outcomes
3427
+ )
3428
+ ),
3429
+ evidence=freeze_json(
3430
+ {
3431
+ "market_receipt_sha256": (
3432
+ market_receipt.receipt_sha256
3433
+ ),
3434
+ "diagnostic_receipt_sha256": (
3435
+ diagnostic_receipt.receipt_sha256
3436
+ ),
3437
+ "adaptive_step_receipt_sha256s": [
3438
+ value.receipt_sha256
3439
+ for value in receipts
3440
+ if value.phase
3441
+ is OutcomeAdaptiveResidualPhase
3442
+ .ADAPTIVE_STEP_EVALUATED
3443
+ ],
3444
+ "diagnostic_joint_gain_hex": (
3445
+ diagnostic_joint_gain.hex()
3446
+ ),
3447
+ "set_outcome_sha256s": [
3448
+ value.set_outcome_sha256
3449
+ for value in set_outcomes
3450
+ ],
3451
+ **(
3452
+ {}
3453
+ if not paired_audit_executions
3454
+ else {
3455
+ "paired_audit_plan_receipt_sha256s": [
3456
+ value.plan_receipt_sha256
3457
+ for value in paired_audit_executions
3458
+ ],
3459
+ "paired_audit_execution_sha256s": [
3460
+ value.execution_sha256
3461
+ for value in paired_audit_executions
3462
+ ],
3463
+ "paired_audit_physical_extra_real_evaluation_count": (
3464
+ len(paired_audit_executions)
3465
+ ),
3466
+ "paired_audit_union_admitted_to_"
3467
+ "authoritative_archive": False,
3468
+ }
3469
+ ),
3470
+ "causal_set_outcomes_used_for_selection": (
3471
+ uses_causal_set_outcomes
3472
+ ),
3473
+ "current_prefix_candidate_outcomes_used_for_selection": (
3474
+ self.forecast_opportunity_challenger is not None
3475
+ ),
3476
+ "eligible_candidate_outcomes_observed": False,
3477
+ "all_selected_actions_really_evaluated": True,
3478
+ "unobserved_candidate_outcomes_available": False,
3479
+ "workload_model_provider_prompt_branches": False,
3480
+ }
3481
+ ),
3482
+ )
3483
+ final_decision = self.broker.select(
3484
+ MaterializedActionBrokerRequest(
3485
+ actions=actions,
3486
+ evaluation_slots=request.evaluation_slots,
3487
+ slate_value=self.slate_value,
3488
+ slate_feasibility=self.slate_feasibility,
3489
+ reference_escrow_slots=request.reference_escrow_slots,
3490
+ allocation_requirement=directive,
3491
+ )
3492
+ )
3493
+ if {
3494
+ value.action_sha256
3495
+ for value in final_decision.selected_actions
3496
+ } != selected:
3497
+ raise ValueError("final broker did not honor adaptive directive")
3498
+ merged = _merge_waves(proposals, tuple(waves))
3499
+ combined = ResidualPortfolioEvolutionResult(
3500
+ request=request,
3501
+ proposals=proposals,
3502
+ broker_decision=final_decision,
3503
+ evaluation_batches=merged,
3504
+ slate_value_definition_sha256=(
3505
+ self.slate_value.definition_sha256
3506
+ ),
3507
+ slate_feasibility_definition_sha256=(
3508
+ self.slate_feasibility.definition_sha256
3509
+ ),
3510
+ )
3511
+ final_receipt = OutcomeAdaptiveResidualPhaseReceipt(
3512
+ phase=OutcomeAdaptiveResidualPhase.FINALIZED,
3513
+ phase_ordinal=len(receipts) + 1,
3514
+ residual_request_sha256=request.request_sha256,
3515
+ diagnostic_decision_sha256=diagnostic.decision_sha256,
3516
+ product_sha256s=(
3517
+ directive.directive_sha256,
3518
+ final_decision.decision_sha256,
3519
+ combined.result_sha256,
3520
+ *(
3521
+ value.execution_sha256
3522
+ for value in paired_audit_executions
3523
+ ),
3524
+ ),
3525
+ evidence=freeze_json(
3526
+ {
3527
+ "allocation_directive": directive.to_record(
3528
+ include_evidence=True
3529
+ ),
3530
+ "final_broker_decision": (
3531
+ final_decision.to_record(
3532
+ include_allocation_evidence=True
3533
+ )
3534
+ ),
3535
+ "combined_result_sha256": combined.result_sha256,
3536
+ "real_evaluation_budget_preserved": (
3537
+ not paired_audit_executions
3538
+ ),
3539
+ **(
3540
+ {}
3541
+ if not paired_audit_executions
3542
+ else {
3543
+ "selected_real_evaluation_budget_preserved": True,
3544
+ "physical_real_evaluation_budget_includes_"
3545
+ "assay_extras": True,
3546
+ "paired_audit_physical_extra_real_"
3547
+ "evaluation_count": len(
3548
+ paired_audit_executions
3549
+ ),
3550
+ "paired_audit_execution_sha256s": [
3551
+ value.execution_sha256
3552
+ for value in paired_audit_executions
3553
+ ],
3554
+ "paired_audit_union_admitted_to_"
3555
+ "authoritative_archive": False,
3556
+ }
3557
+ ),
3558
+ "selected_action_count": len(selected),
3559
+ "set_outcome_sha256s": [
3560
+ value.set_outcome_sha256
3561
+ for value in set_outcomes
3562
+ ],
3563
+ "causal_set_outcomes_used_for_selection": (
3564
+ uses_causal_set_outcomes
3565
+ ),
3566
+ "current_prefix_candidate_outcomes_used_for_selection": (
3567
+ self.forecast_opportunity_challenger is not None
3568
+ ),
3569
+ "eligible_candidate_outcomes_observed": False,
3570
+ }
3571
+ ),
3572
+ )
3573
+ receipts.append(final_receipt)
3574
+ ack = await self._commit(final_receipt)
3575
+ if ack is not None:
3576
+ acks.append(ack)
3577
+ return OutcomeAdaptiveResidualPortfolioEvolutionResult(
3578
+ result=combined,
3579
+ prior_broker_decision=prior_decision,
3580
+ adaptive_actions=adaptive_actions,
3581
+ diagnostic_decision=diagnostic,
3582
+ continuation_decisions=tuple(continuation_decisions),
3583
+ evaluation_waves=tuple(waves),
3584
+ outcomes=tuple(
3585
+ sorted(
3586
+ outcomes,
3587
+ key=lambda value: value.action_sha256,
3588
+ )
3589
+ ),
3590
+ set_outcomes=tuple(set_outcomes),
3591
+ diagnostic_joint_gain=diagnostic_joint_gain,
3592
+ allocation_directive=directive,
3593
+ phase_receipts=tuple(receipts),
3594
+ phase_commit_acks=tuple(acks),
3595
+ market_projector_definition_sha256=(
3596
+ self.market_projector.definition_sha256
3597
+ ),
3598
+ market_projector_state_sha256=(
3599
+ self.market_projector.state_sha256
3600
+ ),
3601
+ outcome_projector_definition_sha256=(
3602
+ self.outcome_projector.definition_sha256
3603
+ ),
3604
+ forecast_opportunity_challenger_definition_sha256=(
3605
+ None
3606
+ if self.forecast_opportunity_challenger is None
3607
+ else self.forecast_opportunity_challenger
3608
+ .definition_sha256
3609
+ ),
3610
+ paired_audit_executions=tuple(paired_audit_executions),
3611
+ forecast_opportunity_calibration_observations=tuple(
3612
+ forecast_calibration_observations
3613
+ ),
3614
+ method_definition_sha256=(
3615
+ OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_STRATIFIED_AUDIT_EVOLUTION_DEFINITION_SHA256
3616
+ if (
3617
+ any(
3618
+ value.plan.designer_id
3619
+ == FORECAST_STRATIFIED_SAME_PREFIX_AUDIT_DESIGNER_ID
3620
+ for value in paired_audit_executions
3621
+ )
3622
+ )
3623
+ else (
3624
+ OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_SHADOW_EVOLUTION_DEFINITION_SHA256
3625
+ if (
3626
+ self.forecast_opportunity_challenger is not None
3627
+ and paired_audit_executions
3628
+ )
3629
+ else (
3630
+ _FORECAST_OPPORTUNITY_DEFINITION_SHA256
3631
+ if self.forecast_opportunity_challenger is not None
3632
+ else (
3633
+ _PAIRED_AUDIT_DEFINITION_SHA256
3634
+ if paired_audit_executions
3635
+ else OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_DEFINITION_SHA256
3636
+ )
3637
+ )
3638
+ )
3639
+ ),
3640
+ )
3641
+
3642
+
3643
+ __all__ = [
3644
+ "AdaptiveActionMarketProjectorPort",
3645
+ "AdaptiveActionOutcomeProjectorPort",
3646
+ "AdaptiveActionSemanticView",
3647
+ "AdaptiveActionSemanticViewPort",
3648
+ "CandidateArchiveAdaptiveActionOutcomeProjector",
3649
+ "FactorStratifiedAdaptiveMarketProjector",
3650
+ "OutcomeAdaptivePairedAuditExecution",
3651
+ "OutcomeAdaptiveResidualPhase",
3652
+ "OutcomeAdaptiveResidualPhaseCommitAck",
3653
+ "OutcomeAdaptiveResidualPhaseCommitPort",
3654
+ "OutcomeAdaptiveResidualPhaseReceipt",
3655
+ "OutcomeAdaptiveResidualPortfolioEvolution",
3656
+ "OutcomeAdaptiveResidualPortfolioEvolutionResult",
3657
+ "OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_DEFINITION_SHA256",
3658
+ "OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_ID",
3659
+ "OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_VERSION",
3660
+ "OUTCOME_ADAPTIVE_RESIDUAL_PAIRED_AUDIT_EVOLUTION_DEFINITION_SHA256",
3661
+ "OUTCOME_ADAPTIVE_RESIDUAL_PAIRED_AUDIT_EVOLUTION_VERSION",
3662
+ "OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_OPPORTUNITY_EVOLUTION_DEFINITION_SHA256",
3663
+ "OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_OPPORTUNITY_EVOLUTION_VERSION",
3664
+ "OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_SHADOW_EVOLUTION_DEFINITION_SHA256",
3665
+ "OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_SHADOW_EVOLUTION_VERSION",
3666
+ "OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_STRATIFIED_AUDIT_EVOLUTION_DEFINITION_SHA256",
3667
+ "OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_STRATIFIED_AUDIT_EVOLUTION_VERSION",
3668
+ "PortableMaterializedAdaptiveMarketProjector",
3669
+ "PortableMaterializedAdaptiveSemanticView",
3670
+ "ScoreEnsembleMaterializedAdaptiveMarketProjector",
3671
+ ]