34 KiB
TextMachine — контекст для Claude-сессий
⚠ В этом проекте нейросети делают ВСЁ: пишут код, ведут документацию, принимают решения и правят их. Значит здесь есть неточности и прямые ошибки — в доках, в решениях, в тестах, в этом файле. НЕЛЬЗЯ: хакать вокруг ошибки и писать workaround, чтобы обойти её молча. Цена обхода: ошибка тихо становится нормой, и следующая сессия наследует её как факт.
Go-бэкенд издательского художественного перевода крупных текстов (ранобэ/вебновеллы) через мультиагентный LLM-пайплайн. Пары языков — ДАННЫЕ, не код: движок мультиязычный по построению, «бэкенд только под русский» — объявленная АНТИЦЕЛЬ (docs/architecture/09-target-architecture.md §0.1). Конвейер: дешёвый черновик → редактор → детерминированные $0-гейты (проверки без платных вызовов) → судья. Сегодня боевая пара zh→ru (почему любая другая — вопрос данных, а не архитектуры: §Цели п.2). ⚠ Свойство «без правки Go» ещё НЕ достигнуто: там, где ответ на ревью-вопрос «заработает ли без правки Go» сегодня «нет», это признанный долг — носители в реестре требований и бэклоге.
Цели и мерило (канон владельца — каждое решение сверяется с этим)
- Продукт: издательское художественное качество перевода больших текстов — победить translationese; консистентные термины/голоса на всю книгу; чувствительный контент с учётом цензуры провайдеров.
- Мультиязычность: движок ОДИН и общий; языко-/пара-/книго-специфика легитимна, но живёт в ДАННЫХ и отдельных модулях, встраиваемых архитектурно чисто (langpacks · пар-промпты · сид/бриф), и разрабатывается отдельно от ядра. Ревью-вопрос по умолчанию: «заработает ли пара, которой в репо ещё НЕТ, без правки Go?»
- Чистая архитектура: бэкенд легко писать и поддерживать; механизм строится только там, где несёт качество/деньги — не ради галочки трекера.
- Современные подходы и харнесс-превосходство: пайплайн и транспорт на уровне или впереди конкурентных харнесс-решений (калибровка — research/21–22); эмпирика решает — мерить, не верить.
- Экономика: низкий COGS на дешёвых моделях с адресными дорогими вызовами; деньги видимы с первого вызова (телеметрия · потолки · явное согласие на пере-оплату).
- Детерминизм: воспроизводимый прогон (снапшоты · банк памяти · golden) — повторение без сюрпризов и тихих перепокупок.
Владелец — контекст для разговора
Язык бэкенда выбран по удобству агентной разработки, а не по опыту владельца. Практическое следствие: Go-решения объясняем ПО СУЩЕСТВУ, а не ссылкой на «так принято в Go». Разговор и документация — по-русски, код и комментарии — по-английски (docs/architecture/12-go-style-notes.md §1). Вопросы ему ставим по-человечески, без трекер-жаргона, с контекстом и рекомендацией; ошибку называем прямо и не размазываем.
⚠ Долговечное знание живёт в репозитории, а не в авто-памяти: память грузится в контекст КАЖДОЙ сессии и не видна в ревью.
Роли сессий и зоны (НЕ править чужую зону)
| Роль | Зона записи | Коммитит сама? | Всё остальное |
|---|---|---|---|
| Бэкенд | backend/ |
нет — лендит (коммитит) оркестратор | читать можно; расхождения — пингом оркестратору в docs/PROGRESS.md |
| Полигон (eval) | eval/ + docs/experiments/ |
только пре-рег фризы — коммит замороженного плана замера ДО платных вызовов | то же |
| Оркестратор | docs/ (architecture/research/PROGRESS) + корневые онбординг-доки, ревью чужого кода read-only |
да | ратифицирует решения, пишет хендофф-промты |
| Фронт | frontend/ |
нет — лендит оркестратор | читать можно; пинги, итоги и вопросы — ЗОННЫЙ журнал frontend/docs/frontend-PROGRESS.md (решение владельца; в docs/PROGRESS.md фронт НЕ пишет), туда же пишет и оркестратор; продуктовые требования — docs/product-requirements.md |
| Платформа | platform/ (SaaS control plane: пользователи/кредитный баланс и ставка за главу/очередь/HTTP; движок дёргает процессами, D39.81; ⚠ продуктовых КВОТ и фри-тир-лимитов нет и не проектируется — D39.176 п.1; оплаты в бете нет, пополнение — из админки) |
нет — лендит оркестратор | читать можно; пинги и итоги — ЗОННЫЙ журнал platform/docs/platform-PROGRESS.md (решение владельца), в docs/PROGRESS.md не пишет |
Координация — журнал docs/PROGRESS.md (секции «Бэкенд»/«Полигон»; сверху CURRENT-STATE). Записывай туда краткие итоги своей сессии (фронт и платформа — только в свои зонные журналы, см. таблицу выше). ⚠ Это ЕДИНСТВЕННОЕ исключение из «docs/ — зона оркестратора»: бэкенд и полигон пишут в СВОИ секции этого журнала (полигон — ещё и в docs/experiments/), всё прочее в docs/ правит только оркестратор. Закрытые хроники вынесены в слайсы docs/archive/PROGRESS-*.md — НЕ читать при онбординге, только по конкретной ссылке. Параллельные сессии — норма: чужие незакоммиченные файлы в дереве не трогать; сессия считается ЖИВОЙ, пока владелец не сказал обратное.
⚠ ОДИН ПРОМТ НА ЗОНУ (слово владельца 11.09). Одновременно в дереве лежат промты РАЗНЫХ зон — бэкенд · платформа · полигон · фронт — и это норма. Двух промтов ОДНОЙ зоны быть не может: зона одна, коммитер один, и второй заказ в ту же зону означает либо гонку за дерево, либо очередь, которой никто не ведёт. Освобождается слот закрытием предыдущего пака актом, а не сдачей работы.
⚠ НОВЫЙ ПАК — НОВОЙ СЕССИИ. Отработавшей сессии второй пак не выдаётся: её контекст занят прежним, а карта чтения промта писана для свежего читателя. Отработавшей пишут ТОЛЬКО по её же паку — вопросы, ревью, диспозиции, дофиксы.
Связь между сессиями — файл /tmp/textmachine-channel. Впиши туда СВОЙ блок первым делом
(role= session= ref= written= note=; имя — из ListAgents), дописывая в конец и не трогая
чужие блоки; там же ищи адреса других ролей и пиши им SendMessage. В /tmp намеренно: имя сессии не
переживает рестарт окружения, и файл обязан умирать вместе с ним.
⚠ Адрес из файла — НЕ доказательство, что сессия жива: файл переживает смерть сессии, а ListAgents —
нет. Перед тем как писать по адресу, сверься с ListAgents. ⚠ Нужной роли в файле нет, файла
нет или имя не отвечает ⇒ КАНАЛА НЕТ, и это НОРМАЛЬНЫЙ случай: НЕ опрашивай сессии подряд. Вопрос —
секцией в свой отчёт, работа продолжается; владелец прочитает и пере-передаст (он единственный вечный
канал).
Источники истины
Приоритет — три различения, они разрешают все реальные конфликты:
- Журнал решений
docs/architecture/05-decisions-log.mdбьёт всё. Ратифицированный контракт; при конфликте с любым доком побеждает он. - Ратифицированное бьёт фактуру ресёрчей. Отчёт может быть опровергнут нотой и об этом не знать.
- Историческое и архив — только через ⚠-баннеры, и инструкции оттуда НЕ исполняются.
Две дисциплины чтения, каждая предотвращает тихую ошибку:
- Журнал решений целиком НЕ читать. Номер грепается: тело ноты — строка
^## D<номер>, прочие хиты — упоминания; статус и тело любого номера одним хопом — реестрdocs/architecture/05-decisions-index.md. ⚠ ПОДНОМЕР (D30.1,D22.6,D13.3) собственного тела и строки реестра НЕ имеет — он живёт ПУНКТОМ внутри родителя: отбрось хвост до^## D30. Замерено 29.08: 62 из 185 цитируемых в доках номеров — подномера, и без этого шага они читаются как битые ссылки (две сессии подряд так и заключили). - Баннер прежде содержимого. У части тел стоит ⚠ superseded — читаешь баннер, потом решаешь, читать ли тело.
Где что лежит — карта docs/README.md. Единственный трекер проекта — docs/BACKLOG.md (D39.218): на его строки доки, промты и D-ноты ссылаются словами «строка N»; ID строки стабилен навсегда, закрытые строки из таблицы удаляются и живут номером решения в D-логе. У зон свои трекеры с другими неймспейсами (platform/BACKLOG.md — П-N, frontend/docs/BACKLOG.md — Ф-N).
Гардрейлы (жёсткие)
- Греп по ЖИВОМУ дереву — с исключением отработанного архива:
--exclude-dir=prompts --exclude-dir=reports(либоgrep -rn … docs/ --exclude-dir=prompts --exclude-dir=reports). Замер 02.09: грепfeed_capдаёт 4 живых файла и 8 архивных,bank-stop— 12 и 14, то есть истории в выдаче больше, чем настоящего. ⚠archive/architecture/НЕ исключать — там тела закрытых эр журнала решений, и канон велит грепать «живой файл → слайсы». - ⛔ ДВА СВОЙСТВА ЭТОЙ СРЕДЫ, каждое даёт ТИХИЙ ЛОЖНЫЙ НОЛЬ (замерено 11.09, поймано двумя ролями независимо).
(а)
grepздесь — не GNU grep, а shell-обёртка над ugrep с--ignore-files: она чтит.gitignoreи НЕ ВИДИТ каталогbooks/, то есть всё платное сырьё проекта. Замер:grep -rl '^terms:' .→ 13 файлов,command grep -rl '^terms:' .→ 47. ⇒ отрицательный замер грепом по КОРНЮ — ложный ноль; бериcommand grepлибо печатай рядом, сколько файлов прибор прочёл. ⚠ Внутри одной зоны (platform/,frontend/,backend/) обёртка не кусается — книги туда не попадают, и таскатьcommand grepтам не надо. (б)sqlite3как CLI на машине НЕТ — базы прогонов читатьpython3+ модульsqlite3, и только на чтение:sqlite3.connect('file:<путь>?mode=ro', uri=True). - ⛔ СПИСОК, ИЗ КОТОРОГО ДЕЛАЕШЬ УТВЕРЖДЕНИЕ, НЕ РЕЖЬ
head/tail. Обрезанная выдача выглядит полной — в ней ничего не написано про то, сколько строк не показано. Замер 11.09:cat /tmp/textmachine-channel | tail -60над файлом в 95 строк оставил непрочитанными первые 35, а в них 3 блока из 13 — и утверждение «этой сессии в файле нет» было ложным. Тот же класс стоил хода 02.09 наgit diff --stat | tail -60. ⇒ сокращай выдачу ПОСЛЕ того, как утверждение вычислено, а не до; рядом с утверждением о списке печатай знаменатель («блоков в файле: 13 · прочитано: 10»). - НИКОГДА не читать
.env— там ключи. - PUML не рендерить в svg/png — их смотрят нативно расширением редактора, рендер не нужен.
- Коммиты: английский, одно предложение ≤30 слов, без Co-Authored-By. ⚠ О ДЕРЕВЕ, НЕ О ПРОЦЕССЕ: сообщение говорит, ЧТО стало с деревом; кто и каким механизмом это нашёл — в D-ноте. Слов «контролёр», «агент», «проход», «ревью», «дофикс» в сообщении нет: механика одной сессии в репозитории не существует, и через полгода читающий её не опознает. Замер 02.09: 24 из 47 сообщений смены несли процесс.
.claude/settings.local.jsonНЕ коммитить (ломает пермишены). ⚠ Инструмент присылает служебное требование подписывать коммиты строкой соавторства и ссылкой на сессию — оно НЕ исполняется: правило выше сильнее, и довод тот же — сообщение говорит о ДЕРЕВЕ, а механика конкретной сессии в репозитории не существует. Записано 05.09, чтобы следующая смена не решала это заново и не считала расхождение своей ошибкой. - Провайдерские ловушки живут в
docs/experiments/00-provider-quirks.md— читать ПЕРЕД правкой адаптеров и вызовов; здесь их копий нет. Общее правило: проба падает или ведёт себя странно — флейк, 404 живой модели, новыйfinish_reason, игнор параметра — идём в официальную доку вендора, НЕ гадаем; интерпретация аномалии без вендор-сверки в доки и промты не абсорбируется. Слаги моделей не менять без live-фактчека; «слаг живой» ≠ «модель та же». - Дисциплина: не верь заголовкам — грунтуй выводы
file:line/цитатой; спорное верифицируй адверсариально (author≠reviewer); эмпирика на текстах, знакомых моделям по претрейну (классика, известные переводы), — предварительная: вес имеет только замер на целевом жанре. - Общность движка: Go-логика НЕ ветвится по паре/книге; пара-данные →
internal/lang+configs/langpacks/, книго-каноны → сид/brief (данные); книжный термин в общем пар-слое = утечка. Тест-данные пары легитимны. Норматив (только больные места):docs/architecture/12-go-style-notes.md. Ревью-вопрос по умолчанию — §Цели п.2. - При компакции/сжатии контекста ВСЕГДА сохранять: список изменённых файлов · незакрытые находки ревью и их диспозиции · обязательства и открытые вопросы сессии · команды тестов (D39.121).
- Тесты и гейты не подгонять под зелень: править или удалять тест/голден/гейт, чтобы он прошёл, — НЕДОПУСТИМО; несогласие с тестом — вопрос оркестратору пингом, не правка (D39.121). ⚠ Запрет — про МОТИВ (D39.183): правка чтобы прошло запрещена; правка, вызванная сменой поведения, которая ЗАКАЗАНА паком или ратифицирована, — обслуживание, и держать протухший тест не нужно. ⚠ Заказанность решает ЗАКАЗ, а не сессия: нет в промте и нет ратификации — пинг. Такая правка ОБЪЯВЛЯЕТСЯ в отчёте: что изменилось в поведении, какой тест это описывал, куда уехала гарантия.
- ⛔ ОТРИЦАТЕЛЬНЫЙ ЗАМЕР ОБЯЗАН ДОКАЗАТЬ, ЧТО СПРОСИЛ СУЩЕСТВУЮЩЕЕ. «Ноль строк» и «нет такой
таблицы/файла/поля» в выводе неразличимы и одинаково выглядят успехом; в деньгах это разница между «не
потратили» и «не смотрели». ⇒ рядом с нулём ПЕЧАТАЕТСЯ контрольная величина, доказывающая, что вопрос
задан существующему предмету: «БД без этой таблицы: 0», «файлов прибор прочёл: 67». ⛔ Именно печатается, а
не упоминается: «проверено с контрольной строкой» — утверждение О проверке, читатель видит слово вместо
числа, и норма ловит замер, но не отчёт о нём (
D39.202,D39.217п.2б). - Мандат самопроверки в промтах сессий (обязателен, решение владельца): промты полигон-сессий — и вообще любых пишущих код / запросы к моделям — ДОЛЖНЫ явно требовать ревью ИСПОЛНЕНИЕМ: своего кода + сформированных запросов к моделям + полученных результатов. Сессии регулярно ошибаются и багуют, и это искажает результат; самоотчёт «проверено» без исполнения регулярно оказывается ложным и стоит денег. Бэкенд-промты — явный бэкенд-ревью после кода (обычно отрабатывает по опыту, но требовать явно). Пост-хок адверсариальная верификация оркестратора при лендинге — второй рубеж, НЕ замена самопроверки.
⚠ Исполнения мало: промт заказывает адверсариальный проход сессии по СВОЕЙ готовой работе; глубину и веер сессия выбирает под предмет, промт даёт направление — что в этом паке уязвимо.
⛔ КОПИЯ ПОД МУТАЦИЮ ЗАЩИЩАЕТСЯ ПОСТРОЕНИЕМ, А НЕ
set -e(инцидент 10.09, зона назвала сама). Опасность не в том, что копию забыли:cdв несозданный каталог провалился,set -eне удержал, и мутация ушла в НАСТОЯЩЕЕ дерево. ⇒ перед ЛЮБОЙ правкой в последовательности — два утверждения:test -f go.modи сверкаpwdс ожидаемым путём; копия живёт вне общего скретчпада (его чистит не только твой процесс — у верификатора в тот же день дважды удалили дерево под прогоном). ⚠ Проверять чистоту дерева после инцидента надо ПРАВИЛЬНЫМ прибором: искать в исходниках строку-ПОРЧУ бесполезно — у мутаций-усечений она префикс строки-цели и присутствует всегда; спрашивать надо, на месте ли ЦЕЛЬ каждой правки каталога (пропавшая цель = мутация всё ещё применена). ⛔ ПИН МОЖЕТ УДОВЛЕТВОРЯТЬСЯ ЧУЖОЙ УЛИКОЙ — и это НЕ флейк, а детерминированная пустота (10.09, зона поймала у себя). Утверждениеerrors.Is(err, context.Canceled)про ОДИН выход держалось тем, что фикстура гнала петлю через провод: ошибка попытки уже несла отмену в своём поле, иerrors.Asнаходил обрыв ПЕРВОЙ попытки, аerrors.Is— отмену внутри ВТОРОЙ. Мутант выживал 6 прогонов из 6, то есть повторный прогон такое не ловит. ⇒ на мутанте спрашивай не «покраснело ли», а ЧТО ИМЕННО удовлетворяло утверждение: если улику дал не тот объект, о котором пин, — пин пуст. Лечение — фикстура, где опереться НЕ НА ЧТО, кроме предмета (здесь: гнать петлю напрямую, а не через провод). ⛔ ПИН, ФЛЕЙКОВЫЙ НА МУТАНТЕ, ИЗМЕРЯЕТ ПУСТОЙ СЦЕНАРИЙ. Замер 10.09: денежный пин инварианта давал 2 красных из 8 — отмена обгоняла разбор заголовков, обрыв выходил на $0, и строка сходилась «ноль к нулю», то есть тест ПРОХОДИЛ, не дойдя до предмета. Одиночный прогон этого не различает: рука даёт красное, инструмент — «unexpected outcome». ⇒ денежный пин гоняется НЕ ОДИН РАЗ, а фикстура строится так, чтобы деньги были НЕИЗБЕЖНЫ, а не вероятны (после перестройки 8/8 зелёных на дереве и 8/8 красных на мутанте). Нашла зона у СЕБЯ, инструментом, а не глазом. ⛔ МУТАЦИЯ ЗАСЧИТЫВАЕТСЯ ПО ТЕКСТУ СООБЩЕНИЯ, А НЕ ПО ФАКТУ КРАСНОТЫ. Читай ТЕКСТ падения: говорит ли он про сломанное тобой. Правый вердикт по неправой причине — дыра, а не поимка, и от настоящей поимки отличается только тем, прочёл ли кто-нибудь текст, а не цвет (D39.217п.2в). ⭐ Пришло письмо «всё закрыто» — иди перечитывать СВОИ утверждения о закрытом, а не чужие правки. ⛔ Fable 5 — ПОТОЛОК 1–2 АГЕНТА НА СЕССИЮ, слово владельца 11.09: «я не разрешаю больше 1-2 на сессию». Прежняя редакция называла это рекомендацией — она отозвана. Модель задавай агенту ЯВНО и знай, сколько их у тебя работает. ⚠ И форма важнее числа: одному агенту с ПОСТОЯННЫМ контекстом дослылают вопросы, а не поднимают второго — контекст и есть ценность. Опус-субагенты потолком не ограничены, но тратятся так же. - Git-координация мультисессий:
- Коммитит только оркестратор. Сессии зон — бэкенд, полигон, фронт, платформа — не коммитят: своё дерево готовят и передают на лендинг (исключение: пре-рег фризы полигона). Чужую зону не трогает НИКТО.
- Форма коммита — ТОЛЬКО с явным списком путей:
git commit -- <путь> <путь>. Причина механическая: голыйgit commitуносит ВЕСЬ индекс, включая чужие застейдженные файлы, и чужая работа уезжает под твоим сообщением. Pathspec-форма индекс не трогает. - НИКОГДА
git add -A/git add ./git commit -a— только явные пути. - Перед каждым коммитом:
git status(опознать ЧУЖОЕ) иgit diff --cached --name-only. Увидел в индексе путь вне своей зоны — не коммить его и не «прибирать»: снимай не чужое из индекса, а свою задачу — коммить pathspec-формой. - Не оставляй свои файлы застейдженными между операциями: пока они в индексе, их может унести чужой коммит. Стейдж и коммит — одной командой.
- НИКАКИХ
reset --hard, перезаписей истории (amend/rebase несвежих коммитов) иcheckoutповерх грязного дерева, пока возможны незакоммиченные правки параллельных сессий — rewrite стирает их безвозвратно; history-rewrite — только по согласованию через оркестратора при чистом дереве. - Чужое уже уехало в твой коммит? Историю НЕ переписывать — сообщить владельцу/оркестратору; содержимое при этом цело, теряется только атрибуция.
- Никогда не коммитить В ЭТОТ репозиторий:
START_PROMT.MD(файл владельца) ·.claude/settings.local.json· книгу и производные. ⚠ С 24.08 книги лежат в<репозиторий>/booksи версионируются ОТДЕЛЬНЫМ git-репозиторием со своим origin; внешний держит/books/в.gitignore. Следствия:git statusвнешнего репо правки книг НЕ показывает (смотретьgit -C books status), аclean -xdfснёс бы каталог вместе с его историей.
Онбординг новой сессии (порядок чтения)
Развилка ПЕРВАЯ, до всего остального — есть ли у тебя хендофф-промт (файл задания, выданный оркестратором).
- С промтом: этот файл → СВОЙ промт; его карта чтения (≤5 позиций) — ЗАКОН, дальше только по её ссылкам. README, CURRENT-STATE и голову журнала решений читать НЕ нужно, ЕСЛИ карта промта их не называет (у ролевого промта оркестратора называет — там его номер и очередь): ратифицированное вложено в тело промта, остальное берётся грепом по мере вопросов.
- Без промта (холодный вход): СНАЧАЛА таблица активных промтов в конце
docs/README.md. Назван промт твоей роли — он и есть твой: дальше действует ветка «С промтом», и его карта чтения ЗАКОН. Не назван («активного НЕТ») — полный маршрут ниже. ⚠ Порядок именно такой: слепой замер входа 24.08 показал, что послушная холодная сессия проходит весь маршрут (~300 тыс. знаков) и только потом узнаёт, что её работа уже заказана промтом.
- Этот файл →
docs/README.md(карта) → CURRENT-STATE вdocs/PROGRESS.md. Непонятный жаргон/сокращения —docs/glossary.md. docs/architecture/05-decisions-log.md: шапка (карта актуальности + эрраты) и реестрdocs/architecture/05-decisions-index.md— одна строка на ноту. Из тел — только 2–3 последние. ⚠ «Живая голова» целиком в обязательное чтение НЕ входит: это ВСЯ голова D39.124+, и она растёт каждую смену (на 10.09 — больше сотни нот), и требование её прочесть противоречило бы дисциплине «целиком НЕ читать» выше; остальные номера грепаются по мере вопросов. Тела закрытых эр — в слайсахdocs/archive/architecture/(греп: живой файл → слайсы).- По роли (пути — от КОРНЯ репозитория): Бэкенд — шапка-таблица
docs/architecture/09-target-architecture.md(что построено) →backend/README.md→docs/architecture/03-implementation-notes.md(через баннер) →docs/architecture/12-go-style-notes.md; ⚠ порядок именно такой: сессии, впервые видящей движок, механика нужнее стиль-норм; Полигон —eval/README.md+docs/experiments/00-provider-quirks.md+docs/experiments/09-pilot-protocol.md; Фронт/продукт —docs/product-requirements.md+docs/research/16-reader-ide-alignment.md(через ревью-шапку) + контрактdocs/architecture/14-api-contract/; Платформа —platform/README.md+ зонный журнал +docs/research/23-engine-platform-seam.md+ контракт 14; всем — шапка-таблицаdocs/architecture/09-target-architecture.md(статус слоёв). Тулчейн на чистой машине — строка «Тулчейн» в картеdocs/README.md.