{"record":{"id":"31d18be9dc63a304","repo":"santifer/career-ops","slug":"skipping-file-report-reportnum-is-mark","errorCode":null,"errorMessage":"⚠️  Skipping ${file}: report #${reportNum} is marked \"failed\" in batch-state.tsv — refusing to merge a tracker line for an offer the batch runner itself recorded as failed (possible fabricated result)","messagePattern":"⚠️  Skipping (.+?): report #(.+?) is marked \"failed\" in batch-state\\.tsv — refusing to merge a tracker line for an offer the batch runner itself recorded as failed \\(possible fabricated result\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"merge-tracker.mjs","lineNumber":1018,"sourceCode":"  // The TSV convention carries a root-relative `reports/...` link; rewrite it\n  // so it resolves correctly when clicked from applications.md (see #760).\n  addition.report = normalizeReportLink(addition.report);\n\n  // Derive the key from the linked report when the TSV did not carry one, so a\n  // row added through the normal nine-column flow is born WITH its key. This\n  // must run before the dedup below reads addition.url — deriving it afterwards\n  // would populate the column while leaving Pass 0 nothing to match on, which is\n  // the original bug with extra steps.\n  if (!addition.url) addition.url = resolveReportUrl(addition.report).url;\n\n  // Check for duplicate by:\n  // 0. Exact normalized posting URL (deterministic, authoritative)\n  // 1. Exact report number match\n  // 2. Company + role fuzzy match\n  const reportNum = extractReportNum(addition.report, addition.notes);\n\n  if (reportNum && FAILED_REPORT_NUMBERS.has(reportNum)) {\n    console.warn(`⚠️  Skipping ${file}: report #${reportNum} is marked \"failed\" in batch-state.tsv — refusing to merge a tracker line for an offer the batch runner itself recorded as failed (possible fabricated result)`);\n    skipped++;\n    continue;\n  }\n\n  let duplicate = null;\n  // True only for a tier-1 match (report number + company): the one heuristic\n  // tier where the addition is provably the same evaluation as the existing\n  // row, so its role title may replace the row's. Tier-2 (entry num) and\n  // tier-3 (fuzzy role) matches keep the existing title — a fuzzy false\n  // positive that also rewrites the title destroys the evidence that two reqs\n  // were distinct. Pass 0 (URL) grants the same trust for the same reason; it\n  // tracks that separately in `dupReason`.\n  let reportNumMatched = false;\n\n  // Pass 0 — the posting URL is the stable natural key. When it hits it is\n  // authoritative and no heuristic runs. Tiers 1-3 below remain the fallback\n  // for rows with no URL yet.\n  const addUrl = normalizeUrl(addition.url);","sourceCodeStart":1000,"sourceCodeEnd":1036,"githubUrl":"https://github.com/santifer/career-ops/blob/60398d6549a46f5266929538af21cfab94badc75/merge-tracker.mjs#L1000-L1036","documentation":"Safety gate in merge-tracker.mjs against fabricated batch results: the batch runner records failed evaluations by report number in batch-state.tsv, and those numbers are loaded into FAILED_REPORT_NUMBERS. If an additions file cites one of those report numbers, the tracker line is refused — a worker that failed cannot legitimately have produced a tracker row for that offer.","triggerScenarios":"A batch worker crashes mid-evaluation (recorded 'failed' in batch-state.tsv for report #042) but a leftover tracker-additions TSV for #042 still sits in the directory — extractReportNum() finds the number, the FAILED_REPORT_NUMBERS match fires, and the file is skipped as a possible fabricated result.","commonSituations":"Retried batch runs where the first attempt failed and the second succeeded under a different number; orphaned TSVs from killed workers; mixing additions directories across batch attempts.","solutions":["Check batch-state.tsv and the report file for that number — if the evaluation genuinely failed, delete the orphaned TSV in batch/tracker-additions/","If the evaluation was re-run and succeeded, make sure the TSV cites the new (successful) report number","Re-run the evaluation for that offer so a real report exists, then regenerate the tracker addition from it"],"exampleFix":"# before: orphaned addition citing a failed run\nbatch/tracker-additions/042-acme.tsv  # report 042 = failed in batch-state.tsv\n\n# after: remove it, re-run the evaluation, add the new TSV\nrm batch/tracker-additions/042-acme.tsv\n# re-run eval -> report 043 succeeds\n# batch/tracker-additions/043-acme.tsv merges cleanly","handlingStrategy":"validation","validationCode":"import { readFileSync, existsSync } from 'node:fs';\nfunction loadFailedReportNumbers(batchStatePath) {\n  if (!existsSync(batchStatePath)) return new Set();\n  const failed = new Set();\n  for (const line of readFileSync(batchStatePath, 'utf8').split('\\n')) {\n    const [num, state] = line.split('\\t');\n    if (state && /failed/i.test(state)) failed.add(num.trim());\n  }\n  return failed;\n}\n// Drop addition files whose report link cites a failed number BEFORE merging.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Let the batch runner own tracker-additions files; delete orphans from failed workers instead of merging them","After a failed run, clean batch/tracker-additions/ before the retry so stale lines cannot reach the tracker","Cross-check each addition's report number against batch-state.tsv before merging by hand"],"tags":["tracker","batch","fabricated-result","merge","safety-gate","warning"],"backgroundTag":"fabricated-result-blocked","analyzedSha":"60398d6549a46f5266929538af21cfab94badc75","analyzedAt":"2026-08-20T23:00:06.764Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}