[object Object]

← back to Designerwallcoverings

Stroheim onboard: read-only price/coverage canary (auto-resume signal on price-landing); DTD 3/2, launchd install deferred (gated)

eb3b88765727bfef8481a8560e780d71987c5a9a · 2026-07-26 16:48:38 -0700 · Steve Abrams

Files touched

Diff

commit eb3b88765727bfef8481a8560e780d71987c5a9a
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sun Jul 26 16:48:38 2026 -0700

    Stroheim onboard: read-only price/coverage canary (auto-resume signal on price-landing); DTD 3/2, launchd install deferred (gated)
---
 .gitignore                                |  1 +
 scripts/stroheim-onboard/price-canary.mjs | 56 +++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+)

diff --git a/.gitignore b/.gitignore
index ecfab95..d2fe66c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ dist/
 build/
 .next/
 uploads/
+scripts/stroheim-onboard/data/
diff --git a/scripts/stroheim-onboard/price-canary.mjs b/scripts/stroheim-onboard/price-canary.mjs
new file mode 100644
index 0000000..f7b19af
--- /dev/null
+++ b/scripts/stroheim-onboard/price-canary.mjs
@@ -0,0 +1,56 @@
+#!/usr/bin/env node
+/**
+ * Stroheim price/coverage canary — READ-ONLY. (DTD 3/2, yolo-plus 2026-07-26.)
+ *
+ * The onboard is complete but HELD on price (price_retail 100% NULL). This canary turns that
+ * indefinite external block into an auto-resume signal:
+ *   • detects the NULL→non-NULL transition on price_retail (price has LANDED → onboard can fire)
+ *   • reports coverage: staged · priced · minted (DWST) · drafts-on-Shopify
+ *   • classifies BLOCKED_NO_PRICE / READY_TO_ONBOARD / ONBOARDING / DONE
+ * Writes data/latest.json each run (heartbeat + prior state for transition detection).
+ *
+ * Pure reads against the local dw_unified mirror — no writes, no network, $0 (local).
+ * NOTE: this only runs when invoked (or by resume.sh); wiring a launchd schedule + CNCP/George
+ * alert is a SEPARATE gated step (scheduled-job install) — drafted, not installed here.
+ *
+ *   node price-canary.mjs          # print verdict + coverage, update data/latest.json
+ */
+import fs from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { execFileSync } from 'node:child_process';
+
+const HERE = path.dirname(fileURLToPath(import.meta.url));
+const DATA = path.join(HERE, 'data');
+fs.mkdirSync(DATA, { recursive: true });
+const LATEST = path.join(DATA, 'latest.json');
+const PSQL = '/opt/homebrew/opt/postgresql@14/bin/psql';
+const PGENV = { ...process.env, PGHOST: '/tmp', PGDATABASE: 'dw_unified' };
+const q = sql => execFileSync(PSQL, ['-d', 'dw_unified', '-tAc', sql], { env: PGENV, encoding: 'utf8' }).trim();
+
+const stats = JSON.parse(q(`SELECT json_build_object(
+  'staged',       count(*),
+  'priced',       count(*) FILTER (WHERE price_retail IS NOT NULL AND price_retail > 0),
+  'minted',       count(*) FILTER (WHERE proposed_dw_sku IS NOT NULL),
+  'on_shopify',   count(*) FILTER (WHERE on_shopify IS TRUE),
+  'net_new',      count(*) FILTER (WHERE dedup_status = 'net_new')
+)::text FROM stroheim_catalog`));
+
+let verdict;
+if (stats.priced === 0) verdict = 'BLOCKED_NO_PRICE';
+else if (stats.on_shopify === 0) verdict = 'READY_TO_ONBOARD';
+else if (stats.on_shopify < stats.priced) verdict = 'ONBOARDING';
+else verdict = 'DONE';
+
+const prior = fs.existsSync(LATEST) ? JSON.parse(fs.readFileSync(LATEST, 'utf8')) : null;
+const priceLanded = prior && prior.priced === 0 && stats.priced > 0;   // NULL→non-NULL transition
+
+const rec = { checked_at: new Date().toISOString(), verdict, ...stats,
+  coverage_pct: stats.priced ? Math.round((stats.on_shopify / stats.priced) * 100) : 0,
+  price_landed_transition: !!priceLanded };
+fs.writeFileSync(LATEST, JSON.stringify(rec, null, 2));
+
+const bar = { BLOCKED_NO_PRICE: '⛔', READY_TO_ONBOARD: '🟢', ONBOARDING: '🔄', DONE: '✅' }[verdict];
+console.log(`${bar} Stroheim ${verdict} · staged ${stats.staged} · priced ${stats.priced} · minted ${stats.minted} · on-Shopify ${stats.on_shopify} (${rec.coverage_pct}%)`);
+if (priceLanded) console.log(`  🔔 PRICE LANDED (was NULL) — run resume.sh to fire the onboard (mint → build → gate → create-drafts).`);
+if (verdict === 'BLOCKED_NO_PRICE') console.log(`  waiting on Steve: populate stroheim_catalog.price_retail (trade-login scrape or cost-map).`);

← 07f745c Stroheim onboard: add settlement-gate + go-live (Steve-gated  ·  back to Designerwallcoverings  ·  stout-onboard: fix stale docs — double-roll (not single), Ge 16717b2 →