[MINOR] The self-test workflow uses ./.gitea/actions/review (the Gitea action path) even though it runs on GitHub. This means the GitHub runner will execute the .gitea/actions/review/action.yml file. This is intentional based on the comment ('Download binary from Gitea, post review to Gitea'), but it's slightly odd that the GitHub workflow uses the .gitea action path — the two action files are now identical, so it works, but it could confuse future maintainers who expect .github/workflows to use .github/actions.
[NIT] `ACTION_REPO="${{ inputs.action-repo
[MINOR] The VCS detection heuristic grep -qi 'gitea' matches on the word 'gitea' anywhere in the server URL. This works for the known cases (e.g. https://gitea.example.com) but would misfire for a GitHub Enterprise Server instance with 'gitea' in its hostname, or fail for a self-hosted Gitea instance that doesn't include 'gitea' in its URL (e.g. https://code.mycompany.com). A more robust approach would be to attempt the Gitea API path and fall back, or to expose an explicit api-version input. This is acceptable as a pragmatic heuristic for the stated use-cases but worth documenting as a known limitation.
[MINOR] The self-test workflow uses ./.gitea/actions/review (line 32: uses: ./.gitea/actions/review) rather than ./.github/actions/review. On GitHub the runner will look for local composite actions under .github/, not .gitea/. While GitHub Actions does allow resolving .gitea/ paths in some environments, this is unexpected and could break on a standard GitHub or GHES runner that doesn't support the Gitea convention. The intent of this workflow is to validate the GitHub path, so it should reference ./.github/actions/review.
[MINOR] The hostname-based VCS detection (grep -qi 'github') would misclassify a Gitea instance whose hostname happens to contain the word 'github' (e.g., github.internal-infra.corp). This is an edge case, but since the detection is heuristic and there is already a user-facing action-repo input, consider also providing an explicit vcs-type input or at least documenting the limitation.
[MINOR] The GitHub.com releases API endpoint is /api/v3/ only for GitHub Enterprise Server. On github.com the correct base URL is https://api.github.com, not https://github.com/api/v3/. So constructing ${SERVER_URL}/api/v3/repos/... will produce https://github.com/api/v3/repos/... which is a 404 on public GitHub. This is fine as long as this action is only ever hosted/running on GHES and Gitea (never on github.com itself), but the comment 'github.com uses /api/v3/ too' is incorrect and could mislead future maintainers.
[NIT] The truncated variable is initialized to false and only set to true in the loop body. Since Go zero-initializes booleans, the explicit false initialization is redundant. var truncated bool would be idiomatic, but this is extremely minor.
[NIT] The ListReviews method uses slog.Warn directly (package-level default logger) rather than a logger injected via the Client. This is consistent with the rest of the codebase based on what's visible, so it's fine — just worth noting that it makes the log output untestable without replacing the global logger.
[NIT] GetAuthenticatedUser is now in reviews.go, which is a reviews-focused file. It was previously in its own identity.go. A dedicated identity.go or user.go file would be more cohesive (per the file-organization-by-responsibility pattern), but this is a minor organizational concern — the PR description acknowledges the consolidation tradeoff.
[NIT] The truncation check at if page == maxPages is logically unreachable inside the loop body because the loop condition is page <= maxPages. When page == maxPages and len(responses) == perPage, the loop exits naturally after this iteration anyway (the next iteration would have page = maxPages+1 > maxPages). The truncated = true path is actually reached, but only on the final iteration when the page is full. This is correct behavior but slightly confusing — a comment clarifying 'this is the last iteration and the page was full, so data was likely cut off' would help readers. No functional bug; the logic is sound.
[NIT] Import ordering: fmt is inserted before encoding/json but goimports/gofmt would order stdlib imports alphabetically (context, encoding/json, errors, fmt, io, net/http, strings, testing). This is a minor style deviation that goimports would fix automatically.
[NIT] The comment // nil body: the GitHub DELETE endpoint for reviews requires no request body. was removed in the diff. It was a useful clarification for why nil is passed to doRequestWithBody. Consider retaining it or replacing with an equivalent inline comment.
[NIT] TestPostReview_CommitID uses io.ReadAll(r.Body) then json.Unmarshal, while the existing TestPostReview uses json.NewDecoder(r.Body).Decode. Inconsistent style within the same file, though not a correctness issue. Consider using the decoder pattern to match the surrounding tests.