ADR-0014: Інтелект як дані — offline-артефакти замість online-інференсу
Статус: accepted · 2026-07-12 · власник @Vladbandurin
Контекст
Section titled “Контекст”Serving abitly-recsys тримається на інваріанті детермінізму: видача однозначна за (inputs, policyVersion, editorialVersion, featureSnapshotId) → точний кеш-ключ, відтворюваність, admin-preview = prod-видача. Online ML-інференс цей інваріант ламає і додає другий always-on сервіс. Дані рекомендацій за природою batch: co-application — річний знімок кампанії, декларований інтент змінюється рідко.
Рішення
Section titled “Рішення”«Інтелект заходить як дані, не як код». Увесь ML — offline Python batch: apps/compute (uv) у тому ж монорепо, запуск ECS Scheduled Task (патерн Scheduler→Fargate як в abitly-ads sync), нічний. Артефакти — версіоновані таблиці в Postgres recsys під snapshotId (item_item_edges, фічі, intent read-model), без S3/parquet-прошарку у v1. Serving (NestJS) лише читає артефакти і застосовує policy ⊕ editorial; персональна видача — детерміністичний scoring (eligibility-SQL + matching), не інференс.
Відхилена альтернатива
Section titled “Відхилена альтернатива”Окремий online Python-скорер за /v1/rank (шлях, який спека 2026-06-06 §9 тримала за замовчуванням для «ML пізніше») — виправданий лише з появою behavioral feedback loop реального часу; контракт його не блокує.
Наслідки
Section titled “Наслідки”- + Інваріант детермінізму та дешевий fail-open виживають (артефакт застарів → показуємо вчорашній); нема другого always-on сервісу.
- + Offline eval артефактів (coverage/overlap/staleness → Grafana) ловить «матриця зіпсувалась» до користувача.
- − Жодного real-time навчання/оновлення видач між прогонами batch.
Деталі — spec docs/superpowers/specs/2026-07-12-recommendation-core-design.md §5–6 (репо abitly-mc).