- байтовый порядок канонических форм остался тай-брейком только внутри одной доставки: на живом корпусе он решал 98,8% спорных координат и системно хранил меньшее значение, из-за чего step_count терял род и verify:archive был красным - правило перестало быть коммутативным осознанно, поэтому порядок свёртки приведён к журнальному: проход воркера прекращается на отложенной доставке, а свёртка вне порядка журнала пишет WARN - заведены счётчики PointsHeld и PointsErased — удержание полнотой и единственное направление, в котором правило теряет содержание
369 lines
35 KiB
Markdown
369 lines
35 KiB
Markdown
# Триаж: tie-break-equal-completeness
|
||
|
||
## Сводка
|
||
|
||
- **Профиль:** `deep`, режим — линейный (по слову оператора). База диффа
|
||
`de2001d`.
|
||
- **Гейт:** зелёный. Непокрытыми остались 9 изменённых строк — все ветки
|
||
обработки ошибок (`internal/replay/worker.go:272-275`,
|
||
`internal/store/bucket.go:488,564-565`, `internal/store/delivery.go:266-267`).
|
||
- **Проходы поимённо, с исходом** (сверено с профилем: `deep` = 7–8 проходов по
|
||
`docs/review.md`, здесь 7 на коде включая триггерный `reimpl` — расхождения с
|
||
составом профиля нет):
|
||
- `gate` — отработал, зелёный, 3 находки о покрытии тестами;
|
||
- `specs` — отработал, 6 находок; отдельно подтвердил построчно, что
|
||
переписанные тесты не подгоняют оракул;
|
||
- `code` — отработал, 0 находок;
|
||
- `adversary` — отработал, 4 находки + ответ на вопрос журнала (пути значения
|
||
точки в лог выше `DEBUG` не найдено, 7 враждебных тел);
|
||
- `ops` — отработал, 4 находки + ответ на вопрос журнала (результат — функция
|
||
префикса журнала плюс порядка появления строк учёта);
|
||
- `reimpl` — запускался по триггеру «новое правило слияния», 3 находки; поимённо
|
||
назвал 6 мест, где существующее решение лучше его собственного, и снял одну
|
||
чужую находку (стоящая голова очереди не нема: `internal/fold/fold.go:450`
|
||
пишет `WARN` на каждую отложенную свёртку);
|
||
- `architecture` — отработал, 2 находки + 2 замечания «дешевле до мерджа»;
|
||
- до кода — профиль `design` (`specs`, `rubric`, `architecture`): находки
|
||
отработаны в спеках и коде, повторно не поднимались.
|
||
- **Вход/выход:** на входе 22 именованных находки семи проходов; после
|
||
дедупликации, оракулов и отсева — 3 блокирующих, 4 «исправить сейчас»,
|
||
6 гипотез, 3 promote-кандидата. Выброшено как вкусовщина 3 (названы в
|
||
границах покрытия).
|
||
- **Оракулы триажа** (добыты на временных базах, `./tmp/oracle/`, в `./data` не
|
||
ходил): падающий тест на разрушительное направление слияния; замер
|
||
`ParsedAfter` на 2 000/8 000/20 000 доставках; `EXPLAIN QUERY PLAN`.
|
||
- **Разрешённые конфликты проходов:** O1 против R3 — оба замера верны, спор был
|
||
об интерпретации; разрешён собственным замером (см. пункт 3 «Стоит
|
||
исправить»). A1 сверен с корпусным замером оркестратора — конструкция
|
||
воспроизводится, на живом корпусе 0 вхождений.
|
||
|
||
---
|
||
|
||
## Блокирует мердж
|
||
|
||
### 1. Обеднённая доставка стирает измеренное поле сохранённой точки, и ни один счётчик этого не видит
|
||
|
||
- Файл: `internal/store/bucket.go:561-605` (`resolve`, `pointLess`),
|
||
`internal/canon/canon.go:267-283` (`Relate`)
|
||
- Severity: critical
|
||
- Confidence: high
|
||
- Оракул: падающий тест триажа `tmp/oracle/a1_test.go`
|
||
(`TestA1ОбеднённаяПришедшаяСтираетПолеБезСчётчика`): сохранено
|
||
`{date, asleep:7.5, rem:1.2, deep:0.9}`, приехало
|
||
`{date, asleep:7.4, deep:0.9}` — `Relate` даёт `equal` (значения общего ключа
|
||
разошлись, разряд полноты гаснет), тай-брейк отдаёт победу пришедшей, в
|
||
витрине остаётся точка **без `rem`**, `PointsHeld=0`, `Incomparable=0`,
|
||
`Overwrites=1` (направления не различает). Подтверждает конструкцию
|
||
`adversary` (A1).
|
||
- Последствие: нарушение инварианта «Ничего не теряем молча» (`CLAUDE.md`,
|
||
critical). До изменения этот исход был жребием байтового порядка; теперь он
|
||
**детерминированно** в пользу обеднённой пришедшей, а новый счётчик
|
||
`PointsHeld` считает только обратное, безобидное направление. Вероятность
|
||
низкая: корпусный замер оркестратора — 0 вхождений на 80 129 спорных
|
||
координат (2 координаты с потерей ключа — ровно 2 несравнимые пары, их
|
||
считает `Incomparable`). Но порча с низкой вероятностью весит больше
|
||
гарантированного неудобства, и молчание здесь полное.
|
||
- Предложение — выбор владельца, оба варианта названы `adversary`:
|
||
- (а) счётчик разрушительного направления: победитель `incoming`, а у
|
||
проигравшего сохранённого есть содержательный ключ, которого нет у
|
||
победителя → счётчик + координата в лог (зеркально `PointsHeld`, сравнение
|
||
уже посчитанных `fields`, цена ~нулевая). Семантика слияния не меняется;
|
||
на текущем корпусе счётчик будет нулевым — это и есть утверждение.
|
||
- (б) сузить «побеждает пришедшая» до случая совпавших множеств
|
||
содержательных ключей; при несовпавших — побеждает более полная по именам.
|
||
Меняет правило слияния и текст дельты storage, требует прогона
|
||
`verify:archive` заново.
|
||
- Рекомендация триажа: (а) — восстанавливает наблюдаемость без смены
|
||
семантики, соответствует уже принятому в проекте образцу («объединение
|
||
полей отложено до счётчика, который заговорит»).
|
||
- Действие: развилка
|
||
- Найдено проходом: adversary; сверено с корпусным замером оркестратора
|
||
|
||
### 2. Стоящая голова очереди молчит меткой отставания — вопреки MUST дельты, а метка порядка при этом врёт и повторяется
|
||
|
||
- Файл: `internal/replay/worker.go:151-211` (`Pass`), `worker.go:184`
|
||
(`warnOutOfOrder` до свёртки), `worker.go:290-298` (`warnLag`)
|
||
- Severity: major
|
||
- Confidence: high
|
||
- Оракул: чтение кода — `warnLag` вызывается только в ветке пустой выборки
|
||
(`worker.go:174`), а при `Deferred` проход возвращается из середины цикла
|
||
(`worker.go:206`), не взводя и `startupDone`; значит доставка, которую
|
||
занятость откладывает проход за проходом, в метку отставания не попадает
|
||
никогда. Подтверждено живым замером `adversary` (блокировка 22.1 с: строк о
|
||
задержке 0, об отложенной свёртке 1). Дельта ingest (строки 29-33) обещает
|
||
дословно: «Стоящая голова очереди молчать MUST NOT… Метка отставания…
|
||
покрывает этот случай». Обещание не выполнено. Та же ранняя точка выхода
|
||
делает `warnOutOfOrder` лжецом: он пишется **до** свёртки, при `Deferred`
|
||
утверждает свёртку, которой не было, и повторяется каждым проходом — против
|
||
собственного комментария «одна запись на доставку».
|
||
- Последствие: класс «молчание» — задолженность растёт при занятой базе, а
|
||
единственный обещанный спекой сигнал о ней не срабатывает (частично прикрыто
|
||
`WARN "delivery fold deferred"` из `internal/fold/fold.go:450` — этим
|
||
находка понижена с потенциального critical); плюс ложный `WARN` о свёртке
|
||
вне порядка, приучающий не верить именно той строке, по которой решают о
|
||
`reindex`.
|
||
- Предложение (инлайн, одна зона в `Pass`): вызывать `w.warnLag(ctx, lag)` и на
|
||
выходе по `Deferred` (метка — одна строка на проход, шквала нет; подавление
|
||
первого прохода можно сохранить, взводя `startupDone` по завершении первого
|
||
прохода независимо от исхода); `warnOutOfOrder` писать после свёртки и только
|
||
при исходе, реально записавшем разбор (не при `Deferred`).
|
||
- Действие: инлайн
|
||
- Найдено проходами: specs (F1, F4), adversary (A2), ops (O2) — одна причина:
|
||
ранний выход `Pass` при `Deferred` не согласован с обеими метками
|
||
|
||
### 3. Документы в шести местах продолжают утверждать «победитель — функция множества», и следующий автор откатит починку молча
|
||
|
||
- Файл: `docs/architecture.md:937`, `docs/database.md:130`,
|
||
`docs/conventions/storage.md:38-40`, `internal/store/winner.go:16-19`,
|
||
`internal/store/entity_test.go:821-828`, `internal/replay/replay_test.go:173-174`
|
||
- Severity: major
|
||
- Confidence: high
|
||
- Оракул: проверено чтением — `docs/architecture.md:937`: «Победитель — функция
|
||
множества точек, а не порядка их поступления»; `docs/database.md:130`: «При
|
||
столкновении выигрывает более полная точка, а не последняя пришедшая»;
|
||
`docs/conventions/storage.md:38-40` утверждает «порядок свёртки порядку
|
||
журнала не равен» — ровно то, что это изменение сделало неверным;
|
||
`winner.go:16-19` ссылается на обещание architecture.md сменить тай-брейк «когда
|
||
род будет измерен» — дизайн это отверг (Non-Goals). Риск назван самим
|
||
`design.md`: «чтобы следующий автор не восстановил коммутативность „для
|
||
чистоты“ и не откатил починку молча» — а шесть мест документации ровно к
|
||
этому и приглашают.
|
||
- Последствие: докдрейф на critical-инварианте («Ничего не теряем молча» —
|
||
формулировка правила столкновения теперь в `CLAUDE.md` другая); строка
|
||
таблицы двух правил завышает гарантию сущностей (на несравнимых версиях они
|
||
тоже расходятся).
|
||
- Предложение: привести все шесть мест к формулировке «функция множества **и
|
||
позиции в журнале**»; заодно выполнить записанное правило `CLAUDE.md`
|
||
(«причина отказа от готового решения — промоутом в `docs/adr/`»): причина
|
||
отказа от LWW-Register/CRDT уже написана в `design.md`, её осталось поднять
|
||
в ADR — это часть той же работы «документы догоняют правило».
|
||
- Действие: инлайн
|
||
- Найдено проходом: architecture (AR1 + замечание про ADR)
|
||
|
||
---
|
||
|
||
## Стоит исправить сейчас
|
||
|
||
### 1. Отчёт пересборки не называет удержанные точки (SHALL дельты), а одно из требований дельты невыполнимо как записано
|
||
|
||
- Файл: `cmd/healthlog/reindex_report.go:37-38`;
|
||
`openspec/changes/tie-break-equal-completeness/specs/reindex/spec.md:30-46`
|
||
- Severity: major
|
||
- Confidence: high
|
||
- Оракул: чтение — отчёт печатает `Partial, Incomparable, EntitiesHeld,
|
||
EntitiesDiverging`, но не `PointsHeld`, хотя дельта reindex SHALL требует
|
||
«называть число точек, удержанных правилом полноты против пришедшей
|
||
доставки», и число уже лежит в `Report` (`internal/replay/replay.go:214`).
|
||
Второе: дельта требует «число записей „свёртка вне порядка журнала“ прогон
|
||
SHALL печатать рядом с отпечатком» — эти записи существуют только в логе
|
||
живого сервиса, нигде не хранятся, а пересборке та же дельта проверку прямо
|
||
запрещает (ingest:55). Требование структурно невыполнимо.
|
||
- Последствие: SHALL дельты нарушен кодом (счётчик — единственный способ
|
||
увидеть, что правило удержания стало слишком строгим, сходимость отпечатка
|
||
его не проверяет по построению); невыполнимое SHALL, влитое в спеку, станет
|
||
вечно красным пунктом для следующего читателя.
|
||
- Предложение: `PointsHeld` — добавить в строку «слияние:» отчёта (инлайн,
|
||
одна строка). Невыполнимую величину — переписать в дельте на то, что
|
||
измеримо (например: «число `failed` печатает прогон; записи „вне порядка“
|
||
наблюдаются в логе сервиса и в отчёт не входят»). Правка текста дельты —
|
||
решение не оркестратора.
|
||
- Действие: развилка (код — инлайн, но формулировка требования дельты требует
|
||
решения владельца: что именно обязана печатать посылка равенства)
|
||
- Найдено проходами: specs (F2, F5), reimpl (R1)
|
||
|
||
### 2. Сценарий дельты «отложенная занятостью доставка не разводит приём и пересборку» не проверен ни одним оракулом
|
||
|
||
- Файл: `openspec/changes/tie-break-equal-completeness/specs/reindex/spec.md:56-62`;
|
||
тесты: `internal/replay/worker_internal_test.go` (барьер — на подменённой
|
||
свёртке), `internal/replay/order_test.go` (сходимость — без отложенной)
|
||
- Severity: major
|
||
- Confidence: high
|
||
- Оракул: отсутствие теста подтверждено чтением обоих файлов (specs, проверено
|
||
и триажем): композиция «настоящий `Deferred` × сходимость отпечатков»
|
||
не проверяется ничем; `task verify:busy` (зелёный) проверяет только «занятость
|
||
оставляет доставку в очереди», без сверки отпечатков.
|
||
- Последствие: равенство «пересборка = приём» — ровно то свойство, ради
|
||
которого изменение существует (инвариант «Хранилище — свёртка по журналу»,
|
||
critical), — в самом опасном режиме держится на рассуждении, а прецедент
|
||
2026-08-01 показал, что такие рассуждения расходятся с кодом молча.
|
||
- Предложение — варианты specs: (а) busy-тест в `internal/replay` под флагом
|
||
`-healthlog.busy`: журнал с равнополными столкновениями, свёртка под
|
||
удерживаемой блокировкой, сверка отпечатков живого пути и пересборки;
|
||
(б) сузить сценарий дельты и записать ограничение в границы. Рекомендация:
|
||
(а) — цена одного теста против цены молчаливого расхождения витрины.
|
||
- Действие: развилка
|
||
- Найдено проходом: specs (F3)
|
||
|
||
### 3. design.md утверждает «цена не измеряется» и «тот же индекс» — оба утверждения неверны, замер триажа прилагается
|
||
|
||
- Файл: `openspec/changes/tie-break-equal-completeness/design.md:157-159`;
|
||
`internal/store/delivery.go:256-269`
|
||
- Severity: minor (после разрешения конфликта O1/R3)
|
||
- Confidence: high
|
||
- Оракул: замер триажа `tmp/oracle/parsedafter_test.go` на временной базе:
|
||
полный проход проверок по чистой задолженности — N=2000: 0.26 с; N=8000:
|
||
3.12 с; N=20000: 19.8 с (форма квадратичная, экстраполяция N=110 000 → ~10
|
||
мин, N=330 000 → ~1.5 ч). Установившийся режим — 0.0077 мс на вызов.
|
||
`EXPLAIN QUERY PLAN`: `SEARCH delivery USING INDEX delivery_received_at` —
|
||
**не** тот же индекс, что у `PendingDeliveries` (частичный `delivery_pending`
|
||
требует `parse_status='pending'` и к предикату `IN ('parsed','partial')`
|
||
неприменим).
|
||
- Последствие: конфликт O1 (ops) против R3 (reimpl) разрешён: оба замера верны,
|
||
неверна интерпретация O1 «часами не может разобрать бэклог из-за проверок» —
|
||
часы даёт сама свёртка (~0.4 с/доставку по verify:archive: при N=20 000 это
|
||
~2 ч свёртки против 20 с проверок, <2% накладных). Реалистичный потолок
|
||
задолженности — архив квартала ~27 000 доставок (~300 строк/сутки) → ~35 с
|
||
проверок. Оптимизация кода не нужна (правка была бы незаказанной); неверные
|
||
утверждения в design.md — нужно поправить, иначе следующий читатель примет
|
||
решение по ложному числу.
|
||
- Предложение: заменить в design.md «цена не измеряется» на измеренные числа
|
||
(квадратична по задолженности, ~1% от цены свёртки, 7.7 мкс в установившемся
|
||
режиме) и «по тому же индексу» на `delivery_received_at`. Код не трогать.
|
||
- Действие: инлайн
|
||
- Найдено проходами: ops (O1), adversary (A3), reimpl (R3) — одна причина
|
||
|
||
### 4. 71 773 координаты живой витрины остаются на старом исходе до ручного `reindex`, и напоминания об этом нет нигде, кроме отчёта ревью
|
||
|
||
- Файл: процедура выкладки; `design.md` Risks («Этим изменением не выполняется»)
|
||
- Severity: major
|
||
- Confidence: high
|
||
- Оракул: корпусный замер оркестратора — исход меняется на 75 494 координатах
|
||
(95% — `basal_energy_burned/raw`); `verify:archive` после изменения зелёный с
|
||
новым отпечатком `03aace91…`, значит рабочая витрина под старым отпечатком с
|
||
новым правилом **не сойдётся**, пока её не пересоберут.
|
||
- Последствие: до пересборки живая витрина расходится с тем, что даёт
|
||
`import + replay` — «состояние, которое даёт пересборка» в этом проекте
|
||
объявлено внешним поведением (`docs/review.md`). Подмена файла базы —
|
||
необратимое действие человека (`CLAUDE.md`, спрашивается всегда), оркестратор
|
||
выполнить его не вправе.
|
||
- Предложение — готовый вопрос владельцу: «После мерджа витрина расходится с
|
||
новым правилом на ~75 тыс. координат (95% — basal_energy_burned/raw).
|
||
(а) выполнить `healthlog reindex` с остановкой сервиса и подменой базы сразу
|
||
после выкладки; (б) отложить до планового окна, приняв расхождение витрины на
|
||
этот срок; (в) не пересобирать — витрина сойдётся только по метрикам, которые
|
||
переприедут доставками.» Рекомендация: (а).
|
||
- Действие: развилка
|
||
- Найдено проходами: ops (O4), architecture (замечание про подмену базы)
|
||
|
||
---
|
||
|
||
## Гипотезы без доказательства
|
||
|
||
- **Откат бинаря молча возвращает старое правило слияния** (ops O3, было major
|
||
confidence medium → остаётся major-гипотезой без оракула). Миграций нет,
|
||
откат стартует без слова, свёртка идёт по коммутативному правилу, и витрина
|
||
расходится с пересборкой новым бинарём. Путь не построен и не воспроизведён;
|
||
частично это плата, уже принятая проектом за «версия базы ниже бинаря — не
|
||
отказ». Если владелец сочтёт класс важным — это та же развилка, что решалась
|
||
в задаче про откат релиза.
|
||
- **`failed`-доставка «в витрину ничего не записала» — посылка предиката
|
||
`ParsedAfter` держится раскладкой кода, а не проверкой** (adversary). Если
|
||
когда-нибудь `failed` начнёт писать частично, страж окна ослепнет молча.
|
||
Оракула нет — гипотеза, потолок major.
|
||
- **`hasIncomparablePair` не видит отмены и способен продлить свёртку за
|
||
дедлайн под транзакцией записи** (reimpl R2, замер честный: ≈51 с при ~7000
|
||
кандидатов на координате). Понижено до гипотезы о масштабе: на живом корпусе
|
||
кандидатов на координате единицы, путь к ~7000 версий одной координаты не
|
||
построен; `pickBest` при том же масштабе сам стоит 103 с — чинить пришлось бы
|
||
оба, то есть это вопрос предела на кандидатов, а не пропущенного `ctx.Err()`.
|
||
- **Порядок свёртки под конкурентным приёмом не проверяется ни одним тестом с
|
||
параллельными писателями** (gate-3): `-race` зелёный на последовательных
|
||
сценариях. Дефекта не построено; остаточное окно конкурентного приёма
|
||
осознанно вынесено в `journal-order-on-ingest` (ops O5 туда же присоединился).
|
||
- **Ветки ошибок нового кода не покрыты тестами** (gate-1, gate-2): отказ
|
||
`ParsedAfter` → `warnOutOfOrder`/`ERROR`, отмена контекста в
|
||
`resolve`/`pickBest` — 9 строк, названных оркестратором. Поведение веток
|
||
прямое (залогировать и продолжить / вернуть ошибку), дефекта в них не
|
||
предъявлено. Закроются заодно с правкой блокирующего пункта 2, если
|
||
оркестратор добавит тест на `Deferred`-выход.
|
||
- **Имя метрики из чужого тела уезжает в первичный ключ витрины без предела
|
||
длины** (adversary A4). Подтверждено конструкцией (512 КиБ в ключе), но
|
||
дефект предсуществующий, изменением не внесён — этому изменению не
|
||
предъявляется. Конвенция уже записана (`docs/conventions/storage.md`: «любое
|
||
значение из чужого JSON, попадающее в ключ… имеет названный предел длины») —
|
||
значит это не promote, а невыполненное правило: заводится задачей вне этого
|
||
изменения.
|
||
|
||
## Promote candidates
|
||
|
||
- **Ошибки уровня `store` не проходят через единую границу обрезки** (adversary):
|
||
сегодня утечку значений в текст ошибки сдерживает дисциплина каждого
|
||
call-site. Кандидат в `docs/conventions/errors.md`: текст ошибки хранения
|
||
несёт род и координату, но не значение; проверяется тем же разобранным
|
||
буфером, что и логи.
|
||
- **Агрегат счётчиков (`Outcome.Add`, `MergeStats`) суммируется руками —
|
||
забытая строка молча занулит счётчик** (architecture AR2): кандидат в
|
||
конвенцию тестирования — рефлексивный тест «каждое числовое поле участвует в
|
||
Add», или правило «новое поле счётчика приходит вместе со строкой в Add и
|
||
тестом». Не находка против этого кода: все нынешние поля просуммированы.
|
||
- **Проверка «в логе нет значения точки» для новых поверхностей вывода**
|
||
(по мотивам A1/PointsHeldAt): координата в лог идёт через `clipMetric`, но
|
||
правило «новая поверхность вывода получает тест на утечку» записано только
|
||
для отчёта пересборки комментарием. Кандидат в `docs/conventions/testing.md`.
|
||
|
||
## Границы покрытия
|
||
|
||
**Запускалось:** профиль `deep`, линейно: `gate` (зелёный), `specs`, `code`,
|
||
`adversary`, `ops`, `reimpl` (по триггеру «новое правило слияния»),
|
||
`architecture`; до кода — профиль `design` (`specs`, `rubric`, `architecture`).
|
||
Оркестратор дополнительно прогнал `task verify:archive` (до изменения красный —
|
||
унаследованный `step_count`, после — зелёный, отпечаток `03aace91…`,
|
||
воспроизведён дважды) и `task verify:busy` (зелёный) — то, что по
|
||
`docs/review.md` числится «перестали проверять сознательно», в этой задаче
|
||
прогнано, потому что она триггерная (правило слияния).
|
||
|
||
**Не запускалось:** `rubric` на коде — намеренно, только в `design` (его
|
||
свойства легли приёмочными критериями задачи); других проходов профиля не
|
||
пропущено.
|
||
|
||
**Что запущенные проходы не могли проверить в принципе (из charter'ов):**
|
||
`specs` судит код против дельт, а не поведение под нагрузкой; `code` — только
|
||
записанные конвенции; `adversary` назвал свойство без пути — постоянную
|
||
остановку очереди построить не удалось (`Deferred` только из
|
||
`ErrBusy`/`Canceled`); `ops` не наблюдал реальную ночную нагрузку и реальный
|
||
рестарт с большой задолженностью (его замеры — синтетика, как и мои); `reimpl`
|
||
переигрывал только правило слияния и порядок, не разбор; `architecture` не
|
||
запускает код; триаж ничего нового не находит по определению — пропуск любого
|
||
прохода был бы и моим пропуском.
|
||
|
||
**Целиком на человеке — два списка, намеренно раздельных.**
|
||
|
||
*Не проверит ни один проход:* реальный профиль нагрузки телефона (объём и
|
||
частота меряются только по факту); поведение HAE за пределами наблюдённого —
|
||
в том числе пришлёт ли он когда-нибудь ту самую «обеднённую точку с
|
||
разошедшимся значением» из блокирующего пункта 1 (сегодня — 0 вхождений на
|
||
корпусе); полнота словаря переводов после обновления iOS; секции, которых
|
||
поток ещё не приносил (`symptoms`, `ecg`, `heartRateNotifications`,
|
||
`cycleTracking`, `medications`); история инцидентов; завязка потребителей на
|
||
текущее поведение витрины; вопрос «нужна ли эта функциональность вообще» —
|
||
решён владельцем 2026-08-04 (тай-брейк — его выбор), но последствия выбора
|
||
наблюдаются только эксплуатацией.
|
||
|
||
*Перестали проверять сознательно:* `verify:archive`/`verify:busy` вне гейта
|
||
(в этой задаче прогнаны — см. выше; следующая задача без триггера их не
|
||
увидит); класс «в Go так не пишут» — не покрыт вовсе после упразднения `idiom`
|
||
(запись 2026-08-02), к этому диффу поимённая сверка со стайлгайдами не
|
||
применялась; класс «чего нет в зрелой реализации такого узла» — вне профиля
|
||
`design`, на коде не проверялся.
|
||
|
||
**Документы проекта:** всё, что нужно триажу, на месте — `CLAUDE.md` с
|
||
инвариантами и severity (веса пунктам присвоены по ним, а не выведены заново),
|
||
`docs/review.md` с разделами «Типовые ложноположительные» (использован: ни одна
|
||
находка под шесть записанных классов не подпала, отсев шёл по общим критериям
|
||
плюс этот раздел) и «Недоступно проверке» (перенесён выше двумя списками),
|
||
`docs/security.md`, `docs/research/apple-health.md` (находка 54 — по ней
|
||
`adversary` строил обеднённые тела). Ни один проход недостающего документа не
|
||
заявил. Единственный документный пробел — не отсутствие, а протухание:
|
||
`docs/database.md:130` и ещё пять мест из блокирующего пункта 3.
|
||
|
||
**Что не влезло в потолок и куда делось:** все понижения названы в «Гипотезах»
|
||
поимённо, молча не выброшено ничего. Отсеяно как вкусовщина, целиком по трём
|
||
критериям (не меняет поведения, не влияет на цену следующего изменения, не
|
||
нарушает записанной конвенции): атрибут `waited_sec` в новом `WARN` (specs F6 —
|
||
дельта ограничивает состав «без значений точек», и это выполнено; секунды
|
||
ожидания значением точки не являются); схлопывание `Worker.player`+`fold` в
|
||
замыкание (architecture); переименования/перестановки из generative-выводов не
|
||
поступали. Замечания `reimpl` «где существующее решение лучше» — не находки, а
|
||
подтверждение решений; перечислены в его сыром выводе и сохранены в истории
|
||
задачи.
|