# Вне очереди Задачи, которых нет в нумерованных срезах. Сюда не дописывают срез 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 и сейв не трогаем.