← 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
M data/reconciled-draft-ledger.jsonM scripts/send-reconciled.mjs
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 →