{"slug":"new-import-viewer","total":42,"limit":100,"offset":0,"since":null,"commits":[{"hash":"8f6d032","date":"2026-07-13 14:55:46 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-13T14:55:38 (1 files) — package.json","body":""},{"hash":"3479a52","date":"2026-07-13 12:11:47 -0700","author":"Steve Abrams","subject":"similar-pattern search: per-card '≈ Similar' button → /api/similar proxy to all.dw (creds server-side) → scored live substitutes in an in-card panel","body":""},{"hash":"0250f13","date":"2026-07-09 09:08:42 -0700","author":"Steve","subject":"chore: lint (node --check ✓), v1.0.1 (session close)","body":""},{"hash":"ff72920","date":"2026-07-08 12:38:50 -0700","author":"Steve","subject":"new.: fill primary image from Shopify + full gallery (product_images) with hover-cycle","body":""},{"hash":"7582d03","date":"2026-07-03 08:08:07 -0700","author":"Steve","subject":"chore: macstudio3 migration — reconcile from mac2 + repoint paths (stevestudio2→macstudio3, node/npm/npx→/opt/homebrew)","body":""},{"hash":"e34ec31","date":"2026-07-02 17:51:37 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-02T17:51:29 (2 files) — public/index.html server.js","body":""},{"hash":"f65d9a6","date":"2026-07-02 08:40:52 -0700","author":"Steve","subject":"Grid UI upgrade: sortable list-view column headers (server-side sorts), density max 20, Safari user:pass@ fetch fix","body":"- Density slider max 10 → 20.\n- List view: sticky header row of 12 sortable column labels (vendor, pattern,\n  color, status, vendor SKU, DW SKU, collection, type, sync, shopify id,\n  first seen, last crawl) sharing ONE grid-template-columns rule with the row\n  cards so labels align with cells by construction. Click = asc, click again =\n  desc, ▲/▼ indicator; new list-only cells (.lcell) per field.\n- Sorting stays SERVER-side (grid paginates limit/offset — client-sorting the\n  loaded page would lie): extended the injection-safe SORTS whitelist in\n  server.js with asc/desc pairs for dwsku/collection/type/sync/shopid/status\n  (derived SHOP_STATUS CASE) + vendor/pattern/color/sku desc + firstseen_asc.\n- Safari creds fix: all fetch('/api/…') → fetch(location.origin+'/api/…') —\n  relative fetches break in WebKit on pages opened with user:pass@ URLs.\n- Presentational + sort wiring only; NO changes to arm-toggle / live-write /\n  stage-action machinery.\n- E2E-verified with Playwright on local :9790 against dw_unified: slider\n  max=20, header row renders + computed grid template matches row cards,\n  vendor asc→desc reorders, DW-SKU header reorders again, sticky on scroll,\n  0 console/page errors.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>"},{"hash":"d85bde7","date":"2026-06-19 10:02:18 -0700","author":"SteveStudio2","subject":"Retire new-import-viewer duplicate cadence plists — consolidating on Designer-Wallcoverings/shopify cadence-import.js (already publishes + uses shared variant budget)","body":""},{"hash":"4573e7c","date":"2026-06-19 09:43:46 -0700","author":"SteveStudio2","subject":"Add one-shot auto first-run (429-gated validated 42-batch + CNCP report + self-disable)","body":""},{"hash":"b4ec23e","date":"2026-06-19 09:32:57 -0700","author":"SteveStudio2","subject":"phase8-fix: real create+publish module (mirrors consumer.js 96cd954 publish-gap fix) + wiring patch for Kamatera full-monte","body":""},{"hash":"c345dc3","date":"2026-06-19 09:28:13 -0700","author":"SteveStudio2","subject":"cadence: hourly wrapper (run-cadence.sh, --limit 42 live+publish) + launchd plist (staged, not bootstrapped)","body":""},{"hash":"fb73edf","date":"2026-06-19 09:27:36 -0700","author":"SteveStudio2","subject":"cadence: manifest generator (42/batch, oldest-first round-robin, consumer-eligible, 3-source dedup-aware)","body":""},{"hash":"96cd954","date":"2026-06-19 09:18:08 -0700","author":"steve","subject":"consumer.js: fix publish gap (publishablePublish to Online Store) + add required Sample variant","body":"REST status:'active' never publishes to a sales channel — products landed on\nzero channels (publishedOnPublication=false). Add GraphQL publishablePublish to\nthe Online Store publication after each active create, plus the mandatory\n{DW_SKU}-Sample $4.25 variant. Drafts stay unpublished by design."},{"hash":"5a2715d","date":"2026-06-11 11:00:55 -0700","author":"SteveStudio2","subject":"snapshot: 9790 stats fix + required-indexes note","body":""},{"hash":"6e38f8b","date":"2026-06-11 10:39:53 -0700","author":"SteveStudio2","subject":"9790: document load-bearing dw_sku_registry functional index (replay on DB rebuild)","body":""},{"hash":"0d81ad3","date":"2026-06-11 10:39:22 -0700","author":"SteveStudio2","subject":"9790: fix /api/stats death-spiral — statement_timeout guard + non-blocking warmer","body":"Root cause: netnew count's NOT EXISTS vs dw_sku_registry had no functional\nindex (upper(trim(mfr_sku))) → seq scan → 75s+/never. Every page-load + the\nboot warmer fired it; runs piled up (13 stacked 18-43min), saturating PG into\na death spiral that froze the whole single-threaded server ('and loading').\n\nFix (this commit): PGOPTIONS statement_timeout=30000 on q()+qAsync so no query\ncan ever run away/pile up again; background stats warmer + STATS_CACHE serve\n/api/stats instantly.\nDB side (not in git): CREATE INDEX idx_registry_mfr_upper_trim ON\ndw_sku_registry (upper(trim(mfr_sku))) — drops the stats query to ~1.6s."},{"hash":"1fb9644","date":"2026-06-10 17:42:12 -0700","author":"SteveStudio2","subject":"new-import-viewer: enforce 3-source NEVER-DUPLICATE in net-new predicate + hard server-side stage gate","body":"NETNEW_PRED now NOT-EXISTS against dw_sku_registry as well as shopify_products\n(was shopify-only — 49,386 distinct mfr_skus were shopify-clean but already in\nthe 84k registry → would have imported as dups). Added dedupFilterIds() that\nre-validates every staged/live candidate row's mfr_sku against shopify_products\nAND dw_sku_registry on upper(trim()), dropping dups + un-dedupable rows, fail-safe\n(query error aborts the whole batch). Applied in /api/action before BOTH staging\nand live writes so a stale id list / raw curl can never push a known dup. /dtd-A 2026-06-10."},{"hash":"7be6207","date":"2026-06-10 08:22:33 -0700","author":"SteveStudio2","subject":"index.html review fixes: map Shopify lowercase status (active/draft/archived) → app vocabulary after live action (chip styled + Publish button disables correctly); show staged-so-far count in bulk error; only emit vendor link for http(s) urls (block javascript:/data: from scraped p.url)","body":""},{"hash":"01ee7be","date":"2026-06-10 08:21:02 -0700","author":"SteveStudio2","subject":"review fixes (3-agent panel): consumer atomic ledger-before-UPDATE (no orphaned creates→dup), images.length gate (no imageless products via non-http urls), dedup keyed on mfr-alone + sibling-row check (dup2) + self-sealing mirror insert + NULL-mfr skip, command54 HOLD pending brand ruling, private-label-no-mask skip, payload-wide command54 leak scan, consec-failure circuit breaker, skipped no longer blocks reprocess, per-manifest parse guard + action=launch assert, single-number parsePrice, .env-first precedence; server localhost bind + SSRF redirect:manual host-revalidation + numeric-host block, NETNEW upper(trim()) match, /api/ids real 250k cap; functional indexes idx_sp/vc_mfr_upper_trim (stats 60s→1s)","body":""},{"hash":"24a8d83","date":"2026-06-10 07:49:03 -0700","author":"SteveStudio2","subject":"launch-queue CONSUMER: manifested batches → Shopify draft products. DRY-RUN default; live needs LAUNCH_CONSUMER_LIVE=1 + --live (Steve gate). Per-product execution gates: image required, dw_sku+pattern required, fresh NEVER-DUPLICATE (mfr_sku vs shopify_products + in-run dedup + linked check), vendor_registry skip_shopify + private-label display names, cowtan denylist, status forced draft, 450/run hard cap (daily variant limit), 600ms throttle + 429 retry, idempotent ledger resume; writes linkage back to vendor_catalog on create","body":""},{"hash":"863ce65","date":"2026-06-10 07:38:45 -0700","author":"SteveStudio2","subject":"staging manifests: every batch persists full id/SKU manifest to data/launch-batches/ (queue lines were counts-only = un-actionable); superseded pre-gate count-only batches via queue marker; restaged ALL netnew gated: 120,991 staged with manifests, 8,221 no-image BLOCKED, cowtan_tout (8,312) excluded per Steve 'never'","body":""},{"hash":"4fb4e88","date":"2026-06-10 07:16:21 -0700","author":"SteveStudio2","subject":"HARD GATE: all products must have images (Steve 2026-06-10) — launch staging filters no-image rows server-side (single, bulk, raw API); launch buttons disabled on no-image cards with reason; bulk UI reports blocked count; non-launch actions unaffected","body":""},{"hash":"01963b9","date":"2026-06-10 07:11:35 -0700","author":"SteveStudio2","subject":"harden: noimage boot-trap defused (persisted diagnostic filter falls back to netnew) + /img local thumbnail proxy with disk cache + SSRF guard — grid no longer depends on 100+ vendor hosts hotlink policy","body":""},{"hash":"cd99729","date":"2026-06-10 06:25:49 -0700","author":"SteveStudio2","subject":"stage net-new for ALL vendors (101 vendors, 111,234 skus) to launch queue — draft, stage-only (no Shopify writes). Excluded: cowtan_tout (Steve 'never'), newwall+command54 (already staged). With newwall+command54 = 125,950 total net-new queued. NEVER-DUPLICATE: all pre-filtered against Shopify mfr_sku","body":""},{"hash":"a4c7ca5","date":"2026-06-09 20:35:02 -0700","author":"SteveStudio2","subject":"stage net-new for newwall (8485) + command54 (6231) to launch queue — draft mode, stage-only (no Shopify writes). command54 carries private-label rule (Phillipe Romano relabel at import)","body":""},{"hash":"58e24b2","date":"2026-06-09 19:26:54 -0700","author":"SteveStudio2","subject":"NET NEW by vendor panel: per-vendor breakdown (count + image coverage withImg/noImg) shown for netnew/new status, click-to-filter, image-% bar per vendor. /api/vendors now returns image coverage. Surfaces which vendors have importable net-new WITH images (e.g. hollywood 8997 100%, brewster_york 7772 94%)","body":""},{"hash":"bde393a","date":"2026-06-09 19:23:25 -0700","author":"SteveStudio2","subject":"NET NEW view: new MINUS already-on-Shopify (Steve: 'new - on shopify = new not on shopify'). NETNEW_PRED excludes any flagged-new row whose mfr pattern number already exists in shopify_products (index-friendly equality, 240ms). New default status + header pill + health-strip chip + dup-overlap warning. Found 62,030 'new' rows are actually already on Shopify -> true net-new 134,247 not 196,277","body":""},{"hash":"1833735","date":"2026-06-09 19:22:26 -0700","author":"SteveStudio2","subject":"Full action suite per chip + select 1→all: every card renders all 5 actions (disabled-with-reason; launch hard-disabled on linked rows = dup guard) + copy SKU/DW + vendor/admin/storefront links; visible 🕓 crawl date+time on grid cards; /api/ids endpoint + first-N / shown / ALL-matching selection; bulk staging chunks through the 5k cap (includes parallel-session netnew predicate)","body":""},{"hash":"b8c32b4","date":"2026-06-09 19:15:31 -0700","author":"SteveStudio2","subject":"Panel items B+D: No-image filter (12,156 rows) + structured empty state; threshold-colored catalog-health strip with click-to-filter quick chips","body":""},{"hash":"fe11c1f","date":"2026-06-09 18:59:42 -0700","author":"SteveStudio2","subject":"Panel item A: split details/actions into separate triggers — ⓘ details (read-only) vs ⚙ actions (write surface); browsing metadata never reveals a live button; actions chip reddens when armed","body":""},{"hash":"e4e0ced","date":"2026-06-09 18:45:48 -0700","author":"SteveStudio2","subject":"DTD-C: per-session arm toggle defaults OFF every load; live write now needs .env ceiling AND session-armed (arm:true). .env stays hard ceiling, bulk still stage-only","body":""},{"hash":"0d6de3d","date":"2026-06-09 18:39:35 -0700","author":"SteveStudio2","subject":"Apply design-agent critique: red danger treatment for live action buttons + armed top strip + pulsing LIVE badge, de-shout vendor labels, title hierarchy, two-column spec drawer","body":""},{"hash":"90782f6","date":"2026-06-09 18:13:00 -0700","author":"SteveStudio2","subject":"Refine: bulk forced stage-only (live single-card only), in-place chip+action refresh after live write, accurate live-vs-staged confirms, live result detail","body":""},{"hash":"16d4ca8","date":"2026-06-09 18:10:57 -0700","author":"SteveStudio2","subject":"Force live-write gate OFF by default (SHOPIFY_LIVE_WRITES master switch, stage-only); restore aligned CSS-grid list view; clear test launch-queue lines","body":"- /api/action stages to data/launch-queue.jsonl and never writes the store unless SHOPIFY_LIVE_WRITES=1 (default 0); .env ships gate=0, no live actions allow-listed\n- List view rebuilt as aligned CSS grid (display:contents on card body) so checkbox/thumb/vendor/pattern/status-chip/SKU/crawl columns line up across rows; full crawl date+time, ~54px rows; details drawer drops full-width below\n- indexed shopify_products join (gid built on vc side) keeps /api/stats sub-second\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"b2cb29b","date":"2026-06-09 18:09:33 -0700","author":"SteveStudio2","subject":"Wire live Shopify unpublish behind double gate (master switch + per-action allowlist); fix admin-link store handle to designer-laboratory-sandbox","body":""},{"hash":"d24c5ab","date":"2026-06-09 18:01:09 -0700","author":"SteveStudio2","subject":"Show full Shopify state (new/published/unpublished/archived) + staged action suite under collapsed per-card chips; indexed shopify_products join","body":""},{"hash":"af2b077","date":"2026-06-09 17:51:06 -0700","author":"SteveStudio2","subject":"snapshot before shopify-status + collapsed-chips rebuild","body":""},{"hash":"186111c","date":"2026-06-09 17:38:44 -0700","author":"SteveStudio2","subject":"viewer: add List view toggle (compact horizontal rows, persisted) alongside the card grid","body":""},{"hash":"039ba4a","date":"2026-06-09 16:38:00 -0700","author":"SteveStudio2","subject":"viewer: select-and-launch — per-product checkboxes, select-all, launch bar (draft/active) → /api/launch stages a batch (live Shopify push stays a separate gated step)","body":""},{"hash":"a368e81","date":"2026-06-09 15:54:55 -0700","author":"SteveStudio2","subject":"viewer: clean 'no image' placeholder on broken vendor image URLs (e.g. timorous logo-404 bug)","body":""},{"hash":"f6b1300","date":"2026-06-09 15:47:38 -0700","author":"SteveStudio2","subject":"fix: strip psql trailing newline from final field (stats newestCrawl + per-vendor crawled)","body":""},{"hash":"1a10b71","date":"2026-06-09 15:46:53 -0700","author":"SteveStudio2","subject":"new-import-viewer: agent + web viewer for products new-to-import (sync_status=new / not on Shopify)","body":"Zero-dep node+psql server over dw_unified.vendor_catalog. /api/stats, /api/vendors,\n/api/new-products (vendor filter + search + 7 sort modes + pagination). Viewer has\nthe mandatory sort select + density slider (localStorage-persisted) and the admin\ncrawl date+time chip per standing rules. Read-only; surfaces what the latest vendor\ncrawl flagged as NEW before any Phase-8 push. Port 9790.\n"}]}