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,1841 @@
1
+ """Authenticated global falsification for reflected optimization hypotheses.
2
+
3
+ The gate in this module is deliberately provider- and workload-neutral. A
4
+ workload-owned matcher interprets typed trigger predicates and intervention
5
+ signatures. The engine then joins that classification to every authenticated
6
+ observation visible at a sealed cutoff, applies exact metric predictions, and
7
+ issues an immutable receipt.
8
+
9
+ Semantic claim auditing and memory-treatment causality are intentionally
10
+ different estimands. Candidate-level contrasts may support or falsify a
11
+ hypothesis, but every observation remains attached to its enclosing wave or
12
+ portfolio ITT unit. Audit receipts contain no reward and cannot assign causal
13
+ credit to an individual insight.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import hashlib
19
+ import math
20
+ import re
21
+ from dataclasses import dataclass, field
22
+ from enum import Enum
23
+ from typing import Protocol, Sequence, runtime_checkable
24
+
25
+ from agent_evolve.domain.insight import InsightRef
26
+ from agent_evolve.domain.ids import CandidateId, OperatorInvocationId
27
+ from agent_evolve.domain.patch import require_sha256
28
+ from agent_evolve.domain.typed_json import (
29
+ FrozenJsonObject,
30
+ canonical_typed_json_bytes,
31
+ freeze_json,
32
+ thaw_json,
33
+ )
34
+ from agent_evolve.ports.agentic_generator import MetricEffectDirection
35
+
36
+
37
+ _TOKEN = re.compile(r"^[a-z][a-z0-9_.-]{0,127}$")
38
+ _METRIC = re.compile(r"^[a-z][a-z0-9_.:-]{0,191}$")
39
+ _PATH = re.compile(r"^\$\.[^.\[\]\s]+(?:\.[^.\[\]\s]+|\[(?:0|[1-9][0-9]*)\])*$")
40
+ _TEXT_LIMIT = 4_096
41
+ _MAX_EVENT_INDEX = (1 << 63) - 1
42
+
43
+ _PREDICATE_DOMAIN = b"agent-evolve:typed-hypothesis-predicate:v1\x00"
44
+ _INTERVENTION_DOMAIN = b"agent-evolve:typed-intervention-signature:v1\x00"
45
+ _SCOPE_DOMAIN = b"agent-evolve:global-hypothesis-audit-scope:v1\x00"
46
+ _REQUEST_DOMAIN = b"agent-evolve:global-hypothesis-audit-request:v1\x00"
47
+ _BOUNDARY_DOMAIN = b"agent-evolve:hypothesis-evidence-itt-boundary:v1\x00"
48
+ _OBSERVATION_DOMAIN = b"agent-evolve:global-hypothesis-observation:v3\x00"
49
+ _REGISTRY_DOMAIN = b"agent-evolve:global-hypothesis-registry:v1\x00"
50
+ _MATCH_DOMAIN = b"agent-evolve:hypothesis-evidence-match:v1\x00"
51
+ _CLUSTER_DOMAIN = b"agent-evolve:hypothesis-effective-cluster:v1\x00"
52
+ _RECEIPT_DOMAIN = b"agent-evolve:global-hypothesis-audit-receipt:v1\x00"
53
+ _REVISION_DOMAIN = b"agent-evolve:append-only-hypothesis-revision:v1\x00"
54
+
55
+
56
+ def _hash_record(domain: bytes, record: object) -> str:
57
+ return hashlib.sha256(
58
+ domain + canonical_typed_json_bytes(freeze_json(record))
59
+ ).hexdigest()
60
+
61
+
62
+ GLOBAL_FALSIFICATION_POLICY_ID = "global_hypothesis_falsification"
63
+ GLOBAL_FALSIFICATION_POLICY_VERSION = 2
64
+ GLOBAL_FALSIFICATION_POLICY_DEFINITION_SHA256 = _hash_record(
65
+ b"agent-evolve:global-hypothesis-falsification-policy:v2\x00",
66
+ {
67
+ "policy_id": GLOBAL_FALSIFICATION_POLICY_ID,
68
+ "policy_version": GLOBAL_FALSIFICATION_POLICY_VERSION,
69
+ "join": "exhaustive_authenticated_registry_at_inclusive_event_cutoff",
70
+ "repeat_rule": "earliest_event_then_source_id_per_configuration_evaluator",
71
+ "support_rule": "all_required_known_directions_and_magnitudes_match",
72
+ "counterexample_rule": "any_required_direction_or_magnitude_mismatch",
73
+ "necessity_rule": "matching_off_trigger_response_contradicts_necessity",
74
+ "cluster_rule": (
75
+ "instance_evaluator_campaign_lineage_factorial_block_itt_unit"
76
+ ),
77
+ "support_temporality_rule": (
78
+ "declared_support_thresholds_must_be_met_by_post_origin_evidence"
79
+ ),
80
+ "mechanism_temporality_rule": (
81
+ "mechanistic_support_requires_post_origin_identifying_evidence"
82
+ ),
83
+ "causal_credit_rule": "semantic_audit_only_no_retroactive_card_credit",
84
+ },
85
+ )
86
+
87
+
88
+ def _require_token(value: str, *, name: str) -> None:
89
+ if type(value) is not str or _TOKEN.fullmatch(value) is None:
90
+ raise ValueError(f"{name} must use the closed lowercase token grammar")
91
+
92
+
93
+ def _require_metric(value: str, *, name: str = "metric_id") -> None:
94
+ if type(value) is not str or _METRIC.fullmatch(value) is None:
95
+ raise ValueError(f"{name} must use the closed metric identifier grammar")
96
+
97
+
98
+ def _require_event_index(value: int, *, name: str) -> None:
99
+ if type(value) is not int or not 0 <= value <= _MAX_EVENT_INDEX:
100
+ raise ValueError(f"{name} must be an exact non-negative int63")
101
+
102
+
103
+ def _require_canonical_text(value: str, *, name: str) -> None:
104
+ if (
105
+ type(value) is not str
106
+ or not value
107
+ or value != value.strip()
108
+ or len(value) > _TEXT_LIMIT
109
+ ):
110
+ raise ValueError(f"{name} must be bounded canonical non-empty text")
111
+
112
+
113
+ def _require_sha_tuple(values: tuple[str, ...], *, name: str, empty: bool) -> None:
114
+ if type(values) is not tuple or any(type(value) is not str for value in values):
115
+ raise TypeError(f"{name} must be an exact tuple of SHA-256 strings")
116
+ for value in values:
117
+ require_sha256(value, name)
118
+ if not empty and not values:
119
+ raise ValueError(f"{name} cannot be empty")
120
+ if values != tuple(sorted(set(values))):
121
+ raise ValueError(f"{name} must be unique and canonically sorted")
122
+
123
+
124
+ def _require_frozen_object(value: FrozenJsonObject, *, name: str) -> None:
125
+ if type(value) is not FrozenJsonObject:
126
+ raise TypeError(f"{name} must be an exact FrozenJsonObject")
127
+ if freeze_json(value) is not value:
128
+ raise TypeError(f"{name} must already be frozen typed JSON")
129
+
130
+
131
+ @dataclass(frozen=True, slots=True)
132
+ class TypedEvidencePredicate:
133
+ """Workload-owned, replayable predicate with engine-authenticated identity."""
134
+
135
+ schema_id: str
136
+ schema_version: int
137
+ schema_definition_sha256: str
138
+ payload: FrozenJsonObject
139
+ predicate_sha256: str = field(init=False)
140
+
141
+ def __post_init__(self) -> None:
142
+ _require_token(self.schema_id, name="schema_id")
143
+ if type(self.schema_version) is not int or self.schema_version <= 0:
144
+ raise ValueError("schema_version must be a positive exact integer")
145
+ require_sha256(self.schema_definition_sha256, "schema_definition_sha256")
146
+ _require_frozen_object(self.payload, name="payload")
147
+ object.__setattr__(
148
+ self,
149
+ "predicate_sha256",
150
+ _hash_record(_PREDICATE_DOMAIN, self._unsigned_record()),
151
+ )
152
+
153
+ def _unsigned_record(self) -> dict[str, object]:
154
+ return {
155
+ "schema_version": 1,
156
+ "predicate_schema_id": self.schema_id,
157
+ "predicate_schema_version": self.schema_version,
158
+ "predicate_schema_definition_sha256": self.schema_definition_sha256,
159
+ "payload": thaw_json(self.payload),
160
+ }
161
+
162
+ def to_record(self) -> dict[str, object]:
163
+ return {**self._unsigned_record(), "predicate_sha256": self.predicate_sha256}
164
+
165
+
166
+ @dataclass(frozen=True, slots=True)
167
+ class TypedInterventionSignature:
168
+ """Exact semantic edit requested by a sealed hypothesis."""
169
+
170
+ affected_paths: tuple[str, ...]
171
+ old_value_predicate: TypedEvidencePredicate
172
+ new_action: TypedEvidencePredicate
173
+ admissible_operator_families: tuple[str, ...]
174
+ signature_sha256: str = field(init=False)
175
+
176
+ def __post_init__(self) -> None:
177
+ if type(self.affected_paths) is not tuple or not self.affected_paths:
178
+ raise ValueError("affected_paths must be a non-empty exact tuple")
179
+ if any(
180
+ type(path) is not str or _PATH.fullmatch(path) is None
181
+ for path in self.affected_paths
182
+ ):
183
+ raise ValueError("affected_paths must contain canonical JSON paths")
184
+ if self.affected_paths != tuple(sorted(set(self.affected_paths))):
185
+ raise ValueError("affected_paths must be unique and canonically sorted")
186
+ if type(self.old_value_predicate) is not TypedEvidencePredicate:
187
+ raise TypeError("old_value_predicate must be exact TypedEvidencePredicate")
188
+ if type(self.new_action) is not TypedEvidencePredicate:
189
+ raise TypeError("new_action must be exact TypedEvidencePredicate")
190
+ if (
191
+ type(self.admissible_operator_families) is not tuple
192
+ or not self.admissible_operator_families
193
+ ):
194
+ raise ValueError("admissible_operator_families must be non-empty")
195
+ for family in self.admissible_operator_families:
196
+ _require_token(family, name="admissible_operator_families")
197
+ if self.admissible_operator_families != tuple(
198
+ sorted(set(self.admissible_operator_families))
199
+ ):
200
+ raise ValueError(
201
+ "admissible_operator_families must be unique and canonically sorted"
202
+ )
203
+ object.__setattr__(
204
+ self,
205
+ "signature_sha256",
206
+ _hash_record(_INTERVENTION_DOMAIN, self._unsigned_record()),
207
+ )
208
+
209
+ def _unsigned_record(self) -> dict[str, object]:
210
+ return {
211
+ "schema_version": 1,
212
+ "affected_paths": list(self.affected_paths),
213
+ "old_value_predicate_sha256": self.old_value_predicate.predicate_sha256,
214
+ "new_action_sha256": self.new_action.predicate_sha256,
215
+ "admissible_operator_families": list(self.admissible_operator_families),
216
+ }
217
+
218
+ def to_record(self) -> dict[str, object]:
219
+ return {**self._unsigned_record(), "signature_sha256": self.signature_sha256}
220
+
221
+
222
+ @dataclass(frozen=True, slots=True)
223
+ class HypothesisMetricPrediction:
224
+ """One required direction and optional child-minus-parent magnitude interval."""
225
+
226
+ metric_id: str
227
+ direction: MetricEffectDirection
228
+ minimum_delta: float | None = None
229
+ maximum_delta: float | None = None
230
+
231
+ def __post_init__(self) -> None:
232
+ _require_metric(self.metric_id)
233
+ if (
234
+ type(self.direction) is not MetricEffectDirection
235
+ or self.direction is MetricEffectDirection.UNKNOWN
236
+ ):
237
+ raise ValueError("direction must be a known MetricEffectDirection")
238
+ if (self.minimum_delta is None) != (self.maximum_delta is None):
239
+ raise ValueError("magnitude claims require both interval endpoints")
240
+ if self.minimum_delta is not None:
241
+ if (
242
+ type(self.minimum_delta) is not float
243
+ or type(self.maximum_delta) is not float
244
+ or not math.isfinite(self.minimum_delta)
245
+ or not math.isfinite(self.maximum_delta)
246
+ ):
247
+ raise TypeError("magnitude endpoints must be finite canonical floats")
248
+ if self.minimum_delta > self.maximum_delta:
249
+ raise ValueError("minimum_delta cannot exceed maximum_delta")
250
+
251
+ @property
252
+ def has_magnitude_claim(self) -> bool:
253
+ return self.minimum_delta is not None
254
+
255
+ def to_record(self) -> dict[str, object]:
256
+ return {
257
+ "metric_id": self.metric_id,
258
+ "direction": self.direction.value,
259
+ "minimum_delta_hex": (
260
+ None if self.minimum_delta is None else self.minimum_delta.hex()
261
+ ),
262
+ "maximum_delta_hex": (
263
+ None if self.maximum_delta is None else self.maximum_delta.hex()
264
+ ),
265
+ }
266
+
267
+
268
+ @dataclass(frozen=True, slots=True)
269
+ class HypothesisClaimStrength:
270
+ """Typed logical flags; prose is never parsed by the gate."""
271
+
272
+ sufficiency: bool = True
273
+ necessity: bool = False
274
+ invariance: bool = False
275
+ mechanistic_or_causal: bool = False
276
+
277
+ def __post_init__(self) -> None:
278
+ if any(
279
+ type(getattr(self, name)) is not bool
280
+ for name in (
281
+ "sufficiency",
282
+ "necessity",
283
+ "invariance",
284
+ "mechanistic_or_causal",
285
+ )
286
+ ):
287
+ raise TypeError("logical strength flags must be exact booleans")
288
+ if not any(
289
+ (
290
+ self.sufficiency,
291
+ self.necessity,
292
+ self.invariance,
293
+ self.mechanistic_or_causal,
294
+ )
295
+ ):
296
+ raise ValueError("a hypothesis must declare at least one logical claim")
297
+
298
+ def to_record(self) -> dict[str, bool]:
299
+ return {
300
+ "sufficiency": self.sufficiency,
301
+ "necessity": self.necessity,
302
+ "invariance": self.invariance,
303
+ "mechanistic_or_causal": self.mechanistic_or_causal,
304
+ }
305
+
306
+
307
+ @dataclass(frozen=True, slots=True)
308
+ class HypothesisAuditScope:
309
+ """Closed workload/evaluator/campaign scope for one global join."""
310
+
311
+ workload_instance_sha256s: tuple[str, ...]
312
+ evaluator_contract_sha256: str
313
+ metric_adjudicator_definition_sha256: str
314
+ campaign_sha256s: tuple[str, ...] = ()
315
+ cross_instance_claim: bool = False
316
+ scope_sha256: str = field(init=False)
317
+
318
+ def __post_init__(self) -> None:
319
+ _require_sha_tuple(
320
+ self.workload_instance_sha256s,
321
+ name="workload_instance_sha256s",
322
+ empty=False,
323
+ )
324
+ require_sha256(self.evaluator_contract_sha256, "evaluator_contract_sha256")
325
+ require_sha256(
326
+ self.metric_adjudicator_definition_sha256,
327
+ "metric_adjudicator_definition_sha256",
328
+ )
329
+ _require_sha_tuple(self.campaign_sha256s, name="campaign_sha256s", empty=True)
330
+ if type(self.cross_instance_claim) is not bool:
331
+ raise TypeError("cross_instance_claim must be an exact boolean")
332
+ if self.cross_instance_claim and len(self.workload_instance_sha256s) < 2:
333
+ raise ValueError("cross-instance claims require at least two instances")
334
+ object.__setattr__(
335
+ self, "scope_sha256", _hash_record(_SCOPE_DOMAIN, self._unsigned_record())
336
+ )
337
+
338
+ def _unsigned_record(self) -> dict[str, object]:
339
+ return {
340
+ "schema_version": 1,
341
+ "workload_instance_sha256s": list(self.workload_instance_sha256s),
342
+ "evaluator_contract_sha256": self.evaluator_contract_sha256,
343
+ "metric_adjudicator_definition_sha256": (
344
+ self.metric_adjudicator_definition_sha256
345
+ ),
346
+ "campaign_sha256s": list(self.campaign_sha256s),
347
+ "cross_instance_claim": self.cross_instance_claim,
348
+ }
349
+
350
+ def to_record(self) -> dict[str, object]:
351
+ return {**self._unsigned_record(), "scope_sha256": self.scope_sha256}
352
+
353
+
354
+ @dataclass(frozen=True, slots=True)
355
+ class GlobalHypothesisAuditRequest:
356
+ """Sealed hypothesis, evidence universe, and predeclared support threshold."""
357
+
358
+ reference: InsightRef
359
+ draft_content_sha256: str
360
+ trigger: TypedEvidencePredicate
361
+ intervention: TypedInterventionSignature
362
+ predictions: tuple[HypothesisMetricPrediction, ...]
363
+ claim_strength: HypothesisClaimStrength
364
+ scope: HypothesisAuditScope
365
+ matcher_definition_sha256: str
366
+ origin_cutoff_event_index: int
367
+ audit_cutoff_event_index: int
368
+ registry_snapshot_sha256: str
369
+ minimum_support_clusters: int = 2
370
+ minimum_support_instances: int = 1
371
+ audit_policy_definition_sha256: str = GLOBAL_FALSIFICATION_POLICY_DEFINITION_SHA256
372
+ request_sha256: str = field(init=False)
373
+
374
+ def __post_init__(self) -> None:
375
+ if type(self.reference) is not InsightRef:
376
+ raise TypeError("reference must be an exact InsightRef")
377
+ InsightRef.__post_init__(self.reference)
378
+ require_sha256(self.draft_content_sha256, "draft_content_sha256")
379
+ if type(self.trigger) is not TypedEvidencePredicate:
380
+ raise TypeError("trigger must be exact TypedEvidencePredicate")
381
+ if type(self.intervention) is not TypedInterventionSignature:
382
+ raise TypeError("intervention must be exact TypedInterventionSignature")
383
+ if (
384
+ type(self.predictions) is not tuple
385
+ or not self.predictions
386
+ or any(
387
+ type(value) is not HypothesisMetricPrediction
388
+ for value in self.predictions
389
+ )
390
+ ):
391
+ raise ValueError("predictions must contain typed metric predictions")
392
+ metric_ids = tuple(value.metric_id for value in self.predictions)
393
+ if metric_ids != tuple(sorted(set(metric_ids))):
394
+ raise ValueError("predictions must use unique canonical metric order")
395
+ if type(self.claim_strength) is not HypothesisClaimStrength:
396
+ raise TypeError("claim_strength must be exact HypothesisClaimStrength")
397
+ if type(self.scope) is not HypothesisAuditScope:
398
+ raise TypeError("scope must be exact HypothesisAuditScope")
399
+ require_sha256(self.matcher_definition_sha256, "matcher_definition_sha256")
400
+ _require_event_index(
401
+ self.origin_cutoff_event_index, name="origin_cutoff_event_index"
402
+ )
403
+ _require_event_index(
404
+ self.audit_cutoff_event_index, name="audit_cutoff_event_index"
405
+ )
406
+ if self.origin_cutoff_event_index > self.audit_cutoff_event_index:
407
+ raise ValueError("origin cutoff cannot follow the audit cutoff")
408
+ require_sha256(self.registry_snapshot_sha256, "registry_snapshot_sha256")
409
+ for name in ("minimum_support_clusters", "minimum_support_instances"):
410
+ value = getattr(self, name)
411
+ if type(value) is not int or value <= 0:
412
+ raise ValueError(f"{name} must be a positive exact integer")
413
+ require_sha256(
414
+ self.audit_policy_definition_sha256,
415
+ "audit_policy_definition_sha256",
416
+ )
417
+ if self.scope.cross_instance_claim and self.minimum_support_instances < 2:
418
+ raise ValueError(
419
+ "cross-instance claims require support from at least two instances"
420
+ )
421
+ object.__setattr__(
422
+ self,
423
+ "request_sha256",
424
+ _hash_record(_REQUEST_DOMAIN, self._unsigned_record()),
425
+ )
426
+
427
+ def _unsigned_record(self) -> dict[str, object]:
428
+ return {
429
+ "schema_version": 1,
430
+ "reference": {
431
+ "insight_id": self.reference.insight_id.value,
432
+ "version": self.reference.version,
433
+ },
434
+ "draft_content_sha256": self.draft_content_sha256,
435
+ "trigger_predicate_sha256": self.trigger.predicate_sha256,
436
+ "intervention_signature_sha256": self.intervention.signature_sha256,
437
+ "predictions": [value.to_record() for value in self.predictions],
438
+ "claim_strength": self.claim_strength.to_record(),
439
+ "scope_sha256": self.scope.scope_sha256,
440
+ "matcher_definition_sha256": self.matcher_definition_sha256,
441
+ "origin_cutoff_event_index": self.origin_cutoff_event_index,
442
+ "audit_cutoff_event_index": self.audit_cutoff_event_index,
443
+ "registry_snapshot_sha256": self.registry_snapshot_sha256,
444
+ "minimum_support_clusters": self.minimum_support_clusters,
445
+ "minimum_support_instances": self.minimum_support_instances,
446
+ "audit_policy_definition_sha256": (self.audit_policy_definition_sha256),
447
+ }
448
+
449
+ def to_record(self) -> dict[str, object]:
450
+ return {**self._unsigned_record(), "request_sha256": self.request_sha256}
451
+
452
+
453
+ class EvidenceProvenance(str, Enum):
454
+ DIRECT_MUTATION = "direct_mutation"
455
+ RECOMBINATION_EXACT_ABLATION = "recombination_exact_ablation"
456
+ FULL_SLATE_DIAGNOSTIC = "full_slate_diagnostic"
457
+ RANDOMIZED_ADMINISTRATION = "randomized_administration"
458
+ OBSERVATIONAL_ASSOCIATION = "observational_association"
459
+
460
+
461
+ class InterventionIdentifiability(str, Enum):
462
+ EXACT_SINGLE = "exact_single_intervention"
463
+ JOINT_WITHOUT_ABLATION = "joint_intervention_without_exact_ablation"
464
+ AMBIGUOUS = "ambiguous_intervention_identity"
465
+
466
+
467
+ class CausalEstimandUnit(str, Enum):
468
+ WAVE = "wave"
469
+ PORTFOLIO = "portfolio"
470
+
471
+
472
+ @dataclass(frozen=True, slots=True)
473
+ class EvidenceCausalBoundary:
474
+ """Enclosing prospective ITT unit; never an individual reflected card."""
475
+
476
+ wave_sha256: str
477
+ estimand_unit: CausalEstimandUnit
478
+ portfolio_sha256: str | None = None
479
+ prospective_assignment_sha256: str | None = None
480
+ boundary_sha256: str = field(init=False)
481
+
482
+ def __post_init__(self) -> None:
483
+ require_sha256(self.wave_sha256, "wave_sha256")
484
+ if type(self.estimand_unit) is not CausalEstimandUnit:
485
+ raise TypeError("estimand_unit must be exact CausalEstimandUnit")
486
+ if self.portfolio_sha256 is not None:
487
+ require_sha256(self.portfolio_sha256, "portfolio_sha256")
488
+ if (
489
+ self.estimand_unit is CausalEstimandUnit.PORTFOLIO
490
+ and self.portfolio_sha256 is None
491
+ ):
492
+ raise ValueError("a portfolio estimand requires portfolio_sha256")
493
+ if self.prospective_assignment_sha256 is not None:
494
+ require_sha256(
495
+ self.prospective_assignment_sha256,
496
+ "prospective_assignment_sha256",
497
+ )
498
+ object.__setattr__(
499
+ self,
500
+ "boundary_sha256",
501
+ _hash_record(_BOUNDARY_DOMAIN, self._unsigned_record()),
502
+ )
503
+
504
+ @property
505
+ def estimand_unit_sha256(self) -> str:
506
+ if self.estimand_unit is CausalEstimandUnit.PORTFOLIO:
507
+ assert self.portfolio_sha256 is not None
508
+ return self.portfolio_sha256
509
+ return self.wave_sha256
510
+
511
+ def _unsigned_record(self) -> dict[str, object]:
512
+ return {
513
+ "schema_version": 1,
514
+ "wave_sha256": self.wave_sha256,
515
+ "estimand_unit": self.estimand_unit.value,
516
+ "portfolio_sha256": self.portfolio_sha256,
517
+ "prospective_assignment_sha256": self.prospective_assignment_sha256,
518
+ "credit_boundary": "semantic_audit_only_no_per_card_credit",
519
+ }
520
+
521
+ def to_record(self) -> dict[str, object]:
522
+ return {**self._unsigned_record(), "boundary_sha256": self.boundary_sha256}
523
+
524
+
525
+ @dataclass(frozen=True, slots=True)
526
+ class ObservedMetricEffect:
527
+ metric_id: str
528
+ direction: MetricEffectDirection
529
+ delta: float
530
+ adjudicator_definition_sha256: str
531
+
532
+ def __post_init__(self) -> None:
533
+ _require_metric(self.metric_id)
534
+ if (
535
+ type(self.direction) is not MetricEffectDirection
536
+ or self.direction is MetricEffectDirection.UNKNOWN
537
+ ):
538
+ raise ValueError("direction must be a known MetricEffectDirection")
539
+ if type(self.delta) is not float or not math.isfinite(self.delta):
540
+ raise TypeError("delta must be a finite canonical float")
541
+ require_sha256(
542
+ self.adjudicator_definition_sha256,
543
+ "adjudicator_definition_sha256",
544
+ )
545
+
546
+ def to_record(self) -> dict[str, object]:
547
+ return {
548
+ "metric_id": self.metric_id,
549
+ "direction": self.direction.value,
550
+ "delta_hex": self.delta.hex(),
551
+ "adjudicator_definition_sha256": self.adjudicator_definition_sha256,
552
+ }
553
+
554
+
555
+ @dataclass(frozen=True, slots=True)
556
+ class AuthenticatedHypothesisObservation:
557
+ """One immutable parent/child fact available to the global evidence join."""
558
+
559
+ source_evidence_id: str
560
+ event_index: int
561
+ workload_instance_sha256: str
562
+ evaluator_contract_sha256: str
563
+ campaign_sha256: str
564
+ parent_candidate_id: CandidateId
565
+ child_candidate_id: CandidateId
566
+ operator_invocation_id: OperatorInvocationId
567
+ finite_contract_identity_sha256: str
568
+ provenance: EvidenceProvenance
569
+ causal_boundary: EvidenceCausalBoundary
570
+ parent_configuration: FrozenJsonObject
571
+ child_configuration: FrozenJsonObject
572
+ parent_configuration_sha256: str
573
+ child_configuration_sha256: str
574
+ parent_outcome_sha256: str
575
+ child_outcome_sha256: str
576
+ operator_family: str
577
+ affected_paths: tuple[str, ...]
578
+ observed_action: FrozenJsonObject
579
+ action_semantics_compiler_id: str
580
+ action_semantics_compiler_version: int
581
+ action_semantics_definition_sha256: str
582
+ intervention_identifiability: InterventionIdentifiability
583
+ metrics: tuple[ObservedMetricEffect, ...]
584
+ lineage_cluster_sha256: str
585
+ factorial_block_sha256: str
586
+ mechanism_identifying_design: bool = False
587
+ observation_sha256: str = field(init=False)
588
+
589
+ def __post_init__(self) -> None:
590
+ require_sha256(self.source_evidence_id, "source_evidence_id")
591
+ _require_event_index(self.event_index, name="event_index")
592
+ for name in (
593
+ "workload_instance_sha256",
594
+ "evaluator_contract_sha256",
595
+ "campaign_sha256",
596
+ "finite_contract_identity_sha256",
597
+ "parent_configuration_sha256",
598
+ "child_configuration_sha256",
599
+ "parent_outcome_sha256",
600
+ "child_outcome_sha256",
601
+ "lineage_cluster_sha256",
602
+ "factorial_block_sha256",
603
+ ):
604
+ require_sha256(getattr(self, name), name)
605
+ if type(self.parent_candidate_id) is not CandidateId:
606
+ raise TypeError("parent_candidate_id must be an exact CandidateId")
607
+ if type(self.child_candidate_id) is not CandidateId:
608
+ raise TypeError("child_candidate_id must be an exact CandidateId")
609
+ if type(self.operator_invocation_id) is not OperatorInvocationId:
610
+ raise TypeError(
611
+ "operator_invocation_id must be an exact OperatorInvocationId"
612
+ )
613
+ CandidateId.__post_init__(self.parent_candidate_id)
614
+ CandidateId.__post_init__(self.child_candidate_id)
615
+ OperatorInvocationId.__post_init__(self.operator_invocation_id)
616
+ if self.parent_candidate_id == self.child_candidate_id:
617
+ raise ValueError(
618
+ "authenticated child occurrence cannot reuse its parent ID"
619
+ )
620
+ if type(self.provenance) is not EvidenceProvenance:
621
+ raise TypeError("provenance must be exact EvidenceProvenance")
622
+ if type(self.causal_boundary) is not EvidenceCausalBoundary:
623
+ raise TypeError("causal_boundary must be exact EvidenceCausalBoundary")
624
+ _require_frozen_object(self.parent_configuration, name="parent_configuration")
625
+ _require_frozen_object(self.child_configuration, name="child_configuration")
626
+ if (
627
+ _hash_record(
628
+ b"agent-evolve:configuration:v1\x00",
629
+ thaw_json(self.parent_configuration),
630
+ )
631
+ != self.parent_configuration_sha256
632
+ ):
633
+ raise ValueError("parent_configuration_sha256 does not match configuration")
634
+ if (
635
+ _hash_record(
636
+ b"agent-evolve:configuration:v1\x00",
637
+ thaw_json(self.child_configuration),
638
+ )
639
+ != self.child_configuration_sha256
640
+ ):
641
+ raise ValueError("child_configuration_sha256 does not match configuration")
642
+ _require_token(self.operator_family, name="operator_family")
643
+ if type(self.affected_paths) is not tuple or not self.affected_paths:
644
+ raise ValueError("affected_paths must be a non-empty exact tuple")
645
+ if any(
646
+ type(path) is not str or _PATH.fullmatch(path) is None
647
+ for path in self.affected_paths
648
+ ):
649
+ raise ValueError("affected_paths must contain canonical JSON paths")
650
+ if self.affected_paths != tuple(sorted(set(self.affected_paths))):
651
+ raise ValueError("affected_paths must be unique and canonically sorted")
652
+ _require_frozen_object(self.observed_action, name="observed_action")
653
+ _require_token(
654
+ self.action_semantics_compiler_id,
655
+ name="action_semantics_compiler_id",
656
+ )
657
+ if (
658
+ type(self.action_semantics_compiler_version) is not int
659
+ or self.action_semantics_compiler_version <= 0
660
+ ):
661
+ raise ValueError("action_semantics_compiler_version must be positive")
662
+ require_sha256(
663
+ self.action_semantics_definition_sha256,
664
+ "action_semantics_definition_sha256",
665
+ )
666
+ if type(self.intervention_identifiability) is not InterventionIdentifiability:
667
+ raise TypeError(
668
+ "intervention_identifiability must be exact InterventionIdentifiability"
669
+ )
670
+ if (
671
+ type(self.metrics) is not tuple
672
+ or not self.metrics
673
+ or any(type(value) is not ObservedMetricEffect for value in self.metrics)
674
+ ):
675
+ raise ValueError("metrics must contain exact ObservedMetricEffect values")
676
+ metric_ids = tuple(value.metric_id for value in self.metrics)
677
+ if metric_ids != tuple(sorted(set(metric_ids))):
678
+ raise ValueError("metrics must use unique canonical metric order")
679
+ if type(self.mechanism_identifying_design) is not bool:
680
+ raise TypeError("mechanism_identifying_design must be an exact boolean")
681
+ if self.mechanism_identifying_design and self.provenance is not (
682
+ EvidenceProvenance.RANDOMIZED_ADMINISTRATION
683
+ ):
684
+ raise ValueError(
685
+ "mechanism-identifying evidence must be randomized administration"
686
+ )
687
+ if (
688
+ self.provenance is EvidenceProvenance.RANDOMIZED_ADMINISTRATION
689
+ and self.causal_boundary.prospective_assignment_sha256 is None
690
+ ):
691
+ raise ValueError(
692
+ "randomized administration requires a prospective ITT assignment"
693
+ )
694
+ object.__setattr__(
695
+ self,
696
+ "observation_sha256",
697
+ _hash_record(_OBSERVATION_DOMAIN, self._unsigned_record()),
698
+ )
699
+
700
+ @classmethod
701
+ def configuration_sha256(cls, value: FrozenJsonObject) -> str:
702
+ _require_frozen_object(value, name="configuration")
703
+ return _hash_record(b"agent-evolve:configuration:v1\x00", thaw_json(value))
704
+
705
+ def _unsigned_record(self) -> dict[str, object]:
706
+ return {
707
+ "schema_version": 3,
708
+ "source_evidence_id": self.source_evidence_id,
709
+ "event_index": self.event_index,
710
+ "workload_instance_sha256": self.workload_instance_sha256,
711
+ "evaluator_contract_sha256": self.evaluator_contract_sha256,
712
+ "campaign_sha256": self.campaign_sha256,
713
+ "parent_candidate_id": self.parent_candidate_id.value,
714
+ "child_candidate_id": self.child_candidate_id.value,
715
+ "operator_invocation_id": self.operator_invocation_id.value,
716
+ "finite_contract_identity_sha256": (self.finite_contract_identity_sha256),
717
+ "provenance": self.provenance.value,
718
+ "causal_boundary": self.causal_boundary.to_record(),
719
+ "parent_configuration": thaw_json(self.parent_configuration),
720
+ "child_configuration": thaw_json(self.child_configuration),
721
+ "parent_configuration_sha256": self.parent_configuration_sha256,
722
+ "child_configuration_sha256": self.child_configuration_sha256,
723
+ "parent_outcome_sha256": self.parent_outcome_sha256,
724
+ "child_outcome_sha256": self.child_outcome_sha256,
725
+ "operator_family": self.operator_family,
726
+ "affected_paths": list(self.affected_paths),
727
+ "observed_action": thaw_json(self.observed_action),
728
+ "action_semantics_compiler": {
729
+ "compiler_id": self.action_semantics_compiler_id,
730
+ "compiler_version": self.action_semantics_compiler_version,
731
+ "definition_sha256": self.action_semantics_definition_sha256,
732
+ },
733
+ "intervention_identifiability": self.intervention_identifiability.value,
734
+ "metrics": [value.to_record() for value in self.metrics],
735
+ "lineage_cluster_sha256": self.lineage_cluster_sha256,
736
+ "factorial_block_sha256": self.factorial_block_sha256,
737
+ "mechanism_identifying_design": self.mechanism_identifying_design,
738
+ }
739
+
740
+ def to_record(self) -> dict[str, object]:
741
+ return {
742
+ **self._unsigned_record(),
743
+ "observation_sha256": self.observation_sha256,
744
+ }
745
+
746
+
747
+ @dataclass(frozen=True, slots=True)
748
+ class GlobalEvidenceRegistrySnapshot:
749
+ """Complete immutable observation registry visible through one event index."""
750
+
751
+ captured_through_event_index: int
752
+ observations: tuple[AuthenticatedHypothesisObservation, ...]
753
+ snapshot_sha256: str = field(init=False)
754
+
755
+ def __post_init__(self) -> None:
756
+ _require_event_index(
757
+ self.captured_through_event_index,
758
+ name="captured_through_event_index",
759
+ )
760
+ if type(self.observations) is not tuple or any(
761
+ type(value) is not AuthenticatedHypothesisObservation
762
+ for value in self.observations
763
+ ):
764
+ raise TypeError(
765
+ "observations must be an exact tuple of authenticated observations"
766
+ )
767
+ keys = tuple(value.source_evidence_id for value in self.observations)
768
+ if keys != tuple(sorted(set(keys))):
769
+ raise ValueError(
770
+ "observations must have unique source IDs in canonical order"
771
+ )
772
+ if any(
773
+ value.event_index > self.captured_through_event_index
774
+ for value in self.observations
775
+ ):
776
+ raise ValueError("registry contains evidence after its capture cutoff")
777
+ object.__setattr__(
778
+ self,
779
+ "snapshot_sha256",
780
+ _hash_record(_REGISTRY_DOMAIN, self._unsigned_record()),
781
+ )
782
+
783
+ @classmethod
784
+ def seal(
785
+ cls,
786
+ *,
787
+ captured_through_event_index: int,
788
+ observations: Sequence[AuthenticatedHypothesisObservation],
789
+ ) -> "GlobalEvidenceRegistrySnapshot":
790
+ if isinstance(observations, (str, bytes)) or not isinstance(
791
+ observations, Sequence
792
+ ):
793
+ raise TypeError("observations must be a sequence")
794
+ if any(
795
+ type(value) is not AuthenticatedHypothesisObservation
796
+ for value in observations
797
+ ):
798
+ raise TypeError(
799
+ "observations must contain exact authenticated observations"
800
+ )
801
+ canonical = tuple(
802
+ sorted(observations, key=lambda value: value.source_evidence_id)
803
+ )
804
+ return cls(captured_through_event_index, canonical)
805
+
806
+ def _unsigned_record(self) -> dict[str, object]:
807
+ return {
808
+ "schema_version": 1,
809
+ "captured_through_event_index": self.captured_through_event_index,
810
+ "observation_sha256s": [
811
+ value.observation_sha256 for value in self.observations
812
+ ],
813
+ }
814
+
815
+ def to_record(self) -> dict[str, object]:
816
+ return {**self._unsigned_record(), "snapshot_sha256": self.snapshot_sha256}
817
+
818
+
819
+ class TriggerMatch(str, Enum):
820
+ EXACT = "exact_trigger"
821
+ OFF_TRIGGER = "off_trigger"
822
+ AMBIGUOUS = "ambiguous_trigger"
823
+
824
+
825
+ class InterventionMatch(str, Enum):
826
+ EXACT = "exact_intervention"
827
+ NEAR = "near_intervention"
828
+ DIFFERENT = "different_intervention"
829
+ NON_IDENTIFIABLE = "non_identifiable_intervention"
830
+
831
+
832
+ @dataclass(frozen=True, slots=True)
833
+ class HypothesisEvidenceMatchReceipt:
834
+ """Workload matcher result bound to one request and one observation."""
835
+
836
+ request_sha256: str
837
+ observation_sha256: str
838
+ trigger_match: TriggerMatch
839
+ intervention_match: InterventionMatch
840
+ matcher_policy_id: str
841
+ matcher_policy_version: int
842
+ matcher_definition_sha256: str
843
+ receipt_sha256: str = field(init=False)
844
+
845
+ def __post_init__(self) -> None:
846
+ require_sha256(self.request_sha256, "request_sha256")
847
+ require_sha256(self.observation_sha256, "observation_sha256")
848
+ if type(self.trigger_match) is not TriggerMatch:
849
+ raise TypeError("trigger_match must be exact TriggerMatch")
850
+ if type(self.intervention_match) is not InterventionMatch:
851
+ raise TypeError("intervention_match must be exact InterventionMatch")
852
+ _require_token(self.matcher_policy_id, name="matcher_policy_id")
853
+ if (
854
+ type(self.matcher_policy_version) is not int
855
+ or self.matcher_policy_version <= 0
856
+ ):
857
+ raise ValueError("matcher_policy_version must be a positive integer")
858
+ require_sha256(self.matcher_definition_sha256, "matcher_definition_sha256")
859
+ object.__setattr__(
860
+ self,
861
+ "receipt_sha256",
862
+ _hash_record(_MATCH_DOMAIN, self._unsigned_record()),
863
+ )
864
+
865
+ def _unsigned_record(self) -> dict[str, object]:
866
+ return {
867
+ "schema_version": 1,
868
+ "request_sha256": self.request_sha256,
869
+ "observation_sha256": self.observation_sha256,
870
+ "trigger_match": self.trigger_match.value,
871
+ "intervention_match": self.intervention_match.value,
872
+ "matcher": {
873
+ "policy_id": self.matcher_policy_id,
874
+ "policy_version": self.matcher_policy_version,
875
+ "definition_sha256": self.matcher_definition_sha256,
876
+ },
877
+ }
878
+
879
+ def to_record(self) -> dict[str, object]:
880
+ return {**self._unsigned_record(), "receipt_sha256": self.receipt_sha256}
881
+
882
+
883
+ @runtime_checkable
884
+ class GlobalHypothesisEvidenceMatcher(Protocol):
885
+ """Inverted workload seam for typed trigger/intervention matching."""
886
+
887
+ policy_id: str
888
+ policy_version: int
889
+ definition_sha256: str
890
+
891
+ def classify(
892
+ self,
893
+ request: GlobalHypothesisAuditRequest,
894
+ observation: AuthenticatedHypothesisObservation,
895
+ ) -> HypothesisEvidenceMatchReceipt: ...
896
+
897
+
898
+ class EvidenceDisposition(str, Enum):
899
+ SUPPORT = "support"
900
+ COUNTEREXAMPLE = "counterexample"
901
+ OFF_TRIGGER_CONTROL = "off_trigger_control"
902
+ NON_IDENTIFIABLE = "non_identifiable"
903
+ NEAR_INTERVENTION = "near_intervention"
904
+ IRRELEVANT = "irrelevant"
905
+ DUPLICATE = "deduplicated_exact_repeat"
906
+ OUT_OF_SCOPE = "out_of_scope"
907
+ AFTER_CUTOFF = "after_cutoff"
908
+
909
+
910
+ @dataclass(frozen=True, slots=True)
911
+ class MetricClaimAssessment:
912
+ metric_id: str
913
+ expected_direction: MetricEffectDirection
914
+ actual_direction: MetricEffectDirection
915
+ actual_delta: float
916
+ direction_matches: bool
917
+ magnitude_matches: bool | None
918
+
919
+ @property
920
+ def matches(self) -> bool:
921
+ return self.direction_matches and self.magnitude_matches is not False
922
+
923
+ def to_record(self) -> dict[str, object]:
924
+ return {
925
+ "metric_id": self.metric_id,
926
+ "expected_direction": self.expected_direction.value,
927
+ "actual_direction": self.actual_direction.value,
928
+ "actual_delta_hex": self.actual_delta.hex(),
929
+ "direction_matches": self.direction_matches,
930
+ "magnitude_matches": self.magnitude_matches,
931
+ "matches": self.matches,
932
+ }
933
+
934
+
935
+ @dataclass(frozen=True, slots=True)
936
+ class GlobalEvidenceDecision:
937
+ source_evidence_id: str
938
+ observation_sha256: str
939
+ event_index: int
940
+ workload_instance_sha256: str
941
+ itt_estimand_unit_sha256: str
942
+ disposition: EvidenceDisposition
943
+ match_receipt_sha256: str | None
944
+ metric_assessments: tuple[MetricClaimAssessment, ...]
945
+ effective_cluster_sha256: str | None
946
+ post_origin_revision_evidence: bool
947
+ duplicate_of_source_evidence_id: str | None = None
948
+ predictions_match: bool | None = None
949
+
950
+ def __post_init__(self) -> None:
951
+ require_sha256(self.source_evidence_id, "source_evidence_id")
952
+ require_sha256(self.observation_sha256, "observation_sha256")
953
+ require_sha256(self.workload_instance_sha256, "workload_instance_sha256")
954
+ require_sha256(self.itt_estimand_unit_sha256, "itt_estimand_unit_sha256")
955
+ _require_event_index(self.event_index, name="event_index")
956
+ if type(self.disposition) is not EvidenceDisposition:
957
+ raise TypeError("disposition must be exact EvidenceDisposition")
958
+ for name in (
959
+ "match_receipt_sha256",
960
+ "effective_cluster_sha256",
961
+ "duplicate_of_source_evidence_id",
962
+ ):
963
+ value = getattr(self, name)
964
+ if value is not None:
965
+ require_sha256(value, name)
966
+ if type(self.metric_assessments) is not tuple:
967
+ raise TypeError("metric_assessments must be an exact tuple")
968
+ if type(self.post_origin_revision_evidence) is not bool:
969
+ raise TypeError("post_origin_revision_evidence must be an exact boolean")
970
+ if (
971
+ self.predictions_match is not None
972
+ and type(self.predictions_match) is not bool
973
+ ):
974
+ raise TypeError("predictions_match must be an exact boolean or None")
975
+ if self.disposition is EvidenceDisposition.DUPLICATE:
976
+ if self.duplicate_of_source_evidence_id is None:
977
+ raise ValueError("duplicate evidence must identify its representative")
978
+ elif self.duplicate_of_source_evidence_id is not None:
979
+ raise ValueError("only duplicate evidence may identify a representative")
980
+
981
+ def to_record(self) -> dict[str, object]:
982
+ return {
983
+ "source_evidence_id": self.source_evidence_id,
984
+ "observation_sha256": self.observation_sha256,
985
+ "event_index": self.event_index,
986
+ "workload_instance_sha256": self.workload_instance_sha256,
987
+ "itt_estimand_unit_sha256": self.itt_estimand_unit_sha256,
988
+ "disposition": self.disposition.value,
989
+ "match_receipt_sha256": self.match_receipt_sha256,
990
+ "metric_assessments": [
991
+ value.to_record() for value in self.metric_assessments
992
+ ],
993
+ "effective_cluster_sha256": self.effective_cluster_sha256,
994
+ "post_origin_revision_evidence": self.post_origin_revision_evidence,
995
+ "duplicate_of_source_evidence_id": self.duplicate_of_source_evidence_id,
996
+ "predictions_match": self.predictions_match,
997
+ }
998
+
999
+
1000
+ class GlobalHypothesisVerdict(str, Enum):
1001
+ SUPPORT = "globally_audited_support"
1002
+ COUNTEREXAMPLE = "contradicted"
1003
+ INSUFFICIENT = "insufficient_evidence"
1004
+ NON_IDENTIFIABLE = "non_identifiable"
1005
+
1006
+
1007
+ @dataclass(frozen=True, slots=True)
1008
+ class GlobalHypothesisAuditReceipt:
1009
+ """Closed semantic decision with no causal-memory reward channel."""
1010
+
1011
+ request_sha256: str
1012
+ registry_snapshot_sha256: str
1013
+ audit_policy_id: str
1014
+ audit_policy_version: int
1015
+ audit_policy_definition_sha256: str
1016
+ verdict: GlobalHypothesisVerdict
1017
+ decisions: tuple[GlobalEvidenceDecision, ...]
1018
+ support_ids: tuple[str, ...]
1019
+ counterexample_ids: tuple[str, ...]
1020
+ off_trigger_control_ids: tuple[str, ...]
1021
+ non_identifiable_ids: tuple[str, ...]
1022
+ raw_support_count: int
1023
+ effective_support_cluster_count: int
1024
+ support_instance_count: int
1025
+ untested_workload_instance_sha256s: tuple[str, ...]
1026
+ coverage_gaps: tuple[str, ...]
1027
+ necessity_contradicted: bool
1028
+ mechanism_identified: bool
1029
+ lifecycle_decision: str
1030
+ audit_receipt_sha256: str = field(init=False)
1031
+
1032
+ def __post_init__(self) -> None:
1033
+ require_sha256(self.request_sha256, "request_sha256")
1034
+ require_sha256(self.registry_snapshot_sha256, "registry_snapshot_sha256")
1035
+ _require_token(self.audit_policy_id, name="audit_policy_id")
1036
+ if type(self.audit_policy_version) is not int or self.audit_policy_version <= 0:
1037
+ raise ValueError("audit_policy_version must be a positive exact integer")
1038
+ require_sha256(
1039
+ self.audit_policy_definition_sha256,
1040
+ "audit_policy_definition_sha256",
1041
+ )
1042
+ if type(self.verdict) is not GlobalHypothesisVerdict:
1043
+ raise TypeError("verdict must be exact GlobalHypothesisVerdict")
1044
+ if type(self.decisions) is not tuple or any(
1045
+ type(value) is not GlobalEvidenceDecision for value in self.decisions
1046
+ ):
1047
+ raise TypeError(
1048
+ "decisions must contain exact GlobalEvidenceDecision values"
1049
+ )
1050
+ decision_ids = tuple(value.source_evidence_id for value in self.decisions)
1051
+ if decision_ids != tuple(sorted(set(decision_ids))):
1052
+ raise ValueError("decisions must have unique canonical source order")
1053
+ for name in (
1054
+ "support_ids",
1055
+ "counterexample_ids",
1056
+ "off_trigger_control_ids",
1057
+ "non_identifiable_ids",
1058
+ ):
1059
+ _require_sha_tuple(getattr(self, name), name=name, empty=True)
1060
+ expected_ids = {
1061
+ disposition: tuple(
1062
+ value.source_evidence_id
1063
+ for value in self.decisions
1064
+ if value.disposition is disposition
1065
+ )
1066
+ for disposition in (
1067
+ EvidenceDisposition.SUPPORT,
1068
+ EvidenceDisposition.COUNTEREXAMPLE,
1069
+ EvidenceDisposition.OFF_TRIGGER_CONTROL,
1070
+ EvidenceDisposition.NON_IDENTIFIABLE,
1071
+ )
1072
+ }
1073
+ observed_ids = {
1074
+ EvidenceDisposition.SUPPORT: self.support_ids,
1075
+ EvidenceDisposition.COUNTEREXAMPLE: self.counterexample_ids,
1076
+ EvidenceDisposition.OFF_TRIGGER_CONTROL: self.off_trigger_control_ids,
1077
+ EvidenceDisposition.NON_IDENTIFIABLE: self.non_identifiable_ids,
1078
+ }
1079
+ if observed_ids != expected_ids:
1080
+ raise ValueError("receipt evidence ID summaries differ from its decisions")
1081
+ for name in (
1082
+ "raw_support_count",
1083
+ "effective_support_cluster_count",
1084
+ "support_instance_count",
1085
+ ):
1086
+ value = getattr(self, name)
1087
+ if type(value) is not int or value < 0:
1088
+ raise ValueError(f"{name} must be a non-negative exact integer")
1089
+ _require_sha_tuple(
1090
+ self.untested_workload_instance_sha256s,
1091
+ name="untested_workload_instance_sha256s",
1092
+ empty=True,
1093
+ )
1094
+ support_decisions = tuple(
1095
+ value
1096
+ for value in self.decisions
1097
+ if value.disposition is EvidenceDisposition.SUPPORT
1098
+ )
1099
+ if self.raw_support_count != len(support_decisions):
1100
+ raise ValueError("raw_support_count differs from support decisions")
1101
+ if any(value.effective_cluster_sha256 is None for value in support_decisions):
1102
+ raise ValueError("support decisions require an effective cluster")
1103
+ if self.effective_support_cluster_count != len(
1104
+ {value.effective_cluster_sha256 for value in support_decisions}
1105
+ ):
1106
+ raise ValueError(
1107
+ "effective_support_cluster_count differs from support decisions"
1108
+ )
1109
+ if self.support_instance_count != len(
1110
+ {value.workload_instance_sha256 for value in support_decisions}
1111
+ ):
1112
+ raise ValueError("support_instance_count differs from support decisions")
1113
+ if type(self.coverage_gaps) is not tuple:
1114
+ raise TypeError("coverage_gaps must be an exact tuple")
1115
+ for value in self.coverage_gaps:
1116
+ _require_token(value, name="coverage_gaps")
1117
+ if self.coverage_gaps != tuple(sorted(set(self.coverage_gaps))):
1118
+ raise ValueError("coverage_gaps must be unique and canonically sorted")
1119
+ if type(self.necessity_contradicted) is not bool:
1120
+ raise TypeError("necessity_contradicted must be an exact boolean")
1121
+ if type(self.mechanism_identified) is not bool:
1122
+ raise TypeError("mechanism_identified must be an exact boolean")
1123
+ _require_canonical_text(self.lifecycle_decision, name="lifecycle_decision")
1124
+ object.__setattr__(
1125
+ self,
1126
+ "audit_receipt_sha256",
1127
+ _hash_record(_RECEIPT_DOMAIN, self._unsigned_record()),
1128
+ )
1129
+
1130
+ @property
1131
+ def causal_credit_updates(self) -> tuple[()]:
1132
+ """Truth audits can never retroactively credit an individual card."""
1133
+
1134
+ return ()
1135
+
1136
+ def _unsigned_record(self) -> dict[str, object]:
1137
+ return {
1138
+ "schema_version": 1,
1139
+ "request_sha256": self.request_sha256,
1140
+ "registry_snapshot_sha256": self.registry_snapshot_sha256,
1141
+ "audit_policy": {
1142
+ "policy_id": self.audit_policy_id,
1143
+ "policy_version": self.audit_policy_version,
1144
+ "definition_sha256": self.audit_policy_definition_sha256,
1145
+ },
1146
+ "verdict": self.verdict.value,
1147
+ "decisions": [value.to_record() for value in self.decisions],
1148
+ "support_ids": list(self.support_ids),
1149
+ "counterexample_ids": list(self.counterexample_ids),
1150
+ "off_trigger_control_ids": list(self.off_trigger_control_ids),
1151
+ "non_identifiable_ids": list(self.non_identifiable_ids),
1152
+ "raw_support_count": self.raw_support_count,
1153
+ "effective_support_cluster_count": self.effective_support_cluster_count,
1154
+ "support_instance_count": self.support_instance_count,
1155
+ "untested_workload_instance_sha256s": list(
1156
+ self.untested_workload_instance_sha256s
1157
+ ),
1158
+ "coverage_gaps": list(self.coverage_gaps),
1159
+ "necessity_contradicted": self.necessity_contradicted,
1160
+ "mechanism_identified": self.mechanism_identified,
1161
+ "lifecycle_decision": self.lifecycle_decision,
1162
+ "causal_credit_policy": ("semantic_truth_only_no_retroactive_card_credit"),
1163
+ "causal_credit_updates": [],
1164
+ }
1165
+
1166
+ def to_record(self) -> dict[str, object]:
1167
+ return {
1168
+ **self._unsigned_record(),
1169
+ "audit_receipt_sha256": self.audit_receipt_sha256,
1170
+ }
1171
+
1172
+
1173
+ class AmbiguousInterventionIdentityError(ValueError):
1174
+ """A matcher attempted to identify an ambiguous or joint intervention."""
1175
+
1176
+
1177
+ @dataclass(frozen=True, slots=True)
1178
+ class GlobalHypothesisFalsificationGate:
1179
+ """Exhaustively adjudicate one sealed hypothesis against a sealed registry."""
1180
+
1181
+ policy_id: str = GLOBAL_FALSIFICATION_POLICY_ID
1182
+ policy_version: int = GLOBAL_FALSIFICATION_POLICY_VERSION
1183
+ definition_sha256: str = GLOBAL_FALSIFICATION_POLICY_DEFINITION_SHA256
1184
+
1185
+ def __post_init__(self) -> None:
1186
+ _require_token(self.policy_id, name="policy_id")
1187
+ if (
1188
+ type(self.policy_version) is not int
1189
+ or self.policy_version != GLOBAL_FALSIFICATION_POLICY_VERSION
1190
+ ):
1191
+ raise ValueError("unsupported global falsification policy version")
1192
+ if self.definition_sha256 != GLOBAL_FALSIFICATION_POLICY_DEFINITION_SHA256:
1193
+ raise ValueError("unsupported global falsification policy definition")
1194
+
1195
+ def audit(
1196
+ self,
1197
+ *,
1198
+ request: GlobalHypothesisAuditRequest,
1199
+ registry: GlobalEvidenceRegistrySnapshot,
1200
+ matcher: GlobalHypothesisEvidenceMatcher,
1201
+ ) -> GlobalHypothesisAuditReceipt:
1202
+ if type(request) is not GlobalHypothesisAuditRequest:
1203
+ raise TypeError("request must be exact GlobalHypothesisAuditRequest")
1204
+ if type(registry) is not GlobalEvidenceRegistrySnapshot:
1205
+ raise TypeError("registry must be exact GlobalEvidenceRegistrySnapshot")
1206
+ if registry.snapshot_sha256 != request.registry_snapshot_sha256:
1207
+ raise ValueError("request is bound to a different registry snapshot")
1208
+ if registry.captured_through_event_index < request.audit_cutoff_event_index:
1209
+ raise ValueError("registry does not cover the requested audit cutoff")
1210
+ if request.audit_policy_definition_sha256 != self.definition_sha256:
1211
+ raise ValueError("audit policy differs from the sealed request")
1212
+ if not isinstance(matcher, GlobalHypothesisEvidenceMatcher):
1213
+ raise TypeError("matcher must implement GlobalHypothesisEvidenceMatcher")
1214
+ _require_token(matcher.policy_id, name="matcher.policy_id")
1215
+ if type(matcher.policy_version) is not int or matcher.policy_version <= 0:
1216
+ raise ValueError("matcher.policy_version must be a positive integer")
1217
+ require_sha256(matcher.definition_sha256, "matcher.definition_sha256")
1218
+ if matcher.definition_sha256 != request.matcher_definition_sha256:
1219
+ raise ValueError("matcher identity differs from the sealed request")
1220
+
1221
+ representative_by_repeat: dict[tuple[str, str, str, str, str], str] = {}
1222
+ for observation in sorted(
1223
+ registry.observations,
1224
+ key=lambda value: (value.event_index, value.source_evidence_id),
1225
+ ):
1226
+ if (
1227
+ observation.event_index <= request.audit_cutoff_event_index
1228
+ and self._in_scope(request.scope, observation)
1229
+ ):
1230
+ repeat_key = (
1231
+ observation.workload_instance_sha256,
1232
+ observation.campaign_sha256,
1233
+ observation.parent_configuration_sha256,
1234
+ observation.child_configuration_sha256,
1235
+ observation.evaluator_contract_sha256,
1236
+ )
1237
+ representative_by_repeat.setdefault(
1238
+ repeat_key, observation.source_evidence_id
1239
+ )
1240
+ decisions: list[GlobalEvidenceDecision] = []
1241
+ support_instances: set[str] = set()
1242
+ support_clusters: set[str] = set()
1243
+ post_origin_support_instances: set[str] = set()
1244
+ post_origin_support_clusters: set[str] = set()
1245
+ mechanism_identified = False
1246
+ post_origin_mechanism_identified = False
1247
+
1248
+ for observation in registry.observations:
1249
+ post_origin = observation.event_index > request.origin_cutoff_event_index
1250
+ if observation.event_index > request.audit_cutoff_event_index:
1251
+ decisions.append(
1252
+ self._simple_decision(
1253
+ observation,
1254
+ EvidenceDisposition.AFTER_CUTOFF,
1255
+ post_origin=post_origin,
1256
+ )
1257
+ )
1258
+ continue
1259
+ if not self._in_scope(request.scope, observation):
1260
+ decisions.append(
1261
+ self._simple_decision(
1262
+ observation,
1263
+ EvidenceDisposition.OUT_OF_SCOPE,
1264
+ post_origin=post_origin,
1265
+ )
1266
+ )
1267
+ continue
1268
+ repeat_key = (
1269
+ observation.workload_instance_sha256,
1270
+ observation.campaign_sha256,
1271
+ observation.parent_configuration_sha256,
1272
+ observation.child_configuration_sha256,
1273
+ observation.evaluator_contract_sha256,
1274
+ )
1275
+ representative = representative_by_repeat[repeat_key]
1276
+ if representative != observation.source_evidence_id:
1277
+ decisions.append(
1278
+ self._simple_decision(
1279
+ observation,
1280
+ EvidenceDisposition.DUPLICATE,
1281
+ post_origin=post_origin,
1282
+ duplicate_of=representative,
1283
+ )
1284
+ )
1285
+ continue
1286
+ match = matcher.classify(request, observation)
1287
+ self._validate_match(request, observation, matcher, match)
1288
+ assessments = self._metric_assessments(request, observation)
1289
+ predictions_match = (
1290
+ None
1291
+ if assessments is None
1292
+ else all(value.matches for value in assessments)
1293
+ )
1294
+ cluster = self._effective_cluster(observation)
1295
+ disposition = self._disposition(
1296
+ observation=observation,
1297
+ match=match,
1298
+ assessments=assessments,
1299
+ )
1300
+ if disposition is EvidenceDisposition.SUPPORT:
1301
+ support_instances.add(observation.workload_instance_sha256)
1302
+ support_clusters.add(cluster)
1303
+ mechanism_identified = mechanism_identified or (
1304
+ observation.mechanism_identifying_design
1305
+ )
1306
+ if post_origin:
1307
+ post_origin_support_instances.add(
1308
+ observation.workload_instance_sha256
1309
+ )
1310
+ post_origin_support_clusters.add(cluster)
1311
+ post_origin_mechanism_identified = (
1312
+ post_origin_mechanism_identified
1313
+ or observation.mechanism_identifying_design
1314
+ )
1315
+ decisions.append(
1316
+ GlobalEvidenceDecision(
1317
+ source_evidence_id=observation.source_evidence_id,
1318
+ observation_sha256=observation.observation_sha256,
1319
+ event_index=observation.event_index,
1320
+ workload_instance_sha256=(observation.workload_instance_sha256),
1321
+ itt_estimand_unit_sha256=(
1322
+ observation.causal_boundary.estimand_unit_sha256
1323
+ ),
1324
+ disposition=disposition,
1325
+ match_receipt_sha256=match.receipt_sha256,
1326
+ metric_assessments=() if assessments is None else assessments,
1327
+ effective_cluster_sha256=(
1328
+ cluster
1329
+ if disposition
1330
+ in {
1331
+ EvidenceDisposition.SUPPORT,
1332
+ EvidenceDisposition.COUNTEREXAMPLE,
1333
+ EvidenceDisposition.OFF_TRIGGER_CONTROL,
1334
+ }
1335
+ else None
1336
+ ),
1337
+ post_origin_revision_evidence=post_origin,
1338
+ predictions_match=predictions_match,
1339
+ )
1340
+ )
1341
+
1342
+ canonical = tuple(sorted(decisions, key=lambda value: value.source_evidence_id))
1343
+ support_ids = self._ids(canonical, EvidenceDisposition.SUPPORT)
1344
+ counterexample_ids = self._ids(canonical, EvidenceDisposition.COUNTEREXAMPLE)
1345
+ control_ids = self._ids(canonical, EvidenceDisposition.OFF_TRIGGER_CONTROL)
1346
+ non_identifiable_ids = self._ids(
1347
+ canonical, EvidenceDisposition.NON_IDENTIFIABLE
1348
+ )
1349
+ necessity_contradicted = request.claim_strength.necessity and any(
1350
+ decision.disposition is EvidenceDisposition.OFF_TRIGGER_CONTROL
1351
+ and decision.predictions_match is True
1352
+ for decision in canonical
1353
+ )
1354
+ exact_trigger_instance_ids = {
1355
+ decision.workload_instance_sha256
1356
+ for decision in canonical
1357
+ if decision.disposition
1358
+ in {
1359
+ EvidenceDisposition.SUPPORT,
1360
+ EvidenceDisposition.COUNTEREXAMPLE,
1361
+ }
1362
+ }
1363
+ untested_instances = tuple(
1364
+ sorted(
1365
+ set(request.scope.workload_instance_sha256s)
1366
+ - exact_trigger_instance_ids
1367
+ )
1368
+ )
1369
+ coverage_gaps = []
1370
+ if not support_ids and not counterexample_ids:
1371
+ coverage_gaps.append("no_identifiable_exact_trigger_intervention_evidence")
1372
+ if len(support_clusters) < request.minimum_support_clusters:
1373
+ coverage_gaps.append("support_cluster_threshold_not_met")
1374
+ if len(support_instances) < request.minimum_support_instances:
1375
+ coverage_gaps.append("support_instance_threshold_not_met")
1376
+ post_origin_support_ids = tuple(
1377
+ value.source_evidence_id
1378
+ for value in canonical
1379
+ if value.disposition is EvidenceDisposition.SUPPORT
1380
+ and value.post_origin_revision_evidence
1381
+ and value.event_index > request.origin_cutoff_event_index
1382
+ )
1383
+ if not post_origin_support_ids:
1384
+ coverage_gaps.append("post_origin_support_absent")
1385
+ if len(post_origin_support_clusters) < request.minimum_support_clusters:
1386
+ coverage_gaps.append("post_origin_support_cluster_threshold_not_met")
1387
+ if len(post_origin_support_instances) < request.minimum_support_instances:
1388
+ coverage_gaps.append("post_origin_support_instance_threshold_not_met")
1389
+ if request.claim_strength.necessity and not control_ids:
1390
+ coverage_gaps.append("necessity_off_trigger_controls_absent")
1391
+ if request.claim_strength.mechanistic_or_causal and not mechanism_identified:
1392
+ coverage_gaps.append("mechanism_identifying_trial_absent")
1393
+ if (
1394
+ request.claim_strength.mechanistic_or_causal
1395
+ and not post_origin_mechanism_identified
1396
+ ):
1397
+ coverage_gaps.append("post_origin_mechanism_identifying_trial_absent")
1398
+ if untested_instances:
1399
+ coverage_gaps.append(
1400
+ "workload_instances_without_identifiable_trigger_evidence"
1401
+ )
1402
+ if counterexample_ids or necessity_contradicted:
1403
+ verdict = GlobalHypothesisVerdict.COUNTEREXAMPLE
1404
+ lifecycle = "contradicted__retain_or_deprecate_predecessor_and_revise"
1405
+ elif (
1406
+ request.claim_strength.mechanistic_or_causal
1407
+ and not post_origin_mechanism_identified
1408
+ ):
1409
+ verdict = GlobalHypothesisVerdict.NON_IDENTIFIABLE
1410
+ lifecycle = "quarantined__mechanism_requires_post_origin_identifying_trial"
1411
+ elif (
1412
+ len(post_origin_support_clusters) >= request.minimum_support_clusters
1413
+ and len(post_origin_support_instances) >= request.minimum_support_instances
1414
+ ):
1415
+ verdict = GlobalHypothesisVerdict.SUPPORT
1416
+ lifecycle = (
1417
+ "globally_audited_local_support__eligible_for_preregistered_trial"
1418
+ )
1419
+ elif not support_ids and non_identifiable_ids:
1420
+ verdict = GlobalHypothesisVerdict.NON_IDENTIFIABLE
1421
+ lifecycle = "quarantined__intervention_or_trigger_not_identifiable"
1422
+ else:
1423
+ verdict = GlobalHypothesisVerdict.INSUFFICIENT
1424
+ lifecycle = "quarantined__undersupported_or_scope_restricted"
1425
+ return GlobalHypothesisAuditReceipt(
1426
+ request_sha256=request.request_sha256,
1427
+ registry_snapshot_sha256=registry.snapshot_sha256,
1428
+ audit_policy_id=self.policy_id,
1429
+ audit_policy_version=self.policy_version,
1430
+ audit_policy_definition_sha256=self.definition_sha256,
1431
+ verdict=verdict,
1432
+ decisions=canonical,
1433
+ support_ids=support_ids,
1434
+ counterexample_ids=counterexample_ids,
1435
+ off_trigger_control_ids=control_ids,
1436
+ non_identifiable_ids=non_identifiable_ids,
1437
+ raw_support_count=len(support_ids),
1438
+ effective_support_cluster_count=len(support_clusters),
1439
+ support_instance_count=len(support_instances),
1440
+ untested_workload_instance_sha256s=untested_instances,
1441
+ coverage_gaps=tuple(sorted(coverage_gaps)),
1442
+ necessity_contradicted=necessity_contradicted,
1443
+ mechanism_identified=mechanism_identified,
1444
+ lifecycle_decision=lifecycle,
1445
+ )
1446
+
1447
+ @staticmethod
1448
+ def _in_scope(
1449
+ scope: HypothesisAuditScope,
1450
+ observation: AuthenticatedHypothesisObservation,
1451
+ ) -> bool:
1452
+ return (
1453
+ observation.workload_instance_sha256 in scope.workload_instance_sha256s
1454
+ and observation.evaluator_contract_sha256 == scope.evaluator_contract_sha256
1455
+ and all(
1456
+ metric.adjudicator_definition_sha256
1457
+ == scope.metric_adjudicator_definition_sha256
1458
+ for metric in observation.metrics
1459
+ )
1460
+ and (
1461
+ not scope.campaign_sha256s
1462
+ or observation.campaign_sha256 in scope.campaign_sha256s
1463
+ )
1464
+ )
1465
+
1466
+ @staticmethod
1467
+ def _validate_match(
1468
+ request: GlobalHypothesisAuditRequest,
1469
+ observation: AuthenticatedHypothesisObservation,
1470
+ matcher: GlobalHypothesisEvidenceMatcher,
1471
+ receipt: HypothesisEvidenceMatchReceipt,
1472
+ ) -> None:
1473
+ if type(receipt) is not HypothesisEvidenceMatchReceipt:
1474
+ raise TypeError("matcher returned a foreign receipt type")
1475
+ observed = (
1476
+ receipt.request_sha256,
1477
+ receipt.observation_sha256,
1478
+ receipt.matcher_policy_id,
1479
+ receipt.matcher_policy_version,
1480
+ receipt.matcher_definition_sha256,
1481
+ )
1482
+ expected = (
1483
+ request.request_sha256,
1484
+ observation.observation_sha256,
1485
+ matcher.policy_id,
1486
+ matcher.policy_version,
1487
+ matcher.definition_sha256,
1488
+ )
1489
+ if observed != expected:
1490
+ raise ValueError("matcher receipt belongs to a foreign request or policy")
1491
+ if (
1492
+ observation.intervention_identifiability
1493
+ is not InterventionIdentifiability.EXACT_SINGLE
1494
+ and receipt.intervention_match is not InterventionMatch.NON_IDENTIFIABLE
1495
+ ):
1496
+ raise AmbiguousInterventionIdentityError(
1497
+ "ambiguous or joint interventions must fail closed as non-identifiable"
1498
+ )
1499
+ if receipt.intervention_match is InterventionMatch.EXACT and (
1500
+ observation.affected_paths != request.intervention.affected_paths
1501
+ or observation.operator_family
1502
+ not in request.intervention.admissible_operator_families
1503
+ ):
1504
+ raise ValueError(
1505
+ "exact intervention match contradicts the sealed path or operator family"
1506
+ )
1507
+
1508
+ @staticmethod
1509
+ def _metric_assessments(
1510
+ request: GlobalHypothesisAuditRequest,
1511
+ observation: AuthenticatedHypothesisObservation,
1512
+ ) -> tuple[MetricClaimAssessment, ...] | None:
1513
+ by_metric = {value.metric_id: value for value in observation.metrics}
1514
+ if any(value.metric_id not in by_metric for value in request.predictions):
1515
+ return None
1516
+ result = []
1517
+ for prediction in request.predictions:
1518
+ actual = by_metric[prediction.metric_id]
1519
+ magnitude_matches = None
1520
+ if prediction.has_magnitude_claim:
1521
+ assert prediction.minimum_delta is not None
1522
+ assert prediction.maximum_delta is not None
1523
+ magnitude_matches = (
1524
+ prediction.minimum_delta <= actual.delta <= prediction.maximum_delta
1525
+ )
1526
+ result.append(
1527
+ MetricClaimAssessment(
1528
+ metric_id=prediction.metric_id,
1529
+ expected_direction=prediction.direction,
1530
+ actual_direction=actual.direction,
1531
+ actual_delta=actual.delta,
1532
+ direction_matches=prediction.direction is actual.direction,
1533
+ magnitude_matches=magnitude_matches,
1534
+ )
1535
+ )
1536
+ return tuple(result)
1537
+
1538
+ @staticmethod
1539
+ def _disposition(
1540
+ *,
1541
+ observation: AuthenticatedHypothesisObservation,
1542
+ match: HypothesisEvidenceMatchReceipt,
1543
+ assessments: tuple[MetricClaimAssessment, ...] | None,
1544
+ ) -> EvidenceDisposition:
1545
+ if (
1546
+ observation.intervention_identifiability
1547
+ is not InterventionIdentifiability.EXACT_SINGLE
1548
+ or match.intervention_match is InterventionMatch.NON_IDENTIFIABLE
1549
+ or match.trigger_match is TriggerMatch.AMBIGUOUS
1550
+ ):
1551
+ return EvidenceDisposition.NON_IDENTIFIABLE
1552
+ if match.intervention_match is InterventionMatch.NEAR:
1553
+ return EvidenceDisposition.NEAR_INTERVENTION
1554
+ if match.intervention_match is InterventionMatch.DIFFERENT:
1555
+ return EvidenceDisposition.IRRELEVANT
1556
+ if assessments is None:
1557
+ return EvidenceDisposition.NON_IDENTIFIABLE
1558
+ if match.trigger_match is TriggerMatch.OFF_TRIGGER:
1559
+ return EvidenceDisposition.OFF_TRIGGER_CONTROL
1560
+ if all(value.matches for value in assessments):
1561
+ return EvidenceDisposition.SUPPORT
1562
+ return EvidenceDisposition.COUNTEREXAMPLE
1563
+
1564
+ @staticmethod
1565
+ def _effective_cluster(observation: AuthenticatedHypothesisObservation) -> str:
1566
+ return _hash_record(
1567
+ _CLUSTER_DOMAIN,
1568
+ {
1569
+ "workload_instance_sha256": observation.workload_instance_sha256,
1570
+ "evaluator_contract_sha256": observation.evaluator_contract_sha256,
1571
+ "campaign_sha256": observation.campaign_sha256,
1572
+ "lineage_cluster_sha256": observation.lineage_cluster_sha256,
1573
+ "factorial_block_sha256": observation.factorial_block_sha256,
1574
+ "itt_estimand_unit_sha256": (
1575
+ observation.causal_boundary.estimand_unit_sha256
1576
+ ),
1577
+ },
1578
+ )
1579
+
1580
+ @staticmethod
1581
+ def _ids(
1582
+ decisions: tuple[GlobalEvidenceDecision, ...],
1583
+ disposition: EvidenceDisposition,
1584
+ ) -> tuple[str, ...]:
1585
+ return tuple(
1586
+ value.source_evidence_id
1587
+ for value in decisions
1588
+ if value.disposition is disposition
1589
+ )
1590
+
1591
+ @staticmethod
1592
+ def _simple_decision(
1593
+ observation: AuthenticatedHypothesisObservation,
1594
+ disposition: EvidenceDisposition,
1595
+ *,
1596
+ post_origin: bool,
1597
+ duplicate_of: str | None = None,
1598
+ ) -> GlobalEvidenceDecision:
1599
+ return GlobalEvidenceDecision(
1600
+ source_evidence_id=observation.source_evidence_id,
1601
+ observation_sha256=observation.observation_sha256,
1602
+ event_index=observation.event_index,
1603
+ workload_instance_sha256=observation.workload_instance_sha256,
1604
+ itt_estimand_unit_sha256=(observation.causal_boundary.estimand_unit_sha256),
1605
+ disposition=disposition,
1606
+ match_receipt_sha256=None,
1607
+ metric_assessments=(),
1608
+ effective_cluster_sha256=None,
1609
+ post_origin_revision_evidence=post_origin,
1610
+ duplicate_of_source_evidence_id=duplicate_of,
1611
+ )
1612
+
1613
+
1614
+ class RevisionEvidenceTiming(str, Enum):
1615
+ AVAILABLE_AT_ORIGIN = "available_at_origin"
1616
+ POST_ORIGIN_REVISION_EVIDENCE = "post_origin_revision_evidence"
1617
+
1618
+
1619
+ @dataclass(frozen=True, slots=True)
1620
+ class RevisionEvidenceReference:
1621
+ source_evidence_id: str
1622
+ disposition: EvidenceDisposition
1623
+ timing: RevisionEvidenceTiming
1624
+
1625
+ def __post_init__(self) -> None:
1626
+ require_sha256(self.source_evidence_id, "source_evidence_id")
1627
+ if type(self.disposition) is not EvidenceDisposition:
1628
+ raise TypeError("disposition must be exact EvidenceDisposition")
1629
+ if type(self.timing) is not RevisionEvidenceTiming:
1630
+ raise TypeError("timing must be exact RevisionEvidenceTiming")
1631
+
1632
+ def to_record(self) -> dict[str, str]:
1633
+ return {
1634
+ "source_evidence_id": self.source_evidence_id,
1635
+ "disposition": self.disposition.value,
1636
+ "timing": self.timing.value,
1637
+ }
1638
+
1639
+
1640
+ @dataclass(frozen=True, slots=True)
1641
+ class AppendOnlyHypothesisRevision:
1642
+ """Successor metadata that never mutates or inherits credit from its parent."""
1643
+
1644
+ predecessor: InsightRef
1645
+ successor: InsightRef
1646
+ predecessor_draft_content_sha256: str
1647
+ successor_draft_content_sha256: str
1648
+ predecessor_audit_request_sha256: str
1649
+ audit_receipt_sha256: str
1650
+ successor_trigger_predicate_sha256: str
1651
+ successor_intervention_signature_sha256: str
1652
+ successor_scope_sha256: str
1653
+ claim_diff: str
1654
+ scope_diff: str
1655
+ evidence: tuple[RevisionEvidenceReference, ...]
1656
+ successor_lifecycle_state: str = field(init=False, default="quarantined")
1657
+ trial_eligibility_reset: bool = field(init=False, default=True)
1658
+ inherited_confirmation_count: int = field(init=False, default=0)
1659
+ inherited_causal_credit: bool = field(init=False, default=False)
1660
+ revision_sha256: str = field(init=False)
1661
+
1662
+ def __post_init__(self) -> None:
1663
+ if (
1664
+ type(self.predecessor) is not InsightRef
1665
+ or type(self.successor) is not InsightRef
1666
+ ):
1667
+ raise TypeError("predecessor and successor must be exact InsightRef values")
1668
+ if (
1669
+ self.successor.insight_id != self.predecessor.insight_id
1670
+ or self.successor.version != self.predecessor.version + 1
1671
+ ):
1672
+ raise ValueError("successor must be the exact next version of predecessor")
1673
+ for name in (
1674
+ "predecessor_draft_content_sha256",
1675
+ "successor_draft_content_sha256",
1676
+ "predecessor_audit_request_sha256",
1677
+ "audit_receipt_sha256",
1678
+ "successor_trigger_predicate_sha256",
1679
+ "successor_intervention_signature_sha256",
1680
+ "successor_scope_sha256",
1681
+ ):
1682
+ require_sha256(getattr(self, name), name)
1683
+ _require_canonical_text(self.claim_diff, name="claim_diff")
1684
+ _require_canonical_text(self.scope_diff, name="scope_diff")
1685
+ if (
1686
+ self.predecessor_draft_content_sha256 == self.successor_draft_content_sha256
1687
+ and self.claim_diff == "unchanged"
1688
+ and self.scope_diff == "unchanged"
1689
+ ):
1690
+ raise ValueError("a revision must change claim content or scope")
1691
+ if type(self.evidence) is not tuple or any(
1692
+ type(value) is not RevisionEvidenceReference for value in self.evidence
1693
+ ):
1694
+ raise TypeError(
1695
+ "evidence must contain exact RevisionEvidenceReference values"
1696
+ )
1697
+ allowed_evidence_dispositions = {
1698
+ EvidenceDisposition.SUPPORT,
1699
+ EvidenceDisposition.COUNTEREXAMPLE,
1700
+ EvidenceDisposition.OFF_TRIGGER_CONTROL,
1701
+ EvidenceDisposition.NON_IDENTIFIABLE,
1702
+ }
1703
+ if any(
1704
+ value.disposition not in allowed_evidence_dispositions
1705
+ for value in self.evidence
1706
+ ):
1707
+ raise ValueError(
1708
+ "revision evidence may contain only matched semantic audit rows"
1709
+ )
1710
+ evidence_ids = tuple(value.source_evidence_id for value in self.evidence)
1711
+ if evidence_ids != tuple(sorted(set(evidence_ids))):
1712
+ raise ValueError("revision evidence must use unique canonical source order")
1713
+ object.__setattr__(
1714
+ self,
1715
+ "revision_sha256",
1716
+ _hash_record(_REVISION_DOMAIN, self._unsigned_record()),
1717
+ )
1718
+
1719
+ @classmethod
1720
+ def from_audit(
1721
+ cls,
1722
+ *,
1723
+ request: GlobalHypothesisAuditRequest,
1724
+ receipt: GlobalHypothesisAuditReceipt,
1725
+ successor: InsightRef,
1726
+ successor_draft_content_sha256: str,
1727
+ successor_trigger_predicate_sha256: str,
1728
+ successor_intervention_signature_sha256: str,
1729
+ successor_scope_sha256: str,
1730
+ claim_diff: str,
1731
+ scope_diff: str,
1732
+ ) -> "AppendOnlyHypothesisRevision":
1733
+ if type(request) is not GlobalHypothesisAuditRequest:
1734
+ raise TypeError("request must be exact GlobalHypothesisAuditRequest")
1735
+ if type(receipt) is not GlobalHypothesisAuditReceipt:
1736
+ raise TypeError("receipt must be exact GlobalHypothesisAuditReceipt")
1737
+ if receipt.request_sha256 != request.request_sha256:
1738
+ raise ValueError("audit receipt belongs to a different hypothesis request")
1739
+ evidence = tuple(
1740
+ RevisionEvidenceReference(
1741
+ source_evidence_id=decision.source_evidence_id,
1742
+ disposition=decision.disposition,
1743
+ timing=(
1744
+ RevisionEvidenceTiming.POST_ORIGIN_REVISION_EVIDENCE
1745
+ if decision.post_origin_revision_evidence
1746
+ else RevisionEvidenceTiming.AVAILABLE_AT_ORIGIN
1747
+ ),
1748
+ )
1749
+ for decision in receipt.decisions
1750
+ if decision.disposition
1751
+ in {
1752
+ EvidenceDisposition.SUPPORT,
1753
+ EvidenceDisposition.COUNTEREXAMPLE,
1754
+ EvidenceDisposition.OFF_TRIGGER_CONTROL,
1755
+ EvidenceDisposition.NON_IDENTIFIABLE,
1756
+ }
1757
+ )
1758
+ return cls(
1759
+ predecessor=request.reference,
1760
+ successor=successor,
1761
+ predecessor_draft_content_sha256=request.draft_content_sha256,
1762
+ successor_draft_content_sha256=successor_draft_content_sha256,
1763
+ predecessor_audit_request_sha256=request.request_sha256,
1764
+ audit_receipt_sha256=receipt.audit_receipt_sha256,
1765
+ successor_trigger_predicate_sha256=(successor_trigger_predicate_sha256),
1766
+ successor_intervention_signature_sha256=(
1767
+ successor_intervention_signature_sha256
1768
+ ),
1769
+ successor_scope_sha256=successor_scope_sha256,
1770
+ claim_diff=claim_diff,
1771
+ scope_diff=scope_diff,
1772
+ evidence=evidence,
1773
+ )
1774
+
1775
+ def _unsigned_record(self) -> dict[str, object]:
1776
+ return {
1777
+ "schema_version": 1,
1778
+ "predecessor": {
1779
+ "insight_id": self.predecessor.insight_id.value,
1780
+ "version": self.predecessor.version,
1781
+ },
1782
+ "successor": {
1783
+ "insight_id": self.successor.insight_id.value,
1784
+ "version": self.successor.version,
1785
+ },
1786
+ "predecessor_draft_content_sha256": (self.predecessor_draft_content_sha256),
1787
+ "successor_draft_content_sha256": self.successor_draft_content_sha256,
1788
+ "predecessor_audit_request_sha256": (self.predecessor_audit_request_sha256),
1789
+ "audit_receipt_sha256": self.audit_receipt_sha256,
1790
+ "successor_trigger_predicate_sha256": (
1791
+ self.successor_trigger_predicate_sha256
1792
+ ),
1793
+ "successor_intervention_signature_sha256": (
1794
+ self.successor_intervention_signature_sha256
1795
+ ),
1796
+ "successor_scope_sha256": self.successor_scope_sha256,
1797
+ "claim_diff": self.claim_diff,
1798
+ "scope_diff": self.scope_diff,
1799
+ "evidence": [value.to_record() for value in self.evidence],
1800
+ "successor_lifecycle_state": self.successor_lifecycle_state,
1801
+ "trial_eligibility_reset": self.trial_eligibility_reset,
1802
+ "inherited_confirmation_count": self.inherited_confirmation_count,
1803
+ "inherited_causal_credit": self.inherited_causal_credit,
1804
+ }
1805
+
1806
+ def to_record(self) -> dict[str, object]:
1807
+ return {**self._unsigned_record(), "revision_sha256": self.revision_sha256}
1808
+
1809
+
1810
+ __all__ = [
1811
+ "AmbiguousInterventionIdentityError",
1812
+ "AppendOnlyHypothesisRevision",
1813
+ "AuthenticatedHypothesisObservation",
1814
+ "CausalEstimandUnit",
1815
+ "EvidenceCausalBoundary",
1816
+ "EvidenceDisposition",
1817
+ "EvidenceProvenance",
1818
+ "GlobalEvidenceDecision",
1819
+ "GlobalEvidenceRegistrySnapshot",
1820
+ "GLOBAL_FALSIFICATION_POLICY_DEFINITION_SHA256",
1821
+ "GLOBAL_FALSIFICATION_POLICY_ID",
1822
+ "GLOBAL_FALSIFICATION_POLICY_VERSION",
1823
+ "GlobalHypothesisAuditReceipt",
1824
+ "GlobalHypothesisAuditRequest",
1825
+ "GlobalHypothesisEvidenceMatcher",
1826
+ "GlobalHypothesisFalsificationGate",
1827
+ "GlobalHypothesisVerdict",
1828
+ "HypothesisAuditScope",
1829
+ "HypothesisClaimStrength",
1830
+ "HypothesisEvidenceMatchReceipt",
1831
+ "HypothesisMetricPrediction",
1832
+ "InterventionIdentifiability",
1833
+ "InterventionMatch",
1834
+ "MetricClaimAssessment",
1835
+ "ObservedMetricEffect",
1836
+ "RevisionEvidenceReference",
1837
+ "RevisionEvidenceTiming",
1838
+ "TriggerMatch",
1839
+ "TypedEvidencePredicate",
1840
+ "TypedInterventionSignature",
1841
+ ]