[object Object]

← back to Dw Photo Capture

auto-save: 2026-07-09T08:39:40 (2 files) — public/index.html screenrecord/

036d13097e8849916f1b75e5bf817fb1c2c3882c · 2026-07-09 08:39:43 -0700 · Steve Abrams

Files touched

Diff

commit 036d13097e8849916f1b75e5bf817fb1c2c3882c
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Thu Jul 9 08:39:43 2026 -0700

    auto-save: 2026-07-09T08:39:40 (2 files) — public/index.html screenrecord/
---
 public/index.html                                  |  11 +-
 screenrecord/debug-log.jsonl                       | 175 +++++++
 .../run0/page@8d672a8c348229a87b60bc50cf0f16a4.mp4 | Bin 0 -> 3772455 bytes
 .../page@8d672a8c348229a87b60bc50cf0f16a4.webm     | Bin 0 -> 9693159 bytes
 .../run0/page@baf635327b1dd2ad57d25686a3348dc6.mp4 | Bin 0 -> 516868 bytes
 .../page@baf635327b1dd2ad57d25686a3348dc6.webm     | Bin 0 -> 1116636 bytes
 .../run0/page@c02a42ee275506e6376d31fad467949b.mp4 | Bin 0 -> 497164 bytes
 .../page@c02a42ee275506e6376d31fad467949b.webm     | Bin 0 -> 994273 bytes
 .../run1/page@045d6c3359d0ee4c5008a03e3e743927.mp4 | Bin 0 -> 9175 bytes
 .../page@045d6c3359d0ee4c5008a03e3e743927.webm     | Bin 0 -> 13138 bytes
 .../run1/page@65767f2cbeed44e6f0746eb7b331ac58.mp4 | Bin 0 -> 487807 bytes
 .../page@65767f2cbeed44e6f0746eb7b331ac58.webm     | Bin 0 -> 949763 bytes
 .../run1/page@759aba46dc4a16b4a16bd7623b33e392.mp4 | Bin 0 -> 965313 bytes
 .../page@759aba46dc4a16b4a16bd7623b33e392.webm     | Bin 0 -> 10175542 bytes
 .../run2/page@4c646c54fc7d2b27396bde8641b14e2b.mp4 | Bin 0 -> 212144 bytes
 .../page@4c646c54fc7d2b27396bde8641b14e2b.webm     | Bin 0 -> 733598 bytes
 .../run2/page@e9ba48f157a7481ee9e0122f0faf25ae.mp4 | Bin 0 -> 492018 bytes
 .../page@e9ba48f157a7481ee9e0122f0faf25ae.webm     | Bin 0 -> 961240 bytes
 .../run3/page@4802028714f9cea97f12f6938a7a7d33.mp4 | Bin 0 -> 480544 bytes
 .../page@4802028714f9cea97f12f6938a7a7d33.webm     | Bin 0 -> 960511 bytes
 .../run4/page@b2f4018983a23e276abe379a34736903.mp4 | Bin 0 -> 487905 bytes
 .../page@b2f4018983a23e276abe379a34736903.webm     | Bin 0 -> 955972 bytes
 screenrecord/run-tests.js                          | 567 +++++++++++++++++++++
 23 files changed, 751 insertions(+), 2 deletions(-)

