[object Object]

← back to York Reprice 2026 08

Fix two reproduced defects: silent-degrade in york-cadence + hard-exit-on-missing-secret regression

a908d02607b0bad98f14a21fe2d3af90a8386184 · 2026-09-15 19:06:38 -0700 · Steve

1. cadence/york-cadence.mjs: the bare try{}catch(e){} wrapping the naturals
   single-roll (RPS) query and the onboard-candidate query silently emptied
   both on a transient PG hiccup, letting the daily cadence run on degraded
   data with no signal (silent-MAP-overprice class). Both catches now log an
   explicit error naming the failed query and process.exit(1) instead of
   proceeding on empty data. Pricing math unchanged.

2. All 6 scripts (bridge-reprice, build-rows-17, cadence/york-cadence,
   diag-brewster-images, recover-7-settlement, recover-images-17): the prior
   fix made a missing DW_ADMIN_PG_PASSWORD a hard process.exit(1). dw_admin on
   127.0.0.1 is TRUST auth, so a wrong/empty password still connects — the
   hard-exit was a new regression where the job previously ran. Softened to
   WARN-and-proceed: wrap the .env read in try/catch, warn, set PGPASSWORD='',
   and let the actual psql call fail loudly only if a password is truly
   required on the host. Still reads the pw from secrets-manager/.env when present.

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

Files touched

Diff

commit a908d02607b0bad98f14a21fe2d3af90a8386184
Author: Steve <steve@designerwallcoverings.com>
Date:   Tue Sep 15 19:06:38 2026 -0700

    Fix two reproduced defects: silent-degrade in york-cadence + hard-exit-on-missing-secret regression
    
    1. cadence/york-cadence.mjs: the bare try{}catch(e){} wrapping the naturals
       single-roll (RPS) query and the onboard-candidate query silently emptied
       both on a transient PG hiccup, letting the daily cadence run on degraded
       data with no signal (silent-MAP-overprice class). Both catches now log an
       explicit error naming the failed query and process.exit(1) instead of
       proceeding on empty data. Pricing math unchanged.
    
    2. All 6 scripts (bridge-reprice, build-rows-17, cadence/york-cadence,
       diag-brewster-images, recover-7-settlement, recover-images-17): the prior
       fix made a missing DW_ADMIN_PG_PASSWORD a hard process.exit(1). dw_admin on
       127.0.0.1 is TRUST auth, so a wrong/empty password still connects — the
       hard-exit was a new regression where the job previously ran. Softened to
       WARN-and-proceed: wrap the .env read in try/catch, warn, set PGPASSWORD='',
       and let the actual psql call fail loudly only if a password is truly
       required on the host. Still reads the pw from secrets-manager/.env when present.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 bridge-reprice.mjs       |  4 ++--
 build-rows-17.mjs        |  4 ++--
 cadence/york-cadence.mjs | 10 ++++++----
 diag-brewster-images.mjs |  4 ++--
 recover-7-settlement.mjs |  4 ++--
 recover-images-17.mjs    |  4 ++--
 6 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/bridge-reprice.mjs b/bridge-reprice.mjs
index 5935bdd..940f9f1 100644
--- a/bridge-reprice.mjs
+++ b/bridge-reprice.mjs
@@ -4,8 +4,8 @@ const SHOP='designer-laboratory-sandbox.myshopify.com',VER='2024-10';
 const TOKEN=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)||[])[1]?.trim();
 const URL=`https://${SHOP}/admin/api/${VER}/graphql.json`;
 // PG auth: read dw_admin's real password from secrets-manager/.env (same source as SHOPIFY_ADMIN_TOKEN). Nothing exports PGPASSWORD and ~/.pgpass has no dw_unified/dw_admin line, so the old inline `PGPASSWORD=` prefix sent libpq an empty password → auth failure swallowed → silent MAP-only overpricing of naturals.
-const PGPW=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^DW_ADMIN_PG_PASSWORD=(.+)$/m)||[])[1]?.trim();
-if(!PGPW){console.error('FATAL: DW_ADMIN_PG_PASSWORD missing from ~/Projects/secrets-manager/.env — cannot price safely, aborting.');process.exit(1);}
+let PGPW; try{ PGPW=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^DW_ADMIN_PG_PASSWORD=(.+)$/m)||[])[1]?.trim(); }catch(e){}
+if(!PGPW){console.warn('WARN: DW_ADMIN_PG_PASSWORD missing from ~/Projects/secrets-manager/.env — proceeding with empty PGPASSWORD (dw_admin on 127.0.0.1 is TRUST auth); the psql loads below fail loudly (and abort) if a password is truly required on this host.'); PGPW=''; }
 const args=Object.fromEntries(process.argv.slice(2).map(a=>{const[k,v]=a.replace(/^--/,'').split('=');return[k,v===undefined?true:v];}));
 const APPLY=args.apply===true&&args['i-am-steve']===true;
 const INCLUDE_DOWN=args['include-down']===true;
