# Success-record review and Luban one-by-one runner fixes (2026-05-11) ## Why this review was needed BOSS asked to deeply revisit the known phone-verification success records and compare them with the current Luban flow. The immediate trigger was a Luban France event where a code was received but OpenAI stayed on `phone-verification`, followed by a one-by-one test that ended with: ```json {"bought":4,"sms_received":0,"sms_timeout":2,"submit_no_sms_page":2} ``` The current OpenAI page then showed `糟糕,出错了!` on `https://auth.openai.com/add-phone`. ## Success records reviewed ### 1. 5sim Vietnam success, 2026-05-10 Reference: `openai-phone-free-country-vietnam-sms-success-codex2api-region-block-2026-05-10.md`. Key success properties: - Strict country/area-code gate before buying and again before submit. - Count only actual provider activations. - If OpenAI reaches `phone-verification`, poll provider. - Submit a strict 6-digit code. - Consider phone success only when OpenAI leaves `phone-verification` and reaches `about-you` / profile. ### 2. 5sim Indonesia success at 335 activations, 2026-05-11 Reference: `openai-phone-335-success-cpa-oauth-login-session-pitfalls-2026-05-11.md`. Key success properties: - OpenAI phone codes should prefer strict 6-digit extraction. - Do not mark provider activation as finished until browser leaves `phone-verification`. - A wrong parser selected a 4-digit candidate from a provider blob; rechecking the finished activation and extracting a 6-digit code fixed it. - After phone success, fill `about-you` fields explicitly (`name`, `age`, `birthday`). ## Defects found in the current Luban one-by-one flow ### Defect 1 — submit-code method not identical to successful 5sim method The current Luban runner used a generic `setVal` with plain `Event('input')` in one path. The successful 5sim submit used: ```javascript const input=document.querySelector('input[autocomplete=one-time-code], input[name=code], input'); const setter=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,'value').set; input.focus(); setter.call(input, code); input.dispatchEvent(new InputEvent('input', {bubbles:true, inputType:'insertText', data:code})); input.dispatchEvent(new Event('change', {bubbles:true})); click exact '继续'; ``` Fix: use this exact method for OpenAI phone-code submit. ### Defect 2 — Bad Request / OpenAI error state was not fatal enough The one-by-one run continued country gates after OpenAI became: ```text title: 糟糕,出错了! - OpenAI url: https://auth.openai.com/add-phone ``` The page had no usable country selector/tel input for later countries, producing repeated false country-gate failures. Fix: add `ensure_add_phone_ready()`: - require `add-phone` URL, country `select`, and tel input; - reject pages whose title/body match `糟糕|出错|Bad request|unknown_error|HTTP ERROR`; - try reload/direct navigate a few times; - if still not ready, stop the runner before buying another number. ### Defect 3 — Luban release retry was too shallow France `34133707` initially returned: ```text 停用失败,该供应商需要在:118 秒 后停止. 停用失败,该供应商需要在:43 秒 后停止. ``` The runner stopped retrying, requiring manual cleanup. Later manual check showed `该号码已释放`. Fix: `reject_after_min_wait()` now loops until: - `success`, or - `已释放`, or - `wrong_status`, or - hard retry deadline. It parses provider messages such as `N 秒 后停止` and sleeps accordingly. ### Defect 4 — provider/channel ambiguity was under-logged The current OpenAI phone page can show WhatsApp delivery text: ```text 重新发送 WhatsApp 消息 ``` The runner must log page channel (`whatsapp`, `sms`, `unknown`). If provider reports a code while page says WhatsApp, classify failures as ambiguous until provider raw fields and OpenAI error text are inspected. ### Defect 5 — `submit_no_sms_page` must not be treated as SMS delivery evidence If OpenAI stays on `add-phone` after submit but does not show an explicit phone reject, classify as `submit_no_sms_page`, hold for the minimum Luban release window, release, then recover page. Do not count it as `phone-verification` SMS timeout. ## Implemented optimized runner New script: ```text scripts/luban_one_by_one_phone_verify.py ``` Key behavior: 1. Buys only one Luban request at a time. 2. Validates OpenAI `add-phone` readiness before each country and before buying. 3. Stops instead of buying when the page is in Bad Request/error state. 4. Holds unused Luban orders for at least 3 minutes before reject. 5. Retries reject until success/already-released/wrong_status or hard deadline. 6. Polls provider for strict 6-digit code. 7. On SMS received, writes the code only to a local file and logs `sms_received` without printing it. 8. Submits code with the proven 5sim InputEvent method. 9. If submit fails, keeps page and provider order for retry and exits with `sms_submit_failed_hold_for_retry`. 10. Does not set success unless OpenAI leaves `/phone-verification`. Run example: ```bash PYTHONUNBUFFERED=1 MAX_BUYS=10 PHONE_POLL_SECONDS=220 MIN_HOLD_SECONDS=180 \ /Users/chick/homebrew/opt/python@3.11/bin/python3.11 \ /Users/chick/.hermes/skills/software-development/codex-oauth-plus-onboarding/scripts/luban_one_by_one_phone_verify.py \ | tee /tmp/luban_one_by_one_phone_verify.log ``` Optional priority override: ```bash LUBAN_COUNTRY_PRIORITY='France,Vietnam,Portugal,Romania,Germany,Netherlands,Argentina' ``` ## Operational rule going forward For Luban/OpenAI tests, use the optimized script above instead of ad-hoc `/tmp/luban_one_by_one_stop_on_sms.py`. If the runner exits with `sms_submit_failed_hold_for_retry`, do not release the order and do not navigate away. Retry from the preserved page using the local code file and corrected submit helper.