# Проверенные срезы Журнал ревью. Фаза с ✅ в [`README.md`](README.md) — заявка автора; строка здесь — проверенный факт: каждое обещание фазы сверено с кодом и тестом, найденное дописано или исправлено. Коммит в «Проверен на» делает журнал самопроверяющимся. Срез перестаёт считаться проверенным, как только `git log <коммит>..HEAD -- <пути>` перестаёт быть пустым — поэтому «Пути» обязательны. Закрытые замечания из прошлых проходов сюда не возвращаются. История перепроверок свёрнута в строку «Проверен на». Последняя проверка срезов 1–6 была до фаз 29–30 (страна, одежда): дрейф по путям есть, это очередь следующего прохода, а не задняя датировка. Оговорки, которые относятся сразу к нескольким срезам (не дублировать ниже): - Хостовый `OpeningASchoolDuringAMathLesson_...` после правки явки не гонялся: Aspire держал DLL (`MSB3021`). Симуляционные тесты явки зелёные. - `npm test` в клиенте не гоняет `tsc`. Дубликат поля и любой TS2300 зелёный в vitest и красный на `npm run build`. - `GET /api/catalog` отдаёт каркас дня без `lunchBreaks` (только `longBreakAfter`). Сетке смены не нужны; молча расширять HTTP ревью не стало. ## Срез 1. Оболочка и карта - **Фазы:** 0–4 - **Проверен на:** `418a4ea`, 2026-08-20 - **Пути:** `src/HSchool.Client`, `src/HSchool.Protocol`, `src/HSchool.Content`, `src/HSchool.Server/Game`, `src/HSchool.Server/Api/ModEndpoints.cs`, `src/HSchool.Server/Api/SchoolEndpoints.cs`, `src/HSchool.Server/Net`, `tests/HSchool.Content.Tests`, `tests/HSchool.Protocol.Tests`, `tests/HSchool.AppHost.Tests/SchoolApiTests.cs`, `tests/HSchool.AppHost.Tests/GameSocketTests.cs` - **Итог:** обещания фаз 0–4 целы; дописаны 3 теста; протокол v7 в трёх местах Что подтверждено: - PixiJS нет; дерево карты, пять секций локации, клиентский фильтр, `localize()`. Оболочка — вкладки Карта/Люди, не три панели; отказ от ленты событий записан в фазе 1 и в `design/near-term.md`. - `SchoolWorker` — `LongRunning`, свой `World`, аккумулятор с потолком 5. Супервизор таблицу держит и `World` не трогает. Сейв на create/shutdown/`SaveIntervalSeconds`; `ReloadFromDisk_RestoresAPausedClock`, `PausingOneSchool_DoesNotStopAnother`. - Восемь тестов каталога/карты в `HSchool.Content.Tests`. Ванильная раскладка валидна. Пропавшая папка мода не стартует школу и файл не трогает. - `GET /api/mods`, каталог, create с картой и модами, снимок при OpenSchool. `core` в диалоге создания нельзя снять. Кодек, `protocol.ts` и `docs/protocol.md` описывают один `MapSnapshot`. - `modal.ts` резолвит промис явно; `.dialog--screen` — `height: fit-content`; `DefaultStartDate` UTC; `MapSnapshotSize` от сообщения; outbox `DropOldest`; `WaitToReadAsync` переносится между итерациями; меню патчит `card.update`. - Родной язык — HTTP/JSON без бампа протокола. Старый сейв без поля берёт первый язык набора, не бросает кубик (`ReloadWithoutASavedPick_TakesTheFirstLanguageInsteadOfRolling`). Дописано: - `SchoolApiTests.Catalog_WithAnUnknownMod_IsRejected` - `SchoolApiTests.ModId_ThatEscapesTheModsFolder_IsRejectedOnBothEndpoints` - `SkillGrantTests.ReloadWithoutASavedPick_TakesTheFirstLanguageInsteadOfRolling` Исправлено: - Два поля `speedIndex` в клиентском `School` (`api.ts`) — артефакт мержа фазы 26; vitest не ловил, `npm run build` падал с TS2300. ## Срез 2. Люди - **Фазы:** 5–9 - **Проверен на:** `bdb1253`, 2026-08-20 - **Пути:** `src/HSchool.People`, `src/HSchool.Content/PeopleDefs.cs`, `src/HSchool.Simulation/RosterSpawner.cs`, `src/HSchool.Simulation/School.cs`, `src/HSchool.Server/Api/SchoolEndpoints.cs`, `src/HSchool.Server/Game/PersonCardReader.cs`, `src/HSchool.Server/Game/SchoolWorker.cs`, `src/HSchool.Client/src/ui/peoplePanel.ts`, `src/HSchool.Client/src/ui/personCard.ts`, `tests/HSchool.People.Tests`, `tests/HSchool.Content.Tests/PeopleDefTests.cs`, `tests/HSchool.Simulation.Tests/PeopleInSchoolTests.cs`, `tests/HSchool.AppHost.Tests/PeopleApiTests.cs`, `tests/HSchool.AppHost.Tests/SchoolSeedTests.cs` - **Итог:** обещания фаз 5–9 целы; починены два API-теста, дописан один на reload после набора Что подтверждено: - Дефы человека: разбор, наследование, патч, неизвестная ссылка, склонение, мод со своим набором. - Генератор: шесть тестов списка фазы, без Arch/ASP.NET/`DateTime.Now`. Неполные семьи 5–10%. Сид — поле школы, не `school.Id`; хостовые тесты, которым нужен состав, передают сид явно. - Одиннадцать кабинетов, сущности в `World`, `PersistPeople` только при смене состава. Штат при создании пуст — это фаза 11. - Список с опубликованного снимка, карточка через `TaskCompletionSource`. Фильтры, пейджер, семейные ссылки, всё через `t(...)`. Вкладка рядом с картой, не нижний ряд — так записано в фазе 8 и в `design/people.md`. - Выпуск старшей имеющейся, вместимость, семьи через поколения, reload после набора. Дописано: - `PeopleApiTests.ReloadAfterTheYearlyIntake_RestoresTheNewComposition` — ждёт 1 сентября и требует состав **после** набора, отличный от исходного (детерминизм от сида иначе скрыл бы потерянный файл). Исправлено: - `Card_IncludesFamilyAndLiveNeeds` брал `People[0]` и требовал двух родителей. Состав зависит от сида; на чистом клоне первый ученик иногда из неполной семьи. Теперь ищет ученика с матерью и проверяет диапазон. - `List_SortsBySurname` требовал ordinal-порядок, сервер ставит Ё на место Е. Совпадали, пока в `core` не было фамилий на Ё. ## Срез 3. Штат - **Фазы:** 10–13 - **Проверен на:** `bdb1253`, 2026-08-20 - **Пути:** `src/HSchool.People/Staffing.cs`, `src/HSchool.People/ApplicantPool.cs`, `src/HSchool.Content/SubjectDef` и `defs/staffing`, `src/HSchool.Server/Api/SchoolEndpoints.cs` (staffing/hire/subjects), `src/HSchool.Server/mods/core/defs/{subjects,positions,rooms,staffing,traits}`, `src/HSchool.Client/src/ui/managementPanel.ts`, `src/HSchool.Client/src/net/api.ts`, `tests/HSchool.People.Tests/{StaffingTests,ApplicantPoolTests}.cs`, `tests/HSchool.AppHost.Tests/StaffingApiTests.cs`, `src/HSchool.Client/src/ui/managementPanel.test.ts` - **Итог:** обещания фаз 10–13 целы; дописаны 3 теста; `docs/protocol.md` дополнен `?lang=` Что подтверждено: - `PETeacher` нет; кабинеты без учительской должности; места через `defaultSeats`. Неизвестный навык в предмете роняет каталог. Стартовая дата 31 марта 2012. - Пул: детерминизм по сиду и неделе, частичное обновление, устойчивый размер, «сильный просит больше», пустой штат, соискатель вне ростера до найма. Пул 32. - Фонд оплаты, деление часов, пол ставки, покрытие. `GET /staffing` читает снимок, наём и назначение — `GameCommand` с `TaskCompletionSource`. `MaxWeeklyHours` не запрещает назначение, а оставляет предмет непокрытым. `PrimarySchool` на ванили требует трёх учителей (`teachersShort`). - Экран: деньги, непокрытые, пул, штат, назначение с карточки, отказ по пределу текстом, всё через `t(...)`. - Полностью укомплектованная школа влезает в 100 000 впритык (запас 5–13%). Нанять пул целиком без назначений предела достигает. Раскладка «каждому все предметы» — самая дешёвая, не «укомплектованная школа». Дописано: - `StaffingApiTests.AssigningPastTheCap_IsRejectedWithTheNumbers` — фаза 12 требовала API-тест на отказ по пределу; единственное место было написано через `if (over.StatusCode == Conflict)` и проходило при любом исходе. - `ApplicantPoolTests.ConfidentTraits_AskForMoreAndQuietOnesForLess` - В `AssignAndUnassign_HonourTheCap_AndReloadKeepsAssignments` — тот же пул с теми же ставками после перезапуска. Исправлено: - `docs/protocol.md` не упоминал `?lang=` у hire/subjects, хотя клиент его шлёт. ## Срез 4. Расписание - **Фазы:** 14–17 - **Проверен на:** `bdb1253`, 2026-08-20 - **Пути:** `src/HSchool.Schedule`, `src/HSchool.Content` (каркас дня, каникулы, `SubjectDef.room`), `src/HSchool.Simulation/SchoolTimetables.cs`, `src/HSchool.Server/Api/TimetableEndpoints.cs`, `src/HSchool.Server/Game/SchoolWorker.cs` (пин, перестроение), `src/HSchool.Client/src/ui/timetableGrid.ts`, `src/HSchool.Client/src/ui/gameScreen.ts`, `tests/HSchool.Schedule.Tests`, `tests/HSchool.Content.Tests/CalendarTests.cs`, `tests/HSchool.Content.Tests/LunchBreakTests.cs`, `tests/HSchool.AppHost.Tests/TimetableApiTests.cs`, `src/HSchool.Client/src/ui/timetableGrid.test.ts` - **Итог:** обещания фаз 14–17 целы; дописан тест на коды отказа пина; две строки дизайна помечены как отменённые срезом 5 Что подтверждено: - Календарь: суббота, каникулы и ночь — «вне учебного дня»; 10:20 вторника — третий урок; шестидневка; зима через 1 января. Физкультура в спортзале. Обеденные смены в каркасе дня (младшие после 3-го, старшие после 4-го). - Планировщик: четыре запрета, класс не влезает в меньший кабинет, без Arch/ASP.NET/`DateTime.Now`. - Перестроение только при `PeopleChanged` + `TimetableDirty`, не по тику. `GET /timetable` читает снимок, пин — `TaskCompletionSource`. `Reload_RestoresLockedLessons`. - Сетка, закрепление, тексты отказа (`pin-rejected` / `no-teacher` / `unknown-lesson`), скобки в дереве из присутствия, личное расписание в карточке. Всё через `t(...)`. - Занятость узла в протоколе v7 живёт в кадре `Presence`, не в снимке карты — фаза 19. Дописано: - `TimetableApiTests.PinAndUnpinRefusals_CarryTheDocumentedCodes` — `no-teacher`, `unknown-class`, `unknown-subject`, `unknown-room`, `unknown-lesson`, `invalid-query`. Исправлено: - В `design/schedule.md` «панель локации из расписания» и «люди находятся по расписанию» помечены как отменённые срезом 5. ## Срез 5. Жизнь школы - **Фазы:** 18–21 - **Проверен на:** `cbe739a`, 2026-08-20 - **Пути:** `src/HSchool.Ai`, `src/HSchool.Simulation/{PresenceSystem,ActivitySystem,LessonLearningSystem,School}.cs`, `src/HSchool.Protocol` (кадр `Presence`, пропуск в кадре часов), `src/HSchool.Server/Game/PresenceFrame.cs`, `src/HSchool.Client/src/ui/gameScreen.ts`, `src/HSchool.Server/mods/core/defs/{actions,behavior,needs}`, `tests/HSchool.Ai.Tests`, `tests/HSchool.Simulation.Tests/{PresenceTests,DecisionTests,ActivityTests,NeedDecayTests,LunchTests}.cs`, `tests/HSchool.AppHost.Tests/GameSocketTests.cs` - **Итог:** все 32 теста из списков фаз на месте; дописаны 2 теста явки; `SetTimetable` сбрасывает планы дня. Голод закрыт данными. AppHost после правки не гонялся — Aspire держал DLL. Что подтверждено: - Ходьба: 13 тестов списка фазы 18 (маршрут, `travelMinutes`, воскресенье/каникулы, звонок, детерминизм, пропуск пустого времени, лето, промотанная неделя). - Присутствие: раскладка с обеих сторон, круговой прогон, люди не в снимке карты, пропуск в учебное время отбрасывается. На паузе кадры **идут** (occupancy + подписи урока); людей в них может не быть. - Нужды: декей, обед, стулья, ночь вне школы, неизвестная нужда, детерминизм. `Hunger` восстанавливается вне школы, в столовой 112 стульев, обед — смена по параллелям. `SleepAndHunger_ReturnToMaxOffCampus`, `AfterASchoolDay_NobodyIsLeftStarving`. - Решения: восемь тестов фазы 21, в том числе туалет с урока и возврат, потолок отложенных, детерминизм за неделю. `HSchool.Ai` без Arch/ASP.NET/`DateTime.Now`. Дописано: - `HireAndAssignMath_DuringLessonThree_PutsSomeoneOnCampus` - `AssigningMath_AfterDayPlansWereBuilt_PutsSomeoneOnCampus` Исправлено: - `School.SetTimetable` обнуляет `PlanDay`. Иначе после назначения предмета без смены численности `EnsurePlans` считает планы актуальными, `AppearAt` остаётся `null`, кампус пуст. Найм это маскировал (численность растёт). - `OpeningASchoolDuringAMathLesson_...` после снятия паузы сразу ждал людей и съедал бюджет на паузные кадры. Теперь ждёт `clock.Running`, потом людей. ## Срез 6. Фундамент - **Фазы:** 22–28 - **Проверен на:** `cbe739a`, 2026-08-20 - **Пути:** `src/HSchool.Content` (`PackManifest`, `PackLoadOrder`, `BehaviorDef`), `src/HSchool.Server/mods/{core/pack.jsonc,example}`, `src/HSchool.Server/Game/SchoolStore.cs`, `src/HSchool.Server/Api/DevEndpoints.cs`, `src/HSchool.Server/Game/SchoolDumpReader.cs`, `src/HSchool.People/RosterJson.cs`, `src/HSchool.Client/src/ui/*.test.ts`, `tests/HSchool.Content.Tests/{PackIdentityTests,ExamplePackTests,BehaviorDefTests}.cs`, `tests/HSchool.People.Tests/GoldenRosterTests.cs`, `tests/HSchool.AppHost.Tests/{ExamplePackTests,GoldenSaveTests,SchoolSeedTests,ServiceabilityTests}.cs` - **Итог:** все тесты из списков семи фаз на месте; дописан один клиентский; `foundation.md` приведён к закрытому срезу. Хостовые тесты сверены по коду, не прогоном. Что подтверждено: - Пак: манифест, `missing-mod`, порядок — выбор игрока плюс топология (не алфавит), цикл — `mod-cycle`, def без подписи предупреждает и грузится. - `mods/example` на диске; каталог/create/reload; патч только с паком; ваниль без выбора не меняется. - Веса в `BehaviorDef`; пак с обедом выше урока уводит класс; отрицательный вес роняет загрузку. - Золотой ростер и сейв; `PrimarySchool` требует трёх; `teachersShort` в API и в `t(...)`. - Сид — поле школы. Format новее — школа не стартует, файл нетронут. Дамп через снимок + мейлбокс, не в `World` с HTTP. `HSchool.Simulation.Tests` без параллельности. - Клиентские экраны в `happy-dom`: фильтры/пейджер, create, сетка, предел фонда текстом. Дописано: - `managementPanel.test.ts` — непокрытый предмет показывает `teachersShort`. Исправлено: - `AGENTS.md` утверждал, что на паузе кадры присутствия не приходят. Работник их шлёт (occupancy + подписи). Тест, который ждёт *людей* на паузе, зависнет; тест на подпись урока — нет. - `design/foundation.md`: порядок загрузки — не алфавит; «почему сейчас» про веса в `Decision.cs` устарел. Замечено рядом: - `Dump_ReturnsPeopleNodesAndTimetable` принимает `NodeId is not null || Needs.Count > 0`. Нужды есть у всех, так что узлы на кампусе не проверяются. Усиливать до явки — срез 5. ## Срез 7. Этап A — данные и гардероб - **Фазы:** 29–31 - **Проверен на:** `d5547b7`, 2026-08-20 - **Пути:** `src/HSchool.Content/{CountryDef,ApparelDefs,CatalogLoader}.cs`, `src/HSchool.People/{DressGenerator,CountryClimate,RosterJson}.cs`, `src/HSchool.Server/{Game/SchoolStore.cs,Api/{ModEndpoints,SchoolEndpoints}.cs,Api/PeopleModels.cs}`, `src/HSchool.Client/src/ui/{createSchoolDialog.ts,personCard.ts}`, `tests/HSchool.Content.Tests/{CountryDefTests,ApparelDefTests,VanillaCoreTests}.cs`, `tests/HSchool.People.Tests/{DressGeneratorTests,GoldenRosterTests}.cs`, `tests/HSchool.AppHost.Tests/{SchoolApiTests,InventoryApiTests,GoldenSaveTests,ServiceabilityTests}.cs`, `src/HSchool.Client/src/ui/createSchoolDialog.test.ts` - **Итог:** все 17 тестов из списков фаз на месте; исправлен дубликат `peopleTabOverview` в `strings.ts` (ломал `npm run build`); одно замечание рядом про вкладки карточки Что подтверждено: - **29:** `CountryDef`/`ClimatePresetDef`; `namesets/` убран; ваниль `Russia` с двумя пресетами; каталог отдаёт `countries`; create принимает `countryId`, `unknown-country` на чужую страну; пресет от сида (`CreateSchool_WithTheSameSeed_GetsTheSameClimatePreset`); `nameSetId: Slavic` поднимается через `UpgradeOlderSave` (`GoldenSaveTests`, `legacy-no-native/`); формат без страны не стартует (`ServiceabilityTests`); диалог — страны и языки (`createSchoolDialog.test.ts`); золотой ростер обновлён (`GoldenRosterTests`). - **30:** поля `ThingDef`/`ColorDef`, слои как роли, мебель без `layers`; ванильная палитра и одежда в `VanillaCoreTests`; локали ru/en (`EveryVanillaLabel_ExistsInBothLocales`); учебник один def без `subject` на def. - **31:** `InventoryItem` с `def`/`color`/`condition`/`location`/`subject`; `DressGenerator` детерминирован (`DressGeneratorTests`, `InventoryApiTests.SameSeed_YieldsTheSameShirt`); слои без пересечения, платье на два слоя; пол/яркость/учебник/родители/соискатели/масса/Hauling; карточка отдаёт worn+carried, список — нет (`InventoryApiTests`); старый `people.json` без items одевается на reload (`PeopleJsonWithoutInventory_IsDressedOnReloadAndRewritten`); `HSchool.People`/`HSchool.Content` без ASP.NET; протокол не тронут. Дописано: - (нет новых тестов — списки фаз закрыты существующими) Исправлено: - Дубликат ключа `peopleTabOverview` в `strings.ts` (ru/en): vitest не ловит TS2300/TS1117, `npm run build` падал; ключ перенесён, `peopleTabPortrait` рядом с остальными вкладками. - Повтор `using HSchool.Content` в `SchoolStore.cs` (CS0105). Замечено рядом: - Карточка уже с вкладками (`personCard.ts`, фаза 31 обещала один свиток — позже по `design/inventory.md`); портрет/SwarmUI-строки в `strings.ts` — не этап A. - `ResolveClimatePreset` в `SchoolWorker` при reload без сохранённого пресета берёт первый пресет страны (`schoolSeed: 0`, `rollIfOmitted: false`) — по дизайну для legacy; create кидает пресет из `GameLoopService` до spawn. ## Срез 7. Этап B–C — климат, жизнь одежды и правила - **Фазы:** 32–37 - **Проверен на:** `5dcdee6`, 2026-08-20 - **Пути:** `src/HSchool.Simulation/{WeatherSampler,WarmthDecay,PlaceClimate,ApparelDresser,ApparelWear,MorningDress,PersonLogBrowser}.cs`, `src/HSchool.People/LockerAssigner.cs`, `src/HSchool.Content/{Appropriateness,ClimatePreset,DressRules}.cs`, `src/HSchool.Ai/ApparelGoals.cs`, `src/HSchool.Protocol`, `src/HSchool.Server/Api/{SchoolEndpoints,DressRulesModels}.cs`, `src/HSchool.Server/Game/{PersonCardReader,SchoolWorker}.cs`, `src/HSchool.Client/src/{ui/dressRulesPanel.ts,ui/managementPanel.ts,format/weather.ts,net/api.ts}`, `docs/protocol.md`, `tests/HSchool.Simulation.Tests`, `tests/HSchool.People.Tests/LockerAssignerTests.cs`, `tests/HSchool.Content.Tests/{ClimatePresetTests,AppropriatenessTests,ChangingRoomMapTests}.cs`, `tests/HSchool.AppHost.Tests/{PersonLogApiTests,DressRulesApiTests}.cs`, `tests/HSchool.Protocol.Tests`, `src/HSchool.Client/src/ui/{personCard,dressRulesPanel,managementPanel}.test.ts` - **Итог:** фазы 32–37 подтверждены; дописано 5 тестов симуляции; исправлены 2 бага переодевания и 2 регрессии тестов (не протокол) Что подтверждено: - **32–36:** погода детерминирована; skip выставляет утро; кадр часов v8 (27 байт) в трёх местах; `Warmth` и техник; шкафчики; износ и утренняя замена; уместность и PE; вкладки карточки и HTTP-лог. - **37:** вкладка «Правила» в «Управлении»; четыре комбобокса; GET/POST `dress-rules` с pending; `unknown-form`/`unknown-color` → `400`; правило с завтра; `ColorAllowed` для `whiteTopBlackBottom`; `dressRulesPanel.test.ts` — combobox без API до Apply, ошибка текстом; `ManagementPanel` не ломает штат и сетку. Дописано (32–36, прошлый проход): - `AppropriatenessSimulationTests.MorningDress_StagesPeKitForTodaysLesson` - `AppropriatenessSimulationTests.PeBreak_CompletesChangeBeforeLesson` - `AppropriatenessSimulationTests.PeLesson_WearsPeThenReturnsToEveryday` - `AppropriatenessSimulationTests.AfterPeBreak_ModeExpectsEveryday` - `PresenceTests.PhysicalEducationBeforeLesson_GoesToChangingRoomOnTheBreak` Исправлено: - `PresenceSystem`: ходьба по duty не обрывает активный `ChangeClothes`. - `ApparelPresence.ModeAt`: после перемены following PE — режим everyday. - `managementPanel.test.ts`: панель штата скрывается через `hidden`, не удаляется из DOM. - `PortraitApiTests.GetSwarmUiSettings_ReturnsPresets`: URL `/api/settings/swarmui` (CS1503). - `dressRulesPanel.ts`: неиспользуемый импорт `clear` — TS6133 на `npm run build`. Замечено рядом: - `PhysicalEducationBeforeLesson_…` не гоняет полный цикл «зал с формой» — это в `AppropriatenessSimulationTests.PeLesson_…`. - Портреты/SwarmUI — вне среза 7, но `PortraitApiTests` чинился, чтобы AppHost-сборка не падала.