revive: reseed applied from forge main, no proposed fallback

This commit is contained in:
damocles 2026-08-18 00:02:48 +02:00 committed by mara
commit 07d3d3060e
3 changed files with 96 additions and 8 deletions

View file

@ -255,11 +255,15 @@ pub async fn create_container(name: &str, hive: &HiveEnv, paths: &AgentPaths) ->
/// 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.
/// in `provision_container`. Recover from `agent-configs/<name>` on the
/// forge when that's the case (kept current after every deploy by
/// `forge::push_config` — see `forge::fetch_config_main_into_applied`'s own
/// doc comment) rather than bailing outright. Deliberately **no fallback to
/// `proposed`**: that repo is seeded once at first spawn and never touched
/// again (`setup_proposed`'s own doc comment), so it can be arbitrarily
/// stale for a long-lived agent — restoring from it would silently revive
/// the *wrong* config rather than recovering the right one, which is worse
/// than the clear bail this replaces.
pub async fn prepare_rebuild_dirs(name: &str, paths: &AgentPaths) -> Result<()> {
validate(name)?;
if let Some(other) = port_collision(name).await {
@ -268,8 +272,17 @@ pub async fn prepare_rebuild_dirs(name: &str, paths: &AgentPaths) -> Result<()>
agent_web_port(name)
);
}
let reseed_from = paths.proposed.exists().then_some(paths.proposed.as_path());
setup_applied(&paths.applied, reseed_from, name).await?;
if !paths.applied.join(".git").exists()
&& !crate::forge::fetch_config_main_into_applied(name).await
{
bail!(
"applied repo at {} is missing its .git directory and could not be reseeded from \
the forge (agent-configs/{name} unreachable, not yet mirrored, or absent); \
destroy --purge and re-spawn this agent.",
paths.applied.display()
);
}
setup_applied(&paths.applied, None, name).await?;
ensure_agent_state_subvolume(name).await?;
ensure_claude_dir(&paths.claude)?;
ensure_state_dir(&paths.notes)?;