Files
clickstream-ch-kafka-supers…/.scratch/generator-model-time-startup-history/issues/09-seam-browser-fixture-not-preserved.md
T
ddadminandClaude Opus 4.8 d7f02fd700 docs(generator): зафиксировано независимое ревью и задачи на потом
- Зачем:
  - после coordinator-loop нужно независимое ревью результатов модельного
    времени и стартовой истории; пропущенный внешний review gate после задачи 5
    закрыт другой родословной.
- Что:
  - добавлен verification-handoff: что проверено независимо, дефект стыка
    (issue 09) и открытые пробелы (×K, crash recovery, коридоры мат-спеки,
    воспроизводимость, review gate задачи 3).
  - заведены issues 08 (портативный артефакт + runbook + идеи интерфейса),
    09 (баг браузерной фактуры на стыке), 10 (читаемость гео-карты).
  - в docs/course/PRD.md §7 — открытый вопрос «генератор как скрытая
    инфраструктура vs отдельный урок».
- Проверка:
  - git show --stat HEAD
  - чтение .scratch/handoffs/2026-06-14-generator-model-time-verification-review.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 23:03:08 +03:00

5.2 KiB
Raw Blame History

Status: needs-triage

Браузерная фактура не сохраняется на стыке восстановления визита

Parent

.scratch/generator-model-time-startup-history/PRD.md

Что нашли

Визит, переживший стык backfill->live (активен на T_end и продолжается живьём), меняет браузерную фактуру в live-продолжении. Внутри одного click_id человек как будто «пересел» с одного браузера на другой посреди сессии.

Эмпирика. Чистый стенд, 2 суток backfill + 6 live-тиков за T_end, GEN_SEED=4242, GEN_MODEL_T0=2026-01-01T00:00:00+00:00, GEN_MODEL_T_END=2026-01-03T00:00:00+00:00, speed=1:

  • crossing_visits=22; browser_name отличается у 17/22, browser_language у 22/22; каждая сторона внутренне постоянна (22/22).
  • Чисто-исторические визиты (>=3 событий, целиком до T_end): браузер постоянен у 0/14556.
  • device / os / geo на стыке НЕ расходятся: 0/22 конфликтов на уровне ODS.
  • duplicate_events=0: дублей на границе нет.
  • Пример click_id: в истории Chrome / or_IN, в live Firefox / el_CY.

Почему это дефект

Нарушает заявленный критерий задач 04 и 05: «визит, переживший восстановление, остаётся однородным; контекст визита не меняется на стыке и не создаёт второй путь генерации внутри одного click_id». Браузер — часть контекста визита.

Критерий был помечен выполненным, но проверялся неполно: саморевью и ревьюер смотрели только поля dds.click (user / device / geo), которые по одной строке на click_id и потому однородны структурно. Per-event браузерные поля в dds.event не проверялись. Это ровно слепая зона «двух путей генерации», под которую PRD требовал внешний review gate другой родословной после задачи 5 — а он был выполнен той же родословной, и дефект прошёл.

Причина (гипотеза по коду)

Конкретные браузерные строки визита (ActiveVisit.batch) в state не сериализуются: хранятся seed_click_id, page_url_paths, timestamps, next_index (state.py). При восстановлении live-путь пересобирает фактуру (runtime.py._compact_visit_batch: browser_by_click_id[seed_click_id], индекс event_index % len). device и geo переживают восстановление, потому что привязаны к UserProfile (user.device, user.geo) и не зависят от индекса события; браузер зависит от выравнивания event_index между уже выпущенной частью и восстановленной — вероятен рассинхрон индекса. Точную точку уточнить при фиксе.

Масштаб и важность

  • Затрагивает только визиты, активные ровно на T_end (здесь 22 из 17397 визитов, ~0.13%). Чистый backfill и чистый live — без дефекта.
  • Тот же механизм (фактура пересобирается при restore) вероятно затрагивает и восстановление после сбоя (задача 04), не только backfill->live; проверка задачи 04 его не ловила, потому что смотрела только dds.click.
  • Для учебного демо урон низкий, но это реальное нарушение стыковой однородности и сигнал, что браузерная фактура не входит в восстановимое состояние визита.

Направление фикса

  • Либо сериализовать браузерную фактуру визита в state рядом с page_url_paths/timestamps, чтобы восстановленная часть точно продолжила выпущенную.
  • Либо выбирать браузер по абсолютному event_index визита, а не по позиции в остатке, чтобы restore воспроизводил те же строки.
  • В проверку стыка добавить per-event браузерные поля (dds.event), а не только dds.click, чтобы регресс ловился автоматически.

Blocked by

  • Нет. Это bug по результатам независимой проверки задач 05 и 06.