From fb989bbbd0f9f8f595daaad9e9533cdf93d6e0e0 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 27 Sep 2026 03:10:58 +0000 Subject: [PATCH 1/2] refactor(mcp): answer info and runtime reads through their owners tracedecay_status, tracedecay_active_project, tracedecay_remote_status and tracedecay_runtime are graph-tool operations the project's graph-tool owner answers, and tracedecay_project_list, tracedecay_project_search and tracedecay_project_context are profile registry reads the daemon's profile owner answers for every connection, with or without a project. Each decodes its arguments against a typed request, so an unknown key or a wrong type is refused instead of ignored, and each result is a typed catalog result that serializes to the JSON these tools already emitted. The projectless connection's hand-written registry path is folded into the profile owner, and the per-server registry read port is gone. The doctor and remote-status types derive JsonSchema. A route refusal from an owner now keeps its reason code instead of reading as a config error. --- .../src/http/application_operation_owner.rs | 9 +- crates/tracedecay-cli/src/tool_command.rs | 88 +- .../tests/core_cli_suite/tool_daemon_test.rs | 119 ++- .../core_cli_suite/tool_first_touch_test.rs | 19 +- .../src/code_index_freshness.rs | 4 +- .../tracedecay-contracts/src/doctor/report.rs | 2 +- .../src/doctor/sources.rs | 17 +- crates/tracedecay-contracts/src/graph_tool.rs | 25 + crates/tracedecay-contracts/src/lib.rs | 7 +- .../src/project_registry.rs | 95 +- .../tracedecay-contracts/src/remote/status.rs | 9 +- .../src/retrieval/catalog.rs | 69 +- .../tracedecay-contracts/src/retrieval/mod.rs | 14 + .../src/retrieval/project_info_surface.rs | 471 ++++++++++ .../tracedecay-contracts/src/sdk_catalog.rs | 9 +- .../src/storage/telemetry.rs | 2 +- .../src/application_surface.rs | 11 +- .../src/application_surface/invocation.rs | 19 + .../src/contract/mod.rs | 59 +- .../src/adoption_observation.rs | 23 +- .../src/invocation/dispatch.rs | 8 +- .../invocation/invocation_observability.rs | 1 + .../src/mcp_project_registry.rs | 15 +- crates/tracedecay-domain/src/errors.rs | 4 +- crates/tracedecay-domain/src/remote.rs | 13 +- crates/tracedecay-domain/src/research/id.rs | 13 +- .../tracedecay-mcp-catalog/src/definitions.rs | 14 +- .../src/definitions/admin.rs | 116 +-- .../src/definitions/application.rs | 13 +- .../src/definitions/application_schema.rs | 11 - .../tracedecay-mcp/src/handlers/graph_tool.rs | 28 +- .../tracedecay-mcp/src/handlers/health/mod.rs | 2 +- .../src/handlers/health/runtime.rs | 207 ++--- .../tracedecay-mcp/src/handlers/info/mod.rs | 9 +- .../src/handlers/info/registry.rs | 424 ++++----- .../src/handlers/info/remote_status.rs | 50 +- .../src/handlers/info/status.rs | 814 ++++++++---------- crates/tracedecay-mcp/src/handlers/support.rs | 23 +- crates/tracedecay-mcp/src/tools/binding.rs | 17 +- .../tracedecay-tool-catalog/src/operation.rs | 21 + crates/tracedecay/src/daemon.rs | 1 + ...e_index_runtime_generation_census_tests.rs | 8 +- .../src/daemon/invocation_dispatch.rs | 14 +- .../src/daemon/invocation_executor.rs | 1 + .../invocation_state/project_invocation.rs | 23 + .../tracedecay/src/daemon/profile_registry.rs | 145 ++++ .../tracedecay/src/daemon/profile_retained.rs | 96 ++- crates/tracedecay/src/daemon/projectless.rs | 90 +- .../src/daemon/retained_test_support.rs | 50 +- .../daemon/tests/multi_root_execute_mcp.rs | 2 - crates/tracedecay/src/mcp/server.rs | 16 +- .../src/mcp/server/graph_tool_owner.rs | 10 + .../src/mcp/server/requests/tool_dispatch.rs | 12 +- .../mcp/tools/handlers/application_surface.rs | 14 +- .../handlers/configuration_dispatch_tests.rs | 6 - .../context_scout_control_dispatch_tests.rs | 2 - .../src/mcp/tools/handlers/dispatch_groups.rs | 191 ++-- .../dispatch_groups/health_dispatch.rs | 41 - .../tools/handlers/dispatch_test_support.rs | 13 +- .../src/mcp/tools/handlers/dispatch_tests.rs | 68 +- .../info/remote_status_dispatch_tests.rs | 14 +- .../tracedecay/src/mcp/tools/handlers/mod.rs | 57 +- .../retained_timeout_dispatch_tests.rs | 10 - .../runtime_behavior_dispatch_tests.rs} | 56 +- ...untime_generation_census_dispatch_tests.rs | 4 +- .../src/test_support/host_admission.rs | 50 +- crates/tracedecay/src/test_support/mod.rs | 1 + .../tests/mcp_suite/mcp_cli_serve_test.rs | 12 +- .../tests/mcp_suite/mcp_handler_test.rs | 2 +- .../mcp_suite/mcp_handler_test/admin_test.rs | 226 ++--- .../mcp_suite/mcp_handler_test/edit_test.rs | 39 +- .../mcp_handler_test/graph_analysis_test.rs | 184 ++-- .../info_health_request_test.rs | 314 +++++++ .../mcp_suite/mcp_handler_test/lcm_test.rs | 34 +- .../mcp_handler_test/move_symbol_test.rs | 18 - .../mcp_handler_test/project_context_test.rs | 50 +- .../mcp_handler_test/project_list_test.rs | 15 +- .../project_search_behavior_test.rs | 67 +- .../mcp_handler_test/remote_status_test.rs | 15 +- .../mcp_handler_test/replace_symbol_test.rs | 2 +- .../mcp_handler_test/session_search_test.rs | 15 +- .../source_edit_reconcile_test.rs | 15 +- .../mcp_handler_test/status_runtime_test.rs | 77 +- .../mcp_server_test/protocol_test.rs | 17 +- .../mcp_suite/mcp_server_test/support.rs | 2 + crates/tracedecay/tests/mcp_suite/support.rs | 88 +- .../tests/mcp_suite/workflow_query_test.rs | 6 +- 87 files changed, 2794 insertions(+), 2273 deletions(-) create mode 100644 crates/tracedecay-contracts/src/retrieval/project_info_surface.rs create mode 100644 crates/tracedecay/src/daemon/profile_registry.rs delete mode 100644 crates/tracedecay/src/mcp/tools/handlers/dispatch_groups/health_dispatch.rs rename crates/tracedecay/{tests/mcp_suite/mcp_handler_test/runtime_behavior_test.rs => src/mcp/tools/handlers/runtime_behavior_dispatch_tests.rs} (80%) create mode 100644 crates/tracedecay/tests/mcp_suite/mcp_handler_test/info_health_request_test.rs diff --git a/crates/tracedecay-api/src/http/application_operation_owner.rs b/crates/tracedecay-api/src/http/application_operation_owner.rs index e56d227e30..3dc0f33cd5 100644 --- a/crates/tracedecay-api/src/http/application_operation_owner.rs +++ b/crates/tracedecay-api/src/http/application_operation_owner.rs @@ -159,7 +159,14 @@ pub const fn http_application_owner_kind( | ApplicationSurfaceOperation::Analytics | ApplicationSurfaceOperation::Search | ApplicationSurfaceOperation::RunAffectedTests - | ApplicationSurfaceOperation::Dashboard => return None, + | ApplicationSurfaceOperation::Dashboard + | ApplicationSurfaceOperation::Status + | ApplicationSurfaceOperation::ActiveProject + | ApplicationSurfaceOperation::RemoteStatus + | ApplicationSurfaceOperation::Runtime + | ApplicationSurfaceOperation::ProjectList + | ApplicationSurfaceOperation::ProjectSearch + | ApplicationSurfaceOperation::ProjectContext => return None, ApplicationSurfaceOperation::FactStoreCurate | ApplicationSurfaceOperation::FactStoreAdd | ApplicationSurfaceOperation::FactStoreSearch diff --git a/crates/tracedecay-cli/src/tool_command.rs b/crates/tracedecay-cli/src/tool_command.rs index 6f008d7869..b7863c0049 100644 --- a/crates/tracedecay-cli/src/tool_command.rs +++ b/crates/tracedecay-cli/src/tool_command.rs @@ -120,17 +120,6 @@ const FIRST_TOUCH_STORE_TOOLS: &[&str] = &[ "tracedecay_lcm_expand_query", ]; -/// Tools that read the profile's project registry. They need no mounted -/// project: a project, when one is connected, only marks the active listing -/// entry. An explicit `--project` that is not an initialised project therefore -/// routes projectless instead of being refused for a project the read never -/// depended on. -const PROFILE_REGISTRY_TOOLS: &[&str] = &[ - "tracedecay_project_list", - "tracedecay_project_search", - "tracedecay_project_context", -]; - fn tool_deadline_range_error() -> TraceDecayError { TraceDecayError::Config { message: format!( @@ -227,6 +216,19 @@ fn run_inner( ) .await; } + if operation.is_profile_registry_read() { + let mut tool_args = tool_args; + let dispatch = DaemonToolDispatch::for_tool( + profile, + explicit_project, + tool_name, + &mut tool_args, + ); + return dispatch_cli_profile_registry( + profile, operation, tool_args, dispatch, raw_json, deadline, + ) + .await; + } if operation.is_graph_tool() { let project_path = DaemonToolDispatch::project_scoped(profile, explicit_project, tool_name) @@ -344,6 +346,16 @@ fn run_inner( ) .await; } + if let Some(operation) = ApplicationSurfaceOperation::from_tool_name(&def.name) + && operation.is_profile_registry_read() + { + let dispatch = + DaemonToolDispatch::for_tool(profile, explicit_project, &def.name, &mut tool_args); + return dispatch_cli_profile_registry( + profile, operation, tool_args, dispatch, raw_json, deadline, + ) + .await; + } if let Some(operation) = ApplicationSurfaceOperation::from_tool_name(&def.name) && operation.is_graph_tool() { @@ -847,6 +859,51 @@ async fn dispatch_cli_graph_tool( tool_result_process_outcome(&result.value, tool_name) } +/// Run one profile registry read through the daemon's profile owner and print +/// the same tool result its MCP call returns. The handshake's project, when +/// the dispatch names one, only marks that project active. +#[hotpath::measure(label = "cli.tool.profile_registry", future = true)] +async fn dispatch_cli_profile_registry( + profile: &ProfileRoot, + operation: ApplicationSurfaceOperation, + tool_args: Value, + dispatch: DaemonToolDispatch, + raw_json: bool, + deadline: Instant, +) -> Result<()> { + let tool_name = operation.mcp_tool_name(); + let request_id = + mint_global_request_id(GlobalRequestSurface::Cli).map_err(|_| TraceDecayError::Config { + message: "could not allocate an application surface request id".to_owned(), + })?; + let client = + tracedecay_daemon_identity::invocation_client_for_current(dispatch.handshake(profile)?)?; + let (request_deadline, cancellation) = cli_request_controls(&request_id, deadline)?; + let outcome = tracedecay::mcp::tools::execute_graph_tool_surface( + tracedecay_tool_catalog::BindingSurface::Cli, + operation, + tool_args.clone(), + Some(&client), + Some(request_id), + Some(request_deadline), + Some(cancellation), + ) + .await?; + let response_handle_root = cli_response_handle_root(profile, dispatch.project_path.as_deref())?; + let mut result = match outcome { + Ok(completion) => tracedecay_mcp::handlers::graph_tool::render_graph_tool( + response_handle_root.as_deref(), + &tool_args, + completion, + )?, + Err(refusal) => refusal.render(response_handle_root.as_deref(), &tool_args)?, + }; + account_tool_result(dispatch.project_path.as_deref(), &mut result); + tracedecay_mcp::tool_errors::mark_semantic_tool_error(&mut result); + print_tool_output(&result.value, raw_json); + tool_result_process_outcome(&result.value, tool_name) +} + /// Enrolled project's handle root, or none when that path has no store. fn cli_response_handle_root( profile: &ProfileRoot, @@ -921,7 +978,14 @@ impl DaemonToolDispatch { allow_init: false, }; } - if PROFILE_REGISTRY_TOOLS.contains(&tool_name) { + // Registry reads need no mounted project: a project, when one is + // connected, only marks the active listing entry. An explicit + // `--project` that is not an initialised project therefore routes + // projectless instead of being refused for a project the read never + // depended on. + if ApplicationSurfaceOperation::from_tool_name(tool_name) + .is_some_and(ApplicationSurfaceOperation::is_profile_registry_read) + { return Self::registry_scoped(profile, explicit_project, tool_name, tool_args); } Self::project_scoped(profile, explicit_project, tool_name) diff --git a/crates/tracedecay-cli/tests/core_cli_suite/tool_daemon_test.rs b/crates/tracedecay-cli/tests/core_cli_suite/tool_daemon_test.rs index 22b5811bc6..521cfc40d4 100644 --- a/crates/tracedecay-cli/tests/core_cli_suite/tool_daemon_test.rs +++ b/crates/tracedecay-cli/tests/core_cli_suite/tool_daemon_test.rs @@ -458,10 +458,34 @@ fn daemon_first_init_enrolls_a_clean_profile_from_a_linked_worktree() { ); } +/// Sends one MCP tool call through the daemon's project server, then reads +/// that server's tool-call counter from its typed status. Until the full +/// project server takes over from the core, the call and the status can land +/// on different servers, so the pair is re-sent until the status server has +/// counted a call. fn wait_for_tool_status_server_tool_calls(home: &Path, project: &Path) -> u64 { let project_arg = project.to_string_lossy().to_string(); let deadline = Instant::now() + CLI_ROUNDTRIP_TIMEOUT; loop { + let counted = tracedecay_command_with_home(home) + .current_dir(project) + .args([ + "tool", + "--project", + &project_arg, + "dashboard", + "--action", + "stop", + "--json", + ]) + .output() + .expect("tracedecay tool dashboard should run"); + assert!( + counted.status.success(), + "dashboard stop should succeed\nstdout:\n{}\nstderr:\n{}", + String::from_utf8_lossy(&counted.stdout), + String::from_utf8_lossy(&counted.stderr) + ); let output = tracedecay_command_with_home(home) .current_dir(project) .args([ @@ -486,23 +510,17 @@ fn wait_for_tool_status_server_tool_calls(home: &Path, project: &Path) -> u64 { .as_str() .expect("status result text"); let payload: Value = serde_json::from_str(text).expect("status payload json"); - if let Some(tool_calls) = payload["server"]["tool_calls"].as_u64() { + let tool_calls = payload["server"]["tool_calls"] + .as_u64() + .unwrap_or_else(|| panic!("typed status must carry its server counters: {payload}")); + if tool_calls >= 1 { return tool_calls; } - assert_eq!( - payload["project_open"]["state"], "converging", - "status without server stats must report typed project convergence: {payload}" - ); - let retry_after = Duration::from_millis( - payload["project_open"]["retry_after_ms"] - .as_u64() - .unwrap_or_else(|| panic!("converging status omitted retry delay: {payload}")), - ); assert!( - Instant::now() + retry_after <= deadline, - "project server did not converge before the CLI roundtrip deadline: {payload}" + Instant::now() < deadline, + "the status server never counted a tool call before the CLI roundtrip deadline: {payload}" ); - std::thread::sleep(retry_after); + std::thread::sleep(Duration::from_millis(100)); } } @@ -1192,7 +1210,7 @@ fn tool_cli_skips_daemon_notifications_until_matching_response() { let socket_path = socket_dir.path().join("tracedecay.sock"); let observed_request = spawn_sentinel_daemon_with_notification( socket_path.clone(), - "tracedecay_status", + "tracedecay_dashboard", true, false, sentinel, @@ -1202,7 +1220,15 @@ fn tool_cli_skips_daemon_notifications_until_matching_response() { let output = tracedecay_command_with_home(&home_path) .current_dir(&project_path) .env("TRACEDECAY_DAEMON_SOCKET", &socket_path) - .args(["tool", "--project", &project_arg, "status", "--json"]) + .args([ + "tool", + "--project", + &project_arg, + "dashboard", + "--action", + "stop", + "--json", + ]) .output() .expect("tracedecay tool should run"); @@ -1543,17 +1569,18 @@ fn daemon_reuses_project_engine_across_tool_clients() { // `init` is brokered through the daemon now (`tracedecay_status` then // `tracedecay_admin_sync`), so the fixture has already spent tool calls on - // this engine and the first status here is no longer call number one. What - // this test is about survives that: the counter is the engine's, so the - // first call sees itself and a second client sees exactly one more. + // this engine and the first counted call here is no longer call number one. + // What this test is about survives that: the counter is the engine's, so + // the first client's call is counted and a second client's call is exactly + // one more on the same engine. assert!( first_tool_calls >= 1, - "first status call should see itself counted, got {first_tool_calls}" + "the first client's tool call should be counted, got {first_tool_calls}" ); assert_eq!( second_tool_calls, first_tool_calls + 1, - "second status call should reuse the daemon engine and see exactly one more tool call" + "the second client should reuse the daemon engine and see exactly one more tool call" ); } @@ -1668,7 +1695,15 @@ fn daemon_project_handshake_uses_client_profile_identity() { "TRACEDECAY_DAEMON_SOCKET", common::daemon_socket_path(&daemon_home_path), ) - .args(["tool", "--project", &project_arg, "status", "--json"]) + .args([ + "tool", + "--project", + &project_arg, + "dashboard", + "--action", + "stop", + "--json", + ]) .output() .expect("tracedecay tool status should run"); @@ -1736,10 +1771,8 @@ fn daemon_first_touch_uses_registered_runtime_without_rewriting_legacy_config() #[test] fn daemon_project_handshake_uses_registry_backed_profile_store_without_marker() { - let daemon_home = TempDir::new().unwrap(); let client_home = TempDir::new().unwrap(); let project = TempDir::new().unwrap(); - let daemon_home_path = canonical_existing_path(daemon_home.path()); let client_home_path = canonical_existing_path(client_home.path()); let project_path = canonical_existing_path(project.path()); @@ -1758,12 +1791,10 @@ fn daemon_project_handshake_uses_registry_backed_profile_store_without_marker() // state rather than a setup failure. crate::cli_non_interactive_test::remove_repo_local_marker_dir_if_present(&project_path); - let _daemon = spawn_tracedecay_daemon(&daemon_home_path); - let socket_path = common::daemon_socket_path(&daemon_home_path); + let _daemon = spawn_tracedecay_daemon(&client_home_path); let project_arg = project_path.to_string_lossy().to_string(); let output = tracedecay_command_with_home(&client_home_path) .current_dir(&project_path) - .env("TRACEDECAY_DAEMON_SOCKET", &socket_path) .args(["tool", "--project", &project_arg, "active_project"]) .output() .expect("tracedecay tool active_project should run"); @@ -1783,10 +1814,8 @@ fn daemon_project_handshake_uses_registry_backed_profile_store_without_marker() #[test] fn daemon_project_handshake_uses_registered_remote_store_after_rename() { - let daemon_home = TempDir::new().unwrap(); let client_home = TempDir::new().unwrap(); let workspace = TempDir::new().unwrap(); - let daemon_home_path = canonical_existing_path(daemon_home.path()); let client_home_path = canonical_existing_path(client_home.path()); let original_path = workspace.path().join("repo-before-rename"); let renamed_path = workspace.path().join("repo-after-rename"); @@ -1807,12 +1836,10 @@ fn daemon_project_handshake_uses_registered_remote_store_after_rename() { std::fs::rename(&original_path, &renamed_path).unwrap(); let renamed_path = canonical_existing_path(&renamed_path); - let _daemon = spawn_tracedecay_daemon(&daemon_home_path); - let socket_path = common::daemon_socket_path(&daemon_home_path); + let _daemon = spawn_tracedecay_daemon(&client_home_path); let project_arg = renamed_path.to_string_lossy().to_string(); let output = tracedecay_command_with_home(&client_home_path) .current_dir(&renamed_path) - .env("TRACEDECAY_DAEMON_SOCKET", &socket_path) .args(["tool", "--project", &project_arg, "active_project"]) .output() .expect("tracedecay tool active_project should run"); @@ -1863,7 +1890,15 @@ fn daemon_project_cache_is_scoped_by_client_identity() { let client_a_output = tracedecay_command_with_home(&client_a_home_path) .current_dir(&project_path) .env("TRACEDECAY_DAEMON_SOCKET", &socket_path) - .args(["tool", "--project", &project_arg, "status", "--json"]) + .args([ + "tool", + "--project", + &project_arg, + "dashboard", + "--action", + "stop", + "--json", + ]) .output() .expect("client A tool status should run"); assert!( @@ -1876,7 +1911,15 @@ fn daemon_project_cache_is_scoped_by_client_identity() { let client_b_output = tracedecay_command_with_home(&client_b_home_path) .current_dir(&project_path) .env("TRACEDECAY_DAEMON_SOCKET", &socket_path) - .args(["tool", "--project", &project_arg, "status", "--json"]) + .args([ + "tool", + "--project", + &project_arg, + "dashboard", + "--action", + "stop", + "--json", + ]) .output() .expect("client B tool status should run"); assert!( @@ -1910,7 +1953,15 @@ fn tool_cli_without_daemon_socket_reports_daemon_unavailable() { let output = tracedecay_command_with_home(&home_path) .current_dir(&project_path) .env("TRACEDECAY_DAEMON_SOCKET", &missing_socket) - .args(["tool", "--project", &project_arg, "status", "--json"]) + .args([ + "tool", + "--project", + &project_arg, + "dashboard", + "--action", + "stop", + "--json", + ]) .output() .expect("tracedecay tool should run"); diff --git a/crates/tracedecay-cli/tests/core_cli_suite/tool_first_touch_test.rs b/crates/tracedecay-cli/tests/core_cli_suite/tool_first_touch_test.rs index 83194e1c8c..fe5e7bccaa 100644 --- a/crates/tracedecay-cli/tests/core_cli_suite/tool_first_touch_test.rs +++ b/crates/tracedecay-cli/tests/core_cli_suite/tool_first_touch_test.rs @@ -276,11 +276,20 @@ fn code_graph_tools_do_not_first_touch_project_store() { !output.status.success(), "code-graph tools must not first-touch create project stores" ); - let stderr = String::from_utf8_lossy(&output.stderr); - assert!( - stderr.contains("project route error (project_not_enrolled)") - && stderr.contains("run 'tracedecay init' in that directory"), - "expected init guidance, got:\n{stderr}" + let stdout = String::from_utf8_lossy(&output.stdout); + let result: serde_json::Value = serde_json::from_str(stdout.trim()) + .unwrap_or_else(|error| panic!("status --json prints its refusal: {error}\n{stdout}")); + let problem = &result["problem"]; + assert_eq!( + (&problem["kind"], &problem["code"], &problem["message"]), + ( + &serde_json::json!("invalid_request"), + &serde_json::json!("project_not_enrolled"), + &serde_json::json!(format!( + "no TraceDecay index found at '{target_arg}': project is not enrolled in the authenticated profile; run 'tracedecay init' in that directory, or start the MCP server with 'tracedecay serve --path '" + )), + ), + "expected init guidance in the owner's refusal, got:\n{stdout}" ); assert!(!target_path.join(".tracedecay").exists()); } diff --git a/crates/tracedecay-contracts/src/code_index_freshness.rs b/crates/tracedecay-contracts/src/code_index_freshness.rs index c7c9ff60b9..ed6d760dbf 100644 --- a/crates/tracedecay-contracts/src/code_index_freshness.rs +++ b/crates/tracedecay-contracts/src/code_index_freshness.rs @@ -49,7 +49,7 @@ pub enum CodeIndexBuildBlockedReasonV1 { /// /// Every count is scoped to `generation_id`. The snapshot never includes a /// staged page: work is reported only after the batch that owns it commits. -#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)] pub struct CodeIndexBuildProgressV1 { /// Exact generation receiving the committed build work. pub generation_id: String, @@ -498,7 +498,7 @@ pub struct CodeIndexRestoreProgressV1 { /// `Deserialize` is part of the wire contract: the CLI status command decodes /// exactly this type back out of the daemon's `tracedecay_status` response, /// keeping one authority for the freshness shape. -#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] +#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, JsonSchema)] pub struct CodeIndexWorktreeFreshnessV1 { /// Display path of the mounted worktree root. pub worktree_root: String, diff --git a/crates/tracedecay-contracts/src/doctor/report.rs b/crates/tracedecay-contracts/src/doctor/report.rs index 5326b3c4c1..7ec0221ee1 100644 --- a/crates/tracedecay-contracts/src/doctor/report.rs +++ b/crates/tracedecay-contracts/src/doctor/report.rs @@ -281,7 +281,7 @@ impl DoctorReportEntryV1 { /// finding with complete coverage does not weaken report completeness, and only /// genuinely complete coverage with every finding healthy makes the whole report /// assert health. -#[derive(Clone, Debug, Serialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, JsonSchema, PartialEq, Eq)] pub struct DoctorReportV1 { entries: Vec, coverage: DoctorReportCoverageV1, diff --git a/crates/tracedecay-contracts/src/doctor/sources.rs b/crates/tracedecay-contracts/src/doctor/sources.rs index 2c3374129d..4e70e8602c 100644 --- a/crates/tracedecay-contracts/src/doctor/sources.rs +++ b/crates/tracedecay-contracts/src/doctor/sources.rs @@ -33,6 +33,7 @@ use std::borrow::Cow; use std::future::Future; use std::pin::Pin; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; use tracedecay_domain::{ @@ -326,7 +327,7 @@ pub trait RuntimeHealthDoctorPort: Send + Sync { ) -> DoctorSourceFuture<'a, RuntimeHealthReadV1>; } -#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum RemoteListenerReadV1 { Serving, @@ -1236,7 +1237,9 @@ pub trait CodeIndexMountDoctorPort: Send + Sync { } /// Aggregate state of the project-active language-server analyzers. -#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive( + Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, PartialOrd, Ord, Hash, +)] #[serde(rename_all = "snake_case")] pub enum LanguageServerStateV1 { /// Every active analyzer is ready. @@ -1260,7 +1263,7 @@ pub enum LanguageServerStateV1 { /// executable is missing and how to install it, resolved by the daemon /// process (the only PATH that matters, since the daemon spawns analyzers) /// rather than by whichever shell ran the CLI. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] pub struct LanguageServerAnalyzerV1 { /// Adapter language (`typescript`, `rust`, …). pub language: String, @@ -1285,7 +1288,9 @@ pub struct LanguageServerAnalyzerV1 { /// `Inactive` is the one state the aggregate never takes: the language has no /// files in the project, so Doctor does not grade it, but `lsp servers` still /// lists it from this same read so both surfaces share one authority. -#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive( + Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, PartialOrd, Ord, Hash, +)] #[serde(rename_all = "snake_case")] pub enum LanguageServerAnalyzerStateV1 { Ready, @@ -1355,7 +1360,7 @@ impl LanguageServerReadV1 { } /// One live read from the daemon language-server/analyzer owner. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename_all = "snake_case", tag = "kind")] pub enum LanguageServerReadV1 { /// The owner observed all project-active analyzer states. @@ -1606,7 +1611,7 @@ pub fn observability_finding( /// One worktree holding a retained owner's memory, and what it holds: a /// generation id, or an LSP session id. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] pub struct ResidentMemoryHolderReadV1 { pub worktree_id: String, pub holding: String, diff --git a/crates/tracedecay-contracts/src/graph_tool.rs b/crates/tracedecay-contracts/src/graph_tool.rs index 5f5c185591..f9510281a3 100644 --- a/crates/tracedecay-contracts/src/graph_tool.rs +++ b/crates/tracedecay-contracts/src/graph_tool.rs @@ -6,6 +6,11 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use crate::InvocationAnalyticsV1; +use crate::remote::status::RemoteOperationalStatusReadV1; +use crate::retrieval::{ + ActiveProjectResultV1, ProjectContextResultV1, ProjectRegistryListingResultV1, RuntimeResultV1, + StatusResultV1, +}; use crate::retrieval::{ AffectedResultV1, AnalyticsResultV1, AstGrepSearchResultV1, AutomationRunArtifactViewResultV1, AutomationRunListResultV1, AutomationRunViewResultV1, BranchDiffResultV1, BranchListResultV1, @@ -86,6 +91,13 @@ pub enum GraphToolResultV1 { Search(Box), RunAffectedTests(RunAffectedTestsResultV1), Dashboard(DashboardResultV1), + Status(StatusResultV1), + ActiveProject(ActiveProjectResultV1), + RemoteStatus(RemoteOperationalStatusReadV1), + Runtime(Box), + ProjectList(ProjectRegistryListingResultV1), + ProjectSearch(ProjectRegistryListingResultV1), + ProjectContext(ProjectContextResultV1), } impl GraphToolResultV1 { @@ -157,6 +169,13 @@ impl GraphToolResultV1 { Operation::Search => Self::Search(serde_json::from_value(value)?), Operation::RunAffectedTests => Self::RunAffectedTests(serde_json::from_value(value)?), Operation::Dashboard => Self::Dashboard(serde_json::from_value(value)?), + Operation::Status => Self::Status(serde_json::from_value(value)?), + Operation::ActiveProject => Self::ActiveProject(serde_json::from_value(value)?), + Operation::RemoteStatus => Self::RemoteStatus(serde_json::from_value(value)?), + Operation::Runtime => Self::Runtime(serde_json::from_value(value)?), + Operation::ProjectList => Self::ProjectList(serde_json::from_value(value)?), + Operation::ProjectSearch => Self::ProjectSearch(serde_json::from_value(value)?), + Operation::ProjectContext => Self::ProjectContext(serde_json::from_value(value)?), operation => { return Err(serde::de::Error::custom(format!( "{} is not a graph-tool operation", @@ -228,6 +247,12 @@ impl GraphToolResultV1 { Self::Search(result) => serde_json::to_value(result), Self::RunAffectedTests(result) => serde_json::to_value(result), Self::Dashboard(result) => serde_json::to_value(result), + Self::Status(result) => serde_json::to_value(result), + Self::ActiveProject(result) => serde_json::to_value(result), + Self::RemoteStatus(result) => serde_json::to_value(result), + Self::Runtime(result) => serde_json::to_value(result), + Self::ProjectList(result) | Self::ProjectSearch(result) => serde_json::to_value(result), + Self::ProjectContext(result) => serde_json::to_value(result), } } } diff --git a/crates/tracedecay-contracts/src/lib.rs b/crates/tracedecay-contracts/src/lib.rs index 044bc73e31..55ffe0a723 100644 --- a/crates/tracedecay-contracts/src/lib.rs +++ b/crates/tracedecay-contracts/src/lib.rs @@ -327,10 +327,9 @@ pub use profile_identity::ProfileIdentityReadPort; pub use project_registry::{ ProjectRegistryContextCommand, ProjectRegistryContextFuture, ProjectRegistryContextOutcome, ProjectRegistryContextView, ProjectRegistryEntry, ProjectRegistryListingCommand, - ProjectRegistryListingFuture, ProjectRegistryListingOutcome, ProjectRegistryListingScope, - ProjectRegistryListingView, ProjectRegistryReadPort, ProjectRegistrySelector, - ProjectRegistrySummary, ProjectRegistryView, ProjectRepoGroup, PublicCodeProject, - list_registered_projects, read_registered_project_context, render_project_registry_view, + ProjectRegistryListingFuture, ProjectRegistryListingScope, ProjectRegistryListingView, + ProjectRegistryReadPort, ProjectRegistrySelector, ProjectRegistrySummary, ProjectRegistryView, + ProjectRepoGroup, PublicCodeProject, render_project_registry_view, }; pub use remote::status::RemoteOperationalStatusReaderV1; pub use result::{ diff --git a/crates/tracedecay-contracts/src/project_registry.rs b/crates/tracedecay-contracts/src/project_registry.rs index 7e1f5b9d5a..f9b35cabf5 100644 --- a/crates/tracedecay-contracts/src/project_registry.rs +++ b/crates/tracedecay-contracts/src/project_registry.rs @@ -3,7 +3,7 @@ //! MCP owns selector parsing and rendering; the daemon owns the registry //! database. Handlers therefore name a [`ProjectRegistryReadPort`] instead of a //! concrete registry store, and receive presentation views plus the typed -//! missing-registry and unresolved states. +//! unresolved state. //! //! Genuine read failures keep [`tracedecay_domain::errors::TraceDecayError`] so an //! unreadable registry stays a failure instead of collapsing into a @@ -19,14 +19,14 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use tracedecay_domain::errors::Result; -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] pub struct ProjectRegistrySummary { pub project_count: usize, pub repo_count: usize, pub truncated: bool, } -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] pub struct ProjectRepoGroup { pub label: String, pub git_common_dir: Option, @@ -35,7 +35,7 @@ pub struct ProjectRepoGroup { pub projects: Vec, } -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] pub struct ProjectRegistryEntry { pub project_id: String, pub label: String, @@ -56,7 +56,7 @@ pub struct ProjectRegistryEntry { pub is_active: Option, } -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] pub struct PublicCodeProject { pub project_id: String, pub label: String, @@ -75,7 +75,7 @@ pub struct PublicCodeProject { pub is_active: Option, } -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] pub struct ProjectRegistryView { pub summary: ProjectRegistrySummary, pub project_tree: Vec, @@ -198,15 +198,6 @@ pub struct ProjectRegistryContextView { pub stores: Vec, } -/// Closed set of listing results. -#[derive(Clone, Debug)] -pub enum ProjectRegistryListingOutcome { - Listing(ProjectRegistryListingView), - /// No registry authority is mounted for this profile. This is a state, not - /// an empty listing: callers must report it as such. - RegistryUnavailable, -} - /// Closed set of single-project context results. #[derive(Clone, Debug)] pub enum ProjectRegistryContextOutcome { @@ -215,86 +206,16 @@ pub enum ProjectRegistryContextOutcome { NotFound { registry_path: PathBuf, }, - RegistryUnavailable, } pub type ProjectRegistryListingFuture<'a> = - Pin> + Send + 'a>>; + Pin> + Send + 'a>>; pub type ProjectRegistryContextFuture<'a> = Pin> + Send + 'a>>; -/// The one path MCP handlers use to read the project registry. +/// The one path the registry reads take through the daemon's profile registry. pub trait ProjectRegistryReadPort: Send + Sync { fn list(&self, command: ProjectRegistryListingCommand) -> ProjectRegistryListingFuture<'_>; fn context(&self, command: ProjectRegistryContextCommand) -> ProjectRegistryContextFuture<'_>; } - -/// Reads the registry through `port`, reporting the typed missing-registry -/// state when no port is mounted. -#[hotpath::measure(future = true, label = "mcp.project.registry.list")] -pub async fn list_registered_projects( - port: Option<&dyn ProjectRegistryReadPort>, - command: ProjectRegistryListingCommand, -) -> Result { - match port { - Some(port) => port.list(command).await, - None => Ok(ProjectRegistryListingOutcome::RegistryUnavailable), - } -} - -/// Resolves one registered project through `port`, reporting the typed -/// missing-registry state when no port is mounted. -#[hotpath::measure(future = true, label = "mcp.project.registry.context")] -pub async fn read_registered_project_context( - port: Option<&dyn ProjectRegistryReadPort>, - command: ProjectRegistryContextCommand, -) -> Result { - match port { - Some(port) => port.context(command).await, - None => Ok(ProjectRegistryContextOutcome::RegistryUnavailable), - } -} - -#[cfg(test)] -mod tests { - use super::*; - - fn listing_command() -> ProjectRegistryListingCommand { - ProjectRegistryListingCommand { - active_project_root: Some(PathBuf::from("/srv/checkout")), - scope: ProjectRegistryListingScope::Matching { - query: "checkout".to_string(), - }, - limit: 7, - } - } - - fn context_command() -> ProjectRegistryContextCommand { - ProjectRegistryContextCommand { - active_project_root: Some(PathBuf::from("/srv/checkout")), - selector: ProjectRegistrySelector::ProjectId("project.checkout".to_string()), - } - } - - /// An unmounted registry is a state. It must not answer as a registry that - /// exists and happens to hold nothing. - #[tokio::test] - async fn absent_port_reports_unavailable_rather_than_an_empty_listing() { - let outcome = list_registered_projects(None, listing_command()) - .await - .expect("listing"); - assert!(matches!( - outcome, - ProjectRegistryListingOutcome::RegistryUnavailable - )); - - let outcome = read_registered_project_context(None, context_command()) - .await - .expect("context"); - assert!(matches!( - outcome, - ProjectRegistryContextOutcome::RegistryUnavailable - )); - } -} diff --git a/crates/tracedecay-contracts/src/remote/status.rs b/crates/tracedecay-contracts/src/remote/status.rs index 30cbab3c7d..0a3406bbcc 100644 --- a/crates/tracedecay-contracts/src/remote/status.rs +++ b/crates/tracedecay-contracts/src/remote/status.rs @@ -2,6 +2,7 @@ use std::sync::Arc; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use tracedecay_domain::{CurrentRemoteAuthorityStateV1, UtcMicros}; @@ -11,7 +12,7 @@ use crate::doctor::{ }; use crate::{ApplicationProblem, LegalAction, RetryDirective, SafeDiagnostic}; -#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename_all = "snake_case")] pub enum RemoteOperationalReadinessV1 { Unconfigured, @@ -20,7 +21,7 @@ pub enum RemoteOperationalReadinessV1 { RecoveryRequired, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub struct RemoteSpoolOperationalStatusV1 { pub pending_count: u64, @@ -28,7 +29,7 @@ pub struct RemoteSpoolOperationalStatusV1 { pub has_sequence_gap: bool, } -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub struct RemoteOperationalStatusV1 { pub readiness: RemoteOperationalReadinessV1, @@ -108,7 +109,7 @@ impl RemoteOperationalStatusV1 { /// mounted daemon authorities. Every operator surface (Doctor, CLI, MCP, /// dashboard) reads this one shape; `Unavailable` is reserved for a genuinely /// unmounted or unreadable authority, never a rendering shortcut. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename_all = "snake_case", tag = "kind")] pub enum RemoteOperationalStatusReadV1 { Observed { diff --git a/crates/tracedecay-contracts/src/retrieval/catalog.rs b/crates/tracedecay-contracts/src/retrieval/catalog.rs index 1efac3f49d..9adb88f28c 100644 --- a/crates/tracedecay-contracts/src/retrieval/catalog.rs +++ b/crates/tracedecay-contracts/src/retrieval/catalog.rs @@ -22,6 +22,7 @@ use crate::capability_manifest::{ }; use crate::error::ApplicationContractError; use crate::handlers::{ApplicationHandlerDescriptor, ApplicationOperation}; +use crate::remote::status::RemoteOperationalStatusReadV1; use crate::result::ResultContractRef; use crate::retrieval::DependencyDepthResultV1; use crate::retrieval::analysis_report_surface::{ @@ -65,6 +66,12 @@ use crate::retrieval::primitive_surface::{ use crate::retrieval::project_file_surface::{ ConfigResultV1, ConfigSurfaceRequestV1, FilesResultV1, FilesSurfaceRequestV1, }; +use crate::retrieval::project_info_surface::{ + ActiveProjectResultV1, ActiveProjectSurfaceRequestV1, ProjectContextResultV1, + ProjectContextSurfaceRequestV1, ProjectListSurfaceRequestV1, ProjectRegistryListingResultV1, + ProjectSearchSurfaceRequestV1, RemoteStatusSurfaceRequestV1, RuntimeResultV1, + RuntimeSurfaceRequestV1, StatusResultV1, StatusSurfaceRequestV1, +}; use crate::retrieval::requests::{ CallChainPrimitiveRequest, CallChainPrimitiveResult, DiagnosticsPrimitiveRequest, DiagnosticsPrimitiveResult, FileDependentsPrimitiveRequest, FileDependentsPrimitiveResult, @@ -264,6 +271,13 @@ const PRIMITIVE_READ_SPECS: &[PrimitiveReadSpec] = &[ graph_report_spec("search"), owner_side_effect_spec(ApplicationSurfaceOperation::RunAffectedTests), owner_side_effect_spec(ApplicationSurfaceOperation::Dashboard), + graph_report_spec("status"), + graph_report_spec("active_project"), + graph_report_spec("remote_status"), + graph_report_spec("runtime"), + graph_report_spec("project_list"), + graph_report_spec("project_search"), + graph_report_spec("project_context"), git_context_spec("affected"), git_context_spec("diff_context"), git_context_spec("changelog"), @@ -363,7 +377,14 @@ fn primitive_read_surfaces(spec: &PrimitiveReadSpec) -> &'static [BindingSurface | "analytics" | "search" | "run_affected_tests" - | "dashboard" => &CLI_MCP_PRIMITIVE_SURFACES, + | "dashboard" + | "status" + | "active_project" + | "remote_status" + | "runtime" + | "project_list" + | "project_search" + | "project_context" => &CLI_MCP_PRIMITIVE_SURFACES, "health_read" | "storage_status" | "diagnostics_read" => &DASHBOARD_PRIMITIVE_SURFACES, _ => &PRE_DASHBOARD_PRIMITIVE_SURFACES, } @@ -591,6 +612,25 @@ fn primitive_read_description(operation: &str) -> &'static str { "dashboard" => { "Start or stop this project's loopback dashboard server and report its bound address." } + "status" => { + "Report the served project's graph census, code-index freshness, retrieval serving, and resident memory, with opt-in branch, storage, and session diagnostics." + } + "active_project" => { + "Report the active project's identity, store paths, and branch identity for this session." + } + "remote_status" => { + "Read the Remote Brain operational plane: listener, enrollment, spool, replay coverage, and failover/recovery state." + } + "runtime" => { + "Capture the daemon's process and database telemetry, with the opt-in authority audit, session health, and Doctor report." + } + "project_list" => "List a bounded page of the profile's registered projects.", + "project_search" => { + "Search the profile's registered projects by id, root path, alias, or default branch." + } + "project_context" => { + "Read one registered project's metadata, aliases, and store instances." + } _ => "Read bounded data from the admitted project's current retained state.", } } @@ -1121,6 +1161,33 @@ fn primitive_executable_schemas( RunAffectedTestsResultV1 ); add!("dashboard", DashboardSurfaceRequestV1, DashboardResultV1); + add!("status", StatusSurfaceRequestV1, StatusResultV1); + add!( + "active_project", + ActiveProjectSurfaceRequestV1, + ActiveProjectResultV1 + ); + add!( + "remote_status", + RemoteStatusSurfaceRequestV1, + RemoteOperationalStatusReadV1 + ); + add!("runtime", RuntimeSurfaceRequestV1, RuntimeResultV1); + add!( + "project_list", + ProjectListSurfaceRequestV1, + ProjectRegistryListingResultV1 + ); + add!( + "project_search", + ProjectSearchSurfaceRequestV1, + ProjectRegistryListingResultV1 + ); + add!( + "project_context", + ProjectContextSurfaceRequestV1, + ProjectContextResultV1 + ); Ok(schemas) } diff --git a/crates/tracedecay-contracts/src/retrieval/mod.rs b/crates/tracedecay-contracts/src/retrieval/mod.rs index c94f31ff87..afcdcd6849 100644 --- a/crates/tracedecay-contracts/src/retrieval/mod.rs +++ b/crates/tracedecay-contracts/src/retrieval/mod.rs @@ -14,6 +14,7 @@ mod owner_effect_surface; mod ports; mod primitive_surface; mod project_file_surface; +mod project_info_surface; mod requests; mod response_handle_surface; mod search_surface; @@ -71,6 +72,8 @@ fn validate_current_temporal_meta( PageRequest::new(meta.page.page_size, meta.page.cursor.clone()).map(|_| ()) } +/// The Remote Brain read is `tracedecay_remote_status`'s catalog result. +pub use crate::remote::status::RemoteOperationalStatusReadV1; pub use analysis_report_surface::{ CircularCycleV1, CircularResultV1, CircularSurfaceRequestV1, ComplexityReportEntryV1, ComplexityReportV1, ComplexitySurfaceRequestV1, ConstructorFieldCoverageV1, @@ -211,6 +214,17 @@ pub use project_file_surface::{ ConfigKeyFoundV1, ConfigKeyMissingV1, ConfigMatchV1, ConfigParseErrorV1, ConfigResultV1, ConfigSurfaceRequestV1, FilesLayoutV1, FilesResultV1, FilesSurfaceRequestV1, IndexedFileV1, }; +pub use project_info_surface::{ + ActiveProjectBranchV1, ActiveProjectResolutionSourceV1, ActiveProjectResultV1, + ActiveProjectStorageV1, ActiveProjectSurfaceRequestV1, ProjectContextResultV1, + ProjectContextSurfaceRequestV1, ProjectListSurfaceRequestV1, ProjectRegistryListingResultV1, + ProjectSearchSurfaceRequestV1, ProjectStatusV1, RegisteredProjectIdSelectorV1, + RemoteStatusSurfaceRequestV1, RuntimeDoctorReportV1, RuntimeResultV1, RuntimeSurfaceRequestV1, + StatusAdmissionV1, StatusBranchMismatchV1, StatusCodeIndexFreshnessV1, StatusGitStalenessV1, + StatusMemoryOwnerV1, StatusMemoryPressureV1, StatusMemoryV1, StatusResultV1, + StatusRetrievalServingV1, StatusSchemaConvergenceStateV1, StatusSchemaConvergenceV1, + StatusServingConditionV1, StatusServingFreshnessV1, StatusSurfaceRequestV1, +}; pub use requests::{ AffectedTestAttributionV1, AffectedTestsRequest, AffectedTestsResult, AnchorExpandRequest, AnchorExpandResult, CallChainPrimitiveRequest, CallChainPrimitiveResult, diff --git a/crates/tracedecay-contracts/src/retrieval/project_info_surface.rs b/crates/tracedecay-contracts/src/retrieval/project_info_surface.rs new file mode 100644 index 0000000000..14cb8d7b0d --- /dev/null +++ b/crates/tracedecay-contracts/src/retrieval/project_info_surface.rs @@ -0,0 +1,471 @@ +//! Canonical CLI/MCP wire contracts for the project-info and runtime reads: +//! `tracedecay_status`, `tracedecay_active_project`, `tracedecay_remote_status`, +//! and `tracedecay_runtime`, which the project's graph-tool owner answers, and +//! the profile project-registry reads (`tracedecay_project_list`, +//! `tracedecay_project_search`, `tracedecay_project_context`), which the +//! daemon's profile owner answers. +//! +//! Presentation-only transport keys such as `format` are removed before these +//! request bodies are decoded. Sections whose authority lives above this crate +//! (the generation census, storage telemetry, branch diagnostics, session +//! ingest health, GitHub source) cross as that authority's own serialized +//! value. + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use tracedecay_domain::errors::StoreResetRequiredV1; + +use crate::code_index_freshness::{ + CodeIndexReadinessWaitOutcomeV1, CodeIndexReadinessWaitV1, CodeIndexWorktreeFreshnessV1, +}; +use crate::doctor::{DoctorReportV1, LanguageServerReadV1, ResidentMemoryHolderReadV1}; +use crate::project_registry::{ProjectRegistrySummary, ProjectRepoGroup, PublicCodeProject}; +use crate::storage::{SchemaConvergenceFindingV1, TableGrowthDoctorEvidenceV1}; + +#[derive(Clone, Debug, Default, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct StatusSurfaceRequestV1 { + /// Report only that the project route is admitted, reading no graph, + /// index, or session state. Default false. + #[serde(default)] + pub admission_only: bool, + /// Full tracked-branch diagnostic list. Default false. + #[serde(default)] + pub include_branch_diagnostics: bool, + /// Storage-health snapshot. Default false. + #[serde(default)] + pub include_storage_health: bool, + /// Session-ingest health. Default false. + #[serde(default)] + pub include_session_ingest: bool, + /// Git staleness object. Default false. + #[serde(default)] + pub include_staleness: bool, + /// Hold the status read until the code index reaches `state` (`fresh`: + /// status `current`; `ready`: also native graph serving; `graph_ready`: a + /// published generation's native graph serves, whatever the freshness), + /// for at most `timeout_ms`. The payload's `wait` reports `reached`, + /// `timed_out` with `last_state`, or `unavailable` with `reason`. + pub wait_for: Option, +} + +/// `tracedecay_status` for an `admission_only` read, or the project's status. +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)] +#[serde(untagged)] +pub enum StatusResultV1 { + Admission(StatusAdmissionV1), + Project(Box), +} + +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct StatusAdmissionV1 { + pub project_admitted: bool, + pub project_root: String, + /// The serving MCP server's request counters. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub server: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub scope_prefix: Option, +} + +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ProjectStatusV1 { + pub project_root: String, + /// The exact-scope sealed-generation census. + pub graph_statistics: Value, + pub memory: StatusMemoryV1, + pub schema_convergence: StatusSchemaConvergenceV1, + /// Registered stores this binary serves only as a typed reset-required + /// refusal, each with the command that resets it. + pub reset_required_stores: Vec, + pub code_index_freshness: StatusCodeIndexFreshnessV1, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub code_index_freshness_warning: Option, + /// Whether exact-scope retrieval can serve, when the census authority is + /// attached. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub retrieval_serving: Option, + /// The checkout's GitHub source as its advisory owner observed it. + pub github_source: Value, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub storage_health: Option, + /// The serving MCP server's request counters. + #[serde(default, skip_serializing_if = "Option::is_none")] + pub server: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub branch_diagnostics: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub active_branch: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub current_branch: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub live_branch: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub serving_branch: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub parent_branch: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub branch_drifted: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub branch_resolution: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub tracked_branch_count: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub branch_mismatch: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub branch_warnings: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub session_ingest: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub session_history_catch_up: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub git_staleness: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub scope_prefix: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub wait: Option, +} + +/// The daemon's resident memory as one project sees it. +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct StatusMemoryV1 { + pub status: StatusMemoryPressureV1, + pub resident_bytes: Option, + pub limit_bytes: u64, + pub high_watermark_bytes: u64, + pub low_watermark_bytes: u64, + pub psi_some_avg10: Option, + pub idle_window_seconds: u64, + pub shed_order: Vec, + pub retained_bytes: u64, + pub unmeasured_owners: usize, + /// This project's retained owners; other projects' belong to the + /// daemon-wide Doctor inventory. + pub owners: Vec, +} + +#[derive(Clone, Copy, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum StatusMemoryPressureV1 { + Unobserved, + Nominal, + OverBudget, +} + +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct StatusMemoryOwnerV1 { + pub project_id: String, + pub kind: String, + pub holders: Vec, + pub content_digest: Option, + pub bytes: Option, + pub measured: bool, + pub idle_seconds: u64, + pub protected: bool, +} + +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct StatusSchemaConvergenceV1 { + pub status: StatusSchemaConvergenceStateV1, + pub findings: Vec, +} + +#[derive(Clone, Copy, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum StatusSchemaConvergenceStateV1 { + Completed, + InProgress, + Degraded, +} + +/// The code-index freshness of the served worktree, labeled the way readiness +/// waits report their last state. +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)] +#[serde(tag = "status", rename_all = "snake_case", deny_unknown_fields)] +pub enum StatusCodeIndexFreshnessV1 { + Current { + worktree: Box, + }, + Stale { + worktree: Box, + }, + Restoring { + worktree: Box, + }, + Warming { + worktree: Box, + }, + Parked { + worktree: Box, + }, + Unavailable { + reason: String, + }, +} + +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(tag = "status", rename_all = "snake_case", deny_unknown_fields)] +pub enum StatusRetrievalServingV1 { + /// A sealed complete generation serves the exact worktree. The ages tell a + /// routine rebuild window from a wedged route. + Serving { + freshness: StatusServingFreshnessV1, + #[serde(default, skip_serializing_if = "Option::is_none")] + condition: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + seated_generation_age_seconds: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + last_reconcile_age_seconds: Option, + }, + /// The census answered and nothing is servable yet. + Unavailable { reason: String }, +} + +#[derive(Clone, Copy, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum StatusServingFreshnessV1 { + Current, + Restoring, + LastCompleteStale, + Unknown, +} + +#[derive(Clone, Copy, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum StatusServingConditionV1 { + ArtifactRestore, + SourceVerification, + Rebuilding, + Stalled, +} + +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct StatusBranchMismatchV1 { + pub git_branch: Option, + pub indexed_branch: Option, + pub serving_branch: Option, +} + +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct StatusGitStalenessV1 { + pub status: String, + pub reason: String, + pub message: String, +} + +#[derive(Clone, Debug, Default, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ActiveProjectSurfaceRequestV1 {} + +/// The resolved active project of this MCP session. +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ActiveProjectResultV1 { + pub project_id: Option, + pub repository_id: String, + pub project_root: String, + pub resolution_source: ActiveProjectResolutionSourceV1, + pub storage: ActiveProjectStorageV1, + pub branch: ActiveProjectBranchV1, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub scope_prefix: Option, +} + +#[derive(Clone, Copy, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(rename_all = "snake_case")] +pub enum ActiveProjectResolutionSourceV1 { + ActiveProject, +} + +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ActiveProjectStorageV1 { + pub class: String, + pub mode: String, + pub data_root: String, + pub graph_db_path: String, + pub graph_db_exists: bool, + pub graph_db_size_bytes: u64, + pub sessions_db_path: String, + pub response_handle_root: String, + pub lcm_payload_root: String, +} + +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ActiveProjectBranchV1 { + pub current_branch: Option, + pub open_active_branch: Option, + pub serving_branch: Option, + pub branch_resolution: String, + pub branch_drifted: bool, + pub tracked_branch_count: usize, + pub warnings: Vec, +} + +#[derive(Clone, Debug, Default, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct RemoteStatusSurfaceRequestV1 {} + +#[derive(Clone, Debug, Default, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct RuntimeSurfaceRequestV1 { + /// Run the exhaustive observation-authority audit and include + /// authority_audit_ok (true = audit ran and passed, false = audit ran and + /// failed, null = audit did not run), authority_audit_reason (typed: + /// authority_invariant_failed, authority_store_unavailable, + /// authority_store_missing, authority_audit_not_run), and + /// authority_audit_error (observed detail) in database telemetry. Also + /// includes session-temporal health. Default false. + #[serde(default)] + pub authority_audit: bool, + /// Include session-temporal health without the authority audit. Default + /// false. + #[serde(default)] + pub session_temporal_health: bool, + /// Include the daemon-owned canonical Doctor report and typed per-table + /// growth evidence. Default false. + #[serde(default)] + pub doctor_report: bool, + /// Include Cursor transcript-ingest health from the daemon-retained + /// project session authority. Default false. + #[serde(default)] + pub session_ingest_health: bool, + /// Ask a connection's first request for only the daemon-mounted database + /// integrity telemetry, for post-update startup validation; the daemon + /// core answers that probe before a project owner exists, and a project + /// owner's snapshot already carries the same telemetry. Default false. + #[serde(default)] + pub startup_health: bool, +} + +/// Process, database, and session-observation telemetry for the running +/// daemon, with the sections the request opted into. +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct RuntimeResultV1 { + /// Unix epoch seconds. + pub captured_at: u64, + pub tracedecay_version: String, + pub host_os: String, + /// Cached process sample. + pub process: Value, + /// Store telemetry, with the authority-audit verdict when it ran. + pub database: Value, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub session_temporal_health: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cursor_session_ingest: Option, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub cursor_session_placeholder_paths: Option>, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub doctor_report: Option, +} + +/// The daemon's canonical Doctor report as this route could read it. +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(tag = "kind", rename_all = "snake_case", deny_unknown_fields)] +pub enum RuntimeDoctorReportV1 { + Observed { + report: DoctorReportV1, + table_growth_evidence: Vec, + schema_convergences: Vec, + language_servers: LanguageServerReadV1, + }, + /// The reader is mounted and the read failed. + Unknown { + table_growth_evidence: Vec, + schema_convergences: Vec, + language_servers: LanguageServerReadV1, + }, + /// No Doctor reader is mounted on this route. + Unsupported { + table_growth_evidence: Vec, + schema_convergences: Vec, + language_servers: LanguageServerReadV1, + }, +} + +#[derive(Clone, Debug, Default, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ProjectListSurfaceRequestV1 { + /// Maximum projects to return (default: 25, max: 100). + pub limit: Option, +} + +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ProjectSearchSurfaceRequestV1 { + /// Case-insensitive substring query over registry project metadata. + pub query: String, + /// Maximum projects to return (default: 10, max: 50). + pub limit: Option, +} + +#[derive(Clone, Debug, Default, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +pub struct ProjectContextSurfaceRequestV1 { + /// Registered project id to inspect. Omit to use path or the active + /// project. + #[serde(default)] + #[schemars(with = "RegisteredProjectIdSelectorV1")] + pub project_selector: Option, + /// Project path or registered alias to resolve. + pub path: Option, +} + +/// The selector is inlined: the MCP selector policy reads its shape in place. +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(deny_unknown_fields)] +#[schemars(inline)] +pub struct RegisteredProjectIdSelectorV1 { + /// Registered project id to query. + pub project_id: String, +} + +/// A bounded page of the profile's registered projects. +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(tag = "status", rename_all = "snake_case", deny_unknown_fields)] +pub enum ProjectRegistryListingResultV1 { + Ok { + title: String, + registry_path: String, + #[serde(default, skip_serializing_if = "Option::is_none")] + query: Option, + limit: usize, + truncated: bool, + summary: ProjectRegistrySummary, + project_tree: Vec, + projects: Vec, + }, +} + +/// One registered project's context, or the registry's typed miss. +#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Eq, Serialize)] +#[serde(tag = "status", rename_all = "snake_case", deny_unknown_fields)] +pub enum ProjectContextResultV1 { + Ok { + is_active: bool, + registry_path: String, + project: Box, + /// Alias rows exactly as the registry serializes them. + aliases: Vec, + /// Store rows exactly as the registry serializes them. + stores: Vec, + }, + /// The registry answered and no registered project matches the selector. + NotFound { + registry_path: String, + project: (), + aliases: Vec, + stores: Vec, + }, +} diff --git a/crates/tracedecay-contracts/src/sdk_catalog.rs b/crates/tracedecay-contracts/src/sdk_catalog.rs index 658c91d4df..ee1b943fa7 100644 --- a/crates/tracedecay-contracts/src/sdk_catalog.rs +++ b/crates/tracedecay-contracts/src/sdk_catalog.rs @@ -167,7 +167,14 @@ pub fn application_http_route_path(operation: ApplicationSurfaceOperation) -> St | ApplicationSurfaceOperation::Analytics | ApplicationSurfaceOperation::Search | ApplicationSurfaceOperation::RunAffectedTests - | ApplicationSurfaceOperation::Dashboard) => { + | ApplicationSurfaceOperation::Dashboard + | ApplicationSurfaceOperation::Status + | ApplicationSurfaceOperation::ActiveProject + | ApplicationSurfaceOperation::RemoteStatus + | ApplicationSurfaceOperation::Runtime + | ApplicationSurfaceOperation::ProjectList + | ApplicationSurfaceOperation::ProjectSearch + | ApplicationSurfaceOperation::ProjectContext) => { format!("/primitives/{}", operation.as_str()) } operation @ (ApplicationSurfaceOperation::ConfigurationList diff --git a/crates/tracedecay-contracts/src/storage/telemetry.rs b/crates/tracedecay-contracts/src/storage/telemetry.rs index 2f708c2f78..c7d0360660 100644 --- a/crates/tracedecay-contracts/src/storage/telemetry.rs +++ b/crates/tracedecay-contracts/src/storage/telemetry.rs @@ -299,7 +299,7 @@ pub fn is_significant_table_growth(sample: &TableGrowthSampleV1) -> bool { /// Contract-independent evidence ready to wrap in a future `TableGrowth` /// Storage finding once that generated-contract variant is available. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename_all = "snake_case", tag = "kind")] pub enum TableGrowthDoctorEvidenceV1 { SignificantGrowth { diff --git a/crates/tracedecay-daemon-protocol/src/application_surface.rs b/crates/tracedecay-daemon-protocol/src/application_surface.rs index 09616bcc1f..0bb42012d3 100644 --- a/crates/tracedecay-daemon-protocol/src/application_surface.rs +++ b/crates/tracedecay-daemon-protocol/src/application_surface.rs @@ -240,7 +240,7 @@ impl ApplicationSurfaceRequest { return request.operation().as_str() == operation.as_str(); } if let Self::GraphTool(_) = self { - return operation.is_graph_tool(); + return operation.is_graph_tool() || operation.is_profile_registry_read(); } matches!( (self, operation), @@ -943,7 +943,14 @@ pub fn parse_application_surface_request( | ApplicationSurfaceOperation::Analytics | ApplicationSurfaceOperation::Search | ApplicationSurfaceOperation::RunAffectedTests - | ApplicationSurfaceOperation::Dashboard => match value { + | ApplicationSurfaceOperation::Dashboard + | ApplicationSurfaceOperation::Status + | ApplicationSurfaceOperation::ActiveProject + | ApplicationSurfaceOperation::RemoteStatus + | ApplicationSurfaceOperation::Runtime + | ApplicationSurfaceOperation::ProjectList + | ApplicationSurfaceOperation::ProjectSearch + | ApplicationSurfaceOperation::ProjectContext => match value { Value::Object(arguments) => Ok(ApplicationSurfaceRequest::GraphTool(arguments)), _ => Err(ApplicationSurfaceAdapterError::invalid_request(format!( "invalid arguments: {} expects a JSON object", diff --git a/crates/tracedecay-daemon-protocol/src/application_surface/invocation.rs b/crates/tracedecay-daemon-protocol/src/application_surface/invocation.rs index b43f8c0740..12e3d61957 100644 --- a/crates/tracedecay-daemon-protocol/src/application_surface/invocation.rs +++ b/crates/tracedecay-daemon-protocol/src/application_surface/invocation.rs @@ -394,6 +394,18 @@ pub async fn invoke_application_surface( cancellation.context(), ) } + (InvocationTarget::Profile, ApplicationSurfaceRequest::GraphTool(arguments)) + if operation.is_profile_registry_read() => + { + DaemonInvocationRequest::profile_graph_tool( + request_id.as_str(), + operation, + arguments, + now_micros(), + deadline.clone(), + cancellation.context(), + ) + } (InvocationTarget::Profile, _) => return Err(InvocationError::InvalidRequest), (target, request) => daemon_invocation_request( &request_id, @@ -908,6 +920,13 @@ pub fn application_surface_feedback_operation( | ApplicationSurfaceOperation::Search | ApplicationSurfaceOperation::RunAffectedTests | ApplicationSurfaceOperation::Dashboard + | ApplicationSurfaceOperation::Status + | ApplicationSurfaceOperation::ActiveProject + | ApplicationSurfaceOperation::RemoteStatus + | ApplicationSurfaceOperation::Runtime + | ApplicationSurfaceOperation::ProjectList + | ApplicationSurfaceOperation::ProjectSearch + | ApplicationSurfaceOperation::ProjectContext | ApplicationSurfaceOperation::HealthRead | ApplicationSurfaceOperation::HealthDelta | ApplicationSurfaceOperation::StorageStatus diff --git a/crates/tracedecay-daemon-protocol/src/contract/mod.rs b/crates/tracedecay-daemon-protocol/src/contract/mod.rs index c2235b4718..a670b66ad4 100644 --- a/crates/tracedecay-daemon-protocol/src/contract/mod.rs +++ b/crates/tracedecay-daemon-protocol/src/contract/mod.rs @@ -415,6 +415,7 @@ pub enum DaemonInvocationOperation { ObservatoryRead, RetainedApplication, ProfileRetainedApplication, + ProfileGraphTool, MultiRootScopeSetRead, MultiRootScopeSetCompareAndSwap, MultiRootExecute, @@ -482,6 +483,7 @@ impl DaemonInvocationOperation { Self::ObservatoryRead => "observatory_read", Self::RetainedApplication => "retained_application", Self::ProfileRetainedApplication => "profile_retained_application", + Self::ProfileGraphTool => "profile_graph_tool", Self::MultiRootScopeSetRead => "multi_root_scope_set_read", Self::MultiRootScopeSetCompareAndSwap => "multi_root_scope_set_compare_and_swap", Self::MultiRootExecute => "multi_root_execute", @@ -689,6 +691,15 @@ pub enum DaemonInvocationPayload { deadline: Deadline, cancellation: CancellationContext, }, + /// A read of the authenticated profile's project registry. It names no + /// project: the daemon composition root owns the profile registry. + ProfileGraphTool { + surface_operation: ApplicationSurfaceOperation, + arguments: serde_json::Map, + observed_at: UtcMicros, + deadline: Deadline, + cancellation: CancellationContext, + }, MultiRootScopeSetRead { request: MultiRootScopeSetReadRequestV1, observed_at: UtcMicros, @@ -786,6 +797,29 @@ pub enum DaemonInvocationPayload { } impl DaemonInvocationRequest { + pub fn profile_graph_tool( + request_id: impl Into, + surface_operation: ApplicationSurfaceOperation, + arguments: serde_json::Map, + observed_at: UtcMicros, + deadline: Deadline, + cancellation: CancellationContext, + ) -> Self { + Self { + protocol: DAEMON_INVOCATION_PROTOCOL.to_owned(), + revision: DAEMON_INVOCATION_REVISION, + request_id: request_id.into(), + delivery_route: None, + payload: DaemonInvocationPayload::ProfileGraphTool { + surface_operation, + arguments, + observed_at, + deadline, + cancellation, + }, + } + } + pub fn graph_tool( request_id: impl Into, surface_operation: ApplicationSurfaceOperation, @@ -1042,7 +1076,14 @@ impl DaemonInvocationRequest { | ApplicationSurfaceOperation::Analytics | ApplicationSurfaceOperation::Search | ApplicationSurfaceOperation::RunAffectedTests - | ApplicationSurfaceOperation::Dashboard => { + | ApplicationSurfaceOperation::Dashboard + | ApplicationSurfaceOperation::Status + | ApplicationSurfaceOperation::ActiveProject + | ApplicationSurfaceOperation::RemoteStatus + | ApplicationSurfaceOperation::Runtime + | ApplicationSurfaceOperation::ProjectList + | ApplicationSurfaceOperation::ProjectSearch + | ApplicationSurfaceOperation::ProjectContext => { unreachable!("graph-tool operations use their typed constructor") } ApplicationSurfaceOperation::FactStoreCurate @@ -1884,6 +1925,9 @@ impl DaemonInvocationRequest { DaemonInvocationPayload::ProfileRetainedApplication { .. } => { DaemonInvocationOperation::ProfileRetainedApplication } + DaemonInvocationPayload::ProfileGraphTool { .. } => { + DaemonInvocationOperation::ProfileGraphTool + } DaemonInvocationPayload::MultiRootScopeSetRead { .. } => { DaemonInvocationOperation::MultiRootScopeSetRead } @@ -2225,6 +2269,19 @@ impl DaemonInvocationRequest { return Err(DaemonInvocationProblem::InvalidRequest); } } + DaemonInvocationPayload::ProfileGraphTool { + surface_operation, + observed_at, + deadline, + cancellation, + .. + } => { + if !valid_observation_window(observed_at, deadline, cancellation) + || !surface_operation.is_profile_registry_read() + { + return Err(DaemonInvocationProblem::InvalidRequest); + } + } DaemonInvocationPayload::ObservatoryRead { request, observed_at, diff --git a/crates/tracedecay-daemon-service/src/adoption_observation.rs b/crates/tracedecay-daemon-service/src/adoption_observation.rs index 0cec101fc2..7432aa315d 100644 --- a/crates/tracedecay-daemon-service/src/adoption_observation.rs +++ b/crates/tracedecay-daemon-service/src/adoption_observation.rs @@ -312,6 +312,10 @@ mod tests { "capability.application.code-query.type-definition", "available", ), + ( + "capability.application.primitive.active-project", + "available", + ), ("capability.application.primitive.affected", "available"), ("capability.application.primitive.analytics", "available"), ( @@ -382,11 +386,11 @@ mod tests { ("capability.application.primitive.doc-coverage", "available"), ("capability.application.primitive.dsm", "available"), ("capability.application.primitive.field-sites", "available"), - ("capability.application.primitive.files", "available"), ( "capability.application.primitive.file-dependents", "available", ), + ("capability.application.primitive.files", "available"), ( "capability.application.primitive.find-exact-symbol", "available", @@ -413,6 +417,15 @@ mod tests { ("capability.application.primitive.port-order", "available"), ("capability.application.primitive.port-status", "available"), ("capability.application.primitive.pr-context", "available"), + ( + "capability.application.primitive.project-context", + "available", + ), + ("capability.application.primitive.project-list", "available"), + ( + "capability.application.primitive.project-search", + "available", + ), ( "capability.application.primitive.qualified-name", "available", @@ -420,15 +433,20 @@ mod tests { ("capability.application.primitive.rank", "available"), ("capability.application.primitive.recursion", "available"), ("capability.application.primitive.redundancy", "available"), - ("capability.application.primitive.retrieve", "available"), + ( + "capability.application.primitive.remote-status", + "available", + ), ( "capability.application.primitive.rename-preview", "available", ), + ("capability.application.primitive.retrieve", "available"), ( "capability.application.primitive.run-affected-tests", "available", ), + ("capability.application.primitive.runtime", "available"), ("capability.application.primitive.search", "available"), ( "capability.application.primitive.session-lookup", @@ -444,6 +462,7 @@ mod tests { "capability.application.primitive.source-outline", "available", ), + ("capability.application.primitive.status", "available"), ( "capability.application.primitive.storage-status", "available", diff --git a/crates/tracedecay-daemon-service/src/invocation/dispatch.rs b/crates/tracedecay-daemon-service/src/invocation/dispatch.rs index 8f18490667..3a0c8af982 100644 --- a/crates/tracedecay-daemon-service/src/invocation/dispatch.rs +++ b/crates/tracedecay-daemon-service/src/invocation/dispatch.rs @@ -864,12 +864,14 @@ impl DaemonInvocationService { )) .await } - // Multi-root routes and the profile's retained stores belong to the - // daemon composition root, which serves them before this service. + // Multi-root routes and the profile's retained stores and project + // registry belong to the daemon composition root, which serves them + // before this service. DaemonInvocationPayload::MultiRootScopeSetRead { .. } | DaemonInvocationPayload::MultiRootScopeSetCompareAndSwap { .. } | DaemonInvocationPayload::MultiRootExecute { .. } - | DaemonInvocationPayload::ProfileRetainedApplication { .. } => { + | DaemonInvocationPayload::ProfileRetainedApplication { .. } + | DaemonInvocationPayload::ProfileGraphTool { .. } => { DaemonInvocationResponse::problem( request_id, DaemonInvocationProblem::InvalidRequest, diff --git a/crates/tracedecay-daemon-service/src/invocation/invocation_observability.rs b/crates/tracedecay-daemon-service/src/invocation/invocation_observability.rs index f128fd1cd8..18847651c6 100644 --- a/crates/tracedecay-daemon-service/src/invocation/invocation_observability.rs +++ b/crates/tracedecay-daemon-service/src/invocation/invocation_observability.rs @@ -75,6 +75,7 @@ pub(super) fn feedback_observation_operation( | DaemonInvocationOperation::ObservatoryRead | DaemonInvocationOperation::RetainedApplication | DaemonInvocationOperation::ProfileRetainedApplication + | DaemonInvocationOperation::ProfileGraphTool | DaemonInvocationOperation::MultiRootScopeSetRead | DaemonInvocationOperation::MultiRootScopeSetCompareAndSwap | DaemonInvocationOperation::MultiRootExecute diff --git a/crates/tracedecay-daemon-service/src/mcp_project_registry.rs b/crates/tracedecay-daemon-service/src/mcp_project_registry.rs index 557051ba6f..cf76b4b116 100644 --- a/crates/tracedecay-daemon-service/src/mcp_project_registry.rs +++ b/crates/tracedecay-daemon-service/src/mcp_project_registry.rs @@ -3,8 +3,7 @@ //! [`ProjectRegistryReadPort`] implementation. //! //! This module owns the registry database handle so MCP handlers do not. A -//! mounted-but-empty registry answers with an empty listing, an absent -//! registry never reaches here (the boundary reports that state), and an +//! mounted-but-empty registry answers with an empty listing, and an //! unreadable registry still fails. use serde_json::Value; @@ -13,8 +12,8 @@ use std::path::Path; use tracedecay_contracts::{ ProjectRegistryContextCommand, ProjectRegistryContextFuture, ProjectRegistryContextOutcome, ProjectRegistryContextView, ProjectRegistryListingCommand, ProjectRegistryListingFuture, - ProjectRegistryListingOutcome, ProjectRegistryListingScope, ProjectRegistryListingView, - ProjectRegistryReadPort, ProjectRegistrySelector, + ProjectRegistryListingScope, ProjectRegistryListingView, ProjectRegistryReadPort, + ProjectRegistrySelector, }; use tracedecay_dashboard_api::project_registry::{ align_public_checkout_branches, build_project_registry_view, public_code_project_for_checkout, @@ -90,7 +89,7 @@ impl DaemonProjectRegistryReadService { async fn execute_list( &self, command: ProjectRegistryListingCommand, - ) -> Result { + ) -> Result { let ProjectRegistryListingCommand { active_project_root, scope, @@ -104,10 +103,8 @@ impl DaemonProjectRegistryReadService { self.registry.try_search_code_projects(query, page).await? } }; - Ok(ProjectRegistryListingOutcome::Listing( - self.listing(active_project_root.as_deref(), projects, limit) - .await?, - )) + self.listing(active_project_root.as_deref(), projects, limit) + .await } #[hotpath::skip] diff --git a/crates/tracedecay-domain/src/errors.rs b/crates/tracedecay-domain/src/errors.rs index 3b5b799635..3951774901 100644 --- a/crates/tracedecay-domain/src/errors.rs +++ b/crates/tracedecay-domain/src/errors.rs @@ -125,7 +125,9 @@ pub const PROFILE_RESET_COMMAND: &str = "tracedecay wipe --all --yes"; /// instead of refusing to serve: every read against it returns the typed /// refusal, stores that admit keep serving, and `remedy` is the exact command /// the operator runs to reset it. -#[derive(Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +#[derive( + Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema, +)] pub struct StoreResetRequiredV1 { pub store: String, pub authority: String, diff --git a/crates/tracedecay-domain/src/remote.rs b/crates/tracedecay-domain/src/remote.rs index 137c3eb8fe..d34dbbd340 100644 --- a/crates/tracedecay-domain/src/remote.rs +++ b/crates/tracedecay-domain/src/remote.rs @@ -6,6 +6,7 @@ use std::collections::BTreeSet; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use crate::{ @@ -44,7 +45,7 @@ impl RemoteRepositoryScopeV1 { } } -#[derive(Clone, Copy, Debug, Serialize, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, Debug, Serialize, JsonSchema, PartialEq, Eq, PartialOrd, Ord, Hash)] #[serde(transparent)] pub struct RemotePlacementRevisionV1(u64); @@ -85,7 +86,7 @@ impl<'de> Deserialize<'de> for RemotePlacementRevisionV1 { } /// The complete single-writer identity for one mutable shard. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub struct RemoteWriterFenceV1 { pub brain_id: BrainId, @@ -392,7 +393,7 @@ pub struct CredentialRevocationReceiptV1 { } /// Authenticated current authority for a mutable shard. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(deny_unknown_fields)] pub struct CurrentRemoteAuthorityV1 { pub fence: RemoteWriterFenceV1, @@ -413,7 +414,9 @@ impl CurrentRemoteAuthorityV1 { } } -#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive( + Clone, Copy, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, PartialOrd, Ord, Hash, +)] #[serde(rename_all = "snake_case")] pub enum RemoteAuthorityUnavailableReasonV1 { RegistryUnavailable, @@ -431,7 +434,7 @@ pub enum RemoteAuthorityUnavailableReasonV1 { /// Truthful authority lookup state. Missing evidence is never represented as /// an available authority or a successful empty response. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename_all = "snake_case", tag = "state", content = "value")] pub enum CurrentRemoteAuthorityStateV1 { Available(CurrentRemoteAuthorityV1), diff --git a/crates/tracedecay-domain/src/research/id.rs b/crates/tracedecay-domain/src/research/id.rs index 959ab9412e..966045e04e 100644 --- a/crates/tracedecay-domain/src/research/id.rs +++ b/crates/tracedecay-domain/src/research/id.rs @@ -209,7 +209,18 @@ digest_id!( /// Monotonic epoch of the writer authority for a shard. #[derive( - Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, + Clone, + Copy, + Debug, + Default, + Serialize, + Deserialize, + JsonSchema, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, )] #[serde(transparent)] pub struct AuthorityEpoch(pub u64); diff --git a/crates/tracedecay-mcp-catalog/src/definitions.rs b/crates/tracedecay-mcp-catalog/src/definitions.rs index 1c48bb36aa..2efe0756b9 100644 --- a/crates/tracedecay-mcp-catalog/src/definitions.rs +++ b/crates/tracedecay-mcp-catalog/src/definitions.rs @@ -329,16 +329,16 @@ fn build_maximal_tool_definitions() -> Result, McpCatalogErr def_context(request_schema("context")?), def_impact(request_schema("impact")?), def_node(request_schema("node")?), - def_status(), - def_active_project(), - def_project_list(), - def_project_search(), - def_project_context(), + def_status(request_schema("status")?), + def_active_project(request_schema("active_project")?), + def_project_list(request_schema("project_list")?), + def_project_search(request_schema("project_search")?), + def_project_context(request_schema("project_context")?), def_files(request_schema("files")?), def_multi_root_scope_set_read(), def_multi_root_scope_set_compare_and_swap(), def_multi_root_execute()?, - def_remote_status_read(), + def_remote_status_read(request_schema("remote_status")?), def_affected(request_schema("affected")?), def_dead_code(request_schema("dead_code")?), def_diff_context(request_schema("diff_context")?), @@ -373,7 +373,7 @@ fn build_maximal_tool_definitions() -> Result, McpCatalogErr def_gini(request_schema("gini")?), def_dependency_depth(request_schema("dependency_depth")?), def_health(request_schema("health")?), - def_runtime(), + def_runtime(request_schema("runtime")?), def_dsm(request_schema("dsm")?), def_test_risk(request_schema("test_risk")?), def_todos(request_schema("todos")?), diff --git a/crates/tracedecay-mcp-catalog/src/definitions/admin.rs b/crates/tracedecay-mcp-catalog/src/definitions/admin.rs index 125bdb2819..515c7ebf6a 100644 --- a/crates/tracedecay-mcp-catalog/src/definitions/admin.rs +++ b/crates/tracedecay-mcp-catalog/src/definitions/admin.rs @@ -2,150 +2,60 @@ use serde_json::{Value, json}; -use super::{def, def_always_load, def_rw, project_selector_object}; +use super::{def, def_always_load, def_rw}; use crate::ToolDefinition; -pub(super) fn def_status() -> ToolDefinition { +pub(super) fn def_status(input_schema: Value) -> ToolDefinition { def_always_load( "tracedecay_status", "Graph Status", "Return a compact summary of the code graph (counts and freshness). Full branch diagnostics are opt-in.", - json!({ - "type": "object", - "additionalProperties": false, - "properties": { - "include_branch_diagnostics": { - "type": "boolean", - "default": false, - "description": "Full tracked-branch diagnostic list. Default false." - }, - "include_storage_health": { - "type": "boolean", - "default": false, - "description": "Storage-health snapshot. Default false." - }, - "include_session_ingest": { - "type": "boolean", - "default": false, - "description": "Session-ingest health. Default false." - }, - "include_staleness": { - "type": "boolean", - "default": false, - "description": "Git staleness object. Default false." - }, - "wait_for": { - "type": "object", - "additionalProperties": false, - "required": ["state", "timeout_ms"], - "description": "Hold the status read until the code index reaches `state` (`fresh`: status `current`; `ready`: also native graph serving; `graph_ready`: a published generation's native graph serves, whatever the freshness), for at most `timeout_ms`. The payload's `wait` reports `reached`, `timed_out` with `last_state`, or `unavailable` with `reason`.", - "properties": { - "state": { "type": "string", "enum": ["fresh", "ready", "graph_ready"] }, - "timeout_ms": { "type": "integer", "minimum": 0 } - } - } - } - }), + input_schema, ) } -pub(super) fn def_active_project() -> ToolDefinition { +pub(super) fn def_active_project(input_schema: Value) -> ToolDefinition { def_always_load( "tracedecay_active_project", "Active Project", "Return the resolved active project context for this MCP session, including project ID, project root, scope prefix, branch identity, and the active project store paths. Use this instead of guessing from repo-local marker files or hardcoded DB paths.", - json!({ - "type": "object", - "properties": {} - }), + input_schema, ) } -pub(super) fn def_project_list() -> ToolDefinition { +pub(super) fn def_project_list(input_schema: Value) -> ToolDefinition { def( "tracedecay_project_list", "Project List", "List projects from the profile/global registry without opening or mutating their stores. Results are bounded and include only registry metadata. Output is grouped into a `project_tree` by repository alongside a `summary`, and the calling project is marked with `is_active` when it is registered.", - json!({ - "type": "object", - "properties": { - "limit": { - "type": "number", - "description": "Maximum projects to return (default: 25, max: 100)" - } - } - }), + input_schema, ) } -pub(super) fn def_project_search() -> ToolDefinition { +pub(super) fn def_project_search(input_schema: Value) -> ToolDefinition { def( "tracedecay_project_search", "Project Search", "Search registered projects by project id, root path, aliases, or default branch. This is read-only and bounded; output omits credential-bearing remotes. Output is grouped into a `project_tree` by repository alongside a `summary`, and the calling project is marked with `is_active` when it is registered.", - json!({ - "type": "object", - "properties": { - "query": { - "type": "string", - "description": "Case-insensitive substring query over registry project metadata" - }, - "limit": { - "type": "number", - "description": "Maximum projects to return (default: 10, max: 50)" - } - }, - "required": ["query"] - }), + input_schema, ) } -pub(super) fn def_project_context() -> ToolDefinition { +pub(super) fn def_project_context(input_schema: Value) -> ToolDefinition { def( "tracedecay_project_context", "Project Context", "Return registry context for one project: project metadata, aliases, store instances, graph scopes, and artifacts. Defaults to the active project alias when neither project_selector nor path is provided.", - json!({ - "type": "object", - "properties": { - "project_selector": project_selector_object( - "Optional registered project id to inspect. Omit to use path or the active project." - ), - "path": { - "type": "string", - "description": "Project path or registered alias to resolve" - } - } - }), + input_schema, ) } -pub(super) fn def_runtime() -> ToolDefinition { +pub(super) fn def_runtime(input_schema: Value) -> ToolDefinition { def( "tracedecay_runtime", "Runtime Snapshot", "Capture a process + database telemetry snapshot for the running tracedecay MCP server: PID, resident memory, virtual size, sustained CPU% (sampled over ~200ms), thread count, system memory, DB / WAL / SHM file sizes, journal mode, and the DB-to-source byte ratio. Use this when triaging unexpected CPU or RAM consumption (issue #80). Set authority_audit=true only for exhaustive Doctor-style observation-authority validation. Single call, output is a JSON object.", - json!({ - "type": "object", - "properties": { - "authority_audit": { - "type": "boolean", - "description": "Run the exhaustive observation-authority audit and include authority_audit_ok (true = audit ran and passed, false = audit ran and failed, null = audit did not run), authority_audit_reason (typed: authority_invariant_failed, authority_store_unavailable, authority_store_missing, authority_audit_not_run), and authority_audit_error (observed detail) in database telemetry (default: false)" - }, - "doctor_report": { - "type": "boolean", - "description": "Include the daemon-owned canonical Doctor report and typed per-table growth evidence (default: false)" - }, - "session_ingest_health": { - "type": "boolean", - "description": "Include Cursor transcript-ingest health from the daemon-retained project session authority (default: false)" - }, - "startup_health": { - "type": "boolean", - "description": "Return only daemon-mounted database integrity telemetry for post-update startup validation (default: false)" - } - } - }), + input_schema, ) } diff --git a/crates/tracedecay-mcp-catalog/src/definitions/application.rs b/crates/tracedecay-mcp-catalog/src/definitions/application.rs index ec34ad8717..e4a6110634 100644 --- a/crates/tracedecay-mcp-catalog/src/definitions/application.rs +++ b/crates/tracedecay-mcp-catalog/src/definitions/application.rs @@ -3,7 +3,7 @@ use tracedecay_tool_catalog::{ ApplicationSurfaceOperation, CatalogContributionV1, CatalogValidationError, OperationId, }; -use super::application_schema::{bound_tagged_union, closed_object_schema}; +use super::application_schema::bound_tagged_union; use super::def; use crate::{McpCatalogError, ToolDefinition}; @@ -85,6 +85,13 @@ const HANDWRITTEN_DEFINITION_OPERATIONS: &[ApplicationSurfaceOperation] = &[ ApplicationSurfaceOperation::Search, ApplicationSurfaceOperation::RunAffectedTests, ApplicationSurfaceOperation::Dashboard, + ApplicationSurfaceOperation::Status, + ApplicationSurfaceOperation::ActiveProject, + ApplicationSurfaceOperation::RemoteStatus, + ApplicationSurfaceOperation::Runtime, + ApplicationSurfaceOperation::ProjectList, + ApplicationSurfaceOperation::ProjectSearch, + ApplicationSurfaceOperation::ProjectContext, ApplicationSurfaceOperation::StrReplace, ApplicationSurfaceOperation::MultiStrReplace, ApplicationSurfaceOperation::InsertAt, @@ -283,12 +290,12 @@ fn invalid_application_definition(field: &'static str, reason: &'static str) -> CatalogValidationError::InvalidValue { field, reason }.into() } -pub(super) fn def_remote_status_read() -> ToolDefinition { +pub(super) fn def_remote_status_read(input_schema: Value) -> ToolDefinition { def( "tracedecay_remote_status", "Read Remote Brain status", "Read the Remote Brain operational plane: listener, enrollment, spool, replay coverage, and failover/recovery state.", - closed_object_schema(json!({}), &[]), + input_schema, ) } diff --git a/crates/tracedecay-mcp-catalog/src/definitions/application_schema.rs b/crates/tracedecay-mcp-catalog/src/definitions/application_schema.rs index 73ff0d98c8..8f8dbe4144 100644 --- a/crates/tracedecay-mcp-catalog/src/definitions/application_schema.rs +++ b/crates/tracedecay-mcp-catalog/src/definitions/application_schema.rs @@ -7,8 +7,6 @@ use std::collections::BTreeSet; use serde_json::{Map, Value, json}; use tracedecay_tool_catalog::{ExecutableBindingRegistryV1, OperationId}; -use super::required_object_schema; - type DiscoveryResult = Result; pub(super) fn canonical_application_request_schema( @@ -32,15 +30,6 @@ fn invalid_terminal_application_discovery() -> crate::McpCatalogError { .into() } -pub(super) fn closed_object_schema( - properties: serde_json::Value, - required: &[&str], -) -> serde_json::Value { - let mut schema = required_object_schema(properties, required); - schema["additionalProperties"] = json!(false); - schema -} - /// Project a canonical executable request schema into the MCP `inputSchema` /// advertised for a tool. /// diff --git a/crates/tracedecay-mcp/src/handlers/graph_tool.rs b/crates/tracedecay-mcp/src/handlers/graph_tool.rs index 83ffb54635..03fd55e968 100644 --- a/crates/tracedecay-mcp/src/handlers/graph_tool.rs +++ b/crates/tracedecay-mcp/src/handlers/graph_tool.rs @@ -6,12 +6,13 @@ use std::path::Path; -use serde_json::Value; +use serde_json::{Value, json}; use tracedecay_application::code_index::CodeIndexIgnoredDependencyAdmissionPortV1; use tracedecay_contracts::graph_tool::{GraphToolCompletionV1, GraphToolResultV1}; use tracedecay_contracts::retrieval::{CallableCodeOperationKind, callable_code_operation}; use tracedecay_contracts::retrieval::{ DerivesResultV1, NodeResultV1, RenamePreviewPrimitiveOutcomeV1, RetrieveResultV1, + StatusResultV1, }; use tracedecay_domain::errors::{Result, TraceDecayError}; use tracedecay_tool_catalog::ApplicationSurfaceOperation; @@ -35,7 +36,7 @@ use crate::handlers::health::{ }; use crate::handlers::info::{ compute_config, compute_files, compute_port_order, compute_port_status, compute_todos, - render_files_md, + render_files_md, render_registry_listing_md, render_status_md, }; use crate::handlers::retrieve::{compute_retrieve, render_retrieved_page}; use crate::handlers::support::{ @@ -334,6 +335,29 @@ pub fn render_graph_tool( GraphToolResultV1::Analytics(_) => { render_value_markdown(response_handle_root, args, &result, renderers::analytics_md)? } + GraphToolResultV1::Status(status) => { + let value = result.result_value()?; + let mut rendered = + rendered_tool_result(response_handle_root, args, &value, Vec::new(), || { + render_status_md(&value) + }); + // Structured content beside the rendered body in every format, + // like a typed `problem`, so a caller such as `tracedecay tool` + // can type its exit status on the readiness wait's outcome. + if let StatusResultV1::Project(project) = status + && let Some(wait) = &project.wait + && let Some(object) = rendered.value.as_object_mut() + { + object.insert("structuredContent".to_owned(), json!({ "wait": wait })); + } + rendered + } + // A listing renders inline: it is bounded by its own page limit. + GraphToolResultV1::ProjectList(listing) | GraphToolResultV1::ProjectSearch(listing) => { + rendered_tool_result(None, args, &result.result_value()?, Vec::new(), || { + render_registry_listing_md(listing) + }) + } _ => generic_tool_result( response_handle_root, args, diff --git a/crates/tracedecay-mcp/src/handlers/health/mod.rs b/crates/tracedecay-mcp/src/handlers/health/mod.rs index 08c3ef04f3..d691fca33d 100644 --- a/crates/tracedecay-mcp/src/handlers/health/mod.rs +++ b/crates/tracedecay-mcp/src/handlers/health/mod.rs @@ -7,7 +7,7 @@ mod test_map; pub use dsm::{compute_dsm, render_dsm_md}; pub use reports::{compute_dependency_depth, compute_gini, compute_health}; -pub use runtime::{collect_database_snapshot, handle_runtime}; +pub use runtime::{collect_database_snapshot, compute_runtime}; pub use test_map::{compute_test_map, compute_test_risk}; use std::collections::{HashMap, HashSet}; diff --git a/crates/tracedecay-mcp/src/handlers/health/runtime.rs b/crates/tracedecay-mcp/src/handlers/health/runtime.rs index ff9c288134..5400bd59e8 100644 --- a/crates/tracedecay-mcp/src/handlers/health/runtime.rs +++ b/crates/tracedecay-mcp/src/handlers/health/runtime.rs @@ -7,7 +7,12 @@ use tracedecay_domain::errors::{Result, TraceDecayError}; use tracedecay_global_db::RegisteredGlobalDb; use tracedecay_session_temporal_store::SessionTemporalAccess; -use crate::{McpDoctorReportV1, McpToolContext, ToolResult, generic_tool_result}; +use tracedecay_contracts::doctor::LanguageServerReadV1; +use tracedecay_contracts::retrieval::{ + RuntimeDoctorReportV1, RuntimeResultV1, RuntimeSurfaceRequestV1, +}; + +use crate::{McpDoctorReportV1, McpToolContext}; /// Bound for the session-temporal doctor probe so a wedged sessions DB cannot /// monopolize a `tracedecay_runtime` request indefinitely. @@ -123,28 +128,25 @@ async fn literal_workspace_placeholder_transcript_paths( paths } -fn attach_doctor_report(value: &mut Value, report: McpDoctorReportV1<'_>) { - value["doctor_report"] = match report { - McpDoctorReportV1::Read(admitted) => json!({ - "kind": "observed", - "report": admitted.report, - "table_growth_evidence": admitted.table_growth_evidence, - "schema_convergences": admitted.schema_convergences, - "language_servers": admitted.language_servers, - }), - McpDoctorReportV1::ReadFailed => json!({ - "kind": "unknown", - "table_growth_evidence": [], - "schema_convergences": [], - "language_servers": tracedecay_contracts::doctor::LanguageServerReadV1::Unknown, - }), - McpDoctorReportV1::NotAttached => json!({ - "kind": "unsupported", - "table_growth_evidence": [], - "schema_convergences": [], - "language_servers": tracedecay_contracts::doctor::LanguageServerReadV1::Unsupported, - }), - }; +fn runtime_doctor_report(report: McpDoctorReportV1<'_>) -> RuntimeDoctorReportV1 { + match report { + McpDoctorReportV1::Read(admitted) => RuntimeDoctorReportV1::Observed { + report: admitted.report.clone(), + table_growth_evidence: admitted.table_growth_evidence.clone(), + schema_convergences: admitted.schema_convergences.clone(), + language_servers: admitted.language_servers.clone(), + }, + McpDoctorReportV1::ReadFailed => RuntimeDoctorReportV1::Unknown { + table_growth_evidence: Vec::new(), + schema_convergences: Vec::new(), + language_servers: LanguageServerReadV1::Unknown, + }, + McpDoctorReportV1::NotAttached => RuntimeDoctorReportV1::Unsupported { + table_growth_evidence: Vec::new(), + schema_convergences: Vec::new(), + language_servers: LanguageServerReadV1::Unsupported, + }, + } } pub async fn collect_database_snapshot( @@ -207,16 +209,13 @@ async fn collect_runtime_snapshot( /// Surfaces process and database telemetry so users hitting unexpected /// CPU/RAM pressure can attach a structured snapshot to a bug report. #[hotpath::measure(label = "mcp.health.runtime.total")] -pub async fn handle_runtime( +pub async fn compute_runtime( ctx: &McpToolContext<'_>, - args: Value, + request: &RuntimeSurfaceRequestV1, registry: Option<&RegisteredGlobalDb>, tracedecay_version: &str, -) -> Result { - let authority_audit = args - .get("authority_audit") - .and_then(Value::as_bool) - .unwrap_or(false); +) -> Result { + let authority_audit = request.authority_audit; let snap = hotpath::future!( collect_runtime_snapshot(ctx, authority_audit, tracedecay_version), label = "mcp.health.runtime.telemetry" @@ -225,17 +224,25 @@ pub async fn handle_runtime( // A snapshot that cannot be serialized is a contract bug, not an empty // status: swallowing it into `{}` made doctor report "omitted database // telemetry" with no trace of the cause. - let mut value = serde_json::to_value(&snap).map_err(|error| TraceDecayError::Config { + let serialization_error = |error: serde_json::Error| TraceDecayError::Config { message: format!("runtime telemetry snapshot could not be serialized: {error}"), - })?; + }; + let mut database = serde_json::to_value(&snap.database).map_err(serialization_error)?; + let mut runtime = RuntimeResultV1 { + captured_at: snap.captured_at, + tracedecay_version: snap.tracedecay_version, + host_os: snap.host_os, + process: serde_json::to_value(&snap.process).map_err(serialization_error)?, + database: Value::Null, + session_temporal_health: None, + cursor_session_ingest: None, + cursor_session_placeholder_paths: None, + doctor_report: None, + }; // Doctor historically keys temporal health off `authority_audit`. Keep that // coupling, and also allow an explicit independent opt-in. - let include_session_temporal_health = authority_audit - || args - .get("session_temporal_health") - .and_then(Value::as_bool) - .unwrap_or(false); - if authority_audit || include_session_temporal_health { + let include_session_temporal_health = authority_audit || request.session_temporal_health; + if include_session_temporal_health { let (authority, temporal) = tokio::join!( async { if authority_audit { @@ -250,25 +257,16 @@ pub async fn handle_runtime( None } }, - async { - if include_session_temporal_health { - Some( - hotpath::future!( - session_temporal_health_value( - ctx.authorized_project_session_db() - .map(|(lease, _)| lease.as_ref()), - ), - label = "mcp.health.runtime.session_temporal" - ) - .await, - ) - } else { - None - } - } + hotpath::future!( + session_temporal_health_value( + ctx.authorized_project_session_db() + .map(|(lease, _)| lease.as_ref()), + ), + label = "mcp.health.runtime.session_temporal" + ) ); if let Some((authority_audit_ok, authority_audit_reason, authority_audit_error)) = authority - && let Some(database) = value.get_mut("database").and_then(Value::as_object_mut) + && let Some(database) = database.as_object_mut() { database.insert("authority_audit_ok".to_string(), json!(authority_audit_ok)); database.insert( @@ -280,93 +278,70 @@ pub async fn handle_runtime( json!(authority_audit_error), ); } - if let Some(temporal) = temporal { - value["session_temporal_health"] = temporal; - } + runtime.session_temporal_health = Some(temporal); } - if args - .get("session_ingest_health") - .and_then(Value::as_bool) - .unwrap_or(false) - { + runtime.database = database; + if request.session_ingest_health { match ctx.authorized_project_session_db() { Some((lease, _)) => { let db = lease.as_ref(); - value["cursor_session_ingest"] = match hotpath::future!( - db.cursor_session_ingest_health(), - label = "mcp.health.runtime.session_ingest" - ) - .await - { - Ok(health) => serde_json::to_value(health).unwrap_or_else(|error| { - json!({ + runtime.cursor_session_ingest = Some( + match hotpath::future!( + db.cursor_session_ingest_health(), + label = "mcp.health.runtime.session_ingest" + ) + .await + { + Ok(health) => serde_json::to_value(health).map_err(serialization_error)?, + Err(error) => json!({ "status": "unavailable", - "reason": "session_ingest_serialization_failed", - "message": error.to_string(), - }) - }), - Err(error) => json!({ - "status": "unavailable", - "reason": "session_ingest_query_failed", - "message": error, - }), - }; - match hotpath::future!( - db.read_snapshot(), - label = "mcp.health.runtime.session_snapshot" - ) - .await - { - Ok(snapshot) => { - value["cursor_session_placeholder_paths"] = json!( + "reason": "session_ingest_query_failed", + "message": error, + }), + }, + ); + runtime.cursor_session_placeholder_paths = Some( + match hotpath::future!( + db.read_snapshot(), + label = "mcp.health.runtime.session_snapshot" + ) + .await + { + Ok(snapshot) => { hotpath::future!( literal_workspace_placeholder_transcript_paths(&snapshot, 10), label = "mcp.health.runtime.placeholder_paths" ) .await - ); - } - Err(_) => { - value["cursor_session_placeholder_paths"] = json!([]); - } - } + } + Err(_) => Vec::new(), + }, + ); } None => { - value["cursor_session_ingest"] = json!({ + runtime.cursor_session_ingest = Some(json!({ "status": "unavailable", "reason": "session_store_denied", "message": "this request is not authorized to read the admitted project session store", - }); + })); } } } - if args - .get("doctor_report") - .and_then(Value::as_bool) - .unwrap_or(false) - { - attach_doctor_report(&mut value, ctx.doctor_report()); + if request.doctor_report { + runtime.doctor_report = Some(runtime_doctor_report(ctx.doctor_report())); } - Ok(generic_tool_result( - Some(&ctx.store_layout().response_handle_root), - &args, - &value, - vec![], - )) + Ok(runtime) } #[cfg(test)] mod tests { use super::*; - #[tokio::test] - async fn requested_doctor_report_is_typed_unavailable_without_reader() { - let mut value = json!({}); - - attach_doctor_report(&mut value, McpDoctorReportV1::NotAttached); - + #[test] + fn requested_doctor_report_is_typed_unsupported_without_reader() { assert_eq!( - value["doctor_report"], + serde_json::to_value(runtime_doctor_report(McpDoctorReportV1::NotAttached)) + .expect("doctor report serializes"), json!({ "kind": "unsupported", "table_growth_evidence": [], diff --git a/crates/tracedecay-mcp/src/handlers/info/mod.rs b/crates/tracedecay-mcp/src/handlers/info/mod.rs index c2012ed2a6..976f722df6 100644 --- a/crates/tracedecay-mcp/src/handlers/info/mod.rs +++ b/crates/tracedecay-mcp/src/handlers/info/mod.rs @@ -18,11 +18,12 @@ pub use files::compute_files; pub(crate) use files::render_files_md; pub use port_order::compute_port_order; pub use port_status::compute_port_status; -pub use registry::{handle_project_context, handle_project_list, handle_project_search}; -pub use remote_status::handle_remote_status; +pub use registry::compute_registry_read; +pub(crate) use registry::render_registry_listing_md; +pub use remote_status::read_remote_status; +pub(crate) use status::render_status_md; pub use status::{ - graph_statistics_value, handle_active_project, handle_status, readiness_wait_outcome, - status_readiness_wait, + compute_active_project, compute_status, graph_statistics_value, readiness_wait_outcome, }; pub use todos::compute_todos; diff --git a/crates/tracedecay-mcp/src/handlers/info/registry.rs b/crates/tracedecay-mcp/src/handlers/info/registry.rs index 7b02ae5097..b93b65bbf0 100644 --- a/crates/tracedecay-mcp/src/handlers/info/registry.rs +++ b/crates/tracedecay-mcp/src/handlers/info/registry.rs @@ -3,83 +3,29 @@ use std::path::Path; -use serde_json::{Value, json}; +use serde_json::Value; +use tracedecay_contracts::graph_tool::{GraphToolCompletionV1, GraphToolResultV1}; +use tracedecay_contracts::retrieval::{ + ProjectContextResultV1, ProjectContextSurfaceRequestV1, ProjectListSurfaceRequestV1, + ProjectRegistryListingResultV1, ProjectSearchSurfaceRequestV1, +}; use tracedecay_contracts::{ ProjectRegistryContextCommand, ProjectRegistryContextOutcome, ProjectRegistryListingCommand, - ProjectRegistryListingOutcome, ProjectRegistryListingScope, ProjectRegistryReadPort, - ProjectRegistrySelector, ProjectRegistryView, list_registered_projects, - read_registered_project_context, render_project_registry_view, + ProjectRegistryListingScope, ProjectRegistryListingView, ProjectRegistryReadPort, + ProjectRegistrySelector, ProjectRegistryView, render_project_registry_view, }; use tracedecay_domain::errors::{Result, TraceDecayError}; +use tracedecay_tool_catalog::ApplicationSurfaceOperation; -use crate::ToolResult; -use crate::rendered_tool_result; -use crate::tools::render; +use crate::handlers::graph::graph_tool_completion; +use crate::handlers::support::{decode_primitive_request, decode_selector_request}; fn display_path(path: &Path) -> String { path.display().to_string() } -fn bounded_limit(args: &Value, default: usize, max: usize) -> usize { - args.get("limit") - .and_then(Value::as_u64) - .and_then(|value| usize::try_from(value).ok()) - .map_or(default, |value| value.clamp(1, max)) -} - -fn registry_result(args: &Value, payload: &Value) -> ToolResult { - render_registry_result(None, args, payload) -} - -/// The registry tree view renders only an `ok` listing. An `unavailable` -/// payload carries the same zeroed tree keys for shape stability and must -/// not be read back as "no registered projects". -fn render_registry_result( - response_handle_root: Option<&Path>, - args: &Value, - payload: &Value, -) -> ToolResult { - rendered_tool_result(response_handle_root, args, payload, vec![], || { - if payload.get("status").and_then(Value::as_str) == Some("ok") - && payload.get("project_tree").is_some() - { - let view = serde_json::from_value::(json!({ - "summary": payload.get("summary").cloned().unwrap_or_else(|| json!({})), - "project_tree": payload.get("project_tree").cloned().unwrap_or_else(|| json!([])), - })); - if let Ok(view) = view { - let title = payload - .get("title") - .and_then(Value::as_str) - .unwrap_or("registered projects"); - return render_project_registry_view(title, &view); - } - } - render::generic_md(payload) - }) -} - -fn registry_missing_payload() -> Value { - json!({ - "status": "unavailable", - "message": "project registry is not present for this profile", - "projects": [], - }) -} - -/// Zeroed summary/tree keys for the missing-registry branch, mirroring the -/// ok-shape's `summary`/`project_tree` so callers get a stable payload shape -/// regardless of whether the registry is present. -fn empty_registry_view_payload(title: &str) -> (Value, Value, Value) { - ( - json!(title), - json!({ - "project_count": 0, - "repo_count": 0, - "truncated": false, - }), - json!([]), - ) +fn bounded_limit(limit: Option, default: usize, max: usize) -> usize { + limit.map_or(default, |value| value.clamp(1, max)) } /// Whether a selector names a path rather than a bare project name. Pure @@ -96,131 +42,141 @@ fn is_explicit_project_path_selector(selector: &str) -> bool { || selector.contains('\\')) } -/// `project_root` is the served project when the call arrives over a -/// project connection; a projectless connection reads the same profile -/// registry with `None` and marks no project active. -#[hotpath::measure(label = "mcp.info.project_list.total")] -pub async fn handle_project_list( - project_root: Option<&Path>, +/// Computes one profile registry read. `active_project_root` is the project +/// the calling connection serves, when it has one; it only marks that +/// project active and is the context read's default selector. +#[hotpath::measure(future = true, label = "mcp.info.project_registry.total")] +pub async fn compute_registry_read( + registry: &dyn ProjectRegistryReadPort, + active_project_root: Option<&Path>, + operation: ApplicationSurfaceOperation, args: Value, - registry: Option<&dyn ProjectRegistryReadPort>, -) -> Result { - let limit = bounded_limit(&args, 25, 100); - let outcome = hotpath::future!( - list_registered_projects( - registry, - ProjectRegistryListingCommand { - active_project_root: project_root.map(Path::to_path_buf), - scope: ProjectRegistryListingScope::All, +) -> Result { + let tool_name = operation.mcp_tool_name(); + let active_project_root = active_project_root.map(Path::to_path_buf); + let result = match operation { + ApplicationSurfaceOperation::ProjectList => { + let request: ProjectListSurfaceRequestV1 = decode_primitive_request(&args, tool_name)?; + let limit = bounded_limit(request.limit, 25, 100); + let listing = registry + .list(ProjectRegistryListingCommand { + active_project_root, + scope: ProjectRegistryListingScope::All, + limit, + }) + .await?; + GraphToolResultV1::ProjectList(listing_result( + "registered projects".to_owned(), + None, limit, - }, - ), - label = "mcp.info.project_list.list" - ) - .await?; - Ok(registry_listing_result( - &args, - "registered projects", - None, - limit, - outcome, - )) -} - -#[hotpath::measure(label = "mcp.info.project_search.total")] -pub async fn handle_project_search( - project_root: Option<&Path>, - args: Value, - registry: Option<&dyn ProjectRegistryReadPort>, -) -> Result { - let query = args - .get("query") - .and_then(Value::as_str) - .ok_or_else(|| TraceDecayError::Config { - message: "missing required parameter: query".to_string(), - })? - .to_owned(); - let limit = bounded_limit(&args, 10, 50); - let outcome = hotpath::future!( - list_registered_projects( - registry, - ProjectRegistryListingCommand { - active_project_root: project_root.map(Path::to_path_buf), - scope: ProjectRegistryListingScope::Matching { - query: query.clone(), - }, + listing, + )) + } + ApplicationSurfaceOperation::ProjectSearch => { + let request: ProjectSearchSurfaceRequestV1 = + decode_primitive_request(&args, tool_name)?; + let limit = bounded_limit(request.limit, 10, 50); + let listing = registry + .list(ProjectRegistryListingCommand { + active_project_root, + scope: ProjectRegistryListingScope::Matching { + query: request.query.clone(), + }, + limit, + }) + .await?; + GraphToolResultV1::ProjectSearch(listing_result( + format!("projects matching \"{}\"", request.query), + Some(request.query), limit, - }, - ), - label = "mcp.info.project_search.search" - ) - .await?; - Ok(registry_listing_result( - &args, - &format!("projects matching \"{query}\""), - Some(&query), - limit, - outcome, - )) -} - -/// Renders a listing outcome, keeping the missing-registry state a stable -/// `unavailable` payload with the same summary/tree keys as the `ok` shape. -fn registry_listing_result( - args: &Value, - title: &str, - query: Option<&str>, - limit: usize, - outcome: ProjectRegistryListingOutcome, -) -> ToolResult { - match outcome { - ProjectRegistryListingOutcome::RegistryUnavailable => { - let mut payload = registry_missing_payload(); - let (title, summary, project_tree) = empty_registry_view_payload(title); - payload["title"] = title; - payload["summary"] = summary; - payload["project_tree"] = project_tree; - if let Some(query) = query { - payload["query"] = json!(query); - } - payload["limit"] = json!(limit); - payload["truncated"] = json!(false); - registry_result(args, &payload) + listing, + )) + } + ApplicationSurfaceOperation::ProjectContext => { + let request: ProjectContextSurfaceRequestV1 = + decode_selector_request(&args, tool_name)?; + let selector = project_context_selector(active_project_root.as_deref(), request)?; + let outcome = registry + .context(ProjectRegistryContextCommand { + active_project_root, + selector, + }) + .await?; + GraphToolResultV1::ProjectContext(match outcome { + ProjectRegistryContextOutcome::NotFound { registry_path } => { + ProjectContextResultV1::NotFound { + registry_path: display_path(®istry_path), + project: (), + aliases: Vec::new(), + stores: Vec::new(), + } + } + ProjectRegistryContextOutcome::Context(context) => ProjectContextResultV1::Ok { + is_active: context.is_active, + registry_path: display_path(&context.registry_path), + project: Box::new(context.project), + aliases: context.aliases, + stores: context.stores, + }, + }) } - ProjectRegistryListingOutcome::Listing(listing) => { - let mut payload = json!({ - "status": "ok", - "title": title, - "registry_path": display_path(&listing.registry_path), - "limit": limit, - "truncated": listing.truncated, - "summary": listing.view.summary, - "project_tree": listing.view.project_tree, - "projects": listing.projects, + operation => { + return Err(TraceDecayError::Config { + message: format!( + "unknown tool: {} is not a profile registry read", + operation.mcp_tool_name() + ), }); - if let Some(query) = query { - payload["query"] = json!(query); - } - registry_result(args, &payload) } + }; + Ok(graph_tool_completion(result, Vec::new())) +} + +fn listing_result( + title: String, + query: Option, + limit: usize, + listing: ProjectRegistryListingView, +) -> ProjectRegistryListingResultV1 { + ProjectRegistryListingResultV1::Ok { + title, + registry_path: display_path(&listing.registry_path), + query, + limit, + truncated: listing.truncated, + summary: listing.view.summary, + project_tree: listing.view.project_tree, + projects: listing.projects, } } +/// The listing's tree view as the registry tools render it. +pub(crate) fn render_registry_listing_md(listing: &ProjectRegistryListingResultV1) -> String { + let ProjectRegistryListingResultV1::Ok { + title, + summary, + project_tree, + .. + } = listing; + render_project_registry_view( + title, + &ProjectRegistryView { + summary: summary.clone(), + project_tree: project_tree.clone(), + }, + ) +} + /// The selector defaults to the served project root; a projectless call has /// no such default and must name the project explicitly. fn project_context_selector( project_root: Option<&Path>, - args: &Value, + request: ProjectContextSurfaceRequestV1, ) -> Result { - if let Some(project_id) = args - .get("project_selector") - .and_then(Value::as_object) - .and_then(|selector| selector.get("project_id")) - .and_then(Value::as_str) - { - return Ok(ProjectRegistrySelector::ProjectId(project_id.to_owned())); + if let Some(selector) = request.project_selector { + return Ok(ProjectRegistrySelector::ProjectId(selector.project_id)); } - let Some(path) = args.get("path").and_then(Value::as_str) else { + let Some(path) = request.path else { let Some(project_root) = project_root else { return Err(TraceDecayError::Config { message: "missing required parameter: path or project_selector (no active \ @@ -233,7 +189,7 @@ fn project_context_selector( allow_git_identity: true, }); }; - let path = Path::new(path); + let path = Path::new(&path); let allow_git_identity = path.is_absolute() && is_explicit_project_path_selector(path.to_string_lossy().as_ref()); Ok(ProjectRegistrySelector::Path { @@ -242,109 +198,30 @@ fn project_context_selector( }) } -#[hotpath::measure(label = "mcp.info.project_context.total")] -pub async fn handle_project_context( - project_root: Option<&Path>, - response_handle_root: Option<&Path>, - args: Value, - registry: Option<&dyn ProjectRegistryReadPort>, -) -> Result { - let selector = project_context_selector(project_root, &args)?; - let outcome = hotpath::future!( - read_registered_project_context( - registry, - ProjectRegistryContextCommand { - active_project_root: project_root.map(Path::to_path_buf), - selector, - }, - ), - label = "mcp.info.project_context.read" - ) - .await?; - let payload = match outcome { - ProjectRegistryContextOutcome::RegistryUnavailable => registry_missing_payload(), - ProjectRegistryContextOutcome::NotFound { registry_path } => json!({ - "status": "not_found", - "registry_path": display_path(®istry_path), - "project": null, - "aliases": [], - "stores": [], - }), - ProjectRegistryContextOutcome::Context(context) => json!({ - "status": "ok", - "is_active": context.is_active, - "registry_path": display_path(&context.registry_path), - "project": context.project, - "aliases": context.aliases, - "stores": context.stores, - }), - }; - Ok(render_registry_result( - response_handle_root, - &args, - &payload, - )) -} - #[cfg(test)] mod tests { use std::path::Path; - use serde_json::json; - use tracedecay_contracts::{ProjectRegistryListingOutcome, ProjectRegistrySelector}; - - use super::{project_context_selector, registry_listing_result, registry_missing_payload}; - - #[test] - fn missing_registry_payload_preserves_unavailable_state() { - let payload = registry_missing_payload(); - - assert_eq!(payload["status"], "unavailable"); - assert_eq!( - payload["message"], - "project registry is not present for this profile" - ); - assert_eq!(payload["projects"].as_array().map(Vec::len), Some(0)); - assert!(payload.get("registry_path").is_none()); - } + use tracedecay_contracts::ProjectRegistrySelector; + use tracedecay_contracts::retrieval::{ + ProjectContextSurfaceRequestV1, RegisteredProjectIdSelectorV1, + }; - /// The rendered text of an unavailable registry must say so; the zeroed - /// tree keys exist for payload-shape stability, not to read as an empty - /// listing. - #[test] - fn unavailable_listing_does_not_render_as_an_empty_registry() { - let result = registry_listing_result( - &json!({}), - "registered projects", - None, - 25, - ProjectRegistryListingOutcome::RegistryUnavailable, - ); - let text = result.value["content"][0]["text"] - .as_str() - .expect("rendered text"); - assert!( - text.contains("unavailable") && text.contains("not present"), - "unavailable state must survive rendering, got:\n{text}" - ); - assert!( - !text.contains("No registered projects found"), - "an absent registry must not read as an empty one, got:\n{text}" - ); - } + use super::project_context_selector; #[test] fn project_context_selector_defaults_to_the_served_root_only_when_one_exists() { let served = Path::new("/srv/checkout"); assert_eq!( - project_context_selector(Some(served), &json!({})).expect("served root selector"), + project_context_selector(Some(served), ProjectContextSurfaceRequestV1::default()) + .expect("served root selector"), ProjectRegistrySelector::Path { path: served.to_path_buf(), allow_git_identity: true, } ); - let error = project_context_selector(None, &json!({})) + let error = project_context_selector(None, ProjectContextSurfaceRequestV1::default()) .expect_err("a projectless read with no selector must be refused"); assert!( error @@ -361,8 +238,14 @@ mod tests { "/srv/other" }; assert_eq!( - project_context_selector(None, &json!({"path": other})) - .expect("explicit path selector"), + project_context_selector( + None, + ProjectContextSurfaceRequestV1 { + project_selector: None, + path: Some(other.to_owned()), + } + ) + .expect("explicit path selector"), ProjectRegistrySelector::Path { path: Path::new(other).to_path_buf(), allow_git_identity: true, @@ -371,7 +254,12 @@ mod tests { assert_eq!( project_context_selector( None, - &json!({"project_selector": {"project_id": "project.other"}}) + ProjectContextSurfaceRequestV1 { + project_selector: Some(RegisteredProjectIdSelectorV1 { + project_id: "project.other".to_owned(), + }), + path: None, + } ) .expect("project id selector"), ProjectRegistrySelector::ProjectId("project.other".to_owned()) diff --git a/crates/tracedecay-mcp/src/handlers/info/remote_status.rs b/crates/tracedecay-mcp/src/handlers/info/remote_status.rs index 4799114572..b0e028e8c3 100644 --- a/crates/tracedecay-mcp/src/handlers/info/remote_status.rs +++ b/crates/tracedecay-mcp/src/handlers/info/remote_status.rs @@ -1,62 +1,18 @@ //! `tracedecay_remote_status`, Remote Brain operational-plane read. -use std::path::Path; - -use serde_json::Value; use tracedecay_contracts::remote::status::RemoteOperationalStatusReadV1; use tracedecay_contracts::remote::status::RemoteOperationalStatusReaderV1; -use tracedecay_domain::errors::Result; - -use crate::ToolResult; -use crate::tool_json; /// Reads the daemon-mounted Remote Brain operational plane. /// /// Absence of the provider is the typed unmounted-authority outcome /// [`RemoteOperationalStatusReadV1::Unavailable`], never an empty success. #[hotpath::measure(label = "mcp.info.remote_status.total")] -pub fn handle_remote_status( - response_handle_root: &Path, - args: &Value, +pub fn read_remote_status( provider: Option<&RemoteOperationalStatusReaderV1>, -) -> Result { - let status = match provider { +) -> RemoteOperationalStatusReadV1 { + match provider { Some(provider) => provider(), None => RemoteOperationalStatusReadV1::Unavailable, - }; - let value = serde_json::to_value(&status)?; - Ok(tool_json(Some(response_handle_root), args, &value)) -} - -#[cfg(test)] -mod tests { - use std::path::Path; - - use serde_json::{Value, json}; - - use super::handle_remote_status; - use crate::ToolResult; - - fn parse_tool_json(result: &ToolResult) -> Value { - serde_json::from_str( - result.value["content"][0]["text"] - .as_str() - .expect("tool JSON text"), - ) - .expect("parse tool JSON") - } - - #[test] - fn handler_returns_typed_unavailable_when_provider_is_absent() { - let result = handle_remote_status( - Path::new("response-handles"), - &json!({ "format": "json" }), - None, - ) - .expect("absent provider is a typed read"); - let parsed = parse_tool_json(&result); - assert_eq!(parsed, json!({ "kind": "unavailable" })); - assert_ne!(parsed, json!({})); - assert_ne!(result.semantic_error(), Some(true)); } } diff --git a/crates/tracedecay-mcp/src/handlers/info/status.rs b/crates/tracedecay-mcp/src/handlers/info/status.rs index 1bca967055..5b0236353a 100644 --- a/crates/tracedecay-mcp/src/handlers/info/status.rs +++ b/crates/tracedecay-mcp/src/handlers/info/status.rs @@ -7,11 +7,20 @@ use tracedecay_application::advisory::github_runtime::github_source_status_v1; use tracedecay_application::tracedecay::BranchDiagnostics; use tracedecay_contracts::code_index_freshness::{ CodeIndexFreshnessCoverageV1, CodeIndexReadinessWaitOutcomeV1, CodeIndexReadinessWaitReadV1, - CodeIndexReadinessWaitV1, CodeIndexStalenessStateV1, + CodeIndexStalenessStateV1, CodeIndexWorktreeFreshnessV1, +}; +use tracedecay_contracts::doctor::ResidentMemoryHolderReadV1; +use tracedecay_contracts::retrieval::{ + ActiveProjectBranchV1, ActiveProjectResolutionSourceV1, ActiveProjectResultV1, + ActiveProjectStorageV1, ProjectStatusV1, StatusAdmissionV1, StatusBranchMismatchV1, + StatusCodeIndexFreshnessV1, StatusGitStalenessV1, StatusMemoryOwnerV1, StatusMemoryPressureV1, + StatusMemoryV1, StatusResultV1, StatusRetrievalServingV1, StatusSchemaConvergenceStateV1, + StatusSchemaConvergenceV1, StatusServingConditionV1, StatusServingFreshnessV1, + StatusSurfaceRequestV1, }; use tracedecay_contracts::storage::{SchemaConvergenceFindingV1, SchemaConvergenceStateV1}; -use tracedecay_domain::errors::{Result, TraceDecayError}; -use tracedecay_domain::{ManifestDigest, ProjectId}; +use tracedecay_domain::ProjectId; +use tracedecay_domain::errors::Result; use tracedecay_global_db::{RegisteredGlobalDb, SessionIngestHealth}; use tracedecay_runtime_core::resident_memory::{ RESIDENT_OWNER_SHED_ORDER_V1, ResidentMemoryPressureStateV1, ResidentMemoryPressureV1, @@ -21,27 +30,13 @@ use tracedecay_runtime_core::resident_memory::{ use tracedecay_runtime_core::runtime_telemetry::GenerationCensusSnapshot; use tracedecay_runtime_core::storage::{StorageMode, StoreKind}; +use crate::McpToolContext; use crate::tools::render::Md; -use crate::{McpToolContext, ToolResult, generic_tool_result, rendered_tool_result}; fn display_path(path: &Path) -> String { path.display().to_string() } -/// The `wait_for` argument, when present. -pub fn status_readiness_wait(args: &Value) -> Result> { - match args.get("wait_for") { - None | Some(Value::Null) => Ok(None), - Some(wait_for) => serde_json::from_value(wait_for.clone()) - .map(Some) - .map_err(|error| TraceDecayError::Config { - message: format!( - "tracedecay_status wait_for must be {{\"state\": \"fresh\"|\"ready\"|\"graph_ready\", \"timeout_ms\": }}: {error}" - ), - }), - } -} - /// Project what a readiness wait observed onto the caller-facing outcome. /// `last_state` is the `code_index_freshness.status` label of the last /// reading, or `not_mounted` when no scheduler was mounted for the root. @@ -56,7 +51,7 @@ pub fn readiness_wait_outcome( last_state: last .as_ref() .map_or("not_mounted", |freshness| { - code_index_freshness_projection(freshness).0 + code_index_freshness_projection(freshness).0.as_str() }) .to_owned(), } @@ -67,16 +62,12 @@ pub fn readiness_wait_outcome( } } -fn status_arg_flag(args: &Value, key: &str, default: bool) -> bool { - args.get(key).and_then(Value::as_bool).unwrap_or(default) -} - -fn schema_convergence_status(findings: &[SchemaConvergenceFindingV1]) -> Value { +fn schema_convergence_status(findings: &[SchemaConvergenceFindingV1]) -> StatusSchemaConvergenceV1 { let status = if findings .iter() .any(|finding| finding.state == SchemaConvergenceStateV1::Degraded) { - "degraded" + StatusSchemaConvergenceStateV1::Degraded } else if findings.iter().any(|finding| { matches!( finding.state, @@ -84,11 +75,14 @@ fn schema_convergence_status(findings: &[SchemaConvergenceFindingV1]) -> Value { | SchemaConvergenceStateV1::ReleasedShapeConvergenceInProgress ) }) { - "in_progress" + StatusSchemaConvergenceStateV1::InProgress } else { - "completed" + StatusSchemaConvergenceStateV1::Completed }; - json!({ "status": status, "findings": findings }) + StatusSchemaConvergenceV1 { + status, + findings: findings.to_vec(), + } } /// Whether exact-scope code retrieval can serve at all, derived from the same @@ -99,61 +93,14 @@ fn schema_convergence_status(findings: &[SchemaConvergenceFindingV1]) -> Value { /// every retrieval lane truthfully refused `generation_rebuilding`. Status /// must report the same serving truth the lanes enforce: the branch claim is /// gated on a sealed complete generation existing, and the typed -/// `retrieval_serving` field carries the lane-level answer either way. -enum CodeIndexRetrievalServingV1 { - /// A sealed complete generation exists for the exact worktree. The ages - /// distinguish a routine rebuild window from a wedged route: a seat - /// sealed days ago whose last reconcile observation is equally old is a - /// daemon serving stale answers with nothing progressing, and "serving" - /// alone must not mask that. - Serving { - freshness: &'static str, - condition: Option<&'static str>, - seated_generation_age_seconds: Option, - last_reconcile_age_seconds: Option, - }, - /// The daemon census answered and nothing is servable yet. - NotServing { reason: &'static str }, - /// No census authority is attached (non-daemon server); status cannot - /// claim or deny lane-serving truth. - AuthorityUnattached, -} - -impl CodeIndexRetrievalServingV1 { - fn attach(&self, output: &mut Value) -> bool { - match self { - Self::Serving { - freshness, - condition, - seated_generation_age_seconds, - last_reconcile_age_seconds, - } => { - let mut serving = json!({ - "status": "serving", - "freshness": freshness, - }); - if let Some(condition) = condition { - serving["condition"] = json!(condition); - } - if let Some(age) = seated_generation_age_seconds { - serving["seated_generation_age_seconds"] = json!(age); - } - if let Some(age) = last_reconcile_age_seconds { - serving["last_reconcile_age_seconds"] = json!(age); - } - output["retrieval_serving"] = serving; - true - } - Self::NotServing { reason } => { - output["retrieval_serving"] = json!({ - "status": "unavailable", - "reason": reason, - }); - false - } - Self::AuthorityUnattached => true, - } - } +/// `retrieval_serving` field carries the lane-level answer either way. No +/// census authority attached (a non-daemon server) leaves it absent: status +/// can then neither claim nor deny lane-serving truth. +fn branch_servable(retrieval_serving: Option<&StatusRetrievalServingV1>) -> bool { + !matches!( + retrieval_serving, + Some(StatusRetrievalServingV1::Unavailable { .. }) + ) } /// Whole seconds elapsed since a recorded microsecond timestamp, clamped at @@ -194,75 +141,65 @@ fn ready_serving_source( } fn attach_compact_branch_summary( - open_active_branch: Option<&str>, - serving_branch: Option<&str>, - output: &mut Value, - retrieval_serving: &CodeIndexRetrievalServingV1, + open_active_branch: Option, + serving_branch: Option, + status: &mut ProjectStatusV1, ) { // Both status shapes consume the serving identity reconciled with the // ready generation source below. // Do not alias open/active into current/live: those are distinct under drift. - if let Some(active) = open_active_branch { - output["active_branch"] = json!(active); - } - let branch_servable = retrieval_serving.attach(output); - if branch_servable && let Some(serving) = serving_branch { - output["serving_branch"] = json!(serving); + status.active_branch = open_active_branch; + if branch_servable(status.retrieval_serving.as_ref()) { + status.serving_branch = serving_branch; } } fn attach_full_branch_status( branch_diagnostics: &BranchDiagnostics, - output: &mut Value, - retrieval_serving: &CodeIndexRetrievalServingV1, -) { - output["branch_diagnostics"] = json!(&branch_diagnostics); - if let Some(open_branch) = branch_diagnostics.open_active_branch.as_deref() { - output["active_branch"] = json!(open_branch); - } - if let Some(current_branch) = branch_diagnostics.current_branch.as_deref() { - output["current_branch"] = json!(current_branch); - output["live_branch"] = json!(current_branch); - } - let branch_servable = retrieval_serving.attach(output); - if branch_servable && let Some(serving_branch) = branch_diagnostics.serving_branch.as_deref() { - output["serving_branch"] = json!(serving_branch); + status: &mut ProjectStatusV1, +) -> Result<()> { + status.branch_diagnostics = Some(serde_json::to_value(branch_diagnostics)?); + status + .active_branch + .clone_from(&branch_diagnostics.open_active_branch); + status + .current_branch + .clone_from(&branch_diagnostics.current_branch); + status + .live_branch + .clone_from(&branch_diagnostics.current_branch); + if branch_servable(status.retrieval_serving.as_ref()) { + status + .serving_branch + .clone_from(&branch_diagnostics.serving_branch); } - if let Some(parent) = branch_diagnostics + status.parent_branch = branch_diagnostics .branches .iter() .find(|entry| entry.is_serving) - .and_then(|entry| entry.parent.as_deref()) - { - output["parent_branch"] = json!(parent); - } - output["branch_drifted"] = json!(branch_diagnostics.branch_drifted); - output["branch_resolution"] = json!(branch_diagnostics.branch_resolution.clone()); - output["tracked_branch_count"] = json!(branch_diagnostics.tracked_branch_count); + .and_then(|entry| entry.parent.clone()); + status.branch_drifted = Some(branch_diagnostics.branch_drifted); + status.branch_resolution = Some(branch_diagnostics.branch_resolution.clone()); + status.tracked_branch_count = Some(branch_diagnostics.tracked_branch_count); if branch_diagnostics.branch_drifted { - output["branch_mismatch"] = json!({ - "git_branch": branch_diagnostics.current_branch, - "indexed_branch": branch_diagnostics.open_active_branch, - "serving_branch": branch_diagnostics.serving_branch, + status.branch_mismatch = Some(StatusBranchMismatchV1 { + git_branch: branch_diagnostics.current_branch.clone(), + indexed_branch: branch_diagnostics.open_active_branch.clone(), + serving_branch: branch_diagnostics.serving_branch.clone(), }); } if !branch_diagnostics.warnings.is_empty() { - output["branch_warnings"] = json!(branch_diagnostics.warnings); + status.branch_warnings = Some(branch_diagnostics.warnings.clone()); } + Ok(()) } -/// Serialize the generation census exactly as the CLI decoder reads it back. -/// -/// [`tracedecay_runtime_core::runtime_telemetry::GenerationCensusSnapshot`] is the single wire -/// authority for the `graph_statistics` field: this route serializes it and -/// `tracedecay status` deserializes the same Rust type, so the two sides -/// cannot drift. /// The daemon's resident memory as one project sees it: process RSS against /// the admission ceiling and pressure line, the daemon-wide retained totals, /// and this project's retained owners with their bytes, idle time, and /// whether pressure may shed them. Other projects' owners belong to the /// daemon-wide Doctor inventory, never to a project read. -fn project_memory_value(project_id: &ProjectId) -> Value { +fn project_memory_value(project_id: &ProjectId) -> StatusMemoryV1 { memory_value( process_resident_memory_pressure_v1(), process_resident_owners_v1(), @@ -278,56 +215,64 @@ fn memory_value( psi_some_avg10: Option, now: std::time::Instant, project_id: &ProjectId, -) -> Value { - let (state, resident_bytes) = match pressure.state() { - ResidentMemoryPressureStateV1::Unobserved => ("unobserved", None), +) -> StatusMemoryV1 { + let (status, resident_bytes) = match pressure.state() { + ResidentMemoryPressureStateV1::Unobserved => (StatusMemoryPressureV1::Unobserved, None), ResidentMemoryPressureStateV1::Nominal { observed_bytes, .. } => { - ("nominal", Some(observed_bytes)) + (StatusMemoryPressureV1::Nominal, Some(observed_bytes)) } ResidentMemoryPressureStateV1::OverBudget { observed_bytes, .. } => { - ("over_budget", Some(observed_bytes)) + (StatusMemoryPressureV1::OverBudget, Some(observed_bytes)) } }; let report = owners.report(now); - let rows = report + let owners = report .owners .iter() .filter(|row| row.project_id == *project_id) - .map(|row| { - json!({ - "project_id": row.project_id.as_str(), - "kind": row.kind.as_str(), - "holders": row - .holders - .iter() - .map(|holder| json!({ - "worktree_id": holder.worktree_id.as_str(), - "holding": holder.holding.as_str(), - })) - .collect::>(), - "content_digest": row.content_digest.as_ref().map(ManifestDigest::as_str), - "bytes": row.bytes.measured(), - "measured": row.bytes.measured().is_some(), - "idle_seconds": row.idle_for.as_secs(), - "protected": row.protected, - }) + .map(|row| StatusMemoryOwnerV1 { + project_id: row.project_id.as_str().to_owned(), + kind: row.kind.as_str().to_owned(), + holders: row + .holders + .iter() + .map(|holder| ResidentMemoryHolderReadV1 { + worktree_id: holder.worktree_id.as_str().to_owned(), + holding: holder.holding.as_str().to_owned(), + }) + .collect(), + content_digest: row + .content_digest + .as_ref() + .map(|digest| digest.as_str().to_owned()), + bytes: row.bytes.measured(), + measured: row.bytes.measured().is_some(), + idle_seconds: row.idle_for.as_secs(), + protected: row.protected, }) - .collect::>(); - json!({ - "status": state, - "resident_bytes": resident_bytes, - "limit_bytes": pressure.limit_bytes(), - "high_watermark_bytes": pressure.high_watermark_bytes(), - "low_watermark_bytes": pressure.low_watermark_bytes(), - "psi_some_avg10": psi_some_avg10, - "idle_window_seconds": report.idle_window.as_secs(), - "shed_order": RESIDENT_OWNER_SHED_ORDER_V1.map(ResidentOwnerKindV1::as_str), - "retained_bytes": report.measured_bytes, - "unmeasured_owners": report.unmeasured_owners, - "owners": rows, - }) + .collect(); + StatusMemoryV1 { + status, + resident_bytes, + limit_bytes: pressure.limit_bytes(), + high_watermark_bytes: pressure.high_watermark_bytes(), + low_watermark_bytes: pressure.low_watermark_bytes(), + psi_some_avg10, + idle_window_seconds: report.idle_window.as_secs(), + shed_order: RESIDENT_OWNER_SHED_ORDER_V1 + .map(|kind: ResidentOwnerKindV1| kind.as_str().to_owned()) + .to_vec(), + retained_bytes: report.measured_bytes, + unmeasured_owners: report.unmeasured_owners, + owners, + } } +/// Serialize the generation census exactly as the CLI decoder reads it back. +/// +/// [`GenerationCensusSnapshot`] is the single wire authority for the +/// `graph_statistics` field: this route serializes it and `tracedecay status` +/// deserializes the same Rust type, so the two sides cannot drift. pub fn graph_statistics_value(census: Option<&GenerationCensusSnapshot>) -> Result { let census = census.cloned().unwrap_or( GenerationCensusSnapshot::Unavailable { @@ -338,179 +283,197 @@ pub fn graph_statistics_value(census: Option<&GenerationCensusSnapshot>) -> Resu Ok(serde_json::to_value(&census)?) } +/// The code-index freshness section and the lane-level serving truth it +/// implies. The lanes serve exactly when a sealed complete generation exists +/// for the worktree; until the first seal every retrieval lane refuses +/// `generation_rebuilding`. +fn code_index_freshness_status( + freshness_payload: Option< + &tracedecay_contracts::code_index_freshness::CodeIndexFreshnessPayloadV1, + >, +) -> ( + StatusCodeIndexFreshnessV1, + Option, + Option, +) { + let Some(payload) = freshness_payload else { + return ( + StatusCodeIndexFreshnessV1::Unavailable { + reason: "code_index_scheduler_authority_not_attached".to_owned(), + }, + None, + None, + ); + }; + let Some(freshness) = payload.worktrees.first() else { + return ( + StatusCodeIndexFreshnessV1::Unavailable { + reason: "code_index_scheduler_not_mounted".to_owned(), + }, + None, + Some(StatusRetrievalServingV1::Unavailable { + reason: "code_index_scheduler_not_mounted".to_owned(), + }), + ); + }; + let (label, warning) = code_index_freshness_projection(freshness); + let retrieval_serving = if freshness.latest_generation_id.is_some() { + let (serving_freshness, condition) = match freshness.staleness_state { + Some(CodeIndexStalenessStateV1::Fresh) => (StatusServingFreshnessV1::Current, None), + Some(CodeIndexStalenessStateV1::Restoring) => ( + StatusServingFreshnessV1::Restoring, + Some(StatusServingConditionV1::ArtifactRestore), + ), + Some(CodeIndexStalenessStateV1::Verifying) => ( + StatusServingFreshnessV1::LastCompleteStale, + Some(StatusServingConditionV1::SourceVerification), + ), + Some(_) if freshness.rebuild_in_flight => ( + StatusServingFreshnessV1::LastCompleteStale, + Some(StatusServingConditionV1::Rebuilding), + ), + Some(_) => ( + StatusServingFreshnessV1::LastCompleteStale, + Some(StatusServingConditionV1::Stalled), + ), + None => (StatusServingFreshnessV1::Unknown, None), + }; + StatusRetrievalServingV1::Serving { + freshness: serving_freshness, + condition, + seated_generation_age_seconds: age_seconds(freshness.sealed_at_micros), + last_reconcile_age_seconds: age_seconds(freshness.last_reconcile_micros), + } + } else { + let reason = if freshness.staleness_state == Some(CodeIndexStalenessStateV1::Restoring) { + "generation_restoring" + } else { + "generation_rebuilding" + }; + StatusRetrievalServingV1::Unavailable { + reason: reason.to_owned(), + } + }; + ( + label.with_worktree(freshness.clone()), + warning, + Some(retrieval_serving), + ) +} + +/// Computes `tracedecay_status`. `server_stats` is the serving MCP server's +/// request counters; `wait` is the readiness wait the owner held the read +/// for, when the request asked for one. #[hotpath::measure(label = "mcp.info.status.total")] -pub async fn handle_status( +pub async fn compute_status( ctx: &McpToolContext<'_>, - args: Value, + request: &StatusSurfaceRequestV1, server_stats: Option, scope_prefix: Option<&str>, wait: Option, -) -> Result { - if status_arg_flag(&args, "admission_only", false) { - let mut output = json!({ - "project_admitted": true, - "project_root": ctx.project_root(), - }); - if let Some(ss) = server_stats { - output["server"] = ss; - } - if let Some(prefix) = scope_prefix { - output["scope_prefix"] = json!(prefix); - } - return Ok(generic_tool_result( - Some(&ctx.store_layout().response_handle_root), - &args, - &output, - vec![], - )); +) -> Result { + if request.admission_only { + return Ok(StatusResultV1::Admission(StatusAdmissionV1 { + project_admitted: true, + project_root: display_path(ctx.project_root()), + server: server_stats, + scope_prefix: scope_prefix.map(str::to_owned), + })); } // Compact by default. The CLI already skips these sections because they // commonly push status over the response-frame budget, and the truncated // body is not something the caller should reassemble into context. Opt in // when the full diagnostic section is the thing being asked for. - let include_branch_diagnostics = status_arg_flag(&args, "include_branch_diagnostics", false); - let include_storage_health = status_arg_flag(&args, "include_storage_health", false); - let include_session_ingest = status_arg_flag(&args, "include_session_ingest", false); - let include_staleness = status_arg_flag(&args, "include_staleness", false); - - let graph_statistics = graph_statistics_value(ctx.generation_census())?; - let mut output = json!({ - "project_root": ctx.project_root(), - "graph_statistics": graph_statistics, - "memory": project_memory_value(&ctx.admitted_scope().project_id), - }); - output["schema_convergence"] = schema_convergence_status( - &ctx.store_runtime() - .registered_schema_convergence_observations(), - ); - output["reset_required_stores"] = json!(ctx.store_runtime().reset_required_stores()); let freshness_payload = hotpath::future!( ctx.freshness(), label = "mcp.info.status.code_index_freshness" ) .await; - let (code_index_freshness, retrieval_serving) = match freshness_payload.as_ref() { - Some(payload) => match payload.worktrees.first() { - Some(freshness) => { - let (status, warning) = code_index_freshness_projection(freshness); - if let Some(warning) = warning { - output["code_index_freshness_warning"] = json!(warning); - } - // The lanes serve exactly when a sealed complete generation - // exists for the worktree; until the first seal every - // retrieval lane refuses `generation_rebuilding`. - let retrieval_serving = if freshness.latest_generation_id.is_some() { - let (serving_freshness, condition) = match freshness.staleness_state { - Some(CodeIndexStalenessStateV1::Fresh) => ("current", None), - Some(CodeIndexStalenessStateV1::Restoring) => { - ("restoring", Some("artifact_restore")) - } - Some(CodeIndexStalenessStateV1::Verifying) => { - ("last_complete_stale", Some("source_verification")) - } - Some(_) if freshness.rebuild_in_flight => { - ("last_complete_stale", Some("rebuilding")) - } - Some(_) => ("last_complete_stale", Some("stalled")), - None => ("unknown", None), - }; - CodeIndexRetrievalServingV1::Serving { - freshness: serving_freshness, - condition, - seated_generation_age_seconds: age_seconds(freshness.sealed_at_micros), - last_reconcile_age_seconds: age_seconds(freshness.last_reconcile_micros), - } - } else { - CodeIndexRetrievalServingV1::NotServing { - reason: if freshness.staleness_state - == Some(CodeIndexStalenessStateV1::Restoring) - { - "generation_restoring" - } else { - "generation_rebuilding" - }, - } - }; - ( - json!({ - "status": status, - "worktree": freshness, - }), - retrieval_serving, - ) - } - None => ( - json!({ - "status": "unavailable", - "reason": "code_index_scheduler_not_mounted", - }), - CodeIndexRetrievalServingV1::NotServing { - reason: "code_index_scheduler_not_mounted", - }, - ), - }, - None => ( - json!({ - "status": "unavailable", - "reason": "code_index_scheduler_authority_not_attached", - }), - CodeIndexRetrievalServingV1::AuthorityUnattached, - ), - }; - let ready_serving_source = ready_serving_source(freshness_payload.as_ref()); - let (source_reference, source_revision, source_is_current) = ( - ready_serving_source.map(|source| source.reference), - ready_serving_source.and_then(|source| source.revision), - ready_serving_source.is_some_and(|source| source.current_source_verified), - ); - output["code_index_freshness"] = code_index_freshness; - output["github_source"] = match github_source_status_v1(ctx.project_root()) { + let (code_index_freshness, code_index_freshness_warning, retrieval_serving) = + code_index_freshness_status(freshness_payload.as_ref()); + let github_source = match github_source_status_v1(ctx.project_root()) { Some(source) => serde_json::to_value(&source)?, None => json!({ "state": "absent", "reason": "the checkout has no GitHub origin, or its advisory owner has not mounted in this daemon", }), }; - if include_storage_health { + let storage_health = if request.include_storage_health { let mut storage_health = serde_json::to_value( hotpath::future!( crate::handlers::health::collect_database_snapshot(ctx, false, None), label = "mcp.info.status.storage_health" ) .await?, - ) - .unwrap_or_else(|_| json!({})); + )?; if server_stats.is_some() { storage_health["daemon_owner_pid"] = json!(std::process::id()); storage_health["daemon_generation"] = json!(tracedecay_runtime_core::runtime_identity::process_run_id()); } - output["storage_health"] = storage_health; - } - if let Some(ss) = server_stats { - output["server"] = ss; - } + Some(storage_health) + } else { + None + }; + let mut status = ProjectStatusV1 { + project_root: display_path(ctx.project_root()), + graph_statistics: graph_statistics_value(ctx.generation_census())?, + memory: project_memory_value(&ctx.admitted_scope().project_id), + schema_convergence: schema_convergence_status( + &ctx.store_runtime() + .registered_schema_convergence_observations(), + ), + reset_required_stores: ctx.store_runtime().reset_required_stores(), + code_index_freshness, + code_index_freshness_warning, + retrieval_serving, + github_source, + storage_health, + server: server_stats, + branch_diagnostics: None, + active_branch: None, + current_branch: None, + live_branch: None, + serving_branch: None, + parent_branch: None, + branch_drifted: None, + branch_resolution: None, + tracked_branch_count: None, + branch_mismatch: None, + branch_warnings: None, + session_ingest: None, + session_history_catch_up: None, + git_staleness: request.include_staleness.then(|| StatusGitStalenessV1 { + status: "unavailable".to_owned(), + reason: "sealed_generation_git_watermark_not_published".to_owned(), + message: "the verified code generation does not publish a Git commit watermark" + .to_owned(), + }), + scope_prefix: scope_prefix.map(str::to_owned), + wait, + }; - if include_branch_diagnostics { + let ready_serving_source = ready_serving_source(freshness_payload.as_ref()); + let (source_reference, source_revision, source_is_current) = ( + ready_serving_source.map(|source| source.reference), + ready_serving_source.and_then(|source| source.revision), + ready_serving_source.is_some_and(|source| source.current_source_verified), + ); + if request.include_branch_diagnostics { let branch_diagnostics = ctx.branch_diagnostics_for_serving_source( source_reference, source_revision, source_is_current, ); - attach_full_branch_status(&branch_diagnostics, &mut output, &retrieval_serving); + attach_full_branch_status(&branch_diagnostics, &mut status)?; } else { let (open_active_branch, serving_branch) = ctx.serving_branch_identity_for_serving_source( source_reference, source_revision, source_is_current, ); - attach_compact_branch_summary( - open_active_branch.as_deref(), - serving_branch.as_deref(), - &mut output, - &retrieval_serving, - ); + attach_compact_branch_summary(open_active_branch, serving_branch, &mut status); } // Session-transcript ingest health (recall trust): last ingest time and @@ -518,17 +481,17 @@ pub async fn handle_status( // authority. Match tracedecay_runtime: consult the lease directly rather // than gating on the layout path existing on disk (fixtures and some // retained mounts hold an open authority before the path is observed). - if include_session_ingest { + if request.include_session_ingest { match ctx.authorized_project_session_db() { None => { // Attached means admitted; absent is the typed // unavailable/denied state. Fail closed instead of // opening a second connection here. - output["session_ingest"] = json!({ + status.session_ingest = Some(json!({ "status": "unavailable", "reason": "session_store_denied", "message": "this request is not authorized to read the admitted project session store", - }); + })); } Some((lease, _)) => { let db = lease.as_ref(); @@ -539,69 +502,65 @@ pub async fn handle_status( .await { Ok(ingest) => { - output["session_ingest"] = - serde_json::to_value(&ingest).unwrap_or_else(|error| { - json!({ - "status": "unavailable", - "reason": "session_ingest_serialization_failed", - "message": error.to_string(), - }) - }); + status.session_ingest = Some(serde_json::to_value(&ingest)?); // `session_ingest` stays cursor-scoped so it keeps matching the // doctor-owned signal. Historical catch-up is measured across // providers and remains explicitly partial while the retained // daemon authority drains its bounded backlog. - if let Some(catch_up) = hotpath::future!( - historical_session_catch_up(db), - label = "mcp.info.status.session_history" - ) - .await - { - output["session_history_catch_up"] = catch_up; - } + status.session_history_catch_up = Some( + hotpath::future!( + historical_session_catch_up(db), + label = "mcp.info.status.session_history" + ) + .await, + ); } Err(error) => { - output["session_ingest"] = json!({ + status.session_ingest = Some(json!({ "status": "unavailable", "reason": "session_ingest_query_failed", "message": error, - }); + })); } } } } } - if include_staleness { - output["git_staleness"] = json!({ - "status": "unavailable", - "reason": "sealed_generation_git_watermark_not_published", - "message": "the verified code generation does not publish a Git commit watermark", - }); - } + Ok(StatusResultV1::Project(Box::new(status))) +} - if let Some(prefix) = scope_prefix { - output["scope_prefix"] = json!(prefix); - } - let wait = wait.map(serde_json::to_value).transpose()?; - if let Some(wait) = &wait { - output["wait"] = wait.clone(); +/// The `code_index_freshness.status` label of one freshness reading. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum FreshnessLabelV1 { + Current, + Stale, + Restoring, + Warming, + Parked, +} + +impl FreshnessLabelV1 { + const fn as_str(self) -> &'static str { + match self { + Self::Current => "current", + Self::Stale => "stale", + Self::Restoring => "restoring", + Self::Warming => "warming", + Self::Parked => "parked", + } } - let mut result = rendered_tool_result( - Some(&ctx.store_layout().response_handle_root), - &args, - &output, - vec![], - || render_status_md(&output), - ); - // Structured content beside the rendered body in every format, like a - // typed `problem`, so a caller such as `tracedecay tool` can type its - // exit status on the outcome. - if let (Some(wait), Some(object)) = (wait, result.value.as_object_mut()) { - object.insert("structuredContent".to_owned(), json!({ "wait": wait })); + fn with_worktree(self, worktree: CodeIndexWorktreeFreshnessV1) -> StatusCodeIndexFreshnessV1 { + let worktree = Box::new(worktree); + match self { + Self::Current => StatusCodeIndexFreshnessV1::Current { worktree }, + Self::Stale => StatusCodeIndexFreshnessV1::Stale { worktree }, + Self::Restoring => StatusCodeIndexFreshnessV1::Restoring { worktree }, + Self::Warming => StatusCodeIndexFreshnessV1::Warming { worktree }, + Self::Parked => StatusCodeIndexFreshnessV1::Parked { worktree }, + } } - Ok(result) } /// Project one freshness reading into the operator-facing status label and @@ -613,8 +572,8 @@ pub async fn handle_status( /// the warning carries the exact reason and remediation instead of a /// wait-longer message. fn code_index_freshness_projection( - freshness: &tracedecay_contracts::code_index_freshness::CodeIndexWorktreeFreshnessV1, -) -> (&'static str, Option) { + freshness: &CodeIndexWorktreeFreshnessV1, +) -> (FreshnessLabelV1, Option) { let authoritative = freshness.is_authoritative(); if let Some(parked) = freshness.parked.as_ref() { let warning = format!( @@ -622,19 +581,19 @@ fn code_index_freshness_projection( parked.reason, parked.remediation ); let status = if freshness.staleness_state == Some(CodeIndexStalenessStateV1::Parked) { - "parked" + FreshnessLabelV1::Parked } else if authoritative { - "current" + FreshnessLabelV1::Current } else { - "warming" + FreshnessLabelV1::Warming }; return (status, Some(warning)); } if authoritative { - ("current", None) + (FreshnessLabelV1::Current, None) } else if freshness.staleness_state == Some(CodeIndexStalenessStateV1::Restoring) { ( - "restoring", + FreshnessLabelV1::Restoring, Some( "the sealed lexical artifact is completing bounded authentication before serving" .to_owned(), @@ -642,7 +601,7 @@ fn code_index_freshness_projection( ) } else if freshness.staleness_state == Some(CodeIndexStalenessStateV1::Verifying) { ( - "stale", + FreshnessLabelV1::Stale, Some( "the last complete code index remains available while the scheduler verifies source freshness" .to_owned(), @@ -650,7 +609,7 @@ fn code_index_freshness_projection( ) } else { ( - "warming", + FreshnessLabelV1::Warming, Some( "graph counts are not authoritative until the scheduler seals a complete fresh generation" .to_owned(), @@ -661,16 +620,16 @@ fn code_index_freshness_projection( /// Reports daemon-owned historical warming when any provider's backlog exceeds /// the ordinary catch-up threshold, so partial recall is never read as current. -async fn historical_session_catch_up(db: &RegisteredGlobalDb) -> Option { +async fn historical_session_catch_up(db: &RegisteredGlobalDb) -> Value { match db.session_ingest_health_for_provider(None).await { - Ok(ingest) => Some(historical_session_catch_up_state(&ingest)), - Err(error) => Some(json!({ + Ok(ingest) => historical_session_catch_up_state(&ingest), + Err(error) => json!({ "status": "unavailable", "coverage": "unknown", "authority": "daemon", "reason": "historical_backlog_measurement_failed", "message": error, - })), + }), } } @@ -751,7 +710,7 @@ fn historical_session_catch_up_state(ingest: &SessionIngestHealth) -> Value { }) } -fn render_status_md(value: &Value) -> String { +pub(crate) fn render_status_md(value: &Value) -> String { let mut md = Md::new(); md.heading(2, "Project Status"); if let Some(obj) = value.as_object() { @@ -834,51 +793,6 @@ fn render_status_md(value: &Value) -> String { md.render() } -fn active_project_context( - ctx: &McpToolContext<'_>, - branch: &BranchDiagnostics, - server_stats: Option, - scope_prefix: Option<&str>, -) -> Value { - let project_root = ctx.project_root(); - let layout = ctx.store_layout(); - let graph_db_path = ctx.graph_db_path(); - let admitted_scope = ctx.admitted_scope(); - let mut output = json!({ - "project_id": layout.identity.project_id.as_deref(), - "repository_id": admitted_scope.repository_id.as_str(), - "project_root": display_path(project_root), - "resolution_source": "active_project", - "storage": { - "class": store_kind_name(&layout.store_kind), - "mode": storage_mode_name(&layout.storage_mode), - "data_root": display_path(&layout.data_root), - "graph_db_path": display_path(graph_db_path), - "graph_db_exists": graph_db_path.exists(), - "graph_db_size_bytes": graph_db_path.metadata().map_or(0, |metadata| metadata.len()), - "sessions_db_path": display_path(&layout.sessions_db_path), - "response_handle_root": display_path(&layout.response_handle_root), - "lcm_payload_root": display_path(&layout.lcm_payload_root), - }, - "branch": { - "current_branch": branch.current_branch.clone(), - "open_active_branch": branch.open_active_branch.clone(), - "serving_branch": branch.serving_branch.clone(), - "branch_resolution": branch.branch_resolution.clone(), - "branch_drifted": branch.branch_drifted, - "tracked_branch_count": branch.tracked_branch_count, - "warnings": branch.warnings.clone(), - } - }); - if let Some(prefix) = scope_prefix { - output["scope_prefix"] = json!(prefix); - } - if let Some(stats) = server_stats { - output["server"] = stats; - } - output -} - fn storage_mode_name(mode: &StorageMode) -> &'static str { match mode { StorageMode::ProfileSharded => "profile_sharded", @@ -891,13 +805,12 @@ fn store_kind_name(kind: &StoreKind) -> &'static str { } } +/// Computes `tracedecay_active_project` for the admitted project. #[hotpath::measure(label = "mcp.info.active_project.total")] -pub async fn handle_active_project( +pub async fn compute_active_project( ctx: &McpToolContext<'_>, - args: &Value, - server_stats: Option, scope_prefix: Option<&str>, -) -> Result { +) -> ActiveProjectResultV1 { let freshness_payload = ctx.freshness().await; let ready_serving_source = ready_serving_source(freshness_payload.as_ref()); let branch = ctx.branch_diagnostics_for_serving_source( @@ -905,13 +818,37 @@ pub async fn handle_active_project( ready_serving_source.and_then(|source| source.revision), ready_serving_source.is_some_and(|source| source.current_source_verified), ); - let output = active_project_context(ctx, &branch, server_stats, scope_prefix); - Ok(generic_tool_result( - Some(&ctx.store_layout().response_handle_root), - args, - &output, - vec![], - )) + let layout = ctx.store_layout(); + let graph_db_path = ctx.graph_db_path(); + ActiveProjectResultV1 { + project_id: layout.identity.project_id.clone(), + repository_id: ctx.admitted_scope().repository_id.as_str().to_owned(), + project_root: display_path(ctx.project_root()), + resolution_source: ActiveProjectResolutionSourceV1::ActiveProject, + storage: ActiveProjectStorageV1 { + class: store_kind_name(&layout.store_kind).to_owned(), + mode: storage_mode_name(&layout.storage_mode).to_owned(), + data_root: display_path(&layout.data_root), + graph_db_path: display_path(graph_db_path), + graph_db_exists: graph_db_path.exists(), + graph_db_size_bytes: graph_db_path + .metadata() + .map_or(0, |metadata| metadata.len()), + sessions_db_path: display_path(&layout.sessions_db_path), + response_handle_root: display_path(&layout.response_handle_root), + lcm_payload_root: display_path(&layout.lcm_payload_root), + }, + branch: ActiveProjectBranchV1 { + current_branch: branch.current_branch, + open_active_branch: branch.open_active_branch, + serving_branch: branch.serving_branch, + branch_resolution: branch.branch_resolution, + branch_drifted: branch.branch_drifted, + tracked_branch_count: branch.tracked_branch_count, + warnings: branch.warnings, + }, + scope_prefix: scope_prefix.map(str::to_owned), + } } #[cfg(test)] @@ -925,9 +862,9 @@ mod tests { }; use super::{ - CodeIndexReadinessWaitReadV1, CodeIndexReadinessWaitV1, code_index_freshness_projection, + CodeIndexReadinessWaitReadV1, FreshnessLabelV1, code_index_freshness_projection, graph_statistics_value, historical_session_catch_up_state, readiness_wait_outcome, - render_status_md, schema_convergence_status, status_readiness_wait, + render_status_md, schema_convergence_status, }; use tracedecay_contracts::code_index_freshness::{ CodeIndexFreshnessCoverageV1, CodeIndexStalenessStateV1, @@ -1008,7 +945,7 @@ mod tests { ); assert_eq!( - memory, + serde_json::to_value(memory).expect("memory serializes"), serde_json::json!({ "status": "nominal", "resident_bytes": 6_000, @@ -1075,7 +1012,8 @@ mod tests { degraded_row: (state == SchemaConvergenceStateV1::Degraded) .then(|| "observation_id=obs-7".to_owned()), }; - let value = schema_convergence_status(&[finding]); + let value = serde_json::to_value(schema_convergence_status(&[finding])) + .expect("schema convergence serializes"); assert_eq!(value["status"], expected); assert_eq!(value["findings"][0]["state"], serde_json::json!(state)); assert_eq!(value["findings"][0]["started_at_micros"], 42); @@ -1165,44 +1103,6 @@ mod tests { ); } - #[test] - fn wait_for_rejects_an_unknown_state() { - let refused = status_readiness_wait( - &serde_json::json!({ "wait_for": { "state": "sealed", "timeout_ms": 5 } }), - ) - .expect_err("unknown state is refused"); - assert!( - refused.to_string().contains("wait_for must be"), - "{refused}" - ); - assert_eq!( - status_readiness_wait( - &serde_json::json!({ "wait_for": { "state": "ready", "timeout_ms": 5 } }) - ) - .expect("valid wait"), - Some(CodeIndexReadinessWaitV1 { - state: - tracedecay_contracts::code_index_freshness::CodeIndexReadinessTargetV1::Ready, - timeout_ms: 5, - }) - ); - } - - #[test] - fn wait_for_accepts_graph_ready() { - assert_eq!( - status_readiness_wait( - &serde_json::json!({ "wait_for": { "state": "graph_ready", "timeout_ms": 5 } }) - ) - .expect("graph_ready is a wait state"), - Some(CodeIndexReadinessWaitV1 { - state: - tracedecay_contracts::code_index_freshness::CodeIndexReadinessTargetV1::GraphReady, - timeout_ms: 5, - }) - ); - } - #[test] fn a_parked_deterministic_violation_reports_parked_not_warming() { let freshness = tracedecay_contracts::code_index_freshness::CodeIndexWorktreeFreshnessV1 { @@ -1225,7 +1125,7 @@ mod tests { let (status, warning) = code_index_freshness_projection(&freshness); - assert_eq!(status, "parked"); + assert_eq!(status, FreshnessLabelV1::Parked); let warning = warning.expect("a parked read carries the reason"); assert!(warning.contains("not owner-private (mode 775, need 700)")); assert!(warning.contains("restore owner-only access")); @@ -1280,7 +1180,7 @@ mod tests { let (status, warning) = code_index_freshness_projection(&freshness); - assert_eq!(status, "current"); + assert_eq!(status, FreshnessLabelV1::Current); assert!(warning.expect("the park stays visible").contains("parked")); } @@ -1295,7 +1195,7 @@ mod tests { let (status, warning) = code_index_freshness_projection(&freshness); - assert_eq!(status, "warming"); + assert_eq!(status, FreshnessLabelV1::Warming); assert!( warning .expect("warming names itself") @@ -1324,7 +1224,7 @@ mod tests { let (status, warning) = code_index_freshness_projection(&freshness); - assert_eq!(status, "restoring"); + assert_eq!(status, FreshnessLabelV1::Restoring); assert!(!freshness.rebuild_in_flight); assert!( warning @@ -1345,7 +1245,7 @@ mod tests { let (status, warning) = code_index_freshness_projection(&freshness); - assert_eq!(status, "stale"); + assert_eq!(status, FreshnessLabelV1::Stale); assert!( warning .expect("verification is named") diff --git a/crates/tracedecay-mcp/src/handlers/support.rs b/crates/tracedecay-mcp/src/handlers/support.rs index 6fddeedfb5..258ce6be4d 100644 --- a/crates/tracedecay-mcp/src/handlers/support.rs +++ b/crates/tracedecay-mcp/src/handlers/support.rs @@ -117,20 +117,37 @@ pub fn require_object_args(args: &Value, tool_name: &str) -> Result<()> { /// thread keys are host route identity: the server routes the call by them /// before dispatch, so they never belong to the request body. pub fn decode_primitive_request(args: &Value, tool_name: &str) -> Result { + decode_request_without(args, tool_name, &["project_selector"]) +} + +/// [`decode_primitive_request`] for a request whose own contract names a +/// registered project through `project_selector`, so routing never consumed +/// it. +pub fn decode_selector_request(args: &Value, tool_name: &str) -> Result { + decode_request_without(args, tool_name, &[]) +} + +fn decode_request_without( + args: &Value, + tool_name: &str, + routed_keys: &[&str], +) -> Result { require_object_args(args, tool_name)?; let mut request = args.clone(); if let Some(object) = request.as_object_mut() { for key in [ "format", "__mcp_request_id", - "project_selector", "_meta", "session_id", "sessionId", "thread_id", "threadId", - ] { - object.remove(key); + ] + .iter() + .chain(routed_keys) + { + object.remove(*key); } } serde_json::from_value(request).map_err(|error| TraceDecayError::Config { diff --git a/crates/tracedecay-mcp/src/tools/binding.rs b/crates/tracedecay-mcp/src/tools/binding.rs index f370d4b554..2c49ba96b9 100644 --- a/crates/tracedecay-mcp/src/tools/binding.rs +++ b/crates/tracedecay-mcp/src/tools/binding.rs @@ -50,7 +50,6 @@ pub enum McpToolDispatchGroup { Info, Admin, Git, - Health, Work, Workflow, } @@ -83,7 +82,6 @@ pub fn tool_branch_sensitivity(tool_name: &str) -> BranchSensitivity { McpToolDispatchGroup::Info | McpToolDispatchGroup::Admin | McpToolDispatchGroup::Git - | McpToolDispatchGroup::Health | McpToolDispatchGroup::MultiRoot | McpToolDispatchGroup::ApplicationSurface, ) => BranchSensitivity::Sensitive, @@ -296,6 +294,13 @@ fn application_surface_branch_sensitivity( | ApplicationSurfaceOperation::Search | ApplicationSurfaceOperation::RunAffectedTests | ApplicationSurfaceOperation::Dashboard + | ApplicationSurfaceOperation::Status + | ApplicationSurfaceOperation::ActiveProject + | ApplicationSurfaceOperation::RemoteStatus + | ApplicationSurfaceOperation::Runtime + | ApplicationSurfaceOperation::ProjectList + | ApplicationSurfaceOperation::ProjectSearch + | ApplicationSurfaceOperation::ProjectContext | HealthRead | HealthDelta | DiagnosticsRead @@ -345,11 +350,6 @@ macro_rules! binding_groups { /// access are one slice; a different access starts a new slice. #[rustfmt::skip] const BINDING_GROUPS: &[BindingGroup] = binding_groups![ - [Some(McpToolDispatchGroup::Info), RegisteredProjectAccess::ActiveProjectOnly, - "tracedecay_status", "tracedecay_remote_status", "tracedecay_active_project", - "tracedecay_project_list", "tracedecay_project_search"], - [Some(McpToolDispatchGroup::Info), RegisteredProjectAccess::SelectorOnly, - "tracedecay_project_context"], [Some(McpToolDispatchGroup::Info), RegisteredProjectAccess::ActiveProjectOnly, "tracedecay_admin_sync", "tracedecay_port_status", "tracedecay_port_order", "tracedecay_todos"], @@ -357,12 +357,11 @@ const BINDING_GROUPS: &[BindingGroup] = binding_groups![ "tracedecay_hook_runtime", "tracedecay_admin_cli", "tracedecay_admin_project"], [Some(McpToolDispatchGroup::Git), RegisteredProjectAccess::ActiveProjectOnly, "tracedecay_admin_branch_add"], - [Some(McpToolDispatchGroup::Health), RegisteredProjectAccess::ActiveProjectOnly, - "tracedecay_runtime"], [Some(McpToolDispatchGroup::MultiRoot), RegisteredProjectAccess::ActiveProjectOnly, "tracedecay_multi_root_scope_set_read", "tracedecay_multi_root_scope_set_compare_and_swap", "tracedecay_multi_root_execute"], [None, RegisteredProjectAccess::SelectorOnly, "tracedecay_fact_feedback"], + [None, RegisteredProjectAccess::SelectorOnly, "tracedecay_project_context"], [None, RegisteredProjectAccess::ActiveProjectOnly, "tracedecay_lcm_describe", "tracedecay_lcm_doctor", "tracedecay_lcm_expand", "tracedecay_lcm_expand_query", "tracedecay_lcm_grep", "tracedecay_lcm_load_session", "tracedecay_lcm_status", diff --git a/crates/tracedecay-tool-catalog/src/operation.rs b/crates/tracedecay-tool-catalog/src/operation.rs index 7682d3d550..f07c447336 100644 --- a/crates/tracedecay-tool-catalog/src/operation.rs +++ b/crates/tracedecay-tool-catalog/src/operation.rs @@ -219,6 +219,13 @@ application_surface_operations! { Search => "search"; RunAffectedTests => "run_affected_tests"; Dashboard => "dashboard"; + Status => "status"; + ActiveProject => "active_project"; + RemoteStatus => "remote_status"; + Runtime => "runtime"; + ProjectList => "project_list"; + ProjectSearch => "project_search"; + ProjectContext => "project_context"; HealthRead => "health_read"; HealthDelta => "health_delta"; StorageStatus => "storage_status"; @@ -348,11 +355,25 @@ impl ApplicationSurfaceOperation { Self::Search, Self::RunAffectedTests, Self::Dashboard, + Self::Status, + Self::ActiveProject, + Self::RemoteStatus, + Self::Runtime, ]; + /// Reads of the authenticated profile's project registry. They name no + /// project, so the daemon's profile owner answers them with their typed + /// catalog result for every connection, with or without a project. + pub const PROFILE_REGISTRY_OPERATIONS: &[Self] = + &[Self::ProjectList, Self::ProjectSearch, Self::ProjectContext]; + pub fn is_graph_tool(self) -> bool { Self::GRAPH_TOOL_OPERATIONS.contains(&self) } + + pub fn is_profile_registry_read(self) -> bool { + Self::PROFILE_REGISTRY_OPERATIONS.contains(&self) + } } #[cfg(test)] diff --git a/crates/tracedecay/src/daemon.rs b/crates/tracedecay/src/daemon.rs index d34db24eab..49573e3e95 100644 --- a/crates/tracedecay/src/daemon.rs +++ b/crates/tracedecay/src/daemon.rs @@ -353,6 +353,7 @@ mod store_maintenance; pub use production_harness::ProductionProjectCompositionHarnessV1; #[cfg(all(unix, feature = "test-transport"))] pub use production_harness::capture_exact_git_snapshot_for_test; +mod profile_registry; mod profile_retained; mod projectless; mod remote_deletion; diff --git a/crates/tracedecay/src/daemon/code_index_runtime_generation_census_tests.rs b/crates/tracedecay/src/daemon/code_index_runtime_generation_census_tests.rs index 2448640fad..4898553071 100644 --- a/crates/tracedecay/src/daemon/code_index_runtime_generation_census_tests.rs +++ b/crates/tracedecay/src/daemon/code_index_runtime_generation_census_tests.rs @@ -7,9 +7,7 @@ use std::process::Command; use serde_json::{Value, json}; use tempfile::TempDir; -use crate::mcp::tools::handlers::{ - ToolCallRegistryOptions, handle_tool_call_with_registry_options, -}; +use crate::mcp::tools::handlers::{ToolCallRegistryOptions, dispatch_on_graph_authority}; use tracedecay_code_index_runtime::code_index_scheduler::CodeIndexSchedulerRegistryV1; use tracedecay_code_index_runtime::project_reads::project_code_index_generation_census_reader; use tracedecay_code_index_runtime::resolved_scope_for_project; @@ -66,12 +64,10 @@ async fn runtime_mcp_refuses_counts_until_the_mounted_graph_can_serve_queries() .expect("sealed generation must publish for the mounted root"); } - let result = handle_tool_call_with_registry_options( + let result = dispatch_on_graph_authority( &cg, "tracedecay_runtime", json!({ "format": "json" }), - None, - None, ToolCallRegistryOptions { generation_census_reader: Some(generation_census_reader), ..Default::default() diff --git a/crates/tracedecay/src/daemon/invocation_dispatch.rs b/crates/tracedecay/src/daemon/invocation_dispatch.rs index bfa21c10bd..da12492793 100644 --- a/crates/tracedecay/src/daemon/invocation_dispatch.rs +++ b/crates/tracedecay/src/daemon/invocation_dispatch.rs @@ -373,7 +373,12 @@ pub(super) async fn execute_portable_daemon_invocation( let lsp_project_open_attempts = project_open_attempts.clone(); let git_operation = invocation_is_git_operation(request.operation()); let workflow_application = request.is_workflow_application(); - let mut project_path = None; + // A profile registry read marks the handshake's project active without + // opening it. + let mut project_path = match &request.payload { + DaemonInvocationPayload::ProfileGraphTool { .. } => handshake.project_path.clone(), + _ => None, + }; if request.requires_project() { let project_server = hotpath::measure_block!( "daemon.invocation.project_open", @@ -738,7 +743,12 @@ pub(super) async fn execute_daemon_invocation( }; let git_operation = invocation_is_git_operation(request.operation()); let workflow_application = request.is_workflow_application(); - let mut project_path = None; + // A profile registry read marks the handshake's project active without + // opening it. + let mut project_path = match &request.payload { + DaemonInvocationPayload::ProfileGraphTool { .. } => handshake.project_path.clone(), + _ => None, + }; if request.requires_project() { let project_server = hotpath::measure_block!( "daemon.invocation.project_open", diff --git a/crates/tracedecay/src/daemon/invocation_executor.rs b/crates/tracedecay/src/daemon/invocation_executor.rs index d7d884504a..a532019eb0 100644 --- a/crates/tracedecay/src/daemon/invocation_executor.rs +++ b/crates/tracedecay/src/daemon/invocation_executor.rs @@ -247,6 +247,7 @@ impl InProcessDaemonInvocationExecutor { && !matches!( request.payload, tracedecay_daemon_service::DaemonInvocationPayload::ProfileRetainedApplication { .. } + | tracedecay_daemon_service::DaemonInvocationPayload::ProfileGraphTool { .. } ) { let git_service = if invocation_is_git_operation(request.operation()) { diff --git a/crates/tracedecay/src/daemon/invocation_state/project_invocation.rs b/crates/tracedecay/src/daemon/invocation_state/project_invocation.rs index c5fa9c8444..2963adff3b 100644 --- a/crates/tracedecay/src/daemon/invocation_state/project_invocation.rs +++ b/crates/tracedecay/src/daemon/invocation_state/project_invocation.rs @@ -29,6 +29,7 @@ impl DaemonInvocationState { | DaemonInvocationPayload::MultiRootScopeSetCompareAndSwap { .. } | DaemonInvocationPayload::MultiRootExecute { .. } | DaemonInvocationPayload::ProfileRetainedApplication { .. } + | DaemonInvocationPayload::ProfileGraphTool { .. } ) && request_cancellation.is_none() { let Some(lease) = self @@ -65,6 +66,28 @@ impl DaemonInvocationState { ) .await; } + // The caller's project, when it names one, only marks that project + // active in the profile's registry; the read never opens it. + if let DaemonInvocationPayload::ProfileGraphTool { + surface_operation, + arguments, + deadline, + cancellation, + .. + } = request.payload + { + return super::super::profile_registry::invoke_profile_registry_read( + store_administration, + project_path, + request.request_id, + surface_operation, + arguments, + deadline, + cancellation, + direct_request_cancellation, + ) + .await; + } let request_project_path = request.requires_project().then_some(project_path).flatten(); if let DaemonInvocationPayload::MultiRootScopeSetRead { request: scope_set_request, diff --git a/crates/tracedecay/src/daemon/profile_registry.rs b/crates/tracedecay/src/daemon/profile_registry.rs new file mode 100644 index 0000000000..f2a934094c --- /dev/null +++ b/crates/tracedecay/src/daemon/profile_registry.rs @@ -0,0 +1,145 @@ +//! The daemon's owner of the profile project-registry reads. +//! +//! `tracedecay_project_list`, `tracedecay_project_search`, and +//! `tracedecay_project_context` read the authenticated profile's registry. They +//! name no project, so the composition root answers them from the profile's +//! store administration for every transport: CLI invocations, project MCP +//! servers, and projectless connections. The caller's project, when it has +//! one, only marks that project active and is the context read's default. + +use std::future::Future; +use std::path::Path; + +use serde_json::{Map, Value}; +use tracedecay_contracts::{ + ApplicationProblem, CancellationContext, CancellationStage, CancellationState, Deadline, + ResolvedScope, +}; +use tracedecay_daemon_protocol::{ + DaemonInvocationOutcome, DaemonInvocationProblem, DaemonInvocationResponse, +}; +use tracedecay_daemon_service::DaemonProjectRegistryReadService; +use tracedecay_domain::errors::{Result, TraceDecayError}; +use tracedecay_global_db::RegisteredGlobalDbLeaseV1; +use tracedecay_mcp::tools::dispatch_ceiling::{tool_dispatch_budget, tool_dispatch_deadline_error}; +use tracedecay_runtime_core::cancellation::CancellationToken; +use tracedecay_tool_catalog::ApplicationSurfaceOperation; + +use super::StoreAdministration; +use super::profile_retained::profile_session_scope; +use crate::mcp::tools::graph_tool_error_problem; + +/// Serve one profile registry read from the daemon's pinned profile. +#[allow(clippy::too_many_arguments)] +#[hotpath::measure(label = "daemon.profile_registry.invoke", future = true)] +pub(super) async fn invoke_profile_registry_read( + store_administration: &StoreAdministration, + active_project_root: Option<&Path>, + request_id: String, + operation: ApplicationSurfaceOperation, + arguments: Map, + deadline: Deadline, + cancellation: CancellationContext, + request_cancellation: Option, +) -> DaemonInvocationResponse { + let authority = async { + let scope = profile_session_scope(store_administration.profile_identity()?)?; + let registry = Box::pin(store_administration.registered_profile_database()).await?; + Ok((scope, registry)) + }; + answer_profile_registry_read( + authority, + active_project_root, + request_id, + operation, + arguments, + deadline, + cancellation, + request_cancellation, + ) + .await +} + +/// Answer one profile registry read from `authority`, the profile session +/// scope and registered profile registry, and settle its typed terminal. +/// +/// `request_cancellation` is the daemon's registered cancellation for this +/// request; a cancelled read settles as the typed cancelled problem. +#[allow(clippy::too_many_arguments)] +pub(crate) async fn answer_profile_registry_read( + authority: impl Future> + Send, + active_project_root: Option<&Path>, + request_id: String, + operation: ApplicationSurfaceOperation, + arguments: Map, + deadline: Deadline, + cancellation: CancellationContext, + request_cancellation: Option, +) -> DaemonInvocationResponse { + if matches!(cancellation.state, CancellationState::Cancelled { .. }) { + return DaemonInvocationResponse::application_problem( + request_id, + ApplicationProblem::cancelled_before_admission(), + ); + } + if !operation.is_profile_registry_read() { + return DaemonInvocationResponse::problem( + request_id, + DaemonInvocationProblem::InvalidRequest, + ); + } + let tool_name = operation.mcp_tool_name(); + let Some(budget) = tool_dispatch_budget(tool_name, Some(&deadline)) else { + return DaemonInvocationResponse::application_problem( + request_id, + ApplicationProblem::timed_out_before_admission(), + ); + }; + let read = async { + let (scope, registry) = authority.await?; + let registry = DaemonProjectRegistryReadService::new(registry); + let completion = tracedecay_mcp::handlers::info::compute_registry_read( + ®istry, + active_project_root, + operation, + Value::Object(arguments), + ) + .await?; + Ok::<_, TraceDecayError>((scope, completion)) + }; + let bounded = async { + match tokio::time::timeout(budget, read).await { + Ok(result) => result, + Err(_elapsed) => Err(tool_dispatch_deadline_error(tool_name, budget)), + } + }; + let cancelled = async { + match request_cancellation { + Some(token) => token.cancelled().await, + None => std::future::pending().await, + } + }; + let outcome = tokio::select! { + biased; + () = cancelled => { + return match ApplicationProblem::cancelled(CancellationStage::DuringRead) { + Ok(problem) => DaemonInvocationResponse::application_problem(request_id, problem), + Err(_) => DaemonInvocationResponse::problem( + request_id, + DaemonInvocationProblem::Unavailable, + ), + }; + } + outcome = bounded => outcome, + }; + match outcome { + Ok((scope, completion)) => DaemonInvocationResponse::with_outcome( + request_id, + DaemonInvocationOutcome::GraphTool { scope, completion }, + ), + Err(error) => DaemonInvocationResponse::application_problem( + request_id, + graph_tool_error_problem(&error), + ), + } +} diff --git a/crates/tracedecay/src/daemon/profile_retained.rs b/crates/tracedecay/src/daemon/profile_retained.rs index 22450e59d3..1d3a423403 100644 --- a/crates/tracedecay/src/daemon/profile_retained.rs +++ b/crates/tracedecay/src/daemon/profile_retained.rs @@ -213,14 +213,17 @@ async fn execute_profile_retained( } /// The invocation executor of a connection that opened no project. It serves -/// only the profile's retained stores; every other daemon payload names a -/// project this connection does not have. +/// only the profile's own retained stores and project registry; every other +/// daemon payload names a project this connection does not have. +/// `active_project_root` is the handshake's project, which marks that project +/// active in registry reads without opening it. #[derive(Clone)] -pub(super) struct ProfileRetainedExecutor { +pub(super) struct ProfileExecutor { pub(super) store_administration: StoreAdministration, + pub(super) active_project_root: Option, } -impl tracedecay_contracts::ApplicationInvocationExecutor for ProfileRetainedExecutor { +impl tracedecay_contracts::ApplicationInvocationExecutor for ProfileExecutor { fn invoke( &self, invocation: tracedecay_contracts::ApplicationInvocation, @@ -243,7 +246,7 @@ impl tracedecay_contracts::ApplicationInvocationExecutor for ProfileRetainedExec } } -impl tracedecay_daemon_protocol::DaemonInvocationExecutor for ProfileRetainedExecutor { +impl tracedecay_daemon_protocol::DaemonInvocationExecutor for ProfileExecutor { fn invoke_controlled( &self, request: tracedecay_daemon_protocol::DaemonInvocationRequest, @@ -258,27 +261,47 @@ impl tracedecay_daemon_protocol::DaemonInvocationExecutor for ProfileRetainedExe >, > { Box::pin(async move { - let tracedecay_daemon_protocol::DaemonInvocationPayload::ProfileRetainedApplication { - request: retained_request, - deadline, - cancellation: context, - .. - } = request.payload - else { - return Ok(DaemonInvocationResponse::problem( + let token = CancellationToken::new(); + let invocation = match request.payload { + tracedecay_daemon_protocol::DaemonInvocationPayload::ProfileRetainedApplication { + request: retained_request, + deadline, + cancellation: context, + .. + } => Box::pin(invoke_profile_retained( + &self.store_administration, request.request_id, - DaemonInvocationProblem::NotFoundOrNotAuthorized, - )); + retained_request, + deadline, + context, + Some(token.clone()), + )) + as std::pin::Pin< + Box + Send + '_>, + >, + tracedecay_daemon_protocol::DaemonInvocationPayload::ProfileGraphTool { + surface_operation, + arguments, + deadline, + cancellation: context, + .. + } => Box::pin(super::profile_registry::invoke_profile_registry_read( + &self.store_administration, + self.active_project_root.as_deref(), + request.request_id, + surface_operation, + arguments, + deadline, + context, + Some(token.clone()), + )), + _ => { + return Ok(DaemonInvocationResponse::problem( + request.request_id, + DaemonInvocationProblem::NotFoundOrNotAuthorized, + )); + } }; - let token = CancellationToken::new(); - let invocation = invoke_profile_retained( - &self.store_administration, - request.request_id, - retained_request, - deadline, - context, - Some(token.clone()), - ); tokio::pin!(invocation); Ok(tokio::select! { response = &mut invocation => response, @@ -296,11 +319,24 @@ impl tracedecay_daemon_protocol::DaemonInvocationExecutor for ProfileRetainedExe _observed_at: tracedecay_domain::UtcMicros, _event: tracedecay_contracts::feedback::observations::FeedbackSourceEventV1, ) -> tracedecay_daemon_protocol::DaemonInvocationExecutorFuture<'_, Result<()>> { - // Retained operations publish no feedback observations. + // Profile operations publish no feedback observations. Box::pin(async { Ok(()) }) } } +/// The profile session scope every profile-targeted terminal reports under. +pub(crate) fn profile_session_scope( + profile_identity: &dyn tracedecay_contracts::ProfileIdentityReadPort, +) -> Result { + let (connection, _) = profile_retained_connection_for(profile_identity)?; + connection + .session_identity() + .session_request_scope() + .map_err(|error| TraceDecayError::Config { + message: format!("profile session scope is invalid: {error}"), + }) +} + /// The profile's retained connection authority and session retrieval root, /// derived from the daemon's pinned profile identity. fn profile_retained_connection( @@ -309,7 +345,15 @@ fn profile_retained_connection( ProfileRetainedConnectionAuthorityV1, DaemonSessionRetrievalRoot, )> { - let profile_identity = store_administration.profile_identity()?; + profile_retained_connection_for(store_administration.profile_identity()?) +} + +fn profile_retained_connection_for( + profile_identity: &dyn tracedecay_contracts::ProfileIdentityReadPort, +) -> Result<( + ProfileRetainedConnectionAuthorityV1, + DaemonSessionRetrievalRoot, +)> { let shard = StoreShardIdV1::profile_sessions( profile_identity.brain_id().clone(), profile_identity.profile_id().clone(), diff --git a/crates/tracedecay/src/daemon/projectless.rs b/crates/tracedecay/src/daemon/projectless.rs index 7edeb9ccad..97d3c7fa5d 100644 --- a/crates/tracedecay/src/daemon/projectless.rs +++ b/crates/tracedecay/src/daemon/projectless.rs @@ -7,7 +7,6 @@ use serde_json::json; use tracedecay_daemon_identity::authority; use tracedecay_daemon_protocol::DaemonClientIdentity; -use tracedecay_daemon_service::DaemonProjectRegistryReadService; use tracedecay_domain::errors::Result; use tracedecay_mcp::server::{LiveTranscriptRefreshJoin, join_required_live_transcript_refresh}; use tracedecay_mcp::tools::catalog_discovery::{ @@ -355,7 +354,7 @@ async fn projectless_tools_call_response_with_connection( id, tool_name, arguments, - connection.active_project_root.as_deref(), + connection, store_administration, )) } @@ -372,6 +371,7 @@ async fn projectless_tools_call_response_with_connection( tool_name, operation, arguments, + connection, store_administration, )) } @@ -394,58 +394,39 @@ fn requires_project_error(id: serde_json::Value, tool_name: &str) -> JsonRpcResp ) } -/// Registry reads are profile-scoped: they answer from the authenticated -/// profile's project registry, the same authority `tracedecay projects` -/// reads, so a connection without a mounted project still gets the real -/// listing (possibly empty). Only the handshake's project, if any, is marked -/// active. A registry that cannot be opened is a typed tool error, never an -/// empty listing. +/// Registry reads go to the daemon's profile owner, the one path every +/// connection's registry read takes. Only the handshake's project, if any, is +/// marked active. async fn projectless_registry_response( id: serde_json::Value, tool_name: &str, arguments: serde_json::Value, - active_project_root: Option<&Path>, + connection: &ProjectlessConnectionStateV1, store_administration: &StoreAdministration, ) -> tracedecay_mcp::JsonRpcResponse { - let registry = - match boxed_projectless_phase(store_administration.registered_profile_database()).await { - Ok(registry) => registry, - Err(error) => return tool_error_response(id, tool_name, &error), - }; - let registry_reads = DaemonProjectRegistryReadService::new(registry); - let result = match tool_name { - "tracedecay_project_list" => { - tracedecay_mcp::handlers::info::handle_project_list( - active_project_root, - arguments, - Some(®istry_reads), - ) - .await - } - "tracedecay_project_search" => { - tracedecay_mcp::handlers::info::handle_project_search( - active_project_root, - arguments, - Some(®istry_reads), - ) - .await - } - "tracedecay_project_context" => { - tracedecay_mcp::handlers::info::handle_project_context( - active_project_root, - None, - arguments, - Some(®istry_reads), - ) - .await - } - _ => { - return JsonRpcResponse::error( - id, - ErrorCode::MethodNotFound, - format!("unknown projectless registry tool: {tool_name}"), - ); + let Some(operation) = + tracedecay_tool_catalog::ApplicationSurfaceOperation::from_tool_name(tool_name) + .filter(|operation| operation.is_profile_registry_read()) + else { + return requires_project_error(id, tool_name); + }; + let executor = profile_executor(connection, store_administration); + let result = match boxed_projectless_phase(crate::mcp::tools::execute_graph_tool_surface( + tracedecay_tool_catalog::BindingSurface::Mcp, + operation, + arguments.clone(), + Some(&executor), + None, + None, + None, + )) + .await + { + Ok(Ok(completion)) => { + tracedecay_mcp::handlers::graph_tool::render_graph_tool(None, &arguments, completion) } + Ok(Err(refusal)) => refusal.render(None, &arguments), + Err(error) => Err(error), }; match result { Ok(result) => JsonRpcResponse::success(id, result.value), @@ -453,6 +434,16 @@ async fn projectless_registry_response( } } +fn profile_executor( + connection: &ProjectlessConnectionStateV1, + store_administration: &StoreAdministration, +) -> super::profile_retained::ProfileExecutor { + super::profile_retained::ProfileExecutor { + store_administration: store_administration.clone(), + active_project_root: connection.active_project_root.clone(), + } +} + async fn projectless_admin_project_response( id: serde_json::Value, arguments: serde_json::Value, @@ -653,6 +644,7 @@ async fn projectless_profile_retained_response( tool_name: &str, operation: tracedecay_contracts::RetainedSurfaceOperation, arguments: serde_json::Value, + connection: &ProjectlessConnectionStateV1, store_administration: &StoreAdministration, ) -> tracedecay_mcp::JsonRpcResponse { match crate::mcp::tools::retained_tool_target(operation, &arguments) { @@ -671,9 +663,7 @@ async fn projectless_profile_retained_response( else { return requires_project_error(id, tool_name); }; - let executor = super::profile_retained::ProfileRetainedExecutor { - store_administration: store_administration.clone(), - }; + let executor = profile_executor(connection, store_administration); let result = boxed_projectless_phase(crate::mcp::tools::run_retained_surface_tool( None, tracedecay_tool_catalog::BindingSurface::Mcp, diff --git a/crates/tracedecay/src/daemon/retained_test_support.rs b/crates/tracedecay/src/daemon/retained_test_support.rs index 3fb8bd5d67..c898be769e 100644 --- a/crates/tracedecay/src/daemon/retained_test_support.rs +++ b/crates/tracedecay/src/daemon/retained_test_support.rs @@ -18,17 +18,21 @@ use tracedecay_lsp::LspSessionRegistry; use super::project_open_owners::project_open_retained_grant; use tracedecay_code_index_runtime::code_index_scheduler::CodeIndexSchedulerRegistryV1; use tracedecay_code_index_runtime::resolved_scope_for_project; -use tracedecay_contracts::now_micros; +use tracedecay_contracts::{ResolvedScope, now_micros}; use tracedecay_daemon_service::{ DaemonInvocationService, DaemonRetainedRuntimeRegistrar, daemon_owned_project_source_access_at, }; use tracedecay_domain::errors::{Result, TraceDecayError}; +use tracedecay_global_db::RegisteredGlobalDbLeaseV1; #[derive(Clone)] struct RetainedOwnerTestExecutor { service: DaemonInvocationService, lsp_registry: Arc>, project_root: PathBuf, + /// The profile registry the daemon composition root answers registry + /// reads from, with the profile session scope they report under. + profile_registry: Option<(ResolvedScope, RegisteredGlobalDbLeaseV1)>, } impl tracedecay_contracts::ApplicationInvocationExecutor for RetainedOwnerTestExecutor { @@ -83,6 +87,33 @@ impl tracedecay_daemon_protocol::DaemonInvocationExecutor for RetainedOwnerTestE }, ); } + if let tracedecay_daemon_protocol::DaemonInvocationPayload::ProfileGraphTool { + surface_operation, + arguments, + deadline, + cancellation: context, + .. + } = request.payload + { + let authority = async { + self.profile_registry + .clone() + .ok_or_else(|| TraceDecayError::Config { + message: "the test server mounts no profile registry".to_owned(), + }) + }; + return Ok(super::profile_registry::answer_profile_registry_read( + authority, + Some(&self.project_root), + request.request_id, + surface_operation, + arguments, + deadline, + context, + None, + ) + .await); + } Ok(self .service .invoke_with_cancellation( @@ -116,11 +147,19 @@ pub(crate) struct ProjectRetainedOwnerTransport { pub(crate) executor: Arc, } -/// Builds the in-process retained transport for `project_root`. +/// Builds the in-process retained transport for `context`'s project, with the +/// profile registry its registry reads answer from. pub(crate) fn project_retained_owner_transport( - project_root: &std::path::Path, + context: &crate::mcp::server::McpServerConstructionContext, ) -> Result { - let project_root = project_root.canonicalize()?; + let project_root = context.cg.project_root().canonicalize()?; + let profile_registry = match (context.profile_identity.as_deref(), &context.registry_db) { + (Some(identity), Some(registry)) => Some(( + super::profile_retained::profile_session_scope(identity)?, + registry.clone(), + )), + _ => None, + }; let resident_memory = Arc::new( tracedecay_runtime_core::resident_memory::ProcessResidentMemoryV1::new( tracedecay_runtime_core::resident_memory::DEFAULT_PROCESS_RESIDENT_MEMORY_LIMIT_V1, @@ -133,6 +172,7 @@ pub(crate) fn project_retained_owner_transport( service: service.clone(), lsp_registry: Arc::new(Mutex::new(LspSessionRegistry::default())), project_root, + profile_registry, }; Ok(ProjectRetainedOwnerTransport { service, @@ -212,7 +252,7 @@ pub(crate) async fn register_project_retained_owner_for_test( pub(crate) async fn mcp_server_with_project_retained_owner_for_test( context: crate::mcp::server::McpServerConstructionContext, ) -> Result> { - let transport = project_retained_owner_transport(context.cg.project_root())?; + let transport = project_retained_owner_transport(&context)?; let context = context.with_application_invocation_executor(Arc::clone(&transport.executor)); let server = crate::mcp::McpServer::new_with_context(context).await; register_project_retained_owner_for_test(&transport.service, server.as_ref()).await?; diff --git a/crates/tracedecay/src/daemon/tests/multi_root_execute_mcp.rs b/crates/tracedecay/src/daemon/tests/multi_root_execute_mcp.rs index 80debfe8cc..b938d5e43b 100644 --- a/crates/tracedecay/src/daemon/tests/multi_root_execute_mcp.rs +++ b/crates/tracedecay/src/daemon/tests/multi_root_execute_mcp.rs @@ -195,8 +195,6 @@ async fn call_execute( graph, "tracedecay_multi_root_execute", arguments, - None, - None, options, ) .await diff --git a/crates/tracedecay/src/mcp/server.rs b/crates/tracedecay/src/mcp/server.rs index 2ea08ae184..a4edd45e26 100644 --- a/crates/tracedecay/src/mcp/server.rs +++ b/crates/tracedecay/src/mcp/server.rs @@ -49,7 +49,6 @@ use tracedecay_sessions::runtime::git_correlation::{ SpanObservation, SpanSource, }; -use tracedecay_contracts::ProjectRegistryReadPort; use tracedecay_domain::HostIntegrationIdV1; use tracedecay_mcp::hook_events::{self, HookEventPlan}; use tracedecay_mcp::tools::catalog_discovery::default_catalog_discovery_authority; @@ -82,7 +81,7 @@ pub(crate) use rmcp::RmcpInitializeResponseDecorator; pub(crate) use rmcp::{RmcpSelectedProjectResponseAuthority, RmcpWorkDeliverySettlement}; pub(crate) use routing::*; use tracedecay_daemon_service::DaemonSessionRefreshService; -use tracedecay_daemon_service::{DaemonProjectRegistryReadService, DaemonWorkflowIndexReadService}; +use tracedecay_daemon_service::DaemonWorkflowIndexReadService; pub(crate) use tracedecay_mcp::server::ProjectServerResponseLifecycle; use tracedecay_mcp::server::{ IdenticalReadCoalescer, McpBackgroundTaskOwner, McpDispatchRequest, @@ -367,9 +366,6 @@ pub struct McpServer { /// when global accounting is disabled so daemon clients do not fall back /// to the daemon process profile for selector resolution. registry_db: Option, - /// Registry-read service handed to MCP handlers so they read registered - /// projects through a port instead of holding [`Self::registry_db`]. - project_registry_reads: Option>, automation_scheduler_reconciler: Option, database_owner_reconciler: Option, @@ -735,9 +731,8 @@ impl McpServer { let retained_owner_transport = if context.application_invocation_executor.is_none() && context.cg.store_layout().identity.project_id.is_some() { - let transport = crate::daemon::retained_test_support::project_retained_owner_transport( - context.cg.project_root(), - )?; + let transport = + crate::daemon::retained_test_support::project_retained_owner_transport(&context)?; context = context.with_application_invocation_executor(Arc::clone(&transport.executor)); Some(transport) } else { @@ -985,10 +980,6 @@ impl McpServer { Some(project_id), )) as Arc }); - let project_registry_reads = registry_db.as_ref().map(|registry| { - Arc::new(DaemonProjectRegistryReadService::new(registry.clone())) - as Arc - }); let project_application_retrieval = project_session_db .as_ref() .zip(project_session_retrieval_root.clone()) @@ -1041,7 +1032,6 @@ impl McpServer { profile_identity, project_session_db, registry_db, - project_registry_reads, profile_session_db, host_admission_broker, background_cpu, diff --git a/crates/tracedecay/src/mcp/server/graph_tool_owner.rs b/crates/tracedecay/src/mcp/server/graph_tool_owner.rs index 7d4b686914..b10086c2fc 100644 --- a/crates/tracedecay/src/mcp/server/graph_tool_owner.rs +++ b/crates/tracedecay/src/mcp/server/graph_tool_owner.rs @@ -11,6 +11,7 @@ use tracedecay_daemon_service::{ RegisteredGraphToolOwnerV1, }; use tracedecay_domain::errors::{Result, TraceDecayError}; +use tracedecay_tool_catalog::ApplicationSurfaceOperation; use super::McpServer; use crate::mcp::tools::{ @@ -45,6 +46,10 @@ impl McpServer { invocation: GraphToolInvocationV1, ) -> Result { let (cg, _live_branch) = self.reopen_if_branch_drifted_memoized().await; + let server_stats = match invocation.operation { + ApplicationSurfaceOperation::Status => Some(self.server_stats_json().await), + _ => None, + }; let options = ToolCallRegistryOptions { global_db: self.registry_db.as_ref(), accounting_db: self.accounting_db.as_deref(), @@ -53,6 +58,11 @@ impl McpServer { self.project_session_db.as_ref(), self.profile_session_db.as_ref(), ), + server_stats, + doctor_report_reader: self.dashboard_doctor_report_reader.clone(), + remote_operational_status: self.remote_operational_status.clone(), + code_index_readiness_waiter: self.code_index_readiness_waiter.clone(), + generation_census_reader: self.generation_census_reader(), registered_project_session_db: self.project_session_db.clone(), application_request_id: Some(invocation.request_id), application_deadline: Some(invocation.deadline), diff --git a/crates/tracedecay/src/mcp/server/requests/tool_dispatch.rs b/crates/tracedecay/src/mcp/server/requests/tool_dispatch.rs index 33263efcf8..22a3ce8806 100644 --- a/crates/tracedecay/src/mcp/server/requests/tool_dispatch.rs +++ b/crates/tracedecay/src/mcp/server/requests/tool_dispatch.rs @@ -137,7 +137,6 @@ impl McpServer { tool_name, routed.arguments, routed.selected_project.as_ref(), - None, application_invocation_executor, application_invocation_target, Some( @@ -209,11 +208,6 @@ impl McpServer { publish_activity, ) .await; - let server_stats = if tool_name == "tracedecay_status" { - Some(dispatch_server.server_stats_json().await) - } else { - None - }; let ApplicationSurfaceDispatch { invocation_executor: application_invocation_executor, .. @@ -226,7 +220,6 @@ impl McpServer { tool_name, routed.arguments, routed.selected_project.as_ref(), - server_stats, application_invocation_executor, application_invocation_target, application_request_id, @@ -255,7 +248,6 @@ impl McpServer { tool_name: &str, handler_arguments: Value, resolved_project_route: Option<&crate::mcp::project_route::ResolvedProjectRoute>, - server_stats: Option, application_invocation_executor: Option< &dyn tracedecay_daemon_protocol::DaemonInvocationExecutor, >, @@ -287,11 +279,9 @@ impl McpServer { cg, tool_name, handler_arguments, - server_stats, - self.scope_prefix(), ToolCallRegistryOptions { global_db: self.registry_db.as_ref(), - project_registry_reads: self.project_registry_reads.as_deref(), + server_stats: None, accounting_db: self.accounting_db.as_deref(), registered_project_session_db: self.project_session_db.clone(), registered_profile_session_db: self.profile_session_db.clone(), diff --git a/crates/tracedecay/src/mcp/tools/handlers/application_surface.rs b/crates/tracedecay/src/mcp/tools/handlers/application_surface.rs index 89a6cbef8f..aa06359c62 100644 --- a/crates/tracedecay/src/mcp/tools/handlers/application_surface.rs +++ b/crates/tracedecay/src/mcp/tools/handlers/application_surface.rs @@ -459,9 +459,10 @@ pub type GraphToolOutcome = std::result::Result< ApplicationRefusal, >; -/// Invoke one graph-tool operation through the project's graph-tool owner and -/// return its typed result. Every refusal keeps the owner's whole problem -/// record for the surface to render. +/// Invoke one graph-tool operation through the project's graph-tool owner, or +/// one profile registry read through the daemon's profile owner, and return +/// its typed result. Every refusal keeps the owner's whole problem record for +/// the surface to render. #[allow(clippy::too_many_arguments)] #[hotpath::measure(future = true, label = "mcp.graph_tool.total")] pub async fn execute_graph_tool_surface( @@ -497,7 +498,7 @@ pub async fn execute_graph_tool_surface( ) }, )?; - let dispatched = tracedecay_daemon_service::application_surface::resolve_application_surface_dispatch_with_controls( + let mut dispatched = tracedecay_daemon_service::application_surface::resolve_application_surface_dispatch_with_controls( surface, operation, request_id, @@ -510,6 +511,11 @@ pub async fn execute_graph_tool_surface( RequestedOutputFormat::Json, ) .map_err(application_surface_dispatch_error)?; + // The profile registry names no project, so the daemon's profile owner + // answers it whatever project this caller's executor serves. + if operation.is_profile_registry_read() { + dispatched.invocation.invocation.scope = InvocationTarget::Profile; + } let binding_id = dispatched.invocation.binding_id.clone(); let result = tracedecay_daemon_service::application_surface::execute_application_surface( operation, dispatched, executor, diff --git a/crates/tracedecay/src/mcp/tools/handlers/configuration_dispatch_tests.rs b/crates/tracedecay/src/mcp/tools/handlers/configuration_dispatch_tests.rs index a873c6d832..b23fa6d611 100644 --- a/crates/tracedecay/src/mcp/tools/handlers/configuration_dispatch_tests.rs +++ b/crates/tracedecay/src/mcp/tools/handlers/configuration_dispatch_tests.rs @@ -137,8 +137,6 @@ async fn available_configuration_effect_reaches_canonical_executor() { &cg, "tracedecay_configuration_set", request, - None, - None, ToolCallRegistryOptions { application_invocation_executor: Some(&executor), application_cancellation: Some(cancellation.clone()), @@ -247,8 +245,6 @@ async fn every_other_configuration_effect_reaches_the_authoritative_daemon_execu &cg, tool_name, request.clone(), - None, - None, ToolCallRegistryOptions { application_invocation_executor: Some(&executor), application_cancellation: Some(cancellation.clone()), @@ -358,8 +354,6 @@ async fn every_configuration_read_and_preview_reaches_its_canonical_daemon_handl &cg, tool_name, request.clone(), - None, - None, ToolCallRegistryOptions { application_invocation_executor: Some(&executor), ..Default::default() diff --git a/crates/tracedecay/src/mcp/tools/handlers/context_scout_control_dispatch_tests.rs b/crates/tracedecay/src/mcp/tools/handlers/context_scout_control_dispatch_tests.rs index 18a75f4dfb..ca3619715b 100644 --- a/crates/tracedecay/src/mcp/tools/handlers/context_scout_control_dispatch_tests.rs +++ b/crates/tracedecay/src/mcp/tools/handlers/context_scout_control_dispatch_tests.rs @@ -136,8 +136,6 @@ async fn context_scout_pause_and_resume_preserve_caller_idempotency_keys() { "expected_revision": "revision.mcp-context-scout-control-dispatch", "idempotency_key": idempotency_key }), - None, - None, ToolCallRegistryOptions { application_invocation_executor: Some(&executor), application_cancellation: Some(cancellation.clone()), diff --git a/crates/tracedecay/src/mcp/tools/handlers/dispatch_groups.rs b/crates/tracedecay/src/mcp/tools/handlers/dispatch_groups.rs index b643adf592..a4bea05a5a 100644 --- a/crates/tracedecay/src/mcp/tools/handlers/dispatch_groups.rs +++ b/crates/tracedecay/src/mcp/tools/handlers/dispatch_groups.rs @@ -12,10 +12,16 @@ use tracedecay_project::project::TraceDecay; use tracedecay_contracts::code_index_freshness::{ CodeIndexFreshnessReader, CodeIndexReadinessWaitOutcomeV1, CodeIndexReadinessWaitV1, }; +use tracedecay_contracts::graph_tool::GraphToolResultV1; +use tracedecay_contracts::retrieval::{ + ActiveProjectSurfaceRequestV1, RemoteStatusSurfaceRequestV1, RuntimeSurfaceRequestV1, + StatusSurfaceRequestV1, +}; use tracedecay_dashboard_api::AdmittedDoctorReportV1; +use tracedecay_mcp::handlers::health as portable_health; use tracedecay_mcp::handlers::info as portable_info; use tracedecay_mcp::handlers::{ - VerifiedGraphOpenFuture, unknown_tool_error, verified_read_operation, + VerifiedGraphOpenFuture, decode_primitive_request, unknown_tool_error, verified_read_operation, }; use tracedecay_mcp::tools::binding::tool_dispatches_registered_project_reader; use tracedecay_mcp::tools::dispatch_ceiling::{tool_dispatch_budget, tool_dispatch_deadline_error}; @@ -29,9 +35,6 @@ use super::ToolCallRegistryOptions; use super::{application_surface, dashboard, dispatch_controls, info}; use tracedecay_mcp::handlers::{admin_cli, admin_project, edit, hook_runtime, workflow}; -mod health_dispatch; -pub(super) use health_dispatch::dispatch_health_tools; - fn graph_read_unavailable(detail: &str) -> TraceDecayError { TraceDecayError::ProjectRoute { reason_code: "verified-code-graph-read-unavailable".to_owned(), @@ -107,93 +110,19 @@ async fn admitted_graph_query_for_operation( Ok(query) } -/// Dispatch project-info, registry, and file-inspection tools -/// (`tracedecay_status`, `tracedecay_project_list`, ...). -#[allow(clippy::too_many_arguments)] +/// Dispatch the daemon-only `tracedecay_admin_sync`. #[hotpath::measure(future = true, label = "mcp.dispatch.info")] pub(super) async fn dispatch_info_tools( tool_name: &str, cg: &TraceDecay, - args: Value, - server_stats: Option, - scope_prefix: Option<&str>, options: ToolCallRegistryOptions<'_>, ) -> Result { - dispatch_info_tools_inner(tool_name, cg, args, server_stats, scope_prefix, options).await -} - -fn dispatch_info_tools_inner<'a>( - tool_name: &'a str, - cg: &'a TraceDecay, - args: Value, - server_stats: Option, - scope_prefix: Option<&'a str>, - options: ToolCallRegistryOptions<'a>, -) -> std::pin::Pin> + Send + 'a>> { - // Erase the deeply nested match-arm futures before they reach the - // measured wrapper so every profiling feature can compute its layout. - Box::pin(async move { - // Registry, status, and remote-status reads bind daemon authorities - // only the root holds (registry port, status snapshots, remote - // status reader, reconcile sink); the graph-backed file inspections - // dispatch through the portable table. - match tool_name { - "tracedecay_remote_status" => portable_info::handle_remote_status( - &cg.store_layout().response_handle_root, - &args, - options.remote_operational_status.as_ref(), - ), - "tracedecay_status" => { - // Wait before admitting snapshots, so the payload describes - // the worktree the wait ended on. - let wait = match portable_info::status_readiness_wait(&args)? { - Some(request) => { - Some(status_readiness_wait(&options, cg.project_root(), request).await?) - } - None => None, - }; - let project = admitted_project_authorities(cg, &options)?; - let snapshots = admitted_status_snapshots(&options).await; - let ctx = admitted_tool_context_for(&options, &project, &snapshots)?; - portable_info::handle_status(&ctx, args, server_stats, scope_prefix, wait).await - } - "tracedecay_active_project" => { - let project = admitted_project_authorities(cg, &options)?; - let snapshots = AdmittedRequestSnapshotsV1::default(); - let ctx = admitted_tool_context_for(&options, &project, &snapshots)?; - portable_info::handle_active_project(&ctx, &args, server_stats, scope_prefix).await - } - "tracedecay_project_list" => { - portable_info::handle_project_list( - Some(cg.project_root()), - args, - options.project_registry_reads, - ) - .await - } - "tracedecay_project_search" => { - portable_info::handle_project_search( - Some(cg.project_root()), - args, - options.project_registry_reads, - ) - .await - } - "tracedecay_project_context" => { - portable_info::handle_project_context( - Some(cg.project_root()), - Some(&cg.store_layout().response_handle_root), - args, - options.project_registry_reads, - ) - .await - } - "tracedecay_admin_sync" => { - info::handle_admin_sync(cg, options.code_index_reconcile_sink.as_ref()).await - } - _ => Err(unknown_tool_error(tool_name)), + match tool_name { + "tracedecay_admin_sync" => { + info::handle_admin_sync(cg, options.code_index_reconcile_sink.as_ref()).await } - }) + _ => Err(unknown_tool_error(tool_name)), + } } /// Dispatch administrative tools (`tracedecay_hook_runtime`, @@ -294,7 +223,7 @@ fn dispatch_application_surface_tools_inner<'a>( }; let retained = RetainedSurfaceOperation::from_application(operation).is_some(); let source_edit = tracedecay_daemon_protocol::is_source_edit_operation(operation); - let graph_tool = operation.is_graph_tool(); + let graph_tool = operation.is_graph_tool() || operation.is_profile_registry_read(); // An already-elapsed carried deadline is refused before these tools // dispatch, exactly as their retained handlers always refused it. if (retained || source_edit || graph_tool) @@ -435,6 +364,29 @@ pub(crate) fn compute_graph_tool_for_owner<'a>( Err(_elapsed) => Err(tool_dispatch_deadline_error(tool_name, budget)), }; } + if matches!( + operation, + ApplicationSurfaceOperation::Status + | ApplicationSurfaceOperation::ActiveProject + | ApplicationSurfaceOperation::RemoteStatus + | ApplicationSurfaceOperation::Runtime + ) { + let computed = compute_project_info(cg, operation, &args, scope_prefix, &options); + return match tokio::time::timeout(budget, computed).await { + Ok(result) => { + result.map( + |result| tracedecay_contracts::graph_tool::GraphToolCompletionV1 { + result, + touched_files: Vec::new(), + code_graph: None, + analytics: None, + cost: None, + }, + ) + } + Err(_elapsed) => Err(tool_dispatch_deadline_error(tool_name, budget)), + }; + } let project = admitted_project_authorities(cg, &options)?; let snapshots = AdmittedRequestSnapshotsV1::default(); let freshness = graph_freshness_reader(tool_name, &options); @@ -470,6 +422,75 @@ pub(crate) fn compute_graph_tool_for_owner<'a>( }) } +/// The project-info and runtime reads the owner answers from the daemon +/// authorities it holds: the census and readiness waiter (status), the +/// Remote Brain reader (remote status), and the doctor report and global +/// registry (runtime). +async fn compute_project_info( + cg: &TraceDecay, + operation: ApplicationSurfaceOperation, + args: &Value, + scope_prefix: Option<&str>, + options: &ToolCallRegistryOptions<'_>, +) -> Result { + let tool_name = operation.mcp_tool_name(); + match operation { + ApplicationSurfaceOperation::Status => { + let request: StatusSurfaceRequestV1 = decode_primitive_request(args, tool_name)?; + // Wait before admitting snapshots, so the payload describes the + // worktree the wait ended on. + let wait = match request.wait_for { + Some(wait_for) => { + Some(status_readiness_wait(options, cg.project_root(), wait_for).await?) + } + None => None, + }; + let project = admitted_project_authorities(cg, options)?; + let snapshots = admitted_status_snapshots(options).await; + let ctx = admitted_tool_context_for(options, &project, &snapshots)?; + portable_info::compute_status( + &ctx, + &request, + options.server_stats.clone(), + scope_prefix, + wait, + ) + .await + .map(GraphToolResultV1::Status) + } + ApplicationSurfaceOperation::ActiveProject => { + let ActiveProjectSurfaceRequestV1 {} = decode_primitive_request(args, tool_name)?; + let project = admitted_project_authorities(cg, options)?; + let snapshots = AdmittedRequestSnapshotsV1::default(); + let ctx = admitted_tool_context_for(options, &project, &snapshots)?; + Ok(GraphToolResultV1::ActiveProject( + portable_info::compute_active_project(&ctx, scope_prefix).await, + )) + } + ApplicationSurfaceOperation::RemoteStatus => { + let RemoteStatusSurfaceRequestV1 {} = decode_primitive_request(args, tool_name)?; + Ok(GraphToolResultV1::RemoteStatus( + portable_info::read_remote_status(options.remote_operational_status.as_ref()), + )) + } + ApplicationSurfaceOperation::Runtime => { + let request: RuntimeSurfaceRequestV1 = decode_primitive_request(args, tool_name)?; + let project = admitted_project_authorities(cg, options)?; + let snapshots = admitted_runtime_snapshots(options, request.doctor_report).await; + let ctx = admitted_tool_context(options, &project, &snapshots, None)?; + portable_health::compute_runtime( + &ctx, + &request, + options.global_db.map(RegisteredGlobalDbLeaseV1::as_ref), + tracedecay_project::version::build_version()?, + ) + .await + .map(|runtime| GraphToolResultV1::Runtime(Box::new(runtime))) + } + operation => Err(unknown_tool_error(operation.mcp_tool_name())), + } +} + /// Builds the request-scoped admitted project snapshot from the live /// `TraceDecay` this call already holds. It must not be cached: a later /// branch reopen swaps the served instance. diff --git a/crates/tracedecay/src/mcp/tools/handlers/dispatch_groups/health_dispatch.rs b/crates/tracedecay/src/mcp/tools/handlers/dispatch_groups/health_dispatch.rs deleted file mode 100644 index 61f588dd75..0000000000 --- a/crates/tracedecay/src/mcp/tools/handlers/dispatch_groups/health_dispatch.rs +++ /dev/null @@ -1,41 +0,0 @@ -//! Runtime-telemetry MCP dispatch family. - -use serde_json::Value; - -use tracedecay_domain::errors::Result; -use tracedecay_global_db::RegisteredGlobalDbLeaseV1; -use tracedecay_project::project::TraceDecay; - -use super::super::ToolCallRegistryOptions; -use super::{admitted_project_authorities, admitted_runtime_snapshots, admitted_tool_context}; -use tracedecay_mcp::ToolResult; -use tracedecay_mcp::handlers::health as portable_health; -use tracedecay_mcp::handlers::unknown_tool_error; - -/// Dispatch `tracedecay_runtime`: it snapshots the daemon census and doctor -/// report the root holds, and stamps the build the root was compiled as. -#[hotpath::measure(future = true, label = "mcp.dispatch.health")] -pub(in crate::mcp::tools::handlers) async fn dispatch_health_tools( - tool_name: &str, - cg: &TraceDecay, - args: Value, - options: ToolCallRegistryOptions<'_>, -) -> Result { - if tool_name != "tracedecay_runtime" { - return Err(unknown_tool_error(tool_name)); - } - let project = admitted_project_authorities(cg, &options)?; - let include_doctor = args - .get("doctor_report") - .and_then(Value::as_bool) - .unwrap_or(false); - let snapshots = admitted_runtime_snapshots(&options, include_doctor).await; - let ctx = admitted_tool_context(&options, &project, &snapshots, None)?; - portable_health::handle_runtime( - &ctx, - args, - options.global_db.map(RegisteredGlobalDbLeaseV1::as_ref), - tracedecay_project::version::build_version()?, - ) - .await -} diff --git a/crates/tracedecay/src/mcp/tools/handlers/dispatch_test_support.rs b/crates/tracedecay/src/mcp/tools/handlers/dispatch_test_support.rs index 978c172b41..b3001c6346 100644 --- a/crates/tracedecay/src/mcp/tools/handlers/dispatch_test_support.rs +++ b/crates/tracedecay/src/mcp/tools/handlers/dispatch_test_support.rs @@ -249,7 +249,7 @@ fn verified_graph_options_with_freshness<'a>( /// computes them under the owning server's admitted authorities and renders /// the typed result; every other tool still dispatches through the MCP /// handler table. -pub(super) async fn dispatch_on_graph_authority( +pub(crate) async fn dispatch_on_graph_authority( cg: &TraceDecay, tool_name: &str, args: Value, @@ -268,9 +268,7 @@ pub(super) async fn dispatch_on_graph_authority( completion, ) } - None => { - handle_tool_call_with_registry_options(cg, tool_name, args, None, None, options).await - } + None => handle_tool_call_with_registry_options(cg, tool_name, args, options).await, } } @@ -388,14 +386,9 @@ pub(super) async fn concrete_dispatch_group_accepts( McpToolDispatchGroup::MultiRoot => { owned(handle_multi_root(tool_name, invalid_args, None, None, None, None).await) } - McpToolDispatchGroup::Info => { - owned(dispatch_info_tools(tool_name, cg, invalid_args, None, None, options).await) - } + McpToolDispatchGroup::Info => owned(dispatch_info_tools(tool_name, cg, options).await), McpToolDispatchGroup::Admin => { owned(dispatch_admin_tools(tool_name, cg, invalid_args, options).await) } - McpToolDispatchGroup::Health => { - owned(dispatch_health_tools(tool_name, cg, invalid_args, options).await) - } } } diff --git a/crates/tracedecay/src/mcp/tools/handlers/dispatch_tests.rs b/crates/tracedecay/src/mcp/tools/handlers/dispatch_tests.rs index 0d3785462c..725c6844d8 100644 --- a/crates/tracedecay/src/mcp/tools/handlers/dispatch_tests.rs +++ b/crates/tracedecay/src/mcp/tools/handlers/dispatch_tests.rs @@ -97,8 +97,6 @@ async fn retired_file_metadata_is_absent_and_refused_by_public_dispatch() { &cg, retired, json!({"files": ["../outside"]}), - None, - None, ToolCallRegistryOptions::default(), ) .await @@ -156,8 +154,6 @@ async fn multi_root_tools_invoke_the_closed_daemon_routes() { &cg, tool_name, args, - None, - None, ToolCallRegistryOptions { application_invocation_executor: Some(&executor), ..Default::default() @@ -368,15 +364,9 @@ async fn advertised_tools_resolve_one_concrete_dispatch_entry() { None, "{tool_name} must fail closed" ); - let rejected = handle_tool_call_with_registry_options( - &cg, - tool_name, - json!({}), - None, - None, - options.clone(), - ) - .await; + let rejected = + handle_tool_call_with_registry_options(&cg, tool_name, json!({}), options.clone()) + .await; assert!( rejected.is_err(), "{tool_name} must reject handler dispatch" @@ -502,7 +492,7 @@ async fn status_and_runtime_share_cursor_session_ingest_authority() { .admit_opened_project(&cg) .expect("opened fixture admits") }; - let status = handle_tool_call_with_registry_options( + let status = dispatch_on_graph_authority( &cg, "tracedecay_status", json!({ @@ -514,21 +504,17 @@ async fn status_and_runtime_share_cursor_session_ingest_authority() { "include_storage_health": false, "include_staleness": false, }), - None, - None, options(), ) .await .unwrap(); - let runtime_result = handle_tool_call_with_registry_options( + let runtime_result = dispatch_on_graph_authority( &cg, "tracedecay_runtime", json!({ "format": "json", "session_ingest_health": true, }), - None, - None, options(), ) .await @@ -723,12 +709,10 @@ async fn status_serving_branch_reports_the_lane_serving_truth() { }; // Fresh daemon: the census answers, nothing has sealed yet. - let rebuilding = handle_tool_call_with_registry_options( + let rebuilding = dispatch_on_graph_authority( &cg, "tracedecay_status", json!({"format": "json"}), - None, - None, ToolCallRegistryOptions { code_index_freshness_reader: Some(freshness_reader(None, Some("indexing"), true)), ..Default::default() @@ -750,12 +734,10 @@ async fn status_serving_branch_reports_the_lane_serving_truth() { ); // A sealed complete generation exists: the branch claim is truthful again. - let serving = handle_tool_call_with_registry_options( + let serving = dispatch_on_graph_authority( &cg, "tracedecay_status", json!({"format": "json"}), - None, - None, ToolCallRegistryOptions { code_index_freshness_reader: Some(freshness_reader( Some("generation.status-serving-truth.1"), @@ -812,14 +794,12 @@ async fn status_serving_branch_reports_the_lane_serving_truth() { }); reader }; - let stale_public = handle_tool_call_with_registry_options( + let stale_public = dispatch_on_graph_authority( &cg, "tracedecay_status", // Full branch claim fields (branch_resolution, diagnostics) are opt-in // after compact-by-default status; serving truth still uses the freshness path. json!({"format": "json", "include_branch_diagnostics": true}), - None, - None, ToolCallRegistryOptions { code_index_freshness_reader: Some(public_freshness_reader( Some("0".repeat(40)), @@ -837,12 +817,10 @@ async fn status_serving_branch_reports_the_lane_serving_truth() { assert_ne!(stale_public["branch_resolution"], json!("exact")); let committed_public_reader = public_freshness_reader(Some(public_revision), "fresh"); - let current_public = handle_tool_call_with_registry_options( + let current_public = dispatch_on_graph_authority( &cg, "tracedecay_status", json!({"format": "json", "include_branch_diagnostics": true}), - None, - None, ToolCallRegistryOptions { code_index_freshness_reader: Some(committed_public_reader), ..Default::default() @@ -870,12 +848,10 @@ async fn status_serving_branch_reports_the_lane_serving_truth() { // A dirty worktree snapshot has an exact content identity but no Git OID. // Its complete, fresh, ready source witness still identifies the current // public branch without inventing a revision. - let active_public = handle_tool_call_with_registry_options( + let active_public = dispatch_on_graph_authority( &cg, "tracedecay_active_project", json!({"format": "json"}), - None, - None, ToolCallRegistryOptions { code_index_freshness_reader: Some(public_freshness_reader(None, "fresh")), ..Default::default() @@ -945,12 +921,10 @@ async fn status_serving_branch_reports_the_lane_serving_truth() { }; Box::pin(async move { Ok(Some(freshness)) }) }); - let published_feature = handle_tool_call_with_registry_options( + let published_feature = dispatch_on_graph_authority( &cg, "tracedecay_status", json!({"format": "json", "include_branch_diagnostics": true}), - None, - None, ToolCallRegistryOptions { code_index_freshness_reader: Some(feature_reader.clone()), ..Default::default() @@ -986,12 +960,10 @@ async fn status_serving_branch_reports_the_lane_serving_truth() { assert_eq!(feature_row["is_ready"], json!(true)); assert!(published_feature.get("branch_warnings").is_none()); - let compact_feature = handle_tool_call_with_registry_options( + let compact_feature = dispatch_on_graph_authority( &cg, "tracedecay_status", json!({"format": "json", "include_branch_diagnostics": false}), - None, - None, ToolCallRegistryOptions { code_index_freshness_reader: Some(feature_reader), ..Default::default() @@ -1005,12 +977,10 @@ async fn status_serving_branch_reports_the_lane_serving_truth() { assert_eq!(compact_feature["active_branch"], json!("feature")); assert_eq!(compact_feature["serving_branch"], json!("feature")); - let rebuilding = handle_tool_call_with_registry_options( + let rebuilding = dispatch_on_graph_authority( &cg, "tracedecay_status", json!({"format": "json"}), - None, - None, ToolCallRegistryOptions { code_index_freshness_reader: Some(freshness_reader( Some("generation.status-serving-truth.1"), @@ -1057,12 +1027,10 @@ async fn status_serving_branch_reports_the_lane_serving_truth() { }; Box::pin(async move { Ok(Some(freshness)) }) }); - let aged = handle_tool_call_with_registry_options( + let aged = dispatch_on_graph_authority( &cg, "tracedecay_status", json!({"format": "json"}), - None, - None, ToolCallRegistryOptions { code_index_freshness_reader: Some(aged_reader), ..Default::default() @@ -1118,8 +1086,6 @@ async fn unsupported_selector_tool_rejects_explicit_project_selector() { "project_id": "explicit-selector-should-not-fall-open" }, }), - None, - None, ) .await .expect_err("unsupported selector tools must reject explicit selectors"); @@ -1157,8 +1123,6 @@ async fn query_search_rejects_cross_project_selector() { }, "query": "target", }), - None, - None, ) .await .expect_err("single-root search must reject project selectors"); @@ -2071,8 +2035,6 @@ async fn unavailable_user_lcm_effect_is_rejected_before_profile_store_open() { "provider": "codex", "session_id": "retired", }), - None, - None, ToolCallRegistryOptions { profile: Some(&lcm_profile), ..Default::default() @@ -2132,8 +2094,6 @@ async fn admin_sync_reports_terminal_publication_corruption_without_queueing() { &cg, "tracedecay_admin_sync", json!({"format": "json"}), - None, - None, ToolCallRegistryOptions { code_index_reconcile_sink: Some(reconcile_sink), ..Default::default() diff --git a/crates/tracedecay/src/mcp/tools/handlers/info/remote_status_dispatch_tests.rs b/crates/tracedecay/src/mcp/tools/handlers/info/remote_status_dispatch_tests.rs index 04e04c9432..4b6d112b6e 100644 --- a/crates/tracedecay/src/mcp/tools/handlers/info/remote_status_dispatch_tests.rs +++ b/crates/tracedecay/src/mcp/tools/handlers/info/remote_status_dispatch_tests.rs @@ -14,9 +14,9 @@ use tracedecay_contracts::remote::status::{ use tracedecay_contracts::{DoctorCoverageCompletenessV1, RemoteListenerReadV1}; use tracedecay_domain::{CurrentRemoteAuthorityStateV1, UtcMicros}; -use crate::mcp::tools::handlers::dispatch_test_support::SelectorProfile; -use crate::mcp::tools::handlers::{ - ToolCallRegistryOptions, handle_tool_call_with_registry_options, +use crate::mcp::tools::handlers::ToolCallRegistryOptions; +use crate::mcp::tools::handlers::dispatch_test_support::{ + SelectorProfile, dispatch_on_graph_authority, }; use tracedecay_mcp::ToolResult; use tracedecay_project::project::TraceDecay; @@ -102,12 +102,10 @@ async fn dispatch_returns_provider_json_or_typed_unavailable() { let expected = expected.clone(); Arc::new(move || expected.clone()) }; - let observed = handle_tool_call_with_registry_options( + let observed = dispatch_on_graph_authority( &cg, "tracedecay_remote_status", json!({ "format": "json" }), - None, - None, ToolCallRegistryOptions { remote_operational_status: Some(provider), ..Default::default() @@ -120,12 +118,10 @@ async fn dispatch_returns_provider_json_or_typed_unavailable() { serde_json::to_value(&expected).unwrap() ); - let absent = handle_tool_call_with_registry_options( + let absent = dispatch_on_graph_authority( &cg, "tracedecay_remote_status", json!({ "format": "json" }), - None, - None, ToolCallRegistryOptions::default(), ) .await diff --git a/crates/tracedecay/src/mcp/tools/handlers/mod.rs b/crates/tracedecay/src/mcp/tools/handlers/mod.rs index 3266c3f7d9..9084356cd8 100644 --- a/crates/tracedecay/src/mcp/tools/handlers/mod.rs +++ b/crates/tracedecay/src/mcp/tools/handlers/mod.rs @@ -52,6 +52,8 @@ mod dispatch_groups; )] mod dispatch_test_support; #[cfg(test)] +pub(crate) use dispatch_test_support::dispatch_on_graph_authority; +#[cfg(test)] #[allow( clippy::unwrap_used, clippy::expect_used, @@ -97,6 +99,15 @@ mod retained_timeout_dispatch_tests; clippy::redundant_closure_for_method_calls, clippy::uninlined_format_args )] +mod runtime_behavior_dispatch_tests; +#[cfg(test)] +#[allow( + clippy::unwrap_used, + clippy::expect_used, + clippy::await_holding_lock, + clippy::redundant_closure_for_method_calls, + clippy::uninlined_format_args +)] mod runtime_generation_census_dispatch_tests; #[cfg(test)] #[allow( @@ -165,12 +176,10 @@ use tracedecay_tool_catalog::{ApplicationSurfaceOperation, BindingSurface}; use super::LegacyToolCompatibilityOwner; use dispatch_groups::{ - dispatch_admin_tools, dispatch_application_surface_tools, dispatch_health_tools, - dispatch_info_tools, + dispatch_admin_tools, dispatch_application_surface_tools, dispatch_info_tools, }; use tool_call_support::{boxed_send, rejected_tool_project_selector_present}; use tracedecay_api::{WorkHttpRequest, WorkflowHttpRequest}; -use tracedecay_contracts::ProjectRegistryReadPort; use tracedecay_daemon_protocol::DaemonInvocationExecutor; use tracedecay_daemon_service::application_surface::resolve_catalog_tool_binding; use tracedecay_domain::errors::{Result, TraceDecayError}; @@ -188,11 +197,6 @@ use tracedecay_mcp::{handle_multi_root, handle_work, handle_workflow}; use tracedecay_project::project::TraceDecay; use tracedecay_runtime_core::storage::registered_project_id; -/// Dispatches a tool call to the appropriate handler. -/// -/// Returns the tool result and touched file paths, or an error if the tool -/// name is unknown or the handler fails. The optional `server_stats` value -/// is included in `tracedecay_status` responses when provided. fn ensure_mcp_dispatch_available(tool_name: &str) -> Result<()> { if INTERNAL_DAEMON_TOOL_NAMES.contains(&tool_name) { return Ok(()); @@ -218,19 +222,15 @@ fn ensure_mcp_dispatch_available(tool_name: &str) -> Result<()> { Ok(()) } -pub async fn handle_tool_call( - cg: &TraceDecay, - tool_name: &str, - args: Value, - server_stats: Option, - scope_prefix: Option<&str>, -) -> Result { +/// Dispatches a tool call to the appropriate handler. +/// +/// Returns the tool result and touched file paths, or an error if the tool +/// name is unknown or the handler fails. +pub async fn handle_tool_call(cg: &TraceDecay, tool_name: &str, args: Value) -> Result { Box::pin(handle_tool_call_with_registry_options( cg, tool_name, args, - server_stats, - scope_prefix, ToolCallRegistryOptions::default().admit_opened_project(cg)?, )) .await @@ -283,9 +283,9 @@ impl ServedCodeGraphSlot { #[derive(Clone)] pub struct ToolCallRegistryOptions<'a> { pub(crate) global_db: Option<&'a RegisteredGlobalDbLeaseV1>, - /// Daemon-owned project-registry reads. `None` is the typed - /// missing-registry state, not an empty registry. - pub(crate) project_registry_reads: Option<&'a dyn ProjectRegistryReadPort>, + /// The serving MCP server's request counters, which the graph-tool owner + /// reports in `tracedecay_status`. + pub(crate) server_stats: Option, pub(crate) accounting_db: Option<&'a tracedecay_global_db::RegisteredGlobalDb>, pub(crate) registered_project_session_db: Option, @@ -384,7 +384,7 @@ impl Default for ToolCallRegistryOptions<'_> { fn default() -> Self { Self { global_db: None, - project_registry_reads: None, + server_stats: None, accounting_db: None, registered_project_session_db: None, registered_profile_session_db: None, @@ -461,8 +461,6 @@ pub fn handle_tool_call_with_registry_options<'a>( cg: &'a TraceDecay, tool_name: &'a str, args: Value, - server_stats: Option, - scope_prefix: Option<&'a str>, options: ToolCallRegistryOptions<'a>, ) -> std::pin::Pin> + Send + 'a>> { #[cfg(feature = "hotpath")] @@ -609,22 +607,11 @@ pub fn handle_tool_call_with_registry_options<'a>( let dispatched = async { match dispatch_group { Some(McpToolDispatchGroup::Info) => { - boxed_send(dispatch_info_tools( - tool_name, - cg, - args, - server_stats, - scope_prefix, - options, - )) - .await + boxed_send(dispatch_info_tools(tool_name, cg, options)).await } Some(McpToolDispatchGroup::Admin) => { boxed_send(dispatch_admin_tools(tool_name, cg, args, options)).await } - Some(McpToolDispatchGroup::Health) => { - boxed_send(dispatch_health_tools(tool_name, cg, args, options)).await - } // Typed daemon surface tools already returned above, and the daemon // serves the internal branch-add tool before MCP dispatch; reaching // here means the name resolves to no reachable dispatch entry. diff --git a/crates/tracedecay/src/mcp/tools/handlers/retained_timeout_dispatch_tests.rs b/crates/tracedecay/src/mcp/tools/handlers/retained_timeout_dispatch_tests.rs index db9ccbbf74..db6414e9fb 100644 --- a/crates/tracedecay/src/mcp/tools/handlers/retained_timeout_dispatch_tests.rs +++ b/crates/tracedecay/src/mcp/tools/handlers/retained_timeout_dispatch_tests.rs @@ -400,8 +400,6 @@ async fn fact_store_curate_forwards_only_bounds_and_preserves_canonical_success( "min_confidence_millionths": 810_000, "format": "json", }), - None, - None, ToolCallRegistryOptions { application_invocation_executor: Some(&executor), application_request_id: Some(request_id.clone()), @@ -459,8 +457,6 @@ async fn fact_store_curate_expired_deadline_does_not_mutate() { &cg, "tracedecay_fact_store_curate", json!({"fact_review_limit": 5, "min_confidence_millionths": 700_000}), - None, - None, ToolCallRegistryOptions { application_invocation_executor: Some(&executor), application_request_id: Some( @@ -691,8 +687,6 @@ async fn fact_store_curate_rejects_a_partial_receipt_from_another_scope() { &cg, "tracedecay_fact_store_curate", json!({"fact_review_limit": 8, "min_confidence_millionths": 730_000}), - None, - None, ToolCallRegistryOptions { application_invocation_executor: Some(&executor), application_request_id: Some(request_id), @@ -738,8 +732,6 @@ async fn fact_store_curate_pre_commit_cancellation_does_not_mutate() { &cg, "tracedecay_fact_store_curate", json!({"fact_review_limit": 5, "min_confidence_millionths": 700_000}), - None, - None, ToolCallRegistryOptions { application_invocation_executor: Some(&executor), application_request_id: Some( @@ -866,8 +858,6 @@ async fn a_stale_refresh_frontier_reaches_mcp_as_typed_detail() { }, "format": format, }), - None, - None, ToolCallRegistryOptions { application_invocation_executor: Some(&executor), application_request_id: Some( diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/runtime_behavior_test.rs b/crates/tracedecay/src/mcp/tools/handlers/runtime_behavior_dispatch_tests.rs similarity index 80% rename from crates/tracedecay/tests/mcp_suite/mcp_handler_test/runtime_behavior_test.rs rename to crates/tracedecay/src/mcp/tools/handlers/runtime_behavior_dispatch_tests.rs index 4515bab934..29d480161e 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/runtime_behavior_test.rs +++ b/crates/tracedecay/src/mcp/tools/handlers/runtime_behavior_dispatch_tests.rs @@ -1,16 +1,19 @@ -//! Observed `tracedecay_runtime` responses. +//! Observed `tracedecay_runtime` results from the project's graph-tool owner. //! -//! Calls go through the production MCP dispatch (`handle_tool_call`), the -//! same entry the server uses for `tools/call`. Assertions are the JSON a -//! caller reads, not which helpers ran. +//! The owner computes the runtime read from the authorities its server holds; +//! these fixtures hold none beyond the opened project, so every opt-in section +//! reports its typed unattached state. Assertions are the JSON a caller reads, +//! not which helpers ran. +use std::fs; use std::path::{Path, PathBuf}; use std::time::Duration; use serde_json::{Value, json}; -use tracedecay_project::project::TraceDecay; +use tempfile::TempDir; -use crate::support::{extract_json, handle_tool_call, setup_empty_project}; +use super::dispatch_test_support::{SelectorProfile, dispatch_on_graph_authority}; +use super::*; fn with_suffix(path: &Path, suffix: &str) -> PathBuf { let mut name = path.as_os_str().to_owned(); @@ -27,11 +30,38 @@ fn observed_file_len(path: &Path) -> u64 { } async fn runtime_payload(cg: &TraceDecay, args: Value) -> Value { - let result = handle_tool_call(cg, "tracedecay_runtime", args, None, None) - .await - .expect("tracedecay_runtime call"); + let result = dispatch_on_graph_authority( + cg, + "tracedecay_runtime", + args, + ToolCallRegistryOptions::default() + .admit_opened_project(cg) + .expect("opened fixture admits"), + ) + .await + .expect("tracedecay_runtime call"); assert_eq!(result.value["content"][0]["type"], "text"); - extract_json(&result.value) + serde_json::from_str( + result.value["content"][0]["text"] + .as_str() + .expect("runtime JSON text"), + ) + .expect("parse runtime JSON") +} + +async fn runtime_fixture(dir: &TempDir, name: &str) -> TraceDecay { + let profile = SelectorProfile::new(dir.path()); + let project = dir.path().join(name); + fs::create_dir_all(project.join("src")).expect("create fixture source root"); + fs::write(project.join("src/lib.rs"), "pub fn fixture() {}\n").expect("write fixture source"); + let (cg, _runtime) = TraceDecay::init_test_fixture_with_registered_runtime( + profile.data_dir(), + &project, + &format!("project.{name}"), + ) + .await + .expect("open mounted runtime fixture"); + cg } fn assert_unavailable_census(database: &Value) { @@ -49,7 +79,8 @@ fn assert_unavailable_census(database: &Value) { /// not invent doctor, session, or audit sections. #[tokio::test] async fn runtime_reports_this_process_and_the_admitted_store_files() { - let (cg, _env, _dir) = setup_empty_project().await; + let dir = TempDir::new().expect("fixture root"); + let cg = runtime_fixture(&dir, "mcp-runtime-store-files").await; let graph_db = cg.store_layout().graph_db_path.clone(); let dirty = with_suffix(&graph_db, ".dirty"); assert!( @@ -143,7 +174,8 @@ async fn runtime_reports_this_process_and_the_admitted_store_files() { /// Opt-in arguments add one typed section and leave the others off. #[tokio::test] async fn runtime_opt_in_sections_are_exact_typed_payloads() { - let (cg, _env, _dir) = setup_empty_project().await; + let dir = TempDir::new().expect("fixture root"); + let cg = runtime_fixture(&dir, "mcp-runtime-opt-in-sections").await; let baseline = runtime_payload(&cg, json!({ "format": "json" })).await; assert!(baseline.get("doctor_report").is_none()); diff --git a/crates/tracedecay/src/mcp/tools/handlers/runtime_generation_census_dispatch_tests.rs b/crates/tracedecay/src/mcp/tools/handlers/runtime_generation_census_dispatch_tests.rs index b43a1df09c..d01d065434 100644 --- a/crates/tracedecay/src/mcp/tools/handlers/runtime_generation_census_dispatch_tests.rs +++ b/crates/tracedecay/src/mcp/tools/handlers/runtime_generation_census_dispatch_tests.rs @@ -24,12 +24,10 @@ async fn runtime_mcp_marks_missing_generation_census_authority_unavailable() { .await .expect("open v32 mounted runtime fixture"); - let result = handle_tool_call_with_registry_options( + let result = dispatch_on_graph_authority( &cg, "tracedecay_runtime", json!({ "format": "json" }), - None, - None, ToolCallRegistryOptions::default() .admit_opened_project(&cg) .expect("opened fixture admits"), diff --git a/crates/tracedecay/src/test_support/host_admission.rs b/crates/tracedecay/src/test_support/host_admission.rs index cf1157903c..aae84f8cb9 100644 --- a/crates/tracedecay/src/test_support/host_admission.rs +++ b/crates/tracedecay/src/test_support/host_admission.rs @@ -2,57 +2,16 @@ //! //! The runtime itself, registered databases, session registry, and the //! project-graph opens through it, lives in `tracedecay-project`; this -//! module adds the pieces that need the root's MCP server: tool calls through the registry-aware dispatcher and direct -//! server construction contexts. +//! module adds the direct MCP server construction context that needs the +//! root's MCP server. -#[cfg(any(test, feature = "test-transport"))] use std::sync::Arc; -use tracedecay_domain::errors::Result; -#[cfg(any(test, feature = "test-transport"))] -use tracedecay_domain::errors::TraceDecayError; +use tracedecay_domain::errors::{Result, TraceDecayError}; use tracedecay_sessions::admission::HostAdmissionScope; -use tracedecay_project::test_support::host_admission::HostAdmissionTestRuntimeV1; - -use tracedecay_mcp::handlers::mcp_session_authorities; use tracedecay_project::project::TraceDecay; - -/// Calls one MCP tool through the registry-aware dispatcher with this -/// runtime's registered databases as the tool's authorities. -#[doc(hidden)] -pub async fn call_mcp_tool_for_test( - runtime: &HostAdmissionTestRuntimeV1, - cg: &TraceDecay, - tool_name: &str, - arguments: serde_json::Value, - server_stats: Option, - scope_prefix: Option<&str>, -) -> Result { - let profile_database = runtime.profile_database_lease(); - let project_registry_reads = - tracedecay_daemon_service::DaemonProjectRegistryReadService::new(profile_database.clone()); - crate::mcp::tools::handle_tool_call_with_registry_options( - cg, - tool_name, - arguments, - server_stats, - scope_prefix, - crate::mcp::tools::ToolCallRegistryOptions { - global_db: Some(profile_database), - project_registry_reads: Some(&project_registry_reads), - accounting_db: Some(profile_database.as_ref()), - registered_project_session_db: runtime - .registered_database_arc(HostAdmissionScope::Project), - registered_savings_db: Some(profile_database.clone()), - profile: Some(&test_runtime_profile(runtime)), - session_authorities: mcp_session_authorities(runtime), - ..Default::default() - } - .admit_opened_project(cg)?, - ) - .await -} +use tracedecay_project::test_support::host_admission::HostAdmissionTestRuntimeV1; /// The owner a test runtime serves: its profile, with the profile's parent as /// the home its host transcripts live under. @@ -69,7 +28,6 @@ fn test_runtime_profile( /// A direct MCP server construction context bound to this runtime's /// registered databases, profile identity, and background CPU authority. -#[cfg(any(test, feature = "test-transport"))] pub(crate) fn mcp_server_context_for_test( runtime: Arc, cg: TraceDecay, diff --git a/crates/tracedecay/src/test_support/mod.rs b/crates/tracedecay/src/test_support/mod.rs index a7933aab93..e4d3be786b 100644 --- a/crates/tracedecay/src/test_support/mod.rs +++ b/crates/tracedecay/src/test_support/mod.rs @@ -2,4 +2,5 @@ //! `test-helpers`, never into a default or `production` library build. pub mod git; +#[cfg(any(test, feature = "test-transport"))] pub mod host_admission; diff --git a/crates/tracedecay/tests/mcp_suite/mcp_cli_serve_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_cli_serve_test.rs index 7c6c260055..cacab10c15 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_cli_serve_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_cli_serve_test.rs @@ -915,15 +915,9 @@ async fn explicit_read_only_open_reports_and_guards_read_only_store() { .await .expect("current-schema read-only DB should open explicitly"); - let status = handle_tool_call( - &cg, - "tracedecay_storage_status", - json!({"format": "json"}), - None, - None, - ) - .await - .unwrap(); + let status = handle_tool_call(&cg, "tracedecay_storage_status", json!({"format": "json"})) + .await + .unwrap(); let payload: Value = serde_json::from_str(extract_tool_text(&status.value)).unwrap(); // Plan 21 moved storage_status onto the daemon-retained typed primitive // owner. Without a live daemon transport this in-process harness receives diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_handler_test.rs index d4c200b07b..2c27f29dd6 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_handler_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_handler_test.rs @@ -82,6 +82,7 @@ mod hermes_skill_bridge_test; mod impact_behavior_test; mod implementations_test; mod info_file_request_test; +mod info_health_request_test; mod inheritance_depth_test; #[cfg(feature = "test-transport")] mod insert_at_test; @@ -134,7 +135,6 @@ mod rename_symbol_test; #[cfg(feature = "test-transport")] mod replace_symbol_test; mod retrieve_truncation_test; -mod runtime_behavior_test; mod schema_test; mod search_behavior_test; mod session_refresh_begin_test; diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/admin_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/admin_test.rs index db452ddaa8..6a3caf5cee 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/admin_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/admin_test.rs @@ -16,13 +16,21 @@ async fn project_registry_tools_are_bounded_read_only_and_contextual() { let registry_path = registry_dir.path().join("global.db"); let seeded_project_root = registry_dir.path().join("registered-alpha-project"); fs::create_dir_all(&seeded_project_root).unwrap(); - let registry_runtime = seed_project_registry(®istry_path, &seeded_project_root).await; + drop(seed_project_registry(®istry_path, &seeded_project_root).await); let active_project_id = cg .store_layout() .identity .project_id .clone() .expect("active project identity"); + let registry_runtime = HostAdmissionTestRuntimeV1::project_scoped( + registry_dir.path(), + cg.project_root(), + tracedecay_domain::ProjectId::new(active_project_id.clone()) + .expect("test project identity"), + ) + .await + .unwrap(); registry_runtime .upsert_code_project( &active_project_id, @@ -33,18 +41,26 @@ async fn project_registry_tools_are_bounded_read_only_and_contextual() { ) .await .unwrap(); + let server = tracedecay::mcp::McpServer::new_with_host_admission_test_runtime_for_test( + tracedecay_project::project::TraceDecay::open_with_options( + cg.project_root(), + crate::support::graph_open_options(&cg), + ) + .await + .unwrap(), + None, + registry_runtime, + ) + .await + .expect("registered test server"); - let list = handle_tool_call_with_runtime( - &cg, - ®istry_runtime, + let list = handle_real_server_tool_call( + &server, "tracedecay_project_list", json!({"limit": 1, "format": "json"}), - None, - None, ) - .await - .unwrap(); - let list_payload: Value = serde_json::from_str(extract_text(&list.value)).unwrap(); + .await; + let list_payload: Value = serde_json::from_str(extract_real_server_text(&list)).unwrap(); assert_eq!(list_payload["projects"].as_array().unwrap().len(), 1); assert_eq!(list_payload["limit"], 1); assert_eq!(list_payload["truncated"], true); @@ -57,39 +73,31 @@ async fn project_registry_tools_are_bounded_read_only_and_contextual() { ) || list_payload["projects"][0]["project_id"] == active_project_id, "the bounded list must return one registered project: {list_payload}" ); - let list_text = extract_text(&list.value); + let list_text = extract_real_server_text(&list); assert!( !list_text.contains("secret") && !list_text.contains("git_remote_url"), "project list must not expose credential-bearing remotes: {list_text}" ); - let list_markdown = handle_tool_call_with_runtime( - &cg, - ®istry_runtime, + let list_markdown = handle_real_server_tool_call( + &server, "tracedecay_project_list", json!({"limit": 2, "format": "markdown"}), - None, - None, ) - .await - .unwrap(); - let list_markdown_text = extract_text(&list_markdown.value); + .await; + let list_markdown_text = extract_real_server_text(&list_markdown); assert!( list_markdown_text.contains("Repositories") && list_markdown_text.contains("branches: main"), "project list should render compact grouped markdown: {list_markdown_text}" ); - let search = handle_tool_call_with_runtime( - &cg, - ®istry_runtime, + let search = handle_real_server_tool_call( + &server, "tracedecay_project_search", json!({"query": "alpha", "limit": 10, "format": "json"}), - None, - None, ) - .await - .unwrap(); - let search_payload: Value = serde_json::from_str(extract_text(&search.value)).unwrap(); + .await; + let search_payload: Value = serde_json::from_str(extract_real_server_text(&search)).unwrap(); let search_projects = search_payload["projects"].as_array().unwrap(); assert_eq!(search_projects.len(), 1); assert_eq!(search_projects[0]["project_id"], "proj_alpha"); @@ -98,24 +106,20 @@ async fn project_registry_tools_are_bounded_read_only_and_contextual() { "a separately registered project must not be marked active: {search_payload}" ); assert_eq!(search_payload["project_tree"].as_array().unwrap().len(), 1); - let search_text = extract_text(&search.value); + let search_text = extract_real_server_text(&search); assert!( !search_text.contains("secret") && !search_text.contains("git_remote_url"), "project search must not expose credential-bearing remotes: {search_text}" ); - let multi_term_search = handle_tool_call_with_runtime( - &cg, - ®istry_runtime, + let multi_term_search = handle_real_server_tool_call( + &server, "tracedecay_project_search", json!({"query": "alpha beta", "limit": 10, "format": "json"}), - None, - None, ) - .await - .unwrap(); + .await; let multi_term_payload: Value = - serde_json::from_str(extract_text(&multi_term_search.value)).unwrap(); + serde_json::from_str(extract_real_server_text(&multi_term_search)).unwrap(); let multi_term_ids: Vec<&str> = multi_term_payload["projects"] .as_array() .unwrap() @@ -127,35 +131,27 @@ async fn project_registry_tools_are_bounded_read_only_and_contextual() { "multi-term project search should match either term: {multi_term_payload}" ); - let remote_secret_search = handle_tool_call_with_runtime( - &cg, - ®istry_runtime, + let remote_secret_search = handle_real_server_tool_call( + &server, "tracedecay_project_search", json!({"query": "secret", "limit": 10, "format": "json"}), - None, - None, ) - .await - .unwrap(); + .await; let remote_secret_payload: Value = - serde_json::from_str(extract_text(&remote_secret_search.value)).unwrap(); + serde_json::from_str(extract_real_server_text(&remote_secret_search)).unwrap(); assert_eq!( remote_secret_payload["projects"].as_array().unwrap().len(), 0, "project search must not match credential-bearing remote URL text: {remote_secret_payload}" ); - let context = handle_tool_call_with_runtime( - &cg, - ®istry_runtime, + let context = handle_real_server_tool_call( + &server, "tracedecay_project_context", json!({"project_selector": {"project_id": active_project_id}, "format": "json"}), - None, - None, ) - .await - .unwrap(); - let context_payload: Value = serde_json::from_str(extract_text(&context.value)).unwrap(); + .await; + let context_payload: Value = serde_json::from_str(extract_real_server_text(&context)).unwrap(); assert_eq!(context_payload["project"]["project_id"], active_project_id); assert_eq!( context_payload["is_active"], true, @@ -165,23 +161,19 @@ async fn project_registry_tools_are_bounded_read_only_and_contextual() { context_payload["project"]["is_active"], true, "the nested project record must also carry is_active: {context_payload}" ); - let context_text = extract_text(&context.value); + let context_text = extract_real_server_text(&context); assert!( !context_text.contains("secret") && !context_text.contains("git_remote_url"), "project context must not expose credential-bearing remotes: {context_text}" ); - let seeded_context = handle_tool_call_with_runtime( - &cg, - ®istry_runtime, + let seeded_context = handle_real_server_tool_call( + &server, "tracedecay_project_context", json!({"project_selector": {"project_id": "proj_alpha"}, "format": "json"}), - None, - None, ) - .await - .unwrap(); + .await; let seeded_context_payload: Value = - serde_json::from_str(extract_text(&seeded_context.value)).unwrap(); + serde_json::from_str(extract_real_server_text(&seeded_context)).unwrap(); assert_eq!( seeded_context_payload["stores"].as_array().unwrap().len(), 1 @@ -195,17 +187,14 @@ async fn project_registry_tools_are_bounded_read_only_and_contextual() { "graph_db" ); - let alias_context = handle_tool_call_with_runtime( - &cg, - ®istry_runtime, + let alias_context = handle_real_server_tool_call( + &server, "tracedecay_project_context", json!({"path": "registered-alias", "format": "json"}), - None, - None, ) - .await - .unwrap(); - let alias_payload: Value = serde_json::from_str(extract_text(&alias_context.value)).unwrap(); + .await; + let alias_payload: Value = + serde_json::from_str(extract_real_server_text(&alias_context)).unwrap(); assert_eq!(alias_payload["status"], "ok"); assert_eq!(alias_payload["project"]["project_id"], "proj_alpha"); assert_eq!( @@ -213,82 +202,18 @@ async fn project_registry_tools_are_bounded_read_only_and_contextual() { seeded_project_root.to_string_lossy().as_ref() ); - let unknown_alias = handle_tool_call_with_runtime( - &cg, - ®istry_runtime, + let unknown_alias = handle_real_server_tool_call( + &server, "tracedecay_project_context", json!({"path": "unknown-alias", "format": "json"}), - None, - None, ) - .await - .unwrap(); - let unknown_payload: Value = serde_json::from_str(extract_text(&unknown_alias.value)).unwrap(); + .await; + let unknown_payload: Value = + serde_json::from_str(extract_real_server_text(&unknown_alias)).unwrap(); assert_eq!(unknown_payload["status"], "not_found"); assert!(unknown_payload["project"].is_null()); } -/// When no project registry authority is mounted for the profile, all three -/// registry tools report `unavailable`. List and search still return the same -/// top-level keys as the ok-shape (`title`, `summary`, `project_tree`) with -/// zeroed/empty values, so callers can rely on a stable payload shape without -/// mistaking the unavailable authority for an authoritative empty result. -#[tokio::test] -async fn project_registry_tools_missing_registry_carries_stable_shape() { - let (cg, _env, _dir) = setup_empty_project().await; - - let list = handle_tool_call( - &cg, - "tracedecay_project_list", - json!({"format": "json"}), - None, - None, - ) - .await - .unwrap(); - let list_payload: Value = serde_json::from_str(extract_text(&list.value)).unwrap(); - assert_eq!(list_payload["status"], "unavailable"); - assert_eq!(list_payload["title"], "registered projects"); - assert_eq!(list_payload["summary"]["project_count"], 0); - assert_eq!(list_payload["summary"]["repo_count"], 0); - assert_eq!(list_payload["summary"]["truncated"], false); - assert_eq!(list_payload["project_tree"].as_array().unwrap().len(), 0); - assert_eq!(list_payload["projects"].as_array().unwrap().len(), 0); - - let search = handle_tool_call( - &cg, - "tracedecay_project_search", - json!({"query": "alpha", "format": "json"}), - None, - None, - ) - .await - .unwrap(); - let search_payload: Value = serde_json::from_str(extract_text(&search.value)).unwrap(); - assert_eq!(search_payload["status"], "unavailable"); - assert_eq!(search_payload["title"], "projects matching \"alpha\""); - assert_eq!(search_payload["summary"]["project_count"], 0); - assert_eq!(search_payload["summary"]["repo_count"], 0); - assert_eq!(search_payload["summary"]["truncated"], false); - assert_eq!(search_payload["project_tree"].as_array().unwrap().len(), 0); - assert_eq!(search_payload["projects"].as_array().unwrap().len(), 0); - - let context = handle_tool_call( - &cg, - "tracedecay_project_context", - json!({"project_selector": {"project_id": "project.missing"}, "format": "json"}), - None, - None, - ) - .await - .unwrap(); - let context_payload: Value = serde_json::from_str(extract_text(&context.value)).unwrap(); - assert_eq!( - context_payload["status"], "unavailable", - "an unmounted profile registry is not an authoritative not-found answer" - ); -} - #[cfg(feature = "test-transport")] #[tokio::test] async fn project_context_surfaces_registry_read_failure_as_tool_error() { @@ -344,12 +269,13 @@ async fn project_context_surfaces_registry_read_failure_as_tool_error() { ) .await; - let message = response["error"]["message"] - .as_str() - .unwrap_or_else(|| panic!("registry read failure should surface as an error: {response}")); - assert!( - message.contains("resolve project identity alias") || message.contains("project_aliases"), - "{message}" + assert_eq!( + crate::support::tool_refusal(&response), + json!({ + "kind": "unavailable", + "code": "graph_tool.failed", + "message": "database error: SQLite prepare query failed: no such table: project_aliases (operation: resolve project identity alias)", + }) ); } @@ -404,12 +330,14 @@ async fn project_search_surfaces_registry_read_failure_as_tool_error() { ) .await; - let message = response["error"]["message"].as_str().unwrap_or_else(|| { - panic!("registry read failure must not become a successful empty search: {response}") - }); - assert!( - message.contains("search code projects") || message.contains("project_aliases"), - "{message}" + // A registry read failure never becomes a successful empty search. + assert_eq!( + crate::support::tool_refusal(&response), + json!({ + "kind": "unavailable", + "code": "graph_tool.failed", + "message": "database error: SQLite prepare query failed: no such table: project_aliases (operation: search registered code projects)", + }) ); } diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/edit_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/edit_test.rs index 2909402ae2..b4e619b755 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/edit_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/edit_test.rs @@ -47,7 +47,6 @@ async fn source_edit_preview_apply_and_retry_use_daemon_owned_cas_authority() { "dry_run": true }), None, - None, ) .await .unwrap(); @@ -62,15 +61,9 @@ async fn source_edit_preview_apply_and_retry_use_daemon_owned_cas_authority() { "idempotency_key": "mcp-test.source-edit.exact-retry", "expected_state": expected_state }); - let first = handle_tool_call( - &cg, - "tracedecay_str_replace", - apply_args.clone(), - None, - None, - ) - .await - .unwrap(); + let first = handle_tool_call(&cg, "tracedecay_str_replace", apply_args.clone(), None) + .await + .unwrap(); let first: Value = serde_json::from_str(extract_text(&first.value)).unwrap(); assert_eq!(first["success"], true); assert_eq!(first["replayed"], false); @@ -85,7 +78,7 @@ async fn source_edit_preview_apply_and_retry_use_daemon_owned_cas_authority() { assert!(first["effect"]["receipt"]["committed_state"].is_string()); assert_eq!(fs::read(project.join("src/main.rs")).unwrap(), applied); - let retry = handle_tool_call(&cg, "tracedecay_str_replace", apply_args, None, None) + let retry = handle_tool_call(&cg, "tracedecay_str_replace", apply_args, None) .await .unwrap(); let retry: Value = serde_json::from_str(extract_text(&retry.value)).unwrap(); @@ -105,7 +98,6 @@ async fn source_edit_preview_apply_and_retry_use_daemon_owned_cas_authority() { "dry_run": true }), None, - None, ) .await .unwrap(); @@ -124,7 +116,6 @@ async fn source_edit_preview_apply_and_retry_use_daemon_owned_cas_authority() { "expected_state": stale_expected_state }), None, - None, ) .await .unwrap(); @@ -160,7 +151,6 @@ async fn path_containment_config_rejects_parent_traversal_before_serving_config( "tracedecay_config", json!({"path": "../outside.toml", "key": "token"}), None, - None, ) .await; @@ -197,7 +187,6 @@ async fn path_containment_config_rejects_symlink_escape_before_serving_config() "tracedecay_config", json!({"path": "escape/secret.toml", "key": "token"}), None, - None, ) .await; @@ -220,7 +209,6 @@ async fn project_selector_is_rejected_before_write_tool_parsing() { "tracedecay_str_replace", json!({"project_selector": {"include_all_registered": true}}), None, - None, ) .await; let message = expect_tool_error(result); @@ -251,7 +239,6 @@ async fn test_str_replace_not_found() { "new_str": "fn replaced() {}" }), None, - None, ) .await .unwrap(); @@ -282,7 +269,6 @@ async fn test_str_replace_multiple_matches_fails() { "new_str": "fn bar() {}" }), None, - None, ) .await .unwrap(); @@ -320,7 +306,6 @@ async fn test_multi_str_replace_atomic_failure() { ] }), None, - None, ) .await .unwrap(); @@ -364,7 +349,6 @@ async fn test_multi_str_replace_unicode_preview_does_not_panic() { ] }), None, - None, ) .await .unwrap(); @@ -413,7 +397,6 @@ async fn test_multi_str_replace_earlier_insertion_collision_lands_correctly() { ] }), None, - None, ) .await .unwrap(); @@ -457,7 +440,6 @@ async fn test_multi_str_replace_overlapping_ranges_error() { ] }), None, - None, ) .await .unwrap(); @@ -506,7 +488,6 @@ async fn test_replace_symbol_documented_fn_keeps_single_doc_comment() { "new_source": "/// Doc for foo.\nfn foo() {\n let _ = 2;\n}" }), None, - None, ) .await .unwrap(); @@ -557,7 +538,6 @@ async fn test_insert_at_symbol_before_lands_above_attribute() { "position": "before" }), None, - None, ) .await .unwrap(); @@ -608,7 +588,6 @@ async fn test_str_replace_unsupported_file_type_succeeds() { "new_str": "\tfont-size: 0.85rem;" }), None, - None, ) .await .unwrap(); @@ -646,7 +625,6 @@ async fn ast_grep_rewrite_has_literal_fallback_when_binary_missing() { "tracedecay_ast_grep_rewrite", json!({"path": "src/lib.rs", "pattern": "old_name", "rewrite": "new_name"}), None, - None, ) .await .unwrap(); @@ -682,7 +660,6 @@ async fn ast_grep_rewrite_uses_current_cli_update_flag() { "tracedecay_ast_grep_rewrite", json!({"path": "src/lib.rs", "pattern": "old_name()", "rewrite": "new_name()"}), None, - None, ) .await .unwrap(); @@ -729,7 +706,6 @@ async fn ast_grep_rewrite_surfaces_useful_error_on_empty_stderr() { "rewrite": "whatever" }), None, - None, ) .await .unwrap(); @@ -785,7 +761,6 @@ async fn test_multi_str_replace_unsupported_file_type_succeeds() { ] }), None, - None, ) .await .unwrap(); @@ -836,7 +811,6 @@ async fn test_insert_at_string_anchor_before() { "dry_run": true }), None, - None, ) .await .unwrap(); @@ -856,7 +830,6 @@ async fn test_insert_at_string_anchor_before() { "expected_state": expected_state }), None, - None, ) .await .unwrap(); @@ -890,7 +863,6 @@ async fn test_insert_at_line_number() { "before": false }), None, - None, ) .await .unwrap(); @@ -933,7 +905,6 @@ async fn test_insert_at_anchor_not_found() { "before": true }), None, - None, ) .await .unwrap(); @@ -967,7 +938,6 @@ async fn test_insert_at_unicode_anchor_prefix_does_not_panic() { "before": true }), None, - None, ) .await .unwrap(); @@ -1006,7 +976,6 @@ async fn test_insert_at_ambiguous_anchor() { "before": true }), None, - None, ) .await .unwrap(); diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/graph_analysis_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/graph_analysis_test.rs index 8de71c78aa..3b9174a529 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/graph_analysis_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/graph_analysis_test.rs @@ -23,7 +23,6 @@ trait AnalysisToolHost { &self, tool_name: &str, arguments: Value, - server_stats: Option, scope_prefix: Option<&str>, ) -> TraceDecayResult; @@ -64,7 +63,6 @@ impl AnalysisToolHost for ProductionCompositionFixture { &self, tool_name: &str, arguments: Value, - _server_stats: Option, _scope_prefix: Option<&str>, ) -> TraceDecayResult { call_production_tool(&self.harness, &self.project_root, tool_name, arguments).await @@ -80,7 +78,6 @@ impl AnalysisToolHost for MountedProductionProject { &self, tool_name: &str, arguments: Value, - _server_stats: Option, _scope_prefix: Option<&str>, ) -> TraceDecayResult { call_production_tool(&self.harness, &self.project_root, tool_name, arguments).await @@ -96,11 +93,9 @@ impl AnalysisToolHost for TestTraceDecay { &self, tool_name: &str, arguments: Value, - server_stats: Option, scope_prefix: Option<&str>, ) -> TraceDecayResult { - crate::support::handle_tool_call(self, tool_name, arguments, server_stats, scope_prefix) - .await + crate::support::handle_tool_call(self, tool_name, arguments, scope_prefix).await } async fn close_analysis_host(self) { @@ -112,10 +107,9 @@ async fn handle_tool_call( host: &impl AnalysisToolHost, tool_name: &str, arguments: Value, - server_stats: Option, scope_prefix: Option<&str>, ) -> TraceDecayResult { - host.call_analysis_tool(tool_name, arguments, server_stats, scope_prefix) + host.call_analysis_tool(tool_name, arguments, scope_prefix) .await } @@ -332,7 +326,6 @@ pub fn recovered() -> BuildOptions { "tracedecay_constructors", json!({"struct": "BuildOptions"}), None, - None, ) .await .unwrap(); @@ -394,7 +387,6 @@ pub mod second { "tracedecay_constructors", json!({"struct": "Options"}), None, - None, ) .await .unwrap(); @@ -461,7 +453,6 @@ export default defineConfig({ "tracedecay_unmounted_files", json!({"ecosystem": "typescript"}), None, - None, ) .await .unwrap(); @@ -511,15 +502,31 @@ async fn test_branch_list_reports_live_vs_serving_drift_state() { .await .unwrap(), ); + // The serving server opens on `main`; the checkout moves under it. + let server = Box::pin( + tracedecay::mcp::McpServer::new_with_host_admission_test_runtime_for_test( + TraceDecay::open_with_options(project, graph_open_options(&cg)) + .await + .unwrap(), + None, + open_active_project_scoped_runtime(&cg).await, + ), + ) + .await + .unwrap(); git_run(project, &["checkout", "-b", "feature"]); // Branch drift diagnostics moved off `tracedecay_branch_list` (now the // paginated branch-ref snapshot read) to the active-project context's // `branch` block. - let result = handle_tool_call(&cg, "tracedecay_active_project", json!({}), None, None) - .await - .unwrap(); - let report: Value = serde_json::from_str(extract_text(&result.value)).unwrap(); + let result = handle_real_server_tool_call( + &server, + "tracedecay_active_project", + json!({"format": "json"}), + ) + .await; + server.shutdown().await; + let report: Value = serde_json::from_str(extract_real_server_text(&result)).unwrap(); let branch = &report["branch"]; assert_eq!(branch["current_branch"], json!("feature")); assert_eq!(branch["open_active_branch"], json!("main")); @@ -547,7 +554,7 @@ async fn test_dead_code() { let cg = production_composition_fixture().await; let _populated = find_node_id(&cg, "format_greeting").await; - let result = handle_tool_call(&cg, "tracedecay_dead_code", json!({}), None, None) + let result = handle_tool_call(&cg, "tracedecay_dead_code", json!({}), None) .await .unwrap(); let payload = extract_json(&result.value); @@ -578,7 +585,6 @@ async fn test_diff_context() { "tracedecay_diff_context", json!({"files": ["src/utils.rs"]}), None, - None, ) .await .unwrap(); @@ -632,7 +638,7 @@ async fn test_circular() { let cg = production_composition_fixture().await; let _populated = find_node_id(&cg, "helper").await; - let result = handle_tool_call(&cg, "tracedecay_circular", json!({}), None, None) + let result = handle_tool_call(&cg, "tracedecay_circular", json!({}), None) .await .unwrap(); let payload = extract_json(&result.value); @@ -659,7 +665,6 @@ async fn test_rename_preview() { "tracedecay_rename_preview", json!({"node_id": node_id}), None, - None, ) .await .unwrap(); @@ -712,7 +717,7 @@ async fn test_recursion() { let cg = production_composition_fixture().await; let _populated = find_node_id(&cg, "format_greeting").await; - let result = handle_tool_call(&cg, "tracedecay_recursion", json!({}), None, None) + let result = handle_tool_call(&cg, "tracedecay_recursion", json!({}), None) .await .unwrap(); let payload = extract_json(&result.value); @@ -741,7 +746,6 @@ async fn test_changelog_no_git() { "tracedecay_changelog", json!({"from_ref": "HEAD~1", "to_ref": "HEAD"}), None, - None, ) .await .unwrap(); @@ -767,7 +771,6 @@ async fn pr_context_no_git_returns_structured_git_error() { "tracedecay_pr_context", json!({"base_ref": "HEAD~1", "head_ref": "HEAD"}), None, - None, ) .await .unwrap(); @@ -787,7 +790,6 @@ async fn test_port_status() { "tracedecay_port_status", json!({"source_dir": "src", "target_dir": "tests"}), None, - None, ) .await .unwrap(); @@ -874,7 +876,6 @@ async fn port_status_does_not_match_methods_of_different_parents() { "kinds": ["method"], }), None, - None, ) .await .unwrap(); @@ -933,7 +934,6 @@ async fn port_status_matches_methods_with_same_parent_type() { "kinds": ["method"], }), None, - None, ) .await .unwrap(); @@ -956,7 +956,6 @@ async fn test_port_order() { "tracedecay_port_order", json!({"source_dir": "src"}), None, - None, ) .await .unwrap(); @@ -1035,7 +1034,6 @@ async fn port_order_sorts_a_tied_level_before_applying_the_limit() { "tracedecay_port_order", json!({"source_dir": "src", "kinds": ["function"], "limit": 2}), None, - None, ) .await .unwrap(); @@ -1059,7 +1057,6 @@ async fn test_rename_preview_not_found() { "tracedecay_rename_preview", json!({"node_id": "nonexistent_id_12345"}), None, - None, ) .await .unwrap(); @@ -1098,7 +1095,6 @@ async fn commit_context_clean_worktree_returns_json() { "tracedecay_commit_context", json!({"format": "json"}), None, - None, ) .await .unwrap(); @@ -1152,7 +1148,6 @@ async fn commit_context_staged_source_and_test_reports_symbols() { "tracedecay_commit_context", json!({"format": "json"}), None, - None, ) .await .unwrap(); @@ -1214,7 +1209,6 @@ async fn commit_context_config_and_docs_report_chore() { "tracedecay_commit_context", json!({"format": "json"}), None, - None, ) .await .unwrap(); @@ -1277,7 +1271,6 @@ async fn commit_context_staged_only_excludes_unstaged_file() { "tracedecay_commit_context", json!({"format": "json", "staged_only": true}), None, - None, ) .await .unwrap(); @@ -1286,7 +1279,6 @@ async fn commit_context_staged_only_excludes_unstaged_file() { "tracedecay_commit_context", json!({"format": "json", "staged_only": false}), None, - None, ) .await .unwrap(); @@ -1355,7 +1347,6 @@ async fn commit_context_unborn_head_is_git_status_error() { "tracedecay_commit_context", json!({"format": "json"}), None, - None, ) .await .unwrap(); @@ -1435,7 +1426,6 @@ async fn test_changelog_with_real_git() { "tracedecay_changelog", json!({"from_ref": "HEAD~1", "to_ref": "HEAD"}), None, - None, ) .await .unwrap(); @@ -1470,15 +1460,9 @@ async fn test_changelog_with_real_git() { #[tokio::test] async fn test_health_detailed_includes_raw_signals() { let cg = production_composition_fixture().await; - let result = handle_tool_call( - &cg, - "tracedecay_health", - json!({ "details": true }), - None, - None, - ) - .await - .unwrap(); + let result = handle_tool_call(&cg, "tracedecay_health", json!({ "details": true }), None) + .await + .unwrap(); let text = extract_text(&result.value); let parsed: serde_json::Value = serde_json::from_str(text).unwrap(); let dims = parsed.get("dimensions").expect("dimensions should exist"); @@ -1539,7 +1523,7 @@ fn write_dsm_coupling_sources(project: &Path) { } async fn call_dsm(host: &ProductionCompositionFixture, args: Value) -> String { - let result = handle_tool_call(host, "tracedecay_dsm", args, None, None) + let result = handle_tool_call(host, "tracedecay_dsm", args, None) .await .unwrap_or_else(|error| panic!("tracedecay_dsm failed over production MCP: {error}")); extract_text(&result.value).to_owned() @@ -1694,7 +1678,6 @@ async fn test_dsm_reports_authored_file_dependencies() { "tracedecay_dsm", json!({ "format": "json", "shape": "layers" }), None, - None, ) .await; assert_refusal_problem( @@ -1790,15 +1773,9 @@ _No dependency clusters found._ #[tokio::test] async fn test_test_risk() { let cg = production_composition_fixture().await; - let result = handle_tool_call( - &cg, - "tracedecay_test_risk", - json!({ "limit": 10 }), - None, - None, - ) - .await - .unwrap(); + let result = handle_tool_call(&cg, "tracedecay_test_risk", json!({ "limit": 10 }), None) + .await + .unwrap(); let text = extract_text(&result.value); let parsed: serde_json::Value = serde_json::from_str(text).unwrap(); let summary = parsed.get("summary").expect("summary should exist"); @@ -1836,7 +1813,6 @@ async fn test_test_risk_distinguishes_direct_and_closure_attribution() { "tracedecay_test_risk", json!({ "limit": 10, "include_tested": true }), None, - None, ) .await .unwrap(); @@ -1916,7 +1892,6 @@ async fn test_test_risk_scopes_workspace_source_before_following_external_test_c "include_tested": true }), None, - None, ) .await .unwrap(); @@ -1942,7 +1917,6 @@ async fn test_test_risk_attributes_ts_describe_it_tests() { "tracedecay_test_risk", json!({ "limit": 10, "include_tested": true }), None, - None, ) .await .unwrap(); @@ -1982,7 +1956,6 @@ async fn test_test_map_lists_ts_it_title_as_covering_test() { "tracedecay_test_map", json!({ "file": "src/math.ts" }), None, - None, ) .await .unwrap(); @@ -2012,7 +1985,6 @@ async fn test_test_risk_excludes_non_src_functions_from_denominator_and_risks() "tracedecay_test_risk", json!({ "limit": 10, "include_tested": true }), None, - None, ) .await .unwrap(); @@ -2077,7 +2049,7 @@ fn helper() { let cg = init_test_project(project).await; wait_for_current_graph(&cg).await; - let result = handle_tool_call(&cg, "tracedecay_todos", json!({}), None, None) + let result = handle_tool_call(&cg, "tracedecay_todos", json!({}), None) .await .unwrap(); let text = extract_text(&result.value); @@ -2125,15 +2097,9 @@ fn main() { .unwrap(); let cg = init_test_project(project).await; - let result = handle_tool_call( - &cg, - "tracedecay_todos", - json!({"kinds": ["FIXME"]}), - None, - None, - ) - .await - .unwrap(); + let result = handle_tool_call(&cg, "tracedecay_todos", json!({"kinds": ["FIXME"]}), None) + .await + .unwrap(); let text = extract_text(&result.value); let output: Value = serde_json::from_str(text).unwrap(); assert_eq!(output["match_count"].as_u64().unwrap(), 1); @@ -2169,7 +2135,6 @@ pub fn second() { dep::shared(); } "tracedecay_diff_context", json!({"files": ["src/lib.rs"], "depth": 3}), None, - None, ) .await .unwrap(); @@ -2202,7 +2167,7 @@ async fn recursion_keeps_direct_recursion() { ) .unwrap(); let cg = init_test_project(project).await; - let result = handle_tool_call(&cg, "tracedecay_recursion", json!({}), None, None) + let result = handle_tool_call(&cg, "tracedecay_recursion", json!({}), None) .await .unwrap(); let output = extract_json(&result.value); @@ -2236,7 +2201,7 @@ async fn recursion_filters_self_edge_artifacts() { ) .unwrap(); let cg = init_test_project(project).await; - let result = handle_tool_call(&cg, "tracedecay_recursion", json!({}), None, None) + let result = handle_tool_call(&cg, "tracedecay_recursion", json!({}), None) .await .unwrap(); let output = extract_json(&result.value); @@ -2274,7 +2239,7 @@ pub fn c() { a(); } ) .unwrap(); let cg = init_test_project(project).await; - let result = handle_tool_call(&cg, "tracedecay_recursion", json!({}), None, None) + let result = handle_tool_call(&cg, "tracedecay_recursion", json!({}), None) .await .unwrap(); let output = extract_json(&result.value); @@ -2329,7 +2294,6 @@ async fn changelog_filters_directory_paths() { "tracedecay_changelog", json!({"from_ref": "HEAD~1", "to_ref": "HEAD"}), None, - None, ) .await .unwrap(); @@ -2371,7 +2335,7 @@ pub fn caller() { called(); } .unwrap(); let cg = init_test_project(project).await; - let default_result = handle_tool_call(&cg, "tracedecay_dead_code", json!({}), None, None) + let default_result = handle_tool_call(&cg, "tracedecay_dead_code", json!({}), None) .await .unwrap(); let default_text = extract_text(&default_result.value); @@ -2387,7 +2351,6 @@ pub fn caller() { called(); } "tracedecay_dead_code", json!({"include_public": true}), None, - None, ) .await .unwrap(); @@ -2437,7 +2400,6 @@ async fn diagnose_normalizes_absolute_and_backslash_paths() { "tracedecay_diagnose", json!({"cargo_output": cargo_output, "include_callers": true}), None, - None, ) .await .unwrap(); @@ -2497,7 +2459,6 @@ pub fn helper() {} "tracedecay_callees", json!({"node_id": caller_id, "maximum_depth": 1, "resolve_trait_dispatch": false}), None, - None, ) .await .unwrap(); @@ -2559,7 +2520,6 @@ impl Default for B { fn default() -> Self { B } } "tracedecay_rank", json!({"edge_kind": "implements", "direction": "incoming", "limit": 100}), None, - None, ) .await .unwrap(); @@ -2613,7 +2573,7 @@ async fn circular_reports_one_entry_per_scc_not_per_walk() { ) .unwrap(); let cg = init_test_project(project).await; - let result = handle_tool_call(&cg, "tracedecay_circular", json!({}), None, None) + let result = handle_tool_call(&cg, "tracedecay_circular", json!({}), None) .await .unwrap(); let text = extract_text(&result.value); @@ -2669,7 +2629,6 @@ pub fn leaf() {} "tracedecay_port_order", json!({"source_dir": "src"}), None, - None, ) .await .unwrap(); @@ -2731,7 +2690,6 @@ pub fn h() { a(); } "tracedecay_port_order", json!({"source_dir": "src"}), None, - None, ) .await .unwrap(); @@ -2809,7 +2767,6 @@ impl Triplet { "tracedecay_port_order", json!({"source_dir": "src"}), None, - None, ) .await .unwrap(); @@ -2841,7 +2798,7 @@ pub trait Leaf: Middle {} ) .unwrap(); let cg = init_test_project(project).await; - let result = handle_tool_call(&cg, "tracedecay_inheritance_depth", json!({}), None, None) + let result = handle_tool_call(&cg, "tracedecay_inheritance_depth", json!({}), None) .await .unwrap(); let text = extract_text(&result.value); @@ -2915,7 +2872,7 @@ async fn analysis_symbol_locations_are_one_based() { 3, ), ] { - let result = handle_tool_call(&graph, tool, arguments, None, None) + let result = handle_tool_call(&graph, tool, arguments, None) .await .unwrap(); let output: Value = serde_json::from_str(extract_text(&result.value)).unwrap(); @@ -2932,15 +2889,9 @@ async fn analysis_symbol_locations_are_one_based() { ("tracedecay_complexity", "ranking", "evaluate", 19), ("tracedecay_god_class", "ranking", "AuditEngine", 1), ] { - let result = handle_tool_call( - &graph, - tool, - json!({"limit": 100, "format": "json"}), - None, - None, - ) - .await - .unwrap(); + let result = handle_tool_call(&graph, tool, json!({"limit": 100, "format": "json"}), None) + .await + .unwrap(); let output: Value = serde_json::from_str(extract_text(&result.value)).unwrap(); let item = output[collection] .as_array() @@ -2956,7 +2907,6 @@ async fn analysis_symbol_locations_are_one_based() { "tracedecay_recursion", json!({"limit": 100, "format": "json"}), None, - None, ) .await .unwrap(); @@ -3103,7 +3053,6 @@ function helper() { return unrelated; } "tracedecay_type_hierarchy", json!({"node_id": parent_id, "format": "json"}), None, - None, ) .await .unwrap(); @@ -3118,7 +3067,6 @@ function helper() { return unrelated; } "tracedecay_inheritance_depth", json!({"path": "src", "limit": 10}), None, - None, ) .await .unwrap(); @@ -3149,7 +3097,6 @@ function helper() { return unrelated; } "tracedecay_type_hierarchy", json!({"node_id": parent_id, "format": "json"}), None, - None, ) .await .unwrap(); @@ -3165,7 +3112,6 @@ function helper() { return unrelated; } "tracedecay_find_exact_symbol", json!({"name": "Base", "limit": 20}), None, - None, ) .await .unwrap(); @@ -3188,7 +3134,6 @@ function helper() { return unrelated; } "tracedecay_type_hierarchy", json!({"node_id": namespace_id(namespace), "format": "json"}), None, - None, ) .await .unwrap(); @@ -3250,7 +3195,6 @@ async fn circular_emits_disjoint_sccs_under_load() { "tracedecay_circular", json!({"member_limit": 200}), None, - None, ) .await .unwrap(); @@ -3301,7 +3245,6 @@ async fn diff_context_dedupes_modified_symbols_on_duplicate_input() { "tracedecay_diff_context", json!({"files": ["src/lib.rs", "src/lib.rs", "src/lib.rs"], "depth": 1}), None, - None, ) .await .unwrap(); @@ -3349,7 +3292,6 @@ async fn changelog_filters_deleted_directory_entries() { "tracedecay_changelog", json!({"from_ref": "HEAD~1", "to_ref": "HEAD"}), None, - None, ) .await .unwrap(); @@ -3410,7 +3352,6 @@ async fn pr_context_collapses_cargo_toml_keys() { "tracedecay_pr_context", json!({"base_ref": "base", "head_ref": "HEAD"}), None, - None, ) .await .unwrap(); @@ -3465,7 +3406,7 @@ fn git_with_pinned_dates(dir: &Path, args: &[&str], date: Option<&str>) { } async fn pr_context_json(host: &impl AnalysisToolHost, arguments: Value) -> Value { - let result = handle_tool_call(host, "tracedecay_pr_context", arguments, None, None) + let result = handle_tool_call(host, "tracedecay_pr_context", arguments, None) .await .unwrap_or_else(|error| { panic!("tracedecay_pr_context should return a tool result: {error}") @@ -3685,7 +3626,6 @@ async fn pr_context_reports_the_pinned_feature_summary() { "tracedecay_pr_context", json!({"format": "json", "base_ref": "master", "head_ref": "feature", "cursor": 1}), None, - None, ) .await; assert_refusal_problem( @@ -3796,7 +3736,7 @@ fn dead_helper_with_attr() {} .unwrap(); let cg = init_test_project(project).await; - let result = handle_tool_call(&cg, "tracedecay_dead_code", json!({}), None, None) + let result = handle_tool_call(&cg, "tracedecay_dead_code", json!({}), None) .await .unwrap(); let text = extract_text(&result.value); @@ -3829,7 +3769,6 @@ async fn unsafe_patterns_reports_unsafe_block_in_markdown_and_json() { "tracedecay_unsafe_patterns", json!({"format": "markdown"}), None, - None, ) .await .unwrap(); @@ -3854,7 +3793,6 @@ async fn unsafe_patterns_reports_unsafe_block_in_markdown_and_json() { "tracedecay_unsafe_patterns", json!({"format": "json"}), None, - None, ) .await .unwrap(); @@ -3921,7 +3859,6 @@ pub fn write_both(target: &mut Target, other: &mut Other) { "tracedecay_field_sites", json!({"field": "Target::value", "limit": 20, "format": "json"}), None, - None, ) .await .unwrap(); @@ -3995,7 +3932,6 @@ pub fn while_let_then_sibling(target: &Target, mut other: Option) -> u32 "tracedecay_field_sites", json!({"field": "Target::value", "format": "json"}), None, - None, ) .await, ); @@ -4034,7 +3970,6 @@ async fn field_sites_ignores_field_text_in_real_rust_literals() { "tracedecay_field_sites", json!({"field": "MmapReader::mmap", "limit": 100, "format": "json"}), None, - None, ) .await .unwrap(); @@ -4127,7 +4062,7 @@ pub fn bump(counter: &mut Counter, gauge: &mut Gauge) -> u32 { "#; async fn call_field_sites(host: &impl AnalysisToolHost, arguments: Value) -> Value { - let result = handle_tool_call(host, "tracedecay_field_sites", arguments, None, None) + let result = handle_tool_call(host, "tracedecay_field_sites", arguments, None) .await .expect("production MCP field-sites call"); extract_json(&result.value) @@ -4221,7 +4156,6 @@ async fn field_sites_behavior_reports_literal_read_and_write_sites() { "tracedecay_field_sites", json!({"format": "json"}), None, - None, ) .await, ); @@ -4241,7 +4175,6 @@ async fn field_sites_behavior_reports_literal_read_and_write_sites() { "tracedecay_field_sites", json!({"field": "Counter::n", "format": "json"}), None, - None, ) .await, ); @@ -4336,7 +4269,6 @@ pub fn closure_then_sibling(counter: &Counter) -> u32 { "tracedecay_field_sites", json!({"field": "Counter::n", "format": "json"}), None, - None, ) .await, ); @@ -4364,7 +4296,6 @@ async fn wait_for_current_graph(host: &impl AnalysisToolHost) { "include_staleness": false, }), None, - None, ) .await .expect("typed project status while awaiting the current graph"); @@ -4403,7 +4334,6 @@ async fn find_node_id(host: &impl AnalysisToolHost, name: &str) -> String { "tracedecay_find_exact_symbol", json!({"name": name, "limit": 20}), None, - None, ) .await .unwrap_or_else(|error| panic!("production exact-symbol read failed: {error}")); @@ -4492,7 +4422,6 @@ async fn diff_context_reports_changed_symbols_callers_and_refuses_invalid_input( "tracedecay_diff_context", json!({"files": ["src/tier_c.rs"], "depth": 1, "format": "json"}), None, - None, ) .await .expect("depth-1 diff_context"); @@ -4528,7 +4457,6 @@ async fn diff_context_reports_changed_symbols_callers_and_refuses_invalid_input( "tracedecay_diff_context", json!({"files": ["src/tier_c.rs"], "depth": 2, "format": "json"}), None, - None, ) .await .expect("depth-2 diff_context"); @@ -4553,7 +4481,6 @@ async fn diff_context_reports_changed_symbols_callers_and_refuses_invalid_input( "format": "json" }), None, - None, ) .await .expect("duplicate-path diff_context"); @@ -4580,7 +4507,6 @@ async fn diff_context_reports_changed_symbols_callers_and_refuses_invalid_input( "tracedecay_diff_context", json!({"files": ["src/not_in_repo.rs"], "format": "json"}), None, - None, ) .await .expect("unpublished-path diff_context"); @@ -4601,7 +4527,6 @@ async fn diff_context_reports_changed_symbols_callers_and_refuses_invalid_input( "tracedecay_diff_context", json!({"files": [], "format": "json"}), None, - None, ) .await .expect("empty-files diff_context"); @@ -4622,7 +4547,6 @@ async fn diff_context_reports_changed_symbols_callers_and_refuses_invalid_input( "tracedecay_diff_context", json!({"format": "json"}), None, - None, ) .await; assert_refusal_problem( @@ -4637,7 +4561,6 @@ async fn diff_context_reports_changed_symbols_callers_and_refuses_invalid_input( "tracedecay_diff_context", json!({"files": "src/tier_c.rs", "format": "json"}), None, - None, ) .await; assert_refusal_problem( @@ -4652,7 +4575,6 @@ async fn diff_context_reports_changed_symbols_callers_and_refuses_invalid_input( "tracedecay_diff_context", json!(["src/tier_c.rs"]), None, - None, ) .await; // A non-object argument list never reaches the owner's typed parser: the @@ -4669,7 +4591,6 @@ async fn diff_context_reports_changed_symbols_callers_and_refuses_invalid_input( "tracedecay_diff_context", json!({"files": ["src/tier_c.rs"], "depth": 0, "format": "json"}), None, - None, ) .await; assert_refusal_problem( @@ -4733,7 +4654,7 @@ pub fn branched(n: i32) -> i32 {\n \ } async fn gini_json(host: &impl AnalysisToolHost, args: Value) -> Value { - let result = handle_tool_call(host, "tracedecay_gini", args, None, None) + let result = handle_tool_call(host, "tracedecay_gini", args, None) .await .expect("tracedecay_gini over production MCP"); extract_json(&result.value) @@ -5012,7 +4933,7 @@ fn write_fanout_project(project: &Path) -> usize { } async fn call_hotspots(host: &MountedProductionProject, arguments: Value) -> Value { - let result = handle_tool_call(host, "tracedecay_hotspots", arguments, None, None) + let result = handle_tool_call(host, "tracedecay_hotspots", arguments, None) .await .unwrap_or_else(|error| panic!("tracedecay_hotspots failed over production MCP: {error}")); result.value @@ -5499,7 +5420,7 @@ fn assert_reported_cycles_close(payload: &Value) { } async fn call_recursion(graph: &impl AnalysisToolHost, arguments: Value) -> Value { - let result = handle_tool_call(graph, "tracedecay_recursion", arguments, None, None) + let result = handle_tool_call(graph, "tracedecay_recursion", arguments, None) .await .unwrap_or_else(|error| panic!("tracedecay_recursion failed: {error}")); extract_json(&result.value) @@ -5558,7 +5479,6 @@ async fn recursion_reports_literal_cycles_and_refuses_non_positive_limit() { "tracedecay_recursion", json!({"format": "json", "limit": 0}), None, - None, ) .await, ); diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/info_health_request_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/info_health_request_test.rs new file mode 100644 index 0000000000..05a93af70f --- /dev/null +++ b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/info_health_request_test.rs @@ -0,0 +1,314 @@ +//! The project-info, registry, and runtime reads decode their arguments +//! against a typed request over the production MCP `tools/call` path: an +//! argument outside the request contract is refused instead of being silently +//! ignored, and a valid call answers the typed result through its owner. + +#![cfg(feature = "test-transport")] + +use serde_json::{Value, json}; +use tracedecay_runtime_core::path_safety::canonical_existing_identity; + +use crate::support::{ProductionCompositionFixture, production_composition_fixture}; + +async fn call_json( + fixture: &ProductionCompositionFixture, + tool_name: &str, + mut arguments: Value, +) -> Value { + arguments["format"] = json!("json"); + let response = fixture + .harness + .call_tool(&fixture.project_root, tool_name, arguments) + .await + .unwrap_or_else(|error| panic!("{tool_name} production invocation failed: {error}")); + assert!( + response.error.is_none(), + "{tool_name} returned a production MCP error: {:?}", + response.error.as_ref().map(|error| &error.message) + ); + let result = response + .result + .unwrap_or_else(|| panic!("{tool_name} returned no production MCP result")); + let text = result["content"][0]["text"] + .as_str() + .unwrap_or_else(|| panic!("{tool_name} returned no text: {result}")); + let payload: Value = serde_json::from_str(text) + .unwrap_or_else(|error| panic!("{tool_name} JSON: {error}: {text}")); + if payload["truncated"] != true { + return payload; + } + // The full body behind a truncated envelope, read back through + // `tracedecay_retrieve` the way a host recovers it. + let mut body = String::new(); + let mut offset = 0; + loop { + let page = fixture + .harness + .call_tool( + &fixture.project_root, + "tracedecay_retrieve", + json!({ "handle": payload["handle"], "format": "json", "offset": offset }), + ) + .await + .expect("retrieve invocation"); + let page: Value = serde_json::from_str( + page.result.expect("retrieve result")["content"][0]["text"] + .as_str() + .expect("retrieve text"), + ) + .expect("retrieve page JSON"); + body.push_str(page["content"].as_str().expect("retrieved content")); + match page["next_offset"].as_u64() { + Some(next) => offset = next, + None => break, + } + } + serde_json::from_str(&body).unwrap_or_else(|error| panic!("{tool_name} body JSON: {error}")) +} + +/// The owner's refusal record for one call: its kind, code, and message. +async fn refusal( + fixture: &ProductionCompositionFixture, + tool_name: &str, + arguments: Value, +) -> Value { + let response = fixture + .harness + .call_tool(&fixture.project_root, tool_name, arguments) + .await + .unwrap_or_else(|error| panic!("{tool_name} production invocation failed: {error}")); + assert!( + response.error.is_none(), + "{tool_name} must refuse through its owner's problem record: {:?}", + response.error.as_ref().map(|error| &error.message) + ); + let result = response + .result + .unwrap_or_else(|| panic!("{tool_name} returned no production MCP result")); + assert_eq!(result["isError"], true, "{tool_name} must refuse: {result}"); + let problem = &result["problem"]; + json!({ + "kind": problem["kind"], + "code": problem["code"], + "message": problem["message"], + }) +} + +fn invalid(tool_name: &str, detail: &str) -> Value { + json!({ + "kind": "invalid_request", + "code": "application.surface.invalid_request", + "message": format!("invalid arguments for {tool_name}: {detail}"), + }) +} + +#[tokio::test] +async fn info_and_runtime_reads_refuse_arguments_outside_their_typed_request() { + let fixture = production_composition_fixture().await; + let root = canonical_existing_identity(&fixture.project_root) + .expect("canonical project root") + .display() + .to_string(); + let project_id = fixture + .harness + .project_id(&fixture.project_root) + .await + .expect("registered project id"); + let registry_path = canonical_existing_identity(fixture.harness.profile_root()) + .expect("canonical profile root") + .join("global.db") + .display() + .to_string(); + + let admission = call_json( + &fixture, + "tracedecay_status", + json!({"admission_only": true}), + ) + .await; + assert_eq!( + (&admission["project_admitted"], &admission["project_root"]), + (&json!(true), &json!(root)) + ); + assert_eq!(admission["server"]["errors"], 0, "{admission}"); + assert_eq!( + refusal( + &fixture, + "tracedecay_status", + json!({"include_diagnostics": true}) + ) + .await, + invalid( + "tracedecay_status", + "unknown field `include_diagnostics`, expected one of `admission_only`, `include_branch_diagnostics`, `include_storage_health`, `include_session_ingest`, `include_staleness`, `wait_for`" + ) + ); + + let active = call_json(&fixture, "tracedecay_active_project", json!({})).await; + assert_eq!( + ( + &active["project_id"], + &active["project_root"], + &active["resolution_source"], + &active["storage"]["class"], + &active["storage"]["mode"], + ), + ( + &json!(project_id), + &json!(root), + &json!("active_project"), + &json!("code_project"), + &json!("profile_sharded"), + ) + ); + assert_eq!( + refusal( + &fixture, + "tracedecay_active_project", + json!({"project": "other"}) + ) + .await, + invalid( + "tracedecay_active_project", + "unknown field `project`, there are no fields" + ) + ); + + assert_eq!( + call_json(&fixture, "tracedecay_remote_status", json!({})).await, + json!({"kind": "unconfigured"}) + ); + assert_eq!( + refusal( + &fixture, + "tracedecay_remote_status", + json!({"kind": "observed"}) + ) + .await, + invalid( + "tracedecay_remote_status", + "unknown field `kind`, there are no fields" + ) + ); + + let runtime = call_json( + &fixture, + "tracedecay_runtime", + json!({"doctor_report": true}), + ) + .await; + let doctor = &runtime["doctor_report"]; + assert_eq!(doctor["kind"], "observed", "{doctor}"); + assert_eq!( + doctor + .as_object() + .map(|report| report.keys().cloned().collect::>()), + Some( + [ + "kind", + "language_servers", + "report", + "schema_convergences", + "table_growth_evidence" + ] + .map(str::to_owned) + .to_vec() + ), + "{doctor}" + ); + assert_eq!( + doctor["report"] + .as_object() + .map(|report| report.keys().cloned().collect::>()), + Some(["coverage", "entries"].map(str::to_owned).to_vec()), + "{doctor}" + ); + assert_eq!( + refusal(&fixture, "tracedecay_runtime", json!({"doctor": true})).await, + invalid( + "tracedecay_runtime", + "unknown field `doctor`, expected one of `authority_audit`, `session_temporal_health`, `doctor_report`, `session_ingest_health`, `startup_health`" + ) + ); + + let listing = call_json(&fixture, "tracedecay_project_list", json!({"limit": 5})).await; + assert_eq!( + ( + &listing["status"], + &listing["title"], + &listing["registry_path"], + &listing["limit"], + &listing["truncated"], + &listing["summary"], + ), + ( + &json!("ok"), + &json!("registered projects"), + &json!(registry_path), + &json!(5), + &json!(false), + &json!({"project_count": 1, "repo_count": 1, "truncated": false}), + ) + ); + assert_eq!( + ( + &listing["projects"][0]["project_id"], + &listing["projects"][0]["is_active"], + ), + (&json!(project_id), &json!(true)), + "{listing}" + ); + assert_eq!( + refusal(&fixture, "tracedecay_project_list", json!({"limt": 5})).await, + invalid( + "tracedecay_project_list", + "unknown field `limt`, expected `limit`" + ) + ); + assert_eq!( + refusal(&fixture, "tracedecay_project_list", json!({"limit": 2.5})).await, + invalid( + "tracedecay_project_list", + "invalid type: floating point `2.5`, expected usize" + ) + ); + + assert_eq!( + refusal(&fixture, "tracedecay_project_search", json!({"query": 12})).await, + invalid( + "tracedecay_project_search", + "invalid type: integer `12`, expected a string" + ) + ); + + let context = call_json(&fixture, "tracedecay_project_context", json!({})).await; + assert_eq!( + ( + &context["status"], + &context["is_active"], + &context["registry_path"], + &context["project"]["project_id"], + ), + ( + &json!("ok"), + &json!(true), + &json!(registry_path), + &json!(project_id), + ), + "{context}" + ); + assert_eq!( + refusal( + &fixture, + "tracedecay_project_context", + json!({"project_selector": {"project": "other"}}) + ) + .await, + invalid( + "tracedecay_project_context", + "unknown field `project`, expected `project_id`" + ) + ); + + fixture.harness.shutdown().await; +} diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/lcm_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/lcm_test.rs index ead952d3e3..774f40ffaa 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/lcm_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/lcm_test.rs @@ -48,9 +48,8 @@ async fn lcm_tools_reject_invalid_storage_routing_arguments() { args.as_object_mut() .unwrap() .insert(removed.to_string(), value); - let error = expect_tool_error( - handle_tool_call(&cg, "tracedecay_lcm_status", args, None, None).await, - ); + let error = + expect_tool_error(handle_tool_call(&cg, "tracedecay_lcm_status", args, None).await); assert!( error.contains(expected), "invalid {removed} should fail clearly: {error}" @@ -80,7 +79,6 @@ async fn lcm_session_handlers_expose_bounded_read_apis_and_placeholders() { "tracedecay_lcm_status", json!({"provider": "cursor"}), None, - None, ) .await .unwrap(); @@ -97,7 +95,6 @@ async fn lcm_session_handlers_expose_bounded_read_apis_and_placeholders() { "content_limit": 24 }), None, - None, ) .await .unwrap(); @@ -125,7 +122,6 @@ async fn lcm_session_handlers_expose_bounded_read_apis_and_placeholders() { "tracedecay_lcm_grep", json!({"provider": "cursor", "query": "orchard dispatch", "limit": 5}), None, - None, ) .await .unwrap(); @@ -155,7 +151,6 @@ async fn lcm_session_handlers_expose_bounded_read_apis_and_placeholders() { "tracedecay_lcm_grep", json!({"query": "orchard dispatch", "limit": 5}), None, - None, ) .await .unwrap(); @@ -217,7 +212,6 @@ async fn lcm_session_handlers_expose_bounded_read_apis_and_placeholders() { "limit": 5 }), None, - None, ) .await .unwrap(); @@ -248,7 +242,6 @@ async fn lcm_session_handlers_expose_bounded_read_apis_and_placeholders() { "limit": 5 }), None, - None, ) .await .unwrap(); @@ -274,7 +267,6 @@ async fn lcm_session_handlers_expose_bounded_read_apis_and_placeholders() { "tracedecay_lcm_describe", json!({"provider": "cursor", "session_id": "lcm-session"}), None, - None, ) .await .unwrap(); @@ -321,7 +313,6 @@ async fn lcm_session_handlers_expose_bounded_read_apis_and_placeholders() { "content_limit": 16 }), None, - None, ) .await .unwrap(); @@ -356,7 +347,6 @@ async fn lcm_session_handlers_expose_bounded_read_apis_and_placeholders() { "max_tokens": 64 }), None, - None, ) .await .unwrap(); @@ -431,7 +421,7 @@ async fn lcm_load_session_cursor_walk_reads_every_message_exactly_once() { .unwrap() .insert("cursor".to_owned(), json!(cursor)); } - let loaded = handle_tool_call(&cg, "tracedecay_lcm_load_session", args, None, None) + let loaded = handle_tool_call(&cg, "tracedecay_lcm_load_session", args, None) .await .unwrap_or_else(|error| panic!("page {pages} of a large session must load: {error}")); let loaded: Value = serde_json::from_str(extract_text(&loaded.value)).unwrap(); @@ -534,7 +524,6 @@ async fn lcm_status_response_is_valid_json_and_omits_payload_secrets() { "session_id": "lcm-status-session" }), None, - None, ) .await .unwrap(); @@ -606,7 +595,6 @@ async fn lcm_status_reports_lifecycle_fields_from_active_project() { "session_id": "lcm-status-frontier" }), None, - None, ) .await .unwrap(); @@ -810,7 +798,6 @@ async fn lcm_grep_raw_hit_store_id_expands_byte_exactly() { "limit": 1 }), None, - None, ) .await .unwrap(); @@ -828,7 +815,6 @@ async fn lcm_grep_raw_hit_store_id_expands_byte_exactly() { "target": {"kind": "raw_message", "store_id": store_id} }), None, - None, ) .await .unwrap(); @@ -887,7 +873,6 @@ async fn lcm_grep_and_load_session_honor_native_filters_and_content_clamp() { "limit": 10 }), None, - None, ) .await .unwrap(); @@ -918,7 +903,6 @@ async fn lcm_grep_and_load_session_honor_native_filters_and_content_clamp() { "limit": 10 }), None, - None, ) .await .unwrap(); @@ -996,7 +980,6 @@ async fn lcm_grep_accepts_string_timestamp_filters() { "limit": 10 }), None, - None, ) .await .unwrap(); @@ -1054,7 +1037,6 @@ async fn lcm_grep_accepts_relative_time_filters() { "limit": 10 }), None, - None, ) .await .unwrap(); @@ -1096,7 +1078,7 @@ async fn lcm_load_session_rejects_fractional_negative_and_wrong_type_numeric_arg ), ] { let err = expect_tool_error( - handle_tool_call(&cg, "tracedecay_lcm_load_session", args, None, None).await, + handle_tool_call(&cg, "tracedecay_lcm_load_session", args, None).await, ); assert!( err.contains("limit"), @@ -2307,7 +2289,6 @@ async fn lcm_status_reports_dag_store_and_config_diagnostics_over_mcp() { "tracedecay_lcm_status", json!({"provider": "cursor", "session_id": "lcm-diag-session"}), None, - None, ) .await .unwrap(); @@ -2359,7 +2340,6 @@ async fn lcm_status_all_provider_aggregates_provider_counts() { "tracedecay_lcm_status", json!({"provider": "all"}), None, - None, ) .await .unwrap(); @@ -2401,7 +2381,6 @@ async fn lcm_status_all_provider_counts_payload_health_once() { "tracedecay_lcm_status", json!({"provider": "all"}), None, - None, ) .await .unwrap(); @@ -2849,7 +2828,6 @@ async fn lcm_grep_rejects_invalid_scope() { "tracedecay_lcm_grep", json!({"query": "anything", "scope": "everything"}), None, - None, ) .await, ); @@ -2863,7 +2841,6 @@ async fn lcm_grep_rejects_invalid_scope() { "tracedecay_lcm_grep", json!({"query": "anything", "relationship_scope": "children"}), None, - None, ) .await, ); @@ -2911,7 +2888,7 @@ async fn lcm_read_only_tools_return_not_ingested_without_creating_sessions_db() json!({"provider": "cursor", "session_id": "ghost-session", "prompt": "anything"}), ), ] { - match handle_tool_call(&cg, tool, args.clone(), None, None).await { + match handle_tool_call(&cg, tool, args.clone(), None).await { Ok(result) => { let text = extract_text(&result.value); let payload: Value = serde_json::from_str(text) @@ -2979,7 +2956,6 @@ async fn lcm_load_session_missing_store_uses_typed_empty_messages_without_creati "tracedecay_lcm_load_session", json!({"session_id": "ghost-session"}), None, - None, ) .await .unwrap_or_else(|error| panic!("tracedecay_lcm_load_session returned error: {error}")); diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/move_symbol_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/move_symbol_test.rs index d756f37a0f..bfa4b75b44 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/move_symbol_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/move_symbol_test.rs @@ -26,7 +26,6 @@ async fn test_move_symbol_dry_run_reports_impact_and_writes_nothing() { "tracedecay_move_symbol", json!({ "symbol": "compute_grand_total", "dest_file": "src/grand_total.rs" }), None, - None, ) .await .unwrap(); @@ -119,7 +118,6 @@ async fn test_move_symbol_resolves_qualified_names_like_bare_names() { "tracedecay_move_symbol", json!({ "symbol": symbol, "dest_file": "src/grand_total.rs" }), None, - None, ) .await .unwrap_or_else(|error| panic!("move for {symbol:?} failed: {error}")); @@ -187,7 +185,6 @@ async fn test_move_symbol_only_prefers_callable_for_bare_names() { "tracedecay_move_symbol", json!({ "symbol": "same", "dest_file": "src/moved.rs" }), None, - None, ) .await .unwrap(); @@ -200,7 +197,6 @@ async fn test_move_symbol_only_prefers_callable_for_bare_names() { "tracedecay_move_symbol", json!({ "symbol": "common::same", "dest_file": "src/moved.rs" }), None, - None, ) .await .expect("qualified collision returns a durable failed effect"); @@ -214,7 +210,6 @@ async fn test_move_symbol_only_prefers_callable_for_bare_names() { "tracedecay_move_symbol", json!({ "symbol": "wrong::same", "dest_file": "src/moved.rs" }), None, - None, ) .await .expect("wrong module returns a durable failed effect"); @@ -247,7 +242,6 @@ async fn test_move_symbol_apply_moves_and_rerun_errors_cleanly() { "tracedecay_move_symbol", json!({ "symbol": "compute_grand_total", "dest_file": "src/grand_total.rs", "dry_run": false }), None, - None, ) .await .unwrap(); @@ -285,7 +279,6 @@ async fn test_move_symbol_apply_moves_and_rerun_errors_cleanly() { "tracedecay_move_symbol", json!({ "symbol": "compute_grand_total", "dest_file": "src/grand_total.rs", "dry_run": false }), None, - None, ) .await .unwrap(); @@ -321,7 +314,6 @@ async fn test_move_symbol_clean_move_has_empty_impact() { "tracedecay_move_symbol", json!({ "symbol": "standalone", "dest_file": "src/b.rs" }), None, - None, ) .await .unwrap(); @@ -362,7 +354,6 @@ async fn test_move_symbol_dest_collision_refuses() { "tracedecay_move_symbol", json!({ "symbol": "src/a.rs::dup", "dest_file": "src/b.rs", "dry_run": false }), None, - None, ) .await .unwrap(); @@ -408,7 +399,6 @@ async fn test_move_symbol_private_dependency_hints() { "tracedecay_move_symbol", json!({ "symbol": "uses_secret", "dest_file": "src/b.rs" }), None, - None, ) .await .unwrap(); @@ -478,7 +468,6 @@ async fn test_move_symbol_qualified_caller_hint() { "tracedecay_move_symbol", json!({ "symbol": "compute_grand_total", "dest_file": "src/grand_total.rs" }), None, - None, ) .await .unwrap(); @@ -536,7 +525,6 @@ async fn test_move_symbol_first_in_file_docs_travel() { "tracedecay_move_symbol", json!({ "symbol": "leading", "dest_file": "src/b.rs", "dry_run": false }), None, - None, ) .await .unwrap(); @@ -585,7 +573,6 @@ async fn test_move_symbol_dot_prefixed_same_file_refuses() { "tracedecay_move_symbol", json!({ "symbol": "compute_grand_total", "dest_file": "./src/pricing.rs", "dry_run": false }), None, - None, ) .await .unwrap(); @@ -629,7 +616,6 @@ async fn test_move_symbol_symlink_escape_refuses() { "dry_run": false }), None, - None, ) .await .expect("containment refusal should return a durable failed effect"); @@ -677,7 +663,6 @@ async fn test_move_symbol_aliases_to_source_refuse() { "dry_run": false }), None, - None, ) .await .unwrap(); @@ -710,7 +695,6 @@ async fn test_move_symbol_dot_prefixed_dest_normalizes() { "tracedecay_move_symbol", json!({ "symbol": "compute_grand_total", "dest_file": "./src/grand_total.rs", "dry_run": false }), None, - None, ) .await .unwrap(); @@ -759,7 +743,6 @@ async fn test_move_symbol_leaves_contiguous_module_doc_behind() { "tracedecay_move_symbol", json!({ "symbol": "fact", "dest_file": "src/b.rs", "dry_run": false }), None, - None, ) .await .unwrap(); @@ -825,7 +808,6 @@ async fn test_move_symbol_non_utf8_destination_refuses() { "tracedecay_move_symbol", json!({ "symbol": "movable", "dest_file": "src/blob.rs", "dry_run": false }), None, - None, ) .await .unwrap(); diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/project_context_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/project_context_test.rs index be1c4923e9..eac9e46e64 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/project_context_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/project_context_test.rs @@ -278,37 +278,6 @@ async fn project_context_returns_the_project_the_caller_named() { ); } -#[tokio::test] -async fn project_context_reports_an_unmounted_registry_as_unavailable() { - let (cg, _env, _dir) = setup_empty_project().await; - let server = tracedecay::mcp::McpServer::new( - tracedecay_project::project::TraceDecay::open_with_options( - cg.project_root(), - crate::support::graph_open_options(&cg), - ) - .await - .expect("open served project"), - None, - ) - .await; - - let payload = call_project_context( - &server, - json!({"project_selector": {"project_id": "proj_alpha"}}), - ) - .await; - - assert_eq!( - payload, - json!({ - "status": "unavailable", - "message": "project registry is not present for this profile", - "projects": [], - }), - "a server with no registry port must not answer not_found" - ); -} - #[tokio::test] async fn project_context_reports_a_broken_registry_read_as_a_tool_error() { let (cg, _env, _dir) = setup_empty_project().await; @@ -361,19 +330,14 @@ async fn project_context_reports_a_broken_registry_read_as_a_tool_error() { ) .await; - assert_eq!(response["error"]["code"], -32603, "{response}"); - assert_eq!( - response["error"]["data"]["tool"], "tracedecay_project_context", - "{response}" - ); + // A broken alias table refuses; it never becomes a successful context. assert_eq!( - response["error"]["message"], - "tool execution failed: database error: SQLite prepare query failed: no such table: project_aliases (operation: resolve project identity alias)", - "{response}" - ); - assert!( - response.get("result").is_none() || response["result"].is_null(), - "a broken alias table must not become a successful context: {response}" + crate::support::tool_refusal(&response), + json!({ + "kind": "unavailable", + "code": "graph_tool.failed", + "message": "database error: SQLite prepare query failed: no such table: project_aliases (operation: resolve project identity alias)", + }) ); } diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/project_list_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/project_list_test.rs index 7ef039447a..6b1b8e3ad8 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/project_list_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/project_list_test.rs @@ -365,18 +365,11 @@ async fn project_list_reports_a_broken_registry_as_a_tool_error() { let response = tools_call(&server, json!({"format": "json"})).await; assert_eq!( - response, + crate::support::tool_refusal(&response), json!({ - "jsonrpc": "2.0", - "id": 1, - "error": { - "code": -32603, - "message": "tool execution failed: database error: SQLite prepare query failed: no such table: project_aliases (operation: resolve project identity alias)", - "data": { - "tool": "tracedecay_project_list", - "cli_fallback": "This tool is also available from the shell: `tracedecay tool project_list ...` (`tracedecay tool project_list --help` for parameters). If MCP calls keep failing or timing out, fall back to that CLI instead of querying .tracedecay databases directly." - } - } + "kind": "unavailable", + "code": "graph_tool.failed", + "message": "database error: SQLite prepare query failed: no such table: project_aliases (operation: resolve project identity alias)", }) ); } diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/project_search_behavior_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/project_search_behavior_test.rs index 8f1cd5f700..ea84dee438 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/project_search_behavior_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/project_search_behavior_test.rs @@ -538,53 +538,32 @@ async fn project_search_bounds_pages_and_does_not_expand_wildcards() { } #[tokio::test] -async fn project_search_rejects_a_non_string_query_and_an_unmounted_registry() { - let (cg, _env, _dir) = setup_empty_project().await; - let server = McpServer::new( - TraceDecay::open_with_options(cg.project_root(), crate::support::graph_open_options(&cg)) - .await - .expect("open calling project"), - None, - ) - .await; +async fn project_search_refuses_arguments_outside_its_typed_request() { + let fixture = open_search_fixture().await; - for arguments in [json!({}), json!({"query": 12}), json!({"query": null})] { - let response = handle_real_server_tool_call_raw(&server, TOOL, arguments).await; - assert_eq!(response["jsonrpc"], "2.0"); - assert!(response["result"].is_null(), "{response}"); + for (arguments, detail) in [ + (json!({}), "missing field `query`"), + ( + json!({"query": 12}), + "invalid type: integer `12`, expected a string", + ), + ( + json!({"query": null}), + "invalid type: null, expected a string", + ), + ( + json!({"query": "search-alpha", "limt": 3}), + "unknown field `limt`, expected `query` or `limit`", + ), + ] { + let response = handle_real_server_tool_call_raw(&fixture.server, TOOL, arguments).await; assert_eq!( - response["error"], + crate::support::tool_refusal(&response), json!({ - "code": -32602, - "message": "missing required parameter: query", - "data": { - "tool": TOOL, - "reason_code": "missing_required_parameter", - "retryable": false, - "detail": "missing required parameter: query" - } - }) + "kind": "invalid_request", + "code": "application.surface.invalid_request", + "message": format!("invalid arguments for {TOOL}: {detail}"), + }), ); } - - let unavailable = - search_json(&server, json!({"query": "search-alpha", "format": "json"})).await; - assert_eq!( - unavailable, - json!({ - "status": "unavailable", - "message": "project registry is not present for this profile", - "projects": [], - "title": "projects matching \"search-alpha\"", - "summary": { - "project_count": 0, - "repo_count": 0, - "truncated": false - }, - "project_tree": [], - "query": "search-alpha", - "limit": 10, - "truncated": false - }) - ); } diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/remote_status_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/remote_status_test.rs index 078dd96375..3c9e4f454d 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/remote_status_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/remote_status_test.rs @@ -1,9 +1,9 @@ //! Real `tools/call` coverage for `tracedecay_remote_status`. //! //! The production daemon mounts the Remote Brain reader. With no listener and -//! no registered node, that reader is `unconfigured`. A direct server never -//! installs the reader, so the same call is `unavailable`. Neither outcome is -//! an empty success or a semantic tool error. +//! no registered node, that reader is `unconfigured`. A registered test server +//! that never installs the reader answers the same call `unavailable`. Neither +//! outcome is an empty success or a semantic tool error. //! //! The configured (`observed`) plane is proved at the two seams that can mount //! one cheaply: `daemon::remote_protocol_tests` provisions a real node and @@ -21,7 +21,8 @@ use tracedecay::daemon::ProductionProjectCompositionHarnessV1; use crate::common; use crate::fixture; use crate::mcp_server_test::support::{ - jsonrpc_request, response_with_id, run_server_with_messages, setup_server, successful_tool_text, + jsonrpc_request, response_with_id, run_server_with_messages, setup_accounted_server, + successful_tool_text, }; use crate::support::{TestTempDir, test_temp_dir}; @@ -122,10 +123,10 @@ async fn production_daemon_reports_unconfigured_remote_plane() { } #[tokio::test] -async fn direct_server_reports_unmounted_remote_authority() { - let (server, _dir) = setup_server().await; +async fn a_server_without_the_remote_reader_reports_unmounted_remote_authority() { + let fixture = setup_accounted_server().await; let responses = run_server_with_messages( - server, + std::sync::Arc::clone(&fixture.server), vec![ jsonrpc_request( json!(1), diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/replace_symbol_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/replace_symbol_test.rs index 2efb317167..7d4368bed1 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/replace_symbol_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/replace_symbol_test.rs @@ -158,7 +158,7 @@ async fn open_sources( } async fn call_replace(fixture: &ProductionSourceEditFixture, args: Value) -> Value { - let result = handle_tool_call(fixture, "tracedecay_replace_symbol", args, None, None) + let result = handle_tool_call(fixture, "tracedecay_replace_symbol", args, None) .await .expect("tracedecay_replace_symbol dispatch"); tool_payload(&result.value) diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/session_search_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/session_search_test.rs index 6ba71f98b0..848b47fe3c 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/session_search_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/session_search_test.rs @@ -219,7 +219,6 @@ async fn message_search_rejects_invalid_scope() { "tracedecay_message_search", json!({"query": "anything", "scope": invalid}), None, - None, ) .await, ); @@ -236,7 +235,6 @@ async fn message_search_rejects_invalid_scope() { "tracedecay_message_search", json!({"query": "anything", "provider": "unknown-agent"}), None, - None, ) .await, ); @@ -251,7 +249,6 @@ async fn message_search_rejects_invalid_scope() { "tracedecay_message_search", json!({"query": "anything", "message_type": "promptish"}), None, - None, ) .await, ); @@ -282,7 +279,6 @@ async fn message_search_rejects_removed_request_spellings() { "tracedecay_message_search", json!({"query": "anything", field: value}), None, - None, ) .await, ); @@ -297,7 +293,6 @@ async fn message_search_rejects_removed_request_spellings() { "tracedecay_message_search", json!({"query": "anything", "since": 0, "until": 1, "require_fresh": false}), None, - None, ) .await .expect("canonical spellings must stay served"); @@ -322,7 +317,6 @@ async fn message_search_rejects_foreign_project_selectors() { "tracedecay_message_search", json!({"query": "anything", alias: value}), None, - None, ) .await, ); @@ -342,7 +336,6 @@ async fn message_search_rejects_foreign_project_selectors() { "project_selector": {"project_id": "proj_0123456789abcdef"} }), None, - None, ) .await, ); @@ -357,7 +350,6 @@ async fn message_search_rejects_foreign_project_selectors() { "tracedecay_message_search", json!({"query": "anything", "project_selector": {"path": "/some/path"}}), None, - None, ) .await, ); @@ -417,7 +409,6 @@ async fn message_search_limit_one_hydrates_a_bounded_multi_session_corpus() { "limit": 1, }), None, - None, ) .await .expect("a limit-one retained search must fit the admitted budget"); @@ -453,7 +444,6 @@ async fn message_search_limit_one_hydrates_a_bounded_multi_session_corpus() { "limit": 1, }), None, - None, ) .await .expect("the bounded record read must resolve duplicate candidate lanes once"); @@ -481,7 +471,6 @@ async fn message_search_limit_one_hydrates_a_bounded_multi_session_corpus() { "limit": 1, }), None, - None, ) .await .expect("an exact query without a maintained-index token is a valid empty search"); @@ -1133,7 +1122,6 @@ async fn message_search_returns_literal_seeded_messages() { "tracedecay_message_search", json!({"format": "json"}), None, - None, ) .await, )); @@ -1167,7 +1155,6 @@ async fn message_search_returns_literal_seeded_messages() { "format": "json", }), None, - None, ) .await, )); @@ -1208,7 +1195,7 @@ async fn materialize_proof_session(cg: &TraceDecay, session_id: &str) { #[cfg(feature = "test-transport")] async fn message_search_payload(cg: &TraceDecay, arguments: Value) -> Value { - let result = handle_tool_call(cg, "tracedecay_message_search", arguments, None, None) + let result = handle_tool_call(cg, "tracedecay_message_search", arguments, None) .await .expect("tracedecay_message_search MCP call"); let envelope = extract_json(&result.value); diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/source_edit_reconcile_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/source_edit_reconcile_test.rs index 2b7cfd7e9e..61309921e9 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/source_edit_reconcile_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/source_edit_reconcile_test.rs @@ -91,14 +91,8 @@ async fn call_reconcile( fixture: &ProductionSourceEditFixture, args: Value, ) -> Result { - handle_production_source_edit_tool_call( - fixture, - "tracedecay_source_edit_reconcile", - args, - None, - None, - ) - .await + handle_production_source_edit_tool_call(fixture, "tracedecay_source_edit_reconcile", args, None) + .await } fn reconcile_args( @@ -135,7 +129,6 @@ async fn admitted_expected_state(fixture: &ProductionSourceEditFixture) -> Strin "dry_run": true }), None, - None, ) .await .expect("source edit preview"); @@ -213,7 +206,6 @@ async fn retain_unpublished_effect( "expected_state": expected_state, }), None, - None, ) .await .expect("unpublished source edit"); @@ -435,7 +427,6 @@ async fn unpublished_effect_confirms_rolled_back_and_releases_the_file() { "expected_state": expected_state, }), None, - None, ) .await .expect("original edit retry"), @@ -465,7 +456,6 @@ async fn unpublished_effect_confirms_rolled_back_and_releases_the_file() { "expected_state": expected_state, }), None, - None, ) .await .expect("follow-up edit"), @@ -597,7 +587,6 @@ async fn mismatched_inspection_keeps_bytes_and_confirm_committed_keeps_the_posti "expected_state": expected_state, }), None, - None, ) .await .expect("original edit retry"), diff --git a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/status_runtime_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/status_runtime_test.rs index db279997e0..8640980ded 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_handler_test/status_runtime_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_handler_test/status_runtime_test.rs @@ -34,15 +34,9 @@ fn assert_sealed_graph_statistics_are_unavailable(text: &str) { #[tokio::test] async fn test_status() { let (cg, _env, _dir) = setup_empty_project().await; - let result = handle_tool_call( - &cg, - "tracedecay_status", - json!({}), - Some(json!({"uptime": 100})), - None, - ) - .await - .unwrap(); + let result = handle_tool_call(&cg, "tracedecay_status", json!({}), None) + .await + .unwrap(); let text = extract_text(&result.value); assert_sealed_graph_statistics_are_unavailable(text); assert!( @@ -75,7 +69,6 @@ async fn status_includes_verbose_sections_only_when_requested() { "include_session_ingest": true, "include_staleness": true, }), - Some(json!({"uptime": 100})), None, ) .await @@ -96,7 +89,6 @@ async fn status_can_omit_verbose_branch_diagnostics() { &cg, "tracedecay_status", json!({"include_branch_diagnostics": false}), - Some(json!({"uptime": 100})), None, ) .await @@ -143,17 +135,11 @@ async fn status_reports_daemon_owned_partial_history_catch_up() { .unwrap() ); - let result = tracedecay::mcp::tools::handle_tool_call_with_registry_options( + let result = handle_tool_call( &cg, "tracedecay_status", json!({"format": "json", "include_session_ingest": true}), None, - None, - tracedecay::mcp::tools::ToolCallRegistryOptions::with_session_authorities( - tracedecay_mcp::handlers::mcp_session_authorities(&runtime), - ) - .admit_opened_project(&cg) - .unwrap(), ) .await .unwrap(); @@ -202,17 +188,11 @@ async fn runtime_exposes_cursor_ingest_health_for_daemon_owned_doctor_checks() { ); } - let result = tracedecay::mcp::tools::handle_tool_call_with_registry_options( + let result = handle_tool_call( &cg, "tracedecay_runtime", json!({ "format": "json", "session_ingest_health": true }), None, - None, - tracedecay::mcp::tools::ToolCallRegistryOptions::with_session_authorities( - tracedecay_mcp::handlers::mcp_session_authorities(&runtime), - ) - .admit_opened_project(&cg) - .unwrap(), ) .await .unwrap(); @@ -226,51 +206,10 @@ async fn runtime_exposes_cursor_ingest_health_for_daemon_owned_doctor_checks() { ); } -#[cfg(feature = "test-transport")] -#[tokio::test] -async fn status_without_retained_session_authority_fails_closed() { - let (cg, _env, _dir) = setup_empty_project().await; - drop(open_active_project_session_db(&cg).await); - - let result = handle_tool_call( - &cg, - "tracedecay_status", - json!({ "format": "json", "include_session_ingest": true }), - None, - None, - ) - .await - .unwrap(); - let payload: Value = serde_json::from_str(extract_text(&result.value)).unwrap(); - - assert_eq!(payload["session_ingest"]["status"], "unavailable"); - assert_eq!(payload["session_ingest"]["reason"], "session_store_denied"); - assert_eq!( - payload["session_ingest"]["message"], - "this request is not authorized to read the admitted project session store" - ); - assert!(payload.get("cursor_session_ingest").is_none()); -} - -#[tokio::test] -async fn test_status_without_server_stats() { - let (cg, _env, _dir) = setup_empty_project().await; - let result = handle_tool_call(&cg, "tracedecay_status", json!({}), None, None) - .await - .unwrap(); - let text = extract_text(&result.value); - assert_sealed_graph_statistics_are_unavailable(text); - // Should NOT contain "server" key when None is passed - assert!( - !text.contains("\"server\""), - "status without server_stats should not include 'server' key" - ); -} - #[tokio::test] async fn test_status_reports_scope_prefix() { let (cg, _env, _dir) = setup_empty_project().await; - let result = handle_tool_call(&cg, "tracedecay_status", json!({}), None, Some("src/mcp")) + let result = handle_tool_call(&cg, "tracedecay_status", json!({}), Some("src/mcp")) .await .unwrap(); let text = extract_text(&result.value); @@ -294,7 +233,7 @@ async fn test_status_reports_scope_prefix() { #[tokio::test] async fn test_runtime_snapshot_exposes_process_and_db_signals() { let (cg, _env, _dir) = setup_empty_project().await; - let result = handle_tool_call(&cg, "tracedecay_runtime", json!({}), None, None) + let result = handle_tool_call(&cg, "tracedecay_runtime", json!({}), None) .await .unwrap(); let text = extract_text(&result.value); @@ -330,7 +269,7 @@ async fn test_runtime_snapshot_exposes_process_and_db_signals() { // stale rather than falsely label the retained observation as current. let proc = tokio::time::timeout(std::time::Duration::from_secs(10), async { loop { - let result = handle_tool_call(&cg, "tracedecay_runtime", json!({}), None, None) + let result = handle_tool_call(&cg, "tracedecay_runtime", json!({}), None) .await .unwrap(); let parsed: serde_json::Value = diff --git a/crates/tracedecay/tests/mcp_suite/mcp_server_test/protocol_test.rs b/crates/tracedecay/tests/mcp_suite/mcp_server_test/protocol_test.rs index e5d71ff005..272f643588 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_server_test/protocol_test.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_server_test/protocol_test.rs @@ -370,7 +370,8 @@ async fn test_tools_call_plain_text_failure_sets_is_error() { #[tokio::test] async fn test_tools_call_timings_enabled_by_default() { - let (server, _dir) = setup_server().await; + let fixture = setup_accounted_server().await; + let server = Arc::clone(&fixture.server); let responses = run_server_with_messages( server, vec![jsonrpc_request( @@ -397,7 +398,8 @@ async fn test_tools_call_timings_enabled_by_default() { #[tokio::test] async fn test_tools_call_timings_can_be_disabled() { - let (server, dir) = setup_server().await; + let fixture = setup_accounted_server().await; + let server = Arc::clone(&fixture.server); server.set_timings_enabled(false); let responses = run_server_with_messages( server, @@ -417,7 +419,7 @@ async fn test_tools_call_timings_can_be_disabled() { assert_eq!(payload["project_admitted"], true, "{payload}"); assert_eq!( payload["project_root"], - json!(canonical_existing_identity(dir.path()).unwrap()), + json!(canonical_existing_identity(&fixture.project_root).unwrap()), "{payload}" ); assert!( @@ -717,7 +719,8 @@ async fn cancellable_tool_call_fails_connection_on_peer_write_failure() { #[tokio::test] async fn test_tools_call_status() { - let (server, _dir) = setup_server().await; + let fixture = setup_accounted_server().await; + let server = Arc::clone(&fixture.server); let responses = run_server_with_messages( server, vec![jsonrpc_request( @@ -1152,7 +1155,8 @@ async fn test_server_stats_include_response_handle_metrics() { } #[tokio::test] async fn test_server_stats_after_run() { - let (server, _dir) = setup_server().await; + let fixture = setup_accounted_server().await; + let server = Arc::clone(&fixture.server); let server_handle = server.clone(); // Send several requests then a tracedecay_status to check stats are embedded. let responses = run_server_with_messages( @@ -1207,7 +1211,8 @@ async fn test_server_stats_after_run() { #[tokio::test] async fn test_error_tracking() { - let (server, _dir) = setup_server().await; + let fixture = setup_accounted_server().await; + let server = Arc::clone(&fixture.server); let stats_view = Arc::clone(&server); let responses = run_server_with_messages( server, diff --git a/crates/tracedecay/tests/mcp_suite/mcp_server_test/support.rs b/crates/tracedecay/tests/mcp_suite/mcp_server_test/support.rs index f47315489f..bd1dbf5051 100644 --- a/crates/tracedecay/tests/mcp_suite/mcp_server_test/support.rs +++ b/crates/tracedecay/tests/mcp_suite/mcp_server_test/support.rs @@ -197,6 +197,7 @@ impl McpTransport for ReadErrorTransport { pub(crate) struct AccountedServer { pub(crate) server: Arc, pub(crate) global_db_path: PathBuf, + pub(crate) project_root: PathBuf, _project: TempDir, _profile: TempDir, } @@ -258,6 +259,7 @@ async fn setup_accounted_server_with_source(source: &str) -> AccountedServer { AccountedServer { server, global_db_path, + project_root: dir.path().to_path_buf(), _project: dir, _profile: profile_dir, } diff --git a/crates/tracedecay/tests/mcp_suite/support.rs b/crates/tracedecay/tests/mcp_suite/support.rs index 94a60a5c39..0fa66572a9 100644 --- a/crates/tracedecay/tests/mcp_suite/support.rs +++ b/crates/tracedecay/tests/mcp_suite/support.rs @@ -246,6 +246,25 @@ pub(crate) fn extract_real_server_text(result: &Value) -> &str { .expect("MCP text result") } +/// The owner's refusal a JSON-RPC `tools/call` response carries, as its +/// problem kind, code, and message, after asserting the call refused through +/// that record rather than a protocol error. +#[cfg(feature = "test-transport")] +pub(crate) fn tool_refusal(response: &Value) -> Value { + assert!( + response["error"].is_null(), + "the owner refuses through its problem record: {response}" + ); + let result = &response["result"]; + assert_eq!(result["isError"], true, "the call must refuse: {response}"); + let problem = &result["structuredContent"]["problem"]; + json!({ + "kind": problem["kind"], + "code": problem["code"], + "message": problem["message"], + }) +} + /// Polls the daemon-owned code-index search authority until an exact /// generation is bound and its native code graph is serving. /// @@ -588,7 +607,6 @@ pub(crate) async fn handle_tool_call( cg: &TraceDecay, tool_name: &str, mut args: serde_json::Value, - server_stats: Option, scope_prefix: Option<&str>, ) -> tracedecay_domain::errors::Result { let owns_format = tracedecay_mcp::tool_defaults_to_markdown(tool_name); @@ -606,11 +624,22 @@ pub(crate) async fn handle_tool_call( // // Every retained-surface tool (LCM, message search, fact store, session // and workflow reads) executes through the daemon retained owner in - // production, so dispatch it through the registered test server, which - // mounts that owner in process, rather than the bare registry path whose - // missing executor truthfully reports the transport as unavailable. + // production, and every graph-tool and profile registry read through its + // graph-tool or profile owner, so dispatch them through the registered + // test server, which mounts those owners in process, rather than the bare + // registry path whose missing executor truthfully reports the transport as + // unavailable. + #[cfg(feature = "test-transport")] + let retained = + tracedecay_contracts::RetainedSurfaceOperation::from_tool_name(tool_name).is_some(); + #[cfg(feature = "test-transport")] + let owner_answered = + tracedecay_tool_catalog::ApplicationSurfaceOperation::from_tool_name(tool_name) + .is_some_and(|operation| { + operation.is_graph_tool() || operation.is_profile_registry_read() + }); #[cfg(feature = "test-transport")] - if tracedecay_contracts::RetainedSurfaceOperation::from_tool_name(tool_name).is_some() { + if retained || owner_answered { let runtime = open_active_project_scoped_runtime(cg).await; // The daemon serves retained tools only for registered projects, so // mirror `real_mcp_server` and register this graph's identity in the @@ -630,7 +659,9 @@ pub(crate) async fn handle_tool_call( )) .await?; let server = Box::pin(McpServer::new_with_host_admission_test_runtime_for_test( - graph, None, runtime, + graph, + scope_prefix.map(str::to_owned), + runtime, )) .await?; if !server.has_project_application_retrieval_for_test() { @@ -677,18 +708,17 @@ pub(crate) async fn handle_tool_call( Ok(response["result"].clone()) } }; - let outcome = handle_retained_dispatch(tool_name, args, dispatch).await; + let outcome = if retained { + handle_retained_dispatch(tool_name, args, dispatch).await + } else { + dispatch(tool_name.to_owned(), args) + .await + .map(|result| ToolResult::new(result, Vec::new())) + }; server.shutdown().await; return outcome; } - Box::pin(tracedecay::mcp::handle_tool_call( - cg, - tool_name, - args, - server_stats, - scope_prefix, - )) - .await + Box::pin(tracedecay::mcp::handle_tool_call(cg, tool_name, args)).await } /// Dispatches `tool_name` through `dispatch`, recovers truncated responses @@ -758,33 +788,6 @@ where Ok(ToolResult::new(unwrapped, Vec::new())) } -#[cfg(feature = "test-transport")] -pub(crate) async fn handle_tool_call_with_runtime( - cg: &TraceDecay, - runtime: &HostAdmissionTestRuntimeV1, - tool_name: &str, - mut args: serde_json::Value, - server_stats: Option, - scope_prefix: Option<&str>, -) -> tracedecay_domain::errors::Result { - let owns_format = tracedecay_mcp::tool_defaults_to_markdown(tool_name); - if !owns_format && let Some(obj) = args.as_object_mut() { - obj.entry("format".to_string()) - .or_insert_with(|| serde_json::json!("json")); - } - Box::pin( - tracedecay::test_support::host_admission::call_mcp_tool_for_test( - runtime, - cg, - tool_name, - args, - server_stats, - scope_prefix, - ), - ) - .await -} - #[cfg(feature = "test-transport")] async fn handle_project_open_source_edit_tool_call( cg: &TraceDecay, @@ -856,7 +859,6 @@ pub(crate) async fn handle_production_source_edit_tool_call( fixture: &ProductionSourceEditFixture, tool_name: &str, mut args: Value, - _server_stats: Option, _scope_prefix: Option<&str>, ) -> tracedecay_domain::errors::Result { let owns_format = tracedecay_mcp::tool_defaults_to_markdown(tool_name); diff --git a/crates/tracedecay/tests/mcp_suite/workflow_query_test.rs b/crates/tracedecay/tests/mcp_suite/workflow_query_test.rs index 4a97ad226d..367d0f4fc4 100644 --- a/crates/tracedecay/tests/mcp_suite/workflow_query_test.rs +++ b/crates/tracedecay/tests/mcp_suite/workflow_query_test.rs @@ -244,7 +244,7 @@ async fn call( obj.entry("format".to_string()) .or_insert_with(|| json!("json")); } - let result = crate::support::handle_tool_call(cg, tool, args, None, None) + let result = crate::support::handle_tool_call(cg, tool, args, None) .await .unwrap_or_else(|e| panic!("{tool} should succeed: {e}")); extract_json(&result) @@ -272,7 +272,7 @@ async fn workflow_queries_distinguish_missing_schema_from_empty_results() { json!({"run_id": RUN_ID}), json!({"branch": "main"}), ] { - let error = crate::support::handle_tool_call(&cg, "tracedecay_workflows", args, None, None) + let error = crate::support::handle_tool_call(&cg, "tracedecay_workflows", args, None) .await .expect_err("a missing workflow index must be a retained problem") .to_string(); @@ -596,7 +596,7 @@ fn unbuilt_index_problem() -> Value { } async fn refuse(cg: &TraceDecay, args: Value) -> String { - crate::support::handle_tool_call(cg, "tracedecay_workflows", args, None, None) + crate::support::handle_tool_call(cg, "tracedecay_workflows", args, None) .await .expect_err("tracedecay_workflows should refuse this request") .to_string() From 01daa780ed6b7e6d1b3e9f79d501862d6e08a84a Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 27 Sep 2026 11:35:14 +0000 Subject: [PATCH 2/2] test(mcp): follow the dashboard and affected-tests owner cutover --- .../tracedecay-cli/src/tool_command/tests.rs | 44 + .../tests/core_cli_suite/tool_daemon_test.rs | 237 ++--- .../src/definitions/admin.rs | 2 +- .../src/tools/catalog_discovery.rs | 3 +- crates/tracedecay/src/daemon/projectless.rs | 5 +- crates/tracedecay/src/daemon/tests/socket.rs | 46 + .../src/mcp/server/graph_tool_owner.rs | 2 - .../src/mcp/tools/handlers/dispatch_groups.rs | 1 - .../src/mcp/tools/handlers/dispatch_tests.rs | 4 +- crates/tracedecay/tests/mcp_suite/support.rs | 20 +- sdks/typescript/src/operations.ts | 957 +++++++++++------- 11 files changed, 764 insertions(+), 557 deletions(-) diff --git a/crates/tracedecay-cli/src/tool_command/tests.rs b/crates/tracedecay-cli/src/tool_command/tests.rs index 37371ae279..6bcefc7fe8 100644 --- a/crates/tracedecay-cli/src/tool_command/tests.rs +++ b/crates/tracedecay-cli/src/tool_command/tests.rs @@ -1580,3 +1580,47 @@ fn application_surface_rejects_invalid_output_formats() { )); } } + +/// A `status` wait that ends `timed_out` is the retryable readiness refusal +/// the process exits 75 on, naming the last state; one that cannot reach its +/// state is the non-retryable refusal naming the reason; one that reached +/// exits 0. +#[test] +fn tool_status_exit_follows_the_wait_outcome() { + let status = |wait: Value| { + json!({ + "content": [{"type": "text", "text": "## Project Status"}], + "structuredContent": {"wait": wait}, + }) + }; + let refusal = |wait: Value| { + let error = tool_result_process_outcome(&status(wait), "tracedecay_status") + .expect_err("an unreached wait exits non-zero"); + error + .project_route_context() + .map(|(code, retryable, detail)| (code.to_owned(), retryable, detail.to_owned())) + .unwrap_or_else(|| panic!("the wait refusal is a typed route error: {error}")) + }; + + assert_eq!( + refusal(json!({"outcome": "timed_out", "last_state": "warming"})), + ( + CODE_INDEX_READINESS_WAIT_TIMED_OUT.to_owned(), + true, + "tracedecay_status wait_for timed out before the index reached the requested \ + state; last state: warming" + .to_owned(), + ) + ); + assert_eq!( + refusal(json!({"outcome": "unavailable", "reason": "scheduler_not_mounted"})), + ( + CODE_INDEX_READINESS_WAIT_UNAVAILABLE.to_owned(), + false, + "tracedecay_status wait_for cannot reach the requested state: scheduler_not_mounted" + .to_owned(), + ) + ); + tool_result_process_outcome(&status(json!({"outcome": "reached"})), "tracedecay_status") + .expect("a reached wait exits 0"); +} diff --git a/crates/tracedecay-cli/tests/core_cli_suite/tool_daemon_test.rs b/crates/tracedecay-cli/tests/core_cli_suite/tool_daemon_test.rs index 521cfc40d4..5086d2eb33 100644 --- a/crates/tracedecay-cli/tests/core_cli_suite/tool_daemon_test.rs +++ b/crates/tracedecay-cli/tests/core_cli_suite/tool_daemon_test.rs @@ -109,13 +109,7 @@ fn run_command_with_timeout(mut command: Command, timeout: Duration) -> Output { } enum FakeDaemonResponse { - Complete { - text: String, - }, - /// A whole tool result, for members beside `content`. - Result { - result: Value, - }, + Complete { text: String }, HoldOpen, } @@ -260,16 +254,6 @@ fn spawn_scripted_daemon( writeln!(writer, "{}", serde_json::to_string(&response).unwrap()) .expect("write fake daemon response"); } - FakeDaemonResponse::Result { result } => { - let response = json!({ - "jsonrpc": "2.0", - "id": request["id"].clone(), - "result": result, - }); - let mut writer = stream; - writeln!(writer, "{}", serde_json::to_string(&response).unwrap()) - .expect("write fake daemon response"); - } FakeDaemonResponse::HoldOpen => { // Keep the accepted socket open without writing a matching response. std::thread::sleep(CLI_CHILD_KILL_TIMEOUT + Duration::from_secs(2)); @@ -458,6 +442,37 @@ fn daemon_first_init_enrolls_a_clean_profile_from_a_linked_worktree() { ); } +/// Arguments for a tool the CLI still sends to the daemon as an MCP +/// `tools/call`. The scope set is absent, so the admitted project's +/// multi-root owner answers its concealed not-found problem. +const COMPAT_TOOL_PROBE: [&str; 4] = [ + "multi_root_scope_set_read", + "--scope-set-id", + "scope-set.absent", + "--json", +]; + +/// Asserts `output` is the multi-root owner's concealed not-found answer to +/// [`COMPAT_TOOL_PROBE`], which only an admitted project server gives. +fn assert_compat_probe_answered(output: &Output, context: &str) { + let stdout = String::from_utf8_lossy(&output.stdout); + let stderr = String::from_utf8_lossy(&output.stderr); + let result: Value = serde_json::from_str(stdout.trim()) + .unwrap_or_else(|error| panic!("{context}: {error}\nstdout:\n{stdout}\nstderr:\n{stderr}")); + let text = result["content"][0]["text"] + .as_str() + .unwrap_or_else(|| panic!("{context}: no probe text\nstdout:\n{stdout}")); + let payload: Value = serde_json::from_str(text).expect("probe payload json"); + assert_eq!( + ( + &result["isError"], + &payload["application"]["problem"]["kind"] + ), + (&json!(true), &json!("not_found_or_not_authorized")), + "{context}\nstdout:\n{stdout}\nstderr:\n{stderr}" + ); +} + /// Sends one MCP tool call through the daemon's project server, then reads /// that server's tool-call counter from its typed status. Until the full /// project server takes over from the core, the call and the status can land @@ -469,23 +484,11 @@ fn wait_for_tool_status_server_tool_calls(home: &Path, project: &Path) -> u64 { loop { let counted = tracedecay_command_with_home(home) .current_dir(project) - .args([ - "tool", - "--project", - &project_arg, - "dashboard", - "--action", - "stop", - "--json", - ]) + .args(["tool", "--project", &project_arg]) + .args(COMPAT_TOOL_PROBE) .output() - .expect("tracedecay tool dashboard should run"); - assert!( - counted.status.success(), - "dashboard stop should succeed\nstdout:\n{}\nstderr:\n{}", - String::from_utf8_lossy(&counted.stdout), - String::from_utf8_lossy(&counted.stderr) - ); + .expect("tracedecay tool multi_root_scope_set_read should run"); + assert_compat_probe_answered(&counted, "the probe must reach the project server"); let output = tracedecay_command_with_home(home) .current_dir(project) .args([ @@ -1210,7 +1213,7 @@ fn tool_cli_skips_daemon_notifications_until_matching_response() { let socket_path = socket_dir.path().join("tracedecay.sock"); let observed_request = spawn_sentinel_daemon_with_notification( socket_path.clone(), - "tracedecay_dashboard", + "tracedecay_multi_root_scope_set_read", true, false, sentinel, @@ -1220,15 +1223,8 @@ fn tool_cli_skips_daemon_notifications_until_matching_response() { let output = tracedecay_command_with_home(&home_path) .current_dir(&project_path) .env("TRACEDECAY_DAEMON_SOCKET", &socket_path) - .args([ - "tool", - "--project", - &project_arg, - "dashboard", - "--action", - "stop", - "--json", - ]) + .args(["tool", "--project", &project_arg]) + .args(COMPAT_TOOL_PROBE) .output() .expect("tracedecay tool should run"); @@ -1695,23 +1691,14 @@ fn daemon_project_handshake_uses_client_profile_identity() { "TRACEDECAY_DAEMON_SOCKET", common::daemon_socket_path(&daemon_home_path), ) - .args([ - "tool", - "--project", - &project_arg, - "dashboard", - "--action", - "stop", - "--json", - ]) + .args(["tool", "--project", &project_arg]) + .args(COMPAT_TOOL_PROBE) .output() - .expect("tracedecay tool status should run"); + .expect("tracedecay tool multi_root_scope_set_read should run"); - assert!( - output.status.success(), - "daemon should open the client's profile-sharded project\nstdout:\n{}\nstderr:\n{}", - String::from_utf8_lossy(&output.stdout), - String::from_utf8_lossy(&output.stderr) + assert_compat_probe_answered( + &output, + "daemon should open the client's profile-sharded project", ); } @@ -1890,38 +1877,22 @@ fn daemon_project_cache_is_scoped_by_client_identity() { let client_a_output = tracedecay_command_with_home(&client_a_home_path) .current_dir(&project_path) .env("TRACEDECAY_DAEMON_SOCKET", &socket_path) - .args([ - "tool", - "--project", - &project_arg, - "dashboard", - "--action", - "stop", - "--json", - ]) + .args(["tool", "--project", &project_arg]) + .args(COMPAT_TOOL_PROBE) .output() - .expect("client A tool status should run"); - assert!( - client_a_output.status.success(), - "client A should open its initialized project through the shared daemon\nstdout:\n{}\nstderr:\n{}", - String::from_utf8_lossy(&client_a_output.stdout), - String::from_utf8_lossy(&client_a_output.stderr) + .expect("client A tool multi_root_scope_set_read should run"); + assert_compat_probe_answered( + &client_a_output, + "client A should open its initialized project through the shared daemon", ); let client_b_output = tracedecay_command_with_home(&client_b_home_path) .current_dir(&project_path) .env("TRACEDECAY_DAEMON_SOCKET", &socket_path) - .args([ - "tool", - "--project", - &project_arg, - "dashboard", - "--action", - "stop", - "--json", - ]) + .args(["tool", "--project", &project_arg]) + .args(COMPAT_TOOL_PROBE) .output() - .expect("client B tool status should run"); + .expect("client B tool multi_root_scope_set_read should run"); assert!( !client_b_output.status.success(), "client B should not reuse client A's cached project server\nstdout:\n{}\nstderr:\n{}", @@ -1953,15 +1924,8 @@ fn tool_cli_without_daemon_socket_reports_daemon_unavailable() { let output = tracedecay_command_with_home(&home_path) .current_dir(&project_path) .env("TRACEDECAY_DAEMON_SOCKET", &missing_socket) - .args([ - "tool", - "--project", - &project_arg, - "dashboard", - "--action", - "stop", - "--json", - ]) + .args(["tool", "--project", &project_arg]) + .args(COMPAT_TOOL_PROBE) .output() .expect("tracedecay tool should run"); @@ -2774,77 +2738,10 @@ fn daemon_status_headline_is_the_daemon_when_the_service_manager_is_unreachable( assert!(lines.contains(&"protocol: Ready"), "{stdout}"); } -/// A `status` wait that ends `timed_out` prints the status and exits 75, the -/// retry-later status, naming the last state; a wait that reached exits 0. -#[test] -fn tool_status_exit_follows_the_wait_outcome() { - let home = TempDir::new().unwrap(); - let project = TempDir::new().unwrap(); - let home_path = canonical_existing_path(home.path()); - let project_path = canonical_existing_path(project.path()); - init_project_with_cli(&home_path, &project_path); - let run = |wait: Value| { - let socket_dir = TempDir::new().unwrap(); - let socket_path = socket_dir.path().join("tracedecay.sock"); - let observed = spawn_scripted_daemon( - socket_path.clone(), - "tracedecay_status", - FakeDaemonResponse::Result { - result: json!({ - "content": [{"type": "text", "text": "## Project Status\n- **wait**: …"}], - "structuredContent": {"wait": wait}, - }), - }, - ); - let mut command = tracedecay_command_with_home(&home_path); - command - .current_dir(&project_path) - .env("TRACEDECAY_DAEMON_SOCKET", &socket_path) - .args([ - "tool", - "status", - "--args", - r#"{"wait_for":{"state":"fresh","timeout_ms":1000}}"#, - ]); - let output = run_command_with_timeout(command, CLI_ROUNDTRIP_TIMEOUT); - let request = observed - .recv_timeout(CLI_ROUNDTRIP_TIMEOUT) - .expect("the status call reached the daemon"); - assert_eq!( - request["params"]["arguments"]["wait_for"], - json!({"state": "fresh", "timeout_ms": 1000}) - ); - output - }; - - let timed_out = run(json!({"outcome": "timed_out", "last_state": "warming"})); - let stderr = String::from_utf8_lossy(&timed_out.stderr); - assert_eq!(timed_out.status.code(), Some(75), "{stderr}"); - assert_eq!( - String::from_utf8_lossy(&timed_out.stdout), - "## Project Status\n- **wait**: …\n" - ); - assert!( - stderr.contains( - "tracedecay_status wait_for timed out before the index reached the requested \ - state; last state: warming" - ), - "{stderr}" - ); - - let reached = run(json!({"outcome": "reached"})); - assert_eq!( - reached.status.code(), - Some(0), - "{}", - String::from_utf8_lossy(&reached.stderr) - ); -} - /// A JSON request the daemon refuses because no project is in reach still /// prints the typed problem on stdout, and the process exits non-zero, on /// the owner-answered route (`search`) and the compatibility route -/// (`status`) alike. +/// (`multi_root_scope_set_read`) alike. #[test] fn projectless_json_tool_call_prints_the_typed_refusal() { let home = TempDir::new().unwrap(); @@ -2862,8 +2759,9 @@ fn projectless_json_tool_call_prints_the_typed_refusal() { assert_eq!(output.status.code(), Some(1), "{output:?}"); serde_json::from_slice::(&output.stdout).unwrap_or_else(|error| { panic!( - "stdout is not one JSON document ({error}): {}", - String::from_utf8_lossy(&output.stdout) + "stdout is not one JSON document ({error}): {}\nstderr:\n{}", + String::from_utf8_lossy(&output.stdout), + String::from_utf8_lossy(&output.stderr) ) }) }; @@ -2893,17 +2791,22 @@ fn projectless_json_tool_call_prints_the_typed_refusal() { inside an initialized project or pass --project " ); - let status = run(&["status", "--format", "json"]); + let compat = run(&[ + "multi_root_scope_set_read", + "--scope-set-id", + "scope-set.absent", + "--json", + ]); assert_eq!( - status, + compat, json!({"problem": { - "tool": "tracedecay_status", + "tool": "tracedecay_multi_root_scope_set_read", "kind": "invalid_request", "code": "project_required", "reason_code": "project_required", "retryable": false, - "detail": "tracedecay_status requires an initialized code project; run it inside \ - an initialized project or pass --project ", + "detail": "tracedecay_multi_root_scope_set_read requires an initialized code \ + project; run it inside an initialized project or pass --project ", }}) ); } diff --git a/crates/tracedecay-mcp-catalog/src/definitions/admin.rs b/crates/tracedecay-mcp-catalog/src/definitions/admin.rs index 515c7ebf6a..dc0501f36f 100644 --- a/crates/tracedecay-mcp-catalog/src/definitions/admin.rs +++ b/crates/tracedecay-mcp-catalog/src/definitions/admin.rs @@ -1,6 +1,6 @@ //! Project registry, runtime, and automation admin tool definitions. -use serde_json::{Value, json}; +use serde_json::Value; use super::{def, def_always_load, def_rw}; use crate::ToolDefinition; diff --git a/crates/tracedecay-mcp/src/tools/catalog_discovery.rs b/crates/tracedecay-mcp/src/tools/catalog_discovery.rs index 6d84503245..5748958323 100644 --- a/crates/tracedecay-mcp/src/tools/catalog_discovery.rs +++ b/crates/tracedecay-mcp/src/tools/catalog_discovery.rs @@ -467,7 +467,7 @@ mod tests { assert!( definitions .iter() - .any(|definition| definition.name == "tracedecay_status"), + .any(|definition| definition.name == "tracedecay_multi_root_execute"), "legacy production tools remain discoverable until cataloged" ); assert!( @@ -475,6 +475,7 @@ mod tests { definition.name != "tracedecay_search" && definition.name != "tracedecay_run_affected_tests" && definition.name != "tracedecay_dashboard" + && definition.name != "tracedecay_status" && definition.name != "tracedecay_context" && definition.name != "tracedecay_git_preview" }), diff --git a/crates/tracedecay/src/daemon/projectless.rs b/crates/tracedecay/src/daemon/projectless.rs index 97d3c7fa5d..0c9f474e2e 100644 --- a/crates/tracedecay/src/daemon/projectless.rs +++ b/crates/tracedecay/src/daemon/projectless.rs @@ -429,7 +429,10 @@ async fn projectless_registry_response( Err(error) => Err(error), }; match result { - Ok(result) => JsonRpcResponse::success(id, result.value), + Ok(mut result) => { + tracedecay_mcp::tool_errors::mark_semantic_tool_error(&mut result); + JsonRpcResponse::success(id, result.value) + } Err(error) => tool_error_response(id, tool_name, &error), } } diff --git a/crates/tracedecay/src/daemon/tests/socket.rs b/crates/tracedecay/src/daemon/tests/socket.rs index 1707521372..9036c1d10f 100644 --- a/crates/tracedecay/src/daemon/tests/socket.rs +++ b/crates/tracedecay/src/daemon/tests/socket.rs @@ -758,6 +758,23 @@ async fn projectless_project_list_reads_the_empty_profile_registry() { .await .expect("write tools/call"); writer.write_all(b"\n").await.expect("newline"); + writer + .write_all( + serde_json::to_string(&json!({ + "jsonrpc": "2.0", + "id": 9, + "method": "tools/call", + "params": { + "name": "tracedecay_project_list", + "arguments": {"format": "json", "limt": 5} + } + })) + .expect("tools/call json") + .as_bytes(), + ) + .await + .expect("write refused tools/call"); + writer.write_all(b"\n").await.expect("newline"); writer.shutdown().await.expect("shutdown writer"); let mut lines = tokio::io::BufReader::new(reader).lines(); @@ -781,6 +798,35 @@ async fn projectless_project_list_reads_the_empty_profile_registry() { "listing must name the registry it read: {payload}" ); + // A request outside the typed contract is the owner's refusal, flagged as + // a tool error rather than served as a listing. + let line = tokio::time::timeout(HALF_CLOSE_ROUND_TRIP_BOUND, lines.next_line()) + .await + .expect("refused project list should not time out") + .expect("read refusal") + .expect("projectless refusal"); + let refused: Value = serde_json::from_str(&line).expect("refusal json"); + let result = &refused["result"]; + assert_eq!( + ( + &refused["id"], + &result["isError"], + &result["problem"]["kind"], + &result["problem"]["code"], + &result["problem"]["message"], + ), + ( + &json!(9), + &json!(true), + &json!("invalid_request"), + &json!("application.surface.invalid_request"), + &json!( + "invalid arguments for tracedecay_project_list: unknown field `limt`, expected `limit`" + ), + ), + "{refused}" + ); + server_task .await .expect("server task should complete") diff --git a/crates/tracedecay/src/mcp/server/graph_tool_owner.rs b/crates/tracedecay/src/mcp/server/graph_tool_owner.rs index b10086c2fc..b98ae72805 100644 --- a/crates/tracedecay/src/mcp/server/graph_tool_owner.rs +++ b/crates/tracedecay/src/mcp/server/graph_tool_owner.rs @@ -59,8 +59,6 @@ impl McpServer { self.profile_session_db.as_ref(), ), server_stats, - doctor_report_reader: self.dashboard_doctor_report_reader.clone(), - remote_operational_status: self.remote_operational_status.clone(), code_index_readiness_waiter: self.code_index_readiness_waiter.clone(), generation_census_reader: self.generation_census_reader(), registered_project_session_db: self.project_session_db.clone(), diff --git a/crates/tracedecay/src/mcp/tools/handlers/dispatch_groups.rs b/crates/tracedecay/src/mcp/tools/handlers/dispatch_groups.rs index a4bea05a5a..b4bcbd45b1 100644 --- a/crates/tracedecay/src/mcp/tools/handlers/dispatch_groups.rs +++ b/crates/tracedecay/src/mcp/tools/handlers/dispatch_groups.rs @@ -12,7 +12,6 @@ use tracedecay_project::project::TraceDecay; use tracedecay_contracts::code_index_freshness::{ CodeIndexFreshnessReader, CodeIndexReadinessWaitOutcomeV1, CodeIndexReadinessWaitV1, }; -use tracedecay_contracts::graph_tool::GraphToolResultV1; use tracedecay_contracts::retrieval::{ ActiveProjectSurfaceRequestV1, RemoteStatusSurfaceRequestV1, RuntimeSurfaceRequestV1, StatusSurfaceRequestV1, diff --git a/crates/tracedecay/src/mcp/tools/handlers/dispatch_tests.rs b/crates/tracedecay/src/mcp/tools/handlers/dispatch_tests.rs index 725c6844d8..4e6bdb001f 100644 --- a/crates/tracedecay/src/mcp/tools/handlers/dispatch_tests.rs +++ b/crates/tracedecay/src/mcp/tools/handlers/dispatch_tests.rs @@ -579,12 +579,10 @@ async fn status_wait_outcome_rides_beside_the_body_and_the_budget_refusal_names_ }) }); let status = |args: Value| { - handle_tool_call_with_registry_options( + dispatch_on_graph_authority( &cg, "tracedecay_status", args, - None, - None, ToolCallRegistryOptions { code_index_readiness_waiter: Some(std::sync::Arc::clone(&waiter)), ..Default::default() diff --git a/crates/tracedecay/tests/mcp_suite/support.rs b/crates/tracedecay/tests/mcp_suite/support.rs index 0fa66572a9..55bd8b8909 100644 --- a/crates/tracedecay/tests/mcp_suite/support.rs +++ b/crates/tracedecay/tests/mcp_suite/support.rs @@ -624,11 +624,12 @@ pub(crate) async fn handle_tool_call( // // Every retained-surface tool (LCM, message search, fact store, session // and workflow reads) executes through the daemon retained owner in - // production, and every graph-tool and profile registry read through its - // graph-tool or profile owner, so dispatch them through the registered - // test server, which mounts those owners in process, rather than the bare - // registry path whose missing executor truthfully reports the transport as - // unavailable. + // production, and the project-info and profile registry reads through the + // serving server's graph-tool or profile owner, which alone holds the + // request counters and scope prefix `tracedecay_status` reports, so + // dispatch them through the registered test server, which mounts those + // owners in process, rather than the bare registry path whose missing + // executor truthfully reports the transport as unavailable. #[cfg(feature = "test-transport")] let retained = tracedecay_contracts::RetainedSurfaceOperation::from_tool_name(tool_name).is_some(); @@ -636,7 +637,14 @@ pub(crate) async fn handle_tool_call( let owner_answered = tracedecay_tool_catalog::ApplicationSurfaceOperation::from_tool_name(tool_name) .is_some_and(|operation| { - operation.is_graph_tool() || operation.is_profile_registry_read() + operation.is_profile_registry_read() + || matches!( + operation, + tracedecay_tool_catalog::ApplicationSurfaceOperation::Status + | tracedecay_tool_catalog::ApplicationSurfaceOperation::ActiveProject + | tracedecay_tool_catalog::ApplicationSurfaceOperation::RemoteStatus + | tracedecay_tool_catalog::ApplicationSurfaceOperation::Runtime + ) }); #[cfg(feature = "test-transport")] if retained || owner_answered { diff --git a/sdks/typescript/src/operations.ts b/sdks/typescript/src/operations.ts index 83d8a7a7a4..1a5f04c49a 100644 --- a/sdks/typescript/src/operations.ts +++ b/sdks/typescript/src/operations.ts @@ -31,6 +31,9 @@ export type AcceptWorkTaskRequestV1 = { readonly evidence_by_criterion: { readon export type AccessPolicyDigest = string; export type AccessRuleId = string; export type ActivationDriftV1 = "current" | "never_activated" | "pending_restart" | "activation_failed"; +export type ActiveProjectBranchV1 = { readonly branch_drifted: boolean; readonly branch_resolution: string; readonly current_branch?: string | null; readonly open_active_branch?: string | null; readonly serving_branch?: string | null; readonly tracked_branch_count: number; readonly warnings: readonly string[] }; +export type ActiveProjectResolutionSourceV1 = "active_project"; +export type ActiveProjectStorageV1 = { readonly class: string; readonly data_root: string; readonly graph_db_exists: boolean; readonly graph_db_path: string; readonly graph_db_size_bytes: number; readonly lcm_payload_root: string; readonly mode: string; readonly response_handle_root: string; readonly sessions_db_path: string }; export type ActorId = string; export type AddWorkTaskRequestV1 = { readonly item: WorkItemV1; readonly mutation: WorkProductMutationIdentityV1; readonly selection: WorkProductSelectionScopeV1 }; export type AdjudicateWorkLeakCommandV1 = { readonly adjudication_id: string; readonly attempt: WorkAttemptIdentityV1; readonly command_id: WorkCommandId; readonly detection_horizon_micros: number; readonly expected_revision?: number | null }; @@ -81,6 +84,7 @@ export type ApplyWorkRelationReplanRequestV1 = { readonly mutation: WorkProductM export type AstGrepResult = { readonly diff?: string | null; readonly dry_run?: boolean; readonly file_path: string; readonly message: string; readonly pattern: string; readonly rewrite: string; readonly success: boolean; readonly [key: string]: unknown }; export type AstGrepSearchMatchV1 = { readonly column: number; readonly file: string; readonly lang: string; readonly line: number; readonly line_text: string; readonly match: string }; export type AttemptId = string; +export type AuthorityEpoch = number; export type AuthorityReceipt = { readonly authorized_scope_digest: ManifestDigest; readonly disclosure: DisclosureClass; readonly grant_digest: ManifestDigest; readonly grant_id: string; readonly grant_revision: number; readonly policy: PolicyDecisionRef; readonly revalidated_at: UtcMicros }; export type AuthorityRef = { readonly id: ProjectId; readonly kind: "project"; readonly [key: string]: unknown } | { readonly id: UserProfileId; readonly kind: "projectless_hermes"; readonly [key: string]: unknown }; export type AuthorizedRoot = { readonly locator?: RegisteredRootLocatorV1 | null; readonly scope: ResolvedScope }; @@ -108,6 +112,7 @@ export type AutomationTaskSettingsV1 = { readonly cooldown_secs?: number | null; export type AutomationTaskV1 = "memory_curator" | "session_reflector" | "skill_writer" | "combined_review" | "user_job"; export type AutomationTrigger = "manual_cli" | "manual_mcp" | "dashboard" | "application" | "scheduler" | "host_receipt"; export type BrainId = string; +export type BrainNodeId = string; export type BranchCollisionPolicyV1 = { readonly kind: "reject"; readonly [key: string]: unknown } | { readonly kind: "append_monotonic_ordinal"; readonly maximum_attempts: number; readonly [key: string]: unknown }; export type BranchDiffCompleteV1 = { readonly base: string; readonly base_generation: string; readonly base_revision: string; readonly base_tree: string; readonly changes: readonly BranchSymbolChangeV1[]; readonly head: string; readonly head_generation: string; readonly head_revision: string; readonly head_tree: string; readonly status: GitReadCompleteV1; readonly summary: BranchDiffSummaryV1; readonly total_changes: number }; export type BranchDiffPartialV1 = { readonly base: string; readonly base_generation: string; readonly base_revision: string; readonly base_tree: string; readonly changes: readonly BranchSymbolChangeV1[]; readonly head: string; readonly head_generation: string; readonly head_revision: string; readonly head_tree: string; readonly next_cursor: string; readonly reason: GitResultLimitV1; readonly status: GitReadPartialV1; readonly summary: BranchDiffSummaryV1; readonly total_changes: number }; @@ -149,14 +154,30 @@ export type ChangelogCompleteV1 = { readonly base_generation: string; readonly c export type ChangelogPartialV1 = { readonly changed_file_count: number; readonly changed_files: readonly string[]; readonly from_ref: string; readonly status: GitReadPartialV1; readonly symbol_changes_coverage: SymbolChangesUnavailableV1; readonly symbols_added: readonly GitComparedSymbolV1[]; readonly symbols_modified: readonly GitComparedSymbolV1[]; readonly symbols_removed: readonly GitComparedSymbolV1[]; readonly to_ref: string }; export type CircularCycleV1 = { readonly member_count: number; readonly members: readonly string[]; readonly omitted_member_count: number }; export type ClosedUtcIntervalV1 = { readonly from_inclusive?: number | null; readonly through_inclusive?: number | null }; +export type CodeCloneIndexBudgetsV1 = { readonly candidate_bodies: number; readonly hot_posting_rows: number; readonly minimum_body_tokens: number; readonly minimum_directional_coverage_millionths: number; readonly posting_rows: number; readonly verification_bodies: number; readonly verification_token_work: number; readonly [key: string]: unknown }; +export type CodeCloneIndexCoverageV1 = { readonly conservative_normalized_bodies?: number | null; readonly eligible_source_bodies?: number | null; readonly exact_postings?: number | null; readonly excluded_incomplete_tokenization_bodies?: number | null; readonly excluded_too_large_bodies?: number | null; readonly excluded_too_small_bodies?: number | null; readonly hot_posting_rows_skipped?: number | null; readonly hot_postings_skipped?: number | null; readonly near_fingerprint_bodies?: number | null; readonly near_fingerprint_postings?: number | null; readonly payloads_reused?: number | null; readonly rename_normalized_bodies?: number | null; readonly rename_partial_bodies?: number | null; readonly rename_unsupported_bodies?: number | null; readonly source_bodies?: number | null; readonly unique_payloads?: number | null; readonly [key: string]: unknown }; +export type CodeCloneIndexObservationV1 = { readonly artifact_format_revision?: number | null; readonly budgets: CodeCloneIndexBudgetsV1; readonly conservative_normalization_revision: number; readonly coverage: CodeCloneIndexCoverageV1; readonly generation_id: string; readonly rename_normalization_revision: number; readonly resources: CodeCloneIndexResourcesV1; readonly source_revision?: string | null; readonly [key: string]: unknown }; +export type CodeCloneIndexResourcesV1 = { readonly bytes_on_disk?: number | null; readonly changed_symbol_update_micros?: number | null; readonly peak_scratch_memory_bytes?: number | null; readonly stale_invalidations?: number | null; readonly [key: string]: unknown }; +export type CodeCloneIndexStatusV1 = { readonly reason: string; readonly state: "unavailable"; readonly [key: string]: unknown } | { readonly observation: CodeCloneIndexObservationV1; readonly omission_reasons: readonly string[]; readonly state: "partial"; readonly [key: string]: unknown } | { readonly observation: CodeCloneIndexObservationV1; readonly state: "ready"; readonly [key: string]: unknown } | { readonly observation: CodeCloneIndexObservationV1; readonly reason: string; readonly state: "stale"; readonly [key: string]: unknown }; export type CodeFacetDimension = "kind" | "language" | "path"; export type CodeFacetRecord = { readonly count: number; readonly dimension: CodeFacetDimension; readonly value: string }; export type CodeGenerationId = string; export type CodeGraphReadFreshnessV1 = { readonly state: "current"; readonly [key: string]: unknown } | { readonly rebuild_in_flight: boolean; readonly sealed_at: UtcMicros; readonly state: "last_complete_stale"; readonly [key: string]: unknown }; +export type CodeGraphServingReadinessV1 = { readonly reason: string; readonly state: "unavailable"; readonly [key: string]: unknown } | { readonly state: "pending"; readonly [key: string]: unknown } | { readonly reason: string; readonly state: "refused"; readonly [key: string]: unknown } | { readonly state: "ready"; readonly [key: string]: unknown }; export type CodeIndexBuildBlockedReasonV1 = "resident_memory" | "source_unavailable" | "artifact_store_unavailable" | "retry_backoff" | "publication_authority_corrupt"; +export type CodeIndexBuildPhaseV1 = "source_scan" | "relational_preparation" | "bulk_commit" | "index_build" | "verification" | "ready"; +export type CodeIndexBuildProgressV1 = { readonly blocked_reason?: CodeIndexBuildBlockedReasonV1 | null; readonly committed_chunks: number; readonly committed_imports: number; readonly committed_pages: number; readonly committed_payload_bytes: number; readonly completed_files: number; readonly completed_lexical_units: number; readonly current_batch_pages: number; readonly current_batch_payload_bytes: number; readonly daemon_incarnation: number; readonly elapsed_micros: number; readonly estimated_remaining_seconds?: number | null; readonly files_per_second?: number | null; readonly generation_id: string; readonly last_commit_latency_micros?: number | null; readonly last_progress_micros: number; readonly lexical_units_per_second?: number | null; readonly phase: CodeIndexBuildPhaseV1; readonly producer_incarnation: number; readonly progress_epoch: number; readonly sealed_source_digest: string; readonly total_files: number; readonly total_lexical_units: number; readonly [key: string]: unknown }; export type CodeIndexConvergenceParkedV1 = { readonly blocked_reason?: CodeIndexBuildBlockedReasonV1 | null; readonly observed_passes: number; readonly parked_at_micros: number; readonly reason: string; readonly remediation: string; readonly retries_on_wake: boolean; readonly [key: string]: unknown }; +export type CodeIndexFreshnessCoverageV1 = "unobserved" | "complete" | "partial_refresh_in_progress" | "partial_artifact_restore" | "partial_source_verification" | "partial_unverified_restore" | "partial_hook_hint_overflow"; +export type CodeIndexGenerationRecoveryServingV1 = "preserved" | "refused"; +export type CodeIndexGenerationRecoveryV1 = { readonly incompatibilities: readonly string[]; readonly incompatible_generation_id: string; readonly serving: CodeIndexGenerationRecoveryServingV1; readonly [key: string]: unknown }; +export type CodeIndexReadinessTargetV1 = "fresh" | "ready" | "graph_ready"; +export type CodeIndexReadinessWaitOutcomeV1 = { readonly outcome: "reached"; readonly [key: string]: unknown } | { readonly last_state: string; readonly outcome: "timed_out"; readonly [key: string]: unknown } | { readonly outcome: "unavailable"; readonly reason: string; readonly [key: string]: unknown }; +export type CodeIndexReadinessWaitV1 = { readonly state: CodeIndexReadinessTargetV1; readonly timeout_ms: number }; +export type CodeIndexRestoreProgressV1 = { readonly artifact_digest: string; readonly authenticated_completed: number; readonly authenticated_remaining: number; readonly authenticated_total: number; readonly generation_id: string; readonly [key: string]: unknown }; export type CodeIndexStalenessStateV1 = "fresh" | "stale" | "indexing" | "refreshing" | "restoring" | "verifying" | "parked"; export type CodeIndexWorkerSelectionV1 = { readonly mode: "automatic" } | { readonly mode: "exact"; readonly workers: number }; +export type CodeIndexWorktreeFreshnessV1 = { readonly clone_index?: CodeCloneIndexStatusV1 | null; readonly code_graph_serving?: CodeGraphServingReadinessV1 | null; readonly coverage: CodeIndexFreshnessCoverageV1; readonly generation_recovery?: CodeIndexGenerationRecoveryV1 | null; readonly hook_hint_count?: number | null; readonly last_reconcile_micros?: number | null; readonly latest_generation_id?: string | null; readonly parked?: CodeIndexConvergenceParkedV1 | null; readonly progress?: CodeIndexBuildProgressV1 | null; readonly rebuild_in_flight?: boolean; readonly repository_id?: string | null; readonly restore_progress?: CodeIndexRestoreProgressV1 | null; readonly sealed_at_micros?: number | null; readonly snapshot_content_identity?: string | null; readonly source_reference?: string | null; readonly source_revision?: string | null; readonly staleness_state?: CodeIndexStalenessStateV1 | null; readonly worktree_id?: string | null; readonly worktree_root: string; readonly [key: string]: unknown }; export type CodeLexicalField = "symbol_name" | "qualified_name" | "path" | "signature" | "documentation" | "body_text" | "preamble_text" | "exact_term" | "subtoken"; export type CodeLexicalFieldFilter = { readonly field: CodeLexicalField; readonly include: boolean }; export type CodeOccurrenceRecord = { readonly chunk?: CodeSearchChunkId | null; readonly file: FileOccurrenceId; readonly path: string; readonly span: SourceSpan; readonly symbol?: SymbolOccurrenceId | null }; @@ -253,6 +274,8 @@ export type CreateWorkTaskRequestV1 = { readonly initiative: WorkInitiativeV1; r export type CredentialReferenceId = string; export type CrossMergeModeV1 = "disabled" | "manual_receipt_only" | "fast_forward_only" | "merge_commit" | "cherry_pick_exact_commits"; export type CrossMergePolicyV1 = { readonly allow_cross_repository: boolean; readonly allowed_modes: readonly CrossMergeModeV1[]; readonly default_mode: CrossMergeModeV1 }; +export type CurrentRemoteAuthorityStateV1 = { readonly state: "available"; readonly value: CurrentRemoteAuthorityV1; readonly [key: string]: unknown } | { readonly state: "partial"; readonly value: { readonly known_fence?: RemoteWriterFenceV1 | null; readonly missing: readonly RemoteAuthorityUnavailableReasonV1[]; readonly observed_at: UtcMicros; readonly [key: string]: unknown }; readonly [key: string]: unknown } | { readonly state: "unavailable"; readonly value: { readonly observed_at: UtcMicros; readonly reason: RemoteAuthorityUnavailableReasonV1; readonly [key: string]: unknown }; readonly [key: string]: unknown }; +export type CurrentRemoteAuthorityV1 = { readonly credential_revision: number; readonly fence: RemoteWriterFenceV1; readonly observed_at: UtcMicros }; export type DashboardActionV1 = "start" | "stop"; export type DeadCodeSymbolV1 = { readonly file: string; readonly id: string; readonly kind: string; readonly line: number; readonly name: string; readonly signature?: string | null }; export type Deadline = { readonly expires_at: UtcMicros }; @@ -280,6 +303,20 @@ export type DistributionFileV1 = { readonly file: string; readonly kinds: readon export type DistributionKindCountV1 = { readonly count: number; readonly kind: string }; export type DocCoverageFileV1 = { readonly count: number; readonly file: string; readonly symbols: readonly DocCoverageSymbolV1[] }; export type DocCoverageSymbolV1 = { readonly id: string; readonly kind: string; readonly line: number; readonly name: string; readonly signature?: string | null }; +export type DoctorCoverageCompletenessV1 = "complete" | "partial" | "unknown"; +export type DoctorCoverageStatementV1 = { readonly completeness: DoctorCoverageCompletenessV1; readonly statement: string; readonly [key: string]: unknown }; +export type DoctorEvidenceRefV1 = { readonly family: DoctorFindingFamilyV1; readonly reference: DoctorEvidenceReferenceV1; readonly [key: string]: unknown }; +export type DoctorEvidenceReferenceV1 = string; +export type DoctorEvidenceStateV1 = "unsupported" | "absent" | "stale" | "degraded" | "partial" | "unknown" | "denied" | "healthy_complete_coverage"; +export type DoctorFamilyConsultationV1 = { readonly status: "consulted"; readonly [key: string]: unknown } | { readonly reason: DoctorFamilyUnavailableReasonV1; readonly status: "unavailable"; readonly [key: string]: unknown }; +export type DoctorFamilyCoverageV1 = { readonly consultation: DoctorFamilyConsultationV1; readonly family: DoctorFindingFamilyV1; readonly [key: string]: unknown }; +export type DoctorFamilyUnavailableReasonV1 = "unwired" | "unsupported" | "absent" | "denied" | "unknown" | "unavailable" | "reset_required" | "corrupt"; +export type DoctorFindingFamilyV1 = "advisory" | "configuration" | "storage_runtime" | "storage" | "language_server" | "code_index" | "observability" | "memory"; +export type DoctorFindingV1 = { readonly coverage: DoctorCoverageStatementV1; readonly evidence: readonly DoctorEvidenceRefV1[]; readonly family: DoctorFindingFamilyV1; readonly state: DoctorEvidenceStateV1; readonly [key: string]: unknown }; +export type DoctorReportCoverageV1 = { readonly completeness: DoctorCoverageCompletenessV1; readonly families: readonly DoctorFamilyCoverageV1[]; readonly statement: DoctorCoverageStatementV1; readonly [key: string]: unknown }; +export type DoctorReportEntryV1 = { readonly finding: DoctorFindingV1; readonly storage_kind?: DoctorStorageFindingKindV1 | null; readonly [key: string]: unknown }; +export type DoctorReportV1 = { readonly coverage: DoctorReportCoverageV1; readonly entries: readonly DoctorReportEntryV1[]; readonly [key: string]: unknown }; +export type DoctorStorageFindingKindV1 = "over_budget_store" | "orphan_store" | "incident_debris_present" | "retention_backlog" | "table_growth" | "pending_schema_migration"; export type DsmClusterV1 = { readonly boundary_edges: number; readonly directory: string; readonly file_count: number; readonly incoming_edges: number; readonly internal_edges: number; readonly outgoing_edges: number }; export type DsmMatrixV1 = { readonly files: readonly string[]; readonly matrix: readonly (readonly number[])[]; readonly note: string }; export type DsmShapeV1 = "stats" | "clusters" | "matrix"; @@ -493,6 +530,10 @@ export type IndexedFileV1 = { readonly bytes: number; readonly path: string; rea export type InheritanceDepthEntryV1 = { readonly depth: number; readonly file: string; readonly id: string; readonly kind: string; readonly line: number; readonly name: string }; export type InsertResult = { readonly anchor_line: number; readonly before: boolean; readonly content: string; readonly diff?: string | null; readonly dry_run?: boolean; readonly file_path: string; readonly message: string; readonly success: boolean; readonly [key: string]: unknown }; export type InvestigationHandoffSurfaceV1 = { readonly finding_id: FeedbackFindingId; readonly owner_version_digest: ManifestDigest }; +export type LanguageServerAnalyzerStateV1 = "ready" | "available" | "refreshing" | "disabled" | "unavailable" | "crashed" | "inactive"; +export type LanguageServerAnalyzerV1 = { readonly command: string; readonly detail?: string | null; readonly executable_found: boolean; readonly install?: string | null; readonly language: string; readonly state: LanguageServerAnalyzerStateV1; readonly [key: string]: unknown }; +export type LanguageServerReadV1 = { readonly analyzers?: readonly LanguageServerAnalyzerV1[]; readonly coverage: DoctorCoverageCompletenessV1; readonly kind: "observed"; readonly state: LanguageServerStateV1; readonly [key: string]: unknown } | { readonly kind: "unsupported"; readonly [key: string]: unknown } | { readonly analyzers?: readonly LanguageServerAnalyzerV1[]; readonly kind: "absent"; readonly [key: string]: unknown } | { readonly kind: "denied"; readonly [key: string]: unknown } | { readonly kind: "unknown"; readonly [key: string]: unknown }; +export type LanguageServerStateV1 = "ready" | "available" | "refreshing" | "disabled" | "unavailable" | "crashed"; export type LargestEntryV1 = { readonly end_line: number; readonly file: string; readonly id: string; readonly kind: string; readonly lines: number; readonly name: string; readonly start_line: number }; export type LatencyDistributionReadModelV1 = { readonly p50: MetricValueV1; readonly p95: MetricValueV1; readonly p99: MetricValueV1; readonly [key: string]: unknown }; export type LcmAuthorityOutcomeV1 = { readonly state: "ready"; readonly [key: string]: unknown } | { readonly state: "denied"; readonly [key: string]: unknown } | { readonly state: "cancelled"; readonly [key: string]: unknown } | { readonly state: "timed_out"; readonly [key: string]: unknown } | { readonly reason: string; readonly state: "unavailable"; readonly [key: string]: unknown } | { readonly diagnostic: string; readonly state: "failed"; readonly [key: string]: unknown }; @@ -692,6 +733,10 @@ export type PrimitiveSymbolLocationV1 = { readonly end_line: number; readonly fi export type PrimitiveUnavailableEvidenceV1 = { readonly detail: string; readonly reason_code: string; readonly retryable: boolean; readonly status: PrimitiveUnavailableStatusV1 }; export type PrimitiveUnavailableStatusV1 = "unavailable"; export type ProjectId = string; +export type ProjectRegistryEntry = { readonly alias_count: number; readonly artifact_count: number; readonly branches: readonly string[]; readonly canonical_root: string; readonly default_branch?: string | null; readonly head_branch?: string | null; readonly is_active?: boolean | null; readonly kind: string; readonly label: string; readonly last_seen_at: number; readonly project_id: string; readonly project_root: string; readonly store_count: number; readonly [key: string]: unknown }; +export type ProjectRegistrySummary = { readonly project_count: number; readonly repo_count: number; readonly truncated: boolean; readonly [key: string]: unknown }; +export type ProjectRepoGroup = { readonly branches: readonly string[]; readonly git_common_dir?: string | null; readonly label: string; readonly project_count: number; readonly projects: readonly ProjectRegistryEntry[]; readonly [key: string]: unknown }; +export type ProjectStatusV1 = { readonly active_branch?: string | null; readonly branch_diagnostics?: unknown; readonly branch_drifted?: boolean | null; readonly branch_mismatch?: StatusBranchMismatchV1 | null; readonly branch_resolution?: string | null; readonly branch_warnings?: readonly string[] | null; readonly code_index_freshness: StatusCodeIndexFreshnessV1; readonly code_index_freshness_warning?: string | null; readonly current_branch?: string | null; readonly git_staleness?: StatusGitStalenessV1 | null; readonly github_source: unknown; readonly graph_statistics: unknown; readonly live_branch?: string | null; readonly memory: StatusMemoryV1; readonly parent_branch?: string | null; readonly project_root: string; readonly reset_required_stores: readonly StoreResetRequiredV1[]; readonly retrieval_serving?: StatusRetrievalServingV1 | null; readonly schema_convergence: StatusSchemaConvergenceV1; readonly scope_prefix?: string | null; readonly server?: unknown; readonly serving_branch?: string | null; readonly session_history_catch_up?: unknown; readonly session_ingest?: unknown; readonly storage_health?: unknown; readonly tracked_branch_count?: number | null; readonly wait?: CodeIndexReadinessWaitOutcomeV1 | null }; export type ProjectionGenerationId = string; export type ProposalId = string; export type ProtectedChange = { readonly kind: "bind_source"; readonly value: ScopeSourceBinding; readonly [key: string]: unknown } | { readonly kind: "rebind_source"; readonly value: ScopeSourceBinding; readonly [key: string]: unknown } | { readonly kind: "unbind_source"; readonly value: { readonly binding_id: SourceBindingId; readonly [key: string]: unknown }; readonly [key: string]: unknown } | { readonly kind: "upsert_access_rule"; readonly value: ScopeAccessRule; readonly [key: string]: unknown } | { readonly kind: "remove_access_rule"; readonly value: { readonly rule_id: AccessRuleId; readonly [key: string]: unknown }; readonly [key: string]: unknown } | { readonly kind: "replace_work_topology_policy"; readonly value: WorkTopologyPolicyV1; readonly [key: string]: unknown }; @@ -705,6 +750,7 @@ export type ProviderLatencyReadModelV1 = { readonly first_progress: LatencyDistr export type ProximityAddressV1 = { readonly file: FileOccurrenceId; readonly scope: FeedbackScopeV1; readonly span?: SourceSpan | null; readonly symbol?: SymbolOccurrenceId | null }; export type ProximityCoverageV1 = "complete" | "partial" | "stale" | "unavailable" | "denied" | "private"; export type ProximityWarningClassV1 = "same_file" | "overlapping_range" | "same_symbol" | "same_package" | "same_crate" | "neighborhood" | "shared_caller" | "shared_dependency" | "shared_test" | "incompatible_branch_worktree"; +export type PublicCodeProject = { readonly canonical_root: string; readonly created_at: number; readonly default_branch?: string | null; readonly display_root: string; readonly git_common_dir?: string | null; readonly head_branch?: string | null; readonly is_active?: boolean | null; readonly label: string; readonly last_seen_at: number; readonly project_id: string; readonly project_root: string; readonly [key: string]: unknown }; export type QuantityEvidenceClassV1 = "owner_receipt" | "locally_measured" | "estimated" | "unknown"; export type QueryCollectionId = string; export type RankDirectionV1 = "incoming" | "outgoing"; @@ -732,6 +778,12 @@ export type RejectedArgumentErrorClassV1 = "missing" | "invalid_shape" | "out_of export type RejectedArgumentGroupV1 = { readonly argument: RejectedArgumentNameV1; readonly count: number; readonly error_class: RejectedArgumentErrorClassV1; readonly operation: string; readonly rate?: number | null; readonly surface: RejectedArgumentSurfaceV1; readonly [key: string]: unknown }; export type RejectedArgumentNameV1 = "request_body" | "pagination" | "request_handle" | "operation" | "lifecycle" | "unknown"; export type RejectedArgumentSurfaceV1 = "cli" | "mcp" | "http" | "unknown"; +export type RemoteAuthorityUnavailableReasonV1 = "registry_unavailable" | "placement_unknown" | "authority_unreachable" | "authority_authentication_failed" | "caller_authentication_failed" | "enrollment_expired" | "enrollment_revoked" | "insufficient_capability" | "scope_mismatch" | "fence_unverified" | "protocol_incompatible"; +export type RemoteListenerReadV1 = "serving" | "disabled" | "degraded"; +export type RemoteOperationalReadinessV1 = "unconfigured" | "partial" | "ready" | "recovery_required"; +export type RemoteOperationalStatusV1 = { readonly authority: CurrentRemoteAuthorityStateV1; readonly enrollment_configured: boolean; readonly failover_in_progress: boolean; readonly observed_at: UtcMicros; readonly readiness: RemoteOperationalReadinessV1; readonly recovery_required: boolean; readonly replay_coverage_complete: boolean; readonly spool: RemoteSpoolOperationalStatusV1 }; +export type RemoteSpoolOperationalStatusV1 = { readonly has_sequence_gap: boolean; readonly pending_count: number; readonly quarantined_count: number }; +export type RemoteWriterFenceV1 = { readonly authority_epoch: AuthorityEpoch; readonly authority_node_id: BrainNodeId; readonly brain_id: BrainId; readonly generation_id: ProjectionGenerationId; readonly placement_revision: number; readonly shard_id: ShardId }; export type RenameDispositionCountsV1 = { readonly blocked: number; readonly changed: number; readonly skipped: number; readonly unchanged: number }; export type RenameFileEditV1 = { readonly file: string; readonly replaced_count: number }; export type RenameHazardKindV1 = "invalid_identifier" | "stale_evidence" | "ambiguous_symbol" | "namespace_collision" | "changed_resolution" | "shadowing" | "unsupported_syntax" | "macro_expansion" | "generated_source" | "overlapping_site"; @@ -757,6 +809,7 @@ export type RepositoryWorkingTreeSnapshotV1 = { readonly ignored_collision_diges export type RepositoryWorkingTreeStateV1 = "clean" | "tracked_dirty" | "untracked_only" | "mixed" | "conflicted" | "unreadable"; export type RequiredCheckExpectationV1 = "successful_terminal"; export type RequiredCheckV1 = { readonly capability_id: CapabilityId; readonly expectation: RequiredCheckExpectationV1; readonly maximum_age_seconds: number }; +export type ResidentMemoryHolderReadV1 = { readonly holding: string; readonly worktree_id: string; readonly [key: string]: unknown }; export type ResolvedScope = { readonly project_id: ProjectId; readonly reference?: RefId | null; readonly repository_id: RepositoryId; readonly scope_digest: ManifestDigest; readonly worktree_id: WorktreeId }; export type RestartRequirementV1 = "none" | "analyzer_restart" | "daemon_restart"; export type ResultProjection = "summary" | "evidence" | "references_only"; @@ -784,10 +837,15 @@ export type RootScopeOutcomeV1ForNullableRootGenerationV1 = { readonly outcome: export type RootScopeOutcomeV1ForNullableString = { readonly outcome: ScopeOutcomeForNullableString; readonly scope_digest: ManifestDigest }; export type RuleEffect = "allow" | "deny"; export type RunId = string; +export type RuntimeDoctorReportV1 = { readonly kind: "observed"; readonly language_servers: LanguageServerReadV1; readonly report: DoctorReportV1; readonly schema_convergences: readonly SchemaConvergenceFindingV1[]; readonly table_growth_evidence: readonly TableGrowthDoctorEvidenceV1[] } | { readonly kind: "unknown"; readonly language_servers: LanguageServerReadV1; readonly schema_convergences: readonly SchemaConvergenceFindingV1[]; readonly table_growth_evidence: readonly TableGrowthDoctorEvidenceV1[] } | { readonly kind: "unsupported"; readonly language_servers: LanguageServerReadV1; readonly schema_convergences: readonly SchemaConvergenceFindingV1[]; readonly table_growth_evidence: readonly TableGrowthDoctorEvidenceV1[] }; export type SanitizationReceiptId = string; export type SanitizationReceiptRefV1 = { readonly receipt_id: SanitizationReceiptId; readonly sanitizer_version: ComponentVersion }; export type SanitizationReceiptV1 = { readonly disposition: SanitizerDispositionV1; readonly payload?: PayloadReferenceV1 | null; readonly receipt: SanitizationReceiptRefV1; readonly sensitivity: SensitivityV1 }; export type SanitizerDispositionV1 = "accepted" | "redacted" | "rejected" | "quarantined"; +export type SchemaConvergenceFindingV1 = { readonly degraded_row?: string | null; readonly progress?: SchemaConvergenceProgressV1 | null; readonly stage: SchemaConvergenceStageV1; readonly started_at_micros: number; readonly state: SchemaConvergenceStateV1; readonly store: string }; +export type SchemaConvergenceProgressV1 = { readonly done: number; readonly remaining: number; readonly unit: "rows" } | { readonly done: number; readonly remaining: number; readonly unit: "pages" }; +export type SchemaConvergenceStageV1 = "registered_schema"; +export type SchemaConvergenceStateV1 = "pending_schema_migration" | "released_shape_convergence_in_progress" | "degraded" | "completed"; export type ScopeAccessRule = { readonly authority: AuthorityRef; readonly capabilities: readonly CapabilityId[]; readonly effect: RuleEffect; readonly expires_at?: UtcMicros | null; readonly rule_id: AccessRuleId; readonly subject: ScopeAccessSubjectV1 }; export type ScopeAccessSubjectV1 = { readonly actor?: ActorId | null; readonly operation?: ScopeControlOperationV1 | null; readonly source_kind?: SourceKindV1 | null }; export type ScopeControlOperationV1 = "read" | "source_bind" | "source_rebind" | "source_unbind" | "access_rule_upsert" | "access_rule_remove" | "replace_topology_policy" | "rollback"; @@ -849,6 +907,7 @@ export type SessionSourceCoverageV1 = { readonly committed_frontier: number; rea export type SettingKey = string; export type SettingSensitivityV1 = "public" | "sensitive"; export type SettingSummary = { readonly key: SettingKey; readonly restart_requirement: RestartRequirementV1; readonly sensitivity: SettingSensitivityV1; readonly [key: string]: unknown }; +export type ShardId = string; export type SharedProfileStoreLocatorV1 = { readonly brain_id: BrainId; readonly profile_id: UserProfileId; readonly store_id: string }; export type SimilarCoverageV1 = { readonly status: "complete" } | { readonly status: "partial" } | { readonly minimum_tokens: number; readonly status: "excluded_too_small" } | { readonly maximum_bytes: number; readonly maximum_tokens: number; readonly status: "excluded_too_large" } | { readonly status: "excluded_incomplete_tokenization" }; export type SimilarFamilyV1 = { readonly complete: boolean; readonly family_digest: ManifestDigest; readonly match_class: SimilarMatchClassV1; readonly member_count: number; readonly members: readonly SimilarOccurrenceV1[]; readonly next_cursor?: string | null; readonly normalization_revision: number; readonly representative_payload_digest: ManifestDigest }; @@ -886,7 +945,22 @@ export type StackNodeId = string; export type StackSignalId = string; export type StackSignalKindV1 = "dependency_ready" | "actual_conflict" | "stack_tip_drift" | "pull_request_drift" | "ci_evaluated_commit_drift" | "integration_committed" | "integration_needs_inspection"; export type StartWorkAttemptCommand = { readonly attempt_id: AttemptId; readonly commit: CommitId; readonly effect_state: WorkEffectStateV1; readonly execution_snapshot: WorkExecutionSnapshot; readonly instructions: string; readonly occurred_at: UtcMicros; readonly operation: WorkflowOperationRef; readonly reference?: RefId | null; readonly run_id: RunId; readonly task_id: TaskId; readonly worktree_root: string }; +export type StatusAdmissionV1 = { readonly project_admitted: boolean; readonly project_root: string; readonly scope_prefix?: string | null; readonly server?: unknown }; +export type StatusBranchMismatchV1 = { readonly git_branch?: string | null; readonly indexed_branch?: string | null; readonly serving_branch?: string | null }; +export type StatusCodeIndexFreshnessV1 = { readonly status: "current"; readonly worktree: CodeIndexWorktreeFreshnessV1 } | { readonly status: "stale"; readonly worktree: CodeIndexWorktreeFreshnessV1 } | { readonly status: "restoring"; readonly worktree: CodeIndexWorktreeFreshnessV1 } | { readonly status: "warming"; readonly worktree: CodeIndexWorktreeFreshnessV1 } | { readonly status: "parked"; readonly worktree: CodeIndexWorktreeFreshnessV1 } | { readonly reason: string; readonly status: "unavailable" }; +export type StatusGitStalenessV1 = { readonly message: string; readonly reason: string; readonly status: string }; +export type StatusMemoryOwnerV1 = { readonly bytes?: number | null; readonly content_digest?: string | null; readonly holders: readonly ResidentMemoryHolderReadV1[]; readonly idle_seconds: number; readonly kind: string; readonly measured: boolean; readonly project_id: string; readonly protected: boolean }; +export type StatusMemoryPressureV1 = "unobserved" | "nominal" | "over_budget"; +export type StatusMemoryV1 = { readonly high_watermark_bytes: number; readonly idle_window_seconds: number; readonly limit_bytes: number; readonly low_watermark_bytes: number; readonly owners: readonly StatusMemoryOwnerV1[]; readonly psi_some_avg10?: number | null; readonly resident_bytes?: number | null; readonly retained_bytes: number; readonly shed_order: readonly string[]; readonly status: StatusMemoryPressureV1; readonly unmeasured_owners: number }; +export type StatusRetrievalServingV1 = { readonly condition?: StatusServingConditionV1 | null; readonly freshness: StatusServingFreshnessV1; readonly last_reconcile_age_seconds?: number | null; readonly seated_generation_age_seconds?: number | null; readonly status: "serving" } | { readonly reason: string; readonly status: "unavailable" }; +export type StatusSchemaConvergenceStateV1 = "completed" | "in_progress" | "degraded"; +export type StatusSchemaConvergenceV1 = { readonly findings: readonly SchemaConvergenceFindingV1[]; readonly status: StatusSchemaConvergenceStateV1 }; +export type StatusServingConditionV1 = "artifact_restore" | "source_verification" | "rebuilding" | "stalled"; +export type StatusServingFreshnessV1 = "current" | "restoring" | "last_complete_stale" | "unknown"; +export type StorageByteSizeV1 = number; export type StorageStatusHistoryPointV1 = { readonly database_bytes: number; readonly observed_at: number }; +export type StoreKeyV1 = string; +export type StoreResetRequiredV1 = { readonly authority: string; readonly found_version?: number | null; readonly reason: string; readonly remedy: string; readonly required_version?: number | null; readonly store: string; readonly [key: string]: unknown }; export type SymbolChangesCompleteV1 = { readonly status: GitReadCompleteV1 }; export type SymbolChangesUnavailableV1 = { readonly reason: string; readonly retryable: boolean; readonly status: GitReadUnavailableV1 }; export type SymbolGraphScope = { readonly path_prefix?: string | null }; @@ -894,6 +968,8 @@ export type SymbolOccurrenceId = string; export type SymbolPrimitiveRecord = { readonly end_line: number; readonly file: string; readonly is_async: boolean; readonly kind: string; readonly line: number; readonly name: string; readonly node_id: string; readonly qualified_name: string; readonly score?: number | null; readonly signature?: string | null }; export type SymbolRelationRecord = { readonly depth?: number | null; readonly dispatch_from?: string | null; readonly dispatch_via_trait: boolean; readonly edge_kind: string; readonly symbol: SymbolPrimitiveRecord }; export type SymbolSignatureV1 = { readonly cost_to_expand: NodeExpansionCostV1; readonly docstring?: string | null; readonly end_line: number; readonly file: string; readonly is_async: boolean; readonly kind: string; readonly name: string; readonly node_id: string; readonly qualified_name: string; readonly signature?: string | null; readonly start_line: number; readonly unavailable_fields: readonly string[]; readonly visibility: string }; +export type TableGrowthDoctorEvidenceV1 = { readonly current_bytes: StorageByteSizeV1; readonly current_observed_at: UtcMicros; readonly growth_bytes: StorageByteSizeV1; readonly kind: "significant_growth"; readonly previous_bytes: StorageByteSizeV1; readonly previous_observed_at: UtcMicros; readonly store: StoreKeyV1; readonly table: TableNameV1; readonly [key: string]: unknown } | { readonly kind: "baseline_established"; readonly observed_at: UtcMicros; readonly store: StoreKeyV1; readonly tables_observed: number; readonly [key: string]: unknown } | { readonly current_bytes: StorageByteSizeV1; readonly kind: "table_baseline_pending"; readonly observed_at: UtcMicros; readonly store: StoreKeyV1; readonly table: TableNameV1; readonly [key: string]: unknown } | { readonly kind: "unsupported"; readonly store: StoreKeyV1; readonly [key: string]: unknown } | { readonly kind: "denied"; readonly store: StoreKeyV1; readonly [key: string]: unknown } | { readonly kind: "unknown"; readonly store: StoreKeyV1; readonly [key: string]: unknown }; +export type TableNameV1 = string; export type TaskEvidenceLinkV1 = { readonly anchor_id: RetrievalAnchorId; readonly evidence_digest: ManifestDigest; readonly link_id: string; readonly observed_at: UtcMicros; readonly revision: number; readonly task_id: TaskId }; export type TaskHandoffScope = { readonly definition_id: WorkflowDefinitionId; readonly definition_version: number; readonly from_actor_id: ActorId; readonly project_id: ProjectId; readonly repository_id: RepositoryId; readonly run_id: RunId; readonly step_id: WorkflowStepId; readonly task_id: TaskId; readonly thread_id: ThreadId; readonly to_actor_id: ActorId; readonly worktree_id: WorktreeId }; export type TaskHandoffSurfaceV1 = { readonly task_id: TaskId; readonly version: number }; @@ -1181,6 +1257,8 @@ export type WorktreePresenceV1 = "present" | "stale" | "unavailable" | "foreign" export type WorktreeRetentionPolicyV1 = { readonly abandoned_retention_seconds?: number | null; readonly automatic_gc: AutomaticWorktreeGcV1; readonly maximum_retained_per_repository?: number | null; readonly terminal_retention_seconds?: number | null }; export type WorktreeRootPolicyV1 = { readonly locator: SensitiveFilesystemLocatorV1; readonly maximum_active_worktrees: number; readonly repository_scope: RepositoryPlacementScopeV1; readonly root_id: string }; +export type OperationApplicationActiveProjectRequest = { }; +export type OperationApplicationActiveProjectResult = { readonly branch: ActiveProjectBranchV1; readonly project_id?: string | null; readonly project_root: string; readonly repository_id: string; readonly resolution_source: ActiveProjectResolutionSourceV1; readonly scope_prefix?: string | null; readonly storage: ActiveProjectStorageV1 }; export type OperationApplicationAffectedRequest = { readonly depth?: number | null; readonly files: readonly string[]; readonly filter?: string | null }; export type OperationApplicationAffectedResult = { readonly affected_tests: readonly string[]; readonly changed_files: readonly string[]; readonly count: number; readonly ranked_tests: readonly RankedAffectedTestV1[]; readonly ranking_metadata: AffectedRankingMetadataV1; readonly recommended_tests: readonly string[] }; export type OperationApplicationAffectedTestsRequest = { readonly request_handle: string }; @@ -1447,6 +1525,12 @@ export type OperationApplicationPrContextRequest = { readonly base_ref?: string export type OperationApplicationPrContextResult = PrContextCompleteV1 | PrContextSymbolsUnavailableV1 | PrContextGraphPendingV1 | GitToolFailureV1; export type OperationApplicationPreflightNativeIntegrationRequest = { readonly preferred_mode?: MechanicalIntegrationModeV1 | null; readonly snapshot: NativeIntegrationSealedStackSnapshotV1 }; export type OperationApplicationPreflightNativeIntegrationResult = { readonly outcome: "stack_snapshot"; readonly sealed_snapshot: NativeIntegrationSealedStackSnapshotV1; readonly selection: NativeIntegrationSnapshotProjectionV1 } | { readonly analysis?: NativeIntegrationAnalysisReportV1 | null; readonly created_at: UtcMicros; readonly disposition: NativeIntegrationPreviewDispositionV1; readonly expires_at: UtcMicros; readonly ordered_commit_count: number; readonly outcome: "preview"; readonly preview_digest: ManifestDigest; readonly preview_id: NativeIntegrationPreviewId; readonly selection: NativeIntegrationSnapshotProjectionV1 } | { readonly approval_digest: ManifestDigest; readonly approval_id: NativeIntegrationApprovalId; readonly capability: CapabilityId; readonly expires_at: UtcMicros; readonly issued_at: UtcMicros; readonly outcome: "approval"; readonly preview_digest: ManifestDigest; readonly preview_id: NativeIntegrationPreviewId; readonly principal: ActorId; readonly transaction_id: NativeIntegrationTransactionId } | { readonly completed_at: UtcMicros; readonly final_ref_tip: string; readonly final_tree: string; readonly outcome: "receipt"; readonly receipt_digest: ManifestDigest; readonly status: NativeIntegrationStatusProjectionV1; readonly terminal_outcome: NativeIntegrationTerminalOutcomeV1 } | { readonly cancellation_requested: boolean; readonly destination_ref: RefId; readonly outcome: "status"; readonly phase: NativeIntegrationPhaseV1; readonly phase_revision: number; readonly preview_digest: ManifestDigest; readonly preview_id: NativeIntegrationPreviewId; readonly repository_id: RepositoryId; readonly terminal_outcome?: NativeIntegrationTerminalOutcomeV1 | null; readonly transaction_id: NativeIntegrationTransactionId; readonly updated_at: UtcMicros } | "cancellation_requested" | "commit_point_passed" | { readonly already_terminal: NativeIntegrationTerminalOutcomeV1; readonly [key: string]: unknown } | NativeWorktreeSurfaceResultV1 | { readonly outcome: "unavailable"; readonly reason: NativeIntegrationSurfaceUnavailableV1; readonly [key: string]: unknown }; +export type OperationApplicationProjectContextRequest = { readonly path?: string | null; readonly project_selector?: { readonly project_id: string } }; +export type OperationApplicationProjectContextResult = { readonly aliases: readonly unknown[]; readonly is_active: boolean; readonly project: PublicCodeProject; readonly registry_path: string; readonly status: "ok"; readonly stores: readonly unknown[] } | { readonly aliases: readonly unknown[]; readonly project: null; readonly registry_path: string; readonly status: "not_found"; readonly stores: readonly unknown[] }; +export type OperationApplicationProjectListRequest = { readonly limit?: number | null }; +export type OperationApplicationProjectListResult = { readonly limit: number; readonly project_tree: readonly ProjectRepoGroup[]; readonly projects: readonly PublicCodeProject[]; readonly query?: string | null; readonly registry_path: string; readonly status: "ok"; readonly summary: ProjectRegistrySummary; readonly title: string; readonly truncated: boolean }; +export type OperationApplicationProjectSearchRequest = { readonly limit?: number | null; readonly query: string }; +export type OperationApplicationProjectSearchResult = { readonly limit: number; readonly project_tree: readonly ProjectRepoGroup[]; readonly projects: readonly PublicCodeProject[]; readonly query?: string | null; readonly registry_path: string; readonly status: "ok"; readonly summary: ProjectRegistrySummary; readonly title: string; readonly truncated: boolean }; export type OperationApplicationQualifiedNameRequest = { readonly page: PageRequest; readonly qualified_name: string }; export type OperationApplicationQualifiedNameResult = { readonly next_cursor?: string | null; readonly symbols: readonly SymbolPrimitiveRecord[]; readonly total?: number | null }; export type OperationApplicationRankRequest = { readonly direction?: RankDirectionV1 | null; readonly edge_kind: RankEdgeKindV1; readonly limit?: number | null; readonly node_kind?: string | null; readonly path?: string | null }; @@ -1455,6 +1539,8 @@ export type OperationApplicationRecursionRequest = { readonly limit?: number | n export type OperationApplicationRecursionResult = { readonly cycle_count: number; readonly cycles: readonly RecursionCycleV1[] }; export type OperationApplicationRedundancyRequest = { readonly cursor?: string | null; readonly family_limit: number; readonly include_generated_paths: boolean; readonly match_classes: readonly SimilarMatchClassV1[]; readonly member_limit: number; readonly project_id: ProjectId; readonly repository_id: RepositoryId; readonly scope: RedundancyScopeV1; readonly work_limit: number }; export type OperationApplicationRedundancyResult = { readonly coverage: RedundancyCoverageV1; readonly families: readonly RedundancyFamilyV1[]; readonly next_cursor?: string | null; readonly ranked_by: RedundancyRankingV1; readonly source_generation: CodeGenerationId }; +export type OperationApplicationRemoteStatusRequest = { }; +export type OperationApplicationRemoteStatusResult = { readonly coverage: DoctorCoverageCompletenessV1; readonly kind: "observed"; readonly listener: RemoteListenerReadV1; readonly status: RemoteOperationalStatusV1; readonly [key: string]: unknown } | { readonly kind: "unconfigured"; readonly [key: string]: unknown } | { readonly kind: "unavailable"; readonly [key: string]: unknown }; export type OperationApplicationRenamePreviewRequest = { readonly new_name?: string | null; readonly node_id: string }; export type OperationApplicationRenamePreviewResult = RenamePreviewPrimitiveResultV1 | PrimitiveNotFoundV1; export type OperationApplicationRenameSymbolRequest = { readonly accepted_preview?: RenamePreviewAcceptanceV1 | null; readonly dry_run?: boolean; readonly expected_state?: string | null; readonly file: string; readonly idempotency_key?: string | null; readonly kind: string; readonly new_name: string; readonly node_id: string; readonly old_name: string; readonly qualified_name: string; readonly verify?: boolean }; @@ -1465,6 +1551,8 @@ export type OperationApplicationRetrieveRequest = { readonly handle: string; rea export type OperationApplicationRetrieveResult = RetrievedPageV1 | RetrieveHandleMissingV1 | RetrieveHandleExpiredV1; export type OperationApplicationRunAffectedTestsRequest = { readonly changed_paths: readonly string[]; readonly max_tests?: number | null; readonly profile?: TestProfileV1 | null; readonly timeout_secs?: number | null }; export type OperationApplicationRunAffectedTestsResult = AffectedTestRunV1 | AffectedTestsNotRunV1; +export type OperationApplicationRuntimeRequest = { readonly authority_audit?: boolean; readonly doctor_report?: boolean; readonly session_ingest_health?: boolean; readonly session_temporal_health?: boolean; readonly startup_health?: boolean }; +export type OperationApplicationRuntimeResult = { readonly captured_at: number; readonly cursor_session_ingest?: unknown; readonly cursor_session_placeholder_paths?: readonly string[] | null; readonly database: unknown; readonly doctor_report?: RuntimeDoctorReportV1 | null; readonly host_os: string; readonly process: unknown; readonly session_temporal_health?: unknown; readonly tracedecay_version: string }; export type OperationApplicationSearchRequest = { readonly cursor?: string | null; readonly lazy_index_ignored_dependencies?: boolean | null; readonly lexical_aliases?: readonly SearchLexicalAliasV1[] | null; readonly lexical_anchors?: readonly string[] | null; readonly lexical_field_filters?: readonly SearchLexicalFieldFilterV1[] | null; readonly lexical_phrases?: readonly string[] | null; readonly lexical_proximities?: readonly SearchLexicalProximityV1[] | null; readonly limit?: number | null; readonly prefer_symbol?: boolean | null; readonly query: string }; export type OperationApplicationSearchResult = SearchCompleteV1 | SearchUnavailableV1; export type OperationApplicationSessionLookupRequest = { readonly meta: RetrievalRequestMeta; readonly session_id: SessionId }; @@ -1497,6 +1585,8 @@ export type OperationApplicationSourceOutlineRequest = { readonly file: string } export type OperationApplicationSourceOutlineResult = { readonly file: string; readonly symbols: readonly SymbolPrimitiveRecord[] }; export type OperationApplicationStackSnapshotRequest = { readonly authorized_scope_set_digest: ManifestDigest; readonly authorized_scope_set_id: ScopeSetId; readonly authorized_scope_set_revision: ScopeSetRevision; readonly destination: ResolvedScope; readonly grant_digest: ManifestDigest; readonly inventory_epoch: WorktreeInventoryEpoch; readonly inventory_snapshot_id: WorktreeInventorySnapshotId; readonly policy_digest: ManifestDigest; readonly selection: NativeIntegrationSelectionDeclarationV1; readonly source: ResolvedScope }; export type OperationApplicationStackSnapshotResult = { readonly outcome: "stack_snapshot"; readonly sealed_snapshot: NativeIntegrationSealedStackSnapshotV1; readonly selection: NativeIntegrationSnapshotProjectionV1 } | { readonly analysis?: NativeIntegrationAnalysisReportV1 | null; readonly created_at: UtcMicros; readonly disposition: NativeIntegrationPreviewDispositionV1; readonly expires_at: UtcMicros; readonly ordered_commit_count: number; readonly outcome: "preview"; readonly preview_digest: ManifestDigest; readonly preview_id: NativeIntegrationPreviewId; readonly selection: NativeIntegrationSnapshotProjectionV1 } | { readonly approval_digest: ManifestDigest; readonly approval_id: NativeIntegrationApprovalId; readonly capability: CapabilityId; readonly expires_at: UtcMicros; readonly issued_at: UtcMicros; readonly outcome: "approval"; readonly preview_digest: ManifestDigest; readonly preview_id: NativeIntegrationPreviewId; readonly principal: ActorId; readonly transaction_id: NativeIntegrationTransactionId } | { readonly completed_at: UtcMicros; readonly final_ref_tip: string; readonly final_tree: string; readonly outcome: "receipt"; readonly receipt_digest: ManifestDigest; readonly status: NativeIntegrationStatusProjectionV1; readonly terminal_outcome: NativeIntegrationTerminalOutcomeV1 } | { readonly cancellation_requested: boolean; readonly destination_ref: RefId; readonly outcome: "status"; readonly phase: NativeIntegrationPhaseV1; readonly phase_revision: number; readonly preview_digest: ManifestDigest; readonly preview_id: NativeIntegrationPreviewId; readonly repository_id: RepositoryId; readonly terminal_outcome?: NativeIntegrationTerminalOutcomeV1 | null; readonly transaction_id: NativeIntegrationTransactionId; readonly updated_at: UtcMicros } | "cancellation_requested" | "commit_point_passed" | { readonly already_terminal: NativeIntegrationTerminalOutcomeV1; readonly [key: string]: unknown } | NativeWorktreeSurfaceResultV1 | { readonly outcome: "unavailable"; readonly reason: NativeIntegrationSurfaceUnavailableV1; readonly [key: string]: unknown }; +export type OperationApplicationStatusRequest = { readonly admission_only?: boolean; readonly include_branch_diagnostics?: boolean; readonly include_session_ingest?: boolean; readonly include_staleness?: boolean; readonly include_storage_health?: boolean; readonly wait_for?: CodeIndexReadinessWaitV1 | null }; +export type OperationApplicationStatusResult = StatusAdmissionV1 | ProjectStatusV1; export type OperationApplicationStorageStatusRequest = { readonly include_details?: boolean }; export type OperationApplicationStorageStatusResult = { readonly database_bytes?: number | null; readonly details: readonly string[]; readonly freelist_pages?: number | null; readonly history?: readonly StorageStatusHistoryPointV1[]; readonly history_coverage?: string | null; readonly page_count?: number | null; readonly page_size_bytes?: number | null; readonly project_id?: string | null; readonly read_only: boolean; readonly status: string; readonly store_path?: string | null }; export type OperationApplicationStrReplaceRequest = { readonly dry_run?: boolean; readonly expected_state?: string | null; readonly idempotency_key?: string | null; readonly new_str: string; readonly old_str: string; readonly path: string; readonly verify?: boolean }; @@ -1642,6 +1732,9 @@ const DEFINITIONS = { AccessPolicyDigest: {"description":"Strongly typed algorithm-tagged integrity digest: `AccessPolicyDigest`.","type":"string"}, AccessRuleId: {"description":"Strongly typed canonical identity: `AccessRuleId`.","type":"string"}, ActivationDriftV1: {"enum":["current","never_activated","pending_restart","activation_failed"],"type":"string"}, + ActiveProjectBranchV1: {"additionalProperties":false,"properties":{"branch_drifted":{"type":"boolean"},"branch_resolution":{"type":"string"},"current_branch":{"type":["string","null"]},"open_active_branch":{"type":["string","null"]},"serving_branch":{"type":["string","null"]},"tracked_branch_count":{"format":"uint","minimum":0,"type":"integer"},"warnings":{"items":{"type":"string"},"type":"array"}},"required":["branch_resolution","branch_drifted","tracked_branch_count","warnings"],"type":"object"}, + ActiveProjectResolutionSourceV1: {"enum":["active_project"],"type":"string"}, + ActiveProjectStorageV1: {"additionalProperties":false,"properties":{"class":{"type":"string"},"data_root":{"type":"string"},"graph_db_exists":{"type":"boolean"},"graph_db_path":{"type":"string"},"graph_db_size_bytes":{"format":"uint64","minimum":0,"type":"integer"},"lcm_payload_root":{"type":"string"},"mode":{"type":"string"},"response_handle_root":{"type":"string"},"sessions_db_path":{"type":"string"}},"required":["class","mode","data_root","graph_db_path","graph_db_exists","graph_db_size_bytes","sessions_db_path","response_handle_root","lcm_payload_root"],"type":"object"}, ActorId: {"description":"Strongly typed canonical identity: `ActorId`.","type":"string"}, AddWorkTaskRequestV1: {"additionalProperties":false,"properties":{"item":{"$ref":"#/$defs/WorkItemV1"},"mutation":{"$ref":"#/$defs/WorkProductMutationIdentityV1"},"selection":{"$ref":"#/$defs/WorkProductSelectionScopeV1"}},"required":["selection","item","mutation"],"type":"object"}, AdjudicateWorkLeakCommandV1: {"additionalProperties":false,"properties":{"adjudication_id":{"type":"string"},"attempt":{"$ref":"#/$defs/WorkAttemptIdentityV1"},"command_id":{"$ref":"#/$defs/WorkCommandId"},"detection_horizon_micros":{"format":"uint64","minimum":0,"type":"integer"},"expected_revision":{"format":"uint64","minimum":0,"type":["integer","null"]}},"required":["adjudication_id","attempt","detection_horizon_micros","command_id"],"title":"AdjudicateWorkLeakCommandV1","type":"object"}, @@ -1692,6 +1785,7 @@ const DEFINITIONS = { AstGrepResult: {"description":"Result of an ast-grep rewrite operation.","properties":{"diff":{"description":"Bounded preview of the would-be change. Populated only on a successful\ndry run; `None` for real edits and for failures.","type":["string","null"]},"dry_run":{"description":"True when this was a dry run: the rewrite was resolved (via the built-in\nliteral fallback or an ast-grep preview run) but nothing was written.","type":"boolean"},"file_path":{"type":"string"},"message":{"type":"string"},"pattern":{"type":"string"},"rewrite":{"type":"string"},"success":{"type":"boolean"}},"required":["success","file_path","pattern","rewrite","message"],"type":"object"}, AstGrepSearchMatchV1: {"additionalProperties":false,"properties":{"column":{"format":"uint32","minimum":0,"type":"integer"},"file":{"type":"string"},"lang":{"type":"string"},"line":{"format":"uint32","minimum":0,"type":"integer"},"line_text":{"type":"string"},"match":{"type":"string"}},"required":["file","line","column","lang","match","line_text"],"type":"object"}, AttemptId: {"description":"Strongly typed canonical identity: `AttemptId`.","type":"string"}, + AuthorityEpoch: {"description":"Monotonic epoch of the writer authority for a shard.","format":"uint64","minimum":0,"type":"integer"}, AuthorityReceipt: {"additionalProperties":false,"description":"Proof that this request crossed the current authorization boundary.","properties":{"authorized_scope_digest":{"$ref":"#/$defs/ManifestDigest"},"disclosure":{"$ref":"#/$defs/DisclosureClass"},"grant_digest":{"$ref":"#/$defs/ManifestDigest"},"grant_id":{"type":"string"},"grant_revision":{"format":"uint64","minimum":0,"type":"integer"},"policy":{"$ref":"#/$defs/PolicyDecisionRef"},"revalidated_at":{"$ref":"#/$defs/UtcMicros"}},"required":["grant_id","grant_revision","grant_digest","authorized_scope_digest","disclosure","policy","revalidated_at"],"type":"object"}, AuthorityRef: {"description":"Authoritative scope of a source binding. A mutable path, label, or host\nprofile cannot be represented as authority.","oneOf":[{"properties":{"id":{"$ref":"#/$defs/ProjectId"},"kind":{"const":"project","type":"string"}},"required":["kind","id"],"type":"object"},{"properties":{"id":{"$ref":"#/$defs/UserProfileId"},"kind":{"const":"projectless_hermes","type":"string"}},"required":["kind","id"],"type":"object"}]}, AuthorizedRoot: {"additionalProperties":false,"description":"One exact application scope paired with its registered physical locator.\n\nThe scope remains the identity authority. The locator is retained only so\na later read or restart can reopen the exact registered root without an\nactive-graph or CWD fallback.","properties":{"locator":{"anyOf":[{"$ref":"#/$defs/RegisteredRootLocatorV1"},{"type":"null"}]},"scope":{"$ref":"#/$defs/ResolvedScope"}},"required":["scope"],"type":"object"}, @@ -1719,6 +1813,7 @@ const DEFINITIONS = { AutomationTaskV1: {"description":"Automation capability selected after one registered application admission.","enum":["memory_curator","session_reflector","skill_writer","combined_review","user_job"],"type":"string"}, AutomationTrigger: {"enum":["manual_cli","manual_mcp","dashboard","application","scheduler","host_receipt"],"type":"string"}, BrainId: {"description":"Strongly typed canonical identity: `BrainId`.","type":"string"}, + BrainNodeId: {"description":"Strongly typed canonical identity: `BrainNodeId`.","type":"string"}, BranchCollisionPolicyV1: {"oneOf":[{"properties":{"kind":{"const":"reject","type":"string"}},"required":["kind"],"type":"object"},{"properties":{"kind":{"const":"append_monotonic_ordinal","type":"string"},"maximum_attempts":{"format":"uint16","maximum":65535,"minimum":1,"type":"integer"}},"required":["kind","maximum_attempts"],"type":"object"}]}, BranchDiffCompleteV1: {"additionalProperties":false,"properties":{"base":{"type":"string"},"base_generation":{"type":"string"},"base_revision":{"type":"string"},"base_tree":{"type":"string"},"changes":{"items":{"$ref":"#/$defs/BranchSymbolChangeV1"},"type":"array"},"head":{"type":"string"},"head_generation":{"type":"string"},"head_revision":{"type":"string"},"head_tree":{"type":"string"},"status":{"$ref":"#/$defs/GitReadCompleteV1"},"summary":{"$ref":"#/$defs/BranchDiffSummaryV1"},"total_changes":{"format":"uint","minimum":0,"type":"integer"}},"required":["status","base","head","base_revision","base_tree","head_revision","head_tree","base_generation","head_generation","total_changes","summary","changes"],"type":"object"}, BranchDiffPartialV1: {"additionalProperties":false,"properties":{"base":{"type":"string"},"base_generation":{"type":"string"},"base_revision":{"type":"string"},"base_tree":{"type":"string"},"changes":{"items":{"$ref":"#/$defs/BranchSymbolChangeV1"},"type":"array"},"head":{"type":"string"},"head_generation":{"type":"string"},"head_revision":{"type":"string"},"head_tree":{"type":"string"},"next_cursor":{"type":"string"},"reason":{"$ref":"#/$defs/GitResultLimitV1"},"status":{"$ref":"#/$defs/GitReadPartialV1"},"summary":{"$ref":"#/$defs/BranchDiffSummaryV1"},"total_changes":{"format":"uint","minimum":0,"type":"integer"}},"required":["status","reason","base","head","base_revision","base_tree","head_revision","head_tree","base_generation","head_generation","total_changes","next_cursor","summary","changes"],"type":"object"}, @@ -1760,14 +1855,30 @@ const DEFINITIONS = { ChangelogPartialV1: {"additionalProperties":false,"description":"The tree diff without symbol changes: the refs are not both exact local\nbranches with sealed generations.","properties":{"changed_file_count":{"format":"uint","minimum":0,"type":"integer"},"changed_files":{"items":{"type":"string"},"type":"array"},"from_ref":{"type":"string"},"status":{"$ref":"#/$defs/GitReadPartialV1"},"symbol_changes_coverage":{"$ref":"#/$defs/SymbolChangesUnavailableV1"},"symbols_added":{"items":{"$ref":"#/$defs/GitComparedSymbolV1"},"type":"array"},"symbols_modified":{"items":{"$ref":"#/$defs/GitComparedSymbolV1"},"type":"array"},"symbols_removed":{"items":{"$ref":"#/$defs/GitComparedSymbolV1"},"type":"array"},"to_ref":{"type":"string"}},"required":["status","from_ref","to_ref","changed_file_count","changed_files","symbols_added","symbols_removed","symbols_modified","symbol_changes_coverage"],"type":"object"}, CircularCycleV1: {"additionalProperties":false,"description":"One reported file cycle: the members that fit the member bound, plus the\ncomponent's true size so the omission is stated rather than hidden.","properties":{"member_count":{"format":"uint64","minimum":0,"type":"integer"},"members":{"items":{"type":"string"},"type":"array"},"omitted_member_count":{"format":"uint64","minimum":0,"type":"integer"}},"required":["members","member_count","omitted_member_count"],"type":"object"}, ClosedUtcIntervalV1: {"additionalProperties":false,"properties":{"from_inclusive":{"format":"int64","type":["integer","null"]},"through_inclusive":{"format":"int64","type":["integer","null"]}},"type":"object"}, + CodeCloneIndexBudgetsV1: {"description":"Fixed per-request clone candidate and verification budgets.","properties":{"candidate_bodies":{"format":"uint64","minimum":0,"type":"integer"},"hot_posting_rows":{"format":"uint64","minimum":0,"type":"integer"},"minimum_body_tokens":{"format":"uint64","minimum":0,"type":"integer"},"minimum_directional_coverage_millionths":{"format":"uint64","minimum":0,"type":"integer"},"posting_rows":{"format":"uint64","minimum":0,"type":"integer"},"verification_bodies":{"format":"uint64","minimum":0,"type":"integer"},"verification_token_work":{"format":"uint64","minimum":0,"type":"integer"}},"required":["posting_rows","candidate_bodies","verification_bodies","verification_token_work","hot_posting_rows","minimum_body_tokens","minimum_directional_coverage_millionths"],"type":"object"}, + CodeCloneIndexCoverageV1: {"description":"Coverage retained by one clone-index artifact or in-progress successor.\n\nCounts are `None` until the clone artifact has observed the corresponding\ndenominator. A complete empty repository reports `Some(0)`, which keeps a\ndesigned zero distinct from unavailable coverage.","properties":{"conservative_normalized_bodies":{"description":"Eligible bodies with a conservative exact posting.","format":"uint64","minimum":0,"type":["integer","null"]},"eligible_source_bodies":{"description":"Source bodies admitted for automatic clone discovery.","format":"uint64","minimum":0,"type":["integer","null"]},"exact_postings":{"description":"Conservative and rename-normalized exact posting rows.","format":"uint64","minimum":0,"type":["integer","null"]},"excluded_incomplete_tokenization_bodies":{"description":"Bodies excluded because conservative tokenization was incomplete.","format":"uint64","minimum":0,"type":["integer","null"]},"excluded_too_large_bodies":{"description":"Bodies excluded because they exceed the automatic-discovery token maximum.","format":"uint64","minimum":0,"type":["integer","null"]},"excluded_too_small_bodies":{"description":"Bodies excluded because they are below the automatic-discovery minimum.","format":"uint64","minimum":0,"type":["integer","null"]},"hot_posting_rows_skipped":{"description":"Positional rows omitted when those hot posting lists are skipped.","format":"uint64","minimum":0,"type":["integer","null"]},"hot_postings_skipped":{"description":"Fingerprint posting lists above the interactive read threshold.","format":"uint64","minimum":0,"type":["integer","null"]},"near_fingerprint_bodies":{"description":"Eligible bodies represented by positional fingerprints.","format":"uint64","minimum":0,"type":["integer","null"]},"near_fingerprint_postings":{"description":"Positional fingerprint posting rows retained by the artifact.","format":"uint64","minimum":0,"type":["integer","null"]},"payloads_reused":{"description":"Current payload occurrences reused from the preceding generation.","format":"uint64","minimum":0,"type":["integer","null"]},"rename_normalized_bodies":{"description":"Eligible bodies with a complete rename-normalized exact posting.","format":"uint64","minimum":0,"type":["integer","null"]},"rename_partial_bodies":{"description":"Eligible bodies whose rename normalization is partial.","format":"uint64","minimum":0,"type":["integer","null"]},"rename_unsupported_bodies":{"description":"Eligible bodies whose language has no rename normalization.","format":"uint64","minimum":0,"type":["integer","null"]},"source_bodies":{"description":"Clone body occurrences observed in the sealed lexical source.","format":"uint64","minimum":0,"type":["integer","null"]},"unique_payloads":{"description":"Distinct content-addressed payloads retained by the artifact.","format":"uint64","minimum":0,"type":["integer","null"]}},"type":"object"}, + CodeCloneIndexObservationV1: {"description":"Generation-pinned clone-index evidence shared by non-error readiness states.","properties":{"artifact_format_revision":{"format":"uint32","minimum":0,"type":["integer","null"]},"budgets":{"$ref":"#/$defs/CodeCloneIndexBudgetsV1"},"conservative_normalization_revision":{"format":"uint16","maximum":65535,"minimum":0,"type":"integer"},"coverage":{"$ref":"#/$defs/CodeCloneIndexCoverageV1"},"generation_id":{"type":"string"},"rename_normalization_revision":{"format":"uint16","maximum":65535,"minimum":0,"type":"integer"},"resources":{"$ref":"#/$defs/CodeCloneIndexResourcesV1"},"source_revision":{"type":["string","null"]}},"required":["generation_id","conservative_normalization_revision","rename_normalization_revision","coverage","budgets","resources"],"type":"object"}, + CodeCloneIndexResourcesV1: {"description":"Measured resources and update accounting for one clone-index generation.","properties":{"bytes_on_disk":{"description":"Durable artifact bytes.","format":"uint64","minimum":0,"type":["integer","null"]},"changed_symbol_update_micros":{"description":"Latest observed source-edit arrival through clone-ready publication.","format":"uint64","minimum":0,"type":["integer","null"]},"peak_scratch_memory_bytes":{"description":"Largest measured clone-row serialization scratch during the build.","format":"uint64","minimum":0,"type":["integer","null"]},"stale_invalidations":{"description":"Prior clone payload bindings invalidated by the latest publication.","format":"uint64","minimum":0,"type":["integer","null"]}},"type":"object"}, + CodeCloneIndexStatusV1: {"description":"Clone readiness, independent from lexical and graph serving.","oneOf":[{"description":"The sealed lexical artifact or its clone rows cannot be read.","properties":{"reason":{"type":"string"},"state":{"const":"unavailable","type":"string"}},"required":["state","reason"],"type":"object"},{"description":"Some clone evidence is readable, but required postings are missing.","properties":{"observation":{"$ref":"#/$defs/CodeCloneIndexObservationV1"},"omission_reasons":{"items":{"type":"string"},"type":"array"},"state":{"const":"partial","type":"string"}},"required":["state","observation","omission_reasons"],"type":"object"},{"description":"Required exact and fingerprint postings cover every eligible body.","properties":{"observation":{"$ref":"#/$defs/CodeCloneIndexObservationV1"},"state":{"const":"ready","type":"string"}},"required":["state","observation"],"type":"object"},{"description":"The artifact is readable but belongs to a superseded source generation.","properties":{"observation":{"$ref":"#/$defs/CodeCloneIndexObservationV1"},"reason":{"type":"string"},"state":{"const":"stale","type":"string"}},"required":["state","observation","reason"],"type":"object"}]}, CodeFacetDimension: {"enum":["kind","language","path"],"type":"string"}, CodeFacetRecord: {"additionalProperties":false,"properties":{"count":{"format":"uint64","minimum":0,"type":"integer"},"dimension":{"$ref":"#/$defs/CodeFacetDimension"},"value":{"type":"string"}},"required":["dimension","value","count"],"type":"object"}, CodeGenerationId: {"description":"Strongly typed canonical identity: `CodeGenerationId`.","type":"string"}, CodeGraphReadFreshnessV1: {"description":"Freshness of the generation a verified graph read serves.","oneOf":[{"properties":{"state":{"const":"current","type":"string"}},"required":["state"],"type":"object"},{"properties":{"rebuild_in_flight":{"type":"boolean"},"sealed_at":{"$ref":"#/$defs/UtcMicros"},"state":{"const":"last_complete_stale","type":"string"}},"required":["state","sealed_at","rebuild_in_flight"],"type":"object"}]}, + CodeGraphServingReadinessV1: {"description":"Interactive graph-serving state for the latest sealed generation.\n\nA sealed generation can expose truthful census statistics before its graph\nprojection is ready to serve queries, so readiness is reported separately.","oneOf":[{"description":"No graph-serving authority exists for this worktree or generation.","properties":{"reason":{"type":"string"},"state":{"const":"unavailable","type":"string"}},"required":["state","reason"],"type":"object"},{"description":"The sealed generation exists, but graph activation has not completed.","properties":{"state":{"const":"pending","type":"string"}},"required":["state"],"type":"object"},{"description":"Graph activation completed without a serving projection.","properties":{"reason":{"type":"string"},"state":{"const":"refused","type":"string"}},"required":["state","reason"],"type":"object"},{"description":"The verified graph projection is installed for interactive reads.","properties":{"state":{"const":"ready","type":"string"}},"required":["state"],"type":"object"}]}, CodeIndexBuildBlockedReasonV1: {"description":"A typed reason an otherwise active generation cannot make durable progress.","enum":["resident_memory","source_unavailable","artifact_store_unavailable","retry_backoff","publication_authority_corrupt"],"type":"string"}, + CodeIndexBuildPhaseV1: {"description":"The durable build phase whose committed boundary the dashboard is reading.\n\nA phase is not inferred from scheduler state. The mounted registry publishes\nthe exact phase that owns the active generation.","enum":["source_scan","relational_preparation","bulk_commit","index_build","verification","ready"],"type":"string"}, + CodeIndexBuildProgressV1: {"description":"The latest committed progress boundary for one active code-index generation.\n\nEvery count is scoped to `generation_id`. The snapshot never includes a\nstaged page: work is reported only after the batch that owns it commits.","properties":{"blocked_reason":{"anyOf":[{"$ref":"#/$defs/CodeIndexBuildBlockedReasonV1"},{"type":"null"}],"description":"Reason the active generation cannot currently advance, when known."},"committed_chunks":{"description":"Search chunks committed to the artifact database.","format":"uint64","minimum":0,"type":"integer"},"committed_imports":{"description":"Import evidence rows committed to the artifact database.","format":"uint64","minimum":0,"type":"integer"},"committed_pages":{"description":"Source pages committed to the artifact database.","format":"uint64","minimum":0,"type":"integer"},"committed_payload_bytes":{"description":"Payload bytes committed to the artifact database.","format":"uint64","minimum":0,"type":"integer"},"completed_files":{"description":"Authenticated sealed-source file boundary completed by committed work.","format":"uint64","minimum":0,"type":"integer"},"completed_lexical_units":{"description":"Authenticated lexical-span boundary completed by committed work, in the\nsealed source's own advance unit.\n\nThe unit is the source's, not this surface's: a sealed-layout source\nadvances over the files-array byte span, while a published or\npartitioned source advances over file ordinals because its file records\nare not a contiguous byte range at all. Both are monotone and share the\ndenominator below, so completion and the derived estimate are truthful;\nnaming them bytes was not, and a consumer that multiplied this by an\naverage file size was wrong by orders of magnitude (issue #1205).","format":"uint64","minimum":0,"type":"integer"},"current_batch_pages":{"description":"Source pages in the batch currently being processed.","format":"uint64","minimum":0,"type":"integer"},"current_batch_payload_bytes":{"description":"Sealed payload bytes in the batch currently being processed.","format":"uint64","minimum":0,"type":"integer"},"daemon_incarnation":{"description":"Durable daemon-authority epoch that produced this snapshot.\n\nThis orders snapshots across daemon restarts without relying on wall\nclock time.","format":"uint64","minimum":0,"type":"integer"},"elapsed_micros":{"description":"Monotonic elapsed time for this process's active generation build.","format":"uint64","minimum":0,"type":"integer"},"estimated_remaining_seconds":{"description":"Estimated remaining build duration, absent without a truthful rate.","format":"uint64","minimum":0,"type":["integer","null"]},"files_per_second":{"description":"Rolling committed-file throughput, absent until it is established.","format":"double","type":["number","null"]},"generation_id":{"description":"Exact generation receiving the committed build work.","type":"string"},"last_commit_latency_micros":{"description":"Duration of the last committed SQLite batch, when one exists.","format":"uint64","minimum":0,"type":["integer","null"]},"last_progress_micros":{"description":"Unix-epoch timestamp of the last durable progress publication.","format":"int64","type":"integer"},"lexical_units_per_second":{"description":"Rolling committed lexical-span throughput in units per second, absent\nuntil it is established. Not a byte rate; see\n[`Self::completed_lexical_units`].","format":"double","type":["number","null"]},"phase":{"$ref":"#/$defs/CodeIndexBuildPhaseV1","description":"Durable pipeline phase that published this snapshot."},"producer_incarnation":{"description":"Registry-minted scheduler incarnation within one daemon.\n\nA worktree retirement/remount creates a new value. `progress_epoch` is\ncomparable only when both incarnation fields match.","format":"uint64","minimum":0,"type":"integer"},"progress_epoch":{"description":"Monotonic publication epoch for replacing delayed progress reads.","format":"uint64","minimum":0,"type":"integer"},"sealed_source_digest":{"description":"Identity of the sealed source whose authenticated bounds define progress.","type":"string"},"total_files":{"description":"Authenticated sealed-source file bound for this generation.","format":"uint64","minimum":0,"type":"integer"},"total_lexical_units":{"description":"Authenticated lexical-span bound for this generation, in the same unit\nas [`Self::completed_lexical_units`].","format":"uint64","minimum":0,"type":"integer"}},"required":["generation_id","daemon_incarnation","producer_incarnation","progress_epoch","sealed_source_digest","phase","committed_pages","committed_chunks","committed_imports","committed_payload_bytes","completed_files","total_files","completed_lexical_units","total_lexical_units","current_batch_pages","current_batch_payload_bytes","elapsed_micros","last_progress_micros"],"type":"object"}, CodeIndexConvergenceParkedV1: {"description":"A deterministic contract violation that parked background convergence.\n\nParked is not dead: the worker keeps re-observing the violation on its\nordinary wake cadence, so an operator fix (for example restoring an\nowner-private mode) is picked up on the next wake without a restart. The\nstate exists so `status`, doctor, and the dashboard report the violation\ntyped instead of an indefinite \"warming\".","properties":{"blocked_reason":{"anyOf":[{"$ref":"#/$defs/CodeIndexBuildBlockedReasonV1"},{"type":"null"}],"description":"Stable class for callers that must decide whether new work is admissible."},"observed_passes":{"description":"Background passes that re-observed the violation since parking.","format":"uint64","minimum":0,"type":"integer"},"parked_at_micros":{"description":"When the violation was first observed (microseconds since the Unix epoch).","format":"int64","type":"integer"},"reason":{"description":"Exact typed failure that parked convergence.","type":"string"},"remediation":{"description":"Operator action that clears the violation.","type":"string"},"retries_on_wake":{"description":"Whether the worker re-checks this violation on every ordinary wake.\nTrue for filesystem/contract violations an operator fix clears in\nplace; false for an abnormal task failure that only changed input (a\nnew sealed generation) retries.","type":"boolean"}},"required":["reason","remediation","parked_at_micros","observed_passes","retries_on_wake"],"type":"object"}, + CodeIndexFreshnessCoverageV1: {"description":"Coverage of one freshness read. Distinct from [`CodeIndexStalenessStateV1`]:\na generation can be fresh and still omit hook-hint counts, or unverified\nwhile the ladder would otherwise say ready.\n\n`Unobserved` is only the constructed default. A projected read never emits\nit, so an absent observation cannot be mistaken for `complete`.","enum":["unobserved","complete","partial_refresh_in_progress","partial_artifact_restore","partial_source_verification","partial_unverified_restore","partial_hook_hint_overflow"],"type":"string"}, + CodeIndexGenerationRecoveryServingV1: {"description":"Serving disposition of an incompatible generation during recovery.","enum":["preserved","refused"],"type":"string"}, + CodeIndexGenerationRecoveryV1: {"description":"Recovery state for a durable generation sealed under a different production\nowner configuration.","properties":{"incompatibilities":{"description":"Stable owner-input reason codes reported by the code-index authority.","items":{"type":"string"},"type":"array"},"incompatible_generation_id":{"description":"Generation retired from incremental reuse.","type":"string"},"serving":{"$ref":"#/$defs/CodeIndexGenerationRecoveryServingV1","description":"Whether the prior generation may continue serving while its replacement\nbuilds under the current configuration."}},"required":["incompatible_generation_id","incompatibilities","serving"],"type":"object"}, + CodeIndexReadinessTargetV1: {"description":"The readiness a status caller can wait for.","oneOf":[{"const":"fresh","description":"A sealed complete generation serves exact and lexical reads for the\ncurrent source: `code_index_freshness.status` is `current`.","type":"string"},{"const":"ready","description":"`fresh`, and the generation's native code graph also serves.","type":"string"},{"const":"graph_ready","description":"A published generation's native code graph serves and no convergence\npark is set, whatever the source freshness. Waiting for it never\nsweeps the source, so it cannot arm the reconcile it would observe.","type":"string"}]}, + CodeIndexReadinessWaitOutcomeV1: {"description":"How a `wait_for` status read ended. The status payload beside it is read\nafter the wait ends.","oneOf":[{"properties":{"outcome":{"const":"reached","type":"string"}},"required":["outcome"],"type":"object"},{"description":"The caller's budget elapsed; `last_state` is the last observed\n`code_index_freshness.status`.","properties":{"last_state":{"type":"string"},"outcome":{"const":"timed_out","type":"string"}},"required":["outcome","last_state"],"type":"object"},{"description":"Waiting cannot reach the target: no scheduler is mounted, graph\nserving was refused, convergence is parked, or the request ended.","properties":{"outcome":{"const":"unavailable","type":"string"},"reason":{"type":"string"}},"required":["outcome","reason"],"type":"object"}]}, + CodeIndexReadinessWaitV1: {"additionalProperties":false,"description":"`tracedecay_status` `wait_for`: hold the status read until the worktree\nreaches `state`, for at most the caller's `timeout_ms`.","properties":{"state":{"$ref":"#/$defs/CodeIndexReadinessTargetV1"},"timeout_ms":{"format":"uint64","minimum":0,"type":"integer"}},"required":["state","timeout_ms"],"type":"object"}, + CodeIndexRestoreProgressV1: {"description":"Bounded authentication work required to restore one immutable lexical\nartifact as a serving reader.\n\nThe unit is a fixed restore check, not bytes or build work. Completed\nchecks are published only after they pass. `authenticated_remaining` is\nalways `authenticated_total - authenticated_completed`, so a caller can\ndistinguish bounded cold restore from an unbounded rebuild.","properties":{"artifact_digest":{"description":"Whole-file content address from the durable artifact descriptor.","type":"string"},"authenticated_completed":{"description":"Successfully completed authentication checks.","format":"uint64","minimum":0,"type":"integer"},"authenticated_remaining":{"description":"Checks that have not completed yet.","format":"uint64","minimum":0,"type":"integer"},"authenticated_total":{"description":"Fixed number of authentication checks for this restore.","format":"uint64","minimum":0,"type":"integer"},"generation_id":{"description":"Generation whose lexical serving seat is being restored.","type":"string"}},"required":["generation_id","artifact_digest","authenticated_completed","authenticated_total","authenticated_remaining"],"type":"object"}, CodeIndexStalenessStateV1: {"description":"Closed staleness ladder for one mounted worktree.\n\nThe scheduler publishes one of these tokens. MCP, the dashboard, and the\nCLI must match the variant, not a hand-copied string, so a new ladder\nstate cannot appear at one caller and be missed at the others.","enum":["fresh","stale","indexing","refreshing","restoring","verifying","parked"],"type":"string"}, CodeIndexWorkerSelectionV1: {"description":"Profile-level worker-count intent for the process-wide code-index pool.\n`Automatic` delegates the concrete count to runtime resource admission;\n`Exact` persists an operator-requested positive worker count.","oneOf":[{"additionalProperties":false,"properties":{"mode":{"const":"automatic","type":"string"}},"required":["mode"],"type":"object"},{"additionalProperties":false,"properties":{"mode":{"const":"exact","type":"string"},"workers":{"format":"uint16","maximum":65535,"minimum":0,"type":"integer"}},"required":["mode","workers"],"type":"object"}]}, + CodeIndexWorktreeFreshnessV1: {"description":"Freshness/generation state for one mounted worktree.\n\n`Deserialize` is part of the wire contract: the CLI status command decodes\nexactly this type back out of the daemon's `tracedecay_status` response,\nkeeping one authority for the freshness shape.","properties":{"clone_index":{"anyOf":[{"$ref":"#/$defs/CodeCloneIndexStatusV1"},{"type":"null"}],"description":"Clone readiness from the same sealed lexical artifact."},"code_graph_serving":{"anyOf":[{"$ref":"#/$defs/CodeGraphServingReadinessV1"},{"type":"null"}],"description":"Whether that generation's verified graph projection can serve reads."},"coverage":{"$ref":"#/$defs/CodeIndexFreshnessCoverageV1","description":"Whether this read covers the complete mounted scheduler state."},"generation_recovery":{"anyOf":[{"$ref":"#/$defs/CodeIndexGenerationRecoveryV1"},{"type":"null"}],"description":"One-shot owner-configuration recovery currently replacing an\nincompatible durable generation."},"hook_hint_count":{"description":"Pending hook-hint count, when cheaply available.","format":"uint64","minimum":0,"type":["integer","null"]},"last_reconcile_micros":{"description":"Last reconcile observation time (microseconds since the Unix epoch).","format":"int64","type":["integer","null"]},"latest_generation_id":{"description":"Latest sealed generation identity, when a complete generation exists.","type":["string","null"]},"parked":{"anyOf":[{"$ref":"#/$defs/CodeIndexConvergenceParkedV1"},{"type":"null"}],"description":"Deterministic contract violation currently parking background\nconvergence, when one is observed. `staleness_state` reads `parked`\nwhile this is set and no generation serves."},"progress":{"anyOf":[{"$ref":"#/$defs/CodeIndexBuildProgressV1"},{"type":"null"}],"description":"Latest committed progress for the active generation, if one is mounted."},"rebuild_in_flight":{"default":false,"description":"Whether the exact scheduler route owns a reconcile pass or has a\npending wake. A stale seated generation with this false is stalled,\nnot in a routine rebuild window.","type":"boolean"},"repository_id":{"description":"Stable repository identity resolved by the scheduler.","type":["string","null"]},"restore_progress":{"anyOf":[{"$ref":"#/$defs/CodeIndexRestoreProgressV1"},{"type":"null"}],"description":"Bounded immutable-artifact restore work currently in flight. This is\nseparate from build progress because restore commits no index data."},"sealed_at_micros":{"description":"Time the complete generation was durably sealed.","format":"int64","type":["integer","null"]},"snapshot_content_identity":{"description":"Content identity of the complete source snapshot.","type":["string","null"]},"source_reference":{"description":"Exact source reference captured by the sealed generation.","type":["string","null"]},"source_revision":{"description":"Exact source revision captured by the sealed generation.","type":["string","null"]},"staleness_state":{"anyOf":[{"$ref":"#/$defs/CodeIndexStalenessStateV1"},{"type":"null"}],"description":"Staleness-ladder state from the last scheduler execution. `fresh` means\nthe scheduler most recently observed a fresh source; the status read\ndoes not probe the worktree to revalidate that observation."},"worktree_id":{"description":"Stable worktree identity resolved by the scheduler.","type":["string","null"]},"worktree_root":{"description":"Display path of the mounted worktree root.","type":"string"}},"required":["worktree_root","coverage"],"type":"object"}, CodeLexicalField: {"description":"Typed code fields accepted by the generation-owned lexical authority.","enum":["symbol_name","qualified_name","path","signature","documentation","body_text","preamble_text","exact_term","subtoken"],"type":"string"}, CodeLexicalFieldFilter: {"additionalProperties":false,"properties":{"field":{"$ref":"#/$defs/CodeLexicalField"},"include":{"type":"boolean"}},"required":["field","include"],"type":"object"}, CodeOccurrenceRecord: {"additionalProperties":false,"properties":{"chunk":{"anyOf":[{"$ref":"#/$defs/CodeSearchChunkId"},{"type":"null"}]},"file":{"$ref":"#/$defs/FileOccurrenceId"},"path":{"type":"string"},"span":{"$ref":"#/$defs/SourceSpan"},"symbol":{"anyOf":[{"$ref":"#/$defs/SymbolOccurrenceId"},{"type":"null"}]}},"required":["file","path","span"],"type":"object"}, @@ -1864,6 +1975,8 @@ const DEFINITIONS = { CredentialReferenceId: {"description":"Strongly typed canonical identity: `CredentialReferenceId`.","type":"string"}, CrossMergeModeV1: {"enum":["disabled","manual_receipt_only","fast_forward_only","merge_commit","cherry_pick_exact_commits"],"type":"string"}, CrossMergePolicyV1: {"additionalProperties":false,"properties":{"allow_cross_repository":{"type":"boolean"},"allowed_modes":{"items":{"$ref":"#/$defs/CrossMergeModeV1"},"type":"array","uniqueItems":true},"default_mode":{"$ref":"#/$defs/CrossMergeModeV1"}},"required":["allowed_modes","default_mode","allow_cross_repository"],"type":"object"}, + CurrentRemoteAuthorityStateV1: {"description":"Truthful authority lookup state. Missing evidence is never represented as\nan available authority or a successful empty response.","oneOf":[{"properties":{"state":{"const":"available","type":"string"},"value":{"$ref":"#/$defs/CurrentRemoteAuthorityV1"}},"required":["state","value"],"type":"object"},{"properties":{"state":{"const":"partial","type":"string"},"value":{"properties":{"known_fence":{"anyOf":[{"$ref":"#/$defs/RemoteWriterFenceV1"},{"type":"null"}]},"missing":{"items":{"$ref":"#/$defs/RemoteAuthorityUnavailableReasonV1"},"type":"array","uniqueItems":true},"observed_at":{"$ref":"#/$defs/UtcMicros"}},"required":["missing","observed_at"],"type":"object"}},"required":["state","value"],"type":"object"},{"properties":{"state":{"const":"unavailable","type":"string"},"value":{"properties":{"observed_at":{"$ref":"#/$defs/UtcMicros"},"reason":{"$ref":"#/$defs/RemoteAuthorityUnavailableReasonV1"}},"required":["reason","observed_at"],"type":"object"}},"required":["state","value"],"type":"object"}]}, + CurrentRemoteAuthorityV1: {"additionalProperties":false,"description":"Authenticated current authority for a mutable shard.","properties":{"credential_revision":{"description":"Revision of the authority node's current enrollment credential.","format":"uint64","minimum":0,"type":"integer"},"fence":{"$ref":"#/$defs/RemoteWriterFenceV1"},"observed_at":{"$ref":"#/$defs/UtcMicros"}},"required":["fence","credential_revision","observed_at"],"type":"object"}, DashboardActionV1: {"description":"What `tracedecay_dashboard` does.","enum":["start","stop"],"type":"string"}, DeadCodeSymbolV1: {"additionalProperties":false,"properties":{"file":{"type":"string"},"id":{"type":"string"},"kind":{"type":"string"},"line":{"format":"uint32","minimum":0,"type":"integer"},"name":{"type":"string"},"signature":{"type":["string","null"]}},"required":["id","name","kind","file","line"],"type":"object"}, Deadline: {"additionalProperties":false,"description":"One immutable deadline supplied by the caller or upstream admission layer.","properties":{"expires_at":{"$ref":"#/$defs/UtcMicros"}},"required":["expires_at"],"type":"object"}, @@ -1891,6 +2004,20 @@ const DEFINITIONS = { DistributionKindCountV1: {"additionalProperties":false,"properties":{"count":{"format":"uint64","minimum":0,"type":"integer"},"kind":{"type":"string"}},"required":["kind","count"],"type":"object"}, DocCoverageFileV1: {"additionalProperties":false,"properties":{"count":{"format":"uint64","minimum":0,"type":"integer"},"file":{"type":"string"},"symbols":{"items":{"$ref":"#/$defs/DocCoverageSymbolV1"},"type":"array"}},"required":["file","count","symbols"],"type":"object"}, DocCoverageSymbolV1: {"additionalProperties":false,"properties":{"id":{"type":"string"},"kind":{"type":"string"},"line":{"format":"uint32","minimum":0,"type":"integer"},"name":{"type":"string"},"signature":{"type":["string","null"]}},"required":["id","name","kind","line"],"type":"object"}, + DoctorCoverageCompletenessV1: {"description":"Whether Doctor observed all of a family's evidence sources.","oneOf":[{"const":"complete","description":"Every relevant evidence source for the family was observed.","type":"string"},{"const":"partial","description":"Some evidence sources were observed; others were omitted.","type":"string"},{"const":"unknown","description":"Whether coverage is complete could not be determined.","type":"string"}]}, + DoctorCoverageStatementV1: {"description":"A bounded, human-readable coverage statement plus its completeness.","properties":{"completeness":{"$ref":"#/$defs/DoctorCoverageCompletenessV1"},"statement":{"type":"string"}},"required":["completeness","statement"],"type":"object"}, + DoctorEvidenceRefV1: {"description":"A typed reference to one piece of evidence Doctor composed into a finding.\n\nThe `family` records which audited input surface produced the evidence, so\na finding may cross-cite evidence from more than one family without losing\nprovenance.","properties":{"family":{"$ref":"#/$defs/DoctorFindingFamilyV1"},"reference":{"$ref":"#/$defs/DoctorEvidenceReferenceV1"}},"required":["family","reference"],"type":"object"}, + DoctorEvidenceReferenceV1: {"description":"Durable, non-disclosing reference to one owning-authority evidence\nrecord (for example a `FeedbackFindingId`, configuration revision, or\nruntime read coverage anchor). Doctor stores the reference only; the\nowning authority remains the single source of the record.","type":"string"}, + DoctorEvidenceStateV1: {"description":"Exact Doctor evidence states.\n\nMissing, partial, or unknown truth never becomes healthy or clean. Only\n[`DoctorEvidenceStateV1::HealthyCompleteCoverage`] asserts a healthy result,\nand only when its finding carries complete coverage (see\n[`DoctorFindingV1::new`]).","oneOf":[{"const":"unsupported","description":"The owning authority does not support this evidence on this platform.","type":"string"},{"const":"absent","description":"The evidence source is supported but produced nothing.","type":"string"},{"const":"stale","description":"The evidence exists but is behind the current generation/watermark.","type":"string"},{"const":"degraded","description":"The evidence proves a degraded but observed condition.","type":"string"},{"const":"partial","description":"Only part of the evidence was observed.","type":"string"},{"const":"unknown","description":"The evidence state could not be determined.","type":"string"},{"const":"denied","description":"Authorization to read the evidence was denied.","type":"string"},{"const":"healthy_complete_coverage","description":"The evidence proves a healthy condition with complete coverage.","type":"string"}]}, + DoctorFamilyConsultationV1: {"description":"Whether a family was consulted from an observed source or is unavailable.","oneOf":[{"description":"A source produced observed evidence for this family.","properties":{"status":{"const":"consulted","type":"string"}},"required":["status"],"type":"object"},{"description":"Complete family coverage was unavailable. Storage may still carry\nfindings from resolved producers when an independent producer failed.","properties":{"reason":{"$ref":"#/$defs/DoctorFamilyUnavailableReasonV1"},"status":{"const":"unavailable","type":"string"}},"required":["status","reason"],"type":"object"}]}, + DoctorFamilyCoverageV1: {"description":"The consultation status of one finding family within a report.","properties":{"consultation":{"$ref":"#/$defs/DoctorFamilyConsultationV1"},"family":{"$ref":"#/$defs/DoctorFindingFamilyV1"}},"required":["family","consultation"],"type":"object"}, + DoctorFamilyUnavailableReasonV1: {"description":"Why complete coverage of a finding family was unavailable.","oneOf":[{"const":"unwired","description":"No source port is wired for this family in this composition.","type":"string"},{"const":"unsupported","description":"The source is unsupported on this build/platform.","type":"string"},{"const":"absent","description":"The source is supported but produced nothing.","type":"string"},{"const":"denied","description":"The source read was denied.","type":"string"},{"const":"unknown","description":"The source state could not be determined.","type":"string"},{"const":"unavailable","description":"The source could not be reached. Named separately from `Unknown`: the\nsource is identified and its unreachability is an observation, not an\nundetermined state.","type":"string"},{"const":"reset_required","description":"The source must be rebuilt before it can be read again.","type":"string"},{"const":"corrupt","description":"The source was read and found corrupt.","type":"string"}]}, + DoctorFindingFamilyV1: {"description":"Stable Doctor finding families.\n\nThe initial list covers advisory findings from\nBrain, Explorer, Loom, Code, and Observatory, plus the legacy\n`core_doctor` checks (graph quick-check, temporal/migration health,\nconfiguration compatibility drift, code-index mount state, session ingest).\nEach family maps to one audited typed input surface. The set is kept small\nand honest; new families are added through a future versioned enum rather\nthan by widening the meaning of an existing variant.","oneOf":[{"const":"advisory","description":"advisory/scout findings (GitHub review, CI localization,\nproximity, context scout): `crate::advisory` / domain feedback.","type":"string"},{"const":"configuration","description":"Desired-versus-effective configuration and compatibility drift from\n`ProjectConfigurationRuntime` / `ConfigurationControlPlane`.","type":"string"},{"const":"storage_runtime","description":"Store, graph, and temporal runtime health plus migration coverage\n(`RuntimeReadOperationV1` health family, `StoreRuntimeClientLease`).","type":"string"},{"const":"storage","description":"Storage retention, size, and efficiency over canonical observability\nread models. Distinct from [`Self::StorageRuntime`] health: this\nfamily surfaces over-budget stores, identity-drift orphans, incident\ndebris, and retention backlog. The typed\nsubclass vocabulary is [`DoctorStorageFindingKindV1`].","type":"string"},{"const":"language_server","description":"Language-server / analyzer engine status from the LSP gateway's\n`AnalyzerState`.","type":"string"},{"const":"code_index","description":"Code index mount state (mounted, indexing, stale, unmounted,\nincompatible, parked).","type":"string"},{"const":"observability","description":"Denominator-safe measurement and telemetry health from analytics,\naccounting read models, and session ingest.","type":"string"},{"const":"memory","description":"Retained daemon memory as the resident-memory inventory reports it:\nRSS against the admission limit and pressure line, and each retained\nowner's bytes.","type":"string"}]}, + DoctorFindingV1: {"description":"One canonical Doctor finding.\n\nA finding pins its diagnosis `family`, its evidence `state`, the typed\nevidence it composed, and a coverage statement. Construction enforces the\ninvariants that keep unknown/partial evidence from collapsing into a\nhealthy or clean result.","properties":{"coverage":{"$ref":"#/$defs/DoctorCoverageStatementV1"},"evidence":{"items":{"$ref":"#/$defs/DoctorEvidenceRefV1"},"type":"array"},"family":{"$ref":"#/$defs/DoctorFindingFamilyV1"},"state":{"$ref":"#/$defs/DoctorEvidenceStateV1"}},"required":["family","state","evidence","coverage"],"type":"object"}, + DoctorReportCoverageV1: {"description":"The report-wide coverage statement: which families were consulted versus\nunavailable, plus an overall completeness and a bounded human statement.","properties":{"completeness":{"$ref":"#/$defs/DoctorCoverageCompletenessV1"},"families":{"items":{"$ref":"#/$defs/DoctorFamilyCoverageV1"},"type":"array"},"statement":{"$ref":"#/$defs/DoctorCoverageStatementV1"}},"required":["families","completeness","statement"],"type":"object"}, + DoctorReportEntryV1: {"description":"One entry in a Doctor report: a canonical finding plus, for the storage\nfamily, its typed subclass. The subclass is present only for storage findings\n(a non-storage entry never carries one).","properties":{"finding":{"$ref":"#/$defs/DoctorFindingV1"},"storage_kind":{"anyOf":[{"$ref":"#/$defs/DoctorStorageFindingKindV1"},{"type":"null"}]}},"required":["finding"],"type":"object"}, + DoctorReportV1: {"description":"One composed Doctor report.\n\nThe report carries one or more entries per family (findings are never merged\nby label) plus a coverage statement that enumerates every family consulted\nversus unavailable. Severity (the finding's evidence state) and evidence\nquality (coverage completeness) are kept as separate dimensions: a degraded\nfinding with complete coverage does not weaken report completeness, and only\ngenuinely complete coverage with every finding healthy makes the whole report\nassert health.","properties":{"coverage":{"$ref":"#/$defs/DoctorReportCoverageV1"},"entries":{"items":{"$ref":"#/$defs/DoctorReportEntryV1"},"type":"array"}},"required":["entries","coverage"],"type":"object"}, + DoctorStorageFindingKindV1: {"description":"Typed subclasses of the [`DoctorFindingFamilyV1::Storage`] finding family.\n\nThe storage family never reports a silent overage: each subclass names one\nobservable retention/size condition Doctor surfaces over canonical size\nobservability read models. The set is closed and grows only through a future\nversioned enum, never by widening an existing subclass.","oneOf":[{"const":"over_budget_store","description":"A store exceeds its owner-configured soft size budget.","type":"string"},{"const":"orphan_store","description":"A store whose project identity no longer resolves to a live repository\nroot (identity-drift orphan), reported with age and size.","type":"string"},{"const":"incident_debris_present","description":"Recovery/corruption artifacts are present beside a store and awaiting\ndeletion.","type":"string"},{"const":"retention_backlog","description":"Retention-eligible rows or stores are past their window and awaiting\noffload/collection.","type":"string"},{"const":"table_growth","description":"Per-table SQLite payload growth observed between two retained\nwatermarks, including baseline and unavailable measurement states.","type":"string"},{"const":"pending_schema_migration","description":"A store whose historical schema convergence has not completed: the\nmigrations whose cost scales with store size are still pending, still\nrunning, or stopped on a failure. The daemon serves while they run, so\nthis is the surface that says which store is still migrating and why.","type":"string"}]}, DsmClusterV1: {"additionalProperties":false,"properties":{"boundary_edges":{"format":"uint64","minimum":0,"type":"integer"},"directory":{"type":"string"},"file_count":{"format":"uint64","minimum":0,"type":"integer"},"incoming_edges":{"format":"uint64","minimum":0,"type":"integer"},"internal_edges":{"format":"uint64","minimum":0,"type":"integer"},"outgoing_edges":{"format":"uint64","minimum":0,"type":"integer"}},"required":["directory","file_count","internal_edges","outgoing_edges","incoming_edges","boundary_edges"],"type":"object"}, DsmMatrixV1: {"additionalProperties":false,"properties":{"files":{"items":{"type":"string"},"type":"array"},"matrix":{"items":{"items":{"format":"uint8","maximum":255,"minimum":0,"type":"integer"},"type":"array"},"type":"array"},"note":{"type":"string"}},"required":["files","matrix","note"],"type":"object"}, DsmShapeV1: {"description":"Shape of the design-structure-matrix report.","enum":["stats","clusters","matrix"],"type":"string"}, @@ -2104,6 +2231,10 @@ const DEFINITIONS = { InheritanceDepthEntryV1: {"additionalProperties":false,"properties":{"depth":{"format":"uint64","minimum":0,"type":"integer"},"file":{"type":"string"},"id":{"type":"string"},"kind":{"type":"string"},"line":{"format":"uint32","minimum":0,"type":"integer"},"name":{"type":"string"}},"required":["id","name","kind","file","line","depth"],"type":"object"}, InsertResult: {"description":"Result of an insert-at operation.","properties":{"anchor_line":{"format":"uint32","minimum":0,"type":"integer"},"before":{"type":"boolean"},"content":{"type":"string"},"diff":{"description":"Bounded preview diff of the would-be change. Populated only on a\nsuccessful dry run; `None` for real edits and for failures.","type":["string","null"]},"dry_run":{"description":"True when this was a dry run: the insertion point was resolved and the\nresulting content computed, but nothing was written to disk.","type":"boolean"},"file_path":{"type":"string"},"message":{"type":"string"},"success":{"type":"boolean"}},"required":["success","file_path","anchor_line","content","before","message"],"type":"object"}, InvestigationHandoffSurfaceV1: {"additionalProperties":false,"properties":{"finding_id":{"$ref":"#/$defs/FeedbackFindingId"},"owner_version_digest":{"$ref":"#/$defs/ManifestDigest"}},"required":["finding_id","owner_version_digest"],"type":"object"}, + LanguageServerAnalyzerStateV1: {"description":"State of one analyzer as the daemon owner holds it.\n\n`Inactive` is the one state the aggregate never takes: the language has no\nfiles in the project, so Doctor does not grade it, but `lsp servers` still\nlists it from this same read so both surfaces share one authority.","enum":["ready","available","refreshing","disabled","unavailable","crashed","inactive"],"type":"string"}, + LanguageServerAnalyzerV1: {"description":"Live state of one analyzer the daemon resolved for the current project.\n\n`LanguageServerStateV1` is the aggregate the finding is graded on; this is\nthe per-analyzer evidence behind it, so an operator learns *which*\nexecutable is missing and how to install it, resolved by the daemon\nprocess (the only PATH that matters, since the daemon spawns analyzers)\nrather than by whichever shell ran the CLI.","properties":{"command":{"description":"The configured executable, after any operator command override.","type":"string"},"detail":{"description":"The owner's last recorded error for this analyzer, when one exists.","type":["string","null"]},"executable_found":{"description":"Whether the daemon process finds `command` on its own PATH. For an\nactive analyzer `state` is the finer verdict (a rustup proxy whose\ntoolchain lacks the component is found yet `Unavailable`); for an\ninactive one this is the only availability evidence.","type":"boolean"},"install":{"description":"The first install command the adapter advertises, when one exists.","type":["string","null"]},"language":{"description":"Adapter language (`typescript`, `rust`, …).","type":"string"},"state":{"$ref":"#/$defs/LanguageServerAnalyzerStateV1"}},"required":["language","command","state","executable_found"],"type":"object"}, + LanguageServerReadV1: {"description":"One live read from the daemon language-server/analyzer owner.","oneOf":[{"description":"The owner observed all project-active analyzer states.","properties":{"analyzers":{"default":[],"description":"Every analyzer the owner resolved, active or not; the aggregate\n`state` covers the active ones only.","items":{"$ref":"#/$defs/LanguageServerAnalyzerV1"},"type":"array"},"coverage":{"$ref":"#/$defs/DoctorCoverageCompletenessV1"},"kind":{"const":"observed","type":"string"},"state":{"$ref":"#/$defs/LanguageServerStateV1"}},"required":["kind","state","coverage"],"type":"object"},{"description":"Language-server inspection is unsupported on this build/platform.","properties":{"kind":{"const":"unsupported","type":"string"}},"required":["kind"],"type":"object"},{"description":"No project-active analyzer is configured. The owner's inactive\nanalyzers are still carried so `lsp servers` can list them.","properties":{"analyzers":{"default":[],"items":{"$ref":"#/$defs/LanguageServerAnalyzerV1"},"type":"array"},"kind":{"const":"absent","type":"string"}},"required":["kind"],"type":"object"},{"description":"Authorization to inspect analyzer state was denied.","properties":{"kind":{"const":"denied","type":"string"}},"required":["kind"],"type":"object"},{"description":"Analyzer state could not be determined.","properties":{"kind":{"const":"unknown","type":"string"}},"required":["kind"],"type":"object"}]}, + LanguageServerStateV1: {"description":"Aggregate state of the project-active language-server analyzers.","oneOf":[{"const":"ready","description":"Every active analyzer is ready.","type":"string"},{"const":"available","description":"At least one analyzer is installed but has not produced a ready snapshot.","type":"string"},{"const":"refreshing","description":"At least one analyzer is currently refreshing/indexing.","type":"string"},{"const":"disabled","description":"At least one project analyzer is disabled.","type":"string"},{"const":"unavailable","description":"At least one project analyzer executable is unavailable.","type":"string"},{"const":"crashed","description":"At least one analyzer process crashed.","type":"string"}]}, LargestEntryV1: {"additionalProperties":false,"properties":{"end_line":{"format":"uint32","minimum":0,"type":"integer"},"file":{"type":"string"},"id":{"type":"string"},"kind":{"type":"string"},"lines":{"format":"uint32","minimum":0,"type":"integer"},"name":{"type":"string"},"start_line":{"format":"uint32","minimum":0,"type":"integer"}},"required":["id","name","kind","file","start_line","end_line","lines"],"type":"object"}, LatencyDistributionReadModelV1: {"description":"p50/p95/p99 for one provider operation latency stage.","properties":{"p50":{"$ref":"#/$defs/MetricValueV1"},"p95":{"$ref":"#/$defs/MetricValueV1"},"p99":{"$ref":"#/$defs/MetricValueV1"}},"required":["p50","p95","p99"],"type":"object"}, LcmAuthorityOutcomeV1: {"oneOf":[{"properties":{"state":{"const":"ready","type":"string"}},"required":["state"],"type":"object"},{"properties":{"state":{"const":"denied","type":"string"}},"required":["state"],"type":"object"},{"properties":{"state":{"const":"cancelled","type":"string"}},"required":["state"],"type":"object"},{"properties":{"state":{"const":"timed_out","type":"string"}},"required":["state"],"type":"object"},{"properties":{"reason":{"type":"string"},"state":{"const":"unavailable","type":"string"}},"required":["state","reason"],"type":"object"},{"properties":{"diagnostic":{"type":"string"},"state":{"const":"failed","type":"string"}},"required":["state","diagnostic"],"type":"object"}]}, @@ -2303,6 +2434,10 @@ const DEFINITIONS = { PrimitiveUnavailableEvidenceV1: {"additionalProperties":false,"properties":{"detail":{"type":"string"},"reason_code":{"type":"string"},"retryable":{"type":"boolean"},"status":{"$ref":"#/$defs/PrimitiveUnavailableStatusV1"}},"required":["status","reason_code","retryable","detail"],"type":"object"}, PrimitiveUnavailableStatusV1: {"enum":["unavailable"],"type":"string"}, ProjectId: {"description":"Strongly typed canonical identity: `ProjectId`.","type":"string"}, + ProjectRegistryEntry: {"properties":{"alias_count":{"format":"uint","minimum":0,"type":"integer"},"artifact_count":{"format":"uint","minimum":0,"type":"integer"},"branches":{"items":{"type":"string"},"type":"array"},"canonical_root":{"type":"string"},"default_branch":{"description":"Repository default branch recorded at registration.","type":["string","null"]},"head_branch":{"description":"Branch the checkout's HEAD names now; `None` when HEAD is detached or\nno checkout of this project could be read.","type":["string","null"]},"is_active":{"type":["boolean","null"]},"kind":{"type":"string"},"label":{"type":"string"},"last_seen_at":{"format":"int64","type":"integer"},"project_id":{"type":"string"},"project_root":{"type":"string"},"store_count":{"format":"uint","minimum":0,"type":"integer"}},"required":["project_id","label","project_root","canonical_root","kind","branches","store_count","artifact_count","alias_count","last_seen_at"],"type":"object"}, + ProjectRegistrySummary: {"properties":{"project_count":{"format":"uint","minimum":0,"type":"integer"},"repo_count":{"format":"uint","minimum":0,"type":"integer"},"truncated":{"type":"boolean"}},"required":["project_count","repo_count","truncated"],"type":"object"}, + ProjectRepoGroup: {"properties":{"branches":{"items":{"type":"string"},"type":"array"},"git_common_dir":{"type":["string","null"]},"label":{"type":"string"},"project_count":{"format":"uint","minimum":0,"type":"integer"},"projects":{"items":{"$ref":"#/$defs/ProjectRegistryEntry"},"type":"array"}},"required":["label","project_count","branches","projects"],"type":"object"}, + ProjectStatusV1: {"additionalProperties":false,"properties":{"active_branch":{"type":["string","null"]},"branch_diagnostics":true,"branch_drifted":{"type":["boolean","null"]},"branch_mismatch":{"anyOf":[{"$ref":"#/$defs/StatusBranchMismatchV1"},{"type":"null"}]},"branch_resolution":{"type":["string","null"]},"branch_warnings":{"items":{"type":"string"},"type":["array","null"]},"code_index_freshness":{"$ref":"#/$defs/StatusCodeIndexFreshnessV1"},"code_index_freshness_warning":{"type":["string","null"]},"current_branch":{"type":["string","null"]},"git_staleness":{"anyOf":[{"$ref":"#/$defs/StatusGitStalenessV1"},{"type":"null"}]},"github_source":{"description":"The checkout's GitHub source as its advisory owner observed it."},"graph_statistics":{"description":"The exact-scope sealed-generation census."},"live_branch":{"type":["string","null"]},"memory":{"$ref":"#/$defs/StatusMemoryV1"},"parent_branch":{"type":["string","null"]},"project_root":{"type":"string"},"reset_required_stores":{"description":"Registered stores this binary serves only as a typed reset-required\nrefusal, each with the command that resets it.","items":{"$ref":"#/$defs/StoreResetRequiredV1"},"type":"array"},"retrieval_serving":{"anyOf":[{"$ref":"#/$defs/StatusRetrievalServingV1"},{"type":"null"}],"description":"Whether exact-scope retrieval can serve, when the census authority is\nattached."},"schema_convergence":{"$ref":"#/$defs/StatusSchemaConvergenceV1"},"scope_prefix":{"type":["string","null"]},"server":{"description":"The serving MCP server's request counters."},"serving_branch":{"type":["string","null"]},"session_history_catch_up":true,"session_ingest":true,"storage_health":true,"tracked_branch_count":{"format":"uint","minimum":0,"type":["integer","null"]},"wait":{"anyOf":[{"$ref":"#/$defs/CodeIndexReadinessWaitOutcomeV1"},{"type":"null"}]}},"required":["project_root","graph_statistics","memory","schema_convergence","reset_required_stores","code_index_freshness","github_source"],"type":"object"}, ProjectionGenerationId: {"description":"Strongly typed canonical identity: `ProjectionGenerationId`.","type":"string"}, ProposalId: {"description":"Strongly typed canonical identity: `ProposalId`.","type":"string"}, ProtectedChange: {"description":"The protected configuration operation set. Ordinary scalar mutations are\nintentionally absent; they activate directly after validation.","oneOf":[{"properties":{"kind":{"const":"bind_source","type":"string"},"value":{"$ref":"#/$defs/ScopeSourceBinding"}},"required":["kind","value"],"type":"object"},{"properties":{"kind":{"const":"rebind_source","type":"string"},"value":{"$ref":"#/$defs/ScopeSourceBinding"}},"required":["kind","value"],"type":"object"},{"properties":{"kind":{"const":"unbind_source","type":"string"},"value":{"properties":{"binding_id":{"$ref":"#/$defs/SourceBindingId"}},"required":["binding_id"],"type":"object"}},"required":["kind","value"],"type":"object"},{"properties":{"kind":{"const":"upsert_access_rule","type":"string"},"value":{"$ref":"#/$defs/ScopeAccessRule"}},"required":["kind","value"],"type":"object"},{"properties":{"kind":{"const":"remove_access_rule","type":"string"},"value":{"properties":{"rule_id":{"$ref":"#/$defs/AccessRuleId"}},"required":["rule_id"],"type":"object"}},"required":["kind","value"],"type":"object"},{"properties":{"kind":{"const":"replace_work_topology_policy","type":"string"},"value":{"$ref":"#/$defs/WorkTopologyPolicyV1"}},"required":["kind","value"],"type":"object"}]}, @@ -2316,6 +2451,7 @@ const DEFINITIONS = { ProximityAddressV1: {"additionalProperties":false,"description":"A privacy-scoped code address. It identifies the coarse changed-code shape\nbut carries no other actor, session, or private-source content.","properties":{"file":{"$ref":"#/$defs/FileOccurrenceId"},"scope":{"$ref":"#/$defs/FeedbackScopeV1"},"span":{"anyOf":[{"$ref":"#/$defs/SourceSpan"},{"type":"null"}]},"symbol":{"anyOf":[{"$ref":"#/$defs/SymbolOccurrenceId"},{"type":"null"}]}},"required":["scope","file"],"type":"object"}, ProximityCoverageV1: {"enum":["complete","partial","stale","unavailable","denied","private"],"type":"string"}, ProximityWarningClassV1: {"enum":["same_file","overlapping_range","same_symbol","same_package","same_crate","neighborhood","shared_caller","shared_dependency","shared_test","incompatible_branch_worktree"],"type":"string"}, + PublicCodeProject: {"properties":{"canonical_root":{"type":"string"},"created_at":{"format":"int64","type":"integer"},"default_branch":{"description":"Repository default branch recorded at registration.","type":["string","null"]},"display_root":{"type":"string"},"git_common_dir":{"type":["string","null"]},"head_branch":{"description":"Branch the checkout's HEAD names now; `None` when HEAD is detached or\nno checkout of this project could be read.","type":["string","null"]},"is_active":{"type":["boolean","null"]},"label":{"type":"string"},"last_seen_at":{"format":"int64","type":"integer"},"project_id":{"type":"string"},"project_root":{"type":"string"}},"required":["project_id","label","project_root","display_root","canonical_root","created_at","last_seen_at"],"type":"object"}, QuantityEvidenceClassV1: {"enum":["owner_receipt","locally_measured","estimated","unknown"],"type":"string"}, QueryCollectionId: {"description":"Strongly typed canonical identity: `QueryCollectionId`.","type":"string"}, RankDirectionV1: {"description":"Which endpoint of each counted edge the rank report ranks.","enum":["incoming","outgoing"],"type":"string"}, @@ -2343,6 +2479,12 @@ const DEFINITIONS = { RejectedArgumentGroupV1: {"description":"One surface × operation × argument × error-class cell in the rejected-argument view.","properties":{"argument":{"$ref":"#/$defs/RejectedArgumentNameV1"},"count":{"format":"uint64","minimum":0,"type":"integer"},"error_class":{"$ref":"#/$defs/RejectedArgumentErrorClassV1"},"operation":{"type":"string"},"rate":{"description":"Eligible-attempt rate for this cell. Absent when the attempt\ndenominator or coverage is insufficient.","format":"double","type":["number","null"]},"surface":{"$ref":"#/$defs/RejectedArgumentSurfaceV1"}},"required":["surface","operation","argument","error_class","count"],"type":"object"}, RejectedArgumentNameV1: {"description":"Normalized rejected-argument name. Raw flags, values, and tokens never\nenter this vocabulary.","enum":["request_body","pagination","request_handle","operation","lifecycle","unknown"],"type":"string"}, RejectedArgumentSurfaceV1: {"description":"Transport that rejected a surface argument. Unknown preserves missing\nattribution instead of inventing cli/mcp/http.","enum":["cli","mcp","http","unknown"],"type":"string"}, + RemoteAuthorityUnavailableReasonV1: {"enum":["registry_unavailable","placement_unknown","authority_unreachable","authority_authentication_failed","caller_authentication_failed","enrollment_expired","enrollment_revoked","insufficient_capability","scope_mismatch","fence_unverified","protocol_incompatible"],"type":"string"}, + RemoteListenerReadV1: {"enum":["serving","disabled","degraded"],"type":"string"}, + RemoteOperationalReadinessV1: {"enum":["unconfigured","partial","ready","recovery_required"],"type":"string"}, + RemoteOperationalStatusV1: {"additionalProperties":false,"properties":{"authority":{"$ref":"#/$defs/CurrentRemoteAuthorityStateV1"},"enrollment_configured":{"type":"boolean"},"failover_in_progress":{"type":"boolean"},"observed_at":{"$ref":"#/$defs/UtcMicros"},"readiness":{"$ref":"#/$defs/RemoteOperationalReadinessV1"},"recovery_required":{"type":"boolean"},"replay_coverage_complete":{"type":"boolean"},"spool":{"$ref":"#/$defs/RemoteSpoolOperationalStatusV1"}},"required":["readiness","enrollment_configured","authority","spool","replay_coverage_complete","failover_in_progress","recovery_required","observed_at"],"type":"object"}, + RemoteSpoolOperationalStatusV1: {"additionalProperties":false,"properties":{"has_sequence_gap":{"type":"boolean"},"pending_count":{"format":"uint64","minimum":0,"type":"integer"},"quarantined_count":{"format":"uint64","minimum":0,"type":"integer"}},"required":["pending_count","quarantined_count","has_sequence_gap"],"type":"object"}, + RemoteWriterFenceV1: {"additionalProperties":false,"description":"The complete single-writer identity for one mutable shard.","properties":{"authority_epoch":{"$ref":"#/$defs/AuthorityEpoch"},"authority_node_id":{"$ref":"#/$defs/BrainNodeId"},"brain_id":{"$ref":"#/$defs/BrainId"},"generation_id":{"$ref":"#/$defs/ProjectionGenerationId"},"placement_revision":{"format":"uint64","minimum":0,"type":"integer"},"shard_id":{"$ref":"#/$defs/ShardId"}},"required":["brain_id","shard_id","generation_id","placement_revision","authority_epoch","authority_node_id"],"type":"object"}, RenameDispositionCountsV1: {"additionalProperties":false,"properties":{"blocked":{"format":"uint","minimum":0,"type":"integer"},"changed":{"format":"uint","minimum":0,"type":"integer"},"skipped":{"format":"uint","minimum":0,"type":"integer"},"unchanged":{"format":"uint","minimum":0,"type":"integer"}},"required":["changed","unchanged","skipped","blocked"],"type":"object"}, RenameFileEditV1: {"additionalProperties":false,"description":"One file a rename changed (or would change), with the exact bound-site count.","properties":{"file":{"type":"string"},"replaced_count":{"format":"uint","minimum":0,"type":"integer"}},"required":["file","replaced_count"],"type":"object"}, RenameHazardKindV1: {"enum":["invalid_identifier","stale_evidence","ambiguous_symbol","namespace_collision","changed_resolution","shadowing","unsupported_syntax","macro_expansion","generated_source","overlapping_site"],"type":"string"}, @@ -2368,6 +2510,7 @@ const DEFINITIONS = { RepositoryWorkingTreeStateV1: {"enum":["clean","tracked_dirty","untracked_only","mixed","conflicted","unreadable"],"type":"string"}, RequiredCheckExpectationV1: {"enum":["successful_terminal"],"type":"string"}, RequiredCheckV1: {"additionalProperties":false,"properties":{"capability_id":{"$ref":"#/$defs/CapabilityId"},"expectation":{"$ref":"#/$defs/RequiredCheckExpectationV1"},"maximum_age_seconds":{"format":"uint32","minimum":1,"type":"integer"}},"required":["capability_id","expectation","maximum_age_seconds"],"type":"object"}, + ResidentMemoryHolderReadV1: {"description":"One worktree holding a retained owner's memory, and what it holds: a\ngeneration id, or an LSP session id.","properties":{"holding":{"type":"string"},"worktree_id":{"type":"string"}},"required":["worktree_id","holding"],"type":"object"}, ResolvedScope: {"additionalProperties":false,"description":"The resolved configuration scope is one exact project/repository/worktree root.\n\nPaths, CWDs, labels, and mutable branch spellings are deliberately absent.","properties":{"project_id":{"$ref":"#/$defs/ProjectId"},"reference":{"anyOf":[{"$ref":"#/$defs/RefId"},{"type":"null"}]},"repository_id":{"$ref":"#/$defs/RepositoryId"},"scope_digest":{"$ref":"#/$defs/ManifestDigest"},"worktree_id":{"$ref":"#/$defs/WorktreeId"}},"required":["project_id","repository_id","worktree_id","scope_digest"],"type":"object"}, RestartRequirementV1: {"enum":["none","analyzer_restart","daemon_restart"],"type":"string"}, ResultProjection: {"description":"Bounded output projection chosen by a concrete use case.","enum":["summary","evidence","references_only"],"type":"string"}, @@ -2395,10 +2538,15 @@ const DEFINITIONS = { RootScopeOutcomeV1ForNullableString: {"additionalProperties":false,"description":"One typed outcome pinned to the digest of an exact resolved root.","properties":{"outcome":{"$ref":"#/$defs/ScopeOutcome_for_Nullable_string"},"scope_digest":{"$ref":"#/$defs/ManifestDigest"}},"required":["scope_digest","outcome"],"type":"object"}, RuleEffect: {"enum":["allow","deny"],"type":"string"}, RunId: {"description":"Strongly typed canonical identity: `RunId`.","type":"string"}, + RuntimeDoctorReportV1: {"description":"The daemon's canonical Doctor report as this route could read it.","oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"observed","type":"string"},"language_servers":{"$ref":"#/$defs/LanguageServerReadV1"},"report":{"$ref":"#/$defs/DoctorReportV1"},"schema_convergences":{"items":{"$ref":"#/$defs/SchemaConvergenceFindingV1"},"type":"array"},"table_growth_evidence":{"items":{"$ref":"#/$defs/TableGrowthDoctorEvidenceV1"},"type":"array"}},"required":["kind","report","table_growth_evidence","schema_convergences","language_servers"],"type":"object"},{"additionalProperties":false,"description":"The reader is mounted and the read failed.","properties":{"kind":{"const":"unknown","type":"string"},"language_servers":{"$ref":"#/$defs/LanguageServerReadV1"},"schema_convergences":{"items":{"$ref":"#/$defs/SchemaConvergenceFindingV1"},"type":"array"},"table_growth_evidence":{"items":{"$ref":"#/$defs/TableGrowthDoctorEvidenceV1"},"type":"array"}},"required":["kind","table_growth_evidence","schema_convergences","language_servers"],"type":"object"},{"additionalProperties":false,"description":"No Doctor reader is mounted on this route.","properties":{"kind":{"const":"unsupported","type":"string"},"language_servers":{"$ref":"#/$defs/LanguageServerReadV1"},"schema_convergences":{"items":{"$ref":"#/$defs/SchemaConvergenceFindingV1"},"type":"array"},"table_growth_evidence":{"items":{"$ref":"#/$defs/TableGrowthDoctorEvidenceV1"},"type":"array"}},"required":["kind","table_growth_evidence","schema_convergences","language_servers"],"type":"object"}]}, SanitizationReceiptId: {"description":"Strongly typed canonical identity: `SanitizationReceiptId`.","type":"string"}, SanitizationReceiptRefV1: {"additionalProperties":false,"description":"Reference to a capture-owned sanitization receipt.\n\nReceipt references are the explicit boundary between untrusted wire data and\nthe proof-carrying text types below. They do not claim that the domain crate\nran a sanitizer; the capture layer owns issuance and persistence of receipts.","properties":{"receipt_id":{"$ref":"#/$defs/SanitizationReceiptId"},"sanitizer_version":{"$ref":"#/$defs/ComponentVersion"}},"required":["receipt_id","sanitizer_version"],"type":"object"}, SanitizationReceiptV1: {"additionalProperties":false,"properties":{"disposition":{"$ref":"#/$defs/SanitizerDispositionV1"},"payload":{"anyOf":[{"$ref":"#/$defs/PayloadReferenceV1"},{"type":"null"}]},"receipt":{"$ref":"#/$defs/SanitizationReceiptRefV1"},"sensitivity":{"$ref":"#/$defs/SensitivityV1"}},"required":["receipt","disposition","sensitivity"],"type":"object"}, SanitizerDispositionV1: {"enum":["accepted","redacted","rejected","quarantined"],"type":"string"}, + SchemaConvergenceFindingV1: {"additionalProperties":false,"properties":{"degraded_row":{"type":["string","null"]},"progress":{"anyOf":[{"$ref":"#/$defs/SchemaConvergenceProgressV1"},{"type":"null"}]},"stage":{"$ref":"#/$defs/SchemaConvergenceStageV1"},"started_at_micros":{"format":"int64","type":"integer"},"state":{"$ref":"#/$defs/SchemaConvergenceStateV1"},"store":{"type":"string"}},"required":["store","stage","state","started_at_micros"],"type":"object"}, + SchemaConvergenceProgressV1: {"oneOf":[{"additionalProperties":false,"properties":{"done":{"format":"uint64","minimum":0,"type":"integer"},"remaining":{"format":"uint64","minimum":0,"type":"integer"},"unit":{"const":"rows","type":"string"}},"required":["unit","done","remaining"],"type":"object"},{"additionalProperties":false,"properties":{"done":{"format":"uint64","minimum":0,"type":"integer"},"remaining":{"format":"uint64","minimum":0,"type":"integer"},"unit":{"const":"pages","type":"string"}},"required":["unit","done","remaining"],"type":"object"}]}, + SchemaConvergenceStageV1: {"enum":["registered_schema"],"type":"string"}, + SchemaConvergenceStateV1: {"enum":["pending_schema_migration","released_shape_convergence_in_progress","degraded","completed"],"type":"string"}, ScopeAccessRule: {"additionalProperties":false,"description":"Restrictive policy input. An allow never grants capabilities absent from\nthe independently authorized capability set passed to the resolver.","properties":{"authority":{"$ref":"#/$defs/AuthorityRef"},"capabilities":{"items":{"$ref":"#/$defs/CapabilityId"},"type":"array","uniqueItems":true},"effect":{"$ref":"#/$defs/RuleEffect"},"expires_at":{"anyOf":[{"$ref":"#/$defs/UtcMicros"},{"type":"null"}]},"rule_id":{"$ref":"#/$defs/AccessRuleId"},"subject":{"$ref":"#/$defs/ScopeAccessSubjectV1"}},"required":["rule_id","subject","authority","capabilities","effect"],"type":"object"}, ScopeAccessSubjectV1: {"additionalProperties":false,"description":"Typed rule selectors. Unset dimensions match all values at that dimension,\nbut at least one dimension must be constrained. Free-form paths, labels,\ncollection names, and branch names are deliberately absent.","properties":{"actor":{"anyOf":[{"$ref":"#/$defs/ActorId"},{"type":"null"}]},"operation":{"anyOf":[{"$ref":"#/$defs/ScopeControlOperationV1"},{"type":"null"}]},"source_kind":{"anyOf":[{"$ref":"#/$defs/SourceKindV1"},{"type":"null"}]}},"type":"object"}, ScopeControlOperationV1: {"enum":["read","source_bind","source_rebind","source_unbind","access_rule_upsert","access_rule_remove","replace_topology_policy","rollback"],"type":"string"}, @@ -2460,6 +2608,7 @@ const DEFINITIONS = { SettingKey: {"description":"Typed configuration key. Keys are lowercase, dotted product identifiers;\nuntyped host/adapter keys are not representable.","type":"string"}, SettingSensitivityV1: {"enum":["public","sensitive"],"type":"string"}, SettingSummary: {"properties":{"key":{"$ref":"#/$defs/SettingKey"},"restart_requirement":{"$ref":"#/$defs/RestartRequirementV1"},"sensitivity":{"$ref":"#/$defs/SettingSensitivityV1"}},"required":["key","sensitivity","restart_requirement"],"type":"object"}, + ShardId: {"description":"Strongly typed canonical identity: `ShardId`.","type":"string"}, SharedProfileStoreLocatorV1: {"additionalProperties":false,"description":"Logical and verified physical identity of the shared Profile shard.\n\nBrain and profile IDs select the shard; the verified store locator binds its\nphysical store. Lease incarnations and authority epochs remain runtime fences.","properties":{"brain_id":{"$ref":"#/$defs/BrainId"},"profile_id":{"$ref":"#/$defs/UserProfileId"},"store_id":{"type":"string"}},"required":["brain_id","profile_id","store_id"],"type":"object"}, SimilarCoverageV1: {"oneOf":[{"additionalProperties":false,"properties":{"status":{"const":"complete","type":"string"}},"required":["status"],"type":"object"},{"additionalProperties":false,"properties":{"status":{"const":"partial","type":"string"}},"required":["status"],"type":"object"},{"additionalProperties":false,"properties":{"minimum_tokens":{"format":"uint32","minimum":0,"type":"integer"},"status":{"const":"excluded_too_small","type":"string"}},"required":["status","minimum_tokens"],"type":"object"},{"additionalProperties":false,"properties":{"maximum_bytes":{"format":"uint64","minimum":0,"type":"integer"},"maximum_tokens":{"format":"uint32","minimum":0,"type":"integer"},"status":{"const":"excluded_too_large","type":"string"}},"required":["status","maximum_tokens","maximum_bytes"],"type":"object"},{"additionalProperties":false,"properties":{"status":{"const":"excluded_incomplete_tokenization","type":"string"}},"required":["status"],"type":"object"}]}, SimilarFamilyV1: {"additionalProperties":false,"properties":{"complete":{"type":"boolean"},"family_digest":{"$ref":"#/$defs/ManifestDigest"},"match_class":{"$ref":"#/$defs/SimilarMatchClassV1"},"member_count":{"format":"uint","minimum":0,"type":"integer"},"members":{"items":{"$ref":"#/$defs/SimilarOccurrenceV1"},"type":"array"},"next_cursor":{"type":["string","null"]},"normalization_revision":{"format":"uint16","maximum":65535,"minimum":0,"type":"integer"},"representative_payload_digest":{"$ref":"#/$defs/ManifestDigest"}},"required":["match_class","normalization_revision","family_digest","representative_payload_digest","member_count","members","complete"],"type":"object"}, @@ -2497,7 +2646,22 @@ const DEFINITIONS = { StackSignalId: {"description":"Strongly typed canonical identity: `StackSignalId`.","type":"string"}, StackSignalKindV1: {"description":"Durable classification of one GitHub stack transition.","enum":["dependency_ready","actual_conflict","stack_tip_drift","pull_request_drift","ci_evaluated_commit_drift","integration_committed","integration_needs_inspection"],"type":"string"}, StartWorkAttemptCommand: {"additionalProperties":false,"description":"Starts one admitted provider attempt. Every field is a typed fact; there\nis no argv, environment entry, executable path, or shell string here. The\nprojection binding and admission facts are re-read from the canonical Work\nauthority, never trusted from the caller.","properties":{"attempt_id":{"$ref":"#/$defs/AttemptId"},"commit":{"$ref":"#/$defs/CommitId"},"effect_state":{"$ref":"#/$defs/WorkEffectStateV1"},"execution_snapshot":{"$ref":"#/$defs/WorkExecutionSnapshot"},"instructions":{"type":"string"},"occurred_at":{"$ref":"#/$defs/UtcMicros"},"operation":{"$ref":"#/$defs/WorkflowOperationRef"},"reference":{"anyOf":[{"$ref":"#/$defs/RefId"},{"type":"null"}]},"run_id":{"$ref":"#/$defs/RunId"},"task_id":{"$ref":"#/$defs/TaskId"},"worktree_root":{"type":"string"}},"required":["task_id","run_id","attempt_id","operation","execution_snapshot","worktree_root","commit","instructions","effect_state","occurred_at"],"type":"object"}, + StatusAdmissionV1: {"additionalProperties":false,"properties":{"project_admitted":{"type":"boolean"},"project_root":{"type":"string"},"scope_prefix":{"type":["string","null"]},"server":{"description":"The serving MCP server's request counters."}},"required":["project_admitted","project_root"],"type":"object"}, + StatusBranchMismatchV1: {"additionalProperties":false,"properties":{"git_branch":{"type":["string","null"]},"indexed_branch":{"type":["string","null"]},"serving_branch":{"type":["string","null"]}},"type":"object"}, + StatusCodeIndexFreshnessV1: {"description":"The code-index freshness of the served worktree, labeled the way readiness\nwaits report their last state.","oneOf":[{"additionalProperties":false,"properties":{"status":{"const":"current","type":"string"},"worktree":{"$ref":"#/$defs/CodeIndexWorktreeFreshnessV1"}},"required":["status","worktree"],"type":"object"},{"additionalProperties":false,"properties":{"status":{"const":"stale","type":"string"},"worktree":{"$ref":"#/$defs/CodeIndexWorktreeFreshnessV1"}},"required":["status","worktree"],"type":"object"},{"additionalProperties":false,"properties":{"status":{"const":"restoring","type":"string"},"worktree":{"$ref":"#/$defs/CodeIndexWorktreeFreshnessV1"}},"required":["status","worktree"],"type":"object"},{"additionalProperties":false,"properties":{"status":{"const":"warming","type":"string"},"worktree":{"$ref":"#/$defs/CodeIndexWorktreeFreshnessV1"}},"required":["status","worktree"],"type":"object"},{"additionalProperties":false,"properties":{"status":{"const":"parked","type":"string"},"worktree":{"$ref":"#/$defs/CodeIndexWorktreeFreshnessV1"}},"required":["status","worktree"],"type":"object"},{"additionalProperties":false,"properties":{"reason":{"type":"string"},"status":{"const":"unavailable","type":"string"}},"required":["status","reason"],"type":"object"}]}, + StatusGitStalenessV1: {"additionalProperties":false,"properties":{"message":{"type":"string"},"reason":{"type":"string"},"status":{"type":"string"}},"required":["status","reason","message"],"type":"object"}, + StatusMemoryOwnerV1: {"additionalProperties":false,"properties":{"bytes":{"format":"uint64","minimum":0,"type":["integer","null"]},"content_digest":{"type":["string","null"]},"holders":{"items":{"$ref":"#/$defs/ResidentMemoryHolderReadV1"},"type":"array"},"idle_seconds":{"format":"uint64","minimum":0,"type":"integer"},"kind":{"type":"string"},"measured":{"type":"boolean"},"project_id":{"type":"string"},"protected":{"type":"boolean"}},"required":["project_id","kind","holders","measured","idle_seconds","protected"],"type":"object"}, + StatusMemoryPressureV1: {"enum":["unobserved","nominal","over_budget"],"type":"string"}, + StatusMemoryV1: {"additionalProperties":false,"description":"The daemon's resident memory as one project sees it.","properties":{"high_watermark_bytes":{"format":"uint64","minimum":0,"type":"integer"},"idle_window_seconds":{"format":"uint64","minimum":0,"type":"integer"},"limit_bytes":{"format":"uint64","minimum":0,"type":"integer"},"low_watermark_bytes":{"format":"uint64","minimum":0,"type":"integer"},"owners":{"description":"This project's retained owners; other projects' belong to the\ndaemon-wide Doctor inventory.","items":{"$ref":"#/$defs/StatusMemoryOwnerV1"},"type":"array"},"psi_some_avg10":{"format":"double","type":["number","null"]},"resident_bytes":{"format":"uint64","minimum":0,"type":["integer","null"]},"retained_bytes":{"format":"uint64","minimum":0,"type":"integer"},"shed_order":{"items":{"type":"string"},"type":"array"},"status":{"$ref":"#/$defs/StatusMemoryPressureV1"},"unmeasured_owners":{"format":"uint","minimum":0,"type":"integer"}},"required":["status","limit_bytes","high_watermark_bytes","low_watermark_bytes","idle_window_seconds","shed_order","retained_bytes","unmeasured_owners","owners"],"type":"object"}, + StatusRetrievalServingV1: {"oneOf":[{"additionalProperties":false,"description":"A sealed complete generation serves the exact worktree. The ages tell a\nroutine rebuild window from a wedged route.","properties":{"condition":{"anyOf":[{"$ref":"#/$defs/StatusServingConditionV1"},{"type":"null"}]},"freshness":{"$ref":"#/$defs/StatusServingFreshnessV1"},"last_reconcile_age_seconds":{"format":"int64","type":["integer","null"]},"seated_generation_age_seconds":{"format":"int64","type":["integer","null"]},"status":{"const":"serving","type":"string"}},"required":["status","freshness"],"type":"object"},{"additionalProperties":false,"description":"The census answered and nothing is servable yet.","properties":{"reason":{"type":"string"},"status":{"const":"unavailable","type":"string"}},"required":["status","reason"],"type":"object"}]}, + StatusSchemaConvergenceStateV1: {"enum":["completed","in_progress","degraded"],"type":"string"}, + StatusSchemaConvergenceV1: {"additionalProperties":false,"properties":{"findings":{"items":{"$ref":"#/$defs/SchemaConvergenceFindingV1"},"type":"array"},"status":{"$ref":"#/$defs/StatusSchemaConvergenceStateV1"}},"required":["status","findings"],"type":"object"}, + StatusServingConditionV1: {"enum":["artifact_restore","source_verification","rebuilding","stalled"],"type":"string"}, + StatusServingFreshnessV1: {"enum":["current","restoring","last_complete_stale","unknown"],"type":"string"}, + StorageByteSizeV1: {"description":"A byte size measurement. A newtype keeps sizes from being confused with\ncounts, ratios, or timestamps in the read models and producers.","format":"uint64","minimum":0,"type":"integer"}, StorageStatusHistoryPointV1: {"additionalProperties":false,"properties":{"database_bytes":{"format":"uint64","minimum":0,"type":"integer"},"observed_at":{"format":"int64","type":"integer"}},"required":["observed_at","database_bytes"],"type":"object"}, + StoreKeyV1: {"description":"Logical name of one owner-profile store (for example `sessions.db`,\n`graph.db`, or `projects/proj_x`). Never an absolute on-disk path.","type":"string"}, + StoreResetRequiredV1: {"description":"A persisted store the daemon keeps mounted in a typed reset-required state\ninstead of refusing to serve: every read against it returns the typed\nrefusal, stores that admit keep serving, and `remedy` is the exact command\nthe operator runs to reset it.","properties":{"authority":{"type":"string"},"found_version":{"format":"int64","type":["integer","null"]},"reason":{"type":"string"},"remedy":{"type":"string"},"required_version":{"format":"int64","type":["integer","null"]},"store":{"type":"string"}},"required":["store","authority","reason","remedy"],"type":"object"}, SymbolChangesCompleteV1: {"additionalProperties":false,"properties":{"status":{"$ref":"#/$defs/GitReadCompleteV1"}},"required":["status"],"type":"object"}, SymbolChangesUnavailableV1: {"additionalProperties":false,"description":"Exact base/head symbol comparison was unavailable; the git evidence beside\nit is still the answer.","properties":{"reason":{"type":"string"},"retryable":{"type":"boolean"},"status":{"$ref":"#/$defs/GitReadUnavailableV1"}},"required":["status","reason","retryable"],"type":"object"}, SymbolGraphScope: {"additionalProperties":false,"description":"Optional narrowing inside the immutable project/repository/worktree scope\ncarried by [`RequestContext`]. A path prefix never establishes identity or\nauthorization.","properties":{"path_prefix":{"type":["string","null"]}},"type":"object"}, @@ -2505,6 +2669,8 @@ const DEFINITIONS = { SymbolPrimitiveRecord: {"additionalProperties":false,"properties":{"end_line":{"format":"uint32","minimum":0,"type":"integer"},"file":{"type":"string"},"is_async":{"type":"boolean"},"kind":{"type":"string"},"line":{"description":"One-based user-facing line.","format":"uint32","minimum":0,"type":"integer"},"name":{"type":"string"},"node_id":{"type":"string"},"qualified_name":{"type":"string"},"score":{"format":"double","type":["number","null"]},"signature":{"type":["string","null"]}},"required":["node_id","name","qualified_name","kind","file","line","end_line","is_async"],"type":"object"}, SymbolRelationRecord: {"additionalProperties":false,"properties":{"depth":{"format":"uint32","minimum":0,"type":["integer","null"]},"dispatch_from":{"type":["string","null"]},"dispatch_via_trait":{"type":"boolean"},"edge_kind":{"type":"string"},"symbol":{"$ref":"#/$defs/SymbolPrimitiveRecord"}},"required":["symbol","edge_kind","dispatch_via_trait"],"type":"object"}, SymbolSignatureV1: {"additionalProperties":false,"properties":{"cost_to_expand":{"$ref":"#/$defs/NodeExpansionCostV1"},"docstring":{"type":["string","null"]},"end_line":{"format":"uint32","minimum":0,"type":"integer"},"file":{"type":"string"},"is_async":{"type":"boolean"},"kind":{"type":"string"},"name":{"type":"string"},"node_id":{"type":"string"},"qualified_name":{"type":"string"},"signature":{"type":["string","null"]},"start_line":{"format":"uint32","minimum":0,"type":"integer"},"unavailable_fields":{"items":{"type":"string"},"type":"array"},"visibility":{"type":"string"}},"required":["node_id","name","qualified_name","kind","visibility","is_async","file","start_line","end_line","cost_to_expand","unavailable_fields"],"type":"object"}, + TableGrowthDoctorEvidenceV1: {"description":"Contract-independent evidence ready to wrap in a future `TableGrowth`\nStorage finding once that generated-contract variant is available.","oneOf":[{"properties":{"current_bytes":{"$ref":"#/$defs/StorageByteSizeV1"},"current_observed_at":{"$ref":"#/$defs/UtcMicros"},"growth_bytes":{"$ref":"#/$defs/StorageByteSizeV1"},"kind":{"const":"significant_growth","type":"string"},"previous_bytes":{"$ref":"#/$defs/StorageByteSizeV1"},"previous_observed_at":{"$ref":"#/$defs/UtcMicros"},"store":{"$ref":"#/$defs/StoreKeyV1"},"table":{"$ref":"#/$defs/TableNameV1"}},"required":["kind","store","table","previous_bytes","current_bytes","growth_bytes","previous_observed_at","current_observed_at"],"type":"object"},{"properties":{"kind":{"const":"baseline_established","type":"string"},"observed_at":{"$ref":"#/$defs/UtcMicros"},"store":{"$ref":"#/$defs/StoreKeyV1"},"tables_observed":{"format":"uint64","minimum":0,"type":"integer"}},"required":["kind","store","observed_at","tables_observed"],"type":"object"},{"properties":{"current_bytes":{"$ref":"#/$defs/StorageByteSizeV1"},"kind":{"const":"table_baseline_pending","type":"string"},"observed_at":{"$ref":"#/$defs/UtcMicros"},"store":{"$ref":"#/$defs/StoreKeyV1"},"table":{"$ref":"#/$defs/TableNameV1"}},"required":["kind","store","table","current_bytes","observed_at"],"type":"object"},{"properties":{"kind":{"const":"unsupported","type":"string"},"store":{"$ref":"#/$defs/StoreKeyV1"}},"required":["kind","store"],"type":"object"},{"properties":{"kind":{"const":"denied","type":"string"},"store":{"$ref":"#/$defs/StoreKeyV1"}},"required":["kind","store"],"type":"object"},{"properties":{"kind":{"const":"unknown","type":"string"},"store":{"$ref":"#/$defs/StoreKeyV1"}},"required":["kind","store"],"type":"object"}]}, + TableNameV1: {"description":"A physical table name inside a store, used for per-table growth telemetry.","type":"string"}, TaskEvidenceLinkV1: {"additionalProperties":false,"properties":{"anchor_id":{"$ref":"#/$defs/RetrievalAnchorId"},"evidence_digest":{"$ref":"#/$defs/ManifestDigest"},"link_id":{"type":"string"},"observed_at":{"$ref":"#/$defs/UtcMicros"},"revision":{"format":"uint64","minimum":0,"type":"integer"},"task_id":{"$ref":"#/$defs/TaskId"}},"required":["link_id","revision","task_id","anchor_id","evidence_digest","observed_at"],"type":"object"}, TaskHandoffScope: {"additionalProperties":false,"properties":{"definition_id":{"$ref":"#/$defs/WorkflowDefinitionId"},"definition_version":{"format":"uint64","minimum":1,"type":"integer"},"from_actor_id":{"$ref":"#/$defs/ActorId"},"project_id":{"$ref":"#/$defs/ProjectId"},"repository_id":{"$ref":"#/$defs/RepositoryId"},"run_id":{"$ref":"#/$defs/RunId"},"step_id":{"$ref":"#/$defs/WorkflowStepId"},"task_id":{"$ref":"#/$defs/TaskId"},"thread_id":{"$ref":"#/$defs/ThreadId"},"to_actor_id":{"$ref":"#/$defs/ActorId"},"worktree_id":{"$ref":"#/$defs/WorktreeId"}},"required":["project_id","repository_id","worktree_id","definition_id","definition_version","step_id","task_id","thread_id","run_id","from_actor_id","to_actor_id"],"type":"object"}, TaskHandoffSurfaceV1: {"additionalProperties":false,"properties":{"task_id":{"$ref":"#/$defs/TaskId"},"version":{"format":"uint64","minimum":0,"type":"integer"}},"required":["task_id","version"],"type":"object"}, @@ -2793,6 +2959,8 @@ const DEFINITIONS = { WorktreeRootPolicyV1: {"additionalProperties":false,"properties":{"locator":{"$ref":"#/$defs/SensitiveFilesystemLocatorV1"},"maximum_active_worktrees":{"format":"uint16","maximum":65535,"minimum":1,"type":"integer"},"repository_scope":{"$ref":"#/$defs/RepositoryPlacementScopeV1"},"root_id":{"type":"string"}},"required":["root_id","locator","repository_scope","maximum_active_worktrees"],"type":"object"}, } satisfies Readonly>; const SCHEMAS: readonly CanonicalJsonSchema[] = [ + {"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"title":"ActiveProjectSurfaceRequestV1","type":"object"}, + {"$defs":{"ActiveProjectBranchV1":DEFINITIONS.ActiveProjectBranchV1,"ActiveProjectResolutionSourceV1":DEFINITIONS.ActiveProjectResolutionSourceV1,"ActiveProjectStorageV1":DEFINITIONS.ActiveProjectStorageV1},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"description":"The resolved active project of this MCP session.","properties":{"branch":{"$ref":"#/$defs/ActiveProjectBranchV1"},"project_id":{"type":["string","null"]},"project_root":{"type":"string"},"repository_id":{"type":"string"},"resolution_source":{"$ref":"#/$defs/ActiveProjectResolutionSourceV1"},"scope_prefix":{"type":["string","null"]},"storage":{"$ref":"#/$defs/ActiveProjectStorageV1"}},"required":["repository_id","project_root","resolution_source","storage","branch"],"title":"ActiveProjectResultV1","type":"object"}, {"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"depth":{"description":"Maximum dependency traversal depth (default: 5, at most 10).","format":"uint32","minimum":0,"type":["integer","null"]},"files":{"description":"List of changed file paths to analyze.","items":{"type":"string"},"type":"array"},"filter":{"description":"Custom glob pattern for test files (default: common test patterns).","type":["string","null"]}},"required":["files"],"title":"AffectedSurfaceRequestV1","type":"object"}, {"$defs":{"AffectedRankingMetadataV1":DEFINITIONS.AffectedRankingMetadataV1,"RankedAffectedTestV1":DEFINITIONS.RankedAffectedTestV1},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"affected_tests":{"items":{"type":"string"},"type":"array"},"changed_files":{"items":{"type":"string"},"type":"array"},"count":{"format":"uint","minimum":0,"type":"integer"},"ranked_tests":{"items":{"$ref":"#/$defs/RankedAffectedTestV1"},"type":"array"},"ranking_metadata":{"$ref":"#/$defs/AffectedRankingMetadataV1"},"recommended_tests":{"description":"Tests within two dependency hops of a changed file.","items":{"type":"string"},"type":"array"}},"required":["changed_files","affected_tests","count","ranked_tests","recommended_tests","ranking_metadata"],"title":"AffectedResultV1","type":"object"}, {"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"description":"Opaque daemon-minted handle accepted by the first feedback read invocation.","properties":{"request_handle":{"type":"string"}},"required":["request_handle"],"title":"FeedbackHandleRequestV1","type":"object"}, @@ -3024,6 +3192,11 @@ const SCHEMAS: readonly CanonicalJsonSchema[] = [ {"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"base_ref":{"description":"Base branch or ref to compare against (default: detected repository\ndefault branch). A short branch name selects the descendant of its\nlocal and origin tracking tips; use an explicit ref when they diverge.","type":["string","null"]},"cursor":{"description":"Authenticated continuation cursor returned by a previous page.","type":["string","null"]},"head_ref":{"description":"Head branch or ref (default: 'HEAD'). Accepts local branches,\nremote-tracking refs such as origin/topic, full refs, and Git revision\nexpressions.","type":["string","null"]},"maximum_symbols":{"description":"Maximum symbols returned on this page (default: 200, clamped to 1-500).","format":"uint32","minimum":0,"type":["integer","null"]}},"title":"PrContextSurfaceRequestV1","type":"object"}, {"$defs":{"ConfigSummaryKindV1":DEFINITIONS.ConfigSummaryKindV1,"ConfigSummaryV1":DEFINITIONS.ConfigSummaryV1,"GitCommitSubjectV1":DEFINITIONS.GitCommitSubjectV1,"GitComparedSymbolV1":DEFINITIONS.GitComparedSymbolV1,"GitContextSymbolV1":DEFINITIONS.GitContextSymbolV1,"GitFileChangeStatusV1":DEFINITIONS.GitFileChangeStatusV1,"GitFileChangeV1":DEFINITIONS.GitFileChangeV1,"GitReadCompleteV1":DEFINITIONS.GitReadCompleteV1,"GitReadPartialV1":DEFINITIONS.GitReadPartialV1,"GitReadUnavailableV1":DEFINITIONS.GitReadUnavailableV1,"GitToolErrorKindV1":DEFINITIONS.GitToolErrorKindV1,"GitToolErrorV1":DEFINITIONS.GitToolErrorV1,"GitToolFailureV1":DEFINITIONS.GitToolFailureV1,"GitToolOperationV1":DEFINITIONS.GitToolOperationV1,"PrAnalysisCoverageV1":DEFINITIONS.PrAnalysisCoverageV1,"PrContextCompleteV1":DEFINITIONS.PrContextCompleteV1,"PrContextGraphPendingV1":DEFINITIONS.PrContextGraphPendingV1,"PrContextSymbolsUnavailableV1":DEFINITIONS.PrContextSymbolsUnavailableV1,"PrCoverageSelectionV1":DEFINITIONS.PrCoverageSelectionV1,"PrSelectionCoverageV1":DEFINITIONS.PrSelectionCoverageV1,"PrSymbolChangesCompleteV1":DEFINITIONS.PrSymbolChangesCompleteV1,"PrSymbolEntryV1":DEFINITIONS.PrSymbolEntryV1,"PrSymbolPageV1":DEFINITIONS.PrSymbolPageV1,"PrSymbolSelectionV1":DEFINITIONS.PrSymbolSelectionV1,"PrimitiveUnavailableEvidenceV1":DEFINITIONS.PrimitiveUnavailableEvidenceV1,"PrimitiveUnavailableStatusV1":DEFINITIONS.PrimitiveUnavailableStatusV1,"SymbolChangesUnavailableV1":DEFINITIONS.SymbolChangesUnavailableV1},"$schema":"https://json-schema.org/draft/2020-12/schema","anyOf":[{"$ref":"#/$defs/PrContextCompleteV1"},{"$ref":"#/$defs/PrContextSymbolsUnavailableV1"},{"$ref":"#/$defs/PrContextGraphPendingV1"},{"$ref":"#/$defs/GitToolFailureV1"}],"title":"PrContextResultV1"}, {"$defs":{"BranchStackEdgeV1":DEFINITIONS.BranchStackEdgeV1,"BranchStackId":DEFINITIONS.BranchStackId,"BranchStackNodeV1":DEFINITIONS.BranchStackNodeV1,"BranchStackRevisionId":DEFINITIONS.BranchStackRevisionId,"BranchStackRevisionV1":DEFINITIONS.BranchStackRevisionV1,"BranchStackSourceV1":DEFINITIONS.BranchStackSourceV1,"CommitId":DEFINITIONS.CommitId,"ManifestDigest":DEFINITIONS.ManifestDigest,"MechanicalIntegrationModeV1":DEFINITIONS.MechanicalIntegrationModeV1,"NativeIntegrationDirectionV1":DEFINITIONS.NativeIntegrationDirectionV1,"NativeIntegrationSealedStackSnapshotV1":DEFINITIONS.NativeIntegrationSealedStackSnapshotV1,"NativeIntegrationSelectionBindingV1":DEFINITIONS.NativeIntegrationSelectionBindingV1,"ProjectId":DEFINITIONS.ProjectId,"RefId":DEFINITIONS.RefId,"RepositoryId":DEFINITIONS.RepositoryId,"ResolvedScope":DEFINITIONS.ResolvedScope,"ScopeSetId":DEFINITIONS.ScopeSetId,"ScopeSetRevision":DEFINITIONS.ScopeSetRevision,"StackNodeId":DEFINITIONS.StackNodeId,"WorktreeId":DEFINITIONS.WorktreeId,"WorktreeInventoryEpoch":DEFINITIONS.WorktreeInventoryEpoch,"WorktreeInventorySnapshotId":DEFINITIONS.WorktreeInventorySnapshotId},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"description":"Read-only preflight over one frozen snapshot identity.\n\n`preferred_mode` selects only one of the three fixed mechanical encodings.\nIt cannot change topology, commit order, or the commit set.","properties":{"preferred_mode":{"anyOf":[{"$ref":"#/$defs/MechanicalIntegrationModeV1"},{"type":"null"}],"default":null},"snapshot":{"$ref":"#/$defs/NativeIntegrationSealedStackSnapshotV1"}},"required":["snapshot"],"title":"NativeIntegrationPreflightSurfaceRequest","type":"object"}, + {"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"path":{"description":"Project path or registered alias to resolve.","type":["string","null"]},"project_selector":{"additionalProperties":false,"default":null,"description":"Registered project id to inspect. Omit to use path or the active\nproject.","properties":{"project_id":{"description":"Registered project id to query.","type":"string"}},"required":["project_id"],"type":"object"}},"title":"ProjectContextSurfaceRequestV1","type":"object"}, + {"$defs":{"PublicCodeProject":DEFINITIONS.PublicCodeProject},"$schema":"https://json-schema.org/draft/2020-12/schema","description":"One registered project's context, or the registry's typed miss.","oneOf":[{"additionalProperties":false,"properties":{"aliases":{"description":"Alias rows exactly as the registry serializes them.","items":true,"type":"array"},"is_active":{"type":"boolean"},"project":{"$ref":"#/$defs/PublicCodeProject"},"registry_path":{"type":"string"},"status":{"const":"ok","type":"string"},"stores":{"description":"Store rows exactly as the registry serializes them.","items":true,"type":"array"}},"required":["status","is_active","registry_path","project","aliases","stores"],"type":"object"},{"additionalProperties":false,"description":"The registry answered and no registered project matches the selector.","properties":{"aliases":{"items":true,"type":"array"},"project":{"type":"null"},"registry_path":{"type":"string"},"status":{"const":"not_found","type":"string"},"stores":{"items":true,"type":"array"}},"required":["status","registry_path","project","aliases","stores"],"type":"object"}],"title":"ProjectContextResultV1"}, + {"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"limit":{"description":"Maximum projects to return (default: 25, max: 100).","format":"uint","minimum":0,"type":["integer","null"]}},"title":"ProjectListSurfaceRequestV1","type":"object"}, + {"$defs":{"ProjectRegistryEntry":DEFINITIONS.ProjectRegistryEntry,"ProjectRegistrySummary":DEFINITIONS.ProjectRegistrySummary,"ProjectRepoGroup":DEFINITIONS.ProjectRepoGroup,"PublicCodeProject":DEFINITIONS.PublicCodeProject},"$schema":"https://json-schema.org/draft/2020-12/schema","description":"A bounded page of the profile's registered projects.","oneOf":[{"additionalProperties":false,"properties":{"limit":{"format":"uint","minimum":0,"type":"integer"},"project_tree":{"items":{"$ref":"#/$defs/ProjectRepoGroup"},"type":"array"},"projects":{"items":{"$ref":"#/$defs/PublicCodeProject"},"type":"array"},"query":{"type":["string","null"]},"registry_path":{"type":"string"},"status":{"const":"ok","type":"string"},"summary":{"$ref":"#/$defs/ProjectRegistrySummary"},"title":{"type":"string"},"truncated":{"type":"boolean"}},"required":["status","title","registry_path","limit","truncated","summary","project_tree","projects"],"type":"object"}],"title":"ProjectRegistryListingResultV1"}, + {"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"limit":{"description":"Maximum projects to return (default: 10, max: 50).","format":"uint","minimum":0,"type":["integer","null"]},"query":{"description":"Case-insensitive substring query over registry project metadata.","type":"string"}},"required":["query"],"title":"ProjectSearchSurfaceRequestV1","type":"object"}, {"$defs":{"PageRequest":DEFINITIONS.PageRequest},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"page":{"$ref":"#/$defs/PageRequest"},"qualified_name":{"type":"string"}},"required":["qualified_name","page"],"title":"QualifiedNamePrimitiveRequest","type":"object"}, {"$defs":{"SymbolPrimitiveRecord":DEFINITIONS.SymbolPrimitiveRecord},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"next_cursor":{"description":"Opaque resume token; its bounded string is the public wire form.","type":["string","null"]},"symbols":{"items":{"$ref":"#/$defs/SymbolPrimitiveRecord"},"type":"array"},"total":{"format":"uint64","minimum":0,"type":["integer","null"]}},"required":["symbols"],"title":"QualifiedNamePrimitiveResult","type":"object"}, {"$defs":{"RankDirectionV1":DEFINITIONS.RankDirectionV1,"RankEdgeKindV1":DEFINITIONS.RankEdgeKindV1},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"direction":{"anyOf":[{"$ref":"#/$defs/RankDirectionV1"},{"type":"null"}],"description":"Edge direction: 'incoming' ranks targets (default, e.g.\nmost-implemented interface), 'outgoing' ranks sources (e.g. class that\nimplements the most interfaces)."},"edge_kind":{"$ref":"#/$defs/RankEdgeKindV1","description":"The relationship type to rank by (e.g. 'implements' to find\nmost-implemented interfaces)."},"limit":{"description":"Maximum number of results to return (default: 10, at most 100).","format":"uint32","minimum":0,"type":["integer","null"]},"node_kind":{"description":"Optional filter for node kind (e.g. 'interface', 'class', 'trait',\n'function', 'method').","type":["string","null"]},"path":{"description":"Filter to files under this directory path (e.g. 'src/main/java').","type":["string","null"]}},"required":["edge_kind"],"title":"RankSurfaceRequestV1","type":"object"}, @@ -3032,6 +3205,8 @@ const SCHEMAS: readonly CanonicalJsonSchema[] = [ {"$defs":{"RecursionCycleV1":DEFINITIONS.RecursionCycleV1,"RecursionSymbolV1":DEFINITIONS.RecursionSymbolV1},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"cycle_count":{"format":"uint64","minimum":0,"type":"integer"},"cycles":{"items":{"$ref":"#/$defs/RecursionCycleV1"},"type":"array"}},"required":["cycle_count","cycles"],"title":"RecursionResultV1","type":"object"}, {"$defs":{"CommitId":DEFINITIONS.CommitId,"ProjectId":DEFINITIONS.ProjectId,"ProviderId":DEFINITIONS.ProviderId,"RedundancyScopeV1":DEFINITIONS.RedundancyScopeV1,"RepositoryId":DEFINITIONS.RepositoryId,"SimilarMatchClassV1":DEFINITIONS.SimilarMatchClassV1},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"cursor":{"type":["string","null"]},"family_limit":{"description":"Preferred family page size.","format":"uint32","minimum":0,"type":"integer"},"include_generated_paths":{"type":"boolean"},"match_classes":{"items":{"$ref":"#/$defs/SimilarMatchClassV1"},"type":"array"},"member_limit":{"format":"uint32","minimum":0,"type":"integer"},"project_id":{"$ref":"#/$defs/ProjectId"},"repository_id":{"$ref":"#/$defs/RepositoryId"},"scope":{"$ref":"#/$defs/RedundancyScopeV1"},"work_limit":{"format":"uint32","minimum":0,"type":"integer"}},"required":["project_id","repository_id","match_classes","scope","include_generated_paths","family_limit","member_limit","work_limit"],"title":"RedundancySurfaceRequestV1","type":"object"}, {"$defs":{"CodeGenerationId":DEFINITIONS.CodeGenerationId,"ManifestDigest":DEFINITIONS.ManifestDigest,"ProjectId":DEFINITIONS.ProjectId,"RedundancyCoverageV1":DEFINITIONS.RedundancyCoverageV1,"RedundancyFamilyV1":DEFINITIONS.RedundancyFamilyV1,"RedundancyPartialReasonV1":DEFINITIONS.RedundancyPartialReasonV1,"RedundancyRankingV1":DEFINITIONS.RedundancyRankingV1,"RepositoryId":DEFINITIONS.RepositoryId,"SimilarFamilyV1":DEFINITIONS.SimilarFamilyV1,"SimilarMatchClassV1":DEFINITIONS.SimilarMatchClassV1,"SimilarOccurrenceV1":DEFINITIONS.SimilarOccurrenceV1,"SourceSpan":DEFINITIONS.SourceSpan,"SymbolOccurrenceId":DEFINITIONS.SymbolOccurrenceId,"WorktreeId":DEFINITIONS.WorktreeId},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"coverage":{"$ref":"#/$defs/RedundancyCoverageV1"},"families":{"items":{"$ref":"#/$defs/RedundancyFamilyV1"},"type":"array"},"next_cursor":{"type":["string","null"]},"ranked_by":{"$ref":"#/$defs/RedundancyRankingV1"},"source_generation":{"$ref":"#/$defs/CodeGenerationId"}},"required":["source_generation","ranked_by","families","coverage"],"title":"RedundancyResultV1","type":"object"}, + {"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"title":"RemoteStatusSurfaceRequestV1","type":"object"}, + {"$defs":{"AuthorityEpoch":DEFINITIONS.AuthorityEpoch,"BrainId":DEFINITIONS.BrainId,"BrainNodeId":DEFINITIONS.BrainNodeId,"CurrentRemoteAuthorityStateV1":DEFINITIONS.CurrentRemoteAuthorityStateV1,"CurrentRemoteAuthorityV1":DEFINITIONS.CurrentRemoteAuthorityV1,"DoctorCoverageCompletenessV1":DEFINITIONS.DoctorCoverageCompletenessV1,"ProjectionGenerationId":DEFINITIONS.ProjectionGenerationId,"RemoteAuthorityUnavailableReasonV1":DEFINITIONS.RemoteAuthorityUnavailableReasonV1,"RemoteListenerReadV1":DEFINITIONS.RemoteListenerReadV1,"RemoteOperationalReadinessV1":DEFINITIONS.RemoteOperationalReadinessV1,"RemoteOperationalStatusV1":DEFINITIONS.RemoteOperationalStatusV1,"RemoteSpoolOperationalStatusV1":DEFINITIONS.RemoteSpoolOperationalStatusV1,"RemoteWriterFenceV1":DEFINITIONS.RemoteWriterFenceV1,"ShardId":DEFINITIONS.ShardId,"UtcMicros":DEFINITIONS.UtcMicros},"$schema":"https://json-schema.org/draft/2020-12/schema","description":"Typed read of the Remote Brain operational plane as observed from the\nmounted daemon authorities. Every operator surface (Doctor, CLI, MCP,\ndashboard) reads this one shape; `Unavailable` is reserved for a genuinely\nunmounted or unreadable authority, never a rendering shortcut.","oneOf":[{"properties":{"coverage":{"$ref":"#/$defs/DoctorCoverageCompletenessV1"},"kind":{"const":"observed","type":"string"},"listener":{"$ref":"#/$defs/RemoteListenerReadV1"},"status":{"$ref":"#/$defs/RemoteOperationalStatusV1"}},"required":["kind","listener","status","coverage"],"type":"object"},{"properties":{"kind":{"const":"unconfigured","type":"string"}},"required":["kind"],"type":"object"},{"properties":{"kind":{"const":"unavailable","type":"string"}},"required":["kind"],"type":"object"}],"title":"RemoteOperationalStatusReadV1"}, {"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"new_name":{"type":["string","null"]},"node_id":{"type":"string"}},"required":["node_id"],"title":"RenamePreviewPrimitiveRequestV1","type":"object"}, {"$defs":{"PrimitiveNotFoundV1":DEFINITIONS.PrimitiveNotFoundV1,"RenamePreviewNodeV1":DEFINITIONS.RenamePreviewNodeV1,"RenamePreviewPrimitiveResultV1":DEFINITIONS.RenamePreviewPrimitiveResultV1,"RenamePreviewReferenceV1":DEFINITIONS.RenamePreviewReferenceV1,"RenamePreviewTextOnlyMatchV1":DEFINITIONS.RenamePreviewTextOnlyMatchV1},"$schema":"https://json-schema.org/draft/2020-12/schema","anyOf":[{"$ref":"#/$defs/RenamePreviewPrimitiveResultV1"},{"$ref":"#/$defs/PrimitiveNotFoundV1"}],"title":"RenamePreviewPrimitiveOutcomeV1"}, {"$defs":{"ManifestDigest":DEFINITIONS.ManifestDigest,"RenamePreviewAcceptanceV1":DEFINITIONS.RenamePreviewAcceptanceV1},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"description":"Exact public input accepted by `tracedecay_rename_symbol`.\n\nThe five identity fields consume the preview's exact symbol identity; the\nflattened control consumes its exact candidate-state digest.","properties":{"accepted_preview":{"anyOf":[{"$ref":"#/$defs/RenamePreviewAcceptanceV1"},{"type":"null"}],"description":"Exact output identity from the accepted dry-run preview. Required when\n`dry_run=false` and omitted when computing a preview."},"dry_run":{"default":true,"type":"boolean"},"expected_state":{"description":"Exact `preview_digest`/`expected_state` returned by the dry run. Apply\nre-resolves the typed plan and rejects any candidate-state drift.","type":["string","null"]},"file":{"type":"string"},"idempotency_key":{"type":["string","null"]},"kind":{"type":"string"},"new_name":{"type":"string"},"node_id":{"description":"Canonical `SymbolOccurrenceId` returned by `tracedecay_rename_preview`.","type":"string"},"old_name":{"type":"string"},"qualified_name":{"type":"string"},"verify":{"default":true,"type":"boolean"}},"required":["node_id","qualified_name","kind","file","old_name","new_name"],"title":"RenameSymbolSurfaceRequestV1","type":"object"}, @@ -3040,6 +3215,8 @@ const SCHEMAS: readonly CanonicalJsonSchema[] = [ {"$defs":{"RetrieveHandleExpiredV1":DEFINITIONS.RetrieveHandleExpiredV1,"RetrieveHandleMissingV1":DEFINITIONS.RetrieveHandleMissingV1,"RetrievedPageV1":DEFINITIONS.RetrievedPageV1},"$schema":"https://json-schema.org/draft/2020-12/schema","anyOf":[{"$ref":"#/$defs/RetrievedPageV1"},{"$ref":"#/$defs/RetrieveHandleMissingV1"},{"$ref":"#/$defs/RetrieveHandleExpiredV1"}],"description":"What a retrieve found under the handle.","title":"RetrieveResultV1"}, {"$defs":{"TestProfileV1":DEFINITIONS.TestProfileV1},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"changed_paths":{"description":"Explicit manifest of project-relative file paths used to compute\naffected tests.","items":{"type":"string"},"type":"array"},"max_tests":{"description":"Cap on tests dispatched in a single invocation, 1 through 500\n(default: 100).","format":"uint64","maximum":500,"minimum":1,"type":["integer","null"]},"profile":{"anyOf":[{"$ref":"#/$defs/TestProfileV1"},{"type":"null"}],"description":"Cargo profile (default: debug)."},"timeout_secs":{"description":"Maximum wall time in seconds before the cargo subprocess is killed,\n1 through 300 (default: 300).","format":"uint64","maximum":300,"minimum":1,"type":["integer","null"]}},"required":["changed_paths"],"title":"RunAffectedTestsSurfaceRequestV1","type":"object"}, {"$defs":{"AffectedTestErrorV1":DEFINITIONS.AffectedTestErrorV1,"AffectedTestOutcomeV1":DEFINITIONS.AffectedTestOutcomeV1,"AffectedTestRunV1":DEFINITIONS.AffectedTestRunV1,"AffectedTestsNotRunV1":DEFINITIONS.AffectedTestsNotRunV1,"CancellationObservation":DEFINITIONS.CancellationObservation,"CancellationStage":DEFINITIONS.CancellationStage,"Deadline":DEFINITIONS.Deadline,"ManagedTestTerminalV1":DEFINITIONS.ManagedTestTerminalV1,"OperationBudgetUsage":DEFINITIONS.OperationBudgetUsage,"OperationReceipt":DEFINITIONS.OperationReceipt_2,"OperationTermination":DEFINITIONS.OperationTermination_2,"UtcMicros":DEFINITIONS.UtcMicros},"$schema":"https://json-schema.org/draft/2020-12/schema","anyOf":[{"$ref":"#/$defs/AffectedTestRunV1"},{"$ref":"#/$defs/AffectedTestsNotRunV1"}],"title":"RunAffectedTestsResultV1"}, + {"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"authority_audit":{"default":false,"description":"Run the exhaustive observation-authority audit and include\nauthority_audit_ok (true = audit ran and passed, false = audit ran and\nfailed, null = audit did not run), authority_audit_reason (typed:\nauthority_invariant_failed, authority_store_unavailable,\nauthority_store_missing, authority_audit_not_run), and\nauthority_audit_error (observed detail) in database telemetry. Also\nincludes session-temporal health. Default false.","type":"boolean"},"doctor_report":{"default":false,"description":"Include the daemon-owned canonical Doctor report and typed per-table\ngrowth evidence. Default false.","type":"boolean"},"session_ingest_health":{"default":false,"description":"Include Cursor transcript-ingest health from the daemon-retained\nproject session authority. Default false.","type":"boolean"},"session_temporal_health":{"default":false,"description":"Include session-temporal health without the authority audit. Default\nfalse.","type":"boolean"},"startup_health":{"default":false,"description":"Ask a connection's first request for only the daemon-mounted database\nintegrity telemetry, for post-update startup validation; the daemon\ncore answers that probe before a project owner exists, and a project\nowner's snapshot already carries the same telemetry. Default false.","type":"boolean"}},"title":"RuntimeSurfaceRequestV1","type":"object"}, + {"$defs":{"DoctorCoverageCompletenessV1":DEFINITIONS.DoctorCoverageCompletenessV1,"DoctorCoverageStatementV1":DEFINITIONS.DoctorCoverageStatementV1,"DoctorEvidenceRefV1":DEFINITIONS.DoctorEvidenceRefV1,"DoctorEvidenceReferenceV1":DEFINITIONS.DoctorEvidenceReferenceV1,"DoctorEvidenceStateV1":DEFINITIONS.DoctorEvidenceStateV1,"DoctorFamilyConsultationV1":DEFINITIONS.DoctorFamilyConsultationV1,"DoctorFamilyCoverageV1":DEFINITIONS.DoctorFamilyCoverageV1,"DoctorFamilyUnavailableReasonV1":DEFINITIONS.DoctorFamilyUnavailableReasonV1,"DoctorFindingFamilyV1":DEFINITIONS.DoctorFindingFamilyV1,"DoctorFindingV1":DEFINITIONS.DoctorFindingV1,"DoctorReportCoverageV1":DEFINITIONS.DoctorReportCoverageV1,"DoctorReportEntryV1":DEFINITIONS.DoctorReportEntryV1,"DoctorReportV1":DEFINITIONS.DoctorReportV1,"DoctorStorageFindingKindV1":DEFINITIONS.DoctorStorageFindingKindV1,"LanguageServerAnalyzerStateV1":DEFINITIONS.LanguageServerAnalyzerStateV1,"LanguageServerAnalyzerV1":DEFINITIONS.LanguageServerAnalyzerV1,"LanguageServerReadV1":DEFINITIONS.LanguageServerReadV1,"LanguageServerStateV1":DEFINITIONS.LanguageServerStateV1,"RuntimeDoctorReportV1":DEFINITIONS.RuntimeDoctorReportV1,"SchemaConvergenceFindingV1":DEFINITIONS.SchemaConvergenceFindingV1,"SchemaConvergenceProgressV1":DEFINITIONS.SchemaConvergenceProgressV1,"SchemaConvergenceStageV1":DEFINITIONS.SchemaConvergenceStageV1,"SchemaConvergenceStateV1":DEFINITIONS.SchemaConvergenceStateV1,"StorageByteSizeV1":DEFINITIONS.StorageByteSizeV1,"StoreKeyV1":DEFINITIONS.StoreKeyV1,"TableGrowthDoctorEvidenceV1":DEFINITIONS.TableGrowthDoctorEvidenceV1,"TableNameV1":DEFINITIONS.TableNameV1,"UtcMicros":DEFINITIONS.UtcMicros},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"description":"Process, database, and session-observation telemetry for the running\ndaemon, with the sections the request opted into.","properties":{"captured_at":{"description":"Unix epoch seconds.","format":"uint64","minimum":0,"type":"integer"},"cursor_session_ingest":true,"cursor_session_placeholder_paths":{"items":{"type":"string"},"type":["array","null"]},"database":{"description":"Store telemetry, with the authority-audit verdict when it ran."},"doctor_report":{"anyOf":[{"$ref":"#/$defs/RuntimeDoctorReportV1"},{"type":"null"}]},"host_os":{"type":"string"},"process":{"description":"Cached process sample."},"session_temporal_health":true,"tracedecay_version":{"type":"string"}},"required":["captured_at","tracedecay_version","host_os","process","database"],"title":"RuntimeResultV1","type":"object"}, {"$defs":{"SearchLexicalAliasV1":DEFINITIONS.SearchLexicalAliasV1,"SearchLexicalFieldFilterV1":DEFINITIONS.SearchLexicalFieldFilterV1,"SearchLexicalFieldV1":DEFINITIONS.SearchLexicalFieldV1,"SearchLexicalProximityV1":DEFINITIONS.SearchLexicalProximityV1},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"cursor":{"description":"Authenticated opaque continuation returned as next_cursor. Repeat the same query and lexical options with it.","type":["string","null"]},"lazy_index_ignored_dependencies":{"description":"Opt in to bounded indexing of ignored dependency entry files when an import hint matches (default: false).","type":["boolean","null"]},"lexical_aliases":{"description":"Named query-time vocabulary aliases. The strict query always ranks first. Alias-only hits follow it with the strict query, alternative, and configured-vocabulary reason disclosed.","items":{"$ref":"#/$defs/SearchLexicalAliasV1"},"maxItems":8,"type":["array","null"]},"lexical_anchors":{"description":"Exact identifiers or technical terms (e.g. 'reserve_stock', 'Foo::bar', 'E0308') that the answer must be about. Each is ranked through the lexical lane as its own route: a hit carrying an anchor outranks every hit that carries none, exact hits included, every anchor with matches keeps at least its best sites through the lane cap, and `lexical_anchors` in the response reports each anchor's outcome (`matched` rows, `admitted` sites this response returns, `dropped` admitted sites it could not carry with the reason, `unmatched`, or `not_served`). Ranked retrieval, not exhaustive grep (use tracedecay_grep for that). Each result names the routes that ranked it. At most 8 anchors, each one whitespace-free term of at most 128 bytes, no repeats.","items":{"type":"string"},"maxItems":8,"type":["array","null"]},"lexical_field_filters":{"description":"Include or exclude lexical symbol_name, qualified_name, path, signature, documentation, body_text, preamble_text, exact_term, or subtoken fields.","items":{"$ref":"#/$defs/SearchLexicalFieldFilterV1"},"maxItems":9,"type":["array","null"]},"lexical_phrases":{"description":"Exact lexical phrases to rank through n-gram candidate pruning.","items":{"type":"string"},"maxItems":4,"type":["array","null"]},"lexical_proximities":{"description":"Ordered lexical terms that must occur within the bounded intervening-token gap.","items":{"$ref":"#/$defs/SearchLexicalProximityV1"},"maxItems":4,"type":["array","null"]},"limit":{"description":"Maximum number of results to return (default: 10)","format":"uint64","minimum":0,"type":["integer","null"]},"prefer_symbol":{"description":"Add a lexical route restricted to symbol-name matches for the identifier-shaped words of the query (default: false). Query words such as class/struct/function/find/explain are ignored; 'Foo::bar' and 'Foo.bar' contribute 'bar'.","type":["boolean","null"]},"query":{"description":"Search query string to match against symbol names","type":"string"}},"required":["query"],"title":"SearchSurfaceRequestV1","type":"object"}, {"$defs":{"ApplicationProblemDetailV1":DEFINITIONS.ApplicationProblemDetailV1_2,"CalibrationProfileId":DEFINITIONS.CalibrationProfileId,"CandidateContribution":DEFINITIONS.CandidateContribution,"CodeIndexBuildBlockedReasonV1":DEFINITIONS.CodeIndexBuildBlockedReasonV1,"CodeIndexConvergenceParkedV1":DEFINITIONS.CodeIndexConvergenceParkedV1,"CodeIndexStalenessStateV1":DEFINITIONS.CodeIndexStalenessStateV1,"ComponentRevision":DEFINITIONS.ComponentRevision,"ContextLexicalAnchorV1":DEFINITIONS.ContextLexicalAnchorV1,"DiagnosticsSearchedTsconfigV1":DEFINITIONS.DiagnosticsSearchedTsconfigV1,"EvidenceRole":DEFINITIONS.EvidenceRole,"ExactClass":DEFINITIONS.ExactClass,"FileOccurrenceId":DEFINITIONS.FileOccurrenceId,"FixedPointScore":DEFINITIONS.FixedPointScore,"FreshnessCompatibilityV1":DEFINITIONS.FreshnessCompatibilityV1,"FusedCandidate":DEFINITIONS.FusedCandidate,"LexicalAnchorDropReasonV1":DEFINITIONS.LexicalAnchorDropReasonV1,"LexicalAnchorDropV1":DEFINITIONS.LexicalAnchorDropV1,"LogicalCopyClusterId":DEFINITIONS.LogicalCopyClusterId,"LogicalEvidenceId":DEFINITIONS.LogicalEvidenceId,"OccurrenceProvenance":DEFINITIONS.OccurrenceProvenance,"PrimitiveFreshnessStateV1":DEFINITIONS.PrimitiveFreshnessStateV1,"PrimitiveIndexingStateV1":DEFINITIONS.PrimitiveIndexingStateV1,"PrimitiveLaneCompleteV1":DEFINITIONS.PrimitiveLaneCompleteV1,"PrimitiveRecallV1":DEFINITIONS.PrimitiveRecallV1,"PrimitiveSearchFreshnessV1":DEFINITIONS.PrimitiveSearchFreshnessV1,"PrimitiveUnavailableEvidenceV1":DEFINITIONS.PrimitiveUnavailableEvidenceV1,"PrimitiveUnavailableStatusV1":DEFINITIONS.PrimitiveUnavailableStatusV1,"RankingDecision":DEFINITIONS.RankingDecision,"RankingDecisionKind":DEFINITIONS.RankingDecisionKind,"RepositoryId":DEFINITIONS.RepositoryId,"RetrievalAnchorId":DEFINITIONS.RetrievalAnchorId,"RetrieverKind":DEFINITIONS.RetrieverKind,"ScoreDomainId":DEFINITIONS.ScoreDomainId,"SearchCompleteV1":DEFINITIONS.SearchCompleteV1,"SearchCoverageV1":DEFINITIONS.SearchCoverageV1,"SearchExternalImportCandidatesV1":DEFINITIONS.SearchExternalImportCandidatesV1,"SearchExternalImportHintV1":DEFINITIONS.SearchExternalImportHintV1,"SearchExternalImportV1":DEFINITIONS.SearchExternalImportV1,"SearchLaneStateV1":DEFINITIONS.SearchLaneStateV1,"SearchLaneStatusV1":DEFINITIONS.SearchLaneStatusV1,"SearchLexicalAlternativeReasonV1":DEFINITIONS.SearchLexicalAlternativeReasonV1,"SearchLexicalRouteV1":DEFINITIONS.SearchLexicalRouteV1,"SearchResultDisplayV1":DEFINITIONS.SearchResultDisplayV1,"SearchResultRowV1":DEFINITIONS.SearchResultRowV1,"SearchRouteMatchV1":DEFINITIONS.SearchRouteMatchV1,"SearchSpellingVariantV1":DEFINITIONS.SearchSpellingVariantV1,"SearchUnavailableV1":DEFINITIONS.SearchUnavailableV1,"SessionOrThreadId":DEFINITIONS.SessionOrThreadId,"SourceFreshness":DEFINITIONS.SourceFreshness,"SourceInstanceKey":DEFINITIONS.SourceInstanceKey,"SourceNamespace":DEFINITIONS.SourceNamespace,"SourceOccurrenceId":DEFINITIONS.SourceOccurrenceId,"UtcMicros":DEFINITIONS.UtcMicros},"$schema":"https://json-schema.org/draft/2020-12/schema","anyOf":[{"$ref":"#/$defs/SearchCompleteV1"},{"$ref":"#/$defs/SearchUnavailableV1"}],"description":"What a search served: a ranked page, or the typed reason no generation\ncould answer.","title":"SearchResultV1"}, {"$defs":{"PageRequest":DEFINITIONS.PageRequest,"ResultProjection":DEFINITIONS.ResultProjection,"RetrievalOrder":DEFINITIONS.RetrievalOrder,"RetrievalRequestMeta":DEFINITIONS.RetrievalRequestMeta,"SessionId":DEFINITIONS.SessionId,"TemporalModeV1":DEFINITIONS.TemporalModeV1,"UtcMicros":DEFINITIONS.UtcMicros},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"meta":{"$ref":"#/$defs/RetrievalRequestMeta"},"session_id":{"$ref":"#/$defs/SessionId"}},"required":["session_id","meta"],"title":"SessionLookupRequest","type":"object"}, @@ -3066,6 +3243,8 @@ const SCHEMAS: readonly CanonicalJsonSchema[] = [ {"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"file":{"type":"string"}},"required":["file"],"title":"SourceOutlinePrimitiveRequest","type":"object"}, {"$defs":{"SymbolPrimitiveRecord":DEFINITIONS.SymbolPrimitiveRecord},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"file":{"type":"string"},"symbols":{"items":{"$ref":"#/$defs/SymbolPrimitiveRecord"},"type":"array"}},"required":["file","symbols"],"title":"SourceOutlinePrimitiveResult","type":"object"}, {"$defs":{"BranchStackEdgeV1":DEFINITIONS.BranchStackEdgeV1,"BranchStackId":DEFINITIONS.BranchStackId,"BranchStackNodeV1":DEFINITIONS.BranchStackNodeV1,"BranchStackRevisionId":DEFINITIONS.BranchStackRevisionId,"CommitId":DEFINITIONS.CommitId,"ManifestDigest":DEFINITIONS.ManifestDigest,"NativeIntegrationDirectionV1":DEFINITIONS.NativeIntegrationDirectionV1,"NativeIntegrationSelectionDeclarationV1":DEFINITIONS.NativeIntegrationSelectionDeclarationV1,"ProjectId":DEFINITIONS.ProjectId,"RefId":DEFINITIONS.RefId,"RepositoryId":DEFINITIONS.RepositoryId,"ResolvedScope":DEFINITIONS.ResolvedScope,"ScopeSetId":DEFINITIONS.ScopeSetId,"ScopeSetRevision":DEFINITIONS.ScopeSetRevision,"StackNodeId":DEFINITIONS.StackNodeId,"WorktreeId":DEFINITIONS.WorktreeId,"WorktreeInventoryEpoch":DEFINITIONS.WorktreeInventoryEpoch,"WorktreeInventorySnapshotId":DEFINITIONS.WorktreeInventorySnapshotId},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"description":"Exact caller-supplied identity frozen by `stack_snapshot`.\n\nThis proof binds the exact authorized `ProjectId`, `RepositoryId`, source\nand destination worktree/ref identity, frozen inventory, scope/grant/policy\nrevisions, and one declared-edge or independent-branch selection. Paths,\nfree-form SHA values, branch display names, and provider topology remain\nunrepresentable.","properties":{"authorized_scope_set_digest":{"$ref":"#/$defs/ManifestDigest"},"authorized_scope_set_id":{"$ref":"#/$defs/ScopeSetId"},"authorized_scope_set_revision":{"$ref":"#/$defs/ScopeSetRevision"},"destination":{"$ref":"#/$defs/ResolvedScope"},"grant_digest":{"$ref":"#/$defs/ManifestDigest"},"inventory_epoch":{"$ref":"#/$defs/WorktreeInventoryEpoch"},"inventory_snapshot_id":{"$ref":"#/$defs/WorktreeInventorySnapshotId"},"policy_digest":{"$ref":"#/$defs/ManifestDigest"},"selection":{"$ref":"#/$defs/NativeIntegrationSelectionDeclarationV1"},"source":{"$ref":"#/$defs/ResolvedScope"}},"required":["source","destination","authorized_scope_set_id","authorized_scope_set_revision","authorized_scope_set_digest","inventory_snapshot_id","inventory_epoch","selection","grant_digest","policy_digest"],"title":"NativeIntegrationStackSnapshotSurfaceRequest","type":"object"}, + {"$defs":{"CodeIndexReadinessTargetV1":DEFINITIONS.CodeIndexReadinessTargetV1,"CodeIndexReadinessWaitV1":DEFINITIONS.CodeIndexReadinessWaitV1},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"admission_only":{"default":false,"description":"Report only that the project route is admitted, reading no graph,\nindex, or session state. Default false.","type":"boolean"},"include_branch_diagnostics":{"default":false,"description":"Full tracked-branch diagnostic list. Default false.","type":"boolean"},"include_session_ingest":{"default":false,"description":"Session-ingest health. Default false.","type":"boolean"},"include_staleness":{"default":false,"description":"Git staleness object. Default false.","type":"boolean"},"include_storage_health":{"default":false,"description":"Storage-health snapshot. Default false.","type":"boolean"},"wait_for":{"anyOf":[{"$ref":"#/$defs/CodeIndexReadinessWaitV1"},{"type":"null"}],"description":"Hold the status read until the code index reaches `state` (`fresh`:\nstatus `current`; `ready`: also native graph serving; `graph_ready`: a\npublished generation's native graph serves, whatever the freshness),\nfor at most `timeout_ms`. The payload's `wait` reports `reached`,\n`timed_out` with `last_state`, or `unavailable` with `reason`."}},"title":"StatusSurfaceRequestV1","type":"object"}, + {"$defs":{"CodeCloneIndexBudgetsV1":DEFINITIONS.CodeCloneIndexBudgetsV1,"CodeCloneIndexCoverageV1":DEFINITIONS.CodeCloneIndexCoverageV1,"CodeCloneIndexObservationV1":DEFINITIONS.CodeCloneIndexObservationV1,"CodeCloneIndexResourcesV1":DEFINITIONS.CodeCloneIndexResourcesV1,"CodeCloneIndexStatusV1":DEFINITIONS.CodeCloneIndexStatusV1,"CodeGraphServingReadinessV1":DEFINITIONS.CodeGraphServingReadinessV1,"CodeIndexBuildBlockedReasonV1":DEFINITIONS.CodeIndexBuildBlockedReasonV1,"CodeIndexBuildPhaseV1":DEFINITIONS.CodeIndexBuildPhaseV1,"CodeIndexBuildProgressV1":DEFINITIONS.CodeIndexBuildProgressV1,"CodeIndexConvergenceParkedV1":DEFINITIONS.CodeIndexConvergenceParkedV1,"CodeIndexFreshnessCoverageV1":DEFINITIONS.CodeIndexFreshnessCoverageV1,"CodeIndexGenerationRecoveryServingV1":DEFINITIONS.CodeIndexGenerationRecoveryServingV1,"CodeIndexGenerationRecoveryV1":DEFINITIONS.CodeIndexGenerationRecoveryV1,"CodeIndexReadinessWaitOutcomeV1":DEFINITIONS.CodeIndexReadinessWaitOutcomeV1,"CodeIndexRestoreProgressV1":DEFINITIONS.CodeIndexRestoreProgressV1,"CodeIndexStalenessStateV1":DEFINITIONS.CodeIndexStalenessStateV1,"CodeIndexWorktreeFreshnessV1":DEFINITIONS.CodeIndexWorktreeFreshnessV1,"ProjectStatusV1":DEFINITIONS.ProjectStatusV1,"ResidentMemoryHolderReadV1":DEFINITIONS.ResidentMemoryHolderReadV1,"SchemaConvergenceFindingV1":DEFINITIONS.SchemaConvergenceFindingV1,"SchemaConvergenceProgressV1":DEFINITIONS.SchemaConvergenceProgressV1,"SchemaConvergenceStageV1":DEFINITIONS.SchemaConvergenceStageV1,"SchemaConvergenceStateV1":DEFINITIONS.SchemaConvergenceStateV1,"StatusAdmissionV1":DEFINITIONS.StatusAdmissionV1,"StatusBranchMismatchV1":DEFINITIONS.StatusBranchMismatchV1,"StatusCodeIndexFreshnessV1":DEFINITIONS.StatusCodeIndexFreshnessV1,"StatusGitStalenessV1":DEFINITIONS.StatusGitStalenessV1,"StatusMemoryOwnerV1":DEFINITIONS.StatusMemoryOwnerV1,"StatusMemoryPressureV1":DEFINITIONS.StatusMemoryPressureV1,"StatusMemoryV1":DEFINITIONS.StatusMemoryV1,"StatusRetrievalServingV1":DEFINITIONS.StatusRetrievalServingV1,"StatusSchemaConvergenceStateV1":DEFINITIONS.StatusSchemaConvergenceStateV1,"StatusSchemaConvergenceV1":DEFINITIONS.StatusSchemaConvergenceV1,"StatusServingConditionV1":DEFINITIONS.StatusServingConditionV1,"StatusServingFreshnessV1":DEFINITIONS.StatusServingFreshnessV1,"StoreResetRequiredV1":DEFINITIONS.StoreResetRequiredV1},"$schema":"https://json-schema.org/draft/2020-12/schema","anyOf":[{"$ref":"#/$defs/StatusAdmissionV1"},{"$ref":"#/$defs/ProjectStatusV1"}],"description":"`tracedecay_status` for an `admission_only` read, or the project's status.","title":"StatusResultV1"}, {"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"include_details":{"default":false,"type":"boolean"}},"title":"StorageStatusPrimitiveRequest","type":"object"}, {"$defs":{"StorageStatusHistoryPointV1":DEFINITIONS.StorageStatusHistoryPointV1},"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"database_bytes":{"format":"uint64","minimum":0,"type":["integer","null"]},"details":{"items":{"type":"string"},"type":"array"},"freelist_pages":{"default":null,"format":"uint64","minimum":0,"type":["integer","null"]},"history":{"default":[],"items":{"$ref":"#/$defs/StorageStatusHistoryPointV1"},"type":"array"},"history_coverage":{"default":null,"type":["string","null"]},"page_count":{"default":null,"format":"uint64","minimum":0,"type":["integer","null"]},"page_size_bytes":{"default":null,"format":"uint32","minimum":0,"type":["integer","null"]},"project_id":{"default":null,"type":["string","null"]},"read_only":{"type":"boolean"},"status":{"type":"string"},"store_path":{"default":null,"type":["string","null"]}},"required":["status","read_only","details"],"title":"StorageStatusPrimitiveResult","type":"object"}, {"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"description":"Exact public input accepted by `tracedecay_str_replace`.","properties":{"dry_run":{"default":false,"type":"boolean"},"expected_state":{"description":"Exact `preview_digest`/`expected_state` returned by the dry run. Apply\nre-resolves the typed plan and rejects any candidate-state drift.","type":["string","null"]},"idempotency_key":{"type":["string","null"]},"new_str":{"type":"string"},"old_str":{"type":"string"},"path":{"type":"string"},"verify":{"default":false,"type":"boolean"}},"required":["path","old_str","new_str"],"title":"StrReplaceSurfaceRequestV1","type":"object"}, @@ -3185,1062 +3364,1090 @@ const DECODERS = SCHEMAS.map((schema): Decoder => (value) => decodeCano function decoder(index: number): Decoder { const decode = DECODERS[index]; if (decode === undefined) throw new TypeError(`generated canonical schema ${index} is missing`); return decode as Decoder; } export const OPERATIONS = [ + { operation: "active_project", operationId: "operation.application.active_project", transport: { kind: "mcp_tool", toolName: "tracedecay_active_project" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.active_project.v1", + requestSchema: { schemaId: "schema.application.primitive.active-project.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.active-project.result", revision: 1 }, + cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], + decodeRequest: decoder(0), decodeResult: decoder(1) }, { operation: "affected", operationId: "operation.application.affected", transport: { kind: "mcp_tool", toolName: "tracedecay_affected" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.affected.v1", requestSchema: { schemaId: "schema.application.primitive.affected.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.affected.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(0), decodeResult: decoder(1) }, + decodeRequest: decoder(2), decodeResult: decoder(3) }, { operation: "application_affected_tests", operationId: "operation.application.affected_tests", transport: { kind: "http", route: "/application/tests/affected", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.affected_tests.v1", requestSchema: { schemaId: "schema.application.feedback.affected-tests.request", revision: 1 }, resultSchema: { schemaId: "schema.application.feedback.affected-tests.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(2), decodeResult: decoder(3), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.affected_tests.v1", "schema.application.feedback.affected-tests.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(3)) }, + decodeRequest: decoder(4), decodeResult: decoder(5), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.affected_tests.v1", "schema.application.feedback.affected-tests.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(5)) }, { operation: "analytics", operationId: "operation.application.analytics", transport: { kind: "mcp_tool", toolName: "tracedecay_analytics" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.analytics.v1", requestSchema: { schemaId: "schema.application.primitive.analytics.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.analytics.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(4), decodeResult: decoder(5) }, + decodeRequest: decoder(6), decodeResult: decoder(7) }, { operation: "apply_native_integration", operationId: "operation.application.apply_native_integration", transport: { kind: "mcp_tool", toolName: "tracedecay_apply_native_integration" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.apply_native_integration.v1", requestSchema: { schemaId: "schema.application.native-integration.apply.request", revision: 1 }, resultSchema: { schemaId: "schema.application.native-integration.apply.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(6), decodeResult: decoder(7) }, + decodeRequest: decoder(8), decodeResult: decoder(9) }, { operation: "approve_native_integration", operationId: "operation.application.approve_native_integration", transport: { kind: "mcp_tool", toolName: "tracedecay_approve_native_integration" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.approve_native_integration.v1", requestSchema: { schemaId: "schema.application.native-integration.approve.request", revision: 1 }, resultSchema: { schemaId: "schema.application.native-integration.approve.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(8), decodeResult: decoder(7) }, + decodeRequest: decoder(10), decodeResult: decoder(9) }, { operation: "ast_grep_rewrite", operationId: "operation.application.ast_grep_rewrite", transport: { kind: "mcp_tool", toolName: "tracedecay_ast_grep_rewrite" }, effect: "source_edit", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.ast_grep_rewrite.v1", requestSchema: { schemaId: "schema.application.source-edit.ast-grep-rewrite.request", revision: 1 }, resultSchema: { schemaId: "schema.application.source-edit.ast-grep-rewrite.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(9), decodeResult: decoder(10) }, + decodeRequest: decoder(11), decodeResult: decoder(12) }, { operation: "ast_grep_search", operationId: "operation.application.ast_grep_search", transport: { kind: "mcp_tool", toolName: "tracedecay_ast_grep_search" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.ast_grep_search.v1", requestSchema: { schemaId: "schema.application.primitive.ast-grep-search.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.ast-grep-search.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(11), decodeResult: decoder(12) }, + decodeRequest: decoder(13), decodeResult: decoder(14) }, { operation: "automation_run_artifact_view", operationId: "operation.application.automation_run_artifact_view", transport: { kind: "mcp_tool", toolName: "tracedecay_automation_run_artifact_view" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.automation_run_artifact_view.v1", requestSchema: { schemaId: "schema.application.primitive.automation-run-artifact-view.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.automation-run-artifact-view.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(13), decodeResult: decoder(14) }, + decodeRequest: decoder(15), decodeResult: decoder(16) }, { operation: "automation_run_list", operationId: "operation.application.automation_run_list", transport: { kind: "mcp_tool", toolName: "tracedecay_automation_run_list" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.automation_run_list.v1", requestSchema: { schemaId: "schema.application.primitive.automation-run-list.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.automation-run-list.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(15), decodeResult: decoder(16) }, + decodeRequest: decoder(17), decodeResult: decoder(18) }, { operation: "automation_run_view", operationId: "operation.application.automation_run_view", transport: { kind: "mcp_tool", toolName: "tracedecay_automation_run_view" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.automation_run_view.v1", requestSchema: { schemaId: "schema.application.primitive.automation-run-view.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.automation-run-view.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(17), decodeResult: decoder(18) }, + decodeRequest: decoder(19), decodeResult: decoder(20) }, { operation: "branch_diff", operationId: "operation.application.branch_diff", transport: { kind: "mcp_tool", toolName: "tracedecay_branch_diff" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.branch_diff.v1", requestSchema: { schemaId: "schema.application.primitive.branch-diff.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.branch-diff.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(19), decodeResult: decoder(20) }, + decodeRequest: decoder(21), decodeResult: decoder(22) }, { operation: "branch_list", operationId: "operation.application.branch_list", transport: { kind: "mcp_tool", toolName: "tracedecay_branch_list" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.branch_list.v1", requestSchema: { schemaId: "schema.application.primitive.branch-list.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.branch-list.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(21), decodeResult: decoder(22) }, + decodeRequest: decoder(23), decodeResult: decoder(24) }, { operation: "branch_search", operationId: "operation.application.branch_search", transport: { kind: "mcp_tool", toolName: "tracedecay_branch_search" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.branch_search.v1", requestSchema: { schemaId: "schema.application.primitive.branch-search.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.branch-search.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(23), decodeResult: decoder(24) }, + decodeRequest: decoder(25), decodeResult: decoder(26) }, { operation: "by_qualified_name", operationId: "operation.application.by_qualified_name", transport: { kind: "mcp_tool", toolName: "tracedecay_by_qualified_name" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.by_qualified_name.v1", requestSchema: { schemaId: "schema.application.primitive.by-qualified-name.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.by-qualified-name.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(25), decodeResult: decoder(26) }, + decodeRequest: decoder(27), decodeResult: decoder(28) }, { operation: "application_call_chain", operationId: "operation.application.call_chain", transport: { kind: "http", route: "/application/primitives/call_chain", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.call_chain.v1", requestSchema: { schemaId: "schema.application.primitive.call-chain.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.call-chain.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(27), decodeResult: decoder(28), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.call_chain.v1", "schema.application.primitive.call-chain.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(28)) }, + decodeRequest: decoder(29), decodeResult: decoder(30), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.call_chain.v1", "schema.application.primitive.call-chain.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(30)) }, { operation: "cancel_native_integration", operationId: "operation.application.cancel_native_integration", transport: { kind: "mcp_tool", toolName: "tracedecay_cancel_native_integration" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.cancel_native_integration.v1", requestSchema: { schemaId: "schema.application.native-integration.cancel.request", revision: 1 }, resultSchema: { schemaId: "schema.application.native-integration.cancel.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(29), decodeResult: decoder(7) }, + decodeRequest: decoder(31), decodeResult: decoder(9) }, { operation: "changelog", operationId: "operation.application.changelog", transport: { kind: "mcp_tool", toolName: "tracedecay_changelog" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.changelog.v1", requestSchema: { schemaId: "schema.application.primitive.changelog.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.changelog.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(30), decodeResult: decoder(31) }, + decodeRequest: decoder(32), decodeResult: decoder(33) }, { operation: "circular", operationId: "operation.application.circular", transport: { kind: "mcp_tool", toolName: "tracedecay_circular" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.circular.v1", requestSchema: { schemaId: "schema.application.primitive.circular.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.circular.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(32), decodeResult: decoder(33) }, + decodeRequest: decoder(34), decodeResult: decoder(35) }, { operation: "code_callees", operationId: "operation.application.code_callees", transport: { kind: "http", route: "/application/code/code_callees", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.code_callees.v1", requestSchema: { schemaId: "schema.application.code-query.callees.request", revision: 1 }, resultSchema: { schemaId: "schema.application.code-query.callees.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(34), decodeResult: decoder(35), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_callees.v1", "schema.application.code-query.callees.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(35)) }, + decodeRequest: decoder(36), decodeResult: decoder(37), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_callees.v1", "schema.application.code-query.callees.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(37)) }, { operation: "code_callers", operationId: "operation.application.code_callers", transport: { kind: "http", route: "/application/code/code_callers", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.code_callers.v1", requestSchema: { schemaId: "schema.application.primitive.code-callers.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.code-callers.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(36), decodeResult: decoder(37), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_callers.v1", "schema.application.primitive.code-callers.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(37)) }, + decodeRequest: decoder(38), decodeResult: decoder(39), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_callers.v1", "schema.application.primitive.code-callers.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(39)) }, { operation: "code_declaration", operationId: "operation.application.code_declaration", transport: { kind: "http", route: "/application/code/code_declaration", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.code_declaration.v1", requestSchema: { schemaId: "schema.application.code-query.declaration.request", revision: 1 }, resultSchema: { schemaId: "schema.application.code-query.declaration.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(38), decodeResult: decoder(39), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_declaration.v1", "schema.application.code-query.declaration.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(39)) }, + decodeRequest: decoder(40), decodeResult: decoder(41), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_declaration.v1", "schema.application.code-query.declaration.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(41)) }, { operation: "code_exact_occurrence", operationId: "operation.application.code_exact_occurrence", transport: { kind: "http", route: "/application/code/code_exact_occurrence", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.code_exact_occurrence.v1", requestSchema: { schemaId: "schema.application.code-query.exact-occurrence.request", revision: 1 }, resultSchema: { schemaId: "schema.application.code-query.exact-occurrence.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(40), decodeResult: decoder(41), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_exact_occurrence.v1", "schema.application.code-query.exact-occurrence.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(41)) }, + decodeRequest: decoder(42), decodeResult: decoder(43), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_exact_occurrence.v1", "schema.application.code-query.exact-occurrence.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(43)) }, { operation: "code_facets", operationId: "operation.application.code_facets", transport: { kind: "http", route: "/application/code/code_facets", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.code_facets.v1", requestSchema: { schemaId: "schema.application.code-query.facets.request", revision: 1 }, resultSchema: { schemaId: "schema.application.code-query.facets.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(42), decodeResult: decoder(43), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_facets.v1", "schema.application.code-query.facets.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(43)) }, + decodeRequest: decoder(44), decodeResult: decoder(45), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_facets.v1", "schema.application.code-query.facets.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(45)) }, { operation: "code_implementations", operationId: "operation.application.code_implementations", transport: { kind: "http", route: "/application/code/code_implementations", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.code_implementations.v1", requestSchema: { schemaId: "schema.application.primitive.code-implementations.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.code-implementations.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(44), decodeResult: decoder(45), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_implementations.v1", "schema.application.primitive.code-implementations.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(45)) }, + decodeRequest: decoder(46), decodeResult: decoder(47), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_implementations.v1", "schema.application.primitive.code-implementations.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(47)) }, { operation: "code_phrase_search", operationId: "operation.application.code_phrase_search", transport: { kind: "http", route: "/application/code/code_phrase_search", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.code_phrase_search.v1", requestSchema: { schemaId: "schema.application.code-query.phrase-search.request", revision: 1 }, resultSchema: { schemaId: "schema.application.code-query.phrase-search.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(46), decodeResult: decoder(47), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_phrase_search.v1", "schema.application.code-query.phrase-search.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(47)) }, + decodeRequest: decoder(48), decodeResult: decoder(49), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_phrase_search.v1", "schema.application.code-query.phrase-search.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(49)) }, { operation: "code_references", operationId: "operation.application.code_references", transport: { kind: "http", route: "/application/code/code_references", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.code_references.v1", requestSchema: { schemaId: "schema.application.code-query.references.request", revision: 1 }, resultSchema: { schemaId: "schema.application.code-query.references.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(38), decodeResult: decoder(35), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_references.v1", "schema.application.code-query.references.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(35)) }, + decodeRequest: decoder(40), decodeResult: decoder(37), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_references.v1", "schema.application.code-query.references.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(37)) }, { operation: "code_signature_search", operationId: "operation.application.code_signature_search", transport: { kind: "http", route: "/application/code/code_signature_search", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.code_signature_search.v1", requestSchema: { schemaId: "schema.application.primitive.code-signature-search.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.code-signature-search.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(48), decodeResult: decoder(49), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_signature_search.v1", "schema.application.primitive.code-signature-search.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(49)) }, + decodeRequest: decoder(50), decodeResult: decoder(51), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_signature_search.v1", "schema.application.primitive.code-signature-search.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(51)) }, { operation: "code_symbol_search", operationId: "operation.application.code_symbol_search", transport: { kind: "http", route: "/application/code/code_symbol_search", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.code_symbol_search.v1", requestSchema: { schemaId: "schema.application.symbol-search.request", revision: 1 }, resultSchema: { schemaId: "schema.application.symbol-search.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(50), decodeResult: decoder(49), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_symbol_search.v1", "schema.application.symbol-search.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(49)) }, + decodeRequest: decoder(52), decodeResult: decoder(51), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_symbol_search.v1", "schema.application.symbol-search.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(51)) }, { operation: "code_timeline", operationId: "operation.application.code_timeline", transport: { kind: "http", route: "/application/code/code_timeline", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.code_timeline.v1", requestSchema: { schemaId: "schema.application.code-query.timeline.request", revision: 1 }, resultSchema: { schemaId: "schema.application.code-query.timeline.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(51), decodeResult: decoder(52), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_timeline.v1", "schema.application.code-query.timeline.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(52)) }, + decodeRequest: decoder(53), decodeResult: decoder(54), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_timeline.v1", "schema.application.code-query.timeline.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(54)) }, { operation: "code_type_definition", operationId: "operation.application.code_type_definition", transport: { kind: "http", route: "/application/code/code_type_definition", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.code_type_definition.v1", requestSchema: { schemaId: "schema.application.code-query.type-definition.request", revision: 1 }, resultSchema: { schemaId: "schema.application.code-query.type-definition.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(38), decodeResult: decoder(39), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_type_definition.v1", "schema.application.code-query.type-definition.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(39)) }, + decodeRequest: decoder(40), decodeResult: decoder(41), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_type_definition.v1", "schema.application.code-query.type-definition.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(41)) }, { operation: "code_type_hierarchy", operationId: "operation.application.code_type_hierarchy", transport: { kind: "http", route: "/application/code/code_type_hierarchy", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.code_type_hierarchy.v1", requestSchema: { schemaId: "schema.application.primitive.code-type-hierarchy.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.code-type-hierarchy.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(53), decodeResult: decoder(54), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_type_hierarchy.v1", "schema.application.primitive.code-type-hierarchy.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(54)) }, + decodeRequest: decoder(55), decodeResult: decoder(56), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.code_type_hierarchy.v1", "schema.application.primitive.code-type-hierarchy.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(56)) }, { operation: "commit_context", operationId: "operation.application.commit_context", transport: { kind: "mcp_tool", toolName: "tracedecay_commit_context" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.commit_context.v1", requestSchema: { schemaId: "schema.application.primitive.commit-context.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.commit-context.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(55), decodeResult: decoder(56) }, + decodeRequest: decoder(57), decodeResult: decoder(58) }, { operation: "complexity", operationId: "operation.application.complexity", transport: { kind: "mcp_tool", toolName: "tracedecay_complexity" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.complexity.v1", requestSchema: { schemaId: "schema.application.primitive.complexity.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.complexity.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(57), decodeResult: decoder(58) }, + decodeRequest: decoder(59), decodeResult: decoder(60) }, { operation: "config", operationId: "operation.application.config", transport: { kind: "mcp_tool", toolName: "tracedecay_config" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.config.v1", requestSchema: { schemaId: "schema.application.primitive.config.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.config.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(59), decodeResult: decoder(60) }, + decodeRequest: decoder(61), decodeResult: decoder(62) }, { operation: "application_configuration_audit", operationId: "operation.application.configuration_audit", transport: { kind: "http", route: "/application/configuration/configuration_audit", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.configuration_audit.v1", requestSchema: { schemaId: "schema.application.configuration.configuration_audit.request", revision: 1 }, resultSchema: { schemaId: "schema.application.configuration.configuration_audit.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(61), decodeResult: decoder(62), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_audit.v1", "schema.application.configuration.configuration_audit.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(62)) }, + decodeRequest: decoder(63), decodeResult: decoder(64), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_audit.v1", "schema.application.configuration.configuration_audit.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(64)) }, { operation: "application_configuration_batch", operationId: "operation.application.configuration_batch", transport: { kind: "http", route: "/application/configuration/configuration_batch", method: "POST" }, effect: "configuration_write", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.configuration_batch.v1", requestSchema: { schemaId: "schema.application.configuration.configuration_batch.request", revision: 1 }, resultSchema: { schemaId: "schema.application.configuration.configuration_batch.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":15000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(63), decodeResult: decoder(64), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_batch.v1", "schema.application.configuration.configuration_batch.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(64)) }, + decodeRequest: decoder(65), decodeResult: decoder(66), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_batch.v1", "schema.application.configuration.configuration_batch.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(66)) }, { operation: "application_configuration_get", operationId: "operation.application.configuration_get", transport: { kind: "http", route: "/application/configuration/configuration_get", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.configuration_get.v1", requestSchema: { schemaId: "schema.application.configuration.configuration_get.request", revision: 1 }, resultSchema: { schemaId: "schema.application.configuration.configuration_get.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(65), decodeResult: decoder(66), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_get.v1", "schema.application.configuration.configuration_get.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(66)) }, + decodeRequest: decoder(67), decodeResult: decoder(68), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_get.v1", "schema.application.configuration.configuration_get.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(68)) }, { operation: "application_configuration_list", operationId: "operation.application.configuration_list", transport: { kind: "http", route: "/application/configuration/configuration_list", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.configuration_list.v1", requestSchema: { schemaId: "schema.application.configuration.configuration_list.request", revision: 1 }, resultSchema: { schemaId: "schema.application.configuration.configuration_list.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(67), decodeResult: decoder(68), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_list.v1", "schema.application.configuration.configuration_list.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(68)) }, + decodeRequest: decoder(69), decodeResult: decoder(70), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_list.v1", "schema.application.configuration.configuration_list.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(70)) }, { operation: "application_configuration_observed_state", operationId: "operation.application.configuration_observed_state", transport: { kind: "http", route: "/application/configuration/configuration_observed_state", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.configuration_observed_state.v1", requestSchema: { schemaId: "schema.application.configuration.configuration_observed_state.request", revision: 1 }, resultSchema: { schemaId: "schema.application.configuration.configuration_observed_state.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(69), decodeResult: decoder(70), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_observed_state.v1", "schema.application.configuration.configuration_observed_state.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(70)) }, + decodeRequest: decoder(71), decodeResult: decoder(72), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_observed_state.v1", "schema.application.configuration.configuration_observed_state.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(72)) }, { operation: "application_configuration_protected_apply", operationId: "operation.application.configuration_protected_apply", transport: { kind: "http", route: "/application/configuration/configuration_protected_apply", method: "POST" }, effect: "configuration_write", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.configuration_protected_apply.v1", requestSchema: { schemaId: "schema.application.configuration.configuration_protected_apply.request", revision: 1 }, resultSchema: { schemaId: "schema.application.configuration.configuration_protected_apply.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":15000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(71), decodeResult: decoder(64), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_protected_apply.v1", "schema.application.configuration.configuration_protected_apply.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(64)) }, + decodeRequest: decoder(73), decodeResult: decoder(66), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_protected_apply.v1", "schema.application.configuration.configuration_protected_apply.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(66)) }, { operation: "application_configuration_protected_preview", operationId: "operation.application.configuration_protected_preview", transport: { kind: "http", route: "/application/configuration/configuration_protected_preview", method: "POST" }, effect: "preview", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.configuration_protected_preview.v1", requestSchema: { schemaId: "schema.application.configuration.configuration_protected_preview.request", revision: 1 }, resultSchema: { schemaId: "schema.application.configuration.configuration_protected_preview.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(72), decodeResult: decoder(73), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_protected_preview.v1", "schema.application.configuration.configuration_protected_preview.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(73)) }, + decodeRequest: decoder(74), decodeResult: decoder(75), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_protected_preview.v1", "schema.application.configuration.configuration_protected_preview.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(75)) }, { operation: "application_configuration_rollback_apply", operationId: "operation.application.configuration_rollback_apply", transport: { kind: "http", route: "/application/configuration/configuration_rollback_apply", method: "POST" }, effect: "configuration_write", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.configuration_rollback_apply.v1", requestSchema: { schemaId: "schema.application.configuration.configuration_rollback_apply.request", revision: 1 }, resultSchema: { schemaId: "schema.application.configuration.configuration_rollback_apply.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":15000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(71), decodeResult: decoder(64), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_rollback_apply.v1", "schema.application.configuration.configuration_rollback_apply.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(64)) }, + decodeRequest: decoder(73), decodeResult: decoder(66), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_rollback_apply.v1", "schema.application.configuration.configuration_rollback_apply.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(66)) }, { operation: "application_configuration_rollback_preview", operationId: "operation.application.configuration_rollback_preview", transport: { kind: "http", route: "/application/configuration/configuration_rollback_preview", method: "POST" }, effect: "preview", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.configuration_rollback_preview.v1", requestSchema: { schemaId: "schema.application.configuration.configuration_rollback_preview.request", revision: 1 }, resultSchema: { schemaId: "schema.application.configuration.configuration_rollback_preview.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(74), decodeResult: decoder(73), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_rollback_preview.v1", "schema.application.configuration.configuration_rollback_preview.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(73)) }, + decodeRequest: decoder(76), decodeResult: decoder(75), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_rollback_preview.v1", "schema.application.configuration.configuration_rollback_preview.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(75)) }, { operation: "application_configuration_set", operationId: "operation.application.configuration_set", transport: { kind: "http", route: "/application/configuration/configuration_set", method: "POST" }, effect: "configuration_write", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.configuration_set.v1", requestSchema: { schemaId: "schema.application.configuration.configuration_set.request", revision: 1 }, resultSchema: { schemaId: "schema.application.configuration.configuration_set.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":15000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(75), decodeResult: decoder(64), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_set.v1", "schema.application.configuration.configuration_set.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(64)) }, + decodeRequest: decoder(77), decodeResult: decoder(66), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_set.v1", "schema.application.configuration.configuration_set.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(66)) }, { operation: "application_configuration_unset", operationId: "operation.application.configuration_unset", transport: { kind: "http", route: "/application/configuration/configuration_unset", method: "POST" }, effect: "configuration_write", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.configuration_unset.v1", requestSchema: { schemaId: "schema.application.configuration.configuration_unset.request", revision: 1 }, resultSchema: { schemaId: "schema.application.configuration.configuration_unset.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":15000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(76), decodeResult: decoder(64), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_unset.v1", "schema.application.configuration.configuration_unset.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(64)) }, + decodeRequest: decoder(78), decodeResult: decoder(66), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.configuration_unset.v1", "schema.application.configuration.configuration_unset.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(66)) }, { operation: "constructors", operationId: "operation.application.constructors", transport: { kind: "mcp_tool", toolName: "tracedecay_constructors" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.constructors.v1", requestSchema: { schemaId: "schema.application.primitive.constructors.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.constructors.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(77), decodeResult: decoder(78) }, + decodeRequest: decoder(79), decodeResult: decoder(80) }, { operation: "context", operationId: "operation.application.context", transport: { kind: "mcp_tool", toolName: "tracedecay_context" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.context.v1", requestSchema: { schemaId: "schema.application.primitive.context.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.context.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(79), decodeResult: decoder(80) }, + decodeRequest: decoder(81), decodeResult: decoder(82) }, { operation: "application_context_scout_budget", operationId: "operation.application.context_scout_budget", transport: { kind: "http", route: "/application/context-scout/context_scout_budget", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.context_scout_budget.v1", requestSchema: { schemaId: "schema.application.context-scout-budget.request", revision: 1 }, resultSchema: { schemaId: "schema.application.context-scout-budget.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(81), decodeResult: decoder(82), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_budget.v1", "schema.application.context-scout-budget.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(82)) }, + decodeRequest: decoder(83), decodeResult: decoder(84), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_budget.v1", "schema.application.context-scout-budget.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(84)) }, { operation: "application_context_scout_cancel", operationId: "operation.application.context_scout_cancel", transport: { kind: "http", route: "/application/context-scout/context_scout_cancel", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.context_scout_cancel.v1", requestSchema: { schemaId: "schema.application.context-scout-cancel.request", revision: 1 }, resultSchema: { schemaId: "schema.application.context-scout-cancel.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":15000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(83), decodeResult: decoder(84), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_cancel.v1", "schema.application.context-scout-cancel.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(84)) }, + decodeRequest: decoder(85), decodeResult: decoder(86), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_cancel.v1", "schema.application.context-scout-cancel.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(86)) }, { operation: "application_context_scout_capability", operationId: "operation.application.context_scout_capability", transport: { kind: "http", route: "/application/context-scout/context_scout_capability", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.context_scout_capability.v1", requestSchema: { schemaId: "schema.application.context-scout-capability.request", revision: 1 }, resultSchema: { schemaId: "schema.application.context-scout-capability.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(81), decodeResult: decoder(85), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_capability.v1", "schema.application.context-scout-capability.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(85)) }, + decodeRequest: decoder(83), decodeResult: decoder(87), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_capability.v1", "schema.application.context-scout-capability.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(87)) }, { operation: "application_context_scout_claim", operationId: "operation.application.context_scout_claim", transport: { kind: "http", route: "/application/context-scout/context_scout_claim", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.context_scout_claim.v1", requestSchema: { schemaId: "schema.application.context-scout-claim.request", revision: 1 }, resultSchema: { schemaId: "schema.application.context-scout-claim.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":15000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(86), decodeResult: decoder(87), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_claim.v1", "schema.application.context-scout-claim.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(87)) }, + decodeRequest: decoder(88), decodeResult: decoder(89), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_claim.v1", "schema.application.context-scout-claim.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(89)) }, { operation: "application_context_scout_delivery", operationId: "operation.application.context_scout_delivery", transport: { kind: "http", route: "/application/context-scout/context_scout_delivery", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.context_scout_delivery.v1", requestSchema: { schemaId: "schema.application.context-scout-delivery.request", revision: 1 }, resultSchema: { schemaId: "schema.application.context-scout-delivery.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":15000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(88), decodeResult: decoder(89), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_delivery.v1", "schema.application.context-scout-delivery.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(89)) }, + decodeRequest: decoder(90), decodeResult: decoder(91), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_delivery.v1", "schema.application.context-scout-delivery.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(91)) }, { operation: "application_context_scout_explain", operationId: "operation.application.context_scout_explain", transport: { kind: "http", route: "/application/context-scout/context_scout_explain", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.context_scout_explain.v1", requestSchema: { schemaId: "schema.application.context-scout-explain.request", revision: 1 }, resultSchema: { schemaId: "schema.application.context-scout-explain.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(90), decodeResult: decoder(91), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_explain.v1", "schema.application.context-scout-explain.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(91)) }, + decodeRequest: decoder(92), decodeResult: decoder(93), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_explain.v1", "schema.application.context-scout-explain.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(93)) }, { operation: "application_context_scout_feedback", operationId: "operation.application.context_scout_feedback", transport: { kind: "http", route: "/application/context-scout/context_scout_feedback", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.context_scout_feedback.v1", requestSchema: { schemaId: "schema.application.context-scout-feedback.request", revision: 1 }, resultSchema: { schemaId: "schema.application.context-scout-feedback.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":15000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(92), decodeResult: decoder(84), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_feedback.v1", "schema.application.context-scout-feedback.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(84)) }, + decodeRequest: decoder(94), decodeResult: decoder(86), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_feedback.v1", "schema.application.context-scout-feedback.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(86)) }, { operation: "application_context_scout_pause", operationId: "operation.application.context_scout_pause", transport: { kind: "http", route: "/application/context-scout/context_scout_pause", method: "POST" }, effect: "configuration_write", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.context_scout_pause.v1", requestSchema: { schemaId: "schema.application.context-scout-pause.request", revision: 1 }, resultSchema: { schemaId: "schema.application.context-scout-pause.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":15000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(93), decodeResult: decoder(64), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_pause.v1", "schema.application.context-scout-pause.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(64)) }, + decodeRequest: decoder(95), decodeResult: decoder(66), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_pause.v1", "schema.application.context-scout-pause.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(66)) }, { operation: "application_context_scout_recent", operationId: "operation.application.context_scout_recent", transport: { kind: "http", route: "/application/context-scout/context_scout_recent", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.context_scout_recent.v1", requestSchema: { schemaId: "schema.application.context-scout-recent.request", revision: 1 }, resultSchema: { schemaId: "schema.application.context-scout-recent.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(90), decodeResult: decoder(94), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_recent.v1", "schema.application.context-scout-recent.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(94)) }, + decodeRequest: decoder(92), decodeResult: decoder(96), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_recent.v1", "schema.application.context-scout-recent.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(96)) }, { operation: "application_context_scout_resume", operationId: "operation.application.context_scout_resume", transport: { kind: "http", route: "/application/context-scout/context_scout_resume", method: "POST" }, effect: "configuration_write", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.context_scout_resume.v1", requestSchema: { schemaId: "schema.application.context-scout-resume.request", revision: 1 }, resultSchema: { schemaId: "schema.application.context-scout-resume.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":15000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(93), decodeResult: decoder(64), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_resume.v1", "schema.application.context-scout-resume.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(64)) }, + decodeRequest: decoder(95), decodeResult: decoder(66), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_resume.v1", "schema.application.context-scout-resume.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(66)) }, { operation: "application_context_scout_status", operationId: "operation.application.context_scout_status", transport: { kind: "http", route: "/application/context-scout/context_scout_status", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.context_scout_status.v1", requestSchema: { schemaId: "schema.application.context-scout-status.request", revision: 1 }, resultSchema: { schemaId: "schema.application.context-scout-status.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(81), decodeResult: decoder(95), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_status.v1", "schema.application.context-scout-status.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(95)) }, + decodeRequest: decoder(83), decodeResult: decoder(97), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.context_scout_status.v1", "schema.application.context-scout-status.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(97)) }, { operation: "coupling", operationId: "operation.application.coupling", transport: { kind: "mcp_tool", toolName: "tracedecay_coupling" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.coupling.v1", requestSchema: { schemaId: "schema.application.primitive.coupling.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.coupling.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(96), decodeResult: decoder(97) }, + decodeRequest: decoder(98), decodeResult: decoder(99) }, { operation: "dashboard", operationId: "operation.application.dashboard", transport: { kind: "mcp_tool", toolName: "tracedecay_dashboard" }, effect: "binds_server", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.dashboard.v1", requestSchema: { schemaId: "schema.application.primitive.dashboard.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.dashboard.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(98), decodeResult: decoder(99) }, + decodeRequest: decoder(100), decodeResult: decoder(101) }, { operation: "dead_code", operationId: "operation.application.dead_code", transport: { kind: "mcp_tool", toolName: "tracedecay_dead_code" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.dead_code.v1", requestSchema: { schemaId: "schema.application.primitive.dead-code.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.dead-code.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(100), decodeResult: decoder(101) }, + decodeRequest: decoder(102), decodeResult: decoder(103) }, { operation: "dependency_depth", operationId: "operation.application.dependency_depth", transport: { kind: "mcp_tool", toolName: "tracedecay_dependency_depth" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.dependency_depth.v1", requestSchema: { schemaId: "schema.application.primitive.dependency-depth.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.dependency-depth.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(102), decodeResult: decoder(103) }, + decodeRequest: decoder(104), decodeResult: decoder(105) }, { operation: "derives", operationId: "operation.application.derives", transport: { kind: "mcp_tool", toolName: "tracedecay_derives" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.derives.v1", requestSchema: { schemaId: "schema.application.primitive.derives.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.derives.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(104), decodeResult: decoder(105) }, + decodeRequest: decoder(106), decodeResult: decoder(107) }, { operation: "diagnose", operationId: "operation.application.diagnose", transport: { kind: "mcp_tool", toolName: "tracedecay_diagnose" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.diagnose.v1", requestSchema: { schemaId: "schema.application.primitive.diagnose.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.diagnose.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(106), decodeResult: decoder(107) }, + decodeRequest: decoder(108), decodeResult: decoder(109) }, { operation: "application_diagnostics_read", operationId: "operation.application.diagnostics_read", transport: { kind: "http", route: "/application/primitives/diagnostics_read", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.diagnostics_read.v1", requestSchema: { schemaId: "schema.application.primitive.diagnostics-read.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.diagnostics-read.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(108), decodeResult: decoder(109), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.diagnostics_read.v1", "schema.application.primitive.diagnostics-read.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(109)) }, + decodeRequest: decoder(110), decodeResult: decoder(111), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.diagnostics_read.v1", "schema.application.primitive.diagnostics-read.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(111)) }, { operation: "diff_context", operationId: "operation.application.diff_context", transport: { kind: "mcp_tool", toolName: "tracedecay_diff_context" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.diff_context.v1", requestSchema: { schemaId: "schema.application.primitive.diff-context.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.diff-context.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(110), decodeResult: decoder(111) }, + decodeRequest: decoder(112), decodeResult: decoder(113) }, { operation: "distribution", operationId: "operation.application.distribution", transport: { kind: "mcp_tool", toolName: "tracedecay_distribution" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.distribution.v1", requestSchema: { schemaId: "schema.application.primitive.distribution.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.distribution.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(112), decodeResult: decoder(113) }, + decodeRequest: decoder(114), decodeResult: decoder(115) }, { operation: "doc_coverage", operationId: "operation.application.doc_coverage", transport: { kind: "mcp_tool", toolName: "tracedecay_doc_coverage" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.doc_coverage.v1", requestSchema: { schemaId: "schema.application.primitive.doc-coverage.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.doc-coverage.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(114), decodeResult: decoder(115) }, + decodeRequest: decoder(116), decodeResult: decoder(117) }, { operation: "dsm", operationId: "operation.application.dsm", transport: { kind: "mcp_tool", toolName: "tracedecay_dsm" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.dsm.v1", requestSchema: { schemaId: "schema.application.primitive.dsm.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.dsm.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(116), decodeResult: decoder(117) }, + decodeRequest: decoder(118), decodeResult: decoder(119) }, { operation: "application_fact_feedback", operationId: "operation.application.fact_feedback", transport: { kind: "http", route: "/application/retained/fact_feedback", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.fact_feedback.v1", requestSchema: { schemaId: "schema.application.retained.fact-feedback.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.fact-feedback.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], - decodeRequest: decoder(118), decodeResult: decoder(119), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_feedback.v1", "schema.application.retained.fact-feedback.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(119)) }, + decodeRequest: decoder(120), decodeResult: decoder(121), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_feedback.v1", "schema.application.retained.fact-feedback.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(121)) }, { operation: "application_fact_store_add", operationId: "operation.application.fact_store_add", transport: { kind: "http", route: "/application/retained/fact_store_add", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.fact_store_add.v1", requestSchema: { schemaId: "schema.application.retained.fact-store-add.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.fact-store-add.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], - decodeRequest: decoder(120), decodeResult: decoder(121), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_add.v1", "schema.application.retained.fact-store-add.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(121)) }, + decodeRequest: decoder(122), decodeResult: decoder(123), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_add.v1", "schema.application.retained.fact-store-add.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(123)) }, { operation: "application_fact_store_contradict", operationId: "operation.application.fact_store_contradict", transport: { kind: "http", route: "/application/retained/fact_store_contradict", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.fact_store_contradict.v1", requestSchema: { schemaId: "schema.application.retained.fact-store-contradict.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.fact-store-contradict.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(122), decodeResult: decoder(123), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_contradict.v1", "schema.application.retained.fact-store-contradict.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(123)) }, + decodeRequest: decoder(124), decodeResult: decoder(125), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_contradict.v1", "schema.application.retained.fact-store-contradict.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(125)) }, { operation: "application_fact_store_curate", operationId: "operation.application.fact_store_curate", transport: { kind: "http", route: "/application/retained/fact_store_curate", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "required", resultSemantics: "fact_store_curate_terminal", bindingId: "binding.http.fact_store_curate.v1", requestSchema: { schemaId: "schema.application.retained.fact-store-curate.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.fact-store-curate.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":90000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], - decodeRequest: decoder(124), decodeResult: decoder(125), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_curate.v1", "schema.application.retained.fact-store-curate.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(125)) }, + decodeRequest: decoder(126), decodeResult: decoder(127), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_curate.v1", "schema.application.retained.fact-store-curate.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(127)) }, { operation: "application_fact_store_get", operationId: "operation.application.fact_store_get", transport: { kind: "http", route: "/application/retained/fact_store_get", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.fact_store_get.v1", requestSchema: { schemaId: "schema.application.retained.fact-store-get.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.fact-store-get.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(126), decodeResult: decoder(127), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_get.v1", "schema.application.retained.fact-store-get.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(127)) }, + decodeRequest: decoder(128), decodeResult: decoder(129), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_get.v1", "schema.application.retained.fact-store-get.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(129)) }, { operation: "application_fact_store_list", operationId: "operation.application.fact_store_list", transport: { kind: "http", route: "/application/retained/fact_store_list", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.fact_store_list.v1", requestSchema: { schemaId: "schema.application.retained.fact-store-list.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.fact-store-list.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(128), decodeResult: decoder(129), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_list.v1", "schema.application.retained.fact-store-list.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(129)) }, + decodeRequest: decoder(130), decodeResult: decoder(131), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_list.v1", "schema.application.retained.fact-store-list.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(131)) }, { operation: "application_fact_store_probe", operationId: "operation.application.fact_store_probe", transport: { kind: "http", route: "/application/retained/fact_store_probe", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.fact_store_probe.v1", requestSchema: { schemaId: "schema.application.retained.fact-store-probe.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.fact-store-probe.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(130), decodeResult: decoder(131), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_probe.v1", "schema.application.retained.fact-store-probe.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(131)) }, + decodeRequest: decoder(132), decodeResult: decoder(133), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_probe.v1", "schema.application.retained.fact-store-probe.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(133)) }, { operation: "application_fact_store_reason", operationId: "operation.application.fact_store_reason", transport: { kind: "http", route: "/application/retained/fact_store_reason", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.fact_store_reason.v1", requestSchema: { schemaId: "schema.application.retained.fact-store-reason.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.fact-store-reason.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(132), decodeResult: decoder(133), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_reason.v1", "schema.application.retained.fact-store-reason.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(133)) }, + decodeRequest: decoder(134), decodeResult: decoder(135), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_reason.v1", "schema.application.retained.fact-store-reason.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(135)) }, { operation: "application_fact_store_related", operationId: "operation.application.fact_store_related", transport: { kind: "http", route: "/application/retained/fact_store_related", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.fact_store_related.v1", requestSchema: { schemaId: "schema.application.retained.fact-store-related.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.fact-store-related.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(134), decodeResult: decoder(135), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_related.v1", "schema.application.retained.fact-store-related.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(135)) }, + decodeRequest: decoder(136), decodeResult: decoder(137), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_related.v1", "schema.application.retained.fact-store-related.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(137)) }, { operation: "application_fact_store_remove", operationId: "operation.application.fact_store_remove", transport: { kind: "http", route: "/application/retained/fact_store_remove", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.fact_store_remove.v1", requestSchema: { schemaId: "schema.application.retained.fact-store-remove.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.fact-store-remove.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], - decodeRequest: decoder(136), decodeResult: decoder(137), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_remove.v1", "schema.application.retained.fact-store-remove.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(137)) }, + decodeRequest: decoder(138), decodeResult: decoder(139), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_remove.v1", "schema.application.retained.fact-store-remove.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(139)) }, { operation: "application_fact_store_search", operationId: "operation.application.fact_store_search", transport: { kind: "http", route: "/application/retained/fact_store_search", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.fact_store_search.v1", requestSchema: { schemaId: "schema.application.retained.fact-store-search.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.fact-store-search.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(138), decodeResult: decoder(139), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_search.v1", "schema.application.retained.fact-store-search.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(139)) }, + decodeRequest: decoder(140), decodeResult: decoder(141), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_search.v1", "schema.application.retained.fact-store-search.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(141)) }, { operation: "application_fact_store_supersede", operationId: "operation.application.fact_store_supersede", transport: { kind: "http", route: "/application/retained/fact_store_supersede", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.fact_store_supersede.v1", requestSchema: { schemaId: "schema.application.retained.fact-store-supersede.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.fact-store-supersede.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], - decodeRequest: decoder(140), decodeResult: decoder(141), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_supersede.v1", "schema.application.retained.fact-store-supersede.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(141)) }, + decodeRequest: decoder(142), decodeResult: decoder(143), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_supersede.v1", "schema.application.retained.fact-store-supersede.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(143)) }, { operation: "application_fact_store_update", operationId: "operation.application.fact_store_update", transport: { kind: "http", route: "/application/retained/fact_store_update", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.fact_store_update.v1", requestSchema: { schemaId: "schema.application.retained.fact-store-update.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.fact-store-update.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], - decodeRequest: decoder(142), decodeResult: decoder(143), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_update.v1", "schema.application.retained.fact-store-update.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(143)) }, + decodeRequest: decoder(144), decodeResult: decoder(145), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.fact_store_update.v1", "schema.application.retained.fact-store-update.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(145)) }, { operation: "application_feedback_advisory_cycle", operationId: "operation.application.feedback_advisory_cycle", transport: { kind: "http", route: "/application/feedback/advisory_cycle", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.feedback_advisory_cycle.v1", requestSchema: { schemaId: "schema.application.feedback.advisory-cycle.request", revision: 1 }, resultSchema: { schemaId: "schema.application.feedback.advisory-cycle.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(144), decodeResult: decoder(145), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.feedback_advisory_cycle.v1", "schema.application.feedback.advisory-cycle.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(145)) }, + decodeRequest: decoder(146), decodeResult: decoder(147), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.feedback_advisory_cycle.v1", "schema.application.feedback.advisory-cycle.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(147)) }, { operation: "application_feedback_diagnostics", operationId: "operation.application.feedback_diagnostics", transport: { kind: "http", route: "/application/feedback/diagnostics", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.feedback_diagnostics.v1", requestSchema: { schemaId: "schema.application.feedback.diagnostics.request", revision: 1 }, resultSchema: { schemaId: "schema.application.feedback.diagnostics.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(2), decodeResult: decoder(146), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.feedback_diagnostics.v1", "schema.application.feedback.diagnostics.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(146)) }, + decodeRequest: decoder(4), decodeResult: decoder(148), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.feedback_diagnostics.v1", "schema.application.feedback.diagnostics.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(148)) }, { operation: "application_feedback_expand", operationId: "operation.application.feedback_expand", transport: { kind: "http", route: "/application/feedback/expand", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.feedback_expand.v1", requestSchema: { schemaId: "schema.application.feedback.expand.request", revision: 1 }, resultSchema: { schemaId: "schema.application.feedback.expand.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(2), decodeResult: decoder(147), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.feedback_expand.v1", "schema.application.feedback.expand.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(147)) }, + decodeRequest: decoder(4), decodeResult: decoder(149), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.feedback_expand.v1", "schema.application.feedback.expand.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(149)) }, { operation: "application_feedback_get", operationId: "operation.application.feedback_get", transport: { kind: "http", route: "/application/feedback/get", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.feedback_get.v1", requestSchema: { schemaId: "schema.application.feedback.get.request", revision: 1 }, resultSchema: { schemaId: "schema.application.feedback.get.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(2), decodeResult: decoder(148), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.feedback_get.v1", "schema.application.feedback.get.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(148)) }, + decodeRequest: decoder(4), decodeResult: decoder(150), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.feedback_get.v1", "schema.application.feedback.get.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(150)) }, { operation: "application_feedback_impact", operationId: "operation.application.feedback_impact", transport: { kind: "http", route: "/application/feedback/impact", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.feedback_impact.v1", requestSchema: { schemaId: "schema.application.feedback.impact.request", revision: 1 }, resultSchema: { schemaId: "schema.application.feedback.impact.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(2), decodeResult: decoder(149), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.feedback_impact.v1", "schema.application.feedback.impact.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(149)) }, + decodeRequest: decoder(4), decodeResult: decoder(151), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.feedback_impact.v1", "schema.application.feedback.impact.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(151)) }, { operation: "application_feedback_list", operationId: "operation.application.feedback_list", transport: { kind: "http", route: "/application/feedback/list", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.feedback_list.v1", requestSchema: { schemaId: "schema.application.feedback.list.request", revision: 1 }, resultSchema: { schemaId: "schema.application.feedback.list.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(2), decodeResult: decoder(150), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.feedback_list.v1", "schema.application.feedback.list.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(150)) }, + decodeRequest: decoder(4), decodeResult: decoder(152), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.feedback_list.v1", "schema.application.feedback.list.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(152)) }, { operation: "application_feedback_proximity", operationId: "operation.application.feedback_proximity", transport: { kind: "http", route: "/application/feedback/proximity", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.feedback_proximity.v1", requestSchema: { schemaId: "schema.application.feedback.proximity.request", revision: 1 }, resultSchema: { schemaId: "schema.application.feedback.proximity.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(151), decodeResult: decoder(152), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.feedback_proximity.v1", "schema.application.feedback.proximity.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(152)) }, + decodeRequest: decoder(153), decodeResult: decoder(154), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.feedback_proximity.v1", "schema.application.feedback.proximity.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(154)) }, { operation: "field_sites", operationId: "operation.application.field_sites", transport: { kind: "mcp_tool", toolName: "tracedecay_field_sites" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.field_sites.v1", requestSchema: { schemaId: "schema.application.primitive.field-sites.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.field-sites.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(153), decodeResult: decoder(154) }, + decodeRequest: decoder(155), decodeResult: decoder(156) }, { operation: "application_file_dependents", operationId: "operation.application.file_dependents", transport: { kind: "http", route: "/application/primitives/file_dependents", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.file_dependents.v1", requestSchema: { schemaId: "schema.application.primitive.file-dependents.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.file-dependents.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(155), decodeResult: decoder(156), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.file_dependents.v1", "schema.application.primitive.file-dependents.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(156)) }, + decodeRequest: decoder(157), decodeResult: decoder(158), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.file_dependents.v1", "schema.application.primitive.file-dependents.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(158)) }, { operation: "files", operationId: "operation.application.files", transport: { kind: "mcp_tool", toolName: "tracedecay_files" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.files.v1", requestSchema: { schemaId: "schema.application.primitive.files.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.files.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(157), decodeResult: decoder(158) }, + decodeRequest: decoder(159), decodeResult: decoder(160) }, { operation: "find_exact_symbol", operationId: "operation.application.find_exact_symbol", transport: { kind: "mcp_tool", toolName: "tracedecay_find_exact_symbol" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.find_exact_symbol.v1", requestSchema: { schemaId: "schema.application.primitive.find-exact-symbol.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.find-exact-symbol.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(159), decodeResult: decoder(160) }, + decodeRequest: decoder(161), decodeResult: decoder(162) }, { operation: "gini", operationId: "operation.application.gini", transport: { kind: "mcp_tool", toolName: "tracedecay_gini" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.gini.v1", requestSchema: { schemaId: "schema.application.primitive.gini.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.gini.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(161), decodeResult: decoder(162) }, + decodeRequest: decoder(163), decodeResult: decoder(164) }, { operation: "git_apply", operationId: "operation.application.git_apply", transport: { kind: "mcp_tool", toolName: "tracedecay_git_apply" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.git_apply.v1", requestSchema: { schemaId: "schema.application.git.apply.request", revision: 1 }, resultSchema: { schemaId: "schema.application.git.apply.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(163), decodeResult: decoder(164) }, + decodeRequest: decoder(165), decodeResult: decoder(166) }, { operation: "application_git_blame", operationId: "operation.application.git_blame", transport: { kind: "http", route: "/application/git/blame", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.git_blame.v1", requestSchema: { schemaId: "schema.application.git.blame.request", revision: 1 }, resultSchema: { schemaId: "schema.application.git.blame.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(165), decodeResult: decoder(166), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.git_blame.v1", "schema.application.git.blame.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(166)) }, + decodeRequest: decoder(167), decodeResult: decoder(168), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.git_blame.v1", "schema.application.git.blame.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(168)) }, { operation: "application_git_diff", operationId: "operation.application.git_diff", transport: { kind: "http", route: "/application/git/diff", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.git_diff.v1", requestSchema: { schemaId: "schema.application.git.diff.request", revision: 1 }, resultSchema: { schemaId: "schema.application.git.diff.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(167), decodeResult: decoder(166), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.git_diff.v1", "schema.application.git.diff.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(166)) }, + decodeRequest: decoder(169), decodeResult: decoder(168), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.git_diff.v1", "schema.application.git.diff.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(168)) }, { operation: "application_git_history", operationId: "operation.application.git_history", transport: { kind: "http", route: "/application/git/history", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.git_history.v1", requestSchema: { schemaId: "schema.application.git.history.request", revision: 1 }, resultSchema: { schemaId: "schema.application.git.history.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(168), decodeResult: decoder(166), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.git_history.v1", "schema.application.git.history.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(166)) }, + decodeRequest: decoder(170), decodeResult: decoder(168), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.git_history.v1", "schema.application.git.history.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(168)) }, { operation: "application_git_hunks", operationId: "operation.application.git_hunks", transport: { kind: "http", route: "/application/git/hunks", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.git_hunks.v1", requestSchema: { schemaId: "schema.application.git.hunks.request", revision: 1 }, resultSchema: { schemaId: "schema.application.git.hunks.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(169), decodeResult: decoder(166), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.git_hunks.v1", "schema.application.git.hunks.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(166)) }, + decodeRequest: decoder(171), decodeResult: decoder(168), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.git_hunks.v1", "schema.application.git.hunks.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(168)) }, { operation: "git_preview", operationId: "operation.application.git_preview", transport: { kind: "mcp_tool", toolName: "tracedecay_git_preview" }, effect: "preview", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.git_preview.v1", requestSchema: { schemaId: "schema.application.git.preview.request", revision: 1 }, resultSchema: { schemaId: "schema.application.git.preview.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(170), decodeResult: decoder(171) }, + decodeRequest: decoder(172), decodeResult: decoder(173) }, { operation: "application_git_status", operationId: "operation.application.git_status", transport: { kind: "http", route: "/application/git/status", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.git_status.v1", requestSchema: { schemaId: "schema.application.git.status.request", revision: 1 }, resultSchema: { schemaId: "schema.application.git.status.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(172), decodeResult: decoder(166), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.git_status.v1", "schema.application.git.status.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(166)) }, + decodeRequest: decoder(174), decodeResult: decoder(168), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.git_status.v1", "schema.application.git.status.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(168)) }, { operation: "application_github_stack_signal_expand", operationId: "operation.application.github_stack_signal_expand", transport: { kind: "http", route: "/application/github-stack/signal-expand", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.github_stack_signal_expand.v1", requestSchema: { schemaId: "schema.application.github-stack.signal-expand.request", revision: 1 }, resultSchema: { schemaId: "schema.application.github-stack.signal-expand.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(173), decodeResult: decoder(174), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.github_stack_signal_expand.v1", "schema.application.github-stack.signal-expand.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(174)) }, + decodeRequest: decoder(175), decodeResult: decoder(176), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.github_stack_signal_expand.v1", "schema.application.github-stack.signal-expand.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(176)) }, { operation: "god_class", operationId: "operation.application.god_class", transport: { kind: "mcp_tool", toolName: "tracedecay_god_class" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.god_class.v1", requestSchema: { schemaId: "schema.application.primitive.god-class.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.god-class.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(175), decodeResult: decoder(176) }, + decodeRequest: decoder(177), decodeResult: decoder(178) }, { operation: "grep", operationId: "operation.application.grep", transport: { kind: "mcp_tool", toolName: "tracedecay_grep" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.grep.v1", requestSchema: { schemaId: "schema.application.primitive.grep.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.grep.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(177), decodeResult: decoder(178) }, + decodeRequest: decoder(179), decodeResult: decoder(180) }, { operation: "health", operationId: "operation.application.health", transport: { kind: "mcp_tool", toolName: "tracedecay_health" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.health.v1", requestSchema: { schemaId: "schema.application.primitive.health.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.health.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(179), decodeResult: decoder(180) }, + decodeRequest: decoder(181), decodeResult: decoder(182) }, { operation: "application_health_delta", operationId: "operation.application.health_delta", transport: { kind: "http", route: "/application/primitives/health_delta", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.health_delta.v1", requestSchema: { schemaId: "schema.application.primitive.health-delta.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.health-delta.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(181), decodeResult: decoder(182), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.health_delta.v1", "schema.application.primitive.health-delta.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(182)) }, + decodeRequest: decoder(183), decodeResult: decoder(184), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.health_delta.v1", "schema.application.primitive.health-delta.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(184)) }, { operation: "application_health_read", operationId: "operation.application.health_read", transport: { kind: "http", route: "/application/primitives/health_read", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.health_read.v1", requestSchema: { schemaId: "schema.application.primitive.health-read.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.health-read.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(183), decodeResult: decoder(184), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.health_read.v1", "schema.application.primitive.health-read.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(184)) }, + decodeRequest: decoder(185), decodeResult: decoder(186), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.health_read.v1", "schema.application.primitive.health-read.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(186)) }, { operation: "hermes_skill_bridge", operationId: "operation.application.hermes_skill_bridge", transport: { kind: "mcp_tool", toolName: "tracedecay_hermes_skill_bridge" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.hermes_skill_bridge.v1", requestSchema: { schemaId: "schema.application.primitive.hermes-skill-bridge.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.hermes-skill-bridge.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(185), decodeResult: decoder(186) }, + decodeRequest: decoder(187), decodeResult: decoder(188) }, { operation: "hotspots", operationId: "operation.application.hotspots", transport: { kind: "mcp_tool", toolName: "tracedecay_hotspots" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.hotspots.v1", requestSchema: { schemaId: "schema.application.primitive.hotspots.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.hotspots.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(187), decodeResult: decoder(188) }, + decodeRequest: decoder(189), decodeResult: decoder(190) }, { operation: "impact", operationId: "operation.application.impact", transport: { kind: "mcp_tool", toolName: "tracedecay_impact" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.impact.v1", requestSchema: { schemaId: "schema.application.primitive.impact.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.impact.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(189), decodeResult: decoder(190) }, + decodeRequest: decoder(191), decodeResult: decoder(192) }, { operation: "inheritance_depth", operationId: "operation.application.inheritance_depth", transport: { kind: "mcp_tool", toolName: "tracedecay_inheritance_depth" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.inheritance_depth.v1", requestSchema: { schemaId: "schema.application.primitive.inheritance-depth.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.inheritance-depth.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(191), decodeResult: decoder(192) }, + decodeRequest: decoder(193), decodeResult: decoder(194) }, { operation: "insert_at", operationId: "operation.application.insert_at", transport: { kind: "mcp_tool", toolName: "tracedecay_insert_at" }, effect: "source_edit", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.insert_at.v1", requestSchema: { schemaId: "schema.application.source-edit.insert-at.request", revision: 1 }, resultSchema: { schemaId: "schema.application.source-edit.insert-at.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(193), decodeResult: decoder(10) }, + decodeRequest: decoder(195), decodeResult: decoder(12) }, { operation: "insert_at_symbol", operationId: "operation.application.insert_at_symbol", transport: { kind: "mcp_tool", toolName: "tracedecay_insert_at_symbol" }, effect: "source_edit", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.insert_at_symbol.v1", requestSchema: { schemaId: "schema.application.source-edit.insert-at-symbol.request", revision: 1 }, resultSchema: { schemaId: "schema.application.source-edit.insert-at-symbol.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(194), decodeResult: decoder(10) }, + decodeRequest: decoder(196), decodeResult: decoder(12) }, { operation: "largest", operationId: "operation.application.largest", transport: { kind: "mcp_tool", toolName: "tracedecay_largest" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.largest.v1", requestSchema: { schemaId: "schema.application.primitive.largest.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.largest.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(195), decodeResult: decoder(196) }, + decodeRequest: decoder(197), decodeResult: decoder(198) }, { operation: "application_lcm_describe", operationId: "operation.application.lcm_describe", transport: { kind: "http", route: "/application/retained/lcm_describe", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.lcm_describe.v1", requestSchema: { schemaId: "schema.application.retained.lcm-describe.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.lcm-describe.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(197), decodeResult: decoder(198), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.lcm_describe.v1", "schema.application.retained.lcm-describe.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(198)) }, + decodeRequest: decoder(199), decodeResult: decoder(200), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.lcm_describe.v1", "schema.application.retained.lcm-describe.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(200)) }, { operation: "application_lcm_doctor", operationId: "operation.application.lcm_doctor", transport: { kind: "http", route: "/application/retained/lcm_doctor", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.lcm_doctor.v1", requestSchema: { schemaId: "schema.application.retained.lcm-doctor.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.lcm-doctor.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(199), decodeResult: decoder(200), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.lcm_doctor.v1", "schema.application.retained.lcm-doctor.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(200)) }, + decodeRequest: decoder(201), decodeResult: decoder(202), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.lcm_doctor.v1", "schema.application.retained.lcm-doctor.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(202)) }, { operation: "application_lcm_expand", operationId: "operation.application.lcm_expand", transport: { kind: "http", route: "/application/retained/lcm_expand", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.lcm_expand.v1", requestSchema: { schemaId: "schema.application.retained.lcm-expand.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.lcm-expand.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(201), decodeResult: decoder(202), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.lcm_expand.v1", "schema.application.retained.lcm-expand.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(202)) }, + decodeRequest: decoder(203), decodeResult: decoder(204), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.lcm_expand.v1", "schema.application.retained.lcm-expand.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(204)) }, { operation: "application_lcm_expand_query", operationId: "operation.application.lcm_expand_query", transport: { kind: "http", route: "/application/retained/lcm_expand_query", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.lcm_expand_query.v1", requestSchema: { schemaId: "schema.application.retained.lcm-expand-query.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.lcm-expand-query.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(203), decodeResult: decoder(204), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.lcm_expand_query.v1", "schema.application.retained.lcm-expand-query.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(204)) }, + decodeRequest: decoder(205), decodeResult: decoder(206), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.lcm_expand_query.v1", "schema.application.retained.lcm-expand-query.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(206)) }, { operation: "application_lcm_grep", operationId: "operation.application.lcm_grep", transport: { kind: "http", route: "/application/retained/lcm_grep", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.lcm_grep.v1", requestSchema: { schemaId: "schema.application.retained.lcm-grep.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.lcm-grep.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(205), decodeResult: decoder(206), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.lcm_grep.v1", "schema.application.retained.lcm-grep.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(206)) }, + decodeRequest: decoder(207), decodeResult: decoder(208), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.lcm_grep.v1", "schema.application.retained.lcm-grep.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(208)) }, { operation: "application_lcm_load_session", operationId: "operation.application.lcm_load_session", transport: { kind: "http", route: "/application/retained/lcm_load_session", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.lcm_load_session.v1", requestSchema: { schemaId: "schema.application.retained.lcm-load-session.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.lcm-load-session.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(207), decodeResult: decoder(208), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.lcm_load_session.v1", "schema.application.retained.lcm-load-session.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(208)) }, + decodeRequest: decoder(209), decodeResult: decoder(210), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.lcm_load_session.v1", "schema.application.retained.lcm-load-session.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(210)) }, { operation: "application_lcm_status", operationId: "operation.application.lcm_status", transport: { kind: "http", route: "/application/retained/lcm_status", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.lcm_status.v1", requestSchema: { schemaId: "schema.application.retained.lcm-status.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.lcm-status.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(209), decodeResult: decoder(210), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.lcm_status.v1", "schema.application.retained.lcm-status.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(210)) }, + decodeRequest: decoder(211), decodeResult: decoder(212), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.lcm_status.v1", "schema.application.retained.lcm-status.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(212)) }, { operation: "application_memory_status", operationId: "operation.application.memory_status", transport: { kind: "http", route: "/application/retained/memory_status", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.memory_status.v1", requestSchema: { schemaId: "schema.application.retained.memory-status.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.memory-status.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(211), decodeResult: decoder(212), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.memory_status.v1", "schema.application.retained.memory-status.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(212)) }, + decodeRequest: decoder(213), decodeResult: decoder(214), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.memory_status.v1", "schema.application.retained.memory-status.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(214)) }, { operation: "application_message_search", operationId: "operation.application.message_search", transport: { kind: "http", route: "/application/retained/message_search", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.message_search.v1", requestSchema: { schemaId: "schema.application.retained.message-search.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.message-search.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(213), decodeResult: decoder(214), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.message_search.v1", "schema.application.retained.message-search.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(214)) }, + decodeRequest: decoder(215), decodeResult: decoder(216), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.message_search.v1", "schema.application.retained.message-search.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(216)) }, { operation: "application_module_api", operationId: "operation.application.module_api", transport: { kind: "http", route: "/application/primitives/module_api", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.module_api.v1", requestSchema: { schemaId: "schema.application.primitive.module-api.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.module-api.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(215), decodeResult: decoder(216), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.module_api.v1", "schema.application.primitive.module-api.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(216)) }, + decodeRequest: decoder(217), decodeResult: decoder(218), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.module_api.v1", "schema.application.primitive.module-api.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(218)) }, { operation: "move_symbol", operationId: "operation.application.move_symbol", transport: { kind: "mcp_tool", toolName: "tracedecay_move_symbol" }, effect: "source_edit", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.move_symbol.v1", requestSchema: { schemaId: "schema.application.source-edit.move-symbol.request", revision: 1 }, resultSchema: { schemaId: "schema.application.source-edit.move-symbol.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(217), decodeResult: decoder(10) }, + decodeRequest: decoder(219), decodeResult: decoder(12) }, { operation: "multi_str_replace", operationId: "operation.application.multi_str_replace", transport: { kind: "mcp_tool", toolName: "tracedecay_multi_str_replace" }, effect: "source_edit", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.multi_str_replace.v1", requestSchema: { schemaId: "schema.application.source-edit.multi-str-replace.request", revision: 1 }, resultSchema: { schemaId: "schema.application.source-edit.multi-str-replace.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(218), decodeResult: decoder(10) }, + decodeRequest: decoder(220), decodeResult: decoder(12) }, { operation: "native_integration_status", operationId: "operation.application.native_integration_status", transport: { kind: "mcp_tool", toolName: "tracedecay_native_integration_status" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.native_integration_status.v1", requestSchema: { schemaId: "schema.application.native-integration.status.request", revision: 1 }, resultSchema: { schemaId: "schema.application.native-integration.status.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(219), decodeResult: decoder(7) }, + decodeRequest: decoder(221), decodeResult: decoder(9) }, { operation: "node", operationId: "operation.application.node", transport: { kind: "mcp_tool", toolName: "tracedecay_node" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.node.v1", requestSchema: { schemaId: "schema.application.primitive.node.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.node.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(220), decodeResult: decoder(221) }, + decodeRequest: decoder(222), decodeResult: decoder(223) }, { operation: "observatory_read", operationId: "operation.application.observatory_read", transport: { kind: "mcp_tool", toolName: "tracedecay_observatory_read" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.observatory_read.v1", requestSchema: { schemaId: "schema.application.observatory-read.request", revision: 1 }, resultSchema: { schemaId: "schema.application.observatory-read.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(222), decodeResult: decoder(223) }, + decodeRequest: decoder(224), decodeResult: decoder(225) }, { operation: "port_order", operationId: "operation.application.port_order", transport: { kind: "mcp_tool", toolName: "tracedecay_port_order" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.port_order.v1", requestSchema: { schemaId: "schema.application.primitive.port-order.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.port-order.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(224), decodeResult: decoder(225) }, + decodeRequest: decoder(226), decodeResult: decoder(227) }, { operation: "port_status", operationId: "operation.application.port_status", transport: { kind: "mcp_tool", toolName: "tracedecay_port_status" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.port_status.v1", requestSchema: { schemaId: "schema.application.primitive.port-status.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.port-status.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(226), decodeResult: decoder(227) }, + decodeRequest: decoder(228), decodeResult: decoder(229) }, { operation: "pr_context", operationId: "operation.application.pr_context", transport: { kind: "mcp_tool", toolName: "tracedecay_pr_context" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.pr_context.v1", requestSchema: { schemaId: "schema.application.primitive.pr-context.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.pr-context.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(228), decodeResult: decoder(229) }, + decodeRequest: decoder(230), decodeResult: decoder(231) }, { operation: "preflight_native_integration", operationId: "operation.application.preflight_native_integration", transport: { kind: "mcp_tool", toolName: "tracedecay_preflight_native_integration" }, effect: "preview", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.preflight_native_integration.v1", requestSchema: { schemaId: "schema.application.native-integration.preflight.request", revision: 1 }, resultSchema: { schemaId: "schema.application.native-integration.preflight.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(230), decodeResult: decoder(7) }, + decodeRequest: decoder(232), decodeResult: decoder(9) }, + { operation: "project_context", operationId: "operation.application.project_context", transport: { kind: "mcp_tool", toolName: "tracedecay_project_context" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.project_context.v1", + requestSchema: { schemaId: "schema.application.primitive.project-context.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.project-context.result", revision: 1 }, + cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], + decodeRequest: decoder(233), decodeResult: decoder(234) }, + { operation: "project_list", operationId: "operation.application.project_list", transport: { kind: "mcp_tool", toolName: "tracedecay_project_list" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.project_list.v1", + requestSchema: { schemaId: "schema.application.primitive.project-list.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.project-list.result", revision: 1 }, + cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], + decodeRequest: decoder(235), decodeResult: decoder(236) }, + { operation: "project_search", operationId: "operation.application.project_search", transport: { kind: "mcp_tool", toolName: "tracedecay_project_search" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.project_search.v1", + requestSchema: { schemaId: "schema.application.primitive.project-search.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.project-search.result", revision: 1 }, + cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], + decodeRequest: decoder(237), decodeResult: decoder(236) }, { operation: "application_qualified_name", operationId: "operation.application.qualified_name", transport: { kind: "http", route: "/application/primitives/qualified_name", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.qualified_name.v1", requestSchema: { schemaId: "schema.application.primitive.qualified-name.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.qualified-name.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(231), decodeResult: decoder(232), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.qualified_name.v1", "schema.application.primitive.qualified-name.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(232)) }, + decodeRequest: decoder(238), decodeResult: decoder(239), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.qualified_name.v1", "schema.application.primitive.qualified-name.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(239)) }, { operation: "rank", operationId: "operation.application.rank", transport: { kind: "mcp_tool", toolName: "tracedecay_rank" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.rank.v1", requestSchema: { schemaId: "schema.application.primitive.rank.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.rank.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(233), decodeResult: decoder(234) }, + decodeRequest: decoder(240), decodeResult: decoder(241) }, { operation: "recursion", operationId: "operation.application.recursion", transport: { kind: "mcp_tool", toolName: "tracedecay_recursion" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.recursion.v1", requestSchema: { schemaId: "schema.application.primitive.recursion.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.recursion.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(235), decodeResult: decoder(236) }, + decodeRequest: decoder(242), decodeResult: decoder(243) }, { operation: "redundancy", operationId: "operation.application.redundancy", transport: { kind: "mcp_tool", toolName: "tracedecay_redundancy" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.redundancy.v1", requestSchema: { schemaId: "schema.application.primitive.redundancy.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.redundancy.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(237), decodeResult: decoder(238) }, + decodeRequest: decoder(244), decodeResult: decoder(245) }, + { operation: "remote_status", operationId: "operation.application.remote_status", transport: { kind: "mcp_tool", toolName: "tracedecay_remote_status" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.remote_status.v1", + requestSchema: { schemaId: "schema.application.primitive.remote-status.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.remote-status.result", revision: 1 }, + cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], + decodeRequest: decoder(246), decodeResult: decoder(247) }, { operation: "rename_preview", operationId: "operation.application.rename_preview", transport: { kind: "mcp_tool", toolName: "tracedecay_rename_preview" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.rename_preview.v1", requestSchema: { schemaId: "schema.application.primitive.rename-preview.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.rename-preview.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(239), decodeResult: decoder(240) }, + decodeRequest: decoder(248), decodeResult: decoder(249) }, { operation: "rename_symbol", operationId: "operation.application.rename_symbol", transport: { kind: "mcp_tool", toolName: "tracedecay_rename_symbol" }, effect: "source_edit", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.rename_symbol.v1", requestSchema: { schemaId: "schema.application.source-edit.rename-symbol.request", revision: 1 }, resultSchema: { schemaId: "schema.application.source-edit.rename-symbol.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(241), decodeResult: decoder(10) }, + decodeRequest: decoder(250), decodeResult: decoder(12) }, { operation: "replace_symbol", operationId: "operation.application.replace_symbol", transport: { kind: "mcp_tool", toolName: "tracedecay_replace_symbol" }, effect: "source_edit", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.replace_symbol.v1", requestSchema: { schemaId: "schema.application.source-edit.replace-symbol.request", revision: 1 }, resultSchema: { schemaId: "schema.application.source-edit.replace-symbol.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(242), decodeResult: decoder(10) }, + decodeRequest: decoder(251), decodeResult: decoder(12) }, { operation: "retrieve", operationId: "operation.application.retrieve", transport: { kind: "mcp_tool", toolName: "tracedecay_retrieve" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.retrieve.v1", requestSchema: { schemaId: "schema.application.primitive.retrieve.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.retrieve.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(243), decodeResult: decoder(244) }, + decodeRequest: decoder(252), decodeResult: decoder(253) }, { operation: "run_affected_tests", operationId: "operation.application.run_affected_tests", transport: { kind: "mcp_tool", toolName: "tracedecay_run_affected_tests" }, effect: "spawns_process", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.run_affected_tests.v1", requestSchema: { schemaId: "schema.application.primitive.run-affected-tests.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.run-affected-tests.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","effect_in_flight"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":600000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(245), decodeResult: decoder(246) }, + decodeRequest: decoder(254), decodeResult: decoder(255) }, + { operation: "runtime", operationId: "operation.application.runtime", transport: { kind: "mcp_tool", toolName: "tracedecay_runtime" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.runtime.v1", + requestSchema: { schemaId: "schema.application.primitive.runtime.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.runtime.result", revision: 1 }, + cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], + decodeRequest: decoder(256), decodeResult: decoder(257) }, { operation: "search", operationId: "operation.application.search", transport: { kind: "mcp_tool", toolName: "tracedecay_search" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.search.v1", requestSchema: { schemaId: "schema.application.primitive.search.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.search.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(247), decodeResult: decoder(248) }, + decodeRequest: decoder(258), decodeResult: decoder(259) }, { operation: "session_lookup", operationId: "operation.application.session_lookup", transport: { kind: "mcp_tool", toolName: "tracedecay_session_lookup" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.session_lookup.v1", requestSchema: { schemaId: "schema.application.primitive.session-lookup.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.session-lookup.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(249), decodeResult: decoder(250) }, + decodeRequest: decoder(260), decodeResult: decoder(261) }, { operation: "application_session_refresh_begin", operationId: "operation.application.session_refresh_begin", transport: { kind: "http", route: "/application/retained/session_refresh_begin", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.session_refresh_begin.v1", requestSchema: { schemaId: "schema.application.retained.session-refresh-begin.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.session-refresh-begin.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], - decodeRequest: decoder(251), decodeResult: decoder(252), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.session_refresh_begin.v1", "schema.application.retained.session-refresh-begin.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(252)) }, + decodeRequest: decoder(262), decodeResult: decoder(263), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.session_refresh_begin.v1", "schema.application.retained.session-refresh-begin.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(263)) }, { operation: "application_session_refresh_cancel", operationId: "operation.application.session_refresh_cancel", transport: { kind: "http", route: "/application/retained/session_refresh_cancel", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.session_refresh_cancel.v1", requestSchema: { schemaId: "schema.application.retained.session-refresh-cancel.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.session-refresh-cancel.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], - decodeRequest: decoder(251), decodeResult: decoder(253), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.session_refresh_cancel.v1", "schema.application.retained.session-refresh-cancel.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(253)) }, + decodeRequest: decoder(262), decodeResult: decoder(264), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.session_refresh_cancel.v1", "schema.application.retained.session-refresh-cancel.result", 1, ["completed","cancelled","timed_out","failed","unavailable","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","reconciling","after_commit"]}, "durable_effect", "required", decoder(264)) }, { operation: "application_session_refresh_status", operationId: "operation.application.session_refresh_status", transport: { kind: "http", route: "/application/retained/session_refresh_status", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.session_refresh_status.v1", requestSchema: { schemaId: "schema.application.retained.session-refresh-status.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.session-refresh-status.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(251), decodeResult: decoder(254), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.session_refresh_status.v1", "schema.application.retained.session-refresh-status.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(254)) }, + decodeRequest: decoder(262), decodeResult: decoder(265), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.session_refresh_status.v1", "schema.application.retained.session-refresh-status.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(265)) }, { operation: "application_sessions_for", operationId: "operation.application.sessions_for", transport: { kind: "http", route: "/application/retained/sessions_for", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.sessions_for.v1", requestSchema: { schemaId: "schema.application.retained.sessions-for.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.sessions-for.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(255), decodeResult: decoder(256), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.sessions_for.v1", "schema.application.retained.sessions-for.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(256)) }, + decodeRequest: decoder(266), decodeResult: decoder(267), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.sessions_for.v1", "schema.application.retained.sessions-for.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(267)) }, { operation: "signature", operationId: "operation.application.signature", transport: { kind: "mcp_tool", toolName: "tracedecay_signature" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.signature.v1", requestSchema: { schemaId: "schema.application.primitive.signature.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.signature.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(104), decodeResult: decoder(257) }, + decodeRequest: decoder(106), decodeResult: decoder(268) }, { operation: "similar", operationId: "operation.application.similar", transport: { kind: "mcp_tool", toolName: "tracedecay_similar" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.similar.v1", requestSchema: { schemaId: "schema.application.primitive.similar.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.similar.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(258), decodeResult: decoder(259) }, + decodeRequest: decoder(269), decodeResult: decoder(270) }, { operation: "skill_list", operationId: "operation.application.skill_list", transport: { kind: "mcp_tool", toolName: "tracedecay_skill_list" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.skill_list.v1", requestSchema: { schemaId: "schema.application.primitive.skill-list.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.skill-list.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(260), decodeResult: decoder(261) }, + decodeRequest: decoder(271), decodeResult: decoder(272) }, { operation: "skill_view", operationId: "operation.application.skill_view", transport: { kind: "mcp_tool", toolName: "tracedecay_skill_view" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.skill_view.v1", requestSchema: { schemaId: "schema.application.primitive.skill-view.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.skill-view.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(262), decodeResult: decoder(263) }, + decodeRequest: decoder(273), decodeResult: decoder(274) }, { operation: "application_source_body", operationId: "operation.application.source_body", transport: { kind: "http", route: "/application/primitives/source_body", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.source_body.v1", requestSchema: { schemaId: "schema.application.primitive.source-body.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.source-body.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(264), decodeResult: decoder(265), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.source_body.v1", "schema.application.primitive.source-body.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(265)) }, + decodeRequest: decoder(275), decodeResult: decoder(276), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.source_body.v1", "schema.application.primitive.source-body.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(276)) }, { operation: "source_edit_reconcile", operationId: "operation.application.source_edit_reconcile", transport: { kind: "mcp_tool", toolName: "tracedecay_source_edit_reconcile" }, effect: "source_edit", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.source_edit_reconcile.v1", requestSchema: { schemaId: "schema.application.source-edit.reconcile.request", revision: 1 }, resultSchema: { schemaId: "schema.application.source-edit.reconcile.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(266), decodeResult: decoder(10) }, + decodeRequest: decoder(277), decodeResult: decoder(12) }, { operation: "source_edit_rollback", operationId: "operation.application.source_edit_rollback", transport: { kind: "mcp_tool", toolName: "tracedecay_source_edit_rollback" }, effect: "source_edit", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.source_edit_rollback.v1", requestSchema: { schemaId: "schema.application.source-edit.rollback.request", revision: 1 }, resultSchema: { schemaId: "schema.application.source-edit.rollback.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(267), decodeResult: decoder(10) }, + decodeRequest: decoder(278), decodeResult: decoder(12) }, { operation: "application_source_lines", operationId: "operation.application.source_lines", transport: { kind: "http", route: "/application/primitives/source_lines", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.source_lines.v1", requestSchema: { schemaId: "schema.application.primitive.source-lines.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.source-lines.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(268), decodeResult: decoder(269), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.source_lines.v1", "schema.application.primitive.source-lines.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(269)) }, + decodeRequest: decoder(279), decodeResult: decoder(280), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.source_lines.v1", "schema.application.primitive.source-lines.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(280)) }, { operation: "application_source_outline", operationId: "operation.application.source_outline", transport: { kind: "http", route: "/application/primitives/source_outline", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.source_outline.v1", requestSchema: { schemaId: "schema.application.primitive.source-outline.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.source-outline.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(270), decodeResult: decoder(271), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.source_outline.v1", "schema.application.primitive.source-outline.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(271)) }, + decodeRequest: decoder(281), decodeResult: decoder(282), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.source_outline.v1", "schema.application.primitive.source-outline.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(282)) }, { operation: "stack_snapshot", operationId: "operation.application.stack_snapshot", transport: { kind: "mcp_tool", toolName: "tracedecay_stack_snapshot" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.stack_snapshot.v1", requestSchema: { schemaId: "schema.application.native-integration.stack-snapshot.request", revision: 1 }, resultSchema: { schemaId: "schema.application.native-integration.stack-snapshot.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(272), decodeResult: decoder(7) }, + decodeRequest: decoder(283), decodeResult: decoder(9) }, + { operation: "status", operationId: "operation.application.status", transport: { kind: "mcp_tool", toolName: "tracedecay_status" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.status.v1", + requestSchema: { schemaId: "schema.application.primitive.status.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.status.result", revision: 1 }, + cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], + decodeRequest: decoder(284), decodeResult: decoder(285) }, { operation: "application_storage_status", operationId: "operation.application.storage_status", transport: { kind: "http", route: "/application/primitives/storage_status", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.storage_status.v1", requestSchema: { schemaId: "schema.application.primitive.storage-status.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.storage-status.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(273), decodeResult: decoder(274), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.storage_status.v1", "schema.application.primitive.storage-status.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(274)) }, + decodeRequest: decoder(286), decodeResult: decoder(287), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.storage_status.v1", "schema.application.primitive.storage-status.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(287)) }, { operation: "str_replace", operationId: "operation.application.str_replace", transport: { kind: "mcp_tool", toolName: "tracedecay_str_replace" }, effect: "source_edit", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.str_replace.v1", requestSchema: { schemaId: "schema.application.source-edit.str-replace.request", revision: 1 }, resultSchema: { schemaId: "schema.application.source-edit.str-replace.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(275), decodeResult: decoder(10) }, + decodeRequest: decoder(288), decodeResult: decoder(12) }, { operation: "test_map", operationId: "operation.application.test_map", transport: { kind: "mcp_tool", toolName: "tracedecay_test_map" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.test_map.v1", requestSchema: { schemaId: "schema.application.primitive.test-map.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.test-map.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(276), decodeResult: decoder(277) }, + decodeRequest: decoder(289), decodeResult: decoder(290) }, { operation: "application_test_results", operationId: "operation.application.test_results", transport: { kind: "http", route: "/application/tests/results", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.test_results.v1", requestSchema: { schemaId: "schema.application.feedback.test-results.request", revision: 1 }, resultSchema: { schemaId: "schema.application.feedback.test-results.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":15000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(278), decodeResult: decoder(279), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.test_results.v1", "schema.application.feedback.test-results.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(279)) }, + decodeRequest: decoder(291), decodeResult: decoder(292), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.test_results.v1", "schema.application.feedback.test-results.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(292)) }, { operation: "test_risk", operationId: "operation.application.test_risk", transport: { kind: "mcp_tool", toolName: "tracedecay_test_risk" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.test_risk.v1", requestSchema: { schemaId: "schema.application.primitive.test-risk.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.test-risk.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(280), decodeResult: decoder(281) }, + decodeRequest: decoder(293), decodeResult: decoder(294) }, { operation: "todos", operationId: "operation.application.todos", transport: { kind: "mcp_tool", toolName: "tracedecay_todos" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.todos.v1", requestSchema: { schemaId: "schema.application.primitive.todos.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.todos.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":10000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(282), decodeResult: decoder(283) }, + decodeRequest: decoder(295), decodeResult: decoder(296) }, { operation: "unmounted_files", operationId: "operation.application.unmounted_files", transport: { kind: "mcp_tool", toolName: "tracedecay_unmounted_files" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.unmounted_files.v1", requestSchema: { schemaId: "schema.application.primitive.unmounted-files.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.unmounted-files.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(284), decodeResult: decoder(285) }, + decodeRequest: decoder(297), decodeResult: decoder(298) }, { operation: "unsafe_patterns", operationId: "operation.application.unsafe_patterns", transport: { kind: "mcp_tool", toolName: "tracedecay_unsafe_patterns" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.mcp.unsafe_patterns.v1", requestSchema: { schemaId: "schema.application.primitive.unsafe-patterns.request", revision: 1 }, resultSchema: { schemaId: "schema.application.primitive.unsafe-patterns.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":120000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(286), decodeResult: decoder(287) }, + decodeRequest: decoder(299), decodeResult: decoder(300) }, { operation: "application_workflows", operationId: "operation.application.workflows", transport: { kind: "http", route: "/application/retained/workflows", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflows.v1", requestSchema: { schemaId: "schema.application.retained.workflows.request", revision: 1 }, resultSchema: { schemaId: "schema.application.retained.workflows.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","unavailable","partial"], - decodeRequest: decoder(288), decodeResult: decoder(289), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflows.v1", "schema.application.retained.workflows.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(289)) }, + decodeRequest: decoder(301), decodeResult: decoder(302), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflows.v1", "schema.application.retained.workflows.result", 1, ["completed","cancelled","timed_out","failed","unavailable","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(302)) }, { operation: "application_worktree_cleanup_confirm", operationId: "operation.application.worktree_cleanup_confirm", transport: { kind: "http", route: "/application/native-integration/worktree_cleanup_confirm", method: "POST" }, effect: "preview", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.worktree_cleanup_confirm.v1", requestSchema: { schemaId: "schema.application.native-integration.worktree-cleanup-confirm.request", revision: 1 }, resultSchema: { schemaId: "schema.application.native-integration.worktree-cleanup-confirm.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(290), decodeResult: decoder(7), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.worktree_cleanup_confirm.v1", "schema.application.native-integration.worktree-cleanup-confirm.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(7)) }, + decodeRequest: decoder(303), decodeResult: decoder(9), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.worktree_cleanup_confirm.v1", "schema.application.native-integration.worktree-cleanup-confirm.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(9)) }, { operation: "application_worktree_cleanup_inspect", operationId: "operation.application.worktree_cleanup_inspect", transport: { kind: "http", route: "/application/native-integration/worktree_cleanup_inspect", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.worktree_cleanup_inspect.v1", requestSchema: { schemaId: "schema.application.native-integration.worktree-cleanup-inspect.request", revision: 1 }, resultSchema: { schemaId: "schema.application.native-integration.worktree-cleanup-inspect.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(291), decodeResult: decoder(7), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.worktree_cleanup_inspect.v1", "schema.application.native-integration.worktree-cleanup-inspect.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(7)) }, + decodeRequest: decoder(304), decodeResult: decoder(9), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.worktree_cleanup_inspect.v1", "schema.application.native-integration.worktree-cleanup-inspect.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(9)) }, { operation: "application_worktree_cleanup_reconcile", operationId: "operation.application.worktree_cleanup_reconcile", transport: { kind: "http", route: "/application/native-integration/worktree_cleanup_reconcile", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.worktree_cleanup_reconcile.v1", requestSchema: { schemaId: "schema.application.native-integration.worktree-cleanup-reconcile.request", revision: 1 }, resultSchema: { schemaId: "schema.application.native-integration.worktree-cleanup-reconcile.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(292), decodeResult: decoder(7), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.worktree_cleanup_reconcile.v1", "schema.application.native-integration.worktree-cleanup-reconcile.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(7)) }, + decodeRequest: decoder(305), decodeResult: decoder(9), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.worktree_cleanup_reconcile.v1", "schema.application.native-integration.worktree-cleanup-reconcile.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(9)) }, { operation: "application_worktree_cleanup_remove", operationId: "operation.application.worktree_cleanup_remove", transport: { kind: "http", route: "/application/native-integration/worktree_cleanup_remove", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.worktree_cleanup_remove.v1", requestSchema: { schemaId: "schema.application.native-integration.worktree-cleanup-remove.request", revision: 1 }, resultSchema: { schemaId: "schema.application.native-integration.worktree-cleanup-remove.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(293), decodeResult: decoder(7), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.worktree_cleanup_remove.v1", "schema.application.native-integration.worktree-cleanup-remove.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(7)) }, + decodeRequest: decoder(306), decodeResult: decoder(9), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.worktree_cleanup_remove.v1", "schema.application.native-integration.worktree-cleanup-remove.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(9)) }, { operation: "application_worktree_inventory", operationId: "operation.application.worktree_inventory", transport: { kind: "http", route: "/application/native-integration/worktree_inventory", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.worktree_inventory.v1", requestSchema: { schemaId: "schema.application.native-integration.worktree-inventory.request", revision: 1 }, resultSchema: { schemaId: "schema.application.native-integration.worktree-inventory.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(294), decodeResult: decoder(7), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.worktree_inventory.v1", "schema.application.native-integration.worktree-inventory.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(7)) }, + decodeRequest: decoder(307), decodeResult: decoder(9), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.worktree_inventory.v1", "schema.application.native-integration.worktree-inventory.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(9)) }, { operation: "handoff_issue_task_handoff", operationId: "operation.handoff.issue_task_handoff", transport: { kind: "http", route: "/application/handoff/issue-task", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.handoff.issue_task_handoff", requestSchema: { schemaId: "schema.handoff.issue_task_handoff.request", revision: 1 }, resultSchema: { schemaId: "schema.handoff.issue_task_handoff.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(295), decodeResult: decoder(296), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.handoff.issue_task_handoff", "schema.handoff.issue_task_handoff.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(296)) }, + decodeRequest: decoder(308), decodeResult: decoder(309), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.handoff.issue_task_handoff", "schema.handoff.issue_task_handoff.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(309)) }, { operation: "handoff_list_task_handoffs", operationId: "operation.handoff.list_task_handoffs", transport: { kind: "http", route: "/application/handoff/list-task", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.handoff.list_task_handoffs", requestSchema: { schemaId: "schema.handoff.list_task_handoffs.request", revision: 1 }, resultSchema: { schemaId: "schema.handoff.list_task_handoffs.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","timed_out","failed","partial"], - decodeRequest: decoder(297), decodeResult: decoder(298), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.handoff.list_task_handoffs", "schema.handoff.list_task_handoffs.result", 1, ["completed","timed_out","failed","partial"], {"mode":"not_cancellable"}, "operation", "not_required", decoder(298)) }, + decodeRequest: decoder(310), decodeResult: decoder(311), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.handoff.list_task_handoffs", "schema.handoff.list_task_handoffs.result", 1, ["completed","timed_out","failed","partial"], {"mode":"not_cancellable"}, "operation", "not_required", decoder(311)) }, { operation: "handoff_open_investigation_handoff", operationId: "operation.handoff.open_investigation_handoff", transport: { kind: "http", route: "/application/handoff/open-investigation", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.handoff.open_investigation_handoff", requestSchema: { schemaId: "schema.handoff.open_investigation_handoff.request", revision: 1 }, resultSchema: { schemaId: "schema.handoff.open_investigation_handoff.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(299), decodeResult: decoder(300), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.handoff.open_investigation_handoff", "schema.handoff.open_investigation_handoff.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(300)) }, + decodeRequest: decoder(312), decodeResult: decoder(313), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.handoff.open_investigation_handoff", "schema.handoff.open_investigation_handoff.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(313)) }, { operation: "handoff_open_task_handoff", operationId: "operation.handoff.open_task_handoff", transport: { kind: "http", route: "/application/handoff/open-task", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.handoff.open_task_handoff", requestSchema: { schemaId: "schema.handoff.open_task_handoff.request", revision: 1 }, resultSchema: { schemaId: "schema.handoff.open_task_handoff.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(301), decodeResult: decoder(302), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.handoff.open_task_handoff", "schema.handoff.open_task_handoff.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(302)) }, + decodeRequest: decoder(314), decodeResult: decoder(315), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.handoff.open_task_handoff", "schema.handoff.open_task_handoff.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(315)) }, { operation: "multi_root_execute", operationId: "operation.multi_root.execute", transport: { kind: "http", route: "/application/multi-root/execute", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.multi_root.execute.v1", requestSchema: { schemaId: "schema.tracedecay.multi-root.execute-request.v1", revision: 1 }, resultSchema: { schemaId: "schema.tracedecay.multi-root.execute-result.v1", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(303), decodeResult: decoder(304), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.multi_root.execute.v1", "schema.tracedecay.multi-root.execute-result.v1", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(304)) }, + decodeRequest: decoder(316), decodeResult: decoder(317), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.multi_root.execute.v1", "schema.tracedecay.multi-root.execute-result.v1", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(317)) }, { operation: "multi_root_scope_set_compare_and_swap", operationId: "operation.multi_root.scope_set_compare_and_swap", transport: { kind: "http", route: "/application/multi-root/scope-set/compare-and-swap", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.multi_root.scope_set_compare_and_swap.v1", requestSchema: { schemaId: "schema.tracedecay.multi-root.scope-set-compare-and-swap-request.v1", revision: 1 }, resultSchema: { schemaId: "schema.tracedecay.multi-root.scope-set-compare-and-swap-result.v1", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(305), decodeResult: decoder(306), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.multi_root.scope_set_compare_and_swap.v1", "schema.tracedecay.multi-root.scope-set-compare-and-swap-result.v1", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(306)) }, + decodeRequest: decoder(318), decodeResult: decoder(319), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.multi_root.scope_set_compare_and_swap.v1", "schema.tracedecay.multi-root.scope-set-compare-and-swap-result.v1", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(319)) }, { operation: "multi_root_scope_set_read", operationId: "operation.multi_root.scope_set_read", transport: { kind: "http", route: "/application/multi-root/scope-set/read", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.multi_root.scope_set_read.v1", requestSchema: { schemaId: "schema.tracedecay.multi-root.scope-set-read-request.v1", revision: 1 }, resultSchema: { schemaId: "schema.tracedecay.multi-root.scope-set-read-result.v1", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(307), decodeResult: decoder(308), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.multi_root.scope_set_read.v1", "schema.tracedecay.multi-root.scope-set-read-result.v1", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(308)) }, + decodeRequest: decoder(320), decodeResult: decoder(321), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.multi_root.scope_set_read.v1", "schema.tracedecay.multi-root.scope-set-read-result.v1", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(321)) }, { operation: "work_accept_proposal", operationId: "operation.work.accept_proposal", transport: { kind: "http", route: "/application/work/accept-proposal", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.accept_proposal", requestSchema: { schemaId: "schema.work.accept_proposal.request", revision: 1 }, resultSchema: { schemaId: "schema.work.accept_proposal.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(309), decodeResult: decoder(310), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.accept_proposal", "schema.work.accept_proposal.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(310)) }, + decodeRequest: decoder(322), decodeResult: decoder(323), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.accept_proposal", "schema.work.accept_proposal.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(323)) }, { operation: "work_adjudicate_duplicate", operationId: "operation.work.adjudicate_duplicate", transport: { kind: "http", route: "/application/work/adjudicate-duplicate", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.adjudicate_duplicate", requestSchema: { schemaId: "schema.work.adjudicate_duplicate.request", revision: 1 }, resultSchema: { schemaId: "schema.work.adjudicate_duplicate.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(311), decodeResult: decoder(312), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.adjudicate_duplicate", "schema.work.adjudicate_duplicate.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(312)) }, + decodeRequest: decoder(324), decodeResult: decoder(325), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.adjudicate_duplicate", "schema.work.adjudicate_duplicate.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(325)) }, { operation: "work_adjudicate_leak", operationId: "operation.work.adjudicate_leak", transport: { kind: "http", route: "/application/work/adjudicate-leak", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.adjudicate_leak", requestSchema: { schemaId: "schema.work.adjudicate_leak.request", revision: 1 }, resultSchema: { schemaId: "schema.work.adjudicate_leak.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(313), decodeResult: decoder(314), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.adjudicate_leak", "schema.work.adjudicate_leak.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(314)) }, + decodeRequest: decoder(326), decodeResult: decoder(327), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.adjudicate_leak", "schema.work.adjudicate_leak.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(327)) }, { operation: "work_admit_execution", operationId: "operation.work.admit_execution", transport: { kind: "http", route: "/application/work/admit-execution", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.admit_execution", requestSchema: { schemaId: "schema.work.admit_execution.request", revision: 1 }, resultSchema: { schemaId: "schema.work.admit_execution.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(315), decodeResult: decoder(316), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.admit_execution", "schema.work.admit_execution.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(316)) }, + decodeRequest: decoder(328), decodeResult: decoder(329), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.admit_execution", "schema.work.admit_execution.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(329)) }, { operation: "work_admit_placement", operationId: "operation.work.admit_placement", transport: { kind: "http", route: "/application/work/admit-placement", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.admit_placement", requestSchema: { schemaId: "schema.work.admit_placement.request", revision: 1 }, resultSchema: { schemaId: "schema.work.admit_placement.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(317), decodeResult: decoder(318), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.admit_placement", "schema.work.admit_placement.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(318)) }, + decodeRequest: decoder(330), decodeResult: decoder(331), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.admit_placement", "schema.work.admit_placement.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(331)) }, { operation: "work_attempt_status", operationId: "operation.work.attempt_status", transport: { kind: "http", route: "/application/work/attempt-status", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.attempt_status", requestSchema: { schemaId: "schema.work.attempt_status.request", revision: 1 }, resultSchema: { schemaId: "schema.work.attempt_status.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(319), decodeResult: decoder(320), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.attempt_status", "schema.work.attempt_status.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(320)) }, + decodeRequest: decoder(332), decodeResult: decoder(333), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.attempt_status", "schema.work.attempt_status.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(333)) }, { operation: "work_cancel_attempt", operationId: "operation.work.cancel_attempt", transport: { kind: "http", route: "/application/work/cancel-attempt", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.cancel_attempt", requestSchema: { schemaId: "schema.work.cancel_attempt.request", revision: 1 }, resultSchema: { schemaId: "schema.work.cancel_attempt.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(321), decodeResult: decoder(320), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.cancel_attempt", "schema.work.cancel_attempt.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(320)) }, + decodeRequest: decoder(334), decodeResult: decoder(333), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.cancel_attempt", "schema.work.cancel_attempt.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(333)) }, { operation: "work_compare_proposal", operationId: "operation.work.compare_proposal", transport: { kind: "http", route: "/application/work/compare-proposal", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.compare_proposal", requestSchema: { schemaId: "schema.work.compare_proposal.request", revision: 1 }, resultSchema: { schemaId: "schema.work.compare_proposal.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(322), decodeResult: decoder(323), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.compare_proposal", "schema.work.compare_proposal.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(323)) }, + decodeRequest: decoder(335), decodeResult: decoder(336), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.compare_proposal", "schema.work.compare_proposal.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(336)) }, { operation: "work_create", operationId: "operation.work.create", transport: { kind: "http", route: "/application/work/create", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.create", requestSchema: { schemaId: "schema.work.create.request", revision: 1 }, resultSchema: { schemaId: "schema.work.create.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(324), decodeResult: decoder(310), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.create", "schema.work.create.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(310)) }, + decodeRequest: decoder(337), decodeResult: decoder(323), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.create", "schema.work.create.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(323)) }, { operation: "work_execution_history", operationId: "operation.work.execution_history", transport: { kind: "http", route: "/application/work/execution-history", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.execution_history", requestSchema: { schemaId: "schema.work.execution_history.request", revision: 1 }, resultSchema: { schemaId: "schema.work.execution_history.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(325), decodeResult: decoder(326), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.execution_history", "schema.work.execution_history.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(326)) }, + decodeRequest: decoder(338), decodeResult: decoder(339), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.execution_history", "schema.work.execution_history.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(339)) }, { operation: "work_experience", operationId: "operation.work.experience", transport: { kind: "http", route: "/application/work/experience", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.experience", requestSchema: { schemaId: "schema.work.experience.request", revision: 1 }, resultSchema: { schemaId: "schema.work.experience.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(327), decodeResult: decoder(328), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.experience", "schema.work.experience.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(328)) }, + decodeRequest: decoder(340), decodeResult: decoder(341), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.experience", "schema.work.experience.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(341)) }, { operation: "work_generate_proposal", operationId: "operation.work.generate_proposal", transport: { kind: "http", route: "/application/work/generate-proposal", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.generate_proposal", requestSchema: { schemaId: "schema.work.generate_proposal.request", revision: 1 }, resultSchema: { schemaId: "schema.work.generate_proposal.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(329), decodeResult: decoder(330), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.generate_proposal", "schema.work.generate_proposal.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(330)) }, + decodeRequest: decoder(342), decodeResult: decoder(343), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.generate_proposal", "schema.work.generate_proposal.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(343)) }, { operation: "work_hydrate_artifacts", operationId: "operation.work.hydrate_artifacts", transport: { kind: "http", route: "/application/work/hydrate-artifacts", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.hydrate_artifacts", requestSchema: { schemaId: "schema.work.hydrate_artifacts.request", revision: 1 }, resultSchema: { schemaId: "schema.work.hydrate_artifacts.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(331), decodeResult: decoder(332), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.hydrate_artifacts", "schema.work.hydrate_artifacts.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(332)) }, + decodeRequest: decoder(344), decodeResult: decoder(345), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.hydrate_artifacts", "schema.work.hydrate_artifacts.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(345)) }, { operation: "work_list_attempts", operationId: "operation.work.list_attempts", transport: { kind: "http", route: "/application/work/list-attempts", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.list_attempts", requestSchema: { schemaId: "schema.work.list_attempts.request", revision: 1 }, resultSchema: { schemaId: "schema.work.list_attempts.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(325), decodeResult: decoder(333), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.list_attempts", "schema.work.list_attempts.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(333)) }, + decodeRequest: decoder(338), decodeResult: decoder(346), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.list_attempts", "schema.work.list_attempts.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(346)) }, { operation: "work_mutate_graph", operationId: "operation.work.mutate_graph", transport: { kind: "http", route: "/application/work/mutate-graph", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.mutate_graph", requestSchema: { schemaId: "schema.work.mutate_graph.request", revision: 1 }, resultSchema: { schemaId: "schema.work.mutate_graph.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(334), decodeResult: decoder(310), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.mutate_graph", "schema.work.mutate_graph.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(310)) }, + decodeRequest: decoder(347), decodeResult: decoder(323), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.mutate_graph", "schema.work.mutate_graph.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(323)) }, { operation: "work_pause_run", operationId: "operation.work.pause_run", transport: { kind: "http", route: "/application/work/pause-run", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.pause_run", requestSchema: { schemaId: "schema.work.pause_run.request", revision: 1 }, resultSchema: { schemaId: "schema.work.pause_run.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(335), decodeResult: decoder(336), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.pause_run", "schema.work.pause_run.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(336)) }, + decodeRequest: decoder(348), decodeResult: decoder(349), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.pause_run", "schema.work.pause_run.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(349)) }, { operation: "work_placement_preflight", operationId: "operation.work.placement_preflight", transport: { kind: "http", route: "/application/work/placement-preflight", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.placement_preflight", requestSchema: { schemaId: "schema.work.placement_preflight.request", revision: 1 }, resultSchema: { schemaId: "schema.work.placement_preflight.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(337), decodeResult: decoder(338), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.placement_preflight", "schema.work.placement_preflight.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(338)) }, + decodeRequest: decoder(350), decodeResult: decoder(351), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.placement_preflight", "schema.work.placement_preflight.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(351)) }, { operation: "work_placement_status", operationId: "operation.work.placement_status", transport: { kind: "http", route: "/application/work/placement-status", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.placement_status", requestSchema: { schemaId: "schema.work.placement_status.request", revision: 1 }, resultSchema: { schemaId: "schema.work.placement_status.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(339), decodeResult: decoder(340), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.placement_status", "schema.work.placement_status.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(340)) }, + decodeRequest: decoder(352), decodeResult: decoder(353), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.placement_status", "schema.work.placement_status.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(353)) }, { operation: "work_prepare_duplicate_adjudication", operationId: "operation.work.prepare_duplicate_adjudication", transport: { kind: "http", route: "/application/work/prepare-duplicate-adjudication", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.prepare_duplicate_adjudication", requestSchema: { schemaId: "schema.work.prepare_duplicate_adjudication.request", revision: 1 }, resultSchema: { schemaId: "schema.work.prepare_duplicate_adjudication.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(341), decodeResult: decoder(311), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.prepare_duplicate_adjudication", "schema.work.prepare_duplicate_adjudication.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(311)) }, + decodeRequest: decoder(354), decodeResult: decoder(324), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.prepare_duplicate_adjudication", "schema.work.prepare_duplicate_adjudication.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(324)) }, { operation: "work_prepare_graph_mutation", operationId: "operation.work.prepare_graph_mutation", transport: { kind: "http", route: "/application/work/prepare-graph-mutation", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.prepare_graph_mutation", requestSchema: { schemaId: "schema.work.prepare_graph_mutation.request", revision: 1 }, resultSchema: { schemaId: "schema.work.prepare_graph_mutation.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(342), decodeResult: decoder(334), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.prepare_graph_mutation", "schema.work.prepare_graph_mutation.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(334)) }, + decodeRequest: decoder(355), decodeResult: decoder(347), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.prepare_graph_mutation", "schema.work.prepare_graph_mutation.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(347)) }, { operation: "work_release_placement", operationId: "operation.work.release_placement", transport: { kind: "http", route: "/application/work/release-placement", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.release_placement", requestSchema: { schemaId: "schema.work.release_placement.request", revision: 1 }, resultSchema: { schemaId: "schema.work.release_placement.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(343), decodeResult: decoder(318), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.release_placement", "schema.work.release_placement.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(318)) }, + decodeRequest: decoder(356), decodeResult: decoder(331), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.release_placement", "schema.work.release_placement.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(331)) }, { operation: "work_resume_attempts", operationId: "operation.work.resume_attempts", transport: { kind: "http", route: "/application/work/resume-attempts", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.resume_attempts", requestSchema: { schemaId: "schema.work.resume_attempts.request", revision: 1 }, resultSchema: { schemaId: "schema.work.resume_attempts.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(344), decodeResult: decoder(345), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.resume_attempts", "schema.work.resume_attempts.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(345)) }, + decodeRequest: decoder(357), decodeResult: decoder(358), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.resume_attempts", "schema.work.resume_attempts.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(358)) }, { operation: "work_resume_run", operationId: "operation.work.resume_run", transport: { kind: "http", route: "/application/work/resume-run", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.resume_run", requestSchema: { schemaId: "schema.work.resume_run.request", revision: 1 }, resultSchema: { schemaId: "schema.work.resume_run.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(346), decodeResult: decoder(336), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.resume_run", "schema.work.resume_run.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(336)) }, + decodeRequest: decoder(359), decodeResult: decoder(349), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.resume_run", "schema.work.resume_run.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(349)) }, { operation: "work_retrieve_evidence", operationId: "operation.work.retrieve_evidence", transport: { kind: "http", route: "/application/work/retrieve-evidence", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.retrieve_evidence", requestSchema: { schemaId: "schema.work.retrieve_evidence.request", revision: 1 }, resultSchema: { schemaId: "schema.work.retrieve_evidence.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(347), decodeResult: decoder(348), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.retrieve_evidence", "schema.work.retrieve_evidence.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(348)) }, + decodeRequest: decoder(360), decodeResult: decoder(361), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.retrieve_evidence", "schema.work.retrieve_evidence.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(361)) }, { operation: "work_retry_attempt", operationId: "operation.work.retry_attempt", transport: { kind: "http", route: "/application/work/retry-attempt", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.retry_attempt", requestSchema: { schemaId: "schema.work.retry_attempt.request", revision: 1 }, resultSchema: { schemaId: "schema.work.retry_attempt.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(349), decodeResult: decoder(350), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.retry_attempt", "schema.work.retry_attempt.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(350)) }, + decodeRequest: decoder(362), decodeResult: decoder(363), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.retry_attempt", "schema.work.retry_attempt.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(363)) }, { operation: "work_review_proposal", operationId: "operation.work.review_proposal", transport: { kind: "http", route: "/application/work/review-proposal", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.review_proposal", requestSchema: { schemaId: "schema.work.review_proposal.request", revision: 1 }, resultSchema: { schemaId: "schema.work.review_proposal.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(351), decodeResult: decoder(310), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.review_proposal", "schema.work.review_proposal.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(310)) }, + decodeRequest: decoder(364), decodeResult: decoder(323), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.review_proposal", "schema.work.review_proposal.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(323)) }, { operation: "work_run_control", operationId: "operation.work.run_control", transport: { kind: "http", route: "/application/work/run-control", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.run_control", requestSchema: { schemaId: "schema.work.run_control.request", revision: 1 }, resultSchema: { schemaId: "schema.work.run_control.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(352), decodeResult: decoder(353), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.run_control", "schema.work.run_control.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(353)) }, + decodeRequest: decoder(365), decodeResult: decoder(366), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.run_control", "schema.work.run_control.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(366)) }, { operation: "work_start_attempt", operationId: "operation.work.start_attempt", transport: { kind: "http", route: "/application/work/start-attempt", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.start_attempt", requestSchema: { schemaId: "schema.work.start_attempt.request", revision: 1 }, resultSchema: { schemaId: "schema.work.start_attempt.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(354), decodeResult: decoder(320), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.start_attempt", "schema.work.start_attempt.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(320)) }, + decodeRequest: decoder(367), decodeResult: decoder(333), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.start_attempt", "schema.work.start_attempt.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(333)) }, { operation: "work_synthesize", operationId: "operation.work.synthesize", transport: { kind: "http", route: "/application/work/synthesize", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.synthesize", requestSchema: { schemaId: "schema.work.synthesize.request", revision: 1 }, resultSchema: { schemaId: "schema.work.synthesize.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","cancelled","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(355), decodeResult: decoder(356), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.synthesize", "schema.work.synthesize.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(356)) }, + decodeRequest: decoder(368), decodeResult: decoder(369), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.synthesize", "schema.work.synthesize.result", 1, ["completed","cancelled","timed_out","failed","effect_unknown","partial"], {"mode":"cooperative","points":["before_admission","before_effect","effect_in_flight","after_commit"]}, "durable_effect", "required", decoder(369)) }, { operation: "work_topology", operationId: "operation.work.topology", transport: { kind: "http", route: "/application/work/topology", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.topology", requestSchema: { schemaId: "schema.work.topology.request", revision: 1 }, resultSchema: { schemaId: "schema.work.topology.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(357), decodeResult: decoder(358), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.topology", "schema.work.topology.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(358)) }, + decodeRequest: decoder(370), decodeResult: decoder(371), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.topology", "schema.work.topology.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(371)) }, { operation: "work_topology_metrics", operationId: "operation.work.topology_metrics", transport: { kind: "http", route: "/application/work/topology-metrics", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.topology_metrics", requestSchema: { schemaId: "schema.work.topology_metrics.request", revision: 1 }, resultSchema: { schemaId: "schema.work.topology_metrics.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(359), decodeResult: decoder(360), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.topology_metrics", "schema.work.topology_metrics.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(360)) }, + decodeRequest: decoder(372), decodeResult: decoder(373), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.topology_metrics", "schema.work.topology_metrics.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(373)) }, { operation: "work_views", operationId: "operation.work.views", transport: { kind: "http", route: "/application/work/views", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.work.views", requestSchema: { schemaId: "schema.work.views.request", revision: 1 }, resultSchema: { schemaId: "schema.work.views.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(361), decodeResult: decoder(362), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.views", "schema.work.views.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(362)) }, + decodeRequest: decoder(374), decodeResult: decoder(375), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.work.views", "schema.work.views.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(375)) }, { operation: "workflow_activate_definition", operationId: "operation.workflow.activate_definition", transport: { kind: "http", route: "/application/workflow/activate-definition", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.activate_definition", requestSchema: { schemaId: "schema.workflow.activate_definition.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.activate_definition.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(363), decodeResult: decoder(364), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.activate_definition", "schema.workflow.activate_definition.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(364)) }, + decodeRequest: decoder(376), decodeResult: decoder(377), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.activate_definition", "schema.workflow.activate_definition.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(377)) }, { operation: "workflow_cancel_run", operationId: "operation.workflow.cancel_run", transport: { kind: "http", route: "/application/workflow/cancel-run", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.cancel_run", requestSchema: { schemaId: "schema.workflow.cancel_run.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.cancel_run.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(365), decodeResult: decoder(366), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.cancel_run", "schema.workflow.cancel_run.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(366)) }, + decodeRequest: decoder(378), decodeResult: decoder(379), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.cancel_run", "schema.workflow.cancel_run.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(379)) }, { operation: "workflow_definition_history", operationId: "operation.workflow.definition_history", transport: { kind: "http", route: "/application/workflow/definition-history", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.definition_history", requestSchema: { schemaId: "schema.workflow.definition_history.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.definition_history.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(367), decodeResult: decoder(368), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.definition_history", "schema.workflow.definition_history.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(368)) }, + decodeRequest: decoder(380), decodeResult: decoder(381), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.definition_history", "schema.workflow.definition_history.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(381)) }, { operation: "workflow_diff_definition", operationId: "operation.workflow.diff_definition", transport: { kind: "http", route: "/application/workflow/diff-definition", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.diff_definition", requestSchema: { schemaId: "schema.workflow.diff_definition.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.diff_definition.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(369), decodeResult: decoder(370), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.diff_definition", "schema.workflow.diff_definition.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(370)) }, + decodeRequest: decoder(382), decodeResult: decoder(383), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.diff_definition", "schema.workflow.diff_definition.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(383)) }, { operation: "workflow_get_definition", operationId: "operation.workflow.get_definition", transport: { kind: "http", route: "/application/workflow/get-definition", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.get_definition", requestSchema: { schemaId: "schema.workflow.get_definition.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.get_definition.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(371), decodeResult: decoder(372), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.get_definition", "schema.workflow.get_definition.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(372)) }, + decodeRequest: decoder(384), decodeResult: decoder(385), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.get_definition", "schema.workflow.get_definition.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(385)) }, { operation: "workflow_get_run", operationId: "operation.workflow.get_run", transport: { kind: "http", route: "/application/workflow/get-run", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.get_run", requestSchema: { schemaId: "schema.workflow.get_run.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.get_run.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(373), decodeResult: decoder(366), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.get_run", "schema.workflow.get_run.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(366)) }, + decodeRequest: decoder(386), decodeResult: decoder(379), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.get_run", "schema.workflow.get_run.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(379)) }, { operation: "workflow_handoff_issue", operationId: "operation.workflow.handoff_issue", transport: { kind: "http", route: "/application/workflow/handoff-issue", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.handoff_issue", requestSchema: { schemaId: "schema.workflow.handoff_issue.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.handoff_issue.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(374), decodeResult: decoder(375), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.handoff_issue", "schema.workflow.handoff_issue.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(375)) }, + decodeRequest: decoder(387), decodeResult: decoder(388), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.handoff_issue", "schema.workflow.handoff_issue.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(388)) }, { operation: "workflow_handoff_redeem", operationId: "operation.workflow.handoff_redeem", transport: { kind: "http", route: "/application/workflow/handoff-redeem", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.handoff_redeem", requestSchema: { schemaId: "schema.workflow.handoff_redeem.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.handoff_redeem.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(376), decodeResult: decoder(377), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.handoff_redeem", "schema.workflow.handoff_redeem.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(377)) }, + decodeRequest: decoder(389), decodeResult: decoder(390), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.handoff_redeem", "schema.workflow.handoff_redeem.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(390)) }, { operation: "workflow_list_definitions", operationId: "operation.workflow.list_definitions", transport: { kind: "http", route: "/application/workflow/list-definitions", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.list_definitions", requestSchema: { schemaId: "schema.workflow.list_definitions.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.list_definitions.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(378), decodeResult: decoder(368), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.list_definitions", "schema.workflow.list_definitions.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(368)) }, + decodeRequest: decoder(391), decodeResult: decoder(381), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.list_definitions", "schema.workflow.list_definitions.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(381)) }, { operation: "workflow_pause_run", operationId: "operation.workflow.pause_run", transport: { kind: "http", route: "/application/workflow/pause-run", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.pause_run", requestSchema: { schemaId: "schema.workflow.pause_run.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.pause_run.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(379), decodeResult: decoder(366), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.pause_run", "schema.workflow.pause_run.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(366)) }, + decodeRequest: decoder(392), decodeResult: decoder(379), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.pause_run", "schema.workflow.pause_run.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(379)) }, { operation: "workflow_register_definition", operationId: "operation.workflow.register_definition", transport: { kind: "http", route: "/application/workflow/register-definition", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.register_definition", requestSchema: { schemaId: "schema.workflow.register_definition.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.register_definition.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(380), decodeResult: decoder(372), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.register_definition", "schema.workflow.register_definition.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(372)) }, + decodeRequest: decoder(393), decodeResult: decoder(385), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.register_definition", "schema.workflow.register_definition.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(385)) }, { operation: "workflow_reject_definition", operationId: "operation.workflow.reject_definition", transport: { kind: "http", route: "/application/workflow/reject-definition", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.reject_definition", requestSchema: { schemaId: "schema.workflow.reject_definition.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.reject_definition.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(381), decodeResult: decoder(364), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.reject_definition", "schema.workflow.reject_definition.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(364)) }, + decodeRequest: decoder(394), decodeResult: decoder(377), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.reject_definition", "schema.workflow.reject_definition.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(377)) }, { operation: "workflow_resume_run", operationId: "operation.workflow.resume_run", transport: { kind: "http", route: "/application/workflow/resume-run", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.resume_run", requestSchema: { schemaId: "schema.workflow.resume_run.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.resume_run.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(382), decodeResult: decoder(366), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.resume_run", "schema.workflow.resume_run.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(366)) }, + decodeRequest: decoder(395), decodeResult: decoder(379), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.resume_run", "schema.workflow.resume_run.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(379)) }, { operation: "workflow_retire_definition", operationId: "operation.workflow.retire_definition", transport: { kind: "http", route: "/application/workflow/retire-definition", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.retire_definition", requestSchema: { schemaId: "schema.workflow.retire_definition.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.retire_definition.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(383), decodeResult: decoder(364), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.retire_definition", "schema.workflow.retire_definition.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(364)) }, + decodeRequest: decoder(396), decodeResult: decoder(377), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.retire_definition", "schema.workflow.retire_definition.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(377)) }, { operation: "workflow_start_run", operationId: "operation.workflow.start_run", transport: { kind: "http", route: "/application/workflow/start-run", method: "POST" }, effect: "administrative", idempotency: "required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.start_run", requestSchema: { schemaId: "schema.workflow.start_run.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.start_run.result", revision: 1 }, cancellation: {"mode":"not_cancellable"}, deadline: {"behavior":"return_effect_receipt","maximum_millis":30000}, reconciliation: "required", receipt: "durable_effect", terminalStates: ["completed","timed_out","failed","effect_unknown","partial"], - decodeRequest: decoder(384), decodeResult: decoder(366), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.start_run", "schema.workflow.start_run.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(366)) }, + decodeRequest: decoder(397), decodeResult: decoder(379), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.start_run", "schema.workflow.start_run.result", 1, ["completed","timed_out","failed","effect_unknown","partial"], {"mode":"not_cancellable"}, "durable_effect", "required", decoder(379)) }, { operation: "workflow_validate_definition", operationId: "operation.workflow.validate_definition", transport: { kind: "http", route: "/application/workflow/validate-definition", method: "POST" }, effect: "read", idempotency: "not_required", requestIdControl: "server_minted", resultSemantics: "schema_only", bindingId: "binding.http.workflow.validate_definition", requestSchema: { schemaId: "schema.workflow.validate_definition.request", revision: 1 }, resultSchema: { schemaId: "schema.workflow.validate_definition.result", revision: 1 }, cancellation: {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, deadline: {"behavior":"return_operation_receipt","maximum_millis":30000}, reconciliation: "not_required", receipt: "operation", terminalStates: ["completed","cancelled","timed_out","failed","partial"], - decodeRequest: decoder(385), decodeResult: decoder(386), - decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.validate_definition", "schema.workflow.validate_definition.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(386)) }, + decodeRequest: decoder(398), decodeResult: decoder(399), + decodeSuccess: (value: unknown) => decodeHttpSuccessEnvelope(value, "binding.http.workflow.validate_definition", "schema.workflow.validate_definition.result", 1, ["completed","cancelled","timed_out","failed","partial"], {"mode":"cooperative","points":["before_admission","before_read","during_read"]}, "operation", "not_required", decoder(399)) }, ] as const; export type Operation = (typeof OPERATIONS)[number];