Skip to content

[linter-miner] feat(linters): add timenowsub linter — flag time.Now().Sub(t) → time.Since(t)#46633

Merged
pelikhan merged 5 commits into
mainfrom
linter-miner/timenowsub-95d856cd71fa7907
Jul 19, 2026
Merged

[linter-miner] feat(linters): add timenowsub linter — flag time.Now().Sub(t) → time.Since(t)#46633
pelikhan merged 5 commits into
mainfrom
linter-miner/timenowsub-95d856cd71fa7907

Conversation

@github-actions

@github-actions github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

test body

Generated by PR Description Updater for #46633 · 40.8 AIC · ⌖ 7.01 AIC · ⊞ 4.8K ·

Flags time.Now().Sub(t) calls that can be simplified to time.Since(t).
The time.Since function is the idiomatic Go way to compute the elapsed
time since a fixed point and avoids the more verbose two-step pattern.

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 Jul 19, 2026
@pelikhan
pelikhan marked this pull request as ready for review July 19, 2026 18:15
Copilot AI review requested due to automatic review settings July 19, 2026 18:15
@github-actions

github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

PR Code Quality Reviewer completed the code quality review.

@github-actions

github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

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

@github-actions

github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

Test Quality Sentinel completed test quality analysis.

@github-actions

github-actions Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

Design Decision Gate 🏗️ completed the design decision gate check.

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.

Pull request overview

Adds the timenowsub Go analyzer to replace time.Now().Sub(t) with time.Since(t).

Changes:

  • Implements and registers the analyzer.
  • Provides automatic suggested fixes.
  • Adds analyzer tests and golden output.
Show a summary per file
File Description
pkg/linters/timenowsub/timenowsub.go Implements detection and fixes.
pkg/linters/timenowsub/timenowsub_test.go Runs analyzer fixture tests.
pkg/linters/timenowsub/testdata/src/timenowsub/timenowsub.go Defines test cases.
pkg/linters/timenowsub/testdata/src/timenowsub/timenowsub.go.golden Defines expected fixes.
cmd/linters/main.go Registers the analyzer.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comments suppressed due to low confidence (2)

pkg/linters/timenowsub/timenowsub.go:91

  • The fix hard-codes the qualifier time, but isTimeNow also recognizes aliased standard-library imports. For example, clock.Now().Sub(t) is diagnosed and rewritten to time.Since(t), which does not compile when the package is imported only as clock. Build the replacement from the qualifier in the inner selector (and add an aliased-import golden case).
					NewText: []byte(fmt.Sprintf("time.Since(%s)", argText)),

pkg/linters/timenowsub/timenowsub.go:117

  • types.Func.FullName uses the declaring package's name, not its import path, so a third-party package declared as package time with a Now function is also treated as the standard library and may receive an invalid time.Since rewrite. Match fn.Pkg().Path() == "time" and the function name instead, as the other standard-library linters do (for example internal/astutil/astutil.go:148-150).
	fn, ok := obj.(*types.Func)
	if !ok {
		return false
	}
	return fn.FullName() == "time.Now"
  • Files reviewed: 5/5 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment on lines +56 to +57
if len(outer.Args) != 1 {
return

@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 /tdd and /codebase-design — approving with no blocking issues.

📋 Key Themes & Highlights

Key Themes

  • Pattern consistency: Implementation follows the established linter structure (astutil, filecheck, nolint) — no deviations.
  • Type-safe detection: Uses fn.FullName() == "time.Now" rather than string matching on selector names, making it robust against shadowing.
  • Test coverage: Covers the expected positive/negative cases (bad, badAssign, good, goodOtherSub). The golden file correctly verifies the suggested fix rewrite.

Positive Highlights

  • ✅ Proper type checking via TypesInfo.ObjectOf — won't fire on user-defined Now() methods
  • SuggestedFix included — enables automatic rewriting via gopls / go fix
  • ✅ Correctly skips generated files and honours //nolint:timenowsub directives
  • ✅ Registered in cmd/linters/main.go in alphabetical order

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · 18.9 AIC · ⌖ 4.41 AIC · ⊞ 6.7K
Comment /matt to run again

@github-actions

Copy link
Copy Markdown
Contributor Author

🧪 Test Quality Sentinel Report

Test Quality Score: 100/100 — Excellent

Analyzed 1 test(s): 1 design, 0 implementation, 0 violation(s).

📊 Metrics (1 test)
Metric Value
Analyzed 1 (Go: 1, JS: 0)
✅ Design 1 (100%)
⚠️ Implementation 0 (0%)
Edge/error coverage 1 (100%)
Duplicate clusters 0
Inflation No (0.14:1)
🚨 Violations 0
Test File Classification Issues
TestAnalyzer pkg/linters/timenowsub/timenowsub_test.go:13 design_test / behavioral_contract None

Verdict

Passed. 0% implementation tests (threshold: 30%). The single test uses analysistest.RunWithSuggestedFixes against testdata that covers 2 bad patterns and 2 negative cases (already-correct code), verifying both diagnostic messages and suggested fixes — a solid behavioral contract test.

Warning

Firewall blocked 1 domain

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

  • awmgmcpg

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

network:
  allowed:
    - defaults
    - "awmgmcpg"

See Network Configuration for more information.

🧪 Test quality analysis by Test Quality Sentinel · 22.8 AIC · ⌖ 8.69 AIC · ⊞ 7K ·
Comment /review to run again

@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.

✅ Test Quality Sentinel: 100/100. 0% implementation tests (threshold: 30%).

@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.

Review: timenowsub linter

The implementation is clean and follows established patterns in this repo:

  • Correctness: isTimeNow uses type-aware checking (fn.FullName()) — no false positives from user-defined Now() methods.
  • SuggestedFix: Properly replaces the full time.Now().Sub(x) call expression with time.Since(x).
  • Test coverage: Covers bad, good, and non-time.Now() receiver cases; golden file uses RunWithSuggestedFixes.
  • Registration: Correctly inserted in alphabetical order in cmd/linters/main.go.
  • nolint / filecheck / generated-file skipping: Properly wired.

LGTM

🧵 Reviewed using Impeccable skills by Impeccable Skills Reviewer · 17 AIC · ⌖ 4.36 AIC · ⊞ 5K

@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.

LGTM — minor nit on golden file comments

The linter implementation is correct: type-verified detection via types.Func.FullName() == "time.Now", proper nolint/generated-file skipping, and a complete SuggestedFix with the right span (outer.Pos()outer.End()).

🔎 One nit (non-blocking)

pkg/linters/timenowsub/testdata/src/timenowsub/timenowsub.go.golden lines 6 and 10 carry stale // want annotations copied from the source input file:

\_ = time.Since(t) // want `time\.Now\(\)\.Sub\(t\) can be simplified ...`

analysistest.RunWithSuggestedFixes does a byte-for-byte comparison — it does not re-evaluate // want directives in golden files — so tests pass. But the comments are misleading: a future reader may assume these are live expectations on the fixed output. Drop them from the golden file.

🔎 Code quality review by PR Code Quality Reviewer · 26.5 AIC · ⌖ 4.41 AIC · ⊞ 5.6K
Comment /review to run again

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor Author

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (172 new lines in pkg/ directories) but does not have a linked Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/46633-add-timenowsub-linter.md — review and complete it before merging.

🔒 This PR cannot merge until an ADR is linked in the PR body.

📋 What to do next
  1. Review the draft ADR committed to your branch — it was generated from the PR diff
  2. Complete the missing sections — add context the AI could not infer, refine the decision rationale, and list real alternatives you considered
  3. Commit the finalized ADR to docs/adr/ on your branch
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-46633: Add timenowsub Linter

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

❓ Why ADRs Matter

"AI made me procrastinate on key design decisions. Because refactoring was cheap, I could always say 'I'll deal with this later.' Deferring decisions corroded my ability to think clearly."

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 46633-add-timenowsub-linter.md for PR #46633).

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · 49 AIC · ⌖ 10 AIC · ⊞ 8.5K ·
Comment /review to run again

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot merge main and recompile

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

@copilot merge main and recompile

Ran the merge/recompile flow. origin/main was already the merge base for this branch, so there was no new merge commit to create; make merge-main and the recompile completed cleanly. I also fixed the pre-push lint failure in 2b842a4.

@pelikhan

Copy link
Copy Markdown
Collaborator

@copilot run pr-finisher skill

Copilot AI and others added 2 commits July 19, 2026 20:04
…ub-95d856cd71fa7907

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>

Copilot AI commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

@copilot run pr-finisher skill

Ran the PR-finisher pass. Addressed the remaining timenowsub correctness issue in 9f2bd60 and updated the branch with main in 16b3262. Local checks passed: make fmt, make lint, make test-unit, make test, make recompile, and make agent-report-progress. Last-known CI on the previous head was green, but CI on the current agent-pushed head is stale and needs a maintainer to re-trigger before merge.

@gh-aw-bot

Copy link
Copy Markdown
Collaborator

@copilot please run the pr-finisher skill, confirm the branch is current, address any still-unresolved review feedback, and complete the ADR follow-up before rerunning checks.

Open review signals:

Please summarize the next concrete maintainer action after updates are pushed.

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

Warning

Firewall blocked 1 domain

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

  • pi.dev

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

network:
  allowed:
    - defaults
    - "pi.dev"

See Network Configuration for more information.

Generated by 👨‍🍳 PR Sous Chef · 9.67 AIC · ⌖ 8.38 AIC · ⊞ 7.5K ·
Comment /souschef to run again

@pelikhan
pelikhan merged commit b2a4b64 into main Jul 19, 2026
1 check failed
@pelikhan
pelikhan deleted the linter-miner/timenowsub-95d856cd71fa7907 branch July 19, 2026 20:26
Copilot stopped work on behalf of gh-aw-bot due to an error July 19, 2026 20:26
Copilot AI requested a review from gh-aw-bot July 19, 2026 20:26
@github-actions

Copy link
Copy Markdown
Contributor Author

🎉 This pull request is included in a new release.

Release: v0.82.14

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

Labels

automation cookie Issue Monster Loves Cookies! go-linters

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants