Files
pad/internal/events
xarmian bd8667eadf feat: seq-stamped SSE events + stale-event short-circuit (TASK-1358) (#505)
* feat: seq-stamped SSE events + stale-event short-circuit (TASK-1358)

## Server

- events.Event gains a `Seq int64` field (omitempty). Server populates
  it on item lifecycle events so SSE consumers can reason about
  ordering and contiguity against their /items-changes cursor.
- publishItemEventWithName takes seq as a parameter; all call sites
  in handlers_items.go pass the item's current seq:
  - item_created   → item.Seq
  - item_updated   → updated.Seq
  - item_archived  → re-fetched via GetItemIncludeDeleted (DeleteItem
                     bumps seq but doesn't return the updated row)
  - item_restored  → restored.Seq
  - move target    → moved.Seq

## Web

- ItemEvent gains optional `seq` (matches the server's omitempty).
- localIndex.classifySSEEvent(ws, event) returns
  'no-seq' | 'stale' | 'contiguous' | 'gap'. The collection page
  uses this to short-circuit duplicate / replayed events the
  server's replay buffer re-delivers after tab-resume. Non-stale
  events still call deltaSync because the SSE wire payload only
  carries metadata, not the row data; classify does NOT advance
  the cursor (applyDelta with real row data is the only path that
  does — preserving the IDB invariant from TASK-1356).

Parent: PLAN-1343.

* fix(events): version-restore item_updated event carries seq (Codex round 1)

Version-restore in handlers_item_versions.go was publishing the
item_updated event directly via events.Publish without Seq, bypassing
the new seq-stamped SSE contract from TASK-1358. localIndex's
classifySSEEvent would always return 'no-seq' for those events,
forcing a generic /items-changes refetch instead of allowing the
stale/gap fast paths.

Now passes updated.Seq from the store response.

Parent: PLAN-1343.
2026-05-11 20:29:50 -04:00
..