Ядро (ETL)
Замер от: 2026-08-14 · чем проверено: замер базы, замер карты, прогон
test_build_input_manifest.py(50 passed, 0 skipped) Для кого: тому, кто собрался трогать пересчёт фактов (build_*.py), манифест входов или расписание kernel. Читать ПЕРЕД первой правкой.
Что делает
Пятнадцать шагов пересчитывают измерения и факты из разобранных строк приёма,
а последним шагом прогоняют ворота инвариантов. В схеме gwptd_kernel всего 27
таблиц, но не все они принадлежат build_all: например, сохранённые отгрузки и
служебные таблицы публикации живут отдельно. Границы самого прогона: начинается
с товарного мастера (dim_product), кончается validate_invariants; всё, что
до, — сбор и разбор, всё, что после, — выдача и показ. Шаги идут в порядке
зависимостей и останавливаются на первом сбое: упавший шаг не пускает все
последующие (build_all.py:484 — «later steps were not run»).
В прежней карте владельца этого блока не было вовсе — он стоит между сбором и расчётами и потому выпадал из картины (замер карты, блок 4). Фактический порядок:
1 dim_product 9 fact_orders
2 resolve_identifiers 10 fact_returns
3 wb_category 11 fact_analytics
4 fact_supplier_stock 12 dedupe_cross_mp_orders
5 fact_stocks 13 fact_turnover
6 fact_prices 14 fact_rating
7 fact_storage 15 validate_invariants
8 fact_finance
Четыре следствия этого порядка, которые читатель обязан знать:
- финансы (8) идут ПЕРЕД заказами (9) — одна упавшая финансовая строка
морозит весь остаток сборки. Это не теория: ядро однажды стояло восемь дней
(докстрока
repair_fact_stocks.py, замер 10.08.2026); - схлопывание межплощадочных дублей (12) — ПЕРЕД воротами, а не после
(
build_all.py:105); - рейтинг четырнадцатый: зависит от заказов, остатков и запаса поставщика,
раньше считаться не может (
build_all.py:107); validate_invariantsпоследний, и это ворота, а не отчёт: он не докладывает о расхождении, он роняет сборку:validate()возвращает 1 при HARD-нарушении, аbuild()превращает это в исключение (validate_invariants.py:301-348).
Ремонт остатков — отдельный прогон (07:40 через день) и намеренно обходит
ворота расписок: repair() сразу ставит ограждение писателя и выбирает
пропущенные даты. Это решение, а не дефект: штатная сборка публикует остатки из
одного запечатанного прогона, последнего, и дни, собранные во время простоя, не
попали бы в факт никогда. Ремонт добирает только даты, которых в факте нет, и
этим же ограничен (repair_fact_stocks.py).
Замер карты сопоставлял 21 модуль build_*.py с 15 шагами и потому оставлял
шесть неустановленных вызывающих. Точный разбор иной: двенадцать модулей
реализуют шаги STEPS, build_all.py — сам оркестратор, а вне этой цепочки
остаются восемь. Шесть обслуживают подготовку входов общего прогона
(build_input_* и build_reference_input), а два образуют отдельную проекцию
«Золотого яблока»: build_ga_sealed вызывает build_ga_kernel.
Проекция запускается каждые два часа цепочкой crontab.s3-next.txt →
run_goldapple_snapshot.sh → run_kernel_etl.sh build_ga_sealed.
Точка входа в код
marketplace-collector-v3/kernel/etl/build_all.py — список STEPS (строки 89–109)
и main(). В бою запускается только обёрткой
marketplace-collector-v3/scripts/run_kernel_etl.sh build_all; обёртка требует
чистый checkout на ветке next/spec-platform и забор рантайма.
Чем задаётся
STEPSвbuild_all.py— состав и порядок шагов;- манифест входов
specs/kernel/build-all-inputs.yaml— списки целевых таблиц сверяются ТОЧНО, расхождение роняет сборку до первого шага; KERNEL_BUILD_MODE:strictпо умолчанию; в cron —verification(решение владельца 2026-07-23, комментарий вcrontab.s3-next.txt:41): расцепить расчёт от свежести сборов — гейты свежести входов сняты, гейты качества данных остаются;- расписание
marketplace-collector-v3/scripts/crontab.s3-next.txt:build_allв 09:15,repair_fact_stocksв 07:40 через день. Выкладка сверяет root crontab с этим файлом побайтно — править cron руками нельзя.
Какие правила обязан соблюдать
- формулы шагов 13–14 — только канон formulas.yaml; копий не плодить;
- оценка модели — только от реальных продаж, выкуплено минус возвраты (DO-NOT-REGRESS.md);
- новая целевая таблица у описания — дописать её в манифест входов, иначе
сборка встанет (проверка
test_build_input_manifest.pyсравнивает списки точно); - идемпотентность: повторный прогон не двоит (уникальные ключи фактов);
- писатель — только за забором:
ensure_kernel_writer_fences()вызывается вmain()до любого запроса к базе (первая строка блокаtry). dim_warehouse— справочник с ручным управлением, а не выход сборки. Это прямо объявлено вspecs/kernel/build-all-inputs.yaml:474-481. Найденный писатель —marketplace-collector-v3/scripts/backfill_fact_order_warehouses.py: по умолчанию он делает сухой прогон без записи (:2-7), а запись включается только явным--apply(:476-486). ВSTEPSи штатном cron этого скрипта нет, поэтому плановая сборка справочник не наполняет. Из кода нельзя вывести, запускал ли кто-либо ручной--applyи чем закончился такой запуск. Разбор C2 (04.08) рекомендовал для заказов справочник пока не заполнять (C2-warehouse-region.md, строка 329) — сначала извлечь склад вfact_orders.warehouse, аdim_warehouse— потом (хронология, строки 330–337); потребитель справочника — проверкаstocks_alias_splitпосле ETL над остатками (строка 318). Но C2 — исследовательский отчёт DeepSeek со статусом «только чтение» (строки 3–5), а не решение владельца; объяснять им живое состояние как принятое решение нельзя.
Чем проверяется
# Локально, прямо сейчас:
python3 -m pytest marketplace-collector-v3/tests/test_build_input_manifest.py -q
# → 50 passed, 0 skipped (прогон 14.08)
# В бою: /var/log/gwptd-v3-kernel.log, маркеры P1B3_KERNEL_SUCCESS / P1B3_KERNEL_FAILED
# и «step FAILED: <имя>». Итог штатного прогона подтверждать маркером в журнале:
# один лишь статус службы может быть прочитан раньше, чем она запишет итог.
Чего делать нельзя
- менять порядок шагов: зависимости по именам не видны. Пример — F-09: возвраты
СТРОГО после заказов, при обратном порядке первый прогон с нуля давал ноль
возвратов YM/Lamoda (комментарий в
STEPS); - править cron вручную мимо файла расписания: побайтная выверка однажды откатила
такую правку, и пересчёт молча стоял 25–30.07, данные застыли на пять дней
(
crontab.s3-next.txt:44-47); - снимать гейты качества данных без решения владельца;
- трогать отгрузку (
RULES.md, «НЕПРИКОСНОВЕННОЕ»): ядро наполняет факты, а расчёт и сохранение отгрузки образуют отдельный неприкосновенный блок.
Что НЕ установлено
- Почему
dim_warehouseпуста (0 строк на 14.08, замер базы): планового писателя нет, а ручной писатель требует явного--apply. Код не хранит доказательство, запускал ли владелец этот режим и чем он закончился; рекомендация C2 не является решением владельца.
Куда за подробностью
- замер базы — 27 таблиц ядра, точный счёт строк;
- замер карты — блок 4 «Ядро (ETL)»;
- модель данных и DDL-снимок gwptd_kernel.sql;
- formulas.yaml — формулы, которые реализуют шаги 13–14.