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,2827 @@
|
|
|
1
|
+
"""Outcome-adaptive allocation inside one sealed materialized-action market.
|
|
2
|
+
|
|
3
|
+
The policy in this module is deliberately narrower than proposal generation.
|
|
4
|
+
It receives a workload-opaque market whose candidates were all materialized
|
|
5
|
+
before current outcomes existed. It first chooses a diagnostic pilot using
|
|
6
|
+
only portable action descriptors. After real pilot outcomes are durably
|
|
7
|
+
available, it chooses one continuation action at a time.
|
|
8
|
+
|
|
9
|
+
This is a normal sequential-optimization information boundary:
|
|
10
|
+
|
|
11
|
+
* unobserved candidate outcomes are never accepted by the policy;
|
|
12
|
+
* the proposal market and real-evaluation budget remain fixed;
|
|
13
|
+
* every decision binds the exact observed outcome hashes that precede it; and
|
|
14
|
+
* one continuation seat is randomized over an authenticated exploration pool.
|
|
15
|
+
|
|
16
|
+
The policy knows no workload, objective, configuration field, model, provider,
|
|
17
|
+
or prompt. Callers project those concerns into opaque lane/operator/semantic
|
|
18
|
+
cells and a normalized, outcome-blind prior score.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import hashlib
|
|
24
|
+
import json
|
|
25
|
+
import math
|
|
26
|
+
import random
|
|
27
|
+
import re
|
|
28
|
+
from dataclasses import dataclass, field
|
|
29
|
+
from enum import Enum
|
|
30
|
+
|
|
31
|
+
from agent_evolve.domain.patch import require_sha256
|
|
32
|
+
from agent_evolve.domain.typed_json import (
|
|
33
|
+
FrozenJsonObject,
|
|
34
|
+
freeze_json,
|
|
35
|
+
thaw_json,
|
|
36
|
+
typed_json_sha256,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_POLICY_ID = (
|
|
41
|
+
"outcome_adaptive_action_racing"
|
|
42
|
+
)
|
|
43
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_POLICY_VERSION = 2
|
|
44
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_SET_AWARE_POLICY_VERSION = 3
|
|
45
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_CAUSAL_SET_POLICY_VERSION = 4
|
|
46
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_RISK_CONTROLLED_POLICY_VERSION = 5
|
|
47
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_STRATIFIED_AUDIT_POLICY_VERSION = 6
|
|
48
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_HORIZON_HIERARCHICAL_POLICY_VERSION = 7
|
|
49
|
+
|
|
50
|
+
_CAUSAL_SET_POLICY_VERSIONS = frozenset(
|
|
51
|
+
{
|
|
52
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_CAUSAL_SET_POLICY_VERSION,
|
|
53
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_RISK_CONTROLLED_POLICY_VERSION,
|
|
54
|
+
}
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
_TOKEN = re.compile(r"^[a-z][a-z0-9_.:-]{0,255}$")
|
|
58
|
+
_POLICY_DEFINITION_DOMAIN = (
|
|
59
|
+
b"agent-evolve:outcome-adaptive-action-racing-definition:v1\x00"
|
|
60
|
+
)
|
|
61
|
+
_OUTCOME_DOMAIN = b"agent-evolve:adaptive-action-outcome:v1\x00"
|
|
62
|
+
_SET_OUTCOME_DOMAIN = b"agent-evolve:adaptive-action-set-outcome:v1\x00"
|
|
63
|
+
_DECISION_DOMAIN = b"agent-evolve:adaptive-action-racing-decision:v1\x00"
|
|
64
|
+
_DIRECTIVE_DOMAIN = (
|
|
65
|
+
b"agent-evolve:adaptive-action-allocation-directive:v1\x00"
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _canonical_json(value: object) -> bytes:
|
|
70
|
+
return json.dumps(
|
|
71
|
+
value,
|
|
72
|
+
allow_nan=False,
|
|
73
|
+
ensure_ascii=True,
|
|
74
|
+
separators=(",", ":"),
|
|
75
|
+
sort_keys=True,
|
|
76
|
+
).encode("ascii", errors="strict")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _hash(domain: bytes, value: object) -> str:
|
|
80
|
+
return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _require_token(value: str, *, name: str) -> None:
|
|
84
|
+
if type(value) is not str or _TOKEN.fullmatch(value) is None:
|
|
85
|
+
raise ValueError(f"{name} must use the closed token grammar")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _require_probability(value: float, *, name: str) -> None:
|
|
89
|
+
if (
|
|
90
|
+
type(value) is not float
|
|
91
|
+
or not math.isfinite(value)
|
|
92
|
+
or not 0.0 <= value <= 1.0
|
|
93
|
+
):
|
|
94
|
+
raise ValueError(f"{name} must be a finite probability")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _stable_unit_interval(*parts: object) -> float:
|
|
98
|
+
payload = _canonical_json(list(parts))
|
|
99
|
+
numerator = int.from_bytes(hashlib.sha256(payload).digest()[:8], "big")
|
|
100
|
+
return numerator / float(2**64)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@dataclass(frozen=True, slots=True, order=True)
|
|
104
|
+
class AdaptiveActionFactorCell:
|
|
105
|
+
"""One opaque, pre-evaluation factor level used for audit strata."""
|
|
106
|
+
|
|
107
|
+
family_id: str
|
|
108
|
+
level_id: str
|
|
109
|
+
|
|
110
|
+
def __post_init__(self) -> None:
|
|
111
|
+
_require_token(self.family_id, name="factor family_id")
|
|
112
|
+
_require_token(self.level_id, name="factor level_id")
|
|
113
|
+
|
|
114
|
+
def to_record(self) -> dict[str, str]:
|
|
115
|
+
self.__post_init__()
|
|
116
|
+
return {
|
|
117
|
+
"family_id": self.family_id,
|
|
118
|
+
"level_id": self.level_id,
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@dataclass(frozen=True, slots=True)
|
|
123
|
+
class AdaptiveActionDescriptor:
|
|
124
|
+
"""Portable, outcome-blind view of one materialized action."""
|
|
125
|
+
|
|
126
|
+
action_sha256: str
|
|
127
|
+
phenotype_sha256: str
|
|
128
|
+
lane_id: str
|
|
129
|
+
operator_id: str
|
|
130
|
+
native_rank: int
|
|
131
|
+
lane_size: int
|
|
132
|
+
prior_score: float
|
|
133
|
+
parent_generated_in_current_run: bool
|
|
134
|
+
semantic_cell_ids: tuple[str, ...] = ()
|
|
135
|
+
factor_cells: tuple[AdaptiveActionFactorCell, ...] = ()
|
|
136
|
+
|
|
137
|
+
def __post_init__(self) -> None:
|
|
138
|
+
require_sha256(self.action_sha256, "action_sha256")
|
|
139
|
+
require_sha256(self.phenotype_sha256, "phenotype_sha256")
|
|
140
|
+
_require_token(self.lane_id, name="lane_id")
|
|
141
|
+
_require_token(self.operator_id, name="operator_id")
|
|
142
|
+
if (
|
|
143
|
+
type(self.native_rank) is not int
|
|
144
|
+
or self.native_rank <= 0
|
|
145
|
+
or type(self.lane_size) is not int
|
|
146
|
+
or self.lane_size <= 0
|
|
147
|
+
or self.native_rank > self.lane_size
|
|
148
|
+
):
|
|
149
|
+
raise ValueError("native rank must fit the positive lane size")
|
|
150
|
+
_require_probability(self.prior_score, name="prior_score")
|
|
151
|
+
if type(self.parent_generated_in_current_run) is not bool:
|
|
152
|
+
raise TypeError(
|
|
153
|
+
"parent_generated_in_current_run must be exact"
|
|
154
|
+
)
|
|
155
|
+
if (
|
|
156
|
+
type(self.semantic_cell_ids) is not tuple
|
|
157
|
+
or self.semantic_cell_ids
|
|
158
|
+
!= tuple(sorted(set(self.semantic_cell_ids)))
|
|
159
|
+
):
|
|
160
|
+
raise ValueError(
|
|
161
|
+
"semantic_cell_ids must be an exact canonical tuple"
|
|
162
|
+
)
|
|
163
|
+
for value in self.semantic_cell_ids:
|
|
164
|
+
_require_token(value, name="semantic_cell_id")
|
|
165
|
+
if (
|
|
166
|
+
type(self.factor_cells) is not tuple
|
|
167
|
+
or self.factor_cells != tuple(sorted(self.factor_cells))
|
|
168
|
+
or any(
|
|
169
|
+
type(value) is not AdaptiveActionFactorCell
|
|
170
|
+
for value in self.factor_cells
|
|
171
|
+
)
|
|
172
|
+
):
|
|
173
|
+
raise ValueError(
|
|
174
|
+
"factor_cells must be an exact canonical cell tuple"
|
|
175
|
+
)
|
|
176
|
+
for value in self.factor_cells:
|
|
177
|
+
value.__post_init__()
|
|
178
|
+
if len({value.family_id for value in self.factor_cells}) != len(
|
|
179
|
+
self.factor_cells
|
|
180
|
+
):
|
|
181
|
+
raise ValueError(
|
|
182
|
+
"factor_cells must contain at most one level per family"
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def rank_quality(self) -> float:
|
|
187
|
+
"""Return one for the lane head and zero for the lane tail."""
|
|
188
|
+
|
|
189
|
+
if self.lane_size == 1:
|
|
190
|
+
return 1.0
|
|
191
|
+
return 1.0 - (
|
|
192
|
+
(self.native_rank - 1) / float(self.lane_size - 1)
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
def to_record(self) -> dict[str, object]:
|
|
196
|
+
self.__post_init__()
|
|
197
|
+
record: dict[str, object] = {
|
|
198
|
+
"action_sha256": self.action_sha256,
|
|
199
|
+
"phenotype_sha256": self.phenotype_sha256,
|
|
200
|
+
"lane_id": self.lane_id,
|
|
201
|
+
"operator_id": self.operator_id,
|
|
202
|
+
"native_rank": self.native_rank,
|
|
203
|
+
"lane_size": self.lane_size,
|
|
204
|
+
"rank_quality_hex": self.rank_quality.hex(),
|
|
205
|
+
"prior_score_hex": self.prior_score.hex(),
|
|
206
|
+
"parent_generated_in_current_run": (
|
|
207
|
+
self.parent_generated_in_current_run
|
|
208
|
+
),
|
|
209
|
+
"semantic_cell_ids": list(self.semantic_cell_ids),
|
|
210
|
+
}
|
|
211
|
+
# Preserve byte-identical records for policy versions 2--5.
|
|
212
|
+
if self.factor_cells:
|
|
213
|
+
record["factor_cells"] = [
|
|
214
|
+
value.to_record() for value in self.factor_cells
|
|
215
|
+
]
|
|
216
|
+
return record
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
@dataclass(frozen=True, slots=True)
|
|
220
|
+
class AdaptiveActionOutcome:
|
|
221
|
+
"""One real outcome available before a continuation decision."""
|
|
222
|
+
|
|
223
|
+
action_sha256: str
|
|
224
|
+
evaluation_sha256: str
|
|
225
|
+
feasible: bool
|
|
226
|
+
marginal_archive_gain: float
|
|
227
|
+
outcome_sha256: str = field(init=False)
|
|
228
|
+
|
|
229
|
+
def __post_init__(self) -> None:
|
|
230
|
+
require_sha256(self.action_sha256, "action_sha256")
|
|
231
|
+
require_sha256(self.evaluation_sha256, "evaluation_sha256")
|
|
232
|
+
if type(self.feasible) is not bool:
|
|
233
|
+
raise TypeError("feasible must be exact")
|
|
234
|
+
if (
|
|
235
|
+
type(self.marginal_archive_gain) is not float
|
|
236
|
+
or not math.isfinite(self.marginal_archive_gain)
|
|
237
|
+
or self.marginal_archive_gain < 0.0
|
|
238
|
+
):
|
|
239
|
+
raise ValueError(
|
|
240
|
+
"marginal_archive_gain must be finite and non-negative"
|
|
241
|
+
)
|
|
242
|
+
if not self.feasible and self.marginal_archive_gain != 0.0:
|
|
243
|
+
raise ValueError("an infeasible action cannot contribute gain")
|
|
244
|
+
object.__setattr__(
|
|
245
|
+
self,
|
|
246
|
+
"outcome_sha256",
|
|
247
|
+
_hash(_OUTCOME_DOMAIN, self._unsigned_record()),
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
@property
|
|
251
|
+
def positive(self) -> bool:
|
|
252
|
+
return self.marginal_archive_gain > 0.0
|
|
253
|
+
|
|
254
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
255
|
+
return {
|
|
256
|
+
"schema_version": 1,
|
|
257
|
+
"action_sha256": self.action_sha256,
|
|
258
|
+
"evaluation_sha256": self.evaluation_sha256,
|
|
259
|
+
"feasible": self.feasible,
|
|
260
|
+
"marginal_archive_gain_hex": (
|
|
261
|
+
self.marginal_archive_gain.hex()
|
|
262
|
+
),
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
def to_record(self) -> dict[str, object]:
|
|
266
|
+
self.__post_init__()
|
|
267
|
+
return {
|
|
268
|
+
**self._unsigned_record(),
|
|
269
|
+
"positive": self.positive,
|
|
270
|
+
"outcome_sha256": self.outcome_sha256,
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def _validated_action_evaluation_bindings(
|
|
275
|
+
values: tuple[tuple[str, str], ...],
|
|
276
|
+
*,
|
|
277
|
+
name: str,
|
|
278
|
+
allow_empty: bool,
|
|
279
|
+
) -> tuple[tuple[str, str], ...]:
|
|
280
|
+
if type(values) is not tuple or (not allow_empty and not values):
|
|
281
|
+
raise ValueError(f"{name} must be a canonical exact tuple")
|
|
282
|
+
bindings: list[tuple[str, str]] = []
|
|
283
|
+
for value in values:
|
|
284
|
+
if type(value) is not tuple or len(value) != 2:
|
|
285
|
+
raise TypeError(f"{name} must contain exact hash pairs")
|
|
286
|
+
action_sha256, evaluation_sha256 = value
|
|
287
|
+
require_sha256(action_sha256, f"{name} action_sha256")
|
|
288
|
+
require_sha256(evaluation_sha256, f"{name} evaluation_sha256")
|
|
289
|
+
bindings.append((action_sha256, evaluation_sha256))
|
|
290
|
+
if bindings != sorted(set(bindings)):
|
|
291
|
+
raise ValueError(f"{name} must be unique and canonical")
|
|
292
|
+
if len({value[0] for value in bindings}) != len(bindings):
|
|
293
|
+
raise ValueError(f"{name} repeats an action identity")
|
|
294
|
+
if len({value[1] for value in bindings}) != len(bindings):
|
|
295
|
+
raise ValueError(f"{name} repeats an evaluation identity")
|
|
296
|
+
return tuple(bindings)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def _require_nonnegative_metric(value: float, *, name: str) -> None:
|
|
300
|
+
if (
|
|
301
|
+
type(value) is not float
|
|
302
|
+
or not math.isfinite(value)
|
|
303
|
+
or value < 0.0
|
|
304
|
+
):
|
|
305
|
+
raise ValueError(f"{name} must be finite and non-negative")
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def _metric_close(left: float, right: float) -> bool:
|
|
309
|
+
return math.isclose(left, right, rel_tol=1e-12, abs_tol=1e-15)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
@dataclass(frozen=True, slots=True)
|
|
313
|
+
class AdaptiveActionSetOutcome:
|
|
314
|
+
"""Workload-opaque causal utility observation for one evaluated wave.
|
|
315
|
+
|
|
316
|
+
``current_wave_fixed_set_gain`` values the current wave against the
|
|
317
|
+
pre-stage archive. ``conditional_set_gain`` values the same wave after
|
|
318
|
+
every earlier selected evaluation. Their difference therefore separates
|
|
319
|
+
local saturation (redundancy) from positive set interaction (synergy)
|
|
320
|
+
without exposing objective names, senses, configuration fields, or
|
|
321
|
+
workload semantics to the generic controller.
|
|
322
|
+
"""
|
|
323
|
+
|
|
324
|
+
prior_action_evaluation_bindings: tuple[tuple[str, str], ...]
|
|
325
|
+
current_action_evaluation_bindings: tuple[tuple[str, str], ...]
|
|
326
|
+
prior_selected_set_gain: float
|
|
327
|
+
current_wave_fixed_set_gain: float
|
|
328
|
+
augmented_selected_set_gain: float
|
|
329
|
+
conditional_set_gain: float
|
|
330
|
+
set_outcome_sha256: str = field(init=False)
|
|
331
|
+
|
|
332
|
+
def __post_init__(self) -> None:
|
|
333
|
+
prior = _validated_action_evaluation_bindings(
|
|
334
|
+
self.prior_action_evaluation_bindings,
|
|
335
|
+
name="prior_action_evaluation_bindings",
|
|
336
|
+
allow_empty=True,
|
|
337
|
+
)
|
|
338
|
+
current = _validated_action_evaluation_bindings(
|
|
339
|
+
self.current_action_evaluation_bindings,
|
|
340
|
+
name="current_action_evaluation_bindings",
|
|
341
|
+
allow_empty=False,
|
|
342
|
+
)
|
|
343
|
+
prior_actions = {value[0] for value in prior}
|
|
344
|
+
current_actions = {value[0] for value in current}
|
|
345
|
+
prior_evaluations = {value[1] for value in prior}
|
|
346
|
+
current_evaluations = {value[1] for value in current}
|
|
347
|
+
if prior_actions & current_actions:
|
|
348
|
+
raise ValueError("prior and current bindings repeat an action")
|
|
349
|
+
if prior_evaluations & current_evaluations:
|
|
350
|
+
raise ValueError(
|
|
351
|
+
"prior and current bindings repeat an evaluation"
|
|
352
|
+
)
|
|
353
|
+
for name in (
|
|
354
|
+
"prior_selected_set_gain",
|
|
355
|
+
"current_wave_fixed_set_gain",
|
|
356
|
+
"augmented_selected_set_gain",
|
|
357
|
+
"conditional_set_gain",
|
|
358
|
+
):
|
|
359
|
+
_require_nonnegative_metric(getattr(self, name), name=name)
|
|
360
|
+
if not _metric_close(
|
|
361
|
+
self.augmented_selected_set_gain,
|
|
362
|
+
self.prior_selected_set_gain + self.conditional_set_gain,
|
|
363
|
+
):
|
|
364
|
+
raise ValueError(
|
|
365
|
+
"conditional_set_gain does not close the augmented set"
|
|
366
|
+
)
|
|
367
|
+
object.__setattr__(
|
|
368
|
+
self,
|
|
369
|
+
"set_outcome_sha256",
|
|
370
|
+
_hash(_SET_OUTCOME_DOMAIN, self._unsigned_record()),
|
|
371
|
+
)
|
|
372
|
+
|
|
373
|
+
@property
|
|
374
|
+
def prior_conditioned_redundancy(self) -> float:
|
|
375
|
+
if _metric_close(
|
|
376
|
+
self.current_wave_fixed_set_gain,
|
|
377
|
+
self.conditional_set_gain,
|
|
378
|
+
):
|
|
379
|
+
return 0.0
|
|
380
|
+
return max(
|
|
381
|
+
self.current_wave_fixed_set_gain
|
|
382
|
+
- self.conditional_set_gain,
|
|
383
|
+
0.0,
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
@property
|
|
387
|
+
def prior_conditioned_synergy(self) -> float:
|
|
388
|
+
if _metric_close(
|
|
389
|
+
self.current_wave_fixed_set_gain,
|
|
390
|
+
self.conditional_set_gain,
|
|
391
|
+
):
|
|
392
|
+
return 0.0
|
|
393
|
+
return max(
|
|
394
|
+
self.conditional_set_gain
|
|
395
|
+
- self.current_wave_fixed_set_gain,
|
|
396
|
+
0.0,
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
@property
|
|
400
|
+
def saturation_fraction(self) -> float:
|
|
401
|
+
if self.current_wave_fixed_set_gain == 0.0:
|
|
402
|
+
return 0.0
|
|
403
|
+
return min(
|
|
404
|
+
self.prior_conditioned_redundancy
|
|
405
|
+
/ self.current_wave_fixed_set_gain,
|
|
406
|
+
1.0,
|
|
407
|
+
)
|
|
408
|
+
|
|
409
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
410
|
+
return {
|
|
411
|
+
"schema_version": 1,
|
|
412
|
+
"prior_action_evaluation_bindings": [
|
|
413
|
+
{
|
|
414
|
+
"action_sha256": action_sha256,
|
|
415
|
+
"evaluation_sha256": evaluation_sha256,
|
|
416
|
+
}
|
|
417
|
+
for action_sha256, evaluation_sha256 in (
|
|
418
|
+
self.prior_action_evaluation_bindings
|
|
419
|
+
)
|
|
420
|
+
],
|
|
421
|
+
"current_action_evaluation_bindings": [
|
|
422
|
+
{
|
|
423
|
+
"action_sha256": action_sha256,
|
|
424
|
+
"evaluation_sha256": evaluation_sha256,
|
|
425
|
+
}
|
|
426
|
+
for action_sha256, evaluation_sha256 in (
|
|
427
|
+
self.current_action_evaluation_bindings
|
|
428
|
+
)
|
|
429
|
+
],
|
|
430
|
+
"prior_selected_set_gain_hex": (
|
|
431
|
+
self.prior_selected_set_gain.hex()
|
|
432
|
+
),
|
|
433
|
+
"current_wave_fixed_set_gain_hex": (
|
|
434
|
+
self.current_wave_fixed_set_gain.hex()
|
|
435
|
+
),
|
|
436
|
+
"augmented_selected_set_gain_hex": (
|
|
437
|
+
self.augmented_selected_set_gain.hex()
|
|
438
|
+
),
|
|
439
|
+
"conditional_set_gain_hex": self.conditional_set_gain.hex(),
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
def to_record(self) -> dict[str, object]:
|
|
443
|
+
self.__post_init__()
|
|
444
|
+
return {
|
|
445
|
+
**self._unsigned_record(),
|
|
446
|
+
"prior_conditioned_redundancy_hex": (
|
|
447
|
+
self.prior_conditioned_redundancy.hex()
|
|
448
|
+
),
|
|
449
|
+
"prior_conditioned_synergy_hex": (
|
|
450
|
+
self.prior_conditioned_synergy.hex()
|
|
451
|
+
),
|
|
452
|
+
"saturation_fraction_hex": self.saturation_fraction.hex(),
|
|
453
|
+
"set_outcome_sha256": self.set_outcome_sha256,
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
class AdaptiveActionWave(str, Enum):
|
|
458
|
+
DIAGNOSTIC = "diagnostic"
|
|
459
|
+
ADAPTIVE = "adaptive"
|
|
460
|
+
RANDOMIZED_AUDIT = "randomized_audit"
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
@dataclass(frozen=True, slots=True)
|
|
464
|
+
class AdaptiveActionRacingDecision:
|
|
465
|
+
"""Hash-bound action subset chosen at one information cutoff."""
|
|
466
|
+
|
|
467
|
+
policy_id: str
|
|
468
|
+
policy_version: int
|
|
469
|
+
policy_definition_sha256: str
|
|
470
|
+
residual_request_sha256: str
|
|
471
|
+
wave: AdaptiveActionWave
|
|
472
|
+
selected_action_sha256s: tuple[str, ...]
|
|
473
|
+
prior_selected_action_sha256s: tuple[str, ...]
|
|
474
|
+
observed_outcome_sha256s: tuple[str, ...]
|
|
475
|
+
observed_set_outcome_sha256s: tuple[str, ...]
|
|
476
|
+
selection_propensity: float
|
|
477
|
+
evidence: FrozenJsonObject
|
|
478
|
+
decision_sha256: str = field(init=False)
|
|
479
|
+
|
|
480
|
+
def __post_init__(self) -> None:
|
|
481
|
+
_require_token(self.policy_id, name="policy_id")
|
|
482
|
+
if type(self.policy_version) is not int or self.policy_version <= 0:
|
|
483
|
+
raise ValueError("policy_version must be positive")
|
|
484
|
+
require_sha256(
|
|
485
|
+
self.policy_definition_sha256,
|
|
486
|
+
"policy_definition_sha256",
|
|
487
|
+
)
|
|
488
|
+
require_sha256(
|
|
489
|
+
self.residual_request_sha256,
|
|
490
|
+
"residual_request_sha256",
|
|
491
|
+
)
|
|
492
|
+
if type(self.wave) is not AdaptiveActionWave:
|
|
493
|
+
raise TypeError("wave must be an exact AdaptiveActionWave")
|
|
494
|
+
for values, name in (
|
|
495
|
+
(self.selected_action_sha256s, "selected_action_sha256s"),
|
|
496
|
+
(
|
|
497
|
+
self.prior_selected_action_sha256s,
|
|
498
|
+
"prior_selected_action_sha256s",
|
|
499
|
+
),
|
|
500
|
+
(
|
|
501
|
+
self.observed_outcome_sha256s,
|
|
502
|
+
"observed_outcome_sha256s",
|
|
503
|
+
),
|
|
504
|
+
(
|
|
505
|
+
self.observed_set_outcome_sha256s,
|
|
506
|
+
"observed_set_outcome_sha256s",
|
|
507
|
+
),
|
|
508
|
+
):
|
|
509
|
+
if type(values) is not tuple or values != tuple(
|
|
510
|
+
sorted(set(values))
|
|
511
|
+
):
|
|
512
|
+
raise ValueError(f"{name} must be an exact canonical tuple")
|
|
513
|
+
for value in values:
|
|
514
|
+
require_sha256(value, name)
|
|
515
|
+
if not self.selected_action_sha256s:
|
|
516
|
+
raise ValueError("a racing decision must select an action")
|
|
517
|
+
if set(self.selected_action_sha256s) & set(
|
|
518
|
+
self.prior_selected_action_sha256s
|
|
519
|
+
):
|
|
520
|
+
raise ValueError("a racing decision cannot repeat an action")
|
|
521
|
+
_require_probability(
|
|
522
|
+
self.selection_propensity,
|
|
523
|
+
name="selection_propensity",
|
|
524
|
+
)
|
|
525
|
+
if self.selection_propensity <= 0.0:
|
|
526
|
+
raise ValueError("selection propensity must be positive")
|
|
527
|
+
if (
|
|
528
|
+
self.wave is AdaptiveActionWave.DIAGNOSTIC
|
|
529
|
+
and (
|
|
530
|
+
self.observed_outcome_sha256s
|
|
531
|
+
or self.observed_set_outcome_sha256s
|
|
532
|
+
)
|
|
533
|
+
):
|
|
534
|
+
raise ValueError(
|
|
535
|
+
"diagnostic design cannot observe current outcomes"
|
|
536
|
+
)
|
|
537
|
+
if (
|
|
538
|
+
type(self.evidence) is not FrozenJsonObject
|
|
539
|
+
or freeze_json(self.evidence) is not self.evidence
|
|
540
|
+
):
|
|
541
|
+
raise TypeError("evidence must be an exact frozen object")
|
|
542
|
+
object.__setattr__(
|
|
543
|
+
self,
|
|
544
|
+
"decision_sha256",
|
|
545
|
+
_hash(_DECISION_DOMAIN, self._unsigned_record()),
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
@property
|
|
549
|
+
def candidate_outcomes_observed(self) -> bool:
|
|
550
|
+
return bool(self.observed_outcome_sha256s)
|
|
551
|
+
|
|
552
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
553
|
+
return {
|
|
554
|
+
"schema_version": 2,
|
|
555
|
+
"policy": {
|
|
556
|
+
"policy_id": self.policy_id,
|
|
557
|
+
"policy_version": self.policy_version,
|
|
558
|
+
"definition_sha256": self.policy_definition_sha256,
|
|
559
|
+
},
|
|
560
|
+
"residual_request_sha256": self.residual_request_sha256,
|
|
561
|
+
"wave": self.wave.value,
|
|
562
|
+
"selected_action_sha256s": list(
|
|
563
|
+
self.selected_action_sha256s
|
|
564
|
+
),
|
|
565
|
+
"prior_selected_action_sha256s": list(
|
|
566
|
+
self.prior_selected_action_sha256s
|
|
567
|
+
),
|
|
568
|
+
"observed_outcome_sha256s": list(
|
|
569
|
+
self.observed_outcome_sha256s
|
|
570
|
+
),
|
|
571
|
+
"observed_set_outcome_sha256s": list(
|
|
572
|
+
self.observed_set_outcome_sha256s
|
|
573
|
+
),
|
|
574
|
+
"candidate_outcomes_observed": (
|
|
575
|
+
self.candidate_outcomes_observed
|
|
576
|
+
),
|
|
577
|
+
"selection_propensity_hex": self.selection_propensity.hex(),
|
|
578
|
+
"evidence_sha256": typed_json_sha256(self.evidence),
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
def to_record(self, *, include_evidence: bool = False) -> dict[str, object]:
|
|
582
|
+
self.__post_init__()
|
|
583
|
+
record = {
|
|
584
|
+
**self._unsigned_record(),
|
|
585
|
+
"decision_sha256": self.decision_sha256,
|
|
586
|
+
}
|
|
587
|
+
if include_evidence:
|
|
588
|
+
record["evidence"] = thaw_json(self.evidence)
|
|
589
|
+
return record
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
@dataclass(frozen=True, slots=True)
|
|
593
|
+
class AdaptiveActionAllocationDirective:
|
|
594
|
+
"""Final outcome-adaptive slate constraint consumed by the broker.
|
|
595
|
+
|
|
596
|
+
Unlike ``MaterializedActionAllocationRequirement``, this directive is
|
|
597
|
+
intentionally outcome-conditioned. It binds the complete chain of
|
|
598
|
+
diagnostic and continuation decisions so downstream code cannot mistake it
|
|
599
|
+
for an outcome-blind requirement.
|
|
600
|
+
"""
|
|
601
|
+
|
|
602
|
+
policy_id: str
|
|
603
|
+
policy_version: int
|
|
604
|
+
policy_definition_sha256: str
|
|
605
|
+
residual_request_sha256: str
|
|
606
|
+
proposal_sha256s: tuple[str, ...]
|
|
607
|
+
required_action_sha256s: tuple[str, ...]
|
|
608
|
+
diagnostic_decision_sha256: str
|
|
609
|
+
continuation_decision_sha256s: tuple[str, ...]
|
|
610
|
+
observed_outcome_sha256s: tuple[str, ...]
|
|
611
|
+
observed_set_outcome_sha256s: tuple[str, ...]
|
|
612
|
+
evidence: FrozenJsonObject
|
|
613
|
+
directive_sha256: str = field(init=False)
|
|
614
|
+
|
|
615
|
+
def __post_init__(self) -> None:
|
|
616
|
+
_require_token(self.policy_id, name="policy_id")
|
|
617
|
+
if type(self.policy_version) is not int or self.policy_version <= 0:
|
|
618
|
+
raise ValueError("policy_version must be positive")
|
|
619
|
+
require_sha256(
|
|
620
|
+
self.policy_definition_sha256,
|
|
621
|
+
"policy_definition_sha256",
|
|
622
|
+
)
|
|
623
|
+
require_sha256(
|
|
624
|
+
self.residual_request_sha256,
|
|
625
|
+
"residual_request_sha256",
|
|
626
|
+
)
|
|
627
|
+
for values, name, allow_empty in (
|
|
628
|
+
(self.proposal_sha256s, "proposal_sha256s", False),
|
|
629
|
+
(
|
|
630
|
+
self.required_action_sha256s,
|
|
631
|
+
"required_action_sha256s",
|
|
632
|
+
False,
|
|
633
|
+
),
|
|
634
|
+
(
|
|
635
|
+
self.continuation_decision_sha256s,
|
|
636
|
+
"continuation_decision_sha256s",
|
|
637
|
+
False,
|
|
638
|
+
),
|
|
639
|
+
(
|
|
640
|
+
self.observed_outcome_sha256s,
|
|
641
|
+
"observed_outcome_sha256s",
|
|
642
|
+
False,
|
|
643
|
+
),
|
|
644
|
+
(
|
|
645
|
+
self.observed_set_outcome_sha256s,
|
|
646
|
+
"observed_set_outcome_sha256s",
|
|
647
|
+
False,
|
|
648
|
+
),
|
|
649
|
+
):
|
|
650
|
+
if (
|
|
651
|
+
type(values) is not tuple
|
|
652
|
+
or (not allow_empty and not values)
|
|
653
|
+
or values != tuple(sorted(set(values)))
|
|
654
|
+
):
|
|
655
|
+
raise ValueError(f"{name} must be a canonical exact tuple")
|
|
656
|
+
for value in values:
|
|
657
|
+
require_sha256(value, name)
|
|
658
|
+
require_sha256(
|
|
659
|
+
self.diagnostic_decision_sha256,
|
|
660
|
+
"diagnostic_decision_sha256",
|
|
661
|
+
)
|
|
662
|
+
if (
|
|
663
|
+
type(self.evidence) is not FrozenJsonObject
|
|
664
|
+
or freeze_json(self.evidence) is not self.evidence
|
|
665
|
+
):
|
|
666
|
+
raise TypeError("evidence must be an exact frozen object")
|
|
667
|
+
object.__setattr__(
|
|
668
|
+
self,
|
|
669
|
+
"directive_sha256",
|
|
670
|
+
_hash(_DIRECTIVE_DOMAIN, self._unsigned_record()),
|
|
671
|
+
)
|
|
672
|
+
|
|
673
|
+
@property
|
|
674
|
+
def candidate_outcomes_observed(self) -> bool:
|
|
675
|
+
return True
|
|
676
|
+
|
|
677
|
+
@property
|
|
678
|
+
def requirement_sha256(self) -> str:
|
|
679
|
+
"""Compatibility identity for the broker's existing constraint slot."""
|
|
680
|
+
|
|
681
|
+
return self.directive_sha256
|
|
682
|
+
|
|
683
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
684
|
+
return {
|
|
685
|
+
"schema_version": 2,
|
|
686
|
+
"allocation_kind": "outcome_adaptive_directive",
|
|
687
|
+
"policy": {
|
|
688
|
+
"policy_id": self.policy_id,
|
|
689
|
+
"policy_version": self.policy_version,
|
|
690
|
+
"definition_sha256": self.policy_definition_sha256,
|
|
691
|
+
},
|
|
692
|
+
"residual_request_sha256": self.residual_request_sha256,
|
|
693
|
+
"proposal_sha256s": list(self.proposal_sha256s),
|
|
694
|
+
"required_action_sha256s": list(
|
|
695
|
+
self.required_action_sha256s
|
|
696
|
+
),
|
|
697
|
+
"diagnostic_decision_sha256": (
|
|
698
|
+
self.diagnostic_decision_sha256
|
|
699
|
+
),
|
|
700
|
+
"continuation_decision_sha256s": list(
|
|
701
|
+
self.continuation_decision_sha256s
|
|
702
|
+
),
|
|
703
|
+
"observed_outcome_sha256s": list(
|
|
704
|
+
self.observed_outcome_sha256s
|
|
705
|
+
),
|
|
706
|
+
"observed_set_outcome_sha256s": list(
|
|
707
|
+
self.observed_set_outcome_sha256s
|
|
708
|
+
),
|
|
709
|
+
"candidate_outcomes_observed": True,
|
|
710
|
+
"evidence_sha256": typed_json_sha256(self.evidence),
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
def to_record(self, *, include_evidence: bool = False) -> dict[str, object]:
|
|
714
|
+
self.__post_init__()
|
|
715
|
+
record = {
|
|
716
|
+
**self._unsigned_record(),
|
|
717
|
+
"directive_sha256": self.directive_sha256,
|
|
718
|
+
"requirement_sha256": self.requirement_sha256,
|
|
719
|
+
}
|
|
720
|
+
if include_evidence:
|
|
721
|
+
record["evidence"] = thaw_json(self.evidence)
|
|
722
|
+
return record
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
def _semantic_distance(
|
|
726
|
+
left: tuple[str, ...],
|
|
727
|
+
right: tuple[str, ...],
|
|
728
|
+
) -> float:
|
|
729
|
+
union = set(left) | set(right)
|
|
730
|
+
if not union:
|
|
731
|
+
return 0.0
|
|
732
|
+
return 1.0 - (len(set(left) & set(right)) / len(union))
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
def _action_distance(
|
|
736
|
+
left: AdaptiveActionDescriptor,
|
|
737
|
+
right: AdaptiveActionDescriptor,
|
|
738
|
+
) -> float:
|
|
739
|
+
"""Portable mixed-type distance used only for coverage/uncertainty."""
|
|
740
|
+
|
|
741
|
+
left.__post_init__()
|
|
742
|
+
right.__post_init__()
|
|
743
|
+
return (
|
|
744
|
+
(1.0 if left.lane_id != right.lane_id else 0.0)
|
|
745
|
+
+ abs(left.rank_quality - right.rank_quality)
|
|
746
|
+
+ (
|
|
747
|
+
0.5
|
|
748
|
+
if left.parent_generated_in_current_run
|
|
749
|
+
!= right.parent_generated_in_current_run
|
|
750
|
+
else 0.0
|
|
751
|
+
)
|
|
752
|
+
+ (0.25 if left.operator_id != right.operator_id else 0.0)
|
|
753
|
+
+ 0.25
|
|
754
|
+
* _semantic_distance(
|
|
755
|
+
left.semantic_cell_ids,
|
|
756
|
+
right.semantic_cell_ids,
|
|
757
|
+
)
|
|
758
|
+
) / 3.0
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
@dataclass(frozen=True, slots=True)
|
|
762
|
+
class OutcomeAdaptiveActionRacingPolicy:
|
|
763
|
+
"""Lane-head diagnostic design followed by conservative contextual UCB."""
|
|
764
|
+
|
|
765
|
+
diagnostic_slots: int = 4
|
|
766
|
+
randomized_audit_slots: int = 1
|
|
767
|
+
reference_gain_scale: float = 1.0e-4
|
|
768
|
+
reference_gain_evidence_sha256: str = "0" * 64
|
|
769
|
+
prior_strength: float = 2.0
|
|
770
|
+
ucb_strength: float = 1.0
|
|
771
|
+
counterfactual_strength: float = 0.5
|
|
772
|
+
diversity_strength: float = 0.25
|
|
773
|
+
positive_redundancy_strength: float = 0.0
|
|
774
|
+
conditional_saturation_strength: float = 0.0
|
|
775
|
+
conditional_synergy_strength: float = 0.0
|
|
776
|
+
causal_prior_strength: float = 0.0
|
|
777
|
+
randomized_audit_after_directed_steps: int = 0
|
|
778
|
+
audit_exploration_probability: float = 0.0
|
|
779
|
+
exploration_pool_size: int = 4
|
|
780
|
+
trace_alternative_count: int = 0
|
|
781
|
+
stratified_audit_coverage_family_ids: tuple[str, ...] = ()
|
|
782
|
+
stratified_audit_stratum_family_ids: tuple[str, ...] = ()
|
|
783
|
+
minimum_post_audit_optimization_slots: int = 0
|
|
784
|
+
terminal_hierarchical_slots: int = 0
|
|
785
|
+
native_rank_strength: float = 0.0
|
|
786
|
+
random_seed: int = 0
|
|
787
|
+
policy_id: str = OUTCOME_ADAPTIVE_ACTION_RACING_POLICY_ID
|
|
788
|
+
policy_version: int = OUTCOME_ADAPTIVE_ACTION_RACING_POLICY_VERSION
|
|
789
|
+
definition_sha256: str = field(init=False)
|
|
790
|
+
|
|
791
|
+
def __post_init__(self) -> None:
|
|
792
|
+
if type(self.diagnostic_slots) is not int or self.diagnostic_slots <= 0:
|
|
793
|
+
raise ValueError("diagnostic_slots must be positive")
|
|
794
|
+
if (
|
|
795
|
+
type(self.randomized_audit_slots) is not int
|
|
796
|
+
or self.randomized_audit_slots <= 0
|
|
797
|
+
or self.randomized_audit_slots >= self.diagnostic_slots * 2
|
|
798
|
+
):
|
|
799
|
+
raise ValueError("randomized_audit_slots must be bounded")
|
|
800
|
+
if (
|
|
801
|
+
type(self.reference_gain_scale) is not float
|
|
802
|
+
or not math.isfinite(self.reference_gain_scale)
|
|
803
|
+
or self.reference_gain_scale <= 0.0
|
|
804
|
+
):
|
|
805
|
+
raise ValueError("reference_gain_scale must be positive")
|
|
806
|
+
require_sha256(
|
|
807
|
+
self.reference_gain_evidence_sha256,
|
|
808
|
+
"reference_gain_evidence_sha256",
|
|
809
|
+
)
|
|
810
|
+
for value, name in (
|
|
811
|
+
(self.prior_strength, "prior_strength"),
|
|
812
|
+
(self.ucb_strength, "ucb_strength"),
|
|
813
|
+
(
|
|
814
|
+
self.counterfactual_strength,
|
|
815
|
+
"counterfactual_strength",
|
|
816
|
+
),
|
|
817
|
+
(self.diversity_strength, "diversity_strength"),
|
|
818
|
+
(
|
|
819
|
+
self.positive_redundancy_strength,
|
|
820
|
+
"positive_redundancy_strength",
|
|
821
|
+
),
|
|
822
|
+
(
|
|
823
|
+
self.conditional_saturation_strength,
|
|
824
|
+
"conditional_saturation_strength",
|
|
825
|
+
),
|
|
826
|
+
(
|
|
827
|
+
self.conditional_synergy_strength,
|
|
828
|
+
"conditional_synergy_strength",
|
|
829
|
+
),
|
|
830
|
+
(
|
|
831
|
+
self.causal_prior_strength,
|
|
832
|
+
"causal_prior_strength",
|
|
833
|
+
),
|
|
834
|
+
):
|
|
835
|
+
if (
|
|
836
|
+
type(value) is not float
|
|
837
|
+
or not math.isfinite(value)
|
|
838
|
+
or value < 0.0
|
|
839
|
+
):
|
|
840
|
+
raise ValueError(f"{name} must be finite and non-negative")
|
|
841
|
+
if (
|
|
842
|
+
type(self.exploration_pool_size) is not int
|
|
843
|
+
or self.exploration_pool_size <= 0
|
|
844
|
+
):
|
|
845
|
+
raise ValueError("exploration_pool_size must be positive")
|
|
846
|
+
if (
|
|
847
|
+
type(self.randomized_audit_after_directed_steps) is not int
|
|
848
|
+
or self.randomized_audit_after_directed_steps < 0
|
|
849
|
+
):
|
|
850
|
+
raise ValueError(
|
|
851
|
+
"randomized_audit_after_directed_steps must be "
|
|
852
|
+
"non-negative"
|
|
853
|
+
)
|
|
854
|
+
if (
|
|
855
|
+
type(self.minimum_post_audit_optimization_slots) is not int
|
|
856
|
+
or self.minimum_post_audit_optimization_slots < 0
|
|
857
|
+
):
|
|
858
|
+
raise ValueError(
|
|
859
|
+
"minimum_post_audit_optimization_slots must be non-negative"
|
|
860
|
+
)
|
|
861
|
+
if (
|
|
862
|
+
type(self.terminal_hierarchical_slots) is not int
|
|
863
|
+
or self.terminal_hierarchical_slots < 0
|
|
864
|
+
):
|
|
865
|
+
raise ValueError(
|
|
866
|
+
"terminal_hierarchical_slots must be non-negative"
|
|
867
|
+
)
|
|
868
|
+
if (
|
|
869
|
+
type(self.native_rank_strength) is not float
|
|
870
|
+
or not math.isfinite(self.native_rank_strength)
|
|
871
|
+
or self.native_rank_strength < 0.0
|
|
872
|
+
):
|
|
873
|
+
raise ValueError(
|
|
874
|
+
"native_rank_strength must be finite and non-negative"
|
|
875
|
+
)
|
|
876
|
+
_require_probability(
|
|
877
|
+
self.audit_exploration_probability,
|
|
878
|
+
name="audit_exploration_probability",
|
|
879
|
+
)
|
|
880
|
+
if (
|
|
881
|
+
type(self.trace_alternative_count) is not int
|
|
882
|
+
or self.trace_alternative_count < 0
|
|
883
|
+
):
|
|
884
|
+
raise ValueError(
|
|
885
|
+
"trace_alternative_count must be non-negative"
|
|
886
|
+
)
|
|
887
|
+
for values, name in (
|
|
888
|
+
(
|
|
889
|
+
self.stratified_audit_coverage_family_ids,
|
|
890
|
+
"stratified_audit_coverage_family_ids",
|
|
891
|
+
),
|
|
892
|
+
(
|
|
893
|
+
self.stratified_audit_stratum_family_ids,
|
|
894
|
+
"stratified_audit_stratum_family_ids",
|
|
895
|
+
),
|
|
896
|
+
):
|
|
897
|
+
if (
|
|
898
|
+
type(values) is not tuple
|
|
899
|
+
or values != tuple(sorted(set(values)))
|
|
900
|
+
):
|
|
901
|
+
raise ValueError(f"{name} must be an exact canonical tuple")
|
|
902
|
+
for value in values:
|
|
903
|
+
_require_token(value, name=name)
|
|
904
|
+
if type(self.random_seed) is not int or self.random_seed < 0:
|
|
905
|
+
raise ValueError("random_seed must be non-negative")
|
|
906
|
+
_require_token(self.policy_id, name="policy_id")
|
|
907
|
+
if self.policy_version not in {
|
|
908
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_POLICY_VERSION,
|
|
909
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_SET_AWARE_POLICY_VERSION,
|
|
910
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_CAUSAL_SET_POLICY_VERSION,
|
|
911
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_RISK_CONTROLLED_POLICY_VERSION,
|
|
912
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_STRATIFIED_AUDIT_POLICY_VERSION,
|
|
913
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_HORIZON_HIERARCHICAL_POLICY_VERSION,
|
|
914
|
+
}:
|
|
915
|
+
raise ValueError("policy_version is unsupported")
|
|
916
|
+
if (
|
|
917
|
+
self.policy_version
|
|
918
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_POLICY_VERSION
|
|
919
|
+
and (
|
|
920
|
+
self.positive_redundancy_strength != 0.0
|
|
921
|
+
or self.trace_alternative_count != 0
|
|
922
|
+
or self.conditional_saturation_strength != 0.0
|
|
923
|
+
or self.conditional_synergy_strength != 0.0
|
|
924
|
+
or self.causal_prior_strength != 0.0
|
|
925
|
+
or self.randomized_audit_after_directed_steps != 0
|
|
926
|
+
or self.audit_exploration_probability != 0.0
|
|
927
|
+
or self.stratified_audit_coverage_family_ids
|
|
928
|
+
or self.stratified_audit_stratum_family_ids
|
|
929
|
+
or self.minimum_post_audit_optimization_slots != 0
|
|
930
|
+
or self.terminal_hierarchical_slots != 0
|
|
931
|
+
or self.native_rank_strength != 0.0
|
|
932
|
+
)
|
|
933
|
+
):
|
|
934
|
+
raise ValueError(
|
|
935
|
+
"set-aware controls require policy version 3"
|
|
936
|
+
)
|
|
937
|
+
if (
|
|
938
|
+
self.policy_version
|
|
939
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_SET_AWARE_POLICY_VERSION
|
|
940
|
+
and (
|
|
941
|
+
self.trace_alternative_count <= 0
|
|
942
|
+
or self.conditional_saturation_strength != 0.0
|
|
943
|
+
or self.conditional_synergy_strength != 0.0
|
|
944
|
+
or self.causal_prior_strength != 0.0
|
|
945
|
+
or self.randomized_audit_after_directed_steps != 0
|
|
946
|
+
or self.audit_exploration_probability != 0.0
|
|
947
|
+
or self.stratified_audit_coverage_family_ids
|
|
948
|
+
or self.stratified_audit_stratum_family_ids
|
|
949
|
+
or self.minimum_post_audit_optimization_slots != 0
|
|
950
|
+
or self.terminal_hierarchical_slots != 0
|
|
951
|
+
or self.native_rank_strength != 0.0
|
|
952
|
+
)
|
|
953
|
+
):
|
|
954
|
+
raise ValueError(
|
|
955
|
+
"policy version 3 requires auditable alternatives and "
|
|
956
|
+
"permits only its proxy controls"
|
|
957
|
+
)
|
|
958
|
+
if (
|
|
959
|
+
self.policy_version
|
|
960
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_CAUSAL_SET_POLICY_VERSION
|
|
961
|
+
and (
|
|
962
|
+
self.trace_alternative_count <= 0
|
|
963
|
+
or self.positive_redundancy_strength != 0.0
|
|
964
|
+
or self.conditional_saturation_strength <= 0.0
|
|
965
|
+
or self.causal_prior_strength <= 0.0
|
|
966
|
+
or self.randomized_audit_slots != 1
|
|
967
|
+
or self.audit_exploration_probability != 0.0
|
|
968
|
+
or self.stratified_audit_coverage_family_ids
|
|
969
|
+
or self.stratified_audit_stratum_family_ids
|
|
970
|
+
or self.minimum_post_audit_optimization_slots != 0
|
|
971
|
+
or self.terminal_hierarchical_slots != 0
|
|
972
|
+
or self.native_rank_strength != 0.0
|
|
973
|
+
)
|
|
974
|
+
):
|
|
975
|
+
raise ValueError(
|
|
976
|
+
"policy version 4 requires causal set controls, one "
|
|
977
|
+
"mid-wave audit, and auditable alternatives"
|
|
978
|
+
)
|
|
979
|
+
if (
|
|
980
|
+
self.policy_version
|
|
981
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_RISK_CONTROLLED_POLICY_VERSION
|
|
982
|
+
and (
|
|
983
|
+
self.trace_alternative_count <= 0
|
|
984
|
+
or self.positive_redundancy_strength != 0.0
|
|
985
|
+
or self.conditional_saturation_strength <= 0.0
|
|
986
|
+
or self.causal_prior_strength <= 0.0
|
|
987
|
+
or self.randomized_audit_slots != 1
|
|
988
|
+
or self.audit_exploration_probability <= 0.0
|
|
989
|
+
or self.stratified_audit_coverage_family_ids
|
|
990
|
+
or self.stratified_audit_stratum_family_ids
|
|
991
|
+
or self.minimum_post_audit_optimization_slots != 0
|
|
992
|
+
or self.terminal_hierarchical_slots != 0
|
|
993
|
+
or self.native_rank_strength != 0.0
|
|
994
|
+
)
|
|
995
|
+
):
|
|
996
|
+
raise ValueError(
|
|
997
|
+
"policy version 5 requires causal set controls, one "
|
|
998
|
+
"risk-controlled audit, positive epsilon, and auditable "
|
|
999
|
+
"alternatives"
|
|
1000
|
+
)
|
|
1001
|
+
if (
|
|
1002
|
+
self.policy_version
|
|
1003
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_STRATIFIED_AUDIT_POLICY_VERSION
|
|
1004
|
+
and (
|
|
1005
|
+
self.trace_alternative_count <= 0
|
|
1006
|
+
or self.positive_redundancy_strength != 0.0
|
|
1007
|
+
or self.conditional_saturation_strength != 0.0
|
|
1008
|
+
or self.conditional_synergy_strength != 0.0
|
|
1009
|
+
or self.causal_prior_strength != 0.0
|
|
1010
|
+
or self.randomized_audit_after_directed_steps != 0
|
|
1011
|
+
or self.randomized_audit_slots != 1
|
|
1012
|
+
or self.audit_exploration_probability <= 0.0
|
|
1013
|
+
or not self.stratified_audit_coverage_family_ids
|
|
1014
|
+
or not self.stratified_audit_stratum_family_ids
|
|
1015
|
+
or self.minimum_post_audit_optimization_slots != 0
|
|
1016
|
+
or self.terminal_hierarchical_slots != 0
|
|
1017
|
+
or self.native_rank_strength != 0.0
|
|
1018
|
+
)
|
|
1019
|
+
):
|
|
1020
|
+
raise ValueError(
|
|
1021
|
+
"policy version 6 requires one final risk-controlled audit, "
|
|
1022
|
+
"positive epsilon, auditable alternatives, and explicit "
|
|
1023
|
+
"coverage/stratum factor families"
|
|
1024
|
+
)
|
|
1025
|
+
if (
|
|
1026
|
+
self.policy_version
|
|
1027
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_HORIZON_HIERARCHICAL_POLICY_VERSION
|
|
1028
|
+
and (
|
|
1029
|
+
self.trace_alternative_count <= 0
|
|
1030
|
+
or self.positive_redundancy_strength != 0.0
|
|
1031
|
+
or self.conditional_saturation_strength != 0.0
|
|
1032
|
+
or self.conditional_synergy_strength != 0.0
|
|
1033
|
+
or self.causal_prior_strength != 0.0
|
|
1034
|
+
or self.randomized_audit_slots != 1
|
|
1035
|
+
or self.audit_exploration_probability != 0.0
|
|
1036
|
+
or self.stratified_audit_coverage_family_ids
|
|
1037
|
+
or self.stratified_audit_stratum_family_ids
|
|
1038
|
+
or self.minimum_post_audit_optimization_slots <= 0
|
|
1039
|
+
or self.terminal_hierarchical_slots <= 0
|
|
1040
|
+
or self.native_rank_strength <= 0.0
|
|
1041
|
+
)
|
|
1042
|
+
):
|
|
1043
|
+
raise ValueError(
|
|
1044
|
+
"policy version 7 requires robust hierarchical terminal "
|
|
1045
|
+
"allocation, at least one post-audit optimization slot, "
|
|
1046
|
+
"positive native-rank strength, one horizon-gated audit, "
|
|
1047
|
+
"and auditable alternatives"
|
|
1048
|
+
)
|
|
1049
|
+
definition = {
|
|
1050
|
+
"schema_version": 1,
|
|
1051
|
+
"policy_id": self.policy_id,
|
|
1052
|
+
"policy_version": self.policy_version,
|
|
1053
|
+
"diagnostic_slots": self.diagnostic_slots,
|
|
1054
|
+
"randomized_audit_slots": self.randomized_audit_slots,
|
|
1055
|
+
"reference_gain_scale_hex": (
|
|
1056
|
+
self.reference_gain_scale.hex()
|
|
1057
|
+
),
|
|
1058
|
+
"reference_gain_evidence_sha256": (
|
|
1059
|
+
self.reference_gain_evidence_sha256
|
|
1060
|
+
),
|
|
1061
|
+
"prior_strength_hex": self.prior_strength.hex(),
|
|
1062
|
+
"ucb_strength_hex": self.ucb_strength.hex(),
|
|
1063
|
+
"counterfactual_strength_hex": (
|
|
1064
|
+
self.counterfactual_strength.hex()
|
|
1065
|
+
),
|
|
1066
|
+
"diversity_strength_hex": (
|
|
1067
|
+
self.diversity_strength.hex()
|
|
1068
|
+
),
|
|
1069
|
+
"exploration_pool_size": self.exploration_pool_size,
|
|
1070
|
+
"random_seed": self.random_seed,
|
|
1071
|
+
"diagnostic_design": (
|
|
1072
|
+
"authenticated_fixed_constraints_then_one_consensus_"
|
|
1073
|
+
"lane_head_then_authority_disagreement_maximin"
|
|
1074
|
+
),
|
|
1075
|
+
"continuation": (
|
|
1076
|
+
"sequential_coalition_efficiency_scaled_"
|
|
1077
|
+
"contextual_ucb_plus_randomized_audit"
|
|
1078
|
+
),
|
|
1079
|
+
"unobserved_outcomes_accepted": False,
|
|
1080
|
+
"workload_objective_model_provider_prompt_branches": False,
|
|
1081
|
+
}
|
|
1082
|
+
if (
|
|
1083
|
+
self.policy_version
|
|
1084
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_SET_AWARE_POLICY_VERSION
|
|
1085
|
+
):
|
|
1086
|
+
definition.update(
|
|
1087
|
+
{
|
|
1088
|
+
"positive_redundancy_strength_hex": (
|
|
1089
|
+
self.positive_redundancy_strength.hex()
|
|
1090
|
+
),
|
|
1091
|
+
"trace_alternative_count": (
|
|
1092
|
+
self.trace_alternative_count
|
|
1093
|
+
),
|
|
1094
|
+
"continuation": (
|
|
1095
|
+
"sequential_coalition_efficiency_scaled_contextual_"
|
|
1096
|
+
"ucb_minus_positive_consequence_redundancy_plus_"
|
|
1097
|
+
"randomized_audit"
|
|
1098
|
+
),
|
|
1099
|
+
"set_value_proxy": (
|
|
1100
|
+
"outcome_weighted_portable_action_similarity"
|
|
1101
|
+
),
|
|
1102
|
+
}
|
|
1103
|
+
)
|
|
1104
|
+
if (
|
|
1105
|
+
self.policy_version
|
|
1106
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_CAUSAL_SET_POLICY_VERSION
|
|
1107
|
+
):
|
|
1108
|
+
definition.update(
|
|
1109
|
+
{
|
|
1110
|
+
"conditional_saturation_strength_hex": (
|
|
1111
|
+
self.conditional_saturation_strength.hex()
|
|
1112
|
+
),
|
|
1113
|
+
"conditional_synergy_strength_hex": (
|
|
1114
|
+
self.conditional_synergy_strength.hex()
|
|
1115
|
+
),
|
|
1116
|
+
"causal_prior_strength_hex": (
|
|
1117
|
+
self.causal_prior_strength.hex()
|
|
1118
|
+
),
|
|
1119
|
+
"randomized_audit_after_directed_steps": (
|
|
1120
|
+
self.randomized_audit_after_directed_steps
|
|
1121
|
+
),
|
|
1122
|
+
"trace_alternative_count": (
|
|
1123
|
+
self.trace_alternative_count
|
|
1124
|
+
),
|
|
1125
|
+
"continuation": (
|
|
1126
|
+
"conditional_opportunity_saturation_ucb_with_"
|
|
1127
|
+
"midwave_randomized_audit"
|
|
1128
|
+
),
|
|
1129
|
+
"set_value_evidence": (
|
|
1130
|
+
"real_fixed_and_prior_conditioned_archive_lift"
|
|
1131
|
+
),
|
|
1132
|
+
"proxy_positive_similarity_penalty": False,
|
|
1133
|
+
}
|
|
1134
|
+
)
|
|
1135
|
+
if (
|
|
1136
|
+
self.policy_version
|
|
1137
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_RISK_CONTROLLED_POLICY_VERSION
|
|
1138
|
+
):
|
|
1139
|
+
definition.update(
|
|
1140
|
+
{
|
|
1141
|
+
"conditional_saturation_strength_hex": (
|
|
1142
|
+
self.conditional_saturation_strength.hex()
|
|
1143
|
+
),
|
|
1144
|
+
"conditional_synergy_strength_hex": (
|
|
1145
|
+
self.conditional_synergy_strength.hex()
|
|
1146
|
+
),
|
|
1147
|
+
"causal_prior_strength_hex": (
|
|
1148
|
+
self.causal_prior_strength.hex()
|
|
1149
|
+
),
|
|
1150
|
+
"randomized_audit_after_directed_steps": (
|
|
1151
|
+
self.randomized_audit_after_directed_steps
|
|
1152
|
+
),
|
|
1153
|
+
"audit_exploration_probability_hex": (
|
|
1154
|
+
self.audit_exploration_probability.hex()
|
|
1155
|
+
),
|
|
1156
|
+
"trace_alternative_count": (
|
|
1157
|
+
self.trace_alternative_count
|
|
1158
|
+
),
|
|
1159
|
+
"diagnostic_and_directed_tie_breaks": (
|
|
1160
|
+
"canonical_action_hash_seed_invariant"
|
|
1161
|
+
),
|
|
1162
|
+
"continuation": (
|
|
1163
|
+
"conditional_opportunity_saturation_ucb_with_"
|
|
1164
|
+
"epsilon_greedy_risk_controlled_audit"
|
|
1165
|
+
),
|
|
1166
|
+
"audit_anchor": (
|
|
1167
|
+
"highest_conditional_ucb_action"
|
|
1168
|
+
),
|
|
1169
|
+
"audit_exploration_pool": (
|
|
1170
|
+
"anchor_plus_portable_diversity_ranked_actions"
|
|
1171
|
+
),
|
|
1172
|
+
"audit_propensity": (
|
|
1173
|
+
"anchor=one_minus_epsilon_plus_epsilon_over_pool;"
|
|
1174
|
+
"other=epsilon_over_pool"
|
|
1175
|
+
),
|
|
1176
|
+
"set_value_evidence": (
|
|
1177
|
+
"real_fixed_and_prior_conditioned_archive_lift"
|
|
1178
|
+
),
|
|
1179
|
+
"proxy_positive_similarity_penalty": False,
|
|
1180
|
+
}
|
|
1181
|
+
)
|
|
1182
|
+
if (
|
|
1183
|
+
self.policy_version
|
|
1184
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_STRATIFIED_AUDIT_POLICY_VERSION
|
|
1185
|
+
):
|
|
1186
|
+
definition.update(
|
|
1187
|
+
{
|
|
1188
|
+
"audit_exploration_probability_hex": (
|
|
1189
|
+
self.audit_exploration_probability.hex()
|
|
1190
|
+
),
|
|
1191
|
+
"trace_alternative_count": (
|
|
1192
|
+
self.trace_alternative_count
|
|
1193
|
+
),
|
|
1194
|
+
"stratified_audit_coverage_family_ids": list(
|
|
1195
|
+
self.stratified_audit_coverage_family_ids
|
|
1196
|
+
),
|
|
1197
|
+
"stratified_audit_stratum_family_ids": list(
|
|
1198
|
+
self.stratified_audit_stratum_family_ids
|
|
1199
|
+
),
|
|
1200
|
+
"continuation": (
|
|
1201
|
+
"set_aware_ucb_with_legacy_audit_anchor_and_"
|
|
1202
|
+
"risk_controlled_factor_stratified_exploration"
|
|
1203
|
+
),
|
|
1204
|
+
"audit_anchor": (
|
|
1205
|
+
"frozen_version3_diversity_rank_counterfactual_"
|
|
1206
|
+
"seeded_choice"
|
|
1207
|
+
),
|
|
1208
|
+
"audit_exploration_support": (
|
|
1209
|
+
"maximally_uncovered_configured_factor_cells"
|
|
1210
|
+
),
|
|
1211
|
+
"audit_exploration_propensity": (
|
|
1212
|
+
"uniform-nonempty-factor-stratum-then-uniform-action"
|
|
1213
|
+
),
|
|
1214
|
+
"audit_total_propensity": (
|
|
1215
|
+
"legacy-anchor=one-minus-epsilon-plus-exploration-"
|
|
1216
|
+
"mass-if-supported;other=exploration-mass"
|
|
1217
|
+
),
|
|
1218
|
+
"candidate_factor_cells_outcome_blind": True,
|
|
1219
|
+
"unobserved_outcomes_accepted": False,
|
|
1220
|
+
}
|
|
1221
|
+
)
|
|
1222
|
+
if (
|
|
1223
|
+
self.policy_version
|
|
1224
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_HORIZON_HIERARCHICAL_POLICY_VERSION
|
|
1225
|
+
):
|
|
1226
|
+
definition.update(
|
|
1227
|
+
{
|
|
1228
|
+
"trace_alternative_count": (
|
|
1229
|
+
self.trace_alternative_count
|
|
1230
|
+
),
|
|
1231
|
+
"randomized_audit_after_directed_steps": (
|
|
1232
|
+
self.randomized_audit_after_directed_steps
|
|
1233
|
+
),
|
|
1234
|
+
"minimum_post_audit_optimization_slots": (
|
|
1235
|
+
self.minimum_post_audit_optimization_slots
|
|
1236
|
+
),
|
|
1237
|
+
"terminal_hierarchical_slots": (
|
|
1238
|
+
self.terminal_hierarchical_slots
|
|
1239
|
+
),
|
|
1240
|
+
"native_rank_strength_hex": (
|
|
1241
|
+
self.native_rank_strength.hex()
|
|
1242
|
+
),
|
|
1243
|
+
"engine_return": (
|
|
1244
|
+
"bayesian_mean_of_reference_scale_capped_"
|
|
1245
|
+
"marginal_archive_gain"
|
|
1246
|
+
),
|
|
1247
|
+
"engine_then_action_allocation": True,
|
|
1248
|
+
"within_engine_terminal_index": (
|
|
1249
|
+
"contextual_posterior_gain_plus_calibratable_"
|
|
1250
|
+
"native_rank_prior"
|
|
1251
|
+
),
|
|
1252
|
+
"continuation": (
|
|
1253
|
+
"contextual_ucb_before_terminal_horizon_then_"
|
|
1254
|
+
"robust_engine_exposure_and_within_engine_"
|
|
1255
|
+
"exploitation"
|
|
1256
|
+
),
|
|
1257
|
+
"audit_schedule": (
|
|
1258
|
+
"configured_directed_step_only_when_at_least_"
|
|
1259
|
+
"minimum_post_audit_optimization_slots_remain"
|
|
1260
|
+
),
|
|
1261
|
+
"terminal_information_only_authoritative_purchase": False,
|
|
1262
|
+
"workload_model_provider_prompt_branches": False,
|
|
1263
|
+
}
|
|
1264
|
+
)
|
|
1265
|
+
object.__setattr__(
|
|
1266
|
+
self,
|
|
1267
|
+
"definition_sha256",
|
|
1268
|
+
_hash(_POLICY_DEFINITION_DOMAIN, definition),
|
|
1269
|
+
)
|
|
1270
|
+
|
|
1271
|
+
@staticmethod
|
|
1272
|
+
def _validate_market(
|
|
1273
|
+
actions: tuple[AdaptiveActionDescriptor, ...],
|
|
1274
|
+
) -> dict[str, AdaptiveActionDescriptor]:
|
|
1275
|
+
if type(actions) is not tuple or not actions:
|
|
1276
|
+
raise ValueError("actions must be a non-empty exact tuple")
|
|
1277
|
+
by_action: dict[str, AdaptiveActionDescriptor] = {}
|
|
1278
|
+
lane_counts: dict[str, int] = {}
|
|
1279
|
+
for value in actions:
|
|
1280
|
+
if type(value) is not AdaptiveActionDescriptor:
|
|
1281
|
+
raise TypeError("actions must contain exact descriptors")
|
|
1282
|
+
value.__post_init__()
|
|
1283
|
+
if value.action_sha256 in by_action:
|
|
1284
|
+
raise ValueError("action identities repeat")
|
|
1285
|
+
by_action[value.action_sha256] = value
|
|
1286
|
+
lane_counts[value.lane_id] = lane_counts.get(value.lane_id, 0) + 1
|
|
1287
|
+
if any(
|
|
1288
|
+
value.lane_size != lane_counts[value.lane_id]
|
|
1289
|
+
for value in actions
|
|
1290
|
+
):
|
|
1291
|
+
raise ValueError("declared lane sizes differ from the market")
|
|
1292
|
+
if len({value.phenotype_sha256 for value in actions}) != len(actions):
|
|
1293
|
+
raise ValueError(
|
|
1294
|
+
"adaptive market must contain unique phenotype identities"
|
|
1295
|
+
)
|
|
1296
|
+
return by_action
|
|
1297
|
+
|
|
1298
|
+
@staticmethod
|
|
1299
|
+
def _minimum_distance(
|
|
1300
|
+
action: AdaptiveActionDescriptor,
|
|
1301
|
+
selected: tuple[AdaptiveActionDescriptor, ...],
|
|
1302
|
+
) -> float:
|
|
1303
|
+
if not selected:
|
|
1304
|
+
return 1.0
|
|
1305
|
+
return min(_action_distance(action, value) for value in selected)
|
|
1306
|
+
|
|
1307
|
+
def design_diagnostic_pilot(
|
|
1308
|
+
self,
|
|
1309
|
+
*,
|
|
1310
|
+
residual_request_sha256: str,
|
|
1311
|
+
actions: tuple[AdaptiveActionDescriptor, ...],
|
|
1312
|
+
evaluation_slots: int,
|
|
1313
|
+
required_action_sha256s: tuple[str, ...] = (),
|
|
1314
|
+
) -> AdaptiveActionRacingDecision:
|
|
1315
|
+
"""Choose a constrained lane-head pilot, then fill it by maximin."""
|
|
1316
|
+
|
|
1317
|
+
self.__post_init__()
|
|
1318
|
+
require_sha256(
|
|
1319
|
+
residual_request_sha256,
|
|
1320
|
+
"residual_request_sha256",
|
|
1321
|
+
)
|
|
1322
|
+
by_action = self._validate_market(actions)
|
|
1323
|
+
if (
|
|
1324
|
+
type(evaluation_slots) is not int
|
|
1325
|
+
or not 2 <= evaluation_slots <= len(actions)
|
|
1326
|
+
):
|
|
1327
|
+
raise ValueError("evaluation_slots must fit the action market")
|
|
1328
|
+
pilot_width = min(
|
|
1329
|
+
self.diagnostic_slots,
|
|
1330
|
+
evaluation_slots - self.randomized_audit_slots,
|
|
1331
|
+
)
|
|
1332
|
+
if pilot_width <= 0:
|
|
1333
|
+
raise ValueError("diagnostic design leaves no pilot")
|
|
1334
|
+
if (
|
|
1335
|
+
type(required_action_sha256s) is not tuple
|
|
1336
|
+
or required_action_sha256s
|
|
1337
|
+
!= tuple(sorted(set(required_action_sha256s)))
|
|
1338
|
+
):
|
|
1339
|
+
raise ValueError(
|
|
1340
|
+
"required_action_sha256s must be an exact canonical tuple"
|
|
1341
|
+
)
|
|
1342
|
+
if not set(required_action_sha256s).issubset(by_action):
|
|
1343
|
+
raise ValueError(
|
|
1344
|
+
"a required diagnostic action is outside the sealed market"
|
|
1345
|
+
)
|
|
1346
|
+
if len(required_action_sha256s) > pilot_width:
|
|
1347
|
+
raise ValueError(
|
|
1348
|
+
"fixed allocation constraints exceed diagnostic capacity"
|
|
1349
|
+
)
|
|
1350
|
+
|
|
1351
|
+
by_lane: dict[str, list[AdaptiveActionDescriptor]] = {}
|
|
1352
|
+
for action in actions:
|
|
1353
|
+
by_lane.setdefault(action.lane_id, []).append(action)
|
|
1354
|
+
lane_heads = tuple(
|
|
1355
|
+
sorted(
|
|
1356
|
+
(
|
|
1357
|
+
min(
|
|
1358
|
+
values,
|
|
1359
|
+
key=lambda value: (
|
|
1360
|
+
-value.prior_score,
|
|
1361
|
+
value.native_rank,
|
|
1362
|
+
value.action_sha256,
|
|
1363
|
+
),
|
|
1364
|
+
)
|
|
1365
|
+
for values in by_lane.values()
|
|
1366
|
+
),
|
|
1367
|
+
key=lambda value: (
|
|
1368
|
+
-value.prior_score,
|
|
1369
|
+
value.native_rank,
|
|
1370
|
+
value.lane_id,
|
|
1371
|
+
value.action_sha256,
|
|
1372
|
+
),
|
|
1373
|
+
)
|
|
1374
|
+
)
|
|
1375
|
+
selected: list[AdaptiveActionDescriptor] = [
|
|
1376
|
+
by_action[value] for value in required_action_sha256s
|
|
1377
|
+
]
|
|
1378
|
+
trace: list[dict[str, object]] = [
|
|
1379
|
+
{
|
|
1380
|
+
"ordinal": ordinal,
|
|
1381
|
+
"action_sha256": value.action_sha256,
|
|
1382
|
+
"reason": "fixed_allocation_constraint",
|
|
1383
|
+
"lane_id": value.lane_id,
|
|
1384
|
+
"native_rank": value.native_rank,
|
|
1385
|
+
}
|
|
1386
|
+
for ordinal, value in enumerate(selected, start=1)
|
|
1387
|
+
]
|
|
1388
|
+
for value in lane_heads:
|
|
1389
|
+
if len(selected) >= pilot_width:
|
|
1390
|
+
break
|
|
1391
|
+
if value.action_sha256 in {
|
|
1392
|
+
item.action_sha256 for item in selected
|
|
1393
|
+
}:
|
|
1394
|
+
continue
|
|
1395
|
+
selected.append(value)
|
|
1396
|
+
trace.append(
|
|
1397
|
+
{
|
|
1398
|
+
"ordinal": len(selected),
|
|
1399
|
+
"action_sha256": value.action_sha256,
|
|
1400
|
+
"reason": "lane_head",
|
|
1401
|
+
"lane_id": value.lane_id,
|
|
1402
|
+
"native_rank": value.native_rank,
|
|
1403
|
+
}
|
|
1404
|
+
)
|
|
1405
|
+
while len(selected) < pilot_width:
|
|
1406
|
+
candidates = tuple(
|
|
1407
|
+
value
|
|
1408
|
+
for value in actions
|
|
1409
|
+
if value.action_sha256
|
|
1410
|
+
not in {item.action_sha256 for item in selected}
|
|
1411
|
+
)
|
|
1412
|
+
if not candidates:
|
|
1413
|
+
raise ValueError("action market cannot fill diagnostic pilot")
|
|
1414
|
+
scored = tuple(
|
|
1415
|
+
(
|
|
1416
|
+
abs(value.rank_quality - value.prior_score),
|
|
1417
|
+
self._minimum_distance(value, tuple(selected)),
|
|
1418
|
+
value.prior_score,
|
|
1419
|
+
(
|
|
1420
|
+
0.0
|
|
1421
|
+
if self.policy_version
|
|
1422
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_RISK_CONTROLLED_POLICY_VERSION
|
|
1423
|
+
else _stable_unit_interval(
|
|
1424
|
+
self.random_seed,
|
|
1425
|
+
residual_request_sha256,
|
|
1426
|
+
"diagnostic",
|
|
1427
|
+
len(selected),
|
|
1428
|
+
value.action_sha256,
|
|
1429
|
+
)
|
|
1430
|
+
),
|
|
1431
|
+
value,
|
|
1432
|
+
)
|
|
1433
|
+
for value in candidates
|
|
1434
|
+
)
|
|
1435
|
+
chosen = max(
|
|
1436
|
+
scored,
|
|
1437
|
+
key=lambda row: (
|
|
1438
|
+
row[0],
|
|
1439
|
+
row[1],
|
|
1440
|
+
row[2],
|
|
1441
|
+
row[3],
|
|
1442
|
+
row[4].action_sha256,
|
|
1443
|
+
),
|
|
1444
|
+
)[4]
|
|
1445
|
+
selected.append(chosen)
|
|
1446
|
+
trace.append(
|
|
1447
|
+
{
|
|
1448
|
+
"ordinal": len(selected),
|
|
1449
|
+
"action_sha256": chosen.action_sha256,
|
|
1450
|
+
"reason": "authority_disagreement_maximin",
|
|
1451
|
+
"lane_id": chosen.lane_id,
|
|
1452
|
+
"native_rank": chosen.native_rank,
|
|
1453
|
+
"authority_disagreement_hex": abs(
|
|
1454
|
+
chosen.rank_quality - chosen.prior_score
|
|
1455
|
+
).hex(),
|
|
1456
|
+
"minimum_distance_hex": self._minimum_distance(
|
|
1457
|
+
chosen,
|
|
1458
|
+
tuple(selected[:-1]),
|
|
1459
|
+
).hex(),
|
|
1460
|
+
}
|
|
1461
|
+
)
|
|
1462
|
+
return AdaptiveActionRacingDecision(
|
|
1463
|
+
policy_id=self.policy_id,
|
|
1464
|
+
policy_version=self.policy_version,
|
|
1465
|
+
policy_definition_sha256=self.definition_sha256,
|
|
1466
|
+
residual_request_sha256=residual_request_sha256,
|
|
1467
|
+
wave=AdaptiveActionWave.DIAGNOSTIC,
|
|
1468
|
+
selected_action_sha256s=tuple(
|
|
1469
|
+
sorted(value.action_sha256 for value in selected)
|
|
1470
|
+
),
|
|
1471
|
+
prior_selected_action_sha256s=(),
|
|
1472
|
+
observed_outcome_sha256s=(),
|
|
1473
|
+
observed_set_outcome_sha256s=(),
|
|
1474
|
+
selection_propensity=1.0,
|
|
1475
|
+
evidence=freeze_json(
|
|
1476
|
+
{
|
|
1477
|
+
"selection_trace": trace,
|
|
1478
|
+
"pilot_width": pilot_width,
|
|
1479
|
+
"lane_count": len(by_lane),
|
|
1480
|
+
"lane_head_count": sum(
|
|
1481
|
+
value["reason"] == "lane_head"
|
|
1482
|
+
for value in trace
|
|
1483
|
+
),
|
|
1484
|
+
"fixed_constraint_count": len(
|
|
1485
|
+
required_action_sha256s
|
|
1486
|
+
),
|
|
1487
|
+
"required_action_sha256s": list(
|
|
1488
|
+
required_action_sha256s
|
|
1489
|
+
),
|
|
1490
|
+
"candidate_outcomes_observed": False,
|
|
1491
|
+
"all_actions_materialized_before_decision": True,
|
|
1492
|
+
}
|
|
1493
|
+
),
|
|
1494
|
+
)
|
|
1495
|
+
|
|
1496
|
+
@staticmethod
|
|
1497
|
+
def _outcome_map(
|
|
1498
|
+
*,
|
|
1499
|
+
by_action: dict[str, AdaptiveActionDescriptor],
|
|
1500
|
+
selected_action_sha256s: tuple[str, ...],
|
|
1501
|
+
outcomes: tuple[AdaptiveActionOutcome, ...],
|
|
1502
|
+
) -> dict[str, AdaptiveActionOutcome]:
|
|
1503
|
+
if (
|
|
1504
|
+
type(selected_action_sha256s) is not tuple
|
|
1505
|
+
or selected_action_sha256s
|
|
1506
|
+
!= tuple(sorted(set(selected_action_sha256s)))
|
|
1507
|
+
):
|
|
1508
|
+
raise ValueError(
|
|
1509
|
+
"selected_action_sha256s must be an exact canonical tuple"
|
|
1510
|
+
)
|
|
1511
|
+
if not set(selected_action_sha256s).issubset(by_action):
|
|
1512
|
+
raise ValueError("selected action is outside the sealed market")
|
|
1513
|
+
if (
|
|
1514
|
+
type(outcomes) is not tuple
|
|
1515
|
+
or any(type(value) is not AdaptiveActionOutcome for value in outcomes)
|
|
1516
|
+
):
|
|
1517
|
+
raise TypeError("outcomes must contain exact values")
|
|
1518
|
+
result: dict[str, AdaptiveActionOutcome] = {}
|
|
1519
|
+
for value in outcomes:
|
|
1520
|
+
value.__post_init__()
|
|
1521
|
+
if value.action_sha256 in result:
|
|
1522
|
+
raise ValueError("observed outcomes repeat an action")
|
|
1523
|
+
result[value.action_sha256] = value
|
|
1524
|
+
if set(result) != set(selected_action_sha256s):
|
|
1525
|
+
raise ValueError(
|
|
1526
|
+
"observations must exactly cover all previously selected actions"
|
|
1527
|
+
)
|
|
1528
|
+
return result
|
|
1529
|
+
|
|
1530
|
+
@staticmethod
|
|
1531
|
+
def _validate_set_outcomes(
|
|
1532
|
+
*,
|
|
1533
|
+
selected_action_sha256s: tuple[str, ...],
|
|
1534
|
+
diagnostic_action_sha256s: tuple[str, ...],
|
|
1535
|
+
outcome_by_action: dict[str, AdaptiveActionOutcome],
|
|
1536
|
+
set_outcomes: tuple[AdaptiveActionSetOutcome, ...],
|
|
1537
|
+
) -> tuple[
|
|
1538
|
+
AdaptiveActionSetOutcome | None,
|
|
1539
|
+
dict[str, AdaptiveActionSetOutcome],
|
|
1540
|
+
]:
|
|
1541
|
+
if type(set_outcomes) is not tuple:
|
|
1542
|
+
raise TypeError("set_outcomes must be an exact tuple")
|
|
1543
|
+
if not set_outcomes:
|
|
1544
|
+
return None, {}
|
|
1545
|
+
prior_bindings: list[tuple[str, str]] = []
|
|
1546
|
+
prior_augmented_gain = 0.0
|
|
1547
|
+
singleton_by_action: dict[str, AdaptiveActionSetOutcome] = {}
|
|
1548
|
+
for ordinal, observation in enumerate(set_outcomes):
|
|
1549
|
+
if type(observation) is not AdaptiveActionSetOutcome:
|
|
1550
|
+
raise TypeError("set_outcomes must contain exact values")
|
|
1551
|
+
observation.__post_init__()
|
|
1552
|
+
if observation.prior_action_evaluation_bindings != tuple(
|
|
1553
|
+
sorted(prior_bindings)
|
|
1554
|
+
):
|
|
1555
|
+
raise ValueError(
|
|
1556
|
+
"set outcomes skip their causal evaluation prefix"
|
|
1557
|
+
)
|
|
1558
|
+
if not _metric_close(
|
|
1559
|
+
observation.prior_selected_set_gain,
|
|
1560
|
+
prior_augmented_gain,
|
|
1561
|
+
):
|
|
1562
|
+
raise ValueError(
|
|
1563
|
+
"set outcomes skip their causal utility prefix"
|
|
1564
|
+
)
|
|
1565
|
+
current = observation.current_action_evaluation_bindings
|
|
1566
|
+
current_actions = {value[0] for value in current}
|
|
1567
|
+
if ordinal == 0:
|
|
1568
|
+
if current_actions != set(diagnostic_action_sha256s):
|
|
1569
|
+
raise ValueError(
|
|
1570
|
+
"first set outcome must cover the diagnostic wave"
|
|
1571
|
+
)
|
|
1572
|
+
elif len(current) != 1:
|
|
1573
|
+
raise ValueError(
|
|
1574
|
+
"continuation set outcomes must bind one action"
|
|
1575
|
+
)
|
|
1576
|
+
for action_sha256, evaluation_sha256 in current:
|
|
1577
|
+
outcome = outcome_by_action.get(action_sha256)
|
|
1578
|
+
if (
|
|
1579
|
+
outcome is None
|
|
1580
|
+
or outcome.evaluation_sha256 != evaluation_sha256
|
|
1581
|
+
):
|
|
1582
|
+
raise ValueError(
|
|
1583
|
+
"set outcome does not join an observed outcome"
|
|
1584
|
+
)
|
|
1585
|
+
if len(current) == 1:
|
|
1586
|
+
singleton_by_action[current[0][0]] = observation
|
|
1587
|
+
prior_bindings.extend(current)
|
|
1588
|
+
prior_augmented_gain = (
|
|
1589
|
+
observation.augmented_selected_set_gain
|
|
1590
|
+
)
|
|
1591
|
+
if {value[0] for value in prior_bindings} != set(
|
|
1592
|
+
selected_action_sha256s
|
|
1593
|
+
):
|
|
1594
|
+
raise ValueError(
|
|
1595
|
+
"set outcomes must exactly cover selected actions"
|
|
1596
|
+
)
|
|
1597
|
+
return set_outcomes[0], singleton_by_action
|
|
1598
|
+
|
|
1599
|
+
def _causal_set_components(
|
|
1600
|
+
self,
|
|
1601
|
+
*,
|
|
1602
|
+
candidate: AdaptiveActionDescriptor,
|
|
1603
|
+
selected_by_action: dict[str, AdaptiveActionDescriptor],
|
|
1604
|
+
diagnostic: AdaptiveActionSetOutcome,
|
|
1605
|
+
singleton_by_action: dict[str, AdaptiveActionSetOutcome],
|
|
1606
|
+
base: dict[str, float],
|
|
1607
|
+
) -> dict[str, float]:
|
|
1608
|
+
if not _metric_close(
|
|
1609
|
+
diagnostic.current_wave_fixed_set_gain,
|
|
1610
|
+
base["diagnostic_joint_gain"],
|
|
1611
|
+
):
|
|
1612
|
+
raise ValueError(
|
|
1613
|
+
"diagnostic set outcome differs from joint gain"
|
|
1614
|
+
)
|
|
1615
|
+
diagnostic_sum = base["diagnostic_individual_gain_sum"]
|
|
1616
|
+
diagnostic_saturation = (
|
|
1617
|
+
0.0
|
|
1618
|
+
if diagnostic_sum <= 0.0
|
|
1619
|
+
else max(
|
|
1620
|
+
0.0,
|
|
1621
|
+
1.0 - base["diagnostic_coalition_efficiency"],
|
|
1622
|
+
)
|
|
1623
|
+
)
|
|
1624
|
+
saturation_weighted = (
|
|
1625
|
+
self.causal_prior_strength * diagnostic_saturation
|
|
1626
|
+
)
|
|
1627
|
+
saturation_weight = self.causal_prior_strength
|
|
1628
|
+
synergy_weighted = 0.0
|
|
1629
|
+
synergy_weight = self.causal_prior_strength
|
|
1630
|
+
causal_evidence_count = 0
|
|
1631
|
+
for action_sha256, observation in singleton_by_action.items():
|
|
1632
|
+
action = selected_by_action[action_sha256]
|
|
1633
|
+
similarity = max(
|
|
1634
|
+
0.0,
|
|
1635
|
+
1.0 - _action_distance(candidate, action),
|
|
1636
|
+
)
|
|
1637
|
+
weight = 0.10 + 0.90 * similarity
|
|
1638
|
+
fixed_gain = observation.current_wave_fixed_set_gain
|
|
1639
|
+
if fixed_gain > 0.0:
|
|
1640
|
+
saturation_weighted += (
|
|
1641
|
+
weight * observation.saturation_fraction
|
|
1642
|
+
)
|
|
1643
|
+
saturation_weight += weight
|
|
1644
|
+
causal_evidence_count += 1
|
|
1645
|
+
if (
|
|
1646
|
+
fixed_gain > 0.0
|
|
1647
|
+
or observation.prior_conditioned_synergy > 0.0
|
|
1648
|
+
):
|
|
1649
|
+
synergy_ratio = min(
|
|
1650
|
+
observation.prior_conditioned_synergy
|
|
1651
|
+
/ max(fixed_gain, self.reference_gain_scale),
|
|
1652
|
+
2.0,
|
|
1653
|
+
)
|
|
1654
|
+
synergy_weighted += weight * synergy_ratio
|
|
1655
|
+
synergy_weight += weight
|
|
1656
|
+
posterior_saturation = (
|
|
1657
|
+
saturation_weighted / saturation_weight
|
|
1658
|
+
)
|
|
1659
|
+
posterior_synergy = synergy_weighted / synergy_weight
|
|
1660
|
+
causal_uncertainty = 1.0 / math.sqrt(saturation_weight)
|
|
1661
|
+
conditional_multiplier = max(
|
|
1662
|
+
0.0,
|
|
1663
|
+
1.0
|
|
1664
|
+
- self.conditional_saturation_strength
|
|
1665
|
+
* posterior_saturation
|
|
1666
|
+
+ self.conditional_synergy_strength
|
|
1667
|
+
* posterior_synergy,
|
|
1668
|
+
)
|
|
1669
|
+
predicted_conditional_gain = (
|
|
1670
|
+
base["posterior_gain"] * conditional_multiplier
|
|
1671
|
+
)
|
|
1672
|
+
# Saturation is evidence about expected conditional value, not a
|
|
1673
|
+
# license to equate structural distance with archive complementarity.
|
|
1674
|
+
# The existing UCB already prices uncertainty and diversity once.
|
|
1675
|
+
# Keeping both bonuses at zero avoids the failed V52 proxy penalty's
|
|
1676
|
+
# double counting while retaining them as explicit trace fields.
|
|
1677
|
+
complement_bonus = 0.0
|
|
1678
|
+
causal_uncertainty_bonus = 0.0
|
|
1679
|
+
conditional_ucb_index = (
|
|
1680
|
+
base["ucb_index"]
|
|
1681
|
+
- base["posterior_gain"]
|
|
1682
|
+
+ predicted_conditional_gain
|
|
1683
|
+
+ complement_bonus
|
|
1684
|
+
+ causal_uncertainty_bonus
|
|
1685
|
+
)
|
|
1686
|
+
return {
|
|
1687
|
+
**base,
|
|
1688
|
+
"diagnostic_saturation": diagnostic_saturation,
|
|
1689
|
+
"posterior_saturation": posterior_saturation,
|
|
1690
|
+
"posterior_synergy": posterior_synergy,
|
|
1691
|
+
"causal_evidence_count": float(causal_evidence_count),
|
|
1692
|
+
"causal_effective_weight": saturation_weight,
|
|
1693
|
+
"causal_uncertainty": causal_uncertainty,
|
|
1694
|
+
"conditional_multiplier": conditional_multiplier,
|
|
1695
|
+
"predicted_conditional_gain": predicted_conditional_gain,
|
|
1696
|
+
"complement_bonus": complement_bonus,
|
|
1697
|
+
"causal_uncertainty_bonus": causal_uncertainty_bonus,
|
|
1698
|
+
"conditional_ucb_index": conditional_ucb_index,
|
|
1699
|
+
"ucb_index": conditional_ucb_index,
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
def _ucb_components(
|
|
1703
|
+
self,
|
|
1704
|
+
*,
|
|
1705
|
+
candidate: AdaptiveActionDescriptor,
|
|
1706
|
+
selected: tuple[AdaptiveActionDescriptor, ...],
|
|
1707
|
+
outcome_by_action: dict[str, AdaptiveActionOutcome],
|
|
1708
|
+
diagnostic_action_sha256s: tuple[str, ...],
|
|
1709
|
+
diagnostic_joint_gain: float,
|
|
1710
|
+
) -> dict[str, float]:
|
|
1711
|
+
weighted_gain = 0.0
|
|
1712
|
+
weighted_positive = 0.0
|
|
1713
|
+
total_weight = 0.0
|
|
1714
|
+
same_lane_ranks: list[float] = []
|
|
1715
|
+
for action in selected:
|
|
1716
|
+
outcome = outcome_by_action[action.action_sha256]
|
|
1717
|
+
rank_distance = abs(
|
|
1718
|
+
candidate.rank_quality - action.rank_quality
|
|
1719
|
+
)
|
|
1720
|
+
weight = 0.10
|
|
1721
|
+
if candidate.lane_id == action.lane_id:
|
|
1722
|
+
weight += 0.55 * math.exp(-rank_distance / 0.35)
|
|
1723
|
+
same_lane_ranks.append(action.rank_quality)
|
|
1724
|
+
if candidate.operator_id == action.operator_id:
|
|
1725
|
+
weight += 0.15
|
|
1726
|
+
if (
|
|
1727
|
+
candidate.parent_generated_in_current_run
|
|
1728
|
+
== action.parent_generated_in_current_run
|
|
1729
|
+
):
|
|
1730
|
+
weight += 0.10
|
|
1731
|
+
weight += 0.10 * (
|
|
1732
|
+
1.0
|
|
1733
|
+
- _semantic_distance(
|
|
1734
|
+
candidate.semantic_cell_ids,
|
|
1735
|
+
action.semantic_cell_ids,
|
|
1736
|
+
)
|
|
1737
|
+
)
|
|
1738
|
+
weighted_gain += weight * outcome.marginal_archive_gain
|
|
1739
|
+
weighted_positive += weight * float(outcome.positive)
|
|
1740
|
+
total_weight += weight
|
|
1741
|
+
|
|
1742
|
+
prior_positive = 0.25 + 0.50 * candidate.prior_score
|
|
1743
|
+
prior_gain = self.reference_gain_scale * (
|
|
1744
|
+
0.25 + 0.75 * candidate.prior_score
|
|
1745
|
+
)
|
|
1746
|
+
active_gain_scale = max(
|
|
1747
|
+
self.reference_gain_scale,
|
|
1748
|
+
max(
|
|
1749
|
+
(
|
|
1750
|
+
value.marginal_archive_gain
|
|
1751
|
+
for value in outcome_by_action.values()
|
|
1752
|
+
),
|
|
1753
|
+
default=0.0,
|
|
1754
|
+
),
|
|
1755
|
+
)
|
|
1756
|
+
positive_redundancy = 0.0
|
|
1757
|
+
if (
|
|
1758
|
+
self.policy_version
|
|
1759
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_SET_AWARE_POLICY_VERSION
|
|
1760
|
+
):
|
|
1761
|
+
positive_redundancy = max(
|
|
1762
|
+
(
|
|
1763
|
+
max(0.0, 1.0 - _action_distance(candidate, action))
|
|
1764
|
+
* min(
|
|
1765
|
+
1.0,
|
|
1766
|
+
outcome_by_action[
|
|
1767
|
+
action.action_sha256
|
|
1768
|
+
].marginal_archive_gain
|
|
1769
|
+
/ active_gain_scale,
|
|
1770
|
+
)
|
|
1771
|
+
for action in selected
|
|
1772
|
+
if outcome_by_action[
|
|
1773
|
+
action.action_sha256
|
|
1774
|
+
].positive
|
|
1775
|
+
),
|
|
1776
|
+
default=0.0,
|
|
1777
|
+
)
|
|
1778
|
+
redundancy_penalty = (
|
|
1779
|
+
self.positive_redundancy_strength
|
|
1780
|
+
* active_gain_scale
|
|
1781
|
+
* positive_redundancy
|
|
1782
|
+
)
|
|
1783
|
+
diagnostic_individual_gain_sum = math.fsum(
|
|
1784
|
+
outcome_by_action[value].marginal_archive_gain
|
|
1785
|
+
for value in diagnostic_action_sha256s
|
|
1786
|
+
)
|
|
1787
|
+
diagnostic_coalition_efficiency = (
|
|
1788
|
+
0.0
|
|
1789
|
+
if diagnostic_individual_gain_sum <= 0.0
|
|
1790
|
+
else min(
|
|
1791
|
+
1.0,
|
|
1792
|
+
diagnostic_joint_gain / diagnostic_individual_gain_sum,
|
|
1793
|
+
)
|
|
1794
|
+
)
|
|
1795
|
+
exploration_gain_scale = (
|
|
1796
|
+
self.reference_gain_scale
|
|
1797
|
+
+ (active_gain_scale - self.reference_gain_scale)
|
|
1798
|
+
* (1.0 - diagnostic_coalition_efficiency)
|
|
1799
|
+
)
|
|
1800
|
+
denominator = self.prior_strength + total_weight
|
|
1801
|
+
posterior_positive = (
|
|
1802
|
+
self.prior_strength * prior_positive + weighted_positive
|
|
1803
|
+
) / denominator
|
|
1804
|
+
posterior_gain = (
|
|
1805
|
+
self.prior_strength * prior_gain + weighted_gain
|
|
1806
|
+
) / denominator
|
|
1807
|
+
uncertainty = exploration_gain_scale / math.sqrt(denominator)
|
|
1808
|
+
if same_lane_ranks:
|
|
1809
|
+
rank_counterfactual = min(
|
|
1810
|
+
abs(candidate.rank_quality - value)
|
|
1811
|
+
for value in same_lane_ranks
|
|
1812
|
+
)
|
|
1813
|
+
else:
|
|
1814
|
+
rank_counterfactual = 1.0
|
|
1815
|
+
diversity = self._minimum_distance(candidate, selected)
|
|
1816
|
+
ucb_index = (
|
|
1817
|
+
posterior_gain
|
|
1818
|
+
+ self.ucb_strength * uncertainty
|
|
1819
|
+
+ self.counterfactual_strength
|
|
1820
|
+
* exploration_gain_scale
|
|
1821
|
+
* rank_counterfactual
|
|
1822
|
+
+ self.diversity_strength
|
|
1823
|
+
* exploration_gain_scale
|
|
1824
|
+
* diversity
|
|
1825
|
+
- redundancy_penalty
|
|
1826
|
+
)
|
|
1827
|
+
result = {
|
|
1828
|
+
"posterior_positive": posterior_positive,
|
|
1829
|
+
"posterior_gain": posterior_gain,
|
|
1830
|
+
"uncertainty": uncertainty,
|
|
1831
|
+
"rank_counterfactual": rank_counterfactual,
|
|
1832
|
+
"diversity": diversity,
|
|
1833
|
+
"ucb_index": ucb_index,
|
|
1834
|
+
"effective_observation_weight": total_weight,
|
|
1835
|
+
"active_gain_scale": active_gain_scale,
|
|
1836
|
+
"diagnostic_joint_gain": diagnostic_joint_gain,
|
|
1837
|
+
"diagnostic_individual_gain_sum": (
|
|
1838
|
+
diagnostic_individual_gain_sum
|
|
1839
|
+
),
|
|
1840
|
+
"diagnostic_coalition_efficiency": (
|
|
1841
|
+
diagnostic_coalition_efficiency
|
|
1842
|
+
),
|
|
1843
|
+
"exploration_gain_scale": exploration_gain_scale,
|
|
1844
|
+
}
|
|
1845
|
+
if (
|
|
1846
|
+
self.policy_version
|
|
1847
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_SET_AWARE_POLICY_VERSION
|
|
1848
|
+
):
|
|
1849
|
+
result.update(
|
|
1850
|
+
{
|
|
1851
|
+
"positive_redundancy": positive_redundancy,
|
|
1852
|
+
"redundancy_penalty": redundancy_penalty,
|
|
1853
|
+
}
|
|
1854
|
+
)
|
|
1855
|
+
return result
|
|
1856
|
+
|
|
1857
|
+
def _terminal_hierarchical_ranking(
|
|
1858
|
+
self,
|
|
1859
|
+
*,
|
|
1860
|
+
actions: tuple[AdaptiveActionDescriptor, ...],
|
|
1861
|
+
remaining: tuple[AdaptiveActionDescriptor, ...],
|
|
1862
|
+
selected: tuple[AdaptiveActionDescriptor, ...],
|
|
1863
|
+
outcome_by_action: dict[str, AdaptiveActionOutcome],
|
|
1864
|
+
components: dict[str, dict[str, float]],
|
|
1865
|
+
seats_left: int,
|
|
1866
|
+
) -> tuple[
|
|
1867
|
+
tuple[AdaptiveActionDescriptor, ...],
|
|
1868
|
+
dict[str, dict[str, float]],
|
|
1869
|
+
tuple[str, ...],
|
|
1870
|
+
]:
|
|
1871
|
+
"""Rank engines first, then actions, at a short residual horizon.
|
|
1872
|
+
|
|
1873
|
+
Engine return is capped at the authenticated reference-gain scale so
|
|
1874
|
+
one unusually large action cannot monopolize a sparse engine posterior.
|
|
1875
|
+
This is an allocation statistic only; authoritative archive utility
|
|
1876
|
+
remains uncapped. Within the chosen engine, native rank is retained as
|
|
1877
|
+
a separately weighted cold-start prior rather than mixed into another
|
|
1878
|
+
engine's native units.
|
|
1879
|
+
"""
|
|
1880
|
+
|
|
1881
|
+
if (
|
|
1882
|
+
self.policy_version
|
|
1883
|
+
!= OUTCOME_ADAPTIVE_ACTION_RACING_HORIZON_HIERARCHICAL_POLICY_VERSION
|
|
1884
|
+
):
|
|
1885
|
+
raise ValueError(
|
|
1886
|
+
"terminal hierarchical ranking requires policy version 7"
|
|
1887
|
+
)
|
|
1888
|
+
if not remaining or seats_left <= 0:
|
|
1889
|
+
raise ValueError(
|
|
1890
|
+
"terminal hierarchical ranking requires remaining capacity"
|
|
1891
|
+
)
|
|
1892
|
+
market_by_lane: dict[str, list[AdaptiveActionDescriptor]] = {}
|
|
1893
|
+
remaining_by_lane: dict[str, list[AdaptiveActionDescriptor]] = {}
|
|
1894
|
+
selected_by_lane: dict[str, list[AdaptiveActionDescriptor]] = {}
|
|
1895
|
+
for action in actions:
|
|
1896
|
+
market_by_lane.setdefault(action.lane_id, []).append(action)
|
|
1897
|
+
for action in remaining:
|
|
1898
|
+
remaining_by_lane.setdefault(action.lane_id, []).append(action)
|
|
1899
|
+
for action in selected:
|
|
1900
|
+
selected_by_lane.setdefault(action.lane_id, []).append(action)
|
|
1901
|
+
|
|
1902
|
+
future_optimization_slots = max(0, seats_left - 1)
|
|
1903
|
+
horizon_exploration_fraction = min(
|
|
1904
|
+
1.0,
|
|
1905
|
+
future_optimization_slots
|
|
1906
|
+
/ float(max(1, self.terminal_hierarchical_slots)),
|
|
1907
|
+
)
|
|
1908
|
+
engine: dict[str, dict[str, float]] = {}
|
|
1909
|
+
for lane_id in sorted(remaining_by_lane):
|
|
1910
|
+
lane_market = market_by_lane[lane_id]
|
|
1911
|
+
lane_selected = selected_by_lane.get(lane_id, [])
|
|
1912
|
+
mean_prior_score = math.fsum(
|
|
1913
|
+
value.prior_score for value in lane_market
|
|
1914
|
+
) / len(lane_market)
|
|
1915
|
+
prior_positive = 0.25 + 0.50 * mean_prior_score
|
|
1916
|
+
prior_capped_gain = self.reference_gain_scale * (
|
|
1917
|
+
0.25 + 0.75 * mean_prior_score
|
|
1918
|
+
)
|
|
1919
|
+
observed = tuple(
|
|
1920
|
+
outcome_by_action[value.action_sha256]
|
|
1921
|
+
for value in lane_selected
|
|
1922
|
+
)
|
|
1923
|
+
denominator = self.prior_strength + len(observed)
|
|
1924
|
+
posterior_positive = (
|
|
1925
|
+
self.prior_strength * prior_positive
|
|
1926
|
+
+ math.fsum(float(value.positive) for value in observed)
|
|
1927
|
+
) / denominator
|
|
1928
|
+
posterior_capped_gain = (
|
|
1929
|
+
self.prior_strength * prior_capped_gain
|
|
1930
|
+
+ math.fsum(
|
|
1931
|
+
min(
|
|
1932
|
+
self.reference_gain_scale,
|
|
1933
|
+
value.marginal_archive_gain,
|
|
1934
|
+
)
|
|
1935
|
+
for value in observed
|
|
1936
|
+
)
|
|
1937
|
+
) / denominator
|
|
1938
|
+
uncertainty = self.reference_gain_scale / math.sqrt(denominator)
|
|
1939
|
+
selection_index = (
|
|
1940
|
+
posterior_capped_gain
|
|
1941
|
+
+ horizon_exploration_fraction
|
|
1942
|
+
* self.ucb_strength
|
|
1943
|
+
* uncertainty
|
|
1944
|
+
)
|
|
1945
|
+
engine[lane_id] = {
|
|
1946
|
+
"engine_mean_prior_score": mean_prior_score,
|
|
1947
|
+
"engine_prior_positive": prior_positive,
|
|
1948
|
+
"engine_prior_capped_gain": prior_capped_gain,
|
|
1949
|
+
"engine_observed_count": float(len(observed)),
|
|
1950
|
+
"engine_positive_count": float(
|
|
1951
|
+
sum(value.positive for value in observed)
|
|
1952
|
+
),
|
|
1953
|
+
"engine_posterior_positive": posterior_positive,
|
|
1954
|
+
"engine_posterior_capped_gain": posterior_capped_gain,
|
|
1955
|
+
"engine_uncertainty": uncertainty,
|
|
1956
|
+
"engine_selection_index": selection_index,
|
|
1957
|
+
"future_optimization_slots_after_decision": float(
|
|
1958
|
+
future_optimization_slots
|
|
1959
|
+
),
|
|
1960
|
+
"horizon_exploration_fraction": (
|
|
1961
|
+
horizon_exploration_fraction
|
|
1962
|
+
),
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
engine_order = tuple(
|
|
1966
|
+
sorted(
|
|
1967
|
+
engine,
|
|
1968
|
+
key=lambda lane_id: (
|
|
1969
|
+
engine[lane_id]["engine_selection_index"],
|
|
1970
|
+
engine[lane_id]["engine_posterior_positive"],
|
|
1971
|
+
engine[lane_id]["engine_mean_prior_score"],
|
|
1972
|
+
lane_id,
|
|
1973
|
+
),
|
|
1974
|
+
reverse=True,
|
|
1975
|
+
)
|
|
1976
|
+
)
|
|
1977
|
+
enriched = {
|
|
1978
|
+
action_sha256: dict(value)
|
|
1979
|
+
for action_sha256, value in components.items()
|
|
1980
|
+
}
|
|
1981
|
+
ranked: list[AdaptiveActionDescriptor] = []
|
|
1982
|
+
for lane_id in engine_order:
|
|
1983
|
+
lane_actions = remaining_by_lane[lane_id]
|
|
1984
|
+
for action in lane_actions:
|
|
1985
|
+
row = enriched[action.action_sha256]
|
|
1986
|
+
native_rank_bonus = (
|
|
1987
|
+
self.native_rank_strength
|
|
1988
|
+
* self.reference_gain_scale
|
|
1989
|
+
* action.rank_quality
|
|
1990
|
+
)
|
|
1991
|
+
row.update(engine[lane_id])
|
|
1992
|
+
row["native_rank_bonus"] = native_rank_bonus
|
|
1993
|
+
row["within_engine_terminal_index"] = (
|
|
1994
|
+
row["posterior_gain"] + native_rank_bonus
|
|
1995
|
+
)
|
|
1996
|
+
ranked.extend(
|
|
1997
|
+
sorted(
|
|
1998
|
+
lane_actions,
|
|
1999
|
+
key=lambda value: (
|
|
2000
|
+
enriched[value.action_sha256][
|
|
2001
|
+
"within_engine_terminal_index"
|
|
2002
|
+
],
|
|
2003
|
+
enriched[value.action_sha256][
|
|
2004
|
+
"posterior_positive"
|
|
2005
|
+
],
|
|
2006
|
+
value.prior_score,
|
|
2007
|
+
value.action_sha256,
|
|
2008
|
+
),
|
|
2009
|
+
reverse=True,
|
|
2010
|
+
)
|
|
2011
|
+
)
|
|
2012
|
+
return tuple(ranked), enriched, engine_order
|
|
2013
|
+
|
|
2014
|
+
def select_next(
|
|
2015
|
+
self,
|
|
2016
|
+
*,
|
|
2017
|
+
residual_request_sha256: str,
|
|
2018
|
+
actions: tuple[AdaptiveActionDescriptor, ...],
|
|
2019
|
+
evaluation_slots: int,
|
|
2020
|
+
diagnostic_action_sha256s: tuple[str, ...],
|
|
2021
|
+
diagnostic_joint_gain: float,
|
|
2022
|
+
selected_action_sha256s: tuple[str, ...],
|
|
2023
|
+
outcomes: tuple[AdaptiveActionOutcome, ...],
|
|
2024
|
+
set_outcomes: tuple[AdaptiveActionSetOutcome, ...] = (),
|
|
2025
|
+
excluded_action_sha256s: tuple[str, ...] = (),
|
|
2026
|
+
) -> AdaptiveActionRacingDecision:
|
|
2027
|
+
"""Select one next action using only outcomes of already selected actions."""
|
|
2028
|
+
|
|
2029
|
+
self.__post_init__()
|
|
2030
|
+
require_sha256(
|
|
2031
|
+
residual_request_sha256,
|
|
2032
|
+
"residual_request_sha256",
|
|
2033
|
+
)
|
|
2034
|
+
by_action = self._validate_market(actions)
|
|
2035
|
+
if (
|
|
2036
|
+
type(excluded_action_sha256s) is not tuple
|
|
2037
|
+
or excluded_action_sha256s
|
|
2038
|
+
!= tuple(sorted(set(excluded_action_sha256s)))
|
|
2039
|
+
):
|
|
2040
|
+
raise ValueError(
|
|
2041
|
+
"excluded action hashes must be unique and canonical"
|
|
2042
|
+
)
|
|
2043
|
+
for value in excluded_action_sha256s:
|
|
2044
|
+
require_sha256(value, "excluded_action_sha256")
|
|
2045
|
+
if (
|
|
2046
|
+
not set(excluded_action_sha256s) <= set(by_action)
|
|
2047
|
+
or set(excluded_action_sha256s)
|
|
2048
|
+
& set(selected_action_sha256s)
|
|
2049
|
+
):
|
|
2050
|
+
raise ValueError(
|
|
2051
|
+
"excluded actions must be unselected market members"
|
|
2052
|
+
)
|
|
2053
|
+
if (
|
|
2054
|
+
type(evaluation_slots) is not int
|
|
2055
|
+
or not 2 <= evaluation_slots <= len(actions)
|
|
2056
|
+
):
|
|
2057
|
+
raise ValueError("evaluation_slots must fit the action market")
|
|
2058
|
+
if len(selected_action_sha256s) >= evaluation_slots:
|
|
2059
|
+
raise ValueError("the evaluation slate is already complete")
|
|
2060
|
+
outcome_by_action = self._outcome_map(
|
|
2061
|
+
by_action=by_action,
|
|
2062
|
+
selected_action_sha256s=selected_action_sha256s,
|
|
2063
|
+
outcomes=outcomes,
|
|
2064
|
+
)
|
|
2065
|
+
if (
|
|
2066
|
+
type(diagnostic_action_sha256s) is not tuple
|
|
2067
|
+
or not diagnostic_action_sha256s
|
|
2068
|
+
or diagnostic_action_sha256s
|
|
2069
|
+
!= tuple(sorted(set(diagnostic_action_sha256s)))
|
|
2070
|
+
or not set(diagnostic_action_sha256s).issubset(
|
|
2071
|
+
selected_action_sha256s
|
|
2072
|
+
)
|
|
2073
|
+
):
|
|
2074
|
+
raise ValueError(
|
|
2075
|
+
"diagnostic actions must be a canonical selected subset"
|
|
2076
|
+
)
|
|
2077
|
+
if (
|
|
2078
|
+
type(diagnostic_joint_gain) is not float
|
|
2079
|
+
or not math.isfinite(diagnostic_joint_gain)
|
|
2080
|
+
or diagnostic_joint_gain < 0.0
|
|
2081
|
+
):
|
|
2082
|
+
raise ValueError(
|
|
2083
|
+
"diagnostic_joint_gain must be finite and non-negative"
|
|
2084
|
+
)
|
|
2085
|
+
(
|
|
2086
|
+
diagnostic_set_outcome,
|
|
2087
|
+
singleton_set_outcomes,
|
|
2088
|
+
) = self._validate_set_outcomes(
|
|
2089
|
+
selected_action_sha256s=selected_action_sha256s,
|
|
2090
|
+
diagnostic_action_sha256s=diagnostic_action_sha256s,
|
|
2091
|
+
outcome_by_action=outcome_by_action,
|
|
2092
|
+
set_outcomes=set_outcomes,
|
|
2093
|
+
)
|
|
2094
|
+
if (
|
|
2095
|
+
self.policy_version in _CAUSAL_SET_POLICY_VERSIONS
|
|
2096
|
+
and diagnostic_set_outcome is None
|
|
2097
|
+
):
|
|
2098
|
+
raise ValueError(
|
|
2099
|
+
"causal policy versions require causal set outcomes"
|
|
2100
|
+
)
|
|
2101
|
+
selected = tuple(
|
|
2102
|
+
by_action[value] for value in selected_action_sha256s
|
|
2103
|
+
)
|
|
2104
|
+
selected_phenotypes = {
|
|
2105
|
+
value.phenotype_sha256 for value in selected
|
|
2106
|
+
}
|
|
2107
|
+
remaining = tuple(
|
|
2108
|
+
value
|
|
2109
|
+
for value in actions
|
|
2110
|
+
if value.action_sha256 not in outcome_by_action
|
|
2111
|
+
and value.action_sha256 not in set(excluded_action_sha256s)
|
|
2112
|
+
and value.phenotype_sha256 not in selected_phenotypes
|
|
2113
|
+
)
|
|
2114
|
+
if not remaining:
|
|
2115
|
+
raise ValueError("no unevaluated action can fill the slate")
|
|
2116
|
+
seats_left = evaluation_slots - len(selected)
|
|
2117
|
+
|
|
2118
|
+
components: dict[str, dict[str, float]] = {
|
|
2119
|
+
value.action_sha256: self._ucb_components(
|
|
2120
|
+
candidate=value,
|
|
2121
|
+
selected=selected,
|
|
2122
|
+
outcome_by_action=outcome_by_action,
|
|
2123
|
+
diagnostic_action_sha256s=(
|
|
2124
|
+
diagnostic_action_sha256s
|
|
2125
|
+
),
|
|
2126
|
+
diagnostic_joint_gain=diagnostic_joint_gain,
|
|
2127
|
+
)
|
|
2128
|
+
for value in remaining
|
|
2129
|
+
}
|
|
2130
|
+
if (
|
|
2131
|
+
self.policy_version in _CAUSAL_SET_POLICY_VERSIONS
|
|
2132
|
+
):
|
|
2133
|
+
if diagnostic_set_outcome is None: # pragma: no cover
|
|
2134
|
+
raise AssertionError("validated causal observation vanished")
|
|
2135
|
+
selected_by_action = {
|
|
2136
|
+
value.action_sha256: value for value in selected
|
|
2137
|
+
}
|
|
2138
|
+
components = {
|
|
2139
|
+
value.action_sha256: self._causal_set_components(
|
|
2140
|
+
candidate=value,
|
|
2141
|
+
selected_by_action=selected_by_action,
|
|
2142
|
+
diagnostic=diagnostic_set_outcome,
|
|
2143
|
+
singleton_by_action=singleton_set_outcomes,
|
|
2144
|
+
base=components[value.action_sha256],
|
|
2145
|
+
)
|
|
2146
|
+
for value in remaining
|
|
2147
|
+
}
|
|
2148
|
+
directed_steps_completed = (
|
|
2149
|
+
len(selected) - len(diagnostic_action_sha256s)
|
|
2150
|
+
)
|
|
2151
|
+
terminal_hierarchical = (
|
|
2152
|
+
self.policy_version
|
|
2153
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_HORIZON_HIERARCHICAL_POLICY_VERSION
|
|
2154
|
+
and seats_left <= self.terminal_hierarchical_slots
|
|
2155
|
+
)
|
|
2156
|
+
horizon_audit_due: bool | None = None
|
|
2157
|
+
horizon_audit_blocked_reason: str | None = None
|
|
2158
|
+
if (
|
|
2159
|
+
self.policy_version
|
|
2160
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_HORIZON_HIERARCHICAL_POLICY_VERSION
|
|
2161
|
+
):
|
|
2162
|
+
horizon_audit_due = (
|
|
2163
|
+
directed_steps_completed
|
|
2164
|
+
== self.randomized_audit_after_directed_steps
|
|
2165
|
+
)
|
|
2166
|
+
post_audit_optimization_slots = max(0, seats_left - 1)
|
|
2167
|
+
audit = bool(
|
|
2168
|
+
horizon_audit_due
|
|
2169
|
+
and not terminal_hierarchical
|
|
2170
|
+
and post_audit_optimization_slots
|
|
2171
|
+
>= self.minimum_post_audit_optimization_slots
|
|
2172
|
+
)
|
|
2173
|
+
if horizon_audit_due and not audit:
|
|
2174
|
+
horizon_audit_blocked_reason = (
|
|
2175
|
+
"terminal_hierarchical_exploitation"
|
|
2176
|
+
if terminal_hierarchical
|
|
2177
|
+
else "insufficient_post_audit_optimization_horizon"
|
|
2178
|
+
)
|
|
2179
|
+
elif self.policy_version in _CAUSAL_SET_POLICY_VERSIONS:
|
|
2180
|
+
audit = (
|
|
2181
|
+
directed_steps_completed
|
|
2182
|
+
== self.randomized_audit_after_directed_steps
|
|
2183
|
+
)
|
|
2184
|
+
else:
|
|
2185
|
+
audit = seats_left <= self.randomized_audit_slots
|
|
2186
|
+
directed_ranked = tuple(
|
|
2187
|
+
sorted(
|
|
2188
|
+
remaining,
|
|
2189
|
+
key=lambda value: (
|
|
2190
|
+
components[value.action_sha256]["ucb_index"],
|
|
2191
|
+
components[value.action_sha256][
|
|
2192
|
+
"posterior_positive"
|
|
2193
|
+
],
|
|
2194
|
+
value.prior_score,
|
|
2195
|
+
(
|
|
2196
|
+
0.0
|
|
2197
|
+
if self.policy_version
|
|
2198
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_RISK_CONTROLLED_POLICY_VERSION
|
|
2199
|
+
else _stable_unit_interval(
|
|
2200
|
+
self.random_seed,
|
|
2201
|
+
residual_request_sha256,
|
|
2202
|
+
"adaptive_tie",
|
|
2203
|
+
len(selected),
|
|
2204
|
+
value.action_sha256,
|
|
2205
|
+
)
|
|
2206
|
+
),
|
|
2207
|
+
value.action_sha256,
|
|
2208
|
+
),
|
|
2209
|
+
reverse=True,
|
|
2210
|
+
)
|
|
2211
|
+
)
|
|
2212
|
+
hierarchical_engine_order: tuple[str, ...] = ()
|
|
2213
|
+
if terminal_hierarchical:
|
|
2214
|
+
(
|
|
2215
|
+
directed_ranked,
|
|
2216
|
+
components,
|
|
2217
|
+
hierarchical_engine_order,
|
|
2218
|
+
) = self._terminal_hierarchical_ranking(
|
|
2219
|
+
actions=actions,
|
|
2220
|
+
remaining=remaining,
|
|
2221
|
+
selected=selected,
|
|
2222
|
+
outcome_by_action=outcome_by_action,
|
|
2223
|
+
components=components,
|
|
2224
|
+
seats_left=seats_left,
|
|
2225
|
+
)
|
|
2226
|
+
audit_anchor_sha256: str | None = None
|
|
2227
|
+
audit_exploration_branch: bool | None = None
|
|
2228
|
+
audit_branch_draw: float | None = None
|
|
2229
|
+
audit_choice_draw: float | None = None
|
|
2230
|
+
audit_stratum_draw: float | None = None
|
|
2231
|
+
audit_stratum_key: tuple[str, ...] | None = None
|
|
2232
|
+
audit_strata_record: list[dict[str, object]] | None = None
|
|
2233
|
+
audit_max_uncovered_factor_count: int | None = None
|
|
2234
|
+
legacy_audit_pool_ids: list[str] | None = None
|
|
2235
|
+
if audit:
|
|
2236
|
+
ranked = tuple(
|
|
2237
|
+
sorted(
|
|
2238
|
+
remaining,
|
|
2239
|
+
key=lambda value: (
|
|
2240
|
+
-components[value.action_sha256]["diversity"],
|
|
2241
|
+
-components[value.action_sha256][
|
|
2242
|
+
"rank_counterfactual"
|
|
2243
|
+
],
|
|
2244
|
+
-value.prior_score,
|
|
2245
|
+
value.action_sha256,
|
|
2246
|
+
),
|
|
2247
|
+
)
|
|
2248
|
+
)
|
|
2249
|
+
if (
|
|
2250
|
+
self.policy_version
|
|
2251
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_RISK_CONTROLLED_POLICY_VERSION
|
|
2252
|
+
):
|
|
2253
|
+
anchor = directed_ranked[0]
|
|
2254
|
+
pool_values = [anchor]
|
|
2255
|
+
pool_values.extend(
|
|
2256
|
+
value
|
|
2257
|
+
for value in ranked
|
|
2258
|
+
if value.action_sha256 != anchor.action_sha256
|
|
2259
|
+
)
|
|
2260
|
+
pool = tuple(
|
|
2261
|
+
pool_values[
|
|
2262
|
+
: min(
|
|
2263
|
+
self.exploration_pool_size,
|
|
2264
|
+
len(pool_values),
|
|
2265
|
+
)
|
|
2266
|
+
]
|
|
2267
|
+
)
|
|
2268
|
+
pool_ids = [value.action_sha256 for value in pool]
|
|
2269
|
+
audit_anchor_sha256 = anchor.action_sha256
|
|
2270
|
+
audit_branch_draw = _stable_unit_interval(
|
|
2271
|
+
self.random_seed,
|
|
2272
|
+
residual_request_sha256,
|
|
2273
|
+
"risk_controlled_audit_branch",
|
|
2274
|
+
len(selected),
|
|
2275
|
+
pool_ids,
|
|
2276
|
+
)
|
|
2277
|
+
audit_exploration_branch = (
|
|
2278
|
+
audit_branch_draw
|
|
2279
|
+
< self.audit_exploration_probability
|
|
2280
|
+
)
|
|
2281
|
+
if audit_exploration_branch:
|
|
2282
|
+
audit_choice_draw = _stable_unit_interval(
|
|
2283
|
+
self.random_seed,
|
|
2284
|
+
residual_request_sha256,
|
|
2285
|
+
"risk_controlled_audit_choice",
|
|
2286
|
+
len(selected),
|
|
2287
|
+
pool_ids,
|
|
2288
|
+
)
|
|
2289
|
+
chosen = pool[
|
|
2290
|
+
min(
|
|
2291
|
+
int(audit_choice_draw * len(pool)),
|
|
2292
|
+
len(pool) - 1,
|
|
2293
|
+
)
|
|
2294
|
+
]
|
|
2295
|
+
else:
|
|
2296
|
+
chosen = anchor
|
|
2297
|
+
if chosen.action_sha256 == anchor.action_sha256:
|
|
2298
|
+
propensity = (
|
|
2299
|
+
1.0
|
|
2300
|
+
- self.audit_exploration_probability
|
|
2301
|
+
+ self.audit_exploration_probability / len(pool)
|
|
2302
|
+
)
|
|
2303
|
+
else:
|
|
2304
|
+
propensity = (
|
|
2305
|
+
self.audit_exploration_probability / len(pool)
|
|
2306
|
+
)
|
|
2307
|
+
ranked_candidates = directed_ranked
|
|
2308
|
+
ranking_basis = (
|
|
2309
|
+
"conditional_ucb_anchor_plus_epsilon_greedy_"
|
|
2310
|
+
"portable_diversity_audit"
|
|
2311
|
+
)
|
|
2312
|
+
elif (
|
|
2313
|
+
self.policy_version
|
|
2314
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_STRATIFIED_AUDIT_POLICY_VERSION
|
|
2315
|
+
):
|
|
2316
|
+
legacy_pool = ranked[
|
|
2317
|
+
: min(self.exploration_pool_size, len(ranked))
|
|
2318
|
+
]
|
|
2319
|
+
legacy_audit_pool_ids = [
|
|
2320
|
+
value.action_sha256 for value in legacy_pool
|
|
2321
|
+
]
|
|
2322
|
+
legacy_rng = random.Random(
|
|
2323
|
+
int(
|
|
2324
|
+
hashlib.sha256(
|
|
2325
|
+
_canonical_json(
|
|
2326
|
+
[
|
|
2327
|
+
self.random_seed,
|
|
2328
|
+
residual_request_sha256,
|
|
2329
|
+
"randomized_audit",
|
|
2330
|
+
len(selected),
|
|
2331
|
+
legacy_audit_pool_ids,
|
|
2332
|
+
]
|
|
2333
|
+
)
|
|
2334
|
+
).hexdigest(),
|
|
2335
|
+
16,
|
|
2336
|
+
)
|
|
2337
|
+
)
|
|
2338
|
+
anchor = legacy_pool[
|
|
2339
|
+
legacy_rng.randrange(len(legacy_pool))
|
|
2340
|
+
]
|
|
2341
|
+
audit_anchor_sha256 = anchor.action_sha256
|
|
2342
|
+
required_families = set(
|
|
2343
|
+
self.stratified_audit_coverage_family_ids
|
|
2344
|
+
) | set(self.stratified_audit_stratum_family_ids)
|
|
2345
|
+
factor_by_action: dict[str, dict[str, str]] = {}
|
|
2346
|
+
for action in (*selected, *remaining):
|
|
2347
|
+
factors = {
|
|
2348
|
+
value.family_id: value.level_id
|
|
2349
|
+
for value in action.factor_cells
|
|
2350
|
+
}
|
|
2351
|
+
missing = required_families - set(factors)
|
|
2352
|
+
if missing:
|
|
2353
|
+
raise ValueError(
|
|
2354
|
+
"stratified audit action lacks factor families: "
|
|
2355
|
+
+ ",".join(sorted(missing))
|
|
2356
|
+
)
|
|
2357
|
+
factor_by_action[action.action_sha256] = factors
|
|
2358
|
+
selected_levels = {
|
|
2359
|
+
family_id: {
|
|
2360
|
+
factor_by_action[action.action_sha256][family_id]
|
|
2361
|
+
for action in selected
|
|
2362
|
+
}
|
|
2363
|
+
for family_id in (
|
|
2364
|
+
self.stratified_audit_coverage_family_ids
|
|
2365
|
+
)
|
|
2366
|
+
}
|
|
2367
|
+
uncovered_count = {
|
|
2368
|
+
action.action_sha256: sum(
|
|
2369
|
+
factor_by_action[action.action_sha256][family_id]
|
|
2370
|
+
not in selected_levels[family_id]
|
|
2371
|
+
for family_id in (
|
|
2372
|
+
self.stratified_audit_coverage_family_ids
|
|
2373
|
+
)
|
|
2374
|
+
)
|
|
2375
|
+
for action in remaining
|
|
2376
|
+
}
|
|
2377
|
+
audit_max_uncovered_factor_count = max(
|
|
2378
|
+
uncovered_count.values()
|
|
2379
|
+
)
|
|
2380
|
+
exploration_support = tuple(
|
|
2381
|
+
action
|
|
2382
|
+
for action in remaining
|
|
2383
|
+
if uncovered_count[action.action_sha256]
|
|
2384
|
+
== audit_max_uncovered_factor_count
|
|
2385
|
+
)
|
|
2386
|
+
strata: dict[
|
|
2387
|
+
tuple[str, ...],
|
|
2388
|
+
list[AdaptiveActionDescriptor],
|
|
2389
|
+
] = {}
|
|
2390
|
+
for action in exploration_support:
|
|
2391
|
+
key = tuple(
|
|
2392
|
+
factor_by_action[action.action_sha256][family_id]
|
|
2393
|
+
for family_id in (
|
|
2394
|
+
self.stratified_audit_stratum_family_ids
|
|
2395
|
+
)
|
|
2396
|
+
)
|
|
2397
|
+
strata.setdefault(key, []).append(action)
|
|
2398
|
+
canonical_strata = tuple(
|
|
2399
|
+
(
|
|
2400
|
+
key,
|
|
2401
|
+
tuple(
|
|
2402
|
+
sorted(
|
|
2403
|
+
values,
|
|
2404
|
+
key=lambda value: value.action_sha256,
|
|
2405
|
+
)
|
|
2406
|
+
),
|
|
2407
|
+
)
|
|
2408
|
+
for key, values in sorted(strata.items())
|
|
2409
|
+
)
|
|
2410
|
+
audit_strata_record = [
|
|
2411
|
+
{
|
|
2412
|
+
"stratum_key": list(key),
|
|
2413
|
+
"action_sha256s": [
|
|
2414
|
+
value.action_sha256 for value in values
|
|
2415
|
+
],
|
|
2416
|
+
"conditional_action_propensity_hex": (
|
|
2417
|
+
(1.0 / len(values)).hex()
|
|
2418
|
+
),
|
|
2419
|
+
}
|
|
2420
|
+
for key, values in canonical_strata
|
|
2421
|
+
]
|
|
2422
|
+
pool_ids = sorted(
|
|
2423
|
+
value.action_sha256
|
|
2424
|
+
for value in exploration_support
|
|
2425
|
+
)
|
|
2426
|
+
audit_branch_draw = _stable_unit_interval(
|
|
2427
|
+
self.random_seed,
|
|
2428
|
+
residual_request_sha256,
|
|
2429
|
+
"stratified_audit_branch",
|
|
2430
|
+
len(selected),
|
|
2431
|
+
legacy_audit_pool_ids,
|
|
2432
|
+
pool_ids,
|
|
2433
|
+
)
|
|
2434
|
+
audit_exploration_branch = (
|
|
2435
|
+
audit_branch_draw
|
|
2436
|
+
< self.audit_exploration_probability
|
|
2437
|
+
)
|
|
2438
|
+
if audit_exploration_branch:
|
|
2439
|
+
audit_stratum_draw = _stable_unit_interval(
|
|
2440
|
+
self.random_seed,
|
|
2441
|
+
residual_request_sha256,
|
|
2442
|
+
"stratified_audit_stratum",
|
|
2443
|
+
len(selected),
|
|
2444
|
+
[value[0] for value in canonical_strata],
|
|
2445
|
+
)
|
|
2446
|
+
stratum_index = min(
|
|
2447
|
+
int(audit_stratum_draw * len(canonical_strata)),
|
|
2448
|
+
len(canonical_strata) - 1,
|
|
2449
|
+
)
|
|
2450
|
+
(
|
|
2451
|
+
audit_stratum_key,
|
|
2452
|
+
stratum_actions,
|
|
2453
|
+
) = canonical_strata[stratum_index]
|
|
2454
|
+
audit_choice_draw = _stable_unit_interval(
|
|
2455
|
+
self.random_seed,
|
|
2456
|
+
residual_request_sha256,
|
|
2457
|
+
"stratified_audit_action",
|
|
2458
|
+
len(selected),
|
|
2459
|
+
audit_stratum_key,
|
|
2460
|
+
[
|
|
2461
|
+
value.action_sha256
|
|
2462
|
+
for value in stratum_actions
|
|
2463
|
+
],
|
|
2464
|
+
)
|
|
2465
|
+
action_index = min(
|
|
2466
|
+
int(audit_choice_draw * len(stratum_actions)),
|
|
2467
|
+
len(stratum_actions) - 1,
|
|
2468
|
+
)
|
|
2469
|
+
chosen = stratum_actions[action_index]
|
|
2470
|
+
else:
|
|
2471
|
+
chosen = anchor
|
|
2472
|
+
chosen_factors = factor_by_action[
|
|
2473
|
+
chosen.action_sha256
|
|
2474
|
+
]
|
|
2475
|
+
audit_stratum_key = tuple(
|
|
2476
|
+
chosen_factors[family_id]
|
|
2477
|
+
for family_id in (
|
|
2478
|
+
self.stratified_audit_stratum_family_ids
|
|
2479
|
+
)
|
|
2480
|
+
)
|
|
2481
|
+
chosen_stratum = next(
|
|
2482
|
+
(
|
|
2483
|
+
values
|
|
2484
|
+
for key, values in canonical_strata
|
|
2485
|
+
if key == audit_stratum_key
|
|
2486
|
+
),
|
|
2487
|
+
(),
|
|
2488
|
+
)
|
|
2489
|
+
exploration_propensity = (
|
|
2490
|
+
0.0
|
|
2491
|
+
if not chosen_stratum
|
|
2492
|
+
or chosen.action_sha256
|
|
2493
|
+
not in {
|
|
2494
|
+
value.action_sha256
|
|
2495
|
+
for value in chosen_stratum
|
|
2496
|
+
}
|
|
2497
|
+
else 1.0
|
|
2498
|
+
/ len(canonical_strata)
|
|
2499
|
+
/ len(chosen_stratum)
|
|
2500
|
+
)
|
|
2501
|
+
propensity = (
|
|
2502
|
+
(
|
|
2503
|
+
1.0 - self.audit_exploration_probability
|
|
2504
|
+
if chosen.action_sha256 == anchor.action_sha256
|
|
2505
|
+
else 0.0
|
|
2506
|
+
)
|
|
2507
|
+
+ self.audit_exploration_probability
|
|
2508
|
+
* exploration_propensity
|
|
2509
|
+
)
|
|
2510
|
+
ranked_candidates = ranked
|
|
2511
|
+
ranking_basis = (
|
|
2512
|
+
"legacy_v3_audit_anchor_plus_risk_controlled_"
|
|
2513
|
+
"factor_stratified_exploration"
|
|
2514
|
+
)
|
|
2515
|
+
else:
|
|
2516
|
+
pool = ranked[
|
|
2517
|
+
: min(self.exploration_pool_size, len(ranked))
|
|
2518
|
+
]
|
|
2519
|
+
rng = random.Random(
|
|
2520
|
+
int(
|
|
2521
|
+
hashlib.sha256(
|
|
2522
|
+
_canonical_json(
|
|
2523
|
+
[
|
|
2524
|
+
self.random_seed,
|
|
2525
|
+
residual_request_sha256,
|
|
2526
|
+
"randomized_audit",
|
|
2527
|
+
len(selected),
|
|
2528
|
+
[
|
|
2529
|
+
value.action_sha256
|
|
2530
|
+
for value in pool
|
|
2531
|
+
],
|
|
2532
|
+
]
|
|
2533
|
+
)
|
|
2534
|
+
).hexdigest(),
|
|
2535
|
+
16,
|
|
2536
|
+
)
|
|
2537
|
+
)
|
|
2538
|
+
chosen = pool[rng.randrange(len(pool))]
|
|
2539
|
+
propensity = 1.0 / len(pool)
|
|
2540
|
+
pool_ids = [value.action_sha256 for value in pool]
|
|
2541
|
+
ranked_candidates = ranked
|
|
2542
|
+
ranking_basis = (
|
|
2543
|
+
"diversity_then_rank_counterfactual_then_prior"
|
|
2544
|
+
)
|
|
2545
|
+
wave = AdaptiveActionWave.RANDOMIZED_AUDIT
|
|
2546
|
+
else:
|
|
2547
|
+
chosen = directed_ranked[0]
|
|
2548
|
+
propensity = 1.0
|
|
2549
|
+
wave = AdaptiveActionWave.ADAPTIVE
|
|
2550
|
+
pool_ids = []
|
|
2551
|
+
ranked_candidates = directed_ranked
|
|
2552
|
+
ranking_basis = (
|
|
2553
|
+
(
|
|
2554
|
+
"conditional_opportunity_saturation_ucb_then_"
|
|
2555
|
+
"positive_then_prior"
|
|
2556
|
+
if self.policy_version in _CAUSAL_SET_POLICY_VERSIONS
|
|
2557
|
+
else (
|
|
2558
|
+
"robust_engine_exposure_then_within_engine_"
|
|
2559
|
+
"posterior_plus_native_rank"
|
|
2560
|
+
if terminal_hierarchical
|
|
2561
|
+
else "set_aware_ucb_then_positive_then_prior"
|
|
2562
|
+
)
|
|
2563
|
+
)
|
|
2564
|
+
)
|
|
2565
|
+
chosen_components = components[chosen.action_sha256]
|
|
2566
|
+
evidence: dict[str, object] = {
|
|
2567
|
+
"selected_action": chosen.to_record(),
|
|
2568
|
+
"selected_components": {
|
|
2569
|
+
name: value.hex()
|
|
2570
|
+
for name, value in chosen_components.items()
|
|
2571
|
+
},
|
|
2572
|
+
"randomized_exploration_pool_action_sha256s": pool_ids,
|
|
2573
|
+
"candidate_score_count": len(components),
|
|
2574
|
+
"observed_action_count": len(outcomes),
|
|
2575
|
+
"diagnostic_action_sha256s": list(
|
|
2576
|
+
diagnostic_action_sha256s
|
|
2577
|
+
),
|
|
2578
|
+
"diagnostic_joint_gain_hex": (
|
|
2579
|
+
diagnostic_joint_gain.hex()
|
|
2580
|
+
),
|
|
2581
|
+
"observed_set_outcome_sha256s": [
|
|
2582
|
+
value.set_outcome_sha256 for value in set_outcomes
|
|
2583
|
+
],
|
|
2584
|
+
"causal_set_outcomes_used_for_selection": (
|
|
2585
|
+
self.policy_version in _CAUSAL_SET_POLICY_VERSIONS
|
|
2586
|
+
),
|
|
2587
|
+
"directed_steps_completed_before_decision": (
|
|
2588
|
+
directed_steps_completed
|
|
2589
|
+
),
|
|
2590
|
+
"unobserved_candidate_outcomes_available": False,
|
|
2591
|
+
"all_actions_materialized_before_current_outcomes": True,
|
|
2592
|
+
}
|
|
2593
|
+
if excluded_action_sha256s:
|
|
2594
|
+
evidence.update(
|
|
2595
|
+
{
|
|
2596
|
+
"excluded_action_sha256s": list(
|
|
2597
|
+
excluded_action_sha256s
|
|
2598
|
+
),
|
|
2599
|
+
"exclusion_role": (
|
|
2600
|
+
"same_prefix_counterfactual_quarantine"
|
|
2601
|
+
),
|
|
2602
|
+
"excluded_action_outcomes_used_for_selection": False,
|
|
2603
|
+
}
|
|
2604
|
+
)
|
|
2605
|
+
if (
|
|
2606
|
+
self.policy_version
|
|
2607
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_RISK_CONTROLLED_POLICY_VERSION
|
|
2608
|
+
):
|
|
2609
|
+
evidence.update(
|
|
2610
|
+
{
|
|
2611
|
+
"risk_controlled_audit": audit,
|
|
2612
|
+
"audit_exploration_probability_hex": (
|
|
2613
|
+
self.audit_exploration_probability.hex()
|
|
2614
|
+
),
|
|
2615
|
+
"audit_anchor_action_sha256": (
|
|
2616
|
+
audit_anchor_sha256
|
|
2617
|
+
),
|
|
2618
|
+
"audit_exploration_branch": (
|
|
2619
|
+
audit_exploration_branch
|
|
2620
|
+
),
|
|
2621
|
+
"audit_branch_draw_hex": (
|
|
2622
|
+
None
|
|
2623
|
+
if audit_branch_draw is None
|
|
2624
|
+
else audit_branch_draw.hex()
|
|
2625
|
+
),
|
|
2626
|
+
"audit_choice_draw_hex": (
|
|
2627
|
+
None
|
|
2628
|
+
if audit_choice_draw is None
|
|
2629
|
+
else audit_choice_draw.hex()
|
|
2630
|
+
),
|
|
2631
|
+
"audit_selected_propensity_hex": (
|
|
2632
|
+
float(propensity).hex()
|
|
2633
|
+
),
|
|
2634
|
+
"seed_affects_only_audit_draw": True,
|
|
2635
|
+
}
|
|
2636
|
+
)
|
|
2637
|
+
if (
|
|
2638
|
+
self.policy_version
|
|
2639
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_STRATIFIED_AUDIT_POLICY_VERSION
|
|
2640
|
+
):
|
|
2641
|
+
evidence.update(
|
|
2642
|
+
{
|
|
2643
|
+
"risk_controlled_stratified_audit": audit,
|
|
2644
|
+
"audit_exploration_probability_hex": (
|
|
2645
|
+
self.audit_exploration_probability.hex()
|
|
2646
|
+
),
|
|
2647
|
+
"legacy_audit_anchor_action_sha256": (
|
|
2648
|
+
audit_anchor_sha256
|
|
2649
|
+
),
|
|
2650
|
+
"legacy_audit_pool_action_sha256s": (
|
|
2651
|
+
legacy_audit_pool_ids
|
|
2652
|
+
),
|
|
2653
|
+
"audit_exploration_branch": (
|
|
2654
|
+
audit_exploration_branch
|
|
2655
|
+
),
|
|
2656
|
+
"audit_branch_draw_hex": (
|
|
2657
|
+
None
|
|
2658
|
+
if audit_branch_draw is None
|
|
2659
|
+
else audit_branch_draw.hex()
|
|
2660
|
+
),
|
|
2661
|
+
"audit_stratum_draw_hex": (
|
|
2662
|
+
None
|
|
2663
|
+
if audit_stratum_draw is None
|
|
2664
|
+
else audit_stratum_draw.hex()
|
|
2665
|
+
),
|
|
2666
|
+
"audit_choice_draw_hex": (
|
|
2667
|
+
None
|
|
2668
|
+
if audit_choice_draw is None
|
|
2669
|
+
else audit_choice_draw.hex()
|
|
2670
|
+
),
|
|
2671
|
+
"audit_selected_stratum_key": (
|
|
2672
|
+
None
|
|
2673
|
+
if audit_stratum_key is None
|
|
2674
|
+
else list(audit_stratum_key)
|
|
2675
|
+
),
|
|
2676
|
+
"audit_strata": audit_strata_record,
|
|
2677
|
+
"audit_max_uncovered_factor_count": (
|
|
2678
|
+
audit_max_uncovered_factor_count
|
|
2679
|
+
),
|
|
2680
|
+
"audit_coverage_family_ids": list(
|
|
2681
|
+
self.stratified_audit_coverage_family_ids
|
|
2682
|
+
),
|
|
2683
|
+
"audit_stratum_family_ids": list(
|
|
2684
|
+
self.stratified_audit_stratum_family_ids
|
|
2685
|
+
),
|
|
2686
|
+
"audit_selected_propensity_hex": (
|
|
2687
|
+
float(propensity).hex()
|
|
2688
|
+
),
|
|
2689
|
+
"legacy_anchor_probability_hex": (
|
|
2690
|
+
(1.0 - self.audit_exploration_probability).hex()
|
|
2691
|
+
),
|
|
2692
|
+
"candidate_factor_cells_outcome_blind": True,
|
|
2693
|
+
"seed_affects_legacy_anchor_and_audit_draws": True,
|
|
2694
|
+
}
|
|
2695
|
+
)
|
|
2696
|
+
if (
|
|
2697
|
+
self.policy_version
|
|
2698
|
+
== OUTCOME_ADAPTIVE_ACTION_RACING_HORIZON_HIERARCHICAL_POLICY_VERSION
|
|
2699
|
+
):
|
|
2700
|
+
evidence.update(
|
|
2701
|
+
{
|
|
2702
|
+
"horizon_aware_authoritative_measurement": True,
|
|
2703
|
+
"seats_left_before_decision": seats_left,
|
|
2704
|
+
"future_optimization_slots_after_decision": max(
|
|
2705
|
+
0,
|
|
2706
|
+
seats_left - 1,
|
|
2707
|
+
),
|
|
2708
|
+
"authoritative_audit_due": horizon_audit_due,
|
|
2709
|
+
"authoritative_audit_selected": audit,
|
|
2710
|
+
"authoritative_audit_blocked_reason": (
|
|
2711
|
+
horizon_audit_blocked_reason
|
|
2712
|
+
),
|
|
2713
|
+
"minimum_post_audit_optimization_slots": (
|
|
2714
|
+
self.minimum_post_audit_optimization_slots
|
|
2715
|
+
),
|
|
2716
|
+
"terminal_hierarchical_slots": (
|
|
2717
|
+
self.terminal_hierarchical_slots
|
|
2718
|
+
),
|
|
2719
|
+
"terminal_hierarchical_allocation": (
|
|
2720
|
+
terminal_hierarchical
|
|
2721
|
+
),
|
|
2722
|
+
"hierarchical_engine_order": list(
|
|
2723
|
+
hierarchical_engine_order
|
|
2724
|
+
),
|
|
2725
|
+
"selected_engine_id": chosen.lane_id,
|
|
2726
|
+
"native_rank_strength_hex": (
|
|
2727
|
+
self.native_rank_strength.hex()
|
|
2728
|
+
),
|
|
2729
|
+
"engine_returns_capped_only_for_allocation": True,
|
|
2730
|
+
"authoritative_archive_utility_capped": False,
|
|
2731
|
+
"workload_model_provider_prompt_branches": False,
|
|
2732
|
+
}
|
|
2733
|
+
)
|
|
2734
|
+
if (
|
|
2735
|
+
self.policy_version
|
|
2736
|
+
in {
|
|
2737
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_SET_AWARE_POLICY_VERSION,
|
|
2738
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_CAUSAL_SET_POLICY_VERSION,
|
|
2739
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_RISK_CONTROLLED_POLICY_VERSION,
|
|
2740
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_STRATIFIED_AUDIT_POLICY_VERSION,
|
|
2741
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_HORIZON_HIERARCHICAL_POLICY_VERSION,
|
|
2742
|
+
}
|
|
2743
|
+
):
|
|
2744
|
+
evidence.update(
|
|
2745
|
+
{
|
|
2746
|
+
"candidate_score_cards": [
|
|
2747
|
+
{
|
|
2748
|
+
"rank": rank,
|
|
2749
|
+
"selected": (
|
|
2750
|
+
value.action_sha256
|
|
2751
|
+
== chosen.action_sha256
|
|
2752
|
+
),
|
|
2753
|
+
"randomized_pool_member": (
|
|
2754
|
+
value.action_sha256 in set(pool_ids)
|
|
2755
|
+
),
|
|
2756
|
+
"action": value.to_record(),
|
|
2757
|
+
"components": {
|
|
2758
|
+
name: component.hex()
|
|
2759
|
+
for name, component in components[
|
|
2760
|
+
value.action_sha256
|
|
2761
|
+
].items()
|
|
2762
|
+
},
|
|
2763
|
+
}
|
|
2764
|
+
for rank, value in enumerate(
|
|
2765
|
+
ranked_candidates[
|
|
2766
|
+
: self.trace_alternative_count
|
|
2767
|
+
],
|
|
2768
|
+
start=1,
|
|
2769
|
+
)
|
|
2770
|
+
],
|
|
2771
|
+
"candidate_score_card_count": min(
|
|
2772
|
+
self.trace_alternative_count,
|
|
2773
|
+
len(ranked_candidates),
|
|
2774
|
+
),
|
|
2775
|
+
"candidate_score_ranking_basis": ranking_basis,
|
|
2776
|
+
"chosen_action_present_in_score_cards": (
|
|
2777
|
+
chosen.action_sha256
|
|
2778
|
+
in {
|
|
2779
|
+
value.action_sha256
|
|
2780
|
+
for value in ranked_candidates[
|
|
2781
|
+
: self.trace_alternative_count
|
|
2782
|
+
]
|
|
2783
|
+
}
|
|
2784
|
+
),
|
|
2785
|
+
}
|
|
2786
|
+
)
|
|
2787
|
+
return AdaptiveActionRacingDecision(
|
|
2788
|
+
policy_id=self.policy_id,
|
|
2789
|
+
policy_version=self.policy_version,
|
|
2790
|
+
policy_definition_sha256=self.definition_sha256,
|
|
2791
|
+
residual_request_sha256=residual_request_sha256,
|
|
2792
|
+
wave=wave,
|
|
2793
|
+
selected_action_sha256s=(chosen.action_sha256,),
|
|
2794
|
+
prior_selected_action_sha256s=tuple(
|
|
2795
|
+
sorted(selected_action_sha256s)
|
|
2796
|
+
),
|
|
2797
|
+
observed_outcome_sha256s=tuple(
|
|
2798
|
+
sorted(value.outcome_sha256 for value in outcomes)
|
|
2799
|
+
),
|
|
2800
|
+
observed_set_outcome_sha256s=tuple(
|
|
2801
|
+
sorted(
|
|
2802
|
+
value.set_outcome_sha256
|
|
2803
|
+
for value in set_outcomes
|
|
2804
|
+
)
|
|
2805
|
+
),
|
|
2806
|
+
selection_propensity=float(propensity),
|
|
2807
|
+
evidence=freeze_json(evidence),
|
|
2808
|
+
)
|
|
2809
|
+
|
|
2810
|
+
|
|
2811
|
+
__all__ = [
|
|
2812
|
+
"AdaptiveActionAllocationDirective",
|
|
2813
|
+
"AdaptiveActionDescriptor",
|
|
2814
|
+
"AdaptiveActionFactorCell",
|
|
2815
|
+
"AdaptiveActionOutcome",
|
|
2816
|
+
"AdaptiveActionSetOutcome",
|
|
2817
|
+
"AdaptiveActionRacingDecision",
|
|
2818
|
+
"AdaptiveActionWave",
|
|
2819
|
+
"OUTCOME_ADAPTIVE_ACTION_RACING_CAUSAL_SET_POLICY_VERSION",
|
|
2820
|
+
"OUTCOME_ADAPTIVE_ACTION_RACING_HORIZON_HIERARCHICAL_POLICY_VERSION",
|
|
2821
|
+
"OUTCOME_ADAPTIVE_ACTION_RACING_POLICY_ID",
|
|
2822
|
+
"OUTCOME_ADAPTIVE_ACTION_RACING_POLICY_VERSION",
|
|
2823
|
+
"OUTCOME_ADAPTIVE_ACTION_RACING_RISK_CONTROLLED_POLICY_VERSION",
|
|
2824
|
+
"OUTCOME_ADAPTIVE_ACTION_RACING_STRATIFIED_AUDIT_POLICY_VERSION",
|
|
2825
|
+
"OUTCOME_ADAPTIVE_ACTION_RACING_SET_AWARE_POLICY_VERSION",
|
|
2826
|
+
"OutcomeAdaptiveActionRacingPolicy",
|
|
2827
|
+
]
|