Skip to content

feat: write a review comment against a line from the file view - #30

Closed
JacobAtchley wants to merge 2 commits into
feat/file-viewfrom
feat/inline-comments
Closed

JacobAtchley wants to merge 2 commits into
feat/file-viewfrom
feat/inline-comments

Conversation

@JacobAtchley

Copy link
Copy Markdown
Owner

Stacked on #29 — base is feat/file-view, so the diff here is only the comment feature. Merge #29 first and this retargets to main on its own.

The file view knows which line the cursor is on, and the pull request pane knows how to show a discussion. Nothing could start one — leaving a review comment meant the web UI.

What it does

c opens a prompt against the cursor's line and posts a thread anchored there. The comment appears under the line as soon as the server takes it: added to what the view already holds rather than refetched, because the thread is known and waiting for a round trip to see your own comment reads as the comment having failed.

The prompt owns every key while open, so d typed into it is a letter rather than the diff toggle — the same discipline as the branch and reply prompts.

Refusals

A line the pull request removed is not in the new file, so there is nothing for the server to anchor to. Refused before the request with the reason, the precedent armDraft sets: a check that only happens at the network call hides why behind an error code.

An empty prompt closed with enter is a mistake, not a request to post nothing.

The one unverified thing

CreateThread sends the position as a start and an end, both at column one of the commented line, which is how Azure DevOps spells a whole-line comment. Whether it accepts that exact shape is from the reference, not from a live tenant — and unlike the other unverified assertions, a rejection here loses something you typed.

It goes in the README's list with an explicit recommendation: write one comment on a throwaway pull request before relying on c. I did not want to post a real comment to a real pull request to find out, but say the word and I'll smoke-test one.

Refactor included

Parsing a thread payload moves into threadJSON.thread(). Two endpoints now answer with that shape — listing a discussion and creating one thread — and a second copy of the parsing is a second place for it to drift. Threads() uses it too, so the existing tests cover the extraction.

Tests

Client: the request method, path and body, including that the context carries filePath, both positions and an offset; the created thread coming back parsed with its line and side; a rejection carrying the server's own message.

View: the prompt opens on the cursor's line and names it; enter posts; an empty comment does not; esc cancels; d is swallowed as a letter; a removed line is refused with the reason and reported as a failure; a posted comment appears without a refetch; a failure lands on the status line; a thread for another file is ignored, since Root broadcasts to every view in the stack.

Full suite and go vet pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KT78DJemENKXRQsfKzZPmn

JacobAtchley and others added 2 commits September 19, 2026 14:23
The file view knows which line the cursor is on and the pull request
pane knows how to show a discussion; nothing could start one. Leaving a
review comment meant the web UI.

c opens a prompt against the cursor's line and posts a thread anchored
there. The comment appears under the line as soon as the server takes
it, added to what the view already holds rather than refetched: the
thread is known, and waiting for a round trip to see your own comment
reads as the comment having failed.

A line the pull request removed is not in the new file, so there is
nothing for the server to anchor to. Refused before the request with
the reason, the precedent armDraft sets — a check that only happens at
the network call hides why behind an error code.

CreateThread sends the position as a start and an end, both at column
one of the line, which is how Azure DevOps spells a whole-line comment.
Whether it accepts that exact shape is the one thing here not seen
against a live tenant, so it goes in the README's list — and it is
worth a single comment on a throwaway pull request before relying on
it, since a rejection loses something you typed.

Parsing a thread payload moves into threadJSON.thread(). Two endpoints
now answer with that shape — listing a discussion and creating one
thread — and a second copy of the parsing is a second place for it to
drift.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KT78DJemENKXRQsfKzZPmn
Smoke-testing inline comments against a real pull request turned up a
CRLF README, and every composed line carried a trailing \r.

The carriage return is not part of the line. A terminal reading one
returns the cursor to column zero, so the padding the viewport writes
after the text would overwrite the text. Bubbles strips control
characters before it paints, which is why this was invisible rather
than broken — but the pane's correctness should not rest on a detail
of a component underneath it, and fileLine.Text should hold the line
rather than the line plus a control character.

Dropped where the lines are made, so both the file's own lines and the
removed ones recovered from the hunks are clean.

Also verified in the same run: the threadContext boardwalk sends is
accepted. A comment posted against new-side line 6 of a real pull
request came back anchored to line 6 on the right side, and read back
the same from the threads endpoint. That entry leaves the README's
unverified list, and the note recommending a smoke test before relying
on c goes with it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KT78DJemENKXRQsfKzZPmn
@JacobAtchley

Copy link
Copy Markdown
Owner Author

Smoke-tested against the sandbox — it works

Ran the real code path (buildFileDiff → composeFile → CreateThread → Threads) against PR 11917 in temp-sandbox:

fileDiff: 1 hunks, 868 bytes of text
composed 22 rows
  + new=6   "4.\tAPI references ( of course )"
  + new=7   "5.  Have A Party"
posting against new-side line 6
created thread #90224 file="/README.md" line=6 right=true comments=1
  server says: #90224 file="/README.md" line=6 right=true

The threadContext shape is accepted, the comment anchors to the line asked for, and it reads back the same from the threads endpoint. That entry is out of the README's unverified list, along with the note recommending a smoke test before relying on c.

And it found a bug

That README is CRLF, so every composed line carried a trailing \r.

A terminal reading a carriage return returns the cursor to column zero — so the padding the viewport writes after the text would overwrite the text. Bubbles strips control characters before painting, which made this invisible rather than broken, but the pane's correctness should not rest on a detail of a component underneath it, and fileLine.Text should hold the line rather than the line plus a control character.

Dropped where the lines are made, so both the file's own lines and the removed ones recovered from the hunks are clean. Pushed as a second commit here with a test.

Two smoke-test comments (#90223, #90224) are on 11917 and can be deleted.

@JacobAtchley

Copy link
Copy Markdown
Owner Author

Superseded by #31 — GitHub closed this automatically when feat/file-view was deleted along with #29. Same branch, rebased onto main; the smoke-test results above still stand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant