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,811 @@
|
|
|
1
|
+
"""Small event-auditable Pareto archive for explicit agentic evolution.
|
|
2
|
+
|
|
3
|
+
The archive is deliberately separate from generation policy. It consumes evaluated
|
|
4
|
+
``EvolutionCandidate`` occurrences, applies explicit admissibility gates, deduplicates
|
|
5
|
+
configurations across the whole run, and maintains one deterministic representative
|
|
6
|
+
for exact objective-vector ties. Every state transition is returned as an immutable
|
|
7
|
+
decision that a runner can emit directly into its trace.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import hashlib
|
|
13
|
+
import json
|
|
14
|
+
from collections.abc import Sequence
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
from enum import Enum
|
|
17
|
+
from numbers import Real
|
|
18
|
+
|
|
19
|
+
from agent_evolve.application.agentic_evolution import EvolutionCandidate
|
|
20
|
+
from agent_evolve.application.outcome_relation import (
|
|
21
|
+
OutcomeRelation,
|
|
22
|
+
OutcomeRelationPolicyBinding,
|
|
23
|
+
objective_pareto_outcome_binding,
|
|
24
|
+
)
|
|
25
|
+
from agent_evolve.core.problem import (
|
|
26
|
+
ObjectiveSpec,
|
|
27
|
+
ProblemContractError,
|
|
28
|
+
normalize_objective_values,
|
|
29
|
+
validate_objective_specs,
|
|
30
|
+
)
|
|
31
|
+
from agent_evolve.core.results import dominates
|
|
32
|
+
from agent_evolve.domain.ids import CandidateId
|
|
33
|
+
from agent_evolve.domain.patch import require_sha256
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
_CANDIDATE_HASH_DOMAIN = b"agent-evolve:pareto-candidate:v1\x00"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class ParetoDecisionAction(str, Enum):
|
|
40
|
+
"""The archive state transition described by one decision."""
|
|
41
|
+
|
|
42
|
+
ADMITTED = "admitted"
|
|
43
|
+
REMOVED = "removed"
|
|
44
|
+
REJECTED = "rejected"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ParetoDecisionReason(str, Enum):
|
|
48
|
+
"""Machine-stable explanations for every archive decision."""
|
|
49
|
+
|
|
50
|
+
ADMITTED_NONDOMINATED = "admitted_nondominated"
|
|
51
|
+
ADMITTED_TIE_BREAK_REPLACEMENT = "admitted_tie_break_replacement"
|
|
52
|
+
REMOVED_DOMINATED = "removed_dominated"
|
|
53
|
+
REMOVED_TIE_BREAK = "removed_tie_break"
|
|
54
|
+
REJECTED_INVALID = "rejected_invalid"
|
|
55
|
+
REJECTED_OPERATOR_NONCOMPLIANT = "rejected_operator_noncompliant"
|
|
56
|
+
REJECTED_EVIDENCE_NONCOMPLIANT = "rejected_evidence_noncompliant"
|
|
57
|
+
REJECTED_OBJECTIVE_CONTRACT = "rejected_objective_contract"
|
|
58
|
+
REJECTED_DUPLICATE_CANDIDATE = "rejected_duplicate_candidate"
|
|
59
|
+
REJECTED_CANDIDATE_ID_CONFLICT = "rejected_candidate_id_conflict"
|
|
60
|
+
REJECTED_DUPLICATE_CONFIGURATION = "rejected_duplicate_configuration"
|
|
61
|
+
REJECTED_DOMINATED = "rejected_dominated"
|
|
62
|
+
REJECTED_OBJECTIVE_TIE = "rejected_objective_tie"
|
|
63
|
+
ADMITTED_RELATION_FRONT = "admitted_relation_front"
|
|
64
|
+
ADMITTED_EQUIVALENCE_TIE_BREAK = "admitted_equivalence_tie_break"
|
|
65
|
+
REMOVED_WORSE_RELATION = "removed_worse_relation"
|
|
66
|
+
REMOVED_EQUIVALENCE_TIE_BREAK = "removed_equivalence_tie_break"
|
|
67
|
+
REJECTED_WORSE_RELATION = "rejected_worse_relation"
|
|
68
|
+
REJECTED_EQUIVALENCE = "rejected_equivalence"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class EvidenceAdmissionPolicy(str, Enum):
|
|
72
|
+
"""Whether model-authored annotation errors can exclude objective evidence."""
|
|
73
|
+
|
|
74
|
+
REQUIRE_COMPLIANT = "require_compliant"
|
|
75
|
+
RECORD_ONLY = "record_only"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _objective_hash_values(candidate: EvolutionCandidate) -> list[list[str]]:
|
|
79
|
+
"""Return a deterministic projection even when objectives fail later checks."""
|
|
80
|
+
|
|
81
|
+
if type(candidate.objectives) is not tuple:
|
|
82
|
+
return [["<invalid-container>", type(candidate.objectives).__qualname__]]
|
|
83
|
+
projected: list[list[str]] = []
|
|
84
|
+
for item in candidate.objectives:
|
|
85
|
+
if type(item) is not tuple or len(item) != 2:
|
|
86
|
+
projected.append(["<invalid-item>", type(item).__qualname__])
|
|
87
|
+
continue
|
|
88
|
+
name, value = item
|
|
89
|
+
name_token = name if type(name) is str else f"<{type(name).__qualname__}>"
|
|
90
|
+
if isinstance(value, Real) and not isinstance(value, bool):
|
|
91
|
+
try:
|
|
92
|
+
value_token = float(value).hex()
|
|
93
|
+
except (OverflowError, TypeError, ValueError):
|
|
94
|
+
value_token = f"<invalid-{type(value).__qualname__}>"
|
|
95
|
+
else:
|
|
96
|
+
value_token = f"<{type(value).__qualname__}>"
|
|
97
|
+
projected.append([name_token, value_token])
|
|
98
|
+
return projected
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def pareto_candidate_hash(candidate: EvolutionCandidate) -> str:
|
|
102
|
+
"""Hash the occurrence and all archive-relevant candidate facts.
|
|
103
|
+
|
|
104
|
+
This is an archive projection hash, not a replacement for ``CandidateId`` or the
|
|
105
|
+
canonical typed-JSON configuration hash. Including both identity and gate facts
|
|
106
|
+
makes accidental reuse of one occurrence ID with different evaluation evidence
|
|
107
|
+
visible in the decision stream.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
if type(candidate) is not EvolutionCandidate:
|
|
111
|
+
raise TypeError("candidate must be an exact EvolutionCandidate")
|
|
112
|
+
EvolutionCandidate.__post_init__(candidate)
|
|
113
|
+
occurrence = candidate.occurrence
|
|
114
|
+
record = {
|
|
115
|
+
"candidate_id": candidate.candidate_id.value,
|
|
116
|
+
"configuration_artifact_hash": occurrence.configuration_artifact_hash,
|
|
117
|
+
"configuration_hash": occurrence.configuration_hash,
|
|
118
|
+
"evidence_compliant": candidate.evidence_compliant,
|
|
119
|
+
"objectives": _objective_hash_values(candidate),
|
|
120
|
+
"operator_compliant": candidate.operator_compliant,
|
|
121
|
+
"operator_invocation_id": (
|
|
122
|
+
None
|
|
123
|
+
if occurrence.operator_invocation_id is None
|
|
124
|
+
else occurrence.operator_invocation_id.value
|
|
125
|
+
),
|
|
126
|
+
"proposal_sequence": occurrence.proposal_sequence,
|
|
127
|
+
"valid": candidate.valid,
|
|
128
|
+
}
|
|
129
|
+
if candidate.detailed_evaluation is not None:
|
|
130
|
+
record["detailed_evaluation_sha256"] = (
|
|
131
|
+
candidate.detailed_evaluation.evidence_sha256
|
|
132
|
+
)
|
|
133
|
+
if candidate.objective_resolution_receipt is not None:
|
|
134
|
+
record["objective_resolution_receipt_sha256"] = (
|
|
135
|
+
candidate.objective_resolution_receipt.receipt_sha256
|
|
136
|
+
)
|
|
137
|
+
encoded = json.dumps(
|
|
138
|
+
record,
|
|
139
|
+
ensure_ascii=True,
|
|
140
|
+
separators=(",", ":"),
|
|
141
|
+
sort_keys=True,
|
|
142
|
+
).encode("utf-8")
|
|
143
|
+
return hashlib.sha256(_CANDIDATE_HASH_DOMAIN + encoded).hexdigest()
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@dataclass(frozen=True, slots=True)
|
|
147
|
+
class ParetoCandidateRef:
|
|
148
|
+
"""Minimal immutable identity used in decisions and trace records."""
|
|
149
|
+
|
|
150
|
+
candidate_id: CandidateId
|
|
151
|
+
candidate_hash: str
|
|
152
|
+
configuration_hash: str
|
|
153
|
+
|
|
154
|
+
def __post_init__(self) -> None:
|
|
155
|
+
if type(self.candidate_id) is not CandidateId:
|
|
156
|
+
raise TypeError("candidate_id must be an exact CandidateId")
|
|
157
|
+
CandidateId.__post_init__(self.candidate_id)
|
|
158
|
+
require_sha256(self.candidate_hash, "candidate_hash")
|
|
159
|
+
require_sha256(self.configuration_hash, "configuration_hash")
|
|
160
|
+
|
|
161
|
+
def to_trace_record(self) -> dict[str, str]:
|
|
162
|
+
"""Return a fresh JSON-safe trace projection."""
|
|
163
|
+
|
|
164
|
+
return {
|
|
165
|
+
"candidate_id": self.candidate_id.value,
|
|
166
|
+
"candidate_hash": self.candidate_hash,
|
|
167
|
+
"configuration_hash": self.configuration_hash,
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _candidate_ref(candidate: EvolutionCandidate) -> ParetoCandidateRef:
|
|
172
|
+
return ParetoCandidateRef(
|
|
173
|
+
candidate_id=candidate.candidate_id,
|
|
174
|
+
candidate_hash=pareto_candidate_hash(candidate),
|
|
175
|
+
configuration_hash=candidate.occurrence.configuration_hash,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _ref_key(reference: ParetoCandidateRef) -> tuple[str, str, str]:
|
|
180
|
+
return (
|
|
181
|
+
reference.configuration_hash,
|
|
182
|
+
reference.candidate_id.value,
|
|
183
|
+
reference.candidate_hash,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@dataclass(frozen=True, slots=True)
|
|
188
|
+
class ArchiveRelationEvidence:
|
|
189
|
+
"""Relation of the considered candidate to one incumbent front member."""
|
|
190
|
+
|
|
191
|
+
incumbent: ParetoCandidateRef
|
|
192
|
+
relation: OutcomeRelation
|
|
193
|
+
|
|
194
|
+
def __post_init__(self) -> None:
|
|
195
|
+
if type(self.incumbent) is not ParetoCandidateRef:
|
|
196
|
+
raise TypeError("incumbent must be an exact ParetoCandidateRef")
|
|
197
|
+
if type(self.relation) is not OutcomeRelation:
|
|
198
|
+
raise TypeError("relation must be an OutcomeRelation")
|
|
199
|
+
|
|
200
|
+
def to_trace_record(self) -> dict[str, object]:
|
|
201
|
+
return {
|
|
202
|
+
"incumbent": self.incumbent.to_trace_record(),
|
|
203
|
+
"candidate_relation": self.relation.value,
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
@dataclass(frozen=True, slots=True)
|
|
208
|
+
class ParetoDecision:
|
|
209
|
+
"""One immutable, self-identifying archive decision."""
|
|
210
|
+
|
|
211
|
+
decision_sequence: int
|
|
212
|
+
consideration_sequence: int
|
|
213
|
+
action: ParetoDecisionAction
|
|
214
|
+
reasons: tuple[ParetoDecisionReason, ...]
|
|
215
|
+
candidate: ParetoCandidateRef
|
|
216
|
+
failure_details: tuple[tuple[ParetoDecisionReason, str], ...] = ()
|
|
217
|
+
dominators: tuple[ParetoCandidateRef, ...] = ()
|
|
218
|
+
removed_candidates: tuple[ParetoCandidateRef, ...] = ()
|
|
219
|
+
tie_with: tuple[ParetoCandidateRef, ...] = ()
|
|
220
|
+
duplicate_of: ParetoCandidateRef | None = None
|
|
221
|
+
caused_by: ParetoCandidateRef | None = None
|
|
222
|
+
front_after: tuple[ParetoCandidateRef, ...] = ()
|
|
223
|
+
outcome_relations: tuple[ArchiveRelationEvidence, ...] = ()
|
|
224
|
+
|
|
225
|
+
def __post_init__(self) -> None:
|
|
226
|
+
if type(self.decision_sequence) is not int or self.decision_sequence <= 0:
|
|
227
|
+
raise ValueError("decision_sequence must be a positive exact integer")
|
|
228
|
+
if (
|
|
229
|
+
type(self.consideration_sequence) is not int
|
|
230
|
+
or self.consideration_sequence <= 0
|
|
231
|
+
):
|
|
232
|
+
raise ValueError("consideration_sequence must be a positive exact integer")
|
|
233
|
+
if type(self.action) is not ParetoDecisionAction:
|
|
234
|
+
raise TypeError("action must be a ParetoDecisionAction")
|
|
235
|
+
if type(self.reasons) is not tuple or not self.reasons or any(
|
|
236
|
+
type(reason) is not ParetoDecisionReason for reason in self.reasons
|
|
237
|
+
):
|
|
238
|
+
raise ValueError("reasons must be a non-empty exact reason tuple")
|
|
239
|
+
if type(self.candidate) is not ParetoCandidateRef:
|
|
240
|
+
raise TypeError("candidate must be a ParetoCandidateRef")
|
|
241
|
+
for name in ("dominators", "removed_candidates", "tie_with", "front_after"):
|
|
242
|
+
references = getattr(self, name)
|
|
243
|
+
if type(references) is not tuple or any(
|
|
244
|
+
type(reference) is not ParetoCandidateRef for reference in references
|
|
245
|
+
):
|
|
246
|
+
raise TypeError(f"{name} must be an exact ParetoCandidateRef tuple")
|
|
247
|
+
if self.duplicate_of is not None and type(
|
|
248
|
+
self.duplicate_of
|
|
249
|
+
) is not ParetoCandidateRef:
|
|
250
|
+
raise TypeError("duplicate_of must be a ParetoCandidateRef or None")
|
|
251
|
+
if self.caused_by is not None and type(self.caused_by) is not ParetoCandidateRef:
|
|
252
|
+
raise TypeError("caused_by must be a ParetoCandidateRef or None")
|
|
253
|
+
if type(self.failure_details) is not tuple:
|
|
254
|
+
raise TypeError("failure_details must be an exact tuple")
|
|
255
|
+
for reason, detail in self.failure_details:
|
|
256
|
+
if type(reason) is not ParetoDecisionReason or type(detail) is not str:
|
|
257
|
+
raise TypeError("failure details must contain exact reason/text pairs")
|
|
258
|
+
if type(self.outcome_relations) is not tuple or any(
|
|
259
|
+
type(item) is not ArchiveRelationEvidence
|
|
260
|
+
for item in self.outcome_relations
|
|
261
|
+
):
|
|
262
|
+
raise TypeError(
|
|
263
|
+
"outcome_relations must contain exact ArchiveRelationEvidence values"
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
def to_trace_record(self) -> dict[str, object]:
|
|
267
|
+
"""Return a fresh JSON-safe event suitable for a runner trace sink."""
|
|
268
|
+
|
|
269
|
+
record = {
|
|
270
|
+
"event_type": "pareto_archive_decision",
|
|
271
|
+
"decision_sequence": self.decision_sequence,
|
|
272
|
+
"consideration_sequence": self.consideration_sequence,
|
|
273
|
+
"action": self.action.value,
|
|
274
|
+
"reasons": [reason.value for reason in self.reasons],
|
|
275
|
+
**self.candidate.to_trace_record(),
|
|
276
|
+
"failure_details": [
|
|
277
|
+
{"reason": reason.value, "detail": detail}
|
|
278
|
+
for reason, detail in self.failure_details
|
|
279
|
+
],
|
|
280
|
+
"dominators": [item.to_trace_record() for item in self.dominators],
|
|
281
|
+
"removed_candidates": [
|
|
282
|
+
item.to_trace_record() for item in self.removed_candidates
|
|
283
|
+
],
|
|
284
|
+
"tie_with": [item.to_trace_record() for item in self.tie_with],
|
|
285
|
+
"duplicate_of": (
|
|
286
|
+
None if self.duplicate_of is None else self.duplicate_of.to_trace_record()
|
|
287
|
+
),
|
|
288
|
+
"caused_by": (
|
|
289
|
+
None if self.caused_by is None else self.caused_by.to_trace_record()
|
|
290
|
+
),
|
|
291
|
+
"front_after": [item.to_trace_record() for item in self.front_after],
|
|
292
|
+
}
|
|
293
|
+
if self.outcome_relations:
|
|
294
|
+
record["outcome_relations"] = [
|
|
295
|
+
item.to_trace_record() for item in self.outcome_relations
|
|
296
|
+
]
|
|
297
|
+
return record
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
@dataclass(frozen=True, slots=True)
|
|
301
|
+
class ParetoArchiveSnapshot:
|
|
302
|
+
"""Immutable view of archive state and its complete decision ledger."""
|
|
303
|
+
|
|
304
|
+
objectives: tuple[ObjectiveSpec, ...]
|
|
305
|
+
front_candidates: tuple[EvolutionCandidate, ...]
|
|
306
|
+
front_references: tuple[ParetoCandidateRef, ...]
|
|
307
|
+
decisions: tuple[ParetoDecision, ...]
|
|
308
|
+
consideration_count: int
|
|
309
|
+
eligible_configuration_count: int
|
|
310
|
+
evidence_admission_policy: EvidenceAdmissionPolicy
|
|
311
|
+
outcome_relation_policy: tuple[str, int, str]
|
|
312
|
+
objective_pareto_relation: bool
|
|
313
|
+
|
|
314
|
+
def to_trace_record(self) -> dict[str, object]:
|
|
315
|
+
"""Return aggregate JSON-safe evidence without copying full configurations."""
|
|
316
|
+
|
|
317
|
+
record = {
|
|
318
|
+
"event_type": "pareto_archive_snapshot",
|
|
319
|
+
"objectives": [
|
|
320
|
+
{"name": objective.name, "goal": objective.goal}
|
|
321
|
+
for objective in self.objectives
|
|
322
|
+
],
|
|
323
|
+
"front": [item.to_trace_record() for item in self.front_references],
|
|
324
|
+
"front_size": len(self.front_references),
|
|
325
|
+
"consideration_count": self.consideration_count,
|
|
326
|
+
"eligible_configuration_count": self.eligible_configuration_count,
|
|
327
|
+
"decision_count": len(self.decisions),
|
|
328
|
+
"evidence_admission_policy": self.evidence_admission_policy.value,
|
|
329
|
+
}
|
|
330
|
+
if not self.objective_pareto_relation:
|
|
331
|
+
record["outcome_relation_policy"] = {
|
|
332
|
+
"policy_id": self.outcome_relation_policy[0],
|
|
333
|
+
"policy_version": self.outcome_relation_policy[1],
|
|
334
|
+
"definition_sha256": self.outcome_relation_policy[2],
|
|
335
|
+
}
|
|
336
|
+
return record
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
class ParetoArchive:
|
|
340
|
+
"""Admissibility-gated, deterministic, event-auditable Pareto archive."""
|
|
341
|
+
|
|
342
|
+
def __init__(
|
|
343
|
+
self,
|
|
344
|
+
objectives: Sequence[ObjectiveSpec],
|
|
345
|
+
*,
|
|
346
|
+
evidence_admission_policy: EvidenceAdmissionPolicy = (
|
|
347
|
+
EvidenceAdmissionPolicy.REQUIRE_COMPLIANT
|
|
348
|
+
),
|
|
349
|
+
outcome_relation_binding: OutcomeRelationPolicyBinding | None = None,
|
|
350
|
+
) -> None:
|
|
351
|
+
objective_tuple = tuple(objectives)
|
|
352
|
+
validate_objective_specs(objective_tuple)
|
|
353
|
+
if type(evidence_admission_policy) is not EvidenceAdmissionPolicy:
|
|
354
|
+
raise TypeError(
|
|
355
|
+
"evidence_admission_policy must be an EvidenceAdmissionPolicy"
|
|
356
|
+
)
|
|
357
|
+
default_relation = objective_pareto_outcome_binding(objective_tuple)
|
|
358
|
+
relation = (
|
|
359
|
+
default_relation
|
|
360
|
+
if outcome_relation_binding is None
|
|
361
|
+
else outcome_relation_binding
|
|
362
|
+
)
|
|
363
|
+
if type(relation) is not OutcomeRelationPolicyBinding:
|
|
364
|
+
raise TypeError(
|
|
365
|
+
"outcome_relation_binding must be an OutcomeRelationPolicyBinding"
|
|
366
|
+
)
|
|
367
|
+
OutcomeRelationPolicyBinding.__post_init__(relation)
|
|
368
|
+
self._objectives = objective_tuple
|
|
369
|
+
self._evidence_admission_policy = evidence_admission_policy
|
|
370
|
+
self.outcome_relation_binding = relation
|
|
371
|
+
self._objective_pareto_relation = relation.identity == default_relation.identity
|
|
372
|
+
self._front: dict[str, EvolutionCandidate] = {}
|
|
373
|
+
self._front_objectives: dict[str, dict[str, float]] = {}
|
|
374
|
+
self._observed_ids: dict[str, ParetoCandidateRef] = {}
|
|
375
|
+
self._seen_configurations: dict[str, ParetoCandidateRef] = {}
|
|
376
|
+
self._decisions: list[ParetoDecision] = []
|
|
377
|
+
self._consideration_count = 0
|
|
378
|
+
|
|
379
|
+
@property
|
|
380
|
+
def objectives(self) -> tuple[ObjectiveSpec, ...]:
|
|
381
|
+
return self._objectives
|
|
382
|
+
|
|
383
|
+
@property
|
|
384
|
+
def front(self) -> tuple[EvolutionCandidate, ...]:
|
|
385
|
+
return self._ordered_front()[0]
|
|
386
|
+
|
|
387
|
+
@property
|
|
388
|
+
def decisions(self) -> tuple[ParetoDecision, ...]:
|
|
389
|
+
return tuple(self._decisions)
|
|
390
|
+
|
|
391
|
+
def __len__(self) -> int:
|
|
392
|
+
return len(self._front)
|
|
393
|
+
|
|
394
|
+
def _ordered_front(
|
|
395
|
+
self,
|
|
396
|
+
) -> tuple[tuple[EvolutionCandidate, ...], tuple[ParetoCandidateRef, ...]]:
|
|
397
|
+
pairs = [
|
|
398
|
+
(candidate, _candidate_ref(candidate)) for candidate in self._front.values()
|
|
399
|
+
]
|
|
400
|
+
pairs.sort(key=lambda pair: _ref_key(pair[1]))
|
|
401
|
+
return (
|
|
402
|
+
tuple(candidate for candidate, _ in pairs),
|
|
403
|
+
tuple(reference for _, reference in pairs),
|
|
404
|
+
)
|
|
405
|
+
|
|
406
|
+
def _append_decision(
|
|
407
|
+
self,
|
|
408
|
+
*,
|
|
409
|
+
action: ParetoDecisionAction,
|
|
410
|
+
reasons: tuple[ParetoDecisionReason, ...],
|
|
411
|
+
candidate: ParetoCandidateRef,
|
|
412
|
+
failure_details: tuple[tuple[ParetoDecisionReason, str], ...] = (),
|
|
413
|
+
dominators: tuple[ParetoCandidateRef, ...] = (),
|
|
414
|
+
removed_candidates: tuple[ParetoCandidateRef, ...] = (),
|
|
415
|
+
tie_with: tuple[ParetoCandidateRef, ...] = (),
|
|
416
|
+
duplicate_of: ParetoCandidateRef | None = None,
|
|
417
|
+
caused_by: ParetoCandidateRef | None = None,
|
|
418
|
+
outcome_relations: tuple[ArchiveRelationEvidence, ...] = (),
|
|
419
|
+
) -> ParetoDecision:
|
|
420
|
+
front_after = self._ordered_front()[1]
|
|
421
|
+
decision = ParetoDecision(
|
|
422
|
+
decision_sequence=len(self._decisions) + 1,
|
|
423
|
+
consideration_sequence=self._consideration_count,
|
|
424
|
+
action=action,
|
|
425
|
+
reasons=reasons,
|
|
426
|
+
candidate=candidate,
|
|
427
|
+
failure_details=failure_details,
|
|
428
|
+
dominators=tuple(sorted(dominators, key=_ref_key)),
|
|
429
|
+
removed_candidates=tuple(sorted(removed_candidates, key=_ref_key)),
|
|
430
|
+
tie_with=tuple(sorted(tie_with, key=_ref_key)),
|
|
431
|
+
duplicate_of=duplicate_of,
|
|
432
|
+
caused_by=caused_by,
|
|
433
|
+
front_after=front_after,
|
|
434
|
+
outcome_relations=outcome_relations,
|
|
435
|
+
)
|
|
436
|
+
self._decisions.append(decision)
|
|
437
|
+
return decision
|
|
438
|
+
|
|
439
|
+
@staticmethod
|
|
440
|
+
def _failure_detail(message: str | None, fallback: str) -> str:
|
|
441
|
+
if type(message) is str and message.strip():
|
|
442
|
+
return message
|
|
443
|
+
return fallback
|
|
444
|
+
|
|
445
|
+
def _normalize_candidate_objectives(
|
|
446
|
+
self,
|
|
447
|
+
candidate: EvolutionCandidate,
|
|
448
|
+
) -> dict[str, float]:
|
|
449
|
+
if type(candidate.objectives) is not tuple:
|
|
450
|
+
raise ProblemContractError("candidate objectives must be an exact tuple")
|
|
451
|
+
raw: dict[str, object] = {}
|
|
452
|
+
for item in candidate.objectives:
|
|
453
|
+
if type(item) is not tuple or len(item) != 2:
|
|
454
|
+
raise ProblemContractError(
|
|
455
|
+
"candidate objectives must contain exact (name, value) tuples"
|
|
456
|
+
)
|
|
457
|
+
name, value = item
|
|
458
|
+
if type(name) is not str:
|
|
459
|
+
raise ProblemContractError("candidate objective names must be strings")
|
|
460
|
+
if name in raw:
|
|
461
|
+
raise ProblemContractError(f"duplicate candidate objective {name!r}")
|
|
462
|
+
raw[name] = value
|
|
463
|
+
return normalize_objective_values(raw, self._objectives)
|
|
464
|
+
|
|
465
|
+
def _consider_by_outcome_relation(
|
|
466
|
+
self,
|
|
467
|
+
candidate: EvolutionCandidate,
|
|
468
|
+
reference: ParetoCandidateRef,
|
|
469
|
+
objective_map: dict[str, float],
|
|
470
|
+
front_entries: list[
|
|
471
|
+
tuple[EvolutionCandidate, ParetoCandidateRef, dict[str, float]]
|
|
472
|
+
],
|
|
473
|
+
*,
|
|
474
|
+
start: int,
|
|
475
|
+
) -> tuple[ParetoDecision, ...]:
|
|
476
|
+
detailed = candidate.detailed_evaluation
|
|
477
|
+
if detailed is None:
|
|
478
|
+
raise ProblemContractError(
|
|
479
|
+
"custom outcome relation requires candidate detailed evidence"
|
|
480
|
+
)
|
|
481
|
+
relations: list[
|
|
482
|
+
tuple[EvolutionCandidate, ParetoCandidateRef, OutcomeRelation]
|
|
483
|
+
] = []
|
|
484
|
+
for incumbent, incumbent_ref, _ in sorted(
|
|
485
|
+
front_entries,
|
|
486
|
+
key=lambda entry: _ref_key(entry[1]),
|
|
487
|
+
):
|
|
488
|
+
incumbent_detailed = incumbent.detailed_evaluation
|
|
489
|
+
if incumbent_detailed is None:
|
|
490
|
+
raise RuntimeError(
|
|
491
|
+
"custom-relation archive contains evidence-free incumbent"
|
|
492
|
+
)
|
|
493
|
+
relations.append(
|
|
494
|
+
(
|
|
495
|
+
incumbent,
|
|
496
|
+
incumbent_ref,
|
|
497
|
+
self.outcome_relation_binding.relate(
|
|
498
|
+
detailed,
|
|
499
|
+
incumbent_detailed,
|
|
500
|
+
),
|
|
501
|
+
)
|
|
502
|
+
)
|
|
503
|
+
relation_evidence = tuple(
|
|
504
|
+
ArchiveRelationEvidence(incumbent_ref, relation)
|
|
505
|
+
for _, incumbent_ref, relation in relations
|
|
506
|
+
)
|
|
507
|
+
worse = tuple(
|
|
508
|
+
incumbent_ref
|
|
509
|
+
for _, incumbent_ref, relation in relations
|
|
510
|
+
if relation is OutcomeRelation.WORSE
|
|
511
|
+
)
|
|
512
|
+
if worse:
|
|
513
|
+
self._append_decision(
|
|
514
|
+
action=ParetoDecisionAction.REJECTED,
|
|
515
|
+
reasons=(ParetoDecisionReason.REJECTED_WORSE_RELATION,),
|
|
516
|
+
candidate=reference,
|
|
517
|
+
outcome_relations=relation_evidence,
|
|
518
|
+
)
|
|
519
|
+
return tuple(self._decisions[start:])
|
|
520
|
+
|
|
521
|
+
equivalent = tuple(
|
|
522
|
+
incumbent_ref
|
|
523
|
+
for _, incumbent_ref, relation in relations
|
|
524
|
+
if relation is OutcomeRelation.EQUIVALENT
|
|
525
|
+
)
|
|
526
|
+
if equivalent and min((reference, *equivalent), key=_ref_key) is not reference:
|
|
527
|
+
self._append_decision(
|
|
528
|
+
action=ParetoDecisionAction.REJECTED,
|
|
529
|
+
reasons=(ParetoDecisionReason.REJECTED_EQUIVALENCE,),
|
|
530
|
+
candidate=reference,
|
|
531
|
+
tie_with=equivalent,
|
|
532
|
+
outcome_relations=relation_evidence,
|
|
533
|
+
)
|
|
534
|
+
return tuple(self._decisions[start:])
|
|
535
|
+
|
|
536
|
+
better = tuple(
|
|
537
|
+
incumbent_ref
|
|
538
|
+
for _, incumbent_ref, relation in relations
|
|
539
|
+
if relation is OutcomeRelation.BETTER
|
|
540
|
+
)
|
|
541
|
+
removed = tuple(
|
|
542
|
+
sorted(
|
|
543
|
+
{
|
|
544
|
+
item.candidate_id.value: item
|
|
545
|
+
for item in (*equivalent, *better)
|
|
546
|
+
}.values(),
|
|
547
|
+
key=_ref_key,
|
|
548
|
+
)
|
|
549
|
+
)
|
|
550
|
+
equivalent_ids = {item.candidate_id.value for item in equivalent}
|
|
551
|
+
for item in removed:
|
|
552
|
+
del self._front[item.candidate_id.value]
|
|
553
|
+
del self._front_objectives[item.candidate_id.value]
|
|
554
|
+
self._front[candidate.candidate_id.value] = candidate
|
|
555
|
+
self._front_objectives[candidate.candidate_id.value] = objective_map
|
|
556
|
+
|
|
557
|
+
self._append_decision(
|
|
558
|
+
action=ParetoDecisionAction.ADMITTED,
|
|
559
|
+
reasons=(
|
|
560
|
+
ParetoDecisionReason.ADMITTED_EQUIVALENCE_TIE_BREAK
|
|
561
|
+
if equivalent
|
|
562
|
+
else ParetoDecisionReason.ADMITTED_RELATION_FRONT
|
|
563
|
+
,),
|
|
564
|
+
candidate=reference,
|
|
565
|
+
removed_candidates=removed,
|
|
566
|
+
tie_with=equivalent,
|
|
567
|
+
outcome_relations=relation_evidence,
|
|
568
|
+
)
|
|
569
|
+
for item in removed:
|
|
570
|
+
self._append_decision(
|
|
571
|
+
action=ParetoDecisionAction.REMOVED,
|
|
572
|
+
reasons=(
|
|
573
|
+
ParetoDecisionReason.REMOVED_EQUIVALENCE_TIE_BREAK
|
|
574
|
+
if item.candidate_id.value in equivalent_ids
|
|
575
|
+
else ParetoDecisionReason.REMOVED_WORSE_RELATION
|
|
576
|
+
,),
|
|
577
|
+
candidate=item,
|
|
578
|
+
caused_by=reference,
|
|
579
|
+
)
|
|
580
|
+
return tuple(self._decisions[start:])
|
|
581
|
+
|
|
582
|
+
def consider(self, candidate: EvolutionCandidate) -> tuple[ParetoDecision, ...]:
|
|
583
|
+
"""Consider one candidate and return every resulting atomic decision.
|
|
584
|
+
|
|
585
|
+
An admission that evicts two incumbents returns three decisions: one admission
|
|
586
|
+
naming both removals, followed by one explicit removal decision per incumbent.
|
|
587
|
+
Rejections never mutate the Pareto front. Only gate-passing candidates consume
|
|
588
|
+
configuration-deduplication identities.
|
|
589
|
+
"""
|
|
590
|
+
|
|
591
|
+
reference = _candidate_ref(candidate)
|
|
592
|
+
self._consideration_count += 1
|
|
593
|
+
start = len(self._decisions)
|
|
594
|
+
|
|
595
|
+
previous_id = self._observed_ids.get(candidate.candidate_id.value)
|
|
596
|
+
if previous_id is not None:
|
|
597
|
+
reason = (
|
|
598
|
+
ParetoDecisionReason.REJECTED_DUPLICATE_CANDIDATE
|
|
599
|
+
if previous_id.candidate_hash == reference.candidate_hash
|
|
600
|
+
else ParetoDecisionReason.REJECTED_CANDIDATE_ID_CONFLICT
|
|
601
|
+
)
|
|
602
|
+
self._append_decision(
|
|
603
|
+
action=ParetoDecisionAction.REJECTED,
|
|
604
|
+
reasons=(reason,),
|
|
605
|
+
candidate=reference,
|
|
606
|
+
duplicate_of=previous_id,
|
|
607
|
+
)
|
|
608
|
+
return tuple(self._decisions[start:])
|
|
609
|
+
self._observed_ids[candidate.candidate_id.value] = reference
|
|
610
|
+
|
|
611
|
+
gate_reasons: list[ParetoDecisionReason] = []
|
|
612
|
+
failure_details: list[tuple[ParetoDecisionReason, str]] = []
|
|
613
|
+
if not candidate.valid:
|
|
614
|
+
reason = ParetoDecisionReason.REJECTED_INVALID
|
|
615
|
+
gate_reasons.append(reason)
|
|
616
|
+
failure_details.append(
|
|
617
|
+
(
|
|
618
|
+
reason,
|
|
619
|
+
self._failure_detail(
|
|
620
|
+
candidate.failure_message,
|
|
621
|
+
"candidate.valid is False",
|
|
622
|
+
),
|
|
623
|
+
)
|
|
624
|
+
)
|
|
625
|
+
if not candidate.operator_compliant:
|
|
626
|
+
reason = ParetoDecisionReason.REJECTED_OPERATOR_NONCOMPLIANT
|
|
627
|
+
gate_reasons.append(reason)
|
|
628
|
+
failure_details.append(
|
|
629
|
+
(
|
|
630
|
+
reason,
|
|
631
|
+
self._failure_detail(
|
|
632
|
+
candidate.operator_failure,
|
|
633
|
+
"candidate.operator_compliant is False",
|
|
634
|
+
),
|
|
635
|
+
)
|
|
636
|
+
)
|
|
637
|
+
if (
|
|
638
|
+
self._evidence_admission_policy
|
|
639
|
+
is EvidenceAdmissionPolicy.REQUIRE_COMPLIANT
|
|
640
|
+
and not candidate.evidence_compliant
|
|
641
|
+
):
|
|
642
|
+
reason = ParetoDecisionReason.REJECTED_EVIDENCE_NONCOMPLIANT
|
|
643
|
+
gate_reasons.append(reason)
|
|
644
|
+
failure_details.append(
|
|
645
|
+
(
|
|
646
|
+
reason,
|
|
647
|
+
self._failure_detail(
|
|
648
|
+
candidate.evidence_failure,
|
|
649
|
+
"candidate.evidence_compliant is False",
|
|
650
|
+
),
|
|
651
|
+
)
|
|
652
|
+
)
|
|
653
|
+
if gate_reasons:
|
|
654
|
+
self._append_decision(
|
|
655
|
+
action=ParetoDecisionAction.REJECTED,
|
|
656
|
+
reasons=tuple(gate_reasons),
|
|
657
|
+
candidate=reference,
|
|
658
|
+
failure_details=tuple(failure_details),
|
|
659
|
+
)
|
|
660
|
+
return tuple(self._decisions[start:])
|
|
661
|
+
|
|
662
|
+
try:
|
|
663
|
+
objective_map = self._normalize_candidate_objectives(candidate)
|
|
664
|
+
except (OverflowError, ProblemContractError, TypeError, ValueError) as exc:
|
|
665
|
+
reason = ParetoDecisionReason.REJECTED_OBJECTIVE_CONTRACT
|
|
666
|
+
self._append_decision(
|
|
667
|
+
action=ParetoDecisionAction.REJECTED,
|
|
668
|
+
reasons=(reason,),
|
|
669
|
+
candidate=reference,
|
|
670
|
+
failure_details=((reason, str(exc)),),
|
|
671
|
+
)
|
|
672
|
+
return tuple(self._decisions[start:])
|
|
673
|
+
|
|
674
|
+
duplicate = self._seen_configurations.get(reference.configuration_hash)
|
|
675
|
+
if duplicate is not None:
|
|
676
|
+
self._append_decision(
|
|
677
|
+
action=ParetoDecisionAction.REJECTED,
|
|
678
|
+
reasons=(
|
|
679
|
+
ParetoDecisionReason.REJECTED_DUPLICATE_CONFIGURATION,
|
|
680
|
+
),
|
|
681
|
+
candidate=reference,
|
|
682
|
+
duplicate_of=duplicate,
|
|
683
|
+
)
|
|
684
|
+
return tuple(self._decisions[start:])
|
|
685
|
+
self._seen_configurations[reference.configuration_hash] = reference
|
|
686
|
+
|
|
687
|
+
front_entries = [
|
|
688
|
+
(
|
|
689
|
+
incumbent,
|
|
690
|
+
_candidate_ref(incumbent),
|
|
691
|
+
self._front_objectives[incumbent.candidate_id.value],
|
|
692
|
+
)
|
|
693
|
+
for incumbent in self._front.values()
|
|
694
|
+
]
|
|
695
|
+
if not self._objective_pareto_relation:
|
|
696
|
+
return self._consider_by_outcome_relation(
|
|
697
|
+
candidate,
|
|
698
|
+
reference,
|
|
699
|
+
objective_map,
|
|
700
|
+
front_entries,
|
|
701
|
+
start=start,
|
|
702
|
+
)
|
|
703
|
+
dominators = tuple(
|
|
704
|
+
incumbent_ref
|
|
705
|
+
for _, incumbent_ref, incumbent_objectives in front_entries
|
|
706
|
+
if dominates(incumbent_objectives, objective_map, self._objectives)
|
|
707
|
+
)
|
|
708
|
+
if dominators:
|
|
709
|
+
self._append_decision(
|
|
710
|
+
action=ParetoDecisionAction.REJECTED,
|
|
711
|
+
reasons=(ParetoDecisionReason.REJECTED_DOMINATED,),
|
|
712
|
+
candidate=reference,
|
|
713
|
+
dominators=dominators,
|
|
714
|
+
)
|
|
715
|
+
return tuple(self._decisions[start:])
|
|
716
|
+
|
|
717
|
+
objective_tuple = tuple(objective_map[spec.name] for spec in self._objectives)
|
|
718
|
+
tied = tuple(
|
|
719
|
+
incumbent_ref
|
|
720
|
+
for _, incumbent_ref, incumbent_objectives in front_entries
|
|
721
|
+
if tuple(
|
|
722
|
+
incumbent_objectives[spec.name] for spec in self._objectives
|
|
723
|
+
)
|
|
724
|
+
== objective_tuple
|
|
725
|
+
)
|
|
726
|
+
if tied and min((reference, *tied), key=_ref_key) is not reference:
|
|
727
|
+
self._append_decision(
|
|
728
|
+
action=ParetoDecisionAction.REJECTED,
|
|
729
|
+
reasons=(ParetoDecisionReason.REJECTED_OBJECTIVE_TIE,),
|
|
730
|
+
candidate=reference,
|
|
731
|
+
tie_with=tied,
|
|
732
|
+
)
|
|
733
|
+
return tuple(self._decisions[start:])
|
|
734
|
+
|
|
735
|
+
dominated = tuple(
|
|
736
|
+
incumbent_ref
|
|
737
|
+
for _, incumbent_ref, incumbent_objectives in front_entries
|
|
738
|
+
if dominates(objective_map, incumbent_objectives, self._objectives)
|
|
739
|
+
)
|
|
740
|
+
tied_ids = {item.candidate_id.value for item in tied}
|
|
741
|
+
dominated_ids = {item.candidate_id.value for item in dominated}
|
|
742
|
+
removed = tuple(
|
|
743
|
+
sorted(
|
|
744
|
+
{
|
|
745
|
+
item.candidate_id.value: item
|
|
746
|
+
for item in (*tied, *dominated)
|
|
747
|
+
}.values(),
|
|
748
|
+
key=_ref_key,
|
|
749
|
+
)
|
|
750
|
+
)
|
|
751
|
+
for item in removed:
|
|
752
|
+
del self._front[item.candidate_id.value]
|
|
753
|
+
del self._front_objectives[item.candidate_id.value]
|
|
754
|
+
self._front[candidate.candidate_id.value] = candidate
|
|
755
|
+
self._front_objectives[candidate.candidate_id.value] = objective_map
|
|
756
|
+
|
|
757
|
+
admission_reason = (
|
|
758
|
+
ParetoDecisionReason.ADMITTED_TIE_BREAK_REPLACEMENT
|
|
759
|
+
if tied
|
|
760
|
+
else ParetoDecisionReason.ADMITTED_NONDOMINATED
|
|
761
|
+
)
|
|
762
|
+
self._append_decision(
|
|
763
|
+
action=ParetoDecisionAction.ADMITTED,
|
|
764
|
+
reasons=(admission_reason,),
|
|
765
|
+
candidate=reference,
|
|
766
|
+
removed_candidates=removed,
|
|
767
|
+
tie_with=tied,
|
|
768
|
+
)
|
|
769
|
+
for item in removed:
|
|
770
|
+
removal_reason = (
|
|
771
|
+
ParetoDecisionReason.REMOVED_TIE_BREAK
|
|
772
|
+
if item.candidate_id.value in tied_ids
|
|
773
|
+
else ParetoDecisionReason.REMOVED_DOMINATED
|
|
774
|
+
)
|
|
775
|
+
if item.candidate_id.value not in tied_ids | dominated_ids:
|
|
776
|
+
raise AssertionError("archive removal lacks a deterministic cause")
|
|
777
|
+
self._append_decision(
|
|
778
|
+
action=ParetoDecisionAction.REMOVED,
|
|
779
|
+
reasons=(removal_reason,),
|
|
780
|
+
candidate=item,
|
|
781
|
+
caused_by=reference,
|
|
782
|
+
)
|
|
783
|
+
return tuple(self._decisions[start:])
|
|
784
|
+
|
|
785
|
+
def snapshot(self) -> ParetoArchiveSnapshot:
|
|
786
|
+
"""Return an immutable point-in-time view of state and all decisions."""
|
|
787
|
+
|
|
788
|
+
candidates, references = self._ordered_front()
|
|
789
|
+
return ParetoArchiveSnapshot(
|
|
790
|
+
objectives=self._objectives,
|
|
791
|
+
front_candidates=candidates,
|
|
792
|
+
front_references=references,
|
|
793
|
+
decisions=tuple(self._decisions),
|
|
794
|
+
consideration_count=self._consideration_count,
|
|
795
|
+
eligible_configuration_count=len(self._seen_configurations),
|
|
796
|
+
evidence_admission_policy=self._evidence_admission_policy,
|
|
797
|
+
outcome_relation_policy=self.outcome_relation_binding.identity,
|
|
798
|
+
objective_pareto_relation=self._objective_pareto_relation,
|
|
799
|
+
)
|
|
800
|
+
|
|
801
|
+
|
|
802
|
+
__all__ = [
|
|
803
|
+
"EvidenceAdmissionPolicy",
|
|
804
|
+
"ParetoArchive",
|
|
805
|
+
"ParetoArchiveSnapshot",
|
|
806
|
+
"ParetoCandidateRef",
|
|
807
|
+
"ParetoDecision",
|
|
808
|
+
"ParetoDecisionAction",
|
|
809
|
+
"ParetoDecisionReason",
|
|
810
|
+
"pareto_candidate_hash",
|
|
811
|
+
]
|