Skip to content

v0.5.71

Choose a tag to compare

@github-actions github-actions released this 26 Oct 01:39
· 6 commits to main since this release

If you mutation-test with conclave mutations, install this one. 0.5.70 and every release
before it could destroy the baseline a mutation test depends on, and then report success.

mutations begin no longer eats the original it was keeping

begin copied the file to its backup and wrote the marker unconditionally. A second begin on
a path that already had an outstanding marker therefore replaced the stored original with
whatever was on disk — the previous mutant. The sequence is the ordinary one:

conclave mutations begin src/thing.ts   # records the true original
# ...mutate, run the test, put it back by hand...
conclave mutations begin src/thing.ts   # for the next mutant — and here the baseline is lost

Nothing said so. Both calls exited 0 and printed the same reassuring line.

The part that made it expensive was the reporting, not the lost file. restore then printed
both "restored <path> from its stored original" and "<path> is back to its original;
marker cleared", while writing the mutant back — and cleared the marker, removing the last trace
that anything had been mutated. 0.5.63's fix (#363) made restore verify its copy and keep the
marker on a mismatch; that check could not fire here, because the copy it verifies against was
the mutant. The verification and the thing verified shared the corruption, so their agreement
meant nothing.

begin on a path that already has a marker is now refused, non-zero, naming what is on
record so you can choose a remedy:

conclave: probe.ts already has an outstanding marker — not recorded again
  marker .conclave/mutations/e2886bb7c0bb267d.json, stored original .conclave/mutations/e2886bb7c0bb267d.orig
  original sha256 be72a416e3fb..., begun 2026-10-25T23:42:20.757Z
  if you have already put the original back: `conclave mutations end probe.ts`
  otherwise: `conclave mutations restore probe.ts`, then begin again

Unchanged, deliberately: a begin on a different path while one is outstanding still works —
that is the multi-file mutation session this tool exists for. Naming a stale marker is refused
too, because end clears it in one step.

There is no --force. Destroying the only baseline is never what the operator meant, and an
escape hatch here would be the defect with a flag in front of it.

The fix contained a smaller copy of the same bug, and CodeQL found it

Worth recording, because the shape keeps recurring. The first version guarded with
existsSync(marker) and wrote the marker further down, with the backup copy between them —
check-then-act. Two begin calls racing on one path would both pass the check, and the loser
would have overwritten the .orig before the marker write told it to stop. The same defect, one
layer down, inside its own fix.

The marker is now claimed atomically (wx) and claimed before anything is copied, so exactly
one caller reaches the copy. A crash between the claim and the copy leaves a marker with no
stored original, which restore already reports as its own answer rather than as a restore.

Nothing else changed in this release.