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,954 @@
|
|
|
1
|
+
"""Outcome-blind composition of heterogeneous action consequence scores.
|
|
2
|
+
|
|
3
|
+
The optimizer must not silently treat one fallible consequence estimator as
|
|
4
|
+
ground truth. This module gives the application core a workload-neutral seam
|
|
5
|
+
for composing multiple pre-evaluation score authorities:
|
|
6
|
+
|
|
7
|
+
* every scorer authenticates the exact residual request and sealed proposal
|
|
8
|
+
universe that it inspected;
|
|
9
|
+
* scorers may be learned models, calibrated proposer forecasts, numerical
|
|
10
|
+
acquisitions, or deterministic audit policies;
|
|
11
|
+
* the core allocates an explicit quota to each scorer and de-duplicates exact
|
|
12
|
+
materialized phenotypes while walking that scorer's ranking; and
|
|
13
|
+
* any evaluator capacity not nominated by the portfolio remains available to
|
|
14
|
+
the downstream empirical broker.
|
|
15
|
+
|
|
16
|
+
Scores are intentionally opaque. Workload adapters own feature projection and
|
|
17
|
+
model fitting; this core owns only information-boundary validation, identity,
|
|
18
|
+
quota composition, and durable evidence. No current candidate outcome is
|
|
19
|
+
available at this boundary.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import asyncio
|
|
25
|
+
import hashlib
|
|
26
|
+
import json
|
|
27
|
+
import math
|
|
28
|
+
import re
|
|
29
|
+
from dataclasses import dataclass, field
|
|
30
|
+
from typing import ClassVar, Protocol, runtime_checkable
|
|
31
|
+
|
|
32
|
+
from agent_evolve.application.materialized_action_broker import (
|
|
33
|
+
MaterializedActionAllocationRequirement,
|
|
34
|
+
)
|
|
35
|
+
from agent_evolve.application.residual_portfolio_evolution import (
|
|
36
|
+
MaterializedActionProposalBatch,
|
|
37
|
+
ResidualPortfolioDecisionRequest,
|
|
38
|
+
)
|
|
39
|
+
from agent_evolve.domain.patch import require_sha256
|
|
40
|
+
from agent_evolve.domain.typed_json import freeze_json
|
|
41
|
+
from agent_evolve.ports.hard_feasibility import (
|
|
42
|
+
HardFeasibilityDecision,
|
|
43
|
+
HardFeasibilityPort,
|
|
44
|
+
HardFeasibilityRequest,
|
|
45
|
+
HardFeasibilityVerdict,
|
|
46
|
+
assess_hard_feasibility,
|
|
47
|
+
hard_feasibility_decision_batch_sha256,
|
|
48
|
+
validate_hard_feasibility_port,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
PREQUENTIAL_SCORE_PORTFOLIO_POLICY_ID = (
|
|
53
|
+
"prequential_quota_score_portfolio_allocator"
|
|
54
|
+
)
|
|
55
|
+
PREQUENTIAL_SCORE_PORTFOLIO_POLICY_VERSION = 1
|
|
56
|
+
PREQUENTIAL_SCORE_PORTFOLIO_POLICY_DEFINITION_SHA256 = hashlib.sha256(
|
|
57
|
+
b"agent-evolve:prequential-quota-score-portfolio:v1;"
|
|
58
|
+
b"input=prior-cutoff-request+complete-sealed-proposal-union;"
|
|
59
|
+
b"score-semantics=opaque-injected-authorities;"
|
|
60
|
+
b"composition=canonical-round-robin-explicit-quota;"
|
|
61
|
+
b"within-authority=descending-finite-score+action-sha256-tie-break;"
|
|
62
|
+
b"collision=skip-exact-materialized-phenotype-and-continue;"
|
|
63
|
+
b"unreserved-capacity=downstream-empirical-broker;"
|
|
64
|
+
b"candidate-outcomes=false;async=true;"
|
|
65
|
+
b"workload-model-provider-branches=false"
|
|
66
|
+
).hexdigest()
|
|
67
|
+
|
|
68
|
+
_TOKEN = re.compile(r"^[a-z][a-z0-9_.:-]{0,255}$")
|
|
69
|
+
_SCORE_BATCH_DOMAIN = b"agent-evolve:materialized-action-score-batch:v1\x00"
|
|
70
|
+
_RELIABILITY_EVIDENCE_DOMAIN = (
|
|
71
|
+
b"agent-evolve:materialized-action-score-reliability:v1\x00"
|
|
72
|
+
)
|
|
73
|
+
_ADAPTIVE_POLICY_DOMAIN = (
|
|
74
|
+
b"agent-evolve:reliability-adaptive-score-portfolio:v1\x00"
|
|
75
|
+
)
|
|
76
|
+
RELIABILITY_ADAPTIVE_SCORE_PORTFOLIO_POLICY_ID = (
|
|
77
|
+
"reliability_adaptive_score_portfolio_allocator"
|
|
78
|
+
)
|
|
79
|
+
RELIABILITY_ADAPTIVE_SCORE_PORTFOLIO_POLICY_VERSION = 2
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _canonical_json(value: object) -> bytes:
|
|
83
|
+
return json.dumps(
|
|
84
|
+
value,
|
|
85
|
+
allow_nan=False,
|
|
86
|
+
ensure_ascii=True,
|
|
87
|
+
separators=(",", ":"),
|
|
88
|
+
sort_keys=True,
|
|
89
|
+
).encode("ascii", errors="strict")
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _hash(domain: bytes, value: object) -> str:
|
|
93
|
+
return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _require_token(value: str, *, name: str) -> None:
|
|
97
|
+
if type(value) is not str or _TOKEN.fullmatch(value) is None:
|
|
98
|
+
raise ValueError(f"{name} must use the closed token grammar")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _scorer_identity(
|
|
102
|
+
scorer: "MaterializedActionScorePort",
|
|
103
|
+
) -> tuple[str, int, str]:
|
|
104
|
+
if not isinstance(scorer, MaterializedActionScorePort):
|
|
105
|
+
raise TypeError("scorer must implement MaterializedActionScorePort")
|
|
106
|
+
identity = (
|
|
107
|
+
getattr(scorer, "scorer_id", None),
|
|
108
|
+
getattr(scorer, "scorer_version", None),
|
|
109
|
+
getattr(scorer, "definition_sha256", None),
|
|
110
|
+
)
|
|
111
|
+
_require_token(identity[0], name="scorer_id")
|
|
112
|
+
if type(identity[1]) is not int or identity[1] <= 0:
|
|
113
|
+
raise ValueError("scorer_version must be positive")
|
|
114
|
+
require_sha256(identity[2], "scorer definition_sha256")
|
|
115
|
+
return identity # type: ignore[return-value]
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@dataclass(frozen=True, slots=True)
|
|
119
|
+
class MaterializedActionScore:
|
|
120
|
+
"""One opaque, finite, pre-evaluation score for one materialized action."""
|
|
121
|
+
|
|
122
|
+
action_sha256: str
|
|
123
|
+
value: float
|
|
124
|
+
|
|
125
|
+
def __post_init__(self) -> None:
|
|
126
|
+
require_sha256(self.action_sha256, "action_sha256")
|
|
127
|
+
if type(self.value) is not float or not math.isfinite(self.value):
|
|
128
|
+
raise ValueError("score value must be a finite exact float")
|
|
129
|
+
|
|
130
|
+
def to_record(self) -> dict[str, object]:
|
|
131
|
+
self.__post_init__()
|
|
132
|
+
return {
|
|
133
|
+
"action_sha256": self.action_sha256,
|
|
134
|
+
"value_hex": self.value.hex(),
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
@dataclass(frozen=True, slots=True)
|
|
139
|
+
class MaterializedActionScoreBatch:
|
|
140
|
+
"""Authenticated complete scoring of one sealed proposal universe."""
|
|
141
|
+
|
|
142
|
+
scorer_id: str
|
|
143
|
+
scorer_version: int
|
|
144
|
+
scorer_definition_sha256: str
|
|
145
|
+
residual_request_sha256: str
|
|
146
|
+
proposal_sha256s: tuple[str, ...]
|
|
147
|
+
scores: tuple[MaterializedActionScore, ...]
|
|
148
|
+
candidate_outcomes_observed: bool
|
|
149
|
+
evidence_sha256: str
|
|
150
|
+
batch_sha256: str = field(init=False)
|
|
151
|
+
|
|
152
|
+
def __post_init__(self) -> None:
|
|
153
|
+
_require_token(self.scorer_id, name="scorer_id")
|
|
154
|
+
if type(self.scorer_version) is not int or self.scorer_version <= 0:
|
|
155
|
+
raise ValueError("scorer_version must be positive")
|
|
156
|
+
require_sha256(
|
|
157
|
+
self.scorer_definition_sha256,
|
|
158
|
+
"scorer_definition_sha256",
|
|
159
|
+
)
|
|
160
|
+
require_sha256(
|
|
161
|
+
self.residual_request_sha256,
|
|
162
|
+
"residual_request_sha256",
|
|
163
|
+
)
|
|
164
|
+
if (
|
|
165
|
+
type(self.proposal_sha256s) is not tuple
|
|
166
|
+
or not self.proposal_sha256s
|
|
167
|
+
or self.proposal_sha256s
|
|
168
|
+
!= tuple(sorted(set(self.proposal_sha256s)))
|
|
169
|
+
):
|
|
170
|
+
raise ValueError("proposal_sha256s must be non-empty and canonical")
|
|
171
|
+
for value in self.proposal_sha256s:
|
|
172
|
+
require_sha256(value, "proposal_sha256")
|
|
173
|
+
if type(self.scores) is not tuple or not self.scores:
|
|
174
|
+
raise ValueError("scores must be a non-empty exact tuple")
|
|
175
|
+
for value in self.scores:
|
|
176
|
+
if type(value) is not MaterializedActionScore:
|
|
177
|
+
raise TypeError("scores must contain exact score values")
|
|
178
|
+
value.__post_init__()
|
|
179
|
+
score_actions = tuple(value.action_sha256 for value in self.scores)
|
|
180
|
+
if score_actions != tuple(sorted(set(score_actions))):
|
|
181
|
+
raise ValueError("scores must cover unique actions canonically")
|
|
182
|
+
if type(self.candidate_outcomes_observed) is not bool:
|
|
183
|
+
raise TypeError("candidate_outcomes_observed must be an exact bool")
|
|
184
|
+
if self.candidate_outcomes_observed:
|
|
185
|
+
raise ValueError("prequential scores cannot observe current outcomes")
|
|
186
|
+
require_sha256(self.evidence_sha256, "evidence_sha256")
|
|
187
|
+
object.__setattr__(
|
|
188
|
+
self,
|
|
189
|
+
"batch_sha256",
|
|
190
|
+
_hash(_SCORE_BATCH_DOMAIN, self._unsigned_record()),
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
194
|
+
return {
|
|
195
|
+
"schema_version": 1,
|
|
196
|
+
"scorer": {
|
|
197
|
+
"scorer_id": self.scorer_id,
|
|
198
|
+
"scorer_version": self.scorer_version,
|
|
199
|
+
"definition_sha256": self.scorer_definition_sha256,
|
|
200
|
+
},
|
|
201
|
+
"residual_request_sha256": self.residual_request_sha256,
|
|
202
|
+
"proposal_sha256s": list(self.proposal_sha256s),
|
|
203
|
+
"scores": [value.to_record() for value in self.scores],
|
|
204
|
+
"candidate_outcomes_observed": self.candidate_outcomes_observed,
|
|
205
|
+
"evidence_sha256": self.evidence_sha256,
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
def to_record(self) -> dict[str, object]:
|
|
209
|
+
self.__post_init__()
|
|
210
|
+
return {**self._unsigned_record(), "batch_sha256": self.batch_sha256}
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
@runtime_checkable
|
|
214
|
+
class MaterializedActionScorePort(Protocol):
|
|
215
|
+
"""Score a complete sealed population using strictly prior evidence."""
|
|
216
|
+
|
|
217
|
+
scorer_id: str
|
|
218
|
+
scorer_version: int
|
|
219
|
+
definition_sha256: str
|
|
220
|
+
|
|
221
|
+
async def score(
|
|
222
|
+
self,
|
|
223
|
+
request: ResidualPortfolioDecisionRequest,
|
|
224
|
+
proposals: tuple[MaterializedActionProposalBatch, ...],
|
|
225
|
+
) -> MaterializedActionScoreBatch: ...
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
@dataclass(frozen=True, slots=True)
|
|
229
|
+
class MaterializedActionScoreReliabilityEvidence:
|
|
230
|
+
"""Pre-evaluation authority calibration for one scorer and request."""
|
|
231
|
+
|
|
232
|
+
scorer_id: str
|
|
233
|
+
scorer_version: int
|
|
234
|
+
scorer_definition_sha256: str
|
|
235
|
+
residual_request_sha256: str
|
|
236
|
+
component_authorities: tuple[tuple[str, float], ...]
|
|
237
|
+
overall_reliability: float
|
|
238
|
+
candidate_outcomes_observed: bool
|
|
239
|
+
source_evidence_sha256: str
|
|
240
|
+
evidence_sha256: str = field(init=False)
|
|
241
|
+
|
|
242
|
+
def __post_init__(self) -> None:
|
|
243
|
+
_require_token(self.scorer_id, name="scorer_id")
|
|
244
|
+
if type(self.scorer_version) is not int or self.scorer_version <= 0:
|
|
245
|
+
raise ValueError("scorer_version must be positive")
|
|
246
|
+
require_sha256(
|
|
247
|
+
self.scorer_definition_sha256,
|
|
248
|
+
"scorer_definition_sha256",
|
|
249
|
+
)
|
|
250
|
+
require_sha256(
|
|
251
|
+
self.residual_request_sha256,
|
|
252
|
+
"residual_request_sha256",
|
|
253
|
+
)
|
|
254
|
+
if (
|
|
255
|
+
type(self.component_authorities) is not tuple
|
|
256
|
+
or not self.component_authorities
|
|
257
|
+
or tuple(value[0] for value in self.component_authorities)
|
|
258
|
+
!= tuple(
|
|
259
|
+
sorted(
|
|
260
|
+
{value[0] for value in self.component_authorities}
|
|
261
|
+
)
|
|
262
|
+
)
|
|
263
|
+
):
|
|
264
|
+
raise ValueError(
|
|
265
|
+
"component_authorities must be non-empty and canonical"
|
|
266
|
+
)
|
|
267
|
+
for component_id, authority in self.component_authorities:
|
|
268
|
+
_require_token(component_id, name="reliability component")
|
|
269
|
+
if (
|
|
270
|
+
type(authority) is not float
|
|
271
|
+
or not math.isfinite(authority)
|
|
272
|
+
or not 0.0 <= authority <= 1.0
|
|
273
|
+
):
|
|
274
|
+
raise ValueError("component authority must lie in [0, 1]")
|
|
275
|
+
if (
|
|
276
|
+
type(self.overall_reliability) is not float
|
|
277
|
+
or not math.isfinite(self.overall_reliability)
|
|
278
|
+
or not 0.0 <= self.overall_reliability <= 1.0
|
|
279
|
+
):
|
|
280
|
+
raise ValueError("overall_reliability must lie in [0, 1]")
|
|
281
|
+
if self.overall_reliability != min(
|
|
282
|
+
value for _, value in self.component_authorities
|
|
283
|
+
):
|
|
284
|
+
raise ValueError(
|
|
285
|
+
"overall reliability must be the minimum component authority"
|
|
286
|
+
)
|
|
287
|
+
if type(self.candidate_outcomes_observed) is not bool:
|
|
288
|
+
raise TypeError(
|
|
289
|
+
"candidate_outcomes_observed must be an exact bool"
|
|
290
|
+
)
|
|
291
|
+
if self.candidate_outcomes_observed:
|
|
292
|
+
raise ValueError(
|
|
293
|
+
"score reliability cannot observe current outcomes"
|
|
294
|
+
)
|
|
295
|
+
require_sha256(
|
|
296
|
+
self.source_evidence_sha256,
|
|
297
|
+
"source_evidence_sha256",
|
|
298
|
+
)
|
|
299
|
+
object.__setattr__(
|
|
300
|
+
self,
|
|
301
|
+
"evidence_sha256",
|
|
302
|
+
_hash(_RELIABILITY_EVIDENCE_DOMAIN, self._unsigned_record()),
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
306
|
+
return {
|
|
307
|
+
"schema_version": 1,
|
|
308
|
+
"scorer": {
|
|
309
|
+
"scorer_id": self.scorer_id,
|
|
310
|
+
"scorer_version": self.scorer_version,
|
|
311
|
+
"definition_sha256": self.scorer_definition_sha256,
|
|
312
|
+
},
|
|
313
|
+
"residual_request_sha256": self.residual_request_sha256,
|
|
314
|
+
"component_authorities": {
|
|
315
|
+
component_id: authority.hex()
|
|
316
|
+
for component_id, authority in self.component_authorities
|
|
317
|
+
},
|
|
318
|
+
"overall_reliability_hex": self.overall_reliability.hex(),
|
|
319
|
+
"candidate_outcomes_observed": (
|
|
320
|
+
self.candidate_outcomes_observed
|
|
321
|
+
),
|
|
322
|
+
"source_evidence_sha256": self.source_evidence_sha256,
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
def to_record(self) -> dict[str, object]:
|
|
326
|
+
self.__post_init__()
|
|
327
|
+
return {
|
|
328
|
+
**self._unsigned_record(),
|
|
329
|
+
"evidence_sha256": self.evidence_sha256,
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
@runtime_checkable
|
|
334
|
+
class MaterializedActionScoreReliabilityPort(Protocol):
|
|
335
|
+
"""Expose authenticated prior-only reliability after scoring a batch."""
|
|
336
|
+
|
|
337
|
+
scorer_id: str
|
|
338
|
+
scorer_version: int
|
|
339
|
+
definition_sha256: str
|
|
340
|
+
|
|
341
|
+
def reliability(
|
|
342
|
+
self,
|
|
343
|
+
residual_request_sha256: str,
|
|
344
|
+
component_ids: tuple[str, ...],
|
|
345
|
+
) -> MaterializedActionScoreReliabilityEvidence: ...
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
@dataclass(frozen=True, slots=True)
|
|
349
|
+
class PrequentialQuotaScorePortfolioPolicy:
|
|
350
|
+
"""Nominate a phenotype-unique quota from each independent score lane."""
|
|
351
|
+
|
|
352
|
+
scorers: tuple[MaterializedActionScorePort, ...]
|
|
353
|
+
scorer_quotas: tuple[tuple[str, int], ...]
|
|
354
|
+
|
|
355
|
+
policy_id: ClassVar[str] = PREQUENTIAL_SCORE_PORTFOLIO_POLICY_ID
|
|
356
|
+
policy_version: ClassVar[int] = PREQUENTIAL_SCORE_PORTFOLIO_POLICY_VERSION
|
|
357
|
+
definition_sha256: ClassVar[str] = (
|
|
358
|
+
PREQUENTIAL_SCORE_PORTFOLIO_POLICY_DEFINITION_SHA256
|
|
359
|
+
)
|
|
360
|
+
|
|
361
|
+
def __post_init__(self) -> None:
|
|
362
|
+
if type(self.scorers) is not tuple or not self.scorers:
|
|
363
|
+
raise ValueError("scorers must be a non-empty exact tuple")
|
|
364
|
+
identities = tuple(_scorer_identity(value) for value in self.scorers)
|
|
365
|
+
scorer_ids = tuple(value[0] for value in identities)
|
|
366
|
+
if scorer_ids != tuple(sorted(set(scorer_ids))):
|
|
367
|
+
raise ValueError("scorers must use canonical unique IDs")
|
|
368
|
+
if (
|
|
369
|
+
type(self.scorer_quotas) is not tuple
|
|
370
|
+
or not self.scorer_quotas
|
|
371
|
+
):
|
|
372
|
+
raise ValueError("scorer_quotas must be a non-empty exact tuple")
|
|
373
|
+
quota_ids: list[str] = []
|
|
374
|
+
for scorer_id, quota in self.scorer_quotas:
|
|
375
|
+
_require_token(scorer_id, name="quota scorer_id")
|
|
376
|
+
if type(quota) is not int or quota <= 0:
|
|
377
|
+
raise ValueError("every scorer quota must be positive")
|
|
378
|
+
quota_ids.append(scorer_id)
|
|
379
|
+
if tuple(quota_ids) != tuple(sorted(set(quota_ids))):
|
|
380
|
+
raise ValueError("scorer_quotas must use canonical unique IDs")
|
|
381
|
+
if tuple(quota_ids) != scorer_ids:
|
|
382
|
+
raise ValueError("scorer_quotas must exactly cover scorers")
|
|
383
|
+
_require_token(self.policy_id, name="policy_id")
|
|
384
|
+
if type(self.policy_version) is not int or self.policy_version <= 0:
|
|
385
|
+
raise ValueError("policy_version must be positive")
|
|
386
|
+
require_sha256(self.definition_sha256, "definition_sha256")
|
|
387
|
+
|
|
388
|
+
async def require(
|
|
389
|
+
self,
|
|
390
|
+
request: ResidualPortfolioDecisionRequest,
|
|
391
|
+
proposals: tuple[MaterializedActionProposalBatch, ...],
|
|
392
|
+
) -> MaterializedActionAllocationRequirement:
|
|
393
|
+
self.__post_init__()
|
|
394
|
+
if type(request) is not ResidualPortfolioDecisionRequest:
|
|
395
|
+
raise TypeError("request must be exact")
|
|
396
|
+
request.__post_init__()
|
|
397
|
+
if type(proposals) is not tuple or not proposals:
|
|
398
|
+
raise ValueError("proposals must be a non-empty exact tuple")
|
|
399
|
+
for proposal in proposals:
|
|
400
|
+
if type(proposal) is not MaterializedActionProposalBatch:
|
|
401
|
+
raise TypeError("proposals must contain exact batches")
|
|
402
|
+
proposal.__post_init__()
|
|
403
|
+
proposal.require_request(request)
|
|
404
|
+
|
|
405
|
+
quota_total = sum(value for _, value in self.scorer_quotas)
|
|
406
|
+
if quota_total > request.evaluation_slots:
|
|
407
|
+
raise ValueError("score portfolio quotas exceed evaluation capacity")
|
|
408
|
+
|
|
409
|
+
proposal_sha256s = tuple(
|
|
410
|
+
sorted(value.proposal_sha256 for value in proposals)
|
|
411
|
+
)
|
|
412
|
+
actions = tuple(
|
|
413
|
+
action for proposal in proposals for action in proposal.actions
|
|
414
|
+
)
|
|
415
|
+
action_by_sha256 = {value.action_sha256: value for value in actions}
|
|
416
|
+
if len(action_by_sha256) != len(actions):
|
|
417
|
+
raise ValueError("proposal union repeats an action identity")
|
|
418
|
+
action_sha256s = tuple(sorted(action_by_sha256))
|
|
419
|
+
|
|
420
|
+
batches = tuple(
|
|
421
|
+
await asyncio.gather(
|
|
422
|
+
*(scorer.score(request, proposals) for scorer in self.scorers)
|
|
423
|
+
)
|
|
424
|
+
)
|
|
425
|
+
batch_by_scorer: dict[str, MaterializedActionScoreBatch] = {}
|
|
426
|
+
scorer_by_id = {
|
|
427
|
+
_scorer_identity(value)[0]: value for value in self.scorers
|
|
428
|
+
}
|
|
429
|
+
for batch in batches:
|
|
430
|
+
if type(batch) is not MaterializedActionScoreBatch:
|
|
431
|
+
raise TypeError("scorer returned a foreign score batch")
|
|
432
|
+
batch.__post_init__()
|
|
433
|
+
scorer = scorer_by_id.get(batch.scorer_id)
|
|
434
|
+
if scorer is None:
|
|
435
|
+
raise ValueError("score batch names a foreign scorer")
|
|
436
|
+
if (
|
|
437
|
+
batch.scorer_id,
|
|
438
|
+
batch.scorer_version,
|
|
439
|
+
batch.scorer_definition_sha256,
|
|
440
|
+
) != _scorer_identity(scorer):
|
|
441
|
+
raise ValueError("score batch differs from its scorer identity")
|
|
442
|
+
if batch.residual_request_sha256 != request.request_sha256:
|
|
443
|
+
raise ValueError("score batch targets another residual request")
|
|
444
|
+
if batch.proposal_sha256s != proposal_sha256s:
|
|
445
|
+
raise ValueError("score batch targets another proposal universe")
|
|
446
|
+
if tuple(value.action_sha256 for value in batch.scores) != (
|
|
447
|
+
action_sha256s
|
|
448
|
+
):
|
|
449
|
+
raise ValueError("score batch must exactly cover sealed actions")
|
|
450
|
+
batch_by_scorer[batch.scorer_id] = batch
|
|
451
|
+
|
|
452
|
+
ranked_by_scorer = {
|
|
453
|
+
scorer_id: tuple(
|
|
454
|
+
sorted(
|
|
455
|
+
batch_by_scorer[scorer_id].scores,
|
|
456
|
+
key=lambda value: (-value.value, value.action_sha256),
|
|
457
|
+
)
|
|
458
|
+
)
|
|
459
|
+
for scorer_id, _ in self.scorer_quotas
|
|
460
|
+
}
|
|
461
|
+
selected: list[str] = []
|
|
462
|
+
selected_phenotypes: set[str] = set()
|
|
463
|
+
cursors = {scorer_id: 0 for scorer_id, _ in self.scorer_quotas}
|
|
464
|
+
selected_by_scorer = {
|
|
465
|
+
scorer_id: [] for scorer_id, _ in self.scorer_quotas
|
|
466
|
+
}
|
|
467
|
+
maximum_quota = max(value for _, value in self.scorer_quotas)
|
|
468
|
+
for ordinal in range(maximum_quota):
|
|
469
|
+
for scorer_id, quota in self.scorer_quotas:
|
|
470
|
+
if ordinal >= quota:
|
|
471
|
+
continue
|
|
472
|
+
ranking = ranked_by_scorer[scorer_id]
|
|
473
|
+
while cursors[scorer_id] < len(ranking):
|
|
474
|
+
score = ranking[cursors[scorer_id]]
|
|
475
|
+
cursors[scorer_id] += 1
|
|
476
|
+
action = action_by_sha256[score.action_sha256]
|
|
477
|
+
if (
|
|
478
|
+
action.phenotype_identity_sha256
|
|
479
|
+
in selected_phenotypes
|
|
480
|
+
):
|
|
481
|
+
continue
|
|
482
|
+
selected.append(action.action_sha256)
|
|
483
|
+
selected_phenotypes.add(
|
|
484
|
+
action.phenotype_identity_sha256
|
|
485
|
+
)
|
|
486
|
+
selected_by_scorer[scorer_id].append(
|
|
487
|
+
{
|
|
488
|
+
"action_sha256": action.action_sha256,
|
|
489
|
+
"score_hex": score.value.hex(),
|
|
490
|
+
"rank_position": cursors[scorer_id],
|
|
491
|
+
}
|
|
492
|
+
)
|
|
493
|
+
break
|
|
494
|
+
else:
|
|
495
|
+
raise ValueError(
|
|
496
|
+
"score portfolio cannot satisfy phenotype-unique quotas"
|
|
497
|
+
)
|
|
498
|
+
|
|
499
|
+
if len(selected) != quota_total:
|
|
500
|
+
raise AssertionError("score portfolio did not close its quota")
|
|
501
|
+
return MaterializedActionAllocationRequirement(
|
|
502
|
+
policy_id=self.policy_id,
|
|
503
|
+
policy_version=self.policy_version,
|
|
504
|
+
policy_definition_sha256=self.definition_sha256,
|
|
505
|
+
residual_request_sha256=request.request_sha256,
|
|
506
|
+
proposal_sha256s=proposal_sha256s,
|
|
507
|
+
required_action_sha256s=tuple(sorted(selected)),
|
|
508
|
+
candidate_outcomes_observed=False,
|
|
509
|
+
evidence=freeze_json(
|
|
510
|
+
{
|
|
511
|
+
"score_batch_sha256s": {
|
|
512
|
+
scorer_id: batch_by_scorer[scorer_id].batch_sha256
|
|
513
|
+
for scorer_id, _ in self.scorer_quotas
|
|
514
|
+
},
|
|
515
|
+
"scorer_quotas": {
|
|
516
|
+
scorer_id: quota
|
|
517
|
+
for scorer_id, quota in self.scorer_quotas
|
|
518
|
+
},
|
|
519
|
+
"selected_by_scorer": selected_by_scorer,
|
|
520
|
+
"nomination_slots": quota_total,
|
|
521
|
+
"evaluation_slots": request.evaluation_slots,
|
|
522
|
+
"downstream_unreserved_slots": (
|
|
523
|
+
request.evaluation_slots - quota_total
|
|
524
|
+
),
|
|
525
|
+
"candidate_outcomes_observed": False,
|
|
526
|
+
}
|
|
527
|
+
),
|
|
528
|
+
)
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
@dataclass(frozen=True, slots=True)
|
|
532
|
+
class ReliabilityAdaptiveScorePortfolioPolicy:
|
|
533
|
+
"""Scale primary authority and refill exact-infeasibility rejections.
|
|
534
|
+
|
|
535
|
+
The optional hard-feasibility port is deliberately proof-only. An
|
|
536
|
+
``UNKNOWN`` verdict remains eligible; only an authenticated
|
|
537
|
+
``INFEASIBLE`` decision removes an action. Each score authority then
|
|
538
|
+
continues down its own frozen ranking, preserving quota provenance while
|
|
539
|
+
avoiding a workload-specific branch in this policy.
|
|
540
|
+
"""
|
|
541
|
+
|
|
542
|
+
scorers: tuple[MaterializedActionScorePort, ...]
|
|
543
|
+
primary_scorer_id: str
|
|
544
|
+
primary_reliability: MaterializedActionScoreReliabilityPort = field(
|
|
545
|
+
repr=False,
|
|
546
|
+
compare=False,
|
|
547
|
+
)
|
|
548
|
+
reliability_component_ids: tuple[str, ...]
|
|
549
|
+
minimum_primary_fraction: float = 0.5
|
|
550
|
+
hard_feasibility: HardFeasibilityPort | None = field(
|
|
551
|
+
default=None,
|
|
552
|
+
repr=False,
|
|
553
|
+
compare=False,
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
policy_id: ClassVar[str] = (
|
|
557
|
+
RELIABILITY_ADAPTIVE_SCORE_PORTFOLIO_POLICY_ID
|
|
558
|
+
)
|
|
559
|
+
policy_version: ClassVar[int] = (
|
|
560
|
+
RELIABILITY_ADAPTIVE_SCORE_PORTFOLIO_POLICY_VERSION
|
|
561
|
+
)
|
|
562
|
+
definition_sha256: str = field(init=False)
|
|
563
|
+
|
|
564
|
+
def __post_init__(self) -> None:
|
|
565
|
+
if type(self.scorers) is not tuple or len(self.scorers) < 2:
|
|
566
|
+
raise ValueError(
|
|
567
|
+
"adaptive portfolio requires a primary and fallback scorer"
|
|
568
|
+
)
|
|
569
|
+
identities = tuple(_scorer_identity(value) for value in self.scorers)
|
|
570
|
+
scorer_ids = tuple(value[0] for value in identities)
|
|
571
|
+
if scorer_ids != tuple(sorted(set(scorer_ids))):
|
|
572
|
+
raise ValueError("scorers must use canonical unique IDs")
|
|
573
|
+
_require_token(self.primary_scorer_id, name="primary_scorer_id")
|
|
574
|
+
if self.primary_scorer_id not in scorer_ids:
|
|
575
|
+
raise ValueError("primary scorer is absent")
|
|
576
|
+
if not isinstance(
|
|
577
|
+
self.primary_reliability,
|
|
578
|
+
MaterializedActionScoreReliabilityPort,
|
|
579
|
+
):
|
|
580
|
+
raise TypeError(
|
|
581
|
+
"primary_reliability must implement its runtime port"
|
|
582
|
+
)
|
|
583
|
+
primary_identity = next(
|
|
584
|
+
value
|
|
585
|
+
for value in identities
|
|
586
|
+
if value[0] == self.primary_scorer_id
|
|
587
|
+
)
|
|
588
|
+
if (
|
|
589
|
+
self.primary_reliability.scorer_id,
|
|
590
|
+
self.primary_reliability.scorer_version,
|
|
591
|
+
self.primary_reliability.definition_sha256,
|
|
592
|
+
) != primary_identity:
|
|
593
|
+
raise ValueError(
|
|
594
|
+
"primary reliability identity differs from its scorer"
|
|
595
|
+
)
|
|
596
|
+
if (
|
|
597
|
+
type(self.reliability_component_ids) is not tuple
|
|
598
|
+
or not self.reliability_component_ids
|
|
599
|
+
or self.reliability_component_ids
|
|
600
|
+
!= tuple(sorted(set(self.reliability_component_ids)))
|
|
601
|
+
):
|
|
602
|
+
raise ValueError(
|
|
603
|
+
"reliability components must be non-empty and canonical"
|
|
604
|
+
)
|
|
605
|
+
for value in self.reliability_component_ids:
|
|
606
|
+
_require_token(value, name="reliability component")
|
|
607
|
+
if (
|
|
608
|
+
type(self.minimum_primary_fraction) is not float
|
|
609
|
+
or not math.isfinite(self.minimum_primary_fraction)
|
|
610
|
+
or not 0.0 < self.minimum_primary_fraction <= 1.0
|
|
611
|
+
):
|
|
612
|
+
raise ValueError(
|
|
613
|
+
"minimum_primary_fraction must lie in (0, 1]"
|
|
614
|
+
)
|
|
615
|
+
hard_feasibility_identity = None
|
|
616
|
+
if self.hard_feasibility is not None:
|
|
617
|
+
hard_feasibility_identity = validate_hard_feasibility_port(
|
|
618
|
+
self.hard_feasibility
|
|
619
|
+
)
|
|
620
|
+
_require_token(self.policy_id, name="policy_id")
|
|
621
|
+
object.__setattr__(
|
|
622
|
+
self,
|
|
623
|
+
"definition_sha256",
|
|
624
|
+
_hash(
|
|
625
|
+
_ADAPTIVE_POLICY_DOMAIN,
|
|
626
|
+
{
|
|
627
|
+
"schema_version": 1,
|
|
628
|
+
"policy_id": self.policy_id,
|
|
629
|
+
"policy_version": self.policy_version,
|
|
630
|
+
"scorers": [
|
|
631
|
+
{
|
|
632
|
+
"scorer_id": scorer_id,
|
|
633
|
+
"scorer_version": scorer_version,
|
|
634
|
+
"definition_sha256": definition_sha256,
|
|
635
|
+
}
|
|
636
|
+
for scorer_id, scorer_version, definition_sha256
|
|
637
|
+
in identities
|
|
638
|
+
],
|
|
639
|
+
"primary_scorer_id": self.primary_scorer_id,
|
|
640
|
+
"reliability_component_ids": list(
|
|
641
|
+
self.reliability_component_ids
|
|
642
|
+
),
|
|
643
|
+
"minimum_primary_fraction_hex": (
|
|
644
|
+
self.minimum_primary_fraction.hex()
|
|
645
|
+
),
|
|
646
|
+
"primary_quota_rule": (
|
|
647
|
+
"ceil_fraction_floor_plus_nearest_integer_of_"
|
|
648
|
+
"reliability_times_remaining_capacity"
|
|
649
|
+
),
|
|
650
|
+
"fallback_rule": (
|
|
651
|
+
"canonical_equal_integer_split_with_early_remainder"
|
|
652
|
+
),
|
|
653
|
+
"hard_feasibility": (
|
|
654
|
+
None
|
|
655
|
+
if hard_feasibility_identity is None
|
|
656
|
+
else {
|
|
657
|
+
"policy_id": hard_feasibility_identity[0],
|
|
658
|
+
"policy_version": hard_feasibility_identity[1],
|
|
659
|
+
"definition_sha256": hard_feasibility_identity[2],
|
|
660
|
+
}
|
|
661
|
+
),
|
|
662
|
+
"hard_feasibility_rejection_rule": (
|
|
663
|
+
"reject_only_authenticated_infeasible;"
|
|
664
|
+
"retain_feasible_and_unknown"
|
|
665
|
+
),
|
|
666
|
+
"hard_feasibility_refill_rule": (
|
|
667
|
+
"continue_same_authority_frozen_ranking"
|
|
668
|
+
),
|
|
669
|
+
"composition": (
|
|
670
|
+
"canonical_round_robin_phenotype_unique"
|
|
671
|
+
),
|
|
672
|
+
"candidate_outcomes_observed": False,
|
|
673
|
+
"workload_model_provider_branches": False,
|
|
674
|
+
},
|
|
675
|
+
),
|
|
676
|
+
)
|
|
677
|
+
|
|
678
|
+
async def require(
|
|
679
|
+
self,
|
|
680
|
+
request: ResidualPortfolioDecisionRequest,
|
|
681
|
+
proposals: tuple[MaterializedActionProposalBatch, ...],
|
|
682
|
+
) -> MaterializedActionAllocationRequirement:
|
|
683
|
+
self.__post_init__()
|
|
684
|
+
if type(request) is not ResidualPortfolioDecisionRequest:
|
|
685
|
+
raise TypeError("request must be exact")
|
|
686
|
+
request.__post_init__()
|
|
687
|
+
if type(proposals) is not tuple or not proposals:
|
|
688
|
+
raise ValueError("proposals must be a non-empty exact tuple")
|
|
689
|
+
for proposal in proposals:
|
|
690
|
+
if type(proposal) is not MaterializedActionProposalBatch:
|
|
691
|
+
raise TypeError("proposals must contain exact batches")
|
|
692
|
+
proposal.__post_init__()
|
|
693
|
+
proposal.require_request(request)
|
|
694
|
+
|
|
695
|
+
proposal_sha256s = tuple(
|
|
696
|
+
sorted(value.proposal_sha256 for value in proposals)
|
|
697
|
+
)
|
|
698
|
+
actions = tuple(
|
|
699
|
+
action for proposal in proposals for action in proposal.actions
|
|
700
|
+
)
|
|
701
|
+
action_by_sha256 = {
|
|
702
|
+
value.action_sha256: value for value in actions
|
|
703
|
+
}
|
|
704
|
+
if len(action_by_sha256) != len(actions):
|
|
705
|
+
raise ValueError("proposal union repeats an action identity")
|
|
706
|
+
action_sha256s = tuple(sorted(action_by_sha256))
|
|
707
|
+
scorer_by_id = {
|
|
708
|
+
_scorer_identity(value)[0]: value for value in self.scorers
|
|
709
|
+
}
|
|
710
|
+
batches = tuple(
|
|
711
|
+
await asyncio.gather(
|
|
712
|
+
*(scorer.score(request, proposals) for scorer in self.scorers)
|
|
713
|
+
)
|
|
714
|
+
)
|
|
715
|
+
batch_by_scorer: dict[str, MaterializedActionScoreBatch] = {}
|
|
716
|
+
for batch in batches:
|
|
717
|
+
if type(batch) is not MaterializedActionScoreBatch:
|
|
718
|
+
raise TypeError("scorer returned a foreign score batch")
|
|
719
|
+
batch.__post_init__()
|
|
720
|
+
scorer = scorer_by_id.get(batch.scorer_id)
|
|
721
|
+
if scorer is None:
|
|
722
|
+
raise ValueError("score batch names a foreign scorer")
|
|
723
|
+
if (
|
|
724
|
+
batch.scorer_id,
|
|
725
|
+
batch.scorer_version,
|
|
726
|
+
batch.scorer_definition_sha256,
|
|
727
|
+
) != _scorer_identity(scorer):
|
|
728
|
+
raise ValueError("score batch differs from scorer identity")
|
|
729
|
+
if (
|
|
730
|
+
batch.residual_request_sha256 != request.request_sha256
|
|
731
|
+
or batch.proposal_sha256s != proposal_sha256s
|
|
732
|
+
or tuple(value.action_sha256 for value in batch.scores)
|
|
733
|
+
!= action_sha256s
|
|
734
|
+
):
|
|
735
|
+
raise ValueError("score batch differs from sealed universe")
|
|
736
|
+
batch_by_scorer[batch.scorer_id] = batch
|
|
737
|
+
|
|
738
|
+
reliability = self.primary_reliability.reliability(
|
|
739
|
+
request.request_sha256,
|
|
740
|
+
self.reliability_component_ids,
|
|
741
|
+
)
|
|
742
|
+
if type(reliability) is not MaterializedActionScoreReliabilityEvidence:
|
|
743
|
+
raise TypeError("reliability port returned foreign evidence")
|
|
744
|
+
reliability.__post_init__()
|
|
745
|
+
primary_batch = batch_by_scorer[self.primary_scorer_id]
|
|
746
|
+
if (
|
|
747
|
+
reliability.scorer_id,
|
|
748
|
+
reliability.scorer_version,
|
|
749
|
+
reliability.scorer_definition_sha256,
|
|
750
|
+
) != (
|
|
751
|
+
primary_batch.scorer_id,
|
|
752
|
+
primary_batch.scorer_version,
|
|
753
|
+
primary_batch.scorer_definition_sha256,
|
|
754
|
+
):
|
|
755
|
+
raise ValueError("reliability evidence names another scorer")
|
|
756
|
+
if reliability.residual_request_sha256 != request.request_sha256:
|
|
757
|
+
raise ValueError("reliability evidence names another request")
|
|
758
|
+
|
|
759
|
+
capacity = request.evaluation_slots
|
|
760
|
+
minimum_primary = math.ceil(
|
|
761
|
+
capacity * self.minimum_primary_fraction
|
|
762
|
+
)
|
|
763
|
+
adaptive_capacity = capacity - minimum_primary
|
|
764
|
+
primary_quota = minimum_primary + math.floor(
|
|
765
|
+
reliability.overall_reliability * adaptive_capacity + 0.5
|
|
766
|
+
)
|
|
767
|
+
primary_quota = min(
|
|
768
|
+
capacity,
|
|
769
|
+
max(minimum_primary, primary_quota),
|
|
770
|
+
)
|
|
771
|
+
fallback_ids = tuple(
|
|
772
|
+
value
|
|
773
|
+
for value in sorted(scorer_by_id)
|
|
774
|
+
if value != self.primary_scorer_id
|
|
775
|
+
)
|
|
776
|
+
residual = capacity - primary_quota
|
|
777
|
+
quotient, remainder = divmod(residual, len(fallback_ids))
|
|
778
|
+
quotas = {
|
|
779
|
+
self.primary_scorer_id: primary_quota,
|
|
780
|
+
**{
|
|
781
|
+
scorer_id: quotient + (1 if index < remainder else 0)
|
|
782
|
+
for index, scorer_id in enumerate(fallback_ids)
|
|
783
|
+
},
|
|
784
|
+
}
|
|
785
|
+
if sum(quotas.values()) != capacity:
|
|
786
|
+
raise AssertionError("adaptive quotas do not close")
|
|
787
|
+
|
|
788
|
+
ranked_by_scorer = {
|
|
789
|
+
scorer_id: tuple(
|
|
790
|
+
sorted(
|
|
791
|
+
batch_by_scorer[scorer_id].scores,
|
|
792
|
+
key=lambda value: (-value.value, value.action_sha256),
|
|
793
|
+
)
|
|
794
|
+
)
|
|
795
|
+
for scorer_id in sorted(scorer_by_id)
|
|
796
|
+
}
|
|
797
|
+
feasibility_decisions: tuple[
|
|
798
|
+
tuple[str, HardFeasibilityDecision], ...
|
|
799
|
+
] = ()
|
|
800
|
+
infeasible_action_sha256s: set[str] = set()
|
|
801
|
+
if self.hard_feasibility is not None:
|
|
802
|
+
audited: list[tuple[str, HardFeasibilityDecision]] = []
|
|
803
|
+
for action_sha256 in action_sha256s:
|
|
804
|
+
action = action_by_sha256[action_sha256]
|
|
805
|
+
decision = assess_hard_feasibility(
|
|
806
|
+
self.hard_feasibility,
|
|
807
|
+
HardFeasibilityRequest(
|
|
808
|
+
campaign_scope_sha256=request.campaign_scope_sha256,
|
|
809
|
+
cutoff_index=request.decision_index,
|
|
810
|
+
configuration=action.configuration,
|
|
811
|
+
),
|
|
812
|
+
)
|
|
813
|
+
audited.append((action_sha256, decision))
|
|
814
|
+
if decision.verdict is HardFeasibilityVerdict.INFEASIBLE:
|
|
815
|
+
infeasible_action_sha256s.add(action_sha256)
|
|
816
|
+
feasibility_decisions = tuple(audited)
|
|
817
|
+
if len(actions) - len(infeasible_action_sha256s) < capacity:
|
|
818
|
+
raise ValueError(
|
|
819
|
+
"hard-feasibility-screened proposal union cannot fill "
|
|
820
|
+
"evaluation capacity"
|
|
821
|
+
)
|
|
822
|
+
selected: list[str] = []
|
|
823
|
+
selected_phenotypes: set[str] = set()
|
|
824
|
+
cursors = {scorer_id: 0 for scorer_id in scorer_by_id}
|
|
825
|
+
selected_by_scorer = {
|
|
826
|
+
scorer_id: [] for scorer_id in sorted(scorer_by_id)
|
|
827
|
+
}
|
|
828
|
+
for ordinal in range(max(quotas.values())):
|
|
829
|
+
for scorer_id in sorted(scorer_by_id):
|
|
830
|
+
if ordinal >= quotas[scorer_id]:
|
|
831
|
+
continue
|
|
832
|
+
ranking = ranked_by_scorer[scorer_id]
|
|
833
|
+
while cursors[scorer_id] < len(ranking):
|
|
834
|
+
score = ranking[cursors[scorer_id]]
|
|
835
|
+
cursors[scorer_id] += 1
|
|
836
|
+
action = action_by_sha256[score.action_sha256]
|
|
837
|
+
if action.action_sha256 in infeasible_action_sha256s:
|
|
838
|
+
continue
|
|
839
|
+
if (
|
|
840
|
+
action.phenotype_identity_sha256
|
|
841
|
+
in selected_phenotypes
|
|
842
|
+
):
|
|
843
|
+
continue
|
|
844
|
+
selected.append(action.action_sha256)
|
|
845
|
+
selected_phenotypes.add(
|
|
846
|
+
action.phenotype_identity_sha256
|
|
847
|
+
)
|
|
848
|
+
selected_by_scorer[scorer_id].append(
|
|
849
|
+
{
|
|
850
|
+
"action_sha256": action.action_sha256,
|
|
851
|
+
"score_hex": score.value.hex(),
|
|
852
|
+
"rank_position": cursors[scorer_id],
|
|
853
|
+
}
|
|
854
|
+
)
|
|
855
|
+
break
|
|
856
|
+
else:
|
|
857
|
+
raise ValueError(
|
|
858
|
+
"adaptive portfolio cannot close a unique quota"
|
|
859
|
+
)
|
|
860
|
+
if len(selected) != capacity:
|
|
861
|
+
raise AssertionError("adaptive portfolio did not fill capacity")
|
|
862
|
+
feasibility_verdict_counts = {
|
|
863
|
+
verdict.value: sum(
|
|
864
|
+
decision.verdict is verdict
|
|
865
|
+
for _action_sha256, decision in feasibility_decisions
|
|
866
|
+
)
|
|
867
|
+
for verdict in HardFeasibilityVerdict
|
|
868
|
+
}
|
|
869
|
+
feasibility_record = {
|
|
870
|
+
"enabled": self.hard_feasibility is not None,
|
|
871
|
+
"policy": (
|
|
872
|
+
None
|
|
873
|
+
if self.hard_feasibility is None
|
|
874
|
+
else {
|
|
875
|
+
"policy_id": self.hard_feasibility.policy_id,
|
|
876
|
+
"policy_version": self.hard_feasibility.policy_version,
|
|
877
|
+
"definition_sha256": (
|
|
878
|
+
self.hard_feasibility.definition_sha256
|
|
879
|
+
),
|
|
880
|
+
}
|
|
881
|
+
),
|
|
882
|
+
"verdict_counts": feasibility_verdict_counts,
|
|
883
|
+
"decision_batch_sha256": (
|
|
884
|
+
None
|
|
885
|
+
if not feasibility_decisions
|
|
886
|
+
else hard_feasibility_decision_batch_sha256(
|
|
887
|
+
tuple(
|
|
888
|
+
decision.decision_sha256
|
|
889
|
+
for _action_sha256, decision
|
|
890
|
+
in feasibility_decisions
|
|
891
|
+
)
|
|
892
|
+
)
|
|
893
|
+
),
|
|
894
|
+
"rejected_actions": [
|
|
895
|
+
{
|
|
896
|
+
"action_sha256": action_sha256,
|
|
897
|
+
"decision": decision.to_record(),
|
|
898
|
+
}
|
|
899
|
+
for action_sha256, decision in feasibility_decisions
|
|
900
|
+
if decision.verdict
|
|
901
|
+
is HardFeasibilityVerdict.INFEASIBLE
|
|
902
|
+
],
|
|
903
|
+
"rejection_authority": (
|
|
904
|
+
"authenticated_exact_infeasibility_only"
|
|
905
|
+
),
|
|
906
|
+
"unknown_actions_remain_eligible": True,
|
|
907
|
+
"refill": "same_authority_frozen_ranking",
|
|
908
|
+
"candidate_outcomes_observed": False,
|
|
909
|
+
}
|
|
910
|
+
return MaterializedActionAllocationRequirement(
|
|
911
|
+
policy_id=self.policy_id,
|
|
912
|
+
policy_version=self.policy_version,
|
|
913
|
+
policy_definition_sha256=self.definition_sha256,
|
|
914
|
+
residual_request_sha256=request.request_sha256,
|
|
915
|
+
proposal_sha256s=proposal_sha256s,
|
|
916
|
+
required_action_sha256s=tuple(sorted(selected)),
|
|
917
|
+
candidate_outcomes_observed=False,
|
|
918
|
+
evidence=freeze_json(
|
|
919
|
+
{
|
|
920
|
+
"score_batch_sha256s": {
|
|
921
|
+
scorer_id: batch_by_scorer[
|
|
922
|
+
scorer_id
|
|
923
|
+
].batch_sha256
|
|
924
|
+
for scorer_id in sorted(batch_by_scorer)
|
|
925
|
+
},
|
|
926
|
+
"primary_reliability": reliability.to_record(),
|
|
927
|
+
"minimum_primary_quota": minimum_primary,
|
|
928
|
+
"effective_quotas": {
|
|
929
|
+
scorer_id: quotas[scorer_id]
|
|
930
|
+
for scorer_id in sorted(quotas)
|
|
931
|
+
},
|
|
932
|
+
"selected_by_scorer": selected_by_scorer,
|
|
933
|
+
"hard_feasibility": feasibility_record,
|
|
934
|
+
"candidate_outcomes_observed": False,
|
|
935
|
+
"workload_model_provider_branches": False,
|
|
936
|
+
}
|
|
937
|
+
),
|
|
938
|
+
)
|
|
939
|
+
|
|
940
|
+
|
|
941
|
+
__all__ = [
|
|
942
|
+
"MaterializedActionScore",
|
|
943
|
+
"MaterializedActionScoreBatch",
|
|
944
|
+
"MaterializedActionScorePort",
|
|
945
|
+
"MaterializedActionScoreReliabilityEvidence",
|
|
946
|
+
"MaterializedActionScoreReliabilityPort",
|
|
947
|
+
"PREQUENTIAL_SCORE_PORTFOLIO_POLICY_DEFINITION_SHA256",
|
|
948
|
+
"PREQUENTIAL_SCORE_PORTFOLIO_POLICY_ID",
|
|
949
|
+
"PREQUENTIAL_SCORE_PORTFOLIO_POLICY_VERSION",
|
|
950
|
+
"PrequentialQuotaScorePortfolioPolicy",
|
|
951
|
+
"RELIABILITY_ADAPTIVE_SCORE_PORTFOLIO_POLICY_ID",
|
|
952
|
+
"RELIABILITY_ADAPTIVE_SCORE_PORTFOLIO_POLICY_VERSION",
|
|
953
|
+
"ReliabilityAdaptiveScorePortfolioPolicy",
|
|
954
|
+
]
|