← back to Designer Wallcoverings
chore: image-gate sweep hardening per code review — check DEMOTE userErrors before counting, include Video/ExternalVideo media, media(first:50), summary count reflects demotions (session close)
b05ee05535911da0d5dd32f62a8b50b86657c37a · 2026-07-29 20:18:18 -0700 · Steve
Files touched
M shopify/scripts/cadence/cadence-import.js
Diff
commit b05ee05535911da0d5dd32f62a8b50b86657c37a
Author: Steve <steve@designerwallcoverings.com>
Date: Wed Jul 29 20:18:18 2026 -0700
chore: image-gate sweep hardening per code review — check DEMOTE userErrors before counting, include Video/ExternalVideo media, media(first:50), summary count reflects demotions (session close)
---
shopify/scripts/cadence/cadence-import.js | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/shopify/scripts/cadence/cadence-import.js b/shopify/scripts/cadence/cadence-import.js
index f3ebaba0..55a518ce 100644
--- a/shopify/scripts/cadence/cadence-import.js
+++ b/shopify/scripts/cadence/cadence-import.js
@@ -929,7 +929,7 @@ async function verifyActivatedMedia(pids) {
if (!pids.length) return out;
console.log(`\nverifying image uploads reached READY on ${pids.length} activated product(s)…`);
await sleep(30000); // let async media settle
- const Q = `query($ids:[ID!]!){nodes(ids:$ids){... on Product{id handle status media(first:10){nodes{... on MediaImage{status}}}}}}`;
+ const Q = `query($ids:[ID!]!){nodes(ids:$ids){... on Product{id handle status media(first:50){nodes{... on MediaImage{status} ... on Video{status} ... on ExternalVideo{status}}}}}}`;
const DEMOTE = `mutation($input:ProductInput!){productUpdate(input:$input){product{id} userErrors{message}}}`;
const TAGS = `mutation($id:ID!,$tags:[String!]!){tagsAdd(id:$id,tags:$tags){userErrors{message}}}`;
let pending = pids.slice();
@@ -944,7 +944,9 @@ async function verifyActivatedMedia(pids) {
if (st.includes('READY')) continue; // an image landed — gate satisfied
if (st.includes('PROCESSING')) { next.push(n.id); continue; }
// no READY, nothing PROCESSING (all FAILED or zero media): no image is coming
- await gqlRetry(DEMOTE, { input: { id: n.id, status: 'DRAFT' } });
+ const dr = await gqlRetry(DEMOTE, { input: { id: n.id, status: 'DRAFT' } });
+ const dErr = dr.json?.data?.productUpdate?.userErrors;
+ if (dErr && dErr.length) { console.warn(` ✗ ${n.handle}: DEMOTE failed — ${JSON.stringify(dErr).slice(0,120)} (still ACTIVE+imageless — five-field canary will flag)`); continue; }
await gqlRetry(TAGS, { id: n.id, tags: ['Needs-Image'] });
out.demoted++;
console.log(` ⚠ ${n.handle}: image upload FAILED/absent → demoted to DRAFT (Needs-Image)`);
@@ -1072,8 +1074,9 @@ if (require.main === module) (async () => {
catch (e) { console.warn(' inventory-set failed (products are ACTIVE but inventory not 2026 — re-run inventory-set-2026.js):', e.message); }
}
// TK-10040 image-gate sweep: demote any activated product whose async image upload never landed.
+ let imageDemoted = 0;
if (COMMIT && ACTIVATE && activatedPids.length) {
- try { await verifyActivatedMedia(activatedPids); }
+ try { const sweep = await verifyActivatedMedia(activatedPids); imageDemoted = sweep.demoted; activatedCount -= imageDemoted; }
catch (e) { console.warn(' image-verify sweep failed (products stay as-is; five-field canary is the backstop):', e.message); }
}
// auto-membership into "Trending Wallcovering Collection 2026" (the New-Arrivals auto-flow fix).
← f321a5a0 cadence-import: delete dead <li> spec-list blocks (TK-10039
·
back to Designer Wallcoverings
·
chore: v1.2.8 (session close) 71ee4e4f →