feat(normalizer): точка — разделитель тысяч в суммах OCR (AURORA-1405, #37) #38

Merged
aep merged 2 commits from feat/37-dot-thousands into main 2026-10-16 12:36:21 +03:00
Owner

Суть

AURORA-1405, возврат с тестирования 16.10.2026: после #35 запятая как разделитель тысяч работает (43/43), но значения, где ИС Сканирование вернула точку («4.200», «837.994»), оставались текстом.

Причина. «4.200» проходил parse_amount как Decimal("4.200") (три знака после точки), а document._value по решению №30 (Money = numeric(18,2), не больше двух знаков) отсекал такую сумму: amount = null, текст в string_value, is_recognized = false.

Решение владельца

Тот же обработчик, что для запятой: точки строго через три цифры — разделители тысяч. Шаблон [+-]?[1-9]\d*(\.\d{3})+ (ровно три цифры после каждой точки, цифр до первой точки любое; первая цифра ненулевая — решение владельца 16.10.2026, R-3) применяется ко всему тексту ячейки (после strip и удаления пробелов) или к содержимому пары скобок на всю строку; точки удаляются до остального разбора, is_recognized определяется только confidence == 100.
4.200 → 4200, 837.994 → 837994, (4.200) → −4200, -4.200 → −4200, 1234.567, 1 234.567 → 1234567, 12345.678 → 12345678, (1 234.567) → −1234567, 1.234.567 → 1234567 (раньше при нескольких точках is_recognized = false). Дроби (4.2, 4.20, 12.34, 1234.56) и смешанные (1.234,56) — как раньше.

Closes #37. Правило в docs: RSHB/arm-ka-docs, ветка feat/37-dot-thousands (PR RSHB/arm-ka-docs#109). Продолжение #35 / PR #36. Jira AURORA-1405.

Что изменено

  • api/src/normalizer/ocr/amounts.py — _DOT_THOUSANDS_RE и ветка в parse_amount.
  • api/tests/unit/normalizer/test_amounts.py, test_document.py — позитивные и негативные случаи, регресс по запятым.
  • README.md, openspec/specs/image-recognition-gateway/spec.md — описание правила.

Как проверить

make check-full (ниже). Вручную: прогнать ячейку «4.200» уверенностью 100 через нормализатор — amount = 4200, string_value = null, is_recognized = true.

Проверки

  • make check-full: lint чист; unit 1137 passed; integration 11 passed; docker-build успешно.
  • make golden-update: эталоны в fixtures/ocr/expected_normalize/ не изменились (в реальных ответах нет сумм с точкой-тысячами; регрессии по запятым нет).

Rulings I made

Маркер Решение Статус
R-1 Смешанные записи (1.234,56, 1,234.56, 1.234,567, 1.234.56) шаблону не соответствуют — разбор прежний (123456, is_recognized = false). Шаблон требует один и тот же разделитель на всю строку. fixed 68ffc5b
R-2 4.2, 4.20, 12.34 — дроби (до двух знаков принимаются), 1.2345 — текст (№30); 0.125, 01.234, 1234.567 (ведущий ноль или 4 цифры до точки) — не тысячи. fixed 68ffc5b
R-3 Пробелы убираются первыми: 1. 234 → 1234; точка с ровно тремя цифрами после неё — тысячи при любом числе цифр до неё (1 234.567, 1234.567, 12345.678 → тысячи; решение владельца 16.10.2026). fixed dec3f52
R-4 Влияние на даты, ОКЕИ, коды строк, ИНН: нет — parse_amount вызывается только для ячеек колонок значений (document._value, layout — определение колонок значений, rows — подсчёт пропущенных строк). Даты (31.12.2024) шаблону не соответствуют. fixed 68ffc5b (тест на дроби/даты-подобное)
R-5 1.234.567 теперь is_recognized = true (было false: точки считались «мусором»), как у 1,234,567. fixed 68ffc5b
R-6 1.234 (формально может быть дробью с тремя знаками) → 1234: дробь с тремя знаками всё равно не помещалась в Money (текст), потери нет. fixed 68ffc5b
R-7 Правило для запятой НЕ расширено (решение владельца было только про точку): 1234,567, 1 234,567 — по-прежнему дробь 1234.567 (отсекается №30); тысячи — только \d{0,2} цифр до первой запятой. fixed dec3f52 (тесты)
R-8 Первая цифра ненулевая: 0.125, 01.234 — не тысячи, как раньше. Дробная часть не из трёх цифр (4.2, 4.20, 1234.56) — дробь. fixed dec3f52
R-9 Риск: легитимная дробь с тремя знаками после точки (1234.567) теперь читается как 1234567; раньше такая сумма всё равно отсекалась №30 (текст), поэтому «тихой» порчи нет, но число может не сойтись — аналитик увидит на проверках (по решению владельца). accepted (решение владельца)
O-1 make check в docs падает на validate-openspec (дефолтный CHANGE=slice-0-skeleton уже в архиве) — не связано с этим PR. deferred

🤖 Generated with Claude Code

## Суть AURORA-1405, возврат с тестирования 16.10.2026: после #35 запятая как разделитель тысяч работает (43/43), но значения, где ИС Сканирование вернула **точку** («4.200», «837.994»), оставались текстом. **Причина.** «4.200» проходил `parse_amount` как `Decimal("4.200")` (три знака после точки), а `document._value` по решению №30 (`Money` = numeric(18,2), не больше двух знаков) отсекал такую сумму: `amount = null`, текст в `string_value`, `is_recognized = false`. ## Решение владельца Тот же обработчик, что для запятой: точки строго через три цифры — разделители тысяч. Шаблон `[+-]?[1-9]\d*(\.\d{3})+` (ровно три цифры после каждой точки, цифр до первой точки любое; первая цифра ненулевая — решение владельца 16.10.2026, R-3) применяется ко всему тексту ячейки (после `strip` и удаления пробелов) или к содержимому пары скобок на всю строку; точки удаляются до остального разбора, `is_recognized` определяется только `confidence == 100`. `4.200` → 4200, `837.994` → 837994, `(4.200)` → −4200, `-4.200` → −4200, `1234.567`, `1 234.567` → 1234567, `12345.678` → 12345678, `(1 234.567)` → −1234567, `1.234.567` → 1234567 (раньше при нескольких точках `is_recognized = false`). Дроби (`4.2`, `4.20`, `12.34`, `1234.56`) и смешанные (`1.234,56`) — как раньше. Closes #37. Правило в docs: RSHB/arm-ka-docs, ветка `feat/37-dot-thousands` (PR RSHB/arm-ka-docs#109). Продолжение #35 / PR #36. Jira AURORA-1405. ## Что изменено - `api/src/normalizer/ocr/amounts.py` — `_DOT_THOUSANDS_RE` и ветка в `parse_amount`. - `api/tests/unit/normalizer/test_amounts.py`, `test_document.py` — позитивные и негативные случаи, регресс по запятым. - `README.md`, `openspec/specs/image-recognition-gateway/spec.md` — описание правила. ## Как проверить `make check-full` (ниже). Вручную: прогнать ячейку «4.200» уверенностью 100 через нормализатор — `amount = 4200`, `string_value = null`, `is_recognized = true`. ## Проверки - `make check-full`: lint чист; unit 1137 passed; integration 11 passed; `docker-build` успешно. - `make golden-update`: эталоны в `fixtures/ocr/expected_normalize/` **не изменились** (в реальных ответах нет сумм с точкой-тысячами; регрессии по запятым нет). ## Rulings I made | Маркер | Решение | Статус | |---|---|---| | R-1 | Смешанные записи (`1.234,56`, `1,234.56`, `1.234,567`, `1.234.56`) шаблону не соответствуют — разбор прежний (`123456`, `is_recognized = false`). Шаблон требует один и тот же разделитель на всю строку. | fixed 68ffc5b | | R-2 | `4.2`, `4.20`, `12.34` — дроби (до двух знаков принимаются), `1.2345` — текст (№30); `0.125`, `01.234`, `1234.567` (ведущий ноль или 4 цифры до точки) — не тысячи. | fixed 68ffc5b | | R-3 | Пробелы убираются первыми: `1. 234` → 1234; точка с ровно тремя цифрами после неё — тысячи при любом числе цифр до неё (`1 234.567`, `1234.567`, `12345.678` → тысячи; решение владельца 16.10.2026). | fixed dec3f52 | | R-4 | Влияние на даты, ОКЕИ, коды строк, ИНН: нет — `parse_amount` вызывается только для ячеек колонок значений (`document._value`, `layout` — определение колонок значений, `rows` — подсчёт пропущенных строк). Даты (`31.12.2024`) шаблону не соответствуют. | fixed 68ffc5b (тест на дроби/даты-подобное) | | R-5 | `1.234.567` теперь `is_recognized = true` (было `false`: точки считались «мусором»), как у `1,234,567`. | fixed 68ffc5b | | R-6 | `1.234` (формально может быть дробью с тремя знаками) → 1234: дробь с тремя знаками всё равно не помещалась в `Money` (текст), потери нет. | fixed 68ffc5b | | R-7 | Правило для запятой НЕ расширено (решение владельца было только про точку): `1234,567`, `1 234,567` — по-прежнему дробь 1234.567 (отсекается №30); тысячи — только `\d{0,2}` цифр до первой запятой. | fixed dec3f52 (тесты) | | R-8 | Первая цифра ненулевая: `0.125`, `01.234` — не тысячи, как раньше. Дробная часть не из трёх цифр (`4.2`, `4.20`, `1234.56`) — дробь. | fixed dec3f52 | | R-9 | Риск: легитимная дробь с тремя знаками после точки (`1234.567`) теперь читается как 1234567; раньше такая сумма всё равно отсекалась №30 (текст), поэтому «тихой» порчи нет, но число может не сойтись — аналитик увидит на проверках (по решению владельца). | accepted (решение владельца) | | O-1 | `make check` в docs падает на `validate-openspec` (дефолтный `CHANGE=slice-0-skeleton` уже в архиве) — не связано с этим PR. | deferred | 🤖 Generated with [Claude Code](https://claude.com/claude-code)
aep added 1 commit 2026-10-16 12:29:36 +03:00
«4.200» разбирался как 4.200 с тремя знаками и отсекался решением №30
(amount = null, текст в string_value). Теперь точки строго через три цифры
([+-]?[1-9]\d{0,2}(\.\d{3})+, скобки на всю строку) — разделители тысяч,
как для запятой (#35): 4.200 -> 4200, (4.200) -> -4200, 1.234.567 -> 1234567,
verified не страдает. Дроби и смешанные записи (1.234,56) — как раньше.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
aep added 1 commit 2026-10-16 12:35:38 +03:00
Решение владельца 16.10.2026 (R-3): шаблон точки [+-]?[1-9]\d*(\.\d{3})+ —
«1 234.567», «1234.567», «12345.678», «(1 234.567)» -> тысячи. Дробная часть
не из трёх цифр, ведущий ноль, смешанные записи — как раньше. Правило для
запятой не расширено.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
aep merged commit 36d3f5fbf0 into main 2026-10-16 12:36:21 +03:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: RSHB/arm-scan-gateway#38
No description provided.