{
  "study": "filtering-effects-2026-10-27",
  "runtime": "Node.js 26.8.2",
  "api": "https://api.octocounts.com",
  "datasetSha256": "03dc0f9f6a0896bad5cb2bb25edd0ffcd7f067ce777b7fe2847d06488339ba34",
  "files": {
    "scripts/collect-research-sample.mjs": {
      "sha256": "b3c8fdf17a090351f2472204b3d50565caa5bd1aa21fef5c440847fb56d932d4",
      "content": "#!/usr/bin/env node\n// Sequential, commit-pinned research collection; raw reports survive cache eviction.\n// NODE_USE_SYSTEM_CA=1 node scripts/collect-research-sample.mjs --repos owner/repo,... --out /tmp/study.jsonl --max-repos 10\nimport assert from \"node:assert/strict\";\nimport { appendFile, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { createHash } from \"node:crypto\";\nimport { parseArgs } from \"node:util\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { analyzeAndWait } from \"../cli/src/api.js\";\n\nconst ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), \"..\");\nconst API = process.env.OCTOCOUNTS_API ?? \"https://api.octocounts.com\";\nconst base = { ignoredDirs: [], ignoredLanguages: [], profile: \"default\", includeDocs: true, includeTests: true, includeGenerated: true, respectGitattributes: false };\nexport const CONFIGS = [\n  { config: \"default\", options: { ...base } },\n  { config: \"exclude-tests\", options: { ...base, includeTests: false } },\n  { config: \"exclude-docs\", options: { ...base, includeDocs: false } },\n  { config: \"exclude-generated\", options: { ...base, includeGenerated: false } },\n  { config: \"repository-declarations\", options: { ...base, includeGenerated: false, respectGitattributes: true } },\n];\n\nexport async function collectRun(repository, entry, pinnedCommit, collectorSha256) {\n  const started = Date.now();\n  const row = { study: \"filtering-effects\", repository, config: entry.config, options: entry.options, refName: pinnedCommit || null, collectedAt: new Date().toISOString(), collectorSha256 };\n  try {\n    if (entry.config !== \"default\" && !pinnedCommit) throw new Error(\"baseline failed; variant not submitted without a pinned commit\");\n    const report = await analyzeAndWait(API, { repoUrl: `https://github.com/${repository}`, refName: pinnedCommit || undefined, forceRefresh: false, options: entry.options, source: \"api\" });\n    row.report = report;\n    assert.match(report.commitSha, /^[a-f0-9]{40}$/i, \"complete commit SHA required\");\n    if (pinnedCommit) assert.equal(report.commitSha, pinnedCommit, \"variant changed the measured commit\");\n    assert.equal(`${report.repository.owner}/${report.repository.name}`.toLowerCase(), repository.toLowerCase(), \"repository mismatch\");\n    assert.ok(report.id && report.tokeiVersion && Number.isFinite(Date.parse(report.generatedAt)), \"report provenance required\");\n    assert.ok(report.countingPolicy?.version && report.countingPolicy.repositoryAttributes?.status, \"effective counting rules required\");\n    for (const key of [\"includeDocs\", \"includeTests\", \"includeGenerated\"]) assert.equal(report.countingPolicy[key], entry.options[key], `effective ${key} differs`);\n    assert.equal(report.analysisOptions?.respectGitattributes ?? false, entry.options.respectGitattributes, \"repository declaration option differs\");\n    for (const key of [\"files\", \"lines\", \"code\", \"comments\", \"blanks\"]) assert.ok(Number.isFinite(report.total?.[key]) && report.total[key] >= 0, `invalid ${key}`);\n    return { ...row, outcome: \"ok\", wallTimeMs: Date.now() - started, commitSha: report.commitSha, tokeiVersion: report.tokeiVersion, totals: report.total, report };\n  } catch (error) {\n    return { ...row, outcome: \"failed\", wallTimeMs: Date.now() - started, error: error.message, jobId: error.jobId ?? null };\n  }\n}\n\nasync function main() {\n  const { values } = parseArgs({ options: { repos: { type: \"string\" }, out: { type: \"string\" }, \"max-repos\": { type: \"string\", default: \"2\" }, \"dry-run\": { type: \"boolean\", default: false } } });\n  const repos = values.repos?.split(\",\").map(value => value.trim()) ?? [];\n  const cap = Number(values[\"max-repos\"]);\n  assert.ok(repos.length && values.out, \"--repos and --out are required\");\n  assert.ok(Number.isInteger(cap) && cap > 0 && cap <= 20, \"--max-repos must be 1–20\");\n  assert.ok(repos.every(repo => /^[A-Za-z0-9_.-]+\\/[A-Za-z0-9_.-]+$/.test(repo)), \"repositories must use owner/name\");\n  assert.equal(new Set(repos.map(repo => repo.toLowerCase())).size, repos.length, \"duplicate repository\");\n  const selected = repos.slice(0, cap);\n  if (values[\"dry-run\"]) return console.log(JSON.stringify({ api: API, repos: selected, configs: CONFIGS }, null, 2));\n  const output = path.resolve(ROOT, values.out);\n  const collectorSha256 = createHash(\"sha256\").update(await readFile(fileURLToPath(import.meta.url))).digest(\"hex\");\n  await mkdir(path.dirname(output), { recursive: true });\n  await writeFile(output, \"\", { flag: \"wx\" }); // Never truncate earlier measurements.\n  let first = true;\n  for (const repository of selected) {\n    let pinnedCommit;\n    for (const entry of CONFIGS) {\n      // Stay below the public 5/minute analysis limit, even on cache hits.\n      if (!first) await new Promise(resolve => setTimeout(resolve, 13_000));\n      first = false;\n      const row = await collectRun(repository, entry, pinnedCommit, collectorSha256);\n      if (entry.config === \"default\" && row.outcome === \"ok\") pinnedCommit = row.commitSha;\n      await appendFile(output, `${JSON.stringify(row)}\\n`);\n      console.log(`${repository} ${entry.config}: ${row.outcome} ${row.totals ? `code=${row.totals.code}` : row.error}`);\n    }\n  }\n  console.log(`done → ${output}`);\n}\n\nif (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {\n  main().catch(error => { console.error(error.message); process.exitCode = 1; });\n}\n"
    },
    "cli/src/api.js": {
      "sha256": "b0ffc7be4e654870fc06f02660f03166a2921483f73b04b212e0c0805eb5cc77",
      "content": "export function repositoryOptions(enabled) {\n  if (enabled !== undefined && typeof enabled !== \"boolean\") throw new Error(\"respect_gitattributes must be a boolean\");\n  return enabled ? { ignoredDirs: [], ignoredLanguages: [], profile: \"default\", includeDocs: false, includeTests: false, includeGenerated: false, respectGitattributes: true } : undefined;\n}\n\nexport async function analyzeAndWait(apiBase, request, { signal, timeoutMs = 300_000 } = {}) {\n  const controller = new AbortController();\n  signal?.throwIfAborted();\n  const abort = () => controller.abort(signal.reason);\n  signal?.addEventListener(\"abort\", abort, { once: true });\n  const deadline = Date.now() + timeoutMs;\n  const timer = setTimeout(() => controller.abort(new DOMException(\"OctoCounts analysis timed out\", \"TimeoutError\")), timeoutMs);\n  const context = { signal: controller.signal, deadline };\n  let jobId;\n  try {\n    const result = await fetchJson(`${apiBase}/api/analyze`, { method: \"POST\", headers: { \"content-type\": \"application/json\" }, body: JSON.stringify(request) }, context);\n    if (result?.kind === \"cached\" && result.report) return result.report;\n    if (result?.kind !== \"job\" || !result.jobId) throw new Error(\"Unexpected OctoCounts analyze response\");\n    jobId = result.jobId;\n    while (Date.now() < deadline) {\n      const job = await fetchJson(`${apiBase}/api/jobs/${encodeURIComponent(jobId)}?wait=20`, {}, context);\n      if (job.status === \"completed\" && job.reportId) return await fetchJson(`${apiBase}/api/reports/${encodeURIComponent(job.reportId)}`, {}, context);\n      if (job.status === \"failed\") throw Object.assign(new Error(`${job.error?.code ? `[${job.error.code}] ` : \"\"}${job.error?.message ?? \"OctoCounts analysis failed\"}`), { code: job.error?.code });\n      await sleep(250, controller.signal);\n    }\n    throw new Error(\"OctoCounts analysis timed out\");\n  } catch (error) {\n    if (jobId) throw Object.assign(new Error(`${error.message}; job ${jobId}; resume with GET ${apiBase}/api/jobs/${encodeURIComponent(jobId)}`, { cause: error }), { status: error.status, code: error.code, retryAfterMs: error.retryAfterMs, jobId });\n    throw error;\n  } finally {\n    clearTimeout(timer);\n    signal?.removeEventListener(\"abort\", abort);\n  }\n}\n\nexport async function fetchJson(url, init = {}, { signal = init.signal, deadline = Date.now() + 300_000 } = {}) {\n  const isGet = !init.method || init.method === \"GET\";\n  for (let attempt = 0; ; attempt += 1) {\n    signal?.throwIfAborted();\n    if (Date.now() >= deadline) throw new DOMException(\"OctoCounts request timed out\", \"TimeoutError\");\n    const controller = new AbortController();\n    const abort = () => controller.abort(signal.reason);\n    signal?.addEventListener(\"abort\", abort, { once: true });\n    const timer = setTimeout(() => controller.abort(new DOMException(\"OctoCounts request timed out\", \"TimeoutError\")), Math.min(30_000, deadline - Date.now()));\n    let failure;\n    try {\n      return await readJsonResponse(await fetch(url, { ...init, signal: controller.signal }));\n    } catch (error) {\n      failure = error;\n    } finally {\n      clearTimeout(timer);\n      signal?.removeEventListener(\"abort\", abort);\n    }\n    signal?.throwIfAborted();\n    const canRetry = failure.status !== undefined\n      ? [429, 500, 502, 503, 504].includes(failure.status) && (isGet || failure.requestAccepted === false)\n      : isGet && (failure instanceof TypeError || failure.name === \"TimeoutError\");\n    const waitMs = failure.retryAfterMs ?? 500 * 2 ** attempt + Math.random() * 250;\n    if (!canRetry || attempt >= 3 || !Number.isFinite(waitMs) || Date.now() + waitMs >= deadline) throw failure;\n    await sleep(waitMs, signal);\n  }\n}\n\nexport async function readJsonResponse(response) {\n  const text = await response.text();\n  let body;\n  try { body = JSON.parse(text); } catch { body = null; }\n  if (!response.ok || body === null) {\n    const error = new Error(`HTTP ${response.status}${body?.code ? ` [${body.code}]` : \"\"}: ${body?.message ?? (response.statusText || \"invalid JSON response\")}`);\n    error.status = response.status;\n    error.code = body?.code;\n    error.requestAccepted = body?.requestAccepted;\n    error.retryAfterMs = retryAfterMs(response.headers.get(\"retry-after\"));\n    error.body = body;\n    if (error.retryAfterMs !== undefined) error.message += `; retry after ${Math.ceil(error.retryAfterMs / 1000)} seconds`;\n    throw error;\n  }\n  return body;\n}\n\nexport function retryAfterMs(value) {\n  if (value === null) return undefined;\n  if (/^\\d+$/.test(value.trim())) return Number(value) * 1000;\n  const timestamp = Date.parse(value);\n  return Number.isFinite(timestamp) ? Math.max(0, timestamp - Date.now()) : undefined;\n}\n\nfunction sleep(ms, signal) {\n  signal?.throwIfAborted();\n  return new Promise((resolve, reject) => {\n    const abort = () => { clearTimeout(timer); signal?.removeEventListener(\"abort\", abort); reject(signal.reason); };\n    const timer = setTimeout(() => { signal?.removeEventListener(\"abort\", abort); resolve(); }, ms);\n    signal?.addEventListener(\"abort\", abort, { once: true });\n  });\n}\n\nexport function reportUrl(report) {\n  const base = `https://octocounts.com/github/${encodeURIComponent(report.repository.owner)}/${encodeURIComponent(report.repository.name)}`;\n  const ref = String(report.commitSha || report.refName || \"\").trim();\n  const params = new URLSearchParams();\n  if (report.id) params.set(\"reportId\", report.id);\n  if (report.analysisOptions) params.set(\"analysis\", JSON.stringify(report.analysisOptions));\n  const query = params.toString();\n  return `${base}${ref ? `/${/^[a-f0-9]{7,40}$/i.test(ref) ? \"commit\" : \"tree\"}/${ref.split(\"/\").map(encodeURIComponent).join(\"/\")}` : \"\"}${query ? `?${query}` : \"\"}`;\n}\n\nexport function policyCompatibility(left, right) {\n  if (!left.countingPolicy || !right.countingPolicy) return \"unknown\";\n  const signature = (report) => {\n    const { repositoryAttributes, ignoredDirs, ignoredLanguages, ...policy } = report.countingPolicy;\n    return JSON.stringify({ version: policy.version, includeDocs: policy.includeDocs, includeTests: policy.includeTests, includeGenerated: policy.includeGenerated, engine: report.tokeiVersion, ignoredDirs: [...new Set(ignoredDirs)].sort(), ignoredLanguages: [...new Set(ignoredLanguages.map((language) => language.toLowerCase()))].sort(), attributes: repositoryAttributes.status !== \"off\" });\n  };\n  return signature(left) === signature(right) ? \"same\" : \"different\";\n}\n"
    }
  },
  "replay": "Restore files at their recorded relative paths. For a fixed-commit replay, import collectRun and pass each row.repository, {config: row.config, options: row.options}, and row.commitSha. Pace requests below the public limit. Production engine/policy upgrades can change results; compare the returned versions and effective rules."
}
