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,1523 @@
|
|
|
1
|
+
"""Benchmark-neutral terminal joins for physical provider-attempt evidence.
|
|
2
|
+
|
|
3
|
+
An outbound manifest proves that a request reached the HTTPX pre-transport
|
|
4
|
+
boundary. Queue outcomes and stream progress prove how that physical attempt
|
|
5
|
+
terminated. This module joins those independently durable channels without
|
|
6
|
+
retaining prompts, schemas, response bodies, or stream content.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import hashlib
|
|
12
|
+
import json
|
|
13
|
+
import re
|
|
14
|
+
from collections import Counter
|
|
15
|
+
from collections import defaultdict
|
|
16
|
+
from collections.abc import Mapping, Sequence
|
|
17
|
+
from decimal import Decimal, InvalidOperation
|
|
18
|
+
|
|
19
|
+
from agent_evolve.domain.ids import LLMCallId, ProviderAttemptId
|
|
20
|
+
from agent_evolve.domain.llm_task_queue import (
|
|
21
|
+
AttemptRequestEvidence,
|
|
22
|
+
AttemptRequestVariant,
|
|
23
|
+
AttemptStatus,
|
|
24
|
+
AttemptTelemetry,
|
|
25
|
+
CancellationReason,
|
|
26
|
+
CanonicalProviderErrorCode,
|
|
27
|
+
ExceptionOriginFamily,
|
|
28
|
+
ExceptionProvenanceLink,
|
|
29
|
+
LLMTaskOutcome,
|
|
30
|
+
RetryAfter,
|
|
31
|
+
RetryAfterSource,
|
|
32
|
+
RetryClassification,
|
|
33
|
+
RetryDisposition,
|
|
34
|
+
RetryReason,
|
|
35
|
+
SanitizedAttemptFailure,
|
|
36
|
+
SanitizedExceptionProvenance,
|
|
37
|
+
SanitizedExceptionProvenanceNode,
|
|
38
|
+
SanitizedValidationIssue,
|
|
39
|
+
StreamTimeoutPhase,
|
|
40
|
+
StructuredOutputFailureMode,
|
|
41
|
+
TaskOutcomeStatus,
|
|
42
|
+
TaskTelemetry,
|
|
43
|
+
ValidationIssueCategory,
|
|
44
|
+
ValidationIssueReasonCode,
|
|
45
|
+
)
|
|
46
|
+
from agent_evolve.integrations.pydantic_ai.outbound_request_manifest import (
|
|
47
|
+
validate_openrouter_outbound_request_manifest_record,
|
|
48
|
+
)
|
|
49
|
+
from agent_evolve.integrations.pydantic_ai.queued_runner import (
|
|
50
|
+
SUPPORTED_STRUCTURED_GENERATION_OUTCOME_SCHEMA_VERSIONS,
|
|
51
|
+
validate_structured_generation_request_evidence_record,
|
|
52
|
+
)
|
|
53
|
+
from agent_evolve.ports.structured_generator import (
|
|
54
|
+
StructuredStreamChannel,
|
|
55
|
+
StructuredStreamProgress,
|
|
56
|
+
StructuredStreamProgressKind,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
PROVIDER_ATTEMPT_TERMINAL_JOIN_SCHEMA_VERSION = 1
|
|
61
|
+
PROVIDER_ATTEMPT_TERMINAL_JOIN_CONTRACT_ID = (
|
|
62
|
+
"provider_attempt_outbound_outcome_progress_join_v1"
|
|
63
|
+
)
|
|
64
|
+
PRE_TRANSPORT_FAILURE_EVIDENCE_SCHEMA_VERSION = 1
|
|
65
|
+
|
|
66
|
+
_SHA256 = re.compile(r"^[0-9a-f]{64}$")
|
|
67
|
+
_FAILURE_STAGE = re.compile(r"^[a-z][a-z0-9_.-]{0,95}$")
|
|
68
|
+
_JOIN_DOMAIN = b"agent-evolve:provider-attempt-terminal-join:v1\x00"
|
|
69
|
+
_PRE_TRANSPORT_DOMAIN = (
|
|
70
|
+
b"agent-evolve:provider-attempt-explicit-pre-transport-failure:v1\x00"
|
|
71
|
+
)
|
|
72
|
+
_COLLECTION_DOMAIN = b"agent-evolve:provider-attempt-join-collection:v1\x00"
|
|
73
|
+
_ATTEMPT_STATUSES = frozenset(
|
|
74
|
+
{
|
|
75
|
+
"succeeded",
|
|
76
|
+
"retryable_failure",
|
|
77
|
+
"terminal_failure",
|
|
78
|
+
"timed_out",
|
|
79
|
+
"cancelled",
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
_TASK_STATUSES = frozenset(
|
|
83
|
+
{"succeeded", "terminal_failure", "attempts_exhausted", "cancelled"}
|
|
84
|
+
)
|
|
85
|
+
_OUTCOME_RESPONSE_FIELDS = frozenset(
|
|
86
|
+
{
|
|
87
|
+
"requested_model",
|
|
88
|
+
"resolved_model",
|
|
89
|
+
"resolved_provider",
|
|
90
|
+
"provider_response_id",
|
|
91
|
+
"finish_reason",
|
|
92
|
+
"input_tokens",
|
|
93
|
+
"output_tokens",
|
|
94
|
+
"reasoning_tokens",
|
|
95
|
+
"cache_read_tokens",
|
|
96
|
+
"cache_write_tokens",
|
|
97
|
+
"cost_usd",
|
|
98
|
+
"latency_ns",
|
|
99
|
+
}
|
|
100
|
+
)
|
|
101
|
+
_OUTCOME_FIELDS = frozenset(
|
|
102
|
+
{
|
|
103
|
+
"schema_version",
|
|
104
|
+
"task_id",
|
|
105
|
+
"status",
|
|
106
|
+
"cancellation_reason",
|
|
107
|
+
"queue_time_ns",
|
|
108
|
+
"service_time_ns",
|
|
109
|
+
"total_time_ns",
|
|
110
|
+
"attempts",
|
|
111
|
+
"response",
|
|
112
|
+
}
|
|
113
|
+
)
|
|
114
|
+
_OUTCOME_ATTEMPT_FIELDS = frozenset(
|
|
115
|
+
{
|
|
116
|
+
"attempt_number",
|
|
117
|
+
"status",
|
|
118
|
+
"wait_time_ns",
|
|
119
|
+
"service_time_ns",
|
|
120
|
+
"will_retry",
|
|
121
|
+
"policy_backoff_ns",
|
|
122
|
+
"retry_after_ns",
|
|
123
|
+
"scheduled_delay_ns",
|
|
124
|
+
"error_type",
|
|
125
|
+
"request_evidence",
|
|
126
|
+
"classification",
|
|
127
|
+
"failure",
|
|
128
|
+
}
|
|
129
|
+
)
|
|
130
|
+
_ATTEMPT_REQUEST_EVIDENCE_FIELDS = frozenset(
|
|
131
|
+
{"variant", "prompt_sha256", "provider_attempt_id"}
|
|
132
|
+
)
|
|
133
|
+
_ATTEMPT_CLASSIFICATION_FIELDS = frozenset({"disposition", "reason"})
|
|
134
|
+
_ATTEMPT_FAILURE_FIELDS_V5 = frozenset(
|
|
135
|
+
{
|
|
136
|
+
"kind",
|
|
137
|
+
"retryable",
|
|
138
|
+
"safe_message",
|
|
139
|
+
"status_code",
|
|
140
|
+
"retry_after_seconds",
|
|
141
|
+
"stream_timeout_phase",
|
|
142
|
+
"output_failure_mode",
|
|
143
|
+
"validation_issues",
|
|
144
|
+
}
|
|
145
|
+
)
|
|
146
|
+
_ATTEMPT_FAILURE_FIELDS_V6 = _ATTEMPT_FAILURE_FIELDS_V5 | frozenset(
|
|
147
|
+
{"provider_error_code", "provider_error_envelope_sha256"}
|
|
148
|
+
)
|
|
149
|
+
_ATTEMPT_FAILURE_FIELDS_V8 = _ATTEMPT_FAILURE_FIELDS_V6 | frozenset(
|
|
150
|
+
{"exception_provenance"}
|
|
151
|
+
)
|
|
152
|
+
_EXCEPTION_PROVENANCE_FIELDS_V8 = frozenset({"nodes", "truncated"})
|
|
153
|
+
_EXCEPTION_PROVENANCE_NODE_FIELDS_V8 = frozenset(
|
|
154
|
+
{"parent_index", "link", "family", "type_identity_sha256"}
|
|
155
|
+
)
|
|
156
|
+
_VALIDATION_ISSUE_FIELDS_V6 = frozenset({"category", "location"})
|
|
157
|
+
_VALIDATION_ISSUE_FIELDS_V7 = _VALIDATION_ISSUE_FIELDS_V6 | frozenset({"reason_code"})
|
|
158
|
+
_PROGRESS_FIELDS = frozenset(
|
|
159
|
+
{
|
|
160
|
+
"schema_version",
|
|
161
|
+
"call_id",
|
|
162
|
+
"provider_attempt_id",
|
|
163
|
+
"sequence",
|
|
164
|
+
"kind",
|
|
165
|
+
"channel",
|
|
166
|
+
"elapsed_ns",
|
|
167
|
+
"event_content_utf8_bytes",
|
|
168
|
+
"cumulative_content_utf8_bytes",
|
|
169
|
+
"rolling_content_sha256",
|
|
170
|
+
}
|
|
171
|
+
)
|
|
172
|
+
_FRAMEWORK_VERSION_FIELDS = frozenset({"httpx", "openai", "pydantic", "pydantic-ai"})
|
|
173
|
+
_EXPECTED_TRANSPORT_SETTING_FIELDS = frozenset(
|
|
174
|
+
{
|
|
175
|
+
"model",
|
|
176
|
+
"provider",
|
|
177
|
+
"reasoning",
|
|
178
|
+
"usage",
|
|
179
|
+
"stream",
|
|
180
|
+
"stream_options",
|
|
181
|
+
"tool_choice",
|
|
182
|
+
"response_format",
|
|
183
|
+
}
|
|
184
|
+
)
|
|
185
|
+
_SOURCE_FIELDS = frozenset(
|
|
186
|
+
{
|
|
187
|
+
"logical_requests",
|
|
188
|
+
"outbound_manifests",
|
|
189
|
+
"terminal_outcomes",
|
|
190
|
+
"progress_rows",
|
|
191
|
+
"explicit_pre_transport_failures",
|
|
192
|
+
}
|
|
193
|
+
)
|
|
194
|
+
_SOURCE_COUNT_FIELDS = frozenset(
|
|
195
|
+
{*_SOURCE_FIELDS, "outcome_attempts_with_physical_ids"}
|
|
196
|
+
)
|
|
197
|
+
_PROVIDER_ATTEMPT_ID_FIELDS = frozenset(
|
|
198
|
+
{
|
|
199
|
+
"dispatched",
|
|
200
|
+
"terminal_outcomes",
|
|
201
|
+
"progress",
|
|
202
|
+
"provider_status_response_or_progress",
|
|
203
|
+
"explicit_pre_transport_failures",
|
|
204
|
+
}
|
|
205
|
+
)
|
|
206
|
+
_DEFECT_ATTEMPT_ID_FIELDS = frozenset(
|
|
207
|
+
{
|
|
208
|
+
"duplicate_outbound_manifest_attempt_ids",
|
|
209
|
+
"duplicate_outcome_attempt_ids",
|
|
210
|
+
"duplicate_pre_transport_attempt_ids",
|
|
211
|
+
"missing_logical_request_attempt_ids",
|
|
212
|
+
"logical_physical_mismatch_attempt_ids",
|
|
213
|
+
"framework_version_mismatch_attempt_ids",
|
|
214
|
+
"transport_settings_mismatch_attempt_ids",
|
|
215
|
+
"missing_manifest_attempt_ids",
|
|
216
|
+
"orphan_manifest_attempt_ids",
|
|
217
|
+
"progress_without_manifest_attempt_ids",
|
|
218
|
+
"progress_without_outcome_attempt_ids",
|
|
219
|
+
"progress_duplicate_sequence_attempt_ids",
|
|
220
|
+
"progress_noncontiguous_sequence_attempt_ids",
|
|
221
|
+
"provider_evidence_without_manifest_attempt_ids",
|
|
222
|
+
"pre_transport_with_manifest_attempt_ids",
|
|
223
|
+
"pre_transport_with_provider_evidence_attempt_ids",
|
|
224
|
+
"pre_transport_without_outcome_attempt_ids",
|
|
225
|
+
"call_id_mismatch_attempt_ids",
|
|
226
|
+
}
|
|
227
|
+
)
|
|
228
|
+
_DEFECT_CALL_ID_FIELDS = frozenset({"duplicate_logical_request_call_ids"})
|
|
229
|
+
_DEFECT_FIELDS = _DEFECT_ATTEMPT_ID_FIELDS | _DEFECT_CALL_ID_FIELDS
|
|
230
|
+
_INVARIANT_FIELDS = frozenset(
|
|
231
|
+
{
|
|
232
|
+
"logical_request_exactly_once_per_dispatched_attempt",
|
|
233
|
+
"logical_physical_request_fields_exact",
|
|
234
|
+
"framework_versions_join_qualification_exact",
|
|
235
|
+
"transport_settings_join_selected_profile_exact",
|
|
236
|
+
"manifest_exactly_once_per_dispatched_attempt",
|
|
237
|
+
"outcome_attempt_identity_exactly_once",
|
|
238
|
+
"every_physical_outcome_attempt_accounted_for",
|
|
239
|
+
"every_dispatched_attempt_has_terminal_outcome",
|
|
240
|
+
"provider_evidence_always_has_manifest",
|
|
241
|
+
"progress_joins_manifest_and_outcome",
|
|
242
|
+
"progress_sequence_unique_and_contiguous",
|
|
243
|
+
"explicit_pre_transport_evidence_consistent",
|
|
244
|
+
"explicit_pre_transport_is_affirmative_not_inferred",
|
|
245
|
+
"call_id_join_exact",
|
|
246
|
+
"raw_provider_content_persisted",
|
|
247
|
+
}
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def _canonical_bytes(value: object) -> bytes:
|
|
252
|
+
return json.dumps(
|
|
253
|
+
value,
|
|
254
|
+
ensure_ascii=True,
|
|
255
|
+
allow_nan=False,
|
|
256
|
+
separators=(",", ":"),
|
|
257
|
+
sort_keys=True,
|
|
258
|
+
).encode("ascii")
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _domain_sha256(domain: bytes, value: object) -> str:
|
|
262
|
+
return hashlib.sha256(domain + _canonical_bytes(value)).hexdigest()
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def _canonical_mapping(value: object, *, label: str) -> dict[str, object]:
|
|
266
|
+
if not isinstance(value, Mapping):
|
|
267
|
+
raise TypeError(f"{label} must be a mapping")
|
|
268
|
+
try:
|
|
269
|
+
detached = json.loads(_canonical_bytes(dict(value)))
|
|
270
|
+
except (TypeError, ValueError) as exc:
|
|
271
|
+
raise ValueError(f"{label} must contain canonical JSON values") from exc
|
|
272
|
+
if type(detached) is not dict:
|
|
273
|
+
raise ValueError(f"{label} must encode one exact object")
|
|
274
|
+
return detached
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def _require_sha256(value: object, *, label: str) -> str:
|
|
278
|
+
if type(value) is not str or _SHA256.fullmatch(value) is None:
|
|
279
|
+
raise ValueError(f"{label} must be a lowercase SHA-256 digest")
|
|
280
|
+
return value
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def explicit_pre_transport_failure_evidence_record(
|
|
284
|
+
*,
|
|
285
|
+
call_id: str,
|
|
286
|
+
provider_attempt_id: str,
|
|
287
|
+
failure_stage: str,
|
|
288
|
+
) -> dict[str, object]:
|
|
289
|
+
"""Build content-free affirmative evidence that HTTP dispatch never began."""
|
|
290
|
+
|
|
291
|
+
LLMCallId(call_id)
|
|
292
|
+
ProviderAttemptId(provider_attempt_id)
|
|
293
|
+
if (
|
|
294
|
+
type(failure_stage) is not str
|
|
295
|
+
or _FAILURE_STAGE.fullmatch(failure_stage) is None
|
|
296
|
+
):
|
|
297
|
+
raise ValueError("failure_stage is outside the closed token grammar")
|
|
298
|
+
record: dict[str, object] = {
|
|
299
|
+
"schema_version": PRE_TRANSPORT_FAILURE_EVIDENCE_SCHEMA_VERSION,
|
|
300
|
+
"call_id": call_id,
|
|
301
|
+
"provider_attempt_id": provider_attempt_id,
|
|
302
|
+
"failure_stage": failure_stage,
|
|
303
|
+
"http_transport_dispatch_started": False,
|
|
304
|
+
"raw_failure_content_persisted": False,
|
|
305
|
+
}
|
|
306
|
+
record["evidence_sha256"] = _domain_sha256(_PRE_TRANSPORT_DOMAIN, record)
|
|
307
|
+
return record
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def validate_explicit_pre_transport_failure_evidence_record(
|
|
311
|
+
value: Mapping[str, object],
|
|
312
|
+
) -> dict[str, object]:
|
|
313
|
+
record = _canonical_mapping(value, label="pre-transport failure evidence")
|
|
314
|
+
if frozenset(record) != {
|
|
315
|
+
"schema_version",
|
|
316
|
+
"call_id",
|
|
317
|
+
"provider_attempt_id",
|
|
318
|
+
"failure_stage",
|
|
319
|
+
"http_transport_dispatch_started",
|
|
320
|
+
"raw_failure_content_persisted",
|
|
321
|
+
"evidence_sha256",
|
|
322
|
+
}:
|
|
323
|
+
raise ValueError("pre-transport failure evidence has unexpected fields")
|
|
324
|
+
if (
|
|
325
|
+
record["schema_version"] != PRE_TRANSPORT_FAILURE_EVIDENCE_SCHEMA_VERSION
|
|
326
|
+
or record["http_transport_dispatch_started"] is not False
|
|
327
|
+
or record["raw_failure_content_persisted"] is not False
|
|
328
|
+
):
|
|
329
|
+
raise ValueError("pre-transport failure evidence contract drifted")
|
|
330
|
+
LLMCallId(record["call_id"])
|
|
331
|
+
ProviderAttemptId(record["provider_attempt_id"])
|
|
332
|
+
stage = record["failure_stage"]
|
|
333
|
+
if type(stage) is not str or _FAILURE_STAGE.fullmatch(stage) is None:
|
|
334
|
+
raise ValueError("pre-transport failure stage is invalid")
|
|
335
|
+
supplied = _require_sha256(record["evidence_sha256"], label="evidence_sha256")
|
|
336
|
+
authenticated = dict(record)
|
|
337
|
+
del authenticated["evidence_sha256"]
|
|
338
|
+
if supplied != _domain_sha256(_PRE_TRANSPORT_DOMAIN, authenticated):
|
|
339
|
+
raise ValueError("pre-transport failure evidence hash is invalid")
|
|
340
|
+
return record
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def _collection_sha256(rows: Sequence[object]) -> str:
|
|
344
|
+
digest = hashlib.sha256(_COLLECTION_DOMAIN)
|
|
345
|
+
for index, row in enumerate(rows):
|
|
346
|
+
try:
|
|
347
|
+
payload = _canonical_bytes(row)
|
|
348
|
+
except (TypeError, ValueError):
|
|
349
|
+
payload = f"noncanonical-row:{index}".encode("ascii")
|
|
350
|
+
digest.update(index.to_bytes(8, "big"))
|
|
351
|
+
digest.update(len(payload).to_bytes(8, "big"))
|
|
352
|
+
digest.update(payload)
|
|
353
|
+
return digest.hexdigest()
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
def _validate_outcome_response(value: object) -> dict[str, object]:
|
|
357
|
+
if type(value) is not dict or frozenset(value) != _OUTCOME_RESPONSE_FIELDS:
|
|
358
|
+
raise ValueError("provider outcome response has unexpected fields")
|
|
359
|
+
for name in ("requested_model", "resolved_model", "resolved_provider"):
|
|
360
|
+
if type(value[name]) is not str or not value[name].strip():
|
|
361
|
+
raise ValueError(f"provider outcome response {name} is invalid")
|
|
362
|
+
for name in ("provider_response_id", "finish_reason"):
|
|
363
|
+
item = value[name]
|
|
364
|
+
if item is not None and (type(item) is not str or not item.strip()):
|
|
365
|
+
raise ValueError(f"provider outcome response {name} is invalid")
|
|
366
|
+
for name in (
|
|
367
|
+
"input_tokens",
|
|
368
|
+
"output_tokens",
|
|
369
|
+
"reasoning_tokens",
|
|
370
|
+
"cache_read_tokens",
|
|
371
|
+
"cache_write_tokens",
|
|
372
|
+
"latency_ns",
|
|
373
|
+
):
|
|
374
|
+
if type(value[name]) is not int or value[name] < 0:
|
|
375
|
+
raise ValueError(f"provider outcome response {name} is invalid")
|
|
376
|
+
cost = value["cost_usd"]
|
|
377
|
+
if cost is not None:
|
|
378
|
+
if type(cost) is not str:
|
|
379
|
+
raise ValueError("provider outcome response cost_usd is invalid")
|
|
380
|
+
try:
|
|
381
|
+
parsed = Decimal(cost)
|
|
382
|
+
except InvalidOperation as exc:
|
|
383
|
+
raise ValueError("provider outcome response cost_usd is invalid") from exc
|
|
384
|
+
if not parsed.is_finite() or parsed < 0 or str(parsed) != cost:
|
|
385
|
+
raise ValueError("provider outcome response cost_usd is not canonical")
|
|
386
|
+
return value
|
|
387
|
+
|
|
388
|
+
|
|
389
|
+
def _validate_attempt_request_evidence(
|
|
390
|
+
value: object,
|
|
391
|
+
) -> AttemptRequestEvidence | None:
|
|
392
|
+
if value is None:
|
|
393
|
+
return None
|
|
394
|
+
if type(value) is not dict or frozenset(value) != _ATTEMPT_REQUEST_EVIDENCE_FIELDS:
|
|
395
|
+
raise ValueError("provider attempt request evidence has unexpected fields")
|
|
396
|
+
variant = value["variant"]
|
|
397
|
+
prompt_sha256 = value["prompt_sha256"]
|
|
398
|
+
attempt_id = value["provider_attempt_id"]
|
|
399
|
+
if type(variant) is not str or type(prompt_sha256) is not str:
|
|
400
|
+
raise ValueError("provider attempt request evidence is invalid")
|
|
401
|
+
physical_id = None
|
|
402
|
+
if attempt_id is not None:
|
|
403
|
+
if type(attempt_id) is not str:
|
|
404
|
+
raise ValueError("provider attempt physical identity is invalid")
|
|
405
|
+
physical_id = ProviderAttemptId(attempt_id)
|
|
406
|
+
return AttemptRequestEvidence(
|
|
407
|
+
variant=AttemptRequestVariant(variant),
|
|
408
|
+
prompt_sha256=prompt_sha256,
|
|
409
|
+
provider_attempt_id=physical_id,
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def _validate_attempt_failure(
|
|
414
|
+
value: object,
|
|
415
|
+
*,
|
|
416
|
+
schema_version: int,
|
|
417
|
+
) -> SanitizedAttemptFailure | None:
|
|
418
|
+
if value is None:
|
|
419
|
+
return None
|
|
420
|
+
expected_fields = (
|
|
421
|
+
_ATTEMPT_FAILURE_FIELDS_V8
|
|
422
|
+
if schema_version >= 8
|
|
423
|
+
else (
|
|
424
|
+
_ATTEMPT_FAILURE_FIELDS_V6
|
|
425
|
+
if schema_version >= 6
|
|
426
|
+
else _ATTEMPT_FAILURE_FIELDS_V5
|
|
427
|
+
)
|
|
428
|
+
)
|
|
429
|
+
if type(value) is not dict or frozenset(value) != expected_fields:
|
|
430
|
+
raise ValueError("provider attempt failure has unexpected fields")
|
|
431
|
+
|
|
432
|
+
issues_value = value["validation_issues"]
|
|
433
|
+
if type(issues_value) is not list:
|
|
434
|
+
raise ValueError("provider attempt validation issues must be a list")
|
|
435
|
+
issues: list[SanitizedValidationIssue] = []
|
|
436
|
+
for issue in issues_value:
|
|
437
|
+
expected_issue_fields = (
|
|
438
|
+
_VALIDATION_ISSUE_FIELDS_V7
|
|
439
|
+
if schema_version >= 7
|
|
440
|
+
else _VALIDATION_ISSUE_FIELDS_V6
|
|
441
|
+
)
|
|
442
|
+
if type(issue) is not dict or frozenset(issue) != expected_issue_fields:
|
|
443
|
+
raise ValueError("provider attempt validation issue has unexpected fields")
|
|
444
|
+
category = issue["category"]
|
|
445
|
+
location = issue["location"]
|
|
446
|
+
reason_code = issue.get("reason_code")
|
|
447
|
+
if (
|
|
448
|
+
type(category) is not str
|
|
449
|
+
or type(location) is not list
|
|
450
|
+
or (reason_code is not None and type(reason_code) is not str)
|
|
451
|
+
):
|
|
452
|
+
raise ValueError("provider attempt validation issue is invalid")
|
|
453
|
+
issues.append(
|
|
454
|
+
SanitizedValidationIssue(
|
|
455
|
+
category=ValidationIssueCategory(category),
|
|
456
|
+
location=tuple(location),
|
|
457
|
+
reason_code=(
|
|
458
|
+
None
|
|
459
|
+
if reason_code is None
|
|
460
|
+
else ValidationIssueReasonCode(reason_code)
|
|
461
|
+
),
|
|
462
|
+
)
|
|
463
|
+
)
|
|
464
|
+
|
|
465
|
+
output_mode = value["output_failure_mode"]
|
|
466
|
+
timeout_phase = value["stream_timeout_phase"]
|
|
467
|
+
provider_error_code = value["provider_error_code"] if schema_version >= 6 else None
|
|
468
|
+
exception_provenance_value = (
|
|
469
|
+
value["exception_provenance"] if schema_version >= 8 else None
|
|
470
|
+
)
|
|
471
|
+
for name, item in (
|
|
472
|
+
("output_failure_mode", output_mode),
|
|
473
|
+
("stream_timeout_phase", timeout_phase),
|
|
474
|
+
("provider_error_code", provider_error_code),
|
|
475
|
+
):
|
|
476
|
+
if item is not None and type(item) is not str:
|
|
477
|
+
raise ValueError(f"provider attempt failure {name} is invalid")
|
|
478
|
+
exception_provenance: SanitizedExceptionProvenance | None = None
|
|
479
|
+
if exception_provenance_value is not None:
|
|
480
|
+
if (
|
|
481
|
+
type(exception_provenance_value) is not dict
|
|
482
|
+
or frozenset(exception_provenance_value)
|
|
483
|
+
!= _EXCEPTION_PROVENANCE_FIELDS_V8
|
|
484
|
+
or type(exception_provenance_value["nodes"]) is not list
|
|
485
|
+
or type(exception_provenance_value["truncated"]) is not bool
|
|
486
|
+
):
|
|
487
|
+
raise ValueError("provider attempt exception provenance is invalid")
|
|
488
|
+
provenance_nodes: list[SanitizedExceptionProvenanceNode] = []
|
|
489
|
+
for raw_node in exception_provenance_value["nodes"]:
|
|
490
|
+
if (
|
|
491
|
+
type(raw_node) is not dict
|
|
492
|
+
or frozenset(raw_node) != _EXCEPTION_PROVENANCE_NODE_FIELDS_V8
|
|
493
|
+
):
|
|
494
|
+
raise ValueError(
|
|
495
|
+
"provider attempt exception provenance node is invalid"
|
|
496
|
+
)
|
|
497
|
+
parent_index = raw_node["parent_index"]
|
|
498
|
+
link = raw_node["link"]
|
|
499
|
+
family = raw_node["family"]
|
|
500
|
+
fingerprint = raw_node["type_identity_sha256"]
|
|
501
|
+
if (
|
|
502
|
+
(parent_index is not None and type(parent_index) is not int)
|
|
503
|
+
or type(link) is not str
|
|
504
|
+
or type(family) is not str
|
|
505
|
+
or type(fingerprint) is not str
|
|
506
|
+
):
|
|
507
|
+
raise ValueError(
|
|
508
|
+
"provider attempt exception provenance node fields are invalid"
|
|
509
|
+
)
|
|
510
|
+
provenance_nodes.append(
|
|
511
|
+
SanitizedExceptionProvenanceNode(
|
|
512
|
+
parent_index=parent_index,
|
|
513
|
+
link=ExceptionProvenanceLink(link),
|
|
514
|
+
family=ExceptionOriginFamily(family),
|
|
515
|
+
type_identity_sha256=fingerprint,
|
|
516
|
+
)
|
|
517
|
+
)
|
|
518
|
+
exception_provenance = SanitizedExceptionProvenance(
|
|
519
|
+
nodes=tuple(provenance_nodes),
|
|
520
|
+
truncated=exception_provenance_value["truncated"],
|
|
521
|
+
)
|
|
522
|
+
return SanitizedAttemptFailure(
|
|
523
|
+
kind=value["kind"],
|
|
524
|
+
retryable=value["retryable"],
|
|
525
|
+
safe_message=value["safe_message"],
|
|
526
|
+
status_code=value["status_code"],
|
|
527
|
+
retry_after_seconds=value["retry_after_seconds"],
|
|
528
|
+
output_failure_mode=(
|
|
529
|
+
None if output_mode is None else StructuredOutputFailureMode(output_mode)
|
|
530
|
+
),
|
|
531
|
+
validation_issues=tuple(issues),
|
|
532
|
+
stream_timeout_phase=(
|
|
533
|
+
None if timeout_phase is None else StreamTimeoutPhase(timeout_phase)
|
|
534
|
+
),
|
|
535
|
+
provider_error_code=(
|
|
536
|
+
None
|
|
537
|
+
if provider_error_code is None
|
|
538
|
+
else CanonicalProviderErrorCode(provider_error_code)
|
|
539
|
+
),
|
|
540
|
+
provider_error_envelope_sha256=(
|
|
541
|
+
value["provider_error_envelope_sha256"] if schema_version >= 6 else None
|
|
542
|
+
),
|
|
543
|
+
exception_provenance=exception_provenance,
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
def _validate_outcome_attempt(
|
|
548
|
+
value: object,
|
|
549
|
+
*,
|
|
550
|
+
schema_version: int,
|
|
551
|
+
) -> tuple[AttemptTelemetry, str | None, bool]:
|
|
552
|
+
if type(value) is not dict or frozenset(value) != _OUTCOME_ATTEMPT_FIELDS:
|
|
553
|
+
raise ValueError("provider outcome attempt has unexpected fields")
|
|
554
|
+
status_value = value["status"]
|
|
555
|
+
if type(status_value) is not str or status_value not in _ATTEMPT_STATUSES:
|
|
556
|
+
raise ValueError("provider attempt status is invalid")
|
|
557
|
+
evidence = _validate_attempt_request_evidence(value["request_evidence"])
|
|
558
|
+
failure = _validate_attempt_failure(
|
|
559
|
+
value["failure"],
|
|
560
|
+
schema_version=schema_version,
|
|
561
|
+
)
|
|
562
|
+
classification_value = value["classification"]
|
|
563
|
+
if classification_value is None:
|
|
564
|
+
if failure is not None:
|
|
565
|
+
raise ValueError("provider attempt failure lacks its classification")
|
|
566
|
+
classification = None
|
|
567
|
+
else:
|
|
568
|
+
if (
|
|
569
|
+
type(classification_value) is not dict
|
|
570
|
+
or frozenset(classification_value) != _ATTEMPT_CLASSIFICATION_FIELDS
|
|
571
|
+
):
|
|
572
|
+
raise ValueError("provider attempt classification has unexpected fields")
|
|
573
|
+
disposition = classification_value["disposition"]
|
|
574
|
+
reason = classification_value["reason"]
|
|
575
|
+
if type(disposition) is not str or type(reason) is not str:
|
|
576
|
+
raise ValueError("provider attempt classification is invalid")
|
|
577
|
+
retry_after_ns = value["retry_after_ns"]
|
|
578
|
+
if type(retry_after_ns) is not int or retry_after_ns < 0:
|
|
579
|
+
raise ValueError("provider attempt retry_after_ns is invalid")
|
|
580
|
+
classification = RetryClassification(
|
|
581
|
+
disposition=RetryDisposition(disposition),
|
|
582
|
+
reason=RetryReason(reason),
|
|
583
|
+
retry_after=(
|
|
584
|
+
None
|
|
585
|
+
if retry_after_ns == 0
|
|
586
|
+
else RetryAfter(
|
|
587
|
+
delay_ns=retry_after_ns,
|
|
588
|
+
# The durable projection intentionally omits the header's
|
|
589
|
+
# parsing source; either source has identical queue semantics.
|
|
590
|
+
source=RetryAfterSource.DELAY_SECONDS,
|
|
591
|
+
)
|
|
592
|
+
),
|
|
593
|
+
sanitized_failure=failure,
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
attempt = AttemptTelemetry(
|
|
597
|
+
attempt_number=value["attempt_number"],
|
|
598
|
+
status=AttemptStatus(status_value),
|
|
599
|
+
wait_time_ns=value["wait_time_ns"],
|
|
600
|
+
service_time_ns=value["service_time_ns"],
|
|
601
|
+
will_retry=value["will_retry"],
|
|
602
|
+
policy_backoff_ns=value["policy_backoff_ns"],
|
|
603
|
+
retry_after_ns=value["retry_after_ns"],
|
|
604
|
+
scheduled_delay_ns=value["scheduled_delay_ns"],
|
|
605
|
+
classification=classification,
|
|
606
|
+
error_type=value["error_type"],
|
|
607
|
+
request_evidence=evidence,
|
|
608
|
+
)
|
|
609
|
+
if evidence is None or evidence.provider_attempt_id is None:
|
|
610
|
+
if attempt.status is not AttemptStatus.CANCELLED:
|
|
611
|
+
raise ValueError("non-cancelled attempt lacks physical request evidence")
|
|
612
|
+
return attempt, None, False
|
|
613
|
+
has_provider_evidence = failure is not None and failure.status_code is not None
|
|
614
|
+
return attempt, evidence.provider_attempt_id.value, has_provider_evidence
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
def _outcome_projection(
|
|
618
|
+
row: object,
|
|
619
|
+
) -> tuple[str, list[tuple[str, str, str, bool, str, str]]]:
|
|
620
|
+
value = _canonical_mapping(row, label="provider outcome")
|
|
621
|
+
if frozenset(value) != _OUTCOME_FIELDS:
|
|
622
|
+
raise ValueError("provider outcome has unexpected fields")
|
|
623
|
+
schema_version = value["schema_version"]
|
|
624
|
+
if (
|
|
625
|
+
type(schema_version) is not int
|
|
626
|
+
or schema_version not in SUPPORTED_STRUCTURED_GENERATION_OUTCOME_SCHEMA_VERSIONS
|
|
627
|
+
):
|
|
628
|
+
raise ValueError("provider outcome schema version is unsupported")
|
|
629
|
+
call_id = value["task_id"]
|
|
630
|
+
if type(call_id) is not str:
|
|
631
|
+
raise ValueError("provider outcome lacks task_id")
|
|
632
|
+
LLMCallId(call_id)
|
|
633
|
+
status = value["status"]
|
|
634
|
+
cancellation_reason = value["cancellation_reason"]
|
|
635
|
+
attempts = value["attempts"]
|
|
636
|
+
response = value["response"]
|
|
637
|
+
if type(status) is not str or status not in _TASK_STATUSES:
|
|
638
|
+
raise ValueError("provider outcome status is invalid")
|
|
639
|
+
if type(attempts) is not list:
|
|
640
|
+
raise ValueError("provider outcome attempts/response shape is invalid")
|
|
641
|
+
if response is not None:
|
|
642
|
+
_validate_outcome_response(response)
|
|
643
|
+
if status == "succeeded" and response is None:
|
|
644
|
+
raise ValueError("successful provider outcome lacks its response")
|
|
645
|
+
|
|
646
|
+
projected: list[tuple[str, str, str, bool, str, str]] = []
|
|
647
|
+
telemetry_attempts: list[AttemptTelemetry] = []
|
|
648
|
+
for raw_attempt in attempts:
|
|
649
|
+
attempt, attempt_id, has_provider_evidence = _validate_outcome_attempt(
|
|
650
|
+
raw_attempt,
|
|
651
|
+
schema_version=schema_version,
|
|
652
|
+
)
|
|
653
|
+
telemetry_attempts.append(attempt)
|
|
654
|
+
if attempt_id is not None:
|
|
655
|
+
if attempt.request_evidence is None:
|
|
656
|
+
raise ValueError("physical attempt lacks request evidence")
|
|
657
|
+
projected.append(
|
|
658
|
+
(
|
|
659
|
+
attempt_id,
|
|
660
|
+
call_id,
|
|
661
|
+
attempt.status.value,
|
|
662
|
+
has_provider_evidence or attempt.status is AttemptStatus.SUCCEEDED,
|
|
663
|
+
attempt.request_evidence.prompt_sha256,
|
|
664
|
+
attempt.request_evidence.variant.value,
|
|
665
|
+
)
|
|
666
|
+
)
|
|
667
|
+
|
|
668
|
+
telemetry = TaskTelemetry(
|
|
669
|
+
task_id=call_id,
|
|
670
|
+
queue_time_ns=value["queue_time_ns"],
|
|
671
|
+
service_time_ns=value["service_time_ns"],
|
|
672
|
+
total_time_ns=value["total_time_ns"],
|
|
673
|
+
attempts=tuple(telemetry_attempts),
|
|
674
|
+
)
|
|
675
|
+
status_enum = TaskOutcomeStatus(status)
|
|
676
|
+
if cancellation_reason is not None and type(cancellation_reason) is not str:
|
|
677
|
+
raise ValueError("provider outcome cancellation reason is invalid")
|
|
678
|
+
LLMTaskOutcome(
|
|
679
|
+
status=status_enum,
|
|
680
|
+
telemetry=telemetry,
|
|
681
|
+
response=response,
|
|
682
|
+
cancellation_reason=(
|
|
683
|
+
None
|
|
684
|
+
if cancellation_reason is None
|
|
685
|
+
else CancellationReason(cancellation_reason)
|
|
686
|
+
),
|
|
687
|
+
)
|
|
688
|
+
succeeded = sum(
|
|
689
|
+
attempt.status is AttemptStatus.SUCCEEDED for attempt in telemetry_attempts
|
|
690
|
+
)
|
|
691
|
+
if status_enum is TaskOutcomeStatus.SUCCEEDED and succeeded != 1:
|
|
692
|
+
raise ValueError("provider response does not join one succeeded attempt")
|
|
693
|
+
if status_enum is not TaskOutcomeStatus.SUCCEEDED and succeeded:
|
|
694
|
+
raise ValueError("non-successful provider outcome has a succeeded attempt")
|
|
695
|
+
return call_id, projected
|
|
696
|
+
|
|
697
|
+
|
|
698
|
+
def validate_structured_generation_outcome_record(
|
|
699
|
+
row: Mapping[str, object],
|
|
700
|
+
) -> dict[str, object]:
|
|
701
|
+
"""Strictly validate and detach one durable queue-outcome projection.
|
|
702
|
+
|
|
703
|
+
This is the public, content-free decoder for records produced by
|
|
704
|
+
:func:`structured_generation_outcome_record`. It deliberately returns the
|
|
705
|
+
canonical JSON projection rather than reconstructing a provider response:
|
|
706
|
+
typed response content lives in the separately authenticated structured
|
|
707
|
+
output-evidence channel.
|
|
708
|
+
"""
|
|
709
|
+
|
|
710
|
+
value = _canonical_mapping(row, label="provider outcome")
|
|
711
|
+
_outcome_projection(value)
|
|
712
|
+
return value
|
|
713
|
+
|
|
714
|
+
|
|
715
|
+
def _progress_projection(row: object) -> tuple[str, str, int]:
|
|
716
|
+
value = _canonical_mapping(row, label="provider progress")
|
|
717
|
+
if frozenset(value) != _PROGRESS_FIELDS:
|
|
718
|
+
raise ValueError("provider progress has unexpected fields")
|
|
719
|
+
if value["schema_version"] != 1:
|
|
720
|
+
raise ValueError("provider progress schema version is unsupported")
|
|
721
|
+
call_id = value["call_id"]
|
|
722
|
+
attempt_id = value["provider_attempt_id"]
|
|
723
|
+
sequence = value["sequence"]
|
|
724
|
+
if type(call_id) is not str or type(attempt_id) is not str:
|
|
725
|
+
raise ValueError("provider progress lacks call/attempt identity")
|
|
726
|
+
kind = value["kind"]
|
|
727
|
+
channel = value["channel"]
|
|
728
|
+
if type(kind) is not str or type(channel) is not str:
|
|
729
|
+
raise ValueError("provider progress kind/channel is invalid")
|
|
730
|
+
progress = StructuredStreamProgress(
|
|
731
|
+
call_id=call_id,
|
|
732
|
+
provider_attempt_id=attempt_id,
|
|
733
|
+
sequence=sequence,
|
|
734
|
+
kind=StructuredStreamProgressKind(kind),
|
|
735
|
+
channel=StructuredStreamChannel(channel),
|
|
736
|
+
elapsed_ns=value["elapsed_ns"],
|
|
737
|
+
event_content_utf8_bytes=value["event_content_utf8_bytes"],
|
|
738
|
+
cumulative_content_utf8_bytes=value["cumulative_content_utf8_bytes"],
|
|
739
|
+
rolling_content_sha256=value["rolling_content_sha256"],
|
|
740
|
+
)
|
|
741
|
+
progress.__post_init__()
|
|
742
|
+
return attempt_id, call_id, sequence
|
|
743
|
+
|
|
744
|
+
|
|
745
|
+
def _duplicates(values: Sequence[str]) -> list[str]:
|
|
746
|
+
return sorted(value for value, count in Counter(values).items() if count != 1)
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
def _logical_request_projection(row: object) -> dict[str, object]:
|
|
750
|
+
value = validate_structured_generation_request_evidence_record(
|
|
751
|
+
_canonical_mapping(row, label="logical request evidence")
|
|
752
|
+
)
|
|
753
|
+
return {
|
|
754
|
+
"call_id": value["call_id"],
|
|
755
|
+
"operation": value["operation"],
|
|
756
|
+
"prompt_sha256": value["wire_prompt_sha256"],
|
|
757
|
+
"prompt_utf8_bytes": value["prompt_utf8_bytes"],
|
|
758
|
+
"output_tool_name": value["output_tool_name"],
|
|
759
|
+
"logical_output_schema_sha256": value["output_schema_sha256"],
|
|
760
|
+
"logical_output_schema_utf8_bytes": value["output_schema_utf8_bytes"],
|
|
761
|
+
"max_completion_tokens": value["max_output_tokens"],
|
|
762
|
+
"requested_temperature_hex": value["temperature_hex"],
|
|
763
|
+
"request_evidence_sha256": value["request_evidence_sha256"],
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
def _manifest_logical_projection(value: Mapping[str, object]) -> dict[str, object]:
|
|
768
|
+
message = value["message"]
|
|
769
|
+
tool = value["tool"]
|
|
770
|
+
request_contract = value["request_contract"]
|
|
771
|
+
settings = value["settings"]
|
|
772
|
+
assert isinstance(message, Mapping)
|
|
773
|
+
assert isinstance(tool, Mapping)
|
|
774
|
+
assert isinstance(request_contract, Mapping)
|
|
775
|
+
assert isinstance(settings, Mapping)
|
|
776
|
+
return {
|
|
777
|
+
"call_id": value["call_id"],
|
|
778
|
+
"operation": value["operation"],
|
|
779
|
+
"prompt_sha256": message["content_sha256"],
|
|
780
|
+
"prompt_utf8_bytes": message["content_utf8_bytes"],
|
|
781
|
+
"output_tool_name": tool["name"],
|
|
782
|
+
"logical_output_schema_sha256": request_contract[
|
|
783
|
+
"logical_output_schema_sha256"
|
|
784
|
+
],
|
|
785
|
+
"logical_output_schema_utf8_bytes": request_contract[
|
|
786
|
+
"logical_output_schema_utf8_bytes"
|
|
787
|
+
],
|
|
788
|
+
"max_completion_tokens": settings["max_completion_tokens"],
|
|
789
|
+
"requested_temperature_hex": request_contract["requested_temperature_hex"],
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
|
|
793
|
+
def _validated_expected_framework_versions(
|
|
794
|
+
value: Mapping[str, object] | None,
|
|
795
|
+
) -> dict[str, object] | None:
|
|
796
|
+
if value is None:
|
|
797
|
+
return None
|
|
798
|
+
record = _canonical_mapping(value, label="expected framework versions")
|
|
799
|
+
if frozenset(record) != _FRAMEWORK_VERSION_FIELDS or any(
|
|
800
|
+
type(item) is not str or not item or item != item.strip()
|
|
801
|
+
for item in record.values()
|
|
802
|
+
):
|
|
803
|
+
raise ValueError("expected framework versions violate the closed schema")
|
|
804
|
+
return record
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
def _validated_expected_transport_settings(
|
|
808
|
+
value: Mapping[str, object] | None,
|
|
809
|
+
) -> dict[str, object] | None:
|
|
810
|
+
if value is None:
|
|
811
|
+
return None
|
|
812
|
+
record = _canonical_mapping(value, label="expected transport settings")
|
|
813
|
+
if frozenset(record) != _EXPECTED_TRANSPORT_SETTING_FIELDS:
|
|
814
|
+
raise ValueError("expected transport settings violate the closed schema")
|
|
815
|
+
return record
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
def build_provider_attempt_terminal_join_receipt(
|
|
819
|
+
*,
|
|
820
|
+
logical_requests: Sequence[Mapping[str, object]] = (),
|
|
821
|
+
outbound_manifests: Sequence[Mapping[str, object]],
|
|
822
|
+
terminal_outcomes: Sequence[Mapping[str, object]],
|
|
823
|
+
progress_rows: Sequence[Mapping[str, object]],
|
|
824
|
+
explicit_pre_transport_failures: Sequence[Mapping[str, object]] = (),
|
|
825
|
+
expected_framework_versions: Mapping[str, object] | None = None,
|
|
826
|
+
expected_transport_settings: Mapping[str, object] | None = None,
|
|
827
|
+
) -> dict[str, object]:
|
|
828
|
+
"""Build a redacted terminal join; mismatches yield ``join_valid=False``.
|
|
829
|
+
|
|
830
|
+
Every queue attempt carrying a physical ID requires one outbound manifest,
|
|
831
|
+
unless a separately authenticated record affirmatively proves it failed
|
|
832
|
+
before HTTP dispatch. Missing manifests are never treated as such proof.
|
|
833
|
+
"""
|
|
834
|
+
|
|
835
|
+
collections = (
|
|
836
|
+
logical_requests,
|
|
837
|
+
outbound_manifests,
|
|
838
|
+
terminal_outcomes,
|
|
839
|
+
progress_rows,
|
|
840
|
+
explicit_pre_transport_failures,
|
|
841
|
+
)
|
|
842
|
+
if any(not isinstance(value, Sequence) for value in collections):
|
|
843
|
+
raise TypeError("provider-attempt join inputs must be sequences")
|
|
844
|
+
|
|
845
|
+
expected_frameworks = _validated_expected_framework_versions(
|
|
846
|
+
expected_framework_versions
|
|
847
|
+
)
|
|
848
|
+
expected_settings = _validated_expected_transport_settings(
|
|
849
|
+
expected_transport_settings
|
|
850
|
+
)
|
|
851
|
+
|
|
852
|
+
malformed_logical_requests: list[int] = []
|
|
853
|
+
malformed_manifests: list[int] = []
|
|
854
|
+
malformed_outcomes: list[int] = []
|
|
855
|
+
malformed_progress: list[int] = []
|
|
856
|
+
malformed_pretransport: list[int] = []
|
|
857
|
+
logical_entries: list[dict[str, object]] = []
|
|
858
|
+
manifest_entries: list[dict[str, object]] = []
|
|
859
|
+
outcome_entries: list[tuple[str, str, str, bool, str, str]] = []
|
|
860
|
+
progress_entries: list[tuple[str, str, int]] = []
|
|
861
|
+
pretransport_entries: list[tuple[str, str, str]] = []
|
|
862
|
+
|
|
863
|
+
for index, row in enumerate(logical_requests):
|
|
864
|
+
try:
|
|
865
|
+
logical_entries.append(_logical_request_projection(row))
|
|
866
|
+
except (TypeError, ValueError):
|
|
867
|
+
malformed_logical_requests.append(index)
|
|
868
|
+
for index, row in enumerate(outbound_manifests):
|
|
869
|
+
try:
|
|
870
|
+
manifest = validate_openrouter_outbound_request_manifest_record(row)
|
|
871
|
+
manifest_entries.append(manifest)
|
|
872
|
+
except (TypeError, ValueError):
|
|
873
|
+
malformed_manifests.append(index)
|
|
874
|
+
for index, row in enumerate(terminal_outcomes):
|
|
875
|
+
try:
|
|
876
|
+
_, attempts = _outcome_projection(row)
|
|
877
|
+
outcome_entries.extend(attempts)
|
|
878
|
+
except (TypeError, ValueError):
|
|
879
|
+
malformed_outcomes.append(index)
|
|
880
|
+
for index, row in enumerate(progress_rows):
|
|
881
|
+
try:
|
|
882
|
+
progress_entries.append(_progress_projection(row))
|
|
883
|
+
except (TypeError, ValueError):
|
|
884
|
+
malformed_progress.append(index)
|
|
885
|
+
for index, row in enumerate(explicit_pre_transport_failures):
|
|
886
|
+
try:
|
|
887
|
+
evidence = validate_explicit_pre_transport_failure_evidence_record(row)
|
|
888
|
+
pretransport_entries.append(
|
|
889
|
+
(
|
|
890
|
+
evidence["provider_attempt_id"],
|
|
891
|
+
evidence["call_id"],
|
|
892
|
+
evidence["evidence_sha256"],
|
|
893
|
+
)
|
|
894
|
+
)
|
|
895
|
+
except (TypeError, ValueError):
|
|
896
|
+
malformed_pretransport.append(index)
|
|
897
|
+
|
|
898
|
+
logical_call_ids = [str(value["call_id"]) for value in logical_entries]
|
|
899
|
+
manifest_ids = [str(value["provider_attempt_id"]) for value in manifest_entries]
|
|
900
|
+
outcome_ids = [value[0] for value in outcome_entries]
|
|
901
|
+
progress_ids = [value[0] for value in progress_entries]
|
|
902
|
+
pretransport_ids = [value[0] for value in pretransport_entries]
|
|
903
|
+
manifest_set = set(manifest_ids)
|
|
904
|
+
outcome_set = set(outcome_ids)
|
|
905
|
+
progress_set = set(progress_ids)
|
|
906
|
+
pretransport_set = set(pretransport_ids)
|
|
907
|
+
provider_evidence_set = {
|
|
908
|
+
attempt_id
|
|
909
|
+
for attempt_id, _, _, has_evidence, _, _ in outcome_entries
|
|
910
|
+
if has_evidence
|
|
911
|
+
} | progress_set
|
|
912
|
+
affirmative_pretransport_set = pretransport_set - provider_evidence_set
|
|
913
|
+
required_manifest_set = outcome_set - affirmative_pretransport_set
|
|
914
|
+
|
|
915
|
+
logical_by_call: dict[str, list[dict[str, object]]] = defaultdict(list)
|
|
916
|
+
for value in logical_entries:
|
|
917
|
+
logical_by_call[str(value["call_id"])].append(value)
|
|
918
|
+
attempt_request_by_id = {
|
|
919
|
+
attempt_id: (prompt_sha256, variant)
|
|
920
|
+
for attempt_id, _, _, _, prompt_sha256, variant in outcome_entries
|
|
921
|
+
}
|
|
922
|
+
missing_logical_requests: list[str] = []
|
|
923
|
+
logical_physical_mismatches: list[str] = []
|
|
924
|
+
framework_version_mismatches: list[str] = []
|
|
925
|
+
transport_settings_mismatches: list[str] = []
|
|
926
|
+
for manifest in manifest_entries:
|
|
927
|
+
attempt_id = str(manifest["provider_attempt_id"])
|
|
928
|
+
matching = logical_by_call.get(str(manifest["call_id"]), [])
|
|
929
|
+
if not matching:
|
|
930
|
+
missing_logical_requests.append(attempt_id)
|
|
931
|
+
elif len(matching) == 1:
|
|
932
|
+
observed = _manifest_logical_projection(manifest)
|
|
933
|
+
expected = {
|
|
934
|
+
name: item
|
|
935
|
+
for name, item in matching[0].items()
|
|
936
|
+
if name != "request_evidence_sha256"
|
|
937
|
+
}
|
|
938
|
+
attempt_request = attempt_request_by_id.get(attempt_id)
|
|
939
|
+
if attempt_request is None:
|
|
940
|
+
logical_physical_mismatches.append(attempt_id)
|
|
941
|
+
else:
|
|
942
|
+
attempt_prompt_sha256, variant = attempt_request
|
|
943
|
+
if variant == AttemptRequestVariant.ORIGINAL.value:
|
|
944
|
+
mismatch = (
|
|
945
|
+
attempt_prompt_sha256 != expected["prompt_sha256"]
|
|
946
|
+
or observed != expected
|
|
947
|
+
)
|
|
948
|
+
else:
|
|
949
|
+
# Schema-repair variants preserve every logical request
|
|
950
|
+
# field except the provider-facing prompt, whose exact
|
|
951
|
+
# digest is committed by the per-attempt queue evidence.
|
|
952
|
+
expected["prompt_sha256"] = attempt_prompt_sha256
|
|
953
|
+
observed.pop("prompt_utf8_bytes")
|
|
954
|
+
expected.pop("prompt_utf8_bytes")
|
|
955
|
+
mismatch = observed != expected
|
|
956
|
+
if mismatch:
|
|
957
|
+
logical_physical_mismatches.append(attempt_id)
|
|
958
|
+
if (
|
|
959
|
+
expected_frameworks is None
|
|
960
|
+
or manifest["framework_versions"] != expected_frameworks
|
|
961
|
+
):
|
|
962
|
+
framework_version_mismatches.append(attempt_id)
|
|
963
|
+
settings = manifest["settings"]
|
|
964
|
+
if (
|
|
965
|
+
expected_settings is None
|
|
966
|
+
or type(settings) is not dict
|
|
967
|
+
or any(
|
|
968
|
+
settings[name] != expected_settings[name] for name in expected_settings
|
|
969
|
+
)
|
|
970
|
+
):
|
|
971
|
+
transport_settings_mismatches.append(attempt_id)
|
|
972
|
+
|
|
973
|
+
call_ids_by_attempt: dict[str, set[str]] = defaultdict(set)
|
|
974
|
+
for manifest in manifest_entries:
|
|
975
|
+
call_ids_by_attempt[str(manifest["provider_attempt_id"])].add(
|
|
976
|
+
str(manifest["call_id"])
|
|
977
|
+
)
|
|
978
|
+
for attempt_id, call_id, _, _, _, _ in outcome_entries:
|
|
979
|
+
call_ids_by_attempt[attempt_id].add(call_id)
|
|
980
|
+
for attempt_id, call_id, _ in progress_entries:
|
|
981
|
+
call_ids_by_attempt[attempt_id].add(call_id)
|
|
982
|
+
for attempt_id, call_id, _ in pretransport_entries:
|
|
983
|
+
call_ids_by_attempt[attempt_id].add(call_id)
|
|
984
|
+
|
|
985
|
+
progress_sequences: dict[str, list[int]] = defaultdict(list)
|
|
986
|
+
for attempt_id, _, sequence in progress_entries:
|
|
987
|
+
progress_sequences[attempt_id].append(sequence)
|
|
988
|
+
canonical_progress_sequences = {
|
|
989
|
+
attempt_id: sorted(sequences)
|
|
990
|
+
for attempt_id, sequences in sorted(progress_sequences.items())
|
|
991
|
+
}
|
|
992
|
+
duplicate_progress_sequences = sorted(
|
|
993
|
+
attempt_id
|
|
994
|
+
for attempt_id, sequences in canonical_progress_sequences.items()
|
|
995
|
+
if len(sequences) != len(set(sequences))
|
|
996
|
+
)
|
|
997
|
+
noncontiguous_progress_sequences = sorted(
|
|
998
|
+
attempt_id
|
|
999
|
+
for attempt_id, sequences in canonical_progress_sequences.items()
|
|
1000
|
+
if sequences != list(range(1, len(sequences) + 1))
|
|
1001
|
+
)
|
|
1002
|
+
|
|
1003
|
+
shared_ids = manifest_set | outcome_set | progress_set | pretransport_set
|
|
1004
|
+
call_mismatches = sorted(
|
|
1005
|
+
attempt_id
|
|
1006
|
+
for attempt_id in shared_ids
|
|
1007
|
+
if len(call_ids_by_attempt[attempt_id]) > 1
|
|
1008
|
+
)
|
|
1009
|
+
|
|
1010
|
+
duplicate_logical_call_ids = _duplicates(logical_call_ids)
|
|
1011
|
+
duplicate_manifest_ids = _duplicates(manifest_ids)
|
|
1012
|
+
duplicate_outcome_ids = _duplicates(outcome_ids)
|
|
1013
|
+
duplicate_pretransport_ids = _duplicates(pretransport_ids)
|
|
1014
|
+
missing_manifests = sorted(required_manifest_set - manifest_set)
|
|
1015
|
+
orphan_manifests = sorted(manifest_set - outcome_set)
|
|
1016
|
+
progress_without_manifest = sorted(progress_set - manifest_set)
|
|
1017
|
+
progress_without_outcome = sorted(progress_set - outcome_set)
|
|
1018
|
+
provider_evidence_without_manifest = sorted(provider_evidence_set - manifest_set)
|
|
1019
|
+
pretransport_with_manifest = sorted(pretransport_set & manifest_set)
|
|
1020
|
+
pretransport_with_provider_evidence = sorted(
|
|
1021
|
+
pretransport_set & provider_evidence_set
|
|
1022
|
+
)
|
|
1023
|
+
pretransport_without_outcome = sorted(pretransport_set - outcome_set)
|
|
1024
|
+
|
|
1025
|
+
defects = (
|
|
1026
|
+
malformed_logical_requests,
|
|
1027
|
+
malformed_manifests,
|
|
1028
|
+
malformed_outcomes,
|
|
1029
|
+
malformed_progress,
|
|
1030
|
+
malformed_pretransport,
|
|
1031
|
+
duplicate_logical_call_ids,
|
|
1032
|
+
duplicate_manifest_ids,
|
|
1033
|
+
duplicate_outcome_ids,
|
|
1034
|
+
duplicate_pretransport_ids,
|
|
1035
|
+
missing_logical_requests,
|
|
1036
|
+
logical_physical_mismatches,
|
|
1037
|
+
framework_version_mismatches,
|
|
1038
|
+
transport_settings_mismatches,
|
|
1039
|
+
missing_manifests,
|
|
1040
|
+
orphan_manifests,
|
|
1041
|
+
progress_without_manifest,
|
|
1042
|
+
progress_without_outcome,
|
|
1043
|
+
duplicate_progress_sequences,
|
|
1044
|
+
noncontiguous_progress_sequences,
|
|
1045
|
+
provider_evidence_without_manifest,
|
|
1046
|
+
pretransport_with_manifest,
|
|
1047
|
+
pretransport_with_provider_evidence,
|
|
1048
|
+
pretransport_without_outcome,
|
|
1049
|
+
call_mismatches,
|
|
1050
|
+
)
|
|
1051
|
+
join_valid = not any(defects)
|
|
1052
|
+
record: dict[str, object] = {
|
|
1053
|
+
"schema_version": PROVIDER_ATTEMPT_TERMINAL_JOIN_SCHEMA_VERSION,
|
|
1054
|
+
"contract_id": PROVIDER_ATTEMPT_TERMINAL_JOIN_CONTRACT_ID,
|
|
1055
|
+
"source_counts": {
|
|
1056
|
+
"logical_requests": len(logical_requests),
|
|
1057
|
+
"outbound_manifests": len(outbound_manifests),
|
|
1058
|
+
"terminal_outcomes": len(terminal_outcomes),
|
|
1059
|
+
"outcome_attempts_with_physical_ids": len(outcome_entries),
|
|
1060
|
+
"progress_rows": len(progress_rows),
|
|
1061
|
+
"explicit_pre_transport_failures": len(explicit_pre_transport_failures),
|
|
1062
|
+
},
|
|
1063
|
+
"source_sha256": {
|
|
1064
|
+
"logical_requests": _collection_sha256(logical_requests),
|
|
1065
|
+
"outbound_manifests": _collection_sha256(outbound_manifests),
|
|
1066
|
+
"terminal_outcomes": _collection_sha256(terminal_outcomes),
|
|
1067
|
+
"progress_rows": _collection_sha256(progress_rows),
|
|
1068
|
+
"explicit_pre_transport_failures": _collection_sha256(
|
|
1069
|
+
explicit_pre_transport_failures
|
|
1070
|
+
),
|
|
1071
|
+
},
|
|
1072
|
+
"expected_framework_versions": expected_frameworks,
|
|
1073
|
+
"expected_transport_settings": expected_settings,
|
|
1074
|
+
"logical_request_call_ids": sorted(set(logical_call_ids)),
|
|
1075
|
+
"provider_attempt_ids": {
|
|
1076
|
+
"dispatched": sorted(manifest_set),
|
|
1077
|
+
"terminal_outcomes": sorted(outcome_set),
|
|
1078
|
+
"progress": sorted(progress_set),
|
|
1079
|
+
"provider_status_response_or_progress": sorted(provider_evidence_set),
|
|
1080
|
+
"explicit_pre_transport_failures": sorted(pretransport_set),
|
|
1081
|
+
},
|
|
1082
|
+
"call_ids_by_provider_attempt": {
|
|
1083
|
+
attempt_id: sorted(call_ids_by_attempt[attempt_id])
|
|
1084
|
+
for attempt_id in sorted(shared_ids)
|
|
1085
|
+
},
|
|
1086
|
+
"progress_sequences_by_provider_attempt": canonical_progress_sequences,
|
|
1087
|
+
"malformed_row_indices": {
|
|
1088
|
+
"logical_requests": malformed_logical_requests,
|
|
1089
|
+
"outbound_manifests": malformed_manifests,
|
|
1090
|
+
"terminal_outcomes": malformed_outcomes,
|
|
1091
|
+
"progress_rows": malformed_progress,
|
|
1092
|
+
"explicit_pre_transport_failures": malformed_pretransport,
|
|
1093
|
+
},
|
|
1094
|
+
"defects": {
|
|
1095
|
+
"duplicate_logical_request_call_ids": duplicate_logical_call_ids,
|
|
1096
|
+
"duplicate_outbound_manifest_attempt_ids": duplicate_manifest_ids,
|
|
1097
|
+
"duplicate_outcome_attempt_ids": duplicate_outcome_ids,
|
|
1098
|
+
"duplicate_pre_transport_attempt_ids": duplicate_pretransport_ids,
|
|
1099
|
+
"missing_logical_request_attempt_ids": sorted(
|
|
1100
|
+
set(missing_logical_requests)
|
|
1101
|
+
),
|
|
1102
|
+
"logical_physical_mismatch_attempt_ids": sorted(
|
|
1103
|
+
set(logical_physical_mismatches)
|
|
1104
|
+
),
|
|
1105
|
+
"framework_version_mismatch_attempt_ids": sorted(
|
|
1106
|
+
set(framework_version_mismatches)
|
|
1107
|
+
),
|
|
1108
|
+
"transport_settings_mismatch_attempt_ids": sorted(
|
|
1109
|
+
set(transport_settings_mismatches)
|
|
1110
|
+
),
|
|
1111
|
+
"missing_manifest_attempt_ids": missing_manifests,
|
|
1112
|
+
"orphan_manifest_attempt_ids": orphan_manifests,
|
|
1113
|
+
"progress_without_manifest_attempt_ids": progress_without_manifest,
|
|
1114
|
+
"progress_without_outcome_attempt_ids": progress_without_outcome,
|
|
1115
|
+
"progress_duplicate_sequence_attempt_ids": (duplicate_progress_sequences),
|
|
1116
|
+
"progress_noncontiguous_sequence_attempt_ids": (
|
|
1117
|
+
noncontiguous_progress_sequences
|
|
1118
|
+
),
|
|
1119
|
+
"provider_evidence_without_manifest_attempt_ids": (
|
|
1120
|
+
provider_evidence_without_manifest
|
|
1121
|
+
),
|
|
1122
|
+
"pre_transport_with_manifest_attempt_ids": pretransport_with_manifest,
|
|
1123
|
+
"pre_transport_with_provider_evidence_attempt_ids": (
|
|
1124
|
+
pretransport_with_provider_evidence
|
|
1125
|
+
),
|
|
1126
|
+
"pre_transport_without_outcome_attempt_ids": (pretransport_without_outcome),
|
|
1127
|
+
"call_id_mismatch_attempt_ids": call_mismatches,
|
|
1128
|
+
},
|
|
1129
|
+
"invariants": {
|
|
1130
|
+
"logical_request_exactly_once_per_dispatched_attempt": (
|
|
1131
|
+
not duplicate_logical_call_ids and not missing_logical_requests
|
|
1132
|
+
),
|
|
1133
|
+
"logical_physical_request_fields_exact": (not logical_physical_mismatches),
|
|
1134
|
+
"framework_versions_join_qualification_exact": (
|
|
1135
|
+
not framework_version_mismatches
|
|
1136
|
+
),
|
|
1137
|
+
"transport_settings_join_selected_profile_exact": (
|
|
1138
|
+
not transport_settings_mismatches
|
|
1139
|
+
),
|
|
1140
|
+
"manifest_exactly_once_per_dispatched_attempt": (
|
|
1141
|
+
not duplicate_manifest_ids
|
|
1142
|
+
),
|
|
1143
|
+
"outcome_attempt_identity_exactly_once": not duplicate_outcome_ids,
|
|
1144
|
+
"every_physical_outcome_attempt_accounted_for": not missing_manifests,
|
|
1145
|
+
"every_dispatched_attempt_has_terminal_outcome": not orphan_manifests,
|
|
1146
|
+
"provider_evidence_always_has_manifest": (
|
|
1147
|
+
not provider_evidence_without_manifest
|
|
1148
|
+
),
|
|
1149
|
+
"progress_joins_manifest_and_outcome": (
|
|
1150
|
+
not progress_without_manifest and not progress_without_outcome
|
|
1151
|
+
),
|
|
1152
|
+
"progress_sequence_unique_and_contiguous": (
|
|
1153
|
+
not duplicate_progress_sequences
|
|
1154
|
+
and not noncontiguous_progress_sequences
|
|
1155
|
+
),
|
|
1156
|
+
"explicit_pre_transport_evidence_consistent": (
|
|
1157
|
+
not duplicate_pretransport_ids
|
|
1158
|
+
and not pretransport_with_manifest
|
|
1159
|
+
and not pretransport_with_provider_evidence
|
|
1160
|
+
and not pretransport_without_outcome
|
|
1161
|
+
),
|
|
1162
|
+
"explicit_pre_transport_is_affirmative_not_inferred": True,
|
|
1163
|
+
"call_id_join_exact": not call_mismatches,
|
|
1164
|
+
# Accepted source rows have exact, content-safe durable schemas.
|
|
1165
|
+
# Rejected rows contribute only an index and a collection digest;
|
|
1166
|
+
# no source value is copied into this receipt projection.
|
|
1167
|
+
"raw_provider_content_persisted": False,
|
|
1168
|
+
},
|
|
1169
|
+
"join_valid": join_valid,
|
|
1170
|
+
}
|
|
1171
|
+
record["join_receipt_sha256"] = _domain_sha256(_JOIN_DOMAIN, record)
|
|
1172
|
+
return validate_provider_attempt_terminal_join_receipt(record)
|
|
1173
|
+
|
|
1174
|
+
|
|
1175
|
+
def validate_provider_attempt_terminal_join_receipt(
|
|
1176
|
+
value: Mapping[str, object],
|
|
1177
|
+
) -> dict[str, object]:
|
|
1178
|
+
record = _canonical_mapping(value, label="provider-attempt terminal join")
|
|
1179
|
+
if frozenset(record) != {
|
|
1180
|
+
"schema_version",
|
|
1181
|
+
"contract_id",
|
|
1182
|
+
"source_counts",
|
|
1183
|
+
"source_sha256",
|
|
1184
|
+
"expected_framework_versions",
|
|
1185
|
+
"expected_transport_settings",
|
|
1186
|
+
"logical_request_call_ids",
|
|
1187
|
+
"provider_attempt_ids",
|
|
1188
|
+
"call_ids_by_provider_attempt",
|
|
1189
|
+
"progress_sequences_by_provider_attempt",
|
|
1190
|
+
"malformed_row_indices",
|
|
1191
|
+
"defects",
|
|
1192
|
+
"invariants",
|
|
1193
|
+
"join_valid",
|
|
1194
|
+
"join_receipt_sha256",
|
|
1195
|
+
}:
|
|
1196
|
+
raise ValueError("provider-attempt terminal join has unexpected fields")
|
|
1197
|
+
if (
|
|
1198
|
+
record["schema_version"] != PROVIDER_ATTEMPT_TERMINAL_JOIN_SCHEMA_VERSION
|
|
1199
|
+
or record["contract_id"] != PROVIDER_ATTEMPT_TERMINAL_JOIN_CONTRACT_ID
|
|
1200
|
+
or type(record["join_valid"]) is not bool
|
|
1201
|
+
):
|
|
1202
|
+
raise ValueError("provider-attempt terminal join contract drifted")
|
|
1203
|
+
for name in (
|
|
1204
|
+
"source_counts",
|
|
1205
|
+
"source_sha256",
|
|
1206
|
+
"provider_attempt_ids",
|
|
1207
|
+
"call_ids_by_provider_attempt",
|
|
1208
|
+
"progress_sequences_by_provider_attempt",
|
|
1209
|
+
"malformed_row_indices",
|
|
1210
|
+
"defects",
|
|
1211
|
+
"invariants",
|
|
1212
|
+
):
|
|
1213
|
+
if type(record[name]) is not dict:
|
|
1214
|
+
raise ValueError(f"{name} must be an exact object")
|
|
1215
|
+
source_counts = record["source_counts"]
|
|
1216
|
+
source_sha256 = record["source_sha256"]
|
|
1217
|
+
provider_attempt_ids = record["provider_attempt_ids"]
|
|
1218
|
+
malformed = record["malformed_row_indices"]
|
|
1219
|
+
defects = record["defects"]
|
|
1220
|
+
invariants = record["invariants"]
|
|
1221
|
+
call_ids_by_attempt = record["call_ids_by_provider_attempt"]
|
|
1222
|
+
progress_sequences = record["progress_sequences_by_provider_attempt"]
|
|
1223
|
+
assert type(source_counts) is dict
|
|
1224
|
+
assert type(source_sha256) is dict
|
|
1225
|
+
assert type(provider_attempt_ids) is dict
|
|
1226
|
+
assert type(malformed) is dict
|
|
1227
|
+
assert type(defects) is dict
|
|
1228
|
+
assert type(invariants) is dict
|
|
1229
|
+
assert type(call_ids_by_attempt) is dict
|
|
1230
|
+
assert type(progress_sequences) is dict
|
|
1231
|
+
|
|
1232
|
+
if frozenset(source_counts) != _SOURCE_COUNT_FIELDS or any(
|
|
1233
|
+
type(item) is not int or item < 0 for item in source_counts.values()
|
|
1234
|
+
):
|
|
1235
|
+
raise ValueError("provider-attempt join source counts are invalid")
|
|
1236
|
+
if frozenset(source_sha256) != _SOURCE_FIELDS:
|
|
1237
|
+
raise ValueError("provider-attempt join source hashes are incomplete")
|
|
1238
|
+
for name, digest in source_sha256.items():
|
|
1239
|
+
_require_sha256(digest, label=f"source_sha256.{name}")
|
|
1240
|
+
|
|
1241
|
+
expected_frameworks = _validated_expected_framework_versions(
|
|
1242
|
+
record["expected_framework_versions"]
|
|
1243
|
+
)
|
|
1244
|
+
expected_settings = _validated_expected_transport_settings(
|
|
1245
|
+
record["expected_transport_settings"]
|
|
1246
|
+
)
|
|
1247
|
+
if expected_frameworks != record["expected_framework_versions"]:
|
|
1248
|
+
raise ValueError("expected framework versions are not canonical")
|
|
1249
|
+
if expected_settings != record["expected_transport_settings"]:
|
|
1250
|
+
raise ValueError("expected transport settings are not canonical")
|
|
1251
|
+
|
|
1252
|
+
def exact_identity_list(
|
|
1253
|
+
item: object,
|
|
1254
|
+
*,
|
|
1255
|
+
label: str,
|
|
1256
|
+
constructor: object,
|
|
1257
|
+
unique: bool = True,
|
|
1258
|
+
) -> list[str]:
|
|
1259
|
+
if type(item) is not list or any(type(entry) is not str for entry in item):
|
|
1260
|
+
raise ValueError(f"{label} must be a list of exact identifiers")
|
|
1261
|
+
values = list(item)
|
|
1262
|
+
if values != sorted(values) or (unique and len(values) != len(set(values))):
|
|
1263
|
+
raise ValueError(f"{label} must be canonical sorted identifiers")
|
|
1264
|
+
for entry in values:
|
|
1265
|
+
try:
|
|
1266
|
+
constructor(entry) # type: ignore[operator]
|
|
1267
|
+
except (TypeError, ValueError) as exc:
|
|
1268
|
+
raise ValueError(f"{label} contains an invalid identifier") from exc
|
|
1269
|
+
return values
|
|
1270
|
+
|
|
1271
|
+
logical_call_ids = exact_identity_list(
|
|
1272
|
+
record["logical_request_call_ids"],
|
|
1273
|
+
label="logical_request_call_ids",
|
|
1274
|
+
constructor=LLMCallId,
|
|
1275
|
+
)
|
|
1276
|
+
if frozenset(provider_attempt_ids) != _PROVIDER_ATTEMPT_ID_FIELDS:
|
|
1277
|
+
raise ValueError("provider_attempt_ids violates the closed schema")
|
|
1278
|
+
attempt_sets: dict[str, set[str]] = {}
|
|
1279
|
+
for name in sorted(_PROVIDER_ATTEMPT_ID_FIELDS):
|
|
1280
|
+
attempt_sets[name] = set(
|
|
1281
|
+
exact_identity_list(
|
|
1282
|
+
provider_attempt_ids[name],
|
|
1283
|
+
label=f"provider_attempt_ids.{name}",
|
|
1284
|
+
constructor=ProviderAttemptId,
|
|
1285
|
+
)
|
|
1286
|
+
)
|
|
1287
|
+
|
|
1288
|
+
shared_ids = set().union(*attempt_sets.values())
|
|
1289
|
+
if set(call_ids_by_attempt) != shared_ids:
|
|
1290
|
+
raise ValueError("call ID summary does not cover exact attempt identities")
|
|
1291
|
+
normalized_call_summary: dict[str, list[str]] = {}
|
|
1292
|
+
for attempt_id, call_ids in call_ids_by_attempt.items():
|
|
1293
|
+
ProviderAttemptId(attempt_id)
|
|
1294
|
+
normalized_call_summary[attempt_id] = exact_identity_list(
|
|
1295
|
+
call_ids,
|
|
1296
|
+
label=f"call_ids_by_provider_attempt.{attempt_id}",
|
|
1297
|
+
constructor=LLMCallId,
|
|
1298
|
+
)
|
|
1299
|
+
if not normalized_call_summary[attempt_id]:
|
|
1300
|
+
raise ValueError("attempt call ID summary cannot be empty")
|
|
1301
|
+
|
|
1302
|
+
progress_set = attempt_sets["progress"]
|
|
1303
|
+
if set(progress_sequences) != progress_set:
|
|
1304
|
+
raise ValueError("progress sequence summary does not cover progress attempts")
|
|
1305
|
+
normalized_sequences: dict[str, list[int]] = {}
|
|
1306
|
+
for attempt_id, sequences in progress_sequences.items():
|
|
1307
|
+
ProviderAttemptId(attempt_id)
|
|
1308
|
+
if (
|
|
1309
|
+
type(sequences) is not list
|
|
1310
|
+
or not sequences
|
|
1311
|
+
or any(type(sequence) is not int or sequence < 1 for sequence in sequences)
|
|
1312
|
+
or sequences != sorted(sequences)
|
|
1313
|
+
):
|
|
1314
|
+
raise ValueError("progress sequence summary is invalid")
|
|
1315
|
+
normalized_sequences[attempt_id] = list(sequences)
|
|
1316
|
+
|
|
1317
|
+
if frozenset(malformed) != _SOURCE_FIELDS:
|
|
1318
|
+
raise ValueError("malformed row indices violate the closed schema")
|
|
1319
|
+
for name in sorted(_SOURCE_FIELDS):
|
|
1320
|
+
indices = malformed[name]
|
|
1321
|
+
if (
|
|
1322
|
+
type(indices) is not list
|
|
1323
|
+
or any(type(index) is not int or index < 0 for index in indices)
|
|
1324
|
+
or indices != sorted(set(indices))
|
|
1325
|
+
or any(index >= source_counts[name] for index in indices)
|
|
1326
|
+
):
|
|
1327
|
+
raise ValueError(f"malformed_row_indices.{name} is invalid")
|
|
1328
|
+
|
|
1329
|
+
if frozenset(defects) != _DEFECT_FIELDS:
|
|
1330
|
+
raise ValueError("provider-attempt join defects violate the closed schema")
|
|
1331
|
+
normalized_defects: dict[str, list[str]] = {}
|
|
1332
|
+
for name in sorted(_DEFECT_ATTEMPT_ID_FIELDS):
|
|
1333
|
+
normalized_defects[name] = exact_identity_list(
|
|
1334
|
+
defects[name],
|
|
1335
|
+
label=f"defects.{name}",
|
|
1336
|
+
constructor=ProviderAttemptId,
|
|
1337
|
+
)
|
|
1338
|
+
for name in sorted(_DEFECT_CALL_ID_FIELDS):
|
|
1339
|
+
normalized_defects[name] = exact_identity_list(
|
|
1340
|
+
defects[name],
|
|
1341
|
+
label=f"defects.{name}",
|
|
1342
|
+
constructor=LLMCallId,
|
|
1343
|
+
)
|
|
1344
|
+
|
|
1345
|
+
if frozenset(invariants) != _INVARIANT_FIELDS or any(
|
|
1346
|
+
type(item) is not bool for item in invariants.values()
|
|
1347
|
+
):
|
|
1348
|
+
raise ValueError("provider-attempt join invariants violate the closed schema")
|
|
1349
|
+
|
|
1350
|
+
dispatched = attempt_sets["dispatched"]
|
|
1351
|
+
outcomes = attempt_sets["terminal_outcomes"]
|
|
1352
|
+
provider_evidence = attempt_sets["provider_status_response_or_progress"]
|
|
1353
|
+
pretransport = attempt_sets["explicit_pre_transport_failures"]
|
|
1354
|
+
if not progress_set.issubset(provider_evidence) or not provider_evidence.issubset(
|
|
1355
|
+
outcomes | progress_set
|
|
1356
|
+
):
|
|
1357
|
+
raise ValueError("provider evidence identity summary is inconsistent")
|
|
1358
|
+
if any(
|
|
1359
|
+
value not in dispatched
|
|
1360
|
+
for value in normalized_defects["missing_logical_request_attempt_ids"]
|
|
1361
|
+
+ normalized_defects["logical_physical_mismatch_attempt_ids"]
|
|
1362
|
+
+ normalized_defects["framework_version_mismatch_attempt_ids"]
|
|
1363
|
+
+ normalized_defects["transport_settings_mismatch_attempt_ids"]
|
|
1364
|
+
):
|
|
1365
|
+
raise ValueError("outbound defect names a non-dispatched attempt")
|
|
1366
|
+
if any(
|
|
1367
|
+
value not in progress_set
|
|
1368
|
+
for value in normalized_defects["progress_duplicate_sequence_attempt_ids"]
|
|
1369
|
+
+ normalized_defects["progress_noncontiguous_sequence_attempt_ids"]
|
|
1370
|
+
):
|
|
1371
|
+
raise ValueError("progress sequence defect names a non-progress attempt")
|
|
1372
|
+
if any(
|
|
1373
|
+
value not in shared_ids
|
|
1374
|
+
for value in normalized_defects["call_id_mismatch_attempt_ids"]
|
|
1375
|
+
):
|
|
1376
|
+
raise ValueError("call mismatch names an unknown attempt")
|
|
1377
|
+
if any(
|
|
1378
|
+
value not in logical_call_ids
|
|
1379
|
+
for value in normalized_defects["duplicate_logical_request_call_ids"]
|
|
1380
|
+
):
|
|
1381
|
+
raise ValueError("duplicate logical request names an unknown call")
|
|
1382
|
+
|
|
1383
|
+
duplicate_progress = sorted(
|
|
1384
|
+
attempt_id
|
|
1385
|
+
for attempt_id, sequences in normalized_sequences.items()
|
|
1386
|
+
if len(sequences) != len(set(sequences))
|
|
1387
|
+
)
|
|
1388
|
+
noncontiguous_progress = sorted(
|
|
1389
|
+
attempt_id
|
|
1390
|
+
for attempt_id, sequences in normalized_sequences.items()
|
|
1391
|
+
if sequences != list(range(1, len(sequences) + 1))
|
|
1392
|
+
)
|
|
1393
|
+
call_mismatches = sorted(
|
|
1394
|
+
attempt_id
|
|
1395
|
+
for attempt_id, call_ids in normalized_call_summary.items()
|
|
1396
|
+
if len(call_ids) > 1
|
|
1397
|
+
)
|
|
1398
|
+
affirmative_pretransport = pretransport - provider_evidence
|
|
1399
|
+
derived_defects = {
|
|
1400
|
+
"missing_manifest_attempt_ids": sorted(
|
|
1401
|
+
(outcomes - affirmative_pretransport) - dispatched
|
|
1402
|
+
),
|
|
1403
|
+
"orphan_manifest_attempt_ids": sorted(dispatched - outcomes),
|
|
1404
|
+
"progress_without_manifest_attempt_ids": sorted(progress_set - dispatched),
|
|
1405
|
+
"progress_without_outcome_attempt_ids": sorted(progress_set - outcomes),
|
|
1406
|
+
"progress_duplicate_sequence_attempt_ids": duplicate_progress,
|
|
1407
|
+
"progress_noncontiguous_sequence_attempt_ids": noncontiguous_progress,
|
|
1408
|
+
"provider_evidence_without_manifest_attempt_ids": sorted(
|
|
1409
|
+
provider_evidence - dispatched
|
|
1410
|
+
),
|
|
1411
|
+
"pre_transport_with_manifest_attempt_ids": sorted(pretransport & dispatched),
|
|
1412
|
+
"pre_transport_with_provider_evidence_attempt_ids": sorted(
|
|
1413
|
+
pretransport & provider_evidence
|
|
1414
|
+
),
|
|
1415
|
+
"pre_transport_without_outcome_attempt_ids": sorted(pretransport - outcomes),
|
|
1416
|
+
"call_id_mismatch_attempt_ids": call_mismatches,
|
|
1417
|
+
}
|
|
1418
|
+
if any(
|
|
1419
|
+
normalized_defects[name] != expected
|
|
1420
|
+
for name, expected in derived_defects.items()
|
|
1421
|
+
):
|
|
1422
|
+
raise ValueError("provider-attempt relationship defects are inconsistent")
|
|
1423
|
+
|
|
1424
|
+
expected_invariants = {
|
|
1425
|
+
"logical_request_exactly_once_per_dispatched_attempt": (
|
|
1426
|
+
not normalized_defects["duplicate_logical_request_call_ids"]
|
|
1427
|
+
and not normalized_defects["missing_logical_request_attempt_ids"]
|
|
1428
|
+
),
|
|
1429
|
+
"logical_physical_request_fields_exact": not normalized_defects[
|
|
1430
|
+
"logical_physical_mismatch_attempt_ids"
|
|
1431
|
+
],
|
|
1432
|
+
"framework_versions_join_qualification_exact": not normalized_defects[
|
|
1433
|
+
"framework_version_mismatch_attempt_ids"
|
|
1434
|
+
],
|
|
1435
|
+
"transport_settings_join_selected_profile_exact": not normalized_defects[
|
|
1436
|
+
"transport_settings_mismatch_attempt_ids"
|
|
1437
|
+
],
|
|
1438
|
+
"manifest_exactly_once_per_dispatched_attempt": not normalized_defects[
|
|
1439
|
+
"duplicate_outbound_manifest_attempt_ids"
|
|
1440
|
+
],
|
|
1441
|
+
"outcome_attempt_identity_exactly_once": not normalized_defects[
|
|
1442
|
+
"duplicate_outcome_attempt_ids"
|
|
1443
|
+
],
|
|
1444
|
+
"every_physical_outcome_attempt_accounted_for": not normalized_defects[
|
|
1445
|
+
"missing_manifest_attempt_ids"
|
|
1446
|
+
],
|
|
1447
|
+
"every_dispatched_attempt_has_terminal_outcome": not normalized_defects[
|
|
1448
|
+
"orphan_manifest_attempt_ids"
|
|
1449
|
+
],
|
|
1450
|
+
"provider_evidence_always_has_manifest": not normalized_defects[
|
|
1451
|
+
"provider_evidence_without_manifest_attempt_ids"
|
|
1452
|
+
],
|
|
1453
|
+
"progress_joins_manifest_and_outcome": (
|
|
1454
|
+
not normalized_defects["progress_without_manifest_attempt_ids"]
|
|
1455
|
+
and not normalized_defects["progress_without_outcome_attempt_ids"]
|
|
1456
|
+
),
|
|
1457
|
+
"progress_sequence_unique_and_contiguous": (
|
|
1458
|
+
not normalized_defects["progress_duplicate_sequence_attempt_ids"]
|
|
1459
|
+
and not normalized_defects["progress_noncontiguous_sequence_attempt_ids"]
|
|
1460
|
+
),
|
|
1461
|
+
"explicit_pre_transport_evidence_consistent": (
|
|
1462
|
+
not normalized_defects["duplicate_pre_transport_attempt_ids"]
|
|
1463
|
+
and not normalized_defects["pre_transport_with_manifest_attempt_ids"]
|
|
1464
|
+
and not normalized_defects[
|
|
1465
|
+
"pre_transport_with_provider_evidence_attempt_ids"
|
|
1466
|
+
]
|
|
1467
|
+
and not normalized_defects["pre_transport_without_outcome_attempt_ids"]
|
|
1468
|
+
),
|
|
1469
|
+
"explicit_pre_transport_is_affirmative_not_inferred": True,
|
|
1470
|
+
"call_id_join_exact": not normalized_defects["call_id_mismatch_attempt_ids"],
|
|
1471
|
+
# The receipt validator is itself closed-schema and the builder copies
|
|
1472
|
+
# only the validated identity/counter projections authenticated above.
|
|
1473
|
+
"raw_provider_content_persisted": False,
|
|
1474
|
+
}
|
|
1475
|
+
if invariants != expected_invariants:
|
|
1476
|
+
raise ValueError("provider-attempt join invariant projection is inconsistent")
|
|
1477
|
+
|
|
1478
|
+
malformed_present = any(malformed[name] for name in _SOURCE_FIELDS)
|
|
1479
|
+
defects_present = any(normalized_defects[name] for name in _DEFECT_FIELDS)
|
|
1480
|
+
expected_join_valid = not malformed_present and not defects_present
|
|
1481
|
+
if record["join_valid"] is not expected_join_valid:
|
|
1482
|
+
raise ValueError("provider-attempt join_valid contradicts its defects")
|
|
1483
|
+
if expected_join_valid:
|
|
1484
|
+
if expected_frameworks is None or expected_settings is None:
|
|
1485
|
+
# Empty runs may be finalized before qualification/route construction.
|
|
1486
|
+
if dispatched:
|
|
1487
|
+
raise ValueError(
|
|
1488
|
+
"a green dispatched join lacks environment expectations"
|
|
1489
|
+
)
|
|
1490
|
+
if source_counts["outbound_manifests"] != len(dispatched):
|
|
1491
|
+
raise ValueError("green join outbound count is inconsistent")
|
|
1492
|
+
if source_counts["outcome_attempts_with_physical_ids"] != len(outcomes):
|
|
1493
|
+
raise ValueError("green join outcome-attempt count is inconsistent")
|
|
1494
|
+
if source_counts["logical_requests"] != len(logical_call_ids):
|
|
1495
|
+
raise ValueError("green join logical-request count is inconsistent")
|
|
1496
|
+
if source_counts["progress_rows"] != sum(
|
|
1497
|
+
len(sequences) for sequences in normalized_sequences.values()
|
|
1498
|
+
):
|
|
1499
|
+
raise ValueError("green join progress-row count is inconsistent")
|
|
1500
|
+
if source_counts["explicit_pre_transport_failures"] != len(pretransport):
|
|
1501
|
+
raise ValueError("green join pre-transport count is inconsistent")
|
|
1502
|
+
|
|
1503
|
+
supplied = _require_sha256(
|
|
1504
|
+
record["join_receipt_sha256"],
|
|
1505
|
+
label="join_receipt_sha256",
|
|
1506
|
+
)
|
|
1507
|
+
authenticated = dict(record)
|
|
1508
|
+
del authenticated["join_receipt_sha256"]
|
|
1509
|
+
if supplied != _domain_sha256(_JOIN_DOMAIN, authenticated):
|
|
1510
|
+
raise ValueError("provider-attempt terminal join hash is invalid")
|
|
1511
|
+
return record
|
|
1512
|
+
|
|
1513
|
+
|
|
1514
|
+
__all__ = [
|
|
1515
|
+
"PRE_TRANSPORT_FAILURE_EVIDENCE_SCHEMA_VERSION",
|
|
1516
|
+
"PROVIDER_ATTEMPT_TERMINAL_JOIN_CONTRACT_ID",
|
|
1517
|
+
"PROVIDER_ATTEMPT_TERMINAL_JOIN_SCHEMA_VERSION",
|
|
1518
|
+
"build_provider_attempt_terminal_join_receipt",
|
|
1519
|
+
"explicit_pre_transport_failure_evidence_record",
|
|
1520
|
+
"validate_explicit_pre_transport_failure_evidence_record",
|
|
1521
|
+
"validate_provider_attempt_terminal_join_receipt",
|
|
1522
|
+
"validate_structured_generation_outcome_record",
|
|
1523
|
+
]
|