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,922 @@
1
+ """Authenticated categorical forecast calibration with prior-only snapshots.
2
+
3
+ Numeric metric changes cross only the benchmark-owned adjudicator seam. The
4
+ persistent policy state is a compact set of signed categorical observations,
5
+ filtered at an exclusive wave cutoff before any allocator can consume it.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import hashlib
11
+ import json
12
+ import math
13
+ import re
14
+ from dataclasses import dataclass, field
15
+ from enum import Enum
16
+ from typing import Protocol, Sequence, runtime_checkable
17
+
18
+ from agent_evolve.domain.patch import require_sha256
19
+ from agent_evolve.ports.agentic_generator import MetricEffectDirection
20
+
21
+
22
+ _SCOPE_DOMAIN = b"agent-evolve:forecast-calibration-scope:v1\x00"
23
+ _PREDICTION_DOMAIN = b"agent-evolve:forecast-prediction-receipt:v1\x00"
24
+ _ADJUDICATION_REQUEST_DOMAIN = (
25
+ b"agent-evolve:meaningful-direction-adjudication-request:v1\x00"
26
+ )
27
+ _ADJUDICATION_DOMAIN = b"agent-evolve:meaningful-direction-adjudication:v1\x00"
28
+ _OBSERVATION_DOMAIN = b"agent-evolve:forecast-calibration-observation:v1\x00"
29
+ _SNAPSHOT_DOMAIN = b"agent-evolve:forecast-calibration-snapshot:v1\x00"
30
+ _TOKEN = re.compile(r"^[a-z][a-z0-9_.-]{0,127}$")
31
+ _METRIC = re.compile(r"^[a-z][a-z0-9_.:-]{0,191}$")
32
+ _OPTION = re.compile(r"^[a-z][a-z0-9_.:-]{0,255}$")
33
+ _MAX_WAVE = (1 << 63) - 1
34
+
35
+
36
+ def _canonical_json(value: object) -> bytes:
37
+ return json.dumps(
38
+ value,
39
+ allow_nan=False,
40
+ ensure_ascii=True,
41
+ separators=(",", ":"),
42
+ sort_keys=True,
43
+ ).encode("ascii", errors="strict")
44
+
45
+
46
+ def _hash(domain: bytes, value: object) -> str:
47
+ return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
48
+
49
+
50
+ def _require_token(value: str, *, name: str) -> None:
51
+ if type(value) is not str or _TOKEN.fullmatch(value) is None:
52
+ raise ValueError(f"{name} must use the closed lowercase token grammar")
53
+
54
+
55
+ def _require_metric(value: str, *, name: str = "metric_id") -> None:
56
+ if type(value) is not str or _METRIC.fullmatch(value) is None:
57
+ raise ValueError(f"{name} must use the closed metric identifier grammar")
58
+
59
+
60
+ def _require_option(value: str, *, name: str = "option_id") -> None:
61
+ if type(value) is not str or _OPTION.fullmatch(value) is None:
62
+ raise ValueError(f"{name} must use the closed option identifier grammar")
63
+
64
+
65
+ def _require_wave(value: int, *, name: str) -> None:
66
+ if type(value) is not int or not 1 <= value <= _MAX_WAVE:
67
+ raise ValueError(f"{name} must be an exact positive int63")
68
+
69
+
70
+ def _require_finite_float(value: float, *, name: str) -> None:
71
+ if type(value) is not float or not math.isfinite(value):
72
+ raise TypeError(f"{name} must be a finite canonical float")
73
+
74
+
75
+ class ForecastConfidenceBin(str, Enum):
76
+ """Closed confidence vocabulary emitted with a direction forecast."""
77
+
78
+ LOW = "low"
79
+ MEDIUM = "medium"
80
+ HIGH = "high"
81
+ UNKNOWN = "unknown"
82
+
83
+
84
+ @dataclass(frozen=True, slots=True)
85
+ class ForecastCalibrationScope:
86
+ """Identity of one local model/prompt/policy/benchmark/session stratum."""
87
+
88
+ model_profile_sha256: str
89
+ prompt_definition_sha256: str
90
+ selector_policy_definition_sha256: str
91
+ benchmark_sha256: str
92
+ session_sha256: str
93
+
94
+ def __post_init__(self) -> None:
95
+ for name in (
96
+ "model_profile_sha256",
97
+ "prompt_definition_sha256",
98
+ "selector_policy_definition_sha256",
99
+ "benchmark_sha256",
100
+ "session_sha256",
101
+ ):
102
+ require_sha256(getattr(self, name), name)
103
+
104
+ def revalidate(self) -> None:
105
+ if type(self) is not ForecastCalibrationScope:
106
+ raise TypeError("scope must be exact ForecastCalibrationScope")
107
+ ForecastCalibrationScope.__post_init__(self)
108
+
109
+ def _unsigned_record(self) -> dict[str, object]:
110
+ self.revalidate()
111
+ return {
112
+ "schema_version": 1,
113
+ "model_profile_sha256": self.model_profile_sha256,
114
+ "prompt_definition_sha256": self.prompt_definition_sha256,
115
+ "selector_policy_definition_sha256": (
116
+ self.selector_policy_definition_sha256
117
+ ),
118
+ "benchmark_sha256": self.benchmark_sha256,
119
+ "session_sha256": self.session_sha256,
120
+ }
121
+
122
+ @property
123
+ def scope_sha256(self) -> str:
124
+ return _hash(_SCOPE_DOMAIN, self._unsigned_record())
125
+
126
+ def for_policy_frame(
127
+ self,
128
+ *,
129
+ prompt_definition_sha256: str,
130
+ selector_policy_definition_sha256: str,
131
+ ) -> "ForecastCalibrationScope":
132
+ """Preserve the experiment stratum while changing policy provenance.
133
+
134
+ One campaign can legitimately contain more than one predictor: for
135
+ example, an engine-owned calibrated slate policy and a runtime
136
+ outcome-conditioned consequence expert. Their observations must not
137
+ share prompt/policy identity, while model, benchmark, and session
138
+ identity must remain exact. This immutable operation makes that
139
+ separation explicit at the generic calibration boundary.
140
+ """
141
+
142
+ self.revalidate()
143
+ return ForecastCalibrationScope(
144
+ model_profile_sha256=self.model_profile_sha256,
145
+ prompt_definition_sha256=prompt_definition_sha256,
146
+ selector_policy_definition_sha256=(
147
+ selector_policy_definition_sha256
148
+ ),
149
+ benchmark_sha256=self.benchmark_sha256,
150
+ session_sha256=self.session_sha256,
151
+ )
152
+
153
+ def to_record(self) -> dict[str, object]:
154
+ return {**self._unsigned_record(), "scope_sha256": self.scope_sha256}
155
+
156
+
157
+ @dataclass(frozen=True, slots=True)
158
+ class BetaCorrectnessPrior:
159
+ """Declared shrinkage prior for sparse categorical correctness cells."""
160
+
161
+ alpha: float = 1.0
162
+ beta: float = 1.0
163
+
164
+ def __post_init__(self) -> None:
165
+ _require_finite_float(self.alpha, name="alpha")
166
+ _require_finite_float(self.beta, name="beta")
167
+ if self.alpha <= 0.0 or self.beta <= 0.0:
168
+ raise ValueError("Beta prior parameters must be strictly positive")
169
+
170
+ @property
171
+ def mean(self) -> float:
172
+ self.__post_init__()
173
+ return self.alpha / (self.alpha + self.beta)
174
+
175
+ def to_record(self) -> dict[str, object]:
176
+ self.__post_init__()
177
+ return {
178
+ "family": "beta_bernoulli_correctness",
179
+ "alpha_hex": self.alpha.hex(),
180
+ "beta_hex": self.beta.hex(),
181
+ "mean_hex": self.mean.hex(),
182
+ }
183
+
184
+
185
+ @dataclass(frozen=True, slots=True)
186
+ class ForecastPredictionReceipt:
187
+ """Authenticated categorical prediction emitted before evaluation."""
188
+
189
+ scope: ForecastCalibrationScope
190
+ wave_index: int
191
+ selector_decision_sha256: str
192
+ parent_candidate_identity_sha256: str
193
+ option_id: str
194
+ option_identity_sha256: str
195
+ family: str
196
+ metric_id: str
197
+ asserted_direction: MetricEffectDirection
198
+ confidence: ForecastConfidenceBin
199
+
200
+ def __post_init__(self) -> None:
201
+ if type(self.scope) is not ForecastCalibrationScope:
202
+ raise TypeError("scope must be exact ForecastCalibrationScope")
203
+ self.scope.revalidate()
204
+ _require_wave(self.wave_index, name="wave_index")
205
+ for name in (
206
+ "selector_decision_sha256",
207
+ "parent_candidate_identity_sha256",
208
+ "option_identity_sha256",
209
+ ):
210
+ require_sha256(getattr(self, name), name)
211
+ _require_option(self.option_id)
212
+ _require_token(self.family, name="family")
213
+ _require_metric(self.metric_id)
214
+ if type(self.asserted_direction) is not MetricEffectDirection:
215
+ raise TypeError("asserted_direction must be exact MetricEffectDirection")
216
+ if type(self.confidence) is not ForecastConfidenceBin:
217
+ raise TypeError("confidence must be exact ForecastConfidenceBin")
218
+
219
+ def revalidate(self) -> None:
220
+ if type(self) is not ForecastPredictionReceipt:
221
+ raise TypeError("prediction must be exact ForecastPredictionReceipt")
222
+ ForecastPredictionReceipt.__post_init__(self)
223
+
224
+ def _unsigned_record(self) -> dict[str, object]:
225
+ self.revalidate()
226
+ return {
227
+ "schema_version": 1,
228
+ "scope_sha256": self.scope.scope_sha256,
229
+ "wave_index": self.wave_index,
230
+ "selector_decision_sha256": self.selector_decision_sha256,
231
+ "parent_candidate_identity_sha256": (self.parent_candidate_identity_sha256),
232
+ "option_id": self.option_id,
233
+ "option_identity_sha256": self.option_identity_sha256,
234
+ "family": self.family,
235
+ "metric_id": self.metric_id,
236
+ "asserted_direction": self.asserted_direction.value,
237
+ "confidence": self.confidence.value,
238
+ }
239
+
240
+ @property
241
+ def receipt_sha256(self) -> str:
242
+ return _hash(_PREDICTION_DOMAIN, self._unsigned_record())
243
+
244
+ def to_record(self) -> dict[str, object]:
245
+ return {**self._unsigned_record(), "receipt_sha256": self.receipt_sha256}
246
+
247
+
248
+ @dataclass(frozen=True, slots=True)
249
+ class MeaningfulDirectionRequest:
250
+ """Numeric request interpreted only by a benchmark-owned adjudicator."""
251
+
252
+ benchmark_sha256: str
253
+ session_sha256: str
254
+ wave_index: int
255
+ parent_candidate_identity_sha256: str
256
+ option_id: str
257
+ option_identity_sha256: str
258
+ metric_id: str
259
+ parent_outcome_sha256: str
260
+ child_outcome_sha256: str
261
+ parent_metric_value: float
262
+ child_metric_value: float
263
+
264
+ def __post_init__(self) -> None:
265
+ for name in (
266
+ "benchmark_sha256",
267
+ "session_sha256",
268
+ "parent_candidate_identity_sha256",
269
+ "option_identity_sha256",
270
+ "parent_outcome_sha256",
271
+ "child_outcome_sha256",
272
+ ):
273
+ require_sha256(getattr(self, name), name)
274
+ _require_wave(self.wave_index, name="wave_index")
275
+ _require_option(self.option_id)
276
+ _require_metric(self.metric_id)
277
+ _require_finite_float(self.parent_metric_value, name="parent_metric_value")
278
+ _require_finite_float(self.child_metric_value, name="child_metric_value")
279
+
280
+ def revalidate(self) -> None:
281
+ if type(self) is not MeaningfulDirectionRequest:
282
+ raise TypeError("request must be exact MeaningfulDirectionRequest")
283
+ MeaningfulDirectionRequest.__post_init__(self)
284
+
285
+ def _record(self) -> dict[str, object]:
286
+ self.revalidate()
287
+ return {
288
+ "schema_version": 1,
289
+ "benchmark_sha256": self.benchmark_sha256,
290
+ "session_sha256": self.session_sha256,
291
+ "wave_index": self.wave_index,
292
+ "parent_candidate_identity_sha256": (self.parent_candidate_identity_sha256),
293
+ "option_id": self.option_id,
294
+ "option_identity_sha256": self.option_identity_sha256,
295
+ "metric_id": self.metric_id,
296
+ "parent_outcome_sha256": self.parent_outcome_sha256,
297
+ "child_outcome_sha256": self.child_outcome_sha256,
298
+ "parent_metric_value_hex": self.parent_metric_value.hex(),
299
+ "child_metric_value_hex": self.child_metric_value.hex(),
300
+ }
301
+
302
+ @property
303
+ def request_sha256(self) -> str:
304
+ return _hash(_ADJUDICATION_REQUEST_DOMAIN, self._record())
305
+
306
+
307
+ @dataclass(frozen=True, slots=True)
308
+ class MeaningfulDirectionAdjudicationReceipt:
309
+ """Categorical benchmark judgment bound to exact parent/child outcomes."""
310
+
311
+ request_sha256: str
312
+ benchmark_sha256: str
313
+ session_sha256: str
314
+ wave_index: int
315
+ parent_candidate_identity_sha256: str
316
+ option_id: str
317
+ option_identity_sha256: str
318
+ metric_id: str
319
+ parent_outcome_sha256: str
320
+ child_outcome_sha256: str
321
+ actual_direction: MetricEffectDirection
322
+ adjudicator_policy_id: str
323
+ adjudicator_policy_version: int
324
+ adjudicator_definition_sha256: str
325
+
326
+ def __post_init__(self) -> None:
327
+ for name in (
328
+ "request_sha256",
329
+ "benchmark_sha256",
330
+ "session_sha256",
331
+ "parent_candidate_identity_sha256",
332
+ "option_identity_sha256",
333
+ "parent_outcome_sha256",
334
+ "child_outcome_sha256",
335
+ "adjudicator_definition_sha256",
336
+ ):
337
+ require_sha256(getattr(self, name), name)
338
+ _require_wave(self.wave_index, name="wave_index")
339
+ _require_option(self.option_id)
340
+ _require_metric(self.metric_id)
341
+ if (
342
+ type(self.actual_direction) is not MetricEffectDirection
343
+ or self.actual_direction is MetricEffectDirection.UNKNOWN
344
+ ):
345
+ raise ValueError("actual_direction must be a known metric direction")
346
+ _require_token(self.adjudicator_policy_id, name="adjudicator_policy_id")
347
+ if (
348
+ type(self.adjudicator_policy_version) is not int
349
+ or self.adjudicator_policy_version <= 0
350
+ ):
351
+ raise ValueError("adjudicator_policy_version must be positive")
352
+
353
+ def revalidate(self) -> None:
354
+ if type(self) is not MeaningfulDirectionAdjudicationReceipt:
355
+ raise TypeError(
356
+ "adjudication must be exact MeaningfulDirectionAdjudicationReceipt"
357
+ )
358
+ MeaningfulDirectionAdjudicationReceipt.__post_init__(self)
359
+
360
+ def _unsigned_record(self) -> dict[str, object]:
361
+ self.revalidate()
362
+ return {
363
+ "schema_version": 1,
364
+ "request_sha256": self.request_sha256,
365
+ "benchmark_sha256": self.benchmark_sha256,
366
+ "session_sha256": self.session_sha256,
367
+ "wave_index": self.wave_index,
368
+ "parent_candidate_identity_sha256": (self.parent_candidate_identity_sha256),
369
+ "option_id": self.option_id,
370
+ "option_identity_sha256": self.option_identity_sha256,
371
+ "metric_id": self.metric_id,
372
+ "parent_outcome_sha256": self.parent_outcome_sha256,
373
+ "child_outcome_sha256": self.child_outcome_sha256,
374
+ "actual_direction": self.actual_direction.value,
375
+ "adjudicator": {
376
+ "policy_id": self.adjudicator_policy_id,
377
+ "policy_version": self.adjudicator_policy_version,
378
+ "definition_sha256": self.adjudicator_definition_sha256,
379
+ },
380
+ }
381
+
382
+ @property
383
+ def receipt_sha256(self) -> str:
384
+ return _hash(_ADJUDICATION_DOMAIN, self._unsigned_record())
385
+
386
+ def to_record(self) -> dict[str, object]:
387
+ return {**self._unsigned_record(), "receipt_sha256": self.receipt_sha256}
388
+
389
+ def require_request(self, request: MeaningfulDirectionRequest) -> None:
390
+ """Authenticate this categorical result against its numeric request."""
391
+
392
+ self.revalidate()
393
+ if type(request) is not MeaningfulDirectionRequest:
394
+ raise TypeError("request must be exact MeaningfulDirectionRequest")
395
+ request.revalidate()
396
+ observed = (
397
+ self.request_sha256,
398
+ self.benchmark_sha256,
399
+ self.session_sha256,
400
+ self.wave_index,
401
+ self.parent_candidate_identity_sha256,
402
+ self.option_id,
403
+ self.option_identity_sha256,
404
+ self.metric_id,
405
+ self.parent_outcome_sha256,
406
+ self.child_outcome_sha256,
407
+ )
408
+ expected = (
409
+ request.request_sha256,
410
+ request.benchmark_sha256,
411
+ request.session_sha256,
412
+ request.wave_index,
413
+ request.parent_candidate_identity_sha256,
414
+ request.option_id,
415
+ request.option_identity_sha256,
416
+ request.metric_id,
417
+ request.parent_outcome_sha256,
418
+ request.child_outcome_sha256,
419
+ )
420
+ if observed != expected:
421
+ raise ValueError("adjudication receipt belongs to a foreign request")
422
+
423
+
424
+ @runtime_checkable
425
+ class MeaningfulMetricDirectionAdjudicator(Protocol):
426
+ """Inverted benchmark seam for meaningful parent/child direction."""
427
+
428
+ policy_id: str
429
+ policy_version: int
430
+ definition_sha256: str
431
+
432
+ def adjudicate(
433
+ self, request: MeaningfulDirectionRequest
434
+ ) -> MeaningfulDirectionAdjudicationReceipt: ...
435
+
436
+
437
+ @dataclass(frozen=True, slots=True)
438
+ class ForecastCalibrationObservation:
439
+ """One pre-evaluation prediction joined to one authenticated outcome fact."""
440
+
441
+ prediction: ForecastPredictionReceipt
442
+ adjudication: MeaningfulDirectionAdjudicationReceipt
443
+
444
+ def __post_init__(self) -> None:
445
+ if type(self.prediction) is not ForecastPredictionReceipt:
446
+ raise TypeError("prediction must be exact ForecastPredictionReceipt")
447
+ if type(self.adjudication) is not MeaningfulDirectionAdjudicationReceipt:
448
+ raise TypeError(
449
+ "adjudication must be exact MeaningfulDirectionAdjudicationReceipt"
450
+ )
451
+ self.prediction.revalidate()
452
+ self.adjudication.revalidate()
453
+ scope = self.prediction.scope
454
+ observed = (
455
+ scope.benchmark_sha256,
456
+ scope.session_sha256,
457
+ self.prediction.wave_index,
458
+ self.prediction.parent_candidate_identity_sha256,
459
+ self.prediction.option_id,
460
+ self.prediction.option_identity_sha256,
461
+ self.prediction.metric_id,
462
+ )
463
+ expected = (
464
+ self.adjudication.benchmark_sha256,
465
+ self.adjudication.session_sha256,
466
+ self.adjudication.wave_index,
467
+ self.adjudication.parent_candidate_identity_sha256,
468
+ self.adjudication.option_id,
469
+ self.adjudication.option_identity_sha256,
470
+ self.adjudication.metric_id,
471
+ )
472
+ if observed != expected:
473
+ raise ValueError("prediction and adjudication evidence do not join")
474
+
475
+ def revalidate(self) -> None:
476
+ if type(self) is not ForecastCalibrationObservation:
477
+ raise TypeError("observation must be exact ForecastCalibrationObservation")
478
+ ForecastCalibrationObservation.__post_init__(self)
479
+
480
+ @property
481
+ def is_abstention(self) -> bool:
482
+ return self.prediction.asserted_direction is MetricEffectDirection.UNKNOWN
483
+
484
+ @property
485
+ def correctness(self) -> bool | None:
486
+ if self.is_abstention:
487
+ return None
488
+ return self.prediction.asserted_direction is self.adjudication.actual_direction
489
+
490
+ def _unsigned_record(self) -> dict[str, object]:
491
+ self.revalidate()
492
+ return {
493
+ "schema_version": 1,
494
+ "prediction_receipt": self.prediction.to_record(),
495
+ "adjudication_receipt": self.adjudication.to_record(),
496
+ "is_abstention": self.is_abstention,
497
+ "correctness": self.correctness,
498
+ }
499
+
500
+ @property
501
+ def observation_sha256(self) -> str:
502
+ return _hash(_OBSERVATION_DOMAIN, self._unsigned_record())
503
+
504
+ def to_record(self) -> dict[str, object]:
505
+ return {
506
+ **self._unsigned_record(),
507
+ "observation_sha256": self.observation_sha256,
508
+ }
509
+
510
+
511
+ def observe_forecast(
512
+ prediction: ForecastPredictionReceipt,
513
+ request: MeaningfulDirectionRequest,
514
+ adjudicator: MeaningfulMetricDirectionAdjudicator,
515
+ ) -> ForecastCalibrationObservation:
516
+ """Run the injected adjudicator and close all prediction/outcome joins."""
517
+
518
+ if type(prediction) is not ForecastPredictionReceipt:
519
+ raise TypeError("prediction must be exact ForecastPredictionReceipt")
520
+ prediction.revalidate()
521
+ if type(request) is not MeaningfulDirectionRequest:
522
+ raise TypeError("request must be exact MeaningfulDirectionRequest")
523
+ request.revalidate()
524
+ if not isinstance(adjudicator, MeaningfulMetricDirectionAdjudicator):
525
+ raise TypeError("adjudicator must implement the direction adjudicator port")
526
+ _require_token(adjudicator.policy_id, name="adjudicator.policy_id")
527
+ if type(adjudicator.policy_version) is not int or adjudicator.policy_version <= 0:
528
+ raise ValueError("adjudicator.policy_version must be positive")
529
+ require_sha256(adjudicator.definition_sha256, "adjudicator.definition_sha256")
530
+ receipt = adjudicator.adjudicate(request)
531
+ if type(receipt) is not MeaningfulDirectionAdjudicationReceipt:
532
+ raise TypeError("adjudicator returned a foreign receipt type")
533
+ receipt.require_request(request)
534
+ if (
535
+ receipt.adjudicator_policy_id != adjudicator.policy_id
536
+ or receipt.adjudicator_policy_version != adjudicator.policy_version
537
+ or receipt.adjudicator_definition_sha256 != adjudicator.definition_sha256
538
+ ):
539
+ raise ValueError("adjudicator receipt uses a foreign policy identity")
540
+ return ForecastCalibrationObservation(prediction, receipt)
541
+
542
+
543
+ @dataclass(frozen=True, slots=True)
544
+ class ForecastCalibrationCell:
545
+ """One empirical/Beta-smoothed categorical correctness cell."""
546
+
547
+ metric_id: str
548
+ asserted_direction: MetricEffectDirection
549
+ confidence: ForecastConfidenceBin
550
+ family: str | None
551
+ observation_count: int
552
+ scorable_count: int
553
+ correct_count: int
554
+ prior: BetaCorrectnessPrior
555
+
556
+ def __post_init__(self) -> None:
557
+ _require_metric(self.metric_id)
558
+ if type(self.asserted_direction) is not MetricEffectDirection:
559
+ raise TypeError("asserted_direction must be exact MetricEffectDirection")
560
+ if type(self.confidence) is not ForecastConfidenceBin:
561
+ raise TypeError("confidence must be exact ForecastConfidenceBin")
562
+ if self.family is not None:
563
+ _require_token(self.family, name="family")
564
+ for name in ("observation_count", "scorable_count", "correct_count"):
565
+ if type(getattr(self, name)) is not int or getattr(self, name) < 0:
566
+ raise ValueError(f"{name} must be a non-negative exact integer")
567
+ if not self.correct_count <= self.scorable_count <= self.observation_count:
568
+ raise ValueError("calibration cell counts are inconsistent")
569
+ if type(self.prior) is not BetaCorrectnessPrior:
570
+ raise TypeError("prior must be exact BetaCorrectnessPrior")
571
+ self.prior.__post_init__()
572
+ if (
573
+ self.asserted_direction is MetricEffectDirection.UNKNOWN
574
+ and self.scorable_count != 0
575
+ ):
576
+ raise ValueError("unknown-direction observations must be abstentions")
577
+
578
+ @property
579
+ def empirical_accuracy(self) -> float | None:
580
+ self.__post_init__()
581
+ if self.scorable_count == 0:
582
+ return None
583
+ return self.correct_count / self.scorable_count
584
+
585
+ @property
586
+ def posterior_correctness(self) -> float:
587
+ self.__post_init__()
588
+ return (self.prior.alpha + self.correct_count) / (
589
+ self.prior.alpha + self.prior.beta + self.scorable_count
590
+ )
591
+
592
+ def to_record(self) -> dict[str, object]:
593
+ self.__post_init__()
594
+ empirical = self.empirical_accuracy
595
+ return {
596
+ "metric_id": self.metric_id,
597
+ "asserted_direction": self.asserted_direction.value,
598
+ "confidence": self.confidence.value,
599
+ "family": self.family,
600
+ "observation_count": self.observation_count,
601
+ "scorable_count": self.scorable_count,
602
+ "correct_count": self.correct_count,
603
+ "empirical_accuracy_hex": (None if empirical is None else empirical.hex()),
604
+ "posterior_correctness_hex": self.posterior_correctness.hex(),
605
+ "prior": self.prior.to_record(),
606
+ }
607
+
608
+
609
+ def _observation_key(
610
+ observation: ForecastCalibrationObservation,
611
+ ) -> tuple[int, str, str, str]:
612
+ prediction = observation.prediction
613
+ return (
614
+ prediction.wave_index,
615
+ prediction.selector_decision_sha256,
616
+ prediction.option_id,
617
+ prediction.metric_id,
618
+ )
619
+
620
+
621
+ def _cell_key(
622
+ cell: ForecastCalibrationCell,
623
+ ) -> tuple[str, str, str, str]:
624
+ return (
625
+ cell.metric_id,
626
+ cell.asserted_direction.value,
627
+ cell.confidence.value,
628
+ "" if cell.family is None else cell.family,
629
+ )
630
+
631
+
632
+ def _build_cell(
633
+ observations: tuple[ForecastCalibrationObservation, ...],
634
+ *,
635
+ metric_id: str,
636
+ direction: MetricEffectDirection,
637
+ confidence: ForecastConfidenceBin,
638
+ family: str | None,
639
+ prior: BetaCorrectnessPrior,
640
+ ) -> ForecastCalibrationCell:
641
+ members = tuple(
642
+ observation
643
+ for observation in observations
644
+ if observation.prediction.metric_id == metric_id
645
+ and observation.prediction.asserted_direction is direction
646
+ and observation.prediction.confidence is confidence
647
+ and (family is None or observation.prediction.family == family)
648
+ )
649
+ scorable = tuple(value for value in members if value.correctness is not None)
650
+ return ForecastCalibrationCell(
651
+ metric_id=metric_id,
652
+ asserted_direction=direction,
653
+ confidence=confidence,
654
+ family=family,
655
+ observation_count=len(members),
656
+ scorable_count=len(scorable),
657
+ correct_count=sum(value.correctness is True for value in scorable),
658
+ prior=prior,
659
+ )
660
+
661
+
662
+ @dataclass(frozen=True, slots=True, eq=False)
663
+ class ForecastCalibrationSnapshot:
664
+ """Immutable calibration evidence available strictly before a wave."""
665
+
666
+ scope: ForecastCalibrationScope
667
+ cutoff_wave_index_exclusive: int
668
+ observations: tuple[ForecastCalibrationObservation, ...]
669
+ prior: BetaCorrectnessPrior = field(default_factory=BetaCorrectnessPrior)
670
+ family_min_support: int = 4
671
+
672
+ def __post_init__(self) -> None:
673
+ if type(self.scope) is not ForecastCalibrationScope:
674
+ raise TypeError("scope must be exact ForecastCalibrationScope")
675
+ self.scope.revalidate()
676
+ _require_wave(
677
+ self.cutoff_wave_index_exclusive,
678
+ name="cutoff_wave_index_exclusive",
679
+ )
680
+ if type(self.observations) is not tuple or any(
681
+ type(value) is not ForecastCalibrationObservation
682
+ for value in self.observations
683
+ ):
684
+ raise TypeError("observations must contain exact calibration observations")
685
+ for value in self.observations:
686
+ value.revalidate()
687
+ if self.observations != tuple(sorted(self.observations, key=_observation_key)):
688
+ raise ValueError("observations must use canonical evidence order")
689
+ semantic_keys = tuple(_observation_key(value) for value in self.observations)
690
+ if len(set(semantic_keys)) != len(semantic_keys):
691
+ raise ValueError("snapshot contains duplicate forecast cells")
692
+ if any(value.prediction.scope != self.scope for value in self.observations):
693
+ raise ValueError("snapshot contains a foreign calibration scope")
694
+ if any(
695
+ value.prediction.wave_index >= self.cutoff_wave_index_exclusive
696
+ for value in self.observations
697
+ ):
698
+ raise ValueError("snapshot contains current/future-wave outcome evidence")
699
+ if type(self.prior) is not BetaCorrectnessPrior:
700
+ raise TypeError("prior must be exact BetaCorrectnessPrior")
701
+ self.prior.__post_init__()
702
+ if type(self.family_min_support) is not int or self.family_min_support <= 0:
703
+ raise ValueError("family_min_support must be a positive exact integer")
704
+
705
+ def revalidate(self) -> None:
706
+ if type(self) is not ForecastCalibrationSnapshot:
707
+ raise TypeError("snapshot must be exact ForecastCalibrationSnapshot")
708
+ ForecastCalibrationSnapshot.__post_init__(self)
709
+
710
+ @property
711
+ def cells(self) -> tuple[ForecastCalibrationCell, ...]:
712
+ self.revalidate()
713
+ global_keys = sorted(
714
+ {
715
+ (
716
+ value.prediction.metric_id,
717
+ value.prediction.asserted_direction,
718
+ value.prediction.confidence,
719
+ )
720
+ for value in self.observations
721
+ },
722
+ key=lambda value: (value[0], value[1].value, value[2].value),
723
+ )
724
+ result = [
725
+ _build_cell(
726
+ self.observations,
727
+ metric_id=metric_id,
728
+ direction=direction,
729
+ confidence=confidence,
730
+ family=None,
731
+ prior=self.prior,
732
+ )
733
+ for metric_id, direction, confidence in global_keys
734
+ ]
735
+ family_keys = sorted(
736
+ {
737
+ (
738
+ value.prediction.metric_id,
739
+ value.prediction.asserted_direction,
740
+ value.prediction.confidence,
741
+ value.prediction.family,
742
+ )
743
+ for value in self.observations
744
+ },
745
+ key=lambda value: (value[0], value[1].value, value[2].value, value[3]),
746
+ )
747
+ for metric_id, direction, confidence, family in family_keys:
748
+ cell = _build_cell(
749
+ self.observations,
750
+ metric_id=metric_id,
751
+ direction=direction,
752
+ confidence=confidence,
753
+ family=family,
754
+ prior=self.prior,
755
+ )
756
+ if cell.scorable_count >= self.family_min_support:
757
+ result.append(cell)
758
+ return tuple(sorted(result, key=_cell_key))
759
+
760
+ @property
761
+ def observation_count(self) -> int:
762
+ return len(self.observations)
763
+
764
+ @property
765
+ def abstention_count(self) -> int:
766
+ return sum(value.is_abstention for value in self.observations)
767
+
768
+ @property
769
+ def scorable_count(self) -> int:
770
+ return self.observation_count - self.abstention_count
771
+
772
+ @property
773
+ def correct_count(self) -> int:
774
+ return sum(value.correctness is True for value in self.observations)
775
+
776
+ @property
777
+ def empirical_accuracy(self) -> float | None:
778
+ if self.scorable_count == 0:
779
+ return None
780
+ return self.correct_count / self.scorable_count
781
+
782
+ def lookup(
783
+ self,
784
+ *,
785
+ metric_id: str,
786
+ asserted_direction: MetricEffectDirection,
787
+ confidence: ForecastConfidenceBin,
788
+ family: str,
789
+ ) -> tuple[ForecastCalibrationCell, str]:
790
+ """Use supported family evidence, then metric-global evidence, then prior."""
791
+
792
+ self.revalidate()
793
+ _require_metric(metric_id)
794
+ if type(asserted_direction) is not MetricEffectDirection:
795
+ raise TypeError("asserted_direction must be exact MetricEffectDirection")
796
+ if type(confidence) is not ForecastConfidenceBin:
797
+ raise TypeError("confidence must be exact ForecastConfidenceBin")
798
+ _require_token(family, name="family")
799
+ for cell in self.cells:
800
+ if (
801
+ cell.metric_id == metric_id
802
+ and cell.asserted_direction is asserted_direction
803
+ and cell.confidence is confidence
804
+ and cell.family == family
805
+ ):
806
+ return cell, "supported_family"
807
+ for cell in self.cells:
808
+ if (
809
+ cell.metric_id == metric_id
810
+ and cell.asserted_direction is asserted_direction
811
+ and cell.confidence is confidence
812
+ and cell.family is None
813
+ ):
814
+ return cell, "metric_direction_confidence"
815
+ return (
816
+ ForecastCalibrationCell(
817
+ metric_id=metric_id,
818
+ asserted_direction=asserted_direction,
819
+ confidence=confidence,
820
+ family=None,
821
+ observation_count=0,
822
+ scorable_count=0,
823
+ correct_count=0,
824
+ prior=self.prior,
825
+ ),
826
+ "declared_prior",
827
+ )
828
+
829
+ def _unsigned_record(self) -> dict[str, object]:
830
+ self.revalidate()
831
+ accuracy = self.empirical_accuracy
832
+ return {
833
+ "schema_version": 1,
834
+ "scope": self.scope.to_record(),
835
+ "cutoff_wave_index_exclusive": self.cutoff_wave_index_exclusive,
836
+ "prior": self.prior.to_record(),
837
+ "family_min_support": self.family_min_support,
838
+ "observations": [value.to_record() for value in self.observations],
839
+ "cells": [value.to_record() for value in self.cells],
840
+ "summary": {
841
+ "observation_count": self.observation_count,
842
+ "abstention_count": self.abstention_count,
843
+ "scorable_count": self.scorable_count,
844
+ "correct_count": self.correct_count,
845
+ "empirical_accuracy_hex": (
846
+ None if accuracy is None else accuracy.hex()
847
+ ),
848
+ },
849
+ "leakage_guard": "only_observation_wave_lt_exclusive_cutoff",
850
+ }
851
+
852
+ @property
853
+ def snapshot_sha256(self) -> str:
854
+ return _hash(_SNAPSHOT_DOMAIN, self._unsigned_record())
855
+
856
+ def to_record(self) -> dict[str, object]:
857
+ return {**self._unsigned_record(), "snapshot_sha256": self.snapshot_sha256}
858
+
859
+ def __eq__(self, other: object) -> bool:
860
+ return (
861
+ type(other) is ForecastCalibrationSnapshot
862
+ and self.snapshot_sha256 == other.snapshot_sha256
863
+ )
864
+
865
+ __hash__ = None
866
+
867
+
868
+ def build_calibration_snapshot(
869
+ observations: Sequence[ForecastCalibrationObservation],
870
+ *,
871
+ scope: ForecastCalibrationScope,
872
+ cutoff_wave_index_exclusive: int,
873
+ prior: BetaCorrectnessPrior = BetaCorrectnessPrior(),
874
+ family_min_support: int = 4,
875
+ ) -> ForecastCalibrationSnapshot:
876
+ """Filter an immutable multi-scope ledger at an exclusive wave cutoff."""
877
+
878
+ if isinstance(observations, (str, bytes)):
879
+ raise TypeError("observations must be a finite observation sequence")
880
+ if type(scope) is not ForecastCalibrationScope:
881
+ raise TypeError("scope must be exact ForecastCalibrationScope")
882
+ scope.revalidate()
883
+ _require_wave(
884
+ cutoff_wave_index_exclusive,
885
+ name="cutoff_wave_index_exclusive",
886
+ )
887
+ admitted: list[ForecastCalibrationObservation] = []
888
+ seen: set[str] = set()
889
+ for value in observations:
890
+ if type(value) is not ForecastCalibrationObservation:
891
+ raise TypeError("ledger contains a foreign observation type")
892
+ value.revalidate()
893
+ if value.observation_sha256 in seen:
894
+ raise ValueError("ledger contains a duplicate observation receipt")
895
+ seen.add(value.observation_sha256)
896
+ if (
897
+ value.prediction.scope == scope
898
+ and value.prediction.wave_index < cutoff_wave_index_exclusive
899
+ ):
900
+ admitted.append(value)
901
+ return ForecastCalibrationSnapshot(
902
+ scope=scope,
903
+ cutoff_wave_index_exclusive=cutoff_wave_index_exclusive,
904
+ observations=tuple(sorted(admitted, key=_observation_key)),
905
+ prior=prior,
906
+ family_min_support=family_min_support,
907
+ )
908
+
909
+
910
+ __all__ = [
911
+ "BetaCorrectnessPrior",
912
+ "ForecastCalibrationObservation",
913
+ "ForecastCalibrationScope",
914
+ "ForecastCalibrationSnapshot",
915
+ "ForecastConfidenceBin",
916
+ "ForecastPredictionReceipt",
917
+ "MeaningfulDirectionAdjudicationReceipt",
918
+ "MeaningfulDirectionRequest",
919
+ "MeaningfulMetricDirectionAdjudicator",
920
+ "build_calibration_snapshot",
921
+ "observe_forecast",
922
+ ]