# Контракт внешнего бота · lab-v1

## Подготовка

Зарегистрируйтесь, создайте бота в личном кабинете и сохраните выданный токен. Выберите стол и зарегистрируйте бота на свободное место. Другой бот того же аккаунта за этим столом запрещен сервером и ограничением базы данных. Один бот занимает не более одного места на платформе.

Стол 01: Baseline на месте 0. Стол 02: Monte Carlo на месте 0. Стол 03: два места для ботов разных пользователей. Места платформенных ботов освобождать нельзя. Регистрация на место сохраняется при отключении бота и перезапуске сервера.

## Подключение

Бот открывает исходящий WebSocket на `/ws/bot` с заголовком `Authorization: Bearer <token>`. Полный адрес виден в кабинете. Токен определяет бота и владельца; поля клиента не могут подменить их. Одна активная сессия на бота.

Первое сообщение:

```json
{"type":"hello","protocol":"lab-v1"}
```

Ответ `session.accepted` содержит botId, tableId и seat (0 или 1). Если бот еще не зарегистрирован на стол, tableId/seat равны null. При последующем назначении приходит `seat.assigned`, после освобождения — `seat.released`. Бот может подключиться до занятия места и ждать.

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

## Ход

`action.request` содержит protocol, tableId, matchId, requestId, expiresAt и state. expiresAt — Unix UTC в миллисекундах. Лимит решения 10 секунд. При отключении зарегистрированного бота матч ожидает переподключения.

state содержит:

- hand — номер раздачи; button и actor — места игроков.
- street — preflop/flop/turn/river; board — открытые карты.
- pot — все уже внесенные фишки, включая текущую улицу; bigBlind — 100.
- hero — свое место, stack, contribution на текущей улице, total за раздачу и две карты cards.
- opponent — место, stack, contribution, total; закрытых карт нет.
- legal — fold/check (boolean), call (сумма или null), raiseTo (min/max или null).
- history — публичные события текущей раздачи.

Карты: ранг 2–9,T,J,Q,K,A и масть c,d,h,s, например As. Все суммы — целые фишки. Стек перед каждой раздачей 10 000, блайнды 50/100; позиции чередуются. Сервер тасует колоду и рассчитывает исход.

Ответ:

```json
{"type":"action.submit","requestId":"REQUEST_ID","action":{"kind":"call"}}
```

Разрешены fold, check, call без суммы и raise_to с amount. В raise_to amount — полный взнос на текущей улице после действия, а не добавление. Всегда проверяйте legal.

`action.received` подтверждает буферизацию в памяти. `action.rejected` содержит reason: illegal_action, request_closed, deadline_exceeded или bot_not_seated. Повтор не изменяет уже закрытый ход. При неправильном действии исходный таймер не сбрасывается. При таймауте — check, если доступен, иначе fold.

## Переподключение и токены

После потери связи подключитесь с тем же токеном и снова отправьте hello. Сервер повторит незавершенный запрос при возобновлении. Новый токен сразу отзывает старый и отключает его активную сессию. Токен бота не разрешает менять кабинет, занимать места или управлять аккаунтом; эти действия требуют пользовательской сессии.

Для другой машины используйте LAN-адрес платформы, не 127.0.0.1. LAN-режим — HTTP/WS в доверенной тестовой сети. Для Интернета требуется HTTPS/WSS и соответствующее размещение. Не добавляйте токен в URL, репозиторий или архив.

## Ограничения

Это бесплатная лаборатория без денежных взносов. Аккаунты/токены/регистрации мест сохраняются в SQLite, активные раздачи — в памяти. Сервер не проверяет, один ли реальный человек создал несколько аккаунтов. Он обеспечивает запрет двух ботов одного зарегистрированного пользователя за столом.

Формальная схема сообщений: bot-contract.json (JSON Schema 2020-12). Стартовый проект: bot-starter.zip. Контракт lab-v1 отличается от долгосрочного черновика production v1.
