Remove off-queue.md and add new design documentation files including README.md, defs.md, near-term.md, projects.md, runtime.md, people.md, staffing.md, and schedule.md to outline the structure and agreements for the game's design phases.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
Договорённость на ближайшее планирование, не текущий код.
|
||||
Экран игрока: [`near-term.md`](near-term.md). Потоки: [`runtime.md`](runtime.md).
|
||||
Проекты: [`projects.md`](projects.md). Как устроен хост сейчас: [`../architecture.md`](../architecture.md).
|
||||
Проекты: [`projects.md`](projects.md). Как устроен хост сейчас: [`../architecture.md`](../../architecture.md).
|
||||
|
||||
Идея как у RimWorld: **ядро — код систем**, содержание игры — **данные (defs)**. Новый стул, кабинет
|
||||
или действие, которое уже умеет код, появляются без пересборки `HSchool.Simulation`. Сборка нужна,
|
||||
@@ -1,7 +1,7 @@
|
||||
# Ближайший горизонт: что видит игрок
|
||||
|
||||
Это не текущее состояние кода, а договорённости на ближайшее планирование.
|
||||
Как устроено сейчас — в [`architecture.md`](../architecture.md).
|
||||
Как устроено сейчас — в [`architecture.md`](../../architecture.md).
|
||||
|
||||
## Решение: не PixiJS, а менеджер на DOM
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Люди: генерация, характеристики, просмотр
|
||||
|
||||
Договорённость на следующий срез, не текущий код.
|
||||
Типы и карта: [`defs.md`](defs.md). Экран игрока: [`near-term.md`](near-term.md).
|
||||
Потоки: [`runtime.md`](runtime.md). Проекты: [`projects.md`](projects.md).
|
||||
Типы и карта: [`defs.md`](../01-shell/defs.md). Экран игрока: [`near-term.md`](../01-shell/near-term.md).
|
||||
Потоки: [`runtime.md`](../01-shell/runtime.md). Проекты: [`projects.md`](../01-shell/projects.md).
|
||||
|
||||
Школа перестаёт быть пустой коробкой. Появляются ученики, работники и родители: у каждого имя,
|
||||
тело, навыки, черты и нужды. **Ничего из этого пока ни на что не влияет** — люди не ходят, не
|
||||
@@ -209,7 +209,7 @@
|
||||
Скорость — данные, не код. Когда появится еда и сон, цифра меняется в JSONC, а не в C#.
|
||||
|
||||
Отменено срезом 5: в `core` ненулевой `decayPerHour`, сон и голод восстанавливаются вне школы,
|
||||
см. [`ai.md`](ai.md).
|
||||
см. [`ai.md`](../05-ai/ai.md).
|
||||
|
||||
## Имена
|
||||
|
||||
@@ -343,16 +343,16 @@ Protocol ← Server → Simulation → People → Content
|
||||
- Не отправлять черты и навыки в списке — только в карточке. Список читают глазами, карточку
|
||||
открывают по одному человеку.
|
||||
- Сид на семью, а не один на школу: иначе любая правка генератора переставит всех.
|
||||
- Ненулевую скорость нужд не включать, пока нечем их восполнять — сделано срезом 5, см. [`ai.md`](ai.md).
|
||||
- Ненулевую скорость нужд не включать, пока нечем их восполнять — сделано срезом 5, см. [`ai.md`](../05-ai/ai.md).
|
||||
|
||||
## Заведомо не сейчас
|
||||
|
||||
Срез 2 закрыт. Строки, которые отменили следующие срезы, помечены.
|
||||
|
||||
- Поведение: расписание, уроки, перемещение по карте — отменено срезами 4–5, см. [`schedule.md`](schedule.md), [`ai.md`](ai.md).
|
||||
- Поведение: расписание, уроки, перемещение по карте — отменено срезами 4–5, см. [`schedule.md`](../04-schedule/schedule.md), [`ai.md`](../05-ai/ai.md).
|
||||
- Влияние характеристик на что-либо. Черты и навыки в этом срезе — текст в карточке — отменено срезом 5 (маршрут, обучение).
|
||||
- Вызов родителя в школу. Задел есть (родитель — сущность), реализации нет.
|
||||
- Наём и увольнение вручную. Должности закрываются генератором — отменено срезом 3, см. [`staffing.md`](staffing.md). Школа открывается без штата.
|
||||
- Наём и увольнение вручную. Должности закрываются генератором — отменено срезом 3, см. [`staffing.md`](../03-staffing/staffing.md). Школа открывается без штата.
|
||||
- Смеси наборов имён с весами.
|
||||
- Новые роли из модов: ученик, работник, родитель — код, не данные.
|
||||
- Портреты и любой арт.
|
||||
@@ -391,7 +391,7 @@ Protocol ← Server → Simulation → People → Content
|
||||
| Выдача навыков | Не полный каталог: always, родной, предметы года, взрослые лишние, родственные языки |
|
||||
| Черты в `core` | Около десяти |
|
||||
| Нужды в `core` | Сон, голод, туалет, общение |
|
||||
| Нужды | Машинерия есть; убывание в `core` — срез 5, не ноль, см. [`ai.md`](ai.md) |
|
||||
| Нужды | Машинерия есть; убывание в `core` — срез 5, не ноль, см. [`ai.md`](../05-ai/ai.md) |
|
||||
| Слои по ролям | Одинаковые виды данных; ключи навыков зависят от роли и возраста |
|
||||
| Набор имён | Один на школу, выбор в create, в `core` славянский; прочие — моды |
|
||||
| Родной язык | Один из `nativeLanguages` набора, выбор в create; остальные языки списка — часто низкий навык |
|
||||
@@ -1,8 +1,8 @@
|
||||
# Наём, предметы и бюджет
|
||||
|
||||
Договорённость на следующий срез, не текущий код.
|
||||
Люди: [`people.md`](people.md). Типы и карта: [`defs.md`](defs.md).
|
||||
Экран игрока: [`near-term.md`](near-term.md). Проекты: [`projects.md`](projects.md).
|
||||
Люди: [`people.md`](../02-people/people.md). Типы и карта: [`defs.md`](../01-shell/defs.md).
|
||||
Экран игрока: [`near-term.md`](../01-shell/near-term.md). Проекты: [`projects.md`](../01-shell/projects.md).
|
||||
|
||||
Первый срез, где игрок **что-то решает**. До сих пор школа собиралась сама: генератор закрывал
|
||||
все должности, игрок смотрел. Теперь школа открывается пустой — без единого учителя, — и её
|
||||
@@ -49,7 +49,7 @@
|
||||
- **сколько часов в неделю** в каждой из них — учебный план.
|
||||
|
||||
Часы здесь не задел на расписание, а рабочая величина уже этого среза: из них считается нагрузка
|
||||
учителя, а из нагрузки — зарплата. Расписание ([`schedule.md`](schedule.md)) только расставит эти
|
||||
учителя, а из нагрузки — зарплата. Расписание ([`schedule.md`](../04-schedule/schedule.md)) только расставит эти
|
||||
часы по дням; сколько их — решает учебный план.
|
||||
|
||||
Так «начальные классы» получаются естественно: один предмет, который развивает всё понемногу и
|
||||
@@ -89,7 +89,7 @@
|
||||
на каждый предмет, преподаваемый в существующих параллелях, нужен хотя бы один учитель.
|
||||
|
||||
Нетренерские должности — директор, секретарь, медсестра, библиотекарь, повар — по-прежнему рождаются
|
||||
из комнат, как описано в [`defs.md`](defs.md). Их игрок тоже нанимает, но предметов им не назначают.
|
||||
из комнат, как описано в [`defs.md`](../01-shell/defs.md). Их игрок тоже нанимает, но предметов им не назначают.
|
||||
|
||||
## Соискатели
|
||||
|
||||
@@ -198,7 +198,7 @@
|
||||
|
||||
## Заведомо не сейчас
|
||||
|
||||
- Само расписание: когда именно идут эти часы. Следующий срез, [`schedule.md`](schedule.md).
|
||||
- Само расписание: когда именно идут эти часы. Следующий срез, [`schedule.md`](../04-schedule/schedule.md).
|
||||
Здесь предмет — нагрузка в часах, а не событие в кабинете.
|
||||
- Уроки, звонки, оценки, посещаемость.
|
||||
- Классное руководство: класс закреплён за кабинетом, но не за учителем.
|
||||
@@ -1,8 +1,8 @@
|
||||
# Расписание
|
||||
|
||||
Договорённость на срез после штата, не текущий код.
|
||||
Штат и предметы: [`staffing.md`](staffing.md). Люди: [`people.md`](people.md).
|
||||
Типы и карта: [`defs.md`](defs.md). Экран: [`near-term.md`](near-term.md).
|
||||
Штат и предметы: [`staffing.md`](../03-staffing/staffing.md). Люди: [`people.md`](../02-people/people.md).
|
||||
Типы и карта: [`defs.md`](../01-shell/defs.md). Экран: [`near-term.md`](../01-shell/near-term.md).
|
||||
|
||||
Часы из учебного плана раскладываются по дням и кабинетам. Школа впервые начинает **жить по
|
||||
времени**: в 10:15 у 5Б математика в кабинете 204, и это видно на карте.
|
||||
@@ -140,9 +140,9 @@
|
||||
| Место урока | Кабинет класса, если у предмета нет требования к типу помещения |
|
||||
| Нет учителя | Урок не ставится; предмет числится непокрытым |
|
||||
| Карта | В дереве рядом с комнатой — что и у кого там сейчас |
|
||||
| Панель локации | «Сейчас» и «Персонажи» заполняются из расписания — с срезом 5 из присутствия, см. [`ai.md`](ai.md) |
|
||||
| Панель локации | «Сейчас» и «Персонажи» заполняются из расписания — с срезом 5 из присутствия, см. [`ai.md`](../05-ai/ai.md) |
|
||||
| Расписание класса | В разделе «Управление», сетка «день × урок» |
|
||||
| Расписание учителя | В его карточке, там же где навыки и семья |
|
||||
| Общая сетка школы | Не делаем: её читает только тот, кто раскладывает вручную |
|
||||
| Где живёт код | Отдельная библиотека рядом с `HSchool.People` |
|
||||
| Люди и место | Находятся по расписанию; ходьбы нет — отменено срезом 5, присутствие стало состоянием ([`ai.md`](ai.md)) |
|
||||
| Люди и место | Находятся по расписанию; ходьбы нет — отменено срезом 5, присутствие стало состоянием ([`ai.md`](../05-ai/ai.md)) |
|
||||
@@ -1,8 +1,8 @@
|
||||
# Жизнь школы
|
||||
|
||||
Договорённость на срез после расписания, не текущий код.
|
||||
Расписание: [`schedule.md`](schedule.md). Штат: [`staffing.md`](staffing.md).
|
||||
Люди: [`people.md`](people.md). Типы и карта: [`defs.md`](defs.md). Экран: [`near-term.md`](near-term.md).
|
||||
Расписание: [`schedule.md`](../04-schedule/schedule.md). Штат: [`staffing.md`](../03-staffing/staffing.md).
|
||||
Люди: [`people.md`](../02-people/people.md). Типы и карта: [`defs.md`](../01-shell/defs.md). Экран: [`near-term.md`](../01-shell/near-term.md).
|
||||
|
||||
Люди начинают **ходить и решать**. До сих пор человек находился там, где его застало расписание;
|
||||
теперь он приходит утром, идёт коридором в кабинет, может уйти с урока в туалет и вернуться —
|
||||
@@ -129,7 +129,7 @@
|
||||
не сидят вдвоём. Это связывает мебель на карте с поведением, а не только с вместимостью класса.
|
||||
|
||||
Так мод добавляет поведение, не написав ни строчки кода, — ровно как обещано в
|
||||
[`defs.md`](defs.md).
|
||||
[`defs.md`](../01-shell/defs.md).
|
||||
|
||||
**Обязанности из каталога действий не выбирают.** Урок приходит из расписания, работа по
|
||||
должности — из `RoomDef.works`, который уже проставлен в `core` (`TeachLesson` у кабинета,
|
||||
@@ -1,8 +1,8 @@
|
||||
# Одежда, вещи и климат
|
||||
|
||||
Договорённость на следующий срез, не текущий код.
|
||||
Люди: [`people.md`](people.md). Типы и карта: [`defs.md`](defs.md). Жизнь школы: [`ai.md`](ai.md).
|
||||
Экран: [`near-term.md`](near-term.md). Проекты: [`projects.md`](projects.md).
|
||||
Люди: [`people.md`](../02-people/people.md). Типы и карта: [`defs.md`](../01-shell/defs.md). Жизнь школы: [`ai.md`](../05-ai/ai.md).
|
||||
Экран: [`near-term.md`](../01-shell/near-term.md). Проекты: [`projects.md`](../01-shell/projects.md).
|
||||
|
||||
У человека появляется то, что на нём надето и что он несёт. Школа получает климат и правила
|
||||
одежды. Игрок это **смотрит** и выбирает правила; надевает не он — система сама приводит гардероб
|
||||
@@ -1,8 +1,8 @@
|
||||
# Сессия и темп
|
||||
|
||||
Договорённость на следующий срез, не текущий код.
|
||||
Оболочка: [`near-term.md`](near-term.md). Рантайм: [`runtime.md`](runtime.md).
|
||||
Протокол: [`../protocol.md`](../protocol.md).
|
||||
Оболочка: [`near-term.md`](../01-shell/near-term.md). Рантайм: [`runtime.md`](../01-shell/runtime.md).
|
||||
Протокол: [`../protocol.md`](../../protocol.md).
|
||||
|
||||
Один процесс сервера, несколько браузеров в локальной сети. Это не аккаунты и не интернет:
|
||||
общий пароль альфы пускает к двери, имя отличает игроков. Школу по-прежнему тикает её работник,
|
||||
@@ -1,8 +1,8 @@
|
||||
# Общение, отношения и романтический пак
|
||||
|
||||
Договорённость на срез после сессии/темпа, не текущий код.
|
||||
Люди: [`people.md`](people.md). ИИ: [`ai.md`](ai.md). Одежда (уместность как образец):
|
||||
[`inventory.md`](inventory.md). Моды: [`defs.md`](defs.md), [`foundation.md`](foundation.md).
|
||||
Люди: [`people.md`](../02-people/people.md). ИИ: [`ai.md`](../05-ai/ai.md). Одежда (уместность как образец):
|
||||
[`inventory.md`](../07-inventory/inventory.md). Моды: [`defs.md`](../01-shell/defs.md), [`foundation.md`](../06-foundation/foundation.md).
|
||||
|
||||
У человека появляется, **с кем** он говорит и **что** о нём думают другие. Нужда «общение» уже
|
||||
есть, действие `Chat` уже есть — но это соло в коридоре. Срез делает разговор кружком, тему —
|
||||
@@ -1,8 +1,8 @@
|
||||
# Ремесло: слои, страховка тестов, горячие точки
|
||||
|
||||
Договорённость на срез после одежды, сессии и склейки урока, не текущий код.
|
||||
Фундамент: [`foundation.md`](foundation.md). Проекты: [`projects.md`](projects.md).
|
||||
Вне очереди: [`off-queue.md`](off-queue.md). Общение (не ждём 44/46): [`social.md`](social.md).
|
||||
Фундамент: [`foundation.md`](../06-foundation/foundation.md). Проекты: [`projects.md`](../01-shell/projects.md).
|
||||
Вне очереди: [`off-queue.md`](../off-queue/README.md). Общение (не ждём 44/46): [`social.md`](../09-social/social.md).
|
||||
|
||||
Игра уже живая: люди ходят, одеваются, учатся, болтают. Рядом лежат четыре копии одного
|
||||
запрета на ссылки, `npm test` зелёный при красном `tsc`, работник школы на тысячу строк и
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
## На какие вопросы отвечает
|
||||
|
||||
- Слои из [`projects.md`](projects.md) и инвариант 4 — тест в одном месте, не четыре копипасты.
|
||||
- Слои из [`projects.md`](../01-shell/projects.md) и инвариант 4 — тест в одном месте, не четыре копипасты.
|
||||
- `npm test` клиента = typecheck + vitest; дубликат в `strings.ts` красный без `npm run build`.
|
||||
- `SchoolWorker` и сборка карточки режутся по швам, поведение то же.
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
- Новых экранов, полей сейва, байтов сокета.
|
||||
- Фаз 44 и 46, портретов/SwarmUI как фичи, `GET /api/catalog.lunchBreaks`.
|
||||
- Багов сессии (второе имя при живой куке, ключи DataProtection) — [`../bugs/README.md`](../bugs/README.md).
|
||||
- Багов сессии (второе имя при живой куке, ключи DataProtection) — [`../bugs/README.md`](../../bugs/README.md).
|
||||
- Инверсии Game → Api DTO и «пройти SOLID по всему дереву».
|
||||
|
||||
## Что меняется в уже принятом
|
||||
@@ -50,7 +50,7 @@
|
||||
`GetReferencedAssemblies` и чтение `*.cs`. Копии `Assembly_DoesNotReference*` и `Sources_DoNotUseWallClock`
|
||||
из People/Ai/Schedule/Simulation уезжают сюда.
|
||||
|
||||
Список (как [`projects.md`](projects.md)):
|
||||
Список (как [`projects.md`](../01-shell/projects.md)):
|
||||
|
||||
| Сборка | Не ссылается | Не содержит в исходниках |
|
||||
| --- | --- | --- |
|
||||
@@ -0,0 +1,17 @@
|
||||
# Дизайн
|
||||
|
||||
Договорённости срезов. Не читать целиком: открой папку среза.
|
||||
|
||||
| Срез | Папка |
|
||||
| --- | --- |
|
||||
| 1. Оболочка и карта | [01-shell](01-shell/) |
|
||||
| 2. Люди | [02-people](02-people/people.md) |
|
||||
| 3. Штат | [03-staffing](03-staffing/staffing.md) |
|
||||
| 4. Расписание | [04-schedule](04-schedule/schedule.md) |
|
||||
| 5. Жизнь школы | [05-ai](05-ai/ai.md) |
|
||||
| 6. Фундамент | [06-foundation](06-foundation/foundation.md) |
|
||||
| 7. Одежда, вещи и климат | [07-inventory](07-inventory/inventory.md) |
|
||||
| 8. Сессия и темп | [08-session](08-session/session.md) |
|
||||
| 9. Общение и романтический пак | [09-social](09-social/social.md) |
|
||||
| 10. Ремесло | [10-craft](10-craft/craft.md) |
|
||||
| Вне очереди | [off-queue](off-queue/) |
|
||||
@@ -1,178 +0,0 @@
|
||||
# Вне очереди
|
||||
|
||||
Задачи, которых нет в нумерованных срезах. Срез 10 — ремесло
|
||||
([`craft.md`](craft.md)), не сюда. Сюда — склейка уже живых систем и мелкий DX. После любой
|
||||
фазы школа целая.
|
||||
|
||||
Люди: [`people.md`](people.md). Штат: [`staffing.md`](staffing.md). Расписание:
|
||||
[`schedule.md`](schedule.md). Присутствие: [`ai.md`](ai.md). Одежда и климат:
|
||||
[`inventory.md`](inventory.md).
|
||||
|
||||
## Связность урока
|
||||
|
||||
Урок уже растёт навык, если ученик стоит в кабинете и не голоден. Рядом лежат числа, которые
|
||||
игрок видит и которые на этот рост не влияют: учитель в туалете, навык учителя, тепло,
|
||||
учебник в сумке, снег на дороге.
|
||||
|
||||
Этот кусок отвечает на вопрос «почему нанимать сильного, чинить тепло и класть учебник в
|
||||
сумку». Оценок, посещаемости как журнала и приказов нет.
|
||||
|
||||
### Что меняется в уже принятом
|
||||
|
||||
| Было | Стало | Почему |
|
||||
| --- | --- | --- |
|
||||
| Ученик в кабинете качает навык, учитель может быть где угодно | Рост только если назначенный учитель стоит в том же узле и не идёт | Зазор «обязанность / место» уже есть; урок его не смотрел |
|
||||
| Зарплата зависит от навыков, урок — нет | Навык учителя по предмету масштабирует `Gain` | Иначе «математика 78» в пуле — только цена |
|
||||
| Голод режет урок, тепло — нет | Та же `NeedFactor` на тепло | Полоска уже живая; [`inventory.md`](inventory.md) откладывал штраф |
|
||||
| Учебники сегодняшних предметов едут в сумке | Нет в сумке на этом уроке — половинный рост | Переноска и шкафчик иначе остаются двумя числами |
|
||||
| Погода одевает, на приход не влияет | Дождь и снег добавляют минуты к запасу на дорогу | Часы уже показывают осадки; ленивый уже опаздывает от черты |
|
||||
|
||||
### Формула
|
||||
|
||||
`HSchool.Ai.LessonLearning.Gain` по-прежнему чистое число. Множители:
|
||||
|
||||
- **нужды** — `NeedFactor(голод) × NeedFactor(тепло)`; нет нужды в каталоге — множитель 1;
|
||||
- **черты ученика** — как сейчас;
|
||||
- **учитель** — `NeedFactor(навык / 100)`, навык — среднее по `SubjectDef.skills` у учителя,
|
||||
нет ключа — `Range.Min` этого навыка; учителя нет в комнате — множитель 0, рост не пишется;
|
||||
- **учебник** — 1, если в сумке есть экземпляр с `subject` этого урока; иначе
|
||||
`BehaviorDef.lessonNoTextbookFactor` (ваниль 0.5).
|
||||
|
||||
Учитель «стоит в комнате»: `NodeId` = кабинет урока, путь пуст, остаток минут 0. Действие
|
||||
учителя не отменяет урок (дежурство — не `ActionDef`). Нет человека с этим id — учителя нет.
|
||||
|
||||
Дорога: к нынешнему `SlackMinutes` (черты + бросок) прибавляются минуты из
|
||||
`BehaviorDef.commuteRainMinutes` / `commuteSnowMinutes`, если в момент сборки плана дня на
|
||||
улице дождь или снег. `HSchool.Ai` осадки не знает — симуляция передаёт уже посчитанные минуты.
|
||||
|
||||
### Что видит игрок
|
||||
|
||||
Числа на карточке. Плюс строка в сегодняшней истории, **один раз на ключ в сутки**, не каждый
|
||||
тик:
|
||||
|
||||
| Тип | Когда | `thingDef` |
|
||||
| --- | --- | --- |
|
||||
| `lesson-no-teacher` | Урок шёл, учителя не было в кабинете | предмет |
|
||||
| `lesson-cold` | На уроке, который иначе учил, тепло ниже `needThreshold` | предмет |
|
||||
| `lesson-no-textbook` | На уроке нет учебника этого предмета в сумке | предмет |
|
||||
|
||||
Опоздание из-за снега в лог не пишем: весь состав получил бы одну и ту же строку, а место
|
||||
человека и так видно.
|
||||
|
||||
Клиент по-прежнему рисует `label` с сервера. Сокет и сейв не меняются. Версию протокола не
|
||||
бампить.
|
||||
|
||||
### Где живёт код
|
||||
|
||||
Нового проекта нет. Формула и план дня — `HSchool.Ai`. Присутствие учителя, тепло, сумка,
|
||||
погода на входе в план — `HSchool.Simulation`. Подписи лога — каталог. Список типов —
|
||||
`docs/protocol.md` (HTTP лога).
|
||||
|
||||
### Заведомо не сейчас
|
||||
|
||||
- Оценки, журнал посещаемости, выговор за прогул.
|
||||
- Перегруз замедляет ходьбу.
|
||||
- Насмешки над формой и мнения — срез 9.
|
||||
- Вызов родителей, деньги за одежду, болезнь от промокания.
|
||||
- Клиент сам считает «учится хуже».
|
||||
|
||||
### Зафиксировано этим разговором
|
||||
|
||||
| Тема | Решение |
|
||||
| --- | --- |
|
||||
| Нарезка | Пять фаз во «Вне очереди», не срез 10 |
|
||||
| Стоп | После каждой фазы школа целая |
|
||||
| Протокол | Не бампить; новые `type` только в HTTP лога |
|
||||
| Сейв | Не трогать |
|
||||
| Учитель на уроке | Тот же узел, не идёт; нет id — нет роста |
|
||||
| Навык учителя | Среднее по скиллам предмета, та же кривая что у нужды |
|
||||
| Тепло | Рядом с голодом, произведение двух `NeedFactor` |
|
||||
| Учебник | Только сумка, не шкафчик и не дом; ваниль ×0.5 |
|
||||
| Погода на дорогу | Минуты в `BehaviorDef`; лога нет |
|
||||
|
||||
## Пропуск сборки при запуске
|
||||
|
||||
### Зачем
|
||||
|
||||
`run-aspire.cmd` каждый раз вызывает `dotnet run`, а тот — MSBuild графа Aspire, даже когда
|
||||
исходники не менялись. Повторный запуск после Ctrl+C стоит десятки секунд впустую: SDK
|
||||
пересчитывает хост, хотя dll на месте.
|
||||
|
||||
### Было / Стало / Почему
|
||||
|
||||
**Было.** Скрипт всегда `dotnet run --project src/HSchool.AppHost`. Аргументы проходили насквозь.
|
||||
|
||||
**Стало.** Если `HSchool.AppHost.dll` и `HSchool.Server.dll` новее входов (C#, csproj, props,
|
||||
`global.json`), скрипт делает `dotnet run --no-build`. Иначе — `dotnet build`, потом `--no-build`.
|
||||
`--rebuild` собирает всегда. Конфигурация (`-c` / `--configuration`) выбирает, какие dll сравнивать;
|
||||
по умолчанию Debug, как у `dotnet run`.
|
||||
|
||||
**Почему.** Инкрементальный MSBuild всё равно оценивает Aspire SDK. `--no-build` это пропускает.
|
||||
Клиентский TypeScript и JSONC модов не входы: Vite и каталог читают диск (`ContentRoot`), а не
|
||||
`bin`. Тестовые проекты AppHost не ссылается — их правки запуск не пересобирают.
|
||||
|
||||
Правила «устарел ли билд» живут в `tools/apphost-uptodate.ps1` (то, что вызывает `run-aspire.ps1`) и в
|
||||
`LaunchBuildStamp` (то, что проверяют тесты). Менять надо оба.
|
||||
|
||||
### Что не входит
|
||||
|
||||
Голый `dotnet run --project src/HSchool.AppHost` по-прежнему собирает — так удобнее агентам с
|
||||
грязным деревом. Linux-обёртки нет: точка входа Windows — `.cmd`. Протокол, HTTP и сейв не
|
||||
трогаем.
|
||||
|
||||
## Что нового после входа
|
||||
|
||||
### Зачем
|
||||
|
||||
Альфа обновляется часто. Игрок не смотрит git: если с прошлого захода в этот браузер накатили
|
||||
другую сборку Server, один раз показать, что вошло в неё.
|
||||
|
||||
### Было / Стало / Почему
|
||||
|
||||
**Было.** Нет версии сборки на экране. Сессионная кука HttpOnly и про вход.
|
||||
|
||||
**Стало.** Сборка Server вшивает `HEAD` и `git log --first-parent`. `GET /api/changelog?since=`
|
||||
отдаёт текущий SHA и коммиты после якоря. Клиент держит `hschool.seen-rev` (год, `Path=/`,
|
||||
`SameSite=Lax`, не HttpOnly). Первый заход без куки окно не показывает — только запоминает
|
||||
текущий SHA. Окно — после входа, не при возврате из школы.
|
||||
|
||||
**Почему.** «Накатанный» — то, что в dll, а не грязный HEAD при `--no-build`. First-parent после
|
||||
`--no-ff` — это слитые фазы, не внутренняя нарезка ветки. `Mark phase N` оставляем в цепочке
|
||||
якорем, в список не рисуем: иначе кука на таком HEAD потеряла бы следующее слияние.
|
||||
|
||||
### Что не входит
|
||||
|
||||
Ручной `CHANGELOG.md`. Запись на пользователе в `users.json`. Вызов git из бегущего процесса.
|
||||
Бамп версии сокета. Окно внутри открытой школы.
|
||||
|
||||
## Состояние экрана
|
||||
|
||||
### Зачем
|
||||
|
||||
Менеджер — списки с фильтрами. Сейчас они живут только в RAM: F5 всегда меню, повторный вход
|
||||
сбрасывает вкладки и запросы. Игрок сравнивает людей и соискателей; потерять «ученики 5А» на
|
||||
обновлении — дырка в уже живых экранах, не новая фича.
|
||||
|
||||
### Было / Стало / Почему
|
||||
|
||||
**Было.** SPA без адреса. `GameScreen.show` и `PeoplePanel.show` обнуляют вкладки, фильтры и
|
||||
выбор. Язык уже в `localStorage`; игровые часы — на сервере.
|
||||
|
||||
**Стало.** Query URL держит *где я*: школа, обзор/управление, карта/люди, выбранные комната и
|
||||
человек. `sessionStorage` по `schoolId` держит фильтры, поиски, сорт, страницу, вкладку карточки
|
||||
и класс сетки — и последний маршрут, чтобы вход с меню поднял то же место. F5 с `?school=`
|
||||
шлёт тот же `OpenSchool`, что карточка. Вход/выход — `pushState`; смена вкладки и фильтра —
|
||||
`replaceState`, чтобы «назад» не листал каждый клик.
|
||||
|
||||
**Почему.** Сервер не знает про вкладки; класть их в сейв — лишний HTTP. `localStorage` как у
|
||||
языка держал бы «5А» через месяц. URL без фильтров остаётся коротким и копируемым.
|
||||
|
||||
### Что видит игрок
|
||||
|
||||
F5 внутри школы — та же школа, те же вкладки и фильтры. Назад — меню. Снова открыть ту же
|
||||
школу — не сброс на карту. Гость не входит в управление по ссылке. Скорость часов, пауза,
|
||||
открытый пул соискателей и мастер создания не вспоминаются.
|
||||
|
||||
### Что не входит
|
||||
|
||||
Поиск по имени в списках, где его нет. Роутер-библиотека. Состояние на сервере. Бамп протокола.
|
||||
@@ -0,0 +1,15 @@
|
||||
# Вне очереди
|
||||
|
||||
Склейка уже живых систем и мелкий DX. Именованный срез — не сюда.
|
||||
После любой фазы школа целая. Не читать все темы: открой файл задачи.
|
||||
|
||||
| Тема | Фазы |
|
||||
| --- | --- |
|
||||
| [Связность урока](lesson-consequences.md) | 48, 50–53 |
|
||||
| [Пропуск сборки](skip-stale-build.md) | 49 |
|
||||
| [Что нового](whats-new.md) | 54 |
|
||||
| [Состояние экрана](view-state.md) | 55 |
|
||||
|
||||
Люди: [`../02-people/people.md`](../02-people/people.md). Штат: [`../03-staffing/staffing.md`](../03-staffing/staffing.md).
|
||||
Расписание: [`../04-schedule/schedule.md`](../04-schedule/schedule.md). Присутствие: [`../05-ai/ai.md`](../05-ai/ai.md).
|
||||
Одежда: [`../07-inventory/inventory.md`](../07-inventory/inventory.md). Ремесло: [`../10-craft/craft.md`](../10-craft/craft.md).
|
||||
@@ -0,0 +1,83 @@
|
||||
Часть [Вне очереди](README.md). Соседей по папке не читать, если задача не про них.
|
||||
|
||||
# Связность урока
|
||||
|
||||
Урок уже растёт навык, если ученик стоит в кабинете и не голоден. Рядом лежат числа, которые
|
||||
игрок видит и которые на этот рост не влияют: учитель в туалете, навык учителя, тепло,
|
||||
учебник в сумке, снег на дороге.
|
||||
|
||||
Этот кусок отвечает на вопрос «почему нанимать сильного, чинить тепло и класть учебник в
|
||||
сумку». Оценок, посещаемости как журнала и приказов нет.
|
||||
|
||||
### Что меняется в уже принятом
|
||||
|
||||
| Было | Стало | Почему |
|
||||
| --- | --- | --- |
|
||||
| Ученик в кабинете качает навык, учитель может быть где угодно | Рост только если назначенный учитель стоит в том же узле и не идёт | Зазор «обязанность / место» уже есть; урок его не смотрел |
|
||||
| Зарплата зависит от навыков, урок — нет | Навык учителя по предмету масштабирует `Gain` | Иначе «математика 78» в пуле — только цена |
|
||||
| Голод режет урок, тепло — нет | Та же `NeedFactor` на тепло | Полоска уже живая; [`inventory.md`](../07-inventory/inventory.md) откладывал штраф |
|
||||
| Учебники сегодняшних предметов едут в сумке | Нет в сумке на этом уроке — половинный рост | Переноска и шкафчик иначе остаются двумя числами |
|
||||
| Погода одевает, на приход не влияет | Дождь и снег добавляют минуты к запасу на дорогу | Часы уже показывают осадки; ленивый уже опаздывает от черты |
|
||||
|
||||
### Формула
|
||||
|
||||
`HSchool.Ai.LessonLearning.Gain` по-прежнему чистое число. Множители:
|
||||
|
||||
- **нужды** — `NeedFactor(голод) × NeedFactor(тепло)`; нет нужды в каталоге — множитель 1;
|
||||
- **черты ученика** — как сейчас;
|
||||
- **учитель** — `NeedFactor(навык / 100)`, навык — среднее по `SubjectDef.skills` у учителя,
|
||||
нет ключа — `Range.Min` этого навыка; учителя нет в комнате — множитель 0, рост не пишется;
|
||||
- **учебник** — 1, если в сумке есть экземпляр с `subject` этого урока; иначе
|
||||
`BehaviorDef.lessonNoTextbookFactor` (ваниль 0.5).
|
||||
|
||||
Учитель «стоит в комнате»: `NodeId` = кабинет урока, путь пуст, остаток минут 0. Действие
|
||||
учителя не отменяет урок (дежурство — не `ActionDef`). Нет человека с этим id — учителя нет.
|
||||
|
||||
Дорога: к нынешнему `SlackMinutes` (черты + бросок) прибавляются минуты из
|
||||
`BehaviorDef.commuteRainMinutes` / `commuteSnowMinutes`, если в момент сборки плана дня на
|
||||
улице дождь или снег. `HSchool.Ai` осадки не знает — симуляция передаёт уже посчитанные минуты.
|
||||
|
||||
### Что видит игрок
|
||||
|
||||
Числа на карточке. Плюс строка в сегодняшней истории, **один раз на ключ в сутки**, не каждый
|
||||
тик:
|
||||
|
||||
| Тип | Когда | `thingDef` |
|
||||
| --- | --- | --- |
|
||||
| `lesson-no-teacher` | Урок шёл, учителя не было в кабинете | предмет |
|
||||
| `lesson-cold` | На уроке, который иначе учил, тепло ниже `needThreshold` | предмет |
|
||||
| `lesson-no-textbook` | На уроке нет учебника этого предмета в сумке | предмет |
|
||||
|
||||
Опоздание из-за снега в лог не пишем: весь состав получил бы одну и ту же строку, а место
|
||||
человека и так видно.
|
||||
|
||||
Клиент по-прежнему рисует `label` с сервера. Сокет и сейв не меняются. Версию протокола не
|
||||
бампить.
|
||||
|
||||
### Где живёт код
|
||||
|
||||
Нового проекта нет. Формула и план дня — `HSchool.Ai`. Присутствие учителя, тепло, сумка,
|
||||
погода на входе в план — `HSchool.Simulation`. Подписи лога — каталог. Список типов —
|
||||
`docs/protocol.md` (HTTP лога).
|
||||
|
||||
### Заведомо не сейчас
|
||||
|
||||
- Оценки, журнал посещаемости, выговор за прогул.
|
||||
- Перегруз замедляет ходьбу.
|
||||
- Насмешки над формой и мнения — срез 9.
|
||||
- Вызов родителей, деньги за одежду, болезнь от промокания.
|
||||
- Клиент сам считает «учится хуже».
|
||||
|
||||
### Зафиксировано этим разговором
|
||||
|
||||
| Тема | Решение |
|
||||
| --- | --- |
|
||||
| Нарезка | Пять фаз во «Вне очереди», не срез 10 |
|
||||
| Стоп | После каждой фазы школа целая |
|
||||
| Протокол | Не бампить; новые `type` только в HTTP лога |
|
||||
| Сейв | Не трогать |
|
||||
| Учитель на уроке | Тот же узел, не идёт; нет id — нет роста |
|
||||
| Навык учителя | Среднее по скиллам предмета, та же кривая что у нужды |
|
||||
| Тепло | Рядом с голодом, произведение двух `NeedFactor` |
|
||||
| Учебник | Только сумка, не шкафчик и не дом; ваниль ×0.5 |
|
||||
| Погода на дорогу | Минуты в `BehaviorDef`; лога нет |
|
||||
@@ -0,0 +1,31 @@
|
||||
Часть [Вне очереди](README.md). Соседей по папке не читать, если задача не про них.
|
||||
|
||||
# Пропуск сборки при запуске
|
||||
|
||||
### Зачем
|
||||
|
||||
`run-aspire.cmd` каждый раз вызывает `dotnet run`, а тот — MSBuild графа Aspire, даже когда
|
||||
исходники не менялись. Повторный запуск после Ctrl+C стоит десятки секунд впустую: SDK
|
||||
пересчитывает хост, хотя dll на месте.
|
||||
|
||||
### Было / Стало / Почему
|
||||
|
||||
**Было.** Скрипт всегда `dotnet run --project src/HSchool.AppHost`. Аргументы проходили насквозь.
|
||||
|
||||
**Стало.** Если `HSchool.AppHost.dll` и `HSchool.Server.dll` новее входов (C#, csproj, props,
|
||||
`global.json`), скрипт делает `dotnet run --no-build`. Иначе — `dotnet build`, потом `--no-build`.
|
||||
`--rebuild` собирает всегда. Конфигурация (`-c` / `--configuration`) выбирает, какие dll сравнивать;
|
||||
по умолчанию Debug, как у `dotnet run`.
|
||||
|
||||
**Почему.** Инкрементальный MSBuild всё равно оценивает Aspire SDK. `--no-build` это пропускает.
|
||||
Клиентский TypeScript и JSONC модов не входы: Vite и каталог читают диск (`ContentRoot`), а не
|
||||
`bin`. Тестовые проекты AppHost не ссылается — их правки запуск не пересобирают.
|
||||
|
||||
Правила «устарел ли билд» живут в `tools/apphost-uptodate.ps1` (то, что вызывает `run-aspire.ps1`) и в
|
||||
`LaunchBuildStamp` (то, что проверяют тесты). Менять надо оба.
|
||||
|
||||
### Что не входит
|
||||
|
||||
Голый `dotnet run --project src/HSchool.AppHost` по-прежнему собирает — так удобнее агентам с
|
||||
грязным деревом. Linux-обёртки нет: точка входа Windows — `.cmd`. Протокол, HTTP и сейв не
|
||||
трогаем.
|
||||
@@ -0,0 +1,33 @@
|
||||
Часть [Вне очереди](README.md). Соседей по папке не читать, если задача не про них.
|
||||
|
||||
# Состояние экрана
|
||||
|
||||
### Зачем
|
||||
|
||||
Менеджер — списки с фильтрами. Сейчас они живут только в RAM: F5 всегда меню, повторный вход
|
||||
сбрасывает вкладки и запросы. Игрок сравнивает людей и соискателей; потерять «ученики 5А» на
|
||||
обновлении — дырка в уже живых экранах, не новая фича.
|
||||
|
||||
### Было / Стало / Почему
|
||||
|
||||
**Было.** SPA без адреса. `GameScreen.show` и `PeoplePanel.show` обнуляют вкладки, фильтры и
|
||||
выбор. Язык уже в `localStorage`; игровые часы — на сервере.
|
||||
|
||||
**Стало.** Query URL держит *где я*: школа, обзор/управление, карта/люди, выбранные комната и
|
||||
человек. `sessionStorage` по `schoolId` держит фильтры, поиски, сорт, страницу, вкладку карточки
|
||||
и класс сетки — и последний маршрут, чтобы вход с меню поднял то же место. F5 с `?school=`
|
||||
шлёт тот же `OpenSchool`, что карточка. Вход/выход — `pushState`; смена вкладки и фильтра —
|
||||
`replaceState`, чтобы «назад» не листал каждый клик.
|
||||
|
||||
**Почему.** Сервер не знает про вкладки; класть их в сейв — лишний HTTP. `localStorage` как у
|
||||
языка держал бы «5А» через месяц. URL без фильтров остаётся коротким и копируемым.
|
||||
|
||||
### Что видит игрок
|
||||
|
||||
F5 внутри школы — та же школа, те же вкладки и фильтры. Назад — меню. Снова открыть ту же
|
||||
школу — не сброс на карту. Гость не входит в управление по ссылке. Скорость часов, пауза,
|
||||
открытый пул соискателей и мастер создания не вспоминаются.
|
||||
|
||||
### Что не входит
|
||||
|
||||
Поиск по имени в списках, где его нет. Роутер-библиотека. Состояние на сервере. Бамп протокола.
|
||||
@@ -0,0 +1,26 @@
|
||||
Часть [Вне очереди](README.md). Соседей по папке не читать, если задача не про них.
|
||||
|
||||
# Что нового после входа
|
||||
|
||||
### Зачем
|
||||
|
||||
Альфа обновляется часто. Игрок не смотрит git: если с прошлого захода в этот браузер накатили
|
||||
другую сборку Server, один раз показать, что вошло в неё.
|
||||
|
||||
### Было / Стало / Почему
|
||||
|
||||
**Было.** Нет версии сборки на экране. Сессионная кука HttpOnly и про вход.
|
||||
|
||||
**Стало.** Сборка Server вшивает `HEAD` и `git log --first-parent`. `GET /api/changelog?since=`
|
||||
отдаёт текущий SHA и коммиты после якоря. Клиент держит `hschool.seen-rev` (год, `Path=/`,
|
||||
`SameSite=Lax`, не HttpOnly). Первый заход без куки окно не показывает — только запоминает
|
||||
текущий SHA. Окно — после входа, не при возврате из школы.
|
||||
|
||||
**Почему.** «Накатанный» — то, что в dll, а не грязный HEAD при `--no-build`. First-parent после
|
||||
`--no-ff` — это слитые фазы, не внутренняя нарезка ветки. `Mark phase N` оставляем в цепочке
|
||||
якорем, в список не рисуем: иначе кука на таком HEAD потеряла бы следующее слияние.
|
||||
|
||||
### Что не входит
|
||||
|
||||
Ручной `CHANGELOG.md`. Запись на пользователе в `users.json`. Вызов git из бегущего процесса.
|
||||
Бамп версии сокета. Окно внутри открытой школы.
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
> **Отменено в фазе 8.** Панель общих событий убрана с экрана: пока ленты событий нет, постоянно
|
||||
> пустая треть экрана мешала, и место отдано вкладкам «Карта» и «Люди». Решение записано в
|
||||
> [`../design/near-term.md`](../design/near-term.md); появится лента — вернётся и панель.
|
||||
> [`docs/design/01-shell/near-term.md`](../../design/01-shell/near-term.md); появится лента — вернётся и панель.
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
Индекс срезов: [`../README.md`](../README.md).
|
||||
|
||||
## Срез 1. Оболочка и карта
|
||||
|
||||
Дизайн закрыт: [`../design/near-term.md`](../../design/01-shell/near-term.md),
|
||||
[`../design/defs.md`](../../design/01-shell/defs.md),
|
||||
[`../design/runtime.md`](../../design/01-shell/runtime.md),
|
||||
[`../design/projects.md`](../../design/01-shell/projects.md).
|
||||
|
||||
Новых игровых фич в эти фазы не добавлять. 1 и 2 можно вести параллельно (клиент / сервер).
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [0. Убрать PixiJS](00-drop-pixi.md) | ✅ | Сцена не планируется |
|
||||
| [1. Оболочка менеджера](01-manager-shell.md) | ✅ | Панели с секциями среза, пока без данных |
|
||||
| [2. Работник школы и диск](02-school-worker.md) | ✅ | Поток + World + сейв — основа |
|
||||
| [3. Каталог def и карта](03-defs-map.md) | ✅ | JSONC, core, валидация раскладки |
|
||||
| [4. Моды и редактор в create](04-create-editor.md) | ✅ | Выбор модов, карта в POST, снимок при открытии |
|
||||
@@ -0,0 +1,42 @@
|
||||
# Журнал ревью
|
||||
|
||||
Сводка: [`../reviewed.md`](../reviewed.md). Индекс среза: [`README.md`](README.md).
|
||||
|
||||
## Срез 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,7 +2,7 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 3](03-defs-map.md)
|
||||
- [Фаза 3](../01-shell/03-defs-map.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
- [x] Тот же сид, карта и набор имён — ровно тот же ростер
|
||||
- [x] Тринадцатая семья не меняет, как разыграны первые двенадцать (фамилия, состав, имена).
|
||||
Класс ребёнка при этом меняется — места раздаются вперемешку по школе, иначе братья и
|
||||
сёстры всегда оказывались одноклассниками; см. [`../design/people.md`](../design/people.md)
|
||||
сёстры всегда оказывались одноклассниками; см. [`docs/design/02-people/people.md`](../../design/02-people/people.md)
|
||||
- [x] Фамилии, родовые формы и отчества внутри семьи согласованы
|
||||
- [x] Ученик с телосложением «полное» не получает высокую ловкость
|
||||
- [x] Все ученические места заполнены, все должности закрыты
|
||||
@@ -3,7 +3,7 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 6](06-people-generator.md)
|
||||
- [Фаза 2](02-school-worker.md)
|
||||
- [Фаза 2](../01-shell/02-school-worker.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 7](07-people-in-school.md)
|
||||
- [Фаза 1](01-manager-shell.md)
|
||||
- [Фаза 1](../01-shell/01-manager-shell.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
`TaskCompletionSource`, потому что нужды живые
|
||||
- [x] Панель «Люди» в оболочке менеджера: фильтры, сортируемые колонки, пейджер. Сделана
|
||||
**вкладкой рядом с картой**, а не нижним рядом — заодно с экрана ушла пустая панель
|
||||
событий из фазы 1; см. [`../design/people.md`](../design/people.md)
|
||||
событий из фазы 1; см. [`docs/design/02-people/people.md`](../../design/02-people/people.md)
|
||||
- [x] Строка списка — только лёгкие поля: ФИО, роль, класс или должность, возраст, пол
|
||||
- [x] Карточка: тело, навыки, черты, нужды, семья со ссылками на родных — по ссылке открывается
|
||||
карточка родственника
|
||||
@@ -0,0 +1,19 @@
|
||||
Индекс срезов: [`../README.md`](../README.md).
|
||||
|
||||
## Срез 2. Люди
|
||||
|
||||
Дизайн: [`../design/people.md`](../../design/02-people/people.md).
|
||||
|
||||
Школа наполняется людьми. Ученики, работники и родители существуют, показываются и обновляются
|
||||
раз в год — но **ничего не делают**: ни расписания, ни перемещений, ни влияния характеристик.
|
||||
|
||||
Фазы идут по порядку, кроме 8 и 9: обе зависят только от 7 и могут вестись параллельно
|
||||
(клиент / симуляция).
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [5. Дефы человека](05-people-defs.md) | ✅ | Навыки, черты, тело, нужды, наборы имён в каталоге |
|
||||
| [6. Библиотека генерации](06-people-generator.md) | ✅ | `HSchool.People`: семьи из карты и сида |
|
||||
| [7. Люди в школе](07-people-in-school.md) | ✅ | Сущности в `World`, ростер на диске, 11 кабинетов в `core` |
|
||||
| [8. Просмотр людей](08-people-browser.md) | ✅ | Панель со списком, фильтрами и карточкой |
|
||||
| [9. Годовой набор](09-yearly-intake.md) | ✅ | Первое сентября: переход, выпуск, набор |
|
||||
@@ -0,0 +1,44 @@
|
||||
# Журнал ревью
|
||||
|
||||
Сводка: [`../reviewed.md`](../reviewed.md). Индекс среза: [`README.md`](README.md).
|
||||
|
||||
## Срез 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/02-people/people.md`.
|
||||
- Выпуск старшей имеющейся, вместимость, семьи через поколения, reload после набора.
|
||||
|
||||
Дописано:
|
||||
|
||||
- `PeopleApiTests.ReloadAfterTheYearlyIntake_RestoresTheNewComposition` — ждёт 1 сентября и
|
||||
требует состав **после** набора, отличный от исходного (детерминизм от сида иначе скрыл бы
|
||||
потерянный файл).
|
||||
|
||||
Исправлено:
|
||||
|
||||
- `Card_IncludesFamilyAndLiveNeeds` брал `People[0]` и требовал двух родителей. Состав зависит
|
||||
от сида; на чистом клоне первый ученик иногда из неполной семьи. Теперь ищет ученика с матерью
|
||||
и проверяет диапазон.
|
||||
- `List_SortsBySurname` требовал ordinal-порядок, сервер ставит Ё на место Е. Совпадали, пока
|
||||
в `core` не было фамилий на Ё.
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 5](05-people-defs.md)
|
||||
- [Фаза 7](07-people-in-school.md)
|
||||
- [Фаза 5](../02-people/05-people-defs.md)
|
||||
- [Фаза 7](../02-people/07-people-in-school.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 10](10-subjects.md)
|
||||
- [Фаза 6](06-people-generator.md)
|
||||
- [Фаза 6](../02-people/06-people-generator.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 12](12-hiring-budget.md)
|
||||
- [Фаза 8](08-people-browser.md)
|
||||
- [Фаза 8](../02-people/08-people-browser.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
Индекс срезов: [`../README.md`](../README.md).
|
||||
|
||||
## Срез 3. Штат
|
||||
|
||||
Дизайн: [`../design/staffing.md`](../../design/03-staffing/staffing.md).
|
||||
|
||||
Первый срез, где игрок принимает решения. Школа открывается пустой: надо нанять людей из пула
|
||||
соискателей, раздать им предметы и уложиться в выделенную на месяц сумму. Уроков по-прежнему нет —
|
||||
предмет это запись в нагрузке, а не событие в кабинете.
|
||||
|
||||
Фазы идут строго по порядку: каждая опирается на данные предыдущей.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [10. Предметы и мебель](10-subjects.md) | ✅ | `SubjectDef`, одна учительская должность, кабинет как число мест |
|
||||
| [11. Пустая школа и пул](11-applicants.md) | ✅ | Школа без сотрудников, соискатели с запросом по зарплате |
|
||||
| [12. Наём и бюджет](12-hiring-budget.md) | ✅ | Наём, назначение предметов, предел фонда оплаты |
|
||||
| [13. Раздел «Управление»](13-management-tab.md) | ✅ | Деньги, соискатели, штат и назначения на экране |
|
||||
@@ -0,0 +1,44 @@
|
||||
# Журнал ревью
|
||||
|
||||
Сводка: [`../reviewed.md`](../reviewed.md). Индекс среза: [`README.md`](README.md).
|
||||
|
||||
## Срез 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, хотя клиент его шлёт.
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 10](10-subjects.md)
|
||||
- [Фаза 10](../03-staffing/10-subjects.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 14](14-school-calendar.md)
|
||||
- [Фаза 12](12-hiring-budget.md)
|
||||
- [Фаза 12](../03-staffing/12-hiring-budget.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 16](16-timetable-in-school.md)
|
||||
- [Фаза 13](13-management-tab.md)
|
||||
- [Фаза 13](../03-staffing/13-management-tab.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
Индекс срезов: [`../README.md`](../README.md).
|
||||
|
||||
## Срез 4. Расписание
|
||||
|
||||
Дизайн: [`../design/schedule.md`](../../design/04-schedule/schedule.md).
|
||||
|
||||
Часы учебного плана раскладываются по дням и кабинетам. Школа начинает жить по времени: видно,
|
||||
что идёт в комнате прямо сейчас. Люди при этом по-прежнему **не ходят** — они находятся там, где
|
||||
их застало расписание.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [14. Каркас дня и каникулы](14-school-calendar.md) | ✅ | Звонки, длина недели, каникулы |
|
||||
| [15. Планировщик](15-timetable-planner.md) | ✅ | Раскладка часов по слотам, четыре запрета |
|
||||
| [16. Расписание в школе](16-timetable-in-school.md) | ✅ | Сейв, снимок, «кто где сейчас» |
|
||||
| [17. Расписание на экране](17-timetable-screen.md) | ✅ | Скобки в дереве, сетка класса, расписание учителя |
|
||||
@@ -0,0 +1,40 @@
|
||||
# Журнал ревью
|
||||
|
||||
Сводка: [`../reviewed.md`](../reviewed.md). Индекс среза: [`README.md`](README.md).
|
||||
|
||||
## Срез 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/04-schedule/schedule.md` «панель локации из расписания» и «люди находятся по расписанию» помечены
|
||||
как отменённые срезом 5.
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 16](16-timetable-in-school.md)
|
||||
- [Фаза 16](../04-schedule/16-timetable-in-school.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
- [x] Стабильный порядок обхода людей — собственный список, а не порядок сущностей в Arch
|
||||
- [x] Адаптер в `HSchool.Simulation`: собирает значения из компонентов, зовёт библиотеку,
|
||||
записывает ответ обратно. Горячий путь — движение — границу не пересекает
|
||||
- [x] Ориентир в `AGENTS.md`, `docs/architecture.md` и `docs/design/projects.md` знает про новый
|
||||
- [x] Ориентир в `AGENTS.md`, `docs/architecture.md` и `docs/design/01-shell/projects.md` знает про новый
|
||||
проект
|
||||
- [x] Место, путь и назначение едут в файл часов; кого в файле нет, тот расставляется по
|
||||
обязанности
|
||||
@@ -3,7 +3,7 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 18](18-presence-walking.md)
|
||||
- [Фаза 17](17-timetable-screen.md)
|
||||
- [Фаза 17](../04-schedule/17-timetable-screen.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
Индекс срезов: [`../README.md`](../README.md).
|
||||
|
||||
## Срез 5. Жизнь школы
|
||||
|
||||
Дизайн: [`../design/ai.md`](../../design/05-ai/ai.md).
|
||||
|
||||
Люди начинают ходить и решать. Присутствие перестаёт вычисляться из расписания и становится
|
||||
состоянием: человек приходит утром, идёт коридором, может уйти с урока в туалет и вернуться.
|
||||
|
||||
Срез идёт **двумя этапами**, и между ними можно остановиться — школа останется целостной.
|
||||
|
||||
**Этап A — присутствие.** Люди ходят по обязанности; выбора у них ещё нет.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [18. Присутствие и ходьба](18-presence-walking.md) | ✅ | `HSchool.Ai`, место человека, маршруты, приход и уход |
|
||||
| [19. Присутствие на экране](19-presence-screen.md) | ✅ | Своё сообщение ~2 Гц, числа в дереве, статический снимок карты, пропуск пустого времени |
|
||||
|
||||
**Этап B — поведение.** Появляются нужды, действия и выбор между ними и обязанностью.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [20. Нужды и действия](20-needs-actions.md) | ✅ | `ActionDef` с полями, декей, восполнение |
|
||||
| [21. Выбор действия](21-decisions.md) | ✅ | Цели и веса, «дойти → сделать», уход с урока, рост навыка |
|
||||
@@ -0,0 +1,42 @@
|
||||
# Журнал ревью
|
||||
|
||||
Сводка: [`../reviewed.md`](../reviewed.md). Индекс среза: [`README.md`](README.md).
|
||||
|
||||
## Срез 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`, потом людей.
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 4](04-create-editor.md) — моды и каталог уже ездят в create
|
||||
- [Фаза 4](../01-shell/04-create-editor.md) — моды и каталог уже ездят в create
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
- [x] Разрешённый порядок виден: пишется в лог при старте школы и возвращается в ответе создания
|
||||
- [x] Сейв хранит **разрешённый** порядок паков, чтобы школа поднималась тем же каталогом
|
||||
- [x] Загрузчик пишет предупреждение, когда у конкретного def нет подписи в локали пака
|
||||
- [x] `docs/protocol.md` и [`../design/foundation.md`](../design/foundation.md) правятся тем же
|
||||
- [x] `docs/protocol.md` и [`docs/design/06-foundation/foundation.md`](../../design/06-foundation/foundation.md) правятся тем же
|
||||
коммитом, что и обработчики
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
@@ -18,7 +18,7 @@
|
||||
пока не выбран
|
||||
- [x] Пак едет в вывод сборки тестов теми же правилами, что и `core`
|
||||
- [x] Короткий `README.md` внутри пака: что где лежит и как добавить своё
|
||||
- [x] Ориентир в [`../design/defs.md`](../design/defs.md) показывает на него как на образец
|
||||
- [x] Ориентир в [`docs/design/01-shell/defs.md`](../../design/01-shell/defs.md) показывает на него как на образец
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
+2
-2
@@ -2,11 +2,11 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 20](20-needs-actions.md) — `BehaviorDef` уже есть
|
||||
- [Фаза 20](../05-ai/20-needs-actions.md) — `BehaviorDef` уже есть
|
||||
|
||||
## Зачем
|
||||
|
||||
[`../design/ai.md`](../design/ai.md) обещает: числа поведения — деф правил, как `StaffingDef` у
|
||||
[`docs/design/05-ai/ai.md`](../../design/05-ai/ai.md) обещает: числа поведения — деф правил, как `StaffingDef` у
|
||||
штата. Порог нужды и разброс на дорогу туда уехали, а веса целей остались константами в коде.
|
||||
Пока они там, мод, меняющий одно число, вынужден быть форком.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 7](07-people-in-school.md) — сид уже лежит в файле людей
|
||||
- [Фаза 7](../02-people/07-people-in-school.md) — сид уже лежит в файле людей
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
- [x] Существующие школы не меняются: сид читается из файла людей, как и сейчас
|
||||
- [x] Тесты хоста, которым нужен предсказуемый состав, передают сид явно, а не полагаются на
|
||||
порядок создания
|
||||
- [x] `docs/protocol.md` и [`../design/people.md`](../design/people.md) правятся тем же коммитом
|
||||
- [x] `docs/protocol.md` и [`docs/design/02-people/people.md`](../../design/02-people/people.md) правятся тем же коммитом
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 2](02-school-worker.md) — сейв и дев-поверхность уже есть
|
||||
- [Фаза 2](../01-shell/02-school-worker.md) — сейв и дев-поверхность уже есть
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 13](13-management-tab.md), [Фаза 17](17-timetable-screen.md) — самые крупные экраны уже есть
|
||||
- [Фаза 13](../03-staffing/13-management-tab.md), [Фаза 17](../04-schedule/17-timetable-screen.md) — самые крупные экраны уже есть
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
Индекс срезов: [`../README.md`](../README.md).
|
||||
|
||||
## Срез 6. Фундамент
|
||||
|
||||
Дизайн: [`../design/foundation.md`](../../design/06-foundation/foundation.md).
|
||||
|
||||
Срез без единой новой кнопки для игрока. Мод становится настоящим объектом, числа поведения
|
||||
уезжают из кода в данные, сид перестаёт быть идентификатором, у сейва появляется версия, а то,
|
||||
что ревью ловило глазами, начинает ловиться тестом. Всё здесь дёшево поодиночке и заметно
|
||||
упрощает следующие срезы.
|
||||
|
||||
Порядок свободный: 25, 26 и 27 ни от чего не зависят, 23 стоит на 22. Начинать разумно с 25 —
|
||||
она страхует всё остальное.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [22. Удостоверение пака](22-mod-identity.md) | ✅ | Название, версия, зависимости и порядок загрузки |
|
||||
| [23. Пример мода](23-example-pack.md) | ✅ | Настоящая папка вместо документов в памяти |
|
||||
| [24. Числа поведения](24-behavior-numbers.md) | ✅ | Веса целей в `BehaviorDef`, а не в коде |
|
||||
| [25. Золотые файлы](25-golden-fixtures.md) | ✅ | Отпечаток ростера, старый сейв, кривая голода, нехватка учителей |
|
||||
| [26. Свой сид](26-school-seed.md) | ✅ | Состав школы перестаёт зависеть от порядка создания |
|
||||
| [27. Версия сейва и дамп](27-serviceability.md) | ✅ | Формат читается, внутрь школы можно заглянуть |
|
||||
| [28. Тесты экранов](28-screen-tests.md) | ✅ | DOM-окружение и логика клиента под тестом |
|
||||
@@ -0,0 +1,44 @@
|
||||
# Журнал ревью
|
||||
|
||||
Сводка: [`../reviewed.md`](../reviewed.md). Индекс среза: [`README.md`](README.md).
|
||||
|
||||
## Срез 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/06-foundation/foundation.md`: порядок загрузки — не алфавит; «почему сейчас» про веса в `Decision.cs`
|
||||
устарел.
|
||||
|
||||
Замечено рядом:
|
||||
|
||||
- `Dump_ReturnsPeopleNodesAndTimetable` принимает `NodeId is not null || Needs.Count > 0`.
|
||||
Нужды есть у всех, так что узлы на кампусе не проверяются. Усиливать до явки — срез 5.
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 5](05-people-defs.md)
|
||||
- [Фаза 26](26-school-seed.md)
|
||||
- [Фаза 5](../02-people/05-people-defs.md)
|
||||
- [Фаза 26](../06-foundation/26-school-seed.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 3](03-defs-map.md)
|
||||
- [Фаза 3](../01-shell/03-defs-map.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
ошибка
|
||||
- [x] Вещь с несколькими `layers` допустима (платье). Пересечение слоёв у двух надетых сразу
|
||||
валидатор не проверяет — это состояние человека, не каталога
|
||||
- [x] Ваниль по [`../design/inventory.md`](../design/inventory.md): бельё, носки, низы, верх,
|
||||
- [x] Ваниль по [`docs/design/07-inventory/inventory.md`](../../design/07-inventory/inventory.md): бельё, носки, низы, верх,
|
||||
свитер, куртка/пальто/шуба, обувь, шапка, аксессуары, платье, форма физкультуры,
|
||||
портфель, учебник, телефон, бутылка
|
||||
- [x] Палитра цветов и локали ru/en на все новые def
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
- [Фаза 29](29-country.md)
|
||||
- [Фаза 30](30-apparel-defs.md)
|
||||
- [Фаза 6](06-people-generator.md)
|
||||
- [Фаза 6](../02-people/06-people-generator.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 29](29-country.md)
|
||||
- [Фаза 20](20-needs-actions.md)
|
||||
- [Фаза 20](../05-ai/20-needs-actions.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
|
||||
- [Фаза 31](31-dress-generator.md)
|
||||
- [Фаза 32](32-weather-warmth.md)
|
||||
- [Фаза 11](11-applicants.md)
|
||||
- [Фаза 11](../03-staffing/11-applicants.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 31](31-dress-generator.md)
|
||||
- [Фаза 18](18-presence-walking.md)
|
||||
- [Фаза 18](../05-ai/18-presence-walking.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
- [Фаза 32](32-weather-warmth.md)
|
||||
- [Фаза 33](33-lockers-technician.md)
|
||||
- [Фаза 34](34-wear-home.md)
|
||||
- [Фаза 21](21-decisions.md)
|
||||
- [Фаза 21](../05-ai/21-decisions.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
+2
-2
@@ -3,8 +3,8 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 31](31-dress-generator.md)
|
||||
- [Фаза 8](08-people-browser.md)
|
||||
- [Фаза 28](28-screen-tests.md)
|
||||
- [Фаза 8](../02-people/08-people-browser.md)
|
||||
- [Фаза 28](../06-foundation/28-screen-tests.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
- [Фаза 35](35-appropriateness.md)
|
||||
- [Фаза 36](36-person-card-tabs.md)
|
||||
- [Фаза 13](13-management-tab.md)
|
||||
- [Фаза 13](../03-staffing/13-management-tab.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
- [x] В «Управлении» вкладка **«Правила»** рядом со штатом, не новый верхний режим
|
||||
- [x] Четыре комбобокса: форма учеников, цвет учеников, форма сотрудников, цвет сотрудников.
|
||||
Значения — как в [`../design/inventory.md`](../design/inventory.md)
|
||||
Значения — как в [`docs/design/07-inventory/inventory.md`](../../design/07-inventory/inventory.md)
|
||||
- [x] Сохранение пишет завтрашнее правило; на экране видно, что действует сегодня и что
|
||||
вступит завтра
|
||||
- [x] HTTP: чтение текущих+отложенных, запись отложенных. Отказ по неизвестному коду правила —
|
||||
@@ -0,0 +1,41 @@
|
||||
Индекс срезов: [`../README.md`](../README.md).
|
||||
|
||||
## Срез 7. Одежда, вещи и климат
|
||||
|
||||
Дизайн: [`../design/inventory.md`](../../design/07-inventory/inventory.md).
|
||||
|
||||
Человек одевается, несёт вещи, мёрзнет и переодевается. Игрок смотрит гардероб и выбирает
|
||||
правила школы; надевает не он. Погода видна у часов. Срез можно остановить после этапа A —
|
||||
школа останется одетой, даже если климат ещё не живой.
|
||||
|
||||
**Этап A — данные и гардероб.** Страна вместо набора имён, вещи умеют быть одеждой, генератор
|
||||
одевает.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [29. Страна](29-country.md) | ✅ | `CountryDef`, create выбирает страну, климат-пресет от сида |
|
||||
| [30. Слои и палитра](30-apparel-defs.md) | ✅ | Поля `ThingDef`, `ColorDef`, ванильная одежда и ноша |
|
||||
| [31. Генератор одевает](31-dress-generator.md) | ✅ | Гардероб на человеке, ноша-число, `people.json` |
|
||||
|
||||
29 и 30 независимы; 31 стоит на обеих.
|
||||
|
||||
**Этап B — климат.** Улица, нужда тепла, техник, раздевалки.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [32. Погода и тепло](32-weather-warmth.md) | ✅ | Пресет крутит улицу, кадр часов, нужда, две черты |
|
||||
| [33. Техник и шкафчики](33-lockers-technician.md) | ✅ | Комната техника, две раздевалки, раздача шкафчиков |
|
||||
|
||||
32 стоит на 29; 33 — на 31 и 32.
|
||||
|
||||
**Этап C — жизнь одежды.** Износ, переодевание, экран.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [34. Износ и дом](34-wear-home.md) | ✅ | Прочность, утренняя замена, из ветхого не выходят |
|
||||
| [35. Уместность](35-appropriateness.md) | ✅ | Правила, переодевание действием, физкультура |
|
||||
| [36. Вкладки карточки](36-person-card-tabs.md) | ✅ | Одежда, ноша, сейчас + история за сегодня |
|
||||
| [37. Правила школы](37-school-rules.md) | ✅ | Вкладка в «Управлении», четыре комбобокса, с завтра |
|
||||
|
||||
34 стоит на 31; 35 — на 32–34; 36 — на 31 и может идти параллельно с 35 в части вкладок одежды,
|
||||
история — после 35; 37 стоит на 35 и 36.
|
||||
@@ -0,0 +1,100 @@
|
||||
# Журнал ревью
|
||||
|
||||
Сводка: [`../reviewed.md`](../reviewed.md). Индекс среза: [`README.md`](README.md).
|
||||
|
||||
## Срез 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/07-inventory/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-сборка не падала.
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 1](01-manager-shell.md)
|
||||
- [Фаза 2](02-school-worker.md)
|
||||
- [Фаза 28](28-screen-tests.md)
|
||||
- [Фаза 1](../01-shell/01-manager-shell.md)
|
||||
- [Фаза 2](../01-shell/02-school-worker.md)
|
||||
- [Фаза 28](../06-foundation/28-screen-tests.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 38](38-session.md)
|
||||
- [Фаза 13](13-management-tab.md)
|
||||
- [Фаза 13](../03-staffing/13-management-tab.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 2](02-school-worker.md)
|
||||
- [Фаза 20](20-needs-actions.md)
|
||||
- [Фаза 2](../01-shell/02-school-worker.md)
|
||||
- [Фаза 20](../05-ai/20-needs-actions.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
Индекс срезов: [`../README.md`](../README.md).
|
||||
|
||||
## Срез 8. Сессия и темп
|
||||
|
||||
Дизайн: [`../design/session.md`](../../design/08-session/session.md).
|
||||
|
||||
Несколько браузеров на одном сервере: общий пароль альфы, имя игрока, свои школы и чужие
|
||||
отдельным списком. Часы становятся смотрибельными — минута за секунду, на высоких скоростях
|
||||
тяжёлые системы тикают реже. Срез можно остановить после этапа B: мультиплеер жив, даже если
|
||||
темп ещё старый.
|
||||
|
||||
**Этап A — кто вошёл.** Пароль, имя, кука.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [38. Сессия](38-session.md) | ✅ | Пароль альфы, имя, кука, сокет после входа |
|
||||
|
||||
**Этап B — чьи школы.** Хозяин, слоты, гость только смотрит.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [39. Хозяин школы](39-school-owners.md) | ✅ | `owner`, 2 слота на игрока, мои / чужие, гость без управления |
|
||||
|
||||
39 стоит на 38.
|
||||
|
||||
**Этап C — темп.** Не зависит от A/B, можно вести параллельно с 38.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [40. Темп часов](40-clock-tempo.md) | ✅ | ×1 = минута/с, кнопки ×½ ×1 ×2 ×5 ×10, страйд тяжёлых систем |
|
||||
@@ -0,0 +1,34 @@
|
||||
# Журнал ревью
|
||||
|
||||
Сводка: [`../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` живут в списке меню.
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 8](08-people-browser.md)
|
||||
- [Фаза 36](36-person-card-tabs.md)
|
||||
- [Фаза 8](../02-people/08-people-browser.md)
|
||||
- [Фаза 36](../07-inventory/36-person-card-tabs.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 41](41-opinions.md)
|
||||
- [Фаза 21](21-decisions.md)
|
||||
- [Фаза 31](31-dress-generator.md)
|
||||
- [Фаза 21](../05-ai/21-decisions.md)
|
||||
- [Фаза 31](../07-inventory/31-dress-generator.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 42](42-talk-circles.md)
|
||||
- [Фаза 19](19-presence-screen.md)
|
||||
- [Фаза 19](../05-ai/19-presence-screen.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 42](42-talk-circles.md)
|
||||
- [Фаза 37](37-school-rules.md)
|
||||
- [Фаза 34](34-wear-home.md)
|
||||
- [Фаза 37](../07-inventory/37-school-rules.md)
|
||||
- [Фаза 34](../07-inventory/34-wear-home.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 42](42-talk-circles.md)
|
||||
- [Фаза 23](23-example-pack.md)
|
||||
- [Фаза 23](../06-foundation/23-example-pack.md)
|
||||
- [Фаза 41](41-opinions.md)
|
||||
|
||||
## Зачем
|
||||
@@ -0,0 +1,41 @@
|
||||
Индекс срезов: [`../README.md`](../README.md).
|
||||
|
||||
## Срез 9. Общение и романтический пак
|
||||
|
||||
Дизайн: [`../design/social.md`](../../design/09-social/social.md).
|
||||
|
||||
Разговор становится кружком, мнение — числом, вражда — ссорой. Романтика не ваниль: отдельный
|
||||
пак. Срез можно остановить после этапа B — школа болтает, даже если драк и пака ещё нет.
|
||||
|
||||
**Этап A — мнения.** Число и вкладка.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [41. Мнения и «Связи»](41-opinions.md) | ✅ | −100…100, семья-старт, вкладка карточки |
|
||||
|
||||
**Этап B — разговоры.** Кружок, язык, шёпот.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [42. Темы и кружки](42-talk-circles.md) | ✅ | `TopicDef`, 2–4 человека, учительская, телефон, вместе |
|
||||
| [43. Шёпот и учитель](43-whisper.md) | ✅ | Шёпот на уроке, шанс оборвать, разговор после звонка |
|
||||
|
||||
42 стоит на 41; 43 — на 42.
|
||||
|
||||
**Этап C — конфликт и экран.**
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [44. Ссора и драка](44-quarrel-fight.md) | 🔄 | Жертва задиры, заступник, извинение, двор/физкультура |
|
||||
| [45. Кружок в присутствии](45-presence-talk.md) | ✅ | Id участников и темы в кадре, протокол +1 |
|
||||
|
||||
44 и 45 стоят на 42, можно параллельно.
|
||||
|
||||
**Этап D — правила, дом, пак.**
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [46. Политика речи и дом](46-speech-home.md) | ⬜ | Комбобоксы речи с завтра; утреннее семейное событие |
|
||||
| [47. Пак romance](47-romance-pack.md) | ✅ | Ориентация, симпатия, пара 18+, патч тем |
|
||||
|
||||
46 стоит на 37 и 42; 47 — на 42 и 23. `example` не трогать.
|
||||
+2
-2
@@ -6,14 +6,14 @@
|
||||
|
||||
## Зачем
|
||||
|
||||
Инвариант 4 и таблица в [`projects.md`](../design/projects.md) должны ломаться одним красным
|
||||
Инвариант 4 и таблица в [`projects.md`](../../design/01-shell/projects.md) должны ломаться одним красным
|
||||
тестом, а не «забыли дописать пятую копию». Content и Protocol сейчас молчат.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] Проект `tests/HSchool.Architecture.Tests` в solution, `IsTestProject`, без AppHost и без
|
||||
нового NuGet. Ссылки на Protocol, Content, People, Schedule, Ai, Simulation
|
||||
- [ ] Тесты ссылок: каждая библиотека из таблицы в [`craft.md`](../design/craft.md) — этап A
|
||||
- [ ] Тесты ссылок: каждая библиотека из таблицы в [`craft.md`](../../design/10-craft/craft.md) — этап A
|
||||
- [ ] Тесты исходников: в `src/HSchool.{Protocol,Content,People,Schedule,Ai,Simulation}` нет
|
||||
`DateTime.Now` / `DateTime.UtcNow`
|
||||
- [ ] Удалить копипасты `Assembly_DoesNotReference*` и `Sources_DoNotUseWallClock` из People,
|
||||
@@ -0,0 +1,31 @@
|
||||
Индекс срезов: [`../README.md`](../README.md).
|
||||
|
||||
## Срез 10. Ремесло
|
||||
|
||||
Дизайн: [`../design/craft.md`](../../design/10-craft/craft.md).
|
||||
|
||||
Срез без новой кнопки. Слои ловятся одним тестовым проектом, клиентский `npm test` гоняет tsc,
|
||||
работник и карточка режутся по швам, дамп проверяет явку. После этапа A школа целая, даже если
|
||||
файлы ещё толстые. Не ждёт фазы 44 и 46.
|
||||
|
||||
Порядок свободный: 56, 57 и 59 ни от чего не зависят, 58 удобнее после 57. Начинать разумно с
|
||||
56 или 57.
|
||||
|
||||
**Этап A — страховка.** Слои и tsc.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [56. Слои одной пачкой](56-architecture-tests.md) | ⬜ | Один проект вместо четырёх копипаст |
|
||||
| [57. tsc в npm test](57-client-typecheck.md) | ⬜ | Дубликат ключа красный без `npm run build` |
|
||||
|
||||
**Этап B — горячие точки.** Поведение то же.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [58. SchoolWorker и карточка](58-worker-card-split.md) | ⬜ | partial / модули по швам, один поток |
|
||||
|
||||
**Этап C — дамп.**
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [59. Дамп проверяет узлы](59-dump-nodes.md) | ⬜ | После найма в дампе есть `NodeId` |
|
||||
+22
-274
@@ -1,276 +1,24 @@
|
||||
# Фазы
|
||||
|
||||
Индекс. Статус: ⬜ не начата, 🔄 в работе, ✅ готова.
|
||||
|
||||
Регрессии уже сделанного — [`../bugs/README.md`](../bugs/README.md), не сюда.
|
||||
|
||||
## Срез 1. Оболочка и карта
|
||||
|
||||
Дизайн закрыт: [`../design/near-term.md`](../design/near-term.md),
|
||||
[`../design/defs.md`](../design/defs.md),
|
||||
[`../design/runtime.md`](../design/runtime.md),
|
||||
[`../design/projects.md`](../design/projects.md).
|
||||
|
||||
Новых игровых фич в эти фазы не добавлять. 1 и 2 можно вести параллельно (клиент / сервер).
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [0. Убрать PixiJS](00-drop-pixi.md) | ✅ | Сцена не планируется |
|
||||
| [1. Оболочка менеджера](01-manager-shell.md) | ✅ | Панели с секциями среза, пока без данных |
|
||||
| [2. Работник школы и диск](02-school-worker.md) | ✅ | Поток + World + сейв — основа |
|
||||
| [3. Каталог def и карта](03-defs-map.md) | ✅ | JSONC, core, валидация раскладки |
|
||||
| [4. Моды и редактор в create](04-create-editor.md) | ✅ | Выбор модов, карта в POST, снимок при открытии |
|
||||
|
||||
## Срез 2. Люди
|
||||
|
||||
Дизайн: [`../design/people.md`](../design/people.md).
|
||||
|
||||
Школа наполняется людьми. Ученики, работники и родители существуют, показываются и обновляются
|
||||
раз в год — но **ничего не делают**: ни расписания, ни перемещений, ни влияния характеристик.
|
||||
|
||||
Фазы идут по порядку, кроме 8 и 9: обе зависят только от 7 и могут вестись параллельно
|
||||
(клиент / симуляция).
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [5. Дефы человека](05-people-defs.md) | ✅ | Навыки, черты, тело, нужды, наборы имён в каталоге |
|
||||
| [6. Библиотека генерации](06-people-generator.md) | ✅ | `HSchool.People`: семьи из карты и сида |
|
||||
| [7. Люди в школе](07-people-in-school.md) | ✅ | Сущности в `World`, ростер на диске, 11 кабинетов в `core` |
|
||||
| [8. Просмотр людей](08-people-browser.md) | ✅ | Панель со списком, фильтрами и карточкой |
|
||||
| [9. Годовой набор](09-yearly-intake.md) | ✅ | Первое сентября: переход, выпуск, набор |
|
||||
|
||||
## Срез 3. Штат
|
||||
|
||||
Дизайн: [`../design/staffing.md`](../design/staffing.md).
|
||||
|
||||
Первый срез, где игрок принимает решения. Школа открывается пустой: надо нанять людей из пула
|
||||
соискателей, раздать им предметы и уложиться в выделенную на месяц сумму. Уроков по-прежнему нет —
|
||||
предмет это запись в нагрузке, а не событие в кабинете.
|
||||
|
||||
Фазы идут строго по порядку: каждая опирается на данные предыдущей.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [10. Предметы и мебель](10-subjects.md) | ✅ | `SubjectDef`, одна учительская должность, кабинет как число мест |
|
||||
| [11. Пустая школа и пул](11-applicants.md) | ✅ | Школа без сотрудников, соискатели с запросом по зарплате |
|
||||
| [12. Наём и бюджет](12-hiring-budget.md) | ✅ | Наём, назначение предметов, предел фонда оплаты |
|
||||
| [13. Раздел «Управление»](13-management-tab.md) | ✅ | Деньги, соискатели, штат и назначения на экране |
|
||||
|
||||
## Срез 4. Расписание
|
||||
|
||||
Дизайн: [`../design/schedule.md`](../design/schedule.md).
|
||||
|
||||
Часы учебного плана раскладываются по дням и кабинетам. Школа начинает жить по времени: видно,
|
||||
что идёт в комнате прямо сейчас. Люди при этом по-прежнему **не ходят** — они находятся там, где
|
||||
их застало расписание.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [14. Каркас дня и каникулы](14-school-calendar.md) | ✅ | Звонки, длина недели, каникулы |
|
||||
| [15. Планировщик](15-timetable-planner.md) | ✅ | Раскладка часов по слотам, четыре запрета |
|
||||
| [16. Расписание в школе](16-timetable-in-school.md) | ✅ | Сейв, снимок, «кто где сейчас» |
|
||||
| [17. Расписание на экране](17-timetable-screen.md) | ✅ | Скобки в дереве, сетка класса, расписание учителя |
|
||||
|
||||
## Срез 5. Жизнь школы
|
||||
|
||||
Дизайн: [`../design/ai.md`](../design/ai.md).
|
||||
|
||||
Люди начинают ходить и решать. Присутствие перестаёт вычисляться из расписания и становится
|
||||
состоянием: человек приходит утром, идёт коридором, может уйти с урока в туалет и вернуться.
|
||||
|
||||
Срез идёт **двумя этапами**, и между ними можно остановиться — школа останется целостной.
|
||||
|
||||
**Этап A — присутствие.** Люди ходят по обязанности; выбора у них ещё нет.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [18. Присутствие и ходьба](18-presence-walking.md) | ✅ | `HSchool.Ai`, место человека, маршруты, приход и уход |
|
||||
| [19. Присутствие на экране](19-presence-screen.md) | ✅ | Своё сообщение ~2 Гц, числа в дереве, статический снимок карты, пропуск пустого времени |
|
||||
|
||||
**Этап B — поведение.** Появляются нужды, действия и выбор между ними и обязанностью.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [20. Нужды и действия](20-needs-actions.md) | ✅ | `ActionDef` с полями, декей, восполнение |
|
||||
| [21. Выбор действия](21-decisions.md) | ✅ | Цели и веса, «дойти → сделать», уход с урока, рост навыка |
|
||||
|
||||
## Срез 6. Фундамент
|
||||
|
||||
Дизайн: [`../design/foundation.md`](../design/foundation.md).
|
||||
|
||||
Срез без единой новой кнопки для игрока. Мод становится настоящим объектом, числа поведения
|
||||
уезжают из кода в данные, сид перестаёт быть идентификатором, у сейва появляется версия, а то,
|
||||
что ревью ловило глазами, начинает ловиться тестом. Всё здесь дёшево поодиночке и заметно
|
||||
упрощает следующие срезы.
|
||||
|
||||
Порядок свободный: 25, 26 и 27 ни от чего не зависят, 23 стоит на 22. Начинать разумно с 25 —
|
||||
она страхует всё остальное.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [22. Удостоверение пака](22-mod-identity.md) | ✅ | Название, версия, зависимости и порядок загрузки |
|
||||
| [23. Пример мода](23-example-pack.md) | ✅ | Настоящая папка вместо документов в памяти |
|
||||
| [24. Числа поведения](24-behavior-numbers.md) | ✅ | Веса целей в `BehaviorDef`, а не в коде |
|
||||
| [25. Золотые файлы](25-golden-fixtures.md) | ✅ | Отпечаток ростера, старый сейв, кривая голода, нехватка учителей |
|
||||
| [26. Свой сид](26-school-seed.md) | ✅ | Состав школы перестаёт зависеть от порядка создания |
|
||||
| [27. Версия сейва и дамп](27-serviceability.md) | ✅ | Формат читается, внутрь школы можно заглянуть |
|
||||
| [28. Тесты экранов](28-screen-tests.md) | ✅ | DOM-окружение и логика клиента под тестом |
|
||||
|
||||
## Срез 7. Одежда, вещи и климат
|
||||
|
||||
Дизайн: [`../design/inventory.md`](../design/inventory.md).
|
||||
|
||||
Человек одевается, несёт вещи, мёрзнет и переодевается. Игрок смотрит гардероб и выбирает
|
||||
правила школы; надевает не он. Погода видна у часов. Срез можно остановить после этапа A —
|
||||
школа останется одетой, даже если климат ещё не живой.
|
||||
|
||||
**Этап A — данные и гардероб.** Страна вместо набора имён, вещи умеют быть одеждой, генератор
|
||||
одевает.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [29. Страна](29-country.md) | ✅ | `CountryDef`, create выбирает страну, климат-пресет от сида |
|
||||
| [30. Слои и палитра](30-apparel-defs.md) | ✅ | Поля `ThingDef`, `ColorDef`, ванильная одежда и ноша |
|
||||
| [31. Генератор одевает](31-dress-generator.md) | ✅ | Гардероб на человеке, ноша-число, `people.json` |
|
||||
|
||||
29 и 30 независимы; 31 стоит на обеих.
|
||||
|
||||
**Этап B — климат.** Улица, нужда тепла, техник, раздевалки.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [32. Погода и тепло](32-weather-warmth.md) | ✅ | Пресет крутит улицу, кадр часов, нужда, две черты |
|
||||
| [33. Техник и шкафчики](33-lockers-technician.md) | ✅ | Комната техника, две раздевалки, раздача шкафчиков |
|
||||
|
||||
32 стоит на 29; 33 — на 31 и 32.
|
||||
|
||||
**Этап C — жизнь одежды.** Износ, переодевание, экран.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [34. Износ и дом](34-wear-home.md) | ✅ | Прочность, утренняя замена, из ветхого не выходят |
|
||||
| [35. Уместность](35-appropriateness.md) | ✅ | Правила, переодевание действием, физкультура |
|
||||
| [36. Вкладки карточки](36-person-card-tabs.md) | ✅ | Одежда, ноша, сейчас + история за сегодня |
|
||||
| [37. Правила школы](37-school-rules.md) | ✅ | Вкладка в «Управлении», четыре комбобокса, с завтра |
|
||||
|
||||
34 стоит на 31; 35 — на 32–34; 36 — на 31 и может идти параллельно с 35 в части вкладок одежды,
|
||||
история — после 35; 37 стоит на 35 и 36.
|
||||
|
||||
## Срез 8. Сессия и темп
|
||||
|
||||
Дизайн: [`../design/session.md`](../design/session.md).
|
||||
|
||||
Несколько браузеров на одном сервере: общий пароль альфы, имя игрока, свои школы и чужие
|
||||
отдельным списком. Часы становятся смотрибельными — минута за секунду, на высоких скоростях
|
||||
тяжёлые системы тикают реже. Срез можно остановить после этапа B: мультиплеер жив, даже если
|
||||
темп ещё старый.
|
||||
|
||||
**Этап A — кто вошёл.** Пароль, имя, кука.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [38. Сессия](38-session.md) | ✅ | Пароль альфы, имя, кука, сокет после входа |
|
||||
|
||||
**Этап B — чьи школы.** Хозяин, слоты, гость только смотрит.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [39. Хозяин школы](39-school-owners.md) | ✅ | `owner`, 2 слота на игрока, мои / чужие, гость без управления |
|
||||
|
||||
39 стоит на 38.
|
||||
|
||||
**Этап C — темп.** Не зависит от A/B, можно вести параллельно с 38.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [40. Темп часов](40-clock-tempo.md) | ✅ | ×1 = минута/с, кнопки ×½ ×1 ×2 ×5 ×10, страйд тяжёлых систем |
|
||||
|
||||
## Срез 9. Общение и романтический пак
|
||||
|
||||
Дизайн: [`../design/social.md`](../design/social.md).
|
||||
|
||||
Разговор становится кружком, мнение — числом, вражда — ссорой. Романтика не ваниль: отдельный
|
||||
пак. Срез можно остановить после этапа B — школа болтает, даже если драк и пака ещё нет.
|
||||
|
||||
**Этап A — мнения.** Число и вкладка.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [41. Мнения и «Связи»](41-opinions.md) | ✅ | −100…100, семья-старт, вкладка карточки |
|
||||
|
||||
**Этап B — разговоры.** Кружок, язык, шёпот.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [42. Темы и кружки](42-talk-circles.md) | ✅ | `TopicDef`, 2–4 человека, учительская, телефон, вместе |
|
||||
| [43. Шёпот и учитель](43-whisper.md) | ✅ | Шёпот на уроке, шанс оборвать, разговор после звонка |
|
||||
|
||||
42 стоит на 41; 43 — на 42.
|
||||
|
||||
**Этап C — конфликт и экран.**
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [44. Ссора и драка](44-quarrel-fight.md) | 🔄 | Жертва задиры, заступник, извинение, двор/физкультура |
|
||||
| [45. Кружок в присутствии](45-presence-talk.md) | ✅ | Id участников и темы в кадре, протокол +1 |
|
||||
|
||||
44 и 45 стоят на 42, можно параллельно.
|
||||
|
||||
**Этап D — правила, дом, пак.**
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [46. Политика речи и дом](46-speech-home.md) | ⬜ | Комбобоксы речи с завтра; утреннее семейное событие |
|
||||
| [47. Пак romance](47-romance-pack.md) | ✅ | Ориентация, симпатия, пара 18+, патч тем |
|
||||
|
||||
46 стоит на 37 и 42; 47 — на 42 и 23. `example` не трогать.
|
||||
|
||||
## Срез 10. Ремесло
|
||||
|
||||
Дизайн: [`../design/craft.md`](../design/craft.md).
|
||||
|
||||
Срез без новой кнопки. Слои ловятся одним тестовым проектом, клиентский `npm test` гоняет tsc,
|
||||
работник и карточка режутся по швам, дамп проверяет явку. После этапа A школа целая, даже если
|
||||
файлы ещё толстые. Не ждёт фазы 44 и 46.
|
||||
|
||||
Порядок свободный: 56, 57 и 59 ни от чего не зависят, 58 удобнее после 57. Начинать разумно с
|
||||
56 или 57.
|
||||
|
||||
**Этап A — страховка.** Слои и tsc.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [56. Слои одной пачкой](56-architecture-tests.md) | ⬜ | Один проект вместо четырёх копипаст |
|
||||
| [57. tsc в npm test](57-client-typecheck.md) | ⬜ | Дубликат ключа красный без `npm run build` |
|
||||
|
||||
**Этап B — горячие точки.** Поведение то же.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [58. SchoolWorker и карточка](58-worker-card-split.md) | ⬜ | partial / модули по швам, один поток |
|
||||
|
||||
**Этап C — дамп.**
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [59. Дамп проверяет узлы](59-dump-nodes.md) | ⬜ | После найма в дампе есть `NodeId` |
|
||||
|
||||
## Вне очереди
|
||||
|
||||
Дизайн: [`../design/off-queue.md`](../design/off-queue.md).
|
||||
|
||||
Склейка уже живых систем и мелкий DX, не новый кусок игры. Номера не спорят с именованными
|
||||
срезами. После каждой игровой фазы школа целая. 50–52 стоят на 48; 53 — на 18 и 32, можно
|
||||
параллельно с 48. 49, 54 и 55 от них не зависят. Баг в уже сделанном —
|
||||
[`../bugs/README.md`](../bugs/README.md).
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [48. Учитель в кабинете](48-lesson-teacher-present.md) | ✅ | Нет учителя на месте — нет роста навыка |
|
||||
| [49. Пропуск сборки при запуске](49-skip-stale-build.md) | ✅ | `run-aspire.cmd` не гоняет MSBuild, если dll свежие |
|
||||
| [50. Навык учителя](50-teacher-skill-gain.md) | ✅ | Соискатель 78 учит лучше, чем 41 |
|
||||
| [51. Тепло на уроке](51-warmth-lesson.md) | ✅ | Замёрзший учится хуже, как голодный |
|
||||
| [52. Учебник на уроке](52-textbook-lesson.md) | ✅ | Нет в сумке — половинный рост |
|
||||
| [53. Погода на дороге](53-weather-commute.md) | ✅ | Снег и дождь добавляют минуты к приходу |
|
||||
| [54. Что нового](54-whats-new.md) | ✅ | После входа — окно коммитов с прошлого визита |
|
||||
| [55. Состояние экрана](55-view-state.md) | ✅ | F5 и переходы не сбрасывают школу, вкладки и фильтры |
|
||||
Каталог срезов. Статусы и таблицы фаз — в индексе среза, не здесь.
|
||||
⬜ не начата, 🔄 в работе, ✅ готова.
|
||||
|
||||
Регрессии — [`../bugs/README.md`](../bugs/README.md). Сводка ревью — [`reviewed.md`](reviewed.md);
|
||||
журнал среза — `reviewed.md` в его папке.
|
||||
|
||||
Агенту: это оглавление. Не читай индексы всех срезов. Номер фазы → `docs/phases/*/<NN>-*.md`.
|
||||
Срез → папка и её `README.md`. Дизайн → `docs/design/<та же папка>/`.
|
||||
|
||||
| Срез | Фазы | Индекс | Дизайн |
|
||||
| --- | --- | --- | --- |
|
||||
| 1. Оболочка и карта | 0–4 | [01-shell](01-shell/README.md) | [01-shell](../design/01-shell/) |
|
||||
| 2. Люди | 5–9 | [02-people](02-people/README.md) | [people](../design/02-people/people.md) |
|
||||
| 3. Штат | 10–13 | [03-staffing](03-staffing/README.md) | [staffing](../design/03-staffing/staffing.md) |
|
||||
| 4. Расписание | 14–17 | [04-schedule](04-schedule/README.md) | [schedule](../design/04-schedule/schedule.md) |
|
||||
| 5. Жизнь школы | 18–21 | [05-ai](05-ai/README.md) | [ai](../design/05-ai/ai.md) |
|
||||
| 6. Фундамент | 22–28 | [06-foundation](06-foundation/README.md) | [foundation](../design/06-foundation/foundation.md) |
|
||||
| 7. Одежда, вещи и климат | 29–37 | [07-inventory](07-inventory/README.md) | [inventory](../design/07-inventory/inventory.md) |
|
||||
| 8. Сессия и темп | 38–40 | [08-session](08-session/README.md) | [session](../design/08-session/session.md) |
|
||||
| 9. Общение и романтический пак | 41–47 | [09-social](09-social/README.md) | [social](../design/09-social/social.md) |
|
||||
| 10. Ремесло | 56–59 | [10-craft](10-craft/README.md) | [craft](../design/10-craft/craft.md) |
|
||||
| Вне очереди | 48–55 | [off-queue](off-queue/README.md) | [off-queue](../design/off-queue/) |
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 21](21-decisions.md)
|
||||
- [Фаза 18](18-presence-walking.md)
|
||||
- [Фаза 21](../05-ai/21-decisions.md)
|
||||
- [Фаза 18](../05-ai/18-presence-walking.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 48](48-lesson-teacher-present.md)
|
||||
- [Фаза 12](12-hiring-budget.md)
|
||||
- [Фаза 12](../03-staffing/12-hiring-budget.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 48](48-lesson-teacher-present.md)
|
||||
- [Фаза 32](32-weather-warmth.md)
|
||||
- [Фаза 32](../07-inventory/32-weather-warmth.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
- [x] Лог `lesson-cold` один раз на предмет в сутки, если на уроке, который иначе учил,
|
||||
тепло ниже `BehaviorDef.needThreshold`; `thingDef` — предмет
|
||||
- [x] `docs/protocol.md` — тип лога
|
||||
- [x] В [`inventory.md`](../design/inventory.md) убрать «тепло урок не штрафует»: стало рядом
|
||||
- [x] В [`inventory.md`](../../design/07-inventory/inventory.md) убрать «тепло урок не штрафует»: стало рядом
|
||||
с голодом
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
@@ -3,7 +3,7 @@
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 48](48-lesson-teacher-present.md)
|
||||
- [Фаза 35](35-appropriateness.md)
|
||||
- [Фаза 35](../07-inventory/35-appropriateness.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 18](18-presence-walking.md)
|
||||
- [Фаза 32](32-weather-warmth.md)
|
||||
- [Фаза 18](../05-ai/18-presence-walking.md)
|
||||
- [Фаза 32](../07-inventory/32-weather-warmth.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
- [x] `DayPlans.Build` принимает уже посчитанные лишние минуты; `HSchool.Ai` не знает осадков
|
||||
- [x] Симуляция при сборке плана дня подставляет минуты из текущей улицы
|
||||
- [x] Лог на каждого не пишем — опоздание видно местом
|
||||
- [x] В [`inventory.md`](../design/inventory.md) поправка: погода влияет на дорогу, не только
|
||||
- [x] В [`inventory.md`](../../design/07-inventory/inventory.md) поправка: погода влияет на дорогу, не только
|
||||
на переодевание
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
@@ -17,7 +17,7 @@
|
||||
- [x] Subject `Mark phase N…` в окне нет; в цепочке якоря они остаются
|
||||
- [x] Кука `hschool.seen-rev` (не HttpOnly, не сессионная): первый заход молча запоминает HEAD
|
||||
- [x] Модалка только после `ensureSession` (вход и повторный вход после logout), не с меню школы
|
||||
- [x] [`protocol.md`](../protocol.md) HTTP, версию сокета не бампить
|
||||
- [x] [`protocol.md`](../../protocol.md) HTTP, версию сокета не бампить
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
@@ -20,7 +20,7 @@ F5 и выход в меню не должны выкидывать игрока
|
||||
последний `mode`/`tab`/выбор — чтобы повторный вход с меню поднял то же место
|
||||
- [x] `history.pushState` только вход и выход; смена вкладки и фильтров — `replaceState`.
|
||||
«Назад» из школы — меню. Протокол, HTTP и сейв не трогать; роутер не добавлять
|
||||
- [x] Подписи через `t(...)` не нужны: новых строк нет. `docs/design/off-queue.md` и эта фаза —
|
||||
- [x] Подписи через `t(...)` не нужны: новых строк нет. `docs/design/off-queue/view-state.md` и эта фаза —
|
||||
в том же коммите, что и код
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
@@ -0,0 +1,21 @@
|
||||
Индекс срезов: [`../README.md`](../README.md).
|
||||
|
||||
## Вне очереди
|
||||
|
||||
Дизайн: [`../design/off-queue.md`](../../design/off-queue/README.md).
|
||||
|
||||
Склейка уже живых систем и мелкий DX, не новый кусок игры. Номера не спорят с именованными
|
||||
срезами. После каждой игровой фазы школа целая. 50–52 стоят на 48; 53 — на 18 и 32, можно
|
||||
параллельно с 48. 49, 54 и 55 от них не зависят. Баг в уже сделанном —
|
||||
[`../bugs/README.md`](../../bugs/README.md).
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [48. Учитель в кабинете](48-lesson-teacher-present.md) | ✅ | Нет учителя на месте — нет роста навыка |
|
||||
| [49. Пропуск сборки при запуске](49-skip-stale-build.md) | ✅ | `run-aspire.cmd` не гоняет MSBuild, если dll свежие |
|
||||
| [50. Навык учителя](50-teacher-skill-gain.md) | ✅ | Соискатель 78 учит лучше, чем 41 |
|
||||
| [51. Тепло на уроке](51-warmth-lesson.md) | ✅ | Замёрзший учится хуже, как голодный |
|
||||
| [52. Учебник на уроке](52-textbook-lesson.md) | ✅ | Нет в сумке — половинный рост |
|
||||
| [53. Погода на дороге](53-weather-commute.md) | ✅ | Снег и дождь добавляют минуты к приходу |
|
||||
| [54. Что нового](54-whats-new.md) | ✅ | После входа — окно коммитов с прошлого визита |
|
||||
| [55. Состояние экрана](55-view-state.md) | ✅ | F5 и переходы не сбрасывают школу, вкладки и фильтры |
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user