Skip to content

simplify(mcp): delete the tool compatibility dispatch layer - #2366

Merged
ScriptedAlchemy merged 5 commits into
masterfrom
fleet/mcp-compat-layer-deletion
Sep 28, 2026
Merged

ScriptedAlchemy merged 5 commits into
masterfrom
fleet/mcp-compat-layer-deletion

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Sep 28, 2026 •

Copy link
Copy Markdown
Owner

BEGIN_COMMIT_OVERRIDE
simplify(mcp)!: delete the tool compatibility dispatch layer (#2366)

BREAKING CHANGE: every tracedecay tool route now connects to the daemon socket named by TRACEDECAY_DAEMON_SOCKET when it is set, instead of the daemon the client profile's authority record names. A missing socket is the typed daemon-unreachable refusal with exit code 69 for every tool (previously typed tools such as status still answered). The MCP generic compatibility fallback is gone: a tool name no typed owner serves is unknown tool.
END_COMMIT_OVERRIDE

This finishes the MCP typed migration. Every public tool group and all four internal admin tools now answer through a typed daemon owner:

This PR deletes the compatibility layer that sat under them.

Deleted

  • LegacyToolCompatibilityOwner and its cached advertised-name set (mcp/tools/mod.rs).
  • The generic fallback in handle_tool_call_with_registry_options. That covers the catalog-binding recheck, the owner admission, the universal-ceiling wrapper, the dead group match, and the boundary freshness trailer. A name no typed owner claims is now unknown tool. The internal branch-add tool is still served by the daemon before MCP dispatch.
  • resolve_catalog_tool_binding. The typed path's resolve_application_binding absorbs the resolve_named_binding helper, which had only that caller left.
    • Kept: validate_current_application_binding. The typed dispatch still calls it (application_surface/dispatch.rs:80) to re-check the binding identity and schemas before execution.
    • Three tests used the removed resolver as a lookup. They now resolve against the composed catalog snapshot or CatalogBindingResolver directly: v2_surface_mount_conformance, native_integration_surface_mount, and the CLI transport-equivalence test.
  • The CLI's dispatch_compatibility_tool and its support code:
    • DaemonToolDispatch::call, tool_timeout_error, map_tool_deadline_error, and print_project_route_problem
    • recover_truncated_mcp_result, reject_tool_result_truncation, and that function's unit test.
    • The fake-daemon tool_cli_skips_daemon_notifications_until_matching_response test and its sentinel daemon. They only exercised tracedecay tool's tools/call transport.
  • The Admin dispatch group, its binding rows, and the internal hook definition. The workstream PRs removed these as each tool moved; rg confirms none remain.

Total: 15 files, +226 / −620.

What replaces the last compat routes

  • Multi-root tools on the CLI. tracedecay tool multi_root_* was the last advertised family on the CLI compat path. It now runs through the typed family executor, as Work and Workflow do, by calling the same handle_multi_root the MCP path uses.
  • The client's daemon socket. The typed tracedecay tool routes connect through the new tracedecay::daemon::invocation_client_for_current_client. It resolves the socket that TRACEDECAY_DAEMON_SOCKET names, the same way the tools/call transport does. A missing socket gives the typed daemon-unreachable refusal and exit code 69, which the Pi extension branches on.
    • Before this change, only the compat route honoured the variable. Typed tools answered from whichever daemon the client profile's authority record named.
  • Conformance for internal operations. v2_surface_mount_conformance now treats internal owner operations as served by name, and fails if one is listed. Since refactor(mcp): serve admin sync through the project owner #2343 it had reported the four internal operations as unmounted.

Fail-before / pass-after

core_cli_suite tool_daemon_test::tool_cli_without_daemon_socket_reports_daemon_unavailable now probes both the multi-root read and an owner-served graph tool (tool status --json) with TRACEDECAY_DAEMON_SOCKET pointing at a missing socket.

On origin/master source (fd10010) with only this test file changed:

panicked at tool_daemon_test.rs:1799:9:
["status", "--json"]: Output { status: ExitStatus(unix_wait_status(0)), stdout: "{\n  \"content\": [ ... \"## Project Status ...\"
  left: Some(0)
 right: Some(69)
test result: FAILED. 0 passed; 1 failed

With this change: ok. Both probes exit 69 with project route error (daemon_connect_down): TraceDecay daemon socket '…/missing.sock' is not available.

rg

$ rg -n 'LegacyToolCompatibilityOwner|resolve_catalog_tool_binding|dispatch_compatibility_tool|compatibility_owned|internal_daemon_tool_definition|dispatch_admin_tools|McpToolDispatchGroup::Admin' --glob '!CHANGELOG*' .
(no output; exit 1)

Runtime journey

Setup: debug tracedecay at this branch's head (b20c6b3), isolated HOME, TRACEDECAY_DATA_DIR, TRACEDECAY_GLOBAL_DB, and XDG_CONFIG_HOME, and one daemon under systemd-run --user --scope -p MemoryMax=6G -p MemorySwapMax=1G. The daemon was stopped afterwards (inactive).

$ tracedecay init .      -> initialized …/corpus/.; daemon code-index reconciliation requested
$ tracedecay sync        -> code-index reconciliation queued via daemon for …/corpus
$ tracedecay current-counter -> 0 ; reset-counter -> Local counter reset (was 0) ; gitignore -> gitignore: on
$ tracedecay projects list   -> `proj_a924467a789819fd` * [primary] branches: main; stores: 1
$ tracedecay gain            -> Tool calls 0, Tokens saved 0
$ tracedecay automation facts list -> {"availability":{"state":"available"},"count":0,...}
$ tracedecay hook-claude-session-start / hook-cursor-session-start / hook-stop < {session_id, cwd}  -> exit 0 each
$ tracedecay tool hook_runtime {ingest_transcript, project} -> status committed, messages_upserted 1, observations_committed 1
$ tracedecay analytics diagnostics -> hook_invoked 3, hook_completed 3; by_tool: tracedecay_hook_runtime 2
tracedecay serve --path corpus:
tools/list: 230 tools   (admin_sync/admin_cli/admin_project/hook_runtime advertised: False)
tracedecay_admin_sync {"format":"json"}                         -> {"project_root":"…/corpus","reconcile_scope":"authoritative_project","status":"queued"}
tracedecay_admin_project {"action":"counter_get"}               -> {"counter":0}
tracedecay_admin_cli {"action":"registry_empty"}                -> {"empty":false}
tracedecay_admin_cli {"action":"registry_empty","project_root":"/x"} -> isError=True, structuredContent.problem.code="application.surface.invalid_request"
tracedecay_multi_root_scope_set_read {"scope_set_id":"scope-set.absent"} -> isError=True, application.problem.code="not_found_or_not_authorized"
$ TRACEDECAY_DAEMON_SOCKET=…/missing.sock tracedecay tool status --json -> exit 69

Checks (local, on fd10010)

  • Full mcp_suite (with the CLI built first; the test process ran outside the 6 GB scope): 588 passed, 0 failed.
  • Full core_cli_suite: 146 passed, 0 failed. tracedecay-cli --bins: 333 passed.
  • Lib tests: tracedecay-mcp 380, tracedecay-tool-catalog 7, tracedecay-daemon-service 322 (the adoption_observation census passed), contracts 429, mcp-catalog 28.
  • Root --lib -- mcp:: daemon::: 735 passed, 0 failed.
  • Acceptance: transport_acceptance_suite v2_surface_mount 2 passed; product_surface_suite native_integration_surface_mount 7 passed.
  • cargo clippy -D warnings --all-targets over tracedecay, mcp, contracts, daemon-protocol, api, mcp-catalog, tool-catalog, cli, daemon-service, and agent-hosts, with and without tracedecay/test-transport,test-helpers: clean.
  • cargo fmt --all -- --check: clean. pnpm run contracts:check: up to date.
  • Windows cross-check: cargo check --workspace --all-targets --target x86_64-pc-windows-gnu --features tracedecay/test-transport,tracedecay/test-helpers,tracedecay-cli/test-transport exited 0 (272 warnings, all pre-existing).

@changeset-bot

changeset-bot Bot commented Sep 28, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: b20c6b3

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@ScriptedAlchemy
ScriptedAlchemy merged commit 8b3bcf8 into master Sep 28, 2026
1 check passed
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-28T00:38:52.655742Z b20c6b3 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@ScriptedAlchemy
ScriptedAlchemy deleted the fleet/mcp-compat-layer-deletion branch September 28, 2026 00:34

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b20c6b3fe3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

pub fn invocation_client_for_current_client(
handshake: DaemonHandshake,
) -> Result<tracedecay_daemon_protocol::DaemonInvocationClient> {
let socket_path = default_available_socket_path(&handshake)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Retain restart grace for typed CLI connections

When a CLI call lands after DaemonAuthority::acquire has published the new authority record but before bootstrap has rebound the Unix socket, default_available_socket_path rejects the absent path immediately. The previous invocation_client_for_current path handed the recorded endpoint to DaemonInvocationClient, whose connection helper waits through DAEMON_RESTART_GRACE; this change therefore makes every typed tracedecay tool call spuriously exit 69 during that normal restart window instead of retrying.

Useful? React with 👍 / 👎.

tracedecay::daemon::handshake_for_current_client(profile, project, None, false, false)?;
let executor = FamilyToolExecutor {
client: tracedecay_daemon_identity::invocation_client_for_current(handshake)?,
client: tracedecay::daemon::invocation_client_for_current_client(handshake)?,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep --json failures machine-readable

For a newly migrated multi-root call using --json, any socket or authority failure here is returned before handle_multi_root can render a tool result, leaving stdout empty and only printing an error to stderr. The deleted compatibility route explicitly converted the same project-route failure to {"problem": ...} on stdout, so machine callers that parse the promised JSON output now fail precisely when the daemon is unavailable; preserve that structured error behavior in the typed route before deleting the compatibility support.

AGENTS.md reference: AGENTS.md:L178-L180

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant