Skip to content

Perf/replace fixer queue preview#182

Closed
shrutu0929 wants to merge 1 commit into
Refactron-ai:mainfrom
shrutu0929:perf/replace-fixer-queue-preview
Closed

Perf/replace fixer queue preview#182
shrutu0929 wants to merge 1 commit into
Refactron-ai:mainfrom
shrutu0929:perf/replace-fixer-queue-preview

Conversation

@shrutu0929
Copy link
Copy Markdown

@shrutu0929 shrutu0929 commented Apr 20, 2026

solve #176
This update resolves a significant performance bottleneck in the automated refactoring pipeline caused by the expensive preview-based fixer resolution. We replaced the highly unoptimized workflow, which repetitively executed a simulated code change against dummy code via the AST for every single detected issue. To remediate this, we introduced an O(1) direct mapping mechanism utilizing the AutoFixEngine's registry can_fix check—enabling the orchestrator to assign rule-specific issues unambiguously straight to candidates. For unresolved subsets requiring arbitrary match evaluation, the robust preview-generation fallback remains. The entire operation is now heavily optimized through a new localized _fixer_cache within the RefactronPipeline, caching evaluations down to their granular categories or rule_ids, radically reducing overhead across the matrix of issue lists without triggering regression.

Summary by CodeRabbit

Release Notes

  • New Features
    • Added a new CLI run command for executing pipeline analysis on target directories
    • Supports optional target path specification and incremental analysis mode toggling
    • Displays progress feedback with summary metrics including total files and issues analyzed

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 20, 2026

Warning

Rate limit exceeded

@shrutu0929 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 52 minutes and 47 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 52 minutes and 47 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c38acdcd-e9a1-4b37-b75e-d105964882c7

📥 Commits

Reviewing files that changed from the base of the PR and between 45328d1 and a27612d.

📒 Files selected for processing (4)
  • refactron/cli/main.py
  • refactron/cli/run.py
  • refactron/core/pipeline.py
  • tests/test_pipeline.py
📝 Walkthrough

Walkthrough

A new run CLI command is introduced via conditional registration in main.py, paired with a new RefactronPipeline class in core/pipeline.py that orchestrates configuration loading, analysis execution, and issue-to-fixer queuing with internal caching. Comprehensive tests validate configuration loading, incremental analysis override behavior, and cache performance.

Changes

Cohort / File(s) Summary
CLI Infrastructure
refactron/cli/main.py, refactron/cli/run.py
Added conditional subcommand registration for run in main.py. New run.py module implements a Click command accepting an optional target path and --incremental flag, which instantiates RefactronPipeline, executes analysis, and reports metrics with error handling.
Core Pipeline Orchestration
refactron/core/pipeline.py
New RefactronPipeline class that loads configuration from explicit or .refactron.yaml paths, orchestrates Refactron analysis, and provides queue_issues method with fixer resolution and caching logic to avoid redundant fixer lookups.
Test Coverage
tests/test_pipeline.py
Comprehensive tests validating configuration loading defaults, incremental analysis flag override, and fixer caching behavior with mocked components.

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as CLI (run command)
    participant Pipeline as RefactronPipeline
    participant Refactron
    participant AutoFixEngine
    participant FileSystem

    User->>CLI: Invoke run with target & options
    CLI->>Pipeline: Create instance with project_root
    Pipeline->>FileSystem: Load .refactron.yaml (if exists)
    Pipeline->>Pipeline: Initialize Refactron with config
    Pipeline->>AutoFixEngine: Initialize engine
    
    CLI->>Pipeline: analyze(target, use_incremental)
    Pipeline->>Pipeline: Override incremental setting (if provided)
    Pipeline->>Refactron: analyze(target)
    Refactron->>Refactron: Scan & identify issues
    Refactron-->>Pipeline: Return AnalysisResult
    
    CLI->>Pipeline: queue_issues(issues)
    Pipeline->>Pipeline: For each issue, find fixer (with cache)
    Pipeline->>AutoFixEngine: can_fix(issue) or preview(issue)
    AutoFixEngine-->>Pipeline: Return fixer name
    Pipeline-->>CLI: Return queued issues with fixers
    
    CLI-->>User: Print summary metrics
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Feature/mvp phase3 hero commands #138: Implements similar conditional subcommand registration pattern in main.py for a different CLI command (verify), demonstrating parallel CLI extension approach.

