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
Restore the database-backed course experience to the visual composition copied from the Course Management Platform (CMP) at exact source commit 98a235283904b4ef9ad29e196298540756cf1bcc. The copied CMP course templates are the visual source of truth. Website integration may extend the shared shell for canonical same-host navigation, accessibility, security, and route compatibility, but it must not replace or redesign the composition of learner/course pages.
The rest of the public website continues to use the adopted CMP shell, tokens, typography, spacing, responsive behavior, and controls through the shared base. This urgent issue removes the course-specific redesign; it does not introduce another visual system.
website/settings/base.py configures template directories in this order:
course_platform_templates/;
project-level templates/;
installed-app template directories through APP_DIRS=True.
The clickable skeleton in #97 added templates/courses/course_list.html. It is therefore selected before Django reaches the copied courses/templates/courses/course_list.html. The shadow adds a Course-family promotion block, page-specific metadata, and changed empty-state copy. That is the observed composition change.
The copied destination itself is already correct and must not be rewritten:
current website courses/templates/courses/course_list.html: the same SHA-256;
current project shadow templates/courses/course_list.html: SHA-256 7b41e1f4f130d37630089ec62799734ef6283ea6198aae58972daa55b7200ac5.
A complete logical-name comparison found exactly one project-level collision among all 25 pinned courses/templates/** templates: courses/course_list.html. templates/public/course_hub.html is not a collision; it is the separate empty-database public projection used by content.public_views.course_hub when there are no adopted Course rows.
Scoped implementation
Remove templates/courses/course_list.html from the rendering path by deleting that project-owned shadow. Do not copy its additions into the adopted template.
Keep courses/templates/courses/course_list.html byte-identical to the pinned CMP source and keep all 25 logical templates beneath pinned courses/templates/** protected from higher-precedence project/app shadows.
Add a fail-closed adoption test that derives the protected logical names from the pinned copy ledger, rejects any templates/<logical-name> collision, and proves django.template.loader.get_template() resolves each protected name to its recorded copied destination under the actual unified settings.
Record the visual-source/no-shadow rule in the adoption integration documentation. A necessary future change to a copied course template must be an in-place, readable overlay recorded with source hash, target hash, narrow rationale, and focused tests; a parallel higher-precedence redesign is not an allowed integration mechanism.
Add focused database-backed browser coverage for the copied catalog branch and retain the separate no-database public-catalog coverage.
Allowed integration deltas
The rollback must preserve the existing, recorded shared integration layer, including:
the CMP-derived course_platform_templates/base.html shell;
production canonical URLs and same-host public navigation;
one shared account menu, login/session behavior, and capability-gated Studio entry;
local pinned static assets, security headers, CSRF/session protections, safe external-link semantics, and development noindex policy;
route compatibility, /courses canonical behavior, and the Studio Courses namespace;
narrowly recorded responsive fixes such as preventing long headers from widening the mobile viewport.
Those deltas may add shell semantics or safeguards. They must not add, remove, reorder, regroup, or restyle the page-specific sections/cards/content hierarchy of the copied CMP course templates. Do not revert an already recorded security/accessibility fix merely to obtain byte identity; the overlay ledger remains the explicit review boundary.
Acceptance criteria
templates/courses/course_list.html is absent and no project-level or earlier app template shadows any of the 25 protected logical names from pinned courses/templates/**.
courses/templates/courses/course_list.html remains readable, non-minified, and byte-identical to pinned CMP SHA-256 26e391ffdd2c90b89a668c41118f4a8e43efd2b5dde015097f893aee707984ef.
Under the unified Django settings, every protected logical template resolves to its recorded adopted destination; the contract fails if a future project template silently wins loader precedence.
With at least one visible database Course, canonical /courses renders the copied CMP course-list composition. The P0: Build a fully navigable Django review skeleton #97-only Course-family promotion and No active cohort coursework right now. copy are absent; the source active/open-registration/archive grouping and source empty-state copy remain.
The no-Course branch still renders the existing read-only public catalog projection and its current Course-family/Cohort links; this fallback is not moved into or allowed to shadow copied CMP templates.
The shared canonical navigation, account/login behavior, dark mode, accessibility semantics, security policy, local assets, route compatibility, and Studio Courses entry remain functional without changing CMP page composition.
Existing database-backed course detail, registration/enrollment, dashboard, homework, project/peer-review, leaderboard, and certificate behavior does not regress.
Course-facing template sources remain human-readable and line-broken; no generated/minified HTML replaces source templates.
At approximately 1440×900 and 390×844, deterministic database-backed catalog screenshots match the pinned CMP section order, hierarchy, spacing, cards, controls, and visual language, apart from the explicitly allowed shared-shell integrations. Both have no horizontal overflow, clipping, missing stylesheet/font assets, console/page/request errors, debug page, or error page.
The same desktop/mobile pass covers a representative copied course detail and navigation from catalog to detail; keyboard navigation, visible focus, dark mode, and 200% zoom/reflow remain usable.
No model, migration, fixture, imported content, Course/Cohort behavior, public route, API, Studio mutation, or deployment configuration changes are introduced.
Focused verification
Django and adoption contracts
Exercise core.tests.test_course_platform_adoption with the new protected-template origin/collision contract.
Extend the focused homepage/course-hub tests to cover both branches: no database Course uses public/course_hub.html; a visible database Course uses the copied courses/course_list.html origin and source composition.
Run uv run --frozen python scripts/verify_course_platform_adoption.py; all pinned source rows and explicit integration overlays must verify.
Run the focused courses, content course-hub, shared-shell/accessibility, route/SEO, and template-readability Django tests plus makemigrations --check through uv/Make targets.
Run git diff --check and the repository's applicable lint/format checks. There must be no model or migration diff.
Browser and screenshots
Use deterministic synthetic course data and no PII. At 1440×900 and 390×844:
Traverse to a representative copied course detail and exercise the retained account/course navigation.
Check light/dark mode, keyboard focus, 200% zoom/reflow, local assets, console/page/request failures, and document/body overflow.
Store full-page evidence under .tmp/screenshots/issue-128/ and inspect every image. Record the pinned template hash and equivalent deterministic fixture with the screenshots so “CMP parity” is attributable to the exact source, not memory.
Run make test-playwright-core and the copied CMP browser workflow covering availability/provisioning, enrollment, homework, project/peer review, dashboards, and leaderboard.
The independent tester must compare the desktop/mobile candidate evidence with the exact pinned CMP composition and report the allowed shared-shell differences explicitly; “looks similar” is not sufficient.
Deployment gate
The existing read-only deployed smoke must capture /courses at desktop and mobile and assert the copied-composition markers, absence of the #97-only block, canonical/noindex policy, local assets, exact deployed identity, and no overflow/error state. On-call compares those deployed images with the accepted local CMP-parity evidence. If the deployed environment unexpectedly has no visible database Course and therefore cannot exercise the corrected branch, add human, leave #128 open with Refs #128, and obtain an authorized populated-development visual comparison rather than claiming the rollback is live. No owner-only HUMAN blocker is required while the populated deployed branch is exercised deterministically.
Expected implementation files
Delete templates/courses/course_list.html.
Update core/tests/test_course_platform_adoption.py for the 25-template fail-closed collision/origin contract and pinned course-list digest assertion.
Update core/tests/test_homepage.py for explicit database-backed copied-template and unchanged empty-database fallback coverage.
Update _docs/adoption/course-platform/integration-patches.md with the protected visual-source/no-shadow contract.
Add focused browser parity coverage in playwright_tests/test_course_design_parity.py.
Tighten the existing /courses assertions in playwright_tests/test_deployed_smoke.py.
Do not edit courses/templates/courses/course_list.html, models, migrations, views, URLconfs, Studio Courses, APIs, fixtures, or shared shell/CSS unless a failing acceptance check proves a strictly necessary allowed integration delta; any such expansion requires PM review before implementation continues.
Dependencies and non-goals
Closed #30 supplies the pinned adoption baseline; closed #97 introduced the shadow. There is no open blocking dependency. Open accessibility/account/content HUMAN follow-ups do not block this presentation rollback, and this issue must not absorb their scope.
renaming or rolling back Studio Courses, restoring cadmin as a product namespace, or changing management authorization;
replacing the empty-database public projection or duplicating its Course-family data inside copied CMP templates;
redesigning the copied course cards/sections, creating a new design system, or broadly rewriting editorial page composition;
removing canonical navigation, accessibility, security, route-compatibility, or development SEO safeguards;
making request-time network calls or changing deployment infrastructure.
Process handoff
Implement from current main in an isolated worktree. The engineer implements and tests without committing. A separate tester verifies the exact candidate, runs focused Django/adoption/browser gates, and captures/reads the required screenshots. Product management accepts the user-visible rollback only after tester PASS. Then the engineer commits with Closes #128 unless the conditional deployed HUMAN gate is triggered; the orchestrator merges locally without a pull request, pushes, and hands the exact SHA to on-call.
Product decision
Restore the database-backed course experience to the visual composition copied from the Course Management Platform (CMP) at exact source commit
98a235283904b4ef9ad29e196298540756cf1bcc. The copied CMP course templates are the visual source of truth. Website integration may extend the shared shell for canonical same-host navigation, accessibility, security, and route compatibility, but it must not replace or redesign the composition of learner/course pages.The rest of the public website continues to use the adopted CMP shell, tokens, typography, spacing, responsive behavior, and controls through the shared base. This urgent issue removes the course-specific redesign; it does not introduce another visual system.
Normative authority
_docs/PROCESS.md_docs/specs/01-platform-architecture.md: one Django deployment and Django-template presentation_docs/specs/04-courses-and-cohorts.md: adopt and evolve CMP in place; preserve course discovery and learner behavior_docs/specs/10-verification-strategy.md: focused Django/contract/browser checks and inspected desktop/mobile evidence_docs/adoption/course-platform/README.mdandintegration-patches.md: pinned source ledger and explicit-overlay policyConfirmed cause and baseline
website/settings/base.pyconfigures template directories in this order:course_platform_templates/;templates/;APP_DIRS=True.The clickable skeleton in #97 added
templates/courses/course_list.html. It is therefore selected before Django reaches the copiedcourses/templates/courses/course_list.html. The shadow adds a Course-family promotion block, page-specific metadata, and changed empty-state copy. That is the observed composition change.The copied destination itself is already correct and must not be rewritten:
courses/templates/courses/course_list.html: SHA-25626e391ffdd2c90b89a668c41118f4a8e43efd2b5dde015097f893aee707984ef;courses/templates/courses/course_list.html: the same SHA-256;templates/courses/course_list.html: SHA-2567b41e1f4f130d37630089ec62799734ef6283ea6198aae58972daa55b7200ac5.A complete logical-name comparison found exactly one project-level collision among all 25 pinned
courses/templates/**templates:courses/course_list.html.templates/public/course_hub.htmlis not a collision; it is the separate empty-database public projection used bycontent.public_views.course_hubwhen there are no adoptedCourserows.Scoped implementation
templates/courses/course_list.htmlfrom the rendering path by deleting that project-owned shadow. Do not copy its additions into the adopted template.courses/templates/courses/course_list.htmlbyte-identical to the pinned CMP source and keep all 25 logical templates beneath pinnedcourses/templates/**protected from higher-precedence project/app shadows.templates/<logical-name>collision, and provesdjango.template.loader.get_template()resolves each protected name to its recorded copied destination under the actual unified settings.Allowed integration deltas
The rollback must preserve the existing, recorded shared integration layer, including:
course_platform_templates/base.htmlshell;noindexpolicy;/coursescanonical behavior, and the Studio Courses namespace;Those deltas may add shell semantics or safeguards. They must not add, remove, reorder, regroup, or restyle the page-specific sections/cards/content hierarchy of the copied CMP course templates. Do not revert an already recorded security/accessibility fix merely to obtain byte identity; the overlay ledger remains the explicit review boundary.
Acceptance criteria
templates/courses/course_list.htmlis absent and no project-level or earlier app template shadows any of the 25 protected logical names from pinnedcourses/templates/**.courses/templates/courses/course_list.htmlremains readable, non-minified, and byte-identical to pinned CMP SHA-25626e391ffdd2c90b89a668c41118f4a8e43efd2b5dde015097f893aee707984ef.Course, canonical/coursesrenders the copied CMP course-list composition. The P0: Build a fully navigable Django review skeleton #97-only Course-family promotion andNo active cohort coursework right now.copy are absent; the source active/open-registration/archive grouping and source empty-state copy remain.Coursebranch still renders the existing read-only public catalog projection and its current Course-family/Cohort links; this fallback is not moved into or allowed to shadow copied CMP templates.Focused verification
Django and adoption contracts
core.tests.test_course_platform_adoptionwith the new protected-template origin/collision contract.public/course_hub.html; a visible database Course uses the copiedcourses/course_list.htmlorigin and source composition.uv run --frozen python scripts/verify_course_platform_adoption.py; all pinned source rows and explicit integration overlays must verify.courses,contentcourse-hub, shared-shell/accessibility, route/SEO, and template-readability Django tests plusmakemigrations --checkthroughuv/Make targets.git diff --checkand the repository's applicable lint/format checks. There must be no model or migration diff.Browser and screenshots
Use deterministic synthetic course data and no PII. At 1440×900 and 390×844:
/coursesthrough the database-backed branch; assert the copied source composition and absence of the P0: Build a fully navigable Django review skeleton #97-only promotion block/copy..tmp/screenshots/issue-128/and inspect every image. Record the pinned template hash and equivalent deterministic fixture with the screenshots so “CMP parity” is attributable to the exact source, not memory.make test-playwright-coreand the copied CMP browser workflow covering availability/provisioning, enrollment, homework, project/peer review, dashboards, and leaderboard.The independent tester must compare the desktop/mobile candidate evidence with the exact pinned CMP composition and report the allowed shared-shell differences explicitly; “looks similar” is not sufficient.
Deployment gate
The existing read-only deployed smoke must capture
/coursesat desktop and mobile and assert the copied-composition markers, absence of the #97-only block, canonical/noindex policy, local assets, exact deployed identity, and no overflow/error state. On-call compares those deployed images with the accepted local CMP-parity evidence. If the deployed environment unexpectedly has no visible database Course and therefore cannot exercise the corrected branch, addhuman, leave #128 open withRefs #128, and obtain an authorized populated-development visual comparison rather than claiming the rollback is live. No owner-only HUMAN blocker is required while the populated deployed branch is exercised deterministically.Expected implementation files
templates/courses/course_list.html.core/tests/test_course_platform_adoption.pyfor the 25-template fail-closed collision/origin contract and pinned course-list digest assertion.core/tests/test_homepage.pyfor explicit database-backed copied-template and unchanged empty-database fallback coverage._docs/adoption/course-platform/integration-patches.mdwith the protected visual-source/no-shadow contract.playwright_tests/test_course_design_parity.py./coursesassertions inplaywright_tests/test_deployed_smoke.py.Do not edit
courses/templates/courses/course_list.html, models, migrations, views, URLconfs, Studio Courses, APIs, fixtures, or shared shell/CSS unless a failing acceptance check proves a strictly necessary allowed integration delta; any such expansion requires PM review before implementation continues.Dependencies and non-goals
Closed #30 supplies the pinned adoption baseline; closed #97 introduced the shadow. There is no open blocking dependency. Open accessibility/account/content HUMAN follow-ups do not block this presentation rollback, and this issue must not absorb their scope.
Non-goals:
cadminas a product namespace, or changing management authorization;Process handoff
Implement from current
mainin an isolated worktree. The engineer implements and tests without committing. A separate tester verifies the exact candidate, runs focused Django/adoption/browser gates, and captures/reads the required screenshots. Product management accepts the user-visible rollback only after tester PASS. Then the engineer commits withCloses #128unless the conditional deployed HUMAN gate is triggered; the orchestrator merges locally without a pull request, pushes, and hands the exact SHA to on-call.