From af5df25fa1676ae5ddf9516f900ab29864870aee Mon Sep 17 00:00:00 2001 From: rafapolo Date: Sat, 5 Sep 2026 18:04:29 +0200 Subject: [PATCH] feat: show the German/French drop count in the digest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Jobs rejected for German/French content never reach jobs.csv, so daily.ts had no way to see they existed — the digest silently under-reported how much the run actually looked at. index.ts now counts them across both the LinkedIn and extra-source paths and writes results/.lang-dropped.json; daily.ts reads it back, keyed on the digest date, and appends a count-only category. Count-only because there is no Row to list — these were dropped before ever being parsed. --- daily.ts | 15 ++++++++++++++- index.ts | 9 +++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/daily.ts b/daily.ts index 545dc64..0f6b740 100644 --- a/daily.ts +++ b/daily.ts @@ -8,6 +8,7 @@ import { matchesProfile } from "./profile.ts"; const CSV = "./results/jobs.csv"; const SENT = "./results/sent.txt"; // links already pushed — never resend +const LANG_DROPPED = "./results/.lang-dropped.json"; // written by index.ts — jobs dropped for German/French content never reach the CSV const dry = process.argv.includes("--dry-run"); const resend = process.argv.includes("--resend"); @@ -47,10 +48,19 @@ const sent = new Set( : [] ); const dateArg = process.argv.find((a) => a.startsWith("--date="))?.slice(7); +const digestDate = dateArg ?? new Date().toISOString().slice(0, 10); const fresh = resend - ? all.filter((r) => r.fetched === (dateArg ?? new Date().toISOString().slice(0, 10))) + ? all.filter((r) => r.fetched === digestDate) : all.filter((r) => !before.has(r.link)); +// Jobs dropped for German/French content never make it into the CSV, so this +// is the only place their count survives — shown as a count-only category, +// never listed, since there's no Row to show for them. +const langDropped = await Bun.file(LANG_DROPPED) + .json() + .then((j) => (j.date === digestDate ? j.count : 0)) + .catch(() => 0); + // Only leads that actually match the CV (profile.ts) and haven't been sent before. const matched = fresh.filter((r) => !sent.has(r.link) && matchesProfile(r.title, r.company).ok); console.log(`${fresh.length} new · ${matched.length} match profile · ${fresh.length - matched.length} filtered or already sent`); @@ -95,6 +105,9 @@ for (const k of order) { lines.push(`• ${escapeHtml(r.title)} — ${escapeHtml(r.company)} ${label}`); } } +if (langDropped > 0) { + lines.push(`\n🔴 Ignored (German/French) (${langDropped})`); +} const msg = lines.join("\n"); if (dry) { diff --git a/index.ts b/index.ts index d6bf45f..2515545 100644 --- a/index.ts +++ b/index.ts @@ -54,6 +54,7 @@ try { const date = new Date().toISOString().slice(0, 10); const newRows: string[] = []; +let totalLangDropped = 0; // jobs dropped for German/French content — never reach the CSV, so daily.ts can't see them on its own function csvCell(val: string): string { return `"${val.replace(/"/g, '""')}"`; @@ -111,6 +112,7 @@ async function processLinkedInSearch(config: (typeof searches)[number]): Promise if (!viable.ok) { console.log(`dropped (${viable.reason})`); langDropped++; + totalLangDropped++; continue; } console.log("ok"); @@ -162,6 +164,7 @@ async function processExtraSource({ label, fetch: fetchFn }: (typeof extraSource if (!viable.ok) { console.log(`dropped (${viable.reason})`); langDropped++; + totalLangDropped++; continue; } console.log("ok"); @@ -184,6 +187,12 @@ await Promise.all([ runWithConcurrency(extraSources, EXTRA_SOURCE_CONCURRENCY, processExtraSource), ]); +// Jobs dropped for German/French content never reach the CSV, so this is the +// only record of them — daily.ts reads it back to show a count in the digest +// without listing rejects that were never even parsed into a Row. +const LANG_DROPPED = "./results/.lang-dropped.json"; +await Bun.write(LANG_DROPPED, JSON.stringify({ date, count: totalLangDropped })); + if (newRows.length === 0) { console.log("\nNo new jobs."); process.exit(0);