Skip to content

Guard suggested fixes against comment loss in five linters - #57860

Merged
pelikhan merged 3 commits into
mainfrom
copilot/sergo-fix-linters-silent-delete
Sep 2, 2026
Merged

Guard suggested fixes against comment loss in five linters#57860
pelikhan merged 3 commits into
mainfrom
copilot/sergo-fix-linters-silent-delete

Conversation

Copilot AI commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Five linters (appendoneelement, timenowsub, stringsjoinone, stringscountcontains, and stringsindexcontains) generated whole-expression TextEdit autofixes without checking for overlapping comments. Because AST printing drops comments, running go analysis -fix silently deleted inline or trailing comments falling inside the replaced span.

// Before: -fix rewrote the AST node text, dropping inline comments
s = append(s, []int{x /* important */}...) // -> append(s, x) (comment silently lost)
d := time.Now().Sub(t /* start time */)     // -> time.Since(t)  (comment silently lost)

// After: SuggestedFix is suppressed when HasOverlappingComment returns true, preserving source comments

Changes

  • Shared AST helper (pkg/linters/internal/astutil): Added files []*ast.File parameter to BuildContainsFix and guarded suggested fix construction with astutil.HasOverlappingComment.
  • Contains linters (stringscountcontains, stringsindexcontains): Updated callers to pass pass.Files into BuildContainsFix.
  • Expression linters (appendoneelement, timenowsub, stringsjoinone): Guarded SuggestedFixes attachment with !astutil.HasOverlappingComment(pass.Files, pos, end).
  • Test coverage: Added comment-overlap unit tests in astutil_test.go and corresponding badWithComments golden testdata fixtures across all five linter test packages.

…oinone, stringscountcontains, and stringsindexcontains linters

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix linters that silently delete comments in code Guard suggested fixes against comment loss in five linters Sep 2, 2026
Copilot AI requested a review from pelikhan September 2, 2026 05:45
@pelikhan
pelikhan marked this pull request as ready for review September 2, 2026 05:47
Copilot AI balanced review requested due to automatic review settings September 2, 2026 05:47
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Test Quality Sentinel completed test quality analysis.

Test Quality Sentinel skipped because pre-fetch PR data was unavailable: unable to fetch test file diff

🧪 Test quality analysis by Test Quality Sentinel

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

PR Code Quality Reviewer completed the code quality review.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

⚠️ Security scanning failed for Ponytail Reviewer. Review the logs for details.

Lean already. Ship.

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • ab.chatgpt.com

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "ab.chatgpt.com"

See Network Configuration for more information.

Generated by Ponytail Reviewer for #57860

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Design Decision Gate 🏗️ completed the design decision gate check. See the comment below for the result and any generated ADR draft.

Warning

Firewall blocked 2 domains

The following domains were blocked by the firewall during workflow execution:

  • github.com
  • proxy.golang.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "github.com"
    - "proxy.golang.org"

See Network Configuration for more information.

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • proxy.golang.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "proxy.golang.org"

See Network Configuration for more information.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer

Copilot AI left a comment

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.

🟢 Approval recommended

The guards cover every identified replacement path and the golden tests verify diagnostics remain while unsafe fixes are withheld.

Pull request overview

Prevents five Go linters from deleting comments when applying whole-expression suggested fixes, resolving #57844.

Changes:

  • Suppresses fixes when replacement spans overlap comments.
  • Passes parsed files into the shared contains-fix helper.
  • Adds golden and unit coverage for comment preservation.
