fix(course): правки по итогам слепого ревью лаб 07/08 (#22)
Зачем: два слепых ревью (Codex CODE-1..9, Claude TASK-1..2) и перепроверки нашли дефекты в лабах и метадоках; финал лабы 08 переделан по решению пользователя. Что: - канонический сброс в README курса теперь снимает DAG'и с паузы (все создаются на паузе); - имя дашборда исправлено на «E-commerce Analytics Dashboard»; - финал лабы 08: вместо мифа «users == sessions на статике» — вернувшийся пользователь через границу заморозки и измеренное обещание свежести; §2 велит записать границы и время (§6 их требует); - CONTEXT.md: эталонный мир — замороженный живой, 4 056 пользователей / 26 083 визита, возвраты уже есть; - уроки 5–6 ведут в обязательный маршрут, живое упражнение урока 5 требует канонический сброс; - контрактные тесты: убран якорь на удалённую команду; добавленные на триаже тесты-цитаты срезаны до устойчивых инвариантов (прозаический легаси-жанр — issue #24); - handoff обновлён до текущего состояния. Проверка: make test (219 generator + 31 contract) и make lint зелёные; SQL вернувшегося пользователя проверен на эфемерном ClickHouse 25.1 (на полном наборе — в #23). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -188,7 +188,45 @@ def test_course_readme_lists_uv_before_first_command():
|
||||
text = (REPO_ROOT / "docs" / "course" / "README.md").read_text(encoding="utf-8")
|
||||
|
||||
assert "uv" in text
|
||||
assert text.index("uv") < text.index("make generated-history-analytics")
|
||||
assert text.index("uv") < text.index("make clean")
|
||||
|
||||
|
||||
def test_course_canonical_setup_unpauses_dags_before_world_init():
|
||||
"""Канонический блок называет три DAG, снятие паузы и порядок etl→world_init."""
|
||||
# Прозаические формулировки не проверяем — их сторожит ревью, не pytest.
|
||||
# Держим только структурные факты: якорь-заголовок существует, в блоке
|
||||
# названы три DAG-а, упомянута пауза, а etl_pipeline идёт до world_init.
|
||||
text = (REPO_ROOT / "docs" / "course" / "README.md").read_text(encoding="utf-8")
|
||||
setup = text.split("## Подготовка и канонический сброс", maxsplit=1)[1].split(
|
||||
"## Уроки",
|
||||
maxsplit=1,
|
||||
)[0]
|
||||
|
||||
assert "пауз" in setup
|
||||
for dag_id in ("ddl_init", "etl_pipeline", "world_init"):
|
||||
assert dag_id in setup
|
||||
assert setup.index("etl_pipeline") < setup.index("world_init")
|
||||
|
||||
|
||||
def test_next_day_lab_uses_provisioned_superset_dashboard_name():
|
||||
"""Лаба следующего дня ведёт на существующий дашборд Superset."""
|
||||
text = (
|
||||
REPO_ROOT / "docs" / "course" / "lessons" / "07_lab_next_day.md"
|
||||
).read_text(encoding="utf-8")
|
||||
|
||||
assert "E-commerce Analytics Dashboard" in text
|
||||
assert "Clickstream Analytics" not in text
|
||||
|
||||
|
||||
def test_monitoring_lesson_links_to_canonical_reset():
|
||||
"""Урок мониторинга ведёт обратно к каноническому сбросу курса."""
|
||||
# Проверяем живую перекрёстную ссылку: битый якорь — это дефект, а не
|
||||
# переписанная проза. Точные фразы упражнения не пиним.
|
||||
text = (
|
||||
REPO_ROOT / "docs" / "course" / "lessons" / "05_monitoring.md"
|
||||
).read_text(encoding="utf-8")
|
||||
|
||||
assert "../README.md#подготовка-и-канонический-сброс" in text
|
||||
|
||||
|
||||
def test_startup_history_runbook_warns_about_daily_wave_idle_gap():
|
||||
|
||||
Reference in New Issue
Block a user