diff --git a/hive-c0re/src/lifecycle/mod.rs b/hive-c0re/src/lifecycle/mod.rs index a93edadd..0e9045ba 100644 --- a/hive-c0re/src/lifecycle/mod.rs +++ b/hive-c0re/src/lifecycle/mod.rs @@ -250,6 +250,16 @@ pub async fn create_container(name: &str, hive: &HiveEnv, paths: &AgentPaths) -> /// Rebuild-path preamble, run by the job queue's `Prebuild` node: fail fast on /// a port collision, then make sure the applied repo + state dirs exist. /// Container untouched. +/// +/// `applied` is normally already the right shape here (this runs against a +/// previously-provisioned agent), but a `destroy --purge` removes it +/// (`job_queue::exec::run_purge_state`) — a later revive of the *same* +/// agent name is still a rebuild, not a first-spawn, so it lands here, not +/// in `provision_container`. Pass `proposed` as a reseed source (same shape +/// `setup_applied` already uses on first-spawn) whenever it still exists on +/// disk, so that case recovers instead of bailing — only fall back to the +/// no-source `None` (and `setup_applied`'s existing clear bail) when +/// `proposed` is also gone, which is the genuinely unrecoverable case. pub async fn prepare_rebuild_dirs(name: &str, paths: &AgentPaths) -> Result<()> { validate(name)?; if let Some(other) = port_collision(name).await { @@ -258,7 +268,8 @@ pub async fn prepare_rebuild_dirs(name: &str, paths: &AgentPaths) -> Result<()> agent_web_port(name) ); } - setup_applied(&paths.applied, None, name).await?; + let reseed_from = paths.proposed.exists().then_some(paths.proposed.as_path()); + setup_applied(&paths.applied, reseed_from, name).await?; ensure_agent_state_subvolume(name).await?; ensure_claude_dir(&paths.claude)?; ensure_state_dir(&paths.notes)?;