Module: Moult::Flags
- Defined in:
- lib/moult/flags.rb,
lib/moult/flags/snapshot.rb,
lib/moult/flags/staleness.rb,
lib/moult/flags/classification.rb
Overview
Orchestrates the feature-flag analysis: it asks the FlagScanner for every OpenFeature flag-evaluation call site, groups them by flag key, attributes each site to its enclosing method (best-effort, for the cross-analysis join), and grades each group through the pure Classification model. The result is a FlagsReport cataloguing flag USAGE.
When a provider snapshot is supplied (the static<->provider merge, the flags analogue of the static<->runtime coverage merge), it ALSO joins each flag key to the provider's recorded state and grades a confidence-graded Staleness candidate — the first real use of the per-finding confidence slot in this slice. The snapshot is evidence, never proof; nothing here asserts a flag is certainly stale or dead.
This is the only layer that joins the facts to symbols and to the provider; Classification and Staleness stay pure functions of the observed signals so they can be pinned in isolation, FlagScanner stays the sole keeper of the OpenFeature call shape, and Snapshot the sole keeper of the export format.
Defined Under Namespace
Modules: Classification, Snapshot, Staleness Classes: MethodIndex
Class Method Summary collapse
- .build_report(root:, files:, git_ref: nil, generated_at: nil, snapshot: nil) ⇒ FlagsReport
- .finding_for(key, sites, methods, snapshot = nil, has_dynamic = false) ⇒ Object
- .scan(abs, root) ⇒ Object
-
.staleness_for(key, snapshot, has_dynamic) ⇒ Object
The staleness candidate for a key, joined on the literal flag_key (the flags join key, mirroring how coverage joins on symbol_id).
Class Method Details
.build_report(root:, files:, git_ref: nil, generated_at: nil, snapshot: nil) ⇒ FlagsReport
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
# File 'lib/moult/flags.rb', line 29 def build_report(root:, files:, git_ref: nil, generated_at: nil, snapshot: nil) sites = files.flat_map { |abs| scan(abs, root) } methods = MethodIndex.new(root: root, files: files) literal, dynamic = sites.partition { |s| !s.flag_key.nil? } has_dynamic = dynamic.size.positive? findings = literal.group_by(&:flag_key).map { |key, group| finding_for(key, group, methods, snapshot, has_dynamic) } # With a snapshot, strongest staleness candidate first (then refs, then key); # without, most-referenced first. Either way alphabetical by key breaks ties so # output is stable. findings.sort_by! do |f| f.staleness ? [-f.staleness.confidence, -f.reference_count, f.flag_key] : [-f.reference_count, f.flag_key] end FlagsReport.new( root: root, findings: findings, dynamic_references: dynamic.size, git_ref: git_ref, generated_at: generated_at, provider_source: snapshot&.source ) end |
.finding_for(key, sites, methods, snapshot = nil, has_dynamic = false) ⇒ Object
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/moult/flags.rb', line 59 def finding_for(key, sites, methods, snapshot = nil, has_dynamic = false) assessment = Classification.classify( value_types: sites.map(&:value_type), default_values: sites.map(&:default_value) ) occurrences = sites .sort_by { |s| [s.path, s.line] } .map { |s| FlagsReport::Occurrence.new(symbol_id: methods.symbol_id_at(s.path, s.line), path: s.path, line: s.line, method_name: s.method_name) } staleness = staleness_for(key, snapshot, has_dynamic) FlagsReport::Finding.new( flag_key: key, value_type: assessment.value_type, reference_count: assessment.reference_count, default_values: assessment.default_values, reasons: assessment.reasons, occurrences: occurrences, staleness: staleness ) end |
.scan(abs, root) ⇒ Object
53 54 55 56 57 |
# File 'lib/moult/flags.rb', line 53 def scan(abs, root) FlagScanner.scan_file(abs, SymbolId.relative_path(abs, root)) rescue [] end |
.staleness_for(key, snapshot, has_dynamic) ⇒ Object
The staleness candidate for a key, joined on the literal flag_key (the flags join key, mirroring how coverage joins on symbol_id). nil when no snapshot was supplied, leaving the finding byte-for-byte v1-identical.
82 83 84 85 |
# File 'lib/moult/flags.rb', line 82 def staleness_for(key, snapshot, has_dynamic) return nil unless snapshot Staleness.classify(state: snapshot.state_for(key), has_dynamic_references: has_dynamic) end |