Repository navigation
refactor(decision-engine): strip Part 1 — advisory-only engine as an independent module - #204
Merged
Merged
Conversation
…t/decision_source R1: chat/binding.rs now owns ChatProviderBinding, ChatAdmissionGuard, ChatOperatorSpawn, ChatSourceReceipt, ChatAdmissionMode, ChatTurnBinding (with TurnSourceProof), CapturedChatTrace, ChatDecision, the persistence and resume-failure replies and the test-mock mailbox fixture. chat/decision_source.rs keeps only the advice adapter: issue_decision (with analyze_advisory), decision_advice and decision_routing, until R9. R2: the admission_failure_tests module moves to chat/binding/tests.rs and chat/binding/tests/ with names and bodies unchanged; the advisory test advisory_decide_mode_projects_prediction_and_lazily_opens_store stays with the adapter. Importers and architecture path strings are retargeted. R3: the adapter calls only the advisory method set.
…homes, Full autonomy without permission limits
Requirements done: R4, R5, R6, R7, R8 (shared contract types, capability
policy, runtime key, logical clock and scanner helpers in neutral homes),
R55 (effective engine backend), R11 (AdmissionProbe / HardGatesProbe),
R60 (TurnRuntimeContext, AdmissionFactsV1, VerifiedResumeEvidenceV1),
R9 (free-standing DecisionAdvisory, one prediction-free turn opening,
budget-charged analysis, V-17 execution-owned resume check), R10
(effective telemetry cap, advisory driver tests), R51 (Full autonomy has
no permission limits), R58 (supervised working-root approval test) and
the controller ruling R9-DEAD (the legacy prediction/selection pipeline
is deleted with its exclusive helpers; nothing is hidden behind
cfg(test) or allow). CHANGELOG BREAKING (operators) lines for R9 and R51.
R9-DEAD cascade: causal_tree/{decision_rehearsal,exploration}.rs and
turn_decision/latency_snapshot.rs deleted; decision_select keeps only
Selection::Commit, decision_score keeps SCORER_VERSION + CandidateScore;
EngineDecision without audit trace, scores pipeline or call fingerprints;
CandidateSet without discoverable families or approval-only lists;
ObservedStepKind::Retrieve, HopLineage::After and the observed artifacts
removed (canonical and projection JSON still emit "artifacts":[] and the
record's empty artifact sequences byte-identically); the causal_events
admission deferral machinery, the hop's TurnAccounting, the selected
memory formatters, the progress diagnostic and the clock stall hook are
deleted.
New tests: agent::turn_tests::engine_switch::{engine_on_and_off_open_identical_turns,
tight_budget_skips_analysis_and_never_refuses_the_request},
runtime::turn_decision::tests::exact_call_approval::historical_resume_survives_prediction_free_opening,
runtime::decision_advisory::tests::{decision_advisory_runs_without_turn_decision_service,
forced_drop_is_reported_only_for_its_workspace, late_advisory_drain_warns_exactly_once,
pre_mode_status_reports_effective_cap_zero},
tools::execution::tests::full_autonomy_has_no_permission_limits,
runtime::turn_decision::owner_filesystem::working_root_tests::supervised_working_root_approval_executes_once_and_denial_never_executes,
causal_tree::admission_probe::tests::{hard_gates_probe_reproduces_pre_separation_candidate_sets,
exact_call_scope_is_independent_of_approval_outcome},
config::schema::decision_engine_config_tests::{effective_backend_prefers_explicit_table_over_differing_legacy,
explicit_empty_engine_backend_uses_defaults_not_legacy, legacy_only_backend_is_copied_into_the_engine}.
Deleted or trimmed tests (file: test (reason)):
src/causal_tree/decision_rehearsal.rs: write_and_effectively_write_candidates_never_call_probes
src/causal_tree/decision_rehearsal.rs: serial_slow_probes_share_one_deadline
src/causal_tree/decision_rehearsal.rs: stale_catalog_and_probe_error_never_raise_score
src/causal_tree/decision_rehearsal.rs: duplicate_candidate_batch_calls_no_port
src/causal_tree/decision_rehearsal.rs: partial_required_availability_is_adverse
src/causal_tree/exploration.rs: exploration_forbidden_for_authority_and_hidden_effects
src/causal_tree/exploration.rs: sub_draw_resolution_rate_creates_no_false_propensity
src/causal_tree/decision_select.rs: r3_textless_surface_closes_every_abstention_with_refuse
src/causal_tree/decision_select.rs: r3_below_bar_destructive_asks_and_approved_exact_resume_commits
src/causal_tree/decision_select.rs: a_plain_turn_evidence_value_counts_as_sufficient
src/causal_tree/decision_select.rs: low_utility_tool_choice_gets_one_gated_metadata_recovery
src/causal_tree/decision_select.rs: read_only_near_tie_explores_with_recorded_propensities
src/causal_tree/decision_select.rs: near_tie_with_a_write_candidate_keeps_abstention
src/causal_tree/decision_select.rs: zero_legal_choice_mass_abstains_even_with_high_utility
src/causal_tree/decision_select.rs: equal_utility_uses_stable_candidate_id_tiebreak
src/causal_tree/decision_select.rs: low_choice_confidence_abstains_before_read_tool_commit
src/causal_tree/decision_select.rs: completed_discovery_settles_only_the_targetless_answer
src/causal_tree/decision_select.rs: stale_answer_recovers_only_through_a_passed_retrieval
src/causal_tree/decision_select.rs: missing_target_discovery_matches_supported_family_and_passed_candidate
src/causal_tree/decision_select.rs: missing_exact_direct_candidate_does_not_commit
src/causal_tree/decision_select.rs: exact_read_discovers_or_executes_without_a_redundant_retrieval
src/causal_tree/decision_select.rs: exact_current_tool_cannot_publish_below_the_execution_threshold
src/causal_tree/decision_select.rs: exact_source_configured_delegate_cannot_publish_below_threshold_and_margin
src/causal_tree/decision_select.rs: approval_requires_current_g4_only_proof_and_passed_terminal
src/causal_tree/decision_select.rs: multiple_approval_scopes_select_one_stable_verified_scope
src/causal_tree/decision_select.rs: confidence_fallback_requires_an_admitted_text_terminal
src/causal_tree/decision_select.rs: no_legal_path_needs_a_current_terminal_gate_result
src/causal_tree/decision_select.rs: no_legal_path_approval_keeps_its_verified_scope
src/causal_tree/decision_select.rs: deterministic_commit_retains_unit_propensity_without_exploration_distribution
src/causal_tree/decision_select.rs: confidence_abstention_answers_or_clarifies_on_every_surface
src/causal_tree/decision_select.rs: exact_tool_still_requires_every_execution_bar_and_cannot_repeat_failure
src/causal_tree/decision_score.rs: scorer_defaults_have_valid_positive_budget
src/causal_tree/decision_score.rs: risk_and_uncertainty_only_lower_execution_utility
src/causal_tree/decision_score.rs: execution_latency_still_lowers_the_score
src/causal_tree/decision_score.rs: each_risk_and_uncertainty_coordinate_lowers_an_interior_score
src/causal_tree/decision_score.rs: scorer_rejects_nan_and_invalid_weight_budget
src/causal_tree/decision_score.rs: score_expected_and_distribution_uncertainty_are_normalized
src/causal_tree/decision_score.rs: trusted_risk_floor_covers_every_effect_class
src/causal_tree/decision_score.rs: validated_choice_confidence_is_kept_out_of_candidate_features
src/causal_tree/decision_score.rs: risk_and_uncertainty_are_score_monotone
src/causal_tree/decision_engine.rs: exact_skill_and_loader_are_one_operation_but_distinct_skills_are_not
src/causal_tree/decision_engine.rs: another_named_effect_does_not_force_context_retrieval_before_the_only_named_read
src/causal_tree/decision_engine.rs: validated_audit_trace_keeps_numeric_scores_and_forced_codes_without_state_text
src/causal_tree/decision_engine.rs: outgoing_child_is_new_strict_subset_for_root_and_nested_worker
src/causal_tree/decision_engine.rs: outgoing_child_rejects_excluded_catalog_reference
src/causal_tree/decision_engine.rs: post_rehearsal_denial_cannot_be_restored_by_pre_commit
src/causal_tree/decision_engine.rs: approval_scope_cannot_be_restored_or_rebound
src/causal_tree/decision_engine.rs: exhausted_prediction_has_no_working_choice_mass
src/causal_tree/decision_engine.rs: selected_read_issuers_reject_over_bound_exact_source_queries
src/causal_tree/decision_engine.rs: selected_discovery_issues_only_pinned_visible_allowed_refs
src/causal_tree/decision_engine.rs: expired_turn_skips_backend_and_returns_a_typed_terminal
src/causal_tree/decision_engine/approval_selection_tests.rs: exact_approval_required_tool_requests_approval_instead_of_answering
src/causal_tree/decision_engine/approval_selection_tests.rs: exact_mention_without_call_fingerprint_does_not_answer
src/causal_tree/decision_engine/approval_selection_tests.rs: approval_only_tool_that_is_not_named_still_answers
src/causal_tree/decision_engine/approval_selection_tests.rs: unavailable_or_denied_approval_yields_no_request
src/causal_tree/decision_engine/approval_selection_tests.rs: exact_file_write_stays_on_the_approval_deferred_terminal_path
src/causal_tree/decision_engine/deadline_keep_tests.rs: deadline_keeps_commit_only_after_complete_scoring
src/causal_tree/decision_engine/deadline_keep_tests.rs: r4_deadline_between_scoring_and_selection_closes_without_a_model_answer
src/causal_tree/decision_engine/deadline_keep_tests.rs: o9_long_paths_and_output_contract_reaches_the_model
src/causal_tree/decision_engine/deadline_keep_tests.rs: o5_exact_reply_uses_model_answer
src/causal_tree/decision_engine/deadline_keep_tests.rs: o14_negations_and_ten_paths_do_not_refuse
src/causal_tree/decision_engine/deadline_keep_tests.rs: a_shell_explanation_never_executes_the_quoted_command
src/causal_tree/decision_engine/deadline_keep_tests.rs: failed_tool_cannot_execute_on_the_next_hop
src/causal_tree/decision_engine/deadline_keep_tests.rs: default_destructive_tool_cannot_reach_commit_bar
src/causal_tree/decision_engine/deadline_keep_tests.rs: default_credential_tool_cannot_reach_commit_bar
src/causal_tree/decision_engine/deadline_keep_tests.rs: r3_exact_read_selection_reason_preserves_the_abstention_column
src/causal_tree/decision_engine/resume_availability_tests.rs: resume_availability_is_single_current_reference_and_never_catalog_exposure
src/causal_tree/decision_engine/original_observation/tests.rs: actual_compiler_object_reaches_backend_and_scores_join_outcome
src/causal_tree/decision_engine/original_observation/tests.rs: missing_duplicate_and_overflow_observations_are_not_accepted
src/causal_tree/decision_engine/original_observation/tests.rs: original_request_score_and_source_mutations_are_rejected
src/causal_tree/decision_engine/original_observation/tests.rs: mismatched_model_cannot_create_original_observation
src/causal_tree/decision_engine/original_observation/material.rs: idle_material_has_no_fabricated_request_or_wire
src/causal_tree/decision_engine/original_observation/material.rs: unbound_send_cannot_be_certified_as_idle
src/causal_tree/decision_engine/original_observation/material.rs: oversized_actual_body_invalidates_capture
src/causal_tree/decision_engine/original_observation/material.rs: cancelled_scope_does_not_leak_into_next_capture
src/decision/factory.rs: only_all_semantic_validation_failures_close_the_configured_decision_path
src/causal_tree/outcome.rs: forced_choice_stays_out_of_calibration_and_builtin_shadow
src/runtime/turn_decision/tests/selected_memory.rs: selected_memory_service_rejects_foreign_turn_and_keeps_direct_core_after_read
src/runtime/turn_decision/tests/selected_memory.rs: builtin_agent_discovery_runs_a_bounded_dependent_hop
src/runtime/turn_decision/tests/selected_memory.rs: selected_discovery_is_source_bound_and_never_dispatches_a_tool
src/runtime/turn_decision/tests/selection_probes.rs: selected_session_projection_keeps_kind_and_distrusts_event_identity
src/runtime/turn_decision/tests/selection_probes.rs: selected_memory_artifacts_redact_before_projection_cut_and_distrust_row_metadata
src/runtime/turn_decision/tests/selection_probes.rs: selected_execute_retains_exact_gated_refs_without_dispatch
src/runtime/turn_decision/tests/performance.rs: actual_builtin_fixture_characterization
src/runtime/turn_decision/tests/performance/mcp_inventory.rs: owned_mcp_inventory_catalog_growth_profile
src/runtime/turn_decision/tests/performance/model_binding.rs: actual_compiler_binds_decision_model_before_real_http
src/runtime/turn_decision/tests/performance/model_allowlist.rs: owned_model_allowlist_catalog_growth_profile
src/runtime/turn_decision/tests/performance/phases.rs: actual_builtin_phase_characterization
src/runtime/turn_decision/tests/performance/model_binding/original_service_wire.rs: actual_configured_service_original_wire_ok
src/runtime/turn_decision/tests/performance/model_binding/original_service_wire.rs: actual_configured_service_original_wire_slow
src/runtime/turn_decision/tests/agent_decision.rs: agent_decision_cancellation_stops_before_backend_or_selected_read agent_decision_phases_follow_source_lineage_without_claiming_commit selected_retrieve_redecides_only_after_material_evidence_and_honors_hop_cap memory_rehearsal_rejects_wrong_principal_or_query_before_backend pinned_rehearsal_counts_only_visible_exact_refs_and_skill_family enabled_engine_without_recording_runs_generator_gates_and_builtin agent_initial_decision_respects_configured_four_kib_wire_limit r3_o9_o14_and_quoted_shell_fallbacks_publish_no_execution_refs clarify_without_gate_passed_answer_is_typed_refusal
REWRITTEN agent_decision.rs: record_builder_distinguishes_local_terminal_from_failed_compiled_request -> record_builder_records_the_prediction_free_opening_and_rejects_a_broken_chain (compiled-request half had no subject)
src/agent/terminal/replay.rs: prepared_replay_reads_pre_switch_request_approval_effect_from_recorded_hop (live hop can no longer select RequestApproval)
src/agent/turn_tests/engine_switch.rs: recorded_pre_switch_directive_replays_unchanged (RecordedDirective::RequestApproval unconstructible after R9)
src/causal_tree/directive.rs: approval_scope_uses_pinned_decision_and_call_digest (+ fixture recorded_request_approval_hop)
src/causal_tree/admission_probe/legacy_generator_tests.rs: supervised_generic_write_without_arguments_reports_scope_unavailable (NoLegalReason field removed); delegate_without_an_action_scope_cannot_offer_approval and unrelated_user_text_preserves_candidates_and_exact_name_adds_only_its_pair trimmed (terminal-only, resume-target, extend_selected, evidence_fingerprint halves)
tests/architecture_boundaries/decision_terminals.rs: recovery_cannot_publish_an_executable_tool, confidence_terminals_include_answer_and_cli_clarification (+ scanner_probes mutation_proof_recovery_execution, mutation_proof_confidence_terminal; decision-clock probe retargeted to turn_engine)
src/chat/binding/tests/operator_accounting.rs: actual_operator_task_decision_accounts_physical_send_and_drains, restored_operator_process_decision_accounts_physical_send_without_os_spawn (opening no longer sends a prediction)
src/agent/turn_tests/entry.rs: cli_readonly_shell_request_is_refused_by_policy_before_the_model, cli_turn_exact_named_mcp_write_without_review_ingress_closes_instead_of_answering (hop refusal/close selections)
src/chat/dispatcher/turn_characterization_tests.rs: enabled_interactive_backend_failure_publishes_provider_reply (hop Clarify abstention)
src/agent/turn_tests/engine_switch.rs: enabled_builtin_low_confidence_run_turn_publishes_plain_answer (engine-on refusal/abstention path; replaced by engine_on_and_off_open_identical_turns)
src/causal_tree/questions.rs: fixed_terminals_remain_choices_without_unused_predictions_on_the_wire (scorer extraction removed)
src/causal_tree/store/tests/mod.rs: capability_latency_uses_only_complete_single_call_owner_and_generation_samples, old_read_only_store_keeps_default_latency_without_a_tie_order_index (hop latency reader removed); src/runtime/turn_decision/tests/recorded_chain.rs: enabled_agent_service_records_only_a_successful_decision_chain trimmed (observed_capability_latency half)
src/runtime/turn_decision/latency_snapshot.rs: a_completed_latency_snapshot_preserves_the_scoped_samples, a_blocked_latency_snapshot_falls_back_without_waiting_for_the_read
src/causal_tree/state.rs: the_hop_loop_stops_when_a_hop_found_no_new_evidence (evidence_fingerprint removed); exact_calls test trimmed
src/runtime/turn_decision/tests/catalog_drift.rs: catalog_drift_after_selected_read_discards_retrieved_work_chain (selected read)
src/runtime/turn_decision/tests/discovery_surface.rs: non_english_discovery_reaches_admitted_family_without_full_registry, search_hits_are_admitted_for_the_next_request_through_the_same_gates, discovered_tools_are_capped_per_turn_and_admitted_in_search_rank_order, production_discovery_selects_a_skill_and_loads_its_body_only_on_execution (hop-selected Execute via probe backend)
src/runtime/turn_decision/tests/enabled_service.rs: validated_usage_and_provider_request_id_reach_the_durable_decision, cancellation_while_backend_pending_admits_no_decision_or_outcome (opening no longer calls the backend)
src/runtime/turn_decision/tests/catalog_drift.rs: catalog_drift_closes_with_fresh_unlinked_terminal_and_no_dispatch, cancellation_during_backend_and_catalog_drift_wins_before_recovery (hop backend/terminal recovery); ledger_probe.rs fixture file removed
src/runtime/causal_events/deferral/tests.rs: deferred_telemetry_remains_observable_and_concurrent_drains_preserve_order_with_live_guards (deferral machinery removed)
src/runtime/causal_events/deferral/independence_tests.rs: overlapping_admissions_release_independently_and_controls_bypass_live_deferral, a_live_guard_cannot_extend_its_deadline_and_readmission_releases_old_events (deferral machinery removed)
src/runtime/turn_decision/accounting/tests.rs: admission_releases_phase_writes_while_its_physical_accounting_is_retained (hop accounting and phase deferral removed)
src/causal_tree/state.rs: lineage_and_time_are_not_material, new_inputs_are_material, the_hop_lineage_pairs_hop_and_prior, debug_output_carries_no_private_text trimmed (later-hop lineage and artifact cells; the fixture step is now a Tool step without artifacts)
src/causal_tree/state/canonical_tests.rs: canonical_bytes_and_keyed_digests_match_independent_owned_oracle and canonical_preserves_observation_and_capability_sequence_order trimmed (artifact and later-hop cells); canonical_distinguishes_mixed_delivery_empty_optionals_and_maximum_hop -> canonical_distinguishes_mixed_delivery_and_empty_optionals (maximum hop removed); the empty-state golden bytes are unchanged
src/causal_tree/projection.rs: the_hop_and_the_prior_decision_are_projected_together trimmed to hop 0 (+ "artifacts":[]); any_state proptest strategy and sentinels_never_survive_the_projection lose the artifact and hop inputs
src/causal_tree/questions.rs: byte_budget_shrinks_summaries_without_changing_questions_or_candidates (no artifact summaries left to shrink)
src/causal_tree/questions/tests/ownership.rs: compiler_multiple_shrinks_budget_and_empty_summary_match_original -> compiler_budget_and_invalid_model_match_original (artifact shrink half removed)
src/causal_tree/admission_probe/legacy_generator_tests.rs: approval_only assertions now read the proposed RequestApproval candidates (approval_only_path_carries_concrete_operation_scope no longer sees op ids)
src/agent/memory_loader.rs: selected_memory_formatter_runs_only_for_admitted_memory_summaries, selected_memory_formatter_rejects_other_artifact_kinds_before_callback, selected_documents_do_not_enter_memory_formatter, selected_session_history_does_not_enter_memory_formatter, default_selected_context_preserves_evidence_types_and_memory_text, selected_memory_formatter_failure_is_not_replaced_with_unscoped_recall (selected-read artifacts removed)
src/agent/turn_tests/admission.rs: configured_mechanics_on_wall_clock_expires_when_decision_http_stalls_past_budget (opening no longer calls the decision endpoint)
src/agent/turn_tests/engine_surface.rs: a_spawned_sub_agent_inherits_the_parent_channels_tool_exclusions (required a prediction-committed parent Delegate); run_tool_call_loop_executes_read_only_tools_with_bounded_parallelism loses the hop progress diagnostic
src/skills/lifecycle/tests/acceptance/scenario_{a,b,e}.rs: a_wall_stall_past_the_latency_budget_still_answers; scenario_a.rs: advancing_the_logical_latency_budget_degrades_clarify_to_plain_answer (hop clock stall and Clarify degradation removed)
Unused test fixtures removed with them: AdmittedTurn::{with_enabled_builtin_model_and_mcp, ordinary_controlled_channel}, chat::binding::tests::recorded_plan_source, TurnDecisionContext::ordinary_fixture_prediction_verified, TurnDecisionService::install_ordinary_publication_fixture, McpTool test invocation counter, logical_clock apply_test_stall/arm_wall_stall/arm_logical_advance, turn_decision::progress_diagnostic.
…Probe
R12: AdmissionProbe gains filters(); HardGatesProbe returns true and keeps
every legacy branch unchanged. New AdvisoryProbe wraps the execution probe
the driver builds and returns false: at each appendix A site (exact mention,
named-file group, unbound approval, discovery eligibility, initial apply and
approval synthesis, final apply, no-legal-path, family G9/G2 prefilters,
family selection) admission only annotates; structural filters, order and
the candidate limit stay.
R13: DecisionAdvisory generates the analysed set with AdvisoryProbe over the
locally built HardGatesProbe (scoped so no non-Sync probe is held across the
prediction await). causal_adapter unchanged.
R14 tests (written, not run): causal_tree::admission_probe::tests::
{advisory_probe_annotates_blockers_without_filtering,
advisory_ordering_and_limits_match_structural_order};
hard_gates_probe_reproduces_pre_separation_candidate_sets extended to the
ten appendix B fixtures; runtime::decision_advisory::tests::
engine_driver_generates_with_advisory_probe.
select_family_candidate is pub(super) so the probe tests reach the G2
surface prefilter: a surface-excluded entry is hidden by the view itself,
so generate() never hands it to family selection.
R15/R52: DecisionId -> security/decision_id.rs; the neutral turn scope (SideEffectMode, TurnSurfaceKind, ConstraintCode, TurnBudgets, DeliveryConstraints, TrustedParts, TrustedState, RouterHistoryReadBinding, exact_calls, model_admission) and FRESH/STALE_ARTIFACT_MS, MODEL_VERSION -> tools/capability/turn_state.rs; causal_tree config -> config/schema/causal_tree.rs; decision_engine config -> config/schema/decision_engine.rs; ApprovalReviewAdapter (+ valid_projection) -> security/approval_ledger/review.rs (causal_tree/approval_collection.rs deleted); bounded_artifact_summary and the shared text redactor -> memory/artifact_summary.rs. R16: decisions.db store, store/, store_schema, store_preparation -> runtime/decision_journal/ (open_store only; the plane factory-key helper load_key moves to causal_tree/admin.rs, its only user, so the journal does not import the engine). OutcomeRecord fields widened pub(super) -> pub(crate). Test-only open spy counts decisions.db opens. R17 + 05aS-HOME: decision/loopback.rs and decision/model_pin.rs -> providers/; decision::telemetry -> observability/causal_event.rs; attempt contract (sealed, AttemptBinding, DecisionAttemptAccounting, DecisionAttemptReceipt), DecisionUsage, BackendIdentity and the DecisionError classes -> cost/decision_attempt.rs (+ error.rs); BackendKind, BackendLocality, locality_of, configured_kind, configured_selection, ConfiguredSelection -> config/schema/causal_tree/backend_kind.rs. Old paths stay as forwarding `use` lines until Part 2. R18: tests/architecture_boundaries/decision_engine.rs shared_types_are_not_engine_owned + two planted probes. Scanners retargeted to the moved paths (decision_backend, causal_domain incl. journal scope, causal_policy, decision_seals, scanner_probes). Tests: NEW session_worker::runner::tests::authority:: historical_parent_missing_key_refuses_without_recreation; extended runtime::ingress_recovery::tests:: ingress_recovery_off_with_causal_tree_disabled_creates_no_key_or_store (populated legacy database + open spy). Relocated: the exact_calls canonical test -> causal_tree::state::exact_calls_tests; the credential_ref_for test -> config::schema::causal_tree::backend_kind::tests.
…ion_engine
R19, R20, R21 (amended by R9-DEAD). Moves only what is still live after 05a.
- R19: causal_tree/branch.rs (CandidateId, CausalCandidate, CandidateSpec,
Ns8 and their tests; nothing else remained in it) -> decision_engine/candidate.rs.
ScoringConfig stays in config/schema/causal_tree.rs.
- R20: provider_is_zero_price_exempt users import cost::estimate; the
runtime::turn_cost re-export is gone. RuntimeCostModel stays live (used by
the advisory driver and turn_decision/discovery/append.rs), so it moves with
CostEstimateSource, the test-only CapabilityCostModel/build_cost_model and
their tests to decision_engine/cost_model.rs; runtime/turn_cost.rs deleted.
DecisionTokenReservation + DecisionReserveUnavailable -> cost/estimate.rs.
- R21: src/decision/** -> decision_engine/prediction/** (whole backend stack);
causal_tree/{state(+state/), projection, questions(+questions/),
candidate_generator, decision_score} -> decision_engine/; the prediction half
of causal_tree/decision_engine.rs (PredictionPort, prediction_sealed,
derive_state) -> decision_engine/prediction_port.rs; AdmissionProbe,
ProbeOutcome, Admission, ProbeReport, GenerationError, AdvisoryProbe and
admission_probe::tests -> decision_engine/admission_probe.rs;
HardGatesProbe + legacy_generator_tests -> causal_tree/hard_gates_probe.rs.
EngineDecision and the rest of the legacy half stay in causal_tree.
- Forwarding: only causal_tree/candidate_generator.rs (re-exports CandidateSet
for directive/outcome/refusal/decision_engine; declared in causal_tree/mod.rs
as "forwarding bridge until Part 2"). The 05aS forwards that lived inside
src/decision (error, loopback, model_pin, telemetry, DecisionKey, KeyDomain,
budget/factory/backend/protocol/weights item re-exports) and in
causal_tree/state.rs are removed; every user imports the neutral home.
git ls-files src/decision is empty.
- Visibility edits only: generator helpers select_family_candidate, from_entry,
terminal, names_entry, exact_mention, exact_operation_mention,
contains_bounded are pub(crate) so the legacy generator tests can use them
from causal_tree::hard_gates_probe; cost_model items pub(super) ->
pub(crate).
- Retained legacy readers retargeted: agent/terminal/replay.rs,
tools/delegate_diagnostic.rs, gateway/api/sessions.rs tests.
runtime/turn_context.rs (R60, TurnRuntimeContext) imports
decision_engine::state::{ObservedState, RawRoutingInput}; R60 requires those
fields, the controller handoff names this move.
- Scanners retargeted (none retired): causal_domain (paths, allowlists, AG-01
and AG-24 scope extended to the moved engine files), causal_policy (AG-03
scope; providers::loopback allowed), decision_backend, decision_seals,
labels, panic_policy, scanner_probes.
- Relocated test paths: causal_tree::candidate_generator::tests::* ->
causal_tree::hard_gates_probe::legacy_generator_tests::*;
causal_tree::admission_probe::tests::* -> decision_engine::admission_probe::tests::*;
causal_tree::{state,projection,questions,branch}::* -> decision_engine::{state,
projection,questions,candidate}::*; decision::* -> decision_engine::prediction::*;
runtime::turn_cost::tests::* -> decision_engine::cost_model::tests::*.
- NEW test decision_engine::tests::analysis_is_identical_before_and_after_core_move.
…ate turn state
R22: runtime/turn_context.rs::TurnRuntimeContext now also owns the request
parameter capture (capture/prepared_main_parameters), the pinned provider
release catalog, the per-turn recursive allowance (issue/retire), the turn's
one AccountingScope and remaining_g6_tokens (TurnDecisionContext's accounting
field and remaining_g6_tokens are gone), and the pinned TrustedParts that
agent/terminal.rs validate_terminal_scope now reads instead of the last
decision hop. New TurnRuntimeHolder (publication-scoped, shared by every turn)
owns the recovery holder (recovery_scope; the RecoveryScope::prepare of
build_turn_decision_service runs through TurnRuntimeHolder::prepare, the other
four sites stay until Part 2), the recursive allowances, the ordinary child
money, the parent grant, recursive_money and spend_ceiling (SpendCeiling moved
with it). turn_decision/{request_parameters,recursive_budget}.rs deleted;
turn_decision/accounting.rs renamed to opening.rs. Child-scope carriage
(execution_context.child_scope/child_pin and the service's issued child scope)
moved to runtime/child_source/turn_scope.rs. Consumers retargeted:
agent/{turn_engine,terminal,terminal/recovery_commit,send_admission,entry}.rs,
chat/binding.rs, gateway/api/sessions.rs, runtime/{turn_cleanup,
ingress_recovery,turn_terminal}.rs.
R23: count_tokens_with_source, TokenMeasurement, TokenMeasurementSource, the
test-only count_tokens and the #[cfg(test)] token_timing hook moved to
tokens/count.rs (+ tokens/count/token_timing.rs). agent::context_budget and
decision_engine/render.rs import from crate::tokens.
R41: tests/architecture_boundaries/decision_engine.rs::
decision_engine_never_imports_agent_or_tool_execution (crate:: paths, grouped
imports and super:: chains to the crate root; skips #[cfg(test)] items,
tests.rs and *_tests.rs), eight planted probes in scanner_probes.rs.
Tests (written, not run): NEW runtime::turn_context::tests::
turn_context_carries_parameters_catalog_budgets_and_recursive_money_without_decision_service.
R22 acceptance: `accounting:` hits left in src/runtime/turn_decision* are
`decision_accounting::` module paths and `_accounting:` trait parameters of
test backends, not fields. Files that still name TurnDecisionContext or
TurnDecisionService outside runtime/turn_decision* (R26 holders or Part-2
deletions): agent/{embedded_turn,send_admission,terminal,terminal/replay,
turn_request}.rs, agent/turn_tests/{admission,engine_switch}.rs,
causal_tree/{mod,outcome}.rs, channels/{decision_runtime,decision_turn}.rs,
chat/{binding,decision_source}.rs (+ binding tests, persist_restart_tests),
gateway/{api/sessions,decision_runtime}.rs, runtime/{bootstrap,child_turn,
control_ladder,ingress_recovery,operator_spawn,turn_cleanup,turn_publication,
turn_terminal}.rs, runtime/child_source/operator_process/segments.rs,
runtime/ingress_recovery/auth_02_{2b,3}_tests.rs, session_worker/runner/run.rs,
tools/{delegate_diagnostic,surface_owner}.rs.
…R54)
Group 05a4 of the decision-engine strip, Part 1 (spec
REQ-DECISION-ENGINE-STRIP-P1 r3; rulings 05a4-DIR, 05a4-PROJ, R26-HOLDER).
R24 type homes (moves; use/path/visibility edits only)
- runtime/child_source/publication{,/operator,/ordinary_process}.rs:
ChildExecutionPolicy (built only by of_service), OrdinaryChildPublication,
OperatorChildPublication, OrdinaryProcessLaunch.
- router/turn_routing.rs: router_provider_binding, commit_training_owned.
- runtime/child_turn/segment_observation.rs: SegmentObservation,
validate_envelope, initial_observations.
- runtime/turn_terminal/settlement.rs: SettlementIssueToken,
VerifiedDirectiveApplication, terminal_settlement_ref, settlement_ref.
- runtime/turn_context.rs: TurnOriginMismatch, validate_agent_turn_origin,
validate_agent_retrieval_provenance, selected_custom_memory_read_scope,
AgentTurnKind, AgentDecisionError.
- DecisionApprovalView users import security::approval_ledger::pending.
R53 refusal types -> agent/refusal.rs (no causal_tree/engine import);
causal_tree/refusal.rs keeps classify + refine_budget (caller:
agent/terminal/replay.rs).
R54 historical approval -> security/approval_ledger/historical.rs
(historical API, PreparedDecisionResume, DecisionResumeRequest,
AdmittedDecisionResume + gate_evidence, admit_decision_resume,
ResumeEvidenceWitness, ClaimedDecisionResume, ExecutionResumeAdapter,
published_only), parameterised by HistoricalApprovalRuntime and ResumeTurn.
Both baseline ensure!s and claim_decision_grant are in the moved code.
R25 moved methods (body moved once; service methods delegate until Part 2)
- auxiliary_accounting, smart_group_accounting ->
runtime/decision_accounting/auxiliary.rs; caller channels/decision_turn.rs.
- is_run -> runtime::decision_accounting::is_run; callers
channels/decision_turn.rs, decision_accounting/auxiliary.rs (+ tests).
- owns_prepared_queues -> runtime::ingress_recovery; callers
ingress_recovery.rs, turn_cleanup.rs x3.
- reconcile_child_telemetry (+ ChildRecoveryState, child_recovery_gate,
ChildRecoveryReport) -> runtime/ingress_recovery/child_telemetry.rs;
caller ingress_recovery.rs.
- record_agent_silence -> runtime/turn_terminal/silence.rs; callers
agent/terminal.rs x2, agent/turn_engine.rs.
- capability_search_port, capability_search_spec, discovery_entries,
direct_discovery_ids, prepare/admit_discovered_tool,
admit_offered_discoveries, appended_execution_specs ->
tools/capability/search_tool/discovery_admission.rs (TurnSurfacePort).
- execution_specs, runtime_dependency_spec, prompt_skills,
admit_bound_specs -> tools/capability/execution_binding/specs.rs.
- terminal_execution_trace -> runtime/turn_terminal/execution_close.rs.
Callers of the discovery/spec/trace rows: agent/{turn_engine,
embedded_turn,entry,terminal}.rs, agent/terminal/{recovery_commit,
replay}.rs, channels/decision_turn.rs, chat/{binding,decision_source}.rs,
gateway/api/{runtime,sessions}.rs, gateway/mod.rs, tools/delegate.rs,
runtime/child_turn{,/segment_observation}.rs,
runtime/decision_accounting/auxiliary.rs, runtime/turn_terminal/silence.rs.
- resolve_agent_model, model_can_call_tools, agent_budget_snapshot,
send_limits, check_live_parity, effective_compaction,
effective_provider_capabilities, child_scope, credential_for_proof,
catalog_view, memory/execution/catalog/security/tool_tiering,
prompt_memory_loader -> runtime/turn_context/publication_scope.rs.
Callers: resolve_agent_model: channels/decision_turn.rs,
child_source/publication/operator.rs, child_turn.rs,
decision_accounting/auxiliary.rs, turn_decision/{discovery,owner_filesystem,
pending_approval}.rs, turn_publication/operator_process.rs;
model_can_call_tools: agent/{embedded_turn,terminal,turn_engine}.rs,
channels/decision_turn.rs, chat/binding.rs, gateway/api/sessions.rs,
child_turn.rs, session_worker/runner/run.rs,
tools/capability/{execution_binding/specs,search_tool/discovery_admission}.rs;
send_limits: agent/send_admission.rs; check_live_parity: chat/run.rs,
child_source/publication{,/ordinary_process}.rs, turn_publication.rs,
turn_decision/{discovery,execution}.rs,
security/approval_ledger/{grant,historical,pending,resolution,resume,review}.rs;
effective_compaction: chat/{binding,run}.rs, gateway/{mod,api/sessions}.rs;
effective_provider_capabilities: agent/turn_engine.rs, channels/turn.rs,
gateway/mod.rs, providers/generation.rs, tools/image.rs;
prompt_memory_loader: agent/embedded_turn.rs; tool_tiering:
agent/{embedded_turn,turn_engine}.rs, chat/binding.rs, gateway/api/sessions.rs.
- status()/DecisionPlaneStatus -> runtime/ingress_recovery/status.rs;
caller runtime/control_ladder.rs.
- validate_silent_terminal -> agent/terminal/binding.rs; callers
agent/terminal.rs, agent/terminal/replay.rs.
- Child row already lives on the R24 publication types; rejoin_terminal is
cfg(test) only and stays.
R28 publication rules -> tools/surface_owner/publication.rs
(PublicationRules, PublicationAdmission); TurnRuntimeContext gains
published, discovery, outgoing_delegation. causal_tree/directive.rs deleted
(ruling 05a4-DIR), with TurnDecisionContext::directive,
AgentDecisionError::Directive, HardGates::check_capability_publication,
direct_answer_refs. bind_resume_execution reads the execution-owned resume
surface (fixes every historical resume being refused).
R29 agent/terminal/binding.rs::TerminalBinding; DecisionSettlementRef keeps
decision_id/context/recorded; drafts carry Option<TerminalBinding>, commits
carry TerminalBinding; record_redacted_projection not added (05a4-PROJ).
R27 channels/decision_source.rs -> channels/turn_source.rs,
gateway/decision_source{,/} -> gateway/turn_source{,/}; the cleanup
re-export moves there and gateway/decision_cleanup.rs is deleted.
R26 (ruling R26-HOLDER)
- Builders move to runtime/turn_publication/ and are renamed:
TurnServiceBuild -> PublicationInputs, TurnLoopRuntime ->
PublicationLoopRuntime, build_turn_decision_service -> build_publication,
TurnServiceBuildError -> PublicationBuildError;
ordinary_process_service / operator_process_service ->
turn_publication::{ordinary,operator}_process_publication. Callers:
runtime/turn_publication.rs (publish_scoped, child, ordinary/operator
process publications) and tests.
- ApprovalRuntime / HistoricalApprovalRuntime impls stay on the service and
move to turn_publication/approval.rs.
- Resume variant: turn_publication::open_resume_turn (was
open_issued_resume_turn_context); callers chat/decision_source.rs,
gateway/api/sessions.rs.
- Pre-turn holders: OperatorSpawnSource::new takes Arc<TurnRuntimeHolder>
and funds the operator child from TurnRuntimeHolder::
workspace_remaining_micro_usd (same pinned inputs; caller chat/binding.rs);
WorkerChildSegments holds the worker publication's holder and refuses a
segment turn opened from another holder; OperatorProcessSegments::record
takes the run-keyed approval ledger instead of the service.
- Per-turn objects: TurnDecision carries runtime: &Arc<TurnRuntimeContext>
(turn_engine reads it and checks it is the decision context's),
ChildSegmentTurn carries Arc<TurnRuntimeContext>.
Tests
- New (written, not run): runtime::turn_context::tests::
rehomed_security_items_preserve_refusal; agent::refusal::tests::
historical_refusal_reply_is_byte_identical; security::approval_ledger::
tests::historical_resume_drift::
historical_resume_executes_exact_call_once_and_refuses_drift;
tools::surface_owner::tests::{publication_rules_match_pre_strip_direct_surface,
turn_scope_refuses_foreign_owner_and_other_model};
runtime::child_source::tests::
child_publication_survives_without_turn_decision_service.
- Moved: runtime/turn_decision/tests/exact_call_approval* ->
security::approval_ledger::tests::historical_exact_call_approval::*
(names unchanged).
- Deleted cells (ruling 05a4-DIR; subject was the engine-on refusal path
removed by R9): agent/agent.rs custom_memory_loader_fixture "unclear
request" branch of embedded_custom_memory_loader_runs_only_for_selected_retrieval;
agent/turn_tests/engine_budget.rs configured_small_native_schema_fixture
`if excluded { expect_err }` cell (DirectiveError::NonExecutableSelection).
No whole test function is deleted in this group.
- Rewritten: turn_decision::tests::execution::
child_zero_budget_publishes_no_costed_direct_ref, skill_receipts::
an_admission_waiting_for_approval_is_not_an_executable_capability_id,
native_usage admission assertion; directive assertions re-pointed to the
published surface / is_run (child_process*, g8_segment, worker_probe,
discovery_surface, skill_receipts, historical_exact_call_approval*,
catalog_drift, chat/dispatcher/*).
Part 2 deletes: runtime/turn_decision*, channels/decision_{runtime,turn}.rs,
gateway/decision_runtime.rs, causal_tree legacy half.
…rst send, off-path telemetry P1-01: the analysis no longer prices request/response bytes as tokens. A configured backend runs inside an allowance of the turn's own accounting scope: remaining G6 tokens and money minus the protected first send, with the token allowance shrunk until its highest-rate price fits the money (the same estimate an attempt reserves). New test engine_switch::configured_backend_runs_on_a_production_opened_turn opens a turn through open_turn_context with a valid configuration and proves one charged physical attempt on the 8,192-token slice. P1-03: AnalysisAccounting bounds every analysis attempt to the live remaining budget minus the protected first send (re-read at begin), so an uncertain attempt that retains its whole reservation never consumes the send's allowance. The protected send is priced at the largest prompt its compaction admits plus the response reserve. run_turn drops a brief whose prompt cost would fail the send's token or money admission. P1-04: observation no longer awaits the telemetry open. An open store admits the outcome at once; otherwise a background task opens the store and admits it. Shutdown drain waits for pending openings. New test decision_advisory::tests::observation_never_waits_for_the_telemetry_open. P1-09 (part): RecordingBackend begins and settles a real attempt on the accounting owner it is given; decision_advisory_runs_without_turn_decision_service and tight_budget_skips_analysis_and_never_refuses_the_request assert the exact token and money deltas; the tight-budget test gains the oversized-brief cell. advisory_decide_mode_projects_prediction_and_lazily_opens_store drains before asserting the store opened.
…cation and discovery P1-02 (R51/OV-4): in Full the backend invocation runs at Full whatever the child manifest level (tools/execution.rs); a child's runtime dependencies are not limited by manifest membership (execution_binding/specs.rs); a Supervised manifest no longer makes a Full turn's effectful discoveries ApprovalRequired (surface_owner/publication.rs). Integrity, budget, depth and plan-mode checks are unchanged; Supervised and ReadOnly are unchanged. Tests: full_autonomy_has_no_permission_limits gains a real native-tool cell (FileReadTool reads a file outside the workspace from a Full child with a Supervised manifest); new surface_owner::tests::full_turn_discovery_ignores_an_attenuated_child_manifest (Full: effectful member and non-member Passed; Supervised: member ApprovalRequired, non-member blocked). ChildCase::build_with registers extra tools.
…run the advisory driver
P1-05 (R9/R26): DecisionAdvisory::for_publication builds the advisory
driver of a publication: an enabled engine gets a factory from the effective
engine backend with the publication's state key; a disabled engine builds
none (P1-I2). The root builder, ordinary and operator child publications
(runtime/child_source/publication{,/operator}.rs) and the ordinary and
operator worker publications (runtime/turn_publication/{ordinary,operator}_process.rs)
use it. Worker segment turns (session_worker/runner/run.rs), delegated child
turns (tools/delegate.rs) and sessions_spawn task turns
(tools/sessions_spawn/task_mode.rs) analyse on their own TurnRuntimeContext
and accounting scope instead of hardcoding no advice.
Test: runtime::child_source::tests::child_publication_builds_the_advisory_driver_only_when_enabled.
P1-06: token_count reads the token counter and its timing hook at their R23 home (src/tokens/count.rs, src/tokens/count/token_timing.rs); decision_backend expects the borrowed constructor transport field in its new home (src/runtime/turn_publication/builder.rs); the catch_unwind inventory drops its six obsolete entries (agent/turn_tests/admission.rs and five deleted turn_decision test files); causal_domain drops the deleted causal_tree/directive.rs allowlist. R8: the engine boundary's module-resolving path scanner moves into helpers.rs as module_resolved_paths (with module_segments), so crate_rooted_paths has one definition and every helper lives in helpers.rs; R41 coverage is unchanged.
…te helpers P1-07 (R9-DEAD): PredictedState, ForeignDecision and CausalState::record_fingerprint were production items before the strip and are dead after it. They are deleted, not hidden: the CausalState.predicted field, the record branch of the canonical state JSON (CanonicalRecord, the record flag of canonical/serialize) and, by the compiler's cascade, ObservedStep's event id (field, accessor, constructor argument) and segment_observation::project_trace's event argument. Deleted exclusive tests: state::turn_state_tests::backend_cannot_set_trusted_state (with its sealed/validated helpers). Record halves removed from lineage_and_time_are_not_material, the shuffled-order fingerprint test, canonical_tests (oracle, allocation, empty-state golden, sequence order, model admission), exact_calls_tests (renamed absent_observations_keep_legacy_canonical_and_present_facts_bind_the_fingerprint) and child_process::g8_segment. Their material-fingerprint assertions are unchanged.
…erties (part) P1-09 (fixable part, first half): - RecordingBackend answers every real compiled question through scripted_answers, predicting a chosen action with full confidence (it no longer depends on the native-decision fixture's model pin). - engine_switch::high_confidence_refuse_or_clarify_advice_never_changes_the_turn (new): a backend that predicts refuse or clarify with full confidence through the advisory driver (asserted on the analysed next_action) yields the same single provider request, tools, dispatches and reply as the engine-off turn. The retired commit_threshold cell is removed from engine_on_and_off_open_identical_turns. - engine_on_and_off_open_identical_turns now also compares the opened turns' execution refs and published surface. Historical resume is waived (owner rule), so it opens no resume turn and says so. - runtime::turn_context::tests::child_turn_context_funds_recursive_money_only_through_the_parent_grant (new, R22 parent-grant cell).
…ol set; R29 operator cells The operator child's frozen capability set is a membership limit (controller ruling on audit-fix pass 1). In Full the operator task service publishes under the parent surface policy and a restored operator worker keeps its actual surface policy (R51/OV-4). Supervised and ReadOnly still publish exactly the frozen set. Parity, budget and per-call policy are unchanged. Tests: operator_case builds the task service through the production path (claim, issue_task, task_service) and the first segment's execution context. Supervised: the frozen set excludes an ACL-denied probe; it is not published and its dispatch is refused with 0 calls. Full: no frozen allowed_tools, the probe is published and executes once. In both levels an exhausted task or parent allowance funds no child share, and executor drift refuses the source, the authority and a new task service with no dispatch.
… and gate tests P1-09: the four discovery tests deleted with the hop exercised live behaviour. They are restored on a prediction-free opening: each turn asserts is_run and zero prediction-port calls, and discovery happens only through the model's capability_search call. - discovered_tools_are_capped_per_turn_and_admitted_in_search_rank_order: the rank-order and cap-of-one assertions are unchanged. The production cap of ten is now reached by real searches and admissions (eight extra peers) instead of seeded turn state; the eleventh is refused and passes once the cap is raised. - search_hits_are_admitted_for_the_next_request_through_the_same_gates - non_english_discovery_reaches_admitted_family_without_full_registry (the Plan cell uses recorded_approval_source in Plan mode) - production_discovery_selects_a_skill_and_loads_its_body_only_on_execution
…rify cells run a configured loopback backend The configured-backend and Refuse/Clarify cells configured BackendKind::Mock, which publication's from_config refuses (MockNotConfigurable), so they failed during setup. They now configure a fixed compatible-HTTP backend at a bounded loopback endpoint the test owns (ScriptedDecisionEndpoint: capped bodies, bounded shutdown, scripted full-confidence answers). Publication builds it through from_config, and the cells analyse with the publication's own advisory driver. The default AdmittedTurn transport builds loopback backends with the production HTTP transport and still refuses everything else. Both cells keep the attempt-charge assertions (one request, 1,200 tokens and a cost charged to the turn's scope) and the Refuse/Clarify cell keeps the full-confidence prediction assertions.
…ws prediction-free publication With direct_shell=true at Full, publication's direct surface makes both file_read and shell core, so the cell now asserts both core tools and that the core shell offer admits nothing new. The read-only cell, exclusion, idempotence, rank and cap assertions are unchanged.
…ion with one opener Before the telemetry store is open, every outcome spawned its own task that held the payload, and a growing retain scan tracked the handles, so a stalled opening allowed unbounded tasks and payloads. Now the first observation starts exactly one opener task and a non-blocking queue with the ObserveQueue bound (observe_queue). An outcome that does not fit is dropped and counted. The opener publishes the store, takes the queue over under the admission lock, forwards the queued outcomes and adds the pre-open drops to the store's existing drop counter. Drain waits for the single opener. The retain scan is gone. New test stalled_opener_leaves_a_bounded_queue_and_counts_the_overflow: on a current-thread runtime with a stalled opener, 11 observations at bound 4 each complete on their first poll and leave a queue of exactly 4 with 7 drops counted. After drain, the store holds 4 outcomes and ObserveCounters.dropped is 7.
… pre-open handover
…tch commits Rebased group by group onto origin/main 6676a46 (no squash). Conflicts were resolved in the 05a and 05a4 commits; this commit carries the one path retarget the resolution needed afterwards. Kept from the switch: the confirms_plain_answer acceptance of unbound+denied attempts (and its cells), the TurnScheduler requeue fix, the quinn-udp bump, and control tools on plain answers (Part 1 has no abstention gate left to withhold them). Removed with the prediction hop: clarify_degraded_directive, admitted_fallback_answer, is_plain_answer_abstention, the drift-path degrade, and the test-only plain_abstention_fixture module. Tests deleted (subject gone with the hop): - runtime::turn_decision::tests::agent_decision::clarify_degrades_only_with_a_gate_passed_answer - main's rewrites of catalog_drift_closes_with_fresh_unlinked_terminal_and_no_dispatch and cancellation_during_backend_and_catalog_drift_wins_before_recovery (already deleted by 05a) - main's enabled cell of engine_switch::run_plain_fallback_cell (enabled_builtin_low_confidence_run_turn_publishes_plain_answer, already deleted by 05a) - main's "unclear request" Clarify-degrade cell in agent::tests::custom_memory_loader_fixture (already removed by 05a4) Tests rewritten to the post-R9 contract: - terminal_scope LinkedFixture: the drift turn settles as Answer on the "none" target with no execution refs, and the terminal carries real serving evidence (replaces the stale Clarify expectation) - tools::delegate::tests::delegate_child_logical_deadline_still_refuses_provider_calls -> delegate_child_logical_deadline_never_refuses_the_child: a spent logical deadline never refuses the child; the allowed tool executes once Also: main's refused-call outcome cell builds RecordedToolCall through runtime::decision_journal::store instead of the causal_tree::store forwarding path.
… layout
Real: seven out-of-line test files added by the strip lacked the
repository's `#![cfg(test)]` marker, so AG-01, AG-28, process, ingress,
provider and config scanners read their test code as production. Mark them.
Stale, retargeted with the same coverage:
- compaction: the budget producer moved to turn_context/publication_scope;
pin the turn_decision forwarder exactly and add a mutation proof for it.
- decision_seals: salted_question_ids path; option-id allowlist reduced to
the four criteria keys left after forced choices were deleted (R9-DEAD).
- loop_prompt: reviewed TurnDecision handoffs carry the R26 runtime field.
- providers: auxiliary accounting moved to runtime/decision_accounting.
- causal_domain: per-file entries for hard_gates_probe (CatalogView, R21)
and refusal (agent::refusal reasons, R53).
- decision_seals AG-28: decision_advisory::build_state may name
TrustedState::from_runtime once (R9); literals and writes stay refused.
Scanner bugs in the new R41 engine-import guard (never run before):
path_tree_end treated a block `{` as a use group and panicked; and
whitespace removal turned `use crate::` into `usecrate::`, so five planted
use-statement probes were not caught. Groups now open only after `::`, and
compact_rust_path_text keeps a space between identifiers.
No probe deleted; no scanner retired.
- const fn: TurnDecisionService::advisory, terminal_outcome_action, TurnDecisionContext::runtime, plane_status, prepared_tool_name, DecisionAdvisory::factory. - DecisionAdvisory::observe is synchronous (it never awaited and must not block); callers drop `.await`, the stalled-opener test drops now_or_never. - child_telemetry: bind the recovery gate before `if let`. - hard_gates_probe: return HardGates::apply directly. - tests: map_or_else, assert_eq against empty values, keys() loop, no redundant clone, no drop of borrowed views, queues asserted alive.
Root causes found by the first test run of Part 1: - Full-autonomy children (R51 bypasses manifest membership) published the parent's Direct delegator without a sealed outgoing manifest, so binding failed with "answer surface has no sealed child manifest". A child now publishes a delegator only with its sealed outgoing manifest (V-16 structural integrity, not a permission limit). - The same bypass exposed the parent's catalog to a child's discovery while the child's own task registry carries no search backend: every such child failed with "capability discovery unavailable". A child without a live search control now simply has none. - Without the retired child hop, a child published only Direct entries, so the tools its parent chose (its sealed manifest) were refused as "not exposed". The manifest's members are now published like Direct entries, under the same publication rules. - Prompt skills listed only discoverable skills: a published skill was neither advertised nor produced a selection receipt. Published skills are now listed (no loader needed) together with discoverable ones. - R55: `prx causal config` / Gateway backend mutations wrote the legacy `[causal_tree.backend]` while the engine builds from the migrated `[decision_engine.backend]`, so a backend change never reached the engine and failed validation. Mutations start from and write the effective backend (both tables kept identical); credential reference, pairing, calibration and the validator's change detection read it too. - docs/configuration.md no longer describes the removed engine-on Clarify degrade.
- decision_engine::admission_probe::tests: the NamedTool fixture schema
`{"type":"object"}` has no `properties`, which the catalog's
SchemaCleanr::validate correctly refuses (`Err(Schema)`); it now declares
`properties: {}`. advisory_ordering_and_limits_match_structural_order
compares candidates by action and capability ids: each fixture run mints
its own key, so keyed namespaces never match across runs.
- config::secret_paths: the R15/R17 schema homes causal_tree.rs,
causal_tree/backend_kind.rs and decision_engine.rs join the secret-alias
scan.
- decision_engine::prediction::factory::tests::disabled_builds_builtin_only_order_and_no_transport:
the default engine switch is off (R55), so the default row is Disabled.
- decision_engine::prediction::factory::tests::a_disabled_plane_creates_no_key:
disables the plane (`[causal_tree].enabled`), which owns the key.
- config::schema::decision_engine_config_tests::explicit_empty_engine_backend_uses_defaults_not_legacy:
the `auto` default plans its unconfigured loopback probe; no legacy slot.
- causal_tree::admin::tests::an_excluded_configured_backend_is_not_tested and
cdp_cli::a_disabled_plane_never_opens_the_credential_store: the engine
switch (R55), not `[causal_tree].enabled`, gates the factory.
…imits (R51)
Tests that asserted an identity-scope ACL deny at the default Full level now
run their ACL cell below Full (Supervised), where the deny still applies; a
Full cell asserts the R51 Allow where the test's subject is the level
itself. No test deleted.
Rewritten tests:
- agent::execution_policy::tests::configured_cli_policy_controls_tool_service_and_preserves_actor_scope (Supervised)
- causal_tree::gates::tests::{owner_check_and_execution_scope_use_distinct_source_identities, mcp_alias_acl_denial_uses_executable_public_name} (Supervised)
- tools::execution::tests::admission_matrix::policy::policy_deny_refused_without_backend_call (Supervised)
- tools::execution::local_operator_scope_tests::a_scheduled_scope_carries_the_configured_policy_for_its_creator (Full ⇒ Allow; Supervised ⇒ scope Deny)
- cron::scheduler::tests::a_scheduled_run_is_held_to_its_creators_scope_rules (Full rows run; Supervised webhook row refused)
- int_p1_cross_module::int_cs_03_decide_layers_scope_and_autonomy (Full ⇒ Allow; Supervised ⇒ Deny)
- gateway::api::memory::tests::memory_routes_enforce_service_scope_policy_and_audit_denials (Supervised)
- gateway::api::skills_lifecycle::tests::lifecycle_routes_enforce_service_scope_policy_and_audit_denials (Supervised)
- gateway::compat::tests::card_jwt::mcp_tool_call_denied_by_policy_returns_the_schema_rejection_structure (Supervised)
- tools::skills::executable_tests::an_undeclared_or_ungranted_tool_is_refused (Supervised)
- agent::entry::tests::cli_agent_configured_scope_denies_wire_file_write (Supervised)
- tools::execution::tests::full_autonomy_has_no_permission_limits: the
explicit-grant cell's assertion now reports the outcome text.
…ediction hop
Subjects that are still live are rewritten to the prediction-free contract
(the model chooses tools; the engine only adds a brief). No test deleted.
Fixtures:
- native_decision_fixture: removed the hop-only `require_request` and
child-delegation request assertions (and the dead parameter at all 41
call sites); a request that does arrive (advisory analysis) must still
get a real response, falling back to the plain Answer when its scripted
candidate is absent.
- tests/support/{answer_agent,native_agent,selected_memory}.rs: rewritten
to prediction-free harnesses (no decision endpoint, no prediction-binding
validation); native_agent still checks the provider receives the
published tool; selected_memory seeds the fact before the turn instead of
inside the decision request.
- with_worker_probe_manifest: dead `generation_negative` parameter removed.
- admission fixture: no longer forces the engine on for ordinary
controlled turns (the caller's switch is honoured).
Rewritten tests:
- tools::delegate fixture gate (12 tests): Delegate selection ⇒ the parent
publishes `delegate` with a sealed outgoing manifest.
- channels::tests::signal_accounted::assert_decision_path (5 tests): one
prediction-free Answer row; no retrieve/discover/refuse rows.
- chat::dispatcher::turn_characterization_tests step 7.1 (3 tests):
prediction-free opening on the enabled plane, Answer committed.
- security::approval_ledger historical_exact_call_approval (6 tests incl.
native_usage): the backend is asked 0 times at opening.
- chat::decision_source::advisory_decide_mode_projects_prediction_and_lazily_opens_store,
agent::turn_tests::engine_switch::{configured_backend_runs_on_a_production_opened_turn,
high_confidence_refuse_or_clarify_advice_never_changes_the_turn}: the
turn opens under a cleanup owner, as production entries do, so it has its
accounting scope.
- engine_switch::engine_on_and_off_open_identical_turns: the brief block is
excised, not truncated at its marker.
- agent::entry::tests::cli_agent_persists_no_secret_from_a_{provider_error,reply}:
the recorded backend is `none` (prediction-free).
- agent::terminal::tests::unissued_entrypoint_label_drafts_are_rejected_before_side_effects,
runtime::turn_decision::tests::recorded_chain::enabled_agent_service_records_only_a_successful_decision_chain:
R29 refuses for the missing terminal binding first.
- tools::sessions_spawn::tests::kill_and_events::spawn_denied_without_grant_under_supervised:
refused at the approval gate (the surface publishes, execution approves).
- runtime::child_source::tests::child_publication_survives_without_turn_decision_service:
the ordinary publication re-seals the pinned refs under its run-scoped
parent authority (refs, parent refs and depth compared).
…ry admission, deferred child members Controller rulings on PR #204 CI round 2, applied in production code: - Ruling 1: loading a managed skill through skill_read records the skill selection receipt (idempotent per revision), beside the hydration receipt. A failed selection write marks the task's evidence dropped. - Ruling 2: paid auxiliary calls (Signal vision, smart-group classifier) first run the unpriced-model refusal of provider send admission (send_admission::protected_first_send), so a turn whose main send will be refused never pays for an auxiliary call. - Ruling 3: an auxiliary call reserves at most the live remaining budget minus the protected first send (G6 answer tokens and the price of the largest admissible prompt plus its response reserve, P1-03). A failed or uncertain classifier that retains its whole reservation no longer starves the main model. AccountingScope::begin_physical_within is now visible to runtime::auxiliary_call; the two AuxiliaryAccounting test constructors pass a zero protection. Also a defect found by tool_search_roots (R28): a child that owns a live capability_search control published every Searchable sealed-manifest member eagerly ("deferred memory reader was eagerly declared"). A new admission fact, child_discovery, records whether the child's own executor carries the discovery control; with it, deferred members stay behind capability_search; without it they are still published. Fixture updates that ride with these types: AdmissionFactsV1 fixtures set child_discovery; decision_advisory_runs_without_turn_decision_service runs each backend model in its own workspace (the fixed fixture scope id made both models share one turn's money limit in one cost journal). Removed an unused cfg(test) import in turn_decision.rs.
…p, R51 and stale fixtures
Deleted (subject was only the deleted hop or waived historical resume):
- security::approval_ledger::tests::historical_resume_drift::historical_resume_executes_exact_call_once_and_refuses_drift
(ruling 5; module file removed)
- runtime::turn_decision::tests::discovery_surface::named_skill_and_loader_select_the_skill_without_competing_targets
(hop skill selection; skill discovery is covered by
production_discovery_selects_a_skill_and_loads_its_body_only_on_execution)
Rewritten to the prediction-free contract (R9, R28):
- agent::entry::tests::{cli_single_shot,cli_repl}_routes_*, cron_job_turn_routes_*,
xin_task_turn_routes_*: recalled memory publishes nothing; no extended tool refreshed
- agent::turn_engine::tests::execution_grounding::* (11): opening commits no tool
- agent::turn_engine::tests::{run_tool_call_loop_native_mode_persists_each_tool_output_once,
compiled_request_event_accounts_for_prompt_and_tool_payload_sizes,
compiled_request_event_breaks_the_tool_surface_down_by_root_and_adapter,
a_capability_search_hit_is_declared_on_the_next_request_and_not_the_current_one,
compiled_tool_snapshot_is_rendered_once_per_turn_with_a_stable_system_prefix}:
fixture tool configured Direct (tool_tiering.always_include)
- engine_surface::{run_tool_call_loop_persists_large_tool_output_documents,
production_turn_far_longer_than_the_idle_window_survives_on_progress,
production_turn_whose_tool_goes_silent_past_the_window_is_terminated}: Direct fixture tool
- engine_surface::tool_loop_refreshes_only_intent_selected_dynamic_capabilities
-> tool_loop_refreshes_only_published_dynamic_capabilities;
prompt_guided_provider_receives_only_the_compiled_turn_tool_snapshot,
tool_loop_rejects_a_registered_tool_not_exposed_for_the_turn,
turn_exposure_guard_preserves_unknown_tool_diagnostics: configured Direct pdf_probe
- agent::agent::tests::{embedded_custom_memory_loader_with_durable_builtin_diagnostics,
embedded_selected_memory_preserves_original_source_input}: one Answer receipt, no prior retrieval
- agent::agent::tests::bounded_native_fixture_preserves_supervised_and_readonly_denials:
the gate refuses the call itself and the model answers after it
- channels::tests::process_message (factory_reload_fixture): one Answer row per input
- chat::binding::tests::shell_parity_working_root::chat_workdir_reaches_real_worker_and_unset_keeps_worker_workspace:
binds the published sessions_spawn definition
- runtime::turn_decision::tests::catalog_drift::enabled_service_allocation_diagnostic_holds_candidate_count_fixed:
hop-only Discover/UseTool candidate shape assertions removed
- child_process::full_policy_issues_real_parent_delegate_grant: hop candidate re-gate removed
- child_process::supervised_without_exact_approval_cannot_issue_parent_delegate_grant:
Supervised publishes the Direct spawn; the opening grant is Supervised, model-only, owner-bound
- child_process::g8_segment::*: outside-manifest call in a Full child is refused by its
call budget (R51); no prediction at opening
- discovery_surface::named_memory_recall_becomes_ready_after_selected_discovery_without_publishing_peers
-> named_memory_recall_is_reached_by_search_without_publishing_peers
- discovery_surface::selected_native_write_can_discover_read_peer_without_offering_shell
-> direct_native_write_can_discover_read_peers_through_search
- skill_receipts::below_bar_skill_execution_adapter_is_not_published
-> direct_skill_execution_adapter_is_published_without_a_prompt_document
- skill_receipts::rejoin_without_provider_facts_joins_the_terminal_once_as_unknown
-> rejoin_of_a_verified_recovered_completion_joins_the_terminal_once
- runtime::child_source::tests::child_publication_survives_without_turn_decision_service:
task-scope check covers the sealed manifest only; child dispatch envelope carries its owner
- enabled_service::enabled_service_with_unavailable_key_does_not_open_a_writable_store: R55 engine switch
- execution::child_zero_budget_publishes_no_costed_direct_ref: child with a sealed outgoing manifest
- recorded_chain::enabled_agent_service_records_only_a_successful_decision_chain:
drop the five synthetic latency rows of the deleted reader
- tools::execution::tests::full_autonomy_has_no_permission_limits: H2 cell uses
lifecycle_experiment_admit with an admitted descriptor
- tools::shell_parity_tests::full_parent_supervised_child_keeps_native_restrictions_after_approval
-> full_parent_attenuated_child_runs_native_tools_at_full (R51)
- tests/agent_e2e.rs e2e_memory_enrichment_injects_context, e2e_multi_turn_with_memory_enrichment:
a warm-up turn opens the Agent's own session; the fact is seeded there
Removed the now unused AdmittedTurn::with_prediction_tools.
…ts own executor serves
Root cause of the g8 child failures ("selected executable capability is
missing"): a child's catalog is its parent's pinned catalog, and in Full
the R51 bypass dropped manifest membership from publication, so the child
published every Direct entry of the parent catalog, including ones its own
executor does not run (the parent's interactive-only chat_schedule in a
process worker). execution_specs then failed closed on the missing
descriptor and the whole child turn failed. The "has no call budget"
denial the round-3 notes attributed to a per-tool budget is the R6b
refusal of a model-turn context without any call budget (the raw adapter
context before segment admission). It applies to every tool. The call
budget is not per tool, so in Full it already funds every tool the child
can see (ruling 1).
Fix: a new admission fact, child_served, records for a Full child turn the
pinned catalog entries its own executor serves with descriptor parity.
Outside its manifest, a Full child publishes (direct_surface) and
discovers (child_membership_admits) only those entries. Manifest members,
Supervised/ReadOnly children and non-child turns are unchanged. Money
ceilings, recursive money and spawn depth are untouched.
AdmissionFactsV1 fixtures set child_served: None.
… round, lifecycle selection gates - g8_segment (both cases): the unbudgeted adapter context is refused for every tool, in or outside the manifest (R6b). After segment admission, the Full child publishes and binds the served capability outside its manifest and runs it under its call budget (R51). It never publishes or binds the parent's chat_schedule, which its executor does not serve. - child_source operator cells: dispatch through the production path (ChildSegmentTurn::admit stamps the call budget, bind_agent_execution, turn surface) instead of the raw segment context. Full runs the probe once; Supervised refuses it. - delegate agentic_mode_inherits_parent_tools_only_with_explicit_wildcard (ruling 2, R28): the child searches with capability_search, then calls the inherited deferred echo_tool, then finishes (3 requests). The test asserts echo_tool is not declared before the search. - skills lifecycle acceptance (ruling 4): the slowness was new. Since round 3, skill_read records the selection receipt synchronously, so the selection_gate that held the run's FIRST chat request waited for a receipt only that request's answer can produce. Each gated task stalled 20 s on the gate cap (its panic is swallowed in spawn_blocking). The gates now hold the request carrying the skill_read result (run_task_selected, scenario_b, scenario_e). The acceptance module runs in 21 s, so no nextest override is needed and no scenario is weakened.
Move the credential_containment_tests module (C0-C provider/credential containment) unchanged into src/tools/delegate/credential_containment_tests.rs, declared as `#[cfg(test)] mod credential_containment_tests;`. No behaviour change: the module body is moved verbatim (dedented one level) and keeps its `super::*` imports. src/tools/delegate.rs: 5015 -> 4252 lines (source_size_gate limit 5000). No architecture-scanner path names the moved module: the delegate.rs entries in tool_tables, compaction, loop_prompt, loop_contracts, labels and panic_policy name production code that stays in delegate.rs, and the moved code has no catch_unwind or log lines.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Part 1 of the decision-engine strip: the engine becomes advisory-only and moves into its own module,
src/decision_engine/. Everything it shared with the rest of the crate gets a neutral home. Historical data and recovery stay intact: the legacy decision store, the key, the record writers, terminal replay and AUTH-02 are kept. Deleting them is Part 2.Groups, one commit each:
chat/decision_source.AdvisoryProbe. It annotates with the real hard-gate outcomes and never filters.src/decision_engine.The audit-fix commits that follow these groups address Codex code audit r1, r2 and r3. The last commit records how this branch was rebased onto main 6676a46, which includes the landed engine switch.
Owner rulings
Rebase onto main
The Clarify degrade and the drift-path degrade were built into the prediction hop, so they are removed together with it. The following switch behaviour is kept:
confirms_plain_answeracceptance of unbound and denied attempts;The last commit lists every test that was deleted or rewritten.
Audits
coordination/REQ-DECISION-ENGINE-STRIP-P1.md, spec audits r1–r4.coordination/reports/STRIP-P1-code-audit-r{1,2,3}.md.Verification
cargo check --all-targets --all-featurespasses with zero errors and zero warnings. PR CI is the full gate.