[object Object]

← back to Designerwallcoverings

Verify Sanderson gallery remediation for TK-11302

8dcc371561ca4f78506ca3e568b0e92d5b2c1717 · 2026-09-10 17:39:33 -0700 · Steve Abrams

Files touched

Diff

commit 8dcc371561ca4f78506ca3e568b0e92d5b2c1717
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Sep 10 17:39:33 2026 -0700

    Verify Sanderson gallery remediation for TK-11302
---
 verification/TK-11302/e2e-proof.json | 122 +++++++++++++++++++++++++++++++++++
 verification/TK-11302/verify.mjs     |  73 +++++++++++++++++++++
 2 files changed, 195 insertions(+)

diff --git a/verification/TK-11302/e2e-proof.json b/verification/TK-11302/e2e-proof.json
new file mode 100644
index 0000000..5b6be6d
--- /dev/null
+++ b/verification/TK-11302/e2e-proof.json
@@ -0,0 +1,122 @@
+{
+  "ticket": "TK-11302-dw-image-identity-canary-sanderson-galle",
+  "timestamp": "2026-09-11T00:38:01.270Z",
+  "intent": "Verify already-applied Sanderson gallery remediation and safe staged galleries without catalog writes",
+  "risk_tier": "Read-only external integration; R0 evidence artifact",
+  "environment": "Live Shopify Admin GETs; local dw_unified mirror SELECT",
+  "baseline": {
+    "foreign_products": 75,
+    "foreign_images": 203,
+    "source": "TK-11302 ticket"
+  },
+  "build_identity": {
+    "commit": "0a6978b4dfe0f75e12bd3097d345cda0a6898eab",
+    "verifier_sha256": "bacacc72e24d9841188b2cd7c6797eb3f4d23f59b1ea63cd504830fbcdfb017a",
+    "actions_sha256": "4d3b291840eef7f90189e564762f37a7dbf681c68cfc97bbe8c845e79a1c2f89",
+    "round1_sha256": "2afca3a2783a248b937bee5e6a8b2e6c68d8970c91640a21d5b03667aadd8e51",
+    "payloads_sha256": "5150725c14f3ffb28680126f86dd080472332bca46e54d83218a7d289c07cf83"
+  },
+  "commands": [
+    "node ~/.claude/skills/dw-image-identity-canary/canary.mjs --dump",
+    "node verification/TK-11302/verify.mjs"
+  ],
+  "counts": {
+    "requests": 4,
+    "active": 960,
+    "sku_covered": 960,
+    "gallery_images": 125,
+    "repair_actions": 211,
+    "repair_products": 75,
+    "remaining_repair_images": 0,
+    "payloads": 506,
+    "bad_payload_galleries": 0
+  },
+  "checks": [
+    {
+      "assertion": "Active product coverage matches fresh canary",
+      "verdict": "PASS"
+    },
+    {
+      "assertion": "Every active product has mirror manufacturer SKU",
+      "verdict": "PASS"
+    },
+    {
+      "assertion": "Every planned repair product remains active",
+      "verdict": "PASS"
+    },
+    {
+      "assertion": "All filenames from both repair rounds are absent",
+      "verdict": "PASS"
+    },
+    {
+      "assertion": "Every repaired product retains an image",
+      "verdict": "PASS"
+    },
+    {
+      "assertion": "Staged payload galleries contain only own-SAW images",
+      "verdict": "PASS"
+    },
+    {
+      "assertion": "Canary reports zero foreign images, independent of baseline",
+      "verdict": "PASS"
+    },
+    {
+      "assertion": "Canary evidence is less than 15 minutes old",
+      "verdict": "PASS"
+    }
+  ],
+  "canary": {
+    "skill": "dw-image-identity-canary",
+    "verdict": "PASS",
+    "status": "PASS",
+    "ts": "2026-09-11T00:37:57.933Z",
+    "vendors": [
+      "Sanderson"
+    ],
+    "totals": {
+      "active": 960,
+      "gallery_imgs": 125,
+      "foreign_imgs": 0,
+      "foreign_products": 0
+    },
+    "baseline": {
+      "foreign_products": 6,
+      "foreign_imgs": 6,
+      "ts": "2026-09-03T18:40:47.111Z",
+      "note": "first-run baseline"
+    },
+    "perVendor": {
+      "Sanderson": {
+        "active": 960,
+        "gallery_imgs": 125,
+        "foreign_imgs": 0,
+        "foreign_products": 0,
+        "examples": []
+      }
+    },
+    "note": "no worsening (0 products <= baseline 6)"
+  },
+  "failures": {
+    "missingSku": [],
+    "absentProducts": [],
+    "stillPresent": [],
+    "affectedNoHero": [],
+    "badPayloadGallery": []
+  },
+  "observations": {
+    "unrelatedImagelessProducts": [
+      {
+        "id": 7899582201907,
+        "handle": "101-dalmatians-breeze-blue-sanderson",
+        "images": []
+      }
+    ]
+  },
+  "limitations": [
+    "Filename/SKU identity does not prove visual correctness of unresolved SKU-less assets or hero images.",
+    "Current clean state cannot guarantee future imports.",
+    "No mutation, rollback, or authentication-failure drill needed for read-only closure verification."
+  ],
+  "cleanup": "Only local evidence retained. No catalog writes or alert sends; existing baseline unchanged.",
+  "verdict": "PASS"
+}
diff --git a/verification/TK-11302/verify.mjs b/verification/TK-11302/verify.mjs
new file mode 100644
index 0000000..405ac75
--- /dev/null
+++ b/verification/TK-11302/verify.mjs
@@ -0,0 +1,73 @@
+// Read-only closure verification: Shopify GETs and local SELECTs only.
+import fs from 'node:fs';
+import {execFileSync} from 'node:child_process';
+import {createHash} from 'node:crypto';
+const home = process.env.HOME;
+const root = new URL('../../', import.meta.url);
+const hash = p => createHash('sha256').update(fs.readFileSync(p)).digest('hex');
+const secret = fs.readFileSync(`${home}/Projects/secrets-manager/.env`, 'utf8')
+  .match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)?.[1].trim().replace(/^["']|["']$/g, '');
+if (!secret) throw Error('Missing Shopify credential');
+const sql = `SELECT split_part(shopify_id,'/',5), coalesce(metafields->'dwc'->'manufacturer_sku'->>'value','') FROM shopify_products WHERE vendor='Sanderson';`;
+const mapping = execFileSync('/opt/homebrew/bin/psql', ['-h','/tmp','dw_unified','-v','ON_ERROR_STOP=1','-t','-A','-F','|','-c',sql], {encoding:'utf8'});
+const skuMap = new Map(mapping.trim().split('\n').map(x => x.trim().split('|')));
+const products = [];
+let requests = 0;
+let url = 'https://designer-laboratory-sandbox.myshopify.com/admin/api/2024-10/products.json?vendor=Sanderson&status=active&limit=250&fields=id,handle,images';
+while (url) {
+  const response = await fetch(url, {headers:{'X-Shopify-Access-Token':secret}, signal:AbortSignal.timeout(30000)});
+  requests++;
+  if (!response.ok) throw Error(`Shopify GET failed: ${response.status}`);
+  const body = await response.json();
+  if (!Array.isArray(body.products)) throw Error('Missing products array');
+  products.push(...body.products);
+  url = (response.headers.get('link') || '').split(',').find(x => x.includes('rel="next"'))?.match(/<([^>]+)>/)?.[1];
+  if (url) await new Promise(resolve => setTimeout(resolve,600));
+}
+const actionsPath = `${home}/Projects/dw-sanderson-image-fix/tk11297_actions.json`;
+const round1Path = actionsPath + '.bak-round1-89';
+const actions = [...JSON.parse(fs.readFileSync(round1Path,'utf8')), ...JSON.parse(fs.readFileSync(actionsPath,'utf8'))];
+const byId = new Map(products.map(p => [String(p.id), p]));
+const filename = src => new URL(src).pathname.split('/').pop();
+const missingSku = products.filter(p => !skuMap.get(String(p.id)));
+const absentProducts = actions.filter(a => !byId.has(String(a.id)));
+const stillPresent = actions.filter(a => byId.get(String(a.id))?.images.some(im => filename(im.src) === a.fn));
+const noHero = products.filter(p => !p.images?.length);
+const affectedIds = new Set(actions.map(a => String(a.id)));
+const affectedNoHero = noHero.filter(p => affectedIds.has(String(p.id)));
+const payloadPath = new URL('scripts/sanderson-onboard/out/payloads-imgfixed.jsonl', root);
+const payloads = fs.readFileSync(payloadPath,'utf8').trim().split('\n').map(JSON.parse);
+const key = value => String(value).match(/SAW\s*0*\d{3,4}[-_]\d{1,3}/i)?.[0].toUpperCase().replace(/[^A-Z0-9]/g,'');
+const badPayloadGallery = payloads.flatMap(p => (p.product.images || []).slice(1)
+  .filter(im => !key(p.mfr_sku) || key(im.src) !== key(p.mfr_sku)).map(im => ({sku:p.mfr_sku,src:im.src})));
+const canaryPath = `${home}/.claude/skills/dw-image-identity-canary/data/latest.json`;
+const canary = JSON.parse(fs.readFileSync(canaryPath,'utf8'));
+const checks = [
+  ['Active product coverage matches fresh canary',products.length > 0 && products.length === canary.totals.active],
+  ['Every active product has mirror manufacturer SKU',missingSku.length === 0],
+  ['Every planned repair product remains active',absentProducts.length === 0],
+  ['All filenames from both repair rounds are absent',stillPresent.length === 0],
+  ['Every repaired product retains an image',affectedNoHero.length === 0],
+  ['Staged payload galleries contain only own-SAW images',badPayloadGallery.length === 0],
+  ['Canary reports zero foreign images, independent of baseline',canary.status === 'PASS' && canary.totals.foreign_imgs === 0 && canary.totals.foreign_products === 0],
+  ['Canary evidence is less than 15 minutes old',Date.now() - Date.parse(canary.ts) < 900000],
+].map(([assertion, pass]) => ({assertion,verdict:pass?'PASS':'FAIL'}));
+const evidence = {
+  ticket:'TK-11302-dw-image-identity-canary-sanderson-galle',timestamp:new Date().toISOString(),
+  intent:'Verify already-applied Sanderson gallery remediation and safe staged galleries without catalog writes',
+  risk_tier:'Read-only external integration; R0 evidence artifact',
+  environment:'Live Shopify Admin GETs; local dw_unified mirror SELECT',
+  baseline:{foreign_products:75,foreign_images:203,source:'TK-11302 ticket'},
+  build_identity:{commit:execFileSync('git',['rev-parse','HEAD'],{cwd:root,encoding:'utf8'}).trim(),verifier_sha256:hash(new URL(import.meta.url)),actions_sha256:hash(actionsPath),round1_sha256:hash(round1Path),payloads_sha256:hash(payloadPath)},
+  commands:['node ~/.claude/skills/dw-image-identity-canary/canary.mjs --dump','node verification/TK-11302/verify.mjs'],
+  counts:{requests,active:products.length,sku_covered:products.length-missingSku.length,gallery_images:products.reduce((n,p)=>n+Math.max(0,p.images.length-1),0),repair_actions:actions.length,repair_products:new Set(actions.map(a=>a.id)).size,remaining_repair_images:stillPresent.length,payloads:payloads.length,bad_payload_galleries:badPayloadGallery.length},
+  checks,canary,
+  failures:{missingSku:missingSku.map(p=>p.id),absentProducts,stillPresent,affectedNoHero:affectedNoHero.map(p=>p.id),badPayloadGallery},
+  observations:{unrelatedImagelessProducts:noHero.filter(p=>!affectedIds.has(String(p.id)))} ,
+  limitations:['Filename/SKU identity does not prove visual correctness of unresolved SKU-less assets or hero images.','Current clean state cannot guarantee future imports.','No mutation, rollback, or authentication-failure drill needed for read-only closure verification.'],
+  cleanup:'Only local evidence retained. No catalog writes or alert sends; existing baseline unchanged.',
+  verdict:checks.every(c=>c.verdict==='PASS')?'PASS':'FAIL'
+};
+fs.writeFileSync(new URL('./e2e-proof.json',import.meta.url),JSON.stringify(evidence,null,2)+'\n');
+console.log(JSON.stringify({verdict:evidence.verdict,counts:evidence.counts,checks},null,2));
+if(evidence.verdict!=='PASS')process.exitCode=1;

← 0a6978b TK-11307: theme deploy targeted an UNPUBLISHED theme; rollba  ·  back to Designerwallcoverings  ·  TK-11307: tag-driven Boost card hider (Steve's ruling: keep 5b789a2 →