Document off-queue lesson coherence (phases 48-52).

Teacher presence, teacher skill, warmth, textbooks and weather commute are already visible numbers that do not affect the lesson or the walk to school.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-20 08:21:14 +03:00
co-authored by Cursor
parent 9d96108516
commit 254c43535e
8 changed files with 296 additions and 0 deletions
+1
View File
@@ -24,6 +24,7 @@ way; this file is *how to work in them*.
| login, who owns a school, watching others | [`docs/design/session.md`](docs/design/session.md) — slice 8, phases 3839 |
| clock speed buttons and high-speed stride | `src/HSchool.Simulation/ClockSpeed.cs` **and** [`docs/design/session.md`](docs/design/session.md) — phase 40 |
| talks, opinions, fights, romance pack | [`docs/design/social.md`](docs/design/social.md) — slice 9, phases 4147 |
| lesson consequences (teacher present, skill, warmth, textbook, weather commute) | [`docs/design/off-queue.md`](docs/design/off-queue.md) — phases 4852 |
| a task that is not in any slice | `.claude/skills/side-work` — discuss, document in «Вне очереди» or a new named slice, then implement |
## Commands
+90
View File
@@ -0,0 +1,90 @@
# Вне очереди
Задачи, которых нет в нумерованных срезах. Сюда не дописывают срез 9 и не заводят срез 10:
это склейка уже живых систем, после любой фазы школа целая.
Люди: [`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`; лога нет |
+43
View File
@@ -0,0 +1,43 @@
# Фаза 48. Учитель в кабинете
## Зависимости
- [Фаза 21](21-decisions.md)
- [Фаза 18](18-presence-walking.md)
## Зачем
Ученик в кабинете больше не качает навык в пустоту. Нет учителя на месте — нет роста.
## Задачи
- [ ] `LessonLearningSystem` растёт навык, только если назначенный учитель стоит в
`lesson.RoomId`: на кампусе, путь пуст, остаток минут 0
- [ ] Нет человека с `TeacherId` в мире — как отсутствующий
- [ ] Действие учителя урок не отменяет
- [ ] Формула `LessonLearning.Gain` не меняется
- [ ] Лог ученика `lesson-no-teacher` один раз на предмет в сутки, не каждый тик; `thingDef`
предмет; подпись из каталога
- [ ] `docs/protocol.md` — новый `type` у HTTP лога, без бампа сокета
- [ ] Фикстуры, где учитель был строкой `t1` вне ростера, нанимают живого человека — иначе
существующий тест роста навыка зелёный впустую
## Тесты, без которых фаза не закрыта
- [ ] Ученик и учитель стоят в кабинете → навык за урок вырос
- [ ] Ученик в кабинете, учитель в другом узле → навык не вырос
- [ ] Учитель идёт по коридору в этот кабинет → пока идёт, роста нет
- [ ] Нет человека с id учителя → роста нет
- [ ] За урок без учителя в логе ученика одна строка `lesson-no-teacher`, не по числу тиков
- [ ] Голодный по-прежнему учится хуже сытого, когда учитель на месте
## Критерий готовности
- Учитель ушёл в туалет посреди математики — класс в кабинете есть, навык за эти минуты не
ползёт
- `dotnet test` проходит
## Стоп
Не масштабировать рост навыком учителя. Не трогать тепло, учебник и дорогу. Не бампить
протокол. Не писать лог учителю.
+34
View File
@@ -0,0 +1,34 @@
# Фаза 49. Навык учителя на уроке
## Зависимости
- [Фаза 48](48-lesson-teacher-present.md)
- [Фаза 12](12-hiring-budget.md)
## Зачем
Соискатель с математикой 78 перестаёт отличаться от 41 только зарплатой.
## Задачи
- [ ] `LessonLearning.TeacherFactor` — та же кривая, что `NeedFactor`: навык 0 → 0.25, 100 → 1
- [ ] Навык учителя — среднее его значений по `SubjectDef.skills`; нет ключа — `Range.Min`
- [ ] `Gain` умножает на этот фактор; учитель в кабинете по-прежнему обязателен (фаза 48)
- [ ] Числа кривой в коде рядом с нуждой, не новый экран и не сейв
- [ ] Лог не пишем: рост тише — это и есть сигнал
## Тесты, без которых фаза не закрыта
- [ ] Учитель с навыком 20 даёт меньший прирост, чем с 80, при том же ученике и голоде
- [ ] Предмет с несколькими скиллами берёт среднее, а не первый попавшийся в словаре
- [ ] Нет ключа навыка у учителя — подставляется минимум шкалы, рост не падает в ноль
- [ ] Учителя нет в кабинете — по-прежнему нулевой рост, фактор не спасает
## Критерий готовности
- Два учителя математики в тестовой школе: слабый класс растёт заметно медленнее
- `dotnet test` проходит
## Стоп
Не вводить оценки. Не менять формулу зарплаты. Не трогать тепло и учебник.
+37
View File
@@ -0,0 +1,37 @@
# Фаза 50. Тепло на уроке
## Зависимости
- [Фаза 48](48-lesson-teacher-present.md)
- [Фаза 32](32-weather-warmth.md)
## Зачем
Замёрзший сидит на уроке так же, как голодный: полоска уже есть, рост её должен чувствовать.
## Задачи
- [ ] `Gain` умножает `NeedFactor(голод) × NeedFactor(тепло)`
- [ ] Нет нужды `Warmth` в каталоге — множитель тепла 1, голод как сейчас
- [ ] Лог `lesson-cold` один раз на предмет в сутки, если на уроке, который иначе учил,
тепло ниже `BehaviorDef.needThreshold`; `thingDef` — предмет
- [ ] `docs/protocol.md` — тип лога
- [ ] В [`inventory.md`](../design/inventory.md) убрать «тепло урок не штрафует»: стало рядом
с голодом
## Тесты, без которых фаза не закрыта
- [ ] Тепло 0.1 и голод 1 → меньший прирост, чем оба по 1
- [ ] Тепло 1 и голод 0.1 → как нынешний голодный, тепло не «вылечивает»
- [ ] Нет `Warmth` в каталоге — голодный тест фазы 21 по-прежнему зелёный
- [ ] За урок на холоде одна строка лога, не по числу тиков
- [ ] Учителя нет в кабинете — лога холода нет (урок не учил)
## Критерий готовности
- Январь без техника: полоска тепла падает, навык за тот же урок растёт медленнее, чем в мае
- `dotnet test` проходит
## Стоп
Не болеть от промокания. Не штрафовать ходьбу. Не трогать учебник.
+38
View File
@@ -0,0 +1,38 @@
# Фаза 51. Учебник на уроке
## Зависимости
- [Фаза 48](48-lesson-teacher-present.md)
- [Фаза 35](35-appropriateness.md)
## Зачем
Утренний `RepackBag` уже кладёт учебники сегодняшних предметов в сумку. Урок начинает это
проверять.
## Задачи
- [ ] Рост урока полный, только если в **сумке** есть экземпляр с `subject` этого предмета
- [ ] Шкафчик и дом не считаются: ученик в кабинете
- [ ] Нет учебника — множитель `BehaviorDef.lessonNoTextbookFactor`, ваниль 0.5
- [ ] Валидатор: число 0–1
- [ ] Лог `lesson-no-textbook` один раз на предмет в сутки; `thingDef` — предмет
- [ ] `docs/protocol.md` — тип лога
## Тесты, без которых фаза не закрыта
- [ ] Учебник математики в сумке → полный рост (при учителе на месте)
- [ ] Тот же учебник в шкафчике или дома → рост как с коэффициентом 0.5
- [ ] Учебник другого предмета в сумке не закрывает этот урок
- [ ] Одна строка лога за сутки на предмет, не по числу тиков
- [ ] Пак без поля — 0.5, каталог не падает
## Критерий готовности
- Слабая переноска, учебник остался дома — на уроке растут хуже одноклассника с книгой
- `dotnet test` проходит
## Стоп
Не заставлять идти за учебником отдельной целью. Не замедлять ходьбу перегрузом. Не тратить
деньги на замену.
+38
View File
@@ -0,0 +1,38 @@
# Фаза 52. Погода на дороге
## Зависимости
- [Фаза 18](18-presence-walking.md)
- [Фаза 32](32-weather-warmth.md)
## Зачем
В январе опаздывают чаще, чем в мае. Черта уже двигает запас на дорогу; осадки — тоже.
## Задачи
- [ ] `BehaviorDef.commuteRainMinutes` и `commuteSnowMinutes`; ваниль 3 и 6
- [ ] Валидатор: не отрицательные
- [ ] `DayPlans.Build` принимает уже посчитанные лишние минуты; `HSchool.Ai` не знает осадков
- [ ] Симуляция при сборке плана дня подставляет минуты из текущей улицы
- [ ] Лог на каждого не пишем — опоздание видно местом
- [ ] В [`inventory.md`](../design/inventory.md) поправка: погода влияет на дорогу, не только
на переодевание
## Тесты, без которых фаза не закрыта
- [ ] Снег → `AppearAt` раньше на `commuteSnowMinutes` относительно ясного того же дня
(тот же человек, сид, дата без осадков)
- [ ] Дождь → на `commuteRainMinutes`
- [ ] Ясно → минуты как сейчас, только черты и бросок
- [ ] Пак без полей — 0 лишних минут, каталог не падает
- [ ] Тот же сид и снег → тот же `AppearAt`
## Критерий готовности
- Снежным утром класс наполняется позже, чем ясным; ленивый по-прежнему ближе к звонку
- `dotnet test` проходит
## Стоп
Не мочить одежду. Не пропускать день из-за мороза. Не бампить кадр часов.
+15
View File
@@ -222,3 +222,18 @@
| [47. Пак romance](47-romance-pack.md) | ⬜ | Ориентация, симпатия, пара 18+, патч тем |
46 стоит на 37 и 42; 47 — на 42 и 23. `example` не трогать.
## Вне очереди
Дизайн: [`../design/off-queue.md`](../design/off-queue.md).
Склейка уже живых систем, не новый кусок игры. Номера не спорят со срезом 10. После каждой
фазы школа целая. 49, 50 и 51 стоят на 48; 52 — на 18 и 32, можно параллельно с 48.
| Фаза | Статус | Зачем |
| --- | --- | --- |
| [48. Учитель в кабинете](48-lesson-teacher-present.md) | ⬜ | Нет учителя на месте — нет роста навыка |
| [49. Навык учителя](49-teacher-skill-gain.md) | ⬜ | Соискатель 78 учит лучше, чем 41 |
| [50. Тепло на уроке](50-warmth-lesson.md) | ⬜ | Замёрзший учится хуже, как голодный |
| [51. Учебник на уроке](51-textbook-lesson.md) | ⬜ | Нет в сумке — половинный рост |
| [52. Погода на дороге](52-weather-commute.md) | ⬜ | Снег и дождь добавляют минуты к приходу |