The events of mix mutare --events FILE: one JSON object per line, appended as the run goes,
so a consumer can follow a run with tail -f and filter it a line at a time
(jq -c 'select(.status == "survived")'). The JSON report is the complete record of a
finished run; this is the record of one in progress.
Every event has an event name and elapsed_ms, the milliseconds since the run started.
In order:
start— the run has started, and its scan with it.versionis this format's version (1),mutarethe Mutare version.scanned— the scan is done:mutantswill be tested, fromfilesfiles.phase— the run enteredphase:compiling,baseline,coverage_probe,running(withmutants, the number it will test),confirming_timeouts(withmutants, the number of provisional timeouts to re-run one at a time), and, under--partition-env,checking_partitions(withpartitions, the number whose environment it re-runs one kill's tests in with no mutant active).mutant— one mutant's verdict, written once the run accepts it. The run tests several mutants at once but accepts their verdicts in source order, so a slow mutant holds back the lines of mutants after it that have already finished: a quiet file does not mean no mutant has finished. A provisional timeout is re-run alone after the others (confirming_timeouts), so its line comes at the end. Fields:evaluated— how manymutantlines the file holds, this one included: against thescannedcount, how far the run has got;id— the report id, an integer: the JSON report'sid, which that report writes as a string;file,line,column— where the mutant is: the location the human report prints,--lineselects by, and# mutare:ignorereads;mutator,variant— the family, and the variant labels its# mutare:ignore[family:label]filters match (a list, empty when the family declares none);status— one ofkilled,timeout,atom_exhausted,survived,no_coverage,ignored,poisoned,harness_error;range,original,replacement— the patch:originalis the source text betweenrange.startandrange.end(1-based,endexclusive), andreplacementthe text that takes its place, exactly as the human report's diff applies it. A replacement may cover more than it changes: removing a pipe stage rewrites the whole pipe, whilelineandcolumnpoint at the stage. A column, here and incolumn, counts graphemes, as Elixir's columns do — not bytes, code points or UTF-16 units — so on a line with non-ASCII text, slice by graphemes or findoriginalon the line;duration_ms,selection— how long the mutant's test run took, and which tests it ran (tests,files,apporsuite); absent for a mutant that launched no run (oneno_coverage,ignoredorpoisoned);note,reason— an advisory note from the mutator, and why a mutant was ignored or why its run reached no verdict; each absent when there is none.
finish— the last line, written once the reports are.stoppedsays why:complete,max_survivors,time_budget,sigterm, orerror. All buterrorcarrymutants(the number the run set out to test;nullif a SIGTERM stopped the scan),evaluated,counts(every status, zeros included) andscore, over the mutants evaluated. Anerrorcarrieserror, the reason's name (baseline_failed,compile_failed, …, andabortedfor an abort with no reason of its own, such as a bad# mutare:ignorequalifier or--strict-ignores), andmessage, the textmix mutareprints. Anerrorwrites no final report, so a report file holds what it held before: an earlier run's report, or, when the error came after mutants had run (too_many_harness_errors), possibly this run's last checkpoint, with the mutants it had not testedPending. A SIGTERM that arrives while the final reports are being written stops the writes: each report is then either its final version or the last checkpoint, which may hold fewer verdicts than thefinishcounts.
A file that ends without a finish belongs to a run that is still going or died without
stopping cleanly — a SIGKILL or a crash; its stderr says which.
Object keys are not in a fixed order, and a later version may add fields and events: a
consumer ignores the ones it does not know. A change that would mislead such a consumer
bumps version.