Skip to content

Sub-modules phase B: importer and parser support #398

Description

@alexeygrigorev

Part of the shared-curriculum sub-modules umbrella (#396), phase B of 4. Depends on #397 (phase A models). Full design: _docs/planning/shared-curriculum-submodules-design.md, "Course-repository representation" section 1/3/5 for the exact YAML shape, and section 4's "Website parser parity" paragraph.

Goal

The website's content-source parser and curriculum importer understand the optional sub_modules: key in module.yaml and the optional sub_module: key in cohort.yaml homework bindings, and populate the phase-A models correctly. Absent keys must mean exactly today's behavior — this phase must not require any real course repository to change.

Scope

  1. content_sync/course_repository_v2.py _parse_module: accept an optional sub_modules: list, exclusive with a top-level units: (a module has one or the other, never both, never neither — mirror the design doc's exact validation wording as parser error messages). Flatten sub-module units into the same units tuple the parser builds today (part 1's units then part 2's, in list order) so every existing downstream consumer of ModuleSource.units is unaffected. Add a new SubModuleSource tuple (content id, slug, title, summary, unit index range) on ModuleSource. UnitSource gains sub_module_slug: str | None.
  2. _parse_homework_bindings: accept an optional sub_module: <slug> on a binding, validated against module_by_slug[module].sub_modules. HomeworkBindingSource gains sub_module: str | None. duplicate_homework_module becomes a duplicate-anchor check: (module, None) mapped twice, or (module, sub_module) mapped twice — a module anchor and a part anchor on the same module are NOT a duplicate.
  3. courses/services/curriculum_source.py: update ModuleSource/UnitSource/HomeworkBindingSource dataclasses to match.
  4. courses/curriculum_source_validators.py: new all-or-nothing rule (within one module, either every lesson has a sub-module or none does) and contiguity rule (each sub-module's lessons are contiguous in module position order, matching sub-module list order) — both import-time checks, not DB constraints, per the design doc's reasoning (they're what make "after the anchor's last lesson" unambiguous for phase C rendering).
  5. courses/services/curriculum_import.py _import_shared_modules/_upsert_shared_lessons/_import_shared_placements: write SharedSubModule rows, set SharedLesson.sub_module, set CohortSharedModule.sub_module from the binding's anchor.
  6. Add a mirrored test fixture: content_sync/tests/fixtures/course_repository/llm_zoomcamp_shared/ gets a split module (a new one, don't rewrite the existing single-part fixture module that other tests depend on) with a sub-module-anchored homework binding in a fixture cohort — matching whatever fixture the zoomcamp-ops checker side uses (coordinate naming/shape, though that repo's own fixtures are out of scope for this issue).

Non-goals

  • No zoomcamp-ops checker changes (a separate repository, phase D coordinates with it but doesn't implement it here).
  • No rendering changes (phase C) — this phase only gets data into the database correctly; module/lesson pages continue rendering exactly as before (they simply don't yet read the new fields).
  • No real content repository changes — llm-zoomcamp's actual module.yaml/cohort.yaml are untouched by this phase.

Dependencies

Acceptance criteria

  • make django-check / make migrations-check pass.
  • make test passes, including new parser/importer tests: exclusivity rejected (both units and sub_modules present, or neither), a valid split module imports correctly (sub-module rows created, lessons correctly assigned, flattened unit order matches today's ordering rules), a sub-module-anchored homework binding imports correctly, an invalid sub_module reference in a binding is rejected with a clear error, all-or-nothing and contiguity validators reject malformed fixtures.
  • A dry-run import of the mirrored fixture (module with sub_modules content) succeeds end to end against a test database.
  • Re-running the full existing content-sync/curriculum-import test suite shows zero behavior change for every fixture that doesn't use sub_modules:.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Important follow-upcoursesArea: coursesenhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions