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,908 @@
|
|
|
1
|
+
"""Prior-only empirical calibration for action-consequence forecasts.
|
|
2
|
+
|
|
3
|
+
The language model is a useful semantic proposal expert, but it must not remain
|
|
4
|
+
the numerical oracle after real evaluator evidence exists. This module adds a
|
|
5
|
+
workload-neutral consequence expert over the existing action-outcome ledger.
|
|
6
|
+
It transfers only within an authenticated campaign scope and only from waves
|
|
7
|
+
strictly earlier than the current one.
|
|
8
|
+
|
|
9
|
+
The policy is deliberately conservative. It builds a local empirical
|
|
10
|
+
distribution from repeated patch paths when available, otherwise from the
|
|
11
|
+
option's sealed family, weights observations by parent-metric proximity and
|
|
12
|
+
recency, and fuses it with the model distribution. Both experts are judged
|
|
13
|
+
prequentially: categorical model correctness can reverse an anti-calibrated
|
|
14
|
+
model signal, while empirical transfer loses authority when its own strictly
|
|
15
|
+
prior-wave predictions are below chance. Sparse evidence cannot fully replace
|
|
16
|
+
the model, and exact metric projectors remain a higher authority when applied
|
|
17
|
+
after this policy.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import hashlib
|
|
23
|
+
import json
|
|
24
|
+
import math
|
|
25
|
+
from dataclasses import dataclass
|
|
26
|
+
from typing import Protocol, runtime_checkable
|
|
27
|
+
|
|
28
|
+
from agent_evolve.application.action_structural_signature import (
|
|
29
|
+
parent_relative_changed_paths_by_option,
|
|
30
|
+
)
|
|
31
|
+
from agent_evolve.application.action_target_realization import TargetMetricAlias
|
|
32
|
+
from agent_evolve.application.portfolio_evolution import PortfolioMemberDisposition
|
|
33
|
+
from agent_evolve.application.portfolio_outcome_feedback import (
|
|
34
|
+
PortfolioActionOutcomeFeedback,
|
|
35
|
+
PortfolioOutcomeFeedbackLedger,
|
|
36
|
+
)
|
|
37
|
+
from agent_evolve.domain.artifact import ArtifactRef
|
|
38
|
+
from agent_evolve.domain.typed_json import FrozenJsonObject, freeze_json, thaw_json
|
|
39
|
+
from agent_evolve.policies.selection.forecast_calibration import (
|
|
40
|
+
BetaCorrectnessPrior,
|
|
41
|
+
ForecastCalibrationScope,
|
|
42
|
+
ForecastCalibrationSnapshot,
|
|
43
|
+
ForecastConfidenceBin,
|
|
44
|
+
)
|
|
45
|
+
from agent_evolve.ports.action_forecast import (
|
|
46
|
+
ActionForecastRequest,
|
|
47
|
+
ResolvedActionForecast,
|
|
48
|
+
ResolvedActionForecastBatch,
|
|
49
|
+
ResolvedActionMetricForecast,
|
|
50
|
+
validate_resolved_action_forecasts,
|
|
51
|
+
)
|
|
52
|
+
from agent_evolve.ports.agentic_generator import MetricEffectDirection
|
|
53
|
+
from agent_evolve.ports.artifact_store import ArtifactStore, put_json
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
EMPIRICAL_CONSEQUENCE_POLICY_ID = "competitive_prequential_consequence"
|
|
57
|
+
EMPIRICAL_CONSEQUENCE_POLICY_VERSION = 4
|
|
58
|
+
EMPIRICAL_CONSEQUENCE_POLICY_DEFINITION_SHA256 = hashlib.sha256(
|
|
59
|
+
b"agent-evolve:competitive-prequential-consequence:v4;"
|
|
60
|
+
b"evidence=prior-wave-engine-metric-transitions;"
|
|
61
|
+
b"metric-identity=explicit-target-to-forecast-alias-contract;"
|
|
62
|
+
b"scope=model-prompt-selector-benchmark-session;"
|
|
63
|
+
b"strata=exact-parent-patch-paths-and-family-then-family;"
|
|
64
|
+
b"locality=parent-metric-distance;recency=geometric;"
|
|
65
|
+
b"model-authority=beta-smoothed-direction-correctness-with-negative-skill;"
|
|
66
|
+
b"empirical-authority=weighted-quantiles-gated-by-prequential-skill;"
|
|
67
|
+
b"fusion=bounded-evidence-and-performance-shrinkage;"
|
|
68
|
+
b"validity=family-frequency-bounded-shrinkage;"
|
|
69
|
+
b"audit=bounded-manifest-plus-content-addressed-per-action-artifacts;"
|
|
70
|
+
b"current-future-outcomes=false;workload-model-branches=false"
|
|
71
|
+
).hexdigest()
|
|
72
|
+
_RESULT_DOMAIN = b"agent-evolve:empirical-consequence-calibration-result:v1\x00"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _canonical_json(value: object) -> bytes:
|
|
76
|
+
return json.dumps(
|
|
77
|
+
value,
|
|
78
|
+
allow_nan=False,
|
|
79
|
+
ensure_ascii=True,
|
|
80
|
+
separators=(",", ":"),
|
|
81
|
+
sort_keys=True,
|
|
82
|
+
).encode("ascii", errors="strict")
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _object(value: dict[str, object]) -> FrozenJsonObject:
|
|
86
|
+
frozen = freeze_json(value)
|
|
87
|
+
if type(frozen) is not FrozenJsonObject: # pragma: no cover - closed root.
|
|
88
|
+
raise AssertionError("empirical calibration audit did not freeze to an object")
|
|
89
|
+
return frozen
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _artifact_ref_record(value: ArtifactRef) -> dict[str, object]:
|
|
93
|
+
"""Project an artifact reference without coupling the policy to storage."""
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
"artifact_id": value.artifact_id.value,
|
|
97
|
+
"sha256_hex": value.sha256_hex,
|
|
98
|
+
"size_bytes": value.size_bytes,
|
|
99
|
+
"media_type": value.media_type,
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _weighted_quantile(
|
|
104
|
+
values: tuple[tuple[float, float], ...],
|
|
105
|
+
probability: float,
|
|
106
|
+
) -> float:
|
|
107
|
+
if not values:
|
|
108
|
+
raise ValueError("weighted quantile requires observations")
|
|
109
|
+
if type(probability) is not float or not 0.0 <= probability <= 1.0:
|
|
110
|
+
raise ValueError("quantile probability must be a canonical float in [0,1]")
|
|
111
|
+
ordered = tuple(sorted(values, key=lambda item: (item[0], item[1])))
|
|
112
|
+
total = sum(weight for _, weight in ordered)
|
|
113
|
+
if not math.isfinite(total) or total <= 0.0:
|
|
114
|
+
raise ValueError("weighted quantile requires positive finite weight")
|
|
115
|
+
threshold = probability * total
|
|
116
|
+
cumulative = 0.0
|
|
117
|
+
for value, weight in ordered:
|
|
118
|
+
cumulative += weight
|
|
119
|
+
if cumulative >= threshold:
|
|
120
|
+
return value
|
|
121
|
+
return ordered[-1][0]
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _effective_support(weights: tuple[float, ...]) -> float:
|
|
125
|
+
total = sum(weights)
|
|
126
|
+
square_total = sum(value * value for value in weights)
|
|
127
|
+
if square_total <= 0.0:
|
|
128
|
+
return 0.0
|
|
129
|
+
return (total * total) / square_total
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def _forecast_direction(
|
|
133
|
+
forecast: ResolvedActionMetricForecast,
|
|
134
|
+
) -> MetricEffectDirection:
|
|
135
|
+
"""Use the same interval semantics as selected-forecast calibration."""
|
|
136
|
+
|
|
137
|
+
if type(forecast) is not ResolvedActionMetricForecast:
|
|
138
|
+
raise TypeError("forecast must be an exact resolved metric forecast")
|
|
139
|
+
forecast.__post_init__()
|
|
140
|
+
if forecast.p10_delta == forecast.p50_delta == forecast.p90_delta == 0.0:
|
|
141
|
+
return MetricEffectDirection.UNCHANGED
|
|
142
|
+
if forecast.p90_delta < 0.0:
|
|
143
|
+
return MetricEffectDirection.DECREASE
|
|
144
|
+
if forecast.p10_delta > 0.0:
|
|
145
|
+
return MetricEffectDirection.INCREASE
|
|
146
|
+
return MetricEffectDirection.UNKNOWN
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _confidence_bin(value: float) -> ForecastConfidenceBin:
|
|
150
|
+
if type(value) is not float or not math.isfinite(value):
|
|
151
|
+
raise TypeError("forecast confidence must be a finite canonical float")
|
|
152
|
+
if not 0.0 <= value <= 1.0:
|
|
153
|
+
raise ValueError("forecast confidence must lie in [0,1]")
|
|
154
|
+
if value >= 0.75:
|
|
155
|
+
return ForecastConfidenceBin.HIGH
|
|
156
|
+
if value >= 0.4:
|
|
157
|
+
return ForecastConfidenceBin.MEDIUM
|
|
158
|
+
if value > 0.0:
|
|
159
|
+
return ForecastConfidenceBin.LOW
|
|
160
|
+
return ForecastConfidenceBin.UNKNOWN
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _signed_interval(
|
|
164
|
+
forecast: ResolvedActionMetricForecast,
|
|
165
|
+
factor: float,
|
|
166
|
+
) -> tuple[float, float, float]:
|
|
167
|
+
"""Project correctness skill onto a quantile interval without reordering it."""
|
|
168
|
+
|
|
169
|
+
if type(factor) is not float or not math.isfinite(factor):
|
|
170
|
+
raise TypeError("signed skill factor must be a finite canonical float")
|
|
171
|
+
if not -1.0 <= factor <= 1.0:
|
|
172
|
+
raise ValueError("signed skill factor must lie in [-1,1]")
|
|
173
|
+
values = (
|
|
174
|
+
factor * forecast.p10_delta,
|
|
175
|
+
factor * forecast.p50_delta,
|
|
176
|
+
factor * forecast.p90_delta,
|
|
177
|
+
)
|
|
178
|
+
return tuple(sorted(values)) # type: ignore[return-value]
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@dataclass(frozen=True, slots=True, eq=False)
|
|
182
|
+
class ActionConsequenceCalibrationResult:
|
|
183
|
+
"""Authenticated calibrated batch plus a complete no-leakage audit."""
|
|
184
|
+
|
|
185
|
+
source_forecast_receipt_sha256: str
|
|
186
|
+
cutoff_wave_index_exclusive: int
|
|
187
|
+
forecasts: ResolvedActionForecastBatch
|
|
188
|
+
audit: FrozenJsonObject
|
|
189
|
+
|
|
190
|
+
def __post_init__(self) -> None:
|
|
191
|
+
if (
|
|
192
|
+
type(self.source_forecast_receipt_sha256) is not str
|
|
193
|
+
or len(self.source_forecast_receipt_sha256) != 64
|
|
194
|
+
):
|
|
195
|
+
raise ValueError("source_forecast_receipt_sha256 must be a SHA-256")
|
|
196
|
+
try:
|
|
197
|
+
bytes.fromhex(self.source_forecast_receipt_sha256)
|
|
198
|
+
except ValueError as error:
|
|
199
|
+
raise ValueError(
|
|
200
|
+
"source_forecast_receipt_sha256 must be lowercase hexadecimal"
|
|
201
|
+
) from error
|
|
202
|
+
if (
|
|
203
|
+
type(self.cutoff_wave_index_exclusive) is not int
|
|
204
|
+
or self.cutoff_wave_index_exclusive <= 0
|
|
205
|
+
):
|
|
206
|
+
raise ValueError("cutoff_wave_index_exclusive must be positive")
|
|
207
|
+
if type(self.forecasts) is not ResolvedActionForecastBatch:
|
|
208
|
+
raise TypeError("forecasts must be an exact resolved batch")
|
|
209
|
+
self.forecasts.__post_init__()
|
|
210
|
+
if (
|
|
211
|
+
type(self.audit) is not FrozenJsonObject
|
|
212
|
+
or freeze_json(self.audit) is not self.audit
|
|
213
|
+
):
|
|
214
|
+
raise TypeError("audit must be an exact frozen JSON object")
|
|
215
|
+
|
|
216
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
217
|
+
self.__post_init__()
|
|
218
|
+
return {
|
|
219
|
+
"schema_version": 1,
|
|
220
|
+
"policy": {
|
|
221
|
+
"policy_id": EMPIRICAL_CONSEQUENCE_POLICY_ID,
|
|
222
|
+
"policy_version": EMPIRICAL_CONSEQUENCE_POLICY_VERSION,
|
|
223
|
+
"definition_sha256": (EMPIRICAL_CONSEQUENCE_POLICY_DEFINITION_SHA256),
|
|
224
|
+
},
|
|
225
|
+
"source_forecast_receipt_sha256": self.source_forecast_receipt_sha256,
|
|
226
|
+
"cutoff_wave_index_exclusive": self.cutoff_wave_index_exclusive,
|
|
227
|
+
"calibrated_forecast_receipt_sha256": self.forecasts.receipt_sha256,
|
|
228
|
+
# Frozen typed JSON is the trusted in-memory representation, but
|
|
229
|
+
# result records cross the ordinary JSON evidence boundary. Keep
|
|
230
|
+
# the immutable audit internally and thaw only for serialization.
|
|
231
|
+
"audit": thaw_json(self.audit),
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
def receipt_sha256(self) -> str:
|
|
236
|
+
return hashlib.sha256(
|
|
237
|
+
_RESULT_DOMAIN + _canonical_json(self._unsigned_record())
|
|
238
|
+
).hexdigest()
|
|
239
|
+
|
|
240
|
+
def to_record(self) -> dict[str, object]:
|
|
241
|
+
return {**self._unsigned_record(), "receipt_sha256": self.receipt_sha256}
|
|
242
|
+
|
|
243
|
+
def __eq__(self, other: object) -> bool:
|
|
244
|
+
return (
|
|
245
|
+
type(other) is ActionConsequenceCalibrationResult
|
|
246
|
+
and self.receipt_sha256 == other.receipt_sha256
|
|
247
|
+
)
|
|
248
|
+
|
|
249
|
+
__hash__ = None
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
@runtime_checkable
|
|
253
|
+
class ActionConsequenceCalibrationPolicy(Protocol):
|
|
254
|
+
"""Stable application port for prior-only consequence posteriors."""
|
|
255
|
+
|
|
256
|
+
def calibrate(
|
|
257
|
+
self,
|
|
258
|
+
*,
|
|
259
|
+
request: ActionForecastRequest,
|
|
260
|
+
forecasts: ResolvedActionForecastBatch,
|
|
261
|
+
cutoff_wave_index_exclusive: int,
|
|
262
|
+
metric_aliases: tuple[TargetMetricAlias, ...] = (),
|
|
263
|
+
) -> ActionConsequenceCalibrationResult: ...
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
@dataclass(slots=True)
|
|
267
|
+
class HierarchicalEmpiricalConsequenceCalibrationPolicy:
|
|
268
|
+
"""Compete LLM and local empirical experts without domain branches."""
|
|
269
|
+
|
|
270
|
+
ledger: PortfolioOutcomeFeedbackLedger
|
|
271
|
+
scope: ForecastCalibrationScope
|
|
272
|
+
minimum_path_support: int = 2
|
|
273
|
+
minimum_family_support: int = 2
|
|
274
|
+
prior_strength: float = 3.0
|
|
275
|
+
validity_prior_strength: float = 2.0
|
|
276
|
+
maximum_empirical_authority: float = 0.75
|
|
277
|
+
recency_decay: float = 0.9
|
|
278
|
+
minimum_model_score_support: int = 2
|
|
279
|
+
model_family_min_support: int = 4
|
|
280
|
+
minimum_empirical_score_support: int = 4
|
|
281
|
+
correctness_prior_alpha: float = 1.0
|
|
282
|
+
correctness_prior_beta: float = 1.0
|
|
283
|
+
audit_artifact_store: ArtifactStore | None = None
|
|
284
|
+
maximum_embedded_action_audits: int = 32
|
|
285
|
+
|
|
286
|
+
def __post_init__(self) -> None:
|
|
287
|
+
if type(self.ledger) is not PortfolioOutcomeFeedbackLedger:
|
|
288
|
+
raise TypeError("ledger must be exact PortfolioOutcomeFeedbackLedger")
|
|
289
|
+
if type(self.scope) is not ForecastCalibrationScope:
|
|
290
|
+
raise TypeError("scope must be exact ForecastCalibrationScope")
|
|
291
|
+
self.scope.revalidate()
|
|
292
|
+
for name in (
|
|
293
|
+
"minimum_path_support",
|
|
294
|
+
"minimum_family_support",
|
|
295
|
+
"minimum_model_score_support",
|
|
296
|
+
"model_family_min_support",
|
|
297
|
+
"minimum_empirical_score_support",
|
|
298
|
+
):
|
|
299
|
+
value = getattr(self, name)
|
|
300
|
+
if type(value) is not int or value <= 0:
|
|
301
|
+
raise ValueError(f"{name} must be a positive exact integer")
|
|
302
|
+
for name in (
|
|
303
|
+
"prior_strength",
|
|
304
|
+
"validity_prior_strength",
|
|
305
|
+
"correctness_prior_alpha",
|
|
306
|
+
"correctness_prior_beta",
|
|
307
|
+
):
|
|
308
|
+
value = getattr(self, name)
|
|
309
|
+
if type(value) is not float or not math.isfinite(value) or value <= 0.0:
|
|
310
|
+
raise ValueError(f"{name} must be a positive finite float")
|
|
311
|
+
if (
|
|
312
|
+
type(self.maximum_empirical_authority) is not float
|
|
313
|
+
or not 0.0 <= self.maximum_empirical_authority <= 1.0
|
|
314
|
+
):
|
|
315
|
+
raise ValueError("maximum_empirical_authority must lie in [0,1]")
|
|
316
|
+
if type(self.recency_decay) is not float or not 0.0 < self.recency_decay <= 1.0:
|
|
317
|
+
raise ValueError("recency_decay must lie in (0,1]")
|
|
318
|
+
if self.audit_artifact_store is not None and not isinstance(
|
|
319
|
+
self.audit_artifact_store,
|
|
320
|
+
ArtifactStore,
|
|
321
|
+
):
|
|
322
|
+
raise TypeError("audit_artifact_store must implement ArtifactStore")
|
|
323
|
+
if (
|
|
324
|
+
type(self.maximum_embedded_action_audits) is not int
|
|
325
|
+
or self.maximum_embedded_action_audits < 0
|
|
326
|
+
):
|
|
327
|
+
raise ValueError(
|
|
328
|
+
"maximum_embedded_action_audits must be a non-negative exact integer"
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
def _correctness_prior(self) -> BetaCorrectnessPrior:
|
|
332
|
+
return BetaCorrectnessPrior(
|
|
333
|
+
alpha=self.correctness_prior_alpha,
|
|
334
|
+
beta=self.correctness_prior_beta,
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
def _model_projection(
|
|
338
|
+
self,
|
|
339
|
+
*,
|
|
340
|
+
snapshot: ForecastCalibrationSnapshot,
|
|
341
|
+
family: str,
|
|
342
|
+
outcome_metric_id: str,
|
|
343
|
+
raw: ResolvedActionMetricForecast,
|
|
344
|
+
) -> tuple[ResolvedActionMetricForecast, dict[str, object]]:
|
|
345
|
+
direction = _forecast_direction(raw)
|
|
346
|
+
confidence = _confidence_bin(raw.confidence)
|
|
347
|
+
cell, source = snapshot.lookup(
|
|
348
|
+
metric_id=outcome_metric_id,
|
|
349
|
+
asserted_direction=direction,
|
|
350
|
+
confidence=confidence,
|
|
351
|
+
family=family,
|
|
352
|
+
)
|
|
353
|
+
score_identified = (
|
|
354
|
+
direction is not MetricEffectDirection.UNKNOWN
|
|
355
|
+
and cell.scorable_count >= self.minimum_model_score_support
|
|
356
|
+
)
|
|
357
|
+
signed_skill = (
|
|
358
|
+
1.0 if not score_identified else (2.0 * cell.posterior_correctness) - 1.0
|
|
359
|
+
)
|
|
360
|
+
p10, p50, p90 = _signed_interval(raw, float(signed_skill))
|
|
361
|
+
projected = ResolvedActionMetricForecast(
|
|
362
|
+
metric_id=raw.metric_id,
|
|
363
|
+
p10_delta=float(p10),
|
|
364
|
+
p50_delta=float(p50),
|
|
365
|
+
p90_delta=float(p90),
|
|
366
|
+
confidence=float(
|
|
367
|
+
raw.confidence
|
|
368
|
+
if not score_identified
|
|
369
|
+
else raw.confidence * abs(signed_skill)
|
|
370
|
+
),
|
|
371
|
+
citations=raw.citations,
|
|
372
|
+
)
|
|
373
|
+
return projected, {
|
|
374
|
+
"forecast_metric_id": raw.metric_id,
|
|
375
|
+
"outcome_metric_id": outcome_metric_id,
|
|
376
|
+
"direction": direction.value,
|
|
377
|
+
"confidence_bin": confidence.value,
|
|
378
|
+
"calibration_source": source,
|
|
379
|
+
"scorable_count": cell.scorable_count,
|
|
380
|
+
"correct_count": cell.correct_count,
|
|
381
|
+
"posterior_correctness_hex": cell.posterior_correctness.hex(),
|
|
382
|
+
"score_identified": score_identified,
|
|
383
|
+
"signed_skill_hex": signed_skill.hex(),
|
|
384
|
+
"negative_skill_inversion": signed_skill < 0.0,
|
|
385
|
+
"raw": raw.to_record(),
|
|
386
|
+
"projected": projected.to_record(),
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
def _weighted_metric_observations(
|
|
390
|
+
self,
|
|
391
|
+
*,
|
|
392
|
+
actions: tuple[PortfolioActionOutcomeFeedback, ...],
|
|
393
|
+
metric_id: str,
|
|
394
|
+
current_parent_value: float,
|
|
395
|
+
scale: float,
|
|
396
|
+
cutoff_wave_index_exclusive: int,
|
|
397
|
+
) -> tuple[tuple[PortfolioActionOutcomeFeedback, float, float], ...]:
|
|
398
|
+
observations: list[tuple[PortfolioActionOutcomeFeedback, float, float]] = []
|
|
399
|
+
for action in actions:
|
|
400
|
+
if (
|
|
401
|
+
action.wave_index >= cutoff_wave_index_exclusive
|
|
402
|
+
or action.disposition is not PortfolioMemberDisposition.SCORED
|
|
403
|
+
):
|
|
404
|
+
continue
|
|
405
|
+
transition = next(
|
|
406
|
+
(
|
|
407
|
+
value
|
|
408
|
+
for value in action.metric_transitions
|
|
409
|
+
if value.metric_id == metric_id
|
|
410
|
+
),
|
|
411
|
+
None,
|
|
412
|
+
)
|
|
413
|
+
if transition is None:
|
|
414
|
+
continue
|
|
415
|
+
locality = 1.0 / (
|
|
416
|
+
1.0 + abs(transition.parent_value - current_parent_value) / scale
|
|
417
|
+
)
|
|
418
|
+
age = cutoff_wave_index_exclusive - 1 - action.wave_index
|
|
419
|
+
recency = self.recency_decay ** max(0, age)
|
|
420
|
+
observations.append(
|
|
421
|
+
(
|
|
422
|
+
action,
|
|
423
|
+
transition.child_value - transition.parent_value,
|
|
424
|
+
locality * recency,
|
|
425
|
+
)
|
|
426
|
+
)
|
|
427
|
+
return tuple(observations)
|
|
428
|
+
|
|
429
|
+
def _empirical_rows(
|
|
430
|
+
self,
|
|
431
|
+
*,
|
|
432
|
+
actions: tuple[PortfolioActionOutcomeFeedback, ...],
|
|
433
|
+
changed_paths: tuple[str, ...],
|
|
434
|
+
family: str,
|
|
435
|
+
metric_id: str,
|
|
436
|
+
current_parent_value: float,
|
|
437
|
+
scale: float,
|
|
438
|
+
cutoff_wave_index_exclusive: int,
|
|
439
|
+
) -> tuple[str, tuple[tuple[float, float], ...], int]:
|
|
440
|
+
observations = self._weighted_metric_observations(
|
|
441
|
+
actions=actions,
|
|
442
|
+
metric_id=metric_id,
|
|
443
|
+
current_parent_value=current_parent_value,
|
|
444
|
+
scale=scale,
|
|
445
|
+
cutoff_wave_index_exclusive=cutoff_wave_index_exclusive,
|
|
446
|
+
)
|
|
447
|
+
path_rows = tuple(
|
|
448
|
+
(delta, weight)
|
|
449
|
+
for action, delta, weight in observations
|
|
450
|
+
if action.changed_paths == changed_paths and action.family == family
|
|
451
|
+
)
|
|
452
|
+
family_rows = tuple(
|
|
453
|
+
(delta, weight)
|
|
454
|
+
for action, delta, weight in observations
|
|
455
|
+
if action.family == family
|
|
456
|
+
)
|
|
457
|
+
if len(path_rows) >= self.minimum_path_support:
|
|
458
|
+
return "exact_path_family", path_rows, len(family_rows)
|
|
459
|
+
if len(family_rows) >= self.minimum_family_support:
|
|
460
|
+
return "family", family_rows, len(family_rows)
|
|
461
|
+
return "model_only", (), len(family_rows)
|
|
462
|
+
|
|
463
|
+
def _empirical_prequential_skill(
|
|
464
|
+
self,
|
|
465
|
+
*,
|
|
466
|
+
actions: tuple[PortfolioActionOutcomeFeedback, ...],
|
|
467
|
+
family: str,
|
|
468
|
+
metric_id: str,
|
|
469
|
+
scale: float,
|
|
470
|
+
) -> dict[str, object]:
|
|
471
|
+
scorable = 0
|
|
472
|
+
correct = 0
|
|
473
|
+
for target in sorted(
|
|
474
|
+
(value for value in actions if value.family == family),
|
|
475
|
+
key=lambda value: (
|
|
476
|
+
value.wave_index,
|
|
477
|
+
value.request_sha256,
|
|
478
|
+
value.option_id,
|
|
479
|
+
),
|
|
480
|
+
):
|
|
481
|
+
transition = next(
|
|
482
|
+
(
|
|
483
|
+
value
|
|
484
|
+
for value in target.metric_transitions
|
|
485
|
+
if value.metric_id == metric_id
|
|
486
|
+
),
|
|
487
|
+
None,
|
|
488
|
+
)
|
|
489
|
+
if transition is None:
|
|
490
|
+
continue
|
|
491
|
+
_, rows, _ = self._empirical_rows(
|
|
492
|
+
actions=actions,
|
|
493
|
+
changed_paths=target.changed_paths,
|
|
494
|
+
family=target.family,
|
|
495
|
+
metric_id=metric_id,
|
|
496
|
+
current_parent_value=transition.parent_value,
|
|
497
|
+
scale=scale,
|
|
498
|
+
cutoff_wave_index_exclusive=target.wave_index,
|
|
499
|
+
)
|
|
500
|
+
if not rows:
|
|
501
|
+
continue
|
|
502
|
+
median = _weighted_quantile(rows, 0.5)
|
|
503
|
+
predicted = (
|
|
504
|
+
MetricEffectDirection.DECREASE
|
|
505
|
+
if median < 0.0
|
|
506
|
+
else MetricEffectDirection.INCREASE
|
|
507
|
+
if median > 0.0
|
|
508
|
+
else MetricEffectDirection.UNCHANGED
|
|
509
|
+
)
|
|
510
|
+
scorable += 1
|
|
511
|
+
correct += predicted is transition.actual_direction
|
|
512
|
+
prior = self._correctness_prior()
|
|
513
|
+
posterior = (prior.alpha + correct) / (prior.alpha + prior.beta + scorable)
|
|
514
|
+
identified = scorable >= self.minimum_empirical_score_support
|
|
515
|
+
authority_multiplier = (
|
|
516
|
+
1.0 if not identified else max(0.0, (2.0 * posterior) - 1.0)
|
|
517
|
+
)
|
|
518
|
+
return {
|
|
519
|
+
"scorable_count": scorable,
|
|
520
|
+
"correct_count": correct,
|
|
521
|
+
"posterior_correctness_hex": posterior.hex(),
|
|
522
|
+
"score_identified": identified,
|
|
523
|
+
"authority_multiplier_hex": authority_multiplier.hex(),
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
def _prior_actions(
|
|
527
|
+
self,
|
|
528
|
+
cutoff_wave_index_exclusive: int,
|
|
529
|
+
) -> tuple[PortfolioActionOutcomeFeedback, ...]:
|
|
530
|
+
return tuple(
|
|
531
|
+
action
|
|
532
|
+
for receipt in self.ledger.receipts
|
|
533
|
+
if receipt.scope == self.scope
|
|
534
|
+
and receipt.wave_index < cutoff_wave_index_exclusive
|
|
535
|
+
for action in receipt.actions
|
|
536
|
+
)
|
|
537
|
+
|
|
538
|
+
def _validity_projection(
|
|
539
|
+
self,
|
|
540
|
+
*,
|
|
541
|
+
actions: tuple[PortfolioActionOutcomeFeedback, ...],
|
|
542
|
+
family: str,
|
|
543
|
+
raw_probability: float,
|
|
544
|
+
) -> tuple[float, dict[str, object]]:
|
|
545
|
+
members = tuple(value for value in actions if value.family == family)
|
|
546
|
+
if not members:
|
|
547
|
+
return raw_probability, {
|
|
548
|
+
"support_count": 0,
|
|
549
|
+
"empirical_authority_hex": (0.0).hex(),
|
|
550
|
+
"posterior_valid_probability_hex": None,
|
|
551
|
+
}
|
|
552
|
+
valid_count = sum(
|
|
553
|
+
value.disposition is PortfolioMemberDisposition.SCORED for value in members
|
|
554
|
+
)
|
|
555
|
+
posterior = valid_count / len(members)
|
|
556
|
+
authority = min(
|
|
557
|
+
self.maximum_empirical_authority,
|
|
558
|
+
len(members) / (len(members) + self.validity_prior_strength),
|
|
559
|
+
)
|
|
560
|
+
calibrated = (1.0 - authority) * raw_probability + authority * posterior
|
|
561
|
+
return calibrated, {
|
|
562
|
+
"support_count": len(members),
|
|
563
|
+
"valid_count": valid_count,
|
|
564
|
+
"empirical_authority_hex": authority.hex(),
|
|
565
|
+
"posterior_valid_probability_hex": posterior.hex(),
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
def _metric_projection(
|
|
569
|
+
self,
|
|
570
|
+
*,
|
|
571
|
+
actions: tuple[PortfolioActionOutcomeFeedback, ...],
|
|
572
|
+
model_snapshot: ForecastCalibrationSnapshot,
|
|
573
|
+
changed_paths: tuple[str, ...],
|
|
574
|
+
family: str,
|
|
575
|
+
metric_id: str,
|
|
576
|
+
current_parent_value: float,
|
|
577
|
+
scale: float,
|
|
578
|
+
cutoff_wave_index_exclusive: int,
|
|
579
|
+
raw: ResolvedActionMetricForecast,
|
|
580
|
+
) -> tuple[ResolvedActionMetricForecast, dict[str, object]]:
|
|
581
|
+
model_projected, model_audit = self._model_projection(
|
|
582
|
+
snapshot=model_snapshot,
|
|
583
|
+
family=family,
|
|
584
|
+
outcome_metric_id=metric_id,
|
|
585
|
+
raw=raw,
|
|
586
|
+
)
|
|
587
|
+
stratum, rows, family_support = self._empirical_rows(
|
|
588
|
+
actions=actions,
|
|
589
|
+
changed_paths=changed_paths,
|
|
590
|
+
family=family,
|
|
591
|
+
metric_id=metric_id,
|
|
592
|
+
current_parent_value=current_parent_value,
|
|
593
|
+
scale=scale,
|
|
594
|
+
cutoff_wave_index_exclusive=cutoff_wave_index_exclusive,
|
|
595
|
+
)
|
|
596
|
+
if not rows:
|
|
597
|
+
return model_projected, {
|
|
598
|
+
"metric_id": raw.metric_id,
|
|
599
|
+
"forecast_metric_id": raw.metric_id,
|
|
600
|
+
"outcome_metric_id": metric_id,
|
|
601
|
+
"stratum": stratum,
|
|
602
|
+
"support_count": family_support,
|
|
603
|
+
"effective_support_hex": (0.0).hex(),
|
|
604
|
+
"empirical_authority_hex": (0.0).hex(),
|
|
605
|
+
"model_calibration": model_audit,
|
|
606
|
+
"empirical_prequential_skill": None,
|
|
607
|
+
"raw": raw.to_record(),
|
|
608
|
+
"calibrated": model_projected.to_record(),
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
weights = tuple(weight for _, weight in rows)
|
|
612
|
+
effective = _effective_support(weights)
|
|
613
|
+
support_authority = min(
|
|
614
|
+
self.maximum_empirical_authority,
|
|
615
|
+
effective / (effective + self.prior_strength),
|
|
616
|
+
)
|
|
617
|
+
empirical_skill = self._empirical_prequential_skill(
|
|
618
|
+
actions=actions,
|
|
619
|
+
family=family,
|
|
620
|
+
metric_id=metric_id,
|
|
621
|
+
scale=scale,
|
|
622
|
+
)
|
|
623
|
+
authority_multiplier = float.fromhex(
|
|
624
|
+
str(empirical_skill["authority_multiplier_hex"])
|
|
625
|
+
)
|
|
626
|
+
authority = support_authority * authority_multiplier
|
|
627
|
+
empirical = (
|
|
628
|
+
_weighted_quantile(rows, 0.1),
|
|
629
|
+
_weighted_quantile(rows, 0.5),
|
|
630
|
+
_weighted_quantile(rows, 0.9),
|
|
631
|
+
)
|
|
632
|
+
model_values = (
|
|
633
|
+
model_projected.p10_delta,
|
|
634
|
+
model_projected.p50_delta,
|
|
635
|
+
model_projected.p90_delta,
|
|
636
|
+
)
|
|
637
|
+
calibrated_values = tuple(
|
|
638
|
+
(1.0 - authority) * model_value + authority * empirical_value
|
|
639
|
+
for model_value, empirical_value in zip(
|
|
640
|
+
model_values,
|
|
641
|
+
empirical,
|
|
642
|
+
strict=True,
|
|
643
|
+
)
|
|
644
|
+
)
|
|
645
|
+
empirical_agreement = (
|
|
646
|
+
1.0
|
|
647
|
+
if model_projected.p50_delta == 0.0 or empirical[1] == 0.0
|
|
648
|
+
else 1.0
|
|
649
|
+
if math.copysign(1.0, model_projected.p50_delta)
|
|
650
|
+
== math.copysign(1.0, empirical[1])
|
|
651
|
+
else 0.0
|
|
652
|
+
)
|
|
653
|
+
empirical_confidence = effective / (effective + self.prior_strength)
|
|
654
|
+
calibrated_confidence = (
|
|
655
|
+
1.0 - authority
|
|
656
|
+
) * model_projected.confidence + authority * empirical_confidence * (
|
|
657
|
+
0.5 + 0.5 * empirical_agreement
|
|
658
|
+
)
|
|
659
|
+
calibrated = ResolvedActionMetricForecast(
|
|
660
|
+
metric_id=raw.metric_id,
|
|
661
|
+
p10_delta=float(calibrated_values[0]),
|
|
662
|
+
p50_delta=float(calibrated_values[1]),
|
|
663
|
+
p90_delta=float(calibrated_values[2]),
|
|
664
|
+
confidence=float(min(1.0, max(0.0, calibrated_confidence))),
|
|
665
|
+
citations=raw.citations,
|
|
666
|
+
)
|
|
667
|
+
return calibrated, {
|
|
668
|
+
"metric_id": raw.metric_id,
|
|
669
|
+
"forecast_metric_id": raw.metric_id,
|
|
670
|
+
"outcome_metric_id": metric_id,
|
|
671
|
+
"stratum": stratum,
|
|
672
|
+
"support_count": len(rows),
|
|
673
|
+
"effective_support_hex": effective.hex(),
|
|
674
|
+
"support_authority_hex": support_authority.hex(),
|
|
675
|
+
"empirical_authority_hex": authority.hex(),
|
|
676
|
+
"empirical_quantiles_hex": [value.hex() for value in empirical],
|
|
677
|
+
"parent_metric_value_hex": current_parent_value.hex(),
|
|
678
|
+
"metric_scale_hex": scale.hex(),
|
|
679
|
+
"model_calibration": model_audit,
|
|
680
|
+
"empirical_prequential_skill": empirical_skill,
|
|
681
|
+
"raw": raw.to_record(),
|
|
682
|
+
"calibrated": calibrated.to_record(),
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
def calibrate(
|
|
686
|
+
self,
|
|
687
|
+
*,
|
|
688
|
+
request: ActionForecastRequest,
|
|
689
|
+
forecasts: ResolvedActionForecastBatch,
|
|
690
|
+
cutoff_wave_index_exclusive: int,
|
|
691
|
+
metric_aliases: tuple[TargetMetricAlias, ...] = (),
|
|
692
|
+
) -> ActionConsequenceCalibrationResult:
|
|
693
|
+
self.__post_init__()
|
|
694
|
+
if type(request) is not ActionForecastRequest:
|
|
695
|
+
raise TypeError("request must be an exact ActionForecastRequest")
|
|
696
|
+
request.__post_init__()
|
|
697
|
+
if type(forecasts) is not ResolvedActionForecastBatch:
|
|
698
|
+
raise TypeError("forecasts must be an exact resolved batch")
|
|
699
|
+
validate_resolved_action_forecasts(request, forecasts)
|
|
700
|
+
if (
|
|
701
|
+
type(cutoff_wave_index_exclusive) is not int
|
|
702
|
+
or cutoff_wave_index_exclusive <= 0
|
|
703
|
+
):
|
|
704
|
+
raise ValueError("cutoff_wave_index_exclusive must be positive")
|
|
705
|
+
if type(metric_aliases) is not tuple or any(
|
|
706
|
+
type(value) is not TargetMetricAlias for value in metric_aliases
|
|
707
|
+
):
|
|
708
|
+
raise TypeError("metric_aliases must contain exact TargetMetricAlias values")
|
|
709
|
+
if metric_aliases:
|
|
710
|
+
for value in metric_aliases:
|
|
711
|
+
value.__post_init__()
|
|
712
|
+
forecast_ids = tuple(value.forecast_metric_id for value in metric_aliases)
|
|
713
|
+
target_ids = tuple(value.target_metric_id for value in metric_aliases)
|
|
714
|
+
if len(set(forecast_ids)) != len(forecast_ids):
|
|
715
|
+
raise ValueError("metric aliases must have unique forecast metric IDs")
|
|
716
|
+
if len(set(target_ids)) != len(target_ids):
|
|
717
|
+
raise ValueError("metric aliases must have unique target metric IDs")
|
|
718
|
+
if set(forecast_ids) != set(request.required_metric_ids):
|
|
719
|
+
raise ValueError(
|
|
720
|
+
"metric aliases must cover the forecast request exactly"
|
|
721
|
+
)
|
|
722
|
+
resolved_aliases = metric_aliases
|
|
723
|
+
else:
|
|
724
|
+
resolved_aliases = tuple(
|
|
725
|
+
TargetMetricAlias(
|
|
726
|
+
target_metric_id=metric_id,
|
|
727
|
+
forecast_metric_id=metric_id,
|
|
728
|
+
)
|
|
729
|
+
for metric_id in request.required_metric_ids
|
|
730
|
+
)
|
|
731
|
+
target_by_forecast = {
|
|
732
|
+
value.forecast_metric_id: value.target_metric_id
|
|
733
|
+
for value in resolved_aliases
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
actions = self._prior_actions(cutoff_wave_index_exclusive)
|
|
737
|
+
model_snapshot = self.ledger.calibration_snapshot(
|
|
738
|
+
scope=self.scope,
|
|
739
|
+
cutoff_wave_index_exclusive=cutoff_wave_index_exclusive,
|
|
740
|
+
prior=self._correctness_prior(),
|
|
741
|
+
family_min_support=self.model_family_min_support,
|
|
742
|
+
)
|
|
743
|
+
paths_by_option = parent_relative_changed_paths_by_option(
|
|
744
|
+
request.finite_variation_contract
|
|
745
|
+
)
|
|
746
|
+
parent_by_metric = {
|
|
747
|
+
value.metric_id: value.value for value in request.parent_metric_values
|
|
748
|
+
}
|
|
749
|
+
scale_by_metric = {
|
|
750
|
+
value.metric_id: value.delta_scale for value in request.metric_scales
|
|
751
|
+
}
|
|
752
|
+
calibrated_forecasts: list[ResolvedActionForecast] = []
|
|
753
|
+
action_audits: list[dict[str, object]] = []
|
|
754
|
+
for forecast in forecasts.forecasts:
|
|
755
|
+
probability_valid, validity_audit = self._validity_projection(
|
|
756
|
+
actions=actions,
|
|
757
|
+
family=forecast.family,
|
|
758
|
+
raw_probability=forecast.probability_valid,
|
|
759
|
+
)
|
|
760
|
+
metrics: list[ResolvedActionMetricForecast] = []
|
|
761
|
+
metric_audits: list[dict[str, object]] = []
|
|
762
|
+
for metric in forecast.metric_forecasts:
|
|
763
|
+
outcome_metric_id = target_by_forecast[metric.metric_id]
|
|
764
|
+
calibrated_metric, metric_audit = self._metric_projection(
|
|
765
|
+
actions=actions,
|
|
766
|
+
model_snapshot=model_snapshot,
|
|
767
|
+
changed_paths=paths_by_option[forecast.option_id],
|
|
768
|
+
family=forecast.family,
|
|
769
|
+
metric_id=outcome_metric_id,
|
|
770
|
+
current_parent_value=parent_by_metric[metric.metric_id],
|
|
771
|
+
scale=scale_by_metric[metric.metric_id],
|
|
772
|
+
cutoff_wave_index_exclusive=cutoff_wave_index_exclusive,
|
|
773
|
+
raw=metric,
|
|
774
|
+
)
|
|
775
|
+
metrics.append(calibrated_metric)
|
|
776
|
+
metric_audits.append(metric_audit)
|
|
777
|
+
calibrated = ResolvedActionForecast(
|
|
778
|
+
option_id=forecast.option_id,
|
|
779
|
+
option_identity_sha256=forecast.option_identity_sha256,
|
|
780
|
+
child_configuration_sha256=forecast.child_configuration_sha256,
|
|
781
|
+
family=forecast.family,
|
|
782
|
+
probability_valid=float(probability_valid),
|
|
783
|
+
metric_forecasts=tuple(metrics),
|
|
784
|
+
)
|
|
785
|
+
calibrated_forecasts.append(calibrated)
|
|
786
|
+
action_audits.append(
|
|
787
|
+
{
|
|
788
|
+
"option_id": forecast.option_id,
|
|
789
|
+
"family": forecast.family,
|
|
790
|
+
"changed_paths": list(paths_by_option[forecast.option_id]),
|
|
791
|
+
"validity": validity_audit,
|
|
792
|
+
"metric_cells": metric_audits,
|
|
793
|
+
}
|
|
794
|
+
)
|
|
795
|
+
|
|
796
|
+
calibrated_batch = ResolvedActionForecastBatch(
|
|
797
|
+
request_sha256=forecasts.request_sha256,
|
|
798
|
+
context_sha256=forecasts.context_sha256,
|
|
799
|
+
optimization_semantics_definition_sha256=(
|
|
800
|
+
forecasts.optimization_semantics_definition_sha256
|
|
801
|
+
),
|
|
802
|
+
action_semantics_definition_sha256=(
|
|
803
|
+
forecasts.action_semantics_definition_sha256
|
|
804
|
+
),
|
|
805
|
+
finite_contract_identity_sha256=(forecasts.finite_contract_identity_sha256),
|
|
806
|
+
card_snapshot_sha256=forecasts.card_snapshot_sha256,
|
|
807
|
+
forecasts=tuple(calibrated_forecasts),
|
|
808
|
+
policy_id=EMPIRICAL_CONSEQUENCE_POLICY_ID,
|
|
809
|
+
policy_version=EMPIRICAL_CONSEQUENCE_POLICY_VERSION,
|
|
810
|
+
policy_definition_sha256=(EMPIRICAL_CONSEQUENCE_POLICY_DEFINITION_SHA256),
|
|
811
|
+
)
|
|
812
|
+
validate_resolved_action_forecasts(request, calibrated_batch)
|
|
813
|
+
if len(action_audits) <= self.maximum_embedded_action_audits:
|
|
814
|
+
action_audit_storage: dict[str, object] = {
|
|
815
|
+
"mode": "embedded",
|
|
816
|
+
"action_count": len(action_audits),
|
|
817
|
+
}
|
|
818
|
+
embedded_action_audits: dict[str, object] = {
|
|
819
|
+
"actions": action_audits,
|
|
820
|
+
}
|
|
821
|
+
else:
|
|
822
|
+
if self.audit_artifact_store is None:
|
|
823
|
+
raise RuntimeError(
|
|
824
|
+
"large consequence-calibration audits require an "
|
|
825
|
+
"audit_artifact_store"
|
|
826
|
+
)
|
|
827
|
+
action_artifacts: list[dict[str, object]] = []
|
|
828
|
+
for ordinal, action_audit in enumerate(action_audits, start=1):
|
|
829
|
+
artifact = put_json(
|
|
830
|
+
self.audit_artifact_store,
|
|
831
|
+
{
|
|
832
|
+
"schema_version": 1,
|
|
833
|
+
"artifact_kind": (
|
|
834
|
+
"empirical_consequence_calibration_action_audit"
|
|
835
|
+
),
|
|
836
|
+
"scope_sha256": self.scope.scope_sha256,
|
|
837
|
+
"cutoff_wave_index_exclusive": (
|
|
838
|
+
cutoff_wave_index_exclusive
|
|
839
|
+
),
|
|
840
|
+
"source_forecast_receipt_sha256": (
|
|
841
|
+
forecasts.receipt_sha256
|
|
842
|
+
),
|
|
843
|
+
"action_ordinal": ordinal,
|
|
844
|
+
"action": action_audit,
|
|
845
|
+
},
|
|
846
|
+
)
|
|
847
|
+
action_artifacts.append(
|
|
848
|
+
{
|
|
849
|
+
"option_id": action_audit["option_id"],
|
|
850
|
+
"artifact": _artifact_ref_record(artifact),
|
|
851
|
+
}
|
|
852
|
+
)
|
|
853
|
+
action_audit_storage = {
|
|
854
|
+
"mode": "content_addressed_external",
|
|
855
|
+
"action_count": len(action_audits),
|
|
856
|
+
"artifacts": action_artifacts,
|
|
857
|
+
}
|
|
858
|
+
embedded_action_audits = {}
|
|
859
|
+
audit = _object(
|
|
860
|
+
{
|
|
861
|
+
"schema_version": 2,
|
|
862
|
+
"scope_sha256": self.scope.scope_sha256,
|
|
863
|
+
"cutoff_wave_index_exclusive": cutoff_wave_index_exclusive,
|
|
864
|
+
"eligible_prior_action_count": len(actions),
|
|
865
|
+
"metric_aliases": [
|
|
866
|
+
{
|
|
867
|
+
"target_metric_id": value.target_metric_id,
|
|
868
|
+
"forecast_metric_id": value.forecast_metric_id,
|
|
869
|
+
}
|
|
870
|
+
for value in resolved_aliases
|
|
871
|
+
],
|
|
872
|
+
"minimum_path_support": self.minimum_path_support,
|
|
873
|
+
"minimum_family_support": self.minimum_family_support,
|
|
874
|
+
"prior_strength_hex": self.prior_strength.hex(),
|
|
875
|
+
"validity_prior_strength_hex": (self.validity_prior_strength.hex()),
|
|
876
|
+
"maximum_empirical_authority_hex": (
|
|
877
|
+
self.maximum_empirical_authority.hex()
|
|
878
|
+
),
|
|
879
|
+
"recency_decay_hex": self.recency_decay.hex(),
|
|
880
|
+
"minimum_model_score_support": self.minimum_model_score_support,
|
|
881
|
+
"model_family_min_support": self.model_family_min_support,
|
|
882
|
+
"minimum_empirical_score_support": (
|
|
883
|
+
self.minimum_empirical_score_support
|
|
884
|
+
),
|
|
885
|
+
"correctness_prior": self._correctness_prior().to_record(),
|
|
886
|
+
"model_calibration_snapshot_sha256": model_snapshot.snapshot_sha256,
|
|
887
|
+
"action_audit_storage": action_audit_storage,
|
|
888
|
+
**embedded_action_audits,
|
|
889
|
+
"leakage_guard": "only_feedback_wave_lt_exclusive_cutoff",
|
|
890
|
+
"workload_or_model_branches": False,
|
|
891
|
+
}
|
|
892
|
+
)
|
|
893
|
+
return ActionConsequenceCalibrationResult(
|
|
894
|
+
source_forecast_receipt_sha256=forecasts.receipt_sha256,
|
|
895
|
+
cutoff_wave_index_exclusive=cutoff_wave_index_exclusive,
|
|
896
|
+
forecasts=calibrated_batch,
|
|
897
|
+
audit=audit,
|
|
898
|
+
)
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
__all__ = [
|
|
902
|
+
"ActionConsequenceCalibrationPolicy",
|
|
903
|
+
"ActionConsequenceCalibrationResult",
|
|
904
|
+
"EMPIRICAL_CONSEQUENCE_POLICY_DEFINITION_SHA256",
|
|
905
|
+
"EMPIRICAL_CONSEQUENCE_POLICY_ID",
|
|
906
|
+
"EMPIRICAL_CONSEQUENCE_POLICY_VERSION",
|
|
907
|
+
"HierarchicalEmpiricalConsequenceCalibrationPolicy",
|
|
908
|
+
]
|