diff --git a/swarm-controller/src/config_pr.rs b/swarm-controller/src/config_pr.rs index 913b3607..a94c7da7 100644 --- a/swarm-controller/src/config_pr.rs +++ b/swarm-controller/src/config_pr.rs @@ -93,17 +93,6 @@ impl ConfigPrCache { .cloned() } - /// Every agent with an open PR, per the last successful scan (plus any - /// webhook upserts since). The bulk counterpart to [`Self::get`] — for - /// `GET /api/config-prs` (swarm-ui's config-PR table), which needs every - /// agent's status in one round trip rather than one request per agent. - pub fn snapshot(&self) -> HashMap { - self.0 - .lock() - .unwrap_or_else(std::sync::PoisonError::into_inner) - .clone() - } - /// ⚠️ Can race [`Self::apply_webhook_delivery`]: a scan started before a /// PR opened may finish *after* the webhook already upserted it, and /// this snapshot — taken before that PR existed — will overwrite the @@ -232,21 +221,6 @@ mod tests { assert_eq!(status.pr_number, 6); } - #[test] - fn snapshot_returns_every_agent_with_an_open_pr() { - let cache = ConfigPrCache::new(); - assert!( - cache.snapshot().is_empty(), - "an unpopulated cache snapshots empty, not missing" - ); - cache.apply_webhook_delivery(&payload("damocles", 5, "open")); - cache.apply_webhook_delivery(&payload("iris", 9, "open")); - let snapshot = cache.snapshot(); - assert_eq!(snapshot.len(), 2); - assert_eq!(snapshot["damocles"].pr_number, 5); - assert_eq!(snapshot["iris"].pr_number, 9); - } - #[test] fn a_malformed_payload_leaves_the_cache_unchanged() { let cache = ConfigPrCache::new(); diff --git a/swarm-controller/src/main.rs b/swarm-controller/src/main.rs index 0e939810..a9a578aa 100644 --- a/swarm-controller/src/main.rs +++ b/swarm-controller/src/main.rs @@ -804,43 +804,6 @@ async fn get_agent_config_pr( Ok(Json(cache.get(&name))) } -/// Every agent with an open config PR, in one response — the bulk -/// counterpart to [`get_agent_config_pr`]. swarm-ui's config-PR table needs -/// every agent's status to render, and fetching them one at a time doesn't -/// scale and isn't how the rest of swarm-ui's single-fetch pages (jobq, -/// hives status) work. -/// -/// Deliberately **not** `/api/agents/config-prs`: agent names are -/// user-specified (any string `hive_types::Ident` accepts), so a literal -/// path segment sitting where a `{name}` capture could plausibly also want -/// to live is a real, not theoretical, clash risk the moment someone names -/// an agent `config-prs` — per mara's review call, closed off by -/// construction rather than relying on axum's static-route-priority -/// tiebreak to paper over it. -/// -/// Only agents with a currently-open PR are present — same "absence is the -/// answer" shape [`get_agent_config_pr`]'s `null` uses, just at map-entry -/// granularity instead of per-request. -#[utoipa::path( - get, - path = "/api/config-prs", - responses( - (status = 200, description = "agent name -> open config PR, only agents with one present", body = std::collections::HashMap), - (status = 503, description = "no forge is configured on this host", body = String), - ), - tag = "agents" -)] -async fn get_config_prs( - State(state): State, -) -> Result>, StatusUnavailable> { - let Some(cache) = state.config_prs.as_ref() else { - return Err(StatusUnavailable( - "no forge is configured on this host".to_owned(), - )); - }; - Ok(Json(cache.snapshot())) -} - /// The swarm's own public base URL, as the forge must address it. /// /// Set by `swarm-controller.nix` **only when this host actually serves the @@ -1042,7 +1005,6 @@ async fn main() -> Result<()> { .routes(routes!(get_jobq_graph)) .routes(routes!(get_jobq_rollup)) .routes(routes!(get_agent_config_pr)) - .routes(routes!(get_config_prs)) .routes(routes!(create_agent)) .routes(routes!(webhook::post_webhook_forge)) .split_for_parts();