Date: 2026-07-18 Method: 3 parallel review agents (parsers+trace, classifier+forker+exporter, CLI+TUI+discovery), golangci-lint, fuzz testing, live system testing Total findings: 42 Fixed: 17 (all critical + high) Filed as GitHub issues: 15 (medium + low)
| # | Severity | File | Description | Fix |
|---|---|---|---|---|
| 1 | Critical | parser/claude.go | Multi-tool-use data loss: tool_results applied to wrong iteration | Added toolUseMap for ID-based correlation |
| 2 | Critical | cli/timeline.go | strings.Repeat panic on zero iterations | Added early return guard |
| 3 | Critical | player/views/iteration.go | strings.Repeat panic on narrow terminal (<2 cols) | Added width guard |
| 4 | High | parser/detect.go | 1MB buffer vs 2MB parsers caused format detection failure | Unified to 2MB |
| 5 | High | parser/detect.go | scanner.Err() not checked, errors silently swallowed | Added error check |
| 6 | High | parser/detect.go | Only checked first line, real Claude sessions start with queue-operation | Check up to 20 lines + detect sessionId field |
| 7 | High | classifier/classify.go | Nil pointer on t.Summary in detectVerifierStrict | Added nil guard |
| 8 | High | exporter/markdown.go | Nil pointer on t.Summary in ExportMarkdown | Added nil guard |
| 9 | High | forker/checkpoint.go | Stored raw diffs as file content, corrupting checkpoints | Removed diff-as-content fallback |
| 10 | High | parser/claude.go | containsTestFailure false positives on "error", "fail" substrings | Tightened patterns to "tests failed", "fail:", etc. |
| 11 | High | parser/claude.go | Token attribution skewed for multi-tool-use messages | Divide tokens equally across tool_use blocks |
| 12 | High | player/views/iteration.go | Negative width to lipgloss.Width() on narrow terminal | Added minimum width guard |
| 13 | Medium | parser/ltf.go | Phase overwritten by last event in multi-event iterations | Added priority-based phase selection |
| 14 | Medium | parser/claude.go | truncate() splits multi-byte UTF-8 | Replaced with rune-aware truncateRunes() |
| 15 | Medium | pricing/models.go | DefaultPricing() allocates new map on every call | Cached as package-level var |
| 16 | Medium | classifier/spin.go | Custom min() shadows Go builtin | Replaced with math.Min |
| 17 | Medium | exporter/html.go | Custom escapeHTML missing single-quote, no XSS protection | Replaced with html.EscapeString |
See issues on https://github.com/loop-eng/looprelay/issues