AAYMA
RU
Войти

Moneylai

Moneylai: объяснимый анализ сети переводов для AML-аналитика.

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

О проекте

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

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

Суть

Moneylai: объяснимый анализ сети переводов для AML-аналитика. Шесть ролей клиентов по правилам, кластеры, очередь приоритетной проверки, схема сети, аналитика цепочек, циклов и времени, ассистент с вызовом инструментов графа и экспорт трёх CSV.

Как устроено

Python-пайплайн проверяет схему трёх Parquet, строит направленный граф и считает признаки: суммы, степени, PageRank, betweenness, короткие циклы, seed_share (пропорциональное смешивание потоков), fast_out_share (выход в течение 2 дней). Роли coordinator/consolidator/distributor/transit/terminal/peripheral назначаются каскадом правил с порогами по перцентилям. priority_score равен среднему перцентильных рангов, умноженному на вес роли и поправку за слабую связь с seed. Кластеры строятся Louvain. Сервер на TS отдаёт результаты в React-клиент, ассистент отвечает через вызовы инструментов графа. Правила доработаны по итогам LLM-симуляции жюри.

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

  • PageRank
  • betweenness centrality
  • Louvain
  • percentile thresholds
  • rule cascade
  • short cycle detection
  • flow-mixing seed share
  • sensitivity analysis
  • LLM jury simulation
  • tool calling

Метрики

Симуляция жюри на v3: 65/0/0 (66 gid); 2248 клиентов → 24 coordinator, 63 consolidator, 20 distributor, 20 transit, 193 terminal; 91 кластер

Особенности

Правила ролей проверялись LLM-симуляцией жюри (gpt-5.6-sol): критика правил и проверка evidence во всех 2248 строках, потом переработка до v3. Для каждого порога указан перцентильный источник. Есть анализ устойчивости при удалении топ-узлов и синтетические наборы для сверки.

Стек

Python · Parquet · TypeScript · React · Vite · Bun · shadcn · Docker · Railway

Модели

gpt-5.6-sol


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

README

README.md

Moneylai

Объяснимый анализ транзакционной сети для AML-аналитика. Moneylai помогает разобраться в графе банковских переводов: кто собирает средства, кто передаёт их дальше, какие группы связаны между собой и кого стоит проверить первым. Для каждого клиента решение показывает роль, приоритет и численное обоснование, которое можно сопоставить с исходными переводами.

Проект создан для кейса HackAlem AI «Граф денег». Встроенный пример — обезличенная выгрузка организаторов: 2 248 клиентов, 3 119 направленных связей, 4 840 переводов, 81 исходный клиент (seed) за июль 2026 года.

Роли и приоритеты — гипотезы для аналитической проверки. Структура переводов сама по себе не доказывает причастность клиента к противоправной деятельности.

Развёрнутая версия: moneylai.up.railway.app.

Возможности · Метод · Запуск · Сценарий для жюри · Тесты и эвалы · Риски

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

ВозможностьЧто получает аналитик
Загрузка данныхТри файла Parquet → проверка схемы → расчёт → новая активная выгрузка. Можно переключаться между наборами и удалять загруженные наборы
Роли клиентовОдна из шести ролей по явным правилам: coordinator, consolidator, distributor, transit, terminal, peripheral
Очередь проверкиДо 30 клиентов по priority_score, фильтр по роли, объяснение why, переход к карточке клиента
Карточка клиентаЗначения метрик рядом с порогами правила, суммы и количество переводов, плательщики и получатели, связь с seed, циклы и временные признаки
Схема сетиНаправленные связи, поиск по полному gid или его окончанию, фильтры, раскраска, масштабирование и выбор узла
Группы клиентовКластеры, их состав, внутренний оборот, крупнейшие узлы и гипотезы; карта потоков между группами
Аналитические проверкиПовторяющиеся цепочки, короткие циклы, активность по дням, синхронные поступления, быстрый вывод, нетипичные входящие суммы, изменение связности при удалении приоритетных узлов
Полнота данныхВидимые границы выгрузки и подсказки, какие дополнительные операции запросить
АссистентВопрос на русском → вызовы инструментов графа → ответ и видимая цепочка вызовов. Формы поиска путей и общих получателей работают без LLM
ЭкспортТри обязательных CSV для жюри и дальнейшего анализа

Основные экраны: /, /top, /nodes/:gid, /graph, /network, /clusters, /analysis, /assistant, /upload, /method/rules, /method/architecture. В разделе /analysis доступны вкладки routes, time, anomalies, resilience, completeness.

Реализация интерфейса — client/src/pages, вычислений API — server/src/data, назначения ролей — pipeline/run.py.

Как работает решение

  1. Выбрать входные данные. При запуске открывается демо организаторов. Для своей выгрузки аналитик передаёт nodes.parquet, edges.parquet и transactions.parquet через экран «Данные».
  2. Проверить и рассчитать. Python-пайплайн сверяет схему и согласованность файлов, строит направленный граф, вычисляет структурные и временные признаки, назначает роли, кластеры и приоритеты.
  3. Получить очередь проверки. Аналитик открывает приоритетного клиента и видит фактические значения рядом с условиями сработавшего правила.
  4. Проверить контекст. На схеме и в карточке можно проследить контрагентов, суммы и число переводов; в аналитике — цепочки, циклы, синхронность и границы наблюдения.
  5. Сформировать следующую гипотезу. Поиск путей и ассистент помогают задавать вопросы к уже рассчитанным данным. Аналитик решает, какие операции или периоды запросить дополнительно, и скачивает CSV.

Повторная загрузка тех же трёх файлов определяется по хешу содержимого и активирует существующий набор без пересчёта. Кнопка обновления интерфейса повторно запрашивает API; расчёт запускается при загрузке нового набора либо отдельной командой пайплайна.

Данные и результаты

Вход

Источник демо — файлы организаторов в task/data. Описание полей — task/README.md.

ФайлПоляОбъём демо
nodes.parquetgid, depth, is_seed2 248 клиентов
edges.parquetsrc, dst, sum_kzt, n_tx, depth3 119 пар плательщик → получатель
transactions.parquetsrc, dst, date, sum_kzt4 840 переводов

Период демо — 1–31 июля 2026 года, общий объём видимых переводов — 365 890 012,01 ₸. Граф собран по исходящим переводам от 81 seed на четыре колена, только внутри одного банка и только для сумм от 5 000 ₸. Число клиентов по коленам 0–4: 81 / 472 / 462 / 789 / 444.

gid — идентификатор, а не число для арифметики: в TypeScript и JSON он хранится строкой, в Parquet и Python — как int64. Это сохраняет точность значений, превышающих Number.MAX_SAFE_INTEGER.

Внешнее обогащение клиентских данных не используется. task/starter содержит исходный пример организаторов; рабочий расчёт выполняет собственный pipeline/run.py.

Выход

Результаты демо сохранены в out и пересчитываются из исходных Parquet одной командой.

ФайлСхемаСтрок данных в демо, без заголовка
nodes_roles.csvgid, role, role_score, cluster_id, priority_score, evidence2 248
clusters.csvcluster_id, n_nodes, n_seed, sum_kzt_internal, top_gids, hypothesis91
top_nodes.csvrank, gid, role, priority_score, why30

evidence содержит численные основания и занимает не более 200 символов. role_score и priority_score лежат в диапазоне 0–1. В результат включены все клиенты входного набора, в том числе 19 seed без рёбер.

Дополнительно создаются node_metrics.csv, edge_metrics.csv и node_metrics.json. JSON содержит подробные признаки каждого клиента и _meta: рассчитанные пороги, веса, распределение ролей, период и параметры выгрузки. Сервер использует этот JSON вместе с clusters.csv и top_nodes.csv; при скачивании отдаёт три обязательных CSV. Подробная схема — docs/PIPELINE_CONTRACT.md.

Как назначаются роли и приоритет

Метрики и правила

Роли вычисляются кодом, без LLM. Пайплайн рассчитывает отдельные показатели суммы и количества переводов, числа контрагентов, PageRank, посредничества (betweenness), коротких циклов, связи с seed и времени операций. Роль назначается по условиям таблицы ниже; PageRank и количество переводов служат дополнительным контекстом в карточках и объяснениях и не входят в каскад ролей или формулу приоритета.

pass_through = out_kzt / in_kzt — отношение видимого выхода к видимому входу. seed_share — оценка доли средств от seed в модели пропорционального смешивания потоков. fast_out_share — доля исходящей суммы, перед которой был входящий перевод в пределах двух дней; это временной признак, а не сопоставление конкретных денежных единиц.

Правила проверяются сверху вниз, назначается первая подходящая роль. Часть порогов определяется перцентилями входных данных с нижней границей; долевые и временные пороги заданы явно. Ниже — значения для встроенной выгрузки, воспроизведённые текущим кодом.

