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,758 @@
|
|
|
1
|
+
"""Content-addressed, provider-free live-runtime provenance manifests.
|
|
2
|
+
|
|
3
|
+
The application layer owns the immutable record and its validation rules. It
|
|
4
|
+
does not know any benchmark, provider SDK, credential source, or evaluator.
|
|
5
|
+
Composition roots supply closed JSON sections and an explicit role-indexed
|
|
6
|
+
source closure. Local probes are deliberately content-blind: git diffs and
|
|
7
|
+
status are hashed but never embedded, so a manifest cannot leak source or
|
|
8
|
+
secrets through provenance metadata.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import hashlib
|
|
14
|
+
import importlib.metadata
|
|
15
|
+
import json
|
|
16
|
+
import os
|
|
17
|
+
import platform
|
|
18
|
+
import re
|
|
19
|
+
import subprocess
|
|
20
|
+
import sys
|
|
21
|
+
from dataclasses import dataclass, field
|
|
22
|
+
from datetime import datetime
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
from typing import Mapping, Sequence
|
|
25
|
+
|
|
26
|
+
from agent_evolve.domain.typed_json import (
|
|
27
|
+
FrozenJsonObject,
|
|
28
|
+
freeze_json,
|
|
29
|
+
thaw_json,
|
|
30
|
+
)
|
|
31
|
+
from agent_evolve.ports.artifact_store import decode_json_bytes
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
_SHA256 = re.compile(r"^[0-9a-f]{64}$")
|
|
35
|
+
_TOKEN = re.compile(r"^[a-z][a-z0-9_.-]{0,95}$")
|
|
36
|
+
_UTC_SECONDS = re.compile(r"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}Z$")
|
|
37
|
+
_FILE_DOMAIN = b"agent-evolve:live-runtime-file:v1\x00"
|
|
38
|
+
_SOURCE_DOMAIN = b"agent-evolve:live-runtime-source-closure:v1\x00"
|
|
39
|
+
_SECTION_DOMAIN = b"agent-evolve:live-runtime-section:v1\x00"
|
|
40
|
+
_MANIFEST_DOMAIN = b"agent-evolve:live-runtime-manifest:v1\x00"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class LiveRuntimeManifestError(RuntimeError):
|
|
44
|
+
"""A prospective runtime commitment is missing or has drifted."""
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _canonical_bytes(value: object) -> bytes:
|
|
48
|
+
return json.dumps(
|
|
49
|
+
value,
|
|
50
|
+
ensure_ascii=True,
|
|
51
|
+
allow_nan=False,
|
|
52
|
+
separators=(",", ":"),
|
|
53
|
+
sort_keys=True,
|
|
54
|
+
).encode("ascii")
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _hash(domain: bytes, value: object) -> str:
|
|
58
|
+
return hashlib.sha256(domain + _canonical_bytes(value)).hexdigest()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _sha256_bytes(value: bytes) -> str:
|
|
62
|
+
return hashlib.sha256(value).hexdigest()
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _exact_json_equal(left: object, right: object) -> bool:
|
|
66
|
+
"""JSON equality that does not conflate bool with integer values."""
|
|
67
|
+
|
|
68
|
+
if type(left) is not type(right):
|
|
69
|
+
return False
|
|
70
|
+
if type(left) is dict:
|
|
71
|
+
assert type(right) is dict
|
|
72
|
+
return left.keys() == right.keys() and all(
|
|
73
|
+
_exact_json_equal(left[key], right[key]) for key in left
|
|
74
|
+
)
|
|
75
|
+
if type(left) is list:
|
|
76
|
+
assert type(right) is list
|
|
77
|
+
return len(left) == len(right) and all(
|
|
78
|
+
_exact_json_equal(a, b) for a, b in zip(left, right, strict=True)
|
|
79
|
+
)
|
|
80
|
+
return left == right
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _validate_token(value: str, *, name: str) -> None:
|
|
84
|
+
if type(value) is not str or _TOKEN.fullmatch(value) is None:
|
|
85
|
+
raise ValueError(f"{name} must use the closed lowercase token grammar")
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _validate_logical_path(value: str) -> None:
|
|
89
|
+
if type(value) is not str or not value or "\\" in value:
|
|
90
|
+
raise ValueError("logical_path must be non-empty canonical POSIX text")
|
|
91
|
+
parsed = Path(value)
|
|
92
|
+
if parsed.is_absolute() or value != parsed.as_posix() or ".." in parsed.parts:
|
|
93
|
+
raise ValueError("logical_path must be relative canonical POSIX text")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@dataclass(frozen=True, slots=True)
|
|
97
|
+
class RuntimeFileBinding:
|
|
98
|
+
"""Exact bytes for one source, lock, route, or evaluator dependency."""
|
|
99
|
+
|
|
100
|
+
logical_path: str
|
|
101
|
+
resolved_path: str
|
|
102
|
+
size_bytes: int
|
|
103
|
+
sha256: str
|
|
104
|
+
binding_sha256: str = field(init=False)
|
|
105
|
+
|
|
106
|
+
def __post_init__(self) -> None:
|
|
107
|
+
_validate_logical_path(self.logical_path)
|
|
108
|
+
resolved = Path(self.resolved_path)
|
|
109
|
+
if (
|
|
110
|
+
type(self.resolved_path) is not str
|
|
111
|
+
or not resolved.is_absolute()
|
|
112
|
+
or self.resolved_path != str(resolved)
|
|
113
|
+
):
|
|
114
|
+
raise ValueError("resolved_path must be an absolute normalized path")
|
|
115
|
+
if type(self.size_bytes) is not int or self.size_bytes < 0:
|
|
116
|
+
raise ValueError("size_bytes must be a non-negative exact integer")
|
|
117
|
+
if type(self.sha256) is not str or _SHA256.fullmatch(self.sha256) is None:
|
|
118
|
+
raise ValueError("sha256 must be a lowercase SHA-256 digest")
|
|
119
|
+
object.__setattr__(
|
|
120
|
+
self,
|
|
121
|
+
"binding_sha256",
|
|
122
|
+
_hash(_FILE_DOMAIN, self._identity_record()),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
def _identity_record(self) -> dict[str, object]:
|
|
126
|
+
return {
|
|
127
|
+
"logical_path": self.logical_path,
|
|
128
|
+
"resolved_path": self.resolved_path,
|
|
129
|
+
"size_bytes": self.size_bytes,
|
|
130
|
+
"sha256": self.sha256,
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
def to_record(self) -> dict[str, object]:
|
|
134
|
+
self.__post_init__()
|
|
135
|
+
return {**self._identity_record(), "binding_sha256": self.binding_sha256}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def capture_runtime_file(path: Path, *, logical_path: str) -> RuntimeFileBinding:
|
|
139
|
+
"""Hash one exact file without interpreting or publishing its contents."""
|
|
140
|
+
|
|
141
|
+
_validate_logical_path(logical_path)
|
|
142
|
+
resolved = path.expanduser().resolve(strict=True)
|
|
143
|
+
if not resolved.is_file():
|
|
144
|
+
raise LiveRuntimeManifestError(f"runtime dependency is not a file: {resolved}")
|
|
145
|
+
content = resolved.read_bytes()
|
|
146
|
+
return RuntimeFileBinding(
|
|
147
|
+
logical_path=logical_path,
|
|
148
|
+
resolved_path=str(resolved),
|
|
149
|
+
size_bytes=len(content),
|
|
150
|
+
sha256=_sha256_bytes(content),
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@dataclass(frozen=True, slots=True)
|
|
155
|
+
class RuntimeSourceClosure:
|
|
156
|
+
"""Role-indexed conservative closure over every live execution byte."""
|
|
157
|
+
|
|
158
|
+
files: tuple[RuntimeFileBinding, ...]
|
|
159
|
+
role_paths: tuple[tuple[str, tuple[str, ...]], ...]
|
|
160
|
+
source_sha256: str = field(init=False)
|
|
161
|
+
|
|
162
|
+
def __post_init__(self) -> None:
|
|
163
|
+
if (
|
|
164
|
+
type(self.files) is not tuple
|
|
165
|
+
or not self.files
|
|
166
|
+
or any(type(value) is not RuntimeFileBinding for value in self.files)
|
|
167
|
+
):
|
|
168
|
+
raise TypeError("files must be a non-empty exact tuple of bindings")
|
|
169
|
+
for value in self.files:
|
|
170
|
+
value.__post_init__()
|
|
171
|
+
if self.files != tuple(sorted(self.files, key=lambda value: value.logical_path)):
|
|
172
|
+
raise ValueError("source files must be ordered by logical_path")
|
|
173
|
+
logical_paths = tuple(value.logical_path for value in self.files)
|
|
174
|
+
if len(set(logical_paths)) != len(logical_paths):
|
|
175
|
+
raise ValueError("source closure cannot repeat a logical path")
|
|
176
|
+
if type(self.role_paths) is not tuple or not self.role_paths:
|
|
177
|
+
raise TypeError("role_paths must be a non-empty exact tuple")
|
|
178
|
+
if self.role_paths != tuple(sorted(self.role_paths, key=lambda value: value[0])):
|
|
179
|
+
raise ValueError("source roles must be canonically ordered")
|
|
180
|
+
observed_roles: set[str] = set()
|
|
181
|
+
covered: set[str] = set()
|
|
182
|
+
for item in self.role_paths:
|
|
183
|
+
if type(item) is not tuple or len(item) != 2:
|
|
184
|
+
raise TypeError("each source role must be an exact pair")
|
|
185
|
+
role, paths = item
|
|
186
|
+
_validate_token(role, name="source role")
|
|
187
|
+
if role in observed_roles:
|
|
188
|
+
raise ValueError("source roles cannot repeat")
|
|
189
|
+
observed_roles.add(role)
|
|
190
|
+
if (
|
|
191
|
+
type(paths) is not tuple
|
|
192
|
+
or not paths
|
|
193
|
+
or paths != tuple(sorted(set(paths)))
|
|
194
|
+
or any(path not in logical_paths for path in paths)
|
|
195
|
+
):
|
|
196
|
+
raise ValueError("source role paths must be non-empty and canonical")
|
|
197
|
+
covered.update(paths)
|
|
198
|
+
if covered != set(logical_paths):
|
|
199
|
+
raise ValueError("every source file must belong to at least one role")
|
|
200
|
+
object.__setattr__(
|
|
201
|
+
self,
|
|
202
|
+
"source_sha256",
|
|
203
|
+
_hash(_SOURCE_DOMAIN, self._identity_record()),
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
def _identity_record(self) -> dict[str, object]:
|
|
207
|
+
return {
|
|
208
|
+
"schema_version": 1,
|
|
209
|
+
"files": [value.to_record() for value in self.files],
|
|
210
|
+
"roles": {
|
|
211
|
+
role: list(paths) for role, paths in self.role_paths
|
|
212
|
+
},
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
def to_record(self) -> dict[str, object]:
|
|
216
|
+
self.__post_init__()
|
|
217
|
+
return {**self._identity_record(), "source_sha256": self.source_sha256}
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def capture_runtime_source_closure(
|
|
221
|
+
files_by_role: Mapping[str, Mapping[str, Path]],
|
|
222
|
+
) -> RuntimeSourceClosure:
|
|
223
|
+
"""Capture a deduplicated closure from benchmark-owned semantic roles."""
|
|
224
|
+
|
|
225
|
+
if not isinstance(files_by_role, Mapping) or not files_by_role:
|
|
226
|
+
raise TypeError("files_by_role must be a non-empty mapping")
|
|
227
|
+
bindings: dict[str, RuntimeFileBinding] = {}
|
|
228
|
+
roles: list[tuple[str, tuple[str, ...]]] = []
|
|
229
|
+
for role in sorted(files_by_role):
|
|
230
|
+
_validate_token(role, name="source role")
|
|
231
|
+
sources = files_by_role[role]
|
|
232
|
+
if not isinstance(sources, Mapping) or not sources:
|
|
233
|
+
raise ValueError(f"source role {role} must contain at least one file")
|
|
234
|
+
paths: list[str] = []
|
|
235
|
+
for logical_path in sorted(sources):
|
|
236
|
+
captured = capture_runtime_file(
|
|
237
|
+
Path(sources[logical_path]),
|
|
238
|
+
logical_path=logical_path,
|
|
239
|
+
)
|
|
240
|
+
prior = bindings.get(logical_path)
|
|
241
|
+
if prior is not None and prior != captured:
|
|
242
|
+
raise ValueError(f"logical source path {logical_path} is ambiguous")
|
|
243
|
+
bindings[logical_path] = captured
|
|
244
|
+
paths.append(logical_path)
|
|
245
|
+
roles.append((role, tuple(paths)))
|
|
246
|
+
return RuntimeSourceClosure(
|
|
247
|
+
files=tuple(bindings[key] for key in sorted(bindings)),
|
|
248
|
+
role_paths=tuple(roles),
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
@dataclass(frozen=True, slots=True)
|
|
253
|
+
class RuntimeManifestSection:
|
|
254
|
+
"""One immutable benchmark- or infrastructure-owned manifest section."""
|
|
255
|
+
|
|
256
|
+
section_id: str
|
|
257
|
+
payload: FrozenJsonObject
|
|
258
|
+
section_sha256: str = field(init=False)
|
|
259
|
+
|
|
260
|
+
def __post_init__(self) -> None:
|
|
261
|
+
_validate_token(self.section_id, name="section_id")
|
|
262
|
+
if type(self.payload) is not FrozenJsonObject:
|
|
263
|
+
raise TypeError("section payload must be an exact FrozenJsonObject")
|
|
264
|
+
self.payload.__post_init__()
|
|
265
|
+
object.__setattr__(
|
|
266
|
+
self,
|
|
267
|
+
"section_sha256",
|
|
268
|
+
_hash(
|
|
269
|
+
_SECTION_DOMAIN,
|
|
270
|
+
{
|
|
271
|
+
"section_id": self.section_id,
|
|
272
|
+
"payload": thaw_json(self.payload),
|
|
273
|
+
},
|
|
274
|
+
),
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
@classmethod
|
|
278
|
+
def seal(
|
|
279
|
+
cls,
|
|
280
|
+
section_id: str,
|
|
281
|
+
payload: Mapping[str, object],
|
|
282
|
+
) -> "RuntimeManifestSection":
|
|
283
|
+
if not isinstance(payload, Mapping):
|
|
284
|
+
raise TypeError("section payload must be a mapping")
|
|
285
|
+
frozen = freeze_json(dict(payload))
|
|
286
|
+
if type(frozen) is not FrozenJsonObject:
|
|
287
|
+
raise TypeError("section payload did not freeze as an object")
|
|
288
|
+
return cls(section_id=section_id, payload=frozen)
|
|
289
|
+
|
|
290
|
+
def to_record(self) -> dict[str, object]:
|
|
291
|
+
self.__post_init__()
|
|
292
|
+
return {
|
|
293
|
+
"section_id": self.section_id,
|
|
294
|
+
"payload": thaw_json(self.payload),
|
|
295
|
+
"section_sha256": self.section_sha256,
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def _run_git(root: Path, *args: str) -> bytes:
|
|
300
|
+
try:
|
|
301
|
+
completed = subprocess.run(
|
|
302
|
+
("git", *args),
|
|
303
|
+
cwd=root,
|
|
304
|
+
check=True,
|
|
305
|
+
capture_output=True,
|
|
306
|
+
)
|
|
307
|
+
except (OSError, subprocess.CalledProcessError) as exc:
|
|
308
|
+
raise LiveRuntimeManifestError(
|
|
309
|
+
f"git provenance probe failed: {' '.join(args)}"
|
|
310
|
+
) from exc
|
|
311
|
+
return completed.stdout
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def capture_git_worktree_section(
|
|
315
|
+
repo_root: Path,
|
|
316
|
+
*,
|
|
317
|
+
source_closure: RuntimeSourceClosure,
|
|
318
|
+
) -> RuntimeManifestSection:
|
|
319
|
+
"""Bind HEAD and dirty state while retaining only content-blind digests."""
|
|
320
|
+
|
|
321
|
+
source_closure.__post_init__()
|
|
322
|
+
root = repo_root.expanduser().resolve(strict=True)
|
|
323
|
+
observed_root = Path(
|
|
324
|
+
_run_git(root, "rev-parse", "--show-toplevel").decode("utf-8").strip()
|
|
325
|
+
).resolve(strict=True)
|
|
326
|
+
if observed_root != root:
|
|
327
|
+
raise LiveRuntimeManifestError("repo_root is not the git worktree root")
|
|
328
|
+
head = _run_git(root, "rev-parse", "HEAD").decode("ascii").strip()
|
|
329
|
+
head_tree = _run_git(root, "rev-parse", "HEAD^{tree}").decode("ascii").strip()
|
|
330
|
+
if _SHA256.fullmatch(head) is None and re.fullmatch(r"[0-9a-f]{40}", head) is None:
|
|
331
|
+
raise LiveRuntimeManifestError("git HEAD is not a supported object identity")
|
|
332
|
+
if _SHA256.fullmatch(head_tree) is None and re.fullmatch(r"[0-9a-f]{40}", head_tree) is None:
|
|
333
|
+
raise LiveRuntimeManifestError("git HEAD tree is not a supported identity")
|
|
334
|
+
try:
|
|
335
|
+
branch_probe = subprocess.run(
|
|
336
|
+
("git", "symbolic-ref", "--quiet", "--short", "HEAD"),
|
|
337
|
+
cwd=root,
|
|
338
|
+
check=False,
|
|
339
|
+
capture_output=True,
|
|
340
|
+
)
|
|
341
|
+
except OSError as exc:
|
|
342
|
+
raise LiveRuntimeManifestError("git branch provenance probe failed") from exc
|
|
343
|
+
if branch_probe.returncode not in (0, 1):
|
|
344
|
+
raise LiveRuntimeManifestError("git branch provenance probe failed")
|
|
345
|
+
branch = (
|
|
346
|
+
branch_probe.stdout.decode("utf-8").strip()
|
|
347
|
+
if branch_probe.returncode == 0
|
|
348
|
+
else None
|
|
349
|
+
)
|
|
350
|
+
# Restrict every dirty-state probe to the bound closure. A live run writes
|
|
351
|
+
# journals and evaluator receipts after the prospective manifest is built;
|
|
352
|
+
# hashing full-worktree state would therefore make the gate invalidate
|
|
353
|
+
# itself even though no executable input changed.
|
|
354
|
+
repo_paths = tuple(
|
|
355
|
+
sorted(
|
|
356
|
+
{
|
|
357
|
+
Path(binding.resolved_path).relative_to(root).as_posix()
|
|
358
|
+
for binding in source_closure.files
|
|
359
|
+
if Path(binding.resolved_path).is_relative_to(root)
|
|
360
|
+
}
|
|
361
|
+
)
|
|
362
|
+
)
|
|
363
|
+
if repo_paths:
|
|
364
|
+
pathspec = ("--", *repo_paths)
|
|
365
|
+
status = _run_git(
|
|
366
|
+
root,
|
|
367
|
+
"status",
|
|
368
|
+
"--porcelain=v2",
|
|
369
|
+
"-z",
|
|
370
|
+
"--untracked-files=all",
|
|
371
|
+
*pathspec,
|
|
372
|
+
)
|
|
373
|
+
staged = _run_git(
|
|
374
|
+
root,
|
|
375
|
+
"diff",
|
|
376
|
+
"--cached",
|
|
377
|
+
"--binary",
|
|
378
|
+
"--no-ext-diff",
|
|
379
|
+
*pathspec,
|
|
380
|
+
)
|
|
381
|
+
unstaged = _run_git(
|
|
382
|
+
root,
|
|
383
|
+
"diff",
|
|
384
|
+
"--binary",
|
|
385
|
+
"--no-ext-diff",
|
|
386
|
+
*pathspec,
|
|
387
|
+
)
|
|
388
|
+
tracked = set(
|
|
389
|
+
item.decode("utf-8")
|
|
390
|
+
for item in _run_git(
|
|
391
|
+
root,
|
|
392
|
+
"ls-files",
|
|
393
|
+
"-z",
|
|
394
|
+
*pathspec,
|
|
395
|
+
).split(b"\x00")
|
|
396
|
+
if item
|
|
397
|
+
)
|
|
398
|
+
untracked = set(
|
|
399
|
+
item.decode("utf-8")
|
|
400
|
+
for item in _run_git(
|
|
401
|
+
root,
|
|
402
|
+
"ls-files",
|
|
403
|
+
"--others",
|
|
404
|
+
"--exclude-standard",
|
|
405
|
+
"-z",
|
|
406
|
+
*pathspec,
|
|
407
|
+
).split(b"\x00")
|
|
408
|
+
if item
|
|
409
|
+
)
|
|
410
|
+
else:
|
|
411
|
+
status = staged = unstaged = b""
|
|
412
|
+
tracked: set[str] = set()
|
|
413
|
+
untracked: set[str] = set()
|
|
414
|
+
relevant_states: list[dict[str, str]] = []
|
|
415
|
+
for binding in source_closure.files:
|
|
416
|
+
path = Path(binding.resolved_path)
|
|
417
|
+
if not path.is_relative_to(root):
|
|
418
|
+
state = "external"
|
|
419
|
+
else:
|
|
420
|
+
relative = path.relative_to(root).as_posix()
|
|
421
|
+
if relative in tracked:
|
|
422
|
+
state = "tracked"
|
|
423
|
+
elif relative in untracked:
|
|
424
|
+
state = "untracked"
|
|
425
|
+
else:
|
|
426
|
+
state = "ignored_or_unindexed"
|
|
427
|
+
relevant_states.append(
|
|
428
|
+
{"logical_path": binding.logical_path, "git_state": state}
|
|
429
|
+
)
|
|
430
|
+
return RuntimeManifestSection.seal(
|
|
431
|
+
"git_worktree",
|
|
432
|
+
{
|
|
433
|
+
"schema_version": 1,
|
|
434
|
+
"repo_root": str(root),
|
|
435
|
+
"head_commit": head,
|
|
436
|
+
"head_tree": head_tree,
|
|
437
|
+
"branch": branch,
|
|
438
|
+
"head_mode": "attached" if branch is not None else "detached",
|
|
439
|
+
"dirty": bool(status),
|
|
440
|
+
"dirty_scope": "runtime_source_closure_repo_files_only",
|
|
441
|
+
"repo_relative_source_file_count": len(repo_paths),
|
|
442
|
+
"porcelain_v2_bytes": len(status),
|
|
443
|
+
"porcelain_v2_sha256": _sha256_bytes(status),
|
|
444
|
+
"staged_binary_diff_bytes": len(staged),
|
|
445
|
+
"staged_binary_diff_sha256": _sha256_bytes(staged),
|
|
446
|
+
"unstaged_binary_diff_bytes": len(unstaged),
|
|
447
|
+
"unstaged_binary_diff_sha256": _sha256_bytes(unstaged),
|
|
448
|
+
"relevant_source_manifest_sha256": source_closure.source_sha256,
|
|
449
|
+
"relevant_source_git_states": relevant_states,
|
|
450
|
+
"content_disclosure": "hashes_only_no_patch_or_source_text",
|
|
451
|
+
},
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
def capture_runtime_environment_section(
|
|
456
|
+
*,
|
|
457
|
+
distribution_names: Sequence[str],
|
|
458
|
+
dependency_locks: Sequence[RuntimeFileBinding],
|
|
459
|
+
) -> RuntimeManifestSection:
|
|
460
|
+
"""Bind the interpreter, host ABI, installed transports, and lock bytes."""
|
|
461
|
+
|
|
462
|
+
if (
|
|
463
|
+
not isinstance(distribution_names, Sequence)
|
|
464
|
+
or isinstance(distribution_names, (str, bytes))
|
|
465
|
+
or not distribution_names
|
|
466
|
+
):
|
|
467
|
+
raise TypeError("distribution_names must be a non-empty sequence")
|
|
468
|
+
names = tuple(distribution_names)
|
|
469
|
+
if (
|
|
470
|
+
any(type(value) is not str or not value for value in names)
|
|
471
|
+
or names != tuple(sorted(set(names)))
|
|
472
|
+
):
|
|
473
|
+
raise ValueError("distribution_names must be unique and ordered")
|
|
474
|
+
locks = tuple(dependency_locks)
|
|
475
|
+
if not locks or any(type(value) is not RuntimeFileBinding for value in locks):
|
|
476
|
+
raise TypeError("dependency_locks must contain exact file bindings")
|
|
477
|
+
for value in locks:
|
|
478
|
+
value.__post_init__()
|
|
479
|
+
packages: dict[str, str] = {}
|
|
480
|
+
for name in names:
|
|
481
|
+
try:
|
|
482
|
+
packages[name] = importlib.metadata.version(name)
|
|
483
|
+
except importlib.metadata.PackageNotFoundError as exc:
|
|
484
|
+
raise LiveRuntimeManifestError(
|
|
485
|
+
f"required runtime distribution is unavailable: {name}"
|
|
486
|
+
) from exc
|
|
487
|
+
executable = Path(os.path.abspath(sys.executable))
|
|
488
|
+
if not executable.is_file():
|
|
489
|
+
raise LiveRuntimeManifestError("invocation Python executable is unavailable")
|
|
490
|
+
return RuntimeManifestSection.seal(
|
|
491
|
+
"runtime_environment",
|
|
492
|
+
{
|
|
493
|
+
"schema_version": 1,
|
|
494
|
+
"python_executable": str(executable),
|
|
495
|
+
"python_executable_resolved": str(executable.resolve(strict=True)),
|
|
496
|
+
"python_prefix": os.path.abspath(sys.prefix),
|
|
497
|
+
"python_base_prefix": os.path.abspath(sys.base_prefix),
|
|
498
|
+
"python_version": platform.python_version(),
|
|
499
|
+
"python_implementation": platform.python_implementation(),
|
|
500
|
+
"python_compiler": platform.python_compiler(),
|
|
501
|
+
"platform": platform.platform(),
|
|
502
|
+
"system": platform.system(),
|
|
503
|
+
"release": platform.release(),
|
|
504
|
+
"machine": platform.machine(),
|
|
505
|
+
"installed_distributions": packages,
|
|
506
|
+
"dependency_locks": [value.to_record() for value in locks],
|
|
507
|
+
},
|
|
508
|
+
)
|
|
509
|
+
|
|
510
|
+
|
|
511
|
+
@dataclass(frozen=True, slots=True)
|
|
512
|
+
class LiveRuntimeManifest:
|
|
513
|
+
"""Prospective full-stack commitment produced before credentials or work."""
|
|
514
|
+
|
|
515
|
+
manifest_id: str
|
|
516
|
+
manifest_version: int
|
|
517
|
+
built_at_utc: str
|
|
518
|
+
source_closure: RuntimeSourceClosure
|
|
519
|
+
sections: tuple[RuntimeManifestSection, ...]
|
|
520
|
+
required_section_ids: tuple[str, ...]
|
|
521
|
+
manifest_sha256: str = field(init=False)
|
|
522
|
+
|
|
523
|
+
def __post_init__(self) -> None:
|
|
524
|
+
_validate_token(self.manifest_id, name="manifest_id")
|
|
525
|
+
if type(self.manifest_version) is not int or self.manifest_version <= 0:
|
|
526
|
+
raise ValueError("manifest_version must be a positive exact integer")
|
|
527
|
+
if type(self.built_at_utc) is not str or _UTC_SECONDS.fullmatch(
|
|
528
|
+
self.built_at_utc
|
|
529
|
+
) is None:
|
|
530
|
+
raise ValueError("built_at_utc must be UTC RFC3339 at whole seconds")
|
|
531
|
+
try:
|
|
532
|
+
datetime.strptime(self.built_at_utc, "%Y-%m-%dT%H:%M:%SZ")
|
|
533
|
+
except ValueError as exc:
|
|
534
|
+
raise ValueError("built_at_utc is not a real UTC instant") from exc
|
|
535
|
+
self.source_closure.__post_init__()
|
|
536
|
+
if (
|
|
537
|
+
type(self.sections) is not tuple
|
|
538
|
+
or not self.sections
|
|
539
|
+
or any(type(value) is not RuntimeManifestSection for value in self.sections)
|
|
540
|
+
):
|
|
541
|
+
raise TypeError("sections must be a non-empty exact tuple")
|
|
542
|
+
for value in self.sections:
|
|
543
|
+
value.__post_init__()
|
|
544
|
+
if self.sections != tuple(sorted(self.sections, key=lambda value: value.section_id)):
|
|
545
|
+
raise ValueError("manifest sections must be canonically ordered")
|
|
546
|
+
ids = tuple(value.section_id for value in self.sections)
|
|
547
|
+
if len(set(ids)) != len(ids):
|
|
548
|
+
raise ValueError("manifest section IDs cannot repeat")
|
|
549
|
+
if (
|
|
550
|
+
type(self.required_section_ids) is not tuple
|
|
551
|
+
or not self.required_section_ids
|
|
552
|
+
or self.required_section_ids != tuple(sorted(set(self.required_section_ids)))
|
|
553
|
+
):
|
|
554
|
+
raise ValueError("required_section_ids must be unique and ordered")
|
|
555
|
+
for value in self.required_section_ids:
|
|
556
|
+
_validate_token(value, name="required section ID")
|
|
557
|
+
if not set(self.required_section_ids).issubset(ids):
|
|
558
|
+
raise ValueError("one or more required manifest sections are missing")
|
|
559
|
+
object.__setattr__(
|
|
560
|
+
self,
|
|
561
|
+
"manifest_sha256",
|
|
562
|
+
_hash(_MANIFEST_DOMAIN, self._identity_record()),
|
|
563
|
+
)
|
|
564
|
+
|
|
565
|
+
def _identity_record(self) -> dict[str, object]:
|
|
566
|
+
return {
|
|
567
|
+
"schema_version": 1,
|
|
568
|
+
"manifest_id": self.manifest_id,
|
|
569
|
+
"manifest_version": self.manifest_version,
|
|
570
|
+
"built_at_utc": self.built_at_utc,
|
|
571
|
+
"claim_boundary": {
|
|
572
|
+
"credentials_read": False,
|
|
573
|
+
"provider_called": False,
|
|
574
|
+
"physical_evaluator_called": False,
|
|
575
|
+
"current_run_outcomes_observed": False,
|
|
576
|
+
"meaning": "prospective provider-free runtime commitment only",
|
|
577
|
+
},
|
|
578
|
+
"source_closure": self.source_closure.to_record(),
|
|
579
|
+
"required_section_ids": list(self.required_section_ids),
|
|
580
|
+
"sections": [value.to_record() for value in self.sections],
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
def to_record(self) -> dict[str, object]:
|
|
584
|
+
self.__post_init__()
|
|
585
|
+
return {**self._identity_record(), "manifest_sha256": self.manifest_sha256}
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
def build_live_runtime_manifest(
|
|
589
|
+
*,
|
|
590
|
+
manifest_id: str,
|
|
591
|
+
manifest_version: int,
|
|
592
|
+
built_at_utc: str,
|
|
593
|
+
source_closure: RuntimeSourceClosure,
|
|
594
|
+
sections: Sequence[RuntimeManifestSection],
|
|
595
|
+
required_section_ids: Sequence[str],
|
|
596
|
+
) -> LiveRuntimeManifest:
|
|
597
|
+
"""Canonicalize injected sections into one self-authenticating manifest."""
|
|
598
|
+
|
|
599
|
+
return LiveRuntimeManifest(
|
|
600
|
+
manifest_id=manifest_id,
|
|
601
|
+
manifest_version=manifest_version,
|
|
602
|
+
built_at_utc=built_at_utc,
|
|
603
|
+
source_closure=source_closure,
|
|
604
|
+
sections=tuple(sorted(sections, key=lambda value: value.section_id)),
|
|
605
|
+
required_section_ids=tuple(sorted(required_section_ids)),
|
|
606
|
+
)
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
def verify_runtime_source_closure(source: RuntimeSourceClosure) -> None:
|
|
610
|
+
"""Fail closed if any currently installed source byte differs."""
|
|
611
|
+
|
|
612
|
+
source.__post_init__()
|
|
613
|
+
observed = tuple(
|
|
614
|
+
capture_runtime_file(
|
|
615
|
+
Path(value.resolved_path),
|
|
616
|
+
logical_path=value.logical_path,
|
|
617
|
+
)
|
|
618
|
+
for value in source.files
|
|
619
|
+
)
|
|
620
|
+
if observed != source.files:
|
|
621
|
+
raise LiveRuntimeManifestError("live runtime source closure drifted")
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
def runtime_file_binding_from_record(value: Mapping[str, object]) -> RuntimeFileBinding:
|
|
625
|
+
"""Reconstruct and authenticate one serialized file binding."""
|
|
626
|
+
|
|
627
|
+
try:
|
|
628
|
+
binding = RuntimeFileBinding(
|
|
629
|
+
logical_path=str(value["logical_path"]),
|
|
630
|
+
resolved_path=str(value["resolved_path"]),
|
|
631
|
+
size_bytes=int(value["size_bytes"]),
|
|
632
|
+
sha256=str(value["sha256"]),
|
|
633
|
+
)
|
|
634
|
+
except (KeyError, TypeError, ValueError) as exc:
|
|
635
|
+
raise LiveRuntimeManifestError("runtime file binding is malformed") from exc
|
|
636
|
+
if not _exact_json_equal(dict(value), binding.to_record()):
|
|
637
|
+
raise LiveRuntimeManifestError("runtime file binding identity changed")
|
|
638
|
+
return binding
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
def runtime_source_closure_from_record(
|
|
642
|
+
value: Mapping[str, object],
|
|
643
|
+
) -> RuntimeSourceClosure:
|
|
644
|
+
"""Reconstruct and authenticate a serialized role-indexed source closure."""
|
|
645
|
+
|
|
646
|
+
try:
|
|
647
|
+
raw_files = value["files"]
|
|
648
|
+
raw_roles = value["roles"]
|
|
649
|
+
if type(raw_files) is not list or type(raw_roles) is not dict:
|
|
650
|
+
raise TypeError("source closure files/roles have wrong types")
|
|
651
|
+
files = tuple(
|
|
652
|
+
runtime_file_binding_from_record(item)
|
|
653
|
+
for item in raw_files
|
|
654
|
+
if type(item) is dict
|
|
655
|
+
)
|
|
656
|
+
if len(files) != len(raw_files):
|
|
657
|
+
raise TypeError("one source file binding is not an object")
|
|
658
|
+
role_paths = tuple(
|
|
659
|
+
(role, tuple(paths))
|
|
660
|
+
for role, paths in sorted(raw_roles.items())
|
|
661
|
+
if type(role) is str and type(paths) is list
|
|
662
|
+
)
|
|
663
|
+
if len(role_paths) != len(raw_roles):
|
|
664
|
+
raise TypeError("one source role is malformed")
|
|
665
|
+
closure = RuntimeSourceClosure(files=files, role_paths=role_paths)
|
|
666
|
+
except (KeyError, TypeError, ValueError) as exc:
|
|
667
|
+
raise LiveRuntimeManifestError("runtime source closure is malformed") from exc
|
|
668
|
+
if not _exact_json_equal(dict(value), closure.to_record()):
|
|
669
|
+
raise LiveRuntimeManifestError("runtime source closure identity changed")
|
|
670
|
+
return closure
|
|
671
|
+
|
|
672
|
+
|
|
673
|
+
def runtime_manifest_section_from_record(
|
|
674
|
+
value: Mapping[str, object],
|
|
675
|
+
) -> RuntimeManifestSection:
|
|
676
|
+
"""Reconstruct and authenticate one serialized manifest section."""
|
|
677
|
+
|
|
678
|
+
try:
|
|
679
|
+
payload = value["payload"]
|
|
680
|
+
if type(payload) is not dict:
|
|
681
|
+
raise TypeError("section payload must be an object")
|
|
682
|
+
section = RuntimeManifestSection.seal(str(value["section_id"]), payload)
|
|
683
|
+
except (KeyError, TypeError, ValueError) as exc:
|
|
684
|
+
raise LiveRuntimeManifestError("runtime manifest section is malformed") from exc
|
|
685
|
+
if not _exact_json_equal(dict(value), section.to_record()):
|
|
686
|
+
raise LiveRuntimeManifestError("runtime manifest section identity changed")
|
|
687
|
+
return section
|
|
688
|
+
|
|
689
|
+
|
|
690
|
+
def live_runtime_manifest_from_record(
|
|
691
|
+
value: Mapping[str, object],
|
|
692
|
+
) -> LiveRuntimeManifest:
|
|
693
|
+
"""Reconstruct a complete manifest and reject any forged self-hash."""
|
|
694
|
+
|
|
695
|
+
try:
|
|
696
|
+
raw_source = value["source_closure"]
|
|
697
|
+
raw_sections = value["sections"]
|
|
698
|
+
raw_required = value["required_section_ids"]
|
|
699
|
+
if (
|
|
700
|
+
type(raw_source) is not dict
|
|
701
|
+
or type(raw_sections) is not list
|
|
702
|
+
or type(raw_required) is not list
|
|
703
|
+
):
|
|
704
|
+
raise TypeError("manifest containers have wrong types")
|
|
705
|
+
source = runtime_source_closure_from_record(raw_source)
|
|
706
|
+
sections = tuple(
|
|
707
|
+
runtime_manifest_section_from_record(item)
|
|
708
|
+
for item in raw_sections
|
|
709
|
+
if type(item) is dict
|
|
710
|
+
)
|
|
711
|
+
if len(sections) != len(raw_sections):
|
|
712
|
+
raise TypeError("one manifest section is not an object")
|
|
713
|
+
manifest = LiveRuntimeManifest(
|
|
714
|
+
manifest_id=str(value["manifest_id"]),
|
|
715
|
+
manifest_version=int(value["manifest_version"]),
|
|
716
|
+
built_at_utc=str(value["built_at_utc"]),
|
|
717
|
+
source_closure=source,
|
|
718
|
+
sections=sections,
|
|
719
|
+
required_section_ids=tuple(str(item) for item in raw_required),
|
|
720
|
+
)
|
|
721
|
+
except (KeyError, TypeError, ValueError) as exc:
|
|
722
|
+
raise LiveRuntimeManifestError("live runtime manifest is malformed") from exc
|
|
723
|
+
if not _exact_json_equal(dict(value), manifest.to_record()):
|
|
724
|
+
raise LiveRuntimeManifestError("live runtime manifest identity changed")
|
|
725
|
+
return manifest
|
|
726
|
+
|
|
727
|
+
|
|
728
|
+
def load_live_runtime_manifest(path: Path) -> LiveRuntimeManifest:
|
|
729
|
+
"""Load strict JSON and authenticate every nested manifest commitment."""
|
|
730
|
+
|
|
731
|
+
resolved = path.expanduser().resolve(strict=True)
|
|
732
|
+
try:
|
|
733
|
+
value = decode_json_bytes(resolved.read_bytes())
|
|
734
|
+
except Exception as exc:
|
|
735
|
+
raise LiveRuntimeManifestError("live runtime manifest is unreadable") from exc
|
|
736
|
+
if type(value) is not dict:
|
|
737
|
+
raise LiveRuntimeManifestError("live runtime manifest root is not an object")
|
|
738
|
+
return live_runtime_manifest_from_record(value)
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
__all__ = [
|
|
742
|
+
"LiveRuntimeManifest",
|
|
743
|
+
"LiveRuntimeManifestError",
|
|
744
|
+
"RuntimeFileBinding",
|
|
745
|
+
"RuntimeManifestSection",
|
|
746
|
+
"RuntimeSourceClosure",
|
|
747
|
+
"build_live_runtime_manifest",
|
|
748
|
+
"capture_git_worktree_section",
|
|
749
|
+
"capture_runtime_environment_section",
|
|
750
|
+
"capture_runtime_file",
|
|
751
|
+
"capture_runtime_source_closure",
|
|
752
|
+
"live_runtime_manifest_from_record",
|
|
753
|
+
"load_live_runtime_manifest",
|
|
754
|
+
"runtime_file_binding_from_record",
|
|
755
|
+
"runtime_manifest_section_from_record",
|
|
756
|
+
"runtime_source_closure_from_record",
|
|
757
|
+
"verify_runtime_source_closure",
|
|
758
|
+
]
|