AAYMA
RU
Войти

Граф денег

Воспроизводимый офлайн-анализ AML-графа: роли для всех 2248 участников по документированным формулам, кластеры Louvain, приоритет проверки…

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

О проекте

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

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

Суть

Воспроизводимый офлайн-анализ AML-графа: роли для всех 2248 участников по документированным формулам, кластеры Louvain, приоритет проверки, Streamlit-просмотрщик и статическая версия отчёта для GitHub Pages.

Как устроено

Сырые parquet загружаются в направленный взвешенный граф NetworkX; считаются PageRank, betweenness, степени, доля крупнейшего контрагента и out/in, нормированные по 95-му процентилю. Для каждой роли проверяются условия допустимости и считается балл, выбирается максимальный (≥0,5), иначе peripheral. Louvain работает на неориентированной проекции; все пороги вынесены в config.yaml, прогон пишет run_manifest с хешами. Необязательный слой агентов на OpenAI только переписывает тексты поверх готовых чисел.

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

  • PageRank
  • betweenness centrality
  • Louvain
  • нормировка по q95
  • анализ чувствительности порогов
  • кривая устойчивости сети
  • хеш-манифест прогона

Метрики

расчёт 4.5 с (лимит ТЗ 300 с); 88 кластеров Louvain, 8 с несколькими seed; 20 тестов pytest

Особенности

Механическая проверка решения против ТЗ (tools/compliance.py), побайтовая повторяемость выгрузок, анализ чувствительности порогов и кривая разрушения сети при изъятии топ-N узлов против случайного изъятия.

Стек

Python · pandas · NumPy · PyArrow · NetworkX · PyYAML · Streamlit · Pyvis · pytest

Модели

OpenAI API


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

README

README.md

Граф денег

Какую задачу решает. Аналитику финансового мониторинга известен 81 клиент — нижний уровень цепочки. Наблюдаемая сеть их переводов — 2 248 участников. Вручную он трассирует её неделями и выбирает, кого проверять, интуитивно.

Инструмент за три секунды строит граф переводов, присваивает каждому из 2 248 участников роль по документированным правилам, разбивает сеть на группы и выдаёт ранжированный список: кого проверять первым и какие именно числа это объясняют.

На выходе — три CSV для работы и локальный экран со схемой сети, поиском по gid и карточкой участника. Данные кейса HackAlem AI, июль 2026.

Роли — гипотезы для проверки, а не утверждение о виновности; скоры не являются вероятностью нарушения. Решение о проверке принимает аналитик.

Технологии

СлойЧем сделаноЗачем именно так
РасчётPython 3.12+, pandas, NumPy, PyArrowколоночное чтение parquet и векторные метрики
ГрафNetworkX 3.7направленный взвешенный граф, PageRank, betweenness, Louvain
КонфигурацияPyYAML, config.yamlвсе пороги вынесены из кода и снабжены обоснованием
ИнтерфейсStreamlit, Pyvisлокальный экран без сервера и внешних CDN
Проверкиpytest, 20 тестовинварианты выгрузок и повторяемость
Слой агентовOpenAI API, необязательнопереписывает тексты поверх готовых чисел

Зависимости ядра закреплены точными версиями в requirements.txt, полное окружение — в requirements-lock.txt. Пакет openai вынесен в отдельный requirements-llm.txt: обязательный расчёт не должен зависеть от внешнего сервиса.

Запуск

Требуется Python 3.12+; проверено на Python 3.13. Зафиксированные NumPy, SciPy и NetworkX требуют минимум 3.12. Данные находятся в data/, исходники организаторов — в starter/.

Windows PowerShell, подготовка окружения:

python -m venv .venv
.\.venv\Scripts\python.exe -m pip install -r requirements.txt

Один запуск от сырых данных до всех результатов:

.\.venv\Scripts\python.exe run.py --data data --out out

Экран просмотра:

.\.venv\Scripts\python.exe -m streamlit run app.py

Открыть http://127.0.0.1:8501. На Linux/macOS вместо .venv\Scripts\python.exe использовать .venv/bin/python. В активированном окружении команда расчёта — python run.py. Настройки меняются через --config config.yaml. Для другого набора результатов интерфейса установить переменную GRAPH_OUT_DIR. Обязательный расчёт не использует API и не требует ключей.

Флаг --llm включает необязательный слой агентов — см. раздел «Слой агентов». Он переписывает только тексты и требует ключа OpenAI. Обязательный расчёт от него не зависит.

Не реализованы и не имитируются нулями или фиктивными ответами: HITS, поиск повторяющихся маршрутов и циклов, детекция дробления сумм.

Как проверить решение за пять минут

Шаги для проверяющего. Ключи и интернет не нужны ни на одном из них.

  1. Установить окружение — команды из раздела «Запуск» выше.
  2. Запустить расчёт: .\.venv\Scripts\python.exe run.py --data data --out out В конце печатается время. Ограничение ТЗ — 300 с, фактически 4.5 с.
  3. Проверить выгрузки в out/: nodes_roles.csv — 2 248 строк, у каждой роль, скор, кластер, приоритет и непустое обоснование; clusters.csv — строка на группу; top_nodes.csv — 20 узлов по убыванию приоритета.
  4. Запустить тесты: .\.venv\Scripts\python.exe -m pytest -q — 20 тестов.
  5. Проверить повторяемость: .\.venv\Scripts\python.exe run.py --data data --out out-check и сравнить файлы с out/ — они совпадают побайтово. Хеши входов, конфигурации и каждого артефакта записаны в out/run_manifest.json.
  6. Открыть интерфейс: .\.venv\Scripts\python.exe -m streamlit run app.py, ввести любой gid из nodes_roles.csv в поиск — видно роль, обоснование, направление потоков и всех контрагентов.
  7. Проверить объяснимость: взять gid из top_nodes.csv, открыть карточку и сверить обоснование с правилом из раздела «Как считается роль» и порогом в config.yaml.
  8. Прогнать проверку против ТЗ: .\.venv\Scripts\python.exe tools\compliance.py --out out Скрипт механически проверяет пять обязательных требований и требование раздела 9 об осторожности формулировок, и печатает результат построчно.

Результаты на предоставленных данных

ПроверкаФакт
Узлы / seed2 248 / 81
Направленные рёбра / транзакции3 119 / 4 840
Оборот наблюдаемой сети365 890 012,01 KZT
Изолированные узлы, сохранённые в выгрузке19
Обрезанные узлы на глубине 4444
Слабосвязные компоненты с изолятами / без35 / 16
Крупнейшая компонента / узлы вне неё1 877 / 371
Кластеры Louvain / из них с несколькими seed88 / 8

В ТЗ указано 352 узла вне крупнейшей компоненты: это число получается без 19 изолятов. Мы сохраняем все узлы, поэтому полное число — 371. Суммы и количество транзакций по каждой паре совпали с edges. Число 8 — фактический результат, не цель настройки алгоритма.

Гипотеза ролиУзлов
consolidator85
coordinator12
distributor56
transit42
terminal472
peripheral1 581

Нет размеченных ролей, поэтому accuracy не измерялась. Это распределение эвристических гипотез, а не оценка числа нарушителей. Изменение порогов может изменить результат.

Артефакты

Файл в out/Содержание
nodes_roles.csvВсе gid; обязательные role, role_score, cluster_id, priority_score, evidence
clusters.csvcluster_id, n_nodes, n_seed, sum_kzt_internal, top_gids, hypothesis
top_nodes.csv20 записей: rank, gid, role, priority_score, why
node_features.parquetПолные метрики, допуски ролей, пять скоров, альтернативы, ограничения и слагаемые приоритета
viewer_edges.parquetНаправленные связи из того же прогона
docs/index.htmlСтатическая версия отчёта для публикации на GitHub Pages
resilience.csvКривая разрушения сети: сколько остаётся при изъятии топ-N против случайного изъятия
run_manifest.jsonКонфигурация, хеши входа/выхода, версии, время этапов, диагностика

Дополнительные поля nodes_roles включают метрики, eligible_, score_, best_specialized_role, role_runner_up, runner_up_score, score_margin, data_limitation, next_request, priority_* и rank. Неопределённые отношения и средние при нулевом знаменателе остаются пропусками только в дополнительных полях. Обязательные поля заполнены у всех узлов, evidence ≤200 символов.

Интерфейс проверяет хеши всех артефактов и не открывает смешанные или изменённые результаты. Всё читается из одного прогона, без повторного расчёта. Ресурсы графа встроены в HTML, запросов к CDN нет. Большие int64 gid передаются в JavaScript как строки.

Статическая версия отчёта

Streamlit требует запущенного Python, чего статический хостинг не умеет. Поэтому тот же готовый прогон собирается в одну офлайн-страницу: схема сети, топ-лист с разложением приоритета, кривые устойчивости и ссылки на выгрузки.

.\.venv\Scripts\python.exe toolsuild_site.py --out out --site docs

Страница читает опубликованные CSV и ничего не пересчитывает. Внешних ресурсов нет — графики нарисованы inline-SVG, граф встроен целиком, поэтому страница открывается и без сети.

Публикация: Settings → Pages → Source: Deploy from a branch → main → /docs. Локальный предпросмотр без публикации:

cd docs; ..\.venv\Scripts\python.exe -m http.server 8600

Это дополнение к инструменту, а не замена: полноценная работа с поиском по gid, карточкой участника и ассистентом остаётся в локальном Streamlit.

Как считается роль

Обозначим N(x) = min(x / q95, 1), где q95 — 95-й процентиль положительных значений признака во всей входной выборке. Если положительных значений нет, N(x)=0. Масштабы нормировки сохранены в run_manifest.json. Это относительная шкала данной выборки.

C — доля суммы от крупнейшего входящего контрагента; R — наблюдаемый out_kzt / in_kzt. При нулевом входе C и R не определены. Степени — число направленных связей. Посредничество B — точный нормированный betweenness направленного графа без весов длин: сумма денег не считается расстоянием. Для большого графа можно задать betweenness_sample.

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

РольУсловияБалл
consolidatorНе seed, не обрыв; вход >0; ≥3 плательщиков; C≤0,75; R≤0,60,4·N(in_deg)+0,3·(1−C)+0,3·clip(1−R,0,1)
distributor≥10 получателей, в том числе допустимо для seed0,7·N(out_deg)+0,3·N(out_kzt)
transitНе seed, не обрыв; есть вход и выход; 0,8≤R≤1,20,7·max(0,1−abs(R−1)/0,2)+0,3·N(in_kzt)
terminalНе seed, не обрыв; исходящих 0; вход ≥50 000 KZT; не выполнены условия consolidator0,6+0,4·N(in_kzt)
coordinatorНе seed; есть вход и выход; depth≥2; достижим от ≥2 seed; N(B)≥0,70,7·N(B)+0,3·N(n_seed_sources)
peripheralНи одна допустимая роль не набрала 0,50 для изолята, иначе 0,49·(1−лучший специальный скор)

Если максимальный специальный скор ≥0,5, выбирается его роль. Равенства разрешаются в порядке coordinator, consolidator, distributor, transit, terminal. Специальное правило сбора с многих имеет приоритет допустимости над общим признаком отсутствия исходящих. role_runner_up — второй специальный кандидат с положительным скором; none, если его нет. Для peripheral отдельно сохраняется лучший специальный кандидат; fallback-скор — не уверенность в безвредности и не сопоставим с вероятностью. Обоснования порогов находятся в config.yaml.

Достижимость от seed исключает сам seed даже при наличии цикла. Это структурный признак: он не доказывает, что те же деньги прошли весь путь, и не проверяет временной порядок.

Кластеры и приоритет

