← back to Designerwallcoverings
TK-10895: bring main's copies to the final verified state (27999a6 + b0416ab)
a6afe99c25febd9af69e5fb52506d73429fa14ab · 2026-09-10 14:28:34 -0700 · Steve
The last two cherry-picks conflicted because they replay intermediate states of
files main had already diverged on. Replaying that history is not the goal - the
goal is that main holds the SAME scripts that produced today's verified writes.
So these are the exact file contents from tk11357-zero-price-source-fix; a diff
of all three files against that branch is empty.
Carries:
27999a6 G1/G2/G3 release a row only on a recorded, named adjudication
(LENGTH-NOT-STATED / LOADED-TOKEN-SUPPORTED / WP-ROW-COST-SUPPORTED),
and G1 forces the length-free label on a length-adjudicated row.
b0416ab --table for the sheet-wide fabric-row sweep, plus the CDN grace
period on the reprice script's post-write storefront check.
Why this mattered: all six TK-10895 commits had gone onto another ticket's
branch. main's executor still verified against the Admin API - the exact bug
that produced three false readings today - and tk10895-reprice-fabricrow5.mjs,
the tool that corrected 59 products' prices, did not exist on main at all.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Files touched
M scripts/tk10895-reprice-fabricrow5.mjsM scripts/tk10895-trancheB-golive-269.mjs
Diff
commit a6afe99c25febd9af69e5fb52506d73429fa14ab
Author: Steve <steve@designerwallcoverings.com>
Date: Thu Sep 10 14:28:34 2026 -0700
TK-10895: bring main's copies to the final verified state (27999a6 + b0416ab)
The last two cherry-picks conflicted because they replay intermediate states of
files main had already diverged on. Replaying that history is not the goal - the
goal is that main holds the SAME scripts that produced today's verified writes.
So these are the exact file contents from tk11357-zero-price-source-fix; a diff
of all three files against that branch is empty.
Carries:
27999a6 G1/G2/G3 release a row only on a recorded, named adjudication
(LENGTH-NOT-STATED / LOADED-TOKEN-SUPPORTED / WP-ROW-COST-SUPPORTED),
and G1 forces the length-free label on a length-adjudicated row.
b0416ab --table for the sheet-wide fabric-row sweep, plus the CDN grace
period on the reprice script's post-write storefront check.
Why this mattered: all six TK-10895 commits had gone onto another ticket's
branch. main's executor still verified against the Admin API - the exact bug
that produced three false readings today - and tk10895-reprice-fabricrow5.mjs,
the tool that corrected 59 products' prices, did not exist on main at all.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---
scripts/tk10895-reprice-fabricrow5.mjs | 26 ++++++++++++++++++++++++--
scripts/tk10895-trancheB-golive-269.mjs | 30 +++++++++++++++++++++++++-----
2 files changed, 49 insertions(+), 7 deletions(-)
diff --git a/scripts/tk10895-reprice-fabricrow5.mjs b/scripts/tk10895-reprice-fabricrow5.mjs
index 7c4eef0..3d12284 100644
--- a/scripts/tk10895-reprice-fabricrow5.mjs
+++ b/scripts/tk10895-reprice-fabricrow5.mjs
@@ -30,7 +30,23 @@ const T={
'709221':{p:'Bijou Stripe', wp:148, row:'5060-05WP', fab:183},
'709321':{p:'Birds II', wp:142, row:'5050-04WP', fab:182},
'709421':{p:'Birds II', wp:142, row:'5050-04WP', fab:182},
+ // El Cid, added 2026-09-10: our 7 live products carry mfr 726421-727021, which sit on the mill
+ // sheet's $172.00 row ALONGSIDE 303700F-10 (the 48" linen/cotton FABRIC). The wallpaper series
+ // 303700W-01..-10 is a clean single $143.00. Confirmed by width: ours are 24.5" paper, matching
+ // the W spec, not the 48" F spec.
+ '726421':{p:'El Cid', wp:143, row:'303700W-01', fab:172},
+ '726521':{p:'El Cid', wp:143, row:'303700W-02', fab:172},
+ '726621':{p:'El Cid', wp:143, row:'303700W-03', fab:172},
+ '726721':{p:'El Cid', wp:143, row:'303700W-04', fab:172},
+ '726821':{p:'El Cid', wp:143, row:'303700W-05', fab:172},
+ '726921':{p:'El Cid', wp:143, row:'303700W-06', fab:172},
+ '727021':{p:'El Cid', wp:143, row:'303700W-07', fab:172},
};
+// Optional table file: the hardcoded T above is the original 12; a JSON file lets a wider,
+// evidence-driven sweep be repriced without editing code. Same shape: {mfr:{p,wp,row,fab}}.
+const TF=(()=>{const i=process.argv.indexOf('--table');return i>-1?process.argv[i+1]:null;})();
+if (TF) { const extra=JSON.parse(fs.readFileSync(TF,'utf8')); for (const [k,v] of Object.entries(extra)) T[k]=v;
+ console.log(`loaded ${Object.keys(extra).length} rows from ${TF}`); }
const retail=c=>Math.round((c/0.65/0.85)*100)/100;
async function api(path,opts={},tries=6){
@@ -72,8 +88,14 @@ for(const [mfr,t] of Object.entries(T)){
else res=await api(`/variants/${v.id}.json`,{method:'PUT',body:JSON.stringify({variant:{id:v.id,price:want.toFixed(2)}})});
if(res.status>=400||res.status===0){console.log(`${mfr} HARD FAIL ${res.status}`);hard++;continue;}
- await sleep(800);
- const sf=await storefront(p.handle); // VERIFY on the oracle, not the Admin API
+ // The storefront is CDN-fronted: an 800ms read served stale documents and produced 7 FALSE
+ // hard-failures on writes that had actually landed. Wait, then re-read once before failing.
+ await sleep(2500);
+ let sf=await storefront(p.handle); // VERIFY on the oracle, not the Admin API
+ const settled=x=>{const l=x?x.variants.filter(v=>parseFloat(v.price)>50):null;
+ return MODE==='revert' ? (l&&l.length===0)
+ : (l&&l.length===1&&Math.abs(parseFloat(l[0].price)-want)<0.01);};
+ if(!settled(sf)){ await sleep(4000); sf=await storefront(p.handle); }
const live=sf?sf.variants.filter(x=>parseFloat(x.price)>50):null;
const okNow = MODE==='revert' ? (live && live.length===0)
: (live && live.length===1 && Math.abs(parseFloat(live[0].price)-want)<0.01);
diff --git a/scripts/tk10895-trancheB-golive-269.mjs b/scripts/tk10895-trancheB-golive-269.mjs
index 609b717..76eb39c 100644
--- a/scripts/tk10895-trancheB-golive-269.mjs
+++ b/scripts/tk10895-trancheB-golive-269.mjs
@@ -57,13 +57,33 @@ for (const w of work) {
const e = byMfr[w.mfr];
if (!e) { fail.push([w.mfr, 'not in evidence CSV']); continue; }
if (e.decision !== 'GO') fail.push([w.mfr, `evidence says decision=${e.decision}`]);
- if (e.mill_unit !== 'PER_ROLL') fail.push([w.mfr, `G1 unit=${e.mill_unit}`]);
- if (e.mill_yards_per_roll !== '5') fail.push([w.mfr, `G1 yards=${e.mill_yards_per_roll}`]);
- if (e.cost_cell_clean !== 'YES') fail.push([w.mfr, `G2 ambiguous cost cell ${e.cost_cell}`]);
- if (e.cost_row_type_clean !== 'YES') fail.push([w.mfr, 'G3 priced off the sheet FABRIC row']);
+ // G1: the mill's published spec is the default proof of unit+length. A row may substitute a
+ // recorded LENGTH-NOT-STATED adjudication — which asserts unit=per-roll on independent retail
+ // evidence and explicitly declines to claim a length — and such a row ships a length-free label.
+ const lenAdj = (e.roll_length_adjudicated || '').startsWith('LENGTH-NOT-STATED');
+ if (!lenAdj) {
+ if (e.mill_unit !== 'PER_ROLL') fail.push([w.mfr, `G1 unit=${e.mill_unit}`]);
+ if (e.mill_yards_per_roll !== '5') fail.push([w.mfr, `G1 yards=${e.mill_yards_per_roll}`]);
+ } else if (!/^Sold Per Single Roll - [\d.]+In Wide$/.test(w.label)) {
+ fail.push([w.mfr, 'G1 length-adjudicated row must carry the length-FREE label']);
+ }
+ // G2: a dirty cost cell may be released ONLY by a recorded adjudication that names its basis.
+ // Inference is allowed to unblock, but it must be written down and auditable, never implicit.
+ if (e.cost_cell_clean !== 'YES' && !(e.cost_cell_adjudicated || '').startsWith('LOADED-TOKEN-SUPPORTED'))
+ fail.push([w.mfr, `G2 ambiguous cost cell ${e.cost_cell} with no recorded adjudication`]);
+ // G3: same rule as G2 — a FABRIC-row cost may be released only by a recorded adjudication.
+ if (e.cost_row_type_clean !== 'YES' && !(e.cost_row_adjudicated || '').startsWith('WP-ROW-COST-SUPPORTED'))
+ fail.push([w.mfr, 'G3 priced off the sheet FABRIC row with no recorded adjudication']);
if (!/^\d+$/.test(w.pid)) fail.push([w.mfr, `pid not bare numeric: ${w.pid}`]);
if (!(parseFloat(w.price) > 50)) fail.push([w.mfr, `price sanity: ${w.price}`]);
- if (!/^Sold Per Single Roll - 5 Yards - [\d.]+In Wide$/.test(w.label)) fail.push([w.mfr, `label: ${w.label}`]);
+ // Label: the yardage form is the default. The length-free form is permitted ONLY when the row
+ // carries a recorded LENGTH-NOT-STATED adjudication — i.e. we deliberately decline to state a
+ // length we cannot source, rather than inventing one. (DW house convention already has this
+ // shape: Brunschwig ships "Sold Per Single Roll - 36In Wide".)
+ const withYards = /^Sold Per Single Roll - 5 Yards - [\d.]+In Wide$/.test(w.label);
+ const noYards = /^Sold Per Single Roll - [\d.]+In Wide$/.test(w.label);
+ if (!withYards && !(noYards && (e.roll_length_adjudicated || '').startsWith('LENGTH-NOT-STATED')))
+ fail.push([w.mfr, `label: ${w.label}`]);
}
console.log(`PRE-FLIGHT: ${work.length} rows · evidence rows ${ev.length} · failures ${fail.length}`);
if (fail.length) {
← e14d23e TK-10895: storefront verify needs a CDN grace period
·
back to Designerwallcoverings
·
TK-11404: correct FINDINGS — DTD+live audit found a real JSO e52390b →