arm-ka-docs/context/07-open-questions.md

63 KiB
Raw Blame History

07. Открытые вопросы (реестр)

Правило: агент не закрывает вопросы сам. Если решение нужно для текущего среза — делает явное допущение, помечает его в коде # ASSUMPTION(OQ-nn) и в OpenSpec-change, и переносит вопрос в статус «допущение принято». Пользователь закрывает вопросы с аналитиками/методологами и обновляет этот файл.

ID Вопрос Откуда Влияет на Статус / допущение
OQ-01 Хранить ли все строки ОСВ или только контрагентские; нужен ли parent_entry_id (замечание 2 ревью v5.13) DBML, «Парсинг ОСВ» п. 11 срез 2 (парсер, osv_entry) допущение: хранить все строки + level + parent_entry_id; строку «Итого» не хранить, использовать для сверки
OQ-02 ОСВ «за 2/3/4 квартал» — квартальная или нарастающая? Как определять автоматически FNR01 маппинг периода срез 2, §2 правил допущение: по тексту — квартальная; при наличии Q1 того же года сверять opening
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
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 человеку (сервисы не правились)
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) допущение: матрица не меняется

Служебные идентификаторы в DBML/аналитике: ANL-nnn — замечания аналитика к макету; ARCH-nnn — архитектурные решения; DECISION-n — решения по модели; FIX-nn — исправления дефектов v4.