Merge main into review/slice-7bc-climate-wear; journal 32-37.
Integrate stage A review from main; resolve reviewed.md; fix dressRulesPanel unused import, managementPanel test, PortraitApiTests URL.
This commit is contained in:
@@ -0,0 +1,299 @@
|
||||
# Общение, отношения и романтический пак
|
||||
|
||||
Договорённость на срез после сессии/темпа, не текущий код.
|
||||
Люди: [`people.md`](people.md). ИИ: [`ai.md`](ai.md). Одежда (уместность как образец):
|
||||
[`inventory.md`](inventory.md). Моды: [`defs.md`](defs.md), [`foundation.md`](foundation.md).
|
||||
|
||||
У человека появляется, **с кем** он говорит и **что** о нём думают другие. Нужда «общение» уже
|
||||
есть, действие `Chat` уже есть — но это соло в коридоре. Срез делает разговор кружком, тему —
|
||||
дефом, мнение — числом, вражду — ссорой и редкой дракой. Игрок это **смотрит**. Романтика не
|
||||
ваниль: отдельный пак, который ещё и проверяет, что контентный мод на живой дороге работает.
|
||||
|
||||
Срез отвечает на вопросы «кто кому друг», «о чём болтают» и «что меняет пак». Настроения-нужды,
|
||||
приказов директора и секса нет.
|
||||
|
||||
## Что меняется в уже принятом
|
||||
|
||||
| Было | Стало | Почему |
|
||||
| --- | --- | --- |
|
||||
| `Chat` — один человек стоит в коридоре | Кружок 2–4 в одном узле, одна тема | Иначе общение не общение |
|
||||
| Семья на карточке — только родство | Плюс число мнения; вкладка «Связи» | Родители по умолчанию не ноль |
|
||||
| Конфликтов нет (`ai.md`) | Ссора и редкая драка без травм | Вражда должна быть видна, не только −40 в JSON |
|
||||
| `example` — единственный не-core пак | Рядом контентный `romance` | Скучный образец не доказывает темы, ориентацию и патч `Chat` |
|
||||
| Присутствие: id, узел, идёт/стоит | Плюс кружок (id участников + тема) | «Говорит с Машей о футболе» в локации |
|
||||
| «Правила» — только одежда | Плюс политика речи | Уместность тем — тот же жест, что дресс-код |
|
||||
|
||||
## Этап A — мнения и темы
|
||||
|
||||
### Мнение
|
||||
|
||||
У упорядоченной пары `(A → B)` одно число **−100…100**. Несимметрично: A может любить B, B —
|
||||
терпеть A. Ноль не храним. Пороги и подписи — в `BehaviorDef`, не в UI:
|
||||
|
||||
знакомые / приятели / друзья / близкие друзья на плюсе; натянуто / неприязнь / враги на минусе.
|
||||
|
||||
Семья даёт **стартовое** смещение при генерации (числа тоже в данных):
|
||||
|
||||
| Связь | Типичный старт |
|
||||
| --- | --- |
|
||||
| Родитель → ребёнок и обратно | сильно плюс |
|
||||
| Братья и сёстры | плюс слабее |
|
||||
| Партнёры в семье (уже есть на карточке) | плюс, не обязательно потолок |
|
||||
|
||||
Дальше число живёт: разговоры, дом, ссоры. Родство не переписывается.
|
||||
|
||||
**Дрейф.** Раз в рабочее утро (и skip ночи) каждое ненулевое мнение чуть сдвигается к своему
|
||||
базису: семейная связь — к стартовому семейному числу, остальные — к нулю. Без этого дружба
|
||||
первой недели вечная. Скорость — в `BehaviorDef`. Ноль снова не храним: дошли до базиса-нуля —
|
||||
запись выкидываем.
|
||||
|
||||
Хранение — **на человеке**, разреженно, в `people.json`. Писать при содержательном сдвиге
|
||||
(разговор кончился, драка, утреннее семейное, утренний дрейф), не каждый тик. Тот же шов, что у
|
||||
одежды.
|
||||
|
||||
### Темы
|
||||
|
||||
Новый вид `TopicDef`: id, теги уместности, возраст, роли, можно ли на уроке (шёпот), какой
|
||||
язык помогает (опционально), какой навык качается каплей сверх Communication.
|
||||
|
||||
Ванильные теги, не витрина:
|
||||
|
||||
- учёба, игры, еда, семья, спорт, сплетни, грубое, внешность.
|
||||
|
||||
Тема «внешность / форма» стыкует срез 7: исход смотрит уместность надетого (фаза 35). Не по
|
||||
форме — насмешка или неловкость; по форме / ярко в свободной школе — комплимент. Нет ещё
|
||||
уместности на карточке — тема живёт, модификатор ноль.
|
||||
|
||||
Уместность — **оценка**, как одежда: систему саму не заставит взять грубое на линейке с
|
||||
директором; взяли — мнение может упасть, учитель может оборвать.
|
||||
|
||||
### Политика речи
|
||||
|
||||
Вкладка «Правила», рядом с одеждой. Два комбобокса (ученики / сотрудники), не четыре как форма
|
||||
и цвет:
|
||||
|
||||
| Кого | Речь |
|
||||
| --- | --- |
|
||||
| Ученики | свободно / без грубого / только учёба |
|
||||
| Сотрудники | свободно / без грубого / только учёба |
|
||||
|
||||
«Применить» — **с завтра**, как дресс-код. Сегодняшние кружки доигрывают тему.
|
||||
|
||||
### Вкладка карточки
|
||||
|
||||
Пятая: **Связи**. Семья с числами, топ друзей и врагов, поиск по ненулевым (иначе тихая вражда
|
||||
не видна). Игрок ничего не назначает. Без романтического пака колонки симпатий нет.
|
||||
|
||||
## Этап B — разговоры
|
||||
|
||||
### Кружок
|
||||
|
||||
В одном узле собирается **2–4** человека, одна тема на всех. Пятый начинает соседний кружок,
|
||||
не влезает в этот.
|
||||
|
||||
Кого зовут: сначала друзья и одноклассники в узле, потом остальные. Врагов сами не зовут —
|
||||
столкновение может уйти в ссору. Тихоня реже инициатор, лидер чаще. Веса — поля на `TraitDef`
|
||||
и `BehaviorDef`, не фамилии в коде.
|
||||
|
||||
`Chat` перестаёт быть соло: действие занимает людей кружка. Совместимость ролей как сейчас
|
||||
(ученик и сотрудник могут говорить — учитель после урока, вопрос в коридоре).
|
||||
|
||||
Где: перемена, двор, обед, раздевалка, коридор. **Учительская** — отдельное действие
|
||||
`StaffChat` (`room: TeachersRoom`, только сотрудники): взрослые не обязаны болтать в коридоре
|
||||
с детьми, чтобы восполнить общение. На уроке — только **шёпот** (тема с тегом «можно шептать»).
|
||||
Шёпот восполняет общение слабее, **режет рост навыка урока** у участников.
|
||||
|
||||
**Вместе.** На перемене и в обед друзья тянутся в узел, где уже стоят свои, а не в случайный
|
||||
коридор. Враги не садятся в один кружок (уже) и не выбирают тот же обеденный узел, если есть
|
||||
другой. Это веса цели «досуг», не новая ходьба парой и не состояние присутствия: на карте
|
||||
видно кучку в одном узле.
|
||||
|
||||
**Телефон.** У кого в сумке или в руках есть телефон (срез 7), на перемене может быть **парный**
|
||||
чат слабее живого кружка: оба с телефоном, тема из того же каталога, общение восполняется
|
||||
меньше. Без телефона действия нет. На уроке телефоном не сидят — это шёпот голосом, не экран.
|
||||
|
||||
### Язык и красноречие
|
||||
|
||||
Отдельного навыка «красноречие» нет: это `Communication`. Языки — как сейчас.
|
||||
|
||||
Общий язык: лучший общий навык среди участников выше порога из `BehaviorDef`. Нет общего —
|
||||
кружок всё равно возможен (жесты), но сдвиг мнения почти нулевой и чаще отрицательный.
|
||||
|
||||
`Communication` чуть растёт от разговора (меньше, чем предмет за урок). Язык, на котором
|
||||
говорили, чуть растёт, если он ещё не у потолка.
|
||||
|
||||
### Шёпот
|
||||
|
||||
Если учитель **в том же кабинете**, шанс оборвать — из `BehaviorDef`, черты тише/громче
|
||||
сдвигают. Не каждый шёпот ловят. Учитель, поймавший, начинает разговор-выговор (тот же
|
||||
механизм кружка, тема «дисциплина»).
|
||||
|
||||
После урока учитель может сам взять 2–4 учеников (вопрос по предмету, похвала, выговор) —
|
||||
обязанность с весом, не приказ игрока. Сдвиг мнения ученика об учителе слегка масштабируется
|
||||
**педагогикой** учителя: сильный педагог после похвалы плюсует больше, слабый выговор злит
|
||||
сильнее. Оценок по-прежнему нет.
|
||||
|
||||
### Дом
|
||||
|
||||
Родители на карту не приходят. **Одно** семейное событие на человека за рабочее утро; skip
|
||||
ночи его применяет, как утреннюю одежду. Тема из семейного набора, сдвиг небольшой.
|
||||
Тем же утренним проходом — дрейф всех мнений к базису. Настроения-нужды нет.
|
||||
|
||||
### Черты в `core`
|
||||
|
||||
Уже крутят разговор: задира, тихоня, лидер, добрый, вспыльчивый. Добавляются две:
|
||||
|
||||
- **сплетник** — чаще берёт темы «сплетни», сильнее двигает мнение;
|
||||
- **общительный** — чаще инициатор, выше шанс большого кружка.
|
||||
|
||||
Поля на `TraitDef` (вес инициативы, сдвиг к тегам тем), не списки id в коде.
|
||||
|
||||
## Этап C — ссора и драка
|
||||
|
||||
Отдельные действия, не только −N к мнению.
|
||||
|
||||
**Ссора** — на перемене, двое (иногда трое из распавшегося кружка), общение восполняется
|
||||
криком, мнения падают сильнее обычного грубого разговора.
|
||||
|
||||
**Задира** не бросает кубик по школе каждый день: на человеке память жертвы (id), пока та в
|
||||
ростере. Смена цели — если жертва выпустилась, ушла или мнение уже на полу. Поля на черте, не
|
||||
`if (defName == "Bully")` в коде сверх проверки поля.
|
||||
|
||||
**Заступничество.** Третий в том же узле с высоким плюсом к жертве может встать в ссору на её
|
||||
стороне. Мнение к задире падает, к жертве растёт; кружок ссоры становится тройкой.
|
||||
|
||||
**Извиниться** — отдельное действие после ссоры или выговора, пока оба в одном узле. Возвращает
|
||||
часть (не всё) потерянного мнения. Задира извиняется реже (поле черты). Без этого единственный
|
||||
путь вверх — «ещё поболтать» и утренний дрейф к нулю.
|
||||
|
||||
**Драка** — редко, двор или физкультура. Короткая. Травм, медкабинета и вызова родителей нет.
|
||||
Мнения резко падают, оба в логе. Дежурный учитель или физрук в узле **обрывает** и делает
|
||||
выговор. Никого в кабинете директора насильно нет: игрока нет в приказе, отдельной очереди
|
||||
«к директору» этот срез не заводит.
|
||||
|
||||
Нет сотрудника рядом — драка кончается по длительности действия, лог всё равно пишется.
|
||||
|
||||
## Этап D — что видит игрок
|
||||
|
||||
Игрок **наблюдает**. Не мирит, не рассаживает, не запрещает дружить.
|
||||
|
||||
- **Локация** — «говорит с Машей о футболе»: кадр присутствия несёт id участников и id темы,
|
||||
клиент собирает строку через справочник имён и локаль темы. Имена по-прежнему не строкой в
|
||||
сокете. Раскладка присутствия меняется, **версия протокола +1**.
|
||||
- **Сейчас** на карточке — то же плюс история за сегодня (уже есть лог).
|
||||
- **Связи** — числа и подписи.
|
||||
- **Правила** — политика речи, с завтра.
|
||||
|
||||
Список людей мнения не несёт.
|
||||
|
||||
## Этап E — пак `romance`
|
||||
|
||||
Первый **контентный** мод. `example` не раздуваем: он образец папки. `romance` выбирается в
|
||||
create, `requires: ["core"]`, патчит `Chat`/темы (романтические темы появляются только с паком).
|
||||
|
||||
Без пака генератор не пишет ориентацию и романтические состояния. Живой школе мод не добавить —
|
||||
как все паки сейчас.
|
||||
|
||||
### Ориентация
|
||||
|
||||
Поле на человеке, только если пак в школе. Значения — данные пака (гетеро / би / гомо и веса
|
||||
генератора), не черта «ради галочки» и не хардкод. Пак без поля ориентации романтику не крутит.
|
||||
|
||||
### Симпатия и пара
|
||||
|
||||
Симпатия — односторонний ярлык поверх мнения (порог из данных пака). «Тили-тили тесто» —
|
||||
подпись и лог, не свидание.
|
||||
|
||||
| Кто | Симпатия | Пара / свидание |
|
||||
| --- | --- | --- |
|
||||
| Ученик ↔ ученик близкого возраста | да | только если **обоим 18+** |
|
||||
| Ученик → учитель | да, класс может дразнить; на карточке учителя видно | нет |
|
||||
| Учитель → ученик | **нет**, взаимности нет, осаживает разговором | нет |
|
||||
| Сотрудник ↔ сотрудник | да | да, оба взрослые |
|
||||
| Сотрудник ↔ ученик как пара | нет | нет |
|
||||
|
||||
Близкий возраст учеников: **±2 года или соседняя параллель**. К учителю — исключение из этого
|
||||
фильтра (иначе взрослый никогда не попадает).
|
||||
|
||||
Пара: только **взаимная**, только **одна**. Разрыв — событие (разговор или мнение ниже порога):
|
||||
мнение падает, симпатия может остаться. Новая пара не раньше следующего дня. Неразделённая
|
||||
симпатия живёт сколько угодно. Измену как механику не делаем: вторая симпатия просто висит.
|
||||
|
||||
Никакого сексуального контента, портретов «для романтики» и действий кроме разговора / ссоры /
|
||||
уже существующих перемещений. Детская линия — дразнилки и ярлык симпатии.
|
||||
|
||||
Пак может добавить черты вроде «влюбчивый», «ревнивый» теми же полями `TraitDef`.
|
||||
|
||||
## Поток данных
|
||||
|
||||
Мнения и кружок — состояние мира, считает `HSchool.Ai` (выбор темы, состав, исход), пишет
|
||||
симуляция. Карточка — HTTP через мейлбокс. Присутствие — сокет. Политика речи — снимок школы,
|
||||
как будущий дресс-код.
|
||||
|
||||
Детерминизм: свой поток на человека, обход по id, тема из сида кружка. Тот же сид и те же
|
||||
паки — те же первые дружбы на той же неделе (золотой отпечаток мнений — в фазе, которая
|
||||
начинает писать ненулевые пары сверх семьи).
|
||||
|
||||
## Где живёт код
|
||||
|
||||
Нового проекта нет.
|
||||
|
||||
| Что | Куда |
|
||||
| --- | --- |
|
||||
| `TopicDef`, теги, поля черт, политика речи | `HSchool.Content` + JSONC |
|
||||
| Стартовые мнения семьи, ориентация при паке | `HSchool.People` |
|
||||
| Кружок, шёпот, ссора, драка, дом-утро | `HSchool.Ai` + адаптер в `HSchool.Simulation` |
|
||||
| Кадр присутствия | `HSchool.Protocol` + `protocol.ts` + `docs/protocol.md` |
|
||||
| Вкладка, правила, лог | `HSchool.Server` + клиент |
|
||||
| Пак | `mods/romance/` рядом с `core` и `example` |
|
||||
|
||||
## Советы, которые стоит принять сразу
|
||||
|
||||
- Не заводить нужду «настроение»: мнение + общение уже две шкалы.
|
||||
- Не класть имена в кадр присутствия — только id, как с людьми сейчас.
|
||||
- Не лечить драку травмой: медкабинет тогда обязан стать больницей.
|
||||
- Не делать «ходить вместе» отдельным состоянием присутствия: достаточно одного узла.
|
||||
- `ActionDef` по-прежнему одна комната: учительская и телефон — отдельные действия, не массив комнат.
|
||||
- Не вшивать романтику в `core`: ванильная школа должна собираться без пака.
|
||||
- Не расширять `example`. Контент — другой пак.
|
||||
- Не делать учительскую взаимность «опцией мода»: пак проверяет запрет тестом.
|
||||
|
||||
## Заведомо не сейчас
|
||||
|
||||
- Настроение как нужда, приказы, вызов родителей, рассадка класса.
|
||||
- Секс, поцелуи как действие, свидания вне карты, ревность-сюжет.
|
||||
- Пара учителя и ученика, даже 18+.
|
||||
- Травмы, дневник дисциплины как журнал оценок.
|
||||
- Смена модов у живой школы.
|
||||
- Общая лента событий школы — по-прежнему лог человека.
|
||||
|
||||
## Зафиксировано этим разговором
|
||||
|
||||
| Тема | Решение |
|
||||
| --- | --- |
|
||||
| Мнение | −100…100, несимметрично, подписи по порогам, семья — старт |
|
||||
| Дрейф | Каждое рабочее утро к семейному базису или к нулю; skip применяет |
|
||||
| Хранение | Разреженно на человеке, писать при сдвиге |
|
||||
| Темы | `TopicDef` + теги включая внешность; оценка, не запрет |
|
||||
| Политика речи | Ученики/сотрудники: свободно / без грубого / только учёба; с завтра |
|
||||
| Кружок | Сразу 2–4; пятый — другой кружок |
|
||||
| Кого зовут | Друзья и класс в узле, врагов не зовут |
|
||||
| Вместе | Друзья на перемене/обеде тянутся в один узел |
|
||||
| Где | Перемена, двор, обед, после урока, учительская; на уроке — шёпот |
|
||||
| Телефон | Парный чат на перемене, оба с телефоном, слабее живого |
|
||||
| Шёпот | Режет урок; учитель в кабинете — шанс оборвать |
|
||||
| Язык | Нет общего — слабый разговор, не отказ |
|
||||
| Красноречие | `Communication`; растёт от разговора |
|
||||
| Педагогика | Масштабирует мнение ученика об учителе после разговора |
|
||||
| Игрок | Только смотрит |
|
||||
| Экран | Вкладка «Связи»; локация из id в присутствии; протокол +1 |
|
||||
| Ссора / драка | Действия; жертва задиры помнится; заступник; извинение; без травм |
|
||||
| Дом | Одно семейное событие на рабочее утро; skip применяет |
|
||||
| Настроение | Нет |
|
||||
| Черты core | + сплетник, общительный |
|
||||
| Романтика | Пак `romance`, патчит темы/`Chat` |
|
||||
| Ориентация | Только с паком, поле и веса в данных |
|
||||
| Симпатия учеников | Близкий возраст ±2 / соседняя параллель |
|
||||
| Симпатия к учителю | Можно, видно, учитель осаждает, взаимности нет |
|
||||
| Пара | Оба 18+, взаимно, одна; разрыв — событие; сотрудник↔ученик нет |
|
||||
| Сотрудники | Симпатия и пара между собой — да |
|
||||
@@ -12,24 +12,24 @@
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] В «Управлении» вкладка **«Правила»** рядом со штатом, не новый верхний режим
|
||||
- [ ] Четыре комбобокса: форма учеников, цвет учеников, форма сотрудников, цвет сотрудников.
|
||||
- [x] В «Управлении» вкладка **«Правила»** рядом со штатом, не новый верхний режим
|
||||
- [x] Четыре комбобокса: форма учеников, цвет учеников, форма сотрудников, цвет сотрудников.
|
||||
Значения — как в [`../design/inventory.md`](../design/inventory.md)
|
||||
- [ ] Сохранение пишет завтрашнее правило; на экране видно, что действует сегодня и что
|
||||
- [x] Сохранение пишет завтрашнее правило; на экране видно, что действует сегодня и что
|
||||
вступит завтра
|
||||
- [ ] HTTP: чтение текущих+отложенных, запись отложенных. Отказ по неизвестному коду правила —
|
||||
- [x] HTTP: чтение текущих+отложенных, запись отложенных. Отказ по неизвестному коду правила —
|
||||
`400`, не тишина
|
||||
- [ ] На следующее рабочее утро отложенное становится текущим; фаза 35 уже одевает от него
|
||||
- [ ] Строки через `t(...)`, обе локали
|
||||
- [ ] Vitest: смена комбобокса не зовёт API до подтверждения; ошибка API видна текстом
|
||||
- [x] На следующее рабочее утро отложенное становится текущим; фаза 35 уже одевает от него
|
||||
- [x] Строки через `t(...)`, обе локали
|
||||
- [x] Vitest: смена комбобокса не зовёт API до подтверждения; ошибка API видна текстом
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [ ] GET правил на новой школе — дефолт обычная / без яркого на обе роли
|
||||
- [ ] POST «строгая» сегодня не меняет одежду до следующего рабочего утра
|
||||
- [ ] После утра на теле учеников нет яркого, если отложили «без яркого»
|
||||
- [ ] Неизвестный код политики — `400`
|
||||
- [ ] Вкладка не ломает наём и сетку расписания
|
||||
- [x] GET правил на новой школе — дефолт обычная / без яркого на обе роли
|
||||
- [x] POST «строгая» сегодня не меняет одежду до следующего рабочего утра
|
||||
- [x] После утра на теле учеников нет яркого, если отложили «без яркого»
|
||||
- [x] Неизвестный код политики — `400`
|
||||
- [x] Вкладка не ломает наём и сетку расписания
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# Фаза 41. Мнения и вкладка «Связи»
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 8](08-people-browser.md)
|
||||
- [Фаза 36](36-person-card-tabs.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
У пары появляется число. Семья больше не «просто родственники». Карточка умеет это показать,
|
||||
даже пока кружков ещё нет.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] Мнение A→B: −100…100, несимметрично, ноль не хранить
|
||||
- [ ] Пороги и подписи в `BehaviorDef`; клиент рисует присланную подпись, не считает сам
|
||||
- [ ] Генератор ставит семейные старты (родители, сиблинги, партнёры семьи) из данных
|
||||
- [ ] Каждое рабочее утро (и skip) ненулевые мнения слегка дрейфуют к семейному базису или к нулю;
|
||||
дошли до нуля — запись выкинуть
|
||||
- [ ] `people.json` пишет мнение при сдвиге; старый сейв без поля — все нули кроме семьи
|
||||
после первой загрузки-переписи
|
||||
- [ ] Вкладка карточки **Связи**: семья с числами, топ друзей/врагов, поиск по ненулевым
|
||||
- [ ] Игрок с вкладки ничего не меняет
|
||||
- [ ] `docs/protocol.md` — HTTP карточки
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [ ] Родитель и ребёнок после генерации имеют плюс в обе стороны; чужие одноклассники — нет записи
|
||||
- [ ] A→B и B→A могут различаться
|
||||
- [ ] После нескольких утренних дрейфов без разговоров мнение одноклассников (если появилось)
|
||||
ближе к нулю, семейное — к старту, не к нулю
|
||||
- [ ] Карточка без отдельного запроса «всех пар школы»: только этот человек
|
||||
- [ ] Клиентский тест: вкладка «Связи» не монтирует лог
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- Открыть ученика, на «Связях» родители с подписью «близкие» или соседней, одноклассник без строки
|
||||
- `dotnet test` и `npm test` / `build` проходят
|
||||
|
||||
## Стоп
|
||||
|
||||
Не собирать кружки. Не бампить сокет. Не заводить романтику.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Фаза 42. Темы и кружки
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 41](41-opinions.md)
|
||||
- [Фаза 21](21-decisions.md)
|
||||
- [Фаза 31](31-dress-generator.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
`Chat` перестаёт быть соло. В узле говорят 2–4 человека об одной теме. Язык и
|
||||
`Communication` влияют на исход.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] `TopicDef`: теги, возраст, роли, шёпот-на-уроке, опциональный язык
|
||||
- [ ] Ванильный набор тем (учёба, игры, еда, семья, спорт, сплетни, грубое, внешность) в `core`.
|
||||
Тема внешности учитывает уместность одежды, если сервер её уже прислал; иначе модификатор 0
|
||||
- [ ] Кружок 2–4 в одном узле; пятый не влезает
|
||||
- [ ] Кого зовут: друзья и одноклассники в узле, врагов не зовут; тихоня/лидер — поля черты
|
||||
- [ ] На перемене и в обед друзья тянутся в узел своих; враги не выбирают тот же обеденный узел,
|
||||
если есть другой
|
||||
- [ ] `StaffChat` в `TeachersRoom`, только сотрудники
|
||||
- [ ] Парный телефонный чат на перемене: оба несут `Phone`, слабее живого кружка; на уроке нет
|
||||
- [ ] Нет общего языка — кружок можно, сдвиг мнения слабый и чаще вниз
|
||||
- [ ] `Communication` растёт от разговора меньше, чем предмет за урок; язык разговора — капля,
|
||||
если не у потолка
|
||||
- [ ] Черты **сплетник** и **общительный** в `core` с полями, не списками в коде
|
||||
- [ ] Исход пишет мнения всех пар кружка и строку лога
|
||||
- [ ] На уроке обычный `Chat` не стартует (шёпот — фаза 43)
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [ ] Двое свободных друзей в коридоре на перемене собирают кружок; враги — нет
|
||||
- [ ] Пятый в узле не входит в тот же кружок
|
||||
- [ ] Сотрудники в учительской могут `StaffChat`; ученик это действие не берёт
|
||||
- [ ] Двое с телефоном на перемене могут парный чат; без телефона — нет
|
||||
- [ ] Без общего языка мнение почти не растёт при том же `Communication`
|
||||
- [ ] Высокий `Communication` сильнее двигает число, чем низкий, на одной теме
|
||||
- [ ] Каталог без `TopicDef` не стартует школу с кружками — или падает загрузка, не молча соло-Chat
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- На перемене в коридоре двое «разговаривают», на карточке мнение сдвинулось, в логе тема
|
||||
- `dotnet test` проходит
|
||||
|
||||
## Стоп
|
||||
|
||||
Не шёпот на уроке. Не драка. Не менять кадр присутствия (локация может ещё писать «Разговор»).
|
||||
@@ -0,0 +1,38 @@
|
||||
# Фаза 43. Шёпот и учитель
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 42](42-talk-circles.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
На уроке можно шептаться — ценой учёбы. Учитель иногда слышит. После урока учитель сам
|
||||
говорит с учениками.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] Тема с тегом шёпота может стартовать кружок на уроке в кабинете класса
|
||||
- [ ] У участников на время шёпота режется рост навыка урока (доля в `BehaviorDef`)
|
||||
- [ ] Учитель в том же кабинете: шанс оборвать (данные + черты); не 100 %
|
||||
- [ ] Пойманный шёпот → выговор (кружок учитель + ученики, тема дисциплины), мнения как у
|
||||
строгого разговора
|
||||
- [ ] После урока учитель может взять 2–4 учеников (вопрос / похвала / выговор) по весу цели
|
||||
- [ ] Сдвиг мнения ученика об учителе масштабируется педагогикой (поле навыка, не фамилия)
|
||||
- [ ] Лог: «шептались», «учитель оборвал»
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [ ] Шёпот на уроке даёт меньше прироста предмета, чем тихий урок без кружка
|
||||
- [ ] При фиксированном сиде не каждый шёпот с учителем в кабинете обрывается
|
||||
- [ ] Без учителя в узле шёпот не обрывается этим правилом
|
||||
- [ ] Учитель с высокой педагогикой после похвалы сильнее плюсует мнение, чем с низкой
|
||||
- [ ] Обычный не-шёпотный `Chat` на уроке не стартует
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- На математике двое шепчутся, иногда учитель обрывает, в логе это видно
|
||||
- `dotnet test` проходит
|
||||
|
||||
## Стоп
|
||||
|
||||
Не драка. Не политика речи в UI. Не протокол.
|
||||
@@ -0,0 +1,40 @@
|
||||
# Фаза 44. Ссора и драка
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 42](42-talk-circles.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
Вражда — не только минус в JSON. На перемене ссорятся, на дворе или физкультуре редко дерутся.
|
||||
Травм нет.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] Действие ссоры: 2 (иногда 3), перемена, мнение падает сильнее грубого разговора
|
||||
- [ ] Действие драки: редко, двор или зал; коротко; без травм и медпункта
|
||||
- [ ] Триггер: низкое взаимное мнение, задира/вспыльчивый — поля, не if по defName
|
||||
- [ ] Задира держит id жертвы, пока та в ростере; не меняет цель каждый день
|
||||
- [ ] Третий с высоким плюсом к жертве может вступить в ссору на её стороне
|
||||
- [ ] Действие «извиниться» после ссоры/выговора в одном узле возвращает часть мнения
|
||||
- [ ] Сотрудник в узле обрывает драку и делает выговор; нет сотрудника — действие просто кончается
|
||||
- [ ] Лог обоих; кабинет директора не заводим
|
||||
- [ ] Игрок не приказывает разнять
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [ ] Двое врагов на дворе чаще ссорятся, чем двое друзей
|
||||
- [ ] Задира два дня подряд целится в того же человека, если тот ещё в школе
|
||||
- [ ] Извинение поднимает мнение, но не выше, чем до ссоры
|
||||
- [ ] Драка не меняет нужду «здоровье» — такой нужды нет и не появляется
|
||||
- [ ] Выговор после обрыва есть, если в узле был сотрудник
|
||||
- [ ] Skip пустого времени не оставляет «вечную драку» в состоянии
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- Задира с врагом на дворе: в логе ссора или драка, мнения ниже, оба живы и на ногах
|
||||
- `dotnet test` проходит
|
||||
|
||||
## Стоп
|
||||
|
||||
Не вызов родителей. Не травмы. Не романтика.
|
||||
@@ -0,0 +1,34 @@
|
||||
# Фаза 45. Кружок в присутствии
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 42](42-talk-circles.md)
|
||||
- [Фаза 19](19-presence-screen.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
В панели локации видно, с кем и о чём говорят, без открытия карточки.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] Кадр присутствия: у человека, который в кружке, список id участников и id темы.
|
||||
Имена не строкой. Клиент собирает «говорит с Машей о футболе» из справочника и локали
|
||||
- [ ] Версия протокола +1. `ProtocolCodec.cs`, `protocol.ts`, `docs/protocol.md` в одном коммите
|
||||
- [ ] Не в кружке — пустой список, как сейчас только id/узел/состояние
|
||||
- [ ] Вкладка «Сейчас» на карточке согласована с тем же составом
|
||||
- [ ] Старый клиент отваливается Hello, как обычно
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [ ] Круглый трип и байтовая раскладка человека с кружком и без — на обеих сторонах
|
||||
- [ ] Имя человека не встречается в кадре присутствия
|
||||
- [ ] Клиентский тест: локация показывает тему и имя напарника из directory, не из кадра
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- Клик по коридору на перемене: в «персонажах» видно, кто с кем говорит
|
||||
- `dotnet test` и `npm test` / `build` проходят
|
||||
|
||||
## Стоп
|
||||
|
||||
Не политика речи. Не пак.
|
||||
@@ -0,0 +1,38 @@
|
||||
# Фаза 46. Политика речи и дом
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 42](42-talk-circles.md)
|
||||
- [Фаза 37](37-school-rules.md)
|
||||
- [Фаза 34](34-wear-home.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
Школа задаёт, какие темы уместны — тем же жестом, что дресс-код. Родители двигают мнение утром,
|
||||
не приходя на карту.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] В «Правилах» два комбобокса речи: ученики / сотрудники × свободно / без грубого / только учёба
|
||||
- [ ] В силу с завтра; API сегодня не переодевает темы текущих кружков
|
||||
- [ ] Система не стартует кружок с темой вне политики; начатый вчера доигрывает
|
||||
- [ ] Одно семейное событие на человека за рабочее утро; skip ночи применяет
|
||||
- [ ] Семейные темы из `TopicDef`; сдвиг меньше школьного разговора
|
||||
- [ ] `docs/protocol.md` — HTTP правил речи
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [ ] POST «только учёба» сегодня не мешает текущему кружку «игры»
|
||||
- [ ] На следующее рабочее утро грубая тема у учеников не стартует
|
||||
- [ ] Skip с пятницы на понедельник применяет домашнее событие и дрейф мнений; мнение с
|
||||
родителем сдвинуто, брошенная дружба ближе к нулю
|
||||
- [ ] Клиентский тест: комбобоксы речи рядом с одеждой, подпись «с завтра»
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- Сменить политику, пережить ночь кнопкой, на перемене нет грубых кружков у учеников
|
||||
- `dotnet test` и `npm test` / `build` проходят
|
||||
|
||||
## Стоп
|
||||
|
||||
Не романтика. Не вызов родителей в школу.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Фаза 47. Пак romance
|
||||
|
||||
## Зависимости
|
||||
|
||||
- [Фаза 42](42-talk-circles.md)
|
||||
- [Фаза 23](23-example-pack.md)
|
||||
- [Фаза 41](41-opinions.md)
|
||||
|
||||
## Зачем
|
||||
|
||||
Контентный мод, не скучный образец. Ваниль без романтики. Пак добавляет ориентацию, симпатию,
|
||||
пару 18+ и романтические темы патчем.
|
||||
|
||||
## Задачи
|
||||
|
||||
- [ ] `mods/romance/`: `pack.jsonc` `requires: ["core"]`, локали, ориентация как данные,
|
||||
черты влюбчивый/ревнивый полями, патч тем и при необходимости `Chat`
|
||||
- [ ] Без пака в create ориентации и романтических состояний нет; ванильный каталог без
|
||||
романтических тем
|
||||
- [ ] Симпатия учеников: ±2 года или соседняя параллель
|
||||
- [ ] Симпатия ученик → учитель можно, видна на обеих карточках; учитель → ученик никогда;
|
||||
осадить — разговор; пары сотрудник↔ученик нет
|
||||
- [ ] Пара: оба 18+, взаимно, одна; разрыв — событие, новая не раньше следующего дня
|
||||
- [ ] Сотрудники между собой — симпатия и пара можно
|
||||
- [ ] Никаких сексуальных действий и текстов. Детская линия — дразнилки и ярлык
|
||||
- [ ] Тесты хоста: школа с паком и без; запрет учительской взаимности
|
||||
- [ ] `example` не трогать
|
||||
|
||||
## Тесты, без которых фаза не закрыта
|
||||
|
||||
- [ ] `GET /api/catalog` без `romance` не отдаёт романтические темы
|
||||
- [ ] Create с паком пишет ориентацию; без пака поля нет
|
||||
- [ ] Двое 16-летних не получают статус пары при любом мнении
|
||||
- [ ] Учитель не получает романтическое состояние на ученика
|
||||
- [ ] Первоклассник не получает симпатию к одиннадцатому (возраст)
|
||||
- [ ] Школа с `example` и без `romance` ведёт себя как ваниль в части тем
|
||||
|
||||
## Критерий готовности
|
||||
|
||||
- Создать школу с галкой пака, увидеть симпатию на «Связях» и тему пака в логе; снять галку на
|
||||
новой школе — этого нет
|
||||
- `dotnet test` проходит
|
||||
|
||||
## Стоп
|
||||
|
||||
Не секс. Не пара учителя и ученика. Не раздувать `example`. Не смена модов у живой школы.
|
||||
+41
-1
@@ -149,7 +149,7 @@
|
||||
| [34. Износ и дом](34-wear-home.md) | ✅ | Прочность, утренняя замена, из ветхого не выходят |
|
||||
| [35. Уместность](35-appropriateness.md) | ✅ | Правила, переодевание действием, физкультура |
|
||||
| [36. Вкладки карточки](36-person-card-tabs.md) | ✅ | Одежда, ноша, сейчас + история за сегодня |
|
||||
| [37. Правила школы](37-school-rules.md) | ⬜ | Вкладка в «Управлении», четыре комбобокса, с завтра |
|
||||
| [37. Правила школы](37-school-rules.md) | ✅ | Вкладка в «Управлении», четыре комбобокса, с завтра |
|
||||
|
||||
34 стоит на 31; 35 — на 32–34; 36 — на 31 и может идти параллельно с 35 в части вкладок одежды,
|
||||
история — после 35; 37 стоит на 35 и 36.
|
||||
@@ -182,3 +182,43 @@
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [40. Темп часов](40-clock-tempo.md) | ⬜ | ×1 = минута/с, кнопки ×½ ×1 ×2 ×5 ×10, страйд тяжёлых систем |
|
||||
|
||||
## Срез 9. Общение и романтический пак
|
||||
|
||||
Дизайн: [`../design/social.md`](../design/social.md).
|
||||
|
||||
Разговор становится кружком, мнение — числом, вражда — ссорой. Романтика не ваниль: отдельный
|
||||
пак. Срез можно остановить после этапа B — школа болтает, даже если драк и пака ещё нет.
|
||||
|
||||
**Этап A — мнения.** Число и вкладка.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [41. Мнения и «Связи»](41-opinions.md) | ⬜ | −100…100, семья-старт, вкладка карточки |
|
||||
|
||||
**Этап B — разговоры.** Кружок, язык, шёпот.
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [42. Темы и кружки](42-talk-circles.md) | ⬜ | `TopicDef`, 2–4 человека, учительская, телефон, вместе |
|
||||
| [43. Шёпот и учитель](43-whisper.md) | ⬜ | Шёпот на уроке, шанс оборвать, разговор после звонка |
|
||||
|
||||
42 стоит на 41; 43 — на 42.
|
||||
|
||||
**Этап C — конфликт и экран.**
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [44. Ссора и драка](44-quarrel-fight.md) | ⬜ | Жертва задиры, заступник, извинение, двор/физкультура |
|
||||
| [45. Кружок в присутствии](45-presence-talk.md) | ⬜ | Id участников и темы в кадре, протокол +1 |
|
||||
|
||||
44 и 45 стоят на 42, можно параллельно.
|
||||
|
||||
**Этап D — правила, дом, пак.**
|
||||
|
||||
| Фаза | Статус | Зачем |
|
||||
| --- | --- | --- |
|
||||
| [46. Политика речи и дом](46-speech-home.md) | ⬜ | Комбобоксы речи с завтра; утреннее семейное событие |
|
||||
| [47. Пак romance](47-romance-pack.md) | ⬜ | Ориентация, симпатия, пара 18+, патч тем |
|
||||
|
||||
46 стоит на 37 и 42; 47 — на 42 и 23. `example` не трогать.
|
||||
|
||||
+78
-28
@@ -256,50 +256,100 @@
|
||||
|
||||
- `Dump_ReturnsPeopleNodesAndTimetable` принимает `NodeId is not null || Needs.Count > 0`.
|
||||
Нужды есть у всех, так что узлы на кампусе не проверяются. Усиливать до явки — срез 5.
|
||||
- Срез 7, фаза 37 — в работе на момент проверки B–C; этап A проверяет соседний ревьюер.
|
||||
|
||||
## Срез 7. Этап B–C — климат и жизнь одежды (без 37)
|
||||
## Срез 7. Этап A — данные и гардероб
|
||||
|
||||
- **Фазы:** 32–36
|
||||
- **Проверен на:** `e461a9f`, 2026-08-20
|
||||
- **Пути:** `src/HSchool.Simulation/{WeatherSampler,WarmthDecay,PlaceClimate,ApparelDresser,ApparelWear,MorningDress,PersonLogBrowser}.cs`,
|
||||
`src/HSchool.People/LockerAssigner.cs`, `src/HSchool.Content/{Appropriateness,ClimatePreset,DressRules}.cs`,
|
||||
`src/HSchool.Ai/ApparelGoals.cs`, `src/HSchool.Protocol`, `src/HSchool.Server/Api/{SchoolEndpoints,PeopleModels}.cs`,
|
||||
`src/HSchool.Server/Game/PersonCardReader.cs`, `src/HSchool.Client/src/{ui/personCard.ts,format/weather.ts,net/api.ts}`,
|
||||
`docs/protocol.md`, `tests/HSchool.Simulation.Tests`, `tests/HSchool.People.Tests/LockerAssignerTests.cs`,
|
||||
`tests/HSchool.Content.Tests/{ClimatePresetTests,AppropriatenessTests,ChangingRoomMapTests}.cs`,
|
||||
`tests/HSchool.AppHost.Tests/{PersonLogApiTests,DressRulesApiTests}.cs`, `tests/HSchool.Protocol.Tests`,
|
||||
`src/HSchool.Client/src/ui/personCard.test.ts`
|
||||
- **Итог:** фазы 32–36 подтверждены; дописано 5 тестов; исправлены 2 бага переодевания; фаза 37 в работе
|
||||
- **Фазы:** 29–31
|
||||
- **Проверен на:** `d5547b7`, 2026-08-20
|
||||
- **Пути:** `src/HSchool.Content/{CountryDef,ApparelDefs,CatalogLoader}.cs`,
|
||||
`src/HSchool.People/{DressGenerator,CountryClimate,RosterJson}.cs`,
|
||||
`src/HSchool.Server/{Game/SchoolStore.cs,Api/{ModEndpoints,SchoolEndpoints}.cs,Api/PeopleModels.cs}`,
|
||||
`src/HSchool.Client/src/ui/{createSchoolDialog.ts,personCard.ts}`,
|
||||
`tests/HSchool.Content.Tests/{CountryDefTests,ApparelDefTests,VanillaCoreTests}.cs`,
|
||||
`tests/HSchool.People.Tests/{DressGeneratorTests,GoldenRosterTests}.cs`,
|
||||
`tests/HSchool.AppHost.Tests/{SchoolApiTests,InventoryApiTests,GoldenSaveTests,ServiceabilityTests}.cs`,
|
||||
`src/HSchool.Client/src/ui/createSchoolDialog.test.ts`
|
||||
- **Итог:** все 17 тестов из списков фаз на месте; исправлен дубликат `peopleTabOverview` в
|
||||
`strings.ts` (ломал `npm run build`); одно замечание рядом про вкладки карточки
|
||||
|
||||
Что подтверждено:
|
||||
|
||||
- Погода детерминирована от пресета, сида и времени; skip выставляет утро; кадр часов v8 (27 байт) в
|
||||
`ProtocolCodec`, `protocol.ts`, `docs/protocol.md`; клиент рисует температуру с wire, не из месяца.
|
||||
- `Warmth` декейит на морозе, дома восстанавливается; черты `HeatLoving`/`ColdLoving` несовместимы.
|
||||
- Техник держит комфорт; двор = улица, кабинет теплее двора без техника; две раздевалки на ванили;
|
||||
шкафчики по полу/старшинству, пересчёт на 1 сентября.
|
||||
- Износ только на кампусе, skip/утро заменяют ветхое; утренняя выдача пишет `apparel-replaced`.
|
||||
- Уместность: утро, PE, погода, правила «с завтра» через API; карточка — вкладки и HTTP-лог с 6:00.
|
||||
- `HSchool.Simulation` без ASP.NET; `dotnet test` и Vitest (`personCard`, `weather`, `protocol`) зелёные.
|
||||
- **29:** `CountryDef`/`ClimatePresetDef`; `namesets/` убран; ваниль `Russia` с двумя пресетами;
|
||||
каталог отдаёт `countries`; create принимает `countryId`, `unknown-country` на чужую страну;
|
||||
пресет от сида (`CreateSchool_WithTheSameSeed_GetsTheSameClimatePreset`); `nameSetId: Slavic`
|
||||
поднимается через `UpgradeOlderSave` (`GoldenSaveTests`, `legacy-no-native/`); формат без
|
||||
страны не стартует (`ServiceabilityTests`); диалог — страны и языки (`createSchoolDialog.test.ts`);
|
||||
золотой ростер обновлён (`GoldenRosterTests`).
|
||||
- **30:** поля `ThingDef`/`ColorDef`, слои как роли, мебель без `layers`; ванильная палитра и
|
||||
одежда в `VanillaCoreTests`; локали ru/en (`EveryVanillaLabel_ExistsInBothLocales`); учебник
|
||||
один def без `subject` на def.
|
||||
- **31:** `InventoryItem` с `def`/`color`/`condition`/`location`/`subject`; `DressGenerator`
|
||||
детерминирован (`DressGeneratorTests`, `InventoryApiTests.SameSeed_YieldsTheSameShirt`); слои
|
||||
без пересечения, платье на два слоя; пол/яркость/учебник/родители/соискатели/масса/Hauling;
|
||||
карточка отдаёт worn+carried, список — нет (`InventoryApiTests`); старый `people.json` без
|
||||
items одевается на reload (`PeopleJsonWithoutInventory_IsDressedOnReloadAndRewritten`);
|
||||
`HSchool.People`/`HSchool.Content` без ASP.NET; протокол не тронут.
|
||||
|
||||
Дописано:
|
||||
|
||||
- (нет новых тестов — списки фаз закрыты существующими)
|
||||
|
||||
Исправлено:
|
||||
|
||||
- Дубликат ключа `peopleTabOverview` в `strings.ts` (ru/en): vitest не ловит TS2300/TS1117,
|
||||
`npm run build` падал; ключ перенесён, `peopleTabPortrait` рядом с остальными вкладками.
|
||||
- Повтор `using HSchool.Content` в `SchoolStore.cs` (CS0105).
|
||||
|
||||
Замечено рядом:
|
||||
|
||||
- Карточка уже с вкладками (`personCard.ts`, фаза 31 обещала один свиток — позже по
|
||||
`design/inventory.md`); портрет/SwarmUI-строки в `strings.ts` — не этап A.
|
||||
- `ResolveClimatePreset` в `SchoolWorker` при reload без сохранённого пресета берёт первый
|
||||
пресет страны (`schoolSeed: 0`, `rollIfOmitted: false`) — по дизайну для legacy; create
|
||||
кидает пресет из `GameLoopService` до spawn.
|
||||
|
||||
## Срез 7. Этап B–C — климат, жизнь одежды и правила
|
||||
|
||||
- **Фазы:** 32–37
|
||||
- **Проверен на:** `<commit>`, 2026-08-20
|
||||
- **Пути:** `src/HSchool.Simulation/{WeatherSampler,WarmthDecay,PlaceClimate,ApparelDresser,ApparelWear,MorningDress,PersonLogBrowser}.cs`,
|
||||
`src/HSchool.People/LockerAssigner.cs`, `src/HSchool.Content/{Appropriateness,ClimatePreset,DressRules}.cs`,
|
||||
`src/HSchool.Ai/ApparelGoals.cs`, `src/HSchool.Protocol`, `src/HSchool.Server/Api/{SchoolEndpoints,DressRulesModels}.cs`,
|
||||
`src/HSchool.Server/Game/{PersonCardReader,SchoolWorker}.cs`, `src/HSchool.Client/src/{ui/dressRulesPanel.ts,ui/managementPanel.ts,format/weather.ts,net/api.ts}`,
|
||||
`docs/protocol.md`, `tests/HSchool.Simulation.Tests`, `tests/HSchool.People.Tests/LockerAssignerTests.cs`,
|
||||
`tests/HSchool.Content.Tests/{ClimatePresetTests,AppropriatenessTests,ChangingRoomMapTests}.cs`,
|
||||
`tests/HSchool.AppHost.Tests/{PersonLogApiTests,DressRulesApiTests}.cs`, `tests/HSchool.Protocol.Tests`,
|
||||
`src/HSchool.Client/src/ui/{personCard,dressRulesPanel,managementPanel}.test.ts`
|
||||
- **Итог:** фазы 32–37 подтверждены; дописано 5 тестов симуляции; исправлены 2 бага переодевания и 2
|
||||
регрессии тестов (не протокол)
|
||||
|
||||
Что подтверждено:
|
||||
|
||||
- **32–36:** погода детерминирована; skip выставляет утро; кадр часов v8 (27 байт) в трёх местах;
|
||||
`Warmth` и техник; шкафчики; износ и утренняя замена; уместность и PE; вкладки карточки и HTTP-лог.
|
||||
- **37:** вкладка «Правила» в «Управлении»; четыре комбобокса; GET/POST `dress-rules` с pending;
|
||||
`unknown-form`/`unknown-color` → `400`; правило с завтра; `ColorAllowed` для `whiteTopBlackBottom`;
|
||||
`dressRulesPanel.test.ts` — combobox без API до Apply, ошибка текстом; `ManagementPanel` не ломает штат
|
||||
и сетку.
|
||||
|
||||
Дописано (32–36, прошлый проход):
|
||||
|
||||
- `AppropriatenessSimulationTests.MorningDress_StagesPeKitForTodaysLesson`
|
||||
- `AppropriatenessSimulationTests.PeBreak_CompletesChangeBeforeLesson`
|
||||
- `AppropriatenessSimulationTests.PeLesson_WearsPeThenReturnsToEveryday`
|
||||
- `AppropriatenessSimulationTests.AfterPeBreak_ModeExpectsEveryday`
|
||||
- `PresenceTests.PhysicalEducationBeforeLesson_GoesToChangingRoomOnTheBreak` (переименован с ожидания зала на перемене)
|
||||
- `PresenceTests.PhysicalEducationBeforeLesson_GoesToChangingRoomOnTheBreak`
|
||||
|
||||
Исправлено:
|
||||
|
||||
- `PresenceSystem`: ходьба по duty больше не обрывает активный `ChangeClothes` — форма успевает надеться до
|
||||
звонка.
|
||||
- `ApparelPresence.ModeAt`: после перемены following PE режим «everyday», иначе `PeForbidden` не
|
||||
поднимался и форму не снимали.
|
||||
- `PresenceSystem`: ходьба по duty не обрывает активный `ChangeClothes`.
|
||||
- `ApparelPresence.ModeAt`: после перемены following PE — режим everyday.
|
||||
- `managementPanel.test.ts`: панель штата скрывается через `hidden`, не удаляется из DOM.
|
||||
- `PortraitApiTests.GetSwarmUiSettings_ReturnsPresets`: URL `/api/settings/swarmui` (CS1503).
|
||||
- `dressRulesPanel.ts`: неиспользуемый импорт `clear` — TS6133 на `npm run build`.
|
||||
|
||||
Замечено рядом:
|
||||
|
||||
- Фаза 37 (вкладка «Правила», UI смены дресс-кода) — в работе, не проверялась.
|
||||
- `PhysicalEducationBeforeLesson_…` в `PresenceTests` не гоняет полный цикл «зал с формой» — это в
|
||||
- `PhysicalEducationBeforeLesson_…` не гоняет полный цикл «зал с формой» — это в
|
||||
`AppropriatenessSimulationTests.PeLesson_…`.
|
||||
- Портреты/SwarmUI — вне среза 7, но `PortraitApiTests` чинился, чтобы AppHost-сборка не падала.
|
||||
|
||||
+20
-1
@@ -389,13 +389,32 @@ is `404` `unknown-school`; unknown person is `404` `unknown-person`. Invalid `ki
|
||||
"kind": "avatar",
|
||||
"positive": "cinematic photo, …, close up, head and shoulders portrait, …, age 12, …",
|
||||
"negative": "(low quality, worst quality:1.4), …",
|
||||
"promptExtra": null
|
||||
"promptExtra": null,
|
||||
"presetId": "default",
|
||||
"presetLabel": "Default"
|
||||
}
|
||||
```
|
||||
|
||||
`GET /api/status` includes `swarmUiConfigured` and `swarmUiConnected` (`null` when not configured)
|
||||
so the client can disable generate buttons and show reachability without trying POST first.
|
||||
|
||||
### `GET /api/settings/swarmui`
|
||||
|
||||
Returns the editable SwarmUI preset file (`swarmui.json`): named presets (model, steps, sampler,
|
||||
LoRA lists, per-kind sizes/prompts), `activePresetId` and `ageRules` mapping age bands to presets.
|
||||
Portrait generation resolves the preset from the person's age before building the prompt.
|
||||
|
||||
### `PUT /api/settings/swarmui`
|
||||
|
||||
Replaces the preset file after validation. Invalid preset ids, age rules or numeric ranges return
|
||||
`400` `invalid-body`. Changes apply immediately to new portrait generations.
|
||||
|
||||
### `GET /api/settings/swarmui/discovery`
|
||||
|
||||
When SwarmUI is configured and reachable, proxies `ListT2IParams` and returns
|
||||
`{ connected, models, loras, samplers, schedulers }` for the settings UI comboboxes. When SwarmUI
|
||||
is off or unreachable, `connected` is false and the lists are empty.
|
||||
|
||||
### `GET /api/schools/{id}/dress-rules`
|
||||
|
||||
Student and staff dress-code pairs for the school. Unknown `{id}` is `404` `unknown-school`.
|
||||
|
||||
Reference in New Issue
Block a user