From 717086b02df2dedd6db98e1f20af3639edbc45e8 Mon Sep 17 00:00:00 2001 From: damocles Date: Thu, 21 May 2026 22:14:41 +0200 Subject: [PATCH] forge_notify: HIVE_FORGE_KEEP_SUBSCRIPTIONS=1 disables auto-unsubscribe --- hive-ag3nt/src/forge_notify.rs | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/hive-ag3nt/src/forge_notify.rs b/hive-ag3nt/src/forge_notify.rs index 35785bb..d36e1bc 100644 --- a/hive-ag3nt/src/forge_notify.rs +++ b/hive-ag3nt/src/forge_notify.rs @@ -81,13 +81,28 @@ pub async fn run(socket: PathBuf, is_manager: bool) { // socket becoming available right at boot. interval.tick().await; + // HIVE_FORGE_KEEP_SUBSCRIPTIONS=1 disables auto-unsubscribe for agents + // that intentionally consume the full repo notification firehose (e.g. triage). + let keep_subscriptions = std::env::var("HIVE_FORGE_KEEP_SUBSCRIPTIONS") + .map(|v| v == "1" || v.eq_ignore_ascii_case("true")) + .unwrap_or(false); + // Repos we have already unsubscribed this process lifetime. Persists // across polls so we don't hammer DELETE on every cycle. let mut unsubbed_repos: HashSet = HashSet::new(); loop { interval.tick().await; - poll_once(&client, &forge_url, &token, &socket, is_manager, &mut unsubbed_repos).await; + poll_once( + &client, + &forge_url, + &token, + &socket, + is_manager, + keep_subscriptions, + &mut unsubbed_repos, + ) + .await; } } @@ -233,6 +248,7 @@ async fn poll_once( token: &str, socket: &Path, is_manager: bool, + keep_subscriptions: bool, unsubbed_repos: &mut HashSet, ) { let url = format!("{forge_url}/api/v1/notifications?all=false&limit=50"); @@ -323,14 +339,12 @@ async fn poll_once( } } - // Auto-unsubscribe from broad repo watches. If the notification - // reason is "subscribed" (agent is watching the whole repo) and - // the agent has no personal stake (was just watching), drop the - // watch subscription so we don't accumulate firehose noise from - // repos we contributed to but are no longer actively working in. - // Thread-level subscriptions (specific issue/PR) are unaffected. + // Auto-unsubscribe from broad repo watches when the notification + // reason is "subscribed" (agent watching the whole repo). Skipped + // when HIVE_FORGE_KEEP_SUBSCRIPTIONS=1 — triage and other firehose + // consumers set this to retain broad repo visibility. let reason = notif["reason"].as_str().unwrap_or(""); - if reason == "subscribed" { + if !keep_subscriptions && reason == "subscribed" { if let Some(repo) = notif["repository"]["full_name"].as_str() { if !unsubbed_repos.contains(repo) { let unsub_url = format!("{forge_url}/api/v1/repos/{repo}/subscription");