ПорядокРольУсловиеКлиентов
0peripheral с no_dataПоследнее колено без исходящих либо seed без единого ребра: экономическая роль не определяется463
1coordinator≥3 плательщика, ≥3 получателя, посредничество ≥0,00115965; дополнительно цикл длиной ≤5, либо ≥3 seed выше по потоку, либо сам seed с поступлением от другого seed24
2consolidator≥3 плательщика, пропуск <0,3, вход ≥215 000 ₸, доля крупнейшего плательщика <80%63
3distributor≥16 получателей и число получателей ≥3 × число плательщиков20
4transitЕсть вход и выход, пропуск 0,8–1,2, вход ≥100 000 ₸, быстрый выход ≤2 дней составляет ≥50%; клиент не seed20
5terminalКолено 1–3, нет исходящих либо пропуск <0,3, вход ≥215 000 ₸; клиент не seed193
6peripheralОстальные узлы: ни одно из перечисленных правил не выполнено1 465

Итого peripheral — 1 928 клиентов, включая 463 случая no_data. Последний наблюдаемый hop определяется из данных; для демо 444 узла четвёртого колена не получают роль terminal только из-за отсутствия исходящих.

Источники порогов: число плательщиков — p95; исходящая степень coordinator — p70, distributor — p95; посредничество coordinator — p95 среди узлов с входом и выходом; вход consolidator/terminal — p80; вход transit — p60 с нижней границей 100 000 ₸. Полные условия и формулы — pipeline/run.py и pipeline/RULES.md.

Что означают оценки

role_score показывает запас выполнения правила. Для назначенной роли используется 0,5 + 0,5 × средний нормированный запас по числовым условиям. Для обычной периферии оценка зависит от доли выполненных условий ближайшей роли (nearest_role). Для no_data значение 1 означает уверенность в отсутствии достаточных данных для назначения экономической роли.

priority_score определяет порядок ручной проверки:

base = mean(
  percentile_rank(seed_money_in),
  percentile_rank(n_seed_upstream),
  percentile_rank(in_kzt; для seed — out_kzt),
  percentile_rank(betweenness)
)
priority_score = base × вес_роли × поправка_на_слабую_связь_с_seed

Веса: coordinator — 1,0; consolidator — 0,9; distributor — 0,7; transit — 0,6; terminal — 0,5; peripheral — 0,2; no_data — 0,5. Для coordinator, consolidator, distributor и terminal с seed_share < 10% устанавливается weak_seed_link, приоритет умножается на 0,7, а объяснение допускает легального контрагента. Обе оценки являются техническими показателями правил, а не вероятностью виновности.

Кластеры

Louvain применяется к неориентированной проекции графа: вес пары — сумма переводов в обе стороны, случайное зерно фиксировано (seed=42). Для встроенных данных получен 91 кластер, из них 72 содержат более одного узла. Направление сохраняется при расчёте ролей, потоков и путей, но не используется самим Louvain. Принадлежность к одному кластеру означает связанность в наблюдаемой сети, а не установленную принадлежность к одной организации.

Технологии и архитектура

КомпонентТехнологии и назначение
РасчётPython ≥3.12, pandas, NumPy, PyArrow, NetworkX, SciPy; окружение и lock-файл — uv
APITypeScript, Bun, Hono; hyparquet читает Parquet, ZSTD распаковывается через Bun.zstdDecompressSync; d3-force рассчитывает расположение узлов
ИнтерфейсReact 19, React Router 8, Vite 8, TypeScript 6, Tailwind CSS 4, shadcn/ui на Base UI, Lucide, Sonner, Canvas 2D
AI-ассистентOpenAI Responses API; модель по умолчанию gpt-5.6-sol, настраивается через OPENAI_MODEL
Проверкиpytest, встроенные проверки Python, анализ чувствительности, отдельные скрипты LLM-эвальвации, TypeScript и oxlint
РазвёртываниеDocker, Railway; Bun workspaces для клиента и сервера
flowchart LR
  D[Три Parquet] --> P[Python: метрики, правила, кластеры, приоритет]
  P --> O[CSV и node_metrics.json]
  D --> S[Bun + Hono]
  O --> S
  S -->|REST API| U[React: очередь, граф, карточки, проверки]
  U -->|Загрузка Parquet| S
  S -->|Подпроцесс uv| P
  U -->|Вопрос аналитика| A[Ассистент]
  A <--> L[OpenAI Responses API]
  A <--> T[Локальные инструменты графа]
  S --> T
client/                  интерфейс, маршруты страниц, типизированные запросы API
server/src/routes/       HTTP API: граф, клиенты, результаты, аналитика, наборы, ассистент
server/src/data/          загрузка наборов, реестр, раскладка графа, аналитика, инструменты
pipeline/run.py          полный расчёт из Parquet в CSV/JSON
pipeline/tests/          проверки на небольшом графе с известными ожидаемыми ролями
pipeline/sensitivity.py  изменение порогов и сравнение ролей/топ-20
pipeline/eval/           снимки v1/v3, LLM-эвалы, сырые ответы и журналы расхода
synthetic/               два синтетических набора, генератор, обход и аудит
experiments/             исследовательский notebook probe-0.ipynb
task/data/               неизменяемые входные данные организаторов
out/                     сохранённые результаты для демо
data/datasets/           пользовательские загрузки; каталог исключён из Git
docs/                    контракт данных, методология, требования и схема решения
Dockerfile, railway.json конфигурация развёртывания

Пайплайн — единственный компонент, назначающий роли и приоритет. Сервер читает готовые результаты, строит раскладку, аналитику и индексы запросов. store.ts держит реестр наборов и один активный набор. При загрузке новые файлы сохраняются в data/datasets/<id>/raw, результаты — в out внутри того же каталога, после чего набор становится активным.

API и внешние интеграции

Метод и путьНазначение
GET /api/health, GET /api/statsПроверка сервиса и сводка активного набора
GET /api/graph, GET /api/transactions, GET /api/nodes/:gidГраф, переводы, карточка клиента
GET /api/top, GET /api/clusters, GET /api/metaПриоритеты, кластеры, правила и пороги
GET /api/export/:fileОдин из трёх обязательных CSV
GET /api/analytics/:keytime, routes, anomalies, resilience, completeness
GET /api/datasets, POST /api/datasetsСписок наборов и загрузка трёх Parquet
POST /api/datasets/:id/activate, DELETE /api/datasets/:idПереключение и удаление пользовательского набора
GET /api/assistant/statusДоступность LLM и список инструментов
POST /api/assistant/tools/:nameПрямой запрос к инструменту без LLM
POST /api/assistant/askСвободный вопрос через OpenAI

Ассистент может вызывать семь инструментов: node_metrics, neighbors, common_successors, paths, sync_events, query_nodes, cluster_summary. Модель получает вопрос и результаты вызовов, формулирует ответ; сохранённые роли и CSV она не изменяет. Код задаёт требование брать числа из инструментов, а UI показывает цепочку вызовов для проверки ответа.

Ключ OpenAI нужен только для свободных вопросов и повторных внешних LLM-эвальваций. Расчёт, экспорт, граф и прямые инструменты работают локально без ключа. Шрифты Unbounded и IBM Plex Sans/Mono подключены через Google Fonts. Подключения к банковской системе и базы данных в текущем приложении нет: источником служат файлы.

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

Что требуется

  • Bun для клиента и API. При подготовке README команды проверены на Bun 1.4.2; сервер использует Bun API и не запускается как обычное Node.js-приложение.
  • uv и Python ≥3.12 для пересчёта и загрузки новых наборов. Проверки ниже выполнены на Python 3.13.13; Docker-образ устанавливает Python 3.12.
  • Сеть для первоначальной установки зависимостей. Версии зафиксированы в bun.lock и pipeline/uv.lock.

Локальный запуск

git clone https://github.com/BAITC-Hacks/hack-a5bc9531-menelai.git
cd hack-a5bc9531-menelai
bun install --frozen-lockfile

Подготовить окружение пайплайна и пересчитать демо одной командой из корня репозитория:

(cd pipeline && uv sync --frozen && uv run python run.py)

Команда читает task/data, создаёт out и в конце выводит ПРОВЕРКИ: все assert'ы пройдены, распределение ролей и время. Для просмотра демо уже сохранённых файлов out достаточно; повторный запуск позволяет проверить воспроизводимость. Для загрузок через UI uv должен быть доступен серверу в PATH.

Запустить API и интерфейс:

bun run dev

Открыть http://localhost:5173. API работает на http://localhost:3001, Vite проксирует к нему /api.

Для свободных вопросов ассистенту создайте корневой .env по образцу .env.example и заполните OPENAI_API_KEY; при необходимости задайте OPENAI_MODEL. Если .env уже существует, редактируйте его без перезаписи. Файл исключён из Git. Без ключа чат отключён, прямые инструменты доступны.

Пересчёт другой выгрузки:

cd pipeline
uv run python run.py --data /путь/к/parquet --out /путь/для/результатов

Сборка и запуск в одном сервисе

Из корня репозитория:

bun run build
bun run start

Сервер отдаёт /api и собранный client/dist на http://localhost:3001, включая переходы по адресам страниц SPA.

ПеременнаяНазначение / значение по умолчанию
PORTПорт API, 3001
DATA_DIRИсходные Parquet демо, task/data
OUT_DIRРассчитанные результаты демо, out
DATASETS_DIRКаталог загрузок, data/datasets
API_PROXYАдрес API для Vite при разработке, http://localhost:3001
OPENAI_API_KEYСерверный ключ для свободных вопросов
OPENAI_MODELМодель ассистента, gpt-5.6-sol

