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:
Leonid Pershin
2026-08-20 12:26:13 +03:00
parent 12cc36b4dd
commit a37a5eb82d
101 changed files with 1015 additions and 921 deletions
+21
View File
@@ -0,0 +1,21 @@
# Фаза 0. Убрать PixiJS
## Зависимости
Нет.
## Зачем
`pixi.js` стоит в клиенте «для вида внутри школы». Ближайший вид — DOM-менеджер, не сцена.
Держать пакет без импорта нельзя: это противоречит бюджету зависимостей в `AGENTS.md`.
## Задачи
- [x] Удалить `pixi.js` из `src/HSchool.Client/package.json` и обновить lockfile
- [x] Убрать обещание Pixi из `README.md` и `AGENTS.md` (клиент: Vite + TypeScript + DOM)
## Критерий готовности
- `npm --prefix src/HSchool.Client run build` проходит
- в клиентском коде нет импорта `pixi.js`
- в рабочих соглашениях больше нет формулировки «Pixi стоит на будущий вид»
+32
View File
@@ -0,0 +1,32 @@
# Фаза 1. Оболочка менеджера на экране школы
## Зависимости
- [Фаза 0](00-drop-pixi.md) — логично закрыть первой
## Зачем
Сейчас внутри школы только часы. Нужны места под дерево, события и локацию — с теми секциями,
которые уже закрыты в срезе, даже если списки пустые.
## Задачи
- [x] Три области: дерево карты, общие события, выбранная локация — плюс часы и скорость
- [x] События: заголовок и пустое состояние, без выдуманных записей
- [x] Локация: секции имя, предметы, персонажи, действия на месте, должности — пустые, не ломаются
- [x] Клик по дереву переключает панель локации на клиенте (пока узлы-заглушки или пустое дерево)
- [x] Переключение языка обновляет подписи панелей и пустых состояний (`t(...)`)
> **Отменено в фазе 8.** Панель общих событий убрана с экрана: пока ленты событий нет, постоянно
> пустая треть экрана мешала, и место отдано вкладкам «Карта» и «Люди». Решение записано в
> [`docs/design/01-shell/near-term.md`](../../design/01-shell/near-term.md); появится лента — вернётся и панель.
## Критерий готовности
- Школу можно открыть, часы и пауза работают как раньше
- Видны пустые панели среза
- `npm --prefix src/HSchool.Client test` и `run build` проходят
## Стоп
Не наполнять персонажами и событиями. Данные — с фазы 4.
+32
View File
@@ -0,0 +1,32 @@
# Фаза 2. Работник школы и диск
## Зависимости
Нет по коду клиента. Ломает текущий общий `GameLoopService`.
## Зачем
Основа среза: каждая школа — свой поток, свой Arch `World`, свой файл. Пока ещё можно обойтись
часами без карты — сейв расширится в фазе 3, формат закладывать расширяемым.
## Задачи
- [x] Супервизор держит ящики `id →` очередь; не трогает `World`
- [x] У школы выделенный поток (`LongRunning`), свой таймер фиксированного шага, свой `World`
- [x] Команды create/delete/open/close/running/speed идут в ящик, не в общий цикл
- [x] Меню читает опубликованные снимки, как сейчас, без блокировки работника
- [x] Кадры часов по-прежнему из работника в outbox соединения
- [x] Сейв на диск: имя, id, часы, running, speedIndex; запись при create/delete, shutdown, редкий снимок часов (не 20 Гц)
- [x] Старт процесса поднимает школы с диска
- [x] Обновить инвариант в `AGENTS.md`: трогает школу только её работник
- [x] Тесты AppHost: create → рестарт хоста (или явный reload) → школа на месте с тем же временем с разумной погрешностью снимка
## Критерий готовности
- `dotnet test` проходит
- Две школы тикают независимо (пауза одной не останавливает часы другой — уже так по симуляции; поток не должен это ломать)
- После перезапуска сервера список школ не пустой, если их создали
## Стоп
Не грузить defs в этой фазе. Не писать файл каждый тик.
+34
View File
@@ -0,0 +1,34 @@
# Фаза 3. Каталог def и карта
## Зависимости
- [Фаза 2](02-school-worker.md) — каталог и раскладка живут у работника школы
## Зачем
Типы в JSONC, инстанс карты в школе, валидация связности. Без этого нечему редактировать в create.
## Задачи
- [x] Проект `HSchool.Content` (+ тесты): JSONC, defs, локали, граф карты, валидация. Не Arch, не ASP.NET
- [x] Загрузчик пачки документов (сервер потом подставит папки `mods/`)
- [x] `core` всегда первый; дальше моды по списку; повтор `defName` / ключа локали — последний победил, warning в лог
- [x] Резолв ссылок `ThingDef.actions`, слотов RoomDef после чтения всего набора
- [x] Карта-инстанс: двор (TerritoryDef) всегда есть; здания (BuildingDef), этажи (FloorDef + id), помещения, двусторонние рёбра
- [x] Валидация: неизвестный def, ребро в никуда, несвязный граф, изолированный узел
- [x] Пустая комната допустима; должности для панели — из def узла, если они там есть
- [x] Каталог замораживается на работнике при create/load; сейв хранит id модов и раскладку, не развёрнутый каталог
- [x] Нет папки мода из сейва — школу не стартовать, файл не удалять, в лог
- [x] Обновить ориентир в `AGENTS.md` (куда класть defs)
- [x] Наследование: `parent`, `abstract`, замена полей, запрет цикла и чужого вида, abstract нельзя на карту
- [x] Патчи из `patches/`: add / replace / remove по JSON Pointer; неизвестный op или нет target — ошибка каталога
- [x] Тесты Content: фикстуры JSONC, last-wins, parent/abstract, патч add в actions, связность, пустая комната, одна комната без двора — отказ
## Критерий готовности
- `dotnet test` покрывает загрузчик и валидацию без хоста (`HSchool.Content.Tests`)
- Ванильная раскладка `mods/core/maps/default.jsonc` проходит валидацию
## Стоп
Не UI редактора. Не исполнение ActionDef. Не xpath и не новые op сверх add/replace/remove.
+34
View File
@@ -0,0 +1,34 @@
# Фаза 4. Моды и редактор в create
## Зависимости
- [Фаза 1](01-manager-shell.md)
- [Фаза 3](03-defs-map.md)
## Зачем
Игрок выбирает моды, правит или стирает дефолтную карту, создаёт школу. Внутри школы дерево и
панель локации читают снимок, не заглушки.
## Задачи
- [x] `GET` списка модов: `core` как обязательный, остальные папки `mods/`
- [x] `GET` каталога с `?lang=ru|en` (типы + локали) для `core` + выбранных id
- [x] Hello несёт тот же locale; снимок карты при OpenSchool на этом языке
- [x] `POST /api/schools` принимает доп. моды и раскладку; сервер всегда подставляет `core` первым и валидирует
- [x] В диалоге создания: чекбоксы модов (`core` нельзя снять), редактор дерева/связей/слотов или сброс к дефолту
- [x] При `OpenSchool` — один снимок карты (дерево + локации: имя, предметы, пустые персонажи и действия на месте, должности). Не на каждый клик, не 20 Гц
- [x] Клиент фильтрует выбранный узел; часы как сейчас
- [x] Протокол/HTTP описать в `docs/protocol.md` в том же коммите, что кодек
- [x] Тесты API: create с картой, отказ на дырявый граф, открытие отдаёт снимок
## Критерий готовности
- Создать школу с ванильной картой и с упрощённой своей
- Открыть: дерево кликается, локация показывает имя/предметы/должности, персонажи и действия на месте пустые, события пустые
- Перезапуск сервера поднимает эту школу с той же раскладкой
- `dotnet test` и клиентский `npm test` / `build` проходят
## Стоп
Не приказы «сесть». Не лента событий. Не `OpenLocation` на сервер.
+18
View File
@@ -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, снимок при открытии |
+42
View File
@@ -0,0 +1,42 @@
# Журнал ревью
Сводка: [`../reviewed.md`](../reviewed.md). Индекс среза: [`README.md`](README.md).
## Срез 1. Оболочка и карта
- **Фазы:** 04
- **Проверен на:** `418a4ea`, 2026-08-20
- **Пути:** `src/HSchool.Client`, `src/HSchool.Protocol`, `src/HSchool.Content`,
`src/HSchool.Server/Game`, `src/HSchool.Server/Api/ModEndpoints.cs`,
`src/HSchool.Server/Api/SchoolEndpoints.cs`, `src/HSchool.Server/Net`,
`tests/HSchool.Content.Tests`, `tests/HSchool.Protocol.Tests`,
`tests/HSchool.AppHost.Tests/SchoolApiTests.cs`, `tests/HSchool.AppHost.Tests/GameSocketTests.cs`
- **Итог:** обещания фаз 0–4 целы; дописаны 3 теста; протокол v7 в трёх местах
Что подтверждено:
- PixiJS нет; дерево карты, пять секций локации, клиентский фильтр, `localize()`. Оболочка —
вкладки Карта/Люди, не три панели; отказ от ленты событий записан в фазе 1 и в `design/near-term.md`.
- `SchoolWorker``LongRunning`, свой `World`, аккумулятор с потолком 5. Супервизор таблицу
держит и `World` не трогает. Сейв на create/shutdown/`SaveIntervalSeconds`;
`ReloadFromDisk_RestoresAPausedClock`, `PausingOneSchool_DoesNotStopAnother`.
- Восемь тестов каталога/карты в `HSchool.Content.Tests`. Ванильная раскладка валидна.
Пропавшая папка мода не стартует школу и файл не трогает.
- `GET /api/mods`, каталог, create с картой и модами, снимок при OpenSchool. `core` в диалоге
создания нельзя снять. Кодек, `protocol.ts` и `docs/protocol.md` описывают один `MapSnapshot`.
- `modal.ts` резолвит промис явно; `.dialog--screen``height: fit-content`;
`DefaultStartDate` UTC; `MapSnapshotSize` от сообщения; outbox `DropOldest`;
`WaitToReadAsync` переносится между итерациями; меню патчит `card.update`.
- Родной язык — HTTP/JSON без бампа протокола. Старый сейв без поля берёт первый язык набора,
не бросает кубик (`ReloadWithoutASavedPick_TakesTheFirstLanguageInsteadOfRolling`).
Дописано:
- `SchoolApiTests.Catalog_WithAnUnknownMod_IsRejected`
- `SchoolApiTests.ModId_ThatEscapesTheModsFolder_IsRejectedOnBothEndpoints`
- `SkillGrantTests.ReloadWithoutASavedPick_TakesTheFirstLanguageInsteadOfRolling`
Исправлено:
- Два поля `speedIndex` в клиентском `School` (`api.ts`) — артефакт мержа фазы 26; vitest не
ловил, `npm run build` падал с TS2300.