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,581 @@
1
+ """Post-treatment attribution audit for portfolio memory waves.
2
+
3
+ Whole-wave reward is the correct endpoint for an intention-to-treat study of
4
+ prompt-visible memory. It is not, however, evidence that an explicitly cited
5
+ card-supported candidate created the reward: an uncited member may be the only
6
+ frontier contributor, and another prompt-wide lane may independently select
7
+ the card's exact option. This module records those distinctions at the common
8
+ generation barrier without importing a benchmark, provider, prompt renderer,
9
+ or archive implementation.
10
+
11
+ The leave-one-out endpoint reuses each wave's precommitted aggregation binding.
12
+ It is descriptive performance attribution, never a causal action effect. A
13
+ true card-effect estimate still requires a prospectively randomized,
14
+ prompt-redacted matched control call.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import hashlib
20
+ import json
21
+ import math
22
+ import re
23
+ from dataclasses import dataclass, field
24
+
25
+ from agent_evolve.application.portfolio_evolution import (
26
+ PortfolioVariationWaveRequest,
27
+ PortfolioVariationWaveResult,
28
+ )
29
+ from agent_evolve.domain.insight import InsightRef
30
+ from agent_evolve.domain.patch import require_sha256
31
+
32
+
33
+ _TOKEN = re.compile(r"^[a-z][a-z0-9_.:-]{0,255}$")
34
+ _OPTION_ID = re.compile(r"^[a-z][a-z0-9_.-]{0,255}$")
35
+ _CANDIDATE_DOMAIN = b"agent-evolve:portfolio-memory-candidate-contribution:v1\x00"
36
+ _CARD_DOMAIN = b"agent-evolve:portfolio-memory-card-performance:v1\x00"
37
+ _AUDIT_DOMAIN = b"agent-evolve:portfolio-memory-attribution-audit:v1\x00"
38
+
39
+ PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_ID = (
40
+ "post_treatment_memory_performance_attribution"
41
+ )
42
+ PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_VERSION = 1
43
+ PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_DEFINITION_SHA256 = hashlib.sha256(
44
+ b"agent-evolve:post-treatment-memory-performance-attribution:v1;"
45
+ b"precommitted-wave-aggregator;leave-one-out-member-contribution;"
46
+ b"explicit-card-citation;cross-lane-same-option-interference;"
47
+ b"descriptive-only;no-causal-action-or-card-credit;"
48
+ b"no-online-score-consumption"
49
+ ).hexdigest()
50
+
51
+
52
+ def _canonical_json(value: object) -> bytes:
53
+ return json.dumps(
54
+ value,
55
+ allow_nan=False,
56
+ ensure_ascii=True,
57
+ separators=(",", ":"),
58
+ sort_keys=True,
59
+ ).encode("ascii", errors="strict")
60
+
61
+
62
+ def _hash(domain: bytes, value: object) -> str:
63
+ return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
64
+
65
+
66
+ def _reference_record(reference: InsightRef) -> dict[str, object]:
67
+ if type(reference) is not InsightRef:
68
+ raise TypeError("reference must be an exact InsightRef")
69
+ InsightRef.__post_init__(reference)
70
+ return {
71
+ "insight_id": reference.insight_id.value,
72
+ "version": reference.version,
73
+ }
74
+
75
+
76
+ def _finite(value: float, *, name: str) -> None:
77
+ if type(value) is not float or not math.isfinite(value):
78
+ raise TypeError(f"{name} must be a finite canonical float")
79
+
80
+
81
+ @dataclass(frozen=True, slots=True)
82
+ class PortfolioMemoryCandidateContribution:
83
+ """One evaluated member's descriptive contribution to its memory wave."""
84
+
85
+ generation: int
86
+ request_sha256: str
87
+ result_receipt_sha256: str
88
+ parent_candidate_id: str
89
+ candidate_id: str
90
+ rank: int
91
+ option_id: str
92
+ option_identity_sha256: str
93
+ supporting_card_keys: tuple[str, ...]
94
+ supporting_references: tuple[InsightRef, ...]
95
+ member_reward: float
96
+ joint_wave_reward: float
97
+ leave_one_out_wave_reward: float
98
+ leave_one_out_contribution: float
99
+ better_than_any_parent: bool
100
+ dominates_any_parent: bool
101
+ contribution_sha256: str = field(init=False)
102
+
103
+ def __post_init__(self) -> None:
104
+ if type(self.generation) is not int or self.generation <= 0:
105
+ raise ValueError("generation must be positive")
106
+ for name in ("request_sha256", "result_receipt_sha256"):
107
+ require_sha256(getattr(self, name), name)
108
+ for name in ("parent_candidate_id", "candidate_id"):
109
+ value = getattr(self, name)
110
+ if type(value) is not str or _TOKEN.fullmatch(value) is None:
111
+ raise ValueError(f"{name} must use the closed token grammar")
112
+ if type(self.rank) is not int or self.rank <= 0:
113
+ raise ValueError("rank must be positive")
114
+ if type(self.option_id) is not str or _OPTION_ID.fullmatch(self.option_id) is None:
115
+ raise ValueError("option_id must use the closed option grammar")
116
+ require_sha256(self.option_identity_sha256, "option_identity_sha256")
117
+ if (
118
+ type(self.supporting_card_keys) is not tuple
119
+ or self.supporting_card_keys != tuple(sorted(set(self.supporting_card_keys)))
120
+ ):
121
+ raise ValueError("supporting_card_keys must be unique and canonical")
122
+ for value in self.supporting_card_keys:
123
+ if type(value) is not str or _TOKEN.fullmatch(value) is None:
124
+ raise ValueError("supporting card key is invalid")
125
+ if (
126
+ type(self.supporting_references) is not tuple
127
+ or len(set(self.supporting_references))
128
+ != len(self.supporting_references)
129
+ ):
130
+ raise ValueError("supporting_references must be unique")
131
+ for value in self.supporting_references:
132
+ InsightRef.__post_init__(value)
133
+ if len(self.supporting_card_keys) != len(self.supporting_references):
134
+ raise ValueError("supporting card keys and references differ")
135
+ for name in (
136
+ "member_reward",
137
+ "joint_wave_reward",
138
+ "leave_one_out_wave_reward",
139
+ "leave_one_out_contribution",
140
+ ):
141
+ _finite(getattr(self, name), name=name)
142
+ if type(self.better_than_any_parent) is not bool:
143
+ raise TypeError("better_than_any_parent must be an exact bool")
144
+ if type(self.dominates_any_parent) is not bool:
145
+ raise TypeError("dominates_any_parent must be an exact bool")
146
+ object.__setattr__(
147
+ self,
148
+ "contribution_sha256",
149
+ _hash(_CANDIDATE_DOMAIN, self._unsigned_record()),
150
+ )
151
+
152
+ @property
153
+ def explicitly_card_supported(self) -> bool:
154
+ return bool(self.supporting_references)
155
+
156
+ def _unsigned_record(self) -> dict[str, object]:
157
+ return {
158
+ "schema_version": 1,
159
+ "generation": self.generation,
160
+ "request_sha256": self.request_sha256,
161
+ "result_receipt_sha256": self.result_receipt_sha256,
162
+ "parent_candidate_id": self.parent_candidate_id,
163
+ "candidate_id": self.candidate_id,
164
+ "rank": self.rank,
165
+ "option_id": self.option_id,
166
+ "option_identity_sha256": self.option_identity_sha256,
167
+ "supporting_card_keys": list(self.supporting_card_keys),
168
+ "supporting_references": [
169
+ _reference_record(value) for value in self.supporting_references
170
+ ],
171
+ "member_reward_hex": self.member_reward.hex(),
172
+ "joint_wave_reward_hex": self.joint_wave_reward.hex(),
173
+ "leave_one_out_wave_reward_hex": self.leave_one_out_wave_reward.hex(),
174
+ "leave_one_out_contribution_hex": self.leave_one_out_contribution.hex(),
175
+ "better_than_any_parent": self.better_than_any_parent,
176
+ "dominates_any_parent": self.dominates_any_parent,
177
+ "explicitly_card_supported": self.explicitly_card_supported,
178
+ "attribution_scope": "post_treatment_descriptive_not_causal_credit",
179
+ }
180
+
181
+ def to_record(self) -> dict[str, object]:
182
+ self.__post_init__()
183
+ return {
184
+ **self._unsigned_record(),
185
+ "contribution_sha256": self.contribution_sha256,
186
+ }
187
+
188
+
189
+ @dataclass(frozen=True, slots=True)
190
+ class PortfolioMemoryCardPerformanceAudit:
191
+ """One explicit card/action join plus cross-lane interference evidence."""
192
+
193
+ reference: InsightRef
194
+ card_key: str
195
+ contribution_sha256: str
196
+ generation: int
197
+ request_sha256: str
198
+ candidate_id: str
199
+ option_id: str
200
+ candidate_member_reward: float
201
+ candidate_leave_one_out_contribution: float
202
+ joint_wave_reward: float
203
+ unsupported_positive_member_count: int
204
+ cross_lane_same_option_candidate_ids: tuple[str, ...]
205
+ receipt_sha256: str = field(init=False)
206
+
207
+ def __post_init__(self) -> None:
208
+ InsightRef.__post_init__(self.reference)
209
+ if type(self.card_key) is not str or _TOKEN.fullmatch(self.card_key) is None:
210
+ raise ValueError("card_key must use the closed token grammar")
211
+ for name in ("contribution_sha256", "request_sha256"):
212
+ require_sha256(getattr(self, name), name)
213
+ if type(self.generation) is not int or self.generation <= 0:
214
+ raise ValueError("generation must be positive")
215
+ if type(self.candidate_id) is not str or _TOKEN.fullmatch(self.candidate_id) is None:
216
+ raise ValueError("candidate_id must use the closed token grammar")
217
+ if type(self.option_id) is not str or _OPTION_ID.fullmatch(self.option_id) is None:
218
+ raise ValueError("option_id must use the closed option grammar")
219
+ for name in (
220
+ "candidate_member_reward",
221
+ "candidate_leave_one_out_contribution",
222
+ "joint_wave_reward",
223
+ ):
224
+ _finite(getattr(self, name), name=name)
225
+ if (
226
+ type(self.unsupported_positive_member_count) is not int
227
+ or self.unsupported_positive_member_count < 0
228
+ ):
229
+ raise ValueError("unsupported_positive_member_count must be nonnegative")
230
+ if (
231
+ type(self.cross_lane_same_option_candidate_ids) is not tuple
232
+ or self.cross_lane_same_option_candidate_ids
233
+ != tuple(sorted(set(self.cross_lane_same_option_candidate_ids)))
234
+ ):
235
+ raise ValueError("cross-lane candidate IDs must be unique and canonical")
236
+ for value in self.cross_lane_same_option_candidate_ids:
237
+ if type(value) is not str or _TOKEN.fullmatch(value) is None:
238
+ raise ValueError("cross-lane candidate ID is invalid")
239
+ object.__setattr__(
240
+ self,
241
+ "receipt_sha256",
242
+ _hash(_CARD_DOMAIN, self._unsigned_record()),
243
+ )
244
+
245
+ @property
246
+ def cross_lane_action_spillover(self) -> bool:
247
+ return bool(self.cross_lane_same_option_candidate_ids)
248
+
249
+ @property
250
+ def positive_wave_with_nonpositive_supported_action(self) -> bool:
251
+ return self.joint_wave_reward > 0.0 and self.candidate_member_reward <= 0.0
252
+
253
+ def _unsigned_record(self) -> dict[str, object]:
254
+ return {
255
+ "schema_version": 1,
256
+ "reference": _reference_record(self.reference),
257
+ "card_key": self.card_key,
258
+ "contribution_sha256": self.contribution_sha256,
259
+ "generation": self.generation,
260
+ "request_sha256": self.request_sha256,
261
+ "candidate_id": self.candidate_id,
262
+ "option_id": self.option_id,
263
+ "candidate_member_reward_hex": self.candidate_member_reward.hex(),
264
+ "candidate_leave_one_out_contribution_hex": (
265
+ self.candidate_leave_one_out_contribution.hex()
266
+ ),
267
+ "joint_wave_reward_hex": self.joint_wave_reward.hex(),
268
+ "unsupported_positive_member_count": (
269
+ self.unsupported_positive_member_count
270
+ ),
271
+ "cross_lane_same_option_candidate_ids": list(
272
+ self.cross_lane_same_option_candidate_ids
273
+ ),
274
+ "cross_lane_action_spillover": self.cross_lane_action_spillover,
275
+ "positive_wave_with_nonpositive_supported_action": (
276
+ self.positive_wave_with_nonpositive_supported_action
277
+ ),
278
+ "causal_action_effect_identified": False,
279
+ "eligible_for_online_score_update": False,
280
+ }
281
+
282
+ def to_record(self) -> dict[str, object]:
283
+ self.__post_init__()
284
+ return {**self._unsigned_record(), "receipt_sha256": self.receipt_sha256}
285
+
286
+
287
+ @dataclass(frozen=True, slots=True)
288
+ class PortfolioMemoryAttributionAudit:
289
+ """Generation-wide descriptive audit with an explicit causal boundary."""
290
+
291
+ generation: int
292
+ wave_request_sha256s: tuple[str, ...]
293
+ wave_result_receipt_sha256s: tuple[str, ...]
294
+ candidate_contributions: tuple[PortfolioMemoryCandidateContribution, ...]
295
+ card_performance: tuple[PortfolioMemoryCardPerformanceAudit, ...]
296
+ policy_id: str = field(
297
+ init=False,
298
+ default=PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_ID,
299
+ )
300
+ policy_version: int = field(
301
+ init=False,
302
+ default=PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_VERSION,
303
+ )
304
+ policy_definition_sha256: str = field(
305
+ init=False,
306
+ default=PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_DEFINITION_SHA256,
307
+ )
308
+ audit_sha256: str = field(init=False)
309
+
310
+ def __post_init__(self) -> None:
311
+ if type(self.generation) is not int or self.generation <= 0:
312
+ raise ValueError("generation must be positive")
313
+ for name in ("wave_request_sha256s", "wave_result_receipt_sha256s"):
314
+ values = getattr(self, name)
315
+ if type(values) is not tuple or not values:
316
+ raise ValueError(f"{name} must be non-empty")
317
+ for value in values:
318
+ require_sha256(value, name)
319
+ if values != tuple(sorted(set(values))):
320
+ raise ValueError(f"{name} must be unique and canonical")
321
+ if (
322
+ type(self.candidate_contributions) is not tuple
323
+ or not self.candidate_contributions
324
+ or any(
325
+ type(value) is not PortfolioMemoryCandidateContribution
326
+ for value in self.candidate_contributions
327
+ )
328
+ ):
329
+ raise ValueError("candidate_contributions must contain exact values")
330
+ for value in self.candidate_contributions:
331
+ value.__post_init__()
332
+ if value.generation != self.generation:
333
+ raise ValueError("candidate contribution generation differs")
334
+ contribution_ids = tuple(
335
+ value.contribution_sha256 for value in self.candidate_contributions
336
+ )
337
+ if contribution_ids != tuple(sorted(set(contribution_ids))):
338
+ raise ValueError("candidate contributions must use canonical identities")
339
+ if type(self.card_performance) is not tuple or any(
340
+ type(value) is not PortfolioMemoryCardPerformanceAudit
341
+ for value in self.card_performance
342
+ ):
343
+ raise TypeError("card_performance must contain exact values")
344
+ known = set(contribution_ids)
345
+ for value in self.card_performance:
346
+ value.__post_init__()
347
+ if value.generation != self.generation:
348
+ raise ValueError("card performance generation differs")
349
+ if value.contribution_sha256 not in known:
350
+ raise ValueError("card performance cites a foreign contribution")
351
+ card_ids = tuple(value.receipt_sha256 for value in self.card_performance)
352
+ if card_ids != tuple(sorted(set(card_ids))):
353
+ raise ValueError("card performance must use canonical identities")
354
+ if (
355
+ self.policy_id != PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_ID
356
+ or self.policy_version
357
+ != PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_VERSION
358
+ or self.policy_definition_sha256
359
+ != PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_DEFINITION_SHA256
360
+ ):
361
+ raise ValueError("unsupported memory attribution audit policy")
362
+ object.__setattr__(self, "audit_sha256", _hash(_AUDIT_DOMAIN, self._unsigned_record()))
363
+
364
+ def _unsigned_record(self) -> dict[str, object]:
365
+ return {
366
+ "schema_version": 1,
367
+ "generation": self.generation,
368
+ "wave_request_sha256s": list(self.wave_request_sha256s),
369
+ "wave_result_receipt_sha256s": list(
370
+ self.wave_result_receipt_sha256s
371
+ ),
372
+ "candidate_contribution_sha256s": [
373
+ value.contribution_sha256 for value in self.candidate_contributions
374
+ ],
375
+ "card_performance_receipt_sha256s": [
376
+ value.receipt_sha256 for value in self.card_performance
377
+ ],
378
+ "policy": {
379
+ "policy_id": self.policy_id,
380
+ "policy_version": self.policy_version,
381
+ "definition_sha256": self.policy_definition_sha256,
382
+ },
383
+ "cross_lane_action_spillover_count": sum(
384
+ value.cross_lane_action_spillover for value in self.card_performance
385
+ ),
386
+ "positive_wave_nonpositive_supported_action_count": sum(
387
+ value.positive_wave_with_nonpositive_supported_action
388
+ for value in self.card_performance
389
+ ),
390
+ "causal_card_effect_identified": False,
391
+ "causal_action_effect_identified": False,
392
+ "online_score_update_allowed": False,
393
+ "required_successor_design": (
394
+ "prospective_randomized_prompt_redacted_matched_control"
395
+ ),
396
+ }
397
+
398
+ def to_record(self) -> dict[str, object]:
399
+ self.__post_init__()
400
+ return {
401
+ **self._unsigned_record(),
402
+ "candidate_contributions": [
403
+ value.to_record() for value in self.candidate_contributions
404
+ ],
405
+ "card_performance": [
406
+ value.to_record() for value in self.card_performance
407
+ ],
408
+ "audit_sha256": self.audit_sha256,
409
+ }
410
+
411
+
412
+ def audit_portfolio_memory_attribution(
413
+ *,
414
+ waves: tuple[PortfolioVariationWaveRequest, ...],
415
+ results: tuple[PortfolioVariationWaveResult, ...],
416
+ ) -> PortfolioMemoryAttributionAudit | None:
417
+ """Audit memory-supported action performance at a sealed generation."""
418
+
419
+ if type(waves) is not tuple or type(results) is not tuple:
420
+ raise TypeError("waves/results must be exact tuples")
421
+ if not waves or len(waves) != len(results):
422
+ raise ValueError("waves/results must be non-empty and equally sized")
423
+ if any(type(value) is not PortfolioVariationWaveRequest for value in waves):
424
+ raise TypeError("waves must contain exact requests")
425
+ if any(type(value) is not PortfolioVariationWaveResult for value in results):
426
+ raise TypeError("results must contain exact results")
427
+ for value in waves:
428
+ PortfolioVariationWaveRequest.__post_init__(value)
429
+ for value in results:
430
+ PortfolioVariationWaveResult.__post_init__(value)
431
+ result_by_request = {value.receipt.request_sha256: value for value in results}
432
+ if len(result_by_request) != len(results):
433
+ raise ValueError("results repeat a wave request")
434
+ if set(result_by_request) != {
435
+ value.selection_request.request_sha256 for value in waves
436
+ }:
437
+ raise ValueError("wave requests and results do not form an exact join")
438
+ generations = {value.generation for value in waves}
439
+ if len(generations) != 1:
440
+ raise ValueError("one attribution audit cannot span generations")
441
+ generation = next(iter(generations))
442
+
443
+ contributions: list[PortfolioMemoryCandidateContribution] = []
444
+ for wave in waves:
445
+ credit = wave.memory_credit
446
+ if credit is None:
447
+ continue
448
+ result = result_by_request[wave.selection_request.request_sha256]
449
+ aggregation = credit.aggregation.aggregate
450
+ joint_reward = aggregation(result.outcomes)
451
+ if type(joint_reward) is not float or not math.isfinite(joint_reward):
452
+ raise TypeError("memory aggregation replay must return a finite float")
453
+ committed = result.receipt.memory_credit
454
+ pending = result.pending_memory_credit
455
+ recorded_reward = (
456
+ committed.reward
457
+ if committed is not None
458
+ else (None if pending is None else pending.reward)
459
+ )
460
+ if recorded_reward is None or recorded_reward != joint_reward:
461
+ raise ValueError("memory aggregation replay differs from recorded reward")
462
+ cards = {value.card_key: value.reference for value in wave.selection_request.cards}
463
+ for index, (member, attribution) in enumerate(
464
+ zip(
465
+ result.receipt.members,
466
+ result.action_attributions,
467
+ strict=True,
468
+ )
469
+ ):
470
+ remaining = result.outcomes[:index] + result.outcomes[index + 1 :]
471
+ if not remaining:
472
+ raise ValueError(
473
+ "leave-one-out memory attribution requires portfolio_size >= 2"
474
+ )
475
+ without = aggregation(remaining)
476
+ if type(without) is not float or not math.isfinite(without):
477
+ raise TypeError(
478
+ "leave-one-out aggregation replay must return a finite float"
479
+ )
480
+ supporting_keys = attribution.supporting_card_keys
481
+ references = tuple(cards[value] for value in supporting_keys)
482
+ contributions.append(
483
+ PortfolioMemoryCandidateContribution(
484
+ generation=generation,
485
+ request_sha256=wave.selection_request.request_sha256,
486
+ result_receipt_sha256=result.receipt.receipt_sha256,
487
+ parent_candidate_id=wave.parent.candidate_id.value,
488
+ candidate_id=member.materialization.candidate_id.value,
489
+ rank=member.materialization.rank,
490
+ option_id=member.materialization.option_id,
491
+ option_identity_sha256=(
492
+ member.materialization.option_identity_sha256
493
+ ),
494
+ supporting_card_keys=supporting_keys,
495
+ supporting_references=references,
496
+ member_reward=member.reward,
497
+ joint_wave_reward=joint_reward,
498
+ leave_one_out_wave_reward=without,
499
+ leave_one_out_contribution=joint_reward - without,
500
+ better_than_any_parent=member.better_than_any_parent,
501
+ dominates_any_parent=member.dominates_any_parent,
502
+ )
503
+ )
504
+
505
+ if not contributions:
506
+ return None
507
+ canonical_contributions = tuple(
508
+ sorted(contributions, key=lambda value: value.contribution_sha256)
509
+ )
510
+ card_rows: list[PortfolioMemoryCardPerformanceAudit] = []
511
+ for contribution in canonical_contributions:
512
+ if not contribution.explicitly_card_supported:
513
+ continue
514
+ same_lane = tuple(
515
+ value
516
+ for value in canonical_contributions
517
+ if value.request_sha256 == contribution.request_sha256
518
+ )
519
+ other_lanes = tuple(
520
+ value
521
+ for value in canonical_contributions
522
+ if value.request_sha256 != contribution.request_sha256
523
+ )
524
+ spillovers = tuple(
525
+ sorted(
526
+ value.candidate_id
527
+ for value in other_lanes
528
+ if value.option_id == contribution.option_id
529
+ )
530
+ )
531
+ unsupported_positive = sum(
532
+ not value.explicitly_card_supported and value.member_reward > 0.0
533
+ for value in same_lane
534
+ )
535
+ for card_key, reference in zip(
536
+ contribution.supporting_card_keys,
537
+ contribution.supporting_references,
538
+ strict=True,
539
+ ):
540
+ card_rows.append(
541
+ PortfolioMemoryCardPerformanceAudit(
542
+ reference=reference,
543
+ card_key=card_key,
544
+ contribution_sha256=contribution.contribution_sha256,
545
+ generation=generation,
546
+ request_sha256=contribution.request_sha256,
547
+ candidate_id=contribution.candidate_id,
548
+ option_id=contribution.option_id,
549
+ candidate_member_reward=contribution.member_reward,
550
+ candidate_leave_one_out_contribution=(
551
+ contribution.leave_one_out_contribution
552
+ ),
553
+ joint_wave_reward=contribution.joint_wave_reward,
554
+ unsupported_positive_member_count=unsupported_positive,
555
+ cross_lane_same_option_candidate_ids=spillovers,
556
+ )
557
+ )
558
+ return PortfolioMemoryAttributionAudit(
559
+ generation=generation,
560
+ wave_request_sha256s=tuple(
561
+ sorted(value.selection_request.request_sha256 for value in waves)
562
+ ),
563
+ wave_result_receipt_sha256s=tuple(
564
+ sorted(value.receipt.receipt_sha256 for value in results)
565
+ ),
566
+ candidate_contributions=canonical_contributions,
567
+ card_performance=tuple(
568
+ sorted(card_rows, key=lambda value: value.receipt_sha256)
569
+ ),
570
+ )
571
+
572
+
573
+ __all__ = [
574
+ "PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_DEFINITION_SHA256",
575
+ "PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_ID",
576
+ "PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_VERSION",
577
+ "PortfolioMemoryAttributionAudit",
578
+ "PortfolioMemoryCandidateContribution",
579
+ "PortfolioMemoryCardPerformanceAudit",
580
+ "audit_portfolio_memory_attribution",
581
+ ]