25 KiB
Промт: БЭКЕНД-ПАК «ВХОДНАЯ ДВЕРЬ ШВА» (движковая половина D39.156)
Выдан оркестратором №19, 23.08.2026. Активный промт зоны бэкенда — один. Параллельно законен только
platform/docs/PLATFORM_P8_REVIEW_SESSION_PROMPT.md(read-only ревью платформы, пересечений нет).
1. Какая проблема и что решит твой результат
Продукт — издательский перевод больших книг мультиагентным пайплайном. Его центральная ценность — банк памяти: сквозной глоссарий имён и терминов, который держит консистентность на всю книгу.
Пользователь через веб должен уметь поправить или добавить термин, после чего прогон продолжается с учётом правки. Сегодня этого нет и построить нельзя: движок принимает снаружи только «запустись с флагами», а данные берёт из файлов, которые правит человек в редакторе. Положить правку пользователя некуда — писателя этих файлов не существует ни на одной стороне.
Разбор шва (D39.156) показал, что это не дефект одного места, а отсутствующая половина контракта: наружу из движка идёт богатый поток — журнал событий, полоса кодов выхода, версионированные артефакты, — а внутрь не идёт ничего. Поэтому любой внешний участник вынужден имперсонировать человека-оператора с текстовым редактором.
Твой пак строит входную дверь. После него платформа сможет доставлять решения пользователя в
движок, не зная формата его файлов; развилка владения book.yaml, державшая тему, уже закрыта
ратификацией — не выбором из вариантов, а тем, что объявлять ключи и создавать файлы заранее больше
не нужно никому.
Ещё один твой результат — снятие блокера живого прогона: на SaaS-деплое движок сегодня не получает провайдерских ключей вовсе, и это не гипотеза (строка бэклога 211).
2. Зона записи и git
Пишешь ТОЛЬКО в backend/. Читать можешь всё; platform/, frontend/, eval/, docs/ — чужие зоны,
правки в них запрещены. Единственное исключение: пинги и итог сессии — в docs/PROGRESS.md, секция
«Бэкенд» (своего журнала у зоны нет). Больше в docs/ не пишешь ничего. Ты не коммитишь — дерево готовишь и передаёшь на лендинг оркестратору
(канон git-норм — CLAUDE.md). git add -A, git add ., git commit -a запрещены в любом случае.
В дереве живёт незакоммиченная работа параллельных сессий — не трогай её и не «прибирай».
3. Карта чтения (пять позиций, больше не нужно)
docs/architecture/17-seam-inbound-law.md— ратифицированный закон входной двери. Это твой контракт: семь пунктов, каждый с прецедентом. Читать ЦЕЛИКОМ и до кода.docs/architecture/05-decisions-log.md, нота D39.156 — почему закон такой и что он закрыл.docs/PROGRESS.md— строки БЭКЛОГА 199, 211, 212, 213 (предметные хвосты пака). ⚠ Это ID строк ТАБЛИЦЫ, а не номера строк файла. Брать грепом^| 199 |,^| 211 |и так далее. Буквальныйsed -n '199p'даст совсем другой текст — правдоподобный, но чужой, и заказ ты прочитаешь неверно. ⚠ В теле строки 199 лежат ТРИ мины формата, которые обязана знать сессия, пишущая писателя этих файлов: явныйstatus: approved· терм безdst· кап реверс-секции. Прочитать до кода.docs/experiments/00-provider-quirks.md— обязательное пре-чтение перед любым касанием вызовов провайдеров (тебя касается через--keys-file).docs/architecture/12-go-style-notes.md— норматив общности: Go-логика НЕ ветвится по паре и книге. Ревью-вопрос по умолчанию: «заработает ли на паре, которой в репо ещё НЕТ, без правки Go?»
Код первичен. Все file:line ниже — отправные точки, а не истина: открывай и проверяй сам (дисклеймер о происхождении доков — шапка CLAUDE.md, здесь не повторяется).
3а. Что в секции «Бэкенд» — НЕ твой заказ (пропуск подписывается пропуском)
В docs/PROGRESS.md, секции «Бэкенд», висят два пинга твоей зоне. Ни один из них в этот пак не входит:
пинг про потерю инъекции банка на эскалации в Gemini (строки 208/210, родня 193) и пинг про разошедшиеся
с деревом backend/README.md и components.puml. Не трогай их и не «допиливай попутно» — это скоуп-крип,
и ответ полигону по Gemini даст отдельный промт. Если по ходу работы увидишь, что твой пак ломает или
чинит что-то из них, — пинг, а не тихая правка.
4. Состав пака и разметка свободы
4.1 Конвенционные дефолты двух путей — ДЕЛАЙ РОВНО ТАК
Пустые КЛЮЧИ КОНФИГА mined_delta / mined_rejects движок доставляет сам, по конвенции каталога книги (речь о незаполненном ключе, а не о создании пустых файлов). Имена дефолтных файлов решаешь сам — важно, что конвенция одна и живёт в движке. Механизм
уже существует для базы проекта — повторить его:
backend/internal/config/book.go:163-167=b.ProjectDB = filepath.Join(dir, b.BookID+".db").
Прецедент опционального конвенционного YAML-входа тоже есть:
backend/internal/pipeline/mining.go:644=.auto-bank.yaml.
Жёстко: дефолт срабатывает ТОЛЬКО на пустом ключе. Гард для ЯВНО объявленного пути не ослабляется ни на йоту — объявленный и нечитаемый файл остаётся ошибкой конфига. Отсутствующий дефолтный файл = «решений нет», как отсутствующая база до первого прогона.
4.2 Глагол приёма правок банка — РЕШИ САМ форму, ДЕЛАЙ РОВНО ТАК семантику
Новый $0-глагол В tmctl. Прецедент глаголов без прогона есть (migrate, backup, seed-lint).
Имя, разбиение на подкоманды, схему входа и формат ответа решаешь ты и аргументируешь в отчёте. Ориентир: вход — решения в словаре уже публикуемой движком поверхности (стабильные id банк-экспорта для правки существующих, полный кортеж для добавления); выход — JSON: что принято, что отвергнуто и почему.
Семантика — ровно так, отступление = пинг:
- Повторный вызов тем же решением — байтовый no-op, exit 0, отчёт «уже применено». Двойное возобновление и ретраи воркера существуют; неидемпотентный глагол расщепит состояние.
- Отзыв решения — это ЗАМЕНА, а не возврат в нерешённое. «Вернуть в нерешённое» продукту не нужно при действующей модели подписи; если увидишь основание против — пинг, не решение.
- Частичный отказ запрещён: всё-или-ничего. Приняли девять из десяти — файл не пишется, отчёт называет каждый отказ поимённо.
- Два решения по одному терму в одном вызове — отказ всего вызова как ill-formed.
- Конфликт с подписанной строкой сида — отказ С ИМЕНЕМ, молча принять нельзя: это заминирует следующий прогон.
- Проекция ДО мутации, получаемая БЕЗ мутации. Закон говорит «почём до ПОДТВЕРЖДЕНИЯ», прецеденты —
смета с порогом согласия и
--dry-run. Формулировку «напечатал и тем же вызовом записал» считать НЕисполнением. Форму (режим, флаг, отдельная подкоманда) решаешь сам и аргументируешь. - Занятый лок — отказ РОВНО классом 12, не 10. Полоса различает их не косметически: 10 значит
«деплой сломан, чинит человек, книги ждут», 12 значит «ничего не произошло, подожди и повтори»
(в твоей зоне тот же класс уже назван:
backend/cmd/tmctl/main.go:68=another tmctl owns this project right now; платформенная сторона —platform/internal/ingest/exit.go:58=ExitProjectLocked = 12, читать, не править). - Арбитр гонок — тот же flock проекта, что держит прогон:
backend/internal/store/store.go:55=EXCLUSIVE flock on. Брать неблокирующе. ⚠ Это не перестраховка: движок пере-читает сид ПОСРЕДИ прогона, запись в живой прогон въехала бы в снапшот недетерминированно. - Ответ несёт версию документа (закон, п.3).
⚠ Чего в этом паке НЕ делать: не проектировать «глубину до черновика». Правка через
mined_delta доезжает до редакторской волны и НЕ формирует черновик
(backend/internal/pipeline/seeding.go:140=The DRAFT wave selects over a BASE-scoped bank), и это
сознательно: механика пост-ридингового цикла прямым словом владельца не проектируется до итогов
полигона. Дефолт версии 1 — редакторская глубина, и ответ глагола говорит это ЯВНЫМ полем.
4.3 Путь к файлу ключей аргументом — ДЕЛАЙ РОВНО ТАК
Сегодня на SaaS движок не получает ключей: замысел «читает из .env рядом с book.yaml» записан
комментарием платформы, но файл туда никто не кладёт. Дев-путь при этом наследует окружение
платформы, прод-путь — нет, поэтому стенд зелёный, а прод голодает, и упасть не мог ни один тест.
- Флаг только у
translate. Читающим $0-глаголам ключи запрещены — они не должны их требовать вовсе:backend/cmd/tmctl/dotenv.go:53-55=projections that must not demand keys at all(D20.4). - Деплой-файл грузится ПЕРВЫМ в цепочке без перекрытия: явное бьёт конвенцию, а стендовые книги
флага не передают и ничего не замечают. Текущая цепь —
backend/cmd/tmctl/main.go:184-185=loadDotEnv(filepath.Join(filepath.Dir(inv.cfgPath), ".env"). - Названный и нечитаемый файл — громкий отказ конфигом при старте, не тихий пропуск.
- ⚠ Ключи в проекте общие на всех пользователей (слово владельца 22.08); пер-книжные ключи возможны позже и ложатся в ту же форму. Ничего «на вырост» не строить.
4.4 Строгость загрузчика сида — ДЕЛАЙ РОВНО ТАК
backend/internal/membank/memseed.go:41=yaml.Unmarshal(raw, &sf) — голый разбор без проверки имён
ключей. Опечатка gendr: вместо gender: выбрасывается ДО валидации, и seed-lint её не видит:
он проверяет значения, а не ключи. Прецедент строгости в проекте есть —
backend/internal/config/book.go:143=dec.KnownFields(true).
Нужен и тест на unknown-key: сегодня в сид-линте нет ни одного такого кейса.
4.5 Путь артефакта и версия в status --json — РЕШИ САМ форму
Платформа сегодня знает о твоей стороне ДВЕ вещи, и закрыть надо ОБЕ (строка 213): она сама вычисляет путь
базы книги, дублируя движковую конвенцию, И знает суффикс твоего артефакта
(platform/internal/runner/artifacts.go:37=os.Open(db + ".bank.json") — читать, не править, чужая зона).
Отдай ей ПУТЬ БАНК-ЭКСПОРТА (и путь базы, если сочтёшь нужным) аддитивным полем — форму выбираешь ты.
⚠ Пере-именование банк-экспорта в фикс-имя — ЛОМАЮЩЕЕ, его окно — строка 161, сюда не тащить. Тем же касанием закрой асимметрию: банк-экспорт
и манифест версию документа несут
(backend/internal/pipeline/bankexport.go:33=const bankExportVersion = "tm-bank-v1"),
а status --json — нет.
4.7 Дефолт корпуса в тест-хелперах — ДЕЛАЙ РОВНО ТАК (строка бэклога 218, добавлено 24.08)
Три хелпера резолвят стендовый корпус от $HOME/books, которого на машине больше нет:
internal/miner/miner_parity_test.go:101-106=func standFile(parts ...string) string ·
internal/checks/labelharness_test.go:58-63=func standLabelsDir() string ·
internal/membank/labelharness_test.go:38=func memStandLabelsDir() string.
Правится ДЕФОЛТ, и ровно тем механизмом, который уже применён СОСЕДНЕЙ функцией в том же файле:
internal/miner/miner_parity_test.go:56-57=finds the repository root by MARKER — корень ищется по
маркеру вверх по дереву, а не считается точками и не берётся из $HOME. Env-переопределения
(TM_CHECKER_LABELS_DIR, TM_MINER_PARITY_{CONTRAST,RECORDS,SEED}) уже существуют и остаются
старшими — их не трогать.
⚠ Проверено оркестратором 24.08 и это твоя опорная точка: с переопределениями на новый путь
корпус-батарея ЗЕЛЕНА, красен ровно TestMinerFullBookParity и ровно из-за отсутствующего
eval/exp16/data/jieba_dict_general_zh.txt (строка 123, в git не попадает по построению). Значит
критерий готовности пункта: TM_MINER_PARITY=1 TM_CHECKER_LABELS=1 make battery-stand БЕЗ единого
TM_*_DIR-переопределения даёт ту же картину — всё зелено, кроме парити на jieba. Если краснеет
что-то ещё — дефолт выведен неверно.
4.6 Деньги: платных вызовов в паке НОЛЬ — ДЕЛАЙ РОВНО ТАК
Санкции на платные вызовы у пака нет и не запрашивается. Глагол банка $0 по построению. --keys-file
доказывается юнит-тестами и пробой с ФЕЙКОВЫМИ ключами (проверяется, что путь резолвится, файл читается,
порядок цепочки соблюдён), а не живым translate. Рантайм-вердикт по платному пути остаётся PLAUSIBLE —
это ожидаемый исход, а не дефект отчёта; так и напиши. Упёрся в место, где без денег не доказать, —
пинг с названной суммой, не трата.
5. Мандат самопроверки ИСПОЛНЕНИЕМ
Не «перечитал» — исполнил. Минимум:
- Батарея целиком, ИЗ КАТАЛОГА
backend/после каждой содержательной правки:go build ./...,go vet ./...,go test ./... -count=1. ⚠go.modв корне репозитория НЕТ — модули раздельные, из корня батарея не соберётся. Платформенную батарею не гоняешь вовсе: платформу ты не правишь. Красный тест не «подгоняется»: править или удалять тест, голден или гейт ради зелени — НЕДОПУСТИМО; несогласие с тестом — пинг оркестратору, а не правка. - Собственные адверсариальные посадки ВНЕ твоего списка. Посади мутации в новый код и убедись, что батарея краснеет: дефолт срабатывает на НЕпустом ключе · частичная запись при отказе одной строки · повторный вызов пишет файл заново · глагол берёт лок блокирующе · читающий глагол требует ключи. ⚠ Посадка обязана называть ПАКЕТ, в котором ищется пин — не тот, где лежит правка: на этом уже горели, и ложное «мутация выжила» опаснее пропущенной, потому что выглядит как результат.
- Живая проба глагола на реальной книге стенда (
<репозиторий>/books/gu-zhenren/*— ⚠ каталог книг ПЕРЕЕХАЛ 24.08 внутрь репозитория и версионируется СВОИМ git; прежний адрес~/booksмёртв, D39.157 п.2). Работать в КОПИИ вне рабочего дерева — транзиентные прогоны в чужом каталоге запрещены; правки вbooks/не делать вовсе, это не твоя зона. Проба $0: глагол денег не тратит. - Субагенты РАЗРЕШЕНЫ явно — на ревью своего кода, на поиск дефектов вне твоей карты, на опровержение твоих же выводов. Дефолт-запрет харнесса иначе тихо победит.
- Артефакт-находки обязателен:
backend/docs/SEAM_PACK_FINDINGS.md— что посадил, что краснело, что выжило. В репозитории, не вовне: доказательная база пака едет на приёмку вместе с деревом.
5.1 Обязательное для кодового пака
- Последний абзац отчёта — это план или обещание? Значит сделай его СЕЙЧАС, а не оставляй следующей сессии.
- Дифф
^func Test— исполнением, а не по памяти: покажи командой, какие тесты добавлены и какие тронуты. - Интервальная самоверификация субагентом против ЯВНЫХ критериев — пак с новым глаголом заведомо длинный, и к его середине собственный фрейминг перестаёт быть виден изнутри.
6. Оси ревью (три, по характеру работы)
- Швовая — у шва инвентарь ВСЕХ каналов другой стороны делается чтением ЧУЖОГО кода, не по памяти: что платформа реально зовёт и что реально читает.
- Общность — заработает ли на паре, которой в репо нет, без правки Go.
- Деньги — глагол обязан быть $0. Докажи это ледджером, а не рассуждением.
Ты вправе ЗАМЕНИТЬ любую из осей своей, если аргументируешь, чем твоя лучше ловит дефекты этой работы.
7. Записка-план
До кода — короткая записка backend/docs/SEAM_PACK_PLAN.md (в репозитории, не вовне): что делаешь, в каком порядке, какие развилки видишь. Комплектность
против §4 сверяется МЕХАНИЧЕСКИ (таблицей или грепом), а не глазами.
8. Заявление = команда
Каждое число и каждая категорика в отчёте — с командой, которой получены, прямо рядом. Не по памяти о том, как ты это выяснял. Приёмка пере-ранит выборочно; расхождение отчёта с пере-раном дороже, чем честное «не проверял».
9. Эхо-протокол старта
ДО работы — не больше десяти строк: скоуп как ты его понял · инварианты, которые не тронешь · что делать НЕ будешь. Расхождение с этим промтом видно сразу и стоит дёшево.
10. Что НЕ удалось
Обязательная секция отчёта. «Не проверено» ≠ «работает». Вердикт о рантайме без живого прогона — максимум PLAUSIBLE, и так и пиши.
11. Канал вопросов
Конфликт промта с кодом или доками — пинг через владельца, не интерпретация. Ты вправе сказать «этого делать не надо» с аргументом: пак, который принёс развилку вместо тихой девиации, — хороший пак.