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,1836 @@
1
+ """Closed, canonical durable codec for the isolated M4b value graph.
2
+
3
+ This outward adapter has no event-store, workflow, model, provider, evaluator,
4
+ or benchmark capability. It converts exact, already-valid M4b values to one
5
+ versioned canonical JSON representation and reconstructs them exclusively
6
+ through their validated constructors and public revalidation boundaries.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ import math
13
+ import struct
14
+ from dataclasses import dataclass
15
+ from enum import Enum
16
+ from typing import Final
17
+
18
+ from agent_evolve.domain.ids import CandidateId, InsightId, OperatorInvocationId
19
+ from agent_evolve.domain.insight import InsightRef
20
+ from agent_evolve.domain.lineage import (
21
+ MAX_SELECTED_INSIGHTS,
22
+ AbsenceContextKind,
23
+ AbsenceFailureKind,
24
+ CandidateOccurrence,
25
+ ParentEdge,
26
+ ParentRole,
27
+ PreservationClaim,
28
+ PreservationExpectation,
29
+ PreservationObligation,
30
+ PreservationSource,
31
+ VariationCase,
32
+ VariationKind,
33
+ VariationParent,
34
+ validate_variation_case,
35
+ )
36
+ from agent_evolve.domain.patch import (
37
+ ArrayIndex,
38
+ DeleteSequenceItem,
39
+ InsertSequenceItem,
40
+ JsonPath,
41
+ ObjectKey,
42
+ PatchLimits,
43
+ PermuteSequence,
44
+ ReplaceScalar,
45
+ ReplaceSubtree,
46
+ TypedPatch,
47
+ validate_json_path,
48
+ validate_patch_limits,
49
+ validate_patch_operation,
50
+ validate_typed_patch,
51
+ )
52
+ from agent_evolve.domain.typed_json import (
53
+ FrozenJsonArray,
54
+ FrozenJsonObject,
55
+ TypedJsonLimits,
56
+ freeze_json,
57
+ is_frozen_json_value,
58
+ validate_typed_json_limits,
59
+ )
60
+ from agent_evolve.policies.variation.typed_patch import (
61
+ ComponentTagAssignment,
62
+ ParentConfiguration,
63
+ PatchRelation,
64
+ PatchResolution,
65
+ PreservationObligationRequest,
66
+ PreservationVerification,
67
+ ResolutionChoice,
68
+ ThreeWayPatchClassification,
69
+ ThreeWayRelationKind,
70
+ validate_patch_relation,
71
+ validate_preservation_verification,
72
+ )
73
+
74
+
75
+ LINEAGE_CODEC_FORMAT: Final = "agent_evolve.lineage_value"
76
+ LINEAGE_CODEC_SCHEMA_VERSION: Final = 1
77
+
78
+ _MAX_CODEC_BYTES: Final = 1_073_741_824
79
+ _MAX_CODEC_DEPTH: Final = 512
80
+ _MAX_CODEC_NODES: Final = 5_000_000
81
+ _MAX_CODEC_CONTAINER_ITEMS: Final = 1_000_000
82
+ _MAX_CODEC_STRING_BYTES: Final = 67_108_864
83
+ _MAX_CODEC_INTEGER_DIGITS: Final = 4096
84
+
85
+
86
+ class LineageCodecError(ValueError):
87
+ """A bounded, value-free public codec failure."""
88
+
89
+
90
+ class _CodecFailure(Exception):
91
+ """Private control-flow exception whose details never cross the boundary."""
92
+
93
+
94
+ @dataclass(frozen=True, slots=True)
95
+ class LineageCodecLimits:
96
+ """Process-independent resource bounds for canonical wire processing."""
97
+
98
+ max_bytes: int = 268_435_456
99
+ max_depth: int = 256
100
+ max_nodes: int = 2_000_000
101
+ max_container_items: int = 100_000
102
+ max_string_bytes: int = 16_777_216
103
+ max_integer_digits: int = 4096
104
+
105
+ def __post_init__(self) -> None:
106
+ ceilings = (
107
+ ("max_bytes", self.max_bytes, _MAX_CODEC_BYTES),
108
+ ("max_depth", self.max_depth, _MAX_CODEC_DEPTH),
109
+ ("max_nodes", self.max_nodes, _MAX_CODEC_NODES),
110
+ (
111
+ "max_container_items",
112
+ self.max_container_items,
113
+ _MAX_CODEC_CONTAINER_ITEMS,
114
+ ),
115
+ ("max_string_bytes", self.max_string_bytes, _MAX_CODEC_STRING_BYTES),
116
+ (
117
+ "max_integer_digits",
118
+ self.max_integer_digits,
119
+ _MAX_CODEC_INTEGER_DIGITS,
120
+ ),
121
+ )
122
+ for _, value, ceiling in ceilings:
123
+ if type(value) is not int or value <= 0 or value > ceiling:
124
+ raise ValueError("invalid lineage codec limit")
125
+
126
+
127
+ DEFAULT_LINEAGE_CODEC_LIMITS: Final = LineageCodecLimits()
128
+
129
+
130
+ M4B_EXPORTED_VALUE_TYPES: Final = (
131
+ TypedJsonLimits,
132
+ FrozenJsonArray,
133
+ FrozenJsonObject,
134
+ ObjectKey,
135
+ ArrayIndex,
136
+ JsonPath,
137
+ PatchLimits,
138
+ ReplaceScalar,
139
+ ReplaceSubtree,
140
+ InsertSequenceItem,
141
+ DeleteSequenceItem,
142
+ PermuteSequence,
143
+ TypedPatch,
144
+ CandidateOccurrence,
145
+ VariationParent,
146
+ ParentEdge,
147
+ PreservationClaim,
148
+ PreservationObligation,
149
+ VariationCase,
150
+ ComponentTagAssignment,
151
+ PatchRelation,
152
+ ThreeWayPatchClassification,
153
+ PreservationObligationRequest,
154
+ PatchResolution,
155
+ ParentConfiguration,
156
+ PreservationVerification,
157
+ )
158
+
159
+
160
+ # This is the complete closed type/tag registry. Dispatch walks it with
161
+ # identity checks rather than hashing an attacker-controlled subclass type: a
162
+ # custom metaclass must not execute ``__hash__`` or ``__eq__`` at the boundary.
163
+ _EXACT_TYPE_KIND_REGISTRY: Final = (
164
+ (type(None), "json_none"),
165
+ (bool, "json_bool"),
166
+ (int, "json_int"),
167
+ (float, "json_float"),
168
+ (str, "json_string"),
169
+ (CandidateId, "candidate_id"),
170
+ (OperatorInvocationId, "operator_invocation_id"),
171
+ (InsightId, "insight_id"),
172
+ (InsightRef, "insight_ref"),
173
+ (VariationKind, "variation_kind"),
174
+ (ParentRole, "parent_role"),
175
+ (PreservationSource, "preservation_source"),
176
+ (PreservationExpectation, "preservation_expectation"),
177
+ (AbsenceContextKind, "absence_context_kind"),
178
+ (AbsenceFailureKind, "absence_failure_kind"),
179
+ (ThreeWayRelationKind, "three_way_relation_kind"),
180
+ (ResolutionChoice, "resolution_choice"),
181
+ (TypedJsonLimits, "typed_json_limits"),
182
+ (FrozenJsonArray, "frozen_json_array"),
183
+ (FrozenJsonObject, "frozen_json_object"),
184
+ (ObjectKey, "object_key"),
185
+ (ArrayIndex, "array_index"),
186
+ (JsonPath, "json_path"),
187
+ (PatchLimits, "patch_limits"),
188
+ (ReplaceScalar, "replace_scalar"),
189
+ (ReplaceSubtree, "replace_subtree"),
190
+ (InsertSequenceItem, "insert_sequence_item"),
191
+ (DeleteSequenceItem, "delete_sequence_item"),
192
+ (PermuteSequence, "permute_sequence"),
193
+ (TypedPatch, "typed_patch"),
194
+ (CandidateOccurrence, "candidate_occurrence"),
195
+ (VariationParent, "variation_parent"),
196
+ (ParentEdge, "parent_edge"),
197
+ (PreservationClaim, "preservation_claim"),
198
+ (PreservationObligation, "preservation_obligation"),
199
+ (VariationCase, "variation_case"),
200
+ (ComponentTagAssignment, "component_tag_assignment"),
201
+ (PatchRelation, "patch_relation"),
202
+ (ThreeWayPatchClassification, "three_way_patch_classification"),
203
+ (PreservationObligationRequest, "preservation_obligation_request"),
204
+ (PatchResolution, "patch_resolution"),
205
+ (ParentConfiguration, "parent_configuration"),
206
+ (PreservationVerification, "preservation_verification"),
207
+ )
208
+
209
+ LINEAGE_WIRE_KINDS: Final = tuple(
210
+ sorted(kind for _, kind in _EXACT_TYPE_KIND_REGISTRY)
211
+ )
212
+
213
+
214
+ _VARIATION_KINDS: Final = (
215
+ VariationKind.REPRODUCTION,
216
+ VariationKind.TYPED_MUTATION,
217
+ VariationKind.TWO_PARENT_CROSSOVER,
218
+ VariationKind.THREE_WAY_RECOMBINATION,
219
+ VariationKind.REPAIR,
220
+ )
221
+ _PARENT_ROLES: Final = (
222
+ ParentRole.REPRODUCTION_SOURCE,
223
+ ParentRole.MUTATION_PARENT,
224
+ ParentRole.CROSSOVER_LEFT,
225
+ ParentRole.CROSSOVER_RIGHT,
226
+ ParentRole.COMMON_ANCESTOR,
227
+ ParentRole.REPAIR_TARGET,
228
+ )
229
+ _PRESERVATION_SOURCES: Final = (
230
+ PreservationSource.LEFT_BRANCH,
231
+ PreservationSource.RIGHT_BRANCH,
232
+ PreservationSource.IDENTICAL_NEUTRAL,
233
+ )
234
+ _PRESERVATION_EXPECTATIONS: Final = (
235
+ PreservationExpectation.PRESENT,
236
+ PreservationExpectation.ABSENT,
237
+ )
238
+ _ABSENCE_CONTEXT_KINDS: Final = (
239
+ AbsenceContextKind.OBJECT,
240
+ AbsenceContextKind.ARRAY,
241
+ )
242
+ _ABSENCE_FAILURE_KINDS: Final = (
243
+ AbsenceFailureKind.MISSING_OBJECT_KEY,
244
+ AbsenceFailureKind.ARRAY_INDEX_OUT_OF_BOUNDS,
245
+ )
246
+ _THREE_WAY_RELATION_KINDS: Final = (
247
+ ThreeWayRelationKind.IDENTICAL,
248
+ ThreeWayRelationKind.DISJOINT,
249
+ ThreeWayRelationKind.COMPATIBLE_SAME_COMPONENT,
250
+ ThreeWayRelationKind.CONFLICT,
251
+ ThreeWayRelationKind.INVALIDATED,
252
+ )
253
+ _RESOLUTION_CHOICES: Final = (
254
+ ResolutionChoice.CHOOSE_LEFT,
255
+ ResolutionChoice.CHOOSE_RIGHT,
256
+ ResolutionChoice.SYNTHESIZE,
257
+ ResolutionChoice.DROP_BOTH,
258
+ )
259
+
260
+ _VARIATION_KIND_FROM_WIRE: Final = {
261
+ "reproduction": VariationKind.REPRODUCTION,
262
+ "typed_mutation": VariationKind.TYPED_MUTATION,
263
+ "two_parent_crossover": VariationKind.TWO_PARENT_CROSSOVER,
264
+ "three_way_recombination": VariationKind.THREE_WAY_RECOMBINATION,
265
+ "repair": VariationKind.REPAIR,
266
+ }
267
+ _PARENT_ROLE_FROM_WIRE: Final = {
268
+ "reproduction_source": ParentRole.REPRODUCTION_SOURCE,
269
+ "mutation_parent": ParentRole.MUTATION_PARENT,
270
+ "crossover_left": ParentRole.CROSSOVER_LEFT,
271
+ "crossover_right": ParentRole.CROSSOVER_RIGHT,
272
+ "common_ancestor": ParentRole.COMMON_ANCESTOR,
273
+ "repair_target": ParentRole.REPAIR_TARGET,
274
+ }
275
+ _PRESERVATION_SOURCE_FROM_WIRE: Final = {
276
+ "left_branch": PreservationSource.LEFT_BRANCH,
277
+ "right_branch": PreservationSource.RIGHT_BRANCH,
278
+ "identical_neutral": PreservationSource.IDENTICAL_NEUTRAL,
279
+ }
280
+ _PRESERVATION_EXPECTATION_FROM_WIRE: Final = {
281
+ "present": PreservationExpectation.PRESENT,
282
+ "absent": PreservationExpectation.ABSENT,
283
+ }
284
+ _ABSENCE_CONTEXT_KIND_FROM_WIRE: Final = {
285
+ "object": AbsenceContextKind.OBJECT,
286
+ "array": AbsenceContextKind.ARRAY,
287
+ }
288
+ _ABSENCE_FAILURE_KIND_FROM_WIRE: Final = {
289
+ "missing_object_key": AbsenceFailureKind.MISSING_OBJECT_KEY,
290
+ "array_index_out_of_bounds": AbsenceFailureKind.ARRAY_INDEX_OUT_OF_BOUNDS,
291
+ }
292
+ _THREE_WAY_RELATION_KIND_FROM_WIRE: Final = {
293
+ "identical": ThreeWayRelationKind.IDENTICAL,
294
+ "disjoint": ThreeWayRelationKind.DISJOINT,
295
+ "compatible_same_component": ThreeWayRelationKind.COMPATIBLE_SAME_COMPONENT,
296
+ "conflict": ThreeWayRelationKind.CONFLICT,
297
+ "invalidated": ThreeWayRelationKind.INVALIDATED,
298
+ }
299
+ _RESOLUTION_CHOICE_FROM_WIRE: Final = {
300
+ "choose_left": ResolutionChoice.CHOOSE_LEFT,
301
+ "choose_right": ResolutionChoice.CHOOSE_RIGHT,
302
+ "synthesize": ResolutionChoice.SYNTHESIZE,
303
+ "drop_both": ResolutionChoice.DROP_BOTH,
304
+ }
305
+
306
+ _PATCH_OPERATION_TYPES: Final = (
307
+ ReplaceScalar,
308
+ ReplaceSubtree,
309
+ InsertSequenceItem,
310
+ DeleteSequenceItem,
311
+ PermuteSequence,
312
+ )
313
+ _TYPED_JSON_TYPES: Final = (
314
+ type(None),
315
+ bool,
316
+ int,
317
+ float,
318
+ str,
319
+ FrozenJsonArray,
320
+ FrozenJsonObject,
321
+ )
322
+
323
+
324
+ def _validate_codec_limits(limits: LineageCodecLimits) -> None:
325
+ if type(limits) is not LineageCodecLimits:
326
+ raise _CodecFailure
327
+ LineageCodecLimits.__post_init__(limits)
328
+
329
+
330
+ def _bounded_string(value: object, limits: LineageCodecLimits) -> str:
331
+ if type(value) is not str:
332
+ raise _CodecFailure
333
+ encoded = value.encode("utf-8", errors="strict")
334
+ if len(encoded) > limits.max_string_bytes:
335
+ raise _CodecFailure
336
+ return value
337
+
338
+
339
+ def _bounded_integer(value: object, limits: LineageCodecLimits) -> int:
340
+ if type(value) is not int:
341
+ raise _CodecFailure
342
+ if len(str(abs(value))) > limits.max_integer_digits:
343
+ raise _CodecFailure
344
+ return value
345
+
346
+
347
+ def _bounded_items(value: object, limits: LineageCodecLimits) -> tuple[object, ...]:
348
+ if type(value) is not tuple or len(value) > limits.max_container_items:
349
+ raise _CodecFailure
350
+ return value
351
+
352
+
353
+ def _validate_enum_member(
354
+ value: object,
355
+ enum_type: type[Enum],
356
+ members: tuple[Enum, ...],
357
+ ) -> Enum:
358
+ if type(value) is not enum_type or not any(value is member for member in members):
359
+ raise _CodecFailure
360
+ return value
361
+
362
+
363
+ def _kind_for_exact_type(value_type: type) -> str:
364
+ for registered_type, kind in _EXACT_TYPE_KIND_REGISTRY:
365
+ if value_type is registered_type:
366
+ return kind
367
+ raise _CodecFailure
368
+
369
+
370
+ def _prevalidate_insight_ref(value: object, limits: LineageCodecLimits) -> InsightRef:
371
+ """Close InsightRef's upstream ``isinstance`` ordering before it can run."""
372
+
373
+ if type(value) is not InsightRef:
374
+ raise _CodecFailure
375
+ if type(value.insight_id) is not InsightId or type(value.version) is not int:
376
+ raise _CodecFailure
377
+ InsightId.__post_init__(value.insight_id)
378
+ if value.version <= 0:
379
+ raise _CodecFailure
380
+ _bounded_integer(value.version, limits)
381
+ InsightRef.__post_init__(value)
382
+ return value
383
+
384
+
385
+ def _prevalidate_selected_insights(
386
+ value: VariationCase,
387
+ limits: LineageCodecLimits,
388
+ ) -> None:
389
+ references = _bounded_items(value.selected_insights, limits)
390
+ if len(references) > MAX_SELECTED_INSIGHTS:
391
+ raise _CodecFailure
392
+ for reference in references:
393
+ _prevalidate_insight_ref(reference, limits)
394
+
395
+
396
+ @dataclass(slots=True)
397
+ class _EncodeState:
398
+ limits: LineageCodecLimits
399
+ logical_nodes: int = 0
400
+
401
+ def enter(self, depth: int) -> None:
402
+ if depth > self.limits.max_depth:
403
+ raise _CodecFailure
404
+ self.logical_nodes += 1
405
+ if self.logical_nodes > self.limits.max_nodes:
406
+ raise _CodecFailure
407
+
408
+
409
+ def _record(kind: str, **fields: object) -> dict[str, object]:
410
+ return {"kind": kind, **fields}
411
+
412
+
413
+ def _encode_optional_node(
414
+ value: object | None,
415
+ state: _EncodeState,
416
+ depth: int,
417
+ ) -> object:
418
+ if value is None:
419
+ return None
420
+ return _encode_node(value, state, depth)
421
+
422
+
423
+ def _encode_nodes(
424
+ values: object,
425
+ state: _EncodeState,
426
+ depth: int,
427
+ ) -> list[object]:
428
+ items = _bounded_items(values, state.limits)
429
+ return [_encode_node(item, state, depth) for item in items]
430
+
431
+
432
+ def _encode_strings(values: object, limits: LineageCodecLimits) -> list[str]:
433
+ items = _bounded_items(values, limits)
434
+ return [_bounded_string(item, limits) for item in items]
435
+
436
+
437
+ def _encode_enum(
438
+ value: object,
439
+ enum_type: type[Enum],
440
+ members: tuple[Enum, ...],
441
+ kind: str,
442
+ limits: LineageCodecLimits,
443
+ ) -> dict[str, object]:
444
+ member = _validate_enum_member(value, enum_type, members)
445
+ return _record(kind, value=_bounded_string(member.value, limits))
446
+
447
+
448
+ def _encode_node(value: object, state: _EncodeState, depth: int) -> dict[str, object]:
449
+ state.enter(depth)
450
+ value_type = type(value)
451
+ kind = _kind_for_exact_type(value_type)
452
+ limits = state.limits
453
+
454
+ if value is None:
455
+ return _record("json_none")
456
+ if value_type is bool:
457
+ freeze_json(value)
458
+ return _record("json_bool", value=value)
459
+ if value_type is int:
460
+ freeze_json(value)
461
+ integer = _bounded_integer(value, limits)
462
+ return _record("json_int", value=str(integer))
463
+ if value_type is float:
464
+ freeze_json(value)
465
+ if not math.isfinite(value):
466
+ raise _CodecFailure
467
+ return _record("json_float", bits=struct.pack(">d", value).hex())
468
+ if value_type is str:
469
+ freeze_json(value)
470
+ return _record("json_string", value=_bounded_string(value, limits))
471
+
472
+ if value_type is CandidateId:
473
+ CandidateId.__post_init__(value)
474
+ return _record(kind, value=_bounded_string(value.value, limits))
475
+ if value_type is OperatorInvocationId:
476
+ OperatorInvocationId.__post_init__(value)
477
+ return _record(kind, value=_bounded_string(value.value, limits))
478
+ if value_type is InsightId:
479
+ InsightId.__post_init__(value)
480
+ return _record(kind, value=_bounded_string(value.value, limits))
481
+ if value_type is InsightRef:
482
+ _prevalidate_insight_ref(value, limits)
483
+ return _record(
484
+ kind,
485
+ insight_id=_encode_node(value.insight_id, state, depth + 1),
486
+ version=_bounded_integer(value.version, limits),
487
+ )
488
+
489
+ if value_type is VariationKind:
490
+ return _encode_enum(value, VariationKind, _VARIATION_KINDS, kind, limits)
491
+ if value_type is ParentRole:
492
+ return _encode_enum(value, ParentRole, _PARENT_ROLES, kind, limits)
493
+ if value_type is PreservationSource:
494
+ return _encode_enum(
495
+ value,
496
+ PreservationSource,
497
+ _PRESERVATION_SOURCES,
498
+ kind,
499
+ limits,
500
+ )
501
+ if value_type is PreservationExpectation:
502
+ return _encode_enum(
503
+ value,
504
+ PreservationExpectation,
505
+ _PRESERVATION_EXPECTATIONS,
506
+ kind,
507
+ limits,
508
+ )
509
+ if value_type is AbsenceContextKind:
510
+ return _encode_enum(
511
+ value,
512
+ AbsenceContextKind,
513
+ _ABSENCE_CONTEXT_KINDS,
514
+ kind,
515
+ limits,
516
+ )
517
+ if value_type is AbsenceFailureKind:
518
+ return _encode_enum(
519
+ value,
520
+ AbsenceFailureKind,
521
+ _ABSENCE_FAILURE_KINDS,
522
+ kind,
523
+ limits,
524
+ )
525
+ if value_type is ThreeWayRelationKind:
526
+ return _encode_enum(
527
+ value,
528
+ ThreeWayRelationKind,
529
+ _THREE_WAY_RELATION_KINDS,
530
+ kind,
531
+ limits,
532
+ )
533
+ if value_type is ResolutionChoice:
534
+ return _encode_enum(
535
+ value,
536
+ ResolutionChoice,
537
+ _RESOLUTION_CHOICES,
538
+ kind,
539
+ limits,
540
+ )
541
+
542
+ if value_type is TypedJsonLimits:
543
+ validate_typed_json_limits(value)
544
+ return _record(
545
+ kind,
546
+ max_depth=_bounded_integer(value.max_depth, limits),
547
+ max_nodes=_bounded_integer(value.max_nodes, limits),
548
+ max_container_items=_bounded_integer(value.max_container_items, limits),
549
+ max_string_bytes=_bounded_integer(value.max_string_bytes, limits),
550
+ max_integer_bits=_bounded_integer(value.max_integer_bits, limits),
551
+ max_canonical_bytes=_bounded_integer(value.max_canonical_bytes, limits),
552
+ )
553
+ if value_type is FrozenJsonArray:
554
+ if freeze_json(value) is not value:
555
+ raise _CodecFailure
556
+ return _record(kind, items=_encode_nodes(value.items, state, depth + 1))
557
+ if value_type is FrozenJsonObject:
558
+ if freeze_json(value) is not value:
559
+ raise _CodecFailure
560
+ entries = _bounded_items(value.items, limits)
561
+ return _record(
562
+ kind,
563
+ items=[
564
+ {
565
+ "key": _bounded_string(entry[0], limits),
566
+ "value": _encode_node(entry[1], state, depth + 1),
567
+ }
568
+ for entry in entries
569
+ ],
570
+ )
571
+
572
+ if value_type is ObjectKey:
573
+ ObjectKey.__post_init__(value)
574
+ return _record(kind, value=_bounded_string(value.value, limits))
575
+ if value_type is ArrayIndex:
576
+ ArrayIndex.__post_init__(value)
577
+ return _record(kind, value=_bounded_integer(value.value, limits))
578
+ if value_type is JsonPath:
579
+ validate_json_path(value)
580
+ return _record(kind, segments=_encode_nodes(value.segments, state, depth + 1))
581
+ if value_type is PatchLimits:
582
+ validate_patch_limits(value)
583
+ return _record(
584
+ kind,
585
+ json_limits=_encode_node(value.json_limits, state, depth + 1),
586
+ max_operations=_bounded_integer(value.max_operations, limits),
587
+ max_path_segments=_bounded_integer(value.max_path_segments, limits),
588
+ max_patch_bytes=_bounded_integer(value.max_patch_bytes, limits),
589
+ )
590
+
591
+ if value_type is ReplaceScalar:
592
+ validate_patch_operation(value)
593
+ return _record(
594
+ kind,
595
+ path=_encode_node(value.path, state, depth + 1),
596
+ old_value=_encode_node(value.old_value, state, depth + 1),
597
+ new_value=_encode_node(value.new_value, state, depth + 1),
598
+ source_candidate_id=_encode_node(
599
+ value.source_candidate_id, state, depth + 1
600
+ ),
601
+ semantic_component=(
602
+ None
603
+ if value.semantic_component is None
604
+ else _bounded_string(value.semantic_component, limits)
605
+ ),
606
+ )
607
+ if value_type is ReplaceSubtree:
608
+ validate_patch_operation(value)
609
+ return _record(
610
+ kind,
611
+ path=_encode_node(value.path, state, depth + 1),
612
+ old_value=_encode_node(value.old_value, state, depth + 1),
613
+ new_value=_encode_node(value.new_value, state, depth + 1),
614
+ source_candidate_id=_encode_node(
615
+ value.source_candidate_id, state, depth + 1
616
+ ),
617
+ semantic_component=(
618
+ None
619
+ if value.semantic_component is None
620
+ else _bounded_string(value.semantic_component, limits)
621
+ ),
622
+ )
623
+ if value_type is InsertSequenceItem:
624
+ validate_patch_operation(value)
625
+ return _record(
626
+ kind,
627
+ path=_encode_node(value.path, state, depth + 1),
628
+ index=_bounded_integer(value.index, limits),
629
+ item=_encode_node(value.item, state, depth + 1),
630
+ before_sequence=_encode_node(value.before_sequence, state, depth + 1),
631
+ after_sequence=_encode_node(value.after_sequence, state, depth + 1),
632
+ source_candidate_id=_encode_node(
633
+ value.source_candidate_id, state, depth + 1
634
+ ),
635
+ semantic_component=(
636
+ None
637
+ if value.semantic_component is None
638
+ else _bounded_string(value.semantic_component, limits)
639
+ ),
640
+ )
641
+ if value_type is DeleteSequenceItem:
642
+ validate_patch_operation(value)
643
+ return _record(
644
+ kind,
645
+ path=_encode_node(value.path, state, depth + 1),
646
+ index=_bounded_integer(value.index, limits),
647
+ item=_encode_node(value.item, state, depth + 1),
648
+ before_sequence=_encode_node(value.before_sequence, state, depth + 1),
649
+ after_sequence=_encode_node(value.after_sequence, state, depth + 1),
650
+ source_candidate_id=_encode_node(
651
+ value.source_candidate_id, state, depth + 1
652
+ ),
653
+ semantic_component=(
654
+ None
655
+ if value.semantic_component is None
656
+ else _bounded_string(value.semantic_component, limits)
657
+ ),
658
+ )
659
+ if value_type is PermuteSequence:
660
+ validate_patch_operation(value)
661
+ permutation = _bounded_items(value.permutation, limits)
662
+ return _record(
663
+ kind,
664
+ path=_encode_node(value.path, state, depth + 1),
665
+ permutation=[_bounded_integer(item, limits) for item in permutation],
666
+ before_sequence=_encode_node(value.before_sequence, state, depth + 1),
667
+ after_sequence=_encode_node(value.after_sequence, state, depth + 1),
668
+ source_candidate_id=_encode_node(
669
+ value.source_candidate_id, state, depth + 1
670
+ ),
671
+ semantic_component=(
672
+ None
673
+ if value.semantic_component is None
674
+ else _bounded_string(value.semantic_component, limits)
675
+ ),
676
+ )
677
+ if value_type is TypedPatch:
678
+ validate_typed_patch(value)
679
+ return _record(
680
+ kind,
681
+ base_candidate_id=_encode_node(value.base_candidate_id, state, depth + 1),
682
+ target_candidate_id=_encode_node(
683
+ value.target_candidate_id, state, depth + 1
684
+ ),
685
+ base_hash=_bounded_string(value.base_hash, limits),
686
+ target_hash=_bounded_string(value.target_hash, limits),
687
+ operations=_encode_nodes(value.operations, state, depth + 1),
688
+ limits=_encode_node(value.limits, state, depth + 1),
689
+ schema_version=_bounded_string(value.schema_version, limits),
690
+ )
691
+
692
+ if value_type is CandidateOccurrence:
693
+ CandidateOccurrence.__post_init__(value)
694
+ return _record(
695
+ kind,
696
+ candidate_id=_encode_node(value.candidate_id, state, depth + 1),
697
+ configuration_hash=_bounded_string(value.configuration_hash, limits),
698
+ configuration_artifact_hash=_bounded_string(
699
+ value.configuration_artifact_hash, limits
700
+ ),
701
+ proposal_sequence=_bounded_integer(value.proposal_sequence, limits),
702
+ operator_invocation_id=_encode_optional_node(
703
+ value.operator_invocation_id, state, depth + 1
704
+ ),
705
+ )
706
+ if value_type is VariationParent:
707
+ VariationParent.__post_init__(value)
708
+ return _record(
709
+ kind,
710
+ role=_encode_node(value.role, state, depth + 1),
711
+ occurrence=_encode_node(value.occurrence, state, depth + 1),
712
+ )
713
+ if value_type is ParentEdge:
714
+ ParentEdge.__post_init__(value)
715
+ return _record(
716
+ kind,
717
+ role=_encode_node(value.role, state, depth + 1),
718
+ parent=_encode_node(value.parent, state, depth + 1),
719
+ child=_encode_node(value.child, state, depth + 1),
720
+ patch=_encode_node(value.patch, state, depth + 1),
721
+ )
722
+ if value_type is PreservationClaim:
723
+ PreservationClaim.__post_init__(value)
724
+ return _record(kind, obligation_id=_bounded_string(value.obligation_id, limits))
725
+ if value_type is PreservationObligation:
726
+ PreservationObligation.__post_init__(value)
727
+ return _record(
728
+ kind,
729
+ source=_encode_node(value.source, state, depth + 1),
730
+ source_parent_candidate_ids=_encode_nodes(
731
+ value.source_parent_candidate_ids, state, depth + 1
732
+ ),
733
+ branch_patch_hashes=_encode_strings(value.branch_patch_hashes, limits),
734
+ operation_effect_hashes=_encode_strings(
735
+ value.operation_effect_hashes, limits
736
+ ),
737
+ relation_id=_bounded_string(value.relation_id, limits),
738
+ path=_encode_node(value.path, state, depth + 1),
739
+ expected_state=_encode_node(value.expected_state, state, depth + 1),
740
+ expected_value_hash=(
741
+ None
742
+ if value.expected_value_hash is None
743
+ else _bounded_string(value.expected_value_hash, limits)
744
+ ),
745
+ ancestor_state=_encode_node(value.ancestor_state, state, depth + 1),
746
+ ancestor_value_hash=(
747
+ None
748
+ if value.ancestor_value_hash is None
749
+ else _bounded_string(value.ancestor_value_hash, limits)
750
+ ),
751
+ absence_context_path=_encode_optional_node(
752
+ value.absence_context_path, state, depth + 1
753
+ ),
754
+ absence_context_kind=_encode_optional_node(
755
+ value.absence_context_kind, state, depth + 1
756
+ ),
757
+ absence_context_shape_hash=(
758
+ None
759
+ if value.absence_context_shape_hash is None
760
+ else _bounded_string(value.absence_context_shape_hash, limits)
761
+ ),
762
+ absence_failure_kind=_encode_optional_node(
763
+ value.absence_failure_kind, state, depth + 1
764
+ ),
765
+ )
766
+ if value_type is VariationCase:
767
+ _prevalidate_selected_insights(value, limits)
768
+ validate_variation_case(value)
769
+ return _record(
770
+ kind,
771
+ operator_invocation_id=_encode_node(
772
+ value.operator_invocation_id, state, depth + 1
773
+ ),
774
+ variation_kind=_encode_node(value.variation_kind, state, depth + 1),
775
+ operator_id=_bounded_string(value.operator_id, limits),
776
+ operator_version=_bounded_integer(value.operator_version, limits),
777
+ parents=_encode_nodes(value.parents, state, depth + 1),
778
+ requested_child_count=_bounded_integer(
779
+ value.requested_child_count, limits
780
+ ),
781
+ context_stratum_hash=_bounded_string(value.context_stratum_hash, limits),
782
+ reward_definition_hash=_bounded_string(
783
+ value.reward_definition_hash, limits
784
+ ),
785
+ common_ancestor=_encode_optional_node(
786
+ value.common_ancestor, state, depth + 1
787
+ ),
788
+ ancestor_to_parent_patches=_encode_nodes(
789
+ value.ancestor_to_parent_patches, state, depth + 1
790
+ ),
791
+ selected_insights=_encode_nodes(
792
+ value.selected_insights, state, depth + 1
793
+ ),
794
+ preservation_obligations=_encode_nodes(
795
+ value.preservation_obligations, state, depth + 1
796
+ ),
797
+ )
798
+
799
+ if value_type is ComponentTagAssignment:
800
+ ComponentTagAssignment.__post_init__(value)
801
+ return _record(
802
+ kind,
803
+ path=_encode_node(value.path, state, depth + 1),
804
+ component=_bounded_string(value.component, limits),
805
+ )
806
+ if value_type is PatchRelation:
807
+ validate_patch_relation(value)
808
+ return _record(
809
+ kind,
810
+ relation_kind=_encode_node(value.kind, state, depth + 1),
811
+ left_operations=_encode_nodes(
812
+ value.left_operations, state, depth + 1
813
+ ),
814
+ right_operations=_encode_nodes(
815
+ value.right_operations, state, depth + 1
816
+ ),
817
+ semantic_component=(
818
+ None
819
+ if value.semantic_component is None
820
+ else _bounded_string(value.semantic_component, limits)
821
+ ),
822
+ )
823
+ if value_type is ThreeWayPatchClassification:
824
+ value.revalidate()
825
+ return _record(
826
+ kind,
827
+ ancestor=_encode_node(value.ancestor, state, depth + 1),
828
+ ancestor_candidate_id=_encode_node(
829
+ value.ancestor_candidate_id, state, depth + 1
830
+ ),
831
+ ancestor_hash=_bounded_string(value.ancestor_hash, limits),
832
+ left_patch_hash=_bounded_string(value.left_patch_hash, limits),
833
+ right_patch_hash=_bounded_string(value.right_patch_hash, limits),
834
+ relations=_encode_nodes(value.relations, state, depth + 1),
835
+ left_patch=_encode_node(value.left_patch, state, depth + 1),
836
+ right_patch=_encode_node(value.right_patch, state, depth + 1),
837
+ )
838
+ if value_type is PreservationObligationRequest:
839
+ PreservationObligationRequest.__post_init__(value)
840
+ return _record(
841
+ kind,
842
+ relation_id=_bounded_string(value.relation_id, limits),
843
+ source=_encode_node(value.source, state, depth + 1),
844
+ path=_encode_node(value.path, state, depth + 1),
845
+ )
846
+ if value_type is PatchResolution:
847
+ PatchResolution.__post_init__(value)
848
+ return _record(
849
+ kind,
850
+ relation_id=_bounded_string(value.relation_id, limits),
851
+ choice=_encode_node(value.choice, state, depth + 1),
852
+ synthesized_result_hash=(
853
+ None
854
+ if value.synthesized_result_hash is None
855
+ else _bounded_string(value.synthesized_result_hash, limits)
856
+ ),
857
+ )
858
+ if value_type is ParentConfiguration:
859
+ ParentConfiguration.__post_init__(value)
860
+ return _record(
861
+ kind,
862
+ occurrence=_encode_node(value.occurrence, state, depth + 1),
863
+ configuration=_encode_node(value.configuration, state, depth + 1),
864
+ )
865
+ if value_type is PreservationVerification:
866
+ validate_preservation_verification(value)
867
+ return _record(
868
+ kind,
869
+ child_hash=_bounded_string(value.child_hash, limits),
870
+ verified_claims=_encode_nodes(
871
+ value.verified_claims, state, depth + 1
872
+ ),
873
+ discriminatively_used_parent_ids=_encode_nodes(
874
+ value.discriminatively_used_parent_ids, state, depth + 1
875
+ ),
876
+ )
877
+
878
+ raise _CodecFailure
879
+
880
+
881
+ def _validate_wire_tree(value: object, limits: LineageCodecLimits) -> None:
882
+ stack: list[tuple[object, int]] = [(value, 0)]
883
+ nodes = 0
884
+ while stack:
885
+ current, depth = stack.pop()
886
+ if depth > limits.max_depth:
887
+ raise _CodecFailure
888
+ nodes += 1
889
+ if nodes > limits.max_nodes:
890
+ raise _CodecFailure
891
+ current_type = type(current)
892
+ if current is None or current_type is bool:
893
+ continue
894
+ if current_type is int:
895
+ _bounded_integer(current, limits)
896
+ continue
897
+ if current_type is str:
898
+ _bounded_string(current, limits)
899
+ continue
900
+ if current_type is list:
901
+ if len(current) > limits.max_container_items:
902
+ raise _CodecFailure
903
+ stack.extend((item, depth + 1) for item in reversed(current))
904
+ continue
905
+ if current_type is dict:
906
+ if len(current) > limits.max_container_items:
907
+ raise _CodecFailure
908
+ for key, item in current.items():
909
+ _bounded_string(key, limits)
910
+ stack.append((item, depth + 1))
911
+ continue
912
+ raise _CodecFailure
913
+
914
+
915
+ def _canonical_json_bytes(value: object, limits: LineageCodecLimits) -> bytes:
916
+ _validate_wire_tree(value, limits)
917
+ encoder = json.JSONEncoder(
918
+ ensure_ascii=False,
919
+ allow_nan=False,
920
+ sort_keys=True,
921
+ separators=(",", ":"),
922
+ )
923
+ chunks: list[bytes] = []
924
+ size = 0
925
+ for text in encoder.iterencode(value):
926
+ if type(text) is not str:
927
+ raise _CodecFailure
928
+ chunk = text.encode("utf-8", errors="strict")
929
+ size += len(chunk)
930
+ if size > limits.max_bytes:
931
+ raise _CodecFailure
932
+ chunks.append(chunk)
933
+ return b"".join(chunks)
934
+
935
+
936
+ def _scan_json_structure(content: bytes, limits: LineageCodecLimits) -> None:
937
+ depth = 0
938
+ in_string = False
939
+ escaped = False
940
+ expect_value = True
941
+ nodes = 0
942
+ containers: list[list[object]] = []
943
+ for byte in content:
944
+ if in_string:
945
+ if escaped:
946
+ escaped = False
947
+ elif byte == 0x5C:
948
+ escaped = True
949
+ elif byte == 0x22:
950
+ in_string = False
951
+ continue
952
+ if byte in (0x20, 0x09, 0x0A, 0x0D):
953
+ continue
954
+ if expect_value and byte not in (0x5D, 0x7D):
955
+ nodes += 1
956
+ if nodes > limits.max_nodes:
957
+ raise _CodecFailure
958
+ if containers and containers[-1][0] == "array":
959
+ containers[-1][1] += 1
960
+ if containers[-1][1] > limits.max_container_items:
961
+ raise _CodecFailure
962
+ expect_value = False
963
+ if byte == 0x22:
964
+ in_string = True
965
+ elif byte == 0x5B:
966
+ depth += 1
967
+ if depth > limits.max_depth:
968
+ raise _CodecFailure
969
+ containers.append(["array", 0])
970
+ expect_value = True
971
+ elif byte == 0x7B:
972
+ depth += 1
973
+ if depth > limits.max_depth:
974
+ raise _CodecFailure
975
+ containers.append(["object", 0])
976
+ elif byte == 0x5D:
977
+ if not containers or containers[-1][0] != "array":
978
+ raise _CodecFailure
979
+ containers.pop()
980
+ depth -= 1
981
+ if depth < 0:
982
+ raise _CodecFailure
983
+ expect_value = False
984
+ elif byte == 0x7D:
985
+ if not containers or containers[-1][0] != "object":
986
+ raise _CodecFailure
987
+ containers.pop()
988
+ depth -= 1
989
+ if depth < 0:
990
+ raise _CodecFailure
991
+ expect_value = False
992
+ elif byte == 0x3A:
993
+ if not containers or containers[-1][0] != "object":
994
+ raise _CodecFailure
995
+ containers[-1][1] += 1
996
+ if containers[-1][1] > limits.max_container_items:
997
+ raise _CodecFailure
998
+ expect_value = True
999
+ elif byte == 0x2C and containers and containers[-1][0] == "array":
1000
+ expect_value = True
1001
+ if in_string or escaped or depth != 0 or containers or nodes == 0:
1002
+ raise _CodecFailure
1003
+
1004
+
1005
+ def _decode_json_bytes(content: object, limits: LineageCodecLimits) -> object:
1006
+ if type(content) is not bytes or not content or len(content) > limits.max_bytes:
1007
+ raise _CodecFailure
1008
+ if content.startswith(b"\xef\xbb\xbf"):
1009
+ raise _CodecFailure
1010
+ _scan_json_structure(content, limits)
1011
+ text = content.decode("utf-8", errors="strict")
1012
+
1013
+ def reject_duplicate_keys(pairs: list[tuple[str, object]]) -> dict[str, object]:
1014
+ result: dict[str, object] = {}
1015
+ for key, value in pairs:
1016
+ if key in result:
1017
+ raise _CodecFailure
1018
+ result[key] = value
1019
+ return result
1020
+
1021
+ def parse_integer(token: str) -> int:
1022
+ if type(token) is not str or len(token.lstrip("-")) > limits.max_integer_digits:
1023
+ raise _CodecFailure
1024
+ return int(token)
1025
+
1026
+ def reject_number(_: str) -> object:
1027
+ raise _CodecFailure
1028
+
1029
+ parsed = json.loads(
1030
+ text,
1031
+ object_pairs_hook=reject_duplicate_keys,
1032
+ parse_int=parse_integer,
1033
+ parse_float=reject_number,
1034
+ parse_constant=reject_number,
1035
+ )
1036
+ _validate_wire_tree(parsed, limits)
1037
+ if _canonical_json_bytes(parsed, limits) != content:
1038
+ raise _CodecFailure
1039
+ return parsed
1040
+
1041
+
1042
+ def _expect_record(
1043
+ value: object,
1044
+ kind: str,
1045
+ fields: tuple[str, ...],
1046
+ ) -> dict[str, object]:
1047
+ if type(value) is not dict:
1048
+ raise _CodecFailure
1049
+ expected = {"kind", *fields}
1050
+ if set(value) != expected or value.get("kind") != kind:
1051
+ raise _CodecFailure
1052
+ return value
1053
+
1054
+
1055
+ def _decode_string(value: object, limits: LineageCodecLimits) -> str:
1056
+ return _bounded_string(value, limits)
1057
+
1058
+
1059
+ def _decode_optional_string(value: object, limits: LineageCodecLimits) -> str | None:
1060
+ if value is None:
1061
+ return None
1062
+ return _bounded_string(value, limits)
1063
+
1064
+
1065
+ def _decode_integer(value: object, limits: LineageCodecLimits) -> int:
1066
+ return _bounded_integer(value, limits)
1067
+
1068
+
1069
+ def _decode_list(value: object, limits: LineageCodecLimits) -> list[object]:
1070
+ if type(value) is not list or len(value) > limits.max_container_items:
1071
+ raise _CodecFailure
1072
+ return value
1073
+
1074
+
1075
+ def _decode_as(
1076
+ value: object,
1077
+ expected_type: type,
1078
+ limits: LineageCodecLimits,
1079
+ depth: int,
1080
+ ) -> object:
1081
+ decoded = _decode_node(value, limits, depth)
1082
+ if type(decoded) is not expected_type:
1083
+ raise _CodecFailure
1084
+ return decoded
1085
+
1086
+
1087
+ def _decode_optional_as(
1088
+ value: object,
1089
+ expected_type: type,
1090
+ limits: LineageCodecLimits,
1091
+ depth: int,
1092
+ ) -> object | None:
1093
+ if value is None:
1094
+ return None
1095
+ return _decode_as(value, expected_type, limits, depth)
1096
+
1097
+
1098
+ def _decode_typed_json(
1099
+ value: object,
1100
+ limits: LineageCodecLimits,
1101
+ depth: int,
1102
+ ) -> object:
1103
+ decoded = _decode_node(value, limits, depth)
1104
+ if type(decoded) not in _TYPED_JSON_TYPES or not is_frozen_json_value(decoded):
1105
+ raise _CodecFailure
1106
+ freeze_json(decoded)
1107
+ return decoded
1108
+
1109
+
1110
+ def _decode_operation(
1111
+ value: object,
1112
+ limits: LineageCodecLimits,
1113
+ depth: int,
1114
+ ) -> object:
1115
+ decoded = _decode_node(value, limits, depth)
1116
+ if type(decoded) not in _PATCH_OPERATION_TYPES:
1117
+ raise _CodecFailure
1118
+ validate_patch_operation(decoded)
1119
+ return decoded
1120
+
1121
+
1122
+ def _decode_nodes(
1123
+ value: object,
1124
+ limits: LineageCodecLimits,
1125
+ depth: int,
1126
+ ) -> tuple[object, ...]:
1127
+ return tuple(_decode_node(item, limits, depth) for item in _decode_list(value, limits))
1128
+
1129
+
1130
+ def _decode_enum(
1131
+ value: object,
1132
+ kind: str,
1133
+ mapping: dict[str, Enum],
1134
+ limits: LineageCodecLimits,
1135
+ ) -> Enum:
1136
+ record = _expect_record(value, kind, ("value",))
1137
+ token = _decode_string(record["value"], limits)
1138
+ member = mapping.get(token)
1139
+ if member is None:
1140
+ raise _CodecFailure
1141
+ return member
1142
+
1143
+
1144
+ def _decode_node(
1145
+ value: object,
1146
+ limits: LineageCodecLimits,
1147
+ depth: int,
1148
+ ) -> object:
1149
+ if depth > limits.max_depth or type(value) is not dict:
1150
+ raise _CodecFailure
1151
+ kind = value.get("kind")
1152
+ if type(kind) is not str or kind not in LINEAGE_WIRE_KINDS:
1153
+ raise _CodecFailure
1154
+
1155
+ if kind == "json_none":
1156
+ _expect_record(value, kind, ())
1157
+ return None
1158
+ if kind == "json_bool":
1159
+ record = _expect_record(value, kind, ("value",))
1160
+ if type(record["value"]) is not bool:
1161
+ raise _CodecFailure
1162
+ return freeze_json(record["value"])
1163
+ if kind == "json_int":
1164
+ record = _expect_record(value, kind, ("value",))
1165
+ token = _decode_string(record["value"], limits)
1166
+ if token == "0":
1167
+ integer = 0
1168
+ else:
1169
+ negative = token.startswith("-")
1170
+ digits = token[1:] if negative else token
1171
+ if not digits or digits[0] == "0" or not digits.isascii() or not digits.isdigit():
1172
+ raise _CodecFailure
1173
+ if len(digits) > limits.max_integer_digits:
1174
+ raise _CodecFailure
1175
+ integer = int(token)
1176
+ return freeze_json(integer)
1177
+ if kind == "json_float":
1178
+ record = _expect_record(value, kind, ("bits",))
1179
+ bits = _decode_string(record["bits"], limits)
1180
+ if len(bits) != 16 or any(character not in "0123456789abcdef" for character in bits):
1181
+ raise _CodecFailure
1182
+ number = struct.unpack(">d", bytes.fromhex(bits))[0]
1183
+ if not math.isfinite(number):
1184
+ raise _CodecFailure
1185
+ return freeze_json(number)
1186
+ if kind == "json_string":
1187
+ record = _expect_record(value, kind, ("value",))
1188
+ return freeze_json(_decode_string(record["value"], limits))
1189
+
1190
+ if kind == "candidate_id":
1191
+ record = _expect_record(value, kind, ("value",))
1192
+ return CandidateId(_decode_string(record["value"], limits))
1193
+ if kind == "operator_invocation_id":
1194
+ record = _expect_record(value, kind, ("value",))
1195
+ return OperatorInvocationId(_decode_string(record["value"], limits))
1196
+ if kind == "insight_id":
1197
+ record = _expect_record(value, kind, ("value",))
1198
+ return InsightId(_decode_string(record["value"], limits))
1199
+ if kind == "insight_ref":
1200
+ record = _expect_record(value, kind, ("insight_id", "version"))
1201
+ return InsightRef(
1202
+ _decode_as(record["insight_id"], InsightId, limits, depth + 1),
1203
+ _decode_integer(record["version"], limits),
1204
+ )
1205
+
1206
+ if kind == "variation_kind":
1207
+ return _decode_enum(value, kind, _VARIATION_KIND_FROM_WIRE, limits)
1208
+ if kind == "parent_role":
1209
+ return _decode_enum(value, kind, _PARENT_ROLE_FROM_WIRE, limits)
1210
+ if kind == "preservation_source":
1211
+ return _decode_enum(value, kind, _PRESERVATION_SOURCE_FROM_WIRE, limits)
1212
+ if kind == "preservation_expectation":
1213
+ return _decode_enum(
1214
+ value,
1215
+ kind,
1216
+ _PRESERVATION_EXPECTATION_FROM_WIRE,
1217
+ limits,
1218
+ )
1219
+ if kind == "absence_context_kind":
1220
+ return _decode_enum(value, kind, _ABSENCE_CONTEXT_KIND_FROM_WIRE, limits)
1221
+ if kind == "absence_failure_kind":
1222
+ return _decode_enum(value, kind, _ABSENCE_FAILURE_KIND_FROM_WIRE, limits)
1223
+ if kind == "three_way_relation_kind":
1224
+ return _decode_enum(
1225
+ value,
1226
+ kind,
1227
+ _THREE_WAY_RELATION_KIND_FROM_WIRE,
1228
+ limits,
1229
+ )
1230
+ if kind == "resolution_choice":
1231
+ return _decode_enum(value, kind, _RESOLUTION_CHOICE_FROM_WIRE, limits)
1232
+
1233
+ if kind == "typed_json_limits":
1234
+ record = _expect_record(
1235
+ value,
1236
+ kind,
1237
+ (
1238
+ "max_depth",
1239
+ "max_nodes",
1240
+ "max_container_items",
1241
+ "max_string_bytes",
1242
+ "max_integer_bits",
1243
+ "max_canonical_bytes",
1244
+ ),
1245
+ )
1246
+ return TypedJsonLimits(
1247
+ max_depth=_decode_integer(record["max_depth"], limits),
1248
+ max_nodes=_decode_integer(record["max_nodes"], limits),
1249
+ max_container_items=_decode_integer(
1250
+ record["max_container_items"], limits
1251
+ ),
1252
+ max_string_bytes=_decode_integer(record["max_string_bytes"], limits),
1253
+ max_integer_bits=_decode_integer(record["max_integer_bits"], limits),
1254
+ max_canonical_bytes=_decode_integer(
1255
+ record["max_canonical_bytes"], limits
1256
+ ),
1257
+ )
1258
+ if kind == "frozen_json_array":
1259
+ record = _expect_record(value, kind, ("items",))
1260
+ items = tuple(
1261
+ _decode_typed_json(item, limits, depth + 1)
1262
+ for item in _decode_list(record["items"], limits)
1263
+ )
1264
+ return FrozenJsonArray(items)
1265
+ if kind == "frozen_json_object":
1266
+ record = _expect_record(value, kind, ("items",))
1267
+ entries: list[tuple[str, object]] = []
1268
+ for raw_entry in _decode_list(record["items"], limits):
1269
+ if type(raw_entry) is not dict or set(raw_entry) != {"key", "value"}:
1270
+ raise _CodecFailure
1271
+ entries.append(
1272
+ (
1273
+ _decode_string(raw_entry["key"], limits),
1274
+ _decode_typed_json(raw_entry["value"], limits, depth + 1),
1275
+ )
1276
+ )
1277
+ return FrozenJsonObject(tuple(entries))
1278
+
1279
+ if kind == "object_key":
1280
+ record = _expect_record(value, kind, ("value",))
1281
+ return ObjectKey(_decode_string(record["value"], limits))
1282
+ if kind == "array_index":
1283
+ record = _expect_record(value, kind, ("value",))
1284
+ return ArrayIndex(_decode_integer(record["value"], limits))
1285
+ if kind == "json_path":
1286
+ record = _expect_record(value, kind, ("segments",))
1287
+ segments = tuple(
1288
+ _decode_node(item, limits, depth + 1)
1289
+ for item in _decode_list(record["segments"], limits)
1290
+ )
1291
+ if any(type(item) not in (ObjectKey, ArrayIndex) for item in segments):
1292
+ raise _CodecFailure
1293
+ return JsonPath(segments)
1294
+ if kind == "patch_limits":
1295
+ record = _expect_record(
1296
+ value,
1297
+ kind,
1298
+ (
1299
+ "json_limits",
1300
+ "max_operations",
1301
+ "max_path_segments",
1302
+ "max_patch_bytes",
1303
+ ),
1304
+ )
1305
+ return PatchLimits(
1306
+ json_limits=_decode_as(
1307
+ record["json_limits"], TypedJsonLimits, limits, depth + 1
1308
+ ),
1309
+ max_operations=_decode_integer(record["max_operations"], limits),
1310
+ max_path_segments=_decode_integer(
1311
+ record["max_path_segments"], limits
1312
+ ),
1313
+ max_patch_bytes=_decode_integer(record["max_patch_bytes"], limits),
1314
+ )
1315
+
1316
+ if kind in ("replace_scalar", "replace_subtree"):
1317
+ record = _expect_record(
1318
+ value,
1319
+ kind,
1320
+ (
1321
+ "path",
1322
+ "old_value",
1323
+ "new_value",
1324
+ "source_candidate_id",
1325
+ "semantic_component",
1326
+ ),
1327
+ )
1328
+ arguments = (
1329
+ _decode_as(record["path"], JsonPath, limits, depth + 1),
1330
+ _decode_typed_json(record["old_value"], limits, depth + 1),
1331
+ _decode_typed_json(record["new_value"], limits, depth + 1),
1332
+ _decode_as(
1333
+ record["source_candidate_id"], CandidateId, limits, depth + 1
1334
+ ),
1335
+ _decode_optional_string(record["semantic_component"], limits),
1336
+ )
1337
+ return (
1338
+ ReplaceScalar(*arguments)
1339
+ if kind == "replace_scalar"
1340
+ else ReplaceSubtree(*arguments)
1341
+ )
1342
+ if kind in ("insert_sequence_item", "delete_sequence_item"):
1343
+ record = _expect_record(
1344
+ value,
1345
+ kind,
1346
+ (
1347
+ "path",
1348
+ "index",
1349
+ "item",
1350
+ "before_sequence",
1351
+ "after_sequence",
1352
+ "source_candidate_id",
1353
+ "semantic_component",
1354
+ ),
1355
+ )
1356
+ arguments = (
1357
+ _decode_as(record["path"], JsonPath, limits, depth + 1),
1358
+ _decode_integer(record["index"], limits),
1359
+ _decode_typed_json(record["item"], limits, depth + 1),
1360
+ _decode_as(
1361
+ record["before_sequence"], FrozenJsonArray, limits, depth + 1
1362
+ ),
1363
+ _decode_as(
1364
+ record["after_sequence"], FrozenJsonArray, limits, depth + 1
1365
+ ),
1366
+ _decode_as(
1367
+ record["source_candidate_id"], CandidateId, limits, depth + 1
1368
+ ),
1369
+ _decode_optional_string(record["semantic_component"], limits),
1370
+ )
1371
+ return (
1372
+ InsertSequenceItem(*arguments)
1373
+ if kind == "insert_sequence_item"
1374
+ else DeleteSequenceItem(*arguments)
1375
+ )
1376
+ if kind == "permute_sequence":
1377
+ record = _expect_record(
1378
+ value,
1379
+ kind,
1380
+ (
1381
+ "path",
1382
+ "permutation",
1383
+ "before_sequence",
1384
+ "after_sequence",
1385
+ "source_candidate_id",
1386
+ "semantic_component",
1387
+ ),
1388
+ )
1389
+ permutation = tuple(
1390
+ _decode_integer(item, limits)
1391
+ for item in _decode_list(record["permutation"], limits)
1392
+ )
1393
+ return PermuteSequence(
1394
+ _decode_as(record["path"], JsonPath, limits, depth + 1),
1395
+ permutation,
1396
+ _decode_as(
1397
+ record["before_sequence"], FrozenJsonArray, limits, depth + 1
1398
+ ),
1399
+ _decode_as(
1400
+ record["after_sequence"], FrozenJsonArray, limits, depth + 1
1401
+ ),
1402
+ _decode_as(
1403
+ record["source_candidate_id"], CandidateId, limits, depth + 1
1404
+ ),
1405
+ _decode_optional_string(record["semantic_component"], limits),
1406
+ )
1407
+ if kind == "typed_patch":
1408
+ record = _expect_record(
1409
+ value,
1410
+ kind,
1411
+ (
1412
+ "base_candidate_id",
1413
+ "target_candidate_id",
1414
+ "base_hash",
1415
+ "target_hash",
1416
+ "operations",
1417
+ "limits",
1418
+ "schema_version",
1419
+ ),
1420
+ )
1421
+ operations = tuple(
1422
+ _decode_operation(item, limits, depth + 1)
1423
+ for item in _decode_list(record["operations"], limits)
1424
+ )
1425
+ return TypedPatch(
1426
+ base_candidate_id=_decode_as(
1427
+ record["base_candidate_id"], CandidateId, limits, depth + 1
1428
+ ),
1429
+ target_candidate_id=_decode_as(
1430
+ record["target_candidate_id"], CandidateId, limits, depth + 1
1431
+ ),
1432
+ base_hash=_decode_string(record["base_hash"], limits),
1433
+ target_hash=_decode_string(record["target_hash"], limits),
1434
+ operations=operations,
1435
+ limits=_decode_as(record["limits"], PatchLimits, limits, depth + 1),
1436
+ schema_version=_decode_string(record["schema_version"], limits),
1437
+ )
1438
+
1439
+ if kind == "candidate_occurrence":
1440
+ record = _expect_record(
1441
+ value,
1442
+ kind,
1443
+ (
1444
+ "candidate_id",
1445
+ "configuration_hash",
1446
+ "configuration_artifact_hash",
1447
+ "proposal_sequence",
1448
+ "operator_invocation_id",
1449
+ ),
1450
+ )
1451
+ return CandidateOccurrence(
1452
+ candidate_id=_decode_as(
1453
+ record["candidate_id"], CandidateId, limits, depth + 1
1454
+ ),
1455
+ configuration_hash=_decode_string(record["configuration_hash"], limits),
1456
+ configuration_artifact_hash=_decode_string(
1457
+ record["configuration_artifact_hash"], limits
1458
+ ),
1459
+ proposal_sequence=_decode_integer(record["proposal_sequence"], limits),
1460
+ operator_invocation_id=_decode_optional_as(
1461
+ record["operator_invocation_id"],
1462
+ OperatorInvocationId,
1463
+ limits,
1464
+ depth + 1,
1465
+ ),
1466
+ )
1467
+ if kind == "variation_parent":
1468
+ record = _expect_record(value, kind, ("role", "occurrence"))
1469
+ return VariationParent(
1470
+ _decode_as(record["role"], ParentRole, limits, depth + 1),
1471
+ _decode_as(
1472
+ record["occurrence"], CandidateOccurrence, limits, depth + 1
1473
+ ),
1474
+ )
1475
+ if kind == "parent_edge":
1476
+ record = _expect_record(value, kind, ("role", "parent", "child", "patch"))
1477
+ return ParentEdge(
1478
+ _decode_as(record["role"], ParentRole, limits, depth + 1),
1479
+ _decode_as(record["parent"], CandidateOccurrence, limits, depth + 1),
1480
+ _decode_as(record["child"], CandidateOccurrence, limits, depth + 1),
1481
+ _decode_as(record["patch"], TypedPatch, limits, depth + 1),
1482
+ )
1483
+ if kind == "preservation_claim":
1484
+ record = _expect_record(value, kind, ("obligation_id",))
1485
+ return PreservationClaim(_decode_string(record["obligation_id"], limits))
1486
+ if kind == "preservation_obligation":
1487
+ record = _expect_record(
1488
+ value,
1489
+ kind,
1490
+ (
1491
+ "source",
1492
+ "source_parent_candidate_ids",
1493
+ "branch_patch_hashes",
1494
+ "operation_effect_hashes",
1495
+ "relation_id",
1496
+ "path",
1497
+ "expected_state",
1498
+ "expected_value_hash",
1499
+ "ancestor_state",
1500
+ "ancestor_value_hash",
1501
+ "absence_context_path",
1502
+ "absence_context_kind",
1503
+ "absence_context_shape_hash",
1504
+ "absence_failure_kind",
1505
+ ),
1506
+ )
1507
+ source_ids = tuple(
1508
+ _decode_as(item, CandidateId, limits, depth + 1)
1509
+ for item in _decode_list(record["source_parent_candidate_ids"], limits)
1510
+ )
1511
+ branch_hashes = tuple(
1512
+ _decode_string(item, limits)
1513
+ for item in _decode_list(record["branch_patch_hashes"], limits)
1514
+ )
1515
+ effect_hashes = tuple(
1516
+ _decode_string(item, limits)
1517
+ for item in _decode_list(record["operation_effect_hashes"], limits)
1518
+ )
1519
+ return PreservationObligation(
1520
+ source=_decode_as(
1521
+ record["source"], PreservationSource, limits, depth + 1
1522
+ ),
1523
+ source_parent_candidate_ids=source_ids,
1524
+ branch_patch_hashes=branch_hashes,
1525
+ operation_effect_hashes=effect_hashes,
1526
+ relation_id=_decode_string(record["relation_id"], limits),
1527
+ path=_decode_as(record["path"], JsonPath, limits, depth + 1),
1528
+ expected_state=_decode_as(
1529
+ record["expected_state"],
1530
+ PreservationExpectation,
1531
+ limits,
1532
+ depth + 1,
1533
+ ),
1534
+ expected_value_hash=_decode_optional_string(
1535
+ record["expected_value_hash"], limits
1536
+ ),
1537
+ ancestor_state=_decode_as(
1538
+ record["ancestor_state"],
1539
+ PreservationExpectation,
1540
+ limits,
1541
+ depth + 1,
1542
+ ),
1543
+ ancestor_value_hash=_decode_optional_string(
1544
+ record["ancestor_value_hash"], limits
1545
+ ),
1546
+ absence_context_path=_decode_optional_as(
1547
+ record["absence_context_path"], JsonPath, limits, depth + 1
1548
+ ),
1549
+ absence_context_kind=_decode_optional_as(
1550
+ record["absence_context_kind"],
1551
+ AbsenceContextKind,
1552
+ limits,
1553
+ depth + 1,
1554
+ ),
1555
+ absence_context_shape_hash=_decode_optional_string(
1556
+ record["absence_context_shape_hash"], limits
1557
+ ),
1558
+ absence_failure_kind=_decode_optional_as(
1559
+ record["absence_failure_kind"],
1560
+ AbsenceFailureKind,
1561
+ limits,
1562
+ depth + 1,
1563
+ ),
1564
+ )
1565
+ if kind == "variation_case":
1566
+ record = _expect_record(
1567
+ value,
1568
+ kind,
1569
+ (
1570
+ "operator_invocation_id",
1571
+ "variation_kind",
1572
+ "operator_id",
1573
+ "operator_version",
1574
+ "parents",
1575
+ "requested_child_count",
1576
+ "context_stratum_hash",
1577
+ "reward_definition_hash",
1578
+ "common_ancestor",
1579
+ "ancestor_to_parent_patches",
1580
+ "selected_insights",
1581
+ "preservation_obligations",
1582
+ ),
1583
+ )
1584
+ parents = tuple(
1585
+ _decode_as(item, VariationParent, limits, depth + 1)
1586
+ for item in _decode_list(record["parents"], limits)
1587
+ )
1588
+ patches = tuple(
1589
+ _decode_as(item, TypedPatch, limits, depth + 1)
1590
+ for item in _decode_list(record["ancestor_to_parent_patches"], limits)
1591
+ )
1592
+ insights = tuple(
1593
+ _decode_as(item, InsightRef, limits, depth + 1)
1594
+ for item in _decode_list(record["selected_insights"], limits)
1595
+ )
1596
+ obligations = tuple(
1597
+ _decode_as(item, PreservationObligation, limits, depth + 1)
1598
+ for item in _decode_list(record["preservation_obligations"], limits)
1599
+ )
1600
+ result = VariationCase(
1601
+ operator_invocation_id=_decode_as(
1602
+ record["operator_invocation_id"],
1603
+ OperatorInvocationId,
1604
+ limits,
1605
+ depth + 1,
1606
+ ),
1607
+ variation_kind=_decode_as(
1608
+ record["variation_kind"], VariationKind, limits, depth + 1
1609
+ ),
1610
+ operator_id=_decode_string(record["operator_id"], limits),
1611
+ operator_version=_decode_integer(record["operator_version"], limits),
1612
+ parents=parents,
1613
+ requested_child_count=_decode_integer(
1614
+ record["requested_child_count"], limits
1615
+ ),
1616
+ context_stratum_hash=_decode_string(
1617
+ record["context_stratum_hash"], limits
1618
+ ),
1619
+ reward_definition_hash=_decode_string(
1620
+ record["reward_definition_hash"], limits
1621
+ ),
1622
+ common_ancestor=_decode_optional_as(
1623
+ record["common_ancestor"],
1624
+ CandidateOccurrence,
1625
+ limits,
1626
+ depth + 1,
1627
+ ),
1628
+ ancestor_to_parent_patches=patches,
1629
+ selected_insights=insights,
1630
+ preservation_obligations=obligations,
1631
+ )
1632
+ validate_variation_case(result)
1633
+ return result
1634
+
1635
+ if kind == "component_tag_assignment":
1636
+ record = _expect_record(value, kind, ("path", "component"))
1637
+ return ComponentTagAssignment(
1638
+ _decode_as(record["path"], JsonPath, limits, depth + 1),
1639
+ _decode_string(record["component"], limits),
1640
+ )
1641
+ if kind == "patch_relation":
1642
+ record = _expect_record(
1643
+ value,
1644
+ kind,
1645
+ (
1646
+ "relation_kind",
1647
+ "left_operations",
1648
+ "right_operations",
1649
+ "semantic_component",
1650
+ ),
1651
+ )
1652
+ left = tuple(
1653
+ _decode_operation(item, limits, depth + 1)
1654
+ for item in _decode_list(record["left_operations"], limits)
1655
+ )
1656
+ right = tuple(
1657
+ _decode_operation(item, limits, depth + 1)
1658
+ for item in _decode_list(record["right_operations"], limits)
1659
+ )
1660
+ return PatchRelation(
1661
+ _decode_as(
1662
+ record["relation_kind"], ThreeWayRelationKind, limits, depth + 1
1663
+ ),
1664
+ left,
1665
+ right,
1666
+ _decode_optional_string(record["semantic_component"], limits),
1667
+ )
1668
+ if kind == "three_way_patch_classification":
1669
+ record = _expect_record(
1670
+ value,
1671
+ kind,
1672
+ (
1673
+ "ancestor",
1674
+ "ancestor_candidate_id",
1675
+ "ancestor_hash",
1676
+ "left_patch_hash",
1677
+ "right_patch_hash",
1678
+ "relations",
1679
+ "left_patch",
1680
+ "right_patch",
1681
+ ),
1682
+ )
1683
+ relations = tuple(
1684
+ _decode_as(item, PatchRelation, limits, depth + 1)
1685
+ for item in _decode_list(record["relations"], limits)
1686
+ )
1687
+ result = ThreeWayPatchClassification(
1688
+ ancestor=_decode_typed_json(record["ancestor"], limits, depth + 1),
1689
+ ancestor_candidate_id=_decode_as(
1690
+ record["ancestor_candidate_id"], CandidateId, limits, depth + 1
1691
+ ),
1692
+ ancestor_hash=_decode_string(record["ancestor_hash"], limits),
1693
+ left_patch_hash=_decode_string(record["left_patch_hash"], limits),
1694
+ right_patch_hash=_decode_string(record["right_patch_hash"], limits),
1695
+ relations=relations,
1696
+ left_patch=_decode_as(
1697
+ record["left_patch"], TypedPatch, limits, depth + 1
1698
+ ),
1699
+ right_patch=_decode_as(
1700
+ record["right_patch"], TypedPatch, limits, depth + 1
1701
+ ),
1702
+ )
1703
+ result.revalidate()
1704
+ return result
1705
+ if kind == "preservation_obligation_request":
1706
+ record = _expect_record(value, kind, ("relation_id", "source", "path"))
1707
+ return PreservationObligationRequest(
1708
+ _decode_string(record["relation_id"], limits),
1709
+ _decode_as(
1710
+ record["source"], PreservationSource, limits, depth + 1
1711
+ ),
1712
+ _decode_as(record["path"], JsonPath, limits, depth + 1),
1713
+ )
1714
+ if kind == "patch_resolution":
1715
+ record = _expect_record(
1716
+ value,
1717
+ kind,
1718
+ ("relation_id", "choice", "synthesized_result_hash"),
1719
+ )
1720
+ return PatchResolution(
1721
+ _decode_string(record["relation_id"], limits),
1722
+ _decode_as(record["choice"], ResolutionChoice, limits, depth + 1),
1723
+ _decode_optional_string(record["synthesized_result_hash"], limits),
1724
+ )
1725
+ if kind == "parent_configuration":
1726
+ record = _expect_record(value, kind, ("occurrence", "configuration"))
1727
+ return ParentConfiguration(
1728
+ _decode_as(
1729
+ record["occurrence"], CandidateOccurrence, limits, depth + 1
1730
+ ),
1731
+ _decode_typed_json(record["configuration"], limits, depth + 1),
1732
+ )
1733
+ if kind == "preservation_verification":
1734
+ record = _expect_record(
1735
+ value,
1736
+ kind,
1737
+ (
1738
+ "child_hash",
1739
+ "verified_claims",
1740
+ "discriminatively_used_parent_ids",
1741
+ ),
1742
+ )
1743
+ claims = tuple(
1744
+ _decode_as(item, PreservationClaim, limits, depth + 1)
1745
+ for item in _decode_list(record["verified_claims"], limits)
1746
+ )
1747
+ parent_ids = tuple(
1748
+ _decode_as(item, CandidateId, limits, depth + 1)
1749
+ for item in _decode_list(
1750
+ record["discriminatively_used_parent_ids"], limits
1751
+ )
1752
+ )
1753
+ result = PreservationVerification(
1754
+ _decode_string(record["child_hash"], limits),
1755
+ claims,
1756
+ parent_ids,
1757
+ )
1758
+ validate_preservation_verification(result)
1759
+ return result
1760
+
1761
+ raise _CodecFailure
1762
+
1763
+
1764
+ def _encode_internal(value: object, limits: LineageCodecLimits) -> bytes:
1765
+ _validate_codec_limits(limits)
1766
+ state = _EncodeState(limits)
1767
+ node = _encode_node(value, state, 1)
1768
+ envelope = {
1769
+ "format": LINEAGE_CODEC_FORMAT,
1770
+ "schema_version": LINEAGE_CODEC_SCHEMA_VERSION,
1771
+ "value": node,
1772
+ }
1773
+ return _canonical_json_bytes(envelope, limits)
1774
+
1775
+
1776
+ def _decode_internal(content: object, limits: LineageCodecLimits) -> object:
1777
+ _validate_codec_limits(limits)
1778
+ parsed = _decode_json_bytes(content, limits)
1779
+ if type(parsed) is not dict or set(parsed) != {
1780
+ "format",
1781
+ "schema_version",
1782
+ "value",
1783
+ }:
1784
+ raise _CodecFailure
1785
+ if parsed["format"] != LINEAGE_CODEC_FORMAT:
1786
+ raise _CodecFailure
1787
+ if (
1788
+ type(parsed["schema_version"]) is not int
1789
+ or parsed["schema_version"] != LINEAGE_CODEC_SCHEMA_VERSION
1790
+ ):
1791
+ raise _CodecFailure
1792
+ result = _decode_node(parsed["value"], limits, 1)
1793
+ if _encode_internal(result, limits) != content:
1794
+ raise _CodecFailure
1795
+ return result
1796
+
1797
+
1798
+ def encode_lineage_value(
1799
+ value: object,
1800
+ *,
1801
+ limits: LineageCodecLimits = DEFAULT_LINEAGE_CODEC_LIMITS,
1802
+ ) -> bytes:
1803
+ """Encode one exact registered value to canonical version-1 JSON bytes."""
1804
+
1805
+ try:
1806
+ return _encode_internal(value, limits)
1807
+ except Exception:
1808
+ pass
1809
+ raise LineageCodecError("lineage encode rejected value")
1810
+
1811
+
1812
+ def decode_lineage_value(
1813
+ content: bytes,
1814
+ *,
1815
+ limits: LineageCodecLimits = DEFAULT_LINEAGE_CODEC_LIMITS,
1816
+ ) -> object:
1817
+ """Decode canonical version-1 JSON through validated public constructors."""
1818
+
1819
+ try:
1820
+ return _decode_internal(content, limits)
1821
+ except Exception:
1822
+ pass
1823
+ raise LineageCodecError("lineage decode rejected bytes")
1824
+
1825
+
1826
+ __all__ = [
1827
+ "DEFAULT_LINEAGE_CODEC_LIMITS",
1828
+ "LINEAGE_CODEC_FORMAT",
1829
+ "LINEAGE_CODEC_SCHEMA_VERSION",
1830
+ "LINEAGE_WIRE_KINDS",
1831
+ "M4B_EXPORTED_VALUE_TYPES",
1832
+ "LineageCodecError",
1833
+ "LineageCodecLimits",
1834
+ "decode_lineage_value",
1835
+ "encode_lineage_value",
1836
+ ]