AAYMA
RU
Войти

Координатор казны

Воспроизводимый пайплайн по сети переводов назначает каждому из 2 248 клиентов роль (координатор, распределитель, консолидатор, транзит и др.)…

Доведённый продукт
Команда «DAI» 27💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: DAI
Кейс HackAlem.ai: Финансы — Freedom
Стадия: Доведённый продукт

Задача кейса: «Граф денег»: восстановить структуру организованной группы по сети транзакций (AML)

Суть

Воспроизводимый пайплайн по сети переводов назначает каждому из 2 248 клиентов роль (координатор, распределитель, консолидатор, транзит и др.), кластер и приоритет проверки с числовым обоснованием. Экран аналитика показывает очередь проверки, окрестность узла и карточку.

Как устроено

make pipeline читает parquet и строит направленный граф в NetworkX. Признаки: in/out-degree, обороты, pass_kzt, betweenness, PageRank, число seed выше по потоку, глубина. Временной слой ищет быстрый транзит: сумма ±20%, лаг 0–2 дня. Кластеры строит Louvain (seed 42) на ненаправленной взвешенной проекции. Роли назначаются по опубликованным правилам с порогами в порядке приоритета. Приоритет — единый балл; evidence, next_request и limitations пишутся шаблонами. На выходе три CSV и 49 проверок. FastAPI отдаёт данные, React + d3 рисует граф с таймлапсом.

Ключевые решения

  • NetworkX
  • Louvain
  • PageRank
  • betweenness centrality
  • правила ролей с порогами
  • детекция быстрого транзита
  • сравнение с baseline-ранжированиями
  • перестановочный тест дат
  • d3

Метрики

49 проверок, 0 провалено; роли: coordinator 54, distributor 29, consolidator 144, transit 61, terminal 1034, peripheral 926; 89 кластеров; пайплайн ≈2 с

Особенности

Обрыв графа на 4-м колене учтён: 444 граничных узла не получают роль terminal. Временной признак проверен перестановкой дат. baselines.py сравнивает устойчивость сети при удалении топ-N узлов против наивных ранжирований. В README честно зафиксирован отрицательный результат (quiet-bridge сводится к степени). Все выводы помечены как гипотезы.

Стек

Python · NetworkX · pandas · pyarrow · FastAPI · React · TypeScript · TanStack Router · shadcn/ui · d3 · Docker Compose · Makefile


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-617d5a6a-dai.

README

README.md

DAI — «Координатор казны»: роли и приоритеты проверки в сети переводов (кейс «Граф денег»)

Концепт интерфейса «Координатор казны»

Это макет, а не снимок работающего интерфейса. Его содержимое условное; проверяемые результаты приведены ниже и в outputs/.

Команда DAI, кейс HackAlem AI «Граф денег». «Координатор казны» — имя инструмента: он показывает, кто в наблюдаемой сети переводов координирует движение денег, кто собирает, кто раздаёт и кто пропускает дальше, и ставит клиентов в очередь проверки с объяснением по числам. Все выводы — гипотезы для проверки аналитиком.

Быстрый запуск

Из корня репозитория, нужен Python 3.11–3.13. Сначала проверьте python3 --version. Если версия вне этого диапазона, создайте .venv по разделу Требования. На Python 3.14 закреплённый pyarrow пытался собраться из исходников и установка завершилась ошибкой.

make setup && make pipeline

Есть и путь через Docker: docker compose run --rm --build pipeline даёт те же три CSV, docker compose up --build поднимает экран на http://localhost:8080 (раздел Через Docker).

