[object Object]

← back to Sample Followup Sweep

sample-followup: strip CR/whitespace from FileMaker vid — it was silently dropping chases (TK-11255)

e343b5f7af18ff8cf72ff06bc0cc740763b4cbb3 · 2026-09-12 07:41:39 -0700 · Steve Abrams

Measured live against FileMaker, not hypothesised: of 129 overdue sample records
in the current 10-60 day window, 11 across 7 vendor codes resolve to NO contact
and are skipped with no error and no log line. One of those is a plain key bug.

A Kravet record's vid is literally "kra\r". scheduled-run.mjs keyed the contact
map with String(vid).toUpperCase() and no trim, so "KRA\r" never matched "KRA"
and that vendor's overdue sample was never chased. Same untrimmed pattern in
resolve-original-dates.mjs. build-fleet.js already strips \r from Mfr Pattern and
client name — vid was simply missed.

This is the silent-skip class: nothing errors, nothing logs, the sample just
never gets chased and a client waits.

Both sites now strip CR/LF and trim before upper-casing.

The other 6 skipped vids are NOT this bug and are deliberately not touched here:
  1838, FUT, VAH, BRU  -- vid absent from data/fleet.json, which is 29 days stale
                          and is regenerated by nobody (no launchd job runs
                          build-fleet.js; scheduled-run only READS the file).
                          These are vendors whose samples went overdue after the
                          last build. Fixed by regenerating, now that d8486af
                          makes regeneration safe for the alias stubs.
  POI                  -- has an email as of today but no account_number, and
                          vidContactMap requires BOTH.
  1838 WALLCOVERINGS   -- no email, no account, and no canonical FileMaker row.

Note the item list itself is NOT stale — scheduled-run pulls it live from
FileMaker each run. Only the vid->contact bridge is stale, so the failure mode
is silently skipping a vendor, never chasing a dead lead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Files touched

Diff

commit e343b5f7af18ff8cf72ff06bc0cc740763b4cbb3
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sat Sep 12 07:41:39 2026 -0700

    sample-followup: strip CR/whitespace from FileMaker vid — it was silently dropping chases (TK-11255)
    
    Measured live against FileMaker, not hypothesised: of 129 overdue sample records
    in the current 10-60 day window, 11 across 7 vendor codes resolve to NO contact
    and are skipped with no error and no log line. One of those is a plain key bug.
    
    A Kravet record's vid is literally "kra\r". scheduled-run.mjs keyed the contact
    map with String(vid).toUpperCase() and no trim, so "KRA\r" never matched "KRA"
    and that vendor's overdue sample was never chased. Same untrimmed pattern in
    resolve-original-dates.mjs. build-fleet.js already strips \r from Mfr Pattern and
    client name — vid was simply missed.
    
    This is the silent-skip class: nothing errors, nothing logs, the sample just
    never gets chased and a client waits.
    
    Both sites now strip CR/LF and trim before upper-casing.
    
    The other 6 skipped vids are NOT this bug and are deliberately not touched here:
      1838, FUT, VAH, BRU  -- vid absent from data/fleet.json, which is 29 days stale
                              and is regenerated by nobody (no launchd job runs
                              build-fleet.js; scheduled-run only READS the file).
                              These are vendors whose samples went overdue after the
                              last build. Fixed by regenerating, now that d8486af
                              makes regeneration safe for the alias stubs.
      POI                  -- has an email as of today but no account_number, and
                              vidContactMap requires BOTH.
      1838 WALLCOVERINGS   -- no email, no account, and no canonical FileMaker row.
    
    Note the item list itself is NOT stale — scheduled-run pulls it live from
    FileMaker each run. Only the vid->contact bridge is stale, so the failure mode
    is silently skipping a vendor, never chasing a dead lead.
    
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---
 scripts/resolve-original-dates.mjs | 2 +-
 scripts/scheduled-run.mjs          | 7 ++++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/scripts/resolve-original-dates.mjs b/scripts/resolve-original-dates.mjs
index 0c7c716..8cc9c7a 100644
--- a/scripts/resolve-original-dates.mjs
+++ b/scripts/resolve-original-dates.mjs
@@ -56,7 +56,7 @@ const contacts = JSON.parse(readFileSync(new URL('../data/contacts.json', import
 const vidRecip = {}; for (const v of fleet) { const c = contacts[v.slug] || {}; const e = c.sample_email || c.main_email; if (e && !vidRecip[String(v.vid || '').toUpperCase()]) vidRecip[String(v.vid || '').toUpperCase()] = e; }
 
 const byVid = {};
-for (const r of A2) { const vid = String(r.fieldData.vid || '').toUpperCase(); if (!vid) continue; (byVid[vid] = byVid[vid] || []).push({ mfr: (r.fieldData['Mfr Pattern'] || '').trim(), fmDate: r.fieldData['today for client'] || '' }); }
+for (const r of A2) { const vid = String(r.fieldData.vid || '').replace(/[\r\n]/g, '').trim().toUpperCase(); if (!vid) continue; (byVid[vid] = byVid[vid] || []).push({ mfr: (r.fieldData['Mfr Pattern'] || '').trim(), fmDate: r.fieldData['today for client'] || '' }); }
 
 let hit = 0, miss = 0;
 for (const [vid, rows] of Object.entries(byVid)) {
diff --git a/scripts/scheduled-run.mjs b/scripts/scheduled-run.mjs
index 93ecf70..75dc0e8 100644
--- a/scripts/scheduled-run.mjs
+++ b/scripts/scheduled-run.mjs
@@ -287,7 +287,12 @@ const run = async () => {
   const byVid = {};
   for (const r of A) {
     if (chasedIds.has(String(r.recordId))) continue;   // already requested → do not duplicate
-    const vid = String(r.fieldData.vid || '').toUpperCase(); if (!vid) continue;
+    // TK-11255: FileMaker vid values carry stray CR/whitespace (measured live: a
+    // Kravet record's vid is literally "kra\r"). Without stripping it the key never
+    // matches cmap and that vendor's overdue sample is SILENTLY skipped -- no error,
+    // no log, it just never gets chased. build-fleet.js already strips \r from other
+    // FileMaker fields; vid was the one that was missed.
+    const vid = String(r.fieldData.vid || '').replace(/[\r\n]/g, '').trim().toUpperCase(); if (!vid) continue;
     (byVid[vid] = byVid[vid] || []).push({
       recordId: r.recordId, mfr: (r.fieldData['Mfr Pattern'] || '').trim(),
       sku: r.fieldData['combo sku'] || '', requested: r.fieldData['today for client'] || '',

← eafdc77 chore: v1.1.0 -> v1.1.1 (TK-11255 vendor-desk routing fix, s  ·  back to Sample Followup Sweep  ·  contacts.json: unblock POI + 1838, both silently skipped by a1c761a →