File summaries
File Description
pkg/linters/appendoneelement/appendoneelement.go Guards suggested fixes against comments.
pkg/linters/appendoneelement/testdata/src/appendoneelement/appendoneelement.go Adds inline-comment fixture.
pkg/linters/appendoneelement/testdata/src/appendoneelement/appendoneelement.go.golden Verifies fix suppression.
pkg/linters/timenowsub/timenowsub.go Guards suggested fixes against comments.
pkg/linters/timenowsub/testdata/src/timenowsub/timenowsub.go Adds inline-comment fixture.
pkg/linters/timenowsub/testdata/src/timenowsub/timenowsub.go.golden Verifies fix suppression.
pkg/linters/stringsjoinone/stringsjoinone.go Guards suggested fixes against comments.
pkg/linters/stringsjoinone/testdata/src/stringsjoinone/stringsjoinone.go Adds inline-comment fixture.
pkg/linters/stringsjoinone/testdata/src/stringsjoinone/stringsjoinone.go.golden Verifies fix suppression.
pkg/linters/stringscountcontains/stringscountcontains.go Supplies files to the guarded helper.
pkg/linters/stringscountcontains/testdata/src/stringscountcontains/stringscountcontains.go Adds comment-overlap fixture.
pkg/linters/stringscountcontains/testdata/src/stringscountcontains/stringscountcontains.go.golden Verifies fix suppression.
pkg/linters/stringsindexcontains/stringsindexcontains.go Supplies files to the guarded helper.
pkg/linters/stringsindexcontains/testdata/src/stringsindexcontains/stringsindexcontains.go Adds comment-overlap fixture.
pkg/linters/stringsindexcontains/testdata/src/stringsindexcontains/stringsindexcontains.go.golden Verifies fix suppression.
pkg/linters/internal/astutil/astutil.go Centralizes comment-overlap protection.
pkg/linters/internal/astutil/astutil_test.go Tests guarded fix construction.
Review details
  • Files reviewed: 17/17 changed files
  • Comments generated: 0
  • Review effort level: Balanced

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Comment Memory

reviewed_at: 2026-09-02T05:53:26Z
review_event: REQUEST_CHANGES
top_themes:
  - missing regression coverage for comment-overlap handling in timenowsub
files_reviewed:
  - pkg/linters/appendoneelement/appendoneelement.go
  - pkg/linters/internal/astutil/astutil.go
  - pkg/linters/internal/astutil/astutil_test.go
  - pkg/linters/stringscountcontains/stringscountcontains.go
  - pkg/linters/stringsindexcontains/stringsindexcontains.go
  - pkg/linters/stringsjoinone/stringsjoinone.go
  - pkg/linters/timenowsub/timenowsub.go
comment_count: 1

Note

This comment is managed by comment memory.

It stores persistent context for this thread in the code block at the top of this comment.
Edit only the text inside the backtick fences; workflow metadata and the footer are regenerated automatically.

Learn more about comment memory

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt54 · 23.7 AIC · ⌖ 7.4 AIC · ⊞ 21.8K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

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.

Request changes

One of the changed linters still lacks an executable regression around the exact failure mode this PR is fixing.

Blocking theme

timenowsub only adds golden fixtures for comment overlap. That does not prove the analyzer stopped emitting a SuggestedFix when comments are inside the replacement span, so the bug can regress without the tests noticing. The direct no-fix path needs a targeted analyzer-level assertion, similar in spirit to the new BuildContainsFix unit coverage.

🔎 Code quality review by PR Code Quality Reviewer · copilot · gpt54 · 23.7 AIC · ⌖ 7.4 AIC · ⊞ 21.8K
Comment /review to run again

