Files
Radicade/docs/QUEST-20230907-TEST.md
T
2026-10-16 23:33:13 -07:00

32 KiB
Raw Blame History

Quest 20230907 server test

Current investigation: post-login doll and saved-account fallback (2026-10-07)

After the user supplied a valid birthday, login proceeded further. At 19:18:22 client emitted fatal quit 1550502249 after a Hile report; VPS message was 33489407,7. Exact September disassembly locates the comma-pair formatter in HGEONHBDDLK.PLGOEDKHHBI (0x4f91ffc), gated by AntiHile.QD, reporting type 701. Live config verified that key=true. GameConfigAPI now overrides only that key=false; two focused tests pass for seeded true and missing-key cases, including preservation of unrelated values and stored data. Default Debug test build hit a locked DLL; isolated QuestConfigTest build passed. Commit 04826ca pushed to origin/2023 after cherry-picking the tested local 0b7894b onto remote 2a2df52 in artifacts/quest-config-integration. Primary dirty workspace preserved. VPS deployment and gameplay retest pending. Separate crm/me/config exception observed; not established as the cause of this shutdown.

FreshHTTP test at 19:07 passed the formerly failing current-saves response, outfits, and image verification (placeholder acceptance logged 19:07:54.993). No fatal quit or hex parsing error appeared through 19:09; heartbeats continued. Unity explicitly logged Junior: False at 19:07:38.968 but meta junior login error at 19:07:50.632. User screenshot confirms false database flags, JuniorState=0, and an unset birthday (year 0001). BuildSelfAccount recalculates juniorState=PendingOverride (2) when birthday is absent/year<=1900 regardless of stored zero. Client TitleScreenFlowModel.EJKBHHGALEH -> HBGNIICMAMG -> BKJMLBBNEFL.FBOEAHDMPJF checks the self-account state at +0xa8 for 2 before falling back to its Junior boolean, then checks Meta hardware. This supports incomplete birthday onboarding as the remaining restriction, not an actual true Junior flag. No birthday, Junior flag, or restriction check has been modified.

ImageCompat login at 19:02:38 authenticated successfully (token 200 and self-account 200), but failed before image loading. At 19:02:42.494 the custom-avatar-current-saves response began (200) without a matching chunk end. At 19:02:42.635 Unity reported Can't parse '' as a hex number!; manual login returned doll at 19:02:43.596. A later matchmaking heartbeat hit the same parsing error. No image-placeholder acceptance or fatal-quit event occurred during this attempt, so the image fix remains unverified. Filtered capture: image-compat-events.log.

FreshHTTP.apk is a one-variable transport experiment on top of ImageCompat: HTTPManager.SendRequest sets IsKeepAlive=false via its runtime setter only for https://ns.radicade.app/ requests. This tests connection reuse as a cause; it does not establish the root cause or suppress parser errors. TLS and response validation are unchanged. Native compilation and APK signature verification passed. Device login test pending.

ImageKey test at 18:52 confirmed the request hint reached the VPS and changed the failure from Signature malformed to Signature verification failed. Headset log image-key-events.log records this failure followed by fatal quit code 1550502249. User supplied matching VPS reports. The server's SignatureData is a fixed 256-byte placeholder, not a signature of the returned image.

Built, apksigner-verified, and installed ImageCompat.apk in place, preserving data. Exact-build image verifier HFFEEGBKKFK.DGDJIHJHHBN at RVA 0x6deb934 is reached after header/key-id parsing. The hook recognizes only the exact server placeholder byte array and accepts it in this image-only path; all other signatures call the original verifier. This intentionally relaxes image authenticity checking for that placeholder, does not provide cryptographic image authentication, and does not alter TLS certificate validation or fatal-quit behavior. Source: tools/quest-http-inspect.c and tools/quest-image-placeholder.h. Prologue verified against original ELF and compilation passed -Wall -Wextra -Werror. First alignment attempt failed in sandbox; elevated alignment succeeded. Login outcome pending. No server update required for this test.

Confirmed next trigger from user-provided VPS reports: two Obcured reports say Signature malformed for the same image URL with sig=p1. QuitInspect captured two fatal quits with code 1550502249 and a delegate-invocation caller; shutdown's SpeedHackDetector exception follows them. Live /images/{name} returned key-id KEY:RSA:p1.rec.net, whereas patched Quest metadata expects .radicade.internal. This is an image-signature key-ID mismatch, not proof of a Junior account restriction or TLS certificate-pin failure. Existing PC ImageSignatureRequest.AddKeyId already solves that header selection mismatch with rcsig.

Built, verified and installed ImageKey.apk in place. Added an exact-prologue-checked HTTPManager.SendRequest hook (RVA 0x688e200) that adds the expected rcsig only to https://ns.radicade.app/images/ requests, preserves resize/signature query parameters, and uses the IL2CPP write barrier when replacing the URI. Existing hinted/fragment URLs are left unchanged. Original TLS and RSA verification remain active; the hook activates after the diagnostic 30-second delay. A live request with that parameter returned HTTP 200 and the correct .radicade.internal key ID. Headset acceptance remains pending; the server still supplies static signature bytes, so successful signature cryptographic verification is not established. Capture: artifacts/quest-tls-diagnostic/image-key-events.log.

After deployment, PID 21799 received /outfits/me HTTP 200 at 14:21:37 and progressed to version check and additional startup requests. The user saw “Account not supported” before exit. Two /api/PlayerReporting/v1/hile requests preceded exit; Android recorded signal 9 after the activity stopped at 14:21:48. A public account-2 probe returned isJunior=false, which does not establish private self-account state. The client's SessionManager message table maps error 83 to the Meta Junior restriction text, but the triggering code has not yet been captured.

At the user's request, inspected https://github.com/recflare/quest at 43efb7b9f46a335e978af5520979d8a4d65e81f2 in artifacts/recflare-quest-reference. It targets April 2023, not this September build. Its certificate-pinning and fatal-quit diagnostics suggest a separate post-TLS integrity check worth testing; they do not establish our cause. No repository build scripts or bypass hooks were run. Added an independently implemented exact-prologue-checked trace at this client's SessionManager.FatalApplicationQuit RVA 0x3a1c0b4, logging code/caller/reason length only and preserving behavior. Signed/verified QuitInspect.apk installed in place. Activation is not yet confirmed because the app exited before diagnostic output; user asked to keep headset awake at the password page. No new server changes or account edits made.

The user reported the VPS updated after a808239. An unauthenticated live check of /outfits/me now returns 401 instead of 404, consistent with the new protected route being deployed. Reopened HttpInspect-v3 on the connected Quest as PID 21799; filtered capture is artifacts/quest-tls-diagnostic/http-after-outfit-deploy.log. Authenticated response/client acceptance is still pending a manual login.

Server fix committed and pushed to origin/2023 as a808239: authenticated GET /outfits/me now wraps the existing account avatar in the September current-outfit DTO. Exact-client metadata resolved the request state machine MOEENPJECCH returning FMLIPOPOKDJ; generated formatter JOJEHOPNNIN defines DataVersion, LegacyData, CustomizationSettings, Selections, Slot, Name, Accessibility and ThumbnailFileName. Legacy formatter DEAAHJJLAAE defines SelectionsV1, SelectionsV2, FaceFeatures, SkinColor and HairColor. The initial adapter uses version 0 legacy data, current slot 0 and an empty modern selections list. Client acceptance of the response remains pending VPS deployment and a headset test. All three QuestOutfitsTests passed, covering account isolation, auth rejection, JSON shape and missing-avatar initialization.

Later capture at 14:04:24–26 reproduced empty chunk-length errors on /datacollection/data/event and /matchmaking/player/heartbeat, after the 14:02:29 login failure. The intermittent transport issue is therefore not proven fixed. Avatar descriptor warnings also remain unresolved. The field inspector now supports secondary Android users (active user 10) and records RecNet interface fields as well as runtime fields; it reads type metadata only.

HttpInspect-v3 captured a complete manual login attempt at 14:02:21–29. Password token, account/me and matchmaking login all returned HTTP 200. Every observed chunked response completed, including the avatar catalog. /outfits/me returned HTTP 404 at 14:02:24; the client reported AMIIDJOEAMH: HTTP Error 404 and manual-login doll at 14:02:29. This attempt did not reproduce the earlier empty chunk-length parse error. The client also logged invalid legacy avatar-item descriptors, a separate compatibility concern. The missing outfit route is the current concrete server lead; its response contract is being inspected before implementation.

Follow-up: the user confirmed the password page but signing in exited PID 14518 with signal 11 at 13:57:06. The v2 diagnostic was unsafe: optimized call sites for ReadChunkLength do not preserve its unused receiver argument, so interpreting that argument as an HTTPResponse can dereference invalid memory. Do not reuse HttpInspect or HttpInspect-v2. Updated the hook to ReadChunked (RVA 0x6d941e0), whose receiver is actually consumed, and verified its four copied prologue instructions against the original binary. Built and signature-verified HttpInspect-v3.apk, installed in place, and launched PID 16445. This corrects the identified diagnostic defect; the original post-login doll issue remains unresolved pending a captured attempt. Filtered continuous capture is saved locally in artifacts/quest-tls-diagnostic/http-v3-events.log.

The user successfully interacted with the v3 password form using Touch controllers. Supplied server logs show the headset password grant accepted, followed by authenticated account and matchmaking requests. Password authentication itself succeeded; gameplay has not been reached. At 01:26:07 the client reported doll with BestHTTP ReadChunkLength failing to parse an empty string as hexadecimal. Successful server request logs do not identify which response failed in the client.

Added tools/quest-http-inspect.c, an exact-prologue-checked experimental native hook that logs HTTP chunk reads using response identity, status and URL path only. It does not log passwords, authorization headers, query strings or response bodies. The diagnostic activates after 30 seconds; this timing remains a diagnostic workaround.

A subsequent saved-account auto-login followed TitleScreenFlowModel.MNKODPJLNDD, a different error callback from the initial cached-login path, and showed error 3 before exit. The client patch now redirects that callback at RVA 0x39c67e0 to the existing password page (GoToLogin, 0x39bbd80) as well. Server cached-login rejection remains intact.

Built, signed, verified and installed artifacts/quest-tls-diagnostic/HttpInspect-v2.apk as an in-place update to com.radicade.questtls. No uninstall or data clearing occurred. Quest PID 14518 logged cached-login error 3 at 13:55:58, then activated the chunk diagnostic at 13:56:11 and remained running. Visual confirmation of the password fallback and a fresh manual login with the diagnostic active are pending. No additional server change or deployment was made for this diagnostic.

v3 controller dispatch test (2026-10-07)

The user confirmed v2 displays the password form but physical Touch controllers do not interact, although they work in the Meta menu. Static analysis resolved InputManager.FMJDLCGGGKP's virtual call at 0x460a254 as CurrentPlatform (same vtable slot used by get_CurrentPlatformIsOculusType). Its dispatch table at RVA 0xc35a550 maps Standalone=7 to return no VR input (0x460a2b0). Oculus=1 dispatches to 0x460a2c0, which selects the existing Quest input handler for hardware type 5.

The v3 script changes only that table entry in addition to v2 changes. It preserves password-based platform-7 server authentication and selects Oculus input using the original hardware check. Installed signed StandaloneLogin-v3.apk in the separate diagnostic package without uninstalling. Patched IL2CPP SHA-256 is 1a646b3c85ecf8101e7c131cd87012ab6a9764d01685addee03d2251a811243b. Signature verification passed; controller interaction and end-to-end password login require headset testing. No additional server changes were made.

v2 prototype reaches password page (2026-10-07)

Server commit 835534b was pushed to origin/2023 and the user deployed it. A credential-free live probe returned the specific standalone password-required response, confirming the new guard is active. Those two deployment-probe cached-login 401s were not headset password attempts.

The expanded read-only inspector saved artifacts/quest-tls-diagnostic/quest-method-map.tsv. Runtime method names resolve the Quest-specific original initialization call at 0x3d09f14 to RecRoom.LocalPlayerController.SetVRDisplayMode; v1 skipped it. The v2 patch preserves original initialization through that call, then invokes standalone account initialization with the original stack frame correctly restored. It also redirects TitleScreenFlowModel.DALDIFKKDDA to its existing GoToLogin method. This error redirect is currently broad (all title-screen errors), so this remains an experimental build.

Installed StandaloneLogin-v2.apk into com.radicade.questtls without uninstalling. PID 15954 reported Standalone/OculusQuest, received the expected cached-login 401, and stayed running. An ADB screenshot visually confirmed the username/password page, rather than the error screen. Controller interaction and successful password authentication remain pending user testing. No password was supplied or logged. The original-package TLS-fixed APK and both OBBs remain available. Signature verification, ARM64 stub disassembly, 16 KiB alignment, and Python syntax checks passed.

Independent-login prototype: not playable; rolled back (2026-10-07)

Added local server support for wire platform 7 (Standalone) with password-only login. It clears caller-supplied account identity before resolving the username, generates a local radicade-quest: device namespace, ignores bearer headers for this password grant, rejects cached-login/refresh/signup grants, and suppresses unauthenticated standalone cached-account discovery. Existing whitelist and anti-cheat checks remain active. These are experimental server changes, not deployed or pushed. Refresh and new-account onboarding are not implemented; an existing Radicade account with a password is required. With whitelist enabled, the derived local identity must currently be explicitly allowed.

All 26 AuthOnboardingFlowTests passed, including five standalone cases covering correct/incorrect passwords, correct token identity, hidden cached accounts, and rejection of device-only cached/refresh/signup requests.

tools/patch-quest-standalone-login.py reproduces a failed client experiment: three exact-build checked branches redirect Oculus initialization/auth parameters/platform enum to existing standalone implementations. Only 12 bytes in libil2cpp.so differ from the TLS-fixed clone. The signed APK artifacts/quest-tls-diagnostic/StandaloneLogin.apk passed v2/v3 verification and 16 KiB alignment. On Quest (PID 12596), it passed platform initialization and logged Platform: Standalone, Hardware: OculusQuest, but then attempted cached login, received HTTP 401, and displayed error code 3. The user reported no usable hands. A screenshot confirmed the error screen; the cause of missing interaction is not established. This is NOT a working Quest login implementation, and the initialization replacement must not be promoted to a release.

Restored RadicadeQuest-ScopedTLS-Test.apk over the separate diagnostic package without uninstalling (ADB Success), then launched the unchanged original-package TLS-fixed app. Both OBBs and private data were retained. Before another client test, trace Quest input initialization and the title-screen transition to password login separately; do not simply replace the full initialization method again. The user reports deploying by pushing Git and gives C:\radicade-server as the server folder. No deployment workflow was found in this checkout; production update/restart mechanics are not yet verified.

Latest result: TLS fixed; Meta account initialization remains blocked (2026-10-07)

The currently installed original-package APK is artifacts/quest-tls-diagnostic/RecRoomQuest-ScopedTLS-Test.apk, SHA-256 064fbf29f4c3340abf45863664fd84af1404a74b46c64fa08d733f40654bdffa. It retains package com.AgainstGravity.RecRoom, versionCode 2378787, and the original patched metadata. The only changed APK payload is lib/arm64-v8a/libunity.so; signing metadata also changes. The user explicitly approved replacing the previous differently signed test app and its resulting private-data deletion. The OBB was restored and its SHA-256 again matched ef856a56bfe1667f00435c2b07fb465766196c02bac8b220c7cc36db926998fc.

Native instrumentation found that platform-root X509 validation of ns.radicade.app succeeded (result=0, raw_flags=0, unity_flags=0), but the configured managed verification callback subsequently returned 0x8. This demonstrates an additional client-side rejection; its managed implementation/pinning policy has not been identified. Changing server TLS versions or certificate issuers did not address it.

tools/diagnose-quest-tls.py --radicade-system-trust routes only the exact hostname ns.radicade.app through Unity's existing default verifier (including platform CA chain and hostname validation), preserving the configured callback for all other hosts. It does not return unconditional verification success. The script accepts only the exact known Unity library SHA-256, uses checked empty RX-segment padding, and preserves existing native instructions outside the three hook sites and RX segment length fields. Without that option it only adds diagnostic logging. The native library SHA-256 for the scoped variant is 37c5709cca6b5dff019e16685a819d50d064d3a4c19f45d642cb5383011e23d7.

Both the separate diagnostic package (com.radicade.questtls) and the original-package scoped build passed TLS and loaded game configuration. The original-package run (PID 6353) remained running past the former exit point, but logged GetLoggedInUser failed: The user isn't signed in or their account state wasn't in a recoverable state. (2|-1), followed by Unable to load Oculus user account. Meta's platform logs also show OBTAIN_TOKEN_3P failing with HTTP 400 for this package. No account proof, platform identity, entitlement result, or server authentication policy was forged or changed. Gameplay/login is not yet working.

The original signing password was unavailable. The new local diagnostic signing key and password file are in artifacts/quest-tls-diagnostic/diagnostic.p12 and diagnostic.password, excluded by that directory's .gitignore; retain these for non-destructive future updates. A separate diagnostic app and its OBB remain installed. Signed v2/v3 verification, 16 KiB alignment, original-package payload comparison, checked ARM64 disassembly, and on-device positive TLS tests passed. Rejection-path behavior has not yet been independently exercised with an invalid server certificate.

The VPS currently serves ZeroSSL and has Caddy debug enabled. It is running in the user's foreground PowerShell window. The older sections below describe the investigation history, not the current installed build.

Platform integration investigation (2026-10-07)

Added tools/quest-platform-inspect.c, a read-only JNI diagnostic which enumerates selected runtime class methods and field offsets without reading account values or invoking authentication methods. Installed it only in the separate com.radicade.questtls diagnostic app as artifacts/quest-tls-diagnostic/PlatformInspect.apk. The original-package TLS-fixed APK and both OBBs were retained. The first inspector run raced Unity initialization and aborted; delaying inspection by 30 seconds allowed the second run (PID 10871) to complete. This delay is a diagnostic workaround, not a general initialization synchronization guarantee.

The complete successful method inventory is artifacts/quest-tls-diagnostic/platform-methods.txt; selected ARM64 disassembly is platform-disassembly.txt. Confirmed actual Quest RVAs: OculusPlatformManager.Initialize = 0x3d09d8c, OculusPlatformManager.GetAuthParams = 0x3d0a930, StandalonePlatformManager.Initialize = 0x43d6f0c, and PlatformManager.GetAuthParams = 0x396ad48. The standalone manager exists in the Android build; its platform getter returns enum value 7 and its PC-platform getter returns true. Therefore simply swapping the entire manager would change device behavior and is not yet a validated Quest integration. The server's current Platforms enum does not define value 7. No platform methods or server authentication behavior were changed by this diagnostic.

Next implementation work must preserve Quest hardware behavior and add authenticated Radicade account credentials/session validation before enabling an independent login path. The existing server device-code implementation auto-approves a configured Studio account; it must not be reused as Quest account authorization. A successful metadata inspection does not establish gameplay compatibility or successful login.

Confirmed remaining Meta failure

The user confirmed their Meta profile and other online apps work. Correlated platform logs for the original-package fixed build show https://graph.oculus.com/authenticate_application returning HTTP 400, OAuth error code 27, subcode 1891543, title Unofficial Application. The response explicitly identifies the app as modified and disables platform functionality. This is an app-authorization rejection, not evidence that the user's headset account needs resetting. Changing Caddy or reinstalling the same modified APK cannot supply the original publisher's signing identity. Remaining work requires a separately designed Radicade sign-in integration (for example, server-validated account login/device pairing or an appropriately registered Meta app), preserving account authentication rather than fabricating a Meta user/proof or accepting arbitrary platform IDs.

The supplied folder is an apktool-decoded Android package plus an OBB asset tree. Its APK manifest is com.AgainstGravity.RecRoom, Quest/Quest 2 6DoF, ARM64, and the loaded Unity version literal is 20230907 (not the desktop 20230831 build).

What is ready

tools/patch-quest-client-metadata.py recognizes this exact Quest metadata layout, resolves its live IL2CPP string-literal table, and redirects its bootstrap/auth/site/image URLs to https://ns.radicade.app. It keeps the image-signature tail .radicade.internal. It is dry-run by default, verifies the rebuilt table against every original literal, writes a .orig backup and a patch marker only with --apply, and refuses unknown/mismatched builds.

From the repository root, first preview the changes:

python tools/patch-quest-client-metadata.py 'C:\RecRoom\RecRoom-Quest-20230907' --server https://ns.radicade.app

The image rule targets the server's signed /images/img/{name} route; the domain's /images/avatar/ is not the image endpoint and returns a large generic response. The account's GET / nameserver advertises all other service URLs under the same server.

Earlier state: NSC test APK installed and launched on Quest 3

The Quest 3 is connected via ADB. The local test-signed build was installed after uninstalling the prior test-signed package (the original Store app had already been removed earlier). The app was launched as a VR activity on-device; Unity initialized the OpenXR/Oculus runtime and reached Connecting to RecNet. Its TLS request still fails with Mono.Security.Interface.TlsException: Handshake failed - error code: UNITYTLS_INTERNAL_ERROR, verify result: 4294957312, then the RecNet nameserver query reports summer and the app exits around 17 seconds after start.

A second APK variant adds the official Let’s Encrypt Root YR cross-signed-by-ISRG-Root-X1 certificate as a raw resource and trusts it only for ns.radicade.app, while retaining Android system trust and disallowing cleartext. It was aligned for 16 KiB pages and signed with a separate local test key; Apktool build, apksigner v2/v3 verification, zipalign, package/version/ARM64 checks and inspection of the packaged NSC all passed. Installing it required uninstalling the previous local test package because its signing certificate differed; the user's consent was obtained. The matching OBB was restored from the PC copy and SHA-256 verified identical (ef856a56bfe1667f00435c2b07fb465766196c02bac8b220c7cc36db926998fc). This certificate-resource experiment did not change the TLS error or startup exit.

The currently installed APK is C:\\Users\\user\\Downloads\\RadicadeQuest20230907\\RecRoomQuest-radicade-nsc-test.apk (package com.AgainstGravity.RecRoom, version 20230907, versionCode 2378787). Its narrow Android trust config is apk/res/xml/network_sec_config.xml, and the cross-signed CA resource is apk/res/raw/isrg_root_yr_by_x1.pem. This test shows that adding an Android Network Security Config trust anchor does not fix this Unity MobileAuthenticatedStream TLS handshake, so do not keep changing Android trust settings or weaken TLS validation; investigate the TLS chain/protocol at UnityTLS or server-side and keep certificate validation enabled.

The headset OBB at /sdcard/Android/obb/com.AgainstGravity.RecRoom/main.2378787.com.AgainstGravity.RecRoom.obb is present and hash-matches the local build. Uninstalling the test app removed the on-headset OBB directory, so the local copy was pushed back and verified after install.

Earlier APK/OBB build notes

The pre-existing working tree had a decoded Quest APK (apk/) and separately decoded OBB asset tree (obb/), not the original archives or publisher signing key. The untouched source under C:\\Users\\user\\Downloads\\RecRoom-Quest-20230907 was not modified. A separate working copy under C:\\Users\\user\\Downloads\\RadicadeQuest20230907 has the metadata patch applied; Apktool 3.0.3 built its APK, which was page-aligned and signed with local-only debug keys. Package, version, min SDK 25, target SDK 32 and ARM64 native code were validated. A new tools/package-quest-obb.py validated all 22,199 OBB entries and built the matching expansion-file name (1,394,848,868 bytes); the on-headset copy now has a verified matching hash. Android platform-tools 37.0.1, build-tools 36.1.0 and Apktool were downloaded into %LOCALAPPDATA%\\Radicade\\QuestToolchain.

The remaining significant functional blocker is identity: this APK is built for Oculus/Meta and its IL2CPP metadata contains Oculus Platform APIs (GetUserProof/GetLoggedInUser-related flows), but the server currently only verifies Steam tickets when platform == Steam. Account creation also accepts only platform IDs prefixed 75 or 76, and the existing allowlist is named/configured as a Steam ID list. The server version-check route currently allows all versions, but 20230907 is not in DBConfig.SupportedGameVersions; this does not prove the rest of the server protocol works. The endpoint patch does not add Meta identity verification, change server authentication policy, or port the Windows BepInEx/Harmony plugin to Android.

The metadata patch remains reproducible with the dry-run command above. The current test APK and matching expansion file are installed and have been run on the Quest 3; the app still exits after UnityTLS handshake failure during nameserver discovery. New Meta account onboarding is not supported/verified; existing linked-user login is unknown.

Safe next steps

  1. Keep this test APK/OBB and current headset install available for controlled TLS investigation. Do not uninstall/reinstall again without a reason: that deletes app-private data and Android also removes the OBB directory.
  2. Investigate the failure within Unity's MobileAuthenticatedStream/UnityTLS against the exact chain served by Caddy (leaf ns.radicade.app → YR1 → Root YR cross-signed by ISRG Root X1). Do not disable certificate or hostname validation; the domain-scoped Android NSC root addition had no effect.
  3. If the TLS request succeeds, resolve and test Meta/Oculus identity support with the Radicade server before attempting account creation. Do not weaken authentication based on an assumed Oculus ID shape.

TLS 1.2-only test (2026-10-06 Pacific)

The user identified the server as a netcup Windows VPS, running C:\Caddy\caddy.exe v2.11.4 with C:\Caddy\Caddyfile. The live Radicade site already used key_type rsa2048. The user added protocols tls1.2 tls1.2. Reload initially failed because Caddy was no longer running; the user started it in a foreground PowerShell window.

External OpenSSL checks confirmed that TLS 1.2 succeeded with certificate verification OK and TLS 1.3 was rejected with protocol-version alert 70. A fresh launch of the existing Quest APK (PID 29072) still produced UNITYTLS_INTERNAL_ERROR, verify result 4294957312, followed by nameserver error summer and OnApplicationQuit at approximately 15.2 seconds. The process was absent afterward. TLS 1.2-only did not resolve startup; certificate-chain compatibility remains unproven. No APK reinstall or OBB change was performed. The temporary TLS restriction should be reverted on the VPS; rollback has not yet been confirmed. Caddy currently depends on the user's foreground PowerShell process remaining running.

Rollback confirmed: the user successfully reloaded via 127.0.0.1:2019, and an external TLS 1.3 handshake subsequently succeeded with certificate verification OK. The TLS 1.2-only restriction is no longer active.

ZeroSSL chain test

After the user changed the Radicade site's ACME issuer to ZeroSSL and reloaded successfully, an external OpenSSL probe confirmed the served chain changed to ns.radicade.app -> ZeroSSL RSA DV SSL CA 2 -> Sectigo Public Server Authentication Root R46 -> USERTrust RSA Certification Authority, with verification OK. The new chain was active before the Quest launch.

The existing Quest APK was launched again (PID 30187). It reached Connecting to RecNet at 9.44 seconds, reported the identical UNITYTLS_INTERNAL_ERROR / verify result 4294957312 at 13.16 seconds, then nameserver error summer and OnApplicationQuit at 15.14 seconds. The process exited. Changing issuer did not fix startup. This weakens a Let's Encrypt-specific explanation but does not establish the exact validation failure. ZeroSSL remains configured on the VPS; no rollback has been performed.

Read-only inspection confirmed that the test APK's live metadata literals 41405 (auth) and 41411 (nameserver) both resolve to https://ns.radicade.app. The headset reports Android 14, and both /system/etc/security/cacerts and /apex/com.android.conscrypt/cacerts contain certificate files. This does not establish that Unity successfully loads or trusts those files. Further diagnosis should correlate Caddy TLS handshake errors with a fresh Quest launch before making additional certificate or client changes.

Correlated Caddy debug and headset trust-store checks (2026-10-07 Pacific)

Quest PID 31620 again failed at about 13.29 seconds and quit at 15.27 seconds. The user supplied Caddy debug lines at 07:06:07 UTC showing SNI ns.radicade.app, supported protocol versions [771,770,769] (maximum TLS 1.2), successful selection of the ZeroSSL certificate, and handshake EOF. EOF alone does not identify the client's reason for closing.

The numeric Unity verify result 4294957312 is signed -9984 (-0x2700), matching Mbed TLS's certificate verification failed code; this correspondence suggests certificate validation failure but does not identify the precise Unity verification flag or callback.

Pulled the headset's 134 public system CA certificates to artifacts/quest-system-cacerts and built artifacts/quest-system-ca-bundle.pem. OpenSSL TLS 1.2 verification of the live Radicade server succeeded with this CAfile, -no-CApath, -no-CAstore, -verify_return_error, and -verify_hostname ns.radicade.app. This establishes that the served chain can validate with the headset's public system roots using OpenSSL, not that Unity loads these roots or validates identically. Investigation should focus on Unity's trust loading/custom validation and chain-building behavior rather than assume a missing system root or TLS version mismatch. Caddy debug remains enabled; ZeroSSL remains active.