← back to Norma
IG cadence: close carousel room-image dedup gap (Cody gate) — ledger now records ALL slides + dedup skips candidates whose room OR swatch was already posted, so room photos no longer repeat across accounts
4b58e973dcb916d71572979f304aff57c2d99271 · 2026-08-15 08:05:04 -0700 · Steve
Files touched
M agents/instagram-agent/daily-cadence.jsM agents/instagram-agent/post-to.js
Diff
commit 4b58e973dcb916d71572979f304aff57c2d99271
Author: Steve <steve@designerwallcoverings.com>
Date: Sat Aug 15 08:05:04 2026 -0700
IG cadence: close carousel room-image dedup gap (Cody gate) — ledger now records ALL slides + dedup skips candidates whose room OR swatch was already posted, so room photos no longer repeat across accounts
---
agents/instagram-agent/daily-cadence.js | 12 ++++++++++--
agents/instagram-agent/post-to.js | 3 +++
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/agents/instagram-agent/daily-cadence.js b/agents/instagram-agent/daily-cadence.js
index 9a082e7..6ca2ff5 100644
--- a/agents/instagram-agent/daily-cadence.js
+++ b/agents/instagram-agent/daily-cadence.js
@@ -57,7 +57,14 @@ const everPosted = new Set(rows.map((r) => r.product_handle)); // avoid reusing
// Also dedup by IMAGE identity (filename), not just handle — several handles can share one image
// (e.g. the "Quick Ship Durable Walls" variants), which was silently creating same-image duplicates.
const imgKey = (u) => String(u || '').split('/').pop().split('?')[0].toLowerCase();
-const everPostedImg = new Set(rows.map((r) => imgKey(r.image_url)).filter(Boolean));
+// Build from ALL published slides (carousel room + swatch), not just the swatch — else the room
+// photo repeats across accounts, unguarded (Cody gate, /yoloforever cycle 1).
+const everPostedImg = new Set();
+for (const r of rows) {
+ everPostedImg.add(imgKey(r.image_url));
+ String(r.images || '').split(',').forEach((u) => everPostedImg.add(imgKey(u)));
+}
+everPostedImg.delete('');
function themeFor(h) {
const o = themes[h] || {};
@@ -79,7 +86,8 @@ async function tryCandidates(list) {
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) — UNCHANGED
- if (everPostedImg.has(imgKey(r.image_url))) continue; // same image already posted — skip (no dup)
+ // Skip if ANY slide (room OR swatch) was already posted — not just the swatch.
+ if ((r.images || [r.image_url]).some((u) => everPostedImg.has(imgKey(u)))) continue;
return { handle: p.handle, title: r.title, image_url: r.image_url };
} catch { /* leak or imageless — next */ }
}
diff --git a/agents/instagram-agent/post-to.js b/agents/instagram-agent/post-to.js
index bf91c37..ebe5f3e 100644
--- a/agents/instagram-agent/post-to.js
+++ b/agents/instagram-agent/post-to.js
@@ -254,6 +254,9 @@ async function main() {
ts: new Date().toISOString(), handle: t.handle, page_name: t.page_name || null,
product_handle: args._productHandle || null, product_title: args._productTitle || null,
image_url: args._imageUrl || args.image || null,
+ // ALL published slides (carousel = room + swatch), so the cadence's image-dedup guard
+ // sees the room photo too — not just the swatch (Cody gate, /yoloforever cycle 1).
+ images: args.images || args._imageUrl || args.image || null,
permalink: r.permalink || null, media_id: r.media_id || null, kind: r.kind || null,
}) + '\n');
} catch (_) { /* ledger is best-effort; never block a post */ }
← 43de9ea Norma IG cadence: fresh-source via Boost API (fixes clean-pr
·
back to Norma
·
Norma IG cadence: 8s timeout on Boost fetch (Cody FIX-FIRST, 0ff33f9 →