215 lines
23 KiB
Markdown
215 lines
23 KiB
Markdown
# Промт: БЭКЕНД-ПАК «ВХОДНАЯ ДВЕРЬ ШВА» (движковая половина 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. Карта чтения (пять позиций, больше не нужно)
|
||
|
||
1. **`docs/architecture/17-seam-inbound-law.md`** — ратифицированный закон входной двери. Это твой
|
||
контракт: семь пунктов, каждый с прецедентом. Читать ЦЕЛИКОМ и до кода.
|
||
2. **`docs/architecture/05-decisions-log.md`, нота D39.156** — почему закон такой и что он закрыл.
|
||
3. **`docs/PROGRESS.md` — строки БЭКЛОГА 199, 211, 212, 213** (предметные хвосты пака).
|
||
⚠ **Это ID строк ТАБЛИЦЫ, а не номера строк файла.** Брать грепом `^| 199 |`, `^| 211 |` и так далее.
|
||
Буквальный `sed -n '199p'` даст совсем другой текст — правдоподобный, но чужой, и заказ ты прочитаешь неверно.
|
||
⚠ В теле строки 199 лежат ТРИ мины формата, которые обязана знать сессия, пишущая писателя этих файлов:
|
||
явный `status: approved` · терм без `dst` · кап реверс-секции. Прочитать до кода.
|
||
4. **`docs/experiments/00-provider-quirks.md`** — обязательное пре-чтение перед любым касанием
|
||
вызовов провайдеров (тебя касается через `--keys-file`).
|
||
5. **`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.6 Деньги: платных вызовов в паке НОЛЬ — ДЕЛАЙ РОВНО ТАК
|
||
|
||
Санкции на платные вызовы у пака нет и не запрашивается. Глагол банка $0 по построению. `--keys-file`
|
||
доказывается юнит-тестами и пробой с ФЕЙКОВЫМИ ключами (проверяется, что путь резолвится, файл читается,
|
||
порядок цепочки соблюдён), а не живым `translate`. **Рантайм-вердикт по платному пути остаётся PLAUSIBLE —
|
||
это ожидаемый исход, а не дефект отчёта**; так и напиши. Упёрся в место, где без денег не доказать, —
|
||
пинг с названной суммой, не трата.
|
||
|
||
## 5. Мандат самопроверки ИСПОЛНЕНИЕМ
|
||
|
||
Не «перечитал» — **исполнил**. Минимум:
|
||
|
||
- **Батарея целиком, ИЗ КАТАЛОГА `backend/`** после каждой содержательной правки: `go build ./...`,
|
||
`go vet ./...`, `go test ./... -count=1`. ⚠ `go.mod` в корне репозитория НЕТ — модули раздельные, из корня
|
||
батарея не соберётся. Платформенную батарею не гоняешь вовсе: платформу ты не правишь. Красный тест не «подгоняется»: править или удалять тест, голден или гейт
|
||
ради зелени — НЕДОПУСТИМО; несогласие с тестом — пинг оркестратору, а не правка.
|
||
- **Собственные адверсариальные посадки ВНЕ твоего списка.** Посади мутации в новый код и убедись,
|
||
что батарея краснеет: дефолт срабатывает на НЕпустом ключе · частичная запись при отказе одной
|
||
строки · повторный вызов пишет файл заново · глагол берёт лок блокирующе · читающий глагол требует
|
||
ключи. ⚠ **Посадка обязана называть ПАКЕТ, в котором ищется пин** — не тот, где лежит правка:
|
||
на этом уже горели, и ложное «мутация выжила» опаснее пропущенной, потому что выглядит как результат.
|
||
- **Живая проба глагола на реальной книге стенда** (`~/books/gu-zhenren/*`, работать в КОПИИ вне
|
||
рабочего дерева — транзиентные прогоны в чужом каталоге запрещены). Проба $0: глагол денег не тратит.
|
||
- **Субагенты РАЗРЕШЕНЫ явно** — на ревью своего кода, на поиск дефектов вне твоей карты, на
|
||
опровержение твоих же выводов. Дефолт-запрет харнесса иначе тихо победит.
|
||
- **Артефакт-находки обязателен:** `backend/docs/SEAM_PACK_FINDINGS.md` — что посадил, что краснело, что выжило.
|
||
В репозитории, не вовне: доказательная база пака едет на приёмку вместе с деревом.
|
||
|
||
### 5.1 Обязательное для кодового пака
|
||
|
||
- **Последний абзац отчёта — это план или обещание? Значит сделай его СЕЙЧАС**, а не оставляй следующей сессии.
|
||
- **Дифф `^func Test` — исполнением, а не по памяти:** покажи командой, какие тесты добавлены и какие тронуты.
|
||
- **Интервальная самоверификация субагентом** против ЯВНЫХ критериев — пак с новым глаголом заведомо длинный,
|
||
и к его середине собственный фрейминг перестаёт быть виден изнутри.
|
||
|
||
## 6. Оси ревью (три, по характеру работы)
|
||
|
||
1. **Швовая** — у шва инвентарь ВСЕХ каналов другой стороны делается чтением ЧУЖОГО кода, не по
|
||
памяти: что платформа реально зовёт и что реально читает.
|
||
2. **Общность** — заработает ли на паре, которой в репо нет, без правки Go.
|
||
3. **Деньги** — глагол обязан быть $0. Докажи это ледджером, а не рассуждением.
|
||
|
||
Ты вправе ЗАМЕНИТЬ любую из осей своей, если аргументируешь, чем твоя лучше ловит дефекты этой работы.
|
||
|
||
## 7. Записка-план
|
||
|
||
До кода — короткая записка `backend/docs/SEAM_PACK_PLAN.md` (в репозитории, не вовне): что делаешь, в каком порядке, какие развилки видишь. Комплектность
|
||
против §4 сверяется МЕХАНИЧЕСКИ (таблицей или грепом), а не глазами.
|
||
|
||
## 8. Заявление = команда
|
||
|
||
Каждое число и каждая категорика в отчёте — **с командой, которой получены, прямо рядом**. Не по
|
||
памяти о том, как ты это выяснял. Приёмка пере-ранит выборочно; расхождение отчёта с пере-раном
|
||
дороже, чем честное «не проверял».
|
||
|
||
## 9. Эхо-протокол старта
|
||
|
||
ДО работы — не больше десяти строк: скоуп как ты его понял · инварианты, которые не тронешь ·
|
||
что делать НЕ будешь. Расхождение с этим промтом видно сразу и стоит дёшево.
|
||
|
||
## 10. Что НЕ удалось
|
||
|
||
Обязательная секция отчёта. «Не проверено» ≠ «работает». Вердикт о рантайме без живого прогона —
|
||
максимум PLAUSIBLE, и так и пиши.
|
||
|
||
## 11. Канал вопросов
|
||
|
||
Конфликт промта с кодом или доками — **пинг через владельца, не интерпретация**. Ты вправе сказать
|
||
«этого делать не надо» с аргументом: пак, который принёс развилку вместо тихой девиации, — хороший пак.
|