# gh-regkit-prime: Camoufox multi-stage GitHub runner — pitfalls & ops Stack: Camoufox (Firefox anti-detect) + mail.cx (mailcx provider) + multi-stage runner (reg → email verify → auto-login → repo → 2FA TOTP → PAT → profile). Project: `Desktop/_PROJECTS/gh-regkit-prime`, repo `gbonnet65923/gh-regkit-prime`. Account line format: `email----password----username----totp_secret----has_recovery----pat`. ## Batch operations (CRITICAL) - NEVER run two registration batches concurrently — they share the exit IP, GitHub DataDome bans it fast and accounts come out `suspended`. Before launching, enumerate and kill leftovers. - Filter processes by `main.py` substring ONLY, not by project path — the CommandLine of a batch started with a relative path (`cd project && python main.py`) does not contain the project directory, so a `path in CommandLine` filter silently misses it and duplicate batches keep running. - Enumerate/kill on Windows (wmic is unreliable here): `powershell Get-CimInstance Win32_Process -Filter "Name='python.exe'" | ConvertTo-Json`, parse JSON in Python, `taskkill /F /T /PID`. - Run batches with `background=true` + heartbeat; report OK/FAIL from the heartbeat log, verify saves by `wc -l accounts/github_accounts_*.txt` (a successful log line without a saved row means the crash happened before persistence — see salvage below). ## Signup form - mail.cx issues short local-parts (4 chars) → derived usernames collide constantly. Pad any local-part shorter than ~10 chars with random alnum BEFORE the first attempt. - "Create account stayed disabled after validation wait" is AMBIGUOUS: it can mean octocaptcha pending OR username taken (a taken name keeps the button disabled forever). Probe the username-error element first and raise a distinct "username taken" error → caller retries with a fresh random suffix in-place. Treating it as transient and reloading the page WITH THE SAME DATA burns all page-reload attempts for nothing. ## 2FA (TOTP) stage - The wizard keeps hidden twin otp inputs in the DOM; `locator(...).first` resolves to an INVISIBLE one and `fill()` hangs "element is not visible" until timeout → stage fails. Iterate candidates checking `is_visible() and is_editable()`; last-resort fill via JS `el.value=code` + dispatch `input`/`change` on the `offsetParent!==null` element. - TOTP secret is frequently absent from innerText (dialog closed / rendered as QR). Parse it from `page.content()`: look for `otpauth://totp/...secret=[REDACTED] in BOTH percent-encoded (`secret%3D`) and plain form, then fall back to a bare `[A-Z2-7]{16,32}` scan. - Recovery codes: scrape from the DOM first. SKIP the file download entirely when the DOM scrape succeeded — Firefox/Camoufox download handling intermittently hangs the whole 2FA wizard (user-visible symptom: hang at the backup-download step). - GitHub regenerates the TOTP secret on every load of the setup page — read the secret only from the page you actually submit the code on. ## PAT stage - The `ghp_...` token often lives in HTML attributes (``, clipboard-value), not in innerText. Search `_page_text(page)` first, then `page.content()`, then wait ~5s and retry both — a single innerText search reports "token not found" on success. - Any helper called from the PAT function needs its own local import (`import re as _re` inside the function) — module-level `re` may not be imported in this codebase shape; a NameError here kills the stage after the token was already generated. ## Crash salvage (account-saving checkpoint) - The browser/driver can crash ("Connection closed while reading from the driver", WebGL out-of-memory) AFTER the account is verified and logged in. If credentials are only persisted at the very end, the account is lost. Set a checkpoint dict (`pending["active"]=True`, `pending["username"]`, email) at the start of the finalize stage, and in the outer exception handler salvage a record line from it when the checkpoint is set. Thread the `pending` dict through the post-form flow function. ## Proxies / DataDome - Free HTTP pool (~125 live) gives roughly 30-60% yield; failures are DataDome challenge pages and dead-proxy connect timeouts. When the home IP itself gets DataDome-banned ("email form did not appear (DataDome challenge page); IP is blocked"), only IP rotation helps — residential proxies. - 1024proxy.com residential: the marketing/pricing site is Cloudflare-blocked from a banned/flagged home IP — open it through Camoufox routed via one of the free pool proxies to read prices. Wallet balance alone does NOT enable the gateways: the white API (`white.1024proxy.com/white/api?region=US&num=N&time=M&format=0&type=json`, cookie `zero_sid` auth, navigate not fetch — CORS) returns "Insufficient traffic" until a traffic package is purchased; gateways answer raw CONNECT with 407. Purchase only via the dashboard UI (Buy button); raw api.1024proxy.com calls from Python return "re-login" errors — they need the browser session context. ## Config knobs that silently disable stages - `create_repo`, `set_profile_status`, `complete_profile` can be False in config.json even when the dataclass defaults are True — a warmed-up account (profile + first repo) requires flipping them explicitly in config.json AND restarting the batch (a running process holds the old code/config in memory).