[object Object]

← back to Sample Followup Sweep

sample-followup: --include-suppressed drafts the anti-dup-held vendors for review

db9ca32806de1161ba24cc50f3158d5ca2241695 · 2026-09-01 11:19:46 -0700 · Steve

Steve 9/01: when Drafts came up empty, the cause was the anti-duplicate guard
suppressing ~10 vendors the team already emailed a New Sample Request (last 14d).
--include-suppressed (DRAFT mode only) drafts them ANYWAY, flagging each with a
'[REVIEW — team emailed recently]' subject prefix so they're identifiable in the
Drafts list. Nothing sends — Steve's review stays the dedup. Ran once over the
10-60d backlog: 12 drafts created (11 flagged + Wolf Gordon).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit db9ca32806de1161ba24cc50f3158d5ca2241695
Author: Steve <steve@designerwallcoverings.com>
Date:   Tue Sep 1 11:19:46 2026 -0700

    sample-followup: --include-suppressed drafts the anti-dup-held vendors for review
    
    Steve 9/01: when Drafts came up empty, the cause was the anti-duplicate guard
    suppressing ~10 vendors the team already emailed a New Sample Request (last 14d).
    --include-suppressed (DRAFT mode only) drafts them ANYWAY, flagging each with a
    '[REVIEW — team emailed recently]' subject prefix so they're identifiable in the
    Drafts list. Nothing sends — Steve's review stays the dedup. Ran once over the
    10-60d backlog: 12 drafts created (11 flagged + Wolf Gordon).
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 scripts/scheduled-run.mjs | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/scripts/scheduled-run.mjs b/scripts/scheduled-run.mjs
index 912587f..59297b8 100644
--- a/scripts/scheduled-run.mjs
+++ b/scripts/scheduled-run.mjs
@@ -33,6 +33,10 @@ const SEND = process.argv.includes('--send');
 // Steve 8/20: DRAFT mode — create a Gmail draft per vendor in info@ Drafts for human review,
 // instead of sending directly. The draft IS the human gate; Steve sends from Drafts.
 const DRAFT = process.argv.includes('--draft');
+// Steve 9/01: draft the anti-dup-SUPPRESSED vendors ANYWAY (for review) instead of skipping them.
+// Each such draft's subject is flagged so Steve can see the team already emailed that vendor recently.
+// Nothing sends — the draft is still the human gate, Steve's review is the real dedup. DRAFT-mode only.
+const INCLUDE_SUPPRESSED = process.argv.includes('--include-suppressed') || process.env.INCLUDE_SUPPRESSED === '1';
 const DB = 'WALLPAPER';
 const LAYOUT = 'Report for old memo samples';
 const FIELD_SENT = 'Date Email Sent to Vendor after 10 Days';
@@ -232,7 +236,10 @@ const run = async () => {
     const c = cmap[vid];
     if (!c || c.noChase) { skipped.push({ vid, n: rows.length, reason: c?.noChase ? 'no-chase vendor' : 'no sample email/account on file' }); continue; }
     const recips = String((c.sample_email || c.main_email) || '').toLowerCase().split(/[,;]\s*/).map((s) => s.trim()).filter(Boolean);
-    if (recips.length && recips.some((e) => RECENT.has(e))) { suppressed.push({ vid, name: c.name, to: (c.sample_email || c.main_email), n: rows.length, reason: 'already emailed since 8/15 (manual team send)' }); continue; }
+    const recentlyEmailed = recips.length > 0 && recips.some((e) => RECENT.has(e));
+    // Default: skip a recently-emailed vendor (anti-dup). With --include-suppressed we DRAFT it anyway,
+    // flagged, so Steve can review + decide per-vendor (nothing sends).
+    if (recentlyEmailed && !(INCLUDE_SUPPRESSED && DRAFT)) { suppressed.push({ vid, name: c.name, to: (c.sample_email || c.main_email), n: rows.length, reason: 'already emailed since 8/15 (manual team send)' }); continue; }
     // In SEND mode, an unconfirmed (resolved/fallback) recipient is HELD — never fires. In DRAFT
     // mode the draft itself IS the review, so everything is drafted for Steve to check + send.
     if (c.needs_confirm && !DRAFT) { needsConfirm.push({ vid, name: c.name, to: (c.sample_email || c.main_email), n: rows.length, skus: rows.map((r) => r.sku), reason: 'main-email fallback — CONFIRM person vs recent emails before send' }); continue; }
@@ -240,10 +247,13 @@ const run = async () => {
       const fresh = rows.filter((r) => !draftLedger[r.recordId]);   // only newly-outstanding SKUs
       if (!fresh.length) continue;                                   // already drafted — no dup
       const draft = compose({ name: c.name, account_number: c.account_number, sample_email: c.sample_email, main_email: c.main_email, ship_to: SHIP_TO }, fresh.map((r) => ({ mfr: r.mfr, sku: r.sku, requested: r.requested })));
-      const res = await georgeDraft({ account: 'info', to: draft.to, subject: draft.subject, body: draft.html });
+      // Flag (subject-only, visible in the Drafts list) when the team already emailed this vendor. Strip
+      // the tag before sending — it's a review marker, not part of the vendor-facing letter.
+      const flagPrefix = recentlyEmailed ? '[REVIEW — team emailed recently] ' : '';
+      const res = await georgeDraft({ account: 'info', to: draft.to, subject: flagPrefix + draft.subject, body: draft.html });
       if (res.ok) {
         for (const r of fresh) draftLedger[r.recordId] = today;      // dedup marker (NOT a FileMaker stamp)
-        drafted.push({ vid, name: c.name, to: draft.to, n: fresh.length, draftId: res.id, confirm: !!c.needs_confirm });
+        drafted.push({ vid, name: c.name, to: draft.to, n: fresh.length, draftId: res.id, confirm: !!c.needs_confirm, flagged: recentlyEmailed });
       } else { skipped.push({ vid, n: fresh.length, reason: 'George draft failed: ' + res.detail }); }
       continue;
     }
@@ -269,7 +279,7 @@ const run = async () => {
   console.log(`Scheduled follow-up — ${mode} · window ${win} (>=${MIN_AGE_DAYS}d, ${bandDesc})\n`);
   if (DRAFT) {
     console.log(`Created ${drafted.length} draft(s) in info@ Drafts for review:`);
-    drafted.forEach((s) => console.log(`  ✎ ${s.name.padEnd(30)} [${s.vid}] → ${s.to}  (${s.n} SKU${s.n > 1 ? 's' : ''})${s.confirm ? '  [CONFIRM recipient]' : ''}`));
+    drafted.forEach((s) => console.log(`  ✎ ${s.name.padEnd(30)} [${s.vid}] → ${s.to}  (${s.n} SKU${s.n > 1 ? 's' : ''})${s.confirm ? '  [CONFIRM recipient]' : ''}${s.flagged ? '  [⚠ team emailed recently — REVIEW]' : ''}`));
   } else {
     console.log(`Would ${SEND ? 'HAVE SENT' : 'send'} to ${sent.length} vendor(s):`);
     sent.forEach((s) => console.log(`  ${SEND ? '✓' : '·'} ${s.name.padEnd(30)} [${s.vid}] → ${s.to}  (${s.n} SKU${s.n > 1 ? 's' : ''})`));

← 3d869fe auto-data-snapshot: 2026-09-01T10:56:56 (1 data files) — dat  ·  back to Sample Followup Sweep  ·  auto-data-snapshot: 2026-09-01T11:38:20 (3 data files) — dat 4dfe1c2 →