260 lines
19 KiB
Markdown
260 lines
19 KiB
Markdown
# Проверенные срезы
|
||
|
||
Журнал ревью. Фаза с ✅ в [`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 (одежда) в работе: не писать в журнал как закрытый.
|