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,2762 @@
|
|
|
1
|
+
"""Outcome-safe racing among complete, precommitted portfolio continuations.
|
|
2
|
+
|
|
3
|
+
The module generalizes the binary lineage gate without knowing anything about
|
|
4
|
+
workloads, objectives, models, providers, prompts, or configuration fields.
|
|
5
|
+
Allocation policies first construct several complete slates from one sealed
|
|
6
|
+
proposal market. A small, lane-stratified pilot is then forced into every
|
|
7
|
+
slate before any current outcome exists. Real pilot consequences update only
|
|
8
|
+
the predeclared lane evidence, and a deterministic gate selects one already
|
|
9
|
+
frozen completion.
|
|
10
|
+
|
|
11
|
+
This is deliberately a *portfolio* race rather than candidate-wise Bayesian
|
|
12
|
+
optimization. It preserves exact-K evaluation accounting, avoids
|
|
13
|
+
outcome-conditioned regeneration, and leaves the authoritative evaluator and
|
|
14
|
+
archive utility behind existing injected ports.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import asyncio
|
|
20
|
+
import hashlib
|
|
21
|
+
import json
|
|
22
|
+
import math
|
|
23
|
+
import re
|
|
24
|
+
from dataclasses import dataclass, field
|
|
25
|
+
from typing import Protocol, runtime_checkable
|
|
26
|
+
|
|
27
|
+
from agent_evolve.application.contextual_search_controller import SearchPhase
|
|
28
|
+
from agent_evolve.application.materialized_action_broker import (
|
|
29
|
+
MaterializedActionAllocationRequirement,
|
|
30
|
+
MaterializedActionDescriptor,
|
|
31
|
+
)
|
|
32
|
+
from agent_evolve.application.residual_portfolio_evolution import (
|
|
33
|
+
MaterializedActionAllocationPolicyPort,
|
|
34
|
+
MaterializedActionProposalBatch,
|
|
35
|
+
ResidualPortfolioDecisionRequest,
|
|
36
|
+
)
|
|
37
|
+
from agent_evolve.application.sequential_lineage_allocation import (
|
|
38
|
+
SequentialAllocationGateDecisionPort,
|
|
39
|
+
SequentialAllocationPlanPort,
|
|
40
|
+
SequentialPilotOutcomeBatch,
|
|
41
|
+
)
|
|
42
|
+
from agent_evolve.domain.patch import require_sha256
|
|
43
|
+
from agent_evolve.domain.typed_json import (
|
|
44
|
+
FrozenJsonObject,
|
|
45
|
+
freeze_json,
|
|
46
|
+
thaw_json,
|
|
47
|
+
typed_json_sha256,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
PRECOMMITTED_PORTFOLIO_RACE_PLANNER_ID = (
|
|
51
|
+
"precommitted_portfolio_race_planner"
|
|
52
|
+
)
|
|
53
|
+
PRECOMMITTED_PORTFOLIO_RACE_PLANNER_VERSION = 4
|
|
54
|
+
EVIDENCE_ADAPTIVE_PORTFOLIO_RACE_GATE_ID = (
|
|
55
|
+
"evidence_adaptive_portfolio_race_gate"
|
|
56
|
+
)
|
|
57
|
+
EVIDENCE_ADAPTIVE_PORTFOLIO_RACE_GATE_VERSION = 2
|
|
58
|
+
TRACE_FIELD_PORTFOLIO_LANE_PROJECTION_ID = (
|
|
59
|
+
"trace_field_portfolio_lane_projection"
|
|
60
|
+
)
|
|
61
|
+
TRACE_FIELD_PORTFOLIO_LANE_PROJECTION_VERSION = 2
|
|
62
|
+
PHASE_CONDITIONED_PORTFOLIO_RACE_PRIOR_ID = (
|
|
63
|
+
"phase_conditioned_portfolio_race_prior"
|
|
64
|
+
)
|
|
65
|
+
PHASE_CONDITIONED_PORTFOLIO_RACE_PRIOR_VERSION = 1
|
|
66
|
+
SYMMETRIC_DIFFERENCE_PORTFOLIO_RACE_POLICY_ID = (
|
|
67
|
+
"symmetric_difference_portfolio_race_policy"
|
|
68
|
+
)
|
|
69
|
+
SYMMETRIC_DIFFERENCE_PORTFOLIO_RACE_POLICY_VERSION = 2
|
|
70
|
+
|
|
71
|
+
_TOKEN = re.compile(r"^[a-z][a-z0-9_.:-]{0,255}$")
|
|
72
|
+
_BRANCH_DOMAIN = b"agent-evolve:precommitted-race-branch:v1\x00"
|
|
73
|
+
_PLAN_DOMAIN = b"agent-evolve:precommitted-portfolio-race-plan:v1\x00"
|
|
74
|
+
_PLANNER_DEFINITION_DOMAIN = (
|
|
75
|
+
b"agent-evolve:precommitted-portfolio-race-planner-definition:v1\x00"
|
|
76
|
+
)
|
|
77
|
+
_LANE_PROJECTION_DEFINITION_DOMAIN = (
|
|
78
|
+
b"agent-evolve:portfolio-race-lane-projection-definition:v1\x00"
|
|
79
|
+
)
|
|
80
|
+
_PRIOR_PROJECTION_DEFINITION_DOMAIN = (
|
|
81
|
+
b"agent-evolve:portfolio-race-prior-projection-definition:v1\x00"
|
|
82
|
+
)
|
|
83
|
+
_GATE_DEFINITION_DOMAIN = (
|
|
84
|
+
b"agent-evolve:evidence-adaptive-portfolio-race-gate-definition:v1\x00"
|
|
85
|
+
)
|
|
86
|
+
_GATE_DECISION_DOMAIN = (
|
|
87
|
+
b"agent-evolve:evidence-adaptive-portfolio-race-decision:v1\x00"
|
|
88
|
+
)
|
|
89
|
+
_PILOT_REQUIREMENT_DEFINITION_DOMAIN = (
|
|
90
|
+
b"agent-evolve:precommitted-portfolio-race-pilot:v1\x00"
|
|
91
|
+
)
|
|
92
|
+
_BRANCH_REQUIREMENT_DEFINITION_DOMAIN = (
|
|
93
|
+
b"agent-evolve:precommitted-portfolio-race-branch-requirement:v1\x00"
|
|
94
|
+
)
|
|
95
|
+
_DISAGREEMENT_POLICY_DEFINITION_DOMAIN = (
|
|
96
|
+
b"agent-evolve:portfolio-race-disagreement-policy-definition:v1\x00"
|
|
97
|
+
)
|
|
98
|
+
_DISAGREEMENT_DESIGN_DOMAIN = (
|
|
99
|
+
b"agent-evolve:portfolio-race-disagreement-design:v1\x00"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _canonical_json(value: object) -> bytes:
|
|
104
|
+
return json.dumps(
|
|
105
|
+
value,
|
|
106
|
+
allow_nan=False,
|
|
107
|
+
ensure_ascii=True,
|
|
108
|
+
separators=(",", ":"),
|
|
109
|
+
sort_keys=True,
|
|
110
|
+
).encode("ascii", errors="strict")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _hash(domain: bytes, value: object) -> str:
|
|
114
|
+
return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _require_token(value: str, *, name: str) -> None:
|
|
118
|
+
if type(value) is not str or _TOKEN.fullmatch(value) is None:
|
|
119
|
+
raise ValueError(f"{name} must use the closed token grammar")
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _policy_identity(
|
|
123
|
+
policy: MaterializedActionAllocationPolicyPort,
|
|
124
|
+
) -> tuple[str, int, str]:
|
|
125
|
+
if not isinstance(policy, MaterializedActionAllocationPolicyPort):
|
|
126
|
+
raise TypeError("allocation policy must implement its application port")
|
|
127
|
+
identity = (
|
|
128
|
+
getattr(policy, "policy_id", None),
|
|
129
|
+
getattr(policy, "policy_version", None),
|
|
130
|
+
getattr(policy, "definition_sha256", None),
|
|
131
|
+
)
|
|
132
|
+
_require_token(identity[0], name="allocation policy_id")
|
|
133
|
+
if type(identity[1]) is not int or identity[1] <= 0:
|
|
134
|
+
raise ValueError("allocation policy_version must be positive")
|
|
135
|
+
require_sha256(identity[2], "allocation policy definition_sha256")
|
|
136
|
+
return identity # type: ignore[return-value]
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _requirement_trace(
|
|
140
|
+
requirement: MaterializedActionAllocationRequirement,
|
|
141
|
+
) -> tuple[dict[str, object], ...]:
|
|
142
|
+
requirement.__post_init__()
|
|
143
|
+
evidence = thaw_json(requirement.evidence)
|
|
144
|
+
if type(evidence) is not dict:
|
|
145
|
+
raise TypeError("allocation evidence must have an object root")
|
|
146
|
+
raw_trace = evidence.get("selection_trace")
|
|
147
|
+
if type(raw_trace) is not list:
|
|
148
|
+
raise ValueError("allocation evidence lacks a selection trace")
|
|
149
|
+
rows: list[dict[str, object]] = []
|
|
150
|
+
seen: set[str] = set()
|
|
151
|
+
for fallback_ordinal, raw in enumerate(raw_trace, start=1):
|
|
152
|
+
if type(raw) is not dict:
|
|
153
|
+
raise TypeError("selection trace rows must be objects")
|
|
154
|
+
row = dict(raw)
|
|
155
|
+
action_sha256 = row.get("action_sha256")
|
|
156
|
+
if type(action_sha256) is not str:
|
|
157
|
+
raise TypeError("selection trace omits action_sha256")
|
|
158
|
+
require_sha256(action_sha256, "selection trace action_sha256")
|
|
159
|
+
if action_sha256 in seen:
|
|
160
|
+
raise ValueError("selection trace repeats an action")
|
|
161
|
+
seen.add(action_sha256)
|
|
162
|
+
ordinal = row.get("ordinal", fallback_ordinal)
|
|
163
|
+
if type(ordinal) is not int or ordinal <= 0:
|
|
164
|
+
raise ValueError("selection trace ordinal must be positive")
|
|
165
|
+
row["ordinal"] = ordinal
|
|
166
|
+
rows.append(row)
|
|
167
|
+
required = set(requirement.required_action_sha256s)
|
|
168
|
+
if seen != required:
|
|
169
|
+
raise ValueError(
|
|
170
|
+
"selection trace must exactly cover required action identities"
|
|
171
|
+
)
|
|
172
|
+
return tuple(
|
|
173
|
+
sorted(
|
|
174
|
+
rows,
|
|
175
|
+
key=lambda value: (
|
|
176
|
+
int(value["ordinal"]),
|
|
177
|
+
str(value["action_sha256"]),
|
|
178
|
+
),
|
|
179
|
+
)
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
@runtime_checkable
|
|
184
|
+
class PortfolioLaneProjectionPort(Protocol):
|
|
185
|
+
"""Project an outcome-blind trace/action pair into a portable lane."""
|
|
186
|
+
|
|
187
|
+
projection_id: str
|
|
188
|
+
projection_version: int
|
|
189
|
+
definition_sha256: str
|
|
190
|
+
|
|
191
|
+
def project(
|
|
192
|
+
self,
|
|
193
|
+
trace_row: dict[str, object],
|
|
194
|
+
action: MaterializedActionDescriptor,
|
|
195
|
+
) -> str: ...
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
@dataclass(frozen=True, slots=True)
|
|
199
|
+
class TraceFieldPortfolioLaneProjection:
|
|
200
|
+
"""Use portable trace fields, falling back to source/operator identity."""
|
|
201
|
+
|
|
202
|
+
trace_fields: tuple[str, ...] = (
|
|
203
|
+
"score_lane",
|
|
204
|
+
"allocation_kind",
|
|
205
|
+
)
|
|
206
|
+
include_expert_id: bool = True
|
|
207
|
+
include_operator_id: bool = False
|
|
208
|
+
projection_id: str = TRACE_FIELD_PORTFOLIO_LANE_PROJECTION_ID
|
|
209
|
+
projection_version: int = (
|
|
210
|
+
TRACE_FIELD_PORTFOLIO_LANE_PROJECTION_VERSION
|
|
211
|
+
)
|
|
212
|
+
definition_sha256: str = field(init=False)
|
|
213
|
+
|
|
214
|
+
def __post_init__(self) -> None:
|
|
215
|
+
if (
|
|
216
|
+
type(self.trace_fields) is not tuple
|
|
217
|
+
or not self.trace_fields
|
|
218
|
+
or self.trace_fields != tuple(dict.fromkeys(self.trace_fields))
|
|
219
|
+
):
|
|
220
|
+
raise ValueError(
|
|
221
|
+
"trace_fields must be a non-empty ordered unique tuple"
|
|
222
|
+
)
|
|
223
|
+
for value in self.trace_fields:
|
|
224
|
+
_require_token(value, name="trace field")
|
|
225
|
+
if type(self.include_expert_id) is not bool:
|
|
226
|
+
raise TypeError("include_expert_id must be exact")
|
|
227
|
+
if type(self.include_operator_id) is not bool:
|
|
228
|
+
raise TypeError("include_operator_id must be exact")
|
|
229
|
+
_require_token(self.projection_id, name="projection_id")
|
|
230
|
+
if (
|
|
231
|
+
self.projection_version
|
|
232
|
+
!= TRACE_FIELD_PORTFOLIO_LANE_PROJECTION_VERSION
|
|
233
|
+
):
|
|
234
|
+
raise ValueError("projection_version is immutable")
|
|
235
|
+
object.__setattr__(
|
|
236
|
+
self,
|
|
237
|
+
"definition_sha256",
|
|
238
|
+
_hash(
|
|
239
|
+
_LANE_PROJECTION_DEFINITION_DOMAIN,
|
|
240
|
+
{
|
|
241
|
+
"schema_version": 1,
|
|
242
|
+
"projection_id": self.projection_id,
|
|
243
|
+
"projection_version": self.projection_version,
|
|
244
|
+
"trace_fields": list(self.trace_fields),
|
|
245
|
+
"include_expert_id": self.include_expert_id,
|
|
246
|
+
"include_operator_id": self.include_operator_id,
|
|
247
|
+
"fallback": "allocation_kind_then_action_source",
|
|
248
|
+
"workload_model_provider_branches": False,
|
|
249
|
+
},
|
|
250
|
+
),
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
def project(
|
|
254
|
+
self,
|
|
255
|
+
trace_row: dict[str, object],
|
|
256
|
+
action: MaterializedActionDescriptor,
|
|
257
|
+
) -> str:
|
|
258
|
+
self.__post_init__()
|
|
259
|
+
if type(trace_row) is not dict:
|
|
260
|
+
raise TypeError("trace_row must be an exact dict")
|
|
261
|
+
if type(action) is not MaterializedActionDescriptor:
|
|
262
|
+
raise TypeError("action must be exact")
|
|
263
|
+
action.__post_init__()
|
|
264
|
+
parts: list[str] = []
|
|
265
|
+
for field_name in self.trace_fields:
|
|
266
|
+
value = trace_row.get(field_name)
|
|
267
|
+
if type(value) is str and _TOKEN.fullmatch(value) is not None:
|
|
268
|
+
parts.append(f"{field_name}:{value}")
|
|
269
|
+
break
|
|
270
|
+
if not parts:
|
|
271
|
+
parts.append(f"source:{action.expert_id}")
|
|
272
|
+
if self.include_expert_id:
|
|
273
|
+
parts.append(f"expert:{action.expert_id}")
|
|
274
|
+
if self.include_operator_id:
|
|
275
|
+
parts.append(f"operator:{action.operator_id}")
|
|
276
|
+
lane_id = ".".join(parts)
|
|
277
|
+
_require_token(lane_id, name="projected lane_id")
|
|
278
|
+
return lane_id
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def _lane_projection_identity(
|
|
282
|
+
value: PortfolioLaneProjectionPort,
|
|
283
|
+
) -> tuple[str, int, str]:
|
|
284
|
+
if not isinstance(value, PortfolioLaneProjectionPort):
|
|
285
|
+
raise TypeError("lane projection must implement its application port")
|
|
286
|
+
identity = (
|
|
287
|
+
getattr(value, "projection_id", None),
|
|
288
|
+
getattr(value, "projection_version", None),
|
|
289
|
+
getattr(value, "definition_sha256", None),
|
|
290
|
+
)
|
|
291
|
+
_require_token(identity[0], name="lane projection_id")
|
|
292
|
+
if type(identity[1]) is not int or identity[1] <= 0:
|
|
293
|
+
raise ValueError("lane projection_version must be positive")
|
|
294
|
+
require_sha256(identity[2], "lane projection definition_sha256")
|
|
295
|
+
return identity # type: ignore[return-value]
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
@dataclass(frozen=True, slots=True)
|
|
299
|
+
class PortfolioRacePolicyBinding:
|
|
300
|
+
"""One named continuation policy and its outcome-blind prior mean."""
|
|
301
|
+
|
|
302
|
+
branch_id: str
|
|
303
|
+
policy: MaterializedActionAllocationPolicyPort = field(
|
|
304
|
+
repr=False,
|
|
305
|
+
compare=False,
|
|
306
|
+
)
|
|
307
|
+
prior_mean: float = 0.5
|
|
308
|
+
|
|
309
|
+
def __post_init__(self) -> None:
|
|
310
|
+
_require_token(self.branch_id, name="branch_id")
|
|
311
|
+
_policy_identity(self.policy)
|
|
312
|
+
if (
|
|
313
|
+
type(self.prior_mean) is not float
|
|
314
|
+
or not math.isfinite(self.prior_mean)
|
|
315
|
+
or not 0.0 <= self.prior_mean <= 1.0
|
|
316
|
+
):
|
|
317
|
+
raise ValueError("prior_mean must be finite and lie in [0, 1]")
|
|
318
|
+
|
|
319
|
+
def identity_record(self) -> dict[str, object]:
|
|
320
|
+
identity = _policy_identity(self.policy)
|
|
321
|
+
return {
|
|
322
|
+
"branch_id": self.branch_id,
|
|
323
|
+
"policy_id": identity[0],
|
|
324
|
+
"policy_version": identity[1],
|
|
325
|
+
"policy_definition_sha256": identity[2],
|
|
326
|
+
"prior_mean_hex": self.prior_mean.hex(),
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
@runtime_checkable
|
|
331
|
+
class PortfolioRacePriorProjectionPort(Protocol):
|
|
332
|
+
"""Project frozen search context into one outcome-blind branch prior."""
|
|
333
|
+
|
|
334
|
+
projection_id: str
|
|
335
|
+
projection_version: int
|
|
336
|
+
definition_sha256: str
|
|
337
|
+
|
|
338
|
+
def project(
|
|
339
|
+
self,
|
|
340
|
+
request: ResidualPortfolioDecisionRequest,
|
|
341
|
+
binding: PortfolioRacePolicyBinding,
|
|
342
|
+
source_requirement: MaterializedActionAllocationRequirement,
|
|
343
|
+
) -> float: ...
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def _prior_projection_identity(
|
|
347
|
+
value: PortfolioRacePriorProjectionPort,
|
|
348
|
+
) -> tuple[str, int, str]:
|
|
349
|
+
if not isinstance(value, PortfolioRacePriorProjectionPort):
|
|
350
|
+
raise TypeError(
|
|
351
|
+
"prior projection must implement its application port"
|
|
352
|
+
)
|
|
353
|
+
identity = (
|
|
354
|
+
getattr(value, "projection_id", None),
|
|
355
|
+
getattr(value, "projection_version", None),
|
|
356
|
+
getattr(value, "definition_sha256", None),
|
|
357
|
+
)
|
|
358
|
+
_require_token(identity[0], name="prior projection_id")
|
|
359
|
+
if type(identity[1]) is not int or identity[1] <= 0:
|
|
360
|
+
raise ValueError("prior projection_version must be positive")
|
|
361
|
+
require_sha256(identity[2], "prior projection definition_sha256")
|
|
362
|
+
return identity # type: ignore[return-value]
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
@dataclass(frozen=True, slots=True)
|
|
366
|
+
class PhaseConditionedPortfolioRacePrior:
|
|
367
|
+
"""Frozen method-branch priors indexed only by generic search phase.
|
|
368
|
+
|
|
369
|
+
The core never knows workload, objective, model, provider, prompt, or
|
|
370
|
+
configuration fields. A training pipeline may fit these bounded means
|
|
371
|
+
from earlier authenticated branch consequences and inject the resulting
|
|
372
|
+
immutable table. Missing cells retain each binding's declared prior.
|
|
373
|
+
"""
|
|
374
|
+
|
|
375
|
+
prior_means: tuple[tuple[SearchPhase, str, float], ...]
|
|
376
|
+
projection_id: str = PHASE_CONDITIONED_PORTFOLIO_RACE_PRIOR_ID
|
|
377
|
+
projection_version: int = (
|
|
378
|
+
PHASE_CONDITIONED_PORTFOLIO_RACE_PRIOR_VERSION
|
|
379
|
+
)
|
|
380
|
+
definition_sha256: str = field(init=False)
|
|
381
|
+
|
|
382
|
+
def __post_init__(self) -> None:
|
|
383
|
+
if type(self.prior_means) is not tuple or not self.prior_means:
|
|
384
|
+
raise ValueError("prior_means must be a non-empty exact tuple")
|
|
385
|
+
canonical = tuple(
|
|
386
|
+
sorted(
|
|
387
|
+
self.prior_means,
|
|
388
|
+
key=lambda value: (value[0].value, value[1]),
|
|
389
|
+
)
|
|
390
|
+
)
|
|
391
|
+
if self.prior_means != canonical:
|
|
392
|
+
raise ValueError("phase-conditioned priors must be canonical")
|
|
393
|
+
cells: list[tuple[str, str]] = []
|
|
394
|
+
for phase, branch_id, mean in self.prior_means:
|
|
395
|
+
if type(phase) is not SearchPhase:
|
|
396
|
+
raise TypeError("prior phase must be an exact SearchPhase")
|
|
397
|
+
_require_token(branch_id, name="prior branch_id")
|
|
398
|
+
if (
|
|
399
|
+
type(mean) is not float
|
|
400
|
+
or not math.isfinite(mean)
|
|
401
|
+
or not 0.0 <= mean <= 1.0
|
|
402
|
+
):
|
|
403
|
+
raise ValueError("branch prior mean must lie in [0, 1]")
|
|
404
|
+
cells.append((phase.value, branch_id))
|
|
405
|
+
if len(cells) != len(set(cells)):
|
|
406
|
+
raise ValueError("phase-conditioned prior cells must be unique")
|
|
407
|
+
_require_token(self.projection_id, name="prior projection_id")
|
|
408
|
+
if (
|
|
409
|
+
self.projection_version
|
|
410
|
+
!= PHASE_CONDITIONED_PORTFOLIO_RACE_PRIOR_VERSION
|
|
411
|
+
):
|
|
412
|
+
raise ValueError("prior projection_version is immutable")
|
|
413
|
+
object.__setattr__(
|
|
414
|
+
self,
|
|
415
|
+
"definition_sha256",
|
|
416
|
+
_hash(
|
|
417
|
+
_PRIOR_PROJECTION_DEFINITION_DOMAIN,
|
|
418
|
+
{
|
|
419
|
+
"schema_version": 1,
|
|
420
|
+
"projection_id": self.projection_id,
|
|
421
|
+
"projection_version": self.projection_version,
|
|
422
|
+
"prior_means": [
|
|
423
|
+
{
|
|
424
|
+
"phase": phase.value,
|
|
425
|
+
"branch_id": branch_id,
|
|
426
|
+
"mean_hex": mean.hex(),
|
|
427
|
+
}
|
|
428
|
+
for phase, branch_id, mean in self.prior_means
|
|
429
|
+
],
|
|
430
|
+
"missing_cell": "binding_prior_mean",
|
|
431
|
+
"candidate_outcomes_observed": False,
|
|
432
|
+
"workload_model_provider_branches": False,
|
|
433
|
+
},
|
|
434
|
+
),
|
|
435
|
+
)
|
|
436
|
+
|
|
437
|
+
def project(
|
|
438
|
+
self,
|
|
439
|
+
request: ResidualPortfolioDecisionRequest,
|
|
440
|
+
binding: PortfolioRacePolicyBinding,
|
|
441
|
+
source_requirement: MaterializedActionAllocationRequirement,
|
|
442
|
+
) -> float:
|
|
443
|
+
self.__post_init__()
|
|
444
|
+
if type(request) is not ResidualPortfolioDecisionRequest:
|
|
445
|
+
raise TypeError("request must be exact")
|
|
446
|
+
request.__post_init__()
|
|
447
|
+
if type(binding) is not PortfolioRacePolicyBinding:
|
|
448
|
+
raise TypeError("binding must be exact")
|
|
449
|
+
binding.__post_init__()
|
|
450
|
+
if (
|
|
451
|
+
type(source_requirement)
|
|
452
|
+
is not MaterializedActionAllocationRequirement
|
|
453
|
+
):
|
|
454
|
+
raise TypeError("source_requirement must be exact")
|
|
455
|
+
source_requirement.__post_init__()
|
|
456
|
+
if (
|
|
457
|
+
source_requirement.residual_request_sha256
|
|
458
|
+
!= request.request_sha256
|
|
459
|
+
):
|
|
460
|
+
raise ValueError("prior source targets another request")
|
|
461
|
+
matches = tuple(
|
|
462
|
+
mean
|
|
463
|
+
for phase, branch_id, mean in self.prior_means
|
|
464
|
+
if phase is request.phase and branch_id == binding.branch_id
|
|
465
|
+
)
|
|
466
|
+
if len(matches) > 1:
|
|
467
|
+
raise AssertionError("validated prior table repeated a cell")
|
|
468
|
+
return binding.prior_mean if not matches else matches[0]
|
|
469
|
+
|
|
470
|
+
def to_record(self) -> dict[str, object]:
|
|
471
|
+
self.__post_init__()
|
|
472
|
+
return {
|
|
473
|
+
"schema_version": 1,
|
|
474
|
+
"projection_id": self.projection_id,
|
|
475
|
+
"projection_version": self.projection_version,
|
|
476
|
+
"definition_sha256": self.definition_sha256,
|
|
477
|
+
"prior_means": [
|
|
478
|
+
{
|
|
479
|
+
"phase": phase.value,
|
|
480
|
+
"branch_id": branch_id,
|
|
481
|
+
"mean_hex": mean.hex(),
|
|
482
|
+
}
|
|
483
|
+
for phase, branch_id, mean in self.prior_means
|
|
484
|
+
],
|
|
485
|
+
"missing_cell": "binding_prior_mean",
|
|
486
|
+
"candidate_outcomes_observed": False,
|
|
487
|
+
"workload_model_provider_branches": False,
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
|
|
491
|
+
@dataclass(frozen=True, slots=True)
|
|
492
|
+
class PortfolioRacePilotLaneBinding:
|
|
493
|
+
action_sha256: str
|
|
494
|
+
lane_id: str
|
|
495
|
+
|
|
496
|
+
def __post_init__(self) -> None:
|
|
497
|
+
require_sha256(self.action_sha256, "pilot action_sha256")
|
|
498
|
+
_require_token(self.lane_id, name="pilot lane_id")
|
|
499
|
+
|
|
500
|
+
def to_record(self) -> dict[str, object]:
|
|
501
|
+
self.__post_init__()
|
|
502
|
+
return {
|
|
503
|
+
"action_sha256": self.action_sha256,
|
|
504
|
+
"lane_id": self.lane_id,
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
@dataclass(frozen=True, slots=True)
|
|
509
|
+
class FrozenPortfolioRaceBranch:
|
|
510
|
+
"""One complete slate and its pre-pilot lane exposure."""
|
|
511
|
+
|
|
512
|
+
branch_id: str
|
|
513
|
+
source_requirement_sha256: str
|
|
514
|
+
requirement: MaterializedActionAllocationRequirement
|
|
515
|
+
completion_lane_exposure: tuple[tuple[str, int], ...]
|
|
516
|
+
prior_mean: float
|
|
517
|
+
branch_sha256: str = field(init=False)
|
|
518
|
+
|
|
519
|
+
def __post_init__(self) -> None:
|
|
520
|
+
_require_token(self.branch_id, name="branch_id")
|
|
521
|
+
require_sha256(
|
|
522
|
+
self.source_requirement_sha256,
|
|
523
|
+
"source_requirement_sha256",
|
|
524
|
+
)
|
|
525
|
+
if type(self.requirement) is not MaterializedActionAllocationRequirement:
|
|
526
|
+
raise TypeError("branch requirement must be exact")
|
|
527
|
+
self.requirement.__post_init__()
|
|
528
|
+
if (
|
|
529
|
+
type(self.completion_lane_exposure) is not tuple
|
|
530
|
+
or not self.completion_lane_exposure
|
|
531
|
+
or self.completion_lane_exposure
|
|
532
|
+
!= tuple(sorted(self.completion_lane_exposure))
|
|
533
|
+
):
|
|
534
|
+
raise ValueError(
|
|
535
|
+
"completion_lane_exposure must be non-empty and canonical"
|
|
536
|
+
)
|
|
537
|
+
lane_ids = tuple(value[0] for value in self.completion_lane_exposure)
|
|
538
|
+
if len(lane_ids) != len(set(lane_ids)):
|
|
539
|
+
raise ValueError("completion lane IDs must be unique")
|
|
540
|
+
for lane_id, count in self.completion_lane_exposure:
|
|
541
|
+
_require_token(lane_id, name="completion lane_id")
|
|
542
|
+
if type(count) is not int or count <= 0:
|
|
543
|
+
raise ValueError("completion lane counts must be positive")
|
|
544
|
+
if (
|
|
545
|
+
type(self.prior_mean) is not float
|
|
546
|
+
or not math.isfinite(self.prior_mean)
|
|
547
|
+
or not 0.0 <= self.prior_mean <= 1.0
|
|
548
|
+
):
|
|
549
|
+
raise ValueError("prior_mean must be finite and lie in [0, 1]")
|
|
550
|
+
object.__setattr__(
|
|
551
|
+
self,
|
|
552
|
+
"branch_sha256",
|
|
553
|
+
_hash(_BRANCH_DOMAIN, self._unsigned_record()),
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
557
|
+
return {
|
|
558
|
+
"schema_version": 1,
|
|
559
|
+
"branch_id": self.branch_id,
|
|
560
|
+
"source_requirement_sha256": self.source_requirement_sha256,
|
|
561
|
+
"requirement_sha256": self.requirement.requirement_sha256,
|
|
562
|
+
"completion_lane_exposure": [
|
|
563
|
+
{"lane_id": lane_id, "count": count}
|
|
564
|
+
for lane_id, count in self.completion_lane_exposure
|
|
565
|
+
],
|
|
566
|
+
"prior_mean_hex": self.prior_mean.hex(),
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
def to_record(self, *, include_evidence: bool = False) -> dict[str, object]:
|
|
570
|
+
self.__post_init__()
|
|
571
|
+
return {
|
|
572
|
+
**self._unsigned_record(),
|
|
573
|
+
"requirement": self.requirement.to_record(
|
|
574
|
+
include_evidence=include_evidence
|
|
575
|
+
),
|
|
576
|
+
"branch_sha256": self.branch_sha256,
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
@dataclass(frozen=True, slots=True)
|
|
581
|
+
class PrecommittedPortfolioRacePlan:
|
|
582
|
+
"""A shared diagnostic pilot and N complete frozen continuations."""
|
|
583
|
+
|
|
584
|
+
planner_id: str
|
|
585
|
+
planner_version: int
|
|
586
|
+
planner_definition_sha256: str
|
|
587
|
+
residual_request_sha256: str
|
|
588
|
+
proposal_sha256s: tuple[str, ...]
|
|
589
|
+
evaluation_slots: int
|
|
590
|
+
pilot_requirement: MaterializedActionAllocationRequirement
|
|
591
|
+
pilot_lane_bindings: tuple[PortfolioRacePilotLaneBinding, ...]
|
|
592
|
+
branches: tuple[FrozenPortfolioRaceBranch, ...]
|
|
593
|
+
candidate_outcomes_observed: bool
|
|
594
|
+
evidence: FrozenJsonObject
|
|
595
|
+
plan_sha256: str = field(init=False)
|
|
596
|
+
|
|
597
|
+
def __post_init__(self) -> None:
|
|
598
|
+
_require_token(self.planner_id, name="planner_id")
|
|
599
|
+
if type(self.planner_version) is not int or self.planner_version <= 0:
|
|
600
|
+
raise ValueError("planner_version must be positive")
|
|
601
|
+
require_sha256(
|
|
602
|
+
self.planner_definition_sha256,
|
|
603
|
+
"planner_definition_sha256",
|
|
604
|
+
)
|
|
605
|
+
require_sha256(
|
|
606
|
+
self.residual_request_sha256,
|
|
607
|
+
"residual_request_sha256",
|
|
608
|
+
)
|
|
609
|
+
if (
|
|
610
|
+
type(self.proposal_sha256s) is not tuple
|
|
611
|
+
or not self.proposal_sha256s
|
|
612
|
+
or self.proposal_sha256s
|
|
613
|
+
!= tuple(sorted(set(self.proposal_sha256s)))
|
|
614
|
+
):
|
|
615
|
+
raise ValueError("proposal_sha256s must be non-empty and canonical")
|
|
616
|
+
for value in self.proposal_sha256s:
|
|
617
|
+
require_sha256(value, "proposal_sha256")
|
|
618
|
+
if type(self.evaluation_slots) is not int or self.evaluation_slots <= 0:
|
|
619
|
+
raise ValueError("evaluation_slots must be positive")
|
|
620
|
+
if type(self.pilot_requirement) is not MaterializedActionAllocationRequirement:
|
|
621
|
+
raise TypeError("pilot_requirement must be exact")
|
|
622
|
+
self.pilot_requirement.__post_init__()
|
|
623
|
+
if (
|
|
624
|
+
self.pilot_requirement.residual_request_sha256
|
|
625
|
+
!= self.residual_request_sha256
|
|
626
|
+
or self.pilot_requirement.proposal_sha256s
|
|
627
|
+
!= self.proposal_sha256s
|
|
628
|
+
):
|
|
629
|
+
raise ValueError("pilot requirement targets another proposal market")
|
|
630
|
+
if (
|
|
631
|
+
type(self.pilot_lane_bindings) is not tuple
|
|
632
|
+
or tuple(
|
|
633
|
+
value.action_sha256 for value in self.pilot_lane_bindings
|
|
634
|
+
)
|
|
635
|
+
!= self.pilot_requirement.required_action_sha256s
|
|
636
|
+
):
|
|
637
|
+
raise ValueError(
|
|
638
|
+
"pilot lane bindings must exactly cover canonical pilot actions"
|
|
639
|
+
)
|
|
640
|
+
for value in self.pilot_lane_bindings:
|
|
641
|
+
if type(value) is not PortfolioRacePilotLaneBinding:
|
|
642
|
+
raise TypeError("pilot lane bindings must be exact")
|
|
643
|
+
value.__post_init__()
|
|
644
|
+
if (
|
|
645
|
+
type(self.branches) is not tuple
|
|
646
|
+
or not self.branches
|
|
647
|
+
or tuple(value.branch_id for value in self.branches)
|
|
648
|
+
!= tuple(sorted({value.branch_id for value in self.branches}))
|
|
649
|
+
):
|
|
650
|
+
raise ValueError(
|
|
651
|
+
"branches must contain canonical unique IDs"
|
|
652
|
+
)
|
|
653
|
+
pilot = set(self.pilot_action_sha256s)
|
|
654
|
+
for branch in self.branches:
|
|
655
|
+
if type(branch) is not FrozenPortfolioRaceBranch:
|
|
656
|
+
raise TypeError("branches must be exact")
|
|
657
|
+
branch.__post_init__()
|
|
658
|
+
requirement = branch.requirement
|
|
659
|
+
if (
|
|
660
|
+
requirement.residual_request_sha256
|
|
661
|
+
!= self.residual_request_sha256
|
|
662
|
+
or requirement.proposal_sha256s != self.proposal_sha256s
|
|
663
|
+
or len(requirement.required_action_sha256s)
|
|
664
|
+
!= self.evaluation_slots
|
|
665
|
+
or not pilot.issubset(
|
|
666
|
+
requirement.required_action_sha256s
|
|
667
|
+
)
|
|
668
|
+
):
|
|
669
|
+
raise ValueError(
|
|
670
|
+
"every branch must be a complete pilot-preserving slate"
|
|
671
|
+
)
|
|
672
|
+
if type(self.candidate_outcomes_observed) is not bool:
|
|
673
|
+
raise TypeError("candidate_outcomes_observed must be exact")
|
|
674
|
+
if self.candidate_outcomes_observed:
|
|
675
|
+
raise ValueError("a race plan cannot observe current outcomes")
|
|
676
|
+
if (
|
|
677
|
+
type(self.evidence) is not FrozenJsonObject
|
|
678
|
+
or freeze_json(self.evidence) is not self.evidence
|
|
679
|
+
):
|
|
680
|
+
raise TypeError("race-plan evidence must be a frozen object")
|
|
681
|
+
object.__setattr__(
|
|
682
|
+
self,
|
|
683
|
+
"plan_sha256",
|
|
684
|
+
_hash(_PLAN_DOMAIN, self._unsigned_record()),
|
|
685
|
+
)
|
|
686
|
+
|
|
687
|
+
@property
|
|
688
|
+
def pilot_action_sha256s(self) -> tuple[str, ...]:
|
|
689
|
+
return self.pilot_requirement.required_action_sha256s
|
|
690
|
+
|
|
691
|
+
@property
|
|
692
|
+
def frozen_branch_ids(self) -> tuple[str, ...]:
|
|
693
|
+
return tuple(value.branch_id for value in self.branches)
|
|
694
|
+
|
|
695
|
+
@property
|
|
696
|
+
def frozen_requirements(
|
|
697
|
+
self,
|
|
698
|
+
) -> tuple[MaterializedActionAllocationRequirement, ...]:
|
|
699
|
+
return tuple(value.requirement for value in self.branches)
|
|
700
|
+
|
|
701
|
+
def requirement_for(
|
|
702
|
+
self,
|
|
703
|
+
branch_id: str,
|
|
704
|
+
) -> MaterializedActionAllocationRequirement:
|
|
705
|
+
_require_token(branch_id, name="branch_id")
|
|
706
|
+
matches = tuple(
|
|
707
|
+
value.requirement
|
|
708
|
+
for value in self.branches
|
|
709
|
+
if value.branch_id == branch_id
|
|
710
|
+
)
|
|
711
|
+
if len(matches) != 1:
|
|
712
|
+
raise ValueError("branch_id is not frozen in this plan")
|
|
713
|
+
return matches[0]
|
|
714
|
+
|
|
715
|
+
def branch_for(self, branch_id: str) -> FrozenPortfolioRaceBranch:
|
|
716
|
+
_require_token(branch_id, name="branch_id")
|
|
717
|
+
matches = tuple(
|
|
718
|
+
value for value in self.branches if value.branch_id == branch_id
|
|
719
|
+
)
|
|
720
|
+
if len(matches) != 1:
|
|
721
|
+
raise ValueError("branch_id is not frozen in this plan")
|
|
722
|
+
return matches[0]
|
|
723
|
+
|
|
724
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
725
|
+
return {
|
|
726
|
+
"schema_version": 1,
|
|
727
|
+
"planner": {
|
|
728
|
+
"planner_id": self.planner_id,
|
|
729
|
+
"planner_version": self.planner_version,
|
|
730
|
+
"definition_sha256": self.planner_definition_sha256,
|
|
731
|
+
},
|
|
732
|
+
"residual_request_sha256": self.residual_request_sha256,
|
|
733
|
+
"proposal_sha256s": list(self.proposal_sha256s),
|
|
734
|
+
"evaluation_slots": self.evaluation_slots,
|
|
735
|
+
"pilot_requirement_sha256": (
|
|
736
|
+
self.pilot_requirement.requirement_sha256
|
|
737
|
+
),
|
|
738
|
+
"pilot_lane_bindings": [
|
|
739
|
+
value.to_record() for value in self.pilot_lane_bindings
|
|
740
|
+
],
|
|
741
|
+
"branch_sha256s": [
|
|
742
|
+
value.branch_sha256 for value in self.branches
|
|
743
|
+
],
|
|
744
|
+
"candidate_outcomes_observed": self.candidate_outcomes_observed,
|
|
745
|
+
"evidence_sha256": typed_json_sha256(self.evidence),
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
def to_record(self, *, include_evidence: bool = False) -> dict[str, object]:
|
|
749
|
+
self.__post_init__()
|
|
750
|
+
record = {
|
|
751
|
+
**self._unsigned_record(),
|
|
752
|
+
"pilot_requirement": self.pilot_requirement.to_record(
|
|
753
|
+
include_evidence=include_evidence
|
|
754
|
+
),
|
|
755
|
+
"branches": [
|
|
756
|
+
value.to_record(include_evidence=include_evidence)
|
|
757
|
+
for value in self.branches
|
|
758
|
+
],
|
|
759
|
+
"plan_sha256": self.plan_sha256,
|
|
760
|
+
}
|
|
761
|
+
if include_evidence:
|
|
762
|
+
record["evidence"] = thaw_json(self.evidence)
|
|
763
|
+
return record
|
|
764
|
+
|
|
765
|
+
|
|
766
|
+
def _action_market(
|
|
767
|
+
proposals: tuple[MaterializedActionProposalBatch, ...],
|
|
768
|
+
) -> dict[str, MaterializedActionDescriptor]:
|
|
769
|
+
market: dict[str, MaterializedActionDescriptor] = {}
|
|
770
|
+
candidate_ids: set[object] = set()
|
|
771
|
+
for proposal in proposals:
|
|
772
|
+
if type(proposal) is not MaterializedActionProposalBatch:
|
|
773
|
+
raise TypeError("proposal market must contain exact batches")
|
|
774
|
+
proposal.__post_init__()
|
|
775
|
+
for action in proposal.actions:
|
|
776
|
+
if action.action_sha256 in market:
|
|
777
|
+
raise ValueError("proposal market repeats an action identity")
|
|
778
|
+
if action.target_candidate_id in candidate_ids:
|
|
779
|
+
raise ValueError("proposal market repeats a target candidate")
|
|
780
|
+
market[action.action_sha256] = action
|
|
781
|
+
candidate_ids.add(action.target_candidate_id)
|
|
782
|
+
return market
|
|
783
|
+
|
|
784
|
+
|
|
785
|
+
def _trace_by_action(
|
|
786
|
+
requirement: MaterializedActionAllocationRequirement,
|
|
787
|
+
) -> dict[str, dict[str, object]]:
|
|
788
|
+
return {
|
|
789
|
+
str(value["action_sha256"]): value
|
|
790
|
+
for value in _requirement_trace(requirement)
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
|
|
794
|
+
def _ordered_action_ids(
|
|
795
|
+
requirement: MaterializedActionAllocationRequirement,
|
|
796
|
+
) -> tuple[str, ...]:
|
|
797
|
+
return tuple(
|
|
798
|
+
str(value["action_sha256"])
|
|
799
|
+
for value in _requirement_trace(requirement)
|
|
800
|
+
)
|
|
801
|
+
|
|
802
|
+
|
|
803
|
+
def _stratified_pilot_ids(
|
|
804
|
+
*,
|
|
805
|
+
requirement: MaterializedActionAllocationRequirement,
|
|
806
|
+
market: dict[str, MaterializedActionDescriptor],
|
|
807
|
+
lane_projection: PortfolioLaneProjectionPort,
|
|
808
|
+
pilot_slots: int,
|
|
809
|
+
) -> tuple[tuple[str, str], ...]:
|
|
810
|
+
trace = _requirement_trace(requirement)
|
|
811
|
+
rows = [
|
|
812
|
+
(
|
|
813
|
+
str(value["action_sha256"]),
|
|
814
|
+
lane_projection.project(
|
|
815
|
+
value,
|
|
816
|
+
market[str(value["action_sha256"])],
|
|
817
|
+
),
|
|
818
|
+
)
|
|
819
|
+
for value in trace
|
|
820
|
+
]
|
|
821
|
+
by_lane: dict[str, list[str]] = {}
|
|
822
|
+
for action_sha256, lane_id in rows:
|
|
823
|
+
by_lane.setdefault(lane_id, []).append(action_sha256)
|
|
824
|
+
lane_order = tuple(by_lane)
|
|
825
|
+
selected: list[tuple[str, str]] = []
|
|
826
|
+
selected_actions: set[str] = set()
|
|
827
|
+
selected_phenotypes: set[str] = set()
|
|
828
|
+
depth = 0
|
|
829
|
+
while len(selected) < pilot_slots:
|
|
830
|
+
added = False
|
|
831
|
+
for lane_id in lane_order:
|
|
832
|
+
members = by_lane[lane_id]
|
|
833
|
+
if depth >= len(members):
|
|
834
|
+
continue
|
|
835
|
+
action_sha256 = members[depth]
|
|
836
|
+
action = market[action_sha256]
|
|
837
|
+
if (
|
|
838
|
+
action_sha256 in selected_actions
|
|
839
|
+
or action.phenotype_identity_sha256 in selected_phenotypes
|
|
840
|
+
):
|
|
841
|
+
continue
|
|
842
|
+
selected.append((action_sha256, lane_id))
|
|
843
|
+
selected_actions.add(action_sha256)
|
|
844
|
+
selected_phenotypes.add(action.phenotype_identity_sha256)
|
|
845
|
+
added = True
|
|
846
|
+
if len(selected) == pilot_slots:
|
|
847
|
+
break
|
|
848
|
+
if not added and all(depth + 1 >= len(by_lane[key]) for key in lane_order):
|
|
849
|
+
break
|
|
850
|
+
depth += 1
|
|
851
|
+
if len(selected) != pilot_slots:
|
|
852
|
+
raise ValueError("pilot policy cannot provide the requested unique slots")
|
|
853
|
+
return tuple(sorted(selected))
|
|
854
|
+
|
|
855
|
+
|
|
856
|
+
def _branch_stratified_pilot_ids(
|
|
857
|
+
*,
|
|
858
|
+
branch_bindings: tuple[PortfolioRacePolicyBinding, ...],
|
|
859
|
+
branch_requirements: tuple[
|
|
860
|
+
MaterializedActionAllocationRequirement, ...
|
|
861
|
+
],
|
|
862
|
+
market: dict[str, MaterializedActionDescriptor],
|
|
863
|
+
pilot_slots: int,
|
|
864
|
+
) -> tuple[tuple[str, str], ...]:
|
|
865
|
+
"""Select branch-labelled diagnostics before composing shared slates."""
|
|
866
|
+
|
|
867
|
+
if pilot_slots < len(branch_bindings):
|
|
868
|
+
raise ValueError(
|
|
869
|
+
"branch-stratified pilots require at least one slot per branch"
|
|
870
|
+
)
|
|
871
|
+
ordered_by_branch = {
|
|
872
|
+
binding.branch_id: _ordered_action_ids(requirement)
|
|
873
|
+
for binding, requirement in zip(
|
|
874
|
+
branch_bindings,
|
|
875
|
+
branch_requirements,
|
|
876
|
+
strict=True,
|
|
877
|
+
)
|
|
878
|
+
}
|
|
879
|
+
selected: list[tuple[str, str]] = []
|
|
880
|
+
selected_actions: set[str] = set()
|
|
881
|
+
selected_phenotypes: set[str] = set()
|
|
882
|
+
depth = 0
|
|
883
|
+
while len(selected) < pilot_slots:
|
|
884
|
+
added = False
|
|
885
|
+
for binding in branch_bindings:
|
|
886
|
+
candidates = ordered_by_branch[binding.branch_id]
|
|
887
|
+
candidate_index = depth
|
|
888
|
+
while candidate_index < len(candidates):
|
|
889
|
+
action_sha256 = candidates[candidate_index]
|
|
890
|
+
action = market[action_sha256]
|
|
891
|
+
candidate_index += 1
|
|
892
|
+
if (
|
|
893
|
+
action_sha256 in selected_actions
|
|
894
|
+
or action.phenotype_identity_sha256
|
|
895
|
+
in selected_phenotypes
|
|
896
|
+
):
|
|
897
|
+
continue
|
|
898
|
+
selected.append(
|
|
899
|
+
(action_sha256, f"branch:{binding.branch_id}")
|
|
900
|
+
)
|
|
901
|
+
selected_actions.add(action_sha256)
|
|
902
|
+
selected_phenotypes.add(
|
|
903
|
+
action.phenotype_identity_sha256
|
|
904
|
+
)
|
|
905
|
+
added = True
|
|
906
|
+
break
|
|
907
|
+
if len(selected) == pilot_slots:
|
|
908
|
+
break
|
|
909
|
+
if not added:
|
|
910
|
+
break
|
|
911
|
+
depth += 1
|
|
912
|
+
if len(selected) != pilot_slots:
|
|
913
|
+
raise ValueError(
|
|
914
|
+
"branch policies cannot provide the requested unique pilots"
|
|
915
|
+
)
|
|
916
|
+
return tuple(sorted(selected))
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
def _project_branch_pilot_lanes(
|
|
920
|
+
*,
|
|
921
|
+
pilot_pairs: tuple[tuple[str, str], ...],
|
|
922
|
+
branch_bindings: tuple[PortfolioRacePolicyBinding, ...],
|
|
923
|
+
branch_requirements: tuple[
|
|
924
|
+
MaterializedActionAllocationRequirement, ...
|
|
925
|
+
],
|
|
926
|
+
market: dict[str, MaterializedActionDescriptor],
|
|
927
|
+
lane_projection: PortfolioLaneProjectionPort,
|
|
928
|
+
) -> tuple[
|
|
929
|
+
tuple[tuple[str, str], ...],
|
|
930
|
+
tuple[tuple[str, str, str], ...],
|
|
931
|
+
]:
|
|
932
|
+
"""Replace synthetic branch labels with source-trace exchangeability cells.
|
|
933
|
+
|
|
934
|
+
Branch identity is useful for choosing disagreement pilots, but it is not
|
|
935
|
+
evidence that every later action from that branch is exchangeable with the
|
|
936
|
+
pilot. The returned pilot bindings therefore use the same portable,
|
|
937
|
+
outcome-blind trace projection as continuation actions. A separate
|
|
938
|
+
provenance tuple retains the originating branch without allowing it to
|
|
939
|
+
masquerade as a statistical lane.
|
|
940
|
+
"""
|
|
941
|
+
|
|
942
|
+
source_by_branch = {
|
|
943
|
+
binding.branch_id: requirement
|
|
944
|
+
for binding, requirement in zip(
|
|
945
|
+
branch_bindings,
|
|
946
|
+
branch_requirements,
|
|
947
|
+
strict=True,
|
|
948
|
+
)
|
|
949
|
+
}
|
|
950
|
+
trace_by_branch = {
|
|
951
|
+
branch_id: _trace_by_action(requirement)
|
|
952
|
+
for branch_id, requirement in source_by_branch.items()
|
|
953
|
+
}
|
|
954
|
+
projected: list[tuple[str, str]] = []
|
|
955
|
+
provenance: list[tuple[str, str, str]] = []
|
|
956
|
+
for action_sha256, source_lane in pilot_pairs:
|
|
957
|
+
prefix = "branch:"
|
|
958
|
+
if not source_lane.startswith(prefix):
|
|
959
|
+
raise ValueError(
|
|
960
|
+
"branch-stratified pilot lacks source-branch provenance"
|
|
961
|
+
)
|
|
962
|
+
branch_id = source_lane.removeprefix(prefix)
|
|
963
|
+
if branch_id not in source_by_branch:
|
|
964
|
+
raise ValueError("pilot names a branch outside the active race")
|
|
965
|
+
row = trace_by_branch[branch_id].get(action_sha256)
|
|
966
|
+
if row is None:
|
|
967
|
+
raise ValueError(
|
|
968
|
+
"branch-stratified pilot is absent from its source trace"
|
|
969
|
+
)
|
|
970
|
+
lane_id = lane_projection.project(
|
|
971
|
+
row,
|
|
972
|
+
market[action_sha256],
|
|
973
|
+
)
|
|
974
|
+
projected.append((action_sha256, lane_id))
|
|
975
|
+
provenance.append((action_sha256, branch_id, lane_id))
|
|
976
|
+
return (
|
|
977
|
+
tuple(sorted(projected)),
|
|
978
|
+
tuple(sorted(provenance)),
|
|
979
|
+
)
|
|
980
|
+
|
|
981
|
+
|
|
982
|
+
def _compose_branch_action_ids(
|
|
983
|
+
*,
|
|
984
|
+
pilot_action_ids: tuple[str, ...],
|
|
985
|
+
source_requirement: MaterializedActionAllocationRequirement,
|
|
986
|
+
market: dict[str, MaterializedActionDescriptor],
|
|
987
|
+
evaluation_slots: int,
|
|
988
|
+
) -> tuple[str, ...]:
|
|
989
|
+
selected: list[str] = []
|
|
990
|
+
phenotypes: set[str] = set()
|
|
991
|
+
|
|
992
|
+
def consider(action_sha256: str) -> None:
|
|
993
|
+
if len(selected) >= evaluation_slots or action_sha256 in selected:
|
|
994
|
+
return
|
|
995
|
+
action = market[action_sha256]
|
|
996
|
+
if action.phenotype_identity_sha256 in phenotypes:
|
|
997
|
+
return
|
|
998
|
+
selected.append(action_sha256)
|
|
999
|
+
phenotypes.add(action.phenotype_identity_sha256)
|
|
1000
|
+
|
|
1001
|
+
for value in pilot_action_ids:
|
|
1002
|
+
consider(value)
|
|
1003
|
+
for value in _ordered_action_ids(source_requirement):
|
|
1004
|
+
consider(value)
|
|
1005
|
+
if len(selected) < evaluation_slots:
|
|
1006
|
+
for action in sorted(
|
|
1007
|
+
market.values(),
|
|
1008
|
+
key=lambda value: (
|
|
1009
|
+
value.native_rank,
|
|
1010
|
+
value.expert_id,
|
|
1011
|
+
value.operator_id,
|
|
1012
|
+
value.action_sha256,
|
|
1013
|
+
),
|
|
1014
|
+
):
|
|
1015
|
+
consider(action.action_sha256)
|
|
1016
|
+
if len(selected) != evaluation_slots:
|
|
1017
|
+
raise ValueError("proposal market cannot fill a unique-phenotype branch")
|
|
1018
|
+
return tuple(sorted(selected))
|
|
1019
|
+
|
|
1020
|
+
|
|
1021
|
+
@dataclass(frozen=True, slots=True)
|
|
1022
|
+
class PortfolioRaceDisagreementDesign:
|
|
1023
|
+
"""Outcome-blind pilot design over behaviorally distinct complete slates."""
|
|
1024
|
+
|
|
1025
|
+
pilot_pairs: tuple[tuple[str, str], ...]
|
|
1026
|
+
branch_action_sha256s: tuple[tuple[str, tuple[str, ...]], ...]
|
|
1027
|
+
evidence: FrozenJsonObject
|
|
1028
|
+
design_sha256: str = field(init=False)
|
|
1029
|
+
|
|
1030
|
+
def __post_init__(self) -> None:
|
|
1031
|
+
if (
|
|
1032
|
+
type(self.pilot_pairs) is not tuple
|
|
1033
|
+
or self.pilot_pairs
|
|
1034
|
+
!= tuple(sorted(self.pilot_pairs))
|
|
1035
|
+
):
|
|
1036
|
+
raise ValueError("pilot_pairs must be canonical")
|
|
1037
|
+
pilot_ids: list[str] = []
|
|
1038
|
+
for action_sha256, lane_id in self.pilot_pairs:
|
|
1039
|
+
require_sha256(action_sha256, "pilot action_sha256")
|
|
1040
|
+
_require_token(lane_id, name="pilot lane_id")
|
|
1041
|
+
pilot_ids.append(action_sha256)
|
|
1042
|
+
if len(pilot_ids) != len(set(pilot_ids)):
|
|
1043
|
+
raise ValueError("pilot_pairs repeat an action")
|
|
1044
|
+
if (
|
|
1045
|
+
type(self.branch_action_sha256s) is not tuple
|
|
1046
|
+
or not self.branch_action_sha256s
|
|
1047
|
+
or self.branch_action_sha256s
|
|
1048
|
+
!= tuple(
|
|
1049
|
+
sorted(
|
|
1050
|
+
self.branch_action_sha256s,
|
|
1051
|
+
key=lambda value: value[0],
|
|
1052
|
+
)
|
|
1053
|
+
)
|
|
1054
|
+
):
|
|
1055
|
+
raise ValueError(
|
|
1056
|
+
"branch_action_sha256s must be non-empty and canonical"
|
|
1057
|
+
)
|
|
1058
|
+
branch_ids: list[str] = []
|
|
1059
|
+
pilot_set = set(pilot_ids)
|
|
1060
|
+
for branch_id, action_sha256s in self.branch_action_sha256s:
|
|
1061
|
+
_require_token(branch_id, name="designed branch_id")
|
|
1062
|
+
branch_ids.append(branch_id)
|
|
1063
|
+
if (
|
|
1064
|
+
type(action_sha256s) is not tuple
|
|
1065
|
+
or not action_sha256s
|
|
1066
|
+
or action_sha256s
|
|
1067
|
+
!= tuple(sorted(set(action_sha256s)))
|
|
1068
|
+
):
|
|
1069
|
+
raise ValueError(
|
|
1070
|
+
"designed branch actions must be non-empty and canonical"
|
|
1071
|
+
)
|
|
1072
|
+
for action_sha256 in action_sha256s:
|
|
1073
|
+
require_sha256(action_sha256, "designed action_sha256")
|
|
1074
|
+
if not pilot_set.issubset(action_sha256s):
|
|
1075
|
+
raise ValueError("every designed branch must retain each pilot")
|
|
1076
|
+
if len(branch_ids) != len(set(branch_ids)):
|
|
1077
|
+
raise ValueError("designed branch IDs must be unique")
|
|
1078
|
+
if (
|
|
1079
|
+
type(self.evidence) is not FrozenJsonObject
|
|
1080
|
+
or freeze_json(self.evidence) is not self.evidence
|
|
1081
|
+
):
|
|
1082
|
+
raise TypeError("design evidence must be a frozen object")
|
|
1083
|
+
object.__setattr__(
|
|
1084
|
+
self,
|
|
1085
|
+
"design_sha256",
|
|
1086
|
+
_hash(
|
|
1087
|
+
_DISAGREEMENT_DESIGN_DOMAIN,
|
|
1088
|
+
{
|
|
1089
|
+
"schema_version": 1,
|
|
1090
|
+
"pilot_pairs": [
|
|
1091
|
+
{
|
|
1092
|
+
"action_sha256": action_sha256,
|
|
1093
|
+
"lane_id": lane_id,
|
|
1094
|
+
}
|
|
1095
|
+
for action_sha256, lane_id in self.pilot_pairs
|
|
1096
|
+
],
|
|
1097
|
+
"branch_action_sha256s": [
|
|
1098
|
+
{
|
|
1099
|
+
"branch_id": branch_id,
|
|
1100
|
+
"action_sha256s": list(action_sha256s),
|
|
1101
|
+
}
|
|
1102
|
+
for branch_id, action_sha256s
|
|
1103
|
+
in self.branch_action_sha256s
|
|
1104
|
+
],
|
|
1105
|
+
"evidence_sha256": typed_json_sha256(self.evidence),
|
|
1106
|
+
},
|
|
1107
|
+
),
|
|
1108
|
+
)
|
|
1109
|
+
|
|
1110
|
+
def actions_for(self, branch_id: str) -> tuple[str, ...]:
|
|
1111
|
+
_require_token(branch_id, name="branch_id")
|
|
1112
|
+
matches = tuple(
|
|
1113
|
+
action_sha256s
|
|
1114
|
+
for candidate_id, action_sha256s
|
|
1115
|
+
in self.branch_action_sha256s
|
|
1116
|
+
if candidate_id == branch_id
|
|
1117
|
+
)
|
|
1118
|
+
if len(matches) != 1:
|
|
1119
|
+
raise ValueError("branch is absent from disagreement design")
|
|
1120
|
+
return matches[0]
|
|
1121
|
+
|
|
1122
|
+
def to_record(self) -> dict[str, object]:
|
|
1123
|
+
self.__post_init__()
|
|
1124
|
+
return {
|
|
1125
|
+
"schema_version": 1,
|
|
1126
|
+
"pilot_pairs": [
|
|
1127
|
+
{
|
|
1128
|
+
"action_sha256": action_sha256,
|
|
1129
|
+
"lane_id": lane_id,
|
|
1130
|
+
}
|
|
1131
|
+
for action_sha256, lane_id in self.pilot_pairs
|
|
1132
|
+
],
|
|
1133
|
+
"branch_action_sha256s": [
|
|
1134
|
+
{
|
|
1135
|
+
"branch_id": branch_id,
|
|
1136
|
+
"action_sha256s": list(action_sha256s),
|
|
1137
|
+
}
|
|
1138
|
+
for branch_id, action_sha256s
|
|
1139
|
+
in self.branch_action_sha256s
|
|
1140
|
+
],
|
|
1141
|
+
"evidence": thaw_json(self.evidence),
|
|
1142
|
+
"design_sha256": self.design_sha256,
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
|
|
1146
|
+
@runtime_checkable
|
|
1147
|
+
class PortfolioRaceDisagreementPolicyPort(Protocol):
|
|
1148
|
+
"""Design actionable pilots and distinct slates without current outcomes."""
|
|
1149
|
+
|
|
1150
|
+
policy_id: str
|
|
1151
|
+
policy_version: int
|
|
1152
|
+
definition_sha256: str
|
|
1153
|
+
|
|
1154
|
+
def design(
|
|
1155
|
+
self,
|
|
1156
|
+
*,
|
|
1157
|
+
branch_bindings: tuple[PortfolioRacePolicyBinding, ...],
|
|
1158
|
+
branch_requirements: tuple[
|
|
1159
|
+
MaterializedActionAllocationRequirement,
|
|
1160
|
+
...,
|
|
1161
|
+
],
|
|
1162
|
+
market: dict[str, MaterializedActionDescriptor],
|
|
1163
|
+
evaluation_slots: int,
|
|
1164
|
+
maximum_pilot_slots: int,
|
|
1165
|
+
) -> PortfolioRaceDisagreementDesign: ...
|
|
1166
|
+
|
|
1167
|
+
|
|
1168
|
+
def _disagreement_policy_identity(
|
|
1169
|
+
value: PortfolioRaceDisagreementPolicyPort,
|
|
1170
|
+
) -> tuple[str, int, str]:
|
|
1171
|
+
if not isinstance(value, PortfolioRaceDisagreementPolicyPort):
|
|
1172
|
+
raise TypeError(
|
|
1173
|
+
"disagreement policy must implement its application port"
|
|
1174
|
+
)
|
|
1175
|
+
identity = (
|
|
1176
|
+
getattr(value, "policy_id", None),
|
|
1177
|
+
getattr(value, "policy_version", None),
|
|
1178
|
+
getattr(value, "definition_sha256", None),
|
|
1179
|
+
)
|
|
1180
|
+
_require_token(identity[0], name="disagreement policy_id")
|
|
1181
|
+
if type(identity[1]) is not int or identity[1] <= 0:
|
|
1182
|
+
raise ValueError("disagreement policy_version must be positive")
|
|
1183
|
+
require_sha256(identity[2], "disagreement policy definition_sha256")
|
|
1184
|
+
return identity # type: ignore[return-value]
|
|
1185
|
+
|
|
1186
|
+
|
|
1187
|
+
def _representative_binding(
|
|
1188
|
+
bindings: tuple[PortfolioRacePolicyBinding, ...],
|
|
1189
|
+
) -> PortfolioRacePolicyBinding:
|
|
1190
|
+
if not bindings:
|
|
1191
|
+
raise ValueError("an equivalence class needs a representative")
|
|
1192
|
+
return min(
|
|
1193
|
+
bindings,
|
|
1194
|
+
key=lambda value: (-value.prior_mean, value.branch_id),
|
|
1195
|
+
)
|
|
1196
|
+
|
|
1197
|
+
|
|
1198
|
+
def _equivalence_classes(
|
|
1199
|
+
*,
|
|
1200
|
+
bindings: tuple[PortfolioRacePolicyBinding, ...],
|
|
1201
|
+
actions_by_branch: dict[str, tuple[str, ...]],
|
|
1202
|
+
) -> tuple[
|
|
1203
|
+
tuple[
|
|
1204
|
+
PortfolioRacePolicyBinding,
|
|
1205
|
+
tuple[PortfolioRacePolicyBinding, ...],
|
|
1206
|
+
],
|
|
1207
|
+
...,
|
|
1208
|
+
]:
|
|
1209
|
+
groups: dict[
|
|
1210
|
+
tuple[str, ...],
|
|
1211
|
+
list[PortfolioRacePolicyBinding],
|
|
1212
|
+
] = {}
|
|
1213
|
+
for binding in bindings:
|
|
1214
|
+
groups.setdefault(
|
|
1215
|
+
actions_by_branch[binding.branch_id],
|
|
1216
|
+
[],
|
|
1217
|
+
).append(binding)
|
|
1218
|
+
classes = []
|
|
1219
|
+
for members in groups.values():
|
|
1220
|
+
canonical_members = tuple(
|
|
1221
|
+
sorted(members, key=lambda value: value.branch_id)
|
|
1222
|
+
)
|
|
1223
|
+
classes.append(
|
|
1224
|
+
(
|
|
1225
|
+
_representative_binding(canonical_members),
|
|
1226
|
+
canonical_members,
|
|
1227
|
+
)
|
|
1228
|
+
)
|
|
1229
|
+
return tuple(
|
|
1230
|
+
sorted(classes, key=lambda value: value[0].branch_id)
|
|
1231
|
+
)
|
|
1232
|
+
|
|
1233
|
+
|
|
1234
|
+
def _equivalence_class_records(
|
|
1235
|
+
classes: tuple[
|
|
1236
|
+
tuple[
|
|
1237
|
+
PortfolioRacePolicyBinding,
|
|
1238
|
+
tuple[PortfolioRacePolicyBinding, ...],
|
|
1239
|
+
],
|
|
1240
|
+
...,
|
|
1241
|
+
],
|
|
1242
|
+
*,
|
|
1243
|
+
actions_by_branch: dict[str, tuple[str, ...]],
|
|
1244
|
+
) -> list[dict[str, object]]:
|
|
1245
|
+
return [
|
|
1246
|
+
{
|
|
1247
|
+
"representative_branch_id": representative.branch_id,
|
|
1248
|
+
"member_branch_ids": [
|
|
1249
|
+
value.branch_id for value in members
|
|
1250
|
+
],
|
|
1251
|
+
"action_sha256s": list(
|
|
1252
|
+
actions_by_branch[representative.branch_id]
|
|
1253
|
+
),
|
|
1254
|
+
}
|
|
1255
|
+
for representative, members in classes
|
|
1256
|
+
]
|
|
1257
|
+
|
|
1258
|
+
|
|
1259
|
+
def _outcome_blind_route_resolution(
|
|
1260
|
+
*,
|
|
1261
|
+
source_classes: tuple[
|
|
1262
|
+
tuple[
|
|
1263
|
+
PortfolioRacePolicyBinding,
|
|
1264
|
+
tuple[PortfolioRacePolicyBinding, ...],
|
|
1265
|
+
],
|
|
1266
|
+
...,
|
|
1267
|
+
],
|
|
1268
|
+
final_classes: tuple[
|
|
1269
|
+
tuple[
|
|
1270
|
+
PortfolioRacePolicyBinding,
|
|
1271
|
+
tuple[PortfolioRacePolicyBinding, ...],
|
|
1272
|
+
],
|
|
1273
|
+
...,
|
|
1274
|
+
],
|
|
1275
|
+
) -> list[dict[str, object]]:
|
|
1276
|
+
"""Authenticate source-to-retained aliases through exact slate equality."""
|
|
1277
|
+
|
|
1278
|
+
post_pilot_representative: dict[str, str] = {}
|
|
1279
|
+
for representative, members in final_classes:
|
|
1280
|
+
for member in members:
|
|
1281
|
+
post_pilot_representative[member.branch_id] = (
|
|
1282
|
+
representative.branch_id
|
|
1283
|
+
)
|
|
1284
|
+
rows: list[dict[str, object]] = []
|
|
1285
|
+
for source_representative, source_members in source_classes:
|
|
1286
|
+
retained = post_pilot_representative.get(
|
|
1287
|
+
source_representative.branch_id
|
|
1288
|
+
)
|
|
1289
|
+
if retained is None:
|
|
1290
|
+
continue
|
|
1291
|
+
for member in source_members:
|
|
1292
|
+
path: list[str] = []
|
|
1293
|
+
if member.branch_id != source_representative.branch_id:
|
|
1294
|
+
path.append(
|
|
1295
|
+
"identical_complete_action_set_before_pilot"
|
|
1296
|
+
)
|
|
1297
|
+
if source_representative.branch_id != retained:
|
|
1298
|
+
path.append(
|
|
1299
|
+
"identical_complete_action_set_after_frozen_pilot"
|
|
1300
|
+
)
|
|
1301
|
+
if not path:
|
|
1302
|
+
path.append("identity")
|
|
1303
|
+
rows.append(
|
|
1304
|
+
{
|
|
1305
|
+
"source_branch_id": member.branch_id,
|
|
1306
|
+
"representative_branch_id": retained,
|
|
1307
|
+
"equivalence_path": path,
|
|
1308
|
+
}
|
|
1309
|
+
)
|
|
1310
|
+
return sorted(rows, key=lambda value: str(value["source_branch_id"]))
|
|
1311
|
+
|
|
1312
|
+
|
|
1313
|
+
def _symmetric_difference_pilot_ids(
|
|
1314
|
+
*,
|
|
1315
|
+
branch_bindings: tuple[PortfolioRacePolicyBinding, ...],
|
|
1316
|
+
branch_requirements: dict[
|
|
1317
|
+
str,
|
|
1318
|
+
MaterializedActionAllocationRequirement,
|
|
1319
|
+
],
|
|
1320
|
+
complete_action_ids: dict[str, tuple[str, ...]],
|
|
1321
|
+
market: dict[str, MaterializedActionDescriptor],
|
|
1322
|
+
pilot_slots: int,
|
|
1323
|
+
) -> tuple[tuple[str, str], ...]:
|
|
1324
|
+
"""Choose rare branch-disagreement actions, never common actions."""
|
|
1325
|
+
|
|
1326
|
+
if type(pilot_slots) is not int or pilot_slots <= 0:
|
|
1327
|
+
raise ValueError("pilot_slots must be positive")
|
|
1328
|
+
action_sets = tuple(
|
|
1329
|
+
set(complete_action_ids[value.branch_id])
|
|
1330
|
+
for value in branch_bindings
|
|
1331
|
+
)
|
|
1332
|
+
common = set.intersection(*action_sets)
|
|
1333
|
+
frequency: dict[str, int] = {}
|
|
1334
|
+
for action_set in action_sets:
|
|
1335
|
+
for action_sha256 in action_set:
|
|
1336
|
+
frequency[action_sha256] = frequency.get(action_sha256, 0) + 1
|
|
1337
|
+
order_by_branch: dict[str, dict[str, int]] = {}
|
|
1338
|
+
for binding in branch_bindings:
|
|
1339
|
+
source_order = _ordered_action_ids(
|
|
1340
|
+
branch_requirements[binding.branch_id]
|
|
1341
|
+
)
|
|
1342
|
+
ordinal = {
|
|
1343
|
+
action_sha256: index
|
|
1344
|
+
for index, action_sha256 in enumerate(source_order)
|
|
1345
|
+
}
|
|
1346
|
+
order_by_branch[binding.branch_id] = ordinal
|
|
1347
|
+
ranked_by_branch: dict[str, tuple[str, ...]] = {}
|
|
1348
|
+
for binding in branch_bindings:
|
|
1349
|
+
branch_id = binding.branch_id
|
|
1350
|
+
ranked_by_branch[branch_id] = tuple(
|
|
1351
|
+
sorted(
|
|
1352
|
+
(
|
|
1353
|
+
action_sha256
|
|
1354
|
+
for action_sha256
|
|
1355
|
+
in complete_action_ids[branch_id]
|
|
1356
|
+
if action_sha256 not in common
|
|
1357
|
+
),
|
|
1358
|
+
key=lambda action_sha256: (
|
|
1359
|
+
frequency[action_sha256],
|
|
1360
|
+
order_by_branch[branch_id].get(
|
|
1361
|
+
action_sha256,
|
|
1362
|
+
len(market),
|
|
1363
|
+
),
|
|
1364
|
+
action_sha256,
|
|
1365
|
+
),
|
|
1366
|
+
)
|
|
1367
|
+
)
|
|
1368
|
+
selection_order = tuple(
|
|
1369
|
+
sorted(
|
|
1370
|
+
branch_bindings,
|
|
1371
|
+
key=lambda value: (-value.prior_mean, value.branch_id),
|
|
1372
|
+
)
|
|
1373
|
+
)
|
|
1374
|
+
selected: list[tuple[str, str]] = []
|
|
1375
|
+
selected_actions: set[str] = set()
|
|
1376
|
+
selected_phenotypes: set[str] = set()
|
|
1377
|
+
depth = 0
|
|
1378
|
+
while len(selected) < pilot_slots:
|
|
1379
|
+
added = False
|
|
1380
|
+
for binding in selection_order:
|
|
1381
|
+
candidates = ranked_by_branch[binding.branch_id]
|
|
1382
|
+
candidate_index = depth
|
|
1383
|
+
while candidate_index < len(candidates):
|
|
1384
|
+
action_sha256 = candidates[candidate_index]
|
|
1385
|
+
candidate_index += 1
|
|
1386
|
+
action = market[action_sha256]
|
|
1387
|
+
if (
|
|
1388
|
+
action_sha256 in selected_actions
|
|
1389
|
+
or action.phenotype_identity_sha256
|
|
1390
|
+
in selected_phenotypes
|
|
1391
|
+
):
|
|
1392
|
+
continue
|
|
1393
|
+
selected.append(
|
|
1394
|
+
(
|
|
1395
|
+
action_sha256,
|
|
1396
|
+
f"branch:{binding.branch_id}",
|
|
1397
|
+
)
|
|
1398
|
+
)
|
|
1399
|
+
selected_actions.add(action_sha256)
|
|
1400
|
+
selected_phenotypes.add(
|
|
1401
|
+
action.phenotype_identity_sha256
|
|
1402
|
+
)
|
|
1403
|
+
added = True
|
|
1404
|
+
break
|
|
1405
|
+
if len(selected) == pilot_slots:
|
|
1406
|
+
break
|
|
1407
|
+
if not added:
|
|
1408
|
+
break
|
|
1409
|
+
depth += 1
|
|
1410
|
+
if len(selected) != pilot_slots:
|
|
1411
|
+
raise ValueError(
|
|
1412
|
+
"distinct branches cannot provide the requested disagreement pilots"
|
|
1413
|
+
)
|
|
1414
|
+
return tuple(sorted(selected))
|
|
1415
|
+
|
|
1416
|
+
|
|
1417
|
+
@dataclass(frozen=True, slots=True)
|
|
1418
|
+
class SymmetricDifferencePortfolioRacePolicy:
|
|
1419
|
+
"""Collapse equivalent slates and race only actionable disagreement.
|
|
1420
|
+
|
|
1421
|
+
``maximum_pilot_slots`` remains owned by the planner. This policy treats
|
|
1422
|
+
it as a ceiling, searches downward for the largest diagnostic pilot that
|
|
1423
|
+
leaves at least two distinct complete continuations, and emits a zero-pilot
|
|
1424
|
+
deterministic plan when every source slate is behaviorally equivalent.
|
|
1425
|
+
"""
|
|
1426
|
+
|
|
1427
|
+
policy_id: str = SYMMETRIC_DIFFERENCE_PORTFOLIO_RACE_POLICY_ID
|
|
1428
|
+
policy_version: int = SYMMETRIC_DIFFERENCE_PORTFOLIO_RACE_POLICY_VERSION
|
|
1429
|
+
definition_sha256: str = field(init=False)
|
|
1430
|
+
|
|
1431
|
+
def __post_init__(self) -> None:
|
|
1432
|
+
_require_token(self.policy_id, name="disagreement policy_id")
|
|
1433
|
+
if (
|
|
1434
|
+
self.policy_version
|
|
1435
|
+
!= SYMMETRIC_DIFFERENCE_PORTFOLIO_RACE_POLICY_VERSION
|
|
1436
|
+
):
|
|
1437
|
+
raise ValueError("disagreement policy_version is immutable")
|
|
1438
|
+
object.__setattr__(
|
|
1439
|
+
self,
|
|
1440
|
+
"definition_sha256",
|
|
1441
|
+
_hash(
|
|
1442
|
+
_DISAGREEMENT_POLICY_DEFINITION_DOMAIN,
|
|
1443
|
+
{
|
|
1444
|
+
"schema_version": 1,
|
|
1445
|
+
"policy_id": self.policy_id,
|
|
1446
|
+
"policy_version": self.policy_version,
|
|
1447
|
+
"source_equivalence": (
|
|
1448
|
+
"identical_complete_action_sha256_set"
|
|
1449
|
+
),
|
|
1450
|
+
"representative": (
|
|
1451
|
+
"higher_prior_mean_then_branch_id"
|
|
1452
|
+
),
|
|
1453
|
+
"pilot_support": "source_symmetric_difference_only",
|
|
1454
|
+
"pilot_cardinality": (
|
|
1455
|
+
"largest_at_most_configured_maximum_preserving_"
|
|
1456
|
+
"multiple_complete_continuations"
|
|
1457
|
+
),
|
|
1458
|
+
"no_actionable_disagreement": (
|
|
1459
|
+
"zero_pilot_deterministic_representative"
|
|
1460
|
+
),
|
|
1461
|
+
"collapsed_route_resolution": (
|
|
1462
|
+
"authenticated_exact_action_set_equivalence_chain"
|
|
1463
|
+
),
|
|
1464
|
+
"candidate_outcomes_observed": False,
|
|
1465
|
+
"workload_model_provider_branches": False,
|
|
1466
|
+
},
|
|
1467
|
+
),
|
|
1468
|
+
)
|
|
1469
|
+
|
|
1470
|
+
def design(
|
|
1471
|
+
self,
|
|
1472
|
+
*,
|
|
1473
|
+
branch_bindings: tuple[PortfolioRacePolicyBinding, ...],
|
|
1474
|
+
branch_requirements: tuple[
|
|
1475
|
+
MaterializedActionAllocationRequirement,
|
|
1476
|
+
...,
|
|
1477
|
+
],
|
|
1478
|
+
market: dict[str, MaterializedActionDescriptor],
|
|
1479
|
+
evaluation_slots: int,
|
|
1480
|
+
maximum_pilot_slots: int,
|
|
1481
|
+
) -> PortfolioRaceDisagreementDesign:
|
|
1482
|
+
self.__post_init__()
|
|
1483
|
+
if (
|
|
1484
|
+
type(branch_bindings) is not tuple
|
|
1485
|
+
or len(branch_bindings) < 2
|
|
1486
|
+
or len(branch_bindings) != len(branch_requirements)
|
|
1487
|
+
):
|
|
1488
|
+
raise ValueError("disagreement design needs aligned branches")
|
|
1489
|
+
if (
|
|
1490
|
+
type(evaluation_slots) is not int
|
|
1491
|
+
or type(maximum_pilot_slots) is not int
|
|
1492
|
+
or not 0 < maximum_pilot_slots < evaluation_slots
|
|
1493
|
+
):
|
|
1494
|
+
raise ValueError(
|
|
1495
|
+
"maximum_pilot_slots must leave continuation capacity"
|
|
1496
|
+
)
|
|
1497
|
+
source_by_branch = {
|
|
1498
|
+
binding.branch_id: requirement
|
|
1499
|
+
for binding, requirement in zip(
|
|
1500
|
+
branch_bindings,
|
|
1501
|
+
branch_requirements,
|
|
1502
|
+
strict=True,
|
|
1503
|
+
)
|
|
1504
|
+
}
|
|
1505
|
+
raw_actions = {
|
|
1506
|
+
binding.branch_id: _compose_branch_action_ids(
|
|
1507
|
+
pilot_action_ids=(),
|
|
1508
|
+
source_requirement=source_by_branch[binding.branch_id],
|
|
1509
|
+
market=market,
|
|
1510
|
+
evaluation_slots=evaluation_slots,
|
|
1511
|
+
)
|
|
1512
|
+
for binding in branch_bindings
|
|
1513
|
+
}
|
|
1514
|
+
source_classes = _equivalence_classes(
|
|
1515
|
+
bindings=branch_bindings,
|
|
1516
|
+
actions_by_branch=raw_actions,
|
|
1517
|
+
)
|
|
1518
|
+
active = tuple(value[0] for value in source_classes)
|
|
1519
|
+
source_class_records = _equivalence_class_records(
|
|
1520
|
+
source_classes,
|
|
1521
|
+
actions_by_branch=raw_actions,
|
|
1522
|
+
)
|
|
1523
|
+
attempts: list[dict[str, object]] = []
|
|
1524
|
+
if len(active) == 1:
|
|
1525
|
+
representative = active[0]
|
|
1526
|
+
retained_classes = (
|
|
1527
|
+
(representative, (representative,)),
|
|
1528
|
+
)
|
|
1529
|
+
return PortfolioRaceDisagreementDesign(
|
|
1530
|
+
pilot_pairs=(),
|
|
1531
|
+
branch_action_sha256s=(
|
|
1532
|
+
(
|
|
1533
|
+
representative.branch_id,
|
|
1534
|
+
raw_actions[representative.branch_id],
|
|
1535
|
+
),
|
|
1536
|
+
),
|
|
1537
|
+
evidence=freeze_json(
|
|
1538
|
+
{
|
|
1539
|
+
"policy_definition_sha256": self.definition_sha256,
|
|
1540
|
+
"decision": "equivalent_source_bypass",
|
|
1541
|
+
"source_equivalence_classes": source_class_records,
|
|
1542
|
+
"retained_equivalence_classes": (
|
|
1543
|
+
_equivalence_class_records(
|
|
1544
|
+
retained_classes,
|
|
1545
|
+
actions_by_branch=raw_actions,
|
|
1546
|
+
)
|
|
1547
|
+
),
|
|
1548
|
+
"outcome_blind_route_resolution": (
|
|
1549
|
+
_outcome_blind_route_resolution(
|
|
1550
|
+
source_classes=source_classes,
|
|
1551
|
+
final_classes=retained_classes,
|
|
1552
|
+
)
|
|
1553
|
+
),
|
|
1554
|
+
"configured_maximum_pilot_slots": (
|
|
1555
|
+
maximum_pilot_slots
|
|
1556
|
+
),
|
|
1557
|
+
"effective_pilot_slots": 0,
|
|
1558
|
+
"candidate_outcomes_observed": False,
|
|
1559
|
+
"workload_model_provider_branches": False,
|
|
1560
|
+
}
|
|
1561
|
+
),
|
|
1562
|
+
)
|
|
1563
|
+
|
|
1564
|
+
while len(active) >= 2:
|
|
1565
|
+
largest = min(
|
|
1566
|
+
maximum_pilot_slots,
|
|
1567
|
+
len(active),
|
|
1568
|
+
evaluation_slots - 1,
|
|
1569
|
+
)
|
|
1570
|
+
retained: tuple[PortfolioRacePolicyBinding, ...] | None = None
|
|
1571
|
+
retained_pairs: tuple[tuple[str, str], ...] = ()
|
|
1572
|
+
retained_actions: dict[str, tuple[str, ...]] = {}
|
|
1573
|
+
for requested_slots in range(largest, 0, -1):
|
|
1574
|
+
try:
|
|
1575
|
+
pilot_pairs = _symmetric_difference_pilot_ids(
|
|
1576
|
+
branch_bindings=active,
|
|
1577
|
+
branch_requirements=source_by_branch,
|
|
1578
|
+
complete_action_ids=raw_actions,
|
|
1579
|
+
market=market,
|
|
1580
|
+
pilot_slots=requested_slots,
|
|
1581
|
+
)
|
|
1582
|
+
except ValueError:
|
|
1583
|
+
attempts.append(
|
|
1584
|
+
{
|
|
1585
|
+
"active_branch_ids": [
|
|
1586
|
+
value.branch_id for value in active
|
|
1587
|
+
],
|
|
1588
|
+
"requested_pilot_slots": requested_slots,
|
|
1589
|
+
"pilot_action_sha256s": [],
|
|
1590
|
+
"distinct_complete_continuations": None,
|
|
1591
|
+
"reason": (
|
|
1592
|
+
"insufficient_unique_disagreement_phenotypes"
|
|
1593
|
+
),
|
|
1594
|
+
}
|
|
1595
|
+
)
|
|
1596
|
+
continue
|
|
1597
|
+
pilot_ids = tuple(value[0] for value in pilot_pairs)
|
|
1598
|
+
composed = {
|
|
1599
|
+
binding.branch_id: _compose_branch_action_ids(
|
|
1600
|
+
pilot_action_ids=pilot_ids,
|
|
1601
|
+
source_requirement=source_by_branch[
|
|
1602
|
+
binding.branch_id
|
|
1603
|
+
],
|
|
1604
|
+
market=market,
|
|
1605
|
+
evaluation_slots=evaluation_slots,
|
|
1606
|
+
)
|
|
1607
|
+
for binding in active
|
|
1608
|
+
}
|
|
1609
|
+
final_classes = _equivalence_classes(
|
|
1610
|
+
bindings=active,
|
|
1611
|
+
actions_by_branch=composed,
|
|
1612
|
+
)
|
|
1613
|
+
attempts.append(
|
|
1614
|
+
{
|
|
1615
|
+
"active_branch_ids": [
|
|
1616
|
+
value.branch_id for value in active
|
|
1617
|
+
],
|
|
1618
|
+
"requested_pilot_slots": requested_slots,
|
|
1619
|
+
"pilot_action_sha256s": list(pilot_ids),
|
|
1620
|
+
"distinct_complete_continuations": len(
|
|
1621
|
+
final_classes
|
|
1622
|
+
),
|
|
1623
|
+
}
|
|
1624
|
+
)
|
|
1625
|
+
if len(final_classes) >= 2:
|
|
1626
|
+
retained = tuple(
|
|
1627
|
+
value[0] for value in final_classes
|
|
1628
|
+
)
|
|
1629
|
+
retained_pairs = pilot_pairs
|
|
1630
|
+
retained_actions = {
|
|
1631
|
+
representative.branch_id: composed[
|
|
1632
|
+
representative.branch_id
|
|
1633
|
+
]
|
|
1634
|
+
for representative in retained
|
|
1635
|
+
}
|
|
1636
|
+
break
|
|
1637
|
+
if retained is None:
|
|
1638
|
+
break
|
|
1639
|
+
return PortfolioRaceDisagreementDesign(
|
|
1640
|
+
pilot_pairs=retained_pairs,
|
|
1641
|
+
branch_action_sha256s=tuple(
|
|
1642
|
+
sorted(retained_actions.items())
|
|
1643
|
+
),
|
|
1644
|
+
evidence=freeze_json(
|
|
1645
|
+
{
|
|
1646
|
+
"policy_definition_sha256": (
|
|
1647
|
+
self.definition_sha256
|
|
1648
|
+
),
|
|
1649
|
+
"decision": "actionable_disagreement_race",
|
|
1650
|
+
"source_equivalence_classes": (
|
|
1651
|
+
source_class_records
|
|
1652
|
+
),
|
|
1653
|
+
"retained_equivalence_classes": (
|
|
1654
|
+
_equivalence_class_records(
|
|
1655
|
+
final_classes,
|
|
1656
|
+
actions_by_branch=composed,
|
|
1657
|
+
)
|
|
1658
|
+
),
|
|
1659
|
+
"outcome_blind_route_resolution": (
|
|
1660
|
+
_outcome_blind_route_resolution(
|
|
1661
|
+
source_classes=source_classes,
|
|
1662
|
+
final_classes=final_classes,
|
|
1663
|
+
)
|
|
1664
|
+
),
|
|
1665
|
+
"pilot_search_attempts": attempts,
|
|
1666
|
+
"configured_maximum_pilot_slots": (
|
|
1667
|
+
maximum_pilot_slots
|
|
1668
|
+
),
|
|
1669
|
+
"effective_pilot_slots": len(
|
|
1670
|
+
retained_pairs
|
|
1671
|
+
),
|
|
1672
|
+
"retained_branch_ids": [
|
|
1673
|
+
value.branch_id for value in retained
|
|
1674
|
+
],
|
|
1675
|
+
"candidate_outcomes_observed": False,
|
|
1676
|
+
"workload_model_provider_branches": False,
|
|
1677
|
+
}
|
|
1678
|
+
),
|
|
1679
|
+
)
|
|
1680
|
+
|
|
1681
|
+
representative = _representative_binding(active)
|
|
1682
|
+
representative_source_classes = tuple(
|
|
1683
|
+
value
|
|
1684
|
+
for value in source_classes
|
|
1685
|
+
if value[0].branch_id == representative.branch_id
|
|
1686
|
+
)
|
|
1687
|
+
retained_classes = ((representative, (representative,)),)
|
|
1688
|
+
return PortfolioRaceDisagreementDesign(
|
|
1689
|
+
pilot_pairs=(),
|
|
1690
|
+
branch_action_sha256s=(
|
|
1691
|
+
(
|
|
1692
|
+
representative.branch_id,
|
|
1693
|
+
raw_actions[representative.branch_id],
|
|
1694
|
+
),
|
|
1695
|
+
),
|
|
1696
|
+
evidence=freeze_json(
|
|
1697
|
+
{
|
|
1698
|
+
"policy_definition_sha256": self.definition_sha256,
|
|
1699
|
+
"decision": "no_actionable_pilot_bypass",
|
|
1700
|
+
"source_equivalence_classes": source_class_records,
|
|
1701
|
+
"retained_equivalence_classes": (
|
|
1702
|
+
_equivalence_class_records(
|
|
1703
|
+
retained_classes,
|
|
1704
|
+
actions_by_branch=raw_actions,
|
|
1705
|
+
)
|
|
1706
|
+
),
|
|
1707
|
+
"outcome_blind_route_resolution": (
|
|
1708
|
+
_outcome_blind_route_resolution(
|
|
1709
|
+
source_classes=representative_source_classes,
|
|
1710
|
+
final_classes=retained_classes,
|
|
1711
|
+
)
|
|
1712
|
+
),
|
|
1713
|
+
"pilot_search_attempts": attempts,
|
|
1714
|
+
"configured_maximum_pilot_slots": maximum_pilot_slots,
|
|
1715
|
+
"effective_pilot_slots": 0,
|
|
1716
|
+
"candidate_outcomes_observed": False,
|
|
1717
|
+
"workload_model_provider_branches": False,
|
|
1718
|
+
}
|
|
1719
|
+
),
|
|
1720
|
+
)
|
|
1721
|
+
|
|
1722
|
+
|
|
1723
|
+
@dataclass(frozen=True, slots=True)
|
|
1724
|
+
class PrecommittedPortfolioRacePlanner:
|
|
1725
|
+
"""Freeze a lane-stratified pilot and N complete portfolio branches."""
|
|
1726
|
+
|
|
1727
|
+
branch_bindings: tuple[PortfolioRacePolicyBinding, ...]
|
|
1728
|
+
pilot_policy: MaterializedActionAllocationPolicyPort | None = field(
|
|
1729
|
+
repr=False,
|
|
1730
|
+
compare=False,
|
|
1731
|
+
)
|
|
1732
|
+
pilot_slots: int
|
|
1733
|
+
disagreement_policy: PortfolioRaceDisagreementPolicyPort | None = (
|
|
1734
|
+
field(default=None, repr=False, compare=False)
|
|
1735
|
+
)
|
|
1736
|
+
prior_projection: PortfolioRacePriorProjectionPort | None = field(
|
|
1737
|
+
default=None,
|
|
1738
|
+
repr=False,
|
|
1739
|
+
compare=False,
|
|
1740
|
+
)
|
|
1741
|
+
lane_projection: PortfolioLaneProjectionPort = field(
|
|
1742
|
+
default_factory=TraceFieldPortfolioLaneProjection,
|
|
1743
|
+
repr=False,
|
|
1744
|
+
compare=False,
|
|
1745
|
+
)
|
|
1746
|
+
planner_id: str = PRECOMMITTED_PORTFOLIO_RACE_PLANNER_ID
|
|
1747
|
+
planner_version: int = PRECOMMITTED_PORTFOLIO_RACE_PLANNER_VERSION
|
|
1748
|
+
definition_sha256: str = field(init=False)
|
|
1749
|
+
|
|
1750
|
+
def __post_init__(self) -> None:
|
|
1751
|
+
if (
|
|
1752
|
+
type(self.branch_bindings) is not tuple
|
|
1753
|
+
or len(self.branch_bindings) < 2
|
|
1754
|
+
):
|
|
1755
|
+
raise ValueError("a portfolio race needs at least two branches")
|
|
1756
|
+
for value in self.branch_bindings:
|
|
1757
|
+
if type(value) is not PortfolioRacePolicyBinding:
|
|
1758
|
+
raise TypeError("branch bindings must be exact")
|
|
1759
|
+
value.__post_init__()
|
|
1760
|
+
branch_ids = tuple(value.branch_id for value in self.branch_bindings)
|
|
1761
|
+
if branch_ids != tuple(sorted(set(branch_ids))):
|
|
1762
|
+
raise ValueError("branch bindings must use canonical unique IDs")
|
|
1763
|
+
pilot_identity = (
|
|
1764
|
+
None
|
|
1765
|
+
if self.pilot_policy is None
|
|
1766
|
+
else _policy_identity(self.pilot_policy)
|
|
1767
|
+
)
|
|
1768
|
+
disagreement_identity = (
|
|
1769
|
+
None
|
|
1770
|
+
if self.disagreement_policy is None
|
|
1771
|
+
else _disagreement_policy_identity(
|
|
1772
|
+
self.disagreement_policy
|
|
1773
|
+
)
|
|
1774
|
+
)
|
|
1775
|
+
prior_identity = (
|
|
1776
|
+
None
|
|
1777
|
+
if self.prior_projection is None
|
|
1778
|
+
else _prior_projection_identity(self.prior_projection)
|
|
1779
|
+
)
|
|
1780
|
+
if (
|
|
1781
|
+
self.disagreement_policy is not None
|
|
1782
|
+
and self.pilot_policy is not None
|
|
1783
|
+
):
|
|
1784
|
+
raise ValueError(
|
|
1785
|
+
"disagreement-aware design replaces an injected pilot policy"
|
|
1786
|
+
)
|
|
1787
|
+
if type(self.pilot_slots) is not int or self.pilot_slots <= 0:
|
|
1788
|
+
raise ValueError("pilot_slots must be positive")
|
|
1789
|
+
lane_identity = _lane_projection_identity(self.lane_projection)
|
|
1790
|
+
_require_token(self.planner_id, name="planner_id")
|
|
1791
|
+
if self.planner_version != PRECOMMITTED_PORTFOLIO_RACE_PLANNER_VERSION:
|
|
1792
|
+
raise ValueError("planner_version is immutable")
|
|
1793
|
+
object.__setattr__(
|
|
1794
|
+
self,
|
|
1795
|
+
"definition_sha256",
|
|
1796
|
+
_hash(
|
|
1797
|
+
_PLANNER_DEFINITION_DOMAIN,
|
|
1798
|
+
{
|
|
1799
|
+
"schema_version": 1,
|
|
1800
|
+
"planner_id": self.planner_id,
|
|
1801
|
+
"planner_version": self.planner_version,
|
|
1802
|
+
"branch_policies": [
|
|
1803
|
+
value.identity_record()
|
|
1804
|
+
for value in self.branch_bindings
|
|
1805
|
+
],
|
|
1806
|
+
"pilot_policy": {
|
|
1807
|
+
"mode": (
|
|
1808
|
+
"branch_stratified"
|
|
1809
|
+
if pilot_identity is None
|
|
1810
|
+
else "injected_policy_lane_stratified"
|
|
1811
|
+
),
|
|
1812
|
+
"policy_id": (
|
|
1813
|
+
None
|
|
1814
|
+
if pilot_identity is None
|
|
1815
|
+
else pilot_identity[0]
|
|
1816
|
+
),
|
|
1817
|
+
"policy_version": (
|
|
1818
|
+
None
|
|
1819
|
+
if pilot_identity is None
|
|
1820
|
+
else pilot_identity[1]
|
|
1821
|
+
),
|
|
1822
|
+
"definition_sha256": (
|
|
1823
|
+
None
|
|
1824
|
+
if pilot_identity is None
|
|
1825
|
+
else pilot_identity[2]
|
|
1826
|
+
),
|
|
1827
|
+
},
|
|
1828
|
+
"pilot_slots": self.pilot_slots,
|
|
1829
|
+
"disagreement_policy": (
|
|
1830
|
+
None
|
|
1831
|
+
if disagreement_identity is None
|
|
1832
|
+
else {
|
|
1833
|
+
"policy_id": disagreement_identity[0],
|
|
1834
|
+
"policy_version": disagreement_identity[1],
|
|
1835
|
+
"definition_sha256": disagreement_identity[2],
|
|
1836
|
+
}
|
|
1837
|
+
),
|
|
1838
|
+
"prior_projection": (
|
|
1839
|
+
None
|
|
1840
|
+
if prior_identity is None
|
|
1841
|
+
else {
|
|
1842
|
+
"projection_id": prior_identity[0],
|
|
1843
|
+
"projection_version": prior_identity[1],
|
|
1844
|
+
"definition_sha256": prior_identity[2],
|
|
1845
|
+
}
|
|
1846
|
+
),
|
|
1847
|
+
"prior_projection_timing": (
|
|
1848
|
+
"before_disagreement_equivalence_resolution"
|
|
1849
|
+
),
|
|
1850
|
+
"pilot_provenance_projection_scope": (
|
|
1851
|
+
"full_frozen_source_market_before_branch_collapse"
|
|
1852
|
+
),
|
|
1853
|
+
"lane_projection": {
|
|
1854
|
+
"projection_id": lane_identity[0],
|
|
1855
|
+
"projection_version": lane_identity[1],
|
|
1856
|
+
"definition_sha256": lane_identity[2],
|
|
1857
|
+
},
|
|
1858
|
+
"all_complete_branches_frozen_before_pilot": True,
|
|
1859
|
+
"outcome_conditioned_regeneration": False,
|
|
1860
|
+
"workload_model_provider_branches": False,
|
|
1861
|
+
},
|
|
1862
|
+
),
|
|
1863
|
+
)
|
|
1864
|
+
|
|
1865
|
+
async def plan(
|
|
1866
|
+
self,
|
|
1867
|
+
request: ResidualPortfolioDecisionRequest,
|
|
1868
|
+
proposals: tuple[MaterializedActionProposalBatch, ...],
|
|
1869
|
+
) -> SequentialAllocationPlanPort:
|
|
1870
|
+
self.__post_init__()
|
|
1871
|
+
if type(request) is not ResidualPortfolioDecisionRequest:
|
|
1872
|
+
raise TypeError("request must be exact")
|
|
1873
|
+
request.__post_init__()
|
|
1874
|
+
if not 0 < self.pilot_slots < request.evaluation_slots:
|
|
1875
|
+
raise ValueError("pilot_slots must leave a continuation wave")
|
|
1876
|
+
if type(proposals) is not tuple or not proposals:
|
|
1877
|
+
raise ValueError("proposals must be a non-empty exact tuple")
|
|
1878
|
+
for proposal in proposals:
|
|
1879
|
+
if type(proposal) is not MaterializedActionProposalBatch:
|
|
1880
|
+
raise TypeError("proposals must contain exact batches")
|
|
1881
|
+
proposal.__post_init__()
|
|
1882
|
+
proposal.require_request(request)
|
|
1883
|
+
if self.pilot_policy is None:
|
|
1884
|
+
branch_sources = tuple(
|
|
1885
|
+
await asyncio.gather(
|
|
1886
|
+
*(
|
|
1887
|
+
value.policy.require(request, proposals)
|
|
1888
|
+
for value in self.branch_bindings
|
|
1889
|
+
)
|
|
1890
|
+
)
|
|
1891
|
+
)
|
|
1892
|
+
requirements = branch_sources
|
|
1893
|
+
pilot_source = None
|
|
1894
|
+
else:
|
|
1895
|
+
requirements = tuple(
|
|
1896
|
+
await asyncio.gather(
|
|
1897
|
+
self.pilot_policy.require(request, proposals),
|
|
1898
|
+
*(
|
|
1899
|
+
value.policy.require(request, proposals)
|
|
1900
|
+
for value in self.branch_bindings
|
|
1901
|
+
),
|
|
1902
|
+
)
|
|
1903
|
+
)
|
|
1904
|
+
pilot_source = requirements[0]
|
|
1905
|
+
branch_sources = requirements[1:]
|
|
1906
|
+
for requirement in requirements:
|
|
1907
|
+
if type(requirement) is not MaterializedActionAllocationRequirement:
|
|
1908
|
+
raise TypeError("allocation policy returned a foreign requirement")
|
|
1909
|
+
requirement.__post_init__()
|
|
1910
|
+
if (
|
|
1911
|
+
requirement.residual_request_sha256
|
|
1912
|
+
!= request.request_sha256
|
|
1913
|
+
):
|
|
1914
|
+
raise ValueError("allocation policy targeted another request")
|
|
1915
|
+
proposal_sha256s = tuple(
|
|
1916
|
+
sorted(value.proposal_sha256 for value in proposals)
|
|
1917
|
+
)
|
|
1918
|
+
if any(
|
|
1919
|
+
value.proposal_sha256s != proposal_sha256s
|
|
1920
|
+
for value in requirements
|
|
1921
|
+
):
|
|
1922
|
+
raise ValueError("allocation policies saw different proposal markets")
|
|
1923
|
+
market = _action_market(proposals)
|
|
1924
|
+
source_by_branch = {
|
|
1925
|
+
binding.branch_id: source
|
|
1926
|
+
for binding, source in zip(
|
|
1927
|
+
self.branch_bindings,
|
|
1928
|
+
branch_sources,
|
|
1929
|
+
strict=True,
|
|
1930
|
+
)
|
|
1931
|
+
}
|
|
1932
|
+
projected_prior_by_branch = {
|
|
1933
|
+
binding.branch_id: (
|
|
1934
|
+
binding.prior_mean
|
|
1935
|
+
if self.prior_projection is None
|
|
1936
|
+
else self.prior_projection.project(
|
|
1937
|
+
request,
|
|
1938
|
+
binding,
|
|
1939
|
+
source_by_branch[binding.branch_id],
|
|
1940
|
+
)
|
|
1941
|
+
)
|
|
1942
|
+
for binding in self.branch_bindings
|
|
1943
|
+
}
|
|
1944
|
+
effective_branch_bindings = tuple(
|
|
1945
|
+
PortfolioRacePolicyBinding(
|
|
1946
|
+
branch_id=binding.branch_id,
|
|
1947
|
+
policy=binding.policy,
|
|
1948
|
+
prior_mean=projected_prior_by_branch[binding.branch_id],
|
|
1949
|
+
)
|
|
1950
|
+
for binding in self.branch_bindings
|
|
1951
|
+
)
|
|
1952
|
+
disagreement_design = (
|
|
1953
|
+
None
|
|
1954
|
+
if self.disagreement_policy is None
|
|
1955
|
+
else self.disagreement_policy.design(
|
|
1956
|
+
branch_bindings=effective_branch_bindings,
|
|
1957
|
+
branch_requirements=branch_sources,
|
|
1958
|
+
market=market,
|
|
1959
|
+
evaluation_slots=request.evaluation_slots,
|
|
1960
|
+
maximum_pilot_slots=self.pilot_slots,
|
|
1961
|
+
)
|
|
1962
|
+
)
|
|
1963
|
+
if (
|
|
1964
|
+
disagreement_design is not None
|
|
1965
|
+
and type(disagreement_design)
|
|
1966
|
+
is not PortfolioRaceDisagreementDesign
|
|
1967
|
+
):
|
|
1968
|
+
raise TypeError(
|
|
1969
|
+
"disagreement policy returned a foreign design"
|
|
1970
|
+
)
|
|
1971
|
+
if disagreement_design is not None:
|
|
1972
|
+
disagreement_design.__post_init__()
|
|
1973
|
+
if disagreement_design is None:
|
|
1974
|
+
active_bindings = effective_branch_bindings
|
|
1975
|
+
active_sources = branch_sources
|
|
1976
|
+
raw_pilot_pairs = (
|
|
1977
|
+
_branch_stratified_pilot_ids(
|
|
1978
|
+
branch_bindings=active_bindings,
|
|
1979
|
+
branch_requirements=active_sources,
|
|
1980
|
+
market=market,
|
|
1981
|
+
pilot_slots=self.pilot_slots,
|
|
1982
|
+
)
|
|
1983
|
+
if pilot_source is None
|
|
1984
|
+
else _stratified_pilot_ids(
|
|
1985
|
+
requirement=pilot_source,
|
|
1986
|
+
market=market,
|
|
1987
|
+
lane_projection=self.lane_projection,
|
|
1988
|
+
pilot_slots=self.pilot_slots,
|
|
1989
|
+
)
|
|
1990
|
+
)
|
|
1991
|
+
else:
|
|
1992
|
+
designed_branch_ids = {
|
|
1993
|
+
value[0]
|
|
1994
|
+
for value in disagreement_design.branch_action_sha256s
|
|
1995
|
+
}
|
|
1996
|
+
active_bindings = tuple(
|
|
1997
|
+
value
|
|
1998
|
+
for value in effective_branch_bindings
|
|
1999
|
+
if value.branch_id in designed_branch_ids
|
|
2000
|
+
)
|
|
2001
|
+
active_sources = tuple(
|
|
2002
|
+
source_by_branch[value.branch_id]
|
|
2003
|
+
for value in active_bindings
|
|
2004
|
+
)
|
|
2005
|
+
raw_pilot_pairs = disagreement_design.pilot_pairs
|
|
2006
|
+
if pilot_source is None:
|
|
2007
|
+
projection_bindings = (
|
|
2008
|
+
effective_branch_bindings
|
|
2009
|
+
if disagreement_design is not None
|
|
2010
|
+
else active_bindings
|
|
2011
|
+
)
|
|
2012
|
+
projection_sources = (
|
|
2013
|
+
branch_sources
|
|
2014
|
+
if disagreement_design is not None
|
|
2015
|
+
else active_sources
|
|
2016
|
+
)
|
|
2017
|
+
pilot_pairs, pilot_source_attribution = (
|
|
2018
|
+
_project_branch_pilot_lanes(
|
|
2019
|
+
pilot_pairs=raw_pilot_pairs,
|
|
2020
|
+
branch_bindings=projection_bindings,
|
|
2021
|
+
branch_requirements=projection_sources,
|
|
2022
|
+
market=market,
|
|
2023
|
+
lane_projection=self.lane_projection,
|
|
2024
|
+
)
|
|
2025
|
+
)
|
|
2026
|
+
else:
|
|
2027
|
+
pilot_pairs = raw_pilot_pairs
|
|
2028
|
+
pilot_source_attribution = tuple(
|
|
2029
|
+
(
|
|
2030
|
+
action_sha256,
|
|
2031
|
+
"injected_pilot_policy",
|
|
2032
|
+
lane_id,
|
|
2033
|
+
)
|
|
2034
|
+
for action_sha256, lane_id in pilot_pairs
|
|
2035
|
+
)
|
|
2036
|
+
prior_by_branch = {
|
|
2037
|
+
binding.branch_id: binding.prior_mean
|
|
2038
|
+
for binding in active_bindings
|
|
2039
|
+
}
|
|
2040
|
+
pilot_ids = tuple(value[0] for value in pilot_pairs)
|
|
2041
|
+
pilot_source_sha256s = (
|
|
2042
|
+
tuple(
|
|
2043
|
+
value.requirement_sha256 for value in branch_sources
|
|
2044
|
+
)
|
|
2045
|
+
if pilot_source is None
|
|
2046
|
+
else (pilot_source.requirement_sha256,)
|
|
2047
|
+
)
|
|
2048
|
+
pilot_definition_sha256 = _hash(
|
|
2049
|
+
_PILOT_REQUIREMENT_DEFINITION_DOMAIN,
|
|
2050
|
+
{
|
|
2051
|
+
"planner_definition_sha256": self.definition_sha256,
|
|
2052
|
+
"source_requirement_sha256s": list(
|
|
2053
|
+
pilot_source_sha256s
|
|
2054
|
+
),
|
|
2055
|
+
"mode": (
|
|
2056
|
+
"symmetric_difference_adaptive"
|
|
2057
|
+
if disagreement_design is not None
|
|
2058
|
+
else (
|
|
2059
|
+
"branch_stratified"
|
|
2060
|
+
if pilot_source is None
|
|
2061
|
+
else "injected_policy_lane_stratified"
|
|
2062
|
+
)
|
|
2063
|
+
),
|
|
2064
|
+
"configured_maximum_pilot_slots": self.pilot_slots,
|
|
2065
|
+
"effective_pilot_slots": len(pilot_pairs),
|
|
2066
|
+
"pilot_lane_bindings": [
|
|
2067
|
+
{"action_sha256": action, "lane_id": lane}
|
|
2068
|
+
for action, lane in pilot_pairs
|
|
2069
|
+
],
|
|
2070
|
+
},
|
|
2071
|
+
)
|
|
2072
|
+
pilot_requirement = MaterializedActionAllocationRequirement(
|
|
2073
|
+
policy_id="precommitted_portfolio_race_pilot",
|
|
2074
|
+
policy_version=1,
|
|
2075
|
+
policy_definition_sha256=pilot_definition_sha256,
|
|
2076
|
+
residual_request_sha256=request.request_sha256,
|
|
2077
|
+
proposal_sha256s=proposal_sha256s,
|
|
2078
|
+
required_action_sha256s=pilot_ids,
|
|
2079
|
+
candidate_outcomes_observed=False,
|
|
2080
|
+
evidence=freeze_json(
|
|
2081
|
+
{
|
|
2082
|
+
"selection_trace": [
|
|
2083
|
+
{
|
|
2084
|
+
"ordinal": ordinal,
|
|
2085
|
+
"action_sha256": action_sha256,
|
|
2086
|
+
"allocation_kind": "portfolio_race_pilot",
|
|
2087
|
+
"source_lane": lane_id,
|
|
2088
|
+
"source_branch_id": next(
|
|
2089
|
+
source_branch_id
|
|
2090
|
+
for (
|
|
2091
|
+
source_action_sha256,
|
|
2092
|
+
source_branch_id,
|
|
2093
|
+
_projected_lane_id,
|
|
2094
|
+
) in pilot_source_attribution
|
|
2095
|
+
if source_action_sha256 == action_sha256
|
|
2096
|
+
),
|
|
2097
|
+
"candidate_outcomes_observed": False,
|
|
2098
|
+
}
|
|
2099
|
+
for ordinal, (action_sha256, lane_id) in enumerate(
|
|
2100
|
+
pilot_pairs,
|
|
2101
|
+
start=1,
|
|
2102
|
+
)
|
|
2103
|
+
],
|
|
2104
|
+
"source_requirement_sha256s": list(
|
|
2105
|
+
pilot_source_sha256s
|
|
2106
|
+
),
|
|
2107
|
+
"mode": (
|
|
2108
|
+
"symmetric_difference_adaptive"
|
|
2109
|
+
if disagreement_design is not None
|
|
2110
|
+
else (
|
|
2111
|
+
"branch_stratified"
|
|
2112
|
+
if pilot_source is None
|
|
2113
|
+
else "injected_policy_lane_stratified"
|
|
2114
|
+
)
|
|
2115
|
+
),
|
|
2116
|
+
"lane_stratified": bool(pilot_pairs),
|
|
2117
|
+
"configured_maximum_pilot_slots": (
|
|
2118
|
+
self.pilot_slots
|
|
2119
|
+
),
|
|
2120
|
+
"effective_pilot_slots": len(pilot_pairs),
|
|
2121
|
+
"disagreement_design_sha256": (
|
|
2122
|
+
None
|
|
2123
|
+
if disagreement_design is None
|
|
2124
|
+
else disagreement_design.design_sha256
|
|
2125
|
+
),
|
|
2126
|
+
"pilot_source_attribution": [
|
|
2127
|
+
{
|
|
2128
|
+
"action_sha256": action_sha256,
|
|
2129
|
+
"source_branch_id": source_branch_id,
|
|
2130
|
+
"projected_lane_id": lane_id,
|
|
2131
|
+
}
|
|
2132
|
+
for (
|
|
2133
|
+
action_sha256,
|
|
2134
|
+
source_branch_id,
|
|
2135
|
+
lane_id,
|
|
2136
|
+
) in pilot_source_attribution
|
|
2137
|
+
],
|
|
2138
|
+
"branch_identity_used_as_exchangeability_lane": False,
|
|
2139
|
+
"candidate_outcomes_observed": False,
|
|
2140
|
+
"workload_model_provider_branches": False,
|
|
2141
|
+
}
|
|
2142
|
+
),
|
|
2143
|
+
)
|
|
2144
|
+
|
|
2145
|
+
branches: list[FrozenPortfolioRaceBranch] = []
|
|
2146
|
+
for binding, source in zip(
|
|
2147
|
+
active_bindings,
|
|
2148
|
+
active_sources,
|
|
2149
|
+
strict=True,
|
|
2150
|
+
):
|
|
2151
|
+
source_trace = _trace_by_action(source)
|
|
2152
|
+
final_ids = (
|
|
2153
|
+
_compose_branch_action_ids(
|
|
2154
|
+
pilot_action_ids=pilot_ids,
|
|
2155
|
+
source_requirement=source,
|
|
2156
|
+
market=market,
|
|
2157
|
+
evaluation_slots=request.evaluation_slots,
|
|
2158
|
+
)
|
|
2159
|
+
if disagreement_design is None
|
|
2160
|
+
else disagreement_design.actions_for(
|
|
2161
|
+
binding.branch_id
|
|
2162
|
+
)
|
|
2163
|
+
)
|
|
2164
|
+
completion_ids = tuple(
|
|
2165
|
+
value for value in final_ids if value not in set(pilot_ids)
|
|
2166
|
+
)
|
|
2167
|
+
lane_by_action: dict[str, str] = {}
|
|
2168
|
+
for action_sha256 in completion_ids:
|
|
2169
|
+
row = source_trace.get(
|
|
2170
|
+
action_sha256,
|
|
2171
|
+
{
|
|
2172
|
+
"action_sha256": action_sha256,
|
|
2173
|
+
"allocation_kind": "deterministic_market_refill",
|
|
2174
|
+
},
|
|
2175
|
+
)
|
|
2176
|
+
lane_by_action[action_sha256] = (
|
|
2177
|
+
self.lane_projection.project(
|
|
2178
|
+
row,
|
|
2179
|
+
market[action_sha256],
|
|
2180
|
+
)
|
|
2181
|
+
)
|
|
2182
|
+
exposure: dict[str, int] = {}
|
|
2183
|
+
for lane_id in lane_by_action.values():
|
|
2184
|
+
exposure[lane_id] = exposure.get(lane_id, 0) + 1
|
|
2185
|
+
branch_definition_sha256 = _hash(
|
|
2186
|
+
_BRANCH_REQUIREMENT_DEFINITION_DOMAIN,
|
|
2187
|
+
{
|
|
2188
|
+
"planner_definition_sha256": self.definition_sha256,
|
|
2189
|
+
"branch_id": binding.branch_id,
|
|
2190
|
+
"source_requirement_sha256": (
|
|
2191
|
+
source.requirement_sha256
|
|
2192
|
+
),
|
|
2193
|
+
"pilot_requirement_sha256": (
|
|
2194
|
+
pilot_requirement.requirement_sha256
|
|
2195
|
+
),
|
|
2196
|
+
"completion_lane_exposure": [
|
|
2197
|
+
{"lane_id": lane_id, "count": count}
|
|
2198
|
+
for lane_id, count in sorted(exposure.items())
|
|
2199
|
+
],
|
|
2200
|
+
},
|
|
2201
|
+
)
|
|
2202
|
+
branch_requirement = MaterializedActionAllocationRequirement(
|
|
2203
|
+
policy_id="precommitted_portfolio_race_branch",
|
|
2204
|
+
policy_version=1,
|
|
2205
|
+
policy_definition_sha256=branch_definition_sha256,
|
|
2206
|
+
residual_request_sha256=request.request_sha256,
|
|
2207
|
+
proposal_sha256s=proposal_sha256s,
|
|
2208
|
+
required_action_sha256s=final_ids,
|
|
2209
|
+
candidate_outcomes_observed=False,
|
|
2210
|
+
evidence=freeze_json(
|
|
2211
|
+
{
|
|
2212
|
+
"branch_id": binding.branch_id,
|
|
2213
|
+
"source_requirement_sha256": (
|
|
2214
|
+
source.requirement_sha256
|
|
2215
|
+
),
|
|
2216
|
+
"selection_trace": [
|
|
2217
|
+
{
|
|
2218
|
+
"ordinal": ordinal,
|
|
2219
|
+
"action_sha256": action_sha256,
|
|
2220
|
+
"allocation_kind": (
|
|
2221
|
+
"portfolio_race_common_pilot"
|
|
2222
|
+
if action_sha256 in set(pilot_ids)
|
|
2223
|
+
else "portfolio_race_completion"
|
|
2224
|
+
),
|
|
2225
|
+
"source_lane": (
|
|
2226
|
+
next(
|
|
2227
|
+
lane
|
|
2228
|
+
for action, lane in pilot_pairs
|
|
2229
|
+
if action == action_sha256
|
|
2230
|
+
)
|
|
2231
|
+
if action_sha256 in set(pilot_ids)
|
|
2232
|
+
else lane_by_action[action_sha256]
|
|
2233
|
+
),
|
|
2234
|
+
"candidate_outcomes_observed": False,
|
|
2235
|
+
}
|
|
2236
|
+
for ordinal, action_sha256 in enumerate(
|
|
2237
|
+
final_ids,
|
|
2238
|
+
start=1,
|
|
2239
|
+
)
|
|
2240
|
+
],
|
|
2241
|
+
"completion_lane_exposure": [
|
|
2242
|
+
{"lane_id": lane_id, "count": count}
|
|
2243
|
+
for lane_id, count in sorted(exposure.items())
|
|
2244
|
+
],
|
|
2245
|
+
"candidate_outcomes_observed": False,
|
|
2246
|
+
"workload_model_provider_branches": False,
|
|
2247
|
+
}
|
|
2248
|
+
),
|
|
2249
|
+
)
|
|
2250
|
+
branches.append(
|
|
2251
|
+
FrozenPortfolioRaceBranch(
|
|
2252
|
+
branch_id=binding.branch_id,
|
|
2253
|
+
source_requirement_sha256=source.requirement_sha256,
|
|
2254
|
+
requirement=branch_requirement,
|
|
2255
|
+
completion_lane_exposure=tuple(sorted(exposure.items())),
|
|
2256
|
+
prior_mean=prior_by_branch[binding.branch_id],
|
|
2257
|
+
)
|
|
2258
|
+
)
|
|
2259
|
+
return PrecommittedPortfolioRacePlan(
|
|
2260
|
+
planner_id=self.planner_id,
|
|
2261
|
+
planner_version=self.planner_version,
|
|
2262
|
+
planner_definition_sha256=self.definition_sha256,
|
|
2263
|
+
residual_request_sha256=request.request_sha256,
|
|
2264
|
+
proposal_sha256s=proposal_sha256s,
|
|
2265
|
+
evaluation_slots=request.evaluation_slots,
|
|
2266
|
+
pilot_requirement=pilot_requirement,
|
|
2267
|
+
pilot_lane_bindings=tuple(
|
|
2268
|
+
PortfolioRacePilotLaneBinding(
|
|
2269
|
+
action_sha256=action_sha256,
|
|
2270
|
+
lane_id=lane_id,
|
|
2271
|
+
)
|
|
2272
|
+
for action_sha256, lane_id in pilot_pairs
|
|
2273
|
+
),
|
|
2274
|
+
branches=tuple(sorted(branches, key=lambda value: value.branch_id)),
|
|
2275
|
+
candidate_outcomes_observed=False,
|
|
2276
|
+
evidence=freeze_json(
|
|
2277
|
+
{
|
|
2278
|
+
"pilot_source_requirement_sha256s": list(
|
|
2279
|
+
pilot_source_sha256s
|
|
2280
|
+
),
|
|
2281
|
+
"pilot_mode": (
|
|
2282
|
+
"symmetric_difference_adaptive"
|
|
2283
|
+
if disagreement_design is not None
|
|
2284
|
+
else (
|
|
2285
|
+
"branch_stratified"
|
|
2286
|
+
if pilot_source is None
|
|
2287
|
+
else "injected_policy_lane_stratified"
|
|
2288
|
+
)
|
|
2289
|
+
),
|
|
2290
|
+
"all_branch_source_requirement_sha256s": [
|
|
2291
|
+
value.source_requirement_sha256
|
|
2292
|
+
for value in sorted(
|
|
2293
|
+
branches,
|
|
2294
|
+
key=lambda item: item.branch_id,
|
|
2295
|
+
)
|
|
2296
|
+
],
|
|
2297
|
+
"complete_branch_count": len(branches),
|
|
2298
|
+
"configured_maximum_pilot_slots": self.pilot_slots,
|
|
2299
|
+
"effective_pilot_slots": len(pilot_pairs),
|
|
2300
|
+
"pilot_source_attribution": [
|
|
2301
|
+
{
|
|
2302
|
+
"action_sha256": action_sha256,
|
|
2303
|
+
"source_branch_id": source_branch_id,
|
|
2304
|
+
"projected_lane_id": lane_id,
|
|
2305
|
+
}
|
|
2306
|
+
for (
|
|
2307
|
+
action_sha256,
|
|
2308
|
+
source_branch_id,
|
|
2309
|
+
lane_id,
|
|
2310
|
+
) in pilot_source_attribution
|
|
2311
|
+
],
|
|
2312
|
+
"pilot_and_completion_lanes_share_projection": True,
|
|
2313
|
+
"branch_identity_used_as_exchangeability_lane": False,
|
|
2314
|
+
"branch_prior_projection": (
|
|
2315
|
+
{
|
|
2316
|
+
"mode": "binding_prior_mean",
|
|
2317
|
+
"prior_means": [
|
|
2318
|
+
{
|
|
2319
|
+
"branch_id": branch_id,
|
|
2320
|
+
"mean_hex": mean.hex(),
|
|
2321
|
+
}
|
|
2322
|
+
for branch_id, mean in sorted(
|
|
2323
|
+
projected_prior_by_branch.items()
|
|
2324
|
+
)
|
|
2325
|
+
],
|
|
2326
|
+
"applied_before_disagreement_equivalence": True,
|
|
2327
|
+
"candidate_outcomes_observed": False,
|
|
2328
|
+
}
|
|
2329
|
+
if self.prior_projection is None
|
|
2330
|
+
else {
|
|
2331
|
+
"mode": "injected_outcome_blind_projection",
|
|
2332
|
+
"projection_id": (
|
|
2333
|
+
self.prior_projection.projection_id
|
|
2334
|
+
),
|
|
2335
|
+
"projection_version": (
|
|
2336
|
+
self.prior_projection.projection_version
|
|
2337
|
+
),
|
|
2338
|
+
"definition_sha256": (
|
|
2339
|
+
self.prior_projection.definition_sha256
|
|
2340
|
+
),
|
|
2341
|
+
"request_phase": request.phase.value,
|
|
2342
|
+
"prior_means": [
|
|
2343
|
+
{
|
|
2344
|
+
"branch_id": branch_id,
|
|
2345
|
+
"mean_hex": mean.hex(),
|
|
2346
|
+
}
|
|
2347
|
+
for branch_id, mean in sorted(
|
|
2348
|
+
projected_prior_by_branch.items()
|
|
2349
|
+
)
|
|
2350
|
+
],
|
|
2351
|
+
"applied_before_disagreement_equivalence": True,
|
|
2352
|
+
"candidate_outcomes_observed": False,
|
|
2353
|
+
}
|
|
2354
|
+
),
|
|
2355
|
+
"disagreement_design": (
|
|
2356
|
+
None
|
|
2357
|
+
if disagreement_design is None
|
|
2358
|
+
else disagreement_design.to_record()
|
|
2359
|
+
),
|
|
2360
|
+
"all_complete_branches_frozen_before_pilot": True,
|
|
2361
|
+
"outcome_conditioned_regeneration": False,
|
|
2362
|
+
"candidate_outcomes_observed": False,
|
|
2363
|
+
"workload_model_provider_branches": False,
|
|
2364
|
+
}
|
|
2365
|
+
),
|
|
2366
|
+
)
|
|
2367
|
+
|
|
2368
|
+
|
|
2369
|
+
@dataclass(frozen=True, slots=True)
|
|
2370
|
+
class PortfolioRaceBranchScore:
|
|
2371
|
+
branch_id: str
|
|
2372
|
+
score: float
|
|
2373
|
+
observed_completion_fraction: float
|
|
2374
|
+
lane_posteriors: tuple[tuple[str, float, int], ...]
|
|
2375
|
+
|
|
2376
|
+
def __post_init__(self) -> None:
|
|
2377
|
+
_require_token(self.branch_id, name="branch_id")
|
|
2378
|
+
for value, name in (
|
|
2379
|
+
(self.score, "score"),
|
|
2380
|
+
(
|
|
2381
|
+
self.observed_completion_fraction,
|
|
2382
|
+
"observed_completion_fraction",
|
|
2383
|
+
),
|
|
2384
|
+
):
|
|
2385
|
+
if (
|
|
2386
|
+
type(value) is not float
|
|
2387
|
+
or not math.isfinite(value)
|
|
2388
|
+
or not 0.0 <= value <= 1.0
|
|
2389
|
+
):
|
|
2390
|
+
raise ValueError(f"{name} must be finite and lie in [0, 1]")
|
|
2391
|
+
if (
|
|
2392
|
+
type(self.lane_posteriors) is not tuple
|
|
2393
|
+
or not self.lane_posteriors
|
|
2394
|
+
or self.lane_posteriors
|
|
2395
|
+
!= tuple(sorted(self.lane_posteriors))
|
|
2396
|
+
):
|
|
2397
|
+
raise ValueError("lane_posteriors must be non-empty and canonical")
|
|
2398
|
+
for lane_id, posterior, count in self.lane_posteriors:
|
|
2399
|
+
_require_token(lane_id, name="lane posterior ID")
|
|
2400
|
+
if (
|
|
2401
|
+
type(posterior) is not float
|
|
2402
|
+
or not math.isfinite(posterior)
|
|
2403
|
+
or not 0.0 <= posterior <= 1.0
|
|
2404
|
+
):
|
|
2405
|
+
raise ValueError("lane posterior must lie in [0, 1]")
|
|
2406
|
+
if type(count) is not int or count < 0:
|
|
2407
|
+
raise ValueError("lane observation count must be non-negative")
|
|
2408
|
+
|
|
2409
|
+
def to_record(self) -> dict[str, object]:
|
|
2410
|
+
self.__post_init__()
|
|
2411
|
+
return {
|
|
2412
|
+
"branch_id": self.branch_id,
|
|
2413
|
+
"score_hex": self.score.hex(),
|
|
2414
|
+
"observed_completion_fraction_hex": (
|
|
2415
|
+
self.observed_completion_fraction.hex()
|
|
2416
|
+
),
|
|
2417
|
+
"lane_posteriors": [
|
|
2418
|
+
{
|
|
2419
|
+
"lane_id": lane_id,
|
|
2420
|
+
"posterior_mean_hex": posterior.hex(),
|
|
2421
|
+
"observation_count": count,
|
|
2422
|
+
}
|
|
2423
|
+
for lane_id, posterior, count in self.lane_posteriors
|
|
2424
|
+
],
|
|
2425
|
+
}
|
|
2426
|
+
|
|
2427
|
+
|
|
2428
|
+
@dataclass(frozen=True, slots=True)
|
|
2429
|
+
class PortfolioRaceGateDecision:
|
|
2430
|
+
gate_id: str
|
|
2431
|
+
gate_version: int
|
|
2432
|
+
gate_definition_sha256: str
|
|
2433
|
+
plan_sha256: str
|
|
2434
|
+
pilot_outcome_batch_sha256: str
|
|
2435
|
+
selected_branch_id: str
|
|
2436
|
+
selected_requirement_sha256: str
|
|
2437
|
+
positive_pilot_count: int
|
|
2438
|
+
pilot_count: int
|
|
2439
|
+
branch_scores: tuple[PortfolioRaceBranchScore, ...]
|
|
2440
|
+
evidence: FrozenJsonObject
|
|
2441
|
+
decision_sha256: str = field(init=False)
|
|
2442
|
+
|
|
2443
|
+
def __post_init__(self) -> None:
|
|
2444
|
+
_require_token(self.gate_id, name="gate_id")
|
|
2445
|
+
if type(self.gate_version) is not int or self.gate_version <= 0:
|
|
2446
|
+
raise ValueError("gate_version must be positive")
|
|
2447
|
+
for value, name in (
|
|
2448
|
+
(self.gate_definition_sha256, "gate_definition_sha256"),
|
|
2449
|
+
(self.plan_sha256, "plan_sha256"),
|
|
2450
|
+
(
|
|
2451
|
+
self.pilot_outcome_batch_sha256,
|
|
2452
|
+
"pilot_outcome_batch_sha256",
|
|
2453
|
+
),
|
|
2454
|
+
(
|
|
2455
|
+
self.selected_requirement_sha256,
|
|
2456
|
+
"selected_requirement_sha256",
|
|
2457
|
+
),
|
|
2458
|
+
):
|
|
2459
|
+
require_sha256(value, name)
|
|
2460
|
+
_require_token(self.selected_branch_id, name="selected_branch_id")
|
|
2461
|
+
if (
|
|
2462
|
+
type(self.positive_pilot_count) is not int
|
|
2463
|
+
or type(self.pilot_count) is not int
|
|
2464
|
+
or not 0 <= self.positive_pilot_count <= self.pilot_count
|
|
2465
|
+
):
|
|
2466
|
+
raise ValueError("pilot counts are inconsistent")
|
|
2467
|
+
if (
|
|
2468
|
+
type(self.branch_scores) is not tuple
|
|
2469
|
+
or not self.branch_scores
|
|
2470
|
+
or tuple(value.branch_id for value in self.branch_scores)
|
|
2471
|
+
!= tuple(sorted({value.branch_id for value in self.branch_scores}))
|
|
2472
|
+
):
|
|
2473
|
+
raise ValueError("branch_scores must be non-empty and canonical")
|
|
2474
|
+
for value in self.branch_scores:
|
|
2475
|
+
if type(value) is not PortfolioRaceBranchScore:
|
|
2476
|
+
raise TypeError("branch_scores must be exact")
|
|
2477
|
+
value.__post_init__()
|
|
2478
|
+
if self.selected_branch_id not in {
|
|
2479
|
+
value.branch_id for value in self.branch_scores
|
|
2480
|
+
}:
|
|
2481
|
+
raise ValueError("selected branch is absent from scores")
|
|
2482
|
+
if (
|
|
2483
|
+
type(self.evidence) is not FrozenJsonObject
|
|
2484
|
+
or freeze_json(self.evidence) is not self.evidence
|
|
2485
|
+
):
|
|
2486
|
+
raise TypeError("gate evidence must be a frozen object")
|
|
2487
|
+
object.__setattr__(
|
|
2488
|
+
self,
|
|
2489
|
+
"decision_sha256",
|
|
2490
|
+
_hash(_GATE_DECISION_DOMAIN, self._unsigned_record()),
|
|
2491
|
+
)
|
|
2492
|
+
|
|
2493
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
2494
|
+
return {
|
|
2495
|
+
"schema_version": 1,
|
|
2496
|
+
"gate": {
|
|
2497
|
+
"gate_id": self.gate_id,
|
|
2498
|
+
"gate_version": self.gate_version,
|
|
2499
|
+
"definition_sha256": self.gate_definition_sha256,
|
|
2500
|
+
},
|
|
2501
|
+
"plan_sha256": self.plan_sha256,
|
|
2502
|
+
"pilot_outcome_batch_sha256": (
|
|
2503
|
+
self.pilot_outcome_batch_sha256
|
|
2504
|
+
),
|
|
2505
|
+
"selected_branch_id": self.selected_branch_id,
|
|
2506
|
+
"selected_requirement_sha256": (
|
|
2507
|
+
self.selected_requirement_sha256
|
|
2508
|
+
),
|
|
2509
|
+
"positive_pilot_count": self.positive_pilot_count,
|
|
2510
|
+
"pilot_count": self.pilot_count,
|
|
2511
|
+
"branch_scores": [
|
|
2512
|
+
value.to_record() for value in self.branch_scores
|
|
2513
|
+
],
|
|
2514
|
+
"evidence_sha256": typed_json_sha256(self.evidence),
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
def to_record(self, *, include_evidence: bool = False) -> dict[str, object]:
|
|
2518
|
+
self.__post_init__()
|
|
2519
|
+
record = {
|
|
2520
|
+
**self._unsigned_record(),
|
|
2521
|
+
"decision_sha256": self.decision_sha256,
|
|
2522
|
+
}
|
|
2523
|
+
if include_evidence:
|
|
2524
|
+
record["evidence"] = thaw_json(self.evidence)
|
|
2525
|
+
return record
|
|
2526
|
+
|
|
2527
|
+
|
|
2528
|
+
@dataclass(frozen=True, slots=True)
|
|
2529
|
+
class EvidenceAdaptivePortfolioRaceGate:
|
|
2530
|
+
"""Select a frozen slate only when pilot-to-completion transfer is covered.
|
|
2531
|
+
|
|
2532
|
+
A pilot may update only its predeclared projected lane. Adaptive branch
|
|
2533
|
+
choice is additionally disabled unless *every* branch has sufficient
|
|
2534
|
+
completion exposure in observed lanes. The fail-closed decision then uses
|
|
2535
|
+
frozen branch priors, preventing a single non-exchangeable pilot from
|
|
2536
|
+
deciding an entire heterogeneous continuation.
|
|
2537
|
+
"""
|
|
2538
|
+
|
|
2539
|
+
prior_strength: float = 1.0
|
|
2540
|
+
minimum_observed_completion_fraction: float = 0.5
|
|
2541
|
+
gate_id: str = EVIDENCE_ADAPTIVE_PORTFOLIO_RACE_GATE_ID
|
|
2542
|
+
gate_version: int = EVIDENCE_ADAPTIVE_PORTFOLIO_RACE_GATE_VERSION
|
|
2543
|
+
definition_sha256: str = field(init=False)
|
|
2544
|
+
|
|
2545
|
+
def __post_init__(self) -> None:
|
|
2546
|
+
if (
|
|
2547
|
+
type(self.prior_strength) is not float
|
|
2548
|
+
or not math.isfinite(self.prior_strength)
|
|
2549
|
+
or self.prior_strength <= 0.0
|
|
2550
|
+
):
|
|
2551
|
+
raise ValueError("prior_strength must be finite and positive")
|
|
2552
|
+
if (
|
|
2553
|
+
type(self.minimum_observed_completion_fraction) is not float
|
|
2554
|
+
or not math.isfinite(
|
|
2555
|
+
self.minimum_observed_completion_fraction
|
|
2556
|
+
)
|
|
2557
|
+
or not 0.0
|
|
2558
|
+
< self.minimum_observed_completion_fraction
|
|
2559
|
+
<= 1.0
|
|
2560
|
+
):
|
|
2561
|
+
raise ValueError(
|
|
2562
|
+
"minimum_observed_completion_fraction must lie in (0, 1]"
|
|
2563
|
+
)
|
|
2564
|
+
_require_token(self.gate_id, name="gate_id")
|
|
2565
|
+
if (
|
|
2566
|
+
self.gate_version
|
|
2567
|
+
!= EVIDENCE_ADAPTIVE_PORTFOLIO_RACE_GATE_VERSION
|
|
2568
|
+
):
|
|
2569
|
+
raise ValueError("gate_version is immutable")
|
|
2570
|
+
object.__setattr__(
|
|
2571
|
+
self,
|
|
2572
|
+
"definition_sha256",
|
|
2573
|
+
_hash(
|
|
2574
|
+
_GATE_DEFINITION_DOMAIN,
|
|
2575
|
+
{
|
|
2576
|
+
"schema_version": 1,
|
|
2577
|
+
"gate_id": self.gate_id,
|
|
2578
|
+
"gate_version": self.gate_version,
|
|
2579
|
+
"prior_strength_hex": self.prior_strength.hex(),
|
|
2580
|
+
"minimum_observed_completion_fraction_hex": (
|
|
2581
|
+
self.minimum_observed_completion_fraction.hex()
|
|
2582
|
+
),
|
|
2583
|
+
"pilot_normalization": "max_positive_marginal_gain",
|
|
2584
|
+
"lane_update": "bounded_consequence_posterior_mean",
|
|
2585
|
+
"branch_score": "completion_exposure_weighted_lane_mean",
|
|
2586
|
+
"adaptive_qualification": (
|
|
2587
|
+
"all_branches_meet_minimum_observed_completion_"
|
|
2588
|
+
"fraction"
|
|
2589
|
+
),
|
|
2590
|
+
"unqualified_fallback": (
|
|
2591
|
+
"higher_frozen_prior_then_branch_id"
|
|
2592
|
+
),
|
|
2593
|
+
"tie_break": "higher_score_then_branch_id",
|
|
2594
|
+
"only_pilot_outcomes_observed": True,
|
|
2595
|
+
"workload_model_provider_branches": False,
|
|
2596
|
+
},
|
|
2597
|
+
),
|
|
2598
|
+
)
|
|
2599
|
+
|
|
2600
|
+
def decide(
|
|
2601
|
+
self,
|
|
2602
|
+
plan: SequentialAllocationPlanPort,
|
|
2603
|
+
outcomes: SequentialPilotOutcomeBatch,
|
|
2604
|
+
) -> SequentialAllocationGateDecisionPort:
|
|
2605
|
+
self.__post_init__()
|
|
2606
|
+
if type(plan) is not PrecommittedPortfolioRacePlan:
|
|
2607
|
+
raise TypeError("portfolio-race gate requires its exact plan")
|
|
2608
|
+
plan.__post_init__()
|
|
2609
|
+
if type(outcomes) is not SequentialPilotOutcomeBatch:
|
|
2610
|
+
raise TypeError("outcomes must be exact")
|
|
2611
|
+
outcomes.__post_init__()
|
|
2612
|
+
if (
|
|
2613
|
+
outcomes.plan_sha256 != plan.plan_sha256
|
|
2614
|
+
or outcomes.residual_request_sha256
|
|
2615
|
+
!= plan.residual_request_sha256
|
|
2616
|
+
or tuple(value.action_sha256 for value in outcomes.outcomes)
|
|
2617
|
+
!= plan.pilot_action_sha256s
|
|
2618
|
+
):
|
|
2619
|
+
raise ValueError("pilot outcomes differ from their race plan")
|
|
2620
|
+
lane_by_action = {
|
|
2621
|
+
value.action_sha256: value.lane_id
|
|
2622
|
+
for value in plan.pilot_lane_bindings
|
|
2623
|
+
}
|
|
2624
|
+
maximum_gain = max(
|
|
2625
|
+
(
|
|
2626
|
+
value.marginal_archive_gain
|
|
2627
|
+
for value in outcomes.outcomes
|
|
2628
|
+
),
|
|
2629
|
+
default=0.0,
|
|
2630
|
+
)
|
|
2631
|
+
normalized_by_lane: dict[str, list[float]] = {}
|
|
2632
|
+
for outcome in outcomes.outcomes:
|
|
2633
|
+
normalized = (
|
|
2634
|
+
0.0
|
|
2635
|
+
if maximum_gain == 0.0
|
|
2636
|
+
else outcome.marginal_archive_gain / maximum_gain
|
|
2637
|
+
)
|
|
2638
|
+
normalized_by_lane.setdefault(
|
|
2639
|
+
lane_by_action[outcome.action_sha256],
|
|
2640
|
+
[],
|
|
2641
|
+
).append(normalized)
|
|
2642
|
+
scores: list[PortfolioRaceBranchScore] = []
|
|
2643
|
+
for branch in plan.branches:
|
|
2644
|
+
weighted = 0.0
|
|
2645
|
+
observed_exposure = 0
|
|
2646
|
+
total_exposure = sum(
|
|
2647
|
+
count for _lane_id, count in branch.completion_lane_exposure
|
|
2648
|
+
)
|
|
2649
|
+
posteriors: list[tuple[str, float, int]] = []
|
|
2650
|
+
for lane_id, exposure in branch.completion_lane_exposure:
|
|
2651
|
+
observations = normalized_by_lane.get(lane_id, [])
|
|
2652
|
+
posterior = (
|
|
2653
|
+
branch.prior_mean * self.prior_strength
|
|
2654
|
+
+ math.fsum(observations)
|
|
2655
|
+
) / (self.prior_strength + len(observations))
|
|
2656
|
+
weighted += exposure * posterior
|
|
2657
|
+
if observations:
|
|
2658
|
+
observed_exposure += exposure
|
|
2659
|
+
posteriors.append((lane_id, posterior, len(observations)))
|
|
2660
|
+
scores.append(
|
|
2661
|
+
PortfolioRaceBranchScore(
|
|
2662
|
+
branch_id=branch.branch_id,
|
|
2663
|
+
score=weighted / total_exposure,
|
|
2664
|
+
observed_completion_fraction=(
|
|
2665
|
+
observed_exposure / total_exposure
|
|
2666
|
+
),
|
|
2667
|
+
lane_posteriors=tuple(sorted(posteriors)),
|
|
2668
|
+
)
|
|
2669
|
+
)
|
|
2670
|
+
adaptive_selection_qualified = bool(outcomes.outcomes) and all(
|
|
2671
|
+
value.observed_completion_fraction
|
|
2672
|
+
>= self.minimum_observed_completion_fraction
|
|
2673
|
+
for value in scores
|
|
2674
|
+
)
|
|
2675
|
+
if adaptive_selection_qualified:
|
|
2676
|
+
selected_score = min(
|
|
2677
|
+
scores,
|
|
2678
|
+
key=lambda value: (-value.score, value.branch_id),
|
|
2679
|
+
)
|
|
2680
|
+
selected = plan.branch_for(selected_score.branch_id)
|
|
2681
|
+
selection_mode = "coverage_qualified_lane_adaptation"
|
|
2682
|
+
else:
|
|
2683
|
+
selected = min(
|
|
2684
|
+
plan.branches,
|
|
2685
|
+
key=lambda value: (-value.prior_mean, value.branch_id),
|
|
2686
|
+
)
|
|
2687
|
+
selection_mode = "insufficient_coverage_frozen_prior_fallback"
|
|
2688
|
+
positive_count = sum(
|
|
2689
|
+
value.positive_marginal_utility for value in outcomes.outcomes
|
|
2690
|
+
)
|
|
2691
|
+
return PortfolioRaceGateDecision(
|
|
2692
|
+
gate_id=self.gate_id,
|
|
2693
|
+
gate_version=self.gate_version,
|
|
2694
|
+
gate_definition_sha256=self.definition_sha256,
|
|
2695
|
+
plan_sha256=plan.plan_sha256,
|
|
2696
|
+
pilot_outcome_batch_sha256=outcomes.batch_sha256,
|
|
2697
|
+
selected_branch_id=selected.branch_id,
|
|
2698
|
+
selected_requirement_sha256=(
|
|
2699
|
+
selected.requirement.requirement_sha256
|
|
2700
|
+
),
|
|
2701
|
+
positive_pilot_count=positive_count,
|
|
2702
|
+
pilot_count=len(outcomes.outcomes),
|
|
2703
|
+
branch_scores=tuple(
|
|
2704
|
+
sorted(scores, key=lambda value: value.branch_id)
|
|
2705
|
+
),
|
|
2706
|
+
evidence=freeze_json(
|
|
2707
|
+
{
|
|
2708
|
+
"maximum_pilot_marginal_gain_hex": maximum_gain.hex(),
|
|
2709
|
+
"minimum_observed_completion_fraction_hex": (
|
|
2710
|
+
self.minimum_observed_completion_fraction.hex()
|
|
2711
|
+
),
|
|
2712
|
+
"adaptive_selection_qualified": (
|
|
2713
|
+
adaptive_selection_qualified
|
|
2714
|
+
),
|
|
2715
|
+
"selection_mode": selection_mode,
|
|
2716
|
+
"pilot_to_completion_transfer": (
|
|
2717
|
+
"same_predeclared_projected_lane_only"
|
|
2718
|
+
),
|
|
2719
|
+
"unobserved_completion_lanes_remain_at_frozen_prior": True,
|
|
2720
|
+
"branch_identity_used_as_exchangeability_lane": False,
|
|
2721
|
+
"only_pilot_outcomes_observed": True,
|
|
2722
|
+
"selected_branch_frozen_before_pilot": True,
|
|
2723
|
+
"all_branch_scores": [
|
|
2724
|
+
value.to_record()
|
|
2725
|
+
for value in sorted(
|
|
2726
|
+
scores,
|
|
2727
|
+
key=lambda item: item.branch_id,
|
|
2728
|
+
)
|
|
2729
|
+
],
|
|
2730
|
+
"workload_model_provider_branches": False,
|
|
2731
|
+
}
|
|
2732
|
+
),
|
|
2733
|
+
)
|
|
2734
|
+
|
|
2735
|
+
|
|
2736
|
+
__all__ = [
|
|
2737
|
+
"EVIDENCE_ADAPTIVE_PORTFOLIO_RACE_GATE_ID",
|
|
2738
|
+
"EVIDENCE_ADAPTIVE_PORTFOLIO_RACE_GATE_VERSION",
|
|
2739
|
+
"PHASE_CONDITIONED_PORTFOLIO_RACE_PRIOR_ID",
|
|
2740
|
+
"PHASE_CONDITIONED_PORTFOLIO_RACE_PRIOR_VERSION",
|
|
2741
|
+
"PRECOMMITTED_PORTFOLIO_RACE_PLANNER_ID",
|
|
2742
|
+
"PRECOMMITTED_PORTFOLIO_RACE_PLANNER_VERSION",
|
|
2743
|
+
"SYMMETRIC_DIFFERENCE_PORTFOLIO_RACE_POLICY_ID",
|
|
2744
|
+
"SYMMETRIC_DIFFERENCE_PORTFOLIO_RACE_POLICY_VERSION",
|
|
2745
|
+
"TRACE_FIELD_PORTFOLIO_LANE_PROJECTION_ID",
|
|
2746
|
+
"TRACE_FIELD_PORTFOLIO_LANE_PROJECTION_VERSION",
|
|
2747
|
+
"EvidenceAdaptivePortfolioRaceGate",
|
|
2748
|
+
"FrozenPortfolioRaceBranch",
|
|
2749
|
+
"PhaseConditionedPortfolioRacePrior",
|
|
2750
|
+
"PortfolioLaneProjectionPort",
|
|
2751
|
+
"PortfolioRacePriorProjectionPort",
|
|
2752
|
+
"PortfolioRaceBranchScore",
|
|
2753
|
+
"PortfolioRaceDisagreementDesign",
|
|
2754
|
+
"PortfolioRaceDisagreementPolicyPort",
|
|
2755
|
+
"PortfolioRaceGateDecision",
|
|
2756
|
+
"PortfolioRacePilotLaneBinding",
|
|
2757
|
+
"PortfolioRacePolicyBinding",
|
|
2758
|
+
"PrecommittedPortfolioRacePlan",
|
|
2759
|
+
"PrecommittedPortfolioRacePlanner",
|
|
2760
|
+
"SymmetricDifferencePortfolioRacePolicy",
|
|
2761
|
+
"TraceFieldPortfolioLaneProjection",
|
|
2762
|
+
]
|