Пути к данным по умолчанию вычисляются относительно файлов сервера. При изменении используйте абсолютные пути. Встроенный набор всегда имеет id demo.

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

Демонстрация для жюри

  1. Открыть главную. Выбрать демо и сверить сводку: 2 248 клиентов, 3 119 связей, 4 840 переводов, 81 seed. Скачать три CSV.
  2. Открыть первого клиента очереди — 100000003684369100. Роль coordinator, приоритет 0,9917, 24 плательщика и 62 получателя. В карточке сопоставить порог посредничества с фактом и показать оговорку о неполном входе у seed.
  3. Открыть 100000003115284100. Роль consolidator, приоритет 0,8849: вход 2 160 500 ₸ от 8 плательщиков, выход 517 000 ₸ двум получателям, пропуск 0,24, доля крупнейшего плательщика 29%. Проверить каждое условие правила.
  4. В «Ассистенте» открыть форму поиска путей. Указать первый gid как источник, второй — как получателя. Среди результатов есть прямое направленное ребро на 193 000 ₸, 2 перевода. Этот сценарий не требует OpenAI.
  5. Проверить границу наблюдения — 100000003220685100. Это узел четвёртого колена с входом 1 306 000 ₸. Он помечен peripheral с объяснением «нет данных» и запросом исходящих, поскольку обход остановлен на этом колене.
  6. Открыть «Проверки» → «Полнота данных» и «Маршруты и циклы». Сопоставить гипотезы с охватом данных и циклами. Затем на экране «Данные» загрузить три исходных Parquet, дождаться расчёта и проверить новую активную выгрузку.

Проверка через API

Команды выполняются из корня при запущенном сервере:

curl -fsS http://localhost:3001/api/health
# {"ok":true}

curl -fsS http://localhost:3001/api/stats
# nodes=2248, edges=3119, transactions=4840, seeds=81, clusters=91

curl -fsS http://localhost:3001/api/nodes/100000003684369100

curl -fsS http://localhost:3001/api/assistant/tools/paths \
  -H 'Content-Type: application/json' \
  -d '{"src":"100000003684369100","dst":"100000003115284100","max_len":4}'

curl -fsS http://localhost:3001/api/export/nodes_roles.csv -o /tmp/nodes_roles.csv

Загрузка и возврат к демо:

curl -fsS http://localhost:3001/api/datasets \
  -F nodes=@task/data/nodes.parquet \
  -F edges=@task/data/edges.parquet \
  -F transactions=@task/data/transactions.parquet \
  -F name=jury-check

curl -fsS -X POST http://localhost:3001/api/datasets/demo/activate

Успешная загрузка возвращает { dataset, log } и активирует набор. log содержит последние 40 строк вывода пайплайна. Ошибки входных файлов возвращаются как HTTP 400 с пояснением; без результатов расчёта API ролей, кластеров и аналитики возвращает 503.

Тесты, прогоны и эвалы

Проверки отвечали на разные вопросы: соблюдается ли контракт выгрузки; правильно ли реализованы правила; повторяется ли расчёт; насколько результат зависит от порогов; понятны ли объяснения; насколько синтетические данные пригодны для дальнейших испытаний. Их результаты не объединяются в одну «оценку точности».

1. Полный прогон и проверки контракта

Зачем. Проверить путь от исходных Parquet до обязательных артефактов и убедиться, что интерфейс получает согласованные данные.

Как. load() в pipeline/run.py проверяет обязательные файлы и колонки, уникальность клиентов, наличие seed, концы рёбер и совпадение пар и сумм edges с агрегированными transactions. После расчёта checks() проверяет количество и уникальность строк, словарь ролей, диапазоны оценок, длину evidence, принадлежность к кластерам, обработку отсутствующих данных, порядок топа и ссылки между CSV/JSON.

Что получили. При повторной проверке текущей версии 23.09.2026 два запуска run.py завершились сообщением ПРОВЕРКИ: все assert'ы пройдены за 4,3 и 4,5 секунды по внутреннему таймеру программы. Получены 2 248 строк ролей, 91 кластер и 30 строк приоритета. Установка зависимостей в эти времена не входит.

Как использовали. Проверки встроены в обычный запуск, включая загрузку через API: вычисление должно завершиться успешно прежде, чем новый набор будет зарегистрирован и показан пользователю.

2. Регрессионные тесты на небольшом графе

Зачем. Проверять конкретные экономические паттерны и случаи неполных данных с заранее известным ожидаемым результатом.

Как. pipeline/tests/test_synthetic.py строит искусственный граф на 62 узлах. Три теста проверяют назначение ролей, признаки паттернов и веса приоритета. В сценариях есть быстрый транзит и похожий на него медленный вывод, сборщик, веер, координатор с циклом, конечный получатель, легальный магазин с аналогичной структурой, доминирующий плательщик, обрезанный узел и изолированный seed.

(cd pipeline && uv run pytest tests -q)

Что получили. Повторный запуск при подготовке README: 3 passed in 1.28s. Проверяются, в частности, нулевая seed-доля у изолированного seed, текст «0 вход., 0 исход.», запрос исходящих у обрезанного узла, max_payer_share, поправка 0,7 для слабой связи с seed и отдельный вес no_data.

Как использовали. Эти проверки закрепляют поведение правил и изменения после разбора эвалов. Это регрессионная проверка реализации на сконструированных примерах; она не заменяет оценку на независимо размеченных банковских данных.

3. Повторяемость расчёта

Зачем. Убедиться, что одна и та же выгрузка и версия кода дают один результат для демонстрации и проверки жюри.

Как. Пайплайн дважды запущен в разные временные каталоги; затем сравнили содержимое файлов. Louvain использует фиксированный seed=42.

(cd pipeline && uv run python run.py --out /tmp/moneylai-run-1)
(cd pipeline && uv run python run.py --out /tmp/moneylai-run-2)

for file in nodes_roles.csv clusters.csv top_nodes.csv node_metrics.csv edge_metrics.csv node_metrics.json
do
  cmp "/tmp/moneylai-run-1/$file" "/tmp/moneylai-run-2/$file"
done

Что получили. Все шесть файлов совпали побайтно между двумя прогонами и с текущими файлами out в репозитории. cmp при совпадении ничего не печатает.

Как использовали. Жюри может пересоздать те же артефакты и проверить объяснение любого gid по тем же метрикам. Повторяемость относится к зафиксированным данным, коду и окружению; сама по себе она не доказывает экономическую истинность роли.

4. Чувствительность к порогам

Зачем. Оценить риск изменения роли или очереди проверки при выборе близкого порога.

Как. pipeline/sensitivity.py меняет 15 параметров по одному в обе стороны на 20%, затем все пороги одновременно в сторону более мягких и более строгих условий. Получается 30 одиночных и 2 совместных варианта, плюс базовый. Степенные пороги сдвигаются минимум на единицу: переход 3 → 4 плательщика фактически равен +33%, что явно отмечено в отчёте. Метрики графа сохраняются, пересчитываются роли и приоритет.

До прогона заданы критерии: Jaccard состава топ-20 ≥0,80 и не более 2% клиентов со сменой роли в каждом одиночном варианте. Jaccard — размер пересечения списков, делённый на размер их объединения.

mkdir -p /tmp/moneylai-sensitivity
(cd pipeline && uv run python sensitivity.py --out /tmp/moneylai-sensitivity)

Что получили. Повторный расчёт совпал с out/sensitivity.md побайтно.

ИзменениеJaccard топ-20Сменили роль
Минимум плательщиков consolidator: 3 → 40,6732
Минимальный вход terminal: 215 000 → 172 000 ₸1,0049
Все условия мягче0,67134
Все условия строже0,54102

Как использовали. Критерий выполнен не для всех одиночных вариантов: выявлен риск на границе consolidator/terminal. При переходе 3 → 4 четыре сборщика становятся terminal и покидают топ-20. Для проверки таких случаев интерфейс показывает факты рядом с порогами, а приоритет следует использовать как очередь ручной проверки. Анализ не устанавливает новые пороги автоматически; базовые правила и сам отчёт доступны для воспроизведения.

5. LLM-эвалы: симуляция жюри и проверка объяснений

Зачем. Проверить, можно ли защитить роль конкретного клиента числами, найти неоднозначности методологии и подготовить вопросы для демонстрации. Модель выступала критиком решения; назначение ролей оставалось детерминированным.

Как организовали. Скрипты pipeline/eval/jury.py, evidence_check.py и llm.py используют OpenAI Responses API. В сохранённых журналах вызовов указана gpt-5.6-sol; код предусматривает резервную gpt-5.5. Правила и данные заморожены в snapshot_v1 и snapshot_v3, ответы и расход сохранены отдельно.

Проводились три задачи:

  1. Критика методологии. Модель получила правила, разделы ТЗ и сводку данных и сформулировала замечания к порогам, интерпретации неполной выгрузки и доказательности ролей. Этот этап выполнен на v1; в v3 его не повторяли. Оценка «5/10» в исходном ответе — мнение симулированного жюри, а не оценка реального жюри и не метрика классификации.
  2. Защита отдельного gid. Модель получила карточку: роль, метрики, evidence, крупнейших контрагентов, циклы и синхронные дни; для топа — ещё why и ранг. Ответ — «да / частично / нет» на вопрос об обоснованности роли по правилам и числам, альтернативная роль и уточняющий вопрос. Затем вопросы сгруппированы по темам для подготовки защиты.
  3. Проверка evidence по всей выгрузке. Первый слой — код: наличие цифр, длина ≤200, префикс роли, нежелательные утверждения о виновности и сверка отдельных чисел с метриками. Второй — модель: соответствие правилам, числам и гипотезной формулировке. В каждом прогоне обработано 2 248 строк, 57 пакетов максимум по 40 строк, с восемью параллельными исполнителями.

