fix(trace): key the tool-part decoders by the harness names that arrive - #955
Merged
Conversation
toolPartDecoders held an entry under `kimi`. Every in-repo caller reaches decodeToolPart through SteerableSandboxSession.harness, which is BackendType, and the harness kimi is served under is `kimi-code`, so no caller could select that entry. It was also wrong about the wire: kimi-code streams an Anthropic tool_use content block and a top-level OpenAI tool_calls entry on one session, and the entry named the OpenAI decoder alone. An unknown harness falls through to the try-all path, so no tool call was lost. The defect was a trap: renaming the key to kimi-code while keeping the decoder it named would have made the specific adapter win and dropped the tool_use half in silence. The registry is now typed against HarnessType, so a key no caller can produce does not compile, and kimi-code maps to a decoder that reads both shapes. The three keys that were never harness names are gone; those wire shapes decode identically through the try-all path.
tangletools
approved these changes
Aug 21, 2026
tangletools
left a comment
Contributor
There was a problem hiding this comment.
✅ Auto-approved drewstone PR — 5d81251b
This PR was opened by the trusted drewstone account.
This approval is provisional and was applied by the local stand-in because the pr-reviewer webhook host is unreachable (2026-08-21). CI on this head is fully green. The full PR reviewer audit re-runs via the resweep when the service returns and will publish findings if it detects issues.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
toolPartDecoders(src/runtime/supervise/trace-source.ts:151) is the harness → tool-call-decoder registry. It held an entry underkimi, and no caller can produce that name.Every in-repo path to
decodeToolPartruns through one field:supervise/sandbox-session.ts:154decodeToolPart(part, args.harness)supervise/sandbox-session.ts:100readonly harness: BackendTypesupervise/runtime.ts:1277,runtime.ts:4815spec.harness as BackendTypeBackendType@tangle-network/sandboxExclude<HarnessType, 'gemini'>@tangle-network/agent-interfaceharness.d.ts:23, andsrc/sandbox-backend.ts:31kimi-codeThe literal
'kimi'appears nowhere insrc/,tests/,bench/ordocs/. In the real producer it is a config toggle name and a binary name, never a wire value:cli-bridge/src/server.ts:169registers the backend withharness: 'kimi-code'.The entry was also wrong about the wire. kimi-code streams both shapes on one session — an Anthropic
tool_usecontent block (cli-bridge/src/backends/kimi.ts:281) and a top-level OpenAItool_callsentry (:307). The registry nameddecodeOpenAiPart, which reads only the second. The module's own docstrings already knew::112saysdecodeAnthropicPartcovers "kimi's tool_use variant" and:128saysdecodeOpenAiPartcovers "kimi's top-level form".Three more keys were never harness names either:
anthropic,openai,router.Why nothing broke, and why that is the dangerous part
An unregistered harness falls through to the try-all loop (
:168), which is aSetof the three distinct decoder functions — including the Anthropic one. So no kimi tool call is dropped today; the measured trace is correct. Verified before any edit:The defect is the trap. The obvious repair — rename the key to
kimi-code, keep the decoder the entry names — makes the specific adapter win and silences thetool_usehalf. Measured on that repair:Half of a kimi worker's tool calls would disappear with no error: the trace simply reports fewer calls, and every rate computed from it — repeated-action detection, tool-waste, error streaks — is wrong by an unknown amount. No test would have caught it: every kimi case in
tests/kernel/trace-source.test.tscallsdecodeToolPart(part)with no harness, so thekimikey was never exercised.Change
decodeKimiPartreads both shapes, andkimi-codemaps to it.Partial<Record<HarnessType, ToolPartDecoder>>, so a key no caller can produce does not compile — the same guardsrc/runtime/sandbox-backend.ts:40already uses for the sibling list. This is what makes the defect unrepeatable; a lint rule or a drift test would only report it.anthropic,openaiandrouterare removed. A part carrying any of those wire shapes decodes identically through the try-all path, so no behavior moves.decodeToolPart'sharnessandsandboxSessionTraceSource'sharnessoption narrow fromstringtoHarnessType. A caller with a harness this package does not register omits the argument, which is what try-all is for.Proof
The version gate named exactly the two symbols this change moves and nothing else:
That is #953 working on its first real change: before it, this pull request would have reported "consumer surface unchanged at 0.154.0" and shipped a narrowed public signature under a version the registry already holds.
Simplification
Simplification: four unreachable keys removed from a seven-key registry; the registry's key vocabulary now has one owner (
HarnessType) instead of being a freeRecord<string, …>that no compiler checked.Net: +14 / -8 lines in one source file, +18 in one test; 4 registry entries removed, 1 added.
Not done here: the other unregistered
HarnessTypemembers (nanoclaw,pi,prime,hermes,openclaw,amp,factory-droids,forge,cursor,acp,cli-base) keep using the try-all path. Registering one needs its real wire shape confirmed against the bridge backend that serves it, which is a per-harness measurement, not a list edit.Tests: +1 (both kimi-code wire shapes decode when the harness is named — the case that fails the moment anyone binds
kimi-codeto a single decoder, which is exactly the repair the old entry invited). It is green before this change too, becausekimi-codewas not a key at all; what fails before this change is the compiler, on thekimikey itself. -0 deleted.Refs #954