20 KiB
Проверка членства в СРО: эксплуатация
Источник sro_membership_check, группа/тип sro_membership, карточка
sro-membership-check. Upstream — сайт reestr-sro.ru; внутренний справочник
организаций используется для точной привязки UID и ОКПО. Другие внешние реестры
загрузчик не опрашивает.
Доступ и пределы запросов
По умолчанию сбор закрыт. Для production необходимы одновременно
SRO_UPSTREAM_ACCESS_APPROVED=true и непустой
SRO_UPSTREAM_APPROVAL_REFERENCE — ссылка/номер документированного разрешения
владельца сайта на автоматизированные query/search запросы. Согласование разработки
внутри проекта не заменяет разрешение владельца upstream. Условия разрешения
должны быть совместимы с настройками загрузчика; более строгие пределы задаются
перед включением. Секреты в approval reference хранить нельзя.
15.09.2026 пользователь явно изменил требование: «Изменить требование и включить
сбор на dev». Только для dev предусмотрен отдельный opt-in
SRO_DEV_COLLECTION_ENABLED=true. Он разрешает сбор без изменения
SRO_UPSTREAM_ACCESS_APPROVED и SRO_UPSTREAM_APPROVAL_REFERENCE и не обозначает
разрешение владельца upstream. По умолчанию флаг false; на production он должен
оставаться выключенным. Код разрешает запуск при включённом dev-флаге или при
наличии обоих параметров согласованного доступа. Для отключения dev-исключения
верните флаг в false и примените конфигурацию web/worker.
Исходный source-first контракт
с ограничением production refresh и
документ замечаний
с исходным ответом 409 сохранены как происхождение требования. Настоящее
изменение относится только к включению сбора на dev; ограничения запросов,
привязки организаций и публикации данных сохраняются.
Оба ручных entrypoint проверяют этот gate до enqueue; task и HTTP клиент повторяют
проверку перед внешним IO. Закрытый gate возвращает typed
409 upstream_access_not_approved. Если gate закрыт после постановки,
job завершается с ошибкой, без успешной пустой публикации.
| Настройка | По умолчанию | Значение |
|---|---|---|
SRO_DEV_COLLECTION_ENABLED |
false |
Явное включение сбора только на dev, отдельно от подтверждения разрешения upstream. |
SRO_REQUEST_INTERVAL_SECONDS |
3 |
Минимум 3 секунды между запросами, включая redirects/retries; можно увеличить. |
SRO_HTTP_MAX_RESPONSE_BYTES |
2097152 |
Предел распакованного тела одного ответа. |
SRO_HTTP_TIMEOUT_SECONDS |
30 |
Read timeout; connect timeout 10 секунд. |
SRO_MAX_REQUESTS_PER_RUN |
10000 |
Общий предел запросов одного запуска, включая redirects/retries/sitemaps. |
HTTP клиент делает не более трёх попыток при транспортной ошибке и ответах
429/500/502/503/504. Retry-After учитывается как секунды или HTTP date, ожидание
свыше 300 секунд завершает запуск ошибкой. Цепочка redirects ограничена пятью
ответами; каждый адрес проверяется до обращения. Разрешён только HTTPS без
credentials/нестандартного порта, на reestr-sro.ru и его поддоменах. Переменные
окружения HTTP proxy автоматически не используются. HTML/query с идентификаторами
не выводится в application logs. User-Agent — нейтральный
Mostovik SRO integration, без утверждения о разрешении upstream.
Наблюдаемый 15.09.2026 ответ lookup 404 учитывается как отсутствие членства
только для /proverka_dopuska/ с одним q из 10 или 13 цифр, при точном title
«Проверка членства в реестре СРО, проверить допуск организации в СРО по ИНН»,
единственном h1 «Запрашиваемая страница на сайте отсутствует.» и отсутствии
table.sro-members. Конечный q после redirects должен совпадать с запрошенным
идентификатором организации; иначе запуск отклоняется с
sro_lookup_identifier_mismatch. Другой HTML при lookup 404 отклоняется с
sro_lookup_response_unrecognized. На остальных путях 404 сохраняет прежнее
значение sro_page_not_found, в том числе на страницах даты допуска.
Этот шаблон 404 неоднозначен: он сам по себе не доказывает отсутствие членства.
Поэтому если все кандидаты получили такой ответ и ни один lookup не вернул
успешно разобранный 200, весь запуск отклоняется с sro_ambiguous_empty_scan
до публикации и изменения checkpoints; прежние записи сохраняются. Смешанный
запуск с корректным 200 может учитывать распознанные отрицательные ответы.
Приватный raw manifest сохраняет status_code; artifact metadata содержит
recognized_lookup_404_count и successful_lookup_200_count. Предел размера
ответа действует и для lookup 404. Дата реестра из error-шаблона не извлекается.
Публикация и обновление
Celery task: parsers.sro_membership_check.refresh;
Python entrypoint: apps.parsers.tasks_registry_snapshots.parse_sro_membership,
keyword args requested_by_id=None, mode="incremental"|"full".
Проверяются только организации текущего канонического справочника. Инкрементальный
запуск выбирает новые организации и те, у которых изменились name/full_name,
ИНН/ОГРН/ОКПО. Изменение определяется fingerprint; у модели Organization нет
универсального updated_at. Полный запуск проверяет весь справочник.
Lookup использует точный ОГРН, при его отсутствии/неподходящем формате — ИНН
с проверкой нормализованного имени. Если нет пригодного идентификатора, запуск
отклоняется с sro_candidate_identifier_missing, без удаления прежних записей.
Ответ дополнительно сопоставляется по ИНН+ОГРН через внутренний индекс. Отсутствие
ОКПО, конфликт идентификаторов, неоднозначная организация, неизвестный статус,
неполные обязательные поля или missing/unsafe SRO URL отправляют строку в quarantine.
Новые организации из внешнего ответа не создаются.
Одна запись соответствует паре canonical organization UID + SRO ID. Record UID
стабилен между загрузками, включая переход active → excluded. SRO ID/URL
берётся из same-site ссылки или точного ID, разрешённого по same-site sitemap;
по одному похожему названию URL не угадывается. Для даты допуска читается same-site
страница members по ИНН. Неизвестная дата остаётся null с причиной
not_found, sro_page_unresolved или parse_error. Наблюдаемая дата реестра
не подменяется датой загрузки.
Raw ответы сохраняются в приватном ZIP artifact с manifest URL→файл; отдельные
staged rows содержат source fields, нормализованный payload и причину quarantine.
Для SRO используется отдельный FileSystemStorage: PARSER_PRIVATE_ARTIFACT_ROOT
по умолчанию равен <repository-root>/private-parser-artifacts, вне MEDIA_ROOT.
Путь обязан быть абсолютным и не находиться внутри MEDIA_ROOT, в том числе после
разрешения symlink. Ошибка конфигурации запрещает файловую операцию. Приватный storage
не выдаёт публичный URL; файлы создаются с правами 0600, каталоги 0700.
Остальные источники сохраняют прежний default_storage.
В контейнерном окружении задайте PARSER_PRIVATE_ARTIFACT_ROOT=/app/private-parser-artifacts
и подключите к web/worker один постоянный volume по этому пути. Каталог должен быть
доступен пользователю приложения для записи и не должен монтироваться в public media,
static или reverse-proxy document root. Существующая retention-команда удаляет private
файлы через тот же artifact.file.delete(); удаление/пересоздание контейнера не должно
удалять volume. Миграция 0037 меняет storage в состоянии модели без перемещения данных.
До этой версии живой SRO сбор не запускался. Если оператор ранее создал SRO artifacts
в старом MEDIA_ROOT вручную, их требуется отдельно перенести в private root с сохранением
относительных имён и убрать публичные копии до открытия источника; автоматического
fallback на public raw нет.
Публикация записей, checkpoint организаций, load log и terminal job выполняется в одной транзакции после завершения сбора всех кандидатов. Transport/schema failure, нарушение целостности или отменённая job откатывает публикацию и checkpoints целиком. Незавершённый batch остаётся диагностическим и не становится current snapshot.
Завершённый сбор может закончиться success с quarantine, как в примере истории
исходного контракта. Валидные строки публикуются, включая валидные членства организации,
у которой другая строка оказалась некорректной. Неизвестный статус, отсутствующий
SRO ID или URL, конфликт идентификаторов не исправляются догадками: исходная строка
остаётся в quarantine с причиной. У таких организаций прежние членства, не обновлённые
валидной строкой этого batch, сохраняются с прежними UID, payload и load batch.
Ошибка в строке не доказывает прекращение других членств. Для полностью проверенных
организаций исчезнувшие членства удаляются; допустимый пустой ответ удаляет их все.
При incremental неизменённые, не опрошенные организации также сохраняются.
Checkpoint полностью проверенной организации обновляется. У организации с quarantine
прежний checkpoint удаляется в той же транзакции, чтобы следующий incremental повторил
lookup даже при неизменившемся fingerprint. Raw artifact и staged audit сохраняются.
Если нет ни одной валидной строки и ни одного подтверждённого пустого lookup 200,
quarantine отклоняет запуск с sro_incomplete_membership_scan; смесь invalid rows
и неоднозначных 404 не считается подтверждённым отсутствием. Для полностью состоящего
из 404 запуска сохраняется отдельный sro_ambiguous_empty_scan. В обоих случаях
прежние записи и checkpoints остаются без изменений.
Если incremental не нашёл изменившихся организаций, batch имеет нулевую дельту
и наследует source registry date/version последней успешной публикации; ссылка
на неё сохраняется в metadata.base_snapshot_artifact_id. Данные не переписываются.
После commit безопасно ставится существующая задача обновления общих export artifacts. Ошибка брокера после commit не превращает успешную публикацию в failure; готовность выгрузки отражает собственный контракт export service.
Счётчики и диагностика
artifact.published_count, result.published_records_count и load_log.records_count
содержат размер текущего опубликованного набора источника. Для incremental это
общий результат, включая неизменённые организации. metadata.snapshot_records_count
и snapshot_organizations_count дают такие же общие record/distinct organization
counts; batch_published_records_count и updated_records_count — число опубликованных
строк текущей дельты. При full с quarantine общий count также включает сохранённые
старые членства. retained_records_count — число старых строк организаций с quarantine,
которые не были обновлены валидным upsert и сохранены от удаления;
quarantined_organizations_count — число организаций хотя бы с одной строкой quarantine;
completed_organizations_count — число полностью проверенных организаций без quarantine,
включая допустимые пустые результаты. Эти три поля доступны в metadata API.
В приватном artifact confirmed_empty_lookup_200_count отдельно фиксирует подтверждённые
пустые 200 для проверки допустимости публикации. parsed_count, quarantine и
candidate/queried counts относятся к текущей проверке; складывать их с общим published
count нельзя. Новая дата публикации не изменяет прежнюю lineage сохранённых записей.
Источник публикует весь собственный справочник; карточка/list/dashboard для трёх
новых источников используют весь published scope. Coverage ОПК показывается
отдельно. МСП и бюджет продолжают полную замену: новый scoped аргумент публикации
по умолчанию None сохраняет их поведение.
Для расследования используют job status/error, artifact status,
metadata.rejection_reason, rejection_reasons и staged disposition/reason.
Они содержат ограниченные коды ошибок, не raw HTML. Partial raw ZIP сохраняется
при ошибке уже начатого сбора; предыдущая публикация остаётся доступна.
Приватные raw artifacts удерживаются минимум 90 дней и минимум 10 последних
успешных SRO batches; неуспешные batches не вытесняют эти десять успешных.
Расписания и граница проверки
Миграция parsers.0036_sro_disabled_schedules создаёт выключенные schedules:
daily incremental в 04:00 Europe/Moscow; monthly full 16-го числа в 04:00
Europe/Moscow — после наблюдаемого обновления реестра 15-го. Перед включением
нужно подтвердить фактическую периодичность/условия разрешения. Расписание само
не открывает gate; оба механизма по умолчанию выключены.
На 14.09.2026 query/search и живой SRO snapshot не запускались. Основная страница
без query доступна через read-only web; свежий robots.txt получить не удалось.
Указанные в source-first спецификации Crawl-delay: 3 и query/search disallow
учтены консервативно. DOM selector/mapping проверены синтетическими fixtures формы
из docs/source-integration/sources/sro-membership-check/backend-api.md, а не
полным live scan. После разрешения владельца обязательна ограниченная проверка
фактической разметки перед первой полной загрузкой.