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,1471 @@
1
+ """Generic bounded partitioning and reassembly for all-action forecasts.
2
+
3
+ The application layer owns global coverage, bounded concurrency, deterministic
4
+ reassembly, and health diagnostics. Provider integrations only implement the
5
+ single-block port and never own option or metric identities.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ import asyncio
11
+ import hashlib
12
+ import json
13
+ import math
14
+ import re
15
+ from collections import Counter
16
+ from dataclasses import dataclass
17
+ from enum import Enum
18
+ from typing import Protocol, runtime_checkable
19
+
20
+ from agent_evolve.domain.ids import LLMCallId
21
+ from agent_evolve.domain.patch import require_sha256
22
+ from agent_evolve.ports.action_forecast import (
23
+ ActionEvidenceCitation,
24
+ ActionForecastBlockPolicy,
25
+ ActionForecastBlockRequest,
26
+ ActionForecastBlockResult,
27
+ ActionForecastBlockSpec,
28
+ ActionForecastDraft,
29
+ ActionForecastPartitionLayout,
30
+ ActionForecastPartitionPolicyBinding,
31
+ ActionForecastRequest,
32
+ ActionMetricForecast,
33
+ ResolvedActionForecast,
34
+ ResolvedActionForecastBatch,
35
+ ResolvedActionForecastBlock,
36
+ resolve_action_forecasts,
37
+ validate_action_forecast_partition_layout,
38
+ validate_resolved_action_forecast_block,
39
+ validate_resolved_action_forecasts,
40
+ )
41
+
42
+
43
+ _TOKEN = re.compile(r"^[a-z][a-z0-9_.-]{0,95}$")
44
+ _BLOCK_CALL_ID_DOMAIN = b"agent-evolve:action-forecast-block-call-id:v1\x00"
45
+ _PARTITIONED_RESULT_DOMAIN = b"agent-evolve:partitioned-action-forecast-result:v1\x00"
46
+ _HEALTH_POLICY_DOMAIN = b"agent-evolve:action-forecast-health-policy:v1\x00"
47
+ _METRIC_HEALTH_DOMAIN = b"agent-evolve:action-forecast-metric-health:v2\x00"
48
+ _HEALTH_ASSESSMENT_DOMAIN = b"agent-evolve:action-forecast-health-assessment:v4\x00"
49
+ _HEALTH_SUBSET_POLICY_DOMAIN = (
50
+ b"agent-evolve:action-forecast-health-subset-policy:v1\x00"
51
+ )
52
+ _HEALTH_BLOCK_SUBSET_DOMAIN = b"agent-evolve:action-forecast-health-block-subset:v1\x00"
53
+
54
+ LENIENT_ACTION_FORECAST_HEALTH_POLICY_ID = "lenient_normalized_forecast_health"
55
+ LENIENT_ACTION_FORECAST_HEALTH_V2_POLICY_ID = (
56
+ LENIENT_ACTION_FORECAST_HEALTH_POLICY_ID
57
+ )
58
+ LENIENT_ACTION_FORECAST_HEALTH_V2_POLICY_VERSION = 2
59
+ LENIENT_ACTION_FORECAST_HEALTH_V2_POLICY_DEFINITION_SHA256 = hashlib.sha256(
60
+ b"agent-evolve:lenient-normalized-forecast-health:v2;"
61
+ b"minimum_rows=8;extreme_abs_normalized_median=32;"
62
+ b"collapse_share_threshold=0.95;minimum_distinct_signatures=2"
63
+ ).hexdigest()
64
+ LENIENT_ACTION_FORECAST_HEALTH_POLICY_VERSION = 3
65
+ LENIENT_ACTION_FORECAST_HEALTH_POLICY_DEFINITION_SHA256 = hashlib.sha256(
66
+ b"agent-evolve:lenient-normalized-forecast-health:v3;"
67
+ b"minimum_rows=8;extreme_abs_normalized_median=32;"
68
+ b"collapse_share_threshold=0.95;minimum_distinct_signatures=2;"
69
+ b"unit_confidence_share_below_collapse_threshold=true"
70
+ ).hexdigest()
71
+
72
+
73
+ def _canonical_json(value: object) -> bytes:
74
+ return json.dumps(
75
+ value,
76
+ allow_nan=False,
77
+ ensure_ascii=True,
78
+ separators=(",", ":"),
79
+ sort_keys=True,
80
+ ).encode("ascii")
81
+
82
+
83
+ def _hash(domain: bytes, value: object) -> str:
84
+ return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
85
+
86
+
87
+ def _finite_float(value: object, name: str) -> float:
88
+ if type(value) is not float or not math.isfinite(value):
89
+ raise TypeError(f"{name} must be a finite canonical float")
90
+ return value
91
+
92
+
93
+ def build_action_forecast_partition_layout(
94
+ request: ActionForecastRequest,
95
+ partition_policy: ActionForecastPartitionPolicyBinding,
96
+ ) -> ActionForecastPartitionLayout:
97
+ """Create the unique maximal contiguous partition under two hard bounds."""
98
+
99
+ if type(request) is not ActionForecastRequest:
100
+ raise TypeError("request must be an exact ActionForecastRequest")
101
+ request.__post_init__()
102
+ if type(partition_policy) is not ActionForecastPartitionPolicyBinding:
103
+ raise TypeError(
104
+ "partition_policy must be an exact partition-policy binding"
105
+ )
106
+ partition_policy.__post_init__()
107
+ metric_count = len(request.required_metric_ids)
108
+ cell_bounded_rows = partition_policy.max_metric_cells_per_block // metric_count
109
+ rows_per_block = min(
110
+ partition_policy.max_rows_per_block,
111
+ cell_bounded_rows,
112
+ )
113
+ if rows_per_block < 1:
114
+ raise ValueError(
115
+ "max_metric_cells_per_block cannot hold one complete metric row"
116
+ )
117
+ options = request.finite_variation_contract.options
118
+ option_identities = tuple(option.identity_sha256 for option in options)
119
+ blocks = tuple(
120
+ ActionForecastBlockSpec(
121
+ block_index=block_index,
122
+ global_row_start=start,
123
+ global_row_stop=min(start + rows_per_block, len(options)),
124
+ option_identity_sha256s=option_identities[
125
+ start : min(start + rows_per_block, len(options))
126
+ ],
127
+ )
128
+ for block_index, start in enumerate(range(0, len(options), rows_per_block))
129
+ )
130
+ layout = ActionForecastPartitionLayout(
131
+ finite_contract_identity_sha256=(
132
+ request.finite_variation_contract.identity_sha256
133
+ ),
134
+ option_identity_sha256s=option_identities,
135
+ metric_ids=request.required_metric_ids,
136
+ partition_policy=partition_policy,
137
+ blocks=blocks,
138
+ )
139
+ validate_action_forecast_partition_layout(request, layout)
140
+ return layout
141
+
142
+
143
+ def action_forecast_block_call_id(
144
+ request: ActionForecastRequest,
145
+ layout: ActionForecastPartitionLayout,
146
+ block: ActionForecastBlockSpec,
147
+ ) -> LLMCallId:
148
+ """Derive an opaque stable physical-call identity from sealed receipts."""
149
+
150
+ if type(request) is not ActionForecastRequest:
151
+ raise TypeError("request must be an exact ActionForecastRequest")
152
+ request.__post_init__()
153
+ validate_action_forecast_partition_layout(request, layout)
154
+ if type(block) is not ActionForecastBlockSpec:
155
+ raise TypeError("block must be an exact ActionForecastBlockSpec")
156
+ block.__post_init__()
157
+ if block.block_index >= layout.block_count or (
158
+ block != layout.blocks[block.block_index]
159
+ ):
160
+ raise ValueError("block differs from its exact partition-layout position")
161
+ digest = _hash(
162
+ _BLOCK_CALL_ID_DOMAIN,
163
+ {
164
+ "request_sha256": request.request_sha256,
165
+ "layout_sha256": layout.layout_sha256,
166
+ "block_spec_sha256": block.block_spec_sha256,
167
+ },
168
+ )
169
+ return LLMCallId(
170
+ f"call_action_forecast_block_{block.block_index:06d}_{digest[:32]}"
171
+ )
172
+
173
+
174
+ def build_action_forecast_block_requests(
175
+ request: ActionForecastRequest,
176
+ layout: ActionForecastPartitionLayout,
177
+ ) -> tuple[ActionForecastBlockRequest, ...]:
178
+ """Materialize canonical block requests without dispatching provider work."""
179
+
180
+ validate_action_forecast_partition_layout(request, layout)
181
+ return tuple(
182
+ ActionForecastBlockRequest(
183
+ request=request,
184
+ layout=layout,
185
+ block=block,
186
+ block_call_id=action_forecast_block_call_id(request, layout, block),
187
+ )
188
+ for block in layout.blocks
189
+ )
190
+
191
+
192
+ def _draft_from_resolved(value: ResolvedActionForecast) -> ActionForecastDraft:
193
+ value.__post_init__()
194
+ return ActionForecastDraft(
195
+ option_id=value.option_id,
196
+ probability_valid=value.probability_valid,
197
+ metric_forecasts=tuple(
198
+ ActionMetricForecast(
199
+ metric_id=metric.metric_id,
200
+ p10_delta=metric.p10_delta,
201
+ p50_delta=metric.p50_delta,
202
+ p90_delta=metric.p90_delta,
203
+ confidence=metric.confidence,
204
+ citations=tuple(
205
+ ActionEvidenceCitation(
206
+ card_key=citation.card_key,
207
+ action_binding_identity_sha256=(
208
+ citation.action_binding_identity_sha256
209
+ ),
210
+ )
211
+ for citation in metric.citations
212
+ ),
213
+ )
214
+ for metric in value.metric_forecasts
215
+ ),
216
+ )
217
+
218
+
219
+ @dataclass(frozen=True, slots=True, eq=False)
220
+ class PartitionedActionForecastResult:
221
+ """Complete batch plus canonical physical-block provenance.
222
+
223
+ Telemetry remains available on ``block_results`` but is deliberately not
224
+ part of this scientific forecast receipt. The receipt binds the resolved
225
+ content and every physical block receipt in canonical global order.
226
+ """
227
+
228
+ request_sha256: str
229
+ layout: ActionForecastPartitionLayout
230
+ block_results: tuple[ActionForecastBlockResult, ...]
231
+ forecasts: ResolvedActionForecastBatch
232
+
233
+ def __post_init__(self) -> None:
234
+ require_sha256(self.request_sha256, "request_sha256")
235
+ if type(self.layout) is not ActionForecastPartitionLayout:
236
+ raise TypeError("layout must be an exact ActionForecastPartitionLayout")
237
+ self.layout.__post_init__()
238
+ if type(self.block_results) is not tuple or not self.block_results or any(
239
+ type(value) is not ActionForecastBlockResult
240
+ for value in self.block_results
241
+ ):
242
+ raise ValueError(
243
+ "block_results must be a non-empty exact tuple of block results"
244
+ )
245
+ for value in self.block_results:
246
+ value.__post_init__()
247
+ indices = tuple(value.forecasts.block_index for value in self.block_results)
248
+ if indices != tuple(range(len(self.block_results))):
249
+ raise ValueError("block_results must use canonical complete block order")
250
+ if len(self.block_results) != self.layout.block_count:
251
+ raise ValueError("block_results must completely cover the layout")
252
+ if type(self.forecasts) is not ResolvedActionForecastBatch:
253
+ raise TypeError("forecasts must be an exact ResolvedActionForecastBatch")
254
+ self.forecasts.__post_init__()
255
+ if self.forecasts.request_sha256 != self.request_sha256:
256
+ raise ValueError("assembled forecasts differ from the partition request")
257
+ if (
258
+ self.forecasts.finite_contract_identity_sha256
259
+ != self.layout.finite_contract_identity_sha256
260
+ ):
261
+ raise ValueError("assembled forecasts differ from the partition contract")
262
+ policy_identity = (
263
+ self.forecasts.policy_id,
264
+ self.forecasts.policy_version,
265
+ self.forecasts.policy_definition_sha256,
266
+ )
267
+ for block_spec, result in zip(
268
+ self.layout.blocks,
269
+ self.block_results,
270
+ strict=True,
271
+ ):
272
+ block = result.forecasts
273
+ if block.request_sha256 != self.request_sha256:
274
+ raise ValueError("a block differs from the partition request")
275
+ if block.layout_sha256 != self.layout.layout_sha256:
276
+ raise ValueError("a block differs from the partition layout")
277
+ if block.block_spec_sha256 != block_spec.block_spec_sha256:
278
+ raise ValueError("a block differs from its partition-layout position")
279
+ if (
280
+ block.policy_id,
281
+ block.policy_version,
282
+ block.policy_definition_sha256,
283
+ ) != policy_identity:
284
+ raise ValueError("a block differs from the assembled policy")
285
+ flattened_ids = tuple(
286
+ forecast.option_id
287
+ for result in self.block_results
288
+ for forecast in result.forecasts.forecasts
289
+ )
290
+ if flattened_ids != tuple(
291
+ forecast.option_id for forecast in self.forecasts.forecasts
292
+ ):
293
+ raise ValueError("assembled option order differs from canonical blocks")
294
+ for forecast in self.forecasts.forecasts:
295
+ if tuple(
296
+ metric.metric_id for metric in forecast.metric_forecasts
297
+ ) != self.layout.metric_ids:
298
+ raise ValueError("assembled metrics differ from the partition layout")
299
+
300
+ @property
301
+ def layout_sha256(self) -> str:
302
+ return self.layout.layout_sha256
303
+
304
+ def _unsigned_record(self) -> dict[str, object]:
305
+ self.__post_init__()
306
+ return {
307
+ "schema_version": 1,
308
+ "request_sha256": self.request_sha256,
309
+ "layout_sha256": self.layout.layout_sha256,
310
+ "block_receipt_sha256s": [
311
+ value.forecasts.receipt_sha256 for value in self.block_results
312
+ ],
313
+ "resolved_batch_receipt_sha256": self.forecasts.receipt_sha256,
314
+ }
315
+
316
+ @property
317
+ def receipt_sha256(self) -> str:
318
+ return _hash(_PARTITIONED_RESULT_DOMAIN, self._unsigned_record())
319
+
320
+ def to_record(self) -> dict[str, object]:
321
+ return {**self._unsigned_record(), "receipt_sha256": self.receipt_sha256}
322
+
323
+ def __eq__(self, other: object) -> bool:
324
+ return (
325
+ type(self) is PartitionedActionForecastResult
326
+ and type(other) is PartitionedActionForecastResult
327
+ and self.receipt_sha256 == other.receipt_sha256
328
+ )
329
+
330
+ __hash__ = None
331
+
332
+
333
+ def assemble_partitioned_action_forecasts(
334
+ request: ActionForecastRequest,
335
+ layout: ActionForecastPartitionLayout,
336
+ block_results: tuple[ActionForecastBlockResult, ...],
337
+ ) -> PartitionedActionForecastResult:
338
+ """Validate and deterministically reassemble all blocks or publish nothing."""
339
+
340
+ validate_action_forecast_partition_layout(request, layout)
341
+ if type(block_results) is not tuple or any(
342
+ type(value) is not ActionForecastBlockResult for value in block_results
343
+ ):
344
+ raise TypeError(
345
+ "block_results must be an exact tuple of ActionForecastBlockResult"
346
+ )
347
+ if len(block_results) != layout.block_count:
348
+ raise ValueError("block results do not completely cover the partition layout")
349
+ for value in block_results:
350
+ value.__post_init__()
351
+ by_index: dict[int, ActionForecastBlockResult] = {}
352
+ for value in block_results:
353
+ index = value.forecasts.block_index
354
+ if index in by_index:
355
+ raise ValueError("block results repeat a partition block")
356
+ by_index[index] = value
357
+ if set(by_index) != set(range(layout.block_count)):
358
+ raise ValueError("block results contain a gap or foreign block index")
359
+ canonical = tuple(by_index[index] for index in range(layout.block_count))
360
+ expected_requests = build_action_forecast_block_requests(request, layout)
361
+ for block_request, result in zip(expected_requests, canonical, strict=True):
362
+ validate_resolved_action_forecast_block(
363
+ block_request,
364
+ result.forecasts,
365
+ )
366
+
367
+ policy_identities = {
368
+ (
369
+ result.forecasts.policy_id,
370
+ result.forecasts.policy_version,
371
+ result.forecasts.policy_definition_sha256,
372
+ )
373
+ for result in canonical
374
+ }
375
+ if len(policy_identities) != 1:
376
+ raise ValueError("partition blocks contain policy drift")
377
+ policy_id, policy_version, policy_definition_sha256 = next(
378
+ iter(policy_identities)
379
+ )
380
+ drafts = tuple(
381
+ _draft_from_resolved(forecast)
382
+ for result in canonical
383
+ for forecast in result.forecasts.forecasts
384
+ )
385
+ batch = resolve_action_forecasts(
386
+ request,
387
+ drafts,
388
+ policy_id=policy_id,
389
+ policy_version=policy_version,
390
+ policy_definition_sha256=policy_definition_sha256,
391
+ )
392
+ validate_resolved_action_forecasts(request, batch)
393
+ return PartitionedActionForecastResult(
394
+ request_sha256=request.request_sha256,
395
+ layout=layout,
396
+ block_results=canonical,
397
+ forecasts=batch,
398
+ )
399
+
400
+
401
+ @dataclass(frozen=True, slots=True)
402
+ class ActionForecastBlockFailure:
403
+ block_index: int
404
+ block_request_sha256: str
405
+ error_type: str
406
+ error_message: str
407
+
408
+ def __post_init__(self) -> None:
409
+ if type(self.block_index) is not int or self.block_index < 0:
410
+ raise ValueError("block_index must be a non-negative exact integer")
411
+ require_sha256(self.block_request_sha256, "block_request_sha256")
412
+ if type(self.error_type) is not str or not self.error_type:
413
+ raise ValueError("error_type must be non-empty text")
414
+ if type(self.error_message) is not str:
415
+ raise TypeError("error_message must be exact text")
416
+
417
+ def to_record(self) -> dict[str, object]:
418
+ self.__post_init__()
419
+ return {
420
+ "block_index": self.block_index,
421
+ "block_request_sha256": self.block_request_sha256,
422
+ "error_type": self.error_type,
423
+ "error_message": self.error_message,
424
+ }
425
+
426
+
427
+ class ActionForecastWaveError(RuntimeError):
428
+ """All blocks settled, but at least one failed and no batch was published."""
429
+
430
+ def __init__(
431
+ self,
432
+ *,
433
+ successful_results: tuple[ActionForecastBlockResult, ...],
434
+ failures: tuple[ActionForecastBlockFailure, ...],
435
+ ) -> None:
436
+ if type(successful_results) is not tuple or any(
437
+ type(value) is not ActionForecastBlockResult
438
+ for value in successful_results
439
+ ):
440
+ raise TypeError("successful_results must be an exact result tuple")
441
+ if type(failures) is not tuple or not failures or any(
442
+ type(value) is not ActionForecastBlockFailure for value in failures
443
+ ):
444
+ raise ValueError("failures must be a non-empty exact failure tuple")
445
+ self.successful_results = successful_results
446
+ self.failures = failures
447
+ super().__init__(
448
+ f"{len(failures)} action-forecast block(s) failed after all settled"
449
+ )
450
+
451
+
452
+ @runtime_checkable
453
+ class PartitionedActionForecastPolicy(Protocol):
454
+ async def forecast_partitioned(
455
+ self,
456
+ request: ActionForecastRequest,
457
+ layout: ActionForecastPartitionLayout,
458
+ ) -> PartitionedActionForecastResult: ...
459
+
460
+
461
+ @dataclass(slots=True)
462
+ class ConcurrentActionForecastWave:
463
+ """Queue-agnostic bounded worker coordinator for one partitioned request."""
464
+
465
+ block_policy: ActionForecastBlockPolicy
466
+ max_concurrency: int
467
+
468
+ def __post_init__(self) -> None:
469
+ if not callable(getattr(self.block_policy, "forecast_block", None)):
470
+ raise TypeError("block_policy must expose forecast_block")
471
+ if type(self.max_concurrency) is not int or self.max_concurrency <= 0:
472
+ raise ValueError("max_concurrency must be a positive exact integer")
473
+
474
+ async def forecast_partitioned(
475
+ self,
476
+ request: ActionForecastRequest,
477
+ layout: ActionForecastPartitionLayout,
478
+ ) -> PartitionedActionForecastResult:
479
+ self.__post_init__()
480
+ block_requests = build_action_forecast_block_requests(request, layout)
481
+ results: list[ActionForecastBlockResult | None] = [
482
+ None for _ in block_requests
483
+ ]
484
+ failures: list[ActionForecastBlockFailure] = []
485
+ next_position = 0
486
+
487
+ async def worker() -> None:
488
+ nonlocal next_position
489
+ while next_position < len(block_requests):
490
+ position = next_position
491
+ next_position += 1
492
+ block_request = block_requests[position]
493
+ try:
494
+ result = await self.block_policy.forecast_block(block_request)
495
+ if type(result) is not ActionForecastBlockResult:
496
+ raise TypeError(
497
+ "block_policy returned a non-ActionForecastBlockResult"
498
+ )
499
+ result.__post_init__()
500
+ validate_resolved_action_forecast_block(
501
+ block_request,
502
+ result.forecasts,
503
+ )
504
+ results[position] = result
505
+ except Exception as exc:
506
+ failures.append(
507
+ ActionForecastBlockFailure(
508
+ block_index=block_request.block.block_index,
509
+ block_request_sha256=(
510
+ block_request.block_request_sha256
511
+ ),
512
+ error_type=(
513
+ f"{type(exc).__module__}.{type(exc).__qualname__}"
514
+ ),
515
+ error_message=str(exc),
516
+ )
517
+ )
518
+
519
+ worker_count = min(self.max_concurrency, len(block_requests))
520
+ workers = tuple(asyncio.create_task(worker()) for _ in range(worker_count))
521
+ try:
522
+ await asyncio.gather(*workers)
523
+ except asyncio.CancelledError:
524
+ for task in workers:
525
+ if not task.done():
526
+ task.cancel()
527
+ await asyncio.gather(*workers, return_exceptions=True)
528
+ raise
529
+
530
+ successful = tuple(value for value in results if value is not None)
531
+ if failures:
532
+ raise ActionForecastWaveError(
533
+ successful_results=successful,
534
+ failures=tuple(sorted(failures, key=lambda value: value.block_index)),
535
+ )
536
+ return assemble_partitioned_action_forecasts(
537
+ request,
538
+ layout,
539
+ tuple(value for value in results if value is not None),
540
+ )
541
+
542
+
543
+ @dataclass(frozen=True, slots=True, eq=False)
544
+ class ActionForecastHealthPolicyBinding:
545
+ """Identified, benchmark-neutral normalized forecast health thresholds."""
546
+
547
+ policy_id: str
548
+ policy_version: int
549
+ policy_definition_sha256: str
550
+ minimum_rows: int
551
+ extreme_abs_normalized_median: float
552
+ collapse_share_threshold: float
553
+ minimum_distinct_signatures: int
554
+
555
+ def __post_init__(self) -> None:
556
+ if type(self.policy_id) is not str or _TOKEN.fullmatch(self.policy_id) is None:
557
+ raise ValueError("policy_id must use the closed token grammar")
558
+ if type(self.policy_version) is not int or self.policy_version <= 0:
559
+ raise ValueError("policy_version must be a positive exact integer")
560
+ require_sha256(self.policy_definition_sha256, "policy_definition_sha256")
561
+ if type(self.minimum_rows) is not int or self.minimum_rows <= 0:
562
+ raise ValueError("minimum_rows must be a positive exact integer")
563
+ _finite_float(
564
+ self.extreme_abs_normalized_median,
565
+ "extreme_abs_normalized_median",
566
+ )
567
+ if self.extreme_abs_normalized_median <= 0.0:
568
+ raise ValueError("extreme_abs_normalized_median must be positive")
569
+ _finite_float(self.collapse_share_threshold, "collapse_share_threshold")
570
+ if not 0.0 < self.collapse_share_threshold <= 1.0:
571
+ raise ValueError("collapse_share_threshold must lie in (0,1]")
572
+ if (
573
+ type(self.minimum_distinct_signatures) is not int
574
+ or self.minimum_distinct_signatures < 2
575
+ ):
576
+ raise ValueError("minimum_distinct_signatures must be at least two")
577
+
578
+ def _unsigned_record(self) -> dict[str, object]:
579
+ self.__post_init__()
580
+ return {
581
+ "schema_version": 1,
582
+ "policy_id": self.policy_id,
583
+ "policy_version": self.policy_version,
584
+ "policy_definition_sha256": self.policy_definition_sha256,
585
+ "minimum_rows": self.minimum_rows,
586
+ "extreme_abs_normalized_median_hex": (
587
+ self.extreme_abs_normalized_median.hex()
588
+ ),
589
+ "collapse_share_threshold_hex": self.collapse_share_threshold.hex(),
590
+ "minimum_distinct_signatures": self.minimum_distinct_signatures,
591
+ }
592
+
593
+ @property
594
+ def binding_sha256(self) -> str:
595
+ return _hash(_HEALTH_POLICY_DOMAIN, self._unsigned_record())
596
+
597
+ def to_record(self) -> dict[str, object]:
598
+ return {**self._unsigned_record(), "binding_sha256": self.binding_sha256}
599
+
600
+ def __eq__(self, other: object) -> bool:
601
+ return (
602
+ type(self) is ActionForecastHealthPolicyBinding
603
+ and type(other) is ActionForecastHealthPolicyBinding
604
+ and self.binding_sha256 == other.binding_sha256
605
+ )
606
+
607
+ __hash__ = None
608
+
609
+
610
+ def lenient_action_forecast_health_policy() -> ActionForecastHealthPolicyBinding:
611
+ return ActionForecastHealthPolicyBinding(
612
+ policy_id=LENIENT_ACTION_FORECAST_HEALTH_POLICY_ID,
613
+ policy_version=LENIENT_ACTION_FORECAST_HEALTH_POLICY_VERSION,
614
+ policy_definition_sha256=(
615
+ LENIENT_ACTION_FORECAST_HEALTH_POLICY_DEFINITION_SHA256
616
+ ),
617
+ minimum_rows=8,
618
+ extreme_abs_normalized_median=32.0,
619
+ collapse_share_threshold=0.95,
620
+ minimum_distinct_signatures=2,
621
+ )
622
+
623
+
624
+ def lenient_action_forecast_health_v2_policy() -> ActionForecastHealthPolicyBinding:
625
+ """Reconstruct the frozen v2 policy binding for historical protocols.
626
+
627
+ New experiments must use :func:`lenient_action_forecast_health_policy`.
628
+ This named factory exists only so a sealed v2 protocol never silently
629
+ inherits later default-policy revisions.
630
+ """
631
+
632
+ return ActionForecastHealthPolicyBinding(
633
+ policy_id=LENIENT_ACTION_FORECAST_HEALTH_V2_POLICY_ID,
634
+ policy_version=LENIENT_ACTION_FORECAST_HEALTH_V2_POLICY_VERSION,
635
+ policy_definition_sha256=(
636
+ LENIENT_ACTION_FORECAST_HEALTH_V2_POLICY_DEFINITION_SHA256
637
+ ),
638
+ minimum_rows=8,
639
+ extreme_abs_normalized_median=32.0,
640
+ collapse_share_threshold=0.95,
641
+ minimum_distinct_signatures=2,
642
+ )
643
+
644
+
645
+ @dataclass(frozen=True, slots=True, eq=False)
646
+ class ActionForecastMetricHealth:
647
+ metric_id: str
648
+ row_count: int
649
+ extreme_median_share: float
650
+ largest_median_bucket_share: float
651
+ zero_width_share: float
652
+ unit_confidence_share: float
653
+ distinct_cell_signature_count: int
654
+ distinct_confidence_count: int
655
+ max_abs_normalized_median: float
656
+ threshold_applied: bool
657
+ passes: bool
658
+
659
+ def __post_init__(self) -> None:
660
+ if type(self.metric_id) is not str or not self.metric_id:
661
+ raise ValueError("metric_id must be non-empty text")
662
+ if type(self.row_count) is not int or self.row_count <= 0:
663
+ raise ValueError("row_count must be a positive exact integer")
664
+ for name in (
665
+ "extreme_median_share",
666
+ "largest_median_bucket_share",
667
+ "zero_width_share",
668
+ "unit_confidence_share",
669
+ ):
670
+ value = _finite_float(getattr(self, name), name)
671
+ if not 0.0 <= value <= 1.0:
672
+ raise ValueError(f"{name} must lie in [0,1]")
673
+ for name in (
674
+ "distinct_cell_signature_count",
675
+ "distinct_confidence_count",
676
+ ):
677
+ value = getattr(self, name)
678
+ if type(value) is not int or value <= 0:
679
+ raise ValueError(f"{name} must be a positive exact integer")
680
+ _finite_float(
681
+ self.max_abs_normalized_median,
682
+ "max_abs_normalized_median",
683
+ )
684
+ if self.max_abs_normalized_median < 0.0:
685
+ raise ValueError("max_abs_normalized_median cannot be negative")
686
+ if type(self.threshold_applied) is not bool or type(self.passes) is not bool:
687
+ raise TypeError("threshold_applied and passes must be exact booleans")
688
+
689
+ def _unsigned_record(self) -> dict[str, object]:
690
+ self.__post_init__()
691
+ return {
692
+ "schema_version": 2,
693
+ "metric_id": self.metric_id,
694
+ "row_count": self.row_count,
695
+ "extreme_median_share_hex": self.extreme_median_share.hex(),
696
+ "largest_median_bucket_share_hex": (
697
+ self.largest_median_bucket_share.hex()
698
+ ),
699
+ "zero_width_share_hex": self.zero_width_share.hex(),
700
+ "unit_confidence_share_hex": self.unit_confidence_share.hex(),
701
+ "distinct_cell_signature_count": self.distinct_cell_signature_count,
702
+ "distinct_confidence_count": self.distinct_confidence_count,
703
+ "max_abs_normalized_median_hex": (
704
+ self.max_abs_normalized_median.hex()
705
+ ),
706
+ "threshold_applied": self.threshold_applied,
707
+ "passes": self.passes,
708
+ }
709
+
710
+ @property
711
+ def receipt_sha256(self) -> str:
712
+ return _hash(_METRIC_HEALTH_DOMAIN, self._unsigned_record())
713
+
714
+ def to_record(self) -> dict[str, object]:
715
+ return {**self._unsigned_record(), "receipt_sha256": self.receipt_sha256}
716
+
717
+ def __eq__(self, other: object) -> bool:
718
+ return (
719
+ type(self) is ActionForecastMetricHealth
720
+ and type(other) is ActionForecastMetricHealth
721
+ and self.receipt_sha256 == other.receipt_sha256
722
+ )
723
+
724
+ __hash__ = None
725
+
726
+
727
+ @dataclass(frozen=True, slots=True, eq=False)
728
+ class ActionForecastHealthSubsetPolicyBinding:
729
+ """Identified scientific rule selecting rows from one validated block."""
730
+
731
+ policy_id: str
732
+ policy_version: int
733
+ policy_definition_sha256: str
734
+
735
+ def __post_init__(self) -> None:
736
+ if type(self.policy_id) is not str or _TOKEN.fullmatch(self.policy_id) is None:
737
+ raise ValueError("policy_id must use the closed token grammar")
738
+ if type(self.policy_version) is not int or self.policy_version <= 0:
739
+ raise ValueError("policy_version must be a positive exact integer")
740
+ require_sha256(self.policy_definition_sha256, "policy_definition_sha256")
741
+
742
+ def _unsigned_record(self) -> dict[str, object]:
743
+ self.__post_init__()
744
+ return {
745
+ "schema_version": 1,
746
+ "policy_id": self.policy_id,
747
+ "policy_version": self.policy_version,
748
+ "policy_definition_sha256": self.policy_definition_sha256,
749
+ }
750
+
751
+ @property
752
+ def binding_sha256(self) -> str:
753
+ return _hash(_HEALTH_SUBSET_POLICY_DOMAIN, self._unsigned_record())
754
+
755
+ def to_record(self) -> dict[str, object]:
756
+ return {**self._unsigned_record(), "binding_sha256": self.binding_sha256}
757
+
758
+ def __eq__(self, other: object) -> bool:
759
+ return (
760
+ type(self) is ActionForecastHealthSubsetPolicyBinding
761
+ and type(other) is ActionForecastHealthSubsetPolicyBinding
762
+ and self.binding_sha256 == other.binding_sha256
763
+ )
764
+
765
+ __hash__ = None
766
+
767
+
768
+ @dataclass(frozen=True, slots=True, eq=False)
769
+ class ActionForecastBlockHealthSubsetBinding:
770
+ """Authenticated ordered row subset of one exact resolved partition block."""
771
+
772
+ subset_policy: ActionForecastHealthSubsetPolicyBinding
773
+ request_sha256: str
774
+ layout_sha256: str
775
+ block_request_sha256: str
776
+ block_spec_sha256: str
777
+ parent_block_receipt_sha256: str
778
+ block_index: int
779
+ global_row_start: int
780
+ global_row_stop: int
781
+ included_global_row_indices: tuple[int, ...]
782
+ included_option_identity_sha256s: tuple[str, ...]
783
+
784
+ def __post_init__(self) -> None:
785
+ if type(self.subset_policy) is not ActionForecastHealthSubsetPolicyBinding:
786
+ raise TypeError("subset_policy must be an exact subset-policy binding")
787
+ self.subset_policy.__post_init__()
788
+ for name in (
789
+ "request_sha256",
790
+ "layout_sha256",
791
+ "block_request_sha256",
792
+ "block_spec_sha256",
793
+ "parent_block_receipt_sha256",
794
+ ):
795
+ require_sha256(getattr(self, name), name)
796
+ if type(self.block_index) is not int or self.block_index < 0:
797
+ raise ValueError("block_index must be a non-negative exact integer")
798
+ if type(self.global_row_start) is not int or self.global_row_start < 0:
799
+ raise ValueError("global_row_start must be a non-negative exact integer")
800
+ if (
801
+ type(self.global_row_stop) is not int
802
+ or self.global_row_stop <= self.global_row_start
803
+ ):
804
+ raise ValueError("global_row_stop must be greater than global_row_start")
805
+ if type(self.included_global_row_indices) is not tuple or not (
806
+ self.included_global_row_indices
807
+ ) or any(
808
+ type(value) is not int for value in self.included_global_row_indices
809
+ ):
810
+ raise ValueError(
811
+ "included_global_row_indices must be a non-empty exact tuple"
812
+ )
813
+ if self.included_global_row_indices != tuple(
814
+ sorted(set(self.included_global_row_indices))
815
+ ):
816
+ raise ValueError(
817
+ "included global rows must be unique and in block order"
818
+ )
819
+ if any(
820
+ value < self.global_row_start or value >= self.global_row_stop
821
+ for value in self.included_global_row_indices
822
+ ):
823
+ raise ValueError("an included global row is outside the parent block")
824
+ if type(self.included_option_identity_sha256s) is not tuple or any(
825
+ type(value) is not str
826
+ for value in self.included_option_identity_sha256s
827
+ ):
828
+ raise TypeError(
829
+ "included_option_identity_sha256s must be an exact tuple"
830
+ )
831
+ if len(self.included_option_identity_sha256s) != len(
832
+ self.included_global_row_indices
833
+ ):
834
+ raise ValueError("included row and option identity counts must match")
835
+ for index, value in enumerate(self.included_option_identity_sha256s):
836
+ require_sha256(value, f"included_option_identity_sha256s[{index}]")
837
+ if len(set(self.included_option_identity_sha256s)) != len(
838
+ self.included_option_identity_sha256s
839
+ ):
840
+ raise ValueError("an authenticated subset cannot repeat an option")
841
+
842
+ def _unsigned_record(self) -> dict[str, object]:
843
+ self.__post_init__()
844
+ return {
845
+ "schema_version": 1,
846
+ "subset_policy": self.subset_policy.to_record(),
847
+ "request_sha256": self.request_sha256,
848
+ "layout_sha256": self.layout_sha256,
849
+ "block_request_sha256": self.block_request_sha256,
850
+ "block_spec_sha256": self.block_spec_sha256,
851
+ "parent_block_receipt_sha256": self.parent_block_receipt_sha256,
852
+ "block_index": self.block_index,
853
+ "global_row_start": self.global_row_start,
854
+ "global_row_stop": self.global_row_stop,
855
+ "included_global_row_indices": list(
856
+ self.included_global_row_indices
857
+ ),
858
+ "included_option_identity_sha256s": list(
859
+ self.included_option_identity_sha256s
860
+ ),
861
+ }
862
+
863
+ @property
864
+ def binding_sha256(self) -> str:
865
+ return _hash(_HEALTH_BLOCK_SUBSET_DOMAIN, self._unsigned_record())
866
+
867
+ def to_record(self) -> dict[str, object]:
868
+ return {**self._unsigned_record(), "binding_sha256": self.binding_sha256}
869
+
870
+ def __eq__(self, other: object) -> bool:
871
+ return (
872
+ type(self) is ActionForecastBlockHealthSubsetBinding
873
+ and type(other) is ActionForecastBlockHealthSubsetBinding
874
+ and self.binding_sha256 == other.binding_sha256
875
+ )
876
+
877
+ __hash__ = None
878
+
879
+
880
+ class ActionForecastHealthFrameKind(str, Enum):
881
+ COMPLETE = "complete"
882
+ PARTITION_BLOCK = "partition_block"
883
+ PARTITION_BLOCK_SUBSET = "partition_block_subset"
884
+
885
+
886
+ @dataclass(frozen=True, slots=True)
887
+ class _NormalizedActionForecastHealth:
888
+ metric_assessments: tuple[ActionForecastMetricHealth, ...]
889
+ distinct_row_signature_count: int
890
+ distinct_probability_valid_count: int
891
+ constant_confidence_metric_ids: tuple[str, ...]
892
+ threshold_applied: bool
893
+ passes: bool
894
+
895
+
896
+ @dataclass(frozen=True, slots=True, eq=False)
897
+ class ResolvedActionForecastHealthAssessment:
898
+ member_id: str
899
+ frame_kind: ActionForecastHealthFrameKind
900
+ frame_receipt_sha256: str
901
+ request_sha256: str
902
+ layout_sha256: str | None
903
+ block_request_sha256: str | None
904
+ block_spec_sha256: str | None
905
+ block_index: int | None
906
+ global_row_start: int
907
+ global_row_stop: int
908
+ subset_binding: ActionForecastBlockHealthSubsetBinding | None
909
+ health_policy: ActionForecastHealthPolicyBinding
910
+ metric_assessments: tuple[ActionForecastMetricHealth, ...]
911
+ distinct_row_signature_count: int
912
+ distinct_probability_valid_count: int
913
+ constant_confidence_metric_ids: tuple[str, ...]
914
+ threshold_applied: bool
915
+ passes: bool
916
+
917
+ def __post_init__(self) -> None:
918
+ if type(self.member_id) is not str or _TOKEN.fullmatch(self.member_id) is None:
919
+ raise ValueError("member_id must use the closed token grammar")
920
+ if type(self.frame_kind) is not ActionForecastHealthFrameKind:
921
+ raise TypeError("frame_kind must be an exact health-frame kind")
922
+ require_sha256(self.frame_receipt_sha256, "frame_receipt_sha256")
923
+ require_sha256(self.request_sha256, "request_sha256")
924
+ if type(self.global_row_start) is not int or self.global_row_start < 0:
925
+ raise ValueError("global_row_start must be a non-negative exact integer")
926
+ if (
927
+ type(self.global_row_stop) is not int
928
+ or self.global_row_stop <= self.global_row_start
929
+ ):
930
+ raise ValueError("global_row_stop must be greater than global_row_start")
931
+ if self.frame_kind is ActionForecastHealthFrameKind.COMPLETE:
932
+ if self.global_row_start != 0:
933
+ raise ValueError("complete health frames must start at global row zero")
934
+ if any(
935
+ value is not None
936
+ for value in (
937
+ self.layout_sha256,
938
+ self.block_request_sha256,
939
+ self.block_spec_sha256,
940
+ self.block_index,
941
+ )
942
+ ):
943
+ raise ValueError("complete health frames forbid block identities")
944
+ if self.subset_binding is not None:
945
+ raise ValueError("complete health frames forbid subset bindings")
946
+ else:
947
+ for name in (
948
+ "layout_sha256",
949
+ "block_request_sha256",
950
+ "block_spec_sha256",
951
+ ):
952
+ value = getattr(self, name)
953
+ if type(value) is not str:
954
+ raise TypeError(f"partition-block health requires {name}")
955
+ require_sha256(value, name)
956
+ if type(self.block_index) is not int or self.block_index < 0:
957
+ raise ValueError(
958
+ "partition-block health requires a non-negative block_index"
959
+ )
960
+ if (
961
+ self.frame_kind
962
+ is ActionForecastHealthFrameKind.PARTITION_BLOCK
963
+ ):
964
+ if self.subset_binding is not None:
965
+ raise ValueError(
966
+ "full partition-block health forbids subset bindings"
967
+ )
968
+ else:
969
+ if type(self.subset_binding) is not (
970
+ ActionForecastBlockHealthSubsetBinding
971
+ ):
972
+ raise TypeError(
973
+ "partition-block-subset health requires a subset binding"
974
+ )
975
+ self.subset_binding.__post_init__()
976
+ if (
977
+ self.frame_receipt_sha256
978
+ != self.subset_binding.binding_sha256
979
+ or self.request_sha256 != self.subset_binding.request_sha256
980
+ or self.layout_sha256 != self.subset_binding.layout_sha256
981
+ or self.block_request_sha256
982
+ != self.subset_binding.block_request_sha256
983
+ or self.block_spec_sha256
984
+ != self.subset_binding.block_spec_sha256
985
+ or self.block_index != self.subset_binding.block_index
986
+ or self.global_row_start
987
+ != self.subset_binding.global_row_start
988
+ or self.global_row_stop != self.subset_binding.global_row_stop
989
+ ):
990
+ raise ValueError(
991
+ "subset health frame differs from its authenticated binding"
992
+ )
993
+ if type(self.health_policy) is not ActionForecastHealthPolicyBinding:
994
+ raise TypeError("health_policy must be an exact health-policy binding")
995
+ self.health_policy.__post_init__()
996
+ if type(self.metric_assessments) is not tuple or not (
997
+ self.metric_assessments
998
+ ) or any(
999
+ type(value) is not ActionForecastMetricHealth
1000
+ for value in self.metric_assessments
1001
+ ):
1002
+ raise ValueError("metric_assessments must be a non-empty exact tuple")
1003
+ for value in self.metric_assessments:
1004
+ value.__post_init__()
1005
+ metric_ids = tuple(value.metric_id for value in self.metric_assessments)
1006
+ if metric_ids != tuple(sorted(set(metric_ids))):
1007
+ raise ValueError("metric assessments must use canonical unique order")
1008
+ row_count = (
1009
+ len(self.subset_binding.included_global_row_indices)
1010
+ if self.frame_kind
1011
+ is ActionForecastHealthFrameKind.PARTITION_BLOCK_SUBSET
1012
+ and self.subset_binding is not None
1013
+ else self.global_row_stop - self.global_row_start
1014
+ )
1015
+ if any(value.row_count != row_count for value in self.metric_assessments):
1016
+ raise ValueError("metric health row counts differ from the bound frame")
1017
+ for name in (
1018
+ "distinct_row_signature_count",
1019
+ "distinct_probability_valid_count",
1020
+ ):
1021
+ value = getattr(self, name)
1022
+ if type(value) is not int or value <= 0:
1023
+ raise ValueError(f"{name} must be a positive exact integer")
1024
+ if value > row_count:
1025
+ raise ValueError(f"{name} cannot exceed the bound frame row count")
1026
+ if type(self.constant_confidence_metric_ids) is not tuple or any(
1027
+ type(value) is not str for value in self.constant_confidence_metric_ids
1028
+ ):
1029
+ raise TypeError("constant_confidence_metric_ids must be an exact tuple")
1030
+ if self.constant_confidence_metric_ids != tuple(
1031
+ sorted(set(self.constant_confidence_metric_ids))
1032
+ ):
1033
+ raise ValueError(
1034
+ "constant_confidence_metric_ids must be unique and canonical"
1035
+ )
1036
+ if not set(self.constant_confidence_metric_ids).issubset(metric_ids):
1037
+ raise ValueError("constant-confidence metrics escape the assessment")
1038
+ if type(self.threshold_applied) is not bool or type(self.passes) is not bool:
1039
+ raise TypeError("threshold_applied and passes must be exact booleans")
1040
+ expected_threshold_applied = row_count >= self.health_policy.minimum_rows
1041
+ if self.threshold_applied is not expected_threshold_applied:
1042
+ raise ValueError("threshold_applied differs from the bound frame size")
1043
+ if any(
1044
+ value.threshold_applied is not self.threshold_applied
1045
+ for value in self.metric_assessments
1046
+ ):
1047
+ raise ValueError("metric health threshold application is inconsistent")
1048
+ rows_pass = not self.threshold_applied or (
1049
+ self.distinct_row_signature_count
1050
+ >= self.health_policy.minimum_distinct_signatures
1051
+ )
1052
+ expected_passes = rows_pass and all(
1053
+ value.passes for value in self.metric_assessments
1054
+ )
1055
+ if self.passes is not expected_passes:
1056
+ raise ValueError("passes differs from the normalized health gates")
1057
+
1058
+ def _unsigned_record(self) -> dict[str, object]:
1059
+ self.__post_init__()
1060
+ return {
1061
+ "schema_version": 4,
1062
+ "member_id": self.member_id,
1063
+ "frame_kind": self.frame_kind.value,
1064
+ "frame_receipt_sha256": self.frame_receipt_sha256,
1065
+ "request_sha256": self.request_sha256,
1066
+ "layout_sha256": self.layout_sha256,
1067
+ "block_request_sha256": self.block_request_sha256,
1068
+ "block_spec_sha256": self.block_spec_sha256,
1069
+ "block_index": self.block_index,
1070
+ "global_row_start": self.global_row_start,
1071
+ "global_row_stop": self.global_row_stop,
1072
+ "subset_binding": (
1073
+ None
1074
+ if self.subset_binding is None
1075
+ else self.subset_binding.to_record()
1076
+ ),
1077
+ "health_policy": self.health_policy.to_record(),
1078
+ "metric_assessments": [
1079
+ value.to_record() for value in self.metric_assessments
1080
+ ],
1081
+ "distinct_row_signature_count": self.distinct_row_signature_count,
1082
+ "distinct_probability_valid_count": (
1083
+ self.distinct_probability_valid_count
1084
+ ),
1085
+ "constant_confidence_metric_ids": list(
1086
+ self.constant_confidence_metric_ids
1087
+ ),
1088
+ "threshold_applied": self.threshold_applied,
1089
+ "passes": self.passes,
1090
+ }
1091
+
1092
+ @property
1093
+ def receipt_sha256(self) -> str:
1094
+ return _hash(_HEALTH_ASSESSMENT_DOMAIN, self._unsigned_record())
1095
+
1096
+ def to_record(self) -> dict[str, object]:
1097
+ return {**self._unsigned_record(), "receipt_sha256": self.receipt_sha256}
1098
+
1099
+ def __eq__(self, other: object) -> bool:
1100
+ return (
1101
+ type(self) is ResolvedActionForecastHealthAssessment
1102
+ and type(other) is ResolvedActionForecastHealthAssessment
1103
+ and self.receipt_sha256 == other.receipt_sha256
1104
+ )
1105
+
1106
+ __hash__ = None
1107
+
1108
+
1109
+ def _normalized(value: float, scale: float) -> float:
1110
+ result = value / scale
1111
+ if not math.isfinite(result):
1112
+ raise ValueError("normalized forecast component must remain finite")
1113
+ return 0.0 if result == 0.0 else result
1114
+
1115
+
1116
+ def _validate_health_inputs(
1117
+ *,
1118
+ member_id: str,
1119
+ health_policy: ActionForecastHealthPolicyBinding,
1120
+ ) -> None:
1121
+ if type(member_id) is not str or _TOKEN.fullmatch(member_id) is None:
1122
+ raise ValueError("member_id must use the closed token grammar")
1123
+ if type(health_policy) is not ActionForecastHealthPolicyBinding:
1124
+ raise TypeError("health_policy must be an exact health-policy binding")
1125
+ health_policy.__post_init__()
1126
+
1127
+
1128
+ def _assess_normalized_forecasts(
1129
+ forecasts: tuple[ResolvedActionForecast, ...],
1130
+ request: ActionForecastRequest,
1131
+ health_policy: ActionForecastHealthPolicyBinding,
1132
+ ) -> _NormalizedActionForecastHealth:
1133
+ """Apply one normalized gate implementation to any validated row frame."""
1134
+
1135
+ if type(forecasts) is not tuple or not forecasts or any(
1136
+ type(value) is not ResolvedActionForecast for value in forecasts
1137
+ ):
1138
+ raise ValueError("forecasts must be a non-empty exact resolved tuple")
1139
+ for value in forecasts:
1140
+ value.__post_init__()
1141
+ row_count = len(forecasts)
1142
+ threshold_applied = row_count >= health_policy.minimum_rows
1143
+ metric_assessments: list[ActionForecastMetricHealth] = []
1144
+ constant_confidence_metric_ids: list[str] = []
1145
+ row_signatures: set[tuple[object, ...]] = set()
1146
+ probability_buckets: set[str] = set()
1147
+
1148
+ for forecast in forecasts:
1149
+ probability_buckets.add(forecast.probability_valid.hex())
1150
+ row_signature: list[object] = [forecast.probability_valid.hex()]
1151
+ for metric, scale in zip(
1152
+ forecast.metric_forecasts,
1153
+ request.metric_scales,
1154
+ strict=True,
1155
+ ):
1156
+ median = _normalized(metric.p50_delta, scale.delta_scale)
1157
+ lower = _normalized(
1158
+ metric.p50_delta - metric.p10_delta,
1159
+ scale.delta_scale,
1160
+ )
1161
+ upper = _normalized(
1162
+ metric.p90_delta - metric.p50_delta,
1163
+ scale.delta_scale,
1164
+ )
1165
+ row_signature.append(
1166
+ (median.hex(), lower.hex(), upper.hex(), metric.confidence.hex())
1167
+ )
1168
+ row_signatures.add(tuple(row_signature))
1169
+
1170
+ for metric_index, scale in enumerate(request.metric_scales):
1171
+ median_buckets: Counter[str] = Counter()
1172
+ cell_signatures: set[tuple[str, str, str, str]] = set()
1173
+ confidence_buckets: set[str] = set()
1174
+ extreme_count = 0
1175
+ zero_width_count = 0
1176
+ unit_confidence_count = 0
1177
+ max_abs_median = 0.0
1178
+ for forecast in forecasts:
1179
+ metric = forecast.metric_forecasts[metric_index]
1180
+ median = _normalized(metric.p50_delta, scale.delta_scale)
1181
+ lower = _normalized(
1182
+ metric.p50_delta - metric.p10_delta,
1183
+ scale.delta_scale,
1184
+ )
1185
+ upper = _normalized(
1186
+ metric.p90_delta - metric.p50_delta,
1187
+ scale.delta_scale,
1188
+ )
1189
+ median_buckets[median.hex()] += 1
1190
+ confidence_buckets.add(metric.confidence.hex())
1191
+ cell_signatures.add(
1192
+ (median.hex(), lower.hex(), upper.hex(), metric.confidence.hex())
1193
+ )
1194
+ if abs(median) >= health_policy.extreme_abs_normalized_median:
1195
+ extreme_count += 1
1196
+ if lower == 0.0 and upper == 0.0:
1197
+ zero_width_count += 1
1198
+ if metric.confidence == 1.0:
1199
+ unit_confidence_count += 1
1200
+ max_abs_median = max(max_abs_median, abs(median))
1201
+
1202
+ extreme_share = extreme_count / row_count
1203
+ largest_bucket_share = max(median_buckets.values()) / row_count
1204
+ zero_width_share = zero_width_count / row_count
1205
+ unit_confidence_share = unit_confidence_count / row_count
1206
+ passes = not threshold_applied or (
1207
+ extreme_share < health_policy.collapse_share_threshold
1208
+ and largest_bucket_share < health_policy.collapse_share_threshold
1209
+ and zero_width_share < health_policy.collapse_share_threshold
1210
+ and unit_confidence_share < health_policy.collapse_share_threshold
1211
+ and len(cell_signatures)
1212
+ >= health_policy.minimum_distinct_signatures
1213
+ )
1214
+ metric_assessments.append(
1215
+ ActionForecastMetricHealth(
1216
+ metric_id=scale.metric_id,
1217
+ row_count=row_count,
1218
+ extreme_median_share=float(extreme_share),
1219
+ largest_median_bucket_share=float(largest_bucket_share),
1220
+ zero_width_share=float(zero_width_share),
1221
+ unit_confidence_share=float(unit_confidence_share),
1222
+ distinct_cell_signature_count=len(cell_signatures),
1223
+ distinct_confidence_count=len(confidence_buckets),
1224
+ max_abs_normalized_median=float(max_abs_median),
1225
+ threshold_applied=threshold_applied,
1226
+ passes=passes,
1227
+ )
1228
+ )
1229
+ if len(confidence_buckets) == 1:
1230
+ constant_confidence_metric_ids.append(scale.metric_id)
1231
+
1232
+ rows_pass = not threshold_applied or (
1233
+ len(row_signatures) >= health_policy.minimum_distinct_signatures
1234
+ )
1235
+ assessments = tuple(metric_assessments)
1236
+ return _NormalizedActionForecastHealth(
1237
+ metric_assessments=assessments,
1238
+ distinct_row_signature_count=len(row_signatures),
1239
+ distinct_probability_valid_count=len(probability_buckets),
1240
+ constant_confidence_metric_ids=tuple(
1241
+ sorted(constant_confidence_metric_ids)
1242
+ ),
1243
+ threshold_applied=threshold_applied,
1244
+ passes=rows_pass and all(value.passes for value in assessments),
1245
+ )
1246
+
1247
+
1248
+ def _bind_health_assessment(
1249
+ *,
1250
+ member_id: str,
1251
+ frame_kind: ActionForecastHealthFrameKind,
1252
+ frame_receipt_sha256: str,
1253
+ request_sha256: str,
1254
+ layout_sha256: str | None,
1255
+ block_request_sha256: str | None,
1256
+ block_spec_sha256: str | None,
1257
+ block_index: int | None,
1258
+ global_row_start: int,
1259
+ global_row_stop: int,
1260
+ subset_binding: ActionForecastBlockHealthSubsetBinding | None,
1261
+ health_policy: ActionForecastHealthPolicyBinding,
1262
+ normalized: _NormalizedActionForecastHealth,
1263
+ ) -> ResolvedActionForecastHealthAssessment:
1264
+ return ResolvedActionForecastHealthAssessment(
1265
+ member_id=member_id,
1266
+ frame_kind=frame_kind,
1267
+ frame_receipt_sha256=frame_receipt_sha256,
1268
+ request_sha256=request_sha256,
1269
+ layout_sha256=layout_sha256,
1270
+ block_request_sha256=block_request_sha256,
1271
+ block_spec_sha256=block_spec_sha256,
1272
+ block_index=block_index,
1273
+ global_row_start=global_row_start,
1274
+ global_row_stop=global_row_stop,
1275
+ subset_binding=subset_binding,
1276
+ health_policy=health_policy,
1277
+ metric_assessments=normalized.metric_assessments,
1278
+ distinct_row_signature_count=normalized.distinct_row_signature_count,
1279
+ distinct_probability_valid_count=(
1280
+ normalized.distinct_probability_valid_count
1281
+ ),
1282
+ constant_confidence_metric_ids=(
1283
+ normalized.constant_confidence_metric_ids
1284
+ ),
1285
+ threshold_applied=normalized.threshold_applied,
1286
+ passes=normalized.passes,
1287
+ )
1288
+
1289
+
1290
+ def assess_resolved_action_forecast_health(
1291
+ request: ActionForecastRequest,
1292
+ batch: ResolvedActionForecastBatch,
1293
+ *,
1294
+ member_id: str,
1295
+ health_policy: ActionForecastHealthPolicyBinding,
1296
+ ) -> ResolvedActionForecastHealthAssessment:
1297
+ """Assess one validated complete batch in metric-scale units."""
1298
+
1299
+ if type(request) is not ActionForecastRequest:
1300
+ raise TypeError("request must be an exact ActionForecastRequest")
1301
+ request.__post_init__()
1302
+ validate_resolved_action_forecasts(request, batch)
1303
+ _validate_health_inputs(member_id=member_id, health_policy=health_policy)
1304
+ normalized = _assess_normalized_forecasts(
1305
+ batch.forecasts,
1306
+ request,
1307
+ health_policy,
1308
+ )
1309
+ return _bind_health_assessment(
1310
+ member_id=member_id,
1311
+ frame_kind=ActionForecastHealthFrameKind.COMPLETE,
1312
+ frame_receipt_sha256=batch.receipt_sha256,
1313
+ request_sha256=request.request_sha256,
1314
+ layout_sha256=None,
1315
+ block_request_sha256=None,
1316
+ block_spec_sha256=None,
1317
+ block_index=None,
1318
+ global_row_start=0,
1319
+ global_row_stop=len(batch.forecasts),
1320
+ subset_binding=None,
1321
+ health_policy=health_policy,
1322
+ normalized=normalized,
1323
+ )
1324
+
1325
+
1326
+ def assess_resolved_action_forecast_block_health(
1327
+ block_request: ActionForecastBlockRequest,
1328
+ block: ResolvedActionForecastBlock,
1329
+ *,
1330
+ member_id: str,
1331
+ health_policy: ActionForecastHealthPolicyBinding,
1332
+ ) -> ResolvedActionForecastHealthAssessment:
1333
+ """Assess one validated partition block without presenting it as a batch."""
1334
+
1335
+ if type(block_request) is not ActionForecastBlockRequest:
1336
+ raise TypeError("block_request must be an exact ActionForecastBlockRequest")
1337
+ block_request.__post_init__()
1338
+ validate_resolved_action_forecast_block(block_request, block)
1339
+ _validate_health_inputs(member_id=member_id, health_policy=health_policy)
1340
+ normalized = _assess_normalized_forecasts(
1341
+ block.forecasts,
1342
+ block_request.request,
1343
+ health_policy,
1344
+ )
1345
+ spec = block_request.block
1346
+ return _bind_health_assessment(
1347
+ member_id=member_id,
1348
+ frame_kind=ActionForecastHealthFrameKind.PARTITION_BLOCK,
1349
+ frame_receipt_sha256=block.receipt_sha256,
1350
+ request_sha256=block_request.request.request_sha256,
1351
+ layout_sha256=block_request.layout.layout_sha256,
1352
+ block_request_sha256=block_request.block_request_sha256,
1353
+ block_spec_sha256=spec.block_spec_sha256,
1354
+ block_index=spec.block_index,
1355
+ global_row_start=spec.global_row_start,
1356
+ global_row_stop=spec.global_row_stop,
1357
+ subset_binding=None,
1358
+ health_policy=health_policy,
1359
+ normalized=normalized,
1360
+ )
1361
+
1362
+
1363
+ def assess_resolved_action_forecast_block_subset_health(
1364
+ block_request: ActionForecastBlockRequest,
1365
+ block: ResolvedActionForecastBlock,
1366
+ *,
1367
+ member_id: str,
1368
+ health_policy: ActionForecastHealthPolicyBinding,
1369
+ subset_policy: ActionForecastHealthSubsetPolicyBinding,
1370
+ included_global_row_indices: tuple[int, ...],
1371
+ ) -> ResolvedActionForecastHealthAssessment:
1372
+ """Assess one authenticated ordered subset of a validated partition block."""
1373
+
1374
+ if type(block_request) is not ActionForecastBlockRequest:
1375
+ raise TypeError("block_request must be an exact ActionForecastBlockRequest")
1376
+ block_request.__post_init__()
1377
+ validate_resolved_action_forecast_block(block_request, block)
1378
+ _validate_health_inputs(member_id=member_id, health_policy=health_policy)
1379
+ if type(subset_policy) is not ActionForecastHealthSubsetPolicyBinding:
1380
+ raise TypeError("subset_policy must be an exact subset-policy binding")
1381
+ subset_policy.__post_init__()
1382
+ if type(included_global_row_indices) is not tuple or not (
1383
+ included_global_row_indices
1384
+ ) or any(type(value) is not int for value in included_global_row_indices):
1385
+ raise ValueError(
1386
+ "included_global_row_indices must be a non-empty exact tuple"
1387
+ )
1388
+ if included_global_row_indices != tuple(
1389
+ sorted(set(included_global_row_indices))
1390
+ ):
1391
+ raise ValueError("included global rows must be unique and in block order")
1392
+ spec = block_request.block
1393
+ if any(
1394
+ value < spec.global_row_start or value >= spec.global_row_stop
1395
+ for value in included_global_row_indices
1396
+ ):
1397
+ raise ValueError("an included global row is outside the parent block")
1398
+
1399
+ included_option_identities = tuple(
1400
+ block_request.request.finite_variation_contract.options[
1401
+ global_index
1402
+ ].identity_sha256
1403
+ for global_index in included_global_row_indices
1404
+ )
1405
+ subset_binding = ActionForecastBlockHealthSubsetBinding(
1406
+ subset_policy=subset_policy,
1407
+ request_sha256=block_request.request.request_sha256,
1408
+ layout_sha256=block_request.layout.layout_sha256,
1409
+ block_request_sha256=block_request.block_request_sha256,
1410
+ block_spec_sha256=spec.block_spec_sha256,
1411
+ parent_block_receipt_sha256=block.receipt_sha256,
1412
+ block_index=spec.block_index,
1413
+ global_row_start=spec.global_row_start,
1414
+ global_row_stop=spec.global_row_stop,
1415
+ included_global_row_indices=included_global_row_indices,
1416
+ included_option_identity_sha256s=included_option_identities,
1417
+ )
1418
+ selected_forecasts = tuple(
1419
+ block.forecasts[global_index - spec.global_row_start]
1420
+ for global_index in included_global_row_indices
1421
+ )
1422
+ normalized = _assess_normalized_forecasts(
1423
+ selected_forecasts,
1424
+ block_request.request,
1425
+ health_policy,
1426
+ )
1427
+ return _bind_health_assessment(
1428
+ member_id=member_id,
1429
+ frame_kind=ActionForecastHealthFrameKind.PARTITION_BLOCK_SUBSET,
1430
+ frame_receipt_sha256=subset_binding.binding_sha256,
1431
+ request_sha256=block_request.request.request_sha256,
1432
+ layout_sha256=block_request.layout.layout_sha256,
1433
+ block_request_sha256=block_request.block_request_sha256,
1434
+ block_spec_sha256=spec.block_spec_sha256,
1435
+ block_index=spec.block_index,
1436
+ global_row_start=spec.global_row_start,
1437
+ global_row_stop=spec.global_row_stop,
1438
+ subset_binding=subset_binding,
1439
+ health_policy=health_policy,
1440
+ normalized=normalized,
1441
+ )
1442
+
1443
+
1444
+ __all__ = [
1445
+ "ActionForecastBlockFailure",
1446
+ "ActionForecastBlockHealthSubsetBinding",
1447
+ "ActionForecastHealthFrameKind",
1448
+ "ActionForecastHealthPolicyBinding",
1449
+ "ActionForecastHealthSubsetPolicyBinding",
1450
+ "ActionForecastMetricHealth",
1451
+ "ActionForecastWaveError",
1452
+ "ConcurrentActionForecastWave",
1453
+ "LENIENT_ACTION_FORECAST_HEALTH_POLICY_DEFINITION_SHA256",
1454
+ "LENIENT_ACTION_FORECAST_HEALTH_POLICY_ID",
1455
+ "LENIENT_ACTION_FORECAST_HEALTH_POLICY_VERSION",
1456
+ "LENIENT_ACTION_FORECAST_HEALTH_V2_POLICY_DEFINITION_SHA256",
1457
+ "LENIENT_ACTION_FORECAST_HEALTH_V2_POLICY_ID",
1458
+ "LENIENT_ACTION_FORECAST_HEALTH_V2_POLICY_VERSION",
1459
+ "PartitionedActionForecastPolicy",
1460
+ "PartitionedActionForecastResult",
1461
+ "ResolvedActionForecastHealthAssessment",
1462
+ "action_forecast_block_call_id",
1463
+ "assess_resolved_action_forecast_block_health",
1464
+ "assess_resolved_action_forecast_block_subset_health",
1465
+ "assess_resolved_action_forecast_health",
1466
+ "assemble_partitioned_action_forecasts",
1467
+ "build_action_forecast_block_requests",
1468
+ "build_action_forecast_partition_layout",
1469
+ "lenient_action_forecast_health_policy",
1470
+ "lenient_action_forecast_health_v2_policy",
1471
+ ]