Suggested labels

enhancement, testing, size: large

Poem

🐇 A pipeline built with fixer grace,
The run command sets the pace,
Caching wisdom, cache hit delight,
Configuration loaded just right,
Analysis flows through the night! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Perf/replace fixer queue preview' is directly related to the main change: replacing an expensive preview-based fixer resolution workflow with a direct O(1) mapping via AutoFixEngine's registry, as confirmed by the commit messages and PR objectives.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (1)
tests/test_pipeline.py (1)

43-48: Assert the effective incremental component, not just the config flag.

This test currently passes even if RefactronPipeline.analyze(..., use_incremental=True) only mutates config after Refactron has initialized its tracker. Add an assertion for the initialized tracker state so the test catches the runtime behavior.

Suggested assertion
             config_passed = pipeline.refactron.config
             assert config_passed.enable_incremental_analysis is True
+            assert pipeline.refactron.incremental_tracker.enabled is True
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_pipeline.py` around lines 43 - 48, The test must assert the
runtime tracker was initialized with incremental analysis, not just the config
flag: after calling RefactronPipeline.analyze(..., use_incremental=True) add an
assertion on the Refactron instance's tracker (pipeline.refactron.tracker) to
confirm it reflects incremental mode (e.g.,
pipeline.refactron.tracker.use_incremental or
pipeline.refactron.tracker.is_incremental is True); if tracker may be None
assert it is initialized first (is not None) then check the appropriate tracker
attribute, using the actual tracker attribute name from the Refactron
implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@refactron/cli/run.py`:
- Around line 28-33: RefactronPipeline is being instantiated without the target
project's path so config discovery defaults to the current working directory;
change the code that creates RefactronPipeline() to pass the effective project
root derived from target_path (from _validate_path) — e.g. construct
RefactronPipeline with the project root argument (or call its load/config
initializer) so that pipeline.analyze(target_path, use_incremental=incremental)
picks up /other/project/.refactron.yaml instead of the CWD.
- Around line 35-41: The first console.print uses an f-string with no
placeholders (console.print(f"[green]Pipeline analysis completed
successfully.[/green]"))—replace it with a normal string literal to satisfy
linting (console.print("[green]Pipeline analysis completed
successfully.[/green]")), and in the except block preserve exception chaining by
re-raising SystemExit with the caught exception (use raise SystemExit(1) from e)
so the original traceback (e) is kept; ensure lines remain under the
100-character limit.

In `@refactron/core/pipeline.py`:
- Around line 78-100: The current caching uses issue_type = issue.rule_id or
str(getattr(issue, 'category', ...)) which causes fallback preview matches to be
cached broadly; change the logic in the fixer resolution in resolve/fixer lookup
so that when issue.rule_id is missing you either (a) do not write the fallback
candidate_name into self._fixer_cache for that issue_type, or (b) make the cache
key more specific by including additional issue-specific fields (e.g., a unique
identifier, file/line, or a short snippet from issue.source/statement) before
assigning self._fixer_cache[issue_type] = candidate_name; ensure this applies
only when using the preview-based loop over self.autofix_engine.fixers and keep
the fast-path autofix_engine.can_fix(issue) caching unchanged.
- Line 35: The attribute _fixer_cache is untyped which yields Any; annotate it
as a mapping of fixer keys to optional strings (e.g. Dict[str, Optional[str]])
to satisfy mypy and the Optional[str] return expectations: change the assignment
in the class from self._fixer_cache = {} to self._fixer_cache: Dict[str,
Optional[str]] = {} and add the necessary typing imports (from typing import
Dict, Optional) at the module top if not present.
- Around line 62-64: The code updates only
self.refactron.config.enable_incremental_analysis when use_incremental is
provided but leaves the live tracker unchanged; update the actual
IncrementalAnalysisTracker on the Refactron instance as well. After setting
self.refactron.config.enable_incremental_analysis, either set the existing
tracker’s enabled state (e.g. self.refactron.incremental_tracker.enabled =
use_incremental or call its setter method) or recreate it:
self.refactron.incremental_tracker =
IncrementalAnalysisTracker(enabled=use_incremental) (import
IncrementalAnalysisTracker if needed) so the running tracker matches the new
config.
- Around line 3-19: Remove the duplicated imports of RefactronConfig, Refactron,
and AnalysisResult (keep a single import line for each unique symbol) and update
the RefactronPipeline.__init__ signature so it does not exceed the 100-character
line limit (wrap parameters across multiple lines or use type aliases for
Optional[Union[str, Path]]/config_path) to satisfy black/isort/flake8 formatting
rules.

In `@tests/test_pipeline.py`:
- Around line 105-106: The inline comment above the assertion in
tests/test_pipeline.py is longer than 100 characters; split or reflow that
comment into multiple shorter lines (each <=100 chars) so it complies with
flake8 max-line-length. Locate the long comment that precedes the assertion
using the assertion snippet calls["preview"] == 1 (or the surrounding test
function in test_pipeline.py) and break the sentence into two or more shorter
comment lines or rephrase it to keep each line under the 100-character limit.

---

Nitpick comments:
In `@tests/test_pipeline.py`:
- Around line 43-48: The test must assert the runtime tracker was initialized
with incremental analysis, not just the config flag: after calling
RefactronPipeline.analyze(..., use_incremental=True) add an assertion on the
Refactron instance's tracker (pipeline.refactron.tracker) to confirm it reflects
incremental mode (e.g., pipeline.refactron.tracker.use_incremental or
pipeline.refactron.tracker.is_incremental is True); if tracker may be None
assert it is initialized first (is not None) then check the appropriate tracker
attribute, using the actual tracker attribute name from the Refactron
implementation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d4293809-ef4b-4f07-9670-28211c91e3d0

📥 Commits

Reviewing files that changed from the base of the PR and between a9659f5 and 45328d1.

📒 Files selected for processing (4)
  • refactron/cli/main.py
  • refactron/cli/run.py
  • refactron/core/pipeline.py
  • tests/test_pipeline.py

Comment thread refactron/cli/run.py
Comment on lines +28 to +33
target_path = _validate_path(target) if target else Path.cwd()

with console.status("[primary]Executing pipeline run...[/primary]"):
try:
pipeline = RefactronPipeline()
result = pipeline.analyze(target_path, use_incremental=incremental)
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.

⚠️ Potential issue | 🟠 Major

Load pipeline config from the requested target project.

RefactronPipeline() defaults config discovery to the current working directory, so refactron run /other/project can ignore /other/project/.refactron.yaml. Pass the effective project root derived from target_path.

Proposed fix
     target_path = _validate_path(target) if target else Path.cwd()
+    project_root = target_path if target_path.is_dir() else target_path.parent
 
     with console.status("[primary]Executing pipeline run...[/primary]"):
         try:
-            pipeline = RefactronPipeline()
+            pipeline = RefactronPipeline(project_root=project_root)
             result = pipeline.analyze(target_path, use_incremental=incremental)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
target_path = _validate_path(target) if target else Path.cwd()
with console.status("[primary]Executing pipeline run...[/primary]"):
try:
pipeline = RefactronPipeline()
result = pipeline.analyze(target_path, use_incremental=incremental)
target_path = _validate_path(target) if target else Path.cwd()
project_root = target_path if target_path.is_dir() else target_path.parent
with console.status("[primary]Executing pipeline run...[/primary]"):
try:
pipeline = RefactronPipeline(project_root=project_root)
result = pipeline.analyze(target_path, use_incremental=incremental)
🧰 Tools
🪛 GitHub Actions: Pre-commit

[error] pre-commit hook "black" failed (files were reformatted by the hook)


[error] pre-commit hook "isort" failed (files were modified/fixed by the hook)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@refactron/cli/run.py` around lines 28 - 33, RefactronPipeline is being
instantiated without the target project's path so config discovery defaults to
the current working directory; change the code that creates RefactronPipeline()
to pass the effective project root derived from target_path (from
_validate_path) — e.g. construct RefactronPipeline with the project root
argument (or call its load/config initializer) so that
pipeline.analyze(target_path, use_incremental=incremental) picks up
/other/project/.refactron.yaml instead of the CWD.

Comment thread refactron/cli/run.py
Comment on lines +35 to +41
console.print(f"[green]Pipeline analysis completed successfully.[/green]")
console.print(f"Total files analyzed: {result.total_files}")
console.print(f"Total issues found: {result.total_issues}")

except Exception as e:
console.print(f"[red]Pipeline run failed: {e}[/red]")
raise SystemExit(1)
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.

⚠️ Potential issue | 🟡 Minor

Fix the lint failure and preserve exception chaining.

Line 35 is an f-string without placeholders, and the SystemExit raised from the except block should be chained or explicitly suppressed.

Proposed fix
-            console.print(f"[green]Pipeline analysis completed successfully.[/green]")
+            console.print("[green]Pipeline analysis completed successfully.[/green]")
             console.print(f"Total files analyzed: {result.total_files}")
             console.print(f"Total issues found: {result.total_issues}")
             
-        except Exception as e:
-            console.print(f"[red]Pipeline run failed: {e}[/red]")
-            raise SystemExit(1)
+        except Exception as exc:
+            console.print(f"[red]Pipeline run failed: {exc}[/red]")
+            raise SystemExit(1) from exc

As per coding guidelines, **/*.py: “Use line length of 100 characters, enforced by black, isort, and flake8”.

🧰 Tools
🪛 GitHub Actions: Pre-commit

[error] 38-38: flake8 reported F541 f-string is missing placeholders


[error] pre-commit hook "black" failed (files were reformatted by the hook)


[error] pre-commit hook "isort" failed (files were modified/fixed by the hook)

🪛 Ruff (0.15.10)

[error] 35-35: f-string without any placeholders

Remove extraneous f prefix

(F541)


[warning] 39-39: Do not catch blind exception: Exception

(BLE001)


[warning] 41-41: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@refactron/cli/run.py` around lines 35 - 41, The first console.print uses an
f-string with no placeholders (console.print(f"[green]Pipeline analysis
completed successfully.[/green]"))—replace it with a normal string literal to
satisfy linting (console.print("[green]Pipeline analysis completed
successfully.[/green]")), and in the except block preserve exception chaining by
re-raising SystemExit with the caught exception (use raise SystemExit(1) from e)
so the original traceback (e) is kept; ensure lines remain under the
100-character limit.

Comment on lines +3 to +19
from pathlib import Path
from typing import Optional, Union, List

from refactron.core.config import RefactronConfig
from refactron.core.refactron import Refactron
from refactron.core.analysis_result import AnalysisResult
from refactron.core.models import CodeIssue
from refactron.autofix.engine import AutoFixEngine

from refactron.core.config import RefactronConfig
from refactron.core.refactron import Refactron
from refactron.core.analysis_result import AnalysisResult

class RefactronPipeline:
"""Automated pipeline execution for session-based and CI/CD flows."""

def __init__(self, project_root: Optional[Union[str, Path]] = None, config_path: Optional[Union[str, Path]] = None):
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.

⚠️ Potential issue | 🟡 Minor

Fix the duplicate imports and formatter failures.

RefactronConfig, Refactron, and AnalysisResult are imported twice, and Line 19 exceeds the 100-character formatter/lint limit. This is already causing black/isort pre-commit failures.

Proposed cleanup
 from pathlib import Path
-from typing import Optional, Union, List
+from typing import Dict, List, Optional, Union
 
+from refactron.autofix.engine import AutoFixEngine
+from refactron.core.analysis_result import AnalysisResult
 from refactron.core.config import RefactronConfig
-from refactron.core.refactron import Refactron
-from refactron.core.analysis_result import AnalysisResult
 from refactron.core.models import CodeIssue
-from refactron.autofix.engine import AutoFixEngine
-
-from refactron.core.config import RefactronConfig
 from refactron.core.refactron import Refactron
-from refactron.core.analysis_result import AnalysisResult
+
 
 class RefactronPipeline:
     """Automated pipeline execution for session-based and CI/CD flows."""
 
-    def __init__(self, project_root: Optional[Union[str, Path]] = None, config_path: Optional[Union[str, Path]] = None):
+    def __init__(
+        self,
+        project_root: Optional[Union[str, Path]] = None,
+        config_path: Optional[Union[str, Path]] = None,
+    ):

As per coding guidelines, **/*.py: “Use line length of 100 characters, enforced by black, isort, and flake8”.

🧰 Tools
🪛 GitHub Actions: Pre-commit

[error] pre-commit hook "black" failed (files were reformatted by the hook)


[error] pre-commit hook "isort" failed (files were modified/fixed by the hook)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@refactron/core/pipeline.py` around lines 3 - 19, Remove the duplicated
imports of RefactronConfig, Refactron, and AnalysisResult (keep a single import
line for each unique symbol) and update the RefactronPipeline.__init__ signature
so it does not exceed the 100-character line limit (wrap parameters across
multiple lines or use type aliases for Optional[Union[str, Path]]/config_path)
to satisfy black/isort/flake8 formatting rules.

self._config.enable_incremental_analysis = False
self.refactron = Refactron(self._config)
self.autofix_engine = AutoFixEngine()
self._fixer_cache = {}
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.

⚠️ Potential issue | 🟠 Major

Annotate _fixer_cache to unblock mypy.

The untyped empty dict makes reads return Any, which is why mypy reports both the missing annotation and the Optional[str] return mismatch.

Proposed fix
-        self._fixer_cache = {}
+        self._fixer_cache: Dict[str, Optional[str]] = {}

As per coding guidelines, refactron/**/*.py: “Type annotations are required in refactron/ with mypy disallow_untyped_defs = true enabled”.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
self._fixer_cache = {}
self._fixer_cache: Dict[str, Optional[str]] = {}
🧰 Tools
🪛 GitHub Actions: Pre-commit

[error] pre-commit hook "black" failed (files were reformatted by the hook)


[error] pre-commit hook "isort" failed (files were modified/fixed by the hook)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@refactron/core/pipeline.py` at line 35, The attribute _fixer_cache is untyped
which yields Any; annotate it as a mapping of fixer keys to optional strings
(e.g. Dict[str, Optional[str]]) to satisfy mypy and the Optional[str] return
expectations: change the assignment in the class from self._fixer_cache = {} to
self._fixer_cache: Dict[str, Optional[str]] = {} and add the necessary typing
imports (from typing import Dict, Optional) at the module top if not present.

Comment on lines +62 to +64
if use_incremental is not None:
self.refactron.config.enable_incremental_analysis = use_incremental

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.

⚠️ Potential issue | 🟠 Major

Apply incremental overrides to the initialized tracker, not only the config.

Refactron constructs IncrementalAnalysisTracker(enabled=self.config.enable_incremental_analysis) during initialization, so changing only self.refactron.config.enable_incremental_analysis here can leave the actual tracker running with the old mode. Rebuild Refactron or update the tracker state when use_incremental changes.

Possible fix
         if use_incremental is not None:
-            self.refactron.config.enable_incremental_analysis = use_incremental
+            self._config.enable_incremental_analysis = use_incremental
+            self.refactron.config.enable_incremental_analysis = use_incremental
+            self.refactron.incremental_tracker.enabled = use_incremental
🧰 Tools
🪛 GitHub Actions: Pre-commit

[error] pre-commit hook "black" failed (files were reformatted by the hook)


[error] pre-commit hook "isort" failed (files were modified/fixed by the hook)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@refactron/core/pipeline.py` around lines 62 - 64, The code updates only
self.refactron.config.enable_incremental_analysis when use_incremental is
provided but leaves the live tracker unchanged; update the actual
IncrementalAnalysisTracker on the Refactron instance as well. After setting
self.refactron.config.enable_incremental_analysis, either set the existing
tracker’s enabled state (e.g. self.refactron.incremental_tracker.enabled =
use_incremental or call its setter method) or recreate it:
self.refactron.incremental_tracker =
IncrementalAnalysisTracker(enabled=use_incremental) (import
IncrementalAnalysisTracker if needed) so the running tracker matches the new
config.

Comment on lines +78 to +100
# Use rule_id or category as cache key
issue_type = issue.rule_id or str(getattr(issue, 'category', type(issue).__name__))
if issue_type in self._fixer_cache:
return self._fixer_cache[issue_type]

candidate_name = None

# 1. Ask AutoFixEngine directly without preview (O(1) dictionary lookup)
if hasattr(self, 'autofix_engine') and self.autofix_engine.can_fix(issue):
candidate_name = issue.rule_id
else:
# 2. Fallback to preview-based resolution for ambiguous cases
if hasattr(self, 'autofix_engine'):
for name, fixer in self.autofix_engine.fixers.items():
try:
preview_result = fixer.preview(issue, "x = 1\n")
if preview_result and getattr(preview_result, "success", False):
candidate_name = name
break
except Exception:
continue

self._fixer_cache[issue_type] = candidate_name
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.

⚠️ Potential issue | 🟠 Major

Avoid caching fallback matches by broad category only.

When rule_id is missing, the cache key collapses to the issue category, so one successful preview for a STYLE issue can assign the same fixer to unrelated STYLE issues without re-evaluating them. Either skip caching for rule-less issues or include more issue-specific fields in the fallback key.

Safer cache key option
-        issue_type = issue.rule_id or str(getattr(issue, 'category', type(issue).__name__))
+        if issue.rule_id:
+            issue_type = issue.rule_id
+        else:
+            issue_type = ":".join(
+                [
+                    str(getattr(issue, "category", type(issue).__name__)),
+                    str(getattr(issue, "message", "")),
+                ]
+            )
🧰 Tools
🪛 GitHub Actions: Pre-commit

[error] 84-84: mypy error: Returning Any from function declared to return "Optional[str]" [no-any-return]


[error] pre-commit hook "black" failed (files were reformatted by the hook)


[error] pre-commit hook "isort" failed (files were modified/fixed by the hook)

🪛 Ruff (0.15.10)

[error] 97-98: try-except-continue detected, consider logging the exception

(S112)


[warning] 97-97: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@refactron/core/pipeline.py` around lines 78 - 100, The current caching uses
issue_type = issue.rule_id or str(getattr(issue, 'category', ...)) which causes
fallback preview matches to be cached broadly; change the logic in the fixer
resolution in resolve/fixer lookup so that when issue.rule_id is missing you
either (a) do not write the fallback candidate_name into self._fixer_cache for
that issue_type, or (b) make the cache key more specific by including additional
issue-specific fields (e.g., a unique identifier, file/line, or a short snippet
from issue.source/statement) before assigning self._fixer_cache[issue_type] =
candidate_name; ensure this applies only when using the preview-based loop over
self.autofix_engine.fixers and keep the fast-path autofix_engine.can_fix(issue)
caching unchanged.

Comment thread tests/test_pipeline.py
Comment on lines +105 to +106
# Should only have run preview 1 time, because the subsequent issues have the same rule_id and hit the cache.
assert calls["preview"] == 1
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.

⚠️ Potential issue | 🟡 Minor

Wrap the long comment to satisfy flake8.

Line 105 exceeds the configured 100-character limit and is already failing pre-commit.

Proposed fix
-        # Should only have run preview 1 time, because the subsequent issues have the same rule_id and hit the cache.
+        # Should only have run preview 1 time because subsequent issues have the
+        # same rule_id and hit the cache.

As per coding guidelines, **/*.py: “Flake8 linting must use max-line-length of 100”.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Should only have run preview 1 time, because the subsequent issues have the same rule_id and hit the cache.
assert calls["preview"] == 1
# Should only have run preview 1 time because subsequent issues have the
# same rule_id and hit the cache.
assert calls["preview"] == 1
🧰 Tools
🪛 GitHub Actions: Pre-commit

[error] pre-commit hook "black" failed (files were reformatted by the hook)


[error] pre-commit hook "isort" failed (files were modified/fixed by the hook)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_pipeline.py` around lines 105 - 106, The inline comment above the
assertion in tests/test_pipeline.py is longer than 100 characters; split or
reflow that comment into multiple shorter lines (each <=100 chars) so it
complies with flake8 max-line-length. Locate the long comment that precedes the
assertion using the assertion snippet calls["preview"] == 1 (or the surrounding
test function in test_pipeline.py) and break the sentence into two or more
shorter comment lines or rephrase it to keep each line under the 100-character
limit.

@shrutu0929 shrutu0929 force-pushed the perf/replace-fixer-queue-preview branch from 45328d1 to 1acc555 Compare April 20, 2026 13:45
@shrutu0929 shrutu0929 force-pushed the perf/replace-fixer-queue-preview branch from 1acc555 to a27612d Compare April 20, 2026 13:46
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 5, 2026

This pull request has been automatically marked as stale because it has not had recent activity for 14 days.

If you believe this PR is still relevant, please:

  • Add a comment explaining why
  • Remove the stale label
  • Or simply comment to keep it active

This helps us keep the repository focused on active contributions. Thank you! 🙏

@github-actions github-actions Bot added the stale label May 5, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 8, 2026

This pull request has been automatically closed because it was marked as stale and had no recent activity for 3 days.

If you believe this PR should be reopened, please:

  • Add a comment explaining why
  • Remove the closed-by-stale-bot label
  • Or create a new PR with updated information

Thank you for your understanding! 🙏

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant