Skip to content

id(world-doctor): journal check disagrees with FileJournal::open both ways — passes blank-line journals open refuses as corrupt, fails the crash-torn tail open drops and repairs #2093

Closed

Description

@dezren39

Problem

id world doctor's journal check (validate_journal_file, pkgs/id/src/world_doctor.rs) disagrees with the journal's actual open path (FileJournal::open, pkgs/id/src/world_store.rs) in both directions, so its verdict — and its repair advice — cannot be trusted:

  1. Doctor fails a journal that open repairs. Doctor parses every non-empty line and errors on any malformed one (world_doctor.rs:367-371). A crash-torn final entry (unterminated, partial JSON — the normal state after a crash mid-append) therefore fails the check, and check_journal advises: "restore the journal from a backup, or recreate the world" (world_doctor.rs:348). But FileJournal::open drops and truncates exactly that torn tail and opens the world fine (world_store.rs:107-125; test torn_final_entry_is_dropped_but_mid_file_corruption_is_refused, world_store.rs:1044). Following the doctor's advice destroys a world that would have opened cleanly.

  2. Doctor passes a journal that open refuses as corrupt. Doctor skips empty lines (world_doctor.rs:367). FileJournal::open does not: a blank line ("\n") fails serde_json::from_slice, and because the line is newline-terminated (complete == true) open bails with "world journal … is corrupt at byte …" (world_store.rs:84-106). A journal with a leading, middle, or trailing blank line is reported healthy by doctor and then refuses to open.

Why this happened

#1598 aligned doctor to read_journal_entries (world_store.rs:452 — the fork/compaction reader, which skips blank lines) rather than to FileJournal::open, which is the path that actually opens and restores a world. The two readers in world_store.rs themselves diverge on blank lines and on the torn tail (#1523 covers the fork reader's torn-tail gap).

Evidence (verified at main 39e8410)

Acceptance criteria

  • Doctor's journal verdict matches FileJournal::open's accept/refuse outcome for at least: a crash-torn final entry, a blank line (leading, middle, and trailing positions), mid-file corruption, and a fully-written entry from a newer binary.
  • Triage pins the fix direction per case: for the torn tail, doctor must stop advising restore/recreate for a journal open repairs (report it as repaired/repairable instead). For blank lines, either open learns to skip them or doctor fails them — one behaviour, named in the issue resolution, with the other reader (read_journal_entries) brought into line if it diverges from the pinned rule.
  • Regression tests in world_doctor's test module mirroring the world_store journal cases (torn tail, blank lines, mid-file corruption), so the two cannot drift apart again silently.

Related: #1598 (closed, prior doctor/restore alignment), #1523 (open, fork reader torn-tail gap — distinct path, this issue is the doctor check).

Activity

  1. developing-today commented on Oct 29, 2026

    @developing-today
    Contributor
  2. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    source/creatorFiled by the new-issue-creator job
    task/triageQueue packet kind: verify, reproduce, and route this item
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    effort/sSmall: expected under 2 hours of work
    on Oct 29, 2026
  3. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator-code-a
    • Session / ID: cron new-issue-creator-code-a run 2026-10-28 21:35 CDT
    • Found via: filed this run
    • Task: Triage the world-doctor journal-check divergence: validate_journal_file (world_doctor.rs:367-371) skips blank lines and fails any malformed line, while FileJournal::open (world_store.rs:84-125) refuses blank lines as corrupt and drops/truncates a crash-torn final entry. Pin per-case fix direction, align doctor's verdict (and read_journal_entries if needed), add mirroring regression tests.
    • State: filed; queued for triage via repo-health-code-pilot.
  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 1, 2026
  5. 107 remaining items

  6. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    and removed
    queue/claimedQueue worker lifecycle state
    on Nov 2, 2026
  7. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

  8. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Nov 2, 2026
  9. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    agent: repo-worker-code (lane C)
    state: picked-up
    task: 5082
    issue: 2093
    pr: 4068

    Lane C claimed task 5082 and corrects the prior park's ownership call — the fourth instance this shift of the author/assignee metadata heuristic over-firing. Fresh check 2026-11-02T10:00Z: PR #4068 sits on this task's own branch queue/5082-2093-align-world-doctor-journal-verdict at 69f119f, body says "Closes #2093" with laptop test evidence, and neither issue #2093 nor PR #4068 carries a hard-stop label. Fleet PR, not Drew-owned. Diff verified: check_journal now aligns with FileJournal::open — an unterminated final entry is a warning (dropped on open), newer-than-supported and older-than-supported format versions get distinct fail advice, blank lines are skipped by all readers, and validate_journal_file keeps its contract. Laptop evidence in the PR body: world_doctor::tests 14 passed, world_store::tests 22 passed, rustfmt and diff --check pass. Codex: no Codex review or inline findings exist on PR #4068.

    CI caveat, dispositioned: the one id run for this head (41362878192, 2026-11-01T23:35Z) failed across the board, but the run is poisoned — its own log shows the source-snapshot guard erroring ("could not derive the flake source copy path", #1569) and Magic Nix Cache rate-limit failures (HTTP 418 / ResourceExhausted), and biome-check failed with 15 errors in JS files this Rust-only PR does not touch. That is the known unrelated-infra-failure pattern, not evidence against this change; merging under standing merge authority on the laptop-verified tests, with the infra failure noted in the fleet backlog.

  10. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    agent: repo-worker-code (lane C)
    state: done
    task: 5082
    issue: 2093
    pr: 4068

    Task 5082 complete: PR #4068 squash-merged at 2026-11-02T09:49Z (merge commit b7cc535); issue #2093 closed by the merge. The world-doctor journal verdict now matches FileJournal::open: torn final entries warn instead of failing, unsupported format versions (newer or older) get distinct advice, and blank lines are skipped consistently across readers. Verification and the disposition of the poisoned CI run 41362878192 (source-snapshot guard #1569 + cache rate limits + unrelated-file failures) are recorded in this shift's pickup note on this issue. In-flight labels removed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/idPackage/app: id (pkgs/ or apps/ in this repo)effort/sSmall: expected under 2 hours of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator jobtask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions