DataTalksClub / DataTalksClub/website

Prove whether the courses-focused Django closure can be reduced

Open
#240 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

courses enhancement infra P1 testing
Dominant language
Python
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Description

Product outcome

An ordinary backend-only change owned exclusively by courses/ may run a smaller focused Django closure only when repository evidence proves that every omitted application suite is behaviorally independent of that change. The resulting selection must be materially smaller and faster than the current reviewed closure without reducing the full scheduled safety net or changing product behavior.

This is #228 Slice C and remains a later optimization. Slice A stays shipped and accepted; #238 owns Slice B's smoke/budget measurement. This issue does not reopen either contract.

Normative authority

  • _docs/PROCESS.md: lifecycle, exact verification plan, independent testing, and on-call ownership.
  • _docs/ci/change-selective-ci.md: ownership graph, focused/full rules, exact evidence, fail-closed selection, and the four-hour scheduled backstop.
  • _docs/specs/10-verification-strategy.md: risk-based local coverage plus independent scheduled full coverage.
  • _docs/architecture/app-boundaries.md: courses is the database-owned course/cohort/learner domain; public, Studio, API, jobs, and shared boundaries may consume it only through reviewed dependencies/services.
  • _docs/audits/2026-08-20-ci-smart-test-selection-audit.md, items 3 and 5: reverse-import gaps and the oversized courses closure.
  • Closed #207 and #209: deterministic AST reverse-import enforcement and parallel/non-interactive focused Django execution.
  • Parent #228 and #238's accepted release-budget definition.

Current evidence

At the historical pre-recovery baseline 9a491cd9baeb1e723bd05e8dacb20978fbaf9d33:

  • app.courses closes over these exact downstream nodes:
    django.accounts, django.api, django.content, django.content_sync, django.core, django.courses, django.data, django.management_api, django.studio, and django.studio_courses.
  • The resulting labels are:
    accounts api content.tests content_sync core courses data management_api studio studio_courses.
  • The graph and pinned ownership test contain all ten labels. The prose table currently omits content_sync; engineering must treat graph/test bytes as the current executable baseline and reconcile the prose with the final proved closure.
  • Focused execution already uses manage.py test --parallel --noinput <validated labels>.
  • The accepted #209 historical measurement predates the current ten-label closure: a nine-label courses selection ran 2,088 tests in 86.159s in one tester environment; a later current-state run reported 2,117 passed, 1 skipped in 164.491s. Those measurements are useful context but are not comparable enough to authorize narrowing.
  • The current AST contract inspects repository-local production Python for verification-labeled packages, direct absolute imports and literal dynamic imports; ambiguous dynamic import fails. It does not by itself prove ORM, URL, signal, service, factory, fixture, or string-based runtime independence.
  • The latest scheduled full regression, run 33315212334 at face8e4808d65afbf0374d1ced7a88079950d663, completed failure: selector, factories, container, and Playwright quarantine passed, while quality, migrations, Django, Playwright, full-regression, and scheduled-gate failed. It predates #238, has no successful selected full-regression verdict, and cannot be the exact post-#238 baseline anchor required here. There is still no qualifying green scheduled baseline or nonzero validated #238 duration sample.
PM feasibility ruling at the current graph granularity

The current closure cannot honestly be narrowed by retaining one integration test while dropping its application label. The focused executor accepts graph-derived Django labels only; expanding ownership/selection/execution to individual test node IDs is outside this issue. A direct production import of courses therefore retains the importing label with no retained-node exception. Current inventory finds direct production imports in accounts (1), api (36), content (2), content_sync (2), core (1), management_api (1), studio (1), and studio_courses (18). data has no production import but owns 26 course-coupled tests; because the executor cannot select those nodes separately, data also remains. courses always remains.

