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,714 @@
1
+ """Outcome-blind candidate opportunity against an observed archive prefix.
2
+
3
+ Forecast geometry is sealed before the current candidates are evaluated.
4
+ After each real evaluation wave, this policy may observe only the accepted
5
+ prefix and recompute the conditional archive value of every still-unobserved
6
+ forecast. Workload semantics remain behind the injected archive-utility port.
7
+
8
+ The result is a recommendation, not evaluation authority. A caller can keep
9
+ an existing controller as a protected fallback whenever this policy abstains.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import hashlib
15
+ import json
16
+ import math
17
+ import re
18
+ from dataclasses import dataclass, field
19
+ from typing import Protocol, runtime_checkable
20
+
21
+ from agent_evolve.application.agentic_evolution import EvolutionCandidate
22
+ from agent_evolve.application.candidate_archive_consequence import (
23
+ CandidateArchivePortfolioConsequenceUtilityPort,
24
+ validate_candidate_archive_portfolio_consequence_utility,
25
+ )
26
+ from agent_evolve.application.forecast_geometry_portfolio import (
27
+ MaterializedForecastGeometryBatch,
28
+ MaterializedForecastGeometryMember,
29
+ )
30
+ from agent_evolve.application.prequential_archive_opportunity_calibration import (
31
+ ArchiveOpportunityActionContext,
32
+ ArchiveOpportunityCalibrationResult,
33
+ )
34
+ from agent_evolve.domain.patch import require_sha256
35
+
36
+
37
+ CURRENT_PREFIX_FORECAST_OPPORTUNITY_POLICY_ID = (
38
+ "current_prefix_forecast_opportunity"
39
+ )
40
+ CURRENT_PREFIX_FORECAST_OPPORTUNITY_POLICY_VERSION = 1
41
+ _TOKEN = re.compile(r"^[a-z][a-z0-9_.:-]{0,255}$")
42
+ _POLICY_DOMAIN = b"agent-evolve:current-prefix-opportunity-policy:v1\x00"
43
+ _ARCHIVE_DOMAIN = b"agent-evolve:current-prefix-opportunity-archive:v1\x00"
44
+ _SCORE_DOMAIN = b"agent-evolve:current-prefix-opportunity-score:v1\x00"
45
+ _RANKING_DOMAIN = b"agent-evolve:current-prefix-opportunity-ranking:v1\x00"
46
+
47
+
48
+ def _canonical_json(value: object) -> bytes:
49
+ return json.dumps(
50
+ value,
51
+ allow_nan=False,
52
+ ensure_ascii=True,
53
+ separators=(",", ":"),
54
+ sort_keys=True,
55
+ ).encode("ascii", errors="strict")
56
+
57
+
58
+ def _hash(domain: bytes, value: object) -> str:
59
+ return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
60
+
61
+
62
+ def _require_token(value: str, *, name: str) -> None:
63
+ if type(value) is not str or _TOKEN.fullmatch(value) is None:
64
+ raise ValueError(f"{name} must use the closed token grammar")
65
+
66
+
67
+ def _candidate_record(candidate: EvolutionCandidate) -> dict[str, object]:
68
+ candidate.__post_init__()
69
+ return {
70
+ "candidate_id": candidate.candidate_id.value,
71
+ "configuration_sha256": candidate.occurrence.configuration_hash,
72
+ "generation": candidate.generation,
73
+ "valid": candidate.valid,
74
+ "operator_compliant": candidate.operator_compliant,
75
+ "evidence_compliant": candidate.evidence_compliant,
76
+ "objectives": [
77
+ {"metric_id": metric_id, "value_hex": value.hex()}
78
+ for metric_id, value in candidate.objectives
79
+ ],
80
+ }
81
+
82
+
83
+ def _archive_sha256(
84
+ prior_candidates: tuple[EvolutionCandidate, ...],
85
+ current_prefix_candidates: tuple[EvolutionCandidate, ...],
86
+ ) -> str:
87
+ return _hash(
88
+ _ARCHIVE_DOMAIN,
89
+ {
90
+ "prior": [
91
+ _candidate_record(value)
92
+ for value in sorted(
93
+ prior_candidates,
94
+ key=lambda item: item.candidate_id.value,
95
+ )
96
+ ],
97
+ "current_prefix": [
98
+ _candidate_record(value)
99
+ for value in sorted(
100
+ current_prefix_candidates,
101
+ key=lambda item: item.candidate_id.value,
102
+ )
103
+ ],
104
+ },
105
+ )
106
+
107
+
108
+ @dataclass(frozen=True, slots=True)
109
+ class CurrentPrefixForecastOpportunityScore:
110
+ """Authenticated candidate-specific conditional opportunity evidence."""
111
+
112
+ action_sha256: str
113
+ phenotype_identity_sha256: str
114
+ reliability: float
115
+ adverse_gain: float
116
+ central_gain: float
117
+ favorable_gain: float
118
+ robust_gain: float
119
+ exploration_gain: float
120
+ acquisition_value: float
121
+ abstained: bool
122
+ abstention_reason: str | None
123
+ source_member_sha256: str
124
+ raw_acquisition_value: float | None = None
125
+ calibration_result: ArchiveOpportunityCalibrationResult | None = field(
126
+ default=None,
127
+ repr=False,
128
+ compare=False,
129
+ )
130
+ score_sha256: str = field(init=False)
131
+
132
+ def __post_init__(self) -> None:
133
+ require_sha256(self.action_sha256, "action_sha256")
134
+ require_sha256(
135
+ self.phenotype_identity_sha256,
136
+ "phenotype_identity_sha256",
137
+ )
138
+ require_sha256(self.source_member_sha256, "source_member_sha256")
139
+ if (
140
+ type(self.reliability) is not float
141
+ or not math.isfinite(self.reliability)
142
+ or not 0.0 <= self.reliability <= 1.0
143
+ ):
144
+ raise ValueError("reliability must lie in [0, 1]")
145
+ for name in (
146
+ "adverse_gain",
147
+ "central_gain",
148
+ "favorable_gain",
149
+ "robust_gain",
150
+ "exploration_gain",
151
+ "acquisition_value",
152
+ ):
153
+ value = getattr(self, name)
154
+ if type(value) is not float or not math.isfinite(value) or value < 0.0:
155
+ raise ValueError(f"{name} must be finite and non-negative")
156
+ if type(self.abstained) is not bool:
157
+ raise TypeError("abstained must be exact")
158
+ if self.abstained:
159
+ if self.abstention_reason is None:
160
+ raise ValueError("an abstention must have a reason")
161
+ _require_token(self.abstention_reason, name="abstention_reason")
162
+ elif self.abstention_reason is not None:
163
+ raise ValueError("a recommendation cannot have an abstention reason")
164
+ if (self.raw_acquisition_value is None) != (
165
+ self.calibration_result is None
166
+ ):
167
+ raise ValueError(
168
+ "raw acquisition and calibration result must be jointly present"
169
+ )
170
+ if self.calibration_result is not None:
171
+ if (
172
+ type(self.calibration_result)
173
+ is not ArchiveOpportunityCalibrationResult
174
+ ):
175
+ raise TypeError("calibration_result must be exact")
176
+ self.calibration_result.__post_init__()
177
+ raw_acquisition_valid = (
178
+ type(self.raw_acquisition_value) is float
179
+ and math.isfinite(self.raw_acquisition_value)
180
+ and self.raw_acquisition_value >= 0.0
181
+ )
182
+ if not raw_acquisition_valid:
183
+ raise ValueError(
184
+ "raw_acquisition_value must be finite and non-negative"
185
+ )
186
+ if (
187
+ self.calibration_result.action_sha256
188
+ != self.action_sha256
189
+ or not math.isclose(
190
+ self.acquisition_value,
191
+ self.calibration_result.calibrated_acquisition_value,
192
+ rel_tol=1e-12,
193
+ abs_tol=1e-15,
194
+ )
195
+ ):
196
+ raise ValueError(
197
+ "calibration result differs from the scored action"
198
+ )
199
+ object.__setattr__(
200
+ self,
201
+ "score_sha256",
202
+ _hash(_SCORE_DOMAIN, self._unsigned_record()),
203
+ )
204
+
205
+ def _unsigned_record(self) -> dict[str, object]:
206
+ record: dict[str, object] = {
207
+ "schema_version": 1,
208
+ "action_sha256": self.action_sha256,
209
+ "phenotype_identity_sha256": self.phenotype_identity_sha256,
210
+ "reliability_hex": self.reliability.hex(),
211
+ "adverse_gain_hex": self.adverse_gain.hex(),
212
+ "central_gain_hex": self.central_gain.hex(),
213
+ "favorable_gain_hex": self.favorable_gain.hex(),
214
+ "robust_gain_hex": self.robust_gain.hex(),
215
+ "exploration_gain_hex": self.exploration_gain.hex(),
216
+ "acquisition_value_hex": self.acquisition_value.hex(),
217
+ "abstained": self.abstained,
218
+ "abstention_reason": self.abstention_reason,
219
+ "source_member_sha256": self.source_member_sha256,
220
+ "eligible_candidate_outcome_observed": False,
221
+ }
222
+ if self.calibration_result is not None:
223
+ record["schema_version"] = 2
224
+ record["raw_acquisition_value_hex"] = (
225
+ self.raw_acquisition_value.hex()
226
+ )
227
+ record["calibration_result_sha256"] = (
228
+ self.calibration_result.result_sha256
229
+ )
230
+ return record
231
+
232
+ def to_record(self) -> dict[str, object]:
233
+ self.__post_init__()
234
+ result = {
235
+ **self._unsigned_record(),
236
+ "score_sha256": self.score_sha256,
237
+ }
238
+ if self.calibration_result is not None:
239
+ result["calibration_result"] = (
240
+ self.calibration_result.to_record()
241
+ )
242
+ return result
243
+
244
+
245
+ @dataclass(frozen=True, slots=True)
246
+ class CurrentPrefixForecastOpportunityRanking:
247
+ """One cutoff-bound ranking over an unobserved sealed action market."""
248
+
249
+ policy_id: str
250
+ policy_version: int
251
+ policy_definition_sha256: str
252
+ geometry_batch_sha256: str
253
+ archive_sha256: str
254
+ consumed_action_sha256s: tuple[str, ...]
255
+ eligible_action_sha256s: tuple[str, ...]
256
+ scores: tuple[CurrentPrefixForecastOpportunityScore, ...]
257
+ recommended_action_sha256s: tuple[str, ...]
258
+ current_prefix_outcomes_observed: bool
259
+ eligible_candidate_outcomes_observed: bool
260
+ ranking_sha256: str = field(init=False)
261
+
262
+ def __post_init__(self) -> None:
263
+ _require_token(self.policy_id, name="policy_id")
264
+ if type(self.policy_version) is not int or self.policy_version <= 0:
265
+ raise ValueError("policy_version must be positive")
266
+ for value, name in (
267
+ (self.policy_definition_sha256, "policy_definition_sha256"),
268
+ (self.geometry_batch_sha256, "geometry_batch_sha256"),
269
+ (self.archive_sha256, "archive_sha256"),
270
+ ):
271
+ require_sha256(value, name)
272
+ for values, name in (
273
+ (self.consumed_action_sha256s, "consumed_action_sha256s"),
274
+ (self.eligible_action_sha256s, "eligible_action_sha256s"),
275
+ (self.recommended_action_sha256s, "recommended_action_sha256s"),
276
+ ):
277
+ if type(values) is not tuple or values != tuple(sorted(set(values))):
278
+ raise ValueError(f"{name} must be unique and canonical")
279
+ for value in values:
280
+ require_sha256(value, name[:-1])
281
+ if (
282
+ type(self.scores) is not tuple
283
+ or any(
284
+ type(value) is not CurrentPrefixForecastOpportunityScore
285
+ for value in self.scores
286
+ )
287
+ ):
288
+ raise TypeError("scores must contain exact opportunity scores")
289
+ for value in self.scores:
290
+ value.__post_init__()
291
+ action_ids = tuple(value.action_sha256 for value in self.scores)
292
+ if action_ids != tuple(sorted(set(action_ids))):
293
+ raise ValueError("scores must be action-canonical")
294
+ if action_ids != self.eligible_action_sha256s:
295
+ raise ValueError("scores must cover the exact eligible market")
296
+ if not set(self.recommended_action_sha256s) <= set(action_ids):
297
+ raise ValueError("recommendations escape the eligible market")
298
+ score_by_action = {
299
+ value.action_sha256: value for value in self.scores
300
+ }
301
+ if any(
302
+ score_by_action[action_sha256].abstained
303
+ for action_sha256 in self.recommended_action_sha256s
304
+ ):
305
+ raise ValueError("recommendations cannot include abstentions")
306
+ recommended_phenotypes = tuple(
307
+ score_by_action[value].phenotype_identity_sha256
308
+ for value in self.recommended_action_sha256s
309
+ )
310
+ if len(recommended_phenotypes) != len(set(recommended_phenotypes)):
311
+ raise ValueError("recommendations repeat a phenotype")
312
+ if type(self.current_prefix_outcomes_observed) is not bool:
313
+ raise TypeError("current_prefix_outcomes_observed must be exact")
314
+ if type(self.eligible_candidate_outcomes_observed) is not bool:
315
+ raise TypeError("eligible_candidate_outcomes_observed must be exact")
316
+ if self.eligible_candidate_outcomes_observed:
317
+ raise ValueError("eligible candidate outcomes must remain hidden")
318
+ object.__setattr__(
319
+ self,
320
+ "ranking_sha256",
321
+ _hash(_RANKING_DOMAIN, self._unsigned_record()),
322
+ )
323
+
324
+ def _unsigned_record(self) -> dict[str, object]:
325
+ return {
326
+ "schema_version": 1,
327
+ "policy": {
328
+ "policy_id": self.policy_id,
329
+ "policy_version": self.policy_version,
330
+ "definition_sha256": self.policy_definition_sha256,
331
+ },
332
+ "geometry_batch_sha256": self.geometry_batch_sha256,
333
+ "archive_sha256": self.archive_sha256,
334
+ "consumed_action_sha256s": list(self.consumed_action_sha256s),
335
+ "eligible_action_sha256s": list(self.eligible_action_sha256s),
336
+ "score_sha256s": [value.score_sha256 for value in self.scores],
337
+ "recommended_action_sha256s": list(
338
+ self.recommended_action_sha256s
339
+ ),
340
+ "current_prefix_outcomes_observed": (
341
+ self.current_prefix_outcomes_observed
342
+ ),
343
+ "eligible_candidate_outcomes_observed": (
344
+ self.eligible_candidate_outcomes_observed
345
+ ),
346
+ }
347
+
348
+ def to_record(self, *, include_scores: bool = False) -> dict[str, object]:
349
+ self.__post_init__()
350
+ result = {
351
+ **self._unsigned_record(),
352
+ "ranking_sha256": self.ranking_sha256,
353
+ }
354
+ if include_scores:
355
+ result["scores"] = [value.to_record() for value in self.scores]
356
+ return result
357
+
358
+
359
+ @runtime_checkable
360
+ class CurrentPrefixForecastOpportunityPolicyPort(Protocol):
361
+ """Inverted API for raw or calibrated current-prefix opportunity."""
362
+
363
+ policy_id: str
364
+ policy_version: int
365
+ definition_sha256: str
366
+
367
+ def rank(
368
+ self,
369
+ *,
370
+ prior_candidates: tuple[EvolutionCandidate, ...],
371
+ current_prefix_candidates: tuple[EvolutionCandidate, ...],
372
+ geometry: MaterializedForecastGeometryBatch,
373
+ consumed_action_sha256s: tuple[str, ...] = (),
374
+ eligible_action_sha256s: tuple[str, ...] | None = None,
375
+ recommendation_count: int = 1,
376
+ action_contexts: tuple[
377
+ ArchiveOpportunityActionContext,
378
+ ...,
379
+ ] = (),
380
+ ) -> CurrentPrefixForecastOpportunityRanking: ...
381
+
382
+
383
+ def validate_current_prefix_forecast_opportunity_policy(
384
+ value: CurrentPrefixForecastOpportunityPolicyPort,
385
+ ) -> tuple[str, int, str]:
386
+ if not isinstance(
387
+ value,
388
+ CurrentPrefixForecastOpportunityPolicyPort,
389
+ ):
390
+ raise TypeError(
391
+ "opportunity policy must implement its application port"
392
+ )
393
+ identity = (
394
+ value.policy_id,
395
+ value.policy_version,
396
+ value.definition_sha256,
397
+ )
398
+ _require_token(identity[0], name="opportunity policy_id")
399
+ if type(identity[1]) is not int or identity[1] <= 0:
400
+ raise ValueError("opportunity policy_version must be positive")
401
+ require_sha256(identity[2], "opportunity policy definition_sha256")
402
+ return identity
403
+
404
+
405
+ @dataclass(frozen=True, slots=True)
406
+ class CurrentPrefixForecastOpportunityPolicy:
407
+ """Rank forecasts by conditional archive lift after an observed prefix."""
408
+
409
+ archive_utility: CandidateArchivePortfolioConsequenceUtilityPort = field(
410
+ repr=False,
411
+ compare=False,
412
+ )
413
+ central_scenario_id: str = "median"
414
+ adverse_scenario_id: str = "adverse"
415
+ favorable_scenario_id: str = "favorable"
416
+ risk_aversion: float = 0.25
417
+ exploration_weight: float = 0.0
418
+ minimum_reliability: float = 0.0
419
+ minimum_acquisition_value: float = 0.0
420
+ policy_id: str = CURRENT_PREFIX_FORECAST_OPPORTUNITY_POLICY_ID
421
+ policy_version: int = CURRENT_PREFIX_FORECAST_OPPORTUNITY_POLICY_VERSION
422
+ definition_sha256: str = field(init=False)
423
+
424
+ def __post_init__(self) -> None:
425
+ utility_identity = (
426
+ validate_candidate_archive_portfolio_consequence_utility(
427
+ self.archive_utility
428
+ )
429
+ )
430
+ for value, name in (
431
+ (self.central_scenario_id, "central_scenario_id"),
432
+ (self.adverse_scenario_id, "adverse_scenario_id"),
433
+ (self.favorable_scenario_id, "favorable_scenario_id"),
434
+ (self.policy_id, "policy_id"),
435
+ ):
436
+ _require_token(value, name=name)
437
+ if self.policy_id != CURRENT_PREFIX_FORECAST_OPPORTUNITY_POLICY_ID:
438
+ raise ValueError("policy_id is immutable")
439
+ if self.policy_version != CURRENT_PREFIX_FORECAST_OPPORTUNITY_POLICY_VERSION:
440
+ raise ValueError("policy_version is immutable")
441
+ for name in (
442
+ "risk_aversion",
443
+ "exploration_weight",
444
+ "minimum_acquisition_value",
445
+ ):
446
+ value = getattr(self, name)
447
+ if type(value) is not float or not math.isfinite(value) or value < 0.0:
448
+ raise ValueError(f"{name} must be finite and non-negative")
449
+ if (
450
+ type(self.minimum_reliability) is not float
451
+ or not math.isfinite(self.minimum_reliability)
452
+ or not 0.0 <= self.minimum_reliability <= 1.0
453
+ ):
454
+ raise ValueError("minimum_reliability must lie in [0, 1]")
455
+ object.__setattr__(
456
+ self,
457
+ "definition_sha256",
458
+ _hash(
459
+ _POLICY_DOMAIN,
460
+ {
461
+ "schema_version": 1,
462
+ "policy_id": self.policy_id,
463
+ "policy_version": self.policy_version,
464
+ "archive_utility": {
465
+ "utility_id": utility_identity[0],
466
+ "utility_version": utility_identity[1],
467
+ "definition_sha256": utility_identity[2],
468
+ },
469
+ "central_scenario_id": self.central_scenario_id,
470
+ "adverse_scenario_id": self.adverse_scenario_id,
471
+ "favorable_scenario_id": self.favorable_scenario_id,
472
+ "risk_aversion_hex": self.risk_aversion.hex(),
473
+ "exploration_weight_hex": self.exploration_weight.hex(),
474
+ "minimum_reliability_hex": self.minimum_reliability.hex(),
475
+ "minimum_acquisition_value_hex": (
476
+ self.minimum_acquisition_value.hex()
477
+ ),
478
+ "selection_currency": (
479
+ "current_prefix_conditional_archive_opportunity"
480
+ ),
481
+ "eligible_candidate_outcomes_observed": False,
482
+ "workload_model_provider_branches": False,
483
+ },
484
+ ),
485
+ )
486
+
487
+ def _gain(
488
+ self,
489
+ archive: tuple[EvolutionCandidate, ...],
490
+ member: MaterializedForecastGeometryMember,
491
+ scenario_id: str,
492
+ ) -> float:
493
+ result = self.archive_utility.portfolio_marginal_utility(
494
+ archive,
495
+ (member.scenario(scenario_id).as_mapping(),),
496
+ )
497
+ if type(result) is not float or not math.isfinite(result) or result < 0.0:
498
+ raise ValueError("archive utility returned an invalid opportunity")
499
+ return result
500
+
501
+ def rank(
502
+ self,
503
+ *,
504
+ prior_candidates: tuple[EvolutionCandidate, ...],
505
+ current_prefix_candidates: tuple[EvolutionCandidate, ...],
506
+ geometry: MaterializedForecastGeometryBatch,
507
+ consumed_action_sha256s: tuple[str, ...] = (),
508
+ eligible_action_sha256s: tuple[str, ...] | None = None,
509
+ recommendation_count: int = 1,
510
+ action_contexts: tuple[
511
+ ArchiveOpportunityActionContext,
512
+ ...,
513
+ ] = (),
514
+ ) -> CurrentPrefixForecastOpportunityRanking:
515
+ """Score only unobserved actions against the real accepted prefix."""
516
+
517
+ self.__post_init__()
518
+ for values, name in (
519
+ (prior_candidates, "prior_candidates"),
520
+ (current_prefix_candidates, "current_prefix_candidates"),
521
+ ):
522
+ if (
523
+ type(values) is not tuple
524
+ or any(type(value) is not EvolutionCandidate for value in values)
525
+ ):
526
+ raise TypeError(f"{name} must be an exact candidate tuple")
527
+ for value in values:
528
+ value.__post_init__()
529
+ archive = (*prior_candidates, *current_prefix_candidates)
530
+ candidate_ids = tuple(value.candidate_id for value in archive)
531
+ if len(candidate_ids) != len(set(candidate_ids)):
532
+ raise ValueError("prior and current-prefix candidates overlap")
533
+ if type(geometry) is not MaterializedForecastGeometryBatch:
534
+ raise TypeError("geometry must be an exact batch")
535
+ geometry.__post_init__()
536
+ all_action_ids = tuple(value.action_sha256 for value in geometry.members)
537
+ if (
538
+ type(consumed_action_sha256s) is not tuple
539
+ or consumed_action_sha256s
540
+ != tuple(sorted(set(consumed_action_sha256s)))
541
+ ):
542
+ raise ValueError("consumed action hashes must be unique and canonical")
543
+ for value in consumed_action_sha256s:
544
+ require_sha256(value, "consumed_action_sha256")
545
+ if not set(consumed_action_sha256s) <= set(all_action_ids):
546
+ raise ValueError("consumed actions escape the sealed geometry")
547
+ member_by_action = {
548
+ value.action_sha256: value for value in geometry.members
549
+ }
550
+ consumed_phenotypes = {
551
+ member_by_action[value].phenotype_identity_sha256
552
+ for value in consumed_action_sha256s
553
+ }
554
+ eligible = (
555
+ tuple(
556
+ value
557
+ for value in all_action_ids
558
+ if (
559
+ value not in set(consumed_action_sha256s)
560
+ and member_by_action[
561
+ value
562
+ ].phenotype_identity_sha256 not in consumed_phenotypes
563
+ )
564
+ )
565
+ if eligible_action_sha256s is None
566
+ else eligible_action_sha256s
567
+ )
568
+ if type(eligible) is not tuple or eligible != tuple(sorted(set(eligible))):
569
+ raise ValueError("eligible action hashes must be unique and canonical")
570
+ for value in eligible:
571
+ require_sha256(value, "eligible_action_sha256")
572
+ if not set(eligible) <= set(all_action_ids) - set(consumed_action_sha256s):
573
+ raise ValueError("eligible actions are not unconsumed sealed actions")
574
+ if any(
575
+ member_by_action[value].phenotype_identity_sha256
576
+ in consumed_phenotypes
577
+ for value in eligible
578
+ ):
579
+ raise ValueError("eligible actions repeat a consumed phenotype")
580
+ if type(recommendation_count) is not int or recommendation_count < 0:
581
+ raise ValueError("recommendation_count must be non-negative")
582
+ if (
583
+ type(action_contexts) is not tuple
584
+ or any(
585
+ type(value) is not ArchiveOpportunityActionContext
586
+ for value in action_contexts
587
+ )
588
+ ):
589
+ raise TypeError(
590
+ "action_contexts must contain exact generic contexts"
591
+ )
592
+ for value in action_contexts:
593
+ value.__post_init__()
594
+ context_action_ids = tuple(
595
+ value.action_sha256 for value in action_contexts
596
+ )
597
+ if context_action_ids and context_action_ids != tuple(
598
+ sorted(set(context_action_ids))
599
+ ):
600
+ raise ValueError(
601
+ "action_contexts must be unique and action canonical"
602
+ )
603
+ if context_action_ids and set(context_action_ids) != set(eligible):
604
+ raise ValueError(
605
+ "action_contexts must cover the exact eligible market"
606
+ )
607
+
608
+ required_scenarios = {
609
+ self.central_scenario_id,
610
+ self.adverse_scenario_id,
611
+ self.favorable_scenario_id,
612
+ }
613
+ scores: list[CurrentPrefixForecastOpportunityScore] = []
614
+ for action_sha256 in eligible:
615
+ member = member_by_action[action_sha256]
616
+ if not required_scenarios <= {
617
+ value.scenario_id for value in member.scenarios
618
+ }:
619
+ raise ValueError("forecast geometry omits an opportunity scenario")
620
+ adverse = self._gain(
621
+ archive,
622
+ member,
623
+ self.adverse_scenario_id,
624
+ )
625
+ central = self._gain(
626
+ archive,
627
+ member,
628
+ self.central_scenario_id,
629
+ )
630
+ favorable = self._gain(
631
+ archive,
632
+ member,
633
+ self.favorable_scenario_id,
634
+ )
635
+ robust = max(
636
+ 0.0,
637
+ central
638
+ - self.risk_aversion * max(0.0, central - adverse),
639
+ )
640
+ exploration = max(0.0, favorable - central)
641
+ acquisition = member.reliability * (
642
+ robust + self.exploration_weight * exploration
643
+ )
644
+ if member.reliability < self.minimum_reliability:
645
+ abstention_reason = "below_reliability_floor"
646
+ elif acquisition <= self.minimum_acquisition_value:
647
+ abstention_reason = "no_identified_conditional_opportunity"
648
+ else:
649
+ abstention_reason = None
650
+ scores.append(
651
+ CurrentPrefixForecastOpportunityScore(
652
+ action_sha256=action_sha256,
653
+ phenotype_identity_sha256=(
654
+ member.phenotype_identity_sha256
655
+ ),
656
+ reliability=member.reliability,
657
+ adverse_gain=float(adverse),
658
+ central_gain=float(central),
659
+ favorable_gain=float(favorable),
660
+ robust_gain=float(robust),
661
+ exploration_gain=float(exploration),
662
+ acquisition_value=float(acquisition),
663
+ abstained=abstention_reason is not None,
664
+ abstention_reason=abstention_reason,
665
+ source_member_sha256=member.member_sha256,
666
+ )
667
+ )
668
+ scores.sort(key=lambda value: value.action_sha256)
669
+ ranked = sorted(
670
+ (value for value in scores if not value.abstained),
671
+ key=lambda value: (
672
+ -value.acquisition_value,
673
+ -value.central_gain,
674
+ -value.reliability,
675
+ value.action_sha256,
676
+ ),
677
+ )
678
+ recommended: list[str] = []
679
+ phenotypes: set[str] = set()
680
+ if recommendation_count:
681
+ for value in ranked:
682
+ if value.phenotype_identity_sha256 in phenotypes:
683
+ continue
684
+ recommended.append(value.action_sha256)
685
+ phenotypes.add(value.phenotype_identity_sha256)
686
+ if len(recommended) == recommendation_count:
687
+ break
688
+ return CurrentPrefixForecastOpportunityRanking(
689
+ policy_id=self.policy_id,
690
+ policy_version=self.policy_version,
691
+ policy_definition_sha256=self.definition_sha256,
692
+ geometry_batch_sha256=geometry.batch_sha256,
693
+ archive_sha256=_archive_sha256(
694
+ prior_candidates,
695
+ current_prefix_candidates,
696
+ ),
697
+ consumed_action_sha256s=consumed_action_sha256s,
698
+ eligible_action_sha256s=eligible,
699
+ scores=tuple(scores),
700
+ recommended_action_sha256s=tuple(sorted(recommended)),
701
+ current_prefix_outcomes_observed=bool(current_prefix_candidates),
702
+ eligible_candidate_outcomes_observed=False,
703
+ )
704
+
705
+
706
+ __all__ = [
707
+ "CURRENT_PREFIX_FORECAST_OPPORTUNITY_POLICY_ID",
708
+ "CURRENT_PREFIX_FORECAST_OPPORTUNITY_POLICY_VERSION",
709
+ "CurrentPrefixForecastOpportunityPolicy",
710
+ "CurrentPrefixForecastOpportunityPolicyPort",
711
+ "CurrentPrefixForecastOpportunityRanking",
712
+ "CurrentPrefixForecastOpportunityScore",
713
+ "validate_current_prefix_forecast_opportunity_policy",
714
+ ]