[sergo] Sergo Report: New-Linter-Audit-at-Scale + Reverse-Phantom-Reconcile - 2026-10-03 #65228
Closed
Replies: 1 comment
|
This discussion has been marked as outdated by Sergo - Serena Go Expert. A newer discussion is available at Discussion #65500. |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Executive Summary
Run R85 of 85 total. Registry grew 75->76 with fprintferrorunchecked (PR #65073, 2026-10-02), audited same-day and found to miss its single most common real-world call shape at a scale (938 live occurrences across 193 files) far exceeding any prior instance of this bug class. Reconcile also caught 3 more issues auto-expiring overnight; 2 of the 3 were re-verified unfixed and refiled. 3 issues filed this run (full budget), 0 duplicates skipped (none of the 3 overlapped any currently-open issue). Success score: 9/10.
Tool Updates
-test=false) from day one.Strategy: 50/50 Cached-Reuse + New-Exploration
New-exploration (50%): first-ever full audit of fprintferrorunchecked, the newest registered analyzer. This is the proven highest-yield new-explore move (a fresh linter has had zero chance to inherit established fixes) and it paid off immediately.
Cached-reuse (50%): ran the standing gh-api reconcile step before any new analysis, re-querying live issue state rather than trusting the previous runs predicted post-reconcile list (a methodology fix adopted since R83). This surfaced 3 auto-expired issues from the paren_unwrap_gap vein; 2 were re-verified and refiled.
Findings
1. fprintferrorunchecked: AssignStmt-only filter misses 938 bare-statement call sites (new, #65225)
The linters entire nodeFilter is a single AssignStmt entry (fprintferrorunchecked.go:40), so it only recognizes
_ = fmt.Fprintf(...)/_, _ = fmt.Fprintf(...). A bare statement call with no assignment at all --fmt.Fprintf(w, text)-- is legal Go that silently discards both return values, exactly the failure mode the linter exists to catch, yet it never reaches the check logic since there is no AssignStmt node. Grep across pkg/ (excluding tests) found 938 such bare-statement call sites across 193 files -- vastly more common than the explicit-blank form this linter actually detects. Concrete examples: pkg/console/confirm.go:53-56 (writes to an io.Writer, e.g. os.Stdout) and pkg/workflow/workflow_errors.go:99. This is the established node_filter_too_narrow class (previously seen in globwalkignorederror/strconvparseignorederror), but at the largest scale yet observed for this class.2. 4 library-scope linters still miss the pass.Pkg.Name main guard (4th reverse-phantom, #65226)
osexitinlibrary, rawloginlib, logfatallibrary, and panic-in-library-code all classify library-vs-main code by path substring only, with zero check of the actual package main declaration -- unlike sibling osgetenvlibrary, which correctly adds that check. Lineage: #59627 -> #61518 -> #63342 (auto-expired 2026-10-02) -> this refile. Live (if currently out-of-scope) examples: internal/tools/actions-build/main.go and internal/tools/generate-action-metadata/main.go, both declared as the main package outside a /main or /cmd/ path.
3. nilctxpassed isBuiltinNil still lacks ParenExpr unwrap (3rd occurrence, #65227)
isBuiltinNil (nilctxpassed.go:124-135) bare-asserts the argument as a plain identifier with no unwrap first, so a parenthesized nil passed as a context.Context argument escapes detection. Lineage: #61519 -> #63343 (auto-expired 2026-10-02) -> this refile. CI-enforced both native+wasm.
Not refiled this run (budget): timenowsub.go:50/103 (paren_unwrap_gap, lineage #63344, 2nd occurrence) was independently re-verified still unfixed but the 3-issue cap was already committed to the findings above. Flagged as the top priority for R86.
Generated Tasks (1:1 with filed issues)
All three are small-to-trivial effort, code-verified with concrete repro locations, and independently non-overlapping.
Metrics
Historical Context
The paren_unwrap_gap class (a bare AST type assertion missing a ParenExpr unwrap) remains the single highest-yield recurring bug class across 85 runs, now confirmed independently in closeerrorunchecked (R82) and typeassertionnil (R84) -- two brand-new linters authored with no shared code, meaning this is a systemic blind spot in how new linters get written, not a single unfixed helper. The node_filter_too_narrow class (AssignStmt-only, no ExprStmt) has now claimed its highest-impact instance yet in fprintferrorunchecked. Both classes are strong candidates for a repo-wide lint-authoring guideline rather than one-off per-linter fixes.
Recommendations
Next-Run Focus (R86)
All reactions