No task waits on a Codex review; the redesign tasks are confirmed on the product owner's Z Fold7; TASK-016's leftovers are on hold; no biometric reauthentication. Agent: main (opus) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4.3 KiB
TASK-023: Tolerate a literal JSON null list response
Status: implemented; all required checks pass; physical-device retest confirmed Owner: Claude Reviewer: Codex
Outcome
A repository whose branch (or any other list-shaped) endpoint returns the literal JSON body null — Go's encoding/json serializes a nil slice this way instead of [] — is treated as an empty list, not a parse failure. Previously this surfaced as a generic "Gitea 서버에서 오류가 발생했습니다" (server error) on both the repository-list row's last-pushed-branch indicator and the repository's reference (branch/tag) screen, even though the HTTP response itself was a completely successful 200 OK.
Incident evidence
Reproduced live on the human product owner's authenticated device via wireless adb, against real repositories RobotAutomationDevelopment-Dept/CSOT-T8-iPTN-AMA and CSOT-T8-MACRO_SA. Confirmed via the Gitea container's own request log (Container Manager → 로그) that the branches request returned 200 OK in ~7ms — not a server-side failure. A temporary debug-only diagnostic (Log.e, removed before commit) then captured the actual response body for the failing call: bodyLen=5 bodyPreview=null — the literal 4-character JSON null (plus a trailing artifact in the length count), not an array. GiteaRepositoryBrowserApi.parseList deserialized that to Kotlin null via Gson (no exception), then unconditionally threw ApiFailure.InvalidResponse() on a null parse result — a general-purpose fallback meant for a body that failed to deserialize at all, not for a body that correctly deserializes to "no items."
Acceptance criteria
- A JSON
nullresponse body from anyparseList-backed endpoint (branches, tags, commits, etc.) maps to an empty list rather than a thrown failure. - Existing malformed/genuinely-invalid JSON still throws
ApiFailure.InvalidResponse()(only the specific null-body case changed). - A unit test reproduces the literal
nullbody case forlistBranches. - Verified live on the reporting device:
CSOT-T8-iPTN-AMA(the repository used for diagnosis) now opens correctly instead of showing the generic server-error screen.CSOT-T8-MACRO_SAwas not individually re-confirmed by the human product owner, but is expected to behave identically since the fix is in the sharedparseListhelper both repositories go through. - Build, unit tests, lint, and secret scan pass.
Writable paths
app/src/main/java/com/ubisam/ubgitea/data/repositories/GiteaRepositoryBrowserApi.ktapp/src/test/java/com/ubisam/ubgitea/data/repositories/GiteaRepositoryBrowserApiTest.kttasks/023-tolerate-null-list-responses.md
Required checks
./gradlew assembleDebug
./gradlew testDebugUnitTest
./gradlew lintDebug
Evidence
GiteaRepositoryBrowserApi.kt's privateparseList<T>helper:gson.fromJson<List<T>>(body, type) ?: throw ApiFailure.InvalidResponse()changed to?: emptyList(). This is the single shared helper used bylistBranches,listTags,listCommits, and repository listing, so the fix applies uniformly rather than only to the one endpoint that happened to be reported — the same Go nil-slice-to-null serialization can equally affect any of them.- A genuinely malformed body (unparseable JSON) still throws
ApiFailure.InvalidResponse()via the existingcatch (_: JsonParseException)— only a body that Gson successfully parses tonullchanged behavior. - Diagnostic method: added temporary
BuildConfig.DEBUG-gatedLog.ecalls at three points (loadReferences's catch,listBranches's per-item mapping, and the raw response body) to narrow the failure down via live logcat over a wireless-adbconnection to the reporting device, then removed all three before committing — none of that scaffolding is part of this change. ./gradlew assembleDebug testDebugUnitTest lintDebug --rerun-tasks: BUILD SUCCESSFUL, all unit tests passing, 0 lint errors.git diff --check: clean. Secret-pattern scan of the diff: no matches.- Live device retest: reinstalled the fixed build over wireless
adbon the reporting device (paired via wireless debugging in this session) and the human product owner confirmedCSOT-T8-iPTN-AMAnow opens correctly.
Review findings
None yet — no Codex review pending (Codex retired, 2026-09-29).