Azure litestream egress saga + backup policy (lokalno do plaćenih korisnika) — MC #105462
MC #105462 — Azure litestream ListBlobs egress: FINAL REPORT (za CEO)
Datum: 2026-07-13 | Sesija: john pid-7080 (nastavak; prethodne: c10520f4 team-lead + izvršna sesija pid-20439) Status AC-a: čist mjerni prozor počeo 2026-07-13T08:52:24Z — formalna AC provjera (ListBlobs <5GB/6h) moguća od 14:52Z (16:52 lokalno); 2h checkpoint od 10:52Z (12:52 lokalno).
1. Sažetak
Egress na alaibackups0ebb narastao do ~518 GB/dan (~370 NOK/dan). Root cause NIJE stari l0 graveyard nego litestream per-sync-tick ListBlobs: svaki sync tick lista cijeli ltx prefiks svog DB-a, a flywheel (~113K blobova, 68% egressa) i mission-control (~102K blobova, 23%) imali su 30s/1s intervale. Atribucija dokazana iz $logs storage-loga: exact IP + user-agent + call-rate == konfigurisani intervali (ATTRIBUTION-FINDINGS.md).
2. Šta je primijenjeno (Phase A — GOTOVO, verifikovano)
| Zahvat | Detalj | Evidence |
|---|---|---|
| Sync intervali (1. restart 07:45:56Z) | mission-control 1s→60s, flywheel 30s→600s | restart-verification.md, litestream.yml.before/after-105462 |
| Phase A extension (2. restart 08:52:24Z) | 6 telemetrijskih DB → 300s; svih ostalih 56 DB <60s → 60s | litestream.yml.before/after-phaseA-extension |
| Azure lifecycle | 8d delete pravila proširena sa 9 na svih 64 DB prefiksa | policy-after-phaseA-verified-live.json |
| Restart verifikacija | Novi PID 11505, log potvrđuje svaki novi interval, status=ok, txid napreduje | restart-verification.md |
3. Incident tokom rada (kolizija sesija — sadržano, bez gubitka podataka)
Druga CEO-terminal sesija (c4a3b3f9, PID 27243, živa od 07-10) izvršila je STARE delete-batch korake iz originalnog opisa taska (otkazane u međuvremenu), bez claim lease-a — 2 talasa brisanja l0 blobova na 7 baza (do 92% blobova na agent-routing). Sadržavanje: SIGSTOP cijelog stabla PID 27243 + lease + STOP-DELETE notice u task opisu. Puni detalji: INCIDENT-unauthorized-deletes.md.
DR re-verifikacija poslije oba talasa: SVIH 7 BAZA RESTORABLE — NEMA GUBITKA PODATAKA. 5 baza puni restore + integrity_check=ok + exact row-count match; flywheel i mission-control preko snapshot-coverage dokaza (level-9 snapshot pokriva txid raspon ispod najstarijeg preživjelog l0). Follow-up preporuka: pun restore test za te 2 baze u maintenance prozoru (belt-and-suspenders).
4. Trenutno stanje egressa
- Prije fixa: 10-22 GB/h (hourly buketi 05:54-07:54Z).
- Poslije 1. restarta, prije čistog prozora: pad 1.3GB → 0.67GB per 5min (kontaminirano DR restore testovima koji sami listaju blobove).
- Čist prozor tek počeo (08:52:24Z). Kratki prozori dokazano varljivi (restart transijenti + flywheel 600s tick) — team lead pravilo: minimum 2h prije očitanja.
Očekivana mehanika oporavka: egress ∝ (broj tickova × veličina liste). Intervali su odmah srezali broj tickova (MC 60×, flywheel 60×, 54 DB-a 60×). Veličina liste pada kako litestream retention (flywheel 72h, MC 168h) + Azure lifecycle 8d roll-off smanje broj blobova: flywheel novi tempo ≤144 blobova/dan (sa ~30s tempa), pa za 3 dana l0 count pada sa ~113K na stotine; MC za 7 dana sa ~102K na ~10K. Puni efekat: 3-7 dana, organski, bez ikakvog brisanja.
5. FAZA B — odluke za CEO
B1. ✅ CEO ODABRAO 2026-07-13 11:00: NIŠTA više ne dirati — pustiti retention roll-off. (B2 odbačen za danas.) Phase A + lifecycle već garantuju pad; jedini trošak je repni egress dok se blob countovi ne istope (grubo: nekoliko stotina GB kroz sedmicu, opadajuće). Nula DR rizika. Dnevna kontrola očitanja do AC PASS.
B2. Ubrzanje (opciono, tek nakon AC mjerenja): forsirati kompakciju/snapshot na flywheel+MC.
litestream snapshot + niža retention privremeno → l0 se topi za sate umjesto dana. Ušteda ~200-400 NOK
repnog egressa, ALI dira DR lanac dan nakon incidenta — tražim Proveo-verifikovan runbook i CEO GO prije
izvršenja. NE preporučujem danas.
B3. Strukturno (poseban task, nije hitno): hot-churn telemetrijske baze (flywheel, trace/health-events) dugoročno ne pripadaju per-tick replikaciji — konsolidovani backup tier ili litestream noviji level-config. Predlažem M task nakon što AC prođe.
B4. Sudbina zamrznute sesije (CEO odluka — tvoj terminal): PID 27243 stablo je SIGSTOP (T state).
Drži SP secret u plaintext cmdline-u (vidljivo u ps i SADA — provjereno ovom sesijom). Preporuka:
SIGKILL stabla čim potvrdiš da u tom terminalu nema nespašenog rada, pa rotacija.
B5. SP rotacija alai-backup-writer (#105466, paused): secret kompromitovan kroz ps/transkripte.
Prethodna sesija blokirana permission bound-om na az ad sp credential. Treba ili CEO az ad app credential reset
ili Graph permission za service principal. VEZANO za B4 (rotacija prije kill-a je beskorisna dok frozen proces drži stari secret u memoriji — redoslijed: kill → rotate → update plist + BW).
5b. 2h checkpoint (12:54-13:40 lokalno) — NALAZI
Mjerenje (egress-clean-2h-checkpoint.tsv): ListBlobs ~17.5GB u čistom 2h prozoru (08:52-10:52Z) → pace ~52GB/6h vs AC <5GB/6h. Pozivi ~5.8K/30min (bilo 8.4K pre-fix — pad samo ~2×, ne 60×).
Atribucija pozivaoca — ZATVORENA: jedini proces koji priča s alaibackups0ebb je litestream PID 11505 na ovoj mašini (lsof 70×1s sampling: 100% litestream; sve transakcije OAuth=SP; FORGE ssh-verifikovan čist, Azure VM čist — backup cron 03:00, LaunchAgents čisti, nula rogue procesa). Oscilacija 09→10Z je litestream-ova vlastita (hourly retention pass + "behind replica" retry petlje), NE novi klijent.
Zašto AC danas neće proći: veličina list odgovora je ∝ broju blobova; flywheel (~113K) i MC (~102K) l0 blobovi se NE tope organski — u logu nula "l0 retention enforced" / "compaction complete" eventova za flywheel/MC (litestream retention za njih efektivno ne radi na ovolikim prefiksima). Roll-off zavisi od Azure lifecycle 8d pravila (postavljena danas 07:23Z; prva egzekucija tipično ≤24-48h). Realna prognoza AC PASS: 2026-07-14/15 nakon prve lifecycle egzekucije. Fix je i dalje ispravan — intervali su srezali tick-komponentu; ostaje count-komponenta koju čisti lifecycle.
NOVI DR NALAZ (H task #105490): lifecycle pravilo BackupRetentionRule je account-wide (bez
prefixMatch!) s tierToArchive@30d — arhiviralo je L0 blobove 35 uspavanih DB-ova → litestream 409
BlobArchived retry petlja svakih 5min → tih 35 DB-ova NE replicira (tihi DR gap) (telemetry,
escalations, companies, pipeline...). Fix zahtijeva CEO GO (dira lifecycle policy): scope-ovati
pravilo + reinit malih replika. Detalji u tasku #105490.
5c. Pi checkpoint (13:24 lokalno / 11:24Z) — READ-ONLY
Artifact: CURRENT-STATUS-20260713T1124Z.md
- Destruktivni proces sweep prije Azure read-only metrike: no output za
az storage blob delete,delete-batch,azcopy rm,az storage container delete. - Azure Monitor clean-window-so-far (
2026-07-13T08:52:24Z/2026-07-13T11:24:04Z, PT15M, dimenzijaApiName):ListBlobs=23,314,413,725 bytes= 23.314 GB. - Ekstrapolirani pace: ~55.4GB/6h, tj. formalni AC
<5GB/6hjoš nije dostignut. - Litestream status artifact
litestream-status-20260713T112442Z.txt: pogođene bazemission-control,flywheel,agent-routing,trace-events,health-events,events,email-inboxsuok. - Konfig spot-check ostaje kako je Phase A namjestila: MC 60s, flywheel 600s, pogođene telemetry baze 300s. Bez dodatnih promjena/restarta.
Zaključak: task ostaje PARTIAL / čeka formalni 6h prozor u 14:52Z (16:52 CEST). Ne dirati više (blob delete i B2 i dalje STOP); B1 ostaje važeća CEO odluka.
5d. FORMALNO AC MJERENJE (16:56 lokalno) — REZULTAT
AC FAIL danas, očekivano: ListBlobs egress u formalnom 6h prozoru (08:52:24-14:52Z) = 58.88 GB vs AC <5GB/6h (egress-AC-6h-final.tsv). Napomena: prozor je miješanih režima — u 13:52Z upala je flywheel→local migracija (CEO-autorizovana u drugoj sesiji, 5c/restart-verification).
Ključni novi nalaz — dominantni lister je MISSION-CONTROL, ne flywheel: post-migracijski steady state (13:52-14:52Z, flywheel 100% van Azure-a) = ~3GB/15min ≈ 12GB/h, NEPROMIJENJENO vs prije migracije. Račun se poklapa: MC ~102K blobova ≈ 21 stranica × ~1MB po listingu, listano više puta po 60s ticku (multi-level plan) ≈ 12GB/h. Flywheel-ov udio u pozivima bio je već zanemariv poslije Phase A (600s = 6 lista/h); "flywheel 68%" iz jutarnje atribucije važio je za PRE-Phase-A režim (30s).
Preostala poluga = Azure lifecycle 8d na litestream/mission-control/ (litestream vlastiti retention za MC dokazano ne radi — 0 eventova). Većina MC-ovih 102K L0 blobova je starija od 8 dana → prva lifecycle egzekucija (tipično ≤24-48h od 07:23Z danas) briše bulk → očekivan pad ~10×, a post-Phase-A tempo punjenja je ≤1.440 blobova/dan. Prognoza AC PASS: 2026-07-14/15; re-mjerenje sutra ujutro (boot Next Steps).
Opcije ubrzanja (SAMO uz CEO GO, default ostaje čekanje po B1): B2-lite samo za MC (forsirani snapshot + prune starih generacija); MC→local NE preporučujem (MC je srž sistema — cloud DR mu je i svrha, za razliku od flywheel cache-a).
6. Otvorene stavke do zatvaranja taska
- ⏳ Formalna AC 6h provjera: 14:52Z (16:52 lokalno). AC: ListBlobs <5GB/6h. 2h i 13:24 checkpointi već pokazuju da AC vjerovatno neće proći prije lifecycle roll-offa.
- ⏳ CEO odluke otvorene: B4 (frozen sesija), B5 redoslijed rotacije. B1 je potvrđen 2026-07-13 11:00; B2 odbačen za danas.
- 📋 Follow-up taskovi: #105465 (claim-lease enforcement za destruktivne korake), #105466 (SP rotacija), #105490 (lifecycle archive DR gap), predloženi M task za pun restore test flywheel/MC + B3 strukturni.
Evidence index (sve u ~/system/evidence/105462/)
ATTRIBUTION-FINDINGS.md · INCIDENT-unauthorized-deletes.md · restart-verification.md · litestream.yml.before/after-* · policy-after-phaseA-verified-live.json · egress-.json · restore-verify-.{log,json} · l0-*.csv · raw-listings/ · storage-logs/
7. CEO POLICY ODLUKA 2026-07-13 ~21:55Z — SUPERSEDES sekciju 5 (B1-only)
CEO odluka (verbatim, primljena prvom rukom u sesiji c10520f4 ~21:55Z; zapisana u memo project_backup_policy_local_until_paying_customers_2026-07-13.md u 23:02): "Prebaci lokalno! Nemamo placene korisnika kad to dodje ide backup na azure do tada save money gdje mozemo."
Eksplicitno nadjačava odluku "11:00 B1, B2 odbačen" (sekcija 5) i preporuku iz 16:56 ("MC→local NE preporučujem", sekcija 5d). Nakon dokaza da mission-control i uz pun throttling proizvodi ~12GB/h, CEO je izabrao kompletan fix umjesto parcijalne mitigacije. Nije governance konflikt — evolucija odluke kroz dan s novim dokazima.
POLICY (na snazi): SVE sistemske SQLite baze (litestream.yml, 64 DB) repliciraju SAMO na lokalni disk (~/backups/litestream//, retention ~72h). DR troslojan: lokalna litestream replika (kontinuirano) + lokalni daily db-backup.sh (5d) + B2 offsite 6h (Backblaze, netaknut). Azure storage account alaibackups0ebb se NE briše — 8d lifecycle drenira l0, decommission odluka ~30d, account čuvan za reaktivaciju. Uslov reaktivacije: prvi PLAĆENI korisnik — tada se cloud replikacija vraća, uz prethodni litestream upgrade research (izbjeći full-prefix-per-tick listing).
8. Izvršenje (22:05-23:08Z)
Disk projekcija prije primjene: 63 preostale baze = 713.84MB × 3 = ~2.09GB (ispod 20GB triggera; sanity-check protiv flywheel realnog ratia 0.9x). Transform: awk skripta validirana litestream config parserom prije žive primjene (dry-run: 64/64 file, 0 abs). retention/check-interval/snapshot-interval očuvani per-DB.
Restart: config mtime 22:05:09Z, novi PID 87017, stari 42717 terminiran. Log: 0× "type=abs", 64× "type=file". Svih 63 novo-migriranih DB: očekivani tranzijentni "ltx file missing" prvi sync → svih 63 self-resolved svježim snapshotom u sekundama (63/63 "snapshot complete", 0 s consecutive_errors>1). litestream status: 64/64 "ok".
Disk stvarno: 927MB ukupno (44% projekcije). Najveći: flywheel 346MB, hivemind 220MB, knowledge 167MB, session-index 69MB.
B2 pokrivenost potvrđena ENUMERACIJOM (source-read oba joba — rclone-backup.sh nightly + offsite-backup.sh 6h — nefilterirani globovi nad ~/system/databases/; svih 64 DB fizički prisutno, nula MISSING).
9. FINALNO AC MJERENJE — DEFINITIVAN PASS
ListBlobs po satu: 19:08Z 11.71GB, 20:08Z 12.35GB, 21:08Z 12.25GB (baseline) → 22:08Z 0.0000470 GB (prvi potpuno čist sat). 5-min granularnost 22:08-23:03Z: 14 uzastopnih bucketa = 0 GB (šum ~20-25KB). AC (<5GB/6h): PASS za nekoliko redova veličine. Mehanizam: nula mrežnih poziva prema Azure za replica sync — eliminisana cijela klasa curenja, uključujući nerazjašnjeni 4-6x gap iz sekcije 5d (moot — "unexplained residual mechanism, made moot by full local migration").
10. Task record
MC #105462 record ažuriran 23:13:55 od john/c10520f4: važeća odluka + supersede + NE-REVERTOVATI klauzula. (Raniji pokušaj flowforge agenta ispravno blokiran actor-token gate-om.)
11. Konsolidovani follow-upi
- #105465 claim-lease/bg-process guardrail (kolizioni incidenti — danas 2 slučaja paralelnih sesija)
- #105466 rotacija SP alai-backup-writer + azdo PAT (plaintext ekspozicije)
- #105490 lifecycle archive DR gap (BackupRetentionRule account-wide bez prefixMatch; djelimično moot za 35 lokalnih baza, account-wide pitanje ostaje za preostalu Azure prisutnost)
- #105584 disk higijena (docker/gradle/APFS — objašnjava 35Gi dren, nevezano za ovaj task) + #105521 boot.sh disk-check fix
- PREDLOŽENO M: full restore test flywheel+MC u maintenance prozoru (postoji #105467 — proširiti na lokalne replike)
- PREDLOŽENO M: litestream verzija/upgrade research (generation-state caching umjesto full-prefix listinga) — OBAVEZNO prije Azure reaktivacije
- PREDLOŽENO L: backup-health-check.sh (s ListBlobs alarmom) nigdje raspoređen — regression guard, niži prioritet sada kad mehanizam ne postoji; piggyback na offsite-backup.sh pattern kad se radi
- Azure prefiks cleanup + storage account decommission odluka ~30d (2026-08-13)