Repository navigation
refactor(decision-engine): strip Part 2 — remove legacy decision data and compatibility - #205
Merged
Merged
Conversation
…ey, persisted claim semantic, cost projector Part 2 branches from landed main f4cc5ad (Part 1; 6676a46 is an ancestor). S2 re-measure on f4cc5ad vs the spec's 2318d71 column (lines/files): A1 20/9 = ; A2 102/21 = ; A3 139/32 vs 148/31 (05a4 moved approval wiring to runtime/turn_publication{,/approval}.rs; PR #204 CI 9135849 deleted historical_resume_drift.rs); A4 188/50 vs 187/50 (05a4 IssuedChildGrant moves to terminal/binding.rs and turn_publication/builder.rs; PR #204 CI child_process.rs +1); A5a 1578/253 vs 1635/253 (05a4 rehome and PR #204 CI test rewrites); A5b 845/177 vs 852/178 (05a4 decision_source -> turn_source moves, f4cc5ad delegate split, PR #204 CI fixture rewrites); A5c 63 vs 65 (05a4 moved build_error.rs and execution/operator_process.rs to turn_publication/); A5d 4/3, A5e 18/8, A5f 8, A6 12/3, A7 13/8 unchanged. - P2-R1: session_worker::transport_key::TransportSecret {for_launch, existing}; both session_worker_signing_key copies, existing_session_worker_signing_key and the process-local fallback deleted; SESSION_WORKER_SECRET must be 32 bytes. - P2-R2: runtime key at <ws>/self/runtime/runtime.key; state_key is the runtime key always (no plane gate, no ephemeral fallback). - P2-R3: claim payload always carries the semantic; restart verification of D4.4 steps 1-7 (turn_terminal::restart_verify); canonical key_id enforced. - P2-R4: golden vectors E2-E7b, K_child, K_batch, batch and segment seals, constraints and effective-config payload literals; restart tests per status with negative cells. - P2-R5: runtime::cost_recovery::CostOutboxProjector; scan_recovery_costs with a raw cursor and exhaustion flag replaces pending_recovery_costs. - P2-R6: warn_legacy_files_once. - P2-R7: surface and oversized-reply model id from the pinned TrustedParts. Tests deleted: transport_key::tests::{an_existing_publicly_readable_valid_key_is_ tightened_without_rotation (OV-6), failed_key_publication_logs_the_cause_and_ returns_the_fallback_error (fallback removed), concurrent_transport_key_creators_ return_the_same_persisted_material (replaced), an_invalid_existing_transport_key_ is_never_replaced (replaced)}; runtime_key::tests::ephemeral_keys_need_no_ workspace_and_do_not_share_fingerprints (no ephemeral fallback). Tests retargeted: auth_02_3_tests restart scan -> cost_recovery::run_pass; sqlite recovery_authority tests -> scan_recovery_costs; identity and H2 review key-path tests -> self/runtime/runtime.key. Acceptance: A1 20/9 -> 0 (exit 1).
…e, /api/decision-engine, fresh telemetry store
P2-R8: `prx decision-engine {status, backends, config set <key> <value>}` in
the new `decision_engine_cli.rs`; `config set` goes through
`config/manage/mutation/decision_engine.rs` (renamed from `causal.rs`) with
the allowlist (`EngineSetting`, `engine_setting`, typed `EngineKeyError`).
`prx causal …` prints one deprecation line and exits 0. `causal_cli.rs`,
`causal_cli/backend_transport_tests.rs` and every user deleted; `DecisionSetup`,
`BackendKindArg`, `hosted_owner`, `hosted_setup_steps` moved for `prx init`
and onboarding. The onboarding local backend test is replaced by a status
line (its `DecisionAdmin` is deleted).
P2-R9: the ten `/api/causal/*` routes answer 410 `{"error":"gone","see":
"/api/decision-engine"}`; new `gateway/api/decision_engine.rs` (status,
backends, analyses/outcomes with `limit` 1..=100 default 20, config plan/apply
with allowlisted keys, write-only credential -> 204, typed 400 body).
P2-R10: `decision-engine.sqlite` is fresh-schema v2 (`engine_analyses`,
`engine_outcomes` with the spec DDL; other `user_version` dropped and
recreated); analyses recorded once per turn with the redacted brief sent;
`TurnOutcome.result` (`TurnResultClass`) replaces `succeeded`, plus
`cost_micro_usd` (same priced usage record as the `turn:<id>:usage`
settlement) and `duration_ms`.
P2-R11: `causal_tree::{admin, evaluate, report_catalog, v1_compat}`,
`FactoryDeps::load_key`, `CausalMutation::ApplyCalibration`, `read_proposal`,
`StoredReport` deleted; `config set apply-calibration` is one typed error.
`KeyDomain::ReportOwnership` renamed `SkillRecordSeal` with its label
unchanged (live skill lesson-delivery/study seals; bytes identical).
Admin-only decision-store readers deleted with them (`list`, `inspection_*`,
`evaluation_rows`, `import_progress`, `mark_imported`, `record_decision`,
writer `Close`/`Imported`, `LocalOperator`, `TimeWindow`, `EvaluationRows`,
`DecisionId::legacy`, `detach_last`, `all_stored`); store tests keep
`counts`/`close`/`path` as helpers in the store's `testing` module.
Ruling: `DecisionKey::ephemeral` -> `security::runtime_key::test_support::ephemeral_key` (13 fixture files).
Scanners: `decision_seals.rs` admin entry, `causal_domain.rs` admin entry,
`scanner_probes.rs` admin probe, `panic_policy.rs` causal_cli entry removed;
`causal_policy.rs` writer path renamed.
Tests deleted (reason): causal_cli unit tests and backend_transport_tests
(module deleted); gateway causal tests (routes retired); tests/cdp_cli.rs
`prx causal` read/test/config cells (command retired); mutation
`apply_calibration_needs_a_report_and_a_pin` (ApplyCalibration deleted);
factory `a_disabled_plane_creates_no_key` and the load_key assertion
(load_key deleted); `engine_outcomes_gains_a_scope_column_once` (fresh
schema); `decision_id::a_legacy_id_is_stable_and_round_trips` (legacy
deleted); manage_cli `a_decision_secret_is_read_only_after_confirmation`
(credentials only via PUT /api/decision-engine/credential); store tests that
read deleted admin readers or import progress (files_and_recovery:
a_read_only_store_creates_nothing, a_read_only_open_of_an_existing_store_changes_no_file,
the_workspace_id_is_stable_across_a_move, import_progress_needs_every_decision_stored,
a_read_only_open_sees_rows_in_a_live_wal; tests/mod.rs:
late_outcome_joins_once_and_a_conflicting_settlement_is_refused,
partial_outcome_at_provider_retention_boundary_reopens_and_replays,
a_conflicting_decision_is_refused_not_overwritten,
decision_debug_omits_private_endpoint_projection_and_lineage,
decision_chain_transaction_rolls_back_on_conflict_and_emits_commit_after_storage,
inspect_other_owner_decision_denied, a_newer_schema_opens_read_only;
batching: the_real_writer_stops_batches_at_drain_and_capacity_before_notifying);
agent.rs decision-receipt inspection block of custom_memory_loader_fixture.
New tests: tests/cdp_cli.rs {decision_engine_status_reports_disabled_by_default,
causal_command_prints_one_deprecation_line, decision_engine_config_set_rejects_unknown_and_secret_keys};
gateway::api::decision_engine::tests::{legacy_causal_routes_return_gone,
analyses_are_bounded_and_redacted, config_apply_rejects_secret_and_unknown_keys};
decision_engine::tests::{telemetry_store_holds_only_analyses_and_outcomes,
turn_outcome_records_cost_duration_and_result_class};
mutation `engine_setting_accepts_only_the_allowlist`.
A2: 102 lines / 21 files (f4cc5ad) -> exit 1.
…ger only, decision-bound grants refused
P2-R12 approval ledger ownership
- Deleted security/approval_ledger/{historical, resume, resolution, grant, pending}.rs,
ApprovalLedger, ApprovalRuntime, GrantScope, keys::{DecisionAuthority,
decision_resolution_key}, review::valid_projection and every impl ApprovalLedger.
- DecisionApprovalView and scope_from_source moved unchanged to
security/approval_ledger/view.rs (OV-12); review.rs keeps only ApprovalReviewAdapter.
- ApprovalAuthority keeps the run-keyed key bytes; the decision-only grant-id/op-id
parameters and resume_key are removed (no other implementor).
- The decision store refuses historical collect_approval_arguments evidence instead of
validating it with valid_projection (store deleted in G5).
P2-R13 claimed-decision and resume plumbing
- Deleted security/decision_approval.rs, tools/capability/resume_evidence.rs,
DecisionResumeAdapter/DecisionResumePort, ToolExecutionContext.decision_resume,
TurnRuntimeContext.{resume, resume_evidence}, resume_tool_name,
decision_advisory::resume_gate_maps, the resume parameter of
PublicationRules::{surface, restricts, capability} and TurnSurfacePort::fresh_resume_evidence,
TurnSurface::{restricted_to, single_published}, turn_publication::open_resume_turn and
turn_publication/approval.rs, runtime/turn_decision/pending_approval{,/h2,/sealed_call}.rs,
bind_resume_execution/execute_agent_resume, collected/claimed-resume context state,
RunAllowances::{inherit_resume, retire_pending} and the unfunded allowance state.
- Gateway: the /approvals/{id}/resume route, run_console_resume and ConsoleTurnMode are
deleted; /sessions/{id}/approvals/{id} GET/POST/DELETE serve run-keyed calls only and the
inbox lists run-keyed calls only (run-call routes kept).
- Chat: /resume-decision, /approval --decision, /revoke --decision, /approve|/deny --decision,
decision display aliases and the foreground resume close are deleted.
- Controlled H2 gateway: the local-owner review (LocalOwnerReview/Stamp, attest, the
show/approve/deny/revoke reader verbs) is deleted; the local control reader keeps `exit`.
Gateway lifecycle actions that required a local owner review are refused.
P2-R14 ApprovalGrantV2.decision_binding
- Field and DecisionApprovalBinding kept (wire). verify_for_decision and
issue_decision_one_shot deleted. New typed GrantRefused::DecisionBound via
refuse_decision_binding(); verify_for_operation(_bound) and SecurityPolicy v2 verification
refuse any grant with decision_binding: Some.
- New test acl::approval_grant::tests::grant_with_decision_binding_is_refused.
Tests deleted (reason: they exercise deleted historical decision-approval code):
- security::approval_ledger::tests: decision_keys_are_byte_identical_to_pre_extraction,
pending_and_review_payloads_keep_pre_extraction_bytes, consumed_grant_claim_keeps_pre_extraction_bytes,
revoked_grant_claim_keeps_pre_extraction_bytes, signed_resume_intent_keeps_pre_extraction_bytes,
claim_and_revoke_race_has_exactly_one_winner, consumed_grant_cannot_be_revoked_or_reclaimed_after_restart,
revoked_grant_cannot_be_claimed_after_restart, wrong_owner_or_session_cannot_review_or_claim,
run_keyed_and_decision_keyed_listings_do_not_mix, decision_claim_checks_stored_grant_owner,
pending_approval_loads_from_the_journal_with_a_dropped_store_projection,
pending_approval_with_a_missing_journal_row_is_refused,
pending_approval_with_a_tampered_journal_row_is_refused,
legacy_pending_approval_without_journal_rows_must_be_requested_again,
and the whole historical_exact_call_approval module
- runtime::turn_decision::tests::historical_support (module),
recursive_budget::authenticated_resume_without_original_allowance_cannot_mint_a_child_slot
- tools::skills tests::a_decision_bound_grant_works_only_inside_the_claimed_scope (with_claimed_decision)
- chat::binding::tests::{resume_admission_infrastructure_failure_offers_retry_without_error_details,
resume_admission_authority_failures_share_an_opaque_refusal,
enabled_fresh_plan_resume_without_approved_grant_is_rejected}; resume=true cells removed
- chat::input_queue::refusal_tests (only helper was the resume-failure path)
- runtime::h2_entry::review::tests (module; local owner review deleted),
origin::tests::explicit_resume_normalization_... (replaced by revoked_profile_refuses_new_terminal_input)
- tools::execution::tests::admission_matrix::{budget::resume_context_carries_budget,
surface::console_resume_replays_model_turn_with_surface,
surface::console_and_chat_resume_go_through_model_turn_context} (model_turn_context deleted)
- tests/chat_pty_e2e/decision_resume.rs
- architecture scanners: tool_tests::resume_sites_go_through_model_turn_context + its mutation
probe, the execute_agent_resume entries in tool_tests/tool_tables, causal_domain
valid_projection entry
Retargeted: recursive_allowance::tests::context_drop_removes_every_run_alias (denied-pending half removed),
gateway sessions targeting test (no pending decision count).
Acceptance A3: 139 lines / 32 files (cc50935) -> exit 1.
…ycle actions
G3 removed the controlled-Gateway local-owner review together with the
decision approvals it was attached to, so the Gateway lifecycle actions
publish, annotate, rollback and retire always failed closed. Restore the
review, decoupled from decision approvals:
- EntryInvocation::from_verified is async; a Gateway lifecycle mutation
posts a review request to the original local terminal (in-process
broker on ControlledH2Profile, bounded to 16 waiting reviews, 300 s
window) and admits only after the local owner approves that exact call
(`approve REVIEW CALL_DIGEST`). `deny REVIEW`, timeout, reader exit
or a revoked launch refuses it. The admitted invocation carries the
LocalOwnerReview, which is re-verified (origin, args, call digest,
capability and catalog generations) at consume; consume is single-use.
- The local control reader accepts approve/deny/exit and ends every
waiting review when it exits.
- No decision store, decision id or key is involved.
Tests: runtime::h2_entry::review::tests::{local_owner_review_gates_publish,
local_owner_review_gates_annotate, local_owner_review_gates_rollback,
local_owner_review_gates_retire} (approved -> performed once; denied ->
not performed) and reader_exit_ends_waiting_review_without_performing.
…tor path, delegated grants removed
P2-R15 one issuance path
- Plane conditions removed: child_source/publication.rs (capture, verify_caller,
verify_live, verify_task_scope), turn_decision/execution.rs (ordinary child
publication always captured for delegate/sessions_spawn), turn_decision/issued.rs
(delegation storage readback), outgoing_delegation, session_worker ordinary_source,
sessions_spawn {spawn, batch, batch_journal, tool}, runner/run.rs,
process_terminal/ordinary.rs, parent.rs restore_ordinary_process, delegate.rs.
- config/generation.rs: for_disabled_child -> for_child, assertion removed, encoding
unchanged (S7 pinned by config::generation::tests::for_child_fingerprint_encoding_is_unchanged).
- Every child kind uses the ordinary/operator publication. from_worker_channel sites
already pass MemoryFabric::workspace_id() (S9).
- Child money/scope: TurnRuntimeHolder ordinary_money/recursive_allowances; the
incoming-grant arm of recursive_money/issue_recursive_allowance removed (S6 note in
report: the explicit allow_delegation recursive opt-in required a decision-issued
grant and is now refused on every surface, as it already was on ordinary surfaces).
P2-R16 delegated issuance deleted
- IssuedChildGrant, ChildGrantRuntime, ChildGrantData, ParentModelSelection,
child_source/recursive.rs, ChildSegmentSequence, restore_worker_input,
ChildModelSelection, ChildProviderBinding::{build, build_worker, source_proof,
selection_for}, the outgoing-grant task local, ToolExecutionContext.child_grant,
SpawnExecutionContext.incoming_grant, TurnRuntimeHolder.parent_grant,
TerminalBinding.parent_grant, PublicationInputs.parent_grant,
ChildDecisionPublication, OwnedTurnSourceProof::from_child_receipt,
LogicalTaskTerminalRef::granted, DelegateChildAuthority::Granted (now a struct),
task_mode incoming grant branch, ChildExecutionPolicy.
- turn_decision/delegation.rs deleted: issue_child_grant and
validate_delegation_storage removed; the live ordinary helpers
(configured_delegation_target, verified_delegation_scope, outgoing_delegation)
moved to turn_decision/child_scope.rs (G5 rehomes turn_decision).
- Wire: WorkerManifest.{capability_manifest, child_source}, WorkerChildSource,
WorkerResult.completion_evidence and WorkerCompletionEvidence removed;
WorkerManifest is deny_unknown_fields; WorkerOrdinarySource.capability_manifest kept.
- authority_journal: authority/launch_parent/batch_parent tables and their code
(ParentIssuerEvidence, LaunchParentRow, BatchParentRow, persist, persist_batch_parent,
read_*_parent, verify) removed; decision_evidence/child_outcome kept for G5.
- Verifiers/fallbacks: verify_worker_parent_authority, delegated
process_terminal/launch.rs (process_identity moved up), ProcessRecovery,
VerifiedWorkerCompletion, delegated verify/recover_* paths, legacy_reader,
repair_store, ParentSource::restore_process, batch_journal v1/3/4 arms and
verify_store_parent (v2 only; ordinary_source required; seal bytes unchanged),
operator segment decision_id branch (a decision record is refused).
- Delegated completion journal (session_worker::completion::persist) removed.
- Settled terminal facts keep parent_authority_id in the closed schema, always None.
- Dead after the cascade, deleted: legacy no-source worker provider path
(validate_worker_route, worker_provider, build_worker_provider_selection,
worker_lineage_payload, scoped_reliability, without_rotation_keys),
RecursiveAllowance::{carve_child, ensure_available, claimed},
ChildCapabilityManifest::{for_recursive_spawn, narrow_allowed},
ParentAuthorityId::{as_uuid, decision_grant_id}, DecisionId::from_uuid,
TurnDecisionService::settlement_ref, decision store ReplayChain /
existing_shared_writer / existing_writer, SpawnDelegationStatus::from_grant,
delegation::status/append_metadata, test route observer.
P2-R17 worker verification order
- Outer capability under T, then exactly one of ordinary_source/operator_source
else typed WorkerManifestUnsupported (validate.rs and run.rs); the snapshot
decoder maps undecodable (pre-strip) manifests to WorkerManifestUnsupported.
P2-R18 test written (not run): runtime::child_source::tests::every_child_kind_issues_without_decision_records.
Tests deleted (reason: exercise deleted delegated issuance):
- runtime::turn_decision::tests::child_process (module incl. g8_segment, route_binding,
worker_probe) and recursive_budget (module)
- session_worker::runner::tests::authority (module), tests::probe (module; delegated
parent-issued manifest), manifest_validation::worker_rejects_changed_config_generation_before_workspace_side_effects
- session_worker::runner::tests::credentials legacy no-source provider cells (13)
- tools::sessions_spawn::tests::child_authority (module: batch_v3_verifies_through_store_fallback,
batch_v4_refuses_missing_parent_row, launch_v3_*, delegated child outcome/evidence cells)
- agent::turn_tests::engine_switch::{bound_child_context_keeps_scope_pin_and_grant} and the
admit_bound_child_segment fixtures; turn_context::tests::child_turn_context_funds_recursive_money_only_through_the_parent_grant;
admission_matrix::budget::segment_context_carries_budget; turn_decision::tests::execution::child_zero_budget_publishes_no_costed_direct_ref;
admission_matrix::launcher_authority_cells
- tools::capability::child::recursive_tests recursive-spawn cells (3); providers credential
rotation_keys_follow_the_root_connection; entrypoint worker cell
- decision store shared/store_preparation cells using removed lookups
- tests/session_worker_stdin_protocol.rs sealed_route_worker_sends_only_its_route_key_on_wire (delegated e2e)
Retargeted: shell_parity/tool_tiering assertions -> ordinary_child_publication;
recorded_chain/skill_receipts/turn_context -> terminal_settlement_ref; carve_child -> carve_ordinary_child.
Scanners: memory.rs/panic_policy.rs child_process entries, providers.rs worker factory site.
Acceptance A4: 188 lines / 50 files (1b87566) -> exit 1.
…nd terminal arms, scanners deleted
P2-R20: delete runtime/decision_journal/**, child_source/authority_journal.rs,
child_source/recovery.rs, the child outcome hook, runtime/causal_events* (sink,
repair, routes, worker), ingress_recovery/child_telemetry.rs, turn_decision
store_preparation, the turn_cleanup prepared-store drains and the service
store/durable_events/child_recovery fields. KeyDomain::{IngressRecovery,
ExplorationSeed} deleted (no user). load_key moves to turn_publication/builder.
Execution trace types move to tools/capability/execution_trace.rs.
P2-R21: IngressRecorder::prepare is repository-only; v1/v2 capsule arms,
legacy_key, LegacyEvidence, PreparedAdvisory, open_advisory_store,
recovery_only_legacy deleted; the SQLite scan selects only capsule version 3
in SQL. RecoveryScope::prepare: recordable = recording on && repository ready.
Test runtime::ingress_recovery::tests::legacy_capsules_are_ignored_without_key_reads.
P2-R22: DecisionSettlementRef, validate_durable_chain, PreparedReplay, the whole
agent/terminal/replay module (terminal_replay_v1), served_auxiliary.rs, the
recorded branches of finalize_turn_impl and recovery_commit::claim_semantic,
semantic_mac_v2/decision_id claim fields, OutcomeCorrelator/TerminalFacts
(causal_tree/outcome.rs), settlement_ref and the rejoin_terminal_inner legacy
branch deleted. Execution trace and close flag move onto TurnRuntimeContext.
Test agent::turn_tests::engine_switch::post_deletion_turn_commits_terminal_without_decision_rows
(cells a, b, b2, c, d).
Cascade (sole consumers deleted): causal_tree/{refusal, decision_select,
candidate_generator bridge}.rs, decision_engine/decision_score.rs, EngineDecision
reduced to decision_id/deadline/state/outgoing child, CandidateSet::NoLegalPath
payload, TurnDecisionContext hop/audit methods, DecisionId::parse and
CausalActionKind::ALL moved to cfg(test) test-support modules.
P2-R25: retire causal_domain, decision_seals, decision_terminals scanners and
their probes; AG-10 inverted (no production file opens a legacy decision
database); new decision_engine::no_legacy_decision_artifacts with planted
fixture; deleted paths dropped from memory, panic_policy, process,
retired_feature, NEUTRAL_HOMES.
P2-R26: plain_abstention_fixture and is_plain_answer_abstention already absent;
the delegate deadline test is already the no-decision variant.
G3 orphans deleted: security/approval_ledger/tests/historical_exact_call_approval/*.
Tests deleted (decision-only, D§2.6 or legacy store/replay): turn_decision tests
agent_decision, catalog_drift, enabled_service, execution, recorded_chain;
terminal_scope guard-link, disabled-store, fingerprint-reseal, recorded-rejoin
cells; ingress auth_02_2b_tests (plane-on store), auth_02_2a matrix/legacy
chain/outcome cells, authority_tests legacy MAC compatibility,
copied_workspace_terminals_verify_through_the_real_store,
ingress_recovery_unchanged_by_switch,
ingress_recovery_off_with_causal_tree_disabled_creates_no_key_or_store; chat
persist_restart legacy-seal, empty-store, missing-source, unauthenticated-marker
and queued-decision cells; causal_events tests; decision store timeout probes;
legacy generator approval-report assertions.
A5d: tests/architecture_boundaries/decision_engine.rs only. A5e: exit 1.
A5f: src/agent/turn_tests/engine_switch.rs only. audit_hops: exit 1.
A5a 1214/222 -> 752/174; A5b 708/153 -> 661/138; A5c 44 -> 20 files.
…xt; structural engine; delete causal_tree P2-I2 check (G5a ruling): holds on 0d7c9b7. With a repository and recording on (`MemoryFabric::records_recovery_terminal`), every terminal commits through `recovery_commit::finalize_recovery_terminal`: E2 claim MAC over the persisted semantic (OV-9), settled receipt facts (E5/E4) and the cost outbox (E7) in one `commit_recovery_terminal`; restart rejoin (`rejoin_terminal_inner` -> `load_settled_facts`) verifies the receipt, the chain evidence, the semantic <-> payload comparison and E2/usage/outbox (`restart_verify`). No restoration commit was needed. G5B-R1/R2 (P2-R19): `TurnDecisionService` -> `turn_publication::service:: TurnRuntimeService`; `TurnDecisionContext` -> `turn_context::OpenedTurn` (runtime, owner filesystem, actor, service id, main compaction, deadline). Opening, admission (`admit_opened_context`), execution binding, surface binding, child scope (+ `authority_within_policy`), call approval (gate: `recordable`), owner filesystem move into `runtime/turn_context/`; `verify_operator_spawn_source` into `child_source/publication/operator.rs`. `has_decision_work` deleted (services always retained); `drain_advisory`. `PublicationBuildError` -> `TurnRuntimeBuildError` (`ChildAuthority` -> `WorkerSurface`). Holders: `channels/turn_source/{publication_slot, admitted_turn}.rs`, `gateway/turn_source/publication_slot.rs`; field renames `decisions`/`decision_slot` -> `publication_slot`, `turn_decisions` -> `turn_service`, `publish_turn_runtimes`. Fixtures deleted (evidence, selected-loader, ordinary-child); wrapper calls unwrapped to `Box::pin(inner)` (keeps heap placement). G5B-R3 (P2-R23): `src/causal_tree/` deleted. `admission_facts.rs` -> `tools/surface_owner/facts.rs::PublicationFacts`. Engine is structural-only: `admission_probe.rs` deleted, `GenerationError` moved to `candidate_generator.rs`, `validate_structure`, no probe parameter, approval-only/exact-call machinery and `approval_candidate`/ `collectable_approval_entry`/`names_entry` deleted; `CandidateSet::Legal` keeps candidates + exact mentions. `CausalActionKind::RequestApproval` deleted (its only constructor was `approval_candidate`). `effective_approval_required` removed (state, canonical, projection). `hash_candidate_set` keeps the empty approval-scope encoding. Restart verifier: closed claim key set instead of naming legacy keys. G5B-R6: AG-28 re-added as `turn_state.rs::trust_bearing_turn_state_is_ built_only_by_the_turn_opening` (+10 probes); loop-request scanner renamed; compaction/tool_tables/process/providers/scanner_probes paths. Tests moved: pinned_policy_version_is_order_independent_and_tracks_policy_ changes -> turn_publication::service::tests; discovery_surface, skill_receipts -> turn_context::tests; terminal_scope -> agent::terminal::tests. Restored (G5a had deleted them, G5b R1.2 keeps them live): agent_budget_uses_pinned_route_and_read_only_spend_snapshot, agent_hint_route_drift_is_refused_before_credential_resolution, verified_native_tools_requires_matching_source_selection -> turn_context::tests::publication_scope; discovered_spec_with_changed_schema_still_fails_bind -> turn_context::tests::execution_binding. Added: candidate_generator::tests::{structural_set_rejects_duplicate_ candidate_ids, structural_set_requires_a_refusal_path, structural_ordering_and_limits_are_preserved}; questions::tests::candidate_hash_separates_mentions_and_keeps_its_pre_ change_bytes (pinned literal). Deleted (gate/approval annotation only): admission_probe::tests (all five R14 tests), causal_tree::hard_gates_probe::legacy_generator_tests, questions::tests::hard_gated_candidate_is_absent_from_compiled_request, questions::tests::candidate_hash_separates_mentions_from_approval_scope (replaced), surface_owner::tests::publication_rules_match_pre_strip_ direct_surface (HardGates parity). Rewritten: decision_advisory::tests:: engine_driver_analyses_the_structural_set (was ..._with_advisory_probe), projection::tests::projection_renders_the_intrinsic_approval_requirement. Renamed for A5a: four test names containing `turn_decision`; doctor `ModelProbeOutcome` -> `ModelProbeVerdict` (B4 substring). Local test struct engine_switch::OpenedTurn -> OpenedAgentTurn (B6). Acceptance (before -> after, lines/files): A5a 752/174 -> 185/89, A5b 661/138 -> 652/132, A5c 20 -> 0 files, B1 228/79 -> 193/59, B2 349/90 -> 0, B4 209/50 -> 0, B6 = the three structs (enum comes with commit 2). Every remaining A5a/A5b/B1 hit is the `[causal_tree]` config (`config::schema::causal_tree`, `causal_tree.enabled/backend/scoring`), i.e. P2-R24, which is blocked on a ruling (CausalPolicy destination).
…P2-R24)
Per the G5b/R24 ruling 2026-11-16:
- (1) `[decision_engine]` gains latency_budget_ms (u64, default 500, 50..=5000),
token_ratio_limit (f32, default 0.35, finite > 0) and max_candidates
(u8, default 12, 1..=32): today's causal_tree policy defaults and bounds.
Readers moved: turn budget/deadline and token reservation
(publication_scope), advisory and exact-mention caps (decision_advisory,
child_scope), control ladder, lifecycle validation. The admin mutation
allowlist (`engine_setting`) writes the three keys; SetPolicy/PolicyPatch/
ResetPolicyToDefaults/SetEnabled deleted (no production constructor; the
CLI enables through SetEngine(Enabled)). SetBackend raises a lower latency
budget to the catalog recommendation and keeps a larger one.
- (2) No `[decision_engine.backend]` => the backend's serde default
(static DEFAULT_BACKEND). migrate_backend, effective_backend,
inherited_backend, empty_tables_only deleted.
- (3) durable_key deleted (service, plane status, control ladder). recordable =
OV-13 (RecoveryScope.recordable: recording on AND activated repository) in
build_publication and the operator process; factory keys are the persisted
runtime key. Plane-gated refusals (EventStoreUnsupported,
InboundEventsDisabled, operator worker recording, source "requires durable
input" ensures, accounting-scope gate, auxiliary gate) removed; auxiliary
receipt durability follows MemoryFabric::records_recovery_terminal.
Console recovery/approvals/projection follow console_recordable (OV-13).
with_process_recovery(true) (chat: controlled.is_none()).
- (4) decision_latency_budget_warning and extra_latency_budget_ms_explicit
deleted with their tests; no replacement warning.
Deleted: config/schema/causal_tree.rs (+ migrate_legacy,
normalize_regeneration_document, CausalPolicy, Calibration/Rehearsal/
Scoring/Store/Evaluation configs), causal_tree_config_tests.rs, the init
causal regeneration guard, config/fixtures/agent-full-base-8a5d160d.toml,
deprecations::file_holding, the [causal_tree] init template block. Backend
types moved to config/schema/decision_engine/{backend,backend_kind}.rs
(CausalConfigError -> BackendConfigError, messages name decision_engine.*).
A [causal_tree] table falls under the loader's unknown-path refusal; no
warning, importer or alias. Risk classification, secret paths, config.patch
guard, provider uses and reference_use retarget to [decision_engine].
Control-ladder layer renamed decision_engine.
Tests deleted (legacy only): causal_tree_config_tests::*, causal_tree.rs inline
tests, decision_engine_config_tests legacy-copy/W1-W3 cells,
init::the_base_full_template_disable_reads_as_unset,
persistence::explicit_hosted_latency_ceiling_loads_without_an_upgrade_warning,
persistence::schema_one_hosted_backend_warns_on_load_..., paths::load_path_treats_
the_pre_catalog_serialized_latency_default_as_unset,
defaults_and_integrations::hosted_latency_warning_does_not_change_the_configured_ceiling,
mutation::set_backend_preserves_an_explicit_latency_budget_equal_to_the_default,
mutation::policy_patches_are_explicit_and_validated.
Tests added/rewritten: decision_engine_config_tests::{turn_limits_have_their_defaults_and_bounds,
a_causal_tree_table_is_an_unknown_path, absent_engine_backend_is_the_serde_default,
effective_backend_reads_the_engine_table}, mutation::{turn_limits_are_engine_settings_and_validated,
set_backend_raises_only_a_lower_latency_budget}, config.patch/POST /api/config/generation
round trips on [decision_engine]. Plane fixture params removed or mapped to
memory.events.record_user_messages where the cell is recorded vs unrecorded.
Scanners: causal_policy -> writers of config/schema/decision_engine*, chain
`.decision_engine`; decision_backend loopback path; probes retargeted.
tests/fixtures/config-schema.json updated by hand (causal_tree removed, three
keys added).
Acceptance (817ee4e -> this): A5a 186/90 -> 0 (exit 1); A5b 653/133 -> 0
(exit 1); B1 193/59 -> 0 (exit 1); A5c 0 files.
…rity; relaunch removed
G5B-R4 (recursion parity, production) and G5B-R5.3 (relaunch removal).
The R4.8 in-crate cells and the R5 real-parent worker harness follow in
the next commit.
R4:
- turn_context/child_scope.rs: the ordinary root's sealed parent set is
every permitted catalog entry (operator-root rule). The
allow_recursive_delegation capability_search capture and the
delegator-only capture are deleted; depth, inherited branch and the
allocation-free early return are unchanged.
- child_source/publication.rs: OrdinaryChildPublication = { inner, scope }.
PartialEq compares both halves; new same_parent, with_recursive_delegation
(ForeignParent, NoDelegator, DepthExhausted, Manifest, Caller) and
verify_derived_from. verify_caller/verify_live/dispatch_pin/allows_tool/
verify_task_scope/allocate_child_budget read the selected scope.
- tools/execution.rs: ChildCallContext::with_ordinary_publication re-scopes
the caller only onto an object sharing its authenticated parent.
- sessions_spawn: refuse_recursive_request -> requested(args) (booleans
only); spawn re-scopes the caller when allow_delegation is true and the
caller carries an ordinary publication; operator sources are unchanged.
Schema text rewritten; "recursive grants permit one child" deleted;
goldens updated.
- SessionsSpawnConfig.{allow_recursive_delegation, max_recursive_depth} and
config/schema/recursive_spawn.rs deleted (no deprecation or warning; the
parser's unknown-key behaviour applies). Default moves to agent.rs.
h2_entry "refuse recursive process delegation" check deleted.
tests/fixtures/config-schema.json edited to drop both keys. Docs
(configuration.md, tools.md) state the parity rule.
R5.3 (FU-PROCESS-RELAUNCH):
- ChildSessionRegistry::{relaunch, relaunch_record, relaunch_worker} and
RelaunchIdentityError deleted. RelaunchRecipe stays as mailbox record
data; ExecRef stays (mailbox producers).
Tests renamed:
- tools::sessions_spawn::delegation::tests::
recursive_request_is_refused_without_a_decision_issued_grant ->
recursive_request_parses_only_booleans (true is now accepted).
Tests deleted (reason: relaunch removed):
- chat::sessions::child::tests::{relaunch_keeps_session_addr_and_mints_new_run,
concurrent_history_insert_and_relaunch_keep_both_updates}
- memory::sqlite::tests::mailbox::{send_before_and_after_task_reopen_uses_same_session_addr,
run_pinned_message_nacks_after_relaunch}
- tests/session_worker_stdin_protocol.rs::{relaunch_real_worker_keeps_session_addr,
relaunch_refuses_manifest_identity_mismatch_before_record_update,
relaunch_scope_key_separates_session_and_agent_and_is_stable}
Tests trimmed (relaunch steps removed):
- child_registry_is_excluded_from_picker_resume_and_latest (newest activity
is now an insert)
- relaunch_and_insert_preserve_complete_child_record ->
insert_preserves_complete_child_record
- child_sessions_owner_and_agent_erase_remove_records_and_block_relaunch ->
child_sessions_owner_and_agent_erase_remove_records
Tests deleted (reason: recursion-only vetoes and config keys deleted):
- config::schema::recursive_spawn::tests::{recursive_depth_two_is_refused_at_the_configuration_boundary,
recursive_spawn_permission_is_default_off_and_requires_positive_depth}
- the allow_recursive_delegation cell of
h2_entry::profile::tests::strict_profile_refuses_executable_and_remote_factories_before_writes
Acceptance (36f6ba1 -> this): B3 1 -> 0 files; B5 24/7 -> 0 (exit 1);
B6 3 -> 4 files; B7 35/11 -> 0 (exit 1). A5a/A5b/B1/B2/B4 stay exit 1,
A5c prints nothing.
…rsion cells
Parity default (controller ruling "G5b c2a ruling 2026-11-14"): an omitted
`allow_delegation` on sessions_spawn now means true. Every ordinary child
gets the derived recursive publication by default; only an explicit `false`
keeps the captured, non-delegating scope.
- delegation::requested: None | true -> true; false -> false; other values
are still refused ("allow_delegation must be a boolean").
- OrdinaryChildPublication::select_for_spawn(caller, recursive): the derived
scope, or the captured object itself for an opt-out. spawn.rs re-scopes the
caller through it and ChildCallContext::with_ordinary_publication.
- Schema text "default true ... Set false for a child that cannot spawn",
`default: true`; both sessions_spawn goldens updated; docs/configuration.md
and docs/tools.md describe the default.
Tests (written, not run locally):
- runtime::child_source::tests::recursive_derivation_shares_the_authenticated_parent
(a) derived keeps sessions_spawn at depth parent-1, seal verifies,
same_parent && !=; (b) a second bound turn's publication -> ForeignParent and
verify_derived_from refuses; (c) a depth-1 parent -> DepthExhausted;
(d) select_for_spawn(false) is pointer-equal to the captured object.
- tools::sessions_spawn::tests::recursive::{task_child_runs_under_the_derived_publication,
full_root_and_child_spawn_without_grant, supervised_child_follows_root_dispatch_approval
(layer 1 only, see report), read_only_root_spawn_is_refused_as_without_recursion,
root_without_delegate_derives_a_recursive_child,
exhausted_allowance_spawns_a_zero_funded_child,
omitted_flag_child_spawns_until_the_depth_bound}.
- recursive_request_parses_only_booleans: an omitted flag is now true.
- task_mode_no_tools_preserves_single_turn_trace_usage: its scripted spawn now
passes allow_delegation=false (the cell asserts a tool-less child).
… strategy; omitted flag falls back at the bound
Ruling (1), Supervised child approval parity: a task child's turn adapter
dispatches its published execution under the run's production
AgentToolApprovalStrategy (run approval manager + resolver from the
SpawnApprovalResolverFactory), as a root turn does. Without a resolver it
refuses with the same literal as the root. ToolExecutionService::with_approval
(promoted from the cfg(test) with_test_approval) swaps only the strategy.
Layer 2 of supervised_child_follows_root_dispatch_approval added.
Ruling (2), omitted-flag fallback: DelegationRequest { Omitted, Explicit }.
An omitted allow_delegation that hits a bound (NoDelegator, DepthExhausted,
NotStrictSubset) issues a non-delegating child, as false does; integrity
refusals are never masked; explicit true keeps the typed refusal. Chain cell
and derivation cell (c) updated; schema text, goldens and docs updated.
…estored worker tests R5.1: tests/ordinary_process_worker.rs with helpers parent.rs, provider.rs and scan.rs. Real `prx chat --plain` parents (CARGO_BIN_EXE_prx) run with a cleared environment, a process-local 0700 HOME and OPENPRX_SESSION_WORKER_SECRET_PATH=<home>/session_worker.secret, shared by the workers and a restarted parent (no SESSION_WORKER_SECRET, no production seam). Named bounds: MAX_REQUEST_HEAD_BYTES 64 KiB, MAX_REQUEST_BODY_BYTES 1 MiB, REQUEST_READ_TIMEOUT 3 s, MAX_CAPTURED_REQUESTS 256, MAX_PARENT_OUTPUT_BYTES 4 MiB per stream, PARENT_DEADLINE/WORKER_DEADLINE 180 s, HOLD_WAIT 30 s, ACCEPT_POLL 5 ms, scan caps 64 MiB/4096 files. stdout/stderr drained on two threads; Drop guards kill and reap the parent, release holds, stop and join the server (bounded). R5.2 (moved from the in-crate probe and P2-R18 cells, now in tests/): session_worker_persists_no_secret_from_a_reply, session_worker_persists_no_secret_from_a_provider_error (sentinel AKIAIOSFODNN7EXAMPLE, pinned bodies), process_child_issues_without_decision_records, batch_children_issue_without_decision_records, restarted_parent_recovers_and_verifies_ordinary_launch. R5.4: sealed_route_worker_sends_only_its_route_key_on_wire restored from 74e193f^ with P4 (opt-in succeeds), P5 (ordinary-source scope checks, pins removed), P7 (fan-out with funding conservation) and the ordinary refusal literals; forged capabilities are signed with T read from the secret file. nextest: the new binary takes two slots and up to 180 s.
P2-R27: the decision inspector page is deleted; DecisionPlanePage becomes IntentAnalysisPage (status, effective backend, last 20 analyses from /api/decision-engine/*, write-only credential). api.js moves to /api/decision-engine/* and drops the causal calls and the deleted approval resume route; the approval panel keeps approve, reject and revoke. console/dist is rebuilt. P2-R28: docs/decision-plane.md is merged into docs/decision-engine.md with the fresh-workspace and 410 notes; every backlink and remaining mention of [causal_tree], the deleted CLI and routes, relaunch and the recursive keys is retargeted to the end state, including the new [decision_engine] turn limits in docs/configuration.md. CHANGELOG records the breaking removals and default-on recursive delegation. The shared worker harness no longer needs #[allow(dead_code)]: the restart controls move to tests/ordinary_process_worker/restart.rs and harness faults answer through Reply::Raw. A6: 12/3 before -> only the 410 note in docs/decision-engine.md. A7: 13/8 before -> exit 1.
…gets, default and all features
New test files carry #![cfg(test)] so the scanners read them as test code; the restart tests become the agent::terminal::tests::restart module instead of an include!; the status DTO field is engine_status (serialized as decision_engine) so the policy scanner sees no config write; the provider label guard follows the claim redaction into recovery_commit.rs; the legacy artifact scanner gets a planted probe; golden_vectors.rs and the restart cells' brain.db edits are listed.
…mes the artifact literally
…ckend selection never changes latency_budget_ms F1: engine_setting matches the exact P2-R8 allowlist first, so prompt_budget_tokens and token_ratio_limit are accepted; unknown and credential-bearing keys are refused. CLI (tests/cdp_cli.rs) and HTTP (config_apply_accepts_allowlisted_token_keys) success tests. F6: a selection whose catalog latency recommendation exceeds the configured budget is refused with CausalMutationError::LatencyBudgetBelowRecommendation naming both values, engine on or off. set_backend_raises_only_a_lower_latency_budget replaced by set_backend_never_changes_the_latency_budget.
…le row and stops with process shutdown F2: the inline path re-arms whenever it leaves a pending/error row (Err or Error state); a failed, cancelled or deadline-cut pass is never exhaustion and retries on the back-off; only an exhausted scan with no retryable metered row idles. Re-arm uses an epoch plus notify_waiters, so a re-arm during a pass is not lost. F8: CostOutboxProjector::start takes the process shutdown token (child token) at the gateway, channels and chat entries; the entry owns the handle and awaits stop(), bounded by the 15 s pass deadline; passes stop at the next row on cancel. F7: bounded ledger read and sync_channel(1) in cost_recovery tests. Tests: background_scheduler_rearms_after_empty_pass_and_retries_transient_failures, failed_or_incomplete_passes_are_retried_on_the_back_off, projector_ends_with_the_process_shutdown_token.
…retained settlement evidence F3: a failed, cancelled or refused turn records the cost of the metered usage retained in RetainedProviderTrace, the evidence the terminal settles from. Real-turn test ended_turns_record_the_settled_metered_cost (metered round, then failure / cancellation / send refusal; 2 000 000 micro-USD each).
… for_child bytes against literals F4: golden_constraints_and_effective_config_payloads compares the full production payload with prefix literal + golden_effective_config.json (sorted compact JSON from an independent encoder) + ']'; the seal is a pinned literal recomputed with ring over the literal. for_child_fingerprint_encoding_is_unchanged pins the SHA-256 of the literal preimage.
… with WorkerManifestUnsupported F9: parse_worker_manifest_line maps an inline decode failure to WorkerManifestUnsupported; inline_pre_strip_manifest_is_worker_manifest_unsupported asserts the type through the reader. F7: sync_channel(1) in transport_key tests.
…recommendation explicitly F6 follow-on ruling: setup and onboarding (DecisionSetup::check, check_hosted, apply, apply_hosted) lead the plan with latency_budget_ms = the catalog recommendation when the written budget is lower (with_recommended_latency_budget), in the same transaction. The plain mutation API keeps refusing. Test: decision_engine_cli::tests::wizard_hosted_openrouter_writes_the_recommended_latency_budget.
…roduction skills_manage
F5 ruling: (b) wiring for publish, annotate, rollback and retire: production
SkillsManageTool execution on a temporary lifecycle repository; approved reaches the
lifecycle service past consume, verify and the exact grant; denied is never admitted;
a repeat is refused at consume. (a) end to end for annotate on the experiments fixture:
approve writes exactly one adoption record, deny none, repeat nothing more.
Test support: h2_entry::test_support::ReviewedGateway and profile::tests::{profile_over,
origin_of} (test-only). Added revoked_launch_cannot_approve_or_admit (exact digest only;
a revoked launch neither approves nor admits). No skills behaviour, action or test removed.
…ery backend selection entrypoint The catalog latency_budget_ms recommendation is checked once on the resulting backend selection in CausalConfigService::mutate, whenever a mutation selects the backend (SetBackend, ResetBackendToAuto, the backend.kind/endpoint/model keys of config set and the Gateway), with the engine on or off. Setup keeps writing the budget explicitly. CLI and HTTP refusal tests cover SetEngine, both enabled states, an unchanged stored config, and success after raising the budget. cdp_cli reads config.toml under a named byte cap.
…tFound is an absent ledger
…s instead of sleeping A cfg(test) PassObserver field reports each scheduler pass on a bounded channel. The test waits (bounded) for the exhausted startup pass and a failed scheduled projection, only then clears the ledger failure, and asserts the acknowledging pass and exactly one ledger entry.
… TerminalNotReplayable load_settled_facts normalizes every D§4.4 failure (receipt authentication, facts parse, identity mismatch, evidence, a non-settled receipt, a repository store without recovery authority) to TerminalNotReplayable, keeping the cause in the chain. A missing receipt stays LegacyUnconfirmed. The negative restart cells assert the type; the receipt-tampering cells lift and restore the immutability trigger, and the prepared-parameters cell is non-vacuous.
… task ledger, console transcript, quarantine, approval gate - sessions_spawn derives a recursive scope only when the child's own executor and surface can run sessions_spawn (else NoDelegator: an omitted flag falls back, an explicit true is refused) (G5b c2a/2b rulings) - a child publishes manifest members directly unless capability_search is on its own surface (in-process delegate/task children, P2-R15) - task-mode child executor keeps the parent's idempotency ledger - recorded console turns project the committed assistant event into the transcript (the deleted replay projection did this) - restart scan quarantines TerminalNotReplayable / LegacyUnconfirmed terminals instead of failing startup (D§4.4, P2-R22 cell d) - approvals: recording off -> 409 disabled; no recovery repository -> 503 (OV-13) - worker manifest: structural checks before the P2-R17 source steps - ordinary lineage refusal names the differing fields
…aviour Rewritten (class a): decision-store reads -> no-store assertions (P2-R20, P2-I1); enabled-plane receipt rule -> unrecorded proof carries no source event (P2-R22); projector replaces scope-prepare projection (P2-R5); repository-less backend gets no recorder (P2-R21); [causal_tree] fixtures -> [decision_engine] (P2-R24); runtime key path (OV-2); analysis rows precede the outcome (P2-R10); execution_trace null in terminals (D§4.2); enabled-helper children use the production provider selection (P2-R15). Deleted: doctor_reports_a_below_catalog_hosted_latency_budget (R24 ruling 4: the warning and its tests are deleted).
…/2 test and help updates
…ldren, console transcript rejoin, missing receipt not replayable
… the projection through the SQLite test helper
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.
Decision-engine strip, Part 2: legacy decision data and compatibility removed
Part 1 made the decision engine advisory-only and independent. Part 2 deletes what the old gating decision plane left behind. Development phase: no migration, compatibility shims or importers.
What changes
src/causal_tree/, the decision store and journal, legacy decision recovery, the[causal_tree]config section, decision-bound approval grants and/approvals/{decision_id}/resume, process relaunch, and the scanners that guarded the deleted code. Retired routes answer 410.prx init --decision-enableturns on the advisory engine.TerminalNotReplayable. A terminal that fails verification is quarantined instead of blocking startup.Specs and audits
REQ-DECISION-ENGINE-STRIP-P2.md(+ G5B addendum, controller rulings), designDESIGN-P-DECISION-ENGINE-PART2-MIGRATION.md(both Codex-audited).Verification (before this PR)
Full CI gate set mirrored on the qaa build host at effee62: same rustc 1.99.0, nextest 0.9.151 profile
ci, test_home_guard and shard filter.After landing
A full
prx chatsession with a real provider, built from main, is the real test. It covers tools, approval, engine on/off, child and process-mode child, restart, retired surfaces, cost, the network guard and a gateway webhook turn.