Skip to content

id(artifact): a blank line in the artifact journal bricks Directory::open — ArtifactLog refuses blank lines its sibling loader skips, and truncates torn tails silently #2128

Closed

Description

@dezren39

id(artifact): a blank line in artifacts.jsonl bricks Directory::open — and its torn-tail truncation is silent

Summary

ArtifactLog::open (pkgs/id/src/artifact.rs:573-593, main 0f5b4cbb) parses
every line of the artifact journal strictly. A single blank line — in the
middle, as a trailing extra newline (...\n\n), or as the file's only
content — fails the whole open with artifact line N is corrupt, even though
every artifact in the file is intact. ArtifactLog is loaded by
Directory::open (pkgs/id/src/directory.rs:473), so the failure takes the
whole directory down with it.

The sibling journal loaded in the very same Directory::open treats blank
lines differently: Directory::replay explicitly skips them
(directory.rs:535-537: if line.trim().is_empty() { continue; }).

Second divergence in the same function: when open drops a crash-torn final
line it truncates the file with no log line at all (artifact.rs:578-584).
Both sibling loaders warn with the byte offset when they do exactly this —
Directory::replay at directory.rs:525-528 ("dropping torn final entry at
byte {kept_len}") and FileJournal::open at world_store.rs:116-119. A torn
artifact tail therefore loses a signed artifact (e.g. a friend-removal record
replayed at directory.rs:475-490) with no trace anywhere.

Evidence (verified this run)

Laptop probe ~/git/fleet/probe-2026-10-29-artifactlog/ — the open loop
copied verbatim from artifact.rs (main 0f5b4cbb), artifacts as minimal
JSON objects, run 2026-10-29:

case ArtifactLog::open directory-style parse
two valid lines (control) Ok, 2 stored Ok, 2
valid, blank, valid Err "artifact line 2 is corrupt: EOF while parsing a value" Ok, 2
valid, valid, blank (\n\n ending) Err "artifact line 3 is corrupt" Ok, 2
file is only "\n" Err "artifact line 1 is corrupt" Ok, 0
valid + torn tail (no trailing \n) Ok, 1 — file truncated, no warning emitted by the code path —

Blank lines reach this file in ordinary ways: a hand edit, an editor that
adds a final newline, a restore/sync that appends one. Nothing in the append
path (artifact.rs:601-608, one line + \n per write) ever needs a blank
line to be fatal.

Why it matters

  • Availability: one stray newline makes Directory::open fail, which is on
    the world-open path (world_store.rs open_world loads the directory) —
    the directory is down until someone hand-repairs the file, despite zero
    corrupt artifacts.
  • Observability: the silent truncation is the only one of the three JSONL
    loaders in this crate that drops data without a warning, so a lost
    artifact leaves nothing to investigate.

Acceptance criteria

  • ArtifactLog::open skips blank/whitespace-only lines the way
    Directory::replay does; a file with blank lines in any position
    (including a \n\n ending and a blank-only file) opens with all its
    artifacts intact.
  • The torn-tail truncation in ArtifactLog::open emits a warning naming
    the file and the byte offset, matching the Directory::replay /
    FileJournal::open wording.
  • A genuinely corrupt non-blank line still fails the open with the
    existing artifact line N is corrupt context.
  • Regression tests cover: blank middle, blank final, blank-only, torn
    tail (opens, truncates, warns), and corrupt-line refusal.

Dedup

Searched open + closed issues for "ArtifactLog", "artifact blank line" and
"torn": #1521 (closed) fixed the same class for Directory::replay and notes
ArtifactLog is "loaded in the same open", but covered only the torn tail of
the directory journal, not the artifact log's blank-line refusal or its
silent truncation. #1499/#1522/#1523/#1544/#1620 are the petname, group,
world-fork, records and outbox loaders respectively — none touches
artifact.rs.

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/lowNice to have; do when convenient
    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/xsTrivial: expected under 30 minutes of work
    on Oct 29, 2026
  3. dezren39 commented on Oct 29, 2026

    @dezren39
    MemberAuthor

    Filed this run by the issue creator (lane A) after verification on current main.

    What: ArtifactLog::open (artifact.rs:573-593) refuses any blank line in the artifact journal — the whole open fails, and Directory::open (directory.rs:473) loads it in the same open, so one stray newline takes the directory down with every artifact intact. Its torn-tail truncation is also the crate's only silent one (both sibling loaders warn with the byte offset).

    Evidence: laptop probe ~/git/fleet/probe-2026-10-29-artifactlog/ (open loop verbatim, main 0f5b4cbb): control Ok(2); blank-middle Err line 2; blank-final Err line 3; blank-only Err line 1; torn tail Ok(1) + silent truncate; directory-style parse Ok on all blank cases. Full table in the issue body.

    State: labelled queue/queued + task/triage; a repo-task/v1 triage packet is enqueued on repo-health-code-pilot for the worker. Not self-solved: the fix shape (skip blanks + warn, matching the siblings) is triage's pin.

    Found via: filed this run

  4. added
    work/assignedQueue worker lifecycle state
    queue/claimedQueue worker lifecycle state
    and removed on Nov 1, 2026
  5. 15 remaining items

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

    @dezren39
    MemberAuthor

    🤖 Agent note · done — fixed and merged

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/xsTrivial: expected under 30 minutes of workkind/bugSomething isn't working (prefixed form of the classic bug label)priority/lowNice to have; do when convenientsource/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