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,908 @@
1
+ """Prior-only empirical calibration for action-consequence forecasts.
2
+
3
+ The language model is a useful semantic proposal expert, but it must not remain
4
+ the numerical oracle after real evaluator evidence exists. This module adds a
5
+ workload-neutral consequence expert over the existing action-outcome ledger.
6
+ It transfers only within an authenticated campaign scope and only from waves
7
+ strictly earlier than the current one.
8
+
9
+ The policy is deliberately conservative. It builds a local empirical
10
+ distribution from repeated patch paths when available, otherwise from the
11
+ option's sealed family, weights observations by parent-metric proximity and
12
+ recency, and fuses it with the model distribution. Both experts are judged
13
+ prequentially: categorical model correctness can reverse an anti-calibrated
14
+ model signal, while empirical transfer loses authority when its own strictly
15
+ prior-wave predictions are below chance. Sparse evidence cannot fully replace
16
+ the model, and exact metric projectors remain a higher authority when applied
17
+ after this policy.
18
+ """
19
+
20
+ from __future__ import annotations
21
+
22
+ import hashlib
23
+ import json
24
+ import math
25
+ from dataclasses import dataclass
26
+ from typing import Protocol, runtime_checkable
27
+
28
+ from agent_evolve.application.action_structural_signature import (
29
+ parent_relative_changed_paths_by_option,
30
+ )
31
+ from agent_evolve.application.action_target_realization import TargetMetricAlias
32
+ from agent_evolve.application.portfolio_evolution import PortfolioMemberDisposition
33
+ from agent_evolve.application.portfolio_outcome_feedback import (
34
+ PortfolioActionOutcomeFeedback,
35
+ PortfolioOutcomeFeedbackLedger,
36
+ )
37
+ from agent_evolve.domain.artifact import ArtifactRef
38
+ from agent_evolve.domain.typed_json import FrozenJsonObject, freeze_json, thaw_json
39
+ from agent_evolve.policies.selection.forecast_calibration import (
40
+ BetaCorrectnessPrior,
41
+ ForecastCalibrationScope,
42
+ ForecastCalibrationSnapshot,
43
+ ForecastConfidenceBin,
44
+ )
45
+ from agent_evolve.ports.action_forecast import (
46
+ ActionForecastRequest,
47
+ ResolvedActionForecast,
48
+ ResolvedActionForecastBatch,
49
+ ResolvedActionMetricForecast,
50
+ validate_resolved_action_forecasts,
51
+ )
52
+ from agent_evolve.ports.agentic_generator import MetricEffectDirection
53
+ from agent_evolve.ports.artifact_store import ArtifactStore, put_json
54
+
55
+
56
+ EMPIRICAL_CONSEQUENCE_POLICY_ID = "competitive_prequential_consequence"
57
+ EMPIRICAL_CONSEQUENCE_POLICY_VERSION = 4
58
+ EMPIRICAL_CONSEQUENCE_POLICY_DEFINITION_SHA256 = hashlib.sha256(
59
+ b"agent-evolve:competitive-prequential-consequence:v4;"
60
+ b"evidence=prior-wave-engine-metric-transitions;"
61
+ b"metric-identity=explicit-target-to-forecast-alias-contract;"
62
+ b"scope=model-prompt-selector-benchmark-session;"
63
+ b"strata=exact-parent-patch-paths-and-family-then-family;"
64
+ b"locality=parent-metric-distance;recency=geometric;"
65
+ b"model-authority=beta-smoothed-direction-correctness-with-negative-skill;"
66
+ b"empirical-authority=weighted-quantiles-gated-by-prequential-skill;"
67
+ b"fusion=bounded-evidence-and-performance-shrinkage;"
68
+ b"validity=family-frequency-bounded-shrinkage;"
69
+ b"audit=bounded-manifest-plus-content-addressed-per-action-artifacts;"
70
+ b"current-future-outcomes=false;workload-model-branches=false"
71
+ ).hexdigest()
72
+ _RESULT_DOMAIN = b"agent-evolve:empirical-consequence-calibration-result:v1\x00"
73
+
74
+
75
+ def _canonical_json(value: object) -> bytes:
76
+ return json.dumps(
77
+ value,
78
+ allow_nan=False,
79
+ ensure_ascii=True,
80
+ separators=(",", ":"),
81
+ sort_keys=True,
82
+ ).encode("ascii", errors="strict")
83
+
84
+
85
+ def _object(value: dict[str, object]) -> FrozenJsonObject:
86
+ frozen = freeze_json(value)
87
+ if type(frozen) is not FrozenJsonObject: # pragma: no cover - closed root.
88
+ raise AssertionError("empirical calibration audit did not freeze to an object")
89
+ return frozen
90
+
91
+
92
+ def _artifact_ref_record(value: ArtifactRef) -> dict[str, object]:
93
+ """Project an artifact reference without coupling the policy to storage."""
94
+
95
+ return {
96
+ "artifact_id": value.artifact_id.value,
97
+ "sha256_hex": value.sha256_hex,
98
+ "size_bytes": value.size_bytes,
99
+ "media_type": value.media_type,
100
+ }
101
+
102
+
103
+ def _weighted_quantile(
104
+ values: tuple[tuple[float, float], ...],
105
+ probability: float,
106
+ ) -> float:
107
+ if not values:
108
+ raise ValueError("weighted quantile requires observations")
109
+ if type(probability) is not float or not 0.0 <= probability <= 1.0:
110
+ raise ValueError("quantile probability must be a canonical float in [0,1]")
111
+ ordered = tuple(sorted(values, key=lambda item: (item[0], item[1])))
112
+ total = sum(weight for _, weight in ordered)
113
+ if not math.isfinite(total) or total <= 0.0:
114
+ raise ValueError("weighted quantile requires positive finite weight")
115
+ threshold = probability * total
116
+ cumulative = 0.0
117
+ for value, weight in ordered:
118
+ cumulative += weight
119
+ if cumulative >= threshold:
120
+ return value
121
+ return ordered[-1][0]
122
+
123
+
124
+ def _effective_support(weights: tuple[float, ...]) -> float:
125
+ total = sum(weights)
126
+ square_total = sum(value * value for value in weights)
127
+ if square_total <= 0.0:
128
+ return 0.0
129
+ return (total * total) / square_total
130
+
131
+
132
+ def _forecast_direction(
133
+ forecast: ResolvedActionMetricForecast,
134
+ ) -> MetricEffectDirection:
135
+ """Use the same interval semantics as selected-forecast calibration."""
136
+
137
+ if type(forecast) is not ResolvedActionMetricForecast:
138
+ raise TypeError("forecast must be an exact resolved metric forecast")
139
+ forecast.__post_init__()
140
+ if forecast.p10_delta == forecast.p50_delta == forecast.p90_delta == 0.0:
141
+ return MetricEffectDirection.UNCHANGED
142
+ if forecast.p90_delta < 0.0:
143
+ return MetricEffectDirection.DECREASE
144
+ if forecast.p10_delta > 0.0:
145
+ return MetricEffectDirection.INCREASE
146
+ return MetricEffectDirection.UNKNOWN
147
+
148
+
149
+ def _confidence_bin(value: float) -> ForecastConfidenceBin:
150
+ if type(value) is not float or not math.isfinite(value):
151
+ raise TypeError("forecast confidence must be a finite canonical float")
152
+ if not 0.0 <= value <= 1.0:
153
+ raise ValueError("forecast confidence must lie in [0,1]")
154
+ if value >= 0.75:
155
+ return ForecastConfidenceBin.HIGH
156
+ if value >= 0.4:
157
+ return ForecastConfidenceBin.MEDIUM
158
+ if value > 0.0:
159
+ return ForecastConfidenceBin.LOW
160
+ return ForecastConfidenceBin.UNKNOWN
161
+
162
+
163
+ def _signed_interval(
164
+ forecast: ResolvedActionMetricForecast,
165
+ factor: float,
166
+ ) -> tuple[float, float, float]:
167
+ """Project correctness skill onto a quantile interval without reordering it."""
168
+
169
+ if type(factor) is not float or not math.isfinite(factor):
170
+ raise TypeError("signed skill factor must be a finite canonical float")
171
+ if not -1.0 <= factor <= 1.0:
172
+ raise ValueError("signed skill factor must lie in [-1,1]")
173
+ values = (
174
+ factor * forecast.p10_delta,
175
+ factor * forecast.p50_delta,
176
+ factor * forecast.p90_delta,
177
+ )
178
+ return tuple(sorted(values)) # type: ignore[return-value]
179
+
180
+
181
+ @dataclass(frozen=True, slots=True, eq=False)
182
+ class ActionConsequenceCalibrationResult:
183
+ """Authenticated calibrated batch plus a complete no-leakage audit."""
184
+
185
+ source_forecast_receipt_sha256: str
186
+ cutoff_wave_index_exclusive: int
187
+ forecasts: ResolvedActionForecastBatch
188
+ audit: FrozenJsonObject
189
+
190
+ def __post_init__(self) -> None:
191
+ if (
192
+ type(self.source_forecast_receipt_sha256) is not str
193
+ or len(self.source_forecast_receipt_sha256) != 64
194
+ ):
195
+ raise ValueError("source_forecast_receipt_sha256 must be a SHA-256")
196
+ try:
197
+ bytes.fromhex(self.source_forecast_receipt_sha256)
198
+ except ValueError as error:
199
+ raise ValueError(
200
+ "source_forecast_receipt_sha256 must be lowercase hexadecimal"
201
+ ) from error
202
+ if (
203
+ type(self.cutoff_wave_index_exclusive) is not int
204
+ or self.cutoff_wave_index_exclusive <= 0
205
+ ):
206
+ raise ValueError("cutoff_wave_index_exclusive must be positive")
207
+ if type(self.forecasts) is not ResolvedActionForecastBatch:
208
+ raise TypeError("forecasts must be an exact resolved batch")
209
+ self.forecasts.__post_init__()
210
+ if (
211
+ type(self.audit) is not FrozenJsonObject
212
+ or freeze_json(self.audit) is not self.audit
213
+ ):
214
+ raise TypeError("audit must be an exact frozen JSON object")
215
+
216
+ def _unsigned_record(self) -> dict[str, object]:
217
+ self.__post_init__()
218
+ return {
219
+ "schema_version": 1,
220
+ "policy": {
221
+ "policy_id": EMPIRICAL_CONSEQUENCE_POLICY_ID,
222
+ "policy_version": EMPIRICAL_CONSEQUENCE_POLICY_VERSION,
223
+ "definition_sha256": (EMPIRICAL_CONSEQUENCE_POLICY_DEFINITION_SHA256),
224
+ },
225
+ "source_forecast_receipt_sha256": self.source_forecast_receipt_sha256,
226
+ "cutoff_wave_index_exclusive": self.cutoff_wave_index_exclusive,
227
+ "calibrated_forecast_receipt_sha256": self.forecasts.receipt_sha256,
228
+ # Frozen typed JSON is the trusted in-memory representation, but
229
+ # result records cross the ordinary JSON evidence boundary. Keep
230
+ # the immutable audit internally and thaw only for serialization.
231
+ "audit": thaw_json(self.audit),
232
+ }
233
+
234
+ @property
235
+ def receipt_sha256(self) -> str:
236
+ return hashlib.sha256(
237
+ _RESULT_DOMAIN + _canonical_json(self._unsigned_record())
238
+ ).hexdigest()
239
+
240
+ def to_record(self) -> dict[str, object]:
241
+ return {**self._unsigned_record(), "receipt_sha256": self.receipt_sha256}
242
+
243
+ def __eq__(self, other: object) -> bool:
244
+ return (
245
+ type(other) is ActionConsequenceCalibrationResult
246
+ and self.receipt_sha256 == other.receipt_sha256
247
+ )
248
+
249
+ __hash__ = None
250
+
251
+
252
+ @runtime_checkable
253
+ class ActionConsequenceCalibrationPolicy(Protocol):
254
+ """Stable application port for prior-only consequence posteriors."""
255
+
256
+ def calibrate(
257
+ self,
258
+ *,
259
+ request: ActionForecastRequest,
260
+ forecasts: ResolvedActionForecastBatch,
261
+ cutoff_wave_index_exclusive: int,
262
+ metric_aliases: tuple[TargetMetricAlias, ...] = (),
263
+ ) -> ActionConsequenceCalibrationResult: ...
264
+
265
+
266
+ @dataclass(slots=True)
267
+ class HierarchicalEmpiricalConsequenceCalibrationPolicy:
268
+ """Compete LLM and local empirical experts without domain branches."""
269
+
270
+ ledger: PortfolioOutcomeFeedbackLedger
271
+ scope: ForecastCalibrationScope
272
+ minimum_path_support: int = 2
273
+ minimum_family_support: int = 2
274
+ prior_strength: float = 3.0
275
+ validity_prior_strength: float = 2.0
276
+ maximum_empirical_authority: float = 0.75
277
+ recency_decay: float = 0.9
278
+ minimum_model_score_support: int = 2
279
+ model_family_min_support: int = 4
280
+ minimum_empirical_score_support: int = 4
281
+ correctness_prior_alpha: float = 1.0
282
+ correctness_prior_beta: float = 1.0
283
+ audit_artifact_store: ArtifactStore | None = None
284
+ maximum_embedded_action_audits: int = 32
285
+
286
+ def __post_init__(self) -> None:
287
+ if type(self.ledger) is not PortfolioOutcomeFeedbackLedger:
288
+ raise TypeError("ledger must be exact PortfolioOutcomeFeedbackLedger")
289
+ if type(self.scope) is not ForecastCalibrationScope:
290
+ raise TypeError("scope must be exact ForecastCalibrationScope")
291
+ self.scope.revalidate()
292
+ for name in (
293
+ "minimum_path_support",
294
+ "minimum_family_support",
295
+ "minimum_model_score_support",
296
+ "model_family_min_support",
297
+ "minimum_empirical_score_support",
298
+ ):
299
+ value = getattr(self, name)
300
+ if type(value) is not int or value <= 0:
301
+ raise ValueError(f"{name} must be a positive exact integer")
302
+ for name in (
303
+ "prior_strength",
304
+ "validity_prior_strength",
305
+ "correctness_prior_alpha",
306
+ "correctness_prior_beta",
307
+ ):
308
+ value = getattr(self, name)
309
+ if type(value) is not float or not math.isfinite(value) or value <= 0.0:
310
+ raise ValueError(f"{name} must be a positive finite float")
311
+ if (
312
+ type(self.maximum_empirical_authority) is not float
313
+ or not 0.0 <= self.maximum_empirical_authority <= 1.0
314
+ ):
315
+ raise ValueError("maximum_empirical_authority must lie in [0,1]")
316
+ if type(self.recency_decay) is not float or not 0.0 < self.recency_decay <= 1.0:
317
+ raise ValueError("recency_decay must lie in (0,1]")
318
+ if self.audit_artifact_store is not None and not isinstance(
319
+ self.audit_artifact_store,
320
+ ArtifactStore,
321
+ ):
322
+ raise TypeError("audit_artifact_store must implement ArtifactStore")
323
+ if (
324
+ type(self.maximum_embedded_action_audits) is not int
325
+ or self.maximum_embedded_action_audits < 0
326
+ ):
327
+ raise ValueError(
328
+ "maximum_embedded_action_audits must be a non-negative exact integer"
329
+ )
330
+
331
+ def _correctness_prior(self) -> BetaCorrectnessPrior:
332
+ return BetaCorrectnessPrior(
333
+ alpha=self.correctness_prior_alpha,
334
+ beta=self.correctness_prior_beta,
335
+ )
336
+
337
+ def _model_projection(
338
+ self,
339
+ *,
340
+ snapshot: ForecastCalibrationSnapshot,
341
+ family: str,
342
+ outcome_metric_id: str,
343
+ raw: ResolvedActionMetricForecast,
344
+ ) -> tuple[ResolvedActionMetricForecast, dict[str, object]]:
345
+ direction = _forecast_direction(raw)
346
+ confidence = _confidence_bin(raw.confidence)
347
+ cell, source = snapshot.lookup(
348
+ metric_id=outcome_metric_id,
349
+ asserted_direction=direction,
350
+ confidence=confidence,
351
+ family=family,
352
+ )
353
+ score_identified = (
354
+ direction is not MetricEffectDirection.UNKNOWN
355
+ and cell.scorable_count >= self.minimum_model_score_support
356
+ )
357
+ signed_skill = (
358
+ 1.0 if not score_identified else (2.0 * cell.posterior_correctness) - 1.0
359
+ )
360
+ p10, p50, p90 = _signed_interval(raw, float(signed_skill))
361
+ projected = ResolvedActionMetricForecast(
362
+ metric_id=raw.metric_id,
363
+ p10_delta=float(p10),
364
+ p50_delta=float(p50),
365
+ p90_delta=float(p90),
366
+ confidence=float(
367
+ raw.confidence
368
+ if not score_identified
369
+ else raw.confidence * abs(signed_skill)
370
+ ),
371
+ citations=raw.citations,
372
+ )
373
+ return projected, {
374
+ "forecast_metric_id": raw.metric_id,
375
+ "outcome_metric_id": outcome_metric_id,
376
+ "direction": direction.value,
377
+ "confidence_bin": confidence.value,
378
+ "calibration_source": source,
379
+ "scorable_count": cell.scorable_count,
380
+ "correct_count": cell.correct_count,
381
+ "posterior_correctness_hex": cell.posterior_correctness.hex(),
382
+ "score_identified": score_identified,
383
+ "signed_skill_hex": signed_skill.hex(),
384
+ "negative_skill_inversion": signed_skill < 0.0,
385
+ "raw": raw.to_record(),
386
+ "projected": projected.to_record(),
387
+ }
388
+
389
+ def _weighted_metric_observations(
390
+ self,
391
+ *,
392
+ actions: tuple[PortfolioActionOutcomeFeedback, ...],
393
+ metric_id: str,
394
+ current_parent_value: float,
395
+ scale: float,
396
+ cutoff_wave_index_exclusive: int,
397
+ ) -> tuple[tuple[PortfolioActionOutcomeFeedback, float, float], ...]:
398
+ observations: list[tuple[PortfolioActionOutcomeFeedback, float, float]] = []
399
+ for action in actions:
400
+ if (
401
+ action.wave_index >= cutoff_wave_index_exclusive
402
+ or action.disposition is not PortfolioMemberDisposition.SCORED
403
+ ):
404
+ continue
405
+ transition = next(
406
+ (
407
+ value
408
+ for value in action.metric_transitions
409
+ if value.metric_id == metric_id
410
+ ),
411
+ None,
412
+ )
413
+ if transition is None:
414
+ continue
415
+ locality = 1.0 / (
416
+ 1.0 + abs(transition.parent_value - current_parent_value) / scale
417
+ )
418
+ age = cutoff_wave_index_exclusive - 1 - action.wave_index
419
+ recency = self.recency_decay ** max(0, age)
420
+ observations.append(
421
+ (
422
+ action,
423
+ transition.child_value - transition.parent_value,
424
+ locality * recency,
425
+ )
426
+ )
427
+ return tuple(observations)
428
+
429
+ def _empirical_rows(
430
+ self,
431
+ *,
432
+ actions: tuple[PortfolioActionOutcomeFeedback, ...],
433
+ changed_paths: tuple[str, ...],
434
+ family: str,
435
+ metric_id: str,
436
+ current_parent_value: float,
437
+ scale: float,
438
+ cutoff_wave_index_exclusive: int,
439
+ ) -> tuple[str, tuple[tuple[float, float], ...], int]:
440
+ observations = self._weighted_metric_observations(
441
+ actions=actions,
442
+ metric_id=metric_id,
443
+ current_parent_value=current_parent_value,
444
+ scale=scale,
445
+ cutoff_wave_index_exclusive=cutoff_wave_index_exclusive,
446
+ )
447
+ path_rows = tuple(
448
+ (delta, weight)
449
+ for action, delta, weight in observations
450
+ if action.changed_paths == changed_paths and action.family == family
451
+ )
452
+ family_rows = tuple(
453
+ (delta, weight)
454
+ for action, delta, weight in observations
455
+ if action.family == family
456
+ )
457
+ if len(path_rows) >= self.minimum_path_support:
458
+ return "exact_path_family", path_rows, len(family_rows)
459
+ if len(family_rows) >= self.minimum_family_support:
460
+ return "family", family_rows, len(family_rows)
461
+ return "model_only", (), len(family_rows)
462
+
463
+ def _empirical_prequential_skill(
464
+ self,
465
+ *,
466
+ actions: tuple[PortfolioActionOutcomeFeedback, ...],
467
+ family: str,
468
+ metric_id: str,
469
+ scale: float,
470
+ ) -> dict[str, object]:
471
+ scorable = 0
472
+ correct = 0
473
+ for target in sorted(
474
+ (value for value in actions if value.family == family),
475
+ key=lambda value: (
476
+ value.wave_index,
477
+ value.request_sha256,
478
+ value.option_id,
479
+ ),
480
+ ):
481
+ transition = next(
482
+ (
483
+ value
484
+ for value in target.metric_transitions
485
+ if value.metric_id == metric_id
486
+ ),
487
+ None,
488
+ )
489
+ if transition is None:
490
+ continue
491
+ _, rows, _ = self._empirical_rows(
492
+ actions=actions,
493
+ changed_paths=target.changed_paths,
494
+ family=target.family,
495
+ metric_id=metric_id,
496
+ current_parent_value=transition.parent_value,
497
+ scale=scale,
498
+ cutoff_wave_index_exclusive=target.wave_index,
499
+ )
500
+ if not rows:
501
+ continue
502
+ median = _weighted_quantile(rows, 0.5)
503
+ predicted = (
504
+ MetricEffectDirection.DECREASE
505
+ if median < 0.0
506
+ else MetricEffectDirection.INCREASE
507
+ if median > 0.0
508
+ else MetricEffectDirection.UNCHANGED
509
+ )
510
+ scorable += 1
511
+ correct += predicted is transition.actual_direction
512
+ prior = self._correctness_prior()
513
+ posterior = (prior.alpha + correct) / (prior.alpha + prior.beta + scorable)
514
+ identified = scorable >= self.minimum_empirical_score_support
515
+ authority_multiplier = (
516
+ 1.0 if not identified else max(0.0, (2.0 * posterior) - 1.0)
517
+ )
518
+ return {
519
+ "scorable_count": scorable,
520
+ "correct_count": correct,
521
+ "posterior_correctness_hex": posterior.hex(),
522
+ "score_identified": identified,
523
+ "authority_multiplier_hex": authority_multiplier.hex(),
524
+ }
525
+
526
+ def _prior_actions(
527
+ self,
528
+ cutoff_wave_index_exclusive: int,
529
+ ) -> tuple[PortfolioActionOutcomeFeedback, ...]:
530
+ return tuple(
531
+ action
532
+ for receipt in self.ledger.receipts
533
+ if receipt.scope == self.scope
534
+ and receipt.wave_index < cutoff_wave_index_exclusive
535
+ for action in receipt.actions
536
+ )
537
+
538
+ def _validity_projection(
539
+ self,
540
+ *,
541
+ actions: tuple[PortfolioActionOutcomeFeedback, ...],
542
+ family: str,
543
+ raw_probability: float,
544
+ ) -> tuple[float, dict[str, object]]:
545
+ members = tuple(value for value in actions if value.family == family)
546
+ if not members:
547
+ return raw_probability, {
548
+ "support_count": 0,
549
+ "empirical_authority_hex": (0.0).hex(),
550
+ "posterior_valid_probability_hex": None,
551
+ }
552
+ valid_count = sum(
553
+ value.disposition is PortfolioMemberDisposition.SCORED for value in members
554
+ )
555
+ posterior = valid_count / len(members)
556
+ authority = min(
557
+ self.maximum_empirical_authority,
558
+ len(members) / (len(members) + self.validity_prior_strength),
559
+ )
560
+ calibrated = (1.0 - authority) * raw_probability + authority * posterior
561
+ return calibrated, {
562
+ "support_count": len(members),
563
+ "valid_count": valid_count,
564
+ "empirical_authority_hex": authority.hex(),
565
+ "posterior_valid_probability_hex": posterior.hex(),
566
+ }
567
+
568
+ def _metric_projection(
569
+ self,
570
+ *,
571
+ actions: tuple[PortfolioActionOutcomeFeedback, ...],
572
+ model_snapshot: ForecastCalibrationSnapshot,
573
+ changed_paths: tuple[str, ...],
574
+ family: str,
575
+ metric_id: str,
576
+ current_parent_value: float,
577
+ scale: float,
578
+ cutoff_wave_index_exclusive: int,
579
+ raw: ResolvedActionMetricForecast,
580
+ ) -> tuple[ResolvedActionMetricForecast, dict[str, object]]:
581
+ model_projected, model_audit = self._model_projection(
582
+ snapshot=model_snapshot,
583
+ family=family,
584
+ outcome_metric_id=metric_id,
585
+ raw=raw,
586
+ )
587
+ stratum, rows, family_support = self._empirical_rows(
588
+ actions=actions,
589
+ changed_paths=changed_paths,
590
+ family=family,
591
+ metric_id=metric_id,
592
+ current_parent_value=current_parent_value,
593
+ scale=scale,
594
+ cutoff_wave_index_exclusive=cutoff_wave_index_exclusive,
595
+ )
596
+ if not rows:
597
+ return model_projected, {
598
+ "metric_id": raw.metric_id,
599
+ "forecast_metric_id": raw.metric_id,
600
+ "outcome_metric_id": metric_id,
601
+ "stratum": stratum,
602
+ "support_count": family_support,
603
+ "effective_support_hex": (0.0).hex(),
604
+ "empirical_authority_hex": (0.0).hex(),
605
+ "model_calibration": model_audit,
606
+ "empirical_prequential_skill": None,
607
+ "raw": raw.to_record(),
608
+ "calibrated": model_projected.to_record(),
609
+ }
610
+
611
+ weights = tuple(weight for _, weight in rows)
612
+ effective = _effective_support(weights)
613
+ support_authority = min(
614
+ self.maximum_empirical_authority,
615
+ effective / (effective + self.prior_strength),
616
+ )
617
+ empirical_skill = self._empirical_prequential_skill(
618
+ actions=actions,
619
+ family=family,
620
+ metric_id=metric_id,
621
+ scale=scale,
622
+ )
623
+ authority_multiplier = float.fromhex(
624
+ str(empirical_skill["authority_multiplier_hex"])
625
+ )
626
+ authority = support_authority * authority_multiplier
627
+ empirical = (
628
+ _weighted_quantile(rows, 0.1),
629
+ _weighted_quantile(rows, 0.5),
630
+ _weighted_quantile(rows, 0.9),
631
+ )
632
+ model_values = (
633
+ model_projected.p10_delta,
634
+ model_projected.p50_delta,
635
+ model_projected.p90_delta,
636
+ )
637
+ calibrated_values = tuple(
638
+ (1.0 - authority) * model_value + authority * empirical_value
639
+ for model_value, empirical_value in zip(
640
+ model_values,
641
+ empirical,
642
+ strict=True,
643
+ )
644
+ )
645
+ empirical_agreement = (
646
+ 1.0
647
+ if model_projected.p50_delta == 0.0 or empirical[1] == 0.0
648
+ else 1.0
649
+ if math.copysign(1.0, model_projected.p50_delta)
650
+ == math.copysign(1.0, empirical[1])
651
+ else 0.0
652
+ )
653
+ empirical_confidence = effective / (effective + self.prior_strength)
654
+ calibrated_confidence = (
655
+ 1.0 - authority
656
+ ) * model_projected.confidence + authority * empirical_confidence * (
657
+ 0.5 + 0.5 * empirical_agreement
658
+ )
659
+ calibrated = ResolvedActionMetricForecast(
660
+ metric_id=raw.metric_id,
661
+ p10_delta=float(calibrated_values[0]),
662
+ p50_delta=float(calibrated_values[1]),
663
+ p90_delta=float(calibrated_values[2]),
664
+ confidence=float(min(1.0, max(0.0, calibrated_confidence))),
665
+ citations=raw.citations,
666
+ )
667
+ return calibrated, {
668
+ "metric_id": raw.metric_id,
669
+ "forecast_metric_id": raw.metric_id,
670
+ "outcome_metric_id": metric_id,
671
+ "stratum": stratum,
672
+ "support_count": len(rows),
673
+ "effective_support_hex": effective.hex(),
674
+ "support_authority_hex": support_authority.hex(),
675
+ "empirical_authority_hex": authority.hex(),
676
+ "empirical_quantiles_hex": [value.hex() for value in empirical],
677
+ "parent_metric_value_hex": current_parent_value.hex(),
678
+ "metric_scale_hex": scale.hex(),
679
+ "model_calibration": model_audit,
680
+ "empirical_prequential_skill": empirical_skill,
681
+ "raw": raw.to_record(),
682
+ "calibrated": calibrated.to_record(),
683
+ }
684
+
685
+ def calibrate(
686
+ self,
687
+ *,
688
+ request: ActionForecastRequest,
689
+ forecasts: ResolvedActionForecastBatch,
690
+ cutoff_wave_index_exclusive: int,
691
+ metric_aliases: tuple[TargetMetricAlias, ...] = (),
692
+ ) -> ActionConsequenceCalibrationResult:
693
+ self.__post_init__()
694
+ if type(request) is not ActionForecastRequest:
695
+ raise TypeError("request must be an exact ActionForecastRequest")
696
+ request.__post_init__()
697
+ if type(forecasts) is not ResolvedActionForecastBatch:
698
+ raise TypeError("forecasts must be an exact resolved batch")
699
+ validate_resolved_action_forecasts(request, forecasts)
700
+ if (
701
+ type(cutoff_wave_index_exclusive) is not int
702
+ or cutoff_wave_index_exclusive <= 0
703
+ ):
704
+ raise ValueError("cutoff_wave_index_exclusive must be positive")
705
+ if type(metric_aliases) is not tuple or any(
706
+ type(value) is not TargetMetricAlias for value in metric_aliases
707
+ ):
708
+ raise TypeError("metric_aliases must contain exact TargetMetricAlias values")
709
+ if metric_aliases:
710
+ for value in metric_aliases:
711
+ value.__post_init__()
712
+ forecast_ids = tuple(value.forecast_metric_id for value in metric_aliases)
713
+ target_ids = tuple(value.target_metric_id for value in metric_aliases)
714
+ if len(set(forecast_ids)) != len(forecast_ids):
715
+ raise ValueError("metric aliases must have unique forecast metric IDs")
716
+ if len(set(target_ids)) != len(target_ids):
717
+ raise ValueError("metric aliases must have unique target metric IDs")
718
+ if set(forecast_ids) != set(request.required_metric_ids):
719
+ raise ValueError(
720
+ "metric aliases must cover the forecast request exactly"
721
+ )
722
+ resolved_aliases = metric_aliases
723
+ else:
724
+ resolved_aliases = tuple(
725
+ TargetMetricAlias(
726
+ target_metric_id=metric_id,
727
+ forecast_metric_id=metric_id,
728
+ )
729
+ for metric_id in request.required_metric_ids
730
+ )
731
+ target_by_forecast = {
732
+ value.forecast_metric_id: value.target_metric_id
733
+ for value in resolved_aliases
734
+ }
735
+
736
+ actions = self._prior_actions(cutoff_wave_index_exclusive)
737
+ model_snapshot = self.ledger.calibration_snapshot(
738
+ scope=self.scope,
739
+ cutoff_wave_index_exclusive=cutoff_wave_index_exclusive,
740
+ prior=self._correctness_prior(),
741
+ family_min_support=self.model_family_min_support,
742
+ )
743
+ paths_by_option = parent_relative_changed_paths_by_option(
744
+ request.finite_variation_contract
745
+ )
746
+ parent_by_metric = {
747
+ value.metric_id: value.value for value in request.parent_metric_values
748
+ }
749
+ scale_by_metric = {
750
+ value.metric_id: value.delta_scale for value in request.metric_scales
751
+ }
752
+ calibrated_forecasts: list[ResolvedActionForecast] = []
753
+ action_audits: list[dict[str, object]] = []
754
+ for forecast in forecasts.forecasts:
755
+ probability_valid, validity_audit = self._validity_projection(
756
+ actions=actions,
757
+ family=forecast.family,
758
+ raw_probability=forecast.probability_valid,
759
+ )
760
+ metrics: list[ResolvedActionMetricForecast] = []
761
+ metric_audits: list[dict[str, object]] = []
762
+ for metric in forecast.metric_forecasts:
763
+ outcome_metric_id = target_by_forecast[metric.metric_id]
764
+ calibrated_metric, metric_audit = self._metric_projection(
765
+ actions=actions,
766
+ model_snapshot=model_snapshot,
767
+ changed_paths=paths_by_option[forecast.option_id],
768
+ family=forecast.family,
769
+ metric_id=outcome_metric_id,
770
+ current_parent_value=parent_by_metric[metric.metric_id],
771
+ scale=scale_by_metric[metric.metric_id],
772
+ cutoff_wave_index_exclusive=cutoff_wave_index_exclusive,
773
+ raw=metric,
774
+ )
775
+ metrics.append(calibrated_metric)
776
+ metric_audits.append(metric_audit)
777
+ calibrated = ResolvedActionForecast(
778
+ option_id=forecast.option_id,
779
+ option_identity_sha256=forecast.option_identity_sha256,
780
+ child_configuration_sha256=forecast.child_configuration_sha256,
781
+ family=forecast.family,
782
+ probability_valid=float(probability_valid),
783
+ metric_forecasts=tuple(metrics),
784
+ )
785
+ calibrated_forecasts.append(calibrated)
786
+ action_audits.append(
787
+ {
788
+ "option_id": forecast.option_id,
789
+ "family": forecast.family,
790
+ "changed_paths": list(paths_by_option[forecast.option_id]),
791
+ "validity": validity_audit,
792
+ "metric_cells": metric_audits,
793
+ }
794
+ )
795
+
796
+ calibrated_batch = ResolvedActionForecastBatch(
797
+ request_sha256=forecasts.request_sha256,
798
+ context_sha256=forecasts.context_sha256,
799
+ optimization_semantics_definition_sha256=(
800
+ forecasts.optimization_semantics_definition_sha256
801
+ ),
802
+ action_semantics_definition_sha256=(
803
+ forecasts.action_semantics_definition_sha256
804
+ ),
805
+ finite_contract_identity_sha256=(forecasts.finite_contract_identity_sha256),
806
+ card_snapshot_sha256=forecasts.card_snapshot_sha256,
807
+ forecasts=tuple(calibrated_forecasts),
808
+ policy_id=EMPIRICAL_CONSEQUENCE_POLICY_ID,
809
+ policy_version=EMPIRICAL_CONSEQUENCE_POLICY_VERSION,
810
+ policy_definition_sha256=(EMPIRICAL_CONSEQUENCE_POLICY_DEFINITION_SHA256),
811
+ )
812
+ validate_resolved_action_forecasts(request, calibrated_batch)
813
+ if len(action_audits) <= self.maximum_embedded_action_audits:
814
+ action_audit_storage: dict[str, object] = {
815
+ "mode": "embedded",
816
+ "action_count": len(action_audits),
817
+ }
818
+ embedded_action_audits: dict[str, object] = {
819
+ "actions": action_audits,
820
+ }
821
+ else:
822
+ if self.audit_artifact_store is None:
823
+ raise RuntimeError(
824
+ "large consequence-calibration audits require an "
825
+ "audit_artifact_store"
826
+ )
827
+ action_artifacts: list[dict[str, object]] = []
828
+ for ordinal, action_audit in enumerate(action_audits, start=1):
829
+ artifact = put_json(
830
+ self.audit_artifact_store,
831
+ {
832
+ "schema_version": 1,
833
+ "artifact_kind": (
834
+ "empirical_consequence_calibration_action_audit"
835
+ ),
836
+ "scope_sha256": self.scope.scope_sha256,
837
+ "cutoff_wave_index_exclusive": (
838
+ cutoff_wave_index_exclusive
839
+ ),
840
+ "source_forecast_receipt_sha256": (
841
+ forecasts.receipt_sha256
842
+ ),
843
+ "action_ordinal": ordinal,
844
+ "action": action_audit,
845
+ },
846
+ )
847
+ action_artifacts.append(
848
+ {
849
+ "option_id": action_audit["option_id"],
850
+ "artifact": _artifact_ref_record(artifact),
851
+ }
852
+ )
853
+ action_audit_storage = {
854
+ "mode": "content_addressed_external",
855
+ "action_count": len(action_audits),
856
+ "artifacts": action_artifacts,
857
+ }
858
+ embedded_action_audits = {}
859
+ audit = _object(
860
+ {
861
+ "schema_version": 2,
862
+ "scope_sha256": self.scope.scope_sha256,
863
+ "cutoff_wave_index_exclusive": cutoff_wave_index_exclusive,
864
+ "eligible_prior_action_count": len(actions),
865
+ "metric_aliases": [
866
+ {
867
+ "target_metric_id": value.target_metric_id,
868
+ "forecast_metric_id": value.forecast_metric_id,
869
+ }
870
+ for value in resolved_aliases
871
+ ],
872
+ "minimum_path_support": self.minimum_path_support,
873
+ "minimum_family_support": self.minimum_family_support,
874
+ "prior_strength_hex": self.prior_strength.hex(),
875
+ "validity_prior_strength_hex": (self.validity_prior_strength.hex()),
876
+ "maximum_empirical_authority_hex": (
877
+ self.maximum_empirical_authority.hex()
878
+ ),
879
+ "recency_decay_hex": self.recency_decay.hex(),
880
+ "minimum_model_score_support": self.minimum_model_score_support,
881
+ "model_family_min_support": self.model_family_min_support,
882
+ "minimum_empirical_score_support": (
883
+ self.minimum_empirical_score_support
884
+ ),
885
+ "correctness_prior": self._correctness_prior().to_record(),
886
+ "model_calibration_snapshot_sha256": model_snapshot.snapshot_sha256,
887
+ "action_audit_storage": action_audit_storage,
888
+ **embedded_action_audits,
889
+ "leakage_guard": "only_feedback_wave_lt_exclusive_cutoff",
890
+ "workload_or_model_branches": False,
891
+ }
892
+ )
893
+ return ActionConsequenceCalibrationResult(
894
+ source_forecast_receipt_sha256=forecasts.receipt_sha256,
895
+ cutoff_wave_index_exclusive=cutoff_wave_index_exclusive,
896
+ forecasts=calibrated_batch,
897
+ audit=audit,
898
+ )
899
+
900
+
901
+ __all__ = [
902
+ "ActionConsequenceCalibrationPolicy",
903
+ "ActionConsequenceCalibrationResult",
904
+ "EMPIRICAL_CONSEQUENCE_POLICY_DEFINITION_SHA256",
905
+ "EMPIRICAL_CONSEQUENCE_POLICY_ID",
906
+ "EMPIRICAL_CONSEQUENCE_POLICY_VERSION",
907
+ "HierarchicalEmpiricalConsequenceCalibrationPolicy",
908
+ ]