{"record":{"id":"db7188b9b1d56251","repo":"Hmbown/CodeWhale","slug":"invalid-pet-random-stream-native","errorCode":null,"errorMessage":"Invalid pet random stream.","messagePattern":"Invalid pet random stream\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"pet/ios/Resources/pet-native.js","lineNumber":728,"sourceCode":"        || ![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;\n        } });\n}\n/** Work reorganizes the same particles; no new random draws or invented facts.\n * These are expressive fields, not diagrams of unobserved network/file topology. */\nfunction fieldTarget(q, t, act, att, key) {\n    const u = q.s * 2 - 1, lane = q.pod - 2.5, a = q.s * Math.PI * 2;\n    const flow = t * (.35 + act * .65);\n    if (key === 'reasoning') {\n        const ring = .34 + .105 * Math.cos(a * 3 + flow + lane * .18);\n        return [ring * Math.cos(a * 2 + flow * .3), ring * Math.sin(a * 2 + flow * .3) * .7 + .10 * Math.sin(a * 3 + flow)];\n    }\n    if (key === 'memory')\n        return [.46 * Math.cos(a + lane * .1 + flow * .25), lane * .082 + .052 * Math.sin(a * 2 + flow)];\n    if (key === 'code')\n        return [u * .57, lane * .066 + .12 * Math.sin(u * 7 + flow * 2 + q.pod * Math.PI / 3)];\n    if (key === 'filesystem') {\n        const branch = Math.max(0, (u + .3) / 1.3);","sourceCodeStart":710,"sourceCodeEnd":746,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/pet/ios/Resources/pet-native.js#L710-L746","documentation":"PetWorld uses a mulberry32 PRNG whose 32-bit state `a` can be snapshotted via `state()` and restored via `restore(state)`. `restore` throws when the given state is not a safe integer in the range [0, 0xffffffff] — i.e. anything outside what `state()` can ever produce.","triggerScenarios":"Calling `rng.restore(x)` with a value that was not produced by `rng.state()` — e.g. a float from JSON parsing, a negative number, a value > 4294967295, a null/undefined placeholder, or a state saved from a different PRNG implementation.","commonSituations":"Persisting RNG state to JSON/storage where it round-trips as a string or loses exactness; hand-crafting seeds outside 32 bits; restoring from a save file written by an older version with a different state format; mixing up a seed value with a mid-stream state value.","solutions":["Only restore values captured from `rng.state()`, stored verbatim (as an integer, not reformatted) — verify the saved value with `Number.isSafeInteger(s) && s >= 0 && s <= 0xffffffff` before calling restore.","If the stored state is a string, convert with `Number(s)` and re-check the range before restoring.","For a fresh stream, re-seed the PRNG by constructing it with a valid seed instead of restoring a fabricated state."],"exampleFix":"// before\nrng.restore(saved.rngState); // may be a string/null from JSON\n// after\nconst s = Number(saved.rngState);\nif (!Number.isSafeInteger(s) || s < 0 || s > 0xffffffff) {\n  throw new Error('corrupt saved rng state: ' + saved.rngState);\n}\nrng.restore(s);","handlingStrategy":"type-guard","validationCode":"function isRestorableRngState(s) { return Number.isSafeInteger(s) && s >= 0 && s <= 0xffffffff; }","typeGuard":"function isRngState(v) { return typeof v === 'number' && Number.isSafeInteger(v) && v >= 0 && v <= 0xffffffff; }","tryCatchPattern":"try { rng.restore(saved); } catch (e) { if (e.message.includes('Invalid pet random stream')) { rng = makeRng(DEFAULT_SEED); } else throw e; }","preventionTips":["Persist only values returned by rng.state(), and store them as JSON numbers without reformatting.","Validate the saved state against [0, 0xffffffff] before restoring.","Convert legacy string-typed states with Number() and range-check first.","Fall back to re-seeding rather than fabricating a mid-stream state."],"tags":["random","serialization","validation","javascript"],"backgroundTag":"value-out-of-range","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}