Review M2b: accept with one follow-up task; record lessons
All ten tasks pass the checklist, the gate, the audit and the device checks, including a four-turn conversation with a loopd restart and no cache loss. Reading and probing found four low defects: the busy guard is released before the final frame on the main path but not on the three error paths, its Drop skips a poisoned lock, an unreadable core.md is treated as missing, and bxctl's interactive loop exits on a failed turn. Task 11 carries the fixes with two new tests, checked against a fixed copy of the branch. The Model column is filled in (all Ornith) and one malformed row is repaired. Two rules are promoted to AGENTS.md. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -57,6 +57,8 @@ fn fake_loopd(events: Vec<TurnEvent>, end: End) -> FakeLoopd {
|
||||
let id = request.id;
|
||||
let end = if turn.resume && turn.content == "trigger-no-such-session" {
|
||||
End::Error(ErrorCode::NoSuchSession, "session x does not exist")
|
||||
} else if turn.content == "trigger-turn-limit" {
|
||||
End::Error(ErrorCode::TurnLimit, "the turn hit a limit")
|
||||
} else {
|
||||
end.clone()
|
||||
};
|
||||
@@ -417,3 +419,45 @@ fn bad_arguments_print_usage() {
|
||||
.unwrap();
|
||||
assert_eq!(output.status.code(), Some(2));
|
||||
}
|
||||
|
||||
/// A failed turn is reported, and the conversation goes on: the session still exists and the
|
||||
/// next line is a new turn on it.
|
||||
#[test]
|
||||
fn interactive_mode_survives_a_failed_turn() {
|
||||
let fake = fake_loopd(
|
||||
vec![TurnEvent::Content {
|
||||
text: "ok".to_string(),
|
||||
}],
|
||||
End::Done(TurnDone {
|
||||
content: "ok".to_string(),
|
||||
usage: usage(),
|
||||
}),
|
||||
);
|
||||
let mut child = Command::new(env!("CARGO_BIN_EXE_bxctl"))
|
||||
.args(["chat", "--socket"])
|
||||
.arg(&fake.socket)
|
||||
.stdin(std::process::Stdio::piped())
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.stderr(std::process::Stdio::piped())
|
||||
.spawn()
|
||||
.unwrap();
|
||||
{
|
||||
let mut stdin = child.stdin.take().unwrap();
|
||||
std::io::Write::write_all(&mut stdin, b"first\ntrigger-turn-limit\nthird\n/quit\n")
|
||||
.unwrap();
|
||||
}
|
||||
let output = child.wait_with_output().unwrap();
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"a failed turn does not end the chat"
|
||||
);
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
assert!(
|
||||
stderr.contains("turn limit: the turn hit a limit"),
|
||||
"{stderr}"
|
||||
);
|
||||
let turns = fake.turns.lock().unwrap();
|
||||
assert_eq!(turns.len(), 3, "the turn after the failure was sent");
|
||||
assert!(turns[2].resume, "and it resumed the same session");
|
||||
assert_eq!(turns[2].session, turns[0].session);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user