apiVersion: schedules.gwptd.io/v1alpha1
kind: S3NextSchedule
metadata:
  name: s3-next
  timezone: UTC
  generatedArtifact: marketplace-collector-v3/scripts/crontab.s3-next.txt
runtime:
  repositoryRoot: /opt/gwptd-analytics/repo
  scriptDirectory: marketplace-collector-v3/scripts
  collectorRepositoryRoot: /opt/gwptd-collector/repo
  # Должен совпадать с жёстко заданным путём сторожа runtime_data_fence.py
  # (CODEBASE_LOCK = /opt/mcp-gwptd/logs/codebase-reindex.lock). Отдельный замок
  # коллектора (2026-08-06) нарушал контракт сторожа — дескриптор открывался на
  # другом файле, аттестация inode падала, сбор молча стоял (2026-08-07 revert).
  collectorCodebaseLock: /opt/mcp-gwptd/logs/codebase-reindex.lock
document:
  header:
    - "# GWPTD s3 Next — автономный runtime без чтения/записи s2."
    - "# Установить: crontab /opt/gwptd-analytics/repo/marketplace-collector-v3/scripts/crontab.s3-next.txt"
    - "# Секреты загружаются только wrapper-скриптами из root-owned secret files."
    - ""
  afterEnvironment:
    - ""
  footer:
    - ""
    - "# Намеренно отсутствуют: refresh_s2_calc_mirror, cutover_reconciliation,"
    - "# run_legacy_mirror и amz_sync. Amazon FBA теперь забирается напрямую SP-API;"
    - "# S2 используется comparator-ом только read-only."
environment:
  - name: CRON_TZ
    value: UTC
  - name: SHELL
    value: /bin/bash
  - name: PATH
    value: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
jobs:
  - id: supplier-catalog
    kind: collector
    cron: "45 3  * * *"
    before:
      - "# NextCollector: immutable ProductSpec registry обязан совпасть с exact-set"
      - "# collector_runtime_pointer; endpoint-ы исполняются одним spec_runtime без"
      - "# legacy dispatcher/fallback. Host-flock + DB lease не допускают дублей."
      - "# Основные внешние API стартуют в 04:00 UTC через run_collector_fleet.sh:"
      - "# одновременный запуск четырёх площадок (wb, ozon, ym, lamoda) без"
      - "# пересечения с действующим утренним S2 и без конкуренции за общие API-токены."
      - "# Решение владельца 07.08.2026: площадки параллельно, внутри — последовательно."
    runner:
      script: run_collector.sh
      args: [--endpoint, 1c.supplier_catalog]
    log: /var/log/gwptd-v3-1c.log
    completion:
      type: collector_exact_success_set
    endpointSet:
      mode: explicit
      endpoints: [1c.supplier_catalog]
  - id: fleet-daily
    kind: collector
    # Одновременный старт четырёх площадок через run_collector_fleet.sh.
    # Полосы идут параллельно; внутри полосы — строго последовательно.
    # Решение владельца 07.08.2026: площадки одновременно, параллельность
    # внутри площадки запрещена (654 отказа 429 за 30 дней).
    # ДВА запуска в сутки, 04:00 и 16:00 UTC. Причина — норматив свежести 27 часов:
    # при одном запуске одиночный отказ даёт 48 часов простоя и выводит эндпоинт
    # за норматив; при двух попытках с промежутком ~12 часов одиночный отказ
    # укладывается в 24 часа, двойной — в 36. Это обоснование стояло у прежних
    # посуточных слотов площадок и переходом на полосы не отменяется: полосы
    # сокращают ДЛИТЕЛЬНОСТЬ прохода, а не вероятность отказа площадки.
    # Длительность прохода задаёт самая долгая площадка (Lamoda ~60 мин);
    # до сборки ядра в 09:15 UTC остаётся запас.
    cron: "0  4,16 * * *"
    before:
      - "# YM core идёт первым под единым marketplace-lock; quota-heavy конкурентная"
      - "# позиция запускается отдельным child только после обновления остальных данных."
    runner:
      script: run_collector_fleet.sh
      args: [--lanes, "wb,ozon,ym,lamoda"]
    log: /var/log/gwptd-v3-fleet.log
    completion:
      type: collector_exact_success_set
    endpointSet:
      mode: fleet
      lanes: [wb, ozon, ym, lamoda]
      exclude:
        wb: [wb.stocks]
        lamoda: [lamoda.documents, lamoda.cabinet_prices, lamoda.funnel]
  - id: goldapple-snapshot
    kind: collector
    cron: "20 */2 * * *"
    before:
      - "# Отдельный кабинетный snapshot GA через Moscow egress; все 29 ga_raw tags"
      - "# завершаются до build_all и не конкурируют с токенами основных marketplace API."
    runner:
      script: run_goldapple_snapshot.sh
      args: []
    log: /var/log/gwptd-v3-goldapple.log
    completion:
      type: collector_exact_success_set
    endpointSet:
      mode: explicit
      endpoints: [goldapple.snapshot]
  - id: amazon-fba-inventory
    kind: collector
    cron: "0  11 * * *"
    before:
      - "# MERULA TRADE SP-API small mode (owner decision 2026-07-14). Daily work is"
      - "# limited to FBA inventory plus orders/Sales & Traffic. Finance and settlements"
      - "# run weekly; the closed monthly group runs once per month. Buybox, sales ranks"
      - "# and the broad technical weekly group are deliberately unscheduled."
    runner:
      script: run_amazon_fba_inventory.sh
      args: []
    log: /var/log/gwptd-v3-amazon-fba.log
    completion:
      type: collector_exact_success_set
    endpointSet:
      mode: explicit
      endpoints: [amazon.fba_inventory]
  - id: amazon-daily-reports
    kind: collector
    cron: "20 11 * * *"
    runner:
      script: run_amazon_report_group.sh
      args: [daily]
    log: /var/log/gwptd-v3-amazon-daily.log
    completion:
      type: collector_exact_success_set
    endpointSet:
      mode: explicit
      endpoints: [amazon.daily_reports]
  - id: amazon-finance
    kind: collector
    cron: "0  12 * * 0"
    runner:
      script: run_amazon_direct.sh
      args: [finance]
    log: /var/log/gwptd-v3-amazon-finance.log
    completion:
      type: collector_exact_success_set
    endpointSet:
      mode: explicit
      endpoints: [amazon.finance_events]
  - id: amazon-settlements
    kind: collector
    cron: "0  13 * * 0"
    runner:
      script: run_amazon_direct.sh
      args: [settlements]
    log: /var/log/gwptd-v3-amazon-settlements.log
    completion:
      type: collector_exact_success_set
    endpointSet:
      mode: explicit
      endpoints: [amazon.settlements]
  - id: amazon-monthly-reports
    kind: collector
    cron: "0  17 1 * *"
    runner:
      script: run_amazon_report_group.sh
      args: [monthly]
    log: /var/log/gwptd-v3-amazon-monthly.log
    completion:
      type: collector_exact_success_set
    endpointSet:
      mode: explicit
      endpoints: [amazon.monthly_reports]
  - id: onec-warehouse-movements
    kind: collector
    cron: "55 4  * * *"
    before:
      - "# Отгрузки и возвраты со склада 1С — ежедневный сбор окна 3 дня."
      - "# INSERT IGNORE по row_content_hash: существующие строки не перезаписываются."
      - "# Решение владельца 07.08.2026: «новое — вставлять, существующее — сверять»."
    runner:
      # Обёртка та же, что у 1c.supplier_catalog: тот собирает 140 954 строки
      # через run_collector.sh с тем же способом разрешения токена. Проверено
      # 08.08.2026: run_reference_sync.sh принимает имя позиционно (onec,
      # brand), а не --endpoint, и сюда не годится.
      script: run_collector.sh
      args: [--endpoint, 1c.warehouse_movements]
    log: /var/log/gwptd-v3-1c-movements.log
    completion:
      type: collector_exact_success_set
    endpointSet:
      mode: explicit
      endpoints: [1c.warehouse_movements]
  - id: kernel-build-all
    kind: kernel_etl
    cron: "15 9  * * *"
    before:
      - "# Архивный Statistics API endpoint wb.stocks оставлен только для ручного аудита"
      - "# и fallback-истории. Канонический wb.warehouse_stocks входит в утренний WB-run;"
      - "# повторные 429 архивного endpoint не должны расходовать квоту и шуметь freshness."
      - ""
      - "# Kernel и локальный мониторинг Next."
      - "# KERNEL_BUILD_MODE=verification — решение владельца 2026-07-23: расцепить расчёт"
      - "# от свежести сборов. Временный отказ маркетплейса (504 у wb.analytics, блокировки"
      - "# данных WB из-за пожаров на складах) больше не морозит ВЕСЬ пересчёт — снимаются"
      - "# только гейты свежести входов, проверки качества данных остаются включёнными."
      - "# Тогда правку внесли в живой crontab, но НЕ в реестр, и первый же деплой её"
      - "# откатил: расписание приводится к сгенерированному файлу побайтно. Пересчёт"
      - "# молча падал 25–30.07, данные в интерфейсе застыли на пять дней."
    runner:
      script: run_kernel_etl.sh
      args: [build_all]
      environment:
        - name: KERNEL_BUILD_MODE
          value: verification
    log: /var/log/gwptd-v3-kernel.log
    completion:
      type: kernel_build_all_success
  - id: kernel-repair-stocks
    kind: kernel_etl
    # Раз в два дня, в 07:40 UTC — до утренней сборки ядра в 09:15, чтобы
    # добранные дни попали в её расчёты в тот же день.
    #
    # Решение владельца 11.08.2026: «нужно проводить ремонтные работы, запускать
    # наш скрипт, чтобы он искал то, что потеряно, и заполнял; считаю достаточно
    # раз в каждый второй день».
    cron: "40 7  */2 * *"
    before:
      - ""
      - "# Ремонт остатков: добор дней, которые есть в приёме и не разобраны в факте."
      - "# Штатная сборка публикует остатки из ОДНОГО запечатанного прогона, последнего,"
      - "# и дни, собранные во время простоя, не попадают в факт никогда. 10.08.2026 это"
      - "# дало 24 дня присутствия из 30 в окне расчёта и завысило КАЖДЫЙ прогноз отгрузки"
      - "# на четверть — velocity делит на дни присутствия и умножает на дни покрытия."
      - "#"
      - "# Область запечатана тремя способами: уникальный ключ факта не даёт задвоить;"
      - "# берутся только ОТСУТСТВУЮЩИЕ даты; сегодняшний день исключён всегда."
      - "# Чинит WB FBO, Ozon FBO и Lamoda; Ozon FBS и Яндекс намеренно не трогает."
    runner:
      script: run_kernel_etl.sh
      args: [repair_fact_stocks]
    log: /var/log/gwptd-v3-kernel-repair.log
    completion:
      type: kernel_repair_exit_zero
  - id: freshness-check
    kind: monitor
    cron: "45 *  * * *"
    runner:
      script: run_monitor.sh
      args: [freshness_check]
    log: /var/log/gwptd-v3-freshness.log
    completion:
      type: monitor_exit_zero
  - id: daily-reconciliation
    kind: monitor
    cron: "45 9  * * *"
    runner:
      script: run_monitor.sh
      args: [daily_reconciliation]
    log: /var/log/gwptd-v3-recon.log
    completion:
      type: monitor_exit_zero
  - id: kernel-freshness
    kind: monitor
    cron: "15 10 * * *"
    before:
      - "# Свежесть данных kernel — то, что видит человек. Ежедневный build_all мог падать"
      - "# неделями, сообщая об этом только строкой в логе: 25–30.07 так и вышло. Проверка"
      - "# идёт через час после пересчёта и раз в день, антиспам внутри модуля."
    runner:
      script: run_monitor.sh
      args: [kernel_freshness]
    log: /var/log/gwptd-v3-kernel-freshness.log
    completion:
      type: monitor_exit_zero
  - id: shadow-watch
    kind: monitor
    cron: "30 9  * * *"
    runner:
      script: run_monitor.sh
      args: [shadow_watch]
    log: /var/log/gwptd-v3-shadow-watch.log
    completion:
      type: monitor_exit_zero
  - id: parity-breakdown
    kind: monitor
    cron: "45 14 * * *"
    before:
      - "# Разбор сверки по площадкам через 15 минут после самого сравнения."
      - "# Компаратор говорит «расхождение в 20 группах из 56», но не говорит в каких;"
      - "# разбивка по паре день+маркетплейс уже посчитана и лежит в details_json."
    runner:
      script: run_monitor.sh
      args: [parity_breakdown]
    log: /var/log/gwptd-parity-breakdown.log
    completion:
      type: monitor_exit_zero
  - id: canon-next-compare
    kind: monitor
    cron: "30 14 * * *"
    before:
      - "# Только агрегированный read-only экспорт закрытого окна; не запускает collector"
      - "# и не пишет на s2. Время после дневных build_all обоих контуров."
    runner:
      script: run_monitor.sh
      args: [canon_next_compare]
    log: /var/log/gwptd-canon-next-compare.log
    completion:
      type: monitor_exit_zero
  - id: s20-preview
    kind: reference_sync
    cron: "0  3  * * *"
    before:
      - ""
      - "# Локальные/внешние справочники. Эти задачи не обращаются к s2."
    runner:
      script: run_s20_sync.sh
      args: [preview]
    log: /var/log/gwptd-v3-s20-mirror.log
    completion:
      type: reference_sync_exit_zero
  - id: s20-attributes
    kind: reference_sync
    cron: "20 3  * * *"
    runner:
      script: run_s20_sync.sh
      args: [attributes]
    log: /var/log/gwptd-v3-s20-attrs.log
    completion:
      type: reference_sync_exit_zero
  - id: s20-description
    kind: reference_sync
    cron: "40 3  * * *"
    runner:
      script: run_s20_sync.sh
      args: [description]
    log: /var/log/gwptd-v3-s20-description.log
    completion:
      type: reference_sync_exit_zero
  - id: reference-brand
    kind: reference_sync
    cron: "0  4  * * *"
    runner:
      script: run_reference_sync.sh
      args: [brand]
    log: /var/log/gwptd-v3-brand.log
    completion:
      type: reference_sync_exit_zero
  - id: reference-onec
    kind: reference_sync
    cron: "30 4  * * *"
    runner:
      script: run_reference_sync.sh
      args: [onec]
    log: /var/log/gwptd-v3-1c-ref.log
    completion:
      type: reference_sync_exit_zero
  - id: reference-onec-stock
    kind: reference_sync
    cron: "50 4  * * *"
    runner:
      script: run_reference_sync.sh
      args: [onec-stock]
    log: /var/log/gwptd-v3-1c-stock.log
    completion:
      type: reference_sync_exit_zero
  - id: lamoda-documents-weekly
    kind: collector
    cron: "0  2  * * 1"
    before:
      - ""
      - "# Кабинетные Lamoda-источники: те же CollectionRun/raw/lease/freshness,"
      - "# что и остальные spec-runtime endpoints. Live cron меняется только после canary."
    runner:
      script: run_collector.sh
      args: [--endpoint, lamoda.documents]
    log: /var/log/gwptd-lamoda-cabinet.log
    completion:
      type: collector_exact_success_set
    endpointSet:
      mode: explicit
      endpoints: [lamoda.documents]
  - id: lamoda-cabinet-prices
    kind: collector
    cron: "20 2  * * *"
    runner:
      script: run_collector.sh
      args: [--endpoint, lamoda.cabinet_prices]
    log: /var/log/gwptd-lamoda-cabinet.log
    completion:
      type: collector_exact_success_set
    endpointSet:
      mode: explicit
      endpoints: [lamoda.cabinet_prices]
  - id: lamoda-funnel
    kind: collector
    cron: "40 2  * * *"
    runner:
      script: run_collector.sh
      args: [--endpoint, lamoda.funnel]
    log: /var/log/gwptd-lamoda-cabinet.log
    completion:
      type: collector_exact_success_set
    endpointSet:
      mode: explicit
      endpoints: [lamoda.funnel]
coverage:
  dedicatedEndpoints:
    - 1c.warehouse_movements
    - lamoda.documents
    - lamoda.cabinet_prices
    - lamoda.funnel
    - goldapple.snapshot
    - amazon.fba_inventory
    - amazon.daily_reports
    - amazon.weekly_reports
    - amazon.monthly_reports
    - amazon.finance_events
    - amazon.sales_ranks
    - amazon.buybox
    - amazon.settlements
  unscheduledEndpoints:
    - amazon.buybox
    - amazon.sales_ranks
    - amazon.weekly_reports
    - wb.stocks
