use rusqlite::Connection;
use std::path::Path;
use tempfile::TempDir;
mod common;
use common::aid_cmd_in;
#[test]
fn fresh_codex_0147_accepts_native_permissions() {
assert_fresh_codex_succeeds("t-current-codex-approval", false);
}
#[test]
fn fresh_codex_0146_accepts_native_permissions() {
assert_fresh_codex_succeeds("t-legacy-codex-approval", true);
}
#[test]
fn exact_short_answer_is_a_successful_delivery() {
let aid_home = TempDir::new().unwrap();
let bin_dir = TempDir::new().unwrap();
write_fake_codex(bin_dir.path());
let output = aid_cmd_in(aid_home.path())
.env("PATH", test_path(bin_dir.path()))
.env("FAKE_CODEX_SHORT_FINAL", "1")
.args([
"run",
"codex",
"Reply with the single word: ok",
"--id",
"t-short-final",
])
.output()
.unwrap();
assert!(
output.status.success(),
"stdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
let conn = Connection::open(aid_home.path().join("aid.db")).unwrap();
assert_eq!(task_facts(&conn, "t-short-final").0, "done");
}
#[test]
fn missing_explicit_result_file_fails_on_the_artifact_contract() {
assert_missing_explicit_result_file_fails(false);
}
#[test]
fn missing_explicit_result_file_fails_in_background_on_the_artifact_contract() {
assert_missing_explicit_result_file_fails(true);
}
fn assert_missing_explicit_result_file_fails(background: bool) {
let aid_home = TempDir::new().unwrap();
let bin_dir = TempDir::new().unwrap();
write_fake_codex(bin_dir.path());
let mut command = aid_cmd_in(aid_home.path());
command
.env("PATH", test_path(bin_dir.path()))
.env("FAKE_CODEX_SHORT_FINAL", "1")
.args([
"run",
"codex",
"Reply with the single word: ok",
"--result-file",
"required-result.md",
"--id",
"t-missing-required-result",
]);
if background {
command.arg("--bg");
}
let output = command.output().unwrap();
assert_eq!(
output.status.success(),
background,
"stdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
if background {
let wait = aid_cmd_in(aid_home.path())
.args(["wait", "--timeout", "5", "t-missing-required-result"])
.output()
.unwrap();
assert_eq!(
wait.status.code(),
Some(1),
"background task unexpectedly succeeded"
);
}
let conn = Connection::open(aid_home.path().join("aid.db")).unwrap();
let facts = task_facts(&conn, "t-missing-required-result");
assert_eq!(facts.0, "failed");
assert_eq!(facts.1.as_deref(), Some("missing_final_delivery"));
}
fn assert_fresh_codex_succeeds(task_id: &str, legacy: bool) {
let aid_home = TempDir::new().unwrap();
let bin_dir = TempDir::new().unwrap();
write_fake_codex(bin_dir.path());
let mut command = aid_cmd_in(aid_home.path());
command
.env("PATH", test_path(bin_dir.path()))
.env("FAKE_CODEX_FINAL_ON_FRESH", "1");
if legacy {
command.env("FAKE_CODEX_LEGACY", "1");
}
let output = command
.args([
"run",
"codex",
"Implement and report the requested change",
"--id",
task_id,
])
.output()
.unwrap();
assert!(
output.status.success(),
"stdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
let conn = Connection::open(aid_home.path().join("aid.db")).unwrap();
assert_eq!(task_facts(&conn, task_id).0, "done");
}
#[test]
fn missing_final_delivery_fails_parent_and_resumes_once() {
let aid_home = TempDir::new().unwrap();
let bin_dir = TempDir::new().unwrap();
write_fake_codex(bin_dir.path());
let path = format!(
"{}:{}",
bin_dir.path().display(),
std::env::var("PATH").unwrap_or_default()
);
let home = home_with_seeded_rollout();
let workspace = TempDir::new().unwrap();
let output = aid_cmd_in(aid_home.path())
.current_dir(workspace.path())
.env("PATH", path)
.env("HOME", home.path())
.args([
"run",
"codex",
"Investigate and report the result",
"--read-only",
"--id",
"t-delivery-parent",
])
.output()
.unwrap();
assert!(
output.status.success(),
"stdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
let conn = Connection::open(aid_home.path().join("aid.db")).unwrap();
let parent = task_facts(&conn, "t-delivery-parent");
assert_eq!(parent.0, "failed");
assert_eq!(parent.1.as_deref(), Some("missing_final_delivery"));
let child = child_facts(&conn, "t-delivery-parent");
assert_eq!(child.0, "done");
assert_eq!(child.1, 1);
}
#[test]
fn repeated_missing_delivery_does_not_start_third_attempt() {
let aid_home = TempDir::new().unwrap();
let bin_dir = TempDir::new().unwrap();
write_fake_codex(bin_dir.path());
let home = home_with_seeded_rollout();
let workspace = TempDir::new().unwrap();
let output = aid_cmd_in(aid_home.path())
.current_dir(workspace.path())
.env("PATH", test_path(bin_dir.path()))
.env("HOME", home.path())
.env("FAKE_CODEX_HOLLOW_RESUME", "1")
.args([
"run",
"codex",
"Investigate and report the result",
"--read-only",
"--id",
"t-delivery-repeat",
])
.output()
.unwrap();
assert!(
!output.status.success(),
"repeated hollow delivery must fail"
);
let conn = Connection::open(aid_home.path().join("aid.db")).unwrap();
let facts: (i64, i64) = conn
.query_row(
"SELECT COUNT(*), SUM(status = 'failed') FROM tasks",
[],
|row| Ok((row.get(0)?, row.get(1)?)),
)
.unwrap();
assert_eq!(facts, (2, 2));
}
const FIXTURE_SESSION_ID: &str = "019e3e49-6b83-7563-a3d8-b51a3a716dd1";
fn home_with_seeded_rollout() -> TempDir {
let home = TempDir::new().unwrap();
let sessions = home.path().join(".codex/sessions/2026/08/09");
std::fs::create_dir_all(&sessions).unwrap();
std::fs::write(
sessions.join(format!(
"rollout-2026-08-09T00-00-00-{FIXTURE_SESSION_ID}.jsonl"
)),
"{\"type\":\"turn_context\",\"model\":\"gpt-5.6-sol\"}\n",
)
.unwrap();
home
}
fn task_facts(conn: &Connection, task_id: &str) -> (String, Option<String>) {
conn.query_row(
"SELECT status, delivery_assessment FROM tasks WHERE id = ?1",
[task_id],
|row| Ok((row.get(0)?, row.get(1)?)),
)
.unwrap()
}
fn child_facts(conn: &Connection, parent_id: &str) -> (String, i64) {
conn.query_row(
"SELECT status, COUNT(*) OVER () FROM tasks WHERE parent_task_id = ?1",
[parent_id],
|row| Ok((row.get(0)?, row.get(1)?)),
)
.unwrap()
}
fn write_fake_codex(dir: &Path) {
let path = dir.join("codex");
common::write_executable(&path, include_str!("fixtures/codex-delivery-cli.sh"));
}
fn test_path(bin_dir: &Path) -> String {
format!(
"{}:{}",
bin_dir.display(),
std::env::var("PATH").unwrap_or_default()
)
}