{"record":{"id":"c7254e1f9626c516","repo":"paperclipai/paperclip","slug":"a-safe-unique-revision-is-required","errorCode":null,"errorMessage":"A safe, unique --revision is required","messagePattern":"A safe, unique --revision is required","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/scripts/refresh-runner-protocol-eval-report.mjs","lineNumber":21,"sourceCode":"import { execFileSync } from \"node:child_process\";\nimport { createHash } from \"node:crypto\";\nimport { mkdir, readFile, writeFile, lstat, readdir } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\nimport { sanitizeProtocolEvalRuns } from \"./runner-protocol-eval-campaign.mjs\";\nimport { validatePublicProtocolEvalReport } from \"./publish-runner-protocol-eval-history.mjs\";\nimport { sumAttemptCosts } from \"./runner-protocol-eval-metrics.mjs\";\n\nexport async function refreshProtocolEvalReport({\n  sourceRoot,\n  evalsRoot,\n  viewerRoot,\n  outputRoot,\n  revision,\n  selection,\n  renderedAt = new Date().toISOString(),\n}) {\n  if (!/^[a-z0-9][a-z0-9-]{0,39}$/.test(revision ?? \"\"))\n    throw new Error(\"A safe, unique --revision is required\");\n  if (await lstat(outputRoot).catch(() => null))\n    throw new Error(\"Report refresh output must be a new directory\");\n  const campaign = JSON.parse(\n    await readFile(join(sourceRoot, \"campaign.json\"), \"utf8\"),\n  );\n  if (!/^gha-[1-9][0-9]*-[1-9][0-9]*$/.test(campaign.campaignId ?? \"\"))\n    throw new Error(\"Expected an original Actions campaign\");\n  const program = join(\n    evalsRoot,\n    \"evals/paperclip-runner/tools/eval_program.py\",\n  );\n  const rendererDigest = createHash(\"sha256\")\n    .update(await readFile(program))\n    .digest(\"hex\");\n  await mkdir(outputRoot, { recursive: true });\n  const runsRoot = join(outputRoot, \"public-runs\");\n  const reportRoot = join(outputRoot, \"report\");\n  await sanitizeProtocolEvalRuns({","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/scripts/refresh-runner-protocol-eval-report.mjs#L3-L39","documentation":"refreshProtocolEvalReport validates the --revision argument against /^[a-z0-9][a-z0-9-]{0,39}$/ before creating a new report output directory. The error means the revision was missing or contained unsafe characters (uppercase, underscores, slashes, >40 chars, leading hyphen). Revisions become directory names, so the check prevents path injection and collisions.","triggerScenarios":"Running refresh-runner-protocol-eval-report.mjs without --revision, or with a revision like 'Fix_Bug#1', 'My Revision', a 50-char string, or one starting with '-'.","commonSituations":"A CI step interpolates a branch name (contains '/') as the revision; the flag is forgotten entirely; someone reuses a timestamp with colons from a Date string.","solutions":["Supply --revision with lowercase alphanumeric/hyphen text, 1-40 chars, starting with a letter or digit","Slugify the source string (e.g. branch name) to lowercase-hyphen form before passing","For uniqueness, prefix with a run number: gha-${{ github.run_id }}-... or a date like 20260909a","Check the resolved argv: the flag name must be exactly --revision"],"exampleFix":"// before\nnode refresh-runner-protocol-eval-report.mjs --revision feature/Fix_Bug\n// after\nnode refresh-runner-protocol-eval-report.mjs --revision fix-bug-1234","handlingStrategy":"validation","validationCode":"if (!/^[a-z0-9][a-z0-9-]{0,39}$/.test(revision ?? '')) throw new Error('Bad revision: ' + revision);","typeGuard":"const isSafeRevision = (v) => typeof v === 'string' && /^[a-z0-9][a-z0-9-]{0,39}$/.test(v);","tryCatchPattern":"try { await refreshProtocolEvalReport({ revision }); } catch (e) { if (e.message.includes('--revision is required')) console.error('Provide --revision matching ^[a-z0-9][a-z0-9-]{0,39}$'); throw e; }","preventionTips":["Slugify branch/ticket names to lowercase-hyphen before using as revision","Include a run number or date for uniqueness","Keep revisions under 40 chars"],"tags":["cli","validation","revision"],"backgroundTag":"invalid-cli-argument","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}