О проекте
Команда: 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.mdDAI — «Координатор казны»: роли и приоритеты проверки в сети переводов (кейс «Граф денег»)

Это макет, а не снимок работающего интерфейса. Его содержимое условное; проверяемые результаты приведены ниже и в 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 млн узлов
- Раскрытие ранее созданного (п. 6.4)
- Структура репозитория
- Развёрнутая версия
Краткое описание
Правоохранительные органы передали банку 81 клиента (seed), ранее выявленных как участники незаконного оборота наркотиков. Банк выгрузил исходящие переводы от них на 4 колена: 2 248 клиентов, 3 119 пар плательщик→получатель, 4 840 переводов на 365 890 012 KZT за июль 2026. Аналитику финмониторинга нужно решить, кого из 2 248 клиентов проверять первым, почему и какие данные запросить следующими.
Решение для аналитика без ML-подготовки: каждому клиенту назначаются роль по опубликованному правилу с порогами, кластер и приоритет проверки, а рядом пишется обоснование с числами. Всё это гипотезы для проверки, а не утверждения о виновности: роль «консолидатор» означает «есть признаки консолидации средств».
Что реализовано
Пять обязательных пунктов ТЗ (§7):
| № | Пункт ТЗ | Где | Как проверить |
|---|---|---|---|
| 1 | Воспроизводимый пайплайн от parquet до трёх CSV | pipeline/run.py, make pipeline | одна команда, ≈2 с, гейт проверок 49, провалено 0 |
| 2 | Роль, role_score и evidence у каждого узла | outputs/nodes_roles.csv | 2 248 строк, все обязательные колонки заполнены, evidence с числами ≤ 200 символов |
| 3 | Критерии ролей задокументированы | pipeline/rules.py, pipeline/roles_v1.py, раздел Критерии ролей | колонка role_checks у любого gid показывает, какие условия правила выполнены и с какими числами |
| 4 | Кластеризация | pipeline/clusters.py, outputs/clusters.csv | 89 кластеров, 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 узлов и считает остаток крупнейшей компоненты и оборота против наивных ранжирований.
Как работает
Сценарий аналитика:
- Аналитик получает 81 известный
gidи выгрузку переводов на 4 колена (task/data/). - Одна команда
make pipelineприсваивает каждому из 2 248 узлов роль, кластер и приоритет, пишет обоснование и проверяет выгрузки. - Аналитик открывает
outputs/top_nodes.csvили экран: первые строки топа — узлы, у которых не меньше двух фактов о переводах попадают в 5 % самых заметных. - По
gidоткрывает карточку: роль и выполненные условия правила (role_checks), приоритет и два факта с наибольшим вкладом, быстрый транзит, ограничения данных по узлу и следующий запрос данных. - Решает, кого проверять первым, и какие данные запросить в банке.
Экран (снимки 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:
load.pyчитает три parquet и сверяет их между собой: 2 248 узлов, 3 119 рёбер, 4 840 переводов, 81 seed, 19 изолятов, оборот 365 890 012 KZT.features.pyстроит направленный граф и считает признаки узла: число разных плательщиков и получателей (in_deg,out_deg), входящий и исходящий оборот, сквозную суммуpass_kzt = min(вход, выход), betweenness, PageRank, число seed, от которых узел достижим (n_seed_upstream), глубину и флаги неполноты.temporal.pyсопоставляет входящие и исходящие переводы узла один к одному и ставит флаг быстрого транзита.clusters.pyделит сеть на кластеры: Louvain (seed 42, resolution 1,0) на ненаправленной проекции, где вес пары — сумма переводов в обе стороны. Несвязные части сообщества разделяются, изоляты идут отдельными кластерами.roles_v1.pyназначает роль по правилам и порогам изrules.py.priority.pyсчитает единый приоритет и очередь проверки.evidence.pyпишетevidence,why, гипотезу кластера,next_requestиlimitations.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 ≥ 2 | 54 |
distributor | веер выходов (fan-out) | out_deg ≥ 10 | 29 |
consolidator | сходимость входов (fan-in) | in_deg ≥ 3 | 144 |
transit | пропускает средства дальше | in_kzt > 0 и out_kzt > 0 и (выход/вход ∈ [0,8; 1,2] у не-seed или быстрый транзит, не меньше 2 пар) | 61 |
terminal | получатель без видимых исходящих | in_deg ≥ 1 и out_deg = 0 и глубина < 4 и не seed | 1 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_deg | 3 | in_deg: P90/P95/P99 = 2/3/6; 91,1 % узлов ниже 3 |
coordinator_min_out_deg | 5 | out_deg: P90/P95/P99 = 3/5/23,5; 94,2 % узлов ниже 5 |
coordinator_min_seed_upstream | 3 | n_seed_upstream: P25 = 1, P50 = P75 = 7, P90 = 9; 28,9 % узлов ниже 3 (при ≥2 было 27,3 %); у всех 54 координаторов ≥ 6, так что 2→3 никого не отсекает |
coordinator_betweenness_q | 0.99 | альтернативная ветка: betweenness ≥ P99 среди узлов |
coordinator_betweenness_min_deg | 2 | |
distributor_min_out_deg | 10 | out_deg ≈ P97 (97,2 % узлов ниже 10) |
consolidator_min_in_deg | 3 | in_deg P95 |
transit_ratio_low | 0.8 | out_kzt/in_kzt ∈ [0,8; 1,2] (72 узла) или быстрый транзит |
transit_ratio_high | 1.2 | |
terminal_min_in_deg | 1 | in_deg P5 < 1: 1,9 % узлов без входов |
terminal_max_depth_exclusive | 4 | глубина 4 — граница выгрузки, исходящие не собирались |
peripheral_score | 0.3 | только v0: role_score периферии фиксирован; в v1 — 1 − макс. поддержка других ролей |
coordinator_in_norm | 6 | только v0 (запасной метод) |
coordinator_out_norm | 10 | только v0 (запасной метод) |
distributor_out_norm | 25 | только v0 (запасной метод) |
consolidator_in_norm | 8 | только v0 (запасной метод) |
terminal_score | 0.5 | только v0 (запасной метод) |
priority_w_pagerank | 0.5 | только v0 (запасной метод) |
priority_w_degree | 0.4 | только v0 (запасной метод) |
priority_w_seed | 0.1 | только v0 (запасной метод) |
ROLE_ORDER | coordinator > distributor > consolidator > transit > terminal > peripheral | первая сработавшая роль |
PRIORITY_THRESHOLD_RAW | 6 | справочный порог суммы, не очередь |
QUEUE_MIN_TERMS_ABOVE_P95 | 2 | очередь: столько признаков в верхних 5 % |
TERM_P95_CONTRIBUTION | 2.9957 | вклад признака в верхних 5 %: −ln 0,05 |
FAST_TRANSIT_WEIGHT | 1 | добавка к 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 |
| API | FastAPI 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 минут:
-
make setup && make pipeline→ в концепроверок 49, провалено 0и строка с числом ролей. Время прогона — в строкеготово за … s. -
wc -l outputs/nodes_roles.csv outputs/clusters.csv outputs/top_nodes.csv→ 2249, 90, 51. -
Детерминизм:
git status --short outputs/показывает изменённым толькоoutputs/run_meta.json(в нём время запуска и длительность). Три CSV побайтно совпадают с закоммиченными. -
Строгая проверка:
.venv/bin/python -m pipeline.check --data task/data --out outputs --require-method v1→проверок 51, провалено 0. -
Пять контрольных случаев с ожидаемыми ролями, основаниями и следующим запросом — 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())" -
Экран: терминал 1
make api, терминал 2 — команды из раздела Интерфейс, затем страница узла из первой строкиoutputs/top_nodes.csv(адрес печатает команда сTOP_GIDв том же разделе). -
Временной признак против случайных дат:
.venv/bin/python -m pipeline.temporal_check --data task/data(≈1 с, 1 000 перестановок). -
Сравнение с наивными ранжированиями:
.venv/bin/python -m pipeline.baselines --data task/data --out outputs(≈1 с). Файлов не пишет, числа — в таблице раздела Как мы себя проверяли. -
Проверки выгрузок без разметки (устойчивость топа к шуму, чувствительность ролей к порогам, стабильность кластеров по 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 | следующий запрос данных и ограничения данных по узлу |
method | v1 |
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.py1 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/, APIbackend/, экраны кейса, документы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/ | гипотезы и их проверка: временной признак, смежные работы, сценарий аналитика, порядок переводов, контрольные случаи, проверки без разметки, устройство системы |
Makefile | setup, 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
Развёрнутая версия
Нет. Решение запускается локально по шагам выше.
Авторы коммитов
История коммитов
- 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 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.

