Class: Insika::Soak::Envelope
- Inherits:
-
Object
- Object
- Insika::Soak::Envelope
- Defined in:
- lib/insika/soak/envelope.rb
Overview
The frozen pre-declared envelope for a soak run. Parses the
fenced yaml block inside a markdown file, validates it completely or not
at all, and exposes the SHA-256 of the WHOLE file — every hourly snapshot
is stamped with it, so editing the envelope mid-run turns the run
invalid instead of producing a verdict nobody can defend.
No defaults, no tolerance: an envelope with a hole is not a pre-declaration. Contrast with EnvSchema (tolerant, warn-and-boot) — that resilience protects a live service; this strictness protects a claim.
Constant Summary collapse
- REQUIRED =
Required keys. A missing one is a ConfigError, not a default.
%i[ version target duration_hours warmup_hours arrival turns_per_hour session_turns concurrency_cap web_concurrency rss_growth_ratio prep_p95_drift_ratio restarts_max error_rate_ceiling no_usage_rate_ceiling coverage_min_ratio gap_seconds_max hourly_turn_floor ].freeze
- CALIBRATED =
Written after E1, before E2 (techspec D3). Absent ->
calibrated?is false and the 72h run refuses to start; the 4h dry run does not require them. %i[rss_ceiling_mb prep_p95_ceiling_ms total_p95_ceiling_ms].freeze
- RATIO_KEYS =
Keys validated as ratios: must be strictly greater than 1 (the gate is "no more than 1.15x", so a ratio of 1 or below is a nonsense gate).
%i[rss_growth_ratio prep_p95_drift_ratio].freeze
- POSITIVE_COUNT_KEYS =
Keys validated as positive integers.
%i[ duration_hours warmup_hours turns_per_hour session_turns concurrency_cap web_concurrency gap_seconds_max hourly_turn_floor ].freeze
- RATE_KEYS =
Keys validated as rates in [0, 1].
%i[error_rate_ceiling no_usage_rate_ceiling coverage_min_ratio].freeze
Instance Attribute Summary collapse
-
#sha ⇒ Object
readonly
Returns the value of attribute sha.
-
#values ⇒ Object
readonly
Returns the value of attribute values.
Class Method Summary collapse
-
.load(path) ⇒ Object
Raises Insika::ConfigError: file missing, no fenced yaml block, unparseable, a REQUIRED key absent, or a value out of range.
-
.parse(source, sha:) ⇒ Object
Pure parse (specs, fixtures).
Instance Method Summary collapse
- #[](key) ⇒ Object
- #calibrated? ⇒ Boolean
-
#dry_run? ⇒ Boolean
E1 shape (<= 8h): the dry run skips the calibrated ceilings.
-
#initialize(values:, sha:) ⇒ Envelope
constructor
A new instance of Envelope.
- #to_h ⇒ Object
Constructor Details
#initialize(values:, sha:) ⇒ Envelope
Returns a new instance of Envelope.
125 126 127 128 |
# File 'lib/insika/soak/envelope.rb', line 125 def initialize(values:, sha:) @values = values @sha = sha end |
Instance Attribute Details
#sha ⇒ Object (readonly)
Returns the value of attribute sha.
123 124 125 |
# File 'lib/insika/soak/envelope.rb', line 123 def sha @sha end |
#values ⇒ Object (readonly)
Returns the value of attribute values.
123 124 125 |
# File 'lib/insika/soak/envelope.rb', line 123 def values @values end |
Class Method Details
.load(path) ⇒ Object
Raises Insika::ConfigError: file missing, no fenced yaml block, unparseable, a REQUIRED key absent, or a value out of range.
46 47 48 49 50 51 |
# File 'lib/insika/soak/envelope.rb', line 46 def self.load(path) bytes = File.binread(path) parse(bytes, sha: "sha256:#{Digest::SHA256.hexdigest(bytes)}") rescue Errno::ENOENT raise ConfigError, "soak envelope not found: #{path}" end |
.parse(source, sha:) ⇒ Object
Pure parse (specs, fixtures). sha is stamped verbatim.
54 55 56 57 58 |
# File 'lib/insika/soak/envelope.rb', line 54 def self.parse(source, sha:) new(values: validate(YAML.safe_load(fenced_yaml(source)) || {}), sha: sha) rescue Psych::SyntaxError => e raise ConfigError, "soak envelope yaml is unparseable: #{e..lines.first.to_s.strip}" end |
Instance Method Details
#[](key) ⇒ Object
130 |
# File 'lib/insika/soak/envelope.rb', line 130 def [](key) = values[key] |
#calibrated? ⇒ Boolean
132 |
# File 'lib/insika/soak/envelope.rb', line 132 def calibrated? = CALIBRATED.all? { |key| !values[key].nil? } |
#dry_run? ⇒ Boolean
E1 shape (<= 8h): the dry run skips the calibrated ceilings.
135 |
# File 'lib/insika/soak/envelope.rb', line 135 def dry_run? = values[:duration_hours] <= 8 |
#to_h ⇒ Object
137 |
# File 'lib/insika/soak/envelope.rb', line 137 def to_h = values.merge(sha: sha) |