Skip to content

Merge dev into main: GitLab diff-aware review anchors and note fallback - #125

Merged
factory-nizar merged 3 commits into
mainfrom
dev
Aug 13, 2026
Merged

Merge dev into main: GitLab diff-aware review anchors and note fallback#125
factory-nizar merged 3 commits into
mainfrom
dev

Conversation

@factory-nizar

Copy link
Copy Markdown
Contributor

Ships #124 to main (the only delta between dev and main):

  • Diff-aware inline comment anchoring for GitLab review posting (added → new_line, removed → old_line, context → both) — fixes the customer-reported GitLab API 400: Bad Request on context-line anchors
  • Plain-note fallback for out-of-diff anchors
  • GitLab API error bodies surfaced in error messages
  • Softened all-failed hard-fail; prompt guardrails for anchor lines

Validation: 577 unit tests, typecheck, prettier, review feedback addressed, plus a live e2e replication on a scratch GitLab project (old code reproduced the 400s byte-for-byte; fixed code posted every anchor type correctly).

Part of VAL-14

factory-nizar and others added 3 commits August 12, 2026 18:17
gitlab-post-review sent `new_line`-only positions for every RIGHT-side
comment, but GitLab requires both line numbers for unchanged context
lines and refuses lines outside the diff entirely, so those findings
400'd and the job hard-failed (seen on a customer MR where both
approved comments targeted untouched code).

- Build a per-file line index from the MR changes and shape each
  position to the line's role: added -> new_line, removed -> old_line,
  context -> both.
- Post comments whose line is not in the diff (or that GitLab refuses)
  as plain MR notes instead of dropping them; only comments failing
  both routes count as failures, and the job only hard-fails when
  nothing reached the MR at all.
- Surface the GitLab error response body in GitlabApiError messages
  ("400 Bad Request" alone was undebuggable from CI logs).
- Track fallback counts in review_post_results.json and the sticky
  tracking note.
- Tell Pass 1/Pass 2 prompts (GitHub + GitLab) that anchors must be
  lines visible in the diff.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
…wording

- validator prompt: mention removed/LEFT lines as valid anchors and what
  `side` means for the line anchor
- ReviewPostOutcome.failed doc + tracking note: `failed` now means both
  inline and note fallback failed, not an anchoring refusal
- fallbackNoteBody: use old_path for LEFT-side comments and drop the
  "outside the MR diff" claim (API refusals also land here)

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
fix(gitlab): diff-aware anchors and note fallback for review posting
@factory-droid

factory-droid Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Droid finished @factory-nizar's task —— View job


Security Review

The diff-aware GitLab anchoring changes look solid and are well-covered by tests. Remaining follow-ups are prompt wording around LEFT-side anchors, slightly misleading tracking-note text for fallback notes, and minor hardening for Markdown injection in fallback-note locations.

@factory-nizar
factory-nizar merged commit fca711f into main Aug 13, 2026
9 checks passed
'Relative file path (use the new_path from the diff, e.g., "src/index.ts")',
lineFieldDescription:
"Target line number in the new file (single-line) or end line number (multi-line). Must be ≥ 0.",
"Target line number in the new file (single-line) or end line number (multi-line). Must be ≥ 0. " +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2] Mention LEFT-side anchors (removed lines) in GitLab terminology

This still says the anchor is "in the new file" and only mentions added/context lines, but the posting code now supports side: "LEFT" anchors to old-file (removed) lines. Updating this description will help the model emit correct anchors and reduce fallback-to-note.

Suggested change
"Target line number in the new file (single-line) or end line number (multi-line). Must be ≥ 0. " +
lineFieldDescription:
"Target line number (single-line) or end line number (multi-line). Must be ≥ 0. " +
"Must be a line that appears in the MR diff (added, removed, or context inside a hunk). " +
"Use side: \"RIGHT\" to anchor to the new-file line and side: \"LEFT\" to anchor to the old-file line. " +
"A finding about untouched code should anchor to the nearest related changed line instead.",

counts.push(
`${review.fallbackPosted} posted as ${
review.fallbackPosted === 1 ? "a regular note" : "regular notes"
} (line outside the diff)`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2] Don’t attribute all fallback notes to out-of-diff lines

fallbackPosted counts any case where inline posting fails but the MR note fallback succeeds, including API refusals that aren’t strictly "line outside the diff". The tracking note text currently hard-codes the out-of-diff explanation.

Suggested change
} (line outside the diff)`,
`${review.fallbackPosted} posted as ${
review.fallbackPosted === 1 ? "a regular note" : "regular notes"
} (could not be posted inline)`,

): string {
const filePath =
comment.side === "LEFT" ? (comment.old_path ?? comment.path) : comment.path;
const location = line !== null ? `${filePath}:${line}` : filePath;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2] [security] Sanitize/validate file paths in fallback MR notes

fallbackNoteBody() interpolates comment.path/comment.old_path into a Markdown inline-code span without escaping, but parseValidatedReview() accepts any non-empty string. If the validated JSON is prompt-injected, a path containing backticks or newlines can break out of the code span and inject arbitrary Markdown into the bot-posted MR note. Consider validating paths against the MR changes list (or at least stripping control chars/backticks) before formatting location.

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