Skip to content

id(groups): a torn final line in groups.jsonl bricks every group command — GroupLog::open refuses the crash-torn tail that FileJournal and Outbox drop and truncate #1522

Closed

Description

@dezren39

Problem

A crash-torn final line in groups.jsonl bricks every group command: GroupLog::open refuses the unterminated partial event 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/groups/log.rs:137-150 — GroupLog::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/groups/log.rs:48-71 — GroupLog::open collects text.lines() through serde_json::from_str(...)? for every non-empty line. lines() yields the unterminated final fragment as a line, so one torn append fails the whole open with line N is not an event. There is no torn-tail special case: no missing-final-newline check, no truncation/repair.
  • pkgs/id/src/commands/group.rs:200,361,395 — every group command (cmd_group and helpers) starts with GroupLog::open(&log_path(path))?, so one torn append makes all group operations fail the same way until someone hand-edits groups.jsonl.
  • 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 the last complete line; a newline-terminated unparseable line is corruption and still fails.
    • pkgs/id/src/envelope_outbox.rs:143-165 (Outbox::open): unterminated failing final line is dropped and the file truncated via set_len(kept); a complete corrupt line still errors.
    • pkgs/id/src/artifact.rs:575-600 and pkgs/id/src/directory_log.rs:196-235: same drop-the-torn-tail treatment.
  • Existing test test_a_line_that_is_not_an_event_is_an_error (groups/log.rs:386-392) writes "not json\n" — a complete, newline-terminated line — and correctly asserts an error. No test covers an unterminated final fragment, which is the distinct torn case the sibling stores forgive.
  • 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); the directory journal instance is filed separately as 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. No open or recently-closed issue mentions GroupLog / groups.jsonl torn tails.

Why it matters

Groups are a user-facing feature whose entire local history lives in this one append-only log. 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 group log, while the envelope outbox written by the same binary already survives the same crash.

Acceptance criteria

  • GroupLog::open on a log whose final line is an unterminated truncated fragment loads all complete events, drops the fragment, and truncates the file to the last complete line (mirroring FileJournal::open / Outbox::open semantics, including a warning log).
  • A newline-terminated line that does not parse, anywhere including the last line, still fails — the existing test_a_line_that_is_not_an_event_is_an_error test keeps passing unchanged.
  • New tests cover: torn final fragment (loads + file truncated), torn fragment after valid events (earlier events intact and projection() still folds).
  • No change to the event format, the fold, or append behaviour.

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/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 27, 2026
  2. developing-today commented on Oct 27, 2026

    @developing-today
    Contributor
  3. added
    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

  5. added
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 28, 2026
  6. 5 remaining items

  7. added
    queue/queuedHas a queued task in the Supabase agent queue
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    and removed
    task/triageQueue packet kind: verify, reproduce, and route this item
    queue/queuedHas a queued task in the Supabase agent queue
    on Oct 28, 2026
  8. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  9. dezren39 commented on Oct 31, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

  10. removed
    task/small-fixQueue packet kind: bounded fix with reproduction and targeted tests
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    on Oct 31, 2026
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/normalOrdinary priority (the default)source/creatorFiled by the new-issue-creator job

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions