64 lines
8.7 KiB
Markdown
64 lines
8.7 KiB
Markdown
# Журнал ревью
|
||
|
||
Сводка: [`../reviewed.md`](../reviewed.md). Индекс среза: [`README.md`](README.md).
|
||
|
||
## Срез 8. Сессия и темп
|
||
|
||
- **Фазы:** 38–40
|
||
- **Проверен на:** `1c3ae9a`, 2026-08-20
|
||
- **Пути:** `src/HSchool.Server/{Session,Api/SessionEndpoints.cs,Api/SchoolAccess.cs,Game/SchoolOwnership.cs,Game/UserStore.cs,Net/ClientRegistry.cs,Net/GameSocketHandler.cs,Game/GameLoopService.cs}`, `src/HSchool.Simulation/{ClockSpeed.cs,GameClock.cs,School.cs,SimulationOptions.cs}`, `src/HSchool.Client/src/{ui/sessionGate.ts,ui/mainMenu.ts,ui/gameScreen.ts,ui/schoolCard.ts,net/protocol.ts,net/api.ts,main.ts}`, `docs/protocol.md`, `../../design/08-session/session.md`, `tests/HSchool.AppHost.Tests/{SessionApiTests.cs,SchoolOwnerApiTests.cs,GameSocketTests.cs}`, `tests/HSchool.Simulation.Tests/{ClockTempoTests.cs,GameClockTests.cs}`, `src/HSchool.Client/src/ui/{sessionGate,gameScreen,schoolCard,mainMenu}.test.ts`
|
||
- **Итог:** обещания 38–40 на месте; дописано 4 теста; вторая вкладка с той же кукой больше не получает Welcome. Срез 9 (44/45/47) в работе — не ревьюился
|
||
|
||
Что подтверждено:
|
||
|
||
- **38:** `HSchool:AlphaPassword` (пустой — `ValidateOnStart`); `POST/GET/DELETE /api/session`; кука HttpOnly, `SameSite=Lax`, `Path=/`, `Max-Age` из `SessionCookieDays` (14); `users.json` каноническое имя; повтор другим регистром — та же запись; игровой HTTP без куки — `401`; `/health` и три ручки сессии — без неё; сокет без куки — close `PolicyViolation`, без Welcome; Hello по-прежнему версия + локаль; клиент — сначала сессия, потом сокет; хостовые тесты логинятся в `ResetAsync`/`LoginAsync`. Версия протокола не бампилась (v8).
|
||
- **39:** `MaxSchools` = 2 на игрока, `MaxSchoolsTotal` = 16 (в AppHost-тестах Total = 7); create пишет `owner`; `limit-reached` в коде — `school-limit-reached` (как в `protocol.md`); `server-full`; `GET /api/schools` — `schools` / `others`, `mine`, `owner` или `null`; Welcome.`MaxSchools` — слоты игрока; гость: найм `403` `not-owner`, `SetRunning` не меняет `running`; бесхозная в `others`, удаляется вторым; меню «Мои»/«Чужие»; в чужой школе нет «Управление» и кнопок часов. Портретный POST без `RequireManage`. Формат сейва не бампился.
|
||
- **40:** база 1 игровая минута/с; таблица `0.5, 1, 2, 5, 10` в `ClockSpeed`, `protocol.ts` и `protocol.md`; 20 импульсов ×1 = 1 минута, индексы 3/4 = 5 и 10 минут; на ×10 тяжёлые 10 раз с квантом 1; на ×5 — 5 раз; индекс 5 игнорируется; воркер по-прежнему 20 Гц и потолок догона 5; пять кнопок на экране. `HSchool.Simulation` без ASP.NET.
|
||
|
||
Дописано:
|
||
|
||
- `SessionApiTests.Login_SetsHttpOnlyLaxSessionCookie`
|
||
- `SessionApiTests.SecondWebSocket_ForAnOnlineName_ClosesWithoutWelcome`
|
||
- `ClockTempoTests.AtX5_TwentyImpulses_RunHeavyFiveTimesAndAdvanceFiveGameMinutes` (и календарь +1 на ×1 в `AtX1_…`)
|
||
- `mainMenu.test.ts` — чужая карточка без удаления, бесхозная с удалением
|
||
|
||
Исправлено:
|
||
|
||
- Второй WebSocket того же имени принимался и слал Welcome: `POST` проверял «онлайн», upgrade — нет. Две вкладки с живой кукой обходили `409` `name-online`. Теперь `ClientRegistry.TryClaimUserName` под тем же замком, второй сокет закрывается `PolicyViolation` без Welcome.
|
||
|
||
Открыто:
|
||
|
||
- `POST /api/session` с другим именем при живой куке перезаписывает сессию без `DELETE`. Дизайн: «Без выхода второе имя с той же куки не взять». Кода ошибки нет — новый HTTP-код молча не вводился.
|
||
- `AddDataProtection()` без ключей рядом с `saves/`. Рестарт того же профиля Windows куки, скорее всего, не сбрасывает; новый контейнер — может.
|
||
- Текст фазы 39 пишет `limit-reached`; живой код и `protocol.md` — `school-limit-reached` (так было до среза). Не менялось.
|
||
- Бесхозная карточка показывает «Хозяин: —», не голый прочерк. `GET /api/schools/{id}` из дизайна нет: `mine`/`owner` живут в списке меню.
|
||
|
||
## Перепроверка. Срез 8. Сессия и темп
|
||
|
||
- **Фазы:** 38–40
|
||
- **Проверен на:** `7100065`, 2026-08-20
|
||
- **Пути:** `src/HSchool.Server/{Session,Api/SessionEndpoints.cs,Api/SchoolAccess.cs,Game/SchoolOwnership.cs,Game/UserStore.cs,Game/SchoolStore.cs,Net/ClientRegistry.cs,Net/GameSocketHandler.cs,Game/GameLoopService.cs}`, `src/HSchool.Simulation/{ClockSpeed.cs,GameClock.cs,School.cs,SimulationOptions.cs}`, `src/HSchool.Client/src/{ui/sessionGate.ts,ui/mainMenu.ts,ui/gameScreen.ts,ui/schoolCard.ts,net/protocol.ts,net/api.ts,main.ts}`, `docs/protocol.md`, `../../design/08-session/session.md`, `tests/HSchool.AppHost.Tests/{SessionApiTests.cs,SchoolOwnerApiTests.cs,GameSocketTests.cs}`, `tests/HSchool.Simulation.Tests/{ClockTempoTests.cs,GameClockTests.cs}`, `tests/HSchool.Server.Tests/SchoolStoreTests.cs`, `src/HSchool.Client/src/ui/{sessionGate,gameScreen,schoolCard,mainMenu}.test.ts`
|
||
- **Итог:** перепроверка после дрейфа с `1c3ae9a`. Обещания 38–40 держатся; `users.json` больше не читается как сейв школы; бесхозная карточка показывает голый прочерк. Следующий срез не брался.
|
||
|
||
Что подтверждено:
|
||
|
||
- Дрейф после `1c3ae9a`: `UserStore.FileName` открыт для `SchoolStore.LoadAll` (пропуск `users.json`); `GameLoopService` / `School.Tick` получили речь и talk-circle на страйде тяжёлых систем. Сессия, хозяин, таблица скоростей и `TryClaimUserName` не разъехались.
|
||
- Все тесты из списков фаз 38–40 на месте: сессия 401/200, `users.json` и регистр, `name-online`, сокет без куки и второй сокет `PolicyViolation`, клиентский пароль без сетки; два игрока по две школы / `server-full` / гость 403 и `SetRunning` / бесхозная в `others`; ×1 = 1 минута, индексы 3/4, страйд ×5/×10, индекс 5, пять кнопок.
|
||
- Протокол на проводе сейчас v9 (срез 9, talk-circle); раскладка Hello/Welcome/`SetSpeed` и смысл `MaxSchools` не менялись. `HSchool.Simulation` без ASP.NET. Воркер 20 Гц, потолок догона 5.
|
||
|
||
Дописано:
|
||
|
||
- `ClockTempoTests.LowSpeed_EveryImpulseRunsHeavySystems` — ×½ и ×2 каждый импульс, не только ×1
|
||
- `schoolCard.test.ts` — бесхозная карточка с голым прочерком, не «Хозяин: —»
|
||
|
||
Исправлено:
|
||
|
||
- Бесхозная карточка оборачивала «—» в шаблон «Хозяин: {owner}». Меню теперь отдаёт уже готовую подпись: чужая — «Хозяин: Bob», бесхозная — «—».
|
||
|
||
Открыто:
|
||
|
||
- `POST /api/session` с другим именем при живой куке перезаписывает сессию без `DELETE`. Дизайн: «Без выхода второе имя с той же куки не взять». Кода ошибки нет — новый HTTP-код молча не вводился.
|
||
- `AddDataProtection()` без ключей рядом с `saves/`. Рестарт того же профиля Windows куки, скорее всего, не сбрасывает; новый контейнер — может.
|
||
- Текст фазы 39 пишет `limit-reached`; живой код и `protocol.md` — `school-limit-reached` (так было до среза). Не менялось.
|
||
- `GET /api/schools/{id}` из дизайна нет: `mine`/`owner` живут в списке меню (`schoolFromList`).
|