docs(openspec): решения №21–25 (Task 8: values по колонкам, лукалайки только для дат, пустая редакция, form_name)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
This commit is contained in:
parent
80622ed331
commit
37b36047fe
@ -93,7 +93,7 @@ docstring'ами на русском; алгоритмы и регулярки
|
|||||||
положит владелец, код не меняется. Выбор редакции для документа: по `report_date` шапки → по самой поздней
|
положит владелец, код не меняется. Выбор редакции для документа: по `report_date` шапки → по самой поздней
|
||||||
`period_date` колонок → по совпадениям кодов (с предупреждением). Пустая выбранная редакция → предупреждение
|
`period_date` колонок → по совпадениям кодов (с предупреждением). Пустая выбранная редакция → предупреждение
|
||||||
«редакция fsbu4 не заполнена», имена из OCR, `needs_check`. Код не в выбранной редакции, но есть в другой →
|
«редакция fsbu4 не заполнена», имена из OCR, `needs_check`. Код не в выбранной редакции, но есть в другой →
|
||||||
предупреждение, `needs_check`; код нигде → имя из ячейки OCR, `line_code_confidence` из OCR.
|
предупреждение, `needs_check`; код нигде → имя из ячейки OCR, `line_code_confidence = min(confidence ячейки кода, 99)` (решение №19).
|
||||||
- `ocr_lookalikes.yaml`: пары «символ → цифра» и список символов замены.
|
- `ocr_lookalikes.yaml`: пары «символ → цифра» и список символов замены.
|
||||||
- `statement_labels.yaml`: нормализованные подстроки `label` таблицы → `BALANCE` / `INCOME`.
|
- `statement_labels.yaml`: нормализованные подстроки `label` таблицы → `BALANCE` / `INCOME`.
|
||||||
Загрузка один раз при старте (`SCAN_RULES_DIR`, по умолчанию `rules/` сервиса), pydantic-валидация; битый yaml — ошибка
|
Загрузка один раз при старте (`SCAN_RULES_DIR`, по умолчанию `rules/` сервиса), pydantic-валидация; битый yaml — ошибка
|
||||||
@ -160,3 +160,8 @@ docs: bounded-PR (`03-architecture.md`, OQ-137, §11.1 п. 6 и 9, новые OQ
|
|||||||
| 18 | 2026-10-07 | R-1. Тест плана `test_aep3_like_rows_without_header` требовал `5 in layout.value_idxs`; ожидание заменено на `layout.value_idxs == (2, 4)`, алгоритм `infer_layout` не менялся | столбец 5 содержит только мусор («:», «+ :») и пустые ячейки: по дословному `_infer_layout` суммы (0) < мусор (2) — столбец не значение; ошибка плана, а не переноса | если реальный `aep_3.json` даст иной набор колонок — выяснится в golden (Task 10) |
|
| 18 | 2026-10-07 | R-1. Тест плана `test_aep3_like_rows_without_header` требовал `5 in layout.value_idxs`; ожидание заменено на `layout.value_idxs == (2, 4)`, алгоритм `infer_layout` не менялся | столбец 5 содержит только мусор («:», «+ :») и пустые ячейки: по дословному `_infer_layout` суммы (0) < мусор (2) — столбец не значение; ошибка плана, а не переноса | если реальный `aep_3.json` даст иной набор колонок — выяснится в golden (Task 10) |
|
||||||
| 19 | 2026-10-07 | R-2. `line_code_confidence = confidence ячейки кода` только если очищенный текст равен сырому И код есть в выбранной редакции; иначе `min(confidence, 99)`; `line_name_confidence` словарного имени равна `line_code_confidence`, имени из OCR — `confidence` ячейки наименования | требование «Нормализация ответа ИС» спеки; код плана капил уверенность только при мусоре в тексте кода, тест плана ожидал 99 для кода вне справочника | код вне справочника чаще даёт `needs_check` — это то, что нужно аналитику |
|
| 19 | 2026-10-07 | R-2. `line_code_confidence = confidence ячейки кода` только если очищенный текст равен сырому И код есть в выбранной редакции; иначе `min(confidence, 99)`; `line_name_confidence` словарного имени равна `line_code_confidence`, имени из OCR — `confidence` ячейки наименования | требование «Нормализация ответа ИС» спеки; код плана капил уверенность только при мусоре в тексте кода, тест плана ожидал 99 для кода вне справочника | код вне справочника чаще даёт `needs_check` — это то, что нужно аналитику |
|
||||||
| 20 | 2026-10-07 | О-3 (наблюдение, не меняет поведение): прочерк «—»/«–» при `confidence = 100` даёт `is_recognized = false` (дословный `parse_amount` вырезает тире → `verified = false`), дефис «-» — `true` | дословный перенос и формулировка спеки «разбор не отбрасывал символов» | лишний `needs_check` на формах с длинным тире; правило уточняется в §11.1 после проверки на стенде |
|
| 20 | 2026-10-07 | О-3 (наблюдение, не меняет поведение): прочерк «—»/«–» при `confidence = 100` даёт `is_recognized = false` (дословный `parse_amount` вырезает тире → `verified = false`), дефис «-» — `true` | дословный перенос и формулировка спеки «разбор не отбрасывал символов» | лишний `needs_check` на формах с длинным тире; правило уточняется в §11.1 после проверки на стенде |
|
||||||
|
| 21 | 2026-10-07 | R-3. `values` строки строятся по позиции колонки документа; при ином числе колонок у раскладки строки после повторной шапки — недостающие как «ячейки нет», лишние отбрасываются, одно предупреждение на таблицу, `needs_check` | спека: «values — по одному на колонку»; код плана давал значения по индексам раскладки строки и мог породить `column_index`-сироту, на которой упадёт уникальность `(meta_id, column_index)` в 3b | значения «лишних» колонок повторной шапки теряются в документе (остаются в `raw/`) |
|
||||||
|
| 22 | 2026-10-07 | R-4. `fix_lookalikes` — только для дат (дата отчёта, подписи колонок); коды — `clean_value`, суммы — `parse_amount`, ИНН — `digits_only`. Формулировка спеки про коды и суммы исправлена | §11.1 п. 1 и проверенный на стенде старый код; замена `S→5` и т. п. в суммах не проверена на стенде | код с латинской `O` вместо нуля отбрасывается как не-целое (остаётся в `raw/`) |
|
||||||
|
| 23 | 2026-10-07 | R-5. Предупреждения «код N из редакции X» не выдаются, если выбранная редакция пуста | до заполнения `fsbu4` каждая строка 2025 года давала бы шумное предупреждение (на `aep_6` 39+25), информативно одно «редакция <id> не заполнена» | при пустой редакции аналитик не видит, что код из другой редакции |
|
||||||
|
| 24 | 2026-10-07 | `header.form_name` не передаётся, если у таблицы нет `label` | контракт запрещает `null` в `form_name` (`OptionalNotNull`) | поле отсутствует вместо `null` |
|
||||||
|
| 25 | 2026-10-07 | R-6. Таблица без колонок значений (`columns = []`) → предупреждение «нет колонок значений», `needs_check` | иначе документ без колонок мог оказаться `done` | — |
|
||||||
|
|||||||
@ -168,7 +168,9 @@
|
|||||||
нет в справочниках — текст ячейки наименования. `line_code_confidence` — `confidence` ячейки кода, если очищенный текст
|
нет в справочниках — текст ячейки наименования. `line_code_confidence` — `confidence` ячейки кода, если очищенный текст
|
||||||
равен сырому и код есть в справочнике, иначе `min(confidence, 99)`; `line_name_confidence` — то же для словарного
|
равен сырому и код есть в справочнике, иначе `min(confidence, 99)`; `line_name_confidence` — то же для словарного
|
||||||
имени, иначе `confidence` ячейки наименования.
|
имени, иначе `confidence` ячейки наименования.
|
||||||
- `values` — по одному на колонку: `amount` — `parse_amount` (запятая → точка, скобки → минус, пробелы и прочие символы
|
- `values` — по одному на колонку документа (по позиции; если раскладка строки после повторной шапки даёт иное число колонок —
|
||||||
|
недостающие значения как «ячейки нет», лишние отбрасываются, одно предупреждение на таблицу «повторная шапка изменила
|
||||||
|
число колонок значений», решение №21; таблица без колонок значений — предупреждение «нет колонок значений», №25): `amount` — `parse_amount` (запятая → точка, скобки → минус, пробелы и прочие символы
|
||||||
отбрасываются, несколько точек — разделители тысяч; прочерк/пусто → `null`); `string_value` — текст ячейки как
|
отбрасываются, несколько точек — разделители тысяч; прочерк/пусто → `null`); `string_value` — текст ячейки как
|
||||||
распознан (`\n`/`\t` → пробел, края обрезаны) **только если `amount = null`** и текст не прочерк (DBML: «как распознано,
|
распознан (`\n`/`\t` → пробел, края обрезаны) **только если `amount = null`** и текст не прочерк (DBML: «как распознано,
|
||||||
если не число»), иначе `null`; `confidence` — ячейки; `is_recognized = confidence == 100 и разбор не отбрасывал символов`;
|
если не число»), иначе `null`; `confidence` — ячейки; `is_recognized = confidence == 100 и разбор не отбрасывал символов`;
|
||||||
@ -179,8 +181,10 @@
|
|||||||
`report_date_text` — сырой текст `date.form_name`, `report_date` — `parse_date` после `fix_lookalikes`
|
`report_date_text` — сырой текст `date.form_name`, `report_date` — `parse_date` после `fix_lookalikes`
|
||||||
(`null`, если текст не дата); `okud`, `okpo`, `okopf`, `okfs`, `address` — `null` (ИС их не отдаёт).
|
(`null`, если текст не дата); `okud`, `okpo`, `okopf`, `okfs`, `address` — `null` (ИС их не отдаёт).
|
||||||
- `checks` MUST NOT присутствовать.
|
- `checks` MUST NOT присутствовать.
|
||||||
Двойники букв и цифр (`fix_lookalikes`) SHALL применяться к тексту кодов, сумм, дат и ИНН только вплотную к цифрам;
|
Двойники букв и цифр (`fix_lookalikes`) SHALL применяться к тексту дат (дата отчёта и подписи колонок) только вплотную
|
||||||
`|` SHALL считаться разделителем клеток, если первая строка значения состоит из цифр, пробелов и знаков пунктуации.
|
к цифрам; `|` SHALL считаться разделителем клеток, если первая строка значения состоит из цифр, пробелов и знаков
|
||||||
|
пунктуации. Коды очищаются `clean_value`, суммы — `parse_amount`, ИНН — выделением цифр (как в проверенном на стенде
|
||||||
|
старом ядре, §11.1 п. 1; решение №22 `design.md`).
|
||||||
|
|
||||||
#### Scenario: Чистый скан с шапкой (`aep_6.json`)
|
#### Scenario: Чистый скан с шапкой (`aep_6.json`)
|
||||||
- **WHEN** нормализуется `aep_6.json` (две таблицы: «Бухгалтерский баланс» 122 строки со строкой-шапкой «Наименование показателя / Код / На 30 июня 2025 г / На 31 декабря 2024 г. / На 31 декабря 2023 г.» и «Отчет о финансовых результатах» 49 строк)
|
- **WHEN** нормализуется `aep_6.json` (две таблицы: «Бухгалтерский баланс» 122 строки со строкой-шапкой «Наименование показателя / Код / На 30 июня 2025 г / На 31 декабря 2024 г. / На 31 декабря 2023 г.» и «Отчет о финансовых результатах» 49 строк)
|
||||||
@ -217,8 +221,8 @@
|
|||||||
`fsbu4` (с 2025-01-01) присутствует и может быть пустой. Редакция документа SHALL выбираться по `header.report_date`,
|
`fsbu4` (с 2025-01-01) присутствует и может быть пустой. Редакция документа SHALL выбираться по `header.report_date`,
|
||||||
при его отсутствии — по самой поздней `period_date` колонок, при отсутствии обеих — по числу совпадений кодов с
|
при его отсутствии — по самой поздней `period_date` колонок, при отсутствии обеих — по числу совпадений кодов с
|
||||||
предупреждением «редакция определена по кодам». Пустая выбранная редакция → предупреждение «редакция <id> не
|
предупреждением «редакция определена по кодам». Пустая выбранная редакция → предупреждение «редакция <id> не
|
||||||
заполнена», имена строк — из OCR. Код, отсутствующий в выбранной редакции, но присутствующий в другой → предупреждение
|
заполнена», имена строк — из OCR. Код, отсутствующий в выбранной непустой редакции, но присутствующий в другой → предупреждение
|
||||||
«код <код> из редакции <id>». `ocr_lookalikes.yaml` SHALL задавать таблицу двойников; `statement_labels.yaml` —
|
«код <код> из редакции <id>» (для пустой редакции не выдаётся — достаточно «редакция <id> не заполнена»; решение №23). `ocr_lookalikes.yaml` SHALL задавать таблицу двойников; `statement_labels.yaml` —
|
||||||
нормализованные подстроки `label` → `BALANCE`/`INCOME`. Коды справочника SHALL быть строками из 4–5 цифр без дублей.
|
нормализованные подстроки `label` → `BALANCE`/`INCOME`. Коды справочника SHALL быть строками из 4–5 цифр без дублей.
|
||||||
|
|
||||||
#### Scenario: Редакция по дате отчёта
|
#### Scenario: Редакция по дате отчёта
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user