This runbook is for the IDEAL Lab IT administrator. The active 2026 service uses
IDEALLab/onboarding-IT as source and soheylm-passport-sandbox for the three
runtime repositories. For compatible releases, use the routine-update matrix
below. Initial provisioning and first-cutover gates remain as reference; do not
recreate working Apps, secrets, learner forks or control records.
Repository Actions are disabled on IDEALLab/onboarding-IT. Do not re-enable
them or add a source-side workflow. Source validation is dispatched to the
private sandbox control repository described below.
Routine Compatible Update#
| Change | Artifacts | Required verification |
|---|---|---|
| Lesson copy/navigation | Website and compatible launcher; generated exercise/controller exports when changed | Full source checks, desktop/mobile and three-engine journeys, contract comparison, release assets and synthetic reopen |
| Controller behavior | Reviewed private control export | Accepted/rejected agreement, protected-state diff and trusted status behavior |
| Required assessment meaning | Versioned curriculum, website, launcher, exercises and controller | Owner-reviewed contract/migration and old complete/draft/pending/new learner cases |
Build from one exact reviewed source. Preserve protected assignments, history, enrollments and registry; keep the previous compatible release available. Publish only after qualification, then compare the live website with the reviewed build and verify the downloaded launcher. Provisioning below is for a new service.
1. Build From One Reviewed Revision#
From a clean reviewed onboarding-IT commit:
python3 scripts/export_exercises_repo.py /tmp/passport-exercises
python3 scripts/export_gh_passport.py /tmp/gh-passport
git clone git@github.com:soheylm-passport-sandbox/onboarding-control.git /tmp/onboarding-control
python3 scripts/export_onboarding_control.py --update-existing /tmp/onboarding-control
python3 scripts/render_deployment_assets.py --check
Diff each export before pushing. Exercises and launcher are public;
onboarding-control is private. The initial overhaul branch cutover is historical.
For a routine update, embed the exact reviewed source and publish the qualified
main tree; do not reinterpret or replace existing learner assessment records.
Never replace the control repository with a fresh directory or use an
unqualified rsync --delete: assignments, enrollments, registry events, and
completion records are append-only operational state. --update-existing
refuses a dirty clone, a branch other than main, or an origin other than the
configured control repository. It preserves trusted state while replacing
generated code and rebuilding the operational views.
Generated Public Browser Qualification#
Each launcher export now includes qualification/ and a local reusable WebKit
workflow. Run the export from one clean reviewed source; --skip-web-build
requires the matching current and compatibility build proofs. Missing proofs,
modified or extra assets, and mismatched source revisions stop the export.
Rebuild rather than relabelling an old bundle. Dirty preview exports remain
available locally, but cannot pass the public qualification verifier.
The exporter copies the unchanged tracked browser cases and only their public fixtures. It serves the launcher's actual embedded pages. A public-repository preflight runs before allocating a Mac; tag builds require the complete WebKit result and native tests. Keep other final source/controller/browser gates. No learner version, existing progress or production permissions change here.
Local reusable workflows run from the caller's commit and context; a public callee does not make a private caller's runner usage free. See GitHub reusable workflow rules. Use the generated README for local verification; never upload the private checkout or protected records. Only ordinary standard public runners are used.
2. Publish The Static First Contact#
Build the stateless browser product locally from the reviewed revision:
PNPM=pnpm python3 scripts/build_web.py \
--source-ref "$(git rev-parse HEAD)" \
--site-url https://ideal-passport.pages.dev
cd platform/cloudflare-worker
pnpm install --frozen-lockfile
pnpm exec wrangler pages deploy ../../web/dist --project-name ideal-passport
Expected: Cloudflare prints the deployed HTTPS URL. Open /getting-started/
without GitHub login and verify all internal links. This Pages project stores no
learner identity or progress and needs no GitHub repository access or secret.
3. Protect Public Exercises#
Protect passport-exercises:main: require PRs and conversation resolution,
disable force pushes and deletion, and require the trusted controller Check Run
once live. Keep the repository free of privileged workflows and secrets.
4. Configure Two GitHub Apps#
Controller App#
Install only on passport-exercises:
| Permission | Level |
|---|---|
| Metadata | read |
| Contents | read |
| Checks | read/write |
| Issues | read/write |
| Pull requests | read/write |
Subscribe only to Pull request. Configure the deployed Cloudflare Worker as
Webhook URL and a new random webhook secret. Store this App's client ID and
private key only in private onboarding-control as
CONTROLLER_APP_CLIENT_ID and CONTROLLER_APP_PRIVATE_KEY. The immutable App
ID must match platform/deployment.json and the launcher release.
Dispatch App#
Install only on private onboarding-control:
| Permission | Level |
|---|---|
| Metadata | read |
| Actions | write |
Do not subscribe it to public events. Put its App ID, installation ID, and PKCS#8 private key only in Cloudflare Worker secrets.
5. Deploy The Signed Worker#
Follow platform/cloudflare-worker/README.md. Review wrangler.toml, run the
local Worker tests, enter six secrets through hidden Wrangler prompts, deploy,
and update the Controller App webhook URL. Never broaden either App installation
as a debugging shortcut.
A successful webhook forwards only delivery ID, exercise repository, PR number,
and head SHA. GitHub's delivery log must show 202 controller_dispatched.
6. Route Source CI To The Sandbox#
Export platform/onboarding-control so that source-ci.yml,
validate_source_ci_event.py, and classify_source_ci.py exist on the control
repository's main branch. Configure these two credentials:
- Create one dedicated Ed25519 deploy key. Add only its public key to
IDEALLab/onboarding-ITas a read-only deploy key. - Store only its private key in the private control repository as
SOURCE_REPOSITORY_DEPLOY_KEY. - Generate a new random webhook secret and store it in Cloudflare as
SOURCE_WEBHOOK_SECRET. - Add a repository webhook to
IDEALLab/onboarding-ITwith the Worker URL ending in/source-ci, the same source secret, JSON content type, SSL verification, and only Pull requests selected.
Keep Actions disabled at repository level on IDEALLab/onboarding-IT. A push to
a same-repository PR must create one fast run in
soheylm-passport-sandbox/onboarding-control and zero runs in IDEALLab. The
automatic suite is one Ubuntu job and cancels obsolete revisions. Run the
release suite manually only before a release; it expands to exactly three OS
jobs and three browser jobs (Chromium/Firefox on Linux, WebKit on macOS);
Chromium also packages the launcher. Finish local checks before dispatch, and
rerun only failed jobs for the same exact source SHA during diagnosis.
The sandbox run does not become an IDEALLab-hosted Check Run. Review its exact PR number and head SHA in the private Actions run before merging source. Do not replace the read-only deploy key with a personal access token or give it write access.
7. Lock Cost#
The private workflow has one serial assessment per changed learner SHA, bounded job timeouts, and workflow concurrency. A recovery cron runs only four times per day. No large runner is allowed.
Before enabling a cohort:
- confirm the sandbox organization has no payment method, so usage stops at included quota; or
- if a payment method exists, set a GitHub Actions product budget with Stop usage when budget limit is reached.
Keep usage alerts enabled. Measure minutes after five synthetic learners and project the full cohort. A notification is not a spending lock. The owner confirmed a 50 USD monthly Actions budget on 2026-10-15. Read metered usage before paid qualification, keep the stop-usage setting enabled, and stop discretionary CI at 75% of the budget to retain student capacity.
8. Publish The Launcher#
The release workflow tests and emits Windows x64, macOS x64/arm64, and Linux
x64/arm64 binaries. It generates release compatibility metadata from
SOURCE.json. Tag the reviewed matching release, then test:
gh extension install soheylm-passport-sandbox/gh-passport --force --pin v0.12.1
gh passport version
For an existing compatible Passport, also open the older launcher, press Update and reopen, and verify that the new launcher reopens the same current mission. Force one update-verification failure in a disposable qualification fixture and confirm the previous launcher is restored. Do not publish a release whose compatibility marker names a different curriculum.
On Apple Silicon, verify both boundaries: the downloaded release asset must match GitHub's raw SHA-256 before installation, and the installed executable must match the deterministic ad-hoc signing transformation performed by GitHub CLI. A raw post-install checksum comparison is invalid because that signature changes the file.
The update API returns a saved success or rollback only when its recorded launcher version matches the launcher serving the dashboard. Keep this check on both the local API and browser renderer so a later manual installation does not present a stale rollback as a current failure.
Do not ask learners to bypass Gatekeeper, SmartScreen, antivirus, or execution policy.
9. Enroll Learners#
Enroll GitHub usernames and one operational reviewer asynchronously in private
onboarding-control. Do not store operating system, answers, credentials, or
research context in enrollment. The learner starts from the public first-contact
page and does not join the sandbox organization.
Registration derives one exact editable allowlist from the frozen mission
route: each assigned submission receipt plus only that mission's declared
artifacts. Re-registering an active assignment repairs an older allowlist
without changing its identity, route, branch, PR, baseline, attempts, or
history. When a repair occurs, a private manifest_reassessment_required
marker queues the same public commit again without clearing its recorded SHA or
counting another attempt. The controller removes the marker only after it
publishes the replacement assessment. Never replace this migration with a
broad workspace/** rule or ask the learner to purge their Passport.
10. Production Transaction#
Before invitation, use a non-admin synthetic learner to prove:
- no public artifact exists before browser consent;
- start creates exactly one personal fork and central draft transport PR;
- a mission submission causes one signed Worker dispatch;
- the controller assesses the exact SHA without credentials or network;
- the expected trusted App publishes one Check Run and sanitized feedback;
- wrong signature/repository/App/branch/SHA inputs cause no assessment;
- an unchanged redelivery does not increase attempts or duplicate records;
- completion writes one private record, closes without merging, and resumes;
- public help works asynchronously without a secret or private log.
11. Cutover And Rollback#
After qualification, merge the reviewed onboarding branch, change
handbook_ref to main, rebuild all four products from the same commit, and
publish the first-contact URL. Rollback pins a previously reviewed matching
curriculum, launcher, exercises, controller, Worker, and static build. Never
delete public records or private completion history.
Production Gates#
- Static first contact is public and tested without authentication.
-
passport-exercisesis public and protected. -
gh-passportis tagged and installable on clean Windows, macOS, and Linux. -
onboarding-controlis private with controller credentials configured. - Controller App is limited to
passport-exercises. - Dispatch App is limited to
onboarding-control. - Cloudflare Worker signature and real webhook transaction pass.
- Owner confirmed a 50 USD/month Actions limit on 2026-10-15; metered usage is checked before manual paid runs.
- Source PR webhook dispatched one sandbox CI run and zero IDEALLab runs on 2026-09-06.
- Scheduled recovery and exact-SHA assessment succeeded in the sandbox on 2026-09-02.
- One synthetic non-admin learner completes the full public-record loop.
- Real Euler CPU, NAS, Blade, and Windows SSH pilots pass where claimed.
- No privileged key appears in public code, workflow, artifact, or log.
- The overhaul PR is reviewed and remains unmerged until cutover approval.