О проекте
Команда: OFFSCRIPT
Кейс HackAlem.ai: Энергетика — Самрук-Казына
Стадия: Доведённый продукт
Задача кейса: AI-агент, прогнозирующий выработку ветровой электростанции по погодным данным
Суть
AI-агент почасового вероятностного прогноза (P10/P50/P90) выработки двухтурбинной ВЭС на 24–48 ч по архивным прогнозам погоды, с воспроизведением февраля 2026 по дням, брифингами на трёх языках и hash-chained журналом прогнозов.
Как устроено
SCADA очищается (смена часового пояса, почасовое усреднение, флаги простоя и обледенения); погода берётся из Open-Meteo Previous Runs (ECMWF IFS, GFS, ICON), а TemporalGuard выбирает только прогнозы, доступные на момент выпуска. ML-ядро: изотоническая кривая мощности + MOS-коррекция ветра + квантильный градиентный бустинг, коэффициент доступности и конформная калибровка P10–P90. Агент проходит этапы PLAN→FETCH→QC→PREDICT→ANALYZE→DECIDE→CRITIC→RECALC→BRIEF→PUBLISH: планировщик, решатель и критик работают на LLM или на правилах (офлайн-фолбэк), брифинг на KZ/RU/EN сверяется с посчитанными числами. Прогнозы пишутся в SHA-256 журнал и отдаются через FastAPI/SSE в React-интерфейс.
Ключевые решения
- квантильный градиентный бустинг
- изотоническая кривая мощности
- MOS-коррекция
- конформная калибровка
- TemporalGuard (защита от утечки будущего)
- critic с детерминированным вето
- SHA-256 hash-chained ledger
- LLM response cache
- бэктест против persistence и климатологии
Метрики
NMAE 20.29% (фев 2025), 18.08% (зима 2025–26); skill vs persistence +51.6%/+51.9%; покрытие P10–P90 92.95%/79.62%; bias +2.13/+1.25 п.п.
Особенности
Строгая защита от утечки данных: используются только архивные прогнозы, доступные на момент выпуска, с регрессионным тестом. Бэктест честно сравнивается с persistence и климатологией, критик может перезапустить цикл, а LLM-кеш позволяет воспроизвести демо без ключа.
Стек
Python · FastAPI · React · TypeScript · Docker Compose · Makefile · joblib · Open-Meteo API
Модели
OpenAI (provider-neutral LLM adapter)
Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-3cc2878c-offscript.
README
README.mdOpenWind: agentic wind-farm power forecasting
HackAlem AI 2026 · Case: Agentic AI for Wind Farm Generation Forecasting (ВЭС).
OpenWind is an AI agent that produces hourly probabilistic (P10/P50/P90) generation forecasts 24–48 h ahead for a two-turbine wind farm in the Shelek corridor (Almaty region). It replays the February 2026 test period day by day, selecting archived forecast offsets under a documented availability assumption (provider release times are not verified), checks its own output, writes dispatcher briefings in Kazakh, Russian and English, and seals every published forecast in a tamper-evident hash-chained ledger.
Быстрый запуск для технической комиссии (3 команды, нужен только Docker):
git clone https://github.com/BAITC-Hacks/hack-3cc2878c-offscript.git && cd hack-3cc2878c-offscript cp .env.example .env docker compose up --buildОткройте http://localhost:5173 (интерфейс) и http://localhost:8000/docs (API). Интернет, ключи API и обучение моделей не требуются: архив прогнозов погоды, обученные модели и результаты уже находятся в репозитории. Проверка основного сценария описана в разделе 9.
README requirements checklist / Соответствие требованиям к README.
| Требование (HackAlem AI) | Section |
|---|---|
| Описание решения и его назначения | 1 |
| Описание архитектуры | 2 |
| Используемые технологии | 3 |
| Системные требования | 4 |
| Инструкции по установке | 5 |
| Настройка, параметры окружения | 6 |
| Инструкции по запуску | 7 |
| Необходимые зависимости | 8 |
| Порядок проверки основного сценария | 9 |
1. Описание решения / Solution and purpose.
Problem. Wind generation is variable. The grid operator and the farm need an hourly forecast for the next day, with an honest uncertainty range, so they can plan balancing reserves and limit imbalance costs.
What OpenWind does. It forecasts the normalized output (0–1 of farm capacity) of the two-turbine farm (turbine coordinates 43.64515 N, 78.53560 E and 43.64320 N, 78.53883 E; farm point used for weather 43.6442 N, 78.5372 E):
The source column is normalized active power on the line side. Charts multiply that 0–1 quantity by 100: 100% means full assumed farm capacity, not forecast confidence or a probability. P10/P50/P90 are power quantiles on the same scale; MW/MWh use the configurable 5 MW capacity assumption.
- Forecast issues. One forecast is issued at 00:00 local time (Asia/Almaty, UTC+5) on every day from 31 Jan to 27 Feb 2026, which is 28 issues.
- Horizon. Each issue covers the next 48 hours at hourly resolution. Leads 24–47 h are the day-ahead product, so the 28 issues cover every hour of 1–28 Feb 2026 (672 hours).
- Archived-offset weather. Weather comes from the Open-Meteo Previous Runs archive (ECMWF IFS 0.25°, NCEP GFS, DWD ICON). TemporalGuard selects fixed lead-time offsets using a configured 8-hour latency assumption; the API does not provide verified source release timestamps (see Compliance).
- The agent runs the cycle. It plans, retrieves the archived weather, checks input quality, runs the ML model, scans risks, decides, has a critic audit the result (reruns are possible), writes a briefing and publishes the forecast to the ledger.
- Deterministic fallback. Without an LLM key, every LLM decision is replaced by a rule-based policy, so the project runs fully offline.
How the case requirements are covered
| Case requirement | Implementation | Where / how to check |
|---|---|---|
| Model built on the provided history (Mar 2023 – Jan 2026) | SCADA cleaning (UTC+6→UTC+5 clock change on 1 Mar 2024, hourly averaging, outage/stuck/icing flags) → empirical power curve (isotonic) → MOS wind correction → quantile gradient boosting → availability correction → conformal calibration of P10–P90 | ml/openwind_ml/data.py, models.py, power_curve.py |
| Weather forecasts from open sources, by the farm coordinates, as available at the forecast moment | Open-Meteo Previous Runs API, three NWP models; previous_dayK offsets chosen by the TemporalGuard rule; downloaded archive committed to data/cache/nwp/ | ml/openwind_ml/weather.py, temporal_guard.py; make fetch |
| Hourly forecast for the next 24–48 h | 48 hourly rows per issue; day-ahead product = leads 24–47 | data/outputs/submission/forecast_feb2026_dayahead.csv (672 rows) |
| Agentic cycle: retrieve weather → prepare data → run model → hourly forecast → analyze → recalculate on new input | Orchestrator stages PLAN → FETCH → QC → PREDICT → ANALYZE → DECIDE → CRITIC → RECALC → BRIEF → PUBLISH, streamed live to the UI | backend/app/agent/orchestrator.py; UI tab Agent console |
| Replay as if in the past: 31 Jan → forecast, 1 Feb → new forecast, … through February | 28 sequential issues, each built only from data available at its issue time | make test-run, make demo; data/outputs/forecasts/test/ |
| Archived forecast offsets, never actual weather | TemporalGuard checks the configured offset/latency policy inside every feature build; manifests hash cached chunks; new ledger blocks record an estimated NWP initialization time and explicit unverified-release status | ml/tests/test_temporal_guard.py; POST /api/ledger/verify |
Validation (honest backtests, day-ahead leads 24–47 h, error normalized to farm capacity)
Each validation model is trained only on data before the first issue of its period (SCADA after that point is removed before any fitting), then replayed issue by issue exactly like the test period.
The OpenWind hybrid median is a fixed 50/50 blend of the quantile model and the MOS power curve. It is multiplied by an availability factor: the share of hours in the 56-day calibration window before training ends in which the farm produced without outage, stuck-sensor or missing-data flags. Before this correction the hybrid over-forecast by about 8–9 percentage points of capacity, because real output includes downtime. The correction brought the hybrid bias down to +2.1 pp (Feb 2025) and +1.2 pp (winter).
Winter P10–P90 coverage is near its 80% target; February 2025 over-covers at 92.95%, a remaining calibration limitation.
| Held-out period | Hours | Model | NMAE | Bias | Skill vs persistence | P10–P90 coverage (target 80%) |
|---|---|---|---|---|---|---|
| Feb 2025 (seasonal twin) | 667 | OpenWind hybrid | 20.29% | +2.13 pp | +51.56% | 92.95% |
| MOS wind + power curve | 21.27% | +8.41 pp | +49.22% | 66.57% | ||
| Raw NWP wind + power curve | 21.48% | +8.58 pp | +48.73% | 65.67% | ||
| Climatology (month × hour) | 31.83% | +7.87 pp | +24.01% | 18.74% | ||
| Persistence (last observed power) | 41.89% | +1.28 pp | +0.00% | 28.79% | ||
| Winter 2025–26 (Nov–Jan) | 2,208 | OpenWind hybrid | 18.08% | +1.25 pp | +51.90% | 79.62% |
| MOS wind + power curve | 18.12% | +6.76 pp | +51.78% | 52.45% | ||
| Raw NWP wind + power curve | 19.55% | +8.89 pp | +47.98% | 51.13% | ||
| Climatology (month × hour) | 33.15% | +5.19 pp | +11.80% | 16.80% | ||
| Persistence (last observed power) | 37.59% | -5.98 pp | +0.00% | 29.89% |
Numbers are copied from data/outputs/metrics/val_feb2025.json and val_winter.json; make validate regenerates them.
February 2026 actual generation was not provided, so no test-period accuracy is claimed.
2. Архитектура / Architecture
flowchart LR
subgraph DATA["Data in the repository"]
S["Organizer SCADA<br/>data/raw/turbine_1.csv, turbine_2.csv"]
W["Open-Meteo Previous Runs API<br/>ECMWF IFS · GFS · ICON"]
C["Archived NWP cache<br/>data/cache/nwp/*.csv.gz"]
end
W -->|"make fetch"| C
C --> TG["TemporalGuard<br/>K = ceil((lead_h + 8) / 24)"]
S --> CL["SCADA cleaning<br/>UTC, hourly, quality flags"]
TG --> FE["Feature builder<br/>hub wind, air density, spread"]
CL --> ML
FE --> ML["ML engine (openwind_ml)<br/>power curve · MOS · quantile GBM<br/>availability correction · conformal P10–P90"]
subgraph AGENT["Agent orchestrator (backend)"]
PL["Planner<br/>LLM or rules"] --> TO["Tools<br/>fetch → QC → forecast → risk scan"]
TO --> DE["Decider<br/>LLM or rules"]
DE --> CR["Critic<br/>LLM + deterministic veto"]
CR -->|"reject, up to 2 reruns"| TO
CR --> BR["Briefing EN / RU / KZ<br/>numbers checked against computed facts"]
end
ML --> TO
BR --> LG["SHA-256 hash-chained ledger<br/>data/ledger/ledger.jsonl"]
LG --> API["FastAPI REST + SSE<br/>:8000"]
API --> UI["React control room<br/>:5173"]
Components
| Folder | Role |
|---|---|
ml/openwind_ml/ | Forecasting engine (Python package): SCADA loading and cleaning (data.py), archived weather retrieval and cache (weather.py), no-lookahead rule (temporal_guard.py), features (features.py), models (models.py, power_curve.py), baselines, risk flags (risk.py), metrics, backtest/replay and submission writer (backtest.py), CLI (cli.py), stable JSON API for the backend (api.py) |
backend/app/ | FastAPI service: agent orchestrator (agent/orchestrator.py), rule-based policy (agent/policy.py), provider-neutral LLM adapter with structured JSON output and a response cache (agent/llm.py), briefing grounding check (agent/briefing.py), ledger (ledger.py), REST/SSE routers (routers/), batch replay (batch.py) |
frontend/src/ | React control room with 5 tabs: Forecast, Agent console, Backtest & skill, Ledger, Economics |
data/ | raw/ organizer SCADA · cache/nwp/ archived weather (27 files: 3 models × 9 date chunks) · models/ trained bundles · outputs/ forecasts, metrics, submission CSVs, agent runs, ledger payloads · ledger/ hash chain · llm_cache/ recorded LLM responses |
shared/mocks/ | JSON fixtures that mirror the API contract (used only with VITE_USE_MOCKS=1 or USE_ML_STUB=1) |
docs/ | API contracts (CONTRACTS.md), design decisions (ARCHITECTURE.md), demo script, task text |
Agent cycle (one issue). The frontend calls POST /api/agent/run, then streams progress from GET /api/agent/stream/{run_id} (SSE):
PLAN: the planner chooses the weather models and the model variant.FETCH: archived NWP is loaded through TemporalGuard, which records an offset-derived estimated weather-run time, not a provider-verified timestamp.QC: input coverage and model-disagreement checks.PREDICT: the ML engine computes 48 hourly P10/P50/P90 values.ANALYZE: the risk scan flags ramps, low confidence, model disagreement, cut-out and icing.DECIDE: ACCEPT / WIDEN / RERUN / ESCALATE.CRITIC: an independent audit. If it rejects, the forecast is rerun (at most twice). A deterministic physical check can veto an LLM approval.RECALC: each new replay issue compares its 24 overlapping target hours against the prior published issue, including comparable per-hour selected-NWP fingerprints and forecast MAE/max change. The new issue remains aFORECASTblock. For the same issue, an automatic weather check publishes aREVISIONonly when selected input values changed; otherwise it ends without a new block. An operator can explicitly request a separately labelled manual uncertainty review.BRIEF: dispatcher briefing in EN/RU/KZ. LLM text is rejected if it contains a number that is not in the computed facts.PUBLISH: the forecast payload is written to an immutable file, and its SHA-256 goes into a new ledger block.
Numeric forecasts always come from Python, never from the LLM.
Optional NWP watcher. Set NWP_WATCH_ENABLED=1 to poll the selected archived cache for a published issue. It compares the current selected-input fingerprint with the latest sealed version and automatically starts one keyless recalculation per changed version. Set NWP_WATCH_ISSUE_DATE to pin an issue, or leave it blank to watch the latest published issue in NWP_WATCH_MODE. This watches the local archive; it does not fetch live provider updates or prove when a source run was released. Refreshing the cache is a separate operation.
REST API (interactive documentation at http://localhost:8000/docs)
| Method and path | Purpose |
|---|---|
GET /api/health | Service status and active configuration |
GET /api/meta | Farm metadata, issue schedules, TemporalGuard rule |
GET /api/forecast?issue_date=2026-02-15&mode=test&variant=hybrid | 48-hour forecast, risk flags, briefing, ledger integrity record when sealed |
POST /api/agent/run, POST /api/agent/recalc | Start an agent run or a same-issue recalculation; reason:"new_nwp" requires changed selected inputs, while reason:"manual_uncertainty_review" explicitly publishes an operator review |
GET /api/agent/stream/{run_id} | Live agent trace (Server-Sent Events) |
GET /api/agent/runs, GET /api/agent/runs/{run_id} | Stored agent runs |
GET /api/backtest?mode=val_feb2025, GET /api/series?mode=val_winter | Validation metrics and day-ahead series |
GET /api/ledger, POST /api/ledger/verify, POST /api/ledger/tamper-demo | Ledger contents, verification, tamper-detection demo |
GET /api/economics?capacity_mw=5&price_kzt_mwh=15000 | Illustrative imbalance-cost comparison |
3. Технологии / Technologies
| Layer | Technologies (pinned versions) |
|---|---|
| ML | Python 3.11, pandas 2.2.3, NumPy 1.26.4, scikit-learn 1.5.2 (HistGradientBoosting with quantile loss, IsotonicRegression), joblib 1.4.2, requests 2.32.3 |
| Backend and agent | FastAPI 0.115.0, Uvicorn 0.30.6, Pydantic 2.9.2, sse-starlette 2.1.3, python-dotenv 1.0.1; optional LLM SDKs openai 3.19.0 / anthropic 1.8.0 |
| Frontend | React 18.3.1, TypeScript 5.6.3, Vite 5.4.11, Tailwind CSS 3.4.17, Recharts 2.13.3, lucide-react |
| Weather data | Open-Meteo Previous Runs API (ECMWF IFS 0.25°, NCEP GFS, DWD ICON), no API key required |
| Delivery | Docker Compose (python:3.11-slim, node:20-alpine build, nginx:1.27-alpine), pytest 8.3.3 |
4. Системные требования / System requirements
| Docker option (recommended) | Local option | |
|---|---|---|
| OS | Linux, macOS (Intel or Apple Silicon), Windows 10/11 with Docker Desktop | macOS or Linux (on Windows use WSL2 or Git Bash) |
| Software | Docker Engine 24+ with the Compose v2 plugin (docker compose), or Docker Desktop 4.x | Python 3.11 or newer, Node.js 20 (18+ works), npm, Git, make (optional) |
| RAM / disk | 4 GB RAM free; about 3 GB disk for images and build cache | 4 GB RAM; about 1.5 GB disk for the virtual environment and node_modules |
| Ports | 5173 (UI) and 8000 (API) must be free | 5173 and 8000 |
| Internet | Only for the first image build and package download. Running and verifying works offline. | Only for installing packages (and optionally make fetch) |
The repository itself is about 50 MB. It includes SCADA data, the weather archive, trained models and outputs, so no separate download is needed.
5. Установка / Installation
Option A: Docker (recommended for the technical commission)
# 1. Get the code
git clone https://github.com/BAITC-Hacks/hack-3cc2878c-offscript.git
cd hack-3cc2878c-offscript
# 2. Create the environment file (defaults work as is: offline weather, real ML, no LLM key)
cp .env.example .env # Windows PowerShell: Copy-Item .env.example .env
# 3. Build the images (first build takes a few minutes: it downloads base images and Python/Node packages)
docker compose build
Option B: local installation (macOS / Linux)
# 1. Get the code
git clone https://github.com/BAITC-Hacks/hack-3cc2878c-offscript.git
cd hack-3cc2878c-offscript
# 2. Python environment (Python 3.11+)
python3.11 -m venv .venv
source .venv/bin/activate
pip install -r backend/requirements.txt # also installs ml/requirements.txt
pip install -e ml # install the forecasting Python package
# 3. Frontend packages (Node.js 20)
cd frontend && npm ci && cd ..
# 4. Environment file
cp .env.example .env
Steps 2–3 can be replaced by make setup PY=python3.11.
6. Настройка и переменные окружения / Configuration and environment variables
All server settings are read from the repository-root .env file (template: .env.example). Docker Compose passes it to the backend,
and local runs load it automatically. The defaults need no changes.
| Variable | Default | Allowed values | Meaning |
|---|---|---|---|
LLM_PROVIDER | none | none, openai, openai_compatible, anthropic | LLM used by the planner, decider, critic and briefing. none = deterministic rule-based agent (fully offline). |
LLM_MODEL | empty | e.g. gpt-4o-mini | Model name for the chosen provider. If empty, the OpenAI adapter uses gpt-4o-mini. |
LLM_API_KEY | empty | secret key | Put it only in the root .env; never commit it or place it in frontend variables. |
LLM_BASE_URL | empty | URL | Endpoint for openai_compatible providers. |
WEATHER_OFFLINE | 1 | 0 / 1 | 1 = use the committed weather archive (Docker Compose always sets 1). 0 allows make fetch to download missing archive chunks from Open-Meteo. |
NWP_LATENCY_H | 8 | integer hours | Assumed publication delay of a weather-model run, used by the TemporalGuard rule. If you change it, retrain (make validate, make test-run). |
FARM_CAPACITY_MW | 5.0 | number | Assumed farm capacity, used only to convert normalized power to MW/MWh for display and economics. |
HUB_HEIGHT_M | 100 | number | Informational only; the model uses a fixed 100 m hub height (ml/openwind_ml/config.py). |
DEMO_PACING | 0 | 0 / 1 | 1 adds short pauses between agent stages so the live trace is easy to follow during a presentation. |
USE_ML_STUB | 0 | 0 / 1 | 1 serves fixture data instead of the real ML engine (frontend development only). Keep 0. |
NWP_WATCH_ENABLED | 0 | 0 / 1 | Start an opt-in background poller for selected cached NWP inputs. No API key or external fetch is required. |
NWP_WATCH_POLL_SECONDS | 60 | integer ≥ 5 | Interval between fingerprint checks. |
NWP_WATCH_MODE | test | test, val_feb2025, val_winter | Replay schedule to watch. |
NWP_WATCH_ISSUE_DATE | empty | issue date or empty | Pin a published issue; empty watches the latest published issue for the selected mode. |
NWP_WATCH_USE_LLM | 0 | 0 / 1 | Whether watcher-triggered recalculation calls the LLM; keyless deterministic mode is the default. |
Frontend build-time variables (set in docker-compose.yml → frontend.build.args, or in the shell for npm run dev):
| Variable | Default | Meaning |
|---|---|---|
VITE_API_URL | http://127.0.0.1:8000 | Address of the API as seen from the browser. Change it if the UI is opened from another machine (see Troubleshooting). |
VITE_USE_MOCKS | 0 | 1 shows bundled demo fixtures without a backend. |
Optional LLM mode. Set LLM_PROVIDER=openai, LLM_MODEL=gpt-4o-mini and LLM_API_KEY=<key> in .env, then restart the backend.
LLM responses are validated against Pydantic schemas and cached in data/llm_cache/. When LLM_PROVIDER=openai is set without a key, a
recorded response is replayed if the prompt matches exactly; otherwise the deterministic policy is used. The system never depends on the LLM
to produce numbers.
7. Запуск / Running
Option A: Docker
docker compose up --build # add -d to run in the background
The service is ready when the backend log shows Uvicorn running on http://0.0.0.0:8000. Then open:
- UI: http://localhost:5173 (the header shows Live API when the UI is connected to the backend)
- API documentation: http://localhost:8000/docs
Stop with Ctrl+C, or docker compose down.
Option B: local (two terminals, from the repository root)
# Terminal 1: API (run from the repository root)
source .venv/bin/activate
cd backend && PYTHONPATH=.:../ml uvicorn app.main:app --port 8000
# Terminal 2: UI (run from the repository root)
cd frontend && npm run dev -- --port 5173
Reproducing the forecasting pipeline (optional; results are already in the repository)
The make targets are for the local option and run from the repository root with the virtual environment active. With Docker, run
the same steps inside the backend container, for example docker compose exec backend python -m openwind_ml.cli validate --mode val_feb2025,
docker compose exec backend python -m openwind_ml.cli test-run, docker compose exec backend python -m app.batch --mode test.
| Command | What it does | Output |
|---|---|---|
make validate | Trains a model before each validation period (Feb 2025, winter 2025–26) and replays every issue (about 10 minutes on a laptop) | data/models/val_*.joblib, data/outputs/metrics/*.json, data/outputs/forecasts/val_*/ |
make test-run | Trains on all data up to 30 Jan 2026 and replays the 28 February issues | data/models/test.joblib, data/outputs/submission/forecast_feb2026_dayahead.csv, forecast_feb2026_all_issues.csv |
make demo | Runs the agent (deterministic mode) over all 28 test issues and appends them to the ledger | data/ledger/ledger.jsonl, data/outputs/agent_runs/ |
make tests | Runs the ML and backend test suites | pytest summary |
WEATHER_OFFLINE=0 make fetch | Downloads missing archived weather chunks from Open-Meteo (needs internet); existing committed chunks remain unchanged. | data/cache/nwp/*.csv.gz |
Agent runs and make demo append to data/ledger/ledger.jsonl in your checkout (Docker mounts ./data). For repeatable judging, use a fresh clone or copy data/ before a new batch; preserve audit records you want to keep.
8. Зависимости / Dependencies
- Python:
ml/requirements.txt(pandas, NumPy, scikit-learn, requests, joblib, python-dotenv, pytest) andbackend/requirements.txt(includes the ML list, plus FastAPI, Uvicorn, Pydantic, sse-starlette, httpx, openai, anthropic). All versions are pinned. - ML package:
ml/pyproject.toml(pip install -e ml, Python ≥ 3.10; the backend needs 3.11+). - Frontend:
frontend/package.jsonwith the exact lockfilefrontend/package-lock.json(npm ci). - Data dependencies, all committed:
- organizer SCADA in
data/raw/; - archived weather in
data/cache/nwp/; - trained models in
data/models/; - outputs in
data/outputs/.
- organizer SCADA in
- External services: none needed to run. Optional: Open-Meteo (
make fetch) and an LLM API (LLM_PROVIDER).
9. Проверка основного сценария / Verifying the main scenario
Start the project (section 7), then follow the steps. Expected results are shown for each step.
-
API is healthy
curl http://localhost:8000/api/healthExpected:
{"status":"ok","version":"0.1.0","llm_provider":"none","weather_offline":true,"ml_stub":false}(ml_stub:falsemeans the real ML engine is serving forecasts.) -
Forecast tab (http://localhost:5173): choose Issue date 2026-02-15 (use Earlier / Later). Expected:
- a 48-hour fan chart with P10–P90 band and P50 line;
- the chart's left-axis percentages labelled as normalized farm power (% of assumed installed capacity), not forecast probability;
- the day-ahead window (leads 24–47 h) highlighted in the hourly table;
- risk flags and the dispatcher briefing (EN / RU / KZ tabs);
- the ledger badge "Sealed in block #N", and the Model variant selector for comparing baselines.
-
Agent console: click Run agent for 2026-02-15. The live trace shows the stages
PLAN → FETCH (TemporalGuard) → QC → PREDICT → ANALYZE → DECIDE → CRITIC → RECALC (change vs the previous day's forecast) → BRIEF → PUBLISH → DONE. The run ends with a newFORECASTblock whose comparison records the prior issue date, comparable old/new overlap-input hashes, 24 shared hours, MAE/max change, and whether the forecast changed materially. Click Manual uncertainty review only to request an explicitly labelled operatorREVISIONwhen weather inputs are unchanged. An automaticnew_nwpcheck with unchanged inputs instead publishes no revision. -
Ledger tab:
- Click Verify chain. Expected: valid chain, no errors.
- Choose a forecast block and click Tamper demo. Expected: the altered payload is detected (
payload_sha256 mismatch).
The same check with curl:
curl -X POST http://localhost:8000/api/ledger/verify curl -X POST -H "Content-Type: application/json" -d '{"block_index":2}' http://localhost:8000/api/ledger/tamper-demo -
Backtest & skill tab: validation metrics for February 2025 and winter 2025–26, all baselines, error by lead time and daily error.
-
Submission files (the forecast for the whole test period):
head -3 data/outputs/submission/forecast_feb2026_dayahead.csv wc -l data/outputs/submission/forecast_feb2026_dayahead.csv # 673 = header + 672 hours (1–28 Feb 2026)Columns:
target_time_local, target_time_utc, issue_time_utc, lead_h, p10, p50, p90, p50_mw.forecast_feb2026_all_issues.csvcontains all 48 leads of all 28 issues (1,344 rows). -
Automated tests, including the configured availability-policy checks
make tests # or: pytest ml/tests backend/tests -q pytest ml/tests/test_temporal_guard.py -q # weather availability rule, future-SCADA refusalWith Docker:
docker compose exec backend sh -c "cd /app && pytest ml/tests backend/tests -q".
Compliance with "archived forecasts only"
For a target hour at lead lead_h after the issue time, OpenWind uses only the Open-Meteo offset *_previous_dayK with
K = ceil((lead_h + 8) / 24). According to the Open-Meteo Previous Runs documentation, previous_day1 is a value predicted 24 hours before valid
time, previous_day2 48 hours before, and so on. The 8-hour margin is a configured assumption, not an observed publication delay;
the check cannot prove that a particular provider run was actually released by the issue time. previous_day0 (the live run) is never used.
assert_no_lookahead enforces this inside every feature build, for training rows too. Training data for each model ends at its first issue
time. New forecast and ledger records store max_estimated_nwp_init_time_used, policy version, configured latency, and
source_release_time_verified:false; max_nwp_init_time_used remains as a backward-compatible alias. The verifier re-checks the
recorded policy arithmetic and labels older anchored blocks as legacy_policy_evidence without altering their hashes.
Each NWP cache chunk has a sidecar manifest with its request, artifact hash, policy version, and explicit unavailable-release status.
Historical chunks have retrieved_at:null because their original HTTP retrieval time and headers were not preserved; their request URLs are reconstructed from the filename and current fetch configuration and are explicitly marked as such.
For exact run-level initialization data, Open-Meteo directs users to its Single Runs API, whose historical model coverage differs from this cache. See PROJECT_PLAN.md §5.3 and ml/openwind_ml/temporal_guard.py.
Limitations
- The system replays a historical period.
GET /api/live/tomorrowis intentionally disabled (HTTP 501). - The agent's
FETCHstep reads the committed weather archive, so the replay is reproducible offline. New archive data is downloaded withmake fetch. - The ledger detects changes to anchored forecast rows (and, for new blocks, the full saved forecast file) and records whether the configured offset policy was followed. Older anchored blocks retain row-only hash coverage. It cannot independently prove provider publication time or when a replayed forecast was created.
- Pre-rename audit records remain byte-for-byte unchanged to preserve their existing hashes. Their historical labels may still appear in raw archived JSON; current application branding, source package, and newly generated records use OpenWind.
- Farm capacity (5 MW) and imbalance prices on the Economics tab are illustrative assumptions.
- February 2026 actual generation was not provided, so test-period accuracy cannot be measured.
Troubleshooting
| Symptom | Fix |
|---|---|
env file .env not found from Docker Compose | Run cp .env.example .env in the repository root. |
| Port 8000 or 5173 already in use | Stop the other process, or change the left-hand port in docker-compose.yml ("8001:8000"); if you change the API port, also update VITE_API_URL. |
| UI header shows API offline | Check curl http://localhost:8000/api/health. If the UI is opened from a different computer than the one running Docker, set VITE_API_URL in docker-compose.yml to http://<server-ip>:8000 and run docker compose up --build again. |
ImportError: cannot import name 'UTC' from 'datetime' | Python is older than 3.11. Create the virtual environment with Python 3.11+. |
npm run dev fails on Windows (cp/mkdir -p) | Use Docker, WSL2 or Git Bash on Windows. |
| Ledger shows many new blocks after testing | Expected: runs append to the chain. Use a fresh clone to inspect the submitted baseline; preserve the changed data/ directory if the new audit records matter. |
Third-party components, data & AI tools (rule 5.4.4)
- Weather data by Open-Meteo.com (CC BY 4.0): ECMWF IFS, NCEP GFS, DWD ICON via the Open-Meteo Previous Runs API.
- Open-source libraries listed in section 3 (their licenses apply).
- SCADA data provided by the organizers.
- AI tools used during development: Claude Code and Codex (code assistance).
- Runtime LLM: optional OpenAI API for planning, risk decisions, critique and briefings. Only derived facts enter the prompts, Pydantic validates the responses, and a deterministic fallback keeps the system working when the LLM is unavailable.
Team
- Person A: ML and forecasting engine (
ml/) - Person B: Backend, agent and ledger (
backend/) - Person C: Frontend, README and demo (
frontend/)
Авторы коммитов
История коммитов
- 2026-09-23 17:25docs: punctuate READMEnurd-cloud
- 2026-09-23 17:46[docs] freeze OpenWind release; ledger head 5700b976498ad975a1eef2d6ef9ecb497e3fb85a15d759b380079f5c67a267yerbol1212
- 2026-09-23 17:44Merge remote-tracking branch 'origin/main'yerbol1212
- 2026-09-23 17:43[docs] release OpenWind with reproducible runbook and normalized-power labelsyerbol1212
- 2026-09-23 17:32[backend] make replay recalculation evidence automaticyerbol1212
- 2026-09-23 16:30[ml] adjust README section punctuationnurd-cloud
- 2026-09-23 17:27docs: punctuate solution headingAltynay Turakhan
- 2026-09-23 17:13docs: punctuate README checklistAltynay Turakhan
Все коммиты (36)
- 2026-09-23 17:06[ml] audit previous-runs availability evidenceyerbol1212
- 2026-09-23 17:00docs: punctuate README titleAltynay Turakhan
- 2026-09-23 16:37[ml] fix validation power-curve leak, bias-correct P50, honest baseline tableyerbol1212
- 2026-09-23 16:35[docs] README per HackAlem requirements: setup, config, run, verification, resultsyerbol1212
- 2026-09-23 15:33[ml] adjust README heading punctuationnurd-cloud
- 2026-09-23 16:31docs: punctuate README headingAltynay Turakhan
- 2026-09-23 16:09[ml] train only on SCADA up to train_end; regression test for power-curve leakyerbol1212
- 2026-09-23 15:08[ml] adjust README punctuationnurd-cloud
- 2026-09-23 16:02[backend] enforce live ML and isolate agent testsyerbol1212
- 2026-09-23 15:48[backend] trace automatic daily forecast updatesyerbol1212
- 2026-09-23 15:44[frontend] open published agent forecast by defaultyerbol1212
- 2026-09-23 15:41[backend] sync persisted run proofs after ledger migrationyerbol1212
- 2026-09-23 15:40[docs] merge remote README punctuationyerbol1212
- 2026-09-23 15:40[docs] finalize README metrics, contracts changelog and progressyerbol1212
- 2026-09-23 15:38[docs] punctuate frontend listAltynay Turakhan
- 2026-09-23 15:38[ml] commit NWP cache, trained models, validation metrics and Feb 2026 submissionyerbol1212
- 2026-09-23 15:38[backend] record demo agent runs, ledger and LLM cache for keyless replayyerbol1212
- 2026-09-23 15:38[frontend] target 127.0.0.1 API and follow forecast ledger-proof contractyerbol1212
- 2026-09-23 15:38[backend] load local OpenAI config and replay cached decisionsyerbol1212
- 2026-09-23 15:38[backend] exact-match ledger proofs, immutable payloads, offline recalcyerbol1212
- 2026-09-23 15:32[docs] clarify coordinate punctuationAltynay Turakhan
- 2026-09-23 14:21[ml] implement leakage-safe forecast enginenurd-cloud
- 2026-09-23 14:58[docs] punctuate README titleAltynay Turakhan
- 2026-09-23 13:57Add ml directorynurd-cloud
- 2026-09-23 14:55[frontend] build SAMAL forecast control roomyerbol1212
- 2026-09-23 14:35[docs] add README punctuationAltynay Turakhan
- 2026-09-23 14:24[backend] implement agentic forecasting serviceyerbol1212
- 2026-09-23 13:53[docs] SAMAL plan and workspace skeletonyerbol1212
Структура репозитория (365 файлов)
.dockerignore .env.example .gitignore AGENTS.md CLAUDE.md Makefile PROJECT_PLAN.md README.md START_HERE.md backend/AGENTS.md backend/CLAUDE.md backend/Dockerfile backend/app/__init__.py backend/app/agent/__init__.py backend/app/agent/briefing.py backend/app/agent/llm.py backend/app/agent/orchestrator.py backend/app/agent/policy.py backend/app/agent/prompts/.gitkeep backend/app/agent/prompts/briefing.md backend/app/agent/prompts/critic.md backend/app/agent/prompts/decider.md backend/app/agent/prompts/planner.md backend/app/agent/recalculation.py backend/app/agent/tools.py backend/app/batch.py backend/app/ledger.py backend/app/main.py backend/app/migrate_ledger_payloads.py backend/app/ml_bridge.py backend/app/ml_stub.py backend/app/routers/__init__.py backend/app/routers/agent.py backend/app/routers/backtest.py backend/app/routers/economics.py backend/app/routers/forecast.py backend/app/routers/health.py backend/app/routers/ledger.py backend/app/routers/live.py backend/app/runs.py backend/app/schemas.py backend/app/settings.py backend/app/watch.py backend/requirements.txt backend/tests/.gitkeep backend/tests/test_api_contract.py backend/tests/test_grounding.py backend/tests/test_ledger.py backend/tests/test_llm_cache.py backend/tests/test_recalculation.py backend/tests/test_runs.py data/cache/nwp/.gitkeep data/cache/nwp/ecmwf_ifs025_2024-03-01_2024-05-31.csv.gz data/cache/nwp/ecmwf_ifs025_2024-03-01_2024-05-31.csv.gz.manifest.json data/cache/nwp/ecmwf_ifs025_2024-06-01_2024-08-31.csv.gz data/cache/nwp/ecmwf_ifs025_2024-06-01_2024-08-31.csv.gz.manifest.json data/cache/nwp/ecmwf_ifs025_2024-09-01_2024-11-30.csv.gz data/cache/nwp/ecmwf_ifs025_2024-09-01_2024-11-30.csv.gz.manifest.json data/cache/nwp/ecmwf_ifs025_2024-12-01_2025-02-28.csv.gz data/cache/nwp/ecmwf_ifs025_2024-12-01_2025-02-28.csv.gz.manifest.json data/cache/nwp/ecmwf_ifs025_2025-03-01_2025-05-31.csv.gz data/cache/nwp/ecmwf_ifs025_2025-03-01_2025-05-31.csv.gz.manifest.json data/cache/nwp/ecmwf_ifs025_2025-06-01_2025-08-31.csv.gz data/cache/nwp/ecmwf_ifs025_2025-06-01_2025-08-31.csv.gz.manifest.json data/cache/nwp/ecmwf_ifs025_2025-09-01_2025-11-30.csv.gz data/cache/nwp/ecmwf_ifs025_2025-09-01_2025-11-30.csv.gz.manifest.json data/cache/nwp/ecmwf_ifs025_2025-12-01_2026-02-28.csv.gz data/cache/nwp/ecmwf_ifs025_2025-12-01_2026-02-28.csv.gz.manifest.json data/cache/nwp/ecmwf_ifs025_2026-03-01_2026-03-02.csv.gz data/cache/nwp/ecmwf_ifs025_2026-03-01_2026-03-02.csv.gz.manifest.json data/cache/nwp/gfs_seamless_2024-03-01_2024-05-31.csv.gz data/cache/nwp/gfs_seamless_2024-03-01_2024-05-31.csv.gz.manifest.json data/cache/nwp/gfs_seamless_2024-06-01_2024-08-31.csv.gz data/cache/nwp/gfs_seamless_2024-06-01_2024-08-31.csv.gz.manifest.json data/cache/nwp/gfs_seamless_2024-09-01_2024-11-30.csv.gz data/cache/nwp/gfs_seamless_2024-09-01_2024-11-30.csv.gz.manifest.json data/cache/nwp/gfs_seamless_2024-12-01_2025-02-28.csv.gz data/cache/nwp/gfs_seamless_2024-12-01_2025-02-28.csv.gz.manifest.json data/cache/nwp/gfs_seamless_2025-03-01_2025-05-31.csv.gz data/cache/nwp/gfs_seamless_2025-03-01_2025-05-31.csv.gz.manifest.json data/cache/nwp/gfs_seamless_2025-06-01_2025-08-31.csv.gz data/cache/nwp/gfs_seamless_2025-06-01_2025-08-31.csv.gz.manifest.json data/cache/nwp/gfs_seamless_2025-09-01_2025-11-30.csv.gz data/cache/nwp/gfs_seamless_2025-09-01_2025-11-30.csv.gz.manifest.json data/cache/nwp/gfs_seamless_2025-12-01_2026-02-28.csv.gz data/cache/nwp/gfs_seamless_2025-12-01_2026-02-28.csv.gz.manifest.json data/cache/nwp/gfs_seamless_2026-03-01_2026-03-02.csv.gz data/cache/nwp/gfs_seamless_2026-03-01_2026-03-02.csv.gz.manifest.json data/cache/nwp/icon_seamless_2024-03-01_2024-05-31.csv.gz data/cache/nwp/icon_seamless_2024-03-01_2024-05-31.csv.gz.manifest.json data/cache/nwp/icon_seamless_2024-06-01_2024-08-31.csv.gz data/cache/nwp/icon_seamless_2024-06-01_2024-08-31.csv.gz.manifest.json data/cache/nwp/icon_seamless_2024-09-01_2024-11-30.csv.gz data/cache/nwp/icon_seamless_2024-09-01_2024-11-30.csv.gz.manifest.json data/cache/nwp/icon_seamless_2024-12-01_2025-02-28.csv.gz data/cache/nwp/icon_seamless_2024-12-01_2025-02-28.csv.gz.manifest.json data/cache/nwp/icon_seamless_2025-03-01_2025-05-31.csv.gz data/cache/nwp/icon_seamless_2025-03-01_2025-05-31.csv.gz.manifest.json data/cache/nwp/icon_seamless_2025-06-01_2025-08-31.csv.gz data/cache/nwp/icon_seamless_2025-06-01_2025-08-31.csv.gz.manifest.json data/cache/nwp/icon_seamless_2025-09-01_2025-11-30.csv.gz data/cache/nwp/icon_seamless_2025-09-01_2025-11-30.csv.gz.manifest.json data/cache/nwp/icon_seamless_2025-12-01_2026-02-28.csv.gz data/cache/nwp/icon_seamless_2025-12-01_2026-02-28.csv.gz.manifest.json data/cache/nwp/icon_seamless_2026-03-01_2026-03-02.csv.gz data/cache/nwp/icon_seamless_2026-03-01_2026-03-02.csv.gz.manifest.json data/ledger/.gitkeep data/ledger/ledger.jsonl data/llm_cache/.gitkeep data/llm_cache/2da86b24e69b60caa32fb34c7037943b7241d3c95a78d39e71eb69be0b065908.json data/llm_cache/3cca9fdc90aa5a7060d7b588a0152e27873796bf47cacbe53c993fc325cea468.json data/llm_cache/5971cb02d5031eb4fb39b87a9d69373dee601ad5821aff445ffbdea999d229fa.json data/llm_cache/5d9750033c51ec60dd8a6283bb277c9bf8aba296cda6516ef9b53b22340258ff.json data/llm_cache/7b808582e7e9ab3064478dae0d9004775e9f5d12f7d8d683416ba1c2e79fc04c.json data/llm_cache/8d6c65502fd6c964bc31adf1a3d771cd9df7e330c6b70da34a6bf1e1be66fbfe.json data/llm_cache/9e097b3b8ac18e00cf3dcd06c8064af7539b0ef67f42aa564c1a263e3b6ce26c.json data/llm_cache/b17f27321f97cff612ba5d2832c53daf122fc08798340c520b929fb3120b7962.json data/llm_cache/cac165873c21079910f1a668025853fc25ab82faffd362e48012b9ae774c47fb.json data/llm_cache/e3fe7bd6bff86d526dce8cda2d6fabb0a38eb79edd86cb9bf01e70a1f0ef30e9.json data/models/.gitkeep data/models/test.joblib data/models/val_feb2025.joblib data/models/val_winter.joblib data/outputs/.gitkeep data/outputs/agent_runs/r_20260214_384d43.json data/outputs/agent_runs/r_20260214_defa90.json data/outputs/agent_runs/r_20260215_33e510.json data/outputs/agent_runs/r_20260215_e32ece.json data/outputs/agent_runs/r_20260216_3b7df8.json data/outputs/agent_runs/r_20260217_b39b1a.json data/outputs/forecasts/test/2026-01-31.json data/outputs/forecasts/test/2026-02-01.json data/outputs/forecasts/test/2026-02-02.json data/outputs/forecasts/test/2026-02-03.json data/outputs/forecasts/test/2026-02-04.json data/outputs/forecasts/test/2026-02-05.json data/outputs/forecasts/test/2026-02-06.json data/outputs/forecasts/test/2026-02-07.json data/outputs/forecasts/test/2026-02-08.json data/outputs/forecasts/test/2026-02-09.json data/outputs/forecasts/test/2026-02-10.json data/outputs/forecasts/test/2026-02-11.json data/outputs/forecasts/test/2026-02-12.json data/outputs/forecasts/test/2026-02-13.json data/outputs/forecasts/test/2026-02-14.json data/outputs/forecasts/test/2026-02-15.json data/outputs/forecasts/test/2026-02-16.json data/outputs/forecasts/test/2026-02-17.json data/outputs/forecasts/test/2026-02-18.json data/outputs/forecasts/test/2026-02-19.json data/outputs/forecasts/test/2026-02-20.json data/outputs/forecasts/test/2026-02-21.json data/outputs/forecasts/test/2026-02-22.json data/outputs/forecasts/test/2026-02-23.json data/outputs/forecasts/test/2026-02-24.json data/outputs/forecasts/test/2026-02-25.json data/outputs/forecasts/test/2026-02-26.json data/outputs/forecasts/test/2026-02-27.json data/outputs/forecasts/val_feb2025/2025-01-31.json data/outputs/forecasts/val_feb2025/2025-02-01.json data/outputs/forecasts/val_feb2025/2025-02-02.json data/outputs/forecasts/val_feb2025/2025-02-03.json data/outputs/forecasts/val_feb2025/2025-02-04.json data/outputs/forecasts/val_feb2025/2025-02-05.json data/outputs/forecasts/val_feb2025/2025-02-06.json data/outputs/forecasts/val_feb2025/2025-02-07.json data/outputs/forecasts/val_feb2025/2025-02-08.json data/outputs/forecasts/val_feb2025/2025-02-09.json data/outputs/forecasts/val_feb2025/2025-02-10.json data/outputs/forecasts/val_feb2025/2025-02-11.json data/outputs/forecasts/val_feb2025/2025-02-12.json data/outputs/forecasts/val_feb2025/2025-02-13.json data/outputs/forecasts/val_feb2025/2025-02-14.json data/outputs/forecasts/val_feb2025/2025-02-15.json data/outputs/forecasts/val_feb2025/2025-02-16.json data/outputs/forecasts/val_feb2025/2025-02-17.json data/outputs/forecasts/val_feb2025/2025-02-18.json data/outputs/forecasts/val_feb2025/2025-02-19.json data/outputs/forecasts/val_feb2025/2025-02-20.json data/outputs/forecasts/val_feb2025/2025-02-21.json data/outputs/forecasts/val_feb2025/2025-02-22.json data/outputs/forecasts/val_feb2025/2025-02-23.json data/outputs/forecasts/val_feb2025/2025-02-24.json data/outputs/forecasts/val_feb2025/2025-02-25.json data/outputs/forecasts/val_feb2025/2025-02-26.json data/outputs/forecasts/val_feb2025/2025-02-27.json data/outputs/forecasts/val_winter/2025-10-31.json data/outputs/forecasts/val_winter/2025-11-01.json data/outputs/forecasts/val_winter/2025-11-02.json data/outputs/forecasts/val_winter/2025-11-03.json data/outputs/forecasts/val_winter/2025-11-04.json data/outputs/forecasts/val_winter/2025-11-05.json data/outputs/forecasts/val_winter/2025-11-06.json data/outputs/forecasts/val_winter/2025-11-07.json data/outputs/forecasts/val_winter/2025-11-08.json data/outputs/forecasts/val_winter/2025-11-09.json data/outputs/forecasts/val_winter/2025-11-10.json data/outputs/forecasts/val_winter/2025-11-11.json data/outputs/forecasts/val_winter/2025-11-12.json data/outputs/forecasts/val_winter/2025-11-13.json data/outputs/forecasts/val_winter/2025-11-14.json data/outputs/forecasts/val_winter/2025-11-15.json data/outputs/forecasts/val_winter/2025-11-16.json data/outputs/forecasts/val_winter/2025-11-17.json data/outputs/forecasts/val_winter/2025-11-18.json data/outputs/forecasts/val_winter/2025-11-19.json data/outputs/forecasts/val_winter/2025-11-20.json data/outputs/forecasts/val_winter/2025-11-21.json data/outputs/forecasts/val_winter/2025-11-22.json data/outputs/forecasts/val_winter/2025-11-23.json data/outputs/forecasts/val_winter/2025-11-24.json data/outputs/forecasts/val_winter/2025-11-25.json data/outputs/forecasts/val_winter/2025-11-26.json data/outputs/forecasts/val_winter/2025-11-27.json data/outputs/forecasts/val_winter/2025-11-28.json data/outputs/forecasts/val_winter/2025-11-29.json data/outputs/forecasts/val_winter/2025-11-30.json data/outputs/forecasts/val_winter/2025-12-01.json data/outputs/forecasts/val_winter/2025-12-02.json data/outputs/forecasts/val_winter/2025-12-03.json data/outputs/forecasts/val_winter/2025-12-04.json data/outputs/forecasts/val_winter/2025-12-05.json data/outputs/forecasts/val_winter/2025-12-06.json data/outputs/forecasts/val_winter/2025-12-07.json data/outputs/forecasts/val_winter/2025-12-08.json data/outputs/forecasts/val_winter/2025-12-09.json data/outputs/forecasts/val_winter/2025-12-10.json data/outputs/forecasts/val_winter/2025-12-11.json data/outputs/forecasts/val_winter/2025-12-12.json data/outputs/forecasts/val_winter/2025-12-13.json data/outputs/forecasts/val_winter/2025-12-14.json data/outputs/forecasts/val_winter/2025-12-15.json data/outputs/forecasts/val_winter/2025-12-16.json data/outputs/forecasts/val_winter/2025-12-17.json data/outputs/forecasts/val_winter/2025-12-18.json data/outputs/forecasts/val_winter/2025-12-19.json data/outputs/forecasts/val_winter/2025-12-20.json data/outputs/forecasts/val_winter/2025-12-21.json data/outputs/forecasts/val_winter/2025-12-22.json data/outputs/forecasts/val_winter/2025-12-23.json data/outputs/forecasts/val_winter/2025-12-24.json data/outputs/forecasts/val_winter/2025-12-25.json data/outputs/forecasts/val_winter/2025-12-26.json data/outputs/forecasts/val_winter/2025-12-27.json data/outputs/forecasts/val_winter/2025-12-28.json data/outputs/forecasts/val_winter/2025-12-29.json data/outputs/forecasts/val_winter/2025-12-30.json data/outputs/forecasts/val_winter/2025-12-31.json data/outputs/forecasts/val_winter/2026-01-01.json data/outputs/forecasts/val_winter/2026-01-02.json data/outputs/forecasts/val_winter/2026-01-03.json data/outputs/forecasts/val_winter/2026-01-04.json data/outputs/forecasts/val_winter/2026-01-05.json data/outputs/forecasts/val_winter/2026-01-06.json data/outputs/forecasts/val_winter/2026-01-07.json data/outputs/forecasts/val_winter/2026-01-08.json data/outputs/forecasts/val_winter/2026-01-09.json data/outputs/forecasts/val_winter/2026-01-10.json data/outputs/forecasts/val_winter/2026-01-11.json data/outputs/forecasts/val_winter/2026-01-12.json data/outputs/forecasts/val_winter/2026-01-13.json data/outputs/forecasts/val_winter/2026-01-14.json data/outputs/forecasts/val_winter/2026-01-15.json data/outputs/forecasts/val_winter/2026-01-16.json data/outputs/forecasts/val_winter/2026-01-17.json data/outputs/forecasts/val_winter/2026-01-18.json data/outputs/forecasts/val_winter/2026-01-19.json data/outputs/forecasts/val_winter/2026-01-20.json data/outputs/forecasts/val_winter/2026-01-21.json data/outputs/forecasts/val_winter/2026-01-22.json data/outputs/forecasts/val_winter/2026-01-23.json data/outputs/forecasts/val_winter/2026-01-24.json data/outputs/forecasts/val_winter/2026-01-25.json data/outputs/forecasts/val_winter/2026-01-26.json data/outputs/forecasts/val_winter/2026-01-27.json data/outputs/forecasts/val_winter/2026-01-28.json data/outputs/forecasts/val_winter/2026-01-29.json data/outputs/forecasts/val_winter/2026-01-30.json data/outputs/ledger_payloads/legacy-block-2.json data/outputs/ledger_payloads/legacy-block-3.json data/outputs/ledger_payloads/r_20260215_33e510.json data/outputs/ledger_payloads/r_20260215_e32ece.json data/outputs/ledger_payloads/r_20260216_3b7df8.json data/outputs/ledger_payloads/r_20260217_b39b1a.json data/outputs/metrics/val_feb2025.json data/outputs/metrics/val_winter.json data/outputs/submission/forecast_feb2026_all_issues.csv data/outputs/submission/forecast_feb2026_dayahead.csv data/raw/.gitkeep data/raw/turbine_1.csv data/raw/turbine_2.csv docker-compose.yml docs/ARCHITECTURE.md docs/CHANGELOG_CONTRACTS.md docs/CONTRACTS.md docs/DEMO_SCRIPT.md docs/PROGRESS.md docs/RULES_CHECKLIST.md docs/TASK_ORIGINAL.md docs/TIMELINE.md docs/img/.gitkeep frontend/.gitignore frontend/AGENTS.md frontend/CLAUDE.md frontend/Dockerfile frontend/README.md frontend/index.html frontend/package-lock.json frontend/package.json frontend/postcss.config.cjs frontend/src/App.tsx frontend/src/api/client.ts frontend/src/api/types.ts frontend/src/components/AgentTimeline.tsx frontend/src/components/FanChart.tsx frontend/src/components/Shared.tsx frontend/src/main.tsx frontend/src/pages/AgentPage.tsx frontend/src/pages/BacktestPage.tsx frontend/src/pages/EconomicsPage.tsx frontend/src/pages/ForecastPage.tsx frontend/src/pages/LedgerPage.tsx frontend/src/styles.css frontend/src/vite-env.d.ts frontend/tailwind.config.cjs frontend/tsconfig.json frontend/vite.config.ts ml/.gitignore ml/.gitkeep ml/AGENTS.md ml/CLAUDE.md ml/README.md ml/openwind_ml/.gitkeep ml/openwind_ml/__init__.py ml/openwind_ml/api.py ml/openwind_ml/backtest.py ml/openwind_ml/baselines.py ml/openwind_ml/cli.py ml/openwind_ml/config.py ml/openwind_ml/data.py ml/openwind_ml/features.py ml/openwind_ml/metrics.py ml/openwind_ml/models.py ml/openwind_ml/power_curve.py ml/openwind_ml/risk.py ml/openwind_ml/temporal_guard.py ml/openwind_ml/weather.py ml/pyproject.toml ml/requirements.txt ml/tests/.gitkeep ml/tests/test_api_shapes.py ml/tests/test_models.py ml/tests/test_temporal_guard.py ml/tests/test_weather_manifest.py shared/make_mocks.py shared/mocks/agent_events.json shared/mocks/backtest_val_feb2025.json shared/mocks/economics.json shared/mocks/forecast.json shared/mocks/health.json shared/mocks/ledger.json shared/mocks/ledger_tamper.json shared/mocks/ledger_verify.json shared/mocks/meta.json shared/mocks/series_val_feb2025.json
Обсуждение 0 комментариев
Войдите, чтобы комментироватьПока нет комментариев — будьте первым.