Module groups
Expand description
Where a version’s name lives: in the document, with the changes it names.
A name that lived in the widget would vanish on close, and a name that lived beside the document would never reach a collaborator. So a name is written into the same CRDT as the content it describes — one record at the document root per named range, keyed by the range it covers:
ROOT
"tilo:group:<hex of the range's first change>" <- the key IS the range
label : "Intro rewrite"
end : "<hex of the range's last change>" (absent while open)
by : "<actor hex of whoever wrote the name>"
at : <unix millis>The key is the range’s first change, not minted per writer: two people
naming the same run then collide on one map key, and automerge’s own
conflict rule resolves it deterministically and identically on every
peer (the loser stays reachable via get_conflicts). Records sit at the
root rather than under one container map for the same reason at a
coarser grain: a container created independently by two peers naming
different ranges at the same time would have one discarded whole,
silently losing a name. Flat, prefixed root keys have no container to
race over.
Naming a version is a change like any other, but is deliberately not
given its own row in the history surfaces — see is_group_marker.
Structs§
- Displayed
Session - One work session beside a seam, as the person saw it: its named record,
or
Nonewhile it is still an automatic projection with these bounds and title.
Constants§
- GROUPS_
KEY - Namespaced so it cannot collide with an app’s own schema:
tilo-docusescontent/comments/props, and the shell’s room document usesworkspaces/active. - MAX_
LABEL_ LEN - A version name is a label, not a paragraph; past this it stops fitting anywhere it is rendered and starts being a way to make another user’s timeline unreadable.
Functions§
- clear_
name - Remove a name. The changes it covered stay; only the band goes.
- close_
range - Close an open range at
end.falsewhen no such record exists. - is_
group_ marker - True when every patch in
patcheslands inside the named-range map — used by the producer to keep naming out of the row list. An empty patch set is not a marker: a change that did nothing visible is still a change, and hiding it would be incorrect behaviour. - materialize_
and_ move_ boundary - Correct a seam even when one or both work sessions are still automatic projections. Missing records are materialized with the titles and bounds the person saw, then the bordering action is moved in the same document transaction. The atomic history entries themselves are never rewritten.
- merge_
named_ ranges - Merge named bands into one caller-resolved range. Every old record must exist before anything is changed, so a stale UI cannot partially merge a set that a collaborator has already edited.
- move_
named_ boundary - Move the boundary between two named bands while preserving both labels. As with split, the caller resolves the two sides from its displayed causal order and sends exact ids.
- name_
range - Names the run of changes from
starttoend, or opens an unbounded run whenendisNone. Returns the record id (also the document key). The transaction is left open — the host commits, so the naming lands stamped and attributed like any other edit. - read_
named_ ranges - Records that do not parse (a corrupted key, a missing label) are skipped rather than guessed at — a band in the wrong place is worse than no band.
- split_
named_ range - Split one named band into two adjacent named bands in the current transaction. The caller supplies both boundary ids because a CRDT history is not inherently linear at concurrent branches; guessing adjacency here would make the operation non-deterministic across peers.