fix(windows): a web-console deploy that half-succeeded stops reporting success
windows-host / package (push) Failing after 26s
windows-host / canary-manifest (push) Skipped
windows-host / winget-source (push) Skipped
ci / web (push) Successful in 1m7s
apple / swift (push) Successful in 1m28s
ci / rust-arm64 (push) Successful in 1m57s
ci / docs-site (push) Successful in 2m31s
docker / builders (--build-arg FEDORA_VERSION=44, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm, -f44) (push) Successful in 6s
docker / builders (ci/android-ci.Dockerfile, punktfunk-android-ci) (push) Successful in 7s
docker / builders (ci/arch-ci.Dockerfile, punktfunk-arch-ci) (push) Successful in 7s
docker / builders (ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 6s
docker / builders (ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 7s
docker / builders (ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 6s
deb / build-publish-client-arm64 (push) Successful in 2m22s
docker / apps (., web/Dockerfile, punktfunk-web) (push) Successful in 48s
deb / build-publish-host (push) Successful in 4m38s
docker / apps (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 1m26s
deb / build-publish (push) Successful in 5m45s
docker / builders-arm64cross (push) Successful in 13s
docker / deploy-docs (push) Successful in 31s
android / android (push) Successful in 7m33s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 6m55s
arch / build-publish (push) Successful in 8m58s
ci / rust (push) Successful in 7m17s
flatpak / build-publish (push) Successful in 7m11s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 4m2s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 4m39s
release / apple (push) Successful in 16m28s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 17m39s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 17m59s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 8m53s
apple / screenshots (push) Canceled after 16m31s

Found by investigating a console that had been serving errors on .173 for
hours while every health check said HTTP 200.

Nitro's `entry.mjs` imports its sibling chunks by CONTENT HASH, so a
`.output` that mixes two builds is not degraded — it is dead: bun answers
every page with a `ResolveMessage` JSON body ("Cannot find module
../_/router-<hash>.mjs") under a 200 status. Two defects here let exactly
that ship and then hid it:

* The pre-copy `Remove-Item` used `-ErrorAction SilentlyContinue`, so a
  removal blocked by a still-running bun was swallowed and `Copy-Item`
  merged the new build into the old tree. (Reproduced live: an older
  task-based copy of this script, run against the now supervised-child
  host, tried `schtasks /end` for a task that no longer exists, never
  stopped the service, and so could never unlock the files.) The removal
  is now verified and refuses to copy over a tree it could not clear.
* The success probe read only the status code, so it reported a healthy
  console for a server that serves nothing but an error. It now checks
  that `/login` actually returns HTML, and says so loudly when the body
  is a module-resolution error instead.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-31 22:40:26 +02:00
co-authored by Claude Fable 5
parent 2ce0bea830
commit 47eb8c9f6f
+24 -7
View File
@@ -31,9 +31,20 @@ if (-not (Test-Path $appWeb)) {
}
Write-Host "swapping $appWeb\.output (stopping the PunktfunkHost service) ..."
$dst = Join-Path $appWeb '.output'
& net stop PunktfunkHost | Out-Null
try {
Remove-Item (Join-Path $appWeb '.output') -Recurse -Force -ErrorAction SilentlyContinue
# The removal MUST succeed before the copy. A merge of two builds is not a degraded
# install, it is a dead one: Nitro's entry.mjs imports its siblings by content hash, so a
# stale chunks/_ next to a new entry.mjs makes every page 200 with a bun ResolveMessage
# body instead of the app. Observed on .173 2026-07-31 (an older task-based copy of this
# script could not unlock the files under the supervised-child host, its
# -ErrorAction SilentlyContinue swallowed that, and the console served a JSON error for
# hours while the probe below reported success).
Remove-Item $dst -Recurse -Force -ErrorAction SilentlyContinue
if (Test-Path $dst) {
throw "could not remove $dst (files still locked - is another bun/host still running?). Refusing to copy over it: a mixed .output serves errors, not the console."
}
Copy-Item (Join-Path $web '.output') -Destination $appWeb -Recurse -Force
}
finally {
@@ -43,14 +54,20 @@ finally {
# The console serves HTTPS-only (PUNKTFUNK_UI_SECURE=1, the host's own cert) - probe with curl.exe
# (-k for the self-signed cert; Invoke-WebRequest under Windows PowerShell 5.1, which this script
# runs under, has no -SkipCertificateCheck), retrying while the service/bun cold-starts.
$code = $null
#
# The BODY is the check, not the status code: a bun that started but cannot resolve its own
# chunks answers 200 with a ResolveMessage JSON, so a code-only probe reports a healthy
# console that serves nothing but an error (exactly how the .173 breakage stayed invisible).
$body = $null
for ($i = 0; $i -lt 15; $i++) {
Start-Sleep 2
$code = & curl.exe -sk -o NUL -w '%{http_code}' --max-time 5 'https://127.0.0.1:47992/login' 2>$null
if ($code -eq '200') { break }
$body = & curl.exe -sk --max-time 5 'https://127.0.0.1:47992/login' 2>$null
if ($body -match '<html|<!DOCTYPE html') { break }
}
if ($code -eq '200') {
Write-Host "DONE - web /login -> HTTP $code"
if ($body -match '<html|<!DOCTYPE html') {
Write-Host "DONE - the console serves the app (/login returned HTML)"
} elseif ($body -match 'Cannot find module|ResolveMessage') {
Write-Error "BROKEN - /login answered with a bun module-resolution error, i.e. .output is inconsistent: $body"
} else {
Write-Warning "console swapped but /login did not return 200 yet (last: $code) - check %ProgramData%\punktfunk\logs\web.log"
Write-Warning "console swapped but /login did not serve HTML yet - check %ProgramData%\punktfunk\logs\web.log. Last body: $body"
}