{"record":{"id":"a1e1a66eb90beb1a","repo":"Hmbown/CodeWhale","slug":"invalid-interval-for-e-id","errorCode":null,"errorMessage":"Invalid interval for ${e.id}.","messagePattern":"Invalid interval for (.+?)\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/pet_watch/pet-native.js","lineNumber":1326,"sourceCode":"}\nconst FIELDS = ['onsets', 'activeMs', 'outputTokens', 'cost', 'errors'];\n/** O(events + channels × bins), including long intervals. No span-length inner loop. */\nfunction buildPyramid(events, requestedDuration, maxBins = 16_384) {\n    if (!Number.isInteger(maxBins) || maxBins < 16 || maxBins > 1_048_576)\n        throw new Error('maxBins must be an integer in [16, 1048576].');\n    let duration = requestedDuration ?? 1;\n    for (const e of events)\n        duration = Math.max(duration, e.endTime, e.startTime, e.status === 'error' ? (0, model_js_1.errorOnsetOf)(e) : 0);\n    if (!Number.isFinite(duration) || duration < 0)\n        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(model_js_1.CATEGORIES.length * stride), tokenDiff = new Float64Array(model_js_1.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)\n            throw new Error(`Invalid interval for ${e.id}.`);\n        const channel = model_js_1.CATEGORIES.indexOf(e.category);\n        if (channel < 0)\n            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')\n            fine.errors[at + Math.floor((0, model_js_1.errorOnsetOf)(e) / binMs)]++;\n        const d = e.endTime - e.startTime, tokens = e.outputTokens ?? 0;\n        if (d === 0) {\n            fine.outputTokens[at + a] += tokens;\n            continue;\n        }\n        if (a === b) {\n            fine.activeMs[at + a] += d;\n            fine.outputTokens[at + a] += tokens;\n        }","sourceCodeStart":1308,"sourceCodeEnd":1344,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/pet_watch/pet-native.js#L1308-L1344","documentation":"buildPyramid() re-validates each event's interval as it bins it: startTime and endTime must be finite numbers, startTime >= 0, and endTime >= startTime. It throws 'Invalid interval for <id>.' naming the offending event when any of these fail. This is a per-event guard distinct from the aggregate duration check.","triggerScenarios":"An event with NaN/undefined startTime or endTime; negative timestamps (pre-epoch or a subtracted origin larger than the timestamp); endTime earlier than startTime due to clock skew or reversed start/end fields; Infinity from unclosed spans.","commonSituations":"Corrupt or partially imported traces; events hand-constructed with (end, start) swapped; timezone/clock adjustments applied to one field but not the other; older data format missing timestamp fields.","solutions":["Find the event by the id in the message and inspect its startTime/endTime values.","Fix or drop the offending event: swap reversed fields, clamp negatives to 0, or assign a finite endTime to open spans.","Run the data through importTrace() which enforces the event-v1 interval invariants upstream.","Add a pre-pass filter that removes or repairs events failing Number.isFinite(t) && t >= 0 && end >= start."],"exampleFix":"// before\nbuildPyramid(events, duration); // throws on one bad event\n// after\nconst valid = events.filter(e =>\n  Number.isFinite(e.startTime) && Number.isFinite(e.endTime) &&\n  e.startTime >= 0 && e.endTime >= e.startTime);\nbuildPyramid(valid, duration);","handlingStrategy":"type-guard","validationCode":"const validInterval = (e) =>\n  Number.isFinite(e.startTime) && Number.isFinite(e.endTime) &&\n  e.startTime >= 0 && e.endTime >= e.startTime;\nconst bad = events.filter(e => !validInterval(e));\nif (bad.length) console.warn('dropping', bad.map(e => e.id));\nbuildPyramid(events.filter(validInterval), duration);","typeGuard":"const hasValidInterval = (e) =>\n  typeof e?.startTime === 'number' && typeof e?.endTime === 'number' &&\n  Number.isFinite(e.startTime) && Number.isFinite(e.endTime) &&\n  e.startTime >= 0 && e.endTime >= e.startTime;","tryCatchPattern":"try {\n  return buildPyramid(events, duration, maxBins);\n} catch (e) {\n  if (e.message.startsWith('Invalid interval for ')) {\n    const badId = e.message.slice('Invalid interval for '.length).replace(/\\.$/, '');\n    return buildPyramid(events.filter(ev => ev.id !== badId), duration, maxBins);\n  }\n  throw e;\n}","preventionTips":["Sanitize timestamps at import: coerce, clamp negatives to 0, repair swapped start/end","Drop or quarantine events failing interval invariants before analysis","Watch for Infinity endTime from unclosed spans — close them with a finite value"],"tags":["validation","data-integrity"],"backgroundTag":"invalid-argument-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}