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,680 @@
1
+ """Rank-normalized, role-factorized value for small action portfolios.
2
+
3
+ One scalar acquisition law is brittle when consequence forecasts are weak:
4
+ optimistic uncertain actions can monopolize exploitation, while risk aversion
5
+ can suppress the global probes that discover new basins. This module assigns
6
+ each member of a small feasible portfolio to one of three workload-neutral
7
+ roles: reliable archive exploitation, residual bridging, or epistemic probing.
8
+
9
+ Role scores are empirical-CDF normalized over the sealed eligible forecast
10
+ snapshot. This avoids workload- and objective-scale weights. Two exploit
11
+ slots retain joint expected-hypervolume value; bridge and probe each receive a
12
+ protected slot. The ordinary feasible beam allocator still owns uniqueness,
13
+ family coverage, and patch compatibility.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import hashlib
19
+ import itertools
20
+ import json
21
+ import math
22
+ from dataclasses import dataclass, field
23
+ from enum import Enum
24
+ from functools import lru_cache
25
+
26
+ from agent_evolve.application.action_archive_value import (
27
+ ReliabilityAdjustedResidualCellExpectedHypervolumeUtility,
28
+ )
29
+ from agent_evolve.application.action_target_realization import (
30
+ ResidualTargetClosurePortfolioUtility,
31
+ )
32
+ from agent_evolve.domain.patch import require_sha256
33
+ from agent_evolve.ports.action_allocation import (
34
+ ForecastPortfolioUtilityBinding,
35
+ ForecastPortfolioUtilityInput,
36
+ ForecastQuantile,
37
+ )
38
+ from agent_evolve.ports.action_forecast import (
39
+ ActionForecastRequest,
40
+ ResolvedActionForecast,
41
+ ResolvedActionForecastBatch,
42
+ validate_resolved_action_forecasts,
43
+ )
44
+
45
+
46
+ ROLE_FACTORIZED_ACTION_UTILITY_ID = "role_factorized_action_portfolio"
47
+ ROLE_FACTORIZED_ACTION_UTILITY_VERSION = 2
48
+ ROLE_FACTORIZED_ACTION_UTILITY_DEFINITION_SHA256 = hashlib.sha256(
49
+ b"agent-evolve:role-factorized-action-portfolio:v2;"
50
+ b"roles=reliable-archive-exploit,residual-bridge,epistemic-probe;"
51
+ b"slots=wave-budgeted-with-default-2,1,1;"
52
+ b"normalization=sealed-eligible-empirical-cdf-midrank;"
53
+ b"exploit=joint-reliability-adjusted-fixed-reference-hypervolume;"
54
+ b"bridge=singleton-residual-target-closure;"
55
+ b"probe=one-minus-weakest-target-metric-confidence;"
56
+ b"assignment=maximum-weight-injective-role-assignment;"
57
+ b"workload-model-provider-family-option-text-branches=false;outcomes=false"
58
+ ).hexdigest()
59
+ _BINDING_DOMAIN = b"agent-evolve:role-factorized-action-binding:v2\x00"
60
+ _ELIGIBLE_DOMAIN = b"agent-evolve:role-factorized-eligible:v1\x00"
61
+
62
+
63
+ def _canonical_json(value: object) -> bytes:
64
+ return json.dumps(
65
+ value,
66
+ allow_nan=False,
67
+ ensure_ascii=True,
68
+ separators=(",", ":"),
69
+ sort_keys=True,
70
+ ).encode("ascii")
71
+
72
+
73
+ def _finite(value: object, *, name: str) -> float:
74
+ if type(value) is not float or not math.isfinite(value):
75
+ raise TypeError(f"{name} must be a finite exact float")
76
+ return value
77
+
78
+
79
+ class ActionAcquisitionRole(str, Enum):
80
+ RELIABLE_ARCHIVE_EXPLOIT = "reliable_archive_exploit"
81
+ RESIDUAL_BRIDGE = "residual_bridge"
82
+ EPISTEMIC_PROBE = "epistemic_probe"
83
+
84
+
85
+ @dataclass(frozen=True, slots=True)
86
+ class RoleScoreRow:
87
+ option_id: str
88
+ exploit_rank_scores: tuple[float, float, float]
89
+ bridge_rank_scores: tuple[float, float, float]
90
+ probe_rank_score: float
91
+
92
+ def __post_init__(self) -> None:
93
+ if type(self.option_id) is not str or not self.option_id:
94
+ raise ValueError("option_id must be non-empty")
95
+ for name in ("exploit_rank_scores", "bridge_rank_scores"):
96
+ values = getattr(self, name)
97
+ if type(values) is not tuple or len(values) != 3:
98
+ raise ValueError(f"{name} must contain p10, p50, and p90")
99
+ for value in values:
100
+ _finite(value, name=name)
101
+ if not 0.0 <= value <= 1.0:
102
+ raise ValueError(f"{name} must lie in [0,1]")
103
+ _finite(self.probe_rank_score, name="probe_rank_score")
104
+ if not 0.0 <= self.probe_rank_score <= 1.0:
105
+ raise ValueError("probe_rank_score must lie in [0,1]")
106
+
107
+ def to_record(self) -> dict[str, object]:
108
+ self.__post_init__()
109
+ return {
110
+ "option_id": self.option_id,
111
+ "exploit_rank_scores_hex": [
112
+ value.hex() for value in self.exploit_rank_scores
113
+ ],
114
+ "bridge_rank_scores_hex": [
115
+ value.hex() for value in self.bridge_rank_scores
116
+ ],
117
+ "probe_rank_score_hex": self.probe_rank_score.hex(),
118
+ }
119
+
120
+
121
+ @dataclass(frozen=True, slots=True)
122
+ class RoleAssignmentMember:
123
+ option_id: str
124
+ role: ActionAcquisitionRole
125
+
126
+ def __post_init__(self) -> None:
127
+ if type(self.option_id) is not str or not self.option_id:
128
+ raise ValueError("option_id must be non-empty")
129
+ if type(self.role) is not ActionAcquisitionRole:
130
+ raise TypeError("role must be an exact ActionAcquisitionRole")
131
+
132
+ def to_record(self) -> dict[str, str]:
133
+ self.__post_init__()
134
+ return {"option_id": self.option_id, "role": self.role.value}
135
+
136
+
137
+ @dataclass(frozen=True, slots=True)
138
+ class RoleAssignmentAudit:
139
+ """Receipt-bound explanation of one complete role assignment."""
140
+
141
+ utility_definition_sha256: str
142
+ forecast_receipt_sha256: str
143
+ quantile: ForecastQuantile
144
+ assignments: tuple[RoleAssignmentMember, ...]
145
+ utility_value: float
146
+
147
+ def __post_init__(self) -> None:
148
+ require_sha256(
149
+ self.utility_definition_sha256,
150
+ "utility_definition_sha256",
151
+ )
152
+ require_sha256(self.forecast_receipt_sha256, "forecast_receipt_sha256")
153
+ if type(self.quantile) is not ForecastQuantile:
154
+ raise TypeError("quantile must be an exact ForecastQuantile")
155
+ if type(self.assignments) is not tuple or not self.assignments:
156
+ raise ValueError("assignments must be a non-empty exact tuple")
157
+ for value in self.assignments:
158
+ if type(value) is not RoleAssignmentMember:
159
+ raise TypeError(
160
+ "assignments must contain exact RoleAssignmentMember values"
161
+ )
162
+ value.__post_init__()
163
+ option_ids = tuple(value.option_id for value in self.assignments)
164
+ if option_ids != tuple(sorted(set(option_ids))):
165
+ raise ValueError("assignments must use unique canonical option order")
166
+ _finite(self.utility_value, name="utility_value")
167
+
168
+ def to_record(self) -> dict[str, object]:
169
+ self.__post_init__()
170
+ return {
171
+ "schema_version": 1,
172
+ "utility_definition_sha256": self.utility_definition_sha256,
173
+ "forecast_receipt_sha256": self.forecast_receipt_sha256,
174
+ "quantile": self.quantile.value,
175
+ "assignments": [value.to_record() for value in self.assignments],
176
+ "utility_value_hex": self.utility_value.hex(),
177
+ }
178
+
179
+
180
+ def _quantile_index(value: ForecastQuantile) -> int:
181
+ if value is ForecastQuantile.P10:
182
+ return 0
183
+ if value is ForecastQuantile.P50:
184
+ return 1
185
+ if value is ForecastQuantile.P90:
186
+ return 2
187
+ raise TypeError("quantile must be exact")
188
+
189
+
190
+ def _midrank_scores(values: dict[str, float]) -> dict[str, float]:
191
+ if not values:
192
+ raise ValueError("role score table cannot be empty")
193
+ ordered = sorted(values.values())
194
+ count = len(ordered)
195
+ result: dict[str, float] = {}
196
+ for option_id, value in values.items():
197
+ lower = sum(candidate < value for candidate in ordered)
198
+ equal = sum(candidate == value for candidate in ordered)
199
+ result[option_id] = (lower + 0.5 * equal) / count
200
+ return result
201
+
202
+
203
+ @lru_cache(maxsize=32)
204
+ def _cached_role_sequences(
205
+ exploit_slots: int,
206
+ bridge_slots: int,
207
+ probe_slots: int,
208
+ member_count: int,
209
+ ) -> tuple[tuple[ActionAcquisitionRole, ...], ...]:
210
+ slots = (
211
+ (ActionAcquisitionRole.RELIABLE_ARCHIVE_EXPLOIT,) * exploit_slots
212
+ + (ActionAcquisitionRole.RESIDUAL_BRIDGE,) * bridge_slots
213
+ + (ActionAcquisitionRole.EPISTEMIC_PROBE,) * probe_slots
214
+ )
215
+ return tuple(
216
+ sorted(
217
+ set(itertools.permutations(slots, member_count)),
218
+ key=lambda row: tuple(value.value for value in row),
219
+ )
220
+ )
221
+
222
+
223
+ @dataclass(frozen=True, slots=True)
224
+ class RoleFactorizedActionPortfolioUtility:
225
+ """Identified utility with an explicit workload-neutral role budget."""
226
+
227
+ exploit_utility: ReliabilityAdjustedResidualCellExpectedHypervolumeUtility
228
+ bridge_utility: ResidualTargetClosurePortfolioUtility
229
+ forecast_receipt_sha256: str
230
+ eligible_option_ids_sha256: str
231
+ score_rows: tuple[RoleScoreRow, ...]
232
+ exploit_denominators: tuple[tuple[float, ...], ...]
233
+ exploit_slots: int = 2
234
+ bridge_slots: int = 1
235
+ probe_slots: int = 1
236
+ _exploit_value_cache: dict[tuple[str, tuple[str, ...]], float] = field(
237
+ default_factory=dict,
238
+ init=False,
239
+ repr=False,
240
+ compare=False,
241
+ hash=False,
242
+ )
243
+ _row_cache: dict[str, RoleScoreRow] = field(
244
+ default_factory=dict,
245
+ init=False,
246
+ repr=False,
247
+ compare=False,
248
+ hash=False,
249
+ )
250
+
251
+ def __post_init__(self) -> None:
252
+ if (
253
+ type(self.exploit_utility)
254
+ is not ReliabilityAdjustedResidualCellExpectedHypervolumeUtility
255
+ ):
256
+ raise TypeError("exploit_utility must be exact")
257
+ self.exploit_utility.__post_init__()
258
+ if type(self.bridge_utility) is not ResidualTargetClosurePortfolioUtility:
259
+ raise TypeError("bridge_utility must be exact")
260
+ self.bridge_utility.__post_init__()
261
+ require_sha256(self.forecast_receipt_sha256, "forecast_receipt_sha256")
262
+ require_sha256(
263
+ self.eligible_option_ids_sha256,
264
+ "eligible_option_ids_sha256",
265
+ )
266
+ if type(self.score_rows) is not tuple or not self.score_rows:
267
+ raise ValueError("score_rows must be non-empty")
268
+ for row in self.score_rows:
269
+ if type(row) is not RoleScoreRow:
270
+ raise TypeError("score_rows must contain exact RoleScoreRow values")
271
+ row.__post_init__()
272
+ option_ids = tuple(value.option_id for value in self.score_rows)
273
+ if option_ids != tuple(sorted(set(option_ids))):
274
+ raise ValueError("score_rows must use unique canonical option order")
275
+ for name in ("exploit_slots", "bridge_slots", "probe_slots"):
276
+ value = getattr(self, name)
277
+ if type(value) is not int or value < 0:
278
+ raise ValueError(f"{name} must be a non-negative exact integer")
279
+ if self.exploit_slots <= 0:
280
+ raise ValueError("role allocation requires at least one exploit slot")
281
+ if self.bridge_slots > 1 or self.probe_slots > 1:
282
+ raise ValueError("v2 supports at most one protected bridge/probe slot")
283
+ if self.portfolio_size > 8:
284
+ raise ValueError("role-factorized portfolios are bounded to eight")
285
+ if (
286
+ type(self.exploit_denominators) is not tuple
287
+ or len(self.exploit_denominators) != 3
288
+ ):
289
+ raise ValueError("exploit_denominators must contain three quantiles")
290
+ for values in self.exploit_denominators:
291
+ if type(values) is not tuple or len(values) != self.exploit_slots:
292
+ raise ValueError("exploit denominator width differs from slots")
293
+ previous = 0.0
294
+ for value in values:
295
+ _finite(value, name="exploit denominator")
296
+ if value < previous or value < 0.0:
297
+ raise ValueError(
298
+ "exploit denominators must be cumulative and non-negative"
299
+ )
300
+ previous = value
301
+
302
+ @property
303
+ def portfolio_size(self) -> int:
304
+ return self.exploit_slots + self.bridge_slots + self.probe_slots
305
+
306
+ @property
307
+ def binding_definition_sha256(self) -> str:
308
+ self.__post_init__()
309
+ payload = {
310
+ "schema_version": 1,
311
+ "base_policy_definition_sha256": (
312
+ ROLE_FACTORIZED_ACTION_UTILITY_DEFINITION_SHA256
313
+ ),
314
+ "exploit_utility_definition_sha256": (
315
+ self.exploit_utility.binding_definition_sha256
316
+ ),
317
+ "bridge_utility_definition_sha256": (
318
+ self.bridge_utility.binding_definition_sha256
319
+ ),
320
+ "forecast_receipt_sha256": self.forecast_receipt_sha256,
321
+ "eligible_option_ids_sha256": self.eligible_option_ids_sha256,
322
+ "role_slots": {
323
+ ActionAcquisitionRole.RELIABLE_ARCHIVE_EXPLOIT.value: (
324
+ self.exploit_slots
325
+ ),
326
+ ActionAcquisitionRole.RESIDUAL_BRIDGE.value: self.bridge_slots,
327
+ ActionAcquisitionRole.EPISTEMIC_PROBE.value: self.probe_slots,
328
+ },
329
+ "score_rows": [value.to_record() for value in self.score_rows],
330
+ "exploit_denominators_hex": [
331
+ [value.hex() for value in row]
332
+ for row in self.exploit_denominators
333
+ ],
334
+ }
335
+ return hashlib.sha256(
336
+ _BINDING_DOMAIN + _canonical_json(payload)
337
+ ).hexdigest()
338
+
339
+ def binding(self) -> ForecastPortfolioUtilityBinding:
340
+ return ForecastPortfolioUtilityBinding(
341
+ utility=self,
342
+ policy_id=ROLE_FACTORIZED_ACTION_UTILITY_ID,
343
+ policy_version=ROLE_FACTORIZED_ACTION_UTILITY_VERSION,
344
+ definition_sha256=self.binding_definition_sha256,
345
+ )
346
+
347
+ @property
348
+ def _rows_by_id(self) -> dict[str, RoleScoreRow]:
349
+ if not self._row_cache:
350
+ self._row_cache.update(
351
+ (value.option_id, value) for value in self.score_rows
352
+ )
353
+ return self._row_cache
354
+
355
+ def _role_sequences(
356
+ self,
357
+ member_count: int,
358
+ ) -> tuple[tuple[ActionAcquisitionRole, ...], ...]:
359
+ if not 0 < member_count <= self.portfolio_size:
360
+ raise ValueError("member_count lies outside the role portfolio")
361
+ return _cached_role_sequences(
362
+ self.exploit_slots,
363
+ self.bridge_slots,
364
+ self.probe_slots,
365
+ member_count,
366
+ )
367
+
368
+ def _subinput(
369
+ self,
370
+ request: ForecastPortfolioUtilityInput,
371
+ members: tuple[ResolvedActionForecast, ...],
372
+ ) -> ForecastPortfolioUtilityInput:
373
+ return ForecastPortfolioUtilityInput(
374
+ optimization_semantics=request.optimization_semantics,
375
+ parent_metric_values=request.parent_metric_values,
376
+ metric_scales=request.metric_scales,
377
+ members=members,
378
+ quantile=request.quantile,
379
+ )
380
+
381
+ def _assignment_score(
382
+ self,
383
+ request: ForecastPortfolioUtilityInput,
384
+ roles: tuple[ActionAcquisitionRole, ...],
385
+ *,
386
+ rows: dict[str, RoleScoreRow],
387
+ ) -> float:
388
+ index = _quantile_index(request.quantile)
389
+ exploit_members = tuple(
390
+ member
391
+ for member, role in zip(request.members, roles, strict=True)
392
+ if role is ActionAcquisitionRole.RELIABLE_ARCHIVE_EXPLOIT
393
+ )
394
+ score = 0.0
395
+ if exploit_members:
396
+ cache_key = (
397
+ request.quantile.value,
398
+ tuple(value.option_id for value in exploit_members),
399
+ )
400
+ raw = self._exploit_value_cache.get(cache_key)
401
+ if raw is None:
402
+ raw = self.exploit_utility(
403
+ self._subinput(request, exploit_members)
404
+ )
405
+ self._exploit_value_cache[cache_key] = raw
406
+ denominator = self.exploit_denominators[index][
407
+ len(exploit_members) - 1
408
+ ]
409
+ if denominator > 0.0:
410
+ score += len(exploit_members) * min(1.0, raw / denominator)
411
+ else:
412
+ score += sum(
413
+ rows[value.option_id].exploit_rank_scores[index]
414
+ for value in exploit_members
415
+ )
416
+ for member, role in zip(request.members, roles, strict=True):
417
+ row = rows.get(member.option_id)
418
+ if row is None:
419
+ raise ValueError("utility member is outside the sealed score table")
420
+ if role is ActionAcquisitionRole.RESIDUAL_BRIDGE:
421
+ score += row.bridge_rank_scores[index]
422
+ elif role is ActionAcquisitionRole.EPISTEMIC_PROBE:
423
+ score += row.probe_rank_score
424
+ if not math.isfinite(score):
425
+ raise RuntimeError("role assignment score became non-finite")
426
+ return float(score)
427
+
428
+ def _best_assignment(
429
+ self,
430
+ request: ForecastPortfolioUtilityInput,
431
+ ) -> tuple[tuple[ActionAcquisitionRole, ...], float]:
432
+ rows = self._rows_by_id
433
+ if any(member.option_id not in rows for member in request.members):
434
+ raise ValueError("utility member is outside the sealed score table")
435
+ best_roles: tuple[ActionAcquisitionRole, ...] | None = None
436
+ best_score: float | None = None
437
+ for roles in self._role_sequences(len(request.members)):
438
+ score = self._assignment_score(request, roles, rows=rows)
439
+ if best_score is None or score > best_score:
440
+ best_roles = roles
441
+ best_score = score
442
+ if best_roles is None or best_score is None:
443
+ raise AssertionError("role assignment search produced no assignment")
444
+ return best_roles, best_score
445
+
446
+ def assign_roles(
447
+ self,
448
+ request: ForecastPortfolioUtilityInput,
449
+ ) -> tuple[RoleAssignmentMember, ...]:
450
+ if type(request) is not ForecastPortfolioUtilityInput:
451
+ raise TypeError("request must be exact ForecastPortfolioUtilityInput")
452
+ request.__post_init__()
453
+ self.__post_init__()
454
+ if len(request.members) > self.portfolio_size:
455
+ raise ValueError("members exceed the role portfolio size")
456
+ best_roles, _ = self._best_assignment(request)
457
+ return tuple(
458
+ RoleAssignmentMember(member.option_id, role)
459
+ for member, role in zip(request.members, best_roles, strict=True)
460
+ )
461
+
462
+ def __call__(self, request: ForecastPortfolioUtilityInput) -> float:
463
+ if type(request) is not ForecastPortfolioUtilityInput:
464
+ raise TypeError("request must be exact")
465
+ if len(request.members) > self.portfolio_size:
466
+ raise ValueError("members exceed the role portfolio size")
467
+ _, score = self._best_assignment(request)
468
+ return score
469
+
470
+
471
+ def build_role_factorized_action_utility(
472
+ *,
473
+ forecast_request: ActionForecastRequest,
474
+ forecasts: ResolvedActionForecastBatch,
475
+ eligible_option_ids: tuple[str, ...],
476
+ exploit_utility: ReliabilityAdjustedResidualCellExpectedHypervolumeUtility,
477
+ bridge_utility: ResidualTargetClosurePortfolioUtility,
478
+ exploit_slots: int = 2,
479
+ bridge_slots: int = 1,
480
+ probe_slots: int = 1,
481
+ ) -> RoleFactorizedActionPortfolioUtility:
482
+ """Freeze rank-normalized role evidence from one forecast cutoff."""
483
+
484
+ if type(forecast_request) is not ActionForecastRequest:
485
+ raise TypeError("forecast_request must be exact")
486
+ forecast_request.__post_init__()
487
+ if type(forecasts) is not ResolvedActionForecastBatch:
488
+ raise TypeError("forecasts must be exact")
489
+ validate_resolved_action_forecasts(forecast_request, forecasts)
490
+ if (
491
+ type(eligible_option_ids) is not tuple
492
+ or not eligible_option_ids
493
+ or eligible_option_ids != tuple(sorted(set(eligible_option_ids)))
494
+ ):
495
+ raise ValueError("eligible_option_ids must be a non-empty canonical tuple")
496
+ by_id = {value.option_id: value for value in forecasts.forecasts}
497
+ if not set(eligible_option_ids).issubset(by_id):
498
+ raise ValueError("eligible_option_ids contains a foreign forecast")
499
+ if (
500
+ type(exploit_utility)
501
+ is not ReliabilityAdjustedResidualCellExpectedHypervolumeUtility
502
+ ):
503
+ raise TypeError("exploit_utility must be exact")
504
+ exploit_utility.__post_init__()
505
+ if type(bridge_utility) is not ResidualTargetClosurePortfolioUtility:
506
+ raise TypeError("bridge_utility must be exact")
507
+ bridge_utility.__post_init__()
508
+ if type(exploit_slots) is not int or exploit_slots <= 0:
509
+ raise ValueError("exploit_slots must be a positive exact integer")
510
+ for name, value in (
511
+ ("bridge_slots", bridge_slots),
512
+ ("probe_slots", probe_slots),
513
+ ):
514
+ if type(value) is not int or not 0 <= value <= 1:
515
+ raise ValueError(f"{name} must be zero or one")
516
+ if exploit_slots + bridge_slots + probe_slots > 8:
517
+ raise ValueError("role-factorized portfolios are bounded to eight")
518
+
519
+ quantiles = (
520
+ ForecastQuantile.P10,
521
+ ForecastQuantile.P50,
522
+ ForecastQuantile.P90,
523
+ )
524
+ exploit_raw: list[dict[str, float]] = []
525
+ bridge_raw: list[dict[str, float]] = []
526
+ for quantile in quantiles:
527
+ exploit_values: dict[str, float] = {}
528
+ bridge_values: dict[str, float] = {}
529
+ for option_id in eligible_option_ids:
530
+ member = by_id[option_id]
531
+ query = ForecastPortfolioUtilityInput(
532
+ optimization_semantics=forecast_request.optimization_semantics,
533
+ parent_metric_values=forecast_request.parent_metric_values,
534
+ metric_scales=forecast_request.metric_scales,
535
+ members=(member,),
536
+ quantile=quantile,
537
+ )
538
+ exploit_values[option_id] = exploit_utility(query)
539
+ bridge_values[option_id] = bridge_utility(query)
540
+ exploit_raw.append(exploit_values)
541
+ bridge_raw.append(bridge_values)
542
+ exploit_ranks = tuple(_midrank_scores(value) for value in exploit_raw)
543
+ bridge_ranks = tuple(_midrank_scores(value) for value in bridge_raw)
544
+
545
+ probe_raw: dict[str, float] = {}
546
+ target_forecast_ids = {
547
+ value.forecast_metric_id for value in exploit_utility.aliases
548
+ } or set(exploit_utility.target.metric_ids)
549
+ for option_id in eligible_option_ids:
550
+ member = by_id[option_id]
551
+ metric_by_id = {
552
+ value.metric_id: value for value in member.metric_forecasts
553
+ }
554
+ if not target_forecast_ids.issubset(metric_by_id):
555
+ raise ValueError("forecast omits a target metric for probing")
556
+ probe_raw[option_id] = 1.0 - min(
557
+ metric_by_id[metric_id].confidence
558
+ for metric_id in target_forecast_ids
559
+ )
560
+ probe_ranks = _midrank_scores(probe_raw)
561
+
562
+ score_rows = tuple(
563
+ RoleScoreRow(
564
+ option_id=option_id,
565
+ exploit_rank_scores=tuple(
566
+ values[option_id] for values in exploit_ranks
567
+ ), # type: ignore[arg-type]
568
+ bridge_rank_scores=tuple(
569
+ values[option_id] for values in bridge_ranks
570
+ ), # type: ignore[arg-type]
571
+ probe_rank_score=probe_ranks[option_id],
572
+ )
573
+ for option_id in eligible_option_ids
574
+ )
575
+ denominators: list[tuple[float, ...]] = []
576
+ for values in exploit_raw:
577
+ ordered = sorted(values.values(), reverse=True)
578
+ cumulative = []
579
+ total = 0.0
580
+ for index in range(exploit_slots):
581
+ total += ordered[index] if index < len(ordered) else 0.0
582
+ cumulative.append(float(total))
583
+ denominators.append(tuple(cumulative))
584
+ eligible_sha256 = hashlib.sha256(
585
+ _ELIGIBLE_DOMAIN
586
+ + _canonical_json({"eligible_option_ids": list(eligible_option_ids)})
587
+ ).hexdigest()
588
+ return RoleFactorizedActionPortfolioUtility(
589
+ exploit_utility=exploit_utility,
590
+ bridge_utility=bridge_utility,
591
+ forecast_receipt_sha256=forecasts.receipt_sha256,
592
+ eligible_option_ids_sha256=eligible_sha256,
593
+ score_rows=score_rows,
594
+ exploit_denominators=tuple(denominators),
595
+ exploit_slots=exploit_slots,
596
+ bridge_slots=bridge_slots,
597
+ probe_slots=probe_slots,
598
+ )
599
+
600
+
601
+ def audit_role_factorized_action_portfolio(
602
+ *,
603
+ utility: RoleFactorizedActionPortfolioUtility,
604
+ forecast_request: ActionForecastRequest,
605
+ forecasts: ResolvedActionForecastBatch,
606
+ selected_option_ids: tuple[str, ...],
607
+ ) -> tuple[RoleAssignmentAudit, ...]:
608
+ """Explain a final portfolio at all forecast quantiles without outcomes."""
609
+
610
+ if type(utility) is not RoleFactorizedActionPortfolioUtility:
611
+ raise TypeError("utility must be exact")
612
+ utility.__post_init__()
613
+ if type(forecast_request) is not ActionForecastRequest:
614
+ raise TypeError("forecast_request must be exact")
615
+ forecast_request.__post_init__()
616
+ if type(forecasts) is not ResolvedActionForecastBatch:
617
+ raise TypeError("forecasts must be exact")
618
+ validate_resolved_action_forecasts(forecast_request, forecasts)
619
+ if forecasts.receipt_sha256 != utility.forecast_receipt_sha256:
620
+ raise ValueError("utility belongs to a foreign forecast receipt")
621
+ if (
622
+ type(selected_option_ids) is not tuple
623
+ or selected_option_ids != tuple(sorted(set(selected_option_ids)))
624
+ or len(selected_option_ids) != utility.portfolio_size
625
+ ):
626
+ raise ValueError(
627
+ "selected_option_ids must be one complete canonical role portfolio"
628
+ )
629
+ by_id = {value.option_id: value for value in forecasts.forecasts}
630
+ if not set(selected_option_ids).issubset(by_id):
631
+ raise ValueError("selected_option_ids contains a foreign option")
632
+ members = tuple(
633
+ sorted(
634
+ (by_id[option_id] for option_id in selected_option_ids),
635
+ key=lambda value: (value.option_identity_sha256, value.option_id),
636
+ )
637
+ )
638
+ audits: list[RoleAssignmentAudit] = []
639
+ for quantile in (
640
+ ForecastQuantile.P10,
641
+ ForecastQuantile.P50,
642
+ ForecastQuantile.P90,
643
+ ):
644
+ request = ForecastPortfolioUtilityInput(
645
+ optimization_semantics=forecast_request.optimization_semantics,
646
+ parent_metric_values=forecast_request.parent_metric_values,
647
+ metric_scales=forecast_request.metric_scales,
648
+ members=members,
649
+ quantile=quantile,
650
+ )
651
+ assignments = tuple(
652
+ sorted(
653
+ utility.assign_roles(request),
654
+ key=lambda value: value.option_id,
655
+ )
656
+ )
657
+ audits.append(
658
+ RoleAssignmentAudit(
659
+ utility_definition_sha256=utility.binding_definition_sha256,
660
+ forecast_receipt_sha256=forecasts.receipt_sha256,
661
+ quantile=quantile,
662
+ assignments=assignments,
663
+ utility_value=utility(request),
664
+ )
665
+ )
666
+ return tuple(audits)
667
+
668
+
669
+ __all__ = [
670
+ "ActionAcquisitionRole",
671
+ "ROLE_FACTORIZED_ACTION_UTILITY_DEFINITION_SHA256",
672
+ "ROLE_FACTORIZED_ACTION_UTILITY_ID",
673
+ "ROLE_FACTORIZED_ACTION_UTILITY_VERSION",
674
+ "RoleAssignmentAudit",
675
+ "RoleAssignmentMember",
676
+ "RoleFactorizedActionPortfolioUtility",
677
+ "RoleScoreRow",
678
+ "audit_role_factorized_action_portfolio",
679
+ "build_role_factorized_action_utility",
680
+ ]