"""When a body change is worth keeping a version of. A note's body used to snapshot into `note_revisions` on EVERY write, which made a write expensive — and the clients compensated by writing as rarely as they could get away with, saving only when an editor closed. That is durability paying for version history: a crash mid-session lost everything typed, so that the revision list would stay tidy. The safety property is worth more than the feature it was subsidising. The rule here breaks that trade. A body change earns a snapshot only if it is the first one of an editing session, so a client may write as often as it likes. Session granularity falls out of the window rather than being declared. A snapshot stores the body as it was BEFORE the edit, so the first write of a sitting captures the note as you found it and every write after it inside the window adds nothing — one revision per sitting, with no "commit" flag for a client to send and no wire surface to carry it. That last part is why this is a time rule and not a protocol one: `sync.py` applies pushed bodies through the same check, so a client autosaving every second cannot make the server snapshot every second either. Deliberately NOT applied to restoring a revision. That is a considered act rather than a keystroke, and it snapshots unconditionally so restoring is itself undoable. """ from __future__ import annotations import uuid from datetime import datetime, timedelta, timezone from sqlalchemy import select from .models.note_revision import NoteRevision # How long one editing session is assumed to last. A constant rather than a setting: # it is not a preference anyone holds, and the value only has to be longer than a # sitting and shorter than the gap between two of them. Promote it to the settings # registry (rule 25) if that ever stops being true. REVISION_WINDOW_MINUTES = 10 async def should_snapshot(db, note_id: uuid.UUID, old_body: str, new_body: str) -> bool: """Whether `old_body` should be kept as a revision before `new_body` replaces it. False when the text did not actually change — re-saving identical bytes is not a version of anything — and False when this note already has a revision from the current session. """ if old_body == new_body: return False cutoff = datetime.now(timezone.utc) - timedelta(minutes=REVISION_WINDOW_MINUTES) recent = await db.scalar( select(NoteRevision.id) .where(NoteRevision.note_id == note_id, NoteRevision.created_at >= cutoff) .limit(1) ) return recent is None