{"version":3,"file":"checkAllProblems.cjs","names":["DecisionCode","path","findDefaultStdioHarnessFiles","formatDefaultHarnessError","findModelAnswerDirs","readTestCases","readProblemMarkdownFrontMatter","judgesWithoutTestCases","MISSING_TEST_CASES_ERROR","findFailingModelAnswerDirs","copyProblemDirToTemporaryRoot","forciblyRemoveDirectory","TEST_CASE_RESULT_PREFIX","testCaseResultSchema","child_process","fs"],"sources":["../../src/cli/checkAllProblems.ts"],"sourcesContent":["import child_process from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\n\nimport {\n  copyProblemDirToTemporaryRoot,\n  forciblyRemoveDirectory,\n  forciblyRemoveDirectorySync,\n} from '../helpers/checkProblemDirIsolation.js';\nimport { findDefaultStdioHarnessFiles } from '../helpers/defaultStdioHarness.js';\nimport { findFailingModelAnswerDirs, findModelAnswerDirs } from '../helpers/findModelAnswerDirs.js';\nimport { judgesWithoutTestCases, readProblemMarkdownFrontMatter } from '../helpers/readProblemMarkdownFrontMatter.js';\nimport { readTestCases } from '../helpers/readTestCases.js';\nimport { DecisionCode } from '../types/decisionCode.js';\nimport { TEST_CASE_RESULT_PREFIX, testCaseResultSchema } from '../types/testCaseResult.js';\n\nimport { formatDefaultHarnessError, MISSING_TEST_CASES_ERROR } from './runSingleHarness.js';\n\nconst RUN_TIMEOUT_MS = 600_000;\nconst MAX_RUN_OUTPUT_BYTES = 64 * 1024 * 1024;\nconst MAX_FAILURE_DETAIL_LENGTH = 1000;\n\n// DecisionCode is a plain const object (not a TypeScript enum), so it has no reverse mapping.\nconst decisionCodeNames = new Map<number, string>(Object.entries(DecisionCode).map(([name, code]) => [code, name]));\n\ninterface CheckOptions {\n  rootDir: string;\n  concurrency: number;\n  only: string[];\n  skip: string[];\n}\n\ninterface CheckRun {\n  problemDir: string;\n  answerDir: string;\n  /** Whether all test cases must be accepted (`model_answers`) or at least one must fail (`model_answers.fails`). */\n  expectation: 'accepted' | 'rejected';\n}\n\n/**\n * Judge all model answers of all problems (directories containing `problem.md` or\n * `<id>.problem.md`) under a root directory: `model_answers/*` must be fully accepted and\n * `model_answers.fails/*` must fail at least one test case. Returns the process exit code.\n */\nexport async function checkAllProblems(args: readonly string[]): Promise<number> {\n  const options = parseCheckArgs(args);\n  const rootDir = path.resolve(options.rootDir);\n  // Normalize to forward slashes so --only / --skip substrings like courses/foo match on Windows.\n  const toRelative = (dir: string): string => (path.relative(rootDir, dir) || '.').replaceAll(path.sep, '/');\n\n  const allProblemDirs = await findProblemDirs(rootDir);\n  const problemDirs = allProblemDirs.filter((problemDir) => {\n    const relativeDir = toRelative(problemDir);\n    if (options.only.length > 0 && !options.only.some((substring) => relativeDir.includes(substring))) return false;\n    return !options.skip.some((substring) => relativeDir.includes(substring));\n  });\n  if (problemDirs.length === 0) {\n    console.error(\n      allProblemDirs.length === 0\n        ? `No problem directories (containing problem.md or <id>.problem.md) found under ${rootDir}.`\n        : `All ${allProblemDirs.length} problem directories under ${rootDir} were excluded by --only/--skip.`\n    );\n    return 1;\n  }\n\n  const failures: string[] = [];\n  const runs: CheckRun[] = [];\n  for (const problemDir of problemDirs) {\n    const defaultHarnessFileNames = await findDefaultStdioHarnessFiles(problemDir);\n    if (defaultHarnessFileNames.length > 0) {\n      failures.push(`${toRelative(problemDir)}: ${formatDefaultHarnessError(defaultHarnessFileNames)}`);\n      continue;\n    }\n\n    const modelAnswerDirs = await findModelAnswerDirs(problemDir);\n    if (modelAnswerDirs.length === 0) {\n      failures.push(`${toRelative(problemDir)}: no model answers found under model_answers/`);\n      continue;\n    }\n\n    // Without test cases, stdioJudgePreset prints a single accepted sentinel result, so a standard\n    // problem with an empty or missing test_cases/ would otherwise pass without being judged —\n    // unless static-analysis rules or manual scoring make the problem judgeable without them.\n    if (!(await fileExists(path.join(problemDir, 'judge.ts')))) {\n      const testCases = await readTestCases(path.join(problemDir, 'test_cases'));\n      if (testCases.length === 0) {\n        let frontMatter;\n        try {\n          frontMatter = await readProblemMarkdownFrontMatter(problemDir);\n        } catch (error) {\n          failures.push(\n            `${toRelative(problemDir)}: failed to read the problem markdown front matter: ${error instanceof Error ? error.message : String(error)}`\n          );\n          continue;\n        }\n        if (!judgesWithoutTestCases(frontMatter)) {\n          failures.push(`${toRelative(problemDir)}: ${MISSING_TEST_CASES_ERROR}`);\n          continue;\n        }\n      }\n    }\n\n    const failingModelAnswerDirs = await findFailingModelAnswerDirs(problemDir);\n    runs.push(\n      ...modelAnswerDirs.map((answerDir): CheckRun => ({ problemDir, answerDir, expectation: 'accepted' })),\n      ...failingModelAnswerDirs.map((answerDir): CheckRun => ({ problemDir, answerDir, expectation: 'rejected' }))\n    );\n  }\n  for (const failure of failures) console.error(`✗ ${failure}`);\n\n  const cliEntryPath = path.resolve(process.argv[1] ?? '');\n  let passedCount = 0;\n  let nextRunIndex = 0;\n  await Promise.all(\n    Array.from({ length: Math.max(1, Math.min(options.concurrency, runs.length)) }, async () => {\n      while (nextRunIndex < runs.length) {\n        const run = runs[nextRunIndex++];\n        if (!run) return;\n        const label = `${toRelative(run.problemDir)} ${path.relative(run.problemDir, run.answerDir).replaceAll(path.sep, '/')}`;\n        const failureDetail = await executeCheckRun(run, cliEntryPath);\n        if (failureDetail === undefined) {\n          passedCount++;\n          console.info(`✓ ${label}`);\n        } else {\n          failures.push(`${label}: ${failureDetail}`);\n          console.error(`✗ ${label}: ${failureDetail}`);\n        }\n      }\n    })\n  );\n\n  console.info(\n    `\\n${passedCount} passed, ${failures.length} failed (${runs.length} runs, ${problemDirs.length} problems)`\n  );\n  return failures.length === 0 ? 0 : 1;\n}\n\n/**\n * Run one answer directory through the problem's harness and return a failure detail, if any.\n * The problem directory is copied to a temporary location first so that judging (e.g. build\n * artifacts in answer directories) never modifies the checked repository.\n */\nasync function executeCheckRun(run: CheckRun, cliEntryPath: string): Promise<string | undefined> {\n  let tempRoot: string;\n  let copiedProblemDir: string;\n  try {\n    ({ tempRoot, copiedProblemDir } = await copyProblemDirToTemporaryRoot(run.problemDir));\n  } catch (error) {\n    return truncate(\n      `failed to copy the problem directory to a temporary location: ${error instanceof Error ? error.message : String(error)}`\n    );\n  }\n\n  let harnessFailureDetail;\n  let removedTempRoot;\n  try {\n    const result = await runHarnessProcess(\n      ['run', cliEntryPath, 'judge', path.relative(run.problemDir, run.answerDir)],\n      copiedProblemDir,\n      tempRoot\n    );\n    harnessFailureDetail = summarizeHarnessFailure(run, result);\n  } catch (error) {\n    harnessFailureDetail = truncate(\n      `harness execution failed: ${error instanceof Error ? error.message : String(error)}`\n    );\n  } finally {\n    removedTempRoot = await forciblyRemoveDirectory(tempRoot);\n  }\n  if (removedTempRoot) return harnessFailureDetail;\n  const removalFailureDetail = `failed to remove the temporary copy at ${tempRoot} (judged code may have left permission-locked files)`;\n  return harnessFailureDetail === undefined\n    ? removalFailureDetail\n    : truncate(`${harnessFailureDetail}; ${removalFailureDetail}`);\n}\n\n/** Return why the harness run failed the check, or `undefined` when it passed. */\nfunction summarizeHarnessFailure(run: CheckRun, result: HarnessProcessResult): string | undefined {\n  const { stdout, stderr } = result;\n  if (result.failureReason !== undefined) return truncate(result.failureReason);\n  if (result.exitCode !== 0) {\n    return truncate(`harness exited with ${result.exitCode ?? 'a signal'}${stderr.trim() ? `: ${stderr.trim()}` : ''}`);\n  }\n\n  const resultLines = stdout.split(/\\r?\\n/).filter((line) => line.startsWith(TEST_CASE_RESULT_PREFIX));\n  const testCaseResults = [];\n  for (const line of resultLines) {\n    let parsedResult;\n    try {\n      parsedResult = testCaseResultSchema.safeParse(JSON.parse(line.slice(TEST_CASE_RESULT_PREFIX.length)));\n    } catch {\n      parsedResult = undefined;\n    }\n    if (!parsedResult?.success) return truncate(`malformed test case result line: ${line}`);\n    testCaseResults.push(parsedResult.data);\n  }\n  if (testCaseResults.length === 0) return 'no test case results were printed';\n\n  if (run.expectation === 'accepted') {\n    const rejectedResult = testCaseResults.find((result) => result.decisionCode !== DecisionCode.ACCEPTED);\n    if (rejectedResult) {\n      return truncate(\n        `${decisionCodeNames.get(rejectedResult.decisionCode) ?? rejectedResult.decisionCode} on test case ${rejectedResult.testCaseId}${rejectedResult.stderr?.trim() ? `: ${rejectedResult.stderr.trim()}` : ''}`\n      );\n    }\n    return undefined;\n  }\n  return testCaseResults.every((result) => result.decisionCode === DecisionCode.ACCEPTED)\n    ? 'expected at least one failing test case, but all test cases were accepted'\n    : undefined;\n}\n\ninterface HarnessProcessResult {\n  stdout: string;\n  stderr: string;\n  exitCode: number | undefined;\n  failureReason: string | undefined;\n}\n\ninterface LiveHarnessRun {\n  pid: number;\n  tempRoot: string;\n}\n\n// Detached harness groups no longer receive the terminal's SIGINT, so an interrupted check run must\n// tear them down (and remove their temp copies) itself before exiting.\nconst liveHarnessRuns = new Set<LiveHarnessRun>();\nlet signalHandlersInstalled = false;\n\n/**\n * Run the harness in its own process group, killing the whole group on timeout or when the output\n * cap is exceeded so grandchild submission processes cannot outlive the run.\n */\nfunction runHarnessProcess(\n  commandArgs: readonly string[],\n  cwd: string,\n  tempRoot: string\n): Promise<HarnessProcessResult> {\n  installSignalHandlers();\n  return new Promise((resolve) => {\n    // process.execPath keeps the harness on the same bun executable regardless of PATH.\n    const child = child_process.spawn(process.execPath, commandArgs, {\n      cwd,\n      detached: process.platform !== 'win32',\n      env: createHarnessEnv(),\n      stdio: ['ignore', 'pipe', 'pipe'],\n    });\n    const liveRun: LiveHarnessRun | undefined = child.pid === undefined ? undefined : { pid: child.pid, tempRoot };\n    if (liveRun) liveHarnessRuns.add(liveRun);\n    const stdoutChunks: Buffer[] = [];\n    const stderrChunks: Buffer[] = [];\n    let totalOutputBytes = 0;\n    let failureReason: string | undefined;\n    let settled = false;\n\n    const killProcessGroup = (reason: string): void => {\n      if (failureReason !== undefined) return;\n      failureReason = reason;\n      // Stop buffering immediately: OS pipe buffers can keep emitting data after the kill, and\n      // destroyed streams also let `close` fire even if a stray grandchild inherited the pipes.\n      child.stdout?.destroy();\n      child.stderr?.destroy();\n      try {\n        if (child.pid === undefined) {\n          child.kill('SIGKILL');\n        } else {\n          killHarnessTree(child.pid);\n        }\n      } catch {\n        child.kill('SIGKILL');\n      }\n    };\n    const timeoutId = setTimeout(\n      () => killProcessGroup(`timed out after ${RUN_TIMEOUT_MS / 1000} seconds`),\n      RUN_TIMEOUT_MS\n    );\n\n    const appendOutput = (chunk: Buffer, chunks: Buffer[]): void => {\n      totalOutputBytes += chunk.byteLength;\n      if (totalOutputBytes > MAX_RUN_OUTPUT_BYTES) {\n        killProcessGroup(`the harness printed more than ${MAX_RUN_OUTPUT_BYTES / 1024 / 1024} MB of output`);\n        return;\n      }\n      chunks.push(chunk);\n    };\n    child.stdout?.on('data', (chunk: Buffer) => appendOutput(chunk, stdoutChunks));\n    child.stderr?.on('data', (chunk: Buffer) => appendOutput(chunk, stderrChunks));\n\n    const settle = (exitCode: number | undefined, spawnError?: Error): void => {\n      if (settled) return;\n      settled = true;\n      clearTimeout(timeoutId);\n      if (liveRun) liveHarnessRuns.delete(liveRun);\n      resolve({\n        stdout: Buffer.concat(stdoutChunks).toString('utf8'),\n        stderr: Buffer.concat(stderrChunks).toString('utf8'),\n        exitCode,\n        failureReason: failureReason ?? (spawnError ? `failed to run the harness: ${spawnError.message}` : undefined),\n      });\n    };\n    child.on('error', (error) => settle(undefined, error));\n    child.on('close', (exitCode) => settle(exitCode ?? undefined));\n  });\n}\n\nfunction installSignalHandlers(): void {\n  if (signalHandlersInstalled) return;\n  signalHandlersInstalled = true;\n  for (const signal of ['SIGINT', 'SIGTERM'] as const) {\n    process.once(signal, () => {\n      for (const liveRun of liveHarnessRuns) {\n        try {\n          killHarnessTree(liveRun.pid);\n        } catch {\n          // The tree already exited.\n        }\n        // Best-effort cleanup while exiting; judged code may have left permission-locked entries.\n        forciblyRemoveDirectorySync(liveRun.tempRoot);\n      }\n      process.kill(process.pid, signal);\n    });\n  }\n}\n\n// On Windows the harness is not detached (process groups are unavailable), so killing only the\n// direct child would leave submission grandchildren running; taskkill terminates the whole tree.\nfunction killHarnessTree(pid: number): void {\n  if (process.platform === 'win32') {\n    child_process.spawnSync('taskkill', ['/PID', String(pid), '/T', '/F'], { stdio: 'ignore' });\n  } else {\n    process.kill(-pid, 'SIGKILL');\n  }\n}\n\n// The all-problem check runs harnesses concurrently and has no sandbox-delegation contract, while the sandbox\n// helpers assume one harness at a time (their pkill targets every process of the sandbox user), so\n// never forward the sandbox user to judged runs.\nfunction createHarnessEnv(): NodeJS.ProcessEnv {\n  const env = { ...process.env };\n  delete env.EXERCODE_SANDBOX_USER;\n  return env;\n}\n\nfunction parseCheckArgs(args: readonly string[]): CheckOptions {\n  const options: CheckOptions = {\n    rootDir: '.',\n    // Serial by default: judging decides TIME_LIMIT_EXCEEDED from wall-clock time, so parallel\n    // runs on a small CI runner could fail timing-sensitive problems non-deterministically.\n    concurrency: 1,\n    only: [],\n    skip: [],\n  };\n  let hasRootDir = false;\n  for (let index = 0; index < args.length; index++) {\n    const arg = args[index];\n    if (arg === undefined) break;\n    if (arg === '--concurrency' || arg === '--only' || arg === '--skip') {\n      const value = args[++index];\n      if (value === undefined) throw new Error(`${arg} requires a value`);\n      if (arg === '--concurrency') {\n        options.concurrency = Number(value);\n        if (!Number.isInteger(options.concurrency) || options.concurrency <= 0) {\n          throw new Error(`--concurrency requires a positive integer, but got ${value}`);\n        }\n      } else if (arg === '--only') {\n        options.only.push(value);\n      } else {\n        options.skip.push(value);\n      }\n    } else if (arg.startsWith('--')) {\n      throw new Error(`Unknown option: ${arg}`);\n    } else if (hasRootDir) {\n      throw new Error(`Only one root directory can be specified, but got both ${options.rootDir} and ${arg}`);\n    } else {\n      options.rootDir = arg;\n      hasRootDir = true;\n    }\n  }\n  return options;\n}\n\n/** Find directories containing `problem.md` or `<id>.problem.md`, without descending into found problems. */\nasync function findProblemDirs(rootDir: string): Promise<string[]> {\n  const problemDirs: string[] = [];\n  await visitDirectory(rootDir, problemDirs);\n  return problemDirs.toSorted();\n}\n\nasync function visitDirectory(dir: string, problemDirs: string[]): Promise<void> {\n  // Traversal errors (e.g. an unreadable subtree) must fail the check: skipping them silently\n  // could report a green result while covering only part of the repository.\n  const entries = await fs.readdir(dir, { withFileTypes: true });\n  if (entries.some((entry) => entry.isFile() && (entry.name === 'problem.md' || entry.name.endsWith('.problem.md')))) {\n    problemDirs.push(dir);\n    return;\n  }\n  for (const entry of entries) {\n    if (!entry.isDirectory() || entry.name === 'node_modules' || entry.name.startsWith('.')) continue;\n    await visitDirectory(path.join(dir, entry.name), problemDirs);\n  }\n}\n\nasync function fileExists(filePath: string): Promise<boolean> {\n  try {\n    await fs.stat(filePath);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\nfunction truncate(text: string): string {\n  return text.length <= MAX_FAILURE_DETAIL_LENGTH ? text : `${text.slice(0, MAX_FAILURE_DETAIL_LENGTH)}...`;\n}\n"],"mappings":"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"}