[object Object]

← back to Dw Photo Capture

Contrarian gate fix (dedup): add _addSession guard before every DOM write (no stale warning/switch into a reopened modal) + require a non-null product_id before offering 'Update instead' (was binding null pid → wrong-product write)

828996ff2a1f6d180e924af80b9eedaa00cc3b90 · 2026-07-07 10:18:06 -0700 · Steve Abrams

Files touched

Diff

commit 828996ff2a1f6d180e924af80b9eedaa00cc3b90
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Tue Jul 7 10:18:06 2026 -0700

    Contrarian gate fix (dedup): add _addSession guard before every DOM write (no stale warning/switch into a reopened modal) + require a non-null product_id before offering 'Update instead' (was binding null pid → wrong-product write)
---
 public/index.html | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/public/index.html b/public/index.html
index bfbaf51..0c15180 100644
--- a/public/index.html
+++ b/public/index.html
@@ -1554,17 +1554,19 @@ async function bindProduct(mfr,sku,confirmed){ const qs=mfr?('mfr='+encodeURICom
     if(r.found){ _updatePid=r.product_id; _updateSku=r.dw_sku; _updateNeedsConfirm=!confirmed; return r; } }catch(e){} return null; }
 // ADD-MODE DEDUP: before creating a new SKU, check the pattern photo against the catalog (fine-tuned
 // visual-ID). If it strongly matches an existing product, WARN (non-blocking) + offer "Update instead".
-async function addDedupCheck(){ const photos=addPhotosList(); if(!photos.length || _addMode!=='add') return;
+async function addDedupCheck(){ const mySession=_addSession;   // guard against a stale result landing in a reopened modal
+  const photos=addPhotosList(); if(!photos.length || _addMode!=='add') return;
   let r; try{ r=await(await fetch('/api/identify-multi',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({front:photos[photos.length-1]})})).json(); }catch(e){ return; }
-  const prim=r&&r.primary; if(!prim || !r.confidence || r.confidence==='low' || _addMode!=='add') return;   // only warn on a confident match
+  const prim=r&&r.primary; if(!prim || !r.confidence || r.confidence==='low') return;   // only warn on a confident match
+  if(_addMode!=='add' || _addSession!==mySession) return;   // modal switched/reopened mid-request — discard
   const label=prim.pattern || prim.dw_sku || prim.mfr_sku || 'an existing item';
   // WARN using the visual match itself (the pattern exists in the catalog even if it doesn't map to a live product_id)
   $('#addTarget').innerHTML=`⚠ This pattern may already exist as <b>${label}</b>${prim.dw_sku?(' <small>('+prim.dw_sku+')</small>'):''} <small>· ${r.confidence}</small>`;
-  // try to resolve it to a LIVE product (mfr then dw_sku) so we can offer a one-tap "Update instead"
+  // resolve to a LIVE product (mfr then dw_sku) — REQUIRE a real product_id, else no "Update" shortcut
   let hit=null;
   for(const qs of [prim.mfr_sku&&('mfr='+encodeURIComponent(prim.mfr_sku)), prim.dw_sku&&('sku='+encodeURIComponent(prim.dw_sku))].filter(Boolean)){
-    try{ const h=await(await fetch('/api/resolve-product?'+qs)).json(); if(h.found){ hit=h; break; } }catch(e){} }
-  if(_addMode!=='add') return;
+    try{ const h=await(await fetch('/api/resolve-product?'+qs)).json(); if(h.found && h.product_id){ hit=h; break; } }catch(e){} }
+  if(_addMode!=='add' || _addSession!==mySession) return;   // re-check after the resolve awaits
   if(hit){ $('#addTarget').innerHTML+=` <button class="vid-chip" id="addSwitchUpd">↻ Update it instead</button>`;
     const el=document.getElementById('addSwitchUpd'); if(el) el.addEventListener('click',()=>switchToUpdate(hit)); } }
 // user chose to update the existing match instead of creating a dup — bind it (explicit → no extra confirm)

← cf2ea4a Add-mode visual dedup: new-SKU pattern photo → fine-tuned vi  ·  back to Dw Photo Capture  ·  5x: 2 consecutive clean sweeps (0 app defects) post FT-model 8694d87 →