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,812 @@
|
|
|
1
|
+
"""Authenticated portable feature projection for T-RAP profile v1.
|
|
2
|
+
|
|
3
|
+
The projector converts typed, prior-only engine facts into the exact 70-column
|
|
4
|
+
development schema. It is intentionally separate from the acquisition model:
|
|
5
|
+
workload adapters materialize configurations and archive snapshots, while this
|
|
6
|
+
module owns generic normalization, transition differencing, target alignment,
|
|
7
|
+
feature order, and cryptographic receipts.
|
|
8
|
+
|
|
9
|
+
Profile v1 is scale-qualified for an eight-member proposal slate, two parent
|
|
10
|
+
lanes, and proposal generations 1/3/5. Those are explicit validation limits,
|
|
11
|
+
not hidden assumptions of the generic acquisition core.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import hashlib
|
|
17
|
+
import json
|
|
18
|
+
import math
|
|
19
|
+
from dataclasses import dataclass
|
|
20
|
+
from statistics import fmean
|
|
21
|
+
from typing import ClassVar, Sequence
|
|
22
|
+
|
|
23
|
+
from agent_evolve.domain.patch import require_sha256
|
|
24
|
+
from agent_evolve.domain.typed_json import (
|
|
25
|
+
FrozenJsonValue,
|
|
26
|
+
thaw_json,
|
|
27
|
+
typed_json_sha256,
|
|
28
|
+
)
|
|
29
|
+
from agent_evolve.policies.selection.calibrated_slate import SlateAllocationRequest
|
|
30
|
+
from agent_evolve.policies.selection.forecast_calibration import ForecastConfidenceBin
|
|
31
|
+
from agent_evolve.policies.selection.structural_posterior_slate import (
|
|
32
|
+
StructuralPosteriorMemberScoreRow,
|
|
33
|
+
)
|
|
34
|
+
from agent_evolve.policies.selection.target_conditioned_prequential import (
|
|
35
|
+
TargetConditionedMemberFeatures,
|
|
36
|
+
)
|
|
37
|
+
from agent_evolve.ports.archive_context import (
|
|
38
|
+
CampaignPortfolioArchiveContextProjection,
|
|
39
|
+
)
|
|
40
|
+
from agent_evolve.ports.frontier_target import CampaignPortfolioFrontierTarget
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
PROJECTOR_ID = "trap_portable_features_v1"
|
|
44
|
+
PROJECTOR_VERSION = 1
|
|
45
|
+
PROJECTOR_DEFINITION_SHA256 = hashlib.sha256(
|
|
46
|
+
b"agent-evolve:trap-portable-features:v1;"
|
|
47
|
+
b"schema=70-exact-columns;inputs=sealed-k8,prior-structural-score-rows,"
|
|
48
|
+
b"typed-parent-child-configurations,authenticated-affine-archive-context,"
|
|
49
|
+
b"authenticated-frontier-target,generation,lane-slot,remaining-horizon;"
|
|
50
|
+
b"scale=k8,two-lanes,generations-1-3-5,horizon-2;"
|
|
51
|
+
b"missing-extra-nonfinite=fail-closed;"
|
|
52
|
+
b"workload-model-provider-option-name-current-outcome-features=false"
|
|
53
|
+
).hexdigest()
|
|
54
|
+
|
|
55
|
+
PORTABLE_FEATURES = (
|
|
56
|
+
"bias",
|
|
57
|
+
*tuple(f"rank_{value}" for value in range(1, 9)),
|
|
58
|
+
"generation_1",
|
|
59
|
+
"generation_3",
|
|
60
|
+
"generation_5",
|
|
61
|
+
"parent_slot_0",
|
|
62
|
+
"parent_slot_1",
|
|
63
|
+
"role_proposal_exploit",
|
|
64
|
+
"role_proposal_falsify",
|
|
65
|
+
"role_proposal_coverage",
|
|
66
|
+
"family_frequency",
|
|
67
|
+
"family_rarity",
|
|
68
|
+
"supporting_card_count",
|
|
69
|
+
"archive_novelty",
|
|
70
|
+
"structural_coverage_raw",
|
|
71
|
+
"calibrated_exploitation_score",
|
|
72
|
+
"calibrated_frontier_score",
|
|
73
|
+
"raw_epistemic_score",
|
|
74
|
+
"structural_coverage_score",
|
|
75
|
+
"epistemic_structural_score",
|
|
76
|
+
"confidence_low_fraction",
|
|
77
|
+
"confidence_medium_fraction",
|
|
78
|
+
"confidence_high_fraction",
|
|
79
|
+
"favorable_fraction",
|
|
80
|
+
"adverse_fraction",
|
|
81
|
+
"abstention_fraction",
|
|
82
|
+
"posterior_correctness_mean",
|
|
83
|
+
"calibration_observation_count_log",
|
|
84
|
+
"transition_change_count",
|
|
85
|
+
"transition_numeric_fraction",
|
|
86
|
+
"transition_categorical_fraction",
|
|
87
|
+
"transition_relative_numeric_delta_log",
|
|
88
|
+
"transition_numeric_sign",
|
|
89
|
+
"transition_path_depth",
|
|
90
|
+
"parent_desirability_mean",
|
|
91
|
+
"parent_desirability_min",
|
|
92
|
+
"parent_desirability_max",
|
|
93
|
+
"archive_base_hypervolume",
|
|
94
|
+
"archive_point_count_log",
|
|
95
|
+
)
|
|
96
|
+
TARGET_FEATURES = (
|
|
97
|
+
"target_favorable_fraction",
|
|
98
|
+
"target_adverse_fraction",
|
|
99
|
+
"target_abstention_fraction",
|
|
100
|
+
"off_target_favorable_fraction",
|
|
101
|
+
"off_target_adverse_fraction",
|
|
102
|
+
"off_target_abstention_fraction",
|
|
103
|
+
"target_declared_confidence",
|
|
104
|
+
"target_posterior_correctness",
|
|
105
|
+
"target_signed_evidence",
|
|
106
|
+
"target_reliability_adjusted_evidence",
|
|
107
|
+
"target_opportunity_from_ideal",
|
|
108
|
+
"target_parent_achievement",
|
|
109
|
+
"target_parent_regret",
|
|
110
|
+
"target_active_axis_fraction",
|
|
111
|
+
"target_zero_axis_fraction",
|
|
112
|
+
*tuple(f"target_opportunity_rank_{value}" for value in range(1, 8)),
|
|
113
|
+
"remaining_proposal_horizon",
|
|
114
|
+
"remaining_proposal_horizon_fraction",
|
|
115
|
+
)
|
|
116
|
+
FEATURE_NAMES = (*PORTABLE_FEATURES, *TARGET_FEATURES)
|
|
117
|
+
|
|
118
|
+
_TRANSITION_DOMAIN = b"agent-evolve:trap-portable-transition:v1\x00"
|
|
119
|
+
_PROJECTION_REQUEST_DOMAIN = b"agent-evolve:trap-feature-request:v1\x00"
|
|
120
|
+
_CONFIDENCE_VALUE = {
|
|
121
|
+
ForecastConfidenceBin.UNKNOWN: 0.0,
|
|
122
|
+
ForecastConfidenceBin.LOW: 1.0 / 3.0,
|
|
123
|
+
ForecastConfidenceBin.MEDIUM: 2.0 / 3.0,
|
|
124
|
+
ForecastConfidenceBin.HIGH: 1.0,
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def _canonical_json(value: object) -> bytes:
|
|
129
|
+
return json.dumps(
|
|
130
|
+
value,
|
|
131
|
+
allow_nan=False,
|
|
132
|
+
ensure_ascii=True,
|
|
133
|
+
separators=(",", ":"),
|
|
134
|
+
sort_keys=True,
|
|
135
|
+
).encode("ascii", errors="strict")
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _hash(domain: bytes, value: object) -> str:
|
|
139
|
+
return hashlib.sha256(domain + _canonical_json(value)).hexdigest()
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _finite(value: float, *, name: str) -> None:
|
|
143
|
+
if type(value) is not float or not math.isfinite(value):
|
|
144
|
+
raise TypeError(f"{name} must be an exact finite float")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _decimal(value: object, *, name: str) -> float:
|
|
148
|
+
if type(value) is not str:
|
|
149
|
+
raise TypeError(f"{name} must be finite decimal text")
|
|
150
|
+
try:
|
|
151
|
+
result = float(value)
|
|
152
|
+
except ValueError as error:
|
|
153
|
+
raise ValueError(f"{name} is not finite decimal text") from error
|
|
154
|
+
_finite(result, name=name)
|
|
155
|
+
return result
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _flatten(value: object, path: str = "$") -> dict[str, object]:
|
|
159
|
+
if type(value) is dict:
|
|
160
|
+
result: dict[str, object] = {}
|
|
161
|
+
for key in sorted(value):
|
|
162
|
+
result.update(_flatten(value[key], f"{path}.{key}"))
|
|
163
|
+
return result
|
|
164
|
+
if type(value) is list:
|
|
165
|
+
result = {}
|
|
166
|
+
for index, item in enumerate(value):
|
|
167
|
+
result.update(_flatten(item, f"{path}[{index}]"))
|
|
168
|
+
return result
|
|
169
|
+
return {path: value}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@dataclass(frozen=True, slots=True, eq=False)
|
|
173
|
+
class PortableTransitionReceipt:
|
|
174
|
+
"""Generic structural delta between one parent and proposed child."""
|
|
175
|
+
|
|
176
|
+
option_id: str
|
|
177
|
+
option_identity_sha256: str
|
|
178
|
+
parent_configuration_sha256: str
|
|
179
|
+
child_configuration_sha256: str
|
|
180
|
+
changed_paths: tuple[str, ...]
|
|
181
|
+
change_count: float
|
|
182
|
+
numeric_fraction: float
|
|
183
|
+
categorical_fraction: float
|
|
184
|
+
relative_numeric_delta_log: float
|
|
185
|
+
numeric_sign: float
|
|
186
|
+
path_depth: float
|
|
187
|
+
|
|
188
|
+
def __post_init__(self) -> None:
|
|
189
|
+
if type(self.option_id) is not str or not self.option_id:
|
|
190
|
+
raise ValueError("option_id must be non-empty")
|
|
191
|
+
for name in (
|
|
192
|
+
"option_identity_sha256",
|
|
193
|
+
"parent_configuration_sha256",
|
|
194
|
+
"child_configuration_sha256",
|
|
195
|
+
):
|
|
196
|
+
require_sha256(getattr(self, name), name)
|
|
197
|
+
if type(self.changed_paths) is not tuple or any(
|
|
198
|
+
type(value) is not str or not value for value in self.changed_paths
|
|
199
|
+
):
|
|
200
|
+
raise TypeError("changed_paths must be an exact string tuple")
|
|
201
|
+
if self.changed_paths != tuple(sorted(set(self.changed_paths))):
|
|
202
|
+
raise ValueError("changed_paths must be unique and canonical")
|
|
203
|
+
for name in (
|
|
204
|
+
"change_count",
|
|
205
|
+
"numeric_fraction",
|
|
206
|
+
"categorical_fraction",
|
|
207
|
+
"relative_numeric_delta_log",
|
|
208
|
+
"numeric_sign",
|
|
209
|
+
"path_depth",
|
|
210
|
+
):
|
|
211
|
+
_finite(getattr(self, name), name=name)
|
|
212
|
+
if self.change_count != float(len(self.changed_paths)):
|
|
213
|
+
raise ValueError("change_count differs from changed_paths")
|
|
214
|
+
for name in ("numeric_fraction", "categorical_fraction"):
|
|
215
|
+
if not 0.0 <= getattr(self, name) <= 1.0:
|
|
216
|
+
raise ValueError(f"{name} must lie in [0, 1]")
|
|
217
|
+
if not -1.0 <= self.numeric_sign <= 1.0:
|
|
218
|
+
raise ValueError("numeric_sign must lie in [-1, 1]")
|
|
219
|
+
if self.relative_numeric_delta_log < 0.0 or self.path_depth < 0.0:
|
|
220
|
+
raise ValueError("transition magnitudes must be non-negative")
|
|
221
|
+
|
|
222
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
223
|
+
self.__post_init__()
|
|
224
|
+
return {
|
|
225
|
+
"schema_version": 1,
|
|
226
|
+
"option_id": self.option_id,
|
|
227
|
+
"option_identity_sha256": self.option_identity_sha256,
|
|
228
|
+
"parent_configuration_sha256": self.parent_configuration_sha256,
|
|
229
|
+
"child_configuration_sha256": self.child_configuration_sha256,
|
|
230
|
+
"changed_paths": list(self.changed_paths),
|
|
231
|
+
"features_hex": {
|
|
232
|
+
"transition_change_count": self.change_count.hex(),
|
|
233
|
+
"transition_numeric_fraction": self.numeric_fraction.hex(),
|
|
234
|
+
"transition_categorical_fraction": self.categorical_fraction.hex(),
|
|
235
|
+
"transition_relative_numeric_delta_log": (
|
|
236
|
+
self.relative_numeric_delta_log.hex()
|
|
237
|
+
),
|
|
238
|
+
"transition_numeric_sign": self.numeric_sign.hex(),
|
|
239
|
+
"transition_path_depth": self.path_depth.hex(),
|
|
240
|
+
},
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
@property
|
|
244
|
+
def transition_sha256(self) -> str:
|
|
245
|
+
return _hash(_TRANSITION_DOMAIN, self._unsigned_record())
|
|
246
|
+
|
|
247
|
+
def to_record(self) -> dict[str, object]:
|
|
248
|
+
return {
|
|
249
|
+
**self._unsigned_record(),
|
|
250
|
+
"transition_sha256": self.transition_sha256,
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
def feature_map(self) -> dict[str, float]:
|
|
254
|
+
self.__post_init__()
|
|
255
|
+
return {
|
|
256
|
+
"transition_change_count": self.change_count,
|
|
257
|
+
"transition_numeric_fraction": self.numeric_fraction,
|
|
258
|
+
"transition_categorical_fraction": self.categorical_fraction,
|
|
259
|
+
"transition_relative_numeric_delta_log": (
|
|
260
|
+
self.relative_numeric_delta_log
|
|
261
|
+
),
|
|
262
|
+
"transition_numeric_sign": self.numeric_sign,
|
|
263
|
+
"transition_path_depth": self.path_depth,
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
def __eq__(self, other: object) -> bool:
|
|
267
|
+
return (
|
|
268
|
+
type(other) is PortableTransitionReceipt
|
|
269
|
+
and self.transition_sha256 == other.transition_sha256
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
__hash__ = None
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def project_portable_transition(
|
|
276
|
+
*,
|
|
277
|
+
option_id: str,
|
|
278
|
+
option_identity_sha256: str,
|
|
279
|
+
parent_configuration: FrozenJsonValue,
|
|
280
|
+
child_configuration: FrozenJsonValue,
|
|
281
|
+
) -> PortableTransitionReceipt:
|
|
282
|
+
"""Compute the profile-v1 configuration delta without domain knowledge."""
|
|
283
|
+
|
|
284
|
+
parent_sha256 = typed_json_sha256(parent_configuration)
|
|
285
|
+
child_sha256 = typed_json_sha256(child_configuration)
|
|
286
|
+
parent = _flatten(thaw_json(parent_configuration))
|
|
287
|
+
child = _flatten(thaw_json(child_configuration))
|
|
288
|
+
paths = sorted(set(parent) | set(child))
|
|
289
|
+
changed = tuple(path for path in paths if parent.get(path) != child.get(path))
|
|
290
|
+
numeric_relative: list[float] = []
|
|
291
|
+
numeric_signs: list[float] = []
|
|
292
|
+
categorical = 0
|
|
293
|
+
for path in changed:
|
|
294
|
+
old = parent.get(path)
|
|
295
|
+
new = child.get(path)
|
|
296
|
+
if (
|
|
297
|
+
type(old) in {int, float}
|
|
298
|
+
and type(new) in {int, float}
|
|
299
|
+
and type(old) is not bool
|
|
300
|
+
and type(new) is not bool
|
|
301
|
+
):
|
|
302
|
+
delta = float(new) - float(old)
|
|
303
|
+
numeric_relative.append(abs(delta) / max(abs(float(old)), 1e-12))
|
|
304
|
+
numeric_signs.append(
|
|
305
|
+
0.0 if delta == 0.0 else math.copysign(1.0, delta)
|
|
306
|
+
)
|
|
307
|
+
else:
|
|
308
|
+
categorical += 1
|
|
309
|
+
denominator = max(1, len(changed))
|
|
310
|
+
depths = [path.count(".") + path.count("[") for path in changed]
|
|
311
|
+
return PortableTransitionReceipt(
|
|
312
|
+
option_id=option_id,
|
|
313
|
+
option_identity_sha256=option_identity_sha256,
|
|
314
|
+
parent_configuration_sha256=parent_sha256,
|
|
315
|
+
child_configuration_sha256=child_sha256,
|
|
316
|
+
changed_paths=changed,
|
|
317
|
+
change_count=float(len(changed)),
|
|
318
|
+
numeric_fraction=len(numeric_relative) / denominator,
|
|
319
|
+
categorical_fraction=categorical / denominator,
|
|
320
|
+
relative_numeric_delta_log=(
|
|
321
|
+
0.0
|
|
322
|
+
if not numeric_relative
|
|
323
|
+
else fmean(math.log1p(value) for value in numeric_relative)
|
|
324
|
+
),
|
|
325
|
+
numeric_sign=0.0 if not numeric_signs else fmean(numeric_signs),
|
|
326
|
+
path_depth=0.0 if not depths else fmean(depths),
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
@dataclass(frozen=True, slots=True, eq=False)
|
|
331
|
+
class TargetConditionedFeatureProjectionRequest:
|
|
332
|
+
allocation_request: SlateAllocationRequest
|
|
333
|
+
structural_score_rows: tuple[StructuralPosteriorMemberScoreRow, ...]
|
|
334
|
+
transition_receipts: tuple[PortableTransitionReceipt, ...]
|
|
335
|
+
archive_context: CampaignPortfolioArchiveContextProjection
|
|
336
|
+
frontier_target: CampaignPortfolioFrontierTarget
|
|
337
|
+
campaign_generation: int
|
|
338
|
+
lane_slot: int
|
|
339
|
+
remaining_proposal_horizon: int
|
|
340
|
+
|
|
341
|
+
def __post_init__(self) -> None:
|
|
342
|
+
if type(self.allocation_request) is not SlateAllocationRequest:
|
|
343
|
+
raise TypeError("allocation_request must be exact")
|
|
344
|
+
self.allocation_request.revalidate()
|
|
345
|
+
if type(self.structural_score_rows) is not tuple or any(
|
|
346
|
+
type(value) is not StructuralPosteriorMemberScoreRow
|
|
347
|
+
for value in self.structural_score_rows
|
|
348
|
+
):
|
|
349
|
+
raise TypeError("structural_score_rows must contain exact rows")
|
|
350
|
+
if type(self.transition_receipts) is not tuple or any(
|
|
351
|
+
type(value) is not PortableTransitionReceipt
|
|
352
|
+
for value in self.transition_receipts
|
|
353
|
+
):
|
|
354
|
+
raise TypeError("transition_receipts must contain exact rows")
|
|
355
|
+
for value in (*self.structural_score_rows, *self.transition_receipts):
|
|
356
|
+
value.__post_init__()
|
|
357
|
+
members = self.allocation_request.slate.members
|
|
358
|
+
member_ids = {value.option_id for value in members}
|
|
359
|
+
score_ids = tuple(value.option_id for value in self.structural_score_rows)
|
|
360
|
+
transition_ids = tuple(value.option_id for value in self.transition_receipts)
|
|
361
|
+
canonical = tuple(sorted(member_ids))
|
|
362
|
+
if score_ids != canonical or transition_ids != canonical:
|
|
363
|
+
raise ValueError("score and transition rows must exactly cover the slate")
|
|
364
|
+
member_by_id = {value.option_id: value for value in members}
|
|
365
|
+
for row in self.structural_score_rows:
|
|
366
|
+
if (
|
|
367
|
+
row.option_identity_sha256
|
|
368
|
+
!= member_by_id[row.option_id].option_identity_sha256
|
|
369
|
+
):
|
|
370
|
+
raise ValueError("structural row names a foreign option")
|
|
371
|
+
parent_sha256 = self.allocation_request.slate.parent_candidate_identity_sha256
|
|
372
|
+
for row in self.transition_receipts:
|
|
373
|
+
if (
|
|
374
|
+
row.option_identity_sha256
|
|
375
|
+
!= member_by_id[row.option_id].option_identity_sha256
|
|
376
|
+
or row.parent_configuration_sha256 != parent_sha256
|
|
377
|
+
):
|
|
378
|
+
raise ValueError("transition row names a foreign parent or option")
|
|
379
|
+
if type(self.archive_context) is not CampaignPortfolioArchiveContextProjection:
|
|
380
|
+
raise TypeError("archive_context must be exact")
|
|
381
|
+
self.archive_context.__post_init__()
|
|
382
|
+
if type(self.frontier_target) is not CampaignPortfolioFrontierTarget:
|
|
383
|
+
raise TypeError("frontier_target must be exact")
|
|
384
|
+
self.frontier_target.__post_init__()
|
|
385
|
+
if (
|
|
386
|
+
self.archive_context.archive_utility_snapshot_sha256
|
|
387
|
+
!= self.frontier_target.archive_utility_snapshot_sha256
|
|
388
|
+
or self.archive_context.parent_configuration_sha256 != parent_sha256
|
|
389
|
+
or self.frontier_target.parent_configuration_sha256 != parent_sha256
|
|
390
|
+
):
|
|
391
|
+
raise ValueError("archive context, target, and slate disagree")
|
|
392
|
+
if type(self.campaign_generation) is not int or self.campaign_generation not in {
|
|
393
|
+
1,
|
|
394
|
+
3,
|
|
395
|
+
5,
|
|
396
|
+
}:
|
|
397
|
+
raise ValueError("profile v1 supports campaign generations 1, 3, and 5")
|
|
398
|
+
if type(self.lane_slot) is not int or self.lane_slot not in {0, 1}:
|
|
399
|
+
raise ValueError("profile v1 supports exactly lane slots 0 and 1")
|
|
400
|
+
expected_horizon = {1: 2, 3: 1, 5: 0}[self.campaign_generation]
|
|
401
|
+
if (
|
|
402
|
+
type(self.remaining_proposal_horizon) is not int
|
|
403
|
+
or self.remaining_proposal_horizon != expected_horizon
|
|
404
|
+
):
|
|
405
|
+
raise ValueError("remaining horizon differs from profile-v1 generation")
|
|
406
|
+
if len(members) != 8:
|
|
407
|
+
raise ValueError("profile v1 requires an exact K8 proposal slate")
|
|
408
|
+
|
|
409
|
+
def _unsigned_record(self) -> dict[str, object]:
|
|
410
|
+
self.__post_init__()
|
|
411
|
+
return {
|
|
412
|
+
"schema_version": 1,
|
|
413
|
+
"allocation_request_sha256": self.allocation_request.request_sha256,
|
|
414
|
+
"structural_score_rows": [
|
|
415
|
+
value.to_record() for value in self.structural_score_rows
|
|
416
|
+
],
|
|
417
|
+
"transition_receipts": [
|
|
418
|
+
value.to_record() for value in self.transition_receipts
|
|
419
|
+
],
|
|
420
|
+
"archive_context": self.archive_context.to_record(),
|
|
421
|
+
"frontier_target": self.frontier_target.to_record(),
|
|
422
|
+
"campaign_generation": self.campaign_generation,
|
|
423
|
+
"lane_slot": self.lane_slot,
|
|
424
|
+
"remaining_proposal_horizon": self.remaining_proposal_horizon,
|
|
425
|
+
"current_or_future_outcomes_consulted": False,
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
@property
|
|
429
|
+
def request_sha256(self) -> str:
|
|
430
|
+
return _hash(_PROJECTION_REQUEST_DOMAIN, self._unsigned_record())
|
|
431
|
+
|
|
432
|
+
def to_record(self) -> dict[str, object]:
|
|
433
|
+
return {**self._unsigned_record(), "request_sha256": self.request_sha256}
|
|
434
|
+
|
|
435
|
+
def __eq__(self, other: object) -> bool:
|
|
436
|
+
return (
|
|
437
|
+
type(other) is TargetConditionedFeatureProjectionRequest
|
|
438
|
+
and self.request_sha256 == other.request_sha256
|
|
439
|
+
)
|
|
440
|
+
|
|
441
|
+
__hash__ = None
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def _weighted(
|
|
445
|
+
rows: dict[str, object],
|
|
446
|
+
metric_ids: Sequence[str],
|
|
447
|
+
weights: Sequence[float],
|
|
448
|
+
value,
|
|
449
|
+
) -> float:
|
|
450
|
+
denominator = sum(weights)
|
|
451
|
+
if denominator <= 0.0:
|
|
452
|
+
return 0.0
|
|
453
|
+
return sum(
|
|
454
|
+
weight * float(value(rows[metric_id]))
|
|
455
|
+
for metric_id, weight in zip(metric_ids, weights, strict=True)
|
|
456
|
+
) / denominator
|
|
457
|
+
|
|
458
|
+
|
|
459
|
+
def _geometry(
|
|
460
|
+
request: TargetConditionedFeatureProjectionRequest,
|
|
461
|
+
) -> tuple[
|
|
462
|
+
tuple[str, ...],
|
|
463
|
+
tuple[float, ...],
|
|
464
|
+
tuple[float, ...],
|
|
465
|
+
float,
|
|
466
|
+
float,
|
|
467
|
+
float,
|
|
468
|
+
tuple[float, ...],
|
|
469
|
+
float,
|
|
470
|
+
int,
|
|
471
|
+
]:
|
|
472
|
+
archive = thaw_json(request.archive_context.payload)
|
|
473
|
+
target = thaw_json(request.frontier_target.payload)
|
|
474
|
+
if type(archive) is not dict or type(target) is not dict:
|
|
475
|
+
raise TypeError("affine archive and target payloads must be objects")
|
|
476
|
+
frame = archive.get("optimization_frame")
|
|
477
|
+
archive_rows = archive.get("archive")
|
|
478
|
+
parent = archive.get("parent")
|
|
479
|
+
target_direction = target.get("target_direction")
|
|
480
|
+
assigned_parent = target.get("assigned_parent")
|
|
481
|
+
if any(
|
|
482
|
+
type(value) is not dict
|
|
483
|
+
for value in (frame, archive_rows, parent, target_direction, assigned_parent)
|
|
484
|
+
):
|
|
485
|
+
raise ValueError("affine archive or target payload is incomplete")
|
|
486
|
+
axes = frame.get("axes")
|
|
487
|
+
directions = frame.get("reference_directions")
|
|
488
|
+
points = archive_rows.get("normalized_points_decimal")
|
|
489
|
+
parent_point_raw = parent.get("normalized_point_decimal")
|
|
490
|
+
if (
|
|
491
|
+
type(axes) is not list
|
|
492
|
+
or len(axes) not in (2, 3)
|
|
493
|
+
or type(directions) is not list
|
|
494
|
+
or type(points) is not list
|
|
495
|
+
or not points
|
|
496
|
+
or type(parent_point_raw) is not list
|
|
497
|
+
or len(parent_point_raw) != len(axes)
|
|
498
|
+
):
|
|
499
|
+
raise ValueError("affine geometry has an unsupported shape")
|
|
500
|
+
metric_ids = tuple(
|
|
501
|
+
axis.get("metric_id") if type(axis) is dict else None for axis in axes
|
|
502
|
+
)
|
|
503
|
+
if any(type(value) is not str for value in metric_ids) or len(
|
|
504
|
+
set(metric_ids)
|
|
505
|
+
) != len(metric_ids):
|
|
506
|
+
raise ValueError("affine axes must use unique metric IDs")
|
|
507
|
+
direction = next(
|
|
508
|
+
(
|
|
509
|
+
value
|
|
510
|
+
for value in directions
|
|
511
|
+
if type(value) is dict
|
|
512
|
+
and value.get("direction_id") == request.frontier_target.direction_id
|
|
513
|
+
),
|
|
514
|
+
None,
|
|
515
|
+
)
|
|
516
|
+
if type(direction) is not dict:
|
|
517
|
+
raise ValueError("frontier target direction is absent from archive context")
|
|
518
|
+
archive_weights_raw = direction.get("normalized_importance_decimal")
|
|
519
|
+
target_weights_raw = target_direction.get("normalized_weights_decimal")
|
|
520
|
+
if (
|
|
521
|
+
type(archive_weights_raw) is not list
|
|
522
|
+
or type(target_weights_raw) is not list
|
|
523
|
+
or len(archive_weights_raw) != len(metric_ids)
|
|
524
|
+
or len(target_weights_raw) != len(metric_ids)
|
|
525
|
+
):
|
|
526
|
+
raise ValueError("frontier weights differ from affine dimension")
|
|
527
|
+
archive_weights = tuple(
|
|
528
|
+
_decimal(value, name="archive direction weight")
|
|
529
|
+
for value in archive_weights_raw
|
|
530
|
+
)
|
|
531
|
+
maximum = max(archive_weights)
|
|
532
|
+
if maximum <= 0.0 or any(value < 0.0 for value in archive_weights):
|
|
533
|
+
raise ValueError("affine direction weights must be non-negative")
|
|
534
|
+
expected_weights = tuple(value / maximum for value in archive_weights)
|
|
535
|
+
weights = tuple(
|
|
536
|
+
_decimal(value, name="target direction weight")
|
|
537
|
+
for value in target_weights_raw
|
|
538
|
+
)
|
|
539
|
+
if any(
|
|
540
|
+
not math.isclose(left, right, rel_tol=0.0, abs_tol=1e-12)
|
|
541
|
+
for left, right in zip(weights, expected_weights, strict=True)
|
|
542
|
+
):
|
|
543
|
+
raise ValueError("frontier target weights disagree with archive context")
|
|
544
|
+
parent_point = tuple(
|
|
545
|
+
_decimal(value, name="archive parent point") for value in parent_point_raw
|
|
546
|
+
)
|
|
547
|
+
assigned_point_raw = assigned_parent.get("normalized_point_decimal")
|
|
548
|
+
if type(assigned_point_raw) is not list or len(assigned_point_raw) != len(
|
|
549
|
+
parent_point
|
|
550
|
+
):
|
|
551
|
+
raise ValueError("frontier target parent point is malformed")
|
|
552
|
+
assigned_point = tuple(
|
|
553
|
+
_decimal(value, name="target parent point") for value in assigned_point_raw
|
|
554
|
+
)
|
|
555
|
+
if any(
|
|
556
|
+
not math.isclose(left, right, rel_tol=0.0, abs_tol=1e-12)
|
|
557
|
+
for left, right in zip(parent_point, assigned_point, strict=True)
|
|
558
|
+
):
|
|
559
|
+
raise ValueError("frontier target parent differs from archive context")
|
|
560
|
+
opportunity = _decimal(
|
|
561
|
+
target_direction.get("opportunity_from_ideal_decimal"),
|
|
562
|
+
name="target opportunity",
|
|
563
|
+
)
|
|
564
|
+
parent_achievement = _decimal(
|
|
565
|
+
assigned_parent.get("achievement_decimal"), name="parent achievement"
|
|
566
|
+
)
|
|
567
|
+
parent_regret = _decimal(
|
|
568
|
+
assigned_parent.get("regret_above_archive_best_decimal"),
|
|
569
|
+
name="parent regret",
|
|
570
|
+
)
|
|
571
|
+
base_hypervolume = _decimal(
|
|
572
|
+
frame.get("base_hypervolume_decimal"), name="base hypervolume"
|
|
573
|
+
)
|
|
574
|
+
return (
|
|
575
|
+
metric_ids,
|
|
576
|
+
weights,
|
|
577
|
+
tuple(float(value == 0.0) for value in weights),
|
|
578
|
+
opportunity,
|
|
579
|
+
parent_achievement,
|
|
580
|
+
parent_regret,
|
|
581
|
+
parent_point,
|
|
582
|
+
base_hypervolume,
|
|
583
|
+
len(points),
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
@dataclass(frozen=True, slots=True)
|
|
588
|
+
class TargetConditionedPortableFeatureProjector:
|
|
589
|
+
projector_id: ClassVar[str] = PROJECTOR_ID
|
|
590
|
+
projector_version: ClassVar[int] = PROJECTOR_VERSION
|
|
591
|
+
definition_sha256: ClassVar[str] = PROJECTOR_DEFINITION_SHA256
|
|
592
|
+
feature_names: ClassVar[tuple[str, ...]] = FEATURE_NAMES
|
|
593
|
+
|
|
594
|
+
def project(
|
|
595
|
+
self, request: TargetConditionedFeatureProjectionRequest
|
|
596
|
+
) -> tuple[TargetConditionedMemberFeatures, ...]:
|
|
597
|
+
if type(request) is not TargetConditionedFeatureProjectionRequest:
|
|
598
|
+
raise TypeError("request must be exact")
|
|
599
|
+
request.__post_init__()
|
|
600
|
+
(
|
|
601
|
+
metric_ids,
|
|
602
|
+
target_weights,
|
|
603
|
+
off_target_weights,
|
|
604
|
+
opportunity,
|
|
605
|
+
parent_achievement,
|
|
606
|
+
parent_regret,
|
|
607
|
+
parent_point,
|
|
608
|
+
base_hypervolume,
|
|
609
|
+
archive_point_count,
|
|
610
|
+
) = _geometry(request)
|
|
611
|
+
members = {
|
|
612
|
+
value.option_id: value for value in request.allocation_request.slate.members
|
|
613
|
+
}
|
|
614
|
+
scores = {value.option_id: value for value in request.structural_score_rows}
|
|
615
|
+
transitions = {
|
|
616
|
+
value.option_id: value for value in request.transition_receipts
|
|
617
|
+
}
|
|
618
|
+
family_counts: dict[str, int] = {}
|
|
619
|
+
for member in members.values():
|
|
620
|
+
family_counts[member.family] = family_counts.get(member.family, 0) + 1
|
|
621
|
+
desirability = tuple(1.0 - value for value in parent_point)
|
|
622
|
+
rows = []
|
|
623
|
+
for option_id in sorted(members):
|
|
624
|
+
member = members[option_id]
|
|
625
|
+
score = scores[option_id]
|
|
626
|
+
metric_rows = {value.metric_id: value for value in score.metric_scores}
|
|
627
|
+
if set(metric_rows) != set(metric_ids):
|
|
628
|
+
raise ValueError("structural metrics differ from affine target axes")
|
|
629
|
+
count = float(len(metric_rows))
|
|
630
|
+
|
|
631
|
+
def weighted(weights: Sequence[float], value) -> float:
|
|
632
|
+
return _weighted(metric_rows, metric_ids, weights, value)
|
|
633
|
+
|
|
634
|
+
signed = lambda row: float(row.favorable_assertion) - float( # noqa: E731
|
|
635
|
+
row.adverse_assertion
|
|
636
|
+
)
|
|
637
|
+
features: dict[str, float] = {"bias": 1.0}
|
|
638
|
+
for rank in range(1, 9):
|
|
639
|
+
features[f"rank_{rank}"] = float(member.model_rank == rank)
|
|
640
|
+
for generation in (1, 3, 5):
|
|
641
|
+
features[f"generation_{generation}"] = float(
|
|
642
|
+
request.campaign_generation == generation
|
|
643
|
+
)
|
|
644
|
+
features["parent_slot_0"] = float(request.lane_slot == 0)
|
|
645
|
+
features["parent_slot_1"] = float(request.lane_slot == 1)
|
|
646
|
+
for role in ("exploit", "falsify", "coverage"):
|
|
647
|
+
features[f"role_proposal_{role}"] = float(
|
|
648
|
+
member.role_proposal.value == role
|
|
649
|
+
)
|
|
650
|
+
family_frequency = family_counts[member.family] / 8.0
|
|
651
|
+
features.update(
|
|
652
|
+
{
|
|
653
|
+
"family_frequency": family_frequency,
|
|
654
|
+
"family_rarity": 1.0 / max(1.0, 8.0 * family_frequency),
|
|
655
|
+
"supporting_card_count": float(len(member.supporting_card_keys)),
|
|
656
|
+
"archive_novelty": (
|
|
657
|
+
member.structural_evidence.archive_novelty_score
|
|
658
|
+
),
|
|
659
|
+
"structural_coverage_raw": (
|
|
660
|
+
member.structural_evidence.structural_coverage_score
|
|
661
|
+
),
|
|
662
|
+
"calibrated_exploitation_score": (
|
|
663
|
+
score.calibrated_exploitation_score
|
|
664
|
+
),
|
|
665
|
+
"calibrated_frontier_score": score.calibrated_frontier_score,
|
|
666
|
+
"raw_epistemic_score": score.raw_epistemic_score,
|
|
667
|
+
"structural_coverage_score": score.structural_coverage_score,
|
|
668
|
+
"epistemic_structural_score": score.epistemic_structural_score,
|
|
669
|
+
"confidence_low_fraction": sum(
|
|
670
|
+
value.confidence is ForecastConfidenceBin.LOW
|
|
671
|
+
for value in metric_rows.values()
|
|
672
|
+
)
|
|
673
|
+
/ count,
|
|
674
|
+
"confidence_medium_fraction": sum(
|
|
675
|
+
value.confidence is ForecastConfidenceBin.MEDIUM
|
|
676
|
+
for value in metric_rows.values()
|
|
677
|
+
)
|
|
678
|
+
/ count,
|
|
679
|
+
"confidence_high_fraction": sum(
|
|
680
|
+
value.confidence is ForecastConfidenceBin.HIGH
|
|
681
|
+
for value in metric_rows.values()
|
|
682
|
+
)
|
|
683
|
+
/ count,
|
|
684
|
+
"favorable_fraction": sum(
|
|
685
|
+
value.favorable_assertion for value in metric_rows.values()
|
|
686
|
+
)
|
|
687
|
+
/ count,
|
|
688
|
+
"adverse_fraction": sum(
|
|
689
|
+
value.adverse_assertion for value in metric_rows.values()
|
|
690
|
+
)
|
|
691
|
+
/ count,
|
|
692
|
+
"abstention_fraction": sum(
|
|
693
|
+
value.explicit_abstention for value in metric_rows.values()
|
|
694
|
+
)
|
|
695
|
+
/ count,
|
|
696
|
+
"posterior_correctness_mean": fmean(
|
|
697
|
+
value.calibration_cell.posterior_correctness
|
|
698
|
+
for value in metric_rows.values()
|
|
699
|
+
),
|
|
700
|
+
"calibration_observation_count_log": math.log1p(
|
|
701
|
+
sum(
|
|
702
|
+
value.calibration_cell.observation_count
|
|
703
|
+
for value in metric_rows.values()
|
|
704
|
+
)
|
|
705
|
+
),
|
|
706
|
+
**transitions[option_id].feature_map(),
|
|
707
|
+
"parent_desirability_mean": fmean(desirability),
|
|
708
|
+
"parent_desirability_min": min(desirability),
|
|
709
|
+
"parent_desirability_max": max(desirability),
|
|
710
|
+
"archive_base_hypervolume": base_hypervolume,
|
|
711
|
+
"archive_point_count_log": math.log1p(archive_point_count),
|
|
712
|
+
"target_favorable_fraction": weighted(
|
|
713
|
+
target_weights, lambda row: row.favorable_assertion
|
|
714
|
+
),
|
|
715
|
+
"target_adverse_fraction": weighted(
|
|
716
|
+
target_weights, lambda row: row.adverse_assertion
|
|
717
|
+
),
|
|
718
|
+
"target_abstention_fraction": weighted(
|
|
719
|
+
target_weights, lambda row: row.explicit_abstention
|
|
720
|
+
),
|
|
721
|
+
"off_target_favorable_fraction": weighted(
|
|
722
|
+
off_target_weights, lambda row: row.favorable_assertion
|
|
723
|
+
),
|
|
724
|
+
"off_target_adverse_fraction": weighted(
|
|
725
|
+
off_target_weights, lambda row: row.adverse_assertion
|
|
726
|
+
),
|
|
727
|
+
"off_target_abstention_fraction": weighted(
|
|
728
|
+
off_target_weights, lambda row: row.explicit_abstention
|
|
729
|
+
),
|
|
730
|
+
"target_declared_confidence": weighted(
|
|
731
|
+
target_weights, lambda row: _CONFIDENCE_VALUE[row.confidence]
|
|
732
|
+
),
|
|
733
|
+
"target_posterior_correctness": weighted(
|
|
734
|
+
target_weights,
|
|
735
|
+
lambda row: row.calibration_cell.posterior_correctness,
|
|
736
|
+
),
|
|
737
|
+
"target_signed_evidence": weighted(target_weights, signed),
|
|
738
|
+
"target_reliability_adjusted_evidence": weighted(
|
|
739
|
+
target_weights,
|
|
740
|
+
lambda row: signed(row)
|
|
741
|
+
* (2.0 * row.calibration_cell.posterior_correctness - 1.0),
|
|
742
|
+
),
|
|
743
|
+
"target_opportunity_from_ideal": opportunity,
|
|
744
|
+
"target_parent_achievement": parent_achievement,
|
|
745
|
+
"target_parent_regret": parent_regret,
|
|
746
|
+
"target_active_axis_fraction": sum(
|
|
747
|
+
value > 0.0 for value in target_weights
|
|
748
|
+
)
|
|
749
|
+
/ len(target_weights),
|
|
750
|
+
"target_zero_axis_fraction": sum(
|
|
751
|
+
value == 0.0 for value in target_weights
|
|
752
|
+
)
|
|
753
|
+
/ len(target_weights),
|
|
754
|
+
"remaining_proposal_horizon": float(
|
|
755
|
+
request.remaining_proposal_horizon
|
|
756
|
+
),
|
|
757
|
+
"remaining_proposal_horizon_fraction": (
|
|
758
|
+
request.remaining_proposal_horizon / 2.0
|
|
759
|
+
),
|
|
760
|
+
}
|
|
761
|
+
)
|
|
762
|
+
for rank in range(1, 8):
|
|
763
|
+
features[f"target_opportunity_rank_{rank}"] = float(
|
|
764
|
+
request.frontier_target.opportunity_rank == rank
|
|
765
|
+
)
|
|
766
|
+
if set(features) != set(self.feature_names):
|
|
767
|
+
raise RuntimeError("portable feature implementation drifted")
|
|
768
|
+
values = tuple(float(features[name]) for name in self.feature_names)
|
|
769
|
+
if any(not math.isfinite(value) for value in values):
|
|
770
|
+
raise ValueError("portable features must all be finite")
|
|
771
|
+
rows.append(
|
|
772
|
+
TargetConditionedMemberFeatures(
|
|
773
|
+
option_id=option_id,
|
|
774
|
+
option_identity_sha256=member.option_identity_sha256,
|
|
775
|
+
feature_names=self.feature_names,
|
|
776
|
+
values=values,
|
|
777
|
+
projector_id=self.projector_id,
|
|
778
|
+
projector_version=self.projector_version,
|
|
779
|
+
projector_definition_sha256=self.definition_sha256,
|
|
780
|
+
)
|
|
781
|
+
)
|
|
782
|
+
return tuple(rows)
|
|
783
|
+
|
|
784
|
+
def to_record(self) -> dict[str, object]:
|
|
785
|
+
return {
|
|
786
|
+
"projector_id": self.projector_id,
|
|
787
|
+
"projector_version": self.projector_version,
|
|
788
|
+
"definition_sha256": self.definition_sha256,
|
|
789
|
+
"feature_names": list(self.feature_names),
|
|
790
|
+
"scale_qualification": {
|
|
791
|
+
"proposal_slate_size": 8,
|
|
792
|
+
"lane_slots": 2,
|
|
793
|
+
"proposal_generations": [1, 3, 5],
|
|
794
|
+
"maximum_remaining_horizon": 2,
|
|
795
|
+
},
|
|
796
|
+
"workload_model_provider_option_name_features": False,
|
|
797
|
+
"current_or_future_outcomes_consulted": False,
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
__all__ = [
|
|
802
|
+
"FEATURE_NAMES",
|
|
803
|
+
"PORTABLE_FEATURES",
|
|
804
|
+
"PROJECTOR_DEFINITION_SHA256",
|
|
805
|
+
"PROJECTOR_ID",
|
|
806
|
+
"PROJECTOR_VERSION",
|
|
807
|
+
"PortableTransitionReceipt",
|
|
808
|
+
"TARGET_FEATURES",
|
|
809
|
+
"TargetConditionedFeatureProjectionRequest",
|
|
810
|
+
"TargetConditionedPortableFeatureProjector",
|
|
811
|
+
"project_portable_transition",
|
|
812
|
+
]
|