Skip to content

id(currency_poc): one corrupt or foreign .json file in the FileIntentStore directory aborts recovery for every pending conversion #4125

Closed

Description

@dezren39

Problem

FileIntentStore::unresolved() (pkgs/id/src/currency_poc/intent.rs:165-181) aborts on the first file it cannot read or parse:

let bytes = fs::read(&path)?;
let record: IntentRecord = serde_json::from_slice(&bytes)
    .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))?;

and recovery::reconcile propagates that error before reconciling anything (recovery.rs:54, store.unresolved().context("listing unresolved intents")?). One stray file in the intent directory — a truncated or hand-edited record, a file written by an older/newer record schema, any unrelated *.json file someone dropped in the directory, or a subdirectory named *.json (fs::read fails on it) — therefore blocks recovery of every pending conversion, indefinitely, with a single opaque listing error. The scanner's own design already rejects this failure mode for resubmissions ("One rejected resubmission must not abort recovery of every later record", recovery.rs) but not for the listing step that gates the whole scan.

Note the store's writes are atomic (tmp + rename + fsync, intent.rs put), so this is not about torn writes from this implementation — it is about the directory being a long-lived recovery surface that must survive schema evolution, operator handling, and foreign files.

Evidence (verified this run, laptop probe, main caacf3a)

Probe crate with verbatim copies of the currency_poc modules (md5 intent.rs 4b413d6505f423428eabe27ba5e0b753, recovery.rs f4885f69754643cb92e946aaf33ff758, matching main caacf3a):

  • Control directory (one valid Recorded intent, conversion 777): reconcile(Resubmit) returns [(777, Resubmitted)], 3 legs posted.
  • Same valid record plus one file deadbeef.json containing {not json: unresolved() returns Err("data did not match any variant of untagged enum AdjacentValue @ line 1 column 12.."), reconcile returns the same error, 0 legs posted, and the valid record is still Recorded — total recovery blockage from one bad file.

Why it matters

The recovery scanner is the component that runs precisely when something has already gone wrong (a crash mid-conversion, #2289). A design where one damaged record silently freezes reconciliation of all the healthy ones turns a single-record incident into a full stop, and the operator gets no list of what was skipped — the valid records are not even reported.

Acceptance criteria

  • reconcile processes every readable unresolved record even when other files in the store directory are unreadable or unparseable; the bad entries are surfaced (returned in the outcome list under a distinct outcome, logged, or collected into the error report) rather than silently dropped or fatal.
  • A subdirectory named *.json and a non-JSON-content *.json file are both covered by tests.
  • The valid-record control scenario (resubmission posts its legs) still passes with a corrupt sibling file present, and the corrupt entry remains identifiable for an operator afterwards (not deleted by the scanner).
  • All existing currency_poc tests pass unchanged; the IntentStore::unresolved trait contract documents whatever error/skip semantics are chosen so the in-memory store and future stores agree.

Related: #2289 (the PoC this store belongs to).

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    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
    priority/normalOrdinary priority (the default)
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    effort/sSmall: expected under 2 hours of work
    on Nov 2, 2026
  2. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job (lane A, new-issue-creator-code-a)
    • Session / ID: cron run 2026-11-01 20:05 CST (2026-11-02T02:05Z)
    • Found via: filed this run
    • Task: Filed issue id(currency_poc): one corrupt or foreign .json file in the FileIntentStore directory aborts recovery for every pending conversion #4125 — FileIntentStore::unresolved() aborts on the first unreadable/unparseable .json file, so one corrupt or foreign file in the intent directory blocks reconcile() for every pending conversion. Verified this run on the laptop with verbatim currency_poc modules from main caacf3a (md5 intent.rs 4b413d6505f423428eabe27ba5e0b753): valid record + deadbeef.json containing {not json → reconcile errors, 0 legs posted, valid record still Recorded; control without the bad file resubmits cleanly.
    • Expectation: effort/s — reconcile processes every readable record, surfaces bad entries distinctly (never silently drops or deletes them), trait contract documents the semantics, plus tests for a corrupt file and a *.json subdirectory; existing currency_poc tests unchanged.
    • Links: probe ~/git/fleet/probe-2026-11-01-laneA-currencypoc/ (laptop); queue packet enqueued this run (repo-health-code-pilot).
  3. 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 2, 2026
  4. 15 remaining items

  5. 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
  6. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  7. 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 Nov 2, 2026
  8. added a commit that references this issue on Nov 2, 2026
  9. dezren39 commented on Nov 2, 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)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/small-fixQueue packet kind: bounded fix with reproduction and targeted tests

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions