{"record":{"id":"fa419e79590b6a39","repo":"paperclipai/paperclip","slug":"label-smoke-artifacts-are-older-than-their-sour","errorCode":null,"errorMessage":"${label} smoke artifacts are older than their source. Rebuild the targeted artifacts before running the smoke.","messagePattern":"(.+?) smoke artifacts are older than their source\\. Rebuild the targeted artifacts before running the smoke\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/scripts/run-local-provider-smoke.mjs","lineNumber":122,"sourceCode":"      if (!skipDirectory(path)) {\n        files.push(...(await filesUnder(path, include, skipDirectory)));\n      }\n    } else if (entry.isFile() && include(path)) {\n      files.push(path);\n    }\n  }\n  return files;\n}\n\nasync function assertArtifactsFresh(label, sources, artifacts) {\n  const sourceTimes = await Promise.all(\n    sources.map(async (source) => (await stat(source)).mtimeMs),\n  );\n  const artifactTimes = await Promise.all(\n    artifacts.map(async (artifact) => (await stat(artifact)).mtimeMs),\n  );\n  if (Math.max(...sourceTimes) > Math.min(...artifactTimes)) {\n    throw new Error(\n      `${label} smoke artifacts are older than their source. Rebuild the targeted artifacts before running the smoke.`,\n    );\n  }\n}\n\nconst profiles = parseProfiles(process.argv.slice(2));\nconst packageRoot = resolve(import.meta.dirname, \"..\");\nconst runnerd = resolve(\n  packageRoot,\n  \"runner\",\n  \"target\",\n  \"debug\",\n  process.platform === \"win32\" ? \"paperclip-runnerd.exe\" : \"paperclip-runnerd\",\n);\nconst requiredArtifacts = [\n  runnerd,\n  resolve(packageRoot, \"dist\", \"eval\", \"index.js\"),\n  ...(profiles.some((profile) => profile.startsWith(\"runner-acpx-\"))","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/scripts/run-local-provider-smoke.mjs#L104-L140","documentation":"assertArtifactsFresh compares the newest mtime of source files against the oldest mtime of the built artifacts used by the smoke. If any source is newer than any artifact, the stale-artifact guard throws so the smoke does not test outdated binaries. It is a freshness invariant, not a build error.","triggerScenarios":"Editing TypeScript or Rust sources (or any file in the sources list) after the last build, then running `pnpm smoke:local-provider` without rebuilding. Also triggered by filesystem operations that touch source mtimes (git checkout, rebase, stash pop) after a build.","commonSituations":"Pulling new commits that touch sources while keeping dist/ artifacts, switching branches, or building once and iterating on code before rerunning the smoke.","solutions":["Rebuild the targeted artifacts: run `pnpm build:typescript` and `pnpm build:runner-binaries`, then rerun the smoke.","If only one artifact set is stale, rebuild just that set so its mtime is newer than all sources.","Avoid touching sources between build and smoke; if a git operation refreshed mtimes unnecessarily, rebuild."],"exampleFix":"// before\npnpm smoke:local-provider -- --profile all\n// after\npnpm build:typescript && pnpm build:runner-binaries && pnpm smoke:local-provider -- --profile all","handlingStrategy":"validation","validationCode":"const { statSync } = require('fs');\nconst newestSource = Math.max(...srcs.map(s => statSync(s).mtimeMs));\nconst oldestArtifact = Math.min(...arts.map(a => statSync(a).mtimeMs));\nif (newestSource > oldestArtifact) console.log('rebuild before smoke');","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Rebuild after every source edit before smokes","Rebuild after git pull/rebase/checkout","Wrap build+smoke in one command"],"tags":["build","stale-artifacts","mtime","smoke-test"],"backgroundTag":"stale-build-artifact","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}