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,938 @@
1
+ """Prospective active-versus-neutral experiments for portfolio memory.
2
+
3
+ The ordinary memory-credit path measures the utility of a complete candidate
4
+ wave. It cannot tell whether the visible memory card, its explicitly supported
5
+ action, or an unrelated slate member created that utility. This module defines
6
+ the narrow workload-neutral successor experiment:
7
+
8
+ * one exact source-bound card is chosen before provider dispatch;
9
+ * two stable lane units are randomized between MEMORY and canonical NEUTRAL;
10
+ * both arms retain the same source identity and required finite candidate-pool
11
+ actions, while the neutral prompt redacts prompt, evidence, score, and action
12
+ compartments; and
13
+ * one realized pair is recorded as experimental evidence, never as an
14
+ identified effect or an online score update.
15
+
16
+ The optimizer may administer a hard supported-action dose in the MEMORY arm.
17
+ If it does, the estimand is the complete memory-guided dose package versus the
18
+ same-pool neutral arm, not prose alone. Workload adapters still own finite
19
+ contract construction and evaluation; no benchmark or provider is imported.
20
+ """
21
+
22
+ from __future__ import annotations
23
+
24
+ import hashlib
25
+ import json
26
+ import math
27
+ from dataclasses import dataclass, field
28
+
29
+ from agent_evolve.application.campaign_diagnostic_blocks import (
30
+ CampaignDiagnosticSupportCardInput,
31
+ CampaignDiagnosticSupportLaneInput,
32
+ )
33
+ from agent_evolve.application.portfolio_memory_dose import (
34
+ derive_portfolio_memory_dose_card_support,
35
+ )
36
+ from agent_evolve.application.portfolio_projection import (
37
+ bind_portfolio_experimental_view,
38
+ )
39
+ from agent_evolve.domain.finite_variation import (
40
+ FiniteVariationContract,
41
+ validate_finite_variation_contract,
42
+ )
43
+ from agent_evolve.domain.insight import InsightRef
44
+ from agent_evolve.domain.patch import require_sha256
45
+ from agent_evolve.policies.memory.balanced_subset_blocks import (
46
+ StableMemoryAssignmentUnit,
47
+ )
48
+ from agent_evolve.ports.portfolio_selection import (
49
+ CANONICAL_NEUTRAL_PORTFOLIO_PROMPT_PAYLOAD,
50
+ CANONICAL_REDACTED_PORTFOLIO_EVIDENCE_SHA256,
51
+ PortfolioCard,
52
+ PortfolioCardSourceRegistry,
53
+ PortfolioCardViewTransform,
54
+ PortfolioExperimentalArm,
55
+ PortfolioExperimentalViewReceipt,
56
+ derive_portfolio_card_view,
57
+ )
58
+ from agent_evolve.ports.portfolio_memory_dose import (
59
+ PortfolioMemoryDoseCardSupport,
60
+ )
61
+
62
+
63
+ PORTFOLIO_MEMORY_MATCHED_CONTROL_POLICY_ID = (
64
+ "portfolio_memory_randomized_active_neutral_pair"
65
+ )
66
+ PORTFOLIO_MEMORY_MATCHED_CONTROL_POLICY_VERSION = 1
67
+ PORTFOLIO_MEMORY_MATCHED_CONTROL_DEFINITION_SHA256 = hashlib.sha256(
68
+ b"agent-evolve:portfolio-memory-randomized-active-neutral-pair:v1:"
69
+ b"two-stable-lane-units;external-binary-permutation-rank;"
70
+ b"one-source-bound-card;memory-versus-canonical-redacted-neutral;"
71
+ b"same-required-common-pool-actions;compound-memory-dose-estimand;"
72
+ b"lane-randomized-not-parent-or-full-pool-matched;"
73
+ b"single-block-not-identified;no-online-score-update"
74
+ ).hexdigest()
75
+ PORTFOLIO_MEMORY_LANE_SUPPORT_POLICY_ID = (
76
+ "portfolio_memory_independent_exact_lane_support"
77
+ )
78
+ PORTFOLIO_MEMORY_LANE_SUPPORT_POLICY_VERSION = 1
79
+ PORTFOLIO_MEMORY_LANE_SUPPORT_POLICY_DEFINITION_SHA256 = hashlib.sha256(
80
+ b"agent-evolve:portfolio-memory-independent-exact-lane-support:v1:"
81
+ b"one-current-lane;source-bound-cards;exact-finite-action-support;"
82
+ b"task-lane-keyed-card-selection;provider-and-outcome-blind;"
83
+ b"optimization-exposure-only;card-vs-neutral-effect=false;"
84
+ b"online-causal-credit=false"
85
+ ).hexdigest()
86
+ _PLAN_DOMAIN = b"agent-evolve:portfolio-memory-matched-control-plan:v1\x00"
87
+ _VIEW_DOMAIN = b"agent-evolve:portfolio-memory-matched-control-view:v1\x00"
88
+ _OUTCOME_DOMAIN = b"agent-evolve:portfolio-memory-matched-control-outcome:v2\x00"
89
+ _SUPPORT_DOMAIN = b"agent-evolve:portfolio-memory-matched-support:v1\x00"
90
+ _CARD_ORDER_DOMAIN = b"agent-evolve:portfolio-memory-matched-card-order:v1\x00"
91
+ _LANE_SUPPORT_DOMAIN = b"agent-evolve:portfolio-memory-lane-support:v1\x00"
92
+ _LANE_CARD_ORDER_DOMAIN = b"agent-evolve:portfolio-memory-lane-card-order:v1\x00"
93
+
94
+
95
+ def _canonical_json(value: object) -> bytes:
96
+ return json.dumps(
97
+ value,
98
+ allow_nan=False,
99
+ ensure_ascii=True,
100
+ separators=(",", ":"),
101
+ sort_keys=True,
102
+ ).encode("ascii", errors="strict")
103
+
104
+
105
+ def _hash(domain: bytes, value: object) -> str:
106
+ return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
107
+
108
+
109
+ def _reference_record(reference: InsightRef) -> dict[str, object]:
110
+ if type(reference) is not InsightRef:
111
+ raise TypeError("reference must be an exact InsightRef")
112
+ InsightRef.__post_init__(reference)
113
+ return {
114
+ "insight_id": reference.insight_id.value,
115
+ "version": reference.version,
116
+ }
117
+
118
+
119
+ @dataclass(frozen=True, slots=True)
120
+ class PortfolioMemoryMatchedArmAssignment:
121
+ """One pre-provider binary arm assignment for a stable lane unit."""
122
+
123
+ unit: StableMemoryAssignmentUnit
124
+ arm: PortfolioExperimentalArm
125
+ schedule_position: int
126
+ assignment_probability_numerator: int = field(init=False, default=1)
127
+ assignment_probability_denominator: int = field(init=False, default=2)
128
+
129
+ def __post_init__(self) -> None:
130
+ if type(self.unit) is not StableMemoryAssignmentUnit:
131
+ raise TypeError("unit must be an exact StableMemoryAssignmentUnit")
132
+ self.unit.__post_init__()
133
+ if self.arm not in (
134
+ PortfolioExperimentalArm.MEMORY,
135
+ PortfolioExperimentalArm.NEUTRAL,
136
+ ):
137
+ raise ValueError("matched memory assignments admit only M or N")
138
+ if type(self.schedule_position) is not int or self.schedule_position < 0:
139
+ raise ValueError("schedule_position must be nonnegative")
140
+
141
+ def to_record(self) -> dict[str, object]:
142
+ self.__post_init__()
143
+ return {
144
+ "unit": self.unit.to_record(),
145
+ "arm": self.arm.value,
146
+ "schedule_position": self.schedule_position,
147
+ "assignment_probability": [
148
+ self.assignment_probability_numerator,
149
+ self.assignment_probability_denominator,
150
+ ],
151
+ }
152
+
153
+
154
+ @dataclass(frozen=True, slots=True)
155
+ class PortfolioMemoryMatchedControlPlan:
156
+ """One authenticated randomized M/N lane pair for an exact card."""
157
+
158
+ reference: InsightRef
159
+ exact_context_sha256: str
160
+ ordered_units: tuple[StableMemoryAssignmentUnit, ...]
161
+ active_unit_rank: int
162
+ assignments: tuple[PortfolioMemoryMatchedArmAssignment, ...]
163
+ policy_id: str = field(
164
+ init=False,
165
+ default=PORTFOLIO_MEMORY_MATCHED_CONTROL_POLICY_ID,
166
+ )
167
+ policy_version: int = field(
168
+ init=False,
169
+ default=PORTFOLIO_MEMORY_MATCHED_CONTROL_POLICY_VERSION,
170
+ )
171
+ policy_definition_sha256: str = field(
172
+ init=False,
173
+ default=PORTFOLIO_MEMORY_MATCHED_CONTROL_DEFINITION_SHA256,
174
+ )
175
+ plan_sha256: str = field(init=False)
176
+
177
+ def __post_init__(self) -> None:
178
+ InsightRef.__post_init__(self.reference)
179
+ require_sha256(self.exact_context_sha256, "exact_context_sha256")
180
+ if (
181
+ type(self.ordered_units) is not tuple
182
+ or len(self.ordered_units) != 2
183
+ or any(
184
+ type(value) is not StableMemoryAssignmentUnit
185
+ for value in self.ordered_units
186
+ )
187
+ ):
188
+ raise ValueError("a matched block requires exactly two stable units")
189
+ for value in self.ordered_units:
190
+ value.__post_init__()
191
+ if len({value.unit_key for value in self.ordered_units}) != 2:
192
+ raise ValueError("matched units must have distinct identities")
193
+ if len({value.lane_id for value in self.ordered_units}) != 2:
194
+ raise ValueError("matched units must occupy distinct stable lanes")
195
+ if len({value.generation for value in self.ordered_units}) != 1:
196
+ raise ValueError("one matched block cannot span generations")
197
+ if (
198
+ type(self.active_unit_rank) is not int
199
+ or self.active_unit_rank not in (0, 1)
200
+ ):
201
+ raise ValueError("active_unit_rank must be one exact binary rank")
202
+ if (
203
+ type(self.assignments) is not tuple
204
+ or len(self.assignments) != 2
205
+ or any(
206
+ type(value) is not PortfolioMemoryMatchedArmAssignment
207
+ for value in self.assignments
208
+ )
209
+ ):
210
+ raise ValueError("assignments must cover exactly two units")
211
+ expected = tuple(
212
+ PortfolioMemoryMatchedArmAssignment(
213
+ unit=unit,
214
+ arm=(
215
+ PortfolioExperimentalArm.MEMORY
216
+ if position == self.active_unit_rank
217
+ else PortfolioExperimentalArm.NEUTRAL
218
+ ),
219
+ schedule_position=position,
220
+ )
221
+ for position, unit in enumerate(self.ordered_units)
222
+ )
223
+ if self.assignments != expected:
224
+ raise ValueError("assignments do not replay from the external rank")
225
+ if (
226
+ self.policy_id != PORTFOLIO_MEMORY_MATCHED_CONTROL_POLICY_ID
227
+ or self.policy_version != PORTFOLIO_MEMORY_MATCHED_CONTROL_POLICY_VERSION
228
+ or self.policy_definition_sha256
229
+ != PORTFOLIO_MEMORY_MATCHED_CONTROL_DEFINITION_SHA256
230
+ ):
231
+ raise ValueError("unsupported matched-control policy")
232
+ object.__setattr__(
233
+ self,
234
+ "plan_sha256",
235
+ _hash(_PLAN_DOMAIN, self._unsigned_record()),
236
+ )
237
+
238
+ @property
239
+ def generation(self) -> int:
240
+ return self.ordered_units[0].generation
241
+
242
+ def assignment_for(
243
+ self,
244
+ *,
245
+ generation: int,
246
+ lane_id: str,
247
+ ) -> PortfolioMemoryMatchedArmAssignment:
248
+ self.__post_init__()
249
+ matches = tuple(
250
+ value
251
+ for value in self.assignments
252
+ if value.unit.generation == generation and value.unit.lane_id == lane_id
253
+ )
254
+ if len(matches) != 1:
255
+ raise KeyError("generation/lane does not resolve one matched assignment")
256
+ return matches[0]
257
+
258
+ def _unsigned_record(self) -> dict[str, object]:
259
+ return {
260
+ "schema_version": 1,
261
+ "reference": _reference_record(self.reference),
262
+ "exact_context_sha256": self.exact_context_sha256,
263
+ "generation": self.generation,
264
+ "active_unit_rank": self.active_unit_rank,
265
+ "assignments": [value.to_record() for value in self.assignments],
266
+ "policy": {
267
+ "policy_id": self.policy_id,
268
+ "policy_version": self.policy_version,
269
+ "definition_sha256": self.policy_definition_sha256,
270
+ },
271
+ "estimand": (
272
+ "memory_guided_action_dose_package_vs_neutral_with_shared_"
273
+ "required_actions"
274
+ ),
275
+ "provider_and_outcome_blind_assignment": True,
276
+ "same_parent_matched": False,
277
+ "full_candidate_pool_matched": False,
278
+ "single_block_card_effect_identified": False,
279
+ "online_score_update_allowed": False,
280
+ "required_analysis": (
281
+ "aggregate_repeated_precommitted_blocks_with_arm_aware_outcomes"
282
+ ),
283
+ "required_stronger_successor": (
284
+ "replicated_same_parent_same_full_pool_active_neutral_slots"
285
+ ),
286
+ }
287
+
288
+ def to_record(self) -> dict[str, object]:
289
+ self.__post_init__()
290
+ return {**self._unsigned_record(), "plan_sha256": self.plan_sha256}
291
+
292
+
293
+ @dataclass(frozen=True, slots=True)
294
+ class PortfolioMemoryMatchedControlPlanner:
295
+ """Map one external binary rank to a replayable M/N assignment."""
296
+
297
+ def plan(
298
+ self,
299
+ *,
300
+ reference: InsightRef,
301
+ exact_context_sha256: str,
302
+ ordered_units: tuple[StableMemoryAssignmentUnit, ...],
303
+ active_unit_rank: int,
304
+ ) -> PortfolioMemoryMatchedControlPlan:
305
+ assignments = tuple(
306
+ PortfolioMemoryMatchedArmAssignment(
307
+ unit=unit,
308
+ arm=(
309
+ PortfolioExperimentalArm.MEMORY
310
+ if position == active_unit_rank
311
+ else PortfolioExperimentalArm.NEUTRAL
312
+ ),
313
+ schedule_position=position,
314
+ )
315
+ for position, unit in enumerate(ordered_units)
316
+ )
317
+ return PortfolioMemoryMatchedControlPlan(
318
+ reference=reference,
319
+ exact_context_sha256=exact_context_sha256,
320
+ ordered_units=ordered_units,
321
+ active_unit_rank=active_unit_rank,
322
+ assignments=assignments,
323
+ )
324
+
325
+
326
+ @dataclass(frozen=True, slots=True)
327
+ class PortfolioMemoryMatchedLaneSupport:
328
+ """Exact support for the selected source card under one current lane."""
329
+
330
+ lane_id: str
331
+ support: PortfolioMemoryDoseCardSupport
332
+
333
+ def __post_init__(self) -> None:
334
+ if type(self.lane_id) is not str or not self.lane_id:
335
+ raise ValueError("lane_id must be a nonempty string")
336
+ if type(self.support) is not PortfolioMemoryDoseCardSupport:
337
+ raise TypeError("support must be exact PortfolioMemoryDoseCardSupport")
338
+ self.support.__post_init__()
339
+
340
+ def to_record(self) -> dict[str, object]:
341
+ self.__post_init__()
342
+ return {"lane_id": self.lane_id, "support": self.support.to_record()}
343
+
344
+
345
+ @dataclass(frozen=True, slots=True)
346
+ class PortfolioMemoryMatchedSupportResolution:
347
+ """Outcome-blind selection of one card supported by every matched lane."""
348
+
349
+ lane_ids: tuple[str, ...]
350
+ eligible_card_keys: tuple[str, ...]
351
+ selected_card_key: str | None
352
+ selected_lane_supports: tuple[PortfolioMemoryMatchedLaneSupport, ...]
353
+ selection_key_sha256: str
354
+ receipt_sha256: str = field(init=False)
355
+
356
+ def __post_init__(self) -> None:
357
+ if (
358
+ type(self.lane_ids) is not tuple
359
+ or len(self.lane_ids) != 2
360
+ or self.lane_ids != tuple(sorted(set(self.lane_ids)))
361
+ ):
362
+ raise ValueError("matched support requires two canonical lane IDs")
363
+ if (
364
+ type(self.eligible_card_keys) is not tuple
365
+ or self.eligible_card_keys
366
+ != tuple(sorted(set(self.eligible_card_keys)))
367
+ ):
368
+ raise ValueError("eligible card keys must be unique and canonical")
369
+ require_sha256(self.selection_key_sha256, "selection_key_sha256")
370
+ if self.selected_card_key is None:
371
+ if self.eligible_card_keys or self.selected_lane_supports:
372
+ raise ValueError("ineligible resolution cannot carry selected support")
373
+ else:
374
+ if self.selected_card_key not in self.eligible_card_keys:
375
+ raise ValueError("selected card is outside the eligible set")
376
+ if (
377
+ type(self.selected_lane_supports) is not tuple
378
+ or len(self.selected_lane_supports) != 2
379
+ or tuple(value.lane_id for value in self.selected_lane_supports)
380
+ != self.lane_ids
381
+ ):
382
+ raise ValueError("selected support must cover both lanes exactly")
383
+ for value in self.selected_lane_supports:
384
+ value.__post_init__()
385
+ if value.support.card_key != self.selected_card_key:
386
+ raise ValueError("lane support names another selected card")
387
+ object.__setattr__(
388
+ self,
389
+ "receipt_sha256",
390
+ _hash(_SUPPORT_DOMAIN, self._unsigned_record()),
391
+ )
392
+
393
+ @property
394
+ def eligible(self) -> bool:
395
+ return self.selected_card_key is not None
396
+
397
+ def support_for(self, lane_id: str) -> PortfolioMemoryDoseCardSupport:
398
+ self.__post_init__()
399
+ matches = tuple(
400
+ value.support
401
+ for value in self.selected_lane_supports
402
+ if value.lane_id == lane_id
403
+ )
404
+ if len(matches) != 1:
405
+ raise KeyError("lane lacks selected matched-card support")
406
+ return matches[0]
407
+
408
+ def _unsigned_record(self) -> dict[str, object]:
409
+ return {
410
+ "schema_version": 1,
411
+ "eligible": self.eligible,
412
+ "lane_ids": list(self.lane_ids),
413
+ "eligible_card_keys": list(self.eligible_card_keys),
414
+ "selected_card_key": self.selected_card_key,
415
+ "selected_lane_supports": [
416
+ value.to_record() for value in self.selected_lane_supports
417
+ ],
418
+ "selection_key_sha256": self.selection_key_sha256,
419
+ "provider_fields_consulted": False,
420
+ "outcome_values_consulted": False,
421
+ "card_vs_neutral_effect_identified": False,
422
+ }
423
+
424
+ def to_record(self) -> dict[str, object]:
425
+ self.__post_init__()
426
+ return {**self._unsigned_record(), "receipt_sha256": self.receipt_sha256}
427
+
428
+
429
+ @dataclass(frozen=True, slots=True)
430
+ class PortfolioMemoryMatchedSupportResolver:
431
+ """Choose one complete-support card for a two-lane M/N block."""
432
+
433
+ def resolve(
434
+ self,
435
+ *,
436
+ lanes: tuple[CampaignDiagnosticSupportLaneInput, ...],
437
+ cards: tuple[CampaignDiagnosticSupportCardInput, ...],
438
+ selection_key_sha256: str,
439
+ ) -> PortfolioMemoryMatchedSupportResolution:
440
+ if (
441
+ type(lanes) is not tuple
442
+ or len(lanes) != 2
443
+ or any(
444
+ type(value) is not CampaignDiagnosticSupportLaneInput
445
+ for value in lanes
446
+ )
447
+ ):
448
+ raise ValueError("matched resolution requires exactly two lane inputs")
449
+ if type(cards) is not tuple or not cards or any(
450
+ type(value) is not CampaignDiagnosticSupportCardInput for value in cards
451
+ ):
452
+ raise ValueError("matched resolution requires source card inputs")
453
+ for value in lanes:
454
+ value.__post_init__()
455
+ for value in cards:
456
+ value.__post_init__()
457
+ lane_ids = tuple(sorted(value.lane.lane_id for value in lanes))
458
+ if len(set(lane_ids)) != 2:
459
+ raise ValueError("matched lanes must have distinct identities")
460
+ card_keys = tuple(sorted(value.card.card_key for value in cards))
461
+ if len(set(card_keys)) != len(card_keys):
462
+ raise ValueError("matched source cards must have distinct keys")
463
+ require_sha256(selection_key_sha256, "selection_key_sha256")
464
+
465
+ by_lane = {value.lane.lane_id: value for value in lanes}
466
+ by_card = {value.card.card_key: value for value in cards}
467
+ complete: dict[str, tuple[PortfolioMemoryMatchedLaneSupport, ...]] = {}
468
+ for card_key in card_keys:
469
+ card = by_card[card_key]
470
+ supports: list[PortfolioMemoryMatchedLaneSupport] = []
471
+ for lane_id in lane_ids:
472
+ try:
473
+ support = derive_portfolio_memory_dose_card_support(
474
+ card.semantics,
475
+ by_lane[lane_id].finite_variation_contract,
476
+ )
477
+ except ValueError:
478
+ break
479
+ supports.append(
480
+ PortfolioMemoryMatchedLaneSupport(
481
+ lane_id=lane_id,
482
+ support=support,
483
+ )
484
+ )
485
+ if len(supports) == len(lane_ids):
486
+ complete[card_key] = tuple(supports)
487
+
488
+ eligible_keys = tuple(sorted(complete))
489
+ if not eligible_keys:
490
+ return PortfolioMemoryMatchedSupportResolution(
491
+ lane_ids=lane_ids,
492
+ eligible_card_keys=(),
493
+ selected_card_key=None,
494
+ selected_lane_supports=(),
495
+ selection_key_sha256=selection_key_sha256,
496
+ )
497
+ key_bytes = bytes.fromhex(selection_key_sha256)
498
+ selected = min(
499
+ eligible_keys,
500
+ key=lambda card_key: (
501
+ hashlib.sha256(
502
+ _CARD_ORDER_DOMAIN
503
+ + key_bytes
504
+ + card_key.encode("ascii", errors="strict")
505
+ + bytes.fromhex(by_card[card_key].card.card_identity_sha256)
506
+ ).digest(),
507
+ card_key,
508
+ ),
509
+ )
510
+ return PortfolioMemoryMatchedSupportResolution(
511
+ lane_ids=lane_ids,
512
+ eligible_card_keys=eligible_keys,
513
+ selected_card_key=selected,
514
+ selected_lane_supports=complete[selected],
515
+ selection_key_sha256=selection_key_sha256,
516
+ )
517
+
518
+
519
+ @dataclass(frozen=True, slots=True)
520
+ class PortfolioMemoryLaneSupportResolution:
521
+ """Outcome-blind card choice for one independently supportable lane.
522
+
523
+ This resolution is an optimization exposure, not an active-versus-neutral
524
+ causal comparison. It exists so an unrelated second parent cannot erase a
525
+ useful, exactly supported memory treatment from the first parent.
526
+ """
527
+
528
+ lane_id: str
529
+ eligible_card_keys: tuple[str, ...]
530
+ selected_card_key: str | None
531
+ selected_support: PortfolioMemoryDoseCardSupport | None
532
+ selection_key_sha256: str
533
+ receipt_sha256: str = field(init=False)
534
+
535
+ def __post_init__(self) -> None:
536
+ if type(self.lane_id) is not str or not self.lane_id:
537
+ raise ValueError("lane_id must be a nonempty string")
538
+ if (
539
+ type(self.eligible_card_keys) is not tuple
540
+ or self.eligible_card_keys
541
+ != tuple(sorted(set(self.eligible_card_keys)))
542
+ ):
543
+ raise ValueError("eligible card keys must be unique and canonical")
544
+ require_sha256(self.selection_key_sha256, "selection_key_sha256")
545
+ if self.selected_card_key is None:
546
+ if self.eligible_card_keys or self.selected_support is not None:
547
+ raise ValueError("ineligible lane cannot carry selected support")
548
+ else:
549
+ if self.selected_card_key not in self.eligible_card_keys:
550
+ raise ValueError("selected lane card is outside the eligible set")
551
+ if type(self.selected_support) is not PortfolioMemoryDoseCardSupport:
552
+ raise TypeError("eligible lane requires exact selected support")
553
+ self.selected_support.__post_init__()
554
+ if self.selected_support.card_key != self.selected_card_key:
555
+ raise ValueError("selected support names another lane card")
556
+ object.__setattr__(
557
+ self,
558
+ "receipt_sha256",
559
+ _hash(_LANE_SUPPORT_DOMAIN, self._unsigned_record()),
560
+ )
561
+
562
+ @property
563
+ def eligible(self) -> bool:
564
+ return self.selected_card_key is not None
565
+
566
+ def _unsigned_record(self) -> dict[str, object]:
567
+ return {
568
+ "schema_version": 1,
569
+ "lane_id": self.lane_id,
570
+ "eligible": self.eligible,
571
+ "eligible_card_keys": list(self.eligible_card_keys),
572
+ "selected_card_key": self.selected_card_key,
573
+ "selected_support": (
574
+ None
575
+ if self.selected_support is None
576
+ else self.selected_support.to_record()
577
+ ),
578
+ "selection_key_sha256": self.selection_key_sha256,
579
+ "policy": {
580
+ "policy_id": PORTFOLIO_MEMORY_LANE_SUPPORT_POLICY_ID,
581
+ "policy_version": PORTFOLIO_MEMORY_LANE_SUPPORT_POLICY_VERSION,
582
+ "definition_sha256": (
583
+ PORTFOLIO_MEMORY_LANE_SUPPORT_POLICY_DEFINITION_SHA256
584
+ ),
585
+ },
586
+ "provider_fields_consulted": False,
587
+ "outcome_values_consulted": False,
588
+ "card_vs_neutral_effect_identified": False,
589
+ "online_causal_credit_allowed": False,
590
+ }
591
+
592
+ def to_record(self) -> dict[str, object]:
593
+ self.__post_init__()
594
+ return {**self._unsigned_record(), "receipt_sha256": self.receipt_sha256}
595
+
596
+
597
+ @dataclass(frozen=True, slots=True)
598
+ class PortfolioMemoryLaneSupportResolver:
599
+ """Select one exactly supported card for one lane without outcome access."""
600
+
601
+ def resolve(
602
+ self,
603
+ *,
604
+ lane: CampaignDiagnosticSupportLaneInput,
605
+ cards: tuple[CampaignDiagnosticSupportCardInput, ...],
606
+ selection_key_sha256: str,
607
+ ) -> PortfolioMemoryLaneSupportResolution:
608
+ if type(lane) is not CampaignDiagnosticSupportLaneInput:
609
+ raise TypeError("lane must be an exact diagnostic support lane input")
610
+ lane.__post_init__()
611
+ if type(cards) is not tuple or not cards or any(
612
+ type(value) is not CampaignDiagnosticSupportCardInput for value in cards
613
+ ):
614
+ raise ValueError("lane resolution requires source card inputs")
615
+ for value in cards:
616
+ value.__post_init__()
617
+ card_keys = tuple(sorted(value.card.card_key for value in cards))
618
+ if len(set(card_keys)) != len(card_keys):
619
+ raise ValueError("lane source cards must have distinct keys")
620
+ require_sha256(selection_key_sha256, "selection_key_sha256")
621
+
622
+ by_card = {value.card.card_key: value for value in cards}
623
+ supported: dict[str, PortfolioMemoryDoseCardSupport] = {}
624
+ for card_key in card_keys:
625
+ card = by_card[card_key]
626
+ try:
627
+ supported[card_key] = derive_portfolio_memory_dose_card_support(
628
+ card.semantics,
629
+ lane.finite_variation_contract,
630
+ )
631
+ except ValueError:
632
+ continue
633
+ eligible_keys = tuple(sorted(supported))
634
+ if not eligible_keys:
635
+ return PortfolioMemoryLaneSupportResolution(
636
+ lane_id=lane.lane.lane_id,
637
+ eligible_card_keys=(),
638
+ selected_card_key=None,
639
+ selected_support=None,
640
+ selection_key_sha256=selection_key_sha256,
641
+ )
642
+
643
+ key_bytes = bytes.fromhex(selection_key_sha256)
644
+ selected = min(
645
+ eligible_keys,
646
+ key=lambda card_key: (
647
+ hashlib.sha256(
648
+ _LANE_CARD_ORDER_DOMAIN
649
+ + key_bytes
650
+ + bytes.fromhex(lane.lane.lane_identity_sha256)
651
+ + card_key.encode("ascii", errors="strict")
652
+ + bytes.fromhex(by_card[card_key].card.card_identity_sha256)
653
+ ).digest(),
654
+ card_key,
655
+ ),
656
+ )
657
+ return PortfolioMemoryLaneSupportResolution(
658
+ lane_id=lane.lane.lane_id,
659
+ eligible_card_keys=eligible_keys,
660
+ selected_card_key=selected,
661
+ selected_support=supported[selected],
662
+ selection_key_sha256=selection_key_sha256,
663
+ )
664
+
665
+
666
+ @dataclass(frozen=True, slots=True)
667
+ class PortfolioMemoryMatchedArmView:
668
+ """One materialized M or N view with a shared candidate-pool obligation."""
669
+
670
+ plan_sha256: str
671
+ assignment: PortfolioMemoryMatchedArmAssignment
672
+ cards: tuple[PortfolioCard, ...]
673
+ source_registry: PortfolioCardSourceRegistry
674
+ experimental_view_receipt: PortfolioExperimentalViewReceipt
675
+ required_common_pool_option_ids: tuple[str, ...]
676
+ view_sha256: str = field(init=False)
677
+
678
+ def __post_init__(self) -> None:
679
+ require_sha256(self.plan_sha256, "plan_sha256")
680
+ if type(self.assignment) is not PortfolioMemoryMatchedArmAssignment:
681
+ raise TypeError("assignment must be exact")
682
+ self.assignment.__post_init__()
683
+ if type(self.cards) is not tuple or len(self.cards) != 1:
684
+ raise ValueError("a matched arm view requires exactly one card")
685
+ card = self.cards[0]
686
+ if type(card) is not PortfolioCard:
687
+ raise TypeError("matched arm card must be exact")
688
+ card.__post_init__()
689
+ if type(self.source_registry) is not PortfolioCardSourceRegistry:
690
+ raise TypeError("source_registry must be exact")
691
+ self.source_registry.__post_init__()
692
+ if type(self.experimental_view_receipt) is not PortfolioExperimentalViewReceipt:
693
+ raise TypeError("experimental_view_receipt must be exact")
694
+ self.experimental_view_receipt.__post_init__()
695
+ if self.experimental_view_receipt.arm is not self.assignment.arm:
696
+ raise ValueError("experimental view arm differs from its assignment")
697
+ if (
698
+ type(self.required_common_pool_option_ids) is not tuple
699
+ or not self.required_common_pool_option_ids
700
+ or self.required_common_pool_option_ids
701
+ != tuple(sorted(set(self.required_common_pool_option_ids)))
702
+ ):
703
+ raise ValueError(
704
+ "required common-pool actions must be nonempty and canonical"
705
+ )
706
+ if self.assignment.arm is PortfolioExperimentalArm.MEMORY:
707
+ if card.derived_view_receipt is not None or not card.finite_action_evidence:
708
+ raise ValueError("M requires the pristine evidence-bearing source card")
709
+ else:
710
+ if (
711
+ card.prompt_payload != CANONICAL_NEUTRAL_PORTFOLIO_PROMPT_PAYLOAD
712
+ or card.evidence_sha256
713
+ != CANONICAL_REDACTED_PORTFOLIO_EVIDENCE_SHA256
714
+ or card.score_components
715
+ or card.assigned_score is not None
716
+ or card.finite_action_evidence
717
+ ):
718
+ raise ValueError("N does not use the canonical redacted card view")
719
+ object.__setattr__(
720
+ self,
721
+ "view_sha256",
722
+ _hash(_VIEW_DOMAIN, self._unsigned_record()),
723
+ )
724
+
725
+ @property
726
+ def memory_dose_allowed(self) -> bool:
727
+ return self.assignment.arm is PortfolioExperimentalArm.MEMORY
728
+
729
+ def _unsigned_record(self) -> dict[str, object]:
730
+ return {
731
+ "schema_version": 1,
732
+ "plan_sha256": self.plan_sha256,
733
+ "assignment": self.assignment.to_record(),
734
+ "card_snapshot_sha256": (
735
+ self.experimental_view_receipt.card_snapshot_sha256
736
+ ),
737
+ "source_registry_sha256": self.source_registry.registry_sha256,
738
+ "experimental_view_receipt_sha256": (
739
+ self.experimental_view_receipt.receipt_sha256
740
+ ),
741
+ "required_common_pool_option_ids": list(
742
+ self.required_common_pool_option_ids
743
+ ),
744
+ "same_required_common_pool_actions_across_arms": True,
745
+ "memory_dose_allowed": self.memory_dose_allowed,
746
+ }
747
+
748
+ def to_record(self) -> dict[str, object]:
749
+ self.__post_init__()
750
+ return {**self._unsigned_record(), "view_sha256": self.view_sha256}
751
+
752
+
753
+ def materialize_portfolio_memory_matched_arm(
754
+ *,
755
+ plan: PortfolioMemoryMatchedControlPlan,
756
+ assignment: PortfolioMemoryMatchedArmAssignment,
757
+ source_card: PortfolioCard,
758
+ source_registry: PortfolioCardSourceRegistry,
759
+ finite_variation_contract: FiniteVariationContract,
760
+ ) -> PortfolioMemoryMatchedArmView:
761
+ """Create one source-identical M/N view for a precommitted assignment."""
762
+
763
+ if type(plan) is not PortfolioMemoryMatchedControlPlan:
764
+ raise TypeError("plan must be exact")
765
+ plan.__post_init__()
766
+ if assignment not in plan.assignments:
767
+ raise ValueError("assignment is outside the matched plan")
768
+ if type(source_card) is not PortfolioCard:
769
+ raise TypeError("source_card must be exact")
770
+ source_card.__post_init__()
771
+ if source_card.reference != plan.reference:
772
+ raise ValueError("source card differs from the planned reference")
773
+ if (
774
+ source_card.source_binding is None
775
+ or source_card.derived_view_receipt is not None
776
+ ):
777
+ raise ValueError("matched views require a pristine source-bound card")
778
+ if type(source_registry) is not PortfolioCardSourceRegistry:
779
+ raise TypeError("source_registry must be exact")
780
+ source_registry.__post_init__()
781
+ if len(source_registry.source_bindings) != 1 or (
782
+ source_registry.source_bindings[0] != source_card.source_binding
783
+ ):
784
+ raise ValueError("matched view registry must contain exactly the source card")
785
+ validate_finite_variation_contract(finite_variation_contract)
786
+ required_ids = tuple(
787
+ sorted(
788
+ {
789
+ value.option_id
790
+ for value in source_card.source_binding.finite_action_evidence
791
+ }
792
+ )
793
+ )
794
+ available_ids = {value.option_id for value in finite_variation_contract.options}
795
+ if not required_ids or not set(required_ids).issubset(available_ids):
796
+ raise ValueError("source card lacks complete support in the current contract")
797
+
798
+ if assignment.arm is PortfolioExperimentalArm.MEMORY:
799
+ cards = (source_card,)
800
+ else:
801
+ transforms = tuple(
802
+ sorted(
803
+ (
804
+ PortfolioCardViewTransform.ACTION_EVIDENCE_REDACTION,
805
+ PortfolioCardViewTransform.EVIDENCE_REDACTION,
806
+ PortfolioCardViewTransform.PROMPT_REDACTION,
807
+ PortfolioCardViewTransform.SCORE_REDACTION,
808
+ ),
809
+ key=lambda value: value.value,
810
+ )
811
+ )
812
+ cards = (
813
+ derive_portfolio_card_view(
814
+ source_card,
815
+ prompt_payload=CANONICAL_NEUTRAL_PORTFOLIO_PROMPT_PAYLOAD,
816
+ evidence_sha256=CANONICAL_REDACTED_PORTFOLIO_EVIDENCE_SHA256,
817
+ score_components=(),
818
+ assigned_score=None,
819
+ finite_action_evidence=(),
820
+ transforms=transforms,
821
+ policy_id=PORTFOLIO_MEMORY_MATCHED_CONTROL_POLICY_ID,
822
+ policy_version=PORTFOLIO_MEMORY_MATCHED_CONTROL_POLICY_VERSION,
823
+ policy_definition_sha256=(
824
+ PORTFOLIO_MEMORY_MATCHED_CONTROL_DEFINITION_SHA256
825
+ ),
826
+ ),
827
+ )
828
+ receipt = bind_portfolio_experimental_view(
829
+ arm=assignment.arm,
830
+ cards=cards,
831
+ finite_variation_contract=finite_variation_contract,
832
+ source_registry=source_registry,
833
+ policy_id=PORTFOLIO_MEMORY_MATCHED_CONTROL_POLICY_ID,
834
+ policy_version=PORTFOLIO_MEMORY_MATCHED_CONTROL_POLICY_VERSION,
835
+ policy_definition_sha256=(
836
+ PORTFOLIO_MEMORY_MATCHED_CONTROL_DEFINITION_SHA256
837
+ ),
838
+ )
839
+ return PortfolioMemoryMatchedArmView(
840
+ plan_sha256=plan.plan_sha256,
841
+ assignment=assignment,
842
+ cards=cards,
843
+ source_registry=source_registry,
844
+ experimental_view_receipt=receipt,
845
+ required_common_pool_option_ids=required_ids,
846
+ )
847
+
848
+
849
+ @dataclass(frozen=True, slots=True)
850
+ class PortfolioMemoryMatchedControlOutcome:
851
+ """Observed M-minus-N contrast from one precommitted lane pair."""
852
+
853
+ plan_sha256: str
854
+ generation: int
855
+ reference: InsightRef
856
+ aggregation_binding_sha256: str
857
+ active_view_sha256: str
858
+ neutral_view_sha256: str
859
+ active_result_receipt_sha256: str
860
+ neutral_result_receipt_sha256: str
861
+ active_wave_reward: float
862
+ neutral_wave_reward: float
863
+ outcome_sha256: str = field(init=False)
864
+
865
+ def __post_init__(self) -> None:
866
+ for name in (
867
+ "plan_sha256",
868
+ "aggregation_binding_sha256",
869
+ "active_view_sha256",
870
+ "neutral_view_sha256",
871
+ "active_result_receipt_sha256",
872
+ "neutral_result_receipt_sha256",
873
+ ):
874
+ require_sha256(getattr(self, name), name)
875
+ if type(self.generation) is not int or self.generation <= 0:
876
+ raise ValueError("generation must be a positive exact integer")
877
+ if type(self.reference) is not InsightRef:
878
+ raise TypeError("reference must be an exact InsightRef")
879
+ InsightRef.__post_init__(self.reference)
880
+ for name in ("active_wave_reward", "neutral_wave_reward"):
881
+ value = getattr(self, name)
882
+ if type(value) is not float or not math.isfinite(value):
883
+ raise TypeError(f"{name} must be a finite canonical float")
884
+ object.__setattr__(
885
+ self,
886
+ "outcome_sha256",
887
+ _hash(_OUTCOME_DOMAIN, self._unsigned_record()),
888
+ )
889
+
890
+ @property
891
+ def observed_active_minus_neutral(self) -> float:
892
+ return self.active_wave_reward - self.neutral_wave_reward
893
+
894
+ def _unsigned_record(self) -> dict[str, object]:
895
+ return {
896
+ "schema_version": 2,
897
+ "plan_sha256": self.plan_sha256,
898
+ "generation": self.generation,
899
+ "reference": _reference_record(self.reference),
900
+ "aggregation_binding_sha256": self.aggregation_binding_sha256,
901
+ "active_view_sha256": self.active_view_sha256,
902
+ "neutral_view_sha256": self.neutral_view_sha256,
903
+ "active_result_receipt_sha256": self.active_result_receipt_sha256,
904
+ "neutral_result_receipt_sha256": self.neutral_result_receipt_sha256,
905
+ "active_wave_reward_hex": self.active_wave_reward.hex(),
906
+ "neutral_wave_reward_hex": self.neutral_wave_reward.hex(),
907
+ "observed_active_minus_neutral_hex": (
908
+ self.observed_active_minus_neutral.hex()
909
+ ),
910
+ "single_block_card_effect_identified": False,
911
+ "online_score_update_allowed": False,
912
+ "analysis_scope": "append_only_arm_aware_experimental_observation",
913
+ }
914
+
915
+ def to_record(self) -> dict[str, object]:
916
+ self.__post_init__()
917
+ return {**self._unsigned_record(), "outcome_sha256": self.outcome_sha256}
918
+
919
+
920
+ __all__ = [
921
+ "PORTFOLIO_MEMORY_LANE_SUPPORT_POLICY_DEFINITION_SHA256",
922
+ "PORTFOLIO_MEMORY_LANE_SUPPORT_POLICY_ID",
923
+ "PORTFOLIO_MEMORY_LANE_SUPPORT_POLICY_VERSION",
924
+ "PORTFOLIO_MEMORY_MATCHED_CONTROL_DEFINITION_SHA256",
925
+ "PORTFOLIO_MEMORY_MATCHED_CONTROL_POLICY_ID",
926
+ "PORTFOLIO_MEMORY_MATCHED_CONTROL_POLICY_VERSION",
927
+ "PortfolioMemoryMatchedArmAssignment",
928
+ "PortfolioMemoryMatchedArmView",
929
+ "PortfolioMemoryMatchedControlOutcome",
930
+ "PortfolioMemoryMatchedControlPlan",
931
+ "PortfolioMemoryMatchedControlPlanner",
932
+ "PortfolioMemoryMatchedLaneSupport",
933
+ "PortfolioMemoryMatchedSupportResolution",
934
+ "PortfolioMemoryMatchedSupportResolver",
935
+ "PortfolioMemoryLaneSupportResolution",
936
+ "PortfolioMemoryLaneSupportResolver",
937
+ "materialize_portfolio_memory_matched_arm",
938
+ ]