← back to Canary Patches

five-field-logo-placeholder.patch

60 lines

--- a/.claude/skills/dw-five-field-canary/auditor.mjs
+++ b/.claude/skills/dw-five-field-canary/auditor.mjs
@@ -68,10 +68,18 @@ const cur = q(`
     count(*) FILTER (WHERE image_url IS NOT NULL) img_scanned,
     count(*) FILTER (WHERE image_url IS NULL) no_image,
     count(*) FILTER (WHERE image_url IS NULL
-        AND created_at_shopify > now() - interval '${RECENT_DAYS} days') recent_no_image
+        AND created_at_shopify > now() - interval '${RECENT_DAYS} days') recent_no_image,
+    -- (7th field, added 2026-08-12, TK-10467): logo-as-placeholder check.
+    -- PJ (~2,468) + Maya Romanoff (~13) = 2,481 known floor. Alert on GROWTH (new
+    -- vendors activated with brand-logo placeholders) or RECENT logo-image cadence.
+    count(*) FILTER (WHERE image_url ILIKE '%logo%') logo_image,
+    count(*) FILTER (WHERE image_url ILIKE '%logo%'
+        AND created_at_shopify > now() - interval '${RECENT_DAYS} days') recent_logo_image
   FROM p;`).split('\t').map(Number);

-const [scanned, miss_sample, miss_product, zero_price, no_desc, no_tags, fail_any, recent_fail, img_scanned, no_image, recent_no_image] = cur;
+const [scanned, miss_sample, miss_product, zero_price, no_desc, no_tags, fail_any, recent_fail, img_scanned, no_image, recent_no_image, logo_image, recent_logo_image] = cur;
@@ -116,6 +124,22 @@ if (img_scanned > 0) {   // image data present in the mirror — check is evalua
   }
 }

+// (7th field) LOGO-AS-PLACEHOLDER check — added 2026-08-12 (TK-10467 canary-gap rec).
+// Known floor: 2,481 (PJ 2,468 + MR 13). Alert on GROWTH above floor (new vendor
+// logo-plaseholders leaking in) or any RECENT cadence (importer should never activate
+// with a logo placeholder image).
+const LOGO_GROWTH_TOL = 20;
+if (img_scanned > 0) {
+  if (recent_logo_image > 0) {
+    const rows = q(`
+      SELECT DISTINCT ON (shopify_id) vendor, variant_sku sku
+      FROM shopify_products WHERE status ILIKE 'active' AND image_url ILIKE '%logo%'
+        AND created_at_shopify > now() - interval '${RECENT_DAYS} days'
+      LIMIT 12;`).split('\n').filter(Boolean).map(l => { const [vendor, sku] = l.split('\t'); return { vendor, sku }; });
+    findings.push({ sev: 'FAIL', check: 'logo-image-cadence', msg: `${recent_logo_image} product(s) created in the last ${RECENT_DAYS} days are ACTIVE with a brand-logo placeholder image — a vendor was activated without real product photos.`, rows });
+  }
+  const logo_floor = baseline?.logo_image ?? logo_image;
+  if (logo_image > logo_floor + LOGO_GROWTH_TOL) {
+    findings.push({ sev: 'FAIL', check: 'logo-image-growth', msg: `Logo-placeholder active products grew ${logo_image - logo_floor} (now ${logo_image}, floor ${logo_floor}) — a new vendor line was activated with logo images only.`, rows: [] });
+  }
+}
+
@@ -140,7 +164,8 @@ const verdict = fail ? 'FAIL' : warn ? 'WARN' : 'PASS';
 writeFileSync(join(DATA, 'latest.json'), JSON.stringify({
   scanned_at: new Date().toISOString(), verdict, fail, warn,
-  metrics: { scanned, miss_sample, miss_product, zero_price, no_desc, no_tags, fail_any, recent_fail, img_scanned, no_image, recent_no_image },
+  metrics: { scanned, miss_sample, miss_product, zero_price, no_desc, no_tags, fail_any, recent_fail, img_scanned, no_image, recent_no_image, logo_image, recent_logo_image },
   baseline: baseline ? baseline.fail_any : null,
   findings,
 }, null, 2));
@@ -148,7 +173,9 @@ writeFileSync(join(DATA, 'latest.json'), JSON.stringify({
 if (verdict === 'PASS') {
   const saved_no_desc = Math.min(no_desc, baseline?.no_desc ?? no_desc);
-  writeFileSync(BASELINE, JSON.stringify({ fail_any, no_image: img_scanned > 0 ? no_image : (baseline?.no_image ?? null), no_desc: saved_no_desc, updated_at: new Date().toISOString() }, null, 2));
+  const saved_logo = Math.min(logo_image, baseline?.logo_image ?? logo_image);
+  writeFileSync(BASELINE, JSON.stringify({ fail_any, no_image: img_scanned > 0 ? no_image : (baseline?.no_image ?? null), no_desc: saved_no_desc, logo_image: img_scanned > 0 ? saved_logo : (baseline?.logo_image ?? null), updated_at: new Date().toISOString() }, null, 2));
 }
-console.log(`${verdict} (${fail} FAIL, ${warn} WARN) — fail_any=${fail_any} recent_fail=${recent_fail} no_image=${no_image} recent_no_image=${recent_no_image}`);
+console.log(`${verdict} (${fail} FAIL, ${warn} WARN) — fail_any=${fail_any} recent_fail=${recent_fail} no_image=${no_image} logo_image=${logo_image} recent_logo_image=${recent_logo_image}`);