{"slug":"dw-photo-capture","total":231,"limit":100,"offset":0,"since":null,"commits":[{"hash":"e944832","date":"2026-07-28 04:27:19 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-28T04:27:17 (1 files) — data/color-dots.json","body":""},{"hash":"2085685","date":"2026-07-28 03:57:09 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-28T03:57:08 (1 files) — data/color-dots.json","body":""},{"hash":"7f05d6c","date":"2026-07-27 04:17:55 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-27T04:17:53 (1 files) — data/color-dots.json","body":""},{"hash":"d407efc","date":"2026-07-27 03:47:47 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-27T03:47:45 (1 files) — data/color-dots.json","body":""},{"hash":"210a279","date":"2026-07-26 04:40:37 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-26T04:40:35 (1 files) — data/color-dots.json","body":""},{"hash":"8038793","date":"2026-07-26 03:40:21 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-26T03:40:20 (1 files) — data/color-dots.json","body":""},{"hash":"89699fd","date":"2026-07-25 04:33:39 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-25T04:33:37 (1 files) — data/color-dots.json","body":""},{"hash":"77c6b64","date":"2026-07-25 03:33:17 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-25T03:33:15 (1 files) — data/color-dots.json","body":""},{"hash":"d7be4c6","date":"2026-07-24 04:25:21 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-24T04:25:19 (1 files) — data/color-dots.json","body":""},{"hash":"98b67d2","date":"2026-07-24 03:55:14 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-24T03:55:12 (1 files) — data/color-dots.json","body":""},{"hash":"d17f80f","date":"2026-07-23 04:18:34 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-23T04:18:33 (1 files) — data/color-dots.json","body":""},{"hash":"c643cf0","date":"2026-07-23 03:48:27 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-23T03:48:26 (1 files) — data/color-dots.json","body":""},{"hash":"214f7fb","date":"2026-07-22 04:41:24 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-22T04:41:22 (1 files) — data/color-dots.json","body":""},{"hash":"22fe1cb","date":"2026-07-22 03:41:11 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-22T03:41:10 (1 files) — data/color-dots.json","body":""},{"hash":"52d98a4","date":"2026-07-21 12:36:28 -0700","author":"Steve Abrams","subject":"chore: lint (drop unused HSL l), refactor (familyOf hue comment, hexToRgb param), v1.5.1 (session close)","body":""},{"hash":"f733796","date":"2026-07-21 04:35:43 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-21T04:35:41 (1 files) — data/color-dots.json","body":""},{"hash":"904218b","date":"2026-07-21 03:35:31 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-21T03:35:30 (1 files) — data/color-dots.json","body":""},{"hash":"d684bcb","date":"2026-07-20 04:29:53 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-20T04:29:52 (1 files) — data/color-dots.json","body":""},{"hash":"2a2122c","date":"2026-07-20 03:59:47 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-20T03:59:45 (1 files) — data/color-dots.json","body":""},{"hash":"e002054","date":"2026-07-19 08:22:33 -0700","author":"Steve Abrams","subject":"shop-by-color: data-driven ΔE-collapsed color dots (real DB hexes, ≥20 patterns, qty-ordered)","body":"- scripts/build-color-dots.cjs: greedy CIELAB ΔE76 clustering (DTD verdict A) of\n  product_colors (live-truth gated) into visually-unique dots; keep clusters\n  ≥20 patterns, order by summed count desc; nearest-Pantone naming + LAB-chroma\n  family bucketing. 146 dots covering 41,907/43,284 products.\n- server.js: public GET /apps/color-dots serving data/color-dots.json (hot-reload\n  on mtime, same CORS posture as /apps/color-index).\n- refresh-color-index.sh: build + rsync color-dots.json alongside the index."},{"hash":"a9c6a11","date":"2026-07-19 07:31:13 -0700","author":"Steve Abrams","subject":"chore: version-up v1.5.0 (session close — shop-by-color product_type)","body":""},{"hash":"8112eaf","date":"2026-07-17 10:29:42 -0700","author":"Steve Abrams","subject":"color-index: carry product_type through builder + both /apps/color-index and /apps/color-widen results (shop-by-color type checkboxes)","body":""},{"hash":"0d6c355","date":"2026-07-16 11:40:44 -0700","author":"Steve","subject":"color-widen: add min param — guarantee >=N results via nearest-neighbor fallback when the band is thin","body":""},{"hash":"e2c9e01","date":"2026-07-16 11:03:10 -0700","author":"Steve","subject":"add /apps/color-widen route: tunable ΔE band (default 15%) for the Shop-by-Color wheel at /pages/colors","body":""},{"hash":"5d305fe","date":"2026-07-15 16:49:33 -0700","author":"Steve Abrams","subject":"color-index: exclude sample-only ($4.25) products — require has_product_variant so shop-by-color never links to a sample-only PDP (harm-reduction until vendor costs are sourced)","body":""},{"hash":"4214868","date":"2026-07-15 16:33:21 -0700","author":"Steve Abrams","subject":"add nightly color-index refresh script + launchd plist (DRAFT — install gated): build from live shopify_products, rsync json to Kamatera (endpoint hot-reloads)","body":""},{"hash":"91ce171","date":"2026-07-15 16:31:35 -0700","author":"Steve Abrams","subject":"deps: add pg so build-color-index runs standalone (needed for scheduled rebuild)","body":""},{"hash":"61eee41","date":"2026-07-15 16:30:51 -0700","author":"Steve Abrams","subject":"color-index: build from live shopify_products (active + online_store_published) — drop archived/unpublished handles so PDP color grid never links to 404s or dead images","body":""},{"hash":"dd6e416","date":"2026-07-13 09:40:58 -0700","author":"Steve Abrams","subject":"chore: session close snapshot (visual-search)","body":""},{"hash":"2212c21","date":"2026-07-13 01:29:32 -0700","author":"Steve Abrams","subject":"nightly embed top-up script + plist draft (coverage anti-decay: both embedders resumable + index hot-reload)","body":""},{"hash":"bdba9e2","date":"2026-07-13 01:10:29 -0700","author":"Steve Abrams","subject":"visual-search: path-(a) Kamatera self-host bundle (lite venv, no torch; pm2 unit reading local dw_unified) — verified 71MB footprint","body":""},{"hash":"fcb1edb","date":"2026-07-13 01:00:19 -0700","author":"Steve Abrams","subject":"visual-search: bind VS_HOST=0.0.0.0 so Kamatera pairs-well can reach the CLIP index over the tailnet (100.82.17.107:9914)","body":"Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"95931a9","date":"2026-07-13 00:51:44 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-13T00:51:43 (2 files) — visual-search/__pycache__/search_service.cpython-312.pyc visual-search/search_service.py","body":""},{"hash":"a0e586b","date":"2026-07-13 00:10:45 -0700","author":"Steve Abrams","subject":"visual-search: make bind host configurable via VS_HOST (default 127.0.0.1, unchanged); enables opt-in tailnet exposure for remote consumers","body":"Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"2890b8f","date":"2026-07-12 23:51:23 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-12T23:51:20 (5 files) — visual-search/search_service.py visual-search/__pycache__/embed_shopify_gap.cpython-312.pyc visual-search/__pycache__/search_service.cpython-312.pyc visual-search/com.steve.visual-search.plist visual-search/embed_shopify_gap.py","body":""},{"hash":"ca63a1e","date":"2026-07-12 23:21:14 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-12T23:21:12 (1 files) — visual-search/.gitignore","body":""},{"hash":"c913d7d","date":"2026-07-09 22:42:32 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-09T22:42:31 (5 files) — screenrecord/debug-log.jsonl screenrecord/rec/run3/page@ea8fb1218f5b7b345af268e4e545b083.mp4 screenrecord/rec/run3/page@ea8fb1218f5b7b345af268e4e545b083.webm screenrecord/rec/run4/page@96324b4cfafc83a80afe7cd203ccecb3.mp4 screenrecord/rec/run4/page@96324b4cfafc83a80afe7cd203ccecb3.webm","body":""},{"hash":"7c5ada1","date":"2026-07-09 22:12:25 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-09T22:12:24 (1 files) — package-lock.json","body":""},{"hash":"bb7bf3e","date":"2026-07-09 21:58:53 -0700","author":"Steve Abrams","subject":"chore: v1.4.0 (session close) — GCV+Gemini OCR fusion, WALLPAPER FileMaker lookup (dash-agnostic + partial search), save-every-scan, iOS freeze fixes (decode-free photo pipeline + 250x memory cut)","body":""},{"hash":"6aa4a18","date":"2026-07-09 19:41:57 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-09T19:41:55 (8 files) — screenrecord/debug-log.jsonl screenrecord/DEBUG-REPORT.md screenrecord/rec/run0_v103/ screenrecord/rec/run1_v103/ screenrecord/rec/run2_v103/","body":""},{"hash":"30757b5","date":"2026-07-09 16:41:20 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-09T16:41:19 (5 files) — schu-candidates.tsv schu-publish.mjs schu-apply-out.json schu-publish-audit.jsonl schu-settlement-hold.json","body":""},{"hash":"d52d765","date":"2026-07-09 16:11:13 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-09T16:11:12 (2 files) — schu-candidates.tsv schu-publish.mjs","body":""},{"hash":"8ef6e5f","date":"2026-07-09 09:09:51 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-09T09:09:49 (1 files) — visual-search/__pycache__/","body":""},{"hash":"602bb7f","date":"2026-07-09 09:09:49 -0700","author":"Steve Abrams","subject":"PDP color-dot color-index: /apps/color-index endpoint + generator (catalog-wide 10% CIELAB tolerance)","body":"New public (CORS-guarded, allowlisted) endpoint POST /apps/color-index on dwphoto:\ntakes {hex,k}, returns catalog-wide products within a perceptual 10% tolerance\n(CIELAB deltaE76, named COLOR_INDEX_TOLERANCE_PCT=0.10 -> deltaE ceiling 10),\nnearest-first, public-safe fields only. Backed by a static color-index.json\n(one dominant color per ACTIVE product w/ precomputed LAB, 60,960 products) built\nby scripts/build-color-index.cjs from dw_unified.product_colors -- no DB at request\ntime. Index loaded once + mtime-hot-reload. Staged/local; do NOT deploy publicly\nwithout Steve's go.\n\nVerified: forest #3C5B49 -> 97 in-tolerance products, all returned deltaE<=6.3."},{"hash":"41d871a","date":"2026-07-09 08:53:24 -0700","author":"steve@designerwallcoverings.com","subject":"CLIP /similar: DW-safe guard — only return storefront products w/ handle + DW-hosted image; drop wallquest.com hotlinks (broken imgs + private-label leak) + handleless entries; backfill to keep strip full","body":""},{"hash":"0bd9187","date":"2026-07-09 08:40:40 -0700","author":"Steve Abrams","subject":"iOS OOM-freeze root cause (found via mobile screenrecord 5x): app fetched /api/twil = 36MB/88,319 items on EVERY page load (default filter=twil) and render() built a DOM card for all 88k → browser hit 13GB and crashed the tab, starving the device so photo capture froze. Fix: RENDER_CAP=500 cards max + 'narrow your search' note; defer the 36MB loadTwil() off page-load (lazy on skip/TWIL-chip)","body":""},{"hash":"036d130","date":"2026-07-09 08:39:43 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-09T08:39:40 (2 files) — public/index.html screenrecord/","body":""},{"hash":"ab7c20f","date":"2026-07-08 16:03:14 -0700","author":"Steve Abrams","subject":"Scan upload-progress (final DTD FIX-THEN-SHIP): identify-multi POST via XHR shows '⬆ Uploading photo… n%' then '🔎 Identifying…' — kills the dead-looking wait on a big raw-photo cellular upload that a user would misread as a freeze","body":""},{"hash":"dd49fa4","date":"2026-07-08 15:59:51 -0700","author":"Steve Abrams","subject":"iOS freeze — close the contrarian gap: ALL photo flows now decode-free. downscale() itself = FileReader raw (fixes Add New SKU / Update SKU / gallery-batch, which still froze via createImageBitmap that v99 proved unsafe). Server normalizes at every ingest: create-item + /api/photo + /api/photos via normB64 (HEIC→JPEG for Shopify; box IM has libheif). Scan regression green","body":""},{"hash":"71b8574","date":"2026-07-08 15:53:14 -0700","author":"Steve Abrams","subject":"iOS freeze — eliminate ALL client-side image decode (DTD verdict B): fbRead uses FileReader.readAsDataURL (raw file, zero decode/canvas/bitmap), server normalizeImage() (ImageMagick: any format→auto-orient→≤1600px JPEG) handles it before OCR + visual. decodeQR capped at 1000px (a full-12MP getImageData is a ~48MB array that froze iOS). Verified: raw 3000px photo → resolves CHC217203. /5x 10/10","body":""},{"hash":"d5ff7da","date":"2026-07-08 15:43:57 -0700","author":"Steve Abrams","subject":"iOS photo-processing freeze fix: downscale() now uses createImageBitmap (off-main-thread, low-memory decode) instead of <img>+canvas.toDataURL which OOM-hangs iOS on a 12MP camera photo; cap 1200px + q0.82. fbRead shows '📷 Processing photo…' immediately + guards a null (undecodable) read","body":""},{"hash":"ef6656d","date":"2026-07-08 15:41:15 -0700","author":"Steve Abrams","subject":"Fix iOS camera freeze on Look Up SKU: stop auto-clicking the BACK capture input after the front photo — iOS Safari LOCKS UP when a capture-input .click() fires from a change-event (no fresh user gesture). Now highlights the Back tile + prompts a tap; front-only Identify also enabled","body":""},{"hash":"6eb9013","date":"2026-07-08 15:05:19 -0700","author":"Steve Abrams","subject":"FM lookup dash-agnostic + printed-code-first: wallpaper-details tries raw+dashless forms on both combo-sku and Mfr-Pattern (CHC-217203 ⇄ CHC217203 auto), and the scan keys the FM lookup off the PRINTED OCR code first (the model# on the label) plus the resolved dw_sku","body":""},{"hash":"c473b21","date":"2026-07-08 14:59:44 -0700","author":"Steve","subject":"dwphoto: add SSRF-guarded CORS-scoped /apps/similar proxy route → loopback CLIP :9914 (shipped GATED-STEP-1)","body":""},{"hash":"06f5839","date":"2026-07-08 14:55:13 -0700","author":"Steve","subject":"visual-search /similar: also return storefront handle (LEFT JOIN shopify_products) so PDP cards link to real product pages","body":""},{"hash":"3e6d84f","date":"2026-07-08 14:54:15 -0700","author":"Steve Abrams","subject":"Save EVERY scan (Steve): identify-multi now persists the raw photo(s) + OCR candidates + engines + resolved identity to data/scan-log.jsonl (append-only, async best-effort — never breaks a scan). New /api/scans (newest-first, filter=unresolved) + /scans review page: photo ⇄ what OCR read ⇄ resolved SKU, so mis-reads are visible and the corpus improves the app. Verified: scan saved, image served, GCV+Gemini fusion recorded","body":""},{"hash":"51cf188","date":"2026-07-08 14:37:44 -0700","author":"Steve Abrams","subject":"OCR: multi-engine fusion for the back label — backOcrFused() runs every available engine (GCV→Gemini→macVision) and unions candidate codes so the catalog partial-search has more shots on goal; literal-transcriber engines lead. GCV is now plug-and-play (set GCV_API_KEY → auto-fuses). Scan read-line shows which engine(s) ran + per-scan cost","body":""},{"hash":"c68081a","date":"2026-07-08 13:15:26 -0700","author":"Steve Abrams","subject":"visual-search: add POST /similar (SKU->CLIP visual neighbors, color+style soft re-rank, lazy CLIP load)","body":""},{"hash":"a7f6374","date":"2026-07-08 13:14:09 -0700","author":"Steve Abrams","subject":"Scan lookup driven by the OCR'd label code: a VISUAL-only identify no longer beats the printed model# — the wallpaper-file lookup now prefers the OCR'd code (so 217500 gets searched even when identify 'found' a visual match), and every scan shows '📄 read: <codes>' so mis-reads are visible on-device. No-code-read state guides toward a clearer label photo","body":""},{"hash":"5cea2c8","date":"2026-07-08 13:04:30 -0700","author":"Steve Abrams","subject":"Scan fixes: (1) scrub DW's OWN header from identification — our phone 888-373-4564 (+ fragments/phone-shaped tokens) never becomes a candidate code, and 'Designer Wallcoverings' never read as the pattern name; model# is what runs down the SKU. (2) partial search now fires AUTOMATICALLY when a scan doesn't confidently match (uses the OCR'd code via back_read). (3) live search-as-you-type (debounced 300ms + race-guard) in the manual search box","body":""},{"hash":"8837b5f","date":"2026-07-08 12:51:20 -0700","author":"Steve Abrams","subject":"Scan: partial/fuzzy wallpaper-file lookup — new /api/wallpaper-search substring-matches any part of combo sku / Mfr Pattern / JS Pattern / Internal Description (FileMaker *q* OR-across-fields), with OCR trailing-char trim tolerance (217500→21750→CHC-21750-style), grouped+coalesced per SKU. Manual search box in the scan modal + auto partial-fallback when exact identify misses; tap a candidate → full detail card","body":""},{"hash":"c3d8429","date":"2026-07-08 12:42:42 -0700","author":"Steve Abrams","subject":"Scan → show WALLPAPER FileMaker details: new /api/wallpaper-details (queries 'Basic List of Fields' by combo sku→Mfr Pattern, coalesces non-empty specs across the mega-table's multiple rows, portal:[] so no stall) + loadWallpaperDetails() renders a spec card (Mfr#/Collection/Width/Repeat/Retail/Net/Cost/Roll/Min/Border/Price-code/Line/SKU) under every scan result. 58k+ SKUs carry rich FM specs; sparse scraped lines show what FM has","body":""},{"hash":"d4db33e","date":"2026-07-08 12:20:29 -0700","author":"Steve Abrams","subject":"doc: cross-reference the shared Date WP Sample Sent writer (mark-received + print-sticker both close the open-sample request via this field) — surfaced by contrarian gate during /5x","body":""},{"hash":"b56afa1","date":"2026-07-08 11:35:29 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-08T11:35:28 (1 files) — package-lock.json","body":""},{"hash":"66895a7","date":"2026-07-08 11:07:37 -0700","author":"Steve Abrams","subject":"chore: v1.2.0 → v1.3.0 (session close — feed + discontinued-successor features)","body":""},{"hash":"5f86fc5","date":"2026-07-08 11:05:22 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-08T11:05:21 (1 files) — data/build.json","body":""},{"hash":"ba63786","date":"2026-07-08 11:00:29 -0700","author":"Steve Abrams","subject":"Add discontinued-SKU resolver → red card → live successor link (local only)","body":"/api/discontinued?q=<sku> resolves discontinued/deleted SKUs dash/punct-insensitively\n(CHC-216830 == CHC216830 == CHC-216830-SAMPLE) and links the live successor via the\nCOPY-OF mfr hint + sibling harvest + active title match, ported from substitutefinder\nfind.py. Scanner lookup falls back to it on 0 active hits and shows a red successor card.\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"140c994","date":"2026-07-08 09:11:02 -0700","author":"Steve Abrams","subject":"gitignore the runtime all-dw feed cache (data/all-catalog.json)","body":""},{"hash":"a4417e3","date":"2026-07-08 09:02:34 -0700","author":"Steve Abrams","subject":"browse whole dw_unified catalog via all-dw feed (was Fentucci-only); disk-cache + Fentucci fallbacks","body":""},{"hash":"62ce2a4","date":"2026-07-08 06:58:24 -0700","author":"Steve Abrams","subject":"Incoming queue: best-effort image enrichment — pass 2 in the background refresh resolves CATALOG-miss samples via identifyUnified (full 267k crossref + 173k shopify_products), concurrency-bounded (6 workers), serve-stale-while-enriching. 0/40 -> 16/40 (40%) thumbnails + real pattern names; also populates dw_sku/mfr_sku so scan-match highlights more incoming cards","body":""},{"hash":"999db25","date":"2026-07-08 06:48:37 -0700","author":"Steve Abrams","subject":"Check Sample In: 'Received' button stamps Date WP Sample Sent=today (Steve's receive-stamp field) via POST /api/mark-received (fmSet), drops the card from the incoming queue; scan-match surfaces a one-tap 'Check in — received today'. Input-guarded (400 on missing recordId/bad json), no live write on my tests","body":""},{"hash":"427db51","date":"2026-07-07 16:59:21 -0700","author":"Steve Abrams","subject":"Check Sample In: incoming-queue panel — shows vendor-ordered+not-sent samples (recent 120d) with spec info, cached server-side + 8-min background refresh (FM find is a ~30s whole-file scan, so cache→instant 0.15s). Scan flags the matching incoming card. Images best-effort from active catalog","body":""},{"hash":"2d627ac","date":"2026-07-07 16:45:44 -0700","author":"Steve Abrams","subject":"Check Sample In → incoming queue: /api/incoming-samples finds vendor-ordered+not-sent samples in FileMaker (the arriving ones), enriched with catalog image+spec. fmFind gains portal:[] to suppress heavy portalData (fixed the FM timeout)","body":""},{"hash":"17b5c68","date":"2026-07-07 13:51:34 -0700","author":"Steve Abrams","subject":"Local aug-model deploy pipeline (mac_deploy_embed): embed full catalog with dw_clip_ft_aug on Mac MPS → Postgres COPY file for Kamatera local ingest (gate-respecting: no Mac→prod tunnel). Reuses 90k cache, 3-state load (ok/dead-404/transient-retry) so rate-limits never false-mark images dead. Resumable","body":""},{"hash":"2acc59c","date":"2026-07-07 13:30:47 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-07T13:30:45 (1 files) — visual-search/train/__pycache__/finetune_aug.cpython-312.pyc","body":""},{"hash":"e56063d","date":"2026-07-07 13:18:26 -0700","author":"Steve Abrams","subject":"Look Up SKU pill: camera-first pure-identify flow — shoot FRONT pattern → auto-prompts/opens BACK label (the text/SKU) → runs identify-multi (visual+OCR+code fusion) and shows the SKU. Skips the sample check-in (that's the separate Check Sample In pill)","body":""},{"hash":"27b572c","date":"2026-07-07 13:09:39 -0700","author":"Steve Abrams","subject":"Fix aug-training crash (cannot write empty image): guard augment against tiny/empty crops + wrap JPEG recompress + AugSet falls back to a neighbor on a corrupt cache image (never crashes the run)","body":""},{"hash":"a376a2d","date":"2026-07-07 13:06:17 -0700","author":"Steve Abrams","subject":"DEVICE-TEST: multi-photo tip — take 2-3 pattern shots for visual-ID (app fuses views; single shot ~28% top-1, multi-view is the reliable path)","body":""},{"hash":"de2aca3","date":"2026-07-07 13:05:42 -0700","author":"Steve Abrams","subject":"robustness_fusion: note CDN rate-limiting makes the A/B unreliable; fusion verified directly (3-view demo promotes the corroborated match)","body":""},{"hash":"6cdd9d9","date":"2026-07-07 13:02:32 -0700","author":"Steve Abrams","subject":"Multi-photo visual-ID fusion: identify-multi now fuses up to 5 views (fronts[]) — a product matching across multiple photos gets a corroboration boost and outranks spurious single-view matches; Add/Update flows send all captured photos. Independent lever on the 28% single-shot problem (complements the augmentation retrain)","body":""},{"hash":"724673e","date":"2026-07-07 13:00:36 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-07T13:00:27 (1 files) — visual-search/train/__pycache__/finetune_aug.cpython-312.pyc","body":""},{"hash":"33641ca","date":"2026-07-07 12:58:22 -0700","author":"Steve Abrams","subject":"eval_aug: A/B degraded→clean image retrieval (base vs current FT vs augmented) → recommend deploy only if the aug model beats current top-1","body":""},{"hash":"54e085f","date":"2026-07-07 12:57:37 -0700","author":"Steve Abrams","subject":"Augmentation re-fine-tune: warm-start from dw_clip_ft.pt + heavy handheld-photo augmentation (rotate/crop/blur/glare/JPEG) on the image side → teach degraded→clean matching (targets the 28% real-photo top-1)","body":""},{"hash":"6a137d9","date":"2026-07-07 12:52:50 -0700","author":"Steve Abrams","subject":"5x contrarian gate: honest re-scope — FT visual-ID validated on the REAL task (degraded phone-like image→image) = only 28% top-1 (n=40), thresholds overlap; clean-image self-match hid this. App still safe (label-OCR primary + confidence+2nd-push gates). Real fix = augmentation re-train (surfaced, gated). Camera/iOS-Safari still untested (headless can't reach getUserMedia)","body":""},{"hash":"8694d87","date":"2026-07-07 12:43:32 -0700","author":"Steve Abrams","subject":"5x: 2 consecutive clean sweeps (0 app defects) post FT-model + dedup — six-way + endpoints + flow + dedup + calibrate all green; sole non-green is the M3 no-auth harness artifact (authed load 0.24s)","body":""},{"hash":"828996f","date":"2026-07-07 10:18:06 -0700","author":"Steve Abrams","subject":"Contrarian gate fix (dedup): add _addSession guard before every DOM write (no stale warning/switch into a reopened modal) + require a non-null product_id before offering 'Update instead' (was binding null pid → wrong-product write)","body":""},{"hash":"cf2ea4a","date":"2026-07-07 10:12:51 -0700","author":"Steve Abrams","subject":"Add-mode visual dedup: new-SKU pattern photo → fine-tuned visual-ID; if it confidently matches an existing catalog pattern, warn (non-blocking) + offer one-tap 'Update it instead' (resolves via mfr then dw_sku). Prevents duplicate SKUs","body":""},{"hash":"7d4ccb6","date":"2026-07-07 08:56:28 -0700","author":"Steve Abrams","subject":"Device-test checklist for the iPhone-Safari real-device pass (camera-first, specs, mics, 10/6 gallery, calibrate-once measure, live Update + 2nd-push confirm, video transcode)","body":""},{"hash":"ec02bd7","date":"2026-07-07 06:39:29 -0700","author":"Steve Abrams","subject":"Wire in fine-tuned DW CLIP: sanity-check picks best epoch (ep4, 52.9% held-out recall@1 vs 23.0% base — 2.3x, no overfit); load dw_clip_ft.pt in search_service + embed_catalog (both sides); catalog re-embedding on FT model (311k, snapshot saved for rollback)","body":""},{"hash":"5673cad","date":"2026-07-06 22:15:46 -0700","author":"Steve Abrams","subject":"Contrarian gate fix: _updateNeedsConfirm invariant — ANY ambiguous visual bind (background OR mid-Push) requires a 2nd Push before a LIVE write; label OCR + chip-tap are explicit (no gate). Plus session checks after resolve/visual awaits in addExtract","body":""},{"hash":"1570feb","date":"2026-07-06 22:05:57 -0700","author":"Steve Abrams","subject":"yolo hardening (8 fixes from adversarial review): C1 visual bind requires confirm before live push · C2 no auto-bind on low-confidence · W1 escape all $$ fields in staging SQL · W2 downscale onerror+timeout (no HEIC hang) · W3 create-item/photo/photos drain+413 · W4 session token guards stale async rebind · S1 calibration viewport check · S2 poll waits for all expected videos","body":""},{"hash":"a2500f8","date":"2026-07-06 21:43:31 -0700","author":"Steve Abrams","subject":"Calibrate-once measurement: card sizes px/in for the device once → stored in localStorage → every later scan just needs the goods box, no card. Zoom locked so focal length stays constant. Recalibrate button to re-anchor.","body":""},{"hash":"8cff6c4","date":"2026-07-06 21:36:02 -0700","author":"Steve Abrams","subject":"Camera-unavailable UX: detect Chrome/3rd-party iOS browsers (no getUserMedia) and tell user to open in Safari, instead of a cryptic error","body":""},{"hash":"b0a3ecc","date":"2026-07-06 21:22:44 -0700","author":"Steve Abrams","subject":"Handoff doc: how to wire the fine-tuned DW CLIP weights into visual search (sanity-check, re-embed both sides, gate the reindex, rollback)","body":""},{"hash":"da94b6f","date":"2026-07-06 21:22:09 -0700","author":"Steve Abrams","subject":"Card-free measurement groundwork: lock camera zoom + /caps capability probe (reports focusDistance/zoom/motion support per device) to pick the right no-reference scale method","body":""},{"hash":"b87d402","date":"2026-07-06 21:13:35 -0700","author":"Steve Abrams","subject":"Visual pattern-ID in capture flow (front photo → identify-multi → bind SKU by design, even with unreadable label; tappable candidate chips) + live on-camera dimension readout (credit-card scale reference → real W×L overlaid live, writes to specs)","body":""},{"hash":"5126f02","date":"2026-07-06 21:07:10 -0700","author":"Steve Abrams","subject":"Overnight DW CLIP fine-tune pipeline (MPS): build_manifest + resumable 256px downloader + open_clip contrastive fine-tune + overnight orchestrator","body":""},{"hash":"942ce16","date":"2026-07-06 20:46:34 -0700","author":"Steve Abrams","subject":"5x: 2 consecutive clean sweeps (0 app defects) — six-way + functional + headless-flow all green; 2 caught items proven harness artifacts","body":""},{"hash":"aa3a6ce","date":"2026-07-06 20:38:09 -0700","author":"Steve Abrams","subject":"Video transcode poll: /api/media-status reads Shopify video processing state; client polls after upload until every clip is READY (or fails), updating the note in-place","body":""},{"hash":"4a51d5b","date":"2026-07-06 20:34:52 -0700","author":"Steve Abrams","subject":"Camera-first capture flow + 10-photo/6-video gallery: pill→camera→details-after-scan; Add mode creates draft, Update mode resolves existing SKU (shopifySearch fallback) and pushes photos+videos LIVE to Shopify; /api/resolve-product endpoint","body":""}]}