Skip to content

feat: add support for disabling rules within a package#41

Merged
oshorefueled merged 4 commits intomainfrom
feat/rule-disabling
Dec 27, 2025
Merged

feat: add support for disabling rules within a package#41
oshorefueled merged 4 commits intomainfrom
feat/rule-disabling

Conversation

@hurshore
Copy link
Collaborator

@hurshore hurshore commented Dec 18, 2025

Summary

Adds support for selectively disabling individual rules within a package via configuration.

Also removes support for property-level overrides (e.g., Pack.Rule.severity=warning) - rule properties should be defined in the rule file itself, not overridden via config.

Usage

[**/*.md]
RunRules=Acme
Acme.GrammarCheck=disabled
Acme.StyleGuide=disabled


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **New Features**
  * Per-scan-path overrides and dynamic rule disabling to control which checks run per path.

* **Bug Fixes**
  * Disabled rules are correctly excluded when scanning specific paths.
  * Prompts that fail due to missing dependencies are skipped with warnings instead of failing the run.

* **Improvements**
  * Preserves input ordering; concurrency handling more robust.
  * Reporting and messaging normalized for consistent empty-field defaults and clearer error/warning text.

<sub>✏️ Tip: You can customize this high-level summary in your review settings.</sub>
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

@coderabbitai
Copy link

coderabbitai bot commented Dec 18, 2025

📝 Walkthrough

Walkthrough

Orchestrator now resolves overrides and available packs, filters prompts by configured scanPaths/packs and resolved overrides, preserves input order in concurrent runs, skips prompts failing with MissingDependencyError, tightens error messaging, and normalizes formatting/initializers.

Changes

Cohort / File(s) Summary
CLI orchestrator updates
src/cli/orchestrator.ts
Adds resolution-based override pre-processing; computes available packs and filters prompts by resolution.packs / scanPaths; excludes prompts disabled via resolution.overrides; preserves input order in runWithConcurrency; skips MissingDependencyError with a warning; tightens error messages and normalizes defaults/formatting.
Type/style adjustments
src/cli/types.ts
Formatting and string-quoting normalization (single → double quotes) and minor spacing changes; no public API signature changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant CLI
  participant Orchestrator
  participant Resolver as "Resolution Resolver"
  participant Filter as "Prompt Filter"
  participant Runner as "Concurrency Runner"
  participant Worker
  participant Evaluator
  participant Reporter

  CLI->>Orchestrator: start scan (scanPaths, resolution)
  Orchestrator->>Resolver: resolve config & packs
  Resolver-->>Orchestrator: resolved.packs, resolved.overrides
  Orchestrator->>Filter: filter prompts by packs & overrides
  Filter-->>Orchestrator: filtered prompt list (ordered)
  Orchestrator->>Runner: dispatch ordered work items
  loop per item (ordered)
    Runner->>Worker: execute item
    Worker->>Evaluator: evaluate prompt
    alt missing dependency
      Evaluator-->>Worker: MissingDependencyError
      Worker-->>Runner: warn and mark skipped
    else success/failure
      Evaluator-->>Worker: result
      Worker-->>Runner: return result (preserve position)
    end
  end
  Runner->>Reporter: emit ordered results (normalized fields)
  Reporter-->>CLI: final report
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped through code with careful paws,

Sorted packs and taped the flaws,
Skipped the gaps that made me sigh,
Kept the order, watched results fly,
Nibbled bugs, then munched a carrot 🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main feature addition: support for disabling rules within a package, which aligns with the PR objectives and commit messages.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/rule-disabling

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

Copy link

@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: 2

🧹 Nitpick comments (1)
src/cli/orchestrator.ts (1)

795-803: Optional: Consider combining filter operations.

The current implementation filters prompts twice in succession. While functionally correct and arguably more readable, this could be optimized into a single filter pass.

🔎 View suggested refactor:
-// Filter prompts by active packs
-let activePrompts = prompts.filter(
-  (p) => p.pack && resolution.packs.includes(p.pack)
-);
-
-// Filter out disabled rules (Pack.RuleId=disabled)
-activePrompts = activePrompts.filter((p) => {
-  const disableKey = `${p.pack}.${p.meta.id}`;
-  return resolution.overrides[disableKey] !== "disabled";
-});
+// Filter prompts by active packs and exclude disabled rules
+const activePrompts = prompts.filter((p) => {
+  if (!p.pack || !resolution.packs.includes(p.pack)) return false;
+  if (!p.meta?.id) return true;
+  const disableKey = `${p.pack}.${p.meta.id}`;
+  return resolution.overrides[disableKey] !== "disabled";
+});

This reduces iteration overhead, though the current approach may be clearer for maintainability.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 659ea2e and ec7206d.

📒 Files selected for processing (1)
  • src/cli/orchestrator.ts (37 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/cli/orchestrator.ts (10)
src/output/vale-json-formatter.ts (1)
  • ValeJsonFormatter (26-86)
src/cli/types.ts (9)
  • ProcessViolationsParams (82-92)
  • ProcessCriterionParams (94-100)
  • ProcessCriterionResult (102-107)
  • ProcessPromptResultParams (114-117)
  • ErrorTrackingResult (40-46)
  • RunPromptEvaluationParams (119-126)
  • RunPromptEvaluationResult (128-130)
  • EvaluateFileParams (132-136)
  • EvaluateFileResult (138-140)
src/output/location.ts (1)
  • locateEvidenceWithMatch (107-151)
src/errors/index.ts (1)
  • handleUnknownError (46-51)
src/output/json-formatter.ts (1)
  • JsonFormatter (54-94)
src/evaluators/evaluator-registry.ts (1)
  • createEvaluator (69-77)
src/evaluators/index.ts (1)
  • createEvaluator (21-21)
src/prompts/prompt-loader.ts (1)
  • PromptFile (8-8)
src/schemas/prompt-schemas.ts (1)
  • PromptFile (64-64)
src/boundaries/scan-path-resolver.ts (1)
  • ScanPathResolver (18-72)
🔇 Additional comments (5)
src/cli/orchestrator.ts (5)

1-44: LGTM: Import formatting improvements.

The consistent use of double quotes and improved formatting enhances code readability without altering functionality.


49-686: LGTM: Style normalization with safer defaults.

The changes consistently use empty strings as defaults for match fields and improve code formatting. These modifications enhance code safety and readability without affecting core behavior.


694-743: LGTM: Override application logic is sound.

The function correctly applies overrides to prompt metadata and maintains proper error handling. The style improvements enhance readability.


748-780: LGTM: File evaluation logic with proper backward compatibility.

The function correctly:

  • Initializes evaluation state and determines applicable prompts
  • Processes overrides into an efficient lookup map (O(1) access)
  • Maintains backward compatibility when scanPaths is not configured
  • Properly aggregates results and handles errors including MissingDependencyError

The implementation preserves existing behavior while adding the new filtering functionality.

Also applies to: 806-901


908-965: LGTM: Style improvements in public API.

The formatting changes improve consistency without altering the public API behavior. Error handling and result aggregation remain intact.

Copy link

@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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/cli/orchestrator.ts (1)

802-814: Override map lookup will fail—key extraction doesn't match prompt identification.

The code splits override keys on the first dot (line 805), extracting the pack name into promptId. For a key like "Acme.GrammarCheck.strictness", it stores the value at overrideMap["Acme"]["GrammarCheck.strictness"]. However, line 817 looks up overrides using prompt.id, which is the filename (e.g., "GrammarCheck"), not the pack name. This mismatch means property overrides will never be retrieved.

Either split on the last dot to extract the property name, or look up using the full "${prompt.pack}.${prompt.meta.id}" key instead of prompt.id.

♻️ Duplicate comments (1)
src/cli/orchestrator.ts (1)

795-800: Consider case-insensitive matching for "disabled" value.

The null safety concern from previous reviews is now addressed by the optional chaining at line 797. However, the case-sensitivity issue at line 799 remains: strict equality (!== "disabled") won't match variations like "Disabled", "DISABLED", or boolean false. Users might expect case-insensitive configuration.

Based on learnings, past reviews suggested handling both string variations and boolean values for better UX.

🔎 View suggested improvement:
-  return resolution.overrides[disableKey] !== "disabled";
+  const value = resolution.overrides[disableKey];
+  return typeof value === "string" 
+    ? value.toLowerCase() !== "disabled"
+    : value !== false;
🧹 Nitpick comments (2)
src/cli/orchestrator.ts (2)

64-75: Cleaner worker construction pattern.

The refactored concurrency logic is more idiomatic. The undefined check at line 71 is defensive—if the items array never contains undefined entries by contract, this guard could be removed for clarity.


704-713: Clarify or remove outdated comment.

The comment at lines 706-710 mentions handling nested properties like "GrammarChecker.strictness=9", but the override preprocessing at lines 802-814 already splits dotted keys, so overrides here are flat (e.g., "strictness"). Consider updating or removing this comment to avoid confusion.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ec7206d and ce47d63.

📒 Files selected for processing (1)
  • src/cli/orchestrator.ts (37 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/cli/orchestrator.ts (3)
src/output/reporter.ts (1)
  • printIssueRow (39-110)
src/cli/types.ts (8)
  • ProcessViolationsParams (82-92)
  • ProcessCriterionParams (94-100)
  • ProcessCriterionResult (102-107)
  • ErrorTrackingResult (40-46)
  • RunPromptEvaluationParams (119-126)
  • RunPromptEvaluationResult (128-130)
  • EvaluateFileParams (132-136)
  • EvaluateFileResult (138-140)
src/boundaries/scan-path-resolver.ts (1)
  • ScanPathResolver (18-72)
🔇 Additional comments (2)
src/cli/orchestrator.ts (2)

49-51: LGTM: Clean helper extraction.

The resolveEvaluatorType helper improves readability by centralizing the default evaluator type logic.


849-856: LGTM: Graceful handling of missing dependencies.

The new error path that skips prompts with MissingDependencyError improves user experience by avoiding hard failures when optional dependencies aren't available. The warning messages provide clear guidance.

Copy link

@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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/cli/orchestrator.ts (1)

801-818: Critical bug: Override map keyed incorrectly.

The override pre-processing splits on the first dot (line 804), which creates map keys using only the pack name (e.g., "Acme"). However, prompts are identified by the combination of pack and rule ID (e.g., "Acme.GrammarCheck" as seen on line 793).

When line 816 looks up overrideMap.get(prompt.id), it won't find the correct overrides because:

  • For config Acme.GrammarCheck.severity=warning, the map stores: {"Acme": {"GrammarCheck.severity": "warning"}}
  • But it should store: {"Acme.GrammarCheck": {"severity": "warning"}}

This means prompt-specific overrides (other than disabled) will not be applied correctly.

🔎 Proposed fix
 // Pre-process overrides into a map for O(1) lookup
 const overrideMap = new Map<string, Record<string, unknown>>();
 for (const [key, value] of Object.entries(resolution.overrides)) {
-  const dotIndex = key.indexOf(".");
-  if (dotIndex > 0) {
-    const promptId = key.substring(0, dotIndex);
-    const prop = key.substring(dotIndex + 1);
+  const parts = key.split(".");
+  if (parts.length >= 2) {
+    const pack = parts[0];
+    const ruleId = parts[1];
+    const promptKey = `${pack}.${ruleId}`;
+    const prop = parts.slice(2).join(".");
+    
+    // Only process property overrides (skip Pack.Rule=disabled which is handled above)
+    if (prop) {
-    if (!overrideMap.has(promptId)) {
-      overrideMap.set(promptId, {});
+      if (!overrideMap.has(promptKey)) {
+        overrideMap.set(promptKey, {});
+      }
+      overrideMap.get(promptKey)![prop] = value;
     }
-    overrideMap.get(promptId)![prop] = value;
   }
 }

 for (const prompt of activePrompts) {
-  const promptOverrides = overrideMap.get(prompt.id) || {};
+  const promptKey = `${prompt.pack}.${prompt.meta?.id || prompt.id}`;
+  const promptOverrides = overrideMap.get(promptKey) || {};
   toRun.push({ prompt, overrides: promptOverrides });
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ce47d63 and f24c44f.

📒 Files selected for processing (1)
  • src/cli/orchestrator.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/cli/orchestrator.ts (4)
src/output/reporter.ts (1)
  • printIssueRow (39-110)
src/output/location.ts (1)
  • locateEvidenceWithMatch (107-151)
src/output/json-formatter.ts (1)
  • JsonFormatter (54-94)
src/boundaries/scan-path-resolver.ts (1)
  • ScanPathResolver (18-72)
🔇 Additional comments (3)
src/cli/orchestrator.ts (3)

57-78: LGTM! Concurrency runner preserves order correctly.

The refactored runWithConcurrency function now explicitly pre-allocates the results array and uses index-based assignment to preserve input order, which is an improvement over the previous implementation. The undefined check at line 71 adds defensive safety.


790-799: LGTM! Rule disabling logic is correct and addresses past concerns.

The filtering logic properly:

  • Checks pack membership (line 791)
  • Handles missing meta.id safely with optional chaining (line 792) ✅ Addresses past null safety concern
  • Performs case-insensitive matching for "disabled" with type guard (lines 795-798) ✅ Addresses past case-sensitivity concern

The logic correctly filters out prompts where Pack.RuleId is set to any case variation of "disabled" in the configuration.


846-855: Good addition: graceful handling of missing dependencies.

The code now distinguishes MissingDependencyError from other failures and skips the evaluation with a warning rather than counting it as a request failure. This provides a better user experience when optional dependencies are unavailable.

@oshorefueled oshorefueled merged commit efb0218 into main Dec 27, 2025
3 checks passed
oshorefueled pushed a commit that referenced this pull request Mar 2, 2026
* feat: add support for disabling rules within a package

* feat: add null check when filtering disabled rules

* feat: make rule disabled key case-insensitive

* fix: remove rule property overrides from config
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants