feat(tui): add TTY trace system and fix footer rendering#108
Conversation
419b9af to
c8eae32
Compare
📦 Previous Review (superseded by newer review)Pull Request Review: TTY Trace System and Footer Rendering FixThis PR adds excellent debugging infrastructure and fixes a real rendering issue. The implementation is well-structured and the problem/solution are clearly documented. Here are my findings: Code Quality ✅Strengths:
Minor suggestions:
Potential Bugs 🐛1. Race condition in footer debouncing ( w.footerTimer = time.AfterFunc(w.footerDebounceDelay, func() {
w.mu.Lock()
defer w.mu.Unlock()
w.redrawFooterLocked()
})This is generally safe, but there's a potential deadlock if 2. Timer leak potential ( 3. File permissions ( return os.WriteFile(path, data, 0644)Trace files may contain sensitive data (as documented). Consider using Performance Considerations ⚡1. Memory growth in long sessions
2. Data copying overhead ( dataCopy := make([]byte, len(data))
copy(dataCopy, data)This is correct (necessary to avoid buffer reuse issues), but adds overhead. The performance impact is acceptable for debugging, but worth documenting that tracing should not be used in production. 3. Footer debouncing efficiency Security Concerns 🔒1. Sensitive data in traces ✅ Well-documented Recommendations:
2. Path traversal in trace save
Test Coverage 📊Strengths:
Gaps:
Recommendation: Add tests for the recording wrappers and concurrent access patterns. TUI Writer Changes 🎨The debouncing fix is elegant ✅ Screen clear changes ( Documentation 📚Excellent documentation ✅
Minor suggestions:
Overall Assessment ✨This is a high-quality PR that solves a real problem and adds valuable debugging infrastructure. The TTY trace system is well-designed and will be useful for diagnosing TUI issues beyond just this one case. Recommended actions before merge:
Nice to have:
The core implementation is solid and the footer debouncing fix is well-reasoned. Great work! 🚀 |
c8eae32 to
f864d24
Compare
📦 Previous Review (superseded by newer review)Pull Request Review: TTY Trace System and Footer Rendering FixThis PR adds a comprehensive terminal I/O tracing system and fixes TUI rendering issues through debounced footer redraws. The implementation is well-structured and addresses a real problem. ✅ StrengthsArchitecture & Design:
Documentation:
Testing:
Code Quality:
🔍 Issues & Suggestions1. Potential Nil Pointer Dereference (Medium severity)
tracer := setupTTYTracer(tracePath, r, command)
defer tracer.save() // ← tracer can be nil!When tracing is disabled, Fix: Add nil check before defer: if tracer != nil {
defer tracer.save()
}2. Data Race in Footer Timer (Low-Medium severity)
The Mitigation: Add a w.footerTimer = time.AfterFunc(w.footerDebounceDelay, func() {
w.mu.Lock()
defer w.mu.Unlock()
if w.closed {
return
}
w.redrawFooterLocked()
})3. Redundant else Clause (Low severity)
var stdin io.Reader = escapeProxy
if tracer != nil {
stdin = trace.NewRecordingReader(escapeProxy, tracer.recorder, trace.EventStdin)
} else {
stdin = escapeProxy // ← Already assigned on line 78
}Fix: Remove the else clause. 4. Large Trace Files (Low severity, acknowledged in docs)Consider documenting typical file sizes and adding compression support for long sessions. 5. Test Coverage Gaps
🔒 Security Considerations✅ Good:
Consider:
📊 Performance ImpactOverhead should be minimal. Main concern is memory usage for very long sessions since trace events accumulate in RAM until save. Consider streaming to disk. 📝 Documentation Follow-upsPer CLAUDE.md guidelines, update:
Minor Nits
VerdictApprove with minor fixes recommended. This is a solid addition that solves a real problem and adds valuable debugging infrastructure. Recommended fixes before merge:
Excellent work overall! |
f864d24 to
3eb780e
Compare
📦 Previous Review (superseded by newer review)Pull Request Review: TTY Trace System and Footer Rendering FixThis is a well-engineered solution to a tricky TUI rendering problem. The PR adds comprehensive terminal I/O tracing infrastructure and fixes the Claude Code banner garbling issue through debounced footer redraws. Overall AssessmentStrengths:
Rating: ✅ Approve with minor suggestions Code Quality & Best Practices1. Trace Package (
|
3eb780e to
bdfac9e
Compare
📦 Previous Review (superseded by newer review)Pull Request Review: TTY Trace System and Footer Rendering FixThis PR adds valuable debugging infrastructure and fixes a concrete TUI rendering issue. The implementation is well-designed with good separation of concerns. Here's my detailed feedback: Strengths1. Excellent Problem Definition 2. Strong Test Coverage
3. Clean Architecture
4. Good Documentation
Issues & ConcernsCritical: Potential Timer Leak in scheduleFooterRedrawLockedLocation: The debouncing implementation has a subtle resource leak: func (w *Writer) scheduleFooterRedrawLocked() {
if w.footerTimer != nil {
w.footerTimer.Stop() // ⚠️ Doesn't drain the channel
}
w.footerTimer = time.AfterFunc(w.footerDebounceDelay, func() {
w.mu.Lock()
defer w.mu.Unlock()
w.redrawFooterLocked()
})
}Problem: According to Go documentation, Recommended Fix: func (w *Writer) scheduleFooterRedrawLocked() {
if w.footerTimer != nil {
if !w.footerTimer.Stop() {
// Timer already fired, try to drain the channel
select {
case <-w.footerTimer.C:
default:
}
}
}
w.footerTimer = time.AfterFunc(w.footerDebounceDelay, func() {
w.mu.Lock()
defer w.mu.Unlock()
w.redrawFooterLocked()
})
}Alternatively, consider using Medium: Unbounded Memory Growth in Trace EventsLocation: r.trace.Events = append(r.trace.Events, Event{...})Problem: For long-running sessions with high I/O volume, the events slice can grow unbounded. There's no cap, rotation, or memory limit. Impact: A 10-minute Claude Code session with 1KB/sec output generates ~600KB of trace data, which is acceptable. But a full development session could hit memory limits. Recommendations:
Medium: Data Race Risk in ttyTracer.save()Location: defer tracer.save()Problem: The Current Mitigation: The mutex in Recommendation: Add a Low: Hardcoded 50ms Debounce DelayLocation: footerDebounceDelay: 50 * time.Millisecond,Observation: The 50ms delay works for Claude Code's banner rendering, but might be too aggressive for slower terminal emulators or high-latency SSH sessions. Recommendation: Consider making this configurable via an environment variable ( Low: Missing Error Handling in redrawFooterLockedLocation: w.out.Write(buf.Bytes()) //nolint:errcheckProblem: Write errors are silently ignored. If stdout is broken (pipe closed, terminal disconnected), this could mask issues. Recommendation: Either log the error or propagate it. At minimum, consider: if _, err := w.out.Write(buf.Bytes()); err != nil {
// Terminal disconnected - stop trying to redraw footer
if w.footerTimer != nil {
w.footerTimer.Stop()
w.footerTimer = nil
}
}Code Quality ObservationsGood Practices:
Minor Improvements:
Security ConsiderationsSensitive Data Exposure:
Mitigations:
Recommendation: Add a prominent warning when fmt.Printf("⚠️ WARNING: Trace will capture ALL terminal I/O including sensitive data.\n")
fmt.Printf(" Do not share traces without sanitizing them first.\n")Performance Considerations
Testing RecommendationsIntegration Tests Needed:
Suggested Test: func TestFooterDebouncing(t *testing.T) {
// Create writer with short debounce delay for testing
w := NewWriter(&buf, bar, "docker")
w.footerDebounceDelay = 10 * time.Millisecond
// Simulate rapid writes
for i := 0; i < 100; i++ {
w.Write([]byte("data\n"))
time.Sleep(1 * time.Millisecond)
}
// Wait for debounce to settle
time.Sleep(20 * time.Millisecond)
// Verify footer was redrawn only once (not 100 times)
// Implementation would require tracking redraw count
}Documentation AccuracyI verified several claims in the documentation against the code: ✅ Correct: Trace format matches documented JSON structure (format.go matches docs/tty-trace-debugging.md:467) Breaking Changes / CompatibilityNone. This is purely additive:
Overall AssessmentRecommendation: Approve with minor fixes This is a well-designed feature that solves a real problem (Claude Code banner garbling) while adding valuable debugging capabilities. The trace system is properly architected and well-tested. Must Fix:
Should Fix:
Nice to Have:
The footer debouncing fix is elegant and the trace system will be invaluable for debugging TUI issues in the future. Great work! 🎉 References
|
Add comprehensive terminal I/O tracing infrastructure for debugging TUI rendering issues. Fix Claude Code banner garbling by implementing debounced footer redraws. Problem: Claude Code's banner rendered with garbled/overlapping text when running inside moat. The issue was caused by moat redrawing the status bar footer after every stdout write, which interrupted Claude's multi-step rendering sequences wrapped in ESC[?2026h/l brackets. Solution: 1. TTY Trace System: Added infrastructure to capture, analyze, and decode terminal I/O with nanosecond timing for debugging TUI issues 2. Footer Debouncing: Changed from immediate footer redraw to debounced redraw with 50ms delay, allowing child process to complete rendering frames without interruption 3. Scroll Region Clearing: Changed from full screen clear (ESC[2J) to scroll region clear (ESC[J) to avoid clearing status bar area New trace system features: - Capture all terminal I/O (stdin/stdout/stderr) with timing - Record resize events and terminal environment - Decode ANSI/VT100 control sequences - Find patterns like screen clears and resize timing issues - CLI: moat tty-trace analyze <file> --decode/--find-clears Footer rendering improvements: - Debounce timer resets on each write, redraw only after 50ms quiet - Timer stopped when entering compositor mode - Alternative approaches documented in comments for future consideration Testing: - All existing tests pass with updated expectations - New trace analysis tests verify control sequence decoding - Verified fix with actual Claude Code session Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
bdfac9e to
7912ee0
Compare
Code Review: TTY Trace System and Footer Rendering FixThis PR adds comprehensive terminal I/O tracing infrastructure and fixes Claude Code banner garbling through debounced footer redraws. The implementation is well-designed with strong test coverage. Overall AssessmentStrengths:
Areas for improvement:
Code Quality & Best Practices✅ Excellent StructureThe trace package is well-organized with clear separation:
✅ Comprehensive TestingStrong test coverage including:
|
Add terminal I/O tracing infrastructure for debugging TUI rendering issues. Fix Claude Code banner garbling by implementing debounced footer redraws.
Problem:
Claude Code's banner rendered with garbled/overlapping text when running inside moat. The issue was caused by moat redrawing the status bar footer after every stdout write, which interrupted Claude's multi-step rendering sequences wrapped in ESC[?2026h/l brackets.
Solution:
New trace system features:
Footer rendering improvements: