Uh oh!
There was an error while loading. Please reload this page.
fix(cli): suppress web-bg dashboard output in silent mode - #203
Conversation
JinHyuk Sung (sjh9714)
commented
May 18, 2026
@microsoft-github-policy-service agree |
Jason Robert (jrob5756)
left a comment
There was a problem hiding this comment.
LGTM — fix is minimal, correctly scoped, and well-tested.
Verified locally:
- Both new regression tests fail when
app.pyis reverted (with the exact pre-fix output from #201's repro) and pass with the fix applied. - Targeted suite green: 7/7 in
test_cli/test_web_flags.pyandtest_cli/test_resume_command.py(-k web_bg). uv run ruff check src testsanduv run ruff format --check src testsboth clean.
Strengths
- Surgically targeted to the two
--web-bgbranches called out in #201 (run + resume), preserving the Run/Resume parity convention fromAGENTS.md. - Uses the existing
is_verbose()helper instead of introducing a new gating mechanism — consistent with the codebase's verbosity model. - No information loss — the dashboard URL remains discoverable via the PID file at
~/.conductor/pids/<workflow>-<port>.pidfor scripted callers running in--silentmode.
Follow-up (out of scope for this PR)
Three other unconditional dashboard-URL prints share the same shape and silently violate the --silent contract: replay (app.py:990), and foreground --web in both run and resume (run.py:1173, run.py:1685 — _verbose_console is a plain stderr Console, not silent-aware). Will file a separate issue.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@## main #203 +/- ##
=======================================
Coverage ? 88.21% =======================================
Files ? 60 Lines ? 9649 Branches ? 0 =======================================
Hits ? 8512 Misses ? 1137 Partials ? 0 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Uh oh!
There was an error while loading. Please reload this page.
- feat(script): script agents output schemas (#206, #118) - feat(validate): warn on undeclared agent.output refs and field-level mismatches in explicit mode (#208) - feat(copilot): attribute verbose logs to agents in parallel/for-each runs (#207) - fix(resume): replay original event log into dashboard on --web (#167, #205) - fix(windows): make --web-bg startup crashes diagnosable (#116, #204) - fix(engine,web): resolve max-iterations gate from dashboard in --web-bg (#202) - fix(bg): detach --web-bg child from Windows job to prevent kill-on-close (#200) - fix(bg): stop passing redundant --silent to bg child (#199, #196) - fix(cli): suppress web-bg dashboard output in silent mode (#203, #211) - fix(config): auto-fetch sibling sub-workflow from registry cache during validation (#197) - fix(registry): mirror repo layout in cache so cross-workflow refs resolve (#194) - fix(copilot): tolerate SDK metadata parsing errors when listing models (#193) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…209) (#223) * fix(cli): make _verbose_console silent-aware and gate replay prints (#209) PR #211 (follow-up to #203) gated three foreground dashboard URL prints behind `is_verbose()` but left the remaining stderr leaks in place, violating the `--silent` contract ("No progress output. Only JSON result on stdout."). Specifically: * `app.py:_run_replay` still printed 'Press Ctrl+C to exit' and 'Replay stopped' unconditionally. * `run.py` had ~12 `_verbose_console.print` call sites that bypassed `is_verbose()` — warnings (dashboard failed to start, log-file open failure, workflow-hash mismatch), 'Press Esc to interrupt', 'Event log written to...', 'Log written to...', and `_print_resume_instructions` (printed on failure). Fix at the source: subclass `Console` for `_verbose_console` so every `.print(...)` no-ops when `is_verbose()` is False. This aligns the implementation with the long-misleading name, removes the per-call-site audit burden, and is a no-op for the already-gated helpers. The app-wide `console` in app.py is intentionally NOT made silent-aware because it carries real error messages; the two remaining replay prints are gated per-call instead. Acceptance criterion verified: `conductor --silent replay <log>` produces 0 bytes on stderr (was leaking 'Press Ctrl+C to exit'). Regression tests: * `TestSilentAwareConsole` (3 tests) — verifies the subclass mechanism and that the module-level instance uses it. * `TestReplaySilentCompliance` (2 tests) — verifies the replay command produces no stderr under `--silent` and still prints when verbose. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(cli): address PR #223 review findings (#209) Comprehensive PR review surfaced one critical coverage gap and a few defensive improvements. All addressed in this commit: * **Critical (pr-test-analyzer)**: The `KeyboardInterrupt` branch at `app.py:1007-1009` (`Replay stopped`) had zero behavioral test coverage — the previous `CancelledError`-via-`asyncio.Event` path never reaches the outer `except KeyboardInterrupt`. Added `test_silent_replay_suppresses_keyboardinterrupt_message` and its verbose counterpart that drive that branch via `patch("asyncio.run", side_effect=KeyboardInterrupt())`. This is also more robust than the inner-path mocking: a future refactor of `_run_replay`'s wait primitive cannot silently bypass it. * **Important (type-design-analyzer)**: `_SilentAwareConsole.__init__` now locks `stderr=True`. A future caller constructing an instance with `stderr=False` would have silently routed gated output to stdout and corrupted the `--silent` JSON contract. * **Important (comment-analyzer)**: Tests now assert on `result.stderr` (not the combined `result.output`), matching the test names and catching a hypothetical regression that moved the prints to stdout. * **Suggestion (pr-test-analyzer)**: Added `test_quiet_replay_prints_dashboard_messages` to lock in the contract at `app.py:204` that `--quiet` (MINIMAL) keeps `verbose_mode=True` — MINIMAL means "limited progress", not zero. * **Suggestion (multiple agents)**: Class-level comment on `_SilentAwareConsole` warns that only `.print()` is gated; `.rule()`/`.log()`/`.status()`/`.print_json()` would silently bypass `--silent`. All current call sites use only `.print`. Verified: `conductor --silent replay <log>` still produces 0 bytes on stderr; `conductor --quiet replay <log>` still prints the dashboard URL and Ctrl+C hint as before. 400 `tests/test_cli` tests pass (was 397; +3 net new). Lint/format/typecheck clean. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
Fixes
--silent --web-bgstill printing dashboard status lines.What changed
run --web-bgandresume --web-bg.--web-bgoutput outside silent mode.Why
Issue #201 reports that
--silentpromises no progress output, but the background dashboard branch still prints to stderr.Testing
uv run pytest tests/test_cli/test_web_flags.py tests/test_cli/test_resume_command.py -k "web_bg"uv run pytest tests/test_cli/test_web_flags.py tests/test_cli/test_resume_command.pymake lintmake typecheck(exit 0; reports an existingpossibly-missing-attributediagnostic insrc/conductor/engine/dialog_evaluator.py)uv run pytest -m "not install_scripts and not real_api"Note:
make testcurrently fails locally ontests/test_integration/test_copilot_large_write.py::test_large_create_tool_call_does_not_truncatebecause the Copilot SDK reports modelclaude-opus-4.7-1m-internalis not available. The web-bg CLI regression tests above pass.Fixes#201