Repository navigation
Releases: AngelStreetCorp/virtualpytest
Release list
Build 90258 — 2026-10-27
| Platform | main-hotfix-2026.10.27-90258 (6d2e9322) |
| Previous | main-2026.10.27-90256 |
| Date | 2026-10-27 |
| Features | ai-dataset, ai-test, avq, cicd, code-graph, companion, device-farm, gitlab, mobile-app, mods, quicktest, virtual-scripts, zammad |
Bug fixes — 1
BUG-0973 — Every release gets its Docker bundle again
the release check that builds the ready-to-run Docker bundle failed on every release since 2026-10-13, so no release carried it: the bundle left out the documentation the server reads. The bundle now ships that documentation (about 8 MB more, compressed). In plain words: the one-download Docker install is attached to releases again
Security — 1
No operator name in what a release ships
four lines of code comments and project notes in build 90256 still named an operator the platform works with; they are reworded, the release check now also catches a name written after an underscore (X_NAME_KEY), and one internal helper script is no longer published. In plain words: the published code names no customer
Roll it out
Every step below is also a script in the bundle: follow virtualpytest/rollout/README.md (one script per step, run on the machine it names).
1. Services (6)
Restart these after the update:
vpt-discard-incidents, vpt-discard-scripts, vpt-heatmap, vpt-procon, vpt-timeline, vpt-companion
Build 90256 — 2026-10-27
| Platform | main-2026.10.27-90256 (e5e4e371) |
| Previous | main-2026.10.26-90145 |
| Date | 2026-10-27 |
| Features | ai-dataset, ai-test, avq, cicd, code-graph, companion, device-farm, gitlab, mobile-app, mods, quicktest, virtual-scripts, zammad |
Features — 1
A second operator's TV web app has a navigation tree — testing · TASK-177
(TASK-177) — A new navigation tree for the operator's TV web app: 21 nodes and 21 edges, one node per screen of the app's navigation (home, live TV, replay, VOD, radio, the settings page and the deeper screens each of them opens), every node carrying one language-free URL verification and every edge a forward and a back action. The app is browsable as a guest, so the tree needs no account at all. The app's own route table was read out of its JavaScript bundles, which is what made the deeper screens reachable, and the playbook — the cookie overlay that has to be dismissed before the navigation is clickable, the nav items that are clickable while the links inside them are not, the two redirects the app does, the settings page that blocks the browser for half a minute after it opens, and the two live channels whose players never stop the browser from loading — is in the internal operator notes. The tree carries the settings and info nodes every tree needs, and the software version under test (2.10.7+0-g49134c0b2) is read from the settings page: the info node waits for the version row itself ("Version de l'application"), the edge into it opens the collapsed section and scrolls that row into view, and the value is read by a script over the page text. The Android mobile and Android TV trees are still blocked: the mobile app wants the operator's account (the key names are in the owner's machine only, on no host of the lab) and no Android TV device of the lab is usable. In plain words: the operator's TV app on the web can now be walked end to end by the platform
Improvements — 2
The server picker reads the platform server list, and Settings edits it (TASK-179) — platform
the servers in the picker are no longer a build-time VITE_SLAVE_SERVER_URL in the frontend .env: the web app keeps VITE_SERVER_URL as its one start address and, once you are signed in, reads the other servers from the platform server list (GET /server/servers), enabled ones in the table's order, and refreshes its hosts as soon as the list changes. Settings → Frontend has a Servers card (name, URL, order, enabled; add and remove) that a platform admin saves into the list; everyone else sees it read-only, and a server that is not in the list shows the server's warning there. The last list is kept in the browser so the picker is there at the first paint after a reload. In plain words: add or switch off a server in Settings and every user's picker follows, with no rebuild · TASK-179
Atlas follows the server picker (TASK-179) — ai
with "All servers" picked, Atlas answers for the whole platform: "list the hosts" or "how many devices" gives one row per server (a Server line on each host) and the platform total, and names any server it could not ask (for example gcloud-standalone: 401). With one server picked it answers for that server only. An action on a device goes to the server that owns it, with your own login (the lock names you, not a service account): take control, press a key, get the screenshot, release. If two servers have a host of the same name, Atlas asks which one. The chat sends your login for that one message and the server keeps it in memory only; Atlas and the MCP tools take an optional server argument. In plain words: pick All servers and Atlas sees and drives every server's devices as you · TASK-179
Bug fixes — 15
BUG-0969 — Atlas no longer says a device does not exist when the chat sent no device list
Atlas's quick first step checks a device against the list of devices the chat page sends. A caller that sends no list (the chat script, an API client) had every device answered with "I don't see any device on this server", even one on another server that Atlas could reach. With no list there is nothing to check against, so the request now goes on to Atlas, which finds the server that owns the device. In plain words: "release device1 on lenovo-local-low" works from a script too
BUG-0968 — The Pokémon runner walks through the gate house of Route 15 on its way to Fuchsia City, instead of walking back and forth over the border with Route 14
the runner was asked to go from Route 15 to Fuchsia City, but the road to Fuchsia passes through the gate house across Route 15 (its two doors are on the route itself, and the route is cut in two without them). The map of the world only learns a place when the runner has been inside it, and the gate house had never been visited: the runner's map knew the door led to an unknown place, so it knew no way to Fuchsia. The guide then walked the runner back to the waypoint it came from — Route 14 — whose own next waypoint is Route 15 again, and the two swapped the runner for ever: no milestone, no new map and no new square for 5 min of game time until the stall detector wrote the run down (2026-10-27, fuchsia, 2261 walks over the same two squares). The places a milestone's stretch passes through are the way on when the next waypoint cannot be reached yet, so the gate house of Route 15 joins the ones of Route 12: the runner goes through it, learns its doors and walks on to Fuchsia. In plain words: the runner keeps walking south to Fuchsia instead of pacing at the top of Route 14
BUG-0967 — A navigation tree write answered with an empty 500 when the platform could not check whether the tree was a prod tree
the platform's own guard that keeps an edit off a prod tree (it re-aims the write at the dev tree the prod one was published from) reads the tree from the database. When the database could not be reached, the guard fell over instead of answering: the request died with a status code and an empty body, so the save looked like a crash with no cause, and the route it was aimed at never ran. The guard now asks the database only when there is one, and when the lookup itself fails the write is refused with a message the caller can read — the rule "an edit never lands on a prod tree" still holds. In plain words: a tree save that could not be checked now says why, instead of failing blank
BUG-0966 — The Pokémon runner fires the door it stands on instead of walking between its two halves
the player came through the elevator's door of the Rocket Hideout and stood on it, and the world graph knew no way out of the corridor he was in (the elevator is the only door of that part, and the elevator's cabin leads back to the floor it came from). The runner's way out was "the door next to me" — the other half of the same two-tile door — and moving between the two halves of a door never triggers a warp, so it walked (24, 19) and (25, 19) back and forth for 5 minutes until the stall detector wrote the run down (2026-10-27, poke_flute, no progress in 5 min). The door under the player's feet is now fired instead: the press goes into the wall next of it, which is what makes the Rocket elevator open. The elevator also no longer takes the floor it came from — the floor the map knows a way out of is taken, so the runner rides up to B2F and walks out through the Game Corner. In plain words: the runner rides the elevator out of the hideout instead of pacing in front of it
BUG-0965 — The Pokémon runner walks out of a room it cannot leave
a door is not part of the walkable squares of a map (stepping on it takes the player to another room), so the square the player stands on and the door can end up in two different parts of the map, and the map then looks like a place with no way out. The runner answered "no route" on every tick and stood still — 607 ticks in a row, on the one square next to the only door of the house on Route 5 — until the stall detector wrote the run down (2026-10-26, vermilion, same spot for 5 min). The door next to the player is now used: the runner steps on it and is out. In plain words: the runner leaves the room instead of standing in it
BUG-0963 — The Pokémon runner goes through Cerulean's trashed house on its way to Vermilion, instead of walking back and forth over the border with Route 24
the runner was asked to go from Cerulean City to Route 5, but Cerulean's south exit lies in another part of the city (the trashed house's two doors are the only way between the parts, and stepping on them warps the player into the house), so the world graph knew no way to Route 5. The guide then walked the runner back to the waypoint it came from — Route 24 — whose own next waypoint is Cerulean again, and the two swapped the runner for ever: no milestone, no new map and no new square for 5 min of game time until the stall detector wrote the run down (2026-10-26, vermilion, 29 walks over the same border). The maps a milestone lists as its stretch are the way on when the next waypoint cannot be reached yet, so they now win over the walk back: the runner explores the trashed house and takes the path under Route 5 to the underground path. In plain words: the runner keeps walking south to Vermilion instead of pacing at the top of Route 24
Build 90145 — 2026-10-26
| Platform | main-2026.10.26-90145 (b3de6dec) |
| Previous | main-2026.10.13-63726 |
| Date | 2026-10-26 |
| Features | ai-dataset, ai-test, avq, cicd, code-graph, companion, device-farm, gitlab, mobile-app, mods, quicktest, virtual-scripts, zammad |
The full release note (features, bug fixes, roll-out steps) is attached as release-notes-main-2026.10.26-90145.md.
Build 63726 — 2026-10-13
fix(auth): paint the real app chrome while auth resolves
App.tsx forced the minimal logo-only header whenever isLoading was true, so
every cold load of every page showed a stripped-down frame with an empty body
while AuthContext waited on a profile round trip. ProtectedRoute already gates
the protected subtree, so the chrome can render immediately instead.
Also raise ProtectedRoute's 'Checking authentication...' delay from 500ms to
1500ms: at 500ms it fired just before real content landed on a remote load,
replacing one loading screen with another.
Build 9396 — 2026-09-27
release: main-2026.09.27-9396 — docs only (standalone guide: docs refresh note); images unchanged from 9394
Build 9395 — 2026-09-27
release: main-2026.09.27-9395 — docs: standalone install behind a Cloudflare tunnel (hostnames, login, mail, VNC, media gate); docs only, images unchanged from 9394
Build 9394 — 2026-09-27
release: main-2026.09.27-9394 — frontend fetches host media manifests with credentials (BUG-0171 second half); supersedes 9393 (syntax error)
Build 9393 — 2026-09-27
release: main-2026.09.27-9393 — frontend fetches host media manifests with credentials (BUG-0171 second half)
Build 9391 — 2026-09-27
release: main-2026.09.27-9391 — Docker host serves nginx-style /host//stream/ gated by the host-session cookie (BUG-0171)
Build 9389 — 2026-09-27
release: main-2026.09.27-9389 — Docker host desktop is XFCE (matches native hosts); viewers may fetch stream URLs (BUG-0168); SMTP + ENABLE_EMAIL_AUTOCONFIRM for Docker stacks