-
Stefy Lanza (nextime / spora ) authored
v0.3.25 shipped the trace as a bare list of findings, and defined the empty list as "the bytes were sound, so the loss is in the serving path". That is wrong whenever the upstream returned no logprobs: there was nothing to analyse, and the emptiness would have read as a confident conclusion drawn from missing data -- exactly the class of mistake the trace exists to stop. So the trace is now a self-describing envelope: {"calls": 7, "with_logprobs": 7, "conclusive": true, "kinds": {"invalid-utf8": 29}, "why": "...", "findings": [...]} and `unreadable.blame` is one of "the model", "the serving path" or "unknown". `conclusive` is false when no calls were recorded (the hook never fired) or when none carried logprobs, and then blame is "unknown" rather than defaulting to either culprit. surya asks for logprobs by default (SURYA_INFERENCE_LOGPROBS = True) and the OCR gateway forwards the body verbatim precisely so they survive, so the normal case is conclusive. But an upstream that declines them is a configuration, not a bug, and it has to be visible instead of silently inverted into an answer. Also: a trace analysis that throws now reports {"conclusive": false, "why": "trace analysis failed: ..."} rather than no key at all, so "the analysis broke" and "the bytes were fine" cannot look the same either. tests/test_ocr_token_trace.py: 37 (was 30), including the inconclusive paths. 825 passed across the OCR/config/admin/runpod selection, same 10 pre-existing failures. Co-Authored-By:Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PxYHWbCAjjjD7A1rhFKtaW
168ac912