Skip to content

id(world): WorldCore::restore installs checkpoint-carried handoff transfers unvalidated — duplicate sides, non-advancing import epochs, and sequence-claiming transfer events all accepted, unlike the standalone entries #3942

Closed

Description

@dezren39

Summary

WorldCore::restore (pkgs/id/src/world/core.rs) treats the journal as untrusted input and validates handoff state strictly when it arrives as standalone entries — but a JournalEntry::Checkpoint's transfers list is installed verbatim with none of those checks. A journal whose checkpoint carries duplicate handoff sides, a non-advancing import epoch, or a transfer event that claims a sequence/participant is restored successfully, while the identical facts as standalone entries are refused. The checkpoint path is exactly the path compaction produces, so this is the durable-state trust boundary for the region-seam handoff state added in #3870 phase 1 (PR #3922).

Evidence (current main c1675d6)

Standalone arms validate (core.rs restore):

  • EntityExported arm (core.rs:322-330): refuses when source_event.sequence != 0 || source_event.participant_id != 0 ("journal export event claims a sequence"), and refuses a second export with the same handoff_id ("journal exports handoff … twice").
  • EntityImported arm (core.rs:363-375): same event check, plus new_owner_epoch == prior_owner_epoch + 1 ("does not advance the owner epoch"), plus the duplicate-import refusal.

Checkpoint arm (core.rs:502-504):

// A checkpoint comes first in its journal, so its
// transfer list is the whole active-handoff state.
core.handoff_transfers = transfers.unwrap_or_default();