Выборка защиты. В v1 взяли топ-30, по пять случайных узлов каждой роли (random_state=42) и 12 специальных случаев: обрезанные узлы, изолированные seed, сборщики со слабой seed-связью и terminal с малым числом плательщиков. После удаления пересечений — 66 gid. В v3 использованы топ-30, по пять случайных на роль и девять случаев no_data, weak_seed_link и terminal с доминирующим плательщиком — 65 gid после удаления пересечений.

Что получили. Итоги ниже пересчитаны из сохранённых JSON/CSV, включая sim_results.json и sim_results_v3.json.

Проверкаv1v3
Уникальных gid в защите6665
Роль обоснована: «да»5465
«Частично»120
«Нет»00
Строк evidence с замечаниями кодовой проверки190
Замечаний модели к evidence21 по 21 gid1 по 1 gid

В v1 код нашёл 19 объяснений изолированных seed без чисел. Модель также указала эти строки и два случая округления: отображение пропуска 0,2988 как 0,30 рядом с условием <0,3 и доли 0,875 как 87%. В v3 осталось одно замечание модели: у 100000007170072100 пропуск 0,995 отображён как 0,99; кодовая проверка допускает такое расхождение в пределах установленной погрешности.

Между выборками v1 и v3 25 общих gid. Результат 65/65 означает согласие модели с обоснованиями выбранных узлов по переданным правилам. Это не «100% точность»: выборки различаются, независимой истинной разметки реальных клиентов нет.

Как использовали замечания. Связь с доработками зафиксирована в истории Git, в частности в коммите b74023e «pipeline v3: правки по симуляции жюри».

Находка при проверкеЧто сделано в коде и объяснениях
Порог посредничества coordinator не был виден в evidenceВ evidence печатаются численный порог p95 и фактическое значение
Несколько плательщиков могли скрывать один доминирующий источникДля consolidator введено условие max_payer_share < 0.8; четыре прежних сборщика с долями крупнейшего плательщика ≥80% перешли в terminal
Обрезанные узлы получали вес обычной периферииВыделен no_data, задан вес 0,5 и явный запрос исходящих переводов
Изолированный seed имел seed-долю 1 при отсутствии денегУстановлена доля 0; evidence содержит «0 вход., 0 исход.»
Структурный паттерн не обязательно связан с seedВ v2 введены weak_seed_link и оговорка о возможном легальном контрагенте; в v3 добавлена поправка приоритета ×0,7
Ближайшая роль периферии и role_score требовали уточненияФормализованы условия, nearest_role сохраняется в метриках
Округление визуально противоречило строгому порогуДобавлена дополнительная точность у границ и уточнено отображение процентов

Поведение доминирующего плательщика, изолированного seed и весов закреплено регрессионными тестами. Между полными снимками v1 и v3 роли изменились у 38 клиентов — это совокупный эффект изменений, а не результат одной поправки. Предложения модели о неттинге встречных потоков, точной атрибуции средств и дополнительных флагах остаются предложениями, если их нет в текущем коде.

Контроль самого эксперимента. Первоначальный запуск задач защиты и evidence смешал карточки v1 с изменёнными в другой сессии правилами v2. Он исключён из содержательных итогов, сохранён в raw/mismatch_v2rules; последующие запросы читают правила из замороженного снимка. Так результаты привязаны к конкретной версии правил.

Отчёты: jury_report.md, jury_report_v3.md, critique_theses.md. Сырые ответы — raw и raw_v3; замечания — evidence_*_issues*.csv в том же каталоге.

Уточнение к архивным текстам: в таблице сравнения jury_report_v3.md знаменатель v1 ошибочно указан как 54; исходные результаты содержат 66 gid, доля «частично» — 12/66 = 18,18%. В pipeline/README.md осталась историческая фраза, что v3 не перезапускалась; сохранённые артефакты подтверждают повтор задач защиты и evidence, но не общей критики методологии.

Расход по журналам. v1 включает и исключённый запуск. Указанная стоимость рассчитана скриптом при допущении $5/$40 за миллион входных/выходных токенов; это не подтверждённый счёт провайдера. Reasoning уже входит в выходные токены.

ЖурналВызововВходных токеновВыходных токеновРасчётная стоимость
usage.jsonl, v12501 339 718205 270$14,91
usage_v3.jsonl, v3123870 06699 643$8,34

Как воспроизвести. Для изучения сохранённых ответов достаточно открыть JSON/CSV; ключ и сеть не нужны. Скрипты исторического прогона можно запустить из pipeline:

cd pipeline
EVAL_SNAP=v3 uv run --with openai --with python-dotenv --with tabulate python eval/jury.py sim
EVAL_SNAP=v3 uv run --with openai --with python-dotenv --with tabulate python eval/jury.py agg
EVAL_SNAP=v3 uv run --with openai --with python-dotenv --with tabulate python eval/evidence_check.py

