Module: Ace::Review::Molecules::ExemptPaths

Defined in:
lib/ace/review/molecules/exempt_paths.rb

Overview

Review-exempt paths: globs whose deltas never require a model report.

A delta round whose changed files all match the declared patterns is recorded as a no-op session without any model call; in mixed rounds the exempt paths are excluded from the subject and enumerated. Patterns are validated at config load — a pattern that matches every path is refused instead of silently exempting the world.

Constant Summary collapse

OVER_BROAD_PROBES =

Probe set covering root-level and nested paths. A pattern matching every probe leaves nothing reviewable by definition. Dotfiles are excluded: wildcard patterns never match them under fnmatch pathname semantics (no FNM_DOTMATCH), so they cannot prove over-breadth.

["README.md", "a.txt", "dir/b.txt", "a/b/c.txt"].freeze
CONVENTIONAL_MATCH_ALL =

Conventional spellings authors use for "everything". fnmatch pathname semantics make bare "*" / "**" single-segment, but their intent is unmistakable — refuse them instead of silently exempting the world.

["*", "**"].freeze

Class Method Summary collapse

Class Method Details

.classify(paths, patterns) ⇒ Hash

Partition changed paths (destination paths, as in the diff manifest) into exempt and non-exempt.

Parameters:

  • paths (Array<String>)
  • patterns (Array<String>, nil)

Returns:

  • (Hash) —

    non_exempt:



51
52
53
54
55
56
57
# File 'lib/ace/review/molecules/exempt_paths.rb', line 51

def self.classify(paths, patterns)
  patterns = Array(patterns)
  exempt, non_exempt = Array(paths).partition do |path|
    patterns.any? { |pattern| SubjectFilter.glob_match?(pattern, path) }
  end
  {exempt: exempt, non_exempt: non_exempt}
end

.validate!(patterns) ⇒ String?

Returns refusal message, or nil when valid.

Parameters:

  • patterns (Object) —

    raw exempt_paths config value

Returns:

  • (String, nil) —

    refusal message, or nil when valid



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/ace/review/molecules/exempt_paths.rb', line 29

def self.validate!(patterns)
  return nil if patterns.nil?

  unless patterns.is_a?(Array) && patterns.all? { |pattern| pattern.is_a?(String) && !pattern.strip.empty? }
    return "exempt_paths must be a list of non-empty glob strings"
  end

  patterns.each do |pattern|
    if CONVENTIONAL_MATCH_ALL.include?(pattern) ||
        OVER_BROAD_PROBES.all? { |probe| SubjectFilter.glob_match?(pattern, probe) }
      return "exempt_paths pattern '#{pattern}' matches every path; refusing to exempt the world"
    end
  end
  nil
end