You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
mountsync: checkpoint event-cursor pattern rejects non-evt_ ids (upstream:v1:...), breaking checkpoint flows once the event ledger lands #531
internal/mountsync/syncer.go validates the checkpoint event cursor with
checkpointEventCursorPattern=regexp.MustCompile(`^(?:0|evt_[0-9]+)$`) // line 54
and applies it to prepared.EventCursor, seal.EventCursor and proof.EventCursor (lines ~3233, 3252, 3423, 3486). The value comes from normalizedCheckpointEventCursor(s.state.EventsCursor), and EventsCursor is set from each websocket event id and each feed nextCursor.
AgentWorkforce/relayfile-cloud#293 (event ledger, issue #289, ADR relayfile-cloud#287) changes provider-ingest events to carry a provider-namespaced canonical upstream id, upstream:v1:<provider>:<id> (multi-event envelopes get a :N suffix), used as events.event_id and as the wire/feed cursor. Local writes keep evt_<n>, so the feed will mix both formats.
Once the newest event a mount has seen is a provider-ingest event, checkpoint prepare, seal and resume validation fail with ErrCheckpointNonConverged. Normal sync still works (advanceEventCursor falls back to "take the candidate" when either id is not evt_N), so the damage is confined to handoff/checkpoint flows, which makes it easy to miss.
Fix
Relax the pattern to accept the new form as an opaque, safe token: for example ^(?:0|evt_[0-9]+|upstream:v1:[A-Za-z0-9._:\-]{1,400})$ (match the exact character set and the 384-char upstream-id cap that fix(writeback): require dispatch for canonical updates #293 emits).
Keep rejecting whitespace, control characters and anything unbounded.
Treat the cursor as opaque everywhere else; add a test that a mixed evt_ / upstream: feed does not trip checkpoint validation.
Acceptance
Checkpoint prepare/seal/resume succeed when the last seen event id is upstream:v1:..., and still fail for malformed cursors.
Unit tests cover evt_N, 0, upstream:v1:... (with and without :N), and rejects (empty-with-spaces, control chars, over-long).
Problem
internal/mountsync/syncer.govalidates the checkpoint event cursor withand applies it to
prepared.EventCursor,seal.EventCursorandproof.EventCursor(lines ~3233, 3252, 3423, 3486). The value comes fromnormalizedCheckpointEventCursor(s.state.EventsCursor), andEventsCursoris set from each websocket event id and each feednextCursor.AgentWorkforce/relayfile-cloud#293 (event ledger, issue #289, ADR relayfile-cloud#287) changes provider-ingest events to carry a provider-namespaced canonical upstream id,
upstream:v1:<provider>:<id>(multi-event envelopes get a:Nsuffix), used asevents.event_idand as the wire/feed cursor. Local writes keepevt_<n>, so the feed will mix both formats.Once the newest event a mount has seen is a provider-ingest event, checkpoint prepare, seal and resume validation fail with
ErrCheckpointNonConverged. Normal sync still works (advanceEventCursorfalls back to "take the candidate" when either id is notevt_N), so the damage is confined to handoff/checkpoint flows, which makes it easy to miss.Fix
^(?:0|evt_[0-9]+|upstream:v1:[A-Za-z0-9._:\-]{1,400})$(match the exact character set and the 384-char upstream-id cap that fix(writeback): require dispatch for canonical updates #293 emits).evt_/upstream:feed does not trip checkpoint validation.Acceptance
upstream:v1:..., and still fail for malformed cursors.evt_N,0,upstream:v1:...(with and without:N), and rejects (empty-with-spaces, control chars, over-long).Found while reviewing relayfile-cloud#293 (read-only review, 2026-10-04).