From 81d58d87a67275d31aaf0a9f10be09dd148c0718 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 16 May 2026 01:11:42 +0000 Subject: [PATCH] fix(canon): correct SSE bytes_out claim in telemetry-validation-gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The original step 3 said "For SSE-streamed responses, expected bytes_out = 0 and tokens_out = 0 per the Emission Contract." This contradicts the wrapper's own design: per klappy://canon/constraints/telemetry-governance §Emission Contract Rule 2, the wrapper measures the in-memory \`content\` envelope BEFORE MCP transport framing. SSE-transported responses still produce non-zero bytes_out and tokens_out at the wrapper. Smoke evidence (main preview, 2026-05-16 00:30Z): all 14 successful SSE-framed tool calls emitted non-zero bytes_out (range 288 to 28,593) and tokens_out (range 121 to 7,780). Zero SSE responses produced zero emitted bytes_out. The wrapper's in-memory measurement defeats the SSE-zero failure mode that originally motivated the wrapper. The "0 for SSE" line in the Numeric Values table of telemetry-governance refers to the old wire-edge instrumentation, not the wrapper. The replaced text clarifies this. --- canon/constraints/telemetry-validation-gate.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/canon/constraints/telemetry-validation-gate.md b/canon/constraints/telemetry-validation-gate.md index e5f1c04..60f393b 100644 --- a/canon/constraints/telemetry-validation-gate.md +++ b/canon/constraints/telemetry-validation-gate.md @@ -43,7 +43,7 @@ Sample size is one per tool per surface. Increase it for operator margin if desi 1. Enumerate every `server.tool()` registration in `workers/src/index.ts`. This is the smoke target list. 2. Drive one synthetic call per tool through the surface's `/mcp` endpoint. Record the exact `args` object sent (the JSON-RPC `params.arguments` payload) and the exact `{ content: [...] }` envelope returned by the handler — not the full HTTP request/response bodies, which include JSON-RPC framing the wrapper does not see. -3. For each call, compute the expected values locally against the same in-memory values the wrapper measures per `klappy://canon/constraints/telemetry-governance` Rule 2: `bytes_in = utf8_byte_length(JSON.stringify(args))`, `bytes_out = utf8_byte_length(JSON.stringify(content_envelope))`, `tokens_in = cl100k_count(JSON.stringify(args))`, `tokens_out = cl100k_count(JSON.stringify(content_envelope))`. For SSE-streamed responses, expected `bytes_out = 0` and `tokens_out = 0` per the Emission Contract. +3. For each call, compute the expected values locally against the same in-memory values the wrapper measures per `klappy://canon/constraints/telemetry-governance` Rule 2: `bytes_in = utf8_byte_length(JSON.stringify(args))`, `bytes_out = utf8_byte_length(JSON.stringify(content_envelope))`, `tokens_in = cl100k_count(JSON.stringify(args))`, `tokens_out = cl100k_count(JSON.stringify(content_envelope))`. Wire-level SSE framing does not zero out these values: the wrapper measures the in-memory envelope before transport, which is the failure mode the Emission Contract was designed to defeat. The "0 for streamed (SSE) responses" caveat in the §Numeric Values table refers to the old wire-edge instrumentation, not the wrapper. 4. Query `oddkit_telemetry` with `event_type = 'tool_call'`, `worker_version = `, and a timestamp window covering the smoke run. 5. Match each emitted row to the corresponding smoke call (by tool name and timing). Compare emitted versus expected on all four fields.