Skip to main content

Slack → mail fallback (MC #107104)

Slack → mail fallback (MC #107104)

Od 2026-08-18 ~/system/tools/slack.js više ne gubi poruku kad Slack odbije da je primi. Fallback je dodan centralno, u cmdSend, cmdReply i cmdSendBlocks, pa pokriva svih ~140 pozivalaca odjednom. Nijedan demon nije mijenjan.

Zašto je uopšte trebalo

Workspace alai-talk.slack.com (6 korisnika) je na besplatnom planu i udara u limit poruka. Greška message_limit_exceeded pojavljuje se u 41 log fajlu pod ~/system/logs, samo u ops-watchdog-error.log 985 puta. Zadnja datirana pojava je 2026-08-13; ništa ne objašnjava zašto je stalo, pa može proraditi bez najave.

Šteta nije bila samo „izgubljen alert":

demon šta je gubio
tldr-weekly-synthesis na Slack padu radi process.exit(1) i baca cijeli sedmični memo
email-reactor-digest gubi dnevni digest u cijelosti
tldr-watch, bilko-demo-uat, mail-boot-signal, lightrag-monitor samo alert; podaci prežive

Mail fallback je jednom već postojao — ceo-daily-digest.js ga je uspješno okinuo 2026-08-13 — pa je tiho uklonjen neispraćenom izmjenom 2026-08-16. Zato sada živi u slack.js, jedno mjesto, umjesto da se ponovo raspe po pozivaocima.

Ugovor: tri razdvojena stanja

Ovo je bio ključni dio dizajna. tldr-weekly-synthesis odlučuje hoće li uništiti svoj izlaz na osnovu odgovora, pa „isporučeno" i „nigdje isporučeno" moraju biti razlučivi.

izlaz značenje exit
✓ Sent to #kanal Slack primio. Tekst nepromijenjen u odnosu na prije. 0
⚠ SLACK_FAILED_MAIL_FALLBACK_SENT #kanal … (Message-ID …) isporučeno mailom 0
⚠ SLACK_FAILED_MAIL_FALLBACK_DEDUPED #kanal … isti alert već mailovan u zadnjih 6 h 0
ERROR: DELIVERY_FAILED_BOTH #kanal: … (stderr) nigdje isporučeno 1

Exit 0 znači isporučeno BILO GDJE. Zato postojeći pozivaoci koji gledaju samo exit kod nisu slomljeni. Ko treba tačno stanje, čita tekst — ne kod.

Detalji koji se lako pokvare

  • Transport je Migadu, ne one.com. Šalje se kroz postojeći mail-native.js sendEmail(); nije pisan nov SMTP klijent. Bilo koja referenca na „one.com" u runbookovima je zastarjela.
  • Idempotency ključ je obavezan: sha256(kanal|normalizovana poruka), prosljeđuje se kao policyContext.source='system_digest' da prođe validaciju u mail-outbox-gateway.js.
  • Dedup ide u zaseban state fajl ~/system/state/slack-mail-fallback-dedup.json. Postojeći 6-satni Slack keš nije diran ni oslabljen. Ključ se markira kao isporučen tek nakon uspješnog slanja — zato pokvaren mail put pada glasno svaki put, umjesto da utihne poslije prvog pokušaja.
  • Fail-closed: nedostajući mail-native.js ili nedostajući sendEmail export dižu se u isti glasni DELIVERY_FAILED_BOTH. Nema tihog no-opa.
  • Primalac je [email protected], override kroz SLACK_MAIL_FALLBACK_TO.

Kako je dokazano (uživo, ne simulirano)

  1. Slack uspio — pravi send na #john-digest✓ Sent to #john-digest, exit 0, mail se ne dira.
  2. Slack pao → mail stigao — prisiljeno stvarno nepostojećim kanalom (resolveChannel() je zaista bacio „Channel not found"). Mail potvrđen dvaput: u Sent folderu (uid 104) i IMAP pretragom u samom inboxu [email protected] (uid 3215), s pročitanim tijelom.
  3. Dedup — isti alert ponovljen odmah → DEDUPED, exit 0, drugi mail nije poslan.
  4. Oba pala — bogus kanal + SLACK_MAIL_FALLBACK_TO na domen bez MX zapisa → DELIVERY_FAILED_BOTH, exit 1.

Nije zasebno paljena samo require()-fail grana (brisanje žive produkcijske datoteke je bilo van opsega); dijeli isti agregacijski put dokazan u testu 4.

Dokazi: ~/system/evidence/107104/ (8 fajlova). Commit 955b8491a5.

Odluka o Slack Pro

CEO, 2026-08-18: ne uzimati Pro za sada. Greške su dormantne od 13.08., a s fallbackom Slack ispad više ne uništava podatke nego alerte preusmjeri na mail. Ušteda ≈ 486–594 EUR/god (€6,75/korisnik/mj godišnje ili €8,25 mjesečno × 6 mjesta). Ponovo procijeniti ako Slack opet stane.

Poznato otvoreno, namjerno nedirano

  • tldr-weekly-synthesis.js i dalje radi process.exit(1) kad oba puta padnu. Zaseban defekt.
  • cmdSend nikad nije ispisivao (ts: …), pa je regex ekstrakcija thread_ts u tom fajlu bila mrtav kod i prije ove izmjene.
  • bilko-demo-uat-daemon.js, email-reactor-digest.js i mail-boot-signal.sh loguju „posted" i kad je isporuka išla mailom, jer gledaju samo exit kod. Kozmetika naslijeđena iz njihovog vlastitog dizajna.