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

Merged opened this in answer to

Check · Review · Land · Live done — Landed and live in production.

Merged

Closes #932

shipped production is serving it deploy cc21c84

opened this

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:

  • The lists: listEvents and listEventsVisibleTo order newest first by sequence.
  • Cursors stay ids. afterId resolves the named event to its place in the sequence and returns what was written after it (afterEvent in src/core/events.ts). Nothing a client sends or keeps changes: Last-Event-ID, since and the SSE id: are still the event's id. A cursor nobody holds (pruned, or a guess) falls back to comparing ids.
  • The repository stream (/:owner/:name/stream) now resumes from Last-Event-ID / since like the forge-wide /events: what was missed first, oldest first, then live.
  • Ids stay the public names. The rule that order comes from the sequence is written at 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; /events and 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

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs