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).
3b. Kolizija #2 (kasno veče) — kontradiktorne CEO odluke iz dvije paralelne sesije, RIJEŠENO bez akcije
Oko 23:10Z, prije primjene team-lead-instruirane pune lokalne migracije, ova sesija je uočila
da task record (mc.js show 105462) pokazuje status=paused i tekst "CEO ODLUKA 2026-07-13 11:00:
FAZA B = B1 (pusti retention roll-off; B2 odbačen)" — direktno u suprotnosti s uputstvom
primljenim ovim kanalom (puna lokalna migracija, uključujući mission-control). Dodatno, u istom
evidence direktorijumu postojao je REPORT.md (16:56, tag "john pid-7080") s eksplicitnom
preporukom "MC→local NE preporučujem". ps je potvrdio PID 7080 kao ŽIVU, aktivnu sesiju
(elapsed 14+ h u tom trenutku).
Sesija je ZAUSTAVILA svaki dalji rad i eskalirala prije nastavka (poruka ~23:10Z), umjesto da nastavi na osnovu konfliktnih signala ili da jednostrano revertuje migraciju. Razrješenje (potvrđeno od team-lead-a): obje odluke su GENUINE — "11:00 B1" je iz PARALELNE sesije pid-7080 (CEO-ov drugi terminal, otvoren 10:50), donesena PRIJE dokaza da throttling ne radi (Phase A
- MC 300s, oba bez efekta na ukupan egress — dokazano poslije 11:00). Odluka "prebaci sve lokalno" primljena je PRVOM RUKOM u team-lead sesiji (c10520f4) ~21:55Z, dakle 10+ sati kasnije i sa potpunijim dokazima. Novija, informisanija odluka ima prednost — ovo NIJE bio governance kvar nego dvije nezavisne, paralelne CEO-John sesije koje su radile na istom tasku bez međusobne vidljivosti, gdje je jedna donijela stariju odluku prije ključnog dokaza, a druga noviju odluku poslije njega.
Ključna razlika od Kolizije #1 (sekcija 3): ovdje NIJE bilo destruktivne akcije niti rizika gubitka podataka — samo dvije verzije istine u task recordu i evidence direktorijumu. Sesija pid-7080 nije dirana (nije njena da se ubija/koordinira — team-lead preuzima taj kontakt s CEO, isto kao za jutrošnji c4a3b3f9). Task record ažuriran (23:13:55) s važećom odlukom, "NE REVERTOVATI bez nove CEO odluke" klauzulom i napomenom o paralelnoj sesiji, tako da sesija pid-7080 (kad se sljedeći put probudi/čita bazu) vidi TAČNO stanje umjesto zastarjelog.
Zajednički nalaz obje kolizije danas — najjači argument za #105241 (PI intake/claim disciplina): dva odvojena incidenta u istom danu, oba korijenski uzrokovana time što paralelne John/CEO sesije rade na istom MC tasku bez claim-lease vidljivosti ili sinhronizacije task-recorda u realnom vremenu — prva rezultovala stvarnim brisanjem podataka (sadržano, bez gubitka), druga rezultovala kontradiktornim infrastrukturnim odlukama u istom konfiguracionom fajlu (sadržano, bez štete jer je novija odluka bila ispravna). #105241 trenutno adresira samo PI-orchestrator auto-claim slučaj (3 dokumentovana primjera); ovaj dan pokazuje da isti problem postoji i između DVIJE John/CEO sesije bez PI posrednika — claim-lease enforcement (već predložen kao #105465 iz Kolizije #1) trebao bi pokriti OBA slučaja, ne samo PI-vs-John nego i John-vs-John.
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.)
12. Disk drain (checkpoint 1 flag) — RIJEŠENO
35Gi pad (94Gi→59Gi) tokom popodneva NIJE bio litestream leak niti bilo šta vezano za ovaj task — dva puna LumisCare docker builda (uklj. --no-cache verify) → docker images/build-cache, gradle dependency download ~8.4GB, 27 APFS snapshota pinovalo obrisane blokove. Disk stabilan na ~61Gi poslije brzog prune-a od strane team-lead sesije, dok je ova sesija radila migraciju. Temeljitija higijena praćena kao #105584 (docker image prune -a, stari image-i 274/37GB triage, .gradle cache policy, APFS snapshot check, cilj <88% capacity, NEEDS REVIEW). Root cause dijagnoze uzrok (boot.sh je čitao pogrešan volume) praćen kao #105521, nezavisno od ovog nalaza. Zatvoreno — bez daljeg praćenja u ovom tasku.
13. backup-health-check.sh scheduling — RIJEŠENO
Skripta (ListBlobs egress alarm, izgrađena ranije danas) nikad nije bila raspoređena nigdje
(potvrđeno pretragom launchctl/crontab/plist — 0 pogodaka). Dedicated LaunchAgent otpada
(launchctl load permission-blokiran za agent sesije). Fix: piggyback na
~/system/daemons/offsite-backup.sh (6h kadenca, com.john.offsite-backup LaunchAgent), isti
pattern kao postojeći LumisCare demo Postgres re-stop guard (MC #105489) u istom fajlu:
perl -e 'alarm 180; exec @ARGV' -- bash <script> >> <log> 2>&1 || true — 3-minutni timeout,
nikad ne obara backup job. Syntax-checked (bash -n, exit 0). Test-run izolovano (bez
trigerovanja stvarnog B2 synca): health check je odradio pun ciklus, ulogovao 4 real nalaza
(GitHub push stale, 3 Docker kontejnera ne rade na ANVIL-u — pre-postojeći uslovi, nevezani
za ovaj task), Slack notifikacija poslata, combined exit code 0 (guard potvrđeno radi).
ListBlobs check specifično: WARN "could not read metric" tokom testa — dijagnostikovano:
Azure Monitor sa NULA ListBlobs saobraćaja izostavlja timeseries entry umjesto da vrati 0,
pa upit ne nalazi ništa (graceful degradation, ne bug — isti upit je ranije danas radio
ispravno kad je bilo stvarnog saobraćaja za mjerenje). Detalji:
backup-health-check-piggyback-test.md.
14. 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) — RIJEŠENO kratkoročno (vidi sekciju 12), temeljitija verzija i dalje u review-u
- #105521 boot.sh disk-check fix (čitao pogrešan volume) — nezavisan nalaz, praćen odvojeno
- 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, uslov upisan u policy memo
- ✅ backup-health-check.sh raspoređen (sekcija 13) — regression guard sada aktivan na 6h kadenci
- Azure prefiks cleanup (svih 64 prefiksa, ~5GB ukupno) + storage account decommission odluka ~30d (2026-08-13)
- $logs Storage Analytics stall nalaz (poslednji finalizovani log segment 15:43:30Z, ništa novo 5+h uprkos saobraćaju) — nije istraženo dalje, flagovano za buduću referencu ako $logs metod ponovo zatreba
CEO reaktivacioni uslov (verbatim, na snazi)
"Prebaci lokalno! Nemamo placene korisnika kad to dodje ide backup na azure do tada save money
gdje mozemo." Azure backup replikacija se REAKTIVIRA s prvim PLAĆENIM korisnikom. Reference:
memo project_backup_policy_local_until_paying_customers_2026-07-13, MC task #105462 opis
(ažuriran 23:13:55). Prije reaktivacije: obavezno istražiti litestream upgrade koji ne lista
pun ltx prefiks na svaki sync tick (follow-up gore) — ponavljanje ovog leaka bez tog istraživanja
je siguran ishod pri ponovnoj Azure replikaciji istog obima podataka.