feat: surface inline-comment anchor fields on pr view --reviews (task 0034) #42

Merged
alexion merged 2 commits from task-0034-pr-review-anchor-fields into main 2026-07-18 16:13:04 -04:00
Owner

Completes both halves of the inline-review round-trip from the pr-review-comments spec, as two commits on one branch:

  • .claude/tasks/0034-pr-review-anchor-fields.md — read side
  • .claude/tasks/0035-pr-review-inline-comments.md — write side

Read side (task 0034)

pr view <n> --reviews now surfaces each inline review comment's anchor so an agent can answer and reply without a second API call:

  • id — the comment's own id, the handle a reply targets.
  • resolvedyes/no, from whether Gitea populated the comment's resolver.
  • diff_hunk — structurally trimmed to its @@ header line plus its last two lines by default (hunks of three lines or fewer left whole), verbatim under --full. The trim is trimDiffHunk in src/diff.ts, distinct from the char-based body truncation.

Raw position/original_position offsets stay unsurfaced; the fields ride the existing fetch (no extra API calls).

Write side (task 0035)

pr review <n> gains --comments-file <path>, a JSON array of inline comments submitted with the review. Each entry is one of two exclusive shapes (no side field anywhere):

  • New comment { path, line, body }new_position on the new side.
  • Reply { reply_to, body } → gitea-axi finds the target via the reviews-plus-comments fan-out (no get-comment-by-id endpoint), reconstructs its anchor from the target's own diff_hunk (anchorFromDiffHunk), and infers old/new side from it, so a same-line post threads with the existing conversation.

All entries map onto the review-submission payload's comments[] — no new HTTP layer. The action flag is still required and top-level --body composes with the batch. An unknown reply_to is a VALIDATION_ERROR raised before the POST; the submitted count rides the action block.

Built test-first at the fixture-server CLI seam. Full suite 400 passing, typecheck clean.

Review

/review-uncommitted ran on each slice; every Standards and Spec finding was fixed in-branch (extracted the shared src/flag-file.ts reader; tightened --comments-file shape validation to reject contradictory entries and to refuse a target lacking path/diff_hunk; replaced a fabricated comment-id sentinel with a reviewCommentId guard). No findings remain unaddressed.

Risk

  • Read side (0034): Low — additive, isolated read-only rendering, well tested.
  • Write side (0035): Medium
    • Blast radius: Medium — new flag + module, existing prReview only additively modified.
    • Reversibility: Low — purely additive; no migrations or breaking signatures.
    • Test coverage: Low — five fixture tests cover new-comment, both reply sides, the error path, and body composition.
    • Sensitive domain: Medium — constructs review-submission payloads with hand-rolled diff-hunk line arithmetic (well tested on both sides).
    • Size & complexity: Medium — the anchorFromDiffHunk hunk-walk is the one non-trivial spot.
    • Runtime criticality: Medium — an opt-in CLI write path that POSTs to a live PR, not a hot path.
