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.
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.
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.
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).
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
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-logsanswers 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.rsreturnsStatusCode::CREATEDand documents it as the "Bundle stored" response.The Android uploader tested for 200 exactly:
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:
LibraryClient.swiftmatchescase 200, 201.Okfor any 2xx; only 4xx/5xx becomeError::StatusCode.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 inSkiaConsole.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 toSendLogs.kt— just don't resurrect the old== 200while resolving.