Skip to content

add-pr-comment: render inline threads as applyable single/multi-line suggestions (fix ready on fork) #1099

Description

@YuliiaKovalova

Proposed fix: render add-pr-comment inline threads as applyable single/multi-line suggestions

I have a fix ready on a fork branch but cannot open a PR directly (this repo limits PR creation to collaborators). The branch is rebased on current main and "Able to merge":

A maintainer can open the PR from that compare link, or pull/cherry-pick the three commits below. Happy to be added as a collaborator so I can open it myself.


Problem

The add-pr-comment safe output produces inline suggestion threads that Azure DevOps renders as broken, non-applyable comments. There are three distinct facets of the same problem, each demonstrated live against real ADO PRs.

1. Zero-width anchor → concatenated / duplicated line

The inline thread is anchored with rightFileEnd at offset 1, i.e. a zero-width range (L184:1 → L184:1). ADO treats a zero-width anchor as an insertion point, so applying a single-line suggestion prepends the suggested text to the original line instead of replacing it:

Mock.Of<IProgress>(MockBehavior.Loose), … Progress = Mock.Of<IProgress>(),

Fix: anchor rightFileEnd to (UTF-16 length of the last covered line) + 1 (CRLF-safe) so the range covers the whole line(s) and Apply performs a clean replace. Adds a pure inline_thread_context() helper plus line_end_offset(), with unit tests for the single- and multi-line cases.

2. Fenced suggestion body HTML-escaped

sanitize()escape_html_tags escapes all </>, including the contents of the ```suggestion fence, so applying the suggestion writes literal &lt;/&gt; into the file. Fix: escape_html_tags is now fence-aware — lines inside ```/~~~ fences pass through verbatim, matching how every Markdown renderer (including ADO) treats fenced code.

3. Inline `code` spans in prose HTML-escaped

The same escaper also mangles inline-code spans in the comment prose, e.g. `Mock.Of<IProgress>()` renders as Mock.Of&lt;IProgress&gt;(). Fix: escape_html_tags now also preserves backtick-delimited inline code. A run of k backticks is closed only by a run of exactly k backticks on the same line; an unmatched backtick is treated as a literal and the remainder of the line is still escaped, so HTML cannot evade neutralization.

Why skipping the escape is safe

Markdown renderers (including ADO) render fenced and inline code literally and never interpret HTML inside them, so leaving </> un-escaped there matches renderer behaviour — any smuggled HTML stays inert. Backtick-run matching slices only at backtick (ASCII 0x60) boundaries, so it is byte-safe for multi-byte UTF-8 content.

Validation

  • cargo test --bins sanitize — 77 passed (5 new tests across the three fixes).
  • cargo clippy --bins — clean.
  • cargo fmt --check — clean.
  • Demonstrated end-to-end by running the patched ado-aw execute against real ADO PRs:
    • Single + multi-line: anchors L1:1→L1:78 and L1:1→L2:49, literal <...>, one-click Apply.
    • Worst-case production repro (Moq1400, line 184): anchor L184:1→L184:45, clean whole-line replace, literal <...> in both the prose inline-code spans and the suggestion body, no &lt;.

Commits

  • 65268f2 feat(safe-outputs): render add-pr-comment inline threads as applyable suggestions
  • 4764358 fix(safe-outputs): preserve fenced code blocks when escaping HTML
  • 01a0096 fix(safe-outputs): preserve inline code spans when escaping HTML

Files touched

  • src/safeoutputs/add_pr_comment.rs — anchor / inline_thread_context() / line_end_offset() + tests + agent-facing schema docs.
  • src/sanitize.rs — fence-aware and inline-code-aware escape_html_tags + tests.
  • docs/safe-outputs.md — "Inline applyable suggestions" section.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions