Repository navigation
Two commands that could answer "everything is fine" when they did not know now say so. Both
were found by using conclave on its own issues; neither changes what a healthy run does.
conclave mutations no longer calls a tree clean when it cannot read its own bookkeeping
A marker file that does not parse — truncated by a crash, half-written, edited by hand — used to
be skipped silently. The listing then printed:
no mutations are recorded
That is not an omission, it is a claim, from the one command whose job is to answer the
question. And conclave relay/session's pre-run check is built on the same reader, so the
"a file is deliberately mutated and was never restored" warning did not fire either. A run
could start on a tree holding an unrestored mutation with both the listing and the guard calling
it clean — the state that nearly committed a reverted fix in #180.
Unreadable markers are now counted and named, by both:
1 mutation marker could not be read; the file it guards may be mutated:
.conclave/mutations/d9053dd1040a5e70.json — Expected property name or '}' in JSON at position 2
Still a warning, still never a refusal. Bad bookkeeping must not become the outage — that
part was right and is unchanged. What changed is that skipping is no longer silence. Valid JSON
that is not a marker (null, a number, an array) counts as unreadable too, rather than being
dropped.
Known, and deliberately left for a decision: the bare listing still exits 0 for a tree
whose only marker is unreadable, the same code as a genuinely clean tree, even though the text
says the guarded file may be mutated. A commit helper gating on the exit code reads that as
clean. Tracked as #395.
mutations begin refuses to overwrite an orphaned original
0.5.71 made begin refuse when a marker already exists. It still overwrote the .orig when the
marker was gone and the backup was not — someone tidying .conclave/mutations, or a crash
between the two writes. That backup is the only surviving copy of the original, and it was
replaced in silence with an exit 0 and a recorded … line.
Refused now, naming both files and leaving each untouched. Adopting the orphan instead was
considered and rejected, which is the part worth knowing: nothing records where an orphaned
.orig came from. It may be the true original, or a mutant left by an earlier version of this
bug, and its own hash is no evidence either way. Rebuilding a marker around it would authorise
restore to overwrite your working file with bytes merely assumed to be original, and report
that as a verified restore. Only a person can tell, so both files are left alone.
An unreadable kimi config no longer prints a Python traceback over your console
readKimiConfig shells out to python3 for TOML. The child's stderr was inherited, so a
malformed config wrote Python's full traceback straight to conclave's stderr — and the thrown
message embedded it a second time, because execFileSync's own message carries the whole
stream. The guidance an operator needed was separated from the filename by a twelve-line stack,
then repeated.
Now: nothing on stderr, and one line for the reason.
kimi: could not read ~/.kimi/config.toml as TOML (TOMLDecodeError: Expected '=' after a key in
a key/value pair (at line 1, column 6)) — it is the config the kimi seat runs with, which
Conclave copies to add its hooks. If the reason is in the file, fix the TOML in it. …
The .json branch had no wrapper at all and threw a bare SyntaxError naming neither the file
nor a remedy. Both formats now fail in one shape, so you cannot tell which branch failed from
how well the message is written.
Two things found while doing it:
- A TOML
infornanused to fail late and anonymously. Left to its default, Python's
json.dumpwritesInfinity, exits 0, and the failure surfaced afterwards in Node's JSON
parse with nothing to say which key caused it. It is now reported where it happens, naming the
value. - "The last line is the exception" is not true of Python. PEP 678 notes print after it, and
json.dumpattaches one per unserialisable value. The reader no longer parses a traceback's
shape; the script reports its own failure as one line, and keeps the notes after the reason
because they name the key.