Louvain применяется к неориентированной проекции: встречные суммы складываются; self-loop не создаёт связь между участниками и исключается из проекции, но сохраняется в оборотах. Изоляты получают собственный кластер. resolution=1, random_seed=42. Кластеры нумеруются по убыванию размера, затем по минимальному gid. Внутренний оборот — сумма исходных направленных рёбер внутри группы, каждое учитывается один раз.

priority = 0,4·role_value + 0,2·N(n_seed_sources)
         + 0,2·N(in_kzt) + 0,2·N(betweenness)

Веса ролей: coordinator 1; consolidator 0,9; distributor 0,7; transit 0,5; terminal 0,4; peripheral 0,1. При равенстве приоритета первым идёт меньший gid. Все четыре вклада видны в карточке и why. Изолят также имеет минимальный ролевой вклад: это элемент очереди обзора, не положительный сигнал о нарушении.

Чувствительность порогов

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

.\.venv\Scripts\python.exe tools\sensitivity.py --data data

Результат — out/sensitivity.csv. Что он показывает на текущих данных:

ПорогЗначениеЧто меняется
consolidator.min_in_degree2 / 3 / 4 / 5 / 8176 / 85 / 42 / 23 / 6 точек консолидации
terminal.min_in_kzt5 000 / 50 000 / 250 000 / 1 000 0001037 / 472 / 119 / 4 конечных получателя
distributor.min_out_degree5 / 10 / 20 / 6063 / 56 / 25 / 8 распределителей
coordinator.min_normalized_betweenness0.5 / 0.7 / 0.913 / 12 / 11 координаторов

Выводы, которые из этого следуют и которые мы не скрываем:

  • Координаторы устойчивы. Сдвиг порога на ±0.2 меняет состав на один узел — эта роль опирается на структуру сети, а не на удачно подобранное число.
  • Конечный получатель — самая чувствительная роль. Порог по сумме меняет её численность в 250 раз. Поэтому terminal имеет низкий вес в приоритете (0.4) и никогда не присваивается узлу, обрезанному границей обхода.
  • Порог сбора выбран шире ориентира. В примечании к ТЗ названы узлы с входящими от 8–24 плательщиков; при пороге 8 мы получили бы 6 точек консолидации. Мы взяли 3, потому что сбор от трёх независимых контрагентов уже является наблюдаемым признаком, а приоритет всё равно сортирует их по объёму и охвату. Ориентир ТЗ воспроизводится: при пороге 8 остаются ровно те узлы, о которых говорят организаторы.

Временной профиль участника

transactions.parquet содержит даты, которых нет в агрегированных рёбрах. Два участника с одинаковым месячным оборотом выглядят одинаково, пока не спросить, задержались ли деньги. Признаки считаются в src/temporal.py и попадают в nodes_roles.csv:

ПризнакСмысл
hold_daysмедиана срока между поступлением и ближайшим последующим переводом дальше
fast_pass_shareдоля исходящих сумм, ушедших в течение двух дней после поступления
fast_passбольше половины исходящих ушло быстро — признак сквозного транзита
same_day_inflowsмаксимум разных плательщиков, заплативших в один день
synchronised_inflowтрое и более плательщиков в один день — синхронность, а не совпадение
active_days, burst_ratioсколько дней участник был активен и насколько выделяется пиковый день

На предоставленных данных: срок удержания удалось наблюдать у 570 участников, медиана — 2 дня; признак сквозного транзита у 275, синхронные поступления у 38.

Эти признаки сообщаются рядом с ролью, но её не меняют. Решение осознанное: критерии ролей должны оставаться стабильными и проверяемыми, а месячная выборка одного банка слишком коротка, чтобы строить на сроках удержания само определение роли. Аналитик видит их в карточке участника как дополнительный сигнал.

Устойчивость сети: проверка самого рейтинга

Рейтинг существует, чтобы отвечать на вопрос «кого проверять первым». Значит, его нужно проверить: src/resilience.py изымает из сети верх списка и измеряет, что осталось, — и сравнивает это со случайным изъятием такого же числа участников, усреднённым по нескольким розыгрышам с фиксированными сидами.

