santifer/career-ops · warning

⚠️ ${s.url} — batch reports report #${s.reportNum} but no r

Error message

⚠️  ${s.url} — batch reports report #${s.reportNum} but no reports/${s.reportNum}-*.md found; left in Pendientes.

What it means

reconcile-pipeline.mjs moves processed pipeline.md entries into the done section by trusting the report numbers recorded in batch TSVs. When a TSV claims report #N but no reports/N-*.md exists, the entry is deliberately left in Pendientes (skippedNoReport) and this warning is printed -- refusing to write a done-line whose report link is dead.

Source

Thrown at reconcile-pipeline.mjs:240

  const parts = body.split('|').map(s => s.trim());
  const company = parts[1] || '';
  const role = parts[2] || '';
  const score = resolveScore(done.score, reportFile);
  const pdf = resolvePdf(reportFile);
  const num = parseInt(done.reportNum, 10);

  const reportLink = normalizeReportLink(`[${num}](reports/${reportFile})`, dirname(PIPELINE_FILE), CAREER_OPS);
  movedProcLines.push(`- [x] ${reportLink} | ${url} | ${company} | ${role} | ${score} | PDF ${pdf}`);
  moved.push({ url, company, role, num, score });
  procUrls.add(url);
  removeIdx.add(i);
}

// ---- report & exit early if nothing changed ----
console.log('=== Reconcile pipeline.md ===');
for (const s of skippedNoReport) {
  console.warn(`⚠️  ${s.url} — batch reports report #${s.reportNum} but no reports/${s.reportNum}-*.md found; left in Pendientes.`);
}

if (removeIdx.size === 0) {
  console.log('✅ pipeline.md already in sync — nothing to reconcile.');
  process.exit(0);
}

// ---- rebuild the file ----
const out = [];
let skipBlankAfterProc = false;
for (let i = 0; i < lines.length; i++) {
  if (removeIdx.has(i)) continue;
  if (skipBlankAfterProc) {
    skipBlankAfterProc = false;
    if (lines[i].trim() === '') continue; // drop the original blank after "## Procesadas"
  }
  out.push(lines[i]);
  if (i === procStart && movedProcLines.length > 0) {

View on GitHub (pinned to 60398d6549)

Solutions

  1. Locate the real report: ls reports/ | grep <number or company-slug> -- it may exist under a different number.
  2. Fix the TSV's report number to match the actual file, or re-run the evaluation for that URL if the report truly never landed.
  3. Re-run node reconcile-pipeline.mjs; the entry moves once the link resolves.

Example fix

# before: TSV claims a report that does not exist
064	2026-08-20	Acme	...	[064](reports/064-acme-2026-08-20.md)	...
$ ls reports/ | grep acme   # -> 065-acme-2026-08-20.md
# after: point the TSV at the real file and re-run reconcile
064	2026-08-20	Acme	...	[064](reports/065-acme-2026-08-20.md)	...
Defensive patterns

Strategy: validation

Validate before calling

// Before reconcile, confirm every TSV's report number has a real file
import { readdirSync, readFileSync, existsSync } from 'node:fs';
const reports = new Set(readdirSync('reports'));
for (const f of readdirSync('batch/tracker-additions').filter(f => f.endsWith('.tsv'))) {
  const cells = readFileSync(`batch/tracker-additions/${f}`, 'utf-8').trim().split('\t');
  const num = cells[0].padStart(3, '0');
  if (![...reports].some(r => r.startsWith(`${num}-`)))
    console.error(`${f}: report #${num} has no reports/${num}-*.md`);
}

Prevention

When it happens

Trigger: A batch worker wrote the tracker TSV but crashed before writing the report file; the report was deleted or renamed by hand; reconcile running against a different CAREER_OPS root than the one hosting reports/.

Common situations: Interrupted parallel batch runs; overzealous manual cleanup of reports/; git operations dropping untracked report files; stale batch/tracker-additions/ from an old session.

Related errors


AI-assisted analysis of santifer/career-ops@60398d6549 (2026-08-20). Data as JSON: /api/errors/c4acc88702c8e2f4. Report an issue: GitHub.