Skip to content

tool --json refusals print three shapes; callers keeps top-level problem #2672

Description

@ScriptedAlchemy

Summary

On v1.0.0-beta.63 (e531946c8c), a refusing tracedecay tool <name> --json prints one of three different shapes depending on the tool and on where the refusal is produced. The #2651 breaking-change note says tracedecay tool --json output carries the typed problem "only at structuredContent.problem; the top-level problem member is removed". That holds for search, but not for callers or for a daemon-connect refusal. The MCP wire itself is consistent: tools/call tracedecay_callers answers isError: true with structuredContent.problem only.

Repro (installed beta.63, run from /fast/projects/tracedecay)

# 1. search: MCP tool-result shape (matches #2651)
c=$(tracedecay tool search --query formatBytes --limit 2 --format json | jq -r .next_cursor)
tracedecay tool search --query formatSignedBytes --limit 2 --cursor "$c" --json
# exit 1; stdout keys: isError=true, structuredContent.problem.code="cursor.parameter_changed", no top-level "problem"

# 2. callers: application envelope with a top-level problem
tracedecay tool callers --node-id no-such-node-beta63 --json
# exit 1; stdout:
# {"contract":{"schema_id":"schema.application.primitive.code-callers.result","schema_revision":1},
#  "request_id":"request.cli.582034c1...","problem":{"revision":1,"kind":"not_found_or_not_authorized",
#  "code":"not_found_or_not_authorized",...,"retry":"never",...}}
# no isError, no structuredContent

# 3. daemon connect refusal: a third, untyped shape
TRACEDECAY_DAEMON_SOCKET=/tmp/does-not-exist.sock tracedecay tool status --json
# exit 69; stdout:
# {"problem":{"detail":"TraceDecay daemon socket '/tmp/does-not-exist.sock' named by TRACEDECAY_DAEMON_SOCKET is not available. ...",
#  "reason_code":"daemon_connect_down","retryable":true,"tool":"tracedecay_status"}}

For comparison, the same callers refusal over MCP (tracedecay serve --path /fast/projects/tracedecay, tools/call tracedecay_callers {"node_id":"no-such-node-beta63"}) returns result keys _meta, content, isError, structuredContent, with isError: true and structuredContent = {problem: {code: "not_found_or_not_authorized", ...}}.

Expected

tool --json has one refusal shape for every tool: the typed problem record at structuredContent.problem and isError: true, as the #2651 note documents. Case 3 is not a typed problem record at all (reason_code/retryable instead of code/kind/retry/legal_actions), so a script cannot read one field to find out whether it should retry.

Impact

Scripts written against the #2651 note (jq .structuredContent.problem) miss the problem for application-primitive tools such as callers, and they miss it for daemon-down refusals.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions