Skip to main content

Mail signal & [INBOX] flood — zašto je CEO signal bio strukturno mrtav (2026-07-24)

Mail signal & [INBOX] flood — zašto je CEO signal bio strukturno mrtav (2026-07-24)

MC taskovi: #106283 (status: paused, čeka Proveo živu validaciju) · #106289 (status: ready_for_review) · #106285 (status: in_progress) Ova stranica je DoD-gate zahtjev za sva tri — dokumentacija je jedina preostala stavka prije zatvaranja.


1. Simptom i kako je otkriveno

CEO gut-feeling test: "provjeri manuelno mail čitanje? koristi API vs naš alat — imam gut feeling da nešto ne radi."

Boot mail-signal filter (korak 2 u ~/.claude/CLAUDE.md / /Users/makinja/CLAUDE.md) vraćao je nula pogodaka svaku sesiju, iako je CEO u međuvremenu slao mailove. Tri nezavisna nalaza povezana u ovoj sesiji objašnjavaju zašto — dva strukturna uzroka (#106283, #106289) i jedna posljedica istog roditeljskog problema koja se manifestovala kao zaseban simptom (#106285).


2. Root cause #1 — \Seen je dijeljeno mutabilno stanje (MC #106283)

  • ~/system/daemons/email-agent.js:1081client.messageFlagsAdd({ uid }, ['\\Seen'], { uid: true }) na kraju svakog ciklusa.
  • LaunchAgent com.john.email-agentStartInterval=300 (300s, potvrđeno u plist-u).
  • Posljedica: nezavisan imapflow probe (van mail-native.js) → [email protected] INBOX = 720 poruka, unseen = 0. Alat NIJE bio pokvaren — tačno je reportovao prazno stanje; premisa signala (IMAP unseen-flag) je bila pogrešna.
  • ~/system/tools/mail-boot-signal.sh (originalno MC #105898) je zvao mail-native.js unread --account "$ACCOUNT" --all. Log ~/system/logs/mail-boot-signal.log: 349 RUN linija od 2026-07-17, new_matches>0 samo 2× — obje na dan izgradnje (17.07). Zadnji total_unread_scanned>0 = 22.07.
  • Drugi, nezavisan blind spot: mail-boot-signal.sh je imao ACCOUNT="john" hardkodiran. CEO mail 21.07 ([email protected]) i 22.07 ([email protected]) sletio je u account=alem — potpuno van skena.
  • Ista klasa unseen-race već viđena ranije: MC #105906 / #105896 (john/alai isti fizički mailbox).

Glavna pouka stranice: IMAP \Seen flag nije validna baza za signal kad bilo koji drugi proces čita isti mailbox — prvi čitalac ga potroši. Signal mora doći iz vremenskog prozora nad DB-om (append-only ingest), ne iz flaga koji je dijeljeno mutabilno stanje.


3. Fix #106283 — DB time-window umjesto IMAP unseen

mail-boot-signal.sh prepisan:

  • Signal se računa iz vremenskog prozora (default 72h, env-override) nad ~/system/databases/email-inbox.db (tabela emails), ne iz IMAP \Seen.
  • Skenira sve naloge (accounts=ALL), ne samo john.
  • Dedupe po message_id (stabilan preko naloga; stari state je bio na IMAP UID koji nije prenosiv preko naloga).
  • Staleness guard: ako DB ne dobije nijedan novi red >60min (konfigurabilno), to je samo po sebi alarm — tiha smrt ingesta se prijavljuje, ne izgleda kao "nema signala".
  • Ista SIGNAL_PATTERN semantika kao ranije (CEO/partner/legal/urgent), da se ne promijeni šta se smatra signalom.

Dokaz (prije/poslije):

STARO: account=john total_unread_scanned=0
NOVO:  accounts=ALL window_hours=72 total_scanned=170 new_matches=1 slack=posted ... state=ok
       [MAIL SIGNAL] [email protected] (account alem) — ... (2026-07-22T08:11:49Z)
       [MAIL SIGNAL] [email protected] (account alem) — Fwd: PR ... (2026-07-21T18:05:43Z)

Cross-account pogodak dokazan uživo (AC1), dedupe potvrđen (dva uzastopna runa, drugi new_matches=0, AC3), staleness alarm okinut na agresivnom pragu i tih na normalnom pragu (AC5).

Razvojni bug vrijedan pomena: prvobitna verzija je koristila IFS=$'\t' za parsiranje redova iz DB-a — bash tretira tab kao IFS-whitespace pa kolabira uzastopne separatore kad je neko polje prazno; from_name je prazno u skoro svim redovima → sva polja poslije njega se pomjere ulijevo i subject se izgubi/pogrešno mapira. Fix: separator promijenjen na \x1f (unit separator, ne pojavljuje se u tekstu maila).

Evidence: ~/system/evidence/106283/ac1-cross-account-hit.log, ac3-dedupe.log, ac4-migration-no-flood.log, ac5-staleness-guard.log, ac6-doc-sync-diff.txt, final-mail-boot-signal.sh, gotcha-task-106283.md.


4. Root cause #2 — signal se davi u CI šumu (MC #106289)

Fix #106283 je bio tehnički tačan ali operativno beskoristan bez ovog drugog fixa: SIGNAL_PATTERN je sadržavao goli INVOICE (bez word-boundary), koji matchuje substring unutar hr-einvoice u Bilko Azure DevOps commit/PR subjektima (npr. fix(hr-einvoice): BT-23/BT-24 UBL conformance).

  • U cijelom email-inbox.db postoji 1249 redova od CI pošiljalaca ([email protected] / [email protected] / [email protected]).
  • Sa starim pattern-om (bez sender-filtera): 36 lažnih pogodaka na INVOICE substring.
  • Sa word-boundary \bINVOICE\b ali bez sender-filtera: i dalje 29 lažnih pogodaka (drugi keyword-i kao "legal" u "b10-legal-config", "BLOCKER" u "build 684 blocker" i dalje matchuju CI subjekte).
  • Sa punim fix-om (word-boundary + sender-exclude, provjeren PRIJE keyword matcha): 0 lažnih pogodaka.
  • Na stvarnom seed-anom production stanju (16 unosa u ~/system/state/mail-signal-seen-uids.txt): 11/11 [email protected] redova → EXCLUDED, tačno kako je task tvrdio ("11 su PR buildovi").

Korekcija broja (bitna za integritet, ne izostaviti): task-opis je tvrdio "samo 2 stvarna CEO maila" preostala. Živa provjera preostalih 16-11=5 redova pokazala je 4 zadržana pogotka, ne 2: 2 stvarna CEO maila ([email protected], [email protected] — webinar fwd) + 2 Apple "Fakturaen din fra Apple" (matchuju na faktura keyword, van scope-a ovog fixa, legitimno zadržani da se signal ne prefiltrira). 5. red (nejasno koji) nije naveden u verdict.md kao dio ni jedne kategorije — ostavljeno kako je zatečeno, nije ovog fixa scope.

Fix (~/system/tools/mail-boot-signal.sh):

SIGNAL_PATTERN='...|\bINVOICE\b|faktura'          # word-boundary
CI_SENDER_EXCLUDE_PATTERN='azuredevops@microsoft\.com|azure-pipelines@|azure-noreply|noreply@dev\.azure\.com'

Sender-exclude provjera dodana PRIJE keyword matcha u oba loop-a (linije 178 i 203 u trenutnoj verziji skripte). Production state fajl očišćen 16→4 zadržana pogotka (backup: seen-uids-BEFORE-cleanup.txt, rezultat: seen-uids-AFTER-cleanup.txt). Finalni produkcijski run: exit=0, new_matches=0, bez ponovnog paljenja 11 uklonjenih CI message_id-ova.

Evidence: ~/system/evidence/106289/AC1-ci-sender-before-after.txt, AC2-hr-einvoice-example.txt, ac3-isolated/, AC4-legit-invoice-still-matches.txt, AC6-production-dedupe-proof.txt, before-after.txt, seen-uids-BEFORE/AFTER-cleanup.txt, verdict.md.

Pouka: kad oživiš mrtav signal, odmah provjeri KO su pogoci. Nijedan acceptance-criterion u #106283 nije to pitao — defekt je izašao tek naknadnim ručnim mapiranjem message_id → pošiljalac protiv 1249 CI redova.


5. [INBOX] flood (MC #106285)

284 otvorena H-priority [INBOX] taska u mission-control.db, verifikovano direktnim SQLite upitom (ne CLI paginacijom):

SELECT COUNT(*) FROM tasks WHERE status='open' AND priority='H' AND title LIKE '[INBOX]%'  -- => 284

Sender breakdown (raw enumeracija, enumeration-284-full.csv):

  • [email protected] (build/PR/approval notifikacije): 149
  • [email protected] (Azure Monitor Sev1/budget alerts): 90
  • Sve ostalo (stvarna korespondencija — efaktura, banke, partneri, CEO, self-alerti): 45

149 + 90 = 239 = stvarni "notification flood" zbog kojeg je task otvoren.

Fix u ~/system/tools/inbox-watcher.js (isNewsletterOrNotification()): nova CI grana koja za [email protected] / azure-pipelines@* / [email protected] vraća {isNoise:false, category:"ci_notification", priority:"M"}snižava prioritet na M, NE guši signal (isNoise ostaje false, task se i dalje kreira, samo ne na H). Namjerno drugačije od self_digest guarda (2026-07-20, full suppress) jer "Build failed" jeste stvaran signal. createMcTask() proširen parametrom priority (default "H", sad prosleđen "M" za CI granu).

Acceptance replay (vm.runInContext nad živom funkcijom, ne ručni prepis logike):

CASE 1 (Build failed, [email protected]) → {isNoise:false, category:"ci_notification", priority:"M"} — PASS
CASE 2 (regresija: self_digest i dalje suppressed) → PASS
CASE 3 (regresija: legit known-contact mail neizmijenjen) → PASS

Triage 284 → 239 zatvoreno, 45 ostalo otvoreno (9 KEEP-OPEN + 36 UNVERIFIED), enumeracijom, ne WHERE-pretpostavkom:

Kategorija Broj Odluka Dokaz
[Build failed] 96 CLOSE-STALE build history + PR status per task (88 superseded, 8 pojedinačno provjereno abandoned/merged/dormant)
[PR build failed] 1 CLOSE-STALE PR #218 abandoned
[Run stage approval pending] 49 CLOSE-STALE live _apis/pipelines/approvals: 0 pending u oba projekta
PR merge notifikacije 2 CLOSE-STALE PR #47/#170 status=completed
PAT rotation info 1 CLOSE-STALE informativno, poznat događaj
Azure Sev1 "API-Availability-Down" 54 CLOSE-STALE live curl 200 na sva tri qody.ba domena, zadnja pojava 07-21
Azure Sev1 "5xx-alert" 33 CLOSE-STALE live curl 200 bilko.cloud, zadnja pojava 07-17
Azure budget threshold exceeded 2 KEEP-OPEN alai-monthly-budget: amount=5500, currentSpend=15292 — jedina od 284 stavki gdje je uslov u trenutku triage-a i dalje VERIFIED true
Action-group email verification 1 UNVERIFIED CLI ne izlaže status verifikacije, nije pretpostavljeno
CEO mail 5 KEEP-OPEN (politika, nikad auto-close)
Ermin Zatega / Avaz 2 KEEP-OPEN-PARKED CEO nalog, ne djeluj bez nove prijave
Test sender / SENTINEL health 3 CLOSE-STALE verifikovano živo (launchctl exit=0)
Ostalo (self-notes + vanjska korespondencija) 35 UNVERIFIED zaseban mail-triage pass, van scope-a ovog MC taska

Evidence: ~/system/evidence/106285/triage-2026-07-24.md (puni breakdown), subtask1-acceptance-replay.txt, enumeration-284-full.csv, non-ci-tasks.csv, Bilko-builds-full.json, QODY-builds-full.json, bilko-approvals.json, qody-approvals.json.

Bitna napomena o pokrivenosti fixa (nije bilo dio brief-a, otkriveno pri pisanju ove stranice): isNewsletterOrNotification() CI grana pokriva SAMO [email protected] / azure-pipelines@ / [email protected] (Azure DevOps CI notifikacije = 149 od 239). [email protected] (Azure Monitor Sev1/budget alerti = 90 od 239) NIJE pokriven ovim guard-om — grep na inbox-watcher.js ne nalazi taj sender pattern nigdje u fajlu. Ovih 90 zatvoreno je samo kao jednokratni bulk-close u triage-u; ako se Sev1/budget alert ponovo desi, novi task će opet biti kreiran na H prioritetu. Ovo nije bug u smislu netačnosti fixa (fix radi tačno ono što je opisan da radi za CI build notifikacije) — ali je gap u pokrivenosti koji vrijedi zatvoriti prije nego se flood ponovi.


6. Šta ostaje otvoreno (pošteno, bez uljepšavanja)

  • ~/.claude/CLAUDE.md je uchg-zaključan (chflags) → boot korak 2 tamo i dalje opisuje mrtvi IMAP mail-native.js unread mehanizam. Zamjenski tekst je pripremljen i čeka u ~/system/evidence/106283/ac6-doc-sync-diff.txt; primjena zahtijeva chflags nouchg ~/.claude/CLAUDE.md (CEO odluka — fajl je namjerno zaključan). /Users/makinja/CLAUDE.md (duplikat istog koraka) je već ažuriran uživo.
  • Azure budget alai-monthly-budget: amount=5500, currentSpend=15292 (az consumption budget list, zabilježeno u triage-u 2026-07-24) — jedina od 284 [INBOX] stavki gdje je osnovni uslov i dalje istinit, nije dio ove klase bug-a. MC #104896 i #105039 (isti recurring nalaz, prijavljen dvaput) ostaju namjerno otvoreni. Napomena: live re-provjera u ovoj sesiji vratila je RBACAccessDenied na trenutno aktivnom Azure profilu — broj je iz evidence fajla triage-a, nije ponovo uživo potvrđen u ovoj sesiji.
  • 36 UNVERIFIED stavki iz [INBOX] flood-a (3 [email protected] self-notes + 32 vanjska korespondencija) — treba zaseban, eksplicitno pozvan mail-triage task; nisu zatvorene niti pretpostavljene riješenim.
  • Gap u ci_notification pokrivenosti (vidi sekciju 5): [email protected] (Azure Monitor Sev1/budget) nema guard u inbox-watcher.js — samo Azure DevOps CI build/PR pošiljaoci su pokriveni.
  • MC #106286 (paused): /prompt-forge skill postoji (~/.claude/skills/prompt-forge/SKILL.md) i po specifikaciji piše forged prompt na ~/system/prompts/forged/<mc_id>.md — ali PI orchestrator gate (~/system/kernel/pi-orchestrator.js, provjera _gotchaPath) čita /tmp/gotcha-task-<id>.md. Putanje se ne poklapaju → svaki H/BLOCKER task automatski upada u awaiting_forge blok bez obzira da li je /prompt-forge stvarno pokrenut, i jedini poznati izlaz je ručni GOTCHA fallback fajl direktno na /tmp/gotcha-task-<id>.md (presedan viđen i u ovoj epizodi: ~/system/evidence/106283/gotcha-task-106283.md je manuelni fallback, ne /prompt-forge izlaz).
  • MC #106294 (blocked, ironično na istom gate-u): PI orchestrator duplo-dispatch u ovoj istoj sesiji — mc.js pause na #106283 nije zaustavio već pokrenut spawn (builder je usred rada pregazio mail-boot-signal.sh drugom implementacijom, uhvaćeno write-guardom, backup u concurrent-edit-found-mail-boot-signal.sh.bak); i na #106289 auto-recovery je reopenovao task koji je već imao živog ne-PI izvršioca. Recidiv poznate klase (project_pi_stale_dispatch_recurrence_2026-07-20, claim-race #105650).

Reference

  • Cross-linked runbook (ažuriran u sklopu #106289): Email System Runbook
  • Evidence: ~/system/evidence/106283/, ~/system/evidence/106285/, ~/system/evidence/106289/
  • GOTCHA briefovi: ~/system/evidence/106283/gotcha-task-106283.md, /tmp/gotcha-task-106289.md