[object Object]

← back to Norma Platform

Norma IG cadence: fresh-source via Boost API (fixes clean-product pool exhaustion)

43de9ea5386433546ec13523423f8572e31f7819 · 2026-08-15 08:00:57 -0700 · Steve Abrams

Root cause: findProduct sourced only 10 candidates/keyword from suggest.json;
as everPosted grew, narrow-keyword pools exhausted -> 'no clean product … all reused'.
Fix pages the Boost SF-filter search API (50/page, thousands available) for the SAME
keyword, applying the IDENTICAL leak/no-image guard to every candidate + suggest.json
fallback. Widens the guard-gated pool WITHOUT loosening the private-label guard.
DTD 7/9 Option C, Cody-scoped. TK-10588.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 43de9ea5386433546ec13523423f8572e31f7819
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sat Aug 15 08:00:57 2026 -0700

    Norma IG cadence: fresh-source via Boost API (fixes clean-product pool exhaustion)
    
    Root cause: findProduct sourced only 10 candidates/keyword from suggest.json;
    as everPosted grew, narrow-keyword pools exhausted -> 'no clean product … all reused'.
    Fix pages the Boost SF-filter search API (50/page, thousands available) for the SAME
    keyword, applying the IDENTICAL leak/no-image guard to every candidate + suggest.json
    fallback. Widens the guard-gated pool WITHOUT loosening the private-label guard.
    DTD 7/9 Option C, Cody-scoped. TK-10588.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 agents/instagram-agent/daily-cadence.js | 37 +++++++++++++++++++++++++++------
 1 file changed, 31 insertions(+), 6 deletions(-)

diff --git a/agents/instagram-agent/daily-cadence.js b/agents/instagram-agent/daily-cadence.js
index 5c23afd..9a082e7 100644
--- a/agents/instagram-agent/daily-cadence.js
+++ b/agents/instagram-agent/daily-cadence.js
@@ -66,14 +66,19 @@ function themeFor(h) {
   return { keyword, sensitive: !!o.sensitive };
 }
 
-async function findProduct(keyword) {
-  const u = `${STORE}/search/suggest.json?q=${encodeURIComponent(keyword)}&resources%5Btype%5D=product&resources%5Blimit%5D=10`;
-  let list = [];
-  try { const j = await (await fetch(u)).json(); list = (j.resources?.results?.products) || []; } catch { return null; }
+// Fresh-sourcing fix (TK-10588, DTD 7/9 C + Cody-scoped 2026-08-15): the old source was
+// suggest.json capped at 10 candidates/keyword, so narrow-keyword pools exhausted as everPosted
+// grew ("no clean product … all reused"). We now page the Boost SF-filter search API (50/keyword/page,
+// thousands available) for the SAME keyword. Every candidate STILL passes the identical leak/no-image
+// guard below — this WIDENS the guard-gated pool, it does NOT loosen the private-label guard.
+const BOOST_SHOP = 'designer-laboratory-sandbox.myshopify.com';
+const CANDIDATE_PAGES = 3; // up to 150 guard-gated candidates before giving up
+
+async function tryCandidates(list) {
   for (const p of list) {
-    if (everPosted.has(p.handle)) continue; // don't repost a product
+    if (!p.handle || everPosted.has(p.handle)) continue; // don't repost a product
     try {
-      const r = await content.resolveProduct(p.handle); // throws on leak/no-image (guard)
+      const r = await content.resolveProduct(p.handle); // throws on leak/no-image (guard) — UNCHANGED
       if (everPostedImg.has(imgKey(r.image_url))) continue; // same image already posted — skip (no dup)
       return { handle: p.handle, title: r.title, image_url: r.image_url };
     } catch { /* leak or imageless — next */ }
@@ -81,6 +86,26 @@ async function findProduct(keyword) {
   return null;
 }
 
+async function findProduct(keyword) {
+  for (let page = 1; page <= CANDIDATE_PAGES; page++) {
+    let list = [];
+    try {
+      const u = `https://services.mybcapps.com/bc-sf-filter/search?q=${encodeURIComponent(keyword)}&shop=${BOOST_SHOP}&limit=50&page=${page}`;
+      const j = await (await fetch(u)).json();
+      list = j.products || [];
+    } catch { break; }
+    if (!list.length) break;
+    const hit = await tryCandidates(list);
+    if (hit) return hit;
+  }
+  // Fallback: original 10-capped suggest.json if the Boost API is unreachable.
+  try {
+    const u = `${STORE}/search/suggest.json?q=${encodeURIComponent(keyword)}&resources%5Btype%5D=product&resources%5Blimit%5D=10`;
+    const j = await (await fetch(u)).json();
+    return await tryCandidates((j.resources?.results?.products) || []);
+  } catch { return null; }
+}
+
 (async () => {
   if (isRestDay) { console.log('REST DAY (Sunday) — no posting today.'); return; }
   const hour = now.getHours();

← 191eee1 IG cadence: dedup by IMAGE filename (not just product handle  ·  back to Norma Platform  ·  IG cadence: close carousel room-image dedup gap (Cody gate) 4b58e97 →