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,1523 @@
1
+ """Benchmark-neutral terminal joins for physical provider-attempt evidence.
2
+
3
+ An outbound manifest proves that a request reached the HTTPX pre-transport
4
+ boundary. Queue outcomes and stream progress prove how that physical attempt
5
+ terminated. This module joins those independently durable channels without
6
+ retaining prompts, schemas, response bodies, or stream content.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import hashlib
12
+ import json
13
+ import re
14
+ from collections import Counter
15
+ from collections import defaultdict
16
+ from collections.abc import Mapping, Sequence
17
+ from decimal import Decimal, InvalidOperation
18
+
19
+ from agent_evolve.domain.ids import LLMCallId, ProviderAttemptId
20
+ from agent_evolve.domain.llm_task_queue import (
21
+ AttemptRequestEvidence,
22
+ AttemptRequestVariant,
23
+ AttemptStatus,
24
+ AttemptTelemetry,
25
+ CancellationReason,
26
+ CanonicalProviderErrorCode,
27
+ ExceptionOriginFamily,
28
+ ExceptionProvenanceLink,
29
+ LLMTaskOutcome,
30
+ RetryAfter,
31
+ RetryAfterSource,
32
+ RetryClassification,
33
+ RetryDisposition,
34
+ RetryReason,
35
+ SanitizedAttemptFailure,
36
+ SanitizedExceptionProvenance,
37
+ SanitizedExceptionProvenanceNode,
38
+ SanitizedValidationIssue,
39
+ StreamTimeoutPhase,
40
+ StructuredOutputFailureMode,
41
+ TaskOutcomeStatus,
42
+ TaskTelemetry,
43
+ ValidationIssueCategory,
44
+ ValidationIssueReasonCode,
45
+ )
46
+ from agent_evolve.integrations.pydantic_ai.outbound_request_manifest import (
47
+ validate_openrouter_outbound_request_manifest_record,
48
+ )
49
+ from agent_evolve.integrations.pydantic_ai.queued_runner import (
50
+ SUPPORTED_STRUCTURED_GENERATION_OUTCOME_SCHEMA_VERSIONS,
51
+ validate_structured_generation_request_evidence_record,
52
+ )
53
+ from agent_evolve.ports.structured_generator import (
54
+ StructuredStreamChannel,
55
+ StructuredStreamProgress,
56
+ StructuredStreamProgressKind,
57
+ )
58
+
59
+
60
+ PROVIDER_ATTEMPT_TERMINAL_JOIN_SCHEMA_VERSION = 1
61
+ PROVIDER_ATTEMPT_TERMINAL_JOIN_CONTRACT_ID = (
62
+ "provider_attempt_outbound_outcome_progress_join_v1"
63
+ )
64
+ PRE_TRANSPORT_FAILURE_EVIDENCE_SCHEMA_VERSION = 1
65
+
66
+ _SHA256 = re.compile(r"^[0-9a-f]{64}$")
67
+ _FAILURE_STAGE = re.compile(r"^[a-z][a-z0-9_.-]{0,95}$")
68
+ _JOIN_DOMAIN = b"agent-evolve:provider-attempt-terminal-join:v1\x00"
69
+ _PRE_TRANSPORT_DOMAIN = (
70
+ b"agent-evolve:provider-attempt-explicit-pre-transport-failure:v1\x00"
71
+ )
72
+ _COLLECTION_DOMAIN = b"agent-evolve:provider-attempt-join-collection:v1\x00"
73
+ _ATTEMPT_STATUSES = frozenset(
74
+ {
75
+ "succeeded",
76
+ "retryable_failure",
77
+ "terminal_failure",
78
+ "timed_out",
79
+ "cancelled",
80
+ }
81
+ )
82
+ _TASK_STATUSES = frozenset(
83
+ {"succeeded", "terminal_failure", "attempts_exhausted", "cancelled"}
84
+ )
85
+ _OUTCOME_RESPONSE_FIELDS = frozenset(
86
+ {
87
+ "requested_model",
88
+ "resolved_model",
89
+ "resolved_provider",
90
+ "provider_response_id",
91
+ "finish_reason",
92
+ "input_tokens",
93
+ "output_tokens",
94
+ "reasoning_tokens",
95
+ "cache_read_tokens",
96
+ "cache_write_tokens",
97
+ "cost_usd",
98
+ "latency_ns",
99
+ }
100
+ )
101
+ _OUTCOME_FIELDS = frozenset(
102
+ {
103
+ "schema_version",
104
+ "task_id",
105
+ "status",
106
+ "cancellation_reason",
107
+ "queue_time_ns",
108
+ "service_time_ns",
109
+ "total_time_ns",
110
+ "attempts",
111
+ "response",
112
+ }
113
+ )
114
+ _OUTCOME_ATTEMPT_FIELDS = frozenset(
115
+ {
116
+ "attempt_number",
117
+ "status",
118
+ "wait_time_ns",
119
+ "service_time_ns",
120
+ "will_retry",
121
+ "policy_backoff_ns",
122
+ "retry_after_ns",
123
+ "scheduled_delay_ns",
124
+ "error_type",
125
+ "request_evidence",
126
+ "classification",
127
+ "failure",
128
+ }
129
+ )
130
+ _ATTEMPT_REQUEST_EVIDENCE_FIELDS = frozenset(
131
+ {"variant", "prompt_sha256", "provider_attempt_id"}
132
+ )
133
+ _ATTEMPT_CLASSIFICATION_FIELDS = frozenset({"disposition", "reason"})
134
+ _ATTEMPT_FAILURE_FIELDS_V5 = frozenset(
135
+ {
136
+ "kind",
137
+ "retryable",
138
+ "safe_message",
139
+ "status_code",
140
+ "retry_after_seconds",
141
+ "stream_timeout_phase",
142
+ "output_failure_mode",
143
+ "validation_issues",
144
+ }
145
+ )
146
+ _ATTEMPT_FAILURE_FIELDS_V6 = _ATTEMPT_FAILURE_FIELDS_V5 | frozenset(
147
+ {"provider_error_code", "provider_error_envelope_sha256"}
148
+ )
149
+ _ATTEMPT_FAILURE_FIELDS_V8 = _ATTEMPT_FAILURE_FIELDS_V6 | frozenset(
150
+ {"exception_provenance"}
151
+ )
152
+ _EXCEPTION_PROVENANCE_FIELDS_V8 = frozenset({"nodes", "truncated"})
153
+ _EXCEPTION_PROVENANCE_NODE_FIELDS_V8 = frozenset(
154
+ {"parent_index", "link", "family", "type_identity_sha256"}
155
+ )
156
+ _VALIDATION_ISSUE_FIELDS_V6 = frozenset({"category", "location"})
157
+ _VALIDATION_ISSUE_FIELDS_V7 = _VALIDATION_ISSUE_FIELDS_V6 | frozenset({"reason_code"})
158
+ _PROGRESS_FIELDS = frozenset(
159
+ {
160
+ "schema_version",
161
+ "call_id",
162
+ "provider_attempt_id",
163
+ "sequence",
164
+ "kind",
165
+ "channel",
166
+ "elapsed_ns",
167
+ "event_content_utf8_bytes",
168
+ "cumulative_content_utf8_bytes",
169
+ "rolling_content_sha256",
170
+ }
171
+ )
172
+ _FRAMEWORK_VERSION_FIELDS = frozenset({"httpx", "openai", "pydantic", "pydantic-ai"})
173
+ _EXPECTED_TRANSPORT_SETTING_FIELDS = frozenset(
174
+ {
175
+ "model",
176
+ "provider",
177
+ "reasoning",
178
+ "usage",
179
+ "stream",
180
+ "stream_options",
181
+ "tool_choice",
182
+ "response_format",
183
+ }
184
+ )
185
+ _SOURCE_FIELDS = frozenset(
186
+ {
187
+ "logical_requests",
188
+ "outbound_manifests",
189
+ "terminal_outcomes",
190
+ "progress_rows",
191
+ "explicit_pre_transport_failures",
192
+ }
193
+ )
194
+ _SOURCE_COUNT_FIELDS = frozenset(
195
+ {*_SOURCE_FIELDS, "outcome_attempts_with_physical_ids"}
196
+ )
197
+ _PROVIDER_ATTEMPT_ID_FIELDS = frozenset(
198
+ {
199
+ "dispatched",
200
+ "terminal_outcomes",
201
+ "progress",
202
+ "provider_status_response_or_progress",
203
+ "explicit_pre_transport_failures",
204
+ }
205
+ )
206
+ _DEFECT_ATTEMPT_ID_FIELDS = frozenset(
207
+ {
208
+ "duplicate_outbound_manifest_attempt_ids",
209
+ "duplicate_outcome_attempt_ids",
210
+ "duplicate_pre_transport_attempt_ids",
211
+ "missing_logical_request_attempt_ids",
212
+ "logical_physical_mismatch_attempt_ids",
213
+ "framework_version_mismatch_attempt_ids",
214
+ "transport_settings_mismatch_attempt_ids",
215
+ "missing_manifest_attempt_ids",
216
+ "orphan_manifest_attempt_ids",
217
+ "progress_without_manifest_attempt_ids",
218
+ "progress_without_outcome_attempt_ids",
219
+ "progress_duplicate_sequence_attempt_ids",
220
+ "progress_noncontiguous_sequence_attempt_ids",
221
+ "provider_evidence_without_manifest_attempt_ids",
222
+ "pre_transport_with_manifest_attempt_ids",
223
+ "pre_transport_with_provider_evidence_attempt_ids",
224
+ "pre_transport_without_outcome_attempt_ids",
225
+ "call_id_mismatch_attempt_ids",
226
+ }
227
+ )
228
+ _DEFECT_CALL_ID_FIELDS = frozenset({"duplicate_logical_request_call_ids"})
229
+ _DEFECT_FIELDS = _DEFECT_ATTEMPT_ID_FIELDS | _DEFECT_CALL_ID_FIELDS
230
+ _INVARIANT_FIELDS = frozenset(
231
+ {
232
+ "logical_request_exactly_once_per_dispatched_attempt",
233
+ "logical_physical_request_fields_exact",
234
+ "framework_versions_join_qualification_exact",
235
+ "transport_settings_join_selected_profile_exact",
236
+ "manifest_exactly_once_per_dispatched_attempt",
237
+ "outcome_attempt_identity_exactly_once",
238
+ "every_physical_outcome_attempt_accounted_for",
239
+ "every_dispatched_attempt_has_terminal_outcome",
240
+ "provider_evidence_always_has_manifest",
241
+ "progress_joins_manifest_and_outcome",
242
+ "progress_sequence_unique_and_contiguous",
243
+ "explicit_pre_transport_evidence_consistent",
244
+ "explicit_pre_transport_is_affirmative_not_inferred",
245
+ "call_id_join_exact",
246
+ "raw_provider_content_persisted",
247
+ }
248
+ )
249
+
250
+
251
+ def _canonical_bytes(value: object) -> bytes:
252
+ return json.dumps(
253
+ value,
254
+ ensure_ascii=True,
255
+ allow_nan=False,
256
+ separators=(",", ":"),
257
+ sort_keys=True,
258
+ ).encode("ascii")
259
+
260
+
261
+ def _domain_sha256(domain: bytes, value: object) -> str:
262
+ return hashlib.sha256(domain + _canonical_bytes(value)).hexdigest()
263
+
264
+
265
+ def _canonical_mapping(value: object, *, label: str) -> dict[str, object]:
266
+ if not isinstance(value, Mapping):
267
+ raise TypeError(f"{label} must be a mapping")
268
+ try:
269
+ detached = json.loads(_canonical_bytes(dict(value)))
270
+ except (TypeError, ValueError) as exc:
271
+ raise ValueError(f"{label} must contain canonical JSON values") from exc
272
+ if type(detached) is not dict:
273
+ raise ValueError(f"{label} must encode one exact object")
274
+ return detached
275
+
276
+
277
+ def _require_sha256(value: object, *, label: str) -> str:
278
+ if type(value) is not str or _SHA256.fullmatch(value) is None:
279
+ raise ValueError(f"{label} must be a lowercase SHA-256 digest")
280
+ return value
281
+
282
+
283
+ def explicit_pre_transport_failure_evidence_record(
284
+ *,
285
+ call_id: str,
286
+ provider_attempt_id: str,
287
+ failure_stage: str,
288
+ ) -> dict[str, object]:
289
+ """Build content-free affirmative evidence that HTTP dispatch never began."""
290
+
291
+ LLMCallId(call_id)
292
+ ProviderAttemptId(provider_attempt_id)
293
+ if (
294
+ type(failure_stage) is not str
295
+ or _FAILURE_STAGE.fullmatch(failure_stage) is None
296
+ ):
297
+ raise ValueError("failure_stage is outside the closed token grammar")
298
+ record: dict[str, object] = {
299
+ "schema_version": PRE_TRANSPORT_FAILURE_EVIDENCE_SCHEMA_VERSION,
300
+ "call_id": call_id,
301
+ "provider_attempt_id": provider_attempt_id,
302
+ "failure_stage": failure_stage,
303
+ "http_transport_dispatch_started": False,
304
+ "raw_failure_content_persisted": False,
305
+ }
306
+ record["evidence_sha256"] = _domain_sha256(_PRE_TRANSPORT_DOMAIN, record)
307
+ return record
308
+
309
+
310
+ def validate_explicit_pre_transport_failure_evidence_record(
311
+ value: Mapping[str, object],
312
+ ) -> dict[str, object]:
313
+ record = _canonical_mapping(value, label="pre-transport failure evidence")
314
+ if frozenset(record) != {
315
+ "schema_version",
316
+ "call_id",
317
+ "provider_attempt_id",
318
+ "failure_stage",
319
+ "http_transport_dispatch_started",
320
+ "raw_failure_content_persisted",
321
+ "evidence_sha256",
322
+ }:
323
+ raise ValueError("pre-transport failure evidence has unexpected fields")
324
+ if (
325
+ record["schema_version"] != PRE_TRANSPORT_FAILURE_EVIDENCE_SCHEMA_VERSION
326
+ or record["http_transport_dispatch_started"] is not False
327
+ or record["raw_failure_content_persisted"] is not False
328
+ ):
329
+ raise ValueError("pre-transport failure evidence contract drifted")
330
+ LLMCallId(record["call_id"])
331
+ ProviderAttemptId(record["provider_attempt_id"])
332
+ stage = record["failure_stage"]
333
+ if type(stage) is not str or _FAILURE_STAGE.fullmatch(stage) is None:
334
+ raise ValueError("pre-transport failure stage is invalid")
335
+ supplied = _require_sha256(record["evidence_sha256"], label="evidence_sha256")
336
+ authenticated = dict(record)
337
+ del authenticated["evidence_sha256"]
338
+ if supplied != _domain_sha256(_PRE_TRANSPORT_DOMAIN, authenticated):
339
+ raise ValueError("pre-transport failure evidence hash is invalid")
340
+ return record
341
+
342
+
343
+ def _collection_sha256(rows: Sequence[object]) -> str:
344
+ digest = hashlib.sha256(_COLLECTION_DOMAIN)
345
+ for index, row in enumerate(rows):
346
+ try:
347
+ payload = _canonical_bytes(row)
348
+ except (TypeError, ValueError):
349
+ payload = f"noncanonical-row:{index}".encode("ascii")
350
+ digest.update(index.to_bytes(8, "big"))
351
+ digest.update(len(payload).to_bytes(8, "big"))
352
+ digest.update(payload)
353
+ return digest.hexdigest()
354
+
355
+
356
+ def _validate_outcome_response(value: object) -> dict[str, object]:
357
+ if type(value) is not dict or frozenset(value) != _OUTCOME_RESPONSE_FIELDS:
358
+ raise ValueError("provider outcome response has unexpected fields")
359
+ for name in ("requested_model", "resolved_model", "resolved_provider"):
360
+ if type(value[name]) is not str or not value[name].strip():
361
+ raise ValueError(f"provider outcome response {name} is invalid")
362
+ for name in ("provider_response_id", "finish_reason"):
363
+ item = value[name]
364
+ if item is not None and (type(item) is not str or not item.strip()):
365
+ raise ValueError(f"provider outcome response {name} is invalid")
366
+ for name in (
367
+ "input_tokens",
368
+ "output_tokens",
369
+ "reasoning_tokens",
370
+ "cache_read_tokens",
371
+ "cache_write_tokens",
372
+ "latency_ns",
373
+ ):
374
+ if type(value[name]) is not int or value[name] < 0:
375
+ raise ValueError(f"provider outcome response {name} is invalid")
376
+ cost = value["cost_usd"]
377
+ if cost is not None:
378
+ if type(cost) is not str:
379
+ raise ValueError("provider outcome response cost_usd is invalid")
380
+ try:
381
+ parsed = Decimal(cost)
382
+ except InvalidOperation as exc:
383
+ raise ValueError("provider outcome response cost_usd is invalid") from exc
384
+ if not parsed.is_finite() or parsed < 0 or str(parsed) != cost:
385
+ raise ValueError("provider outcome response cost_usd is not canonical")
386
+ return value
387
+
388
+
389
+ def _validate_attempt_request_evidence(
390
+ value: object,
391
+ ) -> AttemptRequestEvidence | None:
392
+ if value is None:
393
+ return None
394
+ if type(value) is not dict or frozenset(value) != _ATTEMPT_REQUEST_EVIDENCE_FIELDS:
395
+ raise ValueError("provider attempt request evidence has unexpected fields")
396
+ variant = value["variant"]
397
+ prompt_sha256 = value["prompt_sha256"]
398
+ attempt_id = value["provider_attempt_id"]
399
+ if type(variant) is not str or type(prompt_sha256) is not str:
400
+ raise ValueError("provider attempt request evidence is invalid")
401
+ physical_id = None
402
+ if attempt_id is not None:
403
+ if type(attempt_id) is not str:
404
+ raise ValueError("provider attempt physical identity is invalid")
405
+ physical_id = ProviderAttemptId(attempt_id)
406
+ return AttemptRequestEvidence(
407
+ variant=AttemptRequestVariant(variant),
408
+ prompt_sha256=prompt_sha256,
409
+ provider_attempt_id=physical_id,
410
+ )
411
+
412
+
413
+ def _validate_attempt_failure(
414
+ value: object,
415
+ *,
416
+ schema_version: int,
417
+ ) -> SanitizedAttemptFailure | None:
418
+ if value is None:
419
+ return None
420
+ expected_fields = (
421
+ _ATTEMPT_FAILURE_FIELDS_V8
422
+ if schema_version >= 8
423
+ else (
424
+ _ATTEMPT_FAILURE_FIELDS_V6
425
+ if schema_version >= 6
426
+ else _ATTEMPT_FAILURE_FIELDS_V5
427
+ )
428
+ )
429
+ if type(value) is not dict or frozenset(value) != expected_fields:
430
+ raise ValueError("provider attempt failure has unexpected fields")
431
+
432
+ issues_value = value["validation_issues"]
433
+ if type(issues_value) is not list:
434
+ raise ValueError("provider attempt validation issues must be a list")
435
+ issues: list[SanitizedValidationIssue] = []
436
+ for issue in issues_value:
437
+ expected_issue_fields = (
438
+ _VALIDATION_ISSUE_FIELDS_V7
439
+ if schema_version >= 7
440
+ else _VALIDATION_ISSUE_FIELDS_V6
441
+ )
442
+ if type(issue) is not dict or frozenset(issue) != expected_issue_fields:
443
+ raise ValueError("provider attempt validation issue has unexpected fields")
444
+ category = issue["category"]
445
+ location = issue["location"]
446
+ reason_code = issue.get("reason_code")
447
+ if (
448
+ type(category) is not str
449
+ or type(location) is not list
450
+ or (reason_code is not None and type(reason_code) is not str)
451
+ ):
452
+ raise ValueError("provider attempt validation issue is invalid")
453
+ issues.append(
454
+ SanitizedValidationIssue(
455
+ category=ValidationIssueCategory(category),
456
+ location=tuple(location),
457
+ reason_code=(
458
+ None
459
+ if reason_code is None
460
+ else ValidationIssueReasonCode(reason_code)
461
+ ),
462
+ )
463
+ )
464
+
465
+ output_mode = value["output_failure_mode"]
466
+ timeout_phase = value["stream_timeout_phase"]
467
+ provider_error_code = value["provider_error_code"] if schema_version >= 6 else None
468
+ exception_provenance_value = (
469
+ value["exception_provenance"] if schema_version >= 8 else None
470
+ )
471
+ for name, item in (
472
+ ("output_failure_mode", output_mode),
473
+ ("stream_timeout_phase", timeout_phase),
474
+ ("provider_error_code", provider_error_code),
475
+ ):
476
+ if item is not None and type(item) is not str:
477
+ raise ValueError(f"provider attempt failure {name} is invalid")
478
+ exception_provenance: SanitizedExceptionProvenance | None = None
479
+ if exception_provenance_value is not None:
480
+ if (
481
+ type(exception_provenance_value) is not dict
482
+ or frozenset(exception_provenance_value)
483
+ != _EXCEPTION_PROVENANCE_FIELDS_V8
484
+ or type(exception_provenance_value["nodes"]) is not list
485
+ or type(exception_provenance_value["truncated"]) is not bool
486
+ ):
487
+ raise ValueError("provider attempt exception provenance is invalid")
488
+ provenance_nodes: list[SanitizedExceptionProvenanceNode] = []
489
+ for raw_node in exception_provenance_value["nodes"]:
490
+ if (
491
+ type(raw_node) is not dict
492
+ or frozenset(raw_node) != _EXCEPTION_PROVENANCE_NODE_FIELDS_V8
493
+ ):
494
+ raise ValueError(
495
+ "provider attempt exception provenance node is invalid"
496
+ )
497
+ parent_index = raw_node["parent_index"]
498
+ link = raw_node["link"]
499
+ family = raw_node["family"]
500
+ fingerprint = raw_node["type_identity_sha256"]
501
+ if (
502
+ (parent_index is not None and type(parent_index) is not int)
503
+ or type(link) is not str
504
+ or type(family) is not str
505
+ or type(fingerprint) is not str
506
+ ):
507
+ raise ValueError(
508
+ "provider attempt exception provenance node fields are invalid"
509
+ )
510
+ provenance_nodes.append(
511
+ SanitizedExceptionProvenanceNode(
512
+ parent_index=parent_index,
513
+ link=ExceptionProvenanceLink(link),
514
+ family=ExceptionOriginFamily(family),
515
+ type_identity_sha256=fingerprint,
516
+ )
517
+ )
518
+ exception_provenance = SanitizedExceptionProvenance(
519
+ nodes=tuple(provenance_nodes),
520
+ truncated=exception_provenance_value["truncated"],
521
+ )
522
+ return SanitizedAttemptFailure(
523
+ kind=value["kind"],
524
+ retryable=value["retryable"],
525
+ safe_message=value["safe_message"],
526
+ status_code=value["status_code"],
527
+ retry_after_seconds=value["retry_after_seconds"],
528
+ output_failure_mode=(
529
+ None if output_mode is None else StructuredOutputFailureMode(output_mode)
530
+ ),
531
+ validation_issues=tuple(issues),
532
+ stream_timeout_phase=(
533
+ None if timeout_phase is None else StreamTimeoutPhase(timeout_phase)
534
+ ),
535
+ provider_error_code=(
536
+ None
537
+ if provider_error_code is None
538
+ else CanonicalProviderErrorCode(provider_error_code)
539
+ ),
540
+ provider_error_envelope_sha256=(
541
+ value["provider_error_envelope_sha256"] if schema_version >= 6 else None
542
+ ),
543
+ exception_provenance=exception_provenance,
544
+ )
545
+
546
+
547
+ def _validate_outcome_attempt(
548
+ value: object,
549
+ *,
550
+ schema_version: int,
551
+ ) -> tuple[AttemptTelemetry, str | None, bool]:
552
+ if type(value) is not dict or frozenset(value) != _OUTCOME_ATTEMPT_FIELDS:
553
+ raise ValueError("provider outcome attempt has unexpected fields")
554
+ status_value = value["status"]
555
+ if type(status_value) is not str or status_value not in _ATTEMPT_STATUSES:
556
+ raise ValueError("provider attempt status is invalid")
557
+ evidence = _validate_attempt_request_evidence(value["request_evidence"])
558
+ failure = _validate_attempt_failure(
559
+ value["failure"],
560
+ schema_version=schema_version,
561
+ )
562
+ classification_value = value["classification"]
563
+ if classification_value is None:
564
+ if failure is not None:
565
+ raise ValueError("provider attempt failure lacks its classification")
566
+ classification = None
567
+ else:
568
+ if (
569
+ type(classification_value) is not dict
570
+ or frozenset(classification_value) != _ATTEMPT_CLASSIFICATION_FIELDS
571
+ ):
572
+ raise ValueError("provider attempt classification has unexpected fields")
573
+ disposition = classification_value["disposition"]
574
+ reason = classification_value["reason"]
575
+ if type(disposition) is not str or type(reason) is not str:
576
+ raise ValueError("provider attempt classification is invalid")
577
+ retry_after_ns = value["retry_after_ns"]
578
+ if type(retry_after_ns) is not int or retry_after_ns < 0:
579
+ raise ValueError("provider attempt retry_after_ns is invalid")
580
+ classification = RetryClassification(
581
+ disposition=RetryDisposition(disposition),
582
+ reason=RetryReason(reason),
583
+ retry_after=(
584
+ None
585
+ if retry_after_ns == 0
586
+ else RetryAfter(
587
+ delay_ns=retry_after_ns,
588
+ # The durable projection intentionally omits the header's
589
+ # parsing source; either source has identical queue semantics.
590
+ source=RetryAfterSource.DELAY_SECONDS,
591
+ )
592
+ ),
593
+ sanitized_failure=failure,
594
+ )
595
+
596
+ attempt = AttemptTelemetry(
597
+ attempt_number=value["attempt_number"],
598
+ status=AttemptStatus(status_value),
599
+ wait_time_ns=value["wait_time_ns"],
600
+ service_time_ns=value["service_time_ns"],
601
+ will_retry=value["will_retry"],
602
+ policy_backoff_ns=value["policy_backoff_ns"],
603
+ retry_after_ns=value["retry_after_ns"],
604
+ scheduled_delay_ns=value["scheduled_delay_ns"],
605
+ classification=classification,
606
+ error_type=value["error_type"],
607
+ request_evidence=evidence,
608
+ )
609
+ if evidence is None or evidence.provider_attempt_id is None:
610
+ if attempt.status is not AttemptStatus.CANCELLED:
611
+ raise ValueError("non-cancelled attempt lacks physical request evidence")
612
+ return attempt, None, False
613
+ has_provider_evidence = failure is not None and failure.status_code is not None
614
+ return attempt, evidence.provider_attempt_id.value, has_provider_evidence
615
+
616
+
617
+ def _outcome_projection(
618
+ row: object,
619
+ ) -> tuple[str, list[tuple[str, str, str, bool, str, str]]]:
620
+ value = _canonical_mapping(row, label="provider outcome")
621
+ if frozenset(value) != _OUTCOME_FIELDS:
622
+ raise ValueError("provider outcome has unexpected fields")
623
+ schema_version = value["schema_version"]
624
+ if (
625
+ type(schema_version) is not int
626
+ or schema_version not in SUPPORTED_STRUCTURED_GENERATION_OUTCOME_SCHEMA_VERSIONS
627
+ ):
628
+ raise ValueError("provider outcome schema version is unsupported")
629
+ call_id = value["task_id"]
630
+ if type(call_id) is not str:
631
+ raise ValueError("provider outcome lacks task_id")
632
+ LLMCallId(call_id)
633
+ status = value["status"]
634
+ cancellation_reason = value["cancellation_reason"]
635
+ attempts = value["attempts"]
636
+ response = value["response"]
637
+ if type(status) is not str or status not in _TASK_STATUSES:
638
+ raise ValueError("provider outcome status is invalid")
639
+ if type(attempts) is not list:
640
+ raise ValueError("provider outcome attempts/response shape is invalid")
641
+ if response is not None:
642
+ _validate_outcome_response(response)
643
+ if status == "succeeded" and response is None:
644
+ raise ValueError("successful provider outcome lacks its response")
645
+
646
+ projected: list[tuple[str, str, str, bool, str, str]] = []
647
+ telemetry_attempts: list[AttemptTelemetry] = []
648
+ for raw_attempt in attempts:
649
+ attempt, attempt_id, has_provider_evidence = _validate_outcome_attempt(
650
+ raw_attempt,
651
+ schema_version=schema_version,
652
+ )
653
+ telemetry_attempts.append(attempt)
654
+ if attempt_id is not None:
655
+ if attempt.request_evidence is None:
656
+ raise ValueError("physical attempt lacks request evidence")
657
+ projected.append(
658
+ (
659
+ attempt_id,
660
+ call_id,
661
+ attempt.status.value,
662
+ has_provider_evidence or attempt.status is AttemptStatus.SUCCEEDED,
663
+ attempt.request_evidence.prompt_sha256,
664
+ attempt.request_evidence.variant.value,
665
+ )
666
+ )
667
+
668
+ telemetry = TaskTelemetry(
669
+ task_id=call_id,
670
+ queue_time_ns=value["queue_time_ns"],
671
+ service_time_ns=value["service_time_ns"],
672
+ total_time_ns=value["total_time_ns"],
673
+ attempts=tuple(telemetry_attempts),
674
+ )
675
+ status_enum = TaskOutcomeStatus(status)
676
+ if cancellation_reason is not None and type(cancellation_reason) is not str:
677
+ raise ValueError("provider outcome cancellation reason is invalid")
678
+ LLMTaskOutcome(
679
+ status=status_enum,
680
+ telemetry=telemetry,
681
+ response=response,
682
+ cancellation_reason=(
683
+ None
684
+ if cancellation_reason is None
685
+ else CancellationReason(cancellation_reason)
686
+ ),
687
+ )
688
+ succeeded = sum(
689
+ attempt.status is AttemptStatus.SUCCEEDED for attempt in telemetry_attempts
690
+ )
691
+ if status_enum is TaskOutcomeStatus.SUCCEEDED and succeeded != 1:
692
+ raise ValueError("provider response does not join one succeeded attempt")
693
+ if status_enum is not TaskOutcomeStatus.SUCCEEDED and succeeded:
694
+ raise ValueError("non-successful provider outcome has a succeeded attempt")
695
+ return call_id, projected
696
+
697
+
698
+ def validate_structured_generation_outcome_record(
699
+ row: Mapping[str, object],
700
+ ) -> dict[str, object]:
701
+ """Strictly validate and detach one durable queue-outcome projection.
702
+
703
+ This is the public, content-free decoder for records produced by
704
+ :func:`structured_generation_outcome_record`. It deliberately returns the
705
+ canonical JSON projection rather than reconstructing a provider response:
706
+ typed response content lives in the separately authenticated structured
707
+ output-evidence channel.
708
+ """
709
+
710
+ value = _canonical_mapping(row, label="provider outcome")
711
+ _outcome_projection(value)
712
+ return value
713
+
714
+
715
+ def _progress_projection(row: object) -> tuple[str, str, int]:
716
+ value = _canonical_mapping(row, label="provider progress")
717
+ if frozenset(value) != _PROGRESS_FIELDS:
718
+ raise ValueError("provider progress has unexpected fields")
719
+ if value["schema_version"] != 1:
720
+ raise ValueError("provider progress schema version is unsupported")
721
+ call_id = value["call_id"]
722
+ attempt_id = value["provider_attempt_id"]
723
+ sequence = value["sequence"]
724
+ if type(call_id) is not str or type(attempt_id) is not str:
725
+ raise ValueError("provider progress lacks call/attempt identity")
726
+ kind = value["kind"]
727
+ channel = value["channel"]
728
+ if type(kind) is not str or type(channel) is not str:
729
+ raise ValueError("provider progress kind/channel is invalid")
730
+ progress = StructuredStreamProgress(
731
+ call_id=call_id,
732
+ provider_attempt_id=attempt_id,
733
+ sequence=sequence,
734
+ kind=StructuredStreamProgressKind(kind),
735
+ channel=StructuredStreamChannel(channel),
736
+ elapsed_ns=value["elapsed_ns"],
737
+ event_content_utf8_bytes=value["event_content_utf8_bytes"],
738
+ cumulative_content_utf8_bytes=value["cumulative_content_utf8_bytes"],
739
+ rolling_content_sha256=value["rolling_content_sha256"],
740
+ )
741
+ progress.__post_init__()
742
+ return attempt_id, call_id, sequence
743
+
744
+
745
+ def _duplicates(values: Sequence[str]) -> list[str]:
746
+ return sorted(value for value, count in Counter(values).items() if count != 1)
747
+
748
+
749
+ def _logical_request_projection(row: object) -> dict[str, object]:
750
+ value = validate_structured_generation_request_evidence_record(
751
+ _canonical_mapping(row, label="logical request evidence")
752
+ )
753
+ return {
754
+ "call_id": value["call_id"],
755
+ "operation": value["operation"],
756
+ "prompt_sha256": value["wire_prompt_sha256"],
757
+ "prompt_utf8_bytes": value["prompt_utf8_bytes"],
758
+ "output_tool_name": value["output_tool_name"],
759
+ "logical_output_schema_sha256": value["output_schema_sha256"],
760
+ "logical_output_schema_utf8_bytes": value["output_schema_utf8_bytes"],
761
+ "max_completion_tokens": value["max_output_tokens"],
762
+ "requested_temperature_hex": value["temperature_hex"],
763
+ "request_evidence_sha256": value["request_evidence_sha256"],
764
+ }
765
+
766
+
767
+ def _manifest_logical_projection(value: Mapping[str, object]) -> dict[str, object]:
768
+ message = value["message"]
769
+ tool = value["tool"]
770
+ request_contract = value["request_contract"]
771
+ settings = value["settings"]
772
+ assert isinstance(message, Mapping)
773
+ assert isinstance(tool, Mapping)
774
+ assert isinstance(request_contract, Mapping)
775
+ assert isinstance(settings, Mapping)
776
+ return {
777
+ "call_id": value["call_id"],
778
+ "operation": value["operation"],
779
+ "prompt_sha256": message["content_sha256"],
780
+ "prompt_utf8_bytes": message["content_utf8_bytes"],
781
+ "output_tool_name": tool["name"],
782
+ "logical_output_schema_sha256": request_contract[
783
+ "logical_output_schema_sha256"
784
+ ],
785
+ "logical_output_schema_utf8_bytes": request_contract[
786
+ "logical_output_schema_utf8_bytes"
787
+ ],
788
+ "max_completion_tokens": settings["max_completion_tokens"],
789
+ "requested_temperature_hex": request_contract["requested_temperature_hex"],
790
+ }
791
+
792
+
793
+ def _validated_expected_framework_versions(
794
+ value: Mapping[str, object] | None,
795
+ ) -> dict[str, object] | None:
796
+ if value is None:
797
+ return None
798
+ record = _canonical_mapping(value, label="expected framework versions")
799
+ if frozenset(record) != _FRAMEWORK_VERSION_FIELDS or any(
800
+ type(item) is not str or not item or item != item.strip()
801
+ for item in record.values()
802
+ ):
803
+ raise ValueError("expected framework versions violate the closed schema")
804
+ return record
805
+
806
+
807
+ def _validated_expected_transport_settings(
808
+ value: Mapping[str, object] | None,
809
+ ) -> dict[str, object] | None:
810
+ if value is None:
811
+ return None
812
+ record = _canonical_mapping(value, label="expected transport settings")
813
+ if frozenset(record) != _EXPECTED_TRANSPORT_SETTING_FIELDS:
814
+ raise ValueError("expected transport settings violate the closed schema")
815
+ return record
816
+
817
+
818
+ def build_provider_attempt_terminal_join_receipt(
819
+ *,
820
+ logical_requests: Sequence[Mapping[str, object]] = (),
821
+ outbound_manifests: Sequence[Mapping[str, object]],
822
+ terminal_outcomes: Sequence[Mapping[str, object]],
823
+ progress_rows: Sequence[Mapping[str, object]],
824
+ explicit_pre_transport_failures: Sequence[Mapping[str, object]] = (),
825
+ expected_framework_versions: Mapping[str, object] | None = None,
826
+ expected_transport_settings: Mapping[str, object] | None = None,
827
+ ) -> dict[str, object]:
828
+ """Build a redacted terminal join; mismatches yield ``join_valid=False``.
829
+
830
+ Every queue attempt carrying a physical ID requires one outbound manifest,
831
+ unless a separately authenticated record affirmatively proves it failed
832
+ before HTTP dispatch. Missing manifests are never treated as such proof.
833
+ """
834
+
835
+ collections = (
836
+ logical_requests,
837
+ outbound_manifests,
838
+ terminal_outcomes,
839
+ progress_rows,
840
+ explicit_pre_transport_failures,
841
+ )
842
+ if any(not isinstance(value, Sequence) for value in collections):
843
+ raise TypeError("provider-attempt join inputs must be sequences")
844
+
845
+ expected_frameworks = _validated_expected_framework_versions(
846
+ expected_framework_versions
847
+ )
848
+ expected_settings = _validated_expected_transport_settings(
849
+ expected_transport_settings
850
+ )
851
+
852
+ malformed_logical_requests: list[int] = []
853
+ malformed_manifests: list[int] = []
854
+ malformed_outcomes: list[int] = []
855
+ malformed_progress: list[int] = []
856
+ malformed_pretransport: list[int] = []
857
+ logical_entries: list[dict[str, object]] = []
858
+ manifest_entries: list[dict[str, object]] = []
859
+ outcome_entries: list[tuple[str, str, str, bool, str, str]] = []
860
+ progress_entries: list[tuple[str, str, int]] = []
861
+ pretransport_entries: list[tuple[str, str, str]] = []
862
+
863
+ for index, row in enumerate(logical_requests):
864
+ try:
865
+ logical_entries.append(_logical_request_projection(row))
866
+ except (TypeError, ValueError):
867
+ malformed_logical_requests.append(index)
868
+ for index, row in enumerate(outbound_manifests):
869
+ try:
870
+ manifest = validate_openrouter_outbound_request_manifest_record(row)
871
+ manifest_entries.append(manifest)
872
+ except (TypeError, ValueError):
873
+ malformed_manifests.append(index)
874
+ for index, row in enumerate(terminal_outcomes):
875
+ try:
876
+ _, attempts = _outcome_projection(row)
877
+ outcome_entries.extend(attempts)
878
+ except (TypeError, ValueError):
879
+ malformed_outcomes.append(index)
880
+ for index, row in enumerate(progress_rows):
881
+ try:
882
+ progress_entries.append(_progress_projection(row))
883
+ except (TypeError, ValueError):
884
+ malformed_progress.append(index)
885
+ for index, row in enumerate(explicit_pre_transport_failures):
886
+ try:
887
+ evidence = validate_explicit_pre_transport_failure_evidence_record(row)
888
+ pretransport_entries.append(
889
+ (
890
+ evidence["provider_attempt_id"],
891
+ evidence["call_id"],
892
+ evidence["evidence_sha256"],
893
+ )
894
+ )
895
+ except (TypeError, ValueError):
896
+ malformed_pretransport.append(index)
897
+
898
+ logical_call_ids = [str(value["call_id"]) for value in logical_entries]
899
+ manifest_ids = [str(value["provider_attempt_id"]) for value in manifest_entries]
900
+ outcome_ids = [value[0] for value in outcome_entries]
901
+ progress_ids = [value[0] for value in progress_entries]
902
+ pretransport_ids = [value[0] for value in pretransport_entries]
903
+ manifest_set = set(manifest_ids)
904
+ outcome_set = set(outcome_ids)
905
+ progress_set = set(progress_ids)
906
+ pretransport_set = set(pretransport_ids)
907
+ provider_evidence_set = {
908
+ attempt_id
909
+ for attempt_id, _, _, has_evidence, _, _ in outcome_entries
910
+ if has_evidence
911
+ } | progress_set
912
+ affirmative_pretransport_set = pretransport_set - provider_evidence_set
913
+ required_manifest_set = outcome_set - affirmative_pretransport_set
914
+
915
+ logical_by_call: dict[str, list[dict[str, object]]] = defaultdict(list)
916
+ for value in logical_entries:
917
+ logical_by_call[str(value["call_id"])].append(value)
918
+ attempt_request_by_id = {
919
+ attempt_id: (prompt_sha256, variant)
920
+ for attempt_id, _, _, _, prompt_sha256, variant in outcome_entries
921
+ }
922
+ missing_logical_requests: list[str] = []
923
+ logical_physical_mismatches: list[str] = []
924
+ framework_version_mismatches: list[str] = []
925
+ transport_settings_mismatches: list[str] = []
926
+ for manifest in manifest_entries:
927
+ attempt_id = str(manifest["provider_attempt_id"])
928
+ matching = logical_by_call.get(str(manifest["call_id"]), [])
929
+ if not matching:
930
+ missing_logical_requests.append(attempt_id)
931
+ elif len(matching) == 1:
932
+ observed = _manifest_logical_projection(manifest)
933
+ expected = {
934
+ name: item
935
+ for name, item in matching[0].items()
936
+ if name != "request_evidence_sha256"
937
+ }
938
+ attempt_request = attempt_request_by_id.get(attempt_id)
939
+ if attempt_request is None:
940
+ logical_physical_mismatches.append(attempt_id)
941
+ else:
942
+ attempt_prompt_sha256, variant = attempt_request
943
+ if variant == AttemptRequestVariant.ORIGINAL.value:
944
+ mismatch = (
945
+ attempt_prompt_sha256 != expected["prompt_sha256"]
946
+ or observed != expected
947
+ )
948
+ else:
949
+ # Schema-repair variants preserve every logical request
950
+ # field except the provider-facing prompt, whose exact
951
+ # digest is committed by the per-attempt queue evidence.
952
+ expected["prompt_sha256"] = attempt_prompt_sha256
953
+ observed.pop("prompt_utf8_bytes")
954
+ expected.pop("prompt_utf8_bytes")
955
+ mismatch = observed != expected
956
+ if mismatch:
957
+ logical_physical_mismatches.append(attempt_id)
958
+ if (
959
+ expected_frameworks is None
960
+ or manifest["framework_versions"] != expected_frameworks
961
+ ):
962
+ framework_version_mismatches.append(attempt_id)
963
+ settings = manifest["settings"]
964
+ if (
965
+ expected_settings is None
966
+ or type(settings) is not dict
967
+ or any(
968
+ settings[name] != expected_settings[name] for name in expected_settings
969
+ )
970
+ ):
971
+ transport_settings_mismatches.append(attempt_id)
972
+
973
+ call_ids_by_attempt: dict[str, set[str]] = defaultdict(set)
974
+ for manifest in manifest_entries:
975
+ call_ids_by_attempt[str(manifest["provider_attempt_id"])].add(
976
+ str(manifest["call_id"])
977
+ )
978
+ for attempt_id, call_id, _, _, _, _ in outcome_entries:
979
+ call_ids_by_attempt[attempt_id].add(call_id)
980
+ for attempt_id, call_id, _ in progress_entries:
981
+ call_ids_by_attempt[attempt_id].add(call_id)
982
+ for attempt_id, call_id, _ in pretransport_entries:
983
+ call_ids_by_attempt[attempt_id].add(call_id)
984
+
985
+ progress_sequences: dict[str, list[int]] = defaultdict(list)
986
+ for attempt_id, _, sequence in progress_entries:
987
+ progress_sequences[attempt_id].append(sequence)
988
+ canonical_progress_sequences = {
989
+ attempt_id: sorted(sequences)
990
+ for attempt_id, sequences in sorted(progress_sequences.items())
991
+ }
992
+ duplicate_progress_sequences = sorted(
993
+ attempt_id
994
+ for attempt_id, sequences in canonical_progress_sequences.items()
995
+ if len(sequences) != len(set(sequences))
996
+ )
997
+ noncontiguous_progress_sequences = sorted(
998
+ attempt_id
999
+ for attempt_id, sequences in canonical_progress_sequences.items()
1000
+ if sequences != list(range(1, len(sequences) + 1))
1001
+ )
1002
+
1003
+ shared_ids = manifest_set | outcome_set | progress_set | pretransport_set
1004
+ call_mismatches = sorted(
1005
+ attempt_id
1006
+ for attempt_id in shared_ids
1007
+ if len(call_ids_by_attempt[attempt_id]) > 1
1008
+ )
1009
+
1010
+ duplicate_logical_call_ids = _duplicates(logical_call_ids)
1011
+ duplicate_manifest_ids = _duplicates(manifest_ids)
1012
+ duplicate_outcome_ids = _duplicates(outcome_ids)
1013
+ duplicate_pretransport_ids = _duplicates(pretransport_ids)
1014
+ missing_manifests = sorted(required_manifest_set - manifest_set)
1015
+ orphan_manifests = sorted(manifest_set - outcome_set)
1016
+ progress_without_manifest = sorted(progress_set - manifest_set)
1017
+ progress_without_outcome = sorted(progress_set - outcome_set)
1018
+ provider_evidence_without_manifest = sorted(provider_evidence_set - manifest_set)
1019
+ pretransport_with_manifest = sorted(pretransport_set & manifest_set)
1020
+ pretransport_with_provider_evidence = sorted(
1021
+ pretransport_set & provider_evidence_set
1022
+ )
1023
+ pretransport_without_outcome = sorted(pretransport_set - outcome_set)
1024
+
1025
+ defects = (
1026
+ malformed_logical_requests,
1027
+ malformed_manifests,
1028
+ malformed_outcomes,
1029
+ malformed_progress,
1030
+ malformed_pretransport,
1031
+ duplicate_logical_call_ids,
1032
+ duplicate_manifest_ids,
1033
+ duplicate_outcome_ids,
1034
+ duplicate_pretransport_ids,
1035
+ missing_logical_requests,
1036
+ logical_physical_mismatches,
1037
+ framework_version_mismatches,
1038
+ transport_settings_mismatches,
1039
+ missing_manifests,
1040
+ orphan_manifests,
1041
+ progress_without_manifest,
1042
+ progress_without_outcome,
1043
+ duplicate_progress_sequences,
1044
+ noncontiguous_progress_sequences,
1045
+ provider_evidence_without_manifest,
1046
+ pretransport_with_manifest,
1047
+ pretransport_with_provider_evidence,
1048
+ pretransport_without_outcome,
1049
+ call_mismatches,
1050
+ )
1051
+ join_valid = not any(defects)
1052
+ record: dict[str, object] = {
1053
+ "schema_version": PROVIDER_ATTEMPT_TERMINAL_JOIN_SCHEMA_VERSION,
1054
+ "contract_id": PROVIDER_ATTEMPT_TERMINAL_JOIN_CONTRACT_ID,
1055
+ "source_counts": {
1056
+ "logical_requests": len(logical_requests),
1057
+ "outbound_manifests": len(outbound_manifests),
1058
+ "terminal_outcomes": len(terminal_outcomes),
1059
+ "outcome_attempts_with_physical_ids": len(outcome_entries),
1060
+ "progress_rows": len(progress_rows),
1061
+ "explicit_pre_transport_failures": len(explicit_pre_transport_failures),
1062
+ },
1063
+ "source_sha256": {
1064
+ "logical_requests": _collection_sha256(logical_requests),
1065
+ "outbound_manifests": _collection_sha256(outbound_manifests),
1066
+ "terminal_outcomes": _collection_sha256(terminal_outcomes),
1067
+ "progress_rows": _collection_sha256(progress_rows),
1068
+ "explicit_pre_transport_failures": _collection_sha256(
1069
+ explicit_pre_transport_failures
1070
+ ),
1071
+ },
1072
+ "expected_framework_versions": expected_frameworks,
1073
+ "expected_transport_settings": expected_settings,
1074
+ "logical_request_call_ids": sorted(set(logical_call_ids)),
1075
+ "provider_attempt_ids": {
1076
+ "dispatched": sorted(manifest_set),
1077
+ "terminal_outcomes": sorted(outcome_set),
1078
+ "progress": sorted(progress_set),
1079
+ "provider_status_response_or_progress": sorted(provider_evidence_set),
1080
+ "explicit_pre_transport_failures": sorted(pretransport_set),
1081
+ },
1082
+ "call_ids_by_provider_attempt": {
1083
+ attempt_id: sorted(call_ids_by_attempt[attempt_id])
1084
+ for attempt_id in sorted(shared_ids)
1085
+ },
1086
+ "progress_sequences_by_provider_attempt": canonical_progress_sequences,
1087
+ "malformed_row_indices": {
1088
+ "logical_requests": malformed_logical_requests,
1089
+ "outbound_manifests": malformed_manifests,
1090
+ "terminal_outcomes": malformed_outcomes,
1091
+ "progress_rows": malformed_progress,
1092
+ "explicit_pre_transport_failures": malformed_pretransport,
1093
+ },
1094
+ "defects": {
1095
+ "duplicate_logical_request_call_ids": duplicate_logical_call_ids,
1096
+ "duplicate_outbound_manifest_attempt_ids": duplicate_manifest_ids,
1097
+ "duplicate_outcome_attempt_ids": duplicate_outcome_ids,
1098
+ "duplicate_pre_transport_attempt_ids": duplicate_pretransport_ids,
1099
+ "missing_logical_request_attempt_ids": sorted(
1100
+ set(missing_logical_requests)
1101
+ ),
1102
+ "logical_physical_mismatch_attempt_ids": sorted(
1103
+ set(logical_physical_mismatches)
1104
+ ),
1105
+ "framework_version_mismatch_attempt_ids": sorted(
1106
+ set(framework_version_mismatches)
1107
+ ),
1108
+ "transport_settings_mismatch_attempt_ids": sorted(
1109
+ set(transport_settings_mismatches)
1110
+ ),
1111
+ "missing_manifest_attempt_ids": missing_manifests,
1112
+ "orphan_manifest_attempt_ids": orphan_manifests,
1113
+ "progress_without_manifest_attempt_ids": progress_without_manifest,
1114
+ "progress_without_outcome_attempt_ids": progress_without_outcome,
1115
+ "progress_duplicate_sequence_attempt_ids": (duplicate_progress_sequences),
1116
+ "progress_noncontiguous_sequence_attempt_ids": (
1117
+ noncontiguous_progress_sequences
1118
+ ),
1119
+ "provider_evidence_without_manifest_attempt_ids": (
1120
+ provider_evidence_without_manifest
1121
+ ),
1122
+ "pre_transport_with_manifest_attempt_ids": pretransport_with_manifest,
1123
+ "pre_transport_with_provider_evidence_attempt_ids": (
1124
+ pretransport_with_provider_evidence
1125
+ ),
1126
+ "pre_transport_without_outcome_attempt_ids": (pretransport_without_outcome),
1127
+ "call_id_mismatch_attempt_ids": call_mismatches,
1128
+ },
1129
+ "invariants": {
1130
+ "logical_request_exactly_once_per_dispatched_attempt": (
1131
+ not duplicate_logical_call_ids and not missing_logical_requests
1132
+ ),
1133
+ "logical_physical_request_fields_exact": (not logical_physical_mismatches),
1134
+ "framework_versions_join_qualification_exact": (
1135
+ not framework_version_mismatches
1136
+ ),
1137
+ "transport_settings_join_selected_profile_exact": (
1138
+ not transport_settings_mismatches
1139
+ ),
1140
+ "manifest_exactly_once_per_dispatched_attempt": (
1141
+ not duplicate_manifest_ids
1142
+ ),
1143
+ "outcome_attempt_identity_exactly_once": not duplicate_outcome_ids,
1144
+ "every_physical_outcome_attempt_accounted_for": not missing_manifests,
1145
+ "every_dispatched_attempt_has_terminal_outcome": not orphan_manifests,
1146
+ "provider_evidence_always_has_manifest": (
1147
+ not provider_evidence_without_manifest
1148
+ ),
1149
+ "progress_joins_manifest_and_outcome": (
1150
+ not progress_without_manifest and not progress_without_outcome
1151
+ ),
1152
+ "progress_sequence_unique_and_contiguous": (
1153
+ not duplicate_progress_sequences
1154
+ and not noncontiguous_progress_sequences
1155
+ ),
1156
+ "explicit_pre_transport_evidence_consistent": (
1157
+ not duplicate_pretransport_ids
1158
+ and not pretransport_with_manifest
1159
+ and not pretransport_with_provider_evidence
1160
+ and not pretransport_without_outcome
1161
+ ),
1162
+ "explicit_pre_transport_is_affirmative_not_inferred": True,
1163
+ "call_id_join_exact": not call_mismatches,
1164
+ # Accepted source rows have exact, content-safe durable schemas.
1165
+ # Rejected rows contribute only an index and a collection digest;
1166
+ # no source value is copied into this receipt projection.
1167
+ "raw_provider_content_persisted": False,
1168
+ },
1169
+ "join_valid": join_valid,
1170
+ }
1171
+ record["join_receipt_sha256"] = _domain_sha256(_JOIN_DOMAIN, record)
1172
+ return validate_provider_attempt_terminal_join_receipt(record)
1173
+
1174
+
1175
+ def validate_provider_attempt_terminal_join_receipt(
1176
+ value: Mapping[str, object],
1177
+ ) -> dict[str, object]:
1178
+ record = _canonical_mapping(value, label="provider-attempt terminal join")
1179
+ if frozenset(record) != {
1180
+ "schema_version",
1181
+ "contract_id",
1182
+ "source_counts",
1183
+ "source_sha256",
1184
+ "expected_framework_versions",
1185
+ "expected_transport_settings",
1186
+ "logical_request_call_ids",
1187
+ "provider_attempt_ids",
1188
+ "call_ids_by_provider_attempt",
1189
+ "progress_sequences_by_provider_attempt",
1190
+ "malformed_row_indices",
1191
+ "defects",
1192
+ "invariants",
1193
+ "join_valid",
1194
+ "join_receipt_sha256",
1195
+ }:
1196
+ raise ValueError("provider-attempt terminal join has unexpected fields")
1197
+ if (
1198
+ record["schema_version"] != PROVIDER_ATTEMPT_TERMINAL_JOIN_SCHEMA_VERSION
1199
+ or record["contract_id"] != PROVIDER_ATTEMPT_TERMINAL_JOIN_CONTRACT_ID
1200
+ or type(record["join_valid"]) is not bool
1201
+ ):
1202
+ raise ValueError("provider-attempt terminal join contract drifted")
1203
+ for name in (
1204
+ "source_counts",
1205
+ "source_sha256",
1206
+ "provider_attempt_ids",
1207
+ "call_ids_by_provider_attempt",
1208
+ "progress_sequences_by_provider_attempt",
1209
+ "malformed_row_indices",
1210
+ "defects",
1211
+ "invariants",
1212
+ ):
1213
+ if type(record[name]) is not dict:
1214
+ raise ValueError(f"{name} must be an exact object")
1215
+ source_counts = record["source_counts"]
1216
+ source_sha256 = record["source_sha256"]
1217
+ provider_attempt_ids = record["provider_attempt_ids"]
1218
+ malformed = record["malformed_row_indices"]
1219
+ defects = record["defects"]
1220
+ invariants = record["invariants"]
1221
+ call_ids_by_attempt = record["call_ids_by_provider_attempt"]
1222
+ progress_sequences = record["progress_sequences_by_provider_attempt"]
1223
+ assert type(source_counts) is dict
1224
+ assert type(source_sha256) is dict
1225
+ assert type(provider_attempt_ids) is dict
1226
+ assert type(malformed) is dict
1227
+ assert type(defects) is dict
1228
+ assert type(invariants) is dict
1229
+ assert type(call_ids_by_attempt) is dict
1230
+ assert type(progress_sequences) is dict
1231
+
1232
+ if frozenset(source_counts) != _SOURCE_COUNT_FIELDS or any(
1233
+ type(item) is not int or item < 0 for item in source_counts.values()
1234
+ ):
1235
+ raise ValueError("provider-attempt join source counts are invalid")
1236
+ if frozenset(source_sha256) != _SOURCE_FIELDS:
1237
+ raise ValueError("provider-attempt join source hashes are incomplete")
1238
+ for name, digest in source_sha256.items():
1239
+ _require_sha256(digest, label=f"source_sha256.{name}")
1240
+
1241
+ expected_frameworks = _validated_expected_framework_versions(
1242
+ record["expected_framework_versions"]
1243
+ )
1244
+ expected_settings = _validated_expected_transport_settings(
1245
+ record["expected_transport_settings"]
1246
+ )
1247
+ if expected_frameworks != record["expected_framework_versions"]:
1248
+ raise ValueError("expected framework versions are not canonical")
1249
+ if expected_settings != record["expected_transport_settings"]:
1250
+ raise ValueError("expected transport settings are not canonical")
1251
+
1252
+ def exact_identity_list(
1253
+ item: object,
1254
+ *,
1255
+ label: str,
1256
+ constructor: object,
1257
+ unique: bool = True,
1258
+ ) -> list[str]:
1259
+ if type(item) is not list or any(type(entry) is not str for entry in item):
1260
+ raise ValueError(f"{label} must be a list of exact identifiers")
1261
+ values = list(item)
1262
+ if values != sorted(values) or (unique and len(values) != len(set(values))):
1263
+ raise ValueError(f"{label} must be canonical sorted identifiers")
1264
+ for entry in values:
1265
+ try:
1266
+ constructor(entry) # type: ignore[operator]
1267
+ except (TypeError, ValueError) as exc:
1268
+ raise ValueError(f"{label} contains an invalid identifier") from exc
1269
+ return values
1270
+
1271
+ logical_call_ids = exact_identity_list(
1272
+ record["logical_request_call_ids"],
1273
+ label="logical_request_call_ids",
1274
+ constructor=LLMCallId,
1275
+ )
1276
+ if frozenset(provider_attempt_ids) != _PROVIDER_ATTEMPT_ID_FIELDS:
1277
+ raise ValueError("provider_attempt_ids violates the closed schema")
1278
+ attempt_sets: dict[str, set[str]] = {}
1279
+ for name in sorted(_PROVIDER_ATTEMPT_ID_FIELDS):
1280
+ attempt_sets[name] = set(
1281
+ exact_identity_list(
1282
+ provider_attempt_ids[name],
1283
+ label=f"provider_attempt_ids.{name}",
1284
+ constructor=ProviderAttemptId,
1285
+ )
1286
+ )
1287
+
1288
+ shared_ids = set().union(*attempt_sets.values())
1289
+ if set(call_ids_by_attempt) != shared_ids:
1290
+ raise ValueError("call ID summary does not cover exact attempt identities")
1291
+ normalized_call_summary: dict[str, list[str]] = {}
1292
+ for attempt_id, call_ids in call_ids_by_attempt.items():
1293
+ ProviderAttemptId(attempt_id)
1294
+ normalized_call_summary[attempt_id] = exact_identity_list(
1295
+ call_ids,
1296
+ label=f"call_ids_by_provider_attempt.{attempt_id}",
1297
+ constructor=LLMCallId,
1298
+ )
1299
+ if not normalized_call_summary[attempt_id]:
1300
+ raise ValueError("attempt call ID summary cannot be empty")
1301
+
1302
+ progress_set = attempt_sets["progress"]
1303
+ if set(progress_sequences) != progress_set:
1304
+ raise ValueError("progress sequence summary does not cover progress attempts")
1305
+ normalized_sequences: dict[str, list[int]] = {}
1306
+ for attempt_id, sequences in progress_sequences.items():
1307
+ ProviderAttemptId(attempt_id)
1308
+ if (
1309
+ type(sequences) is not list
1310
+ or not sequences
1311
+ or any(type(sequence) is not int or sequence < 1 for sequence in sequences)
1312
+ or sequences != sorted(sequences)
1313
+ ):
1314
+ raise ValueError("progress sequence summary is invalid")
1315
+ normalized_sequences[attempt_id] = list(sequences)
1316
+
1317
+ if frozenset(malformed) != _SOURCE_FIELDS:
1318
+ raise ValueError("malformed row indices violate the closed schema")
1319
+ for name in sorted(_SOURCE_FIELDS):
1320
+ indices = malformed[name]
1321
+ if (
1322
+ type(indices) is not list
1323
+ or any(type(index) is not int or index < 0 for index in indices)
1324
+ or indices != sorted(set(indices))
1325
+ or any(index >= source_counts[name] for index in indices)
1326
+ ):
1327
+ raise ValueError(f"malformed_row_indices.{name} is invalid")
1328
+
1329
+ if frozenset(defects) != _DEFECT_FIELDS:
1330
+ raise ValueError("provider-attempt join defects violate the closed schema")
1331
+ normalized_defects: dict[str, list[str]] = {}
1332
+ for name in sorted(_DEFECT_ATTEMPT_ID_FIELDS):
1333
+ normalized_defects[name] = exact_identity_list(
1334
+ defects[name],
1335
+ label=f"defects.{name}",
1336
+ constructor=ProviderAttemptId,
1337
+ )
1338
+ for name in sorted(_DEFECT_CALL_ID_FIELDS):
1339
+ normalized_defects[name] = exact_identity_list(
1340
+ defects[name],
1341
+ label=f"defects.{name}",
1342
+ constructor=LLMCallId,
1343
+ )
1344
+
1345
+ if frozenset(invariants) != _INVARIANT_FIELDS or any(
1346
+ type(item) is not bool for item in invariants.values()
1347
+ ):
1348
+ raise ValueError("provider-attempt join invariants violate the closed schema")
1349
+
1350
+ dispatched = attempt_sets["dispatched"]
1351
+ outcomes = attempt_sets["terminal_outcomes"]
1352
+ provider_evidence = attempt_sets["provider_status_response_or_progress"]
1353
+ pretransport = attempt_sets["explicit_pre_transport_failures"]
1354
+ if not progress_set.issubset(provider_evidence) or not provider_evidence.issubset(
1355
+ outcomes | progress_set
1356
+ ):
1357
+ raise ValueError("provider evidence identity summary is inconsistent")
1358
+ if any(
1359
+ value not in dispatched
1360
+ for value in normalized_defects["missing_logical_request_attempt_ids"]
1361
+ + normalized_defects["logical_physical_mismatch_attempt_ids"]
1362
+ + normalized_defects["framework_version_mismatch_attempt_ids"]
1363
+ + normalized_defects["transport_settings_mismatch_attempt_ids"]
1364
+ ):
1365
+ raise ValueError("outbound defect names a non-dispatched attempt")
1366
+ if any(
1367
+ value not in progress_set
1368
+ for value in normalized_defects["progress_duplicate_sequence_attempt_ids"]
1369
+ + normalized_defects["progress_noncontiguous_sequence_attempt_ids"]
1370
+ ):
1371
+ raise ValueError("progress sequence defect names a non-progress attempt")
1372
+ if any(
1373
+ value not in shared_ids
1374
+ for value in normalized_defects["call_id_mismatch_attempt_ids"]
1375
+ ):
1376
+ raise ValueError("call mismatch names an unknown attempt")
1377
+ if any(
1378
+ value not in logical_call_ids
1379
+ for value in normalized_defects["duplicate_logical_request_call_ids"]
1380
+ ):
1381
+ raise ValueError("duplicate logical request names an unknown call")
1382
+
1383
+ duplicate_progress = sorted(
1384
+ attempt_id
1385
+ for attempt_id, sequences in normalized_sequences.items()
1386
+ if len(sequences) != len(set(sequences))
1387
+ )
1388
+ noncontiguous_progress = sorted(
1389
+ attempt_id
1390
+ for attempt_id, sequences in normalized_sequences.items()
1391
+ if sequences != list(range(1, len(sequences) + 1))
1392
+ )
1393
+ call_mismatches = sorted(
1394
+ attempt_id
1395
+ for attempt_id, call_ids in normalized_call_summary.items()
1396
+ if len(call_ids) > 1
1397
+ )
1398
+ affirmative_pretransport = pretransport - provider_evidence
1399
+ derived_defects = {
1400
+ "missing_manifest_attempt_ids": sorted(
1401
+ (outcomes - affirmative_pretransport) - dispatched
1402
+ ),
1403
+ "orphan_manifest_attempt_ids": sorted(dispatched - outcomes),
1404
+ "progress_without_manifest_attempt_ids": sorted(progress_set - dispatched),
1405
+ "progress_without_outcome_attempt_ids": sorted(progress_set - outcomes),
1406
+ "progress_duplicate_sequence_attempt_ids": duplicate_progress,
1407
+ "progress_noncontiguous_sequence_attempt_ids": noncontiguous_progress,
1408
+ "provider_evidence_without_manifest_attempt_ids": sorted(
1409
+ provider_evidence - dispatched
1410
+ ),
1411
+ "pre_transport_with_manifest_attempt_ids": sorted(pretransport & dispatched),
1412
+ "pre_transport_with_provider_evidence_attempt_ids": sorted(
1413
+ pretransport & provider_evidence
1414
+ ),
1415
+ "pre_transport_without_outcome_attempt_ids": sorted(pretransport - outcomes),
1416
+ "call_id_mismatch_attempt_ids": call_mismatches,
1417
+ }
1418
+ if any(
1419
+ normalized_defects[name] != expected
1420
+ for name, expected in derived_defects.items()
1421
+ ):
1422
+ raise ValueError("provider-attempt relationship defects are inconsistent")
1423
+
1424
+ expected_invariants = {
1425
+ "logical_request_exactly_once_per_dispatched_attempt": (
1426
+ not normalized_defects["duplicate_logical_request_call_ids"]
1427
+ and not normalized_defects["missing_logical_request_attempt_ids"]
1428
+ ),
1429
+ "logical_physical_request_fields_exact": not normalized_defects[
1430
+ "logical_physical_mismatch_attempt_ids"
1431
+ ],
1432
+ "framework_versions_join_qualification_exact": not normalized_defects[
1433
+ "framework_version_mismatch_attempt_ids"
1434
+ ],
1435
+ "transport_settings_join_selected_profile_exact": not normalized_defects[
1436
+ "transport_settings_mismatch_attempt_ids"
1437
+ ],
1438
+ "manifest_exactly_once_per_dispatched_attempt": not normalized_defects[
1439
+ "duplicate_outbound_manifest_attempt_ids"
1440
+ ],
1441
+ "outcome_attempt_identity_exactly_once": not normalized_defects[
1442
+ "duplicate_outcome_attempt_ids"
1443
+ ],
1444
+ "every_physical_outcome_attempt_accounted_for": not normalized_defects[
1445
+ "missing_manifest_attempt_ids"
1446
+ ],
1447
+ "every_dispatched_attempt_has_terminal_outcome": not normalized_defects[
1448
+ "orphan_manifest_attempt_ids"
1449
+ ],
1450
+ "provider_evidence_always_has_manifest": not normalized_defects[
1451
+ "provider_evidence_without_manifest_attempt_ids"
1452
+ ],
1453
+ "progress_joins_manifest_and_outcome": (
1454
+ not normalized_defects["progress_without_manifest_attempt_ids"]
1455
+ and not normalized_defects["progress_without_outcome_attempt_ids"]
1456
+ ),
1457
+ "progress_sequence_unique_and_contiguous": (
1458
+ not normalized_defects["progress_duplicate_sequence_attempt_ids"]
1459
+ and not normalized_defects["progress_noncontiguous_sequence_attempt_ids"]
1460
+ ),
1461
+ "explicit_pre_transport_evidence_consistent": (
1462
+ not normalized_defects["duplicate_pre_transport_attempt_ids"]
1463
+ and not normalized_defects["pre_transport_with_manifest_attempt_ids"]
1464
+ and not normalized_defects[
1465
+ "pre_transport_with_provider_evidence_attempt_ids"
1466
+ ]
1467
+ and not normalized_defects["pre_transport_without_outcome_attempt_ids"]
1468
+ ),
1469
+ "explicit_pre_transport_is_affirmative_not_inferred": True,
1470
+ "call_id_join_exact": not normalized_defects["call_id_mismatch_attempt_ids"],
1471
+ # The receipt validator is itself closed-schema and the builder copies
1472
+ # only the validated identity/counter projections authenticated above.
1473
+ "raw_provider_content_persisted": False,
1474
+ }
1475
+ if invariants != expected_invariants:
1476
+ raise ValueError("provider-attempt join invariant projection is inconsistent")
1477
+
1478
+ malformed_present = any(malformed[name] for name in _SOURCE_FIELDS)
1479
+ defects_present = any(normalized_defects[name] for name in _DEFECT_FIELDS)
1480
+ expected_join_valid = not malformed_present and not defects_present
1481
+ if record["join_valid"] is not expected_join_valid:
1482
+ raise ValueError("provider-attempt join_valid contradicts its defects")
1483
+ if expected_join_valid:
1484
+ if expected_frameworks is None or expected_settings is None:
1485
+ # Empty runs may be finalized before qualification/route construction.
1486
+ if dispatched:
1487
+ raise ValueError(
1488
+ "a green dispatched join lacks environment expectations"
1489
+ )
1490
+ if source_counts["outbound_manifests"] != len(dispatched):
1491
+ raise ValueError("green join outbound count is inconsistent")
1492
+ if source_counts["outcome_attempts_with_physical_ids"] != len(outcomes):
1493
+ raise ValueError("green join outcome-attempt count is inconsistent")
1494
+ if source_counts["logical_requests"] != len(logical_call_ids):
1495
+ raise ValueError("green join logical-request count is inconsistent")
1496
+ if source_counts["progress_rows"] != sum(
1497
+ len(sequences) for sequences in normalized_sequences.values()
1498
+ ):
1499
+ raise ValueError("green join progress-row count is inconsistent")
1500
+ if source_counts["explicit_pre_transport_failures"] != len(pretransport):
1501
+ raise ValueError("green join pre-transport count is inconsistent")
1502
+
1503
+ supplied = _require_sha256(
1504
+ record["join_receipt_sha256"],
1505
+ label="join_receipt_sha256",
1506
+ )
1507
+ authenticated = dict(record)
1508
+ del authenticated["join_receipt_sha256"]
1509
+ if supplied != _domain_sha256(_JOIN_DOMAIN, authenticated):
1510
+ raise ValueError("provider-attempt terminal join hash is invalid")
1511
+ return record
1512
+
1513
+
1514
+ __all__ = [
1515
+ "PRE_TRANSPORT_FAILURE_EVIDENCE_SCHEMA_VERSION",
1516
+ "PROVIDER_ATTEMPT_TERMINAL_JOIN_CONTRACT_ID",
1517
+ "PROVIDER_ATTEMPT_TERMINAL_JOIN_SCHEMA_VERSION",
1518
+ "build_provider_attempt_terminal_join_receipt",
1519
+ "explicit_pre_transport_failure_evidence_record",
1520
+ "validate_explicit_pre_transport_failure_evidence_record",
1521
+ "validate_provider_attempt_terminal_join_receipt",
1522
+ "validate_structured_generation_outcome_record",
1523
+ ]