Refill conversions: only count a genuine response. An unrelated ad already running is not a relaunch, and a still-running low campaign is not a conversion at all; adds a reset lever to re-decide verdicts

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
martbost
2026-09-22 05:26:20 -05:00
parent 635844a12b
commit 67fb8193bd
2 changed files with 27 additions and 3 deletions
+22 -3
View File
@@ -180,9 +180,17 @@ async function checkConversions() {
try { const ps = await X.accounts.positions(r.owner); ids = [...new Set([...ids, ...ps.map(p => p.memberId).filter(Boolean)])]; } catch (e) {}
const buy = evs.find(e => ids.includes(Number(e.id || e.buyerId)) && norm(e) > since);
if (buy) { mark(r, 'purchase', { cents: n0(buy.priceCents), tx: buy.tx || null }); continue; }
// 2. put an ad back up, or topped one up
const fresh = all.find(c => c.owner === r.owner && !c.house && (n0(c.created) > since || (c.status === 'active' && !r.campaigns.some(x => x.id === c.id))));
// 2. put an ad back up. Only two things count: a campaign created after we wrote to them, or one of
// the very campaigns we named coming back to life. An unrelated ad that was already running is not a
// response to the email, and counting it was inflating the rate to meaninglessness.
const fresh = all.find(c => c.owner === r.owner && !c.house && n0(c.created) > since);
if (fresh) { mark(r, 'relaunch', { campaignId: fresh.id, name: fresh.name || null }); continue; }
// only meaningful for an ad that had actually stopped: a "running low" ad is still active by
// definition, so counting that as a response would mark every low notice converted on the spot
if (r.state === 'out') {
const revived = all.find(c => c.status === 'active' && r.campaigns.some(x => x.id === c.id) && delivered(c) < n0(c.budget));
if (revived) { mark(r, 'resumed', { campaignId: revived.id, name: revived.name || null }); continue; }
}
const topped = all.find(c => { const was = r.campaigns.find(x => x.id === c.id); return was && n0(c.budget) > was.budget; });
if (topped) { mark(r, 'topup', { campaignId: topped.id, added: Math.round(n0(topped.budget) - r.campaigns.find(x => x.id === topped.id).budget) }); }
}
@@ -222,4 +230,15 @@ function stats() {
};
}
module.exports = { init, tick, stats, PACKS };
// clears conversion verdicts so the corrected rule can re-decide them (used once after the
// first run, where "already had another ad running" was wrongly counted as a relaunch)
function resetConversions(kinds) {
S.records = S.records || {};
const want = new Set(kinds && kinds.length ? kinds : ['relaunch']);
let n = 0;
for (const r of Object.values(S.records)) if (r.converted && want.has(r.converted.kind)) { r.converted = null; n++; }
save();
return { cleared: n };
}
module.exports = { init, tick, stats, resetConversions, PACKS };