{"record":{"id":"32dc12ff618eb6ad","repo":"Hmbown/CodeWhale","slug":"invalid-runtime-retention-horizon","errorCode":null,"errorMessage":"Invalid Runtime retention horizon.","messagePattern":"Invalid Runtime retention horizon\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/pet_watch/pet-native.js","lineNumber":2275,"sourceCode":"            this.bytes = total;\n            this.sizes.set(event, size);\n        }\n        for (const key of Object.keys(event))\n            if (!Object.hasOwn(safe, key))\n                delete event[key];\n        Object.assign(event, safe);\n    }\n    push(event) {\n        if (this.events.length >= this.maxEvents)\n            throw new Error(`Import exceeds the ${this.maxEvents.toLocaleString()} event limit.`);\n        this.measure(event);\n        pushEvent(this.events, event);\n    }\n    /** Keep unfinished lifetimes plus the recent window needed by the bucketer's\n     * 12-second recurrence measure. A completion may still arrive for any open item. */\n    prune(beforeWall) {\n        if (!Number.isFinite(beforeWall))\n            throw new Error('Invalid Runtime retention horizon.');\n        if (this.origin === undefined)\n            return;\n        const cutoff = beforeWall - this.origin;\n        let keep = 0;\n        for (const event of this.events) {\n            if (event.openEnded || Math.max(event.endTime, (0, model_js_1.errorOnsetOf)(event)) >= cutoff)\n                this.events[keep++] = event;\n            else {\n                this.bytes -= this.sizes.get(event) ?? 0;\n                this.sizes.delete(event);\n                if (this.open.get(event.id) === event)\n                    this.open.delete(event.id);\n            }\n        }\n        this.events.length = keep;\n    }\n    append(records) {\n        if (!records.length)","sourceCodeStart":2257,"sourceCodeEnd":2293,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/pet_watch/pet-native.js#L2257-L2293","documentation":"prune(beforeWall) computes a retention cutoff from the given wall-clock timestamp; a non-finite value (NaN, Infinity, undefined coerced) cannot define a valid horizon, so the call is rejected. This is a defensive guard ensuring retention math never silently prunes everything or nothing.","triggerScenarios":"Calling runtime.prune(NaN), prune(Infinity), or prune(undefined) — commonly when the caller's wall-clock source (Date parse, counter) failed and produced NaN.","commonSituations":"Parsing a missing or malformed timestamp into a number that becomes NaN; passing a uninitialized variable intended to hold 'now'; arithmetic overflow producing Infinity.","solutions":["Ensure the beforeWall argument is a finite epoch-milliseconds number before calling prune.","Fix the timestamp source: use Date.now() or validate parsed values with Number.isFinite.","Default the argument when the clock source is unavailable.","Add a Number.isFinite check at the call site."],"exampleFix":"// before\nrt.prune(Date.parse(meta.updatedAt)); // NaN if updatedAt is malformed\n// after\nconst t = Date.parse(meta.updatedAt);\nif (Number.isFinite(t)) rt.prune(t);","handlingStrategy":"validation","validationCode":"if (!Number.isFinite(beforeWall)) throw new TypeError('prune requires a finite epoch-ms timestamp');","typeGuard":"const isFiniteMs = (t) => typeof t === 'number' && Number.isFinite(t);","tryCatchPattern":"try { rt.prune(t); } catch (e) { if (e.message.includes('retention horizon')) rt.prune(Date.now()); else throw e; }","preventionTips":["Use Date.now() as the default horizon source.","Validate parsed timestamps with Number.isFinite before use.","Never pass possibly-undefined variables to prune."],"tags":["validation","time","prune"],"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"}