#478: advisory change feed for sync clients #489

Merged
Cordy merged 10 commits from fix-478 into main 2026-09-11 20:57:40 +00:00
Owner

Implements #478 per the design assessment on the issue.

  • internal/changes: journal (in-memory ring, opaque base64 (epoch, seq) cursors, debounced statestore persistence, clean-close epoch resume, dirty/crash epoch bump → {"expired": true}) + storage.Driver decorator recording only successful write/delete/move/mkdir/copy, no actor identity.
  • Decorator wraps directly above marks/audit, inside unscopedStore — REST, WebDAV, TUS, peering and public-share uploads all covered; logical deletes recorded above trash; .cairn-state/ structurally excluded (statestore binds the raw driver) plus a defensive skip.
  • GET /api/v1/changes?since=&limit=500: session/app-password auth, per-caller visibility filter mirroring scope (own home translated to /home/…, member spaces incl. -ro and app-owned via spacestore), moves with one end out of view degrade to delete/write. No since → cursor only.
  • Journal state added to the s3 statePaths list; changeJournal.Close() on graceful shutdown so cursors survive rollouts.
  • Handbook page docs/handbook/change-feed.md documents the protocol and the advisory contract (reconciliation backstop, no space-history replay).

TDD: 8 journal/driver + 5 endpoint tests, witnessed red on the runner, full suite green.

Implements #478 per the design assessment on the issue. - `internal/changes`: journal (in-memory ring, opaque base64 (epoch, seq) cursors, debounced statestore persistence, clean-close epoch resume, dirty/crash epoch bump → `{"expired": true}`) + storage.Driver decorator recording only successful write/delete/move/mkdir/copy, no actor identity. - Decorator wraps directly above marks/audit, inside `unscopedStore` — REST, WebDAV, TUS, peering and public-share uploads all covered; logical deletes recorded above trash; `.cairn-state/` structurally excluded (statestore binds the raw driver) plus a defensive skip. - `GET /api/v1/changes?since=&limit=500`: session/app-password auth, per-caller visibility filter mirroring scope (own home translated to `/home/…`, member spaces incl. `-ro` and app-owned via spacestore), moves with one end out of view degrade to delete/write. No `since` → cursor only. - Journal state added to the s3 statePaths list; `changeJournal.Close()` on graceful shutdown so cursors survive rollouts. - Handbook page `docs/handbook/change-feed.md` documents the protocol and the advisory contract (reconciliation backstop, no space-history replay). TDD: 8 journal/driver + 5 endpoint tests, witnessed red on the runner, full suite green.
Cordy merged commit e1c855dd33 into main 2026-09-11 20:57:40 +00:00
Cordy deleted branch fix-478 2026-09-11 20:57:43 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#489
No description provided.