Decision
Cordial may download the official Roblox Android build, at the user’s request, from Roblox’s own distribution, to that user’s own machine. Cordial may not ship one, in any sense: nothing committed, nothing vendored, nothing bundled in a release artefact, nothing served to a third party, and nothing modified on the way through.Why this needs an ADR at all
The README says, and it is load-bearing:No Roblox code, ever. No APK, asset, or decompiled material committed, vendored, or pasted into an issue.Fetching does not violate the letter of that. Nothing is committed or vendored; the bytes travel from Roblox’s servers to the user’s disk and Cordial keeps no copy anyone else can reach. But the sentence was written to mean this project does not put Roblox’s property anywhere, and a reasonable reader could take adding a download button as walking it back. So the answer is recorded here rather than assembled after somebody asks.
Why fetching is right
The current arrangement is worse, not purer. Today the install instructions tell people to install Sober — a different Roblox client — in order to obtain a file, and then not use it. That is a dependency on an unrelated project for a step Cordial could do itself, and it is the weakest part of getting started.notice.txt and privacy.txt
describe connecting to Google Play, through VinegarHQ’s servers, which hand
back a Play download link. VinegarHQ’s deployment tracker custard — their one
open-source component that touches Android — asks
clientsettings.roblox.com/v2/client-version/ for WindowsPlayer and
WindowsStudio64 only, and learns the Android version by watching
com.roblox.client on Aptoide, a third-party mirror. The project that would
most like that endpoint to answer for Android does not ask it.
Roblox publishes no Android artefact at all. Measured, with a control:
roblox.com/download answers 200 and links Google Play and the Amazon Appstore
for Android — and no file. Three places an artefact would surface, absent from
all three.
The decision below is unchanged by this, because nothing in it turned on what
Sober does; the argument leaned on Sober and the argument was wrong. What
changes is the practical consequence: there is presently nothing to fetch.
Source::official() is a refusal that names Google Play and the Amazon
Appstore, so a user learns where the build lives rather than that Cordial is
broken, and CORDIAL_ROBLOX_APK_URL lets them point Cordial at a file they
obtained themselves. Aptoide is deliberately not wired: it is a third-party
mirror offering only a hash it supplied itself, which is the weakest form of
verification available and worse than none, because it looks like verification.
Google Play is not wired either — it would require the user’s Google
credentials, which this project will not handle.
A stale client is not a working client. Roblox refuses old builds
server-side, so “update” is not a convenience feature. A client that cannot
update is a client that stops working on Roblox’s schedule, and leaving the user
to notice that themselves — with no error that names the cause — is the failure
mode this project keeps writing down.
What it does not do
- Never modifies what it fetched. Asset overlays are a separate feature with their own decision (ADR-010); they are non-destructive, off by default, and never write into the APK or anything extracted from it.
- Never redistributes. No mirror, no cache anyone else can read, no re-upload, no torrent, no “here is a copy” in an issue.
- Never fetches unasked in the sense that matters. Checking is a version query; downloading is governed by settings the user sets — Auto update, and a switch each for Wi-Fi and metered connections, with the metered one off by default. Both of NetworkManager’s guesses count as metered, so an ordinary desktop takes the metered switch’s branch and waits to be asked.
- Never pretends to be the official client. Cordial identifies itself as
Cordial and reports the platform truthfully (
Linux, which is the engine’s own vocabulary).