Вопросы из open-questions-proposal.md трёх сервисов (с дедупликацией), кандидаты DBML v5.14 (только как строки реестра) и находки сквозной проверки окружения. У каждой строки — репозиторий и маркер источника. OQ-45/46/47 переведены в «допущение принято и применено» с фактами seed и ORM. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
95 lines
50 KiB
Markdown
95 lines
50 KiB
Markdown
# 07. Открытые вопросы (реестр)
|
||
|
||
Правило: агент **не закрывает** вопросы сам. Если решение нужно для текущего среза — делает явное допущение, помечает его
|
||
в коде `# ASSUMPTION(OQ-nn)` и в OpenSpec-change, и переносит вопрос в статус «допущение принято». Пользователь закрывает
|
||
вопросы с аналитиками/методологами и обновляет этот файл.
|
||
|
||
| ID | Вопрос | Откуда | Влияет на | Статус / допущение |
|
||
|---|---|---|---|---|
|
||
| OQ-01 | Хранить ли все строки ОСВ или только контрагентские; нужен ли `parent_entry_id` (замечание 2 ревью v5.13) | DBML, «Парсинг ОСВ» п. 11 | срез 2 (парсер, `osv_entry`) | допущение: хранить все строки + `level` + `parent_entry_id`; строку «Итого» не хранить, использовать для сверки |
|
||
| 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) | допущение: нормализовать в 0–100 по фактическим файлам |
|
||
| OQ-14 | `reporting_date` в JSON ИС Сканирование — «ждём обновлённый JSON» | FNR01 | срез 3 | допущение: парсить из заголовка «на 30 сентября 2025 г.» |
|
||
| 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) | миграции, права БД; платформа | вопрос: допущение принято на Срез 0 — только код и тесты; решение по триггеру/правам — с командой платформы до прода |
|
||
| 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 (`task-4-report.md`) | срез 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 (`task-3-report.md`, `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 (`task-4-report.md`) | срез 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 (`task-4-report.md`, сквозная проверка) | срез 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 (= O-1 `task-5-report.md`), 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) |
|
||
| 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 (= O-2 `task-5-report.md`), 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 (= O-3 `task-5-report.md`), 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 (`task-4-report.md`), design #31 | срез 3 (OQ-13/14, нормализатор); fixtures | вопрос: допущение принято на Срез 0 — успех проверяется синтетическим ответом, `NullNormalizer` пропускает ошибку ИС; образцы запросить у владельцев ИС Сканирование |
|
||
| 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 (нормализатор) | вопрос: допущение принято на Срез 0 — формат не интерпретируется; решение нужно до нормализатора Среза 3 |
|
||
| OQ-78 | Шлюз читает ровно `<output>/<job_id>/<job_id>.json` (спека); старый код читал все файлы каталога `Output/<id>/`. Какие файлы и когда реальная ИС кладёт в `Output`, в каком порядке (момент готовности)? | scan-gateway: п. 5 таблицы предложений (T8.5) | срез 3 (стенд ИС) | вопрос: допущение принято на Срез 0 — имя ответа по спеке; проверить на стенде ИС |
|
||
| OQ-79 | Временный файл `.<имя>.part` лежит в `Input` (атомарная запись `.part` + rename): реальная ИС без маски может забрать недописанный файл. Уточнить у владельцев ИС маску и поведение или перенести временный файл в служебный подкаталог рядом с `Input`? | scan-gateway: п. 6 таблицы предложений (R-5, T7/T8) | срез 3 (стенд ИС) | вопрос: допущение принято на Срез 0 — `.part` + rename в `Input`; вариант с подкаталогом `Input/.tmp` или корнем — после ответа владельцев ИС |
|
||
| 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 (`task-1-report.md`), O-4 и O-5 (`task-2-report.md`), `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 (`task-1-report.md`), `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 (`task-3-report.md`) | срез 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 (`task-3-report.md`; подтверждено ревью для tabular-parser и scan-gateway), `dev/README.md` | срез 0 (процесс), интеграционные тесты | допущение принято: в `dev/README.md` предупреждение и команда `stop` для контейнеров профиля; не гонять `make test-integration` двух сервисов одновременно |
|
||
|
||
Служебные идентификаторы в DBML/аналитике: `ANL-nnn` — замечания аналитика к макету; `ARCH-nnn` — архитектурные решения;
|
||
`DECISION-n` — решения по модели; `FIX-nn` — исправления дефектов v4.
|