diff --git a/docs/README.md b/docs/README.md index dcb21d19..663805c8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -11,7 +11,7 @@ - `architecture/` — синтез и контракты: - [05-decisions-log.md](architecture/05-decisions-log.md) — **источник истины по решениям**. Живой файл после диеты D39.125 и подрезки D39.139: карта + эрраты + живые тела + голова D39.124+; тела закрытых эр — слайсы `archive/architecture/05-decisions-*.md`. Грепай номер сначала в живом, затем в слайсах (тело ноты = строка `^## D<номер>`, прочие хиты — упоминания); целиком не читать. **Статус/суть/тело ЛЮБОГО номера одним хопом — реестр [05-decisions-index.md](architecture/05-decisions-index.md)** (все ноты, колонка тем для грепа «какой закон по X»; D39.126). - [09-target-architecture.md](architecture/09-target-architecture.md) — целевая 7-слойная архитектура (статус стройки — шапка-таблица; §3 — карта находок H/L) · [10-prompt-architecture.md](architecture/10-prompt-architecture.md) — промпт-слой · [12-go-style-notes.md](architecture/12-go-style-notes.md) — норматив общности §0 · [13-tech-debt-anchors.md](architecture/13-tech-debt-anchors.md) — якоря техдолга + археология выселенных строк бэклога §Б-* (справочник к бэклогу, НЕ трекер) · [14-api-contract/](architecture/14-api-contract/) — **контракт API v0 фронт↔платформа (D39.99)**: нормативная спека OpenAPI 3.1 (типы фронта генерятся из неё) + компаньон-README (провенанс ✓/◆/○, К-вопросы; зонная копия `frontend/docs/api-contract/` — байт-зеркало, сверять при лендинге). - - Топикальные входы (D39.126; НЕ источники истины, при конфликте побеждает D-лог): [15-money-path.md](architecture/15-money-path.md) — деньги от гранта до settle одним маршрутом · [16-events-emitter.md](architecture/16-events-emitter.md) — сборка-норматив эмиттера шва (обязательное пре-чтение сессии строки 103) · [STACK.md](STACK.md) — карта «роль → модель → конфиг → квирки». + - Топикальные входы (D39.126; НЕ источники истины, при конфликте побеждает D-лог): [15-money-path.md](architecture/15-money-path.md) — деньги от гранта до settle одним маршрутом · [16-events-emitter.md](architecture/16-events-emitter.md) — сборка-норматив эмиттера шва (обязательное пре-чтение сессии строки 103) · **[17-seam-inbound-law.md](architecture/17-seam-inbound-law.md) — закон ВХОДНОЙ двери шва движок↔платформа (⚠ ПРЕДЛОЖЕНО, НЕ РАТИФИЦИРОВАНО: до слова владельца это записка, ссылаться как на норму нельзя; исходящее направление ратифицировано, входное — нет)** · [STACK.md](STACK.md) — карта «роль → модель → конфиг → квирки». - Исторические, читать через ⚠-баннеры: [01-decisions.md](architecture/01-decisions.md) (Р1–Р10) · [02-mvp-plan.md](architecture/02-mvp-plan.md) · [03-implementation-notes.md](architecture/03-implementation-notes.md) · [04-unhappy-paths.md](architecture/04-unhappy-paths.md) · [06-memory-risk-registry.md](architecture/06-memory-risk-registry.md). - `experiments/` — эмпирика полигона: [00-provider-quirks.md](experiments/00-provider-quirks.md) — **читать перед любым вызовом провайдера**; [08-cost-model-v2.md](experiments/08-cost-model-v2.md) — денежная модель; [09-pilot-protocol.md](experiments/09-pilot-protocol.md) — пилот Ф2.5; остальные 01–21 — отчёты ЗАКРЫТЫХ экспериментов (21 принят D39.117); ⚠ 22/23 — залендены с ревью-шапками приёмки №16 (10.08), НЕ ратифицированы: выводы заморожены до фазы Д (шапка первична; 18–20 — с ревью-шапками приёмки D39.108). - `research/` — фактура ресёрчей 01–28; у принятых — ревью-шапки, часть тел под ⚠ superseded: **читай баннер прежде содержимого**. Ключевые для навигации: 15 голос · 16 ридер-IDE · 17 внешняя критика · 18 рычаги качества · 19 нарезка · 20 банк-майнинг · 21 обзор транспорта · 22 доменные харнессы · 23 шов движок↔платформа (транспорт superseded D39.106) · 25 холодное ревью шва — форма D39.106, отвергнутые альтернативы, требования к эмиттеру (читать перед любым кодом стыка) · 24 арбитраж банка (ПРИНЯТ D39.102: консилиум закрыт классом, вход фикс-пака банка — §G) · 26 официальные практики Anthropic (D39.121: записка-план, сниппеты хендоффов, карта «уже делаем/перенять») · **28 контракт-ревью API v0 (ПРИНЯТ D39.138: решения владельца 16.08 — §8, состав батча 0.3.0 — §5; НОСИТЕЛЬ для исполняющих сессий, читать оригинал, не пересказ)**. diff --git a/docs/STACK.md b/docs/STACK.md index 28310aae..4bcfafa9 100644 --- a/docs/STACK.md +++ b/docs/STACK.md @@ -18,5 +18,5 @@ ## Примечания - **⚠0731 (D39.61):** flash пере-обучен под тем же слагом; `/models` молчал. Развилка решена вариантом (б): явный `reasoning_effort:"low"` черновику + ручка эффорта бэнк-ролям (код `553f1a3`). Версию модели проверять ПОВЕДЕНИЕМ. - **Вахта эффорта pro:** реестр загейченных триггеров — `architecture/13-tech-debt-anchors.md` §Б-108; статус ручки `low` на pro = НЕ УСТАНОВЛЕНО (quirks §3б). -- **Цена:** ~$0.85/ранобэ (⚠ число ДО пере-пина цен 13–15.08: таблица запинена ПИКОМ, счёт шиппинга = 100% DeepSeek ⇒ ×4.2–4.4 в пике и ×2.1–2.2 в долине — D39.137; пере-калибровать первым же платным прогоном. D30.4; тело — `archive/architecture/05-decisions-D1-D38.md`, карта — шапка D-лога); пере-калибровка при следующем платном прогоне (112 залендена, D39.97). Edit-волна не гонялась НИ РАЗУ (строка 16); ставка платформы $0.03/глава (D39.123 п.2г). Цены слагов — `models.yaml` (~~`prices_checked: 2026-07-10`~~ → **`2026-08-15`** (`backend/configs/models.yaml:34`=`prices_checked: "2026-08-15"`; бампнут факт-чеком ТОЛЬКО по DeepSeek — испр. 20.08); катовер 0731 цен не менял). +- **Цена:** ~$0.85/ранобэ (⚠ число ДО пере-пина цен 13–15.08: таблица запинена ПИКОМ, счёт шиппинга = 100% DeepSeek ⇒ ×4.2–4.4 в пике и ×2.1–2.2 в долине — D39.137; пере-калибровать первым же платным прогоном. D30.4; тело — `archive/architecture/05-decisions-D1-D38.md`, карта — шапка D-лога); пере-калибровка при следующем платном прогоне (112 залендена, D39.97). Edit-волна не гонялась на ПОЛНОМ холодном прогоне (строка 16); на малых прогонах отработала и оплачена — ⚠ прежний абсолют «НИ РАЗУ» ложен, испр. №19 по леджерам; ставка платформы $0.03/глава (D39.123 п.2г). Цены слагов — `models.yaml` (~~`prices_checked: 2026-07-10`~~ → **`2026-08-15`** (`backend/configs/models.yaml:34`=`prices_checked: "2026-08-15"`; бампнут факт-чеком ТОЛЬКО по DeepSeek — испр. 20.08); катовер 0731 цен не менял). - **Ключи API:** список env-ключей — `docs/README.md` §«Доступные ключи» (7 шт.); резолв per-провайдер — `models.yaml api_key_env`. **`.env` НЕ читать** (гардрейл CLAUDE.md), `.env.example` можно. diff --git a/docs/architecture/17-seam-inbound-law.md b/docs/architecture/17-seam-inbound-law.md new file mode 100644 index 00000000..dd379802 --- /dev/null +++ b/docs/architecture/17-seam-inbound-law.md @@ -0,0 +1,110 @@ +# 17 — Закон входной двери шва движок ↔ платформа + +> **СТАТУС: ПРЕДЛОЖЕНО К РАТИФИКАЦИИ, НЕ РАТИФИЦИРОВАНО.** Собрано оркестратором №19 по консилиуму +> со сторонним архитектором 22–23.08.2026. До слова владельца это ЗАПИСКА, а не контракт: ссылаться +> на неё как на норму нельзя. Ратифицируется одной D-нотой; после неё двери встают паками без +> возврата к владельцу — ровно так, как код выхода `13` встал в ратифицированную полосу 10–19 без +> новой ратификации (D39.131 п.2а → D39.132 п.2г → D39.134). +> +> **Зачем понадобилось.** Контракт фронт↔платформа ратифицирован (`14-api-contract/`), а контракт +> платформа↔движок — нет: исследование шва дошло до «события пишутся в `events.jsonl`» и дальше +> отвечало на вопрос «как запускать движок» (`research/23`, транспортная часть §1 superseded +> D39.106; `research/25` — ратифицированная форма и отвергнутые альтернативы). В итоге НАРУЖУ из +> движка идёт богатый поток — журнал событий по курсору, полоса кодов выхода, exit-маркер, +> версионированные артефакты-проекции, — а ВНУТРЬ не идёт ничего, кроме запуска с флагами. Данные, +> которыми владеет пользователь продукта, движок принимать не умеет вообще, поэтому каждый внешний +> участник вынужден имперсонировать человека-оператора с текстовым редактором. + +## Почему НОРМА, а не каталог команд + +За осознанный контракт говорят три прожитых инцидента гниения нератифицированных входных конвенций: +дубль дефолта `.db` у платформы (строка бэклога **213**) · ручная константа версии API, +не поднятая при синке (D39.153) · три мины формата карты подписи, вскрытые только трассировкой +строки 199. + +Против ПОЛНОГО каталога — то, что половина будущих дверей гейтится нерешёнными развилками: строка +**192** прямо запрещена к проектированию до полигонных итогов (D39.144 п.1), **161**/**185** ждут +дизайн-пака, **170** — «после беты формы Б». Каталогизировать их сейчас значит выдумывать. + +Прецедент, разрешающий спор, — исходящее направление: там выиграла ратификация ПОЛОСЫ и ДИСЦИПЛИНЫ, +а не перечня. + +## Закон: семь пунктов + +1. **Вход — это аргументы при спавне и файлы, названные аргументами.** Данные, которыми владеет + пользователь продукта, доезжают движковым ГЛАГОЛОМ; движок — единственный писатель файлов своей + схемы и владелец их путей и конвенций. Платформа читает только версионированные артефакты по + путям, которые ей СООБЩЕНЫ, и никогда не выводит путь сама. + *Прецеденты:* потолок аргументом (D39.110 п.2б → `--ceiling-usd`, D39.122) · `--verify-bank` + флагом (`platform/internal/runner/engine.go:83-87`=`func TranslateArgs(workdir string, verifyBank bool`) · дефолт `project_db` по конвенции каталога + (`backend/internal/config/book.go:163-167`=`b.ProjectDB = filepath.Join(dir, b.BookID+".db")`) · конвенционное опциональное чтение `.auto-bank.yaml` + (`backend/internal/pipeline/mining.go:644`=`.auto-bank.yaml`). + +2. **Посреди прогона внутрь идёт ТОЛЬКО сигнал.** `SIGTERM` = «дочти чанк и отпусти лок»; всё + остальное — на границах процессов. Арбитр — эксклюзивный flock проекта на всю жизнь прогона + (`backend/internal/store/store.go:55`=`EXCLUSIVE flock on`), мутирующий глагол берёт его неблокирующе и при занятости + отказывает классом «конфиг/лок». + *Почему жёстко:* движок пере-читает сид ПОСРЕДИ прогона (`mining.go:221`), запись в живой прогон + въехала бы в снапшот недетерминированно. Потолок посреди прогона менять НЕЛЬЗЯ — он едет со + стартом и после не меняется, лекарство — новый прогон + (`platform/internal/runs/reconcile.go:1222-1227`=`answering 202 with the run in the state`). Дверь «менять потолок файлом» закрыта; + не выдумывать её заново из `research/25`. + +3. **Каждый JSON-выход глагола несёт версию документа.** Сегодня асимметрия: `tm-bank-v1` + (`pipeline/bankexport.go:33`=`const bankExportVersion = "tm-bank-v1"`) и `tm-manifest-v2` (`pipeline/manifest.go:46`=`const manifestVersion = "tm-manifest-v2"`) версию несут, + а `status --json` — нет. Закрыть. + +4. **Незнакомый флаг = громкий отказ при спавне.** Сегодня это так по устройству разбора аргументов + (`backend/cmd/tmctl/invocation.go:104,120`=`flag.NewFlagSet(cmd, flag.ContinueOnError)`); зафиксировать законом, а не полагаться на случайность. + +5. **Глагол зовётся ТЕМ ЖЕ пиннутым бинарём, что и возобновляемая попытка** (`runs/spawn.go:240-248`=`engineBinary is the path an attempt is PINNED to`, + строка бэклога 139). Иначе файл, записанный новым бинарём, читается старым — а при нестрогом + загрузчике сида (строка **212**) новое поле теряется МОЛЧА. + +6. **Словарь движка ↔ словарь контракта — одна таблица, два направления, один файл.** + Сегодня перевод односторонний, на чтении (`platform/internal/ingest/bank.go:15-21`=`Every vocabulary crossing here is TRANSLATED and none is passed through`). Запись + делает таблицу двунаправленной, и две копии разъедутся. + +7. **Мутирующий глагол сначала даёт проекцию, потом мутирует.** «Почём ДО подтверждения». + *Прецеденты:* rebill-смета с порогом согласия (D20.2-Q2, `pipeline/rebill.go`) · строка 185 + («сколько глав и почём до подтверждения») · `--dry-run` строки 124(в). + +## Совместимость без второго рукосинхронизируемого контракта + +Версий у КОМАНД нет и заводить их не нужно: совместимость выводится из трёх уже существующих ног — +пиннинг попытки к бинарю (строка 139) · незнакомый флаг роняет спавн громко (п.4) · версионированный +конверт на каждом JSON-выходе (п.3). Плюс одна асимметричная норма: движок не меняет семантику флага +или поля без мажора, новые флаги едут «движок-первым» — расширение уже ратифицированного порядка +деплоя `migrate` (D39.134 п.3). +Хендшейк или `capabilities`-глагол движка — НЕ строить: один хост, «least mechanism» +(`12-go-style-notes.md` §1), а судьбу ручной константы показал инцидент `ContractVersion`. +⚠ Предположение, не механизм: окно «старая платформа + новый движок» считается покрытым обратной +совместимостью флагов. Если деплои разъедутся сильнее — вернуться к вопросу. + +## Двери, УЖЕ подразумеваемые живыми строками + +| дверь | откуда следует | +|---|---| +| приём правок банка движковым глаголом | строка **199(а)** — развилка владения `book.yaml` растворяется этим | +| `--keys-file` (или иной явный путь к ключам) | строка **211** — блокер строки 202 | +| путь артефакта в ответе движка | строка **213** — снимает дубль у платформы | +| `resnapshot --dry-run` | строка **124(в)**, глагол поименован там дословно | +| движковая оценка $/глава | строка **166**; форма (поле в `manifest --json` против нового глагола) — за проектировщиком пака | +| consent-флаги `--resnapshot`/`--accept-rebill` от платформы | строка **199(б)**, гейчена 192 | +| `tmctl init` (форма В) | строка **170**; приоритет ПАДАЕТ после двери 199(а) — та забирает её главный довод | + +**Из чего двери НЕ следует** (экономия паков): **202** — потребитель всего набора, своих команд не +несёт · **208** — фикс транспорта внутри движка · **210** — развилка данных/промпта, вайр-батч 182 · +**164** — не команда, а починка: смета уже едет в `status --json`. + +## Чего НЕ строить + +- **Инбокс-каталог входящих команд** как зеркало `events.jsonl`. Все трассированные нужды садятся на + границы процессов; единственный мид-ран кандидат закрыт каноном (п.2); инбокс-файл возвращает + гонку, ради исключения которой существует flock. +- **Пере-открытие транспорта** (gRPC/сокет/брокер/пуш) — `research/25`, у каждой альтернативы 0 + голосов из ~18, решение владельца принято. +- **Общий Go-пакет типов на две системы** — сварка независимых деплоев против D39.81/85; перевод + словаря на шве — сознательный контракт, а не недоделка. +- **Быстрый poll статуса** — `status` дорог по построению (пере-ингест книги), свежесть даёт журнал + событий; «status — это ремонт, а не поллинг» подтверждено вхолодную независимыми панелями.