Skip to content

Commit 7f66670

Browse files
committed
fix(board): classify harness error banners and empty output as failed
Dev smoke test: opencode session errors surface as a successful turn whose output is an error banner, which settled tasks as SUCCESS. Match known banners at the start of the final message (Error:, [session.error], [MAIN] SESSION.ERROR, Session ended with error) and empty output as failed so the retry/digest path engages.
1 parent fc083b6 commit 7f66670

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

src/api/control/board.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,24 @@ pub fn classify_outcome(
9696
if failed {
9797
return BoardTaskOutcome::Failed;
9898
}
99+
// Harness-level failures can surface as a "successful" turn whose entire
100+
// output is an error banner (e.g. opencode session errors arrive via
101+
// stderr text, not terminal_reason — observed in the dev smoke test).
102+
// Only match banners at the very start so a legit summary that merely
103+
// mentions errors isn't misclassified.
104+
let trimmed = output.trim();
105+
if trimmed.is_empty() {
106+
return BoardTaskOutcome::Failed;
107+
}
108+
const ERROR_BANNERS: [&str; 4] = [
109+
"Error:",
110+
"[session.error]",
111+
"[MAIN] SESSION.ERROR",
112+
"Session ended with error",
113+
];
114+
if ERROR_BANNERS.iter().any(|b| trimmed.starts_with(b)) {
115+
return BoardTaskOutcome::Failed;
116+
}
99117
// Worker contract: a stuck worker ends its turn with a line starting
100118
// "BLOCKED". Look near the start of the final message.
101119
let head: String = output.trim_start().chars().take(600).collect();
@@ -618,6 +636,28 @@ mod tests {
618636
classify_outcome(Some(TerminalReason::Stalled), false, "whatever"),
619637
BoardTaskOutcome::Failed
620638
);
639+
// Harness error banners masquerading as a successful turn.
640+
assert_eq!(
641+
classify_outcome(
642+
Some(TerminalReason::TurnComplete),
643+
true,
644+
"Error: Unexpected error, check log file at /root/.local/share/opencode/log"
645+
),
646+
BoardTaskOutcome::Failed
647+
);
648+
assert_eq!(
649+
classify_outcome(Some(TerminalReason::TurnComplete), true, " "),
650+
BoardTaskOutcome::Failed
651+
);
652+
// A summary that merely mentions an error is still a success.
653+
assert_eq!(
654+
classify_outcome(
655+
Some(TerminalReason::TurnComplete),
656+
true,
657+
"Done. Fixed the Error: handling path and verified with cargo test."
658+
),
659+
BoardTaskOutcome::Success
660+
);
621661
assert_eq!(classify_outcome(None, false, "x"), BoardTaskOutcome::Failed);
622662
assert_eq!(
623663
classify_outcome(Some(TerminalReason::Completed), true, "done"),

0 commit comments

Comments
 (0)