diff --git a/build-rows-17.mjs b/build-rows-17.mjs
index 73e0a27..65b6e71 100644
--- a/build-rows-17.mjs
+++ b/build-rows-17.mjs
@@ -3,8 +3,8 @@
 // data/onboard-rows-17.json (exact phase1-enriched shape build-onboard-payloads expects). $0 local.
 import fs from 'node:fs'; import { execSync } from 'node:child_process';
 // PG auth: read dw_admin's real password from secrets-manager/.env (same source as SHOPIFY_ADMIN_TOKEN); nothing exports PGPASSWORD and ~/.pgpass has no dw_unified/dw_admin line, so an inline empty PGPASSWORD= would silently fail auth.
-const PGPW=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^DW_ADMIN_PG_PASSWORD=(.+)$/m)||[])[1]?.trim();
-if(!PGPW){console.error('FATAL: DW_ADMIN_PG_PASSWORD missing from ~/Projects/secrets-manager/.env');process.exit(1);}
+let PGPW; try{ PGPW=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^DW_ADMIN_PG_PASSWORD=(.+)$/m)||[])[1]?.trim(); }catch(e){}
+if(!PGPW){console.warn('WARN: DW_ADMIN_PG_PASSWORD missing from ~/Projects/secrets-manager/.env — proceeding with empty PGPASSWORD (dw_admin on 127.0.0.1 is TRUST auth); the psql call will fail loudly if a password is truly required on this host.'); PGPW=''; }
 const cands = JSON.parse(fs.readFileSync('data-onboard17-candidates.json','utf8'));
 const skus = cands.map(c=>`'${String(c.mfr_sku).replace(/'/g,"''")}'`).join(',');
 const SEP=String.fromCharCode(31);
diff --git a/cadence/york-cadence.mjs b/cadence/york-cadence.mjs
index 46ccb84..b1db94e 100644
--- a/cadence/york-cadence.mjs
+++ b/cadence/york-cadence.mjs
@@ -17,8 +17,8 @@ const SHOP='designer-laboratory-sandbox.myshopify.com',VER='2024-10';
 const TOKEN=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^SHOPIFY_ADMIN_TOKEN=(.+)$/m)||[])[1]?.trim();
 const URL=`https://${SHOP}/admin/api/${VER}/graphql.json`;
 // PG auth: read dw_admin's real password from secrets-manager/.env (same source as SHOPIFY_ADMIN_TOKEN); nothing exports PGPASSWORD and ~/.pgpass has no dw_unified/dw_admin line, so an inline empty PGPASSWORD= would silently fail auth.
-const PGPW=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^DW_ADMIN_PG_PASSWORD=(.+)$/m)||[])[1]?.trim();
-if(!PGPW){console.error('FATAL: DW_ADMIN_PG_PASSWORD missing from ~/Projects/secrets-manager/.env');process.exit(1);}
+let PGPW; try{ PGPW=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^DW_ADMIN_PG_PASSWORD=(.+)$/m)||[])[1]?.trim(); }catch(e){}
+if(!PGPW){console.warn('WARN: DW_ADMIN_PG_PASSWORD missing from ~/Projects/secrets-manager/.env — proceeding with empty PGPASSWORD (dw_admin on 127.0.0.1 is TRUST auth); the psql call will fail loudly if a password is truly required on this host.'); PGPW=''; }
 // Connect over the /tmp UNIX socket (DW-standard canonical dw_unified path) instead of TCP
 // 127.0.0.1:5432. TCP 5432's listener flaps transiently (it went down Aug 15 → uncaught execSync
 // throw → cadence crash); the /tmp socket is always present. Keep -U dw_admin (md5/scram over the
@@ -53,7 +53,8 @@ for(const line of q(`select concat_ws(chr(31), upper(trim(export_sku)), coalesce
 // natural (grasscloth/sisal/paperweave/cork) as "drift" and would propose re-breaking it daily.
 const RPS=new Map();
 try{ for(const line of q(`select concat_ws(chr(31), upper(trim(mfr_sku)), roll_price_single) from brewster_york_master where roll_price_single is not null and roll_price_single>0`).split('\n').filter(Boolean)){
-  const [s,p]=line.split(String.fromCharCode(31)); if(!RPS.has(s)) RPS.set(s,parseFloat(p)); } }catch(e){}
+  const [s,p]=line.split(String.fromCharCode(31)); if(!RPS.has(s)) RPS.set(s,parseFloat(p)); } }
+catch(e){ console.error('FATAL: naturals single-roll (RPS) query against brewster_york_master failed — refusing to proceed on empty RPS, which would silently MAP-overprice naturals (the banned silent-MAP-overprice class). Aborting.',String(e.message||e).slice(0,160)); process.exit(1); }
 // onboard-ready CANDIDATES from DB (master 'New', settlement-keyword-clear, has a local image in
 // york_catalog OR brewster_catalog). york_catalog holds art for the archived York-branded line;
 // brewster_catalog holds it for the live Brewster/A-Street->Malibu line — every 'New' SKU is the
@@ -66,7 +67,8 @@ let onboardCand=[]; try{ onboardCand=q(`
  where coalesce(nullif(c.image_url,''), nullif(b.image_url,'')) is not null
    and lower(concat_ws(' ',n.pattern_name,n.product_name,n.book_name)) !~ 'banana|grape|bird|butterfly|palm|frond|leaf|leaves|foliage|botanical|floral|flower|tropical|jungle|vine|fern|bloom|garden|blossom|deciduous|egret|flamingo|crane|heron|peacock|feather'`)
    .split('\n').map(x=>x.trim()).filter(Boolean)
-   .map(l=>{const [s,pat]=l.split(String.fromCharCode(31)); return {s,pat:pat||''};}); }catch(e){}
+   .map(l=>{const [s,pat]=l.split(String.fromCharCode(31)); return {s,pat:pat||''};}); }
+catch(e){ console.error('FATAL: onboard-candidate query (york_master_aug2026 New + local image + settlement-clear) failed — refusing to proceed on empty onboard candidates, which would silently degrade onboard-ready to 0 with no signal. Aborting.',String(e.message||e).slice(0,160)); process.exit(1); }
 
 // 2. live Jeffrey Stevens
 let cur=null, reprice=[], disco=[], liveMfr=new Set(), liveTitles=new Map();
diff --git a/diag-brewster-images.mjs b/diag-brewster-images.mjs
index 316d579..d00a3b7 100644
--- a/diag-brewster-images.mjs
+++ b/diag-brewster-images.mjs
@@ -3,8 +3,8 @@
 // Token-overlap (not substring), accent-normalized, to avoid false pos/neg. READ-ONLY. $0 local.
 import { execSync } from 'node:child_process'; import fs from 'node:fs';
 // PG auth: read dw_admin's real password from secrets-manager/.env (same source as SHOPIFY_ADMIN_TOKEN); nothing exports PGPASSWORD and ~/.pgpass has no dw_unified/dw_admin line, so an inline empty PGPASSWORD= would silently fail auth.
-const PGPW=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^DW_ADMIN_PG_PASSWORD=(.+)$/m)||[])[1]?.trim();
-if(!PGPW){console.error('FATAL: DW_ADMIN_PG_PASSWORD missing from ~/Projects/secrets-manager/.env');process.exit(1);}
+let PGPW; try{ PGPW=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^DW_ADMIN_PG_PASSWORD=(.+)$/m)||[])[1]?.trim(); }catch(e){}
+if(!PGPW){console.warn('WARN: DW_ADMIN_PG_PASSWORD missing from ~/Projects/secrets-manager/.env — proceeding with empty PGPASSWORD (dw_admin on 127.0.0.1 is TRUST auth); the psql call will fail loudly if a password is truly required on this host.'); PGPW=''; }
 
 const q=sql=>{fs.writeFileSync('/tmp/_bdiag.sql',sql);return execSync(`/opt/homebrew/opt/postgresql@14/bin/psql -h 127.0.0.1 -U dw_admin -d dw_unified -tA -F'\x1f' -f /tmp/_bdiag.sql`,{encoding:'utf8',env:{...process.env,PGPASSWORD:PGPW}}).trim();};
 const norm=s=>String(s||'').normalize('NFD').replace(/[̀-ͯ]/g,'').toLowerCase();
diff --git a/recover-7-settlement.mjs b/recover-7-settlement.mjs
index 6881ba6..0115871 100644
--- a/recover-7-settlement.mjs
+++ b/recover-7-settlement.mjs
@@ -3,8 +3,8 @@
 // image by name-slug from brewster_catalog (their own row is corrupt), download for eyeball. READ-ONLY. $0.
 import fs from 'node:fs'; import { execSync } from 'node:child_process';
 // PG auth: read dw_admin's real password from secrets-manager/.env (same source as SHOPIFY_ADMIN_TOKEN); nothing exports PGPASSWORD and ~/.pgpass has no dw_unified/dw_admin line, so an inline empty PGPASSWORD= would silently fail auth.
-const PGPW=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^DW_ADMIN_PG_PASSWORD=(.+)$/m)||[])[1]?.trim();
-if(!PGPW){console.error('FATAL: DW_ADMIN_PG_PASSWORD missing from ~/Projects/secrets-manager/.env');process.exit(1);}
+let PGPW; try{ PGPW=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^DW_ADMIN_PG_PASSWORD=(.+)$/m)||[])[1]?.trim(); }catch(e){}
+if(!PGPW){console.warn('WARN: DW_ADMIN_PG_PASSWORD missing from ~/Projects/secrets-manager/.env — proceeding with empty PGPASSWORD (dw_admin on 127.0.0.1 is TRUST auth); the psql call will fail loudly if a password is truly required on this host.'); PGPW=''; }
 const q=sql=>{fs.writeFileSync('/tmp/_r7.sql',sql);return execSync(`/opt/homebrew/opt/postgresql@14/bin/psql -h 127.0.0.1 -U dw_admin -d dw_unified -tA -F'\x1f' -f /tmp/_r7.sql`,{encoding:'utf8',env:{...process.env,PGPASSWORD:PGPW}}).trim();};
 const norm=s=>String(s||'').normalize('NFD').replace(/[̀-ͯ]/g,'').toLowerCase();
 const STOP=new Set(['wallpaper','wallcovering','residential','wall','the','and','light','dark','off']);
diff --git a/recover-images-17.mjs b/recover-images-17.mjs
index c89be85..fe566c9 100644
--- a/recover-images-17.mjs
+++ b/recover-images-17.mjs
@@ -5,8 +5,8 @@
 // $0 local. Does NOT write to brewster_catalog (that DB-level relink is a separate gated job).
 import fs from 'node:fs'; import { execSync } from 'node:child_process';
 // PG auth: read dw_admin's real password from secrets-manager/.env (same source as SHOPIFY_ADMIN_TOKEN); nothing exports PGPASSWORD and ~/.pgpass has no dw_unified/dw_admin line, so an inline empty PGPASSWORD= would silently fail auth.
-const PGPW=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^DW_ADMIN_PG_PASSWORD=(.+)$/m)||[])[1]?.trim();
-if(!PGPW){console.error('FATAL: DW_ADMIN_PG_PASSWORD missing from ~/Projects/secrets-manager/.env');process.exit(1);}
+let PGPW; try{ PGPW=(fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8').match(/^DW_ADMIN_PG_PASSWORD=(.+)$/m)||[])[1]?.trim(); }catch(e){}
+if(!PGPW){console.warn('WARN: DW_ADMIN_PG_PASSWORD missing from ~/Projects/secrets-manager/.env — proceeding with empty PGPASSWORD (dw_admin on 127.0.0.1 is TRUST auth); the psql call will fail loudly if a password is truly required on this host.'); PGPW=''; }
 const slug=s=>String(s||'').toLowerCase().replace(/[^a-z0-9]+/g,'-').replace(/^-|-$/g,'').replace(/-wallpaper$/,'');
 // load every brewster_catalog image once: filename-slug -> url
 const out=execSync(`/opt/homebrew/opt/postgresql@14/bin/psql -h 127.0.0.1 -U dw_admin -d dw_unified -tA -F'|' -c "select image_url from brewster_catalog where image_url is not null and image_url<>''"`,{encoding:'utf8',env:{...process.env,PGPASSWORD:PGPW}}).trim();

← b984417 Fix broken PGPASSWORD psql auth in 6 scripts; read dw_admin  ·  back to York Reprice 2026 08  ·  auto-data-snapshot: 2026-09-15T19:39:01 (1 data files) — cad 8cd3aa3 →