swarm-controller: bulk-read endpoint for agent config-PR status

This commit is contained in:
damocles 2026-08-19 21:51:55 +02:00
commit 9067ba52a9
2 changed files with 57 additions and 0 deletions

View file

@ -93,6 +93,18 @@ 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/agents/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<String, ConfigPrStatus> {
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
@ -221,6 +233,21 @@ 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();