← back to Designer Wallcoverings
TK-11786: scraper fixes — anna-french null-byte sentinel, slack no-op resolve() (Promise hang), kravet GID normalize
008592bf55e7b6aadf876843f698f8259770e2c0 · 2026-09-22 13:35:27 -0700 · Steve
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G3ChReG53fwpNgUESv4SY7
Files touched
M shopify/scripts/anna-french-scraper.jsM shopify/scripts/fix-sample-inventory-only.jsM shopify/scripts/gemini-tag-engine/index.jsM shopify/scripts/kravet-map-reprice.jsM shopify/scripts/push-pattern-repeat-metafields.jsM shopify/scripts/resume-sample-variant-creation.jsM shopify/scripts/texture-repeat-fixer.jsM shopify/scripts/thibaut-repeat-scraper.js
Diff
commit 008592bf55e7b6aadf876843f698f8259770e2c0
Author: Steve <steve@designerwallcoverings.com>
Date: Tue Sep 22 13:35:27 2026 -0700
TK-11786: scraper fixes — anna-french null-byte sentinel, slack no-op resolve() (Promise hang), kravet GID normalize
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G3ChReG53fwpNgUESv4SY7
---
shopify/scripts/anna-french-scraper.js | 2 +-
shopify/scripts/fix-sample-inventory-only.js | 2 +-
shopify/scripts/gemini-tag-engine/index.js | 2 +-
shopify/scripts/kravet-map-reprice.js | 13 ++++++++++++-
shopify/scripts/push-pattern-repeat-metafields.js | 2 +-
shopify/scripts/resume-sample-variant-creation.js | 2 +-
shopify/scripts/texture-repeat-fixer.js | 2 +-
shopify/scripts/thibaut-repeat-scraper.js | 2 +-
8 files changed, 19 insertions(+), 8 deletions(-)
diff --git a/shopify/scripts/anna-french-scraper.js b/shopify/scripts/anna-french-scraper.js
index ab11554c..13db53ae 100644
--- a/shopify/scripts/anna-french-scraper.js
+++ b/shopify/scripts/anna-french-scraper.js
@@ -84,7 +84,7 @@ function cleanWallpaper(s) {
// "Wallpaper", skip wallpapered/wallpapering, case-preserving generic swap.
const WALLPAPER_BRANDS = ['Apartment','Boråstapeter','China Seas','DW Exclusive','Edge','Fentucci','Grasscloth','Laura Ashley','Malibu','MC Escher','Missoni','Nicolette Mayer','PS Removable','Ralph Lauren','Roberto Cavalli','Scalamandre','Schumacher'];
const _brandRe = new RegExp('(' + WALLPAPER_BRANDS.map(function(b){return b.replace(/[.*+?^${}()|[\]\\]/g,'\\$&');}).join('|') + ')\\s+Wallpaper','gi');
- const _hold = []; const _S = ' ';
+ const _hold = []; const _S = '\u0000'; // null-byte sentinel; a plain space collided with numeric repeat/width values and corrupted descriptions (matches anna-french-enrich.js)
let out = String(s).replace(_brandRe, function(m){ _hold.push(m); return _S + (_hold.length-1) + _S; });
out = out.replace(/\bWallpaper(s?)\b(?!ed|ing)/gi, function(m, plural){
const base = plural ? 'wallcoverings' : 'wallcovering';
diff --git a/shopify/scripts/fix-sample-inventory-only.js b/shopify/scripts/fix-sample-inventory-only.js
index 0a3ab8ad..c5759c08 100644
--- a/shopify/scripts/fix-sample-inventory-only.js
+++ b/shopify/scripts/fix-sample-inventory-only.js
@@ -47,7 +47,7 @@ function graphql(query, variables = {}) {
function sendSlack(text) {
return new Promise((resolve) => {
const body = JSON.stringify({ text });
- if (!/^https?:\/\//.test(SLACK_WEBHOOK)) return; // slack: no-op when unset
+ if (!/^https?:\/\//.test(SLACK_WEBHOOK)) return resolve(); // slack: no-op when unset
const url = new URL(SLACK_WEBHOOK);
const req = https.request({
hostname: url.hostname, path: url.pathname, method: 'POST',
diff --git a/shopify/scripts/gemini-tag-engine/index.js b/shopify/scripts/gemini-tag-engine/index.js
index 7536161f..b1eef24e 100644
--- a/shopify/scripts/gemini-tag-engine/index.js
+++ b/shopify/scripts/gemini-tag-engine/index.js
@@ -120,7 +120,7 @@ function log(msg) {
async function sendSlack(text) {
return new Promise((resolve) => {
- if (!/^https?:\/\//.test(SLACK_WEBHOOK)) return; // slack: no-op when unset
+ if (!/^https?:\/\//.test(SLACK_WEBHOOK)) return resolve(); // slack: no-op when unset
const url = new URL(SLACK_WEBHOOK);
const data = JSON.stringify({ text });
const req = https.request({
diff --git a/shopify/scripts/kravet-map-reprice.js b/shopify/scripts/kravet-map-reprice.js
index 262ea6bc..4de77a1b 100644
--- a/shopify/scripts/kravet-map-reprice.js
+++ b/shopify/scripts/kravet-map-reprice.js
@@ -106,7 +106,12 @@ const logFail = o => fs.appendFileSync(FAILLOG, JSON.stringify(o) + '\n');
let i = 0;
for (const row of rows) {
i++;
- const pid = `gid://shopify/Product/${row.shopify_id}`;
+ // shopify_id may be a bare numeric id (frozen CSV) OR already a full GID (the
+ // FTP-regenerated worklist-latest.csv). Normalize so we never double-prefix into
+ // gid://shopify/Product/gid://shopify/Product/… which resolves to nothing.
+ const pid = String(row.shopify_id).startsWith('gid://')
+ ? row.shopify_id
+ : `gid://shopify/Product/${row.shopify_id}`;
const map = parseFloat(row.map), cost = parseFloat(row.cost_price);
if (!(map > 0)) { skipped++; continue; }
@@ -151,4 +156,10 @@ const logFail = o => fs.appendFileSync(FAILLOG, JSON.stringify(o) + '\n');
}
console.log(`\nDone. repriced=${repriced} costSet=${costSet} already=${already} skipped=${skipped} failed=${failed}`);
if (failed) console.log(`failures → ${FAILLOG}`);
+ // Fail loud: if EVERY row failed to resolve, this is a broken run (e.g. malformed ids),
+ // not a clean "nothing to do" — never let a total failure masquerade as success.
+ if (rows.length > 0 && failed === rows.length) {
+ console.error(`\n❌ ALL ${rows.length} rows failed — aborting as a broken run (check id/GID shape and ${FAILLOG}).`);
+ process.exitCode = 1;
+ }
})();
diff --git a/shopify/scripts/push-pattern-repeat-metafields.js b/shopify/scripts/push-pattern-repeat-metafields.js
index 039d0ea1..05e52bae 100644
--- a/shopify/scripts/push-pattern-repeat-metafields.js
+++ b/shopify/scripts/push-pattern-repeat-metafields.js
@@ -149,7 +149,7 @@ function normalizeGid(shopifyId) {
async function sendSlack(text) {
return new Promise((resolve) => {
const body = JSON.stringify({ text });
- if (!/^https?:\/\//.test(SLACK_WEBHOOK)) return; // slack: no-op when unset
+ if (!/^https?:\/\//.test(SLACK_WEBHOOK)) return resolve(); // slack: no-op when unset
const url = new URL(SLACK_WEBHOOK);
const req = https.request({
hostname: url.hostname,
diff --git a/shopify/scripts/resume-sample-variant-creation.js b/shopify/scripts/resume-sample-variant-creation.js
index ad289ab2..ea581c8f 100644
--- a/shopify/scripts/resume-sample-variant-creation.js
+++ b/shopify/scripts/resume-sample-variant-creation.js
@@ -88,7 +88,7 @@ function restApi(method, path, body = null) {
function sendSlack(text) {
return new Promise(resolve => {
const body = JSON.stringify({ text });
- if (!/^https?:\/\//.test(SLACK_WEBHOOK)) return; // slack: no-op when unset
+ if (!/^https?:\/\//.test(SLACK_WEBHOOK)) return resolve(); // slack: no-op when unset
const url = new URL(SLACK_WEBHOOK);
const req = https.request({
hostname: url.hostname, path: url.pathname, method: 'POST',
diff --git a/shopify/scripts/texture-repeat-fixer.js b/shopify/scripts/texture-repeat-fixer.js
index 9aa14e25..914b5e0b 100644
--- a/shopify/scripts/texture-repeat-fixer.js
+++ b/shopify/scripts/texture-repeat-fixer.js
@@ -205,7 +205,7 @@ async function processVendor(vendorConfig) {
async function sendSlackReport(report) {
return new Promise((resolve) => {
const body = JSON.stringify({ text: report });
- if (!/^https?:\/\//.test(SLACK_WEBHOOK)) return; // slack: no-op when unset
+ if (!/^https?:\/\//.test(SLACK_WEBHOOK)) return resolve(); // slack: no-op when unset
const url = new URL(SLACK_WEBHOOK);
const req = https.request({
hostname: url.hostname,
diff --git a/shopify/scripts/thibaut-repeat-scraper.js b/shopify/scripts/thibaut-repeat-scraper.js
index df7502d3..a160b33c 100644
--- a/shopify/scripts/thibaut-repeat-scraper.js
+++ b/shopify/scripts/thibaut-repeat-scraper.js
@@ -107,7 +107,7 @@ async function sendSlackNotification(stats, duration) {
return new Promise((resolve) => {
const payload = JSON.stringify({ text: msg });
- if (!/^https?:\/\//.test(SLACK_WEBHOOK)) return; // slack: no-op when unset
+ if (!/^https?:\/\//.test(SLACK_WEBHOOK)) return resolve(); // slack: no-op when unset
const url = new URL(SLACK_WEBHOOK);
const req = https.request({
hostname: url.hostname, path: url.pathname, method: 'POST',
← a939ff3d TK-11786: fail-loud --apply/--dry-run guards on push + singl
·
back to Designer Wallcoverings
·
TK-11786: remove superseded one-off scripts (romo-drilldown, 83214c10 →