mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-09-24 19:32:10 +00:00
57995c5898
* fix(sync): emit moved-out tombstones for cross-visibility collection moves (BUG-1675) /items-changes filtered deltas by an item's CURRENT collection, so an item moving from a collection a restricted member can see into one they can't vanished with no eviction signal — the stale, now-unauthorized row lingered in their local cache until a full rebootstrap. Server: - store.ListMovedOutSince: finds items that changed since the cursor, are now outside the caller's visible scope, and have a 'moved' activity FROM a collection the caller CAN see. Returns id+seq only — no destination data leaks (the caller has read access to the source). - handleListItemsChanges merges these in as moved_out tombstones, then seq-sorts + caps the combined stream so pagination stays gap-free. - Bulk collection moves now log a proper 'moved' activity with from/to collection slugs (mirroring handleMoveItem) — the signal the tombstone query reads. Previously they logged generic 'updated'. Client: - ItemChangeRow gains moved_out; applyDelta hard-evicts those ids from RAM + search and queues the IDB delete into the SAME atomic cursor-advance tx (persistDelta gains removeIds) so it can't resurrect on warm boot. Full members (nil visibility) skip the extra query entirely — the path only runs for restricted members/guests. Tests: store-level matrix (ListMovedOutSince), end-to-end restricted member /items-changes tombstone, bulk-move 'moved' activity logging. * fix(sync): tie moved-out tombstone to the move event's seq per Codex review (round 1) Keying the tombstone on the item's CURRENT seq meant any later change while it sat in a hidden collection re-emitted a moved_out row — leaking that an invisible item keeps mutating, and never settling. Stamp the post-move seq into the 'moved' activity metadata (both single + bulk move paths) and key the tombstone on THAT seq: it fires once, for the move that crossed the visibility boundary, and the cursor settles past it. Moves logged before the seq stamp are skipped (evict on rebootstrap) rather than risk the re-fire. Test: re-fire regression (a post-move hidden-collection update must not re-emit the tombstone). * fix(sync): page moved-out tombstones by move seq, not current seq per Codex review (round 2) Ordering/capping candidates by the item's current seq could strand an item that moved out early (low move seq) but later churned in the hidden collection (high current seq): it fell past the limit while the cursor advanced beyond its move seq, never to be emitted again. Collect all eligible rows, keep the earliest qualifying move per item, sort by move seq, then apply the limit at a move-seq boundary so dropped rows re-fetch cleanly on the next poll. Test: 3 items move out ascending; the earliest churns to a high current seq; limit=2 must still return the two smallest move seqs, then the third on the next page with no gap. * fix(sync): durable item_collection_moves table for moved-out detection per Codex review (round 3) Moved-out detection read the 'moved' activity row, which is written after the move commits and best-effort (errors discarded) — so a delta poll racing the audit write, or a failed write, could advance the cursor past the move seq and strand the unauthorized item forever. Record every cross-collection move in a new item_collection_moves table inside the SAME transaction as the move (MoveItemWithPreCheck), carrying the workspace seq the move assigned. ListMovedOutSince now reads that table — fully SQL/indexed (from_collection_id IN visible, MIN(seq) for multi-hop, current-collection NOT IN visible), no JSON parsing, no best-effort dependency. The 'moved' activity stays for audit only. Migration 066 adds the table + indexes. Tests updated to rely on the durable record (MoveItem writes it) rather than hand-logged activity. * fix(sync): add Postgres migration for item_collection_moves per Codex review (round 4) Postgres reads the separate pgmigrations/ tree, so the SQLite-only migration 066 left item_collection_moves absent on PG deploys — every cross-collection move would fail at the in-tx insert and moved-out queries would error. Add pgmigrations/045 with the equivalent table + indexes.