← back to George Gmail
fix: add archive-before-delete path to drain script — saves subject/snippet locally before permanent-delete (TK-11609)
cdf6c50c6a9c3db9cd7099c7374c090e315358a6 · 2026-09-13 04:06:46 -0700 · steve@designerwallcoverings.com
Files touched
M delete-old-drafts-info.js
Diff
commit cdf6c50c6a9c3db9cd7099c7374c090e315358a6
Author: steve@designerwallcoverings.com <steve@designerwallcoverings.com>
Date: Sun Sep 13 04:06:46 2026 -0700
fix: add archive-before-delete path to drain script — saves subject/snippet locally before permanent-delete (TK-11609)
---
delete-old-drafts-info.js | 25 +++++++++++++++++++++----
1 file changed, 21 insertions(+), 4 deletions(-)
diff --git a/delete-old-drafts-info.js b/delete-old-drafts-info.js
index c0b53bd..d9d1c12 100644
--- a/delete-old-drafts-info.js
+++ b/delete-old-drafts-info.js
@@ -184,15 +184,31 @@ async function discoverSet() {
// ---- DRAIN LOOP ----
const logFile = `/tmp/george-old-drafts-deleted-${stamp}.jsonl`;
- let totalOk = 0, totalFail = 0, batch = 0;
+ // Archive path (TK-11609): fetch and save draft metadata+snippet BEFORE permanent-delete so
+ // there is a local recovery record. Failure to archive is non-fatal — we log but still delete.
+ const archiveFile = path.join(__dirname, 'data', `archive-before-delete-${stamp.slice(0, 8)}.jsonl`);
+ let totalOk = 0, totalFail = 0, totalArchived = 0, batch = 0;
const target = older.size;
+ console.log(`Archive path: ${archiveFile}`);
while (batch < MAX_BATCHES) {
batch++;
const drafts = await jget(`${BASE}/api/drafts?account=${ACC}&maxResults=500`);
const matches = (drafts || []).filter((d) => d && d.message && older.has(d.message.id) && !KEEP_IDS.has(d.message.id));
if (matches.length === 0) { console.log(`\nbatch ${batch}: 0 matches — drain complete.`); break; }
- console.log(`\nbatch ${batch}: ${matches.length} matches (of ${Array.isArray(drafts) ? drafts.length : '?'} listed) — deleting...`);
+ console.log(`\nbatch ${batch}: ${matches.length} matches (of ${Array.isArray(drafts) ? drafts.length : '?'} listed) — archiving then deleting...`);
for (const t of matches) {
+ // Archive before delete: fetch message headers + snippet for recovery
+ let archiveEntry = { ts: new Date().toISOString(), draftId: t.id, messageId: t.message.id, archived: false };
+ try {
+ const msg = await jget(`${BASE}/api/messages/${t.message.id}?account=${ACC}`);
+ if (msg) {
+ archiveEntry = { ...archiveEntry, subject: msg.subject, from: msg.from, to: msg.to, date: msg.date, snippet: msg.snippet, archived: true };
+ totalArchived++;
+ }
+ } catch (_) { /* non-fatal — delete proceeds regardless */ }
+ try {
+ fs.appendFileSync(archiveFile, JSON.stringify(archiveEntry) + '\n');
+ } catch (_) {}
try {
await jreq(`${BASE}/api/drafts/${t.id}?account=${ACC}`, { method: 'DELETE' });
fs.appendFileSync(logFile, JSON.stringify({ ts: new Date().toISOString(), draftId: t.id, messageId: t.message.id }) + '\n');
@@ -203,8 +219,9 @@ async function discoverSet() {
await sleep(DEL_SLEEP);
}
}
- console.log(`\n\nDONE. deleted=${totalOk} failed=${totalFail} remaining-in-set=${older.size}`);
+ console.log(`\n\nDONE. deleted=${totalOk} failed=${totalFail} archived=${totalArchived} remaining-in-set=${older.size}`);
console.log(`Deletion log: ${logFile}`);
+ console.log(`Archive (recovery): ${archiveFile}`);
if (older.size > 0) console.log('Some >30d drafts remain (batch cap or failures). Re-run to finish.');
- heartbeat({ verdict: totalFail > 0 ? 'WARN' : 'PASS', status: totalFail > 0 ? 'WARN' : 'PASS', deleted: totalOk, failed: totalFail, remaining_in_set: older.size });
+ heartbeat({ verdict: totalFail > 0 ? 'WARN' : 'PASS', status: totalFail > 0 ? 'WARN' : 'PASS', deleted: totalOk, failed: totalFail, archived: totalArchived, remaining_in_set: older.size, archive_path: archiveFile });
})().catch((e) => { console.error('FATAL:', e.message); process.exit(1); });
← 920a946 fix: add 'calendar' to resolveAccount() map + add agentabram
·
back to George Gmail
·
auto-data-snapshot: 2026-09-13T04:15:01 (1 data files) — dat f5f274f →