{"record":{"id":"3b49b68e0630bf50","repo":"Hmbown/CodeWhale","slug":"invalid-pet-pcm-range","errorCode":null,"errorMessage":"Invalid pet PCM range.","messagePattern":"Invalid pet PCM range\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/pet_watch/pet-native.js","lineNumber":1624,"sourceCode":"                if (frame.needs === 'call' && window % 10 === 0)\n                    add(`call:${window}`, pet_sim_js_1.CHANNELS[11].freq * 1.5, .38, .03);\n            }\n        }\n        return out;\n    }\n}\nexports.PetScore = PetScore;\n/** Sample-addressed noise: no global RNG, identical samples when chunked/seeking. */\nfunction noise(seed, sample) {\n    let x = (seed + Math.imul(sample, 0x6D2B79F5)) >>> 0;\n    x = Math.imul(x ^ x >>> 15, x | 1);\n    x ^= x + Math.imul(x ^ x >>> 7, x | 61);\n    return ((x ^ x >>> 14) >>> 0) / 2147483648 - 1;\n}\nfunction renderPetPCM(voices, startSample, length, sampleRate = 48_000) {\n    if (!Number.isInteger(sampleRate) || sampleRate < 8000 || sampleRate > 96000\n        || !Number.isSafeInteger(startSample) || startSample < 0 || !Number.isInteger(length) || length < 0 || length > sampleRate * 120)\n        throw new Error('Invalid pet PCM range.');\n    const left = new Float32Array(length), right = new Float32Array(length);\n    for (const v of voices) {\n        if (![v.start, v.duration, v.frequency, v.gain, v.pan].every(Number.isFinite)\n            || v.start < 0 || v.duration <= 0 || v.duration > 10 || v.frequency <= 0 || v.frequency > sampleRate / 2\n            || v.gain < 0 || v.gain > 1 || Math.abs(v.pan) > 1 || !['tone', 'noise'].includes(v.kind))\n            throw new Error('Invalid pet voice.');\n        const first = Math.max(startSample, Math.ceil(v.start * sampleRate));\n        const last = Math.min(startSample + length, Math.ceil((v.start + v.duration) * sampleRate));\n        const pan = (v.pan + 1) * Math.PI / 4, seed = (0xC0FFEE ^ (0, model_js_1.stableHash)(v.id)) >>> 0;\n        for (let absolute = first; absolute < last; absolute++) {\n            const age = absolute / sampleRate - v.start;\n            const envelope = Math.min(1, age / .015, (v.duration - age) / .045);\n            const sample = v.kind === 'noise' ? noise(seed, absolute) * Math.exp(-age * 14)\n                : Math.sin(2 * Math.PI * v.frequency * age) * .88 + Math.sin(4 * Math.PI * v.frequency * age) * .12;\n            const value = sample * Math.max(0, envelope) * v.gain, at = absolute - startSample;\n            left[at] += value * Math.cos(pan);\n            right[at] += value * Math.sin(pan);\n        }","sourceCodeStart":1606,"sourceCodeEnd":1642,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/pet_watch/pet-native.js#L1606-L1642","documentation":"renderPetPCM validates the sample window before synthesizing audio for the pet visualization. It throws 'Invalid pet PCM range.' when the sampleRate, startSample, or length arguments violate the accepted envelope: sampleRate must be an integer in [8000, 96000], startSample a non-negative safe integer, and length a non-negative integer no greater than 120 seconds worth of samples. This is an input-guard so the renderer never allocates unbounded or nonsensical buffers.","triggerScenarios":"Calling renderPetPCM with a non-integer or out-of-range sampleRate (e.g. 44100.5, 4000, 192000), a negative or non-integer startSample (NaN, -1, fractional seek offsets), or a length that is negative, non-integer, or exceeds sampleRate*120 samples.","commonSituations":"Passing a duration in milliseconds directly as a sample count without multiplying by sampleRate; using a fractional sampleRate from an AudioContext probe; computing startSample from floating-point time math without Math.round/floor; rendering an entire long session at once instead of chunked windows.","solutions":["Convert time to samples explicitly with Math.round(seconds * sampleRate) before calling","Clamp sampleRate to a supported integer value (8000-96000), typically the audio context's sampleRate rounded","Chunk long renders into windows of at most sampleRate*120 samples per call","Ensure startSample is a non-negative safe integer (use Math.max(0, Math.trunc(x)))"],"exampleFix":"// before\nrenderPetPCM(voices, elapsedMs, durationMs);\n// after\nconst sr = 48000;\nrenderPetPCM(voices, Math.round(elapsedSec * sr), Math.min(Math.round(durationSec * sr), sr * 120), sr);","handlingStrategy":"validation","validationCode":"function validPcmRange(startSample, length, sampleRate) {\n  return Number.isInteger(sampleRate) && sampleRate >= 8000 && sampleRate <= 96000\n    && Number.isSafeInteger(startSample) && startSample >= 0\n    && Number.isInteger(length) && length >= 0 && length <= sampleRate * 120;\n}\nif (!validPcmRange(start, len, sr)) throw new RangeError('pcm range');","typeGuard":"const isPcmWindow = (s) => typeof s === 'object' && Number.isSafeInteger(s.startSample) && s.startSample >= 0 && Number.isInteger(s.length) && s.length >= 0 && Number.isInteger(s.sampleRate) && s.sampleRate >= 8000 && s.sampleRate <= 96000;","tryCatchPattern":"try {\n  const pcm = renderPetPCM(voices, startSample, length, sampleRate);\n} catch (err) {\n  if (err.message === 'Invalid pet PCM range.') {\n    startSample = Math.max(0, Math.trunc(startSample));\n    length = Math.min(Math.max(0, Math.trunc(length)), sampleRate * 120);\n    return renderPetPCM(voices, startSample, length, sampleRate);\n  }\n  throw err;\n}","preventionTips":["Always convert seconds to samples with Math.round(seconds * sampleRate)","Chunk renders to windows no longer than 120 seconds","Round AudioContext sample rates to integers before passing them","Clamp seek offsets to >= 0"],"tags":["audio","validation","argument-validation"],"backgroundTag":"value-out-of-range","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"}