Разбор
Замер от: 2026-08-14 · чем проверено: ZAMER-KARTY-BLOKOV-2026-08-14.md, ZAMER-BAZY-2026-08-14.md, прогон проверок разбора — 25 passed, 0 skipped Для кого: кто добавляет целевую таблицу приёма, меняет развёртку (explode) или чинит «ответ получен, а строк нет». Читать до первой правки в
spec_runtime/.
Что делает
Превращает ответ площадки в строки целевых таблиц gwptd_intake. В действующем контуре это часть СБОРА: внутри цикла после fetch() сырой ответ сохраняется через save_raw_payload, затем тот же процесс вызывает _buffer_row и _write_legacy (marketplace-collector-v3/collectors/base.py, строки 789–813). Отдельная пара next_raw_collector.py (неизменяемый захват в gwptd_raw) + next_parser.py (новое поколение разбора из запечатанного захвата) написана, но в расписании отсутствует: if grep -qE 'next_raw_collector|next_parser' marketplace-collector-v3/scripts/crontab.s3-next.txt; then echo 'найдено'; else echo 0; fi → 0. Поэтому правка только next_parser.py боевой разбор не изменит: сейчас нужно проверять parse_and_store из spec_runtime/parsed_runner.py и описания, которые компилирует spec_runtime/product_spec.py. В двухпроходном контуре разбор можно повторить без нового обращения к площадке; действующий контур этого отдельного шага не запускает.
Точка входа в код
marketplace-collector-v3/collectors/base.py, метод run_collection() — цикл действующего однопроходного сбора; из него вызывается parse_and_store текущего разборщика.
Чем задаётся
Секция outputs: каждого описания specs/products/*.yaml. Две формы:
outputs.intakeByKind— маршрутизация по значению поляfield(например_kind): у каждого вида свои целиtargets[kind]. Если она есть, писатель ходит только поtargets[kind](parsed_runner.py, строки 62–81), а явныйoutputs.intakeдля записи не используется.outputs.intake— единственная цель для всех строк описания.
Ловушка 11.08.2026, якорь — комментарий в specs/products/goldapple.snapshot.yaml, строки 39–44: при наличии intakeByKind явный intake молчит, и ga_raw не получила ни строки, хотя дочерние таблицы наполнялись исправно. При компиляции явный intake сохраняет своё explode; без него — синтезируется из первой цели первого вида с отбросом explode (product_spec.py, строки 1250–1260: intake.pop("explode", None) на 1259).
Какие правила обязан соблюдать
- Статусы — по канону STATUS-SEMANTICS.md; формулы не трогать без DO-NOT-REGRESS.md.
- У
BaseCollectorдва пути записи. ДействующийSpecCollectorнаследуетsupports_batch_write = False, поэтому_buffer_rowсразу вызываетparse_and_store(base.py, строки 1025–1046). Отдельные коллекторы сsupports_batch_write = Trueсобирают строки в буфер (base.py, строки 1048–1085), а затем_flush_bufferпередаёт их вexecutemany(base.py, строки 1087–1140). rows_parsedсчитается по записанному, а не по положенному в буфер — честность счётчика под тестом (test_rows_parsed_honesty.py)._buffer_rowпишет разобранную строку в целевую таблицуgwptd_intake: пакетно через буфер либо сразу старым построчным путём._write_legacy— отдельная необязательная запись поlegacy_mapping_pathв старуюlamoda_reports; она включается только приV3_LEGACY_MYSQL_HOST, а ошибка там лишь журналируется и не валит приём. Штатная обёртка s3 удаляет эту переменную, поэтому живой Next пишет только в приём (run_collector.sh).- Схему цели менять нельзя в обход миграций ядра — связь описаний и таблиц держит check_intake_schema_contract.py.
- Раздельный контур сбора и разбора пока является следующим этапом, а не
действующим путём. Он написан, но миграции и учётные записи на сервере не
применены и в расписание он не включён. Включение выделено в этап IV-1
дорожной карты:
сначала одна площадка и сверка с действующим контуром, затем расширение.
Его цель — повторный разбор сохранённого сырья без нового обращения к
площадке (
ROADMAP.md:254-268).
Чем проверяется
python3 -m pytest marketplace-collector-v3/tests/test_buffered_write.py marketplace-collector-v3/tests/test_rows_parsed_honesty.py marketplace-collector-v3/tests/test_spec_goldapple.py::test_product_spec_maps_snapshot_to_existing_ga_raw_shape marketplace-collector-v3/tests/test_spec_goldapple.py::test_ga_raw_leaf_fields_render_values_and_die_on_broken_path -q— 25 passed, 0 skipped (прогнал 14.08).if grep -qE 'next_raw_collector|next_parser' marketplace-collector-v3/scripts/crontab.s3-next.txt; then echo 'найдено'; else echo 0; fi— 0: раздельная пара не в расписании, разбор идёт в одном проходе.
Чего делать нельзя
- Ставить явный
outputs.intakeрядом сintakeByKindи считать, что он пишет: при наличииintakeByKindдля записи используется только она (см. якорь вgoldapple.snapshot.yaml). - Забывать
explode-семантику: без явногоintakeразвёртка цели теряется (product_spec.py, строки 1250–1260). - Править разборщик так, чтобы его
rows_parsedрос от строк в буфере, а не от записанных — тест честности не пропустит. - Трогать отгрузку и миграции ядра без решения владельца (общее для системы, RULES.md).
Что НЕ установлено
- Покрытие парсера тестами целиком — не установлено. Запуск всего набора сборщика не является замером покрытия каждого модуля; поимённое соответствие «модуль парсера → выполняющий его тест» не считалось, а часть тестов требует отдельной базы и пропускается без неё.
Куда за подробностью
- СБОР — как ответ доходит до разбора.
- ХРАНЕНИЕ — куда попадают разобранные строки.
- INTAKE-RAZBOR-STATUS.md — семантика статусов приёма и разбора.
- ENDPOINTS-CATALOG.md — описания адресов, откуда приходят ответы.