Repository navigation
Description
id: a torn final line in petnames.jsonl bricks the whole world — Petnames::open refuses a crash-torn tail that FileJournal and Outbox both drop and truncate
Summary
Petnames::open (pkgs/id/src/petname.rs:56-70) replays petnames.jsonl with text.lines() and fails the entire open on any malformed line — including a torn final line left by a crash mid-append. Petnames::commit (petname.rs:186-199) appends one JSON line + sync_data() per change, so a crash or power loss during write_all leaves exactly that: a partial JSON record with no trailing newline at the tail of the file.
That failure is not contained to petnames. open_world (pkgs/id/src/world_store.rs:389-392) propagates it with ??, so the whole world fails to open — on every restart, forever, until someone hand-edits the journal. There is no recovery path: appends can't happen because open never succeeds.
The two sibling JSONL stores loaded by the same open_world already handle this exact case, deliberately:
- FileJournal (
world_store.rs:52-117): "A torn final line, left by a crash mid-append, is truncated away" — unterminated last line is dropped, the file is truncated to the last good byte, and mid-file corruption is still refused. Test:torn_final_entry_is_dropped_but_mid_file_corruption_is_refused(world_store.rs:1044). - Outbox (
envelope_outbox.rs:141-161): iteratessplit_inclusive('\n'); an unparseable line that does not end with'\n'ends the replay, and the file is truncated to the kept prefix. Test:a_torn_last_line_is_dropped_and_not_mixed_into_the_next_record(envelope_outbox.rs:523).
Petnames (and Directory::replay, directory.rs:517-535 — same strict lines() + ? shape, also propagated by open_world at world_store.rs:385-387) never got the same treatment.
Evidence (verified this run, main 67e0def)
Probe crate on the laptop (~/git/fleet/probe-2026-10-27-laneB-petname) compiling the real petname.rs (sha256 ff6cba651a19ad5814a2540df12433d1444b44ff5fb258a8478cb891be88723e, identical to the checkout) against a stub directory::Refusal:
- Control — clean journal (two records written through
Petnames::setitself): open OK, both names replay. - Torn tail — the same bytes plus a partial record
{"op":"set","owner":"00ff","account":"cc33","name":"Car(no trailing newline):open FAILED: petname journal line 3 is malformed: EOF while parsing a string at line 1 column 55. - Control — malformed line in the middle (newline-terminated, valid record after it): open FAILED, as it should — mid-file corruption must stay refused.
Log: goal bookkeeping hidden_files/probe-2026-10-27-laneB-petname/out.log.
Why it matters
Petnames are a small, private, append-only store; losing the ability to open them should never take down an entire world. Today one unlucky crash during a rename makes the world permanently unopenable without manual file surgery — while the world's main journal and its outbox, loaded seconds earlier in the same function, already survive the identical failure by design.
Fix direction
Bring Petnames::open in line with the house pattern (Outbox is the closest model — same one-record-per-line JSONL, same append commit):
- Replay with
split_inclusive('\n'); a final line that is unterminated and unparseable is a torn append: drop it and truncate the file to the kept prefix (so the next append is not glued onto the partial record — the failure the Outbox test name calls out). - Any other malformed line (terminated, or mid-file) stays a hard error, exactly as today.
- Consider the same treatment for
Directory::replayin the same pass — it is the other strict replay on theopen_worldpath; if it is deliberately out of scope, say so on the issue.
Acceptance criteria
- A
petnames.jsonlwhose final line is a partial JSON record (no trailing newline) opens successfully with all complete records replayed; the torn bytes are truncated from the file. - After such a recovery, a subsequent
set/removeappends a clean record that replays correctly on the next open (no gluing onto the torn bytes). - A malformed line anywhere else (newline-terminated, or followed by more records) still fails the open with the line-numbered error.
- The existing test
a_malformed_line_fails_the_openis updated/narrowed to the mid-file case, and a new test mirrorstorn_final_entry_is_dropped_but_mid_file_corruption_is_refusedfor petnames. -
cargo testfor the petname module passes; behaviour of clean journals is unchanged.
Activity
developing-today commentedon Oct 27, 2026
CODE-564
dezren39 commentedon Oct 27, 2026
🤖 Agent note · filed
53 remaining items
dezren39 commentedon Oct 31, 2026
Agent note — parked (main tier still running; red legs re-verified as pre-existing)
full (main tier): nix flake checkstill in progress (~1h). Red basic legs are the known pre-existing set.cargo fmt --checkover pkgs/id on the PR worktree reports diffs in many files the PR never touched (peers.rs, tag.rs, event_store/sync.rs, groups/tests.rs, web/mod.rs, world_ssh.rs, world_store.rs, tests/*) and none attributable to petname.rs — the fmt-check failures are repo-wide pre-existing debt (rustfmt drift), not branch-owned. test-web-unit red matches the search-panel failure verified failing on clean main this shift.cargo test --lib petnameverification was started but did not finish within the shift window (pkgs/id compiles are slow under fleet load); the petname tests themselves pass in CI test shards 0-3.dezren39 commentedon Oct 31, 2026
Agent note — pickup (resume, merge shift)
Merge pull request #2918 from developing-today/queue/1763-1499-petnam…
dezren39 commentedon Oct 31, 2026
Agent note — done (merged)
fix(id/petname): drop a parseable torn final line in Petnames::open (#…
fix(id/petname): drop a parseable torn final line in Petnames::open (#…