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,643 @@
|
|
|
1
|
+
"""Typed, workload-neutral contracts for bounded portfolio memory use.
|
|
2
|
+
|
|
3
|
+
Showing a memory card to a selector and claiming that a particular action was
|
|
4
|
+
supported by that card are different events. A single provider call exposes
|
|
5
|
+
the whole response slate to every prompt-visible card, so an uncited member is
|
|
6
|
+
*not* a blinded control. It is nevertheless useful to reserve uncited
|
|
7
|
+
exploration slots and to require every explicit card attribution to name an
|
|
8
|
+
action that trusted application code declared compatible before the call.
|
|
9
|
+
|
|
10
|
+
This module records those narrower claims. It owns no prompt renderer,
|
|
11
|
+
provider, benchmark, evaluator, memory bank, or allocation policy.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import hashlib
|
|
17
|
+
import json
|
|
18
|
+
import re
|
|
19
|
+
from dataclasses import dataclass, field
|
|
20
|
+
from enum import Enum
|
|
21
|
+
|
|
22
|
+
from agent_evolve.domain.patch import require_sha256
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
_TOKEN = re.compile(r"^[a-z][a-z0-9_.:-]{0,255}$")
|
|
26
|
+
_OPTION_ID = re.compile(r"^[a-z][a-z0-9_.-]{0,255}$")
|
|
27
|
+
_CONTRACT_DOMAIN = b"agent-evolve:bounded-portfolio-memory-dose-contract:v1\x00"
|
|
28
|
+
_MEMBER_DOMAIN = b"agent-evolve:portfolio-memory-dose-member:v1\x00"
|
|
29
|
+
_ASSESSMENT_DOMAIN = b"agent-evolve:portfolio-memory-dose-assessment:v1\x00"
|
|
30
|
+
|
|
31
|
+
BOUNDED_PORTFOLIO_MEMORY_DOSE_POLICY_ID = "bounded_relevance_aware_memory_dose"
|
|
32
|
+
BOUNDED_PORTFOLIO_MEMORY_DOSE_POLICY_VERSION = 1
|
|
33
|
+
BOUNDED_PORTFOLIO_MEMORY_DOSE_POLICY_DEFINITION_SHA256 = hashlib.sha256(
|
|
34
|
+
b"agent-evolve:bounded-relevance-aware-memory-dose:v1;"
|
|
35
|
+
b"prompt-wide-exposure-not-blinding;exact-card-coverage;"
|
|
36
|
+
b"bounded-supported-member-count;bounded-cards-per-member;"
|
|
37
|
+
b"precommitted-card-option-compatibility;proposal-evaluation-join"
|
|
38
|
+
).hexdigest()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _canonical_json(value: object) -> bytes:
|
|
42
|
+
return json.dumps(
|
|
43
|
+
value,
|
|
44
|
+
allow_nan=False,
|
|
45
|
+
ensure_ascii=True,
|
|
46
|
+
separators=(",", ":"),
|
|
47
|
+
sort_keys=True,
|
|
48
|
+
).encode("ascii", errors="strict")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _hash(domain: bytes, value: object) -> str:
|
|
52
|
+
return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _require_token(value: str, *, name: str) -> None:
|
|
56
|
+
if type(value) is not str or _TOKEN.fullmatch(value) is None:
|
|
57
|
+
raise ValueError(f"{name} must use the closed token grammar")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _require_option_id(value: str, *, name: str) -> None:
|
|
61
|
+
if type(value) is not str or _OPTION_ID.fullmatch(value) is None:
|
|
62
|
+
raise ValueError(f"{name} must use the closed option grammar")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _canonical_card_keys(values: tuple[str, ...], *, name: str) -> None:
|
|
66
|
+
if type(values) is not tuple or any(type(value) is not str for value in values):
|
|
67
|
+
raise TypeError(f"{name} must be an exact tuple of card keys")
|
|
68
|
+
for value in values:
|
|
69
|
+
_require_token(value, name=name)
|
|
70
|
+
if values != tuple(sorted(set(values))):
|
|
71
|
+
raise ValueError(f"{name} must be unique and canonical")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class PortfolioMemoryDoseStage(str, Enum):
|
|
75
|
+
"""The two outcome-blind boundaries at which dose is checked."""
|
|
76
|
+
|
|
77
|
+
PROPOSED_SLATE = "proposed_slate"
|
|
78
|
+
EVALUATED_PORTFOLIO = "evaluated_portfolio"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class PortfolioMemoryExposureScope(str, Enum):
|
|
82
|
+
"""What the dose receipt can honestly say about prompt exposure."""
|
|
83
|
+
|
|
84
|
+
PROMPT_WIDE = "prompt_wide"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class PortfolioMemoryDoseViolation(str, Enum):
|
|
88
|
+
"""Closed failure reasons suitable for schema repair and durable traces."""
|
|
89
|
+
|
|
90
|
+
FOREIGN_CARD_ATTRIBUTION = "foreign_card_attribution"
|
|
91
|
+
INCOMPATIBLE_CARD_ACTION = "incompatible_card_action"
|
|
92
|
+
TOO_MANY_CARDS_PER_MEMBER = "too_many_cards_per_member"
|
|
93
|
+
ASSIGNED_CARD_OMITTED = "assigned_card_omitted"
|
|
94
|
+
TOO_FEW_SUPPORTED_MEMBERS = "too_few_supported_members"
|
|
95
|
+
TOO_MANY_SUPPORTED_MEMBERS = "too_many_supported_members"
|
|
96
|
+
TOO_FEW_UNATTRIBUTED_MEMBERS = "too_few_unattributed_members"
|
|
97
|
+
EVALUATED_MEMBER_NOT_IN_PROPOSAL = "evaluated_member_not_in_proposal"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
@dataclass(frozen=True, slots=True)
|
|
101
|
+
class PortfolioMemoryDoseCardSupport:
|
|
102
|
+
"""Pre-call exact finite options to which one card may be attributed."""
|
|
103
|
+
|
|
104
|
+
card_key: str
|
|
105
|
+
card_content_sha256: str
|
|
106
|
+
finite_contract_identity_sha256: str
|
|
107
|
+
compatible_options: tuple[tuple[str, str], ...]
|
|
108
|
+
support_policy_id: str
|
|
109
|
+
support_policy_version: int
|
|
110
|
+
support_policy_definition_sha256: str
|
|
111
|
+
|
|
112
|
+
def __post_init__(self) -> None:
|
|
113
|
+
_require_token(self.card_key, name="card_key")
|
|
114
|
+
for name in (
|
|
115
|
+
"card_content_sha256",
|
|
116
|
+
"finite_contract_identity_sha256",
|
|
117
|
+
"support_policy_definition_sha256",
|
|
118
|
+
):
|
|
119
|
+
require_sha256(getattr(self, name), name)
|
|
120
|
+
if type(self.compatible_options) is not tuple or not self.compatible_options:
|
|
121
|
+
raise ValueError("compatible_options must be a non-empty exact tuple")
|
|
122
|
+
option_ids: list[str] = []
|
|
123
|
+
option_identities: list[str] = []
|
|
124
|
+
for item in self.compatible_options:
|
|
125
|
+
if type(item) is not tuple or len(item) != 2:
|
|
126
|
+
raise TypeError("compatible_options must contain exact pairs")
|
|
127
|
+
option_id, option_identity_sha256 = item
|
|
128
|
+
_require_option_id(option_id, name="compatible option_id")
|
|
129
|
+
require_sha256(option_identity_sha256, "compatible option identity")
|
|
130
|
+
option_ids.append(option_id)
|
|
131
|
+
option_identities.append(option_identity_sha256)
|
|
132
|
+
if self.compatible_options != tuple(sorted(set(self.compatible_options))):
|
|
133
|
+
raise ValueError("compatible_options must be unique and canonical")
|
|
134
|
+
if len(set(option_ids)) != len(option_ids):
|
|
135
|
+
raise ValueError("compatible_options cannot repeat an option_id")
|
|
136
|
+
if len(set(option_identities)) != len(option_identities):
|
|
137
|
+
raise ValueError("compatible_options cannot repeat an option identity")
|
|
138
|
+
_require_token(self.support_policy_id, name="support_policy_id")
|
|
139
|
+
if type(self.support_policy_version) is not int or self.support_policy_version <= 0:
|
|
140
|
+
raise ValueError("support_policy_version must be positive")
|
|
141
|
+
|
|
142
|
+
def supports(self, option_id: str, option_identity_sha256: str) -> bool:
|
|
143
|
+
self.__post_init__()
|
|
144
|
+
return (option_id, option_identity_sha256) in self.compatible_options
|
|
145
|
+
|
|
146
|
+
def to_record(self) -> dict[str, object]:
|
|
147
|
+
self.__post_init__()
|
|
148
|
+
return {
|
|
149
|
+
"card_key": self.card_key,
|
|
150
|
+
"card_content_sha256": self.card_content_sha256,
|
|
151
|
+
"finite_contract_identity_sha256": self.finite_contract_identity_sha256,
|
|
152
|
+
"compatible_options": [
|
|
153
|
+
{
|
|
154
|
+
"option_id": option_id,
|
|
155
|
+
"option_identity_sha256": option_identity_sha256,
|
|
156
|
+
}
|
|
157
|
+
for option_id, option_identity_sha256 in self.compatible_options
|
|
158
|
+
],
|
|
159
|
+
"support_policy": {
|
|
160
|
+
"policy_id": self.support_policy_id,
|
|
161
|
+
"policy_version": self.support_policy_version,
|
|
162
|
+
"definition_sha256": self.support_policy_definition_sha256,
|
|
163
|
+
},
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@dataclass(frozen=True, slots=True)
|
|
168
|
+
class BoundedPortfolioMemoryDoseContract:
|
|
169
|
+
"""Precommitted bounds for explicit card-supported proposal/evaluation slots.
|
|
170
|
+
|
|
171
|
+
``supported`` always means an explicit, compatibility-checked attribution.
|
|
172
|
+
It never means that other members were hidden from the card. True card
|
|
173
|
+
blinding requires a separate prompt-redacted provider call.
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
card_supports: tuple[PortfolioMemoryDoseCardSupport, ...]
|
|
177
|
+
proposed_supported_member_bounds: tuple[int, int]
|
|
178
|
+
evaluated_supported_member_bounds: tuple[int, int]
|
|
179
|
+
minimum_unattributed_proposed_members: int
|
|
180
|
+
minimum_unattributed_evaluated_members: int
|
|
181
|
+
maximum_cards_per_member: int = 1
|
|
182
|
+
require_every_assigned_card: bool = True
|
|
183
|
+
exposure_scope: PortfolioMemoryExposureScope = (
|
|
184
|
+
PortfolioMemoryExposureScope.PROMPT_WIDE
|
|
185
|
+
)
|
|
186
|
+
policy_id: str = BOUNDED_PORTFOLIO_MEMORY_DOSE_POLICY_ID
|
|
187
|
+
policy_version: int = BOUNDED_PORTFOLIO_MEMORY_DOSE_POLICY_VERSION
|
|
188
|
+
policy_definition_sha256: str = (
|
|
189
|
+
BOUNDED_PORTFOLIO_MEMORY_DOSE_POLICY_DEFINITION_SHA256
|
|
190
|
+
)
|
|
191
|
+
contract_sha256: str = field(init=False)
|
|
192
|
+
|
|
193
|
+
def __post_init__(self) -> None:
|
|
194
|
+
if (
|
|
195
|
+
type(self.card_supports) is not tuple
|
|
196
|
+
or not self.card_supports
|
|
197
|
+
or any(
|
|
198
|
+
type(value) is not PortfolioMemoryDoseCardSupport
|
|
199
|
+
for value in self.card_supports
|
|
200
|
+
)
|
|
201
|
+
):
|
|
202
|
+
raise ValueError("card_supports must contain exact support values")
|
|
203
|
+
for value in self.card_supports:
|
|
204
|
+
PortfolioMemoryDoseCardSupport.__post_init__(value)
|
|
205
|
+
keys = tuple(value.card_key for value in self.card_supports)
|
|
206
|
+
if keys != tuple(sorted(set(keys))):
|
|
207
|
+
raise ValueError("card_supports must use unique canonical card order")
|
|
208
|
+
contract_ids = {
|
|
209
|
+
value.finite_contract_identity_sha256 for value in self.card_supports
|
|
210
|
+
}
|
|
211
|
+
if len(contract_ids) != 1:
|
|
212
|
+
raise ValueError("all card supports must bind one finite contract")
|
|
213
|
+
for name in (
|
|
214
|
+
"proposed_supported_member_bounds",
|
|
215
|
+
"evaluated_supported_member_bounds",
|
|
216
|
+
):
|
|
217
|
+
bounds = getattr(self, name)
|
|
218
|
+
if (
|
|
219
|
+
type(bounds) is not tuple
|
|
220
|
+
or len(bounds) != 2
|
|
221
|
+
or any(type(value) is not int for value in bounds)
|
|
222
|
+
):
|
|
223
|
+
raise TypeError(f"{name} must be an exact integer pair")
|
|
224
|
+
lower, upper = bounds
|
|
225
|
+
if lower < 0 or upper < lower:
|
|
226
|
+
raise ValueError(f"{name} must be ordered and non-negative")
|
|
227
|
+
if self.require_every_assigned_card and lower < len(keys):
|
|
228
|
+
raise ValueError(
|
|
229
|
+
f"{name} lower bound cannot cover every assigned card"
|
|
230
|
+
)
|
|
231
|
+
for name in (
|
|
232
|
+
"minimum_unattributed_proposed_members",
|
|
233
|
+
"minimum_unattributed_evaluated_members",
|
|
234
|
+
):
|
|
235
|
+
value = getattr(self, name)
|
|
236
|
+
if type(value) is not int or value < 0:
|
|
237
|
+
raise ValueError(f"{name} must be a non-negative exact integer")
|
|
238
|
+
if type(self.maximum_cards_per_member) is not int or (
|
|
239
|
+
self.maximum_cards_per_member <= 0
|
|
240
|
+
):
|
|
241
|
+
raise ValueError("maximum_cards_per_member must be positive")
|
|
242
|
+
if type(self.require_every_assigned_card) is not bool:
|
|
243
|
+
raise TypeError("require_every_assigned_card must be exact bool")
|
|
244
|
+
if self.exposure_scope is not PortfolioMemoryExposureScope.PROMPT_WIDE:
|
|
245
|
+
raise ValueError("bounded dose v1 records prompt-wide exposure only")
|
|
246
|
+
if (
|
|
247
|
+
self.policy_id != BOUNDED_PORTFOLIO_MEMORY_DOSE_POLICY_ID
|
|
248
|
+
or self.policy_version != BOUNDED_PORTFOLIO_MEMORY_DOSE_POLICY_VERSION
|
|
249
|
+
or self.policy_definition_sha256
|
|
250
|
+
!= BOUNDED_PORTFOLIO_MEMORY_DOSE_POLICY_DEFINITION_SHA256
|
|
251
|
+
):
|
|
252
|
+
raise ValueError("unsupported bounded memory-dose policy")
|
|
253
|
+
object.__setattr__(
|
|
254
|
+
self,
|
|
255
|
+
"contract_sha256",
|
|
256
|
+
_hash(_CONTRACT_DOMAIN, self._unsigned_record()),
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
@property
|
|
260
|
+
def assigned_card_keys(self) -> tuple[str, ...]:
|
|
261
|
+
return tuple(value.card_key for value in self.card_supports)
|
|
262
|
+
|
|
263
|
+
@property
|
|
264
|
+
def finite_contract_identity_sha256(self) -> str:
|
|
265
|
+
return self.card_supports[0].finite_contract_identity_sha256
|
|
266
|
+
|
|
267
|
+
def support_for(self, card_key: str) -> PortfolioMemoryDoseCardSupport:
|
|
268
|
+
self.__post_init__()
|
|
269
|
+
for value in self.card_supports:
|
|
270
|
+
if value.card_key == card_key:
|
|
271
|
+
return value
|
|
272
|
+
raise ValueError("card_key is outside the bounded dose contract")
|
|
273
|
+
|
|
274
|
+
def bounds_for(self, stage: PortfolioMemoryDoseStage) -> tuple[int, int]:
|
|
275
|
+
if stage is PortfolioMemoryDoseStage.PROPOSED_SLATE:
|
|
276
|
+
return self.proposed_supported_member_bounds
|
|
277
|
+
if stage is PortfolioMemoryDoseStage.EVALUATED_PORTFOLIO:
|
|
278
|
+
return self.evaluated_supported_member_bounds
|
|
279
|
+
raise TypeError("stage must be exact PortfolioMemoryDoseStage")
|
|
280
|
+
|
|
281
|
+
def minimum_unattributed_for(self, stage: PortfolioMemoryDoseStage) -> int:
|
|
282
|
+
if stage is PortfolioMemoryDoseStage.PROPOSED_SLATE:
|
|
283
|
+
return self.minimum_unattributed_proposed_members
|
|
284
|
+
if stage is PortfolioMemoryDoseStage.EVALUATED_PORTFOLIO:
|
|
285
|
+
return self.minimum_unattributed_evaluated_members
|
|
286
|
+
raise TypeError("stage must be exact PortfolioMemoryDoseStage")
|
|
287
|
+
|
|
288
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
289
|
+
return {
|
|
290
|
+
"schema_version": 1,
|
|
291
|
+
"card_supports": [value.to_record() for value in self.card_supports],
|
|
292
|
+
"proposed_supported_member_bounds": list(
|
|
293
|
+
self.proposed_supported_member_bounds
|
|
294
|
+
),
|
|
295
|
+
"evaluated_supported_member_bounds": list(
|
|
296
|
+
self.evaluated_supported_member_bounds
|
|
297
|
+
),
|
|
298
|
+
"minimum_unattributed_proposed_members": (
|
|
299
|
+
self.minimum_unattributed_proposed_members
|
|
300
|
+
),
|
|
301
|
+
"minimum_unattributed_evaluated_members": (
|
|
302
|
+
self.minimum_unattributed_evaluated_members
|
|
303
|
+
),
|
|
304
|
+
"maximum_cards_per_member": self.maximum_cards_per_member,
|
|
305
|
+
"require_every_assigned_card": self.require_every_assigned_card,
|
|
306
|
+
"exposure_scope": self.exposure_scope.value,
|
|
307
|
+
"policy": {
|
|
308
|
+
"policy_id": self.policy_id,
|
|
309
|
+
"policy_version": self.policy_version,
|
|
310
|
+
"definition_sha256": self.policy_definition_sha256,
|
|
311
|
+
},
|
|
312
|
+
"unattributed_member_interpretation": (
|
|
313
|
+
"prompt_exposed_exploration_not_blinded_control"
|
|
314
|
+
),
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
def to_record(self) -> dict[str, object]:
|
|
318
|
+
self.__post_init__()
|
|
319
|
+
return {**self._unsigned_record(), "contract_sha256": self.contract_sha256}
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
@dataclass(frozen=True, slots=True)
|
|
323
|
+
class PortfolioMemoryDoseMember:
|
|
324
|
+
"""One proposed or evaluated finite option with explicit card attribution."""
|
|
325
|
+
|
|
326
|
+
rank: int
|
|
327
|
+
option_id: str
|
|
328
|
+
option_identity_sha256: str
|
|
329
|
+
supporting_card_keys: tuple[str, ...]
|
|
330
|
+
|
|
331
|
+
def __post_init__(self) -> None:
|
|
332
|
+
if type(self.rank) is not int or self.rank <= 0:
|
|
333
|
+
raise ValueError("rank must be positive")
|
|
334
|
+
_require_option_id(self.option_id, name="option_id")
|
|
335
|
+
require_sha256(self.option_identity_sha256, "option_identity_sha256")
|
|
336
|
+
_canonical_card_keys(self.supporting_card_keys, name="supporting_card_keys")
|
|
337
|
+
|
|
338
|
+
def _content_record(self) -> dict[str, object]:
|
|
339
|
+
return {
|
|
340
|
+
"option_id": self.option_id,
|
|
341
|
+
"option_identity_sha256": self.option_identity_sha256,
|
|
342
|
+
"supporting_card_keys": list(self.supporting_card_keys),
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
@property
|
|
346
|
+
def content_binding_sha256(self) -> str:
|
|
347
|
+
self.__post_init__()
|
|
348
|
+
return _hash(_MEMBER_DOMAIN, self._content_record())
|
|
349
|
+
|
|
350
|
+
def to_record(self) -> dict[str, object]:
|
|
351
|
+
self.__post_init__()
|
|
352
|
+
return {
|
|
353
|
+
"rank": self.rank,
|
|
354
|
+
**self._content_record(),
|
|
355
|
+
"content_binding_sha256": self.content_binding_sha256,
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
@dataclass(frozen=True, slots=True)
|
|
360
|
+
class PortfolioMemoryDoseAssessment:
|
|
361
|
+
"""Content-free, replayable result of one proposal/evaluation dose check."""
|
|
362
|
+
|
|
363
|
+
contract_sha256: str
|
|
364
|
+
stage: PortfolioMemoryDoseStage
|
|
365
|
+
member_content_binding_sha256s: tuple[str, ...]
|
|
366
|
+
supported_member_ranks: tuple[int, ...]
|
|
367
|
+
unattributed_member_ranks: tuple[int, ...]
|
|
368
|
+
card_attribution_ranks: tuple[tuple[str, tuple[int, ...]], ...]
|
|
369
|
+
violations: tuple[PortfolioMemoryDoseViolation, ...]
|
|
370
|
+
proposal_assessment_sha256: str | None = None
|
|
371
|
+
assessment_sha256: str = field(init=False)
|
|
372
|
+
|
|
373
|
+
def __post_init__(self) -> None:
|
|
374
|
+
require_sha256(self.contract_sha256, "contract_sha256")
|
|
375
|
+
if type(self.stage) is not PortfolioMemoryDoseStage:
|
|
376
|
+
raise TypeError("stage must be exact PortfolioMemoryDoseStage")
|
|
377
|
+
if (
|
|
378
|
+
type(self.member_content_binding_sha256s) is not tuple
|
|
379
|
+
or not self.member_content_binding_sha256s
|
|
380
|
+
):
|
|
381
|
+
raise ValueError("member bindings must be a non-empty exact tuple")
|
|
382
|
+
for value in self.member_content_binding_sha256s:
|
|
383
|
+
require_sha256(value, "member content binding")
|
|
384
|
+
ranks = tuple(range(1, len(self.member_content_binding_sha256s) + 1))
|
|
385
|
+
for name in ("supported_member_ranks", "unattributed_member_ranks"):
|
|
386
|
+
values = getattr(self, name)
|
|
387
|
+
if type(values) is not tuple or values != tuple(sorted(set(values))):
|
|
388
|
+
raise ValueError(f"{name} must be unique and canonical")
|
|
389
|
+
if any(type(value) is not int or value not in ranks for value in values):
|
|
390
|
+
raise ValueError(f"{name} contains an invalid rank")
|
|
391
|
+
if set(self.supported_member_ranks).intersection(
|
|
392
|
+
self.unattributed_member_ranks
|
|
393
|
+
) or set(self.supported_member_ranks).union(
|
|
394
|
+
self.unattributed_member_ranks
|
|
395
|
+
) != set(ranks):
|
|
396
|
+
raise ValueError("supported/unattributed ranks must partition members")
|
|
397
|
+
if type(self.card_attribution_ranks) is not tuple:
|
|
398
|
+
raise TypeError("card_attribution_ranks must be an exact tuple")
|
|
399
|
+
keys: list[str] = []
|
|
400
|
+
for item in self.card_attribution_ranks:
|
|
401
|
+
if type(item) is not tuple or len(item) != 2:
|
|
402
|
+
raise TypeError("card_attribution_ranks must contain exact pairs")
|
|
403
|
+
card_key, card_ranks = item
|
|
404
|
+
_require_token(card_key, name="card attribution key")
|
|
405
|
+
if (
|
|
406
|
+
type(card_ranks) is not tuple
|
|
407
|
+
or card_ranks != tuple(sorted(set(card_ranks)))
|
|
408
|
+
or any(value not in ranks for value in card_ranks)
|
|
409
|
+
):
|
|
410
|
+
raise ValueError("card attribution ranks must be canonical")
|
|
411
|
+
keys.append(card_key)
|
|
412
|
+
if keys != sorted(set(keys)):
|
|
413
|
+
raise ValueError("card_attribution_ranks must use canonical card order")
|
|
414
|
+
if type(self.violations) is not tuple or any(
|
|
415
|
+
type(value) is not PortfolioMemoryDoseViolation for value in self.violations
|
|
416
|
+
):
|
|
417
|
+
raise TypeError("violations must contain exact closed values")
|
|
418
|
+
if self.violations != tuple(sorted(set(self.violations), key=lambda x: x.value)):
|
|
419
|
+
raise ValueError("violations must be unique and canonical")
|
|
420
|
+
if self.stage is PortfolioMemoryDoseStage.PROPOSED_SLATE:
|
|
421
|
+
if self.proposal_assessment_sha256 is not None:
|
|
422
|
+
raise ValueError("proposal assessment cannot name an earlier proposal")
|
|
423
|
+
elif self.proposal_assessment_sha256 is None:
|
|
424
|
+
raise ValueError("evaluated assessment must join its proposal")
|
|
425
|
+
else:
|
|
426
|
+
require_sha256(
|
|
427
|
+
self.proposal_assessment_sha256,
|
|
428
|
+
"proposal_assessment_sha256",
|
|
429
|
+
)
|
|
430
|
+
object.__setattr__(
|
|
431
|
+
self,
|
|
432
|
+
"assessment_sha256",
|
|
433
|
+
_hash(_ASSESSMENT_DOMAIN, self._unsigned_record()),
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
@property
|
|
437
|
+
def passed(self) -> bool:
|
|
438
|
+
return not self.violations
|
|
439
|
+
|
|
440
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
441
|
+
return {
|
|
442
|
+
"schema_version": 1,
|
|
443
|
+
"contract_sha256": self.contract_sha256,
|
|
444
|
+
"stage": self.stage.value,
|
|
445
|
+
"member_content_binding_sha256s": list(
|
|
446
|
+
self.member_content_binding_sha256s
|
|
447
|
+
),
|
|
448
|
+
"supported_member_ranks": list(self.supported_member_ranks),
|
|
449
|
+
"unattributed_member_ranks": list(self.unattributed_member_ranks),
|
|
450
|
+
"card_attribution_ranks": [
|
|
451
|
+
{"card_key": key, "member_ranks": list(ranks)}
|
|
452
|
+
for key, ranks in self.card_attribution_ranks
|
|
453
|
+
],
|
|
454
|
+
"violations": [value.value for value in self.violations],
|
|
455
|
+
"proposal_assessment_sha256": self.proposal_assessment_sha256,
|
|
456
|
+
"exposure_scope": PortfolioMemoryExposureScope.PROMPT_WIDE.value,
|
|
457
|
+
"unattributed_members_are_blinded_controls": False,
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
def to_record(self) -> dict[str, object]:
|
|
461
|
+
self.__post_init__()
|
|
462
|
+
return {
|
|
463
|
+
**self._unsigned_record(),
|
|
464
|
+
"passed": self.passed,
|
|
465
|
+
"assessment_sha256": self.assessment_sha256,
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
class PortfolioMemoryDoseRejected(ValueError):
|
|
470
|
+
"""A proposed or evaluated slate violated its sealed dose contract."""
|
|
471
|
+
|
|
472
|
+
def __init__(self, assessment: PortfolioMemoryDoseAssessment) -> None:
|
|
473
|
+
if type(assessment) is not PortfolioMemoryDoseAssessment or assessment.passed:
|
|
474
|
+
raise ValueError("rejection requires a failed exact assessment")
|
|
475
|
+
super().__init__("portfolio violates its bounded memory-dose contract")
|
|
476
|
+
self.assessment = assessment
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
def _assess(
|
|
480
|
+
contract: BoundedPortfolioMemoryDoseContract,
|
|
481
|
+
members: tuple[PortfolioMemoryDoseMember, ...],
|
|
482
|
+
*,
|
|
483
|
+
stage: PortfolioMemoryDoseStage,
|
|
484
|
+
proposal_assessment: PortfolioMemoryDoseAssessment | None,
|
|
485
|
+
) -> PortfolioMemoryDoseAssessment:
|
|
486
|
+
if type(contract) is not BoundedPortfolioMemoryDoseContract:
|
|
487
|
+
raise TypeError("contract must be exact BoundedPortfolioMemoryDoseContract")
|
|
488
|
+
contract.__post_init__()
|
|
489
|
+
if (
|
|
490
|
+
type(members) is not tuple
|
|
491
|
+
or not members
|
|
492
|
+
or any(type(value) is not PortfolioMemoryDoseMember for value in members)
|
|
493
|
+
):
|
|
494
|
+
raise ValueError("members must contain exact dose members")
|
|
495
|
+
for value in members:
|
|
496
|
+
PortfolioMemoryDoseMember.__post_init__(value)
|
|
497
|
+
if tuple(value.rank for value in members) != tuple(range(1, len(members) + 1)):
|
|
498
|
+
raise ValueError("members must use contiguous rank order")
|
|
499
|
+
if len({value.option_id for value in members}) != len(members):
|
|
500
|
+
raise ValueError("members cannot repeat an option_id")
|
|
501
|
+
if len({value.option_identity_sha256 for value in members}) != len(members):
|
|
502
|
+
raise ValueError("members cannot repeat an option identity")
|
|
503
|
+
if type(stage) is not PortfolioMemoryDoseStage:
|
|
504
|
+
raise TypeError("stage must be exact PortfolioMemoryDoseStage")
|
|
505
|
+
if stage is PortfolioMemoryDoseStage.PROPOSED_SLATE:
|
|
506
|
+
if proposal_assessment is not None:
|
|
507
|
+
raise ValueError("proposal stage cannot join an earlier proposal")
|
|
508
|
+
else:
|
|
509
|
+
if type(proposal_assessment) is not PortfolioMemoryDoseAssessment:
|
|
510
|
+
raise TypeError("evaluated stage requires an exact proposal assessment")
|
|
511
|
+
PortfolioMemoryDoseAssessment.__post_init__(proposal_assessment)
|
|
512
|
+
if (
|
|
513
|
+
proposal_assessment.stage is not PortfolioMemoryDoseStage.PROPOSED_SLATE
|
|
514
|
+
or proposal_assessment.contract_sha256 != contract.contract_sha256
|
|
515
|
+
or not proposal_assessment.passed
|
|
516
|
+
):
|
|
517
|
+
raise ValueError("evaluated stage requires a passing matching proposal")
|
|
518
|
+
|
|
519
|
+
violations: set[PortfolioMemoryDoseViolation] = set()
|
|
520
|
+
assigned = set(contract.assigned_card_keys)
|
|
521
|
+
support_by_key = {value.card_key: value for value in contract.card_supports}
|
|
522
|
+
card_ranks = {key: [] for key in contract.assigned_card_keys}
|
|
523
|
+
supported_ranks: list[int] = []
|
|
524
|
+
unattributed_ranks: list[int] = []
|
|
525
|
+
proposal_bindings = (
|
|
526
|
+
set()
|
|
527
|
+
if proposal_assessment is None
|
|
528
|
+
else set(proposal_assessment.member_content_binding_sha256s)
|
|
529
|
+
)
|
|
530
|
+
for member in members:
|
|
531
|
+
keys = member.supporting_card_keys
|
|
532
|
+
if keys:
|
|
533
|
+
supported_ranks.append(member.rank)
|
|
534
|
+
else:
|
|
535
|
+
unattributed_ranks.append(member.rank)
|
|
536
|
+
if len(keys) > contract.maximum_cards_per_member:
|
|
537
|
+
violations.add(PortfolioMemoryDoseViolation.TOO_MANY_CARDS_PER_MEMBER)
|
|
538
|
+
for card_key in keys:
|
|
539
|
+
if card_key not in assigned:
|
|
540
|
+
violations.add(PortfolioMemoryDoseViolation.FOREIGN_CARD_ATTRIBUTION)
|
|
541
|
+
continue
|
|
542
|
+
card_ranks[card_key].append(member.rank)
|
|
543
|
+
if not support_by_key[card_key].supports(
|
|
544
|
+
member.option_id,
|
|
545
|
+
member.option_identity_sha256,
|
|
546
|
+
):
|
|
547
|
+
violations.add(PortfolioMemoryDoseViolation.INCOMPATIBLE_CARD_ACTION)
|
|
548
|
+
if proposal_assessment is not None and (
|
|
549
|
+
member.content_binding_sha256 not in proposal_bindings
|
|
550
|
+
):
|
|
551
|
+
violations.add(
|
|
552
|
+
PortfolioMemoryDoseViolation.EVALUATED_MEMBER_NOT_IN_PROPOSAL
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
if contract.require_every_assigned_card and any(
|
|
556
|
+
not card_ranks[key] for key in contract.assigned_card_keys
|
|
557
|
+
):
|
|
558
|
+
violations.add(PortfolioMemoryDoseViolation.ASSIGNED_CARD_OMITTED)
|
|
559
|
+
lower, upper = contract.bounds_for(stage)
|
|
560
|
+
if len(supported_ranks) < lower:
|
|
561
|
+
violations.add(PortfolioMemoryDoseViolation.TOO_FEW_SUPPORTED_MEMBERS)
|
|
562
|
+
if len(supported_ranks) > upper:
|
|
563
|
+
violations.add(PortfolioMemoryDoseViolation.TOO_MANY_SUPPORTED_MEMBERS)
|
|
564
|
+
if len(unattributed_ranks) < contract.minimum_unattributed_for(stage):
|
|
565
|
+
violations.add(PortfolioMemoryDoseViolation.TOO_FEW_UNATTRIBUTED_MEMBERS)
|
|
566
|
+
return PortfolioMemoryDoseAssessment(
|
|
567
|
+
contract_sha256=contract.contract_sha256,
|
|
568
|
+
stage=stage,
|
|
569
|
+
member_content_binding_sha256s=tuple(
|
|
570
|
+
value.content_binding_sha256 for value in members
|
|
571
|
+
),
|
|
572
|
+
supported_member_ranks=tuple(supported_ranks),
|
|
573
|
+
unattributed_member_ranks=tuple(unattributed_ranks),
|
|
574
|
+
card_attribution_ranks=tuple(
|
|
575
|
+
(key, tuple(card_ranks[key])) for key in contract.assigned_card_keys
|
|
576
|
+
),
|
|
577
|
+
violations=tuple(sorted(violations, key=lambda value: value.value)),
|
|
578
|
+
proposal_assessment_sha256=(
|
|
579
|
+
None
|
|
580
|
+
if proposal_assessment is None
|
|
581
|
+
else proposal_assessment.assessment_sha256
|
|
582
|
+
),
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
def assess_proposed_portfolio_memory_dose(
|
|
587
|
+
contract: BoundedPortfolioMemoryDoseContract,
|
|
588
|
+
members: tuple[PortfolioMemoryDoseMember, ...],
|
|
589
|
+
) -> PortfolioMemoryDoseAssessment:
|
|
590
|
+
"""Assess the complete provider-authored slate before allocation."""
|
|
591
|
+
|
|
592
|
+
return _assess(
|
|
593
|
+
contract,
|
|
594
|
+
members,
|
|
595
|
+
stage=PortfolioMemoryDoseStage.PROPOSED_SLATE,
|
|
596
|
+
proposal_assessment=None,
|
|
597
|
+
)
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
def assess_evaluated_portfolio_memory_dose(
|
|
601
|
+
contract: BoundedPortfolioMemoryDoseContract,
|
|
602
|
+
members: tuple[PortfolioMemoryDoseMember, ...],
|
|
603
|
+
*,
|
|
604
|
+
proposal_assessment: PortfolioMemoryDoseAssessment,
|
|
605
|
+
) -> PortfolioMemoryDoseAssessment:
|
|
606
|
+
"""Assess the allocated portfolio and join it to the sealed proposal."""
|
|
607
|
+
|
|
608
|
+
return _assess(
|
|
609
|
+
contract,
|
|
610
|
+
members,
|
|
611
|
+
stage=PortfolioMemoryDoseStage.EVALUATED_PORTFOLIO,
|
|
612
|
+
proposal_assessment=proposal_assessment,
|
|
613
|
+
)
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
def require_passing_portfolio_memory_dose(
|
|
617
|
+
assessment: PortfolioMemoryDoseAssessment,
|
|
618
|
+
) -> None:
|
|
619
|
+
"""Raise a typed rejection while retaining the complete failure receipt."""
|
|
620
|
+
|
|
621
|
+
if type(assessment) is not PortfolioMemoryDoseAssessment:
|
|
622
|
+
raise TypeError("assessment must be exact PortfolioMemoryDoseAssessment")
|
|
623
|
+
PortfolioMemoryDoseAssessment.__post_init__(assessment)
|
|
624
|
+
if not assessment.passed:
|
|
625
|
+
raise PortfolioMemoryDoseRejected(assessment)
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
__all__ = [
|
|
629
|
+
"BOUNDED_PORTFOLIO_MEMORY_DOSE_POLICY_DEFINITION_SHA256",
|
|
630
|
+
"BOUNDED_PORTFOLIO_MEMORY_DOSE_POLICY_ID",
|
|
631
|
+
"BOUNDED_PORTFOLIO_MEMORY_DOSE_POLICY_VERSION",
|
|
632
|
+
"BoundedPortfolioMemoryDoseContract",
|
|
633
|
+
"PortfolioMemoryDoseAssessment",
|
|
634
|
+
"PortfolioMemoryDoseCardSupport",
|
|
635
|
+
"PortfolioMemoryDoseMember",
|
|
636
|
+
"PortfolioMemoryDoseRejected",
|
|
637
|
+
"PortfolioMemoryDoseStage",
|
|
638
|
+
"PortfolioMemoryDoseViolation",
|
|
639
|
+
"PortfolioMemoryExposureScope",
|
|
640
|
+
"assess_evaluated_portfolio_memory_dose",
|
|
641
|
+
"assess_proposed_portfolio_memory_dose",
|
|
642
|
+
"require_passing_portfolio_memory_dose",
|
|
643
|
+
]
|