← back to Dw Yolo Loop
docs: verify resume-roll-adds REMAIN-counter edge-set concern (RESUME-COUNTER-NOTE)
5159ca6fc35c539ac7868c0ce2de4aad26af2cdc · 2026-06-16 00:28:18 -0700 · Steve Abrams
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Files touched
A scripts/price-sheets/RESUME-COUNTER-NOTE.md
Diff
commit 5159ca6fc35c539ac7868c0ce2de4aad26af2cdc
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Jun 16 00:28:18 2026 -0700
docs: verify resume-roll-adds REMAIN-counter edge-set concern (RESUME-COUNTER-NOTE)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---
scripts/price-sheets/RESUME-COUNTER-NOTE.md | 107 ++++++++++++++++++++++++++++
1 file changed, 107 insertions(+)
diff --git a/scripts/price-sheets/RESUME-COUNTER-NOTE.md b/scripts/price-sheets/RESUME-COUNTER-NOTE.md
new file mode 100644
index 0000000..9c5389b
--- /dev/null
+++ b/scripts/price-sheets/RESUME-COUNTER-NOTE.md
@@ -0,0 +1,107 @@
+# resume-roll-adds.sh REMAIN-counter — verification note
+
+Council flagged that the `REMAIN` edge-set count in `resume-roll-adds.sh` (line 29) may
+under-count if some edge-CSV rows carry the bare/`-Roll` sku at field index 5 instead of
+`-Sample`. This note records the verification against **current data**. **Do not modify
+`resume-roll-adds.sh` — it gates a live write loop (Steve-gated).**
+
+## What the counter does (line 29)
+
+```js
+const edge = fs.readFileSync("/tmp/schu-addroll-edge.csv","utf8").trim().split("\n")
+ .filter(l => { const [pid,,optName,optVal,,ssku] = l.split("|");
+ return optName==="Title" && optVal==="Default Title" && /-sample$/i.test(ssku) && !edone.has(pid) })
+ .length;
+```
+
+It re-derives "is this an edge target" from the CSV row shape (`optName/optVal/ssku-suffix`)
+instead of from the reliable done-signal (`addroll-edge-created.json` PIDs).
+
+## Field-shape inspection — `data/price-sheets/schu-addroll-edge.csv` (40 rows, `|`-delimited, 9 fields)
+
+Field layout: `pid|optId|optName|optVal|svid|ssku|rsku|retail|cost` (ssku = index 5, rsku = index 6).
+
+| field | shape | count |
+|---|---|---|
+| `optName` (idx 2) | `Title` | 39 |
+| | `Type` | 1 |
+| `optVal` (idx 3) | `Default Title` | 39 |
+| | `Sample` | 1 |
+| `ssku` (idx 5) | ends `-Sample` | 36 |
+| | **bare (no suffix)** | **4** |
+
+The council's premise is confirmed present in the data: **4 of 40 edge rows carry a bare
+sku at field index 5** (the `-Roll` sku sits at index 6 instead). The current
+`/-sample$/i.test(ssku)` filter counts only the 36 `-Sample` rows and drops those 4.
+
+## Is the bug REAL or HYPOTHETICAL with current data?
+
+**Hypothetical — but only by a fragile coincidence, not by design of the filter.**
+
+The 4 rows the filter drops are exactly these PIDs:
+
+```
+7774638014515 DWLK-824290 (rollsku DWLK-824290-Roll)
+7774642077747 DWLK-824210 (rollsku DWLK-824210-Roll)
+7774849433651 DWLK-824650 (rollsku DWLK-824650-Roll)
+7774907007027 DWLK-824640 (optName=Type/optVal=Sample, rollsku DWLK-824640-Roll)
+```
+
+Those 4 PIDs are **identical** to the 4 rows in `data/price-sheets/schu-addroll-oddball.csv`,
+which the **oddball** bucket counts separately (line 31, `odd`). They are also exactly the
+rows that `add-roll-variant-edge.mjs` itself classifies as `oddballs` (line 34) and leaves
+for manual handling rather than auto-creating.
+
+So dropping them from the edge count is **correct de-duplication**: each of those 4 products
+is counted once, in the oddball bucket — not zero times, not twice. Tonight's live
+`remaining 81 = 41 clean + 36 edge + 4 oddball` was therefore accurate (edge=36 true
+auto-targets, oddball=4 = the same 4 rows). The eyeball reconciliation matched reality.
+
+**Why it is still fragile:** correctness here is protected by the *separate oddball CSV*
+mirroring those PIDs, NOT by the `/-sample$/` row-shape test. The test is the wrong instrument
+for the job — it infers "pending" from CSV cosmetics. If a future edge extraction ever emits a
+row with a bare/`-Roll` sku at index 5 that is **not** also mirrored into
+`schu-addroll-oddball.csv`, that genuine pending target would silently vanish from `REMAIN`,
+the count could hit 0 prematurely, and the script would **self-disable its launchd job**
+(line 36-38) with work still undone. The current 4-row coincidence masks exactly that failure
+mode.
+
+## Proposed one-line fix (key the count off the created-PID signal, not row shape)
+
+Both `add-roll-variant-edge.mjs` (and the clean/oddball scripts) decide "done" purely by PID
+membership in their `*-created.json` revert logs — never by sku suffix. The counter should use
+the same reliable signal: count any edge-CSV row whose PID is not yet in
+`addroll-edge-created.json`, regardless of `optName/optVal/ssku` cosmetics.
+
+Replace the `.filter(...)` body on line 29 with a PID-only predicate:
+
+```js
+const edge = fs.readFileSync("/tmp/schu-addroll-edge.csv","utf8").trim().split("\n")
+ .filter(l => !edone.has(l.split("|")[0])).length;
+```
+
+Caveat for whoever applies it (do NOT apply now): this counts all 40 edge rows including the
+4 oddball PIDs, so it would **double-count** those 4 against the separate `odd` term on line 31.
+To keep the buckets disjoint, exclude the oddball PIDs from the edge predicate, e.g.:
+
+```js
+const oddPids = new Set(fs.readFileSync("data/price-sheets/schu-addroll-oddball.csv","utf8")
+ .trim().split("\n").map(l => l.split("|")[0]));
+const edge = fs.readFileSync("/tmp/schu-addroll-edge.csv","utf8").trim().split("\n")
+ .filter(l => { const pid = l.split("|")[0]; return !oddPids.has(pid) && !edone.has(pid) })
+ .length;
+```
+
+This makes the edge count immune to ssku field-shape drift (the council's concern) while
+preserving the current correct edge=36 / oddball=4 split.
+
+## Verdict
+
+- **Bug real with current data:** No — the count is correct today (edge 36 + oddball 4, the
+ 4 dropped rows are de-duplicated into the oddball bucket, not lost).
+- **Concern legitimate:** Yes — correctness rests on a CSV-mirroring coincidence, not on the
+ filter logic; the `/-sample$/` shape test is the wrong signal and would silently undercount
+ (and could trip the self-disable gate early) the moment a non-mirrored bare-sku edge row
+ appears.
+- **Recommendation:** adopt the PID-keyed predicate above (Steve-gated; `resume-roll-adds.sh`
+ drives a live write loop, untouched here).
← d2d776f refactor: add scripts/lib/shopify.mjs shared GQL client + mi
·
back to Dw Yolo Loop
·
CF DNS drift snapshotter: read-only zone export + diff vs la e122d4f →