# Контракт интерфейса и файлов · schemaVersion 2

## Общая навигация

Работы: «L02 Установка», «L03 Совместимость», «L04 Диагностика», «L05 Наблюдаемость», «L06 Ресурсы», «L07 Политики обновлений», «L08 Восстановление», «L09 Передача поддержки». Заголовок выбранной работы использует разделитель « · ». Поле «Вариант»: A/B/C.

Вкладки (точно): «Практикум», «Состояние», «Проверки», «Журнал», «Доказательства».

Общие кнопки: «Проверить состояние», «Создать снимок», «Сбросить сценарий». Поле «Название снимка». Во вкладке «Доказательства»: «Экспорт конфигурации», «Экспорт доказательств», файловое поле «Импорт конфигурации». В «Журнал» для L04/L09: «Фильтр requestId». В каждой проверке раскрываются inputs, expected, actual и вычисляемый pass. Снимок включает состояние и проверки на своём шаге.

## Элементы действий

| Работа | Поля | Кнопки |
|---|---|---|
| L02 | «Хост / ПК» (№ 1/2), «Runtime» (16/18/20), «Порт» | «Установить runtime», «Назначить порт», «Занять выбранный порт», «Освободить выбранный порт», «Очистить учебный кэш», «Установить пакет», «Запустить службу», «Preflight», «Smoke» |
| L03 | «Хост / ПК» (№ 1/2/3), «Версия клиента» (1/2), «Единицы суммы» (Копейки/Рубли), «Кодировка» (UTF-8/Latin (потеря кириллицы)), «Формат даты» (ISO UTC с часовым поясом / DD-MM-YYYY (теряет время) / Локальное время как UTC (ошибка зоны)) | «Применить адаптер», «Прогнать три заказа» |
| L04 | «requestId», «Компонент» (ui/api/queue/worker), «Состояние» (Запущен/Остановлен), «Маршрут» (orders/archive) | «Отправить / повторить запрос», «Проверить компонент», «Применить состояние», «Назначить маршрут», «Освободить фоновую очередь» |
| L05 | «Порог p95, мс», «Порог ошибок, %», «Последовательных окон», «Режим окна» (Исправное/Задержки/Ошибки), «Фоновая работа» (Включена/Отключена) | «Сохранить пороги», «Смоделировать окно», «Применить фон» |
| L06 | «Сервис» (API/Worker), «Параметр» (vCPU/RAM, ГБ/Пул соединений), «Значение», «Нагрузка» (Обычная/Пиковая/Фоновая) | «Выделить ресурс», «Выбрать нагрузку», «Выполнить ресурсный прогон» |
| L07 | «Уровень» (Локальная/Групповая/Обязательная), «Номер цели (с 1)», «Пакет» (Нет политики/stable/next), «Хост / ПК» (№ 1…6) | «Задать политику», «Проверить один ПК», «Применить ко всем 6 ПК» |
| L08 | «Резервирование» (Выключено/Включено), «Минуты» (1–60), «Объект» (Рабочие данные/Полная копия F0/Журнал J1) | «Сохранить настройку», «Создать полную копию», «Внести пакет изменений», «Продвинуть модельное время», «Смоделировать повреждение», «Проверить контрольные суммы», «Восстановить F0 в песочницу», «Проиграть J1», «Сравнить ID и значения», «Переключить на песочницу» |
| L09 | «Команды runbook (одна на строку)», «Импорт runbook», «Компонент» | «Сохранить runbook», «Выполнить runbook», «Экспорт runbook», «Проверить компонент» |

L07: номер цели 1–6 для локальной, 1–2 для групповой, только 1 для обязательной политики. В JSON индексы начинаются с 0. L04 requestId: `REQ-` плюс 1–24 символа A–Z, 0–9 или дефис. Пример допустимого формата: REQ-001.

## Форматы экспортов

Имена скачивания: `Lxx-A-config.json`, `Lxx-A-evidence.json`, для L09 также `L09-A-runbook.json` (вариант меняет букву).

Конфигурация — объект ровно с пятью полями:

```json
{"kind":"ops-lab-config","schemaVersion":2,"scenarioId":"L02","variant":"A","actions":[]}
```

`actions`: до 300 объектов ровно `{ "type": "...", "params": {...} }`. Это конфигурация воспроизведения, а не редактируемый дамп произвольного currentState. Пустой actions соответствует исходному состоянию. Импорт выполняет строгую валидацию и атомарную замену после полного воспроизведения.

Доказательства — объект:

```text
scenarioId: L02…L09
variant: A|B|C
schemaVersion: 2
initialState: исходное состояние модели
currentState: текущее состояние модели
actions: [{type, params}]
journal: [{step, action, params, before, after, result}]
checkResults: [{name, inputs, expected, actual, pass}]
snapshots: [{step, label, state, checks}]
```

