Act on the senior review of the ratification: correct four facts on the bank ontology page, split its defect class in two, and ratify the disputed-row practice into the register rule itself
This commit is contained in:
parent
126865bf16
commit
371f15ff2b
7 changed files with 71 additions and 22 deletions
File diff suppressed because one or more lines are too long
|
|
@ -11,6 +11,8 @@
|
|||
> ⚠ **Эррата 16.08-г (D39.138 п.2а, часть «TermStatus снять с провода»):** ОПРОКИНУТА пост-ревью АВТОРА отчёта research/28 (по заказу владельца, речек оркестратора уликами): обоснование Б-0 «ни один экран их не рисует» подменяло «экрана подписи ещё НЕТ» — ось статуса ПРОДУКТОВАЯ (спека `:1070-1072`: «главный фильтр работы» S5; шов клиента уже потребляет — `frontend/src/api/vocabulary.ts:159-163`). Читать так: ось `TermStatus` ОСТАВИТЬ, движковые слова значений переименовать в продуктовые; «`TermOrigin` снять/переименовать» (`ruby` — паро-специфика) — В СИЛЕ. Контекст метода: Б-0/Б-11а/Б-23 добавлены в отчёт ПОСЛЕ раунда адверсариального судейства сессии — их основания проверять строже (помечено в ревью-шапке отчёта).
|
||||
> ⚠ **Эррата 20.08 (D39.153 п.7б):** D39.144 п.2 атрибутирует пер-термный гейт полноты банка «изобретению КОНТРАКТНОЙ линии (Ф-14 → спека → 0.3.0)» — верно про ГЕЙТ и **неверно про ФОРМУЛУ**. Формула «стоп очищается, когда каждый терм промоутнут ИЛИ отклонён» родилась 19.07 В ДВИЖКЕ как лечение ливлока R1-FL-B (отклонённый терм переспрашивался каждый прогон — тело D39.19, слайс `../archive/architecture/05-decisions-D39-arch-reset.md:22`) и живёт там до сих пор (`backend/internal/pipeline/mining.go:80-82,243`); контрактная линия 04.08 переписала её дословно и вывела из неё ЭКРАННЫЙ гейт — счётчик «решено N из M» и запрет продолжить (коммит `16e20e5`, `frontend/docs/API_CONTRACT_INPUT.md:258-264`). **Следствие, из-за которого эррата несущая:** снимая гейт, D39.144 адресовала только контракт, поэтому движковая половина осталась БЕЗ явной отмены — она сегодня ОБОЙДЕНА платформой (флаг не передаётся на resume), а не устранена; носитель — строка 191(б), развилка — строка 203(з).
|
||||
> ⚠ **Эррата 27.08 (D39.158 п.7):** D39.153 п.7б объявляет «ОСТАТКА-РАТИФИКАЦИИ НЕТ… гейт проверяет полноту ФАЙЛА решений, а не подписей, и ОДИН файл со всем банком его снимает — конфликта с моделью владельца нет». Читать так: диспозиция отвечала на вопрос «снимает ли гейт один файл» (снимает) и верифицировала СОСТАВНОЕ поведение — платформа снимает флаг, движок уходит по авто-ветке. Вопрос «работает ли флажок БЕЗ обхода» ею не закрывался, и заказанное той же строкой 191(б) «ослабить границу самой паузы» исполнено не было. Исполнено D39.158: движковая половина УСТРАНЕНА, не обойдена.
|
||||
> ⚠ **Эррата 27.08-б (D39.158, страница `18-bank-ontology.md`):** названный там класс дефекта «проекция без потребителя и без якоря свежести» на момент ратификации имел ОДИН ярус и не судил носитель с ДВУМЯ писателями и нулём читателей. Дописан второй ярус: расхождение писателей ничем не судится, пока читателя нет, а в день его появления СТАНЕТ семантикой, разрешаемой задним числом по накопленной истории. Найдено платформенной сессией при вычитке приёмки D39.159 (живой член — `PD-396`); правило «у источника РОВНО один писатель» с этого дня читается в обе стороны.
|
||||
> ⚠ **Эррата 27.08-в (D39.158 п.1):** «движок исполняет продуктовую модель сам» сказано без ратифицированной ОГОВОРКИ — правка ОТДЕЛЬНОГО термина через дверь доступна только для mined-термов; правка СИД-терма дверью отклоняется по имени (`internal/membank/decisions.go:359`), потому что это перенос базового снапшота и пере-оплата черновой волны — другое решение (щель ратифицирована, строка бэклога 192). Ещё три места, где модель шире кода, названы строками: окно глав одним решением не правится (named-узость v1) · банк-экспорт на стопе пуст (224) · «полный останов» — это граница ПЕРЕД редакторской волной, черновая довершается (S16). Найдено вычиткой старшего при ревью D39.159.
|
||||
|
||||
> ⚠ **Навигация (актуализация 07.08, эра D39.1xx):** append-only-дисциплина (D23.3) означает, что
|
||||
> НЕВЕРНЫЙ ФАКТ внутри старой ноты не переписывается, а получает эрратау — и тогда он опасен ровно
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,6 +1,6 @@
|
|||
# 17 — Закон входной двери шва движок ↔ платформа
|
||||
|
||||
> **СТАТУС: РАТИФИЦИРОВАНО D39.156 (слово владельца 23.08).** Это НОРМА, ссылаться на неё можно. Собрано оркестратором №19 по консилиуму
|
||||
> **СТАТУС: РАТИФИЦИРОВАНО D39.156 (слово владельца 23.08).** Это НОРМА, ссылаться на неё можно. ⚠ **ИСПОЛНЕН 27.08: первая дверь по этому закону ПОСТРОЕНА и заленджена** — `tmctl bank-apply`, четыре пака зоны бэкенда, ратификация D39.158 (лендинг `d1eb8a9`). Закон с этого дня читается не как план, а как норма, у которой есть работающий образец; онтология слоя, который дверь обслуживает, — `18-bank-ontology.md`. Собрано оркестратором №19 по консилиуму
|
||||
> со сторонним архитектором 22–23.08.2026. Ратифицирована одной D-нотой; с этого момента двери встают паками без
|
||||
> возврата к владельцу — ровно так, как код выхода `13` встал в ратифицированную полосу 10–19 без
|
||||
> нового решения ВЛАДЕЛЬЦА (D39.131 п.2а → D39.132 п.2г → D39.134: код 13 прошёл через направление и
|
||||
|
|
|
|||
|
|
@ -4,26 +4,33 @@
|
|||
> при конфликте побеждает журнал решений. Собрано оркестратором №19 по консилиуму со сторонним
|
||||
> архитектором при приёмке четырёх паков входной двери шва.
|
||||
>
|
||||
> **Зачем страница.** Вокруг одного понятия — «состояние банка этой книги» — живут девять носителей,
|
||||
> **Зачем страница.** Вокруг одного понятия — «состояние банка этой книги» — живут десять носителей,
|
||||
> выросших пак за паком. Форма при этом СТРОГАЯ: поток однонаправленный, у каждого источника
|
||||
> единственный писатель, вид пересобирается полностью на каждой границе прогона. Но эта строгость не
|
||||
> была записана нигде — каждый файл документировал свою роль, ни одно место не документировало поток.
|
||||
> Из-за этого приёмка сначала прочитала девять носителей как девять заплаток и едва не заказала
|
||||
> рефактор ради стройности. Страница дешевле рефактора и снимает причину, а не симптом.
|
||||
|
||||
## Три роли, и они не смешиваются
|
||||
## Четыре роли, и они не смешиваются
|
||||
|
||||
| Роль | Носители | Писатель | Момент фиксации |
|
||||
|---|---|---|---|
|
||||
| **ИСТОЧНИКИ** — то, из чего банк собирается | `glossary_seed` · `<book_id>.mined-delta.yaml` · `<book_id>.mined-rejects.yaml` (слово ВЛАДЕЛЬЦА, рядом с `book.yaml`, едут с книгой в бэкапе и экспорте) · `<project_db>.auto-bank.yaml` (слово ДВИЖКА, сидит при базе) · ruby-чтения в хранилище | у каждого РОВНО один; у трёх первых — `tmctl bank-apply` и рука владельца, у авто-банка — прогон | запись под эксклюзивным флоком проекта |
|
||||
| **ИСТОЧНИКИ** — то, из чего банк собирается | `glossary_seed` · `<book_id>.mined-delta.yaml` · `<book_id>.mined-rejects.yaml` (слово ВЛАДЕЛЬЦА, рядом с `book.yaml`, едут с книгой в бэкапе и экспорте) · `<project_db>.auto-bank.yaml` (слово ДВИЖКА, сидит при базе) · ruby-чтения в хранилище | у каждого РОВНО один. ⚠ Дверь `bank-apply` пишет ТОЛЬКО два файла решений: правка сид-терма ею ОТКЛОНЯЕТСЯ по имени (`internal/membank/decisions.go:359`), потому что это перенос базового снапшота и пере-оплата черновой волны — другое решение (щель ратифицирована, строка 192). `glossary_seed` — рука владельца · `auto-bank` — прогон · ruby — хранилище | запись двери — под эксклюзивным флоком проекта; рука владельца флока не берёт (остаток — строка 222) |
|
||||
| **ВИД** — банк, каким его видят роли | строки глоссария в хранилище | только `seedGlossary`, и только полным пересбором | каждая граница прогона; один загрузчик, все гарды |
|
||||
| **ПРОЕКЦИИ** — то, что банк рассказывает наружу | `<project_db>.bank.json` (единственный канал банка наружу) · карта подписи `<project_db>.mined-signature.yaml` · человеческая таблица стопа `.bank-stop.txt` | прогон, на границе | после смены вида |
|
||||
| **ПРОЕКЦИИ** — то, что банк рассказывает наружу | `<project_db>.bank.json` (единственный канал банка наружу) · карта подписи `<project_db>.mined-signature.yaml` · человеческая таблица стопа `.bank-stop.txt` | прогон, на границе | ⚠ не одинаков: `bank.json` — ПОСЛЕ смены вида; карта подписи и `.bank-stop.txt` — при вычислении стопа, ДО пере-сида, а на стоп-границе вид вообще не меняется (остановившийся прогон авто-банк не пишет) |
|
||||
| **ПАМЯТЬ ФЛАЖКА** — что стоп уже предъявлял | таблица `bank_stop_presented` | стоп | ПОСЛЕ карты, никогда до |
|
||||
|
||||
**Поток однонаправленный: источники → вид → проекции.** Отсюда главное свойство, из-за которого
|
||||
рефактор не нужен: **расхождение источников с видом структурно невозможно дольше одной границы
|
||||
прогона**, потому что вид не патчится, а пересобирается целиком.
|
||||
|
||||
⚠ **Единственная петля — авто-провод, и она названа здесь нарочно:** прогон пишет собственный ИСТОЧНИК
|
||||
(`auto-bank`) и пере-сидит вид в той же границе. Это первое, куда ткнёт проверяющий однонаправленности.
|
||||
Петля реальна и защищена с двух сторон — `unsignedEngineSurfaces` держит границу подписанного, а
|
||||
`loadAutoBank` отказывает строке со статусом `approved`, — то есть слово движка не может присвоить себе
|
||||
слово владельца. Однонаправленность формулируется точно так: **петля есть, но она не может изменить
|
||||
подписанное.**
|
||||
|
||||
## Почему слово владельца и слово движка не сливаются
|
||||
|
||||
Соблазн понятный: одобрения владельца и авто-строки движка — одинаковые по форме строки банка. Но
|
||||
|
|
@ -48,10 +55,26 @@
|
|||
карты не существует, то есть молчаливую потерю навсегда. Инвариант, живущий в комментарии, не
|
||||
держится ничем — держит его пин.
|
||||
|
||||
⚠ **Класс дефекта, названный этой страницей: проекция без контракта потребителя и без якоря свежести
|
||||
в самой себе.** Три известных члена: снесённая таблица стопа · банк-экспорт до конверта · порядок
|
||||
«карта → память» до пина. Четвёртый живёт строкой бэклога: банк-экспорт на стопе ПУСТ — проекция,
|
||||
наиболее пустая ровно в тот момент, когда её читает экран подписи.
|
||||
⚠ **КЛАСС A, названный этой страницей: проекция без контракта потребителя и без якоря свежести
|
||||
в самой себе.** Два известных члена: снесённая таблица стопа · банк-экспорт до конверта. Третий живёт
|
||||
строкой бэклога 224: банк-экспорт на стопе ПУСТ — проекция, наиболее пустая ровно в тот момент, когда
|
||||
её читает экран подписи.
|
||||
|
||||
⚠ **КЛАСС B — другой, и путать их нельзя: межносительный инвариант, живущий комментарием без пина.**
|
||||
Член — порядок «карта → память» до фикс3. Он НЕ подпадает под класс A: там дефект в том, что документ
|
||||
не несёт контракта, здесь — в том, что связь ДВУХ носителей держится только текстом, который ничего не
|
||||
проверяет. Разделено 27.08 по вычитке старшего: в одном классе они были бы неподсудны — первый же
|
||||
судья отклонил бы членство порядка, и вместе с ним ушёл бы весь класс.
|
||||
|
||||
⚠ **Второй ярус КЛАССА A, дописан 27.08 по замечанию платформенной сессии при приёмке
|
||||
`D39.159`: носитель с ДВУМЯ писателями и НОЛЬ читателей.** Здесь опасность не в отсутствии
|
||||
потребителя — она в том, что расхождение писателей ничем не судится, пока читателя нет, а в день,
|
||||
когда читатель появится, разница СТАНЕТ семантикой, и разрешать её придётся задним числом по уже
|
||||
накопленной истории. Отсутствие потребителя из симптома делается отсрочкой платежа. Живой член —
|
||||
`books.chunker_version` в платформе (`PD-396`); родня по эту сторону шва — мёртвые поля шва и
|
||||
`ingest.StatusReport.UnsignedBankTerms`. Отсюда правило таблицы выше — «у каждого источника РОВНО
|
||||
один писатель» — читается в обе стороны: **два писателя без читателя судятся так же строго, как
|
||||
проекция без потребителя, и чинятся раньше, а не когда читатель придёт.**
|
||||
|
||||
## Чего эта форма НЕ несёт
|
||||
|
||||
|
|
|
|||
|
|
@ -51,3 +51,21 @@
|
|||
- **Глава** — единица структуры книги: детект `chunk/ingest.go` (txt: CJK-шапки/form-feed; epub: документ spine), нумерация плотная позиционная + титульная политика `chunk/chunker.go` (`stripHeading`/`ApplyHeading` по `langpacks/*/heading.txt`), идентичность = контент-хеш в манифесте (`pipeline/manifest.go`), деньги ключуются ПОЗИЦИЕЙ (сдвиг границы = перекупка хвоста). Дизайн будущего — `research/27`.
|
||||
- **Деньги платформы:** **холд** — резервация суммы прироста на счёте ДО спавна; **прирост** — купленные главы × ставка ($0.03, `platform/internal/pricing/pricing.go`); **аргумент потолка** — что уходит движку в `--ceiling-usd` = committed книги + прирост (PD-158; ЭТО НЕ ХОЛД — он больше холда на committed); **baseline** — счётчик книги на старте попытки, списание = разница; **settle/расчёт** — закрытие холда по фигуре движка; **leftover-reserved** — висячий reserved движка после краша (зануляется его write-open); **SpendBound** — верхняя граница отложенного расчёта по baseline следующей попытки (PD-159).
|
||||
- **Лексикон экспериментов:** **жилец** — модель на роли; **арм** — вариант в бейк-оффе; **однопроходка/второй проход** — топологии редактуры; **закон-блок** = доктрина инжекта (D39.104); **пол/floor** — нижний якорь шкалы судьи; **Холм** — поправка Холма на множественные сравнения; **порог различимости** — минимальная дельта, отличимая от шума риге.
|
||||
- **Входная дверь шва** — половина контракта движок↔платформа, которой не было: наружу поток богатый,
|
||||
внутрь не шло ничего, кроме запуска с флагами. Закон — D39.156 (`17-seam-inbound-law.md`), построена
|
||||
и заленджена D39.158.
|
||||
- **`tmctl bank-apply`** — $0-глагол входной двери: кладёт правки банка памяти, сделанные пользователем.
|
||||
Проекция `--dry-run`, всё-или-ничего, байтовый no-op идемпотентен, лок проекта неблокирующий.
|
||||
- **Стоп банка** — ФЛАЖОК, а не развилка: движок останавливается на границе майнинга, показывает банк
|
||||
и ждёт «ОК» = продолжить. Подписывается БАНК целиком либо правится отдельный термин — пер-термной
|
||||
масс-подписи НЕТ (модель владельца 16.08, D39.144). Предъявленное помнится (`bank_stop_presented`,
|
||||
схема store v16), поэтому стоп срабатывает ОДИН раз на одно и то же.
|
||||
- **Полоса отказов [10,19]** — коды выхода движка, отличающие «отказал ЗАКОННО» от «сломался»:
|
||||
10 конфиг · 11 источник · 12 лок · 13 схема · 14 решения отклонены · **15 `write_incomplete`** · 19 без имени.
|
||||
- **Онтология банка** — `architecture/18-bank-ontology.md`: три роли носителей (источники · вид ·
|
||||
проекции · память флага), их писатели и моменты коммита. Названный там класс дефекта — «проекция
|
||||
без названного потребителя и без якоря свежести в кадре».
|
||||
- **`ОСПОРЕНО(PD-N)`** — грепаемый токен реестра дефектов платформы: строка стоит `fixed`, но пак
|
||||
доказал, что её пин доказывает свойство СЛАБЕЕ, чем строка гласит. Статус НЕ меняется, живой пробел
|
||||
несёт новая строка `PD-N`. Ратифицирован D39.159 при условии двусторонней ссылки.
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,13 @@
|
|||
>
|
||||
> Правила: каждая находка любой сессии/приёмки/аудита — строкой сюда ДО закрытия; ID стабилен навсегда;
|
||||
> закрытие — только с коммитом фикса и тестом, пинящим свойство (урок PD-1: свойство без пинящего теста
|
||||
> считается НЕ закрытым). Класс: `vuln` — эксплуатируемо или ослабляет защиту · `bug` — неверное поведение ·
|
||||
> считается НЕ закрытым). ⚠ **Оговорка к PD-1, ратифицирована D39.159 и дописана 27.08 по вычитке
|
||||
> старшего:** строка `fixed`, чей пин доказывает МЕНЬШЕ, чем строка гласит, **не пере-открывается**,
|
||||
> когда описанный ею дефект из кода ушёл, — иначе регистр объявляет вернувшимся баг, который не
|
||||
> воспроизводится, и считает один пробел двумя открытыми. Живой пробел несёт открытая строка-преемник
|
||||
> с ДВУСТОРОННЕЙ ссылкой и токеном `ОСПОРЕНО(PD-N)` в оспоренной строке. Пере-открытие — только когда
|
||||
> дефект ВОСПРОИЗВОДИТСЯ. Без этой оговорки практика и буква правила спорили бы в одном файле, и
|
||||
> следующая приёмка пере-судила бы спор с нуля. Класс: `vuln` — эксплуатируемо или ослабляет защиту · `bug` — неверное поведение ·
|
||||
> `hardening` — защита в глубину / латентное · `doc` — док лжёт о коде · `standards` — расхождение с
|
||||
> объявленной нормой зоны (введены приёмкой P2; словарь отставал от строк — испр. оркестратором №15). Статус: `open` · `fixed(<commit>)` · `accepted-risk(<кем, когда>)`.
|
||||
|
||||
|
|
@ -57,7 +63,7 @@
|
|||
|
||||
| ID | Класс | Серьёзность | Где | Суть | Статус | Источник |
|
||||
|---|---|---|---|---|---|---|
|
||||
| PD-398 | standards | info | `docs/scripts/counts.py` `malformed`, строки `PD-99` и `PD-197` этого файла | **Гейт формы регистра ловит только НЕДОСТАЧУ ячеек, а не избыток — и в файле уже есть две строки, которые он пропускает.** `malformed()` сравнивает `if n < shape`, поэтому строка с лишним символом вертикальной черты внутри инлайн-кода проходит молча: счёт ячеек через `awk` с разделителем-чертой даёт `PD-99` (11 ячеек) и `PD-197` (10), а `counts.py --check` печатает `битая форма: []`. Обе строки допаковые, обе сломаны греп-альтернацией и регекспом в тексте. ⚠ Что СМЯГЧАЕТ и почему это `info`, а не выше: `col()` считает колонки С КОНЦА, поэтому статус и вес таких строк читаются ВЕРНО, и сегодняшние числа зоны не врут — пере-проверено, `PD-99` и `PD-197` попадают в свои корзины правильно. Дыра латентная: лишняя черта в одной из ТРЁХ последних колонок сдвинет уже их, и гейт снова промолчит. Пак наткнулся на это ДВАЖДЫ собственной рукой, и второй раз — этой же строкой: первая её редакция цитировала команду счёта ВМЕСТЕ с разделителем-чертой и сломала себя ровно тем, что описывает. моя же правка `PD-396` внесла конвейер в ячейку, счётчик весов выдал мусорный ключ вместо `info`, а `битая форма` осталась пустой — то есть симптом виден в СЧЁТЕ, а не в проверке формы, которая для этого и написана. Лечение однострочное и не моё: `if n != shape` вместо `if n < shape` (зона `docs/`, решение оркестратора). Родня по классу — весь этот пак: гейт, доказывающий меньше, чем читается | open ⚠ **ПЕРЕ-ФОРМУЛИРОВАНА приёмкой (оркестратор №19, 27.08, D39.159 п.8): предложенная правка ОТКЛОНЕНА замером.** `n != shape` краснит СЕМЬ законных строк (пять бэклога, две регистра), потому что колонки читаются С КОНЦА НАМЕРЕННО — `counts.py:132` называет это прямо и приводит ровно этот случай (строка бэклога 127 несёт три слова через вертикальную черту внутри инлайн-кода). Избыток в ПЕРВОЙ содержательной ячейке легален, и числа из-за него не врут: проверено, статус и вес читаются из хвоста, `PD-99` и `PD-197` разбираются верно. **Настоящий остаточный риск — избыток в ХВОСТОВОЙ ячейке:** там лишняя вертикальная черта сдвинула бы именно статус или вес, и тихо. Ловится не счётом ячеек, а сверкой хвостового словаря (статус ∈ {open, fixed, accepted-risk}); сегодня у такой сверки два известных доброкачественных исключения — `PD-59` и `PD-273` несут статус прозой. Строка остаётся ОТКРЫТОЙ под эту формулировку | ревью-пак P8-REVIEW (наткнулся при правке собственной строки, подтверждено редакторским аудитом) |
|
||||
| PD-398 | standards | info | `docs/scripts/counts.py` `malformed`, строки `PD-99` и `PD-197` этого файла | **Гейт формы регистра ловит только НЕДОСТАЧУ ячеек, а не избыток — и в файле уже есть две строки, которые он пропускает.** `malformed()` сравнивает `if n < shape`, поэтому строка с лишним символом вертикальной черты внутри инлайн-кода проходит молча: счёт ячеек через `awk` с разделителем-чертой даёт `PD-99` (11 ячеек) и `PD-197` (10), а `counts.py --check` печатает `битая форма: []`. Обе строки допаковые, обе сломаны греп-альтернацией и регекспом в тексте. ⚠ Что СМЯГЧАЕТ и почему это `info`, а не выше: `col()` считает колонки С КОНЦА, поэтому статус и вес таких строк читаются ВЕРНО, и сегодняшние числа зоны не врут — пере-проверено, `PD-99` и `PD-197` попадают в свои корзины правильно. Дыра латентная: лишняя черта в одной из ТРЁХ последних колонок сдвинет уже их, и гейт снова промолчит. Пак наткнулся на это ДВАЖДЫ собственной рукой, и второй раз — этой же строкой: первая её редакция цитировала команду счёта ВМЕСТЕ с разделителем-чертой и сломала себя ровно тем, что описывает. моя же правка `PD-396` внесла конвейер в ячейку, счётчик весов выдал мусорный ключ вместо `info`, а `битая форма` осталась пустой — то есть симптом виден в СЧЁТЕ, а не в проверке формы, которая для этого и написана. Лечение однострочное и не моё: `if n != shape` вместо `if n < shape` (зона `docs/`, решение оркестратора). Родня по классу — весь этот пак: гейт, доказывающий меньше, чем читается ⚠ **ПЕРЕ-ФОРМУЛИРОВАНА приёмкой (оркестратор №19, 27.08, D39.159 п.8): предложенная правка ОТКЛОНЕНА замером.** `n != shape` краснит СЕМЬ законных строк (пять бэклога, две регистра), потому что колонки читаются С КОНЦА НАМЕРЕННО — `counts.py:132` называет это прямо и приводит ровно этот случай (строка бэклога 127 несёт три слова через вертикальную черту внутри инлайн-кода). Избыток в ПЕРВОЙ содержательной ячейке легален, и числа из-за него не врут: проверено, статус и вес читаются из хвоста, `PD-99` и `PD-197` разбираются верно. **Настоящий остаточный риск — избыток в ХВОСТОВОЙ ячейке:** там лишняя вертикальная черта сдвинула бы именно статус или вес, и тихо. Ловится не счётом ячеек, а сверкой хвостового словаря (статус ∈ {open, fixed, accepted-risk}); сегодня у такой сверки два известных доброкачественных исключения — `PD-59` и `PD-273` несут статус прозой. Строка остаётся ОТКРЫТОЙ под эту формулировку | open | ревью-пак P8-REVIEW (наткнулся при правке собственной строки, подтверждено редакторским аудитом) |
|
||||
| PD-397 | hardening | info | `internal/pgstore/credits.go:52-53`=`A ledger row is never edited: the correction is another row`, `internal/pgstore/credits.go:354-356`=`The two are never written apart`, миграция `internal/pgstore/migrations/00007_credits.sql` | **Два самых сильных денежных инварианта объявлены ПРОЗОЙ и держатся ТОЛЬКО кодом — схема их не навязывает.** `Adjust` обещает «леджер не правится, коррекция это ещё одна строка, и именно это делает сумму воспроизводимой»; `appendLedger` обещает «кэш и леджер никогда не пишутся врозь, потому что отстающий кэш — это второй ответ про деньги». Проба прямым SQL по стенду показывает, что DDL допускает нарушение обоих: `UPDATE` и `DELETE` строки леджера ПРИНЯТЫ, кэш баланса выставляется ЛОЖЬЮ и ОТРИЦАТЕЛЬНЫМ тоже. Пере-проверено координатором пака независимо от агента — все четыре приняты, и откат пробы сам же оставил расхождение кэша с леджером в 1 микро-доллар, которое поймало только сведение двумя путями, а не база. ⚠ Что схема при этом ДЕРЖИТ и что находкой НЕ является (иначе строка читается как «денежных констрейнтов нет»): знак по каждому виду строки, обязательная нота у коррекции, закрытый словарь видов, непустые `source`/`source_id`, уникальность ключа идемпотентности в пределах аккаунта, положительность сумм резервации, согласованность состояния и времени закрытия, владение книгой через композитный внешний ключ, и переполнение bigint в кэше. То есть DDL закрывает ФОРМУ строки и не закрывает ИСТОРИЮ. Цена названа и она не про сегодняшний код: пути правки леджера в Go нет, поэтому эксплуатации нет — опасны миграция данных, операторский `psql` и будущий инструмент, каждый из которых по построению идёт мимо кода, а прозу в доккомментарии не читает. Лечится либо триггером на `update`/`delete` по `credit_ledger`, либо явной записью «append-only — дисциплина кода, не схемы» рядом с обещанием. ⚠ Заведено ЗАПОЗДАЛО и это отдельный факт: работа была сделана агентом оси 1 по прямому требованию промта («попробуй нарушить каждый прямым SQL; констрейнт, которого нет, это находка»), артефакт `docs/p8-review/axis1-money/constraint-probe.out` лежал в сдаче, а строки не имел — нашёл редакторский аудит полноты. Воспроизведение: `docs/p8-review/axis1-money/constraint-probe.sh` | open | ревью-пак P8-REVIEW, ось 1 (проба агента, пере-проверена координатором; строка заведена по аудиту полноты) |
|
||||
| PD-396 | standards | info | `internal/pgstore/books.go:306`=`chunker_version = $4, parse_started_at = null,`, `internal/pgstore/sink.go:127`=`update books set chunker_version = $2 where id = $1`, `internal/ingest/resync.go:30`=`UnsignedBankTerms int `json:"unsigned_bank_terms"`` | **Мёртвые поля шва: у `books.chunker_version` ДВА писателя и НОЛЬ читателей, и это второй экземпляр класса, первый назвал оркестратор.** Колонку пишет интейк из манифеста движка (`FinishParse`) и пишет тейлер из хендшейка потока (`effect`); ни одного `select` по ней в зоне нет — грепом ноль. Сегодня это безвредно, но следствие названо ЗАРАНЕЕ, потому что оно семантическое, а не техническое: в день, когда читатель появится, РАСХОЖДЕНИЕ двух писателей (чанкер прогона против чанкера разбора) станет значением, и решать, какой из них правда, придётся задним числом — по колонке, у которой уже накоплена история из обоих источников. Родня — п.4 пинга оркестратора №19: `ingest.StatusReport.UnsignedBankTerms` разбирается из ответа движка и не используется НИ ОДНОЙ строкой продакшн-кода (грепом — только объявление и его доккомментарий, где поле описано как опора экрана подписи). Формулировка оркестратора применима дословно к обоим: мёртвое поле в структуре шва читается как контракт. ⚠ Заведено ОТДЕЛЬНОЙ строкой по прямому указанию закрывающего ревью старшей модели и с его же доводом: этой фразе НЕ место в `PD-166` — та строка про потерю значения между двумя автокоммитами, и её свойство построено; держать дефект-строку открытой как плейсхолдер несуществующей фичи есть ровно та патология «open, а лекарство построено», против которой пак завёл шестнадцать дописок. Диспозиция — вопрос владельца, а не зоны: либо назначить владельца колонки (один писатель), либо записать расхождение как ожидаемое до появления читателя Воспроизведение — две команды без конвейера (символ вертикальной черты в ячейку регистра не влезает): `grep -rn chunker_version platform/internal --include=*.go` даёт два `update` и ни одного `select`, `grep -rn UnsignedBankTerms platform/internal platform/cmd --include=*.go` даёт только объявление и его доккомментарий | open | ревью-пак P8-REVIEW (побочная находка сверки реестра, оформлена по указанию закрывающего ревью) |
|
||||
| PD-378 | bug | info | `internal/pgstore/books.go:1053`=`u.RemainingPercent = int(balance * 100 / granted)`, `internal/httpapi/v0.go` `usageState`, канон `14-api-contract` `remaining_percent` | **`/v0/usage` отдаёт `remaining_percent` вне контрактных 0..100 и зажигает предупреждение «low» на полном счёте: `balance * 100` переполняет int64.** Порог измерен точно: баланс 92 233 720 368 547 758 микро ещё даёт 99%, следующий микро-доллар даёт минус 99. Ответ нарушает схему (`minimum: 0`, `maximum: 100`), и хуже того `usageState` видит отрицательное значение ниже порога `lowCredit` и отдаёт `state: "low"` — «денег почти нет» счёту на сто миллиардов. Замерено на проводе: до гранта `{"state":"ok","remaining_percent":96}`, после `grant --usd 100000000000` → `{"state":"low","remaining_percent":-84}`; соседняя арифметика (`pricing.Scale`, `balance`) при том же балансе отвечает верно, то есть переполнение локально именно в этой строке. ⚠ Рефутер сузил minor → info: чтобы туда попасть, оператор должен добавить на счёт не меньше 92.23 млрд долларов, ни одна пользовательская ручка кредит не пишет; прецедент веса — `PD-39`. ⚠ Оговорка рефутера в другую сторону: более правдоподобный носитель — не разовая команда, а конфиг `TM_PLATFORM_SIGNUP_GRANT_USD`, у которого верхней границы нет и значение НАМЕРЕННО не печатается в стартовый лог, так что промах в нём сломал бы `/usage` каждому новому аккаунту невидимо. Воспроизведение: `docs/p8-review/axis1-money/a1-usage-overflow.sh` (сам откатывает грант) | open | ревью-пак P8-REVIEW, ось 1 (живой провод, сужено рефутером с измеренным порогом) |
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue