Skip to content

Support program-specific pathway schools in learner record sharing - #3802

Open
AhtishamShahid wants to merge 11 commits into
mainfrom
ahtisham/12321-program-specific-pathway-schools
Open

Support program-specific pathway schools in learner record sharing#3802
AhtishamShahid wants to merge 11 commits into
mainfrom
ahtisham/12321-program-specific-pathway-schools

Conversation

@AhtishamShahid

@AhtishamShahid AhtishamShahid commented Jul 30, 2026

Copy link
Copy Markdown

Closes mitodl/hq#12321

This pull request introduces program-specific pathway school assignments, allowing each program to be linked to specific partner schools and enabling per-program recipient addresses for learner record sharing. The changes are carefully feature-flagged to preserve legacy behavior until the new logic is enabled. Major updates span the admin interface, API, mail delivery, and test coverage.

These changes lay the groundwork for program-specific pathway school sharing, while ensuring that no behavioral changes occur until the feature flag is enabled.

Feature flag

Flag: mitxonline-12321-program-specific-pathway-schools, ships off.

Two functions read it, both deliberate and both commented:

  • courses.api.partner_schools_for_program — the learner's dropdown and the share endpoint's validation
  • courses.mail_api.send_partner_school_sharing_message — recipient routing

Gating mail matters because assignments are entered before the flip. Without it, a mistyped address among ~122 hand-entered rows would receive a real learner record — name, email, grades — while the flag still claimed nothing had changed.

With the flag off, the set of schools shown and accepted is unchanged, and the email recipient is unchanged, whether or not any assignments have been entered. Verified across the full matrix:


Rollout checklist

  • Create the flag mitxonline-12321-program-specific-pathway-schools in PostHog, off
  • Confirm whether production runs POSTHOG_ENABLED=True. If not, the flag falls back to the FEATURES env var, and the name must be FEATURE_mitxonline-12321-program-specific-pathway-schoolsget_features() strips the FEATURE_ prefix and uses the remainder verbatim, so the hyphens are required and an underscored name silently never matches
  • Product enters assignments for all five programs (DEDP, SCM, SDS, PoM, Finance) at /admin/courses/partnerschool/
  • Spot-check a multi-program school (MIT) has the right address per program
  • Verify a DEDP record and an SCM record show different lists
  • Open a follow-up ticket to delete the flag and both if is_enabled(...) branches

The new import in courses/serializers/v1/programs.py shifted 8 pre-existing
ORM001 violations down one line, and routing partner_schools through the
courses.api helper removed the violation formerly at line 368. The baseline
matches on exact line numbers, so it needed realigning.

Edited surgically rather than regenerated: a full --generate-baseline run
also dropped 24 stale entries for files this branch does not touch
(v1/courses.py, v2/programs.py, v3/courses.py), which is unrelated churn.
@github-actions

Copy link
Copy Markdown

OpenAPI Changes

Show/hide changes
## Changes for v0.yaml:
No changes detected

## Changes for v1.yaml:
No changes detected

## Changes for v2.yaml:
No changes detected

Unexpected changes? Ensure your branch is up-to-date with main (consider rebasing).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for program-specific “pathway school” assignments when learners share program records, including per-program recipient routing and validation, shipped behind a new feature flag (default OFF) to preserve existing behavior until rollout.

Changes:

  • Introduces PartnerSchoolProgram through model to link partner schools to programs with per-program recipient email(s) (and alt_email stored for reference only).
  • Filters/validates learner-visible partner schools via a shared helper (partner_schools_for_program) and rejects sharing to non-assigned schools when the flag is ON.
  • Updates email sending to support multiple recipients (one email per recipient) when the flag is ON, plus extensive test coverage and admin UI for assignment entry.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
main/features.py Adds the ENABLE_PROGRAM_SPECIFIC_PATHWAY_SCHOOLS feature flag constant.
drf_lint_baseline.json Updates baseline line references after serializer changes.
courses/views/v1/views_test.py Adds endpoint-level tests for program-scoped validation and partner school filtering behavior.
courses/views/v1/init.py Adds optional ?program= filtering to partner schools endpoint and enforces program-scoped school validation for record sharing.
courses/serializers/v1/programs.py Routes partner school serialization through the shared helper to keep dropdown + validation consistent.
courses/serializers/v1/programs_test.py Adds serializer tests for program-specific filtering, ordering, deduplication, and flag-off behavior.
courses/models.py Adds PartnerSchoolProgram model, PartnerSchool↔Program M2M through it, alphabetical ordering, and recipient resolution helper.
courses/models_test.py Adds unit tests for per-program recipient resolution, alt-email non-usage, and default ordering.
courses/migrations/0101_partnerschoolprogram.py Creates the new through table, index, constraint, and ordering state change.
courses/mail_api.py Adds feature-flag-gated per-program recipient routing and multi-recipient sending.
courses/mail_api_test.py Adds mail routing tests for per-program, multi-recipient, alt-email exclusion, fallback, and flag-off behavior.
courses/factories.py Adds PartnerSchoolProgramFactory for test data creation.
courses/api.py Adds partner_schools_for_program helper with feature-flag gating and deduplication via distinct().
courses/api_test.py Adds API helper tests for flag-on filtering, flag-off behavior, and deduplication.
courses/admin.py Adds admin inline and changelist enhancements for program assignments and filtering.
courses/admin_test.py Adds admin tests ensuring inline presence and changelist filtering by program.
conftest.py Defaults the new feature flag to OFF in tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread courses/mail_api.py
@AhtishamShahid
AhtishamShahid marked this pull request as ready for review July 30, 2026 10:06
@asadali145
asadali145 requested a review from Copilot July 30, 2026 10:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (1)

courses/models.py:2739

  • PartnerSchool now has a global Meta.ordering = ["name"], which changes the default ordering for all PartnerSchool.objects... queries immediately (including when ENABLE_PROGRAM_SPECIFIC_PATHWAY_SCHOOLS is off). This appears to contradict the PR description’s claim that legacy behavior is preserved until the feature flag is enabled, and could affect any existing API/UI consuming partner schools where ordering was previously insertion/PK-based.

Consider either (a) gating ordering changes behind the feature flag (e.g., apply an explicit .order_by("name") only in the flagged code paths) or (b) updating the PR description/rollout expectations to acknowledge the behavior change if the new ordering is intentional.

    class Meta:
        ordering = ["name"]

A failure for one recipient aborted the loop, so remaining per-program
recipients were never attempted and the log did not say which were skipped.
Raised in review on PR #3802.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants