Ubisam-MobileGit/docs/development-log.md
choiminyeong 93b8d587ee Sort repositories by recent push, page the list, show last-pushed branch
TASK-017, human product owner priority-1 request. Repository list now
requests sort=updated&order=desc from Gitea, loads 5 repositories per
page with explicit prev/next navigation, and each visible row
independently fetches and shows its most recently committed branch.

Removes the legacy eager-loading RepositoryListApi in favor of the
existing paged GiteaRepositoryBrowser.listRepositories. Fixes two
issues found in self-review: missing error handling on page
navigation, and repositories with no default branch (empty repos)
previously failing the whole page instead of just that row.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-26 13:24:31 +09:00

24 KiB

UBGitea development log

This is the append-only implementation and handoff record shared by Codex and Claude. Only the current task owner or assigned reviewer may append an entry, and agents never edit this file concurrently.

2026-08-25 — TASK-001

  • Agent and role: Codex, implementer and integrator
  • Commit/diff: 75aa5f8
  • Features implemented: Android Compose project bootstrap, Korean placeholder home screen, deterministic Gradle wrapper, unit-test and lint baseline.
  • How it was implemented: One application module using Kotlin, Compose, Material 3, API 28 minimum, API 36 target, JDK 17, and version-catalog-managed dependencies.
  • Files changed: Root Gradle configuration, app/, ADR-001, product and task documentation.
  • Checks and results: Debug APK build passed; 1 unit test passed; lint passed; sensitive-pattern scan found no assigned secret.
  • Review findings and resolutions: Independent review found no P0-P3 findings.
  • Known limitations: No device/emulator launch; final icon and authentication were out of scope.
  • Next recommended task: Repository browsing foundations.
  • Next owner: Codex.

2026-08-25 — TASK-003

  • Agent and role: Codex, implementer and integrator
  • Commit/diff: a2cc7d4
  • Features implemented: Immutable repository, branch, tree, file, commit and paging domain contracts; safe coordinate/ref/path validation; read-only repository interface and browse use cases.
  • How it was implemented: Pure Kotlin domain models, defensive byte/list copies, shared pagination validation, Korean read-only placeholder state, and fake-adapter unit tests.
  • Files changed: Domain model/repository/use-case packages, focused tests, home placeholder, product roadmap and TASK-003 through TASK-007 documents.
  • Checks and results: Build passed; 22 unit tests passed; lint passed; sensitive-pattern and diff checks passed.
  • Review findings and resolutions: Two P2 findings covering page output mutability and missing use-case boundary tests were fixed and independently re-reviewed; no findings remain.
  • Known limitations: Live HTTP, authentication, navigation, content rendering, and device testing were out of scope.
  • Next recommended task: OAuth protocol core followed by Android OAuth integration.
  • Next owner: Codex.

2026-08-25 — TASK-002A

  • Agent and role: Codex, implementer and integrator
  • Commit/diff: 6da016c
  • Features implemented: OAuth client configuration, approved read-only scopes, fresh PKCE S256 verifier/state generation, authorization URL construction, exact redirect validation, transaction expiry, denial/success modeling, and strict callback query validation.
  • How it was implemented: Pure Kotlin/JDK code with SecureRandom, SHA-256, unpadded Base64 URL encoding, RFC 7636 verifier grammar, deterministic query component encoding, constant-time state comparison, strict UTF-8 percent decoding, duplicate/ambiguous response rejection, saturating time boundaries, and redacted string representations for sensitive values.
  • Files changed: core/auth/protocol/, matching protocol tests, ADR-002, TASK-002 umbrella, TASK-002A, and TASK-002B.
  • Checks and results: Focused OAuth tests 21/21 passed; full unit tests 43/43 passed; debug APK build passed; Android lint passed; diff check passed; sensitive-pattern scan found no assigned secret/token/password/private key.
  • Review findings and resolutions: P2 verifier grammar fixed with strict RFC character/length validation; P2 parameter pollution and malformed UTF-8 fixed with fail-closed parsing; P3 timestamp overflow fixed with saturating boundaries. Independent re-review found no remaining P0-P3 findings.
  • Known limitations: System browser launch, App Link dispatch, code exchange, Keystore token vault, user identity, and real-server E2E are intentionally deferred to TASK-002B. E2E remains blocked by signing fingerprints and hosted assetlinks.json.
  • Next recommended task: TASK-002B Android OAuth integration, completing locally testable browser/storage/exchange boundaries before the external E2E gate.
  • Next owner: Codex.

2026-08-25 — TASK-011

  • Agent and role: Codex, implementer and integrator
  • Commit/diff: current TASK-011 working-tree diff; user-owned assetlinks.json excluded
  • Features implemented: System-browser Gitea OAuth login, verified HTTPS App Link callback, PKCE code exchange without a client secret, Keystore-backed token storage and logout, authenticated identity check, and a paginated list of every repository visible to the account.
  • How it was implemented: Exact callback validation reuses TASK-002A; pending verifier/state is consumed once; OkHttp runs asynchronously with cancellation/error propagation; Gson DTOs fail closed into typed API errors; /api/v1/user precedes bounded/deduplicated /api/v1/user/repos; Compose exposes localized signed-out, browser-waiting/cancel, loading, content, empty, offline, permission, expired-auth, callback, and server-error states.
  • Files changed: Android manifest and extraction rules, network/auth/repository data layers, repository ViewModel/Compose screen, dependencies/resources, focused tests, and TASK-002B/004/005/011 status documentation.
  • Checks and results: Debug APK build passed; 57 unit tests across 16 suites passed; Android lint passed; diff and sensitive-pattern checks passed; no WebView or production client secret exists.
  • Review findings and resolutions: Browser cancellation dead-end, HTTP response-read exception handling, signed-in error recovery/logout, nullable DTO validation, immutable UI snapshots, and bounded pagination coverage were fixed. Final independent re-review reported no remaining P0/P1.
  • Known limitations: No Android device is connected, so the hosted App Link, system-browser return, live account login, repository result, and device Keystore behavior require one manual E2E run on the target phone.
  • Next recommended task: Install the debug APK on the target Android device and verify login plus the internal repository list; after that, begin branch browsing.
  • Next owner: Human product owner for device E2E, then Codex.

2026-08-25 — TASK-011 device E2E closure

  • Agent and role: Human product owner, device verifier; Codex, evidence recorder
  • Verification performed: Installed application login against the production company Gitea and retrieval of the authenticated account's internal repository list.
  • Result: System-browser OAuth, verified App Link return, authenticated API access, and repository-list rendering passed on the target device.
  • Review status: Automated gates previously passed and final independent review reported no P0/P1; the remaining manual device gate is now closed.
  • Task status: TASK-011 complete.
  • Next recommended task: Add repository selection and branch listing.
  • Next owner: Codex.

2026-08-25 — TASK-012

  • Agent and role: Codex, workflow implementer
  • Commit/diff: TASK-012 documentation diff
  • Features implemented: Durable current-state and remaining-roadmap handoff, Claude working-style prompt, and bidirectional append-only question/answer mailboxes.
  • How it was implemented: Writer-specific directories and immutable per-message files preserve the single-writer protocol; the roadmap orders work by frozen-contract dependencies and assigns one owner per task.
  • Files changed: handoff/, TASK-006A status, TASK-012, collaboration documentation, and this log.
  • Checks and results: Documentation paths, baseline commits, ownership, task dependencies, and mailbox cross-references inspected; no Android code or external infrastructure changed.
  • Review findings and resolutions: Pending Claude read-only review of the handoff package.
  • Known limitations: Mailboxes coordinate repository-based handoff and do not provide real-time notification; agents must inspect them at task start.
  • Next recommended task: Claude implements TASK-006A only and hands its commit to Codex for review.
  • Next owner: Claude.

2026-08-25 — TASK-012 review closure and activation

  • Agent and role: Codex, finding resolver and handoff owner; Claude, independent read-only reviewer
  • Commit/diff: reviewed package commit 57d1c09; immutable activation ref handoff/task-006a-ready
  • Findings resolved: Canonical delivery sequence now explicitly permits independent TASK-006A before the TASK-004/005 remainder; TASK-006A authorizes only its completion-log append; both mailbox directions share symmetric immutable templates and unique correction filenames; completed OAuth evidence is synchronized.
  • Checks and results: Documentation cross-references and task dependencies inspected; git diff --check passed before activation; no Android production file or external infrastructure changed.
  • Review result: No handoff activation occurs until the tag resolves to the committed metadata state. Claude checks out the tag, creates a claude/ branch, implements TASK-006A only, and then stops for Codex review.
  • Known limitation: Repository mailboxes are asynchronous and must be checked manually at task start.
  • Next owner: Claude for TASK-006A.

2026-08-25 — TASK-006A implementation

  • Agent and role: Claude, assigned feature implementer (writable scope limited to feature/codebrowser/content/ and this task's evidence/log entries)
  • Commit/diff: branch claude/task-006a-ready created from activation tag handoff/task-006a-ready (base 965d55d); implementation adds ContentClassification.kt, SourceContentClassifier.kt, and SourceContentClassifierTest.kt under feature/codebrowser/content/
  • Features implemented: Pure-Kotlin classifier that turns already-loaded SourceContent bytes into one of five immutable states — bounded text (with independent line/character truncation flags), binary, Git LFS pointer, unsupported encoding, or oversized — using caller-supplied positive byte/character/line limits.
  • How it was implemented: Oversized input is rejected by raw byte count before any decoding; binary is detected by a raw NUL-byte scan; text decoding uses a strict UTF-8 CharsetDecoder with CodingErrorAction.REPORT for malformed and unmappable input so it never substitutes replacement characters; a Git LFS pointer is recognized only from the exact canonical version line followed by valid oid sha256:<64 hex> and size <integer> lines within the 1024-byte spec bound; remaining text is truncated independently by line count and character count with an explicit isTruncated flag. No shared domain, data, Gradle, manifest, or navigation file was modified; RepositoryModels.kt/RepositoryPath.kt/RepositoryRef.kt remain identical to contract-freeze commit 0929282.
  • Files changed: app/src/main/java/com/ubisam/ubgitea/feature/codebrowser/content/ContentClassification.kt, app/src/main/java/com/ubisam/ubgitea/feature/codebrowser/content/SourceContentClassifier.kt, app/src/test/java/com/ubisam/ubgitea/feature/codebrowser/content/SourceContentClassifierTest.kt, tasks/006a-code-content-classifier.md (evidence/status), this log entry.
  • Checks and results: ./gradlew testDebugUnitTest --tests "com.ubisam.ubgitea.feature.codebrowser.content.*" passed (25/25); ./gradlew assembleDebug testDebugUnitTest lintDebug --rerun-tasks passed (82 unit tests repository-wide, 0 failures; lint 0 errors, 22 pre-existing warnings unchanged from TASK-001 baseline); git diff --check clean; sensitive-pattern scan of changed files found no secret/token/password/private-key markers.
  • Review findings and resolutions: None yet — pending Codex read-only review.
  • Known limitations: No Android device/emulator was used, since this task has no Android framework dependency (pure JVM-testable Kotlin); static formatting/check task remains unconfigured for the module.
  • Next recommended task: Codex reviews this commit read-only per docs/workstreams.md cross-review rules; TASK-006 UI remains blocked until Codex freezes the TASK-004/005 contracts.
  • Next owner: Codex, for review.

2026-08-26 — TASK-006A Codex integration review

  • Agent and role: Codex, integrator and reviewer
  • Commit/diff: Claude commit 979729a, integrated as 4f5faf3, plus Codex Unicode-boundary fix
  • Review findings and resolutions: One P2 was found: UTF-16 substring truncation could split an emoji or another supplementary character into a lone surrogate. Rendering now counts and truncates Unicode code points, with a focused emoji regression test.
  • Checks and results: Focused classifier, full unit-test, debug-build, lint, diff, and sensitive-pattern gates are rerun after the fix.
  • Known limitations: TASK-006 remains blocked on completion and freeze of the TASK-004/005 API and navigation contracts.
  • Next recommended task: Codex completes the TASK-004 branch/tag/tree/file API remainder, then TASK-005 repository selection and branch browsing.
  • Next owner: Codex.

2026-08-26 — TASK-004

  • Agent and role: Codex, implementer and integrator
  • Commit/diff: TASK-004 working diff following ed2121b
  • Features implemented: Authenticated read-only repository, branch, tag, directory-tree, Base64 source-file, and commit API adapter with immutable pagination.
  • How it was implemented: OkHttp HttpUrl encodes every owner/repository/path segment and ref/path query independently; private nullable Gson DTOs validate before mapping; bearer-token access is injected; contents arrays are locally paged; file type/path/encoding/size are verified; HTTP and network outcomes use typed failures.
  • Files changed: Core network failures, repository data adapter/tests, tag domain/use-case contracts, HTTP decision ADR, Gradle test dependency, TASK-004 evidence, and this log.
  • Checks and results: Focused in-memory and MockWebServer tests passed; repository-wide debug build and lint passed; 90 unit tests across 19 suites passed with zero failures/errors; diff check and focused sensitive-pattern scan passed.
  • Review findings and resolutions: Self-review added page-overflow protection, returned-file path matching, nullable size validation, Unicode-safe prior classifier integration, and a real local HTTP boundary test.
  • Known limitations: Gitea contents has no server-side pagination, so later directory pages repeat the request and slice the immutable returned snapshot locally.
  • Review status: Codex completed source/contract self-review. Independent review is deferred while the user has assigned the serial implementation stream to Codex and must be completed before TASK-006 contract freeze.
  • Next recommended task: TASK-005 repository selection and branch/tag browsing UI.
  • Next owner: Codex.

2026-08-26 — TASK-005

  • Agent and role: Codex, implementer and integrator.
  • Commit/diff: TASK-005 working diff following 8a47d30; the exact completion commit is recorded after commit creation.
  • Features implemented: Repository selection plus repository-scoped branch and tag browsing, default/protected/selected reference indicators, abbreviated commit IDs, refresh, retry, logout, and deterministic back navigation.
  • How it was implemented: A unidirectional immutable ViewModel state machine consumes the TASK-004 read-only browser contract, loads bounded pages serially, deduplicates references by name, cancels replaced work, and restores the cached repository-list snapshot. Small gateway interfaces make authentication and repository restoration JVM-testable without Android framework construction.
  • Files changed: Repository Compose/ViewModel/presenter and tests, MainActivity callback wiring, testable authentication/repository gateway boundaries, localized repository strings, and TASK-005 evidence.
  • Checks and results: Focused presenter/ViewModel tests passed; repository-wide debug build, 96 unit tests across 21 suites, and Android lint passed; diff and focused sensitive-pattern checks passed.
  • Review findings and resolutions: Self-review added immutable reference snapshots, operation cancellation on back navigation, typed reference errors retaining repository context, and ViewModel tests for selection/restoration/error behavior. Independent review is deferred while Codex owns the serial stream.
  • Known limitations: No device/emulator interaction test was available in this work cycle. The reviewed contract-freeze checkbox remains open until independent integration review.
  • Next recommended task: TASK-006 directory navigation and bounded source-file viewing using the TASK-004 API and reviewed TASK-006A classifier.
  • Next owner: Codex for continuous implementation; Claude may later perform the independent review when re-enabled by the product owner.

2026-08-26 — TASK-006

  • Agent and role: Codex, temporary feature implementer and integrator while Claude work is paused.
  • Commit/diff: TASK-006 working diff based on TASK-005 commit bbbff77; exact implementation commit recorded after creation.
  • Features implemented: Explicit branch/tag tree browsing, deterministic breadcrumbs and back navigation, directory/file selection, bounded selectable/copyable source text, and dedicated binary/LFS/unsupported-encoding/oversized/symlink/submodule fallbacks.
  • How it was implemented: A feature-owned immutable ViewModel state machine passes repository coordinates, ref, and validated path to every TASK-004 read-only request. It consumes bounded pages serially, cancels replaced work, retains file-vs-directory retry intent, and delegates byte classification to the reviewed TASK-006A component. The Compose screen keeps repository/ref/path visible and virtualizes directory rows.
  • Files changed: Code-browser ViewModel, navigation helper, Compose screen, Korean resources, focused tests, MainActivity feature wiring, selected-reference handoff, and TASK-006 evidence.
  • Checks and results: Focused code-browser tests passed; repository-wide debug build, 102 unit tests across 23 suites, and Android lint passed; diff and focused sensitive-pattern/read-only scans passed.
  • Review findings and resolutions: Self-review fixed root-loading back behavior, file retry incorrectly becoming a directory request, file breadcrumbs attempting directory loads, configuration-change screen loss, and non-virtualized directory rendering. Independent review is deferred.
  • Known limitations: Physical-device interaction has not yet been rerun. TASK-005's reviewed contract-freeze criterion remains open pending later independent review.
  • Next recommended task: TASK-009 immutable history/change/diff API contracts, followed by TASK-007 read-only history and change UI.
  • Next owner: Codex for the continuous serial stream.

2026-08-26 — TASK-004/005/006 independent review and freeze

  • Agent and role: Claude, independent reviewer per handoff/claude-master-handoff.md's "review and freeze" first action; human product owner authorized Claude as incoming primary implementer with handback to Codex kept possible at any time.
  • Commit/diff: reviewed 8a47d30 (TASK-004), bbbff77 (TASK-005), 16c46a5 (TASK-006) read-only, then fixed one finding on branch claude/review-005-006-freeze from 16c46a5.
  • Review scope and method: Independently reran assembleDebug testDebugUnitTest lintDebug --rerun-tasks (did not trust the recorded evidence alone) and read GiteaRepositoryBrowserApi.kt, HttpTransport.kt, RepositoryListViewModel.kt, RepositoryReferencePresenter.kt, CodeBrowserViewModel.kt, CodeBrowserNavigation.kt, and MainActivity.kt against the master handoff's checklist: races/cancellation, root back, rotation restoration, URL encoding, immutable snapshots, page overflow, and 404/409/422 mapping. TASK-009's commit was not yet available (still uncommitted upstream) and was excluded from this pass per human product owner direction.
  • Findings:
    • P2 (fixed): core/network/HttpTransport.kt requireSuccess() mapped 401/403/404/429/5xx but let 409 and 422 fall through to the generic ApiFailure.InvalidResponse, which would have blocked TASK-007's planned conflict/unprocessable UDF states. Added ApiFailure.Conflict/ApiFailure.Unprocessable and extended GiteaRepositoryBrowserApiTest's status-mapping test.
    • P3 (recorded, not fixed): CodeBrowserViewModel runs JSON parsing, Base64 decoding, directory sort/dedupe, and the TASK-006A classifier on viewModelScope's Main dispatcher after the network suspend point resumes. Not blocking; recommended for TASK-016 (release hardening) given its low-end-device and large-content scope.
    • Everything else checked (races/cancellation, root back via BackHandler in both screens, immutable snapshot wrapping, page-overflow bounds, URL component encoding) verified correct with no finding.
  • Checks and results after the fix: assembleDebug testDebugUnitTest lintDebug --rerun-tasks BUILD SUCCESSFUL, 102 unit tests across 23 suites, 0 failures/errors, 0 lint errors; git diff --check clean; sensitive-pattern scan clean (one match was a test asserting client_secret absence, not a leak).
  • Task evidence updated: TASK-004, TASK-005, and TASK-006 each record this closure. TASK-005's "reviewed completion commit is TASK-006's contract-freeze base" and TASK-006's "evidence records the exact reviewed TASK-005 contract-freeze commit" checkboxes are both closed. TASK-009's corresponding freeze checkbox remains open pending its own commit and review.
  • Known limitations: No physical device was available, so device-interaction checks named in TASK-005/006 remain deferred, unchanged from before this review.
  • Next recommended task: TASK-007 (history and change UI), per the ordered backlog in handoff/claude-master-handoff.md, once TASK-009 lands and is reviewed; TASK-010 (work-item API contracts) ownership is transferred to Claude per the same handoff.
  • Next owner: Claude, continuing the primary implementer role with handback to Codex available at any time by flipping a task's Owner field back and picking up from its last recorded commit.

2026-08-26 — TASK-017: recent-push sort, paged repository list, last-pushed branch

  • Agent and role: Claude, feature implementer, per human product owner priority-1 request in conversation on 2026-08-26.
  • Commit/diff: branch claude/task-017-recent-push-favorites from fdda164; new task file tasks/017-repository-list-recent-push.md.
  • Features implemented: Repository list is now sorted most-recently-pushed-first (server-side sort=updated&order=desc, correct across page boundaries), paged 5 at a time with explicit previous/next navigation, and each visible repository independently shows (and can retry) its most recently committed branch.
  • How it was implemented: Added updatedAtEpochMillis to RepositorySummary and commitAtEpochMillis to BranchSummary, mapped from Gitea's updated_at and branch commit.timestamp. Replaced the legacy eager-loading RepositoryListApi/AccessibleRepositoriesGateway with the existing paged GiteaRepositoryBrowser.listRepositories. RepositoryListViewModel now tracks a page number and launches one cancellable job per visible row to fetch and compare that repository's branch timestamps; jobs are cancelled on page change/refresh/navigation-away and resumed (not restarted) when returning via back-navigation.
  • Files changed: domain/model/RepositoryModels.kt, data/repositories/GiteaRepositoryBrowserApi.kt, removed data/repositories/RepositoryListApi.kt and its test, feature/repositories/RepositoryListViewModel.kt, feature/repositories/RepositoryListScreen.kt, MainActivity.kt, strings_repositories.xml, associated tests, tasks/017-repository-list-recent-push.md.
  • Checks and results: assembleDebug testDebugUnitTest lintDebug --rerun-tasks BUILD SUCCESSFUL — 105 unit tests across 22 suites, 0 failures/errors, 0 lint errors; git diff --check clean (CRLF notices only); sensitive-pattern scan clean.
  • Review findings and resolutions: Self-review caught and fixed two issues before they shipped: (1) page-navigation/refresh calls had no try/catch, which would have crashed the app on any network failure during nextPage()/previousPage()/refreshRepositories() — wrapped in the same error-mapping pattern used elsewhere; (2) a repository with no default branch (a real Gitea state for empty repos) would have failed the entire page load via the existing fail-closed .required() mapping — defaultBranch is now nullable at the domain level, matching how the UI already handled it. Independent Codex review is pending.
  • Known limitations: No physical device was available to verify page navigation and per-row branch loading interactively. Timestamp ties between two branches resolve deterministically but arbitrarily (first match kept).
  • Next recommended task: TASK-018 (Gitea-star favorites tab), already scoped in tasks/018-favorites-gitea-star.md, is next; Codex review of TASK-017 can happen in parallel since it touches non-overlapping paths once merged.
  • Next owner: Codex for read-only review of TASK-017; Claude continuing to TASK-018.