Accordingly, all ten current labels are presently retained and a strict-subset optimization is not feasible under this issue's bounded architecture. Engineering, after the dependency gate, starts with the deterministic structural proof only. If the refreshed exact baseline reaches the same result, the accepted outcome is proof of no benefit: preserve the graph unchanged, skip meaningless timing/candidate work, independently verify the proof, and return to PM for no-benefit acceptance/closure. It is not acceptable to invent per-node selection, weaken integration ownership, or manufacture a smaller list.

Dependencies and no-start gate

Do not start engineering until every condition below is true. Grooming readiness does not waive this block.

Before the numbered gate can begin, the shared recovery baseline must complete in order #261 → #253 → #279 → #223 → #270, including the external-source prerequisite and re-grooming required by #253. A changed base invalidates prior plans and evidence.

  1. #232 receives independent tester PASS and PM acceptance on the ordered combined tree.
  2. #236 receives independent tester PASS and PM acceptance on that exact ordered tree.
  3. Their focused commits merge in #232 then #236 order and are pushed as one accepted main state.
  4. That exact combined main SHA records playwright, screenshots, ci-gate, publish, and deploy successful, and the deployed host reports the sealed identity healthy/ready.
  5. #238 is implemented, independently tested, PM-accepted, merged, and observed on-call with at least one valid eligible ordinary-main sample. Its report must have a nonzero verification sample and use verification_seconds = ci-gate.completed_at - classification.started_at; unavailable or an empty sample does not qualify.
  6. After #238 merges, one exact clean main SHA becomes this issue's baseline state. That same SHA must record release CI/deploy green and a subsequent scheduled-full-regression selected full-regression job success. The scheduled artifact's graph, policy, and verification-input digests must match the baseline pinned by #240. A pre-#238 pass, different SHA/state, selector-only unchanged-state skip, cancelled run, or missing/malformed artifact does not qualify. If main or any relevant verification input advances before engineering starts, a new matching scheduled anchor is required.

The engineer records the exact dependency run IDs/attempts, SHAs, graph/state digests, outcomes, and #238 sample evidence in the handoff. Do not dispatch, rerun, or create a no-op commit to manufacture any prerequisite.

Scope

1. Freeze a comparable baseline

After the no-start gate opens, pin one exact clean main baseline SHA, ownership graph digest/policy, Python/Django/uv/OS/architecture/runner/database fingerprint, and the exact successful scheduled-state anchor.

Use the deterministic synthetic ordinary change:

  • event push;
  • one ordinary modified path: courses/registration.py;
  • no migration, template, static, HTML, shared, dependency, configuration, test-infrastructure, or second-app path;
  • valid exact fixture base/head identities.

Before changing the graph, record:

  • classification profile/reason;
  • direct and transitive nodes;
  • the exact ordered ten-label baseline closure;
  • exact collected Django test node IDs and total count;
  • collection result/count and collection-output digest.

Only if structural proof identifies at least one removable whole label, run the current closure three successful measured times after one unmeasured warm-up, on the same source tree and environment with no other project test/build workload. Then record attempted/passed/failed/skipped counts, command/output digests, each duration, and the three-run median. Partial, failed, timed-out, differently fingerprinted, or contaminated runs are not samples.

2. Produce proof for every baseline label

Create a versioned, deterministic proof inventory for every baseline label. A label stays in the closure unless all applicable evidence below is complete and unambiguous.

Reverse-import proof
  • Scan every verification-labeled repository application package and relevant test-support source without importing/executing it.
  • Cover absolute imports at any lexical scope, literal __import__/import_module, aliases, and resolvable relative imports.
  • Any non-literal dynamic import, parse failure, symlink/escape, unknown application, unowned source, unsupported syntax/encoding, or missing verification label fails closed.
  • Every package that can import courses directly or through a reviewed graph edge remains in the courses closure.
Behavioral-boundary proof

For each candidate label, deterministically inventory both production and test paths for:

  • imports/calls of courses models, services, capabilities, forms, views, URLs, commands, template tags, or public module contracts;
  • Django model relations, reverse relations, app-registry/content-type lookups, string model references, signals, receivers, system checks, admin registration, and management-command discovery involving the courses app;
  • URL inclusion/reversal, route names, middleware/context processors, serializers, permissions, and presentation/API/Studio adapters that reach courses behavior;
  • app-local tests, fixtures, factories, setup hooks, and helpers that create/query/mutate course/cohort/registration/enrollment/homework/project data or assert courses side effects;
  • settings or runtime registration that couples the candidate application to courses.

Each inventory hit keeps the candidate application label. This issue does not add individual-node ownership, selection, execution, or evidence semantics, so naming a retained test node cannot justify dropping its label. A prose assertion, a green run alone, or “no top-level import” is not proof. Unknown strings/reflection, conditional/plugin loading, global/shared fixtures, or an integration whose owning test cannot be identified retains the label or forces full.

The checked structural proof uses canonical paths ci/courses_closure_proof.schema.json and ci/courses_closure_proof.json. It binds the baseline SHA, graph/policy digest, scanner version, inspected path manifest/digest, every baseline label, all hits, owning integration tests as explanatory evidence only, per-label disposition/reason, and final closure. It contains repository-relative paths/symbols only—no source bodies, credentials, test data, environment facts, or secrets. Deterministic scanner/schema/manifest tests keep it current.

Raw commands, collected node IDs, output, environment fingerprints, and wall-clock samples are point-in-time evidence under .tmp/verification/issue-240/ and the versioned verification report; they are never committed. The engineer handoff and tester report record their paths and SHA-256 digests. Only deterministic structural facts belong in the checked manifest.

3. Change only the proved courses closure

If and only if the structural proof identifies at least one removable whole application label, continue to paired measurement. If the proof retains all ten labels, take the no-benefit path below and do not change the graph. For a measured candidate that passes:

  • update app.courses downstream verification nodes;
  • update the pinned application-closure table, classifier/selection fixtures, proof manifest/schema, reverse-import/behavioral-boundary tests, and CI documentation together;
  • bump the graph policy version when required by the versioned graph contract;
  • keep django.courses and every proved consumer/integration label;
  • leave every other application closure and component ownership unchanged.

The narrower closure applies only to profile=focused / reason=single_application for exactly one ordinary app.courses owner. It never overrides full-run guards.

4. Compare candidate and safety boundaries only when a candidate exists

On the identical candidate source/environment:

  1. run the frozen old ten-label closure green;
  2. run the proposed closure with one warm-up plus three successful measured samples;
  3. run every removed label explicitly green;
  4. run the complete Django suite green;
  5. run ownership, graph schema/digest, reverse-import, behavioral-boundary, classifier, selection, focused-runner, verification-plan/report, scheduled-workflow, and CI contract tests green.

Candidate duration is the median of its three samples. Counts compare exact collected node IDs, not only console totals.

Measurable acceptance

The optimization proceeds only when all are true:

  • the candidate label list and collected-node set are strict subsets of the baseline;
  • collected test count is at least 20% lower than baseline;
  • candidate median wall-clock is at least 20% lower than baseline;
  • the absolute median saving is at least 20 seconds;
  • all three candidate samples succeed, and the slowest candidate sample is still faster than the baseline median;
  • old closure, each removed label, full Django, and all policy/selection checks are green;
  • #238's metric remains verification_seconds; no local duration is relabeled as a release SLO result.

If structural proof retains all ten labels, or any measured candidate cannot meet every threshold honestly, keep the ten-label closure unchanged and take the explicit no-benefit outcome: preserve the checked proof/scanner/tests/docs, post the exact evidence, receive independent tester PASS and PM acceptance that no safe material optimization exists at label granularity, and close #240 without claiming a speedup. A no-benefit candidate must not change ci/ownership.json, graph policy/version, any application closure, selection behavior, or runtime command. A smaller label list without both count and runtime improvement is neither optimization delivery nor proof of no benefit.

