Repository navigation
[Dream Cycle 2026-10-09] swarm: MessageBus broadcast-retry re-queues under the 'broadcast' sentinel instead of the real subscriber, silently dropping failed deliveries + ruvector-integration, ruview-integration scan #3928
Description
1. Tonight's Rotation
DATE=2026-10-09
DEEP=swarm
SCAN=ruview-integration,ruvector-integration
SLOT=4
COMMIT=58e0ae7e14e68aab45a4127d6f42f567bbcfb328
BRANCH=dream/2026-10-09-swarm
No bonus deep-dive triggers tonight (20261009 % 25 = 9, % 75 = 59).
2. Ledger Check
Last 14 rows inspected in docs/dream-cycle/LEDGER.md (through 2026-09-30). GitHub-verified fates for the trailing 7 nights before tonight (via pull_request_read/list_pull_requests/search_pull_requests, gh CLI present but its GH_TOKEN is invalid this session — FALLBACK applies to local gh use only, GitHub MCP tools work fine):
| Night | Surface | PR | State |
|---|---|---|---|
| 10-01 | security | #3599 | MERGED 2026-10-07 |
| 10-02 | intelligence | #3622 | open/draft |
| 10-03 | memory | #3650 | open/draft |
| 10-04 | swarm | — | no-run gap (confirmed via git ls-remote --heads origin "dream/*"; slot sequence skipped straight to 10-05=performance) |
| 10-05 | performance | #3754 | closed, NOT merged (2026-10-07) |
| 10-06 | security | #3835 | open/draft |
| 10-07 | intelligence | #3879 | open/draft |
| 10-08 | memory | #3909 | open/draft |
Also spot-checked older still-open items: #3339 (09-16 security, round 2) MERGED 2026-10-07; #3539 (09-29 swarm) MERGED 2026-10-07; #3476 (09-27 intelligence) still open/draft but updated today (not stale, <14d... actually 12d, still under the 14d STALE threshold). No new STALE items found (open >14d AND no follow-up) among the trailing 7.
Swarm-surface historical merge rate stays strong: #3086 (08-24), #3123 (08-29), #3243 (09-09), #3357 (09-19), #3539 (09-29) — 5/5 merged.
pi.ruv.io collective-memory check (STEP 2.1, read-only): unreachable from this environment (curl → HTTP status 000, connection failure) — noted as a supplementary-signal gap, not blocking.
3. Deep Dive Findings
5-role parallel research fan-out (deep researcher, competitor analyst, ruview scan, architecture reviewer, plus this session's own direct verification). Full report: docs/dream-cycle/dream-gist-2026-10-09.md (this branch).
Selected finding: MessageBus.broadcast() (v3/@claude-flow/swarm/src/message-bus.ts) sets message.to = 'broadcast' as a sentinel; enqueue() fans the message out to each real subscriber's own agentId-keyed queue. When a subscriber's delivery callback throws, handleDeliveryError()'s retry re-queue used this.addToQueue(message.to, message, entry.attempts) — i.e. the literal string 'broadcast', a queue key with no subscription. processQueues() skips any unsubscribed queue (if (!subscription) continue), so a failing broadcast subscriber's retries — and eventual message.failed — were silently dropped forever, and the orphaned queue entry leaked until shutdown(). This was explicitly flagged in-code as a "KNOWN LIMITATION (pre-existing, not fixed here)" comment by the immediately-preceding #3562/#3563 MessageBus rewrite, which fixed the direct-message path's busy-poll but left this broadcast-path gap disclosed and open.
Candidate scoring (STEP 3.2, 5 candidates, weighted formula): this finding scored highest (4.90) against three other swarm-internal candidates (TopologyManager role re-index gap, TaskOrchestrator priority-map missing-key bug, AgentPool heartbeat dead-code) and the ruview-integration scan (which scored 1.60 — architecturally real but not testable-tonight material). Full scoring table in the gist.
4. Hypothesis
Given a swarm using
MessageBus.broadcast()where at least one subscriber's delivery callback throws, whenhandleDeliveryError()'s retry re-queue is changed to use the real subscriber'sagentId(threaded through fromdeliverMessage()) instead of the literal string'broadcast', then the failing subscriber should receive bounded retries up toconfig.retryAttemptsand emitmessage.failedonce exhausted — matching the already-correct direct-message path — subject to: zero change to happy-path (no-error) behavior, zero regression across the existing 274-test swarm suite, deterministic $0 Vitest evaluation.
Frozen before evaluation; not modified after seeing results.
5. Evaluation Receipt
evaluated: accepted. Real evaluator: Vitest 4.1.8, deterministic, $0, zero LLM calls, against a freshly pnpm install-ed v3/ workspace (not pre-built at session start — native deps like hnswlib-node compiled during setup).
- New test file
message-bus.broadcast-retry.test.ts(2 tests): stash-isolated baseline (fix reverted viagit stash push -- src/message-bus.ts, test file untracked/unaffected) — both fail exactly as predicted (badInvocations1 vs. expected 3;getQueueDepth()1 vs. expected 0, i.e. the leaked orphaned queue). Candidate (stash popped): both pass. - Full
@claude-flow/swarmsuite: baseline 274/274 (17 files) → candidate 276/276 (18 files, +2 new), zero regressions. tsc --noEmit: clean, 0 errors, both ways.- Healthy co-subscriber in the same broadcast delivers exactly once throughout, unaffected by the sibling's failure — explicit regression guard built into the new test.
- Independently re-reproduced end-to-end by the adversarial critic (own stash/pop cycle, own full-suite + tsc run), byte-identical results.
6. Darwin Results
Skipped — binary correctness/wiring fix (which queue key to re-queue a retry under), no continuous or categorical parameter for Darwin's real interface (npx ruvector harness darwin <config> --execute, confirmed available v0.9.2) to search over. Same skip class as nearly every accepted fix in this ledger since 2026-08-18 (#3110/.../#3909).
7. Flywheel Evidence
No .claude-flow/flywheel/ state exists in this repo; npx ruvector harness flywheel --help confirms the real interface (verify/gate) targets signed, LLM-scored replay bundles, not a deterministic code fix like this one — same conclusion every prior night in this ledger has reached for this class of candidate. Evidence retained as: the 2 discriminating tests, this issue, the gist, the stash-isolated comparison (reproduced independently twice), and the full adversarial critique transcript (§9).
Classification: the broadcast-sentinel-vs-real-agentId root cause is an OBSERVATION (directly read from source); the stash-isolated before/after counts are a MEASUREMENT; "this closes the gap #3562/#3563 explicitly disclosed" is an INFERENCE connecting the two; ACCEPT is the DECISION.
8. Reward Hack Check
No standalone reward-hack CLI reachable this session (npx ruvector harness --help and npx metaharness --help expose Darwin/Flywheel/routing but no dedicated reward-hack verb despite @metaharness/weight-eft showing as an available direct dependency in harness doctor). Manual checklist, independently re-verified by the adversarial critic:
- Test/threshold/gold-data weakened? No — diff is purely additive (2 call-site args, 1 new param, 1 re-queue-key line, 1 comment rewrite; one new test file).
- Cherry-picked tasks / hidden preprocessing / seed manipulation? No — deterministic, no RNG involved, full suite disclosed both ways.
- Error suppression hiding a real failure? No — the opposite: the fix makes a previously-suppressed failure (
message.failed) surface correctly. - Cost hiding? N/A, $0 throughout.
9. Security Review
Not security-sensitive — pure in-process queue-key bookkeeping on an already-internal agentId, no new I/O/network/credential/filesystem surface. Independent adversarial critique (separate subagent, no authoring context, own repro): CONFIRMED, no blocking issues. It verified: the bug claim by reading the full file; baseline-fails/candidate-passes via its own stash/pop cycle; full suite 276/276 + clean tsc; that direct-message behavior is unchanged (subscription.agentId for a direct message already equals what message.to held); that subscription.agentId is always === the processQueues() loop's agentId key (no code path decouples them, including across subscribe/unsubscribe/resubscribe); no infinite-retry/double-delivery/leak risk; and that the new test's timing matches the already-merged sibling test exactly (no new flake exposure).
10. Scan Findings: ruview-integration
No real integration exists beyond a well-tested but unwired policy/schema module: v3/@claude-flow/security/src/policy/product-plane.ts defines a RuView product-plane profile (RuViewSemanticObservationV1, validateRuViewSemanticObservation(), privacy-ceiling P2/P3 enforcement) with substantive unit tests, but zero consumers anywhere in the codebase — no CLI command, MCP tool, or caller constructs/validates a real RuView observation. ADR-325 and ADR-326 (the covering design docs) are both still Proposed. This is new-feature work (building a consumer), not a scoped bugfix — not testable-tonight material, consistent with prior nights on this surface.
11. Scan Findings: ruvector-integration
v3/@claude-flow/cli/src/ruvector/graph-analyzer.ts's loadRuVector() checks for ruvector.hooks_graph_mincut/ruvector.hooks_graph_cluster and @ruvector/wasm's GraphAnalyzer class — neither exists in any version of either real package. Independently confirmed by two separate reviews: this session downloaded and inspected ruvector 0.2.27 through 0.3.3 directly (real exports: minCut, spectralClustering, louvainCommunities, buildGraph) and @ruvector/wasm (only VectorDB/SIMD utilities, no GraphAnalyzer); a separately-spawned architecture-reviewer agent independently verified against the locally-installed ruvector v0.2.41. git log --follow shows the file was introduced whole, not regressed from a once-working state — this has been 100% dead code since introduction. analyzeMinCutBoundaries()/analyzeModuleCommunities() always run the slower, approximate JS fallbacks instead of the real package's exact Stoer-Wagner minCut(). The existing test's own assertion (result === null || typeof result === 'object') is trivially true either way, so it doesn't catch this. Scored 4.20 in tonight's candidate table — a strong secondary finding, carried forward as a recommended candidate for a future ruvector-integration night rather than bundled into tonight's patch (keeping tonight's diff to one conceptual change).
12. Competitors Reviewed
LangGraph, Microsoft Agent Framework (AutoGen successor), CrewAI, OpenAI Agents SDK, Temporal (swarm topology/coordination); Qdrant, Weaviate, Milvus, LanceDB, LangChain.js faiss-node/hnswlib-node (native-fallback failure-mode research for the ruvector-integration scan). Full comparison table in the gist.
13. Gist
gh gist create unavailable this session (gh auth status → "Failed to log in... The token in GH_TOKEN is invalid" — same environment gap flagged by the 2026-09-30/10-08 nights). Full SOTA report committed instead at docs/dream-cycle/dream-gist-2026-10-09.md on this branch, and reproduced in full below the witness block for convenience. GIST=LOCAL.
14. Witness
Session commit: 58e0ae7e14e68aab45a4127d6f42f567bbcfb328
Candidate commit: (this branch's tip — see PR for the exact SHA)
Gist SHA-256 (pre-witness, mutable fields stripped to PENDING): 3b02818262f559907245450201b00bb7742dc781270d60f3deea159fa568e1fc
Witness stamp: 1b7e818e917acd3925b622ec26d78632ab8c872dab78da3ecf97fb0da27d461c
Verifier: fetch docs/dream-cycle/dream-gist-2026-10-09.md from this branch, strip its Witness block's filled-in values back to PENDING, SHA-256 the file, concatenate with the session commit above, SHA-256 again — must equal the witness stamp.
15. Recommendation
evaluated: accepted. Human review required before merge — see PR. Do not self-merge, do not autonomously promote Flywheel state. Two follow-up candidates disclosed for future nights: (1) wire the real ruvector package's graph exports into graph-analyzer.ts (ruvector-integration), (2) AgentPool.updateAgentHeartbeat() remains dead code post-#3242/3243 (swarm).
🤖 Generated with RuFlo
Activity
fix(swarm): skip broadcast retry re-queue for a subscriber that unsub…
Merge pull request #3929 from ruvnet/dream/2026-10-09-swarm
dream(swarm): ruvnet#3928 MessageBus broadcast-retry re-queues under …