You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Keep the release matrix moving: main run 34189651084 (4e7d218) failed both the django and playwright jobs. The django failure decomposes into the already-claimed classes (#345 NOT NULL archive_commit_sha; #347/#348 catalogue card routes) plus stragglers, and the playwright job failed for the first time because the change-selective plan widened the browser tier to 281 of 284 tests after #343 and exposed stale #320 route expectations in playwright_tests/ that the 30-test smoke selection never touches. This issue claims the remaining URL-shape stragglers: the Playwright cohort_year reverse kwargs and the flat cohort literals in courses/tests/test_module_pages.py.
Deliberately out of scope here (owned elsewhere): #345 (NOT NULL on course creation), #347/#348 (catalogue card tests and course_list_base.py helpers). Also out of scope, different failure classes: courses.tests.test_curriculum_models.test_cohort_curriculum_format_defaults_to_legacy (expects choices {legacy, modules}, model now also has shared) and courses.tests.test_local_cmp_content_import.test_every_required_column_is_written_by_the_copy (copy does not write the three archive_* columns) - both need their own triage.
Evidence
Playwright job, run 34189651084, 281 selected, 267 passed, 2 failed, 12 errors in 3032.77s:
12 errors in playwright_tests/test_accessibility.py (core smoke, visual evidence, registry, keyboard focus, breadcrumb spacing, javascript-off, reflow, named blink tree): NoReverseMatch: Reverse for 'dashboard' with keyword arguments '{'course_slug': ..., 'cohort_year': '2026'}' not found.
2 failures in playwright_tests/test_course_design_parity.py::test_database_course_catalog_renders_the_design_system_index (desktop + mobile): NoReverseMatch: Reverse for 'course' with keyword arguments '{'course_slug': ..., 'cohort_year': '2026'}' not found.
Django job, same run, 3764 tests, failures=5, errors=45; the URL-shape straggler beyond #347/#348's scope:
courses.tests.test_module_pages.ModulePageTests.test_module_and_unit_links_keep_numeric_source_slugs: reverses with the post-Share current Zoomcamp curriculum across live and self-paced cohorts with GitHub archives #320 route names and cohort_identifier kwargs, but then asserts the legacy flat literals; reverse returns /courses/llm-zoomcamp/cohorts/2026/modules/01-agentic-rag, the test expects /courses/llm-zoomcamp/2026/modules/01-agentic-rag (and the /01-intro unit literal).
Root cause: #320 renamed the cohort route kwargs from cohort_year to cohort_identifier and moved cohort paths under /cohorts/. The catalogue template and courses/urls.py were migrated; four reverse kwarg dicts in playwright_tests/ and two literals in test_module_pages.py were not.
/courses/<family>/cohorts/<identifier> (route cohort) is canonical.
/courses/<family>/cohorts/<identifier>/dashboard (route cohort_dashboard) is canonical.
/courses/<family>/cohorts/<identifier>/modules/<module-slug> (route cohort_module) is redirect-only for shared-format cohorts and resolves against the cohort's own module-format rows for cohorts that still use them. The test fixture creates curriculum_format=CurriculumFormat.MODULES, so the cohorts-shaped URL serves content directly; only the literals are stale.
The product is aligned with the spec; the tests are not. Test-only change.
Scope
playwright_tests/test_accessibility.py: rename the two "cohort_year" keys to "cohort_identifier" in the course_route/empty_course_route kwargs dicts (they feed reverse for dashboard, enrollment, homework, projects, leaderboard surfaces).
playwright_tests/test_course_design_parity.py: rename the two "cohort_year" keys to "cohort_identifier" in the reverse("course", ...) calls.
courses/tests/test_module_pages.py::test_module_and_unit_links_keep_numeric_source_slugs: update the two expected literals to the cohorts shape.
courses/tests/test_wrapped_statistics.py also contains the string cohort_year, but only as a data-dict key of calculate_wrapped_statistics output, not a route kwarg; it passes and stays untouched.
Goal
Keep the release matrix moving: main run 34189651084 (4e7d218) failed both the django and playwright jobs. The django failure decomposes into the already-claimed classes (#345 NOT NULL archive_commit_sha; #347/#348 catalogue card routes) plus stragglers, and the playwright job failed for the first time because the change-selective plan widened the browser tier to 281 of 284 tests after #343 and exposed stale #320 route expectations in
playwright_tests/that the 30-test smoke selection never touches. This issue claims the remaining URL-shape stragglers: the Playwrightcohort_yearreverse kwargs and the flat cohort literals incourses/tests/test_module_pages.py.Deliberately out of scope here (owned elsewhere): #345 (NOT NULL on course creation), #347/#348 (catalogue card tests and
course_list_base.pyhelpers). Also out of scope, different failure classes:courses.tests.test_curriculum_models.test_cohort_curriculum_format_defaults_to_legacy(expects choices {legacy, modules}, model now also has shared) andcourses.tests.test_local_cmp_content_import.test_every_required_column_is_written_by_the_copy(copy does not write the three archive_* columns) - both need their own triage.Evidence
Playwright job, run 34189651084, 281 selected, 267 passed, 2 failed, 12 errors in 3032.77s:
playwright_tests/test_accessibility.py(core smoke, visual evidence, registry, keyboard focus, breadcrumb spacing, javascript-off, reflow, named blink tree):NoReverseMatch: Reverse for 'dashboard' with keyword arguments '{'course_slug': ..., 'cohort_year': '2026'}' not found.playwright_tests/test_course_design_parity.py::test_database_course_catalog_renders_the_design_system_index(desktop + mobile):NoReverseMatch: Reverse for 'course' with keyword arguments '{'course_slug': ..., 'cohort_year': '2026'}' not found.Django job, same run, 3764 tests, failures=5, errors=45; the URL-shape straggler beyond #347/#348's scope:
courses.tests.test_module_pages.ModulePageTests.test_module_and_unit_links_keep_numeric_source_slugs: reverses with the post-Share current Zoomcamp curriculum across live and self-paced cohorts with GitHub archives #320 route names andcohort_identifierkwargs, but then asserts the legacy flat literals; reverse returns/courses/llm-zoomcamp/cohorts/2026/modules/01-agentic-rag, the test expects/courses/llm-zoomcamp/2026/modules/01-agentic-rag(and the/01-introunit literal).Root cause: #320 renamed the cohort route kwargs from
cohort_yeartocohort_identifierand moved cohort paths under/cohorts/. The catalogue template andcourses/urls.pywere migrated; four reverse kwarg dicts inplaywright_tests/and two literals intest_module_pages.pywere not.Deciding spec
_docs/compatibility/shared-curriculum-route-aliases.json(decided 2026-09-07, owner website PM #320/W0; spec authority_docs/specs/02-url-link-seo-compatibility.mdand open-decisions.md #5):/courses/<family>/cohorts/<identifier>(routecohort) is canonical./courses/<family>/cohorts/<identifier>/dashboard(routecohort_dashboard) is canonical./courses/<family>/cohorts/<identifier>/modules/<module-slug>(routecohort_module) is redirect-only for shared-format cohorts and resolves against the cohort's own module-format rows for cohorts that still use them. The test fixture createscurriculum_format=CurriculumFormat.MODULES, so the cohorts-shaped URL serves content directly; only the literals are stale.The product is aligned with the spec; the tests are not. Test-only change.
Scope
playwright_tests/test_accessibility.py: rename the two"cohort_year"keys to"cohort_identifier"in thecourse_route/empty_course_routekwargs dicts (they feedreversefor dashboard, enrollment, homework, projects, leaderboard surfaces).playwright_tests/test_course_design_parity.py: rename the two"cohort_year"keys to"cohort_identifier"in thereverse("course", ...)calls.courses/tests/test_module_pages.py::test_module_and_unit_links_keep_numeric_source_slugs: update the two expected literals to the cohorts shape.courses/tests/test_wrapped_statistics.pyalso contains the stringcohort_year, but only as a data-dict key ofcalculate_wrapped_statisticsoutput, not a route kwarg; it passes and stays untouched.Non-goals
Acceptance criteria
DJANGO_SETTINGS_MODULE=website.settings.test uv run --frozen python manage.py test courses.tests.test_module_pages --noinput --parallel 1passes.--ignore=e2e).make lint,make format-check,make typecheckstay green.cohort_year/flat-cohort failures from the files in scope.