arm-ka-docs/context/07-open-questions.md
2026-10-15 16:53:39 +04:00

146 KiB
Raw Blame History

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

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

ID Вопрос Откуда Влияет на Статус / допущение
OQ-01 Хранить ли все строки ОСВ или только контрагентские; нужен ли parent_entry_id (замечание 2 ревью v5.13) DBML, «Парсинг ОСВ» п. 11 срез 2 (парсер, osv_entry) закрыт решением владельца 05.10.2026: хранить все строки ОСВ с level и parent_entry_id; строку «Итого» не хранить, использовать только для сверки (парсер отдаёт её как group_type = TOTAL, маппер Среза 2c отбрасывает)
OQ-02 ОСВ «за 2/3/4 квартал» — квартальная или нарастающая? Как определять автоматически FNR01 маппинг периода срез 2, §2 правил закрыт решением владельца 05.10.2026: ОСВ «за N квартал» — квартальная; признак сверяется по данным: если есть ОСВ Q1 того же года и opening совпадает — нарастающая (парсер ставит is_cumulative по тексту, ядро переопределяет при маппинге/в консолидации); допущение парсера (Срез 2a): period_quarter и is_cumulative вычисляются только по тексту периода (rules/periods.yaml; Q2–Q4 «N квартал» → false), сверка по данным — в ядре, подсрез 2c (ASSUMPTION(OQ-02))
OQ-03 Приведение квартальных ОСВ к нарастающим: ключ соединения (контрагент vs договор), пропуск промежуточного квартала DOC-259006 срез 4 закрыт решением владельца 06.10.2026 (Срез 4): ключ склейки — (счёт, контрагент по сырому имени и ИНН), договоры внутри контрагента (строка COUNTERPARTY уже содержит их сумму); пропуск квартала — пробел по паре (ЮЛ, счёт), а не блокирующая ошибка: строк пары в своде нет, пробел отдаётся в gaps[] сводки и в листе «Пробелы» экспорта; квартал без строки ключа = нули; дубль ключа внутри квартала суммируется. Правило — 05-domain-rules.md §2; код — domain/consolidation_periods.select_sources, domain/consolidated_osv.build
OQ-04 ОСВ по субсчёту (58.03 вместо 58) закрывает ли обязательный документ «ОСВ 58» фикстуры чек-лист закрыт решением владельца 05.10.2026: нет, ОСВ по субсчёту (58.03) — только субсчёт, обязательный документ «ОСВ 58» закрывает только полная ОСВ по счёту 58; чек-лист считает документ выполненным при osv_account_code = код правила
OQ-05 Нужен ли статус document.RECOGNIZED или все идут через NEEDS_CHECK → CONFIRMED DBML срез 2–3 закрыт решением владельца 05.10.2026: статус RECOGNIZED нужен: документ после успешного распознавания — RECOGNIZED, при нарушениях — NEEDS_CHECK, после подтверждения аналитиком — CONFIRMED. Пересмотрено OQ-157 (08.10.2026): после маппинга чистый документ сразу CONFIRMED; 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; расширение 07.10.2026: формулы и справочники по редакциям форм (66n / fsbu4) — OQ-146
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 закрыт реализацией Среза 1 (05.10.2026): M:N — user_role, PUT /admin/users/{id}/roles заменяет набор ролей
OQ-18 Статусы REJECTED / ARCHIVED из макета (ANL-035); VERIFICATION_GO (РКА ГО) — есть ли в маршруте DBML, DOC-037734 срез 7 допущение: REJECTED не вводить (возврат = переход + комментарий); ARCHIVED — флаг фильтра; VERIFICATION_GO — есть
OQ-19 consolidation_lock (взять в работу / перехват, ANL-036) — подтвердить с заказчиком макет срез 7 закрыт решением владельца 06.10.2026 (Срез 4): блокировка «взять в работу» закрывает все правки версии (периметр, статус, ручное сопоставление; загрузка и подтверждение документов блокировкой не ограничиваются); перехват — любому с CONSOLIDATION_EDIT, с обязательной причиной (takeover_reason), событие CONSOLIDATION_LOCK_TAKEOVER; истечения нет (OQ-119). 05-domain-rules.md §10
OQ-20 company_group.crm_id обязателен (модалка) или nullable (UC-02, DBML) DOC-221280 срез 1 решено DBML: nullable + code
OQ-21 «Дата перевода» ЮЛ в другую ГК — помечена «??» DOC-221280 срез 1 закрыт решением владельца 05.10.2026: дата перевода — effective_date ≥ сегодня, пишется в legal_entity_history; перевод применяется сразу; граница суток — по МСК (OQ-96, follow-up arm-core#8)
OQ-22 Ретеншн results/ в S3 (ARCH-010) DBML срез 2 допущение: как uploads/
OQ-23 Расшифровки (DISCLOSURE): разбирать или только хранить (ANL-040) DBML — только хранить; Срез 3b: допущение реализовано — DISCLOSURE — один документ на тип на файл (locator — через запятую), без данных, статус RECOGNIZED (§9.5 п. 2).
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; пересмотр — DBML v5.17 (docs#53, arm-core#45) закрыт решением владельца 07.10.2026: КПП нужен (пересмотр; повод — макет и комментарий фронтенда «в ручке получения ЮЛ не приходит КПП»): DBML v5.17 — legal_entity.kpp, legal_entity_history.kpp (nullable). Формат — 9 символов: 4 цифры, 2 символа (цифра или латинская A–Z), 3 цифры, иначе INVALID_KPP; у ИП КПП запрещён (422 INVALID_KPP, при импорте строка пропускается с предупреждением); для ЮЛ необязателен (старые записи и импорт без колонки валидны); уникален только inn (КПП — атрибут, сопоставление контрагентов ОСВ по ИНН не меняется); изменение КПП — обычный PATCH со снимком в legal_entity_history. История: 04.10.2026 — «КПП не нужен» (DBML v5.14 без поля; импорт его не читал; формы — без КПП); отменено 07.10.2026
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 закрыт реализацией Среза 1: related_group.code генерируется системой (GSK-NNNNNN/GSZ-NNNNNN), ID из CRM не вводится и не импортируется (в выгрузке ЕЦП его нет — OQ-91). Решение владельца 14.10.2026: POST/PATCH ГСК/ГСЗ принимают crm_id и пока отбрасывают его (arm-core #111), колонка related_group.crm_id — отдельной задачей arm-core #112 (DBML v5.19)
OQ-34 «Удалить» ГСК в меню строки (77-01): физическое удаление или закрытие с историей? В DBML у related_group нет флага/истории удаления макет [77-01] срез 1 закрыт реализацией Среза 1 (ASSUMPTION подтверждено отсутствием возражений): удаляется только пустая ГСК/ГСЗ (409 GROUP_NOT_EMPTY), состав сохраняется в before_value аудита; группа с FK из консолидаций — follow-up GROUP_IN_USE (arm-core#8, T8.1)
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 допущение: строки без кода не хранить и не показывать в первой очереди; Срез 3b: допущение реализовано — financial_statement_line пишется только для строк с кодом (строк без кода в результате нет), экран их не получает.
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 допущение принято и реализовано в Срезе 4 (06.10.2026): consolidation.reporting_date по правилу банка (Q1 → 01.04.Y, Q2 → 01.07.Y, Q3 → 01.10.Y, Q4 → 01.01.Y+1), domain/consolidation_periods.reporting_date; макет неточен
OQ-41 Экран «ЮЛ вне ГК» (61, заголовок «Юридические лица») показывает все ЮЛ с заполненной колонкой ГК, а не только монозаёмщиков. Это сводный реестр ЮЛ или фильтр company_group_id IS NULL? макет [61] срез 1 допущение: сводный реестр всех ЮЛ с фильтром «вне ГК», по умолчанию выключенным
OQ-42 «Проверка распознавания» для ОСВ (xlsx) в макете отсутствует (строки doc-row--readonly, 39). Нужен ли отдельный экран проверки ОСВ (дерево строк, подсветка контрагентов) или проверка ОСВ только через сводную ОСВ (30)? макет [39] срез 2 (UI) закрыт решением владельца 05.10.2026: экран проверки ОСВ нужен (дерево строк, суммы, нераспознанные контрагенты); в макете его нет — проектируется в подсрезе 2d «UI первичных документов»
OQ-43 Кнопка «К отчетности» неактивна у консолидаций в статусах «Инициация» и «Верификация РФ», активна у «Консолидация РФ» и «Верифицирован» (34). Каково правило доступности отчёта по статусу / роли? макет [34] срез 4, 7 (policy) решено владельцем 07.10.2026 (arm-core#42, П-3): «К отчетности» доступна во всех статусах, начиная с INITIATED, для ролей с CONSOLIDATION_VIEW; правка свода (сопоставление контрагента) — только «в работе» со своей блокировкой. Было: допущение: отчёт доступен с 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) закрыт решением владельца 05.10.2026: строки налогового учёта NU хранить в ядре: osv_data_type расширяется значением NU в DBML v5.15 (подсрез 2c, маппинг); контракт уже допускает NU
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 обязательным и предупреждать при старте, если пусто; контекст 07.10.2026: контур временно работает на dev-заглушке аутентификации (DEBUG=true, AUTH_DEV_ISSUER=true, вход по email; dev/contour-transfer-guide.md §6.3); не выяснено, используется ли в контуре raisa_fastapi_protected_api; вероятно, Keycloak (у старого фронта REACT_APP_KEYCLOAK_URL); переход на SSO — после ответа и arm-core#43
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 уточнить с командами парсера и шлюза 09.10.2026, решение владельца: OCR (image) — 20 мин, парсер — 5 мин (arm-core #87; note DBML — OQ-159)
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 закрыт реализацией Среза 2c (06.10.2026, arm-core/openspec/changes/slice-2c-osv-ingest), иначе, чем предлагалось: индекс по lower(email) не добавлен (сверка ORM↔DBML не умеет expression-индексы); в DBML v5.15 app_user.email хранится в нижнем регистре (миграция 0003 приводит существующие, seed и администрирование нормализуют при записи), поэтому обычный UNIQUE регистронезависим по построению
OQ-60 Seed --dev не защищён флагом DEBUG: создаёт dev-пользователей (в том числе ADMIN) на любой БД, на которую указывает .env, и перезаписывает существующего app_user с совпадающим email. Нужна ли защита? arm-core scripts/seed.py; arm-core: предл. 13 (T15.2, T15.4) срез 0 (процесс); прод-развёртывание закрыт реализацией (arm-core PR #10, техдолг Среза 1, 05.10.2026): python -m scripts.seed --dev при DEBUG=false отказывает с кодом 2 до чтения seed и подключения к БД; run_seed(dev=True) для тестов без защиты
OQ-61 Неверный метод на существующий API-маршрут (например POST /api/v1/me) отдаёт 404 вместо 405: SPA-монтирование на / перехватывает частичное совпадение, а /api/* в нём принудительно 404. Приемлемо? arm-core app.py (SPAStaticFiles); arm-core: предл. 14 (T18.2) API-контракт (клиенты, фронт) закрыт реализацией (arm-core PR #10, техдолг Среза 1, 05.10.2026): неверный метод на существующий маршрут /api/v1/* — 405 с заголовком Allow («метод не поддерживается этим маршрутом»); несуществующий путь и dev-маршрут при выключенных флагах — 404
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 (фронт) частично закрыт (arm-core PR #10): редирект / → // устранён (причина — root_path="/", теперь нормализуется), GET / отдаёт index.html. Открыто: фронт не собирается в образ arm-core — follow-up RSHB/arm-core#12
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 (вход, админ-экран); аудит закрыт реализацией (arm-core PR #10, техдолг Среза 1, 05.10.2026): LOGIN — выдача dev-токена и первый успешный запрос пользователя с токеном после старта процесса; LOGIN_FAILED — 401 (токен не принят, без user_id, причина без токена) и 403 аутентификации (email в description); раздел SESSION, отдельная транзакция; запрос без Authorization/не Bearer и 403 по праву — не события входа; LOGOUT не пишется (сессий на сервере нет)
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 (финальное ревью) прод-конфигурация; достоверность аудита частично закрыт (arm-core PR #10): CORS при DEBUG=true — * без credentials, при DEBUG=false — CORS_ORIGINS (пусто — кросс-доменные запрещены); X-Forwarded-For только от FORWARDED_ALLOW_IPS (по умолчанию 127.0.0.1). Открыто (к платформе): перечень доверенных прокси прода — follow-up RSHB/arm-core#12
OQ-66 /docs и /openapi.json FastAPI открыты без аутентификации, в том числе в проде. Закрывать их (выключать при DEBUG=false) или оставить? arm-core app.py (шаблон); arm-core: предл. 18 (финальное ревью) прод-конфигурация; безопасность закрыт реализацией (arm-core PR #10, техдолг Среза 1, 05.10.2026): /docs, /redoc, /openapi.json существуют только при DEBUG=true; в проде — 404
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 (загрузка и маппинг) закрыт реализацией Среза 2c (06.10.2026, arm-core/openspec/changes/slice-2c-osv-ingest): статус файла меняет код, проверивший current_recognition_job_id == job.id (services/file_status.py): ack/результат — PROCESSING, error/timeout/dlq — ERROR (inbox, вахтёр, публикатор), успешный маппинг — PROCESSED, автозамена — SUPERSEDED; current_recognition_job_id ставит загрузка. См. 05-domain-rules.md §9.2, §9.5
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) закрыт реализацией Среза 2c (06.10.2026, arm-core/openspec/changes/slice-2c-osv-ingest): inbox быстрый (фиксация сообщения и статусов, файл результата не читает), маппинг — отдельный фоновый цикл run_mapping_loop (MAPPING_POLL_SECONDS, MAPPING_MAX_ATTEMPTS); ack за ACK_TIMEOUT_SECONDS не задерживается. См. 03-architecture.md, «Цикл маппинга результата»
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 закрыт реализацией Среза 2c (06.10.2026, arm-core/openspec/changes/slice-2c-osv-ingest): цикл маппинга отвергает результат, если бакет не бакет хранилища или ключ не начинается с results/{file_id}/{job_id}/ (без ./../пустых сегментов) — файл ERROR, повтора нет; правило закреплено в 03-architecture.md («Схема ключей S3»)
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 по реальным данным; Срез 3b: допущение реализовано — второй BALANCE/INCOME того же типа в файле не создаётся (предупреждение «вторая форма … пропущена (OQ-77)»), первый документ — NEEDS_CHECK; правило по реальным данным стенда по-прежнему уточнить (§9.5 п. 2).
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) Пересмотрено владельцем 09.10.2026: запись прямо в Input с перезаписью, как в старом АРМ (там работало в контуре); Tmp и .part у шлюза убраны (arm-scan-gateway #26). Допущение: ИС не берёт файл, пока шлюз держит его открытым на запись
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 (образы), прод-сборка закрыт реализацией (arm-core PR #10, техдолг Среза 1, 05.10.2026): .dockerignore исключает api/.env.* (включая .env.test и .env.example); настройки контейнера — только из окружения
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 двух сервисов одновременно. 13.10.2026 (nats-env-config): subject'ы — настройки; интеграционные тесты tabular-parser и scan-gateway идут на уникальных subject'ах прогона и не пересекаются со стендом. Для make e2e ядра вопрос остаётся: ему нужен контейнер tabular-parser стенда на умолчаниях, конфликт — общая queue group arm-core (design R-7). Статус: открыт (частично)
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. 06.10.2026: RSHB/armka_file_worker (PDFWorker старого АРМ, проверен в контуре) тоже работает на core NATS (subscribe/publish + flush, без jetstream()), один JWT на все сервисы АРМ с правами по subject'ам; возможность включить 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 закрыт решением владельца 05.10.2026: граница «сегодня» — по МСК. Код arm-core пока считает по UTC; перевод на МСК — follow-up RSHB/arm-core#8
OQ-97 Право DIRECTORY_DELETE по матрице §10 только у ADMIN: удалять алиасы и пустые ГСК/ГСЗ могут только администраторы, а не КА. Расширить право на KA_RF/KA_GO/CURATOR_GO? §10; arm-core O-6 срез 1 (seed) закрыт решением владельца 05.10.2026: право DIRECTORY_DELETE на КА не расширяется, удаляют алиасы и пустые ГСК/ГСЗ только ADMIN; матрица §10 без изменений
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 по ИНН/имени) реализовано (решение владельца 07.10.2026, RSHB/arm-tabular-parser#9, PR #15, слит с #13): ИНН из конца текста названия контрагента → counterparty_inn, counterparty_name без ИНН (osv_headers.yaml: counterparty_inn_suffix); тесты — tests/unit/parser/test_classify.py (test_inn_is_extracted_from_counterparty_name), синтетика s17_inn_in_name; описание — 05-domain-rules.md §1.3
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); (4) известный обход предсканирования (R-26): лист в части без .xml с ≥ 64 байтами ведущих пробелов и без XML-декларации не попадает в скан (файл 1,8 КБ → 27 с / 1,4 ГБ в openpyxl) — первый follow-up: убрать «sniff» и отдавать expat каждую некаталожную запись; (5) скан сам не ограничен размером чанка: «мусорная» XML-часть с атрибутом в 400 МБ → 1,3 ГБ / 1,2 с, 400 МБ тегов → 8,5 с CPU; (6) xls с очень многими крупными merged-диапазонами (> 10 000 ячеек каждый) — линейный просмотр индекса Sheet (≈ 4,4 мс на обращение), останавливает только PARSE_TIMEOUT_SECONDS: потолок на число таких диапазонов. Предскан — эшелон защиты, не граница безопасности; настоящая граница — лимит памяти контейнера / подпроцесс с RLIMIT. Рекомендация: жёсткий лимит памяти контейнера сервиса; и/или предпроверка объявленного <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 закрыт реализацией Среза 2c (06.10.2026, arm-core/openspec/changes/slice-2c-osv-ingest): ядро ограничивает размер файла на загрузке (UPLOAD_MAX_BYTES = 50 МиБ, как PARSE_MAX_BYTES парсера), поэтому в воркер большие объекты из ядра не попадают; проверка по stat до скачивания в tabular-parser остаётся как есть (дефенсивная, не требуется)
OQ-110 Удаление файла после консолидаций: у document появятся FK из financial_statement_meta, consolidation_document, ex_snapshot_item, а DELETE /files/{id} Среза 2c их не чистит (в 2c строк в этих таблицах нет). ANL-020 запрещает физическое удаление после INITIATED. Что делать: запретить удаление файла, документ которого входит в версию консолидации, и/или каскадно чистить служебные таблицы (financial_statement_meta — в Срезе 3) arm-core Срез 2c: Task 10 (R-23, design №36, №48) Срезы 3, 4 (расширить удаление или запрет) закрыт для Среза 4 (06.10.2026): привязываются к версии только CONFIRMED документы незаменённых файлов, а файл с CONFIRMED документом удалить нельзя (FILE_HAS_CONFIRMED_DOCUMENTS) — удаление файла с документом в версии невозможно, расширять DELETE /files/{id} не нужно; автозамена снимает привязки документов заменённого файла (FILE_REPLACE.unbound_version_ids). Остаток: FK из financial_statement_meta и ex_snapshot_item — Срезы 3 и 7. Уточнено OQ-157: файл с автоподтверждёнными документами удаляется, пока их версии «в работе»; привязки снимаются.
OQ-111 Ретеншн S3-объектов при удалении файла: сейчас DELETE лишь ставит s3_object.expires_at = now(), объекты uploads/results физически не стираются (дополняет OQ-22). Кто и когда их удаляет — lifecycle-правило бакета по метаданным, фоновая задача ядра, ручная очистка? Объект, записанный в S3 до сбоя БД, остаётся сиротой arm-core Срез 2c: design D-10, №36 платформа (lifecycle), Срез 2 → эксплуатация допущение принято: бакет растёт; очистка — вне среза
OQ-112 Остаточные объекты e2e-прогона: каждый запуск make e2e оставляет в MinIO dev-стенда ~2 объекта (uploads/…, results/… — следствие OQ-111) arm-core Срез 2c: Task 11 (O-5) dev-стенд допущение принято: чистить бакет arm-ka вручную (раздел «Сброс стенда» dev/qa-guide.md)
OQ-113 Полнота плана счетов seed: 19 нормализованных кодов строк-счетов golden ОСВ отсутствуют в chart_of_account (01.01, 66.01, 76.01, 60.АВ, 76.ОТ и др.), поэтому у их строк account_id = NULL. Достаточно ли «администратор добавит» или seed должен включать полный набор субсчетов (включая буквенные) до Среза ВГО (§4–§5) arm-core Срез 2c: Task 8 (O-3) Срезы 4–5 (пары счетов элиминации) закрыт: допущение принято — выгрузка плана счетов 1С заказчика (fixtures/directories/chart-of-accounts-1c.xlsx, 488 строк, все 122 кода seed в ней есть) полная (arm-core #25); ранее: частично решён 06.10.2026, перенос в seed — arm-core#23
OQ-114 EntryOut (API строк ОСВ) не отдаёт is_modified/original_*: панели правки подсреза 2d нужен признак правки аналитика (инвариант «первичка не мутируется»: правка — рядом, с аудитом). Добавить поля в схему и контракт API при проектировании 2d arm-core Срез 2c: Task 9 (T9.7) подсрез 2d закрыт решением владельца 07.10.2026 (вариант А, возможен пересмотр): ручной правки строк ОСВ нет — в макете строки ОСВ (xlsx) read-only, ошибка в ОСВ исправляется перезагрузкой файла (автозамена §9.5 п. 3); поля is_modified/original_values/modified_* DBML — резерв, EntryOut не расширяется. Пересмотреть, если качество парсинга или документов потребует правки на месте (RSHB/arm-ka-docs#62)
OQ-115 Автозамена: если новый файл содержит лишь часть документов прежнего (прежний — ОСВ 60 и 51, новый — только 60), прежний уходит в SUPERSEDED целиком, документ 51 пропадает из списка файлов; в FILE_REPLACE.description о нём ничего нет. Подтвердить «замена файлом целиком» (OQ-06) для этого случая или заменять по документам arm-core Срез 2c: Task 8 (T8.4) Срез 2d (список файлов), Срез 4 (комплект документов) допущение принято: замена файлом целиком, документы заменённого файла сохраняются в БД
OQ-116 ОСВ Q2–Q4, признанная нарастающей по данным Q1 (сальдо на начало корня равно сальдо Q1, §1.5), получает предупреждение маппинга и поэтому остаётся NEEDS_CHECK, а не RECOGNIZED (буквально D-7/D-9 спеки: RECOGNIZED только без предупреждений). Верно ли, что аналитик подтверждает такие документы вручную, или нарастающая по данным — штатный случай без предупреждения (OQ-02, OQ-05) arm-core Срез 2c: Task 7 (R-17, design №30) Срез 2d (нагрузка на аналитика), §9.3 допущение принято: NEEDS_CHECK; снять предупреждение — одна правка в result_mapping.py и правило статуса
OQ-117 Индексы osv_entry(parent_entry_id), osv_entry(recognition_job_id), stored_file(current_recognition_job_id): DELETE /files/{id} (и очистка файла при повторном маппинге) делает seq scan на проверке self-FK — на временной таблице 200 тыс. строк удаление документа в 1000 строк 8,6 с без индекса и 16 мс с индексом (замер в psql на временной таблице, final review); при ~3 млн строк DELETE ≈ 2 мин → HTTP-таймаут и долгое удержание блокировок. Требуется DBML v5.16 + миграция 0004. Решает владелец (источник истины — DBML) arm-core Срез 2c: final review (I-1, R-24, design №51) DELETE /files/{id}, повторный маппинг; подсрез 2d (UI удаления), прод закрыт в v5.15 (06.10.2026): индексы добавлены в DBML v5.15 (п. 4 changelog) и миграцию 0003_dbml_v5_15 arm-core — ix_osv_entry_parent_entry_id, ix_osv_entry_recognition_job_id, ix_stored_file_current_recognition_job_id; v5.16 и миграция 0004 не понадобились (v5.15 ещё не слит)
OQ-118 Запрет загрузки и подтверждения документов после перехода версии в DATA_CORRECTION (ТЗ 03_9 A1: «после перехода к исправлению данных загрузка и подтверждение заблокированы»). В Срезе 4 загрузка и подтверждение блокировкой не ограничиваются и в DATA_CORRECTION разрешены решение владельца 06.10.2026; arm-core Срез 4 design D-6 Срез 7 (маршрут) допущение принято: в Срезе 4 запрета нет (только статус «в работе»); запрет вводится вместе с маршрутом
OQ-119 Истечение блокировки «взять в работу»: DBML не задаёт срока, перехват — только вручную с причиной. Нужен ли авто-сброс брошенной блокировки (таймаут, «сессия умерла») arm-core Срез 4 design D-7 Срез 4, 7 (эксплуатация) допущение принято: блокировка не истекает; освободить — DELETE …/lock владельцем или перехват
OQ-120 document.period_check для документов, входящих в версии консолидации: подходящесть документа версии — функция (документ, версия), а один документ может входить в несколько версий (разные периметры и кварталы), поэтому записывать её в document.period_check нельзя. Показывать ли «подходит версиям: …» на карточке файла/документа arm-core Срез 4 design D-12 карточка файла (подсрез 2d), §9.3 допущение принято: period_check остаётся UNKNOWN; подходящесть видна в чек-листе версии
OQ-121 Порог размера сводной ОСВ, после которого нужен кэш процесса: свод строится целиком в памяти на каждый запрос (страница, сводка, экспорт); синтетический тест (5,4 тыс. исходных строк → 1,8 тыс. строк свода) — 0,27 с / 8 запросов; на фикстурах РБ — 1385 строк свода (22 документа). Замер на реальной группе не делался; при десятках тысяч строк может потребоваться кэш (DECISION-5 запрещает кэш в БД) arm-core Срез 4 design D-1, Risks эксплуатация, Срез 5 (шахматка поверх свода) допущение принято: без кэша; замер на реальной группе — до Среза 5
OQ-122 Ячейка чек-листа PROCESSING по всем недостающим столбцам ЮЛ, пока файл не смаплен: до маппинга счёт файла неизвестен, поэтому «в обработке» показывается у всех незакрытых правил ЮЛ. Устраивает ли такая неточность или нужна эвристика по имени файла arm-core Срез 4 design D-13, №6 чек-лист, экраны 34–37 допущение принято: временный шум в чек-листе
OQ-123 Общие строки osv_entry у нескольких версий: документ может входить в несколько версий одной ГК, ручное сопоставление контрагента хранится на строке osv_entry (DECISION-5) и поэтому меняет её для всех версий. Допустимо ли, или сопоставление должно быть «по версии» arm-core Срез 4 design Risks, D-10 Срез 4, 7 (замороженные версии не меняются — они в ex_snapshot) допущение принято: сопоставление общее; before_value аудита хранит прежнее значение
OQ-124 Q1-эквивалентность ОСВ (R-14, design №81): парсер помечает ОСВ за Q1 как нарастающую (период с начала года = Q1), поэтому документ ОСВ за Q1 в Срезе 4 равнозначен и нарастающему, и квартальному и подходит версиям любого квартала года (в версиях Q2+ он — квартальный источник Q1). ББ/ОФР за Q1 версиям Q2–Q4 не подходят (R-14a: баланс на конец Q1). Подтвердить; если ББ/ОФР за Q1 тоже должны подхватываться — снять условие в consolidation_periods.effective_cumulative arm-core Срез 4: Task 13, R-14/R-14a, design №81 fits (привязка), select_sources (свод), чек-лист закрыт 07.10.2026 (владелец): ОСВ за Q1 используется и как нарастающая, и как квартальная (первое звено цепочки для версий Q2–Q4); ББ/ОФР за Q1 — только версии Q1 (R-14a)
OQ-125 Версия за Q1 с квартальным ОСВ Q1: spec говорит «квартальный Q1 равнозначен нарастающему», но по design №50 квартальный Q1 идёт путём склейки (дубли ключа суммируются, None → 0, is_cumulative = false), а нарастающий Q1 отдаётся строка в строку (None сохраняется, дубли остаются раздельными). Различие видно только на дублях ключа и пустых ячейках. Приводить ли обе формы к одной arm-core Срез 4: Task 9 (T9.b), design №50 consolidated_osv.build, версии за Q1 допущение принято: два пути; расхождение — только на дубле ключа внутри квартала и None в ячейках
OQ-126 Область ручного сопоставления контрагента (R-11, design №62/№63): «строка версии» сужена до строк свода — group_type = COUNTERPARTY, data_type BU/SUM привязанных ОСВ-документов; строки NU/ACCOUNT дают 404 NOT_FOUND («строка ОСВ не найдена в версии») и в автоприменение не входят (§3 п. 2, R-3 Среза 2c: НУ не участвует). Цена: NU-строки того же контрагента остаются без counterparty_id. Буквальное чтение spec шире. Подтвердить arm-core Срез 4: Task 11, R-11 counterparty_mapping, автоприменение допущение принято и реализовано
OQ-127 Рекомендация кандидата (recommended) — только точное совпадение normalize_alias имени строки с нормализованным именем/алиасом ЮЛ. На реальных данных «Юг-Финанс / ПЕКАРНЯ СЧАСТЛИВОЧНАЯ» (так записан контрагент в ОСВ РБ) рекомендации не даёт: аналитик находит ЮЛ поиском по q. Нужна ли нечёткая рекомендация (токены, порядок слов, префикс «Юг-Финанс /») или достаточно ручного выбора и накопления алиасов arm-core Срез 4: Task 13 (O-3), design D-11 GET …/counterparty-candidates допущение принято: рекомендация точная; после первого ручного сопоставления алиас закрепляет имя
OQ-128 Неоднозначность дорезолва на лету при тёзке по имени: после ручного сопоставления создаётся алиас, но CounterpartyIndex.resolve на шаге «нормализованное имя/алиас» возвращает контрагента только при единственном кандидате — если ЮЛ-тёзка (по нормализованному name) есть рядом с владельцем нового алиаса, кандидатов двое, резолв неоднозначен и строки без сохранённого counterparty_id остаются несопоставленными. ТЗ DOC-221278: «алиас однозначен» — решает ли это, или алиас должен иметь приоритет над именем arm-core Срез 4: Task 11 (T11.9) дорезолв свода (D-3), CounterpartyIndex закрыт решением владельца 07.10.2026 (вариант Б): совпадение по алиасу приоритетнее совпадения по нормализованному имени — алиас уникален (409 ALIAS_TAKEN), поэтому однозначен; несколько совпадений только по имени → NULL. Правило — 05-domain-rules.md §3 п. 4; реализация — RSHB/arm-core#57
OQ-129 Формулировка сценария «сопоставление и автоприменение» (spec consolidated-osv): «unmapped_total падает на 1 + propagated» неверна на реальных данных. propagated считает записи osv_entry (включая пары-пробелы и строки, не дающие строк свода), а свод склеивает кварталы, поэтому unmapped_total падает на число склеенных строк свода (R-15, design №80). Уточнить текст spec при архивации arm-core Срез 4: Task 13 (T13.M1, R-15) spec consolidated-osv при архивации change допущение принято: тест сверяет обе величины отдельно; текст spec уточнён в change, openspec/specs/ — при архивации
OQ-130 ОСВ произвольного формата: ИНН в ячейке на строку выше названия контрагента (строка только с ИНН, без сумм). Сейчас такая строка уходит в OTHER, ИНН для резолва теряется. Решение владельца 07.10.2026: склеивать со следующей строкой контрагента; синтетические фикстуры на этот случай, на ИНН в тексте и на «ИНН/КПП» в одной ячейке владелец, 07.10.2026 tabular-parser §1.0 п. 4, §1.3; резолв контрагента в ядре реализовано (RSHB/arm-tabular-parser#9, PR #15): строка только с ИНН над названием склеивается со следующей строкой контрагента (inn_only_row, предупреждение «ИНН … над строкой … отнесён к ней»), «ИНН/КПП» в одной ячейке (inn_kpp_cell); тесты — test_classify.py (test_inn_only_row_above_is_glued_to_next_counterparty, test_inn_with_kpp_in_one_column_cell_gives_inn), синтетика s18_inn_row_above, s19_inn_kpp_cell; 05-domain-rules.md §1.3. Правило строки ИНН заменено OQ-163 (13.10.2026).
OQ-131 Скользящий период ОСВ «Октябрь 2024 г. – Сентябрь 2025 г.» (НПЗ 60/62/76, Агрокомплекс 76, osv-dkb/): парсер берёт первый месяц → 2024 Q4, нарастающий. Нужен разбор диапазона дат и признак «не с начала года»; как ядру относиться к такому документу при привязке к версии (не нарастающий и не квартальный) пакет ДКБ 06.10.2026, прогон парсера tabular-parser periods.yaml/header.py; ядро fits (D-5 Среза 4) реализовано в парсере (tabular-parser PR #13 + Срез 2b): диапазон месяцев разбирается (periods.yaml: months, range), границы period_start/period_end/is_from_year_start — в контракте v1.2 (docs change 2b), скользящий период → period_quarter = null, is_cumulative = null и предупреждение «не с начала года» (05-domain-rules.md §1.5). Открыто для ядра: привязка скользящего документа к версии (допущение — не привязывать, показывать в чек-листе как «период не соответствует»)
OQ-132 Тождество сальдо по строкам (§1.4) на счёте 91 (и, вероятно, 90, 99): строки аналитики доходов/расходов несут только обороты, сальдо закрывается на 91.09 → needs_check на каждой ОСВ 91 (Цимлянский, Приманыческий). Исключать ли счета без сальдо по аналитике из проверки тождества строк пакет ДКБ 06.10.2026 tabular-parser checks.py, статус документа закрыт решением владельца 07.10.2026 (вариант Б): счета без сальдо по аналитике исключаются из тождества строк §1.4; список — данные rules/*.yaml tabular-parser, начальный состав 91 и 99 (90 не включать: внутри года у субсчетов 90 сальдо есть); «Итого» и сумма детей = родитель сверяются. Реализация — arm-tabular-parser#11 п. 2
OQ-133 ОСВ варианта 2 без строки корневого счёта: верхний уровень — субсчета (58.01, 58.03), «Итого» = их сумме, парсер сверяет «Итого» с первым корнем → needs_check на каждом листе (Новоросметалл, Агрокомплекс; уточняет OQ-106). Сверять «Итого» с суммой строк уровня 0 пакет ДКБ 06.10.2026 tabular-parser checks.py реализовано (tabular-parser PR #13, arm-tabular-parser#11 п. 3): при нескольких корнях уровня 0 «Итого» сверяется с суммой строк уровня 0 (сальдо по колонкам либо по нетто, как у родителя, R-21); checks.py, 05-domain-rules.md §1.4
OQ-134 Шапка ОСВ без строки организации и с кодом/названием счёта в двух колонках («Счет: Код / Наименование», строка «Бухгалтерский | 9 месяцев 2025 г.»; Новоросметалл ОСВ 63): парсер не находит организацию, счёт, период, тип данных. Новый вариант заголовка — словарь или код пакет ДКБ 06.10.2026 tabular-parser detect.py/header.py, osv_headers.yaml реализовано (tabular-parser PR #13, arm-tabular-parser#11 п. 4): шапка без метки организации (организация — хвост названия ведомости), период и тип данных отдельными ячейками (periods.yaml: standalone, data_types.yaml: standalone_header), подписи «Код»/«Наименование» не группировки (osv_headers.yaml: column_captions), код счёта — из первой строки-счёта (с предупреждением); 05-domain-rules.md §1.1; тест test_header_without_labels_and_code_name_columns_are_found
OQ-135 Отчёт 1С «Анализ счета» с отбором по контрагентам группы (fixtures/analysis-reports/, в именах файлов «ОСВ_…ПоКомпаниямГруппы»): не ОСВ, но содержит ВГО по корреспонденции счетов. Нужен ли отдельный тип документа для Среза 5, или ВГО считаются только из ОСВ пакет ДКБ 06.10.2026 document_type, Срез 5 открыт: допущение — не разбирать; парсер отвечает INVALID_DOCUMENT
OQ-136 ИНН организаций пакета ДКБ (Цимлянский, НКЗ, Новоросметалл, Приманыческий, Агрокомплекс) в шапках ОСВ отсутствуют; для теста консолидации по этим группам нужны ИНН и состав ГК/ГСК (выгрузка ЕЦП или список от ДКБ) пакет ДКБ 06.10.2026 seed/фикстуры справочников, тесты Среза 4–5 на новых группах открыт
OQ-137 Раскладка горячих папок ИС Сканирование: scan-gateway кладёт Input/<job_id>_<original_name> через временный Tmp/.<имя>.part, ничего не удаляет; PDFWorker старого АРМ (RSHB/armka_file_worker, проверен в контуре) кладёт Input/<task_id>.<ext> через временный <назначение>.<uuid>.tmp рядом (ИС игнорирует *.tmp), читает батч Output/<task_id>/*.json и удаляет Output/<task_id>/ и входящий файл после чтения. Какая раскладка актуальна? сравнение armka_file_worker (README «Файлы», clients.py) и scan-gateway/gateway/hotfolder.py, smb.py; OQ-78, OQ-79 scan-gateway (спека image-recognition-gateway, эмулятор, тесты) закрыт владельцем 06.10.2026: «правильно как в FileWorker» — имя <job_id>.<ext>, очистка Output/<job_id>/ и входящего файла после чтения; Output/<job_id>/*.json батчем и стабилизация набора (OQ-78) остаются. Реализация — arm-scan-gateway #6. Уточнение (Срез 3a, решение владельца 06.10.2026): вместо временного *.tmp рядом с назначением — .part в Tmp (в Input временных файлов не класть: ИС может подхватить недописанный файл, гарантии игнора *.tmp у нас нет; OQ-79 остаётся в силе), публикация без замены снимает .part сама; очистка — под флагом SCAN_CLEANUP, по умолчанию выключена (OQ-144) Уточнение 09.10.2026 (решение владельца): .part в Tmp отменён — запись прямо в Input с перезаписью, как в старом АРМ (arm-scan-gateway #26)
OQ-138 Единицы «тыс. руб.» в шапке против значений в рублях с копейками в выгрузках 1С (Унагранде Компани/Групп, НПЗ) и тысяч с дробями (Межениновская): кто и где приводит единицы. Примеры: книга НПЗ (npz/2025-Q3) — ББ needs_check, 1600 = 1700 расходится на 1.94 / 9.02 / 2.48 руб.; ОФР НПЗ и ОФР Унагранде (стр. 1) — needs_check по 2100/2200/2300 по той же причине; полные формы по факту сходятся только у Межениновской fixtures/statements-xlsx/README.md, tabular-parser design 2b D-6, D-7, решения №22–24 (R-11, R-13, R-14) Срез 3 (маппинг форм), §8 (КФО в тыс. руб.) закрыт решением владельца 06.10.2026: единица «тыс. руб.» в шапке считается верной, значения отдаются как в файле; расхождения итогов в пределах округления (до 0,001 % наибольшего числа соотношения) статус не портят — мягкие нарушения «в пределах округления» (arm-tabular-parser#20). Книга НПЗ, ОФР стр. 1 Унагранде — done. Принимать ли расхождение и приводить ли единицы — решает КА в ядре (акцепт проверок, Срез 3). Пересмотрено владельцем 15.10.2026 (AURORA-1528, arm-tabular-parser#42): значение ББ/ОФР из Excel — как его показывает числовой формат ячейки (масштабирующие запятые #,##0, → тысячи, знаки после точки до 2, секции и условия [=0]"-", литералы условных секций как текстовые ячейки, округление половина от нуля, знак от сырого значения); General — как в ячейке; неразобранный формат (%, экспонента, дробь, даты, @) — как в ячейке + предупреждение на документ; xlsb — как в файле + предупреждение; ОСВ не затронута. Решение 06.10.2026 «значения как в файле» заменено
OQ-139 Форма без колонки кодов: сопоставление по именам строк из шаблонов 66н/ФСБУ (словарь statement_lines.yaml, line_code_confidence < 100)? Сейчас документ без строк и needs_check («колонка кодов не найдена») решение владельца 06.10.2026 (вопрос 6), tabular-parser design 2b D-4 §12 п. 2, Срез 3 открыт: нужен реальный файл без колонки кодов; допущение — не сопоставлять по именам; связано (Срез 3a): то же для PDF-пути — справочник кодов по редакциям, имена из OCR при пустой редакции (OQ-146, OQ-150)
OQ-140 Страница-продолжение в отдельном файле (1С печатает ББ/ОФР постранично, один файл = страница): склейка в ядре по ЮЛ + период + тип формы; признак is_continuation / form_page в контракте (MINOR, две необязательных поля) решение владельца 06.10.2026 (вопрос 2), design 2b D-8 §12 п. 9, Срез 3, контракт v1.x допущение принято: страницы разных файлов не склеиваются; страница 2 без шапки — документ с пустой шапкой и needs_check, «загрузите форму одним файлом»; Срез 3b: допущение реализовано — страницы одной формы из разных файлов не склеиваются: каждый файл — отдельный документ со своим периодом.
OQ-141 Строка без кода, но с суммами в ОФР ФСБУ 4/2023 (НПЗ «Реализация иного имущества…»): хранить ли (OQ-36 расширяется с расшифровочных строк на строки с суммами) fixtures/statements-xlsx/npz, design 2b D-6 Срез 3, DBML financial_statement_line (хранит только строки с кодом) допущение принято: строки без кода не отдаются, при наличии сумм — предупреждение «строк без кода с суммами пропущено: N»
OQ-142 Образец ФСБУ 4/2023 (templates/ББ после 01.01.2025.xlsx): «АКТИВ» и код 1110 в одной строке из-за объединённых ячеек; шаблоны (коды есть, сумм и шапки нет) не данные. Нужен ли их разбор вообще fixtures/statements-xlsx/templates, design 2b D-8 §12 п. 10, тесты допущение принято: шаблоны дают needs_check (шапка пустая, значения null); разбор шаблонов как источника данных не планируется, пока владелец не скажет иначе
OQ-143 Лист продолжения с единственной кодовой строкой (книга НПЗ: лист ОФР с одной строкой 2400): min_codes = 3 → лист не распознаётся как форма и пропускается, строка 2400 теряется при needs_check документа. Понизить порог / принимать лист по близости к открытому документу ОФР / маркеру продолжения tabular-parser design 2b: решение №25, O-9 §12 п. 2, п. 9; полнота ОФР НПЗ реализовано в 2b (финальная волна, I-1): лист с 1–2 кодами форм после листа формы берётся как продолжение (min_codes_continuation = 1 в словаре) и присоединяется при совпадении числа колонок сумм и типа формы; не присоединён — needs_check и предупреждение; первая страница с 1–2 кодами формой не считается. Строка 2400 НПЗ в результате есть
OQ-144 Права на удаление на SMB-шаре контура (Input — входящие файлы и .done, Output/<job_id>/, Tmp): можно ли сервису scan-gateway удалять файлы, и не удаляет ли их сама ИС Сканирование после обработки. Пока SCAN_CLEANUP=false — сервис ничего не удаляет (кроме .part, ставшего целью публикации записью без замены), в Input, Output и Tmp накапливаются остатки решение владельца 06.10.2026, change slice-3a-ocr-normalizer D-2, решения №26/№27 scan-gateway (горячие папки), эксплуатация стенда открыт: допущение — очистка выключена; dev-compose включает SCAN_CLEANUP=true. Спросить платформу/владельцев ИС; при положительном ответе — включить флаг на стенде
OQ-145 Редакция формы (66n / fsbu4) в контракте: нужна ли ядру редакция документа в конверте (необязательное поле statementDocument, кандидат MINOR 1.3), или ядро выбирает редакцию по report_date само, по тому же правилу §11.1 п. 10. Сейчас scan-gateway выбирает редакцию внутри и наружу её не отдаёт change slice-3a-ocr-normalizer, открытый вопрос 2 контракт docs/contracts/ (v1.3), Срез 3b (маппинг форм, справочник кодов в ядре) закрыт решением владельца 07.10.2026: редакция формы в контракт не добавляется (контракт v1.2); ядро определяет её по дате периода документа (66n при дате ≤ 2024-12-31, иначе fsbu4) и отдаёт в GET /documents/{id}/statement (edition), как реализовано в Срезе 3b. Досрочное применение ФСБУ 4/2023 до 2025 года — новый OQ при первом реальном случае
OQ-146 Словари §7 (проверки форм) и §12 (справочник кодов statement_lines.yaml, формулы ОФР) по редакциям 66н / ФСБУ 4/2023 для tabular-parser (2b) и ядра (3b): один набор правил на обе редакции или раздельные; как выбирать редакцию в ядре для Excel-пути change slice-3a-ocr-normalizer (справочник с редакциями только в scan-gateway), OQ-12, OQ-139 tabular-parser rules/*.yaml, ядро (Срез 3b), §7, §12 п. 2 открыт, решение владельца 07.10.2026: решается вместе с OQ-150 (состав редакции fsbu4); до тех пор допущение прежнее — scan-gateway ведёт свой api/rules/statement_lines.yaml, tabular-parser и ядро словарь по редакциям не используют, формулы §7 одни на обе редакции; расширяет OQ-12 и OQ-139
OQ-147 Закрывающая скобка, распознанная OCR как } или ] ((7744536} в aep_3.json): дословный перенос parse_amount минус не ставит — сумма положительная, is_recognized = false. Расширить ли множество закрывающих скобок в §11.1 п. 7 после проверки на стенде change slice-3a-ocr-normalizer, решение №12; владелец 06.10.2026: «пока устроит как есть» scan-gateway normalizer/ocr/amounts.py, §11.1 п. 7 открыт: допущение — перенос дословный; знак теряется, строка подсвечена is_recognized = false, исходный текст — в raw/
OQ-148 Длинное/среднее тире «—»/«–» как прочерк: дословный parse_amount вырезает тире как «лишний» символ → сумма null, но is_recognized = false даже при confidence = 100 (дефис «-» даёт true). Лишний needs_check на формах с длинным тире. Считать ли прочерк любого вида распознанным change slice-3a-ocr-normalizer, решение №20 scan-gateway amounts.py, §11.1 п. 7, доля done на реальных сканах открыт: допущение — перенос дословный; правило уточняется после прогона на стенде
OQ-149 Строки таблицы OCR, отброшенные классификацией (поведение источника, §11.1 п. 4), не восстанавливаются: с непустым нечисловым кодом (1150 :) и с пустым кодом, но с суммами (в aep_3.json — «БАЛАНС» и «Выручка»: код пуст, мусор 211(1 | стоит в колонке значения). Нормализатор выдаёт предупреждения строк с нечисловым кодом пропущено: N и строк без кода с суммами пропущено: N (как OQ-141 для Excel), документ — needs_check, содержимое строк остаётся в raw/. Восстанавливать ли такие строки по наименованию (словарь редакции) или по структуре формы fixtures/ocr/aep_3.json, aep_6.json, change slice-3a-ocr-normalizer, решение №29, §11.1 п. 4 scan-gateway rows.py/document.py, полнота форм, OQ-36, OQ-139, OQ-141 открыт: допущение — строки пропускаются с предупреждением; аналитик видит расхождение итогов в проверках 3b
OQ-150 Состав редакции fsbu4 (ФСБУ 4/2023, отчётность с 2025 года) в api/rules/statement_lines.yaml scan-gateway: коды и наименования строк ББ и ОФР; источник — Приложения 3–4 к ФСБУ 4/2023 (черновой перечень кодов — шаблоны fixtures/statements-xlsx/templates/, OQ-142). Пока lines: {} change slice-3a-ocr-normalizer, D-7 scan-gateway api/rules/, эталоны fixtures/ocr/expected_normalize/ для документов 2025 года, статус done открыт: данные даёт владелец, код нормализатора не меняется; до заполнения документы 2025 года идут с именами из OCR, предупреждением «редакция fsbu4 не заполнена» и needs_check. Порядок заполнения — scan-gateway/README.md 09.10.2026, решение владельца: состав fsbu4 (и 66n) для ядра принят из шаблонов банка — arm-core/api/rules/statement_lines.yaml (arm-core#80); словарь scan-gateway — follow-up, копии расходятся (66н scan-gateway — словарь старого ядра).
OQ-151 Эмулятор ИС Сканирование: файл, совпавший по sha256 с PDF из SCAN_FIXTURES_DIR, у которого нет JSON-набора (<имя>.json), отвечает «нет пары» (INVALID_DOCUMENT) и не уходит на SCAN_EMULATOR_DEFAULT. Пробел спеки эмулятора: считать ли такой файл промахом и отдавать набор по умолчанию change slice-3a-ocr-normalizer, спека scan-emulator scan-gateway scan_emulator, dev-стенд (dev/qa-guide.md §6) открыт: допущение — поведение как есть; PDF без JSON-пары в fixtures/ocr не класть
OQ-152 Повтор кода строки в таблице OCR: остаётся первая строка (паритет с Excel-путём, §12 п. 5; решение №15), но в aep_6.json (ОФР) код 2410 повторён, оставленная первая строка пуста, а отброшенная содержит (649). Выбрать правило «первая строка с суммой» вместо «первая» (для aep_3 оно даёт иной результат, чем для aep_6 — нужна проверка на стенде) change slice-3a-ocr-normalizer, решение №34 (R-16), финальное ревью I-2 scan-gateway document.py, §11.1 п. 4, Excel-путь §12 п. 5 открыт: допущение — первая строка; предупреждение «код N повторяется» сигнализирует аналитику, сумма отброшенной строки остаётся в raw/
OQ-153 Журналировать ли скачивание первички (GET /files/{id}/content) и CSV чек-листа (ТЗ 8.2: перечень событий журнала включает «выгрузку»)? Экспорт сводной ОСВ в xlsx пишет audit_event(EXPORT) (Срез 4), а скачивание исходного файла и CSV чек-листа в Срезе 3b — нет; комментарии к документу тоже не аудируются (comment хранит автора и время) change slice-3b-statements-api, design D-10, D-11, D-13, решение №8; ТЗ 8.2 audit_event, GET /files/{id}/content, GET …/checklist?format=csv, §9.5 п. 6 закрыт решением владельца 07.10.2026 (вариант А): скачивание исходного файла (GET /files/{id}/content, это же и просмотр PDF) и CSV чек-листа в audit_event не пишутся; EXPORT пишет только экспорт сводной ОСВ в xlsx (Срез 4)
OQ-154 Автозамена файла работает на уровне файла (ключ документа: тип, счёт/NULL, год, квартал, нарастающий): исправленный отдельный ОФР заменит весь прежний файл-книгу «ББ + ОФР» того же периода (SUPERSEDED), а подтверждённый ББ из неё отвяжется от версий «в работе». Допустима ли такая замена на уровне файла, или формы одного периода нужно заменять по документам финальное ревью Среза 3b (заметка контроллера), change slice-3b-statements-api Срез 3b / 5 закрыт решением владельца 07.10.2026 (вариант А): замена остаётся на уровне файла (DBML file_status.SUPERSEDED, ТЗ 8.2); если у заменённого файла есть документы, ключа которых нет в новом, — предупреждение в metrics.mapping_warnings нового файла (какие документы выпали, был ли CONFIRMED, из каких версий сняты привязки). Правило — 05-domain-rules.md §9.5 п. 3; реализация — RSHB/arm-core#58
OQ-155 Эталонная ручная консолидация (fixtures/golden/Консолидация_Группа РБ.xlsx, лист 01.10.2024, «в т. ч. взаимные обязательства») элиминирует у каждой компании полную сумму её строк на компании группы (Счастливочная 1230 = 108 062 тыс. = 62.01 «БП Производство» 106 311 116,46 + 62.01 «БП Аренда» 1 401 330 + 76.06 350 000; РБ 1520 = 106 311 тыс.), а ТЗ (DOC-223044, §4–§5) — по парам с min и порогом 5 %. Какой алгоритм верен разбор OQ перед Срезом 5 (08.10.2026), сверка эталона с golden ОСВ РБ/Счастливочной Q3 2024 Срез 5 (матчинг §5, тест сверки с эталоном), Срез 6 (КФО) закрыт решением владельца 08.10.2026: алгоритм ТЗ — пары, min, порог 5 % (§4–§5); эталон сверяется только по точным парам (106 311 116,46 по правилу № 6), асимметрия эталона (1 751 тыс. у Счастливочной) — ожидаемое расхождение, описывается в тесте. Связано: OQ-07 (строго 1:1 или гибрид — ждёт владельца), OQ-08
OQ-156 Ответ ИС Сканирование склеивает соседние строки формы в одну: код 1500\n1700, наименование Итого по разделу V\n\nБАЛАНС, суммы 917 775\n2 371 333 (ББ РБ и Счастливочной за 1 кв. 2025, fixtures/ocr/Бухгалтерская отчетность 1 кв.25.json, БО 1 кв 2025.json). Нормализатор отбрасывал строку как нечисловой код — в документе не было 1500 и 1700 прогон 1 кв. 2025 на реальных ответах ИС (arm-ka-fixtures#16) scan-gateway rows.py, §11.1 п. 4 решено (владелец 08.10.2026): разлеплять, если в каждой непустой ячейке значений столько же частей, сколько кодов; иначе — как раньше; предупреждение «строк с несколькими кодами разлеплено: N», needs_check; реализация — RSHB/arm-scan-gateway#16
OQ-157 Чистый документ (без замечаний) требовал ручного «Подтвердить» (RECOGNIZED → CONFIRMED), хотя строки ОСВ не правятся (OQ-114) и ТЗ 03_9 п. 4 / 10_10 даёт «Загружен» сразу при отсутствии замечаний; на комплекте 1 кв. 2025 — 16 пустых кликов прогон владельца 08.10.2026 arm-core services/auto_confirm.py, result_mapping, primary_files.delete; §9.3, §9.5 п. 4–5 решено (владелец 08.10.2026): чистый документ при маппинге сразу CONFIRMED системой (confirmed_by NULL), переход версии — от загрузившего; удаление автоподтверждённого файла — пока версии «в работе»; RSHB/arm-core#64, change auto-confirm-clean-documents
OQ-158 В «Осталось N» (строки свода без ЮЛ и без ИНН) попадают строки аналитики, которые не являются контрагентами-организациями: «Ведомость в счет з/платы», подотчётные лица, физлица и т. п. — на РБ 2025 К1 таких большинство из 1291 строки без ИНН, и довести баннер до нуля сопоставлением с ЮЛ нельзя. Нужно ли отличать такие строки (признак «не организация» вручную / по словарю / по счёту) и исключать их из «Осталось N» и предупреждения [31-00] жалоба владельца на «Указать» в сводной ОСВ (08.10.2026), RSHB/arm-core#74 arm-core domain/consolidated_osv.needs_mapping, §3, экраны [30], [32-osv-no-inn], [31-00] открыт: до решения такие строки считаются несопоставленными (EXTERNAL), переход к следующему шагу ими не блокируется — блокировки в API нет
OQ-159 Note DBML recognition_job.reply_deadline «таймаут ожидания (OCR — 5 мин)» расходится с решением владельца 09.10.2026: срок ответа OCR — 20 мин (DEFAULT_REPLY_TIMEOUT в arm-core, SCAN_TIMEOUT_SECONDS=1200 в scan-gateway). Поправить note при следующей версии DBML решение владельца 09.10.2026 (не выпускать версию DBML ради note); arm-core #87, arm-scan-gateway #26, arm-ka-docs #84 DBML recognition_job, 05-domain-rules.md §9.4 закрыт 09.10.2026: note исправлен в DBML v5.18 (docs #90)
OQ-160 Целевая модель версий консолидации (владелец, 09.10.2026): несколько рабочих версий одного периода с разным периметром делят первичку (рабочий стол консоли, stored_file.consolidation_id); после VERIFIED новая версия (previous_version_id) может менять документы при том же периметре. Ядро сейчас создаёт только версию 1 (POST /consolidations), «новая версия» и параллельные версии не реализованы. Нужны правила: создание второй рабочей версии (обязательно другой периметр?), создание версии после VERIFIED (копия периметра, подхват привязок), что видит панель [39] у верифицированной версии до Среза 7 (ЕХ) brainstorming docs #90, openspec/changes/console-files/design.md R-6, R-7 срез «версии консолидации» (после Среза 4), Срез 7 открыт: модель файлов совместима; реализация — отдельный срез
OQ-161 Документ, период которого не совпадает с периодом консолидации, молча не привязывается к версии: ручное подтверждение проходит (200), а fits (period_year = год версии, D-5 Среза 4) его отбрасывает, period_check остаётся UNKNOWN (OQ-120) — свод пуст без объяснения (владелец 12.10.2026: ОСВ за 1 кв. 2025 в консолидации 2026 Q1). Период ОСВ берётся из шапки и через API не правится. Нужно ли (1) предупреждение «документ не подходит ни одной версии» при загрузке или подтверждении, (2) правка периода документа аналитиком (рядом с первичкой, как original_*), (3) постоянный режим «период из консолидации» для файлов, загруженных в неё разбор владельца 12.10.2026; RSHB/arm-core#103 fits, свод, чек-лист (§2, §9.3), карточка документа временное допущение (решение владельца 12.10.2026): настройка CONSOLIDATION_PERIOD_FROM_VERSION (по умолчанию false; в контуре — OPENBAO__APP__CONSOLIDATION_PERIOD_FROM_VERSION) — ОСВ, загруженная в консолидацию (stored_file.consolidation_id) и не подходящая ей по периоду шапки, считается нарастающей за год и квартал консолидации для привязки, свода, чек-листа и колонки «ОСВ»; документ не меняется; ББ/ОФР и файлы с рабочего стола — по шапке; склейки кварталов нет (один слот на счёт ЮЛ). Только для тестов; открыт выбор постоянного решения (1)–(3), после него режим снять
OQ-162 ОСВ 1С, шапка варианта 2 «Детализация по субсчетам, субконто: Контрагенты, Контрагенты.ИНН» (ООО «Зерновая компания „Новопетровская“», ОСВ 60 за 9 мес. 2025, замечание банка 13.10.2026): ИНН выводится отдельной строкой под контрагентом (уровень глубже, те же суммы, ИНН числом). Парсер принимал «Контрагенты.ИНН» за второй уровень контрагентов: в «Контрагент / аналитика» — 2370012036.0, наименования нет, ИНН у строк null → нет признака ГК/ГСК/Внешний, суммы контрагента в своде дважды замечание банка 13.10.2026; RSHB/arm-tabular-parser#32 tabular-parser §1.1, §1.3; свод и резолв контрагента в ядре решено владельцем 13.10.2026: <группировка>.ИНН — реквизит, не уровень; строка ИНН склеивается с родительским контрагентом (ИНН — родителю, строка из rows убирается, дети — к контрагенту), только если она единственная у родителя и суммы равны; иначе строка OTHER и needs_check; пустая ячейка ИНН (физлицо) — склейка без ИНН (рулинг R-1); целое число из ячейки xls — без «.0». 05-domain-rules.md §1.1, §1.3; реализовано RSHB/arm-tabular-parser#32 (713 из 716 контрагентов файла получили ИНН, 3 физлица без ИНН). Правило строки ИНН заменено OQ-163 (13.10.2026).
OQ-163 ОСВ, где ИНН контрагента выведен отдельной строкой рядом с наименованием, в любой раскладке: над / под × в дереве / не в дереве × с суммами / без (требование владельца 13.10.2026). До решения парсер склеивал только «над, не в дереве, без сумм» (OQ-130) и «под, в дереве» при подсказке «Контрагенты.ИНН» (OQ-162); «под, не в дереве, без сумм» отдавал ИНН следующему контрагенту владелец, 13.10.2026; RSHB/arm-tabular-parser#35, #34 tabular-parser §1.1, §1.3 решено владельцем 13.10.2026: без подсказки в шапке строка ИНН — только с верной контрольной суммой ИНН (во всех раскладках, включая OQ-130); с подсказкой — без проверки, порядок элементов задаёт направление; «над, в дереве» — только единственный ребёнок; соседи — по суммам, без сумм — по направлению листа (шапка → пары по суммам → однозначные блоки); неоднозначное — строка OTHER, needs_check; ведущий ноль числовой строки ИНН (#34). Уточнения владельца (H-1): строка из 10/12 цифр с неверной контрольной суммой не склеивается, остаётся обычной строкой, предупреждение «похожа на ИНН …», needs_check (синтетика s28); (H-2): если пара найдена, но раскладка противоречит направлению подсказки <группировка>.ИНН, строка склеивается, но выдаётся отдельное предупреждение «стоит под/над наименованием … а шапка указывает над/под — проверьте» и needs_check. 05-domain-rules.md §1.3; реализовано RSHB/arm-tabular-parser#35

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