Приёмка шага 5: сплошная сверка выгрузки конструктора с эталонной выгрузкой

Дата: 12.08.2026. Эталон — reference/etalon-punc-avgust-2024.xlsx («Пример выгрузки готового отчета.xlsx» заказчика). Все числа получены запуском python3 verify_punc_full.py; сырой протокол — evidence/verify-punc-full.txt, машинный реестр — evidence/punc-registry.csv (разделитель ;, UTF-8).

**Итог одной строкой: 2368 проверок, совпало 2347, расхождений 24. Ошибок портирования среди них нет: 21 расхождение вызвано отсутствием данных за сентябрь 2024 в наборе 00102, 3 — вторым комплектом листов эталона, правило появления которого из эталонов не выводится. Код после сверки не правился.**

Реестр расхождений одним файлом (CSV, открывается Excel): punc-registry.csv. Спецификация расчёта: spec-punc.html. Приёмка предыдущего шага: punc-acceptance-step4.html.

1. Что и как сверялось

Сверка идёт не «на глаз», а по четырём уровням для каждой ячейки:

УровеньЧто сравнивается
значениечисло или текст ячейки; числа — с двоичным допуском abs 1e-9 / rel 1e-12 (это допуск на представление double, а не на «похоже»: 12896242.430418974 против ...97 — тот же double, 4.605 против 9.629 — расхождение)
формулатекст формулы (лист «Сравнение» держится на формулах =B6, =SUM(C5:C10), =F5-C5, …)
числовой форматnumber_format каждой ячейки (#,##0.000, 0.00%, денежный, @)
структураобъединённые диапазоны листа, состав и порядок листов книги

Сверялись обе выгрузки: собранная в процессе (punc_template.render) **и файл, реально отданный сервисом по HTTP** (GET /api/punc/export?contract_id=20&year=2024&month=8 → HTTP 200, 13 536 байт, evidence/step5-live-aug.xlsx, заголовки — evidence/step5-live-aug.headers).

2. Что сошлось — с числами

Объект сверкиПроверокСовпалоРасхождений
Лист «август 2024» (A1:R26): 468 ячеек × (значение + формат)9369360
Тот же лист в файле из HTTP-ответа сервиса9369360
Лист «Сравнение» (A1:M13 → 143 ячейки × 2) + 5 объединённых диапазонов29127120
Арифметика формул спецификации на листах, которые нечем посчитать (см. §4)2042040
Состав и порядок листов книги101
Листы «сентябрь 2024», «август 2024_1», «сентябрь 2024_1» — листа в книге нет3
Всего2368234724

Лист «август 2024» совпал полностью, включая полную двоичную точность чисел (59921.393000000004, 4.3172822696), все прочерки -, пустую B5, хвостовой пробел в B4 и числовые форматы всех 468 ячеек. Лист «Сравнение» совпал по всем формулам (20 расхождений — только в 20 ячейках-константах, см. §3) и по всем форматам.

3. Реестр расхождений (24 записи)

Полный машинный реестр: evidence/punc-registry.csv. Ниже он же, сгруппированный.

3.1 Лист «Сравнение» — 20 ячеек-констант

Причина у всех одна: агрегаты «Сравнения» считаются по всем листам комплекта (SPEC-PUNC §6), в эталоне это август + сентябрь, а конструктор посчитал только август.

СтрокаПолеЯчейкиЗначение эталонаЗначение конструктора
5в т.ч. покупка мощности, объёмB5, E59.6294.605
5в т.ч. покупка мощности, стоимостьC5, F58 368 852.071873 965 543.75955
6в т.ч. покупка ЭЭ, объёмB6, E67 130 1263 437 811
6в т.ч. покупка ЭЭ, стоимостьC6, F612 896 242.4304189745 842 311.590378701
7Услуга по передаче, объёмB7, E77 118 6893 432 410
7Услуга по передаче, стоимостьC7, F716 872 905.767688 067 566.612380001
8Сбытовая надбавка, стоимостьC8, F81 905 244.7550360002901 881.397263
9Инфраструктура, стоимостьC9, F934 295.9060616 535.87091
10УИРП, объёмB10, E1011 4375 401
10УИРП, стоимостьC10, F106.65257999999999953.99674

Классификация причины: отличие исходных данных, не ошибка портирования. Доказательство — в §4.2: при подстановке строк сентября из эталонной выгрузки лист «Сравнение» совпадает с эталоном полностью (0 расхождений на 286 проверках). Формульные ячейки (D, G, H, I, J, K, L, M и итоговая строка 11) расхождений не дали вообще — формулы перенесены как есть, включая H11=SUM(H5:H9) без строки УИРП.

3.2 Отсутствующие листы — 3 записи

Лист эталонаЧто в конструктореПричинаКлассификация
«сентябрь 2024» (468 ячеек)листа нет; запрос за сентябрь → HTTP 400 с текстом причиныв наборе 00102 единственный период — D_Year=2024, D_Month=8 (386 строк); строк за сентябрь нет ни по одному договору и типу документаотличие исходных данных
«август 2024_1» (468 ячеек)листа нетэталон содержит второй комплект листов; см. §3.4отличие эталона от переданной логики
«сентябрь 2024_1» (468 ячеек)листа нетто жеотличие эталона от переданной логики

3.3 Состав книги — 1 запись

Причина — сумма двух предыдущих пунктов (нет сентября + не воспроизводится второй комплект). Порядок листов у совпадающих имён верный: лист периода первым, «Сравнение» последним.

3.4 Новый факт шага 5 про второй комплект листов

Поячеечное сравнение листов эталона между собой:

Пара листов эталонаНепустых ячеекРазличий
«август 2024» ↔ «август 2024_1»363 / 3630
«сентябрь 2024» ↔ «сентябрь 2024_1»346 / 3460

То есть второй комплект — точная копия первого, а не второй сценарий расчёта с другими числами. Это уточняет [ВОПРОС 1] спецификации, но не закрывает его: из эталонов не выводится, при каком условии код печатает период дважды (это может быть и особенность конкретной выгрузки, и правило вида «раскладка + сводка»). Дублировать листы «на всякий случай» — додумывание логики, прямо запрещённое ТЗ, поэтому конструктор по-прежнему печатает один лист на период. Правило дублирования — за заказчиком (одна строка ответа: дублировать всегда / никогда / по условию).

4. Доказательства того, что расхождения не от логики

4.1 Формулы работают и на сентябрьских числах

К колонкам самих эталонных листов применены формулы спецификации: K = D+E+F+G+I−J (прочерк = 0), N = D·C, O = E·C, P = (F−J)·C, Q = G·C, R = I·C.

Лист эталонаПроверокРасхождений
«сентябрь 2024»660
«август 2024_1»720
«сентябрь 2024_1»660

Это проверяет перенос формул там, где нет исходных данных для проверки выборки: на 11 строках сентября, которых конструктор не считал, его формулы дают ровно те числа, что лежат в эталоне.

4.2 Пробы с подстановкой строк из эталона (в зачёт §2 не входят)

Строки сентября берутся из эталонной выгрузки заказчика (это подстановка чисел, а не расчёт конструктора) и подаются в штатный рендер:

ПробаПроверокРасхождений
Лист «сентябрь 2024»: вёрстка, шапка, прочерки, колонка L, форматы9360
Лист «Сравнение» с подставленным сентябрём286 + 5 объединений0

Вывод: вёрстка листа сентября (имя листа, B6, A9 = за сентябрь 2024 г., другой порядок разделов, матрица прочерков, L только у «Электрической энергии») и агрегаты «Сравнения» (в т.ч. деление объёма мощности на 1000) воспроизводятся точно. Не хватает только исходных строк за сентябрь.

5. Что подгонялось и что правилось в коде

Ничего. После сверки код расчёта и вёрстки (app.py, mart.py, punc_template.py) не изменялся — ошибок портирования сверка не выявила, а расхождения §3 исправлению кодом не подлежат (их причина — данные и неопределённое правило эталона). Добавлены только средства проверки, на результат отчёта не влияющие:

ФайлНазначение
verify_punc_full.pyсплошная сверка всех листов на 4 уровнях + генерация реестра
evidence/punc-registry.csvмашинный реестр расхождений (лист / строка / колонка / поле / эталон / конструктор / вид / причина)
evidence/verify-punc-full.txtпротокол прогона
evidence/step5-live-aug.xlsx, .headersфайл и заголовки HTTP-ответа сервиса, участвовавшие в сверке
тесты в test_punc.pyрегресс: формулы воспроизводят эталонный сентябрь; листы _1 идентичны первым

6. Чем закрыть оставшиеся 24 расхождения

РасхожденийЧто нужно от заказчика
21 (лист сентября + 20 ячеек «Сравнения»)выгрузка наборов 00102 и 00101 за сентябрь 2024 — в data.db их нет; после загрузки сверка идёт тем же скриптом без правок кода
3 (второй комплект листов и состав книги)правило: печатать ли каждый период дважды и при каком условии (в эталоне обе копии идентичны)
Код к отчету.txt в контуре прогона по-прежнему отсутствует (find / -iname '*Код к отчету*' → пусто); спецификация снята с эталонной выгрузки и сохранившихся выжимок кода. С кодом на руках можно было бы подтвердить оба пункта без предположений

7. Как проверить руками

python3 -m pytest -q                 # тесты, включая регресс сверки
python3 verify_punc_full.py          # 2368 проверок, 24 расхождения, реестр в evidence/
python3 app.py --port 8911
curl -o punc.xlsx "http://127.0.0.1:8911/api/punc/export?contract_id=20&year=2024&month=8"
curl "http://127.0.0.1:8911/api/punc/export?contract_id=20&year=2024&month=9"   # 400 + причина

Развёрнутый сервис: https://sol-msqct09w-2ae.apps.sreda-ai.ru (проверка — /healthz, выгрузка — /api/punc/export?contract_id=20&year=2024&month=8). Страницы: приёмка шага 5 — punc-acceptance.html, спецификация — spec-punc.html, приёмка шага 4 — punc-acceptance-step4.html (все — по ссылке проекта https://app.sreda-ai.ru/api/projects/sol-msqct09w-2ae/preview/).