// **A consumer that cannot be bound yet is bound again, never fatal** (novox/hq issue 1793). When the tool runtime // starts this bundle, the runtime's answer to "bind this module's consumer" can be "no responders" for a few seconds (the // runtime restarted by a delivery, the bus not yet serving the stream). That rejection, left unhandled at the top of // index.ts, ended the bundle: nothing heard `mesh-controller.checked` again, and a verdict that landed later never // reached the forge's statuses. A bind that fails is said and asked again with a growing wait until it holds. /** How long to wait before the nth new attempt (1-based): 2 s, 5 s, 10 s, then every 30 s. */ export function bindWait(attempt: number): number { return [2_000, 5_000, 10_000][attempt - 1] ?? 30_000; } /** * Binds with `bind`, asking again after each failure, until it holds. `sleep` is the wait; `say` how a failure is said. * Never rejects; resolves once the bind holds. */ export async function bindUntilHeld(what: string, bind: () => Promise, sleep: (ms: number) => Promise = (ms) => new Promise((r) => setTimeout(r, ms)), say: (line: string) => void = (line) => console.error(line)): Promise { for (let attempt = 1; ; attempt++) { try { await bind(); if (attempt > 1) say(`[gitea] ${what} is bound after ${attempt} attempts`); return; } catch (err) { const wait = bindWait(attempt); say(`[gitea] ${what} could not be bound (${err instanceof Error ? err.message : String(err)}); asking again in ${wait / 1000}s`); await sleep(wait); } } }