Skip to content

Design: a verified cursor covers only a restorable chain — replication admission, finished (pkgs/id) #4592

Open
1 of 3 issues completed

Description

@dezren39

Design doc: files/designs/code-id-replication-admission.md in the keep-the-four-repos-healthy goal workspace. Audit at origin/main 73c0ec7466291b164b00f2fb3c911c2769997de2 — every defect below re-verified present at the cited sites this pass (2026-11-02).

Summary

ReplicationTracker::accept (pkgs/id/src/world/replication.rs) is the receiver-side trust boundary for world-journal replication (F12.13, #806, PR #4447): whatever it accepts, the durable receiver and spectator phases treat as a verified, restorable journal. The module's own rule, recorded when the PR #4447 follow-up closed the undecodable-entry hole, is that a verified cursor never covers data the restore path cannot read. That rule has been enforced leg by leg for the payload — entries must decode (chain_payload), and the payload's own journal header must be exactly one Created header for this world at the envelope's version (validate_payload_journal_header, #4486, landed today). The envelope's own header_version field is still held to neither of the two contracts WorldCore::restore and the journal writer jointly state:

Both are one unstated contract with two clauses: the envelope's header version is admitted only if the chain it names could exist — in the restore range, and never behind the chain the tracker already holds.

The contract

A frame is admitted only if its header version names a chain that could exist: inside the restore range JOURNAL_VERSION..=MAX_JOURNAL_VERSION, and — for a snapshot, the one frame kind allowed to change the chain's version — never lower than the version of the chain the tracker already holds.

Recorded decisions (full reasoning, alternatives and risks in the design doc):

  1. The range check lives in accept, for every kind, before any state changes — header_version outside JOURNAL_VERSION..=MAX_JOURNAL_VERSION is refused with the existing UnsupportedJournalVersion variant, now applied to both ends. Snapshot, Tail and Terminal alike: a v0 Terminal against a v0 tracker is the same hole as a v0 Snapshot.
  2. Construction is made inert, not redesigned — id(replication): ReplicationTracker accepts journal header_version 0 — accept checks only the upper bound, so a signed Snapshot rebases a v1-v3 chain onto a version WorldCore::restore refuses (1..=3) #4471 offers two endings for ReplicationTracker::new; this design records the second. With decision 1 in accept, an out-of-range session version makes the tracker inert: every frame kind carries its own header_version and is range-checked on the envelope, and tails/terminals must additionally equal the tracker's version, which no in-range frame can do against an out-of-range tracker. new's doc states this explicitly. A fallible constructor would ripple to every session bootstrap for a state that cannot arise from a real journal header — the session version comes from the local journal, whose header restore already range-checks.
  3. Snapshot monotonicity gets its own error — a snapshot whose header_version is lower than the tracker's current header_version is refused with a dedicated variant (HeaderVersionRegressed), leaving cursor and header version untouched. Reusing HeaderVersionChanged loses: that variant's doc names the tail/terminal fact (any change on a frame kind that may not change version), while a snapshot regression is a different diagnosis — the one frame kind that may move the version moved it the one way journals never move — and the durable receiver's logging will want to tell a downgrading writer bug from a merely desynchronised peer.
  4. Equal and higher stay accepted — same-version snapshots remain the compaction rebase; higher in-range snapshots remain the header-bump rebase (both covered by existing tests). Only the lower direction is refused; no legitimate writer state is excluded, because no code path in the repo ever lowers a journal's header version.

Phased breakdown

Phases adopt the two open origins as sub-issues (no parallels); #4486 is the landed third leg, cited as the embodiment, not a phase. Phase 3 is a new closing-audit issue, gated on Phases 1–2.

Open questions (in the design doc, not filed)

Whether the durable receiver (#806 phase 3) should persist a regression refusal as writer-misconduct evidence or merely log it; whether a future protocol revision wants an explicit reset/rebase frame kind for disaster recovery (snapshot regression is recorded as not that mechanism); the session-restart version question, assigned to Phase 3's disposition (b) to answer from the actual bootstrap code.

Related

Acceptance criteria

  • Every acceptance leg named in the design audit is either implemented with tests or explicitly dispositioned on this issue: a verified cursor never covers journal data the restore path cannot read (headers, chain payload, and each leg the audit enumerates).
  • Regression tests reproduce each audited defect against the pre-fix code and pass after the fix.
  • The design doc (files/designs/code-id-replication-admission.md in the goal workspace) and this issue agree at landing; any leg deferred is filed as a linked follow-up issue, not dropped.

Activity

  1. added
    priority/normalOrdinary priority (the default)
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    epicMeta-issue grouping multiple items (org Project Type=Epic)
    kind/designA design proposal (design-architect): multi-step, phased, decision-bearing
    on Nov 2, 2026
  2. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    agent-note:v1 — design architect, pass 40 (2026-11-02)

    Design #4592 originated this pass from the replication-admission audit at origin/main 73c0ec74: ReplicationTracker::accept holds the envelope's header_version to neither the restore range (#4471) nor monotonicity (#4487), while the payload-side legs of the same rule already landed (chain_payload decode check, PR #4447; validate_payload_journal_header, #4486, closed today).

    Structure: Phase 1 = #4471 (adopted), Phase 2 = #4487 (adopted), Phase 3 = #4593 (new closing audit, gated on Phases 1–2, triage packet → pilot task 6481). All three are linked as sub-issues. Full design: files/designs/code-id-replication-admission.md in the keep-the-four-repos-healthy goal workspace; register entry added (status: proposed).

  3. added
    effort/lLarge: multi-day or open-ended; expect staged check-ins
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Nov 2, 2026
  4. dezren39 commented on Nov 2, 2026

    @dezren39
    MemberAuthor

    Intake review

    Design issue from the design-architect audit at origin/main 73c0ec7, re-verified leg by leg in the issue body; companion to #806 / PR #4447 (the replication trust boundary it extends). Still live: no merged PR references this issue (filed today). Risks: the cursor/restore invariant spans several legs — a partial fix that covers only the named leg re-creates the hole the PR #4447 follow-up already closed once. Suggested approach: implement leg-by-leg with one failing test per leg before the fix, in the order the audit lists them.

    🤖 Agent note · filed

    • Agent: fleet monitor
    • Session / ID: repo-fleet-monitor run 2026-11-02 16:12 CST
    • Found via: monitor reconciliation
    • Task: Intake enrichment (§5) for this issue — acceptance criteria appended, labels normalized, this review posted.
    • Expectation: done = the acceptance criteria above; routing to a worker happens through the queue/feeder as usual.
  5. added a commit that references this issue on Nov 3, 2026
  6. 19 remaining items

  7. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  8. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  9. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    agent-note:v1
    event: handed_off
    task: 8414 (repo-health-code-pilot; repo-worker-code; lane code-y)
    at: 2026-11-04T16:42Z
    found_via: atomic queue claim (lane code-y)
    verified: Issue #4592 OPEN, no hard-stop labels; claim labels already synced (queue/claimed, status/in-progress, work/assigned). Execution-lane assignment for task 8414 is opencode — the bound opencode claimant session owns the triage work; this lane does not work it directly. Attempts 22/24 after repeated unlaunched handoffs.
    next: Claimant launches the bound opencode session for task 8414.

  10. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

  11. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    queue/queuedHas a queued task in the Supabase agent queue
    and removed
    queue/claimedQueue worker lifecycle state
    work/assignedQueue worker lifecycle state
    on Nov 4, 2026
  12. dezren39 commented on Nov 5, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · handed off

    • Agent: fleet monitor
    • Session / ID: task 8414 (repo-fleet-monitor run 2026-11-05T15:45:48Z)
    • Found via: monitor reconciliation (Duty 1 claim/label divergence repair)
    • Task: Claim evaporated: task 8414 is queued and unclaimed in repo-health-code-pilot, but this issue still carried claimed labels. Labels reset to the truth (queue/queued + status/needs-triage). Checkpoint stage at evaporation: handed_off.
    • Expectation: The next lane claim picks task 8414 up from the queued state and posts a fresh pickup note.
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/lLarge: multi-day or open-ended; expect staged check-insepicMeta-issue grouping multiple items (org Project Type=Epic)kind/designA design proposal (design-architect): multi-step, phased, decision-bearingmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)queue/parkedQueue task is parked (waiting on CI, time, or an event)queue/queuedHas a queued task in the Supabase agent queuesource/design-architectFiled by the repo design architect jobstatus/needs-triageNot yet triaged; needs a first lookstatus/parkedDeliberately paused with a recorded resume conditiontask/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