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,826 @@
1
+ """Model-anchored, prior-calibrated allocation over a finite K8 slate.
2
+
3
+ This opt-in policy deliberately leaves :class:`TraceCalibratedSlatePolicy`
4
+ unchanged. It preserves as many members as possible from a configurable
5
+ model-ranked prefix, then fills the remaining K4 capacity using only a sealed
6
+ prior-wave calibration snapshot. Feasibility is always authoritative:
7
+ compatibility, family, and assigned-card constraints may displace anchors.
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import hashlib
13
+ import json
14
+ import math
15
+ from dataclasses import dataclass
16
+ from enum import Enum
17
+ from itertools import combinations
18
+ from typing import ClassVar
19
+
20
+ from agent_evolve.domain.patch import require_sha256
21
+ from agent_evolve.policies.selection.calibrated_slate import (
22
+ CalibratedSlateMember,
23
+ MetricOptimizationGoal,
24
+ SlateAllocationRequest,
25
+ assess_allocated_slate_memory_dose,
26
+ )
27
+ from agent_evolve.policies.selection.forecast_calibration import (
28
+ ForecastCalibrationCell,
29
+ ForecastConfidenceBin,
30
+ )
31
+ from agent_evolve.ports.agentic_generator import MetricEffectDirection
32
+ from agent_evolve.ports.portfolio_memory_dose import (
33
+ PortfolioMemoryDoseAssessment,
34
+ )
35
+
36
+
37
+ POLICY_ID = "model_anchored_prior_calibrated_slate"
38
+ POLICY_VERSION = 2
39
+ POLICY_DEFINITION_SHA256 = hashlib.sha256(
40
+ b"agent-evolve:model-anchored-prior-calibrated-slate:v2;"
41
+ b"slate-size=8;portfolio-size=4;model-prefix-anchor-count=configurable;"
42
+ b"full-model-top4-anchor-allowed=true;calibrated-fill=fallback-only;"
43
+ b"feasibility-before-ranking=true;maximize-retained-anchors=true;"
44
+ b"fill-score=prior-only-calibrated-exploitation-sum;"
45
+ b"ties=fill-score-vector,fill-structural-sum,diversity,anchor-ranks,"
46
+ b"selected-ranks,option-ids;card-administration=complete;"
47
+ b"calibration-cutoff-exclusive=true;outcome-blind=true"
48
+ ).hexdigest()
49
+
50
+ _CONFIGURATION_DOMAIN = b"agent-evolve:model-anchored-slate-config:v1\x00"
51
+ _DECISION_DOMAIN = b"agent-evolve:model-anchored-slate-decision:v1\x00"
52
+ _SLATE_SIZE = 8
53
+ _PORTFOLIO_SIZE = 4
54
+
55
+
56
+ def _canonical_json(value: object) -> bytes:
57
+ return json.dumps(
58
+ value,
59
+ allow_nan=False,
60
+ ensure_ascii=True,
61
+ separators=(",", ":"),
62
+ sort_keys=True,
63
+ ).encode("ascii", errors="strict")
64
+
65
+
66
+ def _hash(domain: bytes, value: object) -> str:
67
+ return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
68
+
69
+
70
+ def _require_finite_float(value: float, *, name: str) -> None:
71
+ if type(value) is not float or not math.isfinite(value):
72
+ raise TypeError(f"{name} must be a finite canonical float")
73
+
74
+
75
+ class ModelAnchoredSlateRole(str, Enum):
76
+ """Engine-owned provenance of a selected K4 member."""
77
+
78
+ MODEL_ANCHOR = "model_anchor"
79
+ PRIOR_CALIBRATED_FILL = "prior_calibrated_fill"
80
+
81
+
82
+ @dataclass(frozen=True, slots=True)
83
+ class ModelAnchoredMetricScoreRow:
84
+ """One objective's prior-only contribution to exploitation."""
85
+
86
+ metric_id: str
87
+ goal: MetricOptimizationGoal
88
+ asserted_direction: MetricEffectDirection
89
+ confidence: ForecastConfidenceBin
90
+ weight: float
91
+ calibration_cell: ForecastCalibrationCell
92
+ calibration_source: str
93
+ favorable_assertion: bool
94
+ adverse_assertion: bool
95
+ signed_exploitation_score: float
96
+
97
+ def __post_init__(self) -> None:
98
+ if type(self.metric_id) is not str or not self.metric_id:
99
+ raise ValueError("metric_id must be a non-empty string")
100
+ if type(self.goal) is not MetricOptimizationGoal:
101
+ raise TypeError("goal must be exact MetricOptimizationGoal")
102
+ if type(self.asserted_direction) is not MetricEffectDirection:
103
+ raise TypeError("asserted_direction must be exact MetricEffectDirection")
104
+ if type(self.confidence) is not ForecastConfidenceBin:
105
+ raise TypeError("confidence must be exact ForecastConfidenceBin")
106
+ _require_finite_float(self.weight, name="weight")
107
+ if self.weight <= 0.0:
108
+ raise ValueError("weight must be strictly positive")
109
+ if type(self.calibration_cell) is not ForecastCalibrationCell:
110
+ raise TypeError("calibration_cell must be exact ForecastCalibrationCell")
111
+ self.calibration_cell.__post_init__()
112
+ if self.calibration_source not in {
113
+ "supported_family",
114
+ "metric_direction_confidence",
115
+ "declared_prior",
116
+ }:
117
+ raise ValueError("unsupported calibration_source")
118
+ if type(self.favorable_assertion) is not bool:
119
+ raise TypeError("favorable_assertion must be exact bool")
120
+ if type(self.adverse_assertion) is not bool:
121
+ raise TypeError("adverse_assertion must be exact bool")
122
+ if self.favorable_assertion and self.adverse_assertion:
123
+ raise ValueError("one assertion cannot be favorable and adverse")
124
+ _require_finite_float(
125
+ self.signed_exploitation_score,
126
+ name="signed_exploitation_score",
127
+ )
128
+
129
+ def to_record(self) -> dict[str, object]:
130
+ self.__post_init__()
131
+ return {
132
+ "metric_id": self.metric_id,
133
+ "goal": self.goal.value,
134
+ "asserted_direction": self.asserted_direction.value,
135
+ "confidence": self.confidence.value,
136
+ "weight_hex": self.weight.hex(),
137
+ "calibration_cell": self.calibration_cell.to_record(),
138
+ "calibration_source": self.calibration_source,
139
+ "favorable_assertion": self.favorable_assertion,
140
+ "adverse_assertion": self.adverse_assertion,
141
+ "signed_exploitation_score_hex": (
142
+ self.signed_exploitation_score.hex()
143
+ ),
144
+ }
145
+
146
+
147
+ @dataclass(frozen=True, slots=True)
148
+ class ModelAnchoredMemberScoreRow:
149
+ """Prior-only exploitation and frozen structure for one slate member."""
150
+
151
+ option_id: str
152
+ option_identity_sha256: str
153
+ model_rank: int
154
+ metric_scores: tuple[ModelAnchoredMetricScoreRow, ...]
155
+ calibrated_exploitation_score: float
156
+ structural_coverage_score: float
157
+ supported_assigned_card_keys: tuple[str, ...]
158
+
159
+ def __post_init__(self) -> None:
160
+ if type(self.option_id) is not str or not self.option_id:
161
+ raise ValueError("option_id must be a non-empty string")
162
+ require_sha256(self.option_identity_sha256, "option_identity_sha256")
163
+ if type(self.model_rank) is not int or self.model_rank <= 0:
164
+ raise ValueError("model_rank must be a positive exact integer")
165
+ if type(self.metric_scores) is not tuple or not self.metric_scores or any(
166
+ type(value) is not ModelAnchoredMetricScoreRow
167
+ for value in self.metric_scores
168
+ ):
169
+ raise ValueError("metric_scores must contain exact metric score rows")
170
+ for value in self.metric_scores:
171
+ value.__post_init__()
172
+ metric_ids = tuple(value.metric_id for value in self.metric_scores)
173
+ if metric_ids != tuple(sorted(set(metric_ids))):
174
+ raise ValueError("metric_scores must use canonical unique metric order")
175
+ _require_finite_float(
176
+ self.calibrated_exploitation_score,
177
+ name="calibrated_exploitation_score",
178
+ )
179
+ _require_finite_float(
180
+ self.structural_coverage_score,
181
+ name="structural_coverage_score",
182
+ )
183
+ if not 0.0 <= self.structural_coverage_score <= 1.0:
184
+ raise ValueError("structural_coverage_score must lie in [0, 1]")
185
+ if type(self.supported_assigned_card_keys) is not tuple or any(
186
+ type(value) is not str or not value
187
+ for value in self.supported_assigned_card_keys
188
+ ):
189
+ raise TypeError("supported_assigned_card_keys must be an exact tuple")
190
+ if self.supported_assigned_card_keys != tuple(
191
+ sorted(set(self.supported_assigned_card_keys))
192
+ ):
193
+ raise ValueError("supported_assigned_card_keys must be canonical")
194
+
195
+ def to_record(self) -> dict[str, object]:
196
+ self.__post_init__()
197
+ return {
198
+ "option_id": self.option_id,
199
+ "option_identity_sha256": self.option_identity_sha256,
200
+ "model_rank": self.model_rank,
201
+ "metric_scores": [value.to_record() for value in self.metric_scores],
202
+ "calibrated_exploitation_score_hex": (
203
+ self.calibrated_exploitation_score.hex()
204
+ ),
205
+ "structural_coverage_score_hex": (
206
+ self.structural_coverage_score.hex()
207
+ ),
208
+ "supported_assigned_card_keys": list(
209
+ self.supported_assigned_card_keys
210
+ ),
211
+ }
212
+
213
+
214
+ @dataclass(frozen=True, slots=True)
215
+ class ModelAnchoredAllocatedMember:
216
+ """One selected member with auditable model/calibration provenance."""
217
+
218
+ role: ModelAnchoredSlateRole
219
+ option_id: str
220
+ option_identity_sha256: str
221
+ model_rank: int
222
+ calibrated_exploitation_score: float
223
+
224
+ def __post_init__(self) -> None:
225
+ if type(self.role) is not ModelAnchoredSlateRole:
226
+ raise TypeError("role must be exact ModelAnchoredSlateRole")
227
+ if type(self.option_id) is not str or not self.option_id:
228
+ raise ValueError("option_id must be a non-empty string")
229
+ require_sha256(self.option_identity_sha256, "option_identity_sha256")
230
+ if type(self.model_rank) is not int or self.model_rank <= 0:
231
+ raise ValueError("model_rank must be a positive exact integer")
232
+ _require_finite_float(
233
+ self.calibrated_exploitation_score,
234
+ name="calibrated_exploitation_score",
235
+ )
236
+
237
+ def to_record(self) -> dict[str, object]:
238
+ self.__post_init__()
239
+ return {
240
+ "role": self.role.value,
241
+ "option_id": self.option_id,
242
+ "option_identity_sha256": self.option_identity_sha256,
243
+ "model_rank": self.model_rank,
244
+ "calibrated_exploitation_score_hex": (
245
+ self.calibrated_exploitation_score.hex()
246
+ ),
247
+ }
248
+
249
+
250
+ @dataclass(frozen=True, slots=True)
251
+ class _AnchoredAssignment:
252
+ selected: tuple[ModelAnchoredAllocatedMember, ...]
253
+ retained_anchor_option_ids: tuple[str, ...]
254
+ calibrated_fill_option_ids: tuple[str, ...]
255
+ calibrated_fill_exploitation_score: float
256
+ calibrated_fill_structural_score: float
257
+ distinct_family_count: int
258
+ distinct_locus_count: int
259
+ distinct_phenotype_count: int
260
+ administered_card_keys: tuple[str, ...]
261
+ feasible_subset_count: int
262
+ memory_dose_assessment: PortfolioMemoryDoseAssessment | None
263
+
264
+
265
+ def _configuration_record(model_anchor_count: int) -> dict[str, object]:
266
+ return {
267
+ "schema_version": 1,
268
+ "model_anchor_count": model_anchor_count,
269
+ "slate_size": _SLATE_SIZE,
270
+ "portfolio_size": _PORTFOLIO_SIZE,
271
+ }
272
+
273
+
274
+ def _favorable(
275
+ direction: MetricEffectDirection,
276
+ goal: MetricOptimizationGoal,
277
+ ) -> tuple[bool, bool]:
278
+ if direction in {MetricEffectDirection.UNKNOWN, MetricEffectDirection.UNCHANGED}:
279
+ return False, False
280
+ favorable = (
281
+ goal is MetricOptimizationGoal.MINIMIZE
282
+ and direction is MetricEffectDirection.DECREASE
283
+ ) or (
284
+ goal is MetricOptimizationGoal.MAXIMIZE
285
+ and direction is MetricEffectDirection.INCREASE
286
+ )
287
+ return favorable, not favorable
288
+
289
+
290
+ def _score_member(
291
+ request: SlateAllocationRequest,
292
+ member: CalibratedSlateMember,
293
+ ) -> ModelAnchoredMemberScoreRow:
294
+ snapshot = request.calibration_snapshot
295
+ if snapshot is None:
296
+ raise ValueError("model-anchored policy requires a calibration snapshot")
297
+ objective_by_metric = {value.metric_id: value for value in request.objectives}
298
+ metric_scores: list[ModelAnchoredMetricScoreRow] = []
299
+ weighted_score = 0.0
300
+ total_weight = sum(value.weight for value in request.objectives)
301
+ for prediction in member.predictions:
302
+ objective = objective_by_metric[prediction.metric_id]
303
+ cell, source = snapshot.lookup(
304
+ metric_id=prediction.metric_id,
305
+ asserted_direction=prediction.asserted_direction,
306
+ confidence=prediction.confidence,
307
+ family=member.family,
308
+ )
309
+ favorable, adverse = _favorable(
310
+ prediction.asserted_direction,
311
+ objective.goal,
312
+ )
313
+ probability = cell.posterior_correctness
314
+ signed_score = probability if favorable else -probability if adverse else 0.0
315
+ weighted_score += objective.weight * signed_score
316
+ metric_scores.append(
317
+ ModelAnchoredMetricScoreRow(
318
+ metric_id=prediction.metric_id,
319
+ goal=objective.goal,
320
+ asserted_direction=prediction.asserted_direction,
321
+ confidence=prediction.confidence,
322
+ weight=objective.weight,
323
+ calibration_cell=cell,
324
+ calibration_source=source,
325
+ favorable_assertion=favorable,
326
+ adverse_assertion=adverse,
327
+ signed_exploitation_score=signed_score,
328
+ )
329
+ )
330
+ supported_cards = tuple(
331
+ card
332
+ for card in request.assigned_card_keys
333
+ if card in member.supporting_card_keys
334
+ )
335
+ structural_score = (
336
+ member.structural_evidence.archive_novelty_score
337
+ + member.structural_evidence.structural_coverage_score
338
+ ) / 2.0
339
+ return ModelAnchoredMemberScoreRow(
340
+ option_id=member.option_id,
341
+ option_identity_sha256=member.option_identity_sha256,
342
+ model_rank=member.model_rank,
343
+ metric_scores=tuple(metric_scores),
344
+ calibrated_exploitation_score=weighted_score / total_weight,
345
+ structural_coverage_score=structural_score,
346
+ supported_assigned_card_keys=supported_cards,
347
+ )
348
+
349
+
350
+ def _compatible(
351
+ members: tuple[CalibratedSlateMember, ...],
352
+ allowed_pairs: set[frozenset[str]] | None,
353
+ ) -> bool:
354
+ if allowed_pairs is None:
355
+ return True
356
+ return all(
357
+ frozenset((left.option_id, right.option_id)) in allowed_pairs
358
+ for left_index, left in enumerate(members)
359
+ for right in members[left_index + 1 :]
360
+ )
361
+
362
+
363
+ def _best_anchored_assignment(
364
+ request: SlateAllocationRequest,
365
+ score_rows: tuple[ModelAnchoredMemberScoreRow, ...],
366
+ *,
367
+ model_anchor_count: int,
368
+ ) -> _AnchoredAssignment:
369
+ score_by_id = {value.option_id: value for value in score_rows}
370
+ anchor_ids = {
371
+ value.option_id for value in request.slate.members[:model_anchor_count]
372
+ }
373
+ allowed_pairs = (
374
+ None
375
+ if request.pairwise_disjoint_option_id_pairs is None
376
+ else {
377
+ frozenset(value)
378
+ for value in request.pairwise_disjoint_option_id_pairs
379
+ }
380
+ )
381
+ feasible: list[
382
+ tuple[
383
+ tuple[object, ...],
384
+ tuple[CalibratedSlateMember, ...],
385
+ tuple[ModelAnchoredMemberScoreRow, ...],
386
+ tuple[ModelAnchoredMemberScoreRow, ...],
387
+ tuple[str, ...],
388
+ tuple[str, ...],
389
+ int,
390
+ int,
391
+ int,
392
+ PortfolioMemoryDoseAssessment | None,
393
+ ]
394
+ ] = []
395
+ for subset in combinations(request.slate.members, request.portfolio_size):
396
+ if not _compatible(subset, allowed_pairs):
397
+ continue
398
+ family_count = len({value.family for value in subset})
399
+ if (
400
+ request.min_distinct_families is not None
401
+ and family_count < request.min_distinct_families
402
+ ):
403
+ continue
404
+ rows = tuple(score_by_id[value.option_id] for value in subset)
405
+ administered = tuple(
406
+ sorted(
407
+ {
408
+ card
409
+ for row in rows
410
+ for card in row.supported_assigned_card_keys
411
+ }
412
+ )
413
+ )
414
+ if administered != request.assigned_card_keys:
415
+ continue
416
+ memory_dose_assessment = (
417
+ None
418
+ if request.memory_dose_contract is None
419
+ else assess_allocated_slate_memory_dose(
420
+ request,
421
+ subset,
422
+ )
423
+ )
424
+ if (
425
+ memory_dose_assessment is not None
426
+ and not memory_dose_assessment.passed
427
+ ):
428
+ continue
429
+ retained = tuple(value for value in rows if value.option_id in anchor_ids)
430
+ fills = tuple(value for value in rows if value.option_id not in anchor_ids)
431
+ fill_scores = tuple(
432
+ sorted(
433
+ (value.calibrated_exploitation_score for value in fills),
434
+ reverse=True,
435
+ )
436
+ )
437
+ fill_score = sum(fill_scores, 0.0)
438
+ fill_structural = sum(
439
+ (value.structural_coverage_score for value in fills),
440
+ 0.0,
441
+ )
442
+ locus_count = len({value.locus_key for value in subset})
443
+ phenotype_count = len(
444
+ {value.phenotype_identity_sha256 for value in subset}
445
+ )
446
+ retained_ranks = tuple(value.model_rank for value in retained)
447
+ selected_ranks = tuple(value.model_rank for value in rows)
448
+ # ``min`` over this key implements the documented strict priority.
449
+ key: tuple[object, ...] = (
450
+ -len(retained),
451
+ -fill_score,
452
+ tuple(-value for value in fill_scores),
453
+ -fill_structural,
454
+ -family_count,
455
+ -locus_count,
456
+ -phenotype_count,
457
+ retained_ranks,
458
+ selected_ranks,
459
+ tuple(value.option_id for value in rows),
460
+ )
461
+ feasible.append(
462
+ (
463
+ key,
464
+ subset,
465
+ retained,
466
+ fills,
467
+ administered,
468
+ tuple(value.option_id for value in retained),
469
+ family_count,
470
+ locus_count,
471
+ phenotype_count,
472
+ memory_dose_assessment,
473
+ )
474
+ )
475
+ if not feasible:
476
+ raise ValueError(
477
+ "slate has no feasible K4 subset administering every assigned card"
478
+ )
479
+ (
480
+ _,
481
+ subset,
482
+ retained,
483
+ fills,
484
+ administered,
485
+ retained_ids,
486
+ family_count,
487
+ locus_count,
488
+ phenotype_count,
489
+ memory_dose_assessment,
490
+ ) = min(feasible, key=lambda value: value[0])
491
+ fill_ids = tuple(value.option_id for value in fills)
492
+ selected = tuple(
493
+ ModelAnchoredAllocatedMember(
494
+ role=(
495
+ ModelAnchoredSlateRole.MODEL_ANCHOR
496
+ if member.option_id in anchor_ids
497
+ else ModelAnchoredSlateRole.PRIOR_CALIBRATED_FILL
498
+ ),
499
+ option_id=member.option_id,
500
+ option_identity_sha256=member.option_identity_sha256,
501
+ model_rank=member.model_rank,
502
+ calibrated_exploitation_score=(
503
+ score_by_id[member.option_id].calibrated_exploitation_score
504
+ ),
505
+ )
506
+ for member in subset
507
+ )
508
+ return _AnchoredAssignment(
509
+ selected=selected,
510
+ retained_anchor_option_ids=retained_ids,
511
+ calibrated_fill_option_ids=fill_ids,
512
+ calibrated_fill_exploitation_score=sum(
513
+ (value.calibrated_exploitation_score for value in fills),
514
+ 0.0,
515
+ ),
516
+ calibrated_fill_structural_score=sum(
517
+ (value.structural_coverage_score for value in fills),
518
+ 0.0,
519
+ ),
520
+ distinct_family_count=family_count,
521
+ distinct_locus_count=locus_count,
522
+ distinct_phenotype_count=phenotype_count,
523
+ administered_card_keys=administered,
524
+ feasible_subset_count=len(feasible),
525
+ memory_dose_assessment=memory_dose_assessment,
526
+ )
527
+
528
+
529
+ @dataclass(frozen=True, slots=True, eq=False)
530
+ class ModelAnchoredSlateDecision:
531
+ """Replayable receipt for one outcome-blind K8-to-K4 decision."""
532
+
533
+ request: SlateAllocationRequest
534
+ model_anchor_count: int
535
+ score_rows: tuple[ModelAnchoredMemberScoreRow, ...]
536
+ selected: tuple[ModelAnchoredAllocatedMember, ...]
537
+ retained_anchor_option_ids: tuple[str, ...]
538
+ calibrated_fill_option_ids: tuple[str, ...]
539
+ calibrated_fill_exploitation_score: float
540
+ calibrated_fill_structural_score: float
541
+ distinct_family_count: int
542
+ distinct_locus_count: int
543
+ distinct_phenotype_count: int
544
+ administered_card_keys: tuple[str, ...]
545
+ feasible_subset_count: int
546
+ memory_dose_assessment: PortfolioMemoryDoseAssessment | None = None
547
+
548
+ policy_id: ClassVar[str] = POLICY_ID
549
+ policy_version: ClassVar[int] = POLICY_VERSION
550
+ policy_definition_sha256: ClassVar[str] = POLICY_DEFINITION_SHA256
551
+
552
+ def __post_init__(self) -> None:
553
+ if type(self.request) is not SlateAllocationRequest:
554
+ raise TypeError("request must be exact SlateAllocationRequest")
555
+ self.request.revalidate()
556
+ _validate_policy_request(self.request, self.model_anchor_count)
557
+ if type(self.score_rows) is not tuple or any(
558
+ type(value) is not ModelAnchoredMemberScoreRow
559
+ for value in self.score_rows
560
+ ):
561
+ raise TypeError("score_rows must contain exact member score rows")
562
+ for value in self.score_rows:
563
+ value.__post_init__()
564
+ if type(self.selected) is not tuple or any(
565
+ type(value) is not ModelAnchoredAllocatedMember
566
+ for value in self.selected
567
+ ):
568
+ raise TypeError("selected must contain exact allocated members")
569
+ for value in self.selected:
570
+ value.__post_init__()
571
+ if self.memory_dose_assessment is not None:
572
+ if type(self.memory_dose_assessment) is not (
573
+ PortfolioMemoryDoseAssessment
574
+ ):
575
+ raise TypeError("memory_dose_assessment must be exact or None")
576
+ self.memory_dose_assessment.__post_init__()
577
+ expected_rows = tuple(
578
+ _score_member(self.request, value)
579
+ for value in self.request.slate.members
580
+ )
581
+ if self.score_rows != expected_rows:
582
+ raise ValueError("score rows differ from sealed prior calibration")
583
+ expected = _best_anchored_assignment(
584
+ self.request,
585
+ expected_rows,
586
+ model_anchor_count=self.model_anchor_count,
587
+ )
588
+ observed = (
589
+ self.selected,
590
+ self.retained_anchor_option_ids,
591
+ self.calibrated_fill_option_ids,
592
+ self.calibrated_fill_exploitation_score,
593
+ self.calibrated_fill_structural_score,
594
+ self.distinct_family_count,
595
+ self.distinct_locus_count,
596
+ self.distinct_phenotype_count,
597
+ self.administered_card_keys,
598
+ self.feasible_subset_count,
599
+ self.memory_dose_assessment,
600
+ )
601
+ expected_values = (
602
+ expected.selected,
603
+ expected.retained_anchor_option_ids,
604
+ expected.calibrated_fill_option_ids,
605
+ expected.calibrated_fill_exploitation_score,
606
+ expected.calibrated_fill_structural_score,
607
+ expected.distinct_family_count,
608
+ expected.distinct_locus_count,
609
+ expected.distinct_phenotype_count,
610
+ expected.administered_card_keys,
611
+ expected.feasible_subset_count,
612
+ expected.memory_dose_assessment,
613
+ )
614
+ if observed != expected_values:
615
+ raise ValueError("decision differs from exact model-anchored allocation")
616
+
617
+ def revalidate(self) -> None:
618
+ if type(self) is not ModelAnchoredSlateDecision:
619
+ raise TypeError("decision must be exact ModelAnchoredSlateDecision")
620
+ ModelAnchoredSlateDecision.__post_init__(self)
621
+
622
+ @property
623
+ def policy_configuration_sha256(self) -> str:
624
+ return _hash(
625
+ _CONFIGURATION_DOMAIN,
626
+ _configuration_record(self.model_anchor_count),
627
+ )
628
+
629
+ @property
630
+ def prior_only(self) -> bool:
631
+ self.revalidate()
632
+ snapshot = self.request.calibration_snapshot
633
+ assert snapshot is not None
634
+ return all(
635
+ value.prediction.wave_index < self.request.slate.wave_index
636
+ for value in snapshot.observations
637
+ )
638
+
639
+ def _unsigned_record(self) -> dict[str, object]:
640
+ self.revalidate()
641
+ return {
642
+ "schema_version": 1,
643
+ "event_type": "model_anchored_prior_calibrated_slate_allocated",
644
+ "policy_id": self.policy_id,
645
+ "policy_version": self.policy_version,
646
+ "policy_definition_sha256": self.policy_definition_sha256,
647
+ "policy_configuration": _configuration_record(
648
+ self.model_anchor_count
649
+ ),
650
+ "policy_configuration_sha256": (
651
+ self.policy_configuration_sha256
652
+ ),
653
+ "request": self.request.to_record(),
654
+ "request_sha256": self.request.request_sha256,
655
+ "calibration_snapshot_sha256": (
656
+ self.request.calibration_snapshot.snapshot_sha256
657
+ if self.request.calibration_snapshot is not None
658
+ else None
659
+ ),
660
+ "prior_only": self.prior_only,
661
+ "selection_priority": [
662
+ "retained_model_anchor_count",
663
+ "calibrated_fill_exploitation_sum",
664
+ "calibrated_fill_exploitation_vector",
665
+ "calibrated_fill_structural_sum",
666
+ "distinct_family_count",
667
+ "distinct_locus_count",
668
+ "distinct_phenotype_count",
669
+ "retained_anchor_model_ranks",
670
+ "selected_model_ranks",
671
+ "option_ids",
672
+ ],
673
+ "score_rows": [value.to_record() for value in self.score_rows],
674
+ "selected": [value.to_record() for value in self.selected],
675
+ "retained_anchor_option_ids": list(
676
+ self.retained_anchor_option_ids
677
+ ),
678
+ "calibrated_fill_option_ids": list(
679
+ self.calibrated_fill_option_ids
680
+ ),
681
+ "calibrated_fill_exploitation_score_hex": (
682
+ self.calibrated_fill_exploitation_score.hex()
683
+ ),
684
+ "calibrated_fill_structural_score_hex": (
685
+ self.calibrated_fill_structural_score.hex()
686
+ ),
687
+ "distinct_family_count": self.distinct_family_count,
688
+ "distinct_locus_count": self.distinct_locus_count,
689
+ "distinct_phenotype_count": self.distinct_phenotype_count,
690
+ "administered_card_keys": list(self.administered_card_keys),
691
+ "feasible_subset_count": self.feasible_subset_count,
692
+ **(
693
+ {}
694
+ if self.memory_dose_assessment is None
695
+ else {
696
+ "memory_dose_assessment": (
697
+ self.memory_dose_assessment.to_record()
698
+ )
699
+ }
700
+ ),
701
+ "claim_scope": (
702
+ "replayable_prior_only_allocation_not_efficacy_or_outcome_claim"
703
+ ),
704
+ }
705
+
706
+ @property
707
+ def decision_sha256(self) -> str:
708
+ return _hash(_DECISION_DOMAIN, self._unsigned_record())
709
+
710
+ def to_record(self) -> dict[str, object]:
711
+ return {
712
+ **self._unsigned_record(),
713
+ "decision_sha256": self.decision_sha256,
714
+ }
715
+
716
+ def __eq__(self, other: object) -> bool:
717
+ return (
718
+ type(other) is ModelAnchoredSlateDecision
719
+ and self.decision_sha256 == other.decision_sha256
720
+ )
721
+
722
+ __hash__ = None
723
+
724
+
725
+ def _validate_policy_request(
726
+ request: SlateAllocationRequest,
727
+ model_anchor_count: int,
728
+ ) -> None:
729
+ if type(model_anchor_count) is not int or not (
730
+ 1 <= model_anchor_count <= _PORTFOLIO_SIZE
731
+ ):
732
+ raise ValueError("model_anchor_count must lie in [1, 4]")
733
+ if len(request.slate.members) != _SLATE_SIZE:
734
+ raise ValueError("model-anchored policy requires exactly eight slate members")
735
+ if request.portfolio_size != _PORTFOLIO_SIZE:
736
+ raise ValueError("model-anchored policy requires exactly four evaluations")
737
+ snapshot = request.calibration_snapshot
738
+ if snapshot is None:
739
+ raise ValueError("model-anchored policy requires a calibration snapshot")
740
+ if snapshot.cutoff_wave_index_exclusive > request.slate.wave_index:
741
+ raise ValueError("calibration snapshot cutoff reaches beyond current wave")
742
+ if any(
743
+ value.prediction.wave_index >= request.slate.wave_index
744
+ for value in snapshot.observations
745
+ ):
746
+ raise ValueError("calibration snapshot contains current-wave outcome evidence")
747
+
748
+
749
+ @dataclass(frozen=True, slots=True)
750
+ class ModelAnchoredCalibratedSlatePolicy:
751
+ """Preserve model anchors, then use prior calibration for K4 fill slots."""
752
+
753
+ model_anchor_count: int = 3
754
+
755
+ policy_id: ClassVar[str] = POLICY_ID
756
+ policy_version: ClassVar[int] = POLICY_VERSION
757
+ definition_sha256: ClassVar[str] = POLICY_DEFINITION_SHA256
758
+
759
+ def __post_init__(self) -> None:
760
+ if type(self.model_anchor_count) is not int or not (
761
+ 1 <= self.model_anchor_count <= _PORTFOLIO_SIZE
762
+ ):
763
+ raise ValueError("model_anchor_count must lie in [1, 4]")
764
+
765
+ @property
766
+ def configuration_sha256(self) -> str:
767
+ self.__post_init__()
768
+ return _hash(
769
+ _CONFIGURATION_DOMAIN,
770
+ _configuration_record(self.model_anchor_count),
771
+ )
772
+
773
+ def select(self, request: SlateAllocationRequest) -> ModelAnchoredSlateDecision:
774
+ if type(request) is not SlateAllocationRequest:
775
+ raise TypeError("request must be exact SlateAllocationRequest")
776
+ request.revalidate()
777
+ _validate_policy_request(request, self.model_anchor_count)
778
+ rows = tuple(_score_member(request, value) for value in request.slate.members)
779
+ assignment = _best_anchored_assignment(
780
+ request,
781
+ rows,
782
+ model_anchor_count=self.model_anchor_count,
783
+ )
784
+ return ModelAnchoredSlateDecision(
785
+ request=request,
786
+ model_anchor_count=self.model_anchor_count,
787
+ score_rows=rows,
788
+ selected=assignment.selected,
789
+ retained_anchor_option_ids=assignment.retained_anchor_option_ids,
790
+ calibrated_fill_option_ids=assignment.calibrated_fill_option_ids,
791
+ calibrated_fill_exploitation_score=(
792
+ assignment.calibrated_fill_exploitation_score
793
+ ),
794
+ calibrated_fill_structural_score=(
795
+ assignment.calibrated_fill_structural_score
796
+ ),
797
+ distinct_family_count=assignment.distinct_family_count,
798
+ distinct_locus_count=assignment.distinct_locus_count,
799
+ distinct_phenotype_count=assignment.distinct_phenotype_count,
800
+ administered_card_keys=assignment.administered_card_keys,
801
+ feasible_subset_count=assignment.feasible_subset_count,
802
+ memory_dose_assessment=assignment.memory_dose_assessment,
803
+ )
804
+
805
+ def to_record(self) -> dict[str, object]:
806
+ self.__post_init__()
807
+ return {
808
+ "policy_id": self.policy_id,
809
+ "policy_version": self.policy_version,
810
+ "definition_sha256": self.definition_sha256,
811
+ "configuration": _configuration_record(self.model_anchor_count),
812
+ "configuration_sha256": self.configuration_sha256,
813
+ }
814
+
815
+
816
+ __all__ = [
817
+ "ModelAnchoredAllocatedMember",
818
+ "ModelAnchoredCalibratedSlatePolicy",
819
+ "ModelAnchoredMemberScoreRow",
820
+ "ModelAnchoredMetricScoreRow",
821
+ "ModelAnchoredSlateDecision",
822
+ "ModelAnchoredSlateRole",
823
+ "POLICY_DEFINITION_SHA256",
824
+ "POLICY_ID",
825
+ "POLICY_VERSION",
826
+ ]