Если бы наш порядок был неинформативным, обе кривые совпали бы. На предоставленных данных изъятие 20 участников из верха списка даёт:

ПоказательПо приоритетуСлучайноИсходно
Крупнейший связный фрагмент135118411877
Фрагментов сети (от двух участников)10118.616
Доля оборота в уцелевшем ядре63%91%94%

От ядра сети отрезается на 490 участников больше, чем при случайном изъятии того же размера. Это измеримое подтверждение, что список указывает на структуру, а не просто на крупные суммы.

Полная кривая — в out/resilience.csv и во вкладке «Устойчивость сети». Оценка описывает наблюдаемую сеть переводов за июль 2026 и не является прогнозом последствий каких-либо действий в отношении клиентов.

Слой агентов (опционально)

Ядро решения детерминированное: роли, скоры, кластеры и приоритет считает код. Слой агентов включается отдельным флагом и переписывает только тексты поверх уже посчитанных чисел.

.\.venv\Scripts\python.exe -m pip install -r requirements-llm.txt
$env:OPENAI_API_KEY = "..."
.\.venv\Scripts\python.exe run.py --data data --out out --llm

Без флага и без ключа пайплайн полон: те же три CSV, те же роли, тексты из шаблонов. Проверяющему ключ не нужен.

АгентЧто делаетПолучает от
EvidenceWriterобоснование роли для приоритетных узлов—
ClusterAnalystгипотеза назначения кластера—
PriorityExplainerобъяснение позиции в очереди проверкиEvidenceWriter
ComplianceCriticпроверка осторожности формулировок, право вернуть текствсе выше
AnalystAssistantвопрос на обычном языке → ответ по выгрузке через вызов функций—

Почему агентов несколько, а не один запрос: ComplianceCritic оценивает чужой текст со стороны и отклоняет утверждающие формулировки — требование раздела 9 ТЗ закрыто механизмом, а не инструкцией в промпте. Каждое отклонение и исправление попадает в out/llm_review.json.

Границы слоя заданы жёстко:

  • модель не присваивает роли, не считает и не меняет ни одного числа — после прогона это проверяется сравнением расчётных колонок, расхождение останавливает экспорт;
  • текст длиннее лимита ТЗ отбрасывается, остаётся офлайн-вариант — контракт выгрузки важнее красоты формулировки;
  • любая ошибка API, отсутствие ключа или пакета означают возврат к офлайн-тексту, а не падение расчёта;
  • вызовы идут только для топ-20 узлов и содержательных кластеров, не для всех 2 248 узлов.

Результат живого прогона

Слой проверен на выданном ключе, модель gpt-5.4-mini:

ПоказательЗначение
Вызовов писателей93
Текстов принято от модели91
Осталось офлайн-вариантом2
Возвратов от критика формулировок47
Время слоя40 с, полный прогон 44 с

Пример возврата, который видно в логе: черновик «Признаки узла консолидации и распределения…» критик отклонил с замечанием «вывод нужно подать как гипотезу для проверки» и переписал в «Гипотеза о сети как узле сбора…». Каждый такой случай лежит в docs/llm-run/llm_review.json — черновик, замечания критика, принятый текст.

Тексты, не уложившиеся в лимит ТЗ в 200 символов, отбрасываются и заменяются офлайн-вариантом: контракт выгрузки важнее формулировки. Поэтому писателю сообщается бюджет ниже жёсткого предела — перебор тогда всё равно укладывается.

В репозитории опубликован детерминированный прогон. out/ содержит результат обычного запуска без ключа, чтобы проверка побайтовой воспроизводимости из раздела «Как проверить решение за пять минут» сходилась. Результаты прогона со слоем агентов лежат отдельно, в docs/llm-run/.

Модель задаётся в config.yaml. Семейства моделей расходятся в параметрах — новые не принимают max_tokens и требуют max_completion_tokens, некоторые не разрешают своё значение temperature. src/ai/client.py читает имя отклонённого параметра из ответа API, переименовывает или убирает его и повторяет вызов, поэтому смена модели в конфигурации не требует правки кода.

