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,911 @@
1
+ """Hierarchical region-conditional credit with learned forecast trust (R1).
2
+
3
+ Defect D1 (jul28 pareto defect theory): the live broker estimated its
4
+ ``gain``/``positive`` channels at LANE level with n=1, so a single win
5
+ propagated positive=1.0 to every sibling proposal of the lane, and the
6
+ ``forecast_error`` channel was never populated, so anti-calibrated
7
+ forecasts kept full weight. This module replaces the lane-level leaf with
8
+ credit cells keyed by (engine x parent-front-region x radius-or-operator
9
+ class), estimated with the EXISTING Beta-shrinkage machinery in a capped
10
+ three-level hierarchy (cell -> engine -> global), and adds a learned
11
+ forecast-trust channel: per-engine Beta posteriors over forecast direction
12
+ correctness, updated only from (predicted, actual) pairs revealed BEFORE
13
+ the current decision, applied as a demote-only multiplicative weight on
14
+ forecast-derived probability evidence. With no trust evidence the
15
+ multiplier is exactly one, so behavior degrades to the calibrated
16
+ challenger's; measured anti-calibration demotes the forecast channel
17
+ toward zero.
18
+
19
+ This module never modifies the calibrated challenger: it composes over an
20
+ injected ``CalibratedPositiveGainOpportunityPolicy`` (forecast geometry,
21
+ clamping, and score algebra are delegated or mirrored bit-for-bit) and is
22
+ enabled only through config-gated composition (``v9_candidate_policy``).
23
+ The policy knows no workload, objective name, model, provider, or prompt.
24
+ """
25
+
26
+ from __future__ import annotations
27
+
28
+ import hashlib
29
+ import json
30
+ import math
31
+ import re
32
+ from dataclasses import dataclass, field
33
+
34
+ from agent_evolve.application.calibrated_positive_gain_opportunity import (
35
+ CalibratedPositiveGainOpportunityPolicy,
36
+ CalibratedPositiveGainRanking,
37
+ CalibratedPositiveGainScore,
38
+ ObjectivePoint,
39
+ PositiveGainCandidate,
40
+ _beta_posterior_mean,
41
+ _require_objective_point,
42
+ _shrunk_magnitude,
43
+ )
44
+
45
+ REGION_CONDITIONAL_CREDIT_POLICY_ID = "region_conditional_credit"
46
+ REGION_CONDITIONAL_CREDIT_POLICY_VERSION = 1
47
+ _TOKEN = re.compile(r"^[a-z][a-z0-9_.:-]{0,255}$")
48
+ _DEFINITION_DOMAIN = (
49
+ b"agent-evolve:region-conditional-credit-definition:v1\x00"
50
+ )
51
+
52
+ REGION_NO_PARENT = "region.no_parent"
53
+ RADIUS_CLASS_NONE = "radius.none"
54
+ RADIUS_CLASS_SHORT = "radius.short"
55
+ RADIUS_CLASS_MID = "radius.mid"
56
+ RADIUS_CLASS_LONG = "radius.long"
57
+
58
+
59
+ def _canonical_json(value: object) -> bytes:
60
+ return json.dumps(
61
+ value,
62
+ allow_nan=False,
63
+ ensure_ascii=True,
64
+ separators=(",", ":"),
65
+ sort_keys=True,
66
+ ).encode("ascii", errors="strict")
67
+
68
+
69
+ def _hash(domain: bytes, value: object) -> str:
70
+ return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
71
+
72
+
73
+ def _require_token(value: str, *, name: str) -> None:
74
+ if type(value) is not str or _TOKEN.fullmatch(value) is None:
75
+ raise ValueError(f"{name} must use the closed token grammar")
76
+
77
+
78
+ def _point_values(
79
+ point: ObjectivePoint,
80
+ metric_ids: tuple[str, ...],
81
+ ) -> tuple[float, ...]:
82
+ mapping = dict(point)
83
+ if tuple(sorted(mapping)) != metric_ids:
84
+ raise ValueError("objective point uses a foreign metric frame")
85
+ return tuple(mapping[metric_id] for metric_id in metric_ids)
86
+
87
+
88
+ def parent_front_distance(
89
+ archive_points: tuple[ObjectivePoint, ...],
90
+ parent_point: ObjectivePoint,
91
+ ) -> float:
92
+ """Additive-epsilon distance of a parent behind the archive front.
93
+
94
+ ``min over archive points a of max over objectives j of (p_j - a_j)``,
95
+ clamped at zero: the smallest uniform improvement that would move the
96
+ parent onto (or past) some archive point. Zero exactly for parents on
97
+ or beyond the front; dimension-generic and workload-free (operates on
98
+ whatever normalized objective frame the caller uses).
99
+ """
100
+
101
+ _require_objective_point(parent_point, name="parent point")
102
+ if type(archive_points) is not tuple or not archive_points:
103
+ raise ValueError("archive_points must be a non-empty exact tuple")
104
+ metric_ids = tuple(metric_id for metric_id, _value in parent_point)
105
+ parent = _point_values(parent_point, metric_ids)
106
+ best = math.inf
107
+ for point in archive_points:
108
+ _require_objective_point(point, name="archive point")
109
+ values = _point_values(point, metric_ids)
110
+ best = min(
111
+ best,
112
+ max(
113
+ p - a
114
+ for p, a in zip(parent, values, strict=True)
115
+ ),
116
+ )
117
+ return float(max(best, 0.0))
118
+
119
+
120
+ def parent_front_region(
121
+ *,
122
+ archive_points: tuple[ObjectivePoint, ...],
123
+ reference_point: ObjectivePoint,
124
+ parent_point: ObjectivePoint | None,
125
+ near_front_epsilon: float,
126
+ extreme_affinity_threshold: float,
127
+ ) -> str:
128
+ """Classify a parent into a front region token.
129
+
130
+ Region = distance band (near/far by additive-epsilon distance) crossed
131
+ with a wedge: the objective extreme the parent has the strongest
132
+ relative affinity to, or interior when no per-objective affinity is
133
+ strong enough. One wedge per objective plus interior, so the region
134
+ set is dimension-generic (memo R4's wedge construction). Parents are
135
+ absent for archive-seeded candidates: those map to a dedicated token.
136
+ """
137
+
138
+ if parent_point is None:
139
+ return REGION_NO_PARENT
140
+ distance = parent_front_distance(archive_points, parent_point)
141
+ band = "near" if distance <= near_front_epsilon else "far"
142
+ metric_ids = tuple(metric_id for metric_id, _value in parent_point)
143
+ parent = _point_values(parent_point, metric_ids)
144
+ reference = _point_values(reference_point, metric_ids)
145
+ best_per_metric = tuple(
146
+ min(
147
+ _point_values(point, metric_ids)[index]
148
+ for point in archive_points
149
+ )
150
+ for index in range(len(metric_ids))
151
+ )
152
+ affinities: list[tuple[float, str]] = []
153
+ for index, metric_id in enumerate(metric_ids):
154
+ span = reference[index] - best_per_metric[index]
155
+ if span <= 0.0:
156
+ affinity = 0.0
157
+ else:
158
+ affinity = max(
159
+ (parent[index] - best_per_metric[index]) / span,
160
+ 0.0,
161
+ )
162
+ affinities.append((affinity, metric_id))
163
+ affinity, metric_id = min(affinities)
164
+ if affinity <= extreme_affinity_threshold:
165
+ return f"region.{band}.extreme:{metric_id}"
166
+ return f"region.{band}.interior"
167
+
168
+
169
+ def radius_operator_class(
170
+ *,
171
+ radius: int | None,
172
+ operator_class: str | None,
173
+ radius_breakpoints: tuple[int, int],
174
+ ) -> str:
175
+ """Map a move radius (or operator class fallback) into a class token."""
176
+
177
+ short_cap, mid_cap = radius_breakpoints
178
+ if radius is not None:
179
+ if type(radius) is not int or radius < 0:
180
+ raise ValueError("radius must be a non-negative integer")
181
+ if radius <= short_cap:
182
+ return RADIUS_CLASS_SHORT
183
+ if radius <= mid_cap:
184
+ return RADIUS_CLASS_MID
185
+ return RADIUS_CLASS_LONG
186
+ if operator_class is not None:
187
+ _require_token(operator_class, name="operator_class")
188
+ return f"op.{operator_class}"
189
+ return RADIUS_CLASS_NONE
190
+
191
+
192
+ @dataclass(frozen=True, slots=True)
193
+ class RegionFeatures:
194
+ """Outcome-blind provenance features of one market candidate."""
195
+
196
+ parent_point: ObjectivePoint | None = None
197
+ radius: int | None = None
198
+ operator_class: str | None = None
199
+
200
+ def __post_init__(self) -> None:
201
+ if self.parent_point is not None:
202
+ _require_objective_point(
203
+ self.parent_point,
204
+ name="parent point",
205
+ )
206
+ if self.radius is not None and (
207
+ type(self.radius) is not int or self.radius < 0
208
+ ):
209
+ raise ValueError("radius must be a non-negative integer")
210
+ if self.operator_class is not None:
211
+ _require_token(self.operator_class, name="operator_class")
212
+
213
+
214
+ @dataclass(frozen=True, slots=True)
215
+ class RegionConditionalOutcome:
216
+ """One real outcome observed strictly before the current decision.
217
+
218
+ ``region_id`` is None for evidence imported from OUTSIDE the current
219
+ market (warm priors): such outcomes carry no comparable parent
220
+ geometry, so they contribute only to the global and engine levels of
221
+ the hierarchy, never to a leaf cell. Forecast direction fields are
222
+ jointly present exactly when the outcome's candidate carried a
223
+ forecast: ``forecast_predicted_positive`` is whether the forecast's
224
+ central scenario claimed positive archive gain, and
225
+ ``forecast_actual_positive`` whether the realized point achieved
226
+ positive gain against the same base archive.
227
+ """
228
+
229
+ observation_ordinal: int
230
+ engine_id: str
231
+ feasible: bool
232
+ marginal_archive_gain: float
233
+ region_id: str | None = None
234
+ radius_class_id: str | None = None
235
+ forecast_predicted_positive: bool | None = None
236
+ forecast_actual_positive: bool | None = None
237
+
238
+ def __post_init__(self) -> None:
239
+ if (
240
+ type(self.observation_ordinal) is not int
241
+ or self.observation_ordinal <= 0
242
+ ):
243
+ raise ValueError("observation_ordinal must be positive")
244
+ _require_token(self.engine_id, name="engine_id")
245
+ if type(self.feasible) is not bool:
246
+ raise TypeError("feasible must be exact")
247
+ if (
248
+ type(self.marginal_archive_gain) is not float
249
+ or not math.isfinite(self.marginal_archive_gain)
250
+ or self.marginal_archive_gain < 0.0
251
+ ):
252
+ raise ValueError(
253
+ "marginal_archive_gain must be finite and non-negative"
254
+ )
255
+ if not self.feasible and self.marginal_archive_gain != 0.0:
256
+ raise ValueError("an infeasible outcome cannot contribute gain")
257
+ if (self.region_id is None) != (self.radius_class_id is None):
258
+ raise ValueError(
259
+ "region and radius class must be jointly present or absent"
260
+ )
261
+ if self.region_id is not None:
262
+ _require_token(self.region_id, name="region_id")
263
+ _require_token(
264
+ self.radius_class_id,
265
+ name="radius_class_id",
266
+ )
267
+ forecast_fields = (
268
+ self.forecast_predicted_positive,
269
+ self.forecast_actual_positive,
270
+ )
271
+ if any(value is None for value in forecast_fields) != all(
272
+ value is None for value in forecast_fields
273
+ ):
274
+ raise ValueError(
275
+ "forecast direction fields must be jointly present or absent"
276
+ )
277
+ for value in forecast_fields:
278
+ if value is not None and type(value) is not bool:
279
+ raise TypeError("forecast direction fields must be exact")
280
+
281
+ @property
282
+ def positive(self) -> bool:
283
+ return self.marginal_archive_gain > 0.0
284
+
285
+ @property
286
+ def forecast_direction_correct(self) -> bool | None:
287
+ if self.forecast_predicted_positive is None:
288
+ return None
289
+ return (
290
+ self.forecast_predicted_positive
291
+ == self.forecast_actual_positive
292
+ )
293
+
294
+
295
+ @dataclass(frozen=True, slots=True)
296
+ class RegionScoredCandidate:
297
+ """One eligible candidate with its provenance features attached."""
298
+
299
+ candidate: PositiveGainCandidate
300
+ features: RegionFeatures = RegionFeatures()
301
+
302
+ def __post_init__(self) -> None:
303
+ if type(self.candidate) is not PositiveGainCandidate:
304
+ raise TypeError("candidate must be exact")
305
+ self.candidate.__post_init__()
306
+ if type(self.features) is not RegionFeatures:
307
+ raise TypeError("features must be exact")
308
+ self.features.__post_init__()
309
+
310
+
311
+ @dataclass(frozen=True, slots=True)
312
+ class RegionCreditConfig:
313
+ """All R1 constants; every value is an exact dyadic float."""
314
+
315
+ near_front_epsilon: float = 0.125
316
+ extreme_affinity_threshold: float = 0.25
317
+ radius_breakpoints: tuple[int, int] = (1, 3)
318
+ forecast_trust_prior: float = 0.5
319
+
320
+ def __post_init__(self) -> None:
321
+ for name in ("near_front_epsilon", "extreme_affinity_threshold"):
322
+ value = getattr(self, name)
323
+ if (
324
+ type(value) is not float
325
+ or not math.isfinite(value)
326
+ or value < 0.0
327
+ ):
328
+ raise ValueError(
329
+ f"{name} must be finite and non-negative"
330
+ )
331
+ if (
332
+ type(self.radius_breakpoints) is not tuple
333
+ or len(self.radius_breakpoints) != 2
334
+ or any(
335
+ type(value) is not int or value < 0
336
+ for value in self.radius_breakpoints
337
+ )
338
+ or not self.radius_breakpoints[0]
339
+ <= self.radius_breakpoints[1]
340
+ ):
341
+ raise ValueError(
342
+ "radius_breakpoints must be two ascending non-negative "
343
+ "integers"
344
+ )
345
+ if (
346
+ type(self.forecast_trust_prior) is not float
347
+ or not math.isfinite(self.forecast_trust_prior)
348
+ or not 0.0 < self.forecast_trust_prior < 1.0
349
+ ):
350
+ raise ValueError(
351
+ "forecast_trust_prior must lie in (0, 1)"
352
+ )
353
+
354
+ def to_record(self) -> dict[str, object]:
355
+ self.__post_init__()
356
+ return {
357
+ "near_front_epsilon_hex": self.near_front_epsilon.hex(),
358
+ "extreme_affinity_threshold_hex": (
359
+ self.extreme_affinity_threshold.hex()
360
+ ),
361
+ "radius_breakpoints": list(self.radius_breakpoints),
362
+ "forecast_trust_prior_hex": (
363
+ self.forecast_trust_prior.hex()
364
+ ),
365
+ }
366
+
367
+
368
+ @dataclass(frozen=True, slots=True)
369
+ class _RegionCellEvidence:
370
+ observation_count: float
371
+ positive_count: float
372
+ feasible_count: float
373
+ positive_gain_sum: float
374
+
375
+
376
+ @dataclass(frozen=True, slots=True)
377
+ class RegionConditionalChallengerPolicy:
378
+ """Score eligible candidates with region-conditional credit.
379
+
380
+ The score algebra is the calibrated positive-gain challenger's,
381
+ bit-for-bit, with exactly two substitutions:
382
+
383
+ * conversion evidence is estimated over the capped hierarchy
384
+ global -> engine -> (engine x region x radius class) instead of
385
+ global -> engine -> (engine x rank band); and
386
+ * the forecast probability weight is multiplied by the engine's
387
+ learned forecast-trust multiplier (demote-only; exactly one with
388
+ no trust evidence).
389
+ """
390
+
391
+ base: CalibratedPositiveGainOpportunityPolicy = field(repr=False)
392
+ credit: RegionCreditConfig = RegionCreditConfig()
393
+ policy_id: str = REGION_CONDITIONAL_CREDIT_POLICY_ID
394
+ policy_version: int = REGION_CONDITIONAL_CREDIT_POLICY_VERSION
395
+ definition_sha256: str = field(init=False)
396
+
397
+ def __post_init__(self) -> None:
398
+ if type(self.base) is not CalibratedPositiveGainOpportunityPolicy:
399
+ raise TypeError(
400
+ "base must be an exact calibrated challenger"
401
+ )
402
+ self.base.__post_init__()
403
+ if type(self.credit) is not RegionCreditConfig:
404
+ raise TypeError("credit must be an exact region config")
405
+ self.credit.__post_init__()
406
+ _require_token(self.policy_id, name="policy_id")
407
+ if (
408
+ self.policy_id != REGION_CONDITIONAL_CREDIT_POLICY_ID
409
+ or self.policy_version
410
+ != REGION_CONDITIONAL_CREDIT_POLICY_VERSION
411
+ ):
412
+ raise ValueError("policy identity is immutable")
413
+ object.__setattr__(
414
+ self,
415
+ "definition_sha256",
416
+ _hash(
417
+ _DEFINITION_DOMAIN,
418
+ {
419
+ "schema_version": 1,
420
+ "policy_id": self.policy_id,
421
+ "policy_version": self.policy_version,
422
+ "base_challenger": {
423
+ "policy_id": self.base.policy_id,
424
+ "policy_version": self.base.policy_version,
425
+ "definition_sha256": (
426
+ self.base.definition_sha256
427
+ ),
428
+ },
429
+ "credit": self.credit.to_record(),
430
+ "conversion_evidence": (
431
+ "prequential_engine_region_radius_cell_"
432
+ "hierarchical_beta_shrinkage_capped_three_levels"
433
+ ),
434
+ "hierarchy": "cell_engine_global",
435
+ "prior_market_evidence_leaf_cells": False,
436
+ "forecast_trust": (
437
+ "per_engine_direction_correct_beta_posterior_"
438
+ "demote_only_multiplier_min_one_two_posterior"
439
+ ),
440
+ "lane_level_n1_credit_propagation": False,
441
+ "hard_abstention": False,
442
+ "eligible_candidate_outcomes_observed": False,
443
+ "workload_objective_model_provider_prompt_branches": (
444
+ False
445
+ ),
446
+ },
447
+ ),
448
+ )
449
+
450
+ def region_for(
451
+ self,
452
+ *,
453
+ archive_points: tuple[ObjectivePoint, ...],
454
+ reference_point: ObjectivePoint,
455
+ features: RegionFeatures,
456
+ ) -> tuple[str, str]:
457
+ """(region token, radius class token) of one candidate."""
458
+
459
+ features.__post_init__()
460
+ return (
461
+ parent_front_region(
462
+ archive_points=archive_points,
463
+ reference_point=reference_point,
464
+ parent_point=features.parent_point,
465
+ near_front_epsilon=self.credit.near_front_epsilon,
466
+ extreme_affinity_threshold=(
467
+ self.credit.extreme_affinity_threshold
468
+ ),
469
+ ),
470
+ radius_operator_class(
471
+ radius=features.radius,
472
+ operator_class=features.operator_class,
473
+ radius_breakpoints=self.credit.radius_breakpoints,
474
+ ),
475
+ )
476
+
477
+ @staticmethod
478
+ def _validated_outcomes(
479
+ observed_outcomes: tuple[RegionConditionalOutcome, ...],
480
+ ) -> tuple[RegionConditionalOutcome, ...]:
481
+ if type(observed_outcomes) is not tuple or any(
482
+ type(value) is not RegionConditionalOutcome
483
+ for value in observed_outcomes
484
+ ):
485
+ raise TypeError(
486
+ "observed_outcomes must contain exact region outcomes"
487
+ )
488
+ ordinals = tuple(
489
+ value.observation_ordinal for value in observed_outcomes
490
+ )
491
+ if ordinals != tuple(sorted(set(ordinals))):
492
+ raise ValueError(
493
+ "observed outcomes must use unique ascending ordinals"
494
+ )
495
+ for value in observed_outcomes:
496
+ value.__post_init__()
497
+ return observed_outcomes
498
+
499
+ def _conversion_evidence(
500
+ self,
501
+ observed_outcomes: tuple[RegionConditionalOutcome, ...],
502
+ ) -> dict[object, _RegionCellEvidence]:
503
+ counts: dict[object, list[float]] = {}
504
+ for value in observed_outcomes:
505
+ keys: list[object] = [None, value.engine_id]
506
+ if value.region_id is not None:
507
+ keys.append(
508
+ (
509
+ value.engine_id,
510
+ value.region_id,
511
+ value.radius_class_id,
512
+ )
513
+ )
514
+ for key in keys:
515
+ row = counts.setdefault(key, [0.0, 0.0, 0.0, 0.0])
516
+ row[0] += 1.0
517
+ row[1] += float(value.positive)
518
+ row[2] += float(value.feasible)
519
+ row[3] += (
520
+ value.marginal_archive_gain
521
+ if value.positive
522
+ else 0.0
523
+ )
524
+ return {
525
+ key: _RegionCellEvidence(
526
+ observation_count=row[0],
527
+ positive_count=row[1],
528
+ feasible_count=row[2],
529
+ positive_gain_sum=row[3],
530
+ )
531
+ for key, row in counts.items()
532
+ }
533
+
534
+ def _hierarchical_estimates(
535
+ self,
536
+ *,
537
+ evidence: dict[object, _RegionCellEvidence],
538
+ engine_id: str,
539
+ region_id: str,
540
+ radius_class_id: str,
541
+ ) -> dict[str, float]:
542
+ empty = _RegionCellEvidence(0.0, 0.0, 0.0, 0.0)
543
+ chain = (
544
+ evidence.get(None, empty),
545
+ evidence.get(engine_id, empty),
546
+ evidence.get(
547
+ (engine_id, region_id, radius_class_id),
548
+ empty,
549
+ ),
550
+ )
551
+ p_positive = self.base.root_prior_probability
552
+ p_feasible = self.base.root_prior_probability
553
+ magnitude = self.base.reference_gain_scale
554
+ for level in chain:
555
+ p_positive = _beta_posterior_mean(
556
+ prior_mean=p_positive,
557
+ prior_strength=self.base.prior_strength,
558
+ successes=level.positive_count,
559
+ failures=level.observation_count - level.positive_count,
560
+ )
561
+ p_feasible = _beta_posterior_mean(
562
+ prior_mean=p_feasible,
563
+ prior_strength=self.base.prior_strength,
564
+ successes=level.feasible_count,
565
+ failures=level.observation_count - level.feasible_count,
566
+ )
567
+ magnitude = _shrunk_magnitude(
568
+ prior_mean=magnitude,
569
+ prior_strength=self.base.prior_strength,
570
+ positive_gain_sum=level.positive_gain_sum,
571
+ positive_count=level.positive_count,
572
+ )
573
+ cell = chain[2]
574
+ return {
575
+ "p_positive": p_positive,
576
+ "p_feasible": p_feasible,
577
+ "magnitude": magnitude,
578
+ "effective_sample_size": (
579
+ self.base.prior_strength + cell.observation_count
580
+ ),
581
+ }
582
+
583
+ def forecast_trust_multiplier(
584
+ self,
585
+ *,
586
+ observed_outcomes: tuple[RegionConditionalOutcome, ...],
587
+ engine_id: str,
588
+ ) -> float:
589
+ """Demote-only trust weight for one engine's forecast channel.
590
+
591
+ Beta posterior over forecast direction correctness with prior
592
+ mean ``forecast_trust_prior`` and the base challenger's prior
593
+ strength, mapped through ``min(1, 2 * posterior)``: exactly one
594
+ with no evidence or calibrated forecasts, strictly below one
595
+ once measured accuracy falls below one half (anti-calibration).
596
+ """
597
+
598
+ successes = 0.0
599
+ failures = 0.0
600
+ for value in observed_outcomes:
601
+ correct = value.forecast_direction_correct
602
+ if correct is None or value.engine_id != engine_id:
603
+ continue
604
+ if correct:
605
+ successes += 1.0
606
+ else:
607
+ failures += 1.0
608
+ posterior = _beta_posterior_mean(
609
+ prior_mean=self.credit.forecast_trust_prior,
610
+ prior_strength=self.base.prior_strength,
611
+ successes=successes,
612
+ failures=failures,
613
+ )
614
+ return float(min(1.0, 2.0 * posterior))
615
+
616
+ def score_market(
617
+ self,
618
+ *,
619
+ candidates: tuple[RegionScoredCandidate, ...],
620
+ archive_points: tuple[ObjectivePoint, ...],
621
+ reference_point: ObjectivePoint,
622
+ observed_outcomes: tuple[RegionConditionalOutcome, ...],
623
+ future_seats_remaining: int,
624
+ horizon_total: int,
625
+ frozen_fit_training_run_count: int = 0,
626
+ ) -> CalibratedPositiveGainRanking:
627
+ """Score and rank the whole market; never abstain."""
628
+
629
+ self.__post_init__()
630
+ if type(candidates) is not tuple or not candidates:
631
+ raise ValueError("candidates must be a non-empty exact tuple")
632
+ for value in candidates:
633
+ if type(value) is not RegionScoredCandidate:
634
+ raise TypeError(
635
+ "candidates must contain exact region candidates"
636
+ )
637
+ value.__post_init__()
638
+ action_ids = tuple(
639
+ value.candidate.action_sha256 for value in candidates
640
+ )
641
+ if len(action_ids) != len(set(action_ids)):
642
+ raise ValueError("candidate identities repeat")
643
+ if type(archive_points) is not tuple or not archive_points:
644
+ raise ValueError(
645
+ "archive_points must be a non-empty exact tuple"
646
+ )
647
+ for value in archive_points:
648
+ _require_objective_point(value, name="archive point")
649
+ _require_objective_point(
650
+ reference_point,
651
+ name="reference point",
652
+ )
653
+ if (
654
+ type(future_seats_remaining) is not int
655
+ or type(horizon_total) is not int
656
+ or horizon_total <= 0
657
+ or not 0 <= future_seats_remaining <= horizon_total
658
+ ):
659
+ raise ValueError(
660
+ "future seats must fit the positive horizon total"
661
+ )
662
+ if (
663
+ type(frozen_fit_training_run_count) is not int
664
+ or frozen_fit_training_run_count < 0
665
+ ):
666
+ raise ValueError(
667
+ "frozen_fit_training_run_count must be non-negative"
668
+ )
669
+ outcomes = self._validated_outcomes(observed_outcomes)
670
+ evidence = self._conversion_evidence(outcomes)
671
+ trust_by_engine = {
672
+ engine_id: self.forecast_trust_multiplier(
673
+ observed_outcomes=outcomes,
674
+ engine_id=engine_id,
675
+ )
676
+ for engine_id in {
677
+ value.candidate.engine_id for value in candidates
678
+ }
679
+ }
680
+ frozen_history_sufficient = (
681
+ frozen_fit_training_run_count
682
+ >= self.base.frozen_score_minimum_training_runs
683
+ )
684
+ horizon_fraction = future_seats_remaining / horizon_total
685
+ effective_beta = self.base.beta * horizon_fraction
686
+ scores: list[CalibratedPositiveGainScore] = []
687
+ by_action = {
688
+ value.candidate.action_sha256: value
689
+ for value in candidates
690
+ }
691
+ for scored in sorted(
692
+ candidates,
693
+ key=lambda value: value.candidate.action_sha256,
694
+ ):
695
+ candidate = scored.candidate
696
+ region_id, radius_class_id = self.region_for(
697
+ archive_points=archive_points,
698
+ reference_point=reference_point,
699
+ features=scored.features,
700
+ )
701
+ conversion = self._hierarchical_estimates(
702
+ evidence=evidence,
703
+ engine_id=candidate.engine_id,
704
+ region_id=region_id,
705
+ radius_class_id=radius_class_id,
706
+ )
707
+ p_conversion = conversion["p_positive"]
708
+ conversion_magnitude = conversion["magnitude"]
709
+ if candidate.forecast is None:
710
+ geometry: dict[str, float] | None = None
711
+ raw_forecast_weight = 0.0
712
+ else:
713
+ geometry = self.base._forecast_geometry(
714
+ archive_points=archive_points,
715
+ forecast=candidate.forecast,
716
+ )
717
+ raw_forecast_weight = (
718
+ self.base.mixture_weight
719
+ * candidate.forecast.reliability
720
+ * trust_by_engine[candidate.engine_id]
721
+ )
722
+ raw_conversion_weight = 1.0 - self.base.mixture_weight
723
+ frozen_active = (
724
+ candidate.frozen_score is not None
725
+ and frozen_history_sufficient
726
+ and self.base.frozen_score_weight > 0.0
727
+ )
728
+ raw_frozen_weight = (
729
+ self.base.frozen_score_weight if frozen_active else 0.0
730
+ )
731
+ probability_total = (
732
+ raw_forecast_weight
733
+ + raw_conversion_weight
734
+ + raw_frozen_weight
735
+ )
736
+ if (
737
+ geometry is None and not frozen_active
738
+ ) or probability_total <= 0.0:
739
+ p_positive = p_conversion
740
+ else:
741
+ blended_logit = (
742
+ raw_conversion_weight
743
+ * self.base._logit(p_conversion)
744
+ + (
745
+ raw_forecast_weight
746
+ * self.base._logit(geometry["probability"])
747
+ if geometry is not None
748
+ else 0.0
749
+ )
750
+ + (
751
+ raw_frozen_weight
752
+ * self.base._logit(candidate.frozen_score)
753
+ if frozen_active
754
+ else 0.0
755
+ )
756
+ ) / probability_total
757
+ p_positive = 1.0 / (1.0 + math.exp(-blended_logit))
758
+ frozen_evidence_weight = (
759
+ raw_frozen_weight / probability_total
760
+ if frozen_active
761
+ else 0.0
762
+ )
763
+ magnitude_total = raw_forecast_weight + raw_conversion_weight
764
+ forecast_weight = (
765
+ raw_forecast_weight / magnitude_total
766
+ if magnitude_total > 0.0
767
+ else 0.0
768
+ )
769
+ conversion_weight = 1.0 - forecast_weight
770
+ if geometry is None:
771
+ expected_positive_gain = conversion_magnitude
772
+ tail_risk = (
773
+ conversion_weight
774
+ * (1.0 - p_conversion)
775
+ * conversion_magnitude
776
+ )
777
+ else:
778
+ expected_positive_gain = (
779
+ forecast_weight * geometry["magnitude"]
780
+ + conversion_weight * conversion_magnitude
781
+ )
782
+ tail_risk = forecast_weight * geometry[
783
+ "shortfall"
784
+ ] + conversion_weight * (
785
+ (1.0 - p_conversion) * conversion_magnitude
786
+ )
787
+ uncertainty = math.sqrt(
788
+ p_conversion
789
+ * (1.0 - p_conversion)
790
+ / (conversion["effective_sample_size"] + 1.0)
791
+ )
792
+ value_of_information = (
793
+ uncertainty
794
+ * max(
795
+ expected_positive_gain,
796
+ self.base.reference_gain_scale,
797
+ )
798
+ if future_seats_remaining > 0
799
+ else 0.0
800
+ )
801
+ score = (
802
+ p_positive * expected_positive_gain
803
+ - self.base.lambda_ * tail_risk
804
+ + effective_beta * value_of_information
805
+ )
806
+ scores.append(
807
+ CalibratedPositiveGainScore(
808
+ action_sha256=candidate.action_sha256,
809
+ p_feasible=conversion["p_feasible"],
810
+ p_positive_archive_gain=float(p_positive),
811
+ expected_positive_gain=float(
812
+ expected_positive_gain
813
+ ),
814
+ tail_risk=float(tail_risk),
815
+ value_of_information=float(value_of_information),
816
+ uncertainty=float(uncertainty),
817
+ effective_sample_size=float(
818
+ conversion["effective_sample_size"]
819
+ ),
820
+ score=float(score),
821
+ forecast_probability=(
822
+ None
823
+ if geometry is None
824
+ else float(geometry["probability"])
825
+ ),
826
+ forecast_magnitude=(
827
+ None
828
+ if geometry is None
829
+ else float(geometry["magnitude"])
830
+ ),
831
+ forecast_nondominated_fraction=(
832
+ None
833
+ if geometry is None
834
+ else float(geometry["nondominated_fraction"])
835
+ ),
836
+ conversion_probability=float(p_conversion),
837
+ conversion_magnitude=float(conversion_magnitude),
838
+ frozen_score_probability=candidate.frozen_score,
839
+ frozen_evidence_weight=float(
840
+ frozen_evidence_weight
841
+ ),
842
+ )
843
+ )
844
+ rank_quality_by_action = {
845
+ value.candidate.action_sha256: (
846
+ 1.0
847
+ if value.candidate.lane_size == 1
848
+ else 1.0
849
+ - (value.candidate.native_rank - 1)
850
+ / float(value.candidate.lane_size - 1)
851
+ )
852
+ for value in candidates
853
+ }
854
+ ranked = tuple(
855
+ value.action_sha256
856
+ for value in sorted(
857
+ scores,
858
+ key=lambda value: (
859
+ -value.score,
860
+ -value.p_positive_archive_gain,
861
+ (
862
+ -rank_quality_by_action[value.action_sha256]
863
+ if self.base.within_cell_rank_tie_break
864
+ else 0.0
865
+ ),
866
+ value.action_sha256,
867
+ ),
868
+ )
869
+ )
870
+ assert set(ranked) == set(by_action)
871
+ return CalibratedPositiveGainRanking(
872
+ policy_id=self.policy_id,
873
+ policy_version=self.policy_version,
874
+ policy_definition_sha256=self.definition_sha256,
875
+ archive_sha256=_hash(
876
+ _DEFINITION_DOMAIN,
877
+ [
878
+ [
879
+ {
880
+ "metric_id": metric_id,
881
+ "value_hex": metric_value.hex(),
882
+ }
883
+ for metric_id, metric_value in value
884
+ ]
885
+ for value in archive_points
886
+ ],
887
+ ),
888
+ future_seats_remaining=future_seats_remaining,
889
+ horizon_total=horizon_total,
890
+ scores=tuple(scores),
891
+ ranked_action_sha256s=ranked,
892
+ )
893
+
894
+
895
+ __all__ = [
896
+ "RADIUS_CLASS_LONG",
897
+ "RADIUS_CLASS_MID",
898
+ "RADIUS_CLASS_NONE",
899
+ "RADIUS_CLASS_SHORT",
900
+ "REGION_CONDITIONAL_CREDIT_POLICY_ID",
901
+ "REGION_CONDITIONAL_CREDIT_POLICY_VERSION",
902
+ "REGION_NO_PARENT",
903
+ "RegionConditionalChallengerPolicy",
904
+ "RegionConditionalOutcome",
905
+ "RegionCreditConfig",
906
+ "RegionFeatures",
907
+ "RegionScoredCandidate",
908
+ "parent_front_distance",
909
+ "parent_front_region",
910
+ "radius_operator_class",
911
+ ]