A stored bundle is a success — Android stops reporting 201 as a failed log upload #416

Merged
enricobuehler merged 1 commits from worktree-android-sendlogs-201 into main 2026-08-27 16:43:39 +00:00
Owner

Several users reported getting "201" when sending logs to the host from Android. The upload was working the whole time — the client was calling success a failure.

What was happening

POST /api/v1/client-logs answers 201 Created. It is a route that stores a bundle, and it has said so since the feature landed — crates/punktfunk-host/src/mgmt/client_logs.rs returns StatusCode::CREATED and documents it as the "Bundle stored" response.

The Android uploader tested for 200 exactly:

if (resp.code == 200) "" else "host answered HTTP ${resp.code}"

So the toast read "Couldn't send logs — host answered HTTP 201" while the bundle was already sitting on the host's web console Logs page.

That is worse than a cosmetic lie. It invites a retry, and the store keeps only 5 bundles per device — a few retries evict the reporter's own earlier logs, which are exactly the ones the report was about.

The fix

One line, at the only place the status is judged. The check now uses OkHttp's own isSuccessful (200..299) instead of a hand-written code, so there is no second list of numbers to drift out of sync with the host.

Since the send-logs action was spread to every Android UI, both shells — the Skia console's host menu and the touch home's card menu — route through SendLogs.toHost, so this covers both.

Why only Android

The other legs were already correct and are untouched:

  • AppleLibraryClient.swift matches case 200, 201.
  • Desktop (Linux/Windows) — the ureq path returns Ok for any 2xx; only 4xx/5xx become Error::StatusCode.
  • webOS — no leg yet.

A sweep of the remaining strict-200 comparisons across the clients found only GET art/status fetches, where 200 genuinely is the sole success. Nothing else to change.

Verification

./gradlew :app:compileDebugKotlin — BUILD SUCCESSFUL, with the task executed rather than served from cache. No test accompanies it: the fix deletes a hand-rolled predicate in favour of the library's, so the remaining assertion would only be testing OkHttp.

Not fixed on glass — worth confirming the success toast on a device once this lands.

Note for rebases

Four unmerged worktree-android-* branches still carry the pre-extraction inline copy of this line in SkiaConsole.kt (console-extra-keys, gamepad-ui-and-corner, pad-hid-remap, pad-mapping-regression). Rebasing them onto main drops that block entirely, since the upload has moved to SendLogs.kt — just don't resurrect the old == 200 while resolving.

Several users reported getting "201" when sending logs to the host from Android. The upload was working the whole time — the client was calling success a failure. ## What was happening `POST /api/v1/client-logs` answers **201 Created**. It is a route that stores a bundle, and it has said so since the feature landed — `crates/punktfunk-host/src/mgmt/client_logs.rs` returns `StatusCode::CREATED` and documents it as the "Bundle stored" response. The Android uploader tested for 200 exactly: ```kotlin if (resp.code == 200) "" else "host answered HTTP ${resp.code}" ``` So the toast read **"Couldn't send logs — host answered HTTP 201"** while the bundle was already sitting on the host's web console Logs page. That is worse than a cosmetic lie. It invites a retry, and the store keeps only 5 bundles per device — a few retries evict the reporter's own earlier logs, which are exactly the ones the report was about. ## The fix One line, at the only place the status is judged. The check now uses OkHttp's own `isSuccessful` (200..299) instead of a hand-written code, so there is no second list of numbers to drift out of sync with the host. Since the send-logs action was spread to every Android UI, both shells — the Skia console's host menu and the touch home's card menu — route through `SendLogs.toHost`, so this covers both. ## Why only Android The other legs were already correct and are untouched: - **Apple** — `LibraryClient.swift` matches `case 200, 201`. - **Desktop (Linux/Windows)** — the ureq path returns `Ok` for any 2xx; only 4xx/5xx become `Error::StatusCode`. - **webOS** — no leg yet. A sweep of the remaining strict-200 comparisons across the clients found only GET art/status fetches, where 200 genuinely is the sole success. Nothing else to change. ## Verification `./gradlew :app:compileDebugKotlin` — BUILD SUCCESSFUL, with the task **executed** rather than served from cache. No test accompanies it: the fix deletes a hand-rolled predicate in favour of the library's, so the remaining assertion would only be testing OkHttp. Not fixed on glass — worth confirming the success toast on a device once this lands. ## Note for rebases Four unmerged `worktree-android-*` branches still carry the pre-extraction inline copy of this line in `SkiaConsole.kt` (`console-extra-keys`, `gamepad-ui-and-corner`, `pad-hid-remap`, `pad-mapping-regression`). Rebasing them onto main drops that block entirely, since the upload has moved to `SendLogs.kt` — just don't resurrect the old `== 200` while resolving.
enricobuehler added 1 commit 2026-08-27 16:34:19 +00:00
fix(android): a stored bundle is a success — 201 stops reading as a failure
ci / web (pull_request) Successful in 1m10s
ci / docs-site (pull_request) Successful in 1m13s
ci / bun-nix (pull_request) Successful in 1m15s
ci / docs-drift (pull_request) Successful in 1m16s
ci / rust-arm64 (pull_request) Successful in 1m33s
android / android (pull_request) Successful in 5m57s
ci / rust (pull_request) Successful in 9m56s
ec621882f0
Field reports of "201" when sending logs to the host: the upload was working
the whole time, and the client was calling it an error.

`POST /api/v1/client-logs` answers **201 Created** — it is a route that STORES
a bundle, and it has said so since the feature landed (`mgmt/client_logs.rs`,
where CREATED is both the returned status and the documented one). The Android
uploader tested `resp.code == 200` and treated everything else as a failure, so
the user got "Couldn't send logs — host answered HTTP 201" while their bundle
was already sitting on the host's web console Logs page. Worse than a cosmetic
lie: it invites a retry, and the store keeps only 5 bundles per device, so a
few retries evict the reporter's own earlier logs.

The check now uses OkHttp's `isSuccessful` (200..299) rather than a
hand-written code, so there is no second list of numbers to fall out of sync
with the host.

One line covers both Android shells: since the send-logs work spread the action
to every UI, the Skia console and the touch home both route through
`SendLogs.toHost`, which is the only place the status is judged.

The other legs were already correct and are untouched: Apple matches
`case 200, 201` (`LibraryClient.swift`), and the desktop ureq path treats any
2xx as `Ok` — only 4xx/5xx become `Error::StatusCode`. A sweep of the remaining
strict-200 comparisons in the clients found only GET art/status fetches, where
200 really is the sole success.

Verified with `./gradlew :app:compileDebugKotlin` (task executed, not cached).
enricobuehler merged commit 29bfbcb950 into main 2026-08-27 16:43:39 +00:00
enricobuehler deleted branch worktree-android-sendlogs-201 2026-08-27 16:43:49 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: unom/punktfunk#416