AnalystAssistant не видит граф: он вызывает функции по готовой выгрузке (node_card, neighbours, path_between, top_by_role, collectors_for) и называет gid, на которых построен ответ. Список вызовов показывается рядом с ответом во вкладке «Ассистент».

Ограничения и следующий запрос

  • Граница depth=4 без исходящих: terminal и признаки удержания запрещены; нужен дозапрос исходящих.
  • Входящие seed неполны: балансные роли для них запрещены; нужны полные входящие.
  • Любой terminal означает только отсутствие исходящих в этой выборке, не реальный остаток на счёте.
  • Видны только внутрибанковские переводы за июль от 5 000 KZT. Мелкие, внешние и более поздние переводы неизвестны.
  • Маленькая компонента сама по себе не означает нехватку данных. Изоляты явно помечены.
  • Обзор показывает максимум 80 узлов. Поиск любого gid показывает соседей первого колена; если их больше лимита, есть уведомление и полный список прямых связей таблицей.
  • ИИ, временные признаки, устойчивость к порогам и оценка удаления узлов пока отсутствуют.

Проверки

.\.venv\Scripts\python.exe -m pip install -r requirements-dev.txt
.\.venv\Scripts\python.exe -m pytest -q
.\.venv\Scripts\python.exe run.py --data data --out out-check

20 тестов: неверные суммы/количества, неизвестный конец ребра, дубликаты, отсутствующий файл, цепь, сбор, веер, цикл, seed, обрыв, все изоляты, повторяемость при перестановке входа, целостность артефактов, отсутствие CDN, сценарии Streamlit, кривая разрушения сети, соответствие обязательным требованиям ТЗ, а также слой агентов: деградация без ключа, побайтовое совпадение выгрузок с флагом --llm и без него, обязательный проход через критика формулировок. Реальные три CSV повторного прогона совпали побайтово. Просмотр графа и поиск проверены дополнительно в Chrome. requirements-lock.txt фиксирует всё установленное окружение, включая тестовые зависимости; его можно использовать вместо requirements.txt для повторения этой среды.

Схема

flowchart LR
  A[3 файла Parquet] --> B[Проверки схем и агрегатов]
  B --> C[Направленный граф со всеми узлами]
  C --> D[Метрики и ограничения наблюдения]
  D --> E[Допустимость и скоры ролей]
  C --> F[Louvain на проекции]
  E --> G[Приоритет и объяснения]
  F --> G
  D --> T[Временной профиль из транзакций]
  T --> H
  G --> R[Устойчивость: изъятие топ-N против случайного]
  R --> H
  G --> H[3 CSV и артефакты просмотра]
  H --> I[Граф, поиск, карточка и топ-20]
  G -. флаг --llm .-> J[Агенты: тексты и критик формулировок]
  J -. только тексты .-> H

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

Текущий NetworkX и точное посредничество предназначены для объёма кейса. При росте: колоночная обработка DuckDB/Polars, графовый движок igraph/graph-tool, сэмплирование посредничества, ограничение визуализации окружением узла. Достижимость от многих seed потребует оптимизации через компоненты сильной связности и пакетные множества достижимости. Нормировки и глобальные метрики изменяются с сетью: инкрементальные расчёты требуют отдельной проверки, простое добавление новых рёбер не сохраняет автоматически старые роли. Это план развития; масштаб на миллионе узлов не тестировался.

Исходное ТЗ, план, решения, задачи. API алгоритмов сверены с NetworkX, проверка интерфейса использует Streamlit AppTest.

Если Chrome блокирует скачивание CSV

По умолчанию расчёт сохраняет nodes_roles.csv, top_nodes.csv и clusters.csv в out/. Кнопки скачивания в интерфейсе создают дополнительную копию. В боковой панели «Готовые результаты» → «Где лежат готовые CSV» показан полный путь к папке на компьютере, где запущено приложение; он учитывает GRAPH_OUT_DIR. При локальном запуске эту папку можно открыть в Проводнике.