Fail-closed and rollback rules

  • Unknown/unmapped paths, dynamic/reflection ambiguity, shared core/accounts runtime, authentication/security/privacy impact, migrations, templates/static/HTML, dependencies, test infrastructure, graph/policy changes, cross-app ranges, special file modes, or unavailable provenance continue to select full Django.
  • A missing/changed proof manifest, scanner failure, new boundary hit, changed app/model/fixture registry, missing test label, collection drift, digest mismatch, benchmark contamination, or evidence failure blocks narrowing; it never silently uses the smaller closure.
  • Scheduled full regression remains every four hours, read-only, full quality/factory/migration/Django/local-Playwright/container, with remote/live tests excluded. This issue cannot weaken its selection, timeout, gate, queued concurrency, or evidence.
  • Before merge, any red proof, old-closure, removed-label, candidate, full-Django, or policy gate restores the exact baseline closure in the candidate; no partial narrowing is handed off.
  • After push, any release regression attributable to this change returns through #240. For an optimization, the first new-state scheduled full failure also returns through #240, and rollback is the focused revert of the courses graph/proof/docs delta to the recorded ten-label baseline; do not delete tests, add skips/retries, disable the scheduler, or broaden an unrelated product change.
  • For an optimization, a scheduled pass from the pre-change graph state cannot cover the new graph state. A no-benefit proof changes no graph/selection state and relies on the exact matching post-#238 scheduled anchor required above.

Non-goals

  • No application, model, migration, service, URL, API, Studio, template, CSS, JavaScript, auth, database, or product behavior change.
  • No test deletion, move solely to evade selection, assertion weakening, xfail, skip, retry, quarantine, or changed Django discovery semantics.
  • No change to other application closures, classifier Git-range semantics, ownership of paths, release gating, evidence reuse, browser tiers, screenshots, container, publish/deploy, #238 metrics, or #239 live smoke.
  • No removal of --parallel --noinput, no worker-count tuning presented as closure proof, and no comparison across different source/environment fingerprints.
  • No claim that AST imports alone prove safety.
  • No workflow dispatch/rerun or scheduled-run trigger by engineer/tester.

Acceptance criteria

Dependency and baseline evidence
  • Every no-start dependency is satisfied with exact linked SHA/run/attempt/state evidence.
  • The baseline synthetic courses/registration.py change selects focused/single_application and the exact ten graph-derived labels stated above.
  • The exact post-#238 baseline SHA/state has matching green release/deploy and selected scheduled-full evidence; the scheduled graph/policy/verification-input digests match the #240 baseline.
  • Baseline manifest records exact nodes, test IDs/counts, command/output digests, environment, graph, policy, and scheduled anchor. Three timings/median are required only if structural proof finds a removable whole label.
  • Historical #209 numbers are context only and are not mixed into the paired benchmark.
Proof and selection
  • Every baseline label has complete reverse-import and behavioral-boundary inventory. A direct import or behavioral hit retains the whole label; owning test nodes are recorded for explanation and never used as partial-label selection.
  • Ambiguous dynamic/reflection, ORM/app-registry, URL/signal/command, fixture/factory, missing-label, unowned-path, and malformed-source fixtures fail closed.
  • ci/courses_closure_proof.schema.json, ci/courses_closure_proof.json, graph, docs, schema/policy, pinned closures, and tests agree on the exact final label order; timing/environment evidence exists only under .tmp/verification/issue-240/ and is digest-referenced in reports.
  • If an optimization exists, only an ordinary courses-only owner can receive the smaller closure; every existing full guard remains full. The no-benefit path changes no selection.
  • Every other application closure is byte-for-byte unchanged.
