{"challengeId":"bf-golf","entry":"verifier.mjs","sha256":"2f8090a1af20fe3f4d7592cb3396763e68642a10b417adbf2ce651755d1d2a5c","scoreDirection":"minimize","scoreLabel":"bytes","seedPolicy":{"mode":"fixed","testCount":1},"source":"// Frozen verifier for bf-golf. Self-contained (no imports): it interprets the\n// candidate's program on its OWN tiny Brainfuck-class VM and returns a Verdict.\n// It never executes agent code in the parent realm — build() already ran in the\n// sandbox and handed us a plain string of VM instructions, which this verifier\n// simulates exactly like busy-beaver simulates a Turing-machine description.\n// This file is part of the challenge's PROTECTED surface.\n//\n// The task is exact: the program's output must equal, byte for byte, the 95\n// printable ASCII characters 0x20..0x7E in ascending order. Exact-match output\n// is total correctness — there is no hidden input and nothing to overfit, so\n// seedPolicy.mode is \"fixed\". The score is the program's length in bytes\n// (every byte must be one of the 7 ops), so shorter passing programs win.\n//\n// VM semantics (fully specified in spec.md):\n//   30,000 cells, each an unsigned 8-bit integer wrapping mod 256, all zero at\n//   start; the data pointer starts at cell 0 and must stay in bounds (moving it\n//   below 0 or past cell 29,999 fails the run); ops: + - < > . [ ] with the\n//   usual meanings; every executed instruction (brackets included) costs one\n//   step against a hard cap of 1,000,000 steps. No input op exists.\n\nconst OPS = '+-<>.[]';\nconst MAX_SRC = 4096;\nconst TAPE_LEN = 30000;\nconst STEP_CAP = 1_000_000;\nconst TARGET_LEN = 95; // printable ASCII 0x20..0x7E\n\nfunction gate(name, pass, detail) {\n  return { name, pass, detail };\n}\nfunction bad(name, detail) {\n  return { ok: false, score: null, gates: [gate(name, false, detail)], behavior: {}, logs: [] };\n}\n\nexport function verify(ctx) {\n  const sol = ctx.solution;\n  const src = sol && typeof sol === 'object' ? sol.src : undefined;\n  if (typeof src !== 'string') {\n    return bad('structure', 'expected { src: \"<program string>\" }');\n  }\n  if (src.length === 0) return bad('structure', 'program is empty');\n  if (src.length > MAX_SRC) return bad('structure', `program too long (> ${MAX_SRC} bytes)`);\n\n  // Every byte must be one of the 7 ops, and brackets must balance. Precompute\n  // the bracket jump table while validating.\n  const jump = new Array(src.length).fill(-1);\n  const stack = [];\n  for (let i = 0; i < src.length; i++) {\n    const ch = src[i];\n    if (OPS.indexOf(ch) < 0) {\n      return bad('structure', `byte ${i} is not one of the 7 ops \"${OPS}\"`);\n    }\n    if (ch === '[') stack.push(i);\n    else if (ch === ']') {\n      if (stack.length === 0) return bad('structure', `unmatched ']' at byte ${i}`);\n      const open = stack.pop();\n      jump[open] = i;\n      jump[i] = open;\n    }\n  }\n  if (stack.length > 0) return bad('structure', `unmatched '[' at byte ${stack[stack.length - 1]}`);\n\n  // Deterministic run on the frozen VM.\n  const tape = new Uint8Array(TAPE_LEN);\n  const out = [];\n  let p = 0;\n  let ip = 0;\n  let steps = 0;\n  let runFail = '';\n  while (ip < src.length) {\n    if (steps >= STEP_CAP) {\n      // Plain ${STEP_CAP} (not toLocaleString) — locale is ambient state, and a\n      // frozen verifier's output must be byte-identical in every environment.\n      runFail = `did not halt within ${STEP_CAP} steps`;\n      break;\n    }\n    steps++;\n    const ch = src[ip];\n    if (ch === '+') tape[p] = (tape[p] + 1) & 0xff;\n    else if (ch === '-') tape[p] = (tape[p] + 255) & 0xff;\n    else if (ch === '>') {\n      p++;\n      if (p >= TAPE_LEN) {\n        runFail = `data pointer moved past cell ${TAPE_LEN - 1}`;\n        break;\n      }\n    } else if (ch === '<') {\n      p--;\n      if (p < 0) {\n        runFail = 'data pointer moved below cell 0';\n        break;\n      }\n    } else if (ch === '.') {\n      out.push(tape[p]);\n      if (out.length > TARGET_LEN) {\n        runFail = `emitted more than ${TARGET_LEN} bytes`;\n        break;\n      }\n    } else if (ch === '[') {\n      if (tape[p] === 0) ip = jump[ip];\n    } else if (ch === ']') {\n      if (tape[p] !== 0) ip = jump[ip];\n    }\n    ip++;\n  }\n\n  if (runFail) {\n    return {\n      ok: false,\n      score: null,\n      gates: [gate('halts-in-bounds', false, runFail)],\n      behavior: {},\n      logs: [`ran ${steps} steps, emitted ${out.length} bytes`],\n    };\n  }\n\n  // Output gate: byte-exact equality with printable ASCII 0x20..0x7E ascending.\n  // The target is generated arithmetically (codes 32..126) — equivalent byte for\n  // byte to embedding the 95-character constant, with no escaping hazards.\n  let mismatch = '';\n  if (out.length !== TARGET_LEN) {\n    mismatch = `emitted ${out.length} bytes, expected ${TARGET_LEN}`;\n  } else {\n    for (let i = 0; i < TARGET_LEN; i++) {\n      if (out[i] !== 32 + i) {\n        mismatch = `byte ${i} is ${out[i]}, expected ${32 + i}`;\n        break;\n      }\n    }\n  }\n\n  const gates = [\n    gate('halts-in-bounds', true, `halted after ${steps} steps`),\n    gate('exact-output', !mismatch, mismatch || `all ${TARGET_LEN} printable ASCII bytes emitted in order`),\n  ];\n  const ok = gates.every((g) => g.pass);\n  return {\n    ok,\n    score: ok ? src.length : null,\n    gates,\n    behavior: { bytes: src.length, steps },\n    logs: [`bytes=${src.length} steps=${steps} out=${out.length}`],\n  };\n}\n"}