[repository-quality] 🎯 Repository Quality Improvement Report - Unjustified nolint Suppression Debt (2026-09-18) #61808
Closed
Replies: 1 comment
|
This discussion was automatically closed because it expired on 2026-09-19T13:02:50.097Z.
|
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.
🎯 Repository Quality Improvement Report - Unjustified
(nolint/redacted)Suppression DebtAnalysis Date: 2026-09-18
Focus Area: Unjustified
(nolint/redacted)Suppression Debt (Custom)Strategy Type: Custom
Custom Area: Yes — the repo's 68 custom
go/analysislinters are only as trustworthy as the suppressions used to bypass them. Prior runs (2026-09-07, 2026-09-11) audited whether linters were wired into CI; this run audits whether the suppressions escaping those linters are actually justified, which is the next layer of the same trust chain and had not yet been examined.Executive Summary
gh-aw's custom linter suite (
pkg/linters/*, run viamake golint-custom) is a meaningful investment in enforcing repo-specific conventions — but its value depends on(nolint/redacted):<linter>suppressions being reviewable, one-off exceptions rather than silent blanket opt-outs. Across all non-test, non-testdata Go source underpkg/andcmd/, there are 260(nolint/redacted):<linter>directives, and 96 of them (37%) carry no trailing justification comment at all — just the bare directive with no explanation of why the rule doesn't apply at that call site.The problem is heavily concentrated rather than evenly spread:
osgetenvlibrary(41 suppressions, 0% justified) andtolowerequalfold(18 suppressions, 0% justified) account for 61% of all unjustified suppressions between them, withlargefunc(27 unjustified out of 111 total) close behind. By contrast,generatedyamlheredoc(18/18),regexpdynamicpattern(15/15), andmanualpathconcat(7/7) are 100% justified today, proving the repo can sustain full justification discipline when a linter's guidance/skill explicitly calls for it — the gap is inconsistent enforcement, not infeasibility.This matters operationally: an unjustified
(nolint/redacted):osgetenvlibraryonpkg/cli/engine_secrets.go:302(envValue := os.Getenv(req.Name)) reads identically to a justified one, so a reviewer can't tell at a glance whether the env-var-fetch bypasses the intended "route secrets throughpkg/envutil" convention deliberately or by habit-copy. The fix is two-part: (1) backfill justification comments on the 96 existing bare suppressions, prioritizing the two 0%-justified linters, and (2) add a repo-ownednolintjustificationmeta-linter (reusing the existingpkg/linters/internal/nolintdirective index) so future bare suppressions fail CI instead of accumulating silently.Full Analysis Report
Focus Area: Unjustified
(nolint/redacted)Suppression DebtCurrent State Assessment
The repository already indexes every
(nolint/redacted):<name>directive per-file/per-line via the sharedpkg/linters/internal/nolintpackage (BuildDirectiveIndex), which every custom analyzer consults to skip flagged lines. That index currently has no concept of "was this suppression justified" — it only knows a directive exists. Some linters (e.g.generatedyamlheredoc,regexpdynamicpattern,manualpathconcat) are consistently suppressed with a trailing// <reason>comment by convention; others (osgetenvlibrary,tolowerequalfold,largefunc) are not.Metrics Collected:
(nolint/redacted):<linter>directives (non-test, non-testdata)osgetenvlibrarysuppressions justifiedtolowerequalfoldsuppressions justifiedlargefuncsuppressions justifiedhardcodedfilepathsuppressions justifiedgeneratedyamlheredoc/regexpdynamicpattern/manualpathconcatjustifiedosgetenvlibrarysuppressionsshell_completion.go×6,engine_secrets.go×5)tolowerequalfoldsuppressionsoutcome_eval_review.go×6)Findings
Strengths
pkg/linters/internal/nolint.DirectiveIndexalready parses and centralizes every suppression site — no new parsing infrastructure is needed to enforce justification, only a new consumer of the existing index.generatedyamlheredoc,regexpdynamicpattern,manualpathconcat) demonstrate 100% justification compliance today, showing the convention is achievable and likely already documented informally for those linters.jsonmarshalignoredeerroris at 89% justified (17/19), showing most linter categories are close to full compliance and only need a final cleanup pass.Areas for Improvement
osgetenvlibrary(41 sites, 0% justified) — this linter exists specifically to steeros.Getenv/os.LookupEnvcalls in library code toward a shared abstraction (pkg/envutil), but every current suppression is silent, so it's impossible to tell which are deliberate exceptions (e.g. CLI-adjacent helper functions) versus copy-pasted bypasses.tolowerequalfold(18 sites, 0% justified) — flagsstrings.ToLower(x) == ypatterns that should usestrings.EqualFold; zero justification means reviewers can't confirm whether case-sensitivity semantics were actually considered at each site.largefunc(27 of 111 unjustified) — spread acrosspkg/cli/update_workflows.go,update_command.go,pr_command.go,mcp_tools_readonly.go, and others; unlike the fully-justified suppressions infrontmatter_extraction_security.go(which explain why a function stays large), these 27 give no such rationale.hardcodedfilepath(4 sites, 0% justified) and 1 unjustifiederrcheck/ctxbackground/gosecsuppression each — small in count but worth a final sweep once the two large categories are fixed.Detailed Analysis
Root cause:
(nolint/redacted):<linter>[,<linter>...] // reasonis a convention, not an enforced rule. TheBuildDirectiveIndexparser inpkg/linters/internal/nolint/nolint.goalready splits the directive payload before any trailing//comment (seestrings.Index(payload, "//")), so the raw comment text is available at parse time — a justification-length check is a small addition to that existing pass, not a new subsystem.Representative unjustified sites (verified via
grep -rn "nolint:osgetenvlibrary" pkg/ cmd/):pkg/cli/engine_secrets.go:302—envValue := os.Getenv(req.Name) (nolint/redacted):osgetenvlibrarypkg/cli/ci.go:22—if os.Getenv(v) != "" { (nolint/redacted):osgetenvlibrarypkg/cli/compile_orchestrator.go:38—if os.Getenv("GH_HOST") == "" { (nolint/redacted):osgetenvlibrarypkg/workflow/domains.go:167,pkg/workflow/engine_definition.go:492,pkg/workflow/role_checks.go:577— bare(nolint/redacted):tolowerequalfoldContrast with justified pattern already in the codebase (
pkg/workflow/frontmatter_extraction_security.go:77):This is the target style: a short, specific reason after the directive, not just a bare tag.
🤖 Tasks for Copilot Agent
NOTE TO PLANNER AGENT: Split the following tasks into individual work items.
Improvement Tasks
Task 1: Backfill justification comments on all
osgetenvlibrarysuppressionsPriority: High
Estimated Effort: Small
Focus Area: Unjustified
(nolint/redacted)Suppression DebtDescription: Add a trailing
// <reason>comment to each of the 41 bare(nolint/redacted):osgetenvlibrarydirectives acrosspkg/cli/shell_completion.go,pkg/cli/engine_secrets.go,pkg/logger/logger.go,pkg/envutil/envutil.go,pkg/console/accessibility.go,pkg/parser/github.go,pkg/cli/mcp_validation.go,pkg/workflow/process_env_lookup.go,pkg/linters/internal/coverage/coverage.go, andpkg/github/label_objective_mapping.go. Each reason should explain why the directos.Getenv/os.LookupEnvcall is appropriate at that site instead of routing throughpkg/envutil(e.g., "CLI entrypoint reads its own flag-override env var directly" or "envutil package itself must call os.Getenv").Acceptance Criteria:
(nolint/redacted):osgetenvlibrarydirectives in non-test, non-testdata files have a trailing justification commentgrep -rn "nolint:osgetenvlibrary" --include="*.go" pkg/ cmd/ | grep -v _test.go | grep -v testdata | grep -vE '//$'shows zero bare directivesmake golint-customstill passesCode Region:
pkg/cli/shell_completion.go,pkg/cli/engine_secrets.go,pkg/logger/logger.go,pkg/envutil/envutil.go,pkg/console/accessibility.goTask 2: Backfill justification comments on all
tolowerequalfoldsuppressionsPriority: High
Estimated Effort: Small
Focus Area: Unjustified
(nolint/redacted)Suppression DebtDescription: Add a trailing
// <reason>comment to each of the 18 bare(nolint/redacted):tolowerequalfolddirectives, concentrated inpkg/cli/outcome_eval_review.go(6),pkg/cli/model_costs.go(3),pkg/cli/add_interactive_schedule.go(2), and single occurrences inpkg/workflow/role_checks.go,pkg/workflow/observability_otlp.go,pkg/workflow/engine_definition.go,pkg/workflow/domains.go,pkg/cli/codemod_steps_run_secrets_env.go,pkg/cli/audit_diff.go, andpkg/cli/add_package_manifest_parse.go. Explain why thestrings.ToLower(x) == ypattern at each site is correct as-is rather than usingstrings.EqualFold(e.g., "comparing against an empty string, EqualFold offers no benefit" or "y is already normalized to lowercase upstream").Acceptance Criteria:
(nolint/redacted):tolowerequalfolddirectives in non-test, non-testdata files have a trailing justification commentgrep -rn "nolint:tolowerequalfold" --include="*.go" pkg/ cmd/ | grep -v _test.go | grep -v testdata | grep -vE '//$'shows zero bare directivesmake golint-customstill passesCode Region:
pkg/cli/outcome_eval_review.go,pkg/cli/model_costs.go,pkg/workflow/role_checks.go,pkg/workflow/domains.goTask 3: Add a
nolintjustificationmeta-linter to enforce justification comments going forwardPriority: Medium
Estimated Effort: Medium
Focus Area: Unjustified
(nolint/redacted)Suppression DebtDescription: Create a new custom
go/analysislinter packagepkg/linters/nolintjustificationthat reuses the existingpkg/linters/internal/nolintdirective-index infrastructure to flag any(nolint/redacted):<linter>directive that lacks a trailing// <reason>comment of at least a minimum length (e.g., 8 characters after the//). Register it incmd/linters/main.goalongside the other analyzers. This prevents the 37% unjustified rate found in this audit from silently growing again after Tasks 1 and 2 clean up the existing backlog. Exempt the linter's own testdata fixtures and any files undertestdata/from enforcement, matching the pattern used by other linters in this repo (seepkg/linters/internal/filecheckfor generated-file exclusion helpers).Acceptance Criteria:
pkg/linters/nolintjustification/nolintjustification.goanalyzer reports a diagnostic on any(nolint/redacted):<name>directive without a trailing justification commentcmd/linters/main.gopkg/linters/nolintjustification/testdata/src/...usinganalysistest, covering both a justified and unjustified suppression casego test ./pkg/linters/nolintjustification/...passesmake golint-customagainst the current repo (after Tasks 1 & 2 land) produces zero new findings, confirming the backlog was actually cleared before the gate went liveCode Region:
pkg/linters/nolintjustification/(new package),cmd/linters/main.goTask 4: Sweep remaining low-count unjustified suppressions (
hardcodedfilepath,jsonmarshalignoredeerror,errcheck,ctxbackground,gosec)Priority: Low
Estimated Effort: Small
Focus Area: Unjustified
(nolint/redacted)Suppression DebtDescription: Finish the justification backfill by adding trailing reason comments to the remaining scattered unjustified suppressions: 4
hardcodedfilepathsites (pkg/linters/hardcodedfilepath/hardcodedfilepath.go×3 in its own pattern table,pkg/cli/git.go:475), 2jsonmarshalignoredeerrorsites, and 1 each oferrcheck,ctxbackground, andgosec. This closes out the full 96-directive backlog identified in this audit so Task 3's new gate starts from a clean baseline.Acceptance Criteria:
hardcodedfilepath,jsonmarshalignoredeerror,errcheck,ctxbackground,gosec) have trailing justification commentsmake golint-custompasses(nolint/redacted):directives)Code Region:
pkg/cli/git.go,pkg/linters/hardcodedfilepath/hardcodedfilepath.go📊 Historical Context
Previous Focus Areas
(nolint/redacted)Suppression Debt🎯 Recommendations
Immediate Actions (This Week)
osgetenvlibrarysuppressions (Task 1) — Priority: Hightolowerequalfoldsuppressions (Task 2) — Priority: HighShort-term Actions (This Month)
nolintjustificationmeta-linter to prevent regression (Task 3) — Priority: MediumLong-term Actions (This Quarter)
📈 Success Metrics
nolintjustificationlinterNext Steps
Generated by Repository Quality Improvement Agent
Next analysis: 2026-09-19 — Focus area selected by diversity algorithm
All reactions