Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
use super::*;
use crate::LineMutation;

/// Both arming witnesses for the mid-turn flip halt (#1793), and the shell
/// doubles they share.
/// Both arming paths of the mid-turn flip halt (#1793), and the two doubles
/// they share. A child rather than a sibling module so it still reaches this
/// file's scripted ports through `use super::*`, and so the already-oversized
/// `tests.rs` does not grow another module declaration.
///
/// A child rather than a sibling module so the already-oversized `tests.rs`
/// does not grow another module declaration. The doubles deliberately live
/// *inside* it rather than here: see that file's own module doc for why
/// colocating them with the two witnesses is what turns a wholesale rewrite
/// of this parent into a merge conflict instead of a silent deletion.
/// The doubles live in the child with their only users, not here: when they
/// sat in this file, a wholesale rewrite of it took them and the
/// configured-command witness with them, and no gate objected (#1997).
mod flip_halt_arming;

/// #860 acceptance: a baseline that TIMES OUT observed no failing assertion,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,55 @@

use super::*;

/// The shell tool both witnesses script their revision against.
///
/// A distinct name from [`WRITING_TOOL`] because the two fakes answer
/// differently and a flip must be attributable: only this one emits the exit
/// marker [`crate::flip_halt::exit_status`] reads.
const SHELL_TOOL: &str = "bash";

/// One model turn that runs `command` through the shell tool.
///
/// The `command` key is what [`crate::flip_halt::command_of`] looks for, so a
/// call built any other way would be invisible to the halt and the test would
/// pass for the wrong reason.
fn shell_call_result(command: &str) -> CompletionResult {
CompletionResult {
tool_calls: vec![ToolCall {
call_id: "call-shell".into(),
name: SHELL_TOOL.into(),
input: serde_json::json!({ "command": command }),
}],
..text_result("")
}
}

/// A shell whose every command succeeds, reported the way the real bash tool
/// reports it — the trailing `[exit code: 0]` marker.
///
/// That marker is the whole point: [`crate::flip_halt::FlipHalt::observe`]
/// latches only on a tracked command that exited zero, and output without a
/// marker can never stop a turn. A fake returning bare prose would leave the
/// halt unlatched and the arming test green for no reason.
struct PassingShell;
#[async_trait]
impl ToolExecutor for PassingShell {
fn schemas(&self) -> Vec<ToolSchema> {
vec![ToolSchema {
name: SHELL_TOOL.into(),
description: "run a shell command".into(),
input_schema: serde_json::json!({ "type": "object" }),
read_only: false,
speculation_safe: false,
}]
}
async fn execute(&self, _name: &str, _input: &Value) -> ToolOutput {
ToolOutput::Ok {
content: "ok\n[exit code: 0]".into(),
}
}
}

/// #1793 witness (authored side): after `witness_on_demand` seeds a failing
/// witness, a revision that observes the witness command pass halts at that
/// step boundary. As in the configured-command twin, the provider is
Expand Down Expand Up @@ -114,42 +163,6 @@ async fn an_authored_witness_arms_the_revision_flip_halt() {
flipped, not spend the scripted steps beyond it"
);
}
/// A shell double whose every command "passes": the output carries the
/// trailing exit-0 marker [`crate::flip_halt::exit_status`] parses. What
/// [`EmptyTools`] can never express — a worker *observing* the tracked test
/// succeed through a tool result.
struct PassingShell;
#[async_trait]
impl ToolExecutor for PassingShell {
fn schemas(&self) -> Vec<ToolSchema> {
vec![ToolSchema {
name: "bash".into(),
description: "run a shell command".into(),
input_schema: serde_json::json!({ "type": "object" }),
read_only: false,
speculation_safe: false,
}]
}
async fn execute(&self, _name: &str, _input: &Value) -> ToolOutput {
ToolOutput::Ok {
content: "1 passed\n[exit code: 0]".into(),
}
}
}

/// A completion that runs `command` through the shell — the observation the
/// flip halt correlates by `call_id` and scores against the tracked test.
fn shell_call_result(command: &str) -> CompletionResult {
CompletionResult {
tool_calls: vec![ToolCall {
call_id: format!("call-shell-{command}"),
name: "bash".into(),
input: serde_json::json!({ "command": command }),
}],
..text_result("")
}
}

/// #1793 witness (configured-command side): a revision that observes the
/// tracked test go fail→pass halts at that step boundary instead of running
/// on. The provider is scripted with steps BEYOND the flip; consuming them
Expand Down
3 changes: 1 addition & 2 deletions crates/stella-protocol/src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -542,8 +542,7 @@ pub enum AgentEvent {
/// The replacement bytes each in-place rewrite left behind, one entry
/// per digest — what lets reconstruction resolve a compacted block to
/// the bytes the model received rather than the pre-compaction output
/// under the same `call_id` (#1667); see
/// [`CompactionRewrite`](crate::CompactionRewrite).
/// under the same `call_id` (#1667); see [`crate::CompactionRewrite`].
/// `serde(default)` — absent on journals written before rewrites were
/// journaled, whose compacted blocks surface as digest mismatches.
#[serde(default, skip_serializing_if = "Vec::is_empty")]
Expand Down
Loading