Skip to content

id(directory): a torn final line in directory.jsonl bricks the directory — Directory::replay refuses the crash-torn tail that ArtifactLog (loaded in the same open) drops and truncates #1521

Closed

Description

@dezren39

Problem

A crash-torn final line in the directory journal bricks the directory permanently: Directory::open / Directory::replay refuse the unterminated partial entry that a crash mid-append leaves behind, instead of dropping and truncating it the way the sibling JSONL stores in this codebase do.

Evidence (verified this run on main 279c973, code reading)

  • pkgs/id/src/directory.rs:527-543 — Directory::append writes one JSON line + \n with a single write_all followed by sync_data. A crash/power loss during that write leaves a final line that is a truncated JSON fragment with no terminating newline.
  • pkgs/id/src/directory.rs:505-525 — Directory::replay iterates text.lines() (which yields the unterminated final fragment as a line) and propagates any parse failure with ? at :516-517 (directory journal line N is malformed). There is no torn-tail special case: no check for a missing final newline, no truncation/repair.
  • pkgs/id/src/directory.rs:471-473 — Directory::open (the production load path) is Self::replay(path)? first, so one torn append makes every subsequent open fail the same way; the directory never recovers without manual file surgery.
  • Contrast — the established house semantics in the same codebase:
    • pkgs/id/src/world_store.rs:85-130 (FileJournal::open): an unterminated last line is a torn append — dropped, file truncated to good_len, with a comment explaining that a newline-terminated unparseable line is corruption and must still fail.
    • pkgs/id/src/artifact.rs:575-600 (ArtifactLog::open — the very log Directory::open loads immediately after the journal): drops and truncates a final line cut short by a crash.
    • pkgs/id/src/envelope_outbox.rs:143-165 and pkgs/id/src/directory_log.rs:196-235: same drop-the-torn-tail treatment.
  • Existing test replay_rebuilds_the_directory_and_refuses_a_broken_journal (directory.rs:2601) covers an apply-refused complete entry, not a torn tail; no test covers an unterminated final fragment.
  • Dedup: id: a torn final line in petnames.jsonl bricks the whole world — Petnames::open refuses the crash-torn tail that FileJournal and Outbox drop and truncate #1499 (open) is the same defect class in Petnames::open only (pkgs/id/src/petname.rs); it names FileJournal and Outbox as the good examples and does not cover the directory journal. No open or recently-closed issue mentions the directory journal / Directory::replay torn tail.

Why it matters

The directory journal is the durable record of accounts, friendships and group membership for the directory service. Its own append path can produce exactly the torn tail its load path refuses — so a single ill-timed crash converts a recoverable restart into a permanently unopenable directory, while the artifact log sitting next to it (loaded in the same open) already survives the same crash.

Acceptance criteria

  • Directory::replay/open on a journal whose final line is an unterminated truncated fragment loads all complete entries, drops the fragment, and truncates the file to the last complete line (mirroring FileJournal::open / ArtifactLog::open semantics, including a warning log).
  • A newline-terminated line that does not parse, anywhere including the last line, still fails with the existing directory journal line N is malformed error — corruption is never silently dropped.
  • A complete entry that apply refuses still fails replay (existing test at directory.rs:2601 keeps passing).
  • New tests cover: torn final fragment (loads + file truncated), complete-but-corrupt final line (errors), torn fragment after valid entries (earlier entries intact).

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/triageQueue packet kind: verify, reproduce, and route this item
    source/creatorFiled by the new-issue-creator job
    priority/highImportant and time-sensitive
    on Oct 27, 2026
  2. developing-today commented on Oct 27, 2026

    @developing-today
    Contributor
  3. added
    queue/queuedHas a queued task in the Supabase agent queue
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    on Oct 27, 2026
  4. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job (lane A, slug new-issue-creator-code-a)
    • Session / ID: cron job new-issue-creator-code-a, run 2026-10-27 15:05 CDT
    • Found via: filed this run
    • Task: Filed after verifying on main 279c973 that Directory::replay (pkgs/id/src/directory.rs:505-525) propagates a parse error on an unterminated final fragment with no torn-tail handling, while Directory::append (:527-543) can produce exactly that fragment on a crash mid-write_all, and ArtifactLog::open (artifact.rs:575-600, loaded in the same Directory::open) plus FileJournal::open already drop-and-truncate torn tails. Enqueued as a triage packet to repo-health-code-pilot.
    • Expectation: triage (effort s) confirms and routes the fix: drop+truncate an unterminated final fragment in replay, keep failing on newline-terminated corrupt lines, add the three torn/corrupt tests from the acceptance criteria.
    • Links: packet hidden_files/packet-1521.json · related id: a torn final line in petnames.jsonl bricks the whole world — Petnames::open refuses the crash-torn tail that FileJournal and Outbox drop and truncate #1499 (same defect class, petnames store only)
  5. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 28, 2026
  6. 114 remaining items

  7. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    agent-note:v1 — parked

  8. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  9. added
    queue/claimedQueue worker lifecycle state
    and removed
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    on Oct 28, 2026
  10. added a commit that references this issue on Oct 28, 2026
  11. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

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)kind/bugSomething isn't working (prefixed form of the classic bug label)priority/highImportant and time-sensitivesource/creatorFiled by the new-issue-creator jobstatus:donetask/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