{"record":{"id":"225d04966125c1b2","repo":"JuliusBrussee/caveman","slug":"extract-atlas-name-got-want-want","errorCode":null,"errorMessage":"[extract-atlas] ${name}=${got}, want ${want}","messagePattern":"\\[extract-atlas\\] (.+?)=(.+?), want (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"engine/pixel/internal/atlasgen/extract-atlas.mjs","lineNumber":45,"sourceCode":"function constNumber(src, name) {\n  const re = new RegExp(`export\\\\s+const\\\\s+${name}\\\\s*=\\\\s*(\\\\d+)\\\\s*;`);\n  const m = src.match(re);\n  if (!m) throw new Error(`[extract-atlas] missing numeric const ${name}`);\n  return Number(m[1]);\n}\n\nfunction constB64(src, name) {\n  const re = new RegExp(`const\\\\s+${name}\\\\s*=\\\\s*\"([^\"]+)\"\\\\s*;`);\n  const m = src.match(re);\n  if (!m) throw new Error(`[extract-atlas] missing base64 const ${name}`);\n  return Buffer.from(m[1], 'base64');\n}\n\nfunction assertHeader(src, expected) {\n  for (const [name, want] of Object.entries(expected)) {\n    const got = constNumber(src, name);\n    if (got !== want) {\n      throw new Error(`[extract-atlas] ${name}=${got}, want ${want}`);\n    }\n  }\n}\n\nfunction writeBlob(name, bytes) {\n  const out = join(outDir, name);\n  writeFileSync(out, gzipSync(bytes, { level: 9 }));\n  console.log(`${basename(out)} raw=${bytes.length} gzip=${readFileSync(out).length}`);\n}\n\nconst atlas = readSource('src/core/atlas.ts');\nconst gray = readSource('src/core/atlas-gray.ts');\nassertHeader(atlas, HEADER.atlas);\nassertHeader(gray, HEADER.gray);\n\nwriteBlob('atlas-codepoints.bin.gz', constB64(atlas, 'CODEPOINTS_B64'));\nwriteBlob('atlas-offsets.bin.gz', constB64(atlas, 'OFFSETS_B64'));\nwriteBlob('atlas-wideflags.bin.gz', constB64(atlas, 'WIDE_FLAGS_B64'));","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/engine/pixel/internal/atlasgen/extract-atlas.mjs#L27-L63","documentation":"`assertHeader` verifies that numeric header constants in a source file match expected values recorded by the atlas generator. When a constant's actual value differs from the expected one it throws with both values, signaling that the source and the atlas build are out of sync.","triggerScenarios":"A numeric const in the checked source was edited (dimensions, version, tile size changed) so constNumber returns a value different from the `want` in the expected-header table passed to assertHeader.","commonSituations":"Someone changed a sprite-sheet size constant without regenerating the atlas; two branches diverged (one bumped a version const); a manual edit of generated source; the expected map in extract-atlas.mjs wasn't updated alongside the source.","solutions":["Regenerate the atlas/binary blob so its recorded header matches the current source constants","If the constant change is intentional, update the expected values passed to assertHeader in extract-atlas.mjs","Revert the accidental edit to the constant reported in the message","Add a check in CI that runs extract-atlas after any change to the constants file"],"exampleFix":"// before (source edited but expectations stale)\nexport const ATLAS_VERSION = 3; // assertHeader expects 2\n// after: update expectations\nassertHeader(src, { ATLAS_VERSION: 3, /* ... */ });","handlingStrategy":"validation","validationCode":"import { readFileSync } from \"node:fs\";\nconst src = readFileSync(pipelineFile, \"utf8\");\nfor (const [name, want] of Object.entries(expected)) {\n  const m = src.match(new RegExp(`export\\\\s+const\\\\s+${name}\\\\s*=\\\\s*(\\\\d+)\\\\s*;`));\n  if (!m || Number(m[1]) !== want) throw new Error(`${name} drifted; regenerate atlas`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  runAtlasExtract();\n} catch (e) {\n  const m = String(e.message).match(/\\[extract-atlas\\] (\\w+)=(\\d+), want (\\d+)/);\n  if (m) {\n    console.error(`${m[1]} changed ${m[3]} -> ${m[2]}; regenerate the atlas or update expectations`);\n  } else throw e;\n}","preventionTips":["Regenerate atlas artifacts whenever the header constants change","Keep expected values in one place next to the constants they mirror","Run extract-atlas in CI to catch drift early","Avoid hand-editing generated source files"],"tags":["validation","atlas","build"],"backgroundTag":"checksum-mismatch","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}