Сообщение «Ваша организация заблокировала файл» означает ограничение скачивания политикой безопасности. Оно не свидетельствует об ошибке расчёта или CSV. Причину ограничения должен проверить администратор браузера или компьютера: Chrome поддерживает блокировку скачивания политиками. Приложение не меняет настройки защиты браузера.

Состояние работ

Все обязательные требования кейса закрыты: воспроизводимый пайплайн, роль и обоснование у каждого из 2 248 узлов, документированные критерии с порогами, кластеризация и топ-лист с экраном просмотра. Из необязательных реализованы учёт границы обхода, оценка нехватки данных, чувствительность порогов и слой агентов с ассистентом. Измерения: Windows, Python 3.13, полный прогон 4.5 с при лимите 300 с. Время импорта интерпретатора в таймер не входит; полный запуск команды — менее 6 секунд.

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

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

zhastunulani 12zhastunulani 1

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

  • 2026-09-23 17:45feat: publishable static copy of the reportzhastunulani
  • 2026-09-23 17:41feat: run the agent layer against the live API and pin what it provedzhastunulani
  • 2026-09-23 17:17test: check the solution against the brief mechanicallyzhastunulani
  • 2026-09-23 17:15feat: timing profile, network resilience check and a redesigned viewerzhastunulani
  • 2026-09-23 16:28feat: agent layer, threshold sensitivity and jury-ready READMEzhastunulani
  • 2026-09-23 15:16fix: explain blocked downloads and locate existing CSV resultszhastunulani
  • 2026-09-23 15:09fix: preserve artifact hashes across Windows checkoutszhastunulani
  • 2026-09-23 15:09feat: implement reproducible offline graph analysis and viewerzhastunulani
Все коммиты (12)
  • 2026-09-23 14:45Merge remote-tracking branch 'origin/main'zhastunulani
  • 2026-09-23 14:45docs: refine implementation plan and analytical contractszhastunulani
  • 2026-09-23 14:41Add files via uploadzhastunulani
  • 2026-09-23 14:371zhastunulani
Структура репозитория (76 файлов)
.gitattributes
.gitignore
.streamlit/config.toml
AGENTS.md
ARCHITECTURE.md
CASE-TZ.md
CASE.md
CODEX-TASKS.md
DECISIONS.md
DEMO.md
PITCH.md
PLAN.md
PRODUCT.md
README.md
README.template.md
app.py
config.yaml
data/README.md
data/edges.parquet
data/nodes.parquet
data/transactions.parquet
docs/.nojekyll
docs/data/clusters.csv
docs/data/nodes_roles.csv
docs/data/resilience.csv
docs/data/top_nodes.csv
docs/graph.html
docs/index.html
docs/llm-run/llm_review.json
docs/llm-run/summary.json
out/clusters.csv
out/node_features.parquet
out/nodes_roles.csv
out/resilience.csv
out/run_manifest.json
out/sensitivity.csv
out/top_nodes.csv
out/viewer_edges.parquet
pytest.ini
requirements-dev.txt
requirements-llm.txt
requirements-lock.txt
requirements.txt
run.py
src/__init__.py
src/ai/__init__.py
src/ai/agents.py
src/ai/client.py
src/ai/orchestrator.py
src/ai/tools.py
src/clusters.py
src/config.py
src/export.py
src/features.py
src/gaps.py
src/graph.py
src/load.py
src/narrate.py
src/priority.py
src/resilience.py
src/roles.py
src/temporal.py
src/ui.py
src/viewer.py
starter/README.md
starter/requirements.txt
starter/starter.py
tests/test_ai_layer.py
tests/test_app.py
tests/test_compliance.py
tests/test_pipeline.py
tests/test_result_access.py
tools/__init__.py
tools/build_site.py
tools/compliance.py
tools/sensitivity.py

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

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

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