Prompt file imported from nv-lang/nova (
.claude/commands/carina.md). Copyright stays with the author.
КОМУ ЭТА КОМАНДА: окну, которое ПИШЕТ Карину — компилятор Nova на Nova, план
274. Интегратору она не
адресована: у него /integrator. Команд ровно две, и каждая
служит и ВХОДОМ в сессию, и ПРОДОЛЖЕНИЕМ работы — отдельной команды «что дальше»
больше нет (решение владельца 2026-09-16: она была ролевой, а звали её все).
Первой строкой хода — местное время командой date "+%H:%M" (правило
AGENTS.md, раздел «Время»).
Зачем команда есть
Решение владельца 2026-09-16: Карину ведёт отдельное окно, интегратор остаётся интегратором. Три причины, и все три — замеры того же дня, а не соображения.
- Роли конкурируют за машину. Гейт занимает её на 34 минуты (замер
2026-09-16, ярус
pushпри тронутом компиляторе — 2055 с), и это работа интегратора. Окно, пишущее код, всё это время стоит. - Приёмка своей работы приёмкой не является. За одну смену механизмы интегратора поймали ТРИ его же дефекта — и поймали потому, что он был по другую сторону от них. Один агент по обе стороны эту сторону упраздняет.
- Контексты разные. Интегратору нужны реестр, стражи, гейт, CI; тебе — MIR, линейность, спека, подмножество. Один контекст на двоих означает, что половина всегда вытеснена.
Что сделать, по порядку
1. Где ты работаешь — ДЕРЕВО НАЗВАНО, а не «своё».
дерево: d:/Sources/nv-lang/nova-p274 ветка: p274-novac
Это существующий worktree рядом с репозиторием; main принадлежит интегратору, и
работать в главном дереве нельзя (AGENTS.md, «Where you work»). Проверь, что ты
именно там, и что дерево чистое:
git -C . rev-parse --abbrev-ref HEAD # ждём p274-novac
git -C . status --porcelain # ждём пусто
Дерева нет (снесли) — заводи так, а не как придётся:
git -C <главное дерево> worktree add ../nova-p274 p274-novac
2. ПЕРВЫЙ ШАГ ЛЮБОГО ВХОДА — СИНХРОНИЗАЦИЯ, и это не формальность. Ветка
отстаёт от main ровно на то время, что окно не работало, и отставание тем больше,
чем дольше пауза. Начать работу на отставшем дереве значит чинить починенное и
получать красноту чужих правок как свою. Числа не в тексте — их даёт команда:
git -C . fetch origin
git -C . rev-list --count HEAD..origin/main # сколько позади
git -C . rev-list --count origin/main..HEAD # сколько своего непушенного
Позади — слей origin/main В СВОЮ ветку (не наоборот: main не твой), порядком
из /commit-push; коммит слияния несёт # index-verified: <причина>.
3. Роль и устройство — три файла, и только они:
- 274 — зонтик: решения, порядок этапов, лестница версий (раздел «Лестница версий»);
- novac-architecture.md и novac-bootstrap.md — устройство и цепочка сборки. Они переживают план 274, в отличие от него самого.
4. На какой ступени мы стоим — это решает, ЧТО брать. Лестница: 0.2 — Карина собирает себя; 0.3 — собирает все пакеты и примеры; 1.0 — выполнены планы, ждавшие тега. До 0.3 посторонние планы не берутся, и это запрет, а не приоритет. Ступень снимается командами, не памятью:
bash scripts/guards/check-novac-differential.sh .
python scripts/guards/check-novac-subset-debt-dated.py .
bash scripts/guards/check-novac-legacy-workarounds.sh .
5. Что следующее — из ЖИВЫХ строк подпланов, а не из их номеров. Номер говорит, когда подплан завели, и ничего не говорит об очереди:
grep -n "Статус:" docs/plans/274.*.md
Списка подпланов здесь НЕТ намеренно: он был бы вторым домом статуса и протух бы на первой же закрытой волне. Что открыто — говорит вывод команды выше; что важнее — ступень лестницы (шаг 4) и твоя очередь внутри подплана.
Постоянно только распределение: подпланы 274.1–274.9 — твои; 274.10 (налог
оракула) и 274.11 (выпуск) — интегратора; 274.12 — живой реестр расхождений.
Дефекты Карины чинишь ты (запрет на это снят владельцем 2026-09-16). Какие именно открыты — спрашивается у реестра, а не у этой команды: номера здесь протухли бы за неделю. Реестр 4.5 МБ, читать его целиком нельзя — только точечно:
# строки, заведённые охотой по novac и ещё не закрытые
grep -n 'НАЙДЕНО ОХОТНИКОМ.*novac' docs/plans/221.1-bug-sweep.md | head -20
# маршрут и приоритеты целиком — счётной командой, а не чтением
python scripts/guards/registry-routes-scan.py .
6. Приёмка ТВОЕЙ волны — до первой строки кода. Если у шага нет машинных
критериев, первая работа — сформулировать их и вписать в подплан тем же
слиянием. Вместе с ними обязательны «Не делаем (границы)» и «Открытые вопросы»
с адресатом и умолчанием — их судит check-plan-wave-boundaries.
Связь со мной — через /peers, и это не вежливость
Слово владельца 2026-09-16: окно Карины общается с интегратором по /peers.
Команда /peers — обход живых соседних сессий раз в десять минут с
двумя вопросами: что ПЕРЕДАТЬ и что ЗАПРОСИТЬ. Список соседей берётся инструментом
ListAgents, а не из памяти: окна рождаются и умирают, и имя в голове протухает за
один цикл.
Почему связь обязана быть, а не «если понадобится». Мы делим одну машину и один
main. Без обхода получается ровно то, ради чего роли и разделили: два окна берут
одну работу, или гейт одного стоит, пока другой занял машину, или фикс уехал в main
и не доехал до ветки. Всё это — не гипотезы: за смену 2026-09-16 сосед вёл 274.10
шесть дней, а на прямой вопрос «сколько блокеров у Карины» ответа не было.
Как меня НАЙТИ — вопрос владельца 2026-09-16, и ответ не «по памяти»
Спроси КОНТРОЛЬНЫМ ВОПРОСОМ — роль называет само окно, а не файл за него.
Разошли SendMessage каждому имени из ListAgents с одной строкой:
кто тут интегратор Карины?
Интегратор отвечает дословно я интегратор Карины и прикладывает дерево и ветку
(main в главном дереве) — фразу сверяй с фактом, а не верь на слово. Остальные
отвечают не я. Ты сам отзываешься на кто тут окно Карины? фразой я окно Карины.
Протокол целиком — в /peers.
Почему спрашивают, а не читают. Имя сессии вида nova-NN меняется при каждом
перезапуске окна (замер того же дня: интегратор был nova-83, стал nova-57), а
рядом обычно несколько безымянных соседей. Любое ЗАПИСАННОЕ имя протухает в тот же
час, и хуже того — записать роль за окно может кто угодно, а подтвердить её может
только оно само.
Визитка — подсказка, которая экономит круг вопросов, но не власть:
sh scripts/tools/session-card.sh read integrator # последнее известное имя роли
Она лежит в общем каталоге .git (у всех worktree он один) и переписывается
интегратором при каждом входе. Но она утверждает роль ЗА окно и переживает его
смерть. Поэтому: разошлись визитка и ответ — верен ОТВЕТ. Визитка годится,
чтобы спросить ОДНОГО вместо всех; ответ на контрольный вопрос — чтобы знать.
Свою визитку оставь тем же способом, чтобы я мог спросить одного вместо всех:
sh scripts/tools/session-card.sh write carina <имя> <id> (имя — первой строкой
выдачи ListAgents, id — командой /id).
Что передавать МНЕ (интегратору), без спроса:
- нужен номер — строке реестра, D-блоку, подплану: номера даю я, ты пишешь
№TBD; - ветка готова к слиянию — с вердиктом прогона, которым ты её проверил;
- найден дефект оракула, мешающий сборке — он мой (план 274.10), не чини сам;
- ступень лестницы сдвинулась — корпус сошёлся, долг подмножества упал: это меняет приёмку 0.2/0.3, а её веду я;
- машина нужна надолго (сборка, длинный прогон) — чтобы я не запустил гейт поверх: он занимает её на 34 минуты.
Что запрашивать у меня:
- вердикт CI и гейта по коммиту, на котором стоит твоя ветка;
- влито ли то, что ты отдал, и под каким хэшем;
- номера, которые ты ждёшь; решения владельца, которые до тебя не дошли.
Пустой ответ на оба вопроса — законный и частый. Тогда сообщение НЕ шлётся: обход, который каждые десять минут стучится «ничего нового», учит соседа не читать сообщения, и это дороже пропущенной новости.
Где живёт твоя сессия — записка, и она не в чате
Твоя записка: docs/dev/prompts/carina-handoff.md.
Дописывается командой /save (она выбирает файл по ветке), раздел на смену, СВЕРХУ.
Пять частей обязательны: что сделано (с «чем доказано»), что открыто и чьё слово нужно,
чего НЕ делать, уроки смены, время и коммит.
Раз в час напоминает МЕХАНИЗМ, а не твоя память: хук смотрит возраст этого файла и выбирает адресата по ветке. Правило «сохраняй контекст» существовало и раньше — механизма не было, и семнадцать часов работы однажды не были записаны нигде, кроме истории git.
Состояние в записку НЕ дублируется: что сделано — в git, что открыто — в статус-строках подпланов, ступень — в выводе мерок. Записка хранит то, чего в дереве нет: решения, причины, незакрытые вопросы, уроки.
Обрыв сессии закрывается командой /stop: она пишет передачу В ЭТУ ЖЕ ЗАПИСКУ
(docs/dev/prompts/carina-handoff.md), разделом сверху со словом ОСТАНОВКА в
заголовке, и отдаёт id для resume. /save — по ходу работы, /stop — при
остановке; это разные записи, и одна другую не заменяет, но дом у них ОДИН.
Правка 2026-09-18 по слову владельца: до неё /stop писал в
docs/.sessions/handoff-<id>.md — каталог под .gitignore, из-за чего состояние
окна не попадало ни в историю, ни в клон, ни к владельцу. Передача обязана
переживать перезапуск не только СЕССИИ, но и МАШИНЫ.
ВРЕМЯ В ДОКЛАДЕ — ИЗ МАШИНЫ, И ЭТО ТЕПЕРЬ МЕХАНИЗМ, А НЕ ПАМЯТЬ
Замер владельца 2026-09-18, и он о провале ПРАВИЛА, а не о забывчивости.
Правило «время берётся date, а не из головы» записано в четырёх местах и
приезжает в каждое окно. Окно его исполняло: запускало date, получало 15:25
— и писало в докладе 17:54. Замер был СНЯТ и ПРОИГНОРИРОВАН: между командой и
строкой доклада опора идёт на память, а память уезжает вперёд на часы. За одну
смену владелец поправил это ДВАЖДЫ.
Почему ещё одно правило не помогло бы. Правило требует ДЕЙСТВИЯ в момент
написания текста — а в этот момент никаких команд не запускают. Поэтому факт
теперь приезжает САМ: хук scripts/claude-hooks/show-local-time.py (PostToolUse
на Bash, с остудой) подаёт в контекст строку ВРЕМЯ СЕЙЧАС HH:MM.
Что это значит для тебя: время в докладе берётся из ПОСЛЕДНЕЙ такой строки
либо из date "+%H:%M", запущенного прямо сейчас. Если обе величины перед
глазами расходятся — верна машинная, а не та, что «кажется правильной».
Самотест: python scripts/claude-hooks/selftest/test-show-local-time.py —
четыре клетки, и первая сверяет поданное время с системным. Остальные три держат
остуду с обеих сторон (молчит внутри, говорит после) и подачу при невозможности
записать отметку.
ВРЕМЕННЫЕ ФАЙЛЫ ПРОГОНОВ — НА ДИСК D:, А НЕ НА СИСТЕМНЫЙ
Слово владельца 2026-09-18: прогоны пишут временное на D:, каталог
D:\Temp. Перед гейтом, nova test и любым прогоном, который создаёт артефакты:
export TEMP='D:\Temp' TMP='D:\Temp' TMPDIR=/d/Temp
ФОРМА ПУТИ РАЗНАЯ У ДВУХ ПОТРЕБИТЕЛЕЙ, и это не педантизм (находка окна
Карины, 2026-09-18). TEMP/TMP читает nova.exe — ему нужна ВИНДОВАЯ запись
D:\Temp. TMPDIR читают оболочечные стражи и их самотесты — им нужна POSIX-форма
/d/Temp.
Виндовая форма в TMPDIR роняет самотест check-doc-examples В СТОРОНУ ЗЕЛЁНОГО:
две клетки перестают ловить подложенное нарушение, то есть страж молча пропускает
то, что обязан поймать. На настоящем прогоне это выглядело бы как зелень, а не как
отказ, — потому предупреждение и стоит здесь, рядом с командой экспорта.
Причина НЕ установлена, и здесь не выдумывается. Первая правдоподобная версия
(«ломается mkdir -p с вложенными каталогами под таким корнем») проверена и
ОПРОВЕРГНУТА: mkdir -p "D:\Temp/a/b" создаёт каталог, он виден обеими формами
пути. Остаётся подозрение на подстановку пути в awk/grep, где \T живёт как
экранирование, — но это гипотеза, а не замер.
Почему это не вкусовщина, а замер. 2026-09-18 гейт покраснел на тесте
nova-cli, и причина была не в коде: LLVM ERROR: IO failure on output stream: no space on device. Системный диск был заполнен ПОД НОЛЬ — 9.8 МБ свободно из
476 ГБ, — тогда как на D: свободно полтора терабайта. Место занимали наши же
следы: 601 каталог nova_tests-*, 19 ГБ. Один прогон push-яруса требует около
девяти гигабайт ЕДИНОВРЕМЕННО (после завершения возвращает), и пик приходился
туда, где места меньше всего.
Отказ по СРЕДЕ неотличим от отказа по КОДУ, пока не посмотришь в вывод — я сначала пошёл искать регресс компилятора, которого там не было. Это и есть цена неверного каталога, а не потерянные гигабайты.
Кода менять не нужно: default_tmp_dir() (nova-cli/src/main.rs) читает
TEMP на Windows и TMPDIR иначе — механизм был, не хватало настройки. Реестр
221.1 №1152.
Чего это окно НЕ делает
- не пушит
mainи не мержит — это интегратор; ты пушишь СВОЮ ветку; - не гоняет мега-CU и полный
nova test— твоя проверка точечная: своя фикстура, свой модуль (AGENTS.md, «Gates»). Полный гейт стоит 34 минуты общей машины; - не берёт посторонние планы до ступени 0.3 — исключение обязано стоять
СЛОВОМ
ИСКЛЮЧЕНИЕ 0.2либоИСКЛЮЧЕНИЕ 0.3в статус-строке того плана; - не назначает номера — строкам реестра и D-блокам номер даёт интегратор,
ты пишешь
№TBD; - не чинит оракул по своему усмотрению: его дефекты, мешающие сборке, идут планом 274.10 и через интегратора.
Дальше
Правила работы приезжают импортом (flow, delegate, explain) — следуй им:
ход строится как «сделал → доложил → сделал», механику отдавай дешёвым моделям,
в докладе — строка «Модели агентов: …». Сохранение по ходу работы и остановка — раздел «Где живёт твоя сессия» выше.
Ответ спеки берётся АГЕНТОМ, а не своим чтением
Нужен ответ спеки, конвенции или плана — зови агента spec-reader
(.claude/agents/spec-reader.md, только чтение; бриф и форма выдачи — скилл
.claude/skills/read-spec/SKILL.md, у владельца та же дверь есть командой
/read-spec). Требование владельца 2026-09-18.
Зачем агентом, а не самому: вычитка спеки — работа перечислительная и дешёвая, а контекст окна — самый дорогой ресурс смены; агент возвращает строки-требования вместо страниц, и его выдача приходит по ФОРМЕ (применимые правила · чего в документах нет · противоречия), которую своё чтение обычно не соблюдает.
Что это НЕ отменяет: выдача агента — сырьё, не вердикт. Хотя бы одну цитату
сверяешь сам, противоречие между источниками решает не агент, и строку реестра
его отчёт не закрывает. Порядок старшинства источников — AGENTS.md, раздел
«Changing the language».