{"record":{"id":"38609a908a2e3f7d","repo":"ruvnet/ruflo","slug":"unsupported-calibrator-schema-v-j-v","errorCode":null,"errorMessage":"unsupported calibrator schema v=${j?.v}","messagePattern":"unsupported calibrator schema v=(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/ruvector/router-calibrator.ts","lineNumber":128,"sourceCode":"\n    // Linear interpolation between two adjacent bucket midpoints. Could be\n    // binary-searched, but n is typically <30 after PAV so linear is fine.\n    for (let i = 0; i < n - 1; i++) {\n      if (x >= mids[i] && x <= mids[i + 1]) {\n        const t = (x - mids[i]) / (mids[i + 1] - mids[i]);\n        return this.buckets[i].calibrated * (1 - t) + this.buckets[i + 1].calibrated * t;\n      }\n    }\n    return x; // unreachable given the bounds above\n  }\n\n  /** Pure-JSON serialization — calibrator JSON is small (typically <2kB). */\n  toJSON(): CalibratorJSON {\n    return { v: 1, buckets: this.buckets };\n  }\n\n  static fromJSON(j: CalibratorJSON): IsotonicCalibrator {\n    if (!j || j.v !== 1) throw new Error(`unsupported calibrator schema v=${j?.v}`);\n    return new IsotonicCalibrator(j.buckets);\n  }\n\n  /** Diagnostic — number of distinct calibration points after PAV. */\n  get bucketCount(): number {\n    return this.buckets.length;\n  }\n\n  /** Diagnostic — return a copy of the bucket array (read-only view). */\n  inspect(): CalibratorBucket[] {\n    return this.buckets.map(b => ({ ...b }));\n  }\n}\n","sourceCodeStart":110,"sourceCodeEnd":142,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/ruvector/router-calibrator.ts#L110-L142","documentation":"IsotonicCalibrator.fromJSON() deserializes only schema v1: the parsed object must satisfy j.v === 1 (with j.buckets passed to the constructor). Any other value — including undefined when the field is missing, the file is empty (parses to null), or a future writer bumped the version — throws this error, interpolating the offending version (missing prints as 'undefined').","triggerScenarios":"Loading calibrator JSON persisted by a newer/older package version that changed the schema; hand-edited or truncated JSON losing the v field; passing the wrong file entirely (e.g., a KRR router JSON) whose top-level has no v; JSON.parse of an empty file yielding null, then null?.v !== 1.","commonSituations":"Upgrading the library and reusing calibrated state saved before the upgrade; restoring calibration files from backups across versions; pipelines where the calibrator file is regenerated by a different tool version than the one reading it.","solutions":["Regenerate the calibrator through the current calibration pipeline and re-serialize with toJSON() (which always writes {v:1, buckets})","Inspect the file: node -e \"console.log(require('./cal.json').v)\" — anything not 1 cannot be loaded by this version","Keep calibrator artifacts version-pinned next to the package version that produced them; store the writer version alongside","If the buckets layout is unchanged and only v is missing, wrap the file as {v:1, buckets:<old buckets>} after verifying the shape"],"exampleFix":"// before\nconst cal = IsotonicCalibrator.fromJSON(JSON.parse(readFileSync(path, 'utf8'))); // throws on v!==1\n// after\nconst parsed = JSON.parse(readFileSync(path, 'utf8'));\nif (parsed?.v !== 1 || !Array.isArray(parsed.buckets)) {\n  throw new Error(`calibrator artifact stale (v=${parsed?.v}); recalibrating...`);\n}\nconst cal = IsotonicCalibrator.fromJSON(parsed);","handlingStrategy":"type-guard","validationCode":"const parsed = JSON.parse(raw);\nif (parsed?.v !== 1) {\n  throw new Error(`stale calibrator artifact (v=${parsed?.v}); recalibrate before loading`);\n}","typeGuard":"interface CalibratorV1 { v: 1; buckets: unknown[] }\nfunction isCalibratorV1(j: unknown): j is CalibratorV1 {\n  return !!j && typeof j === 'object' && (j as any).v === 1 && Array.isArray((j as any).buckets);\n}","tryCatchPattern":"try {\n  cal = IsotonicCalibrator.fromJSON(parsed);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('unsupported calibrator schema')) {\n    cal = await recalibrate(); // regenerate with current pipeline, then persist via toJSON()\n  } else throw e;\n}","preventionTips":["Store the writer's package version next to calibrator artifacts and validate on load","Always round-trip through toJSON()/fromJSON() of the same version pair","Run isCalibratorV1 on any artifact restored from backup or another environment"],"tags":["calibration","serialization","schema-version","deserialization"],"backgroundTag":"schema-version-mismatch","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}