← back to Sample Followup Sweep
sample-followup: record 3 manually-sent 10-day letters + gated FM-stamp script (TK-12109)
05177f265f922b1a8a095cbffe45346d7d967cda · 2026-09-23 15:47:37 -0700 · Steve Abrams
Steve sent FABR/WAT/GRD 10-day letters manually from info@ (verified in Sent).
recently-contacted.json += the 3 recipients (14-day anti-dup now reflects it).
Added scripts/tk12109-stamp-letter-sent.mjs (+ --rollback) to stamp FM
Date Sample Request Letter Sent=09/23/2026 on the 3 outstanding records
(541857/541215/541860) with a restore-map — gated to Steve (classifier blocks
the FM write). BAR held (not sent), REID arrived, MDCKEN no-chase — not stamped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
M data/recently-contacted.jsonA scripts/tk12109-stamp-letter-sent.mjs
Diff
commit 05177f265f922b1a8a095cbffe45346d7d967cda
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Sep 23 15:47:37 2026 -0700
sample-followup: record 3 manually-sent 10-day letters + gated FM-stamp script (TK-12109)
Steve sent FABR/WAT/GRD 10-day letters manually from info@ (verified in Sent).
recently-contacted.json += the 3 recipients (14-day anti-dup now reflects it).
Added scripts/tk12109-stamp-letter-sent.mjs (+ --rollback) to stamp FM
Date Sample Request Letter Sent=09/23/2026 on the 3 outstanding records
(541857/541215/541860) with a restore-map — gated to Steve (classifier blocks
the FM write). BAR held (not sent), REID arrived, MDCKEN no-chase — not stamped.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
data/recently-contacted.json | 5 +++-
scripts/tk12109-stamp-letter-sent.mjs | 52 +++++++++++++++++++++++++++++++++++
2 files changed, 56 insertions(+), 1 deletion(-)
diff --git a/data/recently-contacted.json b/data/recently-contacted.json
index a2bf542..d8e070a 100644
--- a/data/recently-contacted.json
+++ b/data/recently-contacted.json
@@ -24,5 +24,8 @@
"sample@mdcwall.com": "2026-08-20",
"samples@koroseal.com": "2026-08-20",
"sshortino@koroseal.com": "2026-08-20",
- "therese@egg-and-dart.com": "2026-08-20"
+ "therese@egg-and-dart.com": "2026-08-20",
+ "customers@fabricut.com": "2026-09-23",
+ "sophie@watts1874.co.uk": "2026-09-23",
+ "orders@graduatecollection.co.uk": "2026-09-23"
}
\ No newline at end of file
diff --git a/scripts/tk12109-stamp-letter-sent.mjs b/scripts/tk12109-stamp-letter-sent.mjs
new file mode 100644
index 0000000..2a50b83
--- /dev/null
+++ b/scripts/tk12109-stamp-letter-sent.mjs
@@ -0,0 +1,52 @@
+#!/usr/bin/env node
+// TK-12109 — stamp FileMaker `Date Sample Request Letter Sent` = 09/23/2026 on the 3 outstanding
+// records whose 10-day follow-up letters Steve SENT MANUALLY from info@ on 2026-09-23 (verified in
+// the Sent folder: FABR customers@fabricut.com, WAT sophie@watts1874.co.uk, GRD orders@graduatecollection.co.uk).
+// BAR was NOT sent (held), REID is arrived, MDCKEN is no-chase — none of those are stamped.
+//
+// This is a canonical FileMaker WRITE (the sweep's own FIELD_2ND_DATE stamp) and is blocked by the
+// Claude auto-mode classifier, so it is handed to Steve to run:
+// node ~/Projects/sample-followup-sweep/scripts/tk12109-stamp-letter-sent.mjs # stamp + write restore-map
+// node ~/Projects/sample-followup-sweep/scripts/tk12109-stamp-letter-sent.mjs --rollback # undo (set fields back to '')
+// Blast radius = 3 rows. Reversible via the restore-map (data/tk12109-stamp-restore-map.json).
+import { readFileSync, writeFileSync } from 'node:fs'; import { homedir } from 'node:os'; import { join } from 'node:path';
+const cfg = JSON.parse(readFileSync(join(homedir(), '.claude.json'), 'utf8'));
+const fenv = cfg?.mcpServers?.filemaker?.env || {};
+for (const k of ['FM_CLOUD_HOST', 'FM_CLARIS_EMAIL', 'FM_CLARIS_PASSWORD']) process.env[k] = fenv[k];
+process.env.FM_READONLY = '0';
+const fm = await import('/Users/macstudio3/Projects/filemaker-mcp/src/fm-client.js');
+const DB = 'WALLPAPER', LAYOUT = 'Report for old memo samples', FIELD = 'Date Sample Request Letter Sent', TODAY = '09/23/2026';
+const MAP = join(homedir(), 'Projects/sample-followup-sweep/data/tk12109-stamp-restore-map.json');
+const targets = [
+ { sku: 'DWFC230158', vendor: 'FABR/Fabricut', recordId: '541857' },
+ { sku: 'DWC324296', vendor: 'WAT/Watts 1874', recordId: '541215' },
+ { sku: 'GRD8806', vendor: 'GRD/Graduate Collection', recordId: '541860' },
+];
+const ROLLBACK = process.argv.includes('--rollback');
+
+async function readField(sku, recordId) {
+ const r = await fm.findRecords(DB, LAYOUT, { 'combo sku': sku }, { limit: 20 }).catch(() => ({ records: [] }));
+ const rec = (r.records || []).find((x) => String(x.recordId) === recordId);
+ return rec ? (rec.fieldData[FIELD] || '') : '(record not found)';
+}
+
+if (ROLLBACK) {
+ const map = JSON.parse(readFileSync(MAP, 'utf8'));
+ for (const rec of map.records) {
+ await fm.updateRecord(DB, LAYOUT, rec.recordId, { [FIELD]: rec.oldValue }, { dryRun: false });
+ const back = await readField(rec.sku, rec.recordId);
+ console.log(` ROLLBACK ${rec.vendor} ${rec.sku} rec ${rec.recordId}: -> ${JSON.stringify(back)} ${back === rec.oldValue ? '✓' : '✗'}`);
+ }
+ console.log('rollback complete.');
+} else {
+ const restore = [];
+ for (const t of targets) {
+ const oldVal = await readField(t.sku, t.recordId);
+ restore.push({ sku: t.sku, vendor: t.vendor, recordId: t.recordId, field: FIELD, oldValue: oldVal });
+ await fm.updateRecord(DB, LAYOUT, t.recordId, { [FIELD]: TODAY }, { dryRun: false });
+ const newVal = await readField(t.sku, t.recordId);
+ console.log(` ${t.vendor} ${t.sku} rec ${t.recordId}: old=${JSON.stringify(oldVal)} -> new=${JSON.stringify(newVal)} ${newVal === TODAY ? '✓ VERIFIED' : '✗ MISMATCH'}`);
+ }
+ writeFileSync(MAP, JSON.stringify({ ts: new Date().toISOString(), ticket: 'TK-12109', db: DB, layout: LAYOUT, field: FIELD, stampedTo: TODAY, records: restore }, null, 2));
+ console.log('\nrestore-map:', MAP, '\nrollback: node scripts/tk12109-stamp-letter-sent.mjs --rollback');
+}
← 6c9b709 sample-followup: draft the 5 verified-owed 10-day SKUs + CON
·
back to Sample Followup Sweep
·
auto-data-snapshot: 2026-09-23T15:52:37 (3 data files) — dat ab598e5 →