05-domain-rules §1.4: слепая зона R-21 переформулирована — достаточно свёрнутого непосредственного родителя (N2); §1 «Лимиты»: expat-скан всех XML-частей, после-чтения счёт только индексируемых диапазонов, что не ограничено. 07-open-questions OQ-108: остаточные риски (объём ячеек, sharedStrings/стили, entity expansion) и рекомендации (лимит памяти контейнера, предпроверка dimension/счётчик ячеек, подпроцесс с RLIMIT). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
121 lines
74 KiB
Markdown
121 lines
74 KiB
Markdown
# 07. Открытые вопросы (реестр)
|
||
|
||
Правило: агент **не закрывает** вопросы сам. Если решение нужно для текущего среза — делает явное допущение, помечает его
|
||
в коде `# ASSUMPTION(OQ-nn)` и в OpenSpec-change, и переносит вопрос в статус «допущение принято». Пользователь закрывает
|
||
вопросы с аналитиками/методологами и обновляет этот файл.
|
||
|
||
| ID | Вопрос | Откуда | Влияет на | Статус / допущение |
|
||
|---|---|---|---|---|
|
||
| OQ-01 | Хранить ли все строки ОСВ или только контрагентские; нужен ли `parent_entry_id` (замечание 2 ревью v5.13) | DBML, «Парсинг ОСВ» п. 11 | срез 2 (парсер, `osv_entry`) | допущение: хранить все строки + `level` + `parent_entry_id`; строку «Итого» не хранить, использовать для сверки; **допущение парсера (Срез 2a):** строка «Итого» отдаётся в `rows` как `group_type = TOTAL` (level 0, без родителя), в `metrics.rows` не считается; хранить ли её — решает ядро в 2c (`ASSUMPTION(OQ-01)` в `classify.py`) |
|
||
| OQ-02 | ОСВ «за 2/3/4 квартал» — квартальная или нарастающая? Как определять автоматически | FNR01 маппинг периода | срез 2, §2 правил | допущение: по тексту — квартальная; при наличии Q1 того же года сверять `opening`; **допущение парсера (Срез 2a):** `period_quarter` и `is_cumulative` вычисляются только по тексту периода (`rules/periods.yaml`; Q2–Q4 «N квартал» → `false`), сверка по данным — в ядре, подсрез 2c (`ASSUMPTION(OQ-02)`) |
|
||
| OQ-03 | Приведение квартальных ОСВ к нарастающим: ключ соединения (контрагент vs договор), пропуск промежуточного квартала | DOC-259006 | срез 4 | допущение: ключ (счёт, контрагент); пропуск квартала → блокирующая ошибка чек-листа |
|
||
| OQ-04 | ОСВ по субсчёту (58.03 вместо 58) закрывает ли обязательный документ «ОСВ 58» | фикстуры | чек-лист | допущение: нет; показывать как «частично» |
|
||
| OQ-05 | Нужен ли статус `document.RECOGNIZED` или все идут через `NEEDS_CHECK → CONFIRMED` | DBML | срез 2–3 | допущение: `RECOGNIZED` ставится, но подтверждение всё равно обязательно |
|
||
| OQ-06 | Замена одного документа внутри многодокументного файла | DBML | срез 3 | решено: замена файлом целиком |
|
||
| OQ-07 | Матчинг ВГО: одна строка = одна позиция (DOC-223044) или агрегировать по (компания, контрагент, счёт) (FNR03)? | DOC-223044 vs FNR03 | срез 5 | допущение: агрегировать по (компания, контрагент, счёт, сторона) с детализацией по `osv_entry.id` |
|
||
| OQ-08 | Знак порога 5 % в правиле пары (≤ или <), и к чему считать % — к меньшей сумме (Методика сноска 14) | FNR03 (знак потерян) | срез 5 | допущение: `≤ 5 %` к меньшей |
|
||
| OQ-09 | Правила элиминации ОФР (2110/2120/2310/2320/2330): точный состав субсчетов, источник средневзвешенной ставки НДС, выбор субсчетов «работником ПА самостоятельно» | FNR03 | срез 6 | не реализовывать авто-элиминацию ОФР до решения; только ручные `correction` |
|
||
| OQ-10 | Гудвилл: входит ли стр. 1350 (добавочный капитал) в базу участия; УК из ББ (1310) или из ОСВ 80/83 | DBML, DOC-259025, FNR03 | срез 6 | допущение: 1310 из ББ; 1350 — настраиваемый флаг, по умолчанию выключен |
|
||
| OQ-11 | Строка «ППА» в КФО (правило № 1, когда у А нет ОСВ 03) — что это и куда | FNR03 | срез 6 | не реализовывать |
|
||
| OQ-12 | Формулы ОФР: знаки 2410/2420/2430 по ФСБУ 4/2023 vs 66н; состав 1100 (1120–1140) | DOC-221281 | срез 3 | допущение: формулы §7, строки без значения = 0 |
|
||
| OQ-13 | `confidence` от ИС Сканирование — доли 0..1 или проценты 0..100; имя поля организации (`full_name` vs `form_name`) | FNR02 vs `aep_*.json` | срез 3 (scan-gateway) | **закрыт для scan-gateway (04.10.2026, по `aep_3.json`, `aep_6.json`):** `confidence` — числа 0–100 (не доли); название организации — `data_ocr.organization.form_name` (шумный OCR-текст), ИНН — `inn.form_name`, единицы — `units.form_name`, дата — `date.form_name` (в `aep_6.json` мусор); `full_name`/`inn.inn`/`units.measurement` из ТЗ в реальных файлах нет. Нормализация — Срез 3 |
|
||
| OQ-14 | `reporting_date` в JSON ИС Сканирование — «ждём обновлённый JSON» | FNR01 | срез 3 | **уточнено (04.10.2026):** отдельного поля `reporting_date` в ответе нет; `date.form_name` ненадёжен (в `aep_6.json` — «Общество с ограниченной ответственностью», в `aep_3.json` — «2\|0\|2\|4\|»); даты колонок — в строке-шапке `rows[0]` таблицы («На 30 июня 2025 г» в `aep_6.json`), в `aep_3.json` шапки нет. Допущение прежнее: парсить из шапки таблицы, при её отсутствии — `NEEDS_CHECK`; решение — Срез 3 |
|
||
| OQ-15 | Таймаут OCR 5 мин / 0 повторов (ТЗ 3) vs outbox с повторами (DBML) | DOC-037736 | срез 3 | решено DBML: `max_attempts` OCR = 1, парсер = 3 |
|
||
| OQ-16 | Матрица прав (ТЗ сноска 29 «будет разработана»); роли макета (Аналитик ДКБ, Наблюдатель) ≠ ТЗ (ANL-034) | ТЗ 8.1, макет | срез 1 | допущение: seed по §10 правил |
|
||
| OQ-17 | `user_role` M:N или одна роль на пользователя | DBML | срез 1 | допущение: M:N |
|
||
| OQ-18 | Статусы REJECTED / ARCHIVED из макета (ANL-035); `VERIFICATION_GO` (РКА ГО) — есть ли в маршруте | DBML, DOC-037734 | срез 7 | допущение: REJECTED не вводить (возврат = переход + комментарий); ARCHIVED — флаг фильтра; VERIFICATION_GO — есть |
|
||
| OQ-19 | `consolidation_lock` (взять в работу / перехват, ANL-036) — подтвердить с заказчиком | макет | срез 7 | реализовать как в DBML |
|
||
| OQ-20 | `company_group.crm_id` обязателен (модалка) или nullable (UC-02, DBML) | DOC-221280 | срез 1 | решено DBML: nullable + `code` |
|
||
| OQ-21 | «Дата перевода» ЮЛ в другую ГК — помечена «??» | DOC-221280 | срез 1 | допущение: `effective_date` ≥ сегодня (ANL-046) |
|
||
| OQ-22 | Ретеншн `results/` в S3 (ARCH-010) | DBML | срез 2 | допущение: как `uploads/` |
|
||
| OQ-23 | Расшифровки (`DISCLOSURE`): разбирать или только хранить (ANL-040) | DBML | — | только хранить |
|
||
| OQ-24 | Форма 276-ОД — состав и шаблон | FNR03 3.4 | — | вне scope |
|
||
| OQ-25 | Состав ГСК для тестовой группы «Русский бисквит»: входит ли ОАО «ЧКФ», ООО «ОФГ», «Лидер» | фикстуры | тесты консолидации | **частично закрыт по выгрузке ЕЦП (04.10.2026):** ГК «Русский Бисквит» (`1-AZFL6BQ`, Санкт-Петербургский РФ) — 21 запись; флаг «входит в ГСК» только у АО «Русский бисквит» и ООО «Пекарня Счастливочная»; ЧКФ, ОФГ, Малечкинская птицефабрика, ТК РБ, Регион Финанс и др. — в ГК, но **не в ГСК** (срез — `fixtures/directories/ecp-export-russkiy-biskvit.xlsx`). Периметр тестовой консолидации — две компании; OQ-25 остаётся про то, верен ли состав ГСК в CRM |
|
||
| OQ-26 | Единицы: ББ/ОФР в тыс. руб., ОСВ в руб. — правило округления при элиминации (до тыс., банковское?) | — | срез 6 | допущение: считать в рублях, округлять до тыс. руб. на выходе в `kfo_result_line` (ROUND_HALF_UP) |
|
||
| OQ-27 | Поля ТЗ 5.1 (сценарий, подход, гудвилл) не в модалке создания консолидации | макет [42] vs ТЗ 5.1 | срез 4, 6 | **решено (владелец макета, 03.10)**: `approach = BASIC` всегда в первой очереди, EXTENDED позже — определять по набору загруженных документов; `goodwill_enabled` — переключатель на вкладке «Гудвилл»; `scenario = CONFIRM` включается через меню «…» консолидации в списке |
|
||
| OQ-28 | ~~Нет экрана проверки распознавания~~ — есть, открывается кликом по документу в панели «Первичные документы» (снимок `41`) | макет [41] | срез 3 | **закрыт**: реализовать по макету; для ОСВ (xlsx) левая панель — уточнить |
|
||
| OQ-29 | Макет: нет экранов пользователей / ролей / матрицы прав (ТЗ 8.1, `role_permission`); в журнале макета роли «Аналитик ДКБ», «Кредитный аналитик», «Утверждающий РФ», «Верификатор ГО», «Система распознавания / Сервис» (ANL-034, снимок `43-02`) | макет vs ТЗ 8.1 | срез 1 | допущение: минимальный экран администратора по §10 правил; роли — коды ТЗ 8.1, названия макета не используются |
|
||
| OQ-30 | Макет: шахматка и КФО показаны в тыс. руб. с 2 знаками, ОСВ — в рублях; где и как округлять (связано с OQ-26) | макет [30] [31-01] | срез 5–6 | допущение: хранить и считать в рублях, переключатель единиц — только отображение |
|
||
| OQ-31 | КПП ЮЛ: в макете колонка и поле форм (`50`, `61`, `51-02`, `79`), в DBML v5.13 у `legal_entity` поля нет. Нужен ли КПП (и в импорте, и для ИП, у которых его нет)? | макет [50] [51-02] | срез 1, DBML v5.14 | **закрыт решением владельца 04.10.2026: КПП не нужен** (DBML v5.14 без поля; импорт его не читает; формы — без КПП) |
|
||
| OQ-32 | ЮЛ в макете состоит одновременно в ГСК и ГСЗ («Входит в ГСК» и «Входит в ГСЗ» заполнены, [79]); ТЗ 6.1 / ANL-030 — только в одной. Что верно? | макет [79] [51-02] | срез 1 (partial unique `related_group_member.legal_entity_id`) | **закрыт решением владельца 04.10.2026: ЮЛ только в одной ГК, одновременно — в одной ГСК и одной ГСЗ.** DBML v5.14: `related_group_member.kind` + partial unique `(legal_entity_id, kind) WHERE is_current` (отменяет ANL-030); выгрузка ЕЦП это подтверждает (флаги «входит в ГСК» и «входит в ГСЗ» одновременно) |
|
||
| OQ-33 | «ID ГСК/ГСЗ в CRM» в формах (`51-03`, `51-04`, `77-02`; пример «3-9CGSK01» в формате ЕЦП CRM): у `related_group` в DBML только внутренний `code` (GSK-001). Есть ли у ГСК/ГСЗ идентификатор в CRM? | макет [77-02] | срез 1, DBML | допущение: поле формы = `related_group.code`, генерируется системой; `crm_id` не вводить |
|
||
| OQ-34 | «Удалить» ГСК в меню строки (`77-01`): физическое удаление или закрытие с историей? В DBML у `related_group` нет флага/истории удаления | макет [77-01] | срез 1 | допущение: удаление только пустой группы (без текущих участников), факт — в `audit_event(MEMBERSHIP_CHANGE)` |
|
||
| OQ-35 | База процента отклонения: в таблице корректировки % считается к сумме стороны ЮЛ-1 (−79,77 % для 1 000 ↔ 202,32, `31-02-02`), в «Подтверждении КФО клиента» — к версии банка (ст. 2, `31-06`); DBML и Методика (сноска 14) — к **меньшей** сумме. Что считать правильным для `correction.deviation_percent` и `client_kfo_line.deviation_percent`? | макет [31-02] [31-06] vs DBML, Методика | срезы 5–6 | допущение: к меньшей (Методика); макет считать неточным |
|
||
| OQ-36 | Экран проверки показывает строки формы **без кода** («в том числе: Основные средства, пригодные к использованию…», `41`); DBML хранит только строки с кодом (`financial_statement_line`), контракт требует `line_code`. Хранить ли расшифровочные строки без кода (и как их показывать)? | макет [41] vs DBML, контракт | срез 3, контракт v1.x | допущение: строки без кода не хранить и не показывать в первой очереди |
|
||
| OQ-37 | Строка «Гудвилл 1105» (ФСБУ 4/2023) в распознанной форме (`41`) vs строка `kfo_result_line.line_code = 'GOODWILL'` в разделе I КФО: использовать код 1105 или служебный GOODWILL? Влияет на шаблон строк на фронте и на формулы §7 (1100 = … + 1105?) | макет [41], ФСБУ 4/2023 | срез 3, 6 | допущение: хранить код 1105 как пришёл; строка КФО «GOODWILL» — отдельная, уточнить у методологов |
|
||
| OQ-38 | ЕХ в макете показывает и **неверифицированные** консолидации («Консолидация 2025 К4», без даты верификации, `62` [83-01]); ЕХ ТЗ 6.2 — срез пишется только после «Верифицирован». Показывать ли в ЛК ЕХ незавершённые консолидации (как «в работе») или только `ex_snapshot`? | макет [62] [83-01] vs ЕХ ТЗ 6.2 | срез 7 | допущение: только срезы `ex_snapshot`; незавершённые — в разделе «Отчётность» |
|
||
| OQ-39 | Состав «сформированной отчётности» в ЕХ (`83-01`): КФО .xlsx, Шахматка .xlsx и «Консолидированная отчетность .pdf» с датой «Сформирован» и подписями Утвердил/Верифицировал. Нужен ли PDF-экспорт КФО и какие ещё артефакты (сводная ОСВ, корректировки, гудвилл — ЕХ ТЗ 5.2) показывать? | макет [83-01] vs ЕХ ТЗ 5.2 | срез 7 | допущение: xlsx из `payload` на лету для всех `item_type`; PDF — не делать до решения |
|
||
| OQ-40 | «Квартальная дата» в журнале для консолидации 2024 К1 показана как 01.01.2024 (`43-02`); по правилам банка 1 квартал 2024 = отчётная дата 01.04.2024 (`consolidation.reporting_date`). Что выводить? | макет [43-02] | срез 4, 7 | допущение: `reporting_date` по правилам (01.04.2024); макет неточен |
|
||
| OQ-41 | Экран «ЮЛ вне ГК» (`61`, заголовок «Юридические лица») показывает все ЮЛ с заполненной колонкой ГК, а не только монозаёмщиков. Это сводный реестр ЮЛ или фильтр `company_group_id IS NULL`? | макет [61] | срез 1 | допущение: сводный реестр всех ЮЛ с фильтром «вне ГК», по умолчанию выключенным |
|
||
| OQ-42 | «Проверка распознавания» для ОСВ (xlsx) в макете отсутствует (строки `doc-row--readonly`, `39`). Нужен ли отдельный экран проверки ОСВ (дерево строк, подсветка контрагентов) или проверка ОСВ только через сводную ОСВ (`30`)? | макет [39] | срез 2 (UI) | допущение: минимальный экран таблицы ОСВ по §1 правил без левой панели исходника |
|
||
| OQ-43 | Кнопка «К отчетности» неактивна у консолидаций в статусах «Инициация» и «Верификация РФ», активна у «Консолидация РФ» и «Верифицирован» (`34`). Каково правило доступности отчёта по статусу / роли? | макет [34] | срез 4, 7 (policy) | допущение: отчёт доступен с `CONSOLIDATION_RF` и далее для всех ролей с `CONSOLIDATION_VIEW`; «Инициация» — только карточка |
|
||
| OQ-44 | «Добавить версию» создаёт версию сразу без модалки (`43-01`), копируя периметр; нужно ли подтверждение и выбор сценария/подхода новой версии? | макет [43-01] | срез 7 | допущение: без модалки, периметр и сценарий копируются из предыдущей версии |
|
||
| OQ-45 | Контракт `recognition-result.schema.json` допускает `data_type = NU` (строки налогового учёта в ОСВ «БУ, НУ»), а enum DBML `osv_data_type` — только BU, CURRENCY, QUANTITY, SUM. Добавлять NU в DBML (v5.14) или не хранить строки НУ? | контракт v1.0 vs DBML | срез 2 (маппинг `osv_entry`) | допущение принято и применено в Срезе 0: контракт v1.0 оставляет `NU` (в копиях схем трёх сервисов `DataType` содержит `NU`), ORM `OsvDataType` в arm-core 1:1 с DBML v5.13 (BU, CURRENCY, QUANTITY, SUM), маппинг результата в `osv_entry` — `NoopMapper`, поэтому расхождение Срез 0 не затрагивает; решение (кандидат DBML v5.14: добавить `NU` в `osv_data_type`, либо не хранить строки НУ) — до начала Среза 2; источник: arm-core, предложения, раздел C; **допущение парсера (Срез 2a):** `data_type = NU` выдаётся как есть, без сверки с БУ (`ASSUMPTION(OQ-45)`), решение — в ядре, подсрез 2c |
|
||
| OQ-46 | Обязательны ли все ОСВ расширенного подхода (02, 03, 08, 44, 26, 91, 51, 52, 59, 80, 83, 86, 97, 001, 008, 009, 011) при `approach = EXTENDED`, или часть — «при наличии»? | ТЗ 5.1; `required_document_rule.is_mandatory` | срез 0 (seed), срез 3 (чек-лист) | допущение принято и применено в Срезе 0: все 27 строк EXTENDED в seed `arm-core/api/seed/core/required_document_rules.yaml` (маркер `ASSUMPTION(OQ-46)`) — `is_mandatory = true`; BASIC — 10 строк, все обязательные; смена правила — правка одного yaml; вопрос к методологам остаётся открытым до Среза 3 (чек-лист); источник: arm-core, предложения, раздел A |
|
||
| OQ-47 | Источник полного плана счетов 1С для seed `chart_of_account`: в фикстурах файла нет, «план счетов из бандла макета» не передан | `06-test-data.md` §6, `fixtures/README.md` | срез 0 (seed) | допущение принято и применено в Срезе 0: seed `arm-core/api/seed/core/chart_of_accounts.csv` — 122 строки (62 синтетических счёта Плана счетов 94н, 11 забалансовых, 49 субсчетов и подсубсчетов 1С БП 3.0, упомянутых в §4/§6); названия нестандартных субсчетов (66/67 `.06/.22/.24/.26`, 76.07.x, 76.08/.28/.38) выведены по их роли в §4 правил, а не взяты из справочника 1С; названия-заглушки заменить по справочнику 1С клиента, остальное добавляет администратор (ARCH-004); источник: arm-core, предложения, раздел A |
|
||
| OQ-48 | Правило элиминации № 1 (§4), сторона Б «76.07.1 − 76.07.5 − 76.07.9»: 76.07.5 и 76.07.9 не потомки 76.07.1, поэтому «вычитание» чисто информативно. Так и задумано? | `05-domain-rules.md` §4 (правило 1); seed `elimination_rules_v1.yaml`; arm-core: предл. 1 (T14.1) | срез 5 (пары ВГО) | допущение принято: исключения 76.07.5/76.07.9 на стороне Б хранятся как `is_excluded` и не влияют на сумму (76.07.1 их не содержит); алгоритм на них не опирается; подтвердить с методологами |
|
||
| OQ-49 | Правило № 1, сторона А: резервный счёт 01 лежит в одном списке с 03 и 76.07.9 — приоритета нет. Как выбирать «03, а если у А нет ОСВ 03 — 01»? Что значит «результат в строку ППА» (см. OQ-11)? | `05-domain-rules.md` §4 (правило 1: «01 — резервный»); seed `elimination_rules_v1.yaml`; arm-core: предл. 2 (T14.2) | срез 5–6 | допущение принято: в seed `accounts: ["03", "76.07.9", "01"]` без порядка; fallback «берём 01, если нет ОСВ 03» — в `comment` правила; логику приоритета реализует срез 5, до решения она не реализуется |
|
||
| OQ-50 | Составные коды статей КФО `1450/1550` (правило 1) и `1310/1350` (правило 7, гудвилл) хранятся в `elimination_rule.article_2_line` одной строкой с «/». Как их потреблять: делить по «/» и подбирать строку, которая есть в ББ Б, или хранить две строки? | `05-domain-rules.md` §4 (правила 1, 7); seed `elimination_rules_v1.yaml`; arm-core: предл. 3 (T14.3) | срез 5–6; кандидат DBML v5.14 (note колонки) | допущение принято: хранится как в §4, потребитель делит по «/»; предложение — зафиксировать это в note `article_2_line` в DBML v5.14 (версию не создавали) |
|
||
| OQ-51 | `required_document_rule`: уникальный индекс `(approach, document_type, account_id)` при nullable `account_id` допускает дубли строк для не-ОСВ документов (NULL в PostgreSQL различны). Добавить `NULLS NOT DISTINCT`? | DBML v5.13 (`required_document_rule`, Indexes); arm-core: предл. 4 (T8.3) | срез 3 (чек-лист); кандидат DBML v5.14 | допущение принято: ORM и миграция 1:1 с DBML v5.13 (без `NULLS NOT DISTINCT`); предложение v5.14: `[unique, note: 'NULLS NOT DISTINCT']`, как у `document` |
|
||
| OQ-52 | Контракт v1.0, `recognition-result-message`: `schema_version` принимает только `1.x` (`^1\.\d+$`), а `result_schema_version` — любой MAJOR (`^\d+\.\d+$`). Намеренно (файл результата версионируется отдельно) или небрежность? | `contracts/recognition-result-message.schema.json`; arm-core: предл. 5 (T20.7) | контракт v1.x; срез 2 (inbox, маппинг) | допущение принято: ядро повторяет схему буквально (любой MAJOR проходит валидацию); совместимость MAJOR результата проверяет маппинг Среза 2; уточнить у владельца контракта |
|
||
| OQ-53 | Контракт v1.0: схемы нигде не задают `additionalProperties: false` (кроме `columns` ОСВ). Считать ли неизвестные поля допустимыми расширениями? | `contracts/*.schema.json`; arm-core: предл. 6 (T20) | контракт v1.x; все три сервиса | допущение принято: модели ядра `extra = "ignore"` (строже схемы быть нельзя — ядро отвергнет совместимого пира); изменение — через MINOR контракта |
|
||
| OQ-54 | Параметры JWT РАИСА неизвестны: JWKS URL / публичный ключ, `iss`, `aud`, имя claim с email. Что в продуктивном контуре? Делать ли проверку `aud`/`iss` обязательной в проде? | ТЗ 8.1, `03-architecture.md` (SSO РАИСА); `core/auth.py`; arm-core: предл. 7 (T16.2) | срез 1+ (прод-конфигурация) | допущение принято: настраиваются `AUTH_JWKS_URL`/`AUTH_PUBLIC_KEY` (взаимоисключающие), `AUTH_ISSUER`, `AUTH_AUDIENCE`, `AUTH_EMAIL_CLAIM` (по умолчанию `email`); при пустых `AUTH_AUDIENCE`/`AUTH_ISSUER` `aud`/`iss` не проверяются; предложение: в проде сделать `aud` обязательным и предупреждать при старте, если пусто |
|
||
| OQ-55 | В enum `audit_action` нет действия для смены статуса задания распознавания (`recognition_job`). Добавлять ли (DBML v5.14) и нужен ли аудит обмена вообще? | DBML v5.13 `audit_action`; arm-core: предл. 8 (R-7, design #20 arm-core) | срез 2 (обмен); кандидат DBML v5.14 | допущение принято: Срез 0 не пишет `audit_event` из обмена `recognition_job`; сервис аудита (`services/audit.py`) готов и покрыт тестами; если нужно — действие в v5.14 и вызовы в `recognition_exchange.py` |
|
||
| OQ-56 | Append-only аудит обеспечен только на уровне кода (единственная точка записи, статический тест на UPDATE/DELETE по `AuditEvent`). Нужна ли защита на уровне БД (триггер или `REVOKE UPDATE, DELETE` для роли приложения)? Вопрос поднят дважды (в том числе финальным ревью ветки). | инвариант «Append-only аудит» (`../CLAUDE.md`); `services/audit.py`; arm-core: предл. 9 и дополнение к нему (задача 21) | миграции, права БД; платформа | **решено человеком 04.10.2026: осознанный техдолг.** Append-only на уровне кода и тестов; защита на уровне БД (триггер или `REVOKE UPDATE, DELETE`) — позже, вместе с платформой, до прода |
|
||
| OQ-57 | Счётчик повторных публикаций запроса (`ACK_TIMEOUT_SECONDS` × `OUTBOX_MAX_REPUBLISH`) хранится в `recognition_job.metrics.republish_count` (jsonb), колонки в DBML нет; при каждой повторной публикации `published_at` перезаписывается временем последней, время первой не сохраняется. Нужны ли колонка счётчика и время первой публикации (v5.14)? | `services/recognition_exchange.py` (design #6 arm-core); arm-core: предл. 10 (T23, T23.1); docs: O-19 (задача 4 фазы 2) | срез replay; кандидат DBML v5.14 | допущение принято: счётчик в `metrics.republish_count`, `attempt` при повторе не растёт; `published_at` — время последней публикации (`dlq` через (`OUTBOX_MAX_REPUBLISH`+1)×`ACK_TIMEOUT_SECONDS` ≈ 120 с, описано в `dev/README.md`); при будущем replay счётчик и `reply_deadline` надо сбрасывать |
|
||
| OQ-58 | Семантика сроков и ошибок обмена в ядре: (а) `reply_deadline` по умолчанию = `now + 5 мин` для обоих pipeline (`tabular`, `image`), если у задания NULL; в DBML срок есть только для OCR («OCR — 5 мин»), для парсера значения нет; (б) при невозможности собрать запрос по контракту задание уходит в `error` / `INVALID_REQUEST`; (в) при `ACK_TIMEOUT × (MAX_REPUBLISH+1) ≥ 5 мин` статус `dlq` недостижим (раньше сработает `timeout`). Верно ли? Какой срок у `tabular-parser`? | DBML `recognition_job.reply_deadline` note; `recognition_exchange.py` (`DEFAULT_REPLY_TIMEOUT`); arm-core: предл. 11 и дополнение (T23.4) | срез 2–3; настройка таймаутов | допущение принято: как описано (дефолты 30 с × 3 укладываются в 5 мин); сроки по pipeline уточнить с командами парсера и шлюза |
|
||
| OQ-59 | Email пользователя сопоставляется с `app_user.email` по `lower(email)`; при двух записях, различающихся регистром, — 403 (fail-closed). Добавить `CHECK`/уникальный индекс по `lower(email)` в DBML? | `core/auth.py`, `api/dependencies/auth.py`; arm-core: предл. 12 (R-17, design #29 arm-core) | срез 1 (админ-экран); кандидат DBML v5.14 | допущение принято: уникальность `email` регистрозависимая (как в DBML); регистронезависимая — в v5.14 |
|
||
| OQ-60 | Seed `--dev` не защищён флагом `DEBUG`: создаёт dev-пользователей (в том числе `ADMIN`) на любой БД, на которую указывает `.env`, и перезаписывает существующего `app_user` с совпадающим email. Нужна ли защита? | arm-core `scripts/seed.py`; arm-core: предл. 13 (T15.2, T15.4) | срез 0 (процесс); прод-развёртывание | допущение принято: спека защиты не требует, `--dev` помечен «только для разработки» (в compose запускается `arm-core-migrate`); предложение — отказ при `DEBUG=false` или явный флаг подтверждения |
|
||
| OQ-61 | Неверный метод на существующий API-маршрут (например `POST /api/v1/me`) отдаёт 404 вместо 405: SPA-монтирование на `/` перехватывает частичное совпадение, а `/api/*` в нём принудительно 404. Приемлемо? | arm-core `app.py` (`SPAStaticFiles`); arm-core: предл. 14 (T18.2) | API-контракт (клиенты, фронт) | допущение принято: оставлено как есть (честный 404 для несуществующих путей важнее 405); при необходимости — отдельная правка |
|
||
| OQ-62 | В образе `arm-core` нет фронта (`Dockerfile` не собирает `web/`), `GET /` отдаёт 307 на `//` и затем 404; редирект на `//` похож на дефект монтирования SPA при `ROOT_PATH=/`. Собирать `web/` в образ в Срезе 0/1 и чинить редирект? | arm-core `Dockerfile`, `app.py`; docs: O-10 (задача 3 фазы 2), `dev/README.md` | срез 0 (compose), срез 1 (фронт) | допущение принято: README фиксирует отсутствие UI в образе; редирект на `//` не исследовался (сервис не правился) — follow-up arm-core |
|
||
| OQ-63 | `web/package-lock.json`: шаблон lock не содержит, `raisa-*` из Nexus — lock вне банка отличался бы; в Срезе 0 lock в `.gitignore`. `npm install` сообщает 6 high (npm audit) в зависимостях шаблона web. Коммитить ли lock; кто обновляет зависимости? | arm-core `web/`; arm-core: предл. 15 (T25.1, R-23, design #35 arm-core) | платформа, фронт; до прода | допущение принято: lock не в репозитории, зависимости не менялись; решение — с платформенной командой (Nexus, политика audit) |
|
||
| OQ-64 | Аудит `LOGIN` / `LOGIN_FAILED` (действия есть в `audit_action`) для JWT-аутентификации: в каком срезе и что считать «входом» — первый запрос с токеном, каждый запрос, отказ проверки токена? | DBML `audit_action`; `core/auth.py`; arm-core: предл. 16 (финальное ревью) | срез 1 (вход, админ-экран); аудит | допущение принято: в Срезе 0 вход не аудируется; сервис аудита готов |
|
||
| OQ-65 | Шаблонные CORS `allow_origins=["*"]` + `allow_credentials=True` и `ProxyHeadersMiddleware(trusted_hosts=["*"])`: в проде любой клиент может подставить `X-Forwarded-For`, и `audit_event.ip_address` недостоверен. Какие origins и доверенные прокси на платформе? | arm-core `app.py` (шаблон команды); arm-core: предл. 17 (финальное ревью) | прод-конфигурация; достоверность аудита | допущение принято: оставлено как в шаблоне; перечни origins и доверенных прокси — с платформенной командой до прода |
|
||
| OQ-66 | `/docs` и `/openapi.json` FastAPI открыты без аутентификации, в том числе в проде. Закрывать их (выключать при `DEBUG=false`) или оставить? | arm-core `app.py` (шаблон); arm-core: предл. 18 (финальное ревью) | прод-конфигурация; безопасность | допущение принято: открыты, как в шаблоне; решение — с платформой и ИБ |
|
||
| OQ-67 | Inbox не обновляет `stored_file.status` (`UPLOADED → PROCESSING → PROCESSED / ERROR`) и `stored_file.current_recognition_job_id` по результату задания: после результата файл остаётся `UPLOADED`, `current_recognition_job_id` пуст. Кто и когда это делает в Срезе 2 — inbox или маппер, в одной транзакции? | DBML `stored_file`, `file_status`; `recognition_exchange.py`; arm-core: предл. 19 (финальное ревью); docs: O-18 (задача 4 фазы 2) | срез 2 (загрузка и маппинг) | допущение принято: в Срезе 0 (`NoopMapper`) файл остаётся `UPLOADED`, в `dev/README.md` записано как «не покрывается»; решение — при проектировании маппера Среза 2 |
|
||
| OQ-68 | Конверт `error` у `scan-gateway` публикуется без `metrics`, поэтому `recognition_job.metrics` = NULL (у `tabular-parser` в `metrics` есть `duration_ms`). Требовать ли `metrics` в конверте ошибки и единые поля метрик у обоих сервисов? | scan-gateway `core/worker.py`; docs: O-18 (задача 4 фазы 2, сквозная проверка) | срез 2–3 (наблюдаемость, контракт v1.x) | допущение принято: `metrics` в контракте необязательны, ядро хранит NULL; требование — решение владельца контракта |
|
||
| OQ-69 | Обработчик `recognition.result` выполняется последовательно в callback подписки NATS; длинный маппер Среза 2 задержит следующие сообщения, ack сервиса не успеет за `ACK_TIMEOUT_SECONDS` (30 с) — ложный republish, затем `dlq`. Предложение: развести быстрый inbox (фиксация сообщения и статуса) и отдельный цикл маппинга результата. | arm-core `core/nats.py` (`subscribe_results`), `recognition_exchange.py` (`handle_message`, `ResultMapper`); arm-core: предл. 20 (финальное ревью) | срез 2 (маппинг); архитектура обмена (D-6) | допущение принято: в Срезе 0 `NoopMapper` — проблема не проявляется; решение — до реализации маппера Среза 2 |
|
||
| OQ-70 | Перед чтением файла результата маппер должен проверять, что ключ начинается с `results/{file_id}/{job_id}/`, а бакет — бакет роли `results` (иначе сервис может «подсунуть» чужой объект). Закрепить это в контракте и `03-architecture.md`? | контракт `recognition-result-message` (`result_s3`); arm-core `_register_result_object` (`recognition_exchange.py`); arm-core: предл. 21 (финальное ревью) | срез 2 (маппинг); контракт v1.x | допущение принято: в Срезе 0 результат только регистрируется в `s3_object`, не читается; проверку реализует маппер Среза 2 |
|
||
| OQ-71 | Запрос без читаемых `job_id` / `file_id` / `attempt` остаётся без ответа (конверт собрать нельзя): сервис логирует ошибку и отбрасывает запрос, ядро закрывает задание `dlq` / `NO_ACK` примерно через 120 с. Расходятся и реализации: при нечитаемом `attempt` `tabular-parser` берёт его из заголовка `Nats-Msg-Id` запроса или ничего не отправляет, `scan-gateway` подставляет `attempt = 1` и публикует конверт. Оставить так, выровнять реализации или сделать `file_id` необязательным в конверте `error` (MINOR 1.1)? | `recognition-contract` spec, сценарий «Нечитаемый запрос»; tabular-parser: P-1 (задача 4.3); docs: O-24, design #35 | контракт v1.x; срез 2–3 | допущение принято: молчание сервиса (design #35); реализации выровнять в Срезе 2/3, влияние только на битые запросы |
|
||
| OQ-72 | Ack при несовместимой версии запроса: ранняя формулировка контракта и `03-architecture.md` требовали «`SCHEMA_MISMATCH` и ack», оба сервиса публикуют `error SCHEMA_MISMATCH` без ack (ядро принимает результат из `published`, ack перед ним ничего не добавляет). Спека и документ приведены к поведению сервисов — подтвердить. | tabular-parser: P-2; scan-gateway: п. 2 таблицы предложений (T12.13, R-16); docs: design #34 | контракт v1.x; срез 2 | допущение принято: без ack, результат `SCHEMA_MISMATCH` закрывает задание (design #34); если ядро начнёт требовать ack перед результатом — правка одной строки в воркерах и спеке |
|
||
| OQ-73 | Повторная попытка (`attempt + 1`) того же `job_id` после ошибки или результата: оба сервиса дедуплицируют по `job_id` (LRU `DONE_CACHE_SIZE`), поэтому replay с новым `attempt` получает только ack и не обрабатывается, на единственном инстансе задание повисает до `reply_deadline` → `timeout`. По `03-architecture.md` replay — «сброс в `queued` с `attempt + 1`». Сделать ключ дедупликации `(job_id, attempt)`; повтор во время обработки — только ack? | tabular-parser: P-3 (задача 4.3); scan-gateway: п. 17 таблицы предложений (I-3, R-17); `03-architecture.md` (replay) | срез 3+ (replay); контракт v1.x | вопрос: допущение принято на Срез 0 — дедуп по `job_id`, ядро повторяет только тем же `attempt`; при одобрении — одна строка в воркере (ключ LRU); **человеком 04.10.2026 не рассмотрен — вопрос остаётся открытым** |
|
||
| OQ-74 | `PUBLISH_RETRIES` = одна первая попытка + до 3 повторов (всего до 4) с тем же `Nats-Msg-Id`; у `scan-gateway` тип `PositiveInt` (повторы нельзя отключить настройкой), у `tabular-parser` `NonNegativeInt` (0 допустим); паузы 0,5 с и 2,0 с. Согласовать единую семантику (повторы или всего попыток) и тип? | scan-gateway: п. 1 таблицы предложений (R-13, T11.1); docs: O-25, design #36 | контракт v1.x; настройки сервисов | допущение принято: «1 + 3 повтора» (design #36), расхождение «3 против 4» обмен не ломает (дедуп по `Nats-Msg-Id`); выровнять тип — косметика конфигурации |
|
||
| OQ-75 | `reply_deadline` проверяет только `scan-gateway` (`error TIMEOUT` до отправки в ИС и потолок ожидания ответа); `tabular-parser` обрабатывает просроченный запрос. Пример `contracts/examples/request-image.json` имеет `reply_deadline` в прошлом (`2026-10-03T12:45:00Z`) и даёт `TIMEOUT` при ручном прогоне. Единая обязанность сервисов и свежая дата примера? | scan-gateway: п. 12 таблицы предложений (O-e); docs: O-26, design #37 | контракт v1.x; срез 2 | допущение принято: срок — дело сервиса, пример — иллюстрация формы (оговорка в spec и `03-architecture.md`, design #37); обновить дату можно одним PR с пересинхронизацией копий в трёх репозиториях |
|
||
| OQ-76 | Обе реальные фикстуры `fixtures/ocr` (`aep_5.json`, `aep_8_form4.json`) — ответы-ошибки ИС (`error.code = INVALID_DOCUMENT`, пустой `table_structure`). Успешный путь `image` (`done` / `needs_check`, файл в `results/…`, `s3_object` с `bucket_role = results`) сквозной проверкой не покрыт; в `scan-gateway` проверяется только синтетическим ответом. Нужны образцы успешных ответов Content AI. | scan-gateway: п. 3 таблицы предложений (O-1, R-10, design #32); docs: O-15 (задача 4 фазы 2), design #31 | срез 3 (OQ-13/14, нормализатор); fixtures | **частично закрыт человеком 04.10.2026:** добавлены реальные образцы — `aep_3.json` (успех: баланс 42 строки + ОФР 18 строк), `aep_3_ofr.json` (второй ответ ИС по тому же файлу, `INVALID_DOCUMENT`), `aep_6.json` (успех: баланс 122 строки + ОФР 49 строк); PR в `arm-ka-fixtures`. Успешный путь `image` на реальных ответах — Срез 3 (нормализатор); транспорт `scan-gateway` проверяется на них в Срезе 0 (склейка нескольких json, `NOT_IMPLEMENTED`) |
|
||
| OQ-77 | §11 `05-domain-rules.md` описывает `data_ocr[]` (список), а в фикстурах `data_ocr` — объект с полями `label/organization/inn/units/date/table_structure`. Какой формат фактический на стенде ИС (связано с OQ-13, OQ-14)? | `05-domain-rules.md` §11; scan-gateway: п. 4 таблицы предложений (O-1, T3.2) | срез 3 (нормализатор) | **закрыт человеком 04.10.2026 (по `aep_3.json`, `aep_6.json`):** `data_ocr` — **объект**, один на json-файл (`label`, `organization`, `inn`, `units`, `date` — `{form_name, confidence}`; `table_structure` — **список таблиц** `{label, rows[]}`, одна таблица = один документ БС/ОФР, в одном json их может быть несколько). Успех — `error = {code: "", message: ""}` (не `null`!), ошибка — непустой `code` и пустой `table_structure`. §11 `05-domain-rules.md` исправлен. **Уточнение человека 04.10.2026:** разбиение одной формы на несколько таблиц (сегменты) в образцах не встречалось; наблюдается только несколько таблиц **разных** форм в одном json (баланс + ОФР). Нештатный случай (повтор `label`) — `NEEDS_CHECK`, правило уточнить в Срезе 3 по реальным данным |
|
||
| OQ-78 | Шлюз читает ровно `<output>/<job_id>/<job_id>.json` (спека); старый код читал все файлы каталога `Output/<id>/`. Какие файлы и когда реальная ИС кладёт в `Output`, в каком порядке (момент готовности)? | scan-gateway: п. 5 таблицы предложений (T8.5) | срез 3 (стенд ИС) | **закрыт человеком 04.10.2026:** ИС кладёт **все распознанные документы одновременно** в каталог `<job_id>`, по одному json на документ (пример: `aep_3.json` + `aep_3_ofr.json`); шлюз читает **все** json каталога и склеивает в один ответ (готовность — по стабилизации набора файлов, `SCAN_SETTLE_SECONDS`); ошибка одного документа не отменяет остальные (`metrics.warnings`). Реализуется в Срезе 0 (доработка PR scan-gateway #3) |
|
||
| OQ-79 | Временный файл `.<имя>.part` лежит в `Input` (атомарная запись `.part` + rename): реальная ИС без маски может забрать недописанный файл. Уточнить у владельцев ИС маску и поведение или перенести временный файл в служебный подкаталог рядом с `Input`? | scan-gateway: п. 6 таблицы предложений (R-5, T7/T8) | срез 3 (стенд ИС) | **закрыт человеком 04.10.2026:** временный файл записи уходит из `Input` в служебный каталог рядом (`SCAN_TMP_DIR`, по умолчанию `Tmp`, на той же шаре — `rename` остаётся атомарным). Реализуется в Срезе 0 (доработка PR scan-gateway #3) |
|
||
| OQ-80 | `make up` расходится с эталоном (scan-gateway и `dev/Makefile.common`): в `tabular-parser` нет `minio-init` — на свежем томе бакета `arm-ka` нет, `test_s3_integration` даёт `NoSuchBucket`, хотя README сервиса обещает бакет; в `arm-core` `up -d` без `--wait` и без `--project-name` (имя в compose фиксировано, безвредно). Также `check-full` в arm-core и tabular-parser — через пререквизиты (порядок при `make -j` не гарантирован), в scan-gateway — через `$(MAKE)`; `lint` arm-core включает `mypy scripts`. Подключить `include ../docs/dev/Makefile.common` в сервисах? | tabular-parser: `Makefile` (цель `up`); scan-gateway: п. 18 таблицы предложений (I-1); docs: O-1 и O-2 (задача 1 фазы 2), O-4 и O-5 (задача 2 фазы 2), `dev/checks.md`, `dev/Makefile.common` | срез 0 (процесс), все сервисы | допущение принято: эталон — scan-gateway, расхождения описаны в `dev/checks.md`, Makefile сервисов не правились (design #22, #24); выровнять — правкой Makefile сервисов (follow-up) |
|
||
| OQ-81 | Переменные `ARM_KA_DOCS` / `ARM_KA_FIXTURES` поддержаны неравномерно: `arm-core` — обе; `tabular-parser` — только `ARM_KA_DOCS`; `scan-gateway` — ни одной (жёстко `../docs`, `../../fixtures/ocr`). Текст причины skip («fixtures недоступен: положите репозиторий…») не содержит строки «ARM_KA_FIXTURES недоступен» из сценария «Нет фикстур» spec `quality-checks`; для docs-теста текст тоже без `ARM_KA_DOCS`. Нарушение spec — править сервисы? | scan-gateway и tabular-parser (тесты, Makefile); docs: O-3 (задача 1 фазы 2), `dev/checks.md`; spec `quality-checks` | срез 0 (процесс), все сервисы | допущение принято: расхождение описано в `dev/checks.md`; правка тестов и Makefile в scan-gateway и tabular-parser — follow-up человеку (сервисы не правились); **частично закрыт (Срез 2a, tabular-parser):** хелпер `tests/fixtures_helpers.py` поддерживает `ARM_KA_FIXTURES` (текст skip называет переменную и путь), `ARM_KA_DOCS` поддержан в тесте идентичности контракта; `scan-gateway` — по-прежнему ни одной переменной, остаётся follow-up человеку |
|
||
| OQ-82 | `.dockerignore` в `arm-core` не исключает `api/.env.test`: файл попадает в образ (у `tabular-parser` и `scan-gateway` исключён). Исправлять? | arm-core `.dockerignore`; docs: T3.2 (задача 3 фазы 2) | срез 0 (образы), прод-сборка | допущение принято: безвредно (в файле стандартные dev-учётные данные compose, не секреты), в Срезе 0 не правилось; добавить исключение в arm-core — follow-up |
|
||
| OQ-83 | Контейнеры профиля `services` подписаны на те же subject и queue group общего NATS, что и экземпляры в интеграционных тестах сервисов (`recognition.result` / `arm-core`, `*.request`): NATS может отдать сообщение теста контейнеру и наоборот; интеграционные тесты `scan-gateway` и `arm-core` одновременно тоже делят NATS. Сделать queue group и subject-префикс настраиваемыми для тестов (например `NATS_TEST_PREFIX`) или поднимать отдельный NATS на тесты? | scan-gateway: п. 11 таблицы предложений (T14.1, T11.8); docs: O-11 (задача 3 фазы 2; подтверждено ревью для tabular-parser и scan-gateway), `dev/README.md` | срез 0 (процесс), интеграционные тесты | допущение принято: в `dev/README.md` предупреждение и команда `stop` для контейнеров профиля; не гонять `make test-integration` двух сервисов одновременно |
|
||
| OQ-84 | Запуск сервисов из venv без Nexus (`make venv` + `python run_server.py` из `api/` с `.env` из `docs/dev/.env.example`, healthcheck по `localhost`) в Срезе 0 не проверялся ни в одном из трёх сервисов. Известно по чтению конфигов (design #44): `.env.example` в нынешнем виде отвергнут `scan-gateway` (`OPENBAO__DATABASE__*`) и `tabular-parser` (`OPENBAO__DATABASE__*`, `OPENBAO__SMB__*` — `extra_forbidden`), в нём нет `OPENBAO__MINIO__MINIO_SECURE=false` (по умолчанию `true` — https к http-MinIO). Прогнать сценарий, зафиксировать набор переменных и портов (`SERVER__PORT`, `SCAN_HOTFOLDER_PATH` для `scan-gateway`), решить, нужен ли отдельный `.env.example` на сервис, и снять пометку «черновик» с раздела `dev/README.md`? | spec `dev-environment`, сценарий «Запуск из venv против compose без Nexus»; docs: design #43, `dev/README.md` («Запуск сервисов из venv без Nexus»); финальное ревью фазы 2: I-1 | срез 0 (процесс, окружение разработки); кандидат в follow-up issue | вопрос: допущение Среза 0 — раздел README остаётся черновиком, сценарий не подтверждён (проверка требовала `.venv` внутри сервисных репозиториев, в фазе 2 доступных только для чтения) |
|
||
| OQ-85 | **Возможен ли JetStream на платформе** (серверный дедуп по `Nats-Msg-Id`, durable consumer'ы, redelivery вместо ack и повторной публикации на уровне приложения)? Сейчас NATS без JetStream (ответ платформы 03.10.2026); Срез 0 строит доставку на ack `processing`, повторной публикации ядром и дедупе по `recognition_job.result_msg_id`. Если JetStream подключить можно — меняются только publisher/subscriber (`core/nats.py` в трёх сервисах), outbox/inbox и контракт остаются; исчезают потеря результата при простое ядра и риск повторной обработки. | решение человека 04.10.2026: «узнать у платформы и проверить позже»; `design.md` slice-0-skeleton (D-3, Open Questions п. 4); OQ-72, OQ-73 | инфраструктура NATS (платформа); `core/nats.py`, воркеры сервисов | **вопрос к платформе (поставить напоминание, проверить после ревью Среза 0 / до Среза 3)**: допущение — без JetStream |
|
||
| OQ-86 | Фильтр видимости по ЗО (`business_segment`): сегмент есть только у `app_user`, у ГК/ЮЛ поля нет (DBML v5.14). Откуда брать сегмент ГК (из ЕЦП CRM? из РФ?), нужен ли вообще фильтр по ЗО в первой очереди? | §10.1 правил; DBML v5.14 | срез 1 (policy), DBML v5.15 | допущение: в Срезе 1 ЗО не фильтрует; видимость — только по филиалу (ГО видит всё) |
|
||
| OQ-87 | Выгрузка ЕЦП содержит типы `нерез.` (354), `ФЛ` (180), `нет инн` (2); enum `entity_type` — только ЮЛ/ИП. Нужны ли нерезиденты и физлица в справочнике (контрагенты ОСВ, поручители)? | `docs/source/biq/ecp-export-lagal-entity.xlsx`; §13.2 | срез 1 (импорт), DBML | допущение: строки пропускаются с кодом `UNSUPPORTED_TYPE`, enum не расширяется |
|
||
| OQ-88 | Проверять ли контрольные разряды ИНН при импорте и вводе (сейчас только длина 10/12); в выгрузке 279 нечисловых значений (`LV…`, `РНН…`, `нерез.`) | §13.2 | срез 1 | допущение: только длина; нечисловые → `INVALID_INN` |
|
||
| OQ-89 | «Базовый РФ ГК в CRM» в выгрузке содержит `ЦКБ` (1370 строк) и `Головная организация`: это головной офис (`regional_office.is_head_office`) или отдельные подразделения? Полный список — 53 значения, из них 51 «… РФ» | `ecp-export-lagal-entity.xlsx`; §13.2 | срез 1 (импорт, policy видимости) | допущение: создаются как обычные филиалы с именем из файла; маппинг на ГО — после ответа (миграция данных одной командой) |
|
||
| OQ-90 | Один ИНН в нескольких ГК выгрузки (215 случаев, напр. `7733288488` в `1-5AL0CC8` и `1-5A6WZN2`): какая ГК основная? `legal_entity.company_group_id` — одна | `ecp-export-lagal-entity.xlsx`; §13.2 | срез 1 (импорт) | допущение: первая встретившаяся ГК выигрывает, остальные строки — `LE_IN_OTHER_GROUP` в отчёте; перевод — вручную |
|
||
| OQ-91 | В выгрузке ЕЦП только флаги «входит в ГСК/ГСЗ» без идентификатора группы: у ГК предполагается одна ГСК и одна ГСЗ (в макете у «РМ Агро» две ГСК). Как ЕЦП кодирует несколько ГСК в одной ГК и даёт ли ГСК имя/ID (OQ-33)? | `ecp-export-lagal-entity.xlsx`; §13.2; макет [77] | срез 1 (импорт), срез 4 | допущение: импорт создаёт не более одной ГСК и одной ГСЗ на ГК с именем ГК; разделение — вручную Куратором/КА |
|
||
| OQ-92 | В выгрузке ЕЦП есть строки с непустым `iD ГК`, но пустыми «Организация»/«Группа компаний» (напр. строка 4034, ГК `1-KCKKHRK`). Импорт сейчас создаёт сущность с пустым именем. Пропускать такие строки или брать имя из других строк той же ГК? | `ecp-export-lagal-entity.xlsx`; §13.2; arm-core T9.6 | срез 1 (до боевого импорта) | допущение: импортируются как есть; исправление — повторный импорт с `update` |
|
||
| OQ-93 | ИНН в xlsx бывает числом — ведущий ноль теряется ещё в Excel (`0123456789` → `123456789`, 9 цифр → `INVALID_INN`). Считать ли такие ИНН восстанавливаемыми (дополнять нулём слева до 10/12)? | §13.1; arm-core T9.3 | срез 1 | допущение: не дополняем, строка → `INVALID_INN` |
|
||
| OQ-94 | Импорт с `on_existing = update` обновляет и архивные ГК (`is_archived`), не разархивируя их. Должен ли импорт разархивировать ГК, которая снова пришла из ЕЦП, или пропускать её? | §13.2; arm-core T10.7 | срез 1 | допущение: обновляется без разархивации |
|
||
| OQ-95 | Код `LE_IN_OTHER_GROUP` в отчёте импорта называет ЮЛ (ИНН, имя) из ГК, которую филиальный пользователь с `DIRECTORY_ADMIN` видеть не должен. Допустимо ли раскрытие в отчёте импорта (право по seed только у ADMIN ГО)? | §13.3; §10.1; arm-core T10.9 | срез 1 | допущение: отчёт импорта вне policy видимости, право даётся только ГО |
|
||
| OQ-96 | Граница «`effective_date` не раньше сегодня» (OQ-21) считается по UTC: для МСК правило сдвигается на 3 часа после полуночи. Какой часовой пояс — «банковский» МСК или UTC? | §13.4; arm-core R-9 | срез 1 | допущение: UTC |
|
||
| OQ-97 | Право `DIRECTORY_DELETE` по матрице §10 только у ADMIN: удалять алиасы и пустые ГСК/ГСЗ могут только администраторы, а не КА. Расширить право на KA_RF/KA_GO/CURATOR_GO? | §10; arm-core O-6 | срез 1 (seed) | допущение: матрица не меняется |
|
||
| OQ-98 | Единый список кодов валют для строк `data_type = CURRENCY` («USD», «EUR» под контрагентом): достаточно ли ISO 4217-списка из `rules/data_types.yaml` (`currency_codes`: RUB, USD, EUR, CNY, KZT, BYN, GBP, CHF, JPY, TRY, AED)? Нужны ли нестандартные написания и коды, которые используют конфигурации 1С | tabular-parser: design D-4, R-6, R-22 | срез 2c (маппинг CURRENCY-строк), словарь `data_types.yaml` | допущение принято: ISO-перечень, дополняется строкой в YAML вместе с синтетикой; коды не входят в тест покрытия словарей (R-22) |
|
||
| OQ-99 | Несколько ОСВ **одного счёта** в одной книге (разные листы: два периода или две организации): парсер выдаёт по одному `document` на лист (`locator = sheet:<имя>`) и ничего не дедуплицирует. Как ядро выбирает/сопоставляет такие документы с периодом и организацией? | tabular-parser: spec `osv-parsing` («Листы ОСВ находятся по содержимому») | срез 2c (маппинг, `document.period_check`) | допущение принято: каждый лист — отдельный документ, выбор — за ядром и аналитиком при проверке |
|
||
| OQ-100 | ИНН внутри **текста** строки контрагента («Полиграф, 3528315710», 20 строк в ОСВ 76 Счастливочной) и склеенная ячейка «ИНН/КПП»: извлекать ли ИНН в парсере или в ядре при резолве контрагента? Сейчас `counterparty_inn` берётся только из колонки ИНН (§1.3), `counterparty_name` = весь текст строки | tabular-parser: R-15, R-17 (design №25, №27) | срез 2c (резолв `counterparty_id` по ИНН/имени) | допущение принято: парсер не извлекает; ядро разбирает имя; при отрицательном решении — правило в парсере одной функцией |
|
||
| OQ-101 | Числа с ведущим «+», «.5», «5.» парсер отвергает как нечисловой текст (`null` + предупреждение с номером строки). Встречаются ли такие записи в выгрузках других систем; принимать ли их | tabular-parser: T7.3 | срез 2a+, словарь/правила `numbers.py` | допущение принято: отвергаются; в реальных файлах не встречаются |
|
||
| OQ-102 | Нужен **реальный xlsb из Excel**: единственный `fixtures/osv/synthetic/s13_no_outline_indent.xlsb` собран тестовым писателем BIFF12 и не доказывает чтение файлов, сохранённых Excel (стили, другая раскладка записей). Получить xlsb у аналитиков или пересохранить `s02` в Excel и заменить `s13` по инструкции в README fixtures | tabular-parser: R-9, O-7 | срез 2a (достоверность xlsb) | допущение принято: читаем `pyxlsb` без outline level и форматирования; проверка — на первом настоящем xlsb |
|
||
| OQ-103 | Счета с буквой в **первом** сегменте кода (забалансовые «МЦ.04», «ГТД», «НЕ.01.1») не распознаются как ACCOUNT: регулярка требует цифр в первом сегменте, строка станет контрагентом/группировкой по позиции. Нужны ли такие ОСВ, как их кодировать в `chart_of_account` | tabular-parser: R-16 (design №26), `classify.py` | срез 2c (план счетов), парсер | допущение принято: не распознаются; в 66 реальных файлах не встречаются |
|
||
| OQ-104 | Группировка «Валюта» в строке детализации (шапка варианта 2 «Детализация по субсчетам: …, Валюта») совпадает с меткой валюты шапки и порождает ложное предупреждение «валюта «» не распознана» (`currency = null` в обоих случаях). Править парсер (различать область шапки и строку детализации)? | tabular-parser: O-8, T12.1 (синтетика s16) | срез 2a+ (`header.py`) | допущение принято: дефект малозначим, предупреждение зафиксировано в golden-снимке s16 |
|
||
| OQ-105 | Сверка «сумма детей = родитель» по нетто (R-21): у родителя сальдо свёрнуто (счёт — одна сторона), у детей — развёрнуто. Подтвердить аналитиками, что нетто-свёртка родителя — штатное поведение 1С для **всех** версий выгрузки, а не артефакт двух организаций; остаточные риски RR-1…RR-4 и слепые зоны (перестановка сторон и одинаковое увеличение обеих сторон сальдо ребёнка под свёрнутыми предками не ловятся ничем) перечислены в §1.4 | tabular-parser: R-21 (design №31), `05-domain-rules.md` §1.4 | срез 2a (контрольные суммы), срез 2c | допущение принято: нетто допустимо, если у родителя не более одной ненулевой стороны сальдо; 32 из 66 реальных файлов иначе не сходились |
|
||
| OQ-106 | «Итого = корень» сверяется с **первой** корневой строкой ACCOUNT (уровень 0). Лист с несколькими корнями уровня 0 (несколько счетов в одной ОСВ; ОСВ по субконто без строк-счетов) получает `needs_check`, хотя «Итого» может быть равна Σ корней. Сверять «Итого» с суммой корней? | tabular-parser: финальное ревью Среза 2a, M-4 | срез 2a+ (контрольные суммы `checks.py`), чек-лист документов | допущение принято: сверка с первым корнем; многокорневой лист → `needs_check` (аналитик проверяет вручную); в фикстурах таких листов нет |
|
||
| OQ-107 | При `hierarchy=sums` (дерево восстановлено по равенству «сумма детей = родитель») сверка «сумма детей = родитель» тавтологична — она не может не сойтись. Считать ли такой разбор `needs_check` (или отдельное предупреждение достаточно)? | tabular-parser: финальное ревью Среза 2a, M-5 | срез 2a+ (статус результата), срез 2c (UI проверки) | допущение принято: статус — по контрольным суммам, стратегия видна в `metrics.warnings` (`hierarchy=sums`); на реальных файлах стратегия не выбирается (все — `outline`/`trivial`) |
|
||
| OQ-108 | Защита фазы чтения xlsx от XML-бомб (entity expansion) — `defusedxml` как новая зависимость сервиса — и иные лимиты памяти чтения. Остаточные риски после R-23/R-25: (1) бомба по объёму самих ячеек в пределах лимита распакованного zip — xlsx в 5 МБ с 2 млн обычных ячеек читается openpyxl 13 с и занимает 1,5 ГБ (замер ревьюера); (2) объём `sharedStrings` и стилей в тех же пределах; (3) entity expansion (от экспоненты «billion laughs» защищает только сам expat ≥ 2.4). Рекомендация: жёсткий лимит памяти контейнера сервиса; и/или предпроверка объявленного `<dimension>` и потоковый счётчик ячеек `<c>`/строк `sharedStrings` (тем же expat-сканом, что объединения) с лимитом; и/или разбор книги в подпроцессе с `RLIMIT_AS`/таймаутом, который можно убить. Решение платформы | tabular-parser: финальное ревью Среза 2a, I-1 (хвост), R-23, R-25 | tabular-parser (readers), платформа (зависимости и лимиты образа/пода) | допущение принято: действуют лимиты R-23/R-25 — распакованный zip ≤ 10 × `PARSE_MAX_BYTES`, площадь объединённых ячеек книги ≤ 200 000 (потоковый expat-скан всех XML-частей до openpyxl); объём ячеек, `sharedStrings`/стили и entity expansion не ограничены (README «Известные ограничения») |
|
||
| OQ-109 | Воркер tabular-parser скачивает объект S3 целиком и только потом проверяет `PARSE_MAX_BYTES`; проверять размер по `stat` до скачивания | tabular-parser: финальное ревью Среза 2a, M-7 | tabular-parser (`core/worker.py`) — вне Среза 2a | открыт: правка воркера — follow-up; лимит размера сейчас срабатывает после скачивания (память под файл выделяется) |
|
||
|
||
Служебные идентификаторы в DBML/аналитике: `ANL-nnn` — замечания аналитика к макету; `ARCH-nnn` — архитектурные решения;
|
||
`DECISION-n` — решения по модели; `FIX-nn` — исправления дефектов v4.
|