Completes both halves of the inline-review round-trip from the `pr-review-comments` spec, as two commits on one branch: - `.claude/tasks/0034-pr-review-anchor-fields.md` — read side - `.claude/tasks/0035-pr-review-inline-comments.md` — write side ## Read side (task 0034) `pr view <n> --reviews` now surfaces each inline review comment's anchor so an agent can answer and reply without a second API call: - `id` — the comment's own id, the handle a reply targets. - `resolved` — `yes`/`no`, from whether Gitea populated the comment's `resolver`. - `diff_hunk` — structurally trimmed to its `@@` header line plus its last two lines by default (hunks of three lines or fewer left whole), verbatim under `--full`. The trim is `trimDiffHunk` in `src/diff.ts`, distinct from the char-based body truncation. Raw `position`/`original_position` offsets stay unsurfaced; the fields ride the existing fetch (no extra API calls). ## Write side (task 0035) `pr review <n>` gains `--comments-file <path>`, a JSON array of inline comments submitted with the review. Each entry is one of two exclusive shapes (no `side` field anywhere): - New comment `{ path, line, body }` → `new_position` on the new side. - Reply `{ reply_to, body }` → gitea-axi finds the target via the reviews-plus-comments fan-out (no get-comment-by-id endpoint), reconstructs its anchor from the target's own `diff_hunk` (`anchorFromDiffHunk`), and infers old/new side from it, so a same-line post threads with the existing conversation. All entries map onto the review-submission payload's `comments[]` — no new HTTP layer. The action flag is still required and top-level `--body` composes with the batch. An unknown `reply_to` is a `VALIDATION_ERROR` raised before the POST; the submitted count rides the action block. Built test-first at the fixture-server CLI seam. Full suite 400 passing, typecheck clean. ## Review `/review-uncommitted` ran on each slice; every Standards and Spec finding was fixed in-branch (extracted the shared `src/flag-file.ts` reader; tightened `--comments-file` shape validation to reject contradictory entries and to refuse a target lacking path/diff_hunk; replaced a fabricated comment-id sentinel with a `reviewCommentId` guard). No findings remain unaddressed. ### Risk - Read side (0034): **Low** — additive, isolated read-only rendering, well tested. - Write side (0035): **Medium** - Blast radius: Medium — new flag + module, existing `prReview` only additively modified. - Reversibility: Low — purely additive; no migrations or breaking signatures. - Test coverage: Low — five fixture tests cover new-comment, both reply sides, the error path, and body composition. - Sensitive domain: Medium — constructs review-submission payloads with hand-rolled diff-hunk line arithmetic (well tested on both sides). - Size & complexity: Medium — the `anchorFromDiffHunk` hunk-walk is the one non-trivial spot. - Runtime criticality: Medium — an opt-in CLI write path that POSTs to a live PR, not a hot path.
alexion added 2 commits 2026-07-18 16:11:46 -04:00
Each inline review comment under `pr view <n> --reviews` now renders its
`id` (the handle a reply targets), `resolved` (`yes`/`no`, from whether
Gitea populated the comment's `resolver`), and `diff_hunk`. The hunk is
structurally trimmed to its `@@` header line plus its last two lines by
default (hunks of three lines or fewer are left whole) and emitted
verbatim under `--full`, so the trim never touches the char-based body
truncation path. The raw `position`/`original_position` diff offsets stay
unsurfaced. The fields ride the existing reviews-plus-per-review-comments
fetch — no extra API calls.
feat: add --comments-file to pr review for inline comments (task 0035)
All checks were successful
CI / test (pull_request) Successful in 55s
CI / test (push) Successful in 53s
662ba82d71
`pr review <n>` gains `--comments-file <path>`, a JSON array of inline
comments submitted with the review. Each entry is one of two exclusive
shapes: a new comment `{ path, line, body }` (mapped to `new_position`,
always the new side) or a reply `{ reply_to, body }`. A reply carries no
line or side — gitea-axi finds the target via the reviews-plus-comments
fan-out (there is no get-comment-by-id endpoint), reconstructs its anchor
from the target's own `diff_hunk`, and infers old/new side from it, so a
same-line post threads with the existing conversation. All entries map
onto the review-submission payload's `comments[]`; no new HTTP layer is
added. An unknown `reply_to` is a VALIDATION_ERROR raised before the POST,
and the submitted inline-comment count rides the action block.

The shared path-resolve-and-read behind --body-file and --comments-file is
extracted into src/flag-file.ts.
alexion force-pushed task-0034-pr-review-anchor-fields from 4e9e4cb9d3 to 662ba82d71 2026-07-18 16:11:46 -04:00 Compare
alexion merged commit 662ba82d71 into main 2026-07-18 16:13:04 -04:00
alexion deleted branch task-0034-pr-review-anchor-fields 2026-07-18 16:13:04 -04:00
Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: alexion/gitea-axi#42