Files
h-school/docs/phases/08-session/reviewed.md
T

8.7 KiB
Raw Blame History

Журнал ревью

Сводка: ../reviewed.md. Индекс среза: README.md.

Срез 8. Сессия и темп

  • Фазы: 3840
  • Проверен на: 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/schoolsschools / 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.mdschool-limit-reached (так было до среза). Не менялось.
  • Бесхозная карточка показывает «Хозяин: —», не голый прочерк. GET /api/schools/{id} из дизайна нет: mine/owner живут в списке меню.

Перепроверка. Срез 8. Сессия и темп

  • Фазы: 3840
  • Проверен на: 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.mdschool-limit-reached (так было до среза). Не менялось.
  • GET /api/schools/{id} из дизайна нет: mine/owner живут в списке меню (schoolFromList).