[object Object]

← back to Sample Followup Sweep

sample-followup: draft the 5 verified-owed 10-day SKUs + CONFIRM-RECIPIENT banner/ledger mark (TK-12107)

6c9b7096ebca6e8bd4253299156be987eb88881c · 2026-09-23 15:40:04 -0700 · Steve Abrams

send-reconciled.mjs draft() now returns the George draftId; needs_confirm vendors
get an INTERNAL 'CONFIRM RECIPIENT' body banner + a '⚠ CONFIRM RECIPIENT' ledger
mark so Steve fixes To: before send. Created 4 drafts (5 SKUs): FABR customers@
fabricut.com, WAT sophie@watts1874.co.uk [confirm], BAR studio@/alice@barnebygates.com
x2 [confirm], GRD orders@graduatecollection.co.uk [confirm]. REID guard-suppressed
(arrived), MDCKEN no-chase. Drafts only — nothing sent, no FM write.

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

Files touched

Diff

commit 6c9b7096ebca6e8bd4253299156be987eb88881c
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Sep 23 15:40:04 2026 -0700

    sample-followup: draft the 5 verified-owed 10-day SKUs + CONFIRM-RECIPIENT banner/ledger mark (TK-12107)
    
    send-reconciled.mjs draft() now returns the George draftId; needs_confirm vendors
    get an INTERNAL 'CONFIRM RECIPIENT' body banner + a '⚠ CONFIRM RECIPIENT' ledger
    mark so Steve fixes To: before send. Created 4 drafts (5 SKUs): FABR customers@
    fabricut.com, WAT sophie@watts1874.co.uk [confirm], BAR studio@/alice@barnebygates.com
    x2 [confirm], GRD orders@graduatecollection.co.uk [confirm]. REID guard-suppressed
    (arrived), MDCKEN no-chase. Drafts only — nothing sent, no FM write.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 data/reconciled-draft-ledger.json | 10 +++++-----
 scripts/send-reconciled.mjs       | 15 +++++++++++----
 2 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/data/reconciled-draft-ledger.json b/data/reconciled-draft-ledger.json
index 3eae304..c9a6bee 100644
--- a/data/reconciled-draft-ledger.json
+++ b/data/reconciled-draft-ledger.json
@@ -119,11 +119,11 @@
   "FTR:GLM9215": "09/23/2026",
   "FTR:GLM4113": "09/23/2026",
   "FTR:GLM4117": "09/23/2026",
-  "WAT:DWC324296": "09/23/2026",
-  "BAR:DWBW600341": "09/23/2026",
-  "BAR:DWBW600342": "09/23/2026",
   "REID:DWRW210156": "09/23/2026",
-  "FABR:DWFC230158": "09/23/2026",
   "SAND:DWXH255221": "09/23/2026",
-  "GRD:GRD8806": "09/23/2026"
+  "WAT:DWC324296": "⚠ CONFIRM RECIPIENT 09/23/2026",
+  "BAR:DWBW600341": "⚠ CONFIRM RECIPIENT 09/23/2026",
+  "BAR:DWBW600342": "⚠ CONFIRM RECIPIENT 09/23/2026",
+  "FABR:DWFC230158": "09/23/2026",
+  "GRD:GRD8806": "⚠ CONFIRM RECIPIENT 09/23/2026"
 }
\ No newline at end of file
diff --git a/scripts/send-reconciled.mjs b/scripts/send-reconciled.mjs
index 6fdc460..0062913 100644
--- a/scripts/send-reconciled.mjs
+++ b/scripts/send-reconciled.mjs
@@ -138,7 +138,8 @@ let auth = genv('GEORGE_BASIC_AUTH'); if (!auth.includes(':')) auth = 'admin:' +
 auth = 'Basic ' + Buffer.from(auth).toString('base64');
 async function draft(to, subject, body) {
   const result = await georgeRequest({ path: '/api/drafts', payload: { account: 'info', to, subject, body }, headers: { Authorization: auth } });
-  try { const parsed = JSON.parse(result.body); return parsed.success ? 'ok' : result.body.slice(0, 80); } catch { return result.body.slice(0, 80); }
+  try { const parsed = JSON.parse(result.body); return { ok: !!parsed.success, id: parsed.draftId || '', detail: parsed.success ? '' : result.body.slice(0, 80) }; }
+  catch { return { ok: false, id: '', detail: result.body.slice(0, 80) }; }
 }
 
 const DO = process.argv.includes('--draft');
@@ -157,9 +158,15 @@ for (const [key, rows] of Object.entries(items)) {
   const subj = `Sample Follow-Up — Outstanding Memos (Acct ${v.acct}) — Designer Wallcoverings`;
   const cflag = v.needsConfirm ? '  [CONFIRM recipient]' : '';
   if (!DO) { console.log(`  · ${v.name.padEnd(26)} → ${v.to.padEnd(40)} (${fresh.length})${cflag} refs: ${fresh.map(r => r.sku).join(', ')}`); continue; }
-  const r = await draft(v.to, subj, letter(v, fresh));
-  console.log(`  ${r === 'ok' ? '✎' : '✗'} ${v.name.padEnd(26)} → ${v.to.padEnd(40)} (${fresh.length})${cflag} ${r === 'ok' ? '' : r}`);
-  if (r === 'ok') for (const row of fresh) ledger[`${key}:${row.sku}`] = stamp;
+  // TK-12107: for a CONFIRM-RECIPIENT (needs_confirm) vendor, prepend an INTERNAL banner so Steve
+  // verifies/fixes the To: and DELETES the line before sending — never silently send to a maybe-wrong
+  // desk. The subject stays clean (vendor-facing); the banner is a loud in-draft note.
+  const banner = v.needsConfirm
+    ? `<div style="background:#fff3cd;border:1px solid #ffc107;padding:8px 12px;margin:0 0 14px;font-size:13px;color:#7a5b00"><strong>⚠ INTERNAL — CONFIRM RECIPIENT before sending.</strong> Verify the To: address (<strong>${esc(v.to)}</strong>) is the correct sample desk for this vendor, then DELETE this line. (Resolved from correspondence, not a confirmed sample desk.)</div>`
+    : '';
+  const res = await draft(v.to, subj, banner + letter(v, fresh));
+  console.log(`  ${res.ok ? '✎' : '✗'} ${v.name.padEnd(26)} → ${v.to.padEnd(40)} (${fresh.length})${cflag} ${res.ok ? 'draftId=' + res.id : res.detail}`);
+  if (res.ok) for (const row of fresh) ledger[`${key}:${row.sku}`] = v.needsConfirm ? `⚠ CONFIRM RECIPIENT ${stamp}` : stamp;
 }
 if (guardSuppressed.length) {
   console.log(`\n\u{1F6E1} Never-false-chase guard suppressed ${guardSuppressed.length} SKU(s) (already arrived / 10-day letter already sent):`);

← d04d106 sample-followup: two-part never-false-chase guard (arrival-d  ·  back to Sample Followup Sweep  ·  sample-followup: record 3 manually-sent 10-day letters + gat 05177f2 →