From 3a91ca4732e181446107921bb8a80645e33c66bf Mon Sep 17 00:00:00 2001 From: Gustavo Date: Mon, 3 Aug 2026 13:06:51 -0300 Subject: [PATCH] resumeCampaign resets semana_iniciada_em to avoid immediate escalation resumeCampaign only updated status/pause_reason, so a campaign auto-paused for many days and then resumed could immediately satisfy escalateWeeklyLimits' 7-day check and double its daily limit right after coming back from an unhealthy state -- the opposite of the intended safety behavior. Now resumeCampaign also stamps semana_iniciada_em to datetime('now'), resetting the weekly clock on every resume. --- src/outreach/campaign-store.mjs | 9 +++++++-- tests/campaign-store.test.mjs | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/outreach/campaign-store.mjs b/src/outreach/campaign-store.mjs index bab7e58..799c0bf 100644 --- a/src/outreach/campaign-store.mjs +++ b/src/outreach/campaign-store.mjs @@ -62,9 +62,14 @@ export function setCampaignStatus(db, campaignId, status, pauseReason = null) { // So avanca campanha que estiver de fato pausada — retomar uma campanha em // rascunho, por exemplo, deveria usar setCampaignStatus(db, id, 'rodando'). export function resumeCampaign(db, campaignId) { + // Reseta semana_iniciada_em pra agora: uma campanha que ficou pausada (por + // saude ruim ou motivo manual) por varios dias nao pode, ao ser retomada, + // já satisfazer o "rodando ha 7+ dias" do escalateWeeklyLimits e dobrar o + // limite diario logo de cara — isso inverteria a logica de seguranca. db.prepare( - `UPDATE outreach_campaigns SET status = 'rodando', pause_reason = NULL, updated_at = datetime('now') - WHERE id = ? AND status = 'pausado'` + `UPDATE outreach_campaigns + SET status = 'rodando', pause_reason = NULL, semana_iniciada_em = datetime('now'), updated_at = datetime('now') + WHERE id = ? AND status = 'pausado'` ).run(campaignId); return getCampaign(db, campaignId); } diff --git a/tests/campaign-store.test.mjs b/tests/campaign-store.test.mjs index 81637b1..3de6f56 100644 --- a/tests/campaign-store.test.mjs +++ b/tests/campaign-store.test.mjs @@ -79,6 +79,23 @@ test('setCampaignStatus rodando does not reset already-set semana_iniciada_em', db.close(); }); +test('resumeCampaign reseta semana_iniciada_em, evitando escalonamento imediato apos retomar de uma pausa longa', () => { + const db = openDb(':memory:'); + const campanha = createCampaign(db, campanhaBase({ limiteDiarioInicial: 10, limiteDiarioTeto: 80 })); + setCampaignStatus(db, campanha.id, 'rodando'); + setCampaignStatus(db, campanha.id, 'pausado', 'high_failure_rate'); + // Simula que a campanha ficou pausada por muito tempo: semana_iniciada_em + // backdated 10 dias, o que satisfaria os "7 dias corridos" do escalonamento. + db.prepare(`UPDATE outreach_campaigns SET semana_iniciada_em = datetime('now', '-10 days') WHERE id = ?`).run(campanha.id); + + resumeCampaign(db, campanha.id); + const escaladas = escalateWeeklyLimits(db); + assert.equal(escaladas, 0, 'retomar deveria ter resetado o relogio semanal, entao nao deveria escalonar imediatamente'); + const atualizada = getCampaign(db, campanha.id); + assert.equal(atualizada.limite_diario_atual, 10); + db.close(); +}); + test('resumeCampaign nao faz nada se a campanha nao estiver pausada', () => { const db = openDb(':memory:'); const campanha = createCampaign(db, campanhaBase());