`result` может быть null или структурированным результатом действия. step — порядковый номер, не реальная временная метка. Для L08 время явно хранится в currentState.time. Для L09 currentState содержит runbookVersion, execution, executionHistory; история содержит `{run, version, commands, steps, verified}`, steps — `{command, before, result, after}`. Результат условия содержит condition, matched, skipped, result. before/after команд содержат изменяемые эксплуатационные поля; полные состояния — в общем journal. Импорт доказательств намеренно не поддерживается.

Runbook — ровно четыре поля:

```json
{"kind":"ops-lab-runbook","schemaVersion":2,"variant":"A","commands":["probe api"]}
```

Команд от 1 до 24. Разрешены только:

```text
probe ui
probe api
probe queue
probe worker
route orders
worker start
queue drain
retry ticket
verify ticket
if worker stopped -> worker start
if route wrong -> route orders
if queue full -> queue drain
if ticket pending -> retry ticket
```

Это перечень синтаксиса, не готовая инструкция исправления. Условия проверяются непосредственно перед действием. Произвольные выражения, вложенные условия, циклы, shell, удаления и сброс запрещены. `queue drain` освобождает только фоновую очередь. `retry ticket` использует единственный ID ticket. `verify ticket` проверяет однократное завершение этой заявки. Импорт допускается только в чистый L09 того же варианта; повтор того же импорта до выполнения идемпотентен. После действий импорт runbook отвергается: для передачи нужен чистый сценарий. Конфигурация восстанавливает и историю; runbook переносит только текст команд и вариант.

## Допустимые действия конфигурации

Все параметры обязательны; дополнительные поля запрещены.

| Область | type → params |
|---|---|
| Общие | check → {}; snapshot → {label:string≤80} |
| L02 | preflight/smoke → {}; runtime → {host:0..1,value:16\|18\|20}; port → {host:0..1,value:1024..65535}; clean/install/start/occupyPort/releasePort → {host:0..1} |
| L03 | configure → {host:0..2,client:1\|2,unit:kop\|rub,encoding:utf8\|latin,date:iso\|dmy\|naive}; orders → {} |
| L04 | request → {requestId:string}; probe → {component:ui\|api\|queue\|worker}; repair → {component:worker,value:start\|stop} или {component:route,value:orders\|archive} или {component:queue,value:drain} |
| L05 | threshold → {latency:50..2000,errors:0..100,windows:1..5}; background → {enabled:boolean}; window → {mode:control\|latency\|errors} |
| L06 | resource → {host:0..1,parameter:cpu\|ram\|pool,value:целое}; load → {value:normal\|peak\|background}; run → {}. Диапазоны: cpu 1..8, ram 1..16, pool 1..40; суммарный CPU/RAM ограничен бюджетом |
| L07 | policy → {level:local\|group\|mandatory,target:целый индекс,value:none\|stable\|next}; probe → {host:0..5}; rollout → {} |
| L08 | backupConfig → {enabled:boolean}; corrupt → {target:live\|full\|journal}; createBackup/applyBatch/checksum/restore/replay/compare/promote → {}; advance → {minutes:1..60} |
| L09 | edit → {commands:string[]}; execute → {}; probe → {component:ui\|api\|queue\|worker} |

Варианты и начальные состояния воспроизводимы; случайность и зависимость от системных часов отсутствуют. Единственное реальное окружение — сохранение и скачивание файлов браузером. Неправильные действия, которые модель отвергает исключением, не меняют state/journal; отказы штатных проб или неуспешная установка записываются как результат действия.

## Дополнения версии 2

L02: preflight содержит снимок inputs каждого хоста. Результат установки содержит stalePreflight (кроме уже установленного пакета); raceEvidence хранит checked, atInstall, фактический preflight и blocked. Общая проверка «Устаревший preflight выявлен» требует реального отказа установки после ранее успешной проверки. Действие occupyPort занимает текущий выбранный порт и останавливает службу; releasePort освобождает его.

L04/L09: записи trace содержат requestId, attempt, component, message. В «Журнал» таблица имеет колонки «requestId», «Попытка», «Компонент», «Сообщение». Завершённая повторная заявка возвращается на уровне API; очередь и обработчик не вызываются.

L08: backupCreated — факт выполнения создания копии; batchApplied — факт внесения подготовленного пакета; fullTime — модельное время созданной копии; expectedLive — целевые ID/значения после последнего корректного пакета. Начальная старая F0 не заменяет учебное действие создания копии. Создание копии требует включённой настройки и неповреждённого состояния до инцидента; обновляет F0 и её сумму, обнуляет J1, песочницу и прежние проверки. Повтор копирования уже актуальной F0 идемпотентен. Пакет требует созданной копии и целостных F0/J1, обновляет рабочие данные и J1 атомарно. Его повтор идемпотентен. «Переключить на песочницу» требует инцидента, точного совпадения с expectedLive и ранее успешного сравнения текущей песочницы.

Версия 1 не импортируется в модель версии 2. Старые localStorage-ключи v1 остаются нетронутыми.
