{"slug":"all-designerwallcoverings","total":104,"limit":100,"offset":0,"since":null,"commits":[{"hash":"09077cc","date":"2026-07-27 15:21:39 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-27T15:21:37 (1 files) — package-lock.json","body":""},{"hash":"699a5fd","date":"2026-07-27 15:13:57 -0700","author":"Steve Abrams","subject":"chore: v1.7.0 — async job+poll live-check feature (session close)","body":"Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"26c4bba","date":"2026-07-27 15:05:58 -0700","author":"Steve","subject":"astek CF-Access: env-gated service-token headers on crawler + feed proxy (TK-11, memo 260727A)","body":"Inert/byte-identical (Basic-Auth-only) until CF_ACCESS_ASTEK_ID/SECRET are set;\nscoped to astek.designerwallcoverings.com only. Deploy to Kamatera stays gated."},{"hash":"ae33f6d","date":"2026-07-27 14:51:28 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-27T14:51:27 (1 files) — server.js","body":""},{"hash":"76b0372","date":"2026-07-27 14:45:14 -0700","author":"Steve","subject":"all.dw: raise live-scrape worker timeout 52s->75s (async/poll decoupled from proxy cap; genuine ~63s scrapes now complete)","body":""},{"hash":"ad479fd","date":"2026-07-27 14:39:37 -0700","author":"Steve Abrams","subject":"all.dw: async job+poll for metered live check (never 504s the proxy)","body":"DB_AUTHORITATIVE (Kravet) tier stays fully synchronous (instant local PG read,\nreturns status:done inline). Browserbase tiers now fire-and-poll: the initiating\nrequest starts the scrape WITHOUT awaiting it and returns status:pending\nimmediately (well under the ~60s Cloudflare/nginx proxy cap), so slow portals\n(WallQuest/Romo ~63s) can no longer 504. Spend-accrual + result caching moved\ninto the background .then(); .catch caches an error result so a later poll\nresolves cleanly and no unhandled rejection can occur. Front-end polls\nlivestock?...&poll=1 every poll_after_ms (max ~30 polls/~90s), renders on\nstatus:done, falls back to the Email-Vendor copy on status:gone/exhaustion.\nLIVE_WORKER made env-overridable for mocked local verification.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"fde98d3","date":"2026-07-23 12:20:58 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-23T12:20:57 (1 files) — server.js","body":""},{"hash":"eb95b2f","date":"2026-07-16 17:13:52 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-16T17:13:50 (1 files) — package-lock.json","body":""},{"hash":"9d4985f","date":"2026-07-16 17:06:24 -0700","author":"Steve Abrams","subject":"chore: v1.6.1 (session close — lint ✓ clean, refactor ✓ no-change, code verified clean as shipped)","body":""},{"hash":"763b16b","date":"2026-07-16 17:04:16 -0700","author":"Steve Abrams","subject":"Keep Schumacher visible on all-dw (internal 401-gated aggregator, Steve OK 2026-07-16); revert schumacher from BANNED — private-label vendor names stay banned","body":""},{"hash":"c3f43e4","date":"2026-07-16 16:43:47 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-16T16:43:46 (1 files) — data/live-stock-coverage.json","body":""},{"hash":"1e3c12a","date":"2026-07-16 16:36:07 -0700","author":"Steve Abrams","subject":"Kravet dash→dot W-code match: Shopify stores wallcovering codes dash-form (W3909-50), price file dot-form (W3909.50.0) — add the conversion to kravet-db candidateKeys + coverage counter. Kravet resolvable 840→2250 (32%→86%), ~1,410 more SKUs priced $0","body":""},{"hash":"fc6f2ba","date":"2026-07-16 10:34:22 -0700","author":"Steve","subject":"all-dw: add schumacher to BANNED regex (internal-only vendor)","body":"Schumacher is INTERNAL-ONLY (Steve 2026-07-16). BANNED already drops private-label\nupstream names from the public search grid + microsite directory; adding schumacher\nfilters any Schumacher product row AND the internal.schumacher / schumacher microsite\ntiles from this aggregator. Local commit only — deploy to the gated public surface\nstays Steve-gated per this repo's CLAUDE.md.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>"},{"hash":"81aa19f","date":"2026-07-15 17:44:25 -0700","author":"Steve Abrams","subject":"Live-scrape 504 fix: kill scrape at 52s (below the 60s CF/nginx proxy cap) → honest in-app 'timed out — use Email Vendor' JSON instead of a raw gateway 504; document the 3-step Kravet prod light-up recovery in build-coverage.js","body":""},{"hash":"8a79e7b","date":"2026-07-15 16:42:45 -0700","author":"Steve Abrams","subject":"Backfill mfr_sku for 163 mfr-less Kravet-family SKUs at $0 (title-exact + price-consensus tiers, local-model tier for residual honestly declines no-signal cases) — kravet_mfr_backfill table wired into grid loader, kravet-db adapter, coverage counter; Kravet resolvable 840→1003","body":""},{"hash":"3658c7c","date":"2026-07-15 16:38:38 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-15T16:38:37 (4 files) — scripts/adapters/kravet-db.js scripts/build-coverage.js server.js scripts/backfill-kravet-mfr.js","body":""},{"hash":"c5afd0d","date":"2026-07-15 14:39:50 -0700","author":"Steve Abrams","subject":"contrarian fixes: price-only live result gets neutral dot + 'availability unknown — price file only' disclosure + human tooltip; STOCK lookup falls back to -Sample-stripped key","body":""},{"hash":"add8bb3","date":"2026-07-15 14:34:37 -0700","author":"Steve Abrams","subject":"coverage hot-reload: re-read live-stock-coverage.json on mtime change (10-min check) so regenerated coverage flows without a pm2 restart","body":""},{"hash":"750e7f4","date":"2026-07-15 14:31:33 -0700","author":"Steve Abrams","subject":"Every SKU card gets a smart face button: live price check (tier-labeled cost) → stored stock → Email Vendor fallback; shared per-card popovers + price-forward live render","body":""},{"hash":"f9158ab","date":"2026-07-15 14:18:28 -0700","author":"Steve Abrams","subject":"Kravet family gets a $0 authoritative-price live check (kravet-db adapter, DB_AUTHORITATIVE tier)","body":"- new scripts/adapters/kravet-db.js: resolves the grid SKU's mfr code and answers from\n  dw_unified.kravet_authoritative_pricing with the MAP retail (new_map, else whls x 1.5 derived);\n  session_opened:false so nothing bills; wholesale never emitted\n- live-scrape.js: DB adapters run without the Browserbase lib (only session adapters need it)\n- server.js: session_opened:false success -> cost 0, no ledger/live-spend entry; DB_AUTHORITATIVE\n  tier exempt from the daily $-cap only (per-IP + inflight limits still apply)\n- build-coverage.js: KRAVET_FAMILY -> DB_AUTHORITATIVE first-branch, kapMatchCount resolvability\n  gate, Kravet removed from NO_LIVE_STOCK_PORTAL; coverage regenerated (12 vendors in tier,\n  7 live-capable: Brunschwig 2636, Gaston 2142, Lee Jofa 2110, Cole & Son 1236, GP&J Baker 1185,\n  Kravet 840, Threads 69)"},{"hash":"016fb39","date":"2026-07-15 13:57:41 -0700","author":"Steve Abrams","subject":"chore: vendor_contacts self-heal DDL, microsites compose validation, v1.6.0 (session close)","body":""},{"hash":"3fa3f9f","date":"2026-07-15 13:33:23 -0700","author":"Steve Abrams","subject":"Email Vendor everywhere: stock & price inquiry compose on every product card + microsite card — /api/vendor-contact + /api/vendor-inquiry (vendor_contacts upsert + George Gmail DRAFT, never auto-send, mailto fallback)","body":""},{"hash":"9317a40","date":"2026-07-14 13:25:11 -0700","author":"Steve","subject":"chore: v1.5.0 (session close — pm2 viewer auto-discovery + /api/skus feed)","body":""},{"hash":"80c128c","date":"2026-07-14 13:11:20 -0700","author":"Steve Abrams","subject":"Auto-discover all co-located pm2 vendor viewers + read /api/skus feed → 49→156 vendors live in all.dw (fulfills 'every vendor viewer must be live'); private-label sources stay BANNED","body":""},{"hash":"2a6cffc","date":"2026-07-14 13:08:38 -0700","author":"Steve","subject":"chore: v1.4.1 (session close) — vendor facet alpha-sort","body":""},{"hash":"ce9854c","date":"2026-07-14 11:19:49 -0700","author":"Steve","subject":"all.dw: vendor facet sorts alphabetically by name on load (was by count)","body":""},{"hash":"7e64421","date":"2026-07-14 09:53:02 -0700","author":"Steve Abrams","subject":"Contrarian fixes: scope crawler cred to internal hosts only; correct zuber-internal note :10105; de-mislead quadrille internalViewer (public-served)","body":""},{"hash":"26c1985","date":"2026-07-14 09:48:55 -0700","author":"Steve Abrams","subject":"Crawler: derive membership handle + title from mfr_sku/pattern_name when feed omits them (fixes gracie/zuber 0-count)","body":""},{"hash":"22ee077","date":"2026-07-14 08:11:32 -0700","author":"Steve Abrams","subject":"Fix crezana internalViewer port 10104->10106; vendor-name fallback for gated 401 directory titles","body":""},{"hash":"f5cefcb","date":"2026-07-13 14:38:36 -0700","author":"Steve","subject":"chore: v1.4.0 — similar-pattern search feature (session close)","body":""},{"hash":"80f0bae","date":"2026-07-13 09:35:12 -0700","author":"Steve Abrams","subject":"disco banner: 'search the catalog' is now a button — /api/similar scores live substitutes (material/style/color/type/vendor/title-token) and renders matched cards below the banner","body":""},{"hash":"301550f","date":"2026-07-09 22:42:32 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-09T22:42:31 (2 files) — data/vendors.json scripts/__pycache__/","body":""},{"hash":"1fa387b","date":"2026-07-09 22:29:26 -0700","author":"steve","subject":"internal category: plug 3 front-facing leaks — build-data.py vendor directory drops internal, /api/vendors+/api/microsites Cache-Control private no-store, microsite external URL suppressed for internal (contrarian FIX-FIRST)","body":""},{"hash":"f37876c","date":"2026-07-09 22:12:25 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-09T22:12:24 (1 files) — server.js","body":""},{"hash":"9d3836e","date":"2026-07-09 16:38:57 -0700","author":"Steve","subject":"microsite crawler: seed from Cloudflare zone (authoritative, self-completing) + register -internal viewers","body":"- add cfZoneSubdomains() 3rd seed source: fetch all A/CNAME for zone e4b88c70,\n  derive <sub>.designerwallcoverings.com, merge with known+DB seeds (dedup)\n- guarded: missing token / CF failure logs a warning + falls back to existing seeds\n- denylist _-prefixed / _domainconnect / _dmarc / apex; www kept out (apex dup)\n- token via env (CLOUDFLARE_API_TOKEN) + MICROSITE_CF_ZONE default = the zone\n- register fromental/crezana/gracie/zuber -internal viewers in internal[]\n- fix stale internalViewer ports 10071-10074 -> real Kamatera 10103-10106\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"c22ea62","date":"2026-07-09 16:20:45 -0700","author":"Steve","subject":"all.dw: make microsite feed ports env-overridable (MICROSITE_FEED_PORTS)","body":"Prod's co-located internal viewers listen on different localhost ports than Mac2\ndev (prod: fromental=10103/gracie=10104/zuber=10105/crezana=10106; dev defaults\n10071/10073/10074/10072). Drive the per-line feed port from MICROSITE_FEED_PORTS\n(\"slug=port,...\"), falling back to the dev default so behavior is unchanged when\nunset. Keeps the ingest portable across environments without hardcoding prod ports.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"b2fc39c","date":"2026-07-09 16:17:55 -0700","author":"Steve","subject":"all.dw: surface 4 luxury lines (Fromental/Gracie/Zuber/Crezana) via microsite full-feeds","body":"Ingest the FULL /api/products feed of the 4 DW-family microsites over localhost\n(bypassing the public 401 with the shared internal cred), normalize each feed's\nheterogeneous shape to the grid row shape (colors/styles/materials via the same\ntag lexicons, quote->null price), tag source='microsite', dedupe by vendor+handle,\nand append to ROWS at each snapshot cycle. No Shopify import, no dw_unified write.\nAdditive + guarded: a failed feed keeps the prior cycle's rows for that line.\nVerified locally: /api/facets vendor = Fromental 735 / Gracie 150 / Zuber 192 /\nCrezana Design 443; products filter + color/style facets cross-filter; internal\n/api/catalog-full unaffected (0 microsite rows).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"5def1fd","date":"2026-07-09 09:37:54 -0700","author":"steve","subject":"all.dw: register Fromental/Gracie/Zuber/Crezana brands (onboarding/staging, quote-only, import+deploy gated)","body":""},{"hash":"cdc1dcf","date":"2026-07-09 09:08:41 -0700","author":"Steve","subject":"chore: lint (node --check ✓), v1.3.0 (session close)","body":""},{"hash":"287e09e","date":"2026-07-08 15:19:39 -0700","author":"Steve Abrams","subject":"Designtex dw_sku backfill on mac3 CANONICAL dw_unified: provenance note (288 rows, artifacts durable on-disk, gitignore honored)","body":"Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"fe345ea","date":"2026-07-08 12:34:14 -0700","author":"Steve","subject":"all. cards: gallery count badge + hover-cycle through full Shopify image set","body":""},{"hash":"08c6237","date":"2026-07-08 12:32:55 -0700","author":"Steve","subject":"Full Shopify image galleries: bulk-sync product_images + serve images[] in feed","body":"- scripts/shopify-images-sync.mjs: Shopify Bulk Operations export of every non-archived\n  product's full image set -> dw_unified.product_images (201,568 images / 87,599 products)\n- server.js: load product_images by product_id, add images[] + image_count to every row,\n  gap-fill the primary image from the gallery when featured image_url is null\n- flows to /api/catalog-full so all./substitute/new inherit galleries; No-image dropped to 477"},{"hash":"75328f4","date":"2026-07-08 12:24:32 -0700","author":"steve@designerwallcoverings.com","subject":"all.dw grid: manufacturer-SKU search — backfill mfr_sku from *_catalog tables (sync leaves shopify_products.mfr_sku empty for new lines); feeds mfr_number display + search haystack","body":""},{"hash":"de111d4","date":"2026-07-08 12:06:11 -0700","author":"Steve","subject":"shopify-push: portable Shopify-lib resolution (env/mac3/co-located) for deploy safety","body":""},{"hash":"25613cb","date":"2026-07-08 12:01:50 -0700","author":"Steve","subject":"List view: add Mfr # column with DW·Shop·FM mismatch breakout","body":""},{"hash":"d3b82a5","date":"2026-07-08 11:33:22 -0700","author":"Steve","subject":"Mismatch chip: show DW number alongside Shopify + FileMaker mfr numbers","body":""},{"hash":"f088c73","date":"2026-07-08 11:07:37 -0700","author":"Steve Abrams","subject":"chore: v1.1.0 → v1.2.0 (session close — feed + discontinued-successor features)","body":""},{"hash":"8ed57a0","date":"2026-07-08 11:03:12 -0700","author":"Steve","subject":"FileMaker WALLPAPER as source of truth across all./substitute/photo","body":"- scripts/fm-wallpaper-sync.mjs: mirror FileMaker WALLPAPER (Shopify Detail layout,\n  clean-query rule, Record Type=Master) into dw_unified.filemaker_wallpaper\n- server.js: LEFT-JOIN the mirror by dw_sku -> fm_mfr_number, fm_discontinued,\n  fm_width, fm_specs, mfr_mismatch; hide FMPro-discontinued by default (union);\n  FM stats on /healthz + /api/facets; fields flow to /api/catalog-full (substitute+photo)\n- public/index.html: show both mfr numbers with mismatch flag, FM specs on cards,\n  FM header chip + Mismatches/Show-FM-disco toggles + bulk Preview-sync modal,\n  per-card Update Shopify button (dry-run)\n- scripts/shopify-push.mjs: FileMaker->Shopify diff engine (name/mfr/width/specs);\n  writes only non-empty changed fields, never downgrades richer Shopify data, never\n  pushes a name into the mfr field; commit gated behind SHOPIFY_PUSH_ENABLED"},{"hash":"55b78db","date":"2026-07-08 10:59:46 -0700","author":"Steve","subject":"Add /api/discontinued + red successor banner: dead/archived SKU resolves (dash/-SAMPLE insensitive) → links live successor","body":""},{"hash":"ecdf294","date":"2026-07-08 10:35:16 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-08T10:35:15 (1 files) — scripts/fm-wallpaper-sync.mjs","body":""},{"hash":"949b520","date":"2026-07-08 09:18:35 -0700","author":"Steve Abrams","subject":"Stop tracking data/backfills/ ops artifacts; gitignore the dir (repo hygiene)","body":""},{"hash":"2ac9b38","date":"2026-07-08 09:16:36 -0700","author":"steve","subject":"all.dw internal tool: default scope = all-but-archived (incl. Staged/DRAFT); fold DELETED_FROM_SHOPIFY into Archived","body":""},{"hash":"02ea04b","date":"2026-07-08 09:11:30 -0700","author":"Steve","subject":"env-ify Basic-Auth: support BASIC_AUTH_USER/PASS, default unchanged (admin:DW2024!)","body":""},{"hash":"7d0202a","date":"2026-07-08 09:06:32 -0700","author":"steve","subject":"Enable Designtex live-stock (13→14): drop from SCHEMA_PARSE_PENDING after dw_sku backfill","body":"build-coverage.js: Designtex removed from SCHEMA_PARSE_PENDING (it was the only\nblocker) and given a VERIFIED entry; it now takes the enabled schema-public path and\nclears the resolvability gate 417/417 (100%). Coverage rebuilt on prod against the\nKamatera dw_unified (the DB the aggregator loads) → live-capable 14, all 13 prior\nvendors intact. Designtex proven live on prod: DWDX-220000 → in_stock:true via\nschema-public-live (login-free, $0.03), kill-switch counter incremented. pm2\nrestarted to load the fresh coverage."},{"hash":"005a048","date":"2026-07-08 09:04:56 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-08T09:04:55 (1 files) — scripts/build-coverage.js","body":""},{"hash":"f78c637","date":"2026-07-08 09:01:29 -0700","author":"Steve","subject":"Document targeted-rsync deploy guardrail (no full-tree --delete on this repo)","body":""},{"hash":"104aa8f","date":"2026-07-08 09:00:49 -0700","author":"steve","subject":"Designtex dw_sku backfill on Kamatera dw_unified: backup + rollback artifacts","body":"Wrote authoritative DWDX/DWAH dw_sku into 417 active Designtex rows in shopify_products\n(base(variant_sku)=designtex_catalog.dw_sku, 1:1, 0 unmatched, 0 ambiguous). dw_sku ONLY;\nmfr_sku/variant_sku/sku untouched; 0 non-Designtex rows touched. Target = the LOCAL\nKamatera dw_unified the live aggregator loads (repl_user reads it; write ran as table\nowner dw_admin via .pgpass). Reversible: on-DB _backup_designtex_dwsku_20260708 +\ndata/backfills/*.jsonl + ROLLBACK.sql."},{"hash":"aa87b85","date":"2026-07-08 09:00:14 -0700","author":"Steve Abrams","subject":"add internal /api/catalog-full feed (every non-archived SKU, leak-sanitized, product_id/handle/tags) for substitute + photo apps","body":""},{"hash":"5dfa17e","date":"2026-07-08 08:58:11 -0700","author":"Steve","subject":"deploy: infinite-scroll fix (5cdaf8a) live to all.designerwallcoverings.com (targeted public/index.html)","body":""},{"hash":"053a837","date":"2026-07-08 08:57:28 -0700","author":"steve","subject":"Deploy staged +Koroseal live-stock build to prod (Kamatera 45.61.58.125)","body":"Targeted rsync of scripts/adapters/ + build-coverage.js + live-stock-coverage.json,\npm2 restart --update-env. Smoke: healthz=200, root=401, microsites=200.\nKoroseal DWK-29052 authed live scrape on prod → in_stock:true, price:null,\nsource=koroseal-live, $0.17 (Browserbase 1.16 session_min), kill-switch counter\nincremented (live-spend.json 2026-07-08:0.1739, cap $5). 13 live vendors confirmed."},{"hash":"5cdaf8a","date":"2026-07-08 08:47:36 -0700","author":"Steve","subject":"Fix stuck infinite scroll: pump on live sentinel geometry, not stale observer flag","body":""},{"hash":"59f752c","date":"2026-07-07 20:32:37 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-07T20:32:33 (2 files) — config/known-subdomains.json scripts/crawl-microsites.js","body":""},{"hash":"27f01e1","date":"2026-07-07 16:53:09 -0700","author":"Steve","subject":"Koroseal live-proven: reject synthesized catalog URLs (false-discontinued fix) + record verification","body":"- koroseal.js: accept only a REAL catalog product_url, never resolve.js's shape-general synthesized template guess (which substituted a spec mfr code into a digital-lab pattern-slug URL -> bogus 404 -> false discontinued). Prefer koroseal.js's own mfr-code reconstruction.\n- Proven live: DWK-29052 Available (live 200 PDP) / DWK-32619 Discontinued (302->/NotFound), price:null, $0.03 each\n- build-coverage VERIFIED note for Koroseal"},{"hash":"1aabc95","date":"2026-07-07 16:44:27 -0700","author":"Steve","subject":"Integrate 5 vendor live-stock adapters: enable Koroseal (liveness), dim Designtex/Schumacher/Fabricut/Contrado honestly","body":"- Register koroseal/designtex/schumacher/fabricut/contrado in adapters/index.js\n- resolve.js: shape-general template-learning fallback (additive; only ADDS matches after a product_url miss, needs a recovered mfr_sku)\n- koroseal.js: recover mfr_sku from shopify_products before URL reconstruction (server passes dw_sku, reconstruction keys on mfr code)\n- build-coverage.js: LIVENESS_ADAPTERS (Koroseal, mfr-key resolvability gate, honest Available/Discontinued label); WIRED_DIM (Schumacher quote-only / Fabricut too-small / Contrado made-to-order); Designtex honest-dim (grid rows carry no SKU key)\n- live count 12 -> 13 (+Koroseal); all 12 prior live vendors retained (no regression)"},{"hash":"050399a","date":"2026-07-07 16:40:47 -0700","author":"steve@designerwallcoverings.com","subject":"all.dw: register Pierre Frey Fabrics microsite (pierrefreyfabrics, distinct vendor label so no dedup-merge with wallcovering pierre-frey)","body":""},{"hash":"acfd50a","date":"2026-07-07 15:26:26 -0700","author":"steve@designerwallcoverings.com","subject":"all.dw infinite-scroll: robust pump loop (keep loading while sentinel visible) fixes 'scroll for more' stall when a load is in-flight as user reaches bottom (IntersectionObserver only fires on transition)","body":""},{"hash":"9759482","date":"2026-07-07 13:49:14 -0700","author":"steve@designerwallcoverings.com","subject":"crawler: read co-located Basic-Auth-gated microsite feeds via localhost internalViewer (bypass 401, no credential) + optional MICROSITE_BASIC_AUTH; Pierre Frey now shows 1161 on all.dw","body":""},{"hash":"3340f23","date":"2026-07-07 13:35:39 -0700","author":"Steve","subject":"live-stock: enable Thibaut in coverage (vault-cred proof landed on prod)","body":"Proof (prod 2026-07-07): /api/livestock?sku=DWTT-70471-SAMPLE&live=1 →\nin_stock:true, source:thibaut-live (real logged-in scrape, not a degrade), price:null\n(public-safe), cost $0.1596; daily kill-switch $0.0605→$0.2201. Creds resolved from\ndw-price-stock/.env by path — never copied into this repo or dw_unified."},{"hash":"a35f788","date":"2026-07-07 13:26:21 -0700","author":"Steve","subject":"live-stock: vault-cred adapter for Thibaut (creds referenced in place from dw-price-stock/.env)","body":"- scripts/adapters/creds.js: vault-first cred resolver (dw-price-stock/.env by path via\n  DW_PRICE_STOCK_ENV), registry fallback; values never logged/copied\n- scripts/adapters/thibaut.js: Thibaut trade-portal live-stock adapter (Shopify storefront,\n  #email/#password login), PUBLIC-SAFE availability only, price null\n- scripts/adapters/index.js: register thibaut\n- scripts/build-coverage.js: VAULT_PORTAL_ADAPTERS map + classify branch (Thibaut only),\n  subject to the resolvability gate; placed before the public-Shopify branch (stock is trade-gated)\n- docs/live-stock-creds-in-place.md: design note + 8-vendor feasibility + Steve-gated expansion plan"},{"hash":"9c2f43a","date":"2026-07-07 13:12:36 -0700","author":"steve@designerwallcoverings.com","subject":"all.dw: dedupe microsite seeds by vendor (fold DB auto-slug into registry brand slug); point Pierre Frey at live hyphenated host pierre-frey (401 gated)","body":""},{"hash":"d0fcf53","date":"2026-07-07 13:10:20 -0700","author":"Steve","subject":"chore: lint + light refactor (shared adapter helpers, named consts) + v1.1.0 (session close)","body":""},{"hash":"d537f75","date":"2026-07-07 13:09:58 -0700","author":"steve@designerwallcoverings.com","subject":"all.dw: register Pierre Frey microsite (slug pierrefrey, wave-19 samples viewer, staged/launch-gated)","body":""},{"hash":"77f866b","date":"2026-07-07 12:53:49 -0700","author":"Steve","subject":"live-stock: structured-only availability vote (kills Osborne discontinued-banner false-OOS) + Magento tocart/title CTA read; stamp DG/Marburg/Osborne live-verified","body":""},{"hash":"0ccd9b9","date":"2026-07-07 12:46:24 -0700","author":"Steve","subject":"live-stock: tune schema-public for Designers Guild + Marburg, remap Osborne SKUs, AS Creation honest-dim (8→11 live vendors)","body":""},{"hash":"3790ba8","date":"2026-07-07 10:21:32 -0700","author":"Steve","subject":"live-stock verify: 4 NEW vendors live-verified via schema-public (Mind the Gap/Graham & Brown/Innovations USA/Rebel Walls, in_stock:true, $0.03 ea) — live_capable 4→8, all verified; harden schema-public to read Magento microdata href; AS Creation/Designers Guild/Marburg kept wired-but-dim (JS-rendered availability, parse pending) rather than burn sessions for unknown; total verify spend $0.247 logged to cost-tracker","body":""},{"hash":"d1be0d2","date":"2026-07-07 10:15:28 -0700","author":"Steve","subject":"live-stock: generic schema-public adapter (login-free schema.org/Magento availability) + reclassify 7 mis-tiered PORTAL_NO_CREDS vendors whose anonymous PDPs expose stock — AS Creation, Designers Guild, Graham & Brown, Innovations USA, Marburg, Mind the Gap, Rebel Walls now live-capable (resolvability-gated); Kravet honestly dimmed 'portal does not expose live stock (price sheet only)'; live-capable 4→11","body":""},{"hash":"2c397b4","date":"2026-07-07 10:06:41 -0700","author":"Steve","subject":"live-stock: daily $ kill-switch — global per-day spend ceiling (DAILY_LIVE_CAP_USD, default $5) persisted to data/live-spend.json, survives pm2 restart; live path hard-stops at $0 before any Browserbase session once the day's total hits the cap; day_spend+cap surfaced on every metered response; align findRowBySku with the grid's dw_sku-first identity so live checks actually resolve","body":""},{"hash":"875d338","date":"2026-07-07 09:38:28 -0700","author":"Steve","subject":"live-stock verification: 4 metered scrapes ($0.234 total) prove wallquest+shopify-public+romo adapters return live stock; harden romo nav-chrome parse; record per-vendor verified status in coverage","body":""},{"hash":"5d8857a","date":"2026-07-07 09:34:37 -0700","author":"Steve","subject":"adapters: shared grid-SKU→catalog resolver (bridge via shopify_products mfr_sku/dw_sku) so shopify-public/romo/woo actually resolve display SKUs","body":""},{"hash":"803861a","date":"2026-07-07 09:32:26 -0700","author":"Steve","subject":"coverage: resolvability gate — only ENABLE live-capable vendors whose display SKUs actually align with the catalog (drops PS Removable/Nina/Hygge false-enables); 4 genuinely-usable","body":""},{"hash":"af39b75","date":"2026-07-07 09:28:56 -0700","author":"Steve","subject":"live-stock adapter framework: generalized per-vendor registry (wallquest/romo/shopify-public/woo-public), coverage-driven enable+dim, live-scrape.js dispatcher","body":""},{"hash":"93e37e2","date":"2026-07-07 09:23:12 -0700","author":"Steve","subject":"live-stock coverage audit: classify all 254 display-vendors into feasibility tiers (data/live-stock-coverage.json + scripts/build-coverage.js)","body":""},{"hash":"8c24b22","date":"2026-07-07 08:39:43 -0700","author":"Steve Abrams","subject":"all-dw: show Mfr # (mfr_sku) + Mfr Name (supplier_name) as card fields","body":"Adds two toggleable card fields to the product grid, rendered only when\npresent. Server ships mfr_number/mfr_name in the payload and folds mfr_sku +\nsupplier_name into the search haystack; client registers them in FIELD_DEFS\nwith the h-mfrn/h-mfrname visibility system and renders them between\nVendor·Type and the facet chips. Verified against the DWQW-61447/61443 Adorn\ncards (Mfr # NE50608 / NE50508)."},{"hash":"94d8f0a","date":"2026-07-07 08:31:33 -0700","author":"Steve","subject":"This Item deep-link: capture full per-microsite handle set + resolve by membership (kills ~15-25% dead-ends)","body":""},{"hash":"9769200","date":"2026-07-07 08:21:43 -0700","author":"steve","subject":"all-dw This Item: suppress deep-link for broken/empty vhosts (VENDOR_ITEM excludes up-but-0-product microsites). Partial fix — per-product handle divergence (dw handle != microsite SPA handle) still limits reliability; deploy HELD per yolo final DTD","body":""},{"hash":"435af85","date":"2026-07-07 08:18:06 -0700","author":"Steve Abrams","subject":"livestock: self-contained Browserbase backend (lib/romo-lib.js) so prod can run live checks without the skills dir","body":""},{"hash":"bbcfd96","date":"2026-07-07 08:08:06 -0700","author":"Steve Abrams","subject":"livestock: one-click 'Check Live 🔄' — metered vendor-portal scrape endpoint + card control","body":"/api/livestock?sku=&live=1 spawns scripts/live-scrape.js (reuses browserbase romo-lib\nsession helper + documented WallQuest portal login), returns PUBLIC-SAFE availability +\nour-retail price only (never cost/net). Self-gates to wired adapters (Malibu/PS Removable\n-> WallQuest); dims for all others. 10-min per-SKU cache, concurrent-click coalescing,\nper-IP + global-burst rate limits. Free stored-snapshot path stays $0. Card shows live\nresult + actual $ cost (or 'cached · $0'). Proven once live: DWQW-58220 OutOfStock, $0.0975 (logged)."},{"hash":"ef3b79c","date":"2026-07-07 07:59:02 -0700","author":"steve","subject":"all-dw chips: add 'This Item ↗' link — internal microsite product page (/product/<handle>) for the single item, distinct from 'Line Viewer' (whole line)","body":""},{"hash":"9ca2518","date":"2026-07-07 07:37:03 -0700","author":"Steve","subject":"internal: expand per-card Internal into Admin / Line Viewer / Check Stock grouped control","body":"Server resolves two new public-safe side-channels per SKU: line_viewer_url (the\nvendor's live microsite from the crawl artifact = its internal astek-style line\nviewer) and stock (the FREE stored /livestock snapshot — in_stock/qty/lead/as-of\nfrom stock_checks ∪ every *_catalog in_stock/last_scraped; cost & price never\nselected). Grid card + list row now show Website + an 'Internal ▾' cluster that\nexpands inline to Shopify Admin / Line Viewer / Check Stock; each dims when its\ntarget can't resolve; Check Stock shows the stored snapshot inline (never a metered\n--live scrape on render). stopPropagation preserved so the card's website-open click\nnever fires from the cluster."},{"hash":"a5f3545","date":"2026-07-07 07:18:59 -0700","author":"Steve","subject":"grid: Book/Series facet in left rail + Website/Internal buttons on every card & list row (graceful disable)","body":""},{"hash":"3876a0d","date":"2026-07-07 07:13:35 -0700","author":"Steve","subject":"api: carry series (Book) facet + website/internal_url per product","body":""},{"hash":"7f71cd1","date":"2026-07-06 16:28:25 -0700","author":"Steve Abrams","subject":"microsites.html: density slider 1-30 with live readout + sort every field (products/name/slug/type both dirs, catalog/live/gated)","body":""},{"hash":"ce4838d","date":"2026-07-06 16:02:45 -0700","author":"Steve Abrams","subject":"untrack data/microsites.json (live crawl artifact) + restore .gitignore entry lost in prod reconcile","body":""},{"hash":"2d9b4a7","date":"2026-07-06 16:02:19 -0700","author":"Steve Abrams","subject":"all.: add visible /microsites.html directory (sort + density + infinite scroll over /api/microsites) + nav links from index & vendors","body":""},{"hash":"228a80f","date":"2026-07-06 15:33:48 -0700","author":"Steve Abrams","subject":"reconcile local to deployed prod (5bc3e1a) + re-layer microsite crawl feature onto true prod base","body":""},{"hash":"260257f","date":"2026-07-06 15:18:45 -0700","author":"Steve Abrams","subject":"all.: add live *.designerwallcoverings.com microsite crawl (directory + merged products), served at /api/microsites, polled every 10 min in-process + launchd","body":""},{"hash":"96f3c15","date":"2026-07-02 17:09:30 -0700","author":"Steve Abrams","subject":"Astek-viewer alignment: accordion filter sections + CARD FIELDS toggles (image-only wall) + header count pill + --fs type scale + Basic Auth gate (admin/DW2024!, env-overridable, healthz open)","body":""},{"hash":"bb41e31","date":"2026-07-02 17:02:18 -0700","author":"Steve Abrams","subject":"amazon-style left filter rail + grid/list toggle + sortable columns (every field, asc/desc w/ null-aware desc) + density to 20 + URL param overrides","body":""},{"hash":"86857a5","date":"2026-07-02 16:13:36 -0700","author":"Steve Abrams","subject":"portable snapshot SQL: probe optional mirror-only columns (min_variant_price, online_store_published) so the same code runs on Kamatera canonical","body":""},{"hash":"c8c8cd7","date":"2026-07-02 16:12:31 -0700","author":"Steve Abrams","subject":"banned front-facing vendor scrub on the public snapshot (Brewster/York/WallQuest/NewWall/... per build-data.py hard rule)","body":""}]}