deprecation-warnings-on

Deprecation warnings on stdout pollute handler protocol streams — must route to stderr/log only

Metadata

Statusdone
Assignedagent-161
Agent identityf51439356729d112a6c404803d88015d5b44832c6c584c62b96732b63c2b0c7e
Created2026-04-26T23:04:06.599656953+00:00
Started2026-04-26T23:04:32.733429878+00:00
Completed2026-04-26T23:57:40.907397638+00:00
Tagseval-scheduled
Eval score0.73
└ blocking impact0.70
└ completeness0.70
└ constraint fidelity0.85
└ coordination overhead0.75
└ correctness0.75
└ downstream usability0.75
└ efficiency0.78
└ intent fidelity0.93
└ style adherence0.80

Description

Description

User finding: wg nex --chat (and likely other handlers) was breaking on the second message in TUI chat. Root cause turned out to be deprecation warnings being emitted on stdout during config load. Stdout is the protocol stream for handler binaries (chat-handler reads stdin/writes stdout per chat protocol). Warning lines like 'Deprecated: [coordinator] table is now [dispatcher]' got injected into the json-line stream, corrupting it, and the next-turn parse blew up.

Renaming the deprecated keys in ~/.wg/config.toml silenced the warnings → chat protocol clean → multi-message works.

So the bug is: anything that writes to stdout from inside a handler is part of the protocol stream. Diagnostics, warnings, deprecation notices, config-load chatter — none of these belong on stdout in handler context.

Spec

  1. Audit every println! / eprintln!-but-routed-to-stdout / direct std::io::stdout() call in the codebase. For each, decide:
    • Is it CLI user-output (correct on stdout)?
    • Is it a diagnostic / warning / progress note (must be stderr or log)?
  2. Route ALL diagnostics to stderr OR daemon.log via the existing logger, not stdout. The handler context (claude-handler, nex-handler, codex-handler etc) MUST keep stdout pristine for protocol bytes.
  3. Add an integration test that spawns wg nex --chat (or any handler) with a config that triggers deprecation warnings; assert stdout contains ONLY valid protocol json lines, zero warning text. This is the regression lock.
  4. Audit Config::load and config merge paths specifically since that's where the offending warning fires — make sure those paths use stderr/log even when called transitively from handler code.
  5. Document the contract in a comment at the top of each handler file: 'stdout is protocol; never write diagnostic text to stdout from this code path or anything it transitively calls.'

Why this matters beyond this one bug

Same pattern will bite EVERY handler: claude, nex, codex, future thin-wrapper executors. Any future deprecation warning, any future config-load printout, any future debug eprintln-routed-to-stdout corrupts chats silently. This is a FOUNDATIONAL hygiene fix.

Files likely to touch

  • src/config.rs (the deprecation warning emit site — check if it goes to stderr or stdout)
  • src/commands/claude_handler.rs, src/commands/nex.rs (handler entry points)
  • src/executor/native/agent.rs etc.
  • Anywhere with raw println! that may run during handler execution

Validation

  • Failing test first: test_handler_stdout_pristine_with_warning_config — spawn handler with deprecated keys present; assert stdout stream is parseable json-line ONLY, no warning text
  • grep test: grep -rn 'println!' src/ audited; every stdout-bound diagnostic identified and either justified (CLI output) or redirected
  • Implementation: warnings route to stderr/log; handler stdout pristine
  • cargo build + cargo test pass with no regressions
  • Manual smoke: revert the global config rename to bring back the deprecation warning, run wg nex --chat in TUI, send 5 messages — must still succeed (warning visible in stderr/daemon.log, but doesn't pollute stdout/protocol)

Depends on

Required by

Log