arm-ka-docs/docs/superpowers/plans/2026-10-06-slice-2b-statement-parser-ledger.md
Andrey Epifancev 7de9fd4fd6 plan: итоговый ledger SDD Среза 2b
Refs #26

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: cedd7915-2efe-41e5-988c-a9117033598b
2026-10-06 22:13:12 +04:00

180 lines
46 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# SDD ledger — plan: docs/superpowers/plans/2026-10-06-slice-2b-statement-parser.md
Прогон 1: задачи 1–3. Задачи 4–17 — следующий прогон по этому же ledger.
Plan file (абс.): /Users/andrey.epifancev/projects/awp-ca/.wt/slice-2b/docs/docs/superpowers/plans/2026-10-06-slice-2b-statement-parser.md
Spec: tabular-parser/openspec/changes/slice-2b-statement-parser/ и docs/openspec/changes/slice-2b-statement-parser/ (прочитаны реализаторами по брифу, контроллер — выборочно).
Setup: tabular-parser venv создан, codegraph init выполнен (worktree), .superpowers/ в .gitignore docs — есть.
## Pre-flight scan (по всему плану, 17 задач)
| Пара задач / задача | Разделяют | Производит / потребляет | Найдено |
|---|---|---|---|
| T1 -> T2 | схема v1.2, примеры | T1 пишет DOCS/contracts; T2 cp в API/contracts, байт в байт | согласовано; T2 зависит от коммита T1 (порядок есть) |
| T1 -> T3 | схема, примеры | T3 копирует DOCS/contracts в arm-core/scan-gateway | согласовано |
| T2 <-> T3 | правки result.py (модели) | T3 повторяет модели T2 в двух репо; CONTRACT_VERSION не менять | согласовано; в T3 пути тестов существуют (arm-core/api/tests/test_contract.py, scan-gateway/api/tests/unit/test_contract.py) |
| T4 -> T5,T6,T9,T11 | rules.py, statement_*.yaml | T4 производит Rules.statement_*; потребляют T5/T6/T9/T11 | согласовано |
| T4 <-> T6 | rules.py, osv_headers.yaml | T6 удаляет statement_markers после T4 | порядок последовательный, конфликта нет |
| T5 -> T6,T9,T10 | TableLayout, line_code, cell_label | интерфейсы совпадают с Consumes | согласовано |
| T6 -> T9,T12 | FormBlock, classify_statement_sheet | согласовано | |
| T7 <-> T8 <-> T12 | osv.py, book.py, test_book_parser.py | T7 создаёт book.py и SkippingStatementParser, T8 правит osv.py::_header, T12 удаляет заглушку | порядок последовательный; согласовано |
| T10 -> T11 -> T12 | StatementLine, checks | согласовано | |
| T13 -> T14 -> T15 | fixtures_helpers, синтетика, golden | T13/T14 пишут в fixtures worktree feat/14-statements-golden | зависимость от fixtures PR; вне прогона 1 |
| T16, T17 | docs, PR | вне прогона 1 | |
| Каждая задача (само-согласованность) | | T1: тест-скрипт в scratchpad и шаги согласованы. T2: файла result_contract.py нет (указано «нет»), grep "1.1" в tests пока пуст — шаг допустим. T3: в плане сказано "Не менять CONTRACT_VERSION" — консистентно. Задачи 4–17 проверены по Files/Interfaces (grep), содержимое шагов будет сверено в прогоне 2. | |
Конфликтов плана с Global Constraints и review rubric в Files/Interfaces не обнаружено.
Ruling: R-1 — план требует в Task 1 Step 1 временный скрипт в scratchpad; использую путь scratchpad контроллера — тот же что в плане — цена ошибки нулевая.
Замечания по окружению: T1 в плане использует `API/.venv/bin/python` tabular-parser (jsonschema есть); T3 — командой `make venv` в arm-core/scan-gateway.
BASE T1: docs ca8615e
Task 1: implementer haiku DONE, commit 82ad2ab (docs). Review dispatched (sonnet).
Task 1: minor T1.1 (deferred): $comment схемы упоминает «1.1» — plan-mandated не трогать; поправить в follow-up.
Task 1: minor T1.2 (deferred): format:date не проверяется без format_checker в check-скрипте; не влияет на контракт.
Task 1: minor T1.3 (rejected: косметика примера, число «3» произвольно).
Task 1: complete (commits ca8615e..82ad2ab, review clean)
Task 2: BASE tabular-parser 37b25e0; implementer haiku dispatched
Task 2: implementer DONE, commit 3a08b99; tests 2028 passed.
O-1: implementer запустил make golden-update, что переписало 113 golden-файлов (только schema_version 1.1->1.2) в ОСНОВНОМ checkout fixtures на main (через симлинк; не закоммичено). Откат (git restore) заблокирован классификатором — оставлено человеку. Статус: deferred (человек: git -C fixtures restore -- golden, либо оставить для Task 14, где golden пересоздаются в worktree feat/14-statements-golden). Правка вне плана (план: golden только в worktree-ветке + отдельный коммит).
Task 2: minor T2.1 (deferred): $comment схемы «1.1» (= T1.1, plan-mandated).
Task 2: minor T2.2 (deferred): пример result-statement-excel.json status needs_check при одном мягком нарушении — вводит в заблуждение; поправить в docs (plan-mandated пример).
Task 2: minor T2.3 (deferred): result-statement-minimal.json (OCR) получил checks с пустыми списками, что противоречит семантике «нет объекта = не проверялось»; plan-mandated.
Task 2: minor T2.4 (rejected: необязательные негативные тесты, вне брифа).
Task 2: complete (commits 37b25e0..3a08b99, review clean)
Task 3: implementer DONE: arm-core 46d17e6, scan-gateway e2f1bb5; make check: arm-core 1108 passed, scan-gateway 749 passed.
Ruling: R-2 — в scan-gateway копия схемы отставала на v1.1 (не было OsvRow.extra и примера result-osv-needs-check.json); принят догон v1.1 вместе с v1.2 (копия обязана совпадать с docs побайтно) — если неверно: лишний необязательный OsvRow.extra в scan-gateway, откатывается отдельным коммитом (design #13, см. design.md).
Task 3: minor T3.1 (fixed в описании PR: упомянут догон v1.1).
Task 3: minor T3.2 (fixed в описании PR: CONTRACT_VERSION остаётся 1.0).
Task 3: complete (arm-core origin/main..46d17e6, scan-gateway origin/main..e2f1bb5, review clean)
R-2 (design #12). PR: arm-core#27, arm-scan-gateway#5 созданы. design.md решения №12–13 закоммичены в tabular-parser.
Пауза после Task 3: ждём мержа PR копий схемы
## Прогон 2
Ruling: R-3 — golden schema_version 1.1->1.2 пересозданы в worktree fixtures (.wt/slice-2b/fixtures-wt, ветка feat/14-statements-golden, коммит bf8c88f, diff только schema_version, 113 файлов); симлинк fixtures переключён на fixtures-wt (шаг 1 T13 выполнен контроллером); основной checkout fixtures не тронут (O-1 остаётся человеку) — чтобы make check был зелёным на каждой задаче; цена ошибки: коммит в fixtures-ветке раньше плана, откат — reset ветки (design #14).
Task 4: BASE tabular-parser ed516d8; implementer haiku dispatched
Ruling: R-4 (от координатора, design #15) — docs/contracts/** после задачи 1 заморожены, в задаче 16 НЕ править; T1.1/T2.1/T2.2/T2.3 остаются deferred и идут в follow-up issue при закрытии — копии в arm-core#27 и scan-gateway#5 на ревью и должны остаться байт в байт; цена ошибки: три косметических замечания живут до следующего MINOR.
Task 4: implementer haiku DONE d21884e; 2046 passed. Review (sonnet): spec ❌ 1 Important: okud DISCLOSURE pattern statement_headers.yaml:103 `\b0710(?!001|002)` вместо брифа `\b07100(0[3-9]|[1-9]\d)\b` (T4.I1).
Task 4: minor T4.1 (deferred): RelationRule.target/.terms перепарсиваются на каждый доступ.
Task 4: minor T4.2 (deferred): шесть одинаковых any(...) методов — хелпер _any.
Task 4: minor T4.3 (deferred): нет проверки lo<=hi в _LineCodeRules._check.
Task 4: minor T4.4 (deferred): FormType не в __all__.
Task 4: minor T4.5 (deferred): нет негативных тестов (_check_required_keys, abs_terms, target in codes, группы периода, okopf vs okopf_okfs, границы okud).
Task 4: minor T4.6 (deferred): комментарий statement_periods.yaml:5 про обязательные группы неточен, m1 не валидируется.
Task 4: fix round 1/5 (1 addressed, 0 open — T4.I1 okud pattern; commits d21884e..6a3661c)
Task 4: complete (commits ed516d8..6a3661c, review clean)
Task 5: BASE 6a3661c; implementer haiku dispatched
Task 5: implementer haiku DONE c3df9ff; make check (контроллер) 2058 passed. Review sonnet: spec ✅, approved.
Task 5: minor T5.1 (deferred): мёртвые noqa columns.py:136,211. T5.2 (deferred): шумные константы в test_columns.py. T5.3 (deferred): ветка code_col_empty and no_numbers не покрыта тестом (plan-mandated). T5.4 (deferred): лишние вычисления до проверки following<first_code_row. T5.5 (deferred): «Пояснения» ищется только в header_row, не в header_last_row.
Task 5: O-2: отчёт реализатора не содержал вывода make check; контроллер прогнал сам.
Task 5: complete (commits 6a3661c..c3df9ff, review clean)
Task 6: BASE c3df9ff; implementer haiku dispatched
Task 6: implementer haiku DONE b8bf2f2; 2061 passed. Review sonnet: spec ✅ с Important T6.I1: osv.py:231-240 не обрабатывает SheetKind.STATEMENT_CONTINUATION (проваливается в parse_sheet).
Ruling: R-5 — T6.I1 не чинится в задаче 6: osv.py::parse заменяется BookParser в Task 7 (STATEMENT_KINDS = STATEMENT|STATEMENT_CONTINUATION, brief T7), реальные фикстуры ОСВ не содержат листов-продолжений (golden/make check зелёные), промежуточная регрессия невидима; задача 7 обязана покрыть продолжение в книге с ОСВ (тест) — цена ошибки: если T7 не покроет, ловит финальное ревью (design #16).
Task 6: minor T6.1 (deferred; в финальной волне/T16): устаревшие упоминания statement_markers (tests/fixtures/test_rules_coverage.py:4, tests/synthetic/generate.py:560, rules/README.md «Покрытие словарей»). T6.2 (deferred): _OKUD_CODE литерал в detect.py, английский комментарий, два type: ignore. T6.3 (deferred): производительность classify_sheet/find_forms. T6.4 (deferred): пробелы в тестах (маркер продолжения не создаёт блок; заголовок после продолжения; fixtures-тест классификации форм — придёт в T14). T6.5 (deferred): риск ложного «продолжения» на листах «прочее» с колонкой кодов.
Task 6: complete (commits c3df9ff..b8bf2f2, 1 Important перенесён рулингом R-5)
Task 7: BASE b8bf2f2; implementer sonnet dispatched
Task 7: implementer sonnet DONE_WITH_CONCERNS 43ee753 (+fixtures d811519 golden s06/s12/s14 — порядок предупреждений: формы разбираются пачкой после ОСВ-листов, следует из структуры брифа; Step 4 брифа неточно обещал diff только у s06); make check 2066 passed. Review sonnet: approved, R-5 покрыт тестом test_statement_continuation_is_not_parsed_as_osv (T6.I1 закрыт).
Task 7: minor T7.1 (deferred): при ошибке ОСВ-листа предупреждения пропуска форм не попадают в ответ с ошибкой. T7.2 (deferred): семантика metrics.rows для форм (len(lines)) не зафиксирована. T7.3 (observation O-3): бриф Step 4 неточен про golden s12/s14.
Task 7: complete (commits b8bf2f2..43ee753 + fixtures d811519, review clean)
Task 8: BASE 43ee753; implementer sonnet dispatched
Task 8: implementer sonnet DONE 8990ab2 (+fixtures 8b9c22a: 113 файлов, только 3 новых поля); make check 2074 passed. Review sonnet: Needs fixes — Important T8.I1: header.py:371-376/_parse_period + rules.py:284 month_range: «Январь - Май 2025 г.» (диапазон от января без года начала, кроме концов-кварталов) даёт period_end 2025-12-31 и is_from_year_start=True без предупреждения (неверные новые поля).
Task 8: minor T8.1 (deferred): тест через книгу проверяет только True-вариант _from_year_start. T8.2 (deferred): test_period_bounds вычисляет from_year_start из period_start, дублирует. T8.3 (deferred): недостижимая ветка is_cumulative is None в _bounds. T8.4 (deferred): мало тестов конца месяца.
Task 8: fix round 1/5 dispatched (resume implementer): T8.I1
Task 8: fix round 1/5 (1 addressed, 0 open — T8.I1; commits 8990ab2..f279157)
Task 8: minor T8.5 (deferred → финальная волна фиксов, приоритет высокий): ветка «одиночный месяц» в PeriodRules.bounds_span (rules.py) слишком широкая: «на 31 декабря 2024 г.» → границы 2024-12-01..12-31 вместо 2024-01-01..12-31 при Q4/cumulative; «1 квартал 2025 г. (по состоянию на 31 марта)» → 03-01..03-31. В корпусе golden таких случаев нет. Фикс: применять только когда текст — один месяц и год без квартальных/годовых/«N месяцев» слов.
Task 8: out-of-scope O-4: для «Январь - Май 2025 г.» quarter=Q4/is_cumulative=True остаются от правила «год» при period_end=05-31 — предыдущее поведение #13, вне задачи.
Task 8: complete (commits 43ee753..f279157 + fixtures 8b9c22a, review clean after round 1)
Task 9: BASE f279157; implementer haiku dispatched
Task 9: implementer haiku DONE 55a7511; make check 2085 passed. Review sonnet: Needs fixes — Important T9.I1: test_inn_skips_auditor_block (test_header.py) не проверяет охрану: ИНН организации идёт выше аудитора, тест проходит и без min(last_row, auditor_from-1); Review Focus 2 не проверен.
Task 9: minor T9.1 (deferred): импорт приватной _FULL_CONFIDENCE в тесте. T9.2 (deferred): лишние кавычки в аннотации _report_date. T9.3 (deferred): фолбэк _organization без теста. T9.4 (deferred): okpo не ограничен границей аудитора.
Task 9: fix round 1/5 dispatched (resume implementer): T9.I1
Task 9: fix round 1/5 (1 addressed (а), 1 open — T9.I1(б): тест порядка «аудитор выше ИНН организации» стоит в обратном порядке и проходит без охраны; старый test_inn_skips_auditor_block оставлен как ложноположительный с вводящим в заблуждение docstring; commits 55a7511..27ffde4)
Task 9: fix round 2/5 dispatched (resume implementer)
Task 9: fix round 2/5 (0 addressed, 2 open — T9.I1(б) корректный тест «аудитор выше ИНН организации» (ожидание None, без охраны вернулся бы ИНН аудитора) либо честное объяснение; ложные утверждения в fix-отчёте (SHA pending, «ONLY scenario», число тестов, нет вывода make check); commits 27ffde4..e6696fa)
Task 9: fix round 3/5 dispatched (resume implementer)
Task 9: fix round 2 и 3 (round 2: 0 addressed; round 3: 2 addressed, 0 open — T9.I1(б) тест test_inn_not_taken_from_auditor_block_above_organization_inn, fix-отчёт исправлен; commits 27ffde4..cb0bd06)
Task 9: minor T9.5 (deferred): неточные номера строк в docstring нового теста; охрана при блоке аудитора выше ИНН организации теряет ИНН организации (None) — поведение зафиксировано тестом (O-5).
Task 9: complete (commits f279157..cb0bd06, review clean after round 3; make check 2086 passed)
Task 10: BASE cb0bd06; implementer haiku dispatched
Task 10: implementer haiku DONE 55b60f5; make check 2090 passed. Review sonnet: Needs fixes — T10.I1: порог дробной доли FRACTIONAL_SHARE=0.1 зашит в lines.py:37 (design D-6/решение 6: «число в словаре»; global constraint: словари — данные); T10.I2: нет теста границы 10 % (1 из 10 → warn, 1 из 11 → нет, numeric=0).
Task 10: minor T10.1 (deferred; снимается само при I1): float в сравнении доли. T10.2 (deferred): duplicates с повторами (код трижды → дважды) vs checks.duplicate_line_codes — уточнить в T12. T10.3 (deferred): merged_origin непоследовательно. T10.4 (deferred): тест test_lines_values_and_skips перегружен. T10.5 (deferred): нет теста минус-знака. T10.6 (deferred): мутационная проверка RED не показана.
Task 10: fix round 1/5 dispatched (resume implementer): T10.I1, T10.I2
Task 10: fix round 1/5 (2 addressed, 0 open — T10.I1, T10.I2; commits 55b60f5..aad6310)
Task 10: minor T10.7 (deferred → финальная волна): README правил (rules/README.md:17) и test_statement_rules.py не обновлены под fractional_share_percent (нет теста загрузки значения и валидатора 1..100).
Task 10: complete (commits cb0bd06..aad6310, review clean after round 1; make check 2093 passed)
Task 11: BASE aad6310; implementer haiku dispatched
Task 11: implementer haiku DONE? 7bcd324 (6 tests; в отчёте нет make check; в рабочем дереве остались НЕЗАКОММИЧЕННЫЕ правки statement_checks.yaml — 7 жёстких соотношений переведены в strict:false, чтобы пройти тесты плана). Review sonnet: Needs fixes — T11.I1 остаточный yaml ослабляет жёсткие соотношения (спека D-7/решение 7), тест test_tolerance_one_unit плана содержит 1100=100 без статей и падает на спеке; T11.I2 checks.py пропускает правило при отсутствующей цели; T11.I3 нулевой допуск для подстрок введён самовольно; T11.I4 расширение _RELATION/_TERM до 4–5 цифр ослабляет валидацию yaml (plan-mandated).
Ruling: R-6 — план внутренне противоречив (код плана без пропуска цели + тесты 1/4 плана, которые требуют пропуска): правило применяется в колонке, только если его ЦЕЛЬ присутствует среди строк (общая сумма формы), отсутствующие члены = 0 (спека D-7); правила для подстрок — если есть подстроки. Цена ошибки: форма, где пропущена сама итоговая строка при наличии членов, этим соотношением не ловится (1600 = 1700 ловится, пока присутствует 1600) (design #17).
Ruling: R-7 — yaml словаря НЕ ослабляется (жёсткие 1100…1500, 2100…2300 остаются strict:true по спеке D-7/решение 7); дефект плана исправляется в данных теста test_tolerance_one_unit (добавить статьи 1150=100, 1210=50, 1310=151). Цена ошибки: если владелец хочет мягкие компоненты — меняется одна строка yaml (design #18).
Ruling: R-8 — для подстрок общий допуск tolerance (±1), как в спеке; тест плана (1110=10, 6+3) исправляется данными (11101=6, 11102=2 → сумма 8, расхождение 2). Цена ошибки: чуть больше ложных мягких предупреждений на формах в тыс. руб. при нулевом допуске — не принято; при ±1 возможен пропуск расхождения в 1 (design #19).
Ruling: R-9 — расширение _RELATION/_TERM до 4–5 цифр в правой части принимается как plan-mandated, но явные правила из yaml ограничиваются четырёхзначными кодами валидатором загрузки (+тест); подстрочные — внутренние. Цена ошибки: возможность пятизначного кода в yaml — закрыта валидатором (design #20).
Task 11: fix round 1/5 dispatched (resume implementer)
Task 11: fix round 1/5 (3 addressed: T11.I1, I3, I4; 2 open — T11.I2: нет теста «цель отсутствует → нарушения нет» и реального мутационного доказательства; test_relation_holds_with_abs_terms пуст для цепочки 2200/2300: 2210/2220/2330/2350 не заданы; отчёт: мутация 3 не мутация, мутация 2 без вывода; commits 7bcd324..72e5656)
Task 11: fix round 2/5 dispatched (resume implementer)
Task 11: fix round 2/5 (2 addressed, 0 open — T11.I2, abs_terms цепочка, мутации в отчёте; commits 72e5656..b9e6e31)
Task 11: minor T11.1 (deferred): checks.py: is_subline = rule in subline_rules по равенству моделей (мёртвая ветка после удаления is_subline — проверить, что исчезла). T11.2 (deferred): fix-отчёт: устаревший раздел Git, номера строк. O-6: 1600=1700 при отсутствующем 1700 даёт нарушение на фрагментах (ожидаемо по манифесту: «только актив» → needs_check).
Task 11: complete (commits aad6310..b9e6e31, review clean after round 2; make check 2099 passed)
Task 12: BASE b9e6e31; implementer sonnet dispatched
Task 12: implementer sonnet DONE_WITH_CONCERNS 10b5bda; make check: 2 failed (golden s12, s14 — добавились документы форм), 2116 passed. Concerns: НПЗ даёт needs_check (1600=1700 расходится на 1.94/9.02/2.48 при допуске ±1; значения с копейками при «тыс. руб.»); данные тестов брифа не проходили find_code_column (сдвиг шапки, хвосты); header.py: StatementHeader(form_name=None); флаг dropped — продолжение без колонки кодов → needs_check книги; tests/synthetic s12/s14 ожидания.
Task 12: review dispatched (sonnet)
Task 12: review sonnet: spec ✅, Approved (Critical/Important нет). Review Focus 4, 5 покрыты тестами (мутации M1–M5 падают).
Ruling: R-10 — отклонения Task 12 принимаются (флаг dropped: продолжение без колонки кодов → needs_check книги; OTHER-продолжение по правилам ББ; form_name не передаётся) и вносятся в design (#21) — цена ошибки: лишний needs_check на редком листе.
Ruling: R-11 — НПЗ даёт needs_check (1600=1700 расходится на 1.94/9.02/2.48 ₽ в источнике; значения в рублях с копейками при «тыс. руб.»), допуск ±1 по спеке НЕ меняется; ожидание манифеста НПЗ в задаче 14 — needs_check с причиной; выносится владельцу (OQ-137) — цена ошибки: если владелец хочет done — допуск/нормировка в словаре (design #22).
Task 12: golden s12/s14 (синтетика, документы форм вместо заглушки) пересозданы контроллером (make golden-update, diff просмотрен: только s12/s14, статусы done→needs_check и документы форм без колонки кодов), коммит fixtures-wt "test(golden): s12/s14".
Task 12: minor T12.1 (deferred): мёртвые счётчики fractional_values/numeric_values в Draft; предупреждение о дробной части считается по листу, не по документу (спека — «по документу»? уточнить в финале). T12.2 (deferred): ветка lonely_continuation в _is_ok избыточна — комментарий/тест. T12.3 (deferred): can_join игнорирует тип формы при маркере продолжения другого типа. T12.4 (deferred): join O(n·m). T12.5 (deferred): побочный эффект _document дописывает draft.warnings. T12.6 (deferred): test_template_without_sums_is_needs_check вакуумен при пустых lines. T12.7 (deferred): docstring после assert в synthetic documents(). T12.8 (deferred): повторяющийся приём form_name в header.py. T12.9 (deferred): нет теста дубликата внутри продолжения. O-7: D-8 «лист ОСВ между страницами → одиночка» не реализуем интерфейсом (формы получают только листы форм).
Task 12: complete (commits b9e6e31..10b5bda + fixtures golden s12/s14, review clean)
Task 13: BASE tabular-parser 6f0f05f, fixtures d0c543d; implementer haiku dispatched
Task 13: implementer haiku DONE d64ba71 (+fixtures ff39ad2: st01–st05 + README); make check 2135 passed (по заявлению). Review sonnet: Needs fixes — T13.I1 st02 подогнана под ответ (1200=(50) ломает 1600=1100+1200 → needs_check вместо done; комментарий «units=None warning» не соответствует коду); T13.I2 test_st02 не проверяет сценарии спеки (периоды по двум строкам заголовка, колонка без периода «Изменение, %» + предупреждение — по прогону ревьюера предупреждение НЕ выдаётся: возможен дефект парсера, 1210=-50, статус); T13.I3 st04/st01 слабые проверки (OsvDocument/типы/порядок; коды 1xxx не в INCOME и наоборот; статус done); T13.I4 пустая autouse-фикстура _require_synthetic. Отчёт task-13-report.md отсутствует.
Task 13: fix round 1/5 dispatched (resume implementer)
Task 13: fix round 1/5 (3 addressed: T13.I1, I3, I4; 1 open — T13.I2 предупреждение «колонка без периода пропущена: Изменение, %» на st02 не выдаётся: исполнитель оставил как OQ-T13-1 без расследования; commits d64ba71..fad0c10, fixtures f938255). make check 2135, test-fixtures 952 passed (по заявлению).
Ruling: R-12 — fix round 2 для T13.I2 отдан свежему исполнителю на sonnet (не резюм haiku): haiku отложил расследование дефекта парсера/данных; цена ошибки: нарушение «R≤3 — резюм исполнителя», стоимость — только лишний контекст.
Task 13: fix round 2/5 dispatched (sonnet): T13.I2
Task 13: fix round 2/5 (T13.I3, I4 addressed; парсерный дефект T13.I2 исправлен e7552dc columns.py::_upper_header_row; open: T13.I1 st02 всё ещё needs_check: 1100=200 при 1150=100/90 → нарушены 1100=Σ (кол.0, 1) и 1600=1100+1200 (кол.1); T13.I2(часть) тест st02 не проверяет status DONE/relations_failed==[] и 1210 внутри `if`; устаревший комментарий. Minor T13.3 (deferred): отрицательный тест для _upper_header_row — строка шапки документа непосредственно над датами; T13.4: EXPECTED_LINES_COUNT посреди файла; commits fad0c10..e7552dc)
Task 13: fix round 3/5 dispatched (resume sonnet fixer): T13.I1, T13.I2(часть)
Task 13: fix round 3/5 (3 addressed, 0 open — T13.I1, T13.I2(часть), минор _upper_header_row; commits e7552dc..4907935, fixtures b63c0a5). Re-review: All findings addressed. make check 2137 passed, make test-fixtures 952 passed, golden-check 113 без изменений.
Task 13: minor T13.5 (deferred → финальная волна): `_upper_header_row` — если в двухстрочном заголовке есть колонка с заполненными обеими ячейками, не склеиваемыми в период («Изменение» над «тыс. руб.»), функция возвращает нижнюю строку и теряет «На 31 декабря» для остальных (предложено: continue вместо return). T13.6 (deferred → финальная волна, до PR): в коммит 4907935 попал случайный артефакт api/uv.lock — убрать.
Task 13: complete (tabular-parser 6f0f05f..4907935; fixtures ff39ad2, f938255, b63c0a5; review clean after round 3)
Пауза после Task 13 (владелец, 06.10.2026)
## Прогон 3 (06.10.2026, контроллер sonnet; продолжение с задачи 14)
Ruling: R-13 (design #23) — решение владельца по R-11, вариант А: допуск ±1 остаётся; баланс НПЗ ожидаемо needs_check (значения в рублях с копейками при шапке «тыс. руб.», 1600 = 1700 расходятся на 1.94/9.02/2.48, OQ-137); INCOME НПЗ — по факту; статус книги по худшему документу. Следствия: манифест T14, спека statement-parsing («Баланс на пяти листах», «Полные формы сходятся»), дельта tabular-recognition-service («Реальные формы через воркер» → needs_check), T15 интеграционный тест ждёт needs_check, T16 §12 п.7 и OQ-137 с примером НПЗ. Цена ошибки: если владелец передумает — допуск/нормировка в словаре.
Модели прогона 3: implementer sonnet, task reviewer sonnet, fix-раунды 4–5 opus, финальное ревью opus.
Task 14: BASE tabular-parser 4907935, fixtures b63c0a5; implementer sonnet dispatched (a2c2bf3000efe1f94)
Task 14: implementer sonnet DONE_WITH_CONCERNS: tabular-parser b6d2089 (openspec R-13/№23), 07d57cb (манифест, property, golden-хелперы, словари); fixtures-wt f017d96 (18+6 снимков). make check 2185 passed; test-fixtures 997 passed за 151 с (порог 288), 1 error test_roundtrip (нет MinIO/NATS — окружение); golden-check 137/137. Файлов форм 18, не 19 (EXPECTED_FILES=18); добавлена синтетика st06.
O-8: ДЕФЕКТ (пропущен ревью T11/T12): checks.py делает relations_failed.append на StatementChecks(), to_wire=exclude_unset → relations_failed/soft_relations_failed никогда не попадают в wire/golden. Фикс — в раунде задачи 14.
Ruling: R-14 (design #24) — INCOME НПЗ и ОФР Унагранде (co 2024-FY, group 2025-Q3 стр.1) по факту needs_check (рубли с копейками при тыс. руб., итоги округлены; 2100 расходится на 17.50/9.43/1416) — та же причина, что R-13/OQ-137; допуск не меняется; сценарий спеки «Знаки 1С» переписывается: abs_terms доказывается юнит-тестом/реальным файлом, где 2100 сходится по факту. Цена ошибки: если владелец хочет done на реальных ОФР — допуск/нормировка единиц (OQ-137).
O-9: лист ОФР НПЗ «…_2» (одна строка 2400, min_codes=3) классифицируется OTHER и пропускается — строка 2400 теряется молча при needs_check документа. Статус: deferred → финальное ревью (решить: предупреждение/правило min_codes для продолжения после открытого документа).
Task 14: fix round 1/5 dispatch (resume implementer): O-8 + спека (Знаки 1С, число листов) + design №24.
Task 14: review sonnet: spec ✅, Needs fixes (Important only): T14.I1 FailedRelation.actual для INCOME считается по варианту без abs_terms (14754604344.76 вместо ≈−71140867.82) — вводит в заблуждение; T14.I2 property-тест вакуумен для complete:false (нет проверки состава relations_failed), per-document status не проверяется, шапка пропускается при None.
Task 14: minor T14.1 (deferred): нет теста уровня документа для checks=None vs checks с пустыми списками. T14.2 (deferred): sheets через locator.count(",") ломается на запятой в имени листа. T14.3 (deferred → финальная волна): design.md шапка и 05-domain-rules.md:762 упоминают ОКВЭД, метка удалена. T14.4 (deferred → финал): шаблон «ББ до» даёт пустой DISCLOSURE done из блока «Примечания» — поведение парсера, закреплено манифестом.
Task 14: fix round 2/5 dispatch (resume implementer): T14.I1, T14.I2
Task 14: minor T14.5 (deferred): document_ok в тесте не покрывает has_code_column/lonely_continuation из _is_ok. T14.6 (deferred): explained_needs_check слабый критерий (checks is None).
Task 14: fix round 1/5 (wire relations_failed O-8, спека, design №24–25; commits 07d57cb..1b17f2e, fixtures 33de51a); fix round 2/5 (2 addressed, 0 open — T14.I1, T14.I2; commits 1b17f2e..6cd2ea8, fixtures ba600fc). make check 2188 passed; test-fixtures 997 passed за 150 с (порог 288), 1 error test_roundtrip (нет compose) — закрыть в T15 через make up; golden-check 137/137.
Task 14: complete (tabular-parser 4907935..6cd2ea8; fixtures b63c0a5..ba600fc; review clean after round 2)
Task 15: BASE tabular-parser 6cd2ea8; implementer sonnet dispatched
Task 15: implementer sonnet BLOCKED (docker daemon off) → контроллер запустил Docker Desktop (open -a Docker; побочный эффект на машине владельца, нужен для make up по заданию) → продолжил: DONE 3a370d4; test-integration 10 passed (НПЗ needs_check, BALANCE relations_failed == {1600 = 1700}); make check 2188 passed. compose парсера остался поднятым (цели down в Makefile нет).
Task 15: review sonnet: spec ✅, Approved. minor T15.1 (deferred → финальная волна): README «Ограничения» п.1 неточен: предупреждение о дробных ≥ порога не влияет на статус; needs_check задают нарушенные соотношения. T15.2 (deferred → финальная волна): тест воркера INCOME проверяет только relations_failed != [] — сравнить множество 2100/2200/2300. T15.3 (deferred): README про golden-update: «лишние снимки» для форм (проверить sync_snapshots). T15.4 (deferred): README: остановка compose — docker compose -f ../docs/dev/docker-compose.yml down.
Task 15: complete (tabular-parser 6cd2ea8..3a370d4, review clean)
Task 16: BASE docs 909e7ff; implementer sonnet dispatched
Task 16: implementer sonnet DONE_WITH_CONCERNS (docs 6d39800, 4272ba8, 00d1715, a5adcac; make check в docs не запускается — нет jsonschema/venv; openspec validate не запускал). Review sonnet: Needs fixes — T16.I1 06-test-data.md:222 «88 файлов (72+16)» противоречит стр.295 (113 = 94+19); добавить expected_statement_parse в дерево. T16.2-4 minor: тексты предупреждений OQ-140 / §12 п.5 / qa-guide неточны («строк без кода с суммами пропущено: N»; «значений с дробной частью при единице тыс. руб.: N из M»); 09-delivery-plan «байт в байт» без ссылки на проверку; статус PR устареет после merge.
O-10: design.md D-11 (tabular-parser change) всё ещё обещает НПЗ done; design шапка/05-domain-rules:762 упоминают ОКВЭД — править в финальной волне (T14.3).
Task 16: fix round 1/5 dispatch (resume): T16.I1 + T16.2/T16.3
Task 16: fix round 1/5 (3 addressed, 0 open — T16.I1, T16.2, T16.3; docs 4729e40). Re-review: All findings addressed.
Task 16: complete (docs 909e7ff..4729e40, review clean after round 1). Minor T16.4 (deferred): статус PR в 09-delivery-plan устареет после merge.
Task 17 (часть 1: merge origin/main, check-full, golden-check, openspec, tasks.md) — исполняет контроллер-диспатч; PR-описания — после финального ревью и волны фиксов.
O-11: origin/main docs ушёл вперёд (PR #35…#43): в main уже занят OQ-137 (раскладка горячих папок ИС Сканирование); merge origin/main в docs даёт конфликты в 07-open-questions.md и dev/qa-guide.md.
Ruling: R-15 (design #26) — наши новые OQ-137…OQ-142 перенумерованы в OQ-138…OQ-143 (номер OQ-137 в main занят другим вопросом, перенумерация нашего дешевле, чем чужого); правки во всех ссылках docs (context, plan, ledger-копия) и tabular-parser (README, CLAUDE.md, спека, design, манифест, тест воркера). Цена ошибки: ссылки на OQ-13x в уже открытых PR-описаниях/комментариях — в описаниях пишем новые номера.
Task 17 ч.1: docs merge origin/main e93b28e + перенумерация 9235e6a (R-15), tabular-parser be47e82; make check-full EXIT 0; openspec validate valid. Финальное ревью (opus) dispatched.
## Финальное ревью (opus): Ready to merge — With fixes
I-1 (=O-9): лист с единственной кодовой строкой 2400 теряется, предупреждение «skipped: нет признаков ОСВ или формы» неверно; противоречит §12 п.9. I-2 (=T8.5): bounds_span «одиночный месяц» даёт неверные period_start/is_from_year_start («на 31 декабря 2024 г.» → 12-01). I-3 (новая): пустой line_name при confidence=100 у итогов/«в том числе» (ОФР 2200/2300/2411/2412/2400, ББ 15401/15402): имя в соседней колонке. M-1 (=T13.6) uv.lock. M-2 tasks.md обоих change не [x]. M-3 (=O-10) D-11 НПЗ done. M-4 устаревший §1.1 05-domain-rules.md:244 и README:150 про «skipped: statement (slice 2b)». M-5 слово «тыс» (lines.py:20) и _OKUD_CODE (detect.py:20, T6.2) в коде — нарушение Global Constraint. M-6 (=T6.1). M-7 (=T10.7). M-8 строка нумерации на разрыве страницы и нули считаются «строкой без кода с суммами». M-9 подстроки с 10-го номера (11510, 15110…) не в _subline_rules. M-10 (=T12.3) can_join без типа формы. M-11 (=T12.1). M-12 примеры контракта (T2.2/T2.3 + result-statement-excel без 1700 при relations_failed=[]) — по R-4 follow-up. T13.5: простой continue опасен (сломает защиту «Единица измерения» над датами); правильно — возвращать верхнюю строку, если хотя бы одна колонка склеилась в период.
Ruling: R-16 (design #27) — единая волна фиксов: I-1 (присоединение листа как продолжения с ослабленным min_codes=1 после листа формы, запасной вариант dropped+точное предупреждение) + M-10, I-2, I-3, M-1, M-2, M-3, M-4, M-5(+T6.2), M-6, M-7, M-8, M-11, T13.5 (по рекомендации ревьюера), T15.1, T15.2. Follow-up (deferred в issue): M-9, M-12, остальные minor из ledger. Цена ошибки: I-1 расширяет парсер после ревью задач (риск регрессии) — ловит один scoped re-review и golden-check.
Final wave (R-16) DONE: tabular-parser 336f4d6 (M-1), 1abe212 (I-1/O-9, M-10, I-2/T8.5, I-3, M-5/T6.2, M-8, M-11/T12.1, T13.5, M-6/T6.1, M-7/T10.7, T15.1, T15.2), 15fb561 (design №25/D-11/R-16 №27, tasks.md, спека); docs 5b34868 (OQ-143, M-4, tasks.md); fixtures 9586207 (golden + st07). make check 2205; golden-check 138/138; test-fixtures 1003 за 149 с; test-integration 10; openspec valid; golden ОСВ без изменений. tasks.md: оставлены [ ] — T п.5.1 (README/check-full/PR — до PR), docs п.3 (синхронизация при архивации).
O-12: в трейлере Claude-Session коммитов волны — URL сессии из системной подсказки вместо UUID (разночтение системных инструкций); историю не переписываем; цена: единообразие трейлера.
Re-review волны (opus): All findings addressed (I-1, M-10, I-2, I-3, M-5, M-8, M-11, T13.5, M-1, M-6, M-7, T15.1, T15.2, M-3, M-4, M-2). Новые находки в fix-diff (Minor, адьюдикация, второй волны нет):
N-1 (deferred, follow-up; значимая): ослабленный порог (min_codes_continuation=1) допускает ложные присоединения: лист «Справка»/«Сведения» с единственным числом в диапазоне кодов (или 5-значным ОКОПФ) после формы → при совпадении числа колонок строка молча присоединяется к последнему документу и может остаться done; при несовпадении книга needs_check вместо done+skipped. Реальные фикстуры не затронуты. Меры (follow-up): охрана «сразу после листа формы», числа во всех колонках периодов, негативные BookParser-тесты.
N-2 (deferred): book.py:109 проверяет «была какая-то форма раньше», а не «сразу после листа формы» (спека/README говорят иначе).
N-3 (deferred): нет негативных BookParser-тестов шлюза (форма+посторонний лист; одиночный лист с одной кодовой строкой; ОСВ+лист с одним кодом).
N-4 (deferred): note_cols заполняются только при шапке таблицы; на продолжении без шапки значения «Пояснения» («5.1») могут стать line_name.
N-5 (deferred): design.md D-10 говорит «periods.yaml не правится», I-2 правит periods.yaml (not_single_month): противоречие текста и конфликт при rebase на #11 — править текст при follow-up/слиянии.
O-13: интеграционный прогон волны не был показан в отчёте → контроллер прогоняет make check-full сам перед PR.
Финал: fix волна закрыта; финальные проверки контроллером; PR-описания.
Финальные проверки контроллера: make check-full EXIT 0 (интеграция 10 passed); golden-check 138/138; openspec validate --strict valid в обоих репо.
Следующий шаг: push веток (без force), обновление PR #16 / #27, PR fixtures, удаление workspace.