Class: Mutineer::Baseline
- Inherits:
-
Object
- Object
- Mutineer::Baseline
- Defined in:
- lib/mutineer/baseline.rb
Overview
#13: CI baseline/delta gating. A baseline is literally a prior
mutineer run --format json document (KTD-1) — no bespoke format to
version.
We diff the current run against it by the #10 stable survivor id (KTD-2):
a NEW survivor (id present now, absent in the baseline) OR a score drop is
a regression the CLI turns into exit 1. Pure data — stdlib json only, no
fork, no Rails — so it's testable in isolation from a canned JSON + a hand-
built AggregateResult.
Defined Under Namespace
Classes: Delta
Instance Attribute Summary collapse
-
#score ⇒ Object
readonly
Returns the value of attribute score.
Class Method Summary collapse
-
.load(path) ⇒ Mutineer::Baseline
Load a prior --format json run.
Instance Method Summary collapse
-
#diff(aggregate, epsilon: 0.0) ⇒ Mutineer::Baseline::Delta
Diff a current AggregateResult against this baseline by stable survivor id.
-
#initialize(doc) ⇒ Baseline
constructor
Builds a baseline from a JSON document.
Constructor Details
#initialize(doc) ⇒ Baseline
Builds a baseline from a JSON document.
The baseline retains the survivor document and score from the JSON report.
53 54 55 56 |
# File 'lib/mutineer/baseline.rb', line 53 def initialize(doc) @survivors = doc["survivors"] || [] @score = doc.dig("summary", "score") end |
Instance Attribute Details
#score ⇒ Object (readonly)
Returns the value of attribute score.
46 47 48 |
# File 'lib/mutineer/baseline.rb', line 46 def score @score end |
Class Method Details
.load(path) ⇒ Mutineer::Baseline
Load a prior --format json run. Raises ConfigError (NOT exit — R8: a data class must never kill the host) on a missing/unreadable file, unparseable JSON, or a doc that isn't a baseline shape, so the CLI maps it to exit 2 (usage) like every other bad-path flag.
35 36 37 38 39 40 41 42 43 44 |
# File 'lib/mutineer/baseline.rb', line 35 def self.load(path) doc = JSON.parse(File.read(path)) unless doc.is_a?(Hash) && doc["schema_version"] && doc["survivors"].is_a?(Array) raise ConfigError, "not a Mutineer JSON report: #{path}" end new(doc) rescue JSON::ParserError => e raise ConfigError, "invalid baseline JSON in #{path}: #{e.}" end |
Instance Method Details
#diff(aggregate, epsilon: 0.0) ⇒ Mutineer::Baseline::Delta
Diff a current AggregateResult against this baseline by stable survivor id.
epsilon tolerates float jitter on the score (default 0.0 = any drop
gates).
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/mutineer/baseline.rb', line 65 def diff(aggregate, epsilon: 0.0) current = aggregate.surviving_mutants current_ids = current.map(&:id) baseline_ids = @survivors.map { |h| h["id"] } new_survivors = current.reject { |r| baseline_ids.include?(r.id) } fixed = @survivors.reject { |h| current_ids.include?(h["id"]) } current_score = aggregate.mutation_score # nil-score discipline (mirrors Reporter#exit_code): a score absent on # either side can't be compared — skip the drop check, keep the new- # survivor check. score_drop = !@score.nil? && !current_score.nil? && current_score < @score - epsilon Delta.new(new_survivors: new_survivors, fixed_survivors: fixed, score_before: @score, score_after: current_score, score_drop: score_drop, regressed: !new_survivors.empty? || score_drop) end |