{"record":{"id":"f4ef1e8d474e7323","repo":"ruvnet/ruflo","slug":"mctsexplorer-requires-at-least-one-peer","errorCode":null,"errorMessage":"MctsExplorer requires at least one peer","messagePattern":"MctsExplorer requires at least one peer","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/browser/src/application/mcts-explorer.ts","lineNumber":69,"sourceCode":"  trajectoryEnvelope: unknown,\n) => Promise<RootAction[]>;\n\nexport class MctsExplorer {\n  private readonly peers: PeerAdapter[];\n  private readonly scorer: ValueScorer;\n  private readonly maxDepth: number;\n  private readonly maxBranches: number;\n  private readonly defaultPeerBudgetUsd: number;\n  private readonly ucb: UcbParams;\n  private readonly trustedPublicKeys: string[];\n\n  private branches: Map<string, McTsBranch> = new Map();\n  private peerSpend: Map<string, number> = new Map();\n  private peerBlacklist: Set<string> = new Set();\n  private peerSignatureBlacklist: Set<string> = new Set();\n\n  constructor(options: MctsExplorerOptions) {\n    if (options.peers.length === 0) throw new Error('MctsExplorer requires at least one peer');\n    this.peers = options.peers;\n    this.scorer = options.scorer;\n    this.maxDepth = options.maxDepth ?? 5;\n    this.maxBranches = options.maxBranches ?? 32;\n    this.defaultPeerBudgetUsd = options.defaultPeerBudgetUsd ?? 1.0;\n    this.ucb = options.ucb ?? { c: Math.SQRT2 };\n    this.trustedPublicKeys = options.trustedPublicKeys ?? [];\n  }\n\n  /** Explore from a seed root action. Returns the winning branch's ID + aggregate stats. */\n  async explore(input: {\n    rootAction: RootAction;\n    goal: string;\n    expansionPolicy: ExpansionPolicy;\n  }): Promise<MctsRunResult> {\n    const runId = 'run-' + Date.now() + '-' + randomBytes(3).toString('hex');\n    const rootId = 'br-root-' + randomBytes(3).toString('hex');\n    const rootPeer = this.pickPeer();","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/browser/src/application/mcts-explorer.ts#L51-L87","documentation":"Constructor guard in MctsExplorer: it refuses to build an explorer whose options.peers is an empty array. The Monte-Carlo Tree Search exploration requires at least one peer to expand/roll out branches against, and the rest of the options (maxDepth, maxBranches, ucb.c, defaultPeerBudgetUsd, trustedPublicKeys) all default sensibly, but peers has no default and cannot be empty.","triggerScenarios":"new MctsExplorer({ peers: [], ... }) — e.g. the peer list was filtered down to zero by peerBlacklist/signature checks before construction, or a config loader returned an empty peers array.","commonSituations":"Initialising the explorer before the peer-discovery/allowlist step has populated peers; a config/env var that lists peers being unset; all configured peers failing a trust/public-key filter upstream so the array handed to the constructor is empty.","solutions":["Ensure options.peers has at least one entry before constructing the explorer; gate construction on peers.length > 0.","Run peer discovery/trust filtering after, not before, you have a non-empty candidate set.","If zero peers is a legitimate runtime state, skip constructing the explorer (return null / a no-op explorer) rather than passing [].","Add a config validation step that fails fast with a clearer message when the peers source is empty."],"exampleFix":"// before\nconst explorer = new MctsExplorer({ peers: filteredPeers, scorer }); // throws if filteredPeers=[]\n// after\nif (filteredPeers.length === 0) {\n  throw new Error(\"no trusted peers available after filtering; cannot run MCTS exploration\");\n}\nconst explorer = new MctsExplorer({ peers: filteredPeers, scorer });","handlingStrategy":"validation","validationCode":"if (!Array.isArray(peers) || peers.length === 0) {\n  throw new Error(\"MctsExplorer needs >=1 peer; got 0\");\n}\nreturn new MctsExplorer({ peers, scorer });","typeGuard":"function isNonEmptyPeerList(x: unknown): x is unknown[] {\n  return Array.isArray(x) && x.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Gate construction on peers.length > 0; return a no-op explorer when zero peers is a legitimate runtime state.","Run peer discovery before constructing the explorer, not after filtering to empty.","Fail fast in config loading when the peers source is unset, with a clearer message than the constructor's."],"tags":["validation","mcts","swarm","constructor"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}