{"record":{"id":"60fba13beb9914b5","repo":"ruvnet/ruflo","slug":"proposal-proposalid-not-found","errorCode":null,"errorMessage":"Proposal ${proposalId} not found","messagePattern":"Proposal (.+?) not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/guidance/src/adversarial.ts","lineNumber":696,"sourceCode":"          oldestTimestamp = proposal.timestamp;\n          oldestId = id;\n        }\n      }\n      if (oldestId) {\n        this.proposals.delete(oldestId);\n      }\n    }\n\n    return proposalId;\n  }\n\n  /**\n   * Vote on a proposal\n   */\n  vote(proposalId: string, voterId: string, approve: boolean): void {\n    const proposal = this.proposals.get(proposalId);\n    if (!proposal) {\n      throw new Error(`Proposal ${proposalId} not found`);\n    }\n    if (proposal.resolved) {\n      throw new Error(`Proposal ${proposalId} already resolved`);\n    }\n\n    proposal.votes.set(voterId, approve);\n  }\n\n  /**\n   * Resolve a proposal (check if quorum reached)\n   */\n  resolve(proposalId: string): QuorumResult {\n    const proposal = this.proposals.get(proposalId);\n    if (!proposal) {\n      throw new Error(`Proposal ${proposalId} not found`);\n    }\n\n    // Single pass over votes instead of two filter calls","sourceCodeStart":678,"sourceCodeEnd":714,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/guidance/src/adversarial.ts#L678-L714","documentation":"AdversarialCoordinator.vote() registers a voter's approve/reject decision on a memory proposal held in the in-memory `proposals` Map. It throws when `proposalId` does not match any proposal in this instance. Because state is per-instance and in-memory, the most common root cause is an ID from a previous run or a different coordinator object.","triggerScenarios":"Calling `coordinator.vote(someId, voterId, true)` where someId was never returned by propose(); using a proposalId captured before a process restart (the Map is not persisted); concatenating or truncating the ID string.","commonSituations":"Service restarted between proposing and voting, dropping all in-memory proposals; multiple coordinator instances (one per worker) with IDs crossing between them; IDs passed through JSON and mangled; voting on already-garbage-collected proposals in long test runs.","solutions":["Always use the exact proposalId returned by `propose()`","Check existence first via the public accessor: `if (coordinator.getProposal(proposalId) === undefined) return;`","If the coordinator was restarted, re-run propose() to mint a fresh proposal and vote on that","In multi-instance setups, route all votes for a proposal to the same coordinator instance that created it"],"exampleFix":"// before\ncoordinator.vote(proposalIdFromLastRun, voterId, true); // throws\n\n// after\nconst proposal = coordinator.getProposal(proposalIdFromLastRun);\nif (proposal && !proposal.resolved) {\n  coordinator.vote(proposalIdFromLastRun, voterId, true);\n}","handlingStrategy":"validation","validationCode":"const proposal = coordinator.getProposal(proposalId);\nif (proposal === undefined) {\n  // unknown to this instance: skip, re-propose, or log\n}","typeGuard":null,"tryCatchPattern":"try {\n  coordinator.vote(proposalId, voterId, approve);\n} catch (err) {\n  if (err instanceof Error && err.message.endsWith('not found')) {\n    // stale ID (restart / wrong instance) — drop the vote, do not crash the voter\n  } else throw err;\n}","preventionTips":["Treat the proposalId returned by propose() as the only valid handle","Keep propose/vote/resolve on one coordinator instance","Expect in-memory proposals to vanish on restart and re-propose"],"tags":["adversarial","proposal","guidance","not-found","in-memory-state"],"backgroundTag":"entity-not-found","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}