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,1395 @@
1
+ """Provider-free sequential replay over sealed markets with real outcomes.
2
+
3
+ A market record freezes one already-materialized candidate market together
4
+ with the archive it faced, an exact hypervolume reference, and the real
5
+ evaluated outcomes. The replay harness then re-runs any allocation policy
6
+ under the honest information boundary: at every step the policy sees ONLY
7
+ the outcomes of candidates it already selected, selects one next candidate,
8
+ and only then has that candidate's outcome revealed.
9
+
10
+ Outputs are causal receipts: per-step selections with propensities, exact
11
+ conditional marginal hypervolume gains, cumulative realized gain, and
12
+ regret against the exact oracle-K subset enumerated over evaluated
13
+ candidates only. Oracle ceilings are retrospective upper bounds over
14
+ already-generated candidates, never prospective performance claims.
15
+
16
+ Reference baseline policies (uniform random, native-rank round-robin,
17
+ frozen-score top-K, and the V70-style frozen lane-heads walk) are included
18
+ for comparison, plus an adapter that drives the composed V8-lite policy.
19
+ No provider, workload, objective-name, or model branch exists anywhere.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import hashlib
25
+ import itertools
26
+ import json
27
+ import math
28
+ import re
29
+ from dataclasses import dataclass, field
30
+
31
+ from agent_evolve.application.calibrated_positive_gain_opportunity import (
32
+ ObjectivePoint,
33
+ ObservedConversionOutcome,
34
+ PositiveGainForecast,
35
+ )
36
+ from agent_evolve.application.outcome_adaptive_action_racing import (
37
+ AdaptiveActionDescriptor,
38
+ AdaptiveActionOutcome,
39
+ )
40
+ from agent_evolve.application.v8lite_allocation_policy import (
41
+ V8LiteAllocationPolicy,
42
+ )
43
+ from agent_evolve.domain.patch import require_sha256
44
+
45
+ SEQUENTIAL_MARKET_REPLAY_ID = "sequential_market_replay"
46
+ SEQUENTIAL_MARKET_REPLAY_VERSION = 1
47
+ _TOKEN = re.compile(r"^[a-z][a-z0-9_.:-]{0,255}$")
48
+ _MARKET_DOMAIN = b"agent-evolve:sequential-replay-market:v1\x00"
49
+ _RESULT_DOMAIN = b"agent-evolve:sequential-replay-result:v1\x00"
50
+
51
+ #: Exhaustive oracle enumeration guard: beyond this many subsets the
52
+ #: harness refuses rather than silently approximating.
53
+ DEFAULT_ORACLE_SUBSET_LIMIT = 250_000
54
+ #: Union hypervolume is computed by float slicing, so a point lying
55
+ #: exactly on the archive frontier can yield a difference of a few
56
+ #: ulps instead of exact zero. Gains at or below this epsilon (in
57
+ #: normalized hypervolume units; real recorded gains are >= 1e-5) are
58
+ #: treated as exactly zero everywhere: replay marginals, oracle
59
+ #: positivity, and the exact gain port.
60
+ HYPERVOLUME_GAIN_EPSILON = 1.0e-12
61
+
62
+
63
+ def _clamped_gain(value: float) -> float:
64
+ return value if value > HYPERVOLUME_GAIN_EPSILON else 0.0
65
+ #: Neutral prior score used when a candidate carries no frozen score but
66
+ #: an adapter needs a probability-typed prior.
67
+ NEUTRAL_PRIOR_SCORE = 0.5
68
+
69
+
70
+ def _canonical_json(value: object) -> bytes:
71
+ return json.dumps(
72
+ value,
73
+ allow_nan=False,
74
+ ensure_ascii=True,
75
+ separators=(",", ":"),
76
+ sort_keys=True,
77
+ ).encode("ascii", errors="strict")
78
+
79
+
80
+ def _hash(domain: bytes, value: object) -> str:
81
+ return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
82
+
83
+
84
+ def _require_token(value: str, *, name: str) -> None:
85
+ if type(value) is not str or _TOKEN.fullmatch(value) is None:
86
+ raise ValueError(f"{name} must use the closed token grammar")
87
+
88
+
89
+ def _stable_unit_interval(*parts: object) -> float:
90
+ payload = _canonical_json(list(parts))
91
+ numerator = int.from_bytes(hashlib.sha256(payload).digest()[:8], "big")
92
+ return numerator / float(2**64)
93
+
94
+
95
+ def exact_hypervolume(
96
+ points: tuple[tuple[float, ...], ...],
97
+ reference: tuple[float, ...],
98
+ ) -> float:
99
+ """Exact minimization hypervolume by recursive objective slicing."""
100
+
101
+ if type(reference) is not tuple or not reference:
102
+ raise ValueError("reference must be a non-empty exact tuple")
103
+ kept = sorted(
104
+ {
105
+ point
106
+ for point in points
107
+ if len(point) == len(reference)
108
+ and all(
109
+ value < bound
110
+ for value, bound in zip(point, reference, strict=True)
111
+ )
112
+ }
113
+ )
114
+ if not kept:
115
+ return 0.0
116
+ if len(reference) == 1:
117
+ return reference[0] - min(point[0] for point in kept)
118
+ kept.sort(key=lambda point: point[-1])
119
+ total = 0.0
120
+ for index, point in enumerate(kept):
121
+ z_low = point[-1]
122
+ z_high = (
123
+ kept[index + 1][-1]
124
+ if index + 1 < len(kept)
125
+ else reference[-1]
126
+ )
127
+ if z_high > z_low:
128
+ slab = exact_hypervolume(
129
+ tuple(value[:-1] for value in kept[: index + 1]),
130
+ reference[:-1],
131
+ )
132
+ total += slab * (z_high - z_low)
133
+ return total
134
+
135
+
136
+ def _point_values(
137
+ point: ObjectivePoint,
138
+ metric_ids: tuple[str, ...],
139
+ ) -> tuple[float, ...]:
140
+ mapping = dict(point)
141
+ if tuple(sorted(mapping)) != metric_ids:
142
+ raise ValueError("objective point uses a foreign metric frame")
143
+ return tuple(mapping[metric_id] for metric_id in metric_ids)
144
+
145
+
146
+ @dataclass(frozen=True, slots=True)
147
+ class MarketCandidateRecord:
148
+ """One frozen market candidate with its real outcome, if any."""
149
+
150
+ action_sha256: str
151
+ engine_id: str
152
+ native_rank: int
153
+ frozen_score: float | None
154
+ forecast: PositiveGainForecast | None
155
+ evaluated: bool
156
+ feasible: bool
157
+ objectives: ObjectivePoint | None
158
+ #: The candidate's parent objective point, known at proposal time.
159
+ anchor_point: ObjectivePoint | None = None
160
+
161
+ def __post_init__(self) -> None:
162
+ require_sha256(self.action_sha256, "action_sha256")
163
+ _require_token(self.engine_id, name="engine_id")
164
+ if type(self.native_rank) is not int or self.native_rank <= 0:
165
+ raise ValueError("native_rank must be positive")
166
+ if self.frozen_score is not None and (
167
+ type(self.frozen_score) is not float
168
+ or not math.isfinite(self.frozen_score)
169
+ ):
170
+ raise ValueError("frozen_score must be finite or None")
171
+ if self.forecast is not None:
172
+ if type(self.forecast) is not PositiveGainForecast:
173
+ raise TypeError("forecast must be exact or None")
174
+ self.forecast.__post_init__()
175
+ if type(self.evaluated) is not bool or type(self.feasible) is not bool:
176
+ raise TypeError("evaluated and feasible must be exact")
177
+ if self.feasible and not self.evaluated:
178
+ raise ValueError("a feasible candidate must be evaluated")
179
+ if (self.objectives is not None) != self.feasible:
180
+ raise ValueError(
181
+ "objectives must be present exactly for feasible candidates"
182
+ )
183
+
184
+ def to_record(self) -> dict[str, object]:
185
+ self.__post_init__()
186
+ record = {
187
+ "action_sha256": self.action_sha256,
188
+ "engine_id": self.engine_id,
189
+ "native_rank": self.native_rank,
190
+ "frozen_score_hex": (
191
+ None
192
+ if self.frozen_score is None
193
+ else self.frozen_score.hex()
194
+ ),
195
+ "forecast": (
196
+ None
197
+ if self.forecast is None
198
+ else self.forecast.to_record()
199
+ ),
200
+ "evaluated": self.evaluated,
201
+ "feasible": self.feasible,
202
+ "objectives": (
203
+ None
204
+ if self.objectives is None
205
+ else [
206
+ {"metric_id": metric_id, "value_hex": value.hex()}
207
+ for metric_id, value in self.objectives
208
+ ]
209
+ ),
210
+ }
211
+ # Emitted only when present so a market recorded without parent
212
+ # anchors keeps its pre-existing bytes and market_sha256.
213
+ if self.anchor_point is not None:
214
+ record["anchor_point"] = [
215
+ {"metric_id": metric_id, "value_hex": value.hex()}
216
+ for metric_id, value in self.anchor_point
217
+ ]
218
+ return record
219
+
220
+
221
+ @dataclass(frozen=True, slots=True)
222
+ class MarketRecord:
223
+ """Minimal sealed-market view sufficient for allocator replay."""
224
+
225
+ market_id: str
226
+ archive_points: tuple[ObjectivePoint, ...]
227
+ hv_reference_point: ObjectivePoint
228
+ candidates: tuple[MarketCandidateRecord, ...]
229
+ market_sha256: str = field(init=False)
230
+
231
+ def __post_init__(self) -> None:
232
+ _require_token(self.market_id, name="market_id")
233
+ if (
234
+ type(self.hv_reference_point) is not tuple
235
+ or not self.hv_reference_point
236
+ or self.hv_reference_point
237
+ != tuple(sorted(self.hv_reference_point))
238
+ ):
239
+ raise ValueError(
240
+ "hv_reference_point must be non-empty and canonical"
241
+ )
242
+ metric_ids = self.metric_ids
243
+ if type(self.archive_points) is not tuple or not self.archive_points:
244
+ raise ValueError("archive_points must be non-empty")
245
+ for point in self.archive_points:
246
+ _point_values(point, metric_ids)
247
+ if type(self.candidates) is not tuple or not self.candidates:
248
+ raise ValueError("candidates must be non-empty")
249
+ seen: set[str] = set()
250
+ lanes: dict[str, list[int]] = {}
251
+ for value in self.candidates:
252
+ if type(value) is not MarketCandidateRecord:
253
+ raise TypeError("candidates must be exact market records")
254
+ value.__post_init__()
255
+ if value.action_sha256 in seen:
256
+ raise ValueError("candidate identities repeat")
257
+ seen.add(value.action_sha256)
258
+ lanes.setdefault(value.engine_id, []).append(
259
+ value.native_rank
260
+ )
261
+ if value.objectives is not None:
262
+ _point_values(value.objectives, metric_ids)
263
+ for engine_id, ranks in lanes.items():
264
+ if sorted(ranks) != list(range(1, len(ranks) + 1)):
265
+ raise ValueError(
266
+ f"engine {engine_id} ranks must be contiguous"
267
+ )
268
+ object.__setattr__(
269
+ self,
270
+ "market_sha256",
271
+ _hash(
272
+ _MARKET_DOMAIN,
273
+ {
274
+ "schema_version": 1,
275
+ "market_id": self.market_id,
276
+ "hv_reference_point": [
277
+ {
278
+ "metric_id": metric_id,
279
+ "value_hex": value.hex(),
280
+ }
281
+ for metric_id, value in self.hv_reference_point
282
+ ],
283
+ "archive_points": [
284
+ [
285
+ {
286
+ "metric_id": metric_id,
287
+ "value_hex": value.hex(),
288
+ }
289
+ for metric_id, value in point
290
+ ]
291
+ for point in self.archive_points
292
+ ],
293
+ "candidates": [
294
+ value.to_record() for value in self.candidates
295
+ ],
296
+ },
297
+ ),
298
+ )
299
+
300
+ @property
301
+ def metric_ids(self) -> tuple[str, ...]:
302
+ return tuple(
303
+ metric_id for metric_id, _value in self.hv_reference_point
304
+ )
305
+
306
+ def candidate(self, action_sha256: str) -> MarketCandidateRecord:
307
+ for value in self.candidates:
308
+ if value.action_sha256 == action_sha256:
309
+ return value
310
+ raise ValueError("candidate is outside the market")
311
+
312
+ def hypervolume(
313
+ self,
314
+ extra_points: tuple[ObjectivePoint, ...] = (),
315
+ ) -> float:
316
+ metric_ids = self.metric_ids
317
+ reference = _point_values(self.hv_reference_point, metric_ids)
318
+ return exact_hypervolume(
319
+ tuple(
320
+ _point_values(point, metric_ids)
321
+ for point in (*self.archive_points, *extra_points)
322
+ ),
323
+ reference,
324
+ )
325
+
326
+
327
+ class ExactHypervolumeGainPort:
328
+ """Module-level gain port valuing points against arbitrary archives."""
329
+
330
+ utility_id = "exact_hypervolume_gain"
331
+ utility_version = 1
332
+
333
+ def __init__(self, hv_reference_point: ObjectivePoint) -> None:
334
+ self._reference = hv_reference_point
335
+ self._metric_ids = tuple(
336
+ metric_id for metric_id, _value in hv_reference_point
337
+ )
338
+ self.definition_sha256 = _hash(
339
+ _MARKET_DOMAIN,
340
+ {
341
+ "utility": self.utility_id,
342
+ "reference": [
343
+ {"metric_id": metric_id, "value_hex": value.hex()}
344
+ for metric_id, value in hv_reference_point
345
+ ],
346
+ },
347
+ )
348
+
349
+ def marginal_archive_gain(
350
+ self,
351
+ archive_points: tuple[ObjectivePoint, ...],
352
+ objective_point: ObjectivePoint,
353
+ ) -> float:
354
+ reference = _point_values(self._reference, self._metric_ids)
355
+ base = tuple(
356
+ _point_values(point, self._metric_ids)
357
+ for point in archive_points
358
+ )
359
+ with_point = (
360
+ *base,
361
+ _point_values(objective_point, self._metric_ids),
362
+ )
363
+ return _clamped_gain(
364
+ float(
365
+ exact_hypervolume(with_point, reference)
366
+ - exact_hypervolume(base, reference)
367
+ )
368
+ )
369
+
370
+
371
+ @dataclass(frozen=True, slots=True)
372
+ class ReplaySelection:
373
+ """One policy answer: which candidate, at what propensity."""
374
+
375
+ action_sha256: str
376
+ selection_propensity: float
377
+ evidence: dict[str, object] = field(default_factory=dict)
378
+
379
+ def __post_init__(self) -> None:
380
+ require_sha256(self.action_sha256, "action_sha256")
381
+ if (
382
+ type(self.selection_propensity) is not float
383
+ or not math.isfinite(self.selection_propensity)
384
+ or not 0.0 < self.selection_propensity <= 1.0
385
+ ):
386
+ raise ValueError(
387
+ "selection_propensity must be a positive probability"
388
+ )
389
+
390
+
391
+ @dataclass(frozen=True, slots=True)
392
+ class ReplayStepReceipt:
393
+ step_index: int
394
+ action_sha256: str
395
+ selection_propensity: float
396
+ evaluated: bool
397
+ feasible: bool
398
+ imputed_zero_outcome: bool
399
+ marginal_gain: float
400
+ cumulative_gain: float
401
+
402
+ def to_record(self) -> dict[str, object]:
403
+ return {
404
+ "step_index": self.step_index,
405
+ "action_sha256": self.action_sha256,
406
+ "selection_propensity_hex": (
407
+ self.selection_propensity.hex()
408
+ ),
409
+ "evaluated": self.evaluated,
410
+ "feasible": self.feasible,
411
+ "imputed_zero_outcome": self.imputed_zero_outcome,
412
+ "marginal_gain_hex": self.marginal_gain.hex(),
413
+ "cumulative_gain_hex": self.cumulative_gain.hex(),
414
+ }
415
+
416
+
417
+ @dataclass(frozen=True, slots=True)
418
+ class ReplayResult:
419
+ market_sha256: str
420
+ policy_id: str
421
+ budget: int
422
+ restricted_to_evaluated: bool
423
+ receipts: tuple[ReplayStepReceipt, ...]
424
+ realized_gain: float
425
+ oracle_gain: float
426
+ oracle_subset: tuple[str, ...]
427
+ regret: float
428
+ result_sha256: str = field(init=False)
429
+
430
+ def __post_init__(self) -> None:
431
+ object.__setattr__(
432
+ self,
433
+ "result_sha256",
434
+ _hash(_RESULT_DOMAIN, self.to_record()),
435
+ )
436
+
437
+ @property
438
+ def selected_action_sha256s(self) -> tuple[str, ...]:
439
+ return tuple(
440
+ value.action_sha256 for value in self.receipts
441
+ )
442
+
443
+ def to_record(self) -> dict[str, object]:
444
+ return {
445
+ "schema_version": 1,
446
+ "market_sha256": self.market_sha256,
447
+ "policy_id": self.policy_id,
448
+ "budget": self.budget,
449
+ "restricted_to_evaluated": self.restricted_to_evaluated,
450
+ "receipts": [value.to_record() for value in self.receipts],
451
+ "realized_gain_hex": self.realized_gain.hex(),
452
+ "oracle_gain_hex": self.oracle_gain.hex(),
453
+ "oracle_subset": list(self.oracle_subset),
454
+ "regret_hex": self.regret.hex(),
455
+ "oracle_is_retrospective_upper_bound": True,
456
+ }
457
+
458
+
459
+ class UniformRandomReplayPolicy:
460
+ """Seeded uniform selection over the selectable support."""
461
+
462
+ def __init__(self, seed: int) -> None:
463
+ self.policy_id = "replay_baseline.uniform_random"
464
+ self._seed = seed
465
+
466
+ def select(
467
+ self,
468
+ *,
469
+ record: MarketRecord,
470
+ revealed: tuple[ReplayStepReceipt, ...],
471
+ selectable_action_sha256s: tuple[str, ...],
472
+ step_index: int,
473
+ budget: int,
474
+ ) -> ReplaySelection:
475
+ # The draw must not condition on unrevealed outcomes, so it
476
+ # hashes only the outcome-blind market identity and support.
477
+ draw = _stable_unit_interval(
478
+ self._seed,
479
+ record.market_id,
480
+ "uniform_random",
481
+ step_index,
482
+ list(selectable_action_sha256s),
483
+ )
484
+ support = tuple(sorted(selectable_action_sha256s))
485
+ chosen = support[
486
+ min(int(draw * len(support)), len(support) - 1)
487
+ ]
488
+ return ReplaySelection(
489
+ action_sha256=chosen,
490
+ selection_propensity=1.0 / len(support),
491
+ )
492
+
493
+
494
+ class NativeRankRoundRobinReplayPolicy:
495
+ """Round-robin engines in canonical order; best native rank first."""
496
+
497
+ def __init__(self) -> None:
498
+ self.policy_id = "replay_baseline.native_rank_round_robin"
499
+
500
+ def select(
501
+ self,
502
+ *,
503
+ record: MarketRecord,
504
+ revealed: tuple[ReplayStepReceipt, ...],
505
+ selectable_action_sha256s: tuple[str, ...],
506
+ step_index: int,
507
+ budget: int,
508
+ ) -> ReplaySelection:
509
+ selectable = set(selectable_action_sha256s)
510
+ engines = sorted(
511
+ {
512
+ value.engine_id
513
+ for value in record.candidates
514
+ if value.action_sha256 in selectable
515
+ }
516
+ )
517
+ engine_id = engines[step_index % len(engines)]
518
+ chosen = min(
519
+ (
520
+ value
521
+ for value in record.candidates
522
+ if value.action_sha256 in selectable
523
+ and value.engine_id == engine_id
524
+ ),
525
+ key=lambda value: (value.native_rank, value.action_sha256),
526
+ )
527
+ return ReplaySelection(
528
+ action_sha256=chosen.action_sha256,
529
+ selection_propensity=1.0,
530
+ )
531
+
532
+
533
+ class FrozenScoreTopKReplayPolicy:
534
+ """Descending global frozen score; native rank breaks ties."""
535
+
536
+ def __init__(self) -> None:
537
+ self.policy_id = "replay_baseline.frozen_score_topk"
538
+
539
+ def select(
540
+ self,
541
+ *,
542
+ record: MarketRecord,
543
+ revealed: tuple[ReplayStepReceipt, ...],
544
+ selectable_action_sha256s: tuple[str, ...],
545
+ step_index: int,
546
+ budget: int,
547
+ ) -> ReplaySelection:
548
+ selectable = set(selectable_action_sha256s)
549
+ chosen = min(
550
+ (
551
+ value
552
+ for value in record.candidates
553
+ if value.action_sha256 in selectable
554
+ ),
555
+ key=lambda value: (
556
+ -(
557
+ value.frozen_score
558
+ if value.frozen_score is not None
559
+ else NEUTRAL_PRIOR_SCORE
560
+ ),
561
+ value.native_rank,
562
+ value.action_sha256,
563
+ ),
564
+ )
565
+ return ReplaySelection(
566
+ action_sha256=chosen.action_sha256,
567
+ selection_propensity=1.0,
568
+ )
569
+
570
+
571
+ class LaneHeadsReplayPolicy:
572
+ """V70 D4 behavior: one frozen-score lane head per engine, cycled."""
573
+
574
+ def __init__(self) -> None:
575
+ self.policy_id = "replay_baseline.lane_heads"
576
+
577
+ def select(
578
+ self,
579
+ *,
580
+ record: MarketRecord,
581
+ revealed: tuple[ReplayStepReceipt, ...],
582
+ selectable_action_sha256s: tuple[str, ...],
583
+ step_index: int,
584
+ budget: int,
585
+ ) -> ReplaySelection:
586
+ def frozen(value: MarketCandidateRecord) -> float:
587
+ return (
588
+ value.frozen_score
589
+ if value.frozen_score is not None
590
+ else NEUTRAL_PRIOR_SCORE
591
+ )
592
+
593
+ universe = tuple(
594
+ sorted(
595
+ (
596
+ value
597
+ for value in record.candidates
598
+ if value.action_sha256
599
+ in set(selectable_action_sha256s)
600
+ or any(
601
+ value.action_sha256 == item.action_sha256
602
+ for item in revealed
603
+ )
604
+ ),
605
+ key=lambda value: value.action_sha256,
606
+ )
607
+ )
608
+ by_engine: dict[str, list[MarketCandidateRecord]] = {}
609
+ for value in universe:
610
+ by_engine.setdefault(value.engine_id, []).append(value)
611
+ for values in by_engine.values():
612
+ values.sort(
613
+ key=lambda value: (
614
+ -frozen(value),
615
+ value.native_rank,
616
+ value.action_sha256,
617
+ )
618
+ )
619
+ engine_order = sorted(
620
+ by_engine,
621
+ key=lambda engine_id: (
622
+ -frozen(by_engine[engine_id][0]),
623
+ engine_id,
624
+ ),
625
+ )
626
+ walk = []
627
+ depth = 0
628
+ while len(walk) < len(universe):
629
+ for engine_id in engine_order:
630
+ if depth < len(by_engine[engine_id]):
631
+ walk.append(by_engine[engine_id][depth])
632
+ depth += 1
633
+ selectable = set(selectable_action_sha256s)
634
+ chosen = next(
635
+ value
636
+ for value in walk
637
+ if value.action_sha256 in selectable
638
+ )
639
+ return ReplaySelection(
640
+ action_sha256=chosen.action_sha256,
641
+ selection_propensity=1.0,
642
+ )
643
+
644
+
645
+ class V8LiteReplayPolicy:
646
+ """Drive the composed V8-lite policy inside the replay boundary.
647
+
648
+ The eligible universe is the harness's fixed selectable support plus
649
+ already-selected candidates; native ranks are re-ranked densely
650
+ within that universe so descriptor lane invariants hold. Candidates
651
+ without a frozen score receive the neutral prior score.
652
+ """
653
+
654
+ def __init__(
655
+ self,
656
+ policy: V8LiteAllocationPolicy,
657
+ *,
658
+ frozen_fit_training_run_count: int = 0,
659
+ prior_conversion_outcomes: tuple[
660
+ ObservedConversionOutcome,
661
+ ...,
662
+ ] = (),
663
+ ) -> None:
664
+ if type(policy) is not V8LiteAllocationPolicy:
665
+ raise TypeError("policy must be an exact V8-lite policy")
666
+ policy.__post_init__()
667
+ self.policy_id = "replay_adapter.v8lite"
668
+ self._policy = policy
669
+ self._frozen_fit_training_run_count = (
670
+ frozen_fit_training_run_count
671
+ )
672
+ self._prior_conversion_outcomes = prior_conversion_outcomes
673
+
674
+ @staticmethod
675
+ def _phenotype(action_sha256: str) -> str:
676
+ return hashlib.sha256(
677
+ f"phenotype:{action_sha256}".encode("ascii")
678
+ ).hexdigest()
679
+
680
+ @staticmethod
681
+ def _outcome_blind_request_sha256(
682
+ record: MarketRecord,
683
+ universe_ids: tuple[str, ...],
684
+ ) -> str:
685
+ """Cutoff identity that never conditions on unrevealed outcomes."""
686
+
687
+ return hashlib.sha256(
688
+ _canonical_json(
689
+ [
690
+ "replay-request",
691
+ record.market_id,
692
+ list(universe_ids),
693
+ ]
694
+ )
695
+ ).hexdigest()
696
+
697
+ def _descriptors(
698
+ self,
699
+ record: MarketRecord,
700
+ universe_ids: tuple[str, ...],
701
+ ) -> tuple[AdaptiveActionDescriptor, ...]:
702
+ universe = tuple(
703
+ record.candidate(value) for value in universe_ids
704
+ )
705
+ by_engine: dict[str, list[MarketCandidateRecord]] = {}
706
+ for value in universe:
707
+ by_engine.setdefault(value.engine_id, []).append(value)
708
+ descriptors: list[AdaptiveActionDescriptor] = []
709
+ for engine_id in sorted(by_engine):
710
+ lane = sorted(
711
+ by_engine[engine_id],
712
+ key=lambda value: (
713
+ value.native_rank,
714
+ value.action_sha256,
715
+ ),
716
+ )
717
+ for dense_rank, value in enumerate(lane, start=1):
718
+ prior = (
719
+ value.frozen_score
720
+ if value.frozen_score is not None
721
+ else NEUTRAL_PRIOR_SCORE
722
+ )
723
+ descriptors.append(
724
+ AdaptiveActionDescriptor(
725
+ action_sha256=value.action_sha256,
726
+ phenotype_sha256=self._phenotype(
727
+ value.action_sha256
728
+ ),
729
+ lane_id=engine_id,
730
+ operator_id=engine_id,
731
+ native_rank=dense_rank,
732
+ lane_size=len(lane),
733
+ prior_score=float(
734
+ min(max(prior, 0.0), 1.0)
735
+ ),
736
+ parent_generated_in_current_run=False,
737
+ )
738
+ )
739
+ return tuple(descriptors)
740
+
741
+ def select(
742
+ self,
743
+ *,
744
+ record: MarketRecord,
745
+ revealed: tuple[ReplayStepReceipt, ...],
746
+ selectable_action_sha256s: tuple[str, ...],
747
+ step_index: int,
748
+ budget: int,
749
+ ) -> ReplaySelection:
750
+ universe_ids = tuple(
751
+ sorted(
752
+ {
753
+ *selectable_action_sha256s,
754
+ *(value.action_sha256 for value in revealed),
755
+ }
756
+ )
757
+ )
758
+ descriptors = self._descriptors(record, universe_ids)
759
+ request_sha256 = self._outcome_blind_request_sha256(
760
+ record,
761
+ universe_ids,
762
+ )
763
+ pilot_width = self._policy.pilot_width_for(
764
+ evaluation_slots=budget,
765
+ engine_count=len(
766
+ {value.lane_id for value in descriptors}
767
+ ),
768
+ )
769
+ if pilot_width <= 0:
770
+ raise ValueError("replay budget leaves no pilot")
771
+ selected_ids = tuple(
772
+ sorted(value.action_sha256 for value in revealed)
773
+ )
774
+ outcome_by_action = {
775
+ value.action_sha256: value for value in revealed
776
+ }
777
+ outcomes = tuple(
778
+ AdaptiveActionOutcome(
779
+ action_sha256=action_sha256,
780
+ evaluation_sha256=hashlib.sha256(
781
+ f"replay-evaluation:{action_sha256}".encode(
782
+ "ascii"
783
+ )
784
+ ).hexdigest(),
785
+ feasible=outcome_by_action[action_sha256].feasible,
786
+ marginal_archive_gain=(
787
+ outcome_by_action[action_sha256].marginal_gain
788
+ ),
789
+ )
790
+ for action_sha256 in selected_ids
791
+ )
792
+ if step_index < pilot_width:
793
+ if self._policy.revision_2:
794
+ decision = self._policy.design_pilot_seat(
795
+ residual_request_sha256=request_sha256,
796
+ actions=descriptors,
797
+ evaluation_slots=budget,
798
+ selected_action_sha256s=selected_ids,
799
+ outcomes=outcomes,
800
+ )
801
+ return ReplaySelection(
802
+ action_sha256=(
803
+ decision.selected_action_sha256s[0]
804
+ ),
805
+ selection_propensity=(
806
+ decision.selection_propensity
807
+ ),
808
+ evidence={"phase": decision.phase},
809
+ )
810
+ decision = self._policy.design_pilot(
811
+ residual_request_sha256=request_sha256,
812
+ actions=descriptors,
813
+ evaluation_slots=budget,
814
+ )
815
+ seat = decision.pilot_design.seats[step_index]
816
+ return ReplaySelection(
817
+ action_sha256=seat.selected_action_sha256,
818
+ selection_propensity=seat.selection_propensity,
819
+ evidence={"phase": decision.phase},
820
+ )
821
+ pilot_ids = tuple(
822
+ sorted(
823
+ value.action_sha256
824
+ for value in revealed[:pilot_width]
825
+ )
826
+ )
827
+ pilot_points = tuple(
828
+ record.candidate(value).objectives
829
+ for value in pilot_ids
830
+ if record.candidate(value).objectives is not None
831
+ )
832
+ diagnostic_joint_gain = _clamped_gain(
833
+ float(
834
+ record.hypervolume(pilot_points)
835
+ - record.hypervolume()
836
+ )
837
+ )
838
+ forecasts = tuple(
839
+ (value.action_sha256, value.forecast)
840
+ for value in (
841
+ record.candidate(item) for item in universe_ids
842
+ )
843
+ if value.forecast is not None
844
+ )
845
+ anchors = tuple(
846
+ (value.action_sha256, value.anchor_point)
847
+ for value in (
848
+ record.candidate(item) for item in universe_ids
849
+ )
850
+ if value.anchor_point is not None
851
+ )
852
+ # The archive-geometry channel is defined against the CURRENT
853
+ # archive, so a revision that declares it is handed the sealed
854
+ # archive plus every point already revealed at this cutoff. Every
855
+ # earlier revision keeps the sealed archive exactly, so its replay
856
+ # bytes are unchanged.
857
+ archive_points = record.archive_points
858
+ if getattr(self._policy, "revision_3", False):
859
+ revealed_points = tuple(
860
+ point
861
+ for point in (
862
+ record.candidate(value.action_sha256).objectives
863
+ for value in revealed
864
+ )
865
+ if point is not None
866
+ )
867
+ archive_points = (*archive_points, *revealed_points)
868
+ decision = self._policy.select_next(
869
+ residual_request_sha256=request_sha256,
870
+ actions=descriptors,
871
+ evaluation_slots=budget,
872
+ diagnostic_action_sha256s=pilot_ids,
873
+ diagnostic_joint_gain=diagnostic_joint_gain,
874
+ selected_action_sha256s=selected_ids,
875
+ outcomes=outcomes,
876
+ archive_points=archive_points,
877
+ forecasts=forecasts,
878
+ anchor_points=anchors,
879
+ frozen_fit_training_run_count=(
880
+ self._frozen_fit_training_run_count
881
+ ),
882
+ prior_conversion_outcomes=(
883
+ self._prior_conversion_outcomes
884
+ ),
885
+ )
886
+ return ReplaySelection(
887
+ action_sha256=decision.selected_action_sha256s[0],
888
+ selection_propensity=decision.selection_propensity,
889
+ evidence={"phase": decision.phase},
890
+ )
891
+
892
+
893
+ @dataclass(frozen=True, slots=True)
894
+ class SequentialMarketReplay:
895
+ """Run one policy over one sealed market under the honest boundary."""
896
+
897
+ oracle_subset_limit: int = DEFAULT_ORACLE_SUBSET_LIMIT
898
+
899
+ def __post_init__(self) -> None:
900
+ if (
901
+ type(self.oracle_subset_limit) is not int
902
+ or self.oracle_subset_limit <= 0
903
+ ):
904
+ raise ValueError("oracle_subset_limit must be positive")
905
+
906
+ def oracle(
907
+ self,
908
+ record: MarketRecord,
909
+ budget: int,
910
+ ) -> tuple[float, tuple[str, ...]]:
911
+ """Exact best size-<=budget subset over evaluated candidates.
912
+
913
+ Enumeration runs over the deduplicated non-dominated positive
914
+ subset, which is exact: a candidate with zero marginal
915
+ hypervolume adds nothing to any union, and any member of an
916
+ optimal subset can be replaced by a candidate that weakly
917
+ dominates it without reducing the union. The subset limit
918
+ therefore applies to the reduced frontier, not the raw market.
919
+ """
920
+
921
+ record.__post_init__()
922
+ if type(budget) is not int or budget <= 0:
923
+ raise ValueError("budget must be positive")
924
+ metric_ids = record.metric_ids
925
+ base = record.hypervolume()
926
+ unique_by_point: dict[
927
+ tuple[float, ...],
928
+ MarketCandidateRecord,
929
+ ] = {}
930
+ for value in record.candidates:
931
+ if not value.feasible or value.objectives is None:
932
+ continue
933
+ if (
934
+ _clamped_gain(
935
+ record.hypervolume((value.objectives,)) - base
936
+ )
937
+ <= 0.0
938
+ ):
939
+ continue
940
+ point = _point_values(value.objectives, metric_ids)
941
+ incumbent = unique_by_point.get(point)
942
+ if (
943
+ incumbent is None
944
+ or value.action_sha256 < incumbent.action_sha256
945
+ ):
946
+ unique_by_point[point] = value
947
+ frontier = tuple(
948
+ candidate
949
+ for point, candidate in unique_by_point.items()
950
+ if not any(
951
+ other != point
952
+ and all(
953
+ o <= p
954
+ for o, p in zip(other, point, strict=True)
955
+ )
956
+ for other in unique_by_point
957
+ )
958
+ )
959
+ subset_size = min(budget, len(frontier))
960
+ if subset_size == 0:
961
+ return 0.0, ()
962
+ if (
963
+ math.comb(len(frontier), subset_size)
964
+ > self.oracle_subset_limit
965
+ ):
966
+ raise ValueError(
967
+ "oracle enumeration exceeds the configured subset limit"
968
+ )
969
+ best_gain = 0.0
970
+ best_subset: tuple[str, ...] = ()
971
+ for subset in itertools.combinations(frontier, subset_size):
972
+ gain = (
973
+ record.hypervolume(
974
+ tuple(value.objectives for value in subset)
975
+ )
976
+ - base
977
+ )
978
+ key = tuple(
979
+ sorted(value.action_sha256 for value in subset)
980
+ )
981
+ if gain > best_gain or (
982
+ gain == best_gain and best_subset and key < best_subset
983
+ ):
984
+ best_gain = gain
985
+ best_subset = key
986
+ best_gain = _clamped_gain(float(best_gain))
987
+ if best_gain == 0.0:
988
+ return 0.0, ()
989
+ return best_gain, best_subset
990
+
991
+ def run(
992
+ self,
993
+ *,
994
+ record: MarketRecord,
995
+ policy: object,
996
+ budget: int,
997
+ restrict_to_evaluated: bool = True,
998
+ ) -> ReplayResult:
999
+ record.__post_init__()
1000
+ policy_id = getattr(policy, "policy_id", None)
1001
+ _require_token(str(policy_id), name="policy_id")
1002
+ if type(budget) is not int or budget <= 0:
1003
+ raise ValueError("budget must be positive")
1004
+ selectable = {
1005
+ value.action_sha256
1006
+ for value in record.candidates
1007
+ if not restrict_to_evaluated or value.evaluated
1008
+ }
1009
+ if budget > len(selectable):
1010
+ raise ValueError("budget exceeds the selectable market")
1011
+ receipts: list[ReplayStepReceipt] = []
1012
+ revealed_points: list[ObjectivePoint] = []
1013
+ cumulative = 0.0
1014
+ base_hv = record.hypervolume()
1015
+ for step_index in range(budget):
1016
+ selection = policy.select(
1017
+ record=record,
1018
+ revealed=tuple(receipts),
1019
+ selectable_action_sha256s=tuple(sorted(selectable)),
1020
+ step_index=step_index,
1021
+ budget=budget,
1022
+ )
1023
+ if type(selection) is not ReplaySelection:
1024
+ raise TypeError("policy must return an exact selection")
1025
+ selection.__post_init__()
1026
+ if selection.action_sha256 not in selectable:
1027
+ raise ValueError(
1028
+ "policy selected outside the selectable support"
1029
+ )
1030
+ candidate = record.candidate(selection.action_sha256)
1031
+ imputed = not candidate.evaluated
1032
+ if candidate.feasible and candidate.objectives is not None:
1033
+ with_candidate = record.hypervolume(
1034
+ (*revealed_points, candidate.objectives)
1035
+ )
1036
+ without_candidate = record.hypervolume(
1037
+ tuple(revealed_points)
1038
+ )
1039
+ # Union hypervolume is monotone; sub-epsilon float
1040
+ # differences from a zero-add candidate are exact zero.
1041
+ marginal = _clamped_gain(
1042
+ float(with_candidate - without_candidate)
1043
+ )
1044
+ revealed_points.append(candidate.objectives)
1045
+ else:
1046
+ marginal = 0.0
1047
+ cumulative = _clamped_gain(
1048
+ float(
1049
+ record.hypervolume(tuple(revealed_points))
1050
+ - base_hv
1051
+ )
1052
+ )
1053
+ selectable.discard(selection.action_sha256)
1054
+ receipts.append(
1055
+ ReplayStepReceipt(
1056
+ step_index=step_index,
1057
+ action_sha256=selection.action_sha256,
1058
+ selection_propensity=(
1059
+ selection.selection_propensity
1060
+ ),
1061
+ evaluated=candidate.evaluated,
1062
+ feasible=candidate.feasible,
1063
+ imputed_zero_outcome=imputed,
1064
+ marginal_gain=marginal,
1065
+ cumulative_gain=cumulative,
1066
+ )
1067
+ )
1068
+ oracle_gain, oracle_subset = self.oracle(record, budget)
1069
+ return ReplayResult(
1070
+ market_sha256=record.market_sha256,
1071
+ policy_id=str(policy_id),
1072
+ budget=budget,
1073
+ restricted_to_evaluated=restrict_to_evaluated,
1074
+ receipts=tuple(receipts),
1075
+ realized_gain=float(cumulative),
1076
+ oracle_gain=float(oracle_gain),
1077
+ oracle_subset=oracle_subset,
1078
+ regret=float(oracle_gain - cumulative),
1079
+ )
1080
+
1081
+
1082
+ def _normalized_point(
1083
+ raw: dict[str, float],
1084
+ axes: tuple[dict[str, object], ...],
1085
+ ) -> ObjectivePoint:
1086
+ values: list[tuple[str, float]] = []
1087
+ for axis in axes:
1088
+ metric_id = str(axis["metric_id"])
1089
+ reference = float(axis["reference"])
1090
+ ideal = float(axis["ideal"])
1091
+ if reference == ideal:
1092
+ raise ValueError("axis reference must differ from ideal")
1093
+ values.append(
1094
+ (
1095
+ metric_id,
1096
+ float(
1097
+ (float(raw[metric_id]) - ideal)
1098
+ / (reference - ideal)
1099
+ ),
1100
+ )
1101
+ )
1102
+ return tuple(sorted(values))
1103
+
1104
+
1105
+ #: Frozen-score keys consumed from corpus records, in priority order.
1106
+ #: Values are min-max normalized per market (higher is better) so they
1107
+ #: are usable both as an ordering and as a probability-typed prior.
1108
+ CORPUS_FROZEN_SCORE_KEYS = ("frozen_prior_score", "raw")
1109
+
1110
+
1111
+ def _corpus_engine_id(raw: dict[str, object]) -> str:
1112
+ lane = raw.get("lane")
1113
+ if isinstance(lane, dict) and lane.get("lane_id"):
1114
+ return str(lane["lane_id"])
1115
+ for key in ("expert_id", "family"):
1116
+ if raw.get(key):
1117
+ return str(raw[key])
1118
+ return "engine.unattributed"
1119
+
1120
+
1121
+ def _corpus_action_sha256(
1122
+ market_id: str,
1123
+ raw: dict[str, object],
1124
+ ) -> str:
1125
+ value = raw.get("action_sha256")
1126
+ if isinstance(value, str) and len(value) == 64:
1127
+ return value
1128
+ identity = [
1129
+ raw.get(key)
1130
+ for key in (
1131
+ "candidate_id",
1132
+ "proposal_id",
1133
+ "locus_key",
1134
+ "option_id",
1135
+ "native_rank",
1136
+ )
1137
+ if raw.get(key) is not None
1138
+ ]
1139
+ if not identity:
1140
+ raise ValueError("corpus candidate carries no identity")
1141
+ return hashlib.sha256(
1142
+ _canonical_json(
1143
+ [
1144
+ "replay-candidate-id",
1145
+ market_id,
1146
+ [str(part) for part in identity],
1147
+ ]
1148
+ )
1149
+ ).hexdigest()
1150
+
1151
+
1152
+ def _corpus_frozen_raw(raw: dict[str, object]) -> float | None:
1153
+ frozen_scores = raw.get("frozen_scores")
1154
+ if not isinstance(frozen_scores, dict):
1155
+ return None
1156
+ for key in CORPUS_FROZEN_SCORE_KEYS:
1157
+ value = frozen_scores.get(key)
1158
+ if isinstance(value, (int, float)) and math.isfinite(
1159
+ float(value)
1160
+ ):
1161
+ return float(value)
1162
+ return None
1163
+
1164
+
1165
+ def _corpus_forecast(
1166
+ raw: dict[str, object],
1167
+ axes: tuple[dict[str, object], ...],
1168
+ metric_ids: tuple[str, ...],
1169
+ ) -> PositiveGainForecast | None:
1170
+ """Absolute p10/p50/p90 points from parent objectives plus deltas.
1171
+
1172
+ Corpus forecasts are per-metric DELTAS relative to the candidate's
1173
+ parent, so they are usable only when parent objectives cover every
1174
+ metric. Direction-only forecasts degrade to no forecast.
1175
+ """
1176
+
1177
+ forecast_raw = raw.get("forecast")
1178
+ parent = raw.get("parent")
1179
+ if not isinstance(forecast_raw, list) or not isinstance(
1180
+ parent,
1181
+ dict,
1182
+ ):
1183
+ return None
1184
+ parent_objectives = parent.get("objectives")
1185
+ if not isinstance(parent_objectives, dict) or not set(
1186
+ metric_ids
1187
+ ) <= set(parent_objectives):
1188
+ return None
1189
+ deltas: dict[str, dict[str, float]] = {}
1190
+ confidences: list[float] = []
1191
+ for row in forecast_raw:
1192
+ if not isinstance(row, dict) or "metric_id" not in row:
1193
+ return None
1194
+ metric_id = str(row["metric_id"])
1195
+ try:
1196
+ deltas[metric_id] = {
1197
+ quantile: float(row[f"{quantile}_delta"])
1198
+ for quantile in ("p10", "p50", "p90")
1199
+ }
1200
+ except (KeyError, TypeError, ValueError):
1201
+ return None
1202
+ confidence = row.get("confidence")
1203
+ if isinstance(confidence, (int, float)) and math.isfinite(
1204
+ float(confidence)
1205
+ ):
1206
+ confidences.append(min(max(float(confidence), 0.0), 1.0))
1207
+ if set(deltas) != set(metric_ids):
1208
+ return None
1209
+ quantile_points = tuple(
1210
+ (
1211
+ quantile,
1212
+ _normalized_point(
1213
+ {
1214
+ metric_id: float(parent_objectives[metric_id])
1215
+ + deltas[metric_id][quantile]
1216
+ for metric_id in metric_ids
1217
+ },
1218
+ axes,
1219
+ ),
1220
+ )
1221
+ for quantile in ("p10", "p50", "p90")
1222
+ )
1223
+ reliability = (
1224
+ sum(confidences) / len(confidences) if confidences else 1.0
1225
+ )
1226
+ return PositiveGainForecast(
1227
+ quantile_points=quantile_points,
1228
+ reliability=float(reliability),
1229
+ )
1230
+
1231
+
1232
+ def _corpus_anchor(
1233
+ raw: dict[str, object],
1234
+ axes: tuple[dict[str, object], ...],
1235
+ metric_ids: tuple[str, ...],
1236
+ ) -> ObjectivePoint | None:
1237
+ """The candidate's parent objective point, when the corpus records it."""
1238
+
1239
+ parent = raw.get("parent")
1240
+ if not isinstance(parent, dict):
1241
+ return None
1242
+ objectives = parent.get("objectives")
1243
+ if not isinstance(objectives, dict) or not set(metric_ids) <= set(
1244
+ objectives
1245
+ ):
1246
+ return None
1247
+ return _normalized_point(
1248
+ {
1249
+ metric_id: float(objectives[metric_id])
1250
+ for metric_id in metric_ids
1251
+ },
1252
+ axes,
1253
+ )
1254
+
1255
+
1256
+ def market_record_from_corpus(payload: dict[str, object]) -> MarketRecord:
1257
+ """Build a MarketRecord from one jul27 replay-corpus JSON payload.
1258
+
1259
+ Objective values are normalized onto each axis's ideal-to-reference
1260
+ interval, so the unit point is the hypervolume reference and the
1261
+ stored exact hypervolumes match the corpus's normalized values.
1262
+ Engine identity falls back lane_id -> expert_id -> family; frozen
1263
+ scores are min-max normalized per market; forecasts are rebuilt as
1264
+ absolute quantile points from parent objectives plus recorded
1265
+ deltas, degrading to no forecast when either half is missing.
1266
+ """
1267
+
1268
+ market_id = str(payload["market_id"])
1269
+ axes = tuple(payload["hv_reference_point"]["axes"])
1270
+ metric_ids = tuple(
1271
+ sorted(str(axis["metric_id"]) for axis in axes)
1272
+ )
1273
+ reference = tuple(
1274
+ sorted((metric_id, 1.0) for metric_id in metric_ids)
1275
+ )
1276
+ archive_points = tuple(
1277
+ _normalized_point(point, axes)
1278
+ for point in payload["archive_at_market"]["points"]
1279
+ )
1280
+ raw_candidates = tuple(payload["candidates"])
1281
+ frozen_values = [
1282
+ value
1283
+ for value in (
1284
+ _corpus_frozen_raw(raw) for raw in raw_candidates
1285
+ )
1286
+ if value is not None
1287
+ ]
1288
+ frozen_low = min(frozen_values) if frozen_values else 0.0
1289
+ frozen_high = max(frozen_values) if frozen_values else 0.0
1290
+ candidates: list[MarketCandidateRecord] = []
1291
+ for raw in raw_candidates:
1292
+ objectives_raw = raw.get("objectives")
1293
+ evaluated = bool(raw.get("evaluated", False))
1294
+ feasible = (
1295
+ evaluated
1296
+ and raw.get("valid") is not False
1297
+ and objectives_raw is not None
1298
+ )
1299
+ frozen_raw = _corpus_frozen_raw(raw)
1300
+ if frozen_raw is None:
1301
+ frozen_score = None
1302
+ elif frozen_high == frozen_low:
1303
+ frozen_score = NEUTRAL_PRIOR_SCORE
1304
+ else:
1305
+ frozen_score = float(
1306
+ (frozen_raw - frozen_low)
1307
+ / (frozen_high - frozen_low)
1308
+ )
1309
+ candidates.append(
1310
+ (
1311
+ _corpus_engine_id(raw),
1312
+ int(raw["native_rank"]),
1313
+ MarketCandidateRecord(
1314
+ action_sha256=_corpus_action_sha256(
1315
+ market_id,
1316
+ raw,
1317
+ ),
1318
+ engine_id=_corpus_engine_id(raw),
1319
+ native_rank=1,
1320
+ frozen_score=frozen_score,
1321
+ forecast=_corpus_forecast(
1322
+ raw,
1323
+ axes,
1324
+ metric_ids,
1325
+ ),
1326
+ evaluated=evaluated,
1327
+ feasible=feasible,
1328
+ objectives=(
1329
+ None
1330
+ if not feasible
1331
+ else _normalized_point(objectives_raw, axes)
1332
+ ),
1333
+ anchor_point=_corpus_anchor(raw, axes, metric_ids),
1334
+ ),
1335
+ )
1336
+ )
1337
+ # A failed materialization can leave native-rank gaps inside an
1338
+ # engine, so ranks are densified per engine preserving order.
1339
+ by_engine: dict[str, list[tuple[int, MarketCandidateRecord]]] = {}
1340
+ for engine_id, native_rank, candidate in candidates:
1341
+ by_engine.setdefault(engine_id, []).append(
1342
+ (native_rank, candidate)
1343
+ )
1344
+ dense: list[MarketCandidateRecord] = []
1345
+ for engine_id in sorted(by_engine):
1346
+ lane = sorted(
1347
+ by_engine[engine_id],
1348
+ key=lambda item: (item[0], item[1].action_sha256),
1349
+ )
1350
+ for rank, (_original_rank, candidate) in enumerate(
1351
+ lane,
1352
+ start=1,
1353
+ ):
1354
+ dense.append(
1355
+ MarketCandidateRecord(
1356
+ action_sha256=candidate.action_sha256,
1357
+ engine_id=candidate.engine_id,
1358
+ native_rank=rank,
1359
+ frozen_score=candidate.frozen_score,
1360
+ forecast=candidate.forecast,
1361
+ evaluated=candidate.evaluated,
1362
+ feasible=candidate.feasible,
1363
+ objectives=candidate.objectives,
1364
+ anchor_point=candidate.anchor_point,
1365
+ )
1366
+ )
1367
+ return MarketRecord(
1368
+ market_id=str(payload["market_id"]),
1369
+ archive_points=archive_points,
1370
+ hv_reference_point=reference,
1371
+ candidates=tuple(dense),
1372
+ )
1373
+
1374
+
1375
+ __all__ = [
1376
+ "DEFAULT_ORACLE_SUBSET_LIMIT",
1377
+ "HYPERVOLUME_GAIN_EPSILON",
1378
+ "NEUTRAL_PRIOR_SCORE",
1379
+ "SEQUENTIAL_MARKET_REPLAY_ID",
1380
+ "SEQUENTIAL_MARKET_REPLAY_VERSION",
1381
+ "ExactHypervolumeGainPort",
1382
+ "FrozenScoreTopKReplayPolicy",
1383
+ "LaneHeadsReplayPolicy",
1384
+ "MarketCandidateRecord",
1385
+ "MarketRecord",
1386
+ "NativeRankRoundRobinReplayPolicy",
1387
+ "ReplayResult",
1388
+ "ReplaySelection",
1389
+ "ReplayStepReceipt",
1390
+ "SequentialMarketReplay",
1391
+ "UniformRandomReplayPolicy",
1392
+ "V8LiteReplayPolicy",
1393
+ "exact_hypervolume",
1394
+ "market_record_from_corpus",
1395
+ ]