No duplicate check, no epoch check, no transfer-event check, no bound. (The same arm does validate the checkpoint's execution_profile, caps_ceiling, and schedule agreement — transfers are the unvalidated remainder.)

Verified this run with a laptop probe calling the real WorldCore::restore (transient integration test in the laptop clone ~/git/code at c1675d6, pkgs/id/tests/probe_ckpt_transfers.rs, since removed; log at ~/git/fleet/probe-2026-11-01-laneA-ckpttransfers/run.log; sandbox and laptop core.rs/mod.rs md5-identical):

  • CONTROL standalone duplicate export → Err "journal exports handoff "h1" twice"
  • CONTROL standalone import epoch 5 → 5 → Err "does not advance the owner epoch"
  • CONTROL standalone export event sequence 7 / participant 9 → Err "journal export event claims a sequence"
  • CONTROL standalone valid import 5 → 6 → Ok
  • CASE checkpoint, one valid export transfer → Ok
  • CASE checkpoint, duplicate export transfers (same handoff_id) → Ok (expected Err)
  • CASE checkpoint, import transfer epoch 5 → 5 → Ok (expected Err)
  • CASE checkpoint, export transfer event sequence 7 / participant 9 → Ok (expected Err)

Why it matters

Restore is the journal's trust boundary everywhere else in this function: forged Issued entries for participant 0 (#2972), duplicate issues, out-of-bounds delegation expiry, unknown caps, and schedule disagreement are all refused at restore, precisely so a corrupt or crafted journal cannot resurrect state the live writers would never produce. Checkpoint-carried handoff state is the exception. Duplicate export records break the dedupe invariant the coordinator phases of #3870 rely on (an exact retry returns the existing receipt; two export sides for one handoff_id make that ambiguous), a non-advancing import epoch defeats the epoch fencing the design (#2818 §3) uses to stop a stale source region from re-owning an entity, and a transfer event claiming a sequence/participant violates the host-event invariant replay assumes. Because compaction rewrites the journal behind a checkpoint, any bad transfer state that ever reaches a checkpoint is laundered into the canonical durable form.

Acceptance criteria

  • WorldCore::restore applies the same validation to checkpoint-carried transfers as to standalone EntityExported/EntityImported entries: no duplicate (handoff_id, direction) pair, import records advance the owner epoch (new_owner_epoch == prior_owner_epoch + 1), export records carry no new_owner_epoch, and each transfer's event has sequence == 0 and participant_id == 0.
  • Restore refuses (with a clear error naming the handoff) a checkpoint exhibiting any of: duplicate export side, duplicate import side, non-advancing import epoch, or a transfer event claiming a sequence/participant — matching the standalone-arm error style.
  • New world tests cover each refused checkpoint case plus a control: a checkpoint with valid export and import transfers restores, and the checkpoint/compaction round-trip test from PR feat(id): region-seam handoff journal foundation (#3900) #3922 still passes.
  • Existing world/journal tests still pass; no change to the journal wire format or to what checkpoint_entries writes for live (valid) state.

Dedup notes

Filed by new-issue-creator-code-a. Searched open + closed issues for checkpoint/handoff/restore validation: #3900/#3870 (the phase-1 implementation and its umbrella — this is a validation gap in that landed code, not one of the phase 2-5 implementation issues #3901-#3904), #3911 (WaitingPool::restore duplicate guards — different type), #3373 (journal restore under revoked parent — different invariant). None covers checkpoint-carried transfer validation.

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

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job (new-issue-creator-code-a)
    • Session / ID: cron job new-issue-creator-code-a, run 2026-11-01 13:05 CST
    • Found via: filed this run
    • Task: Make WorldCore::restore validate checkpoint-carried handoff transfers with the same rules as standalone EntityExported/EntityImported entries: refuse duplicate (handoff_id, direction) sides, non-advancing import epochs, and transfer events claiming a sequence/participant.
    • Expectation: effort/s — done when the acceptance criteria on this issue pass, including restore tests for each refused checkpoint case plus the valid-transfer control.
    • Links: evidence in the issue body; laptop probe at ~/git/fleet/probe-2026-11-01-laneA-ckpttransfers/ (real WorldCore::restore at main c1675d6: standalone controls all Err, all three checkpoint cases Ok).
  3. dezren39 commented on Nov 1, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · adopted as Phase 1 of design #4000

  4. removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 2, 2026
  5. 13 remaining items

  6. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  7. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · escalated

    • Agent: fleet monitor
    • Session / ID: repo-fleet-monitor run 2026-11-02 20:12 CST
    • Found via: monitor reconciliation
    • Task: ESCALATION (Duty 3): this issue is effort/s (2h expectation) and has had NO activity since 2026-11-02T19:23Z (~7h, past 2x the deadline). Its queue fix task (task 6271) is DONE in the queue (completed 2026-11-02T19:32Z after a handed-off note bound it to an OpenCode session), yet the issue still carries queue/claimed + work/assigned + status/in-progress, and no PR for this issue can be found. Adding user/review. Recommendation: confirm whether the bound OpenCode session is still alive; if not, requeue — reset labels to queue/queued + status/needs-triage and enqueue a fresh packet resuming from task 6271's handoff.
    • Expectation: a fresh checkpoint from the holder, or a requeue decision.
  8. added
    user/reviewNeeds a user-look: Muse reviews first and handles what it can
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 3, 2026
  9. developing-today commented on Nov 3, 2026

    @developing-today
    Contributor

    agent-note:v1
    state: reviewed (coverage loop-back)
    Coverage pass 2026-11-03, loop-back review: this issue was re-reviewed (drift / overlap / already-handled / stale / blockers / ordering) so every open issue in the four repos is reviewed and in the system. Verdict: still live; in the system as task 6824 (triage, queued, priority 50) in repo-health-code-pilot. Labels audited and synced. If it is already handled at current main, its triage closes it with evidence; if oversized, the triage files the split; blockers belong on this issue.
    Found via: coverage loop-back 2026-11-03

  10. added
    queue/claimedQueue worker lifecycle state
    and removed
    queue/queuedHas a queued task in the Supabase agent queue
    on Nov 3, 2026
  11. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  12. dezren39 commented on Nov 3, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · triage disposition

    • Agent: repo-worker-code (OpenChamber scheduled lane, task 6824)
    • Verdict: already fixed on current main; closing as resolved. No open competing PR is needed.
    • Verified: origin/main at e425b6af52c35067a452c0c4526fef47f00c7f01.
    • Evidence: pkgs/id/src/world/core.rs defines validate_handoff_transfer and uses it for standalone export/import entries and for each checkpoint-carried transfer (list-order validation before installation). It rejects duplicate (handoff_id, direction) pairs, non-successor import epochs using checked_add, export records carrying a new epoch, and transfer events with nonzero sequence/participant.
    • Landed coverage: checkpoint_handoff_transfers_validate_duplicates_epochs_and_events, checkpoint_accepts_valid_export_and_import_transfers, and handoff_transfers_survive_restore_and_checkpoint_compaction in pkgs/id/src/world/tests.rs.
    • Verification limit: inspected current-main code/tests; no tests were executed in this triage pass.
  13. dezren39 commented on Nov 3, 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 jobsource/design-architectFiled by the repo design architect jobtask/triageQueue packet kind: verify, reproduce, and route this itemuser/reviewNeeds a user-look: Muse reviews first and handles what it can

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions