From 85c88f9eed6b212afd6e9739c783c7d141ed7836 Mon Sep 17 00:00:00 2001 From: Claw Date: Fri, 6 Mar 2026 11:25:19 +0000 Subject: [PATCH] fix: make filter idempotent - skip already-scored jobs on collect, exclude by filter_score on submit --- job_filter.mjs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/job_filter.mjs b/job_filter.mjs index 8c4c101..8a9d6fa 100644 --- a/job_filter.mjs +++ b/job_filter.mjs @@ -119,6 +119,9 @@ async function collect(state, settings) { const r = resultMap[job.id]; if (!r) continue; + // Skip jobs already scored (idempotent — safe to re-run collect) + if (job.filter_score != null) continue; + if (r.error || r.score === null) { errors++; job.filter_score = null; @@ -180,8 +183,8 @@ async function collect(state, settings) { async function submit(settings, searchConfig, candidateProfile) { const apiKey = process.env.ANTHROPIC_API_KEY; - // Get all new jobs that haven't been scored and aren't already in a pending batch - const jobs = getJobsByStatus('new').filter(j => j.filter_score == null && !j.filter_batch_id); + // Get all new jobs that haven't been scored yet (no score AND not already in a pending batch) + const jobs = getJobsByStatus('new').filter(j => j.filter_score == null && !j.filter_batch_id && !j.filter_submitted_at); if (jobs.length === 0) { console.log('✅ Nothing to filter — all new jobs already scored.'); @@ -217,7 +220,10 @@ async function submit(settings, searchConfig, candidateProfile) { const allJobs = loadQueue(); const filteredIds = new Set(filterable.map(j => j.id)); for (const job of allJobs) { - if (filteredIds.has(job.id)) job.filter_batch_id = batchId; + if (filteredIds.has(job.id)) { + job.filter_batch_id = batchId; + job.filter_submitted_at = submittedAt; + } } saveQueue(allJobs);