External Perforce builds registered in hydraexperiencelibrary via POST /api/v1/builds/notify carry a build_url pointing at https://releases.experiencenet.com/builds/<project>/<cl>/Builds/<file>.zip, but hydrarelease no longer serves that path. Every body polling /api/v1/experiences/live receives this URL, tries to download, and gets HTTP 404. Experiences appear healthy in the library dashboard and in the promote/rollback API, while no fleet machine can actually install the build.
/var/www/releases/builds/soulmade/91/Builds/MercatorV0.9.zip (1.94 GB, sha256 0f67c044a24d13583228e40c4c5cac2a652735b920a177705168c31fe81cf002). File still intact there.build_url: https://releases.experiencenet.com/builds/soulmade/91/Builds/MercatorV0.9.zip.HTTP/2 404 because hydrarelease only serves /api/v1/builds/<project>/<number> (see internal/api/server.go:111), not raw /builds/* paths. The HYDRARELEASE_MIRROR_URL proxy only covers hydrarelease's own project releases, not external build files.builds/soulmade/91/ with size: 0 and no actual file on disk at /var/lib/hydramirror/files/builds/soulmade/91/. GET /api/v1/builds/soulmade/91 on hydrarelease returns build soulmade/91 not found.[experiences] provisioning mercator-talks build #5
[experiences] downloading mercator-talks from https://releases.experiencenet.com/builds/soulmade/91/Builds/MercatorV0.9.zip...
[experiences] failed to install mercator-talks: downloading: HTTP 404
The previous successful build (CL 88 / V0.8, build #3) is registered with a mirror URL (https://mirror-a.experiencenet.com/api/v1/files/builds/soulmade/88/MercatorV0.8.zip). That URL also 404s today. So the mirror was always the serving path; the release server rsync destination has been dead since the mirror migration.
On the release server: curl -T /var/www/releases/builds/soulmade/91/Builds/MercatorV0.9.zip --upload-file -H "Authorization: Bearer <mirror-token>" https://mirror-a.experiencenet.com/api/v1/files/builds/soulmade/91/MercatorV0.9.zip, then POST /api/v1/builds/notify with the mirror URL, then promote dev to staging and staging to production. Bodies installed build 6 within 3 minutes.
PUT /api/v1/files/builds/<project>/<cl>/<file>.zip (stream via curl -T, no rsync), and emit build_url pointing at the mirror. This matches how hydrarelease publishes its own service binaries./var/www/releases/builds/* as static files, which just restores the old URLs. Less clean because the mirror is now the canonical storage.linkMirrorFiles equivalent that runs when handleBuildNotify fires on hydraexperiencelibrary, reading from the release server and pushing to the mirror. Adds cross-service coupling.Option 1 is the cleanest and matches existing patterns. The watcher already knows the mirror is the target (memory says "hydrarelease uploads binaries to mirror-a, NOT to local disk"); the rsync-to-/var/www/releases path is leftover from pre-mirror days.
Every new Perforce-driven experience build is silently broken at the fleet install layer until someone manually re-publishes the zip to the mirror. Experience library metadata looks healthy, which hides the problem. Today this broke mercator-talks V0.9 for three weeks (registered 2026-03-31, noticed only today 2026-04-21 when promoted to production).
Blocked on deploy step: agent-side config swap.
v0.2.0 binary is published and will auto-update on the visitflanders agent. However, v0.2.0 validates that mirror.url is present, so on the next restart it will fail to start unless the config is migrated first.
The perforce.visitflanders.experiencenet.com machine (88.198.195.179) is not in any of the three configured hcloud contexts (hydraexperiencenet, nimsforest, cederik) and the Claude environment SSH key is not authorized on it. Cannot complete the swap from here.
What is left:
release_server block.mirror:\n url: https://mirror-a.experiencenet.com\n token: <HYDRARELEASE_MIRROR_TOKEN from /etc/hydrarelease.env on 46.225.120.7>.systemctl restart hydraperforcewatcher.To unblock remote execution next time, either add a visitflanders hcloud context to ~/.config/hcloud/cli.toml (if the machine is on a separate Hetzner project) or authorize the Claude environment public key on the machine's root account.
Implemented in 23235f2 and tagged v0.2.0. Pushed to origin main; GH Actions is building now (run 24730910436).
Next steps on the human side: