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,581 @@
|
|
|
1
|
+
"""Post-treatment attribution audit for portfolio memory waves.
|
|
2
|
+
|
|
3
|
+
Whole-wave reward is the correct endpoint for an intention-to-treat study of
|
|
4
|
+
prompt-visible memory. It is not, however, evidence that an explicitly cited
|
|
5
|
+
card-supported candidate created the reward: an uncited member may be the only
|
|
6
|
+
frontier contributor, and another prompt-wide lane may independently select
|
|
7
|
+
the card's exact option. This module records those distinctions at the common
|
|
8
|
+
generation barrier without importing a benchmark, provider, prompt renderer,
|
|
9
|
+
or archive implementation.
|
|
10
|
+
|
|
11
|
+
The leave-one-out endpoint reuses each wave's precommitted aggregation binding.
|
|
12
|
+
It is descriptive performance attribution, never a causal action effect. A
|
|
13
|
+
true card-effect estimate still requires a prospectively randomized,
|
|
14
|
+
prompt-redacted matched control call.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import hashlib
|
|
20
|
+
import json
|
|
21
|
+
import math
|
|
22
|
+
import re
|
|
23
|
+
from dataclasses import dataclass, field
|
|
24
|
+
|
|
25
|
+
from agent_evolve.application.portfolio_evolution import (
|
|
26
|
+
PortfolioVariationWaveRequest,
|
|
27
|
+
PortfolioVariationWaveResult,
|
|
28
|
+
)
|
|
29
|
+
from agent_evolve.domain.insight import InsightRef
|
|
30
|
+
from agent_evolve.domain.patch import require_sha256
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
_TOKEN = re.compile(r"^[a-z][a-z0-9_.:-]{0,255}$")
|
|
34
|
+
_OPTION_ID = re.compile(r"^[a-z][a-z0-9_.-]{0,255}$")
|
|
35
|
+
_CANDIDATE_DOMAIN = b"agent-evolve:portfolio-memory-candidate-contribution:v1\x00"
|
|
36
|
+
_CARD_DOMAIN = b"agent-evolve:portfolio-memory-card-performance:v1\x00"
|
|
37
|
+
_AUDIT_DOMAIN = b"agent-evolve:portfolio-memory-attribution-audit:v1\x00"
|
|
38
|
+
|
|
39
|
+
PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_ID = (
|
|
40
|
+
"post_treatment_memory_performance_attribution"
|
|
41
|
+
)
|
|
42
|
+
PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_VERSION = 1
|
|
43
|
+
PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_DEFINITION_SHA256 = hashlib.sha256(
|
|
44
|
+
b"agent-evolve:post-treatment-memory-performance-attribution:v1;"
|
|
45
|
+
b"precommitted-wave-aggregator;leave-one-out-member-contribution;"
|
|
46
|
+
b"explicit-card-citation;cross-lane-same-option-interference;"
|
|
47
|
+
b"descriptive-only;no-causal-action-or-card-credit;"
|
|
48
|
+
b"no-online-score-consumption"
|
|
49
|
+
).hexdigest()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _canonical_json(value: object) -> bytes:
|
|
53
|
+
return json.dumps(
|
|
54
|
+
value,
|
|
55
|
+
allow_nan=False,
|
|
56
|
+
ensure_ascii=True,
|
|
57
|
+
separators=(",", ":"),
|
|
58
|
+
sort_keys=True,
|
|
59
|
+
).encode("ascii", errors="strict")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _hash(domain: bytes, value: object) -> str:
|
|
63
|
+
return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _reference_record(reference: InsightRef) -> dict[str, object]:
|
|
67
|
+
if type(reference) is not InsightRef:
|
|
68
|
+
raise TypeError("reference must be an exact InsightRef")
|
|
69
|
+
InsightRef.__post_init__(reference)
|
|
70
|
+
return {
|
|
71
|
+
"insight_id": reference.insight_id.value,
|
|
72
|
+
"version": reference.version,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _finite(value: float, *, name: str) -> None:
|
|
77
|
+
if type(value) is not float or not math.isfinite(value):
|
|
78
|
+
raise TypeError(f"{name} must be a finite canonical float")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dataclass(frozen=True, slots=True)
|
|
82
|
+
class PortfolioMemoryCandidateContribution:
|
|
83
|
+
"""One evaluated member's descriptive contribution to its memory wave."""
|
|
84
|
+
|
|
85
|
+
generation: int
|
|
86
|
+
request_sha256: str
|
|
87
|
+
result_receipt_sha256: str
|
|
88
|
+
parent_candidate_id: str
|
|
89
|
+
candidate_id: str
|
|
90
|
+
rank: int
|
|
91
|
+
option_id: str
|
|
92
|
+
option_identity_sha256: str
|
|
93
|
+
supporting_card_keys: tuple[str, ...]
|
|
94
|
+
supporting_references: tuple[InsightRef, ...]
|
|
95
|
+
member_reward: float
|
|
96
|
+
joint_wave_reward: float
|
|
97
|
+
leave_one_out_wave_reward: float
|
|
98
|
+
leave_one_out_contribution: float
|
|
99
|
+
better_than_any_parent: bool
|
|
100
|
+
dominates_any_parent: bool
|
|
101
|
+
contribution_sha256: str = field(init=False)
|
|
102
|
+
|
|
103
|
+
def __post_init__(self) -> None:
|
|
104
|
+
if type(self.generation) is not int or self.generation <= 0:
|
|
105
|
+
raise ValueError("generation must be positive")
|
|
106
|
+
for name in ("request_sha256", "result_receipt_sha256"):
|
|
107
|
+
require_sha256(getattr(self, name), name)
|
|
108
|
+
for name in ("parent_candidate_id", "candidate_id"):
|
|
109
|
+
value = getattr(self, name)
|
|
110
|
+
if type(value) is not str or _TOKEN.fullmatch(value) is None:
|
|
111
|
+
raise ValueError(f"{name} must use the closed token grammar")
|
|
112
|
+
if type(self.rank) is not int or self.rank <= 0:
|
|
113
|
+
raise ValueError("rank must be positive")
|
|
114
|
+
if type(self.option_id) is not str or _OPTION_ID.fullmatch(self.option_id) is None:
|
|
115
|
+
raise ValueError("option_id must use the closed option grammar")
|
|
116
|
+
require_sha256(self.option_identity_sha256, "option_identity_sha256")
|
|
117
|
+
if (
|
|
118
|
+
type(self.supporting_card_keys) is not tuple
|
|
119
|
+
or self.supporting_card_keys != tuple(sorted(set(self.supporting_card_keys)))
|
|
120
|
+
):
|
|
121
|
+
raise ValueError("supporting_card_keys must be unique and canonical")
|
|
122
|
+
for value in self.supporting_card_keys:
|
|
123
|
+
if type(value) is not str or _TOKEN.fullmatch(value) is None:
|
|
124
|
+
raise ValueError("supporting card key is invalid")
|
|
125
|
+
if (
|
|
126
|
+
type(self.supporting_references) is not tuple
|
|
127
|
+
or len(set(self.supporting_references))
|
|
128
|
+
!= len(self.supporting_references)
|
|
129
|
+
):
|
|
130
|
+
raise ValueError("supporting_references must be unique")
|
|
131
|
+
for value in self.supporting_references:
|
|
132
|
+
InsightRef.__post_init__(value)
|
|
133
|
+
if len(self.supporting_card_keys) != len(self.supporting_references):
|
|
134
|
+
raise ValueError("supporting card keys and references differ")
|
|
135
|
+
for name in (
|
|
136
|
+
"member_reward",
|
|
137
|
+
"joint_wave_reward",
|
|
138
|
+
"leave_one_out_wave_reward",
|
|
139
|
+
"leave_one_out_contribution",
|
|
140
|
+
):
|
|
141
|
+
_finite(getattr(self, name), name=name)
|
|
142
|
+
if type(self.better_than_any_parent) is not bool:
|
|
143
|
+
raise TypeError("better_than_any_parent must be an exact bool")
|
|
144
|
+
if type(self.dominates_any_parent) is not bool:
|
|
145
|
+
raise TypeError("dominates_any_parent must be an exact bool")
|
|
146
|
+
object.__setattr__(
|
|
147
|
+
self,
|
|
148
|
+
"contribution_sha256",
|
|
149
|
+
_hash(_CANDIDATE_DOMAIN, self._unsigned_record()),
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
@property
|
|
153
|
+
def explicitly_card_supported(self) -> bool:
|
|
154
|
+
return bool(self.supporting_references)
|
|
155
|
+
|
|
156
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
157
|
+
return {
|
|
158
|
+
"schema_version": 1,
|
|
159
|
+
"generation": self.generation,
|
|
160
|
+
"request_sha256": self.request_sha256,
|
|
161
|
+
"result_receipt_sha256": self.result_receipt_sha256,
|
|
162
|
+
"parent_candidate_id": self.parent_candidate_id,
|
|
163
|
+
"candidate_id": self.candidate_id,
|
|
164
|
+
"rank": self.rank,
|
|
165
|
+
"option_id": self.option_id,
|
|
166
|
+
"option_identity_sha256": self.option_identity_sha256,
|
|
167
|
+
"supporting_card_keys": list(self.supporting_card_keys),
|
|
168
|
+
"supporting_references": [
|
|
169
|
+
_reference_record(value) for value in self.supporting_references
|
|
170
|
+
],
|
|
171
|
+
"member_reward_hex": self.member_reward.hex(),
|
|
172
|
+
"joint_wave_reward_hex": self.joint_wave_reward.hex(),
|
|
173
|
+
"leave_one_out_wave_reward_hex": self.leave_one_out_wave_reward.hex(),
|
|
174
|
+
"leave_one_out_contribution_hex": self.leave_one_out_contribution.hex(),
|
|
175
|
+
"better_than_any_parent": self.better_than_any_parent,
|
|
176
|
+
"dominates_any_parent": self.dominates_any_parent,
|
|
177
|
+
"explicitly_card_supported": self.explicitly_card_supported,
|
|
178
|
+
"attribution_scope": "post_treatment_descriptive_not_causal_credit",
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
def to_record(self) -> dict[str, object]:
|
|
182
|
+
self.__post_init__()
|
|
183
|
+
return {
|
|
184
|
+
**self._unsigned_record(),
|
|
185
|
+
"contribution_sha256": self.contribution_sha256,
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
@dataclass(frozen=True, slots=True)
|
|
190
|
+
class PortfolioMemoryCardPerformanceAudit:
|
|
191
|
+
"""One explicit card/action join plus cross-lane interference evidence."""
|
|
192
|
+
|
|
193
|
+
reference: InsightRef
|
|
194
|
+
card_key: str
|
|
195
|
+
contribution_sha256: str
|
|
196
|
+
generation: int
|
|
197
|
+
request_sha256: str
|
|
198
|
+
candidate_id: str
|
|
199
|
+
option_id: str
|
|
200
|
+
candidate_member_reward: float
|
|
201
|
+
candidate_leave_one_out_contribution: float
|
|
202
|
+
joint_wave_reward: float
|
|
203
|
+
unsupported_positive_member_count: int
|
|
204
|
+
cross_lane_same_option_candidate_ids: tuple[str, ...]
|
|
205
|
+
receipt_sha256: str = field(init=False)
|
|
206
|
+
|
|
207
|
+
def __post_init__(self) -> None:
|
|
208
|
+
InsightRef.__post_init__(self.reference)
|
|
209
|
+
if type(self.card_key) is not str or _TOKEN.fullmatch(self.card_key) is None:
|
|
210
|
+
raise ValueError("card_key must use the closed token grammar")
|
|
211
|
+
for name in ("contribution_sha256", "request_sha256"):
|
|
212
|
+
require_sha256(getattr(self, name), name)
|
|
213
|
+
if type(self.generation) is not int or self.generation <= 0:
|
|
214
|
+
raise ValueError("generation must be positive")
|
|
215
|
+
if type(self.candidate_id) is not str or _TOKEN.fullmatch(self.candidate_id) is None:
|
|
216
|
+
raise ValueError("candidate_id must use the closed token grammar")
|
|
217
|
+
if type(self.option_id) is not str or _OPTION_ID.fullmatch(self.option_id) is None:
|
|
218
|
+
raise ValueError("option_id must use the closed option grammar")
|
|
219
|
+
for name in (
|
|
220
|
+
"candidate_member_reward",
|
|
221
|
+
"candidate_leave_one_out_contribution",
|
|
222
|
+
"joint_wave_reward",
|
|
223
|
+
):
|
|
224
|
+
_finite(getattr(self, name), name=name)
|
|
225
|
+
if (
|
|
226
|
+
type(self.unsupported_positive_member_count) is not int
|
|
227
|
+
or self.unsupported_positive_member_count < 0
|
|
228
|
+
):
|
|
229
|
+
raise ValueError("unsupported_positive_member_count must be nonnegative")
|
|
230
|
+
if (
|
|
231
|
+
type(self.cross_lane_same_option_candidate_ids) is not tuple
|
|
232
|
+
or self.cross_lane_same_option_candidate_ids
|
|
233
|
+
!= tuple(sorted(set(self.cross_lane_same_option_candidate_ids)))
|
|
234
|
+
):
|
|
235
|
+
raise ValueError("cross-lane candidate IDs must be unique and canonical")
|
|
236
|
+
for value in self.cross_lane_same_option_candidate_ids:
|
|
237
|
+
if type(value) is not str or _TOKEN.fullmatch(value) is None:
|
|
238
|
+
raise ValueError("cross-lane candidate ID is invalid")
|
|
239
|
+
object.__setattr__(
|
|
240
|
+
self,
|
|
241
|
+
"receipt_sha256",
|
|
242
|
+
_hash(_CARD_DOMAIN, self._unsigned_record()),
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
@property
|
|
246
|
+
def cross_lane_action_spillover(self) -> bool:
|
|
247
|
+
return bool(self.cross_lane_same_option_candidate_ids)
|
|
248
|
+
|
|
249
|
+
@property
|
|
250
|
+
def positive_wave_with_nonpositive_supported_action(self) -> bool:
|
|
251
|
+
return self.joint_wave_reward > 0.0 and self.candidate_member_reward <= 0.0
|
|
252
|
+
|
|
253
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
254
|
+
return {
|
|
255
|
+
"schema_version": 1,
|
|
256
|
+
"reference": _reference_record(self.reference),
|
|
257
|
+
"card_key": self.card_key,
|
|
258
|
+
"contribution_sha256": self.contribution_sha256,
|
|
259
|
+
"generation": self.generation,
|
|
260
|
+
"request_sha256": self.request_sha256,
|
|
261
|
+
"candidate_id": self.candidate_id,
|
|
262
|
+
"option_id": self.option_id,
|
|
263
|
+
"candidate_member_reward_hex": self.candidate_member_reward.hex(),
|
|
264
|
+
"candidate_leave_one_out_contribution_hex": (
|
|
265
|
+
self.candidate_leave_one_out_contribution.hex()
|
|
266
|
+
),
|
|
267
|
+
"joint_wave_reward_hex": self.joint_wave_reward.hex(),
|
|
268
|
+
"unsupported_positive_member_count": (
|
|
269
|
+
self.unsupported_positive_member_count
|
|
270
|
+
),
|
|
271
|
+
"cross_lane_same_option_candidate_ids": list(
|
|
272
|
+
self.cross_lane_same_option_candidate_ids
|
|
273
|
+
),
|
|
274
|
+
"cross_lane_action_spillover": self.cross_lane_action_spillover,
|
|
275
|
+
"positive_wave_with_nonpositive_supported_action": (
|
|
276
|
+
self.positive_wave_with_nonpositive_supported_action
|
|
277
|
+
),
|
|
278
|
+
"causal_action_effect_identified": False,
|
|
279
|
+
"eligible_for_online_score_update": False,
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
def to_record(self) -> dict[str, object]:
|
|
283
|
+
self.__post_init__()
|
|
284
|
+
return {**self._unsigned_record(), "receipt_sha256": self.receipt_sha256}
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
@dataclass(frozen=True, slots=True)
|
|
288
|
+
class PortfolioMemoryAttributionAudit:
|
|
289
|
+
"""Generation-wide descriptive audit with an explicit causal boundary."""
|
|
290
|
+
|
|
291
|
+
generation: int
|
|
292
|
+
wave_request_sha256s: tuple[str, ...]
|
|
293
|
+
wave_result_receipt_sha256s: tuple[str, ...]
|
|
294
|
+
candidate_contributions: tuple[PortfolioMemoryCandidateContribution, ...]
|
|
295
|
+
card_performance: tuple[PortfolioMemoryCardPerformanceAudit, ...]
|
|
296
|
+
policy_id: str = field(
|
|
297
|
+
init=False,
|
|
298
|
+
default=PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_ID,
|
|
299
|
+
)
|
|
300
|
+
policy_version: int = field(
|
|
301
|
+
init=False,
|
|
302
|
+
default=PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_VERSION,
|
|
303
|
+
)
|
|
304
|
+
policy_definition_sha256: str = field(
|
|
305
|
+
init=False,
|
|
306
|
+
default=PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_DEFINITION_SHA256,
|
|
307
|
+
)
|
|
308
|
+
audit_sha256: str = field(init=False)
|
|
309
|
+
|
|
310
|
+
def __post_init__(self) -> None:
|
|
311
|
+
if type(self.generation) is not int or self.generation <= 0:
|
|
312
|
+
raise ValueError("generation must be positive")
|
|
313
|
+
for name in ("wave_request_sha256s", "wave_result_receipt_sha256s"):
|
|
314
|
+
values = getattr(self, name)
|
|
315
|
+
if type(values) is not tuple or not values:
|
|
316
|
+
raise ValueError(f"{name} must be non-empty")
|
|
317
|
+
for value in values:
|
|
318
|
+
require_sha256(value, name)
|
|
319
|
+
if values != tuple(sorted(set(values))):
|
|
320
|
+
raise ValueError(f"{name} must be unique and canonical")
|
|
321
|
+
if (
|
|
322
|
+
type(self.candidate_contributions) is not tuple
|
|
323
|
+
or not self.candidate_contributions
|
|
324
|
+
or any(
|
|
325
|
+
type(value) is not PortfolioMemoryCandidateContribution
|
|
326
|
+
for value in self.candidate_contributions
|
|
327
|
+
)
|
|
328
|
+
):
|
|
329
|
+
raise ValueError("candidate_contributions must contain exact values")
|
|
330
|
+
for value in self.candidate_contributions:
|
|
331
|
+
value.__post_init__()
|
|
332
|
+
if value.generation != self.generation:
|
|
333
|
+
raise ValueError("candidate contribution generation differs")
|
|
334
|
+
contribution_ids = tuple(
|
|
335
|
+
value.contribution_sha256 for value in self.candidate_contributions
|
|
336
|
+
)
|
|
337
|
+
if contribution_ids != tuple(sorted(set(contribution_ids))):
|
|
338
|
+
raise ValueError("candidate contributions must use canonical identities")
|
|
339
|
+
if type(self.card_performance) is not tuple or any(
|
|
340
|
+
type(value) is not PortfolioMemoryCardPerformanceAudit
|
|
341
|
+
for value in self.card_performance
|
|
342
|
+
):
|
|
343
|
+
raise TypeError("card_performance must contain exact values")
|
|
344
|
+
known = set(contribution_ids)
|
|
345
|
+
for value in self.card_performance:
|
|
346
|
+
value.__post_init__()
|
|
347
|
+
if value.generation != self.generation:
|
|
348
|
+
raise ValueError("card performance generation differs")
|
|
349
|
+
if value.contribution_sha256 not in known:
|
|
350
|
+
raise ValueError("card performance cites a foreign contribution")
|
|
351
|
+
card_ids = tuple(value.receipt_sha256 for value in self.card_performance)
|
|
352
|
+
if card_ids != tuple(sorted(set(card_ids))):
|
|
353
|
+
raise ValueError("card performance must use canonical identities")
|
|
354
|
+
if (
|
|
355
|
+
self.policy_id != PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_ID
|
|
356
|
+
or self.policy_version
|
|
357
|
+
!= PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_VERSION
|
|
358
|
+
or self.policy_definition_sha256
|
|
359
|
+
!= PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_DEFINITION_SHA256
|
|
360
|
+
):
|
|
361
|
+
raise ValueError("unsupported memory attribution audit policy")
|
|
362
|
+
object.__setattr__(self, "audit_sha256", _hash(_AUDIT_DOMAIN, self._unsigned_record()))
|
|
363
|
+
|
|
364
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
365
|
+
return {
|
|
366
|
+
"schema_version": 1,
|
|
367
|
+
"generation": self.generation,
|
|
368
|
+
"wave_request_sha256s": list(self.wave_request_sha256s),
|
|
369
|
+
"wave_result_receipt_sha256s": list(
|
|
370
|
+
self.wave_result_receipt_sha256s
|
|
371
|
+
),
|
|
372
|
+
"candidate_contribution_sha256s": [
|
|
373
|
+
value.contribution_sha256 for value in self.candidate_contributions
|
|
374
|
+
],
|
|
375
|
+
"card_performance_receipt_sha256s": [
|
|
376
|
+
value.receipt_sha256 for value in self.card_performance
|
|
377
|
+
],
|
|
378
|
+
"policy": {
|
|
379
|
+
"policy_id": self.policy_id,
|
|
380
|
+
"policy_version": self.policy_version,
|
|
381
|
+
"definition_sha256": self.policy_definition_sha256,
|
|
382
|
+
},
|
|
383
|
+
"cross_lane_action_spillover_count": sum(
|
|
384
|
+
value.cross_lane_action_spillover for value in self.card_performance
|
|
385
|
+
),
|
|
386
|
+
"positive_wave_nonpositive_supported_action_count": sum(
|
|
387
|
+
value.positive_wave_with_nonpositive_supported_action
|
|
388
|
+
for value in self.card_performance
|
|
389
|
+
),
|
|
390
|
+
"causal_card_effect_identified": False,
|
|
391
|
+
"causal_action_effect_identified": False,
|
|
392
|
+
"online_score_update_allowed": False,
|
|
393
|
+
"required_successor_design": (
|
|
394
|
+
"prospective_randomized_prompt_redacted_matched_control"
|
|
395
|
+
),
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
def to_record(self) -> dict[str, object]:
|
|
399
|
+
self.__post_init__()
|
|
400
|
+
return {
|
|
401
|
+
**self._unsigned_record(),
|
|
402
|
+
"candidate_contributions": [
|
|
403
|
+
value.to_record() for value in self.candidate_contributions
|
|
404
|
+
],
|
|
405
|
+
"card_performance": [
|
|
406
|
+
value.to_record() for value in self.card_performance
|
|
407
|
+
],
|
|
408
|
+
"audit_sha256": self.audit_sha256,
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def audit_portfolio_memory_attribution(
|
|
413
|
+
*,
|
|
414
|
+
waves: tuple[PortfolioVariationWaveRequest, ...],
|
|
415
|
+
results: tuple[PortfolioVariationWaveResult, ...],
|
|
416
|
+
) -> PortfolioMemoryAttributionAudit | None:
|
|
417
|
+
"""Audit memory-supported action performance at a sealed generation."""
|
|
418
|
+
|
|
419
|
+
if type(waves) is not tuple or type(results) is not tuple:
|
|
420
|
+
raise TypeError("waves/results must be exact tuples")
|
|
421
|
+
if not waves or len(waves) != len(results):
|
|
422
|
+
raise ValueError("waves/results must be non-empty and equally sized")
|
|
423
|
+
if any(type(value) is not PortfolioVariationWaveRequest for value in waves):
|
|
424
|
+
raise TypeError("waves must contain exact requests")
|
|
425
|
+
if any(type(value) is not PortfolioVariationWaveResult for value in results):
|
|
426
|
+
raise TypeError("results must contain exact results")
|
|
427
|
+
for value in waves:
|
|
428
|
+
PortfolioVariationWaveRequest.__post_init__(value)
|
|
429
|
+
for value in results:
|
|
430
|
+
PortfolioVariationWaveResult.__post_init__(value)
|
|
431
|
+
result_by_request = {value.receipt.request_sha256: value for value in results}
|
|
432
|
+
if len(result_by_request) != len(results):
|
|
433
|
+
raise ValueError("results repeat a wave request")
|
|
434
|
+
if set(result_by_request) != {
|
|
435
|
+
value.selection_request.request_sha256 for value in waves
|
|
436
|
+
}:
|
|
437
|
+
raise ValueError("wave requests and results do not form an exact join")
|
|
438
|
+
generations = {value.generation for value in waves}
|
|
439
|
+
if len(generations) != 1:
|
|
440
|
+
raise ValueError("one attribution audit cannot span generations")
|
|
441
|
+
generation = next(iter(generations))
|
|
442
|
+
|
|
443
|
+
contributions: list[PortfolioMemoryCandidateContribution] = []
|
|
444
|
+
for wave in waves:
|
|
445
|
+
credit = wave.memory_credit
|
|
446
|
+
if credit is None:
|
|
447
|
+
continue
|
|
448
|
+
result = result_by_request[wave.selection_request.request_sha256]
|
|
449
|
+
aggregation = credit.aggregation.aggregate
|
|
450
|
+
joint_reward = aggregation(result.outcomes)
|
|
451
|
+
if type(joint_reward) is not float or not math.isfinite(joint_reward):
|
|
452
|
+
raise TypeError("memory aggregation replay must return a finite float")
|
|
453
|
+
committed = result.receipt.memory_credit
|
|
454
|
+
pending = result.pending_memory_credit
|
|
455
|
+
recorded_reward = (
|
|
456
|
+
committed.reward
|
|
457
|
+
if committed is not None
|
|
458
|
+
else (None if pending is None else pending.reward)
|
|
459
|
+
)
|
|
460
|
+
if recorded_reward is None or recorded_reward != joint_reward:
|
|
461
|
+
raise ValueError("memory aggregation replay differs from recorded reward")
|
|
462
|
+
cards = {value.card_key: value.reference for value in wave.selection_request.cards}
|
|
463
|
+
for index, (member, attribution) in enumerate(
|
|
464
|
+
zip(
|
|
465
|
+
result.receipt.members,
|
|
466
|
+
result.action_attributions,
|
|
467
|
+
strict=True,
|
|
468
|
+
)
|
|
469
|
+
):
|
|
470
|
+
remaining = result.outcomes[:index] + result.outcomes[index + 1 :]
|
|
471
|
+
if not remaining:
|
|
472
|
+
raise ValueError(
|
|
473
|
+
"leave-one-out memory attribution requires portfolio_size >= 2"
|
|
474
|
+
)
|
|
475
|
+
without = aggregation(remaining)
|
|
476
|
+
if type(without) is not float or not math.isfinite(without):
|
|
477
|
+
raise TypeError(
|
|
478
|
+
"leave-one-out aggregation replay must return a finite float"
|
|
479
|
+
)
|
|
480
|
+
supporting_keys = attribution.supporting_card_keys
|
|
481
|
+
references = tuple(cards[value] for value in supporting_keys)
|
|
482
|
+
contributions.append(
|
|
483
|
+
PortfolioMemoryCandidateContribution(
|
|
484
|
+
generation=generation,
|
|
485
|
+
request_sha256=wave.selection_request.request_sha256,
|
|
486
|
+
result_receipt_sha256=result.receipt.receipt_sha256,
|
|
487
|
+
parent_candidate_id=wave.parent.candidate_id.value,
|
|
488
|
+
candidate_id=member.materialization.candidate_id.value,
|
|
489
|
+
rank=member.materialization.rank,
|
|
490
|
+
option_id=member.materialization.option_id,
|
|
491
|
+
option_identity_sha256=(
|
|
492
|
+
member.materialization.option_identity_sha256
|
|
493
|
+
),
|
|
494
|
+
supporting_card_keys=supporting_keys,
|
|
495
|
+
supporting_references=references,
|
|
496
|
+
member_reward=member.reward,
|
|
497
|
+
joint_wave_reward=joint_reward,
|
|
498
|
+
leave_one_out_wave_reward=without,
|
|
499
|
+
leave_one_out_contribution=joint_reward - without,
|
|
500
|
+
better_than_any_parent=member.better_than_any_parent,
|
|
501
|
+
dominates_any_parent=member.dominates_any_parent,
|
|
502
|
+
)
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
if not contributions:
|
|
506
|
+
return None
|
|
507
|
+
canonical_contributions = tuple(
|
|
508
|
+
sorted(contributions, key=lambda value: value.contribution_sha256)
|
|
509
|
+
)
|
|
510
|
+
card_rows: list[PortfolioMemoryCardPerformanceAudit] = []
|
|
511
|
+
for contribution in canonical_contributions:
|
|
512
|
+
if not contribution.explicitly_card_supported:
|
|
513
|
+
continue
|
|
514
|
+
same_lane = tuple(
|
|
515
|
+
value
|
|
516
|
+
for value in canonical_contributions
|
|
517
|
+
if value.request_sha256 == contribution.request_sha256
|
|
518
|
+
)
|
|
519
|
+
other_lanes = tuple(
|
|
520
|
+
value
|
|
521
|
+
for value in canonical_contributions
|
|
522
|
+
if value.request_sha256 != contribution.request_sha256
|
|
523
|
+
)
|
|
524
|
+
spillovers = tuple(
|
|
525
|
+
sorted(
|
|
526
|
+
value.candidate_id
|
|
527
|
+
for value in other_lanes
|
|
528
|
+
if value.option_id == contribution.option_id
|
|
529
|
+
)
|
|
530
|
+
)
|
|
531
|
+
unsupported_positive = sum(
|
|
532
|
+
not value.explicitly_card_supported and value.member_reward > 0.0
|
|
533
|
+
for value in same_lane
|
|
534
|
+
)
|
|
535
|
+
for card_key, reference in zip(
|
|
536
|
+
contribution.supporting_card_keys,
|
|
537
|
+
contribution.supporting_references,
|
|
538
|
+
strict=True,
|
|
539
|
+
):
|
|
540
|
+
card_rows.append(
|
|
541
|
+
PortfolioMemoryCardPerformanceAudit(
|
|
542
|
+
reference=reference,
|
|
543
|
+
card_key=card_key,
|
|
544
|
+
contribution_sha256=contribution.contribution_sha256,
|
|
545
|
+
generation=generation,
|
|
546
|
+
request_sha256=contribution.request_sha256,
|
|
547
|
+
candidate_id=contribution.candidate_id,
|
|
548
|
+
option_id=contribution.option_id,
|
|
549
|
+
candidate_member_reward=contribution.member_reward,
|
|
550
|
+
candidate_leave_one_out_contribution=(
|
|
551
|
+
contribution.leave_one_out_contribution
|
|
552
|
+
),
|
|
553
|
+
joint_wave_reward=contribution.joint_wave_reward,
|
|
554
|
+
unsupported_positive_member_count=unsupported_positive,
|
|
555
|
+
cross_lane_same_option_candidate_ids=spillovers,
|
|
556
|
+
)
|
|
557
|
+
)
|
|
558
|
+
return PortfolioMemoryAttributionAudit(
|
|
559
|
+
generation=generation,
|
|
560
|
+
wave_request_sha256s=tuple(
|
|
561
|
+
sorted(value.selection_request.request_sha256 for value in waves)
|
|
562
|
+
),
|
|
563
|
+
wave_result_receipt_sha256s=tuple(
|
|
564
|
+
sorted(value.receipt.receipt_sha256 for value in results)
|
|
565
|
+
),
|
|
566
|
+
candidate_contributions=canonical_contributions,
|
|
567
|
+
card_performance=tuple(
|
|
568
|
+
sorted(card_rows, key=lambda value: value.receipt_sha256)
|
|
569
|
+
),
|
|
570
|
+
)
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
__all__ = [
|
|
574
|
+
"PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_DEFINITION_SHA256",
|
|
575
|
+
"PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_ID",
|
|
576
|
+
"PORTFOLIO_MEMORY_ATTRIBUTION_AUDIT_POLICY_VERSION",
|
|
577
|
+
"PortfolioMemoryAttributionAudit",
|
|
578
|
+
"PortfolioMemoryCandidateContribution",
|
|
579
|
+
"PortfolioMemoryCardPerformanceAudit",
|
|
580
|
+
"audit_portfolio_memory_attribution",
|
|
581
|
+
]
|