diff --git a/suite-traffic.js b/suite-traffic.js index 7714b40..0b7cd6f 100644 --- a/suite-traffic.js +++ b/suite-traffic.js @@ -79,32 +79,29 @@ function record(memberId, entry) { writeLedger(trimmed); } -// The ad network counts the SAME `remaining` column in opposite directions for -// the two placement types, which is not documented anywhere and had to be -// measured: +// `remaining` counts DOWN for BOTH placement types — measured across 1,604 +// network ads, and it is exactly what the bridge's stats action already +// computes (`served = assigned - remaining`, falling back to hits when +// assigned was never set). Trust the bridge's `served` field first. // -// TEXT ads — `remaining` counts DOWN from the purchase to zero as it serves. -// (ad 2689: 1,111 left mid-flight, 0 once complete.) -// BANNER ads — `remaining` counts UP as impressions are delivered, straight -// past the amount purchased. (ad 2707: 3,521 one day, 6,129 the -// next, on a 2,500 buy.) -// -// Reading both the same way made every banner report "0 served" while quietly -// delivering thousands — and made stop() treat delivered impressions as -// unserved and refund them. +// The earlier "banners count UP" theory (and its ad-2707 evidence) was the +// network's own post-insert counter top-ups being misread; acting on it made +// every fresh banner look fully delivered the moment it launched, so the +// sweeper deactivated brand-new campaigns and stamped them complete (bug +// Marty caught 2026-09-01: a banner "delivered all its impressions" +// instantly). Do not resurrect the count-up branch. // // Returns what the member should see: served + left always reconciles to what // they bought, and neither can exceed it. function interpret(kind, bought, stat) { const b = Math.max(0, Number(bought) || 0); - const rem = Math.max(0, Number(stat && stat.remaining) || 0); let served; - if (kind === 'text') { - // count-down: what is gone is what was bought minus what is left - served = b - Math.min(rem, b); + if (stat && stat.served != null) { + served = Number(stat.served) || 0; } else { - // count-up: `remaining` IS the delivered count - served = Math.min(rem, b); + // count-down: what is gone is what was bought minus what is left + const rem = Math.max(0, Number(stat && stat.remaining) || 0); + served = b - Math.min(rem, b); } served = Math.max(0, Math.min(served, b)); return { served: served, left: Math.max(0, b - served) };