External-review шаг 3a: accept with 7 confirmed findings led by silent chapter-loss on malformed epub, recommend spine reconciliation
This commit is contained in:
parent
8096224a2f
commit
6700a0f2a6
1 changed files with 13 additions and 0 deletions
|
|
@ -401,6 +401,19 @@ keep-alive (Ф1–2), инъекция глоссария (`selective`), пор
|
|||
|
||||
**Границы/техдолг (не блокеры):** чанк <500 симв. молча выключает excision-гейт — **документированная граница §7b** (после фикса #2 случается только на реально-крошечной главе/хвосте); overlap-инъекция и ruby→глоссарий-лок отложены (§3, ждут msgs-поверхности памяти v2 — строим один раз); epub v1 не сохраняет инлайн-разметку; zip-bomb hardening — future. Форму `ruby_readings` согласовать с памятью v2 при шаге 4 (контракт: base→dst через reading, first_chapter→since_ch, occurrences=confidence). Тесты: чанкер (сегментация/паковка/детерминизм/аббревиатуры/quote-depth), ingest (txt/epub/spine-порядок/entity/ruby/битый-epub/dense-numbering/media-types), ruby-persist (идемпотентность+сходимость), e2e мульти-глава epub→чанки→мок-перевод→resume $0.
|
||||
|
||||
> **Внешнее ревью оркестратора Шага 3a (05.07): ПРИНЯТО, 0 живых блокеров, 7 подтверждённых находок (1 отсеяна).** Независимый воркфлоу — **агенты гоняли реальный код** (пробы в пакете), не утверждали. Money/детерминизм я подтвердил чтением сам. Тема: **тихая потеря главы/контента** — ровно тот класс, ради которого продукт есть. Ранг по важности:
|
||||
> 1. **[major] Тихая потеря главы на dangling spine idref** (ingest.go:168-201). idref-опечатка, орфанящая главу, молча скипается через `continue`; ошибки нет, пока читается хоть одна другая глава (`read>0`). **Противоречит СОБСТВЕННОМУ контракту** (PROGRESS:400 перечисляет dangling idref среди fail-loud; :402 инвариант «тихая потеря главы, против инварианта»). Прогон: manifest=[c1,c2,c3], spine=[c1,ghost,c3] → главы=[c1,c3], c2 потеряна, **и `since_ch` всего хвоста книги сдвинут** (ruby c3 штампуется chapter=2). Асимметрия: пропавший zip-файл фатален, пропавший manifest-id молчит. Фикс: собрать неразрешённые idref → loud-ошибка (как для zip-entry). **Топ-приоритет.**
|
||||
> 2. **[major] Тихая потеря главы на `application/xml`+`.xml`** (ingest.go:212-226). Тот же класс: контент-док, мислейбленный `application/xml`/`text/xml` С расширением `.xml`, промахивается мимо и type-switch, и extension-фолбэка (знает только .xhtml/.html/.htm) → молча скип + dense-renumber сдвигает `since_ch`. (Селфревью-фикс #3 закрыл ПУСТОЙ media-type, но не generic+`.xml`.) Фикс: при generic XML MIME распознавать `.xml` как контент. **Чинить вместе с #1.** → Системный фикс обоих: **spine-reconciliation** — сверять число контент-spine-items с реально прочитанными главами, расхождение = fail-loud.
|
||||
> 3. **[major] Size-зависимая порча invalid-UTF-8 → U+FFFD** (chunker.go:220). Oversize-путь round-trip `[]rune(paragraph)` заменяет невалидный байт на U+FFFD, а нормальный путь (короткий абзац, `strings.Join`) сохраняет сырые байты. Тот же source-байт цел в коротком абзаце, испорчен в длинном — нарушение losslessness + size-зависимая несогласованность; течёт в `{{text}}` и `request_hash`. Триггер: mostly-UTF-8 файл со стрей/обрезанными байтами (txt без charset-guard). Прогон: `abc\xe9def` короткий → байты целы, oversize → `abc\xef\xbf\xbddef`. Фикс: нормализовать invalid-UTF-8 ОДИН раз в `NormalizeSource` (fail-loud или документированная замена, покрыто `chunkerVersion`).
|
||||
> **Minor:**
|
||||
> 4. **[minor] ASCII/эллипсис-граница игнорирует quote-depth** (chunker.go:263-273). Depth-подсистема читается только в CJK-ветке; ASCII-ветка (`.!?…`) депт не проверяет → терминатор внутри трекнутой кавычки over-splits (запретное направление). Прогон: `「Stop. Now.」` → 2 сегмента (CJK-твин → 1). Проявляется в oversize-абзаце (режет диалог через границу чанка). Фикс: гейтить ASCII-границу на `depthHere==0` тоже (straight-quote англ. кейс не регрессит — проверено).
|
||||
> 5. **[minor] `<br>` внутри `<ruby>`** (ingest.go:326-327) не гардится `rubyDepth==0` (в отличие от block-тегов) → `\n` между base-глифами, обходит whitespace-collapse фикс #4; base и body расходятся. Whitespace-only, детерминизм цел. Фикс: гард `rubyDepth==0`.
|
||||
> 6. **[minor] ruby phantom-строки** (ruby.go, нет delete). Пара, УБРАННАЯ правкой источника, навсегда остаётся фантомом (upsert-only, нет delete-by-book). Латентно (память v2 не приземлена, capture-only, ноль текущего impact), но памяти v2 навесит name-lock на имя, которого в книге нет. **Фикс совмещается с шагом 4:** `DELETE FROM ruby_readings WHERE book_id=?` перед bulk-upsert (полная замена агрегата — тогда «сходится к правде» верно и для удалений). Связано с ruby-контрактом в `architecture/06`.
|
||||
> 7. **[minor] нет fuzz/property-теста tiling** (chunker_test.go). Единственный losslessness-тест — 6 ручных valid-UTF-8 инпутов; `Join(split(x))==x` над рандомом (вкл. invalid-UTF-8, вложенные/несбалансир. кавычки) поймал бы #3. Фикс: Go fuzz / testing/quick property + chunk-level losslessness (Σ не-пробел чанков == Σ не-пробел источника).
|
||||
> **Отсеяна: 1** (oversize-хвост <500 симв. — механизм подтверждён, но это документированная граница §7b, не баг; верификатор REFUTED).
|
||||
>
|
||||
> **Приоритет фикса:** #1+#2 (тихая потеря главы, системно через spine-reconciliation) → #3 (losslessness UTF-8) → #7 (fuzz-тест, поймал бы #3) → #4 (quote-depth ASCII) → #5/#6 (мелочь, #6 — с шагом 4). Ничего не горит на боевом (все триггеры — битый/мислейбленный epub или invalid-UTF-8), но #1/#2 — именно тот тихий-потери класс, где мы обязаны быть fail-loud.
|
||||
|
||||
## Полигон
|
||||
(секция параллельной сессии — записи добавлять сюда)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue