henitai 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +296 -1
- data/README.md +109 -16
- data/assets/schema/henitai.schema.json +20 -0
- data/lib/henitai/arid_node_filter.rb +4 -19
- data/lib/henitai/bootstrap_error_message.rb +20 -0
- data/lib/henitai/canonical_report_merger.rb +23 -2
- data/lib/henitai/cli/run_command.rb +25 -7
- data/lib/henitai/cli/run_options.rb +1 -1
- data/lib/henitai/cli.rb +4 -1
- data/lib/henitai/configuration.rb +4 -1
- data/lib/henitai/configuration_validator/rules.rb +8 -0
- data/lib/henitai/configuration_validator/scalars.rb +9 -0
- data/lib/henitai/configuration_validator.rb +2 -1
- data/lib/henitai/constant_path.rb +48 -0
- data/lib/henitai/control_run.rb +73 -0
- data/lib/henitai/coverage_bootstrapper.rb +57 -15
- data/lib/henitai/coverage_formatter.rb +26 -3
- data/lib/henitai/coverage_report_reader.rb +21 -0
- data/lib/henitai/equivalence_detector/operand_predicates.rb +16 -0
- data/lib/henitai/equivalence_detector.rb +46 -38
- data/lib/henitai/example_summary.rb +24 -0
- data/lib/henitai/execution_engine/fork_server_scope.rb +57 -0
- data/lib/henitai/execution_engine.rb +75 -60
- data/lib/henitai/fidelity_check.rb +173 -0
- data/lib/henitai/flaky_detection_baseline.rb +61 -0
- data/lib/henitai/flaky_mutant_retrier.rb +43 -0
- data/lib/henitai/flaky_retry_decision.rb +23 -0
- data/lib/henitai/flaky_test_registry.rb +63 -0
- data/lib/henitai/fork_server/client.rb +231 -0
- data/lib/henitai/fork_server/group_killer.rb +48 -0
- data/lib/henitai/fork_server/group_terminator.rb +47 -0
- data/lib/henitai/fork_server/launcher.rb +38 -0
- data/lib/henitai/fork_server/mutant_runner.rb +141 -0
- data/lib/henitai/fork_server/protocol.rb +73 -0
- data/lib/henitai/fork_server/reaper.rb +24 -0
- data/lib/henitai/fork_server/runtime.rb +109 -0
- data/lib/henitai/fork_server/server.rb +108 -0
- data/lib/henitai/fork_server/server_process.rb +73 -0
- data/lib/henitai/fork_server/status.rb +52 -0
- data/lib/henitai/fork_server.rb +43 -0
- data/lib/henitai/generated_artifacts.rb +3 -0
- data/lib/henitai/git_diff_analyzer.rb +28 -11
- data/lib/henitai/incremental_filter.rb +20 -10
- data/lib/henitai/integration/base.rb +72 -5
- data/lib/henitai/integration/capped_log_sink.rb +34 -0
- data/lib/henitai/integration/child_bootstrap.rb +7 -0
- data/lib/henitai/integration/child_report_store.rb +36 -0
- data/lib/henitai/integration/minitest.rb +17 -7
- data/lib/henitai/integration/minitest_autorun.rb +20 -0
- data/lib/henitai/integration/minitest_outcome_reporter.rb +28 -0
- data/lib/henitai/integration/minitest_preload.rb +30 -0
- data/lib/henitai/integration/minitest_runnable_filter.rb +61 -0
- data/lib/henitai/integration/minitest_test_runner.rb +32 -15
- data/lib/henitai/integration/mutant_run_support.rb +73 -13
- data/lib/henitai/integration/rspec_child_runner.rb +44 -9
- data/lib/henitai/integration/rspec_preload.rb +35 -0
- data/lib/henitai/integration/rspec_process_runner.rb +4 -1
- data/lib/henitai/integration/scenario_log_support.rb +31 -18
- data/lib/henitai/integration.rb +16 -3
- data/lib/henitai/minitest_coverage_reporter.rb +22 -6
- data/lib/henitai/minitest_result_file.rb +62 -0
- data/lib/henitai/mutant/activation.rb +32 -0
- data/lib/henitai/mutant/activator.rb +75 -55
- data/lib/henitai/mutant/def_injection.rb +136 -0
- data/lib/henitai/mutant/lexical_scope_check.rb +120 -0
- data/lib/henitai/mutant/lexical_target.rb +105 -0
- data/lib/henitai/mutant/replacement.rb +52 -0
- data/lib/henitai/mutant.rb +27 -8
- data/lib/henitai/mutant_generator.rb +62 -18
- data/lib/henitai/mutant_history_store/verdict_cache.rb +12 -11
- data/lib/henitai/mutant_history_store.rb +14 -4
- data/lib/henitai/mutant_identity.rb +5 -1
- data/lib/henitai/mutant_verdict.rb +71 -0
- data/lib/henitai/operators/array_declaration.rb +4 -0
- data/lib/henitai/operators/assignment_expression.rb +2 -0
- data/lib/henitai/operators/conditional_expression.rb +21 -1
- data/lib/henitai/operators/hash_literal.rb +7 -4
- data/lib/henitai/operators/method_expression.rb +14 -3
- data/lib/henitai/operators/regex_metacharacters.rb +89 -0
- data/lib/henitai/operators/regex_mutator.rb +23 -28
- data/lib/henitai/operators/return_value.rb +1 -1
- data/lib/henitai/operators.rb +1 -0
- data/lib/henitai/per_test_coverage.rb +11 -7
- data/lib/henitai/per_test_coverage_collector.rb +30 -31
- data/lib/henitai/per_test_coverage_delta.rb +60 -0
- data/lib/henitai/per_test_coverage_selector.rb +26 -13
- data/lib/henitai/process_wakeup.rb +8 -3
- data/lib/henitai/process_worker_runner.rb +19 -5
- data/lib/henitai/reporter.rb +15 -8
- data/lib/henitai/result.rb +32 -16
- data/lib/henitai/reuse_context.rb +50 -0
- data/lib/henitai/rspec_coverage_formatter.rb +4 -0
- data/lib/henitai/rspec_outcomes.rb +72 -0
- data/lib/henitai/runner.rb +58 -19
- data/lib/henitai/runner_dependencies.rb +22 -1
- data/lib/henitai/sampling_strategy.rb +36 -6
- data/lib/henitai/scenario_execution_result.rb +28 -5
- data/lib/henitai/signature_line.rb +21 -0
- data/lib/henitai/slot_scheduler/draining.rb +12 -2
- data/lib/henitai/slot_scheduler/process_control.rb +33 -0
- data/lib/henitai/slot_scheduler/retry_policy.rb +8 -6
- data/lib/henitai/slot_scheduler.rb +47 -8
- data/lib/henitai/source_file_selection.rb +1 -1
- data/lib/henitai/source_parser.rb +29 -9
- data/lib/henitai/static_filter.rb +45 -14
- data/lib/henitai/stillborn_filter.rb +70 -2
- data/lib/henitai/subject.rb +8 -3
- data/lib/henitai/subject_resolver.rb +65 -31
- data/lib/henitai/suite_boot_clock.rb +48 -0
- data/lib/henitai/survivor_activation_cache.rb +18 -11
- data/lib/henitai/survivor_rerun_strategy.rb +47 -43
- data/lib/henitai/test_file_outcomes.rb +79 -0
- data/lib/henitai/timeout_calibrator.rb +31 -9
- data/lib/henitai/timeout_ceiling.rb +37 -0
- data/lib/henitai/verdict_fingerprint.rb +29 -30
- data/lib/henitai/version.rb +1 -1
- data/lib/henitai.rb +17 -1
- data/sig/configuration_validator.rbs +1 -0
- data/sig/henitai.rbs +227 -45
- metadata +46 -3
- data/lib/henitai/survivor_test_filter.rb +0 -72
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4c9ef6e2d806e8d12acfd36adda062192c5cf4ba700ee140ce7d6ad848eff0c8
|
|
4
|
+
data.tar.gz: 800ba49ba72ce0ab6090e1ab9b40ea5146559738e59af5a81ceeb80923bc974e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 60acc4fc6df82c4d273c110302af6a73b7c4f7d6f3ebb2ae9fdcea06ca69e5cef2e61945c396b38810f978b8ace3db2b988d224b637d0f8f11c02ccb03eee368
|
|
7
|
+
data.tar.gz: 9fe40adf6368041348247af329f3153a0027e89bbbe60e9dcdef27a4a666512446ab7569188e891ec7eb2f5fe8419c33eeee2ed1778a5b034c97901ca94a095c
|
data/CHANGELOG.md
CHANGED
|
@@ -7,9 +7,262 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.6.0] - 2026-10-20
|
|
11
|
+
|
|
12
|
+
Minor release with a deliberate score break: false kills and harness
|
|
13
|
+
failures no longer count as detected mutants, so most projects, including
|
|
14
|
+
Henitai's own dogfood run, will report lower Mutation Scores. Re-measure
|
|
15
|
+
before adjusting thresholds.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- **Scores will drop, by design.** A mutant now counts as detected only when a
|
|
20
|
+
test failed because of its mutation (ADR-14). Harness failures that used to
|
|
21
|
+
be credited as kills are now reported as `CompileError` or `RuntimeError`,
|
|
22
|
+
with the reason in `statusReason`. On an assertion-free test suite, 0.5.3
|
|
23
|
+
reported 130 of 137 mutants as killed; this release reports none. Projects
|
|
24
|
+
should expect lower Mutation Scores. Re-measure before adjusting thresholds.
|
|
25
|
+
- **Flaky-test handling.** Survivors are no longer retried: a retry could only
|
|
26
|
+
turn a survivor into a kill and inflate the score. Kills are re-checked, up
|
|
27
|
+
to `max_flaky_retries`, only when every failing test file is known to be
|
|
28
|
+
flaky, as found by the new opt-in `mutation.flaky_detection` (baseline suite
|
|
29
|
+
runs twice; flaky files go to `henitai_flaky_tests.json`, removed by
|
|
30
|
+
`henitai clean`). Without it nothing is retried, so runtime on survivor-heavy
|
|
31
|
+
suites drops. The ">5% of mutants needed a retry" warning is replaced by a
|
|
32
|
+
report of flaky tests and re-checked kills. Child reports now carry
|
|
33
|
+
`failed_tests`. Failures outside an example (an `after(:context)` hook error,
|
|
34
|
+
a suite-level hook, a Minitest result without a file) are attributed to their
|
|
35
|
+
spec file when RSpec names it; otherwise the run is flagged
|
|
36
|
+
`unattributed_failures`, which makes a kill genuine (never retried) and makes
|
|
37
|
+
the flaky baseline reject the run. Baseline runs that fail on a file the two
|
|
38
|
+
runs cannot call flaky (for example one seen in a single run) now abort
|
|
39
|
+
instead of being accepted. Minitest outcomes are keyed to the file defining
|
|
40
|
+
the test class, not to a shared module that supplies the test method.
|
|
41
|
+
- Mutant runs are classified from an explicit report written by the child
|
|
42
|
+
process instead of from its exit status. An exception while activating the
|
|
43
|
+
mutant (for example a `NameError` from a superclass defined in another file)
|
|
44
|
+
is `CompileError`, not `Killed`. A child killed by a signal, or one that
|
|
45
|
+
exits without reporting, is `RuntimeError`, not `Killed`. A `SystemExit`
|
|
46
|
+
raised by the code under test is `RuntimeError`, not `Survived`.
|
|
47
|
+
- Mutants are activated only after the spec or test files have loaded, so a
|
|
48
|
+
subject whose superclass or constants live in other files can be tested.
|
|
49
|
+
Previously the child loaded the subject file on its own and failed with a
|
|
50
|
+
`NameError` (every `ApplicationRecord` model, for example).
|
|
51
|
+
- Mutants are activated by re-evaluating the subject's own `def` inside its
|
|
52
|
+
original module and class openers (ADR-13), not through `define_method`.
|
|
53
|
+
Constant lookup through enclosing modules, implicit `super`, `yield`,
|
|
54
|
+
`block_given?`, argument forwarding, default values, `__FILE__`/`__LINE__`,
|
|
55
|
+
`frozen_string_literal` and visibility now behave as in the original method.
|
|
56
|
+
Mutations in default values take effect, and splices no longer shift after
|
|
57
|
+
multibyte characters or leave heredoc bodies behind. Activation recipes from
|
|
58
|
+
earlier versions are ignored and regenerated.
|
|
59
|
+
|
|
60
|
+
### Added
|
|
61
|
+
|
|
62
|
+
- `mutation.sampling.seed` (integer >= 0, default `0`) and real stratified
|
|
63
|
+
sampling: per subject `max(1, ceil(size * ratio))` mutants, strata by
|
|
64
|
+
operator ordered by `SHA256(seed, stable_id)`, visited round-robin, original
|
|
65
|
+
order kept. The report records `"sampling": {strategy, ratio, seed}`.
|
|
66
|
+
- Report fields: top-level `completeFiles` (non-authoritative runs) and
|
|
67
|
+
per-file `sessionId` and `gitSha` provenance.
|
|
68
|
+
- `rake oracle:reuse` (run in CI): on a scratch copy of the oracle corpus, the
|
|
69
|
+
`--incremental` verdicts must equal a fresh full run after scripted edits to
|
|
70
|
+
source, tests, a helper and the configuration.
|
|
71
|
+
- **Fork server for Minitest and parallel runs.** `mutation.fork_server`
|
|
72
|
+
(opt-in, ADR-15) now supports Minitest and `jobs > 1`: the environment is
|
|
73
|
+
booted once and each mutant process is forked from the server. Falls back to
|
|
74
|
+
per-mutant boot with a warning if the server is unavailable.
|
|
75
|
+
- A fidelity check rejects, before execution, every mutant whose activated
|
|
76
|
+
code differs from the original method by more than the reported mutation.
|
|
77
|
+
Examples are a negated condition that lost its parentheses, keyword
|
|
78
|
+
arguments re-rendered as a positional hash, `|x|` re-rendered as `|x,|`, a
|
|
79
|
+
splice shifted by a multibyte character, and a removed assignment that turns
|
|
80
|
+
a later local-variable read into a method call. Such mutants are reported as
|
|
81
|
+
`CompileError` with the reason.
|
|
82
|
+
- `mutation.control_runs` (default `true`): after execution, every subject
|
|
83
|
+
with a detected verdict runs once more with its unmutated method injected.
|
|
84
|
+
If its tests fail, the subject's detected verdicts are reclassified as
|
|
85
|
+
`CompileError`, because the injection itself broke them.
|
|
86
|
+
- Methods defined in a constructor block assigned to a constant
|
|
87
|
+
(`Point = Struct.new(:x) do ... end`, likewise `Data.define` and
|
|
88
|
+
`Class.new`) and in `class << CONST` are now subjects. Top-level
|
|
89
|
+
`def Const.name` methods are subjects as well.
|
|
90
|
+
- `rake oracle` runs a corpus whose verdicts follow from its construction and
|
|
91
|
+
fails on false kills or false survivors. CI runs it.
|
|
92
|
+
|
|
93
|
+
### Fixed
|
|
94
|
+
|
|
95
|
+
- **Verdict reuse is bound to a reuse context.** `--incremental` reused stale
|
|
96
|
+
`Killed` verdicts after a spec helper, the configuration or the henitai
|
|
97
|
+
version changed. Every cached `Killed` and `Survived` verdict now stores a
|
|
98
|
+
`ReuseContext` fingerprint (test dependency files, henitai version,
|
|
99
|
+
integration, operators, `test_excludes`, `coverage_criteria`) and is reused
|
|
100
|
+
only under an identical one; rows recorded without it are never reused.
|
|
101
|
+
`rake oracle:reuse` reproduced 121 mismatches against fresh runs after a
|
|
102
|
+
helper edit before the fix and none after it.
|
|
103
|
+
- **`--survivors-from` no longer skips survivors on a git heuristic.** The
|
|
104
|
+
selected survivors go through the same content-fingerprint reuse rules as
|
|
105
|
+
`--incremental`, always: new or edited tests and helpers invalidate them,
|
|
106
|
+
reused survivors are reported with `fromCache`, and recipe stubs without a
|
|
107
|
+
source range are always re-executed. `SurvivorTestFilter` is removed.
|
|
108
|
+
The recipe fast path now refreshes coverage (Gate 0) so new or edited tests
|
|
109
|
+
are selected, recipe stubs also run their name-matched tests, and survivor
|
|
110
|
+
reruns never sample (sampling had dropped prior survivors before matching).
|
|
111
|
+
`--force` now also bypasses this reuse. Duplicate programs are collapsed
|
|
112
|
+
before sampling, so a sampled run keeps the same representative as an
|
|
113
|
+
unsampled survivor rerun and its survivors are found again.
|
|
114
|
+
- A survived verdict whose covering-test fingerprint cannot be recomputed keeps
|
|
115
|
+
stored fingerprints only from a survived row of the same subject source,
|
|
116
|
+
never from a killed row or an edited method.
|
|
117
|
+
- Gate 1 source selection has its own per-test coverage instance, so reuse and
|
|
118
|
+
history read the post-bootstrap per-test map.
|
|
119
|
+
- Recipe stubs keep their precomputed stable ID and persist the `replacement`
|
|
120
|
+
source in the history store.
|
|
121
|
+
- **Trend history only records authoritative runs.** `--since`,
|
|
122
|
+
subject-scoped and survivor-rerun results no longer add a `runs` row.
|
|
123
|
+
- **Canonical report merge.** A scoped run that mutated every subject of a file
|
|
124
|
+
replaces that file's prior entry wholesale (and removes it when it has no
|
|
125
|
+
mutants), so stale mutants of edited or deleted code no longer linger.
|
|
126
|
+
`--survivors-from <canonical report>` redirects to the session snapshot only
|
|
127
|
+
when every file entry carries the report's `sessionId`; a file whose every
|
|
128
|
+
prior mutant was re-run takes the new run's provenance.
|
|
129
|
+
- `--since` diffs against the merge base (`REF...HEAD`) instead of the ref's
|
|
130
|
+
tip, so commits that landed on the base branch after the fork point are not
|
|
131
|
+
treated as changes.
|
|
132
|
+
- The dashboard reporter uploads the merged canonical report for scoped runs
|
|
133
|
+
instead of the partial one.
|
|
134
|
+
- `Pending` mutants are excluded from the MS and MSI denominators; MSI is
|
|
135
|
+
`killed / (total - pending)`.
|
|
136
|
+
- **Equivalence detection only flags sound cases.** `false || x` and
|
|
137
|
+
`true && x` (left literal only); `n + 0`, `n * 1` and siblings only for
|
|
138
|
+
Integer/Float literal receivers (not `-0.0`); `==` <-> `eql?` only when both
|
|
139
|
+
operands are string literals; `==` <-> `equal?` for singleton literals.
|
|
140
|
+
Unsound rules (`x || false`, `x && true`, unknown receivers, a single string
|
|
141
|
+
literal) no longer mark mutants `Equivalent`.
|
|
142
|
+
- **`mutation.ignore_patterns` is line-scoped.** A pattern is matched against
|
|
143
|
+
the source line where the mutant's node starts, in `StaticFilter`; matching
|
|
144
|
+
mutants are reported as `Ignored` with an `ignore_reason` instead of being
|
|
145
|
+
dropped at generation time. An enclosing construct whose body matches is no
|
|
146
|
+
longer suppressed. The line is decoded honouring a magic encoding comment,
|
|
147
|
+
so a non-UTF-8 source file no longer aborts filtering.
|
|
148
|
+
- **Review follow-ups.** The slot scheduler no longer signals the process
|
|
149
|
+
group of a reaped pid that owns no mutant slot. Minitest results for tests
|
|
150
|
+
added by reopening a class in another file are attributed to the file that
|
|
151
|
+
defines the method, so coverage-first selection no longer misses them. With
|
|
152
|
+
the fork server active, calibrated timeouts keep the measured suite boot
|
|
153
|
+
(served mutants still run `before(:suite)` hooks). The `fork_server` schema
|
|
154
|
+
description and the remediation plan now state the real scope (RSpec and
|
|
155
|
+
Minitest, any `jobs`).
|
|
156
|
+
- **`--incremental` no longer reuses stale survived verdicts for def-line
|
|
157
|
+
mutants.** Their test selection is widened with name-matched tests that the
|
|
158
|
+
survivor fingerprint does not cover, so survived verdicts for mutants on a
|
|
159
|
+
method's def line always re-execute (killed reuse is unaffected: a kill by
|
|
160
|
+
an unchanged covering test remains valid).
|
|
161
|
+
- **Output capture no longer delays or races on lingering grandchildren.**
|
|
162
|
+
Closing a mutant child's captured stdout/stderr no longer waits up to 1 s
|
|
163
|
+
per stream for EOF and no longer kills the drain thread mid-write (which
|
|
164
|
+
could exceed the cap or write the truncation marker twice). The drain
|
|
165
|
+
thread is stopped cooperatively through a stop pipe and takes what is
|
|
166
|
+
already readable.
|
|
167
|
+
- **Fork-server lifecycle.** A server lost or stalled mid-run no longer turns
|
|
168
|
+
its in-flight mutants into `runtime_error`: they are rerun through the
|
|
169
|
+
per-mutant-boot fallback. Fallback runs use boot-inclusive timeouts. Mutant
|
|
170
|
+
processes forked by the server are cleaned up on timeout, loss and teardown
|
|
171
|
+
even before they lead a process group, and the connection and wake-pipe fds
|
|
172
|
+
are no longer inherited by mutant processes. The parallel event loop no
|
|
173
|
+
longer stalls on an exit event already buffered in the client, and the
|
|
174
|
+
SIGTERM drain window always runs its full length.
|
|
175
|
+
- The "negated condition" mutant now negates the whole condition
|
|
176
|
+
(`!(a > b)`), not just its left operand (`!a > b`).
|
|
177
|
+
- Source files are read as UTF-8 regardless of the process locale. With `LANG`
|
|
178
|
+
unset or `C`, any non-ASCII source file used to abort subject resolution.
|
|
179
|
+
- Per-test coverage now narrows RSpec test selection. RSpec records test files
|
|
180
|
+
as `./spec/x_spec.rb` while candidates arrive as `spec/x_spec.rb`, so the
|
|
181
|
+
lookup never matched and every mutant ran all candidate files.
|
|
182
|
+
- `--since` and the dirty-source and survivor checks now work for a project in
|
|
183
|
+
a sub-directory of its git repository and for non-ASCII file names.
|
|
184
|
+
- A corrupt or locked `mutation-history.sqlite3` no longer discards the run's
|
|
185
|
+
reports. History recording and export now warn instead.
|
|
186
|
+
- Forked mutant children reset the INT, TERM, HUP and CHLD handlers inherited
|
|
187
|
+
from the parent, so a draining SIGTERM is no longer ignored.
|
|
188
|
+
- A zero-example check no longer matches `10 examples, 0 failures`, nor a
|
|
189
|
+
`No examples found.` or `0 examples, 0 failures` quoted in failure output;
|
|
190
|
+
only the run's last summary line counts. Such kills were reported as
|
|
191
|
+
`CompileError`.
|
|
192
|
+
- A run in which harness errors (`CompileError`) left no mutant to score now
|
|
193
|
+
exits `1` with a warning instead of passing its threshold with nothing
|
|
194
|
+
tested.
|
|
195
|
+
- Mutating an `elsif` condition no longer rewrites the whole `if` chain; only
|
|
196
|
+
the condition changes.
|
|
197
|
+
- String parts of interpolated strings, symbols, backticks and regexps, and
|
|
198
|
+
elements of `%w` arrays, are no longer mutated as standalone strings. Their
|
|
199
|
+
replacement text changed the literal's syntax rather than its value.
|
|
200
|
+
- Operator replacements are parenthesised when spliced, so `a && b && c`
|
|
201
|
+
mutated to `a || b` no longer reads as `a || (b && c)`.
|
|
202
|
+
- Two mutants at the same position with the same description no longer share
|
|
203
|
+
one stable identity and history entry.
|
|
204
|
+
- `ReturnValue` mutates only the method's final expression, not every
|
|
205
|
+
expression that happens to equal it.
|
|
206
|
+
- Subject expressions for predicate, bang, setter and operator methods, such
|
|
207
|
+
as `Foo#empty?`, `Foo#save!`, `Foo#name=` and `Foo#==`, select their method
|
|
208
|
+
instead of nothing.
|
|
209
|
+
- Mutants from different operators that produce the same program run once.
|
|
210
|
+
- The implicit value of a shorthand hash pair (`build(config:)`) is no longer
|
|
211
|
+
mutated. Its replacement rewrote the key to `build(nil:)`.
|
|
212
|
+
- A mutant that removes the only assignment of a local variable read later in
|
|
213
|
+
the method is no longer generated. Ruby parses the later read as a method
|
|
214
|
+
call, so every such mutant failed with a `NameError` wherever it ran.
|
|
215
|
+
- Subjects are attributed to the right namespace. A `class ::Top` inside
|
|
216
|
+
`module Outer` is `Top`, not `Outer::Top`. A `def Other.name` inside `Outer`
|
|
217
|
+
belongs to `Other`, not `Outer`. Methods of `class << obj` or `def obj.name`
|
|
218
|
+
for a non-constant `obj` are no longer reported as class methods of the
|
|
219
|
+
enclosing class.
|
|
220
|
+
- "replaced method call with nil" on a call with a block replaces the call
|
|
221
|
+
together with its block. Replacing only the call left `nil { ... }`, which
|
|
222
|
+
does not parse, so these sites were never tested. Blocks attached to
|
|
223
|
+
logger, output and debug calls stay arid.
|
|
224
|
+
- `RegexMutator` no longer drops the interpolations and later lines of a
|
|
225
|
+
dynamic or multi-line regexp, which it now leaves unmutated. It skips
|
|
226
|
+
escaped characters and the contents of character classes, so `[^0-9]` is
|
|
227
|
+
no longer reported as a removed `^` anchor and `[+-]` no longer as a
|
|
228
|
+
quantifier swap.
|
|
229
|
+
|
|
230
|
+
## [0.5.3] - 2026-08-26
|
|
231
|
+
|
|
232
|
+
### Fixed
|
|
233
|
+
|
|
234
|
+
- A timed-out Minitest baseline suite is now actually killed. Its child was
|
|
235
|
+
spawned without `pgroup: true`, so the parent's group-wide `SIGTERM` named a
|
|
236
|
+
process group that never existed, raised `ESRCH`, and left the suite running;
|
|
237
|
+
the parent then blocked in `Process.wait` until the suite finished on its own
|
|
238
|
+
— minutes past the timeout it had already reported, and long after the log
|
|
239
|
+
tail quoted in the error had stopped describing reality. The suite child now
|
|
240
|
+
leads its own group, as the RSpec baseline child already did, and post-run
|
|
241
|
+
cleanup signals that group instead of the single pid, so a Rails test server
|
|
242
|
+
or browser driver started by the suite is torn down with it.
|
|
243
|
+
|
|
244
|
+
## [0.5.2] - 2026-08-26
|
|
245
|
+
|
|
246
|
+
### Changed
|
|
247
|
+
|
|
248
|
+
- `test_excludes` now also applies to the coverage-bootstrap suite, not only to
|
|
249
|
+
per-mutant test selection. Slow end-to-end or integration suites could be kept
|
|
250
|
+
away from mutant children but still had to run in full during the baseline,
|
|
251
|
+
where the fixed suite timeout aborts the run with
|
|
252
|
+
`Henitai::CoverageError: Configured test suite failed while generating
|
|
253
|
+
coverage` even though the suite itself was green. Excluded files are also
|
|
254
|
+
dropped from the coverage freshness watch list, so a test that no longer
|
|
255
|
+
contributes to the baseline no longer invalidates it. Lines covered only by
|
|
256
|
+
excluded tests now count as uncovered and are not mutated — matching what
|
|
257
|
+
already happened at execution time, where such mutants could never be killed.
|
|
258
|
+
A `test_excludes` set that leaves no test file now aborts with
|
|
259
|
+
`Henitai::ConfigurationError` instead of running an empty suite and then
|
|
260
|
+
reporting missing coverage.
|
|
261
|
+
|
|
10
262
|
## [0.5.1] - 2026-08-25
|
|
11
263
|
|
|
12
264
|
### Changed
|
|
265
|
+
|
|
13
266
|
- `minitest` runtime dependency widened from `~> 5.25` to `>= 5.25, < 7`.
|
|
14
267
|
The floor is unchanged; only the ceiling moved. `~> 5.25` capped the
|
|
15
268
|
range below 6.0, so bundles resolving minitest 6.x could not install
|
|
@@ -20,6 +273,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
20
273
|
## [0.5.0] - 2026-08-21
|
|
21
274
|
|
|
22
275
|
### Security
|
|
276
|
+
|
|
23
277
|
- `sqlite3` requirement raised from `~> 1.7` to `>= 2.9.5, < 3`, excluding the
|
|
24
278
|
vulnerable releases up to and including 2.9.4. This is a runtime major bump:
|
|
25
279
|
applications pinned to `sqlite3` 1.x will need to upgrade before installing
|
|
@@ -28,6 +282,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
28
282
|
floors so a regression fails the suite rather than shipping quietly
|
|
29
283
|
|
|
30
284
|
### Changed
|
|
285
|
+
|
|
31
286
|
- `coverage_criteria` now actually affects scoring. The block was documented,
|
|
32
287
|
defaulted and validated since it was introduced, but nothing ever read it —
|
|
33
288
|
`Result` hardcoded the `MS` numerator as `killed + timeout + runtime_error`,
|
|
@@ -50,6 +305,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
50
305
|
4.0-only form), and CI runs the floor alongside 4.0.2
|
|
51
306
|
|
|
52
307
|
### Fixed
|
|
308
|
+
|
|
53
309
|
- Forked mutant children no longer outlive a parent that dies without warning.
|
|
54
310
|
Children run in their own process group, and all parent-side cleanup —
|
|
55
311
|
timeout kills, graceful drain, signal traps — only runs while the parent's
|
|
@@ -84,6 +340,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
84
340
|
0.3.1; this restores it
|
|
85
341
|
|
|
86
342
|
### Internal
|
|
343
|
+
|
|
87
344
|
- Test-suite coupling to private implementation details is now guarded by
|
|
88
345
|
`spec/infra/private_method_reach_spec.rb`, a ratchet: every spec that reaches
|
|
89
346
|
a private method through `send` or an instance-variable poke carries a
|
|
@@ -104,6 +361,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
104
361
|
## [0.4.0] - 2026-07-14
|
|
105
362
|
|
|
106
363
|
### Added
|
|
364
|
+
|
|
107
365
|
- `hard` operator set (`mutation.operators: hard` / `--operators hard`), a
|
|
108
366
|
strict superset of `full` for usually-unkillable mutations (ADR-12):
|
|
109
367
|
currently `EqualityIdentityOperator` and the new `HashKeyType`
|
|
@@ -113,6 +371,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
113
371
|
single-pair hashes and double-splat entries are skipped
|
|
114
372
|
|
|
115
373
|
### Changed
|
|
374
|
+
|
|
116
375
|
- `full` now means "usually killable": the symbol-key -> string-key mutation
|
|
117
376
|
moved from `HashLiteral` into the new hard-set `HashKeyType`, and
|
|
118
377
|
`EqualityIdentityOperator` moved from `full` to `hard` — `full` runs emit
|
|
@@ -121,6 +380,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
121
380
|
## [0.3.1] - 2026-07-13
|
|
122
381
|
|
|
123
382
|
### Fixed
|
|
383
|
+
|
|
124
384
|
- Per-mutant log capture no longer crashes with
|
|
125
385
|
`Encoding::UndefinedConversionError` when the host app sets
|
|
126
386
|
`Encoding.default_internal` (as Rails test environments do) and a child
|
|
@@ -130,6 +390,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
130
390
|
from corrupting the file.
|
|
131
391
|
|
|
132
392
|
### Changed
|
|
393
|
+
|
|
133
394
|
- `--since REF` now includes the working tree: tracked files with
|
|
134
395
|
uncommitted changes and untracked files count as changed, matching what
|
|
135
396
|
actually gets tested. Previously only committed changes in `REF..HEAD`
|
|
@@ -146,6 +407,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
146
407
|
## [0.3.0] - 2026-07-13
|
|
147
408
|
|
|
148
409
|
### Added
|
|
410
|
+
|
|
149
411
|
- `henitai run --incremental`: verdict reuse from the history store. Killed
|
|
150
412
|
verdicts are reused when the subject's source and every covering test file
|
|
151
413
|
are byte-identical to what was recorded; Survived verdicts are additionally
|
|
@@ -181,6 +443,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
181
443
|
moved out of the default light set into its own operator (ADR-10)
|
|
182
444
|
|
|
183
445
|
### Fixed
|
|
446
|
+
|
|
184
447
|
- Mutants in `module_function` modules were unkillable: `module_function`
|
|
185
448
|
copies the method onto the module's singleton and activation only replaced
|
|
186
449
|
the instance side, so callers kept running original code and every such
|
|
@@ -200,6 +463,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
200
463
|
- Flaky-retry counter no longer inflates when a respawned child fails again
|
|
201
464
|
|
|
202
465
|
### Changed
|
|
466
|
+
|
|
203
467
|
- Terminal reporter renders original nodes from their source slice and reuses
|
|
204
468
|
a memoized unparse of the mutated node shared with the JSON reporter
|
|
205
469
|
(a dogfood profile spent 27% of wall time re-unparsing survivors)
|
|
@@ -213,6 +477,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
213
477
|
redefinition warnings into their logs
|
|
214
478
|
|
|
215
479
|
### Internal
|
|
480
|
+
|
|
216
481
|
- Architecture documentation gained §8.11 (incremental verdict reuse) and
|
|
217
482
|
ADR-11 (content-fingerprint verdict reuse, not git scoping); new backlog
|
|
218
483
|
tickets for CI warm verdict cache, child null formatter, and auto-`--since`
|
|
@@ -224,12 +489,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
224
489
|
## [0.2.1] - 2026-06-25
|
|
225
490
|
|
|
226
491
|
### Fixed
|
|
492
|
+
|
|
227
493
|
- `henitai run` now exits 0 when a run evaluates no valid mutants, instead of
|
|
228
494
|
failing a CI gate on a vacuous result
|
|
229
495
|
- Flaky-retry counts are now recorded on the parallel execution path (they were
|
|
230
496
|
always reported as 0 regardless of actual retries)
|
|
231
497
|
|
|
232
498
|
### Changed
|
|
499
|
+
|
|
233
500
|
- `Result` and `Reporter::Json` take their IO as an injected dependency,
|
|
234
501
|
restoring the domain/infrastructure boundary (no public API change)
|
|
235
502
|
- Decomposed the monolithic `integration.rb` into single-responsibility files
|
|
@@ -238,6 +505,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
238
505
|
- Narrowed broad rescues in `safe_unparse` and per-test coverage snapshotting
|
|
239
506
|
|
|
240
507
|
### Internal
|
|
508
|
+
|
|
241
509
|
- De-mocked runner specs, added `process_wakeup` and helper coverage, and
|
|
242
510
|
removed sleep- and chdir-based flakiness from the suite
|
|
243
511
|
- Enabled full-operator dogfooding configuration and isolated the
|
|
@@ -247,6 +515,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
247
515
|
## [0.2.0] - 2026-04-30
|
|
248
516
|
|
|
249
517
|
### Added
|
|
518
|
+
|
|
250
519
|
- `--survivors-from <path>` flag on `henitai run` for survivor-only reruns:
|
|
251
520
|
re-execute only the mutants that survived a prior full run without re-running
|
|
252
521
|
the whole suite
|
|
@@ -281,6 +550,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
281
550
|
- x86_64 platform added to gem platform list
|
|
282
551
|
|
|
283
552
|
### Changed
|
|
553
|
+
|
|
284
554
|
- JSON mutation report vendor extension now always includes `sessionId`
|
|
285
555
|
(and `gitSha` when available) to support survivor-only reruns
|
|
286
556
|
- Terminal reporter labels partial reruns as "Partial survivor rerun" and
|
|
@@ -295,6 +565,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
295
565
|
`max_flaky_retries: 3` added
|
|
296
566
|
|
|
297
567
|
### Fixed
|
|
568
|
+
|
|
298
569
|
- Minitest autorun hook suppressed in mutation child processes to prevent
|
|
299
570
|
spurious re-runs of the full suite inside each fork
|
|
300
571
|
- Coverage bootstrap RSpec subprocess ARGV leakage resolved — child processes
|
|
@@ -307,6 +578,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
307
578
|
preventing stale cache hits after edits
|
|
308
579
|
|
|
309
580
|
### Performance
|
|
581
|
+
|
|
310
582
|
- File discovery cached in the integration layer; repeated calls within one
|
|
311
583
|
run no longer re-scan the filesystem
|
|
312
584
|
- Polling sleep removed from the scheduler hot loop; slots are refilled
|
|
@@ -315,6 +587,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
315
587
|
## [0.1.10] - 2026-04-16
|
|
316
588
|
|
|
317
589
|
### Fixed
|
|
590
|
+
|
|
318
591
|
- RuboCop `RSpec/MultipleExpectations` offenses in `coverage_formatter_spec` and
|
|
319
592
|
`per_test_coverage_collector_spec` resolved by splitting each two-assertion
|
|
320
593
|
example into focused single-expectation examples
|
|
@@ -322,6 +595,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
322
595
|
## [0.1.9] - 2026-04-16
|
|
323
596
|
|
|
324
597
|
### Fixed
|
|
598
|
+
|
|
325
599
|
- SimpleCov is now suppressed during Minitest mutant child runs: `SimpleCov.start`
|
|
326
600
|
is turned into a no-op before test files are required, eliminating the
|
|
327
601
|
"Stopped processing SimpleCov as a previous error has been detected" warning
|
|
@@ -330,12 +604,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
330
604
|
## [0.1.8] - 2026-04-16
|
|
331
605
|
|
|
332
606
|
### Added
|
|
607
|
+
|
|
333
608
|
- Minitest integration now supports per-test coverage: a `MinitestCoverageReporter`
|
|
334
609
|
snapshots `Coverage.peek_result` after each test and writes `henitai_per_test.json`,
|
|
335
610
|
enabling targeted mutation runs that only execute the tests covering the mutated lines —
|
|
336
611
|
the same efficiency that was previously available only to RSpec projects
|
|
337
612
|
|
|
338
613
|
### Fixed
|
|
614
|
+
|
|
339
615
|
- RSpec integration now respects `--exclude-pattern` entries in `.rspec` so excluded
|
|
340
616
|
spec files are not passed to the runner during mutation runs
|
|
341
617
|
- Per-test source file filter corrected to check only the project-relative path prefix
|
|
@@ -345,11 +621,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
345
621
|
## [0.1.7] - 2026-04-14
|
|
346
622
|
|
|
347
623
|
### Added
|
|
624
|
+
|
|
348
625
|
- Committed integration smoke projects for RSpec and Minitest, runnable via
|
|
349
626
|
`bundle exec rake smoke:integration:all`, to exercise `henitai` against
|
|
350
627
|
small real projects that depend on the local source checkout
|
|
351
628
|
|
|
352
629
|
### Fixed
|
|
630
|
+
|
|
353
631
|
- Child-process stdout/stderr restoration after captured test runs now keeps
|
|
354
632
|
the standard streams usable, preventing passing mutant executions from being
|
|
355
633
|
misclassified because the child exited with a closed stdio handle
|
|
@@ -360,6 +638,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
360
638
|
## [0.1.6] - 2026-04-14
|
|
361
639
|
|
|
362
640
|
### Fixed
|
|
641
|
+
|
|
363
642
|
- Minitest is no longer required eagerly when `henitai/integration` loads, so
|
|
364
643
|
projects that do not include Minitest in their bundle can still boot and use
|
|
365
644
|
non-Minitest integrations without a parent-process `LoadError`
|
|
@@ -367,6 +646,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
367
646
|
## [0.1.5] - 2026-04-14
|
|
368
647
|
|
|
369
648
|
### Fixed
|
|
649
|
+
|
|
370
650
|
- Steep type errors in `Runner` after removing targeted-run bootstrap scoping:
|
|
371
651
|
updated `bootstrap_mutants` RBS signature to match the new single-argument
|
|
372
652
|
form and removed stale signatures for `refresh_coverage_for_targeted_run`,
|
|
@@ -375,6 +655,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
375
655
|
workspace setup and report writing into helper methods
|
|
376
656
|
|
|
377
657
|
### Changed
|
|
658
|
+
|
|
378
659
|
- Targeted-run coverage bootstrap no longer scopes the initial run to the
|
|
379
660
|
subject's test files; the full suite is always used for the baseline,
|
|
380
661
|
trading a minor performance optimisation for reliability
|
|
@@ -382,6 +663,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
382
663
|
## [0.1.4] - 2026-04-14
|
|
383
664
|
|
|
384
665
|
### Fixed
|
|
666
|
+
|
|
385
667
|
- `StringLiteral` operator no longer generates no-op mutations where the
|
|
386
668
|
replacement equals the original value (e.g. the spurious `"" → ""` mutant
|
|
387
669
|
that was emitted for methods already returning an empty string literal)
|
|
@@ -397,6 +679,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
397
679
|
runner's configured reports directory
|
|
398
680
|
|
|
399
681
|
### Changed
|
|
682
|
+
|
|
400
683
|
- `ScenarioExecutionResult.build` factory method consolidates status and
|
|
401
684
|
exit-status derivation that was previously spread across `Integration`,
|
|
402
685
|
reducing the mutation surface of the value object
|
|
@@ -404,6 +687,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
404
687
|
## [0.1.3] - 2026-04-13
|
|
405
688
|
|
|
406
689
|
### Added
|
|
690
|
+
|
|
407
691
|
- Four new mutation operators: `UnaryOperator` (negates boolean and numeric
|
|
408
692
|
unary expressions), `UpdateOperator` (swaps `+=`/`-=`/`*=` and targets
|
|
409
693
|
compound-assignment nodes), `RegexMutator` (replaces regex literals with
|
|
@@ -422,6 +706,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
422
706
|
`x || false`, `true && x`, `x && true` are suppressed as equivalent mutants
|
|
423
707
|
|
|
424
708
|
### Changed
|
|
709
|
+
|
|
425
710
|
- Per-line mutation cap (`max_mutants_per_line`) removed from the generator,
|
|
426
711
|
configuration schema, and validator — see ADR-08. All syntactically valid
|
|
427
712
|
mutations on a line are now generated unconditionally
|
|
@@ -436,6 +721,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
436
721
|
without reflection
|
|
437
722
|
|
|
438
723
|
### Performance
|
|
724
|
+
|
|
439
725
|
- Coverage bootstrap freshness check: the baseline RSpec run is skipped when
|
|
440
726
|
`.resultset.json` is newer than every watched source and test file,
|
|
441
727
|
eliminating ~83 % of bootstrap wall time on repeated runs within a session
|
|
@@ -457,6 +743,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
457
743
|
AST node
|
|
458
744
|
|
|
459
745
|
### Fixed
|
|
746
|
+
|
|
460
747
|
- Mutant child processes now run in isolated process groups (`setpgid`);
|
|
461
748
|
`cleanup_process_group` sends `SIGTERM` to the entire group on timeout or
|
|
462
749
|
error, preventing orphaned subprocesses
|
|
@@ -472,10 +759,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
472
759
|
## [0.1.2] - 2026-04-07
|
|
473
760
|
|
|
474
761
|
### Added
|
|
762
|
+
|
|
475
763
|
- Method coverage is now enabled in both RSpec and Minitest bootstraps, and
|
|
476
764
|
the static filter merges method-level coverage into the line map
|
|
477
765
|
|
|
478
766
|
### Fixed
|
|
767
|
+
|
|
479
768
|
- Coverage baseline regeneration now happens on every `henitai run`, so stale
|
|
480
769
|
coverage state does not leak between runs
|
|
481
770
|
- Coverage handling now accepts symbol-keyed `Coverage.peek_result` output and
|
|
@@ -492,6 +781,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
492
781
|
## [0.1.1] - 2026-04-03
|
|
493
782
|
|
|
494
783
|
### Added
|
|
784
|
+
|
|
495
785
|
- Minitest integration for Rails projects: injects SimpleCov for coverage
|
|
496
786
|
collection, sets `RAILS_ENV=test` and `PARALLEL_WORKERS=1` in the baseline
|
|
497
787
|
subprocess, preloads `config/environment.rb` before mutant activation, adds
|
|
@@ -499,6 +789,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
499
789
|
- `simplecov` runtime dependency (required by the Minitest integration)
|
|
500
790
|
|
|
501
791
|
### Fixed
|
|
792
|
+
|
|
502
793
|
- `rspec/core` was unconditionally required at load time, causing a `LoadError`
|
|
503
794
|
in projects that do not have RSpec installed — now loaded lazily only when the
|
|
504
795
|
RSpec integration is used
|
|
@@ -508,6 +799,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
508
799
|
## [0.1.0] - 2026-03-01
|
|
509
800
|
|
|
510
801
|
### Added
|
|
802
|
+
|
|
511
803
|
- Initial gem scaffold with Ruby 4.0.2 support
|
|
512
804
|
- Dev Container configuration (official `ruby:4.0.2-alpine` base image, Codex CLI preinstalled)
|
|
513
805
|
- CI pipeline (RuboCop + RSpec + incremental mutation testing on PRs)
|
|
@@ -516,7 +808,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
516
808
|
- CLI critical path: `henitai run` now executes the full pipeline, supports `--since`, returns CI-friendly exit codes, and `henitai version` prints `Henitai::VERSION`
|
|
517
809
|
- RSpec per-test coverage output: `henitai/coverage_formatter` now writes `coverage/henitai_per_test.json`
|
|
518
810
|
|
|
519
|
-
[Unreleased]: https://github.com/martinotten/henitai/compare/v0.
|
|
811
|
+
[Unreleased]: https://github.com/martinotten/henitai/compare/v0.6.0...HEAD
|
|
812
|
+
[0.6.0]: https://github.com/martinotten/henitai/compare/v0.5.3...v0.6.0
|
|
813
|
+
[0.5.3]: https://github.com/martinotten/henitai/compare/v0.5.2...v0.5.3
|
|
814
|
+
[0.5.2]: https://github.com/martinotten/henitai/compare/v0.5.1...v0.5.2
|
|
520
815
|
[0.5.1]: https://github.com/martinotten/henitai/compare/v0.5.0...v0.5.1
|
|
521
816
|
[0.5.0]: https://github.com/martinotten/henitai/compare/v0.4.0...v0.5.0
|
|
522
817
|
[0.4.0]: https://github.com/martinotten/henitai/compare/v0.3.1...v0.4.0
|