← back to Dw Title Repair
TK-11376: re-read 3x before declaring a product not_found
2933b94faed376044e1a0a28434d1f5f25c95ee5 · 2026-09-10 09:45:51 -0700 · steve
Observed mid-run: the verify read returned null for two products that
demonstrably exist and are ACTIVE (they had already been renamed in stage 1).
A transient null was being treated as 'deleted' and skipped. Harmless for an
already-applied product, but an unapplied one could have been silently missed.
Now re-reads 3x with backoff before believing it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Files touched
Diff
commit 2933b94faed376044e1a0a28434d1f5f25c95ee5
Author: steve <steve@designerwallcoverings.com>
Date: Thu Sep 10 09:45:51 2026 -0700
TK-11376: re-read 3x before declaring a product not_found
Observed mid-run: the verify read returned null for two products that
demonstrably exist and are ACTIVE (they had already been renamed in stage 1).
A transient null was being treated as 'deleted' and skipped. Harmless for an
already-applied product, but an unapplied one could have been silently missed.
Now re-reads 3x with backoff before believing it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---
apply.mjs | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/apply.mjs b/apply.mjs
index 0fa96f2..efd27dc 100755
--- a/apply.mjs
+++ b/apply.mjs
@@ -25,9 +25,17 @@ const Q=`mutation($id:ID!,$t:String!){productUpdate(input:{id:$id,title:$t}){pro
let ok=0,skip=0,err=0;
for(const [i,r] of work.entries()){
// VERIFY-BEFORE-WRITE: only write if the live title is still what we recorded
- const cur=await gql(`{product(id:"${r.id}"){title}}`);
- const live=cur?.data?.product?.title;
- if(live===undefined){err++;ledger.write(JSON.stringify({id:r.id,status:'not_found'})+'\n');continue;}
+ // A null/undefined product can be a TRANSIENT read failure, not a deleted product —
+ // observed mid-run on products that demonstrably exist and are ACTIVE. Re-read before
+ // believing it, so a blip can never silently skip an unapplied product.
+ let live;
+ for(let a=0;a<3;a++){
+ const cur=await gql(`{product(id:"${r.id}"){title}}`);
+ live=cur?.data?.product?.title;
+ if(live!==undefined) break;
+ await new Promise(s=>setTimeout(s,800*(a+1)));
+ }
+ if(live===undefined){err++;ledger.write(JSON.stringify({id:r.id,status:'not_found_after_3_reads'})+'\n');continue;}
if(live===r.to){skip++;ledger.write(JSON.stringify({id:r.id,status:'already_target'})+'\n');continue;}
if(live!==r.from){skip++;ledger.write(JSON.stringify({id:r.id,status:'drifted',live,expected:r.from})+'\n');continue;}
if(!APPLY){ok++;ledger.write(JSON.stringify({id:r.id,status:'DRYRUN',from:r.from,to:r.to})+'\n');continue;}
← 48ff5d4 TK-11376 supplement: recover 920 more products via dw_sku me
·
back to Dw Title Repair
·
TK-11376: add supplement rollback (t8) and document the 17-i 36da240 →