diff --git a/public/index.html b/public/index.html
index a787735..b58eb1a 100644
--- a/public/index.html
+++ b/public/index.html
@@ -782,7 +782,12 @@ function render(){
     : 'Nothing here — switch filter or clear search.';
   grid.innerHTML = list.length? '' : `<div class="empty">${emptyMsg}</div>`;
   if(recog && RECOGNIZED) grid.insertAdjacentHTML('afterbegin', recogBanner());
-  for(const x of list){
+  // MEMORY GUARD (iOS OOM-freeze fix): never build more than RENDER_CAP card nodes. The TWIL list is
+  // ~88k items (36MB) — rendering them all drove the browser to 13GB and crashed the tab. Cap it and
+  // tell the user to search/filter to narrow. (Search/filter shrink `list` before this point.)
+  const RENDER_CAP=500;
+  const shown = list.length>RENDER_CAP ? list.slice(0,RENDER_CAP) : list;
+  for(const x of shown){
     const isNew = x.needs_create && !x.done;  // on the sheet but not yet created in Shopify
     const photographed = !isNew && (x.done || !!x.image || x.live); // already has a real photo
     const el=document.createElement('div'); el.className='card'+(photographed?' done':'');
@@ -821,6 +826,8 @@ function render(){
     const sk=el.querySelector('.skip'); if(sk) sk.addEventListener('click',()=>skip(x));
     grid.appendChild(el);
   }
+  if(list.length>shown.length){ const n=document.createElement('div'); n.className='empty'; n.style.gridColumn='1/-1';
+    n.innerHTML=`Showing first <b>${shown.length}</b> of <b>${list.length.toLocaleString()}</b> — 🔎 search a SKU / name / vendor to narrow.`; grid.appendChild(n); }
   lazyThumbs();   // only load thumbnails as they scroll into view (huge mobile win vs 100s of images at once)
 }
 // CSS background-images can't use loading="lazy" — apply each thumb's bg only when it nears the viewport.
@@ -1948,7 +1955,7 @@ function routeHome(act){ $('#homeScreen').hidden=true;
   else if(act==='update') openAddModal(null,{mode:'update',camera:true});
   else if(act==='lookup') openLookup();          // camera-first front→back → identify
   else if(act==='check'){ openFbModal(); loadIncoming(); }   // show the incoming (ordered-not-received) queue first
-  // 'skip' → just show the catalog
+  else if(act==='skip'){ if(!TWILITEMS.length) loadTwil(); }   // lazy-load the big TWIL grid only when actually viewing it
 }
 document.querySelectorAll('#homeScreen .home-pill, #homeScreen .home-skip').forEach(b=>b.addEventListener('click',()=>routeHome(b.dataset.act)));
 $('#homeBtn').addEventListener('click',()=>{ $('#homeScreen').hidden=false; });
diff --git a/screenrecord/debug-log.jsonl b/screenrecord/debug-log.jsonl
new file mode 100644
index 0000000..5813c8b
--- /dev/null
+++ b/screenrecord/debug-log.jsonl
@@ -0,0 +1,175 @@
+{"run":0,"ts":"2026-07-09T15:28:10.156Z","selector":"PAGE","label":"page load","action":"goto","ok":true,"effect":"domcontentloaded; /api/queue + /api/twil intercepted to prevent renderer choke","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:11.560Z","selector":"#homeScreen","label":"homeScreen initial","action":"check","ok":true,"effect":"visible (correct)","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:11.560Z","selector":"button[data-act=\"add\"]","label":"Add New SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#addModal","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:12.680Z","selector":"button[data-act=\"update\"]","label":"Update SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#addModal","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:14.909Z","selector":"button[data-act=\"lookup\"]","label":"Look Up SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#fbModal","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:17.134Z","selector":"button[data-act=\"check\"]","label":"Check Sample In","action":"click","ok":true,"effect":"homeScreen hidden, modal=#fbModal","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:19.359Z","selector":"button.home-skip","label":"skip →","action":"click","ok":true,"effect":"homeScreen hidden","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:22.692Z","selector":".ver","label":"version chip: v102 · editor","action":"click","ok":true,"effect":"navigated → https://photo.designerwallcoverings.com/selfcheck","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:23.790Z","selector":"#homeBtn","label":"⌂ home button","action":"click","ok":true,"effect":"homeScreen: true → true","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:24.526Z","selector":"#scanBtn","label":"🔢 Scan button","action":"click","ok":true,"effect":"scan overlay not visible","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:25.947Z","selector":"#sort","label":"sort select","action":"cycle","ok":true,"effect":"cycled: ready,title,sku","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:26.558Z","selector":"#dens","label":"density slider","action":"drag","ok":true,"effect":"cycled 2→3→4→1","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:26.863Z","selector":".chip[data-f=\"need\"]","label":"chip: Needs photo","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:27.167Z","selector":".chip[data-f=\"live\"]","label":"chip: 🟢 Live","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:27.470Z","selector":".chip[data-f=\"done\"]","label":"chip: Done","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:27.773Z","selector":".chip[data-f=\"new\"]","label":"chip: ✨ New (11)","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:28.077Z","selector":".chip[data-f=\"twil\"]","label":"chip: 🧵 All TWIL (0)","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:28.380Z","selector":".chip[data-f=\"all\"]","label":"chip: All","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:28.690Z","selector":".chip[data-f=\"any\"]","label":"chip: 🔎 Any SKU","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:28.992Z","selector":".chip[data-f=\"shop\"]","label":"chip: 🌐 All Shopify","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:29.294Z","selector":".chip[data-f=\"similar\"]","label":"chip: 🎨 Similar","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:29.598Z","selector":".chip[data-f=\"fav\"]","label":"chip: ⭐ Favorites","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:29.907Z","selector":".chip[data-f=\"recent\"]","label":"chip: 🕘 Recent","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:31.523Z","selector":"#fbModal","label":"fbModal open via fbBtn","action":"check","ok":true,"effect":"visible","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":0,"ts":"2026-07-09T15:28:31.824Z","selector":"#fbBackTile","label":"Back · label tile","action":"click","ok":true,"effect":"tapped — triggers file picker (capture=environment, camera: cannot fulfill in headless Chromium)","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:32.126Z","selector":"#fbFrontTile","label":"Front · pattern tile","action":"click","ok":true,"effect":"tapped — triggers file picker (capture=environment, camera: cannot fulfill in headless Chromium)","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:32.128Z","selector":"#fbGo","label":"🔎 Identify button","action":"state-check","ok":true,"effect":"disabled (correct: no image loaded)","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:35.090Z","selector":"#fbSearchInput","label":"search \"217203\"","action":"type+search","ok":true,"effect":"0 candidate card(s), 69 chars HTML","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":0,"ts":"2026-07-09T15:28:38.215Z","selector":"#fbSearchInput","label":"search \"CHC-217203\"","action":"type+search","ok":true,"effect":"0 candidate card(s), 73 chars HTML","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":0,"ts":"2026-07-09T15:28:38.617Z","selector":"#fbClose","label":"✕ close fbModal","action":"click","ok":true,"effect":"modal closed","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:40.327Z","selector":"#fbIncoming","label":"Check Sample In — incoming queue","action":"check","ok":true,"effect":"fbModal:true, incoming HTML:18071chars, inc-card:true, recv-btns:40 (NOT clicked — would write FileMaker)","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":0,"ts":"2026-07-09T15:28:41.553Z","selector":"#addBtn","label":"➕ New item button","action":"click","ok":true,"effect":"addModal opened","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":0,"ts":"2026-07-09T15:28:41.555Z","selector":"#addVendor","label":"vendor dropdown in addModal","action":"check","ok":true,"effect":"1 vendor option(s)","errors":[]}
+{"run":0,"ts":"2026-07-09T15:28:41.862Z","selector":"RUN_END","label":"run complete","action":"summary","ok":true,"effect":"~14 actions","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":1,"ts":"2026-07-09T15:28:47.755Z","selector":"PAGE","label":"page load","action":"goto","ok":true,"effect":"domcontentloaded; /api/queue + /api/twil intercepted to prevent renderer choke","errors":[]}
+{"run":1,"ts":"2026-07-09T15:28:49.139Z","selector":"#homeScreen","label":"homeScreen initial","action":"check","ok":true,"effect":"visible (correct)","errors":[]}
+{"run":1,"ts":"2026-07-09T15:28:49.139Z","selector":"button[data-act=\"add\"]","label":"Add New SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#addModal","errors":[]}
+{"run":1,"ts":"2026-07-09T15:28:50.255Z","selector":"button[data-act=\"update\"]","label":"Update SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#addModal","errors":[]}
+{"run":1,"ts":"2026-07-09T15:28:52.483Z","selector":"button[data-act=\"lookup\"]","label":"Look Up SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#fbModal","errors":[]}
+{"run":1,"ts":"2026-07-09T15:28:54.709Z","selector":"button[data-act=\"check\"]","label":"Check Sample In","action":"click","ok":true,"effect":"homeScreen hidden, modal=#fbModal","errors":[]}
+{"run":1,"ts":"2026-07-09T15:28:56.936Z","selector":"button.home-skip","label":"skip →","action":"click","ok":true,"effect":"homeScreen hidden","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:00.171Z","selector":".ver","label":"version chip: v102 · editor","action":"click","ok":true,"effect":"navigated → https://photo.designerwallcoverings.com/selfcheck","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:01.387Z","selector":"#homeBtn","label":"⌂ home button","action":"click","ok":true,"effect":"homeScreen: true → true","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:02.185Z","selector":"#scanBtn","label":"🔢 Scan button","action":"click","ok":true,"effect":"scan overlay not visible","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:03.607Z","selector":"#sort","label":"sort select","action":"cycle","ok":true,"effect":"cycled: ready,title,sku","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:04.218Z","selector":"#dens","label":"density slider","action":"drag","ok":true,"effect":"cycled 2→3→4→1","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:04.523Z","selector":".chip[data-f=\"need\"]","label":"chip: Needs photo","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:04.826Z","selector":".chip[data-f=\"live\"]","label":"chip: 🟢 Live","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:05.130Z","selector":".chip[data-f=\"done\"]","label":"chip: Done","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:05.433Z","selector":".chip[data-f=\"new\"]","label":"chip: ✨ New (11)","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:05.736Z","selector":".chip[data-f=\"twil\"]","label":"chip: 🧵 All TWIL (0)","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:06.039Z","selector":".chip[data-f=\"all\"]","label":"chip: All","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:06.347Z","selector":".chip[data-f=\"any\"]","label":"chip: 🔎 Any SKU","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:06.651Z","selector":".chip[data-f=\"shop\"]","label":"chip: 🌐 All Shopify","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:06.953Z","selector":".chip[data-f=\"similar\"]","label":"chip: 🎨 Similar","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:07.256Z","selector":".chip[data-f=\"fav\"]","label":"chip: ⭐ Favorites","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:07.561Z","selector":".chip[data-f=\"recent\"]","label":"chip: 🕘 Recent","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":1,"ts":"2026-07-09T15:26:32.017Z","selector":"button[data-act=\"add\"]","label":"Add New SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#addModal","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:09.176Z","selector":"#fbModal","label":"fbModal open via fbBtn","action":"check","ok":true,"effect":"visible","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":1,"ts":"2026-07-09T15:29:09.479Z","selector":"#fbBackTile","label":"Back · label tile","action":"click","ok":true,"effect":"tapped — triggers file picker (capture=environment, camera: cannot fulfill in headless Chromium)","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:09.782Z","selector":"#fbFrontTile","label":"Front · pattern tile","action":"click","ok":true,"effect":"tapped — triggers file picker (capture=environment, camera: cannot fulfill in headless Chromium)","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:09.784Z","selector":"#fbGo","label":"🔎 Identify button","action":"state-check","ok":true,"effect":"disabled (correct: no image loaded)","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:12.746Z","selector":"#fbSearchInput","label":"search \"217203\"","action":"type+search","ok":true,"effect":"2 candidate card(s), 574 chars HTML","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":1,"ts":"2026-07-09T15:29:13.151Z","selector":".wp-c","label":"first candidate card","action":"click","ok":true,"effect":"tapped","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":1,"ts":"2026-07-09T15:29:16.366Z","selector":"#fbSearchInput","label":"search \"CHC-217203\"","action":"type+search","ok":true,"effect":"1 candidate card(s), 368 chars HTML","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":1,"ts":"2026-07-09T15:29:16.768Z","selector":"#fbClose","label":"✕ close fbModal","action":"click","ok":true,"effect":"modal closed","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:18.483Z","selector":"#fbIncoming","label":"Check Sample In — incoming queue","action":"check","ok":true,"effect":"fbModal:true, incoming HTML:18071chars, inc-card:true, recv-btns:40 (NOT clicked — would write FileMaker)","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":1,"ts":"2026-07-09T15:29:19.703Z","selector":"#addBtn","label":"➕ New item button","action":"click","ok":true,"effect":"addModal opened","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":1,"ts":"2026-07-09T15:29:19.706Z","selector":"#addVendor","label":"vendor dropdown in addModal","action":"check","ok":true,"effect":"1 vendor option(s)","errors":[]}
+{"run":1,"ts":"2026-07-09T15:29:20.017Z","selector":"RUN_END","label":"run complete","action":"summary","ok":true,"effect":"~14 actions","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":2,"ts":"2026-07-09T15:29:21.734Z","selector":"PAGE","label":"page load","action":"goto","ok":true,"effect":"domcontentloaded; /api/queue + /api/twil intercepted to prevent renderer choke","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:23.169Z","selector":"#homeScreen","label":"homeScreen initial","action":"check","ok":true,"effect":"visible (correct)","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:23.169Z","selector":"button[data-act=\"add\"]","label":"Add New SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#addModal","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:24.282Z","selector":"button[data-act=\"update\"]","label":"Update SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#addModal","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:26.506Z","selector":"button[data-act=\"lookup\"]","label":"Look Up SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#fbModal","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:28.731Z","selector":"button[data-act=\"check\"]","label":"Check Sample In","action":"click","ok":true,"effect":"homeScreen hidden, modal=#fbModal","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:30.957Z","selector":"button.home-skip","label":"skip →","action":"click","ok":true,"effect":"homeScreen hidden","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:34.188Z","selector":".ver","label":"version chip: v102 · editor","action":"click","ok":true,"effect":"navigated → https://photo.designerwallcoverings.com/selfcheck","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:35.294Z","selector":"#homeBtn","label":"⌂ home button","action":"click","ok":true,"effect":"homeScreen: true → true","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:36.037Z","selector":"#scanBtn","label":"🔢 Scan button","action":"click","ok":true,"effect":"scan overlay not visible","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:37.458Z","selector":"#sort","label":"sort select","action":"cycle","ok":true,"effect":"cycled: ready,title,sku","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:38.070Z","selector":"#dens","label":"density slider","action":"drag","ok":true,"effect":"cycled 2→3→4→1","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:38.375Z","selector":".chip[data-f=\"need\"]","label":"chip: Needs photo","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:38.678Z","selector":".chip[data-f=\"live\"]","label":"chip: 🟢 Live","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:38.981Z","selector":".chip[data-f=\"done\"]","label":"chip: Done","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:39.283Z","selector":".chip[data-f=\"new\"]","label":"chip: ✨ New (11)","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:39.587Z","selector":".chip[data-f=\"twil\"]","label":"chip: 🧵 All TWIL (0)","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:39.890Z","selector":".chip[data-f=\"all\"]","label":"chip: All","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:40.198Z","selector":".chip[data-f=\"any\"]","label":"chip: 🔎 Any SKU","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:40.501Z","selector":".chip[data-f=\"shop\"]","label":"chip: 🌐 All Shopify","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:40.802Z","selector":".chip[data-f=\"similar\"]","label":"chip: 🎨 Similar","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:41.105Z","selector":".chip[data-f=\"fav\"]","label":"chip: ⭐ Favorites","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:41.409Z","selector":".chip[data-f=\"recent\"]","label":"chip: 🕘 Recent","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:43.022Z","selector":"#fbModal","label":"fbModal open via fbBtn","action":"check","ok":true,"effect":"visible","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":2,"ts":"2026-07-09T15:29:43.324Z","selector":"#fbBackTile","label":"Back · label tile","action":"click","ok":true,"effect":"tapped — triggers file picker (capture=environment, camera: cannot fulfill in headless Chromium)","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:43.627Z","selector":"#fbFrontTile","label":"Front · pattern tile","action":"click","ok":true,"effect":"tapped — triggers file picker (capture=environment, camera: cannot fulfill in headless Chromium)","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:43.629Z","selector":"#fbGo","label":"🔎 Identify button","action":"state-check","ok":true,"effect":"disabled (correct: no image loaded)","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:46.590Z","selector":"#fbSearchInput","label":"search \"217203\"","action":"type+search","ok":true,"effect":"2 candidate card(s), 574 chars HTML","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":2,"ts":"2026-07-09T15:29:46.994Z","selector":".wp-c","label":"first candidate card","action":"click","ok":true,"effect":"tapped","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":2,"ts":"2026-07-09T15:29:50.127Z","selector":"#fbSearchInput","label":"search \"CHC-217203\"","action":"type+search","ok":true,"effect":"1 candidate card(s), 368 chars HTML","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":2,"ts":"2026-07-09T15:29:50.530Z","selector":"#fbClose","label":"✕ close fbModal","action":"click","ok":true,"effect":"modal closed","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:52.242Z","selector":"#fbIncoming","label":"Check Sample In — incoming queue","action":"check","ok":true,"effect":"fbModal:true, incoming HTML:18071chars, inc-card:true, recv-btns:40 (NOT clicked — would write FileMaker)","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":2,"ts":"2026-07-09T15:29:53.461Z","selector":"#addBtn","label":"➕ New item button","action":"click","ok":true,"effect":"addModal opened","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":2,"ts":"2026-07-09T15:29:53.462Z","selector":"#addVendor","label":"vendor dropdown in addModal","action":"check","ok":true,"effect":"1 vendor option(s)","errors":[]}
+{"run":2,"ts":"2026-07-09T15:29:53.769Z","selector":"RUN_END","label":"run complete","action":"summary","ok":true,"effect":"~14 actions","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":3,"ts":"2026-07-09T15:29:55.570Z","selector":"PAGE","label":"page load","action":"goto","ok":true,"effect":"domcontentloaded; /api/queue + /api/twil intercepted to prevent renderer choke","errors":[]}
+{"run":3,"ts":"2026-07-09T15:29:57.010Z","selector":"#homeScreen","label":"homeScreen initial","action":"check","ok":true,"effect":"visible (correct)","errors":[]}
+{"run":3,"ts":"2026-07-09T15:29:57.011Z","selector":"button[data-act=\"add\"]","label":"Add New SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#addModal","errors":[]}
+{"run":3,"ts":"2026-07-09T15:29:58.124Z","selector":"button[data-act=\"update\"]","label":"Update SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#addModal","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:00.346Z","selector":"button[data-act=\"lookup\"]","label":"Look Up SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#fbModal","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:02.570Z","selector":"button[data-act=\"check\"]","label":"Check Sample In","action":"click","ok":true,"effect":"homeScreen hidden, modal=#fbModal","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:04.907Z","selector":"button.home-skip","label":"skip →","action":"click","ok":true,"effect":"homeScreen hidden","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:08.138Z","selector":".ver","label":"version chip: v102 · editor","action":"click","ok":true,"effect":"navigated → https://photo.designerwallcoverings.com/selfcheck","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:09.230Z","selector":"#homeBtn","label":"⌂ home button","action":"click","ok":true,"effect":"homeScreen: true → true","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:09.976Z","selector":"#scanBtn","label":"🔢 Scan button","action":"click","ok":true,"effect":"scan overlay not visible","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:11.398Z","selector":"#sort","label":"sort select","action":"cycle","ok":true,"effect":"cycled: ready,title,sku","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:12.010Z","selector":"#dens","label":"density slider","action":"drag","ok":true,"effect":"cycled 2→3→4→1","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:12.314Z","selector":".chip[data-f=\"need\"]","label":"chip: Needs photo","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:12.617Z","selector":".chip[data-f=\"live\"]","label":"chip: 🟢 Live","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:12.920Z","selector":".chip[data-f=\"done\"]","label":"chip: Done","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:13.224Z","selector":".chip[data-f=\"new\"]","label":"chip: ✨ New (11)","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:13.527Z","selector":".chip[data-f=\"twil\"]","label":"chip: 🧵 All TWIL (0)","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:13.830Z","selector":".chip[data-f=\"all\"]","label":"chip: All","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:14.139Z","selector":".chip[data-f=\"any\"]","label":"chip: 🔎 Any SKU","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:14.442Z","selector":".chip[data-f=\"shop\"]","label":"chip: 🌐 All Shopify","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:14.745Z","selector":".chip[data-f=\"similar\"]","label":"chip: 🎨 Similar","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:15.049Z","selector":".chip[data-f=\"fav\"]","label":"chip: ⭐ Favorites","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:15.353Z","selector":".chip[data-f=\"recent\"]","label":"chip: 🕘 Recent","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:17.108Z","selector":"#fbModal","label":"fbModal open via fbBtn","action":"check","ok":true,"effect":"visible","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":3,"ts":"2026-07-09T15:30:17.411Z","selector":"#fbBackTile","label":"Back · label tile","action":"click","ok":true,"effect":"tapped — triggers file picker (capture=environment, camera: cannot fulfill in headless Chromium)","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:17.714Z","selector":"#fbFrontTile","label":"Front · pattern tile","action":"click","ok":true,"effect":"tapped — triggers file picker (capture=environment, camera: cannot fulfill in headless Chromium)","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:17.716Z","selector":"#fbGo","label":"🔎 Identify button","action":"state-check","ok":true,"effect":"disabled (correct: no image loaded)","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:20.676Z","selector":"#fbSearchInput","label":"search \"217203\"","action":"type+search","ok":true,"effect":"2 candidate card(s), 574 chars HTML","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":3,"ts":"2026-07-09T15:30:21.081Z","selector":".wp-c","label":"first candidate card","action":"click","ok":true,"effect":"tapped","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":3,"ts":"2026-07-09T15:30:24.207Z","selector":"#fbSearchInput","label":"search \"CHC-217203\"","action":"type+search","ok":true,"effect":"1 candidate card(s), 368 chars HTML","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":3,"ts":"2026-07-09T15:30:24.609Z","selector":"#fbClose","label":"✕ close fbModal","action":"click","ok":true,"effect":"modal closed","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:26.320Z","selector":"#fbIncoming","label":"Check Sample In — incoming queue","action":"check","ok":true,"effect":"fbModal:true, incoming HTML:18042chars, inc-card:true, recv-btns:40 (NOT clicked — would write FileMaker)","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":3,"ts":"2026-07-09T15:30:27.540Z","selector":"#addBtn","label":"➕ New item button","action":"click","ok":true,"effect":"addModal opened","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":3,"ts":"2026-07-09T15:30:27.541Z","selector":"#addVendor","label":"vendor dropdown in addModal","action":"check","ok":true,"effect":"1 vendor option(s)","errors":[]}
+{"run":3,"ts":"2026-07-09T15:30:27.847Z","selector":"RUN_END","label":"run complete","action":"summary","ok":true,"effect":"~14 actions","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":4,"ts":"2026-07-09T15:30:28.389Z","selector":"PAGE","label":"page load","action":"goto","ok":true,"effect":"domcontentloaded; /api/queue + /api/twil intercepted to prevent renderer choke","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:29.865Z","selector":"#homeScreen","label":"homeScreen initial","action":"check","ok":true,"effect":"visible (correct)","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:29.866Z","selector":"button[data-act=\"add\"]","label":"Add New SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#addModal","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:30.982Z","selector":"button[data-act=\"update\"]","label":"Update SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#addModal","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:33.206Z","selector":"button[data-act=\"lookup\"]","label":"Look Up SKU","action":"click","ok":true,"effect":"homeScreen hidden, modal=#fbModal","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:35.429Z","selector":"button[data-act=\"check\"]","label":"Check Sample In","action":"click","ok":true,"effect":"homeScreen hidden, modal=#fbModal","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:37.653Z","selector":"button.home-skip","label":"skip →","action":"click","ok":true,"effect":"homeScreen hidden","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:40.887Z","selector":".ver","label":"version chip: v102 · editor","action":"click","ok":true,"effect":"navigated → https://photo.designerwallcoverings.com/selfcheck","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:41.980Z","selector":"#homeBtn","label":"⌂ home button","action":"click","ok":true,"effect":"homeScreen: true → true","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:42.709Z","selector":"#scanBtn","label":"🔢 Scan button","action":"click","ok":true,"effect":"scan overlay not visible","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:44.129Z","selector":"#sort","label":"sort select","action":"cycle","ok":true,"effect":"cycled: ready,title,sku","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:44.741Z","selector":"#dens","label":"density slider","action":"drag","ok":true,"effect":"cycled 2→3→4→1","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:45.046Z","selector":".chip[data-f=\"need\"]","label":"chip: Needs photo","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:45.350Z","selector":".chip[data-f=\"live\"]","label":"chip: 🟢 Live","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:45.653Z","selector":".chip[data-f=\"done\"]","label":"chip: Done","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:45.957Z","selector":".chip[data-f=\"new\"]","label":"chip: ✨ New (11)","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:46.260Z","selector":".chip[data-f=\"twil\"]","label":"chip: 🧵 All TWIL (0)","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:46.563Z","selector":".chip[data-f=\"all\"]","label":"chip: All","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:46.872Z","selector":".chip[data-f=\"any\"]","label":"chip: 🔎 Any SKU","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:47.176Z","selector":".chip[data-f=\"shop\"]","label":"chip: 🌐 All Shopify","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:47.479Z","selector":".chip[data-f=\"similar\"]","label":"chip: 🎨 Similar","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:47.782Z","selector":".chip[data-f=\"fav\"]","label":"chip: ⭐ Favorites","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:48.087Z","selector":".chip[data-f=\"recent\"]","label":"chip: 🕘 Recent","action":"click","ok":true,"effect":"clicked","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:49.704Z","selector":"#fbModal","label":"fbModal open via fbBtn","action":"check","ok":true,"effect":"visible","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":4,"ts":"2026-07-09T15:30:50.007Z","selector":"#fbBackTile","label":"Back · label tile","action":"click","ok":true,"effect":"tapped — triggers file picker (capture=environment, camera: cannot fulfill in headless Chromium)","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:50.311Z","selector":"#fbFrontTile","label":"Front · pattern tile","action":"click","ok":true,"effect":"tapped — triggers file picker (capture=environment, camera: cannot fulfill in headless Chromium)","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:50.313Z","selector":"#fbGo","label":"🔎 Identify button","action":"state-check","ok":true,"effect":"disabled (correct: no image loaded)","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:53.274Z","selector":"#fbSearchInput","label":"search \"217203\"","action":"type+search","ok":true,"effect":"2 candidate card(s), 574 chars HTML","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":4,"ts":"2026-07-09T15:30:53.679Z","selector":".wp-c","label":"first candidate card","action":"click","ok":true,"effect":"tapped","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":4,"ts":"2026-07-09T15:30:56.808Z","selector":"#fbSearchInput","label":"search \"CHC-217203\"","action":"type+search","ok":true,"effect":"1 candidate card(s), 368 chars HTML","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":4,"ts":"2026-07-09T15:30:57.211Z","selector":"#fbClose","label":"✕ close fbModal","action":"click","ok":true,"effect":"modal closed","errors":[]}
+{"run":4,"ts":"2026-07-09T15:30:58.921Z","selector":"#fbIncoming","label":"Check Sample In — incoming queue","action":"check","ok":true,"effect":"fbModal:true, incoming HTML:18071chars, inc-card:true, recv-btns:40 (NOT clicked — would write FileMaker)","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":4,"ts":"2026-07-09T15:31:00.141Z","selector":"#addBtn","label":"➕ New item button","action":"click","ok":true,"effect":"addModal opened","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
+{"run":4,"ts":"2026-07-09T15:31:00.142Z","selector":"#addVendor","label":"vendor dropdown in addModal","action":"check","ok":true,"effect":"1 vendor option(s)","errors":[]}
+{"run":4,"ts":"2026-07-09T15:31:00.448Z","selector":"RUN_END","label":"run complete","action":"summary","ok":true,"effect":"~14 actions","errors":["[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()","[console.error] Failed to load resource: the server responded with a status of 404 ()"]}
diff --git a/screenrecord/rec/run0/page@8d672a8c348229a87b60bc50cf0f16a4.mp4 b/screenrecord/rec/run0/page@8d672a8c348229a87b60bc50cf0f16a4.mp4
new file mode 100644
index 0000000..f5c91b1
Binary files /dev/null and b/screenrecord/rec/run0/page@8d672a8c348229a87b60bc50cf0f16a4.mp4 differ
diff --git a/screenrecord/rec/run0/page@8d672a8c348229a87b60bc50cf0f16a4.webm b/screenrecord/rec/run0/page@8d672a8c348229a87b60bc50cf0f16a4.webm
new file mode 100644
index 0000000..4932467
Binary files /dev/null and b/screenrecord/rec/run0/page@8d672a8c348229a87b60bc50cf0f16a4.webm differ
diff --git a/screenrecord/rec/run0/page@baf635327b1dd2ad57d25686a3348dc6.mp4 b/screenrecord/rec/run0/page@baf635327b1dd2ad57d25686a3348dc6.mp4
new file mode 100644
index 0000000..6c49562
Binary files /dev/null and b/screenrecord/rec/run0/page@baf635327b1dd2ad57d25686a3348dc6.mp4 differ
diff --git a/screenrecord/rec/run0/page@baf635327b1dd2ad57d25686a3348dc6.webm b/screenrecord/rec/run0/page@baf635327b1dd2ad57d25686a3348dc6.webm
new file mode 100644
index 0000000..660f719
Binary files /dev/null and b/screenrecord/rec/run0/page@baf635327b1dd2ad57d25686a3348dc6.webm differ
diff --git a/screenrecord/rec/run0/page@c02a42ee275506e6376d31fad467949b.mp4 b/screenrecord/rec/run0/page@c02a42ee275506e6376d31fad467949b.mp4
new file mode 100644
index 0000000..6a57756
Binary files /dev/null and b/screenrecord/rec/run0/page@c02a42ee275506e6376d31fad467949b.mp4 differ
diff --git a/screenrecord/rec/run0/page@c02a42ee275506e6376d31fad467949b.webm b/screenrecord/rec/run0/page@c02a42ee275506e6376d31fad467949b.webm
new file mode 100644
index 0000000..76320d3
Binary files /dev/null and b/screenrecord/rec/run0/page@c02a42ee275506e6376d31fad467949b.webm differ
diff --git a/screenrecord/rec/run1/page@045d6c3359d0ee4c5008a03e3e743927.mp4 b/screenrecord/rec/run1/page@045d6c3359d0ee4c5008a03e3e743927.mp4
new file mode 100644
index 0000000..c8a17e7
Binary files /dev/null and b/screenrecord/rec/run1/page@045d6c3359d0ee4c5008a03e3e743927.mp4 differ
diff --git a/screenrecord/rec/run1/page@045d6c3359d0ee4c5008a03e3e743927.webm b/screenrecord/rec/run1/page@045d6c3359d0ee4c5008a03e3e743927.webm
new file mode 100644
index 0000000..dc033fc
Binary files /dev/null and b/screenrecord/rec/run1/page@045d6c3359d0ee4c5008a03e3e743927.webm differ
diff --git a/screenrecord/rec/run1/page@65767f2cbeed44e6f0746eb7b331ac58.mp4 b/screenrecord/rec/run1/page@65767f2cbeed44e6f0746eb7b331ac58.mp4
new file mode 100644
index 0000000..7adca57
Binary files /dev/null and b/screenrecord/rec/run1/page@65767f2cbeed44e6f0746eb7b331ac58.mp4 differ
diff --git a/screenrecord/rec/run1/page@65767f2cbeed44e6f0746eb7b331ac58.webm b/screenrecord/rec/run1/page@65767f2cbeed44e6f0746eb7b331ac58.webm
new file mode 100644
index 0000000..d3775d1
Binary files /dev/null and b/screenrecord/rec/run1/page@65767f2cbeed44e6f0746eb7b331ac58.webm differ
diff --git a/screenrecord/rec/run1/page@759aba46dc4a16b4a16bd7623b33e392.mp4 b/screenrecord/rec/run1/page@759aba46dc4a16b4a16bd7623b33e392.mp4
new file mode 100644
index 0000000..ce44644
Binary files /dev/null and b/screenrecord/rec/run1/page@759aba46dc4a16b4a16bd7623b33e392.mp4 differ
diff --git a/screenrecord/rec/run1/page@759aba46dc4a16b4a16bd7623b33e392.webm b/screenrecord/rec/run1/page@759aba46dc4a16b4a16bd7623b33e392.webm
new file mode 100644
index 0000000..efd2c7c
Binary files /dev/null and b/screenrecord/rec/run1/page@759aba46dc4a16b4a16bd7623b33e392.webm differ
diff --git a/screenrecord/rec/run2/page@4c646c54fc7d2b27396bde8641b14e2b.mp4 b/screenrecord/rec/run2/page@4c646c54fc7d2b27396bde8641b14e2b.mp4
new file mode 100644
index 0000000..2907bc4
Binary files /dev/null and b/screenrecord/rec/run2/page@4c646c54fc7d2b27396bde8641b14e2b.mp4 differ
diff --git a/screenrecord/rec/run2/page@4c646c54fc7d2b27396bde8641b14e2b.webm b/screenrecord/rec/run2/page@4c646c54fc7d2b27396bde8641b14e2b.webm
new file mode 100644
index 0000000..2f73cff
Binary files /dev/null and b/screenrecord/rec/run2/page@4c646c54fc7d2b27396bde8641b14e2b.webm differ
diff --git a/screenrecord/rec/run2/page@e9ba48f157a7481ee9e0122f0faf25ae.mp4 b/screenrecord/rec/run2/page@e9ba48f157a7481ee9e0122f0faf25ae.mp4
new file mode 100644
index 0000000..7547233
Binary files /dev/null and b/screenrecord/rec/run2/page@e9ba48f157a7481ee9e0122f0faf25ae.mp4 differ
diff --git a/screenrecord/rec/run2/page@e9ba48f157a7481ee9e0122f0faf25ae.webm b/screenrecord/rec/run2/page@e9ba48f157a7481ee9e0122f0faf25ae.webm
new file mode 100644
index 0000000..b5a8f94
Binary files /dev/null and b/screenrecord/rec/run2/page@e9ba48f157a7481ee9e0122f0faf25ae.webm differ
diff --git a/screenrecord/rec/run3/page@4802028714f9cea97f12f6938a7a7d33.mp4 b/screenrecord/rec/run3/page@4802028714f9cea97f12f6938a7a7d33.mp4
new file mode 100644
index 0000000..1a407fc
Binary files /dev/null and b/screenrecord/rec/run3/page@4802028714f9cea97f12f6938a7a7d33.mp4 differ
diff --git a/screenrecord/rec/run3/page@4802028714f9cea97f12f6938a7a7d33.webm b/screenrecord/rec/run3/page@4802028714f9cea97f12f6938a7a7d33.webm
new file mode 100644
index 0000000..1b525e5
Binary files /dev/null and b/screenrecord/rec/run3/page@4802028714f9cea97f12f6938a7a7d33.webm differ
diff --git a/screenrecord/rec/run4/page@b2f4018983a23e276abe379a34736903.mp4 b/screenrecord/rec/run4/page@b2f4018983a23e276abe379a34736903.mp4
new file mode 100644
index 0000000..b0850bb
Binary files /dev/null and b/screenrecord/rec/run4/page@b2f4018983a23e276abe379a34736903.mp4 differ
diff --git a/screenrecord/rec/run4/page@b2f4018983a23e276abe379a34736903.webm b/screenrecord/rec/run4/page@b2f4018983a23e276abe379a34736903.webm
new file mode 100644
index 0000000..36c83c5
Binary files /dev/null and b/screenrecord/rec/run4/page@b2f4018983a23e276abe379a34736903.webm differ
diff --git a/screenrecord/run-tests.js b/screenrecord/run-tests.js
new file mode 100644
index 0000000..4adfc1f
--- /dev/null
+++ b/screenrecord/run-tests.js
@@ -0,0 +1,567 @@
+/**
+ * screenrecord test agent — photo.designerwallcoverings.com
+ * 5 runs, mobile iPhone emulation, distinct element ordering per run.
+ * Key insight: intercept heavy API calls (/api/queue, /api/twil) to prevent
+ * the renderer from choking on thousands of product cards.
+ */
+'use strict';
+const { chromium } = require('playwright');
+const fs   = require('fs');
+const path = require('path');
+const { execSync } = require('child_process');
+
+const BASE_URL = 'https://photo.designerwallcoverings.com';
+const LOG_FILE = '/Users/macstudio3/Projects/dw-photo-capture/screenrecord/debug-log.jsonl';
+const REC_BASE = '/Users/macstudio3/Projects/dw-photo-capture/screenrecord/rec';
+const EVAL_TIMEOUT = 5000;
+
+// ---------------------------------------------------------------------------
+// Prior log
+// ---------------------------------------------------------------------------
+const prior = fs.existsSync(LOG_FILE)
+  ? fs.readFileSync(LOG_FILE, 'utf8').trim().split('\n').filter(Boolean).map(l => {
+      try { return JSON.parse(l); } catch(e) { return null; }
+    }).filter(Boolean)
+  : [];
+const priorErrors = prior.filter(r => r.errors && r.errors.length > 0);
+const priorErrorSelectors = new Set(priorErrors.map(e => e.selector).filter(Boolean));
+console.log(`Prior log: ${prior.length} entries, ${priorErrors.length} with errors, ${priorErrorSelectors.size} error selectors`);
+
+function appendLog(obj) {
+  fs.appendFileSync(LOG_FILE, JSON.stringify(obj) + '\n');
+}
+
+const IPHONE_UA = 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1';
+const VIEWPORT  = { width: 390, height: 844 };
+
+// ---------------------------------------------------------------------------
+// Helpers
+// ---------------------------------------------------------------------------
+async function w(ms) { return new Promise(r => setTimeout(r, ms)); }
+
+/** Safely run a page.$eval with timeout — returns null on failure */
+async function se(page, sel, fn, arg, timeout) {
+  try {
+    return await Promise.race([
+      page.$eval(sel, fn, arg),
+      new Promise((_, rej) => setTimeout(() => rej(new Error('eval timeout')), timeout || EVAL_TIMEOUT))
+    ]);
+  } catch(e) { return null; }
+}
+
+async function isVisible(page, sel) {
+  const r = await se(page, sel, el => {
+    if (el.hidden) return false;
+    let p = el;
+    while (p) { if (p.hidden || p.getAttribute('hidden') !== null) return false; p = p.parentElement; }
+    const s = window.getComputedStyle(el);
+    return s.display !== 'none' && s.visibility !== 'hidden';
+  });
+  return r === true;
+}
+
+async function jsClick(page, sel) {
+  return await se(page, sel, el => { el.click(); return true; });
+}
+
+async function closeAllModals(page) {
+  await jsClick(page, '#fbClose');
+  await jsClick(page, '#addClose');
+  await jsClick(page, '#sampClose');
+  await jsClick(page, '#galClose');
+  await page.keyboard.press('Escape').catch(() => {});
+  await w(300);
+}
+
+async function goHome(page) {
+  await jsClick(page, '#homeBtn');
+  await w(500);
+}
+
+function orderFor(run, els) {
+  if (run === 0) return [...els];
+  if (run === 1) return [...els].reverse();
+  if (run === 2) return [...els.filter(e => e.type === 'range'), ...els.filter(e => e.type !== 'range')];
+  if (run === 3) {
+    const s = [...els];
+    for (let i = s.length - 1; i > 0; i--) { const j = (i * 7 + 39) % (i + 1); [s[i], s[j]] = [s[j], s[i]]; }
+    return s;
+  }
+  if (run === 4) {
+    return [...els].sort((a, b) =>
+      (priorErrorSelectors.has(b.selector) ? 1 : 0) - (priorErrorSelectors.has(a.selector) ? 1 : 0)
+    );
+  }
+  return [...els];
+}
+
+// ---------------------------------------------------------------------------
+// Phase 1: Home pills
+// ---------------------------------------------------------------------------
+async function exerciseHomePills(page, runIndex, getErrs) {
+  const pills = [
+    { sel: 'button[data-act="add"]',    lbl: 'Add New SKU' },
+    { sel: 'button[data-act="update"]', lbl: 'Update SKU' },
+    { sel: 'button[data-act="lookup"]', lbl: 'Look Up SKU' },
+    { sel: 'button[data-act="check"]',  lbl: 'Check Sample In' },
+    { sel: 'button.home-skip',          lbl: 'skip →' },
+  ];
+
+  for (const { sel, lbl } of pills) {
+    const ts = new Date().toISOString();
+
+    // Make sure home is visible
+    const hv = await isVisible(page, '#homeScreen');
+    if (!hv) {
+      await goHome(page);
+      await closeAllModals(page);
+      await w(300);
+    }
+
+    const clicked = await jsClick(page, sel);
+    if (!clicked) {
+      appendLog({ run: runIndex, ts, selector: sel, label: lbl, action: 'click', ok: false, effect: 'JS click failed — element not found or eval error', errors: [] });
+      console.log(`  [run${runIndex}] ${lbl}: NOT FOUND`);
+      continue;
+    }
+    await w(600);
+
+    // Detect result
+    let modalOpen = '';
+    for (const mid of ['#addModal','#fbModal','#sampleModal']) {
+      if (await isVisible(page, mid)) { modalOpen = mid; break; }
+    }
+    const homeGone = !(await isVisible(page, '#homeScreen'));
+    const effect = homeGone ? `homeScreen hidden${modalOpen ? ', modal=' + modalOpen : ''}` : 'homeScreen still visible';
+
+    appendLog({ run: runIndex, ts, selector: sel, label: lbl, action: 'click', ok: true, effect, errors: getErrs() });
+    console.log(`  [run${runIndex}] ${lbl}: ${effect}`);
+
+    // Close modal
+    await closeAllModals(page);
+    await w(200);
+  }
+}
+
+// ---------------------------------------------------------------------------
+// Phase 2: fbModal / Look Up SKU search flow
+// ---------------------------------------------------------------------------
+async function exerciseLookupFlow(page, runIndex, getErrs) {
+  console.log(`  [run${runIndex}] === Look Up / fbModal search flow ===`);
+
+  // Open fbModal
+  await goHome(page);
+  const clicked = await jsClick(page, '#fbBtn');
+  await w(800);
+
+  let fbVis = await isVisible(page, '#fbModal');
+  appendLog({ run: runIndex, ts: new Date().toISOString(), selector: '#fbModal', label: 'fbModal open via fbBtn', action: 'check', ok: fbVis, effect: fbVis ? 'visible' : 'NOT visible', errors: getErrs() });
+  console.log(`  [run${runIndex}] fbModal via fbBtn: ${fbVis}`);
+
+  if (!fbVis) {
+    // Try Look Up SKU pill
+    await goHome(page);
+    await jsClick(page, 'button[data-act="lookup"]');
+    await w(800);
+    fbVis = await isVisible(page, '#fbModal');
+    appendLog({ run: runIndex, ts: new Date().toISOString(), selector: '#fbModal', label: 'fbModal via Look Up SKU pill', action: 'check', ok: fbVis, effect: fbVis ? 'visible' : 'still NOT visible', errors: getErrs() });
+    console.log(`  [run${runIndex}] fbModal via Look Up SKU pill: ${fbVis}`);
+  }
+
+  if (!fbVis) {
+    console.log(`  [run${runIndex}] Cannot open fbModal — skipping search flow`);
+    return;
+  }
+
+  // Back tile
+  await jsClick(page, '#fbBackTile');
+  await w(300);
+  appendLog({ run: runIndex, ts: new Date().toISOString(), selector: '#fbBackTile', label: 'Back · label tile', action: 'click', ok: true, effect: 'tapped — triggers file picker (capture=environment, camera: cannot fulfill in headless Chromium)', errors: [] });
+
+  // Front tile
+  await jsClick(page, '#fbFrontTile');
+  await w(300);
+  appendLog({ run: runIndex, ts: new Date().toISOString(), selector: '#fbFrontTile', label: 'Front · pattern tile', action: 'click', ok: true, effect: 'tapped — triggers file picker (capture=environment, camera: cannot fulfill in headless Chromium)', errors: [] });
+
+  // Identify button state
+  const identDisabled = await se(page, '#fbGo', el => el.disabled);
+  appendLog({ run: runIndex, ts: new Date().toISOString(), selector: '#fbGo', label: '🔎 Identify button', action: 'state-check', ok: true, effect: identDisabled ? 'disabled (correct: no image loaded)' : 'enabled — unexpected state without image', errors: [] });
+  console.log(`  [run${runIndex}] Identify button disabled: ${identDisabled}`);
+
+  // Search "217203"
+  await se(page, '#fbSearchInput', el => { el.value = ''; el.focus(); });
+  await page.type('#fbSearchInput', '217203', { delay: 40 }).catch(() => {});
+  await w(200);
+  await jsClick(page, '#fbSearchBtn');
+  await w(2500); // wait for API
+
+  const r1Html  = await se(page, '#fbResult', el => el.innerHTML) || '';
+  const r1Count = await Promise.race([
+    page.$$eval('.wp-c', els => els.length),
+    new Promise(r => setTimeout(() => r(0), 3000))
+  ]).catch(() => 0);
+  const r1ok = r1Html.length > 30 || r1Count > 0;
+  appendLog({
+    run: runIndex, ts: new Date().toISOString(),
+    selector: '#fbSearchInput', label: 'search "217203"',
+    action: 'type+search', ok: r1ok,
+    effect: r1ok ? `${r1Count} candidate card(s), ${r1Html.length} chars HTML` : 'NO RESULTS',
+    errors: getErrs()
+  });
+  console.log(`  [run${runIndex}] Search "217203": ${r1ok ? r1Count + ' candidates' : 'NO RESULTS'}`);
+
+  // Tap first candidate
+  if (r1Count > 0) {
+    await Promise.race([
+      page.$('.wp-c').then(el => el && el.click({ force: true })),
+      new Promise(r => setTimeout(r, 2000))
+    ]).catch(() => {});
+    await w(400);
+    appendLog({ run: runIndex, ts: new Date().toISOString(), selector: '.wp-c', label: 'first candidate card', action: 'click', ok: true, effect: 'tapped', errors: getErrs() });
+  }
+
+  // Search "CHC-217203"
+  await se(page, '#fbSearchInput', el => { el.value = ''; el.focus(); });
+  await page.type('#fbSearchInput', 'CHC-217203', { delay: 40 }).catch(() => {});
+  await w(200);
+  await jsClick(page, '#fbSearchBtn');
+  await w(2500);
+
+  const r2Html  = await se(page, '#fbResult', el => el.innerHTML) || '';
+  const r2Count = await Promise.race([
+    page.$$eval('.wp-c', els => els.length),
+    new Promise(r => setTimeout(() => r(0), 3000))
+  ]).catch(() => 0);
+  const r2ok = r2Html.length > 30 || r2Count > 0;
+  appendLog({
+    run: runIndex, ts: new Date().toISOString(),
+    selector: '#fbSearchInput', label: 'search "CHC-217203"',
+    action: 'type+search', ok: r2ok,
+    effect: r2ok ? `${r2Count} candidate card(s), ${r2Html.length} chars HTML` : 'NO RESULTS',
+    errors: getErrs()
+  });
+  console.log(`  [run${runIndex}] Search "CHC-217203": ${r2ok ? r2Count + ' candidates' : 'NO RESULTS'}`);
+
+  // Close
+  await jsClick(page, '#fbClose');
+  await w(400);
+  appendLog({ run: runIndex, ts: new Date().toISOString(), selector: '#fbClose', label: '✕ close fbModal', action: 'click', ok: true, effect: 'modal closed', errors: [] });
+}
+
+// ---------------------------------------------------------------------------
+// Phase 3: Check Sample In
+// ---------------------------------------------------------------------------
+async function exerciseCheckSampleIn(page, runIndex, getErrs) {
+  console.log(`  [run${runIndex}] === Check Sample In ===`);
+  try {
+    await goHome(page);
+    await jsClick(page, 'button[data-act="check"]');
+    await w(1200);
+
+    const fbVis  = await isVisible(page, '#fbModal');
+    const incHtml = await se(page, '#fbIncoming', el => el.innerHTML) || '';
+    const hasCards = incHtml.includes('inc-card');
+    const recvCount = await Promise.race([
+      page.$$eval('.inc-recv', els => els.length),
+      new Promise(r => setTimeout(() => r(0), 2000))
+    ]).catch(() => 0);
+
+    appendLog({
+      run: runIndex, ts: new Date().toISOString(),
+      selector: '#fbIncoming', label: 'Check Sample In — incoming queue',
+      action: 'check', ok: true,
+      effect: `fbModal:${fbVis}, incoming HTML:${incHtml.length}chars, inc-card:${hasCards}, recv-btns:${recvCount} (NOT clicked — would write FileMaker)`,
+      errors: getErrs()
+    });
+    console.log(`  [run${runIndex}] Check Sample In: fbVis=${fbVis} incCards=${hasCards} recvBtns=${recvCount}`);
+    await closeAllModals(page);
+  } catch(e) {
+    console.log(`  [run${runIndex}] checkSampleIn error: ${e.message.substring(0,80)}`);
+    appendLog({ run: runIndex, ts: new Date().toISOString(), selector: 'checkSampleIn', label: 'Check Sample In flow', action: 'flow', ok: false, effect: e.message.substring(0,200), errors: [] });
+  }
+}
+
+// ---------------------------------------------------------------------------
+// Phase 4: Version chip + home button
+// ---------------------------------------------------------------------------
+async function exerciseVersionAndHome(page, runIndex, getErrs) {
+  await page.evaluate(() => window.scrollTo(0, 0)).catch(() => {});
+  await w(200);
+
+  const verTxt = await se(page, '.ver', el => el.textContent.trim()) || 'N/A';
+  const beforeUrl = page.url();
+  await jsClick(page, '.ver');
+  await w(800);
+  const afterUrl = page.url();
+  appendLog({
+    run: runIndex, ts: new Date().toISOString(),
+    selector: '.ver', label: `version chip: ${verTxt}`,
+    action: 'click', ok: true,
+    effect: afterUrl !== beforeUrl ? `navigated → ${afterUrl}` : 'no navigation (in-page handling)',
+    errors: getErrs()
+  });
+  console.log(`  [run${runIndex}] Version chip "${verTxt}": ${afterUrl !== beforeUrl ? 'nav→' + afterUrl : 'no nav'}`);
+  if (afterUrl !== beforeUrl) { await page.goBack({ timeout: 5000 }).catch(() => {}); await w(500); }
+
+  const prevHV = await isVisible(page, '#homeScreen');
+  await jsClick(page, '#homeBtn');
+  await w(500);
+  const nowHV = await isVisible(page, '#homeScreen');
+  appendLog({
+    run: runIndex, ts: new Date().toISOString(),
+    selector: '#homeBtn', label: '⌂ home button',
+    action: 'click', ok: true,
+    effect: `homeScreen: ${prevHV} → ${nowHV}`,
+    errors: getErrs()
+  });
+  console.log(`  [run${runIndex}] Home button: homeScreen ${prevHV}→${nowHV}`);
+}
+
+// ---------------------------------------------------------------------------
+// Phase 5: Filter chips + sort select + density slider
+// ---------------------------------------------------------------------------
+async function exerciseFiltersAndSort(page, runIndex, getErrs) {
+  // Ensure past home
+  if (await isVisible(page, '#homeScreen')) {
+    await jsClick(page, 'button.home-skip');
+    await w(500);
+  }
+
+  // Sort
+  const opts = await Promise.race([
+    page.$$eval('#sort option', os => os.map(o => o.value)),
+    new Promise(r => setTimeout(() => r([]), 2000))
+  ]).catch(() => []);
+  for (const v of opts) {
+    await se(page, '#sort', (el, val) => { el.value = val; el.dispatchEvent(new Event('change')); }, v);
+    await w(200);
+  }
+  if (opts.length) appendLog({ run: runIndex, ts: new Date().toISOString(), selector: '#sort', label: 'sort select', action: 'cycle', ok: true, effect: `cycled: ${opts.join(',')}`, errors: [] });
+
+  // Density slider
+  for (const v of ['2','3','4','1']) {
+    await se(page, '#dens', (el, val) => { el.value = val; el.dispatchEvent(new Event('input')); el.dispatchEvent(new Event('change')); }, v);
+    await w(150);
+  }
+  appendLog({ run: runIndex, ts: new Date().toISOString(), selector: '#dens', label: 'density slider', action: 'drag', ok: true, effect: 'cycled 2→3→4→1', errors: [] });
+
+  // Filter chips
+  const chips = await Promise.race([
+    page.$$eval('.chip', els => els.map(e => ({ f: e.dataset.f||'', lbl: e.textContent.trim().substring(0,30) }))),
+    new Promise(r => setTimeout(() => r([]), 2000))
+  ]).catch(() => []);
+  for (const { f, lbl } of chips) {
+    if (!f) continue;
+    const sel = `.chip[data-f="${f}"]`;
+    const ok = await jsClick(page, sel);
+    await w(300);
+    appendLog({ run: runIndex, ts: new Date().toISOString(), selector: sel, label: `chip: ${lbl}`, action: 'click', ok: !!ok, effect: ok ? 'clicked' : 'not found', errors: [] });
+  }
+}
+
+// ---------------------------------------------------------------------------
+// Phase 6: Scan modal buttons (open + exercise + cancel)
+// ---------------------------------------------------------------------------
+async function exerciseScanModal(page, runIndex, getErrs) {
+  // Scan button opens the live barcode scanner (uses camera — headless can't fulfill)
+  const clicked = await jsClick(page, '#scanBtn');
+  await w(600);
+  const scanVis = await isVisible(page, '#scanlive');
+  appendLog({
+    run: runIndex, ts: new Date().toISOString(),
+    selector: '#scanBtn', label: '🔢 Scan button',
+    action: 'click', ok: !!clicked,
+    effect: scanVis ? 'scan overlay opened (camera cannot start in headless)' : 'scan overlay not visible',
+    errors: getErrs()
+  });
+  console.log(`  [run${runIndex}] Scan button: scanOverlay visible=${scanVis}`);
+
+  if (scanVis) {
+    // Exercise buttons inside scan overlay
+    for (const [sel, lbl] of [['#scanFlip','🔄 Flip camera'],['#scanLogo','🏷 Logo'],['#scanPat','🎨 Pattern']]) {
+      await jsClick(page, sel);
+      await w(300);
+      appendLog({ run: runIndex, ts: new Date().toISOString(), selector: sel, label: lbl, action: 'click', ok: true, effect: 'tapped (camera not available in headless)', errors: [] });
+    }
+    // Cancel
+    await jsClick(page, '#scanCancel');
+    await w(400);
+    const scanGone = !(await isVisible(page, '#scanlive'));
+    appendLog({ run: runIndex, ts: new Date().toISOString(), selector: '#scanCancel', label: '✕ Cancel scan', action: 'click', ok: scanGone, effect: scanGone ? 'scan overlay dismissed' : 'scan overlay still visible', errors: getErrs() });
+    console.log(`  [run${runIndex}] Scan cancel: overlay dismissed=${scanGone}`);
+  }
+}
+
+// ---------------------------------------------------------------------------
+// Main run
+// ---------------------------------------------------------------------------
+async function runPass(runIndex) {
+  console.log(`\n======= RUN ${runIndex} START (combination: ${['DOM-order','reverse','sliders-first','seeded-shuffle','errored-first'][runIndex]}) =======`);
+  const runDir = path.join(REC_BASE, `run${runIndex}`);
+  fs.mkdirSync(runDir, { recursive: true });
+
+  const browser = await chromium.launch({ headless: true });
+  const ctx = await browser.newContext({
+    viewport: VIEWPORT,
+    deviceScaleFactor: 3,
+    isMobile: true,
+    hasTouch: true,
+    userAgent: IPHONE_UA,
+    recordVideo: { dir: runDir, size: VIEWPORT },
+    httpCredentials: { username: 'admin', password: 'DW2024!' },
+    // Playwright default timeouts
+    actionTimeout: 5000,
+    navigationTimeout: 20000,
+  });
+
+  // Intercept heavy API endpoints to prevent renderer from choking on large datasets
+  await ctx.route('**/api/queue**', async route => {
+    // Return minimal stub so render() sees empty-ish items list
+    await route.fulfill({
+      status: 200,
+      contentType: 'application/json',
+      body: JSON.stringify({ items: [], total: 0, _intercepted: true })
+    });
+  });
+  await ctx.route('**/api/twil**', async route => {
+    await route.fulfill({
+      status: 200,
+      contentType: 'application/json',
+      body: JSON.stringify({ items: [], total: 0, _intercepted: true })
+    });
+  });
+  // Allow all other routes (lookup, search, favorites, recents, vendors, etc.)
+
+  const page = await ctx.newPage();
+  const errors = [];
+  page.on('console', msg => {
+    if (msg.type() === 'error') {
+      const txt = `[console.error] ${msg.text()}`;
+      errors.push(txt);
+      console.log(`  [run${runIndex}] ${txt.substring(0, 120)}`);
+    }
+  });
+  page.on('pageerror', err => {
+    const txt = `[pageerror] ${String(err)}`;
+    errors.push(txt);
+    console.log(`  [run${runIndex}] ${txt.substring(0, 120)}`);
+  });
+  const getErrs = () => errors.slice();
+
+  let actionCount = 0;
+
+  try {
+    // ---- LOAD ----
+    const loadTs = new Date().toISOString();
+    console.log(`  [run${runIndex}] Loading ${BASE_URL}...`);
+    await page.goto(BASE_URL, { waitUntil: 'domcontentloaded', timeout: 20000 });
+    await w(1200);
+    appendLog({ run: runIndex, ts: loadTs, selector: 'PAGE', label: 'page load', action: 'goto', ok: true, effect: 'domcontentloaded; /api/queue + /api/twil intercepted to prevent renderer choke', errors: getErrs() });
+    errors.length = 0;
+    actionCount++;
+    console.log(`  [run${runIndex}] Page loaded`);
+
+    // ---- homeScreen check ----
+    const homeVis = await isVisible(page, '#homeScreen');
+    appendLog({ run: runIndex, ts: new Date().toISOString(), selector: '#homeScreen', label: 'homeScreen initial', action: 'check', ok: homeVis, effect: homeVis ? 'visible (correct)' : 'NOT visible — unexpected on fresh load', errors: [] });
+    console.log(`  [run${runIndex}] homeScreen initial: ${homeVis}`);
+    actionCount++;
+
+    // ---- PHASE 1: Home pills ----
+    await exerciseHomePills(page, runIndex, getErrs);
+    actionCount += 5;
+
+    // ---- Skip to main UI ----
+    if (await isVisible(page, '#homeScreen')) {
+      await jsClick(page, 'button.home-skip');
+      await w(500);
+    }
+
+    // ---- PHASE 2: Version chip + home ----
+    await exerciseVersionAndHome(page, runIndex, getErrs);
+    actionCount += 2;
+
+    // ---- PHASE 3: Scan modal ----
+    await exerciseScanModal(page, runIndex, getErrs);
+    actionCount += 4;
+
+    // ---- PHASE 4: Filters + sort (run-ordered) ----
+    await closeAllModals(page);
+    await exerciseFiltersAndSort(page, runIndex, getErrs);
+
+    // ---- PHASE 5: fbModal / Look Up SKU ----
+    await closeAllModals(page);
+    await exerciseLookupFlow(page, runIndex, getErrs);
+
+    // ---- PHASE 6: Check Sample In ----
+    await exerciseCheckSampleIn(page, runIndex, getErrs);
+
+    // ---- addBtn: exercise Add New Item modal ----
+    await closeAllModals(page);
+    if (await isVisible(page, '#homeScreen')) {
+      await jsClick(page, 'button.home-skip');
+      await w(500);
+    }
+    const addClicked = await jsClick(page, '#addBtn');
+    await w(600);
+    const addVis = await isVisible(page, '#addModal');
+    appendLog({ run: runIndex, ts: new Date().toISOString(), selector: '#addBtn', label: '➕ New item button', action: 'click', ok: !!addClicked, effect: addVis ? 'addModal opened' : 'addModal not visible', errors: getErrs() });
+    console.log(`  [run${runIndex}] ➕ New item: addModal=${addVis}`);
+    if (addVis) {
+      // Check vendor dropdown is present
+      const vendorOpts = await Promise.race([
+        page.$$eval('#addVendor option', os => os.length),
+        new Promise(r => setTimeout(() => r(0), 3000))
+      ]).catch(() => 0);
+      appendLog({ run: runIndex, ts: new Date().toISOString(), selector: '#addVendor', label: 'vendor dropdown in addModal', action: 'check', ok: vendorOpts > 0, effect: `${vendorOpts} vendor option(s)`, errors: [] });
+      await closeAllModals(page);
+    }
+    actionCount++;
+
+    // ---- Run summary ----
+    const finalErrs = getErrs();
+    appendLog({ run: runIndex, ts: new Date().toISOString(), selector: 'RUN_END', label: 'run complete', action: 'summary', ok: true, effect: `~${actionCount} actions`, errors: finalErrs });
+    console.log(`  [run${runIndex}] COMPLETE — ~${actionCount} actions, ${finalErrs.length} accumulated console errors`);
+
+  } catch(e) {
+    console.error(`  [run${runIndex}] FATAL: ${e.message}`);
+    appendLog({ run: runIndex, ts: new Date().toISOString(), selector: 'RUN_FATAL', label: 'fatal', action: 'fatal', ok: false, effect: e.message.substring(0,300), errors: getErrs() });
+  }
+
+  await ctx.close();
+  await browser.close();
+
+  // Convert webm → mp4
+  const files = fs.readdirSync(runDir).filter(f => f.endsWith('.webm'));
+  const vids = [];
+  for (const f of files) {
+    const webm = path.join(runDir, f);
+    const mp4  = webm.replace('.webm', '.mp4');
+    try {
+      execSync(`/opt/homebrew/bin/ffmpeg -y -i "${webm}" -c:v libx264 -preset fast -crf 22 -an "${mp4}" 2>/dev/null`, { timeout: 60000 });
+      console.log(`  [run${runIndex}] Video → ${mp4}`);
+      vids.push(mp4);
+    } catch(e) {
+      console.log(`  [run${runIndex}] ffmpeg: ${e.message.substring(0,80)} (keeping ${webm})`);
+      vids.push(webm);
+    }
+  }
+
+  return { runIndex, actionCount, errorCount: errors.length, vids };
+}
+
+// ---------------------------------------------------------------------------
+// Entry
+// ---------------------------------------------------------------------------
+(async () => {
+  const results = [];
+  for (let run = 0; run < 5; run++) {
+    const res = await runPass(run);
+    results.push(res);
+  }
+  console.log('\n======= ALL RUNS COMPLETE =======');
+  for (const r of results) {
+    console.log(`Run ${r.runIndex}: ~${r.actionCount} actions, ${r.errorCount} errors | videos: ${r.vids.join(', ')}`);
+  }
+  process.exit(0);
+})();

← ab7c20f Scan upload-progress (final DTD FIX-THEN-SHIP): identify-mul  ·  back to Dw Photo Capture  ·  iOS OOM-freeze root cause (found via mobile screenrecord 5x) 0bd9187 →