fix(daemon): prefer stderr over stale stdout in gateway restart diagnostics#93001
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 14, 2026, 10:07 PM ET / 02:07 UTC. Summary PR surface: Source +3, Tests +17. Total +20 across 2 files. Reproducibility: yes. Source inspection gives a high-confidence reproduction path: seed matching stdout and stderr gateway logs on Linux and call Review metrics: none identified. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Next step before merge
Security Review detailsBest possible solution: Land the focused helper-order change after ordinary maintainer review, keeping Do we have a high-confidence way to reproduce the issue? Yes. Source inspection gives a high-confidence reproduction path: seed matching stdout and stderr gateway logs on Linux and call Is this the best way to solve the issue? Yes. The helper owns the selection that all visible callers print, so reversing the combined log order is the narrow maintainable fix; timestamp parsing would be a larger contract change than the current stderr-priority behavior needs. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 44e6caff5401. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +3, Tests +17. Total +20 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
Strengthened the proof to a real-runtime run (beyond the Vitest unit case): seeded real gateway logs at the After fix it returns the stderr line ( @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
Summary
readLastGatewayErrorLine(src/daemon/diagnostics.ts) surfaces the most relevant gateway error line for daemon restart diagnostics (shown instatus/doctor). On non-darwin platforms it reads both stderr and stdout, builds[...stderrRaw.split, ...stdoutRaw.split], then scans from the end. Because stdout is appended last, scanning backwards walks the entire stdout block before reaching any stderr line — so any (even stale) stdout match wins over a newer stderr match. This contradicts the function's own comment ("stderr [is] the strongest failure signal" on non-darwin) and its stderr-first fallback. The existing test only covered the darwin branch (stderr suppressed), so the linux/win32 two-log merge path was uncovered.What changed
[...stdoutRaw.split, ...stderrRaw.split]) so the backward scan reaches the most recent stderr error first, with stdout as the fallback — matching the comment and the stderr-first fallback below. The darwin (stderr-suppressed) behavior is unchanged.Real behavior proof
status/doctorusers at an outdated cause.resolveGatewayLogPaths(env)resolves to ($STATE/logs/gateway.log= stdout with a stale matching line;$STATE/logs/gateway.err.log= stderr with the newer real failure), then drove the real exportedreadLastGatewayErrorLinevianode --import tsx— no mocks; the production function reads the on-disk logs. This returns the exact valuestatusprints asLast gateway error:(status.gather.ts:709→status.print.ts:440) anddoctorprints vianote("Last gateway error: …")(doctor-gateway-daemon-flow.ts:290).status/doctorwould print.src/daemon/diagnostics.test.ts) also asserts this for linux while keeping the darwin stderr-suppressed case.openclaw daemon statusCLI process end-to-end — in this isolated sandbox a from-scratch CLI build is blocked by native postinstall binaries (e.g.@matrix-org/matrix-sdk-crypto-nodejs,node-llama-cpp) downloaded from GitHub Releases timing out. The proof instead drives the exact production function those commands call, against real on-disk logs (real runtime, not a test double).diagnostics.tsto the pre-fix[...stderr, ...stdout]order (git checkout 357000c8^ -- src/daemon/diagnostics.ts) and re-running the same command prints the stale stdout line instead:Tests and validation
node --import tsxdriving the realreadLastGatewayErrorLineon seeded on-disk gateway logs → returns the stderr line (after fix) / the stale stdout line (pre-fix negative control).node scripts/run-vitest.mjs src/daemon/diagnostics.test.ts→ 2 passed (added a linux case asserting stderr wins over a stale stdout match; the existing darwin case still passes). The non-darwin two-log path previously had no coverage.oxfmt --writeclean on both changed files.Risk checklist
status/doctornow report the stderr failure reason on non-darwin instead of a possibly stale stdout line.