Skip to content

fix: route interactive diagnostics away from TUI output - #1185

Merged
SamSaffron merged 3 commits into
SamSaffron:mainfrom
sam-saffron-jarvis:feat/tui-output-consistency
Sep 27, 2026
Merged

SamSaffron merged 3 commits into
SamSaffron:mainfrom
sam-saffron-jarvis:feat/tui-output-consistency

Conversation

@sam-saffron-jarvis

@sam-saffron-jarvis sam-saffron-jarvis commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Follow-up to merged #1183: keep application diagnostics off renderer-owned stdout/stderr in chat and the interactive skills, MCP, sessions and theme views. The scoped runtimeoutput sink writes application diagnostics to restricted $XDG_DATA_HOME/term-llm/diagnostics/tui.log (or the usual home data fallback); actionable session warnings still use the chat footer. It does not replace global descriptors or default loggers, and ordinary CLI, service, renderer, explicit terminal hand-off and auth-login output remain unchanged.

Additional follow-up at 894ac0bc addresses the completed claude-bin:opus-high review (verdict REQUEST CHANGES):

  • B1 resolved: Claude/Grok CLI failure and prompt-truncation retry logs now use runtimeoutput.Error/Info with their original severity and fields. A scoped Go AST guard detects future direct slog, log.Print*, stdout/stderr writes in interactive worker packages and selected chat-reachable command files; named exceptions are documented for guarded authentication, CLI-only output, and unrecoverable forced exit. It intentionally does not flag source string fixtures or renderer/auth output wholesale.
  • B2 resolved: Grok missing and invalid/expired credentials refuse device-code prompts while an interactive UI is active, reporting term-llm auth login grok; missing and expired credential paths have regression coverage.
  • B3 resolved: ChatGPT refresh failure status no longer prints to stderr while an interactive UI is active; the existing guarded prompt returns the actionable login error instead.
  • M1 resolved: failure to open diagnostics is no longer a prerequisite for starting an interactive UI. One startup warning is emitted before renderer ownership, then diagnostics go to an explicit discard sink for that UI. A genuinely overlapping UI still errors. No CWD diagnostic fallback is used when HOME/XDG data cannot provide an absolute path. Tests cover warning delivery, suppression, overlap and sink cleanup.
  • M2 resolved with documented limit: runtimeoutput.Printf writes raw formatted bytes rather than slog-escaped messages. Debug sections and analogous provider CLI/request blocks now write atomically, preserving readable multiline output. User-facing debugging docs distinguish this file from session debug-log JSONL and warn that raw requests/tool results can contain sensitive data; existing debug flags still gate that output. No automatic rotation/retention is introduced; inspect and rotate/delete the file as needed. No new size/time thresholds or flags were added.
  • M3 resolved: child-run MCP/approval progress uses the diagnostic writer rather than footer notices; actionable session-store warnings retain the footer, and child failures remain in run results. A regression test checks progress does not toast. Termhost lifecycle debug also routes safely during UI ownership. Chat diagnostic ownership now follows actual terminal renderer output, including chat --auto-send with redirected stdin; reload/terminal-host gating remains separate.
  • The tracked audit records intentional direct output and verification limits. skills validate --all includes malformed discovered manifests while keeping first-valid precedence (a shadowed invalid duplicate does not replace a valid skill). During explicit handover/reload there is no active UI, so ordinary stderr is expected. A same-user attacker who can replace the diagnostic file between Lstat and OpenFile remains an accepted TOCTOU boundary for now; the directory is private (0700) in the normal case. No platform-specific no-follow implementation or descriptor-wide redirect was introduced.

Verification

At follow-up head 894ac0bc:

  • make build, go build ./..., go vet ./..., make complexity, git diff --check: passed.
  • Isolated go test ./... using temporary HOME/XDG and preserved GOMODCACHE: passed after follow-up changes.
  • Focused go test -race ./internal/runtimeoutput ./internal/llm ./internal/termhost ./cmd -run 'Test(InteractiveWorkersDoNotBypassDiagnosticSink|InteractiveDiagnosticsOpenFailureWarnsBeforeUIAndDiscards|ChildProgressStaysOutOfFooter|GrokPreflightCannotPromptInsideTUI|AuthPromptsRefuseActiveTUI|DebugSectionsRemainRawAndAtomicInInteractiveDiagnostics|BestEffortDiscardOnOpenFailure|RawDebugBlocksAndStructuredLevels|OldDiscardCloserCannotReleaseNewUI|LifecycleDiagnosticUsesActiveSinkInsteadOfTerminal|LifecycleDebugReportsSafeRateLimitedErrorClasses|ChatSessionWarningsAcrossSwitchDetachAndClose|ChatOutputOwnershipIndependentOfInput)' -count=5: passed. A lifecycle test's close-vs-second-state race was observed in one full suite run; the test now accepts the extra safe cancellation class on shutdown, and isolated full suite plus focused repeated/race tests pass.
  • Follow-up CI run 36334162751: all six jobs passed (test, race, frontend, cross-build, passkey smoke, changes).
  • One non-isolated focused cmd run failed tests depending on the host's extra skills; isolated HOME/XDG passed. Prior PR verification included a real PTY config theme run and CLI validation of valid/invalid skill manifests; no new PTY test was run for this follow-up.

Review status

Ready for review. The completed claude-bin:opus-high review requested changes; the follow-up addresses B1–B3 and M1–M3 with the explicit accepted limits above. Parent integration checks verified the routing/auth/startup changes, clean worktree, matching PR head, passing six CI checks and mergeability. There was no second model review or fresh Opus sign-off on the fix commit; do not interpret addressed findings as an Opus approval. No deployment performed.

@sam-saffron-jarvis
sam-saffron-jarvis marked this pull request as ready for review September 27, 2026 16:50
@SamSaffron
SamSaffron merged commit bcb36c9 into SamSaffron:main Sep 27, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants