Files
h-school/docs/design/off-queue.md
T

121 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Вне очереди
Задачи, которых нет в нумерованных срезах. Сюда не дописывают срез 9 и не заводят срез 10:
склейка уже живых систем и мелкий 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 и сейв не
трогаем.