@@ -25,6 +25,10 @@ func badIndex(starts []time.Time, i int) time.Duration {
return time.Now().Sub(starts[i]) // want `time\.Now\(\)\.Sub\(starts\[i\]\) can be simplified to time\.Since\(starts\[i\]\)`

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.

This change fixes comment loss in four of the five linters, but timenowsub only got fixture updates and still has no executable regression test proving the analyzer suppresses autofixes when comments overlap. That leaves the core bug vulnerable to reintroduction because golden files alone do not assert whether a SuggestedFix was omitted versus simply happened to produce identical output.

💡 Add a real analyzer regression for the suppressed fix path

Please add a test that exercises timenowsub through the analyzer and verifies the diagnostic is still reported without a suggested fix when the replaced span contains a comment. Right now only BuildContainsFix has a unit test for the no-fix path; the other direct call-site guards rely on testdata that cannot distinguish "diagnostic with no fix" from "diagnostic with a fix that happened not to rewrite this file." A focused test here would lock in the behavior this PR is trying to preserve.

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor
🏗️ ADR required — draft added for PR #57860

I found that this PR requires ADR enforcement because the prefetch summary reports 107 added lines in default business-logic directories (pkg/), which is above the 100-line threshold.

Evidence used

  • PR title: Guard suggested fixes against comment loss in five linters
  • PR description: the change prevents five linters from emitting unsafe autofixes that can silently delete overlapping comments
  • Diff evidence:
    • adds a shared guard in pkg/linters/internal/astutil/astutil.go
    • updates five linters to suppress SuggestedFixes when comments overlap
    • adds tests and golden fixtures proving diagnostics remain while autofixes are withheld in comment-overlap cases

Gate result

No existing ADR was present in the PR body or docs/adr/ branch files with the required Michael Nygard sections for this decision, so I generated a draft ADR:

  • docs/adr/57860-guard-linter-autofixes-against-comment-loss.md

Inferred decision

The architectural decision in this PR is to prefer comment preservation over always emitting automatic whole-expression rewrites for these analyzers, and to enforce that policy through a shared overlap-check helper.

Next action

Please review and refine the draft ADR, especially the rationale and alternatives, and keep it with the PR as the implementation proceeds.

Warning

Firewall blocked 2 domains

The following domains were blocked by the firewall during workflow execution:

  • github.com
  • proxy.golang.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "github.com"
    - "proxy.golang.org"

See Network Configuration for more information.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · pi · gpt54 · 20.6 AIC · ⌖ 8.43 AIC · ⊞ 9.9K ·
Comment /review to run again

@github-actions github-actions Bot left a comment

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.

Reviewed PR #57860 (backend Go linter fix, not a UI change — Impeccable modes not applicable).

Findings: No blocking issues. The guard pattern (HasOverlappingComment check before attaching SuggestedFixes, while still reporting the diagnostic) is applied consistently across all five linters (appendoneelement, timenowsub, stringsjoinone, stringscountcontains, stringsindexcontains). BuildContainsFix correctly threads pass.Files for the two Contains-based linters. Test coverage is solid: new unit test in astutil_test.go verifies both HasOverlappingComment detection and that BuildContainsFix returns no fixes when a comment overlaps, plus badWithComments/golden fixtures added per linter package.

No inline comments needed.

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · copilot · sonnet50 · 17.7 AIC · ⌖ 13.2 AIC · ⊞ 8.3K

@github-actions github-actions Bot left a comment

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.

Skills-Based Review 🧠

Applied /diagnosing-bugs — the fix is correct, well-tested, and properly root-causes the comment-loss issue for the five targeted linters. No blocking issues found in the changed lines.

📋 Key Themes & Highlights

Positive Highlights

  • ✅ Root cause addressed at the source: HasOverlappingComment correctly checks comment-group overlap against the replaced span, and BuildContainsFix centralizes the guard for both strings.Count/strings.Index linters rather than duplicating the check per-caller.
  • ✅ Solid regression test coverage: a new unit test in astutil_test.go exercises HasOverlappingComment directly plus BuildContainsFix returning zero fixes when a comment overlaps, and each of the five linters gained a badWithComments golden-file fixture proving the diagnostic still fires but the fix is suppressed.
  • ✅ Minimal, surgical diff — diag := analysis.Diagnostic{...} + conditional SuggestedFixes assignment is a clean pattern that's easy to review and extend.

Follow-up worth tracking (non-blocking)

  • Root cause vs. full remediation (/diagnosing-bugs): this PR fixes 5 of the linters that attach SuggestedFixes, but a grep shows ~17 other linters (appendbytestring, bytesbufferstring, bytescomparestring, ctxbackground, execcommandwithoutcontext, fprintlnsprintf, lenstringsplit, lenstringzero, mapclearloop, mapdeletecheck, sprintfbool, sprintfint, stringreplaceminusone, stringsindexhasprefix, tolowerequalfold, writebytestring) still build whole-expression TextEdits without an overlapping-comment guard, so they remain susceptible to the same class of silent comment loss. Since HasOverlappingComment and the diag := ...; if !overlap { diag.SuggestedFixes = ... } pattern are now established, it would be low-effort to sweep the remaining linters in a fast-follow PR (or track via the linked issue #57844 if it covers the full set).

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • proxy.golang.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "proxy.golang.org"

See Network Configuration for more information.

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · copilot · sonnet50 · 29.6 AIC · ⌖ 14.6 AIC · ⊞ 10.3K
Comment /matt to run again

@pelikhan
pelikhan merged commit a61bb31 into main Sep 2, 2026
32 checks passed
@pelikhan
pelikhan deleted the copilot/sergo-fix-linters-silent-delete branch September 2, 2026 06:14
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

🎉 This pull request is included in a new release.

Release: v0.88.2

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.

sergo: 5 linters (appendoneelement, timenowsub, stringsjoinone, stringscountcontains, stringsindexcontains) silently delete comm

3 participants