Watch
0
0
Fork
You've already forked hyperhive
0

drop the proposed config repo: applied seeds from forge main, and the dead pending-init topology list goes with it

This commit is contained in:
damocles 2026-11-01 14:25:46 +01:00 • committed by mara
commit 25295fd33f

View file

@ -1,5 +1,5 @@
//! Startup convergence. Three phases, all idempotent and unguarded:
//! harness files, applied + proposed repos, the agent-set files, plus the
//! harness files, the applied repos, the agent-set files, plus the
//! removal of the legacy meta repo's leftovers. They re-run every
//! boot on purpose — each one is a no-op once its state is already
//! correct.
@ -80,10 +80,10 @@ pub async fn run() -> Result<()> {
Err(e) => tracing::warn!(error = ?e, "migration: removing the legacy meta .git failed"),
}
// Phase 1 + 2: per-agent applied + proposed.
tracing::debug!("migration: phase 1+2 (applied + proposed repos)");
// An archetype agent has neither repo, and seeding one here would hand it
// a config it is not built from.
// Phase 1 + 2: per-agent applied repo.
tracing::debug!("migration: phase 1+2 (applied repo)");
// An archetype agent has no applied repo, and seeding one here would hand
// it a config it is not built from.
let archetypes = crate::archetypes::read_at(&crate::archetypes::path()).unwrap_or_else(|e| {
tracing::warn!(error = ?e, "migration: stored archetypes unreadable; treating every agent as custom");
crate::archetypes::Stored::new()
@ -92,26 +92,10 @@ pub async fn run() -> Result<()> {
if archetypes.contains_key(name.as_str()) {
continue;
}
tracing::debug!(%name, "migration: applied+proposed");
tracing::debug!(%name, "migration: applied");
if let Err(e) = migrate_applied_repo(name.as_str()).await {
tracing::warn!(%name, error = ?e, "migration: applied repo rewrite failed");
}
let proposed_dir = Coordinator::agent_proposed_dir(name);
match remove_meta_remote(&proposed_dir).await {
Ok(true) => tracing::info!(%name, "migration: removed the legacy meta remote"),
Ok(false) => {}
Err(e) => {
tracing::warn!(%name, error = ?e, "migration: removing the meta remote failed");
}
}
let proposed = lifecycle::setup_proposed(&proposed_dir, name.as_str());
match tokio::time::timeout(GIT_TIMEOUT, proposed).await {
Ok(Err(e)) => tracing::warn!(%name, error = ?e, "migration: setup_proposed failed"),
Err(_) => {
tracing::warn!(%name, timeout = ?GIT_TIMEOUT, "migration: setup_proposed timed out — skipping");
}
Ok(Ok(())) => {}
}
}
// Phase 3: the files that follow the agent set.
@ -190,19 +174,6 @@ fn remove_core_token(state: &Path) -> Result<bool> {
}
}
/// Remove the `meta` remote from the proposed repo at `dir`. `true` when it
/// was there; a missing remote, or a `dir` that is no repo, is `false`.
async fn remove_meta_remote(dir: &Path) -> Result<bool> {
let mut cmd = lifecycle::git_command();
cmd.current_dir(dir).args(["remote", "get-url", "meta"]);
let probe = output_with_timeout(cmd, GIT_TIMEOUT, "git remote get-url meta").await?;
if !probe.status.success() {
return Ok(false);
}
raw_git(dir, &["remote", "remove", "meta"]).await?;
Ok(true)
}
async fn enumerate_agents() -> Result<Vec<hive_types::Ident>> {
let containers = lifecycle::list().await?;
Ok(containers
@ -329,35 +300,6 @@ mod tests {
assert!(dir.path().join("topology.json").exists());
}
#[tokio::test]
async fn meta_remote_goes_and_the_others_stay() {
let dir = tempfile::tempdir().expect("tempdir");
raw_git(dir.path(), &["init", "-q", "--initial-branch=main"])
.await
.expect("init");
for (name, url) in [
("meta", "http://forge/core/meta.git"),
("applied", "/applied/x/.git"),
] {
raw_git(dir.path(), &["remote", "add", name, url])
.await
.expect("add remote");
}
assert!(remove_meta_remote(dir.path()).await.expect("first"));
let remotes = lifecycle::git_command()
.current_dir(dir.path())
.arg("remote")
.output()
.await
.expect("list");
assert_eq!(String::from_utf8_lossy(&remotes.stdout).trim(), "applied");
assert!(
!remove_meta_remote(dir.path()).await.expect("second"),
"no-op"
);
}
#[test]
fn core_token_goes_once_and_its_neighbours_stay() {
let dir = tempfile::tempdir().expect("tempdir");
@ -370,12 +312,6 @@ mod tests {
assert!(!remove_core_token(dir.path()).expect("second"), "no-op");
}
#[tokio::test]
async fn a_dir_that_is_no_repo_has_no_meta_remote() {
let dir = tempfile::tempdir().expect("tempdir");
assert!(!remove_meta_remote(dir.path()).await.expect("probe"));
}
#[tokio::test]
async fn unreadable_flake_is_left_untouched() {
let dir = tempfile::tempdir().expect("tempdir");