From b2822246cba10a6691b8f8b9030e67a367718e83 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 10 Jul 2026 17:42:36 +0000 Subject: [PATCH 1/3] slack bridge: self-heal channels resolved after startup (#677) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The bridge resolved each agent's Slack channel once at startup and skipped (never retried) any that didn't resolve. A channel created — or the bot invited — AFTER the bridge last restarted was therefore never mirrored until a manual `systemctl restart agents-slack-bridge`. config-sync restarts the bridge on a roster add, but that restart fires before the channel exists (the human creates the channel + invites the bot afterward), so every newly-added agent hit this. Fix: keep unresolved agents in a `pending` set and retry them against a fresh conversations.list snapshot on a self-rescheduling timer (not setInterval — overlapping ticks could double-append a tail), gating promotion on bot MEMBERSHIP (is_member): a public channel is listed before the bot is invited, so resolving on mere presence would mirror a channel the bot can't post to (not_in_channel) — the exact silent-agent symptom. New tails/mapping are appended live (read by reference by the poll loop + inbound router), so a late resolve needs no restart. The picker loop now reads `tails` live so a late-resolved Claude agent gets pickers too. - src/slack/reresolve.ts: pure matchPendingChannels (membership-gated, promote-once) - src/slack/client.ts: listChannels() one-shot snapshot (id/name/is_member) - src/slack/bridge.ts: pending set + self-rescheduling resolver + picker heal - src/slack-reresolve.test.ts: 9 tests incl. the is_member falsifiability case Co-Authored-By: Claude Opus 4.8 --- cli/src/slack-reresolve.test.ts | 95 +++++++++++++++++++++++++++++++++ cli/src/slack/bridge.ts | 91 +++++++++++++++++++++++++++---- cli/src/slack/client.ts | 35 ++++++++++++ cli/src/slack/reresolve.ts | 54 +++++++++++++++++++ 4 files changed, 264 insertions(+), 11 deletions(-) create mode 100644 cli/src/slack-reresolve.test.ts create mode 100644 cli/src/slack/reresolve.ts diff --git a/cli/src/slack-reresolve.test.ts b/cli/src/slack-reresolve.test.ts new file mode 100644 index 0000000..5396bcc --- /dev/null +++ b/cli/src/slack-reresolve.test.ts @@ -0,0 +1,95 @@ +import { test, describe } from "node:test"; +import { strict as assert } from "node:assert"; +import { matchPendingChannels, PendingAgent } from "./slack/reresolve.js"; +import type { SlackChannelInfo } from "./slack/client.js"; + +const chan = (name: string, id: string, isMember: boolean, isPrivate = false): SlackChannelInfo => ({ + id, + name, + isMember, + isPrivate, +}); +const p = (slug: string, channel: string): PendingAgent => ({ slug, channel }); + +describe("matchPendingChannels (the #677 self-heal core)", () => { + test("public channel that exists but the bot is NOT a member stays pending", () => { + // The #677 trap: conversations.list returns a public channel the moment it + // exists, before the invite. Mirroring it then would post to a channel the + // bot can't write to. Must NOT resolve until is_member flips true. + const { resolved, stillPending } = matchPendingChannels( + [p("kanban-keeper", "#agent-kanban-keeper")], + [chan("agent-kanban-keeper", "C1", false)], + ); + assert.equal(resolved.length, 0); + assert.deepEqual( + stillPending.map((a) => a.slug), + ["kanban-keeper"], + ); + }); + + test("resolves — with the channel id — once the bot becomes a member", () => { + const { resolved, stillPending } = matchPendingChannels( + [p("kanban-keeper", "#agent-kanban-keeper")], + [chan("agent-kanban-keeper", "C1", true)], + ); + assert.deepEqual(resolved, [{ slug: "kanban-keeper", channelId: "C1" }]); + assert.equal(stillPending.length, 0); + }); + + test("a channel absent from the snapshot stays pending", () => { + const { resolved, stillPending } = matchPendingChannels([p("x", "not-created-yet")], [chan("other", "C9", true)]); + assert.equal(resolved.length, 0); + assert.equal(stillPending.length, 1); + }); + + test("private channel (only listed once a member) resolves", () => { + // Slack only returns a private channel in conversations.list when the bot is + // a member, so its presence with isMember=true is the normal resolve path. + const { resolved } = matchPendingChannels([p("sec", "#private-sec")], [chan("private-sec", "CP", true, true)]); + assert.deepEqual(resolved, [{ slug: "sec", channelId: "CP" }]); + }); + + test("a raw channel id in config is taken as-is (operator-wired; membership is theirs)", () => { + const { resolved, stillPending } = matchPendingChannels([p("x", "C0123ABC")], []); + assert.deepEqual(resolved, [{ slug: "x", channelId: "C0123ABC" }]); + assert.equal(stillPending.length, 0); + }); + + test("'#name' and bare 'name' resolve identically", () => { + const withHash = matchPendingChannels([p("a", "#foo")], [chan("foo", "C1", true)]); + const bare = matchPendingChannels([p("a", "foo")], [chan("foo", "C1", true)]); + assert.deepEqual(withHash.resolved, bare.resolved); + }); + + test("mixed roster in ONE snapshot: members resolve, non-members and absent ones pend", () => { + const { resolved, stillPending } = matchPendingChannels( + [p("a", "aa"), p("b", "bb"), p("c", "cc")], + [chan("aa", "CA", true), chan("bb", "CB", false)], // cc absent entirely + ); + assert.deepEqual(resolved, [{ slug: "a", channelId: "CA" }]); + assert.deepEqual( + stillPending.map((a) => a.slug).sort(), + ["b", "c"], + ); + }); + + test("promote-once: resolved agents are removed from stillPending, so the next pass can't re-resolve (no double-tail)", () => { + let pending: PendingAgent[] = [p("a", "aa"), p("b", "bb")]; + // pass 1: only aa's channel is ready + let r = matchPendingChannels(pending, [chan("aa", "CA", true)]); + pending = r.stillPending; + assert.deepEqual(r.resolved, [{ slug: "a", channelId: "CA" }]); + assert.deepEqual(pending.map((x) => x.slug), ["b"]); + // pass 2: aa is STILL in the (now larger) snapshot, but it left `pending`, + // so it is not resolved a second time — only the newly-ready bb is. + r = matchPendingChannels(pending, [chan("aa", "CA", true), chan("bb", "CB", true)]); + assert.deepEqual(r.resolved, [{ slug: "b", channelId: "CB" }]); + assert.equal(r.stillPending.length, 0); + }); + + test("empty pending set resolves to nothing (loop can stop)", () => { + const { resolved, stillPending } = matchPendingChannels([], [chan("aa", "CA", true)]); + assert.equal(resolved.length, 0); + assert.equal(stillPending.length, 0); + }); +}); diff --git a/cli/src/slack/bridge.ts b/cli/src/slack/bridge.ts index ff14cd9..4c11bd5 100644 --- a/cli/src/slack/bridge.ts +++ b/cli/src/slack/bridge.ts @@ -1,7 +1,8 @@ import { existsSync, statSync, openSync, readSync, closeSync } from "node:fs"; import { join } from "node:path"; import { SocketModeClient } from "@slack/socket-mode"; -import { SlackClient } from "./client.js"; +import { SlackClient, SlackChannelInfo } from "./client.js"; +import { matchPendingChannels, PendingAgent } from "./reresolve.js"; import { routeSlackMessage, prefixAuthor, ChannelMapping } from "./inbound.js"; import { formatTranscriptLines, formatCodexRolloutLines, TERMINAL_STOP_REASONS } from "./format.js"; import { loadAgentsConfig } from "../agents/config.js"; @@ -217,12 +218,14 @@ export async function runSlackBridge(opts: BridgeOptions): Promise { list.splice(i, 1); // consume so a genuine resend later is not swallowed return true; }; - for (const a of agents) { - const channelId = await client.resolveChannelId(a.slackChannel!); - if (!channelId) { - console.error(`Slack channel not found for ${a.slug}: ${a.slackChannel}`); - continue; - } + // Build a tail + channel→agent mapping for one agent whose channel is known + // and joinable. Used for agents resolved at startup AND, later, for agents + // whose channel only becomes usable after the bridge started (the pending + // re-resolution loop below). Appends live to `tails`/`mapping`, which the poll + // loop and inbound router read by reference, so a late add needs no restart. + const agentBySlug = new Map(agents.map((a) => [a.slug, a] as const)); + const buildTail = (a: (typeof agents)[number], channelId: string): void => { + if (tails.some((t) => t.slug === a.slug)) return; // promote-once: never double-tail mapping[channelId] = a.slug; const runtime = (a.runtime ?? "claude") as Runtime; const sessionId = agentIdentity(a.slug, runtime).sessionId; @@ -230,6 +233,21 @@ export async function runSlackBridge(opts: BridgeOptions): Promise { const path = runtime === "codex" ? findCodexRollout(cwd) : findSessionJsonl(sessionId); // Start at EOF so we mirror only new activity, not the whole backlog. tails.push({ slug: a.slug, runtime, sessionId, cwd, channelId, path, offset: path ? statSync(path).size : 0 }); + }; + + // Resolve every agent against ONE conversations.list snapshot, gating on bot + // MEMBERSHIP: a public channel is listed the moment it exists — before the bot + // is invited — so mirroring on mere presence would post into a channel the bot + // can't write to and gets no events from (a silent agent — exactly #677). + // Agents that don't resolve (channel absent, or bot not a member yet) go to + // `pending` and are retried by the loop below, so a channel created/invited + // AFTER this restart is picked up with no manual restart. + let pending: PendingAgent[] = agents.map((a) => ({ slug: a.slug, channel: a.slackChannel! })); + { + const snapshot = await client.listChannels(); + const { resolved, stillPending } = matchPendingChannels(pending, snapshot); + pending = stillPending; + for (const r of resolved) buildTail(agentBySlug.get(r.slug)!, r.channelId); } // Per-agent active "working…" pill. Set on each tool/thinking post, cleared @@ -497,10 +515,14 @@ export async function runSlackBridge(opts: BridgeOptions): Promise { // avoid send-keys-ing into a session that does not have this UI. const pickerByAgent = new Map(); const PICKER_POLL_MS = 1000; - const claudeAgents = tails.filter((t) => t.runtime === "claude"); - if (claudeAgents.length) { + // Schedule unconditionally and iterate `tails` live each tick so a Claude + // agent whose channel resolves AFTER startup (pending loop below) still gets + // pickers — a once-built `tails.filter(...)` snapshot would skip it, and zero + // Claude agents at boot would mean the interval was never scheduled at all. + { setInterval(async () => { - for (const t of claudeAgents) { + for (const t of tails) { + if (t.runtime !== "claude") continue; const pane = captureTmuxPane(t.slug); if (!pane) continue; const picker = parsePicker(pane); @@ -708,8 +730,55 @@ export async function runSlackBridge(opts: BridgeOptions): Promise { } } }); + // ── Pending-channel re-resolution: the #677 self-heal ─────────────────── + // Retry pending agents against a fresh snapshot on a SELF-RESCHEDULING timer + // (not setInterval — overlapping ticks under Slack rate-limiting could both + // see an agent pending and double-append its tail). The chain re-arms only + // while agents remain pending, so it costs nothing once all are mirrored, and + // pulls ONE conversations.list snapshot per pass shared across all pending + // agents. A channel created (or the bot invited) after this restart is picked + // up within one interval — no manual `systemctl restart` (issue #677). + const RESOLVE_RETRY_MS = 60_000; + const resolvePendingOnce = async (): Promise => { + if (!pending.length) return; + let snapshot: SlackChannelInfo[]; + try { + snapshot = await client.listChannels(); + } catch (e) { + console.error("pending-resolve listChannels failed (will retry):", e); + return; + } + const { resolved, stillPending } = matchPendingChannels(pending, snapshot); + pending = stillPending; + for (const r of resolved) { + const a = agentBySlug.get(r.slug); + if (!a) continue; + buildTail(a, r.channelId); + console.error(`now mirroring ${r.slug}: channel ${a.slackChannel} became reachable (no restart).`); + } + }; + const schedulePendingResolve = (): void => { + if (!pending.length) return; + setTimeout(async () => { + await resolvePendingOnce(); + schedulePendingResolve(); // re-arm only while agents remain pending + }, RESOLVE_RETRY_MS); + }; + if (pending.length) { + // One log line for the whole pending set (not one per agent per tick) so a + // permanently-misconfigured channel doesn't spam the journal every pass. + console.error( + `${pending.length} agent(s) awaiting a reachable Slack channel (created + bot invited): ${pending + .map((p) => p.slug) + .join(", ")}. Retrying every ${RESOLVE_RETRY_MS / 1000}s.`, + ); + schedulePendingResolve(); + } + await socket.start(); - console.error(`Slack bridge connected. Mirroring ${tails.length} agent(s).`); + console.error( + `Slack bridge connected. Mirroring ${tails.length} agent(s)${pending.length ? `; ${pending.length} pending channel(s).` : "."}`, + ); // Drop attachments older than the retention window so the inbox does not // grow without bound. We sweep on startup and then every hour. Override the diff --git a/cli/src/slack/client.ts b/cli/src/slack/client.ts index 366a587..8f8f5f3 100644 --- a/cli/src/slack/client.ts +++ b/cli/src/slack/client.ts @@ -1,5 +1,15 @@ import { WebClient } from "@slack/web-api"; +/// One channel from a `conversations.list` snapshot. `isMember` reflects whether +/// THIS bot token is in the channel — the bridge gates mirroring on it because a +/// public channel is listed before the bot is invited (see matchPendingChannels). +export interface SlackChannelInfo { + id: string; + name: string; + isMember: boolean; + isPrivate: boolean; +} + /// Thin wrapper over the Slack Web API for what the bridge needs: identify the /// bot, post messages, and resolve channel names to ids. export class SlackClient { @@ -96,4 +106,29 @@ export class SlackClient { } while (cursor); return undefined; } + + /// Page through every channel the bot can see in one pass and return a flat + /// snapshot (id + name + membership). Public channels are returned regardless + /// of membership (with isMember=false until the bot is invited); private + /// channels only where the bot is already a member. The bridge calls this once + /// per re-resolution pass and matches ALL pending agents against the single + /// snapshot, rather than a paginated lookup per agent. + async listChannels(): Promise { + const out: SlackChannelInfo[] = []; + let cursor: string | undefined; + do { + const r = await this.web.conversations.list({ + types: "public_channel,private_channel", + limit: 1000, + cursor, + }); + for (const c of (r.channels ?? []) as any[]) { + if (c?.id && typeof c.name === "string") { + out.push({ id: c.id, name: c.name, isMember: !!c.is_member, isPrivate: !!c.is_private }); + } + } + cursor = r.response_metadata?.next_cursor || undefined; + } while (cursor); + return out; + } } diff --git a/cli/src/slack/reresolve.ts b/cli/src/slack/reresolve.ts new file mode 100644 index 0000000..f901807 --- /dev/null +++ b/cli/src/slack/reresolve.ts @@ -0,0 +1,54 @@ +import type { SlackChannelInfo } from "./client.js"; + +/// A roster agent that wants Slack mirroring but whose channel is not yet +/// usable — the channel does not exist yet, or the bot has not been invited. +/// Held in the bridge's `pending` set and retried against fresh channel +/// snapshots until it becomes mirrorable, so a channel created (or a bot +/// invited) AFTER the bridge last started is picked up without a restart. +export interface PendingAgent { + slug: string; + /// The agent's configured slackChannel: "#name", "name", or a raw id. + channel: string; +} + +export interface ResolvedAgent { + slug: string; + channelId: string; +} + +/// Match pending agents against a single channel snapshot (one +/// `conversations.list` page-through per pass, shared across all pending +/// agents — never a lookup per agent, which would throttle the token bucket +/// the post/pill path also uses). +/// +/// An agent resolves ONLY when its channel is found AND the bot is a member. +/// `conversations.list` returns a PUBLIC channel as soon as it exists — before +/// the bot is invited — so promoting on mere presence would mirror a channel +/// the bot cannot post to (`not_in_channel`) and receives no message events +/// from: a silent half-mirrored agent, the exact bug this guards against. A +/// PRIVATE channel is only listed once the bot is a member, so the gate is +/// implied there. A raw channel id in the config is taken as-is (the operator +/// wired it explicitly; membership is their responsibility), mirroring +/// `resolveChannelId`. +/// +/// Resolved agents are removed from the returned `stillPending` set, so the +/// caller's next pass never re-resolves them (promote-once). +export function matchPendingChannels( + pending: PendingAgent[], + channels: SlackChannelInfo[], +): { resolved: ResolvedAgent[]; stillPending: PendingAgent[] } { + const byName = new Map(); + for (const c of channels) byName.set(c.name, c); + const resolved: ResolvedAgent[] = []; + const stillPending: PendingAgent[] = []; + for (const a of pending) { + if (/^[CG][A-Z0-9]+$/.test(a.channel)) { + resolved.push({ slug: a.slug, channelId: a.channel }); + continue; + } + const hit = byName.get(a.channel.replace(/^#/, "")); + if (hit && hit.isMember) resolved.push({ slug: a.slug, channelId: hit.id }); + else stillPending.push(a); + } + return { resolved, stillPending }; +} From 96539e689abd33d1dbcd1bd19fc002a5acc7ce95 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 10 Jul 2026 17:46:10 +0000 Subject: [PATCH 2/3] proof: #677 Track A terminal evidence (build + suite + is_member falsifiability) Co-Authored-By: Claude Opus 4.8 --- cli/proof/677-reresolve-proof.png | Bin 0 -> 48901 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 cli/proof/677-reresolve-proof.png diff --git a/cli/proof/677-reresolve-proof.png b/cli/proof/677-reresolve-proof.png new file mode 100644 index 0000000000000000000000000000000000000000..2c6f2191625a09d73775fd99778e124d64bd571e GIT binary patch literal 48901 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 literal 0 HcmV?d00001 From c4f3300c68b26ac8f7f750c296af78f7cc358c4d Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Fri, 10 Jul 2026 18:02:43 +0000 Subject: [PATCH 3/3] slack bridge: re-arm the pending-resolve chain even if a pass throws (#677) A throw in resolvePendingOnce (e.g. statSync racing a just-deleted transcript) would reject the awaited pass and skip the re-schedule, silently killing the self-heal retry chain. Wrap in .catch().finally(schedule) so a bad pass logs and the chain always re-arms while agents remain pending. Co-Authored-By: Claude Opus 4.8 --- cli/src/slack/bridge.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cli/src/slack/bridge.ts b/cli/src/slack/bridge.ts index 4c11bd5..3351f7f 100644 --- a/cli/src/slack/bridge.ts +++ b/cli/src/slack/bridge.ts @@ -759,9 +759,12 @@ export async function runSlackBridge(opts: BridgeOptions): Promise { }; const schedulePendingResolve = (): void => { if (!pending.length) return; - setTimeout(async () => { - await resolvePendingOnce(); - schedulePendingResolve(); // re-arm only while agents remain pending + setTimeout(() => { + // Always re-arm (while agents remain pending) even if a pass throws — an + // unexpected error in one pass must not silently kill the self-heal chain. + resolvePendingOnce() + .catch((e) => console.error("pending-resolve pass failed (will retry):", e)) + .finally(() => schedulePendingResolve()); }, RESOLVE_RETRY_MS); }; if (pending.length) {