AAYMA
RU
Войти

Windcast

Agentic-система для диспетчера ВЭС: сама берёт архивный прогноз погоды, считает почасовую выработку на 48 ч с коридором P10–P90, флагует риски и…

Доведённый продукт
Команда «Pushin’ Code» 81💬 0 комментариевс 22 сентября 2026 г.

О проекте

Команда: Pushin’ Code
Кейс HackAlem.ai: Энергетика — Самрук-Казына
Стадия: Доведённый продукт

Задача кейса: AI-агент, прогнозирующий выработку ветровой электростанции по погодным данным

Суть

Agentic-система для диспетчера ВЭС: сама берёт архивный прогноз погоды, считает почасовую выработку на 48 ч с коридором P10–P90, флагует риски и решает о пересчёте; февраль 2026 воспроизведён 29 выпусками без заглядывания в будущее.

Как устроено

SCADA 10 мин агрегируется в часовой ряд с флагом valid; квантильная модель HistGradientBoosting (P10/P50/P90) обучена на архивных прогнозах погоды против факта. LLM-агент (gpt-5.4-mini, function calling) проходит цикл инструментов fetch_weather (Open-Meteo Previous Runs API/кэш) → check_data → run_model → analyze_forecast (рампы, обледенение, ветер >20 м/с, расхождение моделей) → recalc_forecast → publish_forecast; числа считает только модель, правило «без будущего» — код. В Live-режиме watcher будит агента каждые 30 минут; без ключа работает детерминированный режим.

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

  • HistGradientBoosting quantile regression
  • P10/P50/P90
  • Open-Meteo Previous Runs API
  • function calling
  • backtest
  • persistence/power-curve baselines
  • SSE
  • scheduled watcher

Метрики

Январь 2026: nMAE 15,8% против 19,4% (кривая мощности) и 36,5% (персистентность); независимая часть 8–31.01 — 16,8%; факт в P10–P90 в 80,5% часов

Особенности

Строгое правило «без будущего» (учёт задержки публикации прогонов) с верификатором scripts/verify.py; агент сам решает, пересчитывать ли при новом прогоне; ленты решений в outputs/traces; развёрнутое демо без регистрации.

Стек

Python · FastAPI · scikit-learn · React · Docker Compose · Caddy

Модели

gpt-5.4-mini


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

README

README.md

Windcast — агент прогноза выработки ВЭС на 48 часов

Windcast — Agentic AI-система для диспетчера ветроэлектростанции: к каждому моменту выпуска агент сам берёт архивный прогноз погоды, опубликованный до этого момента, считает выработку на 48 часов с вероятным диапазоном, находит риски, при выходе нового прогона решает, пересчитывать ли, и публикует выпуск. Февраль 2026 воспроизведён день за днём — 29 выпусков с 31.01 по 28.02, без единого взгляда в будущее; в Live агент работает сам.

Демо без регистрации: https://pushin.codes · Трек: «Энергетика», HackAlem AI, 23.09.2026 · Команда: Pushin' Code

Проверяющему: 5 минут

ЧтоГде
Что этоАгент диспетчера ВЭС: сам берёт архивный прогноз погоды, опубликованный до момента выпуска, считает выработку на 48 ч с вероятным диапазоном, ищет риски, решает о пересчёте при новом прогоне, публикует выпуск
Запускgit clone … && docker compose up --build → http://localhost:8080 (ключ OpenAI не нужен) — § 6
Проверка честностиpython3 scripts/verify.py → PASS: 29 выпусков, 4176 строк, каждый прогон погоды опубликован до момента выпуска — § 4
Результатыoutputs/forecasts/{D}.csv (29 выпусков 31.01–28.02) и outputs/evaluation/february_day_ahead.csv — один прогноз на каждый час февраля; оценить одной командой: python3 scripts/score.py --actual <папка с фактом> — § 9
ТочностьЯнварь (факт есть): nMAE 15,8 % против 19,4 % у кривой мощности и 36,5 % у персистентности; независимая часть 8–31.01 — 16,8 %; факт в вероятном диапазоне в 80,5 % часов
Где agentic AIПорядок цикла из ТЗ, решение о пересчёте, реакция на сбой и сводка — LLM (gpt-5.4-mini, function calling); числа — только модель; правило «без будущего» — код; ленты решений — outputs/traces/ — § 3.2
Демо без регистрацииhttps://pushin.codes — кнопка «Как проверить за 3 минуты» в шапке; чат «Спросить агента» справа внизу
Честные ограниченияФакта за февраль нет; в архиве событие «новый прогон» объявляет код; одна погодная модель — § 12

Быстрый старт

git clone https://github.com/BAITC-Hacks/hack-07de2d2d-pushin-code && cd hack-07de2d2d-pushin-code
cp .env.example .env              # необязательно: без OPENAI_API_KEY агент работает детерминированно
docker compose up --build         # первая сборка — несколько минут; затем открыть http://localhost:8080
curl http://localhost:8080/health # в другом терминале: {"ok":true,…,"issues_ready":29,"ports":{…"real"}}
python3 scripts/verify.py         # из корня клона, только стандартная библиотека → PASS (14 проверок)
python3 scripts/score.py --actual <папка с turbine_1.csv и turbine_2.csv>  # точность февраля, § 9

Как проверить за 3 минуты — § 8. Без Docker — § 6.3. Что проверяет verify.py — § 4. Цифры качества — § 9. Этот путь проверен 23.09 в 16:17 на свежем клоне с GitHub без .env — § 6.5.

Содержание: 1 Описание · 2 Соответствие задаче · 3 Архитектура · 4 Без будущего · 5 Технологии · 6 Установка и запуск · 7 Окружение · 8 Проверка · 9 Результаты · 10 Структура · 11 Сторонние компоненты · 12 Ограничения · 13 Команда


1. Описание решения и назначение

Для кого. Для диспетчера ВЭС. Каждый день он заявляет почасовой график выработки на следующие сутки, а отклонение факта от графика даёт небаланс: его покрывают резервом и за него платят. Выработка ветровой станции целиком зависит от погоды, поэтому одной цифры диспетчеру мало. Ему нужны ещё оценка неопределённости и предупреждения о рискованных часах.

Что получает диспетчер в каждом выпуске — 48 часов × {турбина 1, турбина 2, ВЭС}:

  • P50 — ожидаемая выработка в долях номинала;
  • коридор P10–P90: на январском бэктесте факт попал в него в 80,5 % часов (цель ≈ 80 %). P10 — осторожная оценка для заявки, а ширина коридора показывает риск;
  • флаги на оси времени: рампа (изменение ≥ 30 % номинала за 2 ч), обледенение (температура от −3 до +1 °C не меньше 2 ч подряд), ветер > 20 м/с, расхождение погодных моделей, скачок против прошлой версии;
  • сводку простым языком и строку «что изменилось», если прогноз пересчитан;
  • CSV выпуска для своих систем.

Выигрыш на январе 2026: nMAE модели 15,8 % номинала против 19,4 % у лучшей простой базовой линии (кривая мощности по прогнозному ветру) — ошибка меньше на 18,5 %; против персистентности («завтра как сегодня», 36,5 %) — меньше в 2,3 раза. Подробности и остальные метрики — § 9.

Что агент делает сам. Полный цикл из ТЗ, этап за этапом:

  1. Получение внешних погодных данных — fetch_weather: Open-Meteo по координатам ВЭС, только прогоны, опубликованные до момента выпуска. Без сети берёт сохранённые ответы из data/weather_cache/.
  2. Подготовка данных — check_data: 48 часов без пропусков, значения конечные, все прогоны опубликованы до момента выпуска.
  3. Запуск модели — run_model.
  4. Формирование почасового прогноза: P10/P50/P90 × 48 ч × {1, 2, ВЭС}.
  5. Анализ результата — analyze_forecast: флаги рисков и сводка.
  6. Повторный расчёт при обновлении входных данных — recalc_forecast. Когда выходит более свежий прогон, агент сравнивает его с прежним и решает сам: пересчитать (версия v2) или объяснить, почему пересчёт не нужен. Если прогон вышел бы после момента выпуска, код откажет в пересчёте.

Цикл завершается действием publish_forecast: агент записывает CSV, запись выпуска и ленту шагов. Порядок шагов и решения — за LLM (OpenAI, function calling), числа прогноза считает только модель (кто что решает — § 3.2).

Без человека. В режиме Live бэкенд сам будит агента раз в 30 минут: тот проверяет, вышел ли новый прогон, решает, выпускать ли новую версию, и записывает итог в журнал (GET /api/live/journal, вкладка «Live»). Если источник погоды отказал, агент повторяет запрос, а при недоступности API берёт кэш и предупреждает о сниженном доверии к выпуску.

Демо-доступ (п. 5.6.6). https://pushin.codes открывается без регистрации и личных аккаунтов. Агент там работает в режиме LLM на ключе OpenAI команды (§ 6.6). Для локального запуска ключ не нужен: без него агент проходит тот же цикл в детерминированном режиме и выдаёт те же числа.

Скриншоты с https://pushin.codes — вкладки «Февраль 2026», «Live» и «Качество»:

Вкладка «Февраль 2026»: календарь выпусков, график и панель агента Вкладка «Live»: прогноз от текущего момента и журнал агента Вкладка «Качество»: январь против базовых линий

2. Как это соответствует задаче

Текст ТЗ — docs/hackathon/task.md.

Требование ТЗКак сделаноГде в кодеКак проверить
Модель почасовой выработки на исторических данныхSCADA 10 мин → часовой ряд в UTC с флагом valid (пропуски, простои и отключение Т1 в 05–07.2024 исключены). Квантильная модель P10/P50/P90 (scikit-learn HistGradientBoosting) учится на архивных прогнозах погоды против фактической мощности; для сравнения — три базовые линииbackend/windcast/data.py, model.py, evaluate.pypython -m windcast.data; python -m windcast.evaluate; вкладка «Качество»; outputs/metrics_jan.json
Сама получает по координатам ВЭС из открытых источников прогнозы погоды, доступные на момент прогнозированияfetch_weather сам запрашивает Open-Meteo Previous Runs API по обеим координатам и берёт только прогоны, опубликованные до момента выпуска T (§ 4). Источник api или cache пишется в каждое событиеweather.py, tools.py, timeline.pyкнопка «✓ Без будущего»; meta.source в ленте шагов; weather_runs в GET /api/forecasts/{D}
Прогноз на 24–48 ч с почасовой детализацией48 часов: h = 1…48, то есть (D+1) 00:00 … (D+2) 23:00 по UTC+5, для турбин 1, 2 и ВЭС, P10/P50/P90model.py, outputs/forecasts/{D}.csv (§ 9)verify.py: 144 строки в каждом выпуске
Agentic AI: система сама выполняет полный циклАгент с шестью инструментами: LLM выбирает следующий шаг, каждый шаг — событие с этапом meta.stage. В Live агент запускается сам по расписанию и ведёт журналagent.py, tools.py, watcher.pyпанель агента: этапы загораются по очереди; outputs/traces/{D}.jsonl; GET /api/live/journal
→ получение внешних погодных данныхfetch_weathertools.py, weather.pyэтап «погода» (meta.stage = weather)
→ подготовка данныхcheck_datatools.py, data.pyэтап «подготовка» (prep)
→ запуск моделиrun_modeltools.py, model.pyэтап «модель» (model)
→ формирование почасового прогнозарезультат run_model: 144 строки P10/P50/P90tools.py, store.pyэтап «прогноз» (forecast)
→ анализ результатаanalyze_forecast: флаги рисков и сводкаtools.pyэтап «анализ» (analysis)
→ повторный расчёт при обновлении входных данныхвышел новый прогон → агент решает → recalc_forecast → v2 или «пересчёт не нужен»agent.py, tools.pyэтап «пересчёт» (recalc); «↻ Перевыпустить агентом», «⚡ Новый прогон погоды»
Воспроизвести, как в прошлом: 31.01, затем 01.02 и далее последовательноВыпуск D делается в момент T = (D+1) 00:00 местного. D = 31.01 … 28.02 — 29 выпусков подряд, каждый прошёл полный цикл агентаbacktest.py, timeline.issue_dates()календарь из 29 выпусков; «▶ Воспроизвести февраль»; verify.py
Только архивные прогнозы, доступные на тот момент, а не фактПравило init + 8 ч ≤ T. В признаках нет факта, реанализа и SCADA. В каждой строке CSV есть weather_init_max_utctimeline.py, weather.py, tools.py, scripts/verify.pypython3 scripts/verify.py → «Без будущего» ✓ 4176/4176 строк, 174/174 прогонов

Каждый день 01–28.02 покрыт выпуском накануне (h 1–24), а начиная с 02.02 ещё и выпуском за двое суток (h 25–48). Выпуск от 28.02 (на 01–02.03) закрывает второе прочтение ТЗ: «повторить прогнозирование в течение тестового периода».

3. Архитектура

