The teaching access manager sends minimal desired eligibility to the private controller. Intakes before 2026-09-01 remain legacy-only. Intakes on or after that date require Passport when Incoming/Active. The sheet retains the start date; the controller receives GitHub identities and access decisions only.
State And Confirmation#
| Requested transition | Expected private confirmation | Preserved history |
|---|---|---|
| Enroll/activate | Persisted request receipt and matching active projection | Existing completion and compatible assignment |
| Depart | Inactive projection and archived assignment | Public fork, answers, attempts and completion |
| Return | Active projection after holds/compatibility review | Frozen identities and historical records |
Dispatch acceptance alone is not confirmation. For a first submission waiting on activation, jump to submissions before activation; do not ask the learner to rewrite correct work. JSON/concurrency below is administrator reference, never a student setup step.
Administrative contract#
sync-enrollments.yml accepts a version-1 batch from the teaching client, checks
immutable GitHub IDs and expected access revisions, and applies at most 100
changes in one private transaction. operations/enrollment-access.json is the
minimal client projection. registry/enrollment-requests/ holds immutable request
receipts; the current projection must also match before the client marks a
student complete in the sheet. No-op client runs dispatch nothing.
The JSON request contains schema_version, changes, and request_id. Each
change has github_user_id, github_user, status, reviewer, reviewer_id, and
expected_revision. Status is active or inactive; inactive requests have null
reviewer fields. The request ID is SHA-256 over the UTF-8, sorted-key compact JSON
body without request_id. Old username-only enrollments are validated against
GitHub before receiving numeric IDs. Version-2 enrollments preserve inactive
records rather than deleting them.
Departure disables eligibility even if the learner never started. Existing assignments become archived; answers, counters, routes, public forks and completion records are retained. A departure can be reversed for returning students. Security holds, unknown manual archives, reviewer changes, and incomplete assignments from an incompatible curriculum require administrator review. Completed training stays complete across release changes. Username changes do not silently rewrite frozen assignment branches or repository identities.
Concurrent operations#
All enrollment, lifecycle, and assessment workflows share one authority queue and
check out the latest default branch after acquiring it. An assessment already
running can finish before deactivation; once the deactivation receipt is committed,
no older assessment can restore its active state. Queued runs are retained up to
GitHub's bounded queue capacity using queue: max; see the
GitHub concurrency reference.
A full queue or cancelled/failed run never counts as a confirmed enrollment.
Source CI remains separate and is not dispatched by eligibility changes.
Submissions made before activation#
A learner can submit their first lesson before their eligibility reaches the
controller. The original PR webhook then has no authorized assignment to assess.
After a successful Sync Passport eligibility, Enroll one learner, or
Enroll a learner cohort run on private main, a
workflow_run completion event
queues assess.yml. Failed or cancelled enrollment runs do not start discovery.
The assessment acquires the existing authority queue, checks out the latest default branch, and registers and assesses currently eligible pending work. It consumes no artifact or learner checkout from the enrollment workflow and requires no additional token permission. A later departure or hold is respected; an unchanged revision with a trusted result is skipped. Replaying a successful enrollment run cannot add another assessment attempt for that revision.
Expected result: a valid submission made before activation receives its normal assessment without another learner edit or push. Check the follow-up assessment run and the trusted Check Run on the submitted revision. GitHub scheduling can still delay execution; the sparse scheduled recovery remains a fallback. If the follow-up fails or is absent, inspect the private workflow and use the existing manual assessment recovery after confirming eligibility. Do not ask the learner to reset their Passport or rewrite correct work to trigger a check.
The dashboard explains that a first result may be waiting for activation and provides the 30-minute help path. It cannot confirm private enrollment state and must not present a missing check as proof of an inactive enrollment.
Deployment and verification#
Human intent: synchronize authorized student access while preserving training history. Context: the teaching sheet decides eligibility; private authority records and registry files decide Passport state. Constraints: no public workflow, learner checkout, research data, or App private key belongs in the teaching client.
Export using the existing controller deployment procedure
and --update-existing. This preserves enrollments, assignments and the entire
registry, including receipts. Review the diff before deploying. Do not replace the
private repository with a fresh export. Prepare the new client only after this
workflow and its access projection are deployed. Existing credentials need private
control Contents read and Actions write; controller App private keys stay private.
Verification: run the local Python and workflow-contract suites and inspect a teaching dry-run before enabling real batches. Test a new enrollment, departure before startup, departure after progress, repeat request, return, administrative hold, and incompatible curriculum. The client must refuse to mark the sheet complete without a persisted receipt and matching current state. A rejected stale revision requires a fresh dry-run; it must not overwrite the newer authority.
Review criteria: unchanged cohorts dispatch nothing, history survives lifecycle changes and controller exports, no frozen assignment is reset, and retrying a request cannot duplicate transitions. Understand before accepting AI output: explain why eligibility differs from training completion and why dispatch acceptance is not a completion receipt. Use the private controller administrator for recovery; never clear a hold or delete history merely to make synchronization green.