make setup создаёт .venv и ставит зависимости из requirements.txt. make pipeline пересчитывает три CSV из task/data/*.parquet в outputs/ и сразу прогоняет проверку выгрузок. Прогон удался, если последние строки такие:

проверок 49, провалено 0
роли: consolidator 144, coordinator 54, distributor 29, peripheral 926, terminal 1034, transit 61
кластеров: 89

Интерфейс запускается отдельно, в двух терминалах: раздел Интерфейс.

Содержание

  1. Краткое описание
  2. Что реализовано
  3. Как работает
  4. Критерии ролей и пороги
  5. Технологии
  6. Архитектура
  7. Требования
  8. Установка и запуск
  9. Как проверить
  10. Что на выходе
  11. Как мы себя проверяли
  12. Данные и интеграции
  13. Ограничения
  14. Масштабирование до ~1 млн узлов
  15. Раскрытие ранее созданного (п. 6.4)
  16. Структура репозитория
  17. Развёрнутая версия

Краткое описание

Правоохранительные органы передали банку 81 клиента (seed), ранее выявленных как участники незаконного оборота наркотиков. Банк выгрузил исходящие переводы от них на 4 колена: 2 248 клиентов, 3 119 пар плательщик→получатель, 4 840 переводов на 365 890 012 KZT за июль 2026. Аналитику финмониторинга нужно решить, кого из 2 248 клиентов проверять первым, почему и какие данные запросить следующими.

Решение для аналитика без ML-подготовки: каждому клиенту назначаются роль по опубликованному правилу с порогами, кластер и приоритет проверки, а рядом пишется обоснование с числами. Всё это гипотезы для проверки, а не утверждения о виновности: роль «консолидатор» означает «есть признаки консолидации средств».

Что реализовано

Пять обязательных пунктов ТЗ (§7):

№Пункт ТЗГдеКак проверить
1Воспроизводимый пайплайн от parquet до трёх CSVpipeline/run.py, make pipelineодна команда, ≈2 с, гейт проверок 49, провалено 0
2Роль, role_score и evidence у каждого узлаoutputs/nodes_roles.csv2 248 строк, все обязательные колонки заполнены, evidence с числами ≤ 200 символов
3Критерии ролей задокументированыpipeline/rules.py, pipeline/roles_v1.py, раздел Критерии ролейколонка role_checks у любого gid показывает, какие условия правила выполнены и с какими числами
4Кластеризацияpipeline/clusters.py, outputs/clusters.csv89 кластеров, cluster_id у каждого узла, у кластера размер, число seed, оборот и гипотеза
5Топ-лист и визуализацияoutputs/top_nodes.csv; backend/ и dai-front/в топе 50 узлов с обоснованием. Экран http://localhost:5173: поле поиска по gid, очередь проверки слева, окрестность узла со стрелками от плательщика к получателю (цвет — роль, обводка — seed и граница выгрузки), карточка узла справа: роль и выполненные условия, приоритет и два факта, пары переводов со статусом по датам, следующий запрос.

Дополнительные пункты (§8), вошедшие в сдачу:

  • Обрыв графа на 4-м колене. 444 узла глубины 4 не получают роль terminal: исходящие у них не собирались. У них обнуляются вклады исходящих признаков в приоритет, а в limitations написано «исходящие не выгружены».
  • Временной признак. Быстрый транзит: пары «вход → выход» с суммами ±20 % и лагом 0–2 дня. Флаг у 54 узлов, проверен перестановкой дат (см. Как мы себя проверяли).
  • Оценка полноты. У каждого узла в next_request указано, какие данные запросить следующими (исходящие для граничных узлов, входящие для seed, назначения платежей для пар быстрого транзита).
  • Устойчивость сети. pipeline/baselines.py снимает топ-10, 20 или 50 узлов и считает остаток крупнейшей компоненты и оборота против наивных ранжирований.

Как работает

Сценарий аналитика:

  1. Аналитик получает 81 известный gid и выгрузку переводов на 4 колена (task/data/).
  2. Одна команда make pipeline присваивает каждому из 2 248 узлов роль, кластер и приоритет, пишет обоснование и проверяет выгрузки.
  3. Аналитик открывает outputs/top_nodes.csv или экран: первые строки топа — узлы, у которых не меньше двух фактов о переводах попадают в 5 % самых заметных.
  4. По gid открывает карточку: роль и выполненные условия правила (role_checks), приоритет и два факта с наибольшим вкладом, быстрый транзит, ограничения данных по узлу и следующий запрос данных.
  5. Решает, кого проверять первым, и какие данные запросить в банке.

Экран (снимки 23.09, узел из первой строки очереди):

Окрестность узла и карточкаОбщий вид с подписями кластеров
Окрестность узла со стрелками направления денегОбщий вид сети с подписями кластеров

Стрелки идут от плательщика к получателю, цвет узла — роль, размер — приоритет проверки, обводка — исходный клиент (seed) и граница выгрузки.

Пример: открыли координатора

Первый узел очереди — координатор (оранжевый ромб в центре). Окружение на 3 шага: 191 узел и 372 связи. Рядом с ним группа таких же ромбов — другие координаторы той же ветви, через которых деньги расходятся дальше; стрелки показывают, откуда деньги пришли и куда ушли. У выбранного узла по связям бежит пунктир. Внизу таймлапс по дням июля: гистограмма переводов из загруженных карточек, можно выделить дни и увидеть, какие связи были активны.

Окружение координатора: ромбы — координаторы, стрелки — направление денег, размер — приоритет проверки

Что обозначают классы на схеме (легенда на экране та же):

ЗнакРоль или признакКак читать
оранжевый ромбкоординаторполучает от нескольких плательщиков и отправляет многим получателям, достижим из нескольких исходных клиентов; кандидат на связующий узел сети, гипотеза для проверки
розовая звездараспределительотправляет переводы 10 и более разным получателям (fan-out)
синий треугольник вниз (воронка)консолидаторполучает переводы от 3 и более разных клиентов (fan-in)
жёлтый треугольник вправотранзитесть вход и выход; отправил 0,8–1,2 от полученного или повторял пары «получил → отправил похожую сумму» за 0–2 дня
серо-голубой квадратполучатель без видимых исходящихденьги пришли, исходящих в выгрузке нет; не относится к узлам на границе выгрузки
светло-серый кругпериферияни одно правило роли не выполнено; в карточке написано, к какому правилу узел ближе всего
размер знакаприоритет проверкичем больше, тем выше priority_score; в очереди проверки узлы с двумя и более фактами среди 5 % самых заметных
светлая обводкаисходный клиент (seed)один из 81 клиента, от которых собрана выгрузка; входящие переводы у него неполны
пунктирная обводкаграница выгрузкиузел четвёртого шага: исходящие переводы не собирались, отсутствие выхода ничего не значит
стрелканаправление денегот плательщика к получателю; толщина — сумма переводов между парой за июль
бегущий пунктирвыбранный узелсвязи открытого узла, чтобы найти его среди соседей

Пороги правил — в таблице «Критерии ролей и пороги»; условия для конкретного узла — в колонке role_checks и в карточке.

Что происходит внутри make pipeline:

  1. load.py читает три parquet и сверяет их между собой: 2 248 узлов, 3 119 рёбер, 4 840 переводов, 81 seed, 19 изолятов, оборот 365 890 012 KZT.
  2. features.py строит направленный граф и считает признаки узла: число разных плательщиков и получателей (in_deg, out_deg), входящий и исходящий оборот, сквозную сумму pass_kzt = min(вход, выход), betweenness, PageRank, число seed, от которых узел достижим (n_seed_upstream), глубину и флаги неполноты.
  3. temporal.py сопоставляет входящие и исходящие переводы узла один к одному и ставит флаг быстрого транзита.
  4. clusters.py делит сеть на кластеры: Louvain (seed 42, resolution 1,0) на ненаправленной проекции, где вес пары — сумма переводов в обе стороны. Несвязные части сообщества разделяются, изоляты идут отдельными кластерами.
  5. roles_v1.py назначает роль по правилам и порогам из rules.py.
  6. priority.py считает единый приоритет и очередь проверки.
  7. evidence.py пишет evidence, why, гипотезу кластера, next_request и limitations.
  8. export.py записывает три CSV и run_meta.json, check.py проверяет выгрузки.

Критерии ролей и пороги

Роли проверяются по порядку; узлу достаётся первая, правило которой выполнено: coordinator > distributor > consolidator > transit > terminal > peripheral. Правило выполнено, если выполнены все его условия.

РольСмыслПравилоУзлов
coordinatorсвязывает несколько ветвей сети, кандидат на роль организатора (гипотеза для проверки)in_deg ≥ 3 и out_deg ≥ 5 и n_seed_upstream ≥ 3; или betweenness ≥ P99 среди узлов с in_deg ≥ 2 и out_deg ≥ 2 (порог ≈ 0,0061) при in_deg ≥ 2 и out_deg ≥ 254
distributorвеер выходов (fan-out)out_deg ≥ 1029
consolidatorсходимость входов (fan-in)in_deg ≥ 3144
transitпропускает средства дальшеin_kzt > 0 и out_kzt > 0 и (выход/вход ∈ [0,8; 1,2] у не-seed или быстрый транзит, не меньше 2 пар)61
terminalполучатель без видимых исходящихin_deg ≥ 1 и out_deg = 0 и глубина < 4 и не seed1 034
peripheralпризнаков роли не выявленони одно правило выше не выполнено926

in_deg и out_deg — число разных плательщиков и получателей. У seed отношение выход/вход не используется: их входы в выгрузку не попали.

role_score — сила поддержки правила, а не вероятность. У назначенной роли это среднее по условиям правила: числовое условие даёт перцентильный ранг значения среди всех 2 248 узлов (0–1), булево даёт 1. У peripheral это 1 минус максимальная поддержка по остальным ролям, то есть насколько узел далёк от любого правила.

Все пороги лежат в одном месте, pipeline/rules.py, и записываются в outputs/run_meta.json. Таблица ниже — вывод print_thresholds(), квантили посчитаны по 2 248 узлам:

.venv/bin/python -c "from pipeline.rules import print_thresholds; print_thresholds()"
порогзначениегде на распределении
coordinator_min_in_deg3in_deg: P90/P95/P99 = 2/3/6; 91,1 % узлов ниже 3
coordinator_min_out_deg5out_deg: P90/P95/P99 = 3/5/23,5; 94,2 % узлов ниже 5
coordinator_min_seed_upstream3n_seed_upstream: P25 = 1, P50 = P75 = 7, P90 = 9; 28,9 % узлов ниже 3 (при ≥2 было 27,3 %); у всех 54 координаторов ≥ 6, так что 2→3 никого не отсекает
coordinator_betweenness_q0.99альтернативная ветка: betweenness ≥ P99 среди узлов
coordinator_betweenness_min_deg2
distributor_min_out_deg10out_deg ≈ P97 (97,2 % узлов ниже 10)
consolidator_min_in_deg3in_deg P95
transit_ratio_low0.8out_kzt/in_kzt ∈ [0,8; 1,2] (72 узла) или быстрый транзит
transit_ratio_high1.2
terminal_min_in_deg1in_deg P5 < 1: 1,9 % узлов без входов
terminal_max_depth_exclusive4глубина 4 — граница выгрузки, исходящие не собирались
peripheral_score0.3только v0: role_score периферии фиксирован; в v1 — 1 − макс. поддержка других ролей
coordinator_in_norm6только v0 (запасной метод)
coordinator_out_norm10только v0 (запасной метод)
distributor_out_norm25только v0 (запасной метод)
consolidator_in_norm8только v0 (запасной метод)
terminal_score0.5только v0 (запасной метод)
priority_w_pagerank0.5только v0 (запасной метод)
priority_w_degree0.4только v0 (запасной метод)
priority_w_seed0.1только v0 (запасной метод)
ROLE_ORDERcoordinator > distributor > consolidator > transit > terminal > peripheralпервая сработавшая роль
PRIORITY_THRESHOLD_RAW6справочный порог суммы, не очередь
QUEUE_MIN_TERMS_ABOVE_P952очередь: столько признаков в верхних 5 %
TERM_P95_CONTRIBUTION2.9957вклад признака в верхних 5 %: −ln 0,05
FAST_TRANSIT_WEIGHT1добавка к priority_raw при флаге

Приоритет и очередь проверки

Приоритет помогает выбрать, кого проверить первым. Семь показателей описывают суммы переводов, число разных плательщиков и получателей, положение клиента между другими клиентами, меньшую из входящей и исходящей сумм и число исходных клиентов, связанных с ним по графу. Редкое значение даёт больше баллов. Повторные пары переводов похожей суммы за 0–2 дня добавляют один балл. Клиент попадает в очередь проверки, если хотя бы два из семи показателей входят в верхние 5 % среди 2 248 клиентов. Баллы не показывают вероятность нарушения.

Формально: приоритет — один скор по семи фактам о переводах: входящий и исходящий оборот, число плательщиков и получателей, betweenness, сквозная сумма, число seed выше по потоку. Для факта со значением x вклад равен −ln p, где p — доля узлов со значением не меньше x. Факт, которым обладает 5 % узлов, даёт вклад 3,0; нулевое значение даёт 0. К сумме добавляется 1,0 при флаге быстрого транзита. У 444 граничных узлов глубины 4 вклады исходящего оборота, числа получателей и сквозной суммы равны 0.

  • priority_raw — эта сумма; priority_score = priority_raw / максимум по выгрузке (41,2), шкала 0–1.
  • Очередь проверки (in_queue = 1): не меньше двух фактов из семи среди 5 % самых заметных, то есть вклад ≥ −ln 0,05 ≈ 3,0. В очереди 165 узлов (7,3 %), все 50 узлов топа в неё входят.
  • Порог суммы 6,0 справочный: из-за корреляции фактов его набирают многие средние узлы (681 из 2 248), поэтому очередь задаётся правилом двух фактов.
  • top_nodes.csv — первые 50 узлов по priority_raw, при равенстве по gid.
  • В evidence и why — роль с числами, два факта с наибольшим вкладом и их перцентили, число фактов выше P95, флаг быстрого транзита и ограничения данных.

Запасной метод v0 (только пороги стартовых гипотез, приоритет по PageRank и степени) оставлен на случай отката: .venv/bin/python -m pipeline.run --data task/data --out outputs --method v0. Сдаётся v1. Команда перезаписывает outputs/ выгрузкой v0: после неё шаги 3–4 раздела Как проверить дадут расхождение CSV с git и провал --require-method v1. Вернуть v1 — make pipeline.

Технологии

ЧастьСтек
ПайплайнPython 3.11–3.13; pandas 2.3.3, pyarrow 20.0.0, networkx 3.4.2 (Louvain, betweenness, PageRank), scipy 1.16.2, numpy; версии закреплены в requirements.txt
APIFastAPI 0.139.0, uvicorn 0.44.0, pydantic 2.12.5
ИнтерфейсReact 19.3, TypeScript 6.0.3, Vite 8.3, Tailwind CSS 4.3, TanStack Router и Query, Hey API (клиент из OpenAPI), d3 7.9 для схемы сети; Node ≥ 22.18, проверено на 24.13 и 26.8, версии в dai-front/package-lock.json

Платных API, GPU, внешних сервисов и секретных ключей решение не использует.

Архитектура

Пайплайн работает пакетно и пишет файлы в outputs/. API читает эти CSV и исходные parquet и отдаёт карточки, окрестности и топ. Интерфейс ходит в API через прокси Vite /api. Контракт dai-front/openapi.json генерируется из бэкенда.

Схема решения: данные → метрики → роли → интерфейс.

flowchart LR
  A["task/data: nodes, edges, transactions (.parquet)"] --> B["load.py: сверка трёх файлов"]
  B --> C["features.py, temporal.py: степени, суммы, betweenness, seed выше по потоку, сквозная сумма, пары вход-выход, флаги неполноты"]
  C --> D["clusters.py: Louvain на проекции, seed 42"]
  C --> E["roles_v1.py + rules.py: правило роли, role_score, role_checks"]
  C --> F["priority.py: сумма −ln p по 7 фактам + флаг, очередь проверки"]
  D --> G["evidence.py: evidence, why, hypothesis, next_request"]
  E --> G
  F --> G
  G --> H["outputs: nodes_roles.csv, clusters.csv, top_nodes.csv, run_meta.json"]
  H --> K["check.py: гейт выгрузок"]
  H --> I["backend: FastAPI :8000"]
  I --> J["dai-front: экран на :5173"]

Требования

  • Python 3.11, 3.12 или 3.13: python3 --version. На 3.9 не ставится fastapi 0.139.0, на 3.10 — scipy 1.16.2. Симптом: make setup заканчивается строками Could not find a version that satisfies the requirement … и No matching distribution found for …, а выше стоит require a different python version или Requires-Python. Это версия Python, а не сеть: при сбое сети в выводе nodename nor servname provided или Failed to establish a new connection (раздел Если нет сети).
  • make (на macOS и Linux есть; без него команды из раздела Без make).
  • Для интерфейса: Node.js не ниже 22.18 (node --version), npm. Проверено на Node 24.13 (версия из dai-front/.nvmrc) и 26.8.
  • Сеть нужна только на установку зависимостей: pypi.org для pip, registry.npmjs.org для npm. Пайплайн и API сетевых вызовов не делают.
  • Свободные порты 8000 (API) и 5173 (интерфейс); как сменить — в разделе Смена портов.

Если системный python3 не версии 3.11, 3.12 или 3.13, создайте .venv подходящей версией. В этом случае make setup не нужен.

uv venv --python 3.11 .venv && uv pip install --python .venv/bin/python -r requirements.txt
python3.11 -m venv .venv && .venv/bin/pip install -r requirements.txt

uv ставится по инструкции docs.astral.sh/uv; python3.11 — установщиком с python.org или brew install [email protected]. После этого make setup не нужен, сразу make pipeline. Если .venv уже создан другой версией Python (в том числе упавшим make setup), сначала удалите его: rm -rf .venv. Версию в .venv проверяет .venv/bin/python --version.

Установка и запуск

Все команды — из корня репозитория.

Пайплайн

make setup      # .venv и зависимости из requirements.txt
make pipeline   # task/data/*.parquet → outputs/*.csv, затем проверка выгрузок
make check      # только проверка выгрузок (код возврата 1 при нарушении)

Ожидаемый вывод make pipeline (замер 23.09.2026, MacBook на Apple M4 Max, Python 3.11; время на другой машине другое, в ТЗ лимит 5 минут). Строка готово за считает только расчёт; вместе с загрузкой библиотек команда идёт 4–5 с, а первый запуск в только что созданном .venv дольше: на чистом клоне с Python 3.13.5 записано 28,6 с (docs/acceptance.md).

готово за 1.81 s: outputs/nodes_roles.csv, outputs/clusters.csv, outputs/top_nodes.csv, outputs/run_meta.json
роли: consolidator=144, coordinator=54, distributor=29, peripheral=926, terminal=1034, transit=61
кластеров: 89
очередь проверки: 165 узлов (...)
...
проверок 49, провалено 0
роли: consolidator 144, coordinator 54, distributor 29, peripheral 926, terminal 1034, transit 61
кластеров: 89

Число строк в выгрузках:

wc -l outputs/nodes_roles.csv outputs/clusters.csv outputs/top_nodes.csv
    2249 outputs/nodes_roles.csv
      90 outputs/clusters.csv
      51 outputs/top_nodes.csv

Это 2 248 узлов, 89 кластеров и 50 узлов топа плюс строка заголовка в каждом файле.

Без make

macOS и Linux:

python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python -m pipeline.run --data task/data --out outputs

Windows (PowerShell, не проверялось):

py -3.11 -m venv .venv
.venv\Scripts\pip install -r requirements.txt
.venv\Scripts\python -m pipeline.run --data task/data --out outputs

pipeline.run сам запускает проверку выгрузок; флаг --no-check её отключает.

Интерфейс: API и экран

Сначала make pipeline: API читает outputs/. Без выгрузок API отдаёт заглушку с пометкой mock: true.

Терминал 1, API на порту 8000:

make api

Проверка: curl -s localhost:8000/health → {"status":"ok","mock":false}.

Терминал 2, интерфейс на порту 5173:

cd dai-front
cp .env.example .env.development
npm ci
npm run dev

Без .env.development клиент не знает адрес API. make web копирует файл из .env.example, если его ещё нет. В образце VITE_MOCKS=false, поэтому экран читает рассчитанные CSV через API.

gid для проверки — из первой строки outputs/top_nodes.csv; команда печатает готовый адрес страницы узла:

TOP_GID=$(python3 -c "import csv; print(next(csv.DictReader(open('outputs/top_nodes.csv', encoding='utf-8')))['gid'])")
echo "http://localhost:5173/nodes/$TOP_GID"

Откройте напечатанный адрес или просто http://localhost:5173: на главной странице поле поиска по gid, очередь проверки и схема сети; клик по строке очереди или ввод gid открывает узел. Слева поиск и очередь, в центре окрестность узла (стрелки показывают направление денег, цвет узла — роль, размер — приоритет, обводка — seed и граница выгрузки), справа карточка: роль и выполненные условия правила, приоритет и два факта с наибольшим вкладом, отметка «в очереди проверки», пары переводов со статусом по датам, следующий запрос и ограничения данных. Другой узел: ввести gid в поиск или заменить его в адресе.

Работающий экран и его элементы описаны в dai-front/README.md. Открытие карточки не сбрасывает положение графа.

Те же данные доступны напрямую из API, в том же терминале, где задан TOP_GID:

curl -s "localhost:8000/top?limit=5"
curl -s "localhost:8000/nodes/$TOP_GID"
curl -s "localhost:8000/nodes/$TOP_GID/subgraph?radius=1"

/nodes/{gid} отдаёт карточку с переводами, /subgraph — узлы и направленные рёбра окрестности. Если пайплайн перезапущен при работающем API, curl -X POST localhost:8000/reload перечитывает outputs/. Остальные эндпоинты и переменные окружения — в backend/README.md.

Смена портов

Если 8000 занят, поднимите API на другом порту и направьте на него прокси интерфейса:

.venv/bin/uvicorn backend.app.main:app --port 8001
cd dai-front
API_PROXY_TARGET=http://localhost:8001 npm run dev -- --port 5174

Если занят 5173, Vite сам берёт следующий свободный порт и печатает адрес в строке Local:; в адресе страницы узла тогда нужен этот порт. Кто занял порт: lsof -i :8000 (или :5173). Остановить API и интерфейс — Ctrl+C в их терминалах.

Если нет сети

  • pip: Could not find a version that satisfies the requirement при nodename nor servname provided — это недоступный pypi.org, а не ошибка в requirements.txt. Если зависимости уже есть в кэше uv, помогает uv pip install --offline --python .venv/bin/python -r requirements.txt.
  • npm: ENOTFOUND registry.npmjs.org или EAI_AGAIN — не резолвится имя реестра, это сеть или DNS машины, а не ошибка в package-lock.json. Обход: npm ci --prefer-offline берёт пакеты из локального кэша npm. Он помогает, только если все пакеты из lockfile уже есть в кэше; если какого-то нет, та же ошибка ENOTFOUND повторится, и нужна сеть (или другой DNS-сервер, если связь по IP есть).

Через Docker (альтернатива нативному пути)

Нужен Docker с Compose v2. Из корня репозитория:

docker compose run --rm --build pipeline   # три CSV в outputs/ (образ пересобирается при изменении кода)
docker compose up --build            # экран на http://localhost:8080, API на :8000; остановка — docker compose down

Замер 23.09.2026 на macOS arm64 при уже скачанных базовых образах: сборка образов около 50 с, пересчёт 1,3 с, стек отвечает через 8 с после старта. Первая сборка на чистой машине дополнительно скачивает около 230 МБ (базовые образы и колёса Python) и требует сети, время зависит от канала. Если порты заняты: API_PORT=18000 WEB_PORT=18080 docker compose up --build. При старте API пайплайн пересчитывается заново; в outputs/run_meta.json при этом меняются только поля времени. Сборка проверена на arm64; базовые образы и закреплённые колёса Python есть и для amd64.

Как проверить

Сценарий на чистой машине, 5–10 минут:

  1. make setup && make pipeline → в конце проверок 49, провалено 0 и строка с числом ролей. Время прогона — в строке готово за … s.

  2. wc -l outputs/nodes_roles.csv outputs/clusters.csv outputs/top_nodes.csv → 2249, 90, 51.

  3. Детерминизм: git status --short outputs/ показывает изменённым только outputs/run_meta.json (в нём время запуска и длительность). Три CSV побайтно совпадают с закоммиченными.

  4. Строгая проверка: .venv/bin/python -m pipeline.check --data task/data --out outputs --require-method v1 → проверок 51, провалено 0.

  5. Пять контрольных случаев с ожидаемыми ролями, основаниями и следующим запросом — docs/acceptance.md. Каждый gid вводится в поле поиска на экране (или открывается по адресу http://localhost:5173/nodes/<gid>). Для трёх любых других gid колонки role_checks, evidence, score_terms в outputs/nodes_roles.csv показывают, почему роль именно такая и откуда приоритет. Например, так:

    .venv/bin/python -c "import pandas as pd; d=pd.read_csv('outputs/nodes_roles.csv', dtype={'gid':'int64'}); print(d.sample(3, random_state=1)[['gid','role','role_score','role_checks','evidence']].to_string())"
    
  6. Экран: терминал 1 make api, терминал 2 — команды из раздела Интерфейс, затем страница узла из первой строки outputs/top_nodes.csv (адрес печатает команда с TOP_GID в том же разделе).

  7. Временной признак против случайных дат: .venv/bin/python -m pipeline.temporal_check --data task/data (≈1 с, 1 000 перестановок).

  8. Сравнение с наивными ранжированиями: .venv/bin/python -m pipeline.baselines --data task/data --out outputs (≈1 с). Файлов не пишет, числа — в таблице раздела Как мы себя проверяли.

  9. Проверки выгрузок без разметки (устойчивость топа к шуму, чувствительность ролей к порогам, стабильность кластеров по seed Louvain и другие): make metrics (≈5 с). Успех — последняя строка проверок …; обязательных провалено 0; …; строки WARN — предупреждения, а не провал. Команда перезаписывает outputs/metrics.json (время запуска и замеры), поэтому после неё git status покажет изменённым и его. Смысл проверок — docs/ds_metrics_2026-09-23.md.

gid — 18-значные целые. Excel и Numbers показывают их как 1E+17 и теряют цифры: открывайте CSV в текстовом редакторе или через pandas.read_csv(..., dtype={"gid": "int64"}).

Что на выходе

Все три файла — в outputs/, кодировка UTF-8. Обязательные колонки ТЗ идут первыми, за ними дополнительные.

nodes_roles.csv — 2 248 строк, по одной на узел:

КолонкиСмысл
gid, role, role_score, cluster_id, priority_score, evidenceобязательные по ТЗ
is_seed, depth, in_deg, out_deg, in_kzt, out_kzt, in_tx, out_tx, pass_kzt, pass_through, pagerank, betweenness, n_seed_upstream, active_days, first_date, last_date, truncated_by_depth, flagsпризнаки узла
fast_transit_pairs, fast_transit_flagчисло пар быстрого транзита и флаг (≥ 2 пар)
priority_raw, score_terms, n_terms_above_p95, in_queueсырой скор, два главных вклада, число фактов выше P95, очередь проверки
role_checksусловия правила роли с числами и отметками ✓/✗
next_request, limitationsследующий запрос данных и ограничения данных по узлу
methodv1

clusters.csv — 89 строк:

КолонкиСмысл
cluster_id, n_nodes, n_seed, sum_kzt_internal, top_gids, hypothesisобязательные по ТЗ; top_gids — до 5 gid через ; по убыванию приоритета
n_edges_internal, share_depth4число рёбер внутри кластера, доля узлов глубины 4

top_nodes.csv — 50 строк:

КолонкиСмысл
rank, gid, role, priority_score, whyобязательные по ТЗ
cluster_id, priority_raw, score_terms, in_queueкластер, сырой скор, главные вклады, очередь

run_meta.json — параметры прогона: пороги, порядок ролей, число узлов по ролям, параметры Louvain, правило очереди, время по стадиям, версии библиотек.

check.py проверяет схему и согласованность выгрузок с parquet: колонки и их порядок, 2 248 уникальных gid из nodes.parquet, роли из словаря, role_score и priority_score в [0; 1], evidence непустой, с числом и не длиннее 200 символов, ни один узел глубины 4 не terminal, суммы узлов и seed по кластерам, top_gids внутри своего кластера, в топе не меньше 20 строк и приоритет не растёт, in_queue сходится с run_meta.json.

Как мы себя проверяли

Почему этим числам можно верить и как это проверить самому:

  • Ни одно число не сгенерировано моделью. Роли, кластеры, приоритет, обоснования и гипотезы считает код в pipeline/ из трёх parquet; языковые модели в расчёте не участвуют, внешних данных нет. Тексты evidence, why, hypothesis и «что запросить» — шаблоны, в которые подставляются рассчитанные значения.

  • Каждая роль — опубликованное правило с порогом. У каждого из 2 248 узлов колонка role_checks показывает, какие условия правила выполнены и с какими числами; пороги — в pipeline/rules.py и в таблице выше, в outputs/run_meta.json они же записаны на момент прогона.

  • Каждое число воспроизводимо командой. make pipeline пересчитывает всё за секунды и даёт байт в байт те же CSV; make check — 49 проверок схемы и согласованности (51 с --require-method v1); make metrics — 51 проверка качества без разметки в outputs/metrics.json (устойчивость кластеров к seed и resolution, устойчивость топ-20 к шуму ±5 % и к исключению каждого признака, перестановочный контроль временного флага, сравнение с наивными ранжированиями); make baselines — сравнение с dummy-моделями; .venv/bin/python -m pipeline.temporal_check --data task/data — перестановочный контроль.

  • Отрицательные результаты опубликованы. Гипотеза «платит раньше, чем получает» и признак «тихий связной» проверены и в скор не вошли (docs/hypothesis_check_2026-09-23.md, docs/ds_system_design_2026-09-23.md); что именно и почему — ниже и в этих документах.

  • Чего проверить нельзя. Разметки ролей в данных нет, поэтому точность как в задачах с ответами не измеряется; всё, что выше, — проверки устойчивости, честности и объяснимости, а не доказательство реальной роли клиента.

  • Гейт выгрузок. 49 проверок pipeline/check.py после каждого прогона, 51 с --require-method v1; все проходят. Ожидаемые числа (узлы, seed, оборот) гейт берёт из parquet, а не из констант.

  • Детерминизм. Повторный прогон и прогон на чистой копии репозитория с новым .venv дают побайтно те же три CSV, что закоммичены. Louvain запускается с seed 42, сортировки стабильные.

  • Граница выгрузки. 0 из 444 узлов глубины 4 получили роль terminal (441 — peripheral, 3 — consolidator). Наивное правило «нет исходящих ⇒ конечный получатель» дало бы 444 ложных terminal.

  • Быстрый транзит против случайных дат. pipeline/temporal_check.py 1 000 раз переставляет даты переводов двумя способами: по всей выгрузке и внутри отправителя (сохраняет активность каждого отправителя). Флаг получают 54 узла против 34,1 и 38,2 в среднем при перестановках, p = 0,001. Поэтому признак вошёл в приоритет флагом с весом 1,0. Гипотезу «узел платит раньше, чем получает» мы проверили так же: 45 узлов против 38,4 и 40,5 при перестановках, p = 0,054 и 0,167. Это не отличается от случайного, и в приоритет признак не вошёл. По разбору в docs/hypothesis_check_2026-09-23.md около половины флагов быстрого транзита появляются и на случайных датах у столь же активных узлов, поэтому число пар как непрерывный признак не используется.

  • Сравнение с наивными ранжированиями (pipeline/baselines.py, снятие топ-N узлов, случайный порядок — медиана 20 повторов):

    РанжированиеДоля оборота на снятых узлах, топ-10 / 20 / 50Крупнейшая компонента после снятия (из 1 877)
    наш priority_score25,5 % / 35,1 % / 51,6 %1 456 / 1 243 / 930
    по обороту28,6 % / 37,7 % / 56,3 %1 466 / 1 376 / 1 034
    по числу контрагентов23,1 % / 30,3 % / 46,7 %1 428 / 1 188 / 620
    PageRank стартового кода6,0 % / 7,2 % / 12,9 %1 846 / 1 834 / 1 749
    случайный0,7 % / 1,6 % / 4,6 %1 863,5 / 1 845 / 1 792

    Наш скор лучше случайного порядка и PageRank по обоим исходам. Ранжирование по обороту снимает больше оборота, по числу контрагентов сильнее дробит сеть: скор — компромисс между ними, а не победитель по каждому исходу. Кластеры: модулярность 0,859 против 0,125 у слабосвязных компонент и около 0 у случайного разбиения тех же размеров. Эти исходы косвенные: меток ролей в данных нет, и «лучше наивного» не означает «правильно».

Данные и интеграции

Только файлы организаторов в task/data/ (описание полей — task/README.md). Внешних источников, обогащения, LLM и ключей нет. Интернет нужен только для установки зависимостей.

API (backend/) читает outputs/*.csv и task/data/*.parquet; пути меняются переменными DAI_OUTPUTS_DIR и DAI_DATA_DIR. Интерфейс получает данные только из API.

Ограничения

Ограничения данных, объявленные в ТЗ, и как они учтены:

  • Обрыв на 4-м колене: у 444 узлов исходящие не собирались. Они не получают роль terminal, их исходящие вклады в приоритет обнулены, в next_request — запрос исходящих.
  • Только исходящий обход: у 81 seed входящие суммы занижены. Отношение выход/вход у seed не используется, в evidence написано «входы неполны».
  • Переводы меньше 5 000 KZT в выгрузку не попали: дробление ниже порога не видно.
  • 19 seed без рёбер — изоляты, отдельные кластеры и роль peripheral с пометкой «переводов в выгрузке нет».
  • Даты с точностью до дня: порядок переводов внутри дня неизвестен, лаг 0 означает «в тот же день».
  • Атрибутов клиентов и разметки ролей нет, поэтому оценка — по обоснованности правил, а не по точности.

Ограничения подхода:

  • Пороги ролей выбраны по квантилям распределений этой выгрузки, а не обучены; на другой выгрузке их нужно пересчитать.
  • Роль одна на узел: узел, подходящий под несколько правил, получает первую по ROLE_ORDER. В role_checks записаны условия только назначенной роли, у peripheral — ближайшая роль и её поддержка.
  • Роли описывают видимые направления переводов. Они не устанавливают, кто распоряжается счетом и кому принадлежат деньги после поступления.
  • Кластеры — сообщества переводов, а не доказанные группы; Louvain на другом seed даёт близкое, но не идентичное разбиение.
  • Приоритет ранжирует необычность узла среди этих 2 248, а не вероятность нарушения. Факты коррелируют (оборот и число контрагентов растут вместе), поэтому сумма вкладов частично учитывает одно и то же дважды.
  • Экран показывает окрестность узла и очередь проверки. В карточке есть список переводов; шкала времени работает по переводам уже открытых карточек. Отдельная карта групп по кластерам пока не реализована.

Масштабирование до ~1 млн узлов

Текущий расчёт занимает 1,8 с, из них 1,0 с — точный betweenness. При росте до миллиона узлов изменится:

  • Граф. networkx → igraph или networkit. Точный betweenness растёт как произведение числа узлов и рёбер, поэтому нужна выборочная оценка по k источникам.
  • Кластеры. Louvain → Leiden (гарантирует связность сообществ), при необходимости по компонентам параллельно.
  • Таблицы. pandas → polars или DuckDB с чтением parquet по партициям. Приоритет считается по перцентилям признаков и переносится как есть: нужны только ранги по каждому признаку.
  • Временной слой. Сопоставление пар вход→выход уже векторизовано по узлам; на полном потоке — окном по датам и по партициям отправителей.
  • Хранение и API. Выгрузки → Postgres или графовая БД; API отдаёт окрестности узла и агрегаты кластеров, а не граф целиком; пересчёт — только компонент, в которых появились новые переводы.
  • Интерфейс. Схема сети показывает окрестность выбранного узла и кластера, а не всю сеть.

Раскрытие ранее созданного (п. 6.4)

  • task/ — материалы организаторов, включая стартовый код task/starter/; не изменялись. Загрузка в pipeline/load.py повторяет логику task/starter/starter.py.
  • Каркас интерфейса dai-front/ (коммиты front-setup и front-docs), каталог .claude/skills и файлы CLAUDE.md созданы до старта как шаблон стека. Скилы shadcn и TanStack — сторонние, официальные от авторов библиотек.
  • Всё остальное — пайплайн pipeline/, API backend/, экраны кейса, документы docs/, этот README — написано 23.09.2026, в день хакатона.

Структура репозитория

ПутьНазначение
task/ТЗ, данные и стартовый код организаторов, без изменений
pipeline/анализ графа и генерация CSV: run.py (вход), rules.py (пороги), roles_v1.py, priority.py, temporal.py, clusters.py, evidence.py, export.py, check.py (гейт), temporal_check.py, baselines.py и metrics.py (проверки)
outputs/итоговые nodes_roles.csv, clusters.csv, top_nodes.csv, run_meta.json; metrics.json — отчёт make metrics
backend/API на FastAPI для интерфейса; запуск и эндпоинты
dai-front/интерфейс на React; запуск, переменные окружения, стек
claude-design/, design-outputs/макеты интерфейса из Claude Design; в design-outputs/ — доработанный движок графа и самостоятельный просмотрщик на D3 + SVG (как открыть); рабочий интерфейс — dai-front/
docs/гипотезы и их проверка: временной признак, смежные работы, сценарий аналитика, порядок переводов, контрольные случаи, проверки без разметки, устройство системы
Makefilesetup, pipeline, check, metrics, baselines (пишет outputs/baselines.json, в git его нет), api, web, contract
requirements.txtзависимости пайплайна и API с закреплёнными версиями

Стартовый код организаторов можно запустить отдельно, его вывод не входит в сдачу:

.venv/bin/python task/starter/starter.py --data task/data --out scratch/starter

Развёрнутая версия

Нет. Решение запускается локально по шагам выше.

Звёзды
⭐ 1
Форки
0
Язык
HTML
Последний push
в прошлом месяце
Коммиты
98
Авторы
3
Файлы
248
Ветки
1

Авторы коммитов

Ivan Kononov 46Amir Zhakyshev 29dinmukhamed 23

История коммитов

  • 2026-09-23 17:54README: concept illustration updatedIvan Kononov
  • 2026-09-23 17:53Remove internal day plan and stale handoff referencesAmir Zhakyshev
  • 2026-09-23 17:52README: overview screenshot replaced with pngIvan Kononov
  • 2026-09-23 17:51Record repository cleanup before submissionAmir Zhakyshev
  • 2026-09-23 17:48README images updatedIvan Kononov
  • 2026-09-23 17:48README: updated concept illustrationIvan Kononov
  • 2026-09-23 17:46Record pre-submission clean-clone acceptanceAmir Zhakyshev
  • 2026-09-23 17:45Remove the close button from the node carddinmukhamed
Все коммиты (98)
  • 2026-09-23 17:44README: coordinator example uses coordinator.jpgIvan Kononov
  • 2026-09-23 17:43Dark workspace, red queue heading, collapsible node carddinmukhamed
  • 2026-09-23 17:43README: coordinator neighbourhood example and legend of node classesIvan Kononov
  • 2026-09-23 17:43Label concept artwork as illustrativeAmir Zhakyshev
  • 2026-09-23 17:42README: concept illustration at the topIvan Kononov
  • 2026-09-23 17:41README: concept illustration at the topIvan Kononov
  • 2026-09-23 17:39Final: remove team handoff notes before submissionIvan Kononov
  • 2026-09-23 17:39README: remove the concept illustration (a new one goes at the top)Ivan Kononov
  • 2026-09-23 17:34README title: team DAI firstIvan Kononov
  • 2026-09-23 17:32Name the tool «Координатор казны»; README: why the numbers can be trusted and how to re-check each oneIvan Kononov
  • 2026-09-23 17:29Freeze fixes: substring gid search, Python version guard in make setup, page title, README notes on Docker rebuild and run_metaIvan Kononov
  • 2026-09-23 17:27Plan of the day marked archived; handoff notes referenced there are removed before submissionIvan Kononov
  • 2026-09-23 17:23Add Claude Design mockups and the standalone graph viewerdinmukhamed
  • 2026-09-23 17:21Show card and queue explanations in plain Russiandinmukhamed
  • 2026-09-23 17:20Default to the node neighbourhood with depth 3dinmukhamed
  • 2026-09-23 17:19Cluster hypothesis states a purpose to verify; peripheral role_checks wording without misleading support numberIvan Kononov
  • 2026-09-23 17:16Open the node neighbourhood automatically when a card opensdinmukhamed
  • 2026-09-23 17:16README: working features no longer marked as planned; backend README run block matches rootIvan Kononov
  • 2026-09-23 17:16Restore gid search on the screen: required by must-have 5 and described in READMEIvan Kononov
  • 2026-09-23 17:15Record final clone checks and current UI stateAmir Zhakyshev
  • 2026-09-23 17:15Fix graph crash on cluster filter, legend highlight, info button, keep user zoomdinmukhamed
  • 2026-09-23 17:12README: resolve merge markers in quick startIvan Kononov
  • 2026-09-23 17:11Docker path: compose with pipeline/api/web, verified from scratchIvan Kononov
  • 2026-09-23 17:07Non-modal reference sheet, drop the gid search block, bolder queue titledinmukhamed
  • 2026-09-23 17:05Document Python 3.14 setup failure and supported versionsAmir Zhakyshev
  • 2026-09-23 17:03Use real API data in the documented frontend setupAmir Zhakyshev
  • 2026-09-23 17:03Preserve card visibility after workspace route refactorAmir Zhakyshev
  • 2026-09-23 17:03Open a node reference sheet from the legenddinmukhamed
  • 2026-09-23 17:03README: main page shows search, queue and network; node opens on clickIvan Kononov
  • 2026-09-23 17:02Handoff: manual e2e test protocol for Amir and submission protocolIvan Kononov
  • 2026-09-23 17:00Keep graph state across mode switches and card open/close; role shapes and arrowheadsdinmukhamed
  • 2026-09-23 16:58README: analyst scenario concept illustrationIvan Kononov
  • 2026-09-23 16:58make web: create .env.development from the example if missingIvan Kononov
  • 2026-09-23 16:55README: full rewrite per organizer checklist and case spec, verified from a clean cloneIvan Kononov
  • 2026-09-23 16:54Add role legend tooltips and role shape iconsdinmukhamed
  • 2026-09-23 16:52Explain priority scale in analyst cardAmir Zhakyshev
  • 2026-09-23 16:51Keep analyst card visible on 1280px screensAmir Zhakyshev
  • 2026-09-23 16:48Record frontend build and pending visual acceptanceAmir Zhakyshev
  • 2026-09-23 16:47Add screenshots of the node screen (neighborhood, overview, zoom)Ivan Kononov
  • 2026-09-23 16:45Use observable descriptions for analyst rolesAmir Zhakyshev
  • 2026-09-23 16:44Add network graph and wire the node screendinmukhamed
  • 2026-09-23 16:41Show review queue, rule checks, priority terms and transfer pairs on the node screendinmukhamed
  • 2026-09-23 16:37Add screen checks for queue and next requestAmir Zhakyshev
  • 2026-09-23 16:36Add DS module: metrics/validation without labels, system design and metrics docsIvan Kononov
  • 2026-09-23 16:34Record CSV acceptance checksAmir Zhakyshev
  • 2026-09-23 16:31Backend: method and queue size fall back to CSV when run_meta.json is absent; commit run_meta.jsonIvan Kononov
  • 2026-09-23 16:30Document review queue and verified acceptance checksAmir Zhakyshev
  • 2026-09-23 16:28Add node card for the node screendinmukhamed
  • 2026-09-23 16:28Add header, gid search and top-20 list for the node screendinmukhamed
  • 2026-09-23 16:26Analyst wording: next_request texts from acceptance, terminal as 'получатель без видимых исходящих', legend descriptionsIvan Kononov
  • 2026-09-23 16:26Plan: rollout schedule 16:30-18:00, code freeze 16:45, Docker dropped from submissionIvan Kononov
  • 2026-09-23 16:24Add node screen foundation: d3, role color tokens, formatters, graph view storedinmukhamed
  • 2026-09-23 16:23Record verified pipeline runtime and check countAmir Zhakyshev
  • 2026-09-23 16:22Pipeline v1: role_score as rule support, explicit review-queue rule, coordinator seed thresholdIvan Kononov
  • 2026-09-23 16:22Add analyst copy and acceptance cases from actual CSVAmir Zhakyshev
  • 2026-09-23 16:21Add pipeline/position.py: cluster-relative position and regularity features (negative result: quiet-bridge flag reduces to degree; README-only)Ivan Kononov
  • 2026-09-23 16:17Handoff: screen brief for the frontend (jury checks, cluster map story, demo script)Ivan Kononov
  • 2026-09-23 16:14Handoff for the frontend: v1 card fieldsIvan Kononov
  • 2026-09-23 16:13Pipeline v1: role rules with thresholds, single priority score, temporal layer, card contractIvan Kononov
  • 2026-09-23 16:04Add pipeline/baselines.py: our ranking, roles and clusters vs dummy baselines on proxy outcomesIvan Kononov
  • 2026-09-23 16:01Add frontend design decisions: screens, network graph, role colorsdinmukhamed
  • 2026-09-23 16:01Prepare frontend data layer: node route, graph view store, error statesdinmukhamed
  • 2026-09-23 16:00Add pipeline v0: parquet -> three CSV in ~2 s, schema gate, MakefileIvan Kononov
  • 2026-09-23 15:52Document equal-amount inflow pattern and dataset limitsAmir Zhakyshev
  • 2026-09-23 15:50Add plain-language task note for Amir; move temporal_check.py to IvanIvan Kononov
  • 2026-09-23 15:48Update frontend README: run with the backend, API contract, mocksdinmukhamed
  • 2026-09-23 15:44Plan: restore time convention and paths note in the headerIvan Kononov
  • 2026-09-23 15:43Plan: start 13:00 and deadline 18:00 confirmedIvan Kononov
  • 2026-09-23 15:42Add execution plan for the rest of the day and the research requestIvan Kononov
  • 2026-09-23 15:36Analyze hidden obligations behind AML transfersAmir Zhakyshev
  • 2026-09-23 15:29Run the backend from the repository rootIvan Kononov
  • 2026-09-23 15:27Pin scipy in backend requirements: nx.pagerank needs it on a clean installIvan Kononov
  • 2026-09-23 15:24Audit AML concept against four strategy frameworksAmir Zhakyshev
  • 2026-09-23 15:17Ground AML strategy in analyst workflow bottleneckAmir Zhakyshev
  • 2026-09-23 15:16Check the temporal hypothesis on data and survey related workIvan Kononov
  • 2026-09-23 15:12Add handoff note for the frontend: API contract, run steps, screen fieldsIvan Kononov
  • 2026-09-23 15:09Center AML JTBD on analyst investigation stepsAmir Zhakyshev
  • 2026-09-23 15:05Map AML analyst job and dataset constraintsAmir Zhakyshev
  • 2026-09-23 15:01Add backend API contract with mock data for the frontendIvan Kononov
  • 2026-09-23 14:54Frame temporal hypothesis as an investigative decisionAmir Zhakyshev
  • 2026-09-23 14:48Reframe hypothesis around temporal settlement motifsAmir Zhakyshev
  • 2026-09-23 14:39readme-rulesdinmukhamed
  • 2026-09-23 14:36State testable temporal network hypothesisAmir Zhakyshev
  • 2026-09-23 14:32Document AML hypothesis for data and UIAmir Zhakyshev
  • 2026-09-23 14:26ignore .idea of my workspacedinmukhamed
  • 2026-09-23 14:18Clarify limits of temporal AML research methodsAmir Zhakyshev
  • 2026-09-23 14:00Document temporal route research for AML graph reviewAmir Zhakyshev
  • 2026-09-23 13:52Add official case materials and team workspaceIvan Kononov
  • 2026-09-23 13:43front-docsdinmukhamed
  • 2026-09-23 13:34front-setupdinmukhamed
Структура репозитория (248 файлов)
.claude/skills/api-layer/SKILL.md
.claude/skills/client-state/SKILL.md
.claude/skills/forms/SKILL.md
.claude/skills/router-core/SKILL.md
.claude/skills/router-core/auth-and-guards/SKILL.md
.claude/skills/router-core/code-splitting/SKILL.md
.claude/skills/router-core/data-loading/SKILL.md
.claude/skills/router-core/navigation/SKILL.md
.claude/skills/router-core/not-found-and-errors/SKILL.md
.claude/skills/router-core/path-params/SKILL.md
.claude/skills/router-core/search-params/SKILL.md
.claude/skills/router-core/search-params/references/validation-patterns.md
.claude/skills/router-core/ssr/SKILL.md
.claude/skills/router-core/type-safety/SKILL.md
.claude/skills/router-plugin/SKILL.md
.claude/skills/shadcn/SKILL.md
.claude/skills/shadcn/agents/openai.yml
.claude/skills/shadcn/assets/shadcn-small.png
.claude/skills/shadcn/assets/shadcn.png
.claude/skills/shadcn/cli.md
.claude/skills/shadcn/customization.md
.claude/skills/shadcn/evals/evals.json
.claude/skills/shadcn/mcp.md
.claude/skills/shadcn/registry.md
.claude/skills/shadcn/rules/base-vs-radix.md
.claude/skills/shadcn/rules/chat.md
.claude/skills/shadcn/rules/composition.md
.claude/skills/shadcn/rules/forms.md
.claude/skills/shadcn/rules/icons.md
.claude/skills/shadcn/rules/styling.md
.claude/skills/tailwind-v4/SKILL.md
.dockerignore
.gitignore
CLAUDE.md
Makefile
README.md
backend/README.md
backend/__init__.py
backend/app/__init__.py
backend/app/data.py
backend/app/main.py
backend/app/schemas.py
backend/export_openapi.py
backend/requirements.txt
claude-design/.thumbnail
claude-design/dai-api.js
claude-design/money-flow.js
claude-design/money-graph.js
claude-design/support.js
claude-design/uploads/BRIEF.md
claude-design/uploads/HackAlem_AI_Граф_денег_восстановление_финансовой_структуры_организованной.md
claude-design/uploads/aml_money_flow_d3_layered.html
claude-design/uploads/dai-design-pack/BRIEF.md
claude-design/uploads/dai-design-pack/data/01_meta.json
claude-design/uploads/dai-design-pack/data/02_top20.json
claude-design/uploads/dai-design-pack/data/03_clusters.json
claude-design/uploads/dai-design-pack/data/04_search_prefix.json
claude-design/uploads/dai-design-pack/data/05_coordinator_card.json
claude-design/uploads/dai-design-pack/data/06_coordinator_subgraph_r1.json
claude-design/uploads/dai-design-pack/data/07_transit_card.json
claude-design/uploads/dai-design-pack/data/08_transit_subgraph_r1.json
claude-design/uploads/dai-design-pack/data/09_truncated_depth4_card.json
claude-design/uploads/dai-design-pack/data/10_isolated_seed_card.json
claude-design/uploads/dai-design-pack/data/11_cluster_small.json
claude-design/uploads/dai-design-pack/data/12_errors.json
claude-design/Граф денег.dc.html
claude-design/Запуск и устойчивость.dc.html
claude-design/Карточка узла.dc.html
claude-design/Кластеры.dc.html
claude-design/Компоненты и состояния.dc.html
claude-design/Обзор сети.dc.html
claude-design/Перечень на проверку.dc.html
claude-design/Рабочее место.dc.html
claude-design/Схема потока D3.dc.html
dai-front/.claude/settings.json
dai-front/.env.example
dai-front/.gitignore
dai-front/.npmrc
dai-front/.nvmrc
dai-front/.oxlintrc.json
dai-front/CLAUDE.md
dai-front/DESIGN.md
dai-front/README.md
dai-front/SETUP.md
dai-front/components.json
dai-front/index.html
dai-front/openapi-ts.config.ts
dai-front/openapi.json
dai-front/package-lock.json
dai-front/package.json
dai-front/public/favicon.svg
dai-front/public/mockServiceWorker.js
dai-front/src/client/@tanstack/react-query.gen.ts
dai-front/src/client/client.gen.ts
dai-front/src/client/client/client.gen.ts
dai-front/src/client/client/index.ts
dai-front/src/client/client/types.gen.ts
dai-front/src/client/client/utils.gen.ts
dai-front/src/client/core/auth.gen.ts
dai-front/src/client/core/bodySerializer.gen.ts
dai-front/src/client/core/params.gen.ts
dai-front/src/client/core/pathSerializer.gen.ts
dai-front/src/client/core/queryKeySerializer.gen.ts
dai-front/src/client/core/serverSentEvents.gen.ts
dai-front/src/client/core/types.gen.ts
dai-front/src/client/core/utils.gen.ts
dai-front/src/client/index.ts
dai-front/src/client/msw.gen.ts
dai-front/src/client/sdk.gen.ts
dai-front/src/client/types.gen.ts
dai-front/src/client/zod.gen.ts
dai-front/src/components/app-header.tsx
dai-front/src/components/gid-search.tsx
dai-front/src/components/graph/graph-panel.tsx
dai-front/src/components/graph/graph-settings.tsx
dai-front/src/components/graph/graph-timeline.tsx
dai-front/src/components/graph/money-graph.ts
dai-front/src/components/node-card.tsx
dai-front/src/components/node-card/insights.tsx
dai-front/src/components/node-card/pairs.tsx
dai-front/src/components/node-card/parts.tsx
dai-front/src/components/role-icon.tsx
dai-front/src/components/role-legend.tsx
dai-front/src/components/top-list.tsx
dai-front/src/components/ui/badge.tsx
dai-front/src/components/ui/button.tsx
dai-front/src/components/ui/card.tsx
dai-front/src/components/ui/dialog.tsx
dai-front/src/components/ui/field.tsx
dai-front/src/components/ui/input.tsx
dai-front/src/components/ui/label.tsx
dai-front/src/components/ui/select.tsx
dai-front/src/components/ui/separator.tsx
dai-front/src/components/ui/sheet.tsx
dai-front/src/components/ui/skeleton.tsx
dai-front/src/components/ui/sonner.tsx
dai-front/src/components/ui/tooltip.tsx
dai-front/src/env.d.ts
dai-front/src/index.css
dai-front/src/lib/api-error.ts
dai-front/src/lib/api.ts
dai-front/src/lib/format.ts
dai-front/src/lib/graph-data.ts
dai-front/src/lib/query-client.ts
dai-front/src/lib/roles.ts
dai-front/src/lib/utils.ts
dai-front/src/main.tsx
dai-front/src/mocks/browser.ts
dai-front/src/routeTree.gen.ts
dai-front/src/routes/__root.tsx
dai-front/src/routes/_workspace.tsx
dai-front/src/routes/_workspace/index.tsx
dai-front/src/routes/_workspace/nodes.$gid.tsx
dai-front/src/stores/auth.ts
dai-front/src/stores/graph-view.ts
dai-front/tsconfig.app.json
dai-front/tsconfig.json
dai-front/tsconfig.node.json
dai-front/vite.config.ts
design-outputs/.thumbnail
design-outputs/README.md
design-outputs/dai-api.js
design-outputs/explorer.css
design-outputs/explorer.js
design-outputs/index.html
design-outputs/money-flow.js
design-outputs/money-graph.js
design-outputs/support.js
design-outputs/uploads/BRIEF.md
design-outputs/uploads/HackAlem_AI_Граф_денег_восстановление_финансовой_структуры_организованной.md
design-outputs/uploads/aml_money_flow_d3_layered.html
design-outputs/uploads/dai-design-pack/BRIEF.md
design-outputs/uploads/dai-design-pack/data/01_meta.json
design-outputs/uploads/dai-design-pack/data/02_top20.json
design-outputs/uploads/dai-design-pack/data/03_clusters.json
design-outputs/uploads/dai-design-pack/data/04_search_prefix.json
design-outputs/uploads/dai-design-pack/data/05_coordinator_card.json
design-outputs/uploads/dai-design-pack/data/06_coordinator_subgraph_r1.json
design-outputs/uploads/dai-design-pack/data/07_transit_card.json
design-outputs/uploads/dai-design-pack/data/08_transit_subgraph_r1.json
design-outputs/uploads/dai-design-pack/data/09_truncated_depth4_card.json
design-outputs/uploads/dai-design-pack/data/10_isolated_seed_card.json
design-outputs/uploads/dai-design-pack/data/11_cluster_small.json
design-outputs/uploads/dai-design-pack/data/12_errors.json
design-outputs/Граф денег.dc.html
design-outputs/Запуск и устойчивость.dc.html
design-outputs/Карточка узла.dc.html
design-outputs/Кластеры.dc.html
design-outputs/Компоненты и состояния.dc.html
design-outputs/Обзор сети.dc.html
design-outputs/Перечень на проверку.dc.html
design-outputs/Рабочее место.dc.html
design-outputs/Схема потока D3.dc.html
docker-compose.yml
docker/Dockerfile.backend
docker/Dockerfile.frontend
docker/nginx.conf
docs/.gitkeep
docs/acceptance.md
docs/aml_analyst_ajtbd.md
docs/deep_research_request_2026-09-23.md
docs/ds_metrics_2026-09-23.md
docs/ds_system_design_2026-09-23.md
docs/hypothesis_check_2026-09-23.md
docs/hypothesis_ivan_din.md
docs/img/coordinator.jpg
docs/img/graph_money.png
docs/img/screen_node_neighborhood.jpg
docs/img/screen_node_zoom.jpg
docs/img/screen_overview.png
docs/related_work_2026-09-23.md
docs/steganography_aml_gap.md
docs/strategy_aml_four_checks.md
docs/temporal_research.md
outputs/.gitkeep
outputs/clusters.csv
outputs/metrics.json
outputs/nodes_roles.csv
outputs/run_meta.json
outputs/top_nodes.csv
pipeline/.gitkeep
pipeline/__init__.py
pipeline/baselines.py
pipeline/check.py
pipeline/clusters.py
pipeline/evidence.py
pipeline/export.py
pipeline/features.py
pipeline/load.py
pipeline/metrics.py
pipeline/position.py
pipeline/priority.py
pipeline/roles_v0.py
pipeline/roles_v1.py
pipeline/rules.py
pipeline/run.py
pipeline/temporal.py
pipeline/temporal_check.py
requirements.txt
skills-lock.json
task/HackAlem_AI_Граф_денег_восстановление_финансовой_структуры_организованной.md
task/README.md
task/data/edges.parquet
task/data/nodes.parquet
task/data/transactions.parquet
task/starter/README.md
task/starter/requirements.txt
task/starter/starter.py

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.