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

312 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Проверенные срезы
Журнал ревью. Фаза с ✅ в [`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. Оболочка и карта
- **Фазы:** 04
- **Проверен на:** `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. Люди
- **Фазы:** 59
- **Проверен на:** `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. Штат
- **Фазы:** 1013
- **Проверен на:** `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. Расписание
- **Фазы:** 1417
- **Проверен на:** `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. Жизнь школы
- **Фазы:** 1821
- **Проверен на:** `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. Фундамент
- **Фазы:** 2228
- **Проверен на:** `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 (одежда) в работе: не писать в журнал как закрытый.
## Срез 7. Этап A — данные и гардероб
- **Фазы:** 2931
- **Проверен на:** `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).
Замечено рядом (фазы 32–37, не правилось):
- Карточка уже с вкладками (`personCard.ts`, фаза 31 обещала один свиток — позже по
`design/inventory.md`); портрет/SwarmUI-строки в `strings.ts` — не этап A.
- `ResolveClimatePreset` в `SchoolWorker` при reload без сохранённого пресета берёт первый
пресет страны (`schoolSeed: 0`, `rollIfOmitted: false`) — по дизайну для legacy; create
кидает пресет из `GameLoopService` до spawn.
- Погода, тепло, уместность, журнал дня — срез 7B–C у соседнего ревьюера.