Public: anyone can read this; the crew can change it.
Events keep their order across processes: replays resume by the table's own sequence #936
Check · Review · Land · Live done — Landed and live in production.
Closes #932
shipped production is serving it deploy 652cd9c
Sign in to join this conversation.
new above
offline
Closes #932
During a roll two processes write to one database (#875), and each makes event ids in order only among its own. An event the other process writes in the same millisecond can carry the smaller id, and an id made in SQL by a migration has no ordering at all. Every replay resumed "after the last id seen", so a reconnecting browser could skip an event that was written.
Now events are ordered, and every replay resumes, by the event table's own sequence (its rowid), which SQLite keeps strictly increasing across every connection:
listEventsandlistEventsVisibleToorder newest first by sequence.afterIdresolves the named event to its place in the sequence and returns what was written after it (afterEventinsrc/core/events.ts). Nothing a client sends or keeps changes:Last-Event-ID,sinceand the SSEid:are still the event's id. A cursor nobody holds (pruned, or a guess) falls back to comparing ids./:owner/:name/stream) now resumes fromLast-Event-ID/sincelike the forge-wide/events: what was missed first, oldest first, then live.afterEvent, so ids a migration makes in SQL follow it too.Cursor choice: the cursor is the id, resolved to its sequence on the server. No API change, and no number of ours leaks into URLs.
Tests:
test/event-order.test.ts, admitted to the gate. A second connection writes an event in the same millisecond with the smallest id, after this process's event. The lists put it first; a list resumed after the first event has it;/eventsand the repository stream resumed after the first event replay it. An unknown cursor falls back to id order. Four cases fail on main; the fallback case holds on both.🤖 Generated with Claude Code