[object Object]

← back to Designerwallcoverings

TK-10895: guards accept recorded adjudications, never implicit inference

27999a6e3e52308bbe5f0af7f919164b72f02471 · 2026-09-10 14:14:19 -0700 · Steve

G1 (unit/length), G2 (ambiguous cost cell) and G3 (FABRIC-row cost) each now
release a row ONLY when the evidence CSV carries a named adjudication -
LENGTH-NOT-STATED / LOADED-TOKEN-SUPPORTED / WP-ROW-COST-SUPPORTED - so an
inference can unblock a product but must be written down and auditable first.

G1 additionally FORCES the length-free label on a length-adjudicated row, and
rejects the length-free label on any row without that adjudication. Both
directions tested against poisoned worklists.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Files touched

Diff

commit 27999a6e3e52308bbe5f0af7f919164b72f02471
Author: Steve <steve@designerwallcoverings.com>
Date:   Thu Sep 10 14:14:19 2026 -0700

    TK-10895: guards accept recorded adjudications, never implicit inference
    
    G1 (unit/length), G2 (ambiguous cost cell) and G3 (FABRIC-row cost) each now
    release a row ONLY when the evidence CSV carries a named adjudication -
    LENGTH-NOT-STATED / LOADED-TOKEN-SUPPORTED / WP-ROW-COST-SUPPORTED - so an
    inference can unblock a product but must be written down and auditable first.
    
    G1 additionally FORCES the length-free label on a length-adjudicated row, and
    rejects the length-free label on any row without that adjudication. Both
    directions tested against poisoned worklists.
    
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---
 scripts/tk10895-trancheB-golive-269.mjs | 21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)

diff --git a/scripts/tk10895-trancheB-golive-269.mjs b/scripts/tk10895-trancheB-golive-269.mjs
index 39d1f22..76eb39c 100644
--- a/scripts/tk10895-trancheB-golive-269.mjs
+++ b/scripts/tk10895-trancheB-golive-269.mjs
@@ -57,8 +57,16 @@ 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}`]);
+  // 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'))
@@ -68,7 +76,14 @@ for (const w of work) {
     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) {

← 5320069 TK-11404: productSet position-1 reorder prototype + FINDINGS  ·  back to Designerwallcoverings  ·  TK-10895: table-driven reprice + CDN grace period b0416ab →