Classify shared course enrollment history in the account inventory

Aperta
#451 7 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
32/100
Tipo di issue
Funzionalità
Chiarezza
Abbastanza chiara
Stato di attività
Attiva
Stack tecnologico
django, python, sqlite

Direzione di ricerca

Start with accounts/identity_inventory.py and the proposed identity_relations.py and identity_relationship_evidence.py extractions, then read the existing reconciliation entry points and the named characterization tests. Run the existing DTC gates before adding accounts/tests/test_course_enrollment_identity.py and its optional fixture. Done means the installed-model catalog, guards, evidence, and reconciliation agree, CourseEnrollment history and collision semantics are covered, and the specified CI, typing, baseline, documentation, and seal updates pass.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

auth bug courses integration P1

Problem and outcome

The owner requests uniform shared course behavior and the greatest safe backend simplification across AISL and DTC while preserving visible UX and every existing feature. community-base PR #402 adds required course-level enrollment history. DTC's account-relation guard correctly rejects its unclassified cb_curriculum.CourseEnrollment.user relation.

Classify this exact relation as reparent, using one explicit installed-model catalog shared by inventory, guards, relationship evidence and reviewed account reconciliation. Preserve both course-level history and existing cohort enrollment/certificate semantics. Support DTC's current tagged package, which lacks CourseEnrollment, without claiming any future tag exists.

Normative references

Observed evidence

Research source: clean committed DTC 3d83926d3312fd9fb7bf564166c12e469c10257a; package pin v0.5.10, resolved in uv.lock to 4c692db461f4c7cbbc2f60afaa05162987a640f6. Package candidate: ce17ad8854e2691abf21fb1d67fc5c0eac59f023.

Two captured package jobs: run 37039387748 / job 110945460390 and run 37039381421 / job 110945438734. Both baselines ran 4172 tests with the existing test_gate_b_operator_contract_is_exact_and_workflow_isolated ERROR. Both linked suites ran 4172 tests with four failures. After existing P16 failure-set normalization and its two link-seal exclusions, the two newly introduced failures are:

  • AccountRelationGuardTests.test_an_unclassified_relation_fails_the_guard
  • AccountRelationGuardTests.test_every_relation_onto_the_account_is_classified

Both identify cb_curriculum.CourseEnrollment.user. The raw-log SHA-256 values, independently checked during grooming, are ab757ac973ced018a1d5f4aa0b21ed1b73ab98e175f05fd5af32b40feb654085 and b449ad306095fb0b3fdce3b045966dea3b8dc8b1050ef1dacceb025fea12c926. Logs remain private project scratch. These failed historical runs prove the defect; they are not acceptance evidence for a new candidate. The baseline ERROR and linked seal FAILs remain distinct and cannot be described as a green DTC gate.

Scope and ownership

  1. Keep every existing explicit classification. Add only the reviewed CourseEnrollment user relation with reparent handling. Allow omission only when this exact model is absent from the installed curriculum app, as with the current pin. An existing model with a missing, renamed or incorrectly targeted user field must fail; missing mandatory models/apps must fail. Do not infer handling from arbitrary package relations or broadly suppress lookup failures.
  2. Resolve one consistent installed-model catalog before consumers use it. Preserve the existing ACCOUNT_RELATIONS import contract where practical so inventory, both guards, evidence and scripts.prod.account_reconciliation._reparent_relations cannot disagree. No runtime version-number branching or second merge policy.
  3. CourseEnrollment is strict retained-row evidence, never an append-only exemption. A successful reviewed merge moves all source-owned active and ended history rows to the survivor exactly once. Retain row IDs, course IDs, enrolled/unenrolled timestamps and source values; never deduplicate, reset, reactivate or close history to manufacture a merge.
  4. The package constraint permits at most one active (user, course) enrollment. Two active rows for the same course across source/survivor must roll back the whole reviewed merge and produce the existing redacted integrity-conflict/quarantine outcome. Ended rows for the same course coexist; an active row may coexist with ended history. Preserve aliases, account/authority/profile state and all other owned relations on failure, subject only to the existing persisted denial/audit contract.
  5. Simplify within this ownership seam. accounts/identity_inventory.py is already 542 lines: extract cohesive catalog and relationship-evidence responsibilities, retain its public import facade, and leave materially changed handwritten files at most 300 lines and new/materially changed functions at most 30 lines. Cover behavior before extraction and after it. Do not expand another oversized module to move the problem.

Proposed exact files:

  • accounts/identity_inventory.py: bounded facade/report/guard responsibilities and imports.
  • accounts/identity_relations.py (new): explicit relation declarations and narrow installed-model activation.
  • accounts/identity_relationship_evidence.py (new): alias-aware evidence and retained/append-only keys extracted without behavior change.
  • accounts/tests/test_course_enrollment_identity.py (new): absent/present catalog, guard and history/reconciliation behavior tests.
  • accounts/tests/course_enrollment_identity_fixture.py (new, only if needed): isolated synthetic registered-model/database fixture; no production model or installed-app fallback.
  • _docs/architecture/single-durable-account.md: exact shared-history classification, optional availability and collision semantics; avoid stale hard-coded relation totals.
  • scripts/ci.py: add only the five issue-owned paths named below to ADOPTION_INTEGRATION_PYTHON; do not change command behavior or existing entries.
  • pyproject.toml: add only their five dotted module names to the existing ignore_errors = false mypy override; no dependency, source, other tool configuration or exemption changes.
  • ci/adoption_baseline.txt: remove only accounts/identity_inventory.py when promoting the materially changed facade to strict checks; no added baseline entries or other removals.
  • core/tests/test_deployment_workflow.py: update only STUDIO_COURSES_PYPROJECT_SHA256 to the independently reviewed final configuration-only pyproject bytes and add a concise issue-specific explanation beside the existing seal history. Preserve the lock seal, all other frozen hashes, assertions, historical workflow identity and Gate B execution contracts.

Required gate paths/modules: accounts/identity_inventory.py / accounts.identity_inventory, accounts/identity_relations.py / accounts.identity_relations, accounts/identity_relationship_evidence.py / accounts.identity_relationship_evidence, accounts/tests/test_course_enrollment_identity.py / accounts.tests.test_course_enrollment_identity, and accounts/tests/course_enrollment_identity_fixture.py / accounts.tests.course_enrollment_identity_fixture if that fixture is present. The facade is currently in the historical baseline and outside the strict opt-in lists; its substantive extraction requires promotion. The four new files cannot claim historical-source exemptions. The optional fixture must be enrolled exactly when it exists.

The configuration list additions and exact facade-baseline removal are required integration work for the existing BE-16 gates, not a change to their coverage policy. The pyproject hash follows the existing reviewed configuration-only seal procedure; this does not authorize changing any test expectation other than that one checksum and its explanatory history comment.

Existing accounts/tests/test_single_identity.py, accounts/tests/test_account_reconciliation.py and scripts/prod/account_reconciliation/__init__.py are characterization consumers. Prefer preserving their public imports; do not grow these oversized files. If preserving the import facade is impossible, return the revised cohesive file scope for grooming before implementation.

Dependencies and sequence

There is no required open issue dependency for the DTC compatibility implementation. PR #402 supplies the future real model but must not become a prerequisite for this issue: the package requires a compatible consumer before its release, while DTC can implement the bounded contract against its existing pin.

  1. Engineer and independent tester run DTC's own gates with the unchanged dependency/source declarations, byte-identical uv.lock and the actual tagged package. The only allowed pyproject delta is the exact strict-mypy module list above, accompanied by the reviewed pyproject seal update. Exercise the model-present contract using a test-only isolated Django model with the candidate's exact relevant fields and conditional active-row constraint. It must register the exact cb_curriculum.CourseEnrollment label, use real account/course FK targets, exercise the actual catalog, guards, inventory, evidence and reviewed reconciliation, create tables only in an ephemeral SQLite test database, and restore registry/schema state without contaminating the ordinary suite. A clean subprocess is appropriate when import-time catalog activation requires it. Do not mock away reparenting, evidence or transaction behavior.
  2. This synthetic contract is bounded compatibility evidence, not evidence that the real package model/migration has been adopted. When the real model is installed by a legitimate tagged package or package-owned P16 link, the same history scenarios must exercise that real model rather than replace it with a synthetic one. Do not skip required present-model tests just because the current pin lacks it.
  3. After independent DTC tester pass and PM acceptance, follow DTC's commit/local merge process; no DTC PR. Root owns isolated implementation worktree creation. Do not edit the shared dirty main.
  4. Package owners then run fresh P16 checks against the exact merged DTC SHA and their exact package candidate, including both consumers. Record real CourseEnrollment history scenarios and the full suites in that package-owned disposable checkout. This belongs to the package gate, not to DTC's acceptance evidence. Report baseline failures separately and compare normalized new failures under existing P16 rules. Do not change normalization or the two seal exclusions here.
  5. Only the package's later verified/tagged release can enable a separately scoped site pin/adoption issue. Record real migration/adoption/development-copy verification as Not run here, needs: tagged package adoption issue; never invent tag availability or assert deployment success.

Any fresh required DTC gate failure, including an unrelated baseline failure, blocks tester-final/PM acceptance under PROCESS and must return to its owning issue. Package P16's comparison policy does not grant DTC permission to waive a red gate.

Explicit non-goals

  • No visible UI, templates, CSS, routes, navigation, public/API shapes, registration/enrollment UX, scoring, certificate or permission changes.
  • No deletion of CourseEnrollment or existing cohort Enrollment; no shared-course runtime route flip or legacy replacement fallback.
  • No package pin, dependency declarations, lock, source-policy or other seal changes; the sole permitted seal update is the reviewed pyproject checksum for the strict-mypy additions above. No migrations, database resets, imports/backfills, cloud access, production data access or deployments.
  • No general automatic account classification, unknown-relation exemption, stale-spec weakening, authority union or broad reconciliation refactor.

