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.
- agent_evolve/__init__.py +722 -0
- agent_evolve/agentic.py +2800 -0
- agent_evolve/api.py +767 -0
- agent_evolve/application/__init__.py +1580 -0
- agent_evolve/application/action_allocation.py +744 -0
- agent_evolve/application/action_allocation_frame.py +347 -0
- agent_evolve/application/action_allocation_frame_commit.py +185 -0
- agent_evolve/application/action_allocation_frame_commit_v3.py +184 -0
- agent_evolve/application/action_allocation_frame_v3.py +338 -0
- agent_evolve/application/action_archive_value.py +497 -0
- agent_evolve/application/action_evidence_consistency.py +455 -0
- agent_evolve/application/action_forecast_partitioning.py +1471 -0
- agent_evolve/application/action_metric_projection.py +211 -0
- agent_evolve/application/action_role_value.py +680 -0
- agent_evolve/application/action_score_authorities.py +363 -0
- agent_evolve/application/action_structural_signature.py +116 -0
- agent_evolve/application/action_target_realization.py +402 -0
- agent_evolve/application/agentic_evolution.py +7734 -0
- agent_evolve/application/agentic_portfolio_residual_expert.py +835 -0
- agent_evolve/application/anchor_residual_identification.py +463 -0
- agent_evolve/application/archive_conditioned_action_target.py +208 -0
- agent_evolve/application/artifact_journal.py +246 -0
- agent_evolve/application/artifact_replay.py +347 -0
- agent_evolve/application/budgeted_optimizer.py +1828 -0
- agent_evolve/application/calibrated_campaign.py +485 -0
- agent_evolve/application/calibrated_current_prefix_forecast_opportunity.py +322 -0
- agent_evolve/application/calibrated_positive_gain_opportunity.py +1581 -0
- agent_evolve/application/campaign_capacity_recourse.py +254 -0
- agent_evolve/application/campaign_contextual_outcomes.py +119 -0
- agent_evolve/application/campaign_diagnostic_blocks.py +930 -0
- agent_evolve/application/campaign_evidence_registry.py +262 -0
- agent_evolve/application/campaign_execution.py +2537 -0
- agent_evolve/application/campaign_generation_audit.py +942 -0
- agent_evolve/application/campaign_learning.py +1812 -0
- agent_evolve/application/campaign_learning_runtime.py +1977 -0
- agent_evolve/application/campaign_search_phase.py +227 -0
- agent_evolve/application/campaign_selector_context_extension.py +220 -0
- agent_evolve/application/campaign_variation_envelope.py +649 -0
- agent_evolve/application/campaign_variation_trace.py +451 -0
- agent_evolve/application/candidate_archive_consequence.py +128 -0
- agent_evolve/application/causal_opportunity_portfolio_gate.py +385 -0
- agent_evolve/application/composite_outcome_updater.py +145 -0
- agent_evolve/application/composition_portfolio_selection.py +363 -0
- agent_evolve/application/concurrent_stage.py +144 -0
- agent_evolve/application/contextual_action_allocation.py +181 -0
- agent_evolve/application/contextual_campaign_outcomes.py +267 -0
- agent_evolve/application/contextual_campaign_planning.py +1366 -0
- agent_evolve/application/contextual_delayed_credit.py +651 -0
- agent_evolve/application/contextual_search_controller.py +2374 -0
- agent_evolve/application/current_prefix_forecast_opportunity.py +714 -0
- agent_evolve/application/decision_metric_projection.py +112 -0
- agent_evolve/application/derived_action_semantics.py +129 -0
- agent_evolve/application/detailed_evaluation.py +449 -0
- agent_evolve/application/earned_lineage.py +1011 -0
- agent_evolve/application/effective_choice_audit.py +484 -0
- agent_evolve/application/empirical_consequence_calibration.py +908 -0
- agent_evolve/application/evaluation_accounting.py +325 -0
- agent_evolve/application/evaluation_cache.py +199 -0
- agent_evolve/application/evaluation_escrow.py +547 -0
- agent_evolve/application/evaluation_recourse.py +253 -0
- agent_evolve/application/event_recorder.py +151 -0
- agent_evolve/application/evolution_campaign.py +1840 -0
- agent_evolve/application/executable_hypothesis.py +323 -0
- agent_evolve/application/factorial_branch_pilot.py +772 -0
- agent_evolve/application/finite_acquisition_capacity_recourse.py +672 -0
- agent_evolve/application/finite_acquisition_residual_expert.py +373 -0
- agent_evolve/application/finite_acquisition_variation_envelope.py +802 -0
- agent_evolve/application/finite_action_hypothesis_semantics.py +446 -0
- agent_evolve/application/finite_action_selection.py +188 -0
- agent_evolve/application/finite_action_set.py +306 -0
- agent_evolve/application/finite_action_transition.py +537 -0
- agent_evolve/application/finite_variation_eligibility.py +296 -0
- agent_evolve/application/forecast_geometry_portfolio.py +799 -0
- agent_evolve/application/forecast_opportunity_shadow_calibration.py +316 -0
- agent_evolve/application/front_proximity_admission.py +311 -0
- agent_evolve/application/front_proximity_parent_basis.py +458 -0
- agent_evolve/application/frozen_hurdle_score.py +659 -0
- agent_evolve/application/g3_causal_screen.py +2257 -0
- agent_evolve/application/g3_causal_validation.py +1046 -0
- agent_evolve/application/g3_postseal_curation.py +818 -0
- agent_evolve/application/gated_agentic_generator.py +205 -0
- agent_evolve/application/generation_feedback.py +293 -0
- agent_evolve/application/generative_proposal_journal.py +185 -0
- agent_evolve/application/geometry_conditional_elasticity.py +453 -0
- agent_evolve/application/global_wave_action_allocation.py +1151 -0
- agent_evolve/application/head_mass_conditional_seat.py +268 -0
- agent_evolve/application/identifiable_reflection_evidence.py +1147 -0
- agent_evolve/application/identifiable_reflection_learning.py +395 -0
- agent_evolve/application/identifiable_reflection_request.py +364 -0
- agent_evolve/application/in_memory_residual_archive.py +341 -0
- agent_evolve/application/insight_memory.py +1804 -0
- agent_evolve/application/live_runtime_manifest.py +758 -0
- agent_evolve/application/llm_task_queue.py +769 -0
- agent_evolve/application/matched_finite_action_block.py +409 -0
- agent_evolve/application/materialized_action_broker.py +2328 -0
- agent_evolve/application/materialized_action_constraints.py +83 -0
- agent_evolve/application/materialized_variation.py +211 -0
- agent_evolve/application/multi_option_evolution.py +1536 -0
- agent_evolve/application/outcome_adaptive_action_racing.py +2827 -0
- agent_evolve/application/outcome_adaptive_residual_campaign_runtime.py +580 -0
- agent_evolve/application/outcome_adaptive_residual_portfolio_evolution.py +3671 -0
- agent_evolve/application/outcome_conditioned_portfolio_selection.py +1374 -0
- agent_evolve/application/outcome_relation.py +193 -0
- agent_evolve/application/paired_allocation_comparison.py +241 -0
- agent_evolve/application/paired_block_schedule.py +127 -0
- agent_evolve/application/parent_measurement.py +226 -0
- agent_evolve/application/pareto_archive.py +811 -0
- agent_evolve/application/portfolio_campaign_runtime.py +4739 -0
- agent_evolve/application/portfolio_evolution.py +2950 -0
- agent_evolve/application/portfolio_hypothesis_observations.py +814 -0
- agent_evolve/application/portfolio_memory_attribution.py +581 -0
- agent_evolve/application/portfolio_memory_dose.py +788 -0
- agent_evolve/application/portfolio_memory_matched_control.py +938 -0
- agent_evolve/application/portfolio_memory_transfer.py +297 -0
- agent_evolve/application/portfolio_optimization_memory.py +363 -0
- agent_evolve/application/portfolio_outcome_feedback.py +1613 -0
- agent_evolve/application/portfolio_projection.py +335 -0
- agent_evolve/application/portfolio_recombination.py +2032 -0
- agent_evolve/application/post_evolution_reflection.py +834 -0
- agent_evolve/application/postcommit_rank_authority.py +245 -0
- agent_evolve/application/precommitted_portfolio_racing.py +2762 -0
- agent_evolve/application/prequential_archive_opportunity_calibration.py +1154 -0
- agent_evolve/application/prequential_residual_exploration.py +343 -0
- agent_evolve/application/prequential_score_portfolio.py +954 -0
- agent_evolve/application/projections.py +292 -0
- agent_evolve/application/protected_action_committee.py +1027 -0
- agent_evolve/application/protected_branch_pilot.py +376 -0
- agent_evolve/application/protected_current_prefix_forecast_opportunity.py +552 -0
- agent_evolve/application/provider_replay.py +910 -0
- agent_evolve/application/rank_balanced_causal_pilot.py +1372 -0
- agent_evolve/application/recombination_residual_expert.py +403 -0
- agent_evolve/application/reflection_workflow.py +571 -0
- agent_evolve/application/region_conditional_credit.py +911 -0
- agent_evolve/application/residual_campaign_runtime.py +531 -0
- agent_evolve/application/residual_headroom_campaign_runtime.py +459 -0
- agent_evolve/application/residual_headroom_ledger.py +1544 -0
- agent_evolve/application/residual_learning_transaction.py +396 -0
- agent_evolve/application/residual_portfolio_evolution.py +1228 -0
- agent_evolve/application/residual_reachability.py +749 -0
- agent_evolve/application/residual_stage_credit.py +499 -0
- agent_evolve/application/same_prefix_paired_audit.py +1580 -0
- agent_evolve/application/semantic_coverage_score_portfolio.py +838 -0
- agent_evolve/application/sequential_lineage_allocation.py +1017 -0
- agent_evolve/application/sequential_market_replay.py +1395 -0
- agent_evolve/application/sequential_residual_campaign_runtime.py +305 -0
- agent_evolve/application/sequential_residual_portfolio_evolution.py +940 -0
- agent_evolve/application/single_score_action_allocation.py +299 -0
- agent_evolve/application/source_exposure_allocation.py +906 -0
- agent_evolve/application/staged_memory.py +210 -0
- agent_evolve/application/stratified_cold_start_allocation.py +732 -0
- agent_evolve/application/support_guarded_hurdle_score.py +549 -0
- agent_evolve/application/target_conditioned_action_forecast.py +595 -0
- agent_evolve/application/target_conditioned_campaign.py +566 -0
- agent_evolve/application/treatment_assignment.py +201 -0
- agent_evolve/application/trusted_objective_evidence.py +217 -0
- agent_evolve/application/two_stage_action_evolution.py +1131 -0
- agent_evolve/application/v8lite_allocation_policy.py +1083 -0
- agent_evolve/application/v9_candidate_policy.py +1303 -0
- agent_evolve/bootstrap.py +108 -0
- agent_evolve/campaign_presets.py +517 -0
- agent_evolve/campaign_profiles.py +452 -0
- agent_evolve/campaign_variation_topology.py +288 -0
- agent_evolve/campaign_workload.py +950 -0
- agent_evolve/cli.py +797 -0
- agent_evolve/contract.py +241 -0
- agent_evolve/core/__init__.py +91 -0
- agent_evolve/core/action_semantics.py +411 -0
- agent_evolve/core/authored.py +105 -0
- agent_evolve/core/formatting.py +286 -0
- agent_evolve/core/optimization_semantics.py +324 -0
- agent_evolve/core/problem.py +167 -0
- agent_evolve/core/results.py +323 -0
- agent_evolve/core/stats.py +70 -0
- agent_evolve/core/telemetry.py +100 -0
- agent_evolve/domain/__init__.py +89 -0
- agent_evolve/domain/artifact.py +162 -0
- agent_evolve/domain/durable_text.py +68 -0
- agent_evolve/domain/event.py +1454 -0
- agent_evolve/domain/finite_action_set.py +426 -0
- agent_evolve/domain/finite_variation.py +526 -0
- agent_evolve/domain/generative_emission.py +559 -0
- agent_evolve/domain/ids.py +163 -0
- agent_evolve/domain/inline_text.py +106 -0
- agent_evolve/domain/insight.py +27 -0
- agent_evolve/domain/lineage.py +737 -0
- agent_evolve/domain/llm_task_queue.py +960 -0
- agent_evolve/domain/outcome.py +96 -0
- agent_evolve/domain/patch.py +854 -0
- agent_evolve/domain/typed_json.py +542 -0
- agent_evolve/domain/variation_space.py +158 -0
- agent_evolve/driver.py +1014 -0
- agent_evolve/harness/__init__.py +29 -0
- agent_evolve/harness/base.py +242 -0
- agent_evolve/harness/directives.py +163 -0
- agent_evolve/harness/generative_seal.py +479 -0
- agent_evolve/harness/registry.py +41 -0
- agent_evolve/infrastructure/__init__.py +39 -0
- agent_evolve/infrastructure/artifacts/__init__.py +6 -0
- agent_evolve/infrastructure/artifacts/_verification.py +67 -0
- agent_evolve/infrastructure/artifacts/filesystem.py +343 -0
- agent_evolve/infrastructure/artifacts/in_memory.py +73 -0
- agent_evolve/infrastructure/asyncio_runtime.py +109 -0
- agent_evolve/infrastructure/authored_runtime.py +188 -0
- agent_evolve/infrastructure/authored_worker.py +171 -0
- agent_evolve/infrastructure/clock.py +53 -0
- agent_evolve/infrastructure/events/__init__.py +6 -0
- agent_evolve/infrastructure/events/_validation.py +89 -0
- agent_evolve/infrastructure/events/in_memory.py +56 -0
- agent_evolve/infrastructure/events/jsonl.py +193 -0
- agent_evolve/infrastructure/exception_provenance.py +215 -0
- agent_evolve/infrastructure/ids.py +118 -0
- agent_evolve/infrastructure/lineage_codec.py +1836 -0
- agent_evolve/infrastructure/outcome_adaptive_phase_journal.py +170 -0
- agent_evolve/infrastructure/residual_headroom_journal.py +221 -0
- agent_evolve/infrastructure/resource_lease.py +370 -0
- agent_evolve/infrastructure/sanitization/__init__.py +8 -0
- agent_evolve/infrastructure/sanitization/strict_json.py +484 -0
- agent_evolve/infrastructure/sequential_phase_journal.py +170 -0
- agent_evolve/infrastructure/stream_liveness.py +383 -0
- agent_evolve/infrastructure/subprocess_boundary.py +136 -0
- agent_evolve/integrations/__init__.py +1 -0
- agent_evolve/integrations/botorch/__init__.py +28 -0
- agent_evolve/integrations/botorch/finite_qlognehvi.py +190 -0
- agent_evolve/integrations/botorch/finite_qlognehvi_batch.py +155 -0
- agent_evolve/integrations/botorch/finite_qlognehvi_batch_identity.py +20 -0
- agent_evolve/integrations/botorch/finite_qlognehvi_batch_worker.py +55 -0
- agent_evolve/integrations/botorch/finite_qlognehvi_identity.py +22 -0
- agent_evolve/integrations/botorch/finite_qlognehvi_worker.py +55 -0
- agent_evolve/integrations/botorch/subprocess_qlognehvi.py +261 -0
- agent_evolve/integrations/botorch/subprocess_qlognehvi_batch.py +273 -0
- agent_evolve/integrations/completion.py +242 -0
- agent_evolve/integrations/pydantic_ai/__init__.py +441 -0
- agent_evolve/integrations/pydantic_ai/action_forecast.py +1068 -0
- agent_evolve/integrations/pydantic_ai/agentic_generator.py +2308 -0
- agent_evolve/integrations/pydantic_ai/async_generator.py +1604 -0
- agent_evolve/integrations/pydantic_ai/boundary_codec.py +1526 -0
- agent_evolve/integrations/pydantic_ai/calibrated_portfolio_campaign.py +756 -0
- agent_evolve/integrations/pydantic_ai/calibrated_portfolio_selection.py +7537 -0
- agent_evolve/integrations/pydantic_ai/campaign_acquisition.py +609 -0
- agent_evolve/integrations/pydantic_ai/execution_binding.py +138 -0
- agent_evolve/integrations/pydantic_ai/forecast_geometry_action_committee.py +217 -0
- agent_evolve/integrations/pydantic_ai/harness.py +159 -0
- agent_evolve/integrations/pydantic_ai/heterogeneous_model_execution.py +306 -0
- agent_evolve/integrations/pydantic_ai/hierarchical_residual_adaptive_semantic_view.py +179 -0
- agent_evolve/integrations/pydantic_ai/json_schema_dialect.py +108 -0
- agent_evolve/integrations/pydantic_ai/materialized_hierarchical_residual_expert.py +952 -0
- agent_evolve/integrations/pydantic_ai/materialized_portfolio_judge.py +520 -0
- agent_evolve/integrations/pydantic_ai/model_execution_profile.py +659 -0
- agent_evolve/integrations/pydantic_ai/outbound_request_manifest.py +1170 -0
- agent_evolve/integrations/pydantic_ai/portable_residual_consequence_features.py +575 -0
- agent_evolve/integrations/pydantic_ai/portfolio_selection.py +422 -0
- agent_evolve/integrations/pydantic_ai/progress_aware_openrouter.py +416 -0
- agent_evolve/integrations/pydantic_ai/provider_attempt_join.py +1523 -0
- agent_evolve/integrations/pydantic_ai/provider_free_calibrated_runner.py +607 -0
- agent_evolve/integrations/pydantic_ai/queued_runner.py +2634 -0
- agent_evolve/integrations/pydantic_ai/reconciled_residual_reachability.py +1417 -0
- agent_evolve/integrations/pydantic_ai/residual_forecast_geometry.py +445 -0
- agent_evolve/integrations/pydantic_ai/residual_reachability.py +674 -0
- agent_evolve/integrations/pydantic_ai/residual_semantic_cells.py +239 -0
- agent_evolve/integrations/pydantic_ai/sealed_output_replay.py +1068 -0
- agent_evolve/integrations/pydantic_ai/semantic_coverage_residual_portfolio.py +770 -0
- agent_evolve/integrations/pydantic_ai/semantic_decision_replay.py +383 -0
- agent_evolve/integrations/pydantic_ai/support_adaptive_residual_portfolio.py +135 -0
- agent_evolve/integrations/pydantic_ai/trusted_residual_prompt_context.py +143 -0
- agent_evolve/integrations/pydantic_ai/validated_openrouter_model.py +107 -0
- agent_evolve/integrations/pymoo_adapter.py +242 -0
- agent_evolve/policies/__init__.py +17 -0
- agent_evolve/policies/check.py +469 -0
- agent_evolve/policies/emit_scaffold.py +451 -0
- agent_evolve/policies/feedback/__init__.py +37 -0
- agent_evolve/policies/feedback/held_out_asn.py +1325 -0
- agent_evolve/policies/genetic.py +607 -0
- agent_evolve/policies/llm_backoff.py +183 -0
- agent_evolve/policies/llm_chooser.py +226 -0
- agent_evolve/policies/llm_generator.py +1760 -0
- agent_evolve/policies/llm_init.py +267 -0
- agent_evolve/policies/llm_operator.py +109 -0
- agent_evolve/policies/llm_prior.py +194 -0
- agent_evolve/policies/llm_surrogate.py +334 -0
- agent_evolve/policies/measurement_evidence.py +704 -0
- agent_evolve/policies/memory/__init__.py +223 -0
- agent_evolve/policies/memory/balanced_subset_blocks.py +707 -0
- agent_evolve/policies/memory/compatibility_matching.py +593 -0
- agent_evolve/policies/memory/global_falsification.py +1841 -0
- agent_evolve/policies/memory/prompt_shape.py +503 -0
- agent_evolve/policies/memory/randomized_subset.py +714 -0
- agent_evolve/policies/memory/staged_causal.py +1270 -0
- agent_evolve/policies/memory/treatment_compliance.py +759 -0
- agent_evolve/policies/objective_resolution/__init__.py +17 -0
- agent_evolve/policies/objective_resolution/fixed_grid.py +364 -0
- agent_evolve/policies/operator_portfolio.py +407 -0
- agent_evolve/policies/reguidance.py +1133 -0
- agent_evolve/policies/reward/__init__.py +83 -0
- agent_evolve/policies/reward/affine_candidate_consequence.py +156 -0
- agent_evolve/policies/reward/affine_candidate_consequence_3d.py +159 -0
- agent_evolve/policies/reward/affine_hypervolume.py +490 -0
- agent_evolve/policies/reward/affine_hypervolume_3d.py +567 -0
- agent_evolve/policies/reward/contextual_marginal_utility.py +318 -0
- agent_evolve/policies/reward/frozen_archive.py +360 -0
- agent_evolve/policies/reward/frozen_wave_archive.py +368 -0
- agent_evolve/policies/search_state.py +208 -0
- agent_evolve/policies/selection/__init__.py +345 -0
- agent_evolve/policies/selection/acquisition_certified_slate.py +684 -0
- agent_evolve/policies/selection/affine_frontier_context.py +330 -0
- agent_evolve/policies/selection/affine_frontier_target.py +473 -0
- agent_evolve/policies/selection/archive_elite.py +1346 -0
- agent_evolve/policies/selection/calibrated_portfolio_binding.py +640 -0
- agent_evolve/policies/selection/calibrated_slate.py +1394 -0
- agent_evolve/policies/selection/calibrated_slate_codec.py +579 -0
- agent_evolve/policies/selection/common_candidate_pool.py +685 -0
- agent_evolve/policies/selection/diagnostic_sampling.py +319 -0
- agent_evolve/policies/selection/disjoint_pairs.py +479 -0
- agent_evolve/policies/selection/elite_explorer.py +719 -0
- agent_evolve/policies/selection/finite_action.py +187 -0
- agent_evolve/policies/selection/finite_option_prompt_projection.py +377 -0
- agent_evolve/policies/selection/finite_palette_evidence.py +247 -0
- agent_evolve/policies/selection/forecast_calibration.py +922 -0
- agent_evolve/policies/selection/frontier_probe_slate.py +814 -0
- agent_evolve/policies/selection/frozen_archive_pairs.py +762 -0
- agent_evolve/policies/selection/full_support_slate.py +91 -0
- agent_evolve/policies/selection/meaningful_direction.py +240 -0
- agent_evolve/policies/selection/memory_dose_feasibility.py +259 -0
- agent_evolve/policies/selection/model_anchored_slate.py +826 -0
- agent_evolve/policies/selection/phenotype_recourse.py +979 -0
- agent_evolve/policies/selection/proposal_support.py +368 -0
- agent_evolve/policies/selection/random_portfolio.py +254 -0
- agent_evolve/policies/selection/regret_bounded_slate.py +1084 -0
- agent_evolve/policies/selection/residual_frontier.py +463 -0
- agent_evolve/policies/selection/residual_frontier_target.py +605 -0
- agent_evolve/policies/selection/structural_posterior_slate.py +1571 -0
- agent_evolve/policies/selection/target_conditioned_allocator.py +648 -0
- agent_evolve/policies/selection/target_conditioned_features.py +812 -0
- agent_evolve/policies/selection/target_conditioned_prequential.py +1527 -0
- agent_evolve/policies/selection/task_keyed_palette.py +906 -0
- agent_evolve/policies/semantics.py +147 -0
- agent_evolve/policies/structure.py +362 -0
- agent_evolve/policies/structured_output_budget.py +62 -0
- agent_evolve/policies/surrogate.py +696 -0
- agent_evolve/policies/variation/__init__.py +1 -0
- agent_evolve/policies/variation/compositional_finite_catalog.py +426 -0
- agent_evolve/policies/variation/crossover_inheritance.py +575 -0
- agent_evolve/policies/variation/disjoint_recombination.py +611 -0
- agent_evolve/policies/variation/exact_composition_capacity.py +214 -0
- agent_evolve/policies/variation/exact_parent_crossover.py +950 -0
- agent_evolve/policies/variation/multiscale_restart_catalog.py +372 -0
- agent_evolve/policies/variation/source_union_finite_catalog.py +403 -0
- agent_evolve/policies/variation/typed_patch.py +1981 -0
- agent_evolve/policies/weighted_prior.py +394 -0
- agent_evolve/ports/__init__.py +383 -0
- agent_evolve/ports/action_allocation.py +733 -0
- agent_evolve/ports/action_allocation_frame.py +1153 -0
- agent_evolve/ports/action_allocation_frame_commit.py +294 -0
- agent_evolve/ports/action_allocation_frame_commit_v3.py +432 -0
- agent_evolve/ports/action_allocation_frame_v3.py +995 -0
- agent_evolve/ports/action_forecast.py +1568 -0
- agent_evolve/ports/action_metric_projection.py +165 -0
- agent_evolve/ports/agentic_generator.py +1561 -0
- agent_evolve/ports/archive_context.py +136 -0
- agent_evolve/ports/artifact_sanitizer.py +44 -0
- agent_evolve/ports/artifact_store.py +225 -0
- agent_evolve/ports/clock.py +13 -0
- agent_evolve/ports/contextual_search_allocation.py +827 -0
- agent_evolve/ports/decision_metric_projection.py +258 -0
- agent_evolve/ports/event_store.py +55 -0
- agent_evolve/ports/executable_hypothesis.py +557 -0
- agent_evolve/ports/finite_acquisition.py +377 -0
- agent_evolve/ports/finite_acquisition_batch.py +296 -0
- agent_evolve/ports/finite_acquisition_batch_json.py +164 -0
- agent_evolve/ports/finite_acquisition_json.py +247 -0
- agent_evolve/ports/finite_acquisition_space.py +168 -0
- agent_evolve/ports/finite_action_selection.py +348 -0
- agent_evolve/ports/finite_action_set.py +256 -0
- agent_evolve/ports/frontier_target.py +396 -0
- agent_evolve/ports/generation_failure.py +43 -0
- agent_evolve/ports/hard_feasibility.py +233 -0
- agent_evolve/ports/id_factory.py +34 -0
- agent_evolve/ports/llm_task_queue.py +93 -0
- agent_evolve/ports/objective_resolution.py +419 -0
- agent_evolve/ports/paired_allocation_comparison.py +401 -0
- agent_evolve/ports/paired_block_schedule.py +475 -0
- agent_evolve/ports/parent_measurement.py +336 -0
- agent_evolve/ports/portfolio_memory_dose.py +643 -0
- agent_evolve/ports/portfolio_selection.py +3169 -0
- agent_evolve/ports/postcommit_rank_authority.py +467 -0
- agent_evolve/ports/presented_action_evidence.py +794 -0
- agent_evolve/ports/resource_lease.py +162 -0
- agent_evolve/ports/structured_generator.py +734 -0
- agent_evolve/ports/structured_output_budget.py +120 -0
- agent_evolve/ports/subprocess_boundary.py +138 -0
- agent_evolve/ports/treatment_assignment.py +466 -0
- agent_evolve/ports/variation_catalog.py +76 -0
- agent_evolve/ports/variation_source.py +226 -0
- agent_evolve/proposal_mode.py +157 -0
- agent_evolve/proposers/__init__.py +10 -0
- agent_evolve/proposers/random_proposer.py +188 -0
- agent_evolve/provider_accounting.py +163 -0
- agent_evolve/py.typed +0 -0
- agent_evolve/reference_method.py +1570 -0
- agent_evolve/session/__init__.py +11 -0
- agent_evolve/session/authorship.py +864 -0
- agent_evolve/session/evaluate.py +236 -0
- agent_evolve/session/fidelity.py +237 -0
- agent_evolve/session/genetic_loop.py +742 -0
- agent_evolve/session/loop.py +803 -0
- agent_evolve/session/screening.py +671 -0
- agent_evolve/settings.py +376 -0
- agent_evolve/workload_kit.py +368 -0
- agent_evolve/workload_prompt.py +398 -0
- agentevolve_optimizer-0.5.0.dist-info/METADATA +599 -0
- agentevolve_optimizer-0.5.0.dist-info/RECORD +414 -0
- agentevolve_optimizer-0.5.0.dist-info/WHEEL +5 -0
- agentevolve_optimizer-0.5.0.dist-info/entry_points.txt +2 -0
- agentevolve_optimizer-0.5.0.dist-info/licenses/LICENSE +21 -0
- agentevolve_optimizer-0.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,950 @@
|
|
|
1
|
+
"""Bounded exact two-parent crossover over immutable typed JSON.
|
|
2
|
+
|
|
3
|
+
This policy gives a model (or any other selector) only a finite set of opaque
|
|
4
|
+
locus handles. The selector chooses which loci to import from the ordered
|
|
5
|
+
donor; it never authors candidate JSON. Materialization starts from the exact
|
|
6
|
+
base parent and copies exact immutable donor subtrees, so all source
|
|
7
|
+
attribution is machine-derived.
|
|
8
|
+
|
|
9
|
+
The module is deliberately benchmark-, engine-, provider-, and framework-
|
|
10
|
+
neutral. It has no synthesis, value witness, tolerance, or natural-language
|
|
11
|
+
rationale surface.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import hashlib
|
|
17
|
+
import json
|
|
18
|
+
from dataclasses import dataclass
|
|
19
|
+
from enum import Enum
|
|
20
|
+
|
|
21
|
+
from agent_evolve.domain.patch import (
|
|
22
|
+
ArrayIndex,
|
|
23
|
+
JsonPath,
|
|
24
|
+
ObjectKey,
|
|
25
|
+
canonical_path_bytes,
|
|
26
|
+
require_sha256,
|
|
27
|
+
validate_json_path,
|
|
28
|
+
)
|
|
29
|
+
from agent_evolve.domain.typed_json import (
|
|
30
|
+
FrozenJsonArray,
|
|
31
|
+
FrozenJsonObject,
|
|
32
|
+
FrozenJsonValue,
|
|
33
|
+
freeze_json,
|
|
34
|
+
typed_json_equal,
|
|
35
|
+
typed_json_sha256,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
MIN_EXACT_PARENT_CROSSOVER_LOCI = 2
|
|
40
|
+
DEFAULT_MAX_EXACT_PARENT_CROSSOVER_LOCI = 256
|
|
41
|
+
MAX_EXACT_PARENT_CROSSOVER_LOCI = 4096
|
|
42
|
+
|
|
43
|
+
_POLICY = "bounded_exact_parent_import_v1"
|
|
44
|
+
_CONTRACT_DOMAIN = b"agent-evolve:exact-parent-crossover-contract:v1\x00"
|
|
45
|
+
_PLAN_DOMAIN = b"agent-evolve:exact-parent-crossover-plan:v1\x00"
|
|
46
|
+
_MATERIALIZATION_DOMAIN = b"agent-evolve:exact-parent-crossover-materialization:v1\x00"
|
|
47
|
+
_RECEIPT_DOMAIN = b"agent-evolve:exact-parent-crossover-receipt:v1\x00"
|
|
48
|
+
_EXCLUSIONS_DOMAIN = b"agent-evolve:exact-parent-import-exclusions:v1\x00"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _canonical_json(record: dict[str, object]) -> bytes:
|
|
52
|
+
return json.dumps(
|
|
53
|
+
record,
|
|
54
|
+
allow_nan=False,
|
|
55
|
+
ensure_ascii=True,
|
|
56
|
+
separators=(",", ":"),
|
|
57
|
+
sort_keys=True,
|
|
58
|
+
).encode("ascii", errors="strict")
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _hash_record(domain: bytes, record: dict[str, object]) -> str:
|
|
62
|
+
return hashlib.sha256(domain + _canonical_json(record)).hexdigest()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _validate_max_loci(max_loci: int) -> None:
|
|
66
|
+
if type(max_loci) is not int:
|
|
67
|
+
raise TypeError("max_loci must be an exact integer")
|
|
68
|
+
if not (
|
|
69
|
+
MIN_EXACT_PARENT_CROSSOVER_LOCI <= max_loci <= MAX_EXACT_PARENT_CROSSOVER_LOCI
|
|
70
|
+
):
|
|
71
|
+
raise ValueError(
|
|
72
|
+
"max_loci must lie in "
|
|
73
|
+
f"[{MIN_EXACT_PARENT_CROSSOVER_LOCI}, "
|
|
74
|
+
f"{MAX_EXACT_PARENT_CROSSOVER_LOCI}]"
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _validate_parent(value: FrozenJsonObject, *, name: str) -> None:
|
|
79
|
+
if type(value) is not FrozenJsonObject:
|
|
80
|
+
raise TypeError(f"{name} must be an exact FrozenJsonObject")
|
|
81
|
+
# Frozen dataclasses can still be reconstructed outside their generated
|
|
82
|
+
# constructor. Revalidate the complete graph at every public boundary.
|
|
83
|
+
freeze_json(value)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def canonical_candidate_path_text(path: JsonPath) -> str:
|
|
87
|
+
"""Return an unambiguous candidate-relative display form for ``path``.
|
|
88
|
+
|
|
89
|
+
Object keys always use JSON bracket notation. This avoids collisions for
|
|
90
|
+
keys containing dots, brackets, quotes, or decimal-looking text.
|
|
91
|
+
Typed :class:`JsonPath` remains the authority; this string is a canonical
|
|
92
|
+
wire/display projection of it.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
validate_json_path(path)
|
|
96
|
+
chunks = ["$"]
|
|
97
|
+
for segment in path.segments:
|
|
98
|
+
if type(segment) is ObjectKey:
|
|
99
|
+
chunks.append(
|
|
100
|
+
"["
|
|
101
|
+
+ json.dumps(
|
|
102
|
+
segment.value,
|
|
103
|
+
allow_nan=False,
|
|
104
|
+
ensure_ascii=True,
|
|
105
|
+
separators=(",", ":"),
|
|
106
|
+
)
|
|
107
|
+
+ "]"
|
|
108
|
+
)
|
|
109
|
+
elif type(segment) is ArrayIndex:
|
|
110
|
+
chunks.append(f"[{segment.value}]")
|
|
111
|
+
else: # pragma: no cover - JsonPath validation closes the union.
|
|
112
|
+
raise AssertionError("unsupported path segment")
|
|
113
|
+
return "".join(chunks)
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _canonical_locus_id(ordinal: int) -> str:
|
|
117
|
+
if type(ordinal) is not int or not (
|
|
118
|
+
1 <= ordinal <= MAX_EXACT_PARENT_CROSSOVER_LOCI
|
|
119
|
+
):
|
|
120
|
+
raise ValueError("locus ordinal is outside the policy bound")
|
|
121
|
+
# IDs are compact contract-scoped handles. The contract digest binds each
|
|
122
|
+
# ordinal to its exact path and parent subtree hashes.
|
|
123
|
+
return f"locus_{ordinal:04d}"
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@dataclass(frozen=True, slots=True)
|
|
127
|
+
class ExactParentCrossoverLocus:
|
|
128
|
+
"""One nonoverlapping parent-discriminating locus."""
|
|
129
|
+
|
|
130
|
+
locus_id: str
|
|
131
|
+
path: JsonPath
|
|
132
|
+
path_text: str
|
|
133
|
+
base_value_sha256: str
|
|
134
|
+
donor_value_sha256: str
|
|
135
|
+
|
|
136
|
+
def __post_init__(self) -> None:
|
|
137
|
+
if type(self.locus_id) is not str:
|
|
138
|
+
raise TypeError("locus_id must be an exact string")
|
|
139
|
+
validate_json_path(self.path)
|
|
140
|
+
if self.path_text != canonical_candidate_path_text(self.path):
|
|
141
|
+
raise ValueError("path_text is not the canonical projection of path")
|
|
142
|
+
require_sha256(self.base_value_sha256, "base_value_sha256")
|
|
143
|
+
require_sha256(self.donor_value_sha256, "donor_value_sha256")
|
|
144
|
+
if self.base_value_sha256 == self.donor_value_sha256:
|
|
145
|
+
raise ValueError("a crossover locus must discriminate the parents")
|
|
146
|
+
|
|
147
|
+
def to_record(self) -> dict[str, object]:
|
|
148
|
+
ExactParentCrossoverLocus.__post_init__(self)
|
|
149
|
+
return {
|
|
150
|
+
"locus_id": self.locus_id,
|
|
151
|
+
"path_text": self.path_text,
|
|
152
|
+
"path_schema_identity": self.path.schema_identity,
|
|
153
|
+
"base_value_sha256": self.base_value_sha256,
|
|
154
|
+
"donor_value_sha256": self.donor_value_sha256,
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _validate_locus_tuple(
|
|
159
|
+
loci: tuple[ExactParentCrossoverLocus, ...],
|
|
160
|
+
*,
|
|
161
|
+
max_loci: int,
|
|
162
|
+
) -> None:
|
|
163
|
+
if type(loci) is not tuple or any(
|
|
164
|
+
type(locus) is not ExactParentCrossoverLocus for locus in loci
|
|
165
|
+
):
|
|
166
|
+
raise TypeError("loci must be an exact tuple of exact crossover loci")
|
|
167
|
+
if not (MIN_EXACT_PARENT_CROSSOVER_LOCI <= len(loci) <= max_loci):
|
|
168
|
+
raise ValueError(
|
|
169
|
+
"a crossover contract requires at least two loci and may not "
|
|
170
|
+
"exceed max_loci"
|
|
171
|
+
)
|
|
172
|
+
for locus in loci:
|
|
173
|
+
ExactParentCrossoverLocus.__post_init__(locus)
|
|
174
|
+
expected_ids = tuple(
|
|
175
|
+
_canonical_locus_id(index) for index in range(1, len(loci) + 1)
|
|
176
|
+
)
|
|
177
|
+
if tuple(locus.locus_id for locus in loci) != expected_ids:
|
|
178
|
+
raise ValueError("locus IDs must be the canonical contract-scoped sequence")
|
|
179
|
+
path_keys = tuple(canonical_path_bytes(locus.path) for locus in loci)
|
|
180
|
+
if path_keys != tuple(sorted(path_keys)):
|
|
181
|
+
raise ValueError("loci must use canonical typed-path order")
|
|
182
|
+
if len(set(path_keys)) != len(path_keys):
|
|
183
|
+
raise ValueError("locus paths must be unique")
|
|
184
|
+
terminal = object()
|
|
185
|
+
root: dict[object, object] = {}
|
|
186
|
+
for locus in loci:
|
|
187
|
+
node = root
|
|
188
|
+
for segment in locus.path.segments:
|
|
189
|
+
if terminal in node:
|
|
190
|
+
raise ValueError("locus paths must not overlap")
|
|
191
|
+
child = node.setdefault(segment, {})
|
|
192
|
+
if type(child) is not dict: # pragma: no cover - local invariant.
|
|
193
|
+
raise AssertionError("invalid locus path trie")
|
|
194
|
+
node = child
|
|
195
|
+
if node:
|
|
196
|
+
# A prior path is either identical (already rejected above) or a
|
|
197
|
+
# strict descendant of this locus.
|
|
198
|
+
raise ValueError("locus paths must not overlap")
|
|
199
|
+
node[terminal] = True
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@dataclass(frozen=True, slots=True)
|
|
203
|
+
class ExactParentCrossoverContract:
|
|
204
|
+
"""Canonical finite action contract for ordered base and donor parents."""
|
|
205
|
+
|
|
206
|
+
max_loci: int
|
|
207
|
+
base_parent_sha256: str
|
|
208
|
+
donor_parent_sha256: str
|
|
209
|
+
loci: tuple[ExactParentCrossoverLocus, ...]
|
|
210
|
+
|
|
211
|
+
def __post_init__(self) -> None:
|
|
212
|
+
_validate_max_loci(self.max_loci)
|
|
213
|
+
require_sha256(self.base_parent_sha256, "base_parent_sha256")
|
|
214
|
+
require_sha256(self.donor_parent_sha256, "donor_parent_sha256")
|
|
215
|
+
if self.base_parent_sha256 == self.donor_parent_sha256:
|
|
216
|
+
raise ValueError("ordered crossover parents must be exact-distinct")
|
|
217
|
+
_validate_locus_tuple(self.loci, max_loci=self.max_loci)
|
|
218
|
+
|
|
219
|
+
def to_record(self) -> dict[str, object]:
|
|
220
|
+
ExactParentCrossoverContract.__post_init__(self)
|
|
221
|
+
return {
|
|
222
|
+
"schema_version": 1,
|
|
223
|
+
"policy": _POLICY,
|
|
224
|
+
"max_loci": self.max_loci,
|
|
225
|
+
"base_parent_sha256": self.base_parent_sha256,
|
|
226
|
+
"donor_parent_sha256": self.donor_parent_sha256,
|
|
227
|
+
"loci": [locus.to_record() for locus in self.loci],
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
@property
|
|
231
|
+
def contract_sha256(self) -> str:
|
|
232
|
+
return _hash_record(_CONTRACT_DOMAIN, self.to_record())
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _append_discriminating_loci(
|
|
236
|
+
base: FrozenJsonValue,
|
|
237
|
+
donor: FrozenJsonValue,
|
|
238
|
+
path: JsonPath,
|
|
239
|
+
loci: list[tuple[JsonPath, FrozenJsonValue, FrozenJsonValue]],
|
|
240
|
+
*,
|
|
241
|
+
max_loci: int,
|
|
242
|
+
) -> None:
|
|
243
|
+
if typed_json_equal(base, donor):
|
|
244
|
+
return
|
|
245
|
+
|
|
246
|
+
if type(base) is FrozenJsonObject and type(donor) is FrozenJsonObject:
|
|
247
|
+
base_keys = tuple(key for key, _ in base.items)
|
|
248
|
+
donor_keys = tuple(key for key, _ in donor.items)
|
|
249
|
+
if base_keys == donor_keys:
|
|
250
|
+
for (key, base_item), (_, donor_item) in zip(
|
|
251
|
+
base.items, donor.items, strict=True
|
|
252
|
+
):
|
|
253
|
+
_append_discriminating_loci(
|
|
254
|
+
base_item,
|
|
255
|
+
donor_item,
|
|
256
|
+
path.child_key(key),
|
|
257
|
+
loci,
|
|
258
|
+
max_loci=max_loci,
|
|
259
|
+
)
|
|
260
|
+
return
|
|
261
|
+
|
|
262
|
+
if type(base) is FrozenJsonArray and type(donor) is FrozenJsonArray:
|
|
263
|
+
if len(base.items) == len(donor.items):
|
|
264
|
+
for index, (base_item, donor_item) in enumerate(
|
|
265
|
+
zip(base.items, donor.items, strict=True)
|
|
266
|
+
):
|
|
267
|
+
_append_discriminating_loci(
|
|
268
|
+
base_item,
|
|
269
|
+
donor_item,
|
|
270
|
+
path.child_index(index),
|
|
271
|
+
loci,
|
|
272
|
+
max_loci=max_loci,
|
|
273
|
+
)
|
|
274
|
+
return
|
|
275
|
+
|
|
276
|
+
# Scalars, type changes, object key-set changes, and array length changes
|
|
277
|
+
# are indivisible exact imports at their nearest containing subtree.
|
|
278
|
+
loci.append((path, base, donor))
|
|
279
|
+
if len(loci) > max_loci:
|
|
280
|
+
raise ValueError("derived crossover contract exceeds max_loci")
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def derive_exact_parent_crossover_contract(
|
|
284
|
+
*,
|
|
285
|
+
base: FrozenJsonObject,
|
|
286
|
+
donor: FrozenJsonObject,
|
|
287
|
+
max_loci: int = DEFAULT_MAX_EXACT_PARENT_CROSSOVER_LOCI,
|
|
288
|
+
) -> ExactParentCrossoverContract:
|
|
289
|
+
"""Derive the canonical bounded locus frontier for ordered parents.
|
|
290
|
+
|
|
291
|
+
Equal subtrees are omitted. Same-shape objects and arrays are recursively
|
|
292
|
+
split; a topology or runtime-type mismatch is represented by one exact
|
|
293
|
+
containing-subtree locus. Derivation fails closed when the exact frontier
|
|
294
|
+
has fewer than two or more than ``max_loci`` members.
|
|
295
|
+
"""
|
|
296
|
+
|
|
297
|
+
_validate_parent(base, name="base")
|
|
298
|
+
_validate_parent(donor, name="donor")
|
|
299
|
+
_validate_max_loci(max_loci)
|
|
300
|
+
|
|
301
|
+
derived: list[tuple[JsonPath, FrozenJsonValue, FrozenJsonValue]] = []
|
|
302
|
+
_append_discriminating_loci(
|
|
303
|
+
base,
|
|
304
|
+
donor,
|
|
305
|
+
JsonPath(),
|
|
306
|
+
derived,
|
|
307
|
+
max_loci=max_loci,
|
|
308
|
+
)
|
|
309
|
+
derived.sort(key=lambda item: canonical_path_bytes(item[0]))
|
|
310
|
+
if len(derived) < MIN_EXACT_PARENT_CROSSOVER_LOCI:
|
|
311
|
+
raise ValueError(
|
|
312
|
+
"ordered parents expose fewer than two exact discriminating loci"
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
loci = tuple(
|
|
316
|
+
ExactParentCrossoverLocus(
|
|
317
|
+
locus_id=_canonical_locus_id(index),
|
|
318
|
+
path=path,
|
|
319
|
+
path_text=canonical_candidate_path_text(path),
|
|
320
|
+
base_value_sha256=typed_json_sha256(base_value),
|
|
321
|
+
donor_value_sha256=typed_json_sha256(donor_value),
|
|
322
|
+
)
|
|
323
|
+
for index, (path, base_value, donor_value) in enumerate(derived, start=1)
|
|
324
|
+
)
|
|
325
|
+
return ExactParentCrossoverContract(
|
|
326
|
+
max_loci=max_loci,
|
|
327
|
+
base_parent_sha256=typed_json_sha256(base),
|
|
328
|
+
donor_parent_sha256=typed_json_sha256(donor),
|
|
329
|
+
loci=loci,
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
@dataclass(frozen=True, slots=True)
|
|
334
|
+
class ExactParentImportPlan:
|
|
335
|
+
"""A canonical, bounded donor-locus selection for one exact contract."""
|
|
336
|
+
|
|
337
|
+
contract_sha256: str
|
|
338
|
+
locus_count: int
|
|
339
|
+
import_locus_ids: tuple[str, ...]
|
|
340
|
+
|
|
341
|
+
def __post_init__(self) -> None:
|
|
342
|
+
require_sha256(self.contract_sha256, "contract_sha256")
|
|
343
|
+
if type(self.locus_count) is not int:
|
|
344
|
+
raise TypeError("locus_count must be an exact integer")
|
|
345
|
+
if not (
|
|
346
|
+
MIN_EXACT_PARENT_CROSSOVER_LOCI
|
|
347
|
+
<= self.locus_count
|
|
348
|
+
<= MAX_EXACT_PARENT_CROSSOVER_LOCI
|
|
349
|
+
):
|
|
350
|
+
raise ValueError("locus_count is outside the crossover policy bound")
|
|
351
|
+
if type(self.import_locus_ids) is not tuple or any(
|
|
352
|
+
type(value) is not str for value in self.import_locus_ids
|
|
353
|
+
):
|
|
354
|
+
raise TypeError("import_locus_ids must be an exact tuple of strings")
|
|
355
|
+
if len(set(self.import_locus_ids)) != len(self.import_locus_ids):
|
|
356
|
+
raise ValueError("import_locus_ids must be unique")
|
|
357
|
+
if self.import_locus_ids != tuple(sorted(self.import_locus_ids)):
|
|
358
|
+
raise ValueError("import_locus_ids must use canonical contract order")
|
|
359
|
+
if not self.import_locus_ids:
|
|
360
|
+
raise ValueError("a crossover plan must import at least one donor locus")
|
|
361
|
+
if len(self.import_locus_ids) >= self.locus_count:
|
|
362
|
+
raise ValueError("a crossover plan must retain at least one base locus")
|
|
363
|
+
|
|
364
|
+
def to_record(self) -> dict[str, object]:
|
|
365
|
+
ExactParentImportPlan.__post_init__(self)
|
|
366
|
+
return {
|
|
367
|
+
"schema_version": 1,
|
|
368
|
+
"policy": _POLICY,
|
|
369
|
+
"contract_sha256": self.contract_sha256,
|
|
370
|
+
"locus_count": self.locus_count,
|
|
371
|
+
"import_locus_ids": list(self.import_locus_ids),
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
@property
|
|
375
|
+
def plan_sha256(self) -> str:
|
|
376
|
+
return _hash_record(_PLAN_DOMAIN, self.to_record())
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
def build_exact_parent_import_plan(
|
|
380
|
+
contract: ExactParentCrossoverContract,
|
|
381
|
+
import_locus_ids: tuple[str, ...],
|
|
382
|
+
) -> ExactParentImportPlan:
|
|
383
|
+
"""Validate model-sized locus handles against their exact contract."""
|
|
384
|
+
|
|
385
|
+
if type(contract) is not ExactParentCrossoverContract:
|
|
386
|
+
raise TypeError("contract must be an exact ExactParentCrossoverContract")
|
|
387
|
+
ExactParentCrossoverContract.__post_init__(contract)
|
|
388
|
+
plan = ExactParentImportPlan(
|
|
389
|
+
contract_sha256=contract.contract_sha256,
|
|
390
|
+
locus_count=len(contract.loci),
|
|
391
|
+
import_locus_ids=import_locus_ids,
|
|
392
|
+
)
|
|
393
|
+
allowed = {locus.locus_id for locus in contract.loci}
|
|
394
|
+
if any(locus_id not in allowed for locus_id in plan.import_locus_ids):
|
|
395
|
+
raise ValueError("import_locus_ids contains an ID outside the contract")
|
|
396
|
+
selected = set(plan.import_locus_ids)
|
|
397
|
+
contract_order = tuple(
|
|
398
|
+
locus.locus_id for locus in contract.loci if locus.locus_id in selected
|
|
399
|
+
)
|
|
400
|
+
if plan.import_locus_ids != contract_order:
|
|
401
|
+
raise ValueError("import_locus_ids must follow exact contract order")
|
|
402
|
+
return plan
|
|
403
|
+
|
|
404
|
+
|
|
405
|
+
def validate_exact_parent_import_exclusions(
|
|
406
|
+
contract: ExactParentCrossoverContract,
|
|
407
|
+
forbidden_import_locus_sets: tuple[tuple[str, ...], ...],
|
|
408
|
+
) -> None:
|
|
409
|
+
"""Validate a canonical set of exact crossover actions to exclude.
|
|
410
|
+
|
|
411
|
+
Every inner tuple is one otherwise-valid proper parent-import plan. The
|
|
412
|
+
outer tuple is lexicographically sorted and duplicate-free so prompt,
|
|
413
|
+
schema, plan, and trace projections all bind one unambiguous value.
|
|
414
|
+
"""
|
|
415
|
+
|
|
416
|
+
if type(contract) is not ExactParentCrossoverContract:
|
|
417
|
+
raise TypeError("contract must be an exact ExactParentCrossoverContract")
|
|
418
|
+
ExactParentCrossoverContract.__post_init__(contract)
|
|
419
|
+
if type(forbidden_import_locus_sets) is not tuple or any(
|
|
420
|
+
type(value) is not tuple for value in forbidden_import_locus_sets
|
|
421
|
+
):
|
|
422
|
+
raise TypeError("forbidden import locus sets must be an exact tuple of tuples")
|
|
423
|
+
for import_locus_ids in forbidden_import_locus_sets:
|
|
424
|
+
build_exact_parent_import_plan(contract, import_locus_ids)
|
|
425
|
+
if forbidden_import_locus_sets != tuple(sorted(set(forbidden_import_locus_sets))):
|
|
426
|
+
raise ValueError(
|
|
427
|
+
"forbidden import locus sets must be unique and canonically sorted"
|
|
428
|
+
)
|
|
429
|
+
if len(forbidden_import_locus_sets) == (1 << len(contract.loci)) - 2:
|
|
430
|
+
raise ValueError(
|
|
431
|
+
"forbidden import locus sets exhaust the exact crossover action space"
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def exact_parent_import_exclusions_sha256(
|
|
436
|
+
contract: ExactParentCrossoverContract,
|
|
437
|
+
forbidden_import_locus_sets: tuple[tuple[str, ...], ...],
|
|
438
|
+
) -> str:
|
|
439
|
+
"""Commit one contract-scoped canonical exclusion set."""
|
|
440
|
+
|
|
441
|
+
validate_exact_parent_import_exclusions(contract, forbidden_import_locus_sets)
|
|
442
|
+
return _hash_record(
|
|
443
|
+
_EXCLUSIONS_DOMAIN,
|
|
444
|
+
{
|
|
445
|
+
"schema_version": 1,
|
|
446
|
+
"policy": _POLICY,
|
|
447
|
+
"contract_sha256": contract.contract_sha256,
|
|
448
|
+
"forbidden_import_locus_sets": [
|
|
449
|
+
list(value) for value in forbidden_import_locus_sets
|
|
450
|
+
],
|
|
451
|
+
},
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
class ExactParentSource(str, Enum):
|
|
456
|
+
"""Closed, machine-derived locus source vocabulary."""
|
|
457
|
+
|
|
458
|
+
BASE = "base"
|
|
459
|
+
DONOR = "donor"
|
|
460
|
+
|
|
461
|
+
|
|
462
|
+
@dataclass(frozen=True, slots=True)
|
|
463
|
+
class ExactParentLocusAttribution:
|
|
464
|
+
"""Hash-only evidence for one retained or imported exact subtree."""
|
|
465
|
+
|
|
466
|
+
locus_id: str
|
|
467
|
+
path_text: str
|
|
468
|
+
source: ExactParentSource
|
|
469
|
+
base_value_sha256: str
|
|
470
|
+
donor_value_sha256: str
|
|
471
|
+
source_value_sha256: str
|
|
472
|
+
materialized_value_sha256: str
|
|
473
|
+
|
|
474
|
+
def __post_init__(self) -> None:
|
|
475
|
+
if type(self.locus_id) is not str or type(self.path_text) is not str:
|
|
476
|
+
raise TypeError("attribution identifiers must be exact strings")
|
|
477
|
+
if type(self.source) is not ExactParentSource:
|
|
478
|
+
raise TypeError("attribution source must be an exact ExactParentSource")
|
|
479
|
+
for name in (
|
|
480
|
+
"base_value_sha256",
|
|
481
|
+
"donor_value_sha256",
|
|
482
|
+
"source_value_sha256",
|
|
483
|
+
"materialized_value_sha256",
|
|
484
|
+
):
|
|
485
|
+
require_sha256(getattr(self, name), name)
|
|
486
|
+
expected = (
|
|
487
|
+
self.base_value_sha256
|
|
488
|
+
if self.source is ExactParentSource.BASE
|
|
489
|
+
else self.donor_value_sha256
|
|
490
|
+
)
|
|
491
|
+
if self.source_value_sha256 != expected:
|
|
492
|
+
raise ValueError("source hash does not match the attributed parent")
|
|
493
|
+
if self.materialized_value_sha256 != self.source_value_sha256:
|
|
494
|
+
raise ValueError("materialized locus does not match its exact source")
|
|
495
|
+
|
|
496
|
+
def to_record(self) -> dict[str, object]:
|
|
497
|
+
ExactParentLocusAttribution.__post_init__(self)
|
|
498
|
+
return {
|
|
499
|
+
"locus_id": self.locus_id,
|
|
500
|
+
"path_text": self.path_text,
|
|
501
|
+
"source": self.source.value,
|
|
502
|
+
"base_value_sha256": self.base_value_sha256,
|
|
503
|
+
"donor_value_sha256": self.donor_value_sha256,
|
|
504
|
+
"source_value_sha256": self.source_value_sha256,
|
|
505
|
+
"materialized_value_sha256": self.materialized_value_sha256,
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
def _materialization_record(
|
|
510
|
+
*,
|
|
511
|
+
contract_sha256: str,
|
|
512
|
+
plan_sha256: str,
|
|
513
|
+
materialized_configuration_sha256: str,
|
|
514
|
+
attributions: tuple[ExactParentLocusAttribution, ...],
|
|
515
|
+
) -> dict[str, object]:
|
|
516
|
+
return {
|
|
517
|
+
"schema_version": 1,
|
|
518
|
+
"policy": _POLICY,
|
|
519
|
+
"contract_sha256": contract_sha256,
|
|
520
|
+
"plan_sha256": plan_sha256,
|
|
521
|
+
"materialized_configuration_sha256": (materialized_configuration_sha256),
|
|
522
|
+
"attributions": [value.to_record() for value in attributions],
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
def _value_at_path(root: FrozenJsonValue, path: JsonPath) -> FrozenJsonValue:
|
|
527
|
+
validate_json_path(path)
|
|
528
|
+
current = root
|
|
529
|
+
missing = object()
|
|
530
|
+
for segment in path.segments:
|
|
531
|
+
if type(segment) is ObjectKey:
|
|
532
|
+
if type(current) is not FrozenJsonObject:
|
|
533
|
+
raise ValueError("object-key path traverses a non-object")
|
|
534
|
+
match = next(
|
|
535
|
+
(item for key, item in current.items if key == segment.value),
|
|
536
|
+
missing,
|
|
537
|
+
)
|
|
538
|
+
if match is missing:
|
|
539
|
+
raise ValueError("object-key path is absent")
|
|
540
|
+
current = match # type: ignore[assignment]
|
|
541
|
+
elif type(segment) is ArrayIndex:
|
|
542
|
+
if type(current) is not FrozenJsonArray:
|
|
543
|
+
raise ValueError("array-index path traverses a non-array")
|
|
544
|
+
if segment.value >= len(current.items):
|
|
545
|
+
raise ValueError("array-index path is absent")
|
|
546
|
+
current = current.items[segment.value]
|
|
547
|
+
else: # pragma: no cover - JsonPath validation closes the union.
|
|
548
|
+
raise AssertionError("unsupported path segment")
|
|
549
|
+
return current
|
|
550
|
+
|
|
551
|
+
|
|
552
|
+
def _replace_existing_path(
|
|
553
|
+
root: FrozenJsonValue,
|
|
554
|
+
path: JsonPath,
|
|
555
|
+
replacement: FrozenJsonValue,
|
|
556
|
+
) -> FrozenJsonValue:
|
|
557
|
+
if not path.segments:
|
|
558
|
+
return replacement
|
|
559
|
+
head = path.segments[0]
|
|
560
|
+
tail = JsonPath(path.segments[1:])
|
|
561
|
+
if type(head) is ObjectKey:
|
|
562
|
+
if type(root) is not FrozenJsonObject:
|
|
563
|
+
raise ValueError("object-key path traverses a non-object")
|
|
564
|
+
found = False
|
|
565
|
+
updated: list[tuple[str, FrozenJsonValue]] = []
|
|
566
|
+
for key, item in root.items:
|
|
567
|
+
if key == head.value:
|
|
568
|
+
found = True
|
|
569
|
+
updated.append((key, _replace_existing_path(item, tail, replacement)))
|
|
570
|
+
else:
|
|
571
|
+
updated.append((key, item))
|
|
572
|
+
if not found:
|
|
573
|
+
raise ValueError("object-key replacement path is absent")
|
|
574
|
+
return FrozenJsonObject(tuple(updated))
|
|
575
|
+
if type(head) is ArrayIndex:
|
|
576
|
+
if type(root) is not FrozenJsonArray:
|
|
577
|
+
raise ValueError("array-index path traverses a non-array")
|
|
578
|
+
if head.value >= len(root.items):
|
|
579
|
+
raise ValueError("array-index replacement path is absent")
|
|
580
|
+
updated_items = list(root.items)
|
|
581
|
+
updated_items[head.value] = _replace_existing_path(
|
|
582
|
+
updated_items[head.value], tail, replacement
|
|
583
|
+
)
|
|
584
|
+
return FrozenJsonArray(tuple(updated_items))
|
|
585
|
+
raise AssertionError("unsupported path segment") # pragma: no cover
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
@dataclass(frozen=True, slots=True)
|
|
589
|
+
class ExactParentCrossoverReceipt:
|
|
590
|
+
"""Self-auditing hash receipt replayable with the exact ordered parents."""
|
|
591
|
+
|
|
592
|
+
max_loci: int
|
|
593
|
+
base_parent_sha256: str
|
|
594
|
+
donor_parent_sha256: str
|
|
595
|
+
contract_sha256: str
|
|
596
|
+
plan_sha256: str
|
|
597
|
+
import_locus_ids: tuple[str, ...]
|
|
598
|
+
materialized_configuration_sha256: str
|
|
599
|
+
materialization_sha256: str
|
|
600
|
+
attributions: tuple[ExactParentLocusAttribution, ...]
|
|
601
|
+
|
|
602
|
+
def __post_init__(self) -> None:
|
|
603
|
+
_validate_max_loci(self.max_loci)
|
|
604
|
+
for name in (
|
|
605
|
+
"base_parent_sha256",
|
|
606
|
+
"donor_parent_sha256",
|
|
607
|
+
"contract_sha256",
|
|
608
|
+
"plan_sha256",
|
|
609
|
+
"materialized_configuration_sha256",
|
|
610
|
+
"materialization_sha256",
|
|
611
|
+
):
|
|
612
|
+
require_sha256(getattr(self, name), name)
|
|
613
|
+
if type(self.import_locus_ids) is not tuple or any(
|
|
614
|
+
type(value) is not str for value in self.import_locus_ids
|
|
615
|
+
):
|
|
616
|
+
raise TypeError(
|
|
617
|
+
"receipt import_locus_ids must be an exact tuple of strings"
|
|
618
|
+
)
|
|
619
|
+
if type(self.attributions) is not tuple or any(
|
|
620
|
+
type(value) is not ExactParentLocusAttribution
|
|
621
|
+
for value in self.attributions
|
|
622
|
+
):
|
|
623
|
+
raise TypeError("receipt attributions must be an exact tuple")
|
|
624
|
+
for attribution in self.attributions:
|
|
625
|
+
ExactParentLocusAttribution.__post_init__(attribution)
|
|
626
|
+
if not (
|
|
627
|
+
MIN_EXACT_PARENT_CROSSOVER_LOCI <= len(self.attributions) <= self.max_loci
|
|
628
|
+
):
|
|
629
|
+
raise ValueError("receipt attribution count is outside its bound")
|
|
630
|
+
if tuple(value.locus_id for value in self.attributions) != tuple(
|
|
631
|
+
_canonical_locus_id(index) for index in range(1, len(self.attributions) + 1)
|
|
632
|
+
):
|
|
633
|
+
raise ValueError("receipt attributions must use canonical locus order")
|
|
634
|
+
plan = ExactParentImportPlan(
|
|
635
|
+
contract_sha256=self.contract_sha256,
|
|
636
|
+
locus_count=len(self.attributions),
|
|
637
|
+
import_locus_ids=self.import_locus_ids,
|
|
638
|
+
)
|
|
639
|
+
if plan.plan_sha256 != self.plan_sha256:
|
|
640
|
+
raise ValueError("receipt plan hash does not match its import plan")
|
|
641
|
+
imported = set(self.import_locus_ids)
|
|
642
|
+
if not imported <= {value.locus_id for value in self.attributions}:
|
|
643
|
+
raise ValueError("receipt imports a locus outside its attribution set")
|
|
644
|
+
for attribution in self.attributions:
|
|
645
|
+
expected_source = (
|
|
646
|
+
ExactParentSource.DONOR
|
|
647
|
+
if attribution.locus_id in imported
|
|
648
|
+
else ExactParentSource.BASE
|
|
649
|
+
)
|
|
650
|
+
if attribution.source is not expected_source:
|
|
651
|
+
raise ValueError("receipt attribution contradicts its import plan")
|
|
652
|
+
expected_materialization = _hash_record(
|
|
653
|
+
_MATERIALIZATION_DOMAIN,
|
|
654
|
+
_materialization_record(
|
|
655
|
+
contract_sha256=self.contract_sha256,
|
|
656
|
+
plan_sha256=self.plan_sha256,
|
|
657
|
+
materialized_configuration_sha256=(
|
|
658
|
+
self.materialized_configuration_sha256
|
|
659
|
+
),
|
|
660
|
+
attributions=self.attributions,
|
|
661
|
+
),
|
|
662
|
+
)
|
|
663
|
+
if self.materialization_sha256 != expected_materialization:
|
|
664
|
+
raise ValueError("receipt materialization hash does not match its evidence")
|
|
665
|
+
|
|
666
|
+
def to_record(self) -> dict[str, object]:
|
|
667
|
+
ExactParentCrossoverReceipt.__post_init__(self)
|
|
668
|
+
return {
|
|
669
|
+
"schema_version": 1,
|
|
670
|
+
"policy": _POLICY,
|
|
671
|
+
"max_loci": self.max_loci,
|
|
672
|
+
"base_parent_sha256": self.base_parent_sha256,
|
|
673
|
+
"donor_parent_sha256": self.donor_parent_sha256,
|
|
674
|
+
"contract_sha256": self.contract_sha256,
|
|
675
|
+
"plan_sha256": self.plan_sha256,
|
|
676
|
+
"import_locus_ids": list(self.import_locus_ids),
|
|
677
|
+
"materialized_configuration_sha256": (
|
|
678
|
+
self.materialized_configuration_sha256
|
|
679
|
+
),
|
|
680
|
+
"materialization_sha256": self.materialization_sha256,
|
|
681
|
+
"attributions": [value.to_record() for value in self.attributions],
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
@property
|
|
685
|
+
def receipt_sha256(self) -> str:
|
|
686
|
+
return _hash_record(_RECEIPT_DOMAIN, self.to_record())
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
@dataclass(frozen=True, slots=True)
|
|
690
|
+
class ExactParentCrossoverMaterialization:
|
|
691
|
+
"""Exact child, finite plan, exhaustive source evidence, and receipt."""
|
|
692
|
+
|
|
693
|
+
configuration: FrozenJsonObject
|
|
694
|
+
contract: ExactParentCrossoverContract
|
|
695
|
+
plan: ExactParentImportPlan
|
|
696
|
+
attributions: tuple[ExactParentLocusAttribution, ...]
|
|
697
|
+
|
|
698
|
+
def __post_init__(self) -> None:
|
|
699
|
+
_validate_parent(self.configuration, name="configuration")
|
|
700
|
+
if type(self.contract) is not ExactParentCrossoverContract:
|
|
701
|
+
raise TypeError("contract must be exact")
|
|
702
|
+
ExactParentCrossoverContract.__post_init__(self.contract)
|
|
703
|
+
if type(self.plan) is not ExactParentImportPlan:
|
|
704
|
+
raise TypeError("plan must be exact")
|
|
705
|
+
ExactParentImportPlan.__post_init__(self.plan)
|
|
706
|
+
if self.plan.contract_sha256 != self.contract.contract_sha256:
|
|
707
|
+
raise ValueError("plan does not bind the supplied contract")
|
|
708
|
+
expected_plan = build_exact_parent_import_plan(
|
|
709
|
+
self.contract, self.plan.import_locus_ids
|
|
710
|
+
)
|
|
711
|
+
if self.plan.to_record() != expected_plan.to_record():
|
|
712
|
+
raise ValueError("plan is not canonical for the supplied contract")
|
|
713
|
+
if type(self.attributions) is not tuple or any(
|
|
714
|
+
type(value) is not ExactParentLocusAttribution
|
|
715
|
+
for value in self.attributions
|
|
716
|
+
):
|
|
717
|
+
raise TypeError("attributions must be an exact tuple")
|
|
718
|
+
if len(self.attributions) != len(self.contract.loci):
|
|
719
|
+
raise ValueError("source evidence must cover every contract locus")
|
|
720
|
+
imported = set(self.plan.import_locus_ids)
|
|
721
|
+
for locus, attribution in zip(
|
|
722
|
+
self.contract.loci, self.attributions, strict=True
|
|
723
|
+
):
|
|
724
|
+
ExactParentLocusAttribution.__post_init__(attribution)
|
|
725
|
+
if (
|
|
726
|
+
attribution.locus_id != locus.locus_id
|
|
727
|
+
or attribution.path_text != locus.path_text
|
|
728
|
+
or attribution.base_value_sha256 != locus.base_value_sha256
|
|
729
|
+
or attribution.donor_value_sha256 != locus.donor_value_sha256
|
|
730
|
+
):
|
|
731
|
+
raise ValueError("source evidence does not match its contract locus")
|
|
732
|
+
expected_source = (
|
|
733
|
+
ExactParentSource.DONOR
|
|
734
|
+
if locus.locus_id in imported
|
|
735
|
+
else ExactParentSource.BASE
|
|
736
|
+
)
|
|
737
|
+
if attribution.source is not expected_source:
|
|
738
|
+
raise ValueError("source evidence contradicts the import plan")
|
|
739
|
+
if (
|
|
740
|
+
typed_json_sha256(_value_at_path(self.configuration, locus.path))
|
|
741
|
+
!= attribution.materialized_value_sha256
|
|
742
|
+
):
|
|
743
|
+
raise ValueError("source evidence does not match the exact child")
|
|
744
|
+
|
|
745
|
+
@property
|
|
746
|
+
def materialized_configuration_sha256(self) -> str:
|
|
747
|
+
return typed_json_sha256(self.configuration)
|
|
748
|
+
|
|
749
|
+
def to_record(self) -> dict[str, object]:
|
|
750
|
+
ExactParentCrossoverMaterialization.__post_init__(self)
|
|
751
|
+
return _materialization_record(
|
|
752
|
+
contract_sha256=self.contract.contract_sha256,
|
|
753
|
+
plan_sha256=self.plan.plan_sha256,
|
|
754
|
+
materialized_configuration_sha256=(self.materialized_configuration_sha256),
|
|
755
|
+
attributions=self.attributions,
|
|
756
|
+
)
|
|
757
|
+
|
|
758
|
+
@property
|
|
759
|
+
def materialization_sha256(self) -> str:
|
|
760
|
+
return _hash_record(_MATERIALIZATION_DOMAIN, self.to_record())
|
|
761
|
+
|
|
762
|
+
@property
|
|
763
|
+
def receipt(self) -> ExactParentCrossoverReceipt:
|
|
764
|
+
return ExactParentCrossoverReceipt(
|
|
765
|
+
max_loci=self.contract.max_loci,
|
|
766
|
+
base_parent_sha256=self.contract.base_parent_sha256,
|
|
767
|
+
donor_parent_sha256=self.contract.donor_parent_sha256,
|
|
768
|
+
contract_sha256=self.contract.contract_sha256,
|
|
769
|
+
plan_sha256=self.plan.plan_sha256,
|
|
770
|
+
import_locus_ids=self.plan.import_locus_ids,
|
|
771
|
+
materialized_configuration_sha256=(self.materialized_configuration_sha256),
|
|
772
|
+
materialization_sha256=self.materialization_sha256,
|
|
773
|
+
attributions=self.attributions,
|
|
774
|
+
)
|
|
775
|
+
|
|
776
|
+
|
|
777
|
+
def materialize_exact_parent_crossover(
|
|
778
|
+
*,
|
|
779
|
+
base: FrozenJsonObject,
|
|
780
|
+
donor: FrozenJsonObject,
|
|
781
|
+
contract: ExactParentCrossoverContract,
|
|
782
|
+
import_locus_ids: tuple[str, ...],
|
|
783
|
+
) -> ExactParentCrossoverMaterialization:
|
|
784
|
+
"""Copy selected exact donor subtrees into the exact base parent."""
|
|
785
|
+
|
|
786
|
+
_validate_parent(base, name="base")
|
|
787
|
+
_validate_parent(donor, name="donor")
|
|
788
|
+
if type(contract) is not ExactParentCrossoverContract:
|
|
789
|
+
raise TypeError("contract must be an exact ExactParentCrossoverContract")
|
|
790
|
+
ExactParentCrossoverContract.__post_init__(contract)
|
|
791
|
+
|
|
792
|
+
# Never trust a detached or reconstructed contract. Re-derive the full
|
|
793
|
+
# exact frontier from the supplied ordered parents before materialization.
|
|
794
|
+
expected_contract = derive_exact_parent_crossover_contract(
|
|
795
|
+
base=base,
|
|
796
|
+
donor=donor,
|
|
797
|
+
max_loci=contract.max_loci,
|
|
798
|
+
)
|
|
799
|
+
if contract.to_record() != expected_contract.to_record():
|
|
800
|
+
raise ValueError("contract does not match the supplied ordered parents")
|
|
801
|
+
|
|
802
|
+
plan = build_exact_parent_import_plan(contract, import_locus_ids)
|
|
803
|
+
imported = set(plan.import_locus_ids)
|
|
804
|
+
child: FrozenJsonValue = base
|
|
805
|
+
attributions: list[ExactParentLocusAttribution] = []
|
|
806
|
+
for locus in contract.loci:
|
|
807
|
+
source = (
|
|
808
|
+
ExactParentSource.DONOR
|
|
809
|
+
if locus.locus_id in imported
|
|
810
|
+
else ExactParentSource.BASE
|
|
811
|
+
)
|
|
812
|
+
source_root = donor if source is ExactParentSource.DONOR else base
|
|
813
|
+
source_value = _value_at_path(source_root, locus.path)
|
|
814
|
+
if source is ExactParentSource.DONOR:
|
|
815
|
+
child = _replace_existing_path(child, locus.path, source_value)
|
|
816
|
+
materialized_value = _value_at_path(child, locus.path)
|
|
817
|
+
attributions.append(
|
|
818
|
+
ExactParentLocusAttribution(
|
|
819
|
+
locus_id=locus.locus_id,
|
|
820
|
+
path_text=locus.path_text,
|
|
821
|
+
source=source,
|
|
822
|
+
base_value_sha256=locus.base_value_sha256,
|
|
823
|
+
donor_value_sha256=locus.donor_value_sha256,
|
|
824
|
+
source_value_sha256=typed_json_sha256(source_value),
|
|
825
|
+
materialized_value_sha256=typed_json_sha256(materialized_value),
|
|
826
|
+
)
|
|
827
|
+
)
|
|
828
|
+
if type(child) is not FrozenJsonObject: # Root imports cannot coexist with
|
|
829
|
+
raise AssertionError("same-root object crossover produced a non-object")
|
|
830
|
+
return ExactParentCrossoverMaterialization(
|
|
831
|
+
configuration=child,
|
|
832
|
+
contract=contract,
|
|
833
|
+
plan=plan,
|
|
834
|
+
attributions=tuple(attributions),
|
|
835
|
+
)
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
def resolve_exact_parent_import_for_target(
|
|
839
|
+
*,
|
|
840
|
+
base: FrozenJsonObject,
|
|
841
|
+
donor: FrozenJsonObject,
|
|
842
|
+
contract: ExactParentCrossoverContract,
|
|
843
|
+
target: FrozenJsonObject,
|
|
844
|
+
) -> tuple[str, ...] | None:
|
|
845
|
+
"""Resolve a known target to its exact donor-import action, if any.
|
|
846
|
+
|
|
847
|
+
Resolution is linear in the bounded locus frontier: each target subtree
|
|
848
|
+
must be typed-equal to exactly its base or donor counterpart. A final
|
|
849
|
+
materialization replay compares the complete target, which also proves
|
|
850
|
+
that all shared/non-locus structure matches. Parent identities are not
|
|
851
|
+
actions in this policy (the import set must remain proper and nonempty), so
|
|
852
|
+
they return ``None`` like every other unrepresentable target.
|
|
853
|
+
"""
|
|
854
|
+
|
|
855
|
+
_validate_parent(base, name="base")
|
|
856
|
+
_validate_parent(donor, name="donor")
|
|
857
|
+
_validate_parent(target, name="target")
|
|
858
|
+
if type(contract) is not ExactParentCrossoverContract:
|
|
859
|
+
raise TypeError("contract must be an exact ExactParentCrossoverContract")
|
|
860
|
+
ExactParentCrossoverContract.__post_init__(contract)
|
|
861
|
+
expected_contract = derive_exact_parent_crossover_contract(
|
|
862
|
+
base=base,
|
|
863
|
+
donor=donor,
|
|
864
|
+
max_loci=contract.max_loci,
|
|
865
|
+
)
|
|
866
|
+
if contract.to_record() != expected_contract.to_record():
|
|
867
|
+
raise ValueError("contract does not match the supplied ordered parents")
|
|
868
|
+
|
|
869
|
+
imported: list[str] = []
|
|
870
|
+
try:
|
|
871
|
+
for locus in contract.loci:
|
|
872
|
+
target_value = _value_at_path(target, locus.path)
|
|
873
|
+
base_value = _value_at_path(base, locus.path)
|
|
874
|
+
donor_value = _value_at_path(donor, locus.path)
|
|
875
|
+
if typed_json_equal(target_value, base_value):
|
|
876
|
+
continue
|
|
877
|
+
if typed_json_equal(target_value, donor_value):
|
|
878
|
+
imported.append(locus.locus_id)
|
|
879
|
+
continue
|
|
880
|
+
return None
|
|
881
|
+
except ValueError:
|
|
882
|
+
# A topology-bearing target can make an otherwise valid parent path
|
|
883
|
+
# absent or non-traversable. Such a target is simply not representable.
|
|
884
|
+
return None
|
|
885
|
+
|
|
886
|
+
import_locus_ids = tuple(imported)
|
|
887
|
+
if not import_locus_ids or len(import_locus_ids) == len(contract.loci):
|
|
888
|
+
return None
|
|
889
|
+
replayed = materialize_exact_parent_crossover(
|
|
890
|
+
base=base,
|
|
891
|
+
donor=donor,
|
|
892
|
+
contract=contract,
|
|
893
|
+
import_locus_ids=import_locus_ids,
|
|
894
|
+
)
|
|
895
|
+
if not typed_json_equal(replayed.configuration, target):
|
|
896
|
+
return None
|
|
897
|
+
return replayed.plan.import_locus_ids
|
|
898
|
+
|
|
899
|
+
|
|
900
|
+
def replay_exact_parent_crossover(
|
|
901
|
+
*,
|
|
902
|
+
base: FrozenJsonObject,
|
|
903
|
+
donor: FrozenJsonObject,
|
|
904
|
+
receipt: ExactParentCrossoverReceipt,
|
|
905
|
+
) -> ExactParentCrossoverMaterialization:
|
|
906
|
+
"""Re-derive, re-materialize, and exactly verify a prior receipt."""
|
|
907
|
+
|
|
908
|
+
_validate_parent(base, name="base")
|
|
909
|
+
_validate_parent(donor, name="donor")
|
|
910
|
+
if type(receipt) is not ExactParentCrossoverReceipt:
|
|
911
|
+
raise TypeError("receipt must be an exact ExactParentCrossoverReceipt")
|
|
912
|
+
ExactParentCrossoverReceipt.__post_init__(receipt)
|
|
913
|
+
contract = derive_exact_parent_crossover_contract(
|
|
914
|
+
base=base,
|
|
915
|
+
donor=donor,
|
|
916
|
+
max_loci=receipt.max_loci,
|
|
917
|
+
)
|
|
918
|
+
if contract.contract_sha256 != receipt.contract_sha256:
|
|
919
|
+
raise ValueError("receipt contract hash does not match the ordered parents")
|
|
920
|
+
replayed = materialize_exact_parent_crossover(
|
|
921
|
+
base=base,
|
|
922
|
+
donor=donor,
|
|
923
|
+
contract=contract,
|
|
924
|
+
import_locus_ids=receipt.import_locus_ids,
|
|
925
|
+
)
|
|
926
|
+
if replayed.receipt.to_record() != receipt.to_record():
|
|
927
|
+
raise ValueError("receipt does not match exact crossover replay")
|
|
928
|
+
return replayed
|
|
929
|
+
|
|
930
|
+
|
|
931
|
+
__all__ = [
|
|
932
|
+
"DEFAULT_MAX_EXACT_PARENT_CROSSOVER_LOCI",
|
|
933
|
+
"MAX_EXACT_PARENT_CROSSOVER_LOCI",
|
|
934
|
+
"MIN_EXACT_PARENT_CROSSOVER_LOCI",
|
|
935
|
+
"ExactParentCrossoverContract",
|
|
936
|
+
"ExactParentCrossoverLocus",
|
|
937
|
+
"ExactParentCrossoverMaterialization",
|
|
938
|
+
"ExactParentCrossoverReceipt",
|
|
939
|
+
"ExactParentImportPlan",
|
|
940
|
+
"ExactParentLocusAttribution",
|
|
941
|
+
"ExactParentSource",
|
|
942
|
+
"build_exact_parent_import_plan",
|
|
943
|
+
"canonical_candidate_path_text",
|
|
944
|
+
"derive_exact_parent_crossover_contract",
|
|
945
|
+
"exact_parent_import_exclusions_sha256",
|
|
946
|
+
"materialize_exact_parent_crossover",
|
|
947
|
+
"replay_exact_parent_crossover",
|
|
948
|
+
"resolve_exact_parent_import_for_target",
|
|
949
|
+
"validate_exact_parent_import_exclusions",
|
|
950
|
+
]
|