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,246 @@
1
+ """Redaction-before-persistence application service for JSON artifacts."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Any, Callable, Optional
7
+
8
+ from agent_evolve.application.event_recorder import EventRecorder
9
+ from agent_evolve.domain.artifact import ArtifactRef, ArtifactRole, artifact_ref_for_bytes
10
+ from agent_evolve.domain.event import ArtifactRegistered, EventEnvelope
11
+ from agent_evolve.domain.ids import CorrelationId, EventId
12
+ from agent_evolve.ports.artifact_sanitizer import ArtifactMinimizer, ArtifactSanitizer
13
+ from agent_evolve.ports.artifact_store import (
14
+ JSON_MEDIA_TYPE,
15
+ ArtifactStore,
16
+ canonical_json_bytes,
17
+ )
18
+
19
+
20
+ class ArtifactJournalError(RuntimeError):
21
+ """Base error for safe preparation or post-write verification failures."""
22
+
23
+
24
+ class ArtifactPreparationError(ArtifactJournalError):
25
+ """An input could not be minimized, sanitized, and encoded safely."""
26
+
27
+
28
+ class ArtifactSizeLimitError(ArtifactPreparationError):
29
+ """The sanitized canonical representation exceeds the configured limit."""
30
+
31
+
32
+ class ArtifactPostWriteVerificationError(ArtifactJournalError):
33
+ """The durable store did not reproduce the complete expected reference."""
34
+
35
+
36
+ AfterArtifactPutHook = Callable[[ArtifactRef], None]
37
+ _PREPARATION_FAILED = object()
38
+
39
+
40
+ @dataclass(frozen=True, slots=True)
41
+ class ArtifactRegistrationResult:
42
+ """Successful durable registration returned by :class:`ArtifactJournal`."""
43
+
44
+ artifact_ref: ArtifactRef
45
+ event: EventEnvelope
46
+
47
+
48
+ class ArtifactJournal:
49
+ """Prepare, durably store, verify, and then journal a canonical JSON value.
50
+
51
+ Raw caller input is passed only to the in-memory minimizer and sanitizer.
52
+ The sole artifact-store call that writes bytes receives the already
53
+ sanitized canonical encoding.
54
+ """
55
+
56
+ def __init__(
57
+ self,
58
+ *,
59
+ artifact_store: ArtifactStore,
60
+ event_recorder: EventRecorder,
61
+ minimizer: ArtifactMinimizer,
62
+ sanitizer: ArtifactSanitizer,
63
+ max_size_bytes: int,
64
+ after_artifact_put: AfterArtifactPutHook | None = None,
65
+ ) -> None:
66
+ if (
67
+ isinstance(max_size_bytes, bool)
68
+ or not isinstance(max_size_bytes, int)
69
+ or max_size_bytes < 1
70
+ ):
71
+ raise ValueError("max_size_bytes must be a positive integer")
72
+ self._artifact_store = artifact_store
73
+ self._event_recorder = event_recorder
74
+ self._minimizer = minimizer
75
+ self._sanitizer = sanitizer
76
+ self._max_size_bytes = max_size_bytes
77
+ self._after_artifact_put = after_artifact_put
78
+
79
+ @staticmethod
80
+ def _preparation_failure() -> ArtifactPreparationError:
81
+ # This message intentionally contains no value, field path, match count,
82
+ # or chained exception from a caller-supplied policy implementation.
83
+ return ArtifactPreparationError(
84
+ "artifact preparation failed under the configured safety policies"
85
+ )
86
+
87
+ def _minimize_without_leaky_context(self, value: Any, role: ArtifactRole) -> Any:
88
+ try:
89
+ return (
90
+ self._minimizer.minimize_json(value, role=role),
91
+ self._minimizer.policy_id,
92
+ self._minimizer.policy_version,
93
+ self._minimizer.policy_config_sha256,
94
+ )
95
+ except Exception:
96
+ # Returning from the handler clears Python's implicit exception
97
+ # context before the caller constructs the public safe error.
98
+ return _PREPARATION_FAILED
99
+
100
+ def _sanitize_without_leaky_context(
101
+ self,
102
+ value: Any,
103
+ role: ArtifactRole,
104
+ ) -> Any:
105
+ try:
106
+ sanitized = self._sanitizer.sanitize_json(value, role=role)
107
+ return (
108
+ sanitized,
109
+ self._sanitizer.policy_id,
110
+ self._sanitizer.policy_version,
111
+ )
112
+ except Exception:
113
+ return _PREPARATION_FAILED
114
+
115
+ @staticmethod
116
+ def _encode_without_leaky_context(value: Any) -> bytes | object:
117
+ try:
118
+ return canonical_json_bytes(value)
119
+ except Exception:
120
+ return _PREPARATION_FAILED
121
+
122
+ @staticmethod
123
+ def _registration_without_leaky_context(
124
+ expected_ref: ArtifactRef,
125
+ role: ArtifactRole,
126
+ minimization_policy_id: Any,
127
+ minimization_policy_version: Any,
128
+ minimization_policy_config_sha256: Any,
129
+ policy_id: Any,
130
+ policy_version: Any,
131
+ ) -> ArtifactRegistered | object:
132
+ try:
133
+ return ArtifactRegistered(
134
+ artifact_id=expected_ref.artifact_id,
135
+ sha256_hex=expected_ref.sha256_hex,
136
+ size_bytes=expected_ref.size_bytes,
137
+ media_type=expected_ref.media_type,
138
+ role=role,
139
+ minimization_policy_id=minimization_policy_id,
140
+ minimization_policy_version=minimization_policy_version,
141
+ minimization_policy_config_sha256=(
142
+ minimization_policy_config_sha256
143
+ ),
144
+ sanitization_policy_id=policy_id,
145
+ sanitization_policy_version=policy_version,
146
+ )
147
+ except Exception:
148
+ return _PREPARATION_FAILED
149
+
150
+ def register_json(
151
+ self,
152
+ value: Any,
153
+ *,
154
+ role: ArtifactRole,
155
+ correlation_id: Optional[CorrelationId] = None,
156
+ causation_event_id: Optional[EventId] = None,
157
+ ) -> ArtifactRegistrationResult:
158
+ """Register one minimized and sanitized JSON artifact.
159
+
160
+ Ordering is a safety and crash-consistency contract, not an
161
+ implementation detail: minimize -> sanitize -> canonical encode -> size
162
+ gate -> durable put -> full verification -> durable event append.
163
+ """
164
+
165
+ if not isinstance(role, ArtifactRole):
166
+ raise TypeError("role must be an ArtifactRole")
167
+
168
+ minimization_result = self._minimize_without_leaky_context(value, role)
169
+ if minimization_result is _PREPARATION_FAILED:
170
+ raise self._preparation_failure()
171
+ (
172
+ minimized,
173
+ minimization_policy_id,
174
+ minimization_policy_version,
175
+ minimization_policy_config_sha256,
176
+ ) = minimization_result
177
+ sanitized_result = self._sanitize_without_leaky_context(minimized, role)
178
+ if sanitized_result is _PREPARATION_FAILED:
179
+ raise self._preparation_failure()
180
+ sanitized, policy_id, policy_version = sanitized_result
181
+ encoded = self._encode_without_leaky_context(sanitized)
182
+ if encoded is _PREPARATION_FAILED:
183
+ raise self._preparation_failure()
184
+ assert isinstance(encoded, bytes) # narrowed from the private sentinel union
185
+
186
+ if len(encoded) > self._max_size_bytes:
187
+ raise ArtifactSizeLimitError(
188
+ "sanitized artifact exceeds the configured size limit"
189
+ )
190
+
191
+ expected_ref = artifact_ref_for_bytes(encoded, media_type=JSON_MEDIA_TYPE)
192
+ # Constructing the payload before the write validates all provenance
193
+ # metadata. It is appended only after post-write verification succeeds.
194
+ registration = self._registration_without_leaky_context(
195
+ expected_ref,
196
+ role,
197
+ minimization_policy_id,
198
+ minimization_policy_version,
199
+ minimization_policy_config_sha256,
200
+ policy_id,
201
+ policy_version,
202
+ )
203
+ if registration is _PREPARATION_FAILED:
204
+ raise self._preparation_failure()
205
+ assert isinstance(registration, ArtifactRegistered)
206
+
207
+ persisted_ref = self._artifact_store.put_bytes(
208
+ encoded,
209
+ media_type=JSON_MEDIA_TYPE,
210
+ )
211
+ if self._after_artifact_put is not None:
212
+ # A test/deployment crash hook receives only content metadata, never
213
+ # the raw or sanitized payload. Raising leaves a store-only orphan.
214
+ self._after_artifact_put(expected_ref)
215
+
216
+ try:
217
+ stat_ref = self._artifact_store.stat(expected_ref.artifact_id)
218
+ reread = self._artifact_store.read_bytes(
219
+ expected_ref.artifact_id,
220
+ expected_media_type=JSON_MEDIA_TYPE,
221
+ )
222
+ reread_ref = artifact_ref_for_bytes(
223
+ reread,
224
+ media_type=JSON_MEDIA_TYPE,
225
+ )
226
+ except Exception:
227
+ raise ArtifactPostWriteVerificationError(
228
+ "artifact could not be fully verified after persistence"
229
+ ) from None
230
+
231
+ if (
232
+ persisted_ref != expected_ref
233
+ or stat_ref != expected_ref
234
+ or reread_ref != expected_ref
235
+ or reread != encoded
236
+ ):
237
+ raise ArtifactPostWriteVerificationError(
238
+ "artifact metadata or bytes changed during persistence"
239
+ )
240
+
241
+ event = self._event_recorder.record(
242
+ registration,
243
+ correlation_id=correlation_id,
244
+ causation_event_id=causation_event_id,
245
+ )
246
+ return ArtifactRegistrationResult(artifact_ref=expected_ref, event=event)
@@ -0,0 +1,347 @@
1
+ """Read-only replay and integrity verification for artifact registrations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import types
6
+ from dataclasses import dataclass, fields
7
+ from typing import Any, Iterable, Optional, Tuple, Union, get_args, get_origin, get_type_hints
8
+
9
+ from agent_evolve.domain.artifact import ArtifactRef, ArtifactRole, artifact_ref_for_bytes
10
+ from agent_evolve.domain.event import (
11
+ EVENT_PAYLOAD_TYPES,
12
+ ArtifactRegistered,
13
+ CandidateProposed,
14
+ EvaluationFailed,
15
+ EventEnvelope,
16
+ EventPayload,
17
+ LLMCallCompleted,
18
+ LLMCallFailed,
19
+ LLMRequestArtifactLinked,
20
+ ProviderAttemptFailed,
21
+ RunAborted,
22
+ RunStarted,
23
+ validated_event_snapshot,
24
+ )
25
+ from agent_evolve.domain.ids import ArtifactId, RunId
26
+ from agent_evolve.ports.artifact_store import (
27
+ JSON_MEDIA_TYPE,
28
+ ArtifactStore,
29
+ canonical_json_bytes,
30
+ decode_json_bytes,
31
+ )
32
+
33
+
34
+ class ArtifactReplayError(RuntimeError):
35
+ """The event stream and artifact store do not form a valid journal."""
36
+
37
+
38
+ class ArtifactStreamOrderError(ArtifactReplayError):
39
+ """Replay input is not one contiguous run stream in sequence order."""
40
+
41
+
42
+ class ArtifactRegistrationIntegrityError(ArtifactReplayError):
43
+ """A registration claim is inconsistent with the durable store."""
44
+
45
+
46
+ class DanglingArtifactReferenceError(ArtifactReplayError):
47
+ """A semantic reference has no preceding registration."""
48
+
49
+
50
+ class IncompatibleArtifactRoleError(ArtifactReplayError):
51
+ """An artifact was registered earlier, but not under the required role."""
52
+
53
+
54
+ class ArtifactReferenceSchemaError(ArtifactReplayError):
55
+ """An ArtifactId-bearing payload field has no explicit role rule."""
56
+
57
+
58
+ _SNAPSHOT_FAILED = object()
59
+ _REGISTRATION_VERIFICATION_FAILED = object()
60
+ _REGISTRATION_MISMATCH = object()
61
+
62
+
63
+ @dataclass(frozen=True, slots=True)
64
+ class ArtifactRegistrationKey:
65
+ artifact_id: ArtifactId
66
+ role: ArtifactRole
67
+
68
+
69
+ @dataclass(frozen=True, slots=True)
70
+ class ArtifactReplayReport:
71
+ run_id: Optional[RunId]
72
+ event_count: int
73
+ registration_event_count: int
74
+ semantic_reference_count: int
75
+ unique_registration_count: int
76
+ unique_referenced_registration_count: int
77
+ orphan_registrations: Tuple[ArtifactRegistrationKey, ...]
78
+
79
+
80
+ @dataclass(frozen=True, slots=True)
81
+ class _RegistrationClaim:
82
+ artifact_ref: ArtifactRef
83
+ minimization_policy_id: str
84
+ minimization_policy_version: str
85
+ minimization_policy_config_sha256: str
86
+ policy_id: str
87
+ policy_version: str
88
+
89
+
90
+ # The map is intentionally explicit and fail-closed. Adding an ArtifactId field
91
+ # to the event vocabulary requires declaring which semantic role may satisfy it.
92
+ _REFERENCE_ROLES: dict[type[EventPayload], dict[str, ArtifactRole]] = {
93
+ RunStarted: {"manifest_artifact_id": ArtifactRole.RUN_MANIFEST},
94
+ RunAborted: {"diagnostics_artifact_id": ArtifactRole.DIAGNOSTICS},
95
+ LLMCallCompleted: {"response_artifact_id": ArtifactRole.LLM_RESPONSE},
96
+ LLMRequestArtifactLinked: {"request_artifact_id": ArtifactRole.LLM_REQUEST},
97
+ LLMCallFailed: {"diagnostics_artifact_id": ArtifactRole.DIAGNOSTICS},
98
+ ProviderAttemptFailed: {"diagnostics_artifact_id": ArtifactRole.DIAGNOSTICS},
99
+ CandidateProposed: {
100
+ "configuration_artifact_id": ArtifactRole.CANDIDATE_CONFIGURATION
101
+ },
102
+ EvaluationFailed: {"diagnostics_artifact_id": ArtifactRole.DIAGNOSTICS},
103
+ }
104
+
105
+
106
+ def _annotation_contains_artifact_id(annotation: Any) -> bool:
107
+ if annotation is ArtifactId:
108
+ return True
109
+ origin = get_origin(annotation)
110
+ if origin in (Union, types.UnionType) or origin in (tuple, list, dict):
111
+ return any(_annotation_contains_artifact_id(arg) for arg in get_args(annotation))
112
+ return False
113
+
114
+
115
+ def _annotation_is_scalar_artifact_id(annotation: Any) -> bool:
116
+ if annotation is ArtifactId:
117
+ return True
118
+ origin = get_origin(annotation)
119
+ args = get_args(annotation)
120
+ return origin in (Union, types.UnionType) and set(args) == {
121
+ ArtifactId,
122
+ type(None),
123
+ }
124
+
125
+
126
+ def _artifact_fields(payload: EventPayload) -> tuple[str, ...]:
127
+ hints = get_type_hints(type(payload))
128
+ return tuple(
129
+ field.name
130
+ for field in fields(payload)
131
+ if _annotation_contains_artifact_id(hints[field.name])
132
+ )
133
+
134
+
135
+ def validate_artifact_reference_schema() -> None:
136
+ """Fail if the complete event vocabulary and semantic role map drift apart."""
137
+
138
+ payload_types = set(EVENT_PAYLOAD_TYPES)
139
+ extra_rule_types = set(_REFERENCE_ROLES) - payload_types
140
+ if extra_rule_types:
141
+ raise ArtifactReferenceSchemaError(
142
+ "artifact reference role rules include an unregistered event payload"
143
+ )
144
+
145
+ for payload_type in EVENT_PAYLOAD_TYPES:
146
+ if payload_type is ArtifactRegistered:
147
+ hints = get_type_hints(payload_type)
148
+ registration_artifact_fields = {
149
+ field.name
150
+ for field in fields(payload_type)
151
+ if _annotation_contains_artifact_id(hints[field.name])
152
+ }
153
+ if registration_artifact_fields != {"artifact_id"}:
154
+ raise ArtifactReferenceSchemaError(
155
+ "ArtifactRegistered identity fields require an explicit schema review"
156
+ )
157
+ continue
158
+ hints = get_type_hints(payload_type)
159
+ artifact_fields = {
160
+ field.name
161
+ for field in fields(payload_type)
162
+ if _annotation_contains_artifact_id(hints[field.name])
163
+ }
164
+ declared_roles = _REFERENCE_ROLES.get(payload_type, {})
165
+ if artifact_fields != set(declared_roles):
166
+ raise ArtifactReferenceSchemaError(
167
+ "artifact reference role rules do not match the event schema"
168
+ )
169
+ for field_name in artifact_fields:
170
+ if not _annotation_is_scalar_artifact_id(hints[field_name]):
171
+ raise ArtifactReferenceSchemaError(
172
+ "non-scalar ArtifactId references require an explicit replay design"
173
+ )
174
+ if not isinstance(declared_roles[field_name], ArtifactRole):
175
+ raise ArtifactReferenceSchemaError(
176
+ "artifact reference rules must declare a constrained role"
177
+ )
178
+
179
+
180
+ # Validate the whole vocabulary at import, not only payload types encountered by
181
+ # a particular run. A schema change therefore cannot remain latent in quiet runs.
182
+ validate_artifact_reference_schema()
183
+
184
+
185
+ def _try_verify_registration_store(
186
+ registration: ArtifactRegistered,
187
+ store: ArtifactStore,
188
+ ) -> ArtifactRef | object:
189
+ expected = registration.artifact_ref
190
+ try:
191
+ stat_ref = store.stat(expected.artifact_id)
192
+ content = store.read_bytes(
193
+ expected.artifact_id,
194
+ expected_media_type=expected.media_type,
195
+ )
196
+ content_ref = artifact_ref_for_bytes(content, media_type=expected.media_type)
197
+ decoded = decode_json_bytes(content)
198
+ canonical_content = canonical_json_bytes(decoded)
199
+ if (
200
+ stat_ref != expected
201
+ or content_ref != expected
202
+ or canonical_content != content
203
+ ):
204
+ return _REGISTRATION_MISMATCH
205
+ except Exception:
206
+ # Return from the handler so secret-bearing adapter/codec exceptions do
207
+ # not become context on the public integrity error raised by the caller.
208
+ return _REGISTRATION_VERIFICATION_FAILED
209
+ return expected
210
+
211
+
212
+ def _verify_registration_store(
213
+ registration: ArtifactRegistered,
214
+ store: ArtifactStore,
215
+ ) -> ArtifactRef:
216
+ expected = registration.artifact_ref
217
+ if expected.media_type != JSON_MEDIA_TYPE:
218
+ raise ArtifactRegistrationIntegrityError(
219
+ "M1c registrations must use the canonical JSON media type"
220
+ )
221
+ verification = _try_verify_registration_store(registration, store)
222
+ if verification is _REGISTRATION_VERIFICATION_FAILED:
223
+ raise ArtifactRegistrationIntegrityError(
224
+ "a registered artifact could not be verified in the durable store"
225
+ )
226
+ if verification is _REGISTRATION_MISMATCH:
227
+ raise ArtifactRegistrationIntegrityError(
228
+ "a registration does not match a canonical durable artifact reference"
229
+ )
230
+ assert type(verification) is ArtifactRef
231
+ return verification
232
+
233
+
234
+ def verify_artifact_journal(
235
+ events: Iterable[EventEnvelope],
236
+ *,
237
+ artifact_store: ArtifactStore,
238
+ ) -> ArtifactReplayReport:
239
+ """Verify one run deterministically without mutating events or artifacts.
240
+
241
+ Registrations that are never referenced are valid: they can result from a
242
+ crash after registration but before the semantic event. Conversely, a
243
+ store-only orphan has no journal record and is deliberately invisible here.
244
+ """
245
+
246
+ try:
247
+ stream = tuple(validated_event_snapshot(event) for event in events)
248
+ except Exception:
249
+ stream = _SNAPSHOT_FAILED
250
+ if stream is _SNAPSHOT_FAILED:
251
+ raise ArtifactStreamOrderError(
252
+ "artifact replay requires canonically validated event snapshots"
253
+ )
254
+ assert isinstance(stream, tuple)
255
+
256
+ run_id: Optional[RunId] = None
257
+ expected_sequence = 1
258
+ event_count = 0
259
+ registration_event_count = 0
260
+ semantic_reference_count = 0
261
+ registrations: dict[ArtifactRegistrationKey, _RegistrationClaim] = {}
262
+ refs_by_id: dict[ArtifactId, ArtifactRef] = {}
263
+ roles_by_id: dict[ArtifactId, set[ArtifactRole]] = {}
264
+ referenced: set[ArtifactRegistrationKey] = set()
265
+
266
+ for event in stream:
267
+ event_count += 1
268
+ if run_id is None:
269
+ run_id = event.run_id
270
+ elif event.run_id != run_id:
271
+ raise ArtifactStreamOrderError(
272
+ "artifact replay requires events from exactly one run"
273
+ )
274
+ if event.sequence_number != expected_sequence:
275
+ raise ArtifactStreamOrderError(
276
+ "artifact replay requires a contiguous sequence beginning at one"
277
+ )
278
+ expected_sequence += 1
279
+
280
+ payload = event.payload
281
+ if isinstance(payload, ArtifactRegistered):
282
+ registration_event_count += 1
283
+ ref = _verify_registration_store(payload, artifact_store)
284
+ previous_ref = refs_by_id.get(ref.artifact_id)
285
+ if previous_ref is not None and previous_ref != ref:
286
+ raise ArtifactRegistrationIntegrityError(
287
+ "registrations disagree on a complete artifact reference"
288
+ )
289
+ refs_by_id[ref.artifact_id] = ref
290
+ key = ArtifactRegistrationKey(ref.artifact_id, payload.role)
291
+ claim = _RegistrationClaim(
292
+ artifact_ref=ref,
293
+ minimization_policy_id=payload.minimization_policy_id,
294
+ minimization_policy_version=payload.minimization_policy_version,
295
+ minimization_policy_config_sha256=(
296
+ payload.minimization_policy_config_sha256
297
+ ),
298
+ policy_id=payload.sanitization_policy_id,
299
+ policy_version=payload.sanitization_policy_version,
300
+ )
301
+ previous_claim = registrations.get(key)
302
+ if previous_claim is not None and previous_claim != claim:
303
+ raise ArtifactRegistrationIntegrityError(
304
+ "duplicate registrations disagree on provenance"
305
+ )
306
+ registrations[key] = claim
307
+ roles_by_id.setdefault(ref.artifact_id, set()).add(payload.role)
308
+ continue
309
+
310
+ artifact_fields = _artifact_fields(payload)
311
+ declared_roles = _REFERENCE_ROLES.get(type(payload), {})
312
+ if set(artifact_fields) != set(declared_roles):
313
+ raise ArtifactReferenceSchemaError(
314
+ "artifact reference role rules do not match the event schema"
315
+ )
316
+ for field_name in artifact_fields:
317
+ artifact_id = getattr(payload, field_name)
318
+ if artifact_id is None:
319
+ continue
320
+ semantic_reference_count += 1
321
+ role = declared_roles[field_name]
322
+ key = ArtifactRegistrationKey(artifact_id, role)
323
+ if key not in registrations:
324
+ if artifact_id in roles_by_id:
325
+ raise IncompatibleArtifactRoleError(
326
+ "an artifact reference has no preceding compatible role"
327
+ )
328
+ raise DanglingArtifactReferenceError(
329
+ "an artifact reference has no preceding registration"
330
+ )
331
+ referenced.add(key)
332
+
333
+ orphan_keys = tuple(
334
+ sorted(
335
+ set(registrations) - referenced,
336
+ key=lambda key: (key.artifact_id.value, key.role.value),
337
+ )
338
+ )
339
+ return ArtifactReplayReport(
340
+ run_id=run_id,
341
+ event_count=event_count,
342
+ registration_event_count=registration_event_count,
343
+ semantic_reference_count=semantic_reference_count,
344
+ unique_registration_count=len(registrations),
345
+ unique_referenced_registration_count=len(referenced),
346
+ orphan_registrations=orphan_keys,
347
+ )