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,1346 @@
1
+ """Authenticated, benchmark-neutral parent selection for evolution planners.
2
+
3
+ The strict elite policy rotates only over the archive's exact current front.
4
+ The singleton-safe reservoir policy replays archive admissibility over complete
5
+ candidate history and ranks it from declared objective directions, without any
6
+ benchmark branches. Both produce deterministic, snapshot-bound receipts.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import hashlib
12
+ import json
13
+ import math
14
+ from dataclasses import dataclass, field
15
+ from enum import Enum
16
+ from typing import Protocol
17
+
18
+ from agent_evolve.application.agentic_evolution import EvolutionCandidate
19
+ from agent_evolve.application.budgeted_optimizer import OptimizerState
20
+ from agent_evolve.application.pareto_archive import (
21
+ EvidenceAdmissionPolicy,
22
+ ParetoCandidateRef,
23
+ ParetoDecision,
24
+ ParetoDecisionReason,
25
+ pareto_candidate_hash,
26
+ )
27
+ from agent_evolve.core.problem import (
28
+ ObjectiveSpec,
29
+ ProblemContractError,
30
+ normalize_objective_values,
31
+ validate_objective_specs,
32
+ )
33
+ from agent_evolve.core.results import dominates
34
+ from agent_evolve.domain.patch import require_sha256
35
+
36
+
37
+ POLICY_ID = "task_keyed_archive_elite_parent"
38
+ POLICY_VERSION = 1
39
+ _SCHEMA_VERSION = 1
40
+ _MAX_ROTATION_INDEX = (1 << 63) - 1
41
+ _DEFINITION_DOMAIN = b"agent-evolve:archive-elite-parent:def:v1\x00"
42
+ _ELIGIBLE_FRONT_DOMAIN = b"agent-evolve:archive-elite-parent:front:v1\x00"
43
+ _ROTATION_DOMAIN = b"agent-evolve:archive-elite-parent:rotation:v1\x00"
44
+ _RECEIPT_DOMAIN = b"agent-evolve:archive-elite-parent:receipt:v1\x00"
45
+ _DEFINITION = {
46
+ "eligible_source": "complete OptimizerState.archive.front_candidates only",
47
+ "archive_authority": "exact ParetoArchiveSnapshot and snapshot hash",
48
+ "outcome_or_objective_access": False,
49
+ "selection": "task/archive/front-keyed cyclic rotation without replacement",
50
+ "stale_or_foreign_candidate_admission": False,
51
+ }
52
+
53
+
54
+ def _canonical_json(value: object) -> bytes:
55
+ return json.dumps(
56
+ value,
57
+ ensure_ascii=True,
58
+ allow_nan=False,
59
+ separators=(",", ":"),
60
+ sort_keys=True,
61
+ ).encode("ascii", errors="strict")
62
+
63
+
64
+ POLICY_DEFINITION_SHA256 = hashlib.sha256(
65
+ _DEFINITION_DOMAIN + _canonical_json(_DEFINITION)
66
+ ).hexdigest()
67
+
68
+
69
+ RESERVOIR_POLICY_ID = "task_keyed_archive_ranked_reservoir_parent"
70
+ RESERVOIR_POLICY_VERSION = 1
71
+ _RESERVOIR_SCHEMA_VERSION = 1
72
+ _RESERVOIR_DEFINITION_DOMAIN = (
73
+ b"agent-evolve:archive-ranked-reservoir-parent:def:v1\x00"
74
+ )
75
+ _RESERVOIR_RANKING_DOMAIN = (
76
+ b"agent-evolve:archive-ranked-reservoir-parent:ranking:v1\x00"
77
+ )
78
+ _RESERVOIR_DOMAIN = b"agent-evolve:archive-ranked-reservoir-parent:reservoir:v1\x00"
79
+ _RESERVOIR_ROTATION_DOMAIN = (
80
+ b"agent-evolve:archive-ranked-reservoir-parent:rotation:v1\x00"
81
+ )
82
+ _RESERVOIR_RECEIPT_DOMAIN = (
83
+ b"agent-evolve:archive-ranked-reservoir-parent:receipt:v1\x00"
84
+ )
85
+ _RESERVOIR_DEFINITION = {
86
+ "eligible_source": (
87
+ "complete archive-authenticated, gate-passing unique-configuration history"
88
+ ),
89
+ "ranking": (
90
+ "nondomination rank; multiobjective crowding when meaningful; "
91
+ "minimax dense objective rank; authenticated proposal-sequence recency; "
92
+ "canonical identity"
93
+ ),
94
+ "reservoir": "first min(reservoir_limit, eligible_count) ranked candidates",
95
+ "selection": (
96
+ "task/archive/ranking-keyed cyclic rotation without replacement; "
97
+ "return min(requested_parent_count, reservoir_cardinality)"
98
+ ),
99
+ "benchmark_branching": False,
100
+ "stale_or_foreign_candidate_admission": False,
101
+ }
102
+ RESERVOIR_POLICY_DEFINITION_SHA256 = hashlib.sha256(
103
+ _RESERVOIR_DEFINITION_DOMAIN + _canonical_json(_RESERVOIR_DEFINITION)
104
+ ).hexdigest()
105
+
106
+
107
+ def _reference_record(reference: ParetoCandidateRef) -> dict[str, str]:
108
+ if type(reference) is not ParetoCandidateRef:
109
+ raise TypeError("front references must be exact ParetoCandidateRef values")
110
+ ParetoCandidateRef.__post_init__(reference)
111
+ return reference.to_trace_record()
112
+
113
+
114
+ def _reference_key(reference: ParetoCandidateRef) -> tuple[str, str, str]:
115
+ return (
116
+ reference.configuration_hash,
117
+ reference.candidate_id.value,
118
+ reference.candidate_hash,
119
+ )
120
+
121
+
122
+ def _candidate_reference(candidate: EvolutionCandidate) -> ParetoCandidateRef:
123
+ if type(candidate) is not EvolutionCandidate:
124
+ raise TypeError("archive front must contain exact EvolutionCandidate values")
125
+ EvolutionCandidate.__post_init__(candidate)
126
+ return ParetoCandidateRef(
127
+ candidate_id=candidate.candidate_id,
128
+ candidate_hash=pareto_candidate_hash(candidate),
129
+ configuration_hash=candidate.occurrence.configuration_hash,
130
+ )
131
+
132
+
133
+ def _eligible_front_sha256(front: tuple[ParetoCandidateRef, ...]) -> str:
134
+ if type(front) is not tuple or not front:
135
+ raise ValueError("eligible archive front must be a non-empty exact tuple")
136
+ return hashlib.sha256(
137
+ _ELIGIBLE_FRONT_DOMAIN
138
+ + _canonical_json([_reference_record(reference) for reference in front])
139
+ ).hexdigest()
140
+
141
+
142
+ def _rotation_anchor(
143
+ *,
144
+ task_sha256: str,
145
+ archive_snapshot_hash: str,
146
+ eligible_front_sha256: str,
147
+ cardinality: int,
148
+ ) -> int:
149
+ require_sha256(task_sha256, "task_sha256")
150
+ require_sha256(archive_snapshot_hash, "archive_snapshot_hash")
151
+ require_sha256(eligible_front_sha256, "eligible_front_sha256")
152
+ if type(cardinality) is not int or cardinality <= 0:
153
+ raise ValueError("archive front cardinality must be positive")
154
+ digest = hashlib.sha256(
155
+ _ROTATION_DOMAIN
156
+ + bytes.fromhex(task_sha256)
157
+ + bytes.fromhex(archive_snapshot_hash)
158
+ + bytes.fromhex(eligible_front_sha256)
159
+ ).digest()
160
+ return int.from_bytes(digest, "big", signed=False) % cardinality
161
+
162
+
163
+ def _validated_front(
164
+ state: OptimizerState,
165
+ ) -> tuple[tuple[EvolutionCandidate, ...], tuple[ParetoCandidateRef, ...]]:
166
+ if type(state) is not OptimizerState:
167
+ raise TypeError("state must be an exact OptimizerState")
168
+ OptimizerState.__post_init__(state)
169
+ candidates = state.archive.front_candidates
170
+ references = state.archive.front_references
171
+ if type(candidates) is not tuple or type(references) is not tuple:
172
+ raise TypeError("archive front and references must be exact tuples")
173
+ if not candidates:
174
+ raise ValueError("archive elite parent selection requires a non-empty front")
175
+ if len(candidates) != len(references):
176
+ raise ValueError("archive front candidates and references have different sizes")
177
+
178
+ derived = tuple(_candidate_reference(candidate) for candidate in candidates)
179
+ for observed, expected in zip(references, derived, strict=True):
180
+ _reference_record(observed)
181
+ if observed != expected:
182
+ raise ValueError("archive front candidate does not match its reference")
183
+ if references != tuple(sorted(references, key=_reference_key)):
184
+ raise ValueError("archive front is not in its canonical archive order")
185
+ if len({reference.candidate_id for reference in references}) != len(references):
186
+ raise ValueError("archive front contains duplicate candidate IDs")
187
+ if len({reference.configuration_hash for reference in references}) != len(
188
+ references
189
+ ):
190
+ raise ValueError("archive front contains duplicate configurations")
191
+
192
+ history_by_id = {
193
+ candidate.candidate_id: _candidate_reference(candidate)
194
+ for candidate in state.candidates
195
+ }
196
+ for reference in references:
197
+ if history_by_id.get(reference.candidate_id) != reference:
198
+ raise ValueError("archive front contains a foreign or stale candidate")
199
+ return candidates, references
200
+
201
+
202
+ class ArchiveReservoirCrowdingKind(str, Enum):
203
+ """Whether a replayed crowding score is applicable and finite."""
204
+
205
+ NOT_APPLICABLE = "not_applicable"
206
+ BOUNDARY = "boundary"
207
+ FINITE = "finite"
208
+
209
+
210
+ @dataclass(frozen=True, slots=True)
211
+ class ArchiveReservoirRankedCandidate:
212
+ """One fully ordered, archive-authenticated reservoir candidate."""
213
+
214
+ reference: ParetoCandidateRef
215
+ nondomination_rank: int
216
+ crowding_kind: ArchiveReservoirCrowdingKind
217
+ crowding_distance_hex: str | None
218
+ objective_worst_dense_rank: int
219
+ objective_dense_rank_sum: int
220
+ proposal_sequence: int
221
+
222
+ def __post_init__(self) -> None:
223
+ _reference_record(self.reference)
224
+ for name in (
225
+ "nondomination_rank",
226
+ "objective_worst_dense_rank",
227
+ "objective_dense_rank_sum",
228
+ ):
229
+ value = getattr(self, name)
230
+ if type(value) is not int or value <= 0:
231
+ raise ValueError(f"{name} must be a positive exact integer")
232
+ if type(self.proposal_sequence) is not int or self.proposal_sequence < 0:
233
+ raise ValueError("proposal_sequence must be a non-negative exact integer")
234
+ if type(self.crowding_kind) is not ArchiveReservoirCrowdingKind:
235
+ raise TypeError("crowding_kind must be an ArchiveReservoirCrowdingKind")
236
+ if self.crowding_kind is ArchiveReservoirCrowdingKind.FINITE:
237
+ if type(self.crowding_distance_hex) is not str:
238
+ raise TypeError("finite crowding distance requires a hexadecimal float")
239
+ try:
240
+ distance = float.fromhex(self.crowding_distance_hex)
241
+ except ValueError as exc:
242
+ raise ValueError(
243
+ "crowding_distance_hex is not a hexadecimal float"
244
+ ) from exc
245
+ if not math.isfinite(distance) or distance < 0.0:
246
+ raise ValueError(
247
+ "finite crowding distance must be finite and non-negative"
248
+ )
249
+ if distance.hex() != self.crowding_distance_hex:
250
+ raise ValueError("crowding_distance_hex must be canonical")
251
+ elif self.crowding_distance_hex is not None:
252
+ raise ValueError("non-finite crowding kinds cannot carry a distance")
253
+
254
+ def to_trace_record(self) -> dict[str, object]:
255
+ ArchiveReservoirRankedCandidate.__post_init__(self)
256
+ return {
257
+ "candidate": _reference_record(self.reference),
258
+ "nondomination_rank": self.nondomination_rank,
259
+ "crowding_kind": self.crowding_kind.value,
260
+ "crowding_distance_hex": self.crowding_distance_hex,
261
+ "objective_worst_dense_rank": self.objective_worst_dense_rank,
262
+ "objective_dense_rank_sum": self.objective_dense_rank_sum,
263
+ "proposal_sequence": self.proposal_sequence,
264
+ }
265
+
266
+
267
+ def _candidate_objective_map(
268
+ candidate: EvolutionCandidate,
269
+ objectives: tuple[ObjectiveSpec, ...],
270
+ ) -> dict[str, float]:
271
+ if type(candidate.objectives) is not tuple:
272
+ raise ProblemContractError("candidate objectives must be an exact tuple")
273
+ raw: dict[str, object] = {}
274
+ for item in candidate.objectives:
275
+ if type(item) is not tuple or len(item) != 2:
276
+ raise ProblemContractError(
277
+ "candidate objectives must contain exact (name, value) tuples"
278
+ )
279
+ name, value = item
280
+ if type(name) is not str:
281
+ raise ProblemContractError("candidate objective names must be strings")
282
+ if name in raw:
283
+ raise ProblemContractError(f"duplicate candidate objective {name!r}")
284
+ raw[name] = value
285
+ return normalize_objective_values(raw, objectives)
286
+
287
+
288
+ def _validated_eligible_history(
289
+ state: OptimizerState,
290
+ ) -> tuple[
291
+ tuple[EvolutionCandidate, ...],
292
+ tuple[dict[str, float], ...],
293
+ tuple[ObjectiveSpec, ...],
294
+ ]:
295
+ """Rejoin complete candidate history to the snapshot's consideration ledger."""
296
+
297
+ _validated_front(state)
298
+ snapshot = state.archive
299
+ if not snapshot.objective_pareto_relation:
300
+ raise ValueError(
301
+ "ranked parent reservoirs require objective Pareto archive semantics"
302
+ )
303
+ objectives = snapshot.objectives
304
+ if type(objectives) is not tuple or any(
305
+ type(objective) is not ObjectiveSpec for objective in objectives
306
+ ):
307
+ raise TypeError("archive objectives must contain exact ObjectiveSpec values")
308
+ validate_objective_specs(objectives)
309
+ if type(snapshot.evidence_admission_policy) is not EvidenceAdmissionPolicy:
310
+ raise TypeError(
311
+ "archive evidence_admission_policy must be an EvidenceAdmissionPolicy"
312
+ )
313
+ if (
314
+ type(snapshot.consideration_count) is not int
315
+ or snapshot.consideration_count < 0
316
+ ):
317
+ raise ValueError("archive consideration_count must be non-negative")
318
+ if (
319
+ type(snapshot.eligible_configuration_count) is not int
320
+ or snapshot.eligible_configuration_count < 0
321
+ ):
322
+ raise ValueError("archive eligible_configuration_count must be non-negative")
323
+ decisions = snapshot.decisions
324
+ if type(decisions) is not tuple:
325
+ raise TypeError("archive decisions must be an exact tuple")
326
+
327
+ grouped: dict[int, list[ParetoDecision]] = {}
328
+ previous_consideration = 0
329
+ for expected_sequence, decision in enumerate(decisions, start=1):
330
+ if type(decision) is not ParetoDecision:
331
+ raise TypeError(
332
+ "archive decisions must contain exact ParetoDecision values"
333
+ )
334
+ ParetoDecision.__post_init__(decision)
335
+ if decision.decision_sequence != expected_sequence:
336
+ raise ValueError(
337
+ "archive decision sequences must be contiguous and ordered"
338
+ )
339
+ if decision.consideration_sequence < previous_consideration:
340
+ raise ValueError("archive consideration decisions must remain contiguous")
341
+ if decision.consideration_sequence > snapshot.consideration_count:
342
+ raise ValueError("archive decision exceeds consideration_count")
343
+ previous_consideration = decision.consideration_sequence
344
+ grouped.setdefault(decision.consideration_sequence, []).append(decision)
345
+ if tuple(grouped) != tuple(range(1, snapshot.consideration_count + 1)):
346
+ raise ValueError("archive consideration ledger is incomplete")
347
+
348
+ history_by_id: dict[str, EvolutionCandidate] = {}
349
+ history_references: dict[str, ParetoCandidateRef] = {}
350
+ for candidate in state.candidates:
351
+ reference = _candidate_reference(candidate)
352
+ candidate_id = candidate.candidate_id.value
353
+ history_by_id[candidate_id] = candidate
354
+ history_references[candidate_id] = reference
355
+ if candidate.generation > state.generation:
356
+ raise ValueError("candidate history cannot be newer than optimizer state")
357
+ primary_ids = tuple(
358
+ grouped[index][0].candidate.candidate_id.value
359
+ for index in range(1, snapshot.consideration_count + 1)
360
+ )
361
+ if len(set(primary_ids)) != len(primary_ids):
362
+ raise ValueError("archive consideration ledger repeats a candidate ID")
363
+ if set(primary_ids) != set(history_by_id):
364
+ raise ValueError("candidate history differs from the complete archive ledger")
365
+
366
+ gate_reason_order = (
367
+ ("valid", ParetoDecisionReason.REJECTED_INVALID),
368
+ (
369
+ "operator_compliant",
370
+ ParetoDecisionReason.REJECTED_OPERATOR_NONCOMPLIANT,
371
+ ),
372
+ (
373
+ "evidence_compliant",
374
+ ParetoDecisionReason.REJECTED_EVIDENCE_NONCOMPLIANT,
375
+ ),
376
+ )
377
+ eligible_reasons = {
378
+ ParetoDecisionReason.ADMITTED_NONDOMINATED,
379
+ ParetoDecisionReason.ADMITTED_TIE_BREAK_REPLACEMENT,
380
+ ParetoDecisionReason.REJECTED_DOMINATED,
381
+ ParetoDecisionReason.REJECTED_OBJECTIVE_TIE,
382
+ }
383
+ seen_configurations: set[str] = set()
384
+ eligible_candidates: list[EvolutionCandidate] = []
385
+ objective_maps: list[dict[str, float]] = []
386
+ for consideration in range(1, snapshot.consideration_count + 1):
387
+ primary = grouped[consideration][0]
388
+ candidate_id = primary.candidate.candidate_id.value
389
+ candidate = history_by_id[candidate_id]
390
+ if primary.candidate != history_references[candidate_id]:
391
+ raise ValueError("archive consideration references a foreign candidate")
392
+
393
+ expected_gate_reasons = tuple(
394
+ reason
395
+ for attribute, reason in gate_reason_order
396
+ if not getattr(candidate, attribute)
397
+ and (
398
+ attribute != "evidence_compliant"
399
+ or snapshot.evidence_admission_policy
400
+ is EvidenceAdmissionPolicy.REQUIRE_COMPLIANT
401
+ )
402
+ )
403
+ if expected_gate_reasons:
404
+ if primary.reasons != expected_gate_reasons:
405
+ raise ValueError(
406
+ "archive gate decision differs from candidate evidence"
407
+ )
408
+ continue
409
+ try:
410
+ objective_map = _candidate_objective_map(candidate, objectives)
411
+ except (OverflowError, ProblemContractError, TypeError, ValueError):
412
+ if primary.reasons != (ParetoDecisionReason.REJECTED_OBJECTIVE_CONTRACT,):
413
+ raise ValueError(
414
+ "archive objective-contract decision differs from candidate evidence"
415
+ )
416
+ continue
417
+
418
+ configuration_hash = candidate.occurrence.configuration_hash
419
+ if configuration_hash in seen_configurations:
420
+ if primary.reasons != (
421
+ ParetoDecisionReason.REJECTED_DUPLICATE_CONFIGURATION,
422
+ ):
423
+ raise ValueError(
424
+ "archive duplicate decision differs from consideration history"
425
+ )
426
+ continue
427
+ seen_configurations.add(configuration_hash)
428
+ if len(primary.reasons) != 1 or primary.reasons[0] not in eligible_reasons:
429
+ raise ValueError("eligible archive candidate has a foreign decision reason")
430
+ eligible_candidates.append(candidate)
431
+ objective_maps.append(objective_map)
432
+
433
+ if len(eligible_candidates) != snapshot.eligible_configuration_count:
434
+ raise ValueError("eligible history differs from archive configuration count")
435
+ return tuple(eligible_candidates), tuple(objective_maps), objectives
436
+
437
+
438
+ def _nondomination_ranks(
439
+ objective_maps: tuple[dict[str, float], ...],
440
+ objectives: tuple[ObjectiveSpec, ...],
441
+ ) -> tuple[int, ...]:
442
+ cardinality = len(objective_maps)
443
+ dominated_sets: list[set[int]] = [set() for _ in range(cardinality)]
444
+ dominator_counts = [0] * cardinality
445
+ for left in range(cardinality):
446
+ for right in range(left + 1, cardinality):
447
+ if dominates(objective_maps[left], objective_maps[right], objectives):
448
+ dominated_sets[left].add(right)
449
+ dominator_counts[right] += 1
450
+ elif dominates(objective_maps[right], objective_maps[left], objectives):
451
+ dominated_sets[right].add(left)
452
+ dominator_counts[left] += 1
453
+
454
+ ranks = [0] * cardinality
455
+ current = [index for index, count in enumerate(dominator_counts) if count == 0]
456
+ rank = 1
457
+ ranked_count = 0
458
+ while current:
459
+ following: list[int] = []
460
+ for index in current:
461
+ ranks[index] = rank
462
+ ranked_count += 1
463
+ for dominated in dominated_sets[index]:
464
+ dominator_counts[dominated] -= 1
465
+ if dominator_counts[dominated] == 0:
466
+ following.append(dominated)
467
+ current = following
468
+ rank += 1
469
+ if ranked_count != cardinality:
470
+ raise RuntimeError("nondomination ranking did not cover eligible history")
471
+ return tuple(ranks)
472
+
473
+
474
+ def _objective_dense_ranks(
475
+ candidates: tuple[EvolutionCandidate, ...],
476
+ objective_maps: tuple[dict[str, float], ...],
477
+ objectives: tuple[ObjectiveSpec, ...],
478
+ ) -> tuple[tuple[int, ...], ...]:
479
+ ranks = [[0] * len(objectives) for _ in candidates]
480
+ references = tuple(_candidate_reference(candidate) for candidate in candidates)
481
+ for objective_index, objective in enumerate(objectives):
482
+ order = sorted(
483
+ range(len(candidates)),
484
+ key=lambda index: (
485
+ -objective_maps[index][objective.name]
486
+ if objective.goal == "max"
487
+ else objective_maps[index][objective.name],
488
+ _reference_key(references[index]),
489
+ ),
490
+ )
491
+ dense_rank = 1
492
+ for position, index in enumerate(order):
493
+ if position and (
494
+ objective_maps[index][objective.name]
495
+ != objective_maps[order[position - 1]][objective.name]
496
+ ):
497
+ dense_rank += 1
498
+ ranks[index][objective_index] = dense_rank
499
+ return tuple(tuple(value) for value in ranks)
500
+
501
+
502
+ def _crowding_values(
503
+ candidates: tuple[EvolutionCandidate, ...],
504
+ objective_maps: tuple[dict[str, float], ...],
505
+ objectives: tuple[ObjectiveSpec, ...],
506
+ nondomination_ranks: tuple[int, ...],
507
+ ) -> tuple[tuple[ArchiveReservoirCrowdingKind, float | None], ...]:
508
+ result = [(ArchiveReservoirCrowdingKind.NOT_APPLICABLE, None) for _ in candidates]
509
+ for rank in sorted(set(nondomination_ranks)):
510
+ front = tuple(
511
+ index
512
+ for index, candidate_rank in enumerate(nondomination_ranks)
513
+ if candidate_rank == rank
514
+ )
515
+ if len(objectives) < 2 or len(front) < 3:
516
+ continue
517
+ boundary: set[int] = set()
518
+ distances = {index: 0.0 for index in front}
519
+ varying_objective = False
520
+ for objective in objectives:
521
+ values = {index: objective_maps[index][objective.name] for index in front}
522
+ distinct_values = sorted(set(values.values()))
523
+ if len(distinct_values) < 2:
524
+ continue
525
+ varying_objective = True
526
+ lower = distinct_values[0]
527
+ upper = distinct_values[-1]
528
+ scale = upper - lower
529
+ boundary.update(index for index in front if values[index] in {lower, upper})
530
+ position = {value: index for index, value in enumerate(distinct_values)}
531
+ for index in front:
532
+ value_position = position[values[index]]
533
+ if value_position in (0, len(distinct_values) - 1):
534
+ continue
535
+ gap = (
536
+ distinct_values[value_position + 1]
537
+ - distinct_values[value_position - 1]
538
+ ) / scale
539
+ distances[index] += gap
540
+ if not varying_objective:
541
+ continue
542
+ for index in front:
543
+ result[index] = (
544
+ (ArchiveReservoirCrowdingKind.BOUNDARY, None)
545
+ if index in boundary
546
+ else (ArchiveReservoirCrowdingKind.FINITE, distances[index])
547
+ )
548
+ return tuple(result)
549
+
550
+
551
+ def _reservoir_member_key(
552
+ member: ArchiveReservoirRankedCandidate,
553
+ ) -> tuple[object, ...]:
554
+ ArchiveReservoirRankedCandidate.__post_init__(member)
555
+ crowding_order = {
556
+ ArchiveReservoirCrowdingKind.BOUNDARY: 0,
557
+ ArchiveReservoirCrowdingKind.FINITE: 1,
558
+ ArchiveReservoirCrowdingKind.NOT_APPLICABLE: 2,
559
+ }[member.crowding_kind]
560
+ crowding_distance = (
561
+ 0.0
562
+ if member.crowding_distance_hex is None
563
+ else float.fromhex(member.crowding_distance_hex)
564
+ )
565
+ return (
566
+ member.nondomination_rank,
567
+ crowding_order,
568
+ -crowding_distance,
569
+ member.objective_worst_dense_rank,
570
+ member.objective_dense_rank_sum,
571
+ -member.proposal_sequence,
572
+ *_reference_key(member.reference),
573
+ )
574
+
575
+
576
+ def _ranked_eligible_history(
577
+ state: OptimizerState,
578
+ ) -> tuple[tuple[EvolutionCandidate, ...], tuple[ArchiveReservoirRankedCandidate, ...]]:
579
+ candidates, objective_maps, objectives = _validated_eligible_history(state)
580
+ if not candidates:
581
+ raise ValueError("ranked parent selection requires eligible candidate history")
582
+ nondomination_ranks = _nondomination_ranks(objective_maps, objectives)
583
+ dense_ranks = _objective_dense_ranks(candidates, objective_maps, objectives)
584
+ crowding = _crowding_values(
585
+ candidates,
586
+ objective_maps,
587
+ objectives,
588
+ nondomination_ranks,
589
+ )
590
+ members = tuple(
591
+ ArchiveReservoirRankedCandidate(
592
+ reference=_candidate_reference(candidate),
593
+ nondomination_rank=nondomination_ranks[index],
594
+ crowding_kind=crowding[index][0],
595
+ crowding_distance_hex=(
596
+ None if crowding[index][1] is None else crowding[index][1].hex()
597
+ ),
598
+ objective_worst_dense_rank=max(dense_ranks[index]),
599
+ objective_dense_rank_sum=sum(dense_ranks[index]),
600
+ proposal_sequence=candidate.occurrence.proposal_sequence,
601
+ )
602
+ for index, candidate in enumerate(candidates)
603
+ )
604
+ ranked_members = tuple(sorted(members, key=_reservoir_member_key))
605
+ candidates_by_id = {candidate.candidate_id: candidate for candidate in candidates}
606
+ ranked_candidates = tuple(
607
+ candidates_by_id[member.reference.candidate_id] for member in ranked_members
608
+ )
609
+ return ranked_candidates, ranked_members
610
+
611
+
612
+ def _eligible_ranking_sha256(
613
+ ranking: tuple[ArchiveReservoirRankedCandidate, ...],
614
+ ) -> str:
615
+ if type(ranking) is not tuple or not ranking:
616
+ raise ValueError("eligible ranking must be a non-empty exact tuple")
617
+ return hashlib.sha256(
618
+ _RESERVOIR_RANKING_DOMAIN
619
+ + _canonical_json([member.to_trace_record() for member in ranking])
620
+ ).hexdigest()
621
+
622
+
623
+ def _reservoir_sha256(reservoir: tuple[ParetoCandidateRef, ...]) -> str:
624
+ if type(reservoir) is not tuple or not reservoir:
625
+ raise ValueError("parent reservoir must be a non-empty exact tuple")
626
+ return hashlib.sha256(
627
+ _RESERVOIR_DOMAIN
628
+ + _canonical_json([_reference_record(reference) for reference in reservoir])
629
+ ).hexdigest()
630
+
631
+
632
+ def _reservoir_rotation_anchor(
633
+ *,
634
+ task_sha256: str,
635
+ archive_snapshot_hash: str,
636
+ eligible_ranking_sha256: str,
637
+ reservoir_sha256: str,
638
+ cardinality: int,
639
+ ) -> int:
640
+ require_sha256(task_sha256, "task_sha256")
641
+ require_sha256(archive_snapshot_hash, "archive_snapshot_hash")
642
+ require_sha256(eligible_ranking_sha256, "eligible_ranking_sha256")
643
+ require_sha256(reservoir_sha256, "reservoir_sha256")
644
+ if type(cardinality) is not int or cardinality <= 0:
645
+ raise ValueError("parent reservoir cardinality must be positive")
646
+ digest = hashlib.sha256(
647
+ _RESERVOIR_ROTATION_DOMAIN
648
+ + bytes.fromhex(task_sha256)
649
+ + bytes.fromhex(archive_snapshot_hash)
650
+ + bytes.fromhex(eligible_ranking_sha256)
651
+ + bytes.fromhex(reservoir_sha256)
652
+ ).digest()
653
+ return int.from_bytes(digest, "big", signed=False) % cardinality
654
+
655
+
656
+ @dataclass(frozen=True, slots=True)
657
+ class ArchiveEliteParentSelectionReceipt:
658
+ """Replayable binding of one parent choice to the complete archive front."""
659
+
660
+ task_sha256: str
661
+ optimizer_generation: int
662
+ archive_snapshot_hash: str
663
+ eligible_front: tuple[ParetoCandidateRef, ...]
664
+ requested_parent_count: int
665
+ rotation_index: int
666
+ rotation_anchor: int
667
+ selected_ordinals: tuple[int, ...]
668
+ selected_parents: tuple[ParetoCandidateRef, ...]
669
+ schema_version: int = field(init=False, default=_SCHEMA_VERSION)
670
+ policy_id: str = field(init=False, default=POLICY_ID)
671
+ policy_version: int = field(init=False, default=POLICY_VERSION)
672
+ policy_definition_sha256: str = field(
673
+ init=False,
674
+ default=POLICY_DEFINITION_SHA256,
675
+ )
676
+ eligible_front_sha256: str = field(init=False, default="")
677
+ receipt_sha256: str = field(init=False, default="")
678
+
679
+ def __post_init__(self) -> None:
680
+ if (
681
+ self.schema_version != _SCHEMA_VERSION
682
+ or self.policy_id != POLICY_ID
683
+ or self.policy_version != POLICY_VERSION
684
+ or self.policy_definition_sha256 != POLICY_DEFINITION_SHA256
685
+ ):
686
+ raise ValueError("archive elite receipt uses a foreign policy identity")
687
+ require_sha256(self.task_sha256, "task_sha256")
688
+ require_sha256(self.archive_snapshot_hash, "archive_snapshot_hash")
689
+ if type(self.optimizer_generation) is not int or self.optimizer_generation < 0:
690
+ raise ValueError("optimizer_generation must be non-negative")
691
+ if type(self.eligible_front) is not tuple or not self.eligible_front:
692
+ raise ValueError("eligible_front must be a non-empty exact tuple")
693
+ for reference in self.eligible_front:
694
+ _reference_record(reference)
695
+ if self.eligible_front != tuple(
696
+ sorted(self.eligible_front, key=_reference_key)
697
+ ):
698
+ raise ValueError("eligible_front must preserve canonical archive order")
699
+ if len({value.candidate_id for value in self.eligible_front}) != len(
700
+ self.eligible_front
701
+ ):
702
+ raise ValueError("eligible_front contains duplicate candidate IDs")
703
+ if len({value.configuration_hash for value in self.eligible_front}) != len(
704
+ self.eligible_front
705
+ ):
706
+ raise ValueError("eligible_front contains duplicate configurations")
707
+
708
+ cardinality = len(self.eligible_front)
709
+ if (
710
+ type(self.requested_parent_count) is not int
711
+ or not 1 <= self.requested_parent_count <= cardinality
712
+ ):
713
+ raise ValueError("requested_parent_count must lie within the front")
714
+ if (
715
+ type(self.rotation_index) is not int
716
+ or not 0 <= self.rotation_index <= _MAX_ROTATION_INDEX
717
+ ):
718
+ raise ValueError("rotation_index must be an exact non-negative int63")
719
+
720
+ computed_front_sha256 = _eligible_front_sha256(self.eligible_front)
721
+ if self.eligible_front_sha256 not in ("", computed_front_sha256):
722
+ raise ValueError("eligible_front_sha256 does not identify eligible_front")
723
+ object.__setattr__(
724
+ self,
725
+ "eligible_front_sha256",
726
+ computed_front_sha256,
727
+ )
728
+ expected_anchor = _rotation_anchor(
729
+ task_sha256=self.task_sha256,
730
+ archive_snapshot_hash=self.archive_snapshot_hash,
731
+ eligible_front_sha256=computed_front_sha256,
732
+ cardinality=cardinality,
733
+ )
734
+ if (
735
+ type(self.rotation_anchor) is not int
736
+ or self.rotation_anchor != expected_anchor
737
+ ):
738
+ raise ValueError("rotation_anchor does not replay the task-keyed policy")
739
+ expected_ordinals = tuple(
740
+ (expected_anchor + self.rotation_index + offset) % cardinality
741
+ for offset in range(self.requested_parent_count)
742
+ )
743
+ if type(self.selected_ordinals) is not tuple:
744
+ raise TypeError("selected_ordinals must be an exact tuple")
745
+ if any(type(ordinal) is not int for ordinal in self.selected_ordinals):
746
+ raise TypeError("selected_ordinals must contain exact ints")
747
+ if type(self.selected_parents) is not tuple:
748
+ raise TypeError("selected_parents must be an exact tuple")
749
+ for reference in self.selected_parents:
750
+ _reference_record(reference)
751
+ if self.selected_ordinals != expected_ordinals:
752
+ raise ValueError("selected_ordinals do not replay the cyclic rotation")
753
+ if self.selected_parents != tuple(
754
+ self.eligible_front[ordinal] for ordinal in expected_ordinals
755
+ ):
756
+ raise ValueError("selected_parents do not match selected_ordinals")
757
+ if len(set(self.selected_ordinals)) != len(self.selected_ordinals):
758
+ raise ValueError("parent selection must be without replacement")
759
+
760
+ computed_receipt_sha256 = hashlib.sha256(
761
+ _RECEIPT_DOMAIN + _canonical_json(self._record_without_hash())
762
+ ).hexdigest()
763
+ if self.receipt_sha256 not in ("", computed_receipt_sha256):
764
+ raise ValueError("receipt_sha256 does not verify")
765
+ object.__setattr__(self, "receipt_sha256", computed_receipt_sha256)
766
+
767
+ def _record_without_hash(self) -> dict[str, object]:
768
+ return {
769
+ "schema_version": self.schema_version,
770
+ "policy_id": self.policy_id,
771
+ "policy_version": self.policy_version,
772
+ "policy_definition_sha256": self.policy_definition_sha256,
773
+ "task_sha256": self.task_sha256,
774
+ "optimizer_generation": self.optimizer_generation,
775
+ "archive_snapshot_hash": self.archive_snapshot_hash,
776
+ "eligible_front": [
777
+ _reference_record(reference) for reference in self.eligible_front
778
+ ],
779
+ "eligible_front_sha256": self.eligible_front_sha256,
780
+ "requested_parent_count": self.requested_parent_count,
781
+ "rotation_index": self.rotation_index,
782
+ "rotation_anchor": self.rotation_anchor,
783
+ "selected_ordinals": list(self.selected_ordinals),
784
+ "selected_parents": [
785
+ _reference_record(reference) for reference in self.selected_parents
786
+ ],
787
+ }
788
+
789
+ def revalidate(self) -> None:
790
+ if type(self) is not ArchiveEliteParentSelectionReceipt:
791
+ raise TypeError(
792
+ "receipt must be an exact ArchiveEliteParentSelectionReceipt"
793
+ )
794
+ ArchiveEliteParentSelectionReceipt.__post_init__(self)
795
+
796
+ def to_trace_record(self) -> dict[str, object]:
797
+ self.revalidate()
798
+ return {**self._record_without_hash(), "receipt_sha256": self.receipt_sha256}
799
+
800
+
801
+ @dataclass(frozen=True, slots=True)
802
+ class ArchiveEliteParentSelection:
803
+ """Selected immutable parent values plus their audit receipt."""
804
+
805
+ parents: tuple[EvolutionCandidate, ...]
806
+ receipt: ArchiveEliteParentSelectionReceipt
807
+
808
+ def __post_init__(self) -> None:
809
+ if type(self.parents) is not tuple or not self.parents:
810
+ raise ValueError("parents must be a non-empty exact tuple")
811
+ if any(type(parent) is not EvolutionCandidate for parent in self.parents):
812
+ raise TypeError("parents must contain exact EvolutionCandidate values")
813
+ for parent in self.parents:
814
+ EvolutionCandidate.__post_init__(parent)
815
+ if type(self.receipt) is not ArchiveEliteParentSelectionReceipt:
816
+ raise TypeError("receipt must be an exact archive elite receipt")
817
+ self.receipt.revalidate()
818
+ if len(self.parents) != self.receipt.requested_parent_count:
819
+ raise ValueError("selected parent count differs from its receipt")
820
+ observed = tuple(_candidate_reference(parent) for parent in self.parents)
821
+ if observed != self.receipt.selected_parents:
822
+ raise ValueError("selected parent values differ from their receipt")
823
+
824
+ def revalidate(self) -> None:
825
+ if type(self) is not ArchiveEliteParentSelection:
826
+ raise TypeError("selection must be an exact ArchiveEliteParentSelection")
827
+ ArchiveEliteParentSelection.__post_init__(self)
828
+
829
+
830
+ def validate_archive_elite_parent_selection(
831
+ state: OptimizerState,
832
+ selection: ArchiveEliteParentSelection,
833
+ ) -> None:
834
+ """Reject a stale, foreign, or tampered selection at planner admission."""
835
+
836
+ candidates, references = _validated_front(state)
837
+ if type(selection) is not ArchiveEliteParentSelection:
838
+ raise TypeError("selection must be an exact ArchiveEliteParentSelection")
839
+ selection.revalidate()
840
+ receipt = selection.receipt
841
+ if receipt.optimizer_generation != state.generation:
842
+ raise ValueError("archive elite selection is stale for this generation")
843
+ if receipt.archive_snapshot_hash != state.archive_snapshot_hash:
844
+ raise ValueError("archive elite selection is stale for this archive snapshot")
845
+ if receipt.eligible_front != references:
846
+ raise ValueError(
847
+ "archive elite receipt does not bind the complete current front"
848
+ )
849
+ expected_parents = tuple(candidates[index] for index in receipt.selected_ordinals)
850
+ if selection.parents != expected_parents:
851
+ raise ValueError("archive elite parents are foreign to the current front")
852
+
853
+
854
+ class ArchiveEliteParentSelector(Protocol):
855
+ """Inverted planner seam for objective-blind archive parent selection."""
856
+
857
+ policy_id: str
858
+ policy_version: int
859
+ definition_sha256: str
860
+
861
+ def select(
862
+ self,
863
+ state: OptimizerState,
864
+ *,
865
+ task_sha256: str,
866
+ expected_archive_snapshot_hash: str,
867
+ parent_count: int = 1,
868
+ rotation_index: int = 0,
869
+ ) -> ArchiveEliteParentSelection: ...
870
+
871
+ def to_record(self) -> dict[str, object]: ...
872
+
873
+
874
+ @dataclass(frozen=True, slots=True)
875
+ class TaskKeyedArchiveEliteParentPolicy:
876
+ """Select distinct elite parents without reading benchmark semantics."""
877
+
878
+ policy_id: str = field(init=False, default=POLICY_ID)
879
+ policy_version: int = field(init=False, default=POLICY_VERSION)
880
+ definition_sha256: str = field(
881
+ init=False,
882
+ default=POLICY_DEFINITION_SHA256,
883
+ )
884
+
885
+ def _validate_identity(self) -> None:
886
+ if type(self) is not TaskKeyedArchiveEliteParentPolicy:
887
+ raise TypeError("policy must be an exact TaskKeyedArchiveEliteParentPolicy")
888
+ if (
889
+ self.policy_id != POLICY_ID
890
+ or self.policy_version != POLICY_VERSION
891
+ or self.definition_sha256 != POLICY_DEFINITION_SHA256
892
+ ):
893
+ raise ValueError("archive elite selector uses a foreign policy identity")
894
+
895
+ def select(
896
+ self,
897
+ state: OptimizerState,
898
+ *,
899
+ task_sha256: str,
900
+ expected_archive_snapshot_hash: str,
901
+ parent_count: int = 1,
902
+ rotation_index: int = 0,
903
+ ) -> ArchiveEliteParentSelection:
904
+ self._validate_identity()
905
+ require_sha256(task_sha256, "task_sha256")
906
+ require_sha256(
907
+ expected_archive_snapshot_hash,
908
+ "expected_archive_snapshot_hash",
909
+ )
910
+ candidates, references = _validated_front(state)
911
+ if expected_archive_snapshot_hash != state.archive_snapshot_hash:
912
+ raise ValueError("expected archive snapshot is stale")
913
+ if type(parent_count) is not int or not 1 <= parent_count <= len(references):
914
+ raise ValueError("parent_count must lie within the archive front")
915
+ if (
916
+ type(rotation_index) is not int
917
+ or not 0 <= rotation_index <= _MAX_ROTATION_INDEX
918
+ ):
919
+ raise ValueError("rotation_index must be an exact non-negative int63")
920
+
921
+ front_sha256 = _eligible_front_sha256(references)
922
+ anchor = _rotation_anchor(
923
+ task_sha256=task_sha256,
924
+ archive_snapshot_hash=state.archive_snapshot_hash,
925
+ eligible_front_sha256=front_sha256,
926
+ cardinality=len(references),
927
+ )
928
+ ordinals = tuple(
929
+ (anchor + rotation_index + offset) % len(references)
930
+ for offset in range(parent_count)
931
+ )
932
+ receipt = ArchiveEliteParentSelectionReceipt(
933
+ task_sha256=task_sha256,
934
+ optimizer_generation=state.generation,
935
+ archive_snapshot_hash=state.archive_snapshot_hash,
936
+ eligible_front=references,
937
+ requested_parent_count=parent_count,
938
+ rotation_index=rotation_index,
939
+ rotation_anchor=anchor,
940
+ selected_ordinals=ordinals,
941
+ selected_parents=tuple(references[index] for index in ordinals),
942
+ )
943
+ selection = ArchiveEliteParentSelection(
944
+ parents=tuple(candidates[index] for index in ordinals),
945
+ receipt=receipt,
946
+ )
947
+ validate_archive_elite_parent_selection(state, selection)
948
+ return selection
949
+
950
+ def to_record(self) -> dict[str, object]:
951
+ self._validate_identity()
952
+ return {
953
+ "policy_id": self.policy_id,
954
+ "policy_version": self.policy_version,
955
+ "definition_sha256": self.definition_sha256,
956
+ }
957
+
958
+
959
+ @dataclass(frozen=True, slots=True)
960
+ class ArchiveReservoirParentSelectionReceipt:
961
+ """Replayable binding of a capped parent choice to complete ranked history."""
962
+
963
+ task_sha256: str
964
+ optimizer_generation: int
965
+ archive_snapshot_hash: str
966
+ eligible_ranking: tuple[ArchiveReservoirRankedCandidate, ...]
967
+ reservoir_limit: int
968
+ reservoir: tuple[ParetoCandidateRef, ...]
969
+ requested_parent_count: int
970
+ returned_parent_count: int
971
+ rotation_index: int
972
+ rotation_anchor: int
973
+ selected_ordinals: tuple[int, ...]
974
+ selected_parents: tuple[ParetoCandidateRef, ...]
975
+ schema_version: int = field(init=False, default=_RESERVOIR_SCHEMA_VERSION)
976
+ policy_id: str = field(init=False, default=RESERVOIR_POLICY_ID)
977
+ policy_version: int = field(init=False, default=RESERVOIR_POLICY_VERSION)
978
+ policy_definition_sha256: str = field(
979
+ init=False,
980
+ default=RESERVOIR_POLICY_DEFINITION_SHA256,
981
+ )
982
+ eligible_ranking_sha256: str = field(init=False, default="")
983
+ reservoir_sha256: str = field(init=False, default="")
984
+ receipt_sha256: str = field(init=False, default="")
985
+
986
+ def __post_init__(self) -> None:
987
+ if (
988
+ self.schema_version != _RESERVOIR_SCHEMA_VERSION
989
+ or self.policy_id != RESERVOIR_POLICY_ID
990
+ or self.policy_version != RESERVOIR_POLICY_VERSION
991
+ or self.policy_definition_sha256 != RESERVOIR_POLICY_DEFINITION_SHA256
992
+ ):
993
+ raise ValueError("archive reservoir receipt uses a foreign policy identity")
994
+ require_sha256(self.task_sha256, "task_sha256")
995
+ require_sha256(self.archive_snapshot_hash, "archive_snapshot_hash")
996
+ if type(self.optimizer_generation) is not int or self.optimizer_generation < 0:
997
+ raise ValueError("optimizer_generation must be non-negative")
998
+ if type(self.eligible_ranking) is not tuple or not self.eligible_ranking:
999
+ raise ValueError("eligible_ranking must be a non-empty exact tuple")
1000
+ if any(
1001
+ type(member) is not ArchiveReservoirRankedCandidate
1002
+ for member in self.eligible_ranking
1003
+ ):
1004
+ raise TypeError("eligible_ranking must contain exact ranked candidates")
1005
+ for member in self.eligible_ranking:
1006
+ ArchiveReservoirRankedCandidate.__post_init__(member)
1007
+ if self.eligible_ranking != tuple(
1008
+ sorted(self.eligible_ranking, key=_reservoir_member_key)
1009
+ ):
1010
+ raise ValueError("eligible_ranking does not preserve policy order")
1011
+ references = tuple(member.reference for member in self.eligible_ranking)
1012
+ if len({value.candidate_id for value in references}) != len(references):
1013
+ raise ValueError("eligible_ranking contains duplicate candidate IDs")
1014
+ if len({value.configuration_hash for value in references}) != len(references):
1015
+ raise ValueError("eligible_ranking contains duplicate configurations")
1016
+ observed_ranks = {member.nondomination_rank for member in self.eligible_ranking}
1017
+ if observed_ranks != set(range(1, max(observed_ranks) + 1)):
1018
+ raise ValueError("eligible_ranking has non-contiguous nondomination ranks")
1019
+
1020
+ computed_ranking_sha256 = _eligible_ranking_sha256(self.eligible_ranking)
1021
+ if self.eligible_ranking_sha256 not in ("", computed_ranking_sha256):
1022
+ raise ValueError("eligible_ranking_sha256 does not identify ranking")
1023
+ object.__setattr__(
1024
+ self,
1025
+ "eligible_ranking_sha256",
1026
+ computed_ranking_sha256,
1027
+ )
1028
+ if type(self.reservoir_limit) is not int or self.reservoir_limit <= 0:
1029
+ raise ValueError("reservoir_limit must be a positive exact integer")
1030
+ expected_reservoir = references[: min(self.reservoir_limit, len(references))]
1031
+ if type(self.reservoir) is not tuple:
1032
+ raise TypeError("reservoir must be an exact tuple")
1033
+ for reference in self.reservoir:
1034
+ _reference_record(reference)
1035
+ if self.reservoir != expected_reservoir:
1036
+ raise ValueError("reservoir is not the ranked top-k eligible prefix")
1037
+ computed_reservoir_sha256 = _reservoir_sha256(self.reservoir)
1038
+ if self.reservoir_sha256 not in ("", computed_reservoir_sha256):
1039
+ raise ValueError("reservoir_sha256 does not identify reservoir")
1040
+ object.__setattr__(self, "reservoir_sha256", computed_reservoir_sha256)
1041
+
1042
+ if (
1043
+ type(self.requested_parent_count) is not int
1044
+ or self.requested_parent_count <= 0
1045
+ ):
1046
+ raise ValueError("requested_parent_count must be a positive exact integer")
1047
+ expected_returned = min(self.requested_parent_count, len(self.reservoir))
1048
+ if (
1049
+ type(self.returned_parent_count) is not int
1050
+ or self.returned_parent_count != expected_returned
1051
+ ):
1052
+ raise ValueError("returned_parent_count does not apply the singleton cap")
1053
+ if (
1054
+ type(self.rotation_index) is not int
1055
+ or not 0 <= self.rotation_index <= _MAX_ROTATION_INDEX
1056
+ ):
1057
+ raise ValueError("rotation_index must be an exact non-negative int63")
1058
+ expected_anchor = _reservoir_rotation_anchor(
1059
+ task_sha256=self.task_sha256,
1060
+ archive_snapshot_hash=self.archive_snapshot_hash,
1061
+ eligible_ranking_sha256=computed_ranking_sha256,
1062
+ reservoir_sha256=computed_reservoir_sha256,
1063
+ cardinality=len(self.reservoir),
1064
+ )
1065
+ if (
1066
+ type(self.rotation_anchor) is not int
1067
+ or self.rotation_anchor != expected_anchor
1068
+ ):
1069
+ raise ValueError("rotation_anchor does not replay the reservoir policy")
1070
+ expected_ordinals = tuple(
1071
+ (expected_anchor + self.rotation_index + offset) % len(self.reservoir)
1072
+ for offset in range(expected_returned)
1073
+ )
1074
+ if type(self.selected_ordinals) is not tuple or any(
1075
+ type(ordinal) is not int for ordinal in self.selected_ordinals
1076
+ ):
1077
+ raise TypeError("selected_ordinals must be an exact tuple of exact ints")
1078
+ if self.selected_ordinals != expected_ordinals:
1079
+ raise ValueError("selected_ordinals do not replay the cyclic rotation")
1080
+ if len(set(self.selected_ordinals)) != len(self.selected_ordinals):
1081
+ raise ValueError("reservoir parent selection must be without replacement")
1082
+ if type(self.selected_parents) is not tuple:
1083
+ raise TypeError("selected_parents must be an exact tuple")
1084
+ for reference in self.selected_parents:
1085
+ _reference_record(reference)
1086
+ if self.selected_parents != tuple(
1087
+ self.reservoir[ordinal] for ordinal in expected_ordinals
1088
+ ):
1089
+ raise ValueError("selected_parents do not match selected_ordinals")
1090
+
1091
+ computed_receipt_sha256 = hashlib.sha256(
1092
+ _RESERVOIR_RECEIPT_DOMAIN + _canonical_json(self._record_without_hash())
1093
+ ).hexdigest()
1094
+ if self.receipt_sha256 not in ("", computed_receipt_sha256):
1095
+ raise ValueError("receipt_sha256 does not verify")
1096
+ object.__setattr__(self, "receipt_sha256", computed_receipt_sha256)
1097
+
1098
+ def _record_without_hash(self) -> dict[str, object]:
1099
+ return {
1100
+ "schema_version": self.schema_version,
1101
+ "policy_id": self.policy_id,
1102
+ "policy_version": self.policy_version,
1103
+ "policy_definition_sha256": self.policy_definition_sha256,
1104
+ "task_sha256": self.task_sha256,
1105
+ "optimizer_generation": self.optimizer_generation,
1106
+ "archive_snapshot_hash": self.archive_snapshot_hash,
1107
+ "eligible_ranking": [
1108
+ member.to_trace_record() for member in self.eligible_ranking
1109
+ ],
1110
+ "eligible_ranking_sha256": self.eligible_ranking_sha256,
1111
+ "reservoir_limit": self.reservoir_limit,
1112
+ "reservoir": [_reference_record(reference) for reference in self.reservoir],
1113
+ "reservoir_sha256": self.reservoir_sha256,
1114
+ "requested_parent_count": self.requested_parent_count,
1115
+ "returned_parent_count": self.returned_parent_count,
1116
+ "rotation_index": self.rotation_index,
1117
+ "rotation_anchor": self.rotation_anchor,
1118
+ "selected_ordinals": list(self.selected_ordinals),
1119
+ "selected_parents": [
1120
+ _reference_record(reference) for reference in self.selected_parents
1121
+ ],
1122
+ }
1123
+
1124
+ def revalidate(self) -> None:
1125
+ if type(self) is not ArchiveReservoirParentSelectionReceipt:
1126
+ raise TypeError(
1127
+ "receipt must be an exact ArchiveReservoirParentSelectionReceipt"
1128
+ )
1129
+ ArchiveReservoirParentSelectionReceipt.__post_init__(self)
1130
+
1131
+ def to_trace_record(self) -> dict[str, object]:
1132
+ self.revalidate()
1133
+ return {**self._record_without_hash(), "receipt_sha256": self.receipt_sha256}
1134
+
1135
+
1136
+ @dataclass(frozen=True, slots=True)
1137
+ class ArchiveReservoirParentSelection:
1138
+ """Up-to-K distinct parents plus their ranked-reservoir receipt."""
1139
+
1140
+ parents: tuple[EvolutionCandidate, ...]
1141
+ receipt: ArchiveReservoirParentSelectionReceipt
1142
+
1143
+ def __post_init__(self) -> None:
1144
+ if type(self.parents) is not tuple or not self.parents:
1145
+ raise ValueError("parents must be a non-empty exact tuple")
1146
+ if any(type(parent) is not EvolutionCandidate for parent in self.parents):
1147
+ raise TypeError("parents must contain exact EvolutionCandidate values")
1148
+ for parent in self.parents:
1149
+ EvolutionCandidate.__post_init__(parent)
1150
+ if type(self.receipt) is not ArchiveReservoirParentSelectionReceipt:
1151
+ raise TypeError("receipt must be an exact archive reservoir receipt")
1152
+ self.receipt.revalidate()
1153
+ if len(self.parents) != self.receipt.returned_parent_count:
1154
+ raise ValueError("selected parent count differs from its receipt")
1155
+ if len({parent.candidate_id for parent in self.parents}) != len(self.parents):
1156
+ raise ValueError("selected parent occurrences must be distinct")
1157
+ if len(
1158
+ {parent.occurrence.configuration_hash for parent in self.parents}
1159
+ ) != len(self.parents):
1160
+ raise ValueError("selected parent configurations must be distinct")
1161
+ if tuple(_candidate_reference(parent) for parent in self.parents) != (
1162
+ self.receipt.selected_parents
1163
+ ):
1164
+ raise ValueError("selected parent values differ from their receipt")
1165
+
1166
+ def revalidate(self) -> None:
1167
+ if type(self) is not ArchiveReservoirParentSelection:
1168
+ raise TypeError(
1169
+ "selection must be an exact ArchiveReservoirParentSelection"
1170
+ )
1171
+ ArchiveReservoirParentSelection.__post_init__(self)
1172
+
1173
+
1174
+ def validate_archive_reservoir_parent_selection(
1175
+ state: OptimizerState,
1176
+ selection: ArchiveReservoirParentSelection,
1177
+ ) -> None:
1178
+ """Reject stale, foreign, incompletely ranked, or tampered reservoir choices."""
1179
+
1180
+ ranked_candidates, ranked_members = _ranked_eligible_history(state)
1181
+ if type(selection) is not ArchiveReservoirParentSelection:
1182
+ raise TypeError("selection must be an exact ArchiveReservoirParentSelection")
1183
+ selection.revalidate()
1184
+ receipt = selection.receipt
1185
+ if receipt.optimizer_generation != state.generation:
1186
+ raise ValueError("archive reservoir selection is stale for this generation")
1187
+ if receipt.archive_snapshot_hash != state.archive_snapshot_hash:
1188
+ raise ValueError("archive reservoir selection is stale for this snapshot")
1189
+ if receipt.eligible_ranking != ranked_members:
1190
+ raise ValueError("receipt does not bind the complete current eligible ranking")
1191
+ expected_reservoir_members = ranked_members[
1192
+ : min(receipt.reservoir_limit, len(ranked_members))
1193
+ ]
1194
+ if receipt.reservoir != tuple(
1195
+ member.reference for member in expected_reservoir_members
1196
+ ):
1197
+ raise ValueError("receipt reservoir differs from the current ranked top-k")
1198
+ expected_parents = tuple(
1199
+ ranked_candidates[ordinal] for ordinal in receipt.selected_ordinals
1200
+ )
1201
+ if selection.parents != expected_parents:
1202
+ raise ValueError("archive reservoir parents are foreign to current history")
1203
+
1204
+
1205
+ class ArchiveReservoirParentSelector(Protocol):
1206
+ """Inverted planner seam for singleton-safe ranked parent reservoirs."""
1207
+
1208
+ policy_id: str
1209
+ policy_version: int
1210
+ definition_sha256: str
1211
+
1212
+ def select(
1213
+ self,
1214
+ state: OptimizerState,
1215
+ *,
1216
+ task_sha256: str,
1217
+ expected_archive_snapshot_hash: str,
1218
+ reservoir_limit: int,
1219
+ parent_count: int = 1,
1220
+ rotation_index: int = 0,
1221
+ ) -> ArchiveReservoirParentSelection: ...
1222
+
1223
+ def to_record(self) -> dict[str, object]: ...
1224
+
1225
+
1226
+ @dataclass(frozen=True, slots=True)
1227
+ class TaskKeyedArchiveReservoirParentPolicy:
1228
+ """Rank eligible history generically, then rotate over its top-k reservoir."""
1229
+
1230
+ policy_id: str = field(init=False, default=RESERVOIR_POLICY_ID)
1231
+ policy_version: int = field(init=False, default=RESERVOIR_POLICY_VERSION)
1232
+ definition_sha256: str = field(
1233
+ init=False,
1234
+ default=RESERVOIR_POLICY_DEFINITION_SHA256,
1235
+ )
1236
+
1237
+ def _validate_identity(self) -> None:
1238
+ if type(self) is not TaskKeyedArchiveReservoirParentPolicy:
1239
+ raise TypeError(
1240
+ "policy must be an exact TaskKeyedArchiveReservoirParentPolicy"
1241
+ )
1242
+ if (
1243
+ self.policy_id != RESERVOIR_POLICY_ID
1244
+ or self.policy_version != RESERVOIR_POLICY_VERSION
1245
+ or self.definition_sha256 != RESERVOIR_POLICY_DEFINITION_SHA256
1246
+ ):
1247
+ raise ValueError("archive reservoir selector uses a foreign identity")
1248
+
1249
+ def select(
1250
+ self,
1251
+ state: OptimizerState,
1252
+ *,
1253
+ task_sha256: str,
1254
+ expected_archive_snapshot_hash: str,
1255
+ reservoir_limit: int,
1256
+ parent_count: int = 1,
1257
+ rotation_index: int = 0,
1258
+ ) -> ArchiveReservoirParentSelection:
1259
+ self._validate_identity()
1260
+ require_sha256(task_sha256, "task_sha256")
1261
+ require_sha256(
1262
+ expected_archive_snapshot_hash,
1263
+ "expected_archive_snapshot_hash",
1264
+ )
1265
+ if type(reservoir_limit) is not int or reservoir_limit <= 0:
1266
+ raise ValueError("reservoir_limit must be a positive exact integer")
1267
+ if type(parent_count) is not int or parent_count <= 0:
1268
+ raise ValueError("parent_count must be a positive exact integer")
1269
+ if (
1270
+ type(rotation_index) is not int
1271
+ or not 0 <= rotation_index <= _MAX_ROTATION_INDEX
1272
+ ):
1273
+ raise ValueError("rotation_index must be an exact non-negative int63")
1274
+ ranked_candidates, ranking = _ranked_eligible_history(state)
1275
+ if expected_archive_snapshot_hash != state.archive_snapshot_hash:
1276
+ raise ValueError("expected archive snapshot is stale")
1277
+
1278
+ reservoir_cardinality = min(reservoir_limit, len(ranking))
1279
+ reservoir_candidates = ranked_candidates[:reservoir_cardinality]
1280
+ reservoir = tuple(
1281
+ member.reference for member in ranking[:reservoir_cardinality]
1282
+ )
1283
+ ranking_sha256 = _eligible_ranking_sha256(ranking)
1284
+ reservoir_hash = _reservoir_sha256(reservoir)
1285
+ anchor = _reservoir_rotation_anchor(
1286
+ task_sha256=task_sha256,
1287
+ archive_snapshot_hash=state.archive_snapshot_hash,
1288
+ eligible_ranking_sha256=ranking_sha256,
1289
+ reservoir_sha256=reservoir_hash,
1290
+ cardinality=reservoir_cardinality,
1291
+ )
1292
+ returned_parent_count = min(parent_count, reservoir_cardinality)
1293
+ ordinals = tuple(
1294
+ (anchor + rotation_index + offset) % reservoir_cardinality
1295
+ for offset in range(returned_parent_count)
1296
+ )
1297
+ receipt = ArchiveReservoirParentSelectionReceipt(
1298
+ task_sha256=task_sha256,
1299
+ optimizer_generation=state.generation,
1300
+ archive_snapshot_hash=state.archive_snapshot_hash,
1301
+ eligible_ranking=ranking,
1302
+ reservoir_limit=reservoir_limit,
1303
+ reservoir=reservoir,
1304
+ requested_parent_count=parent_count,
1305
+ returned_parent_count=returned_parent_count,
1306
+ rotation_index=rotation_index,
1307
+ rotation_anchor=anchor,
1308
+ selected_ordinals=ordinals,
1309
+ selected_parents=tuple(reservoir[index] for index in ordinals),
1310
+ )
1311
+ selection = ArchiveReservoirParentSelection(
1312
+ parents=tuple(reservoir_candidates[index] for index in ordinals),
1313
+ receipt=receipt,
1314
+ )
1315
+ validate_archive_reservoir_parent_selection(state, selection)
1316
+ return selection
1317
+
1318
+ def to_record(self) -> dict[str, object]:
1319
+ self._validate_identity()
1320
+ return {
1321
+ "policy_id": self.policy_id,
1322
+ "policy_version": self.policy_version,
1323
+ "definition_sha256": self.definition_sha256,
1324
+ }
1325
+
1326
+
1327
+ __all__ = [
1328
+ "ArchiveEliteParentSelection",
1329
+ "ArchiveEliteParentSelectionReceipt",
1330
+ "ArchiveEliteParentSelector",
1331
+ "ArchiveReservoirCrowdingKind",
1332
+ "ArchiveReservoirParentSelection",
1333
+ "ArchiveReservoirParentSelectionReceipt",
1334
+ "ArchiveReservoirParentSelector",
1335
+ "ArchiveReservoirRankedCandidate",
1336
+ "POLICY_DEFINITION_SHA256",
1337
+ "POLICY_ID",
1338
+ "POLICY_VERSION",
1339
+ "RESERVOIR_POLICY_DEFINITION_SHA256",
1340
+ "RESERVOIR_POLICY_ID",
1341
+ "RESERVOIR_POLICY_VERSION",
1342
+ "TaskKeyedArchiveEliteParentPolicy",
1343
+ "TaskKeyedArchiveReservoirParentPolicy",
1344
+ "validate_archive_elite_parent_selection",
1345
+ "validate_archive_reservoir_parent_selection",
1346
+ ]