From 24b12425ee21ef79b2369e6358d7a34b95a423e0 Mon Sep 17 00:00:00 2001 From: heaven Date: Wed, 16 Sep 2026 21:54:22 +0300 Subject: [PATCH] Give seven more anchors across three canon docs tokens that distinguish their targets --- docs/architecture/03-implementation-notes.md | 2 +- docs/architecture/05-decisions-log.md | 2 +- docs/architecture/15-money-path.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/architecture/03-implementation-notes.md b/docs/architecture/03-implementation-notes.md index 2336b5cc..877a77ce 100644 --- a/docs/architecture/03-implementation-notes.md +++ b/docs/architecture/03-implementation-notes.md @@ -103,7 +103,7 @@ C2, cache TTL per-стадия. В models.yaml: цены (+cache write/read), п ## 5. [НУЖНО РЕШЕНИЕ] — СНЯТО, всё развязано -> ⚠ **§5 СНЯТ — а код на него ещё ссылается, поэтому вот куда он уехал** (заглушка, испр. 10.09, по образцу заглушки §2 выше). Три не-тестовых сайта продолжают адресовать эту секцию: `backend/internal/config/pipeline.go:471` (формула премиум-бюджета — см. `01-decisions.md`, там же сказано, что в коде её НЕТ и почему), `backend/internal/llm/llm.go:106` (провайдерский стриминг — отнесён к Ф2, §3 этого дока), `backend/internal/pipeline/render.go:34` (§3.4 того же дока). ⇒ читающий из кода приходит сюда и находит указатель, а не пустоту. +> ⚠ **§5 СНЯТ — а код на него ещё ссылается, поэтому вот куда он уехал** (заглушка, испр. 10.09, по образцу заглушки §2 выше). Три не-тестовых сайта продолжают адресовать эту секцию: `backend/internal/config/pipeline.go:471`=`a defect flips the chunk to flagged` (формула премиум-бюджета — см. `01-decisions.md`, там же сказано, что в коде её НЕТ и почему), `backend/internal/llm/llm.go:106`=`JSONOnly bool` (провайдерский стриминг — отнесён к Ф2, §3 этого дока), `backend/internal/pipeline/render.go:34`=`explicit re-translation, not a silent cache miss` (§3.4 того же дока). ⇒ читающий из кода приходит сюда и находит указатель, а не пустоту. Пять вопросов 04.07 закрыты, карта развязок — в баннере вверху (тела D11/D14/D19/D23 — в слайсе `../archive/architecture/05-decisions-D1-D38.md`); пятый, не попавший в карту, — пункты оркестратору (фазовые пометки диаграмм, владелец задачи cache-hit), отработан арх-ресетом D39. Формулировки вопросов — `../archive/PROGRESS-2026-07-04-10.md`. diff --git a/docs/architecture/05-decisions-log.md b/docs/architecture/05-decisions-log.md index aa7cbaf6..d1afca60 100644 --- a/docs/architecture/05-decisions-log.md +++ b/docs/architecture/05-decisions-log.md @@ -3376,7 +3376,7 @@ bought NOTHING». ⇒ **`tmctl manifest` есть НИЖНЯЯ граница, **(в)** `Money` на исходе `stopped` едет ВСЕГДА, а не только когда прежде сработал потолок (сегодня — только тогда: `backend/internal/pipeline/events.go`, греп `ceilingSaid`). Вопрос покупателя «что я купил» от причины остановки не зависит. **(г)** ЗАПАСНОЙ КАНАЛ — обязанность ПЛАТФОРМЫ, не движка: у прогона, убитого по грейсу, кадра `finished` нет вовсе (его отсутствие само по себе значимо), а `status --json` числа несёт всегда ⇒ платформа читает оба. -**2. ⛔ ЭРРАТА К СОБСТВЕННОМУ АКТУ: `D39.234` п.1б назвал МЕХАНИЗМ, который ратифицированных ~20 минут НЕ ДАЁТ.** Слово владельца («одна летящая попытка, ~20 минут приемлемо») в силе и не меняется. Неверна была моя скобка «отказ на пер-вызовном гейте резервации». Замер: резервация берётся ОДИН раз на `runAttempt` (`backend/internal/pipeline/stagerun.go:477`=`finish string`, `admit` на `:570`), а `client.Complete` (`:699`) держит под ней ВСЮ цепочку ретраев — это дословно говорит комментарий самого кода: «This timer wraps client.Complete — the WHOLE retry chain» (`stagerun.go:984`); `retryLoop` между попытками смотрит только `ctx.Err()` (`backend/internal/llm/httpllm.go:197`). ⇒ гейт ограничивает ожидание ЦЕПОЧКОЙ (~64 мин), а не попыткой (~20). Чтобы слово владельца стало правдой, транспорт обязан видеть мягкую остановку МЕЖДУ попытками и в бэкоффе — это заказано §4.2 движкового промта. ⭐ Нашёл не я: моя механика прошла в акт непроверенной, и её опроверг чтением кода старший коллега, которого я позвал ревьюить уже написанный промт. +**2. ⛔ ЭРРАТА К СОБСТВЕННОМУ АКТУ: `D39.234` п.1б назвал МЕХАНИЗМ, который ратифицированных ~20 минут НЕ ДАЁТ.** Слово владельца («одна летящая попытка, ~20 минут приемлемо») в силе и не меняется. Неверна была моя скобка «отказ на пер-вызовном гейте резервации». Замер: резервация берётся ОДИН раз на `runAttempt` (`backend/internal/pipeline/stagerun.go:477`=`finish string`, `admit` на `:570`), а `client.Complete` (`:699`) держит под ней ВСЮ цепочку ретраев — это дословно говорит комментарий самого кода: «This timer wraps client.Complete — the WHOLE retry chain» (`stagerun.go:984`); `retryLoop` между попытками смотрит только `ctx.Err()` (`backend/internal/llm/httpllm.go:197`=`owedCut = moreOwed(owedCut, err)`). ⇒ гейт ограничивает ожидание ЦЕПОЧКОЙ (~64 мин), а не попыткой (~20). Чтобы слово владельца стало правдой, транспорт обязан видеть мягкую остановку МЕЖДУ попытками и в бэкоффе — это заказано §4.2 движкового промта. ⭐ Нашёл не я: моя механика прошла в акт непроверенной, и её опроверг чтением кода старший коллега, которого я позвал ревьюить уже написанный промт. **3. Два парных промта выданы.** `docs/BACKEND_SOFT_STOP_SESSION_PROMPT.md` (строки **381** · **382** · **377** · **372** · **375** · **379**а) и `docs/PLATFORM_SOFT_STOP_SESSION_PROMPT.md`. Порознь НЕ лендятся (`D39.234` п.2). Движковый идёт ОДНОЙ сессией в ДВА лендинга с заранее объявленной линией (резать на две сессии нельзя: §4.2 и §4.8 правят одну функцию `retryLoop`); кончившийся контекст после первого лендинга объявлен штатным исходом. ⚠ Обе редакции промтов правились ДО выдачи по ревью: в движковом восемь мест, в платформенном шесть — включая ДВЕ мои прямые лжи («латч не остановит банковые проходы» — они идут через тот же гейт; «`cancelled` не может затереть настоящую причину» — может, апсерт по ключу стадии ЗАМЕНЯЕТ строку). diff --git a/docs/architecture/15-money-path.md b/docs/architecture/15-money-path.md index 7955e798..e6ee35c8 100644 --- a/docs/architecture/15-money-path.md +++ b/docs/architecture/15-money-path.md @@ -22,8 +22,8 @@ - **`--ceiling-usd` — КНИЖНЫЙ потолок, не бюджет прогона.** Дословно из флага: «the book USD ceiling in force for THIS RUN ONLY — it OVERRIDES book.yaml `ceilings.book_usd` and is never written back. It caps the book's CUMULATIVE committed+reserved spend, not this run's increment…» (`backend/cmd/tmctl/invocation.go:142`=`the book USD ceiling in force for THIS RUN ONLY`; ⚠-коммент `backend/cmd/tmctl/main.go:261`=`--ceiling-usd is NOT a per-run budget`; многоточие закрывает обрыв цитаты — во флаге дальше стоит «, and must be > 0»). Ратификация — D39.122 п.2(в): пересчёт «пользовательский прирост → абсолют» — обязанность ПЛАТФОРМЫ, вторая денежная ось не заводится. День-потолок флаг НЕ перекрывает (PD-157). Проводка внутри: `Ceilings.BookUSD` в `Reserve` и именование сработавшего потолка в ошибке — `backend/internal/pipeline/stagerun.go:629`=`BookUSD: r.bookCeilingUSD()` и `backend/internal/pipeline/stagerun.go:716`=`overrides the book's ceilings.book_usd` (стоп = `errReserveCeiling`, `backend/internal/pipeline/escalation.go:49`=`var errReserveCeiling`). - **Потолки — wiring, не семантика:** `Ceilings` намеренно исключены из `BriefHash` («Wiring fields (paths, ceilings, db) deliberately excluded», `backend/internal/config/book.go:345`=`Wiring fields (paths, ceilings, db) deliberately excluded`; канон — `backend/internal/config/book.go:369`=`canon := struct {`) ⇒ смена ДЕНЕЖНОГО потолка не двигает ни снапшот, ни ре-билл (D39.110 п.2б). ⚠ Верно ровно про ДЕНЬГИ: потолок СЕГМЕНТАЦИИ `edit_ceiling_out` в снапшот ВХОДИТ и меняет границы чанков (`backend/internal/pipeline/snapshot.go:34`=`EditCeilingOut int`). - **`status --json` отдаёт фигуры платформе:** `committed_usd`, `reserved_usd`, `book_ceiling_usd`, `ceiling_pct` = 100·(committed+reserved)/book_ceiling (`backend/internal/pipeline/status.go:342`=`book_ceiling_usd,omitempty`; арифметика `ceiling_pct` — `backend/internal/pipeline/status.go:949`=`100 * (committed + reserved)`). Дневной фигуры в status нет (PD-157 — `platform/docs/DEFECT_REGISTER.md`, греп `PD-157`). -- **Леджер = НИЖНЯЯ граница; строка 78 снята с трекера 10.09, но её ЖИВОЙ ОСТАТОК несёт строка 377.** ⛔ **Испр. 10.09 — прежняя редакция этого пункта, написанная в тот же день, была НЕВЕРНА, и ошибка моя.** Она утверждала, будто оплаченный `2xx` с нечитаемым телом «прежде в `request_log` не попадал» и что это починил пак оборванных вызовов. Замер: ветвь `BilledDecodeError` писала свою строку с пометкой оценки ещё до пака — на `3f05fab^` это `stagerun.go:629`, введено коммитом `2f91b04` **24.07**, а пак этой ветви не касался вовсе (хитов `Estimated` в его диффе по `stagerun.go` — **0**). И носитель я процитировал ЧУЖОЙ: `backend/internal/pipeline/cutcall.go:133` обслуживает `*llm.AttemptCutError` (`backend/internal/pipeline/stagerun.go:741`), а речь шла о `*llm.BilledDecodeError` (`stagerun.go:709`) — это разные классы, и второй до `cutcall.go` не доходит. **Что пак действительно купил:** строку `request_log` за вызов, который оборвали МЫ (прежде он падал в ветвь «ничего не куплено» и получал $0-строку) — вот это `cutcall.go:133`. **Что остаётся правдой:** леджер — нижняя граница, потому что обрыв, за которым ретрай УСПЕЛ, исчезает бесследно (строка **377**). Живой замер `D39.86` — 3 вызова из 14, неизвестность $0.015111 при леджере $0.114378. -- **ГРАНИЦА ДЕНЕГ ЗА ОБОРВАННЫЙ НАМИ ВЫЗОВ — ФАКТ ДОСТАВКИ, а не статус-строка** (пак строки 360, акт `D39.232`; слово владельца — `D39.230`). Деньги берутся, только когда провайдер подтвердил запрос ответным объектом: `backend/internal/llm/attemptcut.go:221`=`Billable: answered && tr.afterHeaders()`. Наш собственный дедлайн даёт свой класс `attempt_timeout` без ретрая; дедлайн вычисляется ИЗ БЮДЖЕТА вызова, а не назначается (`backend/internal/llm/attemptcut.go:269`=`func (p RetryProfile) deriveDeadline`), так что эскалация, удвоившая `max_tokens`, удваивает и время. Оплаченный обрыв получает чекпойнт, и резюм его НЕ перепокупает. ⛔ Пометка «это оценка» — УСЛОВИЕ слова владельца (`D39.230` п.1) — сегодня в движке живёт ТРЕМЯ носителями (колонка `Estimated` в `request_log` — `backend/internal/store/requestlog.go:41`; пара `estimated_rows`/`estimated_usd` в `status --json` — `backend/internal/pipeline/status.go:911`; печать оператору — `backend/cmd/tmctl/render.go:402`), но НАРУЖУ не выходит ни одним каналом шва: строка **382**. ⚠ Формулировка испр. 10.09 — прежняя («живёт только в `status --json`») звала следующего чинить пометку, которая уже есть. +- **Леджер = НИЖНЯЯ граница; строка 78 снята с трекера 10.09, но её ЖИВОЙ ОСТАТОК несёт строка 377.** ⛔ **Испр. 10.09 — прежняя редакция этого пункта, написанная в тот же день, была НЕВЕРНА, и ошибка моя.** Она утверждала, будто оплаченный `2xx` с нечитаемым телом «прежде в `request_log` не попадал» и что это починил пак оборванных вызовов. Замер: ветвь `BilledDecodeError` писала свою строку с пометкой оценки ещё до пака — на `3f05fab^` это `stagerun.go:629`, введено коммитом `2f91b04` **24.07**, а пак этой ветви не касался вовсе (хитов `Estimated` в его диффе по `stagerun.go` — **0**). И носитель я процитировал ЧУЖОЙ: `backend/internal/pipeline/cutcall.go:133`=`rl := r.baseRequestLog(c.stage, c.chunk` обслуживает `*llm.AttemptCutError` (`backend/internal/pipeline/stagerun.go:741`), а речь шла о `*llm.BilledDecodeError` (`stagerun.go:709`) — это разные классы, и второй до `cutcall.go` не доходит. **Что пак действительно купил:** строку `request_log` за вызов, который оборвали МЫ (прежде он падал в ветвь «ничего не куплено» и получал $0-строку) — вот это `cutcall.go:133`. **Что остаётся правдой:** леджер — нижняя граница, потому что обрыв, за которым ретрай УСПЕЛ, исчезает бесследно (строка **377**). Живой замер `D39.86` — 3 вызова из 14, неизвестность $0.015111 при леджере $0.114378. +- **ГРАНИЦА ДЕНЕГ ЗА ОБОРВАННЫЙ НАМИ ВЫЗОВ — ФАКТ ДОСТАВКИ, а не статус-строка** (пак строки 360, акт `D39.232`; слово владельца — `D39.230`). Деньги берутся, только когда провайдер подтвердил запрос ответным объектом: `backend/internal/llm/attemptcut.go:221`=`Billable: answered && tr.afterHeaders()`. Наш собственный дедлайн даёт свой класс `attempt_timeout` без ретрая; дедлайн вычисляется ИЗ БЮДЖЕТА вызова, а не назначается (`backend/internal/llm/attemptcut.go:269`=`func (p RetryProfile) deriveDeadline`), так что эскалация, удвоившая `max_tokens`, удваивает и время. Оплаченный обрыв получает чекпойнт, и резюм его НЕ перепокупает. ⛔ Пометка «это оценка» — УСЛОВИЕ слова владельца (`D39.230` п.1) — сегодня в движке живёт ТРЕМЯ носителями (колонка `Estimated` в `request_log` — `backend/internal/store/requestlog.go:41`=`Estimated marks a row whose CostUSD`; пара `estimated_rows`/`estimated_usd` в `status --json` — `backend/internal/pipeline/status.go:911`=`Re-payment projection (spec`; печать оператору — `backend/cmd/tmctl/render.go:402`), но НАРУЖУ не выходит ни одним каналом шва: строка **382**. ⚠ Формулировка испр. 10.09 — прежняя («живёт только в `status --json`») звала следующего чинить пометку, которая уже есть. - **Согласие на пере-оплату — ДВИЖКОВЫЙ гейт**. Прогон, который пере-покупает уже оплаченные юниты дороже порога, ОСТАНАВЛИВАЕТСЯ и требует явного согласия. Порог по умолчанию ратифицирован D20.2-Q2: `min($0.50, 5% × ProjectedBookUSD)`. Носитель — `backend/internal/pipeline/rebill.go`, греп `rebillConsentThreshold`; единственная ручка книги — `rebill_consent_usd` (валидатор `backend/internal/config/book.go`, греп `rebill_consent_usd`; 0 = ратифицированный дефолт). ⚠ Порог считается БЕЗ контура банк-ролей (D39.182 §3), то есть срабатывает позже, чем подсказывает полная проекция.