Module: Moult::Boundaries
- Defined in:
- lib/moult/boundaries.rb,
lib/moult/boundaries/packwerk.rb,
lib/moult/boundaries/severity.rb
Overview
Orchestrates the architecture-boundaries analysis: it asks the Packwerk adapter for every recorded violation, groups them into findings, and grades each group through the pure Severity model. The result is a ranked BoundariesReport of confidence-null, severity-classified boundary violations — recorded facts, never claims that the code is wrong.
This is the only layer that knows where the facts come from; Severity stays a pure function of the violation type so it can be pinned in isolation.
Defined Under Namespace
Constant Summary collapse
- GROUP_KEY =
A finding is one group of violations sharing this identity (the same constant crossing the same package boundary in the same way); its occurrences are the referencing files.
%i[referencing_package defining_package constant violation_type].freeze
Class Method Summary collapse
- .build_report(root:, min_severity: nil, git_ref: nil, generated_at: nil) ⇒ BoundariesReport
- .finding_for(key, violations) ⇒ Object
- .group(violations) ⇒ Object
- .meets?(severity, floor) ⇒ Boolean
-
.sort_key(finding) ⇒ Object
Most-severe first, then a deterministic alphabetical tie-break so output is stable across runs.
Class Method Details
.build_report(root:, min_severity: nil, git_ref: nil, generated_at: nil) ⇒ BoundariesReport
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/moult/boundaries.rb', line 23 def build_report(root:, min_severity: nil, git_ref: nil, generated_at: nil) result = Packwerk.detect(root: root) findings = group(result.violations).map { |key, violations| finding_for(key, violations) } findings.select! { |f| meets?(f.severity, min_severity) } if min_severity findings.sort_by! { |f| sort_key(f) } BoundariesReport.new( root: root, findings: findings, git_ref: git_ref, generated_at: generated_at, backend: result.backend, backend_version: result.backend_version, configured: result.configured ) end |
.finding_for(key, violations) ⇒ Object
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/moult/boundaries.rb', line 45 def finding_for(key, violations) referencing_package, defining_package, constant, violation_type = key assessment = Severity.classify(violation_type: violation_type) occurrences = violations .map(&:path).uniq.sort .map { |path| BoundariesReport::Occurrence.new(symbol_id: nil, path: path) } BoundariesReport::Finding.new( violation_type: violation_type, severity: assessment.severity, referencing_package: referencing_package, defining_package: defining_package, constant: constant, reasons: assessment.reasons, occurrences: occurrences ) end |
.group(violations) ⇒ Object
41 42 43 |
# File 'lib/moult/boundaries.rb', line 41 def group(violations) violations.group_by { |v| GROUP_KEY.map { |k| v[k] } } end |
.meets?(severity, floor) ⇒ Boolean
69 70 71 |
# File 'lib/moult/boundaries.rb', line 69 def meets?(severity, floor) Severity::SCALE.index(severity) >= Severity::SCALE.index(floor.to_s) end |
.sort_key(finding) ⇒ Object
Most-severe first, then a deterministic alphabetical tie-break so output is stable across runs.
64 65 66 67 |
# File 'lib/moult/boundaries.rb', line 64 def sort_key(finding) [-Severity::SCALE.index(finding.severity), finding.violation_type, finding.referencing_package, finding.defining_package, finding.constant] end |