- Updated `protocol.md` to clarify the concept of uncovered subjects and the number of additional teachers required. - Introduced `teachersShort` property in the `StaffingSubject` interface to indicate how many more teachers are needed for a subject. - Enhanced localization strings to reflect the new uncovered teacher information in both English and Russian. - Updated the management panel UI to display the number of teachers short for each uncovered subject. - Revised the `Uncovered` method in the staffing logic to return detailed information about uncovered subjects, including the shortfall of teachers. - Added tests to validate the new uncovered teacher tracking functionality and ensure accurate reporting in the staffing API. - Marked related tasks as complete in the documentation for the golden fixtures phase.
15 KiB
name, description
| name | description |
|---|---|
| phase-work | Берёт ровно одну фазу из среза в docs/phases/ и доводит её до конца — в своём git worktree и на своей ветке, чтобы над одним срезом можно было запустить несколько агентов параллельно. Используй, когда просят «сделай фазу 25», «возьми фазу», «реализуй фазу», «начни срез», «раздели срез между агентами», «work on the phase». Не для ревью уже написанного — там /phase-review, и не для правки одного файла по просьбе. |
Работа над фазой
Один запуск — одна фаза. Скилл берёт её из docs/phases/, делает целиком, проверяет по её же
критериям приёмки и отдаёт готовую ветку. Ничего сверх взятой фазы он не трогает: именно это
позволяет запустить несколько агентов на один срез и не получить кашу.
Критерии приёмки уже написаны. У каждой фазы есть «Задачи», «Тесты, без которых фаза не закрыта» и
«Критерий готовности», у проекта — инварианты в AGENTS.md, у среза — дизайн-док. Выдумывать
нечего, надо сделать и доказать.
Какую фазу брать
Номер передали в аргументе — берёшь его, вопросов нет. Так пользователь раздаёт фазы агентам:
/phase-work 25, /phase-work 26 в соседних окнах.
Номера нет — выбираешь сам:
- Читаешь
docs/phases/README.md: находишь первый срез, где есть ⬜. - Внутри среза берёшь первую ⬜, у которой закрыты зависимости — они перечислены в шапке фазы.
- Проверяешь, что её никто не взял:
git branch --list "phase/<номер>-*"пусто.
Статус в README.md — первый источник правды, ветка — только арбитр гонки. 🔄 значит занято,
✅ значит сделано, ⬜ значит свободно. Ветка может существовать и при ✅ — её просто не убрали после
слияния; это не заявка, а мусор, см. «Кто убирает ветку».
Фаза 🔄 — чужая работа в процессе. Не трогай её, даже если кажется, что там застряли.
Как застолбить
Ветка — и есть заявка, потому что git не даст создать её дважды:
git branch phase/25-golden-fixtures
Команда упала с «already exists» — значит фазу взял другой агент между твоей проверкой и попыткой. Не спорь, вернись к выбору и возьми следующую.
Ветка создалась — фаза твоя. Сразу пометь её 🔄 в docs/phases/README.md в основном дереве,
отдельным коммитом, состоящим только из этой строки. Это единственная правка, которую ты делаешь
вне своего worktree, и она нужна по двум причинам: соседние агенты видят занятое, а пустая свежая
ветка ещё ничем не отличается от слитой — по ней одной понять, что фаза в работе, нельзя.
Пометить 🔄 надо до первой строчки кода, а не после.
Где работать
В своём worktree, а не в общем дереве. Иначе два агента правят одни файлы и роняют друг другу сборку.
git worktree add <путь-в-scratchpad>/wt-phase-25 phase/25-golden-fixtures
Путь — вне репозитория; каталог scratchpad этой сессии подходит. Worktree внутри репозитория
засоряет git status и попадёт в глаза следующему ревью.
Дальше вся работа там. В конце worktree удаляется (git worktree remove --force), ветка остаётся.
Что нужно знать про worktree:
- Первая сборка полная, минуту-две. Это нормально, а не сломанный кэш.
binиobjу каждого worktree свои, поэтому параллельныеdotnet testне мешают друг другу.- Тесты хоста поднимают сервер со своей папкой сейвов внутри worktree — соседний агент их не видит. Порты Aspire раздаёт сам, конфликтов нет.
node_modulesне копируется. Для клиентской фазы либоnpm ci, либо скопируйnode_modulesиз основного дерева — это быстрее и достаточно.
Порядок работы
1. Прочитай три документа, прежде чем писать код. Саму фазу; дизайн-док среза, ссылка на него
в шапке среза в README.md; инварианты и «Things that will bite you» в AGENTS.md. Дизайн
объясняет почему так, а не иначе — без него легко сделать формально по задачам и мимо смысла.
2. Начни с тестов из списка «Тесты, без которых фаза не закрыта». Они уже сформулированы —
превращай каждый пункт в тест. Проект для теста выбирает не удобство, а «Testing policy» в
AGENTS.md: генерация людей — в HSchool.People.Tests, планировщик — в HSchool.Schedule.Tests,
эндпоинты — в HSchool.AppHost.Tests. Тест генератора в тестах хоста найдёт следующее ревью.
3. Делай задачи по порядку и отмечай - [x] по мере готовности. Галочка ставится, когда есть
код и подтверждение, а не когда «в целом написано».
4. Правь документы тем же коммитом, что и код. Это правило проекта, а не вежливость:
- меняется раскладка сообщения —
ProtocolCodec.cs,protocol.tsиdocs/protocol.mdвместе, плюс бамп версии; - меняется HTTP —
docs/protocol.mdтем же коммитом; - решение разошлось с дизайн-доком — правится документ, и в отчёте это названо явно.
5. Проверь то, что заявляешь. Прогоняешь тесты своей фазы и полный прогон. Не «должно работать», а «прогнал, вот результат».
Что считать сделанным
Фаза закрыта, когда каждый пункт «Тестов, без которых фаза не закрыта» существует отдельным тестом и проходит, и когда выполнен «Критерий готовности». Не раньше.
✅ в README.md ставится последним коммитом ветки, и в этом коммите — только строка статуса.
Отдельным потому, что при слиянии нескольких веток строки статуса конфликтуют, а мелкий коммит
разруливается за секунду.
Не смог закрыть пункт — оставь ⬜ и напиши в отчёте, что именно не вышло и почему. Полработы с честной пометкой лучше, чем ✅ с дырой: следующее ревью её всё равно найдёт, только дороже.
Кто убирает ветку
Ты — нет. Ветка это твой результат: пока её не слили, удалять нечего.
Порядок такой:
- Ты убираешь worktree — сразу, как закончил:
git worktree remove --force <путь>. Пока worktree держит ветку, её нельзя ни слить нормально, ни удалить. - Пользователь сливает ветку и удаляет её:
git branch -d phase/25-golden-fixtures. С-d, а не-D: git откажется, если что-то не слито, и это правильная защита. - Ветку забыли удалить — её уберёт следующий запуск скилла, но только при двух условиях сразу:
фаза стоит ✅ в
README.mdи ветка слита вmain.
git branch --merged main --list "phase/*" --format="%(refname:short)"
Оба условия обязательны, и вот почему: только что созданная ветка ещё не имеет коммитов, а значит
равна main и в этот список попадает. Удалить её по одной «слитости» — снести чужую только что
взятую фазу. Статус ✅ и есть то, что отличает доделанное от начатого.
Осиротевшие worktree (агент умер, каталог остался) подчищаются git worktree prune — это
безопасно, записи о несуществующих каталогах и так мусор.
Границы
- Только своя фаза. Заметил проблему в соседней — строкой в отчёт, не в диф. Реализация, которая походя переписала полпроекта, невозможна к просмотру глазами.
- Не сливай ветку. Слияние и порядок веток — решение пользователя, у него их несколько.
- Не переставляй чужие статусы в
README.mdи не трогай чужие 🔄. - Не меняй молча версию протокола, форму сейва и публичное поведение API — даже когда это очевидно правильно. Если фаза этого требует, так и написано в её задачах.
- Общие файлы трогай минимально.
AGENTS.md,docs/protocol.md,README.mdправят все ветки сразу — чем точечнее правка, тем дешевле слияние.
Окружение: что укусит
MSB3021/MSB3027, «блокирует этот файл» — у пользователя запущено приложение, оно держит DLL. Процесс не убивать. В своём worktree сборка обычно проходит, там своиbin; если всё же упёрлось — проверь то, что можно без сборки, и скажи об этом в отчёте прямо.- Концы строк. В репозитории есть и CRLF, и LF.
sed -iпереворачивает файл целиком: правка в три строки превращается в диф на тысячу. Правь скриптом, который читает и пишет сnewlineпустой строкой, а потом смотриgit diff --stat— внезапные сотни строк там, где ты правил три, это оно. - Heredoc и экранирование. Файлы с табуляциями, юникод-экранами и кавычками приезжают через
heredoc покалеченными. Пиши такие файлы инструментом записи файла, а не
catв шелле. - Тесты хоста делят один сервер и одну папку сейвов, поэтому каждый начинает с очистки списка. Не пиши тест, который полагается на пустую базу или на конкретный id школы.
- Состав школы зависит от её id, пока не сделана фаза 26. Тест, требующий у первого ученика двух родителей или конкретную фамилию, зелёный у тебя и красный в CI. Проверяй свойство, а не совпадение.
- Полный
dotnet testизредка падает целиком с нативной ошибкой вSimulation.Tests. Один раз — перепрогони; повторяется — это находка для отчёта. - Dev-сервер не запускать. Нужно посмотреть на UI — пользуйся уже запущенным приложением пользователя.
Измеряй, а не рассуждай
Когда вопрос звучит как «а хорошо ли ложатся часы» или «а сколько выходит неполных семей» — не рассуждай о коде. Напиши временный тест, который печатает реальные числа, посмотри и удали его. Час размышлений о поведении алгоритма стоит дороже и ошибается чаще, чем один прогон с цифрами. Числа из такого замера — лучшее, что можно положить в отчёт.
Отчёт
Коротко, в конце:
- какая фаза взята и на какой ветке лежит;
- что сделано — по пунктам задач, без пересказа кода;
- какие тесты добавлены, списком по одной строке;
- чем подтверждено: что прогнал и с каким результатом, числа замеров, если были;
- что осталось незакрытым и почему;
- что замечено за границами фазы.
Ветку не сливаешь и не удаляешь — она и есть результат. Worktree за собой убираешь, иначе ветку не получится ни слить, ни удалить.