Skip to content

feat(pr-review): land verified reviews on a GitHub PR#11

Merged
ojowwalker77 merged 3 commits into
mainfrom
feat/pr-review
Jun 24, 2026
Merged

feat(pr-review): land verified reviews on a GitHub PR#11
ojowwalker77 merged 3 commits into
mainfrom
feat/pr-review

Conversation

@ojowwalker77

@ojowwalker77 ojowwalker77 commented Jun 24, 2026

Copy link
Copy Markdown
Owner

Brings Splus closer to the PR review workflow: the agent's verified findings become a real GitHub PR review — inline comments anchored to the diff + a verdict — while staying local-first, agent-led, and key-free.

What's here

  • @splus/shared diff-anchor mapper (prReview.ts, +11 tests) — pure/deterministic file:line → GitHub RIGHT-side anchor. Multi-line within a hunk, collapses cross-hunk, folds out-of-diff findings into the summary (never dropped), picks the event from the must-fix count.
  • prReview MCP tool — read-only; returns the gh-ready JSON + the gh api .../reviews command. The server never shells gh — the agent posts.
  • splus-pr-review skill — resolve the PR (gh pr view) → review base..HEAD → post. Wired into install.sh.
  • Mirrored directive into skills/review; docs/TOOLS.md + CHANGELOG.

Test

This PR is itself the test — Splus reviews it via the new flow.

https://claude.ai/code/session_01477bB25ArAEBeAfLRswLn8


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

Bring Splus closer to the PR review workflow: turn the agent's verified
findings into a real GitHub pull-request review (inline comments + verdict),
without breaking the local-first, agent-led, no-API-key invariants.

- @splus/shared/prReview.ts — deterministic diff→comment anchor mapper
  (buildDiffAnchorIndex / anchorFinding / buildReviewPayload) + 11 tests.
  Resolves file:line to a RIGHT-side anchor, folds out-of-diff findings into
  the summary, picks the event from the must-fix count, tags comments for
  re-review dedup. Pure, zero-inference: the "where", not the "what".
- prReview MCP tool — read-only; returns the gh-ready payload + the
  `gh api .../reviews` command. The server never shells gh.
- splus-pr-review skill — resolve the PR → review base..HEAD → post.
  Wired into install.sh for Claude/Codex/OpenCode.
- Mirrored the directive into skills/review; docs/TOOLS.md + CHANGELOG.

Claude-Session: https://claude.ai/code/session_01477bB25ArAEBeAfLRswLn8

@ojowwalker77 ojowwalker77 left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Splus review — 💬 comment (0 must-fix)

Reviewed main...HEAD (9 files, +688) at SCIP-precise tier. The PR is the test of its own feature — and the feature found a real bug in itself: buildDiffAnchorIndex treats the trailing "" that git diff leaves after split("\n") as a context line, so the last file in any diff gets one phantom commentable line past its final hunk (an inline comment there would 422). One concern below, plus the engine's complexity nit. No must-fix → comment, not request-changes.

flowchart LR
  pr["prReview.ts<br/>mapper · 1 concern"]:::hot --> idx["index.ts<br/>re-export"]
  idx --> mcp["mcp/index.ts<br/>prReview tool"]
  skill["skills/pr-review"] -.drives.-> mcp
  classDef hot fill:#3a0d0d,stroke:#e5534b,color:#fff;
Loading

Posted by the new prReview flow (payload built by @splus/shared, posted via gh api).

Comment thread packages/shared/src/prReview.ts Outdated
const marker = raw[0];
if (marker === "\\") continue; // "\ No newline at end of file" — not a real line
if (marker === "-") continue; // removed (LEFT only) — doesn't advance the new side
if (marker === "+" || marker === " " || raw === "") {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

concern · maintainability/correctness — phantom commentable line

diff.split("\n") on real git diff output (always newline-terminated) yields a trailing "". Inside the last file's last hunk, inHunk is still true, so this raw === "" clause classifies that empty string as a context line: it adds newLine to commentable and advances. Result: one line past the final hunk is reported anchorable, and anchorFinding would emit a line GitHub rejects with 422.

Git always emits a space marker for context lines (even blank ones → " "), so an empty string inside a hunk is only ever the split artifact — drop the clause:

Suggested change
if (marker === "+" || marker === " " || raw === "") {
if (marker === "+" || marker === " ") {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 4c9dc6a — dropped the raw === "" clause and added a regression test (a trailing newline … does not add a phantom line). The mapper found this in itself. ✅

* Those — and only those — are the lines GitHub will accept an inline RIGHT-side
* comment on. Removed (`-`) lines never advance the new side and aren't included.
*/
export function buildDiffAnchorIndex(diff: string): DiffAnchorIndex {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit · maintainability.cognitive-complexity — complexity 26

Inherent to a line-by-line diff state machine, but reviewable-ness would improve by extracting the hunk-body line classification (the marker switch) into a small classifyBodyLine helper. Not blocking.

The self-review on PR #11 caught it: `git diff` output is newline-terminated,
so `split("\n")` leaves a trailing "". Inside the last file's last hunk that
empty string was classified as a context line, marking one line past the final
hunk as anchorable (an inline comment there would 422). Git always emits a
space marker for context lines, so a bare "" inside a hunk is only the split
artifact — drop the `raw === ""` clause. Adds a regression test.

Claude-Session: https://claude.ai/code/session_01477bB25ArAEBeAfLRswLn8
normalizePath only stripped the default a/ b/ prefixes; under
diff.mnemonicPrefix git emits c/ i/ o/ w/, so findings silently fell to the
summary instead of anchoring inline. Strip the full one-letter prefix set.
Fails safe under diff.noprefix (bare paths left as-is). Adds a test.

Claude-Session: https://claude.ai/code/session_01477bB25ArAEBeAfLRswLn8
@ojowwalker77 ojowwalker77 merged commit 66b7b96 into main Jun 24, 2026
2 checks passed
@ojowwalker77 ojowwalker77 deleted the feat/pr-review branch June 24, 2026 19:38
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