18 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/ — чужие зоны,
правки в них запрещены. Ты не коммитишь — дерево готовишь и передаёшь на лендинг оркестратору
(канон git-норм — CLAUDE.md). git add -A, git add ., git commit -a запрещены в любом случае.
В дереве живёт незакоммиченная работа параллельных сессий — не трогай её и не «прибирай».
⚠ Пинги и итоги — в docs/PROGRESS.md, секция «Бэкенд» (у зоны бэкенда своего журнала нет).
3. Карта чтения (пять позиций, больше не нужно)
docs/architecture/17-seam-inbound-law.md— ратифицированный закон входной двери. Это твой контракт: семь пунктов, каждый с прецедентом. Читать ЦЕЛИКОМ и до кода.docs/architecture/05-decisions-log.md, нота D39.156 — почему закон такой и что он закрыл.docs/PROGRESS.md, строки 199, 211, 212, 213 — предметные хвосты твоего пака.docs/experiments/00-provider-quirks.md— обязательное пре-чтение перед любым касанием вызовов провайдеров (тебя касается через--keys-file).docs/architecture/12-go-style-notes.md— норматив общности: Go-логика НЕ ветвится по паре и книге. Ревью-вопрос по умолчанию: «заработает ли на паре, которой в репо ещё НЕТ, без правки Go?»
Код первичен. Все file:line ниже — отправные точки, а не истина: открывай и проверяй сам.
Всю документацию этого проекта писали нейросети, она ошибается, и уже ошибалась в этих самых местах.
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.
- Конфликт с подписанной строкой сида — отказ С ИМЕНЕМ, молча принять нельзя: это заминирует следующий прогон.
- Проекция ДО мутации. Мутирующий глагол сначала говорит, что произойдёт и почём.
- Занятый лок — отказ РОВНО классом 12, не 10. Полоса различает их не косметически: 10 значит
«деплой сломан, чинит человек, книги ждут», 12 значит «ничего не произошло, подожди и повтори»
(
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).
Отдай ей путь — аддитивным полем, форму выбираешь ты. Тем же касанием закрой асимметрию: банк-экспорт
и манифест версию документа несут
(backend/internal/pipeline/bankexport.go:33=const bankExportVersion = "tm-bank-v1"),
а status --json — нет.
5. Мандат самопроверки ИСПОЛНЕНИЕМ
Не «перечитал» — исполнил. Минимум:
- Батарея целиком после каждой содержательной правки:
go build ./...,go vet ./...,go test ./... -count=1. Красный тест не «подгоняется»: править или удалять тест, голден или гейт ради зелени — НЕДОПУСТИМО; несогласие с тестом — пинг оркестратору, а не правка. - Собственные адверсариальные посадки ВНЕ твоего списка. Посади мутации в новый код и убедись, что батарея краснеет: дефолт срабатывает на НЕпустом ключе · частичная запись при отказе одной строки · повторный вызов пишет файл заново · глагол берёт лок блокирующе · читающий глагол требует ключи. ⚠ Посадка обязана называть ПАКЕТ, в котором ищется пин — не тот, где лежит правка: на этом уже горели, и ложное «мутация выжила» опаснее пропущенной, потому что выглядит как результат.
- Живая проба глагола на реальной книге стенда (
~/books/gu-zhenren/*, работать в КОПИИ вне рабочего дерева — транзиентные прогоны в чужом каталоге запрещены). Проба $0: глагол денег не тратит. - Субагенты РАЗРЕШЕНЫ явно — на ревью своего кода, на поиск дефектов вне твоей карты, на опровержение твоих же выводов. Дефолт-запрет харнесса иначе тихо победит.
- Артефакт-находки обязателен:
~/tm-handoff/backend-seam-pack/findings.md— что посадил, что краснело, что выжило. Абсолютный путь, не скрэтчпад.
6. Оси ревью (три, по характеру работы)
- Швовая — у шва инвентарь ВСЕХ каналов другой стороны делается чтением ЧУЖОГО кода, не по памяти: что платформа реально зовёт и что реально читает.
- Общность — заработает ли на паре, которой в репо нет, без правки Go.
- Деньги — глагол обязан быть $0. Докажи это ледджером, а не рассуждением.
7. Записка-план
До кода — короткая записка: что делаешь, в каком порядке, какие развилки видишь. Комплектность против §4 сверяется МЕХАНИЧЕСКИ (таблицей или грепом), а не глазами.
8. Заявление = команда
Каждое число и каждая категорика в отчёте — с командой, которой получены, прямо рядом. Не по памяти о том, как ты это выяснял. Приёмка пере-ранит выборочно; расхождение отчёта с пере-раном дороже, чем честное «не проверял».
9. Эхо-протокол старта
ДО работы — не больше десяти строк: скоуп как ты его понял · инварианты, которые не тронешь · что делать НЕ будешь. Расхождение с этим промтом видно сразу и стоит дёшево.
10. Что НЕ удалось
Обязательная секция отчёта. «Не проверено» ≠ «работает». Вердикт о рантайме без живого прогона — максимум PLAUSIBLE, и так и пиши.
11. Канал вопросов
Конфликт промта с кодом или доками — пинг через владельца, не интерпретация. Ты вправе сказать «этого делать не надо» с аргументом: пак, который принёс развилку вместо тихой девиации, — хороший пак.