{"record":{"id":"cb099ee5de08e6d7","repo":"Hmbown/CodeWhale","slug":"invalid-pet-state","errorCode":null,"errorMessage":"Invalid pet state.","messagePattern":"Invalid pet state\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tui/pet_watch/pet-native.js","lineNumber":711,"sourceCode":"    { key: 'memory', label: 'Memory / RAG', color: '#b6a77f', freq: 195.99, sustained: true, arch: 'gyre', form: 'gyre · scanning' },\n    { key: 'code', label: 'Code execution', color: '#9b9ed7', freq: 164.81, sustained: false, arch: 'strike', form: 'strike · along the body' },\n    { key: 'filesystem', label: 'Filesystem', color: '#92b9c9', freq: 440.00, sustained: false, arch: 'strike', form: 'strike · fanning' },\n    { key: 'network', label: 'Network / API', color: '#d3ac74', freq: 523.25, sustained: false, arch: 'cross', form: 'crossing · one way' },\n    { key: 'browser', label: 'Browser / computer', color: '#9ea9df', freq: 349.23, sustained: false, arch: 'cross', form: 'crossing · a sweep' },\n    { key: 'communication', label: 'Agent messages', color: '#83c5c9', freq: 293.66, sustained: false, arch: 'cross', form: 'crossing · two ways' },\n    { key: 'agent', label: 'Subagent activity', color: '#b09acb', freq: 220.00, sustained: true, arch: 'pod', form: 'pod · peers' },\n    { key: 'orchestration', label: 'Orchestration', color: '#6c8798', freq: 98.00, sustained: true, arch: 'pod', form: 'pod · hub' },\n    { key: 'error', label: 'Errors / exceptions', color: '#e79186', freq: 185.00, sustained: false, arch: 'tear', form: 'torn · irregular' },\n    { key: 'human', label: 'Human interaction', color: '#c2b787', freq: 391.99, sustained: false, arch: 'address', form: 'decision · junction' },\n    { key: 'other', label: 'Unclassified', color: '#738492', freq: 146.83, sustained: false, arch: 'drift', form: 'drifting · unformed' },\n];\nexports.CHANNEL_INDEX = Object.fromEntries(exports.CHANNELS.map((c, i) => [c.key, i]));\nfunction validatePetState(value) {\n    const s = value;\n    if (!s || typeof s !== 'object' || !Object.hasOwn(exports.CHANNEL_INDEX, s.channel)\n        || ![s.activity, s.coherence, s.attention, s.observed, s.lit].every(n => Number.isFinite(n) && n >= 0 && n <= 1)\n        || ![s.roamX, s.roamY, s.flip].every(n => Number.isFinite(n) && Math.abs(n) <= 1))\n        throw new Error('Invalid pet state.');\n}\nconst hex2rgb = (h) => [parseInt(h.slice(1, 3), 16), parseInt(h.slice(3, 5), 16), parseInt(h.slice(5, 7), 16)];\nconst RGB = exports.CHANNELS.map(c => hex2rgb(c.color));\nconst UNKNOWN_RGB = hex2rgb('#738492');\nconst REST_RGB = [122, 214, 240];\n// mulberry32 — a 32-bit seeded PRNG tiny enough to port by hand correctly.\nfunction mulberry32(seed) {\n    let a = seed >>> 0;\n    return Object.assign(() => {\n        a = (a + 0x6D2B79F5) >>> 0;\n        let t = a;\n        t = Math.imul(t ^ (t >>> 15), t | 1);\n        t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n        return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n    }, { state: () => a, restore: (state) => {\n            if (!Number.isSafeInteger(state) || state < 0 || state > 0xffffffff)\n                throw new Error('Invalid pet random stream.');\n            a = state;","sourceCodeStart":693,"sourceCodeEnd":729,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tui/pet_watch/pet-native.js#L693-L729","documentation":"validatePetState() checks that a restored or simulated pet state object has a known channel key and that all normalized fields (activity, coherence, attention, observed, lit in [0,1]; roamX, roamY, flip within ±1) are finite numbers in range. It is called from checkpoint restore (error 20's constructor) and guards the renderer against malformed state that would break drawing or audio math. Any structural or range violation throws immediately.","triggerScenarios":"Calling validatePetState(value) — directly or via PetWorld checkpoint restore — with null/undefined, an object whose s.channel is not a key of CHANNEL_INDEX, any of activity/coherence/attention/observed/lit outside [0,1] or non-finite, or roamX/roamY/flip with |n| > 1 or NaN.","commonSituations":"Restoring checkpoints saved by a version whose channel set changed (renamed/removed channels); a sim bug producing NaN attention after a divide-by-zero; hand-edited state JSON with values like activity: 1.5; loading state serialized as strings.","solutions":["Clamp all normalized fields into range and coerce to numbers before validation: `n = Number(n); Math.min(1, Math.max(0, n))`.","Ensure s.channel is one of the current CHANNELS keys; migrate state saved against an older channel list.","Regenerate the state from a fresh simulation if the source checkpoint is corrupt.","Log the offending field at the call site to identify which numeric constraint failed."],"exampleFix":"// before\nworld.sim.restore(saved.sim); // saved.attention = 1.7 -> throws\n// after\nfor (const k of ['activity','coherence','attention','observed','lit'])\n  saved.sim.state[k] = Math.min(1, Math.max(0, Number(saved.sim.state[k])));\nsaved.sim.state.channel = CHANNELS.some(c => c.key === saved.sim.state.channel) ? saved.sim.state.channel : 'other';\nworld.sim.restore(saved.sim);","handlingStrategy":"type-guard","validationCode":"function isPetState(s, CHANNEL_INDEX) {\n  const in01 = n => typeof n === 'number' && Number.isFinite(n) && n >= 0 && n <= 1;\n  const inPM1 = n => typeof n === 'number' && Number.isFinite(n) && Math.abs(n) <= 1;\n  return !!s && typeof s === 'object' && s.channel in CHANNEL_INDEX &&\n    [s.activity, s.coherence, s.attention, s.observed, s.lit].every(in01) &&\n    [s.roamX, s.roamY, s.flip].every(inPM1);\n}","typeGuard":"const isValidPetState = (s) => !!s && typeof s === 'object' && typeof s.channel === 'string' && [s.activity, s.coherence, s.attention, s.observed, s.lit].every(n => Number.isFinite(n) && n >= 0 && n <= 1) && [s.roamX, s.roamY, s.flip].every(n => Number.isFinite(n) && Math.abs(n) <= 1);","tryCatchPattern":"try {\n  validatePetState(state);\n} catch (e) {\n  if (e.message === 'Invalid pet state.') {\n    state = defaultPetState(); // reset to a known-good state\n  } else throw e;\n}","preventionTips":["Clamp normalized fields to [0,1] and roam/flip to ±1 at every producer","Coerce serialized values back to numbers before validation","Keep the channel key in sync with the current CHANNELS list","Guard sim math against divide-by-zero that yields NaN fields"],"tags":["validation","state","checkpoint"],"backgroundTag":"schema-validation-failed","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"}