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,3671 @@
|
|
|
1
|
+
"""Durable outcome-adaptive evolution over one sealed proposal market.
|
|
2
|
+
|
|
3
|
+
This application service turns outcome-adaptive action racing into an honest
|
|
4
|
+
live protocol. Proposal experts materialize every action before a current
|
|
5
|
+
outcome exists. A diagnostic subset is evaluated first, and each subsequent
|
|
6
|
+
action is selected only from outcomes that have crossed a durable interception
|
|
7
|
+
boundary.
|
|
8
|
+
|
|
9
|
+
The service is workload-, objective-, model-, provider-, prompt-, and
|
|
10
|
+
configuration-schema blind. Workloads remain behind the existing proposal,
|
|
11
|
+
evaluation, archive-utility, slate-value, and slate-feasibility ports.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import asyncio
|
|
17
|
+
import hashlib
|
|
18
|
+
import json
|
|
19
|
+
import math
|
|
20
|
+
import re
|
|
21
|
+
from dataclasses import dataclass, field
|
|
22
|
+
from enum import Enum
|
|
23
|
+
from typing import Protocol, runtime_checkable
|
|
24
|
+
|
|
25
|
+
from agent_evolve.application.agentic_evolution import EvolutionCandidate
|
|
26
|
+
from agent_evolve.application.candidate_archive_consequence import (
|
|
27
|
+
CandidateArchivePortfolioConsequenceUtilityPort,
|
|
28
|
+
validate_candidate_archive_portfolio_consequence_utility,
|
|
29
|
+
)
|
|
30
|
+
from agent_evolve.application.forecast_opportunity_shadow_calibration import (
|
|
31
|
+
ForecastOpportunityShadowCalibrationProjector,
|
|
32
|
+
)
|
|
33
|
+
from agent_evolve.application.materialized_action_broker import (
|
|
34
|
+
BrokerActionScore,
|
|
35
|
+
MaterializedActionAllocationRequirement,
|
|
36
|
+
MaterializedActionBrokerDecision,
|
|
37
|
+
MaterializedActionBrokerRequest,
|
|
38
|
+
MaterializedActionDescriptor,
|
|
39
|
+
MaterializedSlateFeasibilityPort,
|
|
40
|
+
MaterializedSlateValuePort,
|
|
41
|
+
RegretBrokeredMaterializedActionPolicy,
|
|
42
|
+
)
|
|
43
|
+
from agent_evolve.application.outcome_adaptive_action_racing import (
|
|
44
|
+
AdaptiveActionAllocationDirective,
|
|
45
|
+
AdaptiveActionDescriptor,
|
|
46
|
+
AdaptiveActionFactorCell,
|
|
47
|
+
AdaptiveActionOutcome,
|
|
48
|
+
AdaptiveActionRacingDecision,
|
|
49
|
+
AdaptiveActionSetOutcome,
|
|
50
|
+
AdaptiveActionWave,
|
|
51
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_CAUSAL_SET_POLICY_VERSION,
|
|
52
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_RISK_CONTROLLED_POLICY_VERSION,
|
|
53
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_STRATIFIED_AUDIT_POLICY_VERSION,
|
|
54
|
+
OutcomeAdaptiveActionRacingPolicy,
|
|
55
|
+
)
|
|
56
|
+
from agent_evolve.application.prequential_score_portfolio import (
|
|
57
|
+
MaterializedActionScoreBatch,
|
|
58
|
+
MaterializedActionScorePort,
|
|
59
|
+
)
|
|
60
|
+
from agent_evolve.application.prequential_archive_opportunity_calibration import (
|
|
61
|
+
ArchiveOpportunityCalibrationObservation,
|
|
62
|
+
)
|
|
63
|
+
from agent_evolve.application.protected_current_prefix_forecast_opportunity import (
|
|
64
|
+
ProtectedCurrentPrefixForecastOpportunityChallenger,
|
|
65
|
+
)
|
|
66
|
+
from agent_evolve.application.residual_portfolio_evolution import (
|
|
67
|
+
DISJOINT_ACTION_EVALUATION_WAVES_V1,
|
|
68
|
+
MaterializedActionAllocationPolicyPort,
|
|
69
|
+
MaterializedActionEvaluation,
|
|
70
|
+
MaterializedActionEvaluationBatch,
|
|
71
|
+
MaterializedActionProposalBatch,
|
|
72
|
+
MaterializedActionProposalExpertPort,
|
|
73
|
+
ResidualPortfolioDecisionRequest,
|
|
74
|
+
ResidualPortfolioEvolutionResult,
|
|
75
|
+
evaluate_materialized_action_counterfactual_subset,
|
|
76
|
+
evaluate_materialized_action_subset,
|
|
77
|
+
propose_materialized_action_batches,
|
|
78
|
+
)
|
|
79
|
+
from agent_evolve.application.same_prefix_paired_audit import (
|
|
80
|
+
FORECAST_OPPORTUNITY_SAME_PREFIX_AUDIT_DESIGNER_IDS,
|
|
81
|
+
FORECAST_OPPORTUNITY_SAME_PREFIX_SHADOW_DESIGNER_ID,
|
|
82
|
+
FORECAST_STRATIFIED_SAME_PREFIX_AUDIT_DESIGNER_ID,
|
|
83
|
+
ForecastOpportunitySamePrefixShadowDesignerPort,
|
|
84
|
+
SamePrefixPairedAuditAdjudicator,
|
|
85
|
+
SamePrefixPairedAuditArm,
|
|
86
|
+
SamePrefixPairedAuditDesignerPort,
|
|
87
|
+
SamePrefixPairedAuditObservation,
|
|
88
|
+
SamePrefixPairedAuditPlan,
|
|
89
|
+
)
|
|
90
|
+
from agent_evolve.domain.ids import CandidateId
|
|
91
|
+
from agent_evolve.domain.patch import require_sha256
|
|
92
|
+
from agent_evolve.domain.typed_json import (
|
|
93
|
+
FrozenJsonObject,
|
|
94
|
+
freeze_json,
|
|
95
|
+
thaw_json,
|
|
96
|
+
typed_json_sha256,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_ID = (
|
|
101
|
+
"outcome_adaptive_residual_portfolio_evolution"
|
|
102
|
+
)
|
|
103
|
+
OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_VERSION = 5
|
|
104
|
+
OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_DEFINITION_SHA256 = hashlib.sha256(
|
|
105
|
+
b"agent-evolve:outcome-adaptive-residual-portfolio-evolution:v5;"
|
|
106
|
+
b"proposal-market=sealed-once-before-current-outcomes;"
|
|
107
|
+
b"prior-authority=materialized-action-broker-selection-index;"
|
|
108
|
+
b"diagnostic-allocation=optional-outcome-blind-required-action-policy;"
|
|
109
|
+
b"diagnostic=portable-constrained-lane-head-design;"
|
|
110
|
+
b"continuation=one-real-outcome-then-one-action;"
|
|
111
|
+
b"causal-outcomes=fixed-set-and-prior-conditioned-set-lift;"
|
|
112
|
+
b"policy-use-of-causal-set-outcomes=version-gated;"
|
|
113
|
+
b"v4=conditional-opportunity-saturation-and-uniform-audit;"
|
|
114
|
+
b"v5=seed-invariant-directed-selection-and-epsilon-greedy-risk-audit;"
|
|
115
|
+
b"randomized-audit=logged-propensity;"
|
|
116
|
+
b"durability=market-diagnostic-each-adaptive-step-final;"
|
|
117
|
+
b"exactly-once=disjoint-action-evaluation-waves;"
|
|
118
|
+
b"archive-publication=combined-final-slate-only;"
|
|
119
|
+
b"workload-objective-model-provider-prompt-config-branches=false"
|
|
120
|
+
).hexdigest()
|
|
121
|
+
OUTCOME_ADAPTIVE_RESIDUAL_PAIRED_AUDIT_EVOLUTION_VERSION = 6
|
|
122
|
+
OUTCOME_ADAPTIVE_RESIDUAL_PAIRED_AUDIT_EVOLUTION_DEFINITION_SHA256 = (
|
|
123
|
+
hashlib.sha256(
|
|
124
|
+
b"agent-evolve:outcome-adaptive-residual-portfolio-evolution:v6;"
|
|
125
|
+
b"base-definition="
|
|
126
|
+
+ OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_DEFINITION_SHA256.encode(
|
|
127
|
+
"ascii"
|
|
128
|
+
)
|
|
129
|
+
+ b";paired-audit=optional-same-prefix-distinct-arm-assay;"
|
|
130
|
+
b"paired-audit-plan=durable-before-either-arm-evaluation;"
|
|
131
|
+
b"paired-audit-publication=authoritative-arm-only;"
|
|
132
|
+
b"physical-budget=one-extra-real-evaluation-per-assayed-stage;"
|
|
133
|
+
b"workload-objective-model-provider-prompt-config-branches=false"
|
|
134
|
+
).hexdigest()
|
|
135
|
+
)
|
|
136
|
+
OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_OPPORTUNITY_EVOLUTION_VERSION = 7
|
|
137
|
+
OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_OPPORTUNITY_EVOLUTION_DEFINITION_SHA256 = (
|
|
138
|
+
hashlib.sha256(
|
|
139
|
+
b"agent-evolve:outcome-adaptive-residual-portfolio-evolution:v7;"
|
|
140
|
+
b"base-definition="
|
|
141
|
+
+ OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_DEFINITION_SHA256.encode(
|
|
142
|
+
"ascii"
|
|
143
|
+
)
|
|
144
|
+
+ b";continuation=protected-current-prefix-forecast-opportunity;"
|
|
145
|
+
b"forecast-geometry=frozen-before-diagnostic-outcomes;"
|
|
146
|
+
b"fallback=complete-incumbent-racing-decision;"
|
|
147
|
+
b"abstention=preserve-fallback;"
|
|
148
|
+
b"candidate-outcomes=observed-prefix-only;"
|
|
149
|
+
b"eligible-candidate-outcomes=false;"
|
|
150
|
+
b"workload-objective-model-provider-prompt-config-branches=false"
|
|
151
|
+
).hexdigest()
|
|
152
|
+
)
|
|
153
|
+
_FORECAST_OPPORTUNITY_DEFINITION_SHA256 = (
|
|
154
|
+
OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_OPPORTUNITY_EVOLUTION_DEFINITION_SHA256
|
|
155
|
+
)
|
|
156
|
+
_PAIRED_AUDIT_DEFINITION_SHA256 = (
|
|
157
|
+
OUTCOME_ADAPTIVE_RESIDUAL_PAIRED_AUDIT_EVOLUTION_DEFINITION_SHA256
|
|
158
|
+
)
|
|
159
|
+
OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_SHADOW_EVOLUTION_VERSION = 8
|
|
160
|
+
OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_SHADOW_EVOLUTION_DEFINITION_SHA256 = (
|
|
161
|
+
hashlib.sha256(
|
|
162
|
+
b"agent-evolve:outcome-adaptive-residual-portfolio-evolution:v8;"
|
|
163
|
+
b"base-definition="
|
|
164
|
+
+ _FORECAST_OPPORTUNITY_DEFINITION_SHA256.encode("ascii")
|
|
165
|
+
+ b";shadow=optional-same-prefix-challenger-vs-fallback-assay;"
|
|
166
|
+
b"shadow-plan=durable-before-either-arm-evaluation;"
|
|
167
|
+
b"shadow-schedule=final-continuation-only;"
|
|
168
|
+
b"shadow-publication=authoritative-challenger-only;"
|
|
169
|
+
b"physical-budget=one-extra-real-evaluation-per-assayed-stage;"
|
|
170
|
+
b"workload-objective-model-provider-prompt-config-branches=false"
|
|
171
|
+
).hexdigest()
|
|
172
|
+
)
|
|
173
|
+
OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_STRATIFIED_AUDIT_EVOLUTION_VERSION = 9
|
|
174
|
+
OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_STRATIFIED_AUDIT_EVOLUTION_DEFINITION_SHA256 = (
|
|
175
|
+
hashlib.sha256(
|
|
176
|
+
b"agent-evolve:outcome-adaptive-residual-portfolio-evolution:v9;"
|
|
177
|
+
b"base-definition="
|
|
178
|
+
+ _FORECAST_OPPORTUNITY_DEFINITION_SHA256.encode("ascii")
|
|
179
|
+
+ b";audit=one-hash-rotated-same-prefix-forecast-stratum-assay;"
|
|
180
|
+
b"audit-plan=durable-before-either-arm-evaluation;"
|
|
181
|
+
b"abstention-authoritative-arm=protected-fallback;"
|
|
182
|
+
b"intervention-authoritative-arm=forecast-challenger;"
|
|
183
|
+
b"counterfactual-action=quarantined-from-later-authoritative-selection;"
|
|
184
|
+
b"sampling=uniform-nonempty-stratum-then-uniform-action;"
|
|
185
|
+
b"calibration=paired-role-and-propensity-authenticated;"
|
|
186
|
+
b"audit-publication=authoritative-arm-only;"
|
|
187
|
+
b"physical-budget=at-most-one-extra-real-evaluation-per-assayed-stage;"
|
|
188
|
+
b"workload-objective-model-provider-prompt-config-branches=false"
|
|
189
|
+
).hexdigest()
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
PORTABLE_ADAPTIVE_MARKET_PROJECTOR_ID = (
|
|
193
|
+
"portable_materialized_adaptive_market_projector"
|
|
194
|
+
)
|
|
195
|
+
PORTABLE_ADAPTIVE_MARKET_PROJECTOR_VERSION = 1
|
|
196
|
+
PORTABLE_ADAPTIVE_MARKET_PROJECTOR_DEFINITION_SHA256 = hashlib.sha256(
|
|
197
|
+
b"agent-evolve:portable-materialized-adaptive-market-projector:v1;"
|
|
198
|
+
b"deduplicate=required-first-then-prior-score-native-rank-action-hash;"
|
|
199
|
+
b"lane=expert;operator=operator-id;"
|
|
200
|
+
b"prior=broker-selection-index;"
|
|
201
|
+
b"lineage=current-run-parent-membership;"
|
|
202
|
+
b"semantics=generic-materialized-action-context-only;"
|
|
203
|
+
b"workload-objective-model-provider-prompt-config-fields=false"
|
|
204
|
+
).hexdigest()
|
|
205
|
+
PORTABLE_ADAPTIVE_SEMANTIC_VIEW_ID = (
|
|
206
|
+
"portable_materialized_adaptive_semantic_view"
|
|
207
|
+
)
|
|
208
|
+
PORTABLE_ADAPTIVE_SEMANTIC_VIEW_VERSION = 1
|
|
209
|
+
PORTABLE_ADAPTIVE_SEMANTIC_VIEW_DEFINITION_SHA256 = hashlib.sha256(
|
|
210
|
+
b"agent-evolve:portable-materialized-adaptive-semantic-view:v1;"
|
|
211
|
+
b"inputs=generic-materialized-action-context-lineage-and-role;"
|
|
212
|
+
b"workload-objective-model-provider-prompt-config-fields=false"
|
|
213
|
+
).hexdigest()
|
|
214
|
+
|
|
215
|
+
CANDIDATE_ARCHIVE_ADAPTIVE_OUTCOME_PROJECTOR_ID = (
|
|
216
|
+
"candidate_archive_adaptive_action_outcome_projector"
|
|
217
|
+
)
|
|
218
|
+
CANDIDATE_ARCHIVE_ADAPTIVE_OUTCOME_PROJECTOR_VERSION = 2
|
|
219
|
+
|
|
220
|
+
_TOKEN = re.compile(r"^[a-z][a-z0-9_.:-]{0,255}$")
|
|
221
|
+
_MARKET_STATE_DOMAIN = b"agent-evolve:adaptive-market-state:v1\x00"
|
|
222
|
+
_SCORE_ENSEMBLE_PROJECTOR_DEFINITION_DOMAIN = (
|
|
223
|
+
b"agent-evolve:score-ensemble-adaptive-market-projector:v1\x00"
|
|
224
|
+
)
|
|
225
|
+
_FACTOR_STRATIFIED_PROJECTOR_DEFINITION_DOMAIN = (
|
|
226
|
+
b"agent-evolve:factor-stratified-adaptive-market-projector:v1\x00"
|
|
227
|
+
)
|
|
228
|
+
_OUTCOME_PROJECTOR_DEFINITION_DOMAIN = (
|
|
229
|
+
b"agent-evolve:adaptive-outcome-projector-definition:v2\x00"
|
|
230
|
+
)
|
|
231
|
+
_PHASE_RECEIPT_DOMAIN = (
|
|
232
|
+
b"agent-evolve:outcome-adaptive-phase-receipt:v1\x00"
|
|
233
|
+
)
|
|
234
|
+
_PHASE_ACK_DOMAIN = b"agent-evolve:outcome-adaptive-phase-ack:v1\x00"
|
|
235
|
+
_PAIRED_AUDIT_EXECUTION_DOMAIN = (
|
|
236
|
+
b"agent-evolve:outcome-adaptive-paired-audit-execution:v1\x00"
|
|
237
|
+
)
|
|
238
|
+
_RESULT_DOMAIN = b"agent-evolve:outcome-adaptive-result:v5\x00"
|
|
239
|
+
_PAIRED_AUDIT_RESULT_DOMAIN = (
|
|
240
|
+
b"agent-evolve:outcome-adaptive-result:v6\x00"
|
|
241
|
+
)
|
|
242
|
+
_FORECAST_OPPORTUNITY_RESULT_DOMAIN = (
|
|
243
|
+
b"agent-evolve:outcome-adaptive-result:v7\x00"
|
|
244
|
+
)
|
|
245
|
+
_FORECAST_SHADOW_RESULT_DOMAIN = (
|
|
246
|
+
b"agent-evolve:outcome-adaptive-result:v8\x00"
|
|
247
|
+
)
|
|
248
|
+
_FORECAST_STRATIFIED_AUDIT_RESULT_DOMAIN = (
|
|
249
|
+
b"agent-evolve:outcome-adaptive-result:v9\x00"
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def _canonical_json(value: object) -> bytes:
|
|
254
|
+
return json.dumps(
|
|
255
|
+
value,
|
|
256
|
+
allow_nan=False,
|
|
257
|
+
ensure_ascii=True,
|
|
258
|
+
separators=(",", ":"),
|
|
259
|
+
sort_keys=True,
|
|
260
|
+
).encode("ascii", errors="strict")
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def _hash(domain: bytes, value: object) -> str:
|
|
264
|
+
return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
def _require_token(value: str, *, name: str) -> None:
|
|
268
|
+
if type(value) is not str or _TOKEN.fullmatch(value) is None:
|
|
269
|
+
raise ValueError(f"{name} must use the closed token grammar")
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def _candidate_id_tuple(
|
|
273
|
+
values: tuple[CandidateId, ...],
|
|
274
|
+
) -> tuple[str, ...]:
|
|
275
|
+
if type(values) is not tuple:
|
|
276
|
+
raise TypeError("current_run_parent_ids must be an exact tuple")
|
|
277
|
+
result: list[str] = []
|
|
278
|
+
for value in values:
|
|
279
|
+
if type(value) is not CandidateId:
|
|
280
|
+
raise TypeError("current_run_parent_ids must contain exact IDs")
|
|
281
|
+
CandidateId.__post_init__(value)
|
|
282
|
+
result.append(value.value)
|
|
283
|
+
if result != sorted(set(result)):
|
|
284
|
+
raise ValueError(
|
|
285
|
+
"current_run_parent_ids must be unique and canonical"
|
|
286
|
+
)
|
|
287
|
+
return tuple(result)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
@dataclass(frozen=True, slots=True)
|
|
291
|
+
class AdaptiveActionSemanticView:
|
|
292
|
+
"""Portable operator grouping and semantic cells for one action."""
|
|
293
|
+
|
|
294
|
+
operator_id: str
|
|
295
|
+
semantic_cell_ids: tuple[str, ...]
|
|
296
|
+
|
|
297
|
+
def __post_init__(self) -> None:
|
|
298
|
+
_require_token(self.operator_id, name="operator_id")
|
|
299
|
+
if (
|
|
300
|
+
type(self.semantic_cell_ids) is not tuple
|
|
301
|
+
or self.semantic_cell_ids
|
|
302
|
+
!= tuple(sorted(set(self.semantic_cell_ids)))
|
|
303
|
+
):
|
|
304
|
+
raise ValueError(
|
|
305
|
+
"semantic_cell_ids must be unique and canonical"
|
|
306
|
+
)
|
|
307
|
+
for value in self.semantic_cell_ids:
|
|
308
|
+
_require_token(value, name="semantic_cell_id")
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
@runtime_checkable
|
|
312
|
+
class AdaptiveActionSemanticViewPort(Protocol):
|
|
313
|
+
"""Optional pre-evaluation semantic view; never sees candidate outcomes."""
|
|
314
|
+
|
|
315
|
+
projection_id: str
|
|
316
|
+
projection_version: int
|
|
317
|
+
definition_sha256: str
|
|
318
|
+
|
|
319
|
+
def view(
|
|
320
|
+
self,
|
|
321
|
+
action: MaterializedActionDescriptor,
|
|
322
|
+
) -> AdaptiveActionSemanticView: ...
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
@dataclass(frozen=True, slots=True)
|
|
326
|
+
class PortableMaterializedAdaptiveSemanticView:
|
|
327
|
+
"""Default view requiring no workload-specific integration."""
|
|
328
|
+
|
|
329
|
+
projection_id: str = PORTABLE_ADAPTIVE_SEMANTIC_VIEW_ID
|
|
330
|
+
projection_version: int = PORTABLE_ADAPTIVE_SEMANTIC_VIEW_VERSION
|
|
331
|
+
definition_sha256: str = (
|
|
332
|
+
PORTABLE_ADAPTIVE_SEMANTIC_VIEW_DEFINITION_SHA256
|
|
333
|
+
)
|
|
334
|
+
|
|
335
|
+
def view(
|
|
336
|
+
self,
|
|
337
|
+
action: MaterializedActionDescriptor,
|
|
338
|
+
) -> AdaptiveActionSemanticView:
|
|
339
|
+
if type(action) is not MaterializedActionDescriptor:
|
|
340
|
+
raise TypeError("action must be exact")
|
|
341
|
+
action.__post_init__()
|
|
342
|
+
context = action.context
|
|
343
|
+
return AdaptiveActionSemanticView(
|
|
344
|
+
operator_id=action.operator_id,
|
|
345
|
+
semantic_cell_ids=tuple(
|
|
346
|
+
sorted(
|
|
347
|
+
{
|
|
348
|
+
f"role:{action.role_id}",
|
|
349
|
+
f"residual:{context.residual_frontier_cell}",
|
|
350
|
+
(
|
|
351
|
+
"parent_position:"
|
|
352
|
+
f"{context.parent_position_cell}"
|
|
353
|
+
),
|
|
354
|
+
(
|
|
355
|
+
"archive_relation:"
|
|
356
|
+
f"{context.archive_relation_cell}"
|
|
357
|
+
),
|
|
358
|
+
f"patch:{context.patch_compatibility_cell}",
|
|
359
|
+
(
|
|
360
|
+
"calibration:"
|
|
361
|
+
f"{context.forecast_calibration_cell}"
|
|
362
|
+
),
|
|
363
|
+
f"phase:{context.phase.value}",
|
|
364
|
+
f"arity:{len(action.parent_ids)}",
|
|
365
|
+
f"reference:{int(action.reference_action)}",
|
|
366
|
+
(
|
|
367
|
+
"source_distance:"
|
|
368
|
+
f"{context.source_distance_bin}"
|
|
369
|
+
),
|
|
370
|
+
f"memory_dose:{context.memory_dose_bin}",
|
|
371
|
+
"structure:"
|
|
372
|
+
+ context.structural_signature_sha256[:16],
|
|
373
|
+
}
|
|
374
|
+
)
|
|
375
|
+
),
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
|
|
379
|
+
@runtime_checkable
|
|
380
|
+
class AdaptiveActionMarketProjectorPort(Protocol):
|
|
381
|
+
"""Project materialized actions into a portable outcome-blind market."""
|
|
382
|
+
|
|
383
|
+
projector_id: str
|
|
384
|
+
projector_version: int
|
|
385
|
+
definition_sha256: str
|
|
386
|
+
state_sha256: str
|
|
387
|
+
|
|
388
|
+
async def project(
|
|
389
|
+
self,
|
|
390
|
+
request: ResidualPortfolioDecisionRequest,
|
|
391
|
+
proposals: tuple[MaterializedActionProposalBatch, ...],
|
|
392
|
+
actions: tuple[MaterializedActionDescriptor, ...],
|
|
393
|
+
scores: tuple[BrokerActionScore, ...],
|
|
394
|
+
required_action_sha256s: tuple[str, ...],
|
|
395
|
+
) -> tuple[AdaptiveActionDescriptor, ...]: ...
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
@dataclass(frozen=True, slots=True)
|
|
399
|
+
class PortableMaterializedAdaptiveMarketProjector:
|
|
400
|
+
"""Default zero-workload-knowledge projection for adaptive racing."""
|
|
401
|
+
|
|
402
|
+
current_run_parent_ids: tuple[CandidateId, ...] = ()
|
|
403
|
+
semantic_view: AdaptiveActionSemanticViewPort = field(
|
|
404
|
+
default_factory=PortableMaterializedAdaptiveSemanticView,
|
|
405
|
+
repr=False,
|
|
406
|
+
compare=False,
|
|
407
|
+
)
|
|
408
|
+
projector_id: str = PORTABLE_ADAPTIVE_MARKET_PROJECTOR_ID
|
|
409
|
+
projector_version: int = PORTABLE_ADAPTIVE_MARKET_PROJECTOR_VERSION
|
|
410
|
+
definition_sha256: str = (
|
|
411
|
+
PORTABLE_ADAPTIVE_MARKET_PROJECTOR_DEFINITION_SHA256
|
|
412
|
+
)
|
|
413
|
+
state_sha256: str = field(init=False)
|
|
414
|
+
|
|
415
|
+
def __post_init__(self) -> None:
|
|
416
|
+
ids = _candidate_id_tuple(self.current_run_parent_ids)
|
|
417
|
+
if self.projector_id != PORTABLE_ADAPTIVE_MARKET_PROJECTOR_ID:
|
|
418
|
+
raise ValueError("projector_id is immutable")
|
|
419
|
+
if (
|
|
420
|
+
self.projector_version
|
|
421
|
+
!= PORTABLE_ADAPTIVE_MARKET_PROJECTOR_VERSION
|
|
422
|
+
):
|
|
423
|
+
raise ValueError("projector_version is immutable")
|
|
424
|
+
if (
|
|
425
|
+
self.definition_sha256
|
|
426
|
+
!= PORTABLE_ADAPTIVE_MARKET_PROJECTOR_DEFINITION_SHA256
|
|
427
|
+
):
|
|
428
|
+
raise ValueError("projector definition is immutable")
|
|
429
|
+
if not isinstance(
|
|
430
|
+
self.semantic_view,
|
|
431
|
+
AdaptiveActionSemanticViewPort,
|
|
432
|
+
):
|
|
433
|
+
raise TypeError("semantic_view must implement its port")
|
|
434
|
+
_require_token(
|
|
435
|
+
self.semantic_view.projection_id,
|
|
436
|
+
name="semantic projection_id",
|
|
437
|
+
)
|
|
438
|
+
if (
|
|
439
|
+
type(self.semantic_view.projection_version) is not int
|
|
440
|
+
or self.semantic_view.projection_version <= 0
|
|
441
|
+
):
|
|
442
|
+
raise ValueError("semantic projection_version must be positive")
|
|
443
|
+
require_sha256(
|
|
444
|
+
self.semantic_view.definition_sha256,
|
|
445
|
+
"semantic view definition",
|
|
446
|
+
)
|
|
447
|
+
object.__setattr__(
|
|
448
|
+
self,
|
|
449
|
+
"state_sha256",
|
|
450
|
+
_hash(
|
|
451
|
+
_MARKET_STATE_DOMAIN,
|
|
452
|
+
{
|
|
453
|
+
"schema_version": 1,
|
|
454
|
+
"current_run_parent_ids": list(ids),
|
|
455
|
+
"semantic_view_definition_sha256": (
|
|
456
|
+
self.semantic_view.definition_sha256
|
|
457
|
+
),
|
|
458
|
+
},
|
|
459
|
+
),
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
async def project(
|
|
463
|
+
self,
|
|
464
|
+
request: ResidualPortfolioDecisionRequest,
|
|
465
|
+
proposals: tuple[MaterializedActionProposalBatch, ...],
|
|
466
|
+
actions: tuple[MaterializedActionDescriptor, ...],
|
|
467
|
+
scores: tuple[BrokerActionScore, ...],
|
|
468
|
+
required_action_sha256s: tuple[str, ...],
|
|
469
|
+
) -> tuple[AdaptiveActionDescriptor, ...]:
|
|
470
|
+
del request, proposals
|
|
471
|
+
self.__post_init__()
|
|
472
|
+
if type(actions) is not tuple or not actions:
|
|
473
|
+
raise ValueError("actions must be a non-empty exact tuple")
|
|
474
|
+
action_by_sha: dict[str, MaterializedActionDescriptor] = {}
|
|
475
|
+
for action in actions:
|
|
476
|
+
if type(action) is not MaterializedActionDescriptor:
|
|
477
|
+
raise TypeError("actions must contain exact descriptors")
|
|
478
|
+
action.__post_init__()
|
|
479
|
+
if action.action_sha256 in action_by_sha:
|
|
480
|
+
raise ValueError("actions repeat an identity")
|
|
481
|
+
action_by_sha[action.action_sha256] = action
|
|
482
|
+
if (
|
|
483
|
+
type(scores) is not tuple
|
|
484
|
+
or any(type(value) is not BrokerActionScore for value in scores)
|
|
485
|
+
):
|
|
486
|
+
raise TypeError("scores must contain exact broker scores")
|
|
487
|
+
score_by_action = {value.action_sha256: value for value in scores}
|
|
488
|
+
for value in scores:
|
|
489
|
+
value.__post_init__()
|
|
490
|
+
if set(score_by_action) != set(action_by_sha):
|
|
491
|
+
raise ValueError("broker scores do not exactly cover actions")
|
|
492
|
+
if (
|
|
493
|
+
type(required_action_sha256s) is not tuple
|
|
494
|
+
or required_action_sha256s
|
|
495
|
+
!= tuple(sorted(set(required_action_sha256s)))
|
|
496
|
+
or not set(required_action_sha256s).issubset(action_by_sha)
|
|
497
|
+
):
|
|
498
|
+
raise ValueError(
|
|
499
|
+
"required action hashes must be canonical and in-market"
|
|
500
|
+
)
|
|
501
|
+
return self._project_with_prior(
|
|
502
|
+
actions=actions,
|
|
503
|
+
prior_score_by_action={
|
|
504
|
+
value.action_sha256: value.selection_index
|
|
505
|
+
for value in scores
|
|
506
|
+
},
|
|
507
|
+
required_action_sha256s=required_action_sha256s,
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
def _project_with_prior(
|
|
511
|
+
self,
|
|
512
|
+
*,
|
|
513
|
+
actions: tuple[MaterializedActionDescriptor, ...],
|
|
514
|
+
prior_score_by_action: dict[str, float],
|
|
515
|
+
required_action_sha256s: tuple[str, ...],
|
|
516
|
+
) -> tuple[AdaptiveActionDescriptor, ...]:
|
|
517
|
+
action_by_sha = {
|
|
518
|
+
value.action_sha256: value for value in actions
|
|
519
|
+
}
|
|
520
|
+
if set(prior_score_by_action) != set(action_by_sha):
|
|
521
|
+
raise ValueError("prior scores do not exactly cover actions")
|
|
522
|
+
for value in prior_score_by_action.values():
|
|
523
|
+
if (
|
|
524
|
+
type(value) is not float
|
|
525
|
+
or not math.isfinite(value)
|
|
526
|
+
or not 0.0 <= value <= 1.0
|
|
527
|
+
):
|
|
528
|
+
raise ValueError("prior scores must be finite probabilities")
|
|
529
|
+
required = set(required_action_sha256s)
|
|
530
|
+
by_phenotype: dict[str, list[MaterializedActionDescriptor]] = {}
|
|
531
|
+
for action in actions:
|
|
532
|
+
by_phenotype.setdefault(
|
|
533
|
+
action.phenotype_identity_sha256,
|
|
534
|
+
[],
|
|
535
|
+
).append(action)
|
|
536
|
+
representatives: list[MaterializedActionDescriptor] = []
|
|
537
|
+
for rows in by_phenotype.values():
|
|
538
|
+
required_rows = [
|
|
539
|
+
value
|
|
540
|
+
for value in rows
|
|
541
|
+
if value.action_sha256 in required
|
|
542
|
+
]
|
|
543
|
+
if len(required_rows) > 1:
|
|
544
|
+
raise ValueError(
|
|
545
|
+
"fixed constraints repeat one phenotype"
|
|
546
|
+
)
|
|
547
|
+
representatives.append(
|
|
548
|
+
(
|
|
549
|
+
required_rows[0]
|
|
550
|
+
if required_rows
|
|
551
|
+
else max(
|
|
552
|
+
rows,
|
|
553
|
+
key=lambda value: (
|
|
554
|
+
prior_score_by_action[
|
|
555
|
+
value.action_sha256
|
|
556
|
+
],
|
|
557
|
+
-value.native_rank,
|
|
558
|
+
value.action_sha256,
|
|
559
|
+
),
|
|
560
|
+
)
|
|
561
|
+
)
|
|
562
|
+
)
|
|
563
|
+
if not required.issubset(
|
|
564
|
+
{value.action_sha256 for value in representatives}
|
|
565
|
+
):
|
|
566
|
+
raise ValueError(
|
|
567
|
+
"phenotype projection displaced a fixed constraint"
|
|
568
|
+
)
|
|
569
|
+
by_lane: dict[str, list[MaterializedActionDescriptor]] = {}
|
|
570
|
+
for action in representatives:
|
|
571
|
+
by_lane.setdefault(action.expert_id, []).append(action)
|
|
572
|
+
canonical_rank: dict[str, int] = {}
|
|
573
|
+
for rows in by_lane.values():
|
|
574
|
+
for ordinal, action in enumerate(
|
|
575
|
+
sorted(
|
|
576
|
+
rows,
|
|
577
|
+
key=lambda value: (
|
|
578
|
+
value.native_rank,
|
|
579
|
+
value.action_sha256,
|
|
580
|
+
),
|
|
581
|
+
),
|
|
582
|
+
start=1,
|
|
583
|
+
):
|
|
584
|
+
canonical_rank[action.action_sha256] = ordinal
|
|
585
|
+
current_ids = set(self.current_run_parent_ids)
|
|
586
|
+
result: list[AdaptiveActionDescriptor] = []
|
|
587
|
+
for action in sorted(
|
|
588
|
+
representatives,
|
|
589
|
+
key=lambda value: value.action_sha256,
|
|
590
|
+
):
|
|
591
|
+
semantic = self.semantic_view.view(action)
|
|
592
|
+
if type(semantic) is not AdaptiveActionSemanticView:
|
|
593
|
+
raise TypeError("semantic_view returned a foreign value")
|
|
594
|
+
semantic.__post_init__()
|
|
595
|
+
generated_parent = any(
|
|
596
|
+
value in current_ids for value in action.parent_ids
|
|
597
|
+
)
|
|
598
|
+
result.append(
|
|
599
|
+
AdaptiveActionDescriptor(
|
|
600
|
+
action_sha256=action.action_sha256,
|
|
601
|
+
phenotype_sha256=action.phenotype_identity_sha256,
|
|
602
|
+
lane_id=action.expert_id,
|
|
603
|
+
operator_id=semantic.operator_id,
|
|
604
|
+
native_rank=canonical_rank[action.action_sha256],
|
|
605
|
+
lane_size=len(by_lane[action.expert_id]),
|
|
606
|
+
prior_score=float(
|
|
607
|
+
prior_score_by_action[action.action_sha256]
|
|
608
|
+
),
|
|
609
|
+
parent_generated_in_current_run=generated_parent,
|
|
610
|
+
semantic_cell_ids=tuple(
|
|
611
|
+
sorted(
|
|
612
|
+
{
|
|
613
|
+
*semantic.semantic_cell_ids,
|
|
614
|
+
(
|
|
615
|
+
"parent:generated"
|
|
616
|
+
if generated_parent
|
|
617
|
+
else "parent:archive"
|
|
618
|
+
),
|
|
619
|
+
}
|
|
620
|
+
)
|
|
621
|
+
),
|
|
622
|
+
)
|
|
623
|
+
)
|
|
624
|
+
return tuple(result)
|
|
625
|
+
|
|
626
|
+
|
|
627
|
+
@dataclass(frozen=True, slots=True)
|
|
628
|
+
class ScoreEnsembleMaterializedAdaptiveMarketProjector:
|
|
629
|
+
"""Combine opaque pre-evaluation authorities by within-market rank."""
|
|
630
|
+
|
|
631
|
+
scorers: tuple[MaterializedActionScorePort, ...] = field(
|
|
632
|
+
repr=False,
|
|
633
|
+
compare=False,
|
|
634
|
+
)
|
|
635
|
+
scorer_weights: tuple[tuple[str, float], ...]
|
|
636
|
+
current_run_parent_ids: tuple[CandidateId, ...] = ()
|
|
637
|
+
semantic_view: AdaptiveActionSemanticViewPort = field(
|
|
638
|
+
default_factory=PortableMaterializedAdaptiveSemanticView,
|
|
639
|
+
repr=False,
|
|
640
|
+
compare=False,
|
|
641
|
+
)
|
|
642
|
+
projector_id: str = (
|
|
643
|
+
"score_ensemble_materialized_adaptive_market_projector"
|
|
644
|
+
)
|
|
645
|
+
projector_version: int = 1
|
|
646
|
+
definition_sha256: str = field(init=False)
|
|
647
|
+
state_sha256: str = field(init=False)
|
|
648
|
+
|
|
649
|
+
def __post_init__(self) -> None:
|
|
650
|
+
ids = _candidate_id_tuple(self.current_run_parent_ids)
|
|
651
|
+
if type(self.scorers) is not tuple or not self.scorers:
|
|
652
|
+
raise ValueError("scorers must be a non-empty exact tuple")
|
|
653
|
+
identities: list[tuple[str, int, str]] = []
|
|
654
|
+
for scorer in self.scorers:
|
|
655
|
+
if not isinstance(scorer, MaterializedActionScorePort):
|
|
656
|
+
raise TypeError("scorer must implement its port")
|
|
657
|
+
scorer_id = getattr(scorer, "scorer_id", None)
|
|
658
|
+
scorer_version = getattr(scorer, "scorer_version", None)
|
|
659
|
+
definition_sha256 = getattr(
|
|
660
|
+
scorer,
|
|
661
|
+
"definition_sha256",
|
|
662
|
+
None,
|
|
663
|
+
)
|
|
664
|
+
_require_token(scorer_id, name="scorer_id")
|
|
665
|
+
if type(scorer_version) is not int or scorer_version <= 0:
|
|
666
|
+
raise ValueError("scorer_version must be positive")
|
|
667
|
+
require_sha256(
|
|
668
|
+
definition_sha256,
|
|
669
|
+
"scorer definition_sha256",
|
|
670
|
+
)
|
|
671
|
+
identities.append(
|
|
672
|
+
(scorer_id, scorer_version, definition_sha256)
|
|
673
|
+
)
|
|
674
|
+
scorer_ids = tuple(value[0] for value in identities)
|
|
675
|
+
if scorer_ids != tuple(sorted(set(scorer_ids))):
|
|
676
|
+
raise ValueError("scorers must be unique and ID-canonical")
|
|
677
|
+
if (
|
|
678
|
+
type(self.scorer_weights) is not tuple
|
|
679
|
+
or tuple(value[0] for value in self.scorer_weights)
|
|
680
|
+
!= scorer_ids
|
|
681
|
+
):
|
|
682
|
+
raise ValueError("scorer_weights must exactly cover scorers")
|
|
683
|
+
total_weight = 0.0
|
|
684
|
+
for scorer_id, weight in self.scorer_weights:
|
|
685
|
+
_require_token(scorer_id, name="weight scorer_id")
|
|
686
|
+
if (
|
|
687
|
+
type(weight) is not float
|
|
688
|
+
or not math.isfinite(weight)
|
|
689
|
+
or weight <= 0.0
|
|
690
|
+
):
|
|
691
|
+
raise ValueError("scorer weights must be positive")
|
|
692
|
+
total_weight += weight
|
|
693
|
+
if not isinstance(
|
|
694
|
+
self.semantic_view,
|
|
695
|
+
AdaptiveActionSemanticViewPort,
|
|
696
|
+
):
|
|
697
|
+
raise TypeError("semantic_view must implement its port")
|
|
698
|
+
require_sha256(
|
|
699
|
+
self.semantic_view.definition_sha256,
|
|
700
|
+
"semantic view definition",
|
|
701
|
+
)
|
|
702
|
+
_require_token(self.projector_id, name="projector_id")
|
|
703
|
+
if type(self.projector_version) is not int or self.projector_version <= 0:
|
|
704
|
+
raise ValueError("projector_version must be positive")
|
|
705
|
+
object.__setattr__(
|
|
706
|
+
self,
|
|
707
|
+
"definition_sha256",
|
|
708
|
+
_hash(
|
|
709
|
+
_SCORE_ENSEMBLE_PROJECTOR_DEFINITION_DOMAIN,
|
|
710
|
+
{
|
|
711
|
+
"schema_version": 1,
|
|
712
|
+
"projector_id": self.projector_id,
|
|
713
|
+
"projector_version": self.projector_version,
|
|
714
|
+
"scorers": [
|
|
715
|
+
{
|
|
716
|
+
"scorer_id": scorer_id,
|
|
717
|
+
"scorer_version": scorer_version,
|
|
718
|
+
"definition_sha256": definition_sha256,
|
|
719
|
+
"weight_hex": dict(
|
|
720
|
+
self.scorer_weights
|
|
721
|
+
)[scorer_id].hex(),
|
|
722
|
+
}
|
|
723
|
+
for scorer_id, scorer_version, definition_sha256
|
|
724
|
+
in identities
|
|
725
|
+
],
|
|
726
|
+
"normalization": (
|
|
727
|
+
"within-sealed-market-rank-percentile"
|
|
728
|
+
),
|
|
729
|
+
"aggregation": "normalized-positive-weighted-mean",
|
|
730
|
+
"semantic_view_definition_sha256": (
|
|
731
|
+
self.semantic_view.definition_sha256
|
|
732
|
+
),
|
|
733
|
+
"candidate_outcomes_observed": False,
|
|
734
|
+
"workload_model_provider_prompt_config_branches": False,
|
|
735
|
+
},
|
|
736
|
+
),
|
|
737
|
+
)
|
|
738
|
+
object.__setattr__(
|
|
739
|
+
self,
|
|
740
|
+
"state_sha256",
|
|
741
|
+
_hash(
|
|
742
|
+
_MARKET_STATE_DOMAIN,
|
|
743
|
+
{
|
|
744
|
+
"schema_version": 1,
|
|
745
|
+
"projector_definition_sha256": (
|
|
746
|
+
self.definition_sha256
|
|
747
|
+
),
|
|
748
|
+
"current_run_parent_ids": list(ids),
|
|
749
|
+
},
|
|
750
|
+
),
|
|
751
|
+
)
|
|
752
|
+
|
|
753
|
+
@staticmethod
|
|
754
|
+
def _rank_percentiles(
|
|
755
|
+
actions: tuple[MaterializedActionDescriptor, ...],
|
|
756
|
+
values: dict[str, float],
|
|
757
|
+
) -> dict[str, float]:
|
|
758
|
+
ordered = sorted(
|
|
759
|
+
actions,
|
|
760
|
+
key=lambda action: (
|
|
761
|
+
values[action.action_sha256],
|
|
762
|
+
-action.native_rank,
|
|
763
|
+
action.action_sha256,
|
|
764
|
+
),
|
|
765
|
+
)
|
|
766
|
+
if len(ordered) == 1:
|
|
767
|
+
return {ordered[0].action_sha256: 1.0}
|
|
768
|
+
return {
|
|
769
|
+
action.action_sha256: index / (len(ordered) - 1)
|
|
770
|
+
for index, action in enumerate(ordered)
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
async def project(
|
|
774
|
+
self,
|
|
775
|
+
request: ResidualPortfolioDecisionRequest,
|
|
776
|
+
proposals: tuple[MaterializedActionProposalBatch, ...],
|
|
777
|
+
actions: tuple[MaterializedActionDescriptor, ...],
|
|
778
|
+
scores: tuple[BrokerActionScore, ...],
|
|
779
|
+
required_action_sha256s: tuple[str, ...],
|
|
780
|
+
) -> tuple[AdaptiveActionDescriptor, ...]:
|
|
781
|
+
del scores
|
|
782
|
+
self.__post_init__()
|
|
783
|
+
raw = await asyncio.gather(
|
|
784
|
+
*(
|
|
785
|
+
scorer.score(request, proposals)
|
|
786
|
+
for scorer in self.scorers
|
|
787
|
+
)
|
|
788
|
+
)
|
|
789
|
+
batches = tuple(raw)
|
|
790
|
+
proposal_sha256s = tuple(
|
|
791
|
+
sorted(value.proposal_sha256 for value in proposals)
|
|
792
|
+
)
|
|
793
|
+
action_sha256s = {
|
|
794
|
+
value.action_sha256 for value in actions
|
|
795
|
+
}
|
|
796
|
+
percentiles: dict[str, dict[str, float]] = {}
|
|
797
|
+
for scorer, batch in zip(
|
|
798
|
+
self.scorers,
|
|
799
|
+
batches,
|
|
800
|
+
strict=True,
|
|
801
|
+
):
|
|
802
|
+
if type(batch) is not MaterializedActionScoreBatch:
|
|
803
|
+
raise TypeError("scorer returned a foreign batch")
|
|
804
|
+
batch.__post_init__()
|
|
805
|
+
if (
|
|
806
|
+
batch.scorer_id != scorer.scorer_id
|
|
807
|
+
or batch.scorer_version != scorer.scorer_version
|
|
808
|
+
or batch.scorer_definition_sha256
|
|
809
|
+
!= scorer.definition_sha256
|
|
810
|
+
or batch.residual_request_sha256
|
|
811
|
+
!= request.request_sha256
|
|
812
|
+
or batch.proposal_sha256s != proposal_sha256s
|
|
813
|
+
):
|
|
814
|
+
raise ValueError("score batch differs from its authority")
|
|
815
|
+
values = {
|
|
816
|
+
value.action_sha256: value.value
|
|
817
|
+
for value in batch.scores
|
|
818
|
+
}
|
|
819
|
+
if set(values) != action_sha256s:
|
|
820
|
+
raise ValueError("score batch does not cover the market")
|
|
821
|
+
percentiles[batch.scorer_id] = self._rank_percentiles(
|
|
822
|
+
actions,
|
|
823
|
+
values,
|
|
824
|
+
)
|
|
825
|
+
weights = dict(self.scorer_weights)
|
|
826
|
+
total_weight = math.fsum(weights.values())
|
|
827
|
+
combined = {
|
|
828
|
+
action.action_sha256: float(
|
|
829
|
+
math.fsum(
|
|
830
|
+
weights[scorer_id]
|
|
831
|
+
* percentiles[scorer_id][
|
|
832
|
+
action.action_sha256
|
|
833
|
+
]
|
|
834
|
+
for scorer_id in weights
|
|
835
|
+
)
|
|
836
|
+
/ total_weight
|
|
837
|
+
)
|
|
838
|
+
for action in actions
|
|
839
|
+
}
|
|
840
|
+
base = PortableMaterializedAdaptiveMarketProjector(
|
|
841
|
+
current_run_parent_ids=self.current_run_parent_ids,
|
|
842
|
+
semantic_view=self.semantic_view,
|
|
843
|
+
)
|
|
844
|
+
return base._project_with_prior(
|
|
845
|
+
actions=actions,
|
|
846
|
+
prior_score_by_action=combined,
|
|
847
|
+
required_action_sha256s=required_action_sha256s,
|
|
848
|
+
)
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
@dataclass(frozen=True, slots=True)
|
|
852
|
+
class FactorStratifiedAdaptiveMarketProjector:
|
|
853
|
+
"""Add opaque branch/role/rank factor cells to any market projector.
|
|
854
|
+
|
|
855
|
+
The wrapper is an integration-layer adapter. It never parses expert IDs,
|
|
856
|
+
model names, prompts, configurations, objectives, or outcomes. A
|
|
857
|
+
composition root explicitly binds each proposal expert to an opaque source
|
|
858
|
+
branch; the remaining factors are framework-native action role and
|
|
859
|
+
materialized within-lane rank quantile.
|
|
860
|
+
"""
|
|
861
|
+
|
|
862
|
+
delegate: AdaptiveActionMarketProjectorPort = field(
|
|
863
|
+
repr=False,
|
|
864
|
+
compare=False,
|
|
865
|
+
)
|
|
866
|
+
source_branch_by_expert: tuple[tuple[str, str], ...]
|
|
867
|
+
rank_layer_count: int = 3
|
|
868
|
+
projector_id: str = "factor_stratified_adaptive_market_projector"
|
|
869
|
+
projector_version: int = 1
|
|
870
|
+
definition_sha256: str = field(init=False)
|
|
871
|
+
state_sha256: str = field(init=False)
|
|
872
|
+
|
|
873
|
+
def __post_init__(self) -> None:
|
|
874
|
+
if not isinstance(self.delegate, AdaptiveActionMarketProjectorPort):
|
|
875
|
+
raise TypeError("delegate must implement the adaptive market port")
|
|
876
|
+
_require_token(self.delegate.projector_id, name="delegate projector_id")
|
|
877
|
+
if (
|
|
878
|
+
type(self.delegate.projector_version) is not int
|
|
879
|
+
or self.delegate.projector_version <= 0
|
|
880
|
+
):
|
|
881
|
+
raise ValueError("delegate projector_version must be positive")
|
|
882
|
+
require_sha256(
|
|
883
|
+
self.delegate.definition_sha256,
|
|
884
|
+
"delegate definition_sha256",
|
|
885
|
+
)
|
|
886
|
+
require_sha256(self.delegate.state_sha256, "delegate state_sha256")
|
|
887
|
+
if (
|
|
888
|
+
type(self.source_branch_by_expert) is not tuple
|
|
889
|
+
or not self.source_branch_by_expert
|
|
890
|
+
or self.source_branch_by_expert
|
|
891
|
+
!= tuple(sorted(self.source_branch_by_expert))
|
|
892
|
+
):
|
|
893
|
+
raise ValueError(
|
|
894
|
+
"source_branch_by_expert must be non-empty and canonical"
|
|
895
|
+
)
|
|
896
|
+
experts: list[str] = []
|
|
897
|
+
for value in self.source_branch_by_expert:
|
|
898
|
+
if type(value) is not tuple or len(value) != 2:
|
|
899
|
+
raise TypeError(
|
|
900
|
+
"source_branch_by_expert must contain exact pairs"
|
|
901
|
+
)
|
|
902
|
+
expert_id, branch_id = value
|
|
903
|
+
_require_token(expert_id, name="source expert_id")
|
|
904
|
+
_require_token(branch_id, name="source branch_id")
|
|
905
|
+
experts.append(expert_id)
|
|
906
|
+
if len(experts) != len(set(experts)):
|
|
907
|
+
raise ValueError("source_branch_by_expert repeats an expert")
|
|
908
|
+
if (
|
|
909
|
+
type(self.rank_layer_count) is not int
|
|
910
|
+
or self.rank_layer_count < 2
|
|
911
|
+
or self.rank_layer_count > 16
|
|
912
|
+
):
|
|
913
|
+
raise ValueError("rank_layer_count must be an integer in [2, 16]")
|
|
914
|
+
_require_token(self.projector_id, name="projector_id")
|
|
915
|
+
if self.projector_version != 1:
|
|
916
|
+
raise ValueError("projector_version is immutable")
|
|
917
|
+
object.__setattr__(
|
|
918
|
+
self,
|
|
919
|
+
"definition_sha256",
|
|
920
|
+
_hash(
|
|
921
|
+
_FACTOR_STRATIFIED_PROJECTOR_DEFINITION_DOMAIN,
|
|
922
|
+
{
|
|
923
|
+
"schema_version": 1,
|
|
924
|
+
"projector_id": self.projector_id,
|
|
925
|
+
"projector_version": self.projector_version,
|
|
926
|
+
"delegate_definition_sha256": (
|
|
927
|
+
self.delegate.definition_sha256
|
|
928
|
+
),
|
|
929
|
+
"rank_layer_count": self.rank_layer_count,
|
|
930
|
+
"factor_families": [
|
|
931
|
+
"evolutionary_role",
|
|
932
|
+
"materialized_rank_layer",
|
|
933
|
+
"source_branch",
|
|
934
|
+
"source_branch_role",
|
|
935
|
+
],
|
|
936
|
+
"source_branch_semantics": (
|
|
937
|
+
"opaque_explicit_composition_root_binding"
|
|
938
|
+
),
|
|
939
|
+
"candidate_outcomes_observed": False,
|
|
940
|
+
"workload_objective_model_provider_prompt_config": False,
|
|
941
|
+
},
|
|
942
|
+
),
|
|
943
|
+
)
|
|
944
|
+
object.__setattr__(
|
|
945
|
+
self,
|
|
946
|
+
"state_sha256",
|
|
947
|
+
_hash(
|
|
948
|
+
_MARKET_STATE_DOMAIN,
|
|
949
|
+
{
|
|
950
|
+
"schema_version": 2,
|
|
951
|
+
"projector_definition_sha256": self.definition_sha256,
|
|
952
|
+
"delegate_state_sha256": self.delegate.state_sha256,
|
|
953
|
+
"source_branch_by_expert": [
|
|
954
|
+
{
|
|
955
|
+
"expert_id": expert_id,
|
|
956
|
+
"source_branch_id": branch_id,
|
|
957
|
+
}
|
|
958
|
+
for expert_id, branch_id in (
|
|
959
|
+
self.source_branch_by_expert
|
|
960
|
+
)
|
|
961
|
+
],
|
|
962
|
+
},
|
|
963
|
+
),
|
|
964
|
+
)
|
|
965
|
+
|
|
966
|
+
async def project(
|
|
967
|
+
self,
|
|
968
|
+
request: ResidualPortfolioDecisionRequest,
|
|
969
|
+
proposals: tuple[MaterializedActionProposalBatch, ...],
|
|
970
|
+
actions: tuple[MaterializedActionDescriptor, ...],
|
|
971
|
+
scores: tuple[BrokerActionScore, ...],
|
|
972
|
+
required_action_sha256s: tuple[str, ...],
|
|
973
|
+
) -> tuple[AdaptiveActionDescriptor, ...]:
|
|
974
|
+
self.__post_init__()
|
|
975
|
+
projected = await self.delegate.project(
|
|
976
|
+
request,
|
|
977
|
+
proposals,
|
|
978
|
+
actions,
|
|
979
|
+
scores,
|
|
980
|
+
required_action_sha256s,
|
|
981
|
+
)
|
|
982
|
+
action_by_sha = {
|
|
983
|
+
value.action_sha256: value for value in actions
|
|
984
|
+
}
|
|
985
|
+
if len(action_by_sha) != len(actions):
|
|
986
|
+
raise ValueError("materialized actions repeat an identity")
|
|
987
|
+
branch_by_expert = dict(self.source_branch_by_expert)
|
|
988
|
+
observed_experts = {value.lane_id for value in projected}
|
|
989
|
+
if not observed_experts.issubset(branch_by_expert):
|
|
990
|
+
raise ValueError(
|
|
991
|
+
"source branch binding must cover every projected expert"
|
|
992
|
+
)
|
|
993
|
+
result = []
|
|
994
|
+
for value in projected:
|
|
995
|
+
raw = action_by_sha.get(value.action_sha256)
|
|
996
|
+
if raw is None:
|
|
997
|
+
raise ValueError("projected action is absent materialized input")
|
|
998
|
+
branch_id = branch_by_expert[value.lane_id]
|
|
999
|
+
role_id = raw.role_id
|
|
1000
|
+
layer = min(
|
|
1001
|
+
self.rank_layer_count - 1,
|
|
1002
|
+
(
|
|
1003
|
+
(value.native_rank - 1) * self.rank_layer_count
|
|
1004
|
+
)
|
|
1005
|
+
// value.lane_size,
|
|
1006
|
+
)
|
|
1007
|
+
added = (
|
|
1008
|
+
AdaptiveActionFactorCell(
|
|
1009
|
+
family_id="evolutionary_role",
|
|
1010
|
+
level_id=role_id,
|
|
1011
|
+
),
|
|
1012
|
+
AdaptiveActionFactorCell(
|
|
1013
|
+
family_id="materialized_rank_layer",
|
|
1014
|
+
level_id=f"layer{layer}",
|
|
1015
|
+
),
|
|
1016
|
+
AdaptiveActionFactorCell(
|
|
1017
|
+
family_id="source_branch",
|
|
1018
|
+
level_id=branch_id,
|
|
1019
|
+
),
|
|
1020
|
+
AdaptiveActionFactorCell(
|
|
1021
|
+
family_id="source_branch_role",
|
|
1022
|
+
level_id=(
|
|
1023
|
+
"cell:"
|
|
1024
|
+
+ _hash(
|
|
1025
|
+
_FACTOR_STRATIFIED_PROJECTOR_DEFINITION_DOMAIN,
|
|
1026
|
+
{
|
|
1027
|
+
"source_branch_id": branch_id,
|
|
1028
|
+
"evolutionary_role_id": role_id,
|
|
1029
|
+
},
|
|
1030
|
+
)
|
|
1031
|
+
),
|
|
1032
|
+
),
|
|
1033
|
+
)
|
|
1034
|
+
combined = tuple(sorted((*value.factor_cells, *added)))
|
|
1035
|
+
if len({cell.family_id for cell in combined}) != len(combined):
|
|
1036
|
+
raise ValueError(
|
|
1037
|
+
"delegate and stratifier repeat a factor family"
|
|
1038
|
+
)
|
|
1039
|
+
result.append(
|
|
1040
|
+
AdaptiveActionDescriptor(
|
|
1041
|
+
action_sha256=value.action_sha256,
|
|
1042
|
+
phenotype_sha256=value.phenotype_sha256,
|
|
1043
|
+
lane_id=value.lane_id,
|
|
1044
|
+
operator_id=value.operator_id,
|
|
1045
|
+
native_rank=value.native_rank,
|
|
1046
|
+
lane_size=value.lane_size,
|
|
1047
|
+
prior_score=value.prior_score,
|
|
1048
|
+
parent_generated_in_current_run=(
|
|
1049
|
+
value.parent_generated_in_current_run
|
|
1050
|
+
),
|
|
1051
|
+
semantic_cell_ids=value.semantic_cell_ids,
|
|
1052
|
+
factor_cells=combined,
|
|
1053
|
+
)
|
|
1054
|
+
)
|
|
1055
|
+
return tuple(result)
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
@runtime_checkable
|
|
1059
|
+
class AdaptiveActionOutcomeProjectorPort(Protocol):
|
|
1060
|
+
"""Project real candidate evaluations into portable archive gain."""
|
|
1061
|
+
|
|
1062
|
+
projector_id: str
|
|
1063
|
+
projector_version: int
|
|
1064
|
+
definition_sha256: str
|
|
1065
|
+
|
|
1066
|
+
def project(
|
|
1067
|
+
self,
|
|
1068
|
+
evaluations: tuple[MaterializedActionEvaluation, ...],
|
|
1069
|
+
) -> tuple[AdaptiveActionOutcome, ...]: ...
|
|
1070
|
+
|
|
1071
|
+
def joint_gain(
|
|
1072
|
+
self,
|
|
1073
|
+
evaluations: tuple[MaterializedActionEvaluation, ...],
|
|
1074
|
+
) -> float: ...
|
|
1075
|
+
|
|
1076
|
+
def project_set_outcome(
|
|
1077
|
+
self,
|
|
1078
|
+
prior_evaluations: tuple[MaterializedActionEvaluation, ...],
|
|
1079
|
+
evaluations: tuple[MaterializedActionEvaluation, ...],
|
|
1080
|
+
) -> AdaptiveActionSetOutcome: ...
|
|
1081
|
+
|
|
1082
|
+
|
|
1083
|
+
@dataclass(frozen=True, slots=True)
|
|
1084
|
+
class CandidateArchiveAdaptiveActionOutcomeProjector:
|
|
1085
|
+
"""Use an injected workload utility without exposing objective semantics."""
|
|
1086
|
+
|
|
1087
|
+
prior_candidates: tuple[EvolutionCandidate, ...]
|
|
1088
|
+
utility: CandidateArchivePortfolioConsequenceUtilityPort = field(
|
|
1089
|
+
repr=False,
|
|
1090
|
+
compare=False,
|
|
1091
|
+
)
|
|
1092
|
+
projector_id: str = CANDIDATE_ARCHIVE_ADAPTIVE_OUTCOME_PROJECTOR_ID
|
|
1093
|
+
projector_version: int = (
|
|
1094
|
+
CANDIDATE_ARCHIVE_ADAPTIVE_OUTCOME_PROJECTOR_VERSION
|
|
1095
|
+
)
|
|
1096
|
+
definition_sha256: str = field(init=False)
|
|
1097
|
+
|
|
1098
|
+
def __post_init__(self) -> None:
|
|
1099
|
+
if (
|
|
1100
|
+
type(self.prior_candidates) is not tuple
|
|
1101
|
+
or any(
|
|
1102
|
+
type(value) is not EvolutionCandidate
|
|
1103
|
+
for value in self.prior_candidates
|
|
1104
|
+
)
|
|
1105
|
+
):
|
|
1106
|
+
raise TypeError("prior_candidates must be an exact tuple")
|
|
1107
|
+
for value in self.prior_candidates:
|
|
1108
|
+
value.__post_init__()
|
|
1109
|
+
utility_identity = (
|
|
1110
|
+
validate_candidate_archive_portfolio_consequence_utility(
|
|
1111
|
+
self.utility
|
|
1112
|
+
)
|
|
1113
|
+
)
|
|
1114
|
+
if (
|
|
1115
|
+
self.projector_id
|
|
1116
|
+
!= CANDIDATE_ARCHIVE_ADAPTIVE_OUTCOME_PROJECTOR_ID
|
|
1117
|
+
):
|
|
1118
|
+
raise ValueError("projector_id is immutable")
|
|
1119
|
+
if (
|
|
1120
|
+
self.projector_version
|
|
1121
|
+
!= CANDIDATE_ARCHIVE_ADAPTIVE_OUTCOME_PROJECTOR_VERSION
|
|
1122
|
+
):
|
|
1123
|
+
raise ValueError("projector_version is immutable")
|
|
1124
|
+
object.__setattr__(
|
|
1125
|
+
self,
|
|
1126
|
+
"definition_sha256",
|
|
1127
|
+
_hash(
|
|
1128
|
+
_OUTCOME_PROJECTOR_DEFINITION_DOMAIN,
|
|
1129
|
+
{
|
|
1130
|
+
"schema_version": 1,
|
|
1131
|
+
"projector_id": self.projector_id,
|
|
1132
|
+
"projector_version": self.projector_version,
|
|
1133
|
+
"utility": {
|
|
1134
|
+
"utility_id": utility_identity[0],
|
|
1135
|
+
"utility_version": utility_identity[1],
|
|
1136
|
+
"definition_sha256": utility_identity[2],
|
|
1137
|
+
},
|
|
1138
|
+
"prior_candidate_ids": [
|
|
1139
|
+
value.candidate_id.value
|
|
1140
|
+
for value in self.prior_candidates
|
|
1141
|
+
],
|
|
1142
|
+
"admission": (
|
|
1143
|
+
"valid_and_operator_and_evidence_compliant"
|
|
1144
|
+
),
|
|
1145
|
+
"currency": (
|
|
1146
|
+
"individual_fixed_joint_and_conditioned_set_utility"
|
|
1147
|
+
),
|
|
1148
|
+
"set_observation_policy_role": "observational_only",
|
|
1149
|
+
},
|
|
1150
|
+
),
|
|
1151
|
+
)
|
|
1152
|
+
|
|
1153
|
+
@staticmethod
|
|
1154
|
+
def _validate_evaluations(
|
|
1155
|
+
evaluations: tuple[MaterializedActionEvaluation, ...],
|
|
1156
|
+
*,
|
|
1157
|
+
allow_empty: bool = False,
|
|
1158
|
+
) -> None:
|
|
1159
|
+
if (
|
|
1160
|
+
type(evaluations) is not tuple
|
|
1161
|
+
or (not allow_empty and not evaluations)
|
|
1162
|
+
or any(
|
|
1163
|
+
type(value) is not MaterializedActionEvaluation
|
|
1164
|
+
for value in evaluations
|
|
1165
|
+
)
|
|
1166
|
+
):
|
|
1167
|
+
raise ValueError("evaluations must be a non-empty exact tuple")
|
|
1168
|
+
action_ids: list[str] = []
|
|
1169
|
+
for value in evaluations:
|
|
1170
|
+
value.__post_init__()
|
|
1171
|
+
action_ids.append(value.action.action_sha256)
|
|
1172
|
+
if len(action_ids) != len(set(action_ids)):
|
|
1173
|
+
raise ValueError("evaluations repeat an action")
|
|
1174
|
+
|
|
1175
|
+
@staticmethod
|
|
1176
|
+
def _feasible(evaluation: MaterializedActionEvaluation) -> bool:
|
|
1177
|
+
candidate = evaluation.candidate
|
|
1178
|
+
return bool(
|
|
1179
|
+
candidate.valid
|
|
1180
|
+
and candidate.operator_compliant
|
|
1181
|
+
and candidate.evidence_compliant
|
|
1182
|
+
)
|
|
1183
|
+
|
|
1184
|
+
@staticmethod
|
|
1185
|
+
def _bindings(
|
|
1186
|
+
evaluations: tuple[MaterializedActionEvaluation, ...],
|
|
1187
|
+
) -> tuple[tuple[str, str], ...]:
|
|
1188
|
+
return tuple(
|
|
1189
|
+
sorted(
|
|
1190
|
+
(
|
|
1191
|
+
value.action.action_sha256,
|
|
1192
|
+
value.evaluation_sha256,
|
|
1193
|
+
)
|
|
1194
|
+
for value in evaluations
|
|
1195
|
+
)
|
|
1196
|
+
)
|
|
1197
|
+
|
|
1198
|
+
def _portfolio_gain(
|
|
1199
|
+
self,
|
|
1200
|
+
evaluations: tuple[MaterializedActionEvaluation, ...],
|
|
1201
|
+
) -> float:
|
|
1202
|
+
self._validate_evaluations(evaluations, allow_empty=True)
|
|
1203
|
+
points = tuple(
|
|
1204
|
+
value.candidate.objective_map
|
|
1205
|
+
for value in sorted(
|
|
1206
|
+
evaluations,
|
|
1207
|
+
key=lambda item: item.action.action_sha256,
|
|
1208
|
+
)
|
|
1209
|
+
if self._feasible(value)
|
|
1210
|
+
)
|
|
1211
|
+
gain = (
|
|
1212
|
+
0.0
|
|
1213
|
+
if not points
|
|
1214
|
+
else self.utility.portfolio_marginal_utility(
|
|
1215
|
+
self.prior_candidates,
|
|
1216
|
+
points,
|
|
1217
|
+
)
|
|
1218
|
+
)
|
|
1219
|
+
if (
|
|
1220
|
+
type(gain) is not float
|
|
1221
|
+
or not math.isfinite(gain)
|
|
1222
|
+
or gain < 0.0
|
|
1223
|
+
):
|
|
1224
|
+
raise ValueError("archive utility returned invalid joint gain")
|
|
1225
|
+
return float(gain)
|
|
1226
|
+
|
|
1227
|
+
def project(
|
|
1228
|
+
self,
|
|
1229
|
+
evaluations: tuple[MaterializedActionEvaluation, ...],
|
|
1230
|
+
) -> tuple[AdaptiveActionOutcome, ...]:
|
|
1231
|
+
self.__post_init__()
|
|
1232
|
+
self._validate_evaluations(evaluations)
|
|
1233
|
+
outcomes: list[AdaptiveActionOutcome] = []
|
|
1234
|
+
for evaluation in sorted(
|
|
1235
|
+
evaluations,
|
|
1236
|
+
key=lambda value: value.action.action_sha256,
|
|
1237
|
+
):
|
|
1238
|
+
feasible = self._feasible(evaluation)
|
|
1239
|
+
gain = (
|
|
1240
|
+
0.0
|
|
1241
|
+
if not feasible
|
|
1242
|
+
else self.utility.marginal_utility(
|
|
1243
|
+
self.prior_candidates,
|
|
1244
|
+
evaluation.candidate.objective_map,
|
|
1245
|
+
)
|
|
1246
|
+
)
|
|
1247
|
+
if (
|
|
1248
|
+
type(gain) is not float
|
|
1249
|
+
or not math.isfinite(gain)
|
|
1250
|
+
or gain < 0.0
|
|
1251
|
+
):
|
|
1252
|
+
raise ValueError(
|
|
1253
|
+
"archive utility returned invalid individual gain"
|
|
1254
|
+
)
|
|
1255
|
+
outcomes.append(
|
|
1256
|
+
AdaptiveActionOutcome(
|
|
1257
|
+
action_sha256=evaluation.action.action_sha256,
|
|
1258
|
+
evaluation_sha256=evaluation.evaluation_sha256,
|
|
1259
|
+
feasible=feasible,
|
|
1260
|
+
marginal_archive_gain=float(gain),
|
|
1261
|
+
)
|
|
1262
|
+
)
|
|
1263
|
+
return tuple(outcomes)
|
|
1264
|
+
|
|
1265
|
+
def joint_gain(
|
|
1266
|
+
self,
|
|
1267
|
+
evaluations: tuple[MaterializedActionEvaluation, ...],
|
|
1268
|
+
) -> float:
|
|
1269
|
+
self.__post_init__()
|
|
1270
|
+
self._validate_evaluations(evaluations)
|
|
1271
|
+
return self._portfolio_gain(evaluations)
|
|
1272
|
+
|
|
1273
|
+
def project_set_outcome(
|
|
1274
|
+
self,
|
|
1275
|
+
prior_evaluations: tuple[MaterializedActionEvaluation, ...],
|
|
1276
|
+
evaluations: tuple[MaterializedActionEvaluation, ...],
|
|
1277
|
+
) -> AdaptiveActionSetOutcome:
|
|
1278
|
+
"""Measure fixed opportunity and causal lift at one wave boundary."""
|
|
1279
|
+
|
|
1280
|
+
self.__post_init__()
|
|
1281
|
+
self._validate_evaluations(
|
|
1282
|
+
prior_evaluations,
|
|
1283
|
+
allow_empty=True,
|
|
1284
|
+
)
|
|
1285
|
+
self._validate_evaluations(evaluations)
|
|
1286
|
+
prior_actions = {
|
|
1287
|
+
value.action.action_sha256 for value in prior_evaluations
|
|
1288
|
+
}
|
|
1289
|
+
current_actions = {
|
|
1290
|
+
value.action.action_sha256 for value in evaluations
|
|
1291
|
+
}
|
|
1292
|
+
if prior_actions & current_actions:
|
|
1293
|
+
raise ValueError(
|
|
1294
|
+
"prior and current evaluations repeat an action"
|
|
1295
|
+
)
|
|
1296
|
+
prior_receipts = {
|
|
1297
|
+
value.evaluation_sha256 for value in prior_evaluations
|
|
1298
|
+
}
|
|
1299
|
+
current_receipts = {
|
|
1300
|
+
value.evaluation_sha256 for value in evaluations
|
|
1301
|
+
}
|
|
1302
|
+
if prior_receipts & current_receipts:
|
|
1303
|
+
raise ValueError(
|
|
1304
|
+
"prior and current evaluations repeat a receipt"
|
|
1305
|
+
)
|
|
1306
|
+
prior_gain = self._portfolio_gain(prior_evaluations)
|
|
1307
|
+
fixed_gain = self._portfolio_gain(evaluations)
|
|
1308
|
+
augmented = self._portfolio_gain(
|
|
1309
|
+
tuple(
|
|
1310
|
+
sorted(
|
|
1311
|
+
(*prior_evaluations, *evaluations),
|
|
1312
|
+
key=lambda value: value.action.action_sha256,
|
|
1313
|
+
)
|
|
1314
|
+
)
|
|
1315
|
+
)
|
|
1316
|
+
conditional = augmented - prior_gain
|
|
1317
|
+
numerical_tolerance = 1e-12 * max(
|
|
1318
|
+
1.0,
|
|
1319
|
+
abs(prior_gain),
|
|
1320
|
+
abs(augmented),
|
|
1321
|
+
)
|
|
1322
|
+
if conditional < -numerical_tolerance:
|
|
1323
|
+
raise ValueError(
|
|
1324
|
+
"archive utility is non-monotone across selected sets"
|
|
1325
|
+
)
|
|
1326
|
+
if conditional < 0.0:
|
|
1327
|
+
conditional = 0.0
|
|
1328
|
+
return AdaptiveActionSetOutcome(
|
|
1329
|
+
prior_action_evaluation_bindings=self._bindings(
|
|
1330
|
+
prior_evaluations
|
|
1331
|
+
),
|
|
1332
|
+
current_action_evaluation_bindings=self._bindings(
|
|
1333
|
+
evaluations
|
|
1334
|
+
),
|
|
1335
|
+
prior_selected_set_gain=float(prior_gain),
|
|
1336
|
+
current_wave_fixed_set_gain=float(fixed_gain),
|
|
1337
|
+
augmented_selected_set_gain=float(augmented),
|
|
1338
|
+
conditional_set_gain=float(conditional),
|
|
1339
|
+
)
|
|
1340
|
+
|
|
1341
|
+
|
|
1342
|
+
class OutcomeAdaptiveResidualPhase(str, Enum):
|
|
1343
|
+
MARKET_FROZEN = "market_frozen"
|
|
1344
|
+
DIAGNOSTIC_EVALUATED = "diagnostic_evaluated"
|
|
1345
|
+
PAIRED_AUDIT_FROZEN = "paired_audit_frozen"
|
|
1346
|
+
ADAPTIVE_STEP_EVALUATED = "adaptive_step_evaluated"
|
|
1347
|
+
FINALIZED = "finalized"
|
|
1348
|
+
|
|
1349
|
+
|
|
1350
|
+
@dataclass(frozen=True, slots=True)
|
|
1351
|
+
class OutcomeAdaptiveResidualPhaseReceipt:
|
|
1352
|
+
"""One causal interception boundary in an adaptive stage."""
|
|
1353
|
+
|
|
1354
|
+
phase: OutcomeAdaptiveResidualPhase
|
|
1355
|
+
phase_ordinal: int
|
|
1356
|
+
residual_request_sha256: str
|
|
1357
|
+
diagnostic_decision_sha256: str
|
|
1358
|
+
product_sha256s: tuple[str, ...]
|
|
1359
|
+
evidence: FrozenJsonObject
|
|
1360
|
+
receipt_sha256: str = field(init=False)
|
|
1361
|
+
|
|
1362
|
+
def __post_init__(self) -> None:
|
|
1363
|
+
if type(self.phase) is not OutcomeAdaptiveResidualPhase:
|
|
1364
|
+
raise TypeError("phase must be exact")
|
|
1365
|
+
if type(self.phase_ordinal) is not int or self.phase_ordinal <= 0:
|
|
1366
|
+
raise ValueError("phase_ordinal must be positive")
|
|
1367
|
+
require_sha256(
|
|
1368
|
+
self.residual_request_sha256,
|
|
1369
|
+
"residual_request_sha256",
|
|
1370
|
+
)
|
|
1371
|
+
require_sha256(
|
|
1372
|
+
self.diagnostic_decision_sha256,
|
|
1373
|
+
"diagnostic_decision_sha256",
|
|
1374
|
+
)
|
|
1375
|
+
if (
|
|
1376
|
+
type(self.product_sha256s) is not tuple
|
|
1377
|
+
or not self.product_sha256s
|
|
1378
|
+
):
|
|
1379
|
+
raise ValueError("product_sha256s must be a non-empty tuple")
|
|
1380
|
+
for value in self.product_sha256s:
|
|
1381
|
+
require_sha256(value, "product_sha256")
|
|
1382
|
+
if (
|
|
1383
|
+
type(self.evidence) is not FrozenJsonObject
|
|
1384
|
+
or freeze_json(self.evidence) is not self.evidence
|
|
1385
|
+
):
|
|
1386
|
+
raise TypeError("phase evidence must be an exact frozen object")
|
|
1387
|
+
object.__setattr__(
|
|
1388
|
+
self,
|
|
1389
|
+
"receipt_sha256",
|
|
1390
|
+
_hash(_PHASE_RECEIPT_DOMAIN, self._unsigned_record()),
|
|
1391
|
+
)
|
|
1392
|
+
|
|
1393
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
1394
|
+
return {
|
|
1395
|
+
"schema_version": 1,
|
|
1396
|
+
"phase": self.phase.value,
|
|
1397
|
+
"phase_ordinal": self.phase_ordinal,
|
|
1398
|
+
"residual_request_sha256": self.residual_request_sha256,
|
|
1399
|
+
"diagnostic_decision_sha256": (
|
|
1400
|
+
self.diagnostic_decision_sha256
|
|
1401
|
+
),
|
|
1402
|
+
"product_sha256s": list(self.product_sha256s),
|
|
1403
|
+
"evidence_sha256": typed_json_sha256(self.evidence),
|
|
1404
|
+
}
|
|
1405
|
+
|
|
1406
|
+
def to_record(self, *, include_evidence: bool = False) -> dict[str, object]:
|
|
1407
|
+
self.__post_init__()
|
|
1408
|
+
record = {
|
|
1409
|
+
**self._unsigned_record(),
|
|
1410
|
+
"receipt_sha256": self.receipt_sha256,
|
|
1411
|
+
}
|
|
1412
|
+
if include_evidence:
|
|
1413
|
+
record["evidence"] = thaw_json(self.evidence)
|
|
1414
|
+
return record
|
|
1415
|
+
|
|
1416
|
+
|
|
1417
|
+
@dataclass(frozen=True, slots=True)
|
|
1418
|
+
class OutcomeAdaptiveResidualPhaseCommitAck:
|
|
1419
|
+
committer_id: str
|
|
1420
|
+
committer_version: int
|
|
1421
|
+
committer_definition_sha256: str
|
|
1422
|
+
phase_receipt_sha256: str
|
|
1423
|
+
durable: bool
|
|
1424
|
+
evidence: FrozenJsonObject
|
|
1425
|
+
ack_sha256: str = field(init=False)
|
|
1426
|
+
|
|
1427
|
+
def __post_init__(self) -> None:
|
|
1428
|
+
_require_token(self.committer_id, name="committer_id")
|
|
1429
|
+
if type(self.committer_version) is not int or self.committer_version <= 0:
|
|
1430
|
+
raise ValueError("committer_version must be positive")
|
|
1431
|
+
require_sha256(
|
|
1432
|
+
self.committer_definition_sha256,
|
|
1433
|
+
"committer_definition_sha256",
|
|
1434
|
+
)
|
|
1435
|
+
require_sha256(
|
|
1436
|
+
self.phase_receipt_sha256,
|
|
1437
|
+
"phase_receipt_sha256",
|
|
1438
|
+
)
|
|
1439
|
+
if type(self.durable) is not bool:
|
|
1440
|
+
raise TypeError("durable must be exact")
|
|
1441
|
+
if (
|
|
1442
|
+
type(self.evidence) is not FrozenJsonObject
|
|
1443
|
+
or freeze_json(self.evidence) is not self.evidence
|
|
1444
|
+
):
|
|
1445
|
+
raise TypeError("commit evidence must be an exact frozen object")
|
|
1446
|
+
object.__setattr__(
|
|
1447
|
+
self,
|
|
1448
|
+
"ack_sha256",
|
|
1449
|
+
_hash(_PHASE_ACK_DOMAIN, self._unsigned_record()),
|
|
1450
|
+
)
|
|
1451
|
+
|
|
1452
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
1453
|
+
return {
|
|
1454
|
+
"schema_version": 1,
|
|
1455
|
+
"committer": {
|
|
1456
|
+
"committer_id": self.committer_id,
|
|
1457
|
+
"committer_version": self.committer_version,
|
|
1458
|
+
"definition_sha256": self.committer_definition_sha256,
|
|
1459
|
+
},
|
|
1460
|
+
"phase_receipt_sha256": self.phase_receipt_sha256,
|
|
1461
|
+
"durable": self.durable,
|
|
1462
|
+
"evidence_sha256": typed_json_sha256(self.evidence),
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
def to_record(self, *, include_evidence: bool = False) -> dict[str, object]:
|
|
1466
|
+
self.__post_init__()
|
|
1467
|
+
record = {**self._unsigned_record(), "ack_sha256": self.ack_sha256}
|
|
1468
|
+
if include_evidence:
|
|
1469
|
+
record["evidence"] = thaw_json(self.evidence)
|
|
1470
|
+
return record
|
|
1471
|
+
|
|
1472
|
+
|
|
1473
|
+
@runtime_checkable
|
|
1474
|
+
class OutcomeAdaptiveResidualPhaseCommitPort(Protocol):
|
|
1475
|
+
committer_id: str
|
|
1476
|
+
committer_version: int
|
|
1477
|
+
definition_sha256: str
|
|
1478
|
+
|
|
1479
|
+
async def commit(
|
|
1480
|
+
self,
|
|
1481
|
+
receipt: OutcomeAdaptiveResidualPhaseReceipt,
|
|
1482
|
+
) -> OutcomeAdaptiveResidualPhaseCommitAck: ...
|
|
1483
|
+
|
|
1484
|
+
|
|
1485
|
+
def _flatten(
|
|
1486
|
+
batches: tuple[MaterializedActionEvaluationBatch, ...],
|
|
1487
|
+
) -> tuple[MaterializedActionEvaluation, ...]:
|
|
1488
|
+
by_action = {
|
|
1489
|
+
value.action.action_sha256: value
|
|
1490
|
+
for batch in batches
|
|
1491
|
+
for value in batch.evaluations
|
|
1492
|
+
}
|
|
1493
|
+
return tuple(by_action[value] for value in sorted(by_action))
|
|
1494
|
+
|
|
1495
|
+
|
|
1496
|
+
def _merge_waves(
|
|
1497
|
+
proposals: tuple[MaterializedActionProposalBatch, ...],
|
|
1498
|
+
waves: tuple[tuple[MaterializedActionEvaluationBatch, ...], ...],
|
|
1499
|
+
) -> tuple[MaterializedActionEvaluationBatch, ...]:
|
|
1500
|
+
proposal_by_expert = {value.expert_id: value for value in proposals}
|
|
1501
|
+
source_by_expert: dict[str, list[MaterializedActionEvaluationBatch]] = {}
|
|
1502
|
+
for wave in waves:
|
|
1503
|
+
for batch in wave:
|
|
1504
|
+
source_by_expert.setdefault(batch.expert_id, []).append(batch)
|
|
1505
|
+
merged: list[MaterializedActionEvaluationBatch] = []
|
|
1506
|
+
for expert_id in sorted(source_by_expert):
|
|
1507
|
+
source = source_by_expert[expert_id]
|
|
1508
|
+
proposal = proposal_by_expert[expert_id]
|
|
1509
|
+
evaluations = tuple(
|
|
1510
|
+
sorted(
|
|
1511
|
+
(
|
|
1512
|
+
value
|
|
1513
|
+
for batch in source
|
|
1514
|
+
for value in batch.evaluations
|
|
1515
|
+
),
|
|
1516
|
+
key=lambda value: value.action.action_sha256,
|
|
1517
|
+
)
|
|
1518
|
+
)
|
|
1519
|
+
action_ids = tuple(
|
|
1520
|
+
value.action.action_sha256 for value in evaluations
|
|
1521
|
+
)
|
|
1522
|
+
if len(action_ids) != len(set(action_ids)):
|
|
1523
|
+
raise ValueError("adaptive waves repeat an evaluation")
|
|
1524
|
+
merged.append(
|
|
1525
|
+
MaterializedActionEvaluationBatch(
|
|
1526
|
+
proposal_sha256=proposal.proposal_sha256,
|
|
1527
|
+
expert_id=proposal.expert_id,
|
|
1528
|
+
expert_version=proposal.expert_version,
|
|
1529
|
+
expert_definition_sha256=(
|
|
1530
|
+
proposal.expert_definition_sha256
|
|
1531
|
+
),
|
|
1532
|
+
selected_action_sha256s=action_ids,
|
|
1533
|
+
evaluations=evaluations,
|
|
1534
|
+
evidence=freeze_json(
|
|
1535
|
+
{
|
|
1536
|
+
"adaptive_wave_batch_sha256s": [
|
|
1537
|
+
value.batch_sha256 for value in source
|
|
1538
|
+
],
|
|
1539
|
+
"candidate_outcomes_reused": False,
|
|
1540
|
+
"disjoint_action_waves": True,
|
|
1541
|
+
}
|
|
1542
|
+
),
|
|
1543
|
+
)
|
|
1544
|
+
)
|
|
1545
|
+
return tuple(merged)
|
|
1546
|
+
|
|
1547
|
+
|
|
1548
|
+
@dataclass(frozen=True, slots=True)
|
|
1549
|
+
class OutcomeAdaptivePairedAuditExecution:
|
|
1550
|
+
"""One extra real arm excluded from the authoritative K-budget archive."""
|
|
1551
|
+
|
|
1552
|
+
plan: SamePrefixPairedAuditPlan
|
|
1553
|
+
observation: SamePrefixPairedAuditObservation
|
|
1554
|
+
counterfactual_evaluation_batches: tuple[
|
|
1555
|
+
MaterializedActionEvaluationBatch, ...
|
|
1556
|
+
]
|
|
1557
|
+
plan_receipt_sha256: str
|
|
1558
|
+
execution_sha256: str = field(init=False)
|
|
1559
|
+
|
|
1560
|
+
def __post_init__(self) -> None:
|
|
1561
|
+
if type(self.plan) is not SamePrefixPairedAuditPlan:
|
|
1562
|
+
raise TypeError("plan must be exact")
|
|
1563
|
+
self.plan.__post_init__()
|
|
1564
|
+
if type(self.observation) is not SamePrefixPairedAuditObservation:
|
|
1565
|
+
raise TypeError("observation must be exact")
|
|
1566
|
+
self.observation.__post_init__()
|
|
1567
|
+
if self.observation.plan != self.plan:
|
|
1568
|
+
raise ValueError("paired audit observation changed its frozen plan")
|
|
1569
|
+
if (
|
|
1570
|
+
type(self.counterfactual_evaluation_batches) is not tuple
|
|
1571
|
+
or not self.counterfactual_evaluation_batches
|
|
1572
|
+
):
|
|
1573
|
+
raise ValueError(
|
|
1574
|
+
"counterfactual_evaluation_batches must be non-empty"
|
|
1575
|
+
)
|
|
1576
|
+
evaluations: list[MaterializedActionEvaluation] = []
|
|
1577
|
+
for value in self.counterfactual_evaluation_batches:
|
|
1578
|
+
if type(value) is not MaterializedActionEvaluationBatch:
|
|
1579
|
+
raise TypeError(
|
|
1580
|
+
"counterfactual evaluation batches must be exact"
|
|
1581
|
+
)
|
|
1582
|
+
value.__post_init__()
|
|
1583
|
+
evaluations.extend(value.evaluations)
|
|
1584
|
+
if len(evaluations) != 1:
|
|
1585
|
+
raise ValueError("paired audit must buy exactly one extra action")
|
|
1586
|
+
expected_action_sha256 = (
|
|
1587
|
+
self.plan.exploration_action_sha256
|
|
1588
|
+
if self.plan.authoritative_arm
|
|
1589
|
+
is SamePrefixPairedAuditArm.LEGACY
|
|
1590
|
+
else self.plan.legacy_action_sha256
|
|
1591
|
+
)
|
|
1592
|
+
evaluation = evaluations[0]
|
|
1593
|
+
if evaluation.action.action_sha256 != expected_action_sha256:
|
|
1594
|
+
raise ValueError(
|
|
1595
|
+
"counterfactual evaluation differs from the unselected arm"
|
|
1596
|
+
)
|
|
1597
|
+
expected_outcome = (
|
|
1598
|
+
self.observation.exploration_outcome
|
|
1599
|
+
if self.plan.authoritative_arm
|
|
1600
|
+
is SamePrefixPairedAuditArm.LEGACY
|
|
1601
|
+
else self.observation.legacy_outcome
|
|
1602
|
+
)
|
|
1603
|
+
if expected_outcome.evaluation_sha256 != evaluation.evaluation_sha256:
|
|
1604
|
+
raise ValueError(
|
|
1605
|
+
"counterfactual outcome does not join its real evaluation"
|
|
1606
|
+
)
|
|
1607
|
+
require_sha256(
|
|
1608
|
+
self.plan_receipt_sha256,
|
|
1609
|
+
"plan_receipt_sha256",
|
|
1610
|
+
)
|
|
1611
|
+
object.__setattr__(
|
|
1612
|
+
self,
|
|
1613
|
+
"execution_sha256",
|
|
1614
|
+
_hash(
|
|
1615
|
+
_PAIRED_AUDIT_EXECUTION_DOMAIN,
|
|
1616
|
+
self._unsigned_record(),
|
|
1617
|
+
),
|
|
1618
|
+
)
|
|
1619
|
+
|
|
1620
|
+
@property
|
|
1621
|
+
def counterfactual_action_sha256(self) -> str:
|
|
1622
|
+
if self.plan.authoritative_arm is SamePrefixPairedAuditArm.LEGACY:
|
|
1623
|
+
return self.plan.exploration_action_sha256
|
|
1624
|
+
return self.plan.legacy_action_sha256
|
|
1625
|
+
|
|
1626
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
1627
|
+
return {
|
|
1628
|
+
"schema_version": 1,
|
|
1629
|
+
"plan_sha256": self.plan.plan_sha256,
|
|
1630
|
+
"observation_sha256": self.observation.observation_sha256,
|
|
1631
|
+
"counterfactual_evaluation_batch_sha256s": [
|
|
1632
|
+
value.batch_sha256
|
|
1633
|
+
for value in self.counterfactual_evaluation_batches
|
|
1634
|
+
],
|
|
1635
|
+
"counterfactual_action_sha256": (
|
|
1636
|
+
self.counterfactual_action_sha256
|
|
1637
|
+
),
|
|
1638
|
+
"plan_receipt_sha256": self.plan_receipt_sha256,
|
|
1639
|
+
"physical_extra_real_evaluation_count": 1,
|
|
1640
|
+
"assay_union_admitted_to_authoritative_archive": False,
|
|
1641
|
+
}
|
|
1642
|
+
|
|
1643
|
+
def to_record(self, *, include_evidence: bool = False) -> dict[str, object]:
|
|
1644
|
+
self.__post_init__()
|
|
1645
|
+
return {
|
|
1646
|
+
**self._unsigned_record(),
|
|
1647
|
+
"plan": self.plan.to_record(include_evidence=include_evidence),
|
|
1648
|
+
"observation": self.observation.to_record(
|
|
1649
|
+
include_evidence=include_evidence
|
|
1650
|
+
),
|
|
1651
|
+
"counterfactual_evaluation_batches": [
|
|
1652
|
+
value.to_record(include_evidence=include_evidence)
|
|
1653
|
+
for value in self.counterfactual_evaluation_batches
|
|
1654
|
+
],
|
|
1655
|
+
"execution_sha256": self.execution_sha256,
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
|
|
1659
|
+
@dataclass(frozen=True, slots=True)
|
|
1660
|
+
class OutcomeAdaptiveResidualPortfolioEvolutionResult:
|
|
1661
|
+
"""Complete causal trace plus the standard downstream result."""
|
|
1662
|
+
|
|
1663
|
+
result: ResidualPortfolioEvolutionResult
|
|
1664
|
+
prior_broker_decision: MaterializedActionBrokerDecision
|
|
1665
|
+
adaptive_actions: tuple[AdaptiveActionDescriptor, ...]
|
|
1666
|
+
diagnostic_decision: AdaptiveActionRacingDecision
|
|
1667
|
+
continuation_decisions: tuple[AdaptiveActionRacingDecision, ...]
|
|
1668
|
+
evaluation_waves: tuple[
|
|
1669
|
+
tuple[MaterializedActionEvaluationBatch, ...], ...
|
|
1670
|
+
]
|
|
1671
|
+
outcomes: tuple[AdaptiveActionOutcome, ...]
|
|
1672
|
+
set_outcomes: tuple[AdaptiveActionSetOutcome, ...]
|
|
1673
|
+
diagnostic_joint_gain: float
|
|
1674
|
+
allocation_directive: AdaptiveActionAllocationDirective
|
|
1675
|
+
phase_receipts: tuple[OutcomeAdaptiveResidualPhaseReceipt, ...]
|
|
1676
|
+
phase_commit_acks: tuple[
|
|
1677
|
+
OutcomeAdaptiveResidualPhaseCommitAck, ...
|
|
1678
|
+
]
|
|
1679
|
+
market_projector_definition_sha256: str
|
|
1680
|
+
market_projector_state_sha256: str
|
|
1681
|
+
outcome_projector_definition_sha256: str
|
|
1682
|
+
forecast_opportunity_challenger_definition_sha256: str | None = None
|
|
1683
|
+
paired_audit_executions: tuple[
|
|
1684
|
+
OutcomeAdaptivePairedAuditExecution, ...
|
|
1685
|
+
] = ()
|
|
1686
|
+
forecast_opportunity_calibration_observations: tuple[
|
|
1687
|
+
ArchiveOpportunityCalibrationObservation, ...
|
|
1688
|
+
] = ()
|
|
1689
|
+
method_definition_sha256: str = (
|
|
1690
|
+
OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_DEFINITION_SHA256
|
|
1691
|
+
)
|
|
1692
|
+
adaptive_result_sha256: str = field(init=False)
|
|
1693
|
+
|
|
1694
|
+
def __post_init__(self) -> None:
|
|
1695
|
+
if type(self.result) is not ResidualPortfolioEvolutionResult:
|
|
1696
|
+
raise TypeError("result must be exact")
|
|
1697
|
+
self.result.__post_init__()
|
|
1698
|
+
if (
|
|
1699
|
+
type(self.prior_broker_decision)
|
|
1700
|
+
is not MaterializedActionBrokerDecision
|
|
1701
|
+
):
|
|
1702
|
+
raise TypeError("prior_broker_decision must be exact")
|
|
1703
|
+
self.prior_broker_decision.__post_init__()
|
|
1704
|
+
if (
|
|
1705
|
+
type(self.adaptive_actions) is not tuple
|
|
1706
|
+
or not self.adaptive_actions
|
|
1707
|
+
):
|
|
1708
|
+
raise ValueError("adaptive_actions must be non-empty")
|
|
1709
|
+
action_by_sha: dict[str, AdaptiveActionDescriptor] = {}
|
|
1710
|
+
for value in self.adaptive_actions:
|
|
1711
|
+
if type(value) is not AdaptiveActionDescriptor:
|
|
1712
|
+
raise TypeError("adaptive_actions must be exact")
|
|
1713
|
+
value.__post_init__()
|
|
1714
|
+
action_by_sha[value.action_sha256] = value
|
|
1715
|
+
if len(action_by_sha) != len(self.adaptive_actions):
|
|
1716
|
+
raise ValueError("adaptive_actions repeat an identity")
|
|
1717
|
+
if type(self.diagnostic_decision) is not AdaptiveActionRacingDecision:
|
|
1718
|
+
raise TypeError("diagnostic_decision must be exact")
|
|
1719
|
+
self.diagnostic_decision.__post_init__()
|
|
1720
|
+
if self.diagnostic_decision.wave is not AdaptiveActionWave.DIAGNOSTIC:
|
|
1721
|
+
raise ValueError("first decision must be diagnostic")
|
|
1722
|
+
if type(self.continuation_decisions) is not tuple:
|
|
1723
|
+
raise TypeError("continuation_decisions must be a tuple")
|
|
1724
|
+
for value in self.continuation_decisions:
|
|
1725
|
+
if type(value) is not AdaptiveActionRacingDecision:
|
|
1726
|
+
raise TypeError("continuation decisions must be exact")
|
|
1727
|
+
value.__post_init__()
|
|
1728
|
+
if value.wave is AdaptiveActionWave.DIAGNOSTIC:
|
|
1729
|
+
raise ValueError("continuation cannot be diagnostic")
|
|
1730
|
+
if (
|
|
1731
|
+
type(self.evaluation_waves) is not tuple
|
|
1732
|
+
or len(self.evaluation_waves)
|
|
1733
|
+
!= 1 + len(self.continuation_decisions)
|
|
1734
|
+
):
|
|
1735
|
+
raise ValueError(
|
|
1736
|
+
"evaluation waves must cover diagnostic and continuations"
|
|
1737
|
+
)
|
|
1738
|
+
evaluation_by_action: dict[str, MaterializedActionEvaluation] = {}
|
|
1739
|
+
for wave in self.evaluation_waves:
|
|
1740
|
+
if type(wave) is not tuple or not wave:
|
|
1741
|
+
raise ValueError("each evaluation wave must be non-empty")
|
|
1742
|
+
for batch in wave:
|
|
1743
|
+
if type(batch) is not MaterializedActionEvaluationBatch:
|
|
1744
|
+
raise TypeError("evaluation waves must contain exact batches")
|
|
1745
|
+
batch.__post_init__()
|
|
1746
|
+
for evaluation in batch.evaluations:
|
|
1747
|
+
action_sha = evaluation.action.action_sha256
|
|
1748
|
+
if action_sha in evaluation_by_action:
|
|
1749
|
+
raise ValueError("evaluation waves repeat an action")
|
|
1750
|
+
evaluation_by_action[action_sha] = evaluation
|
|
1751
|
+
if type(self.outcomes) is not tuple:
|
|
1752
|
+
raise TypeError("outcomes must be a tuple")
|
|
1753
|
+
outcome_by_action: dict[str, AdaptiveActionOutcome] = {}
|
|
1754
|
+
for value in self.outcomes:
|
|
1755
|
+
if type(value) is not AdaptiveActionOutcome:
|
|
1756
|
+
raise TypeError("outcomes must be exact")
|
|
1757
|
+
value.__post_init__()
|
|
1758
|
+
if value.action_sha256 in outcome_by_action:
|
|
1759
|
+
raise ValueError("outcomes repeat an action")
|
|
1760
|
+
evaluation = evaluation_by_action.get(value.action_sha256)
|
|
1761
|
+
if (
|
|
1762
|
+
evaluation is None
|
|
1763
|
+
or value.evaluation_sha256
|
|
1764
|
+
!= evaluation.evaluation_sha256
|
|
1765
|
+
):
|
|
1766
|
+
raise ValueError("outcome does not join its real evaluation")
|
|
1767
|
+
outcome_by_action[value.action_sha256] = value
|
|
1768
|
+
if (
|
|
1769
|
+
type(self.set_outcomes) is not tuple
|
|
1770
|
+
or len(self.set_outcomes) != len(self.evaluation_waves)
|
|
1771
|
+
):
|
|
1772
|
+
raise ValueError(
|
|
1773
|
+
"set outcomes must cover every causal evaluation wave"
|
|
1774
|
+
)
|
|
1775
|
+
for value in self.set_outcomes:
|
|
1776
|
+
if type(value) is not AdaptiveActionSetOutcome:
|
|
1777
|
+
raise TypeError("set outcomes must be exact")
|
|
1778
|
+
value.__post_init__()
|
|
1779
|
+
selected = set(self.diagnostic_decision.selected_action_sha256s)
|
|
1780
|
+
diagnostic_evaluated = {
|
|
1781
|
+
value.action.action_sha256
|
|
1782
|
+
for value in _flatten(self.evaluation_waves[0])
|
|
1783
|
+
}
|
|
1784
|
+
if diagnostic_evaluated != selected:
|
|
1785
|
+
raise ValueError("diagnostic evaluations differ from decision")
|
|
1786
|
+
if not selected.issubset(outcome_by_action):
|
|
1787
|
+
raise ValueError("diagnostic outcomes are incomplete")
|
|
1788
|
+
for ordinal, decision in enumerate(
|
|
1789
|
+
self.continuation_decisions,
|
|
1790
|
+
start=1,
|
|
1791
|
+
):
|
|
1792
|
+
if decision.prior_selected_action_sha256s != tuple(
|
|
1793
|
+
sorted(selected)
|
|
1794
|
+
):
|
|
1795
|
+
raise ValueError("continuation decision skips causal prefix")
|
|
1796
|
+
expected_outcomes = tuple(
|
|
1797
|
+
sorted(
|
|
1798
|
+
outcome_by_action[value].outcome_sha256
|
|
1799
|
+
for value in selected
|
|
1800
|
+
)
|
|
1801
|
+
)
|
|
1802
|
+
if decision.observed_outcome_sha256s != expected_outcomes:
|
|
1803
|
+
raise ValueError(
|
|
1804
|
+
"continuation decision observed a foreign outcome cutoff"
|
|
1805
|
+
)
|
|
1806
|
+
expected_set_outcomes = tuple(
|
|
1807
|
+
sorted(
|
|
1808
|
+
value.set_outcome_sha256
|
|
1809
|
+
for value in self.set_outcomes[:ordinal]
|
|
1810
|
+
)
|
|
1811
|
+
)
|
|
1812
|
+
if (
|
|
1813
|
+
decision.observed_set_outcome_sha256s
|
|
1814
|
+
!= expected_set_outcomes
|
|
1815
|
+
):
|
|
1816
|
+
raise ValueError(
|
|
1817
|
+
"continuation decision observed a foreign set cutoff"
|
|
1818
|
+
)
|
|
1819
|
+
evaluated = {
|
|
1820
|
+
value.action.action_sha256
|
|
1821
|
+
for value in _flatten(self.evaluation_waves[ordinal])
|
|
1822
|
+
}
|
|
1823
|
+
if evaluated != set(decision.selected_action_sha256s):
|
|
1824
|
+
raise ValueError("continuation wave differs from decision")
|
|
1825
|
+
selected.update(decision.selected_action_sha256s)
|
|
1826
|
+
if selected != set(outcome_by_action):
|
|
1827
|
+
raise ValueError("outcome set differs from selected causal chain")
|
|
1828
|
+
if type(self.paired_audit_executions) is not tuple:
|
|
1829
|
+
raise TypeError("paired_audit_executions must be a tuple")
|
|
1830
|
+
if self.forecast_opportunity_challenger_definition_sha256 is not None:
|
|
1831
|
+
require_sha256(
|
|
1832
|
+
self.forecast_opportunity_challenger_definition_sha256,
|
|
1833
|
+
"forecast_opportunity_challenger_definition_sha256",
|
|
1834
|
+
)
|
|
1835
|
+
continuation_by_sha256 = {
|
|
1836
|
+
value.decision_sha256: value
|
|
1837
|
+
for value in self.continuation_decisions
|
|
1838
|
+
}
|
|
1839
|
+
paired_execution_by_decision: dict[
|
|
1840
|
+
str, OutcomeAdaptivePairedAuditExecution
|
|
1841
|
+
] = {}
|
|
1842
|
+
for value in self.paired_audit_executions:
|
|
1843
|
+
if type(value) is not OutcomeAdaptivePairedAuditExecution:
|
|
1844
|
+
raise TypeError("paired audit executions must be exact")
|
|
1845
|
+
value.__post_init__()
|
|
1846
|
+
decision_sha256 = value.plan.racing_decision_sha256
|
|
1847
|
+
if decision_sha256 in paired_execution_by_decision:
|
|
1848
|
+
raise ValueError(
|
|
1849
|
+
"paired audit executions repeat a racing decision"
|
|
1850
|
+
)
|
|
1851
|
+
decision = continuation_by_sha256.get(decision_sha256)
|
|
1852
|
+
is_forecast_audit = (
|
|
1853
|
+
value.plan.designer_id
|
|
1854
|
+
in FORECAST_OPPORTUNITY_SAME_PREFIX_AUDIT_DESIGNER_IDS
|
|
1855
|
+
)
|
|
1856
|
+
if (
|
|
1857
|
+
decision is None
|
|
1858
|
+
or (
|
|
1859
|
+
not is_forecast_audit
|
|
1860
|
+
and decision.wave
|
|
1861
|
+
is not AdaptiveActionWave.RANDOMIZED_AUDIT
|
|
1862
|
+
)
|
|
1863
|
+
or decision.selected_action_sha256s
|
|
1864
|
+
!= (value.plan.authoritative_action_sha256,)
|
|
1865
|
+
or decision.prior_selected_action_sha256s
|
|
1866
|
+
!= value.plan.common_prefix_action_sha256s
|
|
1867
|
+
):
|
|
1868
|
+
raise ValueError(
|
|
1869
|
+
"paired audit execution does not join its racing decision"
|
|
1870
|
+
)
|
|
1871
|
+
if is_forecast_audit != (
|
|
1872
|
+
self.forecast_opportunity_challenger_definition_sha256
|
|
1873
|
+
is not None
|
|
1874
|
+
):
|
|
1875
|
+
raise ValueError(
|
|
1876
|
+
"paired assay role differs from the method execution mode"
|
|
1877
|
+
)
|
|
1878
|
+
authoritative_evaluation = evaluation_by_action.get(
|
|
1879
|
+
value.plan.authoritative_action_sha256
|
|
1880
|
+
)
|
|
1881
|
+
authoritative_outcome = (
|
|
1882
|
+
value.observation.legacy_outcome
|
|
1883
|
+
if value.plan.authoritative_arm
|
|
1884
|
+
is SamePrefixPairedAuditArm.LEGACY
|
|
1885
|
+
else value.observation.exploration_outcome
|
|
1886
|
+
)
|
|
1887
|
+
if (
|
|
1888
|
+
authoritative_evaluation is None
|
|
1889
|
+
or authoritative_outcome.evaluation_sha256
|
|
1890
|
+
!= authoritative_evaluation.evaluation_sha256
|
|
1891
|
+
):
|
|
1892
|
+
raise ValueError(
|
|
1893
|
+
"paired audit authoritative arm is not the selected "
|
|
1894
|
+
"real evaluation"
|
|
1895
|
+
)
|
|
1896
|
+
if value.counterfactual_action_sha256 in evaluation_by_action:
|
|
1897
|
+
raise ValueError(
|
|
1898
|
+
"paired audit counterfactual entered the authoritative "
|
|
1899
|
+
"evaluation waves"
|
|
1900
|
+
)
|
|
1901
|
+
paired_execution_by_decision[decision_sha256] = value
|
|
1902
|
+
if (
|
|
1903
|
+
type(self.forecast_opportunity_calibration_observations)
|
|
1904
|
+
is not tuple
|
|
1905
|
+
):
|
|
1906
|
+
raise TypeError(
|
|
1907
|
+
"forecast opportunity calibration observations must be a tuple"
|
|
1908
|
+
)
|
|
1909
|
+
expected_calibration_observations: list[
|
|
1910
|
+
ArchiveOpportunityCalibrationObservation
|
|
1911
|
+
] = []
|
|
1912
|
+
calibration_projector = (
|
|
1913
|
+
ForecastOpportunityShadowCalibrationProjector()
|
|
1914
|
+
)
|
|
1915
|
+
for execution in self.paired_audit_executions:
|
|
1916
|
+
if (
|
|
1917
|
+
execution.plan.designer_id
|
|
1918
|
+
not in FORECAST_OPPORTUNITY_SAME_PREFIX_AUDIT_DESIGNER_IDS
|
|
1919
|
+
):
|
|
1920
|
+
continue
|
|
1921
|
+
decision = continuation_by_sha256[
|
|
1922
|
+
execution.plan.racing_decision_sha256
|
|
1923
|
+
]
|
|
1924
|
+
expected_calibration_observations.append(
|
|
1925
|
+
calibration_projector.project(
|
|
1926
|
+
decision_index=self.result.request.decision_index,
|
|
1927
|
+
evidence_cutoff_ordinal=(
|
|
1928
|
+
self.result.request.decision_index
|
|
1929
|
+
),
|
|
1930
|
+
decision=decision,
|
|
1931
|
+
action=action_by_sha[
|
|
1932
|
+
execution.plan.exploration_action_sha256
|
|
1933
|
+
],
|
|
1934
|
+
observation=execution.observation,
|
|
1935
|
+
)
|
|
1936
|
+
)
|
|
1937
|
+
for value in self.forecast_opportunity_calibration_observations:
|
|
1938
|
+
if type(value) is not ArchiveOpportunityCalibrationObservation:
|
|
1939
|
+
raise TypeError(
|
|
1940
|
+
"forecast opportunity calibration observations must "
|
|
1941
|
+
"be exact"
|
|
1942
|
+
)
|
|
1943
|
+
value.__post_init__()
|
|
1944
|
+
if self.forecast_opportunity_calibration_observations != tuple(
|
|
1945
|
+
expected_calibration_observations
|
|
1946
|
+
):
|
|
1947
|
+
raise ValueError(
|
|
1948
|
+
"forecast calibration observations do not close shadow assays"
|
|
1949
|
+
)
|
|
1950
|
+
prior_bindings: list[tuple[str, str]] = []
|
|
1951
|
+
prior_augmented_gain = 0.0
|
|
1952
|
+
for ordinal, (wave, set_outcome) in enumerate(
|
|
1953
|
+
zip(self.evaluation_waves, self.set_outcomes, strict=True)
|
|
1954
|
+
):
|
|
1955
|
+
expected_current_bindings = tuple(
|
|
1956
|
+
sorted(
|
|
1957
|
+
(
|
|
1958
|
+
value.action.action_sha256,
|
|
1959
|
+
value.evaluation_sha256,
|
|
1960
|
+
)
|
|
1961
|
+
for value in _flatten(wave)
|
|
1962
|
+
)
|
|
1963
|
+
)
|
|
1964
|
+
if (
|
|
1965
|
+
set_outcome.prior_action_evaluation_bindings
|
|
1966
|
+
!= tuple(sorted(prior_bindings))
|
|
1967
|
+
or set_outcome.current_action_evaluation_bindings
|
|
1968
|
+
!= expected_current_bindings
|
|
1969
|
+
):
|
|
1970
|
+
raise ValueError(
|
|
1971
|
+
"set outcome does not join its causal evaluation prefix"
|
|
1972
|
+
)
|
|
1973
|
+
if not math.isclose(
|
|
1974
|
+
set_outcome.prior_selected_set_gain,
|
|
1975
|
+
prior_augmented_gain,
|
|
1976
|
+
rel_tol=1e-12,
|
|
1977
|
+
abs_tol=1e-15,
|
|
1978
|
+
):
|
|
1979
|
+
raise ValueError(
|
|
1980
|
+
"set outcome utility chain is not causally contiguous"
|
|
1981
|
+
)
|
|
1982
|
+
if ordinal == 0 and (
|
|
1983
|
+
set_outcome.prior_action_evaluation_bindings
|
|
1984
|
+
or not math.isclose(
|
|
1985
|
+
set_outcome.conditional_set_gain,
|
|
1986
|
+
set_outcome.current_wave_fixed_set_gain,
|
|
1987
|
+
rel_tol=1e-12,
|
|
1988
|
+
abs_tol=1e-15,
|
|
1989
|
+
)
|
|
1990
|
+
):
|
|
1991
|
+
raise ValueError(
|
|
1992
|
+
"diagnostic set outcome must start from an empty prefix"
|
|
1993
|
+
)
|
|
1994
|
+
prior_bindings.extend(expected_current_bindings)
|
|
1995
|
+
prior_augmented_gain = (
|
|
1996
|
+
set_outcome.augmented_selected_set_gain
|
|
1997
|
+
)
|
|
1998
|
+
if (
|
|
1999
|
+
type(self.diagnostic_joint_gain) is not float
|
|
2000
|
+
or not math.isfinite(self.diagnostic_joint_gain)
|
|
2001
|
+
or self.diagnostic_joint_gain < 0.0
|
|
2002
|
+
):
|
|
2003
|
+
raise ValueError("diagnostic_joint_gain must be non-negative")
|
|
2004
|
+
if not math.isclose(
|
|
2005
|
+
self.diagnostic_joint_gain,
|
|
2006
|
+
self.set_outcomes[0].current_wave_fixed_set_gain,
|
|
2007
|
+
rel_tol=1e-12,
|
|
2008
|
+
abs_tol=1e-15,
|
|
2009
|
+
):
|
|
2010
|
+
raise ValueError(
|
|
2011
|
+
"diagnostic joint gain differs from its set observation"
|
|
2012
|
+
)
|
|
2013
|
+
if (
|
|
2014
|
+
type(self.allocation_directive)
|
|
2015
|
+
is not AdaptiveActionAllocationDirective
|
|
2016
|
+
):
|
|
2017
|
+
raise TypeError("allocation_directive must be exact")
|
|
2018
|
+
self.allocation_directive.__post_init__()
|
|
2019
|
+
if (
|
|
2020
|
+
self.allocation_directive.diagnostic_decision_sha256
|
|
2021
|
+
!= self.diagnostic_decision.decision_sha256
|
|
2022
|
+
or self.allocation_directive.continuation_decision_sha256s
|
|
2023
|
+
!= tuple(
|
|
2024
|
+
sorted(
|
|
2025
|
+
value.decision_sha256
|
|
2026
|
+
for value in self.continuation_decisions
|
|
2027
|
+
)
|
|
2028
|
+
)
|
|
2029
|
+
or self.allocation_directive.observed_outcome_sha256s
|
|
2030
|
+
!= tuple(
|
|
2031
|
+
sorted(value.outcome_sha256 for value in self.outcomes)
|
|
2032
|
+
)
|
|
2033
|
+
or self.allocation_directive.observed_set_outcome_sha256s
|
|
2034
|
+
!= tuple(
|
|
2035
|
+
sorted(
|
|
2036
|
+
value.set_outcome_sha256
|
|
2037
|
+
for value in self.set_outcomes
|
|
2038
|
+
)
|
|
2039
|
+
)
|
|
2040
|
+
or set(self.allocation_directive.required_action_sha256s)
|
|
2041
|
+
!= selected
|
|
2042
|
+
):
|
|
2043
|
+
raise ValueError("allocation directive does not close causal trace")
|
|
2044
|
+
if self.forecast_opportunity_challenger_definition_sha256 is not None:
|
|
2045
|
+
if (
|
|
2046
|
+
self.allocation_directive.policy_definition_sha256
|
|
2047
|
+
!= self.forecast_opportunity_challenger_definition_sha256
|
|
2048
|
+
or any(
|
|
2049
|
+
value.policy_definition_sha256
|
|
2050
|
+
!= self.forecast_opportunity_challenger_definition_sha256
|
|
2051
|
+
for value in self.continuation_decisions
|
|
2052
|
+
)
|
|
2053
|
+
):
|
|
2054
|
+
raise ValueError(
|
|
2055
|
+
"forecast challenger identity does not cover every "
|
|
2056
|
+
"continuation"
|
|
2057
|
+
)
|
|
2058
|
+
if (
|
|
2059
|
+
self.result.broker_decision.allocation_requirement
|
|
2060
|
+
!= self.allocation_directive
|
|
2061
|
+
or {
|
|
2062
|
+
value.action_sha256
|
|
2063
|
+
for value in self.result.broker_decision.selected_actions
|
|
2064
|
+
}
|
|
2065
|
+
!= selected
|
|
2066
|
+
):
|
|
2067
|
+
raise ValueError("final broker result differs from directive")
|
|
2068
|
+
if (
|
|
2069
|
+
type(self.phase_receipts) is not tuple
|
|
2070
|
+
or len(self.phase_receipts)
|
|
2071
|
+
!= (
|
|
2072
|
+
3
|
|
2073
|
+
+ len(self.continuation_decisions)
|
|
2074
|
+
+ len(self.paired_audit_executions)
|
|
2075
|
+
)
|
|
2076
|
+
):
|
|
2077
|
+
raise ValueError("phase receipts do not cover causal execution")
|
|
2078
|
+
expected_phase_values = [
|
|
2079
|
+
OutcomeAdaptiveResidualPhase.MARKET_FROZEN,
|
|
2080
|
+
OutcomeAdaptiveResidualPhase.DIAGNOSTIC_EVALUATED,
|
|
2081
|
+
]
|
|
2082
|
+
for decision in self.continuation_decisions:
|
|
2083
|
+
if decision.decision_sha256 in paired_execution_by_decision:
|
|
2084
|
+
expected_phase_values.append(
|
|
2085
|
+
OutcomeAdaptiveResidualPhase.PAIRED_AUDIT_FROZEN
|
|
2086
|
+
)
|
|
2087
|
+
expected_phase_values.append(
|
|
2088
|
+
OutcomeAdaptiveResidualPhase.ADAPTIVE_STEP_EVALUATED
|
|
2089
|
+
)
|
|
2090
|
+
expected_phase_values.append(
|
|
2091
|
+
OutcomeAdaptiveResidualPhase.FINALIZED
|
|
2092
|
+
)
|
|
2093
|
+
expected_phases = tuple(expected_phase_values)
|
|
2094
|
+
if tuple(value.phase for value in self.phase_receipts) != expected_phases:
|
|
2095
|
+
raise ValueError("phase receipts are out of causal order")
|
|
2096
|
+
if tuple(
|
|
2097
|
+
value.phase_ordinal for value in self.phase_receipts
|
|
2098
|
+
) != tuple(range(1, len(self.phase_receipts) + 1)):
|
|
2099
|
+
raise ValueError("phase receipt ordinals are not contiguous")
|
|
2100
|
+
for value in self.phase_receipts:
|
|
2101
|
+
value.__post_init__()
|
|
2102
|
+
if (
|
|
2103
|
+
value.residual_request_sha256
|
|
2104
|
+
!= self.result.request.request_sha256
|
|
2105
|
+
or value.diagnostic_decision_sha256
|
|
2106
|
+
!= self.diagnostic_decision.decision_sha256
|
|
2107
|
+
):
|
|
2108
|
+
raise ValueError("phase receipt names another execution")
|
|
2109
|
+
receipt_by_sha256 = {
|
|
2110
|
+
value.receipt_sha256: value for value in self.phase_receipts
|
|
2111
|
+
}
|
|
2112
|
+
for execution in self.paired_audit_executions:
|
|
2113
|
+
receipt = receipt_by_sha256.get(execution.plan_receipt_sha256)
|
|
2114
|
+
if (
|
|
2115
|
+
receipt is None
|
|
2116
|
+
or receipt.phase
|
|
2117
|
+
is not OutcomeAdaptiveResidualPhase.PAIRED_AUDIT_FROZEN
|
|
2118
|
+
or thaw_json(receipt.evidence).get("plan_sha256")
|
|
2119
|
+
!= execution.plan.plan_sha256
|
|
2120
|
+
):
|
|
2121
|
+
raise ValueError(
|
|
2122
|
+
"paired audit plan lacks its pre-evaluation freeze receipt"
|
|
2123
|
+
)
|
|
2124
|
+
if type(self.phase_commit_acks) is not tuple:
|
|
2125
|
+
raise TypeError("phase_commit_acks must be a tuple")
|
|
2126
|
+
for value in self.phase_commit_acks:
|
|
2127
|
+
value.__post_init__()
|
|
2128
|
+
if self.phase_commit_acks and tuple(
|
|
2129
|
+
value.phase_receipt_sha256
|
|
2130
|
+
for value in self.phase_commit_acks
|
|
2131
|
+
) != tuple(
|
|
2132
|
+
value.receipt_sha256 for value in self.phase_receipts
|
|
2133
|
+
):
|
|
2134
|
+
raise ValueError("phase commit acknowledgements do not close")
|
|
2135
|
+
for name in (
|
|
2136
|
+
"market_projector_definition_sha256",
|
|
2137
|
+
"market_projector_state_sha256",
|
|
2138
|
+
"outcome_projector_definition_sha256",
|
|
2139
|
+
"method_definition_sha256",
|
|
2140
|
+
):
|
|
2141
|
+
require_sha256(getattr(self, name), name)
|
|
2142
|
+
has_forecast = (
|
|
2143
|
+
self.forecast_opportunity_challenger_definition_sha256
|
|
2144
|
+
is not None
|
|
2145
|
+
)
|
|
2146
|
+
has_paired_assay = bool(self.paired_audit_executions)
|
|
2147
|
+
has_forecast_stratified_audit = any(
|
|
2148
|
+
value.plan.designer_id
|
|
2149
|
+
== FORECAST_STRATIFIED_SAME_PREFIX_AUDIT_DESIGNER_ID
|
|
2150
|
+
for value in self.paired_audit_executions
|
|
2151
|
+
)
|
|
2152
|
+
expected_method_definition_sha256 = (
|
|
2153
|
+
OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_STRATIFIED_AUDIT_EVOLUTION_DEFINITION_SHA256
|
|
2154
|
+
if has_forecast_stratified_audit
|
|
2155
|
+
else (
|
|
2156
|
+
OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_SHADOW_EVOLUTION_DEFINITION_SHA256
|
|
2157
|
+
if has_forecast and has_paired_assay
|
|
2158
|
+
else (
|
|
2159
|
+
_FORECAST_OPPORTUNITY_DEFINITION_SHA256
|
|
2160
|
+
if has_forecast
|
|
2161
|
+
else (
|
|
2162
|
+
_PAIRED_AUDIT_DEFINITION_SHA256
|
|
2163
|
+
if has_paired_assay
|
|
2164
|
+
else OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_DEFINITION_SHA256
|
|
2165
|
+
)
|
|
2166
|
+
)
|
|
2167
|
+
)
|
|
2168
|
+
)
|
|
2169
|
+
if (
|
|
2170
|
+
self.method_definition_sha256
|
|
2171
|
+
!= expected_method_definition_sha256
|
|
2172
|
+
):
|
|
2173
|
+
raise ValueError(
|
|
2174
|
+
"method definition does not match paired-audit execution mode"
|
|
2175
|
+
)
|
|
2176
|
+
object.__setattr__(
|
|
2177
|
+
self,
|
|
2178
|
+
"adaptive_result_sha256",
|
|
2179
|
+
_hash(
|
|
2180
|
+
(
|
|
2181
|
+
_FORECAST_STRATIFIED_AUDIT_RESULT_DOMAIN
|
|
2182
|
+
if has_forecast_stratified_audit
|
|
2183
|
+
else (
|
|
2184
|
+
_FORECAST_SHADOW_RESULT_DOMAIN
|
|
2185
|
+
if has_forecast and has_paired_assay
|
|
2186
|
+
else (
|
|
2187
|
+
_FORECAST_OPPORTUNITY_RESULT_DOMAIN
|
|
2188
|
+
if has_forecast
|
|
2189
|
+
else (
|
|
2190
|
+
_PAIRED_AUDIT_RESULT_DOMAIN
|
|
2191
|
+
if has_paired_assay
|
|
2192
|
+
else _RESULT_DOMAIN
|
|
2193
|
+
)
|
|
2194
|
+
)
|
|
2195
|
+
)
|
|
2196
|
+
),
|
|
2197
|
+
self._unsigned_record(),
|
|
2198
|
+
),
|
|
2199
|
+
)
|
|
2200
|
+
|
|
2201
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
2202
|
+
has_forecast = (
|
|
2203
|
+
self.forecast_opportunity_challenger_definition_sha256
|
|
2204
|
+
is not None
|
|
2205
|
+
)
|
|
2206
|
+
has_paired_assay = bool(self.paired_audit_executions)
|
|
2207
|
+
has_forecast_stratified_audit = any(
|
|
2208
|
+
value.plan.designer_id
|
|
2209
|
+
== FORECAST_STRATIFIED_SAME_PREFIX_AUDIT_DESIGNER_ID
|
|
2210
|
+
for value in self.paired_audit_executions
|
|
2211
|
+
)
|
|
2212
|
+
record: dict[str, object] = {
|
|
2213
|
+
"schema_version": (
|
|
2214
|
+
8
|
|
2215
|
+
if has_forecast_stratified_audit
|
|
2216
|
+
else (
|
|
2217
|
+
7
|
|
2218
|
+
if has_forecast and has_paired_assay
|
|
2219
|
+
else (
|
|
2220
|
+
6
|
|
2221
|
+
if has_forecast
|
|
2222
|
+
else (5 if has_paired_assay else 4)
|
|
2223
|
+
)
|
|
2224
|
+
)
|
|
2225
|
+
),
|
|
2226
|
+
"method": {
|
|
2227
|
+
"method_id": OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_ID,
|
|
2228
|
+
"method_version": (
|
|
2229
|
+
OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_STRATIFIED_AUDIT_EVOLUTION_VERSION
|
|
2230
|
+
if has_forecast_stratified_audit
|
|
2231
|
+
else (
|
|
2232
|
+
OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_SHADOW_EVOLUTION_VERSION
|
|
2233
|
+
if has_forecast and has_paired_assay
|
|
2234
|
+
else (
|
|
2235
|
+
OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_OPPORTUNITY_EVOLUTION_VERSION
|
|
2236
|
+
if has_forecast
|
|
2237
|
+
else (
|
|
2238
|
+
OUTCOME_ADAPTIVE_RESIDUAL_PAIRED_AUDIT_EVOLUTION_VERSION
|
|
2239
|
+
if has_paired_assay
|
|
2240
|
+
else OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_VERSION
|
|
2241
|
+
)
|
|
2242
|
+
)
|
|
2243
|
+
)
|
|
2244
|
+
),
|
|
2245
|
+
"definition_sha256": self.method_definition_sha256,
|
|
2246
|
+
},
|
|
2247
|
+
"combined_result_sha256": self.result.result_sha256,
|
|
2248
|
+
"prior_broker_decision_sha256": (
|
|
2249
|
+
self.prior_broker_decision.decision_sha256
|
|
2250
|
+
),
|
|
2251
|
+
"adaptive_action_sha256s": [
|
|
2252
|
+
value.action_sha256 for value in self.adaptive_actions
|
|
2253
|
+
],
|
|
2254
|
+
"diagnostic_decision_sha256": (
|
|
2255
|
+
self.diagnostic_decision.decision_sha256
|
|
2256
|
+
),
|
|
2257
|
+
"continuation_decision_sha256s": [
|
|
2258
|
+
value.decision_sha256
|
|
2259
|
+
for value in self.continuation_decisions
|
|
2260
|
+
],
|
|
2261
|
+
"evaluation_wave_batch_sha256s": [
|
|
2262
|
+
[value.batch_sha256 for value in wave]
|
|
2263
|
+
for wave in self.evaluation_waves
|
|
2264
|
+
],
|
|
2265
|
+
"outcome_sha256s": [
|
|
2266
|
+
value.outcome_sha256 for value in self.outcomes
|
|
2267
|
+
],
|
|
2268
|
+
"set_outcome_sha256s": [
|
|
2269
|
+
value.set_outcome_sha256 for value in self.set_outcomes
|
|
2270
|
+
],
|
|
2271
|
+
"diagnostic_joint_gain_hex": self.diagnostic_joint_gain.hex(),
|
|
2272
|
+
"allocation_directive_sha256": (
|
|
2273
|
+
self.allocation_directive.directive_sha256
|
|
2274
|
+
),
|
|
2275
|
+
"phase_receipt_sha256s": [
|
|
2276
|
+
value.receipt_sha256 for value in self.phase_receipts
|
|
2277
|
+
],
|
|
2278
|
+
"phase_commit_ack_sha256s": [
|
|
2279
|
+
value.ack_sha256 for value in self.phase_commit_acks
|
|
2280
|
+
],
|
|
2281
|
+
"market_projector_definition_sha256": (
|
|
2282
|
+
self.market_projector_definition_sha256
|
|
2283
|
+
),
|
|
2284
|
+
"market_projector_state_sha256": (
|
|
2285
|
+
self.market_projector_state_sha256
|
|
2286
|
+
),
|
|
2287
|
+
"outcome_projector_definition_sha256": (
|
|
2288
|
+
self.outcome_projector_definition_sha256
|
|
2289
|
+
),
|
|
2290
|
+
"current_outcomes_used_only_after_interception": True,
|
|
2291
|
+
"workload_objective_model_provider_prompt_config_branches": False,
|
|
2292
|
+
}
|
|
2293
|
+
if self.paired_audit_executions:
|
|
2294
|
+
record.update(
|
|
2295
|
+
{
|
|
2296
|
+
"paired_audit_execution_sha256s": [
|
|
2297
|
+
value.execution_sha256
|
|
2298
|
+
for value in self.paired_audit_executions
|
|
2299
|
+
],
|
|
2300
|
+
"paired_audit_physical_extra_real_evaluation_count": len(
|
|
2301
|
+
self.paired_audit_executions
|
|
2302
|
+
),
|
|
2303
|
+
"paired_audit_union_admitted_to_authoritative_archive": (
|
|
2304
|
+
False
|
|
2305
|
+
),
|
|
2306
|
+
}
|
|
2307
|
+
)
|
|
2308
|
+
if has_forecast_stratified_audit:
|
|
2309
|
+
record.update(
|
|
2310
|
+
{
|
|
2311
|
+
"forecast_stratified_same_prefix_audit": True,
|
|
2312
|
+
"counterfactual_action_quarantine_enforced": True,
|
|
2313
|
+
"counterfactual_quarantined_action_sha256s": sorted(
|
|
2314
|
+
value.counterfactual_action_sha256
|
|
2315
|
+
for value in self.paired_audit_executions
|
|
2316
|
+
if value.plan.designer_id
|
|
2317
|
+
== FORECAST_STRATIFIED_SAME_PREFIX_AUDIT_DESIGNER_ID
|
|
2318
|
+
),
|
|
2319
|
+
"audit_position_schedule": (
|
|
2320
|
+
"one-hash-uniform-continuation-position-per-request"
|
|
2321
|
+
),
|
|
2322
|
+
}
|
|
2323
|
+
)
|
|
2324
|
+
if self.forecast_opportunity_calibration_observations:
|
|
2325
|
+
record[
|
|
2326
|
+
"forecast_opportunity_calibration_observation_sha256s"
|
|
2327
|
+
] = [
|
|
2328
|
+
value.observation_sha256
|
|
2329
|
+
for value in (
|
|
2330
|
+
self.forecast_opportunity_calibration_observations
|
|
2331
|
+
)
|
|
2332
|
+
]
|
|
2333
|
+
if self.forecast_opportunity_challenger_definition_sha256 is not None:
|
|
2334
|
+
record.update(
|
|
2335
|
+
{
|
|
2336
|
+
"forecast_opportunity_challenger_definition_sha256": (
|
|
2337
|
+
self.forecast_opportunity_challenger_definition_sha256
|
|
2338
|
+
),
|
|
2339
|
+
"forecast_geometry_frozen_before_diagnostic_outcomes": True,
|
|
2340
|
+
"current_prefix_candidate_outcomes_used_for_selection": True,
|
|
2341
|
+
"eligible_candidate_outcomes_observed": False,
|
|
2342
|
+
"fallback_preserved_on_abstention": True,
|
|
2343
|
+
}
|
|
2344
|
+
)
|
|
2345
|
+
return record
|
|
2346
|
+
|
|
2347
|
+
def to_record(self, *, include_evidence: bool = False) -> dict[str, object]:
|
|
2348
|
+
self.__post_init__()
|
|
2349
|
+
record = {
|
|
2350
|
+
**self._unsigned_record(),
|
|
2351
|
+
"adaptive_actions": [
|
|
2352
|
+
value.to_record() for value in self.adaptive_actions
|
|
2353
|
+
],
|
|
2354
|
+
"diagnostic_decision": self.diagnostic_decision.to_record(
|
|
2355
|
+
include_evidence=include_evidence
|
|
2356
|
+
),
|
|
2357
|
+
"continuation_decisions": [
|
|
2358
|
+
value.to_record(include_evidence=include_evidence)
|
|
2359
|
+
for value in self.continuation_decisions
|
|
2360
|
+
],
|
|
2361
|
+
"evaluation_waves": [
|
|
2362
|
+
[
|
|
2363
|
+
value.to_record(include_evidence=include_evidence)
|
|
2364
|
+
for value in wave
|
|
2365
|
+
]
|
|
2366
|
+
for wave in self.evaluation_waves
|
|
2367
|
+
],
|
|
2368
|
+
"outcomes": [value.to_record() for value in self.outcomes],
|
|
2369
|
+
"set_outcomes": [
|
|
2370
|
+
value.to_record() for value in self.set_outcomes
|
|
2371
|
+
],
|
|
2372
|
+
"allocation_directive": self.allocation_directive.to_record(
|
|
2373
|
+
include_evidence=include_evidence
|
|
2374
|
+
),
|
|
2375
|
+
"phase_receipts": [
|
|
2376
|
+
value.to_record(include_evidence=include_evidence)
|
|
2377
|
+
for value in self.phase_receipts
|
|
2378
|
+
],
|
|
2379
|
+
"phase_commit_acks": [
|
|
2380
|
+
value.to_record(include_evidence=include_evidence)
|
|
2381
|
+
for value in self.phase_commit_acks
|
|
2382
|
+
],
|
|
2383
|
+
"combined_result": self.result.to_record(
|
|
2384
|
+
include_allocation_evidence=include_evidence
|
|
2385
|
+
),
|
|
2386
|
+
"adaptive_result_sha256": self.adaptive_result_sha256,
|
|
2387
|
+
}
|
|
2388
|
+
if self.paired_audit_executions:
|
|
2389
|
+
record["paired_audit_executions"] = [
|
|
2390
|
+
value.to_record(include_evidence=include_evidence)
|
|
2391
|
+
for value in self.paired_audit_executions
|
|
2392
|
+
]
|
|
2393
|
+
if self.forecast_opportunity_calibration_observations:
|
|
2394
|
+
record["forecast_opportunity_calibration_observations"] = [
|
|
2395
|
+
value.to_record()
|
|
2396
|
+
for value in (
|
|
2397
|
+
self.forecast_opportunity_calibration_observations
|
|
2398
|
+
)
|
|
2399
|
+
]
|
|
2400
|
+
return record
|
|
2401
|
+
|
|
2402
|
+
|
|
2403
|
+
@dataclass(frozen=True, slots=True)
|
|
2404
|
+
class OutcomeAdaptiveResidualPortfolioEvolution:
|
|
2405
|
+
"""Execute diagnostic and sequential actions from one sealed market."""
|
|
2406
|
+
|
|
2407
|
+
experts: tuple[MaterializedActionProposalExpertPort, ...]
|
|
2408
|
+
broker: RegretBrokeredMaterializedActionPolicy
|
|
2409
|
+
racing_policy: OutcomeAdaptiveActionRacingPolicy
|
|
2410
|
+
market_projector: AdaptiveActionMarketProjectorPort = field(
|
|
2411
|
+
repr=False,
|
|
2412
|
+
compare=False,
|
|
2413
|
+
)
|
|
2414
|
+
outcome_projector: AdaptiveActionOutcomeProjectorPort = field(
|
|
2415
|
+
repr=False,
|
|
2416
|
+
compare=False,
|
|
2417
|
+
)
|
|
2418
|
+
slate_value: MaterializedSlateValuePort = field(
|
|
2419
|
+
repr=False,
|
|
2420
|
+
compare=False,
|
|
2421
|
+
)
|
|
2422
|
+
slate_feasibility: MaterializedSlateFeasibilityPort = field(
|
|
2423
|
+
repr=False,
|
|
2424
|
+
compare=False,
|
|
2425
|
+
)
|
|
2426
|
+
diagnostic_allocation_policy: (
|
|
2427
|
+
MaterializedActionAllocationPolicyPort | None
|
|
2428
|
+
) = field(
|
|
2429
|
+
default=None,
|
|
2430
|
+
repr=False,
|
|
2431
|
+
compare=False,
|
|
2432
|
+
)
|
|
2433
|
+
phase_committer: OutcomeAdaptiveResidualPhaseCommitPort | None = field(
|
|
2434
|
+
default=None,
|
|
2435
|
+
repr=False,
|
|
2436
|
+
compare=False,
|
|
2437
|
+
)
|
|
2438
|
+
paired_audit_designer: SamePrefixPairedAuditDesignerPort | None = field(
|
|
2439
|
+
default=None,
|
|
2440
|
+
repr=False,
|
|
2441
|
+
compare=False,
|
|
2442
|
+
)
|
|
2443
|
+
forecast_opportunity_challenger: (
|
|
2444
|
+
ProtectedCurrentPrefixForecastOpportunityChallenger | None
|
|
2445
|
+
) = field(
|
|
2446
|
+
default=None,
|
|
2447
|
+
repr=False,
|
|
2448
|
+
compare=False,
|
|
2449
|
+
)
|
|
2450
|
+
forecast_opportunity_shadow_designer: (
|
|
2451
|
+
ForecastOpportunitySamePrefixShadowDesignerPort | None
|
|
2452
|
+
) = field(
|
|
2453
|
+
default=None,
|
|
2454
|
+
repr=False,
|
|
2455
|
+
compare=False,
|
|
2456
|
+
)
|
|
2457
|
+
require_durable_phase_commits: bool = False
|
|
2458
|
+
|
|
2459
|
+
def __post_init__(self) -> None:
|
|
2460
|
+
if type(self.experts) is not tuple or not self.experts:
|
|
2461
|
+
raise ValueError("experts must be a non-empty exact tuple")
|
|
2462
|
+
if any(
|
|
2463
|
+
getattr(value, "evaluation_wave_semantics", None)
|
|
2464
|
+
!= DISJOINT_ACTION_EVALUATION_WAVES_V1
|
|
2465
|
+
for value in self.experts
|
|
2466
|
+
):
|
|
2467
|
+
raise ValueError(
|
|
2468
|
+
"adaptive experts must support disjoint action waves"
|
|
2469
|
+
)
|
|
2470
|
+
if type(self.broker) is not RegretBrokeredMaterializedActionPolicy:
|
|
2471
|
+
raise TypeError("broker must be an exact regret-broker policy")
|
|
2472
|
+
self.broker.__post_init__()
|
|
2473
|
+
if type(self.racing_policy) is not OutcomeAdaptiveActionRacingPolicy:
|
|
2474
|
+
# Structural admission for injected allocation controllers:
|
|
2475
|
+
# the policy must expose the exact racing surface (identity
|
|
2476
|
+
# triple plus both decision methods). Version-gated
|
|
2477
|
+
# features (causal set outcomes, paired audits) still key
|
|
2478
|
+
# off policy_version, so a foreign controller only reaches
|
|
2479
|
+
# the plain observational path.
|
|
2480
|
+
required_attributes = (
|
|
2481
|
+
"policy_id",
|
|
2482
|
+
"policy_version",
|
|
2483
|
+
"definition_sha256",
|
|
2484
|
+
"design_diagnostic_pilot",
|
|
2485
|
+
"select_next",
|
|
2486
|
+
"__post_init__",
|
|
2487
|
+
)
|
|
2488
|
+
missing = tuple(
|
|
2489
|
+
name
|
|
2490
|
+
for name in required_attributes
|
|
2491
|
+
if not hasattr(self.racing_policy, name)
|
|
2492
|
+
)
|
|
2493
|
+
if missing:
|
|
2494
|
+
raise TypeError(
|
|
2495
|
+
"racing_policy must be the exact racing policy or "
|
|
2496
|
+
"implement its surface; missing: "
|
|
2497
|
+
+ ",".join(missing)
|
|
2498
|
+
)
|
|
2499
|
+
self.racing_policy.__post_init__()
|
|
2500
|
+
if not isinstance(
|
|
2501
|
+
self.market_projector,
|
|
2502
|
+
AdaptiveActionMarketProjectorPort,
|
|
2503
|
+
):
|
|
2504
|
+
raise TypeError("market_projector must implement its port")
|
|
2505
|
+
_require_token(
|
|
2506
|
+
self.market_projector.projector_id,
|
|
2507
|
+
name="market projector_id",
|
|
2508
|
+
)
|
|
2509
|
+
if (
|
|
2510
|
+
type(self.market_projector.projector_version) is not int
|
|
2511
|
+
or self.market_projector.projector_version <= 0
|
|
2512
|
+
):
|
|
2513
|
+
raise ValueError("market projector_version must be positive")
|
|
2514
|
+
require_sha256(
|
|
2515
|
+
self.market_projector.definition_sha256,
|
|
2516
|
+
"market projector definition",
|
|
2517
|
+
)
|
|
2518
|
+
require_sha256(
|
|
2519
|
+
self.market_projector.state_sha256,
|
|
2520
|
+
"market projector state",
|
|
2521
|
+
)
|
|
2522
|
+
if not isinstance(
|
|
2523
|
+
self.outcome_projector,
|
|
2524
|
+
AdaptiveActionOutcomeProjectorPort,
|
|
2525
|
+
):
|
|
2526
|
+
raise TypeError("outcome_projector must implement its port")
|
|
2527
|
+
_require_token(
|
|
2528
|
+
self.outcome_projector.projector_id,
|
|
2529
|
+
name="outcome projector_id",
|
|
2530
|
+
)
|
|
2531
|
+
if (
|
|
2532
|
+
type(self.outcome_projector.projector_version) is not int
|
|
2533
|
+
or self.outcome_projector.projector_version <= 0
|
|
2534
|
+
):
|
|
2535
|
+
raise ValueError("outcome projector_version must be positive")
|
|
2536
|
+
require_sha256(
|
|
2537
|
+
self.outcome_projector.definition_sha256,
|
|
2538
|
+
"outcome projector definition",
|
|
2539
|
+
)
|
|
2540
|
+
if not isinstance(self.slate_value, MaterializedSlateValuePort):
|
|
2541
|
+
raise TypeError("slate_value must implement its port")
|
|
2542
|
+
if not isinstance(
|
|
2543
|
+
self.slate_feasibility,
|
|
2544
|
+
MaterializedSlateFeasibilityPort,
|
|
2545
|
+
):
|
|
2546
|
+
raise TypeError("slate_feasibility must implement its port")
|
|
2547
|
+
require_sha256(
|
|
2548
|
+
self.slate_value.definition_sha256,
|
|
2549
|
+
"slate value definition",
|
|
2550
|
+
)
|
|
2551
|
+
require_sha256(
|
|
2552
|
+
self.slate_feasibility.definition_sha256,
|
|
2553
|
+
"slate feasibility definition",
|
|
2554
|
+
)
|
|
2555
|
+
if self.diagnostic_allocation_policy is not None:
|
|
2556
|
+
if not isinstance(
|
|
2557
|
+
self.diagnostic_allocation_policy,
|
|
2558
|
+
MaterializedActionAllocationPolicyPort,
|
|
2559
|
+
):
|
|
2560
|
+
raise TypeError(
|
|
2561
|
+
"diagnostic_allocation_policy must implement its port"
|
|
2562
|
+
)
|
|
2563
|
+
_require_token(
|
|
2564
|
+
self.diagnostic_allocation_policy.policy_id,
|
|
2565
|
+
name="diagnostic allocation policy_id",
|
|
2566
|
+
)
|
|
2567
|
+
if (
|
|
2568
|
+
type(self.diagnostic_allocation_policy.policy_version)
|
|
2569
|
+
is not int
|
|
2570
|
+
or self.diagnostic_allocation_policy.policy_version <= 0
|
|
2571
|
+
):
|
|
2572
|
+
raise ValueError(
|
|
2573
|
+
"diagnostic allocation policy_version must be positive"
|
|
2574
|
+
)
|
|
2575
|
+
require_sha256(
|
|
2576
|
+
self.diagnostic_allocation_policy.definition_sha256,
|
|
2577
|
+
"diagnostic allocation policy definition",
|
|
2578
|
+
)
|
|
2579
|
+
if self.phase_committer is not None:
|
|
2580
|
+
if not isinstance(
|
|
2581
|
+
self.phase_committer,
|
|
2582
|
+
OutcomeAdaptiveResidualPhaseCommitPort,
|
|
2583
|
+
):
|
|
2584
|
+
raise TypeError("phase_committer must implement its port")
|
|
2585
|
+
_require_token(
|
|
2586
|
+
self.phase_committer.committer_id,
|
|
2587
|
+
name="committer_id",
|
|
2588
|
+
)
|
|
2589
|
+
if (
|
|
2590
|
+
type(self.phase_committer.committer_version) is not int
|
|
2591
|
+
or self.phase_committer.committer_version <= 0
|
|
2592
|
+
):
|
|
2593
|
+
raise ValueError("committer_version must be positive")
|
|
2594
|
+
require_sha256(
|
|
2595
|
+
self.phase_committer.definition_sha256,
|
|
2596
|
+
"committer definition",
|
|
2597
|
+
)
|
|
2598
|
+
if self.paired_audit_designer is not None:
|
|
2599
|
+
if not isinstance(
|
|
2600
|
+
self.paired_audit_designer,
|
|
2601
|
+
SamePrefixPairedAuditDesignerPort,
|
|
2602
|
+
):
|
|
2603
|
+
raise TypeError(
|
|
2604
|
+
"paired_audit_designer must implement its port"
|
|
2605
|
+
)
|
|
2606
|
+
_require_token(
|
|
2607
|
+
self.paired_audit_designer.designer_id,
|
|
2608
|
+
name="paired audit designer_id",
|
|
2609
|
+
)
|
|
2610
|
+
if (
|
|
2611
|
+
type(self.paired_audit_designer.designer_version) is not int
|
|
2612
|
+
or self.paired_audit_designer.designer_version <= 0
|
|
2613
|
+
):
|
|
2614
|
+
raise ValueError(
|
|
2615
|
+
"paired audit designer_version must be positive"
|
|
2616
|
+
)
|
|
2617
|
+
require_sha256(
|
|
2618
|
+
self.paired_audit_designer.definition_sha256,
|
|
2619
|
+
"paired audit designer definition",
|
|
2620
|
+
)
|
|
2621
|
+
if (
|
|
2622
|
+
self.racing_policy.policy_version
|
|
2623
|
+
!= (
|
|
2624
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_STRATIFIED_AUDIT_POLICY_VERSION
|
|
2625
|
+
)
|
|
2626
|
+
):
|
|
2627
|
+
raise ValueError(
|
|
2628
|
+
"paired audit interception requires racing policy v6"
|
|
2629
|
+
)
|
|
2630
|
+
if self.forecast_opportunity_challenger is not None:
|
|
2631
|
+
if (
|
|
2632
|
+
type(self.forecast_opportunity_challenger)
|
|
2633
|
+
is not ProtectedCurrentPrefixForecastOpportunityChallenger
|
|
2634
|
+
):
|
|
2635
|
+
raise TypeError(
|
|
2636
|
+
"forecast_opportunity_challenger must be exact"
|
|
2637
|
+
)
|
|
2638
|
+
self.forecast_opportunity_challenger.__post_init__()
|
|
2639
|
+
if self.paired_audit_designer is not None:
|
|
2640
|
+
raise ValueError(
|
|
2641
|
+
"forecast challenger and paired audit cannot share one "
|
|
2642
|
+
"authoritative execution"
|
|
2643
|
+
)
|
|
2644
|
+
if (
|
|
2645
|
+
self.forecast_opportunity_challenger.fallback_policy_id
|
|
2646
|
+
!= self.racing_policy.policy_id
|
|
2647
|
+
or self.forecast_opportunity_challenger
|
|
2648
|
+
.fallback_policy_version
|
|
2649
|
+
!= self.racing_policy.policy_version
|
|
2650
|
+
or self.forecast_opportunity_challenger
|
|
2651
|
+
.fallback_policy_definition_sha256
|
|
2652
|
+
!= self.racing_policy.definition_sha256
|
|
2653
|
+
):
|
|
2654
|
+
raise ValueError(
|
|
2655
|
+
"forecast challenger fallback differs from racing policy"
|
|
2656
|
+
)
|
|
2657
|
+
if self.forecast_opportunity_shadow_designer is not None:
|
|
2658
|
+
if self.forecast_opportunity_challenger is None:
|
|
2659
|
+
raise ValueError(
|
|
2660
|
+
"forecast shadow designer requires a forecast challenger"
|
|
2661
|
+
)
|
|
2662
|
+
if self.paired_audit_designer is not None:
|
|
2663
|
+
raise ValueError(
|
|
2664
|
+
"forecast shadow and stratified audit designers are "
|
|
2665
|
+
"mutually exclusive"
|
|
2666
|
+
)
|
|
2667
|
+
if not isinstance(
|
|
2668
|
+
self.forecast_opportunity_shadow_designer,
|
|
2669
|
+
ForecastOpportunitySamePrefixShadowDesignerPort,
|
|
2670
|
+
):
|
|
2671
|
+
raise TypeError(
|
|
2672
|
+
"forecast_opportunity_shadow_designer must implement "
|
|
2673
|
+
"its port"
|
|
2674
|
+
)
|
|
2675
|
+
_require_token(
|
|
2676
|
+
self.forecast_opportunity_shadow_designer.designer_id,
|
|
2677
|
+
name="forecast shadow designer_id",
|
|
2678
|
+
)
|
|
2679
|
+
if (
|
|
2680
|
+
type(
|
|
2681
|
+
self.forecast_opportunity_shadow_designer.designer_version
|
|
2682
|
+
)
|
|
2683
|
+
is not int
|
|
2684
|
+
or (
|
|
2685
|
+
self.forecast_opportunity_shadow_designer.designer_version
|
|
2686
|
+
<= 0
|
|
2687
|
+
)
|
|
2688
|
+
):
|
|
2689
|
+
raise ValueError(
|
|
2690
|
+
"forecast shadow designer_version must be positive"
|
|
2691
|
+
)
|
|
2692
|
+
require_sha256(
|
|
2693
|
+
self.forecast_opportunity_shadow_designer.definition_sha256,
|
|
2694
|
+
"forecast shadow designer definition",
|
|
2695
|
+
)
|
|
2696
|
+
if type(self.require_durable_phase_commits) is not bool:
|
|
2697
|
+
raise TypeError("require_durable_phase_commits must be exact")
|
|
2698
|
+
if (
|
|
2699
|
+
self.require_durable_phase_commits
|
|
2700
|
+
and self.phase_committer is None
|
|
2701
|
+
):
|
|
2702
|
+
raise ValueError(
|
|
2703
|
+
"required durable phase commits need a committer"
|
|
2704
|
+
)
|
|
2705
|
+
|
|
2706
|
+
async def _commit(
|
|
2707
|
+
self,
|
|
2708
|
+
receipt: OutcomeAdaptiveResidualPhaseReceipt,
|
|
2709
|
+
) -> OutcomeAdaptiveResidualPhaseCommitAck | None:
|
|
2710
|
+
if self.phase_committer is None:
|
|
2711
|
+
return None
|
|
2712
|
+
ack = await self.phase_committer.commit(receipt)
|
|
2713
|
+
if type(ack) is not OutcomeAdaptiveResidualPhaseCommitAck:
|
|
2714
|
+
raise TypeError("phase committer returned a foreign ack")
|
|
2715
|
+
ack.__post_init__()
|
|
2716
|
+
if (
|
|
2717
|
+
ack.committer_id != self.phase_committer.committer_id
|
|
2718
|
+
or ack.committer_version
|
|
2719
|
+
!= self.phase_committer.committer_version
|
|
2720
|
+
or ack.committer_definition_sha256
|
|
2721
|
+
!= self.phase_committer.definition_sha256
|
|
2722
|
+
or ack.phase_receipt_sha256 != receipt.receipt_sha256
|
|
2723
|
+
):
|
|
2724
|
+
raise ValueError("phase commit ack differs from request")
|
|
2725
|
+
if self.require_durable_phase_commits and not ack.durable:
|
|
2726
|
+
raise ValueError("required phase commit was not durable")
|
|
2727
|
+
return ack
|
|
2728
|
+
|
|
2729
|
+
async def run(
|
|
2730
|
+
self,
|
|
2731
|
+
request: ResidualPortfolioDecisionRequest,
|
|
2732
|
+
) -> OutcomeAdaptiveResidualPortfolioEvolutionResult:
|
|
2733
|
+
self.__post_init__()
|
|
2734
|
+
if type(request) is not ResidualPortfolioDecisionRequest:
|
|
2735
|
+
raise TypeError("request must be exact")
|
|
2736
|
+
request.__post_init__()
|
|
2737
|
+
uses_causal_set_outcomes = (
|
|
2738
|
+
self.racing_policy.policy_version
|
|
2739
|
+
in {
|
|
2740
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_CAUSAL_SET_POLICY_VERSION,
|
|
2741
|
+
OUTCOME_ADAPTIVE_ACTION_RACING_RISK_CONTROLLED_POLICY_VERSION,
|
|
2742
|
+
}
|
|
2743
|
+
)
|
|
2744
|
+
proposals = await propose_materialized_action_batches(
|
|
2745
|
+
experts=self.experts,
|
|
2746
|
+
request=request,
|
|
2747
|
+
)
|
|
2748
|
+
forecast_geometry = (
|
|
2749
|
+
None
|
|
2750
|
+
if self.forecast_opportunity_challenger is None
|
|
2751
|
+
else await self.forecast_opportunity_challenger.freeze_geometry(
|
|
2752
|
+
request=request,
|
|
2753
|
+
proposals=proposals,
|
|
2754
|
+
)
|
|
2755
|
+
)
|
|
2756
|
+
actions = tuple(
|
|
2757
|
+
action
|
|
2758
|
+
for proposal in proposals
|
|
2759
|
+
for action in proposal.actions
|
|
2760
|
+
)
|
|
2761
|
+
diagnostic_requirement = None
|
|
2762
|
+
if self.diagnostic_allocation_policy is not None:
|
|
2763
|
+
diagnostic_requirement = (
|
|
2764
|
+
await self.diagnostic_allocation_policy.require(
|
|
2765
|
+
request,
|
|
2766
|
+
proposals,
|
|
2767
|
+
)
|
|
2768
|
+
)
|
|
2769
|
+
if (
|
|
2770
|
+
type(diagnostic_requirement)
|
|
2771
|
+
is not MaterializedActionAllocationRequirement
|
|
2772
|
+
):
|
|
2773
|
+
raise TypeError(
|
|
2774
|
+
"diagnostic allocation policy returned a foreign "
|
|
2775
|
+
"requirement"
|
|
2776
|
+
)
|
|
2777
|
+
diagnostic_requirement.__post_init__()
|
|
2778
|
+
if (
|
|
2779
|
+
diagnostic_requirement.policy_id,
|
|
2780
|
+
diagnostic_requirement.policy_version,
|
|
2781
|
+
diagnostic_requirement.policy_definition_sha256,
|
|
2782
|
+
) != (
|
|
2783
|
+
self.diagnostic_allocation_policy.policy_id,
|
|
2784
|
+
self.diagnostic_allocation_policy.policy_version,
|
|
2785
|
+
self.diagnostic_allocation_policy.definition_sha256,
|
|
2786
|
+
):
|
|
2787
|
+
raise ValueError(
|
|
2788
|
+
"diagnostic allocation requirement changed policy identity"
|
|
2789
|
+
)
|
|
2790
|
+
proposal_sha256s = tuple(
|
|
2791
|
+
sorted(value.proposal_sha256 for value in proposals)
|
|
2792
|
+
)
|
|
2793
|
+
if (
|
|
2794
|
+
diagnostic_requirement.residual_request_sha256
|
|
2795
|
+
!= request.request_sha256
|
|
2796
|
+
or diagnostic_requirement.proposal_sha256s
|
|
2797
|
+
!= proposal_sha256s
|
|
2798
|
+
):
|
|
2799
|
+
raise ValueError(
|
|
2800
|
+
"diagnostic allocation requirement changed its "
|
|
2801
|
+
"sealed cutoff"
|
|
2802
|
+
)
|
|
2803
|
+
if not set(
|
|
2804
|
+
diagnostic_requirement.required_action_sha256s
|
|
2805
|
+
).issubset({value.action_sha256 for value in actions}):
|
|
2806
|
+
raise ValueError(
|
|
2807
|
+
"diagnostic allocation selected outside the market"
|
|
2808
|
+
)
|
|
2809
|
+
prior_decision = self.broker.select(
|
|
2810
|
+
MaterializedActionBrokerRequest(
|
|
2811
|
+
actions=actions,
|
|
2812
|
+
evaluation_slots=request.evaluation_slots,
|
|
2813
|
+
slate_value=self.slate_value,
|
|
2814
|
+
slate_feasibility=self.slate_feasibility,
|
|
2815
|
+
reference_escrow_slots=request.reference_escrow_slots,
|
|
2816
|
+
allocation_requirement=diagnostic_requirement,
|
|
2817
|
+
)
|
|
2818
|
+
)
|
|
2819
|
+
fixed_actions = tuple(
|
|
2820
|
+
sorted(
|
|
2821
|
+
set(prior_decision.required_reference_action_sha256s)
|
|
2822
|
+
| (
|
|
2823
|
+
set()
|
|
2824
|
+
if diagnostic_requirement is None
|
|
2825
|
+
else set(
|
|
2826
|
+
diagnostic_requirement.required_action_sha256s
|
|
2827
|
+
)
|
|
2828
|
+
)
|
|
2829
|
+
| (
|
|
2830
|
+
set()
|
|
2831
|
+
if prior_decision.exploration_requirement is None
|
|
2832
|
+
else set(
|
|
2833
|
+
prior_decision.exploration_requirement
|
|
2834
|
+
.required_action_sha256s
|
|
2835
|
+
)
|
|
2836
|
+
)
|
|
2837
|
+
)
|
|
2838
|
+
)
|
|
2839
|
+
adaptive_actions = await self.market_projector.project(
|
|
2840
|
+
request,
|
|
2841
|
+
proposals,
|
|
2842
|
+
actions,
|
|
2843
|
+
prior_decision.scores,
|
|
2844
|
+
fixed_actions,
|
|
2845
|
+
)
|
|
2846
|
+
if len(adaptive_actions) < request.evaluation_slots:
|
|
2847
|
+
raise ValueError(
|
|
2848
|
+
"phenotype-unique adaptive market cannot fill capacity"
|
|
2849
|
+
)
|
|
2850
|
+
adaptive_action_by_sha256 = {
|
|
2851
|
+
value.action_sha256: value for value in adaptive_actions
|
|
2852
|
+
}
|
|
2853
|
+
diagnostic = self.racing_policy.design_diagnostic_pilot(
|
|
2854
|
+
residual_request_sha256=request.request_sha256,
|
|
2855
|
+
actions=adaptive_actions,
|
|
2856
|
+
evaluation_slots=request.evaluation_slots,
|
|
2857
|
+
required_action_sha256s=fixed_actions,
|
|
2858
|
+
)
|
|
2859
|
+
proposal_sha256s = tuple(
|
|
2860
|
+
sorted(value.proposal_sha256 for value in proposals)
|
|
2861
|
+
)
|
|
2862
|
+
receipts: list[OutcomeAdaptiveResidualPhaseReceipt] = []
|
|
2863
|
+
acks: list[OutcomeAdaptiveResidualPhaseCommitAck] = []
|
|
2864
|
+
|
|
2865
|
+
market_receipt = OutcomeAdaptiveResidualPhaseReceipt(
|
|
2866
|
+
phase=OutcomeAdaptiveResidualPhase.MARKET_FROZEN,
|
|
2867
|
+
phase_ordinal=1,
|
|
2868
|
+
residual_request_sha256=request.request_sha256,
|
|
2869
|
+
diagnostic_decision_sha256=diagnostic.decision_sha256,
|
|
2870
|
+
product_sha256s=(
|
|
2871
|
+
*proposal_sha256s,
|
|
2872
|
+
prior_decision.decision_sha256,
|
|
2873
|
+
diagnostic.decision_sha256,
|
|
2874
|
+
*(
|
|
2875
|
+
()
|
|
2876
|
+
if forecast_geometry is None
|
|
2877
|
+
else (forecast_geometry.batch_sha256,)
|
|
2878
|
+
),
|
|
2879
|
+
),
|
|
2880
|
+
evidence=freeze_json(
|
|
2881
|
+
{
|
|
2882
|
+
"proposal_sha256s": list(proposal_sha256s),
|
|
2883
|
+
"proposal_action_count": len(actions),
|
|
2884
|
+
"adaptive_market_action_count": len(
|
|
2885
|
+
adaptive_actions
|
|
2886
|
+
),
|
|
2887
|
+
"fixed_action_sha256s": list(fixed_actions),
|
|
2888
|
+
"prior_broker_decision": (
|
|
2889
|
+
prior_decision.to_record(
|
|
2890
|
+
include_allocation_evidence=True
|
|
2891
|
+
)
|
|
2892
|
+
),
|
|
2893
|
+
"adaptive_actions": [
|
|
2894
|
+
value.to_record()
|
|
2895
|
+
for value in adaptive_actions
|
|
2896
|
+
],
|
|
2897
|
+
"diagnostic_decision": diagnostic.to_record(
|
|
2898
|
+
include_evidence=True
|
|
2899
|
+
),
|
|
2900
|
+
"market_projector": {
|
|
2901
|
+
"projector_id": (
|
|
2902
|
+
self.market_projector.projector_id
|
|
2903
|
+
),
|
|
2904
|
+
"projector_version": (
|
|
2905
|
+
self.market_projector.projector_version
|
|
2906
|
+
),
|
|
2907
|
+
"definition_sha256": (
|
|
2908
|
+
self.market_projector.definition_sha256
|
|
2909
|
+
),
|
|
2910
|
+
"state_sha256": (
|
|
2911
|
+
self.market_projector.state_sha256
|
|
2912
|
+
),
|
|
2913
|
+
},
|
|
2914
|
+
**(
|
|
2915
|
+
{}
|
|
2916
|
+
if forecast_geometry is None
|
|
2917
|
+
else {
|
|
2918
|
+
"forecast_opportunity_challenger": {
|
|
2919
|
+
"challenger_id": (
|
|
2920
|
+
self.forecast_opportunity_challenger
|
|
2921
|
+
.challenger_id
|
|
2922
|
+
),
|
|
2923
|
+
"challenger_version": (
|
|
2924
|
+
self.forecast_opportunity_challenger
|
|
2925
|
+
.challenger_version
|
|
2926
|
+
),
|
|
2927
|
+
"definition_sha256": (
|
|
2928
|
+
self.forecast_opportunity_challenger
|
|
2929
|
+
.definition_sha256
|
|
2930
|
+
),
|
|
2931
|
+
},
|
|
2932
|
+
"forecast_geometry": (
|
|
2933
|
+
forecast_geometry.to_record(
|
|
2934
|
+
include_evidence=True
|
|
2935
|
+
)
|
|
2936
|
+
),
|
|
2937
|
+
"forecast_geometry_frozen_before_"
|
|
2938
|
+
"diagnostic_outcomes": True,
|
|
2939
|
+
}
|
|
2940
|
+
),
|
|
2941
|
+
"current_candidate_outcomes_observed": False,
|
|
2942
|
+
"all_actions_materialized": True,
|
|
2943
|
+
}
|
|
2944
|
+
),
|
|
2945
|
+
)
|
|
2946
|
+
receipts.append(market_receipt)
|
|
2947
|
+
ack = await self._commit(market_receipt)
|
|
2948
|
+
if ack is not None:
|
|
2949
|
+
acks.append(ack)
|
|
2950
|
+
|
|
2951
|
+
diagnostic_batches = await evaluate_materialized_action_subset(
|
|
2952
|
+
experts=self.experts,
|
|
2953
|
+
proposals=proposals,
|
|
2954
|
+
selected_action_sha256s=(
|
|
2955
|
+
diagnostic.selected_action_sha256s
|
|
2956
|
+
),
|
|
2957
|
+
)
|
|
2958
|
+
diagnostic_evaluations = _flatten(diagnostic_batches)
|
|
2959
|
+
outcomes = list(
|
|
2960
|
+
self.outcome_projector.project(
|
|
2961
|
+
diagnostic_evaluations
|
|
2962
|
+
)
|
|
2963
|
+
)
|
|
2964
|
+
diagnostic_joint_gain = self.outcome_projector.joint_gain(
|
|
2965
|
+
diagnostic_evaluations
|
|
2966
|
+
)
|
|
2967
|
+
diagnostic_set_outcome = (
|
|
2968
|
+
self.outcome_projector.project_set_outcome(
|
|
2969
|
+
(),
|
|
2970
|
+
diagnostic_evaluations,
|
|
2971
|
+
)
|
|
2972
|
+
)
|
|
2973
|
+
if not math.isclose(
|
|
2974
|
+
diagnostic_joint_gain,
|
|
2975
|
+
diagnostic_set_outcome.current_wave_fixed_set_gain,
|
|
2976
|
+
rel_tol=1e-12,
|
|
2977
|
+
abs_tol=1e-15,
|
|
2978
|
+
):
|
|
2979
|
+
raise ValueError(
|
|
2980
|
+
"diagnostic joint utility projections disagree"
|
|
2981
|
+
)
|
|
2982
|
+
set_outcomes = [diagnostic_set_outcome]
|
|
2983
|
+
selected_evaluations = list(diagnostic_evaluations)
|
|
2984
|
+
waves = [diagnostic_batches]
|
|
2985
|
+
diagnostic_receipt = OutcomeAdaptiveResidualPhaseReceipt(
|
|
2986
|
+
phase=OutcomeAdaptiveResidualPhase.DIAGNOSTIC_EVALUATED,
|
|
2987
|
+
phase_ordinal=2,
|
|
2988
|
+
residual_request_sha256=request.request_sha256,
|
|
2989
|
+
diagnostic_decision_sha256=diagnostic.decision_sha256,
|
|
2990
|
+
product_sha256s=(
|
|
2991
|
+
*(
|
|
2992
|
+
value.batch_sha256
|
|
2993
|
+
for value in diagnostic_batches
|
|
2994
|
+
),
|
|
2995
|
+
*(value.outcome_sha256 for value in outcomes),
|
|
2996
|
+
diagnostic_set_outcome.set_outcome_sha256,
|
|
2997
|
+
),
|
|
2998
|
+
evidence=freeze_json(
|
|
2999
|
+
{
|
|
3000
|
+
"diagnostic_evaluation_batches": [
|
|
3001
|
+
value.to_record(include_evidence=True)
|
|
3002
|
+
for value in diagnostic_batches
|
|
3003
|
+
],
|
|
3004
|
+
"diagnostic_outcomes": [
|
|
3005
|
+
value.to_record() for value in outcomes
|
|
3006
|
+
],
|
|
3007
|
+
"diagnostic_joint_gain_hex": (
|
|
3008
|
+
diagnostic_joint_gain.hex()
|
|
3009
|
+
),
|
|
3010
|
+
"diagnostic_set_outcome": (
|
|
3011
|
+
diagnostic_set_outcome.to_record()
|
|
3012
|
+
),
|
|
3013
|
+
"causal_set_outcome_policy_role": (
|
|
3014
|
+
"selection_input"
|
|
3015
|
+
if uses_causal_set_outcomes
|
|
3016
|
+
else "observational_only"
|
|
3017
|
+
),
|
|
3018
|
+
"current_prefix_candidate_outcomes_policy_role": (
|
|
3019
|
+
"selection_input"
|
|
3020
|
+
if self.forecast_opportunity_challenger
|
|
3021
|
+
is not None
|
|
3022
|
+
else "observational_only"
|
|
3023
|
+
),
|
|
3024
|
+
"later_candidate_outcomes_observed": False,
|
|
3025
|
+
"next_adaptive_decision_exists": False,
|
|
3026
|
+
}
|
|
3027
|
+
),
|
|
3028
|
+
)
|
|
3029
|
+
receipts.append(diagnostic_receipt)
|
|
3030
|
+
ack = await self._commit(diagnostic_receipt)
|
|
3031
|
+
if ack is not None:
|
|
3032
|
+
acks.append(ack)
|
|
3033
|
+
|
|
3034
|
+
selected = set(diagnostic.selected_action_sha256s)
|
|
3035
|
+
continuation_decisions: list[AdaptiveActionRacingDecision] = []
|
|
3036
|
+
paired_audit_executions: list[
|
|
3037
|
+
OutcomeAdaptivePairedAuditExecution
|
|
3038
|
+
] = []
|
|
3039
|
+
forecast_calibration_observations: list[
|
|
3040
|
+
ArchiveOpportunityCalibrationObservation
|
|
3041
|
+
] = []
|
|
3042
|
+
counterfactual_quarantined_action_sha256s: set[str] = set()
|
|
3043
|
+
paired_audit_adjudicator = (
|
|
3044
|
+
None
|
|
3045
|
+
if (
|
|
3046
|
+
self.paired_audit_designer is None
|
|
3047
|
+
and self.forecast_opportunity_shadow_designer is None
|
|
3048
|
+
)
|
|
3049
|
+
else SamePrefixPairedAuditAdjudicator()
|
|
3050
|
+
)
|
|
3051
|
+
while len(selected) < request.evaluation_slots:
|
|
3052
|
+
excluded_action_sha256s = tuple(
|
|
3053
|
+
sorted(counterfactual_quarantined_action_sha256s)
|
|
3054
|
+
)
|
|
3055
|
+
fallback_decision = self.racing_policy.select_next(
|
|
3056
|
+
residual_request_sha256=request.request_sha256,
|
|
3057
|
+
actions=adaptive_actions,
|
|
3058
|
+
evaluation_slots=request.evaluation_slots,
|
|
3059
|
+
diagnostic_action_sha256s=(
|
|
3060
|
+
diagnostic.selected_action_sha256s
|
|
3061
|
+
),
|
|
3062
|
+
diagnostic_joint_gain=diagnostic_joint_gain,
|
|
3063
|
+
selected_action_sha256s=tuple(sorted(selected)),
|
|
3064
|
+
outcomes=tuple(outcomes),
|
|
3065
|
+
set_outcomes=tuple(set_outcomes),
|
|
3066
|
+
excluded_action_sha256s=excluded_action_sha256s,
|
|
3067
|
+
)
|
|
3068
|
+
decision = (
|
|
3069
|
+
fallback_decision
|
|
3070
|
+
if self.forecast_opportunity_challenger is None
|
|
3071
|
+
else self.forecast_opportunity_challenger.challenge(
|
|
3072
|
+
fallback=fallback_decision,
|
|
3073
|
+
geometry=forecast_geometry,
|
|
3074
|
+
adaptive_actions=adaptive_actions,
|
|
3075
|
+
selected_evaluations=tuple(
|
|
3076
|
+
selected_evaluations
|
|
3077
|
+
),
|
|
3078
|
+
excluded_action_sha256s=(
|
|
3079
|
+
excluded_action_sha256s
|
|
3080
|
+
),
|
|
3081
|
+
)
|
|
3082
|
+
)
|
|
3083
|
+
continuation_decisions.append(decision)
|
|
3084
|
+
paired_plan: SamePrefixPairedAuditPlan | None = None
|
|
3085
|
+
paired_plan_receipt: (
|
|
3086
|
+
OutcomeAdaptiveResidualPhaseReceipt | None
|
|
3087
|
+
) = None
|
|
3088
|
+
if (
|
|
3089
|
+
self.paired_audit_designer is not None
|
|
3090
|
+
and decision.wave is AdaptiveActionWave.RANDOMIZED_AUDIT
|
|
3091
|
+
):
|
|
3092
|
+
paired_plan = self.paired_audit_designer.design(
|
|
3093
|
+
decision=decision,
|
|
3094
|
+
actions=adaptive_actions,
|
|
3095
|
+
)
|
|
3096
|
+
elif self.forecast_opportunity_shadow_designer is not None:
|
|
3097
|
+
paired_plan = (
|
|
3098
|
+
self.forecast_opportunity_shadow_designer.design(
|
|
3099
|
+
adaptive_step=len(continuation_decisions),
|
|
3100
|
+
remaining_authoritative_slots_after_decision=(
|
|
3101
|
+
request.evaluation_slots
|
|
3102
|
+
- len(selected)
|
|
3103
|
+
- len(decision.selected_action_sha256s)
|
|
3104
|
+
),
|
|
3105
|
+
decision=decision,
|
|
3106
|
+
fallback=fallback_decision,
|
|
3107
|
+
actions=adaptive_actions,
|
|
3108
|
+
)
|
|
3109
|
+
)
|
|
3110
|
+
if paired_plan is not None:
|
|
3111
|
+
paired_plan_receipt = OutcomeAdaptiveResidualPhaseReceipt(
|
|
3112
|
+
phase=(
|
|
3113
|
+
OutcomeAdaptiveResidualPhase.PAIRED_AUDIT_FROZEN
|
|
3114
|
+
),
|
|
3115
|
+
phase_ordinal=len(receipts) + 1,
|
|
3116
|
+
residual_request_sha256=request.request_sha256,
|
|
3117
|
+
diagnostic_decision_sha256=(
|
|
3118
|
+
diagnostic.decision_sha256
|
|
3119
|
+
),
|
|
3120
|
+
product_sha256s=(
|
|
3121
|
+
decision.decision_sha256,
|
|
3122
|
+
paired_plan.plan_sha256,
|
|
3123
|
+
),
|
|
3124
|
+
evidence=freeze_json(
|
|
3125
|
+
{
|
|
3126
|
+
"adaptive_step": len(
|
|
3127
|
+
continuation_decisions
|
|
3128
|
+
),
|
|
3129
|
+
"racing_decision_sha256": (
|
|
3130
|
+
decision.decision_sha256
|
|
3131
|
+
),
|
|
3132
|
+
"plan_sha256": paired_plan.plan_sha256,
|
|
3133
|
+
"plan": paired_plan.to_record(
|
|
3134
|
+
include_evidence=True
|
|
3135
|
+
),
|
|
3136
|
+
"current_arm_outcomes_observed": False,
|
|
3137
|
+
"plan_frozen_before_arm_evaluation": True,
|
|
3138
|
+
"durable_commit_required": (
|
|
3139
|
+
self.require_durable_phase_commits
|
|
3140
|
+
),
|
|
3141
|
+
"assay_union_may_enter_authoritative_archive": (
|
|
3142
|
+
False
|
|
3143
|
+
),
|
|
3144
|
+
}
|
|
3145
|
+
),
|
|
3146
|
+
)
|
|
3147
|
+
receipts.append(paired_plan_receipt)
|
|
3148
|
+
ack = await self._commit(paired_plan_receipt)
|
|
3149
|
+
if ack is not None:
|
|
3150
|
+
acks.append(ack)
|
|
3151
|
+
step_batches = await evaluate_materialized_action_subset(
|
|
3152
|
+
experts=self.experts,
|
|
3153
|
+
proposals=proposals,
|
|
3154
|
+
selected_action_sha256s=(
|
|
3155
|
+
decision.selected_action_sha256s
|
|
3156
|
+
),
|
|
3157
|
+
)
|
|
3158
|
+
step_evaluations = _flatten(step_batches)
|
|
3159
|
+
step_outcomes = self.outcome_projector.project(
|
|
3160
|
+
step_evaluations
|
|
3161
|
+
)
|
|
3162
|
+
step_set_outcome = (
|
|
3163
|
+
self.outcome_projector.project_set_outcome(
|
|
3164
|
+
tuple(selected_evaluations),
|
|
3165
|
+
step_evaluations,
|
|
3166
|
+
)
|
|
3167
|
+
)
|
|
3168
|
+
paired_execution: OutcomeAdaptivePairedAuditExecution | None = None
|
|
3169
|
+
forecast_calibration_observation: (
|
|
3170
|
+
ArchiveOpportunityCalibrationObservation | None
|
|
3171
|
+
) = None
|
|
3172
|
+
if paired_plan is not None:
|
|
3173
|
+
if (
|
|
3174
|
+
paired_plan_receipt is None
|
|
3175
|
+
or paired_audit_adjudicator is None
|
|
3176
|
+
):
|
|
3177
|
+
raise RuntimeError(
|
|
3178
|
+
"paired audit plan lacks its frozen execution context"
|
|
3179
|
+
)
|
|
3180
|
+
counterfactual_action_sha256 = (
|
|
3181
|
+
paired_plan.exploration_action_sha256
|
|
3182
|
+
if paired_plan.authoritative_arm
|
|
3183
|
+
is SamePrefixPairedAuditArm.LEGACY
|
|
3184
|
+
else paired_plan.legacy_action_sha256
|
|
3185
|
+
)
|
|
3186
|
+
counterfactual_batches = (
|
|
3187
|
+
await evaluate_materialized_action_counterfactual_subset(
|
|
3188
|
+
experts=self.experts,
|
|
3189
|
+
proposals=proposals,
|
|
3190
|
+
selected_action_sha256s=(
|
|
3191
|
+
counterfactual_action_sha256,
|
|
3192
|
+
),
|
|
3193
|
+
)
|
|
3194
|
+
)
|
|
3195
|
+
counterfactual_evaluations = _flatten(
|
|
3196
|
+
counterfactual_batches
|
|
3197
|
+
)
|
|
3198
|
+
counterfactual_outcomes = (
|
|
3199
|
+
self.outcome_projector.project(
|
|
3200
|
+
counterfactual_evaluations
|
|
3201
|
+
)
|
|
3202
|
+
)
|
|
3203
|
+
counterfactual_set_outcome = (
|
|
3204
|
+
self.outcome_projector.project_set_outcome(
|
|
3205
|
+
tuple(selected_evaluations),
|
|
3206
|
+
counterfactual_evaluations,
|
|
3207
|
+
)
|
|
3208
|
+
)
|
|
3209
|
+
if (
|
|
3210
|
+
len(step_outcomes) != 1
|
|
3211
|
+
or len(counterfactual_outcomes) != 1
|
|
3212
|
+
):
|
|
3213
|
+
raise ValueError(
|
|
3214
|
+
"paired audit arms must each contain one action"
|
|
3215
|
+
)
|
|
3216
|
+
authoritative_outcome = step_outcomes[0]
|
|
3217
|
+
counterfactual_outcome = counterfactual_outcomes[0]
|
|
3218
|
+
if (
|
|
3219
|
+
paired_plan.authoritative_arm
|
|
3220
|
+
is SamePrefixPairedAuditArm.LEGACY
|
|
3221
|
+
):
|
|
3222
|
+
legacy_outcome = authoritative_outcome
|
|
3223
|
+
legacy_set_outcome = step_set_outcome
|
|
3224
|
+
exploration_outcome = counterfactual_outcome
|
|
3225
|
+
exploration_set_outcome = (
|
|
3226
|
+
counterfactual_set_outcome
|
|
3227
|
+
)
|
|
3228
|
+
else:
|
|
3229
|
+
legacy_outcome = counterfactual_outcome
|
|
3230
|
+
legacy_set_outcome = counterfactual_set_outcome
|
|
3231
|
+
exploration_outcome = authoritative_outcome
|
|
3232
|
+
exploration_set_outcome = step_set_outcome
|
|
3233
|
+
paired_observation = (
|
|
3234
|
+
paired_audit_adjudicator.adjudicate(
|
|
3235
|
+
plan=paired_plan,
|
|
3236
|
+
legacy_outcome=legacy_outcome,
|
|
3237
|
+
exploration_outcome=exploration_outcome,
|
|
3238
|
+
legacy_set_outcome=legacy_set_outcome,
|
|
3239
|
+
exploration_set_outcome=(
|
|
3240
|
+
exploration_set_outcome
|
|
3241
|
+
),
|
|
3242
|
+
)
|
|
3243
|
+
)
|
|
3244
|
+
paired_execution = OutcomeAdaptivePairedAuditExecution(
|
|
3245
|
+
plan=paired_plan,
|
|
3246
|
+
observation=paired_observation,
|
|
3247
|
+
counterfactual_evaluation_batches=(
|
|
3248
|
+
counterfactual_batches
|
|
3249
|
+
),
|
|
3250
|
+
plan_receipt_sha256=(
|
|
3251
|
+
paired_plan_receipt.receipt_sha256
|
|
3252
|
+
),
|
|
3253
|
+
)
|
|
3254
|
+
paired_audit_executions.append(paired_execution)
|
|
3255
|
+
counterfactual_quarantined_action_sha256s.add(
|
|
3256
|
+
paired_execution.counterfactual_action_sha256
|
|
3257
|
+
)
|
|
3258
|
+
if (
|
|
3259
|
+
paired_plan.designer_id
|
|
3260
|
+
in FORECAST_OPPORTUNITY_SAME_PREFIX_AUDIT_DESIGNER_IDS
|
|
3261
|
+
):
|
|
3262
|
+
forecast_calibration_observation = (
|
|
3263
|
+
ForecastOpportunityShadowCalibrationProjector().project(
|
|
3264
|
+
decision_index=request.decision_index,
|
|
3265
|
+
evidence_cutoff_ordinal=request.decision_index,
|
|
3266
|
+
decision=decision,
|
|
3267
|
+
action=adaptive_action_by_sha256[
|
|
3268
|
+
paired_plan.exploration_action_sha256
|
|
3269
|
+
],
|
|
3270
|
+
observation=paired_observation,
|
|
3271
|
+
)
|
|
3272
|
+
)
|
|
3273
|
+
forecast_calibration_observations.append(
|
|
3274
|
+
forecast_calibration_observation
|
|
3275
|
+
)
|
|
3276
|
+
outcomes.extend(step_outcomes)
|
|
3277
|
+
set_outcomes.append(step_set_outcome)
|
|
3278
|
+
selected_evaluations.extend(step_evaluations)
|
|
3279
|
+
waves.append(step_batches)
|
|
3280
|
+
selected.update(decision.selected_action_sha256s)
|
|
3281
|
+
step_receipt = OutcomeAdaptiveResidualPhaseReceipt(
|
|
3282
|
+
phase=(
|
|
3283
|
+
OutcomeAdaptiveResidualPhase
|
|
3284
|
+
.ADAPTIVE_STEP_EVALUATED
|
|
3285
|
+
),
|
|
3286
|
+
phase_ordinal=len(receipts) + 1,
|
|
3287
|
+
residual_request_sha256=request.request_sha256,
|
|
3288
|
+
diagnostic_decision_sha256=(
|
|
3289
|
+
diagnostic.decision_sha256
|
|
3290
|
+
),
|
|
3291
|
+
product_sha256s=(
|
|
3292
|
+
decision.decision_sha256,
|
|
3293
|
+
*(value.batch_sha256 for value in step_batches),
|
|
3294
|
+
*(
|
|
3295
|
+
value.outcome_sha256
|
|
3296
|
+
for value in step_outcomes
|
|
3297
|
+
),
|
|
3298
|
+
step_set_outcome.set_outcome_sha256,
|
|
3299
|
+
*(
|
|
3300
|
+
()
|
|
3301
|
+
if paired_execution is None
|
|
3302
|
+
else (
|
|
3303
|
+
paired_execution.execution_sha256,
|
|
3304
|
+
paired_execution.observation.observation_sha256,
|
|
3305
|
+
*(
|
|
3306
|
+
()
|
|
3307
|
+
if forecast_calibration_observation is None
|
|
3308
|
+
else (
|
|
3309
|
+
forecast_calibration_observation
|
|
3310
|
+
.observation_sha256,
|
|
3311
|
+
)
|
|
3312
|
+
),
|
|
3313
|
+
*(
|
|
3314
|
+
value.batch_sha256
|
|
3315
|
+
for value in (
|
|
3316
|
+
paired_execution
|
|
3317
|
+
.counterfactual_evaluation_batches
|
|
3318
|
+
)
|
|
3319
|
+
),
|
|
3320
|
+
)
|
|
3321
|
+
),
|
|
3322
|
+
),
|
|
3323
|
+
evidence=freeze_json(
|
|
3324
|
+
{
|
|
3325
|
+
"adaptive_step": len(
|
|
3326
|
+
continuation_decisions
|
|
3327
|
+
),
|
|
3328
|
+
"decision": decision.to_record(
|
|
3329
|
+
include_evidence=True
|
|
3330
|
+
),
|
|
3331
|
+
"evaluation_batches": [
|
|
3332
|
+
value.to_record(include_evidence=True)
|
|
3333
|
+
for value in step_batches
|
|
3334
|
+
],
|
|
3335
|
+
"outcomes": [
|
|
3336
|
+
value.to_record()
|
|
3337
|
+
for value in step_outcomes
|
|
3338
|
+
],
|
|
3339
|
+
"set_outcome": (
|
|
3340
|
+
step_set_outcome.to_record()
|
|
3341
|
+
),
|
|
3342
|
+
**(
|
|
3343
|
+
{}
|
|
3344
|
+
if paired_execution is None
|
|
3345
|
+
else {
|
|
3346
|
+
"paired_audit_execution": (
|
|
3347
|
+
paired_execution.to_record(
|
|
3348
|
+
include_evidence=True
|
|
3349
|
+
)
|
|
3350
|
+
),
|
|
3351
|
+
"paired_audit_counterfactual_excluded_from_"
|
|
3352
|
+
"authoritative_archive": True,
|
|
3353
|
+
**(
|
|
3354
|
+
{}
|
|
3355
|
+
if forecast_calibration_observation is None
|
|
3356
|
+
else {
|
|
3357
|
+
"forecast_opportunity_calibration_"
|
|
3358
|
+
"observation": (
|
|
3359
|
+
forecast_calibration_observation
|
|
3360
|
+
.to_record()
|
|
3361
|
+
)
|
|
3362
|
+
}
|
|
3363
|
+
),
|
|
3364
|
+
}
|
|
3365
|
+
),
|
|
3366
|
+
"causal_set_outcome_policy_role": (
|
|
3367
|
+
"selection_input"
|
|
3368
|
+
if uses_causal_set_outcomes
|
|
3369
|
+
else "observational_only"
|
|
3370
|
+
),
|
|
3371
|
+
"current_prefix_candidate_outcomes_policy_role": (
|
|
3372
|
+
"selection_input"
|
|
3373
|
+
if self.forecast_opportunity_challenger
|
|
3374
|
+
is not None
|
|
3375
|
+
else "observational_only"
|
|
3376
|
+
),
|
|
3377
|
+
"selected_action_count_after_step": len(
|
|
3378
|
+
selected
|
|
3379
|
+
),
|
|
3380
|
+
"unobserved_candidate_outcomes_available": (
|
|
3381
|
+
False
|
|
3382
|
+
),
|
|
3383
|
+
"next_adaptive_decision_exists": False,
|
|
3384
|
+
}
|
|
3385
|
+
),
|
|
3386
|
+
)
|
|
3387
|
+
receipts.append(step_receipt)
|
|
3388
|
+
ack = await self._commit(step_receipt)
|
|
3389
|
+
if ack is not None:
|
|
3390
|
+
acks.append(ack)
|
|
3391
|
+
|
|
3392
|
+
directive = AdaptiveActionAllocationDirective(
|
|
3393
|
+
policy_id=(
|
|
3394
|
+
self.racing_policy.policy_id
|
|
3395
|
+
if self.forecast_opportunity_challenger is None
|
|
3396
|
+
else self.forecast_opportunity_challenger.challenger_id
|
|
3397
|
+
),
|
|
3398
|
+
policy_version=(
|
|
3399
|
+
self.racing_policy.policy_version
|
|
3400
|
+
if self.forecast_opportunity_challenger is None
|
|
3401
|
+
else self.forecast_opportunity_challenger
|
|
3402
|
+
.challenger_version
|
|
3403
|
+
),
|
|
3404
|
+
policy_definition_sha256=(
|
|
3405
|
+
self.racing_policy.definition_sha256
|
|
3406
|
+
if self.forecast_opportunity_challenger is None
|
|
3407
|
+
else self.forecast_opportunity_challenger
|
|
3408
|
+
.definition_sha256
|
|
3409
|
+
),
|
|
3410
|
+
residual_request_sha256=request.request_sha256,
|
|
3411
|
+
proposal_sha256s=proposal_sha256s,
|
|
3412
|
+
required_action_sha256s=tuple(sorted(selected)),
|
|
3413
|
+
diagnostic_decision_sha256=diagnostic.decision_sha256,
|
|
3414
|
+
continuation_decision_sha256s=tuple(
|
|
3415
|
+
sorted(
|
|
3416
|
+
value.decision_sha256
|
|
3417
|
+
for value in continuation_decisions
|
|
3418
|
+
)
|
|
3419
|
+
),
|
|
3420
|
+
observed_outcome_sha256s=tuple(
|
|
3421
|
+
sorted(value.outcome_sha256 for value in outcomes)
|
|
3422
|
+
),
|
|
3423
|
+
observed_set_outcome_sha256s=tuple(
|
|
3424
|
+
sorted(
|
|
3425
|
+
value.set_outcome_sha256
|
|
3426
|
+
for value in set_outcomes
|
|
3427
|
+
)
|
|
3428
|
+
),
|
|
3429
|
+
evidence=freeze_json(
|
|
3430
|
+
{
|
|
3431
|
+
"market_receipt_sha256": (
|
|
3432
|
+
market_receipt.receipt_sha256
|
|
3433
|
+
),
|
|
3434
|
+
"diagnostic_receipt_sha256": (
|
|
3435
|
+
diagnostic_receipt.receipt_sha256
|
|
3436
|
+
),
|
|
3437
|
+
"adaptive_step_receipt_sha256s": [
|
|
3438
|
+
value.receipt_sha256
|
|
3439
|
+
for value in receipts
|
|
3440
|
+
if value.phase
|
|
3441
|
+
is OutcomeAdaptiveResidualPhase
|
|
3442
|
+
.ADAPTIVE_STEP_EVALUATED
|
|
3443
|
+
],
|
|
3444
|
+
"diagnostic_joint_gain_hex": (
|
|
3445
|
+
diagnostic_joint_gain.hex()
|
|
3446
|
+
),
|
|
3447
|
+
"set_outcome_sha256s": [
|
|
3448
|
+
value.set_outcome_sha256
|
|
3449
|
+
for value in set_outcomes
|
|
3450
|
+
],
|
|
3451
|
+
**(
|
|
3452
|
+
{}
|
|
3453
|
+
if not paired_audit_executions
|
|
3454
|
+
else {
|
|
3455
|
+
"paired_audit_plan_receipt_sha256s": [
|
|
3456
|
+
value.plan_receipt_sha256
|
|
3457
|
+
for value in paired_audit_executions
|
|
3458
|
+
],
|
|
3459
|
+
"paired_audit_execution_sha256s": [
|
|
3460
|
+
value.execution_sha256
|
|
3461
|
+
for value in paired_audit_executions
|
|
3462
|
+
],
|
|
3463
|
+
"paired_audit_physical_extra_real_evaluation_count": (
|
|
3464
|
+
len(paired_audit_executions)
|
|
3465
|
+
),
|
|
3466
|
+
"paired_audit_union_admitted_to_"
|
|
3467
|
+
"authoritative_archive": False,
|
|
3468
|
+
}
|
|
3469
|
+
),
|
|
3470
|
+
"causal_set_outcomes_used_for_selection": (
|
|
3471
|
+
uses_causal_set_outcomes
|
|
3472
|
+
),
|
|
3473
|
+
"current_prefix_candidate_outcomes_used_for_selection": (
|
|
3474
|
+
self.forecast_opportunity_challenger is not None
|
|
3475
|
+
),
|
|
3476
|
+
"eligible_candidate_outcomes_observed": False,
|
|
3477
|
+
"all_selected_actions_really_evaluated": True,
|
|
3478
|
+
"unobserved_candidate_outcomes_available": False,
|
|
3479
|
+
"workload_model_provider_prompt_branches": False,
|
|
3480
|
+
}
|
|
3481
|
+
),
|
|
3482
|
+
)
|
|
3483
|
+
final_decision = self.broker.select(
|
|
3484
|
+
MaterializedActionBrokerRequest(
|
|
3485
|
+
actions=actions,
|
|
3486
|
+
evaluation_slots=request.evaluation_slots,
|
|
3487
|
+
slate_value=self.slate_value,
|
|
3488
|
+
slate_feasibility=self.slate_feasibility,
|
|
3489
|
+
reference_escrow_slots=request.reference_escrow_slots,
|
|
3490
|
+
allocation_requirement=directive,
|
|
3491
|
+
)
|
|
3492
|
+
)
|
|
3493
|
+
if {
|
|
3494
|
+
value.action_sha256
|
|
3495
|
+
for value in final_decision.selected_actions
|
|
3496
|
+
} != selected:
|
|
3497
|
+
raise ValueError("final broker did not honor adaptive directive")
|
|
3498
|
+
merged = _merge_waves(proposals, tuple(waves))
|
|
3499
|
+
combined = ResidualPortfolioEvolutionResult(
|
|
3500
|
+
request=request,
|
|
3501
|
+
proposals=proposals,
|
|
3502
|
+
broker_decision=final_decision,
|
|
3503
|
+
evaluation_batches=merged,
|
|
3504
|
+
slate_value_definition_sha256=(
|
|
3505
|
+
self.slate_value.definition_sha256
|
|
3506
|
+
),
|
|
3507
|
+
slate_feasibility_definition_sha256=(
|
|
3508
|
+
self.slate_feasibility.definition_sha256
|
|
3509
|
+
),
|
|
3510
|
+
)
|
|
3511
|
+
final_receipt = OutcomeAdaptiveResidualPhaseReceipt(
|
|
3512
|
+
phase=OutcomeAdaptiveResidualPhase.FINALIZED,
|
|
3513
|
+
phase_ordinal=len(receipts) + 1,
|
|
3514
|
+
residual_request_sha256=request.request_sha256,
|
|
3515
|
+
diagnostic_decision_sha256=diagnostic.decision_sha256,
|
|
3516
|
+
product_sha256s=(
|
|
3517
|
+
directive.directive_sha256,
|
|
3518
|
+
final_decision.decision_sha256,
|
|
3519
|
+
combined.result_sha256,
|
|
3520
|
+
*(
|
|
3521
|
+
value.execution_sha256
|
|
3522
|
+
for value in paired_audit_executions
|
|
3523
|
+
),
|
|
3524
|
+
),
|
|
3525
|
+
evidence=freeze_json(
|
|
3526
|
+
{
|
|
3527
|
+
"allocation_directive": directive.to_record(
|
|
3528
|
+
include_evidence=True
|
|
3529
|
+
),
|
|
3530
|
+
"final_broker_decision": (
|
|
3531
|
+
final_decision.to_record(
|
|
3532
|
+
include_allocation_evidence=True
|
|
3533
|
+
)
|
|
3534
|
+
),
|
|
3535
|
+
"combined_result_sha256": combined.result_sha256,
|
|
3536
|
+
"real_evaluation_budget_preserved": (
|
|
3537
|
+
not paired_audit_executions
|
|
3538
|
+
),
|
|
3539
|
+
**(
|
|
3540
|
+
{}
|
|
3541
|
+
if not paired_audit_executions
|
|
3542
|
+
else {
|
|
3543
|
+
"selected_real_evaluation_budget_preserved": True,
|
|
3544
|
+
"physical_real_evaluation_budget_includes_"
|
|
3545
|
+
"assay_extras": True,
|
|
3546
|
+
"paired_audit_physical_extra_real_"
|
|
3547
|
+
"evaluation_count": len(
|
|
3548
|
+
paired_audit_executions
|
|
3549
|
+
),
|
|
3550
|
+
"paired_audit_execution_sha256s": [
|
|
3551
|
+
value.execution_sha256
|
|
3552
|
+
for value in paired_audit_executions
|
|
3553
|
+
],
|
|
3554
|
+
"paired_audit_union_admitted_to_"
|
|
3555
|
+
"authoritative_archive": False,
|
|
3556
|
+
}
|
|
3557
|
+
),
|
|
3558
|
+
"selected_action_count": len(selected),
|
|
3559
|
+
"set_outcome_sha256s": [
|
|
3560
|
+
value.set_outcome_sha256
|
|
3561
|
+
for value in set_outcomes
|
|
3562
|
+
],
|
|
3563
|
+
"causal_set_outcomes_used_for_selection": (
|
|
3564
|
+
uses_causal_set_outcomes
|
|
3565
|
+
),
|
|
3566
|
+
"current_prefix_candidate_outcomes_used_for_selection": (
|
|
3567
|
+
self.forecast_opportunity_challenger is not None
|
|
3568
|
+
),
|
|
3569
|
+
"eligible_candidate_outcomes_observed": False,
|
|
3570
|
+
}
|
|
3571
|
+
),
|
|
3572
|
+
)
|
|
3573
|
+
receipts.append(final_receipt)
|
|
3574
|
+
ack = await self._commit(final_receipt)
|
|
3575
|
+
if ack is not None:
|
|
3576
|
+
acks.append(ack)
|
|
3577
|
+
return OutcomeAdaptiveResidualPortfolioEvolutionResult(
|
|
3578
|
+
result=combined,
|
|
3579
|
+
prior_broker_decision=prior_decision,
|
|
3580
|
+
adaptive_actions=adaptive_actions,
|
|
3581
|
+
diagnostic_decision=diagnostic,
|
|
3582
|
+
continuation_decisions=tuple(continuation_decisions),
|
|
3583
|
+
evaluation_waves=tuple(waves),
|
|
3584
|
+
outcomes=tuple(
|
|
3585
|
+
sorted(
|
|
3586
|
+
outcomes,
|
|
3587
|
+
key=lambda value: value.action_sha256,
|
|
3588
|
+
)
|
|
3589
|
+
),
|
|
3590
|
+
set_outcomes=tuple(set_outcomes),
|
|
3591
|
+
diagnostic_joint_gain=diagnostic_joint_gain,
|
|
3592
|
+
allocation_directive=directive,
|
|
3593
|
+
phase_receipts=tuple(receipts),
|
|
3594
|
+
phase_commit_acks=tuple(acks),
|
|
3595
|
+
market_projector_definition_sha256=(
|
|
3596
|
+
self.market_projector.definition_sha256
|
|
3597
|
+
),
|
|
3598
|
+
market_projector_state_sha256=(
|
|
3599
|
+
self.market_projector.state_sha256
|
|
3600
|
+
),
|
|
3601
|
+
outcome_projector_definition_sha256=(
|
|
3602
|
+
self.outcome_projector.definition_sha256
|
|
3603
|
+
),
|
|
3604
|
+
forecast_opportunity_challenger_definition_sha256=(
|
|
3605
|
+
None
|
|
3606
|
+
if self.forecast_opportunity_challenger is None
|
|
3607
|
+
else self.forecast_opportunity_challenger
|
|
3608
|
+
.definition_sha256
|
|
3609
|
+
),
|
|
3610
|
+
paired_audit_executions=tuple(paired_audit_executions),
|
|
3611
|
+
forecast_opportunity_calibration_observations=tuple(
|
|
3612
|
+
forecast_calibration_observations
|
|
3613
|
+
),
|
|
3614
|
+
method_definition_sha256=(
|
|
3615
|
+
OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_STRATIFIED_AUDIT_EVOLUTION_DEFINITION_SHA256
|
|
3616
|
+
if (
|
|
3617
|
+
any(
|
|
3618
|
+
value.plan.designer_id
|
|
3619
|
+
== FORECAST_STRATIFIED_SAME_PREFIX_AUDIT_DESIGNER_ID
|
|
3620
|
+
for value in paired_audit_executions
|
|
3621
|
+
)
|
|
3622
|
+
)
|
|
3623
|
+
else (
|
|
3624
|
+
OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_SHADOW_EVOLUTION_DEFINITION_SHA256
|
|
3625
|
+
if (
|
|
3626
|
+
self.forecast_opportunity_challenger is not None
|
|
3627
|
+
and paired_audit_executions
|
|
3628
|
+
)
|
|
3629
|
+
else (
|
|
3630
|
+
_FORECAST_OPPORTUNITY_DEFINITION_SHA256
|
|
3631
|
+
if self.forecast_opportunity_challenger is not None
|
|
3632
|
+
else (
|
|
3633
|
+
_PAIRED_AUDIT_DEFINITION_SHA256
|
|
3634
|
+
if paired_audit_executions
|
|
3635
|
+
else OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_DEFINITION_SHA256
|
|
3636
|
+
)
|
|
3637
|
+
)
|
|
3638
|
+
)
|
|
3639
|
+
),
|
|
3640
|
+
)
|
|
3641
|
+
|
|
3642
|
+
|
|
3643
|
+
__all__ = [
|
|
3644
|
+
"AdaptiveActionMarketProjectorPort",
|
|
3645
|
+
"AdaptiveActionOutcomeProjectorPort",
|
|
3646
|
+
"AdaptiveActionSemanticView",
|
|
3647
|
+
"AdaptiveActionSemanticViewPort",
|
|
3648
|
+
"CandidateArchiveAdaptiveActionOutcomeProjector",
|
|
3649
|
+
"FactorStratifiedAdaptiveMarketProjector",
|
|
3650
|
+
"OutcomeAdaptivePairedAuditExecution",
|
|
3651
|
+
"OutcomeAdaptiveResidualPhase",
|
|
3652
|
+
"OutcomeAdaptiveResidualPhaseCommitAck",
|
|
3653
|
+
"OutcomeAdaptiveResidualPhaseCommitPort",
|
|
3654
|
+
"OutcomeAdaptiveResidualPhaseReceipt",
|
|
3655
|
+
"OutcomeAdaptiveResidualPortfolioEvolution",
|
|
3656
|
+
"OutcomeAdaptiveResidualPortfolioEvolutionResult",
|
|
3657
|
+
"OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_DEFINITION_SHA256",
|
|
3658
|
+
"OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_ID",
|
|
3659
|
+
"OUTCOME_ADAPTIVE_RESIDUAL_EVOLUTION_VERSION",
|
|
3660
|
+
"OUTCOME_ADAPTIVE_RESIDUAL_PAIRED_AUDIT_EVOLUTION_DEFINITION_SHA256",
|
|
3661
|
+
"OUTCOME_ADAPTIVE_RESIDUAL_PAIRED_AUDIT_EVOLUTION_VERSION",
|
|
3662
|
+
"OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_OPPORTUNITY_EVOLUTION_DEFINITION_SHA256",
|
|
3663
|
+
"OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_OPPORTUNITY_EVOLUTION_VERSION",
|
|
3664
|
+
"OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_SHADOW_EVOLUTION_DEFINITION_SHA256",
|
|
3665
|
+
"OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_SHADOW_EVOLUTION_VERSION",
|
|
3666
|
+
"OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_STRATIFIED_AUDIT_EVOLUTION_DEFINITION_SHA256",
|
|
3667
|
+
"OUTCOME_ADAPTIVE_RESIDUAL_FORECAST_STRATIFIED_AUDIT_EVOLUTION_VERSION",
|
|
3668
|
+
"PortableMaterializedAdaptiveMarketProjector",
|
|
3669
|
+
"PortableMaterializedAdaptiveSemanticView",
|
|
3670
|
+
"ScoreEnsembleMaterializedAdaptiveMarketProjector",
|
|
3671
|
+
]
|