Браузер ──► Caddy   (локально http://localhost:8080 · прод https://pushin.codes)
              ├── /                ──► frontend :3000   React + Vite, отдаёт nginx: «Февраль», «Live», «Качество»
              └── /api/*, /health  ──► backend  :8000   FastAPI: REST + SSE-поток шагов агента
                                             │
   кнопка или POST /api/runs,                ▼
   CLI windcast.backtest,       ──►  агент: ≤ 8 вызовов инструментов ◄──► OpenAI API
   Live-наблюдатель раз в 30 мин     LLM выбирает шаг; без ключа — те же шаги по правилам
                                             │ вызывает
      fetch_weather ─────► Open-Meteo API по координатам ВЭС (без сети — data/weather_cache/)
      check_data ────────► 48 ч без пропусков, все прогоны опубликованы до момента выпуска T
      run_model ─────────► models/quantile_*.pkl → P10/P50/P90 × 48 ч × {турбина 1, турбина 2, ВЭС}
      analyze_forecast ──► рампы, обледенение, ветер > 20 м/с, скачок против прошлой версии
      recalc_forecast ───► вышел более свежий прогон → пересчёт → v2; поздний прогон — отказ кода
      publish_forecast ──► действие: outputs/forecasts/{D}.csv + {D}.json, outputs/traces/{D}.jsonl
                                             │
      API и экран читают только эти файлы ◄──┘  (февраль открывается уже посчитанным)

Подробная схема с диаграммой последовательности — docs/architecture.html (открыть в браузере). Спецификация API и форматов — docs/CONTRACT.md (v0.5). Swagger — http://localhost:8080/api/docs.

Модули бэкенда (backend/windcast/): agent.py — цикл агента, tools.py — шесть инструментов и их JSON-схемы для OpenAI, weather.py — Open-Meteo и кэш, model.py — квантильная модель и базовые линии, evaluate.py — январский бэктест, data.py — SCADA, store.py — атомарная запись выпусков, ports.py — подключение погоды, данных и модели к агенту, runs.py — прогоны в фоне, SSE и журнал, watcher.py — Live-наблюдатель, api.py — REST, backtest.py — CLI, timeline.py — время и правило «без будущего».

3.1 Цикл агента

  1. Прогон запускают кнопка «↻ Перевыпустить агентом», POST /api/runs, CLI windcast.backtest или Live-наблюдатель. Бэкенд ведёт прогон в фоновом потоке и отдаёт каждое событие на экран по SSE (GET /api/runs/{id}/events).
  2. v1. fetch_weather(run="previous") берёт прогон на сутки старше. Затем check_data, run_model, analyze_forecast и publish_forecast, который публикует v1.
  3. Вышел новый прогон. fetch_weather(run="latest") возвращает не решение, а факты: свежее ли прогон, опубликован ли он до T, средний сдвиг ветра за часы 1–24, появились ли новые риски. Решение принимает агент. Политика: пересчитывать, если прогон свежее, опубликован до T и ветер сдвинулся в среднем больше чем на 0,5 м/с или появился новый риск. Тогда recalc_forecast считает v2 со строкой «что изменилось», а publish_forecast её публикует. Иначе агент объясняет, почему v1 остаётся.
  4. «⚡ Новый прогон погоды» (trigger = new_weather_run): агент ищет прогон свежее текущего и опубликованный до T. На архивном дне, где v2 уже учла последний такой прогон, его нет, и агент объясняет: «Более свежего прогона до момента выпуска нет — v2 остаётся».
  5. Сбой источника (scenario = weather_outage имитирует отказ Open-Meteo на первом запросе). В ленте: «Источник погоды недоступен» → «Источник погоды не ответил — повторяю запрос» → «Погода получена со второй попытки — доверие к выпуску ниже обычного». Если API недоступен и при повторе, fetch_weather берёт проверенный кэш (meta.source = "cache").
  6. Лимит — 8 вызовов инструментов. Последнее событие всегда verdict. События идут по схеме docs/references/trace-event-schema.md; у каждого есть meta.stage, meta.status, meta.source, у решений — meta.by.

Так выглядит лента выпуска 13.02 (outputs/traces/2026-02-13.jsonl), сокращённо:

#ТипКтоСобытие
1thoughtкод«Выпуск 13.02: беру только погоду, опубликованную до T … Режим: агент (LLM gpt-5.4-mini)»
3tool_resultинструмент«Погода получена: 48 ч, источник api — часы 1-17 … прогон 12.02 06:00 UTC ✓ опубликован до T; …»
7tool_resultмодель«Прогноз готов: 48 ч × Т1, Т2, ВЭС · P10/P50/P90 — ВЭС: пик 98 % номинала — 15.02 18:00, минимум 1 % — 15.02 01:00, в среднем 34 %»
11actionагент«Опубликован выпуск v1»
14tool_resultинструмент«Новый прогон: свежее v1, сдвиг ветра 1,5 м/с … новых рисков: 0»
15thoughtLLM (meta.by = llm)«Пересчитываю: прогон свежее текущего, все прогоны опубликованы до T, а средний сдвиг ветра за 1–24 ч = 1.51 м/с > 0,5 м/с»
18tool_resultмодель«Пересчитал → v2: ветер +0,7 м/с → пик без изменений, в среднем +2 п.п. против v1»
20actionагент, текст LLM«Опубликован выпуск v2 · По ВЭС ожидается пик 98% номинала 15.02 в 16:00, минимум 1% 14.02 в 15:00, среднее за окно … 36% номинала. Изменение против v1: среднее выросло на 2 п.п., пик без изменений; риски — обледенение 14.02 00:00–09:00 …; держать резерв и учесть в заявке»
21verdictкод«Итог: опубликована v2 — пересчёт на свежем прогоне»

3.2 Где здесь agentic AI

КтоЧто делает
МодельСчитает все числа: P10/P50/P90 на каждый час и турбину. LLM числа не придумывает и не правит: publish_forecast принимает сводку и номер версии, а не строки прогноза.
КодГарантирует правило «без будущего» (init + 8 ч ≤ T): fetch_weather и check_data не пропускают прогон, вышедший после T, а recalc_forecast отказывает в пересчёте на позднем прогоне, что бы ни попросила LLM. Публикует сводку LLM, только если каждое число в ней есть в ответах инструментов, иначе берёт шаблонную (в феврале так было дважды: 08.02 и 25.02). Новая версия появляется только после вызова recalc_forecast: если LLM объявляет пересчёт, но не вызывает инструмент, агент напоминает один раз, а затем решает по правилу и пишет by=rule — в итоговых выпусках таких случаев нет. Держит лимит 8 вызовов. Если LLM недоступна, ошиблась или остановилась раньше, доводит цикл по тем же правилам и пишет об этом в ленту. По одной дате одновременно идёт только один прогон.
LLM (OpenAI Chat Completions, function calling, по умолчанию gpt-5.4-mini)Ведёт цикл: порядок шагов ограничен предусловиями инструментов (без погоды модель не запустить), поэтому решает LLM не «что за чем», а пересчитывать ли после нового прогона (причина пишется в ленту, meta.by = "llm"), как реагировать на сбой источника и что сказать диспетчеру. Решает, как реагировать на сбой источника погоды: повторить запрос или продолжить с предупреждением. Пишет сводку для диспетчера и строку «что изменилось».
Без ключаТот же цикл идёт по правилам (meta.by = "rule"): та же политика пересчёта, сводка по шаблону, те же числа.

Честно про февральский бэктест. В архиве событие «вышел новый прогон» не приходит извне: код объявляет его после публикации v1 (agent.py, _announce_new_run), и более свежий допустимый прогон в архиве есть всегда. Поэтому во всех 29 выпусках правило «сдвиг ветра > 0,5 м/с» дало бы то же решение, что и LLM. Вклад LLM в феврале — объяснение решения, сводка для диспетчера и обработка нештатных ситуаций (сбой источника, scenario = weather_outage); в Live событие настоящее — новые прогоны выходят четыре раза в сутки, и агент проверяет их сам.

Спросить агента. Кнопка «Спросить агента» в правом нижнем углу открывает чат диспетчера: POST /api/ask {"question": "Какие риски 14 февраля?", "issue_date": "2026-02-13"} → ответ по-русски не длиннее трёх предложений. LLM отвечает только по данным инструментов чтения (get_issue_summary, get_hours, get_weather_runs, get_agent_steps, get_quality, get_live); какие инструменты были вызваны, видно в поле tools и под ответом. Без ключа OpenAI чат отвечает сводкой выбранного выпуска; кнопка показывается только когда GET /health отдаёт "ask": true. Готовые вопросы: пик выпуска, риски, почему был пересчёт, насколько точна модель.

Агент работает без человека. Бэкенд раз в LIVE_WATCH_MINUTES минут (по умолчанию 30, 0 — выключено; первая проверка — через 10 секунд после старта) запускает агента для Live (watcher.py). Если выпуска ещё нет, агент делает его, а если есть — проверяет новый прогон и сам решает, выпускать ли новую версию. Каждый запуск Live, свой и по кнопке, пишется в outputs/live/journal.jsonl. Журнал отдаёт GET /api/live/journal?limit=20 (новые сверху): кто запустил (initiator: agent или user), итог (outcome: published, kept, refused, error), версия и фраза агента. Реальная запись наблюдателя через 10 с после старта бэкенда:

{"ts": "2026-09-23T16:12:52+05:00", "initiator": "agent", "trigger": "issue", "run_id": "r_44192848ea97",
 "outcome": "published", "version": 1, "title": "Опубликована v1 — более свежего прогона пока нет"}

GET /health показывает live_watch_minutes и live_last_check_local — когда агент проверял погоду в последний раз.

Детерминированный режим. Без OPENAI_API_KEY (или с "mode": "deterministic") агент идёт по тем же шагам и выдаёт те же числа. Текущий режим показывает GET /health → mode. Если ключа нет, запрос с "mode": "agent" тоже выполняется детерминированно, и первое событие в ленте об этом говорит. Проверено на феврале: детерминированный перевыпуск даёт те же P10/P50/P90 и тот же набор версий, что и записанные выпуски агента (§ 8.2).

Live. Для issue_date = "live" момент выпуска T — «сейчас». Погода берётся из Open-Meteo Forecast API (последний вышедший прогон), окно — 48 ч от следующего полного часа.

3.3 Модель и методика

  • Данные. SCADA двух турбин, 10-минутные записи с 11.03.2023 по 31.01.2026 23:50, превращаются в часовые средние в UTC (python -m windcast.data → data/processed/hourly.parquet). Час помечается valid = false, если он неполный (меньше 6 записей), если это простой (мощность меньше 0,02 при ветре больше 5 м/с) или если он попал в 18.05–17.07.2024 у турбины 1 (≈ 60 дней пропусков). Валидных часов: турбина 1 — 92,4 %, турбина 2 — 97,0 %. Разбор данных — docs/DATA_NOTES.md.
  • Часы SCADA. Сдвиг к UTC постоянный, 5 или 6 часов. evaluate обучает обе версии и выбирает по nMAE на 1–7 января; выбрано 6 (SCADA_UTC_OFFSET_H=6), 8–31 января остались независимой проверкой: nMAE модели там 16,8 % против 36,4 % у персистентности.
  • Погода для обучения и прогноза — одна и та же: Open-Meteo Previous Runs, *_previous_day1/2 с 01.06.2024 (раньше архива нет), обе координаты турбин усреднены. Признаки только погодные и календарные: ветер на 100 м и 10 м, ветер³, sin/cos направления, температура, местный час и месяц, горизонт h, turbine_id (1, 2, 3 = ВЭС), lag_days (1 или 2; прогоны на 3–4 суток для часов 42–48 используют поведение лага 2). SCADA в признаках нет: в феврале её нет. Так модель заодно учит ошибку погодной модели на той же заблаговременности, с которой работает в прогнозе.
  • Цель. Часовая нормированная мощность турбины; ВЭС — отдельная цель, среднее двух турбин за часы, когда обе валидны. В обучение попадают только валидные часы, закончившиеся до границы обучения.
  • Модель: три HistGradientBoostingRegressor из scikit-learn с квантильной функцией потерь (0,1 / 0,5 / 0,9), общие для турбин и ВЭС; 160 итераций, до 15 листьев, минимум 50 наблюдений в листе, L2 = 1, шаг 0,08, random_state = 42 — обучение детерминировано. Выход обрезается в [0, 1] и упорядочивается P10 ≤ P50 ≤ P90. MODEL_VERSION = histgb-q-2026-01-31.
  • Два артефакта (по 0,9 МБ, pickle): models/quantile_2025-12-31.pkl — граница обучения 31.12.2025 19:00 UTC, 115 005 строк, для январского бэктеста; models/quantile_2026-01-31.pkl — граница 31.01.2026 19:00 UTC, 121 608 строк, для февральских выпусков. predict отказывает, если граница обучения артефакта позже момента выпуска или какой-то прогон погоды позже T.
  • Базовые линии на тех же данных: кривая мощности — изотоническая регрессия ветер → мощность, своя для лага 1 и 2, применённая к прогнозному ветру; климатология — медиана по турбине, месяцу и часу; персистентность — факт за те же часы предыдущих суток до T (где факта нет — климатология).
  • Метрики: nMAE и nRMSE по ВЭС в % номинала по всем 30 выпускам × 48 ч (1417 часов с фактом, 23 часа без валидного факта исключены), по горизонту и по дням, покрытие коридора P10–P90.
  • Честное правило стоит точности. Под правилом v0.3 (прогон годен, если стартовал до T) та же схема давала nMAE 15,0 %. Под правилом v0.4 (init + 8 ч ≤ T) часы 18–48 берут прогон на 6–24 часа старше, и ошибка выросла до 15,8 %. Мы оставили честный вариант: прогон, стартовавший в D 12:00 или 18:00 UTC, к моменту выпуска ещё не опубликован.
  • Почему погода, а не история SCADA. Лучшие модели только на истории турбин ошибаются на тех же январских выпусках в 1,7–1,9 раза сильнее (MAE 0,27–0,30 против 0,158) — см. эксперимент в § 9.

4. Правило «без будущего»

Это главная проверка задачи: прогноз на прошлую дату нельзя строить на погоде, которую тогда ещё не знали.

  • Момент выпуска. Выпуск D делается в момент T = D 19:00 UTC = (D+1) 00:00 по UTC+5, прогноз — на 48 часов после T. Внутри системы всё время в UTC, на экране и в файлах — местное UTC+5.

  • Прогон виден не сразу. Глобальные модели стартуют в 00, 06, 12 и 18 UTC; ECMWF публикует открытые данные примерно через 7–8 часов, остальные быстрее. Мы считаем прогон доступным через 8 часов после старта — это наша консервативная оценка по срокам публикации открытых данных, а не документированная гарантия провайдера; для любой модели внутри best_match она с запасом: init + 8 ч ≤ T, то есть старт не позже D 11:00 UTC. Самый свежий допустимый прогон — D 06:00 UTC (опубликован ≈ D 14:00 UTC). Архив Open-Meteo хранит прогноз по суткам давности, а не по конкретным прогонам, поэтому weather_init_max_utc — верхняя граница старта прогона (целевой час минус N суток, округлённые вниз до 00/06/12/18 UTC), а не точное время; в интерфейсе она так и подписана. Модель погоды — best_match Open-Meteo (ECMWF / ICON / GFS по выбору сервиса). Прогоны D 12:00 UTC (≈ D 20:00 UTC) и D 18:00 UTC (≈ D+1 02:00 UTC) стартовали раньше T, но вышли уже после него, поэтому запрещены.

  • Какой прогон берём на каждый час. Open-Meteo Previous Runs API отдаёт *_previous_dayN — значение из прогона, стартовавшего не позже чем за N суток до целевого часа. N подбирается по горизонту так, чтобы прогон был опубликован до T: N = timeline.lead_days(h) = ⌈(h − 1 + 8) / 24⌉.

    Горизонт hЦелевые часы (UTC+5)N (previous_dayN)v1 (прогон на сутки старше)
    1–17(D+1) 00:00 … 16:0012
    18–41(D+1) 17:00 … (D+2) 16:0023
    42–48(D+2) 17:00 … 23:0034
  • Запрещено в признаках: previous_day0, фактическая погода, реанализ, SCADA.

  • У каждой строки CSV есть weather_init_max_utc — верхняя граница старта прогона: целевой час минус N суток, округлённый вниз до 00/06/12/18 UTC (weather.py пишет её в init_time_utc каждого часа).

  • Агент это правило обойти не может. LLM выбирает только run = "previous" или "latest", а время старта вычисляет код. fetch_weather отказывает, если хоть один прогон опубликован после T, check_data проверяет это ещё раз, recalc_forecast отказывает в пересчёте на таком прогоне.

Пример: выпуск D = 13.02.2026, T = 13.02 19:00 UTC = 14.02 00:00 по UTC+5 (рассчитано timeline.py):

hЦелевой час (UTC+5)Nweather_init_max_utcОпубликован ≈≤ T?
114.02 00:0012026-02-12T18:00Z13.02 02:00 UTCда
1714.02 16:0012026-02-13T06:00Z13.02 14:00 UTCда
1814.02 17:0022026-02-12T12:00Z12.02 20:00 UTCда
4115.02 16:0022026-02-13T06:00Z13.02 14:00 UTCда
4215.02 17:0032026-02-12T12:00Z12.02 20:00 UTCда
4815.02 23:0032026-02-12T18:00Z13.02 02:00 UTCда

В записи выпуска это видно как weather_runs: часы 1-17 и 18-41 — прогон 2026-02-13T06:00Z, часы 42-48 — 2026-02-12T18:00Z, у каждого before_issue: true.

Как это доказывает scripts/verify.py. Скрипт работает на стандартной библиотеке Python ≥ 3.9 и намеренно не импортирует timeline.py: правила времени записаны в нём заново, чтобы проверка не повторяла ошибки проверяемого кода. Для каждого из 29 выпусков он проверяет:

  • в каждой строке CSV: weather_init_max_utc + 8 ч ≤ T — 4176 строк;
  • в записи {D}.json: у каждого прогона погоды каждой версии (v1 тоже) init_utc + 8 ч ≤ T — 174 прогона;
  • формат по § 7 контракта: столбцы по порядку, 144 строки = 48 ч × {1, 2, plant}, время в +05:00, одна версия в файле, P10 ≤ P50 ≤ P90 в [0, 1], ветер в [0, 60) м/с;
  • ленту шагов {D}.jsonl: события по схеме, есть действие (action), последнее событие — verdict;
  • что нигде нет заглушек (source = stub), что сводный CSV совпадает с файлами выпусков и что nMAE модели на январе ниже каждой из трёх базовых линий.

Код возврата 0 — PASS, 1 — FAIL. При ошибке печатается файл:строка · что не так. В интерфейсе то же правило видно по кнопке «✓ Без будущего»: какой прогон взят на какие часы и когда он вышел.

5. Технологии и зависимости

СлойТехнологияВерсия
Язык бэкендаPython3.12 (образ python:3.12-slim)
APIFastAPI, Uvicorn; SSE через Starlette StreamingResponse0.115.12, 0.34.0
Данныеpandas, NumPy, PyArrow (Parquet)2.2.3, 2.2.2, 19.0.1
Модельscikit-learn (HistGradientBoostingRegressor, квантильная потеря; IsotonicRegression для базовой линии)1.6.1
Агентopenai-python (Chat Completions, function calling), модель gpt-5.4-mini1.109.1
HTTP-клиентыrequests (Open-Meteo), HTTPX (тесты API)2.32.3, 0.28.1
Тесты и линтерpytest, Ruff8.3.5, 0.16.8
ИнтерфейсReact + Vite; графики — свой SVG без библиотек; шаги агента — EventSource (SSE); тесты — vitest + jsdom. Собирается в node:20.11.1-alpine3.19, dist/ отдаёт nginx на порту 3000 и проксирует /api/ и /health на backend:8000React 18.2.0, Vite 6.4.3, vitest 4.1.11, jsdom 22.1.0, nginx:1.27-alpine
ПроксиCaddy (образ caddy:2.11.4-alpine)2.11.4
ЗапускDocker, Docker Compose v2

Все версии Python-пакетов зафиксированы через == в backend/requirements.txt, его ставит и Docker-образ. Там же LightGBM 4.6.0, SciPy 1.15.2, joblib 1.4.2, build и setuptools — установлены, но в итоговом коде не используются.

Внешние сервисы:

СервисЗачемКлючБез него
Open-Meteo Previous Runs API (previous-runs-api.open-meteo.com)архивные прогнозы из прошлых прогонов (*_previous_day1…4, models=best_match) для выпусков и обученияне нужен, бесплатноответы из data/weather_cache/ (meta.source = "cache")
Open-Meteo Forecast API (api.open-meteo.com)прогноз для Liveне нужен, бесплатноLive берёт последний сохранённый снимок, если он покрывает 48 ч; архивный февраль работает
OpenAI APIвыбор шагов агента, решения о пересчёте, тексты сводокOPENAI_API_KEY, необязателендетерминированный режим, те же числа

Historical Forecast API Open-Meteo в конвейере не используется: в weather.py есть только диагностическая функция, которую модель и агент не вызывают.

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

6.1 Системные требования

  • Docker с Compose v2 (команда docker compose, не docker-compose), например Docker Desktop. Образ backend проверен на Docker 29.6 / Compose 5.2, arm64 (Apple Silicon); сервер https://pushin.codes — amd64.
  • Свободные порты 8080 (интерфейс и API через прокси), 8000 (API напрямую), 3000 (фронтенд напрямую). Если порт занят, поменяйте левую часть в ports в docker-compose.yml, например "8081:8080".
  • Около 2 ГБ на диске под образы (образ backend — 0,72 ГБ; стадия сборки интерфейса на Node.js — ещё несколько сотен МБ, итоговые образы frontend и Caddy — небольшие, на Alpine) и около 1 ГБ свободной памяти.
  • Интернет — для сборки образов (PyPI, Docker Hub) и для погоды Open-Meteo. Без сети при работе агент берёт погоду из data/weather_cache/ (60 файлов, ≈ 3 МБ: окна всех 30 январских и 29 февральских выпусков плюс архив для обучения) — февраль и январь воспроизводятся офлайн.
  • Для scripts/verify.py на хосте нужен только python3 ≥ 3.9, без пакетов. В Windows вместо python3 используйте python или py -3.

6.2 Docker, основной путь

git clone https://github.com/BAITC-Hacks/hack-07de2d2d-pushin-code
cd hack-07de2d2d-pushin-code
cp .env.example .env         # необязательно; для режима LLM впишите OPENAI_API_KEY=…
docker compose up --build    # или docker compose up --build -d, чтобы вернуть терминал
  • Файл .env можно не создавать: compose читает его только для подстановки переменных и без него тоже стартует.
  • Поднимаются три контейнера: backend (FastAPI, собирается из корня репозитория, потому что образу нужны data/, models/ и outputs/), frontend (сборка React в Node.js, затем nginx с dist/) и proxy (Caddy).
  • Готовность: curl http://localhost:8080/health →
{"ok": true, "mode": "deterministic", "model_version": "histgb-q-2026-01-31", "issues_ready": 29,
 "ports": {"weather": "real", "data": "real", "model": "real"},
 "live_watch_minutes": 30, "live_last_check_local": null}

mode станет agent, если в .env есть ключ; ports подтверждает, что погода, данные и модель настоящие, а не заглушки; live_last_check_local заполнится через 10 секунд, когда агент сам проверит погоду для Live.

АдресЧто
http://localhost:8080интерфейс, /api/* и /health через один прокси — открывать это
http://localhost:8080/api/docsSwagger UI со всеми эндпоинтами
http://localhost:8000API напрямую
http://localhost:3000фронтенд напрямую; его nginx сам проксирует /api/ и /health на backend

Февраль уже посчитан: 29 выпусков из outputs/ попадают в образ при сборке. Если вы перегенерировали выпуски на хосте (§ 8.2), пересоберите образ: docker compose up --build.

Остановить: Ctrl+C, затем docker compose down. Удалить и собранные образы: docker compose down --rmi local.

6.3 Без Docker (для разработчика)

Нужен Python 3.12. Все команды — из корня клона:

python3.12 -m venv .venv && source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -r backend/requirements.txt                 # LightGBM в списке есть, но кодом не импортируется: libomp не нужен
export PYTHONPATH=backend                               # Windows PowerShell: $env:PYTHONPATH="backend"
SCADA_UTC_OFFSET_H=6 python -m windcast.data            # SCADA → data/processed/hourly.parquet (секунды)
uvicorn windcast.api:app --port 8000                    # один воркер; если работает docker compose — сначала docker compose down

python -m windcast.data печатает число часов и долю валидных по каждой турбине: turbine 1: hours=25392 valid_fraction=0.9242, turbine 2: hours=25392 valid_fraction=0.9704.

Проверка: curl http://localhost:8000/health.

Интерфейс (React + Vite) в режиме разработки — из frontend/, нужен Node.js 20 (в образе — 20.11.1); API при этом должен работать на :8000:

cd frontend
npm ci            # зависимости строго по package-lock.json
npm run dev       # http://localhost:3000; /api и /health проксируются на localhost:8000
npm test          # vitest: 14 тестов
npm run build     # dist/ — то же делает Dockerfile

?fixtures=1 в адресе — работа без бэкенда на синтетических JSON из frontend/fixtures/, только для разработки. Что где лежит:

ФайлЧто
src/App.jsxшапка, вкладки (#february, #live, #quality), режим агента из /health, панель «Как проверить за 3 минуты»
src/February.jsx, src/Live.jsx, src/Quality.jsxтри экрана
src/AgentPanel.jsxшесть этапов по meta.stage, лента событий, сводка для диспетчера
src/ForecastChart.jsx, src/chart.jsграфики на SVG, без библиотек
src/useAgentRun.jsзапуск агента (POST /api/runs + SSE) и проигрывание сохранённых лент
src/api.js, src/format.jsклиент API § 6 контракта и форматирование
src/*.test.js14 тестов vitest (jsdom)
nginx.confпорт 3000; /api/ и /health проксирует на backend:8000 с proxy_buffering off, чтобы шаги агента шли без задержки; resolver 127.0.0.11 — nginx стартует, даже если backend ещё не поднялся
Dockerfileдве стадии: node:20.11.1-alpine3.19 (npm ci && npm run build) → nginx:1.27-alpine с dist/

Проверено 23.09 на выгрузке main: npm ci, npm test (14 passed) и npm run build (dist/ ≈ 1,3 МБ) проходят. Вкладки открываются и по ссылке: /#february, /#live, /#quality.

Переобучить модели и пересчитать метрики января (≈ 1,5 минуты, погода — из API или кэша):

python -m windcast.evaluate --from 2025-12-31 --to 2026-01-29

Команда обучает модель для обоих сдвигов часов SCADA, выбирает сдвиг по 1–7 января, пишет models/quantile_2025-12-31.pkl и outputs/metrics_jan.json, затем обучает февральский models/quantile_2026-01-31.pkl и печатает:

model: nMAE=15.7629% nRMSE=23.4460%
power_curve: nMAE=19.3513% nRMSE=23.9918%
climatology: nMAE=26.8185% nRMSE=37.1858%
persistence: nMAE=36.4548% nRMSE=47.9054%
SCADA_UTC_OFFSET_H=6

Повторный запуск воспроизводит outputs/metrics_jan.json байт в байт (проверено 23.09).

6.4 Тесты

python -m pytest -q backend/tests    # агент, инструменты, погода, модель, запись выпусков, API, SCADA, время; без сети
python -m pytest -q scripts/tests    # verify.py на синтетических выпусках, запуск как у жюри
cd frontend && npm ci && npm test    # интерфейс: vitest + jsdom, нужен Node.js 20

Сейчас это 155, 34 и 14 тестов, все проходят. У эксперимента ml-prognoz-model/ свои тесты и своё окружение (§ 9).

6.5 Проверено на чистом клоне

23.09 в 16:17 репозиторий склонировали с GitHub в пустой каталог и запустили ровно по § 6.2, без .env (без ключа OpenAI, детерминированный режим):

  1. docker compose up --build -d — все три контейнера собрались и поднялись без ручных правок.
  2. http://localhost:8080 ответил 200, интерфейс открылся.
  3. /health: ports — weather, data, model все real; issues_ready: 29.
  4. /api/issues: все 29 выпусков опубликованы; /api/metrics отдал метрики января.
  5. POST /api/runs с trigger: new_weather_run на 2026-02-13 — агент прошёл цикл в потоке SSE и отказал: «Итог: v2 остаётся — более свежего прогона до момента выпуска нет».
  6. python3 scripts/verify.py на хосте — PASS.

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

https://pushin.codes — тот же код и те же три сервиса, развёрнуты 23.09 в 16:40 через infra/docker-compose.hosted.yml: backend и frontend слушают только 127.0.0.1 (8100 и 3100), наружу их выводит системный Caddy хоста с TLS Let's Encrypt (infra/caddy-site.snippet: /api/* и /health → backend, остальное → frontend, SSE без буферизации). В .env сервера стоит ключ OpenAI команды, поэтому там агент работает в режиме LLM (/health → "mode": "agent"), и проверка не требует личных аккаунтов (п. 5.6.6). Проверено снаружи после деплоя: интерфейс отвечает 200, /health показывает все три ports real и issues_ready: 29, /api/issues отдаёт 29 выпусков (все v2), CSV и метрики скачиваются, шаги агента идут через Caddy событие за событием, решения LLM видны в ленте.

7. Параметры окружения

Все переменные необязательны, проект запускается и без .env. Секреты хранятся только в .env, он в .gitignore. Шаблон — .env.example.

ПеременнаяПо умолчаниюГде читаетсяЧто делает
OPENAI_API_KEYпустоruns.py, agent.py, backtest.pyесть ключ → режим agent (шаги и решения — LLM); нет → deterministic
OPENAI_MODELgpt-5.4-miniagent.pyмодель OpenAI для агента. Нужна модель с function calling в Chat Completions: семейство gpt-6 инструменты в этом API не поддерживает, поэтому по умолчанию gpt-5.4-mini
OPENAI_REASONING_EFFORTпустоagent.pyreasoning_effort для моделей 2025 года gpt-5, gpt-5-mini, gpt-5-nano; для остальных не передаётся
OPENAI_TIMEOUT_S60agent.pyтаймаут запроса к OpenAI, секунд
OPENAI_BASE_URLAPI OpenAIopenai-pythonдругой адрес OpenAI-совместимого API
LIVE_WATCH_MINUTES30watcher.pyкак часто агент сам проверяет новые прогоны для Live; 0 — выключено; первая проверка через 10 с
WINDCAST_ROOTкорень репозитория; в образе /apppaths.pyоткуда читать и куда писать data/, models/, outputs/
SCADA_UTC_OFFSET_H5config.pyсдвиг часов SCADA к UTC для windcast.data: 5 или 6, другое значение — ошибка. Бэктест выбрал 6, модели обучены при 6
WINDCAST_FORCE_STUBSпустоports.py1 — синтетические заглушки вместо погоды и модели (только тесты, без сети)
PYTHONPATHв образе /app/backendPythonдля запуска без Docker: backend, чтобы работало python -m windcast.…

Корневой docker-compose.yml передаёт в контейнер OPENAI_API_KEY, OPENAI_MODEL, OPENAI_REASONING_EFFORT и LIVE_WATCH_MINUTES; .env.example перечисляет первые две и последнюю. Остальное задано в образе (backend/Dockerfile) и нужно только при запуске без Docker. Переменные DOMAIN и DEPLOY_COMPOSE_FILE из infra/.env.example нужны только серверу https://pushin.codes, для проверки они не требуются.

8. Проверка основного сценария

8.1 В интерфейсе, за 3 минуты

Откройте https://pushin.codes (без регистрации) или локально http://localhost:8080. В шапке — три вкладки, режим агента из /health («агент · LLM» или «агент · без LLM») и кнопка «Как проверить за 3 минуты»: она открывает список из десяти требований ТЗ, а «Показать» у каждого переключает вкладку и подсвечивает нужное место на экране.

Вкладка «Февраль 2026 · тест» (/#february):

  1. Февраль уже посчитан. Календарь «Выпуски 31 января — 28 февраля» — 29 выпусков с днями недели, у всех метка v2 (был пересчёт), точка — есть риски. Плеер лент агента (без LLM): «▶ Воспроизвести февраль» — с 31.01, «▶ С {дата}» — с выбранного дня; «Пауза» / «▶ Продолжить с {дата}» — возобновляет с того же шага; «■ Стоп» — останавливает и возвращает сохранённую ленту выбранного дня; скорость 0,5×/1×/2×/4×; клик по дню в календаре во время показа переносит его на этот день.
  2. Выпуск за день. Кликните 13.02: карточка «Выпуск на 14–15 февраля» с графиком на 48 часов (P50, коридор P10–P90, прошлая версия), переключатель объекта ВЭС / Т1 / Т2, «Для системы сейчас 14 февраля 2026, 00:00» — всё правее система не видела, «Что изменилось» против v1 и «Риски в окне». В панели «Агент» справа — сводка для диспетчера («По ВЭС ожидается пик 98% номинала 15.02 в 16:00 …»).
  3. «Без будущего» в блоке «Проверка» — какие прогоны погоды взяты на какие часы и когда они вышли: часы 1-17 и 18-41 — прогон 13.02 06:00 UTC, часы 42-48 — 12.02 18:00 UTC, все опубликованы до T = 13.02 19:00 UTC.
  4. «Перевыпустить агентом» — агент проходит цикл вживую: в панели «Агент» по очереди загораются шесть этапов ТЗ (погода · подготовка · модель · прогноз · анализ · пересчёт) и идёт лента шагов. Агент публикует v1, получает событие «вышел новый прогон погоды», сравнивает и решает: v2 со строкой «что изменилось» или «пересчёт не нужен». В режиме LLM выпуск занимает 9–16 секунд, в детерминированном — 1–2 секунды.
  5. «Новый прогон погоды» — агент ищет прогон свежее текущего и опубликованный до T, не находит и отказывает: «Итог: v2 остаётся — более свежего прогона до момента выпуска нет». В пояснении указано, когда стартовал следующий прогон и когда он вышел — позже T. Так правило «без будущего» соблюдается и в решении агента.
  6. «CSV выпуска» и CSV всех 29 выпусков одним файлом — формат в § 9.

Перевыпуск меняет выпуск только внутри запущенного контейнера; файлы в репозитории, которые проверяет verify.py, не меняются.

Вкладка «Live · сейчас» (/#live):

  1. Статус прогонов: текущее время, последний и следующий прогон, как часто агент сам проверяет обновления. «▶ Выпустить прогноз сейчас» — тот же цикл на последнем прогоне Open-Meteo Forecast API (нужен интернет); «Проверить обновления погоды» — агент решает, нужна ли новая версия.
  2. «Имитировать сбой погоды» — выпуск, в котором первый запрос погоды падает: агент повторяет запрос и предупреждает, что доверие к выпуску ниже обычного.
  3. «Журнал агента» — что агент сделал сам («агент сам») и по кнопке («по кнопке»). Первая запись наблюдателя появляется через 10 секунд после старта бэкенда, без участия человека.

Вкладка «Качество · январь» (/#quality):

  1. «Как модель ошибалась в январе»: четыре числа (nMAE модели 15,8 %, выигрыш против лучшей базовой линии, покрытие P10–P90, число выпусков), таблица «Модель против базовых линий», «Ошибка по горизонту» и «Неделя 15–21 января: прогноз против факта, ВЭС». Факта за февраль нет — см. § 9.

8.2 Из командной строки

Перевыпустить февраль с нуля и проверить результат (после § 6.3):

export PYTHONPATH=backend
python -m windcast.backtest --from 2026-01-31 --to 2026-02-28 --mode deterministic   # ≈ 35 с; с ключом и --mode agent ≈ 6 мин
python3 scripts/verify.py

backtest печатает, откуда взяты погода, данные и модель, и по строке на выпуск:

backtest 2026-01-31 → 2026-02-28: 29 issues · mode=deterministic · weather=real, data=real, model=real
2026-01-31  v2  source=api  mode=deterministic  flags=ramp:2,ice:3  (1.2s)
2026-02-01  v2  source=api  mode=deterministic  flags=ramp:1,ice:2  (1.3s)
…
2026-02-28  v2  source=api  mode=deterministic  flags=ramp:2,ice:3  (1.0s)
combined: outputs/forecast_feb2026.csv (29 issues)

Что появится:

  • outputs/forecasts/{D}.csv и {D}.json — 29 выпусков: CSV содержит последнюю версию, JSON — все версии;
  • outputs/traces/{D}.jsonl — 29 лент шагов агента;
  • outputs/forecast_feb2026.csv — сводный файл;
  • метрики января пишет python -m windcast.evaluate (§ 6.3).

Выпуски в репозитории перезапишутся; что изменилось, покажет git diff --stat outputs/. Чтобы их не трогать, задайте другой корень: mkdir -p /tmp/wc && cp -R data models /tmp/wc && WINDCAST_ROOT=/tmp/wc PYTHONPATH=backend python -m windcast.backtest --from 2026-02-12 --to 2026-02-14 --mode deterministic — CSV в /tmp/wc/outputs/forecasts/ совпадут с файлами в outputs/forecasts/ байт в байт. Записанные выпуски сделаны в режиме LLM (gpt-5.4-mini, 23.09 16:00–16:05; 08, 10, 12 и 14.02 перевыпущены в 16:28–16:29 после исправления агента, § 9). Детерминированный перевыпуск даёт те же числа P10/P50/P90 и тот же набор версий: правило, как и LLM, пересчитало все 29 дней (проверено: все 29 v1 и все 29 v2 совпали строка в строку). Отличаются только тексты сводок — в детерминированном режиме они шаблонные.

То же внутри контейнера, если Python 3.12 ставить не хочется (scripts/ в образ не входит, поэтому проверка — на хосте):

docker compose exec backend python -m windcast.backtest --from 2026-01-31 --to 2026-02-28 --mode deterministic
mkdir -p /tmp/windcast-check && docker compose cp backend:/app/outputs /tmp/windcast-check/
python3 scripts/verify.py --root /tmp/windcast-check

API читает файлы заново на каждый запрос, поэтому интерфейс сразу покажет перевыпущенные выпуски.

Вывод verify.py на выпусках из репозитория (23.09):

Windcast · проверка выпусков 2026-01-31 … 2026-02-28 (29 выпусков)
Корень: …/hack-07de2d2d-pushin-code
T — момент выпуска D: D 19:00 UTC = (D+1) 00:00 по UTC+5
Прогон погоды доступен к выпуску, если старт + 8 ч ≤ T, т. е. старт не позже D 11:00 UTC (§2)

  ✓ Выпуски на месте: forecasts/{D}.csv                             29/29 выпусков
  ✓ Без будущего: прогон доступен к T (старт + 8 ч ≤ T, CSV)        4176/4176 строк
  ✓ Без будущего: прогоны доступны к T (старт + 8 ч ≤ T, {D}.json)  174/174 прогонов
  ✓ Заголовок CSV: столбцы §7 по порядку                            29/29 файлов
  ✓ 144 строки: турбины 1, 2, plant × h 1…48                        29/29 файлов
  ✓ Дата выпуска, T и целевые часы в +05:00                         4176/4176 строк
  ✓ Одна версия ≥ 1 на файл                                         29/29 файлов
  ✓ P10 ≤ P50 ≤ P90, все в [0, 1]                                   4176/4176 строк
  ✓ Ветер wind_fc_ms в [0, 60) м/с                                  4176/4176 строк
  ✓ Лента шагов агента: traces/{D}.jsonl                            29/29 выпусков
  ✓ Запись {D}.json: latest_version = версия CSV                    29/29 выпусков
  ✓ Без заглушек: нигде нет source = stub                           29/29 выпусков
  ✓ Сводный forecast_feb2026.csv = файлы выпусков                   4176/4176 строк
  ✓ Январь: nMAE модели ниже всех базовых линий                     nMAE: model 0.1576 · power_curve 0.1935 · climatology 0.2682 · persistence 0.3645

PASS

8.3 API через curl

Работает и с https://pushin.codes вместо http://localhost:8080:

curl -s http://localhost:8080/health
curl -s "http://localhost:8080/api/issues?from=2026-01-31&to=2026-02-28"      # календарь: 29 выпусков
curl -s http://localhost:8080/api/forecasts/2026-02-13                         # выпуск: 144 строки, weather_runs, сводка
curl -s -o 2026-02-13.csv http://localhost:8080/api/forecasts/2026-02-13.csv   # CSV выпуска
curl -s -o feb.csv http://localhost:8080/api/forecasts/february.csv            # сводный CSV за февраль
curl -s http://localhost:8080/api/traces/2026-02-13                            # записанная лента шагов
curl -s http://localhost:8080/api/metrics                                      # январь: модель и базовые линии
curl -s "http://localhost:8080/api/live/journal?limit=20"                      # что агент сделал сам (initiator=agent)
curl -s http://localhost:8080/api/forecasts/live                               # текущий live-выпуск

# запустить агента и смотреть его шаги вживую (SSE); без ключа — детерминированно
ID=$(curl -s -X POST http://localhost:8080/api/runs -H 'content-type: application/json' \
  -d '{"issue_date": "2026-02-13", "trigger": "new_weather_run"}' \
  | python3 -c 'import json, sys; print(json.load(sys.stdin)["id"])')
curl -N http://localhost:8080/api/runs/$ID/events

# сбой источника погоды: агент повторяет запрос и предупреждает
curl -s -X POST http://localhost:8080/api/runs -H 'content-type: application/json' \
  -d '{"issue_date": "2026-02-13", "scenario": "weather_outage"}'

# неверный запрос — 400 с текстом, а не 500
curl -s http://localhost:8080/api/forecasts/2026-13-45
# {"error":"Неверная дата выпуска «2026-13-45»: нужен формат ГГГГ-ММ-ДД"}

9. Результаты

29 выпусков за февраль — в outputs/, они же видны в интерфейсе. Сделаны 23.09.2026 командой PYTHONPATH=backend python -m windcast.backtest --from 2026-01-31 --to 2026-02-28 --mode agent с OPENAI_MODEL=gpt-5.4-mini, погода — из API (source: api во всех 58 версиях), 9–16 секунд на выпуск.

ФайлЧто
outputs/forecasts/{D}.csvвыпуск D = 2026-01-31 … 2026-02-28, последняя версия, 144 строки
outputs/forecasts/{D}.jsonзапись выпуска со всеми версиями (v1, v2), прогонами погоды, флагами, сводкой — источник для API
outputs/forecast_feb2026.csvвсе 29 выпусков одним файлом, 29 × 144 = 4176 строк
outputs/traces/{D}.jsonlлента шагов агента для каждого выпуска — доказательство, что выпуск сделал агент
outputs/metrics_jan.jsonметрики и ряды января для вкладки «Качество»

Решения агента. 29 из 29 — v2 на более свежем прогоне; решение каждый раз принимал LLM (meta.by = "llm" в каждой ленте). Если LLM объявляет пересчёт, но не вызывает инструмент, агент напоминает один раз, а затем решает по правилу и пишет by=rule — в итоговых выпусках таких случаев нет. Дважды — 08.02 и 25.02 — в сводке LLM для v1 были числа, которых нет ни в одном ответе инструментов, и код опубликовал шаблонную сводку с пометкой «в сводке числа не из инструментов (…) — взял шаблонную». Всё это видно в лентах, мы ничего не правили.

Формат CSV (UTF-8, запятая, порядок столбцов фиксирован):

СтолбецПримерСмысл
issue_date2026-02-13дата выпуска D
issue_time_local2026-02-14T00:00+05:00момент выпуска T
target_time_local2026-02-14T00:00+05:00начало целевого часа; h = 1 → (D+1) 00:00
horizon_h1 … 48горизонт, часов
turbine1, 2, plantтурбина или ВЭС
p10, p50, p900.2134мощность в долях номинала, [0, 1], 4 знака
wind_fc_ms7.41прогноз ветра на высоте 100 м, м/с
weather_init_max_utc2026-02-13T06:00Zверхняя граница старта прогона погоды (§ 4)
version1 или 2версия выпуска: 2 — пересчитан на более свежем прогоне

Точность на январе 2026. Факта за февраль в выданных данных нет: они заканчиваются 31.01.2026 23:50. Поэтому точность показываем на бэктесте января, который прошёл тем же путём и по тому же правилу «без будущего»: 30 выпусков D = 31.12.2025 … 29.01.2026, модель quantile_2025-12-31.pkl обучена на данных до 31.12.2025. Февральские CSV готовы для сверки организатором. ВЭС, все 48 часов каждого выпуска, 1417 часов с фактом:

МетодnMAE, % номиналаnRMSE, % номинала
Windcast, P5015,7623,45
Кривая мощности по прогнозному ветру19,3523,99
Климатология: медиана по турбине, месяцу и часу26,8237,19
Персистентность: «завтра как сегодня»36,4547,91
  • Выигрыш против лучшей базовой линии (кривой мощности): 18,5 % по nMAE; по nRMSE выигрыш небольшой (23,45 против 23,99) — крупные промахи у обеих связаны с ошибкой прогноза ветра.
  • По горизонту: первые сутки (h 1–24) — nMAE 14,6 %, вторые (h 25–48) — 17,0 %; часы 18–48 считаются по прогонам на 1–2 суток старше (§ 4).
  • Покрытие коридора P10–P90: 80,5 % часов при цели ≈ 80 %.
  • Ряд «прогноз против факта» (каждый час января по одному разу, 732 часа): факт внутри коридора в 82,8 % часов, ниже P10 — 7,8 %, выше P90 — 9,4 %; средний P50 0,302 против факта 0,317 — смещение −1,5 п.п.; корреляция P50 с фактом 0,77.
  • Независимая проверка выбора сдвига часов: 8–31 января (не участвовали в выборе) — nMAE модели 16,8 %, персистентности 36,4 %.
  • Под правилом без 8-часовой задержки та же схема давала 15,0 %; честное правило стоит 0,8 п.п. (§ 3.3).
  • Ошибка по каждому горизонту и по дням — вкладка «Качество» и GET /api/metrics (by_horizon, by_day).

Эксперимент: модели только на истории SCADA

Можно ли обойтись без прогноза погоды? Это проверяет отдельный офлайн-эксперимент Кубы ml-prognoz-model/ (PR #7): только выданные CSV, 48 прямых выходов из lag- и rolling-признаков SCADA и календаря, 14 кандидатов (персистентность, сезонная медиана, Ridge, Extra Trees, Random Forest, CatBoost), настройка на октябре–ноябре 2025 и замороженный отложенный период декабрь–январь. MAE прогноза на 48 ч в долях номинала, по турбинам:

МетодОтложенный период эксперимента, 01.12.2025–29.01.2026Январь: те же 30 моментов выпуска, что в нашем бэктесте
Персистентность: последнее значение на все 48 ч0,3520,333
CatBoost — лучшая обучаемая модель по валидации0,3150,303
Сезонная медиана — лучшая на истории0,3100,273
Windcast: прогноз погоды + квантильная модель—0,158

Январский столбец мы посчитали сами: по holdout_predictions.parquet эксперимента — на моментах выпуска 31.12.2025 … 29.01.2026 в 19:00 UTC, а для Windcast — тем же артефактом quantile_2025-12-31.pkl на тех же выпусках (турбина 1 — 0,1585, турбина 2 — 0,1581). Без прогноза погоды ошибка в 1,7–1,9 раза больше, по отложенному периоду эксперимента — примерно вдвое, хотя модели на истории знают фактическую мощность вплоть до момента выпуска. Поэтому продукт строится на прогнозе погоды. Оговорки: модели эксперимента в отложенном периоде обучены по 01.12.2025, наша январская — по 31.12.2025; часы SCADA эксперимент принимает за UTC+5, а продукт по бэктесту выбрал +6.

Эксперимент в продукт не входит. Февраль он воспроизвести не может: каждому его прогнозу нужны последние 24 часа наблюдений, а данных за февраль организаторы не дали. Прогноз у него точечный, без P10–P90. Окружение своё (Python ≥ 3.11, uv); проверено 23.09 на выгрузке main: uv sync занял около минуты, 80 тестов прошли.

cd ml-prognoz-model && uv sync --extra dev && uv run pytest

Подробности — ml-prognoz-model/README.md и ml-prognoz-model/docs/results.md.

Как проверить точность февраля

Для жюри с фактом за февраль — три файла в outputs/evaluation/ (доли номинала 0–1, plant = среднее турбин 1 и 2, целевой час начинается в target_time_local, UTC+5): february_day_ahead.csv — один прогноз на час (выпуск D−1, h 1–24, 2016 строк), february_all_horizons.csv — все 4176 строк с h 1–48, january_day_ahead.csv — январь с колонкой actual для проверки самого скрипта. Оценка одной командой, только стандартная библиотека:

python3 scripts/score.py --actual <папка с turbine_1.csv и turbine_2.csv за февраль>   # --json для машин
python3 scripts/score.py --actual data/raw --forecast outputs/evaluation/january_day_ahead.csv   # самопроверка

Самопроверка на январе: nMAE ВЭС 14,71 % по 732 часам — то же число, что из колонки actual (15,76 % выше в этом разделе — все 48 горизонтов, 1417 часов). Скачать: https://pushin.codes/api/evaluation/february_day_ahead.csv, https://pushin.codes/api/evaluation/february_all_horizons.csv. Часы SCADA организатора мы считаем UTC+6 (выбрано на январе); если иначе — --scada-utc-offset 5. Метрики и правила отбора часов — outputs/evaluation/README.md.

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

backend/                 FastAPI и пакет windcast; Dockerfile собирается из корня репозитория
  windcast/
    paths.py timeline.py             общие: пути от WINDCAST_ROOT, момент выпуска T, горизонт, лаги
    config.py data.py                SCADA → почасовой ряд, check_data (Куба)
    weather.py model.py evaluate.py  Open-Meteo и кэш, квантильная модель и базовые линии, бэктест января (Куба)
    agent.py tools.py store.py       агент, 6 инструментов, запись выпусков (Абылай)
    ports.py _stubs.py               подключение функций погоды, данных и модели; заглушки только для тестов
    api.py runs.py watcher.py        REST + SSE, прогоны в фоне и журнал, Live-наблюдатель (Абылай)
    backtest.py                      CLI: выпуски подряд
  tests/                 pytest, 155 тестов
frontend/                интерфейс (Сула): React + Vite — src/*.jsx, src/*.test.js, nginx.conf, Dockerfile; fixtures/ — синтетические ответы API для разработки
ml-prognoz-model/        эксперимент Кубы: прогноз только по истории SCADA, своё окружение uv; в продукт не входит
data/raw/                CSV SCADA как выданы организатором, не изменяются
data/processed/          hourly.parquet — генерируется, не в git
data/weather_cache/      60 ответов Open-Meteo — запасной путь без сети и архив для обучения
models/                  quantile_2025-12-31.pkl (январь), quantile_2026-01-31.pkl (февраль)
outputs/                 29 выпусков, ленты шагов, сводный CSV, метрики января — результат для сдачи
scripts/verify.py        проверка выпусков для жюри (только стандартная библиотека); scripts/tests/ — её тесты
infra/                   Caddy, compose для сервера, деплой push-to-deploy
docs/                    контракт, ТЗ, разбор данных, схема архитектуры, макет интерфейса
docker-compose.yml       запуск из чистого клона

Свой README.md есть в backend/, frontend/, data/, models/, outputs/, infra/ и ml-prognoz-model/.

11. Сторонние компоненты и заготовки

Полное раскрытие по п. 5.4.4–5.4.4.2 — в docs/THIRD_PARTY.md: открытые библиотеки с версиями и лицензиями, данные (SCADA организатора; погода Open-Meteo, CC BY 4.0), OpenAI API, заготовки до хакатона (инфраструктура, процессные скрипты и шаблоны от 22.09 — без продуктового кода) и использование AI-ассистентов. Вся продуктовая функциональность написана 23.09 в соревновательной части, история — в git. Push от 23.09 12:25, до старта, содержал только эти заготовки — подробно там же.

12. Ограничения и потенциал развития

Ограничения — честно:

  • Одна погодная модель — то, что Open-Meteo отдаёт как best_match. Ансамбля нет, коридор P10–P90 отражает только ошибку, выученную на истории, а флаг «расхождение погодных моделей» не срабатывает: в каждой ленте так и написано — «нет второй модели».
  • Часы 18–48 считаются по суточным корзинам архива (previous_day2/3), а не по конкретному прогону, поэтому вторые сутки на 1–2 прогона старше, чем могли бы быть: nMAE 17,0 % против 14,6 % в первые сутки.
  • Признак lag_days в обучении принимает только 1 или 2, а в выпуске часы 42–48 берут прогон давностью 3 суток (в первом расчёте v1 — 4): деревья относят такие часы к той же ветке, что и лаг 2, прямых обучающих примеров с lag 3–4 у модели нет.
  • Задержка публикации прогона 8 ч — консервативная константа. Архив не хранит реальный момент выхода каждого прогона. Если прогон на деле выходил раньше, мы теряем немного свежести, но утечки нет.
  • Факта за февраль нет, поэтому точность февраля не посчитана. Качество показано на январе, февральские CSV готовы для сверки организатором.
  • Выигрыш по nRMSE над кривой мощности небольшой (23,45 против 23,99): крупные промахи определяет ошибка прогноза ветра, которую одна модель погоды не снимает. Модель слегка занижает выработку (смещение −1,5 п.п.).
  • Прогнозируется выработка исправной турбины. Простои и ограничения (≈ 1 % записей) погодой не предсказываются; в обучении они исключены через valid = false.
  • Архив Previous Runs есть с 06.2024, поэтому модель учится на 20 месяцах (115–122 тысячи часов × турбина × лаг). SCADA с 03.2023 до 06.2024 в обучение модели не входит.
  • Ветер > 20 м/с в истории почти не встречался, так что поведение на отсечке модель знает плохо. Такие часы агент помечает флагом wind_gt20.
  • Обледенение — эвристика по температуре (от −3 до +1 °C), без влажности и осадков.
  • Прогоны агента хранятся в памяти процесса, поэтому API работает с одним воркером uvicorn. Перезапуск обрывает незавершённые потоки SSE, а опубликованные выпуски остаются в outputs/. Live-выпуски и журнал лежат в outputs/live/ внутри контейнера и не переживают его пересборку.
  • Open-Meteo бесплатен только для некоммерческого использования и с лимитом запросов. Для эксплуатации нужен коммерческий тариф или прямая загрузка открытых данных моделей.
  • В Live время прогона погоды — это время загрузки снимка, а не факт запуска модели: Open-Meteo Forecast API не сообщает момент init, поэтому init_time_utc там равен моменту, когда бэкенд забрал ответ.

Что уже сделано нестандартно:

  • «Без будущего» встроено в систему, а не только соблюдено: правило в коде (timeline.py, weather.py, отказ recalc_forecast), независимая проверка (verify.py) и «✓ Без будущего» на экране у каждого выпуска. Мы приняли потерю 0,8 п.п. точности ради честного правила.
  • Пересчёт запускается событием «вышел новый прогон», а решение принимает агент и объясняет его в ленте; все 29 февральских решений — за LLM.
  • Агент работает сам: Live-наблюдатель и журнал решений без участия человека.
  • Прогноз вероятностный (P10–P90, покрытие 80,5 %), а не одна цифра, с флагами рисков на оси времени.
  • Детерминированный режим даёт те же числа без ключа, так что проверка не требует внешних аккаунтов.

Что можно улучшить (ожидаемый эффект — оценка команды, не измерено):

  • Ансамбль погодных моделей (ECMWF IFS, GFS, ICON — все есть в Open-Meteo, в том числе в Previous Runs): ожидаем снижение ошибки на 5–10 % и более узкий, честно откалиброванный коридор; флаг расхождения моделей заработает на реальных данных.
  • Архив конкретных прогонов вместо суточных корзин для часов 18–48: вторые сутки считались бы по прогону D 06:00 UTC, ошибка второго дня — с 17 % до примерно 15 %.
  • Подмешивание SCADA в первые часы в эксплуатации, когда факт доступен онлайн: текущая выработка и её тренд для h 1–6, где персистентность сильна.
  • «Спросить агента»: вопросы диспетчера на естественном языке («почему в 15:00 спад?», «что будет, если ветер усилится?») с ответами через те же инструменты. Пока не реализовано.
  • Модель обледенения: температура, влажность и осадки, поправка к P50/P10 в часы риска.
  • Несколько ВЭС: новая станция — это координаты и история SCADA. Инструменты и правило «без будущего» от станции не зависят.
  • Экспорт графика в формат системного оператора и уведомления диспетчеру о рампах.
  • MCP-адаптер над тем же реестром инструментов: агента можно подключить к любому MCP-клиенту (например, к ассистенту диспетчера) без переписывания инструментов.

13. Команда

Pushin' Code

  • Абылай — мастер: архитектура, агент и API, инфраструктура.
  • Куба — данные, погода, модель.
  • Сула — интерфейс.
Звёзды
⭐ 0
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
114
Авторы
4
Файлы
441
Ветки
11

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

abekesalimzhanov 74kubevele 27Abylay 9Sultan Turan 4

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

  • 2026-09-23 17:51[T8] README: February player controls, climatology wording, two honest limits; RUBRIC: 29 issuesabekesalimzhanov
  • 2026-09-23 17:49[T8] Docs: regulation references in AGENTS, stale pre-start criteria note marked as outdatedabekesalimzhanov
  • 2026-09-23 17:49[T7] Risk ranges across midnight show the end date; baseline labels match the code (median, SCADA power curve)abekesalimzhanov
  • 2026-09-23 17:45[T7] February playback: pause, resume from the same step, speed 0.5-4x, play from any dayabekesalimzhanov
  • 2026-09-23 17:34[T7] Live: plant / turbine 1 / turbine 2 switch, as on the February tababekesalimzhanov
  • 2026-09-23 17:30[T9] Chat: plain-language accuracy answersabekesalimzhanov
  • 2026-09-23 17:29[T9] Chat: accuracy questions answered from the January metrics in both modesabekesalimzhanov
  • 2026-09-23 17:26[T8] README: dispatcher chat; February screenshot with the chat buttonabekesalimzhanov
Все коммиты (114)
  • 2026-09-23 17:25[T9] Chat: peak/min/risk questions go through get_issue_summary firstabekesalimzhanov
  • 2026-09-23 17:23Merge pull request #9 from BAITC-Hacks/t9-ask-backendAbylay
  • 2026-09-23 17:23[T8] Final screenshots and score logabekesalimzhanov
  • 2026-09-23 17:23Add dispatcher ask endpointkubevele
  • 2026-09-23 17:22[T5] Metrics period validation; cap concurrent runs at 3abekesalimzhanov
  • 2026-09-23 17:21[T7] Clearer button labels; run start shown as an upper boundabekesalimzhanov
  • 2026-09-23 17:21[T8] Disclose the 12:25 pre-start push: tooling only, per 5.4.4.2abekesalimzhanov
  • 2026-09-23 17:20[T8] README: five-minute block for the reviewer at the topabekesalimzhanov
  • 2026-09-23 17:19[T8] README: run start is an upper bound, best_match named; rubric counts 29 issuesabekesalimzhanov
  • 2026-09-23 17:14[T8] README: shorter opening, honest note on the injected new-run event, third-party list moved to docs/THIRD_PARTY.mdabekesalimzhanov
  • 2026-09-23 17:10[T8] Screenshots after the readability and wording passesabekesalimzhanov
  • 2026-09-23 17:05Merge Sula's ask-agent chat panel (hidden until /health reports ask: true)abekesalimzhanov
  • 2026-09-23 17:04[T8] February evaluation export and one-command scorerabekesalimzhanov
  • 2026-09-23 16:59[T7] Plain-language confidence labels instead of P10–P90abekesalimzhanov
  • 2026-09-23 16:57[T9] Ask-agent chat panel, shown only when /health reports ask: trueSultan Turan
  • 2026-09-23 16:56[T7] Readability pass: big numbers, one-line risks and steps, lighter chartabekesalimzhanov
  • 2026-09-23 16:54Merge pull request #8 from BAITC-Hacks/fix-t2/t3-archived-weather-availability-for-contract-v0.5-weather-fetch-must-useAbylay
  • 2026-09-23 16:54[T8] Submission texts: 174 weather runs after the regenerationabekesalimzhanov
  • 2026-09-23 16:54[T8] Slides, demo script and submission textsabekesalimzhanov
  • 2026-09-23 16:54[T8] README: counts after regeneration, no-Docker notes, non-destructive rerun (jury dry-run findings)abekesalimzhanov
  • 2026-09-23 16:48[T0] contract v0.6: dispatcher chat POST /api/ask behind a /health flagabekesalimzhanov
  • 2026-09-23 16:47[T8] Screenshots of the three tabs from https://pushin.codesabekesalimzhanov
  • 2026-09-23 16:47[T8] README: final numbers, agent-mode outputs, watcherabekesalimzhanov
  • 2026-09-23 16:47[T8] README: frontend, clean-clone check, CSV-only experimentabekesalimzhanov
  • 2026-09-23 16:47[T8] README: all 29 issues v2 after the nudge fixabekesalimzhanov
  • 2026-09-23 16:47[T8] README: Sula's React UI, screenshots, deploymentabekesalimzhanov
  • 2026-09-23 16:43[T0] Board and score: all tasks done, 83/100 by rubric v3, admission conditions closedabekesalimzhanov
  • 2026-09-23 16:40[T2] Live weather passes check_data at fetch time; the 8 h rule stays for archive issuesabekesalimzhanov
  • 2026-09-23 16:34Merge Sula's dispatcher UI (React, light theme) into mainabekesalimzhanov
  • 2026-09-23 16:31checkpoint(sula): [T6][T7] Light dispatcher UI: February, Live, Quality, agent panel with SSE, 3-minute check; React build served by nginxSultan Turan
  • 2026-09-23 16:31[T7] Live label names the weather run generically; frontend README matches the nginx setupabekesalimzhanov
  • 2026-09-23 16:29[T4] Regenerate 2026-02-08/10/12/14 after the nudge fix: the LLM's recalc decisions now match its wordsabekesalimzhanov
  • 2026-09-23 16:27[T4] Nudge the LLM once when it stops without a tool call; otherwise decide by ruleabekesalimzhanov
  • 2026-09-23 16:27Configure ML development test dependencieskubevele
  • 2026-09-23 16:26[T7] Fix class collisions, mobile layout, SSE tests, frontend READMESultan Turan
  • 2026-09-23 16:26[T6][T7] Light dispatcher UI: February, Live, Quality, agent panel, 3-minute checkSultan Turan
  • 2026-09-23 16:25Fix archived weather availability and model lag handlingkubevele
  • 2026-09-23 16:25Format weather availability changeskubevele
  • 2026-09-23 16:21Merge pull request #7 from BAITC-Hacks/csv-only-forecast-modelsAbylay
  • 2026-09-23 16:19[T3] Add CSV-only forecasting pipeline and trained modelskubevele
  • 2026-09-23 16:19[T3] Clarify shared raw data and direct forecast outputskubevele
  • 2026-09-23 16:16[T7] Frontend on the real API: February, Live, Quality; nginx imageabekesalimzhanov
  • 2026-09-23 16:12Merge pull request #6 from BAITC-Hacks/fix-contract-v0.4-no-future-validation-so-weather-runs-are-accepted-only-when-inAbylay
  • 2026-09-23 16:07Merge remote-tracking branch 'origin/main' into fix-contract-v0.4-no-future-validation-so-weather-runs-are-accepted-only-when-inkubevele
  • 2026-09-23 16:05[T4] February 2026: 29 issues with agent traces (LLM mode), January metrics under v0.4, retrained models, weather cacheabekesalimzhanov
  • 2026-09-23 15:59checkpoint(kuba): [T2] enforce publication delay for archive and Live; [T8] add CSV and record boundary regressionskubevele
  • 2026-09-23 15:57[T2] Weather and model follow the v0.4 no-future ruleabekesalimzhanov
  • 2026-09-23 15:56Enforce weather run publication timeskubevele
  • 2026-09-23 15:56Merge Kuba's weather, quantile model and January backtest (T2, T3) into mainabekesalimzhanov
  • 2026-09-23 15:52[T8] README draft for the juryabekesalimzhanov
  • 2026-09-23 15:52[T4] Default LLM gpt-5.4-mini; 8 h publication delay in the API; stubs visible in /healthabekesalimzhanov
  • 2026-09-23 15:50[T6] Live watcher, run journal and weather-outage scenario per contract v0.5abekesalimzhanov
  • 2026-09-23 15:50[T6] Pass runner options such as scenario through the default runnerabekesalimzhanov
  • 2026-09-23 15:48[T4] Live: v1 on the latest run when no older snapshot existsabekesalimzhanov
  • 2026-09-23 15:41Merge pull request #5 from BAITC-Hacks/t3-quantile-modelAbylay
  • 2026-09-23 15:39[T0] contract v0.5: autonomous live watcher with a journal; weather outage scenarioabekesalimzhanov
  • 2026-09-23 15:37[T4] Agent: six-tool registry, LLM loop with deterministic fallback, store, backtest CLIabekesalimzhanov
  • 2026-09-23 15:37[T4] Clearer dispatcher texts: grouped risks, concrete no-future refusal, issue introabekesalimzhanov
  • 2026-09-23 15:37[T4] LLM edge cases: premature recalc is not a decision, bad data always ends in error + verdictabekesalimzhanov
  • 2026-09-23 15:37Train weather-only quantile forecastskubevele
  • 2026-09-23 15:30Merge pull request #4 from BAITC-Hacks/t2-weather-cacheAbylay
  • 2026-09-23 15:28Reject future live cache snapshotskubevele
  • 2026-09-23 15:27[T8] verify.py: no-future rule counts the run publication delayabekesalimzhanov
  • 2026-09-23 15:26Validate live weather before cachingkubevele
  • 2026-09-23 15:24Cache live weather failureskubevele
  • 2026-09-23 15:23[T0] Stop tracking .DS_Storeabekesalimzhanov
  • 2026-09-23 15:23[T0] contract v0.4: no-future rule accounts for run publication delayabekesalimzhanov
  • 2026-09-23 15:22Reject incomplete weather responseskubevele
  • 2026-09-23 15:22[T8] Build backend from the repo root in the dedicated-host compose tooabekesalimzhanov
  • 2026-09-23 15:22[T8] scripts/verify.py: jury check for the 29 issues, no-future rule firstabekesalimzhanov
  • 2026-09-23 15:22[T8] root docker-compose for a clean clone; backend builds from the repo rootabekesalimzhanov
  • 2026-09-23 15:21Validate weather cache provenancekubevele
  • 2026-09-23 15:21[T5] Add FastAPI API per contract §6 with run registry and SSEabekesalimzhanov
  • 2026-09-23 15:21[T5] Order events by schema, quiet agent-missing log, clamp Last-Event-IDabekesalimzhanov
  • 2026-09-23 15:21[T5] Add backend Dockerfile (root build context) and .dockerignoreabekesalimzhanov
  • 2026-09-23 15:21[T5] Make issue-lock test deterministic; keep tests off the real model importabekesalimzhanov
  • 2026-09-23 15:19Add API-first weather cachekubevele
  • 2026-09-23 15:18Merge pull request #3 from BAITC-Hacks/t1-hourly-scadaAbylay
  • 2026-09-23 15:16[T5a] Add API fixtures for all screensabekesalimzhanov
  • 2026-09-23 15:16Add red tests for weather cachekubevele
  • 2026-09-23 15:13Allow guarded task base fast-forwardkubevele
  • 2026-09-23 15:12Exercise nested virtual environment pruningkubevele
  • 2026-09-23 15:09checkpoint(kubevele): [T1] Validated UTC hourly SCADA parquet, strict check_data, stacked taskflow base receipts; committed and verified.kubevele
  • 2026-09-23 15:08Ignore nested virtual environments during verificationkubevele
  • 2026-09-23 15:07Harden SCADA validation and taskflow verificationkubevele
  • 2026-09-23 15:06Build validated hourly SCADA datasetkubevele
  • 2026-09-23 15:00Add red tests for hourly SCADA pipelinekubevele
  • 2026-09-23 14:58[T0] contract v0.3: internal interfaces, record format; shared backend scaffoldabekesalimzhanov
  • 2026-09-23 14:43[T0] contract v0.2: UI endpoints, 29 issues, repo tree, UI mockup and architectureabekesalimzhanov
  • 2026-09-23 14:42Merge pull request #2 from BAITC-Hacks/taskflow-deliveryAbylay
  • 2026-09-23 14:36Make Ruff verification reproduciblekubevele
  • 2026-09-23 14:33Merge pull request #1 from BAITC-Hacks/taskflow-deliveryAbylay
  • 2026-09-23 14:29Format Python examples for Ruffkubevele
  • 2026-09-23 14:20Add Jira-free taskflow workflowkubevele
  • 2026-09-23 13:56[T0] first brainstorm: case choice, agent design, user flow (draft, not final)abekesalimzhanov
  • 2026-09-23 13:34[T0] task, data notes, contract v1, rubric v3 for the wind power forecasting caseabekesalimzhanov
  • 2026-09-23 12:24docs: align with the 22.09 regulation — 13:00–18:00 window, run-or-disqualified, task-specific criteriaabekesalimzhanov
  • 2026-09-22 21:38fix(infra): chown the bare repo after git init, not beforeabekesalimzhanov
  • 2026-09-22 18:37fix(infra): drop the generic healthcheck that blocked startupabekesalimzhanov
  • 2026-09-22 18:35fix(scripts): checkpoint missed secrets in newly added filesabekesalimzhanov
  • 2026-09-22 18:26docs: point the board and playbook at the live domainabekesalimzhanov
  • 2026-09-22 18:25chore(infra): pushin.codes over the host's existing Caddy, plus a smoke stackabekesalimzhanov
  • 2026-09-22 18:02chore(infra): deploy variant for a host that already serves 80/443abekesalimzhanov
  • 2026-09-22 17:49chore: add infra/.env.example, previously excluded by the ignore rulesabekesalimzhanov
  • 2026-09-22 17:49chore: keep .env.example out of the ignore rulesabekesalimzhanov
  • 2026-09-22 17:48chore: agent config, docs and tooling prepared before the hackathonabekesalimzhanov
Структура репозитория (441 файлов)
.agents/roles/delivery-reviewer.md
.agents/roles/task-worker.md
.agents/skills/worktree-delivery/SKILL.md
.agents/skills/worktree-delivery/agents/openai.yaml
.codex/agents/delivery-reviewer.toml
.codex/agents/task-worker.toml
.dockerignore
.env.example
.gitattributes
.gitignore
AGENTS.md
BOARD.md
CLAUDE.md
README.md
RTK.md
backend/Dockerfile
backend/README.md
backend/pyproject.toml
backend/requirements-dev.txt
backend/requirements.txt
backend/tests/test_agent.py
backend/tests/test_api.py
backend/tests/test_ask.py
backend/tests/test_data.py
backend/tests/test_evaluate.py
backend/tests/test_model.py
backend/tests/test_store.py
backend/tests/test_timeline.py
backend/tests/test_watcher.py
backend/tests/test_weather.py
backend/windcast/__init__.py
backend/windcast/_stubs.py
backend/windcast/agent.py
backend/windcast/api.py
backend/windcast/ask.py
backend/windcast/backtest.py
backend/windcast/config.py
backend/windcast/data.py
backend/windcast/evaluate.py
backend/windcast/model.py
backend/windcast/paths.py
backend/windcast/ports.py
backend/windcast/runs.py
backend/windcast/store.py
backend/windcast/timeline.py
backend/windcast/tools.py
backend/windcast/watcher.py
backend/windcast/weather.py
data/README.md
data/processed/.gitkeep
data/raw/turbine_1.csv
data/raw/turbine_2.csv
data/weather_cache/.gitkeep
data/weather_cache/previous_2025-12-31_2026-01-02.json
data/weather_cache/previous_2026-01-01_2026-01-03.json
data/weather_cache/previous_2026-01-02_2026-01-04.json
data/weather_cache/previous_2026-01-03_2026-01-05.json
data/weather_cache/previous_2026-01-04_2026-01-06.json
data/weather_cache/previous_2026-01-05_2026-01-07.json
data/weather_cache/previous_2026-01-06_2026-01-08.json
data/weather_cache/previous_2026-01-07_2026-01-09.json
data/weather_cache/previous_2026-01-08_2026-01-10.json
data/weather_cache/previous_2026-01-09_2026-01-11.json
data/weather_cache/previous_2026-01-10_2026-01-12.json
data/weather_cache/previous_2026-01-11_2026-01-13.json
data/weather_cache/previous_2026-01-12_2026-01-14.json
data/weather_cache/previous_2026-01-13_2026-01-15.json
data/weather_cache/previous_2026-01-14_2026-01-16.json
data/weather_cache/previous_2026-01-15_2026-01-17.json
data/weather_cache/previous_2026-01-16_2026-01-18.json
data/weather_cache/previous_2026-01-17_2026-01-19.json
data/weather_cache/previous_2026-01-18_2026-01-20.json
data/weather_cache/previous_2026-01-19_2026-01-21.json
data/weather_cache/previous_2026-01-20_2026-01-22.json
data/weather_cache/previous_2026-01-21_2026-01-23.json
data/weather_cache/previous_2026-01-22_2026-01-24.json
data/weather_cache/previous_2026-01-23_2026-01-25.json
data/weather_cache/previous_2026-01-24_2026-01-26.json
data/weather_cache/previous_2026-01-25_2026-01-27.json
data/weather_cache/previous_2026-01-26_2026-01-28.json
data/weather_cache/previous_2026-01-27_2026-01-29.json
data/weather_cache/previous_2026-01-28_2026-01-30.json
data/weather_cache/previous_2026-01-29_2026-01-31.json
data/weather_cache/previous_2026-01-31_2026-02-02.json
data/weather_cache/previous_2026-02-01_2026-02-03.json
data/weather_cache/previous_2026-02-02_2026-02-04.json
data/weather_cache/previous_2026-02-03_2026-02-05.json
data/weather_cache/previous_2026-02-04_2026-02-06.json
data/weather_cache/previous_2026-02-05_2026-02-07.json
data/weather_cache/previous_2026-02-06_2026-02-08.json
data/weather_cache/previous_2026-02-07_2026-02-09.json
data/weather_cache/previous_2026-02-08_2026-02-10.json
data/weather_cache/previous_2026-02-09_2026-02-11.json
data/weather_cache/previous_2026-02-10_2026-02-12.json
data/weather_cache/previous_2026-02-11_2026-02-13.json
data/weather_cache/previous_2026-02-12_2026-02-14.json
data/weather_cache/previous_2026-02-13_2026-02-15.json
data/weather_cache/previous_2026-02-14_2026-02-16.json
data/weather_cache/previous_2026-02-15_2026-02-17.json
data/weather_cache/previous_2026-02-16_2026-02-18.json
data/weather_cache/previous_2026-02-17_2026-02-19.json
data/weather_cache/previous_2026-02-18_2026-02-20.json
data/weather_cache/previous_2026-02-19_2026-02-21.json
data/weather_cache/previous_2026-02-20_2026-02-22.json
data/weather_cache/previous_2026-02-21_2026-02-23.json
data/weather_cache/previous_2026-02-22_2026-02-24.json
data/weather_cache/previous_2026-02-23_2026-02-25.json
data/weather_cache/previous_2026-02-24_2026-02-26.json
data/weather_cache/previous_2026-02-25_2026-02-27.json
data/weather_cache/previous_2026-02-26_2026-02-28.json
data/weather_cache/previous_2026-02-27_2026-03-01.json
data/weather_cache/previous_2026-02-28_2026-03-02.json
data/weather_cache/previous_runs_bulk.json
docker-compose.yml
docs/BRAINSTORM.md
docs/CONTRACT.md
docs/DATA_NOTES.md
docs/DEMO.md
docs/RUBRIC.md
docs/SCORE.md
docs/SLIDES.md
docs/SUBMISSION.md
docs/THIRD_PARTY.md
docs/architecture.html
docs/change-request-template.md
docs/hackathon/cases-forecast.md
docs/hackathon/criteria.md
docs/hackathon/playbook.md
docs/hackathon/regulation.md
docs/hackathon/task.md
docs/progress/kuba.md
docs/progress/kubevele.md
docs/progress/sula.md
docs/references/README.md
docs/references/TracePanel.jsx
docs/references/agent_loop.py
docs/references/data-quickstart.md
docs/references/trace-event-schema.md
docs/screenshots/february.png
docs/screenshots/live.png
docs/screenshots/quality.png
docs/task-workflow.md
docs/ui-mockup.html
frontend/.dockerignore
frontend/Dockerfile
frontend/README.md
frontend/fixtures/.gitkeep
frontend/fixtures/README.md
frontend/fixtures/_generate.py
frontend/fixtures/forecasts_2026-01-31.json
frontend/fixtures/forecasts_2026-02-01.json
frontend/fixtures/forecasts_2026-02-02.json
frontend/fixtures/forecasts_2026-02-03.json
frontend/fixtures/forecasts_2026-02-03_v1.json
frontend/fixtures/forecasts_2026-02-04.json
frontend/fixtures/forecasts_2026-02-05.json
frontend/fixtures/forecasts_2026-02-06.json
frontend/fixtures/forecasts_2026-02-07.json
frontend/fixtures/forecasts_2026-02-08.json
frontend/fixtures/forecasts_2026-02-08_v1.json
frontend/fixtures/forecasts_2026-02-09.json
frontend/fixtures/forecasts_2026-02-10.json
frontend/fixtures/forecasts_2026-02-11.json
frontend/fixtures/forecasts_2026-02-12.json
frontend/fixtures/forecasts_2026-02-13.json
frontend/fixtures/forecasts_2026-02-13_v1.json
frontend/fixtures/forecasts_2026-02-14.json
frontend/fixtures/forecasts_2026-02-15.json
frontend/fixtures/forecasts_2026-02-16.json
frontend/fixtures/forecasts_2026-02-17.json
frontend/fixtures/forecasts_2026-02-18.json
frontend/fixtures/forecasts_2026-02-19.json
frontend/fixtures/forecasts_2026-02-19_v1.json
frontend/fixtures/forecasts_2026-02-20.json
frontend/fixtures/forecasts_2026-02-21.json
frontend/fixtures/forecasts_2026-02-22.json
frontend/fixtures/forecasts_2026-02-23.json
frontend/fixtures/forecasts_2026-02-24.json
frontend/fixtures/forecasts_2026-02-24_v1.json
frontend/fixtures/forecasts_2026-02-25.json
frontend/fixtures/forecasts_2026-02-26.json
frontend/fixtures/forecasts_2026-02-27.json
frontend/fixtures/forecasts_2026-02-27_v1.json
frontend/fixtures/forecasts_2026-02-28.json
frontend/fixtures/forecasts_live.json
frontend/fixtures/health.json
frontend/fixtures/issues.json
frontend/fixtures/live_status.json
frontend/fixtures/metrics.json
frontend/fixtures/metrics_series.json
frontend/fixtures/run_events_issue.json
frontend/fixtures/run_events_new_weather_run.json
frontend/fixtures/traces_2026-01-31.json
frontend/fixtures/traces_2026-02-01.json
frontend/fixtures/traces_2026-02-02.json
frontend/fixtures/traces_2026-02-03.json
frontend/fixtures/traces_2026-02-04.json
frontend/fixtures/traces_2026-02-05.json
frontend/fixtures/traces_2026-02-06.json
frontend/fixtures/traces_2026-02-07.json
frontend/fixtures/traces_2026-02-08.json
frontend/fixtures/traces_2026-02-09.json
frontend/fixtures/traces_2026-02-10.json
frontend/fixtures/traces_2026-02-11.json
frontend/fixtures/traces_2026-02-12.json
frontend/fixtures/traces_2026-02-13.json
frontend/fixtures/traces_2026-02-14.json
frontend/fixtures/traces_2026-02-15.json
frontend/fixtures/traces_2026-02-16.json
frontend/fixtures/traces_2026-02-17.json
frontend/fixtures/traces_2026-02-18.json
frontend/fixtures/traces_2026-02-19.json
frontend/fixtures/traces_2026-02-20.json
frontend/fixtures/traces_2026-02-21.json
frontend/fixtures/traces_2026-02-22.json
frontend/fixtures/traces_2026-02-23.json
frontend/fixtures/traces_2026-02-24.json
frontend/fixtures/traces_2026-02-25.json
frontend/fixtures/traces_2026-02-26.json
frontend/fixtures/traces_2026-02-27.json
frontend/fixtures/traces_2026-02-28.json
frontend/index.html
frontend/nginx.conf
frontend/package-lock.json
frontend/package.json
frontend/src/AgentPanel.jsx
frontend/src/App.jsx
frontend/src/ChatPanel.jsx
frontend/src/February.jsx
frontend/src/ForecastChart.jsx
frontend/src/Live.jsx
frontend/src/Quality.jsx
frontend/src/agent.test.js
frontend/src/api.js
frontend/src/api.test.js
frontend/src/chart.js
frontend/src/chart.test.js
frontend/src/chat.css
frontend/src/chat.test.js
frontend/src/format.js
frontend/src/main.jsx
frontend/src/stream.test.js
frontend/src/styles.css
frontend/src/useAgentRun.js
frontend/vite.config.js
infra/.env.example
infra/Caddyfile
infra/Caddyfile.local
infra/README.md
infra/caddy-site.snippet
infra/deploy.sh
infra/docker-compose.hosted.yml
infra/docker-compose.yml
infra/server-setup.sh
ml-prognoz-model/.gitignore
ml-prognoz-model/README.md
ml-prognoz-model/artifacts/csv_only/best_ml_model.pkl
ml-prognoz-model/artifacts/csv_only/best_ml_model.pkl.manifest.json
ml-prognoz-model/artifacts/csv_only/best_model.pkl
ml-prognoz-model/artifacts/csv_only/best_model.pkl.manifest.json
ml-prognoz-model/artifacts/csv_only/candidate_tuning.csv
ml-prognoz-model/artifacts/csv_only/dataset_manifest.json
ml-prognoz-model/artifacts/csv_only/evaluation_report.json
ml-prognoz-model/artifacts/csv_only/forecast_24h.csv
ml-prognoz-model/artifacts/csv_only/forecast_48h.csv
ml-prognoz-model/artifacts/csv_only/forecast_ml_24h.csv
ml-prognoz-model/artifacts/csv_only/forecast_ml_48h.csv
ml-prognoz-model/artifacts/csv_only/holdout_predictions.parquet
ml-prognoz-model/artifacts/csv_only/leaderboard.csv
ml-prognoz-model/artifacts/csv_only/run_config.json
ml-prognoz-model/configs/default.json
ml-prognoz-model/configs/history.json
ml-prognoz-model/docs/README.md
ml-prognoz-model/docs/data.md
ml-prognoz-model/docs/delivery.md
ml-prognoz-model/docs/evaluation.md
ml-prognoz-model/docs/history.md
ml-prognoz-model/docs/inference.md
ml-prognoz-model/docs/models.md
ml-prognoz-model/docs/reproducibility.md
ml-prognoz-model/docs/results.md
ml-prognoz-model/docs/weather.md
ml-prognoz-model/pyproject.toml
ml-prognoz-model/reports/generated/data_quality.json
ml-prognoz-model/reports/generated/incomplete_hours.csv
ml-prognoz-model/reports/generated/inference_verification.json
ml-prognoz-model/reports/generated/invalid_rows.csv
ml-prognoz-model/src/wind_forecast/__init__.py
ml-prognoz-model/src/wind_forecast/__main__.py
ml-prognoz-model/src/wind_forecast/artifact.py
ml-prognoz-model/src/wind_forecast/cli.py
ml-prognoz-model/src/wind_forecast/config.py
ml-prognoz-model/src/wind_forecast/data.py
ml-prognoz-model/src/wind_forecast/evaluation.py
ml-prognoz-model/src/wind_forecast/features.py
ml-prognoz-model/src/wind_forecast/history.py
ml-prognoz-model/src/wind_forecast/history_artifact.py
ml-prognoz-model/src/wind_forecast/history_evaluation.py
ml-prognoz-model/src/wind_forecast/history_models.py
ml-prognoz-model/src/wind_forecast/io.py
ml-prognoz-model/src/wind_forecast/models.py
ml-prognoz-model/src/wind_forecast/offline.py
ml-prognoz-model/src/wind_forecast/weather.py
ml-prognoz-model/tests/test_artifact.py
ml-prognoz-model/tests/test_cli.py
ml-prognoz-model/tests/test_config.py
ml-prognoz-model/tests/test_data.py
ml-prognoz-model/tests/test_evaluation.py
ml-prognoz-model/tests/test_features.py
ml-prognoz-model/tests/test_history.py
ml-prognoz-model/tests/test_history_artifact.py
ml-prognoz-model/tests/test_history_evaluation.py
ml-prognoz-model/tests/test_history_models.py
ml-prognoz-model/tests/test_io.py
ml-prognoz-model/tests/test_models.py
ml-prognoz-model/tests/test_offline.py
ml-prognoz-model/tests/test_weather.py
ml-prognoz-model/uv.lock
models/.gitkeep
models/README.md
models/quantile_2025-12-31.pkl
models/quantile_2026-01-31.pkl
outputs/README.md
outputs/evaluation/README.md
outputs/evaluation/february_all_horizons.csv
outputs/evaluation/february_day_ahead.csv
outputs/evaluation/january_day_ahead.csv
outputs/forecast_feb2026.csv
outputs/forecasts/.gitkeep
outputs/forecasts/2026-01-31.csv
outputs/forecasts/2026-01-31.json
outputs/forecasts/2026-02-01.csv
outputs/forecasts/2026-02-01.json
outputs/forecasts/2026-02-02.csv
outputs/forecasts/2026-02-02.json
outputs/forecasts/2026-02-03.csv
outputs/forecasts/2026-02-03.json
outputs/forecasts/2026-02-04.csv
outputs/forecasts/2026-02-04.json
outputs/forecasts/2026-02-05.csv
outputs/forecasts/2026-02-05.json
outputs/forecasts/2026-02-06.csv
outputs/forecasts/2026-02-06.json
outputs/forecasts/2026-02-07.csv
outputs/forecasts/2026-02-07.json
outputs/forecasts/2026-02-08.csv
outputs/forecasts/2026-02-08.json
outputs/forecasts/2026-02-09.csv
outputs/forecasts/2026-02-09.json
outputs/forecasts/2026-02-10.csv
outputs/forecasts/2026-02-10.json
outputs/forecasts/2026-02-11.csv
outputs/forecasts/2026-02-11.json
outputs/forecasts/2026-02-12.csv
outputs/forecasts/2026-02-12.json
outputs/forecasts/2026-02-13.csv
outputs/forecasts/2026-02-13.json
outputs/forecasts/2026-02-14.csv
outputs/forecasts/2026-02-14.json
outputs/forecasts/2026-02-15.csv
outputs/forecasts/2026-02-15.json
outputs/forecasts/2026-02-16.csv
outputs/forecasts/2026-02-16.json
outputs/forecasts/2026-02-17.csv
outputs/forecasts/2026-02-17.json
outputs/forecasts/2026-02-18.csv
outputs/forecasts/2026-02-18.json
outputs/forecasts/2026-02-19.csv
outputs/forecasts/2026-02-19.json
outputs/forecasts/2026-02-20.csv
outputs/forecasts/2026-02-20.json
outputs/forecasts/2026-02-21.csv
outputs/forecasts/2026-02-21.json
outputs/forecasts/2026-02-22.csv
outputs/forecasts/2026-02-22.json
outputs/forecasts/2026-02-23.csv
outputs/forecasts/2026-02-23.json
outputs/forecasts/2026-02-24.csv
outputs/forecasts/2026-02-24.json
outputs/forecasts/2026-02-25.csv
outputs/forecasts/2026-02-25.json
outputs/forecasts/2026-02-26.csv
outputs/forecasts/2026-02-26.json
outputs/forecasts/2026-02-27.csv
outputs/forecasts/2026-02-27.json
outputs/forecasts/2026-02-28.csv
outputs/forecasts/2026-02-28.json
outputs/metrics_jan.json
outputs/traces/.gitkeep
outputs/traces/2026-01-31.jsonl
outputs/traces/2026-02-01.jsonl
outputs/traces/2026-02-02.jsonl
outputs/traces/2026-02-03.jsonl
outputs/traces/2026-02-04.jsonl
outputs/traces/2026-02-05.jsonl
outputs/traces/2026-02-06.jsonl
outputs/traces/2026-02-07.jsonl
outputs/traces/2026-02-08.jsonl
outputs/traces/2026-02-09.jsonl
outputs/traces/2026-02-10.jsonl
outputs/traces/2026-02-11.jsonl
outputs/traces/2026-02-12.jsonl
outputs/traces/2026-02-13.jsonl
outputs/traces/2026-02-14.jsonl
outputs/traces/2026-02-15.jsonl
outputs/traces/2026-02-16.jsonl
outputs/traces/2026-02-17.jsonl
outputs/traces/2026-02-18.jsonl
outputs/traces/2026-02-19.jsonl
outputs/traces/2026-02-20.jsonl
outputs/traces/2026-02-21.jsonl
outputs/traces/2026-02-22.jsonl
outputs/traces/2026-02-23.jsonl
outputs/traces/2026-02-24.jsonl
outputs/traces/2026-02-25.jsonl
outputs/traces/2026-02-26.jsonl
outputs/traces/2026-02-27.jsonl
outputs/traces/2026-02-28.jsonl
scripts/checkpoint.sh
scripts/export_evaluation.py
scripts/review-prompt.md
scripts/review.sh
scripts/score.py
scripts/taskflow/lib.sh
scripts/taskflow/test_tf.sh
scripts/taskflow/tf.sh
scripts/tests/test_score.py
scripts/tests/test_verify.py
scripts/verify.py
scripts/watch.sh
templates/CONTRACT.md
templates/README.template.md
templates/SLIDES.md
templates/SUBMISSION_CHECKLIST.md
templates/VIDEO_SCRIPT.md
templates/smoke/README.md
templates/smoke/backend/Dockerfile
templates/smoke/backend/app.py
templates/smoke/frontend/Dockerfile
templates/smoke/frontend/index.html
templates/smoke/frontend/nginx.conf
Ветки (11)

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

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

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