{"record":{"id":"8035fb6d5b538f99","repo":"Hmbown/CodeWhale","slug":"invalid-interval-for-e-id-signal","errorCode":null,"errorMessage":"Invalid interval for ${e.id}.","messagePattern":"Invalid interval for (.+?)\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/src/core/signal.ts","lineNumber":21,"sourceCode":"function emptyLevel(length: number, binMs: number): BinLevel {\n  const n = CATEGORIES.length * length;\n  return { binMs, length, onsets: new Float64Array(n), activeMs: new Float64Array(n),\n    outputTokens: new Float64Array(n), cost: new Float64Array(n), errors: new Float64Array(n), peak: new Float64Array(n) };\n}\nconst FIELDS = ['onsets', 'activeMs', 'outputTokens', 'cost', 'errors'] as const;\n/** O(events + channels × bins), including long intervals. No span-length inner loop. */\nexport function buildPyramid(events: readonly WhaleEvent[], requestedDuration?: number, maxBins = 16_384): SignalPyramid {\n  if (!Number.isInteger(maxBins) || maxBins < 16 || maxBins > 1_048_576) throw new Error('maxBins must be an integer in [16, 1048576].');\n  let duration = requestedDuration ?? 1;\n  for (const e of events) duration = Math.max(duration, e.endTime, e.startTime, e.status === 'error' ? errorOnsetOf(e) : 0);\n  if (!Number.isFinite(duration) || duration < 0) throw new Error('Signal duration must be finite and nonnegative.');\n  duration = Math.max(1, duration);\n  const binMs = 2 ** Math.ceil(Math.log2(Math.max(1, duration / (maxBins - 1))));\n  const length = Math.floor(duration / binMs) + 1, fine = emptyLevel(length, binMs);\n  const stride = length + 1;\n  const activeDiff = new Float64Array(CATEGORIES.length * stride), tokenDiff = new Float64Array(CATEGORIES.length * stride);\n  for (const e of events) {\n    if (!Number.isFinite(e.startTime) || !Number.isFinite(e.endTime) || e.startTime < 0 || e.endTime < e.startTime) throw new Error(`Invalid interval for ${e.id}.`);\n    const channel = CATEGORIES.indexOf(e.category);\n    if (channel < 0) throw new Error(`Unknown category for ${e.id}.`);\n    const a = Math.floor(e.startTime / binMs), b = Math.floor(e.endTime / binMs);\n    const at = channel * length, diff = channel * stride;\n    fine.onsets[at + a]++;\n    fine.cost[at + a] += e.cost ?? 0;\n    if (e.status === 'error') fine.errors[at + Math.floor(errorOnsetOf(e) / binMs)]++;\n    const d = e.endTime - e.startTime, tokens = e.outputTokens ?? 0;\n    if (d === 0) { fine.outputTokens[at + a] += tokens; continue; }\n    if (a === b) { fine.activeMs[at + a] += d; fine.outputTokens[at + a] += tokens; }\n    else {\n      const left = (a + 1) * binMs - e.startTime, right = e.endTime - b * binMs, tokenRate = tokens / d;\n      fine.activeMs[at + a] += left;\n      fine.activeMs[at + b] += right;\n      fine.outputTokens[at + a] += left * tokenRate;\n      fine.outputTokens[at + b] += right * tokenRate;\n      if (b > a + 1) {\n        activeDiff[diff + a + 1] += binMs; activeDiff[diff + b] -= binMs;","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/src/core/signal.ts#L3-L39","documentation":"While binning events into the pyramid, buildPyramid() validates each WhaleEvent's interval. It throws this per-event error when startTime or endTime is not finite, startTime is negative, or endTime is earlier than startTime — an interval that cannot be placed on the time axis.","triggerScenarios":"An event in the array has NaN/Infinity startTime or endTime (missing timestamps, null coerced via arithmetic), a negative startTime, or endTime < startTime (swapped/reversed timestamps, e.g. end recorded before start due to clock skew or a logic bug).","commonSituations":"Traces imported from external formats (OTLP, JSONL) with missing end times; events still in flight recorded with a placeholder end of -1 or undefined; swapping startTime/endTime arguments at the call site; clock skew between distributed producers.","solutions":["Fix the offending event's timestamps so 0 <= startTime <= endTime and both are finite; the error message names the event id to locate it.","Validate/sanitize events before calling buildPyramid, dropping or repairing records with bad intervals.","For in-flight spans, use a sentinel end equal to startTime or the current time, not a negative or undefined value.","Check whether the import layer (OTLP/JSONL adapter) is leaving timestamps undefined."],"exampleFix":"// before\nbuildPyramid([{ id: 'a', startTime: 100, endTime: 50, category: 'tool' }]);\n// after\nbuildPyramid([{ id: 'a', startTime: 50, endTime: 100, category: 'tool' }]);","handlingStrategy":"validation","validationCode":"const bad = events.filter(e => !Number.isFinite(e.startTime) || !Number.isFinite(e.endTime) || e.startTime < 0 || e.endTime < e.startTime);\nif (bad.length) repairOrDrop(bad); // before buildPyramid","typeGuard":"function hasValidInterval(e: WhaleEvent): boolean { return Number.isFinite(e.startTime) && Number.isFinite(e.endTime) && e.startTime >= 0 && e.endTime >= e.startTime; }","tryCatchPattern":"try { buildPyramid(events, duration); } catch (e) { const m = /Invalid interval for (.+)\\./.exec(e.message); if (m) { dropEvent(m[1]); buildPyramid(events, duration); } else throw e; }","preventionTips":["Sanitize timestamps at the import boundary, not at render time.","Give in-flight spans endTime = startTime until they close.","Watch for swapped start/end arguments and clock skew in distributed producers."],"tags":["validation","time","events"],"backgroundTag":"schema-validation-failed","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}