Для v1 используется EVAL_SNAP=v1; отдельная задача критики — eval/jury.py critique. Скрипты требуют OPENAI_API_KEY в корневом .env даже при использовании сохранённых ответов. При наличии raw/*.json или raw_v3/*.json ответ берётся из кеша, при отсутствии — выполняется внешний платный запрос. Архивные снимки имеют расширенную схему для эвала: текущий шестиколоночный out/nodes_roles.csv не следует подставлять вместо них. При подготовке этого README внешние LLM-запросы не выполнялись.

6. Два независимых синтетических набора

Зачем. Создать дополнительные миры с известным авторским замыслом и проверить, насколько генераторы воспроизводят структуру наблюдаемой банковской выгрузки. Это отдельный эксперимент над данными, не измерение точности классификатора на реальных клиентах.

Как. До генерации зафиксированы synthetic/SPEC.md, публичный бриф и критерии проверки. По протоколу генераторы не получали реальные транзакции и реализацию пайплайна. Оба мира проходят один crawl.py: фильтр внутрибанковских операций ≥5 000 ₸ за июль, обход исходящих на четыре колена, сохранение seed без рёбер и обрыв исходящих на границе.

МетодКак создан мирЧто осталось в наблюдаемой выгрузке
A — LLM-журналыСемь авторских частей: шесть ячеек и легальная экономика, CSV участников и операций, пояснения замысла785 узлов, 2 273 ребра, 3 284 перевода, 69 seed
B — стохастическая агентная модельB_abm/gen.py, фиксированный seed=7, случайное поведение участников по архетипам2 153 узла, 4 826 рёбер, 8 364 перевода, 87 seed

Что проверяли и получили.

  • Схема и инварианты. Проверены типы полей, агрегирование переводов в рёбра, сумма/период/направление, отсутствие исходящих у четвёртого колена и пересечений gid с реальными. При повторной проверке сохранённых A и B оба набора прошли crawl.check.
  • Сходство распределений. profile.py сравнивает степени, суммы, повторяемость переводов, активность, компоненты, циклы, временные признаки и статистики KS. В отчёте по 45 свойствам B ближе к реальным данным в 24 случаях, A — в 19, в двух — равенство. При подготовке README профиль пересчитан во временном каталоге и побайтно совпал с PROFILE.md.
  • Наблюдаемость авторской роли. Проверяются отдельные мягкие сигнатуры, а не полный каскад run.py. Среди размеченных авторами участников с вовлечённостью criminal на коленах 1–3, без seed, сигнатура transit видна у 80% из 45 примеров A и примерно 6% из 16 примеров B; consolidator — у 0% из 6 примеров A и 10% из 10 примеров B. Авторская «должность» и наблюдаемая функция счёта могут различаться: сборщик может почти всё передавать дальше, а вход транзитного счёта может исчезнуть за межбанковской границей.
  • Ручной аудит. В REPORT.md разобрано по пять случайно выбранных размеченных узлов: авторская роль согласована с видимыми деньгами у 3 из 5 в A и 2 из 5 в B. audit.py выводит метрики и сырые переводы выбранных клиентов для такого разбора.

Как использовали. Сопоставление показало, для каких дальнейших проверок пригоден каждый набор: A — для разбора смысла роли по журналу и пояснениям автора, B — для изменения масштаба и повторных случайных генераций. Перед расчётом accuracy потребовалась бы отдельная разметка наблюдаемой функции, поскольку метка автора описывает также скрытый от банка мир. Синтетические данные не добавляются к демо и не заменяют исходную выгрузку организаторов.

Пересборка сохранённых наборов и профиля из корня, в отдельной рабочей копии, если нужно сохранить текущие артефакты:

cd synthetic
uv run --project ../pipeline python crawl.py A_llm
(cd B_abm && uv run --project ../../pipeline python gen.py)
uv run --project ../pipeline python crawl.py B_abm
uv run --project ../pipeline python profile.py
uv run --project ../pipeline python audit.py A_llm
uv run --project ../pipeline python audit.py B_abm

Для A используются уже сохранённые журналы, новых LLM-вызовов эти команды не делают. Для B сначала восстанавливаются world_*.csv, затем выполняется общий обход. Команды перезаписывают соответствующие синтетические Parquet и профиль.

7. Проверка приложения при подготовке README

Повторно выполнено на версии 49dfb93 от 23.09.2026; исходные данные и сохранённые результаты не изменялись.

Команда / проверкаРезультат
bun install --frozen-lockfileЗависимости установлены
(cd pipeline && uv sync --frozen)Checked 12 packages
bun run buildTypeScript клиента и production-сборка завершились успешно
(cd client && bun run lint)Код завершения 0, два предупреждения Fast Refresh в badge.tsx и button.tsx
(cd server && bunx tsc --noEmit -p .)Код завершения 0
Тесты, полный расчёт, сравнение файлов и sensitivityРезультаты приведены выше
Локальные запросы через app.request Hono20 GET-маршрутов API/SPA вернули 200; проверены CSV, аналитика, карточка и граф
Путь, загрузка, повторная загрузка, переключение, удаление тестовой загрузкиУспешно; пересчёт запущен в отдельном временном каталоге
Ожидаемые ответы ошибокНеизвестный /api — 404; вопрос ассистенту без ключа — 503

Сборщик Vite сообщил о JavaScript-фрагменте больше 500 kB. Это предупреждение сохранено как ориентир для оценки загрузки интерфейса. Проверка API не является браузерным end-to-end тестом; внешний чат и доступность удалённого развёртывания в эти локальные проверки не входили.

Риски и границы применения

РискКак учитывать при работе
Неполная видимость переводовВ демо отсутствуют межбанковские операции, суммы ниже 5 000 ₸, другие месяцы и исходящие за четвёртым коленом. «Деньги остались» означает отсутствие сопоставимого видимого выхода; для проверки нужны дополнительные данные
Заниженный вход у seedSeed исключены из правил transit/terminal, в компоненте масштаба их приоритета используется выход. Соотношение входа и выхода seed не следует трактовать как полный денежный баланс
Легальные двойники паттерновМагазин, работодатель или семейные переводы могут соответствовать структурной роли. Проверять связь с seed, контрагентов и контекст; weak_seed_link снижает приоритет, но не устанавливает правовую оценку
Зависимость от порогов и порядка правилНа границе consolidator/terminal состав ролей и топа меняется. Использовать таблицу условий и результаты чувствительности; одна назначенная роль не исключает других возможных интерпретаций
Приближённое представление движения денегseed_share основан на пропорциональном смешивании, быстрый вывод — на временном окне. Нет точной попереводной атрибуции, неттинга возвратов и проверки хронологии каждого цикла; даты не содержат времени суток
Интерпретация кластеров и LLMLouvain не учитывает направление, модель может предложить неподтверждённую интерпретацию. Сверять ответ с инструментами и метриками; оценки LLM-эвала не заменяют независимую разметку
Обработка других схем и размеровЗагрузка принимает три Parquet заданной схемы, суммарно до 100 MiB; одна обработка за раз, тайм-аут пять минут. Период и последний hop читаются из данных, но правило terminal и часть подписей рассчитаны на колена 1–3/4; встроенная проверка требует минимум 20 строк топа
Общий серверный контекстАктивный набор один для всех пользователей; при перезапуске выбирается demo. Пользовательские наборы хранятся на диске, постоянный том в конфигурации репозитория не объявлен
Использование реальных банковских данныхВ текущем прототипе нет авторизации и разграничения рабочих пространств. При включённом чате вопрос и результаты инструментов передаются внешнему OpenAI API; для чувствительных данных нужно отдельно определить условия доступа и обработки
Рост нагрузкиДанные и аналитика хранятся в памяти; точное посредничество, перебор циклов и отрисовка всего графа требуют проверки на существенно больших объёмах

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

Текущий замер относится к 2 248 узлам; время работы на миллионе узлов не измерялось. Для такого объёма потребуется перенести агрегации в колоночную обработку, считать приближённое посредничество, ограничивать циклы компонентами и кандидатами, пересчитывать затронутые части графа и отдавать интерфейсу выбранные подграфы. Возможные инструменты для этих изменений — DuckDB/Polars и igraph/graph-tool; в текущую реализацию они не входят. Направление развития подробнее описано в pipeline/README.md.

Развёртывание

Ссылка на приложение, сохранённая в репозитории: https://moneylai.up.railway.app.

Dockerfile собирает один сервис: Bun, uv, Python 3.12, зависимости пайплайна и production-клиент. Hono отдаёт и API, и интерфейс. railway.json выбирает Dockerfile и проверку здоровья /api/health. Python-окружение собирается заранее, поэтому для пересчёта внутри готового контейнера установка зависимостей не требуется.

Локальный запуск такого образа:

docker build -t moneylai .
docker run --rm -p 3001:3001 -e PORT=3001 moneylai

Для воспроизводимого расчёта и демонстрации через локальный интерфейс облачное развёртывание не требуется.

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

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

oljaskrut 26Rakhat Shukirkhan 16Даурен (401kdaniel) 6

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

  • 2026-09-23 17:50cleanupoljaskrut
  • 2026-09-23 17:48upload: один тост об успехе (id) вместо двух в StrictModeoljaskrut
  • 2026-09-23 17:48docs: правила v4, словарь терминов, масштабирование в READMEДаурен (401kdaniel)
  • 2026-09-23 17:47docs: подробный README с тестами, эвалами и рискамиRakhat Shukirkhan
  • 2026-09-23 17:47ui: правила v4 и направление потоков поверх нового интерфейсаДаурен (401kdaniel)
  • 2026-09-23 17:43pipeline и сервер: круг 2 ревью, аналитика и инструменты ассистентаДаурен (401kdaniel)
  • 2026-09-23 17:43pipeline v4: запуск на Windows, приоритет без обрыва, порог оборота координатораДаурен (401kdaniel)
  • 2026-09-23 17:42readmeДаурен (401kdaniel)
Все коммиты (48)
  • 2026-09-23 17:34toast: убрать кнопку закрытия и её стили, стандартный вид sonneroljaskrut
  • 2026-09-23 17:32toast: кнопка закрытия справа сверхуoljaskrut
  • 2026-09-23 17:31upload: спиннер по центру кнопкиoljaskrut
  • 2026-09-23 17:29upload: без поля названия, имя выгрузки — локальное время dd.mm.yy hh:mmoljaskrut
  • 2026-09-23 17:28upload: три строки-дропзоны вместо общей области, тосты sonner об ошибке и успехеoljaskrut
  • 2026-09-23 17:26rename: продукт называется Moneylai, «Граф денег» остаётся только как имя кейсаoljaskrut
  • 2026-09-23 17:25ui: вернуть нейтральную метку «Координатор», убрать число групп из READMEoljaskrut
  • 2026-09-23 17:25Merge remote-tracking branch 'origin/codex/ui-ux-review'oljaskrut
  • 2026-09-23 17:23env exampleoljaskrut
  • 2026-09-23 17:23docs: название Moneylai вместо «Граф денег»; заметка о task/starter в README; удалены шаблонный client/README.md и неиспользуемый solution-diagram.pngoljaskrut
  • 2026-09-23 17:20feat(ui): implement light analysis workspace from design handoffRakhat Shukirkhan
  • 2026-09-23 17:10Merge remote-tracking branch 'origin/feat/synthetic-v2'oljaskrut
  • 2026-09-23 17:04synthetic: два синтетических набора (A — ИИ пишет журнал, B — стохастическая модель), общий обход, профиль и сверка с реальнымиRakhat Shukirkhan
  • 2026-09-23 17:03feat: загрузка своей выгрузки и переключение датасетов; пайплайн без констант датасета; Dockerfile для Railwayoljaskrut
  • 2026-09-23 16:24service urloljaskrut
  • 2026-09-23 16:19docs: METHODOLOGY.md и схема решения из 3523e8a (release/final), сверены с текущим out/; pipeline/.gitignoreoljaskrut
  • 2026-09-23 16:15docs: сервер читает out/ через results.ts; убраны устаревшие API и out.ts из контракта и AGENTS.mdoljaskrut
  • 2026-09-23 16:13fix: убран ложный сигнал «дробление у порога 5 000 ₸», JSON 404 для /api/*, мёртвый код, READMEoljaskrut
  • 2026-09-23 16:13pipeline: nodes_roles.csv — ровно 6 колонок схемы жюри; метрики правил и role_rule перенесены в node_metrics.csvoljaskrut
  • 2026-09-23 16:07Merge feat/ui-redesign into main: UI со схемой сети + пайплайн v3 + docsRakhat Shukirkhan
  • 2026-09-23 16:06merge: feat/ui-redesign в main (новый UI + маршруты results/analytics/assistant)oljaskrut
  • 2026-09-23 16:06pipeline: уборка кода, eval v3 (65/0/0), docs/METHODOLOGY.md и схема решенияRakhat Shukirkhan
  • 2026-09-23 16:00eval: перепроверка жюри на v3 (65/0/0), README пайплайнаRakhat Shukirkhan
  • 2026-09-23 15:57pipeline v3 в main: правила с источниками, тесты, чувствительность, симуляция жюри, выходы по контрактуRakhat Shukirkhan
  • 2026-09-23 15:57graph-money: Python-пайплайн ролей, кластеров и приоритетаДаурен (401kdaniel)
  • 2026-09-23 15:56pipeline: выходы по docs/PIPELINE_CONTRACT.md (node_metrics.csv, edge_metrics.csv, role_rule, true/false)Rakhat Shukirkhan
  • 2026-09-23 15:48pipeline: README пайплайна (запуск, правила, проверка, ограничения, масштабирование)Rakhat Shukirkhan
  • 2026-09-23 15:38pipeline v3: правки по симуляции жюриRakhat Shukirkhan
  • 2026-09-23 15:33deploy to railway: serve client from serveroljaskrut
  • 2026-09-23 15:25eval: симуляция жюри на gpt-5.6-sol (критика правил, 66 gid, evidence всех 2248 строк)Rakhat Shukirkhan
  • 2026-09-23 15:22ui: экраны анализа, ассистент, схема решенияRakhat Shukirkhan
  • 2026-09-23 15:14pipeline v2: пороги-перцентили, transit по времени, флаг слабой связи с seed, синтетический тест, чувствительностьRakhat Shukirkhan
  • 2026-09-23 15:10server: аналитика и инструменты ассистента; правила v2 в UIRakhat Shukirkhan
  • 2026-09-23 15:02ui: новый дизайн клиента и API результатов пайплайнаRakhat Shukirkhan
  • 2026-09-23 14:56pipeline: роли, кластеры, приоритет, выгрузки по ТЗ (v1)Rakhat Shukirkhan
  • 2026-09-23 14:40pipeline backend splitoljaskrut
  • 2026-09-23 14:19agents.mdoljaskrut
  • 2026-09-23 14:10skeletonoljaskrut
  • 2026-09-23 13:38taskoljaskrut
  • 2026-09-23 13:17initoljaskrut
Структура репозитория (554 файлов)
.dockerignore
.env.example
.gitignore
AGENTS.md
Dockerfile
README.md
bun.lock
client/.gitignore
client/.oxlintrc.json
client/components.json
client/index.html
client/package.json
client/public/favicon.svg
client/src/components/NetworkCanvas.tsx
client/src/components/ReviewWorkspace.css
client/src/components/ReviewWorkspace.tsx
client/src/components/kit.tsx
client/src/components/ui/badge.tsx
client/src/components/ui/button.tsx
client/src/components/ui/card.tsx
client/src/components/ui/dropdown-menu.tsx
client/src/components/ui/input.tsx
client/src/components/ui/sonner.tsx
client/src/index.css
client/src/layouts/AppLayout.tsx
client/src/layouts/SectionLayout.tsx
client/src/lib/api.ts
client/src/lib/depth.ts
client/src/lib/format.ts
client/src/lib/roles.ts
client/src/lib/use-api.ts
client/src/lib/utils.ts
client/src/main.tsx
client/src/pages/AnomaliesPage.tsx
client/src/pages/ArchitecturePage.tsx
client/src/pages/AssistantPage.tsx
client/src/pages/ChecksOverviewPage.tsx
client/src/pages/ClustersPage.tsx
client/src/pages/CompletenessPage.tsx
client/src/pages/GraphPage.tsx
client/src/pages/NetworkOverviewPage.tsx
client/src/pages/NodePage.tsx
client/src/pages/NotFoundPage.tsx
client/src/pages/OverviewPage.tsx
client/src/pages/ResiliencePage.tsx
client/src/pages/RoutesPage.tsx
client/src/pages/RulesPage.tsx
client/src/pages/TimePage.tsx
client/src/pages/TopPage.tsx
client/src/pages/UploadPage.tsx
client/src/router.tsx
client/tsconfig.app.json
client/tsconfig.json
client/tsconfig.node.json
client/vite.config.ts
docs/METHODOLOGY.md
docs/PIPELINE_CONTRACT.md
docs/README_REQUIREMENTS.md
docs/solution-diagram.svg
experiments/probe-0.ipynb
out/clusters.csv
out/edge_metrics.csv
out/node_metrics.csv
out/node_metrics.json
out/nodes_roles.csv
out/sensitivity.md
out/top_nodes.csv
package.json
pipeline/.gitignore
pipeline/README.md
pipeline/RULES.md
pipeline/eval/agg_stdout.txt
pipeline/eval/critique_stdout.txt
pipeline/eval/critique_theses.md
pipeline/eval/evidence_check.py
pipeline/eval/evidence_code_issues.csv
pipeline/eval/evidence_code_issues_v3.csv
pipeline/eval/evidence_llm_issues.csv
pipeline/eval/evidence_llm_issues_v3.csv
pipeline/eval/evidence_stdout.txt
pipeline/eval/jury.py
pipeline/eval/jury_report.md
pipeline/eval/jury_report_v3.md
pipeline/eval/llm.py
pipeline/eval/question_themes.json
pipeline/eval/question_themes_v3.json
pipeline/eval/raw/critique.json
pipeline/eval/raw/evid_000.json
pipeline/eval/raw/evid_001.json
pipeline/eval/raw/evid_002.json
pipeline/eval/raw/evid_003.json
pipeline/eval/raw/evid_004.json
pipeline/eval/raw/evid_005.json
pipeline/eval/raw/evid_006.json
pipeline/eval/raw/evid_007.json
pipeline/eval/raw/evid_008.json
pipeline/eval/raw/evid_009.json
pipeline/eval/raw/evid_010.json
pipeline/eval/raw/evid_011.json
pipeline/eval/raw/evid_012.json
pipeline/eval/raw/evid_013.json
pipeline/eval/raw/evid_014.json
pipeline/eval/raw/evid_015.json
pipeline/eval/raw/evid_016.json
pipeline/eval/raw/evid_017.json
pipeline/eval/raw/evid_018.json
pipeline/eval/raw/evid_019.json
pipeline/eval/raw/evid_020.json
pipeline/eval/raw/evid_021.json
pipeline/eval/raw/evid_022.json
pipeline/eval/raw/evid_023.json
pipeline/eval/raw/evid_024.json
pipeline/eval/raw/evid_025.json
pipeline/eval/raw/evid_026.json
pipeline/eval/raw/evid_027.json
pipeline/eval/raw/evid_028.json
pipeline/eval/raw/evid_029.json
pipeline/eval/raw/evid_030.json
pipeline/eval/raw/evid_031.json
pipeline/eval/raw/evid_032.json
pipeline/eval/raw/evid_033.json
pipeline/eval/raw/evid_034.json
pipeline/eval/raw/evid_035.json
pipeline/eval/raw/evid_036.json
pipeline/eval/raw/evid_037.json
pipeline/eval/raw/evid_038.json
pipeline/eval/raw/evid_039.json
pipeline/eval/raw/evid_040.json
pipeline/eval/raw/evid_041.json
pipeline/eval/raw/evid_042.json
pipeline/eval/raw/evid_043.json
pipeline/eval/raw/evid_044.json
pipeline/eval/raw/evid_045.json
pipeline/eval/raw/evid_046.json
pipeline/eval/raw/evid_047.json
pipeline/eval/raw/evid_048.json
pipeline/eval/raw/evid_049.json
pipeline/eval/raw/evid_050.json
pipeline/eval/raw/evid_051.json
pipeline/eval/raw/evid_052.json
pipeline/eval/raw/evid_053.json
pipeline/eval/raw/evid_054.json
pipeline/eval/raw/evid_055.json
pipeline/eval/raw/evid_056.json
pipeline/eval/raw/mismatch_v2rules/evid_000.json
pipeline/eval/raw/mismatch_v2rules/evid_001.json
pipeline/eval/raw/mismatch_v2rules/evid_002.json
pipeline/eval/raw/mismatch_v2rules/evid_003.json
pipeline/eval/raw/mismatch_v2rules/evid_004.json
pipeline/eval/raw/mismatch_v2rules/evid_005.json
pipeline/eval/raw/mismatch_v2rules/evid_006.json
pipeline/eval/raw/mismatch_v2rules/evid_007.json
pipeline/eval/raw/mismatch_v2rules/evid_008.json
pipeline/eval/raw/mismatch_v2rules/evid_009.json
pipeline/eval/raw/mismatch_v2rules/evid_010.json
pipeline/eval/raw/mismatch_v2rules/evid_011.json
pipeline/eval/raw/mismatch_v2rules/evid_012.json
pipeline/eval/raw/mismatch_v2rules/evid_013.json
pipeline/eval/raw/mismatch_v2rules/evid_014.json
pipeline/eval/raw/mismatch_v2rules/evid_015.json
pipeline/eval/raw/mismatch_v2rules/evid_016.json
pipeline/eval/raw/mismatch_v2rules/evid_017.json
pipeline/eval/raw/mismatch_v2rules/evid_018.json
pipeline/eval/raw/mismatch_v2rules/evid_019.json
pipeline/eval/raw/mismatch_v2rules/evid_020.json
pipeline/eval/raw/mismatch_v2rules/evid_021.json
pipeline/eval/raw/mismatch_v2rules/evid_022.json
pipeline/eval/raw/mismatch_v2rules/evid_023.json
pipeline/eval/raw/mismatch_v2rules/evid_024.json
pipeline/eval/raw/mismatch_v2rules/evid_025.json
pipeline/eval/raw/mismatch_v2rules/evid_026.json
pipeline/eval/raw/mismatch_v2rules/evid_027.json
pipeline/eval/raw/mismatch_v2rules/evid_028.json
pipeline/eval/raw/mismatch_v2rules/evid_029.json
pipeline/eval/raw/mismatch_v2rules/evid_030.json
pipeline/eval/raw/mismatch_v2rules/evid_031.json
pipeline/eval/raw/mismatch_v2rules/evid_032.json
pipeline/eval/raw/mismatch_v2rules/evid_033.json
pipeline/eval/raw/mismatch_v2rules/evid_034.json
pipeline/eval/raw/mismatch_v2rules/evid_035.json
pipeline/eval/raw/mismatch_v2rules/evid_036.json
pipeline/eval/raw/mismatch_v2rules/evid_037.json
pipeline/eval/raw/mismatch_v2rules/evid_038.json
pipeline/eval/raw/mismatch_v2rules/evid_039.json
pipeline/eval/raw/mismatch_v2rules/evid_040.json
pipeline/eval/raw/mismatch_v2rules/evid_041.json
pipeline/eval/raw/mismatch_v2rules/evid_042.json
pipeline/eval/raw/mismatch_v2rules/evid_043.json
pipeline/eval/raw/mismatch_v2rules/evid_044.json
pipeline/eval/raw/mismatch_v2rules/evid_045.json
pipeline/eval/raw/mismatch_v2rules/evid_046.json
pipeline/eval/raw/mismatch_v2rules/evid_047.json
pipeline/eval/raw/mismatch_v2rules/evid_048.json
pipeline/eval/raw/mismatch_v2rules/evid_049.json
pipeline/eval/raw/mismatch_v2rules/evid_050.json
pipeline/eval/raw/mismatch_v2rules/evid_051.json
pipeline/eval/raw/mismatch_v2rules/evid_052.json
pipeline/eval/raw/mismatch_v2rules/evid_053.json
pipeline/eval/raw/mismatch_v2rules/evid_054.json
pipeline/eval/raw/mismatch_v2rules/evid_055.json
pipeline/eval/raw/mismatch_v2rules/evid_056.json
pipeline/eval/raw/mismatch_v2rules/evidence_llm_issues.csv
pipeline/eval/raw/mismatch_v2rules/evidence_stdout.txt
pipeline/eval/raw/mismatch_v2rules/question_themes.json
pipeline/eval/raw/mismatch_v2rules/sim_100000000331309100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000000343175100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000000437046100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000000456947100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000000594783100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000000896111100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000001285440100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000001330685100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000001857829100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000001899164100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000002028158100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000002398779100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000002433697100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000002443664100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000002527114100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000002578405100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000002838861100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000002894076100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000002952756100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000002964966100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000003016635100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000003057225100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000003071930100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000003111305100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000003115284100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000003684369100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000003701161100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000003736419100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000003880331100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000004015047100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000004070318100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000004156082100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000004174835100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000004299488100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000004351795100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000004394765100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000004400305100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000004403675100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000004798515100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000004820260100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000004892144100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000004948177100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000005382566100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000005514161100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000005550592100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000005910114100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000005933757100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000006274203100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000006866783100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000007034089100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000007055802100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000007347733100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000008086440100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000008144528100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000008304139100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000008324800100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000008346837100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000008465789100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000008477350100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000008560717100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000008561016100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000008566737100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000008603629100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000008666075100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000008686313100.json
pipeline/eval/raw/mismatch_v2rules/sim_100000008745676100.json
pipeline/eval/raw/mismatch_v2rules/sim_results.json
pipeline/eval/raw/mismatch_v2rules/sim_stdout.txt
pipeline/eval/raw/mismatch_v2rules/sim_table.csv
pipeline/eval/raw/probe.json
pipeline/eval/raw/question_themes.json
pipeline/eval/raw/sim_100000000331309100.json
pipeline/eval/raw/sim_100000000343175100.json
pipeline/eval/raw/sim_100000000437046100.json
pipeline/eval/raw/sim_100000000456947100.json
pipeline/eval/raw/sim_100000000594783100.json
pipeline/eval/raw/sim_100000000896111100.json
pipeline/eval/raw/sim_100000001285440100.json
pipeline/eval/raw/sim_100000001330685100.json
pipeline/eval/raw/sim_100000001857829100.json
pipeline/eval/raw/sim_100000001899164100.json
pipeline/eval/raw/sim_100000002028158100.json
pipeline/eval/raw/sim_100000002398779100.json
pipeline/eval/raw/sim_100000002433697100.json
pipeline/eval/raw/sim_100000002443664100.json
pipeline/eval/raw/sim_100000002527114100.json
pipeline/eval/raw/sim_100000002578405100.json
pipeline/eval/raw/sim_100000002838861100.json
pipeline/eval/raw/sim_100000002894076100.json
pipeline/eval/raw/sim_100000002952756100.json
pipeline/eval/raw/sim_100000002964966100.json
pipeline/eval/raw/sim_100000003016635100.json
pipeline/eval/raw/sim_100000003057225100.json
pipeline/eval/raw/sim_100000003071930100.json
pipeline/eval/raw/sim_100000003111305100.json
pipeline/eval/raw/sim_100000003115284100.json
pipeline/eval/raw/sim_100000003684369100.json
pipeline/eval/raw/sim_100000003701161100.json
pipeline/eval/raw/sim_100000003736419100.json
pipeline/eval/raw/sim_100000003880331100.json
pipeline/eval/raw/sim_100000004015047100.json
pipeline/eval/raw/sim_100000004070318100.json
pipeline/eval/raw/sim_100000004156082100.json
pipeline/eval/raw/sim_100000004174835100.json
pipeline/eval/raw/sim_100000004299488100.json
pipeline/eval/raw/sim_100000004351795100.json
pipeline/eval/raw/sim_100000004394765100.json
pipeline/eval/raw/sim_100000004400305100.json
pipeline/eval/raw/sim_100000004403675100.json
pipeline/eval/raw/sim_100000004798515100.json
pipeline/eval/raw/sim_100000004820260100.json
pipeline/eval/raw/sim_100000004892144100.json
pipeline/eval/raw/sim_100000004948177100.json
pipeline/eval/raw/sim_100000005382566100.json
pipeline/eval/raw/sim_100000005514161100.json
pipeline/eval/raw/sim_100000005550592100.json
pipeline/eval/raw/sim_100000005910114100.json
pipeline/eval/raw/sim_100000005933757100.json
pipeline/eval/raw/sim_100000006274203100.json
pipeline/eval/raw/sim_100000006866783100.json
pipeline/eval/raw/sim_100000007034089100.json
pipeline/eval/raw/sim_100000007055802100.json
pipeline/eval/raw/sim_100000007347733100.json
pipeline/eval/raw/sim_100000008086440100.json
pipeline/eval/raw/sim_100000008144528100.json
pipeline/eval/raw/sim_100000008304139100.json
pipeline/eval/raw/sim_100000008324800100.json
pipeline/eval/raw/sim_100000008346837100.json
pipeline/eval/raw/sim_100000008465789100.json
pipeline/eval/raw/sim_100000008477350100.json
pipeline/eval/raw/sim_100000008560717100.json
pipeline/eval/raw/sim_100000008561016100.json
pipeline/eval/raw/sim_100000008566737100.json
pipeline/eval/raw/sim_100000008603629100.json
pipeline/eval/raw/sim_100000008666075100.json
pipeline/eval/raw/sim_100000008686313100.json
pipeline/eval/raw/sim_100000008745676100.json
pipeline/eval/raw_v3/evid_000.json
pipeline/eval/raw_v3/evid_001.json
pipeline/eval/raw_v3/evid_002.json
pipeline/eval/raw_v3/evid_003.json
pipeline/eval/raw_v3/evid_004.json
pipeline/eval/raw_v3/evid_005.json
pipeline/eval/raw_v3/evid_006.json
pipeline/eval/raw_v3/evid_007.json
pipeline/eval/raw_v3/evid_008.json
pipeline/eval/raw_v3/evid_009.json
pipeline/eval/raw_v3/evid_010.json
pipeline/eval/raw_v3/evid_011.json
pipeline/eval/raw_v3/evid_012.json
pipeline/eval/raw_v3/evid_013.json
pipeline/eval/raw_v3/evid_014.json
pipeline/eval/raw_v3/evid_015.json
pipeline/eval/raw_v3/evid_016.json
pipeline/eval/raw_v3/evid_017.json
pipeline/eval/raw_v3/evid_018.json
pipeline/eval/raw_v3/evid_019.json
pipeline/eval/raw_v3/evid_020.json
pipeline/eval/raw_v3/evid_021.json
pipeline/eval/raw_v3/evid_022.json
pipeline/eval/raw_v3/evid_023.json
pipeline/eval/raw_v3/evid_024.json
pipeline/eval/raw_v3/evid_025.json
pipeline/eval/raw_v3/evid_026.json
pipeline/eval/raw_v3/evid_027.json
pipeline/eval/raw_v3/evid_028.json
pipeline/eval/raw_v3/evid_029.json
pipeline/eval/raw_v3/evid_030.json
pipeline/eval/raw_v3/evid_031.json
pipeline/eval/raw_v3/evid_032.json
pipeline/eval/raw_v3/evid_033.json
pipeline/eval/raw_v3/evid_034.json
pipeline/eval/raw_v3/evid_035.json
pipeline/eval/raw_v3/evid_036.json
pipeline/eval/raw_v3/evid_037.json
pipeline/eval/raw_v3/evid_038.json
pipeline/eval/raw_v3/evid_039.json
pipeline/eval/raw_v3/evid_040.json
pipeline/eval/raw_v3/evid_041.json
pipeline/eval/raw_v3/evid_042.json
pipeline/eval/raw_v3/evid_043.json
pipeline/eval/raw_v3/evid_044.json
pipeline/eval/raw_v3/evid_045.json
pipeline/eval/raw_v3/evid_046.json
pipeline/eval/raw_v3/evid_047.json
pipeline/eval/raw_v3/evid_048.json
pipeline/eval/raw_v3/evid_049.json
pipeline/eval/raw_v3/evid_050.json
pipeline/eval/raw_v3/evid_051.json
pipeline/eval/raw_v3/evid_052.json
pipeline/eval/raw_v3/evid_053.json
pipeline/eval/raw_v3/evid_054.json
pipeline/eval/raw_v3/evid_055.json
pipeline/eval/raw_v3/evid_056.json
pipeline/eval/raw_v3/question_themes.json
pipeline/eval/raw_v3/sim_100000000343175100.json
pipeline/eval/raw_v3/sim_100000000437046100.json
pipeline/eval/raw_v3/sim_100000000552584100.json
pipeline/eval/raw_v3/sim_100000000706545100.json
pipeline/eval/raw_v3/sim_100000001072022100.json
pipeline/eval/raw_v3/sim_100000001164648100.json
pipeline/eval/raw_v3/sim_100000001169666100.json
pipeline/eval/raw_v3/sim_100000001609499100.json
pipeline/eval/raw_v3/sim_100000002173161100.json
pipeline/eval/raw_v3/sim_100000002433697100.json
pipeline/eval/raw_v3/sim_100000002443664100.json
pipeline/eval/raw_v3/sim_100000002738256100.json
pipeline/eval/raw_v3/sim_100000002753146100.json
pipeline/eval/raw_v3/sim_100000002838861100.json
pipeline/eval/raw_v3/sim_100000002872399100.json
pipeline/eval/raw_v3/sim_100000002883402100.json
pipeline/eval/raw_v3/sim_100000002894076100.json
pipeline/eval/raw_v3/sim_100000002939838100.json
pipeline/eval/raw_v3/sim_100000002956769100.json
pipeline/eval/raw_v3/sim_100000003016635100.json
pipeline/eval/raw_v3/sim_100000003071930100.json
pipeline/eval/raw_v3/sim_100000003097324100.json
pipeline/eval/raw_v3/sim_100000003115284100.json
pipeline/eval/raw_v3/sim_100000003134474100.json
pipeline/eval/raw_v3/sim_100000003221384100.json
pipeline/eval/raw_v3/sim_100000003404627100.json
pipeline/eval/raw_v3/sim_100000003684369100.json
pipeline/eval/raw_v3/sim_100000003701161100.json
pipeline/eval/raw_v3/sim_100000003747133100.json
pipeline/eval/raw_v3/sim_100000003798151100.json
pipeline/eval/raw_v3/sim_100000003880331100.json
pipeline/eval/raw_v3/sim_100000004015047100.json
pipeline/eval/raw_v3/sim_100000004070318100.json
pipeline/eval/raw_v3/sim_100000004071080100.json
pipeline/eval/raw_v3/sim_100000004140994100.json
pipeline/eval/raw_v3/sim_100000004159526100.json
pipeline/eval/raw_v3/sim_100000004232712100.json
pipeline/eval/raw_v3/sim_100000004299488100.json
pipeline/eval/raw_v3/sim_100000004394765100.json
pipeline/eval/raw_v3/sim_100000004399686100.json
pipeline/eval/raw_v3/sim_100000004400305100.json
pipeline/eval/raw_v3/sim_100000004403675100.json
pipeline/eval/raw_v3/sim_100000004679953100.json
pipeline/eval/raw_v3/sim_100000005382566100.json
pipeline/eval/raw_v3/sim_100000005498992100.json
pipeline/eval/raw_v3/sim_100000005514161100.json
pipeline/eval/raw_v3/sim_100000005578559100.json
pipeline/eval/raw_v3/sim_100000005778283100.json
pipeline/eval/raw_v3/sim_100000005933757100.json
pipeline/eval/raw_v3/sim_100000006518161100.json
pipeline/eval/raw_v3/sim_100000006788200100.json
pipeline/eval/raw_v3/sim_100000006866783100.json
pipeline/eval/raw_v3/sim_100000006972210100.json
pipeline/eval/raw_v3/sim_100000007055802100.json
pipeline/eval/raw_v3/sim_100000007653094100.json
pipeline/eval/raw_v3/sim_100000008074304100.json
pipeline/eval/raw_v3/sim_100000008104567100.json
pipeline/eval/raw_v3/sim_100000008165763100.json
pipeline/eval/raw_v3/sim_100000008477350100.json
pipeline/eval/raw_v3/sim_100000008547844100.json
pipeline/eval/raw_v3/sim_100000008675322100.json
pipeline/eval/raw_v3/sim_100000008686313100.json
pipeline/eval/raw_v3/sim_100000008712991100.json
pipeline/eval/raw_v3/sim_100000008730371100.json
pipeline/eval/raw_v3/sim_100000008748408100.json
pipeline/eval/report.py
pipeline/eval/report_v3.py
pipeline/eval/sample_gids.json
pipeline/eval/sample_gids_v3.json
pipeline/eval/sim_code_checks.md
pipeline/eval/sim_results.json
pipeline/eval/sim_results_v3.json
pipeline/eval/sim_stdout.txt
pipeline/eval/sim_table.csv
pipeline/eval/sim_table_v3.csv
pipeline/eval/snapshot_v1/RULES_v1.md
pipeline/eval/snapshot_v1/RULES_v2_seen_midrun.md
pipeline/eval/snapshot_v1/clusters.csv
pipeline/eval/snapshot_v1/node_metrics.json
pipeline/eval/snapshot_v1/nodes_roles.csv
pipeline/eval/snapshot_v1/top_nodes.csv
pipeline/eval/snapshot_v3/RULES_v3.md
pipeline/eval/snapshot_v3/clusters.csv
pipeline/eval/snapshot_v3/node_metrics.json
pipeline/eval/snapshot_v3/nodes_roles.csv
pipeline/eval/snapshot_v3/top_nodes.csv
pipeline/eval/tz_5_9.txt
pipeline/eval/usage.jsonl
pipeline/eval/usage_v3.jsonl
pipeline/pyproject.toml
pipeline/run.py
pipeline/sensitivity.py
pipeline/tests/test_synthetic.py
pipeline/uv.lock
railway.json
server/package.json
server/src/app.ts
server/src/data/analytics.ts
server/src/data/dataset.ts
server/src/data/load.ts
server/src/data/results.ts
server/src/data/store.ts
server/src/data/tools.ts
server/src/data/types.ts
server/src/index.ts
server/src/routes/analytics.ts
server/src/routes/assistant.ts
server/src/routes/datasets.ts
server/src/routes/graph.ts
server/src/routes/health.ts
server/src/routes/index.ts
server/src/routes/nodes.ts
server/src/routes/results.ts
server/src/routes/stats.ts
server/src/routes/transactions.ts
server/tsconfig.json
synthetic/.gitignore
synthetic/A_llm/REGISTRY.md
synthetic/A_llm/c1/actors.csv
synthetic/A_llm/c1/tx.csv
synthetic/A_llm/c2/actors.csv
synthetic/A_llm/c2/tx.csv
synthetic/A_llm/c3/actors.csv
synthetic/A_llm/c3/tx.csv
synthetic/A_llm/c4/actors.csv
synthetic/A_llm/c4/tx.csv
synthetic/A_llm/c5/actors.csv
synthetic/A_llm/c5/tx.csv
synthetic/A_llm/c6/actors.csv
synthetic/A_llm/c6/tx.csv
synthetic/A_llm/data/edges.parquet
synthetic/A_llm/data/nodes.parquet
synthetic/A_llm/data/transactions.parquet
synthetic/A_llm/ground_truth.csv
synthetic/A_llm/h/actors.csv
synthetic/A_llm/h/tx.csv
synthetic/B_abm/data/edges.parquet
synthetic/B_abm/data/nodes.parquet
synthetic/B_abm/data/transactions.parquet
synthetic/B_abm/gen.py
synthetic/B_abm/ground_truth.csv
synthetic/PROFILE.md
synthetic/REPORT.md
synthetic/SPEC.md
synthetic/audit.py
synthetic/crawl.py
synthetic/profile.py
task/HackAlem AI_ Граф денег_ восстановление финансовой структуры организованной группы по транзакционной сети.pdf
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
Ветки (7)

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

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

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