Correctness and outcome
  • For optimization delivery, old closure, candidate closure, each removed label, and full Django all pass on the exact candidate tree/environment. For proof of no benefit, the exact old closure, full Django, structural proof, and policy tests pass; candidate/removed-label timing is not_applicable because no removable whole label exists.
  • Optimization delivery requires candidate collected IDs to be a strict subset with at least 20% fewer tests and no collection/import failure; proof-of-no-benefit delivery instead proves all labels retained and leaves selection byte-for-byte unchanged.
  • Optimization delivery requires candidate median at least 20% and 20 seconds faster, with every candidate sample faster than baseline median; this criterion is not_applicable for the proved all-labels-retained path.
  • Focused ownership/selection/proof tests, make test-ci, lint, format, typecheck, security, migration, Django checks, and versioned verification plan/run/report pass.
  • The four-bucket report has no required skip/reuse ambiguity. This internal CI policy change has render.impact=false; screenshots are not_applicable with the computed reason.
  • Independent tester recomputes the exact structural manifest, labels, collected node IDs/counts, and digests, validates every hit/disposition, and reruns applicable old/new/removed/full boundaries. For timings, the tester repeats the same commands/sample protocol under a matching normalized fingerprint and independently recomputes medians and threshold predicates; raw duration values are expected to vary and need not match the engineer byte-for-byte.
  • PM accepts the frozen candidate from the release-operator perspective.
  • [ON-CALL] The accepted push passes release CI. An optimization uses Refs #240 and remains open until its first matching selected scheduled full regression passes. A no-benefit proof may close after green release CI because graph/selection are unchanged and the exact post-#238 baseline scheduled anchor already passed. Any required failure is routed, never called green.

Scenarios

  1. Repository — proved removal: a label has no production/test/ORM/runtime boundary hit; old and removed-label suites pass; candidate collection remains complete and crosses both improvement thresholds.
  2. Repository — real consumer: Studio/API code or tests reach a courses service/model/route; that whole application label remains; an exact owning integration test is explanatory evidence, not a partial-selection escape.
  3. Repository — ambiguous runtime: non-literal import, app-registry string, generic relation, signal registration, or unknown fixture cannot be resolved; narrowing fails closed.
  4. Repository — unsafe range: courses plus another app, migration, template, shared runtime, dependency, or graph-policy path selects full regardless of the smaller courses closure.
  5. Repository — proof of no benefit: direct/behavioral coupling retains every whole label; graph/selection remain unchanged, candidate timings are not run, and independently verified structural evidence supports PM no-benefit closure.
  6. Repository — false optimization: one or more labels appear removable but count/runtime thresholds fail; baseline closure remains and the no-benefit evidence is returned to PM.
  7. Operations — graph state changes: the prior scheduled anchor no longer covers the candidate graph digest; a fresh selected full run is required.
  8. On-call — regression: release or scheduled full is red on the new graph state; revert only this closure delta to the recorded baseline and rerun through the lifecycle.

Lifecycle handoff

After all dependencies open the gate, engineer first refreshes the structural proof in an isolated worktree without commit/push/workflow dispatch. If every label remains, engineer stops before benchmarks/graph edits, runs the applicable versioned plan, and freezes the proof-of-no-benefit candidate. If at least one whole label is removable, engineer records paired evidence and attempts the thresholds. Independent tester reruns the applicable proof, selection, and measurements; exact timing values need not match, but method/fingerprint validity and derived threshold decisions must. PM accepts either a fully proved material optimization or an honest no-benefit result with unchanged graph/selection. The focused commit uses Refs #240; orchestrator merges/pushes; on-call observes release CI. An optimization additionally remains open for its first matching selected scheduled full regression; a no-benefit proof may close after accepted merge and green release CI because selection/graph state did not change.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

First read _docs/PROCESS.md and _docs/ci/change-selective-ci.md, then verify the ordered dependency gate and the required post-#238 scheduled baseline before starting. Inspect the existing courses graph, ci/courses_closure_proof.schema.json, and related scanner tests; done means a deterministic proof and accepted no-benefit result, or a measured, independently verified closure update with matching documentation and tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
django, python
Domain
ci-cd, testing-qa
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.