← back to Dw Yolo Loop

scripts/price-sheets/RESUME-COUNTER-NOTE.md

108 lines

# 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).