39 KiB
Отчёт: пак «ФОРМАТЫ И ЧЕСТНЫЙ СЛОВАРЬ»
Сессия textmachine-main-fe, 05.09. Промт docs/CHAPTER_STRUCTURE_SESSION_PROMPT.md (выдан dba8a0b,
поправлен по находкам сессии: 24f02bb · 23b00a3 · 5a502e7 · cd55329). Денег потрачено $0, платных
вызовов ноль: весь пак — путь tmctl manifest и тесты на фейковом провайдере.
1. ЧИСЛА
Батарея
| команда | EXIT | пакетов | FAIL | линтер | скипы | |
|---|---|---|---|---|---|---|
| до правок | make battery |
0 | 19 | 0 | 0 issues | 3 |
| после | make battery |
0 | 19 | 0 | 0 issues | 3 |
Скипы поимённо и в обоих прогонах те же: TestMinerFullBookParity (корпусный, снимается battery-stand),
TestHelperEventsRun, TestHelperKillLoop (хелперы подпроцессов). Новых скипов не появилось — это
проверялось отдельно, потому что скип читается как зелень.
Каталог мутаций
201 → 205 записей. Шесть прогнаны исполнением на КОПИИ дерева (~/tm-mut-0509, GOFLAGS=-buildvcs=false),
6 RED, 0 неожиданных исходов:
| запись | покрасневший тест |
|---|---|
DF-competition-order-loses-a-chapter |
TestTXTHeaderRightAfterAFormFeedIsNotLost |
EPUB-preamble-joins-chapter-one |
TestEPUBUncoveredBeforeFirstTargetJoinsChapterOne |
EPUB-service-pages-are-exactly-two-roles |
TestEPUB3LandmarksExcludeTocAndCover, TestEPUB2GuideExcludesTocAndCover |
PP-structure-provenance (пере-нацелена) |
TestTheCutSaysWhetherItWasReadOrGuessed + два подтеста |
TITLE-raw-follows-the-kept-index |
TestTitleRawSurvivesAChapterThatTakesNoNumber |
EPUB-collapsed-targets-downgrade-the-provenance |
TestEPUBDuplicateNavTargetsCollapse |
⚠ Полный прогон всех 205 записей НЕ делался — см. §6.
Замеры шага 0
| # | замер | число |
|---|---|---|
| 1 | \f в стенд-книгах |
0 во всех шести файлах |
| 2 | главы-огрызки от print-TOC в 蛊真人 | 0 (мин. глава 1804 знака, медиана 3289) |
| 3 | сброс нумерации по томам | есть: 2283 шапки → 945 уникальных номеров, кратность до 6 |
| 4 | шапки 第N节 |
ровно 2283; 章/節/回/話 — по нулю |
| 5 | 話 в 蛊真人 |
0 вхождений вообще |
| 6 | преамбула до первой шапки | 3130 знаков |
| 7 | declared во всём стенде до пака |
0 (семь detected, один none) |
Замер 1 значит, что конкуренция §2.4 физически не могла сдвинуть разрез боевой книги. Замер 5 — что сведение чанкера к пяти юнитам не тронуло ни одного её чанка.
Счета формата
form feeds ignored, documents attached, documents excluded, toc unresolved, targets collapsed живут в chunk.Document,
уезжают в WARN (events.go, ingestSource) и НЕ на провод — потребителя у них сегодня нет.
2. ГЕЙТ ЛЕНДИНГА — ВЕТКА (а), ВОСЕМЬ ИЗ ВОСЬМИ
Гейт сверяет id глав и номера (ратифицировано находкой 4). Пины сняты до правок и после, тем же
прибором, конфигами сессии в ~/tm-pins-0509.
| исходник | sha256[:16] | глав | structure | разрез |
|---|---|---|---|---|
ch1 |
eda401ef10edbf40 |
1 | none | байт-в-байт |
ch1-2 (= coldrun-b) |
eb87729061be6d39 |
2 | detected | байт-в-байт |
ch4-5 |
33dc2b5b7e491435 |
2 | detected | байт-в-байт |
ch1-5 |
8755afd3e6aab298 |
5 | detected | байт-в-байт |
s11-16 |
5c22ec0ddaf19bb0 |
6 | detected | байт-в-байт |
ch1-10 |
0b5f9b0266d8c32a |
10 | detected | байт-в-байт |
ch26-42 |
1ebcc9efb0fa5006 |
17 | detected | байт-в-байт |
slice25 |
78f4cb7d990f5e1a |
25 | detected | байт-в-байт |
Двинулось ровно заказанное (пример ch1-10): key 1e62a68d93f73534… → 01a00e3669302bc1…;
unit-id главы 1 c3aa4cbbb53de134:d4fb75e2:0 → c3aa4cbbb53de134:1b30b1dd:0 — префикс id главы
неподвижен, уехал сегмент cutTag. Это и есть §2.2, исполненный буквально.
⚠ Носитель гейта — восемь ИСХОДНИКОВ, а не 31 конфиг, и это не сужение: разрез глав есть функция байтов
исходника, кодировки и данных структуры. Проверено ИСПОЛНЕНИЕМ до правок: тот же исходник под другим
конфигом (другой пайплайн, другой book_id) дал идентичные id и номера глав, разошлись только key и
cutTag.
3. ЧТО ПОСТРОЕНО
internal/lang/structure.go— данные структуры ИСТОЧНИКА: типSourceStructure, загрузчикLoadSourceStructureс лестницей (<root>/<язык>/structure.txt→ CJK-дефолт по скрипту → nil), отпечаток для тега разреза. Загрузчик отдельный от пар-пака и достигает книги БЕЗ него. ⚠ Файлzh/structure.txtНЕ создан намеренно: он дублировал быcjk-section.txtи завёл бы ровно тот второй носитель, который пак закрывает. Механизм при этом работает: новая пара кладёт свой файл, Go не правится.- Живой дрейф закрыт. Было: ингест — пять юнитов из
cjk-section.txt, чанкер — четыре изzh-ru/heading.txt. Стало: одно резолвленное значение на обоих путях.heading.txtоставил толькоtemplate;parseHeadingотвергаетmarker/unitsгромко, называя, куда уехал факт.cjk-section.txtНЕ тронут ни одной строкой. - Компонент
StructureвcutInputsи в payloadmanifestKey, безomitempty. - Конкуренция свидетелей и значение
delimited. Порядок ратифицированный:\f→\n\nна рабочей копии → детекция по копии → откат на ОРИГИНАЛ, если шапки проиграли. - EPUB
nav/NCX (internal/chunk/epubtoc.go): приоритет nav → NCX → spine; сплющивание вложенныхol; схлопывание дублей; цели вне spine — игнор со счётом; nav с нулём разрешимых целей = отсутствует;linear="no"не открывает главу; служебные страницы исключаются поproperties="nav", landmarks (EPUB 3) И OPF<guide>(EPUB 2); непокрытые до первой цели — в главу 1, прочие — в предыдущую. - ⛔ Схлопнутые цели ПОНИЖАЮТ провенанс. Книга, пакующая несколько глав в один документ с якорями,
объявляет больше глав, чем пак отдаёт: он группирует документы целиком и по якорям не режет. Назвать такой
разрез
declaredзначило бы выдать своё, более грубое, за утверждение формата — та же ложь, что говорил spine, в новом месте. Поэтому приtargets collapsed > 0книга идёт какdelimited, со счётом в WARN. Четырёхзначного словаря для этого хватило: достраивать ничего не пришлось. ⚠ Резка xhtml по якорям в пак НЕ входит — отдельный заказ; цена названа: текст цел, гранулярность потеряна. title_rawаддитивно: строка шапки как в источнике (txt) /navLabel(EPUB). Понижение подзаголовка не тронуто.- Бамп
chunkerVersionv6 → v7 и пере-захват голдена — один раз, последним действием.
Ревью-вопрос проекта — закрыт исполнением
«Заработает ли пара, которой в репозитории НЕТ, без правки Go?» — да, и это тест, а не утверждение.
TestANewLanguageCutsFromItsDataFileAlone (internal/chunk) проверяет ОБЕ половины на одном тексте и одном
бинаре: корейская книга без своего файла остаётся одной главой (CJK-дефолт даёт маркер 第, которого в
корейском нет), а с ko/structure.txt, объявляющим 제 и 장, режется на три, отдаёт detected и несёт
title_raw = 제2장 전개. Единственная разница между половинами — файл данных.
Половина на уровне загрузчика — TestALanguageAbsentFromTheRepositoryCutsFromDataAlone (internal/lang),
она же пинует, что отпечаток берётся из ФАЙЛА, а не из дефолта: иначе правка чужой грамматики не пере-резала
бы книгу.
⚠ ГРАНИЦА, КОТОРУЮ ЭТОТ ЖЕ ТЕСТ ВСКРЫЛ, и она честнее ответа «да». Ингест режет только по грамматике
С ЮНИТОМ: detectChapterUnit итерирует UnitOrdered, и язык без юнита («Kapitel 12») сегодня НЕ режется —
хотя ЧАНКЕР такую грамматику уже умеет, и на это есть живой тест TestStripHeadingGenericLatinMarker
(matchHeaderLine юнита не требует). То есть половина не-CJK пути готова, а половина нет, и данные это
выразить могут, а детектор — нет. Не достраивал: §2.2 прямо говорит «римские/словесные читатели НЕ
строятся», объём читателей в паке 1 — ровно существующий. Ревью-вопрос закрыт для языков С юнитом и
открыт для языков без него — это кандидат в строку бэклога, не тихий пробел.
4. ОБЪЯВЛЕНИЯ ПО D39.183
Правки тестов, вызванные ЗАКАЗАННОЙ сменой поведения:
ingest_test.go— кейс"the format drew every boundary"(ГЛАВА A\fГЛАВА B) ждалStructureDeclared, сталdelimited. Единственный переехавший ассерт. Сам тест переименован:TestTXTStructureIsDeclaredOnlyWhenTheFormatDrewEVERYBoundary→TestTXTProvenanceNamesTheWinningPath— прежнее имя после конкуренции ни во что не разрешается (класс строки 299).priceprojection_test.go— кейс"a form feed is the format speaking"→"a form feed is a separator, not a chapter", ожиданиеDeclared→Delimited.ingest_encoding_test.go— счёт глав сохранён (шапки победили), поправлен комментарий и текст ошибки: разрез там больше не по\f.chunker_heading_test.go—zhRuHeadingRule()→zhRuChapterRule(), инвентарь больше не переписан руками, а берётся изDefaultCJKStructure()(это и есть закрытие дрейфа).- Механические правки сигнатур (
IngestEncoded+ структура,SplitChunksWithChapters+keptIdx,denseChapters) вbookbuild_test.go,contractblockers_test.go,chunker_manifest_test.go,cuttag_test.go. - Каталог:
DF-declared-means-every-boundaryцелила в предикат V2-7, который §1 приказал УДАЛИТЬ. Заменена наDF-competition-order-loses-a-chapter— свойство, занявшее его место.PP-structure-provenanceпере-нацелена на новыйstructureOf. Обе прогнаны красными.
Гарантия никуда не «уехала»: свойство «стрей \f среди шапок не делает разрез declared» стало
недостижимым ПО ПОСТРОЕНИЮ (смешанного случая нет), а на его место встало свойство порядка операций, у
которого теперь есть и тест, и запись каталога.
5. НАХОДКИ ДО КОДА (все приняты оркестратором и внесены в промт)
- §2.4 заказывал цикл. Решить «есть ли шапки» нельзя до нейтрализации
\f: шапка сразу за ним лежит на ОДНОЙ строке с прозой предыдущей главы (204 руны, начинается с 蛊) и отвергается двумя предикатами —ingest.goдлина >chapterHeaderMaxRunesи якорь^. Дороже цикла то, что существующий тест этого не ловил: он проверял толькоdoc.Structure, а ярлык при наивном порядке остаётся ВЕРНЫМ. - Премисса «дрейф закрыл pair-14» неверна — дрейф был живой: 章节節回話 против 章节節回.
- Риск красного незаказанного теста
TestChapterUnitJaWebnovelпри сборке дефолта из пар-файла. - Гейт был недостижим по построению: требовал байт-в-байт манифест, а пак сам заказывает сдвиг
cutTag, перечеканивающий все unit-id (manifest.go,manifestUnitID). - Пар-пак в чужой ветке:
langpack_root20 конфигов из 31 указывает в рабочее дерево веткиpolygon. - Стенд отстал от движка: стенд-конфиг даёт манифест ровно для 1 исходника из 8 (
{{genre}}ретирован и живёт в шести промтах polygon;mined_delta/mined_rejectsретированы и стоят в 17 конфигах из 31; поляstm_depth/overlap_tokensисчезли).
Находки о СВОЁМ коде, пойманные собственными тестами
Markerбыл одновременно классом рун и литеральным префиксом — тот же дрейф в новой форме. «Chapter» сортировался в набор букв. Исправлено моделью альтернатив +regexp.QuoteMeta.- Файловый парсер был СТРОЖЕ движка: требовал
units, хотя безъюнитная грамматика — ровно не-CJK случай, ради которого пак и делается. - Группировка не приклеивала преамбулу, а открывала ей отдельную главу.
- Граница главы выводилась «первый или последний элемент группы» — хрупко; сделана явным полем.
Выжившая посадка, записанная с аргументом
Переворот сортировки starts в resolveTOC не покрасил ничего. Причина: starts читается как
МНОЖЕСТВО, группировка идёт по spine, и порядок целей на выход не влияет. Сортировка оставлена (она держит
истинным объявленный порядок поля), но комментарий теперь говорит это прямо, а не утверждает, что цели
«упорядочены по позиции в spine» как о несущем свойстве.
6. ЧТО НЕ ПРОВЕРЕНО И ПОЧЕМУ
- Полный каталог (205 записей) не гонялся. Прогнаны 6 записей, целящих в изменённое поведение. Причина —
цена: 124 записи гоняют
./internal/pipeline/, чей набор идёт ~145 с, то есть полный прогон — часы при загруженном хосте. Механически проверено другое и дешёвое: у всех 205 записей цель ЖИВА (грепfindпо дереву), то есть протухших целей после пака не осталось. - EPUB владельца (Кристофф/en, isekai/ja) не прогонялись через новый путь. §3 выводит их из гейта, а
§2.1 п.3 требует ОРАКУЛА, а не замера; оракул построен кодом (
TestEPUBNavOracleReproducesTheTxtCut). Замер их нового разреза числом — не сделан. - Платная книга платформы не трогалась — чужая зона.
- Сквозного прогона не-CJK нет — промтов пары для en/ja не существует (§5), проверка ограничена уровнем ingest/manifest, $0.
counts.py --lintне запускался — гейт оркестратора, доков с якорями я не писал.- Полная 蛊真人 (2283 главы) через новый путь не прогонялась: у неё нет конфига, а её результат по §2.1 идёт числом в отчёт и гейтом не является.
7. ФИКСТУРА delimited ДЛЯ ПЛАТФОРМЫ (§6)
~/tm-pins-0509/delimited/manifest.json — реальный манифест, снятый движком:
"structure": "delimited", три главы, title_raw: "" у каждой (источник заголовков не называет).
Источник — кириллический txt с двумя \f и без единой шапки: шапки проигрывают, побеждает разрыв страницы.
⚠ Фикстура лежит ВНЕ репозитория. Если она нужна платформенному тесту как файл — это решение оркестратора,
куда её положить: platform/ мне не зона.
8. ДОФИКС ПО ПРИЁМКЕ (06.09)
Две линзы приёмки нашли шесть обязательных и пять сопутствующих. Все проверены мной заново перед починкой и все подтвердились — ни одна не отклонена.
Обязательные
| # | что было | чем закрыто |
|---|---|---|
| M-1 | роль toc/cover, объявленная С ФРАГМЕНТОМ (c2.xhtml#pos), исключала ВЕСЬ документ ⇒ молчаливая потеря прозы |
объявление на ТОЧКЕ внутри документа больше не исключает файл; отказ считается (ServiceRolesInsideDocuments). Тесты TestEPUBServiceRoleWithAFragmentDoesNotDeleteTheDocument + обратный …WholeDocumentServiceRoleStillExcludes |
| M-2 | три счёта из пяти не доходили никуда; комментарий обещал WARN | ОДИН репортёр Document.IngestNotes() — и рефлексионный сторож TestEveryIngestCountReachesTheAlarm, который краснеет на любом новом неподключённом счётчике |
| M-3 | manifestKey не пинован ничем |
TestTheManifestKeyCarriesTheStructureGrammar; проверен ровно мутацией верификатора |
| M-4 | EPUB-половина title_raw не покрыта; метки фикстур вырождены (e/p всем) |
метки стали различимыми и НАЗЫВАЮТ свой источник (NAV …/NCX …); три теста, включая «заголовок берётся у ГРАНИЦЫ, а не у вклеенной впереди страницы» |
| M-5 | unresolved рос и на прекрасно разрешившихся служебных/нелинейных целях ⇒ любой обычный EPUB 2 отчитывался «сломанным оглавлением» |
счётчик считает ровно то, что обещает; TestEPUBOrdinaryBookDoesNotReportABrokenTOC |
| M-6 | mutations.json переформатирован целиком (дифф 5080 строк) |
отступ возвращён к 1; дифф стал 62 строки, правка видна |
Сопутствующие
m-5 — комментарий bookfile/epub.go был заказан §7 поимённо и мной пропущен; переписан. m-6 — снят
моей же правкой M-2. m-7 — «all three values» при четырёх (сказано, где пинуется declared) и шапка
stripHeading про HeadingRule/nil (условие no-op — ПУСТОЙ шаблон). m-10 — счёт nav больше не теряется
при переходе на NCX; TestEPUBDanglingNavCountSurvivesTheFallToNCX. L1 — два резолвера href сведены в
hrefTarget; прежний resolveHref был неверен: раскодировал ДО среза фрагмента, значит литеральный #
(приезжающий как %23) обрезал имя файла.
m-8 — ОБЪЯВЛЕНИЕ ПО D39.183, замеренное
Регэксп ингеста стал допускать пробел между маркером и цифрой (第 1章), прежний не допускал. Это
одностороннее расширение, заказом не покрытое: сделано, чтобы ингест и чанкер читали заголовок ОДИНАКОВО —
matchHeaderLine пробел терпел всегда. Цена замерена:
| файл | старый регэксп | новый | разница |
|---|---|---|---|
| 蛊真人 (полная, 215 675 строк) | 2996 | 2996 | 0 |
| фикстура голдена | 8 | 8 | 0 |
isekai_majutsushi_jp.txt |
4 | 4 | 0 |
enkan_no_hate_ja.txt |
0 | 0 | 0 |
Вырожденный разрез EPUB владельца — ЧИСЛОМ, замер мой
Прогнал все три EPUB через новый путь (ингест, $0; tmctl manifest на них не идёт — промтов en-ru/ja-ru
не существует, §5):
| книга | глав | structure | знаков min / медиана / max | глав < 200 знаков | счета |
|---|---|---|---|---|---|
| Kristoff (en) | 71 | declared | 18 / 29 / 397 878 | 64 | attached 54 · excluded 1 · service-role-inside-doc 1 |
| isekai (ja) | 44 | declared | 72 / 6669 / 8999 | 9 | excluded 1 |
| fifty_shades (en) | 32 | declared | 0 / 32 276 / 45 511 | 3 | excluded 2 |
⛔ Цена Kristoff названа прямо: 64 единицы манифеста из 71 несут не текст книги, а строки её заднего
листинга, и пойдут в оплату как главы; окна банка получат на этой книге гранулярность 6. По словарю ярлык
честен (nav действительно объявил эти цели), и §2.3 называет такой исход ожидаемым для пака 1 — но цена
существует и это вопрос владельца, а не мой.
⚠ И service-role-inside-doc 1 у Kristoff — это ровно случай M-1 на живой книге: там роль toc
объявлена с фрагментом, и до починки этот документ был бы вычеркнут целиком.
title_raw заполнен у 71 из 71, 44 из 44 и 32 из 32 глав — EPUB-половина работает на реальных
книгах, а не только на фикстурах.
9. ВТОРОЙ КРУГ ДОФИКСА — И ОДНА ПОПРАВКА К ДОВОДУ, КОТОРЫЙ ЕГО ЗАКАЗАЛ
Д-1 — ИНВАРИАНТ ПОСТРОЕН, но его область УЖЕ, чем было заявлено
Требование верное и принято: счета — это наблюдаемость, инвариант — гарантия. Построен и проверяется ДО любого платного пути, нарушение — громкая ошибка движка:
каждый читаемый документ spine либо исключён НАМЕРЕННО, либо попадает ровно в одну главу; и глава — это ровно её документы плюс вставленные между ними разделители.
⚠ Но довод, которым он заказан, я обязан поправить, потому что проверил обе половины посадками. Было сказано: «инвариант ловит потерю текста ЛЮБЫМ путём — сегодняшним фрагментом и завтрашним неизвестным». По замеру это не так:
| посадка | что делает | ловит ли инвариант |
|---|---|---|
| A | группировка молча роняет документ | ДА — spine document "OEBPS/c1b.xhtml" is neither excluded nor part of a chapter … book text would be lost silently |
| B | возврат дефекта M-1 (роль с фрагментом исключает файл) | НЕТ — падают только собственные тесты M-1 |
Причина простая: исключение учтено, поэтому сумма сходится. Инвариант ловит текст, ушедший из чтения БЕЗ решения; неверное, но записанное решение он по построению увидеть не может. Это не довод против него — класс, который он закрывает, счетами не ловился вовсе. Но «ловит любым путём» под ним не стоит.
Д-2 — МОЙ ДОФИКС M-1 ОБМЕНЯЛ ПОТЕРЮ НА ШУМ, и на книге владельца это регресс
Принято целиком. До починки документ Kristoff, на который роль toc указывает с фрагментом, исключался
ЦЕЛИКОМ — и там это случайно оказалось верно: файл и есть чистое оглавление. После починки он прикреплён
как текст книги (service-role-inside-doc 1 при excluded 1).
⛔ Цена прямым текстом: листинг оглавления уедет модели, будет оплачен и покажется читателю внутри главы.
Относительно состояния ДО дофикса на ЭТОЙ книге стало хуже; относительно общего случая — лучше, потому что
раньше терялась проза, а по D39.205 потеря критична, а шум нет.
Узкий ремонт (текст до якоря — книга, от якоря — служебное) НЕ делался, и это осознанный отказ: он и есть
резка xhtml по якорям, которую пак выводит за границы и под которой лежат четыре пина байт-паритета
extractXHTML. Изобретать её в конце пака — та самая сделка, от которой пак предостерегает. Кандидат в пак 2.
Д-3 — ТРЕВОГА ПОСТРОЕНА, НО ПОЛЬЗОВАТЕЛЮ БЕТЫ НЕ ВИДНА
IngestNotes() идёт в r.Log.Warn, то есть в лог ДВИЖКА. Платформа читает events.jsonl, не stderr.
⇒ «тревога построена» не значит «тревога видна человеку»: для пользователя беты её сегодня нет. Провод
не строился — это шов и чужая зона.
Д-4 — ЦЕНА СХЛОПЫВАНИЯ, названная сознательно
parseNavDoc СПЛЮЩИВАЕТ nav: каждая <a href> любой глубины — граница (§2.3). Схлопнутые цели понижают
книгу до delimited (диспозиция 6). Вместе это значит: любой EPUB, где внутри документа главы есть якоря
на разделы — частая форма хорошо собранной книги, — уходит целиком в delimited, то есть в продажу по
знакам, а не по главам.
На трёх EPUB владельца collapsed = 0, поэтому не наблюдалось. Иерархия, по которой можно было бы отличить
«глава» от «раздел внутри главы», в nav ЕСТЬ и отбрасывается сплющиванием сознательно — значит будущий пак
может её использовать, не ломая словарь.
Мелкое — исправлено, а не оговорено
chapterTitleRaw сканировал главу и на delimited-разрезе: единственная шапкообразная строка в прозе (одно
попадание, пол ≥2 не пройден) становилась title_raw. Теперь заголовок извлекается только когда шапки
победили — на delimited границы провёл разрыв страницы, и честный ответ "", а не уверенный неверный.
10. ПЕРЕ-ЗАМЕР ТРЁХ EPUB ВЛАДЕЛЬЦА ПОСЛЕ ВСЕХ ДОФИКСОВ
По норме, купленной этой же сменой: экземпляр, которым дефект предъявлен, обязан быть пере-мерен ПОСЛЕ починки. Замер «до» доказывает, что дефект был, и ничего не говорит о том, что стало. Ниже — «после».
| книга | глав | structure | ИНВАРИАНТ | attached | excluded | roles-inside-doc | collapsed | toc-unresolved | рун в главах | рун исключено | title_raw |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Kristoff (en) | 71 | declared | СОШЁЛСЯ | 54 | 1 | 1 | 0 | 0 | 1 626 362 | 0 | 71/71 |
| isekai (ja) | 44 | declared | СОШЁЛСЯ | 0 | 1 | 0 | 0 | 0 | 239 209 | 1659 | 44/44 |
| fifty_shades (en) | 32 | declared | СОШЁЛСЯ | 0 | 2 | 0 | 0 | 0 | 879 053 | 976 | 32/32 |
Инвариант проверяется ВНУТРИ ингеста и возвращает громкую ошибку — успешное чтение и ЕСТЬ утверждение, что он сошёлся. Статистика глав (min/медиана/max, число коротких) совпала с замером «до» по всем трём книгам: правки дофикса разрез не двигали.
Именованный перечень исключений — и поправка к моему же отчёту
Перечень вместо числа сразу окупился: он показал, что excluded 1 у Kristoff — это НЕ документ оглавления.
Kristoff: исключён titlepage.xhtml роль=cover рун=0
isekai: исключён EPUB/nav.xhtml роль=nav рун=1659
fifty_shades: исключён …_epub_cvi_r1.htm роль=cover рун=0
исключён …_epub_toc_r1.htm роль=toc рун=976
⛔ В разделе 8 я связал у Kristoff service-role-inside-doc 1 и excluded 1 так, будто это одна сделка.
Это неверно, и перечень это вскрыл: исключён пустой титульный лист (0 рун, потери нет), а документ с
ролью toc на фрагменте — index_split_124.html — НЕ исключён и лежит внутри главы. Число «исключено: 1»
позволяло прочитать это неправильно; имя и размер — нет.
Цена Д-2 — теперь ЗАМЕРЕНА, а не предположена
ДОКУМЕНТ С guide-РОЛЬЮ toc НА ФРАГМЕНТЕ: index_split_124.html
рун = 2187
первые 120 знаков: "Table of Contents\n\n\n\nBOOK ONE\n\n\n\nBOOK TWO\n\n\n\nBOOK THREE\n\n\n\nBOOK FOUR…"
⇒ 2187 рун листинга оглавления уедут модели, будут оплачены и покажутся читателю внутри главы книги Kristoff. Это цена дофикса M-1 на этой книге, и она названа числом. До дофикса этих 2187 рун не было — но не было и гарантии, что на следующей книге в том же месте не окажется глава.
11. ФИНАЛЬНЫЙ ПРОГОН — И ФОРМА, В КОТОРОЙ ОН СДЕЛАН
⚠ make battery одной командой НЕ прошла: система дважды убила её по нехватке памяти (хост держит
несколько сессий, своп занят на 3.3 ГБ; первый раз убита на тестах, второй — на линтере). Прогон сделан ПО
СТАДИЯМ, и отчитываюсь именно этими командами, а не «battery зелёная»:
go build ./... && go vet ./... && go vet -tags live ./...
go build -o bin/tmvet ./cmd/tmvet && go vet -vettool=bin/tmvet ./... && go vet -tags live -vettool=bin/tmvet ./...
GOGC=50 golangci-lint run --timeout=20m --concurrency=2 ./... → 0 issues
go test <16 лёгких пакетов> -race -count=1 -timeout=20m → ok 16
go test ./internal/store -race -count=1 → ok 29.5s
go test ./internal/archguard -race -count=1 → ok 52.2s
go test ./internal/pipeline -race -count=1 → ok 282.7s
go test ./... -count=1 -v → EXIT 0, ok 19, FAIL 0
Покрытие то же, что у make battery: те же цели, тот же -race, тот же сбор скипов. Разница только в том,
что стадии не складывают пик памяти. Скипов 3, поимённо те же, что и в базовой линии:
TestMinerFullBookParity · TestHelperEventsRun · TestHelperKillLoop. Новых нет.
Регресс, пойманный ПЕРЕ-ЗАМЕРОМ — той самой нормой
Сужение title_raw до «только когда шапки победили» оказалось слишком широким, и я это поймал не
рассуждением, а пере-снятием пинов: у односоставного исходника ch1 заголовок исчез (заполнено 0/1).
Причина: одна глава с одной шапкой не проходит пол ≥2, свидетель у неё delimited, и правило выбрасывало
её собственный настоящий заголовок.
Правило разделено по половинам, которые тянут в разные стороны:
| разрез | где ищется шапка | почему |
|---|---|---|
шапки победили (detected) |
вся глава | замороженное правило преамбулы прячет шапку главы 1 в её середине |
| любой другой | только ПЕРВАЯ строка | шапкообразная строка в прозе — одиночное попадание, не граница; но односоставная книга свой настоящий заголовок сохраняет |
Пин — TestTitleRawIsTakenWhereTheCutAllowsIt, три случая. После правки пины сошлись с базой полностью:
разрез идентичен и title_raw идентичен на всех восьми исходниках.
⚠ Это второй раз за смену, когда правку ловил пере-замер, а не тест. Первый — Д-2 (не пере-мерил книгу владельца после починки). Норма работает ровно потому, что она про ЭКЗЕМПЛЯР, а не про мнение.