Dw Photo Capture
Search the build
-
6286a2f2026-09-26 Swipe picker: Pick this one opens the theme full screen (Back / Esc / Go to the app), Open-your-pick button reopens it; fix filter wiring catching the pick button (TK-12343) -
28a13912026-09-26 Swipe picker: one trackpad swipe/wheel flick = one theme (Safari skipped two); app chooser shows once per tab, not on every load (TK-12343) -
24bc0c32026-09-26 Front screen: one-at-a-time swipe theme picker (Figma v1-v25 + Photoshop Kid-Simple v7-v16); capture app moves to /app (TK-12343) -
6e2c3f22026-09-26 Onload chooser: Adobe Spectrum themes (Light/Dark/Darkest/Auto) + accents, smart Suggested action, full UX (TK-12346) -
4ace5d42026-09-26 Add /kid-simple/ review page: Kid-Simple mockups v1-v16 + Photoshop board, behind basic-auth (TK-12344) -
ac134892026-09-26 Untrack runtime build counter data/build.json and gitignore it -
6e169982026-09-26 TK-12090: add verify-only prod vision check paste script -
436c44b2026-09-26 auto-data-snapshot: 2026-09-26T04:44:27 (1 data files) — data/color-dots.json -
d7887da2026-09-26 auto-data-snapshot: 2026-09-26T03:43:38 (1 data files) — data/color-dots.json -
655426a2026-09-25 TK-12268: add creds-in-URL fetch guard (fleet pattern) to gated page -
9b158292026-09-25 TK-12268: add creds-in-URL fetch guard (fleet pattern) to gated page -
7aecde52026-09-25 Editor fits iPhone width: narrow-screen layout (wheel above sliders, Use Photo full-width, Crop/Reset/Cancel row) -
69d50162026-09-25 Front/Back tiles: tap a taken photo to adjust it in the Enhance/Crop editor; Adjust + Retake buttons below each tile (TK-12256) -
a2e81982026-09-25 5x sweep 5: report — sweeps converge at cap, 3 app defects fixed, env SIGTERM open -
0e8aa0e2026-09-25 5x sweep 4: history evidence screenshot viewport-only (Firefox 32767px full-page limit) -
bf95f562026-09-25 5x sweep 3: hung-camera e2e mode (all engines), WebKit stub fix, sweep aborts if server dies -
4fd7dee2026-09-25 5x sweep 2: camera-timeout retry tap now opens the snap camera (as the toast promises) -
b49fdf92026-09-25 deploy: exclude tracked schu-publish-audit.jsonl (identical on remote) from rsync to stop delete-guard false positive -
15beb442026-09-25 5x sweep 1: favicon on captures/batch/cam, consistent missing-side rule, 3-engine e2e + lazy-img scroll -
d1a0b782026-09-25 TK-12228: every captured photo, front and back, displays in the app -
e82585f2026-09-25 deploy: exclude .claude/ from rsync so agent worktree logs on remote aren't deleted -
126f9172026-09-25 Fix grainy Shopify product photos: raise server-side JPEG normalize cap+quality -
afa27772026-09-25 auto-data-snapshot: 2026-09-25T04:38:13 (1 data files) — data/color-dots.json -
14a66232026-09-25 auto-data-snapshot: 2026-09-25T03:37:11 (1 data files) — data/color-dots.json -
8cceebc2026-09-24 TK-12205: untrack agent worktree gitlink auto-snapshotted into main; ignore .claude/worktrees/ -
05c1b612026-09-24 auto-data-snapshot: 2026-09-24T23:32:41 (1 data files) — .claude/worktrees/agent-a841f65dcd871d6ac -
d47866f2026-09-24 auto-data-snapshot: 2026-09-24T23:02:07 (1 data files) — .claude/worktrees/agent-a841f65dcd871d6ac -
99b4c9a2026-09-24 auto-data-snapshot: 2026-09-24T21:00:07 (1 data files) — .claude/worktrees/agent-a841f65dcd871d6ac -
e99e5542026-09-24 auto-data-snapshot: 2026-09-24T20:29:39 (2 data files) — .claude/worktrees/agent-a841f65dcd871d6ac data/build.json -
67566bd2026-09-24 TK-12162: mint checks vendor catalog reservations + confirms the number is free LIVE (FileMaker + Shopify) -
2bc55d42026-09-24 TK-12162: 582 FileMaker masters created for live Tres Tintas products (DWTS); 10 Thibaut records mis-moved earlier restored to DWTT -
30fe09a2026-09-24 TK-12162: fix my collision - 7 Tres Tintas sq-ft listings DWTS-900000..006 -> DWTS-901507..513 (900001-006 reserved in tres_tintas_catalog) -
b1582b82026-09-24 TK-12162: 1168 Tres Tintas Shopify variant SKUs DWTB- -> DWTS- (undo log) -
825c8b22026-09-24 auto-data-snapshot: 2026-09-24T16:24:12 (2 data files) — ops/tres-tintas-dwts-2026-09-24/__pycache__/shop-tb.cpython-314.pyc ops/tres-tintas-dwts-2026-09-24/shop-tb-restore.jsonl -
d6f19b52026-09-24 Henry sync: treat not-yet-created server archive as OK 0, not FAIL (TK-12162) -
26539952026-09-24 Nightly additive rsync of vendor photo archive to Henry + launchd plist (TK-12162) -
0260eb62026-09-24 Save every uploaded photo by vendor: photos/vendors/<Vendor>/ archive + index + /vendor-photos gallery + one-time backfill (TK-12162) -
07b7e8c2026-09-24 deploy: exclude ops/ (Tres Tintas restore maps/scripts are local-only, not server runtime) (TK-12162) -
d5ea1982026-09-24 TK-12162: DWTB-10050 Tres Tintas master -> DWTS, duplicate tagged DUPE-DELETE (restore map) -
83caea32026-09-24 Add 'Other apps' links (4 simplified capture concepts) to home screen + bottom of upload grid (TK-12162) -
450f9532026-09-24 TK-12162: script to move 584 Tres Tintas Shopify products DWTB- -> DWTS- (Steve-run; classifier-gated) -
34ac6462026-09-24 TK-12162: Tres Tintas DWTT/DWRW -> DWTS restore maps + delete list -
a99636b2026-09-24 TK-12162: show a dw_unified save-status line on all 4 capture pages, independent of the Shopify draft result -
e7a50662026-09-24 TK-12162: auto-save only for registry vendors; case-insensitive vendor lookup; Minimal sends pattern name -
360da782026-09-24 TK-12162: await + retry the dw_unified new_items_staging write on every item create and report its result (dw_unified field) instead of fire-and-forget -
7e1353c2026-09-24 TK-12090: verify script resolves dwphoto by name, not stale pm2 id 226 -
1a2c3982026-09-24 TK-12162: pre-shot 11-slider adjust panel + auto-save on all simple-* pages -
4d1311b2026-09-24 TK-12162: full-res native-camera capture on all simple-* pages -
14e31942026-09-24 TK-12162: capture at high res on all simple-* pages + route minimal/wizard/probooth -
2b1d0062026-09-24 Consolidate SKU field cleanup into shared field-clean.js helper -
10d3e402026-09-24 TK-12162: guided wizard never strands a guest on an unexpected finishCapture error -
03f509f2026-09-24 TK-12090/TK-12162: fix numeric-SKU .trim() crash + de-obfuscate deploy verifier -
a7bae5f2026-09-24 auto-data-snapshot: 2026-09-24T13:20:22 (1 data files) — data/build.json -
a262d3e2026-09-24 TK-12162 Instant Film concept: simple-instant.html (Polaroid-style single-photo capture, animation decoupled from real /api/extract upload) -
247c9f92026-09-24 TK-12090: report provider=null when the vision call fails -
dc3cc712026-09-24 TK-12162 Pro Booth concept: simple-probooth.html (3-slider capture, bake-once + speculative extract, single-commit save) + staged Figma build script -
8452fcc2026-09-24 TK-12090: decouple exo VLM ring from HAS_MACVISION, make it the reasoning-path default -
83646152026-09-24 TK-12126: never report Gemini OCR cost for a call that errored -
d9c96122026-09-24 TK-12126: add camera commit:true round-trip proof script (mock-tested, live path gated) -
a1b8ee32026-09-24 Extract shared acquireCamera() helper, adopt across 5 unbounded surfaces (TK-12127) -
0e42baf2026-09-24 Wire ended + mute listeners on _tsTrack, scoped by generation (TK-12128) -
b2bd8932026-09-24 Add persistent "applies at capture, not preview" hint on the Sharpness slider (TK-12125) -
9f4d2c22026-09-24 Fix 3 Cody-found holes in the getUserMedia timeout fix (TK-12124 follow-up) -
ca60ce92026-09-24 Fix: bound getUserMedia() with an 8s timeout so a hung camera prompt can't brick the shutter (TK-12124) -
1d04e3f2026-09-24 auto-data-snapshot: 2026-09-24T04:27:32 (1 data files) — data/color-dots.json -
12011d52026-09-24 auto-data-snapshot: 2026-09-24T03:56:09 (1 data files) — data/color-dots.json -
2a2801e2026-09-23 batch.html: adopt shared capture-pipeline engine, full Photoshop set on top of gray-card calibration (TK-12090) -
880e4d82026-09-23 cam.html + desk.html: full pre-capture photoshop camera (zero→full parity) (TK-12090) -
af5702a2026-09-23 index.html two-shot: adopt shared capture-pipeline + full adjust panel + presets + histogram (TK-12090) -
fdff1372026-09-23 add shared capture-pipeline.js engine (full pre-capture photoshop set, manual canvas pixel math) -
94c8d602026-09-23 server.js: bounded /js/ static route to serve the shared capture-pipeline module (TK-12090) -
63b4de02026-09-23 auto-data-snapshot: 2026-09-23T15:21:10 (2 data files) — visual-search/__pycache__/pattern_siblings.cpython-312.pyc visual-search/__pycache__/search_service.cpython-312.pyc -
409e3382026-09-23 deploy.conf: exclude visual-search venv + CLIP weights + test dirs from rsync (1.3GB, TK-12090 Lane P follow-up) -
95babfe2026-09-23 visual-search: optional pattern-sibling stage (PATTERN_SIBLINGS=1 + body siblings:true) using dw-pairs-well colour-invariant dHash + WS-1 pattern_id, vendor+pattern_name fallback (TK-12090 Lane P) -
6a073192026-09-23 visual-search: product_image_fingerprints PG table + disk-guarded idempotent loader + flagged SQL-filtered PG search path (PG_FINGERPRINTS=1, default off) (TK-12090 Lane P) -
b1c94e32026-09-23 auto-data-snapshot: 2026-09-23T14:48:42 (1 data files) — visual-search/sql/product_image_fingerprints.sql -
d5f6c4a2026-09-23 visual-search nightly embed: env-first DB user (PGUSER or running OS user, drop retired stevestudio2), launchd PATH for psql, fail-loud connect precheck (TK-12090 Lane P) -
5b591d92026-09-23 repoint dead Ollama macvision + Q&A paths to shared exo-vision lib (ring primary, Gemini fallback, honest not_measured) (TK-12090 Lane P) -
2284bdb2026-09-23 auto-data-snapshot: 2026-09-23T04:15:24 (1 data files) — data/color-dots.json -
a7f6dc52026-09-23 auto-data-snapshot: 2026-09-23T03:44:04 (1 data files) — data/color-dots.json -
4d1ee362026-09-22 harden pid interpolation in staging insert (independent-review follow-up) -
060357d2026-09-22 fix SQL injection in create-item staging insert (dollar-quote escape defeated by $$$) -
0d34d1b2026-09-22 gitignore 5x/out/ screen-capture test artifacts -
2bc0f062026-09-22 harden all-dw cache write: atomic tmp+rename, refresh disk-cache sig -
77ae6ab2026-09-21 harden(TK-11962): catalog-cache guard survives corrupt/unreadable cache (Kimi review) -
39cda0e2026-09-21 fix(perf): guard redundant disk-cache reparse in buildCatalog (TK-11962) -
b272ac42026-09-21 auto-data-snapshot: 2026-09-21T17:27:28 (2 data files) — 5x/twoshot-result.json data/build.json -
5e89bec2026-09-21 fix(lint): drop redundant \/ escape in COLOR/NAME label regexes (TK-11962) -
10fd7132026-09-21 auto-data-snapshot: 2026-09-21T10:59:35 (1 data files) — data/build.json -
c5ee50a2026-09-21 photo-capture #8 harden (TK-11962 DTD): TTL-guard stale restore + surface quota failure -
fc871632026-09-21 auto-data-snapshot: 2026-09-21T06:39:23 (1 data files) — data/build.json -
c87b6612026-09-21 harden (TK-11962 review #7/#8/#9): server.on('error') + unconditional create gate + persist in-progress capture -
3af4c922026-09-21 auto-data-snapshot: 2026-09-21T04:28:28 (1 data files) — data/color-dots.json -
9342c102026-09-21 auto-data-snapshot: 2026-09-21T03:55:17 (1 data files) — data/color-dots.json -
ec708082026-09-20 auto-data-snapshot: 2026-09-20T18:59:45 (1 data files) — 5x/out/features-sweep9.json -
71c8d212026-09-20 auto-data-snapshot: 2026-09-20T18:25:19 (3 data files) — 5x/out/s9-dryrun-9890.json 5x/out/s9-dryrun-9899-FM.json data/build.json -
9a8a2722026-09-20 harden: process-level error safety net + string-validate dataUrl (fixes 1-request DoS) -
39c872f2026-09-20 auto-data-snapshot: 2026-09-20T12:15:15 (2 data files) — data/build.json data/scan-log.jsonl -
7d986902026-09-20 5x REPORT: TK-11947 capture rebuild — 51/51, Cody SHIP IT, deploy gated -
635c96e2026-09-20 Cody re-gate #2 hardening: conditional shutter-arm + flip double-tap guard + injected-failure negative test -
18789102026-09-20 5x fix sweep: guard camera race + fail-safe liveness + cap capture res + lock lens on BACK (Cody FIX FIRST) -
480017e2026-09-20 photo-capture: live pre-shutter colour + ordered two-photo ghost capture (#twoShotCam) -
fc976952026-09-20 auto-data-snapshot: 2026-09-20T11:40:52 (1 data files) — data/build.json -
ad2e1762026-09-20 auto-data-snapshot: 2026-09-20T09:27:07 (1 data files) — data/scan-log.jsonl -
5e0422e2026-09-20 auto-data-snapshot: 2026-09-20T08:54:11 (1 data files) — data/build.json -
fe8bd652026-09-20 photo-capture: plain 12-yr-old wording + large simple buttons across index/batch/cam -
3b53e0e2026-09-20 auto-data-snapshot: 2026-09-20T04:26:57 (1 data files) — data/color-dots.json -
c11515c2026-09-20 fix threading race in _get_model(): add _MODEL_LOCK + double-checked locking pattern -
618d0312026-09-20 auto-data-snapshot: 2026-09-20T03:53:01 (1 data files) — data/color-dots.json -
08460f72026-09-19 auto-data-snapshot: 2026-09-19T18:59:45 (2 data files) — data/build.json data/scan-log.jsonl -
131d2a52026-09-19 photo-capture: raise UI scale to 1.35x + extend to batch-shoot + remote-cam -
3b83a722026-09-19 photo-capture: global 1.2x UI scale on editor (--ui-scale dial) — 'make all larger' -
313e6c72026-09-19 auto-data-snapshot: 2026-09-19T13:09:57 (2 data files) — data/scan-log.jsonl data/vendor_profiles.json -
767d07c2026-09-19 auto-data-snapshot: 2026-09-19T11:34:41 (7 data files) — 5x/out/features-sweep6.json 5x/out/features-sweep7.json 5x/out/features-sweep8.json 5x/out/s8-dryrun-9890.json 5x/out/s8-dryrun-9899-FM.json -
725a5452026-09-19 Add-modal: session counter survived only until the modal opened — addTitle.textContent wiped the #sessCount child span, so 'N this session' could never render. Title text now lives in #addTitleTxt. F7.0-F7.2 pass (sweep 7) -
4084d072026-09-19 Add-modal: scrollable overlay (flex-start + overflow-y:auto, card margin:auto) — iPhone 390x844 close/vendor/Preview were unreachable; the sweep-1 fix was logged but never committed. F2m + F1/F6/F9/F12 pass locally (sweep 6) -
237a9ab2026-09-19 auto-data-snapshot: 2026-09-19T11:03:02 (4 data files) — 5x/out/features-sweep5.json 5x/out/features-sweep6.json 5x/out/s5-dryrun-9890.json 5x/out/s5-dryrun-9899-FM.json -
f121f542026-09-19 5x: archive stale July-7 sweep notes so they cannot be mistaken for current evidence (Cody #3) -
1855b9b2026-09-19 5x: sweep-1 evidence screenshots (iPad chips, iPad/iPhone add-modal) -
ed3e9092026-09-19 auto-data-snapshot: 2026-09-19T10:31:17 (3 data files) — 5x/out/features-sweep2.json 5x/out/features-sweep3.json 5x/out/features-sweep4.json -
26941e32026-09-19 chore: lint, refactor, v1.6.1 (session close) — 5x batch harness: track() closure, dead cal/increment removed, eslint browser-globals for harness -
97b02332026-09-19 5x: batch UI calibrates via real #cSave (no synthetic cal seed); B7.10 resume-cal + B7.11 fall-through — 33/33 vs 5f0e9fc -
5f0e9fc2026-09-19 Batch shoot: Resume now restores calibration (was shooting with cal=null) -
7100b302026-09-19 DEVICE-TEST: batch — panel position persistence + WYSIWYG master-vs-original verify step -
1d4b6042026-09-19 5x: add Batch Shoot Mode (/batch) coverage — side-named batch-shot, gate, toolpanel -
243f2672026-09-19 Batch shoot: live WYSIWYG colour tools + PSku/Info two-shot flow + TWIL vendor -
7a758b52026-09-19 auto-data-snapshot: 2026-09-19T09:59:20 (4 data files) — data/batch-sessions/smoke-test.jsonl data/batch-sessions/smoke3.jsonl data/build.json data/scan-log.jsonl -
243f75a2026-09-19 DEVICE-TEST: batch checklist for PSku→Info two-shot flow, side-named files, WYSIWYG sliders, toolpanel -
23bf8042026-09-19 Batch capture: harden against camera death + low-confidence SKU -
721a8a62026-09-19 auto-data-snapshot: 2026-09-19T08:55:30 (2 data files) — data/scan-log.jsonl data/vendor_profiles.json -
036345c2026-09-19 auto-data-snapshot: 2026-09-19T04:40:20 (1 data files) — data/color-dots.json -
1c505d92026-09-19 auto-data-snapshot: 2026-09-19T03:36:55 (1 data files) — data/color-dots.json -
caccd252026-09-18 auto-data-snapshot: 2026-09-18T15:26:25 (6 data files) — 5x/fixtures/warm-cast.y4m 5x/out/features-sweep1.json 5x/out/s1-dryrun-9890.json 5x/out/s1-dryrun-9899-FM.json data/build.json -
ac3ec662026-09-18 Batch UI: redo as a simple 1-2-3 wizard with plain-English explanations -
40f89a12026-09-18 auto-data-snapshot: 2026-09-18T14:54:24 (2 data files) — data/build.json data/scan-log.jsonl -
14ba7452026-09-18 Photo capture: linear 2-photo flow, Measure Depth, White Balance, colour hue, continue-able batch, mic-every-field -
a138b392026-09-18 Batch OCR: load GEMINI_API_KEY from secrets + default to gemini engine -
bad2f482026-09-18 auto-data-snapshot: 2026-09-18T14:19:46 (2 data files) — data/build.json data/scan-log.jsonl -
b99e4d92026-09-18 Photo capture: installable PWA — DW-branded home-screen icon (iPad/iPhone) -
4cbb39e2026-09-18 Photo capture: two-photo capture + mfr# identity gate (front-OCR/back-OCR/manual) -
c03988d2026-09-18 Photo capture: post each metafield with its store-defined type (fix 422) -
37a26822026-09-18 auto-data-snapshot: 2026-09-18T13:45:34 (2 data files) — data/build.json data/scan-log.jsonl -
e74d7de2026-09-18 batch mode: vendor is now a dropdown (catalog vendor list) instead of free text -
0c8c48f2026-09-18 Photo capture: vendor picker → sticky overlay bar on the live camera -
0a65a032026-09-18 Photo capture: vendor-first new-SKU creation across Shopify + dw_unified + FileMaker -
70ed1672026-09-18 batch mode: OCR falls back to manual after a timeout (no more 30s hang) -
e43af572026-09-18 auto-data-snapshot: 2026-09-18T11:01:55 (1 data files) — data/batch-sessions/TESTSESSION-smoke.jsonl -
39ffa6e2026-09-18 batch mode: draw the light-reference band live during shooting too -
02ce83c2026-09-18 batch mode: fix gate + queue bugs from contrarian review -
374d9952026-09-18 auto-data-snapshot: 2026-09-18T10:30:02 (1 data files) — data/build.json -
acf1bf82026-09-18 batch: add Batch Shoot Mode (production-line capture for 400+ samples) -
84755d92026-09-18 auto-data-snapshot: 2026-09-18T04:37:40 (1 data files) — data/color-dots.json -
8b771052026-09-18 auto-data-snapshot: 2026-09-18T03:33:53 (1 data files) — data/color-dots.json -
05bcfcd2026-09-17 auto-data-snapshot: 2026-09-17T04:30:36 (1 data files) — data/color-dots.json -
77c28102026-09-17 auto-data-snapshot: 2026-09-17T03:58:38 (1 data files) — data/color-dots.json -
690f7422026-09-16 auto-data-snapshot: 2026-09-16T04:39:34 (1 data files) — data/color-dots.json -
1a17ae22026-09-16 auto-data-snapshot: 2026-09-16T03:35:57 (1 data files) — data/color-dots.json -
42047ed2026-09-15 chore: commit code deployed in 2026-09-15 fleet push -
b0d1b1e2026-09-15 auto-data-snapshot: 2026-09-15T04:27:49 (1 data files) — data/color-dots.json -
75cca4c2026-09-15 auto-data-snapshot: 2026-09-15T03:56:10 (1 data files) — data/color-dots.json -
2d472c12026-09-14 auto-data-snapshot: 2026-09-14T04:37:30 (1 data files) — data/color-dots.json -
825ecfa2026-09-14 auto-data-snapshot: 2026-09-14T03:34:24 (1 data files) — data/color-dots.json -
ffdc98e2026-09-13 auto-data-snapshot: 2026-09-13T04:15:01 (1 data files) — data/color-dots.json -
3bee7ae2026-09-13 auto-data-snapshot: 2026-09-13T03:42:21 (1 data files) — data/color-dots.json -
4f9634d2026-09-12 auto-data-snapshot: 2026-09-12T04:26:59 (1 data files) — data/color-dots.json -
9ae13602026-09-12 auto-data-snapshot: 2026-09-12T03:53:49 (1 data files) — data/color-dots.json -
b56600e2026-09-11 auto-data-snapshot: 2026-09-11T04:24:06 (1 data files) — data/color-dots.json -
96b8c8d2026-09-11 auto-data-snapshot: 2026-09-11T03:51:39 (1 data files) — data/color-dots.json -
b8aa7682026-09-10 guard TK-11357 Fix D: create_22_new.py minted price-LESS rolls already stocked at 2026 -
625721e2026-09-10 auto-data-snapshot: 2026-09-10T04:15:51 (1 data files) — data/color-dots.json -
eff7edc2026-09-10 auto-data-snapshot: 2026-09-10T03:43:17 (1 data files) — data/color-dots.json -
5f0be7e2026-09-09 auto-data-snapshot: 2026-09-09T04:40:57 (1 data files) — data/color-dots.json -
5d67be12026-09-09 auto-data-snapshot: 2026-09-09T03:37:19 (1 data files) — data/color-dots.json -
30367f12026-09-08 auto-data-snapshot: 2026-09-08T04:33:12 (1 data files) — data/color-dots.json -
4fc4f062026-09-08 auto-data-snapshot: 2026-09-08T03:55:22 (1 data files) — data/color-dots.json -
646369e2026-09-07 auto-data-snapshot: 2026-09-07T04:15:57 (1 data files) — data/color-dots.json -
c47ea8d2026-09-07 auto-data-snapshot: 2026-09-07T03:37:33 (1 data files) — data/color-dots.json -
d17fdf72026-09-06 auto-data-snapshot: 2026-09-06T04:34:41 (1 data files) — data/color-dots.json -
c61c7f42026-09-06 auto-data-snapshot: 2026-09-06T03:56:22 (1 data files) — data/color-dots.json -
424dcfa2026-09-05 auto-data-snapshot: 2026-09-05T04:17:39 (1 data files) — data/color-dots.json -
1af06072026-09-05 auto-data-snapshot: 2026-09-05T03:39:28 (1 data files) — data/color-dots.json -
02b92ea2026-09-04 auto-data-snapshot: 2026-09-04T04:33:28 (1 data files) — data/color-dots.json -
f0906592026-09-04 auto-data-snapshot: 2026-09-04T03:52:16 (1 data files) — data/color-dots.json -
50f78c52026-09-03 auto-data-snapshot: 2026-09-03T04:44:57 (1 data files) — data/color-dots.json -
d64e7f12026-09-03 auto-data-snapshot: 2026-09-03T04:07:16 (1 data files) — data/color-dots.json -
488f4ab2026-09-02 repair autonomous color index rebuild -
731dcfa2026-09-02 auto-data-snapshot: 2026-09-02T04:39:22 (1 data files) — data/color-dots.json -
d854b022026-09-01 auto-data-snapshot: 2026-09-01T04:43:03 (1 data files) — data/color-dots.json -
e89cb1a2026-08-31 auto-data-snapshot: 2026-08-31T04:30:23 (1 data files) — data/color-dots.json -
ac431212026-08-30 deploy-safety: exclude data/ from rsync (TK-10984) -
1407ed72026-08-30 add creds-in-URL fetch guard to gated pages (TK-10984) -
e27fa612026-08-30 auto-data-snapshot: 2026-08-30T04:46:23 (1 data files) — data/color-dots.json -
ac2ed262026-08-30 auto-data-snapshot: 2026-08-30T03:31:23 (1 data files) — data/color-dots.json -
3ad79022026-08-29 auto-data-snapshot: 2026-08-29T04:46:12 (1 data files) — data/color-dots.json -
7e6c2782026-08-29 auto-data-snapshot: 2026-08-29T03:31:35 (1 data files) — data/color-dots.json -
ab4806e2026-08-28 auto-data-snapshot: 2026-08-28T04:38:35 (1 data files) — data/color-dots.json -
76dc4102026-08-28 auto-data-snapshot: 2026-08-28T04:01:51 (1 data files) — data/color-dots.json -
0e3b7c42026-08-27 auto-data-snapshot: 2026-08-27T04:38:11 (1 data files) — data/color-dots.json -
0e657302026-08-27 auto-data-snapshot: 2026-08-27T04:01:50 (1 data files) — data/color-dots.json -
539e67e2026-08-26 auto-data-snapshot: 2026-08-26T04:39:06 (1 data files) — data/color-dots.json -
412b7ce2026-08-26 auto-data-snapshot: 2026-08-26T04:02:16 (1 data files) — data/color-dots.json -
bdc246b2026-08-25 creds-safe fetch guard: resolve relative fetch vs credential-free location (creds-in-URL trap) -
87ae2c52026-08-25 auto-data-snapshot: 2026-08-25T04:35:37 (1 data files) — data/color-dots.json -
cf6bcc92026-08-25 auto-data-snapshot: 2026-08-25T03:58:57 (1 data files) — data/color-dots.json -
38a39ec2026-08-24 auto-data-snapshot: 2026-08-24T04:45:01 (1 data files) — data/color-dots.json -
ff4610e2026-08-24 auto-data-snapshot: 2026-08-24T03:41:17 (1 data files) — data/color-dots.json -
eb531a72026-08-23 auto-data-snapshot: 2026-08-23T04:19:03 (1 data files) — data/color-dots.json -
7cb47722026-08-23 auto-data-snapshot: 2026-08-23T03:47:15 (1 data files) — data/color-dots.json -
8b50b572026-08-22 auto-data-snapshot: 2026-08-22T04:22:57 (1 data files) — data/color-dots.json -
0d2a33e2026-08-22 auto-data-snapshot: 2026-08-22T03:51:11 (1 data files) — data/color-dots.json -
833f1802026-08-21 auto-data-snapshot: 2026-08-21T04:29:08 (1 data files) — data/color-dots.json -
d7bda182026-08-21 auto-data-snapshot: 2026-08-21T03:57:28 (1 data files) — data/color-dots.json -
8cadf1f2026-08-20 auto-data-snapshot: 2026-08-20T04:44:35 (1 data files) — data/color-dots.json -
32bb5012026-08-20 auto-data-snapshot: 2026-08-20T03:38:46 (1 data files) — data/color-dots.json -
80558a82026-08-19 auto-data-snapshot: 2026-08-19T04:17:42 (1 data files) — data/color-dots.json -
f94162f2026-08-19 auto-data-snapshot: 2026-08-19T03:46:07 (1 data files) — data/color-dots.json -
aed22732026-08-18 auto-data-snapshot: 2026-08-18T04:37:55 (1 data files) — data/color-dots.json -
d0fe1352026-08-18 auto-data-snapshot: 2026-08-18T03:37:22 (1 data files) — data/color-dots.json -
7575b382026-08-17 snapshot before restart: preserve in-flight work (auto-saved by /restart pre-reboot) -
8fc972d2026-08-17 auto-data-snapshot: 2026-08-17T04:29:37 (1 data files) — data/color-dots.json -
d62c63f2026-08-17 auto-data-snapshot: 2026-08-17T03:59:16 (1 data files) — data/color-dots.json -
029ddeb2026-08-16 auto-data-snapshot: 2026-08-16T04:20:17 (1 data files) — data/color-dots.json -
e99b6742026-08-16 auto-data-snapshot: 2026-08-16T03:49:55 (1 data files) — data/color-dots.json -
0cb4ba72026-08-15 auto-data-snapshot: 2026-08-15T04:38:51 (1 data files) — data/color-dots.json -
70c224f2026-08-15 auto-data-snapshot: 2026-08-15T03:38:01 (1 data files) — data/color-dots.json -
09346362026-08-14 auto-data-snapshot: 2026-08-14T04:16:15 (1 data files) — data/color-dots.json -
36acc482026-08-14 auto-data-snapshot: 2026-08-14T03:45:50 (1 data files) — data/color-dots.json -
cbb71442026-08-13 auto-data-snapshot: 2026-08-13T15:04:38 (4 data files) — visual-search/train/.gitignore visual-search/train/HANDOFF.md visual-search/train/__pycache__/finetune.cpython-312.pyc visual-search/train/__pycache__/finetune_aug.cpython-312.pyc -
fe6cef32026-08-13 auto-data-snapshot: 2026-08-13T04:16:27 (1 data files) — data/color-dots.json -
dfdac892026-08-13 auto-data-snapshot: 2026-08-13T03:45:50 (1 data files) — data/color-dots.json -
e1301ca2026-08-12 auto-data-snapshot: 2026-08-12T04:15:31 (1 data files) — data/color-dots.json -
ea930772026-08-12 auto-data-snapshot: 2026-08-12T03:44:41 (1 data files) — data/color-dots.json -
2e3fe5b2026-08-11 auto-data-snapshot: 2026-08-11T04:29:53 (1 data files) — data/color-dots.json -
e8477572026-08-11 auto-data-snapshot: 2026-08-11T03:59:02 (1 data files) — data/color-dots.json -
3cb011d2026-08-10 auto-data-snapshot: 2026-08-10T04:16:24 (1 data files) — data/color-dots.json -
1235d6a2026-08-10 auto-data-snapshot: 2026-08-10T03:45:26 (1 data files) — data/color-dots.json -
a2a39ee2026-08-09 auto-data-snapshot: 2026-08-09T04:37:25 (1 data files) — data/color-dots.json -
1af553b2026-08-09 auto-data-snapshot: 2026-08-09T03:35:42 (1 data files) — data/color-dots.json -
98ee7ea2026-08-07 auto-data-snapshot: 2026-08-07T04:23:46 (1 data files) — data/color-dots.json -
662c6722026-08-07 auto-data-snapshot: 2026-08-07T03:53:01 (1 data files) — data/color-dots.json -
baec7aa2026-08-06 auto-save: 2026-08-06T04:18:20 (1 files) — data/color-dots.json -
39c92592026-08-06 auto-save: 2026-08-06T03:48:10 (1 files) — data/color-dots.json -
1565c162026-08-05 auto-save: 2026-08-05T04:39:04 (1 files) — data/color-dots.json -
deec7342026-08-05 auto-save: 2026-08-05T03:38:44 (1 files) — data/color-dots.json -
98368f62026-08-04 auto-save: 2026-08-04T04:29:46 (1 files) — data/color-dots.json -
80c5a952026-08-04 auto-save: 2026-08-04T03:59:36 (1 files) — data/color-dots.json -
d85c5042026-08-03 auto-save: 2026-08-03T04:20:12 (1 files) — data/color-dots.json -
318f2b02026-08-03 auto-save: 2026-08-03T03:50:03 (1 files) — data/color-dots.json -
e3beb542026-08-02 auto-save: 2026-08-02T04:42:12 (1 files) — data/color-dots.json -
e7d41582026-08-02 auto-save: 2026-08-02T03:41:50 (1 files) — data/color-dots.json -
d2c1d792026-08-01 auto-save: 2026-08-01T04:33:25 (1 files) — data/color-dots.json -
1ae3d542026-08-01 auto-save: 2026-08-01T03:33:03 (1 files) — data/color-dots.json -
bd293112026-07-31 auto-save: 2026-07-31T09:26:15 (1 files) — server.js -
b890acb2026-07-31 auto-save: 2026-07-31T04:23:41 (1 files) — data/color-dots.json -
7ab6ab02026-07-31 auto-save: 2026-07-31T03:53:30 (1 files) — data/color-dots.json -
9551f9b2026-07-30 auto-save: 2026-07-30T04:44:39 (1 files) — data/color-dots.json -
2c82b3c2026-07-30 auto-save: 2026-07-30T03:44:22 (1 files) — data/color-dots.json -
f58ad8d2026-07-29 auto-save: 2026-07-29T20:42:08 (1 files) — package-lock.json -
31162352026-07-29 chore: v1.6.0 — public /marketing static route for email assets (session close) -
ba0e2742026-07-29 Add bounded public /marketing/ static route (images only, traversal-safe) + color-coordinate demo GIF for email hosting -
d2042832026-07-29 auto-save: 2026-07-29T04:35:46 (1 files) — data/color-dots.json -
f9dbf0d2026-07-29 auto-save: 2026-07-29T03:35:26 (1 files) — data/color-dots.json -
e9448322026-07-28 auto-save: 2026-07-28T04:27:17 (1 files) — data/color-dots.json -
20856852026-07-28 auto-save: 2026-07-28T03:57:08 (1 files) — data/color-dots.json -
7f05d6c2026-07-27 auto-save: 2026-07-27T04:17:53 (1 files) — data/color-dots.json -
d407efc2026-07-27 auto-save: 2026-07-27T03:47:45 (1 files) — data/color-dots.json -
210a2792026-07-26 auto-save: 2026-07-26T04:40:35 (1 files) — data/color-dots.json -
80387932026-07-26 auto-save: 2026-07-26T03:40:20 (1 files) — data/color-dots.json -
89699fd2026-07-25 auto-save: 2026-07-25T04:33:37 (1 files) — data/color-dots.json -
77c6b642026-07-25 auto-save: 2026-07-25T03:33:15 (1 files) — data/color-dots.json -
d7be4c62026-07-24 auto-save: 2026-07-24T04:25:19 (1 files) — data/color-dots.json -
98b67d22026-07-24 auto-save: 2026-07-24T03:55:12 (1 files) — data/color-dots.json -
d17f80f2026-07-23 auto-save: 2026-07-23T04:18:33 (1 files) — data/color-dots.json -
c643cf02026-07-23 auto-save: 2026-07-23T03:48:26 (1 files) — data/color-dots.json -
214f7fb2026-07-22 auto-save: 2026-07-22T04:41:22 (1 files) — data/color-dots.json -
22fe1cb2026-07-22 auto-save: 2026-07-22T03:41:10 (1 files) — data/color-dots.json -
52d98a42026-07-21 chore: lint (drop unused HSL l), refactor (familyOf hue comment, hexToRgb param), v1.5.1 (session close) -
f7337962026-07-21 auto-save: 2026-07-21T04:35:41 (1 files) — data/color-dots.json -
904218b2026-07-21 auto-save: 2026-07-21T03:35:30 (1 files) — data/color-dots.json -
d684bcb2026-07-20 auto-save: 2026-07-20T04:29:52 (1 files) — data/color-dots.json -
2a2122c2026-07-20 auto-save: 2026-07-20T03:59:45 (1 files) — data/color-dots.json -
e0020542026-07-19 shop-by-color: data-driven ΔE-collapsed color dots (real DB hexes, ≥20 patterns, qty-ordered) -
a9c6a112026-07-19 chore: version-up v1.5.0 (session close — shop-by-color product_type) -
8112eaf2026-07-17 color-index: carry product_type through builder + both /apps/color-index and /apps/color-widen results (shop-by-color type checkboxes) -
0d6c3552026-07-16 color-widen: add min param — guarantee >=N results via nearest-neighbor fallback when the band is thin -
e2c9e012026-07-16 add /apps/color-widen route: tunable ΔE band (default 15%) for the Shop-by-Color wheel at /pages/colors -
5d305fe2026-07-15 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) -
42148682026-07-15 add nightly color-index refresh script + launchd plist (DRAFT — install gated): build from live shopify_products, rsync json to Kamatera (endpoint hot-reloads) -
91ce1712026-07-15 deps: add pg so build-color-index runs standalone (needed for scheduled rebuild) -
61eee412026-07-15 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 -
dd6e4162026-07-13 chore: session close snapshot (visual-search) -
2212c212026-07-13 nightly embed top-up script + plist draft (coverage anti-decay: both embedders resumable + index hot-reload) -
bdba9e22026-07-13 visual-search: path-(a) Kamatera self-host bundle (lite venv, no torch; pm2 unit reading local dw_unified) — verified 71MB footprint -
fcb1edb2026-07-13 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) -
95931a92026-07-13 auto-save: 2026-07-13T00:51:43 (2 files) — visual-search/__pycache__/search_service.cpython-312.pyc visual-search/search_service.py -
a0e586b2026-07-13 visual-search: make bind host configurable via VS_HOST (default 127.0.0.1, unchanged); enables opt-in tailnet exposure for remote consumers -
2890b8f2026-07-12 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 -
ca63a1e2026-07-12 auto-save: 2026-07-12T23:21:12 (1 files) — visual-search/.gitignore -
c913d7d2026-07-09 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 -
7c5ada12026-07-09 auto-save: 2026-07-09T22:12:24 (1 files) — package-lock.json -
bb7bf3e2026-07-09 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) -
6aa4a182026-07-09 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/ -
30757b52026-07-09 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 -
d52d7652026-07-09 auto-save: 2026-07-09T16:11:12 (2 files) — schu-candidates.tsv schu-publish.mjs -
8ef6e5f2026-07-09 auto-save: 2026-07-09T09:09:49 (1 files) — visual-search/__pycache__/ -
602bb7f2026-07-09 PDP color-dot color-index: /apps/color-index endpoint + generator (catalog-wide 10% CIELAB tolerance) -
41d871a2026-07-09 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 -
0bd91872026-07-09 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) -
036d1302026-07-09 auto-save: 2026-07-09T08:39:40 (2 files) — public/index.html screenrecord/ -
ab7c20f2026-07-08 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 -
dd49fa42026-07-08 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 -
71b85742026-07-08 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 -
d5ff7da2026-07-08 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 -
ef6656d2026-07-08 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 -
6eb90132026-07-08 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 -
c473b212026-07-08 dwphoto: add SSRF-guarded CORS-scoped /apps/similar proxy route → loopback CLIP :9914 (shipped GATED-STEP-1) -
06f58392026-07-08 visual-search /similar: also return storefront handle (LEFT JOIN shopify_products) so PDP cards link to real product pages -
3e6d84f2026-07-08 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 -
51cf1882026-07-08 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 -
c68081a2026-07-08 visual-search: add POST /similar (SKU->CLIP visual neighbors, color+style soft re-rank, lazy CLIP load) -
a7f63742026-07-08 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 -
5cea2c82026-07-08 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 -
8837b5f2026-07-08 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 -
c3d84292026-07-08 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 -
d4db33e2026-07-08 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 -
b56afa12026-07-08 auto-save: 2026-07-08T11:35:28 (1 files) — package-lock.json -
66895a72026-07-08 chore: v1.2.0 → v1.3.0 (session close — feed + discontinued-successor features) -
5f86fc52026-07-08 auto-save: 2026-07-08T11:05:21 (1 files) — data/build.json -
ba637862026-07-08 Add discontinued-SKU resolver → red card → live successor link (local only) -
140c9942026-07-08 gitignore the runtime all-dw feed cache (data/all-catalog.json) -
a4417e32026-07-08 browse whole dw_unified catalog via all-dw feed (was Fentucci-only); disk-cache + Fentucci fallbacks -
62ce2a42026-07-08 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 -
999db252026-07-08 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 -
427db512026-07-07 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 -
2d627ac2026-07-07 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) -
17b5c682026-07-07 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 -
2acc59c2026-07-07 auto-save: 2026-07-07T13:30:45 (1 files) — visual-search/train/__pycache__/finetune_aug.cpython-312.pyc -
e56063d2026-07-07 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) -
27b572c2026-07-07 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) -
a376a2d2026-07-07 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) -
de2aca32026-07-07 robustness_fusion: note CDN rate-limiting makes the A/B unreliable; fusion verified directly (3-view demo promotes the corroborated match) -
6cdd9d92026-07-07 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) -
724673e2026-07-07 auto-save: 2026-07-07T13:00:27 (1 files) — visual-search/train/__pycache__/finetune_aug.cpython-312.pyc -
33641ca2026-07-07 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 -
54e085f2026-07-07 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) -
6a137d92026-07-07 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) -
8694d872026-07-07 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) -
828996f2026-07-07 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) -
cf2ea4a2026-07-07 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 -
7d4ccb62026-07-07 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) -
ec02bd72026-07-07 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) -
5673cad2026-07-06 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 -
1570feb2026-07-06 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 -
a2500f82026-07-06 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. -
8cff6c42026-07-06 Camera-unavailable UX: detect Chrome/3rd-party iOS browsers (no getUserMedia) and tell user to open in Safari, instead of a cryptic error -
b0a3ecc2026-07-06 Handoff doc: how to wire the fine-tuned DW CLIP weights into visual search (sanity-check, re-embed both sides, gate the reindex, rollback) -
da94b6f2026-07-06 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 -
b87d4022026-07-06 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) -
5126f022026-07-06 Overnight DW CLIP fine-tune pipeline (MPS): build_manifest + resumable 256px downloader + open_clip contrastive fine-tune + overnight orchestrator -
942ce162026-07-06 5x: 2 consecutive clean sweeps (0 app defects) — six-way + functional + headless-flow all green; 2 caught items proven harness artifacts -
aa3a6ce2026-07-06 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 -
4a51d5b2026-07-06 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 -
29237c62026-07-06 Sticker loop web side LIVE: web_print_request field placed + FM_PRINT_FLAG_FIELD configured on Kamatera; dryRun-verified Print writes sent-date + sku/address flag -
c0cf2c52026-07-06 Add 3 photo slots to Add-item (Front·pattern / Back·label / Detail): label photo drives spec extraction, all 3 attach as ordered Shopify product images (front primary) -
eae81b82026-07-06 Add per-field 🎤 mic buttons on every Add-item field (dictate straight into Mfr#/Vendor/VID/Color/Name/Price) + prominent Voice-fill button -
28573392026-07-06 FileMaker sticker setup: STEP 1 now requires placing web_print_request on the target layout (Data API can only write layout-present fields) -
d548ec82026-07-06 Generalize spec capture to any spec sheet or sample: read product material (Wallcovering/Fabric/Trim/…), drive Shopify product_type + metafield off it, persist full spec set to new_items_staging.specs jsonb -
3fcbec52026-07-06 Capture full wallcovering spec set on scan (repeat/width/roll length/match/substrate/how-sold/collection/price code) → metafields + read-only specs panel in add-item -
264f5cc2026-07-06 feat: max-info extract on scan + voice-only-as-needed. /api/extract: Gemini pulls EVERY label field (vendor, mfr, pattern, colorway, collection, width, length, repeat, content, price) + fuzzy-maps vendor. Add-item photo auto-prefills all fields. Then voice ONLY as needed: if a required field (mfr/vendor) is still blank, the app SPEAKS the prompt (‘Enter vendor name’) via TTS + listens, while the dropdown stays usable + the field is highlighted. Verified extract: WDW2310/Winfield/Compass Clay. -
496dc6c2026-07-06 chore: embed-daemon.sh — resumable batch loop (20k chunks + auto-reload vsearch index), run via nohup + @reboot cron on Kamatera for reboot-resume. Replaces bare nohup embed. (pm2 wouldn't register the bash daemon reliably.) -
2e4814d2026-07-06 feat: onload chooser — 3 white-on-black pills (Add New SKU / Update SKU / Check Sample In), centered 3 rows. Routes: Add→new-item modal, Update→live scan, Check→front/back identify. ⌂ home button reopens; skip→ goes to catalog. Verified on mobile viewport, 0 pageerrors. -
94d5ee92026-07-06 5x: app clean across 2 sweeps — M1/M2/B4 pass, 85 tests, both new modals open, 163-vendor dropdown, 0 console errors, all new endpoints live. M3 flake = harness no-auth + batch load (networkidle settles 1.24s with auth). WebKit skip = install tooling. No app fixes needed. -
9a593762026-07-06 feat: add new SKU to dw_unified + Shopify (draft) with vendor/vid dropdown -
ac1d6d02026-07-06 feat: front+back identify UI + QR/vendor clues. #fbModal captures back label + front pattern; client jsQR decodes QR silently (extracts SKU token, never navigates); server fuses code+QR+vendor+visual. QR token filter requires a digit (skips domain words). Vendor name off the label used to weight visual + fill primary. Verified: QR URL→TR2581→RHT264/Seabrook. -
023d1b22026-07-06 feat: CLIP visual search + multi-photo front/back fusion identify -
873541c2026-07-06 feat: visual identify — Gemini compares the ACTUAL user photo against candidate catalog IMAGES (not typed attributes) and floats the true pixel-match to the front, or honestly reports no-match. Adds fetchImageB64 + geminiVisualMatch; /api/recognize returns a visual{} block. ~$0.0036/recognize (6 imgs). Correctly rejected 5 non-matching grasscloths in test. -
11691f42026-07-06 feat: Option B — Mac-side sticker watcher (use both). sticker-watcher.js polls FileMaker for web_print_request-flagged records, fires the existing print script via AppleScript do-script (combo-sku param), clears the flag; reuses fm-client.js, loads FM creds from filemaker-mcp/.env. launchd plist staged (not started — needs field + real print-script names). Doc: arm ONLY ONE of A/B (double-print race); DTD favored A, B built as the no-FileMaker-window option. -
8d68c8e2026-07-06 docs: precise 2-step FileMaker setup (create web_print_request field + Web Sticker Poller script) — Data API can't create schema/scripts; server pre-staged to activate on field creation. Includes Mac-side AppleScript-watcher alternative. -
5e674582026-07-06 5x: report — desktop + mobile Chrome PASS (0 console errors), lazy-thumb fix (414→4 reqs), M3=harness auth artifact. WebKit engine install broken on this box (tooling, not app). -
060b63d2026-07-06 5x sweep: lazy-load grid thumbnails (IntersectionObserver) — grid used CSS background-images (can't use loading=lazy) so a big filter loaded 100s of images at once. Now bg applies only on-visible: +414 requests after load → +4. Big mobile win; networkidle settles 2.3s. No console errors. -
77542212026-07-06 fix: print-sticker no longer hangs + go-live hardening -
1f9cc3b2026-07-06 docs: FileMaker sticker setup — flag field + OnTimer poller (reuse existing print/stamp scripts) + FM_WRITE gate. Deployed read-only FM creds to Kamatera; sample-request lookup live (Maya50162→Haley McKinley w/ image), print-sticker dry-run until flag field designated. -
7f00ab42026-07-06 feat: sample-request sticker popup + scan cost throttle -
31dbd122026-07-06 feat: FileMaker sample-request lookup + print-sticker handoff -
a9856732026-07-06 feat: best-ID identify-first against unified catalog — identifyUnified(code) resolves a scanned code via dw_sku_crossref (267k, shares FileMaker's Mfr Pattern/combo sku vocabulary) to canonical {internal_sku, mfr_sku, vendor} + best-effort image/title from shopify_products. New GET /api/identify-unified. Verified: TR2581→RHT264/Seabrook, 83615→VIC261B w/ image. -
5483a672026-07-06 feat: hone in on the text — OCR now reads a centered, upscaled ROI (guide-box region, 5:2, up to 2x) instead of the whole frame, so small printed SKUs read sharper; full frame retained for logo/pattern match -
9277da42026-07-06 fix: dw_unified 'match design' works on Kamatera — drop non-existent min_variant_price column from unifiedSimilar (Kamatera schema differs from mac2); app now returns similar products. DW_UNIFIED_DB accepts a full postgres:// URI (app runs as root, no PG role). Verified: grasscloth swatch → 48 products live. -
1ffca172026-07-06 feat: structured field auto-detect (sku#/model#/name/color) + live green highlight + per-vendor spec learning -
761b3562026-07-06 feat: front side auto-matches the design — hold steady on the pattern face → auto-fires /api/recognize (reuses the match path) instead of only prompting a flip; resets on code/open/close -
91923282026-07-06 feat: auto front/back side detection on scan — analyzeOcr classifies label(back) vs pattern-face(front) from OCR density ($0, per-frame); live scanner shows '🎨 flip to the label' on the pattern side. +5 tests (79 total) -
b7eee402026-07-06 chore: photocapture LIVE on Kamatera at photo.designerwallcoverings.com (pm2 dwphoto :9912, gemini engine, CF-proxied + LE cert); retire Mac tunnel -
d3b12d12026-07-06 chore: Kamatera deploy artifacts — .deploy.conf (gemini engine, /healthz smoke), .env.example, DEPLOY.md runbook -
75c75e32026-07-06 feat: pluggable vision engines (macvision|gemini|gcv), runtime-selectable + engine=all — enables Linux/Kamatera hosting -
7bb65212026-07-06 docs: expose photocapture publicly via Cloudflare Tunnel at photo.designerwallcoverings.com (Mac-bound; CF edge TLS for camera) -
ea390e52026-07-03 chore: macstudio3 migration — reconcile from mac2 + repoint paths (stevestudio2→macstudio3, node/npm/npx→/opt/homebrew) -
70f9dc02026-06-26 auto-save: 2026-06-26T10:45:01 (2 files) — OVERNIGHT_LEDGER.md package-lock.json -
fbc4b682026-06-26 chore: lint clean, refactor (none needed), v1.1.0 (session close) -
06f58bc2026-06-26 chore: v1.1.0 — 🎨 Recognize Pattern feature (session close) -
6407d112026-06-26 test: lock parseOcrRows barcode branches + overnight wind-down note (cycle 23) -
25e95322026-06-26 test: cover nmfr + brandRe normalizers (cycle 22) -
2e6d31c2026-06-26 test: cover mfrToHouseSku resolver (cycle 21) -
93cd3e42026-06-26 auto-save: 2026-06-26T08:43:59 (1 files) — data/build.json -
eb1e5462026-06-26 test: reject O/0 OCR fallback (real collisions) + lock verbatim-code contract (cycle 20) -
e3483ef2026-06-26 observability: add /api/stats; backlog O/0 OCR fallback with evidence (cycle 19) -
c3b1b212026-06-26 auto-save: 2026-06-26T08:13:39 (2 files) — data/build.json data/vendor_profiles.json -
4d8fe6d2026-06-26 robustness: atomic saveJSON so a crash/ENOSPC can't corrupt persisted data (cycle 18) -
d9df0cb2026-06-26 test: lock candidate-order contract scanResolve relies on (cycle 17 audit) -
5980db12026-06-26 auto-save: 2026-06-26T07:13:19 (2 files) — data/build.json data/vendor_profiles.json -
830b25f2026-06-26 fuzzy: ambiguity guard so a partial read can't bind the wrong vendor (cycle 16) -
f35ef392026-06-26 security: fix /api/learn prototype-pollution DoS (cycle 15) -
bf76d612026-06-26 auto-save: 2026-06-26T06:43:07 (1 files) — data/build.json -
a3b00cc2026-06-26 harden: prefix support gate so one bad scan can't corrupt learned prefixes (cycle 14) -
3eaa90d2026-06-26 auto-save: 2026-06-26T06:12:56 (1 files) — data/build.json -
ad48b182026-06-26 Recognize Pattern: strip -SAMPLE suffix from result SKUs (2,900 sample-variant rows showed sample SKU on card) -
f050ab32026-06-26 test: fuzzyVendor edge guards + disk-full debug note (cycle 13) -
0801a442026-06-26 test: fingerprintVendor edge cases + reject OCR-confidence-threshold (cycle 12) -
8f32cd42026-06-26 auto-save: 2026-06-26T05:12:44 (1 files) — data/build.json -
bfd82492026-06-26 scan UX: tentative 'hold steady' cue + reject Swift low-light pre-pass (cycle 11) -
367d1252026-06-26 auto-save: 2026-06-26T02:08:48 (2 files) — data/build.json data/vendor_profiles.json -
2c6e0522026-06-26 test: harden analyzeOcr against adversarial OCR inputs (cycle 10, brainstorm) -
f6b8dec2026-06-26 review: fix 3 findings from session code-review (cycle 9) -
a412dce2026-06-26 auto-save: 2026-06-26T01:38:39 (1 files) — data/build.json -
64ab5082026-06-26 scan: background logo-ID when a code locks but OCR names no vendor (cycle 8) -
d76cc5a2026-06-26 identify: per-request model toggle (moondream fast path) + API.md (cycle 7) -
934a7582026-06-26 auto-save: 2026-06-26T00:38:23 (2 files) — data/build.json data/recents.json -
bf7279e2026-06-26 test: analyzeOcr/vendor unit tests (overnight cycle 6) -
6264e282026-06-26 Recognize Pattern refactor: dedupe SQL term-match, single-trigger visual rerank, shared image-pipe helper, reuse one fingerprint canvas -
94dce122026-06-25 ledger: switch overnight loop to NEVER-STOP idea-adding mode (Steve) -
2a4ae142026-06-25 identify: logo-fingerprint tiebreaker (DTD 3/3 verdict A) -
edd68a92026-06-25 Add 🎨 Recognize Pattern: VLM reads a swatch, finds this + visually-similar items across the whole unified DB -
39a065c2026-06-25 learn: surface logo fingerprint + flag rejected logos (overnight cycle 4) -
dfefc4a2026-06-25 Scan UX: distinct BARCODE lock label (overnight cycle 3) -
b10f11c2026-06-25 Overnight cycle 1-2: selfcheck pass + draft gated weekly vendor-refresh launchd -
3c0bcb12026-06-25 Logos: tighten matcher + validate fingerprints (DTD-A verdict) -
33731b62026-06-25 auto-save: 2026-06-25T23:37:59 (8 files) — build_logo_fingerprints.py build_vendor_logos.py data/build.json data/logos/fabricut.jpg data/vendor_logos.json -
85dccb32026-06-25 Harvest vendor logos from Shopify Files → ground logo recognition -
d30783b2026-06-25 Scan: recognize barcodes (exact SKU) + logos/typeface (local VLM) -
8fae1142026-06-25 auto-save: 2026-06-25T23:07:50 (4 files) — bin/ocr bin/ocr.swift data/build.json server.js -
5ebe4e62026-06-25 Learn how each vendor labels their samples (180 vendor profiles) -
47a5ecf2026-06-25 Ask-the-SKU: voice Q&A about a product via local Ollama ($0) -
fc5196a2026-06-25 auto-save: 2026-06-25T18:36:37 (1 files) — data/recents.json -
3948d6a2026-06-25 Voice search: mic button → speak vendor/SKU/what-to-look-for → search -
610fc302026-06-25 Scan audio: outcome-based — yoo-hoo on resolve, 'uh-oh' on no-match -
a045b5f2026-06-25 Scan: brand-aware fast-lock + RED locked-in state -
89ca6322026-06-25 Scan: audible 'yoo-hoo' cue on code lock-in (v41) -
b9742402026-06-25 Auto-refresh mfr# index: hourly incremental (8-18) + nightly full rebuild -
dcb3fda2026-06-25 auto-save: 2026-06-25T17:36:07 (2 files) — build_mfr_index.py refresh_mfr_index.py -
47fbc5a2026-06-25 Add manufacturer-SKU resolver: scanned vendor codes resolve to DW house SKUs -
8ddb73e2026-06-25 Scan: code numbers ONLY — drop name/prose candidates -
3046f622026-06-25 Scan ranks by font size first (largest letters), WD/Winfield Thybony prefix -
e48f07d2026-06-25 auto-save: 2026-06-25T16:05:06 (2 files) — data/build.json photo-app-qr.png -
9a72bcb2026-06-25 Add dev-only ESLint static gate + remove dead tcase helper -
4ba1fb12026-06-25 Fix front-camera scan: mirror-retry (ocrSmart) recovers backwards-text reads on iOS selfie cam; wired into live + snap scan -
3355c702026-06-25 Camera chooser: back/front toggle (header + live-scan flip), persisted, drives scanner + all capture inputs; fix getLS->LS init crash -
f482ee72026-06-25 Multi-pass OCR scan: try every candidate (DW SKU + mfr# + name) across TWIL then all-Shopify -
7a111392026-06-25 Video uploads: 🎥 Video in gallery → /api/video runs the Shopify staged-upload + productCreateMedia(VIDEO) pipeline (multipart to GCS), 150MB cap. Verified end-to-end + cleaned test -
38324932026-06-25 Crop tool: add aspect-ratio presets (Free / 1:1 / 4:3 / 3:4 / 16:9) — ratio-locked, anchor-based corner resize -
f97337a2026-06-25 Add ✂️ Crop tool to photo editor (drag corners/move, dim outside, bakes into final) + default landing = 🧵 All TWIL + Any-SKU auto-falls-back to all-Shopify (mfr#/DW SKU) when not in TWIL index -
a2e7b322026-06-25 Add 🧵 All TWIL chip (every Fentucci/grasscloth item, not just photos-needed) via /api/twil; confirm 🌐 All Shopify gives access to every vendor's SKUs. GRS-27080 = numbering gap (never assigned) -
ae60fb42026-06-25 auto-save: 2026-06-25T09:33:15 (1 files) — server.js -
ae3352b2026-06-25 Live SKU scanner: HTTPS listener (:9891, self-signed cert) enables getUserMedia; 🔢 Scan streams the camera, OCRs each frame, LOCKS IN when a SKU repeats 2x -> auto-lookup. Falls back to tap-snap over HTTP -
5047a832026-06-25 App starts collapsed (clean landing until filter/search/scan) + re-crawl spreadsheet -> 203 GRS items (DWNAT->GRS col-W backfill) -
54495aa2026-06-25 auto-save: 2026-06-25T09:03:03 (1 files) — data/build.json -
b34052e2026-06-25 Camera SKU scan: 🔢 Scan button → macOS Vision OCR (/api/ocr, local/free) reads a printed mfr#/SKU off a sample book, extracts the SKU token, and jumps to that product in Any-SKU search. bin/ocr Swift binary -
f61b6332026-06-25 Desktop-controlled remote shutter (DTD-C): /desk control page + /cam phone live-camera page, paired via SSE+POST over the tailnet. Desktop SHOOT -> SSE shoot event -> phone captures native-res frame from getUserMedia -> uploads via existing /api/photo -> desktop previews. iOS-hardened (playsinline/muted, 3-tier facingMode, auto-reconnect). No new Shopify auto-write; attach stays operator-triggered. -
8ca15e92026-06-25 auto-save: 2026-06-25T08:32:54 (1 files) — server.js -
8cdab9b2026-06-25 Add /selfcheck self-check: server-side health report (catalog/index/queue/token/data) + auto-cleans stale photo refs (kills the dead-link class); HTML report; version pill links to it. selfcheck.sh runs server + deep Playwright UI crawl -
f90170b2026-06-25 Make PWA icon + manifest public (no auth) so iOS Add-to-Home-Screen fetches them; app routes stay gated -
989aa832026-06-25 Installable PWA: app icon (gold DW/camera) + web manifest + apple-touch-icon + standalone meta — Add to Home Screen now gives a real app icon + fullscreen -
4e6ec3f2026-06-25 Multi-photo add: ➕ Multiple in the Photos gallery batch-appends several shots at once (keeps featured + existing images); /api/photos endpoint, never-upscale each, 12/batch cap -
a4af4402026-06-25 All GRS- sold PER YARD: flipped 133 products (variant Roll->Per Yard, unit_of_measure->Priced Per Yard, dwc.order_unit->Yard); now 174/174 uniform. createFromSheet defaults to per-yard for future creates. Price unchanged (already per-yard) -
3c7d0a22026-06-25 Add ⭐ Favorites + 🕘 Recent views: star any card to pin SKUs you update often; recents auto-log on every upload (server-stored, shared across phone+office) -
3cbfbc02026-06-24 All-Shopify search covers collections too: parallel product + collection-products query, merged/deduped, across every vendor; results carry their collections -
418e9722026-06-24 Add collections to search: each product carries its Shopify collection titles; lookup matches collection name + cards show 📚 collection chips -
087b3862026-06-24 Create 22 net-new GRS drafts (full sheet info, photo->live) + per-SKU photo gallery: 🖼 Photos shows every image with ★ Feature / ✕ Remove / 📷 Add (keep existing). /api/images,/api/image/delete,/api/image/feature -
62e3b372026-06-24 auto-save: 2026-06-24T18:28:52 (1 files) — data/queue.json -
6a655b42026-06-24 Add end-to-end test for All-Shopify search + keep/replace photo paths (11/11 pass; throwaway draft, prod-clean teardown) -
7e0a77d2026-06-24 Add ✨ New (N) filter chip (just the net-new sheet SKUs to create) + fix doubled name==color titles; verified create-on-photo end-to-end (Cremona Parchment created live w/ full info + deleted) -
06a420e2026-06-24 auto-save: 2026-06-24T17:58:43 (3 files) — data/build.json public/index.html test-allshopify.js -
708fac72026-06-24 All-Shopify cards: per-card 'Replace all — make this the only image' toggle (DTD verdict C); default keeps existing imagery, explicit opt-in to wipe -
05042e02026-06-24 Any-SKU: include all 170 TWIL-sheet GRS items; photographing a not-yet-in-Shopify one (22 net-new, deduped by GRS+mfr) creates the product from sheet info + photo and goes live; existing-SKU updates preserve room shots (keep_images) -
b4532b22026-06-24 Add 'All Shopify' button: live store-wide SKU search to update any product's photo from phone (non-destructive — keeps existing images) -
a2403b92026-06-24 Add 'Any SKU' lookup: search all 555 Fentucci products by SKU/model#/name to add or replace any product's photo (in-memory catalog index + /api/lookup) -
89c56862026-06-24 Fix grid density slider + editor preview-equals-export bake -
daf466a2026-06-24 auto-save: 2026-06-24T16:58:22 (3 files) — public/index.html server.js data/build.json -
571e9412026-06-24 auto-save: 2026-06-24T16:28:13 (4 files) — data/queue.json ref-roll.jpg screenshot-roll.png screenshot-sheet.png -
444a6832026-06-24 Send Cache-Control: no-store on HTML so browsers never serve a stale page (was hiding the photo editor after deploy) -
4b82a742026-06-24 Roll: add Curl intensity slider + cycle Flat→Tube→Sheet (curled-sheet variant reveals paper's cream back, like the PR roll shot) -
b6eb1622026-06-24 Add 🗞 Roll button: wrap captured pattern around a tube (cylinder shading + sheen + shadow) like the PR roll shot -
9e8d4992026-06-24 auto-save: 2026-06-24T15:58:04 (2 files) — data/queue.json screenshot-editor.png -
dcdf1c32026-06-24 Add Photoshop-style photo editor (brightness/contrast/saturation/hue + color-balance wheel) with review-before-upload step -
ea8d5f12026-06-24 auto-save: 2026-06-24T15:27:54 (2 files) — public/index.html server.js -
2b07e492026-06-24 DW Pattern Photo Capture: mobile-first (iPhone/iPad) camera worklist for 179 photo-less Fentucci patterns; snaps save locally + attach to Shopify draft (filename=DW SKU, leak-safe); basic-auth, sort+density, client-side downscale
Authors
- Steve358
- auto-commit-fleet126
- steve9
Agents used
- secrets-manager1
- code-reviewer1
- vp-engineering1
Skills used
- /color-dots133
- /claude90
- /code90
- /out19
- /ocr16
- /learn16
- /batch13
- /identify13
- /scan-log10
- /cam8
- /photos8
- /apps8
- /back7
- /recognize7
- /rec7
- /photo6
- /extract6
- /vendor6
- /train6
- /index6
- /create-item5
- /worktrees5
- /saturation5
- /captures4
- /agent-a841f65dcd871d6ac4
- /healthz4
- /model4
- /hue4
- /contrast4
- /name4
Creative ideas + design notes
6286a2f · 2026-09-26 · Swipe picker: Pick this one opens the theme full screen (Back / Esc / Go to the app), Open-your-pick button reopens it; fix filter wiring catching the pick button (TK-12343)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SC2DKkJkSNenmFz2Eqnvpk
28a1391 · 2026-09-26 · Swipe picker: one trackpad swipe/wheel flick = one theme (Safari skipped two); app chooser shows once per tab, not on every load (TK-12343)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SC2DKkJkSNenmFz2Eqnvpk
24bc0c3 · 2026-09-26 · Front screen: one-at-a-time swipe theme picker (Figma v1-v25 + Photoshop Kid-Simple v7-v16); capture app moves to /app (TK-12343)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SC2DKkJkSNenmFz2Eqnvpk
6e2c3f2 · 2026-09-26 · Onload chooser: Adobe Spectrum themes (Light/Dark/Darkest/Auto) + accents, smart Suggested action, full UX (TK-12346)
Themed card chooser with icons, descriptions, 1-4/Enter shortcuts, incoming-samples badge, last-used fallback suggestion, ARIA radiogroups, reduced-motion. Tokens scoped to #homeScreen; theme/accent persisted in localStorage. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BnDgaJLtEUJykffiozVpQF
4ace5d4 · 2026-09-26 · Add /kid-simple/ review page: Kid-Simple mockups v1-v16 + Photoshop board, behind basic-auth (TK-12344)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SC2DKkJkSNenmFz2Eqnvpk
ac13489 · 2026-09-26 · Untrack runtime build counter data/build.json and gitignore it
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017oAgztBQGK3Yw8zA83NEnJ
6e16998 · 2026-09-26 · TK-12090: add verify-only prod vision check paste script
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VizMhiDcRGXSVT356UUdHr
655426a · 2026-09-25 · TK-12268: add creds-in-URL fetch guard (fleet pattern) to gated page
Relative fetch() on a Basic-Auth page threw on user:pass@host bookmarks. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7LB6rCwpA7ubJTqYzqXEX
9b15829 · 2026-09-25 · TK-12268: add creds-in-URL fetch guard (fleet pattern) to gated page
Relative fetch() on a Basic-Auth page threw on user:pass@host bookmarks. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D7LB6rCwpA7ubJTqYzqXEX
7aecde5 · 2026-09-25 · Editor fits iPhone width: narrow-screen layout (wheel above sliders, Use Photo full-width, Crop/Reset/Cancel row)
html zoom 1.35 leaves ~289 CSS px on a 390px phone; sliders/values and the action row overflowed the right edge (scrollWidth 323 > 289). Now 0 overflow, headless-verified; desktop unchanged (<=600px only). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TZynS56oLsqJTcschug1a7
69d5016 · 2026-09-25 · Front/Back tiles: tap a taken photo to adjust it in the Enhance/Crop editor; Adjust + Retake buttons below each tile (TK-12256)
Editor/crop overlay raised above the add modal (z 130) so it opens from the tiles. Adjusted pixels replace the local shot only — nothing uploads until Create. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TZynS56oLsqJTcschug1a7
a2e8198 · 2026-09-25 · 5x sweep 5: report — sweeps converge at cap, 3 app defects fixed, env SIGTERM open
TK-12228 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017yv665HsXLibk8kGheHT1P
0e8aa0e · 2026-09-25 · 5x sweep 4: history evidence screenshot viewport-only (Firefox 32767px full-page limit)
TK-12228 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017yv665HsXLibk8kGheHT1P
bf95f56 · 2026-09-25 · 5x sweep 3: hung-camera e2e mode (all engines), WebKit stub fix, sweep aborts if server dies
TK-12228 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017yv665HsXLibk8kGheHT1P
4fd7dee · 2026-09-25 · 5x sweep 2: camera-timeout retry tap now opens the snap camera (as the toast promises)
- index.html: after the live camera times out (8s), the next Photo 1/2 tap goes to the native <input capture> inside the fresh tap's user activation instead of re-running a hung getUserMedia forever (pre-existing since TK-12124; reproduced 4/4 in WebKit with a cold mock camera). Toast names Photo 1 or Photo 2. - e2e: asserts whichever capture path the engine takes (LIVE shutter, or timeout toast -> snap file chooser -> shotAdd); WARM_CAMERA=1 forces LIVE; cam.html check fails loudly if the phone camera never goes live. - 5x/tools/sweep.sh sweep driver. TK-12228 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017yv665HsXLibk8kGheHT1P
15beb44 · 2026-09-25 · 5x sweep 1: favicon on captures/batch/cam, consistent missing-side rule, 3-engine e2e + lazy-img scroll
- captures/batch/cam: declare <link rel=icon> (was /favicon.ico 404 console error; captures new, batch/cam pre-existing) - /api/captures missing_back + captures.html missing()/sort/.miss: one rule — a front/back item lacking a side; single-shot photo-only items (remote cam) no longer inflate the count (was 5 vs real 1) - e2e: ENGINE=chromium|webkit|firefox with per-engine fake camera; scroll lazy thumbs into view before asserting - 5x/tools: console probe, history scroll check, index toolbar clickthrough, missing-side regression check TK-12228 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017yv665HsXLibk8kGheHT1P
d1a0b78 · 2026-09-25 · TK-12228: every captured photo, front and back, displays in the app
- index.html: front/back tiles show the captured photo immediately; Preview shows both sides (and counts them, was "0 photo(s)"); Created + Update results show the server-stored copies; tap to enlarge; links to the new Capture History. - server.js: create-item/photo/photos persist every photo under photos/ with its side in the filename (create-item now also on a failed create) and index one record per item in data/captures.jsonl; responses return the stored URLs. New /captures page + /api/captures merge that log with batch manifests and legacy vendor-log uploads. - captures.html: history grid, front+back per card (missing side shown as a gap), date+time chip, sort + density slider persisted in localStorage, lightbox. - batch.html: FRONT (PSku) + BACK (Info) thumbs side by side, front shown on capture, no more 8s blob revoke. cam.html: last remote shot shown on the phone. - --test seam (DWP_TEST_DIR): rebased data/photos, Shopify/dw_unified/FM writes and paid OCR stubbed; scripts/e2e-front-back-display.cjs drives it (19 checks). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017yv665HsXLibk8kGheHT1P
126f917 · 2026-09-25 · Fix grainy Shopify product photos: raise server-side JPEG normalize cap+quality
TK-12224. Root cause: normalizeImage() (server.js) runs every uploaded camera photo through ImageMagick before it's attached to the live Shopify product (createNewItem / /api/photo / /api/photos all pipe through normB64). It was downscaling to <=1600x1600 at quality 85 -- a SECOND, lower-quality JPEG generation stacked on top of the client's own capture (which already caps to 2000px @ quality 0.92 in index.html/cam.html, or native-res @ 0.92 in batch.html). On busy, high-frequency wallcovering/fabric patterns that shows up as visible JPEG blocking/mosquito noise -- exactly the "grainy" symptom. Fix: raise the resize cap to 3000x3000 (a no-op for size against every client's actual output, still guards oversized/HEIC originals) and the quality factor to 92 (matches the client's own export quality, removing the double-compression quality loss). Auto-orient/HEIC normalization for OCR is unchanged. Client-side getUserMedia constraints, canvas capture sizing, and JPEG export quality were already correct (4096x3072 ideal, videoWidth/videoHeight-sized canvases, 0.90-0.92 export quality) from prior TK-12115/12124/12127/12128 work -- this was the one remaining lossy step, confirmed by tracing /api/photo, /api/photos, and /api/create-item to normB64() -> normalizeImage().
67566bd · 2026-09-24 · TK-12162: mint checks vendor catalog reservations + confirms the number is free LIVE (FileMaker + Shopify)
The mint's sources are all mirrors (shopify_products last synced 09-23) and none read the vendor scrape catalog, which pre-assigns dw_skus (tres_tintas_catalog: DWTS-900001..901506). So a mint could hand out a reserved number, or the same number twice before a sync. - adds vendor_registry.catalog_table reservations to the used-number set - JS Pattern is TEXT in FileMaker (no reliable max), so the chosen number is verified free by an exact live FileMaker find + Shopify SKU prefix search, stepping past taken numbers (max 25); if a live source can't answer, the mint still returns but carries a flag - tested read-only on prod: 901507 taken=true, 987654 taken=false, DWTT-72290 taken=true, Tres Tintas mint -> DWTS-901514, clear of both reserved ranges Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
d6f19b5 · 2026-09-24 · Henry sync: treat not-yet-created server archive as OK 0, not FAIL (TK-12162)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NR59q54WMPw4GdNgi2z1jM
2653995 · 2026-09-24 · Nightly additive rsync of vendor photo archive to Henry + launchd plist (TK-12162)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NR59q54WMPw4GdNgi2z1jM
0260eb6 · 2026-09-24 · Save every uploaded photo by vendor: photos/vendors/<Vendor>/ archive + index + /vendor-photos gallery + one-time backfill (TK-12162)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NR59q54WMPw4GdNgi2z1jM
07b7e8c · 2026-09-24 · deploy: exclude ops/ (Tres Tintas restore maps/scripts are local-only, not server runtime) (TK-12162)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NR59q54WMPw4GdNgi2z1jM
83caea3 · 2026-09-24 · Add 'Other apps' links (4 simplified capture concepts) to home screen + bottom of upload grid (TK-12162)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NR59q54WMPw4GdNgi2z1jM
e7a5066 · 2026-09-24 · TK-12162: auto-save only for registry vendors; case-insensitive vendor lookup; Minimal sends pattern name
Live dry-run against prod showed every simple-* save minting a PROV- sku: create-item matched the label vendor to vendor_registry by exact, case-sensitive name, so 'YORK WALLCOVERINGS' missed 'York Wallcoverings' (DWYK-). Auto-save would have turned that into drafts with placeholder SKUs. - server.js findVendorReg(): exact vid/display/real name first, then a case- and punctuation-insensitive pass that only accepts a single hit (no guessing). - /api/extract returns vendor_registered + the registry display name (private-label name wins, so the source name never reaches Shopify). - All 4 pages auto-save only when vendor_registered; otherwise the manual confirm screen shows. Minimal now sends the pattern name, so its draft titles match. Mocked E2E: auto-save fires for a registered vendor, never for an unregistered one. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014WCvaA6QQCJp2LMdcXyrUD
1a2c398 · 2026-09-24 · TK-12162: pre-shot 11-slider adjust panel + auto-save on all simple-* pages
New public/js/adjust-panel.js puts all 11 CapturePipeline adjustments (exposure, contrast, highlights, shadows, warmth, tint, saturation, vibrance, hue, sharpness, straighten) in a bottom sheet, draws the adjusted live preview over the camera, and bakes the same tune into whichever photo is taken - live shutter or the full-res native photo (up to 4096px). Settings persist between shots. Auto-save (default on, switch in the panel): once the label read returns vendor + mfr#, the draft saves with no extra tap; otherwise the page's manual form shows as before. Minimal keeps its existing Auto-create switch. Pro Booth: its 3 big sliders and the panel edit the same tune; straighten was hard-coded to 0 in its preview and bake, now honoured. Headless E2E (exposure +60): all 4 pages brighten the saved photo (live ~83->152, full-res 170->253 at 4032x3024), auto-save fires without a tap, and the manual save path still works with auto-save off. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014WCvaA6QQCJp2LMdcXyrUD
4d1311b · 2026-09-24 · TK-12162: full-res native-camera capture on all simple-* pages
getUserMedia video frames are capped by the stream (~1920 wide on iPhone Safari). New public/js/native-photo.js opens the device Camera app via <input capture=environment> and returns the real sensor photo: a full copy (JPEG 0.92, up to 4096px long edge, so a whole 12MP shot) for create-item, and a 1600px copy for /api/extract so the Gemini label read stays fast and cheap. Each page gets a Full-res button feeding its existing capture flow (Pro Booth still bakes the 3 sliders into it). Instant's shutter no longer passes the click event into doCapture. Headless E2E: all 4 pages send 4032x3024 to create-item and 1600x1200 to extract. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014WCvaA6QQCJp2LMdcXyrUD
14e3194 · 2026-09-24 · TK-12162: capture at high res on all simple-* pages + route minimal/wizard/probooth
Wizard, Instant and Minimal now match Pro Booth: ask the camera for 4096x3072, keep up to a 2000px long edge, JPEG 0.92 (was 1920x1080/1440, 1600px cap, 0.85). server.js served only /simple-instant; the other three pages 404'd. One fixed allow-list regex now serves all four. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014WCvaA6QQCJp2LMdcXyrUD
2b1d006 · 2026-09-24 · Consolidate SKU field cleanup into shared field-clean.js helper
All four simple-*.html pages now use a common cleanField(v) helper to coerce Gemini Vision JSON string fields (which arrive as numbers or nulls) to trimmed strings before assignment. This replaces inline String(v).trim() or no coercion at all, preventing TypeError crashes when OCR returns unexpected types. - Created public/js/field-clean.js with a single exported function - Wired all four pages (minimal, wizard, probooth, instant) to load it - Updated fillIfEmpty in probooth.html to use cleanField - Updated simple-instant.html line 361 to use cleanField for mfr_sku - All four pages parse correctly with helper loaded before use Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014WCvaA6QQCJp2LMdcXyrUD
10d3e40 · 2026-09-24 · TK-12162: guided wizard never strands a guest on an unexpected finishCapture error
Wrap the Use-This-Photo handler so any throw routes to the staff-handoff done screen instead of leaving Retake/Use disabled on the review step. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014WCvaA6QQCJp2LMdcXyrUD
03f509f · 2026-09-24 · TK-12090/TK-12162: fix numeric-SKU .trim() crash + de-obfuscate deploy verifier
- simple-minimal.html, simple-wizard.html: fields.mfr_sku from Gemini's JSON can come back as a number, not a string; (fields.mfr_sku || '').trim() throws TypeError in that case, silently breaking the capture flow. Coerce to string first (matches the safe pattern already used in simple-probooth.html's fillIfEmpty). - simple-minimal.html: surface the server's read-error message on the manual-entry fallback card instead of a generic string. - STEVE-PASTE-tk12090-deploy2.sh: replace the base64-encoded inline Python verifier with a checked-in, readable script (scripts/verify-vision.py), piped over ssh stdin. The script now refuses to run with blank AUTH_USER/AUTH_PASS instead of silently sending an empty Basic Auth header. Reviewed and code-reviewed; withdrew two other findings (restart-verification alarm was moot — set -e + && already aborts on a dead /healthz; the 200ms 'timeout' in the Python verifier is actually 200 seconds, not milliseconds). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014WCvaA6QQCJp2LMdcXyrUD
a262d3e · 2026-09-24 · TK-12162 Instant Film concept: simple-instant.html (Polaroid-style single-photo capture, animation decoupled from real /api/extract upload)
Warm cream/paper theme with DW gold as accent only (deliberate departure from the dark power-tool theme) — framed viewfinder with film-border + rounded corners, shutter-flash, "developing" reveal on a fixed 1.25s cosmetic timer that is fully decoupled from the real network pipeline: the /api/extract upload fires the instant a frame is captured, before the flash/develop animation even starts, and Save's enabled state is gated on that real response (or a manual field edit) — never on the animation clock. Single photo per session; front-loaded vendor + mfr# fields (both server-required) auto-fill from OCR extraction with a manual-override always available. Verified end-to-end locally via Playwright (fake camera device): camera live in <400ms, extract() dispatched ~56ms after shutter tap, develop reveal fires on schedule regardless of the real Gemini round-trip running 1.9-2.1s (longer than the animation) — proving the UI never blocks on the real pipeline. Found + fixed a real bug in testing: the shutter button never re-armed after Retake. Server.js route addition (server.js's own concurrent history under TK-12090 picked this up) is additive-only (mirrors the existing /batch pattern) and does not touch index.html/cam.html/batch.html/desk.html or any core route. Local exploration only — never linked from nav, never deployed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
247c9f9 · 2026-09-24 · TK-12090: report provider=null when the vision call fails
A failed exo call previously surfaced as provider:"exo" (the requested engine name), so a broken ring looked like a successful exo call. Verified against prod: PROVIDER exo / cost 0 / ok False while the ring had no vision instance. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019vkV6GBLJ9rN1VQ8oM8HJc
8452fcc · 2026-09-24 · TK-12090: decouple exo VLM ring from HAS_MACVISION, make it the reasoning-path default
/api/recognize and /api/identify could never reach the exo ring on Kamatera
(Linux): the ring was only wired into engine==='macvision', and
engineAvailable('macvision') is gated on HAS_MACVISION = IS_DARWIN &&
bin/ocr exists — always false on prod. VISION_URL config + /healthz were
correctly set but no route could actually consume it (confirmed live:
step-3 verify returned provider=gcv, not exo/gemini).
Adds 'exo' as its own engine, decoupled from platform: engineAvailable('exo')
= HAS_EXO (the shared exo-vision.mjs lib is present on this host), a static
config check mirroring HAS_MACVISION's own fs.existsSync pattern. Live
reachability (ring up/down, Gemini fallback, honest not_measured) stays
inside exo-vision.mjs's visionChat() where it already lived correctly.
visionJSON() now routes 'exo' to ollamaVision alongside 'macvision'. The two
reasoning-call sites (/api/identify, /api/recognize) prefer exo when
configured and no explicit {engine:...} was requested by the client -
DEFAULT_ENGINE (and /api/ocr's literal-OCR routing) is untouched, so this
never affects OCR engine selection. provider/model/cost_usd in both
responses already read the real per-call values from the lib, so a Gemini
fallback inside the ring will correctly still report provider:"gemini", not
a false "exo".
Verified: node --check passes; exo-vision.mjs confirmed present on Kamatera
prod at the real deploy path (/root/public-projects/_shared/lib/exo-vision.mjs).
Not yet deployed to prod.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019vkV6GBLJ9rN1VQ8oM8HJc
8364615 · 2026-09-24 · TK-12126: never report Gemini OCR cost for a call that errored
The live run surfaced it: server.js's /api/extract returns a hardcoded cost_usd 0.0006 even when the Gemini call failed (credits depleted), so the proof script echoed spend that never happened. Now trusts cost_usd only when the response carries no err. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017uUWK5VKgXgemKLA9UqwMZ
d9c9612 · 2026-09-24 · TK-12126: add camera commit:true round-trip proof script (mock-tested, live path gated)
Builds scripts/camera-committrue-proof.mjs per the approved memo — proves the one remaining unmeasured link in the camera capture pipeline (commit:true -> Shopify DRAFT -> re-fetch -> byte/pixel-match the baked capture) that the cycle-2 CTA run stopped short of. Mock mode ($0, no network) runs the real ImageMagick normalize step plus a simulated Shopify re-encode and proves the comparator via --self-test (PASS on clean data, FAILs on injected corruption, per the negative-test rule). --live is hard-gated and was never executed here. Ledger: data/camera-committrue-proof-ledger.jsonl (now gitignored, runtime-generated). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017uUWK5VKgXgemKLA9UqwMZ
a1b8ee3 · 2026-09-24 · Extract shared acquireCamera() helper, adopt across 5 unbounded surfaces (TK-12127)
New public/js/acquire-camera.js ports the proven TK-12124/TK-12128 semantics
(bounded 8s getUserMedia race, a per-acquirer GENERATION counter, late-arrival
hardware release, bounded 3s play() wait, optional ended/mute hooks scoped by
generation) into one reusable, script-tag-included module. The generation
counter alone is what prevents "a re-tap during a hang orphans a live stream"
— no separate re-entrancy boolean latch is needed, since a superseded older
acquire is detected and its hardware released the moment it resolves late.
The helper owns HOW a stream is acquired; every adopted surface keeps its own
existing constraint preferences (resolution/facingMode) unchanged.
ADOPTED (5 surfaces, all previously unbounded):
- cam.html startCamera() — "Starting…" could hang forever with no honest
retry path; a re-tap (nothing disabled #gBtn) could orphan a stream.
Fixed message: "Camera took too long to respond" + the existing "Try
Again" tap target (the gate's only affordance — no new UI needed). Also
now gets the bounded play() wait cam.html never had at all.
- batch.html startCameraInto() — same orphan-on-retap risk across its two
call sites; boolean return contract (true/false) preserved unchanged.
- index.html scan (startScanStream), white-balance (openWB), measure
(openMeasure) — three more unbounded getUserMedia awaits outside the
two-shot flow, none of which had ANY timeout at all.
DEFERRED: index.html's two-shot flow (startTsStream) is left AS-IS, not
migrated onto the shared helper. It already has this exact proven logic
inline (TK-12124/12128), the diff to swap it over would touch the most
heavily-tested code path in the app for zero functional gain, and it isn't
part of "surfaces that currently have unbounded acquires" — it was already
fixed. Its 44 existing assertions are confirmed unaffected by this change.
PREMISE NOTES:
- cam.html's 'ended' handler and batch.html's onDead callback are ported
verbatim into the onDead hook — cam.html's bounded-play gap was a bonus
fix, not previously reported.
- Line numbers in the original report (cam.html:278-290, batch.html:297-305)
had drifted slightly from prior edits but pointed at the correct functions.
Negative-tested: a 6-case core suite against a blank fixture proves the
module itself (hang→bounded settle, late-arrival tracks STOPPED not just
dereferenced, a newer generation supersedes a hung older one, bounded
play()-timeout, mute/ended hooks correctly scoped by generation, and an
unaffected fast success path) — 20/20 pass. A second suite exercises all 5
adopted call sites directly (bounded settle, sane UI state on timeout, a
clean retry afterward) — 20/20 pass. Confirmed genuine pre-fix hangs via
git-stash on all 5 surfaces with a targeted 4s-vs-11s settle-window probe
(each hung indefinitely pre-fix, each settled within its bound post-fix).
The pre-existing 44 TK-12124/12125/12128 assertions remain green throughout.
One commit for the whole refactor rather than one per surface: the helper
module has no standalone meaning without a consumer, all 5 adoptions share
one bug class and one fix pattern, and splitting them would fragment a
single coherent change for no review benefit.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KXUyzc9vybUz39rhnNJdwY
0e42baf · 2026-09-24 · Wire ended + mute listeners on _tsTrack, scoped by generation (TK-12128)
Cody-found gap from the TK-12124 red-team pass: the two-shot flow had no
mute/ended listener on _tsTrack. On iOS, a LATER camera request elsewhere
(another app, FaceTime) can mute or end an earlier stream's track without any
getUserMedia call of ours — the preview freezes while _tsLive stays true and
the shutter would save a frozen frame.
batch.html's reference handler (line ~310) only covers 'ended'. The failure
Cody actually described is specifically a MUTE (the track never ends, it just
stops delivering frames) — wiring 'ended' alone per the literal instruction
would have left the named bug unfixed, so both events are wired here.
On either event: _tsLive resets to false, the shutter disables, a toast fires
("Camera stopped — tap Front/Back to restart"), and the stream is stopped +
cleared so a retap goes through the existing bounded acquire path cleanly.
Scoped to the CURRENT generation via the _tsStreamGen counter (from the
TK-12124 pass) plus a direct track-identity check, so an old, already-replaced
track's late event — e.g. from the .stop() call the next acquire makes on it —
can never kill a newer, genuinely-live stream.
Negative-tested: confirmed both 'ended' and 'mute' correctly reset _tsLive/
disable the shutter/toast (mute dispatched synthetically since it's exclusively
OS-triggered with no script-callable trigger; 'ended' likewise synthetic since
MediaStreamTrack.stop() does NOT fire 'ended' per spec — only an external end
does), confirmed a retap re-acquires cleanly afterward, and confirmed a STALE
old-generation track firing either event does NOT affect a newer live stream.
12/12 new assertions pass; the existing 25 TK-12124 assertions are unaffected.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KXUyzc9vybUz39rhnNJdwY
b2bd893 · 2026-09-24 · Add persistent "applies at capture, not preview" hint on the Sharpness slider (TK-12125)
The Sharpness slider does nothing visible on the live 80ms preview by design (capture-only unsharp mask — capture-pipeline.js applies it only when opts.capture===true, never on the preview pass). Showroom staff drag it, see no change, and reasonably assume it's broken. Added a small persistent (non-tooltip) caption directly under the slider in the two-shot panel: "Applies at capture — not shown in this preview", styled consistent with the panel's existing dim/muted caption idiom. Also mirrored the hint in cam.html: contrary to the ticket's assumption that "cam.html has no panel yet", it actually has a live, wired adjustment panel (including a functionally identical Sharpness slider) whose previewTick() also runs capture:false — the same gap exists there. Confirmed batch.html has no sharpness slider at all (only unrelated blur/Laplacian-variance code), so it's correctly skipped. Verified via a real-browser (Playwright + Chrome for Testing) check: the hint renders whenever the panel is open, doesn't overlap or shift the layout of the next slider (Straighten), and the Sharpness range input's width is unchanged vs its sibling sliders. Screenshot captured for evidence. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXUyzc9vybUz39rhnNJdwY
9f4d2c2 · 2026-09-24 · Fix 3 Cody-found holes in the getUserMedia timeout fix (TK-12124 follow-up)
Cody red-teamed ca60ce9 (verdict FIX-FIRST). Three holes, all in startTsStream()/ openTwoShotCam(): Hole 1 (most serious — same bug, one await later): `await v.play()` right after the getUserMedia fix was itself unbounded. A track that CONNECTS but never produces a frame (camera held by another app/FaceTime call, muted track) can leave play() pending forever on WebKit, sticking _tsAcquiring true again — exactly the brick ca60ce9 claimed to have fixed. Bounded play() with a 3s Promise.race; _tsLive is now keyed off whether play() itself settled, not off videoWidth (verified empirically that #tsVideo's own `autoplay muted` attribute populates videoWidth via native autoplay regardless of whether this explicit play() call ever resolves, so videoWidth can't distinguish "confirmed live" from "still nothing" and would have been a false signal). Hole 2: the attempts loop didn't re-check timedOut/generation at the TOP of each iteration, only after a getUserMedia call returned — so a permission decision arriving just after the 8s bail-out could still fire a 2nd/3rd getUserMedia call (fresh prompt + camera light) for a caller who already moved to the fallback. Added the guard at loop entry. Hole 3: the timeout-path fallback auto-.click()'d #frontInput ~8-14s after the original tap. iOS Safari (and usually Chrome past ~5s) will have already expired the user-activation window by then, so that click would silently no-op — the toast promised "using snap camera" and then nothing would happen. Changed the timeout branch to ask for a fresh tap instead of auto-clicking; the fast flat-denial branch (still well inside the activation window) keeps the original auto-click behavior unchanged. Negative-tested: added a 4th test case (v.play() stubbed to never resolve, getUserMedia resolving fine) — confirmed it hangs forever against the pre-hole-1-fix commit (killed at a 30s wall-clock timeout), and post-fix settles within the bounded ~3s window with _tsAcquiring reset. Updated T2 into 2a/2b to separately prove the timeout branch no longer auto-clicks (hole 3) and the fast-denial branch still does (behavior preserved). All 25 assertions pass across the original 3 test scenarios + the 2 hole-specific splits + the new hole-1 case. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXUyzc9vybUz39rhnNJdwY
ca60ce9 · 2026-09-24 · Fix: bound getUserMedia() with an 8s timeout so a hung camera prompt can't brick the shutter (TK-12124)
startTsStream() awaited getUserMedia() with no timeout. On WebKit/Safari (also a
denied/backgrounded permission prompt or an MDM camera restriction on any browser)
that promise can simply never settle, which left _tsOpening/_tsAcquiring stuck true
forever and permanently disabled the shutter + camera-flip buttons until reload.
Race each acquisition attempt against an 8s timer; on timeout, throw a distinct
camera-timeout error so the existing finally blocks reset both flags, surface a
clear toast ("Camera took too long to respond — using snap camera"), and fall
back to the native #frontInput/#backInput capture input. A late-arriving stream
that resolves after the bail-out is stopped immediately (via a generation
counter) instead of being silently adopted as an orphaned hot camera. Success
path is unchanged (verified — no delay, no timeout artifact).
Negative-tested with a real headless Chrome harness stubbing getUserMedia to
never resolve: confirmed the pre-fix code hangs forever (test had to be killed
at a 30s wall-clock timeout), and the fix resolves within the bounded window,
resets both flags, shows the toast, and falls back correctly — 17/17 assertions
pass, including an unaffected fast-path success case.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KXUyzc9vybUz39rhnNJdwY
2a2801e · 2026-09-23 · batch.html: adopt shared capture-pipeline engine, full Photoshop set on top of gray-card calibration (TK-12090)
pipeGains() now returns ONLY the gray-card WB ratio (rGain/gGain/bGain); brightness and temp/warmth now handled by the shared engine's exposure and temp/tint sliders. applyPipeline() threaded with a capture:bool parameter — delegates to CapturePipeline.apply() passing the WB gains as preGain and the auto-exposure multiplier (computeES) as exposureMul. preview tick calls with capture:false (no unsharp); grabPhoto calls with capture:true (unsharp enabled). tune loading uses CapturePipeline.normalizeTune() for back-compat (bright→exposure, warm→temp). bindTune maps legacy HTML slider IDs to new tune field names. Existing 3-slider panel (exposure/temp/hue) still wired; full 11-control extension can be added later. The gray-card CALIBRATE workflow (enterCalib, cSave, CAL_TARGET/CAL_GRAY/CAL_REF, drawCalOverlay) is byte-identical to before; computeES() still reads raw pixels before the engine bake. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XKaojLnVW8hyxsVriY5f9a
880e4d8 · 2026-09-23 · cam.html + desk.html: full pre-capture photoshop camera (zero→full parity) (TK-12090)
cam.html: add WYSIWYG preview canvas + WB tap-to-sample + full 11-control adjust panel (exposure/contrast/highlights+shadows/temp+tint/saturation+vibrance/hue/sharpness) + presets (showroom/daylight/label-closeup) + live histogram + clipping badge + hardware applyConstraints layer. Full-res baked capture replaces raw drawImage. Tune POSTed to /api/pair/cam-status so desktop can show readout. Preview tick at 80ms (capture:false), full-res shutter capture at TS_MAX longest edge (capture:true, unsharp enabled). desk.html: add readonly adjustment tune readout (preset + key slider values from phone status). Displays live as phone adjusts (via SSE tune field in /desk/events status update). Both files preserve existing fetch-guard + SSE pairing + shot result flows unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XKaojLnVW8hyxsVriY5f9a
af5702a · 2026-09-23 · index.html two-shot: adopt shared capture-pipeline + full adjust panel + presets + histogram (TK-12090)
Delegates the two-shot live-cam bake (tsPipeline) to window.CapturePipeline instead of the
old inline WB×brightness/saturation/hue-only bake. tsPreviewTick calls apply() with
capture:false (no unsharp mask, ~80ms budget); tsCapture calls with capture:true (unsharp
mask bakes here only) -- preview/capture parity preserved. _tsWB (tap-sample white-balance
gains) is passed as opts.preGain so it is not double-applied against the engine's own
temp/tint gains. _tsTune is now the full CapturePipeline tune shape, persisted via
CapturePipeline.loadTune/saveTune('dwTsTune') with automatic back-compat for the old
{bright,sat,hue} shape.
Extends the #tsTools panel with: a Preset <select> (Showroom / Daylight / Label close-up /
Custom, persisted as dwTsPreset -- any manual slider move flips it back to Custom), a live
histogram canvas + clipping-warning badge (updated every preview tick), and the full slider
set (Exposure, Contrast, Highlights, Shadows, Temp, Tint, Saturation, Vibrance, Hue,
Sharpness, Straighten) replacing the old 3-slider (Brightness/Saturation/Hue) set. Straighten
now feeds CapturePipeline.drawSource() in both tsPreviewTick and tsCapture in place of the
raw drawImage, so the rotation bakes identically in preview and capture. Panel body was
already max-height:46vh + overflow:auto (scrollable on phone). Native frontInput/backInput
fallback path is untouched.
TK-12115 (parent TK-12090)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KXUyzc9vybUz39rhnNJdwY
fdff137 · 2026-09-23 · add shared capture-pipeline.js engine (full pre-capture photoshop set, manual canvas pixel math)
ONE shared engine (window.CapturePipeline) generalizing the two existing inline pipelines (index.html tsPipeline, batch.html applyPipeline/pipeGains) and extending them to the full Photoshop adjustment set: exposure, contrast, highlights, shadows, temp, tint, saturation, vibrance, hue, sharpness (capture-only unsharp mask), straighten. Manual getImageData/loop/ putImageData only -- no WebGL, no ctx.filter, no CSS filters (survives toDataURL, iOS-safe). Also ships histogram/drawHistogram, 3 starter presets, drawSource (cover-fit + straighten bake), and a best-effort Hardware.probe/apply layer over track.applyConstraints (feature- detected, never throws -- the software pipeline stays the source of truth for WYSIWYG). TK-12115 (parent TK-12090) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXUyzc9vybUz39rhnNJdwY
94c8d60 · 2026-09-23 · server.js: bounded /js/ static route to serve the shared capture-pipeline module (TK-12090)
Raw-http server has no generic static handler; the extracted public/js/capture-pipeline.js needs an explicit route. Mirrors the /marketing/ guard: basename-only, .js/.mjs allowlist, path-traversal guard, no-store. Behind the existing basic-auth (authed page fetches it as a same-origin subresource). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXUyzc9vybUz39rhnNJdwY
409e338 · 2026-09-23 · deploy.conf: exclude visual-search venv + CLIP weights + test dirs from rsync (1.3GB, TK-12090 Lane P follow-up)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXUyzc9vybUz39rhnNJdwY
95babfe · 2026-09-23 · visual-search: optional pattern-sibling stage (PATTERN_SIBLINGS=1 + body siblings:true) using dw-pairs-well colour-invariant dHash + WS-1 pattern_id, vendor+pattern_name fallback (TK-12090 Lane P)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXUyzc9vybUz39rhnNJdwY
6a07319 · 2026-09-23 · visual-search: product_image_fingerprints PG table + disk-guarded idempotent loader + flagged SQL-filtered PG search path (PG_FINGERPRINTS=1, default off) (TK-12090 Lane P)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXUyzc9vybUz39rhnNJdwY
d5f6c4a · 2026-09-23 · visual-search nightly embed: env-first DB user (PGUSER or running OS user, drop retired stevestudio2), launchd PATH for psql, fail-loud connect precheck (TK-12090 Lane P)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KXUyzc9vybUz39rhnNJdwY
File tree
- .claude/worktrees/agent-a841f65dcd871d6ac
- .deploy.conf
- .env.example
- .gitignore
- 5x/REPORT.md
- 5x/archive/README.md
- 5x/archive/REPORT-TK-11947.md
- 5x/archive/REPORT.md
- 5x/archive/sweep-1.md
- 5x/archive/sweep-2.md
- 5x/features.cjs
- 5x/fixtures/back-label.jpg
- 5x/fixtures/front-navy.jpg
- 5x/fixtures/warm-cast.y4m
- 5x/out/features-sweep1.json
- 5x/out/features-sweep2.json
- 5x/out/features-sweep3.json
- 5x/out/features-sweep4.json
- 5x/out/features-sweep5.json
- 5x/out/features-sweep6.json
- 5x/out/features-sweep7.json
- 5x/out/features-sweep8.json
- 5x/out/features-sweep9.json
- 5x/out/s1-chromium-ipad-addmodal.png
- 5x/out/s1-chromium-iphone-addmodal.png
- 5x/out/s1-dryrun-9890.json
- 5x/out/s1-dryrun-9899-FM.json
- 5x/out/s1-ipad-chips.png
- 5x/out/s1-ipad-vendorbar.png
- 5x/out/s2-batch-shoot-ipad.png
- 5x/out/s2-batch-shoot-iphone.png
- 5x/out/s3-batch-shoot-ipad.png
- 5x/out/s3-batch-shoot-iphone.png
- 5x/out/s4-batch-shoot-ipad.png
- 5x/out/s4-batch-shoot-iphone.png
- 5x/out/s5-dryrun-9890.json
- 5x/out/s5-dryrun-9899-FM.json
- 5x/out/s8-dryrun-9890.json
- 5x/out/s8-dryrun-9899-FM.json
- 5x/out/s9-dryrun-9890.json
- 5x/out/s9-dryrun-9899-FM.json
- 5x/sweep-1.md
- 5x/sweep-2.md
- 5x/sweep-3.md
- 5x/sweep-4.md
- 5x/sweep-5.md
- 5x/tools/captures-missing-check.cjs
- 5x/tools/console-probe.cjs
- 5x/tools/history-scroll-check.cjs
- 5x/tools/index-toolbar-click.cjs
- 5x/tools/sweep.sh
- 5x/twoshot-result.json
- 5x/verify-twoshot.mjs
- ACCESS.md
- API.md
- DEPLOY.md
- DEVICE-TEST.md
- FILEMAKER-STICKER-SETUP.md
- OVERNIGHT_LEDGER.md
- bin/ocr
- bin/ocr.swift
- build_logo_fingerprints.py
- build_mfr_index.py
- build_sheet_grs.py
- build_vendor_logos.py
- build_vendor_profiles.py
- create_22_new.py
- data/batch-sessions/TESTSESSION-smoke.jsonl
- data/batch-sessions/smoke-test.jsonl
- data/batch-sessions/smoke3.jsonl
- data/color-dots.json
- data/favorites.json
- data/logos/1838wallcoverings.png
- data/logos/andrewmartin.png
- data/logos/architecturalfabrics.png
- data/logos/architecturalwallcoverings.png
- data/logos/armanicasa.png
- data/logos/coleson.png
- data/logos/fabricut.jpg
- data/logos/hollywoodacoustical.png
- data/logos/hollywoodwallcoverings.png
- data/logos/kravet.jpg
- data/logos/kravet.png
- data/logos/leejofa.jpg
- data/logos/midcenturymodern.jpg
- data/logos/mindthegap.png
- data/logos/ninacampbell.jpg
- data/logos/ninacampbellwallcoverings.jpg
- data/logos/nlxl.jpg
- data/logos/phillipjeffries.png
- data/logos/ralphlauren.png
- data/logos/ralphlaurenfabric.png
- data/logos/rebelwalls.jpg
- data/logos/schumacher.png
- data/logos/telefinafinefabrics.png
- data/logos/thibaut.png
- data/logos/versace.png
- data/logos/williammorris.png
- data/queue.json
- data/recents.json
- data/scan-log.jsonl
- data/sheet_grs.json
- data/vendor_logos.json
- data/vendor_profiles.json
- deploy/launchd/com.steve.color-index-rebuild.plist
- eslint.config.mjs
- fm-client.js
- grs_per_yard.py
- launchd/com.steve.dwphoto-mfr-rebuild.plist
- launchd/com.steve.dwphoto-mfr-refresh.plist
- launchd/com.steve.dwphoto-sticker-watcher.plist
- launchd/com.steve.dwphoto-vendor-refresh.plist
- ops/tres-tintas-dwts-2026-09-24/__pycache__/shop-tb.cpython-314.pyc
- ops/tres-tintas-dwts-2026-09-24/fm-create-masters.js
- ops/tres-tintas-dwts-2026-09-24/fm-created.jsonl
- ops/tres-tintas-dwts-2026-09-24/renum-9015-restore.jsonl
- ops/tres-tintas-dwts-2026-09-24/shop-tb-restore.jsonl
- ops/tres-tintas-dwts-2026-09-24/shop-tb.py
- ops/tres-tintas-dwts-2026-09-24/shopify-sku-restore.jsonl
- ops/tres-tintas-dwts-2026-09-24/tk-dwrw-plan2.json
- ops/tres-tintas-dwts-2026-09-24/tk-dwrw-restore.json
- ops/tres-tintas-dwts-2026-09-24/tk-dwtb10050-restore.json
- ops/tres-tintas-dwts-2026-09-24/tk-dwts-restore.json
- ops/tres-tintas-dwts-2026-09-24/tk-renum-9015.json
- ops/tres-tintas-dwts-2026-09-24/tk-tres-delete-list.json
- ops/tres-tintas-dwts-2026-09-24/tk-tres-tag-restore.json
- package-lock.json
- package.json
- photo-app-qr.png
- public-marketing/color-coordinate-wm.gif
- public/batch.html
- public/cam.html
- public/caps.html
- public/captures.html
- public/desk.html
- public/icon-180.png
- public/icon-192.png
- public/icon-512.png
- public/index.html
- public/index.html.wip-builder-20260918-150511
- public/js/acquire-camera.js
- public/js/adjust-panel.js
- public/js/capture-pipeline.js
- public/js/field-clean.js
- public/js/native-photo.js
- public/kid-simple/index.html
- public/kid-simple/renders/kid-simple-v7-v16-board.jpg
- public/kid-simple/renders/v10-todays-inbox.png
- public/kid-simple/renders/v11-bottom-sheet.png
- public/kid-simple/renders/v12-hold-to-talk.png
- public/kid-simple/renders/v13-sticker-book.png
- public/kid-simple/renders/v14-ticket-printer.png
- public/kid-simple/renders/v15-thumb-zone.png
- public/kid-simple/renders/v16-widget-stack.png
- public/kid-simple/renders/v7-scan-and-go.png
- public/kid-simple/renders/v8-mode-dial.png
- public/kid-simple/renders/v9-story-mode.png
- public/kid-simple/v1-magic-camera.html
- public/kid-simple/v10-todays-inbox.html
- public/kid-simple/v11-bottom-sheet.html
- public/kid-simple/v12-hold-to-talk.html
- public/kid-simple/v13-sticker-book.html
- public/kid-simple/v14-ticket-printer.html
- public/kid-simple/v15-thumb-zone.html
- public/kid-simple/v16-widget-stack.html
- public/kid-simple/v2-four-tiles.html
- public/kid-simple/v3-text-buddy.html
- public/kid-simple/v4-level-up.html
- public/kid-simple/v5-swipe-deck.html
- public/kid-simple/v6-one-thing.html
- public/kid-simple/v7-scan-and-go.html
- public/kid-simple/v8-mode-dial.html
- public/kid-simple/v9-story-mode.html
- public/learn.html
- public/pick.html
- public/simple-instant.html
- public/simple-minimal.html
- public/simple-probooth.html
- public/simple-wizard.html
- public/themes/v07-traffic-light.html
- public/themes/v08-big-emoji.html
- public/themes/v09-checklist.html
- public/themes/v1-magic-camera.html
- public/themes/v10-scan-first.html
- public/themes/v11-talk-to-it.html
- public/themes/v12-bottom-tabs.html
- public/themes/v13-photo-wall.html
- public/themes/v14-sample-ticket.html
- public/themes/v15-giant-words.html
- public/themes/v16-sticky-notes.html
- public/themes/v17-game-pad.html
- public/themes/v18-trail-map.html
- public/themes/v19-left-or-right.html
- public/themes/v2-four-tiles.html
- public/themes/v20-luxe-gold.html
- public/themes/v21-beat-the-clock.html
- public/themes/v22-buddy-pup.html
- public/themes/v23-code-keypad.html
- public/themes/v24-split-screen.html
- public/themes/v25-paper-stack.html
- public/themes/v3-text-buddy.html
- public/themes/v4-level-up.html
- public/themes/v5-swipe-deck.html
- public/themes/v6-one-thing.html
- public/vendor-photos.html
- ref-roll.jpg
- refresh_mfr_index.py
- schu-apply-out.json
- schu-publish-audit.jsonl
- schu-publish.mjs
- schu-settlement-hold.json
- screenrecord/DEBUG-REPORT.md
- screenrecord/debug-log.jsonl
- screenrecord/rec/run0/page@8d672a8c348229a87b60bc50cf0f16a4.mp4
- screenrecord/rec/run0/page@8d672a8c348229a87b60bc50cf0f16a4.webm
- screenrecord/rec/run0/page@baf635327b1dd2ad57d25686a3348dc6.mp4
- screenrecord/rec/run0/page@baf635327b1dd2ad57d25686a3348dc6.webm
- screenrecord/rec/run0/page@c02a42ee275506e6376d31fad467949b.mp4
- screenrecord/rec/run0/page@c02a42ee275506e6376d31fad467949b.webm
- screenrecord/rec/run0_v103/page@8c4e4c64f0efacceccc8ec61cfc18404.mp4
- screenrecord/rec/run0_v103/page@8c4e4c64f0efacceccc8ec61cfc18404.webm
- screenrecord/rec/run1/page@045d6c3359d0ee4c5008a03e3e743927.mp4
- screenrecord/rec/run1/page@045d6c3359d0ee4c5008a03e3e743927.webm
- screenrecord/rec/run1/page@65767f2cbeed44e6f0746eb7b331ac58.mp4
- screenrecord/rec/run1/page@65767f2cbeed44e6f0746eb7b331ac58.webm
- screenrecord/rec/run1/page@759aba46dc4a16b4a16bd7623b33e392.mp4
- screenrecord/rec/run1/page@759aba46dc4a16b4a16bd7623b33e392.webm
- screenrecord/rec/run1_v103/page@2d36e7ee18fbf7abd4adf8890a223e9f.mp4
- screenrecord/rec/run1_v103/page@2d36e7ee18fbf7abd4adf8890a223e9f.webm
- screenrecord/rec/run2/page@4c646c54fc7d2b27396bde8641b14e2b.mp4
- screenrecord/rec/run2/page@4c646c54fc7d2b27396bde8641b14e2b.webm
- screenrecord/rec/run2/page@e9ba48f157a7481ee9e0122f0faf25ae.mp4
- screenrecord/rec/run2/page@e9ba48f157a7481ee9e0122f0faf25ae.webm
- screenrecord/rec/run2_v103/page@792e03857e8e203189e3eda19d9f4e04.mp4
- screenrecord/rec/run2_v103/page@792e03857e8e203189e3eda19d9f4e04.webm
- screenrecord/rec/run3/page@4802028714f9cea97f12f6938a7a7d33.mp4
- screenrecord/rec/run3/page@4802028714f9cea97f12f6938a7a7d33.webm
- screenrecord/rec/run3/page@ea8fb1218f5b7b345af268e4e545b083.mp4
- screenrecord/rec/run3/page@ea8fb1218f5b7b345af268e4e545b083.webm
- screenrecord/rec/run3_v103/page@aeae63853bf8608b4c9f7c1345580f85.mp4
- screenrecord/rec/run3_v103/page@aeae63853bf8608b4c9f7c1345580f85.webm
- screenrecord/rec/run4/page@96324b4cfafc83a80afe7cd203ccecb3.mp4
- screenrecord/rec/run4/page@96324b4cfafc83a80afe7cd203ccecb3.webm
- screenrecord/rec/run4/page@b2f4018983a23e276abe379a34736903.mp4
- screenrecord/rec/run4/page@b2f4018983a23e276abe379a34736903.webm
- screenrecord/rec/run4_v103/page@6bdbb0935be81eb1898f9e213bbef949.mp4
- screenrecord/rec/run4_v103/page@6bdbb0935be81eb1898f9e213bbef949.webm
- screenrecord/run-tests-v103-mobile.js
- screenrecord/run-tests.js
- screenshot-editor.png
- screenshot-roll.png
- screenshot-sheet.png
- scripts/STEVE-PASTE-tk12090-deploy2.sh
- scripts/STEVE-PASTE-tk12090-verify.sh
- scripts/STEVE-PASTE-vision-step3.sh
- scripts/build-color-dots.cjs
- scripts/build-color-index.cjs
- scripts/camera-committrue-proof.mjs
- scripts/e2e-front-back-display.cjs
- scripts/launchd/com.steve.dwphoto-vendor-photos-henry.plist
- scripts/probooth-figma-build.js
- scripts/refresh-color-index.sh
- scripts/sync-vendor-photos-to-henry.sh
- scripts/verify-vision.py
- selfcheck-ui.cjs
- selfcheck.sh
- server.js
- sticker-watcher.js
- test-allshopify.js
- test-analyze-ocr.js
- verification/TK-11007-e2e-proof.json
- visual-search/.gitignore
- visual-search/__pycache__/embed_shopify_gap.cpython-312.pyc
- visual-search/__pycache__/pattern_siblings.cpython-312.pyc
- visual-search/__pycache__/search_service.cpython-312.pyc
- visual-search/__pycache__/search_service.cpython-314.pyc
- visual-search/com.steve.visual-search-embed-nightly.plist
- visual-search/com.steve.visual-search.plist
- visual-search/deploy-kamatera/requirements-lite.txt
- visual-search/deploy-kamatera/setup.sh
- visual-search/embed-daemon.sh
- visual-search/embed-nightly-mac2.sh
- visual-search/embed_catalog.py
- visual-search/embed_shopify_gap.py
- visual-search/load_pg_fingerprints.py
- visual-search/pattern_siblings.py
- visual-search/search_service.py
- visual-search/sql/product_image_fingerprints.sql