fix(console): never crash on MarkupError — chokepoint escape fallback#197
Conversation
…fallback Rich treats every `[anything]` in printed strings as a markup tag. Judge output, file paths, dedupe agent text, and CodeRabbit feedback all carry literal brackets (`[/path/foo.ts]`, `[bug]`, `[ ]`) that look like closing tags to the parser. Any interpolation site that forgot `escape()` was a latent panel killer — MarkupError bubbled mid-render, the background task exited 0, and the GitHub review never got posted. Per-site escapes (PR #193, partially #196) didn't scale: in the last 2 weeks we added 4 new high-surface print sites (#172 file routing, #180 reply-chain rendering, #191 git-delta injection, #196 missing-judge list) and the crash kept jumping to whichever one had unescaped content. Three panel runs on pr-1361 crashed on judge_3 then judge_4 from different render paths. Architectural fix: subclass Console once, catch MarkupError, re-render with markup disabled and dynamic content pre-escaped. One chokepoint. All existing styled cube output keeps working — only crash-prone inputs trip the escaped fallback (literal brackets, no tag styling for THAT print). Future print sites are safe-by-default — no more whack-a-mole. Applied to: - `cube.core.output.console` / `console_err` (covers ~95% of cube prints) - `cube.core.base_layout.BaseLayout.console` (Live render path) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📜 Recent review details🔇 Additional comments (3)
WalkthroughA new ChangesSafeConsole Crash-Handling Integration
Estimated Code Review Effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Warning Review ran into problems🔥 ProblemsErrors were encountered while retrieving linked issues. Errors (1)
Comment |
Five sites that printed dev-debug per panel run, all of which expanded the crash surface for free (each was a new bracket-bearing dynamic interpolation site): - peer_review.py:565 — "Looking for judge_X: <path> (exists: ...)" probe per judge. Pure dev debug. - peer_review.py:567 — per-judge "Decision file not found" warning. Same info is now in the panel summary's missing-judges callout, with one consolidated line instead of N warnings. - peer_review.py:611-613 — split "Fetching existing comments" / "Found N existing comments" collapsed to one line with the count. - peer_review.py:498-500, 824-826 — "Resuming N judges" header + a "→ Judge Label" line per judge. Collapsed into one comma-joined line. - judge_panel.py:708-714 — separate "PR lens breakdown" + per-judge "Skipping X — no files in lens" lines consolidated into one line. What stays on the panel render after this: phase headers, one progress line per judge, the final summary. What used to leak — decision-path probes, per-comment-fetch debug, per-judge label dumps — is gone. Pairs with PR #197 (MarkupError chokepoint) but reduces actual surface area instead of just making it crash-proof. Each line removed is one fewer dynamic-interpolation site that can carry untrusted brackets. Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Summary
Consoleso it never raisesMarkupError. If markup parsing fails, re-render withmarkup=Falseand dynamic content pre-escaped.cube.core.output.console/console_errandBaseThinkingLayout.console— the two consoles that carry judge/agent generated text.escape()calls remain valid but are no longer load-bearing.Why
Three panel runs on aetheron-connect-v2#1361 crashed mid-render with
MarkupError, hitting different judges each time (judge_3, then judge_4). Per-site escapes (#193, partially #196) couldn't keep up: the last 2 weeks shipped 4 new high-surface prints (#172, #180, #191, #196) that interpolate judge/Codex/CodeRabbit content. Whack-a-mole was losing.Architecturally: there's now exactly one place that decides what happens when markup parsing fails. Future print sites are safe-by-default; the worst case is a degraded render (literal
[bold]text on the fallback path) instead of a silent panel death.Test plan
console.print('Issue: [bug] in [/path/to/file.ts]')no longer crashesconsole.print(f'[bold cyan]Decision:[/bold cyan] {dynamic}')with bracket-heavy dynamic content renders (cosmetic loss on fallback, but no crash)🤖 Generated with Claude Code
Problem
Three-panel console rendering crashed with MarkupError when judge/agent-generated text contained unescaped bracket characters, particularly in file paths. Isolated per-site escape() fixes didn't scale as new print sites were added.
Solution
Introduced
_SafeConsole, a Rich Console subclass that acts as a chokepoint for all console output. When markup parsing fails, it gracefully degrades by re-rendering withmarkup=Falseand escaped dynamic content, eliminating crashes whilst preserving normal styled output when markup is valid.Changes
_SafeConsoleclass with overriddenprint()method that catchesMarkupErrorand falls back to safe rendering. Replacedconsoleandconsole_errinstances with_SafeConsole().BaseThinkingLayoutto use_SafeConsoleinstead of raw Rich Console.Impact