Cron tick спрацьовує 3×/день. Pipeline робить fan-in (RSS+select) → fan-out на 3 паралельні output'и (Telegram-пост з PNG, Threads-thread, лог). seen_ids.json — точка дедуплікації, оновлюється після успіху Telegram (мінімальний commitment).
1. CRON tick @ 05:00 / 11:00 / 17:00 UTC
2. load_seen() # set з seen_ids.json
3. articles = fetch_rss(MAX_AGE_HOURS=90)
3a. для кожного з 5 RSS-feed'ів → перші 10 entries, filter за cutoff
3b. помилка одного feed — log + continue
4. new_articles = articles - seen
4a. якщо порожньо → exit «no new articles»
5. selected = gemini_select_and_format(new_articles[:15])
5a. retry 1× з batch=8 якщо timeout
5b. якщо all fail → log error, exit
6. selected містить: {source_article, telegram_html, summary, link, journal}
7. FAN-OUT (паралельно через threads / asyncio.gather):
├── 7a. infographic_pipeline(selected)
├── 7b. telegram_pipeline(selected, png_path_future)
└── 7c. threads_pipeline(selected)
8. join fan-out → collect (tg_ok, threads_ok, png_ok)
9. якщо tg_ok → seen.add(selected.id); save_seen()
10. log_metrics({tg_ok, threads_ok, png_ok, timings})
gemini_call(batch_15, timeout=60)
→ TimeoutError → retry with batch_8, timeout=45
→ still fail → log "[Gemini] hard fail" + exit без поста
threads_publish(root) → OK, root_id збережено
threads_publish(reply_1) → 403 permission
→ log warning, НЕ блокуємо tg_ok, root залишається у фіді одиничним
→ daily-metrics позначає depth=1 замість 3
render_png(spec)
→ Exception (шрифт missing / spec невалідний)
→ telegram_pipeline отримує png=None → sendMessage (text-only) замість sendPhoto
→ log degraded
fetch_rss(hours) → list[Article] з 5 feed'ів, з age-filtergemini_select_and_format(articles) → SelectedPost (Telegram-HTML + machine fields)build_infographic_spec(post) → InfographicSpec (через infographic-builder skill, Gemini)render_png(spec) → PNG path 1080×1080 (PIL, детермінований)build_threads_thread(post) → ThreadsThread (через threads-news-editor agent)telegram_publish(html, png_path|None) → boolthreads_publish_thread(thread) → int depth (0..3) посилаючись на reply_to_id chain з 30-60 сек паузpersist_seen(id) → атомарне save_seen()log_metric(event) → append у /var/log/pediatric-news.jsonlgemini CLI): timeout 60s, prompt-template = telegram-news + окремий = infographic-spec + threads-threadsendPhoto з caption HTML (1024 chars limit на caption!), fallback sendMessagePOST /threads (create container) → POST /threads_publish (publish), пауза 30-60 сек, reply_to_id chain