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