From 254c43535e254d33c4f7c6fdbf0334dfc9d8dac1 Mon Sep 17 00:00:00 2001 From: Leonid Pershin Date: Thu, 20 Aug 2026 08:21:14 +0300 Subject: [PATCH] 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 --- AGENTS.md | 1 + docs/design/off-queue.md | 90 ++++++++++++++++++++++++ docs/phases/48-lesson-teacher-present.md | 43 +++++++++++ docs/phases/49-teacher-skill-gain.md | 34 +++++++++ docs/phases/50-warmth-lesson.md | 37 ++++++++++ docs/phases/51-textbook-lesson.md | 38 ++++++++++ docs/phases/52-weather-commute.md | 38 ++++++++++ docs/phases/README.md | 15 ++++ 8 files changed, 296 insertions(+) create mode 100644 docs/design/off-queue.md create mode 100644 docs/phases/48-lesson-teacher-present.md create mode 100644 docs/phases/49-teacher-skill-gain.md create mode 100644 docs/phases/50-warmth-lesson.md create mode 100644 docs/phases/51-textbook-lesson.md create mode 100644 docs/phases/52-weather-commute.md diff --git a/AGENTS.md b/AGENTS.md index f9adb9c..fa1c387 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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 38–39 | | 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 41–47 | +| lesson consequences (teacher present, skill, warmth, textbook, weather commute) | [`docs/design/off-queue.md`](docs/design/off-queue.md) — phases 48–52 | | a task that is not in any slice | `.claude/skills/side-work` — discuss, document in «Вне очереди» or a new named slice, then implement | ## Commands diff --git a/docs/design/off-queue.md b/docs/design/off-queue.md new file mode 100644 index 0000000..f0661fc --- /dev/null +++ b/docs/design/off-queue.md @@ -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`; лога нет | diff --git a/docs/phases/48-lesson-teacher-present.md b/docs/phases/48-lesson-teacher-present.md new file mode 100644 index 0000000..4a5d233 --- /dev/null +++ b/docs/phases/48-lesson-teacher-present.md @@ -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` проходит + +## Стоп + +Не масштабировать рост навыком учителя. Не трогать тепло, учебник и дорогу. Не бампить +протокол. Не писать лог учителю. diff --git a/docs/phases/49-teacher-skill-gain.md b/docs/phases/49-teacher-skill-gain.md new file mode 100644 index 0000000..7bca179 --- /dev/null +++ b/docs/phases/49-teacher-skill-gain.md @@ -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` проходит + +## Стоп + +Не вводить оценки. Не менять формулу зарплаты. Не трогать тепло и учебник. diff --git a/docs/phases/50-warmth-lesson.md b/docs/phases/50-warmth-lesson.md new file mode 100644 index 0000000..d6432d6 --- /dev/null +++ b/docs/phases/50-warmth-lesson.md @@ -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` проходит + +## Стоп + +Не болеть от промокания. Не штрафовать ходьбу. Не трогать учебник. diff --git a/docs/phases/51-textbook-lesson.md b/docs/phases/51-textbook-lesson.md new file mode 100644 index 0000000..93bc7da --- /dev/null +++ b/docs/phases/51-textbook-lesson.md @@ -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` проходит + +## Стоп + +Не заставлять идти за учебником отдельной целью. Не замедлять ходьбу перегрузом. Не тратить +деньги на замену. diff --git a/docs/phases/52-weather-commute.md b/docs/phases/52-weather-commute.md new file mode 100644 index 0000000..a946a8a --- /dev/null +++ b/docs/phases/52-weather-commute.md @@ -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` проходит + +## Стоп + +Не мочить одежду. Не пропускать день из-за мороза. Не бампить кадр часов. diff --git a/docs/phases/README.md b/docs/phases/README.md index ea891ae..e6385f0 100644 --- a/docs/phases/README.md +++ b/docs/phases/README.md @@ -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) | ⬜ | Снег и дождь добавляют минуты к приходу |