← 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 →