feat(notes): compact the operation log and purge old tombstones
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 1m17s

- Background job at start and every 6 h: log entries older than 30 days
  (private notes: 7) are removed, documents.log_floor marks the boundary;
  clients behind it get resync and keep their queued changes
- Deleted blocks are purged 30 days after deleted_at via a "purge" log
  effect, so open editors drop them without reloading; a tombstone stays
  while a deleted child still points to it
- Text for a purged block becomes a new block at the end; inserts under a
  purged parent go to the top level (server and browser model)
- doc_op_results kept for 90 days; expired lease/session maps are swept
- Tests: storage, API, engine resync, simulation with compactions

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
sandrodachandClaude Opus 5.5 committed 2026-10-28 15:08:13 +01:00
1 parent aea4324c20
commit f26f286fb8
17 files changed
+653 -48

No files matched your search

+30
View File
@@ -272,3 +272,33 @@ func TestClearConflictMarking(t *testing.T) {
t.Fatalf("conflict marking not cleared: %+v", p)
}
}
func TestPurgeKeepsTreeValid(t *testing.T) {
d := docWith(t, [3]string{"p", "", "Eltern"}, [3]string{"c", "p", "Kind"}, [3]string{"x", "", "Anderer"})
Apply(d, Op{OpID: "1", Kind: OpDelete, BlockID: "c"}, anna, Env{})
Apply(d, Op{OpID: "2", Kind: OpDelete, BlockID: "p"}, anna, Env{})
// Only "p" is old enough: it must stay because its deleted child "c" still points to it
if e := Purge(d, []string{"p"}); e != nil {
t.Fatalf("parent of a remaining tombstone must not be purged: %+v", e)
}
e := Purge(d, []string{"p", "c"})
if e == nil || len(e.IDs) != 2 || len(d.Blocks) != 1 {
t.Fatalf("both tombstones must go: %+v, blocks %d", e, len(d.Blocks))
}
mustValid(t, d)
}
func TestTextForPurgedBlockBecomesNewBlock(t *testing.T) {
d := docWith(t, [3]string{"a", "", "A"}, [3]string{"b", "", "B"})
Apply(d, Op{OpID: "1", Kind: OpDelete, BlockID: "b"}, anna, Env{})
Purge(d, []string{"b"})
_, res := Apply(d, Op{OpID: "2", Kind: OpSetContent, BlockID: "b", BaseVersion: 1, Content: str("Wochen offline getippt")}, ben, Env{})
if res.Status != StatusApplied {
t.Fatalf("late text must not be lost: %+v", res)
}
flat := d.Flatten()
if len(flat) != 2 || flat[1].Content != "Wochen offline getippt" {
t.Fatalf("text must be revived at the end: %+v", flat)
}
mustValid(t, d)
}