Context
aidd telemetry read asks every declared tool's reader in turn. OpencodeCostReaderAdapter shells out to opencode export <session> --sanitize with a ten-second budget, and throws OpencodeExportError for any failure that is not the exact string "session not found" — including a timeout, where spawnSync sets result.error.
ReadLocalCostUseCase does not catch. So one tool being slow, hung, or broken aborts the read for every tool, and the records the other readers already produced are never stored.
Found by
A new e2e for aidd telemetry report seeded its sink by running telemetry read first. It passed alone and failed roughly one full-suite run in three, at 8-16 seconds — opencode is installed on this machine, so every run shelled out to it under whatever load the rest of the suite was producing. The e2e was changed to seed the sink directly; the product behaviour it exposed is untouched.
Expected
A reader that cannot answer costs that tool's figures, never the others'. It is the same rule the local-read contract already states for a missing transcript ("a missing, unreadable or truncated source costs attribution, not the figures") and the same rule the run-journal reader already obeys.
The tool should report as unread, with the reason, exactly as not covered and no session found already do — a fourth distinguishable silence rather than a crash.
Actual
aidd telemetry read --session <id>
=> OpencodeExportError: opencode export <id> failed: spawnSync opencode ETIMEDOUT
=> nothing stored, for any tool
Scope
- Where a per-tool reader's failure is contained, and what the report prints for that tool.
- Whether
cli/.claude/rules/00-architecture/0-error-handling.md ("use-cases throw, no try/catch inside them") admits this case, or whether the containment belongs in the composition root instead. That rule already carves out a long-lived process; a fan-out over independent readers is a different shape and the decision should be explicit rather than assumed.
- Not in scope: changing OpenCode's timeout, or reading OpenCode any other way.
Relations
Context
aidd telemetry readasks every declared tool's reader in turn.OpencodeCostReaderAdaptershells out toopencode export <session> --sanitizewith a ten-second budget, and throwsOpencodeExportErrorfor any failure that is not the exact string "session not found" — including a timeout, wherespawnSyncsetsresult.error.ReadLocalCostUseCasedoes not catch. So one tool being slow, hung, or broken aborts the read for every tool, and the records the other readers already produced are never stored.Found by
A new e2e for
aidd telemetry reportseeded its sink by runningtelemetry readfirst. It passed alone and failed roughly one full-suite run in three, at 8-16 seconds —opencodeis installed on this machine, so every run shelled out to it under whatever load the rest of the suite was producing. The e2e was changed to seed the sink directly; the product behaviour it exposed is untouched.Expected
A reader that cannot answer costs that tool's figures, never the others'. It is the same rule the local-read contract already states for a missing transcript ("a missing, unreadable or truncated source costs attribution, not the figures") and the same rule the run-journal reader already obeys.
The tool should report as unread, with the reason, exactly as
not coveredandno session foundalready do — a fourth distinguishable silence rather than a crash.Actual
Scope
cli/.claude/rules/00-architecture/0-error-handling.md("use-cases throw, no try/catch inside them") admits this case, or whether the containment belongs in the composition root instead. That rule already carves out a long-lived process; a fan-out over independent readers is a different shape and the decision should be explicit rather than assumed.Relations