Repository navigation
[Dream Cycle 2026-10-15] performance: RaftConsensus.awaitConsensus() busy-polled instead of using its own 'consensus.achieved' event + security,hive-mind scan #4214
Description
1. Tonight's Rotation
DATE=2026-10-15, DEEP=performance, SCAN=security,hive-mind, SLOT=0, SESSION_COMMIT=1882006a02487590c8c66a7eec8d7504f6af33c3. No bonus deep-dive triggers (DAYINT%25=15, DAYINT%75=65).
2. Ledger Check
Read docs/dream-cycle/LEDGER.md (last row: 2026-10-11, security, #4052/#4053). Verified via git ls-remote --heads origin "dream/*" + GitHub MCP tools that 2026-10-12 (intelligence, #4081), 10-13 (memory, #4138), 10-14 (swarm, #4174) all ran and have real branches/issues/draft PRs — same "ledger rows only reach main via PR merge" structural gap noted since 2026-08-19. Trailing-7-night fates (GitHub-verified via pull_request_read, not inferred): 10-08 #3909 open; 10-09 #3929 MERGED; 10-10 #3977 MERGED; 10-11 #4053 MERGED; 10-12 #4081 open; 10-13 #4138 open; 10-14 #4174 open. None stale (<14d). 10-05 #3754 remains closed-not-merged (duplicate, already recorded). STEP 1.1 learning signals: performance-surface findings since 09-15 are 5 distinct bugs (MoE load-balance, UnifiedSwarmCoordinator busy-poll, MessageBus busy-poll, mmrRerank, fallbackLouvain) — no 3x-repeated direction, no forced rotation needed; merge rate (3/7 recent) is healthy, no small-patch bias triggered.
STEP 1.2 prior-gist score (2026-10-14, swarm): 10/10 — 2 (benchmark evidence, stash-isolated + independent critic reproduction) + 2 (6 competitor rows) + 2 (3 specific recommendations with file paths) + 2 (valid witness) + 1 (1372 words, under 1500) + 1 (genuinely novel: resolved the 10-09/10-10 contradiction about ruvector's real exports).
3. Deep Dive Findings
Closing finding (REJECT, with evidence): v3/@claude-flow/cli/src/ruvector/graph-analyzer.ts's loadRuVector() checks for ruvector.hooks_graph_mincut/hooks_graph_cluster and @ruvector/wasm's GraphAnalyzer — none ever existed. 10-14's gist found the real ruvector package exports minCut/louvainCommunities/buildGraph and recommended wiring them in. Tonight I read those functions' actual source directly: they are plain JS, not native/WASM-accelerated, with the same incremental-bookkeeping complexity class as Ruflo's own already-fixed fallbackLouvain() (10-10, #3977). Wiring them in would not be a performance win — this closes a 3-night (10-09→10-10→10-14) research thread with a definitive answer rather than another partial correction.
Tonight's candidate: RaftConsensus.awaitConsensus() (v3/@claude-flow/swarm/src/consensus/raft.ts) — Ruflo's default hive-mind consensus algorithm (config.algorithm ?? 'raft' in both ConsensusEngine and UnifiedSwarmCoordinator), reachable from production via the public UnifiedSwarmCoordinator.proposeConsensus() API — busy-polled this.proposals via setInterval(..., 10) even though checkConsensus() (called from vote()) already emits 'consensus.achieved' on every pending→accepted/rejected transition. UnifiedSwarmCoordinator itself already listens to that exact event (unified-coordinator.ts:712) for an unrelated purpose — this fix makes awaitConsensus() do the same. Third instance of a bug class the ledger has fixed twice before (UnifiedSwarmCoordinator #3378 ~487x, MessageBus #3563 ~96.5% idle-tick reduction).
Two other candidates were researched and scored lower (see gist): RaftConsensus.handleInboundRaftMessage()'s O(n²) log-index-dedup linear scan (real, but conditional on an explicit ConsensusTransport being supplied — not wired in UnifiedSwarmCoordinator's default path, so weaker confirmed production value); and ByzantineConsensus/GossipConsensus carrying the identical busy-poll pattern (same fix, lower priority since raft is the default — carried forward).
4. Hypothesis
Given a pending consensus proposal in
RaftConsensus, whenawaitConsensus()resolves via the already-emitted'consensus.achieved'event (plus a singlesetTimeoutfor expiry) instead of pollingthis.proposalson a 10mssetInterval, then (a)ConsensusResultfor accept/reject/expire/not-found cases stays behaviorally identical, and (b) proposals that resolve before timeout should resolve with lower, less-discretized latency and zero timer-tick overhead while waiting, subject to: all existing tests green; no change to quorum/vote logic incheckConsensus(); deterministic, $0, zero-LLM evaluation. Frozen before evaluation; not modified after.
5. Evaluation Receipt
evaluated: accepted. Real evaluator: Vitest 4.1.8, deterministic, $0, zero LLM calls.
New test file raft-await-consensus-event-driven.test.ts (4 tests). Stash-isolated baseline (git stash on just raft.ts): 3/4 fail exactly as predicted (setInterval observed called when asserted not-called; immediate-return case measured 11ms ≥ the <10ms bound; expiry case shows 5 setInterval calls); the 4th (unknown-proposal-id immediate rejection, pre-existing behavior) passes both ways — a correct non-discriminating control. Candidate: 4/4 pass. Full @claude-flow/swarm suite: 281/281 passed, 19/19 files green (277 pre-existing + 4 new), zero regressions. tsc --noEmit: clean, 0 errors, both ways. Standalone wall-clock probe (30 trials, vote arriving 3–9ms after awaitConsensus() starts — deliberately off the old 10ms poll grid): baseline mean 3.639ms / max 7.492ms vote→resolve latency, 30 setInterval timers created; candidate mean 0.058ms / max 0.346ms, 0 timers created. Independently reproduced end-to-end by an adversarial critic via its own separate stash/pop cycle, plus its own concurrency test (200 simultaneous awaitConsensus() calls on 200 distinct proposals, zero leaks) and same-tick timeout-vs-vote race test (5 runs, no crash/double-resolve): CONFIRMED, no blocking issues.
6. Darwin Results
Skipped — binary correctness/wiring fix (listen to an already-emitted event instead of polling), no continuous/categorical parameter for Darwin's real interface (npx ruvector harness darwin <config> --execute, confirmed available in STEP 0.5) to search over. Same skip class as nearly every accepted fix since 2026-08-18.
7. Flywheel Evidence
No .claude-flow/flywheel/ state exists in this repo (confirmed, same as every recent night). npx ruvector harness flywheel gate <evidence> requires a signed LLM-task-corpus replay-evidence schema not applicable to this deterministic fix class. Evidence retained as: the 4 new discriminating tests, the stash-isolated comparison (reproduced independently twice), the standalone latency probe, the independent adversarial critique transcript, this issue, and the committed gist.
8. Reward Hack Check
No standalone static reward-hack CLI reachable for this fix class tonight (@metaharness/weight-eft exists but targets LoRA fine-tuning training-data contamination, not applicable — no LLM training run happened). Manual checklist independently verified twice (by me, and by a separate adversarial-critic subagent with no authoring context): no test/threshold weakened, no gold data touched, no cherry-picking, no evaluator exploitation, no cost increase, no seed manipulation, no hidden preprocessing, no error suppression, no undocumented cache. checkConsensus()'s pending-only guard structurally prevents a double-fire of 'consensus.achieved' for the same proposal (confirmed by code reading, not just test absence).
9. Security Review
Not security-sensitive — pure in-process EventEmitter rewiring (swap a polling timer for an existing, already-emitted event listener), no new I/O/network/credential/filesystem surface. setMaxListeners(0) in the constructor is a correctly-scoped companion change (listeners are always 1:1 with in-flight proposals and removed on resolution — confirmed via the critic's 200-concurrent-proposal leak test, final listenerCount() === 0).
10. Scan Findings: security
Two findings (not fixed tonight, carried forward): (1) settings-risk-scanner.ts only inspects settings.hooks/settings.permissions.allow, never enabledPlugins/extraKnownMarketplaces — a capability-granting settings.json surface v3/@claude-flow/cli/src/mods/install.ts's withModEnabled() writes, which every current scanner call site (fresh-init, init --upgrade, the CJS SessionStart port) is blind to. (2) DENYLISTED_ENV_NAMES (CWE-427 loader-hijack family) is missing PYTHONSTARTUP/PYTHONHOME/RUBYOPT/JAVA_TOOL_OPTIONS/_JAVA_OPTIONS/JDK_JAVA_OPTIONS/GIT_ASKPASS/R_PROFILE/R_ENVIRON alongside the names it already covers.
11. Scan Findings: hive-mind
Three findings (not fixed tonight, carried forward): (1) Confirmed real and dead: raft.ts's public handleVoteRequest()/handleAppendEntries() (lines 513–578) are exercised only by consensus.test.ts, zero production callers — the live receiver is the private handleInboundRaftMessage(). The dead path diverges (no index-dedup, unconditional votedFor mutation on heartbeat), giving false test confidence, matching what 10-10's ledger note flagged. (2) New: crdt/quorum are offered as first-class consensus choices in hive-mind.ts's CLI/wizard, but ConsensusAlgorithm only supports raft|byzantine|gossip|paxos and hive-mind.ts never imports the real ConsensusEngine at all — picking crdt/quorum silently does nothing (cosmetic banner only). (3) Corroborated (not new): byzantine.ts's handleCommit() PBFT message-count quorum remains a separate acceptance path from vote()'s weighted tally (flagged 2026-08-24, still unaddressed).
12. Competitors Reviewed
LangGraph (Pregel-style superstep, sync barrier per step — B), AutoGen v0.4/MS Agent Framework (actor-model async message-passing — B), CrewAI (event-driven Flows, no published dispatch internals — C), OpenAI Swarm→Agents SDK (stateless/sequential, no server event bus — C), Milvus/Weaviate/Vespa (real runtime CPU-feature-flag dispatch to compiled SIMD variants — the pattern Ruflo's now-explained dead graph-analyzer.ts detection imitated without a real backend — B). None of the four orchestration frameworks publish internals on poll-vs-event consensus/task-wait dispatch — unaudited industry-wide, not just a Ruflo gap. Full detail, sources, and additional 2026 academic citations (MAFBench arXiv:2602.03128, "The Orchestrator Bottleneck" ICML 2026, CP-WBFT arXiv:2511.10400) in the gist.
13. Gist
docs/dream-cycle/dream-gist-2026-10-15.md (this branch). No gh gist create/gist-equivalent MCP tool reachable this session (same disclosed FALLBACK as every night since 2026-09-30) — full report committed to the repo and embedded above instead.
14. Witness
Session commit: 1882006a02487590c8c66a7eec8d7504f6af33c3
Gist SHA-256 (pre-witness): df858321819d9bb00295ae21dba03fe2752975b6592a86cb845fe06dadfac367
Witness stamp: 2ca9c4955cff2ddfdba4e633a5a823cded52979f91b11423cc95fcc2e1fc5c87
Verifier: fetch docs/dream-cycle/dream-gist-2026-10-15.md from this branch, strip the 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
Human review required. Do not self-merge. Do not autonomously promote Flywheel state. Candidate is small (1 file + 1 test file), independently confirmed by an adversarial critic with no blocking issues, and fixes a real, measured (~63x mean-latency, 30→0 poll-timer) production-reachable performance bug on Ruflo's default consensus algorithm.
Activity
dream(performance): #4214 record PR #4215 in LEDGER.md
dream(performance): #4214 RaftConsensus.awaitConsensus() busy-poll → …