{"record":{"id":"275241228879899d","repo":"ruvnet/ruflo","slug":"estimatedusd-must-be-a-non-negative-finite-number","errorCode":null,"errorMessage":"estimatedUsd must be a non-negative finite number","messagePattern":"estimatedUsd must be a non-negative finite number","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/business-pods/bbs-budget-tracker.ts","lineNumber":193,"sourceCode":"        `INSERT INTO bbs_budget_rooms (room_id, monthly_cap_usd, billing_month, _lock_bump)\n         VALUES (?, ?, ?, 0)\n         ON CONFLICT(room_id) DO UPDATE SET monthly_cap_usd = excluded.monthly_cap_usd`,\n      )\n      .run(roomId, monthlyCapUsd, billingMonth);\n  }\n\n  /**\n   * Atomically check budget and insert a reservation row in a single\n   * BEGIN IMMEDIATE transaction. See ADR-164.1 §5.2.\n   */\n  reserve(\n    roomId: string,\n    callerId: string,\n    estimatedUsd: number,\n    opts?: { auditEnvelopeId?: string; expiryMs?: number },\n  ): ReserveResult {\n    if (!Number.isFinite(estimatedUsd) || estimatedUsd < 0) {\n      throw new Error('estimatedUsd must be a non-negative finite number');\n    }\n    const auditEnvelopeId = opts?.auditEnvelopeId ?? `audit-${randomUUID()}`;\n    const expiryMs = clampReservationExpiry(opts?.expiryMs ?? this.defaultExpiryMs);\n\n    const nowMs = this.clock();\n    const billingMonth = currentBillingMonth(nowMs);\n    const billingMonthStart = billingMonthStartMs(billingMonth);\n\n    const beginStmt = this.db.prepare('BEGIN IMMEDIATE');\n    const commitStmt = this.db.prepare('COMMIT');\n    const rollbackStmt = this.db.prepare('ROLLBACK');\n\n    beginStmt.run();\n    let transactionOpen = true;\n    try {\n      // Step 1: touch the room header row (the _lock_bump write makes the\n      // lock acquisition visible per §3.2 peer-review note).\n      const bumpRes = this.db","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/cli/src/business-pods/bbs-budget-tracker.ts#L175-L211","documentation":"Input guard at the top of AtomicBbsRoomBudgetTracker.reserve(), run before the BEGIN IMMEDIATE transaction so a bad value never touches SQLite. Uses Number.isFinite() (excludes NaN and ±Infinity) plus a < 0 test. estimatedUsd is the projected cost the caller wants to reserve against the monthly cap; a malformed value would corrupt budget accounting or break the SQL CHECK constraint downstream.","triggerScenarios":"Calling tracker.reserve(roomId, callerId, estimatedUsd) where estimatedUsd is NaN (e.g., Number(undefined) or undefined * 1), ±Infinity (division by zero), or a negative number.","commonSituations":"Cost estimate read from env via Number(process.env.X) where the var is unset (NaN); a pricing/cost model returning -1 as a sentinel for unknown; a parseFloat on garbage user input; a division producing Infinity when a denominator is zero.","solutions":["Validate before calling: `if (!Number.isFinite(estimatedUsd) || estimatedUsd < 0) throw ...` or clamp to 0","If the value comes from config/env, default to 0 or a sensible floor instead of passing NaN through","Replace sentinel values like -1 with explicit null and skip the reservation rather than reserving a negative amount"],"exampleFix":"// before:\nconst est = Number(process.env.POD_TICK_COST); // NaN when unset\ntracker.reserve(roomId, callerId, est); // throws\n\n// after:\nconst raw = Number(process.env.POD_TICK_COST);\nconst est = Number.isFinite(raw) && raw >= 0 ? raw : 0;\ntracker.reserve(roomId, callerId, est);","handlingStrategy":"validation","validationCode":"function safeReservationAmount(estimatedUsd: unknown): number {\n  const n = typeof estimatedUsd === 'number' ? estimatedUsd : Number(estimatedUsd);\n  if (!Number.isFinite(n) || n < 0) return 0; // or throw, depending on policy\n  return n;\n}\n// before calling reserve():\nconst amount = safeReservationAmount(rawCost);\ntracker.reserve(roomId, callerId, amount);","typeGuard":"function isValidReservationAmount(v: unknown): v is number {\n  return typeof v === 'number' && Number.isFinite(v) && v >= 0;\n}","tryCatchPattern":null,"preventionTips":["Never pass the result of Number(undefined) or an unvalidated env/config value directly to reserve()","Centralize cost computation in one function that returns a guaranteed finite non-negative number","Unit-test the cost function with undefined, null, NaN, Infinity, and negative inputs"],"tags":["budget","validation","input","bbs","numbers"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}