[object Object]

← back to Gmc Titlefix

TK-11448: archive 33 vendor-discontinued products (Shopify + FileMaker), verified

e42e577d2e54388be8196e3fe969292bbe47e043 · 2026-09-11 12:17:38 -0700 · Steve

Steve approved in-session: 'if not on mfr website. archive it', scope
Shopify + FileMaker discontinued.

Executed, canary-first, with independent verification at every step:
 - Shopify: 33 ACTIVE -> ARCHIVED. Canary 3 verified by re-read before the
   remaining 30. Exhaustive re-read: 33/33 ARCHIVED. 33 undo rows ledgered.
 - FileMaker: 105 WALLPAPER rows stamped Date Discontinued=09/11/2026 on rows
   where it was blank; rows already dated are skipped, never overwritten.
   Live canary verified against an UNWRITTEN control that stayed blank, proving
   the write was targeted. Exhaustive re-read: 105/105 dated, 0 blank,
   0 unreadable. 105 undo rows ledgered.
 - WRITE-2 (close open sample order) was a measured no-op: 0 open orders.

Caught in my own code first: the FM survey defaulted an unreadable client
response to [] and reported 0 rows for all 33 — a false zero indistinguishable
from 'nothing to do'. Replaced with a hard shape assertion that throws.
The client returns {records,dataInfo}, not {response:{data}}.

Fix plan reduced 19 -> 17: Sandberg Oscar grey and Kimono green are gone from
the vendor too and were archived instead of repaired.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JwXCqw4PdXfTY729wX8BFw

Files touched

Diff

commit e42e577d2e54388be8196e3fe969292bbe47e043
Author: Steve <steve@designerwallcoverings.com>
Date:   Fri Sep 11 12:17:38 2026 -0700

    TK-11448: archive 33 vendor-discontinued products (Shopify + FileMaker), verified
    
    Steve approved in-session: 'if not on mfr website. archive it', scope
    Shopify + FileMaker discontinued.
    
    Executed, canary-first, with independent verification at every step:
     - Shopify: 33 ACTIVE -> ARCHIVED. Canary 3 verified by re-read before the
       remaining 30. Exhaustive re-read: 33/33 ARCHIVED. 33 undo rows ledgered.
     - FileMaker: 105 WALLPAPER rows stamped Date Discontinued=09/11/2026 on rows
       where it was blank; rows already dated are skipped, never overwritten.
       Live canary verified against an UNWRITTEN control that stayed blank, proving
       the write was targeted. Exhaustive re-read: 105/105 dated, 0 blank,
       0 unreadable. 105 undo rows ledgered.
     - WRITE-2 (close open sample order) was a measured no-op: 0 open orders.
    
    Caught in my own code first: the FM survey defaulted an unreadable client
    response to [] and reported 0 rows for all 33 — a false zero indistinguishable
    from 'nothing to do'. Replaced with a hard shape assertion that throws.
    The client returns {records,dataInfo}, not {response:{data}}.
    
    Fix plan reduced 19 -> 17: Sandberg Oscar grey and Kimono green are gone from
    the vendor too and were archived instead of repaired.
    
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01JwXCqw4PdXfTY729wX8BFw
---
 data/tk11448-remediation-plan.json | 31 ++++---------------------
 tk11448-apply-fm-disco.mjs         | 47 ++++++++++++++++++++++++++++++++++++++
 tk11448-fm-survey.mjs              | 46 +++++++++++++++++++++++++++++++++++++
 3 files changed, 97 insertions(+), 27 deletions(-)

diff --git a/data/tk11448-remediation-plan.json b/data/tk11448-remediation-plan.json
index c5833e9..9f9f3b8 100644
--- a/data/tk11448-remediation-plan.json
+++ b/data/tk11448-remediation-plan.json
@@ -1,10 +1,10 @@
 {
   "ticket": "TK-11448",
   "built_at": "2026-09-11T18:29:12.922Z",
-  "blast_radius": 19,
+  "blast_radius": 17,
   "tally": {
     "ADD_REAL_IMAGE_AND_FEATURE": 11,
-    "REORDER_FEATURED": 8
+    "REORDER_FEATURED": 6
   },
   "gated": true,
   "fired": false,
@@ -174,30 +174,6 @@
       "undo": "delete the created media id (recorded per row) — restores the prior featured image",
       "spend": "$0 — Shopify-hosted upload from an existing vendor CDN URL"
     },
-    {
-      "handle": "dwss-71022",
-      "vendor": "Sandberg",
-      "title": "Oscar grey Wallcovering | Sandberg",
-      "action": "REORDER_FEATURED",
-      "before_featured": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/221-21_image2.png?v=1646099675",
-      "after_featured": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/221-21_image1.jpg?v=1646099675",
-      "after_px": "800x800",
-      "shopify_op": "productReorderMedia (promote existing media to position 1)",
-      "undo": "productReorderMedia back to the recorded prior order",
-      "spend": "$0 — no upload, image already on the product"
-    },
-    {
-      "handle": "dwss-71076",
-      "vendor": "Sandberg",
-      "title": "Kimono green Wallcovering | Sandberg",
-      "action": "REORDER_FEATURED",
-      "before_featured": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/238-38_image2.png?v=1646100218",
-      "after_featured": "https://cdn.shopify.com/s/files/1/0015/4117/7456/products/238-38_image1.jpg?v=1646100218",
-      "after_px": "800x800",
-      "shopify_op": "productReorderMedia (promote existing media to position 1)",
-      "undo": "productReorderMedia back to the recorded prior order",
-      "spend": "$0 — no upload, image already on the product"
-    },
     {
       "handle": "dwss-71269",
       "vendor": "Sandberg",
@@ -270,5 +246,6 @@
       "undo": "productReorderMedia back to the recorded prior order",
       "spend": "$0 — no upload, image already on the product"
     }
-  ]
+  ],
+  "note": "2026-09-11: dwss-71022 (Oscar grey) and dwss-71076 (Kimono green) REMOVED from the fix set — both confirmed absent from sandbergwallpaper.com and archived instead under TK-11448 archive plan."
 }
\ No newline at end of file
diff --git a/tk11448-apply-fm-disco.mjs b/tk11448-apply-fm-disco.mjs
new file mode 100644
index 0000000..63ffcac
--- /dev/null
+++ b/tk11448-apply-fm-disco.mjs
@@ -0,0 +1,47 @@
+#!/usr/bin/env node
+/** TK-11448 — stamp `Date Discontinued` on the FileMaker WALLPAPER rows for the 33 archived
+ * products (Steve approved Shopify + FileMaker, 2026-09-11).
+ * Follows the discontinued-agent contract: WRITE-1 only (Date Discontinued = today MM/DD/YYYY)
+ * on rows where it is currently BLANK; rows already dated are skipped, never overwritten.
+ * WRITE-2 (close open sample order) is a no-op here — the survey measured 0 open orders.
+ * DRY-RUN BY DEFAULT (the fm client itself defaults dryRun:true). --apply commits.
+ * Every row's prior value is ledgered BEFORE the write; undo = set the field back to ''. */
+import {findRecords,updateRecord} from '/Users/macstudio3/Projects/filemaker-mcp/src/fm-client.js';
+import fs from 'fs';
+const DB='WALLPAPER', LAY='REPORT ON SAMPLES ORDERED';
+const APPLY=process.argv.includes('--apply');
+const CAN=(()=>{const i=process.argv.indexOf('--canary');return i>0?+process.argv[i+1]:0;})();
+const d=new Date(); const TODAY=`${String(d.getMonth()+1).padStart(2,'0')}/${String(d.getDate()).padStart(2,'0')}/${d.getFullYear()}`;
+const survey=JSON.parse(fs.readFileSync('data/tk11448-fm-survey.json','utf8'));
+let subjects=survey.rows.filter(r=>r.blank_disco>0);
+if(CAN) subjects=subjects.slice(0,CAN);
+console.log(`${APPLY?'APPLY':'DRY-RUN'} | Date Discontinued = ${TODAY} | products ${subjects.length}`);
+const led=APPLY?fs.createWriteStream('data/tk11448-fm-ledger.jsonl',{flags:'a'}):null;
+let wrote=0,skipped=0,failed=0,notMeasured=0;
+for(const s of subjects){
+  let recs;
+  try{
+    const r=await findRecords(DB,LAY,[{'combo sku':`==${s.combo}`}],{limit:200});
+    if(!r||!Array.isArray(r.records)) throw new Error('UNEXPECTED_SHAPE');
+    recs=r.records;
+  }catch(e){ console.log('  NOT_MEASURED',s.handle,String(e).slice(0,80)); notMeasured++; continue; }
+  for(const rec of recs){
+    const prior=String(rec.fieldData['Date Discontinued']||'').trim();
+    if(prior){ skipped++; continue; }               // never overwrite an existing date
+    try{
+      const res=await updateRecord(DB,LAY,rec.recordId,{'Date Discontinued':TODAY},{dryRun:!APPLY});
+      if(APPLY){
+        led.write(JSON.stringify({ts:new Date().toISOString(),handle:s.handle,combo:s.combo,
+          recordId:rec.recordId,field:'Date Discontinued',prior_value:'',new_value:TODAY,
+          undo:`updateRecord(WALLPAPER,'${LAY}',${rec.recordId},{'Date Discontinued':''})`})+'\n');
+      }
+      wrote++;
+    }catch(e){ console.log('  ERR',s.handle,rec.recordId,String(e).slice(0,90)); failed++; }
+    await new Promise(z=>setTimeout(z,200));
+  }
+  console.log(`  ${APPLY?'stamped':'would stamp'} ${s.handle} (${s.combo}) rows=${recs.length}`);
+}
+if(led) led.end();
+console.log(`\n${APPLY?'WROTE':'WOULD WRITE'} ${wrote} | skipped(already dated) ${skipped} | failed ${failed} | NOT_MEASURED ${notMeasured}`);
+if(!APPLY) console.log('DRY-RUN ONLY — nothing committed. Re-run with --apply.');
+else console.log('ledger -> data/tk11448-fm-ledger.jsonl');
diff --git a/tk11448-fm-survey.mjs b/tk11448-fm-survey.mjs
new file mode 100644
index 0000000..6d04a61
--- /dev/null
+++ b/tk11448-fm-survey.mjs
@@ -0,0 +1,46 @@
+#!/usr/bin/env node
+/** TK-11448 READ-ONLY FileMaker survey for the 33 archive products.
+ * Joins on `combo sku` (exact: handle dwrw-75513 -> DWRW75513), NOT the `Mfr Pattern` word-match,
+ * which can over-match a neighbouring SKU. Reports per product: rows found, how many already have
+ * Date Discontinued, how many are blank (the WRITE-1 set), and how many are OPEN sample orders
+ * (the WRITE-2 set per the discontinued-agent contract). Writes nothing. */
+import {findRecords} from '/Users/macstudio3/Projects/filemaker-mcp/src/fm-client.js';
+import fs from 'fs';
+const DB='WALLPAPER', LAY='REPORT ON SAMPLES ORDERED';
+const plan=JSON.parse(fs.readFileSync('data/tk11448-archive-plan.json','utf8')).rows.filter(r=>r.verdict==='ARCHIVE');
+const out=[]; let totRows=0,totBlank=0,totDated=0,totOpen=0,notMeasured=0;
+for(const p of plan){
+  const combo=p.handle.replace(/-/g,'').toUpperCase();
+  const rec={handle:p.handle,combo,mfr_sku:p.mfr_sku,title:p.title};
+  try{
+    const r=await findRecords(DB,LAY,[{'combo sku':`==${combo}`}],{limit:200});
+    // HARD SHAPE ASSERTION — never default an unreadable response to []. A silent [] is
+    // indistinguishable from "no rows" and is exactly how a false zero gets reported as done.
+    if(!r || !Array.isArray(r.records)) throw new Error('UNEXPECTED_SHAPE keys='+Object.keys(r||{}).join(','));
+    const rows=r.records;
+    rec.rows=rows.length;
+    rec.blank_disco=rows.filter(x=>!String(x.fieldData['Date Discontinued']||'').trim()).length;
+    rec.already_disco=rows.length-rec.blank_disco;
+    rec.open_orders=rows.filter(x=>{const f=x.fieldData;
+      return (String(f['account']||'').trim()||String(f['Clients::Company']||'').trim())
+        && String(f['Date Sample Request printed for vendor']||'').trim()
+        && !String(f['Date WP Sample Sent']||'').trim();}).length;
+    rec.recordIds=rows.map(x=>x.recordId);
+    rec.vid=[...new Set(rows.map(x=>x.fieldData['vid']))].join(',');
+    totRows+=rec.rows; totBlank+=rec.blank_disco; totDated+=rec.already_disco; totOpen+=rec.open_orders;
+  }catch(e){
+    const msg=String(e).slice(0,90);
+    if(/401|no records|not found|404/i.test(msg)){ rec.rows=0; rec.blank_disco=0; rec.already_disco=0; rec.open_orders=0; rec.note='no FM rows'; }
+    else { rec.status='NOT_MEASURED'; rec.err=msg; notMeasured++; }
+  }
+  out.push(rec);
+  console.log(' ',(rec.status||'ok').padEnd(13),p.handle,combo.padEnd(11),'rows='+String(rec.rows??'?').padStart(3),
+    'blank='+String(rec.blank_disco??'?').padStart(3),'dated='+String(rec.already_disco??'?').padStart(3),
+    'open='+String(rec.open_orders??'?').padStart(2),'|',p.title.slice(0,28));
+  await new Promise(z=>setTimeout(z,250));
+}
+console.log(`\n=== population ${plan.length} | NOT_MEASURED ${notMeasured} ===`);
+console.log(`FM rows total ${totRows} | WRITE-1 set (blank Date Discontinued) ${totBlank} | already dated ${totDated} | WRITE-2 open sample orders ${totOpen}`);
+fs.writeFileSync('data/tk11448-fm-survey.json',JSON.stringify({ticket:'TK-11448',checked_at:new Date().toISOString(),
+ population:plan.length,not_measured:notMeasured,total_rows:totRows,write1_blank:totBlank,already_dated:totDated,write2_open:totOpen,rows:out},null,2));
+console.log('-> data/tk11448-fm-survey.json');

← 3e98b29 auto-data-snapshot: 2026-09-11T12:03:30 (3 data files) — dat  ·  back to Gmc Titlefix  ·  5x sweep 1: fix the storefront probe — redirect:follow measu c0bbc10 →