Skip to content
Closed
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
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,14 @@ dist-manifest.json
.DS_Store

# CI artifacts
.homeboy-action/
/homeboy-ci-results/
.release-last-failed
/homeboy-observations/
/homeboy-test-shard.json
/homeboy-test-shard-plan.json
/homeboy-test-shard-inventory.json
/differential-phase/

# Keep Cargo.lock for reproducible builds
.phpunit.result.cache
88 changes: 11 additions & 77 deletions crates/homeboy-agents/tests/agent_task_handoff_reconnect.rs
Original file line number Diff line number Diff line change
@@ -1,103 +1,37 @@
use homeboy_agents::agent_task_lifecycle::{
record_detached_lab_run, record_lab_offload_planned, status, DetachedLabRunRecord,
LabOffloadProxyPlan,
record_detached_lab_run, record_lab_offload_planned, DetachedLabRunRecord, LabOffloadProxyPlan,
};
use homeboy_agents::agent_task_service::{
discover_runs, reconcile_stale_active_runs, AgentTaskDiscoveryFilter, AgentTaskLiveness,
discover_runs, AgentTaskDiscoveryFilter, AgentTaskLiveness,
};

struct EnvironmentGuard(Vec<(&'static str, Option<std::ffi::OsString>)>);

impl EnvironmentGuard {
fn isolated() -> Self {
let root = tempfile::tempdir().expect("temporary home");
let root = root.keep();
let values = [
("HOME", Some(root.clone().into_os_string())),
(
"XDG_CONFIG_HOME",
Some(root.join("config").into_os_string()),
),
("XDG_DATA_HOME", Some(root.join("data").into_os_string())),
(
"HOMEBOY_ARTIFACT_ROOT",
Some(root.join("artifacts").into_os_string()),
),
(
"HOMEBOY_RUNTIME_TMPDIR",
Some(root.join("runtime").into_os_string()),
),
(
"HOMEBOY_TEST_LAB_HANDOFF_ACCEPTANCE_TIMEOUT_SECONDS",
Some("0".into()),
),
];
let previous = values
.iter()
.map(|(name, value)| {
let prior = std::env::var_os(name);
std::env::set_var(name, value.as_ref().expect("test value"));
(*name, prior)
})
.collect();
Self(previous)
}
}

impl Drop for EnvironmentGuard {
fn drop(&mut self) {
for (name, value) in self.0.drain(..).rev() {
match value {
Some(value) => std::env::set_var(name, value),
None => std::env::remove_var(name),
}
}
}
}
use homeboy_core::test_support::HomeGuard;

#[test]
fn controller_handoff_remains_resolvable_and_reconciles_when_unaccepted() {
let _environment = EnvironmentGuard::isolated();
fn controller_proxy_remains_resolvable_after_detached_runner_acceptance() {
let _home = HomeGuard::new();
let command = vec![
"homeboy".to_string(),
"agent-task".to_string(),
"cook".to_string(),
];

record_lab_offload_planned(LabOffloadProxyPlan {
run_id: "unaccepted-handoff",
run_id: "accepted-handoff",
runner_id: "homeboy-lab",
remote_workspace: "/runner/workspace/homeboy",
remote_command: &command,
durable_plan: None,
})
.expect("persist controller proxy");

let active = discover_runs(AgentTaskDiscoveryFilter::Active).expect("discover unaccepted run");
let run = active.runs.first().expect("unaccepted run");
assert_eq!(run.liveness, Some(AgentTaskLiveness::Unreconciled));
let active =
discover_runs(AgentTaskDiscoveryFilter::Active).expect("discover controller proxy");
let run = active.runs.first().expect("controller proxy");
assert_eq!(
run.commands.status,
"homeboy agent-task status unaccepted-handoff"
);

let reconciled = reconcile_stale_active_runs(false).expect("reconcile unaccepted handoff");
assert_eq!(reconciled.reconciled, 1);
assert_eq!(
status("unaccepted-handoff")
.expect("terminal controller record")
.state,
homeboy_agents::agent_task_lifecycle::AgentTaskRunState::Cancelled
"homeboy --placement local agent-task status accepted-handoff"
);

record_lab_offload_planned(LabOffloadProxyPlan {
run_id: "accepted-handoff",
runner_id: "homeboy-lab",
remote_workspace: "/runner/workspace/homeboy",
remote_command: &command,
durable_plan: None,
})
.expect("persist second controller proxy");
record_detached_lab_run(DetachedLabRunRecord {
run_id: "accepted-handoff",
runner_id: "homeboy-lab",
Expand All @@ -117,6 +51,6 @@ fn controller_handoff_remains_resolvable_and_reconciles_when_unaccepted() {
assert_eq!(run.runner_job_id.as_deref(), Some("accepted-daemon-job"));
assert_eq!(
run.commands.status,
"homeboy agent-task status accepted-handoff"
"homeboy --placement local agent-task status accepted-handoff"
);
}
1 change: 1 addition & 0 deletions crates/homeboy-cli/src/commands/agent_task/review.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1838,6 +1838,7 @@ mod tests {
candidate_ref: "deadbeef".to_string(),
ai_model: Some("openai/gpt-5.6-terra".to_string()),
replace_interrupted: false,
accept_inherited_failures: false,
full: false,
};

Expand Down
Loading
Loading