feat(telemetry): a trace says whether a tool call returned anything #574

Merged
coilyco-ops merged 1 commit from coilyco-ops/a-trace-says-what-a-tool-returned into main 2026-08-13 16:14:57 +00:00 AGit
Member

closes #570 - the outcome reached a metric and a log but never the span, so an investigation into a reply asserting absence stopped one step short of what the tool returned.

closes #570 - the outcome reached a metric and a log but never the span, so an investigation into a reply asserting absence stopped one step short of what the tool returned.
feat(telemetry): a trace says whether a tool call returned anything
All checks were successful
ci / image-build (pull_request) Successful in 21s
ci / test (pull_request) Successful in 33s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
df5270bfdf
Found by needing it. On sirens-echo#195 I established that Echo called
find_trade four times around Kai's transcript, and that the same call today
returns 944 units across two live sellers, while the reply said zero listed.

The one thing that would settle it is what find_trade returned at that moment,
and the trace could not say. mcp.tool.call carried the server and the tool and
nothing else.

The outcome existed and went elsewhere: to a metric, which aggregates and
cannot be joined to one turn, and to a log line, which per sirens-echo#158 is
currently emitted with empty severity for about 97% of lines. Neither is
reachable from the trace a reader is holding.

So a member could see that a call returned nothing, from the disclosure footer,
and an operator reading the trace could not.

mcp.tool.call now carries mcp.tool.outcome and mcp.tool.result_bytes. The
outcome is the existing three-state ToolOutcome rather than a fourth
vocabulary, for the reason tooldisclosure.go gives for referencing the reaction
constants: the surfaces must not drift apart.

The test drives a real tool round through Complete against an httptest proxy
and a fixture provider, then reads the attributes off the recorded span. It
asserts on what a reader would see rather than on the value passed in, and it
fails loudly if no span is recorded, because a noop provider records none while
every assertion passes.

All three states are covered, since an empty result and a failed call reading
alike is the distinction sirens-echo#195 exists to protect.

closes #570

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/sirens-echo!574
No description provided.