Acceptance criteria

  • With the actual unchanged v0.5.10 pin, catalog initialization, account inventory, both-direction guards, relationship evidence and existing reconciliation characterization pass; no nonexistent model lookup escapes and no stale CourseEnrollment spec is reported.
  • With the exact model-present contract, the catalog/report contain cb_curriculum.CourseEnrollment.user exactly once with reparent, its real table/column metadata and deterministic inventory checksum. Counts, checksums and row identities include it consistently, and append-only keys do not.
  • Adding an unrelated real reverse account relation still fails the guard; missing/renamed mandatory specs and present CourseEnrollment without its proper user relation fail. Only absence of this one optional model is accepted.
  • A reviewed source-to-survivor merge preserves every active and ended CourseEnrollment row and non-owner field exactly, maintains alias-aware counts/checksums/row identities, and replay creates or changes no history. Existing cohort enrollments/submissions/certificate behavior and survivor-only authority remain covered and pass.
  • Ended history overlaps and active-plus-ended history for the same course merge without loss; active enrollments in different courses remain separate. Two active same-course rows fail closed with complete business-state rollback and the existing redacted denial/quarantine contract.
  • Characterization before/after extraction establishes one catalog/evidence owner and unchanged existing imports; materially changed code satisfies size limits and documentation states the precise course-history handling.
  • Every present issue-owned Python module, including the materially changed inventory facade, is explicitly linted, formatted and strictly typechecked; the facade is removed from the historical baseline only to enroll it. Adoption-gate coverage and strict-module checks pass with no new exemptions. The pyproject diff contains only the named mypy additions, its reviewed hash matches final bytes and still rejects synthetic unreviewed drift; dependency/source declarations, uv.lock, its seal and all other frozen Gate B inputs are unchanged.
  • Engineer and independent tester produce exact candidate verification plans and valid exhaustive evidence reports, with no required skip, stale evidence substitution or pending screenshot requirement. PM acceptance follows tester pass. Real-package P16/adoption evidence is explicitly separate.

Verification scenarios and dispositions

Focused diagnosis and behavior coverage, with the unchanged pinned source:

DJANGO_SETTINGS_MODULE=website.settings.test uv run --frozen python manage.py test accounts.tests.test_course_enrollment_identity accounts.tests.test_single_identity accounts.tests.test_account_reconciliation
DJANGO_SETTINGS_MODULE=website.settings.test uv run --frozen python manage.py account_identity_inventory
uv run --frozen python scripts/ci.py verification-plan
uv run --frozen python scripts/ci.py verification-run
uv run --frozen python scripts/ci.py verification-evidence-check
uv run --frozen python scripts/ci.py verification-report-check

Use the repository's actual lint/advisory entrypoints and migration-drift gate selected by the plan; coding-standard aliases are not grounds to omit a gate if this checkout exposes them through scripts/ci.py. Authentication/shared compatibility impact is expected to select full Django coverage; obey the computed plan rather than narrowing to the focused diagnosis above. Tester independently recomputes the frozen base/head plan and validates each component/environment/output digest and actual counts. Run backend smoke uv run --frozen python scripts/ci.py test-playwright-smoke and any broader browser component the graph requires.

Browser product scenarios and desktop/mobile screenshots: not_applicable if the final diff preserves the specified backend-only boundary, because no page, route, navigation, copy or rendered state changes. Backend browser smoke remains required. If the final graph finds render impact, obtain independent graph-derived screenshots and browser coverage before tester-final; do not force not-applicable.

Repository/operations scenarios: assert unchanged pinned dependency/source declarations and byte-identical lock; review the exact strict-mypy additions, corresponding opt-in paths, one facade baseline removal and sole permitted pyproject checksum update; no source-model/migration/route/template changes, clean isolated worktree ownership, and valid four-bucket report. Production/development live tests, import rehearsal, deployment, package adoption and real migration verification: not_applicable to this repair with the named downstream dependency above. Historical red logs are diagnosis only, never reused successful gate evidence.

Narrow grooming revision: quality-gate integration

The fresh verification attempt correctly stopped at ci.tests.test_adoption_gate_coverage.test_every_excluded_tree_file_is_baseline_or_opted_in. Its four new account modules are required by this issue but were omitted from the groomed gate-configuration scope. Existing coverage rules also require matching strict-mypy enrollment; the materially changed facade must leave its historical exemption. This revision authorizes only the configuration changes listed above and the existing reviewed configuration-only pyproject seal procedure. It does not waive the failure, add baseline exclusions or alter verification/source policy.

After these edits, regenerate the exact candidate plan and evidence from the frozen base/head and final worktree inputs. Configuration edits invalidate the previous handoff/plan and may select broader fresh coverage; obey the computed full plan, including evidence validation, adoption coverage, strict lint/format/typecheck, Gate B seal/drift contracts, required Django and browser components. The reported 66 focused functional tests are diagnosis/engineering evidence only and do not satisfy independent tester-final or PM acceptance. Any remaining red required gate returns to its owning issue under PROCESS.

Lingua principale
Python
Stelle
0
Fork
0
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

  • Include un Dockerfile o un file Docker Compose
  • Nessun modello di pull request
  • Nessuna guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di DataTalksClub/website

Tutte le issue di DataTalksClub/website

Issue simili

Altre issue su Python

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.