Summary
Adaptive Connect is the part of every Colitu app that picks a server and a protocol when the user leaves the choice to the app. Version 4 moves that choice into a small scoring model that runs on the device, adds city-level hints from other devices, detects networks that only let an allow-list of sites through, and hides servers that this device cannot reach. On 2 November 2026 we put the panel side on the live service and tested test builds of the Android and Windows apps on real devices, alongside the automated test suites of all five apps.
Eight checks on an Android phone and a Windows PC, six on the live panel.
Four smaller issues are still open. iOS, Linux and the browser extension were covered by automated tests only, and the allow-list mode was not tried on a real allow-list network.
The apps with Adaptive Connect 4 are not released yet. This report says what we checked and what we did not; it does not claim that version 4 connects more often than version 3. That needs a comparison on real traffic after the release.
What changed from Adaptive Connect 3
- Honest server list. With the VPN off, a server that fails two ping rounds in a row is hidden from the list and from the automatic choice. Nothing is hidden when half of the servers or more fail, because then the network is the problem, and the connected server is never hidden. With the VPN on, a server that cannot be measured keeps its place.
- A decision model on the device. Each candidate (server × protocol) gets a score from its latency, this device’s own recent results with the server on the current network, a prior from the panel, server hints, a “recommended” flag, server load, how well the protocol suits Wi-Fi or mobile data, and the allow-list mode. 5 % of automatic choices explore another candidate. There is no machine-learning library: the same arithmetic runs in all five apps and is checked against 29 shared test vectors. Without a model, or with the feature switched off, the apps use the Adaptive Connect 3 rules.
- City-level priors. The panel rebuilds the priors every hour. A city gets its own priors only when at least 5 different devices reported from it that day; otherwise the country’s are used. The apps fetch the model once an hour and keep the last one offline.
- Allow-list (“whitelist”) mode. Some mobile networks let only an approved list of sites and addresses through. The app now detects this (at most 1 of 5 foreign hosts reachable and at least 2 of 4 domestic ones), switches to servers marked as working under such lists, bridges first, and shows a short notice. If no server is marked, it only shows the notice.
- Servers in Russia appear in the list only for the Russian app language or on a Russian network. A server in Russia is never picked automatically; a bridge that enters in Russia and exits abroad can be.
- Support. The silent, masked connection report now includes the engine’s recent decisions, and support gets an automatic diagnosis of each report.
- A server or protocol the user picks by hand is never overridden.
Method
Devices
- An Android phone on a home Wi-Fi network with the filtering typical of Russian networks (Google unreachable on port 443).
- A Windows test PC on the same network, with a test build of the Windows app (3.0.6 with Adaptive Connect 4).
Live panel
The panel side went live at 21:34 (UTC+3) with two follow-up fixes later that evening. Adaptive Connect 4 is switched on per platform and per share of devices from the admin settings; the released apps do not contain it yet. During the tests 52 sessions were active on 40 servers.
Automated suites
The unit tests of the panel, the admin web, the five apps and the shared model vectors, plus the panel’s integration tests against a throwaway Postgres database.
Results
Automated tests
| Component | Result |
|---|---|
| Panel, unit tests | pass 2 known failures outside this work: golden files with Windows line endings, and a timing-sensitive test that passes 3 of 3 times on its own |
| Panel, integration tests (Postgres) | pass model, city priors, server and network hints, server problems, support diagnosis, decision engine, full lifecycle, retention |
| Admin web | 6/6 type check clean |
| Model vectors | identical 29 cases plus the random-number and Beta-sample vectors, tolerance 1e-9, in Go, C# (Windows, Linux), Kotlin, Dart and JavaScript |
| Android | 488/488 release build OK |
| Windows | 1189 passed 0 failed, 3 skipped |
| Linux | 1103 passed 5 kill-switch tests fail, as they do on the commit before this work; the Linux tests ran on Windows |
| iOS | 646/646 static analysis clean |
| Browser extension | 164/164 build clean |
Devices (D) and live panel (P)
| # | Check | Result | Evidence |
|---|---|---|---|
| D1 | Android, VPN off: unreachable servers hidden after two rounds | pass | Stockholm, which does not answer from this network, dropped out of Sweden; Germany went from 5 servers to 4 |
| D2 | Android, connected: pings shown | pass | Every row had a value while connected through Finland; Stockholm showed “—” and stayed listed |
| D3 | Android: servers in Russia on a Russian network with the English interface | pass | Russia (Moscow) listed |
| D4 | Android: feature switched on, model fetched | pass | Model request answered in 8–10 ms |
| D5 | Android: automatic connect with Adaptive Connect 4 | pass | Hysteria2 connected in 2059 ms; in the parallel round Hysteria2 beat VLESS Reality in 335 ms |
| D6 | Android: support report with diagnostics | pass | The engine journal arrived masked; the automatic diagnosis was written within seconds (confidence: medium) |
| D7 | Windows, connected: no “— ms” for servers that work | pass after fix | Before the fix 15 servers showed “— ms” (the released 3.0.6 did the same that morning); after it, every server had a value, 49–566 ms |
| D8 | Windows: model and automatic order | pass | Model fetched for the country; the automatic order picked Türkiye (Bursa) and connected |
| P1 | Database migrations on the live panel | pass | All six applied cleanly, after a full database backup |
| P2 | Hourly model build | pass | The first build, four minutes after going live, covered 27 countries |
| P3 | City data collection | pass | About an hour after going live: 677 rows from 17 cities in 6 countries |
| P4 | The admin AI assistant on live data | pass after fix | Attributed the fall from 69.2 % to 63.9 % to networks in Russia, listed the servers and protocols involved (Hysteria2 held up there), called a 0 % value for France a probable single-device artefact, and gave five “watch” items |
| P5 | Admin settings for Adaptive Connect 4 | pass after fix | The switches were hidden until saved once; they now show as not yet set |
| P6 | Live users unaffected | pass | 52 active sessions on 40 servers during the tests; app configuration requests kept succeeding |
Problems found and fixed
- Our own operations mistake. While updating the admin access lists we re-added the addresses of six decommissioned servers, because the query did not skip retired servers. They were removed within the hour.
- The apps disagreed on the hosts used to detect allow-list mode and on what counts as a bridge. Both are now shared constants in the design, applied in Android, Windows, Linux, iOS and the extension.
- The extension did not receive the “works under allow-lists” flag of a server. Fixed on the panel.
- Order of the engine lists. The apps send the newest entry first; the panel expected the oldest first. Fixed on the panel.
- “— ms” for working servers on Windows and Linux while connected, when the ping outside the tunnel fails and no value from before connecting exists. The apps now measure through the tunnel in that case, for display only (D7).
- The Adaptive Connect 4 switches could not be edited in the admin settings (P5). Fixed on the panel.
- The admin AI assistant saw only city data, which is empty right after going live. It now gets country-level context too (P4).
- Wrong country while connected through a bridge. The model request took the country from the request address; through a bridge that address is the exit, so a phone in Russia got Finland’s priors. The signed network token from before connecting now comes first.
- The Android phone stopped connecting at all: every transport timed out, with the feature on or off, and also with an earlier test build. Android kept a pending record of the VPN service with no process behind it, after repeated reinstalls and force-stops during a start; force-stop did not clear it, a reboot did. This was a state of the phone, not a regression in the code.
Open issues
- “Engine not started”. When the VPN service process never starts (problem 9), Android should report that as its own reason, suggest restarting the phone and write it to the journal. The automatic diagnosis blamed the servers because it could not see this.
- Support form focus. On the Android support form, tapping the message field leaves the focus in the subject; only the keyboard’s next key moves it.
- “Recommended” order. The “Recommended” section on Android’s Locations screen still uses the Adaptive Connect 3 order.
- Allow-list mode after a restart. Android and iOS keep the mode in memory, so it resets when the app restarts.
Privacy design
- The device’s own history (per network, server and protocol) never leaves the device. The network is identified by a hash that stays on it.
- The panel’s city table holds no account, device, address or network operator. The city is looked up from the address when an event arrives, using the DB-IP City Lite database (CC BY 4.0), and the address is not stored.
- A city is used, and shown to admins, only when at least 5 different devices reported from it that day; smaller places count only towards their country.
- The admin AI assistant and the nightly analysis receive anonymous totals only. The automatic support diagnosis reads the masked report, in which visited sites and foreign addresses are hidden.
- The model a device downloads holds only the priors for its own country, or city.
Limits of this test
- iOS was not tested on a device (we have no Mac to build it); only its unit tests ran.
- Linux and the browser extension were not tested on a device; unit tests only.
- Allow-list mode was not tested on a real allow-list network, because none was available. The detection and the switch are covered by unit tests in every app.
- The “Recommended” badge was checked only in a local preview: marking a server on the live panel would have changed the default choice of the released iOS app.
- One Android phone and one Windows PC on one network, over one evening. That shows the parts work; it says nothing about how often version 4 picks a better server than version 3.
